Commit Graph
227 Commits
Author SHA1 Message Date
haelyra 15815eca6a fix(install): advance guided state checkpoints safely 2026-08-24 21:30:19 -04:00
haelyra 3c005169b5 fix(opencode): route lifecycle through config overrides 2026-08-24 21:20:17 -04:00
haelyra bbf5493279 fix(release): clear final review blockers 2026-08-24 21:16:39 -04:00
haelyra e3a1ac6f3f fix(opencode): migrate legacy managed home installs 2026-08-24 20:59:57 -04:00
haelyra 8348fb990d fix(security): pin guided preflight reads before validation 2026-08-24 20:28:01 -04:00
haelyra 2c5a91a1d6 fix(release): make ECC 2.2 ready to publish 2026-08-24 20:15:12 -04:00
Santhi Prakashandhaelyra 0b04c1bfa1 fix(scripts): surface unreadable AGENTS.md in legacy codex sync detection
hasMarkerBlock previously swallowed every read/open error and returned
false, so an unreadable AGENTS.md (EACCES, EMFILE, EISDIR, ...) made
detectLegacyCodexSync report a clean Codex home instead of an
indeterminate inspection result. The fallback path could then skip
legacy cleanup and exit 0 with legacy artifacts still in place.

Restrict the catch to ENOENT (a missing file legitimately means no
marker block) and rethrow everything else. detectLegacyCodexSync
already propagates from hasMarkerBlock, so callers now see the actual
inspection error instead of a misleading 'no marker'.

Regression test in tests/lib/codex-legacy-sync.test.js makes a
detectLegacyCodexSync call against an unreadable AGENTS.md and asserts
that it throws something other than ENOENT, plus a sanity check that
a missing AGENTS.md still reads as no-marker.
2026-08-24 20:09:12 -04:00
56dafcc5e3 fix(scripts): require legacy ownership manifest for auto fallback
Restrict the automatic `uninstall` legacy Codex sync fallback to homes
that have a legacy ownership manifest (`~/.codex/ecc/legacy-sync-state.json`).
Marker-only AGENTS.md files are no longer auto-detected as legacy installs,
so a normal `uninstall` will not silently modify user-owned instructions.
The explicit `--legacy-codex-sync` flag still handles marker-only and
manifest-backed cleanup.

Also:
- Track the AGENTS.md path in removedPaths when a marker block is removed.
- Refactor codex home resolution into a helper.
- Add regression tests for marker-only auto vs. explicit behavior.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-24 20:09:12 -04:00
f4f5cf9027 fix(scripts): avoid false-positive legacy Codex sync detection
Tighten uninstall auto-detection so it only falls back to the legacy
sync-ecc-to-codex.sh path when there is an ownership manifest
(~/.codex/ecc/legacy-sync-state.json) or an ECC marker block in
~/.codex/AGENTS.md. Previously a clean Codex home with unrelated prompt
files could be misclassified as a legacy install, causing uninstall to
skip normal install-state reconciliation and exit with a partial warning.

Also make the no-state fallback return 'not-found' when there is no
marker to remove and no candidate files to clean, and make explicit
--legacy-codex-sync report the same on a clean home.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-08-24 20:09:12 -04:00
Alberto Varesioandhaelyra 4caab329db fix(opencode): install to ~/.config/opencode instead of ~/.opencode
OpenCode natively uses ~/.config/opencode per XDG conventions. The
install target was writing to ~/.opencode, which only worked on systems
where that path happened to be symlinked to ~/.config/opencode. The MCP
inventory reader already looked in ~/.config/opencode, so the installer
and reader were inconsistent.
2026-08-24 20:09:12 -04:00
dajiaohuangandhaelyra faaa21c4e4 fix(install): guard state before selective merge 2026-08-24 20:08:58 -04:00
dajiaohuangandhaelyra 64d7dc5da0 fix(install): merge state across selective installs 2026-08-24 20:08:58 -04:00
Affaan Mustafa 28a8fda568 fix: close Nasiko filesystem race windows 2026-08-15 21:47:57 -04:00
Affaan Mustafa 9ba25b9360 fix: harden Nasiko artifact lifecycle 2026-08-15 02:22:29 -04:00
Affaan Mustafa 0d39ae83dd feat: add pinned Nasiko control-plane bridge 2026-08-15 01:57:26 -04:00
haelyra 42d219e0de fix(security): reject Windows reparse digests 2026-08-13 18:29:21 -04:00
haelyra 60ab63fe21 fix(security): pin installer checkpoint reads 2026-08-13 18:21:21 -04:00
haelyra 08edb1cb92 fix(install): checkpoint interrupted migrations 2026-08-13 18:17:26 -04:00
haelyra 9e39385666 fix(install): close reviewed reliability gaps 2026-08-13 18:03:37 -04:00
haelyra 01335551a3 fix(uninstall): preserve path identity and user drift 2026-08-13 18:02:06 -04:00
haelyra 8dc6a8e73a fix(uninstall): close quarantined files before removal 2026-08-13 17:30:38 -04:00
haelyra efdf17b034 fix(security): verify legacy files after opening 2026-08-13 17:20:48 -04:00
haelyra 3f5bf22966 fix(security): enforce no-follow semantics on Windows 2026-08-13 17:16:53 -04:00
haelyra bab38ae91b fix(security): close installer filesystem races
Use no-follow file descriptors for legacy Codex snapshots, verification, restoration, and marker cleanup. Quarantine candidate removals and verify inode identity before deletion.

