compound-agent 1.4.2 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -6,7 +6,7 @@ import { createHash } from 'crypto';
6
6
  import * as fs from 'fs/promises';
7
7
  import { readFile, mkdir, appendFile, writeFile, chmod, rm, rename, readdir } from 'fs/promises';
8
8
  import { Command } from 'commander';
9
- import { getLlama, resolveModelFile } from 'node-llama-cpp';
9
+ import { getLlama, LlamaLogLevel, resolveModelFile } from 'node-llama-cpp';
10
10
  import { homedir, tmpdir } from 'os';
11
11
  import { z } from 'zod';
12
12
  import { execSync, execFileSync, spawn } from 'child_process';
@@ -33,7 +33,7 @@ function ensureSqliteAvailable() {
33
33
  checked = true;
34
34
  } catch (cause) {
35
35
  throw new Error(
36
- 'better-sqlite3 failed to load.\nRun: npx ca setup (auto-configures pnpm native builds)\nOr manually add to your package.json:\n "pnpm": { "onlyBuiltDependencies": ["better-sqlite3", "node-llama-cpp"] }\nThen run: pnpm install && pnpm rebuild better-sqlite3\nFor npm/yarn, run: npm rebuild better-sqlite3',
36
+ 'better-sqlite3 failed to load.\nFor pnpm projects:\n 1. Ensure package.json has: "pnpm": { "onlyBuiltDependencies": ["better-sqlite3"] }\n 2. Run: pnpm install && pnpm rebuild better-sqlite3\nFor npm/yarn projects:\n Run: npm rebuild better-sqlite3\nIf the error persists, check that build tools (python3, make, g++) are installed.',
37
37
  { cause }
38
38
  );
39
39
  }
@@ -42,6 +42,10 @@ function getDatabaseConstructor() {
42
42
  ensureSqliteAvailable();
43
43
  return DatabaseConstructor;
44
44
  }
45
+ function resetSqliteAvailability() {
46
+ checked = false;
47
+ DatabaseConstructor = null;
48
+ }
45
49
  var require2, checked, DatabaseConstructor;
