Commit Graph

13 Commits

Author SHA1 Message Date
Gaurav Dubey
a08445ad78 fix(suggest-compact): clean up old counter temp files (#2159)
* fix(suggest-compact): clean up old counter temp files

claude-tool-count-<sessionId> files were written into the OS temp dir
on every hook run and never removed, accumulating one orphan per
session indefinitely.

Sweep stale counter files at the top of main() before opening the
active counter. Retention is env-tunable via COMPACT_STATE_TTL_DAYS
(default 14 days); invalid values fall back to the default. The
active session's counter file is preserved unconditionally even if
its mtime is past the cutoff. Failures during the sweep are swallowed
to preserve the always-exit-0 hook contract.

Adds 7 regression tests covering the sweep, env-var validation, and
the always-exit-0 invariant under a populated temp dir.

Fixes #2156

* fix(suggest-compact): preserve counter files at the TTL cutoff boundary

The cleanup sweep used `mtimeMs > cutoffMs` to short-circuit, which
matched files whose mtime sits exactly on the cutoff boundary and
deleted them. The cleanupOldCounters docstring promises only files
*older than* retentionDays are removed; a file at age == retentionDays
is not older than retentionDays, so it must survive.

Switch the comparison to `>=` so only strictly older files fall
through to deletion. Add a regression test that pins boundary-aged
files (mtimeMs sitting just past the projected cutoff) are preserved.

Refs #2156
2026-06-07 13:01:27 +08:00
Affaan Mustafa
375d750b4c fix: integrate recent hook and docs PRs (#1905)
Integrates useful changes from #1882, #1884, #1889, #1893, #1898, #1899, and #1903:
- fix rule install docs to preserve language directories
- correct Ruby security command examples
- harden dev-server hook command-substitution parsing
- add Prisma patterns skill and catalog/package surfaces
- allow first-time protected config creation while blocking existing configs
- read cost metrics from Stop hook transcripts
- emit suggest-compact additionalContext on stdout

Co-authored-by: Jamkris <dltmdgus1412@gmail.com>
Co-authored-by: Levi-Evan <levishantz@gmail.com>
Co-authored-by: gaurav0107 <gauravdubey0107@gmail.com>
Co-authored-by: richm-spp <richard.millar@salarypackagingplus.com.au>
Co-authored-by: zomia <zomians@outlook.jp>
Co-authored-by: donghyeun02 <donghyeun02@gmail.com>
2026-05-14 21:37:28 -04:00
Affaan Mustafa
1abc3fb381 fix: port hook session and dashboard safety fixes
Ports suggest-compact session_id isolation and dashboard terminal/document launch safety onto current main.
2026-05-11 02:53:28 -04:00
jtzingsheim1
9661a6f042 fix(hooks): scrub secrets and harden hook security (#348)
* fix(hooks): scrub secrets and harden hook security

- Scrub common secret patterns (api_key, token, password, etc.) from
  observation logs before persisting to JSONL (observe.sh)
- Auto-purge observation files older than 30 days (observe.sh)
- Strip embedded credentials from git remote URLs before saving to
  projects.json (detect-project.sh)
- Add command prefix allowlist to runCommand — only git, node, npx,
  which, where are permitted (utils.js)
- Sanitize CLAUDE_SESSION_ID in temp file paths to prevent path
  traversal (suggest-compact.js)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(hooks): address review feedback from CodeRabbit and Cubic

- Reject shell command-chaining operators (;|&`) in runCommand, strip
  quoted sections before checking to avoid false positives (utils.js)
- Remove command string from blocked error message to avoid leaking
  secrets (utils.js)
- Fix Python regex quoting: switch outer shell string from double to
  single quotes so regex compiles correctly (observe.sh)
- Add optional auth scheme match (Bearer, Basic) to secret scrubber
  regex (observe.sh)
- Scope auto-purge to current project dir and match only archived
  files (observations-*.jsonl), not live queue (observe.sh)
- Add second fallback after session ID sanitization to prevent empty
  string (suggest-compact.js)
- Preserve backward compatibility when credential stripping changes
  project hash — detect and migrate legacy directories
  (detect-project.sh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(hooks): block $() substitution, fix Bearer redaction, add security tests

- Add $ and \n to blocked shell metacharacters in runCommand to prevent
  command substitution via $(cmd) and newline injection (utils.js)
- Make auth scheme group capturing so Bearer/Basic is preserved in
  redacted output instead of being silently dropped (observe.sh)
- Add 10 unit tests covering runCommand allowlist blocking (rm, curl,
  bash prefixes) and metacharacter rejection (;|&`$ chaining), plus
  error message leak prevention (utils.test.js)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(hooks): scrub parse-error fallback, strengthen security tests

Address remaining reviewer feedback from CodeRabbit and Cubic:

- Scrub secrets in observe.sh parse-error fallback path (was writing
  raw unsanitized input to observations file)
- Remove redundant re.IGNORECASE flag ((?i) inline flag already set)
- Add inline comment documenting quote-stripping limitation trade-off
- Fix misleading test name for error-output test
- Add 5 new security tests: single-quote passthrough, mixed
  quoted+unquoted metacharacters, prefix boundary (no trailing space),
  npx acceptance, and newline injection
- Improve existing quoted-metacharacter test to actually exercise
  quote-stripping logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(security): block $() and backtick inside quotes in runCommand

Shell evaluates $() and backticks inside double quotes, so checking
only the unquoted portion was insufficient. Now $ and ` are rejected
anywhere in the command string, while ; | & remain quote-aware.

Addresses CodeRabbit and Cubic review feedback on PR #348.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 14:47:31 -08:00
Affaan Mustafa
f4758ff8f0 fix: consistent periodic interval spacing in suggest-compact, add 10 tests
- suggest-compact.js: count % 25 → (count - threshold) % 25 for consistent
  spacing regardless of threshold value
- Update existing periodic interval test to match corrected behavior
- 10 new tests: interval fix regression (non-25-divisible threshold, false
  suggestion prevention), corrupted counter file, 1M boundary, malformed
  JSON pass-through, non-TS extension pass-through, empty sessions dir,
  blank template skip
2026-02-13 02:45:08 -08:00
Affaan Mustafa
0e0319a1c2 fix: clamp suggest-compact counter overflow, add 9 boundary tests
Counter file could contain huge values (e.g. 999999999999) that pass
Number.isFinite() but cause unbounded growth. Added range clamp to
reject values outside [1, 1000000].

New tests cover:
- Counter overflow reset (huge number, negative number)
- COMPACT_THRESHOLD zero fallback
- session-end empty sections (no tools/files omits headers)
- session-end slice boundaries (10 messages, 20 tools, 30 files)
- post-edit-console-warn 5-match limit
- post-edit-console-warn ignores console.warn/error/debug
2026-02-13 01:59:25 -08:00
Affaan Mustafa
bc0520c6c1 fix: broken cross-references, version sync, and enhanced command validator
- Fix /build-and-fix → /build-fix in tdd.md, plan.md (+ cursor, zh-CN)
- Fix non-existent explorer agent → planner in orchestrate.md (+ cursor, zh-CN, zh-TW)
- Fix /python-test → /tdd in python-review.md (+ cursor, zh-CN)
- Sync package.json version from 1.0.0 to 1.4.1 to match plugin.json
- Enhance validate-commands.js with cross-reference checking:
  command refs, agent path refs, skill dir refs, workflow diagrams
- Strip fenced code blocks before scanning to avoid false positives
- Skip hypothetical "Creates:" lines in evolve.md examples
- Add 46 new tests (suggest-compact, session-manager, utils, hooks)
2026-02-12 16:19:04 -08:00
Affaan Mustafa
ed7ec29ead fix: migrate hooks to stdin JSON input, fix duplicate main() calls, add threshold validation
- Migrate session-end.js and evaluate-session.js from CLAUDE_TRANSCRIPT_PATH
  env var to stdin JSON transcript_path (correct hook input mechanism)
- Remove duplicate main() calls that ran before stdin was read, causing
  session files to be created with empty data
- Add range validation (1-10000) on COMPACT_THRESHOLD in suggest-compact.js
  to prevent negative or absurdly large thresholds
- Add integration/hooks.test.js to tests/run-all.js so CI runs all 97 tests
- Update evaluate-session.sh to parse transcript_path from stdin JSON
- Update hooks.test.js to pass transcript_path via stdin instead of env var
- Sync .cursor/ copies
2026-02-12 15:33:55 -08:00
Affaan Mustafa
63be081741 fix: renameAlias data corruption, empty sessionId match, NaN threshold
- Fix renameAlias() leaving orphaned newAlias key on save failure,
  causing in-memory data corruption with both old and new keys present
- Add sessionPath validation to setAlias() to reject empty/null paths
- Guard getSessionById() against empty string matching all sessions
  (startsWith('') is always true in JavaScript)
- Fix suggest-compact.js NaN comparison when COMPACT_THRESHOLD env var
  is set to a non-numeric value — falls back to 50 instead of silently
  disabling the threshold check
- Sync suggest-compact.js to .cursor/ copy
2026-02-12 14:30:10 -08:00
Affaan Mustafa
36864ea11a fix: harden error handling, fix TOCTOU races, and improve test accuracy
Core library fixes:
- session-manager.js: wrap all statSync calls in try-catch to prevent
  TOCTOU crashes when files are deleted between readdir and stat
- session-manager.js: use birthtime||ctime fallback for Linux compat
- session-manager.js: remove redundant existsSync before readFile
- utils.js: fix findFiles TOCTOU race on statSync inside readdir loop

Hook improvements:
- Add 1MB stdin buffer limits to all PostToolUse hooks to prevent
  unbounded memory growth from large payloads
- suggest-compact.js: use fd-based atomic read+write for counter file
  to reduce race window between concurrent invocations
- session-end.js: log when transcript file is missing, check
  replaceInFile return value for failed timestamp updates
- start-observer.sh: log claude CLI failures instead of silently
  swallowing them, check observations file exists before analysis

Test fixes:
- Fix blocking hook tests to send matching input (dev server command)
  and expect correct exit code 2 instead of 1
2026-02-12 13:40:14 -08:00
Affaan Mustafa
18c5a76a96 fix: improve error handling, fix bugs, and optimize core libraries
utils.js:
- Fix countInFile: enforce global flag on regex to prevent silent
  under-counting (match() without /g returns only first match)
- Add 5s timeout to readStdinJson to prevent hooks hanging forever
- Handle EEXIST race condition in ensureDir
- Pre-compile regex patterns in getGitModifiedFiles to avoid N*M
  compilations and catch invalid patterns before filtering
- Add JSDoc documentation to all improved functions

session-manager.js:
- Fix getSessionById triple file read: pass pre-read content to
  getSessionStats instead of re-reading from disk
- Allow getSessionStats to accept content string directly

session-aliases.js:
- Wrap temp file cleanup in try/catch to prevent cascading errors

check-console-log.js:
- Refactor to use shared utils (isGitRepo, getGitModifiedFiles, log)
  instead of raw execSync calls
- Add exclusion patterns for test files, config files, and scripts/
  where console.log is intentional

session-end.js:
- Log count of skipped unparseable transcript lines for diagnostics

suggest-compact.js:
- Guard against NaN from corrupted counter files

package-manager.js:
- Remove dead fallbackOrder parameter (unused after #162 fix)
2026-02-12 07:06:53 -08:00
Affaan Mustafa
a44a0553bb fix: resolve ESLint errors and update tests for project-name fallback
- Fix 16 ESLint no-unused-vars errors across hook scripts and tests
- Add eslint-disable comment for intentional control-regex in ANSI stripper
- Update session file test to use getSessionIdShort() instead of hardcoded 'default'
  (reflects PR #110's project-name fallback behavior)
- Add marketing/ to .gitignore (local drafts)
- Add skill-create-output.js (terminal output formatter)

All 69 tests now pass. CI should be green.
2026-01-29 02:58:51 -08:00
zerx-lab
970f8bf884 feat: cross-platform support with Node.js scripts
- Rewrite all bash hooks to Node.js for Windows/macOS/Linux compatibility
- Add package manager auto-detection (npm, pnpm, yarn, bun)
- Add scripts/lib/ with cross-platform utilities
- Add /setup-pm command for package manager configuration
- Add comprehensive test suite (62 tests)

Co-authored-by: zerx-lab
2026-01-22 23:08:07 -08:00