Carry the lifecycle runner as a verified artifact so privileged release workflows never dynamically check out and execute an output-selected revision.
2026-08-13 16:59:06 -04:00
1db5c8ab4a fix(install): harden ECC installer lifecycle
Make Antigravity 2.0 installs native and safely migrate legacy state. Ensure doctor, repair, status projection, repeat installs, legacy Codex sync, and uninstall converge without losing user files. Exclude Python bytecode and harden repo-scan bootstrap guidance.

Gate publishing and pull-request merges on one exact packed artifact completing install, repeat, drift, repair, status, and uninstall across Linux, macOS, and Windows.

Co-authored-by: lorencifernando-coder <lorenci.fernando@gmail.com>

Co-authored-by: Suliman Abdulrazzaq <suliman9000a@gmail.com>

Co-authored-by: Wu Shuwen <mikewushuwen@outlook.com>
2026-08-13 16:42:51 -04:00
eb49702651 feat: thin Pi adapter mounting ECC's canonical skills and commands (#2759)
* feat: add thin Pi adapter mounting ECC's canonical skills and commands

Adds first-class Pi (@earendil-works/pi-coding-agent) support as a thin
adapter layer, following the maintainer review on #2352. ECC's canonical
assets stay the single source of truth: nothing is copied or generated
under .pi/.

The `pi` manifest in package.json points Pi directly at `skills/` and
`commands/`. No transformation is needed — ECC's SKILL.md files already
follow the Agent Skills standard Pi implements, and ECC's command
frontmatter is already Pi's prompt-template format.

.pi/extensions/index.ts is the only adapter logic. It:

- uses Pi's documented `pi.on(...)` lifecycle, not an undocumented event bus
- resolves hook scripts from the installed package via `__dirname`, never
  `process.cwd()`, so global installs work from any project directory
- runs hooks with `execFile(process.execPath, [...])` and no shell, so paths
  containing spaces or shell metacharacters are safe
- invokes hooks through ECC's own `run-with-flags.js`, so `ECC_HOOK_PROFILE`
  and `ECC_DISABLED_HOOKS` keep gating hooks under Pi
- runs hooks in the user's project directory so project detection stays
  correct, while resolving the scripts themselves package-relative
- injects the SessionStart hook's `additionalContext` into the system prompt
  on the next `before_agent_start`
- isolates hook failures behind a timeout and an output limit
- registers `/ecc-doctor` for install diagnostics

Registers `.pi` in the platform-configs install module and adds a Pi row to
the harness adapter compliance matrix.

Verified against Pi 0.84.1: a global `pi install` exposes 285 skills and 94
commands resolved from `skills/` and `commands/`, plus `/ecc-doctor`, with
no generated copies.

Scope deliberately excludes subagents, chains, approval gates, todos,
profiles, and MCP; ECC works in Pi without any companion package.

* fix: address review findings on the Pi adapter

Bot review on #2759 surfaced two real runtime defects and several
hardening gaps.

Runtime fixes:

