Commit Graph
2818 Commits
Author SHA1 Message Date
pasmudandCommandCodeBot cee58ba39e fix(control-pane): settle the poll guard against the last settled request
The staleness guard compared a poll against the newest poll STARTED, and
only the failure path used it. Two orderings were wrong.

An older success settling after a newer one had no guard at all, so it
overwrote the newer counts, the canvas label and the announcement with
older data. Both paths now check the token.

An older failure settling while a newer poll was still in flight was
discarded, because a newer poll had merely started. The page then kept
the last successful counts and its no-steering message as if they were
current. Anchoring the guard to the newest poll that has SETTLED fixes
that: the older failure is still the newest thing to have settled, so it
lands, and the pending poll restores the view when it answers.

That single change covers both orderings, so the guard no longer needs
to know which path it is on. Each poll records itself as settled when it
finishes, whatever the outcome.

A poll also had no timeout, so a request that never answered left the
last steering guidance on screen indefinitely. Each poll now aborts
after ten seconds through an AbortController, and that abort is what
wakes the poll, so a timeout is reported as an outage instead of
silently leaving stale guidance.

The test harness can now hold a request open indefinitely and fire
pending timers on demand, so the timeout is exercised without waiting.
New assertions cover an older success losing to a newer one, an older
failure landing while a newer poll is in flight and then being
recovered by it, and a hung poll timing out into the offline state.
Removing the success guard, re-anchoring the guard to the last started
poll, and removing the timeout each fail one of those assertions, and
the unmutated file passes all of them.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-27 08:11:44 +00:00
pasmudandCommandCodeBot e97e333040 fix(control-pane): keep the canvas label and live region consistent
Two ways the outage state could mislead an operator reading either
channel.

The failure branch cleared the live region but left the canvas
aria-label holding the counts from the last successful poll, so landing
on the canvas during an outage reported stale counts. It now sets the
same unavailable wording on the canvas. apply() already restores the
count label on the next valid poll, and there is now a test for that.

Polls run every 5000ms and are not sequenced, so a slow older request
can settle after a newer one has succeeded. Its catch block then
announced an outage while the canvas showed the newer counts, and the
two channels contradicted each other. Each poll now takes a monotonic
token and only the newest one may touch the view, so a superseded
failure is dropped.

The runtime test can park a response, which lets it settle an older
failure after a newer success. New assertions cover the canvas label
after an outage, the restored label after recovery, and the
superseded-failure case. Removing the canvas reset, the token guard, or
the restore in apply() each fail an assertion, and the unmutated view
passes all of them.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-27 02:44:18 +00:00
pasmudandCommandCodeBot 9e0996c6d6 fix(control-pane): replace stale live-region guidance when a poll fails
The live region announced the advisory and steering state on every
change, but a failed or invalid poll only set the visible status to
offline. The live region kept the last known message, so during an
outage a screen-reader user could still hear "No steering is required"
from a poll that had already failed. That is worse than silence,
because stale guidance reads as current.

Route announcements through a single helper and have the failure path
replace the guidance with a message saying the data is unavailable and
the counts are unknown. The helper still suppresses a repeat of the
same message, so a continuing outage stays quiet and recovery speaks
again.

Cover the success then failure and failure then recovery sequences at
runtime. Reverting just the failure-path announcement fails the new
assertion, and the unmutated view passes all of them.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-27 02:01:44 +00:00
pasmudandCommandCodeBot 6744a01748 fix(control-pane): announce polled advisories through a live region
The control-plane view polls every few seconds and rewrites the canvas
aria-label with the new counts, but neither the canvas nor #status is a
live region, so a screen-reader user working elsewhere never hears an
advisory appear.

Add a visually hidden polite live region that speaks only when the
advisory and steering counts actually move. Re-announcing an unchanged
summary every five seconds would talk over the operator without saying
anything new, so the last announced pair is remembered and a no-change
poll writes nothing. The canvas keeps its own label as the on-demand
description.

