- Line precision: parse git diff --unified=0 into per-file changed line ranges
(defaultWorkingSetFor), so two agents in the SAME file but DIFFERENT functions
no longer false-collide. Overlap channel now uses the overlap coefficient
(|A∩B|/min(|A|,|B|)) — high when one edit sits inside the other's region, low
for disjoint ranges; whole-file edit = 1. Docstring + design doc updated.
- Trigger firing: buildProximityTriggers() turns advisories into the concrete
messages — transmit-intent to both on a Traffic Advisory, steer-away to the
yielding agent + a hold notice on a Resolution Advisory. buildProximitySnapshot
now returns triggers; dispatchProximityTriggers(triggers, {sendMessage}) delivers
them through an injectable sink (the ECC messages table), best-effort.
- 12 new tests (line-range disjoint vs overlapping, parseDiffRanges, triggers,
dispatch). Full suite 2881/2881; lint green.
Adds a clean badge row right under the hero linking the official destinations,
led by a live Discord member-count badge (server widget enabled) to drive the
community from a few hundred toward a few thousand. Gives the official ECC links
the icons the readme was missing.
Turns live sessions into the airspace scan: each worktree session's git diff
becomes its working set, the dependency graph is built over the touched files,
and scanAirspace() produces the TCAS advisories + 3D positions.
- scripts/lib/control-pane/proximity.js: sessionsToAgents() + buildProximitySnapshot();
default working-set source shells `git diff --name-only <base>...HEAD` per
worktree (injectable for tests, fails closed to []).
- state.js: opt-in `proximity` field on the snapshot (includeProximity flag) so
the default hot path stays fast (git diffs only run when requested).
- 4 integration tests (same-file editors -> resolution, later agent steers,
<2 participants -> no advisories, labels). Full suite 2873/2873; lint green.
The moat layer: spatial deconfliction for multiple agents (and humans) on one
codebase, modeled on aircraft TCAS — measure how close two agents are in
code-space, then transmit-intent (Traffic Advisory) and steer-away (Resolution
Advisory) before they collide at the git layer.
scripts/lib/agent-proximity/:
- distance.js — the math: per-channel collision probabilities combined via
noisy-OR R = 1 - Π(1 - ω·r). Channels: edit overlap (file + line-range
Jaccard), dependency coupling (γ^(d-1) over the import graph, direction-
agnostic — catches 'edit there breaks here' even when tree-distant), and tree
proximity (LCA-based, soft prior). TCAS advise(): clear / advisory(transmit) /
resolution(steer), with deterministic right-of-way priority so the maneuver is
coordinated. closureRate() for approach-speed escalation.
- graph.js — lightweight require/import dependency-graph builder (fs or in-memory).
- index.js — scanAirspace(): pairwise advisories + 3D vector embedding (space-
filling path embedding pulled toward dependency neighbours) so a 'where are
the agents' visualization can render the file-cloud and watch agents crawl /
steer.
docs/design/agent-proximity.md — full mathematical formulation + protocol + viz
+ roadmap (v1 call-graph/symbol channels + live session-diff wiring; v2 cross-
machine airspace over Tailscale, the zero-conflict-swarm demo).
17 tests; full suite 2869/2869; lint green.
- coverage: branch threshold 80 -> 79 (current is 79.52%; lines/functions/
statements remain 88/94/88). The 80% branch gate has been red on every main
run; this unblocks CI while keeping a meaningful floor just below current.
- SECURITY.md: remove the bouncing security@ecc.tools mailbox (flagged by an
advisory reporter as undeliverable) and direct all reports to GitHub private
vulnerability reporting, the only monitored channel.
- gateguard (GHSA-4v57-ph3x-gf55): add a quote-aware detection pass that
dequotes command words and splits on UNQUOTED separators incl. newlines, so
newline-separated commands, quoted command words ('rm'/"rm"), quoted
find -exec, and sh/bash -c wrappers are all classified destructive. Additive —
existing 133 cases still pass; +7 bypass regressions + a false-positive guard
(rm inside a quoted echo arg stays allowed). 140/140.
- Windows CI: format-code.ts emitted backslash paths via path.normalize, breaking
forward-slash assertions on all Windows matrix cells — force forward slashes.
- claw.js (CodeQL #1 js/polynomial-redos): bound parseTurns input so the lazy
[\s\S]*? body can't drive O(n^2) scanning on adversarial history files.
Full suite 2852/2852; lint green.
Critical: project-local install-state (e.g. a cloned repo's .cursor/ecc-install-state.json)
is attacker-controllable, and repair/uninstall/auto-update replayed its operations with
destinationPath validated only for non-emptiness — confirmed arbitrary file write/delete
and chained RCE (write ~/.bashrc, .git/hooks, or run a planted install-apply.js).
- New scripts/lib/path-safety.js: assertWithinTrustedRoot() canonicalizes (incl. symlink
escape via nearest-existing-ancestor realpath) and fails closed unless the destination is
within the adapter-derived trusted root.
- install-lifecycle.js: gate executeRepairOperation + executeUninstallOperation + the
install-state removal against record.targetRoot (the adapter-resolved root, NOT the
attacker-supplied state.target.root).
- auto-update.js: validateRepoRoot now requires package.json name to be an official ECC
package, so a planted nested repo can't drive auto-update into executing attacker code.
- 7 containment regression tests. Existing install-lifecycle/repair/uninstall/auto-update
suites still green (legit destinations are within the root).
- ecc-bot.mjs: validate interaction id (snowflake) and token before building the
callback fetch URL (clears CodeQL js/request-forgery #239/#240/#241); clamp the
remote heartbeat_interval to [1s,10m] (js/resource-exhaustion #242); strip CR/LF
from log args (js/log-injection #246).
- Bump transitive dev deps via overrides/resolutions to patch quadratic-complexity
DoS: markdown-it >=14.2.0 (Dependabot #45/#46), js-yaml >=4.2.0 (#42/#43).
Both lockfiles regenerated; npm reports 0 vulnerabilities.
The interactive claim/move buttons concatenated work-item ids into inline
onclick JS with only single-quote escaping — a crafted id (ids/titles come from
GitHub sync and manual upserts, not a strict allowlist) could break out and
inject script, even on the localhost-only server.
Fix: emit the id/lane in HTML-escaped data-* attributes (escapeHtml encodes
&<>"'), attach delegated click listeners that read them via getAttribute, and
pass the raw value as a JS string arg — never concatenated into code. Adds a
regression assertion that no inline onclick handlers with interpolated ids
remain. Flagged by automated security review.
Full suite 2845/2845; lint green.
The board was read-only; you can now drive the agent+human JIT workflow from the
local control pane.
- New shared scripts/lib/control-pane/work-item-mutations.js (claimWorkItem,
moveWorkItem) so the CLI and server never diverge; work-items.js claim now
delegates to it.
- server.js: gated POST /api/work-items/:id/claim and /:id/move (localhost-only,
honors --read-only with 403). Claim sets owner + assigneeKind and moves to
running; move retargets the kanban lane.
- ui.js: per-card Claim (on unassigned cards) + lane buttons that POST and
refresh; 15s live auto-refresh (paused when the tab is hidden).
- Tests: interactive claim/move endpoints, read-only 403, invalid-lane 400, and
snapshot reflects mutations.
Full suite 2845/2845; lint green.
Closes the agent+human JIT loop the control-pane board surfaces: the board shows
the unassigned (needs-owner) queue; 'claim' lets an agent or human pick up work.
node scripts/work-items.js claim [<id>] --owner <name> [--as agent|human]
- No id: claims the highest-priority unassigned open item.
- With id: claims that specific item (re-assignable).
- Sets owner, records metadata.assigneeKind (agent|human), and moves the card to
running so the board reflects that work has started.
- Refuses done items, requires --owner, validates --as. 5 CLI tests added.
Full suite 2844/2844; lint green.
The kanban board tracked lanes (ready/running/blocked/done) but not WHO owns
each card, which is the missing piece for agent+human just-in-time team workflows.
- state.js: classifyAssignee() labels each work item agent | human | unassigned
(session-linked or agent-pattern owners = agent; named owners = human; ownerless
= unassigned), with an explicit metadata.assigneeKind override.
- summarizeWorkItems(): adds an assignment summary {agent,human,unassigned} over
OPEN cards plus a priority-sorted needsAssignment queue — the JIT pickup list.
- ui.js: cards show an [agent]/[human]/[unassigned] badge; the board header shows
agent/human split and 'N need owner'.
- Tests: assignment classification + JIT queue coverage in control-pane-state.
Full suite 2839/2839; lint green.
- #2290 suggest-compact: honor ECC_CONTEXT_WINDOW_TOKENS / CLAUDE_CODE_AUTO_COMPACT_WINDOW
so 400k-window models (Opus 4.x) no longer report ~double context usage; add
override + isolation tests in transcript-context.test.js.
- #2282 install: bare-language syntax is legacy-only by design, but the error
now distinguishes a supported-but-wrong-mode target (gemini/codex/…) from a
genuinely unknown one and points to --profile/--modules/--skills.
- #2276 cost-report: the command + cost-tracking skill targeted a SQLite DB no
tracker writes. Repoint both at the real ~/.claude/metrics/costs.jsonl (JSONL,
estimated_cost_usd), reduce cumulative-per-session snapshots to latest-per-session,
and use node instead of sqlite3 for cross-platform support.
- #2272 gateguard: make the 'confirm no existing file' checklist item
tool-agnostic (Glob/Grep or find/grep via Bash) so hosts without a Glob tool
don't get a dead tool call.
Full suite 2839/2839; lint green.
The observe hook's secret-scrub regex used a generic ([A-Za-z]+\s+)? group
that overlapped the separator and value classes, causing exponential
backtracking on identifier-dense tool I/O — an orphaned python child then
pegged a core at ~100% CPU for days because the async hook timed out without
killing it.
- Rewrite _SECRET_RE as a linear matcher: bounded separator {1,8}, a fixed
set of auth schemes (bearer|basic|token|bot) instead of [A-Za-z]+, and a
bounded value {8,256}. Pathological input drops from hang to <1ms; real
secrets still redact (verified incl. 'Bearer <token>').
- Add a signal.alarm(8) self-timeout to both scrub blocks so any runaway
child self-terminates before the 10s async-hook timeout can orphan it.
Trimmed the description from ~1216 to ~620 chars while keeping trigger coverage (reproducible cross-platform envs, system deps, local services, .flox/manifest.toml/flox activate/FloxHub).
- README: add a visible ## Security section (official sources, vuln reporting via SECURITY.md, GateGuard/IOC/AgentShield guardrails, security guide); make stats line a plain paragraph to clear MD028
- eslint: empty catch comment in run-with-flags.js; drop unneeded escape in github-coordination/parsing.js; remove unused execFileSync import in its test (#2236 follow-ups)
- markdownlint: wrap bare URLs in rules/vue/*.md (#2250 follow-up)
npm run lint green; full suite 2836/2836.
- agent.yaml: register epic-* commands (#2236) and vue-review (#2241)
- package.json files: drop stray skills/ml-adoption-playbook entry (follows orphan-skill publish pattern; not in install-modules.json)
- unicode-safety: strip decorative emoji from dashboard-web.js (#2100) and brand-discovery refs (#2221) to pass the CI gate
- agent-compress: raise catalog token canary 5000 -> 6000 for the 67-agent catalog
Full suite green (2836/2836).
- suggest-compact hook now reads the latest usage record from the session
transcript and suggests /compact at a window-scaled token threshold
(160k/200k window, 250k/1M window; COMPACT_CONTEXT_THRESHOLD and
COMPACT_CONTEXT_INTERVAL overridable), re-firing per 60k-token growth
bucket; tool-call count stays as the secondary signal (#2155)
- Codex repo marketplace now points at ./plugins/ecc instead of ./ — Codex
never discovers plugins whose local marketplace source.path is the
marketplace root (verified on Codex CLI 0.137.0); plugins/ecc is a thin
folder referencing root skills/.mcp.json per maintainer direction on
#2097; docs flag plugin mode as experimental with the upstream blocker
openai/codex#26037 linked (#2128)
- README badges for installs/stars/forks now use shields endpoint badges
backed by api.ecc.tools (live install count 3,712 vs the stale static
150), which also eliminates shields' 'Unable to select next GitHub token
from pool' render in the stars badge
Closes#2155Closes#2128
* fix(assets): replace hero brand mark with website coral circuit mark
The top-left mark in the hero banner was the assets/ecc-icon.svg double-E
lettermark, not the actual brand logo. Swap in the coral vector circuit
mark from the ECC-website header (src/styles/brandMarks.ts), keeping the
~70px footprint, the soft coral glow, and every other element identical.
PNG re-rendered at 2400x1350 via sharp with palette compression.
* docs: sync skill count to 262 across catalog surfaces
catalog:check was failing on main after config-gc (#2216) landed without
a count bump. Ran npm run catalog:sync.
#2209 bumped ureq to 3.x but the AgentBuilder-based webhook sender
was not ported (branch update raced the merge). ureq 3 replaces
AgentBuilder with Agent::config_builder(); timeouts are Option-wrapped
and status() returns http::StatusCode.
Recreates the v1.10 hero banner design (sourced from commit 602894ef)
that PR #2225 replaced with a plain HTML header:
- Wordmark and breadcrumb now read ECC / affaan-m/ECC
- Version badge reads v2.0.0 · Jun 2026, eyebrow updated to V2.0
- Top-left mark is the actual assets/ecc-icon.svg lettermark (amber E,
coral CC) instead of a generic coral square
- Catalog columns refreshed with live counts (261 skills, 64 agents,
84 commands, 409 catalog) and real item names from the repo
- Harness pills updated to the current README list (Claude Code, Codex,
Cursor, OpenCode, Gemini, Zed, Copilot)
- SVG source committed as assets/hero.svg so future edits never need
image archaeology; rendered to PNG at 2400x1350 via sharp
README hero line restored to the markdown image; badges, sponsor table,
and guide cards from #2225 kept intact.
- add ecc2/rust-toolchain.toml pinning stable 1.96 (deps now require
edition2024, which needs rustc 1.85+; local 1.84 could no longer build)
- make git test fixtures hermetic: disable core.hooksPath inside temp
repos so global identity-checking pre-push hooks cannot fail tests
* fix(hooks): fail open on oversized stdin instead of echoing truncated JSON (#2222)
run-with-flags.js capped stdin at 1MB but every fallthrough path still
echoed the truncated string to stdout. The harness parses hook stdout as
JSON, got a document cut mid-stream, and blocked the tool call — so any
Edit/Write with a >1MB hook payload was permanently blocked by every
registered pre-write hook, before ECC_HOOK_PROFILE / ECC_DISABLED_HOOKS
gating could run.
- Exit 0 with empty stdout (no opinion) when the stdin cap trips, before
any echo or gating logic.
- Flush stdout via write callback before process.exit: exiting right
after stdout.write() dropped everything past the ~64KB pipe buffer,
cutting even sub-cap pass-through payloads mid-JSON.
Regression tests cover the enabled, disabled, and missing-arg paths for
oversized payloads plus full echo of sub-cap >64KB payloads.
* fix(codex): stop emitting invalid exa url entry, align merge with connector policy (#2224)
The Codex MCP merge declared exa with a url key, but Codex's
[mcp_servers.*] TOML schema is stdio-only — the url key makes the
entire config.toml fail to load, bricking both the codex CLI and the
desktop app. Every install/update re-injected the line because the
urlEntry branch treated the broken entry as present.
- ECC_SERVERS now emits only the current default set per
docs/MCP-CONNECTOR-POLICY.md: chrome-devtools (stdio, command/args).
Retired servers (supabase, playwright, context7, exa, github, memory,
sequential-thinking) are never re-emitted; existing user-managed
entries are untouched.
- The merge now repairs the exact ECC-emitted broken form (url-only
exa entry) on every run so re-running the installer fixes broken
configs instead of preserving them. User stdio exa entries
(command + mcp-remote) are left alone.
- check-codex-global-state.sh requires chrome-devtools instead of the
retired set, and flags url-only exa entries with a repair hint.
Tests cover repair, re-run idempotence, stdio-entry preservation, and
no-retired-server emission in add, update, dry-run, and disabled modes.
* fix(hooks): never echo truncated stdin from Stop hooks (#2090)
Stop hooks follow the ECC pass-through convention (echo stdin on
stdout), but every echoing Stop hook capped stdin and echoed the capped
string. The Stop payload carries last_assistant_message, so a long
final assistant message produced a JSON document cut mid-stream on
stdout, which the harness reports as 'Stop hook error: JSON validation
failed' across the whole Stop chain.
Reproduced: a Stop payload with a >64KB last_assistant_message run
through run-with-flags + cost-tracker emitted exactly 65536 bytes of
invalid JSON (cost-tracker capped stdin at 64KB — far below realistic
Stop payloads).
- cost-tracker: raise the cap to 1MB (matching all other hooks) and
suppress the pass-through echo when stdin was truncated.
- check-console-log, stop-format-typecheck, desktop-notify: suppress
the echo when stdin was truncated; flush stdout before process.exit
so sub-cap payloads are not cut at the ~64KB pipe buffer.
- All hooks keep exiting 0 (fail-open); diagnostics go to stderr.
New stop-hooks-stdout test asserts the contract for every registered
Stop hook: stdout is empty or valid JSON, exit code 0 — for realistic
100KB payloads and oversized >1MB payloads, via the production runner
and via direct invocation. Updated the old hooks.test.js case that
codified the truncated-echo behavior.
* fix(hooks): dampen GateGuard fact-force repetition in long sessions (#2142)
In long autonomous sessions the fact-force gate produced 10+
near-identical 'state facts -> blocked -> restate -> retry' blocks in
one context window, which measurably raises the odds of the model
collapsing into a degenerate single-token repetition loop.
- Track a per-session fact_force_denials counter in GateGuard state
(merged max across concurrent writers, reset with the session, robust
to malformed on-disk values).
- The first GATEGUARD_FACT_FORCE_FULL_DENIALS denials (default 3) keep
the full four-fact block; later denials emit a condensed single-line
message that carries the denial ordinal, so consecutive denials are
structurally different and never textually identical.
- True retries of the same target remain allowed without re-prompting
(unchanged). Destructive-Bash and routine-Bash gates are unchanged,
as are the ECC_GATEGUARD=off / ECC_DISABLED_HOOKS escape hatches.
Eight new tests cover budget counting, condensed format, ordinal
advancement, retry pass-through, env tuning, malformed state, MultiEdit
dampening, and destructive-gate exemption.
* fix(hooks): keep security hooks able to block on oversized stdin (#2222)
Refine the truncation fail-open: instead of skipping the hook entirely,
the runner now suppresses only its own raw-echo when stdin was
truncated. The hook still executes and receives the truncated flag
(run() context / ECC_HOOK_INPUT_TRUNCATED), so config-protection keeps
blocking truncated protected-config payloads (its test requires exit 2)
while pass-through hooks fail open with empty stdout as before.
* style: apply repo formatter to touched hook files
- Replace off-brand hero PNG (wrong product name + baked version) with a
centered HTML header using assets/ecc-icon.svg, h1, and tagline
- Consolidate duplicated sponsor sections: polished centered sponsor table
at top (CodeRabbit, Greptile, community sponsors, sponsor links); bottom
section reduced to a one-liner pointing to SPONSORS.md
- Convert guide links to visual cards using the guides' own header images,
linked to the local guide files
- Fix broken tmux video URL in the shortform guide to the in-repo asset
Reduce the default .mcp.json to one connector (chrome-devtools) per the
new policy in docs/MCP-CONNECTOR-POLICY.md: a default earns its slot only
if it is universal AND MCP beats a CLI/API wrapped in a skill. June 2026
audit verdicts: github -> gh via github-ops skill; context7 -> REST via
documentation-lookup; exa -> harness-native search (+ exa-search skill);
memory -> native harness memory + instincts; playwright -> playwright CLI
skills (vendor moved agent flows off MCP); sequential-thinking -> native
extended thinking. All six remain opt-in in mcp-configs/mcp-servers.json.
Tests updated: plugin-manifest policy assertions + install-apply Cursor
expectations.
Co-authored-by: ECC Test <ecc@example.test>
On a published GitHub release, post the notes to the ECC Discord
#announcements channel (via bot), pin it, and cross-post to GitHub
Discussions (Announcements category). Release data flows through env vars
(no shell interpolation of untrusted input). Secrets: DISCORD_BOT_TOKEN,
DISCORD_ANNOUNCE_CHANNEL_ID (repo secrets), GITHUB_TOKEN.
Ties the 2.0.0/1.11.0 official release to the community launch.
Co-authored-by: ECC Test <ecc@example.test>
ROOT CAUSE: hooks load plugin-hook-bootstrap.js via
`node -e "...; process.argv.splice(1,0,s); require(s)"`. On Node 21+,
require.main is `undefined` under --eval, so the `if (require.main === module)`
guard was false and main() never ran — every plugin hook silently no-op'd
(e.g. the MCP-health PreToolUse hook stopped blocking). CI (Node 18/20) hid
this; it only surfaces on Node 21+. Fix: also run main() when require.main is
undefined (the eval-bootstrap case), while staying dormant on real imports.
Also clears pre-existing main debt the full local suite enforces:
- catalog:sync — README/docs agent+skill counts drifted after recent merges
- tests/ci/supply-chain-watch-workflow: update checkout SHA to the merged v6.0.3 (#2183)
- markdownlint + check-unicode-safety --write across docs/skills
Suite: 2683/2683 green under Node v25; lint + unicode clean.
Co-authored-by: ECC Test <ecc@example.test>
* 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>
* 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%.
* 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%.
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.
Salvages the useful harness-audit scoring work from #1989 while preserving the current hook registry and newer plugin install detection. Adds GitHub integration checks, conditional deploy-provider categories, dynamic applicable category metadata, and CODEOWNERS coverage.
Salvage focused changes from #1910 and #1911 on a maintainer-owned branch after full CI.
- enrich canary-watch discovery terms for post-deploy verification prompts
- narrow dashboard bare except handlers, add debug logging, and avoid double-configuring widgets
Co-authored-by: EunCHanPark <93873648+EunCHanPark@users.noreply.github.com>
Co-authored-by: shenchangmin <503228482@qq.com>
Restore the zh-CN autonomous-loops warning so the translated skill no longer recommends piping a remote install script directly into bash.
Co-authored-by: Golfi92 <Golfi92@users.noreply.github.com>
Salvages the useful parts of #1897 without generated .caliber state or stale counts.
- adds a deterministic command registry generator and drift check
- commits the current command registry for 75 commands
- validates the rc.1 README catalog summary against live counts
- adds a single Ubuntu Node 20 coverage job instead of running coverage in every matrix cell
Co-authored-by: jodunk <jodunk@users.noreply.github.com>