46
50
  var init_availability = __esm({
47
51
  "src/memory/storage/sqlite/availability.ts"() {
@@ -580,7 +584,15 @@ async function isModelUsable() {
580
584
  let context = null;
581
585
  try {
582
586
  const modelPath = join(DEFAULT_MODEL_DIR, MODEL_FILENAME);
583
- llama = await getLlama();
587
+ llama = await getLlama({
588
+ build: "never",
589
+ // Never compile from source in a deployed tool
590
+ progressLogs: false,
591
+ // Suppress prebuilt binary fallback warnings
592
+ logLevel: LlamaLogLevel.error
593
+ // Only surface real errors from C++ backend
594
+ // Set NODE_LLAMA_CPP_DEBUG=true to re-enable all output for troubleshooting
595
+ });
584
596
  model = await llama.loadModel({ modelPath });
585
597
  context = await model.createEmbeddingContext();
586
598
  cachedUsability = { usable: true };
@@ -596,7 +608,19 @@ async function isModelUsable() {
596
608
  } finally {
597
609
  if (context) {
598
610
  try {
599
- context.dispose();
611
+ await context.dispose();
612
+ } catch {
613
+ }
614
+ }
615
+ if (model) {
616
+ try {
617
+ await model.dispose();
618
+ } catch {
619
+ }
620
+ }
621
+ if (llama) {
622
+ try {
623
+ await llama.dispose();
600
624
  } catch {
601
625
  }
602
626
  }
@@ -618,7 +642,15 @@ async function getEmbedding() {
618
642
  pendingInit = (async () => {
619
643
  try {
620
644
  const modelPath = await resolveModel({ cli: true });
621
- llamaInstance = await getLlama();
645
+ llamaInstance = await getLlama({
646
+ build: "never",
647
+ // Never compile from source in a deployed tool
648
+ progressLogs: false,
649
+ // Suppress prebuilt binary fallback warnings
650
+ logLevel: LlamaLogLevel.error
651
+ // Only surface real errors from C++ backend
652
+ // Set NODE_LLAMA_CPP_DEBUG=true to re-enable all output for troubleshooting
653
+ });
622
654
  modelInstance = await llamaInstance.loadModel({ modelPath });
623
655
  embeddingContext = await modelInstance.createEmbeddingContext();
624
656
  return embeddingContext;
@@ -1086,6 +1118,9 @@ async function syncIfNeeded(repoRoot, options = {}) {
1086
1118
  return false;
1087
1119
  }
1088
1120
 
1121
+ // src/memory/storage/sqlite/index.ts
1122
+ init_availability();
1123
+
1089
1124
  // src/memory/search/hybrid.ts
1090
1125
  var DEFAULT_VECTOR_WEIGHT = 0.7;
1091
1126
  var DEFAULT_TEXT_WEIGHT = 0.3;
@@ -3617,6 +3652,19 @@ function printPnpmConfigStatus(result) {
3617
3652
  console.log(` pnpm config: Added onlyBuiltDependencies [${result.added.join(", ")}]`);
3618
3653
  }
3619
3654
  }
3655
+ var SQLITE_STATUS_MSG = {
3656
+ already_ok: "OK",
3657
+ rebuilt: "OK (rebuilt native module)",
3658
+ installed_and_rebuilt: "OK (installed + rebuilt native module)",
3659
+ failed: "FAILED"
3660
+ };
3661
+ function printSqliteStatus(result) {
3662
+ const msg = SQLITE_STATUS_MSG[result.action];
3663
+ console.log(` SQLite: ${msg}`);
3664
+ if (result.error) {
3665
+ console.log(` ${result.error}`);
3666
+ }
3667
+ }
3620
3668
  function printBeadsFullStatus(check) {
3621
3669
  console.log(` Beads CLI: ${check.cliAvailable ? "OK" : "not found"}`);
3622
3670
  if (check.cliAvailable) {
@@ -3651,6 +3699,13 @@ async function runStatus(repoRoot) {
3651
3699
  } catch {
3652
3700
  }
3653
3701
  console.log(` Hooks: ${hooksInstalled ? "installed" : "not installed"}`);
3702
+ let sqliteOk = false;
3703
+ try {
3704
+ ensureSqliteAvailable();
3705
+ sqliteOk = true;
3706
+ } catch {
3707
+ }
3708
+ console.log(` SQLite: ${sqliteOk ? "OK" : "not available (run: pnpm rebuild better-sqlite3)"}`);
3654
3709
  const fullBeads = runFullBeadsCheck(repoRoot);
3655
3710
  printBeadsFullStatus(fullBeads);
3656
3711
  const scope = checkUserScope(repoRoot);
@@ -4842,39 +4897,59 @@ Return a list of relevant memory items:
4842
4897
  `,
4843
4898
  "security-reviewer": `---
4844
4899
  name: Security Reviewer
4845
- description: Reviews code for security vulnerabilities
4900
+ description: Mandatory core-4 reviewer with P0-P3 severity classification and specialist escalation
4846
4901
  ---
4847
4902
 
4848
4903
  # Security Reviewer
4849
4904
 
4850
4905
  ## Role
4851
- Review code changes for security vulnerabilities including OWASP top 10, injection attacks, authentication issues, and data exposure risks.
4906
+ Mandatory core-4 reviewer responsible for identifying security vulnerabilities using P0-P3 severity classification. Has authority to escalate findings to specialist security skills for deep analysis.
4852
4907
 
4853
4908
  ## Instructions
4854
- 1. Read the changed files completely
4855
- 2. Check for injection vulnerabilities (SQL, command, XSS)
4856
- 3. Verify input validation and sanitization
4857
- 4. Review authentication and authorization logic
4858
- 5. Check for hardcoded secrets or credentials
4859
- 6. Verify error messages do not leak sensitive info
4860
- 7. Check dependency versions for known CVEs
4861
- 8. For large diffs, spawn opus subagents to review different file groups in parallel (e.g., 1 per module). Merge findings and deduplicate.
4909
+ 1. Read \`docs/compound/research/security/overview.md\` for severity classification and escalation triggers
4910
+ 2. Read all changed files completely, focusing on:
4911
+ - Input handling and data flow to interpreters (SQL, shell, HTML, templates)
4912
+ - Secrets and credential management
4913
+ - Authentication and authorization enforcement
4914
+ - Logging and error handling for data exposure
4915
+ - Dependency changes in lockfiles or manifests
4916
+ 3. Classify each finding using P0-P3 severity:
4917
+ - **P0**: Unauthenticated RCE, credential compromise, unauth data access (blocks merge)
4918
+ - **P1**: Authenticated exploit, limited data breach, missing auth on sensitive routes (requires ack)
4919
+ - **P2**: Medium impact, harder to exploit, missing hardening (should fix)
4920
+ - **P3**: Best practice, defense in depth, code hygiene (nice to have)
4921
+ 4. Escalate to specialist skills when deep analysis needed:
4922
+ - SQL/command concat or template interpolation -> \`/security-injection\`
4923
+ - Hardcoded strings matching key patterns, committed .env files -> \`/security-secrets\`
4924
+ - Route handlers missing auth middleware, IDOR patterns -> \`/security-auth\`
4925
+ - Logging calls with request objects, verbose error responses -> \`/security-data\`
4926
+ - Lockfile changes, new dependencies, postinstall scripts -> \`/security-deps\`
4927
+ 5. For large diffs, spawn opus subagents to review different file groups in parallel. Merge findings and deduplicate.
4862
4928
 
4863
4929
  ## Literature
4864
- - Consult \`docs/compound/research/code-review/\` for systematic review methodology and severity classification
4930
+ - Consult \`docs/compound/research/security/overview.md\` for severity classification and OWASP mapping
4931
+ - Consult \`docs/compound/research/security/injection-patterns.md\` for injection detection heuristics
4932
+ - Consult \`docs/compound/research/security/secrets-checklist.md\` for secret format patterns
4933
+ - Consult \`docs/compound/research/security/auth-patterns.md\` for auth/authz audit methodology
4934
+ - Consult \`docs/compound/research/security/data-exposure.md\` for data leak detection
4935
+ - Consult \`docs/compound/research/security/dependency-security.md\` for dependency risk assessment
4936
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` for full theoretical foundation
4865
4937
  - Run \`npx ca knowledge "security review OWASP"\` for indexed security knowledge
4866
4938
 
4867
4939
  ## Collaboration
4868
- Share cross-cutting findings via SendMessage: security issues impacting architecture go to architecture-reviewer; secrets in test fixtures go to test-coverage-reviewer.
4940
+ Share cross-cutting findings via SendMessage: security issues impacting architecture go to architecture-reviewer; secrets in test fixtures go to test-coverage-reviewer. Escalate to specialist skills via SendMessage when deep analysis needed.
4869
4941
 
4870
4942
  ## Deployment
4871
4943
  AgentTeam member in the **review** phase. Spawned via TeamCreate. Communicate with teammates via SendMessage.
4872
4944
 
4873
4945
  ## Output Format
4874
- Return findings as:
4875
- - **CRITICAL**: Must fix before merge
4876
- - **WARNING**: Should fix, potential risk
4877
- - **INFO**: Best practice suggestion
4946
+ Return findings classified by severity:
4947
+ - **P0** (BLOCKS MERGE): Must fix before merge, no exceptions
4948
+ - **P1** (REQUIRES ACK): Must acknowledge or fix before merge
4949
+ - **P2** (SHOULD FIX): Should fix, create beads issue if deferred
4950
+ - **P3** (NICE TO HAVE): Best practice suggestion, non-blocking
4951
+
4952
+ If no findings at any severity: return "SECURITY REVIEW: CLEAR -- No findings at any severity level."
4878
4953
  `,
4879
4954
  "architecture-reviewer": `---
4880
4955
  name: Architecture Reviewer
@@ -5013,6 +5088,266 @@ AgentTeam member in the **review** phase. Spawned via TeamCreate. Communicate wi
5013
5088
  - **OVER-ENGINEERED**: Simpler solution exists
5014
5089
  - **YAGNI**: Feature not needed yet
5015
5090
  - **OK**: Appropriate complexity for the task
5091
+ `,
5092
+ "security-injection": `---
5093
+ name: Security Injection Specialist
5094
+ description: Deep trace analysis for SQL, command, XSS, SSRF, and SSTI injection vulnerabilities
5095
+ ---
5096
+
5097
+ # Security Injection Specialist
5098
+
5099
+ ## Role
5100
+ On-demand specialist for deep injection vulnerability analysis. Traces data flow from untrusted input sources to interpreter sinks (SQL engines, shells, browsers, template engines, HTTP clients).
5101
+
5102
+ ## Instructions
5103
+ 1. Read \`docs/compound/research/security/injection-patterns.md\` for detection heuristics and safe/unsafe patterns
5104
+ 2. For each changed file, identify:
5105
+ - **Input sources**: request params, body fields, headers, query strings, URL params, environment variables
5106
+ - **Interpreter sinks**: SQL queries, shell commands, HTML output, template rendering, outbound HTTP requests
5107
+ 3. Trace data flow from each source to each sink:
5108
+ - Direct concatenation or template interpolation into sink -> P0/P1
5109
+ - Flow through sanitization/validation before sink -> check if sanitization is adequate
5110
+ - Parameterized/prepared statement usage -> safe, note as OK
5111
+ 4. Classify by injection type:
5112
+ - **SQL** (survey 4.1): \`db.query\` with template literals, f-strings in queries, raw SQL with string concat
5113
+ - **Command** (survey 4.2): \`exec\`, \`system\`, \`popen\` with user input, \`shell=True\` with untrusted args
5114
+ - **XSS** (survey 4.3): \`innerHTML\`, \`dangerouslySetInnerHTML\`, \`v-html\`, \`| safe\` filter on user input
5115
+ - **SSRF** (survey 4.4): \`axios.get(userUrl)\`, \`requests.get(userUrl)\`, fetch with user-controlled URL
5116
+ - **SSTI** (survey 4.5): \`Template(userString)\`, \`render_template_string(userInput)\`
5117
+ 5. For large diffs, spawn opus subagents to trace different file groups in parallel. Merge findings.
5118
+
5119
+ ## Literature
5120
+ - Consult \`docs/compound/research/security/injection-patterns.md\` for unsafe/safe pattern pairs and detection heuristics
5121
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` sections 4.1-4.5 for theoretical foundation
5122
+ - Run \`npx ca knowledge "injection SQL command XSS SSRF SSTI"\` for indexed knowledge
5123
+
5124
+ ## Collaboration
5125
+ Report findings to security-reviewer via SendMessage with severity classification. Flag architecture-level injection risks (e.g., missing parameterization layer) to architecture-reviewer.
5126
+
5127
+ ## Deployment
5128
+ On-demand AgentTeam member in the **review** phase. Spawned by security-reviewer when injection patterns detected. Communicate with teammates via SendMessage.
5129
+
5130
+ ## Output Format
5131
+ Per finding:
5132
+ - **Type**: SQL / Command / XSS / SSRF / SSTI
5133
+ - **Severity**: P0-P3
5134
+ - **File:Line**: Location
5135
+ - **Source**: Where untrusted data enters
5136
+ - **Sink**: Where it reaches an interpreter
5137
+ - **Flow**: Brief trace description
5138
+ - **Fix**: Recommended safe pattern
5139
+
5140
+ If no findings: return "INJECTION REVIEW: CLEAR -- No injection patterns found."
5141
+ For large diffs (500+ lines): prioritize files with interpreter sinks over pure data/config files.
5142
+ `,
5143
+ "security-secrets": `---
5144
+ name: Security Secrets Specialist
5145
+ description: Credential and secrets scanning using pattern matching, entropy analysis, and git history checks
5146
+ ---
5147
+
5148
+ # Security Secrets Specialist
5149
+
5150
+ ## Role
5151
+ On-demand specialist for detecting hardcoded credentials, leaked secrets, and improper secret management in code and configuration.
5152
+
5153
+ ## Instructions
5154
+ 1. Read \`docs/compound/research/security/secrets-checklist.md\` for key format patterns and detection heuristics
5155
+ 2. Scan changed files for:
5156
+ - **Variable name patterns**: password, secret, token, apiKey, api_key, auth, credential, private_key, connection_string
5157
+ - **Known key formats**: AWS \`AKIA[0-9A-Z]{16}\`, GitHub \`ghp_[a-zA-Z0-9]{36}\`, Slack \`xoxb-\`/\`xoxp-\`, JWT signatures
5158
+ - **High-entropy strings**: 20+ character strings with mixed case, digits, and special chars in assignment context
5159
+ 3. Check for common hiding spots:
5160
+ - Committed \`.env\` files or \`.env.local\` without gitignore
5161
+ - Docker files with \`ENV SECRET=\` or \`ARG PASSWORD=\`
5162
+ - CI config files (\`.github/workflows/\`, \`.gitlab-ci.yml\`) with inline secrets
5163
+ - Test fixtures that use real-looking credentials instead of obvious fakes
5164
+ 4. Check git history for previously committed secrets:
5165
+ - \`git log --diff-filter=D -- '*.env'\` for deleted env files
5166
+ - \`git log -p -- <file>\` for files that changed secret-like values
5167
+ 5. Distinguish real secrets from safe patterns:
5168
+ - Test fixtures prefixed with \`test_\`, \`fake_\`, \`mock_\` -> OK
5169
+ - Placeholder values like \`YOUR_API_KEY_HERE\`, \`changeme\`, \`xxx\` -> OK
5170
+ - Public keys (not private) -> OK
5171
+ - Everything else -> flag for review
5172
+
5173
+ ## Literature
5174
+ - Consult \`docs/compound/research/security/secrets-checklist.md\` for format patterns and hiding spots
5175
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` section 4.6 for theoretical foundation
5176
+ - Run \`npx ca knowledge "secrets credentials hardcoded"\` for indexed knowledge
5177
+
5178
+ ## Collaboration
5179
+ Report findings to security-reviewer via SendMessage with severity classification. Flag secrets in test files to test-coverage-reviewer.
5180
+
5181
+ ## Deployment
5182
+ On-demand AgentTeam member in the **review** phase. Spawned by security-reviewer when secret patterns detected. Communicate with teammates via SendMessage.
5183
+
5184
+ ## Output Format
5185
+ Per finding:
5186
+ - **Severity**: P0 (real credential) / P1 (likely credential) / P2 (suspicious pattern) / P3 (missing .gitignore for secret files)
5187
+ - **File:Line**: Location
5188
+ - **Pattern**: What matched (variable name, key format, entropy)
5189
+ - **Value preview**: First/last 4 chars only (never full secret)
5190
+ - **Fix**: Use environment variable, secret manager, or .gitignore
5191
+
5192
+ If no findings: return "SECRETS REVIEW: CLEAR -- No hardcoded secrets or credential patterns found."
5193
+ `,
5194
+ "security-auth": `---
5195
+ name: Security Auth Specialist
5196
+ description: Route and endpoint audit for authentication, authorization, IDOR, JWT, and CORS vulnerabilities
5197
+ ---
5198
+
5199
+ # Security Auth Specialist
5200
+
5201
+ ## Role
5202
+ On-demand specialist for auditing authentication and authorization enforcement across routes, endpoints, and API handlers.
5203
+
5204
+ ## Instructions
5205
+ 1. Read \`docs/compound/research/security/auth-patterns.md\` for common broken patterns and framework-specific checks
5206
+ 2. Perform route audit:
5207
+ - List all route/endpoint definitions in changed files
5208
+ - For each route, verify auth middleware or guard is applied
5209
+ - Flag routes that modify data (POST/PUT/DELETE) without auth
5210
+ - Flag admin/privileged routes accessible without role checks
5211
+ 3. Check for IDOR (Insecure Direct Object Reference):
5212
+ - Find DB queries using user-supplied IDs from params/body
5213
+ - Verify ownership checks exist (e.g., \`WHERE id = ? AND user_id = ?\`)
5214
+ - Flag queries that fetch by ID alone without ownership verification
5215
+ 4. Check JWT handling:
5216
+ - Verify signature validation is not skipped
5217
+ - Check for algorithm confusion vulnerabilities (\`alg: none\`)
5218
+ - Verify expiry (\`exp\`) is checked
5219
+ - Flag tokens stored in localStorage (prefer httpOnly cookies)
5220
+ 5. Check CORS configuration:
5221
+ - Flag \`Access-Control-Allow-Origin: *\` with credentials
5222
+ - Flag overly permissive origin patterns
5223
+ - Verify CORS is intentional and scoped appropriately
5224
+ 6. Framework-specific checks:
5225
+ - **Express/NestJS**: missing \`authMiddleware\`, missing \`@UseGuards()\`, routes outside auth scope
5226
+ - **Django/FastAPI**: missing \`@login_required\`, missing \`Depends(get_current_user)\`, missing permission classes
5227
+ 7. For non-web projects (CLI tools, libraries): limit scope to file permissions, API key handling, and privilege escalation
5228
+
5229
+ ## Literature
5230
+ - Consult \`docs/compound/research/security/auth-patterns.md\` for broken auth patterns and detection methodology
5231
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` section 4.7 for theoretical foundation
5232
+ - Run \`npx ca knowledge "authentication authorization IDOR"\` for indexed knowledge
5233
+
5234
+ ## Collaboration
5235
+ Report findings to security-reviewer via SendMessage with severity classification. Flag missing middleware patterns to architecture-reviewer.
5236
+
5237
+ ## Deployment
5238
+ On-demand AgentTeam member in the **review** phase. Spawned by security-reviewer when auth patterns need deep analysis. Communicate with teammates via SendMessage.
5239
+
5240
+ ## Output Format
5241
+ Per finding:
5242
+ - **Type**: Missing Auth / IDOR / Role Escalation / JWT / CORS
5243
+ - **Severity**: P0-P3
5244
+ - **File:Line**: Location
5245
+ - **Route/Endpoint**: The affected route
5246
+ - **Issue**: What is missing or broken
5247
+ - **Fix**: Specific middleware, guard, or check to add
5248
+
5249
+ If no findings: return "AUTH REVIEW: CLEAR -- No authentication or authorization issues found."
5250
+ `,
5251
+ "security-data": `---
5252
+ name: Security Data Specialist
5253
+ description: Audit for PII in logs, verbose error responses, sensitive data in URLs, and overly broad API responses
5254
+ ---
5255
+
5256
+ # Security Data Specialist
5257
+
5258
+ ## Role
5259
+ On-demand specialist for detecting sensitive data exposure through logging, error handling, URLs, and API responses.
5260
+
5261
+ ## Instructions
5262
+ 1. Read \`docs/compound/research/security/data-exposure.md\` for exposure patterns and detection heuristics
5263
+ 2. Audit logging calls:
5264
+ - Flag \`console.log(req.body)\`, \`console.log(req.headers)\`, \`logger.info(user)\` -- unfiltered objects may contain passwords/tokens
5265
+ - Flag logging of \`Authorization\` header values
5266
+ - Flag logging of full error objects that may contain connection strings
5267
+ - Check structured loggers for field-level filtering
5268
+ 3. Audit error handlers:
5269
+ - Flag \`res.status(500).json({ error: err.message })\` or \`err.stack\` sent to clients
5270
+ - Flag DB connection strings, internal paths, or query details in error responses
5271
+ - Verify production error handlers return generic messages
5272
+ 4. Audit URLs and query parameters:
5273
+ - Flag tokens, keys, or auth values in query strings (leaks via referrer, logs, browser history)
5274
+ - Flag PII (email, name, SSN) in URL paths or query params
5275
+ - Check redirect URLs for open redirect patterns
5276
+ 5. Audit API responses:
5277
+ - Flag endpoints returning full DB records instead of selected fields
5278
+ - Flag responses containing \`password_hash\`, \`internal_id\`, \`secret\`, or similar internal fields
5279
+ - Verify response serialization uses explicit field selection or DTOs
5280
+
5281
+ ## Literature
5282
+ - Consult \`docs/compound/research/security/data-exposure.md\` for exposure patterns and detection heuristics
5283
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` section 4.8 for theoretical foundation
5284
+ - Run \`npx ca knowledge "data exposure PII logging"\` for indexed knowledge
5285
+
5286
+ ## Collaboration
5287
+ Report findings to security-reviewer via SendMessage with severity classification. Flag logging architecture issues to architecture-reviewer.
5288
+
5289
+ ## Deployment
5290
+ On-demand AgentTeam member in the **review** phase. Spawned by security-reviewer when data exposure patterns detected. Communicate with teammates via SendMessage.
5291
+
5292
+ ## Output Format
5293
+ Per finding:
5294
+ - **Type**: PII in Logs / Verbose Error / URL Exposure / Broad API Response
5295
+ - **Severity**: P0 (credentials in logs/responses) / P1 (PII exposure) / P2 (internal details) / P3 (hardening)
5296
+ - **File:Line**: Location
5297
+ - **Data at risk**: What sensitive data is exposed
5298
+ - **Channel**: Log / Error response / URL / API response
5299
+ - **Fix**: Specific filtering, redaction, or restructuring needed
5300
+
5301
+ If no findings: return "DATA EXPOSURE REVIEW: CLEAR -- No sensitive data exposure patterns found."
5302
+ `,
5303
+ "security-deps": `---
5304
+ name: Security Deps Specialist
5305
+ description: Dependency audit for vulnerable packages, lockfile changes, postinstall scripts, and supply chain risks
5306
+ ---
5307
+
5308
+ # Security Deps Specialist
5309
+
5310
+ ## Role
5311
+ On-demand specialist for auditing dependency security, lockfile changes, and supply chain risks.
5312
+
5313
+ ## Instructions
5314
+ 1. Read \`docs/compound/research/security/dependency-security.md\` for risk model and audit methodology
5315
+ 2. Run audit tools on changed dependency files:
5316
+ - **JS/TS**: \`pnpm audit\` or \`npm audit\` -- report critical and high vulnerabilities
5317
+ - **Python**: \`pip-audit\` or \`safety check\` -- report known CVEs
5318
+ - If audit tool is unavailable, note it and proceed with manual lockfile analysis
5319
+ 3. Check lockfile changes (pnpm-lock.yaml, package-lock.json, poetry.lock, requirements.txt):
5320
+ - **New direct deps**: Were they intentionally added? Check PR context
5321
+ - **Version downgrades**: Suspicious -- may reintroduce vulnerabilities
5322
+ - **New postinstall scripts**: Can execute arbitrary code during install
5323
+ - **Removed integrity hashes**: May indicate tampering
5324
+ 4. Evaluate new dependencies:
5325
+ - Check maintenance status (last commit, open issues, bus factor)
5326
+ - Flag packages with fewer than 100 weekly downloads (typosquat risk)
5327
+ - Flag packages pinned 3+ major versions behind latest
5328
+ - Check for known alternatives with better security track record
5329
+ 5. For large dependency changes, spawn opus subagents to audit different package groups in parallel.
5330
+
5331
+ ## Literature
5332
+ - Consult \`docs/compound/research/security/dependency-security.md\` for risk assessment methodology
5333
+ - Consult \`docs/compound/research/security/secure-coding-failure.md\` section 4.9 for theoretical foundation
5334
+ - Run \`npx ca knowledge "dependency vulnerability supply chain"\` for indexed knowledge
5335
+
5336
+ ## Collaboration
5337
+ Report findings to security-reviewer via SendMessage with severity classification. Flag architecture-level dependency concerns (e.g., replacing a core library) to architecture-reviewer.
5338
+
5339
+ ## Deployment
5340
+ On-demand AgentTeam member in the **review** phase. Spawned by security-reviewer when dependency changes detected. Communicate with teammates via SendMessage.
5341
+
5342
+ ## Output Format
5343
+ Per finding:
5344
+ - **Package**: name@version
5345
+ - **Severity**: P0 (actively exploited CVE) / P1 (critical CVE) / P2 (high CVE, outdated) / P3 (maintenance concern)
5346
+ - **CVE**: ID if applicable
5347
+ - **Issue**: What the vulnerability enables
5348
+ - **Fix**: Update to version X, replace with Y, or accept risk with justification
5349
+
5350
+ If no findings: return "DEPENDENCY REVIEW: CLEAR -- No vulnerable or suspicious dependencies found."
5016
5351
  `
5017
5352
  };
5018
5353
 
@@ -5487,8 +5822,8 @@ Multi-agent code review with severity classification.
5487
5822
 
5488
5823
  - Run quality gates: \`pnpm test && pnpm lint\`
5489
5824
  - Spawn specialized reviewers (security, architecture, performance, etc.)
5490
- - Classify findings as P1/P2/P3
5491
- - Fix all P1 findings before proceeding
5825
+ - Classify findings as P0 (blocks merge) / P1/P2/P3
5826
+ - Fix all P0/P1 findings before proceeding
5492
5827
 
5493
5828
  ## Phase 5: Compound
5494
5829
 
@@ -6169,7 +6504,7 @@ description: Multi-agent review with parallel specialized reviewers and severity
6169
6504
  # Review Skill
6170
6505
 
6171
6506
  ## Overview
6172
- Perform thorough code review by spawning specialized reviewers in parallel, consolidating findings with severity classification (P1/P2/P3), and gating completion on implementation-reviewer approval.
6507
+ Perform thorough code review by spawning specialized reviewers in parallel, consolidating findings with severity classification (P0/P1/P2/P3), and gating completion on implementation-reviewer approval.
6173
6508
 
6174
6509
  ## Methodology
6175
6510
  1. Run quality gates first: \`pnpm test && pnpm lint\`
@@ -6180,10 +6515,11 @@ Perform thorough code review by spawning specialized reviewers in parallel, cons
6180
6515
  - **Large** (500+): all 11 reviewers including docs, consistency, error-handling, pattern-matcher
6181
6516
  4. Spawn reviewers in an **AgentTeam** (TeamCreate + Task with \`team_name\`):
6182
6517
  - Role skills: \`.claude/skills/compound/agents/{security-reviewer,architecture-reviewer,performance-reviewer,test-coverage-reviewer,simplicity-reviewer}/SKILL.md\`
6518
+ - Security specialist skills (on-demand, spawned by security-reviewer): \`.claude/skills/compound/agents/{security-injection,security-secrets,security-auth,security-data,security-deps}/SKILL.md\`
6183
6519
  - For large diffs (500+), deploy MULTIPLE instances; split files across instances, coordinate via SendMessage
6184
6520
  5. Reviewers communicate findings to each other via \`SendMessage\`
6185
6521
  6. Collect, consolidate, and deduplicate all findings
6186
- 7. Classify by severity: P1 (critical/blocking), P2 (important), P3 (minor)
6522
+ 7. Classify by severity: P0 (blocks merge), P1 (critical/blocking), P2 (important), P3 (minor)
6187
6523
  8. Use \`AskUserQuestion\` when severity is ambiguous or fix has multiple valid options
6188
6524
  9. Create beads issues for P1 findings: \`bd create --title="P1: ..."\`
6189
6525
  10. Fix all P1 findings before proceeding
@@ -6212,10 +6548,12 @@ Perform thorough code review by spawning specialized reviewers in parallel, cons
6212
6548
  ## Quality Criteria
6213
6549
  - All quality gates pass (\`pnpm test\`, lint)
6214
6550
  - All 11 reviewer perspectives were applied in parallel
6215
- - Findings are classified P1/P2/P3 and deduplicated
6551
+ - Findings are classified P0/P1/P2/P3 and deduplicated
6216
6552
  - pattern-matcher checked memory and reinforced recurring issues
6217
6553
  - cct-reviewer checked against known Claude failure patterns
6218
6554
  - docs-reviewer confirmed docs/ADR alignment
6555
+ - security-reviewer P0 findings: none (blocks merge)
6556
+ - security-reviewer P1 findings: all acknowledged or resolved
6219
6557
  - All P1 findings fixed before \`/implementation-reviewer\` approval
6220
6558
  - \`/implementation-reviewer\` approved as mandatory gate
6221
6559
 
@@ -6802,6 +7140,60 @@ async function mergePnpmConfig(pkgPath, pkg) {
6802
7140
  await writeFile(pkgPath, JSON.stringify(pkg, null, 2) + "\n", "utf-8");
6803
7141
  return { isPnpm: true, alreadyConfigured: false, added };
6804
7142
  }
7143
+ function trySqliteLoad() {
7144
+ try {
7145
+ ensureSqliteAvailable();
7146
+ return true;
7147
+ } catch {
7148
+ return false;
7149
+ }
7150
+ }
7151
+ function verifySqlite(repoRoot, pnpmConfig) {
7152
+ if (trySqliteLoad()) {
7153
+ return { available: true, action: "already_ok" };
7154
+ }
7155
+ if (!pnpmConfig.isPnpm) {
7156
+ return {
7157
+ available: false,
7158
+ action: "failed",
7159
+ error: "better-sqlite3 failed to load. Run: npm rebuild better-sqlite3"
7160
+ };
7161
+ }
7162
+ try {
7163
+ execFileSync("pnpm", ["rebuild", "better-sqlite3"], {
7164
+ cwd: repoRoot,
7165
+ stdio: "pipe",
7166
+ timeout: 6e4
7167
+ });
7168
+ } catch {
7169
+ }
7170
+ resetSqliteAvailability();
7171
+ if (trySqliteLoad()) {
7172
+ return { available: true, action: "rebuilt" };
7173
+ }
7174
+ try {
7175
+ execFileSync("pnpm", ["install"], {
7176
+ cwd: repoRoot,
7177
+ stdio: "pipe",
7178
+ timeout: 12e4
7179
+ });
7180
+ execFileSync("pnpm", ["rebuild", "better-sqlite3"], {
7181
+ cwd: repoRoot,
7182
+ stdio: "pipe",
7183
+ timeout: 6e4
7184
+ });
7185
+ } catch {
7186
+ }
7187
+ resetSqliteAvailability();
7188
+ if (trySqliteLoad()) {
7189
+ return { available: true, action: "installed_and_rebuilt" };
7190
+ }
7191
+ return {
7192
+ available: false,
7193
+ action: "failed",
7194
+ error: "Auto-rebuild failed. Run manually: pnpm install && pnpm rebuild better-sqlite3"
7195
+ };
7196
+ }
6805
7197
  async function runUninstall(repoRoot, dryRun) {
6806
7198
  const actions = [];
6807
7199
  const dirsToRemove = [
@@ -6998,6 +7390,7 @@ async function runSetup(options) {
6998
7390
  upgrade = await runUpgrade(repoRoot);
6999
7391
  }
7000
7392
  const pnpmConfig = await ensurePnpmBuildConfig(repoRoot);
7393
+ const sqlite = verifySqlite(repoRoot, pnpmConfig);
7001
7394
  const lessonsDir = await ensureLessonsDirectory(repoRoot);
7002
7395
  const agentsMdUpdated = await updateAgentsMd(repoRoot);
7003
7396
  await ensureClaudeMdReference(repoRoot);
@@ -7040,6 +7433,7 @@ async function runSetup(options) {
7040
7433
  postCommitHook,
7041
7434
  model: modelStatus,
7042
7435
  pnpmConfig,
7436
+ sqlite,
7043
7437
  beads,
7044
7438
  scope,
7045
7439
  upgrade,
@@ -7141,6 +7535,7 @@ async function printSetupResult(result, quiet, repoRoot) {
7141
7535
  printSetupGitHooksStatus(result.gitHooks);
7142
7536
  printPostCommitHookStatus(result.postCommitHook);
7143
7537
  printPnpmConfigStatus(result.pnpmConfig);
7538
+ printSqliteStatus(result.sqlite);
7144
7539
  printGitignoreStatus(result.gitignore);
7145
7540
  console.log(` Model: ${MODEL_STATUS_MSG[result.model]}`);
7146
7541
  const fullBeads = runFullBeadsCheck(repoRoot);
@@ -7786,12 +8181,12 @@ async function runDoctor(repoRoot) {
7786
8181
  } catch {
7787
8182
  }
7788
8183
  checks.push(hooksOk ? { name: "Claude hooks", status: "pass" } : { name: "Claude hooks", status: "fail", fix: "Run: npx ca setup" });
7789
- let modelOk = false;
7790
- try {
7791
- modelOk = isModelAvailable();
7792
- } catch {
8184
+ checks.push(checkEmbeddingModel());
8185
+ checks.push(checkSqliteHealth());
8186
+ const pnpmCheck = checkPnpmBuildConfig(repoRoot);
8187
+ if (pnpmCheck !== null) {
8188
+ checks.push(pnpmCheck);
7793
8189
  }
7794
- checks.push(modelOk ? { name: "Embedding model", status: "pass" } : { name: "Embedding model", status: "warn", fix: "Run: npx ca download-model" });
7795
8190
  const beadsResult = checkBeadsAvailable();
7796
8191
  checks.push(beadsResult.available ? { name: "Beads CLI", status: "pass" } : { name: "Beads CLI", status: "warn", fix: "Install beads: https://github.com/Nathandela/beads" });
7797
8192
  checks.push(checkGitignoreHealth(repoRoot) ? { name: ".gitignore health", status: "pass" } : { name: ".gitignore health", status: "warn", fix: "Run: npx ca setup --update" });
@@ -7811,6 +8206,46 @@ async function runDoctor(repoRoot) {
7811
8206
  checks.push(!scope.isUserScope ? { name: "Codebase scope", status: "pass" } : { name: "Codebase scope", status: "warn", fix: "Install in a specific repository, not home directory" });
7812
8207
  return checks;
7813
8208
  }
8209
+ function checkEmbeddingModel() {
8210
+ try {
8211
+ return isModelAvailable() ? { name: "Embedding model", status: "pass" } : { name: "Embedding model", status: "warn", fix: "Run: npx ca download-model" };
8212
+ } catch {
8213
+ return { name: "Embedding model", status: "warn", fix: "Run: npx ca download-model" };
8214
+ }
8215
+ }
8216
+ function checkSqliteHealth() {
8217
+ try {
8218
+ ensureSqliteAvailable();
8219
+ return { name: "SQLite (better-sqlite3)", status: "pass" };
8220
+ } catch {
8221
+ return { name: "SQLite (better-sqlite3)", status: "fail", fix: "Run: pnpm rebuild better-sqlite3 (or npm rebuild better-sqlite3)" };
8222
+ }
8223
+ }
8224
+ function checkPnpmBuildConfig(repoRoot) {
8225
+ const lockPath = join(repoRoot, "pnpm-lock.yaml");
8226
+ const pkgPath = join(repoRoot, "package.json");
8227
+ let pkg;
8228
+ try {
8229
+ pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
8230
+ } catch {
8231
+ return null;
8232
+ }
8233
+ const hasLockfile = existsSync(lockPath);
8234
+ const hasPmField = typeof pkg.packageManager === "string" && pkg.packageManager.startsWith("pnpm");
8235
+ if (!hasLockfile && !hasPmField) return null;
8236
+ const pnpmConfig = pkg.pnpm;
8237
+ const deps = pnpmConfig?.onlyBuiltDependencies;
8238
+ if (!Array.isArray(deps)) {
8239
+ return { name: "pnpm build config", status: "fail", fix: 'Run: npx ca setup (or add "pnpm.onlyBuiltDependencies" to package.json)' };
8240
+ }
8241
+ if (deps.includes("*")) return { name: "pnpm build config", status: "pass" };
8242
+ const required = ["better-sqlite3", "node-llama-cpp"];
8243
+ const missing = required.filter((d) => !deps.includes(d));
8244
+ if (missing.length > 0) {
8245
+ return { name: "pnpm build config", status: "fail", fix: `Missing from onlyBuiltDependencies: [${missing.join(", ")}]. Run: npx ca setup` };
8246
+ }
8247
+ return { name: "pnpm build config", status: "pass" };
8248
+ }
7814
8249
  var STATUS_ICONS = {
7815
8250
  pass: "OK",
7816
8251
  fail: "FAIL",
@@ -8595,29 +9030,61 @@ function registerVerifyGatesCommand(program2) {
8595
9030
  }
8596
9031
 
8597
9032
  // src/changelog-data.ts
8598
- var CHANGELOG_RECENT = `## [1.4.2] - 2026-02-23
9033
+ var CHANGELOG_RECENT = `## [1.4.4] - 2026-02-23
8599
9034
 
8600
- ### Fixed
9035
+ ### Added
8601
9036
 
8602
- - **Banner audio crash on headless Linux**: Async \`ENOENT\` error from missing \`aplay\` no longer crashes \`ca setup --update\`
8603
- - **PowerShell path injection on Windows**: Temp paths containing apostrophes no longer break or inject commands in \`banner-audio.ts\`
8604
- - **Banner audio test coverage**: Rewrote tests with proper mock isolation (\`vi.spyOn\` + file-scope \`vi.mock\`), covering async ENOENT, sync throw, stop() idempotency, and normal exit cleanup
9037
+ - **Security arc with P0-P3 severity model**: Security-reviewer promoted from generic OWASP checker to mandatory core-4 reviewer with P0 (blocks merge), P1 (requires ack), P2 (should fix), P3 (nice to have) classification
9038
+ - **5 on-demand security specialist skills**: \`/security-injection\`, \`/security-secrets\`, \`/security-auth\`, \`/security-data\`, \`/security-deps\` -- spawned by security-reviewer via SendMessage within the review AgentTeam for deep trace analysis
9039
+ - **6 security reference docs** (\`docs/research/security/\`): overview, injection-patterns, secrets-checklist, auth-patterns, data-exposure, dependency-security -- distilled from the secure-coding-failure PhD survey into actionable agent guides
9040
+ - **Native addon build injection** (\`scripts/postinstall.mjs\`): Postinstall script auto-patches consumer \`package.json\` with \`pnpm.onlyBuiltDependencies\` config for \`better-sqlite3\` and \`node-llama-cpp\`. Handles indent preservation, BOM stripping, atomic writes
9041
+ - **CLI preflight diagnostics** (\`src/cli-preflight.ts\`): Catches native module load failures before commands run, prints PM-specific fix instructions (pnpm: 3 options; npm/yarn: rebuild + build tool hints)
9042
+ - **\`ca doctor\` pnpm check**: Verifies \`onlyBuiltDependencies\` is configured correctly for pnpm projects, recognizes wildcard \`["*"]\` as valid
9043
+ - **Escalation-wiring tests**: 7 new tests verifying security-reviewer mentions all 5 specialists, each specialist declares "Spawned by security-reviewer", P0 documented as merge-blocking, each specialist has \`npx ca knowledge\` and references correct research doc
9044
+ - **better-sqlite3 injection patterns**: Added project-specific \`db.exec()\` vs \`db.prepare().run()\` examples to \`injection-patterns.md\`
9045
+
9046
+ ### Fixed
8605
9047
 
8606
- ## [1.4.1] - 2026-02-22
9048
+ - **Noisy \`node-llama-cpp\` warnings on headless Linux**: Vulkan binary fallback and \`special_eos_id\` tokenizer warnings no longer print during \`ca search\` / \`ca knowledge\` -- GPU auto-detection preserved via \`progressLogs: false\` + \`logLevel: error\`
9049
+ - **Resource leak in \`isModelUsable()\`**: \`Llama\` and \`LlamaModel\` instances are now properly disposed after the preflight usability check
9050
+ - **Wildcard \`onlyBuiltDependencies\`**: Doctor and postinstall now recognize \`["*"]\` as fully configured (no false positive)
9051
+ - **Infinity loop marker injection**: \`--model\` validated against shell metacharacters; grep patterns anchored (\`^EPIC_COMPLETE\`, \`^EPIC_FAILED\`) to prevent false-positive matches from prompt echo in logs
9052
+ - **Template-to-deployed SKILL.md drift**: Backported all deployed specialist improvements (output fields, collaboration notes, \`npx ca knowledge\` lines) into source templates so \`ca setup --update\` no longer regresses
9053
+ - **SSRF citations**: 3 OWASP references in \`secure-coding-failure.md\` corrected from A01 (Broken Access Control) to A10 (SSRF)
9054
+ - **Stale verification docs**: Exit criteria updated from 6 to 8 categories (added Security Clear + Workflow Gates); closed-loop review process updated with security check in Stage 4 flowchart
9055
+ - **Broken dual-path reference** in \`subagent-pipeline.md\`: Now documents both \`docs/research/security/\` (source repo) and \`docs/compound/research/security/\` (consumer repos)
9056
+ - **Incomplete OWASP mapping** in \`overview.md\`: Completed from 5/10 to 10/10 (added A04, A05, A07, A08, A09)
8607
9057
 
8608
9058
  ### Changed
8609
9059
 
8610
- - **Broader retrieval messaging**: \`ca search\` and \`ca knowledge\` descriptions in prime output and AGENTS.md now encourage general-purpose use beyond mandatory architectural triggers
9060
+ - **\`getLlama()\` initialization hardened**: Both call sites (\`nomic.ts\`, \`model.ts\`) now pass \`build: 'never'\` to prevent silent compilation from source on exotic platforms; set \`NODE_LLAMA_CPP_DEBUG=true\` to re-enable verbose output
9061
+ - **Review skill wired to security arc**: P0 added to severity overview, security specialist skills listed as on-demand members, quality criteria include P0/P1 checks
9062
+ - **WORKFLOW template**: Severity classification updated from P1/P2/P3 to P0-P3 with "Fix all P0/P1 findings"
9063
+ - **Zero-findings instruction**: All 6 security templates (reviewer + 5 specialists) now include "return CLEAR" instruction when no findings detected
9064
+ - **Scope-limiting instruction**: \`security-injection\` prioritizes files with interpreter sinks over pure data/config for large diffs (500+ lines)
9065
+ - **Non-web context**: \`security-auth\` includes step for CLI/API-only projects without web routes
9066
+ - **Graceful audit skip**: \`security-deps\` handles missing \`pnpm audit\` / \`pip-audit\` gracefully instead of failing
8611
9067
 
8612
- ## [1.4.0] - 2026-02-22
9068
+ ## [1.4.3] - 2026-02-23
8613
9069
 
8614
9070
  ### Fixed
8615
9071
 
8616
- - **Plugin manifest**: Corrected repository URL from \`compound_agent\` to \`learning_agent\`
9072
+ - **Setup reports success when SQLite is broken**: \`npx ca setup\` now verifies that \`better-sqlite3\` actually loads after configuring \`pnpm.onlyBuiltDependencies\`, and auto-rebuilds if needed (escalates from \`pnpm rebuild\` to \`pnpm install + rebuild\`)
9073
+ - **Misleading error message**: \`ensureSqliteAvailable()\` no longer suggests "Run: npx ca setup" (which didn't fix the problem); now provides per-package-manager rebuild instructions and build tools hint
8617
9074
 
8618
- ### Changed
9075
+ ### Added
9076
+
9077
+ - **SQLite health check in \`ca doctor\`**: New check reports \`[FAIL]\` with fix hint when \`better-sqlite3\` cannot load
9078
+ - **SQLite status in \`ca setup --status\`**: Shows "OK" or "not available" alongside other status checks
9079
+ - **\`resetSqliteAvailability()\` export**: Allows re-probing SQLite after native module rebuild
8619
9080
 
8620
- - **Version consolidation**: Roll-up release of v1.3.7\u2013v1.3.9 production readiness fixes (test pipeline hardening, data integrity, two-phase vector search, FTS5 sanitization)`;
9081
+ ## [1.4.2] - 2026-02-23
9082
+
9083
+ ### Fixed
9084
+
9085
+ - **Banner audio crash on headless Linux**: Async \`ENOENT\` error from missing \`aplay\` no longer crashes \`ca setup --update\`
9086
+ - **PowerShell path injection on Windows**: Temp paths containing apostrophes no longer break or inject commands in \`banner-audio.ts\`
9087
+ - **Banner audio test coverage**: Rewrote tests with proper mock isolation (\`vi.spyOn\` + file-scope \`vi.mock\`), covering async ENOENT, sync throw, stop() idempotency, and normal exit cleanup`;
8621
9088
 
8622
9089
  // src/commands/about.ts
8623
9090
  function registerAboutCommand(program2) {
@@ -9256,6 +9723,7 @@ function registerCaptureCommands(program2) {
9256
9723
  });
9257
9724
  }
9258
9725
  var EPIC_ID_PATTERN2 = /^[a-zA-Z0-9_.-]+$/;
9726
+ var MODEL_PATTERN = /^[a-zA-Z0-9_.:/-]+$/;
9259
9727
  function buildScriptHeader(timestamp, maxRetries, model, epicIds) {
9260
9728
  return `#!/usr/bin/env bash
9261
9729
  # Infinity Loop - Generated by: ca loop
@@ -9456,18 +9924,18 @@ while true; do
9456
9924
  -p "$PROMPT" \\
9457
9925
  &> "$LOGFILE" || true
9458
9926
 
9459
- if grep -q "EPIC_COMPLETE" "$LOGFILE"; then
9927
+ if grep -q "^EPIC_COMPLETE$" "$LOGFILE"; then
9460
9928
  log "Epic $EPIC_ID completed successfully"
9461
9929
  SUCCESS=true
9462
9930
  break
9463
- elif grep -q "HUMAN_REQUIRED" "$LOGFILE"; then
9464
- REASON=$(grep "HUMAN_REQUIRED:" "$LOGFILE" | head -1 | sed 's/.*HUMAN_REQUIRED: *//')
9931
+ elif grep -q "^HUMAN_REQUIRED:" "$LOGFILE"; then
9932
+ REASON=$(grep "^HUMAN_REQUIRED:" "$LOGFILE" | head -1 | sed 's/^HUMAN_REQUIRED: *//')
9465
9933
  log "Epic $EPIC_ID needs human action: $REASON"
9466
9934
  bd update "$EPIC_ID" --notes "Human required: $REASON" 2>/dev/null || true
9467
9935
  SKIPPED=$((SKIPPED + 1))
9468
9936
  SUCCESS=skip
9469
9937
  break
9470
- elif grep -q "EPIC_FAILED" "$LOGFILE"; then
9938
+ elif grep -q "^EPIC_FAILED$" "$LOGFILE"; then
9471
9939
  log "Epic $EPIC_ID reported failure (attempt $ATTEMPT)"
9472
9940
  else
9473
9941
  log "Epic $EPIC_ID session ended without marker (attempt $ATTEMPT)"
@@ -9501,6 +9969,9 @@ function validateOptions(options) {
9501
9969
  if (!Number.isInteger(options.maxRetries) || options.maxRetries < 0) {
9502
9970
  throw new Error(`Invalid maxRetries: must be a non-negative integer, got ${options.maxRetries}`);
9503
9971
  }
9972
+ if (!MODEL_PATTERN.test(options.model)) {
9973
+ throw new Error(`Invalid model "${options.model}": must match ${MODEL_PATTERN}`);
9974
+ }
9504
9975
  if (options.epics) {
9505
9976
  for (const id of options.epics) {
9506
9977
  if (!EPIC_ID_PATTERN2.test(id)) {
@@ -9848,6 +10319,109 @@ function registerManagementCommands(program2) {
9848
10319
  registerWorktreeCommands(program2);
9849
10320
  }
9850
10321
 
10322
+ // src/cli-preflight.ts
10323
+ var NEEDS_SQLITE = /* @__PURE__ */ new Set([
10324
+ // Capture
10325
+ "learn",
10326
+ "capture",
10327
+ "detect",
10328
+ // Retrieval
10329
+ "search",
10330
+ "list",
10331
+ "load-session",
10332
+ "check-plan",
10333
+ // Knowledge
10334
+ "knowledge",
10335
+ "index-docs",
10336
+ // Management - CRUD
10337
+ "show",
10338
+ "update",
10339
+ "delete",
10340
+ // Management - invalidation
10341
+ "wrong",
10342
+ "validate",
10343
+ // Management - maintenance
10344
+ "compact",
10345
+ "rebuild",
10346
+ "stats",
10347
+ "prime",
10348
+ // Management - IO
10349
+ "export",
10350
+ "import",
10351
+ // Audit & compound
10352
+ "audit",
10353
+ "compound"
10354
+ ]);
10355
+ function commandNeedsSqlite(cmd) {
10356
+ let current = cmd;
10357
+ while (current) {
10358
+ if (NEEDS_SQLITE.has(current.name())) return true;
10359
+ current = current.parent;
10360
+ }
10361
+ return false;
10362
+ }
10363
+ function detectPackageManager(cwd) {
10364
+ if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
10365
+ try {
10366
+ const raw = readFileSync(join(cwd, "package.json"), "utf-8");
10367
+ const pkg = JSON.parse(raw);
10368
+ if (typeof pkg.packageManager === "string") {
10369
+ if (pkg.packageManager.startsWith("pnpm")) return "pnpm";
10370
+ if (pkg.packageManager.startsWith("yarn")) return "yarn";
10371
+ }
10372
+ } catch {
10373
+ }
10374
+ if (existsSync(join(cwd, "yarn.lock"))) return "yarn";
10375
+ if (existsSync(join(cwd, "package-lock.json"))) return "npm";
10376
+ return "unknown";
10377
+ }
10378
+ function printNativeBuildDiagnostic(err, cwd = process.cwd()) {
10379
+ const pm = detectPackageManager(cwd);
10380
+ console.error("");
10381
+ console.error('ERROR: Native module "better-sqlite3" failed to load.');
10382
+ console.error("");
10383
+ if (pm === "pnpm") {
10384
+ console.error(" pnpm v10+ blocks native addon builds by default.");
10385
+ console.error("");
10386
+ console.error(" Fix (choose one):");
10387
+ console.error("");
10388
+ console.error(" Option A -- Run setup (recommended):");
10389
+ console.error(" npx ca setup");
10390
+ console.error("");
10391
+ console.error(" Option B -- Manual patch:");
10392
+ console.error(" 1. Add to package.json:");
10393
+ console.error(' "pnpm": { "onlyBuiltDependencies": ["better-sqlite3", "node-llama-cpp"] }');
10394
+ console.error(" 2. Run: pnpm install && pnpm rebuild better-sqlite3");
10395
+ console.error("");
10396
+ console.error(" Option C -- Approve build scripts interactively:");
10397
+ console.error(" pnpm approve-builds");
10398
+ console.error("");
10399
+ } else {
10400
+ console.error(" Fix: npm rebuild better-sqlite3");
10401
+ console.error("");
10402
+ console.error(" If the error persists, ensure build tools are installed:");
10403
+ printBuildToolsHint();
10404
+ console.error("");
10405
+ }
10406
+ if (err instanceof Error && err.cause) {
10407
+ const causeMsg = err.cause instanceof Error ? err.cause.message : String(err.cause);
10408
+ console.error(" Underlying error:", causeMsg);
10409
+ console.error("");
10410
+ }
10411
+ }
10412
+ function printBuildToolsHint() {
10413
+ const platform = process.platform;
10414
+ if (platform === "darwin") {
10415
+ console.error(" macOS: xcode-select --install");
10416
+ } else if (platform === "linux") {
10417
+ console.error(" Linux: sudo apt install build-essential python3 (Debian/Ubuntu)");
10418
+ console.error(' sudo dnf groupinstall "Development Tools" (Fedora)');
10419
+ } else if (platform === "win32") {
10420
+ console.error(" Windows: Install Visual Studio Build Tools");
10421
+ console.error(" https://visualstudio.microsoft.com/visual-cpp-build-tools/");
10422
+ }
10423
+ }
10424
+
9851
10425
  // src/cli.ts
9852
10426
  function cleanup() {
9853
10427
  try {
@@ -9873,6 +10447,20 @@ registerSetupCommands(program);
9873
10447
  registerCompoundCommands(program);
9874
10448
  registerLoopCommands(program);
9875
10449
  registerPhaseCheckCommand(program);
10450
+ program.hook("preAction", (_thisCommand, actionCommand) => {
10451
+ if (!commandNeedsSqlite(actionCommand)) return;
10452
+ try {
10453
+ ensureSqliteAvailable();
10454
+ } catch (err) {
10455
+ let root;
10456
+ try {
10457
+ root = getRepoRoot();
10458
+ } catch {
10459
+ }
10460
+ printNativeBuildDiagnostic(err, root);
10461
+ process.exit(1);
10462
+ }
10463
+ });
9876
10464
  program.parse();
9877
10465
  //# sourceMappingURL=cli.js.map
9878
10466
  //# sourceMappingURL=cli.js.map