Rebind the unchanged manually curated trigger payload to the current registry. Preserve all trigger entries, provenance and timestamps; no provider generation is implied.
Preserve the contributor repair and current main protections. Handle operand ordering, bounded literal command wrappers, executable containers and find actions while keeping quoted prose and option values passive.
Source-PR: https://github.com/affaan-m/ECC/pull/2829
Source-Head: c88b3f879a
Integration-Main: d3b8a3e908
Preserve the contributor pin and current main. Keep both default connector declarations at the exact official 1.10.1 release and retain user-managed configuration behavior.
Source-PR: https://github.com/affaan-m/ECC/pull/3233
Source-Head: 62bf2b2910
Integration-Main: d3b8a3e908
Preserve the contributor security repair and current main. Apply the artifact sandbox to SVG document responses and report unavailable symlink checks separately from passing assertions.
Source-PR: https://github.com/affaan-m/ECC/pull/3241
Source-Head: d237e1972f
Integration-Main: d3b8a3e908
Attribute unrecorded OpenCode aliases only to exact trusted ECC source or build bytes while keeping planned and recorded destinations strict. Pass the trusted source root through repair plans and preserve unrelated user plugin files.
* fix(install): make install.sh robust to sh/dash invocation
Two related portability fixes so `sh install.sh` behaves correctly
even though the script is written for bash:
- The cygpath detection used the bash-only `&>/dev/null` redirection.
dash misparses `&>`, so `command -v cygpath &>/dev/null` always took
the true branch and tried to run the nonexistent `cygpath` binary,
failing with "cygpath: not found". Switched to the POSIX-portable
`>/dev/null 2>&1` form.
- Some dash builds don't support `set -o pipefail`, so `sh install.sh`
can fail immediately at that line before even reaching the cygpath
check (or the `[[ ... ]]` symlink-resolution logic further down).
Added a guard that re-execs the script under bash when the current
shell lacks bash capabilities, so the rest of the bash-only syntax
always runs under a real bash regardless of the invoking shell. The
guard probes for the `[[` compound command directly (via
`eval '[[ 1 == 1 ]]'`) rather than trusting the $BASH_VERSION
environment variable, since that variable could be inherited or
spoofed under a non-bash shell and cause the guard to be skipped.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XBaBRjaZgwhrZtYoqcQfp
* test(install): cover the sh install.sh re-exec path
Greptile flagged that the bash re-exec guard added in install.sh has
no automated coverage, since the existing test helper only invoked
the wrapper via `bash`. Adds two regression tests:
- "delegates to the Node installer when invoked via a POSIX sh
wrapper" — runs the script via `sh` and asserts the args/cwd still
reach the Node installer correctly.
- "re-execs into bash under sh even when BASH_VERSION is spoofed in
the environment" — exercises the eval '[[ 1 == 1 ]]' capability
probe directly, guarding against a regression back to trusting the
(spoofable) $BASH_VERSION variable.
CodeRabbit then pointed out that the second test used generic `sh`,
which could trivially pass without exercising the re-exec branch at
all if `sh` ever resolves to bash on some system. Added a
findPosixOnlyShell() helper that prefers `dash` (falling back to
checking `sh`, and skipping with an explicit message if neither
genuinely lacks bash's `[[`), so the test reliably exercises the
branch it claims to cover instead of passing vacuously.
CodeRabbit then flagged that the skip path itself was miscounted as
a pass (the callback returned normally, so `test()` reported success
and `passed` was incremented even though nothing executed). Moved
the findPosixOnlyShell() check outside the test() registration, so
the test is only registered — and only counted — when a genuinely
POSIX-only shell is actually available; otherwise it's excluded from
both the passed and failed counts with an explicit skip line.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019XBaBRjaZgwhrZtYoqcQfp
---------
Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>
The settled-token guard correctly ignored an older poll, but that poll
still set settledPoll to its own token on the way out. With three polls
settling in the order 3, 1, 2, the ignored poll 1 pulled the mark back
to 1, so the even older poll 2 then passed the guard and replaced poll
3's counts, or marked a healthy view offline.
The mark now only moves forward. A poll that settles late is itself
stale, so it has no business moving the mark at all.
Covered by a new runtime case that settles three polls out of order as
3, 1, 2, once with an older success and once with an older failure. The
success case catches the counts regressing, the failure case catches a
healthy view being marked offline. Reverting the fix trips each of them
independently, and the unmutated file passes all 21.
Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
Reject reserved device names (including with extensions and the
superscript COM/LPT variants), trailing dots or spaces, and colon
stream syntax on every platform, and execute the documented snippet
in a regression test.
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>
Add the mirror fixture for the fence scan: $MY_CLAUDE_PROJECT_DIR,
${MY_CLAUDE_PROJECT_DIR}, $CLAUDE_PROJECT_DIR_TMP and
${CLAUDE_PROJECT_DIR_TMP} in a bash fence must not fail. The scan
already requires the `$` to be attached and ends on a word boundary, so
this pins the pass side as firmly as the fail side.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EzFUaXW84Y6LHzKysc5mTc
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>
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>
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>
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>
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>