Also give the runtime test a recording canvas context and a populated
view, so the rendered risk words, the marker shapes, and the live region
are asserted at runtime rather than only against template source. The
risk-level assertion now reads the rendered risk cells instead of the
whole panel, where a level word could be satisfied by a task id.

The populated assertions were mutation checked: collapsing the marker
shapes, dropping the risk words, freezing the canvas label, announcing
on every poll, emptying the live region, and removing the steering cue
each fail at least one assertion.

Fixes the no-regex-spaces lint error on the riskColor match, which used
two literal spaces in a row.

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
2026-09-27 00:46:39 +00:00
pasmudandCommandCodeBot 18e78da390 test(control-pane): derive the a11y palette from the rendered view
CodeRabbit correctly noted that hard-coding #2ea043 and #ff7b72 in the
test decoupled the contrast assertions from the colors the view
actually renders, so a palette change could leave them passing.

The test now reads the legend glyphs, the legend colors, the
riskColor() returns, and the body background back out of the rendered
HTML, and asserts that the legend and canvas palettes agree before
checking any ratio. Verified both directions: a mismatched canvas
color fails the palette check, and a full revert to #3fb950 fails the
luminance check at 1.01:1.

Extends the coverage to the traffic level and the body background,
which were previously unchecked.

Co-Authored-By: CommandCodeBot <noreply@commandcode.ai>
2026-09-26 22:59:22 +00:00
pasmudandCommandCodeBot 3052732f28 fix(control-pane): add non-color risk cues to the control-plane view
The control-plane projection encoded risk with hue alone. The clear
green #3fb950 and the resolution red #ff7b72 differ by only 1.01:1 in
relative luminance, so a red-green color-blind operator saw the same
grey for "clear" and "steer now".

Risk now carries a second, non-color channel, matching the pattern
merged for the sibling airspace view in #3193:

- markers are drawn as a circle, square, or triangle per risk level
- the legend shows the matching glyph instead of color-only dots
- the Lanes panel prints the level name next to the percentage
- the canvas gets role="img" and a live aria-label describing counts

The clear green also moves to #2ea043 so it stays separable from the
resolution red by luminance (1.34:1) while keeping 5.73:1 against the
#0b0e14 background.

Adds tests/lib/control-plane-view-ui-a11y.test.js covering the roles,
the shapes, the legend, and the contrast ratios. The existing test
harness needed a setAttribute stub for the new aria-label update.

