Commit Graph
535 Commits
Author SHA1 Message Date
Quinn O'Donnell 00a8fe96f8 fix(hooks): skip stdin listeners on require and match exact tsc paths in post-edit-typecheck
config-protection.js and post-edit-typecheck.js attached process.stdin
listeners at module scope. tests/hooks/hook-input.test.js requires
config-protection.js, so that test never exits while stdin stays open.
Attach the listeners only when the script runs directly
(require.main === module), as stop-format-typecheck.js and quality-gate.js
already do.

post-edit-typecheck.js picked tsc diagnostics with line.includes(candidate),
so editing a root index.ts reported the errors of src/index.ts, and a
Windows relative path (src\index.ts) never matched tsc's forward-slash
output. Compare the file at the start of each diagnostic instead, the same
check diagnosticMatchesFile() does in stop-format-typecheck.js.

Refs #3821
2026-10-30 12:29:32 -04:00
haelyra 35769d00d9 fix(context): validate budgets and remind before native compaction
Reject numeric prefixes, fractions and unsafe window integers consistently with summary scheduling while preserving resolver precedence. Cap only the default context reminder at eighty percent of a valid earlier native compaction budget; explicit thresholds, including zero, retain their intentional policy. Document the independent capacity, summary and advisory contracts.

RED controls reproduce malformed-budget summary triggers and the known-1M/native-200k missed reminder. Resolver65, helper47, actualStop18 and actualPreToolUse54 pass on Node18 and24. Parent and independent reviewer approved the exact diff before commit. Registry rebinding remains the integration coordinator responsibility after combining documentation repairs.
2026-10-29 19:42:27 -07:00
haelyra 05bc52ae83 test(insaits): report captured monitor failure diagnostics
Include captured stderr, status, signal and spawn error message when the existing unexpected-monitor-failure warning assertions fail. Preserve all status/raw-input/warning assertions, deadlines and product bytes.

The macOS hosted failure did not print its actual stderr, so its transient cause remains unverified. The unchanged source matches green main; 24 prior local diagnostic repeats passed 120 checks. This diagnostic-only patch passes all five fixture cases, affected ESLint and diff checks. Parent independently reviewed the diff. Fresh exact-head hosted CI remains required.
2026-10-29 19:15:02 -07:00
haelyra 3dca6e2e88 fix(hooks): preserve provider conversation identity under inherited environments
Restore the shipped payload-first contract from #3464/#3495 and the explicit source #3755 scope clarification. Two provider conversations must retain distinct IDs despite an inherited registered ECC parent ID. Normal and ambient producer24 tests, canonical resolver10 and independent differential review pass. Keep native importer guards; explicit provider/native correlation is queued separately.
2026-10-29 18:57:29 -07:00
haelyra 6cd41995f4 fix(hooks): attribute native activity to the registered ECC session
Verify review discussion4419348312 against actual native producer/importer behavior. Prefer the independently sanitized ECC_SESSION_ID for the ECC-owned metrics feed, retain payload then legacy fallback for standalone hooks, and leave sibling hooks unchanged.

