215 Commits
Author SHA1 Message Date
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
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
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
754b8dd76c fix: make the installer runtime pass strict supply-chain vetting (#2503)
* fix: make the installer runtime pass strict supply-chain vetting

Remediate the four enterprise supply-chain vetting blockers from
affaan-m/ECC#2502 so the installer runtime (package.json + manifests +
scripts/lib/**) passes strict exact-pin evidence policy:

1. Remove the package.json `postinstall` lifecycle script (it only echoed a
   post-install banner) and move that banner to an explicit opt-in
   `npm run welcome` command. No install-time lifecycle script remains.
2. Exact-pin every dependency in package.json (dependencies + devDependencies)
   to the versions already resolved in package-lock.json; no ^/~ ranges.
3. Replace non-ASCII characters on the installer runtime script/config surface:
   em-dashes (U+2014) in scripts/lib/{path-safety,install-executor,
   install/link-rewrite}.js comments and the two "Itô" (U+00F4) occurrences in
   manifests/{install-components,install-modules}.json descriptions become
   ASCII, so strict-surface Unicode scanners are clean.
4. Drop the bare `require("ajv")` from scripts/lib/install-state.js; the file
   already carries a complete hand-rolled validator enforcing the same
   schemas/install-state.schema.json (ecc.install.v1) constraints, so the
   installer closure is dependency-free (zero non-builtin bare requires).

Refs affaan-m/ECC#2502

* fix: avoid unpinned welcome invocations

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: validate translated skill frontmatter

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: repair skill frontmatter YAML

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>

* fix: add MIT license to core skill manifests; pin verification-loop tsc invocation

* fix: preserve tsc/pyright exit status in verification-loop type-check (set -o pipefail)

* chore(deps): sync lockfiles with exact-pinned package.json

Regenerate package-lock.json and yarn.lock so the pinned dependency
specs are reflected in both lockfiles. npm ci and Yarn's --immutable
install now pass the sync check. The resolution tree is unchanged
(231 yarn resolutions, byte-identical set; zero npm transitive drift);
only the root descriptor strings move from ranges to the versions
already resolved in the committed lockfiles.

Addresses the Codex P1 on #2503.

---------

Signed-off-by: Samar Tomar <samar_tomar@hotmail.com>
Co-authored-by: Samarjeet Singh Tomar <samartomar@gmail.com>
2026-07-17 17:13:49 -04: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
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 49128b5763 feat(install): add Kimi Code CLI install target (kimi-project adapter) (#2441)
Rebuild of #2154 on current main, following the hermes/openclaw (#2433)
adapter recipe: 10-line kimi-project adapter (project kind, ./.kimi root),
registry + helpers ownership, SUPPORTED_INSTALL_TARGETS + legacy-compat
modules, kimi target on the 5 shared modules + .kimi in platform-configs
paths, both schema enums, npm files allowlist, help text, README stub.

Credit to @MoYiC6 for the original adapter design in #2154.
2026-07-03 22:24:13 -07:00
c837139e6c feat: add Hermes and OpenClaw harness install targets (#2433)
* feat: add Hermes and OpenClaw harness install targets

- Add scripts/lib/install-targets/hermes-home.js and openclaw-home.js
- Register new adapters in registry.js and helpers.js
- Add hermes/openclaw to SUPPORTED_INSTALL_TARGETS, schema enum, and install help text
- Add .hermes/ and .openclaw/ platform source directories with READMEs
- Update install-modules.json so rules/agents/commands/platform-configs cover the new targets

Verification:
- npx ecc doctor reports all 13 targets OK (including hermes-home and openclaw-home)
- install-targets regression guard passes for new targets
- Catalog check passes

* fix(install): register hermes/openclaw in install-modules schema enum + npm files allowlist

---------

Co-authored-by: Lxcardoza993 <265670745+Lxcardoza993@users.noreply.github.com>
Co-authored-by: Affaan Mustafa <me@affaanmustafa.com>
2026-07-03 22:20:17 -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
Gaurav DubeyandGitHub 0a926b45ba fix(install): rewrite relative skill links for injected ecc namespace (#2399)
* fix(install): rewrite relative skill links for injected ecc namespace

Skill and rule markdown is byte-copied during a claude install, but the
home/project adapters inject an `ecc/` namespace segment
(skills/<id> -> skills/ecc/<id>, rules/<x> -> rules/ecc/<x>). Source-relative
links such as `../../rules/react/hooks.md` therefore broke after install: the
extra level changed what `../..` resolved to, and the link target itself moved
under rules/ecc/.

Rewrite relative links in namespaced markdown so they resolve to the file's
actual installed location, derived from the plan's own file placements (no
hardcoded namespace literal, so the links cannot drift from where files land).
Non-namespacing adapters and links to non-installed targets are left untouched;
URLs, anchors, absolute paths, and fenced code blocks are never rewritten.

Fixes #2340

* fix(install): keep non-namespaced markdown on the byte-for-byte copy path

Address review feedback: the markdown branch in applyInstallPlan diverted every
copy-file markdown operation through read+rewrite+write, so identity-mapped
markdown (source path == install path, no namespace injected) lost byte-for-byte
content and source mode bits even though no link rewrite was needed.

Gate the rewrite on isNamespacedSource() so only files whose install path
actually changed (e.g. skills/x -> skills/ecc/x) leave the copyFileSync path;
everything else is copied verbatim as before.

* test(install): emit failure stack in the link-rewrite test runner

Address review feedback: the local test() harness logged only error.message,
so a failing assertion lost its source line and diff. Print error.stack on
stderr on failure so broken rewrite cases stay diagnosable.
2026-07-03 20:39:24 -07:00
Gaurav DubeyandGitHub c8c83ef428 fix(install): dedupe copy-file operations sharing a destination (#2429)
OpenCode ships override command files under .opencode/commands/ that
shadow the generic commands/*.md sources. The manifest install plan
recorded both writes against the same destination, so `ecc doctor`
reported perpetual drift for the 29 shadowed command files and `ecc
repair` "fixed" that phantom drift by copying the generic source over
the correct override, corrupting the installed command while never
clearing the warning.

Dedupe copy-file operations by destination in createManifestInstallPlan,
keeping the last writer to match the sequential apply order. install,
repair, and doctor all consume this one builder, so a fresh install is
clean and a single repair rewrites drifted state green.

Fixes #2414
2026-07-03 20:37:32 -07:00