Commit Graph

186 Commits

Author SHA1 Message Date
Affaan Mustafa c8caf193c4
feat: worktree-lifecycle service (deterministic conflict prediction + safe GC) (#2164)
* feat: add worktree-lifecycle service (ecc.worktree-lifecycle.v1)

The "unowned moat" from the orchestrator landscape research: no existing
tool ships deterministic merge-conflict prediction or a safe worktree GC.

- scripts/lib/worktree-lifecycle/git.js: injectable, hermetic git layer.
  Predicts merge conflicts WITHOUT touching the working tree via
  `git merge-tree`. Strips inherited GIT_* env so it is safe inside hooks.
- scripts/lib/worktree-lifecycle/lifecycle.js: deterministic state machine
  (main/dirty/conflict/merge-ready/merged/stale/idle) + planCleanup that
  buckets worktrees into remove / salvage / keep. Only fully-merged trees
  are auto-removable; stale (unmerged+inactive) => salvage, never deleted.
- scripts/worktree-lifecycle.js: CLI (--json/--conflicts/--stale/
  --cleanup-plan/--base/--stale-days/--repo).
- tests/lib/worktree-lifecycle.test.js: 11 tests (fake-git + real-git).

Safety model mirrors the reference-arch salvage rule, validated by the
2026-06-05 MacBook->Mac Mini consolidation. Tests: 11/0.

* fix: hermetic git env in session adapters + mcp-inventory lint

- session adapters (codex-worktree, opencode): resolveGitBranch stripped
  no git env, so the "outside a repo" path returned the host branch when
  run inside a git hook (GIT_DIR set). Strip GIT_* before rev-parse.
- mcp-inventory: fix eslint no-unused-vars (signatures) and a stale
  eslint-disable directive in the merged code.

* test: run each test with inherited git env stripped (hermetic runner)

When the suite runs inside a git hook (pre-push), git sets GIT_DIR/
GIT_WORK_TREE, which hijack 'git -C <dir>' calls in tests that exercise
real git, making them operate on the host repo. Strip GIT_* before
spawning each test so the suite is isolated from ambient git state.

---------

Co-authored-by: ECC Test <ecc@example.test>
2026-06-07 13:00:08 +08:00
Affaan Mustafa 7113b5bf63
feat: MCP inventory (ecc.mcp.v1) — unified cross-harness MCP config view (#2146)
* feat: add MCP inventory (ecc.mcp.v1) across harnesses

Read-only MCP-gateway groundwork: discover MCP server configs across
every installed harness, normalize to a canonical ecc.mcp.v1 inventory,
redact secrets, and report which servers are configured in 2+ harnesses
(the configure-N-times pain). The read+dedup side of a unified gateway,
mirroring how the session-adapter layer started read-only.

Readers (per-harness config formats):
- claude-code: ~/.claude.json mcpServers + project .mcp.json
- codex: ~/.codex/config.toml [mcp_servers.*] TOML via @iarna/toml
- opencode: ~/.config/opencode/opencode.json mcp block (command ARRAY)

canonical-mcp.js:
- normalize transport labels (local=>stdio, remote=>http) to stdio/http/sse
- merge servers by name across harnesses; flag DRIFT when signatures differ
- fragmentation report + aggregates
- SECRET REDACTION: env values stripped to key names; secrets in args
  (--modelApiKey sk-ant-...), inline --flag=secret, and URL userinfo/token
  query params all redacted before storage AND before the dedup signature.

scripts/mcp-inventory.js: CLI (--json, --fragmented, --help).
tests/lib/mcp-inventory.test.js: 12 tests incl. a regression for the
real arg-carried-secret leak found while smoke-testing on live configs.

Tests: 12/0. Real-data smoke: 33 servers across 3 harnesses, 21
configured in 2+ harnesses (7 drift); secret-leak audit clean.

* test: cover reader error paths, collect skip-logic, and CLI main() for mcp-inventory

Lift global branch coverage past the 80% gate (was 79.86%). Adds 6
tests exercising: missing-file/malformed-JSON/missing-block reader
fallbacks, codex no-parser path, collect skipping non-function readers
and swallowing reader errors, CLI usage()/main() help+json+human paths,
and formatHumanReport no-fragmentation + fragmented-only branches.

Also scrub a real API-key fragment that had leaked into a test fixture;
all secret-like fixtures are now obviously-fake FAKE... tokens.

mcp-inventory.js branch 30%->93%, collect.js ->100%. Global branch 80.33%.
2026-06-06 03:55:17 +08:00
Affaan Mustafa ab5e17fea9
feat: extend session-adapter layer with codex-worktree + opencode adapters (#2145)
* feat: add codex-worktree session adapter

Adds the third session adapter (after dmux-tmux and claude-history),
normalizing Codex rollout sessions into the harness-neutral
ecc.session.v1 snapshot. Reads ~/.codex/sessions rollout JSONL,
derives objective (skipping the AGENTS.md preamble + leading message
UUID), model, originator, worktree cwd, and best-effort git branch.

This is step 1 of ECC-2.0-SESSION-ADAPTER-DISCOVERY (move the
abstraction beyond tmux + Claude-history) and supports the
wrap/adapt control-pane strategy: ECC reads sessions from any
harness rather than owning one UX.

- scripts/lib/session-adapters/codex-worktree.js: adapter + rollout parser
- canonical-session.js: normalizeCodexWorktreeSession
- registry.js: register adapter, codex/codex-worktree target types
- tests/lib/session-adapters-codex.test.js: 4 tests (unit + registry routing)

* feat: add opencode session adapter + allow empty intent objective

Adds the fourth session adapter (after dmux-tmux, claude-history,
codex-worktree), normalizing OpenCode sessions into ecc.session.v1.

Reads ~/.local/share/opencode/storage: session/<project>/ses_*.json
for metadata (id, directory, title, version, projectID, time) and
message/<session>/msg_*.json to extract the model (modelID/providerID
from the first assistant message). Derives objective from the session
title, treating the auto-generated "New session - <date>" title as no
objective. Recency-based active/recorded state.

Schema: relax intent.objective from non-empty to allow empty string
(ensureStringAllowEmpty). Sessions legitimately have no objective yet
(fresh/auto-titled), and claude-history already emitted "" via
metadata.title fallback. This fixes a latent over-strict validation.

- scripts/lib/session-adapters/opencode.js: adapter + storage parser
- canonical-session.js: normalizeOpencodeSession + ensureStringAllowEmpty
- registry.js: register adapter + opencode target type
- tests/lib/session-adapters-opencode.test.js: 5 tests

Tests: opencode 5/0, codex 4/0, session-adapters 14/0,
control-pane-state 10/0, session-inspect 8/0, control-pane 12/0.
Smoke-tested on a real OpenCode session (140 messages, gpt-5.3-codex).

* test: cover error/fallback branches for codex-worktree + opencode adapters

Lift global branch coverage past the 80% gate (was 79.53%). Adds error
and fallback path tests: missing-session/unknown-id throws, findRolloutById/
findSessionInfoById, direct file targets, objective truncation, model
fallbacks, corrupt-line skip, mtime activity fallback, and the real
resolveGitBranch path outside a repo.

codex-worktree.js branch 52.8%->78.3%; global branch 80.04%.
2026-06-06 03:55:00 +08:00
Affaan Mustafa bc8e12bb80
feat: add dynamic workflow team orchestration surface
Adds dynamic workflow/team orchestration skills, the content pack, and control-pane work-item/Kanban state DB support. Includes reviewer hardening for state-db CLI validation, optional state DB failure handling, and mergeStateStatus projection.
2026-06-04 21:45:13 +08:00
Affaan Mustafa 0f84c0e279
feat: add ECC2 local control pane (#2131)
* feat: add ECC2 local control pane

* fix: refresh control pane package locks

* test: harden control pane coverage

* test: allow portable control pane shutdown

* test: retry local control pane fetches

* fix: harden control pane error handling

* fix: wrap control pane metadata
2026-06-03 21:54:30 +08:00
Martin Klein 7fef1ddbeb
docs(i18n): add German localization scout (#2029)
Adds de-DE docs, installer wiring, and locale tests. Pre-validated on current main with install manifest checks, markdownlint, locale-install tests, and ECC 2.0 release-surface tests.
2026-05-25 14:12:01 -04:00
Gaurav Dubey ee9e5a19c4
fix(install-targets): validate compiled OpenCode plugin before install (#2041)
Fail fast when the OpenCode home install is attempted from a source checkout without the compiled .opencode/dist payload. PR had the full CI matrix green.
2026-05-25 14:07:52 -04:00
Mhd Ghaith Al Abtah 7004a66243 feat(install-targets): add claude-project (per-project Claude Code) adapter
Completes the install-target matrix for Claude Code. Until now, ECC's
Claude support was home-scope only (~/.claude/) via the `claude` target.
This adds a project-scope counterpart (./.claude/) via a new
`claude-project` target so teams can install ECC per-repo without
contaminating ~/.claude/ — matching the existing project-scope adapters
for Cursor, Antigravity, Gemini, CodeBuddy, Joycode, and Zed.

Symmetric with `claude`:
- Same namespace under rules/ecc and skills/ecc
- Same docs/<locale> handling for --locale
- Same hooks placeholder substitution for hooks.json
- Reuses claude-home's destination-mapping logic 1:1

Use cases:
- Monorepos with multiple Flow-managed projects
- Teams that want ECC scoped per-project without touching ~/.claude/
- Per-project skill/rule isolation when global install isn't desirable

No breaking change: existing --target claude continues to route to
claude-home (user-scope) unchanged. New target is opt-in.

Tests
-----
- 4 new tests in tests/lib/install-targets.test.js
  (root resolution, lookup-by-id, plan parity with claude, foreign-path filtering)
- All install-target regression guards (schema enum / SUPPORTED_INSTALL_TARGETS)
  still pass
- End-to-end smoke: `--target claude-project --profile minimal --dry-run`
  emits 359 ops with destinations rooted at <projectRoot>/.claude/ (parity
  with --target claude which emits 359 ops rooted at ~/.claude/)
2026-05-19 12:14:27 -04:00
Affaan Mustafa 6cb194a3c6 fix(hooks): avoid escaped quotes in plugin bootstrap
Generate the inline hook root resolver with single-quoted JavaScript literals so Windows Git Bash does not choke on nested escaped double quotes before Node starts. Refresh hooks.json and add regression coverage for parsed hook commands and installed hook manifests.
2026-05-19 05:15:42 -04:00
Jamkris 116e61d8cb fix(lib): retry rename on Windows EPERM/EACCES/EBUSY in writeBridgeAtomic
PR #1983 round 1 introduced unique-suffix tmp paths so two concurrent
writers no longer share a single `.tmp` file. That fix is correct
under POSIX semantics — `rename(2)` is atomic between source and
destination, so each writer renames onto the same target without
conflict.

Windows `MoveFileExW` is not the same. It fails with
EPERM / EACCES / EBUSY when the target is currently being renamed
by *another* process — a short race window that fires reliably under
this hook's PostToolUse + statusline concurrency. Round 1's CI run
made this visible:

  Test (windows-latest, Node 18.x, npm) — FAILURE
  Error: EPERM: operation not permitted, rename
    'C:\…\ecc-metrics-test-bridge-race-….json.9504.4aef575a.tmp' ->
    'C:\…\ecc-metrics-test-bridge-race-….json'
      at writeBridgeAtomic (scripts/lib/session-bridge.js:79:8)

All nine Windows matrix cells (Node 18 / 20 / 22 × npm / pnpm / yarn)
hit the same path. POSIX matrices (Linux + macOS) passed unchanged.

Fix: extract a `renameWithRetry(tmp, target)` helper that retries
`fs.renameSync` up to 5 times on EPERM / EACCES / EBUSY with
exponential backoff (20 ms → 320 ms total). Other error codes
(ENOENT, ENOSPC, EROFS, …) re-throw on the first attempt — they are
not transient. POSIX runs hit the first try and exit immediately.

The backoff uses `Atomics.wait` on a throwaway `SharedArrayBuffer`
so the retry path does not busy-spin the CPU; verified on Node ≥ 17
that this works on the main thread. There is a `try/catch` fallback
to a brief busy-wait for older runtimes where `Atomics.wait` is
restricted to workers.

`writeBridgeAtomic` calls the helper instead of `fs.renameSync` and
keeps its existing best-effort tmp cleanup on terminal failure.

`renameWithRetry` is added to `module.exports` so the companion
`writeWarnState` in `scripts/hooks/ecc-context-monitor.js` can
adopt the same retry policy without duplicating the helper. That
adoption lands in the next commit.

Local: `node tests/lib/session-bridge.test.js` 14/14, `yarn test`
green, `yarn lint` clean. The round-1 test (two concurrent child
writers, 200 iterations each) now passes on macOS without retrying
at all (POSIX path) and is expected to pass on Windows via the new
retry loop.
2026-05-19 04:57:10 -04:00
Jamkris 28548f67ba fix(lib): use unique tmp suffix in writeBridgeAtomic to eliminate ENOENT race
`writeBridgeAtomic` wrote to a fixed `${target}.tmp` path before
calling `renameSync`. When two processes write to the same session
bridge concurrently (e.g. PostToolUse `ecc-metrics-bridge` + the
background `ecc-statusline`, both calling `writeBridgeAtomic(sessionId, ...)`),
the canonical atomic-rename race fires:

  1. Process A: writeFileSync(target.tmp, JSON_A) — tmp file exists.
  2. Process B: writeFileSync(target.tmp, JSON_B) — tmp file overwritten.
  3. Process A: renameSync(target.tmp, target) — succeeds; target = JSON_B
     (A's payload silently corrupted en-route).
  4. Process B: renameSync(target.tmp, target) — throws ENOENT (the
     rename consumed the file).

Every caller in the repo wraps `writeBridgeAtomic` in `try {} catch {}`,
so the ENOENT exception is swallowed and the user-visible symptom is
just "the bridge file occasionally contains the wrong process's
payload" with no diagnostic.

Reproduced before this commit:

  $ # two concurrent writers, each calling writeBridgeAtomic 500 times
  $ # against the same session ID
  [A] errors=244   # 244 ENOENT exceptions swallowed
  [B] errors=248   # ditto

After this commit the same workload reports 0 errors in both
subprocesses: tmp paths no longer collide.

Fix: change `${target}.tmp` to
`${target}.${process.pid}.${crypto.randomBytes(4).toString('hex')}.tmp`,
matching the pattern already used by `writeCostWarningIfChanged` in
`scripts/hooks/ecc-metrics-bridge.js` (commit 9b1d8918). The pid +
4-byte nonce gives each writer process a distinct tmp path, so step 2
above no longer overwrites step 1's payload and step 4 no longer
races step 3.

Also added: on `renameSync` failure, attempt `fs.unlinkSync(tmp)` so
a writer that fails (disk full, permission, parent dir gone) does
not leak its tmp file. The cleanup is best-effort and the original
error is still re-thrown.

**Scope clarification.** This commit closes the atomic-rename
primitive's race only. The *read-modify-write* race in callers —
two writers each read the same bridge state, increment, and write
back, the second clobbering the first — is a separate concern that
needs locking or per-writer logs, and is intentionally out of scope
for this PR. The cost-tracker / metrics-bridge callers tolerate
last-writer-wins on their cumulative aggregates today and this
commit does not change that contract.

The companion `writeWarnState` in `ecc-context-monitor.js` has the
same fixed-suffix pattern and the same race; that fix lands in the
next commit so each can be reviewed against its own diff.
2026-05-19 04:57:10 -04:00
Affaan Mustafa 666b4e2261 fix(installer): harden locale docs install 2026-05-17 20:46:04 -04:00
Claude 71aedad889 feat(installer): add --locale flag for translated docs installation
Adds `--locale <code>` support to the ECC installer so users can install
localized reference docs (agents, commands, skills, rules) into
`~/.claude/docs/<locale>/` alongside the existing English installation.

Changes:
- manifests/install-modules.json: add 8 locale doc modules (docs-ja-JP,
  docs-zh-CN, docs-ko-KR, docs-pt-BR, docs-ru, docs-tr, docs-vi-VN,
  docs-zh-TW), each with kind="docs" and defaultInstall=false
- manifests/install-components.json: add 8 locale: components mapping to
  the new modules
- scripts/lib/install-manifests.js: add locale: family prefix,
  SUPPORTED_LOCALES, LOCALE_ALIAS_TO_COMPONENT_ID (with aliases like
  ja=ja-JP, zh=zh-CN, ko=ko-KR), and listSupportedLocales()
- scripts/lib/install/request.js: add --locale flag to parseInstallArgs(),
  resolve locale alias → component ID in normalizeInstallRequest(), throw
  on unsupported locale codes
- scripts/lib/install-targets/claude-home.js: map docs/<locale>/ source
  paths to ~/.claude/docs/<locale>/ destination (side-by-side, no overwrite
  of English files)
- scripts/install-apply.js: import listSupportedLocales, add --locale
  usage line and available locales list to --help output

Usage examples:
  ./install.sh --locale ja                    # Japanese docs only
  ./install.sh --profile core --locale zh-CN  # core profile + zh-CN docs
  ./install.sh typescript --locale ja         # legacy + locale (errors)
2026-05-17 20:32:52 -04:00
Affaan Mustafa 519c592a12 fix: skip disabled discussion queries in platform audit 2026-05-17 20:32:09 -04:00
Affaan Mustafa 2371a3cf05 feat: add zed install target 2026-05-17 07:06:49 -04:00
Affaan Mustafa 6887f2952d Add discussion audit gate 2026-05-15 16:26:57 -04:00
SeungHyun 8cfadfea28
fix(hooks): close grouped command bypasses in gateguard (#1912)
Inspect executable bodies inside plain subshells and brace groups before applying destructive command classifiers.\n\nCo-authored-by: Jamkris <82251632+Jamkris@users.noreply.github.com>
2026-05-15 01:39:15 -04:00
Affaan Mustafa 375d750b4c
fix: integrate recent hook and docs PRs (#1905)
Integrates useful changes from #1882, #1884, #1889, #1893, #1898, #1899, and #1903:
- fix rule install docs to preserve language directories
- correct Ruby security command examples
- harden dev-server hook command-substitution parsing
- add Prisma patterns skill and catalog/package surfaces
- allow first-time protected config creation while blocking existing configs
- read cost metrics from Stop hook transcripts
- emit suggest-compact additionalContext on stdout

Co-authored-by: Jamkris <dltmdgus1412@gmail.com>
Co-authored-by: Levi-Evan <levishantz@gmail.com>
Co-authored-by: gaurav0107 <gauravdubey0107@gmail.com>
Co-authored-by: richm-spp <richard.millar@salarypackagingplus.com.au>
Co-authored-by: zomia <zomians@outlook.jp>
Co-authored-by: donghyeun02 <donghyeun02@gmail.com>
2026-05-14 21:37:28 -04:00
Affaan Mustafa c2762dd569 feat: add Ruby and Rails rules 2026-05-13 06:27:08 -04:00
Affaan Mustafa cdf1b03779
docs: add data-backed harness adapter scorecard (#1785)
* docs: add data-backed harness adapter scorecard

* fix: normalize adapter matrix line endings

* test: avoid doubled CRLF simulation
2026-05-12 02:59:52 -04:00
Affaan Mustafa 940135ea47 feat: add ECC statusline observability hooks
Salvages the useful statusline/context monitor work from stale PR #1504 while preserving the current continuous-learning hook runner wiring.

Adds the metrics bridge, context monitor, statusline script, shared cost/session bridge utilities, and tests. Fixes the reviewed false loop-detection hash collision for non-file tools, avoids default-session cost inflation, sanitizes statusline task lookup, and records hook payload session IDs in cost-tracker.
2026-05-11 23:44:06 -04:00
Affaan Mustafa fd9453f6ee docs: salvage F# agent and language guidance 2026-05-11 21:43:17 -04:00
Affaan Mustafa a8836d7bbd docs: salvage HarmonyOS ArkTS guidance 2026-05-11 21:28:15 -04:00
Affaan Mustafa c45aeee57f
fix: salvage remaining stale queue fixes (#1754) 2026-05-11 16:41:08 -04:00
Affaan Mustafa b1e67788f7 feat: add work items CLI 2026-05-11 12:24:12 -04:00
Affaan Mustafa 8926ea925e feat: track linked work items in status 2026-05-11 12:07:27 -04:00
Affaan Mustafa e70ef4a2ff feat: add Qwen install target 2026-05-11 11:27:46 -04:00
Affaan Mustafa c7c1e36625 feat: add JoyCode install target 2026-05-11 11:10:59 -04:00
Affaan Mustafa fb9a8f2973 feat: add status readiness rollup 2026-05-11 10:50:29 -04:00
Affaan Mustafa 12e1bc424d
fix: port continuous-learning observer fixes
Ports continuous-learning observer signal, storage, remote normalization, and v1 deprecation fixes onto current main.
2026-05-11 03:35:42 -04:00
Affaan Mustafa 1abc3fb381
fix: port hook session and dashboard safety fixes
Ports suggest-compact session_id isolation and dashboard terminal/document launch safety onto current main.
2026-05-11 02:53:28 -04:00
Affaan Mustafa 8a57679222
fix: restore short Claude plugin slug and skill installs (#1712) 2026-05-11 02:10:36 -04:00
Affaan Mustafa e381c8d8a8 fix: namespace claude managed install paths 2026-04-30 07:53:20 -04:00
Affaan Mustafa e1d6d853f7 fix: namespace cursor agent installs 2026-04-30 02:19:57 -04:00
Affaan Mustafa d49f0329a9 fix: avoid cursor nested AGENTS context pollution 2026-04-30 00:43:27 -04:00
Affaan Mustafa 92e0c7e9ff
fix: install native Cursor hook and MCP config (#1543)
* fix: install native cursor hook and MCP config

* fix: avoid false healthy stdio mcp probes
2026-04-21 18:35:21 -04:00
Affaan Mustafa cdeb837838 Merge origin/main into fix/urgent-install-and-name 2026-04-14 20:23:54 -07:00
Affaan Mustafa e46deb93c8 fix: harden dashboard terminal launch helpers 2026-04-14 19:44:32 -07:00
Affaan Mustafa 76b6e22b4d fix: unblock urgent install and gateguard regressions 2026-04-14 19:23:07 -07:00
Affaan Mustafa 9e607ebb30 fix: prefer cursor native hooks during install 2026-04-13 00:07:15 -07:00
Affaan Mustafa 7374ef6a73 fix: normalize cursor rule installs 2026-04-12 23:51:58 -07:00
Affaan Mustafa 133e881ce0 fix: install Cursor rules as mdc files 2026-04-12 23:32:39 -07:00
Affaan Mustafa 2ece2cfc90 fix: stop injecting managed hooks into claude settings 2026-04-12 22:39:48 -07:00
Affaan Mustafa 86cbe3d616 feat: add c language compatibility 2026-04-08 15:42:49 -07:00
Affaan Mustafa 786f46dad5 feat: support disabling bundled mcp servers 2026-04-05 14:37:28 -07:00
Affaan Mustafa 1346f83b08 fix: shorten plugin slug to ecc 2026-04-05 14:31:30 -07:00
Affaan Mustafa 8baffb4ad3 fix: harden install target filtering and MCP health probes 2026-04-05 13:59:42 -07:00
Affaan Mustafa b10080c7dd fix: respect home overrides in hook utilities 2026-04-02 18:22:07 -07:00
Affaan Mustafa 16e9b17ad7 fix: clean up observer sessions on lifecycle end 2026-04-02 18:02:29 -07:00
Affaan Mustafa 8f63697113 fix: port safe ci cleanup from backlog 2026-04-01 16:09:54 -07:00
Affaan Mustafa dba5ae779b fix: harden install and codex sync portability 2026-04-01 16:04:56 -07:00
Affaan Mustafa 6833454778 fix: dedupe managed hooks by semantic identity 2026-04-01 02:16:32 -07:00
Affaan Mustafa e1bc08fa6e fix: harden install planning and sync tracked catalogs 2026-03-31 22:57:48 -07:00
Affaan Mustafa 1744e1ef0e feat: add gemini install target 2026-03-31 15:13:20 -07:00
轻舟Joshua c38bc799fd
feat(install): add CodeBuddy(Tencent) adaptation with installation scripts (#1038)
* feat(install): add CodeBuddy(Tencent) adaptation with installation scripts

* fix: add codebuddy to SUPPORTED_INSTALL_TARGETS

* fix(codebuddy): resolve installer path issues, unused vars, and uninstall safety
2026-03-31 14:06:26 -07:00
Affaan Mustafa 47aa415b06 fix(installer): validate hooks and settings before install 2026-03-28 19:55:34 -04:00
Affaan Mustafa d7e6bb242a fix(installer): reject invalid claude settings roots 2026-03-28 19:55:34 -04:00
Affaan Mustafa 9f37a5d8c7 fix(installer): preserve existing claude hook settings 2026-03-28 19:55:34 -04:00
Lidang-Jiang ae21a8df85 fix(scripts): add os.homedir() fallback for Windows compatibility
On Windows (native cmd/PowerShell), process.env.HOME is undefined.
Seven CLI entry points and two library files pass process.env.HOME
directly as homeDir without a cross-platform fallback, causing all
path resolutions to silently fail (resolving to "undefined/.claude/...").

Node.js os.homedir() correctly handles all platforms (HOME on Unix,
USERPROFILE on Windows, OS-level fallback). The project already uses
this pattern in scripts/lib/state-store/index.js and has a getHomeDir()
utility in scripts/lib/utils.js, but it was not applied consistently.

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

Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
2026-03-28 11:28:12 +08:00
Affaan Mustafa b4296c7095 feat: add install catalog and project config autodetection 2026-03-27 05:56:39 -04:00
Affaan Mustafa b19b4c6b5e fix: finish blocker lane hook and install regressions 2026-03-25 04:00:50 -04:00
Affaan Mustafa 7b510c886e fix: harden session hook guards and session ID handling 2026-03-25 03:36:36 -04:00
Affaan Mustafa 00bc7f30be fix: resolve blocker PR validation regressions 2026-03-25 01:34:29 -04:00
Affaan Mustafa 1d0aa5ac2a fix: fold session manager blockers into one candidate 2026-03-24 23:08:27 -04:00
Neha Prasad 401dca07d0
feat(session): add worker health alongside state in ecc.session.v1 (#751) 2026-03-22 15:39:51 -07:00
Chris Yau 4e6b5cc19f
fix(install): add rust, cpp, csharp to legacy language alias map (#747)
* fix(install): add rust, cpp, csharp to legacy language alias map

The legacy installer compatibility layer in install-manifests.js was
missing entries for rust, cpp, and csharp — languages that have
rules/ directories and (for rust/cpp) install-components.json entries.

Running `./install.sh rust` fails with "Unknown legacy language: rust"
because LEGACY_LANGUAGE_ALIAS_TO_CANONICAL and
LEGACY_LANGUAGE_EXTRA_MODULE_IDS didn't include these languages.

Fixes the issue reported in #694 by @mpiton.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

* fix(install): complete csharp legacy support and add resolution tests

- Add lang:csharp component to install-components.json with
  framework-language module (matching cpp/rust pattern)
- Update csharp mapping in LEGACY_LANGUAGE_EXTRA_MODULE_IDS from
  empty array to ['framework-language']
- Add end-to-end resolution tests for rust, cpp, and csharp verifying
  framework-language module is included in resolved moduleIds

Addresses review feedback from Copilot, Greptile, CodeRabbit, and Cubic.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
2026-03-22 15:39:27 -07:00
Affaan Mustafa bea68549c5
feat: agent description compression with lazy loading (#696)
* feat: add agent description compression with lazy loading (#491)

Agent descriptions consume ~26k tokens (121KB across 27 agents). This adds
a compression library with three modes:
- catalog: metadata only (~2-3k tokens) for agent selection
- summary: metadata + first paragraph (~4-5k tokens) for routing
- full: no compression, for when agent is invoked

Includes lazy-load function to fetch full agent body on demand.
21 tests covering parsing, compression, filtering, and real agents dir.

* fix: update JSDoc to include all stats fields in buildAgentCatalog

Add compressedBytes and mode to the documented return type, matching
the actual implementation.
2026-03-20 03:53:22 -07:00
Affaan Mustafa 68484da2fc
fix: auto-detect ECC root from plugin cache when CLAUDE_PLUGIN_ROOT is unset (#547) (#691)
When ECC is installed as a Claude Code plugin via the marketplace,
scripts live in the plugin cache (~/.claude/plugins/cache/...) but
commands fallback to ~/.claude/ which doesn't have the scripts.

Add resolve-ecc-root.js with a 3-step fallback chain:
  1. CLAUDE_PLUGIN_ROOT env var (existing)
  2. Standard install at ~/.claude/ (existing)
  3. NEW: auto-scan the plugin cache directory

Update sessions.md and skill-health.md commands to use the new
inline resolver. Includes 15 tests covering all fallback paths
including env var priority, standard install, cache discovery,
and the compact INLINE_RESOLVE used in command .md files.
2026-03-20 01:38:15 -07:00
Affaan Mustafa 0b0b66c02f
feat: agent compression, inspection logic, governance hooks (#491, #485, #482) (#688)
Implements three roadmap features:

- Agent description compression (#491): New `agent-compress` module with
  catalog/summary/full compression modes and lazy-loading. Reduces ~26k
  token agent descriptions to ~2-3k catalog entries for context efficiency.

- Inspection logic (#485): New `inspection` module that detects recurring
  failure patterns in skill_runs. Groups by skill + normalized failure
  reason, generates structured reports with suggested remediation actions.
  Configurable threshold (default: 3 failures).

- Governance event capture hook (#482): PreToolUse/PostToolUse hook that
  detects secrets, policy violations, approval-required commands, and
  elevated privilege usage. Gated behind ECC_GOVERNANCE_CAPTURE=1 flag.
  Writes to governance_events table via JSON-line stderr output.

59 new tests (16 + 16 + 27), all passing.
2026-03-20 01:38:13 -07:00
Affaan Mustafa 28de7cc420
fix: strip ANSI escape codes from session persistence hooks (#642) (#684)
Windows terminals emit control sequences (cursor movement, screen
clearing) that leaked into session.tmp files and were injected
verbatim into Claude's context on the next session start.

Add a comprehensive stripAnsi() to utils.js that handles CSI, OSC,
charset selection, and bare ESC sequences. Apply it in session-end.js
(when extracting user messages from the transcript) and in
session-start.js (safety net before injecting session content).
2026-03-20 01:38:11 -07:00
Affaan Mustafa 07f6156d8a
feat: implement --with/--without selective install flags (#679)
Add agent: and skill: component families to the install component
catalog, enabling fine-grained selective install via CLI flags:

  ecc install --profile developer --with lang:typescript --without capability:orchestration
  ecc install --with lang:python --with agent:security-reviewer

Changes:
- Add agent: family (9 entries) and skill: family (10 entries) to
  manifests/install-components.json for granular component addressing
- Update install-components.schema.json to accept agent: and skill:
  family prefixes
- Register agent and skill family prefixes in COMPONENT_FAMILY_PREFIXES
  (scripts/lib/install-manifests.js)
- Add 41 comprehensive tests covering CLI parsing, request normalization,
  component catalog validation, plan resolution, target filtering,
  error handling, and end-to-end install with --with/--without flags

Closes #470
2026-03-20 00:43:32 -07:00
Affaan Mustafa 4bdbf57d98
fix: resolve 8 test failures on main (install pipeline, orchestrator, repair) (#564)
- Add duplicate slug detection in buildOrchestrationPlan to reject
  worker names that collapse to the same slug
- Use buildTemplateVariables() for launcher command interpolation
  so _sh and _raw suffixes are available in templates
2026-03-18 03:03:31 -07:00
Affaan Mustafa f12bb90924
fix: refresh orchestration follow-up after #414 (#430) 2026-03-16 14:29:28 -07:00
Aryan Tejani 89044e8c33
feat(design): skill health dashboard mockup (#518)
* feat(Design): skill health dashboard mockup

* fix(comments): code according to comments
2026-03-16 14:01:41 -07:00
Fredrik Hallerös 17a6ef4edb
Add PowerShell installer wrapper and update documentation (#532)
* Add install.ps1 PowerShell wrapper and tests

Add a Windows-native PowerShell wrapper (install.ps1) that resolves symlinks and delegates to the Node-based installer runtime. Update README with PowerShell usage examples and cross-platform npx entrypoint guidance. Point the ecc-install bin to the Node installer (scripts/install-apply.js) in package.json (and refresh package-lock), include install.ps1 in package files, and add tests: a new install-ps1.test.js and a tweak to install-sh.test.js to skip on Windows. These changes provide native Windows installer support while keeping npm-compatible cross-platform invocation.

* Improve tests for Windows HOME/USERPROFILE

Make tests more cross-platform by ensuring HOME and USERPROFILE are kept in sync and by normalizing test file paths for display.

- tests/lib/session-adapters.test.js: set USERPROFILE when temporarily setting HOME and restore previous USERPROFILE on teardown.
- tests/run-all.js: use a normalized displayPath (forward-slash separated) for logging and error messages so output is consistent across platforms.
- tests/scripts/ecc.test.js & tests/scripts/session-inspect.test.js: build envOverrides from options.env and add HOME <-> USERPROFILE fallbacks so spawned child processes receive both variables when only one is provided.

These changes prevent test failures and inconsistent logs on Windows where USERPROFILE is used instead of HOME.

* Fix Windows paths and test flakiness

Improve cross-platform behavior and test stability.

- Remove unused createLegacyInstallPlan import from install-lifecycle.js.
- Change resolveInstallConfigPath to use path.normalize(path.join(cwd, configPath)) to produce normalized relative paths.
- Tests: add toBashPath and normalizedRelativePath helpers to normalize Windows paths for bash and comparisons.
- Make cleanupTestDir retry rmSync on transient Windows errors (EPERM/EBUSY/ENOTEMPTY) with short backoff using sleepMs.
- Ensure spawned test processes receive USERPROFILE and convert repo/detect paths to bash format when invoking bash.

These changes reduce Windows-specific failures and flakiness in the test suite and tidy up a small unused import.
2026-03-16 13:35:17 -07:00
Affaan Mustafa b48930974b
fix: resolve all CI test failures (19 fixes across 6 files) (#519)
- canonical-session: fall back to JSON file recording when the loaded
  state-store module has no writer methods (factory vs instance)
- install-executor: skip node_modules and .git dirs in listFilesRecursive
  to prevent ETIMEDOUT copying thousands of .opencode dependency files
- ecc.js: increase maxBuffer to 10MB for spawned subcommands to prevent
  ENOBUFS on large install plan JSON output
- install-apply.test: update Cursor and Antigravity path assertions to
  match flattened rule layout and remapped dirs (workflows, skills)
- ecc.test: increase maxBuffer in test runner to handle large output
- orchestrate-codex-worker.sh: guard against unreadable task file before
  cat, write failure status and handoff artifacts on early exit
2026-03-16 01:59:53 -07:00
Affaan Mustafa 426fc54456
feat: record canonical session snapshots via adapters (#511) 2026-03-16 01:35:45 -07:00
Affaan Mustafa bae1129209
feat: add SQLite state store and query CLI (#510)
* feat: add SQLite state store and ECC status CLI

* fix: replace better-sqlite3 with sql.js to eliminate native module CI failures

better-sqlite3 requires native C++ compilation (node-gyp, prebuild-install)
which fails in CI across npm/pnpm on all platforms:
- npm ci: lock file out of sync with native transitive deps
- pnpm: native bindings not found at runtime
- Windows: native compilation fails entirely

sql.js is a pure JavaScript/WASM SQLite implementation with zero native
dependencies. The adapter in index.js wraps the sql.js API to match the
better-sqlite3 interface used by migrations.js and queries.js.

Key implementation detail: sql.js db.export() implicitly ends active
transactions, so the adapter defers disk writes (saveToDisk) until
after transaction commit via an inTransaction guard flag.

createStateStore is now async (sql.js requires async WASM init).
Updated status.js, sessions-cli.js, and tests accordingly.
2026-03-16 01:32:21 -07:00
Affaan Mustafa d5371d28aa
feat: add skill evolution foundation (#514) 2026-03-15 21:47:39 -07:00
Affaan Mustafa 131f977841
feat: strengthen install lifecycle and target adapters (#512)
* fix: strengthen install lifecycle adapters

* fix: restore template content on uninstall
2026-03-15 21:47:31 -07:00
Affaan Mustafa 1e0238de96
feat: wire manifest resolution into install execution (#509) 2026-03-15 21:47:22 -07:00
Affaan Mustafa c53bba9e02 feat: self-improving skills loop — observe, inspect, amend, evaluate
- Add skill health observation layer (execution logging, success/failure tracking)
- Add skill health inspector (trace recurring failures across runs)
- Add amendify mechanism (propose SKILL.md patches from failure evidence)
- Add evaluation scaffolding (compare amended vs original performance)
- Wire into session-inspect CLI: skills:health, skills:amendify, skills:evaluate
- 1145/1145 tests passing (+3 new)
2026-03-14 23:21:18 -07:00
Affaan Mustafa 2b2777915e feat: expand session adapter registry with structured targets
- Registry accepts { type, value } structured targets
- Add --list-adapters and --target-type CLI flags to session-inspect
- Export adapter type from claude-history and dmux-tmux adapters
- 71 new session adapter tests, 34 new session-inspect tests
- All 1142 tests passing
2026-03-14 19:09:26 -07:00
Affaan Mustafa fcaf78e449 merge: dmux worktree (selective install, orchestration, observer fixes) 2026-03-14 12:55:56 -07:00
Affaan Mustafa 4e028bd2d2 feat: orchestration harness, selective install, observer improvements 2026-03-14 12:55:25 -07:00
Frank c5acb5ac32
fix: accept shorter mixed-case session IDs (#408) 2026-03-12 23:29:50 -07:00
Affaan Mustafa 2d43541f0e fix: preserve orchestration launcher compatibility 2026-03-12 15:40:25 -07:00
Affaan Mustafa c5b8a0783e fix: resolve lint regression in plan parsing 2026-03-12 15:35:12 -07:00
Affaan Mustafa af318b8f04 fix: address remaining orchestration review comments 2026-03-12 15:34:05 -07:00
Affaan Mustafa 52daf17cb5 fix: harden orchestration status and skill docs 2026-03-12 15:07:57 -07:00
Affaan Mustafa ad4ef58a8e fix: resolve orchestration lint errors 2026-03-12 14:49:05 -07:00
Affaan Mustafa 4d4ba25d11 feat: add orchestration workflows and harness skills 2026-03-12 14:49:05 -07:00
Affaan Mustafa bdf4befb3e fix: resolve orchestration lint errors 2026-03-12 09:35:03 -07:00
Affaan Mustafa 2349e21731 feat: add orchestration workflows and harness skills 2026-03-12 09:26:36 -07:00
Affaan Mustafa bfc73866c9 Revert "feat: add orchestration workflows and harness skills"
This reverts commit cb43402d7d.
2026-03-12 09:26:12 -07:00
Affaan Mustafa cb43402d7d feat: add orchestration workflows and harness skills 2026-03-12 08:53:52 -07:00
Jonghyeok Park 67841042d6 refactor: deduplicate config lists and unify resolveFormatterBin branches
Extract BIOME_CONFIGS and PRETTIER_CONFIGS as shared constants to eliminate
duplication between PROJECT_ROOT_MARKERS and detectFormatter(). Unify the
biome/prettier branches in resolveFormatterBin() via a FORMATTER_PACKAGES
map. Remove redundant path.resolve() in quality-gate.js.
2026-03-11 10:45:28 +09:00
Jonghyeok Park 0a3afbe38f fix(hooks): add Windows .cmd support with shell injection guard
Handle Windows .cmd shim resolution via spawnSync with strict path
validation. Removes shell:true injection risk, uses strict equality,
and restores .cmd support with path injection guard.
2026-03-11 10:45:28 +09:00
Jonghyeok Park 66498ae9ac perf(hooks): use direct require() instead of spawning child process
Invoke hook scripts directly via require() when they export a
run(rawInput) function, eliminating one Node.js process spawn per
hook invocation (~50-100ms).

Includes path traversal guard, timeouts, error logging, PR review
feedback, legacy hooks guard, normalized filePath, and restored
findProjectRoot config detection with package manager support.
2026-03-11 10:45:27 +09:00
Jonghyeok Park f331d3ecc9 feat(hooks): add shared resolve-formatter utility with caching
Extract project-root discovery, formatter detection, and binary
resolution into a reusable module. Caches results per-process to
avoid redundant filesystem lookups on every Edit hook invocation.

This is the foundation for eliminating npx overhead in format hooks.
2026-03-10 22:17:02 +09:00