Actual Node producer plus read-only cached native binary reproduces zero imported metrics before the fix and exactly one tool/file/log after repeated sessions/status commands. Four producer regression controls and normal/adversarial inherited-env suites pass22/22. Focused coverage96.47percent lines and91.47percent branches; parent independent source review passed.
2026-10-29 17:43:55 -07:00
haelyra b37942d3c1 fix(summary): preserve work before the earlier compaction boundary
Separate confirmed model capacity from Stop-summary scheduling. Use the smaller confirmed capacity/native budget, or native-only budget for inferred capacity. Three unit and one actual hook RED cases now pass; helper43, actualStop15 and ten independent controls pass without changing the capacity resolver.
2026-10-29 17:37:52 -07:00
haelyra fc549b6372 fix: preserve Windows rule examples and conservative summary budgets
Address #3809 review regressions for CRLF code fences and inferred context capacity. Reproduced unit and actual Stop-hook failures; verified llm-summary38, Stop14, Copilot37 and independent code/security review. Keep confirmed model/ECC context authority, native budget scheduling and unknown capacity separate.
2026-10-29 17:27:56 -07:00
haelyra ee21d8da5c fix(hooks): preserve context-window evidence over compact trigger (#3760) 2026-10-29 17:01:04 -07:00
haelyra 5e062a3b3b fix(hooks): integrate reviewed shell quote extraction fix (#3801) 2026-10-29 17:00:10 -07:00
haelyra 26507d9acd test: isolate transcript fixtures in an exclusive temporary directory 2026-10-29 12:08:17 -07:00
leoca eb9a5ca0c6 fix(hooks): keep $'...' open across an escaped apostrophe
Dropping the previous-character check in toggleQuote let the `'` of `\'` close an ANSI-C `$'...'` string, so `echo $'it\'s'; (rm -rf /tmp/x)` left a quote open and the group was never extracted. Track `$'...'` in the quote state and consume backslash escapes inside it, as bash does, and cover the inner scanners (`(...)`, `$(...)`, `{ ...; }` bodies) with quotes ending in a backslash.
2026-10-29 18:44:54 +00:00
haelyra 0cfce78d35 maint: integrate reviewed contribution #3568 2026-10-29 11:28:21 -07:00
haelyra 14ba1e211f maint: integrate reviewed contribution #3777 2026-10-29 11:27:40 -07:00
haelyra 291635f7f9 maint: integrate reviewed contribution #3776 2026-10-29 11:27:01 -07:00
haelyra ff9095f6f7 maint: integrate reviewed contribution #3775 2026-10-29 11:26:59 -07:00
haelyra 65d83f9290 maint: integrate reviewed contribution #3669 2026-10-29 11:25:30 -07:00
haelyra c7db9b410f maint: integrate reviewed contribution #3657 2026-10-29 11:25:29 -07:00
haelyra cbdd9be209 maint: integrate reviewed contribution #3778 2026-10-29 11:23:21 -07:00
haelyra 9aed578c67 fix: integrate symlink-aware GateGuard exemptions from #3726 2026-10-29 11:20:48 -07:00
haelyra 8e00137b04 fix: integrate observer identity and lease repair with canonical root matching 2026-10-29 11:19:43 -07:00
Brian La Plume 4a76f78411 fix(gateguard): expand unique sudo long-option prefixes
getopt_long accepts a unique prefix, so sudo --use root rm -rf build is
--user root and the resolver read root as the command. Expand unique
prefixes from sudo's long option table before the value/non-exec checks.
--help joins the non-executing modes.
2026-10-28 12:28:55 -07:00
Brian La Plume a46e36d488 fix(gateguard): sudo env assignments between options, missing value flags
sudo accepts VAR=value between its options (parse_args.c is_envar), so
sudo FOO=1 -u root rm -rf resolved -u as the command. Keep reading options
past assignments. Add sudo -R/--chroot, -a/--auth-type, -c/--login-class
and doas -a as value flags, and stop a short-cluster scan at any unknown
letter, so sudo -R/live rm -rf no longer reads the l in /live as -l.
doas -C only checks config, so it is non-executing; the existing doas -C dd
case moves to the passive list.
2026-10-28 12:13:25 -07:00
Brian La Plume 9f05c6fe01 test(run-with-flags): pin hook enablement env in GateGuard truncation tests 2026-10-28 11:55:06 -07:00
Brian La Plume fbb9d34fd1 test(config-protection): missing protected target before an existing one 2026-10-28 11:54:16 -07:00
Brian La Plume 7253c8a261 fix(gateguard): treat sudo list/validate/edit modes as non-executing
sudo -l/--list, -v, -K, -V and -e/--edit (and doas -L) do not run the
command operand, so sudo -l rm -rf build was denied as destructive. The
privilege-wrapper resolver now reports no executable command for those
modes. Short clusters stop at the first value flag, so sudo -ul rm -rf
(user l) stays destructive.
2026-10-28 11:54:13 -07:00
Muhammad Zubair b3b13350d1 test: isolate HOME in the test files that write to the real home directory 2026-10-28 12:20:21 +05:00
Wen 7d44734328 fix(continuous-learning-v2): redact numeric DSN passwords cut at the truncation boundary 2026-10-27 16:52:44 -03:00
Wen 64f28b6096 fix(continuous-learning-v2): redact tokens after JSON escapes and truncated DSNs
Dict tool I/O is JSON-encoded before scrubbing, so a newline before a bare
GitHub token or AWS key id became a literal \n and the leading \b never
matched. Replace it with a lookbehind that also accepts a preceding JSON
escape (\b \f \n \r \t or \uXXXX).

Capture truncation (5000 chars, 2000 in the parse-error fallback) can cut
a DSN right before its '@', which defeated the (?=@) password lookahead.
Let the password run to end of string, except a bare trailing host:port.

Applied to both matcher copies. Regression tests cover structured output
with tokens after escaped whitespace and DSNs cut before '@' on the
string, structured input/output and fallback paths. Refresh registryDigest.

Signed-off-by: Wen <jwcastillo@gmail.com>
2026-10-27 16:52:44 -03:00
Wen 4d17020f49 fix(continuous-learning-v2): redact cloud keys, DSNs and PEM blocks in observations
The observation scrubber in observe.sh only redacted a value placed
directly after a bare keyword (token=, secret:, ...). These reached
observations.jsonl in plain text:

- AWS_SECRET_ACCESS_KEY=... / aws_secret_access_key = ... / SECRET_KEY=
- scheme://user:password@host DSN passwords
- PEM private key blocks
- ghp_/gho_/ghu_/ghs_/ghr_ and github_pat_ tokens, AKIA/ASIA key ids

Both identical _SECRET_RE copies (parse-error fallback and main path)
now accept an optional _access_key/_key suffix on the keyword, and a
new _SECRET_VALUE_RE redacts the value-shaped secrets above. Every
branch is anchored on a literal prefix with bounded classes, keeping
the linear-time constraint from #2278.

The existing redaction test gains canaries for each case on both the
input and output paths, plus a negative case that ordinary code,
credential-free URLs and SSH remotes are left untouched.

registryDigest in skill-triggers@1.json is refreshed, which
validate-context-profiles requires after any skills/ change.

Signed-off-by: Wen <jwcastillo@gmail.com>
2026-10-27 16:52:44 -03:00
Brian La Plume 646b4d1442 fix(gateguard): classify rm/Git behind sudo/doas/env/command wrappers
isDestructiveRm/isDestructiveGit keyed on argv[0], so sudo rm -rf,
command rm -rf and env git reset --hard read as calls to the wrapper and
were allowed once the routine shell gate was satisfied. Run both checks on
the unwrapLeadWrappers argv too, the resolution the dd and sh -c paths
already use. Overlaps #2832, which also reworks sh -c parsing and has
conflicts with main; this is the minimal rm/Git part.
2026-10-27 11:06:20 -07:00
Brian La Plume 1d55d690b9 fix(run-with-flags): fail closed for oversized Bash GateGuard input
Fixes #3762. pre:bash:gateguard-fact-force was missing from
FAIL_CLOSED_ON_TRUNCATION_HOOKS, so a Bash payload over the stdin cap
exited 0 while the Edit and PowerShell GateGuard ids blocked. Share one
GateGuard id set for the fail-closed list and the off-switch branch, and
add runner-level tests for all three ids plus each off switch.
2026-10-27 11:03:36 -07:00
Brian La Plume ed2f02dd06 fix(config-protection): check MultiEdit edits[].file_path targets
Fixes #3761. config-protection only read tool_input.file_path, so a MultiEdit
with the config path inside edits[] edited an existing ruff.toml/.eslintrc
without the block. Check every effective target and block if any is an
existing protected config.
2026-10-27 11:03:02 -07:00
haelyra e10f72413f test(hooks): isolate Git fixtures from inherited env 2026-10-25 19:41:21 -04:00
haelyra 0a7a9a718e fix(hooks): use session repository for console warnings 2026-10-25 19:32:16 -04:00
haelyra 605e006137 Integrate L4XB PR #3662 2026-10-25 19:30:50 -04:00
haelyra 9c8a66b696 Integrate L4XB PR #3664 2026-10-25 19:30:50 -04:00
haelyra 0e7588cec5 Integrate L4XB PR #3667 2026-10-25 19:30:50 -04:00
haelyra 6ddc4ea007 Integrate L4XB PR #3666 2026-10-25 19:30:50 -04:00
Gaurav Dubey b98bff4a45 fix(observer): keep project context and leases aligned after remote changes
Integrates #3697 on current main. Prefer the observer project ID, retain a sole legacy ID until the new observer folder exists, and release the ending session lease across same-root aliases. Replace the unsafe live merge hint with read-only project inspection, and validate alias IDs before path use. #3711 independently identified the computed-ID selection gap; its early switch without observer data and unchanged SessionEnd path were not adopted.
2026-10-25 17:54:47 -04:00
Gaurav Dubey dcb947a4e1 fix(gateguard): judge exempt globs against real target location
Port #3656 onto current main, preserving both the contributor fix and the unrelated current changelog entry. Includes the follow-up glob normalization from 2c11fd74.
2026-10-25 17:47:30 -04:00
Gaurav DubeyandClaude Opus 5.5 ce37e4d16d test(hooks): pin hook flags in the held-open stdin helper
The held-open subprocess cases inherited ECC_HOOKS_ENABLED and
ECC_DISABLED_HOOKS from the caller, so disabling block-no-verify or all
hooks made them fail even though the dispatcher behaved correctly. Pin
both flags in the spawned environment.

Refs #3665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:52:59 +00:00
Gaurav DubeyandClaude Opus 5.5 707e0e1956 test(hooks): cover a complete Bash request on held-open stdin
The held-open subprocess cases only sent partial JSON. Add a complete
`git commit --no-verify` request with stdin left open and assert the
dispatcher reaches block-no-verify instead of reporting incomplete input.

Refs #3665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-23 00:33:46 +00:00
Gaurav DubeyandClaude Opus 5.5 2600c70298 fix(hooks): fail closed on incomplete input in bash-hook-dispatcher
- bash-hook-dispatcher: honor the reader's truncated flag. pre-Bash
  blocks (exit 2) because safety checks need the complete request;
  post-Bash skips its hooks and does not echo a partial payload.
- resolveStdinIdleTimeout: treat whitespace-only values as unset instead
  of Number('  ') === 0 silently disabling the deadline.
- isCompleteJsonObject: do not accept a JSON array as a hook payload.
- tests: wait for the child's close event so stdio is drained before
  asserting; cover both bash-hook-dispatcher modes.
- hooks/README.md: keep the example below the 5 s per-hook timeout.

Refs #3665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 23:18:47 +00:00
Gaurav DubeyandClaude Opus 5.5 943eb826b5 fix(hooks): clamp the stdin idle deadline to the timer maximum
setTimeout fires after 1 ms for any delay above 2147483647 ms, so a large
ECC_HOOK_INPUT_IDLE_TIMEOUT_MS turned the deadline into ~1 ms and marked
every hook input incomplete. Clamp to the maximum with a diagnostic, and
surface the invalid-value diagnostic when readStdinRaw resolves the env.

Refs #3665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 22:54:14 +00:00
Gaurav DubeyandClaude Opus 5.5 0ca9eeb3ce fix(hooks): stop hook stdin reads when the caller never sends EOF
readStdinRaw() only settled on end, error or close. If the parent kept
stdin open without writing EOF, every hook that reads through it waited
until the harness killed it (an 8-10 s stall per call).

Add an idle deadline (default 3000 ms, ECC_HOOK_INPUT_IDLE_TIMEOUT_MS,
0 disables). It is reset on each chunk, unref()ed, and on expiry detaches
from and pauses the stream so a held-open pipe cannot keep the hook alive.
Input that already parses as a complete JSON object is accepted; anything
else is marked truncated so fail-closed safety hooks still block.

bash-hook-dispatcher.js now reads through the shared reader instead of its
own end/error-only loop.

Fixes #3665

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 22:39:06 +00:00
L4XB 10e7c5800f fix(hooks): recognize Prettier's TypeScript and JSON5 config files
Prettier's config searcher also reads .prettierrc.json5, .prettierrc.ts/.mts/.cts and prettier.config.ts/.mts/.cts. resolve-formatter knew none of them, so a project configured only through prettier.config.ts was never formatted by post-edit-format, quality-gate or the Stop batch. config-protection's rc pattern stopped at .yaml/.toml, so an existing .prettierrc.ts or .prettierrc.json5 could be edited freely.
2026-10-22 23:51:32 +02:00
L4XB cd1f5b74e2 fix(hooks): match tsc diagnostics by the file they name
The Stop typecheck reported every tsc line that contained the edited path anywhere. A root index.ts has the relative path `index.ts`, which every `src/index.ts(...)` diagnostic contains, so a clean root file was reported with the errors of src/index.ts. The same happened to src/utils.ts with web/src/utils.ts, and to any file named in another file's message.

Compare the path that starts the diagnostic (`path(line,col): `), keeping the slash normalization for Windows.
2026-10-22 23:42:21 +02:00
L4XB b02e02dcd2 fix(hooks): list modified files from the repository root even with diff.relative
With diff.relative=true, `git diff --name-only` reports paths relative to the working directory, so joining them to the repository root pointed at files that do not exist, and a session in a subdirectory again got no console.log warning. getGitModifiedFiles now runs `git -c diff.relative=false diff --name-only HEAD`. The -c form also works on Git versions older than --no-relative.
2026-10-22 23:01:26 +02:00
L4XB 5311485e94 fix(hooks): keep a backslash in double quotes as bash does in the dev-server block
readToken dropped every backslash inside double quotes, while bash drops it only before $, `, ", \\ or a newline. `"echo ready\;"` therefore reached the tmux check as `echo ready;`, read as a command separator, and `tmux send-keys -t dev "echo ready\;" "npm run dev" Enter` was blocked although it types into a pane.
2026-10-22 22:45:28 +02:00
L4XB adf435d36f fix(hooks): find console.log in modified files from a subdirectory session
check-console-log took the paths from `git diff --name-only HEAD`, which are relative to the repository root, and checked them with fs.existsSync from the hook's working directory. In a session started in a subdirectory, such as a monorepo package, no path existed from there, so the hook never warned. Resolve each path from the repository root. The exclusion patterns and the warning still use the root-relative path.
2026-10-22 22:42:08 +02:00