Commit graph

2318 commits

Author SHA1 Message Date
Affaan Mustafa
6f452d48d2 chore: bump plugin version to 2.1.0 2026-07-27 14:05:24 -04:00
Affaan Mustafa
4099794c74 fix(release): bump the claude marketplace and zh-CN heading on macOS
Two bumps were being skipped, both caught by plugin-manifest.test.js only
after the version had already been rewritten across twenty files.

.claude-plugin/marketplace.json used sed with GNU's 0,/re/ address form.
BSD sed on macOS ignores it and exits 0, so the substitution silently did
nothing. Replaced with a node first-match rewrite that fails loudly.

docs/zh-CN/README.md had its version row updated but not its release
heading, unlike the other localized READMEs.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa
2026-07-27 14:05:18 -04:00
Affaan Mustafa
1ffaa75472 fix(release): match the ECC banner name when bumping versions
The banner regex still expected 'Everything Claude Code', but the plugin
banner in .opencode/plugins/ecc-hooks.ts reads 'ECC' since the rename, so
update_opencode_hook_banner_version aborted every bump. Accept both names.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa
2026-07-27 14:03:22 -04:00
Affaan Mustafa
b06c78cc6b docs: add 2.1.0 release notes and Plan Canvas demo assets
Packaged by Haley for the 2.1 launch. These must land on main before the
v2.1.0 tag, because the announcement and README reference the assets by
raw.githubusercontent.com URL on main.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa
2026-07-27 14:01:42 -04:00
Affaan Mustafa
6a9f075cd9
fix: use scalar Claude agent tools (#2583)
Normalize scalar Claude agent tool metadata across validators, adapters, dashboards, and generated surfaces with regression coverage.
2026-07-26 03:20:15 -07:00
Affaan Mustafa
f3afd59045
fix: flatten Claude skill installs (#2582)
Flatten managed Claude skill destinations, preserve user-owned conflicts, and migrate legacy nested installs through the lifecycle tooling.
2026-07-26 03:20:06 -07:00
Alexis D.
71438391e8
fix(opencode): normalize tool paths across platforms (#2459)
Normalize backslash paths for OpenCode formatting and add branch coverage for GitHub coordination behavior.
2026-07-26 03:13:49 -07:00
dependabot[bot]
5a4777777d
chore(deps): bump cargo minor and patch dependencies
Lockfile-only Dependabot Cargo group update for ecc2. Verified PR was clean/mergeable with no failing or pending checks and no unresolved review threads.
2026-07-26 03:13:43 -07:00
dependabot[bot]
a7996b03f5
chore(deps): update checkout action to v7 (#2456)
Update the final SLSA workflow checkout step to the same exact v7.0.0 SHA used across the rest of the repository.
2026-07-26 03:12:29 -07:00
dependabot[bot]
efc91870c7
chore(deps): update pinned GitHub actions (#2540)
Update actions/stale to v10.4.0 and softprops/action-gh-release to v3.0.2 while preserving exact SHA pinning.
2026-07-26 03:11:38 -07:00
Farda Karim
1435f540ff
docs: refresh command quick reference (#2533)
Align the command catalog and retired-command guidance with the current skills-first surface.
2026-07-26 03:04:21 -07:00
黄云龙
19df41d681
test: cover shell substitution parser (#2495)
Add harness-compatible unit coverage for substitution parsing, escaped syntax, compound commands, and edge-case inputs.
2026-07-26 03:00:57 -07:00
Affaan Mustafa
4d0b501b05
feat: add cross-harness memory vault (#2581)
Add a local-first, cross-harness memory vault with CLI and MCP surfaces, bounded search and storage, harness-scoped visibility, setup guidance, and comprehensive tests.
2026-07-26 02:46:59 -07:00
Affaan Mustafa
56d9302f02
docs: map cross-harness control-plane roadmap (#2584)
Map the ECC Ultra report into ten dependency-ordered execution lanes with explicit security, consent, schema, lifecycle, testing, and distribution gates.
2026-07-26 01:46:56 -07:00
Seekers2001
ad8db87780
feat(skills): add contract-first collaboration workflow (#2567)
Add a contract-first workflow for consumer/provider collaboration, including shared artifact authority, compatibility review, generated-type and runtime verification, and safe handling of contract-driven tooling.
2026-07-26 00:05:22 -07:00
Gaurav Dubey
5debb798c8
fix(continuous-learning-v2): honor non-git CLAUDE_PROJECT_DIR (#2488)
Honor an explicit non-git CLAUDE_PROJECT_DIR as an isolated project scope, canonicalize and hash it consistently in the shell observer and Python CLI, and preserve the global fallback for arbitrary non-git working directories.
2026-07-26 00:04:35 -07:00
JongHyeok Park
28b922dee3
fix(hooks): preserve Stop output through lifecycle wrappers (#2493)
Preserve complete Stop-hook stdout through lifecycle wrappers, wait for queued output to flush before exiting, bound child output with a larger explicit buffer, and add end-to-end regressions for large, multibyte, dry-run, and failure cases.
2026-07-26 00:01:57 -07:00
Gaurav Dubey
c714dc5654
fix(resolve-ecc-root): require ECC skills, not just scripts, before accepting a root (#2544) (#2577)
* fix(resolve-ecc-root): require ECC skills, not just scripts, before accepting a root (#2544)

resolveEccRoot() accepted a candidate root on script-only evidence
(scripts/lib/utils.js). A partial install that lands ECC's scripts into
~/.claude but not ECC's skills short-circuited at the standard-install
branch, so skill-resolving callers built skills/... paths against a root
where they do not exist and every command failed three layers away.

For the default probe (skill consumers, reached via INLINE_RESOLVE) a
candidate now qualifies only if it contains both the script tree and a
sentinel ECC skill; the same stricter check guards the plugin-root and
plugin-cache branches. An explicit caller probe is still honored exactly,
so script consumers (e.g. session-start-bootstrap, which probes for the
hook runner) are unaffected. Merely checking that skills/ exists is
insufficient — a user's own ~/.claude/skills/ can be present with none of
ECC's skills.

Adds a regression test for the exact partial-install scenario and updates
the resolver test fixtures to build complete roots.

* test(resolve-ecc-root): cover partial exact-plugin and cache roots; DRY skill sentinel (#2544)

Address CodeRabbit review on PR #2577:
- Extend #2544 regression coverage to the exact-plugin and versioned
  plugin-cache branches, asserting the stricter both-sentinels predicate
  rejects a scripts-only root there too (not only for ~/.claude).
- Extract the ECC_SKILL_SENTINEL constant in command-plugin-root.test.js
  and reuse it at both fixture setup sites instead of duplicating the literal.
2026-07-25 22:21:27 -07:00
Affaan Mustafa
ac30ff3ea2
Use supplied Itō PNG logo (#2570)
Replace the generated Itō SVG wordmark with the supplied transparent monogram assets, keep the exact white-and-gold mark for dark mode, add a same-geometry light-mode variant, and refresh the dependency lock entry flagged by CI.
2026-07-24 17:40:49 -07:00
Affaan Mustafa
abe185c6a4
Center README entry cards and correct sponsor tiers (#2569)
Center the three-card README group, remove stale $5 sponsor copy, and align sponsor docs to the current public tiers.
2026-07-24 13:40:53 -07:00
Affaan Mustafa
751874fef9 Center README entry cards 2026-07-24 16:26:50 -04:00
haelyra
8512dc6f42
Merge pull request #2491 from gaurav0107/fix/2477-opencode-command-agent-scope
fix(opencode): resolve command agent ids to registered opencode agents
2026-07-24 12:53:30 -04:00
haelyra
374feb7f9c
Merge pull request #2536 from latreon/fix/bun-lockfile-detection
fix(scripts): detect modern bun.lock, ignore stray root lockfiles
2026-07-24 12:53:06 -04:00
haelyra
fee94fb778
Merge pull request #2516 from thejesh23/fix/dashboard-refresh-rules-commands
fix(ecc_dashboard): repopulate Rules and Commands trees on Refresh Data
2026-07-24 12:52:36 -04:00
Affaan Mustafa
ce226c94b2
Merge pull request #2568 from affaan-m/agent/readme-asset-alignment-20260724
Merge the official ECC Tools favicon mark, normalized Itō Drive lockup canvas, and equal 16:9 guide cards after full CI and GitHub-render visual verification.
2026-07-24 09:17:13 -07:00
Affaan Mustafa
cf1fb0125e Fix README asset alignment 2026-07-24 11:52:30 -04:00
Affaan Mustafa
fb401834e5
Merge pull request #2566 from affaan-m/agent/readme-kimi-layout-20260724
Merge the aligned ECC entry cards, inline guide row, and documented Kimi/Itō self-hosting path after full CI and visual verification.
2026-07-24 01:13:12 -07:00
Affaan Mustafa
05a7695bc0 docs: align ECC entrypoints and Kimi setup 2026-07-24 03:58:50 -04:00
Affaan Mustafa
e625a07736
docs: compact the sponsor logo row (#2565) 2026-07-23 23:44:42 -07:00
Affaan Mustafa
33c7dbb7d6
feat(ito): expose guarded live node qualification
Expose the canonical Itō CLI's pinned sixtytwo node-qualification path through ECC with double opt-in, explicit node/config gates, credential isolation, and no new MCP or execution authority.

Validated across the full Linux, macOS, and Windows Node/package-manager matrix, hosted coverage, CodeQL, security, lint, and focused bridge tests.
2026-07-23 22:10:57 -07:00
Affaan Mustafa
34fbe007f0
fix: reject credential-bearing Itō CLI shims (#2559) 2026-07-23 21:07:59 -07:00
Affaan Mustafa
7dc2c116e7
docs: restore sponsor contract after mainline merge (#2560)
* fix sponsor contract after mainline merge

* refine sponsor assets and placement

* tighten sponsor asset contract
2026-07-23 20:44:09 -07:00
Affaan Mustafa
6a2e09137c
docs(sponsors): consistent sponsor treatment, Itô + Moonshot AI (Kimi) public + Atlas Cloud (#2553)
* docs: add Itô Markets GPU compute sponsor section to README

Adds a GPU compute sponsor entry under the Sponsors section: Itô Markets
logo linking itomarkets.com plus the compute dashboard at
compute.itomarkets.com, matching the framing from the merged sponsor
routing (4e341183, 8eb43383). Includes a hidden HTML-comment placeholder
for Moonshot AI (Kimi), pending countersign; nothing renders publicly
for Moonshot yet.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa

* docs(sponsors): consistent sponsor treatment, Moonshot public, real brand assets

- Replace cropped ito.svg with the full Drive lockup; add ito-dark.svg
  (white marks) with picture/source theme switching for dark mode
- Add Moonshot AI (Kimi) as a public business sponsor: logo in the top
  sponsors table, SPONSORS.md row, placeholder comment removed
- Swap atlascloud.png for the official atlascloud.svg wordmark; add
  dark-theme variants for Atlas Cloud and Moonshot
- Rewrite the bottom Sponsors section: one consistent list, no
  Ito-only subsection or stray horizontal rule
- Point the self-host/gateway FAQ at the ito-compute skill for
  fixed-rate GPU blocks (npm CLI marked coming soon, not yet published)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa

* docs: drop em dash from sponsor FAQ line

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa

* docs(sponsors): Itô is a Partner, Moonshot AI (Kimi) are Open Source Friends

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0149VwNuynam6rvEfcMmiHHa

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-23 19:34:55 -07:00
Affaan Mustafa
bc774282e6
feat: connect ECC to canonical Ito compute CLI (#2558) 2026-07-23 19:28:55 -07:00
Affaan Mustafa
9d54ee222d
Correct README formatting and update sponsor information
Fixed formatting issue in the language section and removed redundant text
2026-07-23 18:27:19 -07:00
Affaan Mustafa
7b03a834b3
feat: add read-only Itō compute handoff (#2554)
* feat: add read-only Itō compute handoff

* fix(ito): keep handoff portable under CI

* test(ito): run npm welcome through Windows shell
2026-07-23 14:35:57 -07:00
haelyra
a3130f9ebf
feat(codex): add ECC navigation guide (#2525)
* feat(codex): add ECC navigation guide

* fix(codex): ship navigation guide references

---------

Co-authored-by: Haley Chen <2022hachen@gmail.com>
2026-07-22 20:44:37 -04:00
Haley Chen
b6fe5a71e1 fix: harden plan canvas code scanning alerts 2026-07-22 16:28:07 -04:00
haelyra
b6652335d3
fix(hooks): bound plugin shell probe timeouts (#2547)
Co-authored-by: Haley Chen <2022hachen@gmail.com>
2026-07-22 13:15:52 -04:00
KH
8348fb5387
fix: detect Anthropic API keys (sk-ant-...) in pre-commit secret scan (#2529)
The existing OpenAI pattern sk-[a-zA-Z0-9]{20,} never matches real
Anthropic keys: their sk-ant-api03-... format contains hyphens, which
break the character class before reaching the 20-char threshold. Keys
from the fastest-growing Claude Code user base slipped through the scan.

Adds a dedicated sk-ant-[a-zA-Z0-9_-]{20,} pattern (checked before the
OpenAI one) and extends the staged-secrets test with a realistic
Anthropic key fixture.
2026-07-22 12:17:28 -04:00
Jun
a1bf029cbf
fix(observer): repair daemon boot (stale resolver name) and close analysis stdin (#2452) (#2464)
Two continuous-learning-v2 observer regressions reported in #2452:

- start-observer.sh still called _ecc_resolve_homunculus_dir, but the
  shared lib was renamed to _clv2_resolve_homunculus_dir (with observe.sh
  and detect-project.sh updated, start-observer.sh missed). Under set -e
  every launch dies with exit 127 at line 40 - daemon boot is broken on
  all platforms, not just Windows.
- observer-loop.sh backgrounds the analysis claude call with stdin left
  open; on Git Bash/MSYS2 the child inherits it, waits, warns 'no stdin
  data received', and exits 1 before reading the analysis file. Close
  stdin with </dev/null while keeping the -p prompt flag, preserving the
  Windows-compat decision from #842 instead of reverting to a stdin
  redirect.

Adds two source invariant guards to tests/hooks/hooks.test.js: every
*_resolve_homunculus_dir call site must match a function the shared lib
defines, and the backgrounded claude call must close stdin.

Fixes #2452
2026-07-22 12:17:19 -04:00
Girish Kanjiyani
cd39df154c
fix(suggest-compact): recognize large-window model families without a [1m] marker (#2468)
* fix(suggest-compact): recognize large-window model families without a [1m] marker

resolveContextWindowTokens() only detected a 1M window via the env
override, the [1m] model-id marker, or observed tokens already above
200k. Large-window models whose ids carry none of these (e.g.
claude-fable-5) were misclassified as 200k windows, overstating
context usage ~5x in the compact suggestion.

Add a known-model-family substring table (claude-fable-5,
claude-mythos-5) checked after the env override and [1m] marker and
before the token-count heuristic. Env overrides still win, and unknown
model ids still fall back to the 200k default.

Closes #2461

* fix(suggest-compact): anchor known-model-family match at a token boundary

Unanchored substring matching would misclassify a hypothetical smaller
tier sharing a known family prefix (e.g. claude-fable-5-mini) as a 1M
window. Require the family id to end at a token boundary: end of id, a
delimiter, or a dated/versioned suffix (-20260115). Alphanumeric
continuations and letter suffixes no longer match.

Addresses CodeRabbit/Greptile review on #2468
2026-07-22 12:17:11 -04:00
Emad Doughan
e7b3ba07bb
fix(config-protection): match protected filenames case-insensitively (#2543)
On a case-insensitive filesystem (macOS APFS/HFS+, Windows NTFS) a write to
`.ESLINTRC.JS` lands on the exact same inode as `.eslintrc.js`, but the guard
looked the basename up in PROTECTED_FILES with a case-sensitive `Set.has`.
Every entry in that Set is lowercase, so any case-variant path missed the
branch entirely and returned exit 0 — a single Write silently overwrote a
live config while the hook reported success.

Reproduced on macOS APFS: `.eslintrc.js` and `.ESLINTRC.JS` share one inode,
yet the hook returned exit 2 for the former and exit 0 for the latter, and the
uppercase write replaced the real config's contents.

This is a one-step bypass of the whole guard and needs no shell access, unlike
the known delete-then-recreate route.

Fix: also test `basename.toLowerCase()`. All 32 PROTECTED_FILES entries are
already lowercase, so the fallback is exact. On a genuinely case-sensitive
filesystem this costs at most a false positive on a distinct file whose name
differs from a protected one by case alone.

Behaviour deliberately unchanged: first-time creation is still allowed (the
bootstrap affordance), non-config paths still pass through, and the existing
lstat/ENOENT fail-closed semantics are untouched.

Test: adds a case-variant case that asserts exit 2. It guards itself with an
inode comparison and skips on case-sensitive filesystems rather than asserting
something untrue there. Verified in both directions — it FAILS against the
unpatched hook (`Got 0; 0 !== 2`) and passes with the fix. Suite: 9/9.
2026-07-22 12:17:04 -04:00
Affaan Mustafa
96789caaf9
feat: add Itô compute sponsor routing and Phase 2 plan (#2546)
* feat: add Ito compute sponsor routing

* fix: harden Ito integration CI and framing
2026-07-22 03:07:45 -04:00
Thejesh Reddy
5deee34c93
fix(hooks): remove stray '?' that made every 'yarn <anything>' fire tmux reminder (#2517)
* fix(hooks): remove stray '?' that made every 'yarn <anything>' trigger tmux reminder

The tmux-reminder matcher uses one alternation per package manager. Each
branch requires a subcommand (install|test) — except yarn, whose subcommand
group carried a trailing `?`:

    yarn (install|test)?

That made the subcommand optional, so the branch degraded to "yarn " plus
anything: `yarn add foo`, `yarn build`, `yarn dev`, even `yarn --version`
all matched and spammed the "Consider running in tmux" hint into the
additional-context channel.

Drop the `?` so yarn matches parity with npm/pnpm/bun. Verified locally
against 14 cases (yarn install/test still fire; yarn add/build/dev/… no
longer do; npm/pnpm/bun/pytest behavior unchanged).

Fixes #2514

* test(hooks): add pre-bash-tmux-reminder regression tests

Add coverage for the tmux-reminder matcher following the auto-tmux-dev.test.js
structure — the regex-first hook now has direct regression tests for the yarn
branch fix in this PR (and for the sibling package managers, other matched
tools, TMUX bypass, and malformed input).

16 assertions total:
  - fires for: yarn install, yarn test, npm install, pnpm test, bun install,
               pytest tests/, cargo build
  - does NOT fire for: yarn add react, yarn build, yarn dev, yarn --version,
                       bare `yarn`, npm run dev
  - respects TMUX env var
  - tolerates invalid JSON and missing command field

Verified the tests actually catch the bug: reintroducing the buggy
`yarn (install|test)?` fails 4 of the 5 yarn non-match cases (the fifth,
bare `yarn`, stays passing because even the buggy branch requires a trailing
space after yarn).

Addresses CodeRabbit review on #2517.

* test(hooks): fail loudly on spawn errors, use destructuring, split runTests

Address three CodeRabbit review notes on tests/hooks/pre-bash-tmux-reminder.test.js:

- Fail loudly on spawnSync errors: raise instead of coercing
  `result.status || 0`, which would mask spawn errors, timeouts, or signal
  termination as a successful exit 0 (masks legitimate test failures).
- Use destructuring (`const { TMUX, ...env } = process.env`) instead of
  copy-then-`delete` so the base env is built immutably.
- Split `runTests` (was 66 lines) into small per-group helpers
  (runYarnTests, runSiblingPackageManagerTests, runOtherToolTests,
  runTmuxBypassTests, runEdgeCaseTests). `runTests` is now 18 lines and
  purely orchestrates.

16 assertions still pass; no coverage changes.

The 4th CodeRabbit note (avoid console.log in test files) is intentionally
not adopted here — every sibling hook test in this repo
(auto-tmux-dev.test.js, bash-hook-dispatcher.test.js, block-no-verify.test.js,
etc.) writes to console.log because the project's own test runner
(tests/run-all.js) is console-log based and there is no Jest/Mocha
dependency. Diverging from the established convention in a bugfix PR is
out of scope.

* test(hooks): trim tmux reminder regression coverage

---------

Co-authored-by: Haley Chen <2022hachen@gmail.com>
2026-07-20 16:21:03 -04:00
WinterSold1er
ee7dded8e9
fix(observer): use _clv2_resolve_homunculus_dir (matches lib export) (#2511)
Commit 2d40baac (PR #2304) renamed `_ecc_*` -> `_clv2_*` but missed this
single call site. The launcher sources `scripts/lib/homunculus-dir.sh` which
only exports `_clv2_resolve_homunculus_dir`, so any user enabling the
observer (`observer.enabled: true`) gets:

  start-observer.sh: line 40: _ecc_resolve_homunculus_dir: command not found

The hook (`observe.sh`) uses the correct name and writes observations, but
the lazy-start path fails silently via nohup, so the symptom is
"observations grow forever, no new instincts". Confirmed on
affaan-m/ECC@40927950c (HEAD of main).

Default `observer.enabled: false` masks the bug for new users. Opt-in
users hit it on first manual `start-observer.sh start` or first lazy-start
after enabling.

Fix: rename the single call to `_clv2_resolve_homunculus_dir` to match
the lib export and every other caller in the skill.
2026-07-20 15:42:14 -04:00
黄云龙
faff56015f
docs(strategic-compact): document context-window override env vars (#2487)
* docs(strategic-compact): document context-window override env vars

* docs(strategic-compact): mirror context-window override env vars for Codex
2026-07-20 15:41:06 -04:00
someiyoshino-lab
4a4fa907f5
docs(rules): add Delegation Completion Contract to agent orchestration rules (#2471)
The 'Parallel Task Execution' rule encourages agents to spawn subagents,
but defines no completion contract. Observed failure mode: subagents
followed the rule, spawned their own children, and returned 'waiting
for background agents' as their final answer. All children completed
successfully, but their results were orphaned because a parent whose
turn has ended cannot receive completion notifications - leaving
zombie 'running' tasks and lost work.

Adds three rules that apply at every delegation depth:
1. Your final message IS the deliverable (never end with 'waiting')
2. If you delegate, you own collection (no fire-and-forget)
3. Decompose only when work cannot fit in one context
2026-07-20 15:39:55 -04:00
fletcherm-hub
56d2913f38
docs(skills): fix typo in remotion charts rule (#2460) 2026-07-20 15:35:06 -04:00
JongHyeok Park
0071fa5c3c
refactor(hooks): consolidate PostToolUse hooks into sync/async dispatchers (#2494)
* refactor(hooks): consolidate PostToolUse hooks into sync/async dispatchers

Replace 10 individual PostToolUse entries in hooks.json with two
consolidated dispatcher entries (post:dispatcher:sync /
post:dispatcher:async). The dispatcher's internal registry preserves
every hook ID, matcher, and profile, so ECC_DISABLED_HOOKS and
ECC_HOOK_PROFILE gating behave exactly as before.

Performance (Edit event, actual hooks.json commands spawned in
parallel like the harness does, median of 7 runs):
- Blocking hook latency: 81ms -> 49ms (~40% faster; 7 blocking
  processes -> 1 sync dispatcher)
- Node processes per tool call: 10 -> 2 (7 blocking + 3 async
  -> 1 sync + 1 async)
- observe-runner now runs in-process (~370ms) inside the async
  dispatcher, which stays backgrounded (async: true, timeout 45s),
  so it adds no user-facing latency.

Also:
- dashboard-web lists dispatcher-managed child hooks so the hook
  inventory stays complete
- post-edit-console-warn refactored to export run() for in-process
  dispatch while keeping standalone stdin behavior
- dispatcher stdin reading is multi-byte safe (StringDecoder) and
  child hook exit codes propagate to the dispatcher exit code

* test(hooks): replace emoji literal with unicode escape for CI unicode safety check

* fix(hooks): adopt explicit cli() entrypoint and merge multi-hook stdout

Address Greptile review on #2494:

- Replace the non-standard 'require.main === undefined' guard with an
  explicit exported cli(). The hooks.json bootstraps now call
  require(s).cli(), so merely requiring the module (dashboard-web,
  test runners, Jest, worker threads) can never trigger dispatch,
  attach stdin listeners, or set process.exitCode.
- Replace last-writer-wins stdout with mergeHookStdout(): when several
  hooks emit additionalContext envelopes they merge into a single
  PostToolUse envelope; non-mergeable raw stdout keeps the last hook's
  output and emits a stderr warning naming the dropped hook IDs, so
  nothing is lost silently.

Also includes local formatter reformatting of the dispatcher and its
test file (no behavioral changes beyond the above).

* fix(hooks): keep post:bash:dispatcher phase reachable in minimal profile

The Greptile P1 premise was partially incorrect: sub-hooks without
explicit profiles default to standard,strict via parseProfiles()
(scripts/lib/hook-flags.js), so audit/cost logs never ran under the
minimal profile on main either — there is no user-visible regression.

However, main did spawn the bash dispatcher phase unconditionally and
let each sub-hook gate itself. Restore that semantic by opening the
outer registry gate to minimal,standard,strict so a future sub-hook
that opts into minimal is not silently blocked at the phase level.
Adds the previously missing minimal-profile async dry-run test.

* test(hooks): assert failing hook exit code propagates to real process status

Spawns the actual dispatcher subprocess with an injected failing hook
and asserts the OS-level exit status, stderr diagnostic, and suppressed
pass-through — closing the E2E gap CodeRabbit flagged on #2494.

* chore: retrigger CI (flaky windows powershell bootstrap test)
2026-07-19 15:47:10 -04:00