compound-agent 1.6.2 → 1.6.5
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/CHANGELOG.md +36 -1
- package/README.md +10 -0
- package/dist/cli.js +589 -305
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +38 -16
- package/dist/index.js.map +1 -1
- package/docs/research/scenario-testing/advanced-and-emerging.md +470 -0
- package/docs/research/scenario-testing/core-foundations.md +507 -0
- package/docs/research/scenario-testing/domain-specific-and-human-factors.md +474 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -120,7 +120,9 @@ __export(nomic_exports, {
|
|
|
120
120
|
embedTexts: () => embedTexts,
|
|
121
121
|
getEmbedding: () => getEmbedding,
|
|
122
122
|
isModelAvailable: () => isModelAvailable,
|
|
123
|
-
unloadEmbedding: () => unloadEmbedding
|
|
123
|
+
unloadEmbedding: () => unloadEmbedding,
|
|
124
|
+
unloadEmbeddingResources: () => unloadEmbeddingResources,
|
|
125
|
+
withEmbedding: () => withEmbedding
|
|
124
126
|
});
|
|
125
127
|
async function getEmbedding() {
|
|
126
128
|
if (embeddingContext) return embeddingContext;
|
|
@@ -147,23 +149,44 @@ async function getEmbedding() {
|
|
|
147
149
|
})();
|
|
148
150
|
return pendingInit;
|
|
149
151
|
}
|
|
150
|
-
function
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
152
|
+
async function unloadEmbeddingResources() {
|
|
153
|
+
const pending = pendingInit;
|
|
154
|
+
if (pending) {
|
|
155
|
+
try {
|
|
156
|
+
await pending;
|
|
157
|
+
} catch {
|
|
158
|
+
}
|
|
155
159
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
+
const context = embeddingContext;
|
|
161
|
+
const model = modelInstance;
|
|
162
|
+
const llama = llamaInstance;
|
|
163
|
+
embeddingContext = null;
|
|
164
|
+
modelInstance = null;
|
|
165
|
+
llamaInstance = null;
|
|
166
|
+
pendingInit = null;
|
|
167
|
+
const disposals = [];
|
|
168
|
+
if (context) {
|
|
169
|
+
disposals.push(context.dispose());
|
|
160
170
|
}
|
|
161
|
-
if (
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
171
|
+
if (model) {
|
|
172
|
+
disposals.push(model.dispose());
|
|
173
|
+
}
|
|
174
|
+
if (llama) {
|
|
175
|
+
disposals.push(llama.dispose());
|
|
176
|
+
}
|
|
177
|
+
if (disposals.length > 0) {
|
|
178
|
+
await Promise.allSettled(disposals);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
function unloadEmbedding() {
|
|
182
|
+
void unloadEmbeddingResources();
|
|
183
|
+
}
|
|
184
|
+
async function withEmbedding(fn) {
|
|
185
|
+
try {
|
|
186
|
+
return await fn();
|
|
187
|
+
} finally {
|
|
188
|
+
await unloadEmbeddingResources();
|
|
165
189
|
}
|
|
166
|
-
pendingInit = null;
|
|
167
190
|
}
|
|
168
191
|
async function embedText(text) {
|
|
169
192
|
const ctx = await getEmbedding();
|
|
@@ -203,7 +226,9 @@ __export(embeddings_exports, {
|
|
|
203
226
|
isModelAvailable: () => isModelAvailable,
|
|
204
227
|
isModelUsable: () => isModelUsable,
|
|
205
228
|
resolveModel: () => resolveModel,
|
|
206
|
-
unloadEmbedding: () => unloadEmbedding
|
|
229
|
+
unloadEmbedding: () => unloadEmbedding,
|
|
230
|
+
unloadEmbeddingResources: () => unloadEmbeddingResources,
|
|
231
|
+
withEmbedding: () => withEmbedding
|
|
207
232
|
});
|
|
208
233
|
var init_embeddings = __esm({
|
|
209
234
|
"src/memory/embeddings/index.ts"() {
|
|
@@ -2291,7 +2316,7 @@ async function runBackgroundEmbed(repoRoot) {
|
|
|
2291
2316
|
const start = Date.now();
|
|
2292
2317
|
writeEmbedStatus(repoRoot, { state: "running", startedAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
2293
2318
|
try {
|
|
2294
|
-
const result = await embedChunks(repoRoot, { onlyMissing: true });
|
|
2319
|
+
const result = await withEmbedding(async () => embedChunks(repoRoot, { onlyMissing: true }));
|
|
2295
2320
|
writeEmbedStatus(repoRoot, {
|
|
2296
2321
|
state: "completed",
|
|
2297
2322
|
chunksEmbedded: result.chunksEmbedded,
|
|
@@ -2306,7 +2331,6 @@ async function runBackgroundEmbed(repoRoot) {
|
|
|
2306
2331
|
durationMs: Date.now() - start
|
|
2307
2332
|
});
|
|
2308
2333
|
} finally {
|
|
2309
|
-
unloadEmbedding();
|
|
2310
2334
|
closeKnowledgeDb();
|
|
2311
2335
|
lock.release();
|
|
2312
2336
|
}
|
|
@@ -2369,8 +2393,8 @@ function parseBdShowDeps(raw) {
|
|
|
2369
2393
|
init_compound();
|
|
2370
2394
|
init_embeddings();
|
|
2371
2395
|
init_storage();
|
|
2372
|
-
function registerCompoundCommands(
|
|
2373
|
-
|
|
2396
|
+
function registerCompoundCommands(program) {
|
|
2397
|
+
program.command("compound").description("Synthesize cross-cutting patterns from lessons").action(async () => {
|
|
2374
2398
|
const repoRoot = getRepoRoot();
|
|
2375
2399
|
const { items } = await readMemoryItems(repoRoot);
|
|
2376
2400
|
if (items.length === 0) {
|
|
@@ -2385,18 +2409,22 @@ function registerCompoundCommands(program2) {
|
|
|
2385
2409
|
return;
|
|
2386
2410
|
}
|
|
2387
2411
|
openDb(repoRoot);
|
|
2388
|
-
|
|
2412
|
+
let embeddings;
|
|
2389
2413
|
try {
|
|
2390
|
-
|
|
2391
|
-
const
|
|
2392
|
-
const
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
vec =
|
|
2396
|
-
|
|
2414
|
+
embeddings = await withEmbedding(async () => {
|
|
2415
|
+
const vecs = [];
|
|
2416
|
+
for (const item of items) {
|
|
2417
|
+
const text = `${item.trigger} ${item.insight}`;
|
|
2418
|
+
const hash = contentHash(item.trigger, item.insight);
|
|
2419
|
+
let vec = getCachedEmbedding(repoRoot, item.id, hash);
|
|
2420
|
+
if (!vec) {
|
|
2421
|
+
vec = await embedText(text);
|
|
2422
|
+
setCachedEmbedding(repoRoot, item.id, vec, hash);
|
|
2423
|
+
}
|
|
2424
|
+
vecs.push(vec);
|
|
2397
2425
|
}
|
|
2398
|
-
|
|
2399
|
-
}
|
|
2426
|
+
return vecs;
|
|
2427
|
+
});
|
|
2400
2428
|
} catch (err) {
|
|
2401
2429
|
console.error(`Error computing embeddings: ${err instanceof Error ? err.message : String(err)}`);
|
|
2402
2430
|
console.error("Run: npx ca download-model");
|
|
@@ -2707,7 +2735,7 @@ function playBannerAudio() {
|
|
|
2707
2735
|
return null;
|
|
2708
2736
|
}
|
|
2709
2737
|
proc.unref();
|
|
2710
|
-
const
|
|
2738
|
+
const cleanup = () => {
|
|
2711
2739
|
try {
|
|
2712
2740
|
proc.kill();
|
|
2713
2741
|
} catch {
|
|
@@ -2729,7 +2757,7 @@ function playBannerAudio() {
|
|
|
2729
2757
|
} catch {
|
|
2730
2758
|
}
|
|
2731
2759
|
});
|
|
2732
|
-
return { stop:
|
|
2760
|
+
return { stop: cleanup };
|
|
2733
2761
|
} catch {
|
|
2734
2762
|
return null;
|
|
2735
2763
|
}
|
|
@@ -5678,6 +5706,32 @@ $ARGUMENTS
|
|
|
5678
5706
|
**MANDATORY FIRST STEP -- NON-NEGOTIABLE**: Use the Read tool to open and read \`.claude/skills/compound/researcher/SKILL.md\` NOW. Do NOT proceed until you have read the complete skill file.
|
|
5679
5707
|
|
|
5680
5708
|
Then: scan docs/compound/research/ for gaps, propose topics via AskUserQuestion, spawn parallel researcher subagents.
|
|
5709
|
+
`,
|
|
5710
|
+
"agentic-audit.md": `---
|
|
5711
|
+
name: compound:agentic-audit
|
|
5712
|
+
description: Audit codebase against the 15-principle agentic manifesto
|
|
5713
|
+
argument-hint: "<scope or focus area>"
|
|
5714
|
+
---
|
|
5715
|
+
$ARGUMENTS
|
|
5716
|
+
|
|
5717
|
+
# Agentic Audit
|
|
5718
|
+
|
|
5719
|
+
**MANDATORY FIRST STEP -- NON-NEGOTIABLE**: Use the Read tool to open and read \`.claude/skills/compound/agentic/SKILL.md\` NOW. Do NOT proceed until you have read the complete skill file.
|
|
5720
|
+
|
|
5721
|
+
Run in **audit** mode. Score all 15 principles, produce the report, offer beads epic.
|
|
5722
|
+
`,
|
|
5723
|
+
"agentic-setup.md": `---
|
|
5724
|
+
name: compound:agentic-setup
|
|
5725
|
+
description: Set up codebase for agentic AI development (audit-first)
|
|
5726
|
+
argument-hint: "<scope or focus area>"
|
|
5727
|
+
---
|
|
5728
|
+
$ARGUMENTS
|
|
5729
|
+
|
|
5730
|
+
# Agentic Setup
|
|
5731
|
+
|
|
5732
|
+
**MANDATORY FIRST STEP -- NON-NEGOTIABLE**: Use the Read tool to open and read \`.claude/skills/compound/agentic/SKILL.md\` NOW. Do NOT proceed until you have read the complete skill file.
|
|
5733
|
+
|
|
5734
|
+
Run in **setup** mode. Audit first, then propose and create files to fill gaps.
|
|
5681
5735
|
`,
|
|
5682
5736
|
// =========================================================================
|
|
5683
5737
|
// Utility commands (kept: learn-that, check-that, prime)
|
|
@@ -5799,7 +5853,7 @@ npx ca doctor
|
|
|
5799
5853
|
settings.json # Claude Code hooks
|
|
5800
5854
|
plugin.json # Plugin manifest
|
|
5801
5855
|
agents/compound/ # Subagent definitions
|
|
5802
|
-
commands/compound/ # Slash commands (spec-dev, plan, work, review, compound, cook-it)
|
|
5856
|
+
commands/compound/ # Slash commands (spec-dev, plan, work, review, compound, cook-it, agentic-audit, agentic-setup)
|
|
5803
5857
|
skills/compound/ # Phase skills + agent role skills
|
|
5804
5858
|
lessons/
|
|
5805
5859
|
index.jsonl # Memory items (git-tracked source of truth)
|
|
@@ -6160,6 +6214,22 @@ Skills are instructions that Claude reads before executing each phase. They live
|
|
|
6160
6214
|
|
|
6161
6215
|
**What it does**: Analyzes beads epics for knowledge gaps, checks existing docs coverage, proposes research topics for user confirmation, spawns parallel researcher subagents, and stores output at \`docs/compound/research/<topic>/<slug>.md\`.
|
|
6162
6216
|
|
|
6217
|
+
### \`/compound:agentic-audit\`
|
|
6218
|
+
|
|
6219
|
+
**Purpose**: Audit a codebase against the 15-principle Agentic Codebase Manifesto.
|
|
6220
|
+
|
|
6221
|
+
**When invoked**: When evaluating a codebase's readiness for AI agent collaboration.
|
|
6222
|
+
|
|
6223
|
+
**What it does**: Detects the project stack, scores all 15 principles (0-2) with specific evidence across 3 pillars (Codebase Memory, Implementation Feedbacks, Mapping the Context) plus cross-cutting concerns. Produces a scored report (out of 30) with prioritized actions and offers to create a beads epic for improvements.
|
|
6224
|
+
|
|
6225
|
+
### \`/compound:agentic-setup\`
|
|
6226
|
+
|
|
6227
|
+
**Purpose**: Set up a codebase for agentic AI development (runs audit first).
|
|
6228
|
+
|
|
6229
|
+
**When invoked**: When you want to improve a codebase's agentic readiness by filling gaps.
|
|
6230
|
+
|
|
6231
|
+
**What it does**: Runs the full audit first, then proposes concrete remediation actions for each gap found. Creates real content (AGENTS.md, docs/, ADRs, lint configs) generated from actual codebase analysis. Asks for user approval before each file creation.
|
|
6232
|
+
|
|
6163
6233
|
---
|
|
6164
6234
|
|
|
6165
6235
|
## Skill invocation
|
|
@@ -6176,7 +6246,10 @@ Skills are invoked as Claude Code slash commands:
|
|
|
6176
6246
|
/compound:research # Spawn research subagent
|
|
6177
6247
|
/compound:test-clean # Clean test artifacts
|
|
6178
6248
|
/compound:get-a-phd <focus> # Deep research for agent knowledge
|
|
6179
|
-
/compound:
|
|
6249
|
+
/compound:agentic-audit # Audit codebase against agentic manifesto
|
|
6250
|
+
/compound:agentic-setup # Audit then set up agentic infrastructure
|
|
6251
|
+
/compound:learn-that # Conversation-aware lesson capture with confirmation
|
|
6252
|
+
/compound:check-that # Search lessons and apply to current work
|
|
6180
6253
|
/compound:prime # Prime session with workflow context
|
|
6181
6254
|
\`\`\`
|
|
6182
6255
|
|
|
@@ -6330,6 +6403,12 @@ Work is not complete until \`git push\` succeeds.
|
|
|
6330
6403
|
};
|
|
6331
6404
|
|
|
6332
6405
|
// src/setup/templates/skills.ts
|
|
6406
|
+
var _bc = "\x1B[96m";
|
|
6407
|
+
var _cn = "\x1B[36m";
|
|
6408
|
+
var _gr = "\x1B[32m";
|
|
6409
|
+
var _mg = "\x1B[35m";
|
|
6410
|
+
var _yl = "\x1B[33m";
|
|
6411
|
+
var _rs = "\x1B[0m";
|
|
6333
6412
|
var PHASE_SKILLS = {
|
|
6334
6413
|
"spec-dev": `---
|
|
6335
6414
|
name: Spec Dev
|
|
@@ -6832,17 +6911,25 @@ Before starting EACH phase, you MUST use the Read tool to open its skill file:
|
|
|
6832
6911
|
Do NOT proceed from memory. Read the skill, then follow it exactly.
|
|
6833
6912
|
|
|
6834
6913
|
## Session Start
|
|
6835
|
-
When a cooking session begins, IMMEDIATELY print the
|
|
6836
|
-
|
|
6837
|
-
|
|
6838
|
-
|
|
6839
|
-
|
|
6840
|
-
|
|
6841
|
-
|
|
6842
|
-
|
|
6843
|
-
|
|
6844
|
-
|
|
6845
|
-
|
|
6914
|
+
When a cooking session begins, IMMEDIATELY print the brain banner below (copy it verbatim):
|
|
6915
|
+
|
|
6916
|
+
___ ___
|
|
6917
|
+
.."\`) "\`.." "(\`\`.
|
|
6918
|
+
.'; _..=. ${_bc}::${_rs} \`-'._ ;\`.
|
|
6919
|
+
: ) ;"\`':._. ${_bc}::${_rs}_. ( :.
|
|
6920
|
+
.:-" _. \`"${_cn}##${_rs}"\` "._ \`-:\\
|
|
6921
|
+
/." -"\` ._.${_bc}::${_rs}._. .'" ".:
|
|
6922
|
+
: : ( -: \`" ${_bc}::${_rs} "\` :- ) : )
|
|
6923
|
+
( .":==._ ' \`'=._${_cn}##${_rs}_.=' ' _.==: .'
|
|
6924
|
+
(: \`, \`"\` \`"${_cn}##${_rs}"\` \`"\` .'\`".)
|
|
6925
|
+
\\\`' \`"--. "- )( -" ..--"\` \`-/
|
|
6926
|
+
(" (_."\` ="""-..."\`...-""= "._) ")
|
|
6927
|
+
"..__..-" )${_gr}%${_rs}\`..'\`${_gr}%${_rs}( "-..__.."
|
|
6928
|
+
(#"...'\\\\${_gr}%%%%${_rs}/\`..."#)
|
|
6929
|
+
\`${_mg}######${_rs}\`--'${_mg}######${_rs}"
|
|
6930
|
+
"${_mg}###${_rs}")${_yl}@@${_rs}(\`${_mg}###${_rs}"
|
|
6931
|
+
\\${_yl}@@${_rs}/
|
|
6932
|
+
Claw'd
|
|
6846
6933
|
|
|
6847
6934
|
Then proceed with the protocol below.
|
|
6848
6935
|
|
|
@@ -6971,6 +7058,251 @@ Apply the agreed changes:
|
|
|
6971
7058
|
- Full test suite passes after changes
|
|
6972
7059
|
- Coverage not degraded
|
|
6973
7060
|
- Findings captured in compound-agent memory
|
|
7061
|
+
`,
|
|
7062
|
+
"agentic": `---
|
|
7063
|
+
name: Agentic Codebase
|
|
7064
|
+
description: Audit and set up a codebase for agentic AI development using the 15-principle manifesto
|
|
7065
|
+
---
|
|
7066
|
+
|
|
7067
|
+
# Agentic Codebase Skill
|
|
7068
|
+
|
|
7069
|
+
## Overview
|
|
7070
|
+
|
|
7071
|
+
Assess and improve a codebase's readiness for AI agent collaboration. Based on the 15-principle Agentic Codebase Manifesto organized across 3 pillars.
|
|
7072
|
+
|
|
7073
|
+
This skill operates in two modes:
|
|
7074
|
+
- **Mode: audit** -- Score the codebase against all 15 principles, produce a report with evidence and prioritized actions
|
|
7075
|
+
- **Mode: setup** -- Run audit first, then incrementally fill gaps with real content generated from codebase analysis
|
|
7076
|
+
|
|
7077
|
+
Mode is set by the calling command (\\\`/compound:agentic-audit\\\` or \\\`/compound:agentic-setup\\\`). The command wrapper tells you which mode to run -- do not parse \\\`$ARGUMENTS\\\` for mode detection.
|
|
7078
|
+
|
|
7079
|
+
## Stack Detection
|
|
7080
|
+
|
|
7081
|
+
Before auditing, detect the project stack to adapt checks:
|
|
7082
|
+
1. Look for package.json (Node/TS), pyproject.toml or setup.py (Python), Cargo.toml (Rust), go.mod (Go), Makefile, CMakeLists.txt (C/C++)
|
|
7083
|
+
2. Check for framework markers: next.config, django, fastapi, express, etc.
|
|
7084
|
+
3. Identify build/test/lint commands from config files
|
|
7085
|
+
4. Store detected stack for use in principle checks and AGENTS.md generation
|
|
7086
|
+
|
|
7087
|
+
## Audit Methodology
|
|
7088
|
+
|
|
7089
|
+
### Scoring Rubric
|
|
7090
|
+
Each principle is scored:
|
|
7091
|
+
- **0 (Absent)**: No evidence of this principle in the codebase
|
|
7092
|
+
- **1 (Partial)**: Some evidence but incomplete or inconsistent
|
|
7093
|
+
- **2 (Present)**: Clear, consistent implementation
|
|
7094
|
+
|
|
7095
|
+
Adapt criteria to the detected stack. For example: "strict mode" means TypeScript strict, Python mypy --strict, or Rust default safety. "Linter" means ESLint, pylint/ruff, clippy, golangci-lint, etc. Score based on the ecosystem's equivalent tooling.
|
|
7096
|
+
|
|
7097
|
+
### The 15 Principles
|
|
7098
|
+
|
|
7099
|
+
#### Pillar I: Codebase Memory (Traceability) -- max 8 points
|
|
7100
|
+
|
|
7101
|
+
**P1. Repository is the only truth**
|
|
7102
|
+
Check: All context an agent needs lives in version control
|
|
7103
|
+
Evidence: Look for docs/ directory, inline documentation, config files
|
|
7104
|
+
Score 0: No docs directory, no README beyond boilerplate
|
|
7105
|
+
Score 1: README exists but key context lives elsewhere
|
|
7106
|
+
Score 2: Comprehensive docs/, config, and context all in-repo
|
|
7107
|
+
|
|
7108
|
+
**P2. Trace decisions, not just outcomes**
|
|
7109
|
+
Check: Architectural decisions have recorded rationale
|
|
7110
|
+
Evidence: Look for docs/adr/, docs/decisions/, ADR files
|
|
7111
|
+
Score 0: No decision records
|
|
7112
|
+
Score 1: Some decisions documented but inconsistent format
|
|
7113
|
+
Score 2: ADR directory with structured records
|
|
7114
|
+
|
|
7115
|
+
**P3. Never answer the same question twice**
|
|
7116
|
+
Check: Solutions/fixes are documented to prevent rediscovery
|
|
7117
|
+
Evidence: Solutions docs, post-mortems, troubleshooting guides, or a memory system
|
|
7118
|
+
Score 0: No solutions documentation
|
|
7119
|
+
Score 1: Scattered notes but no systematic approach
|
|
7120
|
+
Score 2: Structured solutions docs or integrated memory system
|
|
7121
|
+
|
|
7122
|
+
**P4. Knowledge is infrastructure**
|
|
7123
|
+
Check: Documentation is versioned alongside code
|
|
7124
|
+
Evidence: Specs, research, standards co-located in repo
|
|
7125
|
+
Score 0: Documentation lives outside version control
|
|
7126
|
+
Score 1: Some docs in repo but key knowledge is external
|
|
7127
|
+
Score 2: All project knowledge versioned in docs/
|
|
7128
|
+
|
|
7129
|
+
#### Pillar II: Implementation Feedbacks (Mechanical Verification) -- max 8 points
|
|
7130
|
+
|
|
7131
|
+
**P5. Test is specification**
|
|
7132
|
+
Check: Tests define behavior before or alongside implementation
|
|
7133
|
+
Evidence: Test files, coverage tooling, test-first patterns
|
|
7134
|
+
Score 0: No tests or minimal coverage
|
|
7135
|
+
Score 1: Tests exist but post-hoc or inconsistent
|
|
7136
|
+
Score 2: Comprehensive test suite with test-driven patterns
|
|
7137
|
+
|
|
7138
|
+
**P6. Constraints are multipliers**
|
|
7139
|
+
Check: Linters, type checkers, architectural rules configured and enforced
|
|
7140
|
+
Evidence: ESLint/pylint/clippy config, TypeScript strict mode, CI enforcement
|
|
7141
|
+
Score 0: No linting or type checking
|
|
7142
|
+
Score 1: Linter exists but not enforced in CI
|
|
7143
|
+
Score 2: Strict linting + type checking enforced in CI
|
|
7144
|
+
|
|
7145
|
+
**P7. Write feedback for machines**
|
|
7146
|
+
Check: Error messages, logs, and output are structured for agent consumption
|
|
7147
|
+
Evidence: Structured logging, clear error messages with context
|
|
7148
|
+
Score 0: Unstructured logs, generic error messages
|
|
7149
|
+
Score 1: Some structured logging but inconsistent
|
|
7150
|
+
Score 2: Structured logging throughout, remediation hints in errors
|
|
7151
|
+
|
|
7152
|
+
**P8. Fight entropy continuously**
|
|
7153
|
+
Check: Active maintenance processes prevent drift
|
|
7154
|
+
Evidence: Automated formatting, dependency updates, quality monitoring
|
|
7155
|
+
Score 0: No automated maintenance
|
|
7156
|
+
Score 1: Basic formatting but no proactive monitoring
|
|
7157
|
+
Score 2: Automated formatting + dependency updates + quality tracking
|
|
7158
|
+
|
|
7159
|
+
#### Pillar III: Mapping the Context (Navigable Structure) -- max 8 points
|
|
7160
|
+
|
|
7161
|
+
**P9. Map, not manual**
|
|
7162
|
+
Check: Entry point document provides a navigable map, not an encyclopedia
|
|
7163
|
+
Evidence: AGENTS.md, CLAUDE.md, or similar
|
|
7164
|
+
Score 0: No agent-facing entry point document
|
|
7165
|
+
Score 1: README exists but not optimized for agents
|
|
7166
|
+
Score 2: Dedicated AGENTS.md or CLAUDE.md with commands, structure, conventions
|
|
7167
|
+
|
|
7168
|
+
**P10. Explicit over implicit, always**
|
|
7169
|
+
Check: Types, naming, patterns are explicit
|
|
7170
|
+
Evidence: Type annotations, consistent naming, documented conventions
|
|
7171
|
+
Score 0: No type annotations, inconsistent naming
|
|
7172
|
+
Score 1: Some types but gaps, or undocumented conventions
|
|
7173
|
+
Score 2: Full type coverage, documented naming conventions
|
|
7174
|
+
|
|
7175
|
+
**P11. Modularity is non-negotiable**
|
|
7176
|
+
Check: Single responsibility per file, clear boundaries
|
|
7177
|
+
Evidence: File sizes, module organization, dependency structure
|
|
7178
|
+
Score 0: Monolithic files (>500 LOC common), unclear boundaries
|
|
7179
|
+
Score 1: Some modular structure but large files remain
|
|
7180
|
+
Score 2: Consistent small files, clear APIs, enforced boundaries
|
|
7181
|
+
|
|
7182
|
+
**P12. Structure in layers, govern by inheritance**
|
|
7183
|
+
Check: Layered architecture with explicit dependency rules
|
|
7184
|
+
Evidence: Layer separation, import rules, dependency graph
|
|
7185
|
+
Score 0: No discernible layering
|
|
7186
|
+
Score 1: Informal layers but no enforcement
|
|
7187
|
+
Score 2: Explicit layers with enforced dependency directions
|
|
7188
|
+
|
|
7189
|
+
#### Cross-Cutting -- max 6 points
|
|
7190
|
+
|
|
7191
|
+
**P13. Simplicity compounds**
|
|
7192
|
+
Check: Prefer boring technologies, minimal abstractions
|
|
7193
|
+
Evidence: Dependency count, abstraction depth
|
|
7194
|
+
Score 0: Over-engineered with many abstractions
|
|
7195
|
+
Score 1: Moderate complexity, some unnecessary abstractions
|
|
7196
|
+
Score 2: Minimal dependencies, straightforward patterns
|
|
7197
|
+
|
|
7198
|
+
**P14. Human designs the system, not the output**
|
|
7199
|
+
Check: Human effort in system design (tests, docs, constraints)
|
|
7200
|
+
Evidence: Quality of test harnesses, documentation, CI/CD
|
|
7201
|
+
Score 0: No investment in development infrastructure
|
|
7202
|
+
Score 1: Some tooling but gaps in key areas
|
|
7203
|
+
Score 2: Strong CI, testing framework, documentation system
|
|
7204
|
+
|
|
7205
|
+
**P15. Parallelize by decomposition**
|
|
7206
|
+
Check: Work can be split into independent units
|
|
7207
|
+
Evidence: Module independence, clear interfaces, minimal coupling
|
|
7208
|
+
Score 0: Tightly coupled, hard to work on independently
|
|
7209
|
+
Score 1: Some independent modules but shared state
|
|
7210
|
+
Score 2: Well-decomposed with clear interfaces
|
|
7211
|
+
|
|
7212
|
+
### Audit Execution Steps
|
|
7213
|
+
|
|
7214
|
+
1. Run \\\`npx ca search "agentic codebase"\\\` for relevant lessons
|
|
7215
|
+
2. Detect project stack (see Stack Detection above)
|
|
7216
|
+
3. Use Glob and Grep to check for evidence of each principle:
|
|
7217
|
+
- Glob for: docs/**, *.test.*, .eslintrc*, AGENTS.md, CLAUDE.md
|
|
7218
|
+
- Grep for: type annotations, structured logging, ADR format
|
|
7219
|
+
- Read key files: README, config files, sample source files
|
|
7220
|
+
4. Score each principle (0-2) with specific evidence
|
|
7221
|
+
5. Aggregate scores by pillar and compute total out of 30
|
|
7222
|
+
6. Generate prioritized actions (score-0 first, then score-1)
|
|
7223
|
+
7. Present report to user
|
|
7224
|
+
|
|
7225
|
+
### Report Format
|
|
7226
|
+
|
|
7227
|
+
Present as markdown tables per pillar:
|
|
7228
|
+
|
|
7229
|
+
Pillar I: Codebase Memory -- X/8
|
|
7230
|
+
| # | Principle | Score | Evidence |
|
|
7231
|
+
|---|-----------|-------|----------|
|
|
7232
|
+
| P1 | Repository is the only truth | 0/1/2 | finding |
|
|
7233
|
+
...repeat for all pillars with separator rows...
|
|
7234
|
+
|
|
7235
|
+
**Overall Score: X/30**
|
|
7236
|
+
|
|
7237
|
+
### Priority Actions
|
|
7238
|
+
1. [Score-0 items first, most impactful]
|
|
7239
|
+
2. ...
|
|
7240
|
+
|
|
7241
|
+
After presenting, use \\\`AskUserQuestion\\\`: "Create a beads epic with issues for improvements?"
|
|
7242
|
+
If yes, create epic via bd create and individual issues.
|
|
7243
|
+
|
|
7244
|
+
## Setup Methodology
|
|
7245
|
+
|
|
7246
|
+
### Prerequisites
|
|
7247
|
+
Run the full audit first. Setup only addresses gaps found by the audit.
|
|
7248
|
+
|
|
7249
|
+
### Setup Execution Steps
|
|
7250
|
+
|
|
7251
|
+
1. Present audit findings summary
|
|
7252
|
+
2. For each principle scored 0 or 1, propose a concrete action:
|
|
7253
|
+
|
|
7254
|
+
**P1/P4 gaps**: Create docs/ skeleton (INDEX.md, adr/, standards/) with real content from analysis
|
|
7255
|
+
**P2 gaps**: Create ADR template and first ADR from actual architecture analysis
|
|
7256
|
+
**P3 gaps**: Suggest solutions documentation structure
|
|
7257
|
+
**P5 gaps**: Suggest test framework setup based on detected stack
|
|
7258
|
+
**P6 gaps**: Suggest linter/type checker configuration for detected stack
|
|
7259
|
+
**P7 gaps**: Suggest structured logging patterns for detected stack
|
|
7260
|
+
**P9 gaps**: Generate AGENTS.md by analyzing actual codebase (build commands, structure, conventions)
|
|
7261
|
+
**P10 gaps**: Suggest type annotation and strict mode settings
|
|
7262
|
+
**P11 gaps**: Identify files >500 LOC, suggest refactoring targets
|
|
7263
|
+
**P12 gaps**: Document layer structure and suggest import lint rules (e.g., eslint-plugin-import boundaries, Rust mod visibility)
|
|
7264
|
+
**P13 gaps**: Flag over-abstraction (deep inheritance, excessive wrappers), suggest simplification targets
|
|
7265
|
+
**P14 gaps**: Suggest CI pipeline improvements, test harness setup, or pre-commit hooks for detected stack
|
|
7266
|
+
**P15 gaps**: Identify tightly coupled modules, suggest interface extraction for parallel workability
|
|
7267
|
+
**P8 gaps**: Suggest automated formatting (prettier/black/rustfmt), dependency update tooling (renovate/dependabot), and quality monitoring
|
|
7268
|
+
|
|
7269
|
+
3. Before each action, use \\\`AskUserQuestion\\\`: "Create [file]? Preview: [content]"
|
|
7270
|
+
4. Only create/modify files the user approves
|
|
7271
|
+
5. Never overwrite existing files without explicit approval
|
|
7272
|
+
|
|
7273
|
+
### Setup Completion Gate
|
|
7274
|
+
After all approved actions are applied, verify:
|
|
7275
|
+
- List all files created/modified during setup
|
|
7276
|
+
- Run quality gates if available (\\\`pnpm test\\\`, \\\`pnpm lint\\\`, or stack equivalent)
|
|
7277
|
+
- Confirm no existing files were overwritten without approval
|
|
7278
|
+
- Present summary: principles addressed, files created, remaining gaps
|
|
7279
|
+
|
|
7280
|
+
## Memory Integration
|
|
7281
|
+
|
|
7282
|
+
- Before analysis: \\\`npx ca search "agentic codebase"\\\` for relevant lessons
|
|
7283
|
+
- After completing: offer \\\`npx ca learn\\\` to capture insights
|
|
7284
|
+
|
|
7285
|
+
## Common Pitfalls
|
|
7286
|
+
|
|
7287
|
+
- Scoring too generously without specific evidence for score 2
|
|
7288
|
+
- Generating template content instead of analyzing the actual codebase
|
|
7289
|
+
- Overwriting existing files without asking
|
|
7290
|
+
- Not detecting the project stack before generating content
|
|
7291
|
+
- Creating too many files at once instead of prioritizing
|
|
7292
|
+
- Forgetting to offer beads epic creation after audit
|
|
7293
|
+
|
|
7294
|
+
## Quality Criteria
|
|
7295
|
+
|
|
7296
|
+
- All 15 principles assessed with specific evidence
|
|
7297
|
+
- Scores justified with findings
|
|
7298
|
+
- Pillar totals and overall score calculated correctly
|
|
7299
|
+
- Actions prioritized (score-0 before score-1)
|
|
7300
|
+
- Stack detected and checks adapted accordingly
|
|
7301
|
+
- User consulted via AskUserQuestion at key decisions
|
|
7302
|
+
- Memory searched before analysis
|
|
7303
|
+
- Setup mode ran audit first
|
|
7304
|
+
- No files overwritten without approval
|
|
7305
|
+
- Generated content based on actual codebase analysis
|
|
6974
7306
|
`
|
|
6975
7307
|
};
|
|
6976
7308
|
var PHASE_SKILL_REFERENCES = {
|
|
@@ -7596,12 +7928,12 @@ function registerPhaseSubcommands(phaseCheck, getDryRun, repoRoot) {
|
|
|
7596
7928
|
console.log("Phase state cleaned.");
|
|
7597
7929
|
});
|
|
7598
7930
|
}
|
|
7599
|
-
function registerPhaseCheckCommand(
|
|
7600
|
-
const phaseCheck =
|
|
7931
|
+
function registerPhaseCheckCommand(program) {
|
|
7932
|
+
const phaseCheck = program.command("phase-check").description("Manage cook-it phase state").option("--dry-run", "Show what would be done without making changes");
|
|
7601
7933
|
const getDryRun = () => phaseCheck.opts().dryRun ?? false;
|
|
7602
7934
|
const repoRoot = () => getRepoRoot();
|
|
7603
7935
|
registerPhaseSubcommands(phaseCheck, getDryRun, repoRoot);
|
|
7604
|
-
|
|
7936
|
+
program.command("phase-clean").description("Remove phase state file (alias for `phase-check clean`)").action(() => {
|
|
7605
7937
|
cleanPhaseState(repoRoot());
|
|
7606
7938
|
console.log("Phase state cleaned.");
|
|
7607
7939
|
});
|
|
@@ -7884,8 +8216,8 @@ async function runStopAuditHook() {
|
|
|
7884
8216
|
console.log(JSON.stringify({}));
|
|
7885
8217
|
}
|
|
7886
8218
|
}
|
|
7887
|
-
function registerHooksCommand(
|
|
7888
|
-
const hooksCommand =
|
|
8219
|
+
function registerHooksCommand(program) {
|
|
8220
|
+
const hooksCommand = program.command("hooks").description("Git hooks management");
|
|
7889
8221
|
hooksCommand.command("run <hook>").description("Run a hook script (called by git/Claude hooks)").option("--json", "Output as JSON").action(async (hook, options) => {
|
|
7890
8222
|
if (hook === "pre-commit") {
|
|
7891
8223
|
if (options.json) {
|
|
@@ -8810,8 +9142,8 @@ function registerClaudeSubcommand(setupCommand) {
|
|
|
8810
9142
|
});
|
|
8811
9143
|
}
|
|
8812
9144
|
init_embeddings();
|
|
8813
|
-
function registerDownloadModelCommand(
|
|
8814
|
-
|
|
9145
|
+
function registerDownloadModelCommand(program) {
|
|
9146
|
+
program.command("download-model").description("Download the embedding model for semantic search").option("--json", "Output as JSON").action(async (options) => {
|
|
8815
9147
|
const alreadyExisted = isModelAvailable();
|
|
8816
9148
|
if (alreadyExisted) {
|
|
8817
9149
|
const modelPath2 = join(homedir(), ".node-llama-cpp", "models", MODEL_FILENAME);
|
|
@@ -8881,8 +9213,9 @@ async function handleModelAndEmbed(repoRoot, opts) {
|
|
|
8881
9213
|
} catch {
|
|
8882
9214
|
}
|
|
8883
9215
|
try {
|
|
9216
|
+
const { withEmbedding: withEmbedding2 } = await Promise.resolve().then(() => (init_embeddings(), embeddings_exports));
|
|
8884
9217
|
const { preWarmLessonEmbeddings: preWarmLessonEmbeddings2 } = await Promise.resolve().then(() => (init_prewarm(), prewarm_exports));
|
|
8885
|
-
await preWarmLessonEmbeddings2(repoRoot);
|
|
9218
|
+
await withEmbedding2(async () => preWarmLessonEmbeddings2(repoRoot));
|
|
8886
9219
|
} catch {
|
|
8887
9220
|
}
|
|
8888
9221
|
}
|
|
@@ -9015,8 +9348,8 @@ function printPnpmConfigStatus2(result) {
|
|
|
9015
9348
|
console.log(` pnpm config: Added onlyBuiltDependencies [${result.added.join(", ")}]`);
|
|
9016
9349
|
}
|
|
9017
9350
|
}
|
|
9018
|
-
function registerInitCommand(
|
|
9019
|
-
|
|
9351
|
+
function registerInitCommand(program) {
|
|
9352
|
+
program.command("init").description("Initialize compound-agent in this repository").option("--skip-agents", "Skip AGENTS.md modification").option("--skip-hooks", "Skip git hooks installation").option("--skip-claude", "Skip Claude Code hooks installation").option("--skip-model", "Skip embedding model download").option("--json", "Output result as JSON").option("--update", "Run upgrade logic on existing install").action(async function(options) {
|
|
9020
9353
|
await initAction(this, options);
|
|
9021
9354
|
});
|
|
9022
9355
|
}
|
|
@@ -9243,14 +9576,14 @@ async function deleteAction(ids, options) {
|
|
|
9243
9576
|
}
|
|
9244
9577
|
}
|
|
9245
9578
|
}
|
|
9246
|
-
function registerCrudCommands(
|
|
9247
|
-
|
|
9579
|
+
function registerCrudCommands(program) {
|
|
9580
|
+
program.command("show <id>").description("Show details of a specific lesson").option("--json", "Output as JSON").action(async (id, options) => {
|
|
9248
9581
|
await showAction(id, options);
|
|
9249
9582
|
});
|
|
9250
|
-
|
|
9583
|
+
program.command("update <id>").description("Update a lesson").option("--insight <text>", "Update insight").option("--trigger <text>", "Update trigger").option("--evidence <text>", "Update evidence").option("--severity <level>", "Update severity (low/medium/high)").option("--tags <tags>", "Update tags (comma-separated)").option("--confirmed <bool>", "Update confirmed status (true/false)").option("--json", "Output as JSON").action(async (id, options) => {
|
|
9251
9584
|
await updateAction(id, options);
|
|
9252
9585
|
});
|
|
9253
|
-
|
|
9586
|
+
program.command("delete <ids...>").description("Soft delete lessons (creates tombstone)").option("--json", "Output as JSON").action(async (ids, options) => {
|
|
9254
9587
|
await deleteAction(ids, options);
|
|
9255
9588
|
});
|
|
9256
9589
|
}
|
|
@@ -9356,8 +9689,8 @@ var STATUS_ICONS = {
|
|
|
9356
9689
|
fail: "FAIL",
|
|
9357
9690
|
warn: "WARN"
|
|
9358
9691
|
};
|
|
9359
|
-
function registerDoctorCommand(
|
|
9360
|
-
|
|
9692
|
+
function registerDoctorCommand(program) {
|
|
9693
|
+
program.command("doctor").description("Verify external dependencies and project health").action(async () => {
|
|
9361
9694
|
const repoRoot = getRepoRoot();
|
|
9362
9695
|
const checks = await runDoctor(repoRoot);
|
|
9363
9696
|
console.log("Compound Agent Health Check:\n");
|
|
@@ -9383,8 +9716,8 @@ function registerDoctorCommand(program2) {
|
|
|
9383
9716
|
|
|
9384
9717
|
// src/commands/management-invalidation.ts
|
|
9385
9718
|
init_storage();
|
|
9386
|
-
function registerInvalidationCommands(
|
|
9387
|
-
|
|
9719
|
+
function registerInvalidationCommands(program) {
|
|
9720
|
+
program.command("wrong <id>").description("Mark a lesson as invalid/wrong").option("-r, --reason <text>", "Reason for invalidation").action(async function(id, options) {
|
|
9388
9721
|
const repoRoot = getRepoRoot();
|
|
9389
9722
|
const { items } = await readMemoryItems(repoRoot);
|
|
9390
9723
|
const lesson = items.find((l) => l.id === id);
|
|
@@ -9408,7 +9741,7 @@ function registerInvalidationCommands(program2) {
|
|
|
9408
9741
|
console.log(` Reason: ${options.reason}`);
|
|
9409
9742
|
}
|
|
9410
9743
|
});
|
|
9411
|
-
|
|
9744
|
+
program.command("validate <id>").description("Re-enable a previously invalidated lesson").action(async function(id) {
|
|
9412
9745
|
const repoRoot = getRepoRoot();
|
|
9413
9746
|
const { items } = await readMemoryItems(repoRoot);
|
|
9414
9747
|
const lesson = items.find((l) => l.id === id);
|
|
@@ -9505,11 +9838,11 @@ async function importAction(file) {
|
|
|
9505
9838
|
console.log(`Imported ${imported} ${lessonWord}`);
|
|
9506
9839
|
}
|
|
9507
9840
|
}
|
|
9508
|
-
function registerIOCommands(
|
|
9509
|
-
|
|
9841
|
+
function registerIOCommands(program) {
|
|
9842
|
+
program.command("export").description("Export lessons as JSON to stdout").option("--since <date>", "Only include lessons created after this date (ISO8601)").option("--tags <tags>", "Filter by tags (comma-separated, OR logic)").action(async (options) => {
|
|
9510
9843
|
await exportAction(options);
|
|
9511
9844
|
});
|
|
9512
|
-
|
|
9845
|
+
program.command("import <file>").description("Import lessons from a JSONL file").action(async (file) => {
|
|
9513
9846
|
await importAction(file);
|
|
9514
9847
|
});
|
|
9515
9848
|
}
|
|
@@ -9609,14 +9942,14 @@ async function statsAction() {
|
|
|
9609
9942
|
console.log(`Retrievals: ${totalRetrievals} total, ${avgRetrievals} avg per lesson`);
|
|
9610
9943
|
console.log(`Storage: ${formatBytes(totalSize)} (index: ${formatBytes(indexSize)}, data: ${formatBytes(dataSize)})`);
|
|
9611
9944
|
}
|
|
9612
|
-
function registerMaintenanceCommands(
|
|
9613
|
-
|
|
9945
|
+
function registerMaintenanceCommands(program) {
|
|
9946
|
+
program.command("compact").description("Compact lessons: remove tombstones and invalid records").option("-f, --force", "Run compaction even if below threshold").option("--dry-run", "Show what would be done without making changes").action(async (options) => {
|
|
9614
9947
|
await compactAction(options);
|
|
9615
9948
|
});
|
|
9616
|
-
|
|
9949
|
+
program.command("rebuild").description("Rebuild SQLite index from JSONL").option("-f, --force", "Force rebuild even if unchanged").action(async (options) => {
|
|
9617
9950
|
await rebuildAction(options);
|
|
9618
9951
|
});
|
|
9619
|
-
|
|
9952
|
+
program.command("stats").description("Show database health and statistics").action(async () => {
|
|
9620
9953
|
await statsAction();
|
|
9621
9954
|
});
|
|
9622
9955
|
}
|
|
@@ -9736,8 +10069,8 @@ ${formattedLessons}
|
|
|
9736
10069
|
}
|
|
9737
10070
|
return output;
|
|
9738
10071
|
}
|
|
9739
|
-
function registerPrimeCommand(
|
|
9740
|
-
|
|
10072
|
+
function registerPrimeCommand(program) {
|
|
10073
|
+
program.command("prime").description("Output context for Claude Code (guidelines + top lessons)").action(async () => {
|
|
9741
10074
|
const output = await getPrimeContext();
|
|
9742
10075
|
console.log(output);
|
|
9743
10076
|
});
|
|
@@ -9748,8 +10081,8 @@ function formatFinding(finding) {
|
|
|
9748
10081
|
const filePart = finding.file ? ` ${finding.file}` : "";
|
|
9749
10082
|
return `${label} [${finding.source}]${filePart} -- ${finding.issue}`;
|
|
9750
10083
|
}
|
|
9751
|
-
function registerAuditCommands(
|
|
9752
|
-
|
|
10084
|
+
function registerAuditCommands(program) {
|
|
10085
|
+
program.command("audit").description("Run audit checks against the codebase").option("--json", "Output as JSON").option("--no-rules", "Skip rule checks").option("--no-patterns", "Skip pattern checks").option("--no-lessons", "Skip lesson checks").action(async function() {
|
|
9753
10086
|
const repoRoot = getRepoRoot();
|
|
9754
10087
|
const { quiet } = getGlobalOpts(this);
|
|
9755
10088
|
const opts = this.opts();
|
|
@@ -9845,8 +10178,8 @@ async function disableReviewer(repoRoot, name) {
|
|
|
9845
10178
|
}
|
|
9846
10179
|
|
|
9847
10180
|
// src/commands/reviewer.ts
|
|
9848
|
-
function registerReviewerCommand(
|
|
9849
|
-
const reviewer =
|
|
10181
|
+
function registerReviewerCommand(program) {
|
|
10182
|
+
const reviewer = program.command("reviewer").description("Manage external code reviewers (gemini, codex)");
|
|
9850
10183
|
reviewer.command("enable <name>").description(`Enable an external reviewer (${VALID_REVIEWERS.join(", ")})`).action(async (name) => {
|
|
9851
10184
|
const repoRoot = getRepoRoot();
|
|
9852
10185
|
try {
|
|
@@ -9895,8 +10228,8 @@ function registerReviewerCommand(program2) {
|
|
|
9895
10228
|
}
|
|
9896
10229
|
});
|
|
9897
10230
|
}
|
|
9898
|
-
function registerRulesCommands(
|
|
9899
|
-
const rulesCmd =
|
|
10231
|
+
function registerRulesCommands(program) {
|
|
10232
|
+
const rulesCmd = program.command("rules").description("Run repository-defined rule checks");
|
|
9900
10233
|
rulesCmd.command("check").description("Check codebase against rules in .claude/rules.json").action(function() {
|
|
9901
10234
|
const repoRoot = getRepoRoot();
|
|
9902
10235
|
const { quiet } = getGlobalOpts(this);
|
|
@@ -10007,8 +10340,8 @@ function formatTestSummary(summary, logPath) {
|
|
|
10007
10340
|
lines.push(`LOG: Full output at ${logPath}`);
|
|
10008
10341
|
return lines.join("\n");
|
|
10009
10342
|
}
|
|
10010
|
-
function registerTestSummaryCommand(
|
|
10011
|
-
|
|
10343
|
+
function registerTestSummaryCommand(program) {
|
|
10344
|
+
program.command("test-summary").description("Run tests and output a compact summary").option("--fast", "Run pnpm test:fast instead of pnpm test").option("--cmd <command>", "Custom test command to run").action((options) => {
|
|
10012
10345
|
const repoRoot = getRepoRoot();
|
|
10013
10346
|
let testCmd = "pnpm test";
|
|
10014
10347
|
if (options.cmd) {
|
|
@@ -10103,8 +10436,8 @@ var STATUS_LABEL = {
|
|
|
10103
10436
|
pass: "PASS",
|
|
10104
10437
|
fail: "FAIL"
|
|
10105
10438
|
};
|
|
10106
|
-
function registerVerifyGatesCommand(
|
|
10107
|
-
|
|
10439
|
+
function registerVerifyGatesCommand(program) {
|
|
10440
|
+
program.command("verify-gates <epic-id>").description("Verify workflow gates are satisfied before epic closure").action(async (epicId) => {
|
|
10108
10441
|
try {
|
|
10109
10442
|
const checks = await runVerifyGates(epicId, { repoRoot: getRepoRoot() });
|
|
10110
10443
|
console.log(`Gate checks for epic ${epicId}:
|
|
@@ -10134,100 +10467,38 @@ function registerVerifyGatesCommand(program2) {
|
|
|
10134
10467
|
}
|
|
10135
10468
|
|
|
10136
10469
|
// src/changelog-data.ts
|
|
10137
|
-
var CHANGELOG_RECENT = `## [1.6.
|
|
10470
|
+
var CHANGELOG_RECENT = `## [1.6.5] - 2026-03-07
|
|
10138
10471
|
|
|
10139
10472
|
### Fixed
|
|
10140
10473
|
|
|
10141
|
-
- **
|
|
10474
|
+
- **Loop script bash 3.2 syntax error**: macOS ships bash 3.2 which misparses \`case\` pattern \`)\` inside \`$(...)\` as closing the subshell. Added \`(\` prefix to case patterns for POSIX compliance. Added \`/bin/bash -n\` regression test.
|
|
10475
|
+
- **Loop script \`--verbose\` flag**: \`--output-format=stream-json\` with \`-p\` requires \`--verbose\`, not \`--include-partial-messages\`.
|
|
10142
10476
|
|
|
10143
|
-
## [1.6.
|
|
10144
|
-
|
|
10145
|
-
### Changed
|
|
10146
|
-
|
|
10147
|
-
- **Renamed brainstorm phase to spec-dev**: The \`/compound:brainstorm\` slash command is now \`/compound:spec-dev\`. The phase focuses on structured specification development using EARS notation, Mermaid diagrams, and Socratic dialogue rather than open-ended brainstorming. Old \`brainstorm.md\` command files are auto-cleaned during upgrade.
|
|
10148
|
-
- **Integration test stability**: Reduced integration test parallelism (\`maxForks: 1\`) and increased timeouts to 60s to eliminate non-deterministic ETIMEDOUT failures under load.
|
|
10149
|
-
|
|
10150
|
-
### Added
|
|
10151
|
-
|
|
10152
|
-
- **Spec reference file**: \`.claude/skills/compound/spec-dev/references/spec-guide.md\` provides quick-reference material for EARS patterns, Mermaid diagram selection, NL ambiguity detection, and trade-off documentation frameworks. Installed automatically during \`ca setup\`.
|
|
10153
|
-
- **Hook error visibility**: Hook runners now log errors to stderr when \`CA_DEBUG\` environment variable is set, instead of silently swallowing all failures.
|
|
10154
|
-
- **check-plan stdin safety**: \`ca check-plan\` now enforces a 30-second timeout and 1MB size limit when reading from stdin, preventing hangs in CI/CD environments.
|
|
10155
|
-
- **Embed lock expiry**: Embedding lock files now expire after 1 hour as a safety valve against zombie processes holding locks indefinitely.
|
|
10156
|
-
- **Phase-state backward compatibility**: Legacy \`lfg_active\` field in phase state files is automatically migrated to \`cookit_active\` on read.
|
|
10157
|
-
- **clean-lessons scope messaging**: \`ca clean-lessons\` now reports when non-lesson items are excluded from analysis.
|
|
10477
|
+
## [1.6.4] - 2026-03-07
|
|
10158
10478
|
|
|
10159
10479
|
### Fixed
|
|
10160
10480
|
|
|
10161
|
-
- **
|
|
10162
|
-
-
|
|
10163
|
-
-
|
|
10164
|
-
-
|
|
10165
|
-
-
|
|
10166
|
-
- **
|
|
10167
|
-
- **
|
|
10168
|
-
|
|
10169
|
-
|
|
10170
|
-
|
|
10171
|
-
|
|
10172
|
-
|
|
10173
|
-
- **\`ca watch\` command**: Live pretty-printer for infinity loop trace files. Tails \`agent_logs/trace_*.jsonl\` and formats stream-json events (tool calls, text deltas, token usage, epic markers) with colored output. Supports \`--epic <id>\` to watch a specific epic and \`--no-follow\` for one-shot reads.
|
|
10174
|
-
- **Stream-json micro logging**: Generated infinity loop scripts now use \`--output-format stream-json --include-partial-messages\` to capture structured JSONL event traces alongside the existing macro text log. Trace files written to \`agent_logs/trace_<epic>-<ts>.jsonl\` with \`.latest\` symlink for easy discovery.
|
|
10175
|
-
- **\`/compound:learn-that\` slash command**: Conversation-aware lesson capture with user confirmation before saving
|
|
10176
|
-
- **\`/compound:check-that\` slash command**: Search lessons and proactively apply them to current work
|
|
10177
|
-
- **Eager knowledge embedding**: Knowledge chunks from \`docs/\` are now embedded for semantic search when the model is available
|
|
10178
|
-
- \`ca index-docs --embed\` embeds chunks after indexing
|
|
10179
|
-
- \`ca init\` now downloads the embedding model (with \`--skip-model\` opt-out) and installs the post-commit hook
|
|
10180
|
-
- Background embedding spawns after \`ca init\`/\`ca setup\` so users can start working immediately
|
|
10181
|
-
- PID-based lock file prevents concurrent embedding processes
|
|
10182
|
-
- Status file (\`embed-status.json\`) tracks background embedding progress
|
|
10183
|
-
- **New modules**: \`embed-chunks.ts\`, \`embed-lock.ts\`, \`embed-status.ts\`, \`embed-background.ts\` with full test coverage
|
|
10184
|
-
|
|
10185
|
-
### Removed
|
|
10186
|
-
|
|
10187
|
-
- **\`/compound:learn\` slash command**: Replaced by \`/compound:learn-that\` with conversation-aware capture and user confirmation
|
|
10188
|
-
- **\`ca worktree\` command family**: All five subcommands (\`create\`, \`merge\`, \`list\`, \`cleanup\`, \`wire-deps\`) removed. Claude Code now provides native \`EnterWorktree\` support. Running \`ca worktree\` prints a deprecation notice.
|
|
10189
|
-
- **\`/compound:set-worktree\` slash command**: Use Claude Code's native worktree workflow instead.
|
|
10190
|
-
- **Conditional Merge gate in \`verify-gates\`**: Only Review and Compound gates remain.
|
|
10191
|
-
- **\`shortId\` utility**: Dead code after worktree removal, cleaned up.
|
|
10192
|
-
|
|
10193
|
-
### Changed
|
|
10481
|
+
- **Embedding memory leak**: Every \`npx ca search\` spawned a process that loaded the ~150MB native embedding model. Without explicit cleanup, native threads kept processes alive as zombies. During heavy usage (Claude Code subagents), 32+ processes accumulated = 4.5GB leaked.
|
|
10482
|
+
- \`withEmbedding(fn)\` scoped wrapper guarantees cleanup via try/finally. All 9 command-layer consumers migrated from manual try/finally to this single API.
|
|
10483
|
+
- ESLint rule \`require-embedding-cleanup\` catches any file importing \`embedText\`/\`getEmbedding\` without a cleanup function. Scoped to \`src/commands/\` and \`src/setup/\`.
|
|
10484
|
+
- \`cli-app.ts\` backstop: top-level finally in \`runProgram()\` catches anything the above two miss.
|
|
10485
|
+
- **\`embedText\` probe inside \`withEmbedding\` scope**: \`clean-lessons\` command was calling \`embedText\` outside of \`withEmbedding\`, leaking the model on every invocation.
|
|
10486
|
+
- **Agentic skill report format**: Markdown table was missing \`|---|\` separator row, rendering as plain text in some renderers.
|
|
10487
|
+
- **Agentic skill missing setup remediation**: 5 of 15 principles (P8, P12-P15) had no setup actions. Added concrete remediation guidance for each.
|
|
10488
|
+
- **Agentic skill missing completion gate**: Other skills have phase gates; the agentic skill was missing one. Added Setup Completion Gate with verification steps.
|
|
10489
|
+
- **Agentic skill stack-biased scoring**: Rubric was TypeScript-heavy. Added language-neutral scoring guidance (mypy, clippy, ruff equivalents).
|
|
10490
|
+
- **Agentic skill \`$ARGUMENTS\` dead code**: Mode is set by the calling command (\`/compound:agentic-audit\` or \`/compound:agentic-setup\`), not parsed from \`$ARGUMENTS\`.
|
|
10491
|
+
- **Docs template missing agentic commands**: \`SKILLS.md\` template now lists \`agentic-audit\` and \`agentic-setup\` in the command inventory.
|
|
10194
10492
|
|
|
10195
|
-
|
|
10196
|
-
- **\`ca setup --update\` now cleans deprecated paths**: Automatically removes stale worktree skill/command files from \`.claude/\` and \`.gemini/\` directories.
|
|
10197
|
-
- **\`ca setup\` also cleans deprecated paths**: Fresh setup runs now remove stale files from prior versions.
|
|
10198
|
-
- **SKILLS.md template**: Command inventory now lists all 11 slash commands (was 7).
|
|
10493
|
+
## [1.6.3] - 2026-03-05
|
|
10199
10494
|
|
|
10200
|
-
###
|
|
10495
|
+
### Changed
|
|
10201
10496
|
|
|
10202
|
-
- **
|
|
10203
|
-
- **P0**: Background worker spawn now resolves \`dist/cli.js\` deterministically instead of relying on \`npx ca\` (which failed silently in dev/built contexts)
|
|
10204
|
-
- **P0**: \`embed-worker\` command hidden from \`ca --help\` output
|
|
10205
|
-
- **P1**: Stale lock recovery uses atomic delete-then-\`wx\` to prevent two processes both reclaiming
|
|
10206
|
-
- **P1**: DB connection opened after lock acquisition to prevent leak on contention
|
|
10207
|
-
- **P1**: \`--embed\` now throws when model unavailable (was silently returning 0)
|
|
10208
|
-
- **P2**: Batch embedding (16 chunks per call) with per-batch SQLite transactions (was 1 fsync per row)
|
|
10209
|
-
- **P2**: \`EmbedStatus\` rewritten as discriminated union; removed dead \`chunksTotal\` field
|
|
10210
|
-
- **P2**: \`readLock\` validates JSON shape instead of blind \`as\` cast
|
|
10211
|
-
- **P2**: Vector batch length assertion guards against short responses from embedding backend
|
|
10212
|
-
- **P3**: Extracted \`indexAndSpawnEmbed()\` shared helper \u2014 \`init.ts\` and \`all.ts\` no longer duplicate logic
|
|
10213
|
-
- **P3**: \`ca setup\` now prints feedback when background embedding spawns
|
|
10214
|
-
- **P3**: \`filesErrored\` count shown in \`ca index-docs\` output
|
|
10215
|
-
- **P3**: Barrel re-exports consolidated through \`./memory/knowledge/index.js\`
|
|
10216
|
-
- **\`EPIC_ID_PATTERN\` duplication**: \`loop.ts\` now uses distinctly named \`LOOP_EPIC_ID_PATTERN\` to avoid confusion with the canonical pattern in \`cli-utils.ts\`.
|
|
10217
|
-
- **Stale worktree lesson invalidated**: Memory item \`Ld204372e\` marked invalid to prevent irrelevant context injection.
|
|
10218
|
-
|
|
10219
|
-
### Performance
|
|
10220
|
-
|
|
10221
|
-
- **Eliminate double model initialization**: \`ca search\` now uses \`isModelAvailable()\` (fs.existsSync, zero cost) instead of \`isModelUsable()\` which loaded the 278MB native model just to probe availability, then loaded it again for actual embedding
|
|
10222
|
-
- **Bulk-read cached embeddings**: \`getCachedEmbeddingsBulk()\` replaces N individual \`getCachedEmbedding()\` SQLite queries with a single bulk read
|
|
10223
|
-
- **Eliminate redundant JSONL parsing**: \`searchVector()\` and \`findSimilarLessons()\` now use \`readAllFromSqlite()\` after \`syncIfNeeded()\` instead of re-parsing the JSONL file
|
|
10224
|
-
- **Float32Array consistency**: Lesson embedding path now keeps \`Float32Array\` from node-llama-cpp instead of converting via \`Array.from()\` (4x memory savings per vector)
|
|
10225
|
-
- **Pre-warm lesson embedding cache**: \`ca init\` now pre-computes embeddings for all lessons with missing or stale cache entries, eliminating cold-start latency on first search
|
|
10226
|
-
- **Graceful embedding fallback**: \`ca search\` falls back to keyword-only search on runtime embedding failures instead of crashing`;
|
|
10497
|
+
- **Cook-it session banner**: Replaced "Claude the Cooker" chef ASCII art with rscr's detailed front-view brain ASCII art ("Claw'd"). Brain features ANSI-colored augmentation zones: cyan neural interface (\`##\`), bright cyan signal crosslinks (\`::\`), green bio-circuits (\`%\`), magenta data highways (\`######\`), and yellow power nodes (\`@@\`).`;
|
|
10227
10498
|
|
|
10228
10499
|
// src/commands/about.ts
|
|
10229
|
-
function registerAboutCommand(
|
|
10230
|
-
|
|
10500
|
+
function registerAboutCommand(program) {
|
|
10501
|
+
program.command("about").description("Show version, animation, and recent changelog").action(async () => {
|
|
10231
10502
|
if (process.stdout.isTTY) {
|
|
10232
10503
|
await playInstallBanner();
|
|
10233
10504
|
} else {
|
|
@@ -10239,22 +10510,23 @@ function registerAboutCommand(program2) {
|
|
|
10239
10510
|
}
|
|
10240
10511
|
|
|
10241
10512
|
// src/commands/knowledge.ts
|
|
10513
|
+
init_embeddings();
|
|
10242
10514
|
init_sqlite_knowledge();
|
|
10243
10515
|
var MAX_DISPLAY_TEXT = 200;
|
|
10244
|
-
function registerKnowledgeCommand(
|
|
10245
|
-
|
|
10516
|
+
function registerKnowledgeCommand(program) {
|
|
10517
|
+
program.command("knowledge <query>").description("Search docs knowledge base").option("-n, --limit <number>", "Maximum results", "6").action(async function(query, opts) {
|
|
10246
10518
|
const globalOpts = getGlobalOpts(this);
|
|
10519
|
+
let limit;
|
|
10520
|
+
try {
|
|
10521
|
+
limit = parseLimit(opts.limit, "limit");
|
|
10522
|
+
} catch (err) {
|
|
10523
|
+
const message = err instanceof Error ? err.message : "Invalid limit";
|
|
10524
|
+
console.error(formatError("knowledge", "INVALID_LIMIT", message, "Use -n with a positive integer"));
|
|
10525
|
+
process.exitCode = 1;
|
|
10526
|
+
return;
|
|
10527
|
+
}
|
|
10528
|
+
const repoRoot = getRepoRoot();
|
|
10247
10529
|
try {
|
|
10248
|
-
let limit;
|
|
10249
|
-
try {
|
|
10250
|
-
limit = parseLimit(opts.limit, "limit");
|
|
10251
|
-
} catch (err) {
|
|
10252
|
-
const message = err instanceof Error ? err.message : "Invalid limit";
|
|
10253
|
-
console.error(formatError("knowledge", "INVALID_LIMIT", message, "Use -n with a positive integer"));
|
|
10254
|
-
process.exitCode = 1;
|
|
10255
|
-
return;
|
|
10256
|
-
}
|
|
10257
|
-
const repoRoot = getRepoRoot();
|
|
10258
10530
|
openKnowledgeDb(repoRoot);
|
|
10259
10531
|
if (getChunkCount(repoRoot) === 0) {
|
|
10260
10532
|
try {
|
|
@@ -10270,7 +10542,7 @@ function registerKnowledgeCommand(program2) {
|
|
|
10270
10542
|
out.info(`Auto-index failed (${msg}). Run manually: npx ca index-docs`);
|
|
10271
10543
|
}
|
|
10272
10544
|
}
|
|
10273
|
-
const results = await searchKnowledge(repoRoot, query, { limit });
|
|
10545
|
+
const results = await withEmbedding(async () => searchKnowledge(repoRoot, query, { limit }));
|
|
10274
10546
|
if (results.length === 0) {
|
|
10275
10547
|
out.info("No matching results found.");
|
|
10276
10548
|
return;
|
|
@@ -10298,15 +10570,15 @@ function registerKnowledgeCommand(program2) {
|
|
|
10298
10570
|
// src/commands/knowledge-index.ts
|
|
10299
10571
|
init_embeddings();
|
|
10300
10572
|
init_sqlite_knowledge();
|
|
10301
|
-
function registerKnowledgeIndexCommand(
|
|
10302
|
-
|
|
10573
|
+
function registerKnowledgeIndexCommand(program) {
|
|
10574
|
+
program.command("index-docs").description("Index docs/ directory into knowledge base").option("--force", "Re-index all files (ignore cache)").option("--embed", "Embed chunks for semantic search").action(async function(options) {
|
|
10303
10575
|
const repoRoot = getRepoRoot();
|
|
10304
10576
|
out.info("Indexing docs/ directory...");
|
|
10305
10577
|
try {
|
|
10306
|
-
const result = await indexDocs(repoRoot, {
|
|
10578
|
+
const result = await withEmbedding(async () => indexDocs(repoRoot, {
|
|
10307
10579
|
force: options.force,
|
|
10308
10580
|
embed: options.embed
|
|
10309
|
-
});
|
|
10581
|
+
}));
|
|
10310
10582
|
const skippedPart = result.filesSkipped > 0 ? ` (${result.filesSkipped} skipped)` : "";
|
|
10311
10583
|
const deletedPart = result.chunksDeleted > 0 ? `, ${result.chunksDeleted} deleted` : "";
|
|
10312
10584
|
const duration = (result.durationMs / 1e3).toFixed(1);
|
|
@@ -10321,11 +10593,10 @@ function registerKnowledgeIndexCommand(program2) {
|
|
|
10321
10593
|
}
|
|
10322
10594
|
out.info(`Duration: ${duration}s`);
|
|
10323
10595
|
} finally {
|
|
10324
|
-
unloadEmbedding();
|
|
10325
10596
|
closeKnowledgeDb();
|
|
10326
10597
|
}
|
|
10327
10598
|
});
|
|
10328
|
-
|
|
10599
|
+
program.command("embed-worker <repoRoot>", { hidden: true }).description("Internal: background embedding worker").action(async (repoRoot) => {
|
|
10329
10600
|
const { runBackgroundEmbed: runBackgroundEmbed2 } = await Promise.resolve().then(() => (init_embed_background(), embed_background_exports));
|
|
10330
10601
|
await runBackgroundEmbed2(repoRoot);
|
|
10331
10602
|
});
|
|
@@ -10392,22 +10663,21 @@ async function cleanLessonsAction() {
|
|
|
10392
10663
|
process.exitCode = 1;
|
|
10393
10664
|
return;
|
|
10394
10665
|
}
|
|
10395
|
-
|
|
10396
|
-
|
|
10397
|
-
|
|
10398
|
-
|
|
10399
|
-
|
|
10400
|
-
|
|
10401
|
-
|
|
10402
|
-
|
|
10403
|
-
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
try {
|
|
10666
|
+
await withEmbedding(async () => {
|
|
10667
|
+
try {
|
|
10668
|
+
await embedText("test");
|
|
10669
|
+
} catch (e) {
|
|
10670
|
+
console.error(
|
|
10671
|
+
formatError(
|
|
10672
|
+
"clean-lessons",
|
|
10673
|
+
"MODEL_UNUSABLE",
|
|
10674
|
+
`Embedding model failed to initialize: ${e instanceof Error ? e.message : String(e)}`,
|
|
10675
|
+
"Check model compatibility"
|
|
10676
|
+
)
|
|
10677
|
+
);
|
|
10678
|
+
process.exitCode = 1;
|
|
10679
|
+
return;
|
|
10680
|
+
}
|
|
10411
10681
|
await syncIfNeeded(repoRoot);
|
|
10412
10682
|
const { items } = await readMemoryItems(repoRoot);
|
|
10413
10683
|
const activeItems = items.filter((item) => !item.invalidatedAt && item.type === "lesson");
|
|
@@ -10420,12 +10690,10 @@ async function cleanLessonsAction() {
|
|
|
10420
10690
|
return;
|
|
10421
10691
|
}
|
|
10422
10692
|
printReport(pairs);
|
|
10423
|
-
}
|
|
10424
|
-
unloadEmbedding();
|
|
10425
|
-
}
|
|
10693
|
+
});
|
|
10426
10694
|
}
|
|
10427
|
-
function registerCleanLessonsCommand(
|
|
10428
|
-
|
|
10695
|
+
function registerCleanLessonsCommand(program) {
|
|
10696
|
+
program.command("clean-lessons").description("Analyze lessons for semantic duplicates and contradictions").action(cleanLessonsAction);
|
|
10429
10697
|
}
|
|
10430
10698
|
|
|
10431
10699
|
// src/commands/capture.ts
|
|
@@ -10552,9 +10820,9 @@ async function checkSimilarityPostCapture(repoRoot, item) {
|
|
|
10552
10820
|
if (!isModelAvailable2()) return;
|
|
10553
10821
|
const { syncIfNeeded: syncIfNeeded2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
10554
10822
|
const { findSimilarLessons: findSimilarLessons2 } = await Promise.resolve().then(() => (init_vector(), vector_exports));
|
|
10555
|
-
const { embedText: embedText2,
|
|
10823
|
+
const { embedText: embedText2, withEmbedding: withEmbedding2 } = await Promise.resolve().then(() => (init_nomic(), nomic_exports));
|
|
10556
10824
|
const chalk6 = await import('chalk');
|
|
10557
|
-
|
|
10825
|
+
await withEmbedding2(async () => {
|
|
10558
10826
|
await embedText2("test");
|
|
10559
10827
|
await syncIfNeeded2(repoRoot);
|
|
10560
10828
|
const similar = await findSimilarLessons2(repoRoot, item.insight, { excludeId: item.id });
|
|
@@ -10567,9 +10835,7 @@ async function checkSimilarityPostCapture(repoRoot, item) {
|
|
|
10567
10835
|
console.log("");
|
|
10568
10836
|
console.log(`Run ${chalk6.default.bold("'npx ca clean-lessons'")} to review and resolve.`);
|
|
10569
10837
|
}
|
|
10570
|
-
}
|
|
10571
|
-
unloadEmbedding2();
|
|
10572
|
-
}
|
|
10838
|
+
});
|
|
10573
10839
|
} catch (err) {
|
|
10574
10840
|
if (process.env["CA_DEBUG"]) {
|
|
10575
10841
|
process.stderr.write(`[CA_DEBUG] checkSimilarityPostCapture catch: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -10697,17 +10963,18 @@ async function handleCapture(cmd, options) {
|
|
|
10697
10963
|
outputCapturePreview(lesson);
|
|
10698
10964
|
}
|
|
10699
10965
|
}
|
|
10700
|
-
function registerCaptureCommands(
|
|
10701
|
-
|
|
10966
|
+
function registerCaptureCommands(program) {
|
|
10967
|
+
program.command("learn <insight>").description("Capture a new memory item (lesson, solution, pattern, or preference)").option("-t, --trigger <text>", "What triggered this lesson").option("--tags <tags>", "Comma-separated tags", "").option("-s, --severity <level>", "Lesson severity: high, medium, low").option("-y, --yes", "Skip confirmation").option("--citation <file:line>", "Source file (optionally with :line number)").option("--citation-commit <hash>", "Git commit hash for citation").option("--type <type>", "Memory item type: lesson, solution, pattern, preference", "lesson").option("--pattern-bad <code>", "Bad pattern example (required when --type pattern)").option("--pattern-good <code>", "Good pattern example (required when --type pattern)").action(async function(insight, options) {
|
|
10702
10968
|
await handleLearn(this, insight, options);
|
|
10703
10969
|
});
|
|
10704
|
-
|
|
10970
|
+
program.command("detect").description("Detect learning triggers from input").requiredOption("--input <file>", "Path to JSON input file").option("--save", "Save proposed lesson (requires --yes)").option("-y, --yes", "Confirm save (required with --save)").option("--json", "Output result as JSON").action(async (options) => {
|
|
10705
10971
|
await handleDetect(options);
|
|
10706
10972
|
});
|
|
10707
|
-
|
|
10973
|
+
program.command("capture").description("Capture a lesson from trigger/insight or input file").option("-t, --trigger <text>", "What triggered this lesson").option("-i, --insight <text>", "The insight or lesson learned").option("--input <file>", "Path to JSON input file (alternative to trigger/insight)").option("--json", "Output result as JSON").option("-y, --yes", "Skip confirmation and save immediately").action(async function(options) {
|
|
10708
10974
|
await handleCapture(this, options);
|
|
10709
10975
|
});
|
|
10710
10976
|
}
|
|
10977
|
+
init_embeddings();
|
|
10711
10978
|
init_storage();
|
|
10712
10979
|
init_search2();
|
|
10713
10980
|
function parseLimitOrNull(rawLimit, optionName, commandName) {
|
|
@@ -10803,23 +11070,23 @@ async function searchAction(cmd, query, options) {
|
|
|
10803
11070
|
}
|
|
10804
11071
|
const { verbose, quiet } = getGlobalOpts(cmd);
|
|
10805
11072
|
await syncIfNeeded(repoRoot);
|
|
10806
|
-
|
|
10807
|
-
|
|
10808
|
-
|
|
10809
|
-
|
|
10810
|
-
|
|
10811
|
-
|
|
10812
|
-
|
|
10813
|
-
|
|
10814
|
-
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
11073
|
+
const results = await withEmbedding(async () => {
|
|
11074
|
+
if (isModelAvailable()) {
|
|
11075
|
+
try {
|
|
11076
|
+
const candidateLimit = limit * CANDIDATE_MULTIPLIER;
|
|
11077
|
+
const [vectorResults, keywordResults] = await Promise.all([
|
|
11078
|
+
searchVector(repoRoot, query, { limit: candidateLimit }),
|
|
11079
|
+
searchKeywordScored(repoRoot, query, candidateLimit)
|
|
11080
|
+
]);
|
|
11081
|
+
const merged = mergeHybridResults(vectorResults, keywordResults, { minScore: MIN_HYBRID_SCORE });
|
|
11082
|
+
const ranked = rankLessons(merged);
|
|
11083
|
+
return ranked.slice(0, limit).map((r) => r.lesson);
|
|
11084
|
+
} catch {
|
|
11085
|
+
return await searchKeyword(repoRoot, query, limit);
|
|
11086
|
+
}
|
|
10819
11087
|
}
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
}
|
|
11088
|
+
return await searchKeyword(repoRoot, query, limit);
|
|
11089
|
+
});
|
|
10823
11090
|
if (results.length > 0) {
|
|
10824
11091
|
incrementRetrievalCount(repoRoot, results.map((lesson) => lesson.id));
|
|
10825
11092
|
}
|
|
@@ -10953,7 +11220,7 @@ async function checkPlanAction(cmd, options) {
|
|
|
10953
11220
|
return;
|
|
10954
11221
|
}
|
|
10955
11222
|
try {
|
|
10956
|
-
const result = await retrieveForPlan(repoRoot, planText, limit);
|
|
11223
|
+
const result = await withEmbedding(async () => retrieveForPlan(repoRoot, planText, limit));
|
|
10957
11224
|
if (options.json) {
|
|
10958
11225
|
outputCheckPlanJson(result.lessons);
|
|
10959
11226
|
return;
|
|
@@ -10977,48 +11244,48 @@ async function checkPlanAction(cmd, options) {
|
|
|
10977
11244
|
process.exitCode = 1;
|
|
10978
11245
|
}
|
|
10979
11246
|
}
|
|
10980
|
-
function registerRetrievalCommands(
|
|
10981
|
-
|
|
11247
|
+
function registerRetrievalCommands(program) {
|
|
11248
|
+
program.command("search <query>").description("Search lessons").option("-n, --limit <number>", "Maximum results", DEFAULT_SEARCH_LIMIT).action(async function(query, options) {
|
|
10982
11249
|
await searchAction(this, query, options);
|
|
10983
11250
|
});
|
|
10984
|
-
|
|
11251
|
+
program.command("list").description("List all lessons").option("-n, --limit <number>", "Maximum results", DEFAULT_LIST_LIMIT).option("--invalidated", "Show only invalidated lessons").action(async function(options) {
|
|
10985
11252
|
await listAction(this, options);
|
|
10986
11253
|
});
|
|
10987
|
-
|
|
11254
|
+
program.command("load-session").description("Load high-severity lessons for session context").option("--json", "Output as JSON").action(async function(options) {
|
|
10988
11255
|
await loadSessionAction(this, options);
|
|
10989
11256
|
});
|
|
10990
|
-
|
|
11257
|
+
program.command("check-plan").description("Check plan against relevant lessons").option("--plan <text>", "Plan text to check").option("--json", "Output as JSON").option("-n, --limit <number>", "Maximum results", DEFAULT_CHECK_PLAN_LIMIT).action(async function(options) {
|
|
10991
11258
|
await checkPlanAction(this, options);
|
|
10992
11259
|
});
|
|
10993
11260
|
}
|
|
10994
11261
|
|
|
10995
11262
|
// src/commands/index.ts
|
|
10996
|
-
function registerSetupCommands(
|
|
10997
|
-
registerInitCommand(
|
|
10998
|
-
registerHooksCommand(
|
|
10999
|
-
const setupCommand =
|
|
11263
|
+
function registerSetupCommands(program) {
|
|
11264
|
+
registerInitCommand(program);
|
|
11265
|
+
registerHooksCommand(program);
|
|
11266
|
+
const setupCommand = program.command("setup");
|
|
11000
11267
|
registerSetupAllCommand(setupCommand);
|
|
11001
11268
|
registerClaudeSubcommand(setupCommand);
|
|
11002
11269
|
registerGeminiSubcommand(setupCommand);
|
|
11003
|
-
registerDownloadModelCommand(
|
|
11004
|
-
}
|
|
11005
|
-
function registerManagementCommands(
|
|
11006
|
-
registerInvalidationCommands(
|
|
11007
|
-
registerMaintenanceCommands(
|
|
11008
|
-
registerIOCommands(
|
|
11009
|
-
registerPrimeCommand(
|
|
11010
|
-
registerCrudCommands(
|
|
11011
|
-
registerAuditCommands(
|
|
11012
|
-
registerDoctorCommand(
|
|
11013
|
-
registerReviewerCommand(
|
|
11014
|
-
registerRulesCommands(
|
|
11015
|
-
registerTestSummaryCommand(
|
|
11016
|
-
registerVerifyGatesCommand(
|
|
11017
|
-
registerAboutCommand(
|
|
11018
|
-
registerKnowledgeCommand(
|
|
11019
|
-
registerKnowledgeIndexCommand(
|
|
11020
|
-
registerCleanLessonsCommand(
|
|
11021
|
-
|
|
11270
|
+
registerDownloadModelCommand(program);
|
|
11271
|
+
}
|
|
11272
|
+
function registerManagementCommands(program) {
|
|
11273
|
+
registerInvalidationCommands(program);
|
|
11274
|
+
registerMaintenanceCommands(program);
|
|
11275
|
+
registerIOCommands(program);
|
|
11276
|
+
registerPrimeCommand(program);
|
|
11277
|
+
registerCrudCommands(program);
|
|
11278
|
+
registerAuditCommands(program);
|
|
11279
|
+
registerDoctorCommand(program);
|
|
11280
|
+
registerReviewerCommand(program);
|
|
11281
|
+
registerRulesCommands(program);
|
|
11282
|
+
registerTestSummaryCommand(program);
|
|
11283
|
+
registerVerifyGatesCommand(program);
|
|
11284
|
+
registerAboutCommand(program);
|
|
11285
|
+
registerKnowledgeCommand(program);
|
|
11286
|
+
registerKnowledgeIndexCommand(program);
|
|
11287
|
+
registerCleanLessonsCommand(program);
|
|
11288
|
+
program.command("worktree").description("(removed) Use Claude Code native worktree support").action(() => {
|
|
11022
11289
|
console.error("ca worktree has been removed. Use Claude Code's native EnterWorktree support instead.");
|
|
11023
11290
|
process.exitCode = 1;
|
|
11024
11291
|
});
|
|
@@ -11094,7 +11361,7 @@ get_next_epic() {
|
|
|
11094
11361
|
if [ -n "$EPIC_IDS" ]; then
|
|
11095
11362
|
# From explicit list, find first still-open epic not yet processed
|
|
11096
11363
|
for epic_id in $EPIC_IDS; do
|
|
11097
|
-
case " $PROCESSED " in *" $epic_id "*) continue ;; esac
|
|
11364
|
+
case " $PROCESSED " in (*" $epic_id "*) continue ;; esac
|
|
11098
11365
|
local status
|
|
11099
11366
|
status=$(bd show "$epic_id" --json 2>/dev/null | parse_json '.status' 2>/dev/null || echo "")
|
|
11100
11367
|
if [ "$status" = "open" ]; then
|
|
@@ -11108,7 +11375,7 @@ get_next_epic() {
|
|
|
11108
11375
|
local epic_id
|
|
11109
11376
|
if [ "$HAS_JQ" = true ]; then
|
|
11110
11377
|
epic_id=$(bd list --type=epic --ready --json --limit=10 2>/dev/null | jq -r '.[].id' 2>/dev/null | while read -r id; do
|
|
11111
|
-
case " $PROCESSED " in *" $id "*) continue ;; esac
|
|
11378
|
+
case " $PROCESSED " in (*" $id "*) continue ;; esac
|
|
11112
11379
|
echo "$id"
|
|
11113
11380
|
break
|
|
11114
11381
|
done)
|
|
@@ -11265,7 +11532,7 @@ while true; do
|
|
|
11265
11532
|
claude --dangerously-skip-permissions \\
|
|
11266
11533
|
--model "$MODEL" \\
|
|
11267
11534
|
--output-format stream-json \\
|
|
11268
|
-
--
|
|
11535
|
+
--verbose \\
|
|
11269
11536
|
-p "$PROMPT" \\
|
|
11270
11537
|
2>"$LOGFILE.stderr" | tee "$TRACEFILE" | extract_text > "$LOGFILE" || true
|
|
11271
11538
|
|
|
@@ -11367,8 +11634,8 @@ async function handleLoop(cmd, options) {
|
|
|
11367
11634
|
out.info("Run it with: " + outputPath);
|
|
11368
11635
|
out.info("Preview with: LOOP_DRY_RUN=1 " + outputPath);
|
|
11369
11636
|
}
|
|
11370
|
-
function registerLoopCommands(
|
|
11371
|
-
|
|
11637
|
+
function registerLoopCommands(program) {
|
|
11638
|
+
program.command("loop").description("Generate infinity loop script for epic tasks").option("--epics <ids...>", "Specific epic IDs to process").option("-o, --output <path>", "Output script path", "./infinity-loop.sh").option("--max-retries <n>", "Max retries per epic on failure", "1").option("--model <model>", "Claude model to use", "claude-opus-4-6").option("--force", "Overwrite existing script").action(async function(options) {
|
|
11372
11639
|
await handleLoop(this, options);
|
|
11373
11640
|
});
|
|
11374
11641
|
}
|
|
@@ -11475,15 +11742,15 @@ async function tailFile(filePath, follow) {
|
|
|
11475
11742
|
const child = spawn("tail", ["-f", "-n", "+1", filePath], { stdio: ["ignore", "pipe", "ignore"] });
|
|
11476
11743
|
const rl2 = createInterface({ input: child.stdout });
|
|
11477
11744
|
rl2.on("line", processLine);
|
|
11478
|
-
const
|
|
11745
|
+
const cleanup = () => {
|
|
11479
11746
|
child.kill("SIGTERM");
|
|
11480
11747
|
};
|
|
11481
|
-
process.on("SIGINT",
|
|
11482
|
-
process.on("SIGTERM",
|
|
11748
|
+
process.on("SIGINT", cleanup);
|
|
11749
|
+
process.on("SIGTERM", cleanup);
|
|
11483
11750
|
return new Promise((done) => {
|
|
11484
11751
|
child.on("close", () => {
|
|
11485
|
-
process.off("SIGINT",
|
|
11486
|
-
process.off("SIGTERM",
|
|
11752
|
+
process.off("SIGINT", cleanup);
|
|
11753
|
+
process.off("SIGTERM", cleanup);
|
|
11487
11754
|
done();
|
|
11488
11755
|
});
|
|
11489
11756
|
});
|
|
@@ -11538,8 +11805,8 @@ async function handleWatch(cmd, options) {
|
|
|
11538
11805
|
out.info(`Watching: ${traceFile}`);
|
|
11539
11806
|
await tailFile(traceFile, follow);
|
|
11540
11807
|
}
|
|
11541
|
-
function registerWatchCommand(
|
|
11542
|
-
|
|
11808
|
+
function registerWatchCommand(program) {
|
|
11809
|
+
program.command("watch").description("Tail and pretty-print live trace from infinity loop sessions").option("--epic <id>", "Watch a specific epic trace").option("--no-follow", "Print existing trace and exit (no live tail)").action(async function(options) {
|
|
11543
11810
|
await handleWatch(this, options);
|
|
11544
11811
|
});
|
|
11545
11812
|
}
|
|
@@ -11587,7 +11854,8 @@ function commandNeedsSqlite(cmd) {
|
|
|
11587
11854
|
return false;
|
|
11588
11855
|
}
|
|
11589
11856
|
|
|
11590
|
-
// src/cli.ts
|
|
11857
|
+
// src/cli-app.ts
|
|
11858
|
+
init_embeddings();
|
|
11591
11859
|
init_storage();
|
|
11592
11860
|
function detectPackageManager(cwd) {
|
|
11593
11861
|
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
@@ -11651,46 +11919,62 @@ function printBuildToolsHint() {
|
|
|
11651
11919
|
}
|
|
11652
11920
|
}
|
|
11653
11921
|
|
|
11654
|
-
// src/cli.ts
|
|
11655
|
-
function
|
|
11922
|
+
// src/cli-app.ts
|
|
11923
|
+
async function cleanupCliResources() {
|
|
11924
|
+
try {
|
|
11925
|
+
await unloadEmbeddingResources();
|
|
11926
|
+
} catch {
|
|
11927
|
+
}
|
|
11656
11928
|
try {
|
|
11657
11929
|
closeDb();
|
|
11658
11930
|
} catch {
|
|
11659
11931
|
}
|
|
11660
11932
|
}
|
|
11661
|
-
|
|
11662
|
-
|
|
11663
|
-
|
|
11664
|
-
}
|
|
11665
|
-
process.on("
|
|
11666
|
-
|
|
11667
|
-
|
|
11668
|
-
|
|
11669
|
-
|
|
11670
|
-
program.option("-v, --verbose", "Show detailed output").option("-q, --quiet", "Suppress non-essential output");
|
|
11671
|
-
program.name("ca").description("Semantically-intelligent workflow plugin for Claude Code").version(VERSION);
|
|
11672
|
-
registerCaptureCommands(program);
|
|
11673
|
-
registerRetrievalCommands(program);
|
|
11674
|
-
registerManagementCommands(program);
|
|
11675
|
-
registerSetupCommands(program);
|
|
11676
|
-
registerCompoundCommands(program);
|
|
11677
|
-
registerLoopCommands(program);
|
|
11678
|
-
registerWatchCommand(program);
|
|
11679
|
-
registerPhaseCheckCommand(program);
|
|
11680
|
-
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
11681
|
-
|
|
11682
|
-
try {
|
|
11683
|
-
ensureSqliteAvailable();
|
|
11684
|
-
} catch (err) {
|
|
11685
|
-
let root;
|
|
11933
|
+
function attachSignalHandlers() {
|
|
11934
|
+
const handleSignal = (exitCode) => {
|
|
11935
|
+
void cleanupCliResources().finally(() => process.exit(exitCode));
|
|
11936
|
+
};
|
|
11937
|
+
process.on("SIGINT", () => handleSignal(0));
|
|
11938
|
+
process.on("SIGTERM", () => handleSignal(0));
|
|
11939
|
+
}
|
|
11940
|
+
function createProgram() {
|
|
11941
|
+
const program = new Command();
|
|
11942
|
+
program.option("-v, --verbose", "Show detailed output").option("-q, --quiet", "Suppress non-essential output");
|
|
11943
|
+
program.name("ca").description("Semantically-intelligent workflow plugin for Claude Code").version(VERSION);
|
|
11944
|
+
registerCaptureCommands(program);
|
|
11945
|
+
registerRetrievalCommands(program);
|
|
11946
|
+
registerManagementCommands(program);
|
|
11947
|
+
registerSetupCommands(program);
|
|
11948
|
+
registerCompoundCommands(program);
|
|
11949
|
+
registerLoopCommands(program);
|
|
11950
|
+
registerWatchCommand(program);
|
|
11951
|
+
registerPhaseCheckCommand(program);
|
|
11952
|
+
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
11953
|
+
if (!commandNeedsSqlite(actionCommand)) return;
|
|
11686
11954
|
try {
|
|
11687
|
-
|
|
11688
|
-
} catch {
|
|
11955
|
+
ensureSqliteAvailable();
|
|
11956
|
+
} catch (err) {
|
|
11957
|
+
let root;
|
|
11958
|
+
try {
|
|
11959
|
+
root = getRepoRoot();
|
|
11960
|
+
} catch {
|
|
11961
|
+
}
|
|
11962
|
+
printNativeBuildDiagnostic(err, root);
|
|
11963
|
+
process.exit(1);
|
|
11689
11964
|
}
|
|
11690
|
-
|
|
11691
|
-
|
|
11965
|
+
});
|
|
11966
|
+
return program;
|
|
11967
|
+
}
|
|
11968
|
+
async function runProgram(program, argv = process.argv) {
|
|
11969
|
+
try {
|
|
11970
|
+
await program.parseAsync(argv);
|
|
11971
|
+
} finally {
|
|
11972
|
+
await cleanupCliResources();
|
|
11692
11973
|
}
|
|
11693
|
-
}
|
|
11694
|
-
|
|
11974
|
+
}
|
|
11975
|
+
|
|
11976
|
+
// src/cli.ts
|
|
11977
|
+
attachSignalHandlers();
|
|
11978
|
+
await runProgram(createProgram());
|
|
11695
11979
|
//# sourceMappingURL=cli.js.map
|
|
11696
11980
|
//# sourceMappingURL=cli.js.map
|