Commit Graph
280 Commits
Author SHA1 Message Date
haelyra dac154eff6 test(opencode): cover override lifecycle routing 2026-08-24 21:18:54 -04:00
haelyra 01779a4a2b test(release): cover final review blockers 2026-08-24 21:14:29 -04:00
haelyra e3f2a537f9 test(opencode): cover legacy migration boundaries 2026-08-24 21:01:06 -04:00
haelyra e3a1ac6f3f fix(opencode): migrate legacy managed home installs 2026-08-24 20:59:57 -04:00
haelyra 55a2d4823b test(opencode): cover legacy managed root migration 2026-08-24 20:53:53 -04:00
haelyra d0e14ed8f6 test(opencode): align repair fixtures with canonical home 2026-08-24 20:17:03 -04:00
haelyra 2c5a91a1d6 fix(release): make ECC 2.2 ready to publish 2026-08-24 20:15:12 -04:00
haelyra 528dbea019 test(security): reject symlinked guided install sources 2026-08-24 20:13:18 -04:00
dajiaohuangandhaelyra da1faf1400 test(pack): select the requested package 2026-08-24 20:09:12 -04:00
dajiaohuangandhaelyra 6d42f32ca8 fix(tests): support npm pack object output 2026-08-24 20:09: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
dajiaohuangandhaelyra faaa21c4e4 fix(install): guard state before selective merge 2026-08-24 20:08:58 -04:00
dajiaohuangandhaelyra 55c3cb5bb0 test(install): cover non-Claude state merging 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
haelyra 6e66dfbae8 test(release): add ECC 2.2 readiness regressions 2026-08-24 20:08:41 -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 01335551a3 fix(uninstall): preserve path identity and user drift 2026-08-13 18:02:06 -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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
devin-ai-integration[bot]GitHubDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>affaanDevin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
3af4676e99 refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368) (#2410)
* 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>

* refactor: consolidate duplicated hook-root resolver into shared resolveEccRoot() (#2368)

The inline node -e resolver blob was duplicated ~60x across hooks.json,
command docs, and translations. Each copy inlined the full ~700-char
plugin-root search using a spread over nested array literals
(p.join(d,'plugins',...s) over [['ecc'],...]), which breaks Windows hook
execution due to shell quoting (#2368).

Collapse every copy to a 250-char locator that loads the committed
resolve-ecc-root module and delegates to resolveEccRoot() — no spread, no
nested array literals, no escaped double quotes. The real search logic now
lives in one tested module. Also route session-start-bootstrap.js through
resolveEccRoot() instead of its own duplicated reimplementation, and fix
the auto-update.md 'marketplace' (singular) typo along the way.

Guard tests updated: discovery behavior is asserted against resolveEccRoot();
the inline is asserted to delegate and to contain no Windows-fragile
constructs.

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

* fix(resolve-ecc-root): restore full env-unset discovery in inline resolver

Address Greptile review on #2410: when CLAUDE_PLUGIN_ROOT is unset the
delegating inline could only load the resolver module from ~/.claude,
returning ~/.claude without ever reaching the plugin/cache search. Restore
the old inline's discovery breadth (exact plugin roots + versioned cache)
Windows-safely (no spread, nested arrays, or escaped quotes), then delegate
the authoritative decision to resolveEccRoot(). Add regression tests for
plugin-subdir and versioned-cache bootstrap with env unset.

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-03 20:01:17 -07:00