Co-Authored-By: CommandCodeBot <noreply@commandcode.ai>
2026-09-26 22:52:34 +00:00
Tony YuandGitHub e482e57941 docs: point the Kimi Code link at the international site (kimi.ai/code) (#3183)
kimi.com/code serves mainland China (WeChat / +86 sign-in, Alipay and WeChat Pay), so ECC's international readers cannot sign up or pay there.
Point the Kimi Code link in the install-target tables at kimi.ai/code (Google sign-in, card payment) instead, keeping the same aff value.
2026-09-24 11:52:47 -05:00
xsfandGitHub bf70150eb2 fix(gateguard): sanitize dangerous invisible unicode in denial paths (#3103)
* fix(gateguard): sanitize dangerous invisible unicode in denial paths

sanitizePath only stripped control characters and bidi overrides, so
the 394 codepoints that the repo-wide unicode safety policy classifies
as dangerous-invisible (zero-width U+200B-200D, U+2060, U+2061-2064,
variation selectors U+FE00-FE0F, tag block U+E0000-E007F, Hangul
fillers, U+FEFF, U+180E, U+3164) plus the U+2028/U+2029 line and
paragraph separators passed verbatim into Edit/Write denial messages.
Invisible characters in a quoted file path let a malicious path look
clean to a human reviewer.

Align sanitizePath with the CI policy list and cover it with a
hook-output regression test that asserts no dangerous invisible
character survives into the denial reason while visible path text
stays intact.

* refactor(gateguard): name the sanitizePath unicode policy constants

Address review feedback: move the code points and ranges out of
sanitizePath into descriptive constants mirroring
scripts/ci/check-unicode-safety.js, so the policy is auditable in one
place. Also seed the regression test input with U+2029 so the
paragraph-separator assertion is exercised rather than vacuous.

* fix(gateguard): sanitize C1 control characters in denial paths

Follow-up on the sanitizePath policy alignment: the Unicode C1 control
block (U+0080..U+009F) is invisible in every renderer like the ASCII
controls below 0x20, but the strip only covered the ASCII range. Add
C1_CONTROLS to the policy constants and seed U+0091 into the
regression test input.
2026-09-21 14:40:16 -04:00
LukasandGitHub 8b951d3bf6 fix(skill-comply): stop a failed step supplying evidence downstream (#3109)
* fix(skill-comply): stop a failed step supplying evidence downstream

`_check_temporal_order` fell back to the raw classifier output whenever
the referenced step was absent from `resolved`. A step only enters
`resolved` once it passes, so "failed" and "not graded yet" were the
same thing to that lookup, and a dependant could pass on an event
belonging to a prerequisite that had failed its own ordering check.

With three steps C, A (before C) and B (after A) and events C@T0,
A@T1, B@T2, A fails and B passed on A's classified event: 2/3 instead
of 1/3. It compounds down a chain, so one failed prerequisite could
leave a five-step workflow reading 4/5.

The grader now tracks which steps have been graded at all. A referenced
step that was graded and is missing from `resolved` failed, and its
events are refused with a reason that says so. A step not graded yet is
a forward reference to a step declared later, and the fallback stays as
it was: that is what makes an out-of-order declaration work, and the
existing regression for it goes red if the fallback is removed instead.

`before_step` deliberately keeps the old fallback. The two fail in
opposite directions: an `after_step` fallback can only turn a failure
into a pass, a `before_step` one can only turn a pass into a failure,
so dropping it would relax a constraint because some other step failed.

* fix(skill-comply): revoke a pass that rested on a later-failing prerequisite

Review of #3109 found the mirror image of the case that PR fixes. `graded`
only catches a prerequisite that had already failed when its dependant was
graded. A step declared *before* its `after_step` is graded against the
classifier's raw events for a step that has not run yet — the fallback that
makes an out-of-order declaration work — and nothing revisited it once that
step went on to fail its own checks.

Add a pass after grading that demotes any detected step whose `after_step`
ended up failing, repeated to a fixed point: one demotion can invalidate
whatever depended on it, in either declaration order. Demotion only removes
passes, so it terminates. `compliance_rate` is computed from the demoted
results.

Also from review: build `graded` and the chain test's step list as new
objects rather than mutating (AGENTS.md immutability rule), and annotate the
injected mocks in the tests this PR owns.
2026-09-21 14:39:20 -04:00
Varun GoreandGitHub 7b7dfc6412 fix(gateguard): detect destructive SQL passed quoted to SQL clients (#3107)
* fix(gateguard): detect destructive SQL passed quoted to SQL clients

Quoted SQL like psql -c "drop table users" was stripped before the DESTRUCTIVE_SQL_DD regex ran, making it unreachable. Check dequoted tokens for known SQL clients (psql, mysql, sqlite3, ...) so real invocations are gated while git commit -m / echo mentions stay allowed. Fixes affaan-m/ECC#3024.

* fix(gateguard): unwrap sudo/env flags and ignore SQL string literals

Address review: sudo -u/env VAR= wrappers now resolve to the real SQL client; SQL single/double/dollar-quoted literals are stripped before the destructive regex so SELECT 'drop table' stays allowed. Adds deny/allow regression tests for quoted SQL, wrappers, literals, and non-SQL clients.

* test(gateguard): cover env PGPASSWORD wrapper variant

* fix(gateguard): close wrapper sh-c, env dir, tagged literal gaps

Review 5189686662: recurse sh -c from unwrapped wrapper index (sudo/doas/env + sh -c now denied); consume env -C/--chdir separate values; strip tagged dollar-quoted literals ($tag$...\baseline). Tests: 200 passed.
2026-09-21 14:39:17 -04:00
Ram SinghandGitHub 43b3a01ee0 Update README with install health check instructions (#3196)
Added instructions for checking install health with npx.
2026-09-21 14:33:21 -04:00
Sedat DağandGitHub c056ae7df2 fix(hooks): support python style comments in pre-commit quality checks (#3194)
* fix(hooks): support python style comments in pre-commit quality checks

fix(hooks): support python style comments in pre-commit quality checks

* fix: reject whitespace-only TODO messages

* fix: reject whitespace-only TODO messages

* test: add cases for hash-prefixed comments and string limitations
2026-09-21 14:33:19 -04:00
aspandGitHub d7cf4584cf fix: restore Claude plugin setup compatibility (#3205)
* fix: stop passing removed Claude plugin config flags

* test: cover current Claude plugin install arguments

* docs: add beginner Windows install walkthrough
2026-09-21 14:32:26 -04:00
pablolozano0216-artandGitHub 8d59727633 fix(skills): confine frontend-slides export server to the deck directory and bind loopback (#3206)
The temporary HTTP server that export-pdf.sh spins up to render a deck
joined the decoded request path onto SERVE_DIR without checking the
resolved path, and listened on all interfaces. A request such as
`/..%2f..%2f..%2fetc%2fpasswd` (raw, or issued by a malicious deck via
fetch() while it renders) returned files outside the deck directory, and
any host on the network could hit the port while an export was running.

- resolve the decoded path against SERVE_ROOT and answer 403 when the
  result is not inside it (handles ../, %2e%2e, %2f and query strings)
- answer 400 on malformed percent-encoding instead of throwing
- listen on 127.0.0.1 only; the only client is the local headless browser

Verified with raw HTTP requests against the handler: `/` and
`/index.html` -> 200, `/../x`, `/..%2f..%2fx`, `/%2e%2e/x`,
`/deck/../../x` -> 403, unknown file -> 404, `/%zz` -> 400, and
server.address() reports 127.0.0.1.

Fixes #3101
2026-09-21 14:32:21 -04:00
TamerandGitHub 2b6e839771 Fix/proximity a11y risk cues (#3193)
* fix(control-plane): add non-color airspace risk cues

* test(control-plane): cover airspace accessibility cues
2026-09-20 15:37:57 -04:00
TamerandGitHub 651118bd50 Fix/control plane canvas size (#3192)
* fix(control-plane): constrain visualization canvas layout

* fix(control-plane): constrain visualization canvas layout

* test(control-plane): guard bounded canvas layout
2026-09-20 15:37:51 -04:00
TamerandGitHub 9606a741af fix(control-pane): handle proximity HTTP errors (#3191) 2026-09-20 15:37:47 -04:00
9ac593b55c fix(scripts): extract cross-platform openBrowser helper with structured launch result (#3180)
scripts/plan-canvas.js and scripts/control-pane.js both define their own
openBrowser helpers for launching the user's default browser. The two
implementations have diverged:

- plan-canvas.js dispatches across darwin/win32/linux but its
  try/spawn try/catch does not catch async child errors (ENOENT/EACCES
  on hosts without the launcher command). Returns a bare true/false.
- control-pane.js is darwin-only and silently returns early on
  Windows/Linux, so the two scripts behave inconsistently across
  platforms.

When the launcher command is missing (e.g. headless CI without xdg-open)
the JSON output still says 'browser: opened', lying to the agent.

Changes:
- scripts/lib/platform-launch.js: shared openBrowser helper that
  dispatches per platform, wires child 'error' so ENOENT/EACCES
  propagate, and returns {opened, reason} instead of a bare boolean.
- scripts/plan-canvas.js: drops its local helper, imports the shared
  one, and adds browserReason to its JSON output.
- scripts/control-pane.js: replaces its darwin-only branch with the
  shared helper and logs the structured reason on failure.
- tests/lib/platform-launch.test.js: 7 node:test cases covering
  opener-command selection, invalid-URL guard, structured-result
  shape, and a smoke run for the actual spawn.

Verification: node --test tests/lib/platform-launch.test.js → 7/7 pass.

Co-authored-by: auyua9 <auyua9@users.noreply.github.com>
2026-09-20 14:26:52 -04:00
EasternandGitHub 95448ad81d fix: isolate Claude project hooks from ESM hosts (#3184)
* fix: isolate Claude project hooks from ESM hosts

* fix: handle user-owned Claude scripts package
2026-09-20 14:26:49 -04:00
111387afe4 docs: fix dead MCP overview link in shortform guide (#3190)
The Claude Code docs page at code.claude.com/docs/en/mcp-overview no
longer exists (404). The current MCP page is
https://code.claude.com/docs/en/mcp ("Connect Claude Code to tools via
MCP"). Update the link in the English, zh-CN, and tr versions of the
shortform guide.

Co-authored-by: kuishou68 <kuishou68@users.noreply.github.com>
2026-09-20 14:26:46 -04:00
Affaan MustafaandGitHub 934195f955 Merge pull request #3123 from VarunGore36/fix/security-critical-hardening
Fix/security critical hardening
2026-09-19 20:01:13 -04:00
Affaan MustafaandGitHub b0e2f26b63 Merge pull request #3124 from kapelame/audit/ecc-python-sdk-floor
fix(llm): require an OpenAI SDK that supports provider initialization
2026-09-19 20:01:11 -04:00
Affaan MustafaandGitHub fc9273e5e0 Merge pull request #3126 from VarunGore36/fix/reviewer-followups
fix(security): security follow-ups for worker, installer, claw, hooks
2026-09-19 19:58:43 -04:00
Affaan MustafaandGitHub a0600a00fb Merge pull request #3125 from kapelame/audit/ecc-opencode-output-contract
fix(opencode): write hook results through the output contract
2026-09-19 19:58:40 -04:00
Affaan MustafaandGitHub b2279eb1d7 Merge pull request #3130 from shoyann/fix/preserve-codex-user-config
fix: preserve edited Codex user configuration during reinstall and repair
2026-09-19 17:09:20 -04:00
Affaan MustafaandGitHub 1ec2263b3f Merge pull request #3137 from iyertalks/fix/pi-doctor-scoped-companion
fix(pi): recognize @scope/pi-subagents in /ecc-doctor companion check
2026-09-19 17:09:18 -04:00
Affaan MustafaandGitHub f06d4a02d9 Merge pull request #3064 from wellkilo/feat/dashboard-output-cursor
perf(ecc2): stream dashboard output with a DB cursor
2026-09-19 17:03:57 -04:00
Affaan MustafaandGitHub 0a5207b6f2 Merge pull request #3102 from wellkilo/perf/metrics-tail-read
perf(metrics): cache cumulative session costs
2026-09-19 17:00:05 -04:00
Affaan MustafaandGitHub 4ec7229146 Merge pull request #3104 from cedrickcantero/fix/security-review-sql-placeholder
fix(skills): avoid a literal $1 placeholder in the security-review sql example
2026-09-19 16:53:47 -04:00
Affaan MustafaandGitHub ada4db1157 Merge pull request #3111 from Fibilisim-Tekno/fix/memory-initialized-metadata
fix(memory-mcp): accept metadata on initialized notifications
2026-09-19 16:51:53 -04:00
Affaan MustafaandGitHub e030cb492a Merge pull request #3117 from affaan-m/dependabot/github_actions/actions-minor-and-patch-f97e9e776c
chore(deps): bump the actions-minor-and-patch group with 2 updates
2026-09-19 16:47:29 -04:00
Affaan MustafaandGitHub 56f6807274 Merge pull request #3118 from affaan-m/dependabot/cargo/ecc2/cargo-minor-and-patch-d4c8c185e0
chore(deps): bump the cargo-minor-and-patch group across 1 directory with 3 updates
2026-09-19 16:44:55 -04:00
Affaan MustafaandGitHub 91ba9b4cf6 Merge pull request #3133 from affaan-m/release/ecc-universal-2.2.2
release: ecc-universal 2.2.2
2026-09-19 16:41:20 -04:00
Affaan MustafaandGitHub 1e8e3ad0ac Merge pull request #3172 from Frank-zhu0404/fix/issue-3171-observe-sdk-cli
fix(continuous-learning-v2): allow sdk-cli entrypoint in observe.sh (#3171)
2026-09-19 16:34:38 -04:00
Frank_zhu 08813f49ff test(security): Layer-1 observe.sh entrypoint allowlist evidence (#3171)
Add focused security regression for sdk-cli allowlisting and document
IOC scan + allowlist probe output under .pr/security-evidence-3171.md.

Signed-off-by: Frank_zhu <58329837+Frank-zhu0404@users.noreply.github.com>
2026-09-19 20:56:34 +08:00
Frank_zhu b14004f12f fix(continuous-learning-v2): allow sdk-cli entrypoint in observe.sh (#3171) 2026-09-19 20:33:41 +08:00
Affaan MustafaandGitHub 07756cee15 fix(gateguard): gate ref- and history-destroying git commands (#3154, #3151) (#3170)
branch -D, stash drop/clear, reflog expire/delete, update-ref -d, restore (except --staged alone), and force-with-lease pushes to shared branches now hit the destructive gate. 238 hook tests pass; 49 CI checks green.
2026-09-19 02:58:33 -04:00
Affaan MustafaandGitHub f6eb800474 fix(session-start): scope summary lookup to repository identity (#3160) (#3168)
Windows: compare repo identity via normalizeRepoPath/sameRepoIdentity (8.3 short names, case, separators; inode fallback). All nine windows-latest jobs green on 52587005.
2026-09-19 02:08:50 -04:00
Affaan MustafaandGitHub 9e06a2792b Merge pull request #3162 from affaan-m/fix/readme-badges-star-history-20260918
docs: repair README badges and live star history
2026-09-18 22:34:23 -04:00
Affaan MustafaandGitHub 522b49a3c5 Merge branch 'main' into fix/readme-badges-star-history-20260918 2026-09-18 22:13:36 -04:00
Affaan MustafaandGitHub 10013e8b63 Merge pull request #3149 from affaan-m/docs/lane-rules-20260916
Docs: lane rules and Ito desk relationship (2026-09-16)
2026-09-18 22:13:33 -04:00
Affaan MustafaandGitHub 2bcba5b66f Merge branch 'main' into docs/lane-rules-20260916 2026-09-18 22:06:49 -04:00
Affaan MustafaandGitHub dde604e75f Merge pull request #3146 from yashraj4/fix/agent-location-and-namespacing
fix: correct agent location and add ecc: prefix to agent names in rules
2026-09-18 22:06:46 -04:00
Affaan Mustafa 07e6b42e5c docs: use fenced code blocks in agent rules to satisfy MD046 2026-09-18 21:53:44 -04:00
Affaan Mustafa c7e60cc6a6 Merge remote-tracking branch 'origin/main' into pr-3146
# Conflicts:
#	docs/es/rules/common/agents.md
#	docs/ja-JP/rules/common/agents.md
#	docs/tr/rules/common/agents.md
#	docs/zh-CN/rules/common/agents.md
#	rules/common/agents.md
2026-09-18 21:47:13 -04:00
Affaan Mustafa 75970dda72 docs: fix LANE-RULES heading level and drop personal path 2026-09-18 21:41:50 -04:00
Affaan MustafaandGitHub ce7a4847ca Merge pull request #3147 from AniruddhaAdak/fix/ollama-generation-token-limit
fix(llm): forward max_tokens to Ollama num_predict
2026-09-18 21:10:31 -04:00
Affaan MustafaandGitHub 6715384bb5 Merge pull request #3153 from kenima-arc/docs/ja-readme-refresh
docs(ja-JP): refresh Japanese README to match the English README
2026-09-18 21:10:28 -04:00
Affaan MustafaandGitHub 4007e25b58 Merge pull request #3157 from Frank-zhu0404/fix/issue-2886-heredoc-gateguard
fix(gateguard): ignore heredoc prose for tee and path-qualified sinks
2026-09-18 21:10:25 -04:00
Affaan MustafaandGitHub 63d589903d Merge pull request #3158 from sharadvc/fix/agent-location-docs
docs(rules): fix ECC plugin agent location and ecc: namespaces
2026-09-18 21:10:23 -04:00