- Attach an `error` listener to the hook child's stdin. `stdin.end()`
  writes asynchronously, so a hook that exits, short-circuits, or is
  killed by the timeout before reading the payload raises EPIPE as an
  `error` event that the surrounding try/catch cannot see. Unhandled,
  that event would terminate the Pi session and break the isolation
  guarantee the adapter documents.
- Clear `pendingContext` at the top of the `session_start` handler. Pi
  can start a new session (/new, /resume, /fork) before
  `before_agent_start` consumes the previous value; if the newer hook
  then failed, the next agent start received context describing a
  different session's project state.
- Replace `require.resolve` companion detection with a read of Pi's own
  `packages` list, honoring `PI_CODING_AGENT_DIR`. Pi installs packages
  under its config directory, which is not on Node's module resolution
  path from the extension, so the previous check reported every
  companion as missing no matter what was installed.

Compliance matrix: remove internal semicolons and a trailing period from
the Pi record's list entries. The renderer joins entries with "; ", so
those characters split one entry into several in the rendered cell.

Tests: run profile gating against the temp skeleton instead of the real
checkout so it cannot leave marker artifacts behind; count files under
.pi/ by walking disk rather than git, so untracked copies cannot bypass
the regression guard; allow negated phrasing in the README heuristic;
pin the adapter's real parser guards with source assertions so the local
mirrors cannot silently diverge; add coverage for EPIPE isolation, stale
context clearing, and companion detection.

* docs: point users at existing companion Pi packages instead of bundling them

Every capability listed as out of scope is already provided by a maintained
community Pi package: pi-subagents, @juicesharp/rpiv-ask-user-question,
@juicesharp/rpiv-todo, and pi-mcp-adapter for MCP.

Pi supports pulling other pi packages in via dependencies plus
bundledDependencies, but this adapter deliberately does not. Bundling would
ship third-party code that executes with full user permissions in every ECC
install, turn optional capabilities into mandatory ones, and add four
fast-moving pins to maintain.

Instead /ecc-doctor now prints the exact `pi install npm:<name>` command for
each companion it does not find, so adopting one stays a deliberate user
choice.

Also corrects the MCP claim: Pi core has no MCP surface by design, but the
community pi-mcp-adapter package adds one. This adapter neither installs nor
verifies it, and ECC's MCP reference configs are not known to be compatible.

* docs: ECC's MCP configs work in Pi through pi-mcp-adapter, verbatim

Tested rather than assumed. The community pi-mcp-adapter package reads the
standard mcpServers format from .mcp.json and ~/.config/mcp/mcp.json, which
is exactly the format ECC already uses in .mcp.json and
mcp-configs/mcp-servers.json.

Verified against pi-mcp-adapter 2.21.2 in an isolated PI_CODING_AGENT_DIR:
copying mcp-configs/mcp-servers.json to a project's .mcp.json registers Pi's
`mcp` tool and `/mcp` command with all 35 ECC servers discovered, coexisting
with this adapter's /ecc-doctor. No translation layer and no ECC change are
needed, so this stops being a limitation and becomes documentation.

Recorded caveats: the adapter's first run against a new config performs
initialization that blocks in non-interactive mode, and only discovery was
verified, not live tool invocation.

ECC still neither installs nor depends on the package.

* feat: inject ECC's canonical engineering rules into Pi's system prompt

ECC's rules were the one durable asset the adapter did not deliver: skills
and commands reached Pi in full, but the 122 rule files that carry ECC's
coding style, testing, security, git workflow, and code-review standards
did not, so ECC in Pi was a library of skills rather than a set of
enforced standards.

Rules are read at runtime from the canonical rules/common/ directory of
the installed package and appended to the system prompt inside an
<ecc-engineering-rules> block. Nothing is copied or generated under .pi/,
which keeps the single-source-of-truth constraint this PR exists to
satisfy. Injection reuses the before_agent_start path already built for
session context, so no new lifecycle mapping is introduced.

Rules are re-applied every turn because they are standing policy, while
the session context stays one-shot and is consumed on first use.

agents.md, hooks.md, and performance.md are excluded: they describe Claude
Code primitives Pi does not have (Task/TodoWrite delegation, Claude hook
event types, thinking-budget toggles), so injecting them would point the
model at tools that are not there. A test asserts they stay excluded, and
a leakage test asserts none of those primitives appear in the injected
text. Language-specific rules under rules/<language>/ are out of scope for
this first adapter.

