Commit Graph
1179 Commits
Author SHA1 Message Date
Affaan MustafaandAffaan Mustafa d53359a974 refactor(scripts): table-drive the operator readiness dashboard
parseArgs now reads flags from two lookup tables, one for flags that take a
value in either form and one for standalone switches, instead of thirty-odd
if blocks. The ECC Tools evidence and gap text live in ordered tier tables
keyed by roadmap markers, with the shared marker lists named once.
buildRequirements reads its docs and readiness checks up front, then
assembles the list from four requirement groups. The PR and issue budget
rows share one builder.

Flag errors, requirement order, and every message string are unchanged.
Verified by comparing parseArgs over a flag matrix and buildReport over the
repo, an empty root, and one synthetic roadmap per marker. Clears the four
complexity warnings on this file.
2026-10-19 22:18:32 -04:00
Affaan MustafaandAffaan Mustafa 905bb16ff2 refactor(lib): split gateguard file-context scanners by token
cFamilyStartsFresh ran one 130-line loop over template literals, comments,
regex-vs-division, C# and Rust raw strings, quotes, words, and punctuation.
It now keeps scanner state in one object and walks a fixed list of step
functions, each returning consumed, abort, or not-mine. The Python f-string
field scan, the shell heredoc and quote tokens, and the PowerShell
here-string, block comment, and hash tokens get the same treatment.

Verified byte-for-byte against the recorded test inputs, four hundred real
source files from the repo, random prefixes, and single-character mutations
across every flavor spec. Clears the five complexity warnings on this file.
2026-10-19 22:18:32 -04:00
Affaan MustafaandAffaan Mustafa 1e787f62f5 refactor(lib): split install-lifecycle repair and inspect paths
executeRepairOperation, executeUninstallOperation, and inspectManagedOperation
now dispatch on operation kind to one small function per kind, with the
repeated uninstall result shapes and previous-content restore pulled into
helpers. executeRepairOperation takes an options object instead of four
trailing positionals. analyzeRecord is a sequence of collect* steps, and the
per-record repair closure inside repairInstalledStates hands off to
runRecordRepair with the legacy OpenCode, build-only dry run, and managed
repair paths as separate functions.

Result objects keep the same keys in the same order, and lock, build, and
require ordering is unchanged. Clears the max-params and complexity warnings
on this file.
2026-10-19 22:18:32 -04:00
Affaan MustafaandAffaan Mustafa 3849426a95 refactor(ci): share the catalog count replacer
Six summary-line replacers in catalog.js each took seven to nine positional
capture groups and rebuilt the line by hand. They now go through one
catalogCountReplacer factory that takes the regex group count and the groups
holding the agents, skills, and commands counts. Every other group is written
back verbatim.

Output is byte-identical across the real docs and several synthetic catalogs.
Clears the six max-params warnings on this file.
2026-10-19 22:18:32 -04:00
Affaan MustafaandAffaan Mustafa 8c1925722c refactor(lib): split powershell destructive-command scanners
The here-string normalizer, comment stripper, and balanced-group reader each
carried their own copy of the same inert-region state machine. They now share
createLexState, consumeInertChar, and openInertRegion. The container
extractor, statement tokenizer, nested pwsh scanner, cmd scanner, Start-Process
scanner, and top-level statement walk are split into small named helpers that
each handle one region or one command family.

No classification change. Verified against the recorded test inputs plus
mutated variants with an order-sensitive comparison of findings. Clears the
eleven complexity and prefer-const warnings on this file.
2026-10-19 22:18:32 -04:00
Affaan MustafaandAffaan Mustafa 944ea9d050 fix(ci): unescape node -e inline programs in one pass
validateInlineJs unescaped the shell body with four chained replaces,
so a backslash pair followed by n or t was unescaped twice: the pair
became one backslash, then the new backslash-n became a newline. A
valid hook command such as console.log('\\n') failed validation with
an unterminated string. CodeQL flags the chain as double unescaping.

One regex pass maps each escape exactly once. The regression test
feeds the escaped-backslash program through the validator CLI.
2026-10-19 22:03:57 -04:00
Affaan MustafaandAffaan Mustafa d3c49a80df refactor(ci): split validate-hooks into per-shape validators
validateHookEntry handled command, http and prompt hooks in one function; it now dispatches to validateCommandHook, validateHttpHook and validatePromptHook with the inline node -e check in validateInlineJs. validateHooks reads the file, loads the sidecar and validates the object or legacy array shape through readHooksFile, loadMetadata, validateObjectFormat and validateArrayFormat, so the deepest nesting is gone.

