* fix: filter session-start injection by cwd/project to prevent cross-project contamination
The SessionStart hook previously selected the most recent session file
purely by timestamp, ignoring the current working directory. This caused
Claude to receive a previous project's session context when switching
between projects, leading to incorrect file reads and project analysis.
session-end.js already writes **Project:** and **Worktree:** header
fields into each session file. This commit adds selectMatchingSession()
which uses those fields with the following priority:
1. Exact worktree (cwd) match — most recent
2. Same project name match — most recent
3. Fallback to overall most recent (preserves backward compatibility)
No new dependencies. Gracefully falls back to original behavior when
no matching session exists.
* fix: address review feedback — eliminate duplicate I/O, add null guards, improve docstrings
- Return { session, content, matchReason } from selectMatchingSession()
to avoid reading the same file twice (coderabbitai, greptile P2)
- Add empty array guard: return null when sessions.length === 0 (coderabbitai)
- Stop mutating input objects — no more session._matchReason (coderabbitai)
- Add null check on result before accessing properties (coderabbitai)
- Only log "selected" after confirming content is readable (cubic-dev-ai P3)
- Add full JSDoc with @param/@returns (docstring coverage)
* fix: track fallback session object to prevent session/content mismatch
When sessions[0] is unreadable, fallbackContent came from a later
session (e.g. sessions[1]) while the returned session object still
pointed to sessions[0]. This caused misleading logs and injected
content from the wrong session — the exact problem this PR fixes.
Now tracks fallbackSession alongside fallbackContent so the returned
pair is always consistent.
Addresses greptile-apps P1 review feedback.
* fix: normalize worktree paths to handle symlinks and case differences
On macOS /var is a symlink to /private/var, and on Windows paths may
differ in casing (C:\repo vs c:\repo). Use fs.realpathSync() to
resolve both sides before comparison so worktree matching is reliable
across symlinked and case-insensitive filesystems.
cwd is normalized once outside the loop to avoid repeated syscalls.
Addresses coderabbitai Major review feedback.
---------
Co-authored-by: kuqili <kuqili@tencent.com>
Inline `node -e "..."` in hooks.json contained `!` characters (e.g.
`!org.isDirectory()`) that bash history expansion in certain shell
environments would misinterpret, producing syntax errors and the
"SessionStart:startup hook error" banner in the Claude Code CLI header.
Extract the bootstrap logic to `scripts/hooks/session-start-bootstrap.js`
so the shell never sees the JS source. Behaviour is identical: the script
reads stdin, resolves the ECC plugin root via CLAUDE_PLUGIN_ROOT or a set
of well-known fallback paths, then delegates to run-with-flags.js.
Update the test that asserted the old inline pattern to verify the new
file-based approach instead.
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
The shell wrapper run-with-flags-shell.sh was not extracting the phase
prefix from the hook ID (e.g., "pre:observe" -> "pre") and passing it
as $1 to the invoked script. This caused observe.sh to always default
to "post", recording all observations as tool_complete events with no
tool_start events captured.
Fixes#1018
Co-authored-by: Millectable <noreply@github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(ci): resolve cross-platform test failures
- Sanity check script (check-codex-global-state.sh) now falls back to
grep -E when ripgrep is not available, fixing the codex-hooks sync
test on all CI platforms. Patterns converted to POSIX ERE for
portability.
- Unicode safety test accepts both / and \ path separators so the
executable-file assertion passes on Windows.
- Gacha test sets PYTHONUTF8=1 so Python uses UTF-8 stdout encoding on
Windows instead of cp1252, preventing UnicodeEncodeError on box-drawing
characters.
- Quoted-hook-path test skipped on Windows where NTFS disallows
double-quote characters in filenames.
* feat: port remotion-video-creation skill (29 rules), restore missing files
New skill:
- remotion-video-creation: 29 domain-specific Remotion rules covering 3D/Three.js,
animations, audio, captions, charts, compositions, fonts, GIFs, Lottie,
measuring, sequencing, tailwind, text animations, timing, transitions,
trimming, and video embedding. Ported from personal skills.
Restored:
- autonomous-agent-harness/SKILL.md (was in commit but missing from worktree)
- lead-intelligence/ (full directory restored from branch commit)
Updated:
- manifests/install-modules.json: added remotion-video-creation to media-generation
- README.md + AGENTS.md: synced counts to 139 skills
Catalog validates: 30 agents, 60 commands, 139 skills.
* fix(security): pin MCP server versions, add dependabot, pin github-script SHA
Critical:
- Pin all npx -y MCP server packages to specific versions in .mcp.json
to prevent supply chain attacks via version hijacking:
- @modelcontextprotocol/server-github@2025.4.8
- @modelcontextprotocol/server-memory@2026.1.26
- @modelcontextprotocol/server-sequential-thinking@2025.12.18
- @playwright/mcp@0.0.69 (was 0.0.68)
Medium:
- Add .github/dependabot.yml for weekly npm + github-actions updates
with grouped minor/patch PRs
- Pin actions/github-script to SHA (was @v7 tag, now pinned to commit)
* feat: add social-graph-ranker skill — weighted network proximity scoring
New skill: social-graph-ranker
- Weighted social graph traversal with exponential decay across hops
- Bridge Score: B(m) = Σ w(t) · λ^(d(m,t)-1) ranks mutuals by target proximity
- Extended Score incorporates 2nd-order network (mutual-of-mutual connections)
- Final ranking includes engagement bonus for responsive connections
- Runs in parallel with lead-intelligence skill for combined warm+cold outreach
- Supports X API + LinkedIn CSV for graph harvesting
- Outputs tiered action list: warm intros, direct outreach, network gap analysis
Added to business-content install module. Catalog validates: 30/60/140.
* fix(security): npm audit fix — resolve all dependency vulnerabilities
Applied npm audit fix --force to resolve:
- minimatch ReDoS (3 vulnerabilities, HIGH)
- smol-toml DoS (MODERATE)
- brace-expansion memory exhaustion (MODERATE)
- markdownlint-cli upgraded from 0.47.0 to 0.48.0
npm audit now reports 0 vulnerabilities.
* fix: resolve markdown lint and yarn lockfile sync
- MD047: ensure single trailing newline on all remotion rule files
- MD012: remove consecutive blank lines in lottie, measuring-dom-nodes, trimming
- MD034: wrap bare URLs in angle brackets (tailwind, transcribe-captions)
- yarn.lock: regenerated to sync with npm audit changes in package.json
* fix: replace unicode arrows in lead-intelligence (CI unicode safety check)
* fix(hooks): add WSL desktop notification support via PowerShell + BurntToast
Adds WSL (Windows Subsystem for Linux) desktop notification support to the
existing desktop-notify hook. The hook now detects WSL, finds available
PowerShell (7 or Windows PowerShell), checks for BurntToast module, and
sends Windows toast notifications.
New functions:
- isWSL(): detects WSL environment
- findPowerShell(): finds PowerShell 7 or Windows PowerShell on WSL
- isBurntToastAvailable(): checks if BurntToast module is installed
- notifyWindows(): sends Windows toast notification via BurntToast
If BurntToast is not installed, logs helpful tip for installation.
Falls back silently on non-WSL/non-macOS platforms.
* docs(hooks): update desktop-notify description to include WSL
Updates the hook description in hooks.json to reflect the newly
added WSL notification support alongside macOS.
* fix(hooks): capture stderr properly in notifyWindows
Change stdio to ['ignore', 'pipe', 'pipe'] so stderr is captured
and can be logged on errors. Without this, result.stderr is null
and error logs show 'undefined' instead of the actual error.
* fix(hooks): quote PowerShell path in install tip for shell safety
The PowerShell path contains spaces and needs to be quoted
when displayed as a copy-pasteable command.
* fix(hooks): remove external repo URL from tip message
BurntToast module is a well-known Microsoft module but per project
policy avoiding unvetted external links in user-facing output.
* fix(hooks): probe WSL interop PATH before hardcoded paths
Adds 'pwsh.exe' and 'powershell.exe' as candidates to leverage
WSL's Windows interop PATH resolution, making the hook work with
non-default WSL mount prefixes or Windows drives.
* perf(hooks): memoize isWSL detection at module load
Avoids reading /proc/version twice (once in run(), once in findPowerShell())
by computing the result once when the module loads.
* perf(hooks): reduce PowerShell spawns from 3 to 1 per notification
Merge findPowerShell version check and isBurntToastAvailable check
into a single notifyWindows call. Now just tries to send directly;
if it fails, tries next PowerShell path. Version field was unused.
Net effect: up to 3 spawns reduced to 1 in the happy path.
* fix(hooks): remove duplicate notifyWindows declaration
There were two notifyWindows function declarations due to incomplete
refactoring. Keeps only the version that returns true/false for the
call site. Node.js would throw SyntaxError with 'use strict'.
* fix(hooks): improve error handling and detection robustness
- Increase PowerShell detection timeout from 1s to 3s to avoid false
negatives on slower/cold WSL interop startup
- Return error reason from notifyWindows to distinguish BurntToast
module not found vs other PowerShell errors
- Log actionable error details instead of always showing install tip
---------
Co-authored-by: boss <boss@example.com>
The pre-push hook runs lint/typecheck/test/build checks on every push,
including `git push origin --delete <branch>`. Branch deletion does not
push any code, so verification checks are unnecessary and block the
delete operation.
Detect deletion pushes by reading stdin (local sha is all zeros for
deletes) and exit early.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add options={} parameter to run() to match run-with-flags.js contract
- Remove case-insensitive flag from extension pre-filter for consistency
with ADHOC_FILENAMES regex (both now case-sensitive)
- Expand warning text to list more structured paths
- Add test cases for uppercase extensions (TODO.MD, NOTES.TXT)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
Replace the broad allowlist approach with a targeted denylist that only
warns on known ad-hoc filenames (NOTES, TODO, SCRATCH, TEMP, DRAFT,
BRAINSTORM, SPIKE, DEBUG, WIP) outside structured directories. This
eliminates false positives for legitimate markdown-heavy workflows while
still catching impulse documentation files.
Closes#988
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
Extracted help text into getHelpText() and write both the error message
and usage help to stderr via process.stderr.write(). This ensures that
when output is redirected (e.g. 2>errors.txt), both the error and the
guidance appear in the same stream.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Running install.ps1/install.sh with no arguments gave a cryptic error
with no guidance. Now the usage help is printed after the error so users
know what arguments to pass.
Also added --profile full as the recommended install option in the README
quick-start section, which was previously undocumented.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add @latest suffix to '@upstash/context7-mcp' in ECC_SERVERS so the
generated merge spec matches .codex/config.toml exactly, preventing
configDiffers from flagging false drift on --update-mcp runs.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
The rg pattern anchored at line start (^persistent_instructions) would
miss indented TOML entries. Use ^\s* prefix to match both top-level and
indented configurations.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
On Windows (native cmd/PowerShell), process.env.HOME is undefined.
Seven CLI entry points and two library files pass process.env.HOME
directly as homeDir without a cross-platform fallback, causing all
path resolutions to silently fail (resolving to "undefined/.claude/...").
Node.js os.homedir() correctly handles all platforms (HOME on Unix,
USERPROFILE on Windows, OS-level fallback). The project already uses
this pattern in scripts/lib/state-store/index.js and has a getHomeDir()
utility in scripts/lib/utils.js, but it was not applied consistently.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
The global sanity check (check-codex-global-state.sh) hard-fails when
persistent_instructions is missing from ~/.codex/config.toml, but neither
the baseline .codex/config.toml nor the sync script ever define this field.
This causes a clean install to report a failing sanity check even though the
sync otherwise succeeds (#967).
- Add persistent_instructions to the baseline .codex/config.toml so that
users who cp the config get a working default.
- Downgrade the sanity check from fail to warn, since persistent_instructions
is additive and optional — users who rely solely on AGENTS.md should not be
blocked.
Fixes#967 (persistent_instructions part; context7 naming addressed by #970)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
Reviewers identified that merge-mcp-config.js --update-mcp would
silently strip the startup_timeout_sec from config.toml because the
ECC_SERVERS spec did not include it. Add startup_timeout_sec = 30 to
playwright, context7-mcp, github, memory, and sequential-thinking.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: Lidang-Jiang <lidangjiang@gmail.com>
Codex CLI reads skills natively from ~/.agents/skills/ (installed by
ECC installer / npx skills). The sync script was redundantly copying
the same skills from .agents/skills/ to ~/.codex/skills/.
Changes:
- Remove skill copy loop, variables, and path validation from sync script
- Update sanity checker to validate ~/.agents/skills/ instead of
~/.codex/skills/, downgrade missing skills from FAIL to WARN
- Update test assertions to verify skill sync removal
Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)
Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
- Check spawnSync result and log warning on failure via stderr
- Restore osascript timeout to 5000ms, increase hook deadline to 10s
for sufficient headroom
- Replace JSON.stringify with curly quote substitution for AppleScript
compatibility (AppleScript does not support \" backslash escapes)
- Reduce spawnSync timeout from 5000ms to 3000ms to leave headroom
within the 5s hook deadline
Add a new Stop hook that sends a native macOS notification with the
task summary (first line of last_assistant_message) when Claude finishes
responding. Uses osascript via spawnSync for shell injection safety.
Supports run-with-flags fast require() path. Only active on standard
and strict profiles; silently skips on non-macOS platforms.