Injection is bounded by MAX_RULES_BYTES and can be disabled with
ECC_PI_RULES, following ECC's existing off-switch convention. /ecc-doctor
reports the state and injected size.

Measured on this repo: 7 files, 12,361 characters, roughly 3k tokens.

Also replaces a Function() call in the test helper with direct arithmetic,
and repins a stale assertion that pinned one spelling of the context
handoff rather than the guarantee (read before clear, clear before return).

* fix: /ecc-doctor misreported filtered packages and partial rule installs

Two reporting defects in /ecc-doctor, the command whose whole job is telling
a user what is actually installed.

Pi's settings accept a `packages` entry in two shapes: the bare source string
("npm:pi-subagents") and an object carrying that source alongside resource
filters ({ source: "npm:pi-subagents", skills: [] }). normalizePiPackageName
only recognized the string, so a user who narrowed which resources a companion
contributes was told the companion was not installed, along with an install
command for something already present. The source type still decides whether a
name is comparable, so an object wrapping a git source or a path stays
unrecognized exactly as before.

loadPortableRules drops rule files it cannot read, drops empty ones, and stops
at MAX_RULES_BYTES, but describeRulesStatus reported PORTABLE_RULE_FILES.length
regardless. A partial install that loaded 3 of 7 files reported "7 rule file(s)"
to the one command a user runs to find a partial install. The loaded count is
now tracked next to the cache and reported as a ratio, with the shortfall named.

Also reconciles the Notes bullet in .pi/README.md, which still called MCP out of
scope after the MCP section landed documenting that ECC's configs load in Pi
through pi-mcp-adapter.