Error messages, their order, exit codes and the --update-fingerprints flow are unchanged.
2026-10-19 22:03:57 -04:00
Affaan MustafaandAffaan Mustafa 35c7681d47 refactor(hooks): break up session-end summary and main flow
extractSessionSummary did user-message filtering and two kinds of tool_use collection in one loop body six blocks deep. The per-entry work now lives in userMessageText, recordToolUse and collectEntry. main() is down to the sequence of steps: resolveTranscriptPath, sessionShortId, maybeGenerateLlmSummary, then updateSessionFile or createSessionFile, with the shared footer and empty-session template as constants.

Call order, log lines, file names and the written markdown are unchanged, including the exact summary block replacement and the migration path for files without markers.
2026-10-19 22:03:57 -04:00
Affaan MustafaandAffaan Mustafa 7b1756670f refactor(hooks): split gateguard gate and classifiers into smaller units
gate() handled Edit, MultiEdit and shell in one 220-line function. It now builds a small context and dispatches to gateSingleEdit, gateMultiEdit and gateShell, with the first-touch, sibling-collapse and routine/destructive shell steps as their own functions. isDestructiveGit and isReadOnlyGitIntrospection became subcommand tables; unwrapLeadWrappers got one handler per wrapper; ddLauncherCommandIndex, isDestructiveFindExec and sanitizePath lost their inline option and code point ladders. condensedGateMsg takes an options object instead of seven positional parameters.

Decision order, recorded metrics reasons, state keys and every denial message are unchanged, and the module exports are the same.
2026-10-19 22:03:57 -04:00
Affaan MustafaandAffaan Mustafa cfcd81c076 refactor(lib): share span readers in shell-substitution
extractSubshellGroups and extractBraceGroups each carried their own copies of the quote-aware skipping for $(...), backtick and (...) spans, which is where the complexity and nesting warnings came from. The skipping now lives in findParenSpanEnd, findBacktickEnd and skipOuterSpan, with readSubshellBody and readBraceBody doing the body collection.

Behavior is unchanged: the same bodies come back in the same order, trailing backslashes and unterminated spans resolve the same way, and the three exports keep their signatures.
2026-10-19 22:03:57 -04:00
Affaan MustafaandAffaan Mustafa 603e1dee1e refactor(hooks): flatten block-no-verify decision tree
checkGitWords, executableWords, shellRole, updateShellState and checkCommand were each well over the complexity budget and checkCommand nested seven blocks deep. Split them into named helpers: git global option scanning and bypass flag search, per-wrapper handlers for command/exec/env/sudo, a shell option cluster classifier, declaration flag parsing, and a per-task/per-state/per-environment pipeline inside checkCommand.

