Commit Graph
100 Commits
Author SHA1 Message Date
Affaan Mustafa 0e9f613fd1 Revert "feat(ecc): prune plugin 43→12 items, promote 7 rules to .claude/rules/ (#245)"
This reverts commit 1bd68ff534.
2026-02-20 01:11:30 -08:00
Affaan Mustafa 0b11849f1e chore: update skill count from 37 to 43, add 5 new skills to directory listing
New community skills: content-hash-cache-pattern, cost-aware-llm-pipeline,
regex-vs-llm-structured-text, swift-actor-persistence, swift-protocol-di-testing
2026-02-16 20:04:57 -08:00
Affaan Mustafa 2c26d2d67c fix: add missing process.exit(0) to early return in post-edit-console-warn hook 2026-02-16 20:03:12 -08:00
Affaan Mustafa 182e9e78b9 test: add 3 edge-case tests for readFile binary, output() NaN/Infinity, loadAliases __proto__ safety
Round 125: Tests for readFile returning garbled strings (not null) on binary
files, output() handling undefined/NaN/Infinity as non-objects logged directly
(and JSON.stringify converting NaN/Infinity to null in objects), and loadAliases
with __proto__ key in JSON proving no prototype pollution occurs.
Total: 935 tests, all passing.
2026-02-13 18:44:07 -08:00
Affaan Mustafa 0250de793a test: add 3 edge-case tests for findFiles dotfiles, getAllSessions date format, parseSessionMetadata title regex
Round 124: Tests for findFiles matching dotfiles (unlike shell glob where *
excludes hidden files), getAllSessions strict date equality filter (wrong format
silently returns empty), and parseSessionMetadata title regex edge cases
(no space after #, ## heading, multiple H1, greedy \s+ crossing newlines).
Total: 932 tests, all passing.
2026-02-13 18:40:07 -08:00
Affaan Mustafa 88fa1bdbbc test: add 3 edge-case tests for countInFile overlapping, replaceInFile $& tokens, parseSessionMetadata CRLF
Round 123: Tests for countInFile non-overlapping regex match behavior (aaa with
/aa/g returns 1 not 2), replaceInFile with $& and $$ substitution tokens in
replacement strings, and parseSessionMetadata CRLF section boundary bleed where
\n\n fails to match \r\n\r\n. Total: 929 tests, all passing.
2026-02-13 18:36:09 -08:00
Affaan Mustafa 2753db3a48 test: add 3 edge-case tests for findFiles dot escaping, listAliases limit falsy values, getSessionById old format
Round 122: Tests for findFiles glob dot escaping (*.txt must not match filetxt),
listAliases limit=0/negative/NaN returning all due to JS falsy check, and
getSessionById matching old YYYY-MM-DD-session.tmp filenames via noIdMatch path.
Total: 926 tests, all passing.
2026-02-13 18:30:42 -08:00
Affaan Mustafa e50b05384a test: add Round 121 tests for findFiles ? glob, setAlias path validation, and time metadata extraction
- findFiles: ? glob pattern matches single character only (converted to . regex)
- setAlias: rejects null, empty, whitespace-only, and non-string sessionPath values
- parseSessionMetadata: Started/Last Updated time extraction — present, missing, loose regex

Total tests: 923
2026-02-13 18:25:56 -08:00
Affaan Mustafa 26f3c88902 test: add Round 120 tests for replaceInFile empty search, setAlias length boundary, and notes extraction
- replaceInFile: empty string search — replace prepends at pos 0, replaceAll inserts between every char
- setAlias: 128-char alias accepted (boundary), 129-char rejected (> 128 check)
- parseSessionMetadata: "Notes for Next Session" extraction — last section, empty, ### boundary, markdown

Total tests: 920
2026-02-13 18:23:55 -08:00
Affaan Mustafa df2d3a6d54 test: add Round 119 tests for appendFile type safety, renameAlias reserved names, and context extraction
- appendFile: null/undefined/number content throws TypeError (no try/catch like writeFile)
- renameAlias: reserved names rejected for newAlias (parallel check to setAlias, case-insensitive)
- parseSessionMetadata: "Context to Load" code block extraction — missing close, nested blocks, empty

Total tests: 917
2026-02-13 18:21:39 -08:00
Affaan Mustafa 25c5d58c44 test: add Round 118 edge-case tests for writeFile type safety, renameAlias self, and reserved alias names
- writeFile: null/undefined/number content throws TypeError (no try/catch unlike replaceInFile)
- renameAlias: same-name rename returns "already exists" (no self-rename short-circuit)
- setAlias: reserved names (list, help, remove, delete, create, set) rejected case-insensitively

Total tests: 914
2026-02-13 18:19:21 -08:00
Affaan Mustafa 06af1acb8d test: add Round 117 edge-case tests for grepFile CRLF, getSessionSize boundaries, and parseSessionFilename case
- grepFile: CRLF content leaves trailing \r on lines, breaking anchored $ patterns
- getSessionSize: boundary formatting at 0B, 1023B→"1023 B", 1024B→"1.0 KB", non-existent→"0 B"
- parseSessionFilename: [a-z0-9] regex rejects uppercase short IDs (case-sensitive design)

Total tests: 911
2026-02-13 18:16:10 -08:00
Affaan Mustafa 6a0b231d34 test: add Round 116 edge-case tests for replaceInFile null coercion, loadAliases extra fields, and ensureDir null path
- replaceInFile: null/undefined replacement coerced to string "null"/"undefined" by JS String.replace ToString
- loadAliases: extra unknown JSON fields silently preserved through load/save round-trip (loose validation)
- ensureDir: null/undefined path throws wrapped Error (ERR_INVALID_ARG_TYPE → re-thrown)

Total tests: 908
2026-02-13 18:11:58 -08:00
Affaan Mustafa a563df2a52 test: add edge-case tests for countInFile empty pattern, parseSessionMetadata CRLF, and updateAliasTitle empty string coercion (round 115) 2026-02-13 18:05:28 -08:00
Affaan Mustafa 53e06a8850 test: add edge-case tests for listAliases type coercion, replaceInFile options.all with RegExp, and output BigInt serialization (round 114) 2026-02-13 18:01:25 -08:00
Affaan Mustafa 93633e44f2 test: add 3 tests for century leap years, zero-width regex, and markdown titles (Round 113)
- parseSessionFilename rejects Feb 29 in century non-leap years (1900, 2100) but accepts 2000/2400
- replaceInFile with /(?:)/g zero-width regex inserts at every position boundary
- parseSessionMetadata preserves raw markdown formatting (**bold**, `code`, _italic_) in titles

Total: 899 tests
2026-02-13 17:54:48 -08:00
Affaan Mustafa 791da32c6b test: add 3 tests for Unicode alias rejection, newline-in-path heuristic, and read-only append (Round 112)
- resolveAlias rejects Unicode characters (accented, CJK, emoji, Cyrillic homoglyphs)
- getSessionStats treats absolute .tmp paths with embedded newlines as content, not file paths
- appendSessionContent returns false on EACCES for read-only files

Total: 896 tests
2026-02-13 17:47:50 -08:00
Affaan Mustafa 635eb108ab test: add 3 tests for nested backtick context truncation, newline args injection, alias 128-char boundary
Round 111: Tests for parseSessionMetadata context regex truncation at
nested triple backticks (lazy [\s\S]*? stops early), getExecCommand
accepting newline/tab/CR in args via \s in SAFE_ARGS_REGEX, and setAlias
accepting exactly 128-character alias (off-by-one boundary). 893 tests total.
2026-02-13 17:41:58 -08:00
Affaan Mustafa 1e740724ca test: add 3 tests for findFiles root-unreadable, parseSessionFilename year 0000, uppercase ID rejection
Round 110: Tests for findFiles with unreadable root directory returning
empty array (vs Round 71 which tested subdirectory), parseSessionFilename
year 0000 exposing JS Date 0-99→1900-1999 mapping quirk, and uppercase
session ID rejection by [a-z0-9]{8,} regex. 890 tests total.
2026-02-13 17:30:38 -08:00
Affaan Mustafa 6737f3245b test: add 3 tests for appendFile new-file creation, getExecCommand traversal, getAllSessions non-session skip
Round 109:
- appendFile creating new file in non-existent directory (ensureDir + appendFileSync)
- getExecCommand with ../ path traversal in binary (SAFE_NAME_REGEX allows ../)
- getAllSessions skips .tmp files that don't match session filename format
2026-02-13 17:24:36 -08:00
Affaan Mustafa 1b273de13f test: add 3 tests for grepFile Unicode, SAFE_NAME_REGEX traversal, getSessionSize boundary
Round 108:
- grepFile with Unicode/emoji content (UTF-16 string matching on split lines)
- getRunCommand accepts ../ path traversal via SAFE_NAME_REGEX (allows / and . individually)
- getSessionSize exact 1024-byte B→KB boundary and 1MB KB→MB boundary
2026-02-13 17:18:06 -08:00
Affaan Mustafa 882157ac09 test: add 3 tests for Round 107 (881 total)
- grepFile with ^$ pattern verifies empty line matching including trailing newline phantom
- replaceInFile with self-reintroducing replacement confirms single-pass behavior
- setAlias with whitespace-only title exposes missing trim validation vs sessionPath
2026-02-13 17:11:32 -08:00
Affaan Mustafa 69799f2f80 test: add 3 tests for Round 106 (878 total)
- countInFile with named capture groups verifies match(g) ignores group details
- grepFile with multiline (m) flag confirms flag is preserved unlike stripped g
- getAllSessions with array/object limit tests Number() coercion edge cases
2026-02-13 17:07:13 -08:00
Affaan Mustafa b27c21732f test: add 3 edge-case tests for regex boundary, sticky flag, and type bypass (Round 105)
- parseSessionMetadata: blank line within Completed section truncates items
  due to regex lookahead (?=###|\n\n|$) stopping at \n\n boundary
- grepFile: sticky (y) flag not stripped like g flag, causing stateful
  .test() behavior that misses matching lines
- getExecCommand: object args bypass SAFE_ARGS_REGEX (typeof !== 'string')
  but coerce to "[object Object]" in command string
2026-02-13 16:59:56 -08:00
Affaan Mustafa 332d0f444b test: add Round 104 edge-case tests (detectFromLockFile null, resolveSessionAlias traversal, whitespace notes)
- detectFromLockFile(null): throws TypeError — no input validation before
  path.join (package-manager.js:95)
- resolveSessionAlias('../etc/passwd'): returns path-traversal input unchanged
  when alias lookup fails, documenting the passthrough behavior
- parseSessionMetadata with whitespace-only notes: trim() → "" → hasNotes=false,
  whitespace-only notes treated as absent

Total tests: 872 (all passing)
2026-02-13 16:45:47 -08:00
Affaan Mustafa 45a0b62fcb test: add Round 103 edge-case tests (countInFile bool, grepFile numeric, loadAliases array)
- countInFile(file, false): boolean falls to else-return-0 type guard (utils.js:443)
- grepFile(file, 0): numeric pattern implicitly coerced via RegExp constructor,
  contrasting with countInFile which explicitly rejects non-string non-RegExp
- loadAliases with array aliases: typeof [] === 'object' bypasses validation
  at session-aliases.js:58, returning array instead of plain object

Total tests: 869 (all passing)
2026-02-13 16:08:47 -08:00
Affaan Mustafa a64a294b29 test: add 3 edge-case tests for looksLikePath heuristic, falsy title coercion, and checkbox regex (Round 102)
- getSessionStats with Unix nonexistent .tmp path triggers looksLikePath
  heuristic → readFile returns null → zeroed stats via null content path
- setAlias with title=0 silently converts to null (0 || null === null)
- parseSessionMetadata skips [x] checked items in In Progress section
  (regex only matches unchecked [ ] checkboxes)

Total tests: 866
2026-02-13 16:02:18 -08:00
Affaan Mustafa 4d016babbb test: round 101 — output() circular crash, getSessionStats type confusion, appendSessionContent null
- output() throws TypeError on circular reference object (JSON.stringify has no try/catch)
- getSessionStats(123) throws TypeError (number reaches parseSessionMetadata, .match() fails)
- appendSessionContent(null) returns false (TypeError caught by try/catch)

Total tests: 863
2026-02-13 15:54:02 -08:00
Affaan Mustafa d2c1281e97 test: round 100 — findFiles maxAge+recursive interaction, parseSessionMetadata ### truncation, cleanupAliases falsy coercion
- findFiles with both maxAge AND recursive combined (option interaction test)
- parseSessionMetadata truncates item text at embedded ### due to lazy regex
- cleanupAliases callback returning 0 (falsy non-boolean) removes alias via !0 coercion

Total tests: 860
2026-02-13 15:49:06 -08:00
Affaan Mustafa 78ad952433 test: add 3 tests for no-match rewrite, CR-only grepFile, and null write (R99)
- replaceInFile returns true even when pattern doesn't match (silent rewrite)
- grepFile treats CR-only (\r) file as single line (splits on \n only)
- writeSessionContent(null) returns false (TypeError caught by try/catch)
2026-02-13 15:41:15 -08:00
Affaan Mustafa 274cca025e test: add 3 tests for null-input crashes and negative maxAge boundary (R98)
- getSessionById(null) throws TypeError at line 297 (null.length)
- parseSessionFilename(null) throws TypeError at line 30 (null.match())
- findFiles with maxAge: -1 deterministically excludes all files
2026-02-13 15:35:18 -08:00
Affaan Mustafa 18fcb88168 test: add 3 tests for whitespace ID, lastIndex reuse, and whitespace search (Round 97) 2026-02-13 15:28:06 -08:00
Affaan Mustafa 8604583d16 test: add 3 tests for session-manager edge cases (Round 96)
- parseSessionFilename rejects Feb 30 (Date rollover check)
- getAllSessions with limit: Infinity bypasses pagination
- getAllSessions with limit: null demonstrates destructuring default bypass (null !== undefined)

Total: 848 tests, all passing
2026-02-13 15:13:55 -08:00
Affaan Mustafa 233b341557 test: add 3 tests for alternation regex, double-negative clamping, and self-rename (Round 95) 2026-02-13 14:50:49 -08:00
Affaan Mustafa a95fb54ee4 test: add 3 tests for scoped pkg detection, empty env var, and tools-without-files (Round 94)
- detectFromPackageJson with scoped package name (@scope/pkg@version)
  returns null because split('@')[0] yields empty string
- getPackageManager skips empty string CLAUDE_PACKAGE_MANAGER via
  falsy short-circuit (distinct from unknown PM name test)
- session-end buildSummarySection includes Tools Used but omits
  Files Modified when transcript has only Read/Grep tools

Total tests: 842
2026-02-13 14:44:40 -08:00
Affaan Mustafa 910ffa5530 test: add 3 tests for regex boundary and flag logic gaps (round 93)
- getSessionStats: drive letter without slash (Z:nosession.tmp) treated as content
- countInFile: case-insensitive regex with g flag auto-appended (/foo/i → /foo/ig)
- countInFile: case-insensitive regex with g flag preserved (/foo/gi stays /foo/gi)
2026-02-13 14:21:03 -08:00
Affaan Mustafa b9a38b2680 test: add Round 92 tests for object pattern, UNC path, and empty packageManager
- Test countInFile returns 0 for object pattern type (non-string non-RegExp)
- Test getSessionStats treats Windows UNC path as content (not file path)
- Test detectFromPackageJson returns null for empty string packageManager field

Total tests: 836
2026-02-13 14:05:24 -08:00
Affaan Mustafa 14dfe4d110 test: add Round 91 tests for empty action pattern, whitespace PM, and mixed separators
- Test getCommandPattern('') produces valid regex for empty action string
- Test detectFromPackageJson returns null for whitespace-only packageManager
- Test getSessionStats treats mixed Windows path separators as file path

Total tests: 833
2026-02-13 14:02:41 -08:00
Affaan Mustafa 3e98be3e39 test: add Round 90 tests for readStdinJson timeout and saveAliases double failure
- Test readStdinJson timeout path when stdin never closes (resolves with {})
- Test readStdinJson timeout path with partial invalid JSON (catch resolves with {})
- Test saveAliases backup restore double failure (inner restoreErr catch at line 135)

Total tests: 830
2026-02-13 13:59:03 -08:00
Affaan Mustafa 3ec59c48bc test: add 3 tests for subdirectory skip, TypeScript error detection, and entry.name fallback (Round 89)
- getAllSessions skips subdirectories in sessions dir (!entry.isFile() branch)
- post-edit-typecheck.js error detection path when tsc reports errors (relevantLines > 0)
- extractSessionSummary extracts tools via entry.name + entry.input fallback format
2026-02-13 13:39:16 -08:00
Affaan Mustafa e70d4d2237 test: add 3 tests for replaceInFile deletion, parseSessionMetadata null fields, countInFile zero matches (Round 88)
- replaceInFile with empty replacement string verifies text deletion works
- parseSessionMetadata asserts date/started/lastUpdated are null when fields absent
- countInFile with valid file but non-matching pattern returns 0

Total: 824 tests
2026-02-13 12:49:53 -08:00
Affaan Mustafa 9b286ab3f8 test: add 3 tests for stdin 1MB overflow and analyzePhase async method (round 87)
- post-edit-format.js: verify MAX_STDIN truncation at 1MB limit
- post-edit-typecheck.js: verify MAX_STDIN truncation at 1MB limit
- skill-create-output.js: test analyzePhase() returns Promise and writes output
2026-02-13 12:42:20 -08:00
Affaan Mustafa b3e362105d test: add 3 tests for typeof guard, empty package.json, and learned_skills_path override (round 86)
- loadAliases resets to defaults when aliases field is a truthy non-object (string)
- detectFromPackageJson returns null for empty (0-byte) package.json
- evaluate-session uses learned_skills_path config override with ~ expansion
2026-02-13 12:23:34 -08:00
Affaan Mustafa 8cacf0f6a6 fix: use nullish coalescing for confidence default + add 3 tests (round 85)
Fix confidence=0 showing 80% instead of 0% in patterns() (|| → ??).
Test evaluate-session.js config parse error catch, getSessionIdShort
fallback at root CWD, and precise confidence=0 assertion.
2026-02-13 12:11:26 -08:00
Affaan Mustafa cedcf9a701 test: add 3 tests for TOCTOU catch paths and NaN date sort fallback (round 84)
- getSessionById returns null for broken symlink (session-manager.js:307-310)
- findFiles skips broken symlinks matching the pattern (utils.js:170-173)
- listAliases sorts entries with invalid/missing dates via getTime() || 0 fallback
2026-02-13 11:35:22 -08:00
Affaan Mustafa 15717d6d04 test: cover whitespace-only frontmatter field, empty SKILL.md, and getAllSessions TOCTOU symlink 2026-02-13 11:20:44 -08:00
Affaan Mustafa c8b7d41e42 test: cover tool_name OR fallback, Notification/SubagentStop events, and template regex no-match 2026-02-13 11:12:03 -08:00
Affaan Mustafa 9bec3d7625 test: cover suggest-compact upper bound, getSessionStats null input, and non-string content branch 2026-02-13 11:02:46 -08:00
Affaan Mustafa 2573cbb7b0 test: cover session-end message.role path, getExecCommand non-string args, and legacy hooks format
Round 80: Three previously untested conditional branches:
- session-end.js: entry.message?.role === 'user' third OR condition
  (fires when type is not 'user' but message.role is)
- package-manager.js: getExecCommand with truthy non-string args
  (typeof check short-circuits, value still appended via ternary)
- validate-hooks.js: legacy array format parsing path (lines 115-135)
  with 'Hook N' error labels instead of 'EventType[N]'
2026-02-13 10:39:35 -08:00
Affaan Mustafa 9dccdb9068 test: cover countInFile/grepFile string patterns and validate-commands warnings suffix
Round 79 — untested conditional branches in utils.js and validate-commands.js:
- countInFile: exercise typeof pattern === 'string' branch with valid string
- grepFile: exercise string pattern branch (not RegExp)
- validate-commands: verify (N warnings) suffix in output when warnCount > 0
2026-02-13 10:26:58 -08:00
Affaan Mustafa f000d9b02d test: cover getSessionStats file-path read, hasContent field, and wrapped hooks format
Round 78 — shifted from catch blocks to untested conditional branches:
- getSessionStats: exercise looksLikePath → getSessionContent path (real .tmp file)
- getAllSessions: verify hasContent true/false for non-empty vs empty files
- validate-hooks: test wrapped { hooks: { PreToolUse: [...] } } production format
2026-02-13 10:21:06 -08:00
Affaan Mustafa 27ae5ea299 test: cover evaluate-session/suggest-compact main().catch and validate-hooks JSON parse
- evaluate-session: main().catch when HOME is non-directory (ENOTDIR)
- suggest-compact: main().catch double-failure when TMPDIR is non-directory
- validate-hooks: invalid JSON in hooks.json triggers error exit

Total tests: 831 → 834
2026-02-13 10:03:48 -08:00
Affaan Mustafa 723e69a621 test: cover deleteSession catch, pre-compact and session-end main().catch
- session-manager: deleteSession returns false when dir is read-only (EACCES)
- pre-compact: main().catch handler when HOME is non-directory (ENOTDIR)
- session-end: main().catch handler when HOME is non-directory (ENOTDIR)

Total tests: 828 → 831
2026-02-13 09:59:48 -08:00
Affaan Mustafa 241c35a589 test: cover setGlobal/setProject catch blocks and session-start main().catch
- setup-package-manager: setGlobal catch when HOME is non-directory (ENOTDIR)
- setup-package-manager: setProject catch when CWD is read-only (EACCES)
- session-start: main().catch handler when ensureDir throws (exit 0, don't block)

Total tests: 825 → 828
2026-02-13 09:55:00 -08:00
Affaan Mustafa 0c67e0571e test: cover cleanupAliases save failure, setAlias save failure, and validate-commands statSync catch
Round 73: Add 3 tests for genuine untested code paths:
- session-aliases cleanupAliases returns failure when save blocked after removing aliases
- session-aliases setAlias returns failure when save blocked on new alias creation
- validate-commands silently skips broken symlinks in skill directory scanning
2026-02-13 09:42:25 -08:00
Affaan Mustafa 02d5986049 test: cover setProjectPM save failure, deleteAlias save failure, hooks async/timeout validation
Round 72: Add 4 tests for untested code paths (818 → 822):
- package-manager.js: setProjectPackageManager wraps writeFile errors (lines 275-279)
- session-aliases.js: deleteAlias returns failure when saveAliases fails (line 299)
- validate-hooks.js: rejects non-boolean async field (line 28-31)
- validate-hooks.js: rejects negative timeout value (lines 32-35)
2026-02-13 08:12:27 -08:00
Affaan Mustafa f623e3b429 test: cover findFiles unreadable subdir, session-start default PM, setPreferredPM save failure
Round 71: Add 3 tests for untested code paths (815 → 818):
- utils.js findFiles: recursive scan silently skips unreadable subdirectories (line 188 catch)
- session-start.js: shows getSelectionPrompt when pm.source is 'default' (lines 69-72)
- package-manager.js: setPreferredPackageManager wraps saveConfig errors (lines 250-254)
2026-02-13 08:01:15 -08:00
Affaan Mustafa 44b5a4f9f0 test: add 3 tests for untested fallback/skip/failure paths (Round 70)
- session-end.js: entry.name/entry.input fallback in direct tool_use entries
- validate-commands.js: "would create:" regex alternation skip line
- session-aliases.js: updateAliasTitle save failure with read-only dir
2026-02-13 07:48:39 -08:00
Affaan Mustafa 567664091d test: add 3 tests for untested code paths (Round 69, 812 total)
- getGitModifiedFiles: all-invalid patterns skip filtering (compiled.length === 0)
- getSessionById: returns null when sessions directory doesn't exist
- getPackageManager: global-config success path returns source 'global-config'
2026-02-13 07:35:20 -08:00
Affaan Mustafa 5031a84d6e test: add 3 tests for setup-pm --project success, demo export, --list marker (Round 68) 2026-02-13 07:23:16 -08:00
Affaan Mustafa 702c3f54b4 test: add 3 tests for session-aliases empty file, null resolve, metadata backfill (Round 67) 2026-02-13 07:18:28 -08:00
Affaan Mustafa 162222a46c test: add 3 tests for session-manager noIdMatch, session-end fallbacks (Round 66)
- session-manager.js: getSessionById with date-only string exercises the
  noIdMatch path for old-format sessions (2026-02-10 → 2026-02-10-session.tmp)
- session-end.js: extract user messages from role-only JSONL format
  ({"role":"user",...} without type field) exercises line 48 fallback
- session-end.js: nonexistent transcript_path triggers "Transcript not found"
  log path (lines 153-155), creates session with blank template

Total: 803 tests, all passing
2026-02-13 07:10:54 -08:00
Affaan Mustafa 485def8582 test: add 3 tests for evaluate-session regex, empty rules/skills dirs (Round 65)
- evaluate-session.js: verify regex whitespace tolerance around colon
  matches "type" : "user" (with spaces), not just compact JSON
- validate-rules.js: empty directory with no .md files yields Validated 0
- validate-skills.js: directory with only files, no subdirectories yields
  Validated 0

Total: 800 tests, all passing
2026-02-13 07:04:55 -08:00
Affaan Mustafa cba6b44c61 test: add 3 tests for suggest-compact, session-aliases, typecheck (Round 64)
- suggest-compact: 'default' session ID fallback when CLAUDE_SESSION_ID empty
- session-aliases: loadAliases backfills missing version and metadata fields
- post-edit-typecheck: valid JSON without tool_input passes through unchanged

Total: 797 tests, all passing
2026-02-13 06:59:08 -08:00
Affaan Mustafa 1fcdf12b62 test: add 3 CI validator tests for untested code paths (Round 63)
- validate-hooks: object-format matcher missing matcher field (line 97-100)
- validate-commands: readFileSync catch block for unreadable .md files (lines 56-62)
- validate-commands: empty commands directory with no .md files (Validated 0)

Total: 794 tests, all passing
2026-02-13 06:55:30 -08:00
Affaan Mustafa 85a86f6747 test: add --global success, bare PM name, and source label tests (Round 62)
- setup-package-manager.test.js: --global npm writes config and exits 0
- setup-package-manager.test.js: bare PM name sets global preference
- setup-package-manager.test.js: --detect with env var shows source 'environment'

791 tests total, all passing.
2026-02-13 06:49:29 -08:00
Affaan Mustafa 3ec0aa7b50 test: add replaceInFile write failure, empty sessions dir, and corrupted global config tests (Round 61)
- utils.test.js: replaceInFile returns false on read-only file (catch block)
- session-manager.test.js: getAllSessions returns empty when sessions dir missing
- package-manager.test.js: getPackageManager falls through corrupted global config to npm default

788 tests total, all passing.
2026-02-13 06:44:52 -08:00
Affaan Mustafa 9afecedb21 test: add replaceInFile failure, console-warn overflow, and missing tool_input tests (Round 60) 2026-02-13 06:25:35 -08:00
Affaan Mustafa 7db0d316f5 test: add unreadable session file, stdin overflow, and read-only compact tests (Round 59) 2026-02-13 06:19:02 -08:00
Affaan Mustafa 99fc51dda7 test: add unreadable agent file, colonIdx edge case, and command-as-object tests (Round 58) 2026-02-13 06:14:06 -08:00
Affaan Mustafa 2fea46edc7 test: add SKILL.md-as-directory, broken symlink, and adjacent code block tests (Round 57) 2026-02-13 06:02:56 -08:00
Affaan Mustafa 990c08159c test: add tsconfig walk-up, compact fallback, and Windows atomic write tests (Round 56) 2026-02-13 05:59:07 -08:00
Affaan Mustafa 43808ccf78 test: add maxAge boundary, multi-session injection, and stdin overflow tests (Round 55)
- session-start.js excludes sessions older than 7 days (6.9d vs 8d boundary)
- session-start.js injects newest session when multiple recent sessions exist
- session-end.js handles stdin exceeding 1MB MAX_STDIN limit via env var fallback
2026-02-13 05:48:34 -08:00
Affaan Mustafa 3bc0929c6e test: add search scope, path utility, and zero-value analysis tests (Round 54)
- getAllSessions search matches only shortId, not title/content
- getSessionPath returns absolute path with correct directory structure
- analysisResults handles zero values for all data fields without crash
2026-02-13 05:43:29 -08:00
Affaan Mustafa ad40bf3aad test: add env var fallback, console.log max matches, and format non-existent file tests
Round 53: Adds 3 hook tests — validates evaluate-session.js
falls back to CLAUDE_TRANSCRIPT_PATH env var when stdin JSON
is invalid, post-edit-console-warn.js truncates output to max
5 matches, and post-edit-format.js passes through data when
the target .tsx file doesn't exist.
2026-02-13 05:34:59 -08:00
Affaan Mustafa f1a693f7cf test: add inline backtick ref, workflow whitespace, and code-only rule tests
Round 52: Adds 3 CI validator tests — validates command refs
inside inline backticks are checked (not stripped like fenced
blocks), workflow arrows with irregular whitespace pass, and
rule files containing only fenced code blocks are accepted.
2026-02-13 05:29:04 -08:00
Affaan Mustafa 4e520c6873 test: add timeout enforcement, async hook schema, and command format validation tests
Round 51: Adds 3 integration tests for hook infrastructure —
validates hanging hook timeout/kill mechanism, hooks.json async
hook configuration schema, and all hook command format consistency.
2026-02-13 05:23:16 -08:00
Affaan Mustafa 86844a305a test: add alias reporting, parallel compaction, and graceful degradation tests 2026-02-13 05:13:56 -08:00
Affaan Mustafa b950fd7427 test: add typecheck extension edge cases and conditional summary section tests 2026-02-13 05:10:07 -08:00
Affaan Mustafa 71e86cc93f test: add packageManager version format and sequential save integrity tests 2026-02-13 05:04:58 -08:00
Affaan Mustafa 4f7b50fb78 test: add inline JS escape validation and frontmatter colon-less line tests 2026-02-13 05:01:28 -08:00
Affaan Mustafa 277006bd7f test: add Windows path heuristic and checkbox case sensitivity tests
Round 46: verify getSessionStats recognises C:/ and D:\ as file
paths but not bare C: without slash; verify parseSessionMetadata
only matches lowercase [x] checkboxes (not uppercase [X]).
2026-02-13 04:51:39 -08:00
Affaan Mustafa f6ebc2a3c2 test: add setup-package-manager marker uniqueness and list completeness tests
Round 45: verify --detect shows exactly one (current) marker and
--list includes all four PMs with Lock file + Install entries.
2026-02-13 04:47:30 -08:00
Affaan Mustafa 443986e086 test: verify session-start.js handles empty (0-byte) session file gracefully 2026-02-13 04:43:59 -08:00
Affaan Mustafa c92d3f908f test: verify getSessionById excludes content/metadata/stats when includeContent is false 2026-02-13 04:39:25 -08:00
Affaan Mustafa b868f42ad1 test: add validator edge-case tests for case sensitivity, frontmatter spacing, missing dirs, and empty matchers 2026-02-13 04:35:02 -08:00
Affaan Mustafa 842ff2eff6 test: verify pre-compact annotates only newest session file when multiple exist 2026-02-13 04:31:05 -08:00
Affaan Mustafa b678c2f1b0 fix: collapse newlines in user messages to prevent markdown list breaks in session-end
User messages containing newline characters were being added as-is to
markdown list items in buildSummarySection(), breaking the list format.
Now newlines are replaced with spaces before backtick escaping.
2026-02-13 04:28:50 -08:00
Affaan Mustafa dc11fc2fd8 fix: make saveAliases atomic on Unix by skipping unnecessary unlink before rename
On Unix/macOS, rename(2) atomically replaces the destination file.
The previous code ran unlinkSync before renameSync on all platforms,
creating an unnecessary non-atomic window where a crash could lose
data. Now the delete-before-rename is gated behind process.platform
=== 'win32', where rename cannot overwrite an existing file.
2026-02-13 04:23:22 -08:00
Affaan Mustafa 0daa5cb070 test: add evaluate-session tilde expansion and missing config tests (Round 38) 2026-02-13 04:19:13 -08:00
Affaan Mustafa e2040b46b3 fix: remove unreachable return after process.exit in post-edit-typecheck hook 2026-02-13 04:15:13 -08:00
Affaan Mustafa c93c218cb8 fix: sync Cursor suggest-compact.js with corrected hooks version
The .cursor copy had diverged from scripts/hooks/suggest-compact.js:
- Fixed interval calculation: count % 25 → (count - threshold) % 25
  so suggestions fire relative to the configured threshold
- Added upper bound clamp (<=1000000) to prevent counter corruption
  from large values converting to scientific notation strings
- Removed unreliable String(process.ppid) fallback for session ID
2026-02-13 04:09:31 -08:00
Affaan Mustafa b497135b95 fix: correct box() off-by-one width calculation in skill-create-output
The box() helper produced lines that were width+1 characters instead of
the requested width. Adjusted all three formulas (top border, middle
content, bottom border) by -1 each. Added 4 tests verifying box width
accuracy across instincts(), analysisResults(), and nextSteps() output.
2026-02-13 04:05:12 -08:00
Affaan Mustafa 554b5d6704 fix: header subtitle width mismatch in skill-create-output; add 9 tests (Round 34)
- Fix subtitle padding 55→59 so line 94 matches 64-char border width
- Add 4 header width alignment tests (skill-create-output)
- Add 3 getExecCommand non-string args tests (package-manager)
- Add 2 detectFromPackageJson non-string type tests (package-manager)
2026-02-13 03:58:16 -08:00
Affaan Mustafa bb9df39d96 test: add 10 tests for birthtime fallback, stdin error, alias rollback (Round 33)
Cover createdTime/birthtime fallback in session-manager, readStdinJson
error event settled-flag guard in utils, renameAlias rollback on naming
conflict in session-aliases, and saveAliases backup preservation on
serialization failure. Total: 713 tests.
2026-02-13 03:50:44 -08:00
Affaan Mustafa 72de0a4e2c test: add 17 tests for validators, hooks, and edge cases (Round 32)
Coverage improvements:
- validate-agents: empty frontmatter block, no-content frontmatter,
  partial frontmatter, mixed valid/invalid agents
- validate-rules: directory with .md name (stat.isFile check),
  deeply nested subdirectory rules
- validate-commands: 3-agent workflow chain, broken middle agent
- post-edit-typecheck: spaces in paths, shell metacharacters, .tsx
- check-console-log: git failure passthrough, large stdin
- post-edit-console-warn: console.error only, null tool_input
- session-end: empty transcript, whitespace-only transcript

Total tests: 686 → 703
2026-02-13 03:44:10 -08:00
Affaan Mustafa 167b105cac fix: reject flags passed as package manager names in setup-package-manager CLI
When --global or --project was followed by another flag (e.g., --global --project),
the flag was treated as a package manager name. Added pmName.startsWith('-') check
to both handlers. Added 20 tests across 4 test files covering argument validation,
ensureDir error propagation, runCommand stderr handling, and saveAliases failure paths.
2026-02-13 03:37:46 -08:00
Affaan Mustafa b1eb99d961 fix: use local-time Date constructor in session-manager to prevent timezone day shift
new Date('YYYY-MM-DD') creates UTC midnight, which in negative UTC offset
timezones (e.g., Hawaii) causes getDate() to return the previous day.
Replaced with new Date(year, month - 1, day) for correct local-time behavior.

Added 15 tests: session-manager datetime verification and edge cases (7),
package-manager getCommandPattern special characters (4), and
validators model/skill-reference validation (4). Tests: 651 → 666.
2026-02-13 03:29:04 -08:00
Affaan Mustafa 992688a674 fix: add cwd to prettier hook, consistent process.exit(0), and stdout pass-through
- post-edit-format.js: add cwd based on file directory so npx resolves
  correct local prettier binary
- post-edit-typecheck.js, post-edit-format.js: replace console.log(data)
  with process.stdout.write(data) to avoid trailing newline corruption
- Add process.exit(0) to 4 hooks for consistent termination
  (check-console-log, post-edit-console-warn, post-edit-format,
  post-edit-typecheck)
- run-all.js: switch from execSync to spawnSync so stderr is visible
  on the success path (hook warnings were silently discarded)
- Add 21 tests: cwd verification, process.exit(0) checks, exact
  stdout pass-through, extension edge cases, exclusion pattern
  matching, threshold boundary values (630 → 651)
2026-02-13 03:20:41 -08:00
Affaan Mustafa 253645b5e4 test: add 22 tests for readStdinJson, evaluate-session config, and suggest-compact hook
- utils.test.js: 5 tests for readStdinJson maxSize truncation, whitespace-only stdin, trailing whitespace, and BOM prefix handling
- evaluate-session.test.js: 4 tests for config file parsing, assistant-only transcripts, malformed JSON lines, and empty stdin
- suggest-compact.test.js: 13 new tests covering counter file creation/increment, threshold suggestion, interval suggestion, env var handling, corrupted/empty counter files, and session isolation
2026-02-13 03:11:51 -08:00