Both defects were reported by CodeRabbit and verified against Pi's own
packages.md before fixing. Adapter tests go from 24 to 26; the two source
contracts that pinned the previous spellings now pin the new guards, so the
object-form unwrapping and the loaded-count reporting cannot be silently
reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-12 18:41:33 -04:00
01e15490f0 fix(skill-evolution): wire Skill PostToolUse tracker so skill-health shows real runs (#2490)
* fix(skill-evolution): wire Skill PostToolUse tracker so skill-health shows real runs (#2463)

recordSkillExecution() had no production callers, so
~/.claude/state/skill-runs.jsonl was never written and
`scripts/skills-health.js --dashboard` always reported 0 runs.

Adds scripts/hooks/skill-run-tracker.js and registers it as an async
PostToolUse hook (matcher: Skill) in posttooluse-dispatcher.js, which is now
the single PostToolUse entrypoint on main.

Addresses the privacy and bounds review on #2555's sibling PR:

- No prompt text is persisted. task_description is synthesized as
  "Skill invocation: <skill_id>"; tool_input.task_description/description/
  prompt are never read.
- Every persisted string is bounded and charset-restricted. A skill id is an
  identifier, so free text, newlines, or an over-long value are dropped rather
  than truncated and written through.
- The JSONL sink is created 0600 and re-tightened on each append, repairing
  files written before this bound existed.
- The sink is capped at MAX_RUN_RECORDS (5000), trimmed oldest-first, so the
  append-only file can no longer grow without limit.

Tests cover the privacy guarantee (no prompt text reaches a record), the
identifier bounds, the file mode on POSIX, and the retention cap.

* fix(skill-evolution): re-register the tracker for PostToolUseFailure

The rebase onto current main dropped the hooks.json entry, which silently
resurrected the P1 from the earlier review round: deriveOutcome() still
branches on hook_event_name === 'PostToolUseFailure', but the PostToolUse
dispatcher does not fan that event out, so the branch was unreachable in
production. Hard Skill failures were dropped from telemetry entirely, which
inflates the dashboard success rate — the opposite of what #2463 asks for.

Restores the dedicated PostToolUseFailure entry (matcher Skill, id
post:skill:track, same run-with-flags wrapper and standard,strict gating as
the dispatcher registration). Verified end-to-end: a PostToolUseFailure
payload piped through run-with-flags now records outcome "failure".

Adds a regression test asserting the registration so a future rebase cannot
quietly drop it again.

---------

Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-08-12 18:12:49 -04:00
haelyraandGitHub 569b1d5b32 fix: disable Claude co-author attribution by default (#2758)
* fix: disable Claude co-author attribution by default

* fix: harden default co-author opt-out and correct the docs

Follow-up on the co-author default in this PR.

- Remove the existsSync/writeFileSync race in the installer settings write
  (CodeQL js/file-system-race, high). A single guarded read now covers the
  fresh-install case, and unreadable or non-object settings are left untouched.
- Respect `attribution` as an explicit user choice. It supersedes
  `includeCoAuthoredBy` in Claude Code 2.1.x, so a user who configured it would
  otherwise have had a dead key written into their settings.
- Share one opt-out rule via scripts/lib/claude-commit-attribution.js instead of
  duplicating it across the installer and plugin setup.
- Update the git-workflow rule and its nine mirrors and translations, which
  still told users ECC does not ship this setting.

We keep writing the deprecated `includeCoAuthoredBy` key rather than
`attribution`: unknown keys fail Claude Code settings validation, so writing
`attribution` would break users on older versions.
2026-08-12 00:43:58 -04:00
ff2280a318 fix(plan-canvas): guard localStorage so blocked site data can't disable canvas controls (#2703)
Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-08-12 00:34:15 -04:00
5987bd4dc6 feat(session-start): rank injected instincts by project/stack relevance (#2466)
* feat(session-start): rank injected instincts by project/stack relevance

Instinct selection at SessionStart ranked purely by confidence, so a
high-confidence instinct about an unrelated stack could take an injection
slot from a lower-confidence instinct that is actually relevant to the
current project.

Rank by confidence + location/stack relevance instead: project-scoped
instincts, and instincts whose domain/trigger matches the detected stack
(languages/frameworks via detectProjectType, plus terraform/dbt markers),
get a small additive boost. The confidence>=threshold floor and the
injection cap are unchanged, and ranking degrades to confidence-only when
nothing matches or when ECC_INSTINCT_RELEVANCE_RANKING is set to off.

The ranking helpers live in scripts/lib/instinct-relevance.js with unit
coverage in tests/lib/, plus an end-to-end ordering test in tests/hooks/.

Completes part (b) of #2371; part (a) (configurable count + threshold)
shipped in #2413.

Fixes #2371

* refactor(session-start): drop redundant confidence tiebreaker in instinct sort

Greptile flagged that the secondary `right.confidence` comparison in
summarizeActiveInstincts' sort was dead code when relevance ranking is
disabled and, when enabled, was reached only on a floating-point tie of the
combined score — where it skipped the intended scope-label tiebreaker.

Remove it: the primary combined-score comparison already reduces to
confidence-only ordering when relevance is off, so behavior there is
unchanged; a genuine combined-score tie now falls through to the documented
scope-first, then id, order.

* test: isolate instinct relevance environment

---------

Co-authored-by: haelyra <49814733+haelyra@users.noreply.github.com>
2026-08-10 21:46:24 -04:00
ae303fb6c1 fix(plan-canvas): deliver browser chat to the agent every time (#2739)
Feedback sent from the canvas only reached an agent through a live
/api/await long poll. When a turn ended with no await parked,
queueFeedback wrote the message to sessions.json and nothing ever
consumed it, so sending appeared to do nothing at all. The presence pill
made it worse: workingKeys had no expiry and the feedback handler never
broadcast presence, so it froze on "agent working" while nobody was
listening.

Delivery:
- Add the stop:plan-canvas-pending hook. It drains undelivered feedback
  and blocks the Stop, handing the messages to the agent, so a canvas
  message lands even when no await is running. Scoped to sessions under
  cwd so parallel agents cannot swallow each other's feedback; set
  ECC_PLAN_CANVAS_STOP_SCOPE=all to widen. Honors stop_hook_active and
  fails open on every error path.
- run-with-flags.js did not await a hook's run(), so any async hook
  silently degraded to pass-through. Fixed; plan-canvas-pending is the
  only async hook today.

Presence and indicators:
- Presence is now ended/typing/thinking/listening/queued/waiting.
  thinking and typing self-expire (90s/30s) and a 5s sweep pushes the
  decay to an idle browser, so the pill can no longer stick.
- Broadcast presence when feedback is queued, and clear the activity
  state when an agent reply lands.
- Add POST /api/session/:key/typing so agents can drive the indicator.
- Chat shows an animated dots bubble for thinking and typing, plus an
  explicit note when a message is queued with nobody listening.
  Respects prefers-reduced-motion.
- Send status reports what actually happened instead of always claiming
  the agent will pick it up.

CLI and skill:
- Add `ecc-plan-canvas pending` and `typing <file> --state ...`.
- SKILL.md documents background await as the primary pattern and makes
  replying in the canvas mandatory.

Tests: 6 new server cases covering queued presence, the typing endpoint,
state expiry and the sweep, plus a new hook suite covering delivery,
drain-once, stop_hook_active, cwd scoping and fail-open.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-09 18:15:25 -04:00
Kumar PrateekandGitHub 51a6950bde fix(memory-vault): compare dev only when both stats report one (#2637)
ecc memory writes and --body-file reads fail on Windows. sameFileIdentity()
compares the dev field of a path-based stat against a handle-based fstat, and
libuv 1.49.0 through 1.50.x resolve path-based stat() and lstat() on Windows
through GetFileInformationByName, which leaves the volume serial unset while
fstat() reports it. The comparison never matches, so the TOCTOU guard rejects
every operation.

Keep the inode strict and compare dev only when both sides report one. POSIX
always reports a non-zero dev, so the original strict behaviour is preserved
there.

Request the guard's stats as BigInt. On the affected libuv versions dev is 0,
which leaves the inode as the only identity signal, and Windows file IDs run
past Number.MAX_SAFE_INTEGER where two distinct files can collapse to the same
number-valued inode.

Fixes #2626
2026-08-08 17:06:18 -04:00
Affaan MustafaandGitHub 9de131420b fix(ito-compute): complete device auth lifecycle (#2706) 2026-08-07 14:53:13 -04:00
28e53a0bc1 feat(install): add guided multi-harness installer (#2649)
* feat(install): add guided Claude plugin setup

* fix: support Claude command shims on Windows

* feat: support safe Claude plugin scope migration

* fix(install): preserve interactive setup terminal

* fix(install): auto-migrate setup scope changes

* feat(install): add guided multi-harness installer

* fix(install): sync Yarn binary metadata

* fix(install): handle wizard EOF on Node 18

* ci: allow installer matrix tests to finish

* test(install): allow slower PowerShell delegation

* fix(install): harden guided provider reconciliation

* test(install): harden packaged and local compatibility

* chore: prepare guided installer release 2.2.0

* fix(install): report refreshed Codex marketplace state

* fix(install): verify managed content provenance

* test(install): allow empty Yarn smoke fixture

* test(install): invoke Windows package shims safely

* fix(install): close cross-platform release gaps

* fix(install): require trusted GitHub origins

* fix(install): preserve hook profile precedence

* refactor(install): centralize trusted GitHub origins

* ci: retrigger workflow run after merge of main

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

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-06 15:39:49 -04:00
Affaan MustafaandGitHub 623f2c020f Add bounded harness evaluation and rollback loop (#2686)
* feat(ecc2): add bounded harness evaluation loop

* fix(ecc2): preserve harness evidence and legacy IDs
2026-08-05 18:17:10 -04:00
haelyraandGitHub f1fec0e539 feat: add retention feedback loop and honest support matrix (#2681)
* feat: add retention feedback loop

* test: retire obsolete README parity row guard

* fix: harden public feedback guidance

* fix: let feedback CLI output flush

* test: keep feedback help coverage focused
2026-08-04 21:42:25 -04:00
f235549cb8 fix(install): exclude ECC skills from antigravity install target (#2680)
* fix: exclude ECC skills from antigravity install target

* test(install): cover antigravity skills exclusion

Two tests encoded the collision the parent commit fixes.

install-manifests used skills/example as its example of a supported
antigravity path; it now asserts skills are filtered and uses
commands/example for the positive case, so the test still proves
supported paths survive filtering.

install-apply asserted .agent/skills/tdd-workflow/SKILL.md exists. That
directory is antigravity's agent directory and already receives ECC
agents/, so the assertion was pinning ECC skills and ECC agents to the
same destination. Inverted, with the reason recorded inline.

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

---------

Co-authored-by: Calum Reeves <reevesc88@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 16:57:27 -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
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
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
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 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
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 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 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
Haley Chen b6fe5a71e1 fix: harden plan canvas code scanning alerts 2026-07-22 16:28:07 -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