Every budget.spend call keeps its amount and order so the work quota tests still land in the same window. The module still only requires ./lib/shell-scan and exports run unchanged. Wrapper option sets moved to module constants instead of being rebuilt on every call.
2026-10-19 22:03:57 -04:00
Affaan MustafaandGitHub 6c557856af feat(ci): cap open PRs per contributor at ten (#3639)
Extend the PR burst guard with an open-PR cap. On every opened or reopened
PR by a non-collaborator, the guard lists the repository's open PRs, keeps
the author's oldest `maxOpen` (10) open and closes the newer ones with a
bot comment that names the count and the limit. No lock, no maintainer
alert: the cap is about review capacity, not spam. PRs the burst logic
already closed in the same run are excluded so nothing is mutated twice.
Collaborators with write access stay exempt, dry run reports without
mutating, and the comment is deduplicated on a bot-authored marker.

Haley asked for this on 2026-10-19: each contributor should only have 10
to 15 PRs open at a time. Existing open PRs are not bulk-closed; the cap
applies as each author opens or reopens their next PR.

Verification: 22 unit tests and the HTTP workflow test pass,
validate-workflow-security passes, eslint and markdownlint clean. Dry run
against affaan-m/ECC on #3621 reports openCount 19 and nine cap excess
PRs for that author, with no writes.
2026-10-19 18:08:53 -04:00
haelyra 0ad248d199 feat(ci): guard PR submission bursts and alert maintainers 2026-10-15 14:33:45 -04:00
haelyra 1d1b62e58e fix: recover plugin migration at the effective settings scope 2026-10-11 15:36:49 -04:00
haelyra 87c136fcae fix: integrate strict issue targeting and Windows Python discovery 2026-10-11 15:07:29 -04:00
haelyra c7a467061b Merge remote-tracking branch 'origin/pr-3523' into steward/late-arrivals-20261011 2026-10-11 15:00:38 -04:00
haelyra a4d9297da1 fix: allow bounded sustained Windows atomic replacement contention 2026-10-11 13:47:57 -04:00
akushonkamen 3cf0e709d5 fix(github-coordination): reject malformed issue numbers instead of truncating them
normalizeIssueNumber parsed with Number.parseInt, which stops at the
first non-digit ("42oops" -> 42, "42.9" -> 42, "4e2" -> 4) and loses
precision past 2^53 (9007199254740993 became 9007199254740992). The CLI
shares this helper for --issue, --limit, and the positional issue number,
so malformed values silently targeted the wrong issue before any integer
guard downstream could notice.

Validate the entire trimmed decimal token and require
Number.isSafeInteger so malformed or out-of-range values throw
"Invalid issue number" during argument parsing, before the state store
is opened or GitHub is contacted. Whitespace, leading plus, and leading
zero tolerance is preserved. Regression coverage added at both the
library level (tests/lib/github-coordination-gh-api.test.js) and the CLI
argument parser (tests/scripts/github-coordination.test.js).

Fixes #3514
2026-10-12 01:25:09 +08:00
haelyra 0d4fd902ca fix: carry verified storage capability and deterministic Canvas checks 2026-10-11 12:49:24 -04:00
haelyra bded8387eb fix: preflight and document snapshot storage capability 2026-10-11 12:34:15 -04:00
haelyra 99ee8a8818 fix: carry reviewed staging and plugin-root input guards into follow-up batch 2026-10-11 12:09:35 -04:00
haelyra 1ec5b328c6 fix: normalize root overrides and report unverified snapshot staging 2026-10-11 12:05:00 -04:00
haelyra 32e0a10023 fix: preserve reviewed recovery and command-discovery repairs in follow-up batch 2026-10-11 11:50:21 -04:00
haelyra 3fa6e30502 fix: preserve rollback version state and bounded runtime workflows 2026-10-11 11:45:41 -04:00
haelyra 1abc625de9 fix: integrate six focused workflow repairs with canonical registry identity 2026-10-11 11:19:21 -04:00
haelyra a668d06f30 fix: publish rollback target snapshot before replacing live skill 2026-10-11 11:14:44 -04:00
haelyra c4b8325945 fix: prepare six focused ECC reliability repairs
Preserve complete source ancestry for PRs #3512, #3513, #3515, #3516, #3517 and #3518. Repair bounded recovery, alias compatibility and evaluator packaging gaps while keeping registry reuse inside the canonical loader. Verified actual hook, setup, dashboard, evaluator, sandbox and profile workflows plus full npm, Python, lint and supply-chain checks. ECC-043 preparation only; integration remains with the delivery owner.
2026-10-11 11:10:53 -04:00
haelyra 4e337f0a43 fix: integrate contributor snapshot allocation revision 2026-10-11 10:48:41 -04:00
montjeffrey 8e99eaa4e3 perf(context): load the registry once per resolution and routing index build
compileContextProfile now validates its options, loads the registry and
calls compileContextPlan(registry, options), which compiles against a
registry the caller loaded in the same call. resolveTaskContext and
routingEntries load the registry once and compile from it, so the sources
are hashed once per call instead of twice.

On this repository (full@1, Windows 11, median of 5):
resolveTaskContext 1332 ms -> 645 ms, routingEntries 1321 ms -> 721 ms.

The registry never comes from outside the call: nothing caches it or
accepts one from a caller, so a stale or forged registry cannot be passed
in. The two "Registry changed during ..." checks compared the two loads and
are gone with the second load; each call now works from one snapshot, and
skill bytes are still verified against it when read. compileContextProfile
keeps its signature, output and error order.

Split out of #2945, whose prompt hook is superseded by #3453.
2026-10-11 10:33:21 -04:00
Eneko Ruiz 6d8e69df52 fix: skip occupied snapshot paths without overflowing 2026-10-11 16:29:15 +02:00
haelyra 4ce5ae0119 fix: preserve search scope and installed cache discovery 2026-10-11 10:25:44 -04:00
haelyra a73e04cc6d fix: recover failed ledger batches and preserve project state 2026-10-11 09:42:05 -04:00
akushonkamen cbca1dc2cc fix(claude-plugin): target explicitly disabled destinations in scope migration
Issue #3492: scope migration aborted with generic verification errors in
two real states. When the destination scope is installed but inventory
reports enabled:false because the user explicitly set
enabledPlugins["ecc@ecc"]: false, setup now throws a targeted
DESTINATION_EXPLICITLY_DISABLED error naming the setting and file and
offering the native claude plugin enable recovery, leaving the user's
choice untouched. The generic not-enabled error also gains the enable
command in its recovery list.

uninstallSource now accepts a destination-only state when the source
scope is gone from the fresh inventory even if the uninstall command
errored, and SOURCE_UNINSTALL_FAILED recovery no longer suggests
uninstalling a source scope the inventory no longer lists; it prepends
claude plugin list --json so the stuck state can be inspected.

Tests: node tests/lib/claude-scope-migration.test.js — five new cases
cover explicitly disabled resume and single-scope destinations across
user/project/local settings files, the generic fallback keeping the
enable path, an uninstall error with the source already absent, and
non-circular recovery. 16 -> 21 passing; red against unpatched scripts
is 15 passed / 6 failed. Full-suite failure set is byte-identical to
unpatched HEAD in a zero-dependency environment.

Also sync the pinned SOURCE_UNINSTALL_FAILED recovery in
tests/scripts/setup.test.js ('migration JSON failures retain phase,
scopes, and exact recovery') with the new claude plugin list --json
diagnostic: 29 passed / 1 failed on the patched tree before the sync,
30 passed / 0 failed after, identical to clean 2d515e4f.
2026-10-11 20:48:43 +08:00
chenhz01 cffcf05e7a hooks: sed labels end at semicolon — commands after b/t/T/: are still scanned
CodeRabbit security finding on the merged sed work (CWE-693, verified live
on main via #3495): GNU sed labels for b, t, T and : end at ';' or newline —
verified against GNU sed 4.9 ('bar;e cmd' parses label 'a' and still runs
cmd; '}' is not a label terminator). Reading those operands to end of line
let 'sed :a;e git commit --no-verify' pass the hook while sed executed the
e command.

Labels are now read up to ';' or newline and command parsing resumes after
them. Text, filename and quit operands (a, c, i, r, w, q, Q) keep the
end-of-line reading: nothing after them on the line executes.

5 regression tests pin the three bypass paths and the benign boundary
(a bare label and a bare branch stay data). Suite: 817/817.
2026-10-11 18:52:44 +08:00
haelyra 15d9ffd1c9 fix: validate rollback allocation before changing live skill 2026-10-11 06:49:37 -04:00
haelyra 61b1d49538 fix: bound snapshot allocation to safe version numbers 2026-10-11 06:42:29 -04:00
haelyra a7e5c4d030 fix: preserve snapshot paths and reject malformed skill tracking rows 2026-10-11 06:32:21 -04:00
haelyra 2df7533ee4 chore: include verified first-cohort GateGuard repair 2026-10-11 06:32:21 -04:00
haelyra 2f8b126e3a Merge reviewed contributor PR #3507 for incoming stewardship 2026-10-11 06:17:51 -04:00
haelyra a33e5b3312 Merge reviewed contributor PR #3506 for incoming stewardship 2026-10-11 06:17:51 -04:00
haelyra 542b6a89c1 Merge reviewed contributor PR #3505 for incoming stewardship 2026-10-11 06:17:51 -04:00
haelyra a0b286011a test: preserve Windows GateGuard corpus denial policy 2026-10-11 06:15:49 -04:00
Eneko Ruiz 3ac34cfc3c fix: validate skill execution failure reasons before storage 2026-10-11 11:37:01 +02:00
Eneko Ruiz 1ae4b88e06 fix: skip non-object skill execution JSONL rows 2026-10-11 11:35:31 +02:00
haelyra 3d8f31285f fix: preserve rg type case and filename exclusion scope 2026-10-11 05:35:14 -04:00
Eneko Ruiz acb75bc1ed fix: ignore directories when listing skill snapshots 2026-10-11 11:33:41 +02:00
Eneko Ruiz 32bbddab1d fix: keep unchanged skill rates stable at zero threshold 2026-10-11 11:31:21 +02:00
haelyra bdc9f4b04e Merge verified usage display and actual Compose callback corrections 2026-10-11 03:58:18 -04:00
haelyra 3e395c6b76 fix: preserve opt-in usage data and publish networked callbacks 2026-10-11 03:53:30 -04:00
haelyra 58b704977a fix: correct late search credit and security test gates 2026-10-11 03:51:36 -04:00