* feat: add agent description compression with lazy loading (#491)
Agent descriptions consume ~26k tokens (121KB across 27 agents). This adds
a compression library with three modes:
- catalog: metadata only (~2-3k tokens) for agent selection
- summary: metadata + first paragraph (~4-5k tokens) for routing
- full: no compression, for when agent is invoked
Includes lazy-load function to fetch full agent body on demand.
21 tests covering parsing, compression, filtering, and real agents dir.
* fix: update JSDoc to include all stats fields in buildAgentCatalog
Add compressedBytes and mode to the documented return type, matching
the actual implementation.
When ECC is installed as a Claude Code plugin via the marketplace,
scripts live in the plugin cache (~/.claude/plugins/cache/...) but
commands fallback to ~/.claude/ which doesn't have the scripts.
Add resolve-ecc-root.js with a 3-step fallback chain:
1. CLAUDE_PLUGIN_ROOT env var (existing)
2. Standard install at ~/.claude/ (existing)
3. NEW: auto-scan the plugin cache directory
Update sessions.md and skill-health.md commands to use the new
inline resolver. Includes 15 tests covering all fallback paths
including env var priority, standard install, cache discovery,
and the compact INLINE_RESOLVE used in command .md files.
Windows terminals emit control sequences (cursor movement, screen
clearing) that leaked into session.tmp files and were injected
verbatim into Claude's context on the next session start.
Add a comprehensive stripAnsi() to utils.js that handles CSI, OSC,
charset selection, and bare ESC sequences. Apply it in session-end.js
(when extracting user messages from the transcript) and in
session-start.js (safety net before injecting session content).
- Add duplicate slug detection in buildOrchestrationPlan to reject
worker names that collapse to the same slug
- Use buildTemplateVariables() for launcher command interpolation
so _sh and _raw suffixes are available in templates
- session-end-marker.js now exports run() function
- Enables in-process execution via run-with-flags.js
- Avoids spawnSync cross-platform issues on Windows
- Maintains backward compatibility with direct CLI execution
Fixes#429
Co-authored-by: 阳虎 <yanghu@yanghudeMacBook-Pro.local>
* Add install.ps1 PowerShell wrapper and tests
Add a Windows-native PowerShell wrapper (install.ps1) that resolves symlinks and delegates to the Node-based installer runtime. Update README with PowerShell usage examples and cross-platform npx entrypoint guidance. Point the ecc-install bin to the Node installer (scripts/install-apply.js) in package.json (and refresh package-lock), include install.ps1 in package files, and add tests: a new install-ps1.test.js and a tweak to install-sh.test.js to skip on Windows. These changes provide native Windows installer support while keeping npm-compatible cross-platform invocation.
* Improve tests for Windows HOME/USERPROFILE
Make tests more cross-platform by ensuring HOME and USERPROFILE are kept in sync and by normalizing test file paths for display.
- tests/lib/session-adapters.test.js: set USERPROFILE when temporarily setting HOME and restore previous USERPROFILE on teardown.
- tests/run-all.js: use a normalized displayPath (forward-slash separated) for logging and error messages so output is consistent across platforms.
- tests/scripts/ecc.test.js & tests/scripts/session-inspect.test.js: build envOverrides from options.env and add HOME <-> USERPROFILE fallbacks so spawned child processes receive both variables when only one is provided.
These changes prevent test failures and inconsistent logs on Windows where USERPROFILE is used instead of HOME.
* Fix Windows paths and test flakiness
Improve cross-platform behavior and test stability.
- Remove unused createLegacyInstallPlan import from install-lifecycle.js.
- Change resolveInstallConfigPath to use path.normalize(path.join(cwd, configPath)) to produce normalized relative paths.
- Tests: add toBashPath and normalizedRelativePath helpers to normalize Windows paths for bash and comparisons.
- Make cleanupTestDir retry rmSync on transient Windows errors (EPERM/EBUSY/ENOTEMPTY) with short backoff using sleepMs.
- Ensure spawned test processes receive USERPROFILE and convert repo/detect paths to bash format when invoking bash.
These changes reduce Windows-specific failures and flakiness in the test suite and tidy up a small unused import.
- canonical-session: fall back to JSON file recording when the loaded
state-store module has no writer methods (factory vs instance)
- install-executor: skip node_modules and .git dirs in listFilesRecursive
to prevent ETIMEDOUT copying thousands of .opencode dependency files
- ecc.js: increase maxBuffer to 10MB for spawned subcommands to prevent
ENOBUFS on large install plan JSON output
- install-apply.test: update Cursor and Antigravity path assertions to
match flattened rule layout and remapped dirs (workflows, skills)
- ecc.test: increase maxBuffer in test runner to handle large output
- orchestrate-codex-worker.sh: guard against unreadable task file before
cat, write failure status and handoff artifacts on early exit
* feat: add SQLite state store and ECC status CLI
* fix: replace better-sqlite3 with sql.js to eliminate native module CI failures
better-sqlite3 requires native C++ compilation (node-gyp, prebuild-install)
which fails in CI across npm/pnpm on all platforms:
- npm ci: lock file out of sync with native transitive deps
- pnpm: native bindings not found at runtime
- Windows: native compilation fails entirely
sql.js is a pure JavaScript/WASM SQLite implementation with zero native
dependencies. The adapter in index.js wraps the sql.js API to match the
better-sqlite3 interface used by migrations.js and queries.js.
Key implementation detail: sql.js db.export() implicitly ends active
transactions, so the adapter defers disk writes (saveToDisk) until
after transaction commit via an inTransaction guard flag.
createStateStore is now async (sql.js requires async WASM init).
Updated status.js, sessions-cli.js, and tests accordingly.
- Registry accepts { type, value } structured targets
- Add --list-adapters and --target-type CLI flags to session-inspect
- Export adapter type from claude-history and dmux-tmux adapters
- 71 new session adapter tests, 34 new session-inspect tests
- All 1142 tests passing
Extract BIOME_CONFIGS and PRETTIER_CONFIGS as shared constants to eliminate
duplication between PROJECT_ROOT_MARKERS and detectFormatter(). Unify the
biome/prettier branches in resolveFormatterBin() via a FORMATTER_PACKAGES
map. Remove redundant path.resolve() in quality-gate.js.
Handle Windows .cmd shim resolution via spawnSync with strict path
validation. Removes shell:true injection risk, uses strict equality,
and restores .cmd support with path injection guard.
Invoke hook scripts directly via require() when they export a
run(rawInput) function, eliminating one Node.js process spawn per
hook invocation (~50-100ms).
Includes path traversal guard, timeouts, error logging, PR review
feedback, legacy hooks guard, normalized filePath, and restored
findProjectRoot config detection with package manager support.
- Add get_anomaly_attr() helper that handles both dict and object
anomalies. The SDK's send_message() returns dicts, so getattr()
was silently returning defaults -- critical blocking never triggered.
- Fix field name: "detail" -> "details" (matches SDK schema).
- Make fail-open/fail-closed configurable via INSAITS_FAIL_MODE env var
(defaults to "open" for backward compatibility).
- Include exception type name in fail-open log for diagnostics.
- Normalize severity comparison with .upper() for case-insensitive matching.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
cubic-dev-ai P2: dev_mode now defaults to "false" (strict mode).
Users opt in to dev mode by setting INSAITS_DEV_MODE=true.
cubic-dev-ai P2: Move null-status check above stdout/stderr writes
in wrapper so partial/corrupt output is never leaked. Pass through
original raw input on signal kill, matching the result.error path.
coderabbit major: Wrap insAItsMonitor() and send_message() in
try/except so SDK errors don't crash the hook. Logs warning and
exits 0 (fail-open) on exception.
coderabbit nitpick: write_audit now creates a new dict (enriched)
instead of mutating the caller's event dict.
coderabbit nitpick: Extract magic numbers to named constants:
MIN_CONTENT_LENGTH=10, MAX_SCAN_LENGTH=4000, DEFAULT_MODEL.
Also: added env var documentation to module docstring.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Defaults to true (no API key needed) but can be disabled by setting
INSAITS_DEV_MODE=false for production deployments with an API key.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
P1: Log non-ENOENT spawn errors (timeout, signal kill) to stderr
instead of silently exiting 0. Separate handling for result.error
and null result.status so users know when the security monitor
failed to run.
P1: Remove "async": true from hooks.json — async hooks run in the
background and cannot block tool execution. The security hook needs
to be synchronous so exit(2) actually prevents credential exposure
and other critical findings from proceeding.
P2: Remove dead tool_response/tool_result code from extract_content.
In a PreToolUse hook the tool hasn't executed yet, so tool_response
is never populated. Removed the variable and the unreachable branch
that appended its content.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>