Commit Graph
794 Commits
Author SHA1 Message Date
Alexis D.andGitHub ff15079b9f test(lib): extract shared mini test runner for coordination tests (#2663)
Address CodeRabbit review on #2311: dedupe the local test(name, fn)
harness and route all reporter output through a shared helper
(tests/lib/helpers/mini-test-runner.js) instead of direct console.log.
2026-08-04 00:29:31 -04:00
Karim FarahatandGitHub 203aac7710 fix(commands): probe for auto-update.js in auto-update ECC_ROOT resolver (#2462)
The auto-update command's inline ECC_ROOT resolver delegates to
resolveEccRoot() with the default probe (scripts/lib/utils.js). A
hooks-runtime-only install copies scripts/lib/ into ~/.claude, so the
partial install satisfies the probe and shadows the full plugin root
under ~/.claude/plugins/marketplaces/. The command then fails with
MODULE_NOT_FOUND because ~/.claude/scripts/auto-update.js does not
exist.

Pass {probe: scripts/auto-update.js} so the resolver only accepts a
root that actually contains the script the command runs. Applied to
the command doc and its ja-JP/zh-CN translations, with regression
tests for both the resolver behavior and the embedded snippets.
2026-08-04 00:28:59 -04:00
7b76082b13 fix(mcp): accept reserved _meta field in tools/call params (#2670)
* fix(mcp): accept reserved _meta field in tools/call params

The memory MCP server rejected any tools/call whose params contained a key
other than name/arguments, returning -32602 "Unknown or missing memory tool."

MCP clients (e.g. Claude Code) attach the spec-reserved `_meta` field
(such as progressToken) to request params, so every tool call from a
compliant client failed and the entire memory MCP surface was unreachable —
even though initialize/tools-list and the `ecc memory` CLI kept working.

Per the MCP base protocol, `_meta` is reserved for request metadata and
must be accepted. Add it to the params key allowlist.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* test(mcp): validate _meta shape and cover tools/call param allowlist

Address CodeRabbit review on #2670:
- Validate params._meta when present: accept metadata objects, reject null,
  arrays, and scalar values (reuses isRecord). Keeps _meta optional and
  preserves existing name/arguments/unexpected-key rejection.
- Add regression tests: accept _meta with progressToken, reject malformed
  _meta values, and continue rejecting unrelated top-level params.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-04 00:28:09 -04:00
Bob.HouandGitHub ab373716e7 fix: add claude-opus-5 to KNOWN_MODEL_WINDOW_TOKENS (#2609)
* fix: add claude-opus-5 to KNOWN_MODEL_WINDOW_TOKENS

claude-opus-5 has a 1M context window (verified: 250k tokens at 25%
usage = ~1M), but was missing from the model table. This caused
resolveContextWindowTokens() to fall back to the 200k default when
tokens < 200k, incorrectly triggering compact warnings in the first
20% of a 1M session.

Same failure class as #2290 (Opus 4.x) and #2461 (fable-5/mythos-5).
The env override (ECC_CONTEXT_WINDOW_TOKENS) remains the escape hatch
for unlisted models.

Refs: #2290, #2461, #2468

* test: add regression test for claude-opus-5 context window

Verifies resolveContextWindowTokens returns LARGE_CONTEXT_WINDOW_TOKENS
for claude-opus-5 at 50k tokens, matching the behavior of fable-5 and
mythos-5 in the known-model table.
2026-08-04 00:27:33 -04:00
haelyraandGitHub 85c7822c4a fix(commands): generate discoverable skills from learning workflows (#2653)
Carry #2246 forward on current main with native SKILL.md discovery, guarded writes, portable metadata, and fail-closed validation.
2026-08-02 14:39:29 -04:00
591ab5cbd3 fix(opencode): don't crash the whole session when plugins/lib is missing (#2538)
* fix(opencode): don't crash the whole session when plugins/lib is missing (#2530)

* fix: address review feedback (trailing newlines, symptom wording)

* fix(opencode): also lazy-load the store in ecc-hooks.ts plugin entrypoint

* test(opencode): add regression coverage for missing/present plugins/lib in ecc-hooks

* fix(opencode): guard diagnostic log() against unhandled rejection; tighten test assertion

* fix(opencode): only publish store after init succeeds; scrub loader errors from warning; catch sync log throws

* fix(opencode): scrub raw loader error from changed-files tool; add tool-level regression tests

* fix(ci): make OpenCode checks cross-platform

---------

Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-07-28 21:37:41 -04:00
837acaf20b fix(hooks,lib): fix hook detection and parsing edge cases (#2405)
* fix(hooks,lib): fix hook detection and parsing edge cases

- auto-tmux-dev: dev\b -> dev(?![\w-]) so one-shot dev-build/dev-docs scripts
  are not detached into tmux; align command shapes (yarn run dev, bun dev) with
  pre-bash-dev-server-block.js DEV_PATTERN.
- pre-bash-commit-quality: skip obvious non-secret placeholders (env refs,
  ${...}, <...>, whitelisted tokens) in the api-key rule without suppressing
  real high-entropy secrets; make -m message extraction quote- and
  escaped-quote-aware so `-m "fix: \"x\""` / apostrophes are not truncated.
- pre-compact: annotate the CURRENT worktree's session (match **Worktree:** /
  legacy **Project:**) instead of the newest *-session.tmp across all projects,
  layered onto the LLM-summary flow from #2388; a present-but-blank Worktree
  header is treated as non-legacy (no foreign project fallback).
- shell-substitution: stop double-appending a trailing backslash in an
  unterminated backtick span.
- utils readStdinJson: on overflow, settle and resolve {} immediately (clear
  timer + listeners) instead of waiting for end/timeout and parsing a partial
  prefix; surface the overflow on stderr.

Regression tests added/extended (new tests/hooks/pre-compact.test.js).

Addresses review feedback on #2405. The earlier block-no-verify change was
dropped: its message-value skip on merge/cherry-pick/am/rebase would let
`git rebase -m --no-verify` bypass the hook (rebase's -m is the boolean
--merge), a false-negative worse than the contrived false-positive it fixed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(ci): align hook fixtures and drain oversized stdin

---------

Co-authored-by: djpjronline-netizen <276112803+djpjronline-netizen@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-07-28 21:32:42 -04:00
6be87a56ae fix: clean promoted instinct sources (#2587)
* fix: clean promoted instinct sources

* test(instincts): normalize retained-content line endings

---------

Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-07-28 21:31:12 -04:00
536221cf7a fix(hooks): dedupe transcript usage by message.id in cost-tracker (~2.5-3x inflation) (#2483)
Claude Code writes one transcript JSONL line per content block, so a
single API response (one message.id) spans multiple assistant lines that
each repeat the same message.usage. sumUsageFromTranscript summed every
line, inflating token totals and estimated_cost_usd roughly 2.5-3x.

Verified on a real session: 704 assistant lines but only 286 unique
message.ids (2.46 lines/response on average); line-summing reported
$866.52 while the deduped total is $332.62. Usage payloads are identical
across lines of the same id (0/286 varied), so counting once per id is
equivalent to taking the last line per id.

Fix: collect usage into a Map keyed by message.id (last line wins) and
sum unique entries. Lines without a message.id (older transcript shapes)
keep the previous per-line behavior via a synthetic key, so existing
tests and old transcripts are unaffected.

Adds a regression test: a response split into 3 content-block lines with
the same message.id is counted exactly once.

Note: rows already written to ~/.claude/metrics/costs.jsonl by the old
code carry inflated token counts and estimates (except rows whose cost
came from the harness-cost cache, where cost is authoritative but token
counts are still inflated). Downstream consumers may want to annotate
history; this change intentionally does not rewrite the raw log.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 11:14:47 -07:00
Affaan MustafaandGitHub 382060905e fix: harden local dashboard and data boundaries (#2585)
* fix: harden local data boundaries

Bind the capabilities dashboard exclusively to loopback and reject untrusted Host and Origin values. Constrain project-configured agent data paths to the Cursor data root, and harden lifecycle repair/uninstall operations against state-file traversal, symlink swaps, unsafe sources, and forged install-state destinations.\n\nCloses #2506

* fix: eliminate repair source read race

Read source bytes and mode from one no-follow file descriptor so a path replacement cannot mix metadata from one inode with content from another. Add a regression that rejects separate path-based source metadata lookup.

* fix: close dashboard hardening review gaps
2026-07-27 11:11:29 -07:00
Affaan MustafaandGitHub 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 MustafaandGitHub 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.andGitHub 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
黄云龙andGitHub 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 MustafaandGitHub 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
Gaurav DubeyandGitHub 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 ParkandGitHub 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 DubeyandGitHub 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 MustafaandGitHub 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 751874fef9 Center README entry cards 2026-07-24 16:26:50 -04:00
haelyraandGitHub 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
haelyraandGitHub 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
Affaan Mustafa cf1fb0125e Fix README asset alignment 2026-07-24 11:52:30 -04:00
Affaan Mustafa 05a7695bc0 docs: align ECC entrypoints and Kimi setup 2026-07-24 03:58:50 -04:00
Affaan MustafaandGitHub e625a07736 docs: compact the sponsor logo row (#2565) 2026-07-23 23:44:42 -07:00
Affaan MustafaandGitHub 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 MustafaandGitHub 34fbe007f0 fix: reject credential-bearing Itō CLI shims (#2559) 2026-07-23 21:07:59 -07:00
Affaan MustafaandGitHub 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 MustafaandGitHub bc774282e6 feat: connect ECC to canonical Ito compute CLI (#2558) 2026-07-23 19:28:55 -07:00
Affaan MustafaandGitHub 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
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
KHandGitHub 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
JunandGitHub 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 KanjiyaniandGitHub 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 DoughanandGitHub 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 MustafaandGitHub 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
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
JongHyeok ParkandGitHub 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
Farda Karimov 4da4c7802f fix(scripts): detect modern bun.lock, ignore stray root lockfiles
Bun switched its default lockfile from the binary bun.lockb to the
text-based bun.lock, but detectFromLockFile() only ever checked for
bun.lockb — a project using modern Bun would never be detected as
using Bun at all.

Added bun.lock as the primary lockfile with bun.lockb kept as a
recognized legacy alias, so either format is detected correctly.

Also ignore stray bun.lock/bun.lockb at the repo root: yarn is this
repo's canonical package manager (package.json "packageManager"), so
a lockfile from someone running `bun install` locally shouldn't get
picked up by git status.
2026-07-19 19:39:23 +02:00
黄云龙andGitHub 5da21c2b66 fix(project-detect): parse Python deps pinned with ~ and @ (was losing framework detection on compatible-release pins) (#2498)
* fix(project-detect): parse Python deps pinned with ~= and @ direct references

* test(project-detect): cover ~= compatible-release and @ direct-reference parsing

* test(project-detect): cover direct references

* fix(project-detect): skip bare VCS/URL requirement lines in getPythonDeps

A requirements.txt line like git+https://host/repo.git#egg=pkg carries
no leading package name, so the delimiter split recorded the whole URL
fragment as a dependency. Skip names that start with git+ or contain a
URL scheme, and tighten the test assertions so any leaked URL, scheme,
or @ delimiter fails loudly.
2026-07-17 17:11:09 -04:00
黄云龙andGitHub 5d68ef3617 fix(plan-canvas): stop dropping list items when a block's first item is over-indented (#2501)
* fix(plan-canvas): stop dropping list items when a block's first item is over-indented

* fix: address greptile findings for PR #2501 - list-type detection and outdent nesting

- plan-canvas markdown: fix nested list rendering where outdented runs (indent
  6→4) create duplicate sibling UL blocks instead of sharing parent (#2501)
- transcript-context: add LARGE_WINDOW_NATIVE_MODEL_IDS array for models whose
  default context window is 1M but do NOT carry the [1m] marker (fixes #2497)
- Add test coverage for transcript-context and shell-substitution modules
- Add test coverage for project-detect module (#2498)

* fix(plan-canvas): handle outdented list runs

* fix(plan-canvas): start a new list when marker type changes at the same indent

CommonMark treats a marker-type change (bullet to ordered or back) at
the same indentation as the start of a new list. buildList previously
absorbed the run into the current list, so mixed runs rendered under a
single wrong tag. Stop the run on a tag change and let buildListBlock
render the next run as a sibling list with its own tag.
2026-07-17 17:10:58 -04:00
ThejeshandGitHub fb98726d0a fix(llm/providers/claude): attach cache_control to system block, not top-level (#2515)
* fix(llm/providers/claude): attach cache_control to system block, not top-level

The Anthropic Messages API does not accept `cache_control` as a top-level
request parameter — it is a per-content-block field. Passing it at the top
level raises `TypeError` in the Python SDK (which validates kwargs against
`messages.create()`'s signature) or a `400 unknown_parameter` from the API,
so every ClaudeProvider.generate() call fails.

Move `cache_control: {"type": "ephemeral"}` onto the last system-prompt
block so ephemeral prompt caching still works when a system prompt is
present, and drop it when there isn't one (nothing to cache).

Existing tests didn't catch this because `FakeMessages.create(**_params)`
accepted anything and ignored the kwargs. FakeMessages now records
`last_params`, and two regression tests assert that:
  - `cache_control` never appears as a top-level param, and
  - when a system prompt is set, `cache_control` rides on the last block.

Fixes #2512

* test(claude_provider): split composite isinstance+truthiness assertion (PT018)

Ruff PT018 flagged the combined `isinstance(system, list) and system` check
in `test_generate_does_not_pass_cache_control_as_top_level_param`. Split
it into two focused asserts (`isinstance(system, list)` then `assert system`)
so a failure points at the exact violation instead of a compound condition.

Behavior unchanged; 6/6 tests still pass.

Addresses CodeRabbit review on #2515.
2026-07-17 16:04:32 -04:00
Gaurav Dubey fafc832238 test(opencode): reject any namespace-scoped command agent id, not just the legacy prefix (#2477)
Address review: the frontmatter guard only rejected the `everything-claude-code:`
prefix, so a hypothetical future `<other-plugin>:agent` value could slip through.
opencode registers its inline agents unscoped, so assert the id carries no `:` at
all — rejecting the whole scoped class — alongside the existing
registered-agent-map membership check.
2026-07-10 09:58:03 +05:30
Gaurav Dubey 9d1ecb0754 fix(opencode): resolve command agent ids to registered opencode agents (#2477)
The `.opencode/commands/*.md` frontmatter referenced agents with the Claude
Code plugin namespace (`agent: everything-claude-code:<name>`), but ECC's
opencode integration registers its agents unscoped in `opencode.json`'s
`agent` map (`code-reviewer`, `planner`, ...), and that file's own `command`
section already references them unscoped. The `everything-claude-code:` scope
resolves under no opencode config (the opencode plugin package is
`ecc-universal`, and inline-config agents are bare), so subtask commands like
`/code-review` hard-fail with `Agent not found: everything-claude-code:code-reviewer`.
Non-subtask commands fall back to the default agent and appear to work — which
is why only some commands failed.

Strip the `everything-claude-code:` prefix from all 30 command frontmatter
agent ids so they match the registered agents, fix the MIGRATION.md example,
and replace the test that enforced the broken scoped invariant with one that
asserts each command agent id is a registered opencode agent (fails on the old
scoped ids, passes on the fix).

Fixes #2477
2026-07-10 09:46:40 +05:30
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>affaanDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
38a7ebbe32 fix(install): reference all curated skills in modules + reverse-coverage guard (#2431) (#2440)
* fix(install): reference all curated skills in modules + add reverse-coverage guard (#2431)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* test(install): normalize path separators in delivery-gate dry-run assertion (#2431)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-08 17:14:52 -04:00
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>affaanDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
67537ea480 fix(repair): build opencode payload so repair clears doctor's opencode-plugin-not-built warning (#2414) (#2438)
* fix(repair): build opencode plugin payload so repair clears doctor's opencode-plugin-not-built warning (#2414)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* refactor(repair): narrow validation bypass to specific codes; fix test-artifact cleanup (#2414 review)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-07-08 17:14:33 -04:00
a511395613 feat: Plan Canvas, a browser review canvas for plans (#2467)
* feat: add Plan Canvas - browser annotate-and-approve review for plan artifacts

- scripts/plan-canvas.js CLI (open/await/end/stop/server; bin ecc-plan-canvas)
- loopback server + ECC-styled chrome + annotation SDK + zero-dep markdown renderer
- Approve/Request-changes verdicts wired to the /plan confirmation gate
- plan-canvas skill, /plan-canvas command, SessionStart hook surfacing open reviews
- shared scripts/lib/loopback-guard.js extracted from control-pane (API re-exported)
- 121 new tests incl. full-workflow E2E; registered in manifests, catalog, registry

Inspired by lavish-axi (https://github.com/kunchenguid/lavish-axi) by @kunchenguid;
original ECC-native implementation, not a port.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* refactor(plan-canvas): invoke via ecc-plan-canvas bin so the skill works from any project

Skill/command referenced a cwd-relative `node scripts/plan-canvas.js`, unusable
outside the ECC root. Switch to the ecc-plan-canvas bin (and $CLAUDE_PLUGIN_ROOT
fallback) and align CLI next_step hints so an agent can run it as a skill in any repo.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(plan-canvas): render Mermaid diagrams + ship Codex cross-harness surface

- markdown renderer emits <pre class="mermaid"> for ```mermaid blocks (source
  entity-escaped so the browser decodes it for the renderer while blocking injection)
- artifact template loads a pinned Mermaid build only when a diagram is present,
  themed to ECC dark, securityLevel strict, graceful offline fallback to source
  (ECC_PLAN_CANVAS_MERMAID_URL overrides for a local mirror)
- skill teaches Mermaid-for-diagrams and states the CLI+JSON loop is harness-agnostic
- add .agents/skills/plan-canvas (Codex) with agents/openai.yaml interface manifest
- register in install-modules workflow-quality paths; docs updated

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* docs(plan-canvas): add demo screenshot

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(ci): sync yarn.lock with new bin; add contributor checklist

- yarn.lock records the ecc-plan-canvas bin so Yarn hardened-mode install no
  longer wants to modify the lockfile on public PRs
- PR template + CONTRIBUTING gain a pre-push checklist covering the lockfile
  trap and the full skill/command/CLI registration surfaces

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Haley Chen <2022hachen@gmail.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 17:12:48 -04:00
Affaan MustafaandGitHub 4130457d67 fix(tests): use mkdtempSync for test scratch dirs (CodeQL js/insecure-temporary-file) (#2443)
Replaces 54 predictable os.tmpdir()+Date.now() test-home paths in
tests/hooks/hooks.test.js and the pid-based transcript files in
tests/lib/llm-summary.test.js with fs.mkdtempSync. The 22
claude-tool-count-* sites are left as-is: they intentionally mirror
the path the production hook computes. Clears all 16 open code-scanning
alerts (#256-#271).
2026-07-04 13:44:27 -07:00
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>affaanDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>Affaan Mustafa
2d40baacbd fix: resolve open-issue cluster (#2295, #2298, #2303–#2306, #2340) + createdTime fallback bug (#2408)
* fix: resolve issue cluster (#2295,#2298,#2303,#2304,#2305,#2306,#2340) + createdTime fallback bug

- session-manager: fix createdTime birthtime||ctime fallback that never fired
  (a Date is always truthy); use birthtimeMs>0 check via resolveCreatedTime()
- installer: rewrite source-relative rules/skills links for the injected
  ecc/ namespace so installed skills resolve correctly (#2340)
- continuous-learning-v2: drop unused mock import (#2305); standardize bash
  shebangs (#2303); poll for PID file instead of fixed sleep (#2295);
  rename _ecc_* -> _clv2_* (#2304); align promotion confidence docs (#2298);
  de-brittle Scope Decision Guide cross-reference (#2306)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): resync lockfiles with package.json (eslint 10) + migrate yarn.lock to Yarn 4 format

package.json requires eslint@^10.6.0 but the committed locks pinned 9.39.2, so
npm ci aborted and Yarn 4 hardened mode rejected the stale v1-classic yarn.lock
(YN0028). Regenerate package-lock.json and rewrite yarn.lock in Yarn 4 (berry)
format so npm ci and immutable yarn installs both pass.

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(ci): require clean probe exit for Windows shell/bash detection; add pyyaml dev dep

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix(observer): portable mktemp template on BSD/macOS (#2417); correct false attribution-disabled claim in git-workflow docs (#2426) (#2430)

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: remove duplicate resolveCreatedTime introduced by merge (no-redeclare)

Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>

* fix: restore heading-based Scope Decision Guide ref (line numbers drift) + keep behavioral #2340 install test

---------

Co-authored-by: affaan <affaan@itomarkets.com>
Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
2026-07-03 21:10:45 -07:00