compound-agent 1.6.1 → 1.6.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/CHANGELOG.md +34 -1
- package/README.md +10 -0
- package/dist/cli.js +589 -315
- 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/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
|
|
@@ -6819,16 +6898,6 @@ description: Full-cycle orchestrator chaining all five phases with gates and con
|
|
|
6819
6898
|
|
|
6820
6899
|
## Overview
|
|
6821
6900
|
|
|
6822
|
-
\`\`\`
|
|
6823
|
-
|
|
6824
|
-
\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510
|
|
6825
|
-
\u2502\u2592\u2592\u2592\u2592\u2592\u2502
|
|
6826
|
-
\u2590\u259B\u2588\u2588\u2588\u259C\u258C o
|
|
6827
|
-
\u259D\u259C\u2588\u2588\u2588\u2588\u2588\u259B\u2598|
|
|
6828
|
-
\u2598\u2598 \u259D\u259D
|
|
6829
|
-
Let's cook!
|
|
6830
|
-
\`\`\`
|
|
6831
|
-
|
|
6832
6901
|
Chain all 5 phases end-to-end: Spec Dev, Plan, Work, Review, Compound. This skill governs the orchestration -- phase sequencing, gates, progress tracking, and error recovery.
|
|
6833
6902
|
|
|
6834
6903
|
## CRITICAL RULE -- READ BEFORE EXECUTE
|
|
@@ -6841,6 +6910,29 @@ Before starting EACH phase, you MUST use the Read tool to open its skill file:
|
|
|
6841
6910
|
|
|
6842
6911
|
Do NOT proceed from memory. Read the skill, then follow it exactly.
|
|
6843
6912
|
|
|
6913
|
+
## Session Start
|
|
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
|
|
6933
|
+
|
|
6934
|
+
Then proceed with the protocol below.
|
|
6935
|
+
|
|
6844
6936
|
## Phase Execution Protocol
|
|
6845
6937
|
0. Initialize state: \`npx ca phase-check init <epic-id>\`
|
|
6846
6938
|
For each phase:
|
|
@@ -6966,6 +7058,251 @@ Apply the agreed changes:
|
|
|
6966
7058
|
- Full test suite passes after changes
|
|
6967
7059
|
- Coverage not degraded
|
|
6968
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
|
|
6969
7306
|
`
|
|
6970
7307
|
};
|
|
6971
7308
|
var PHASE_SKILL_REFERENCES = {
|
|
@@ -7591,12 +7928,12 @@ function registerPhaseSubcommands(phaseCheck, getDryRun, repoRoot) {
|
|
|
7591
7928
|
console.log("Phase state cleaned.");
|
|
7592
7929
|
});
|
|
7593
7930
|
}
|
|
7594
|
-
function registerPhaseCheckCommand(
|
|
7595
|
-
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");
|
|
7596
7933
|
const getDryRun = () => phaseCheck.opts().dryRun ?? false;
|
|
7597
7934
|
const repoRoot = () => getRepoRoot();
|
|
7598
7935
|
registerPhaseSubcommands(phaseCheck, getDryRun, repoRoot);
|
|
7599
|
-
|
|
7936
|
+
program.command("phase-clean").description("Remove phase state file (alias for `phase-check clean`)").action(() => {
|
|
7600
7937
|
cleanPhaseState(repoRoot());
|
|
7601
7938
|
console.log("Phase state cleaned.");
|
|
7602
7939
|
});
|
|
@@ -7879,8 +8216,8 @@ async function runStopAuditHook() {
|
|
|
7879
8216
|
console.log(JSON.stringify({}));
|
|
7880
8217
|
}
|
|
7881
8218
|
}
|
|
7882
|
-
function registerHooksCommand(
|
|
7883
|
-
const hooksCommand =
|
|
8219
|
+
function registerHooksCommand(program) {
|
|
8220
|
+
const hooksCommand = program.command("hooks").description("Git hooks management");
|
|
7884
8221
|
hooksCommand.command("run <hook>").description("Run a hook script (called by git/Claude hooks)").option("--json", "Output as JSON").action(async (hook, options) => {
|
|
7885
8222
|
if (hook === "pre-commit") {
|
|
7886
8223
|
if (options.json) {
|
|
@@ -8805,8 +9142,8 @@ function registerClaudeSubcommand(setupCommand) {
|
|
|
8805
9142
|
});
|
|
8806
9143
|
}
|
|
8807
9144
|
init_embeddings();
|
|
8808
|
-
function registerDownloadModelCommand(
|
|
8809
|
-
|
|
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) => {
|
|
8810
9147
|
const alreadyExisted = isModelAvailable();
|
|
8811
9148
|
if (alreadyExisted) {
|
|
8812
9149
|
const modelPath2 = join(homedir(), ".node-llama-cpp", "models", MODEL_FILENAME);
|
|
@@ -8876,8 +9213,9 @@ async function handleModelAndEmbed(repoRoot, opts) {
|
|
|
8876
9213
|
} catch {
|
|
8877
9214
|
}
|
|
8878
9215
|
try {
|
|
9216
|
+
const { withEmbedding: withEmbedding2 } = await Promise.resolve().then(() => (init_embeddings(), embeddings_exports));
|
|
8879
9217
|
const { preWarmLessonEmbeddings: preWarmLessonEmbeddings2 } = await Promise.resolve().then(() => (init_prewarm(), prewarm_exports));
|
|
8880
|
-
await preWarmLessonEmbeddings2(repoRoot);
|
|
9218
|
+
await withEmbedding2(async () => preWarmLessonEmbeddings2(repoRoot));
|
|
8881
9219
|
} catch {
|
|
8882
9220
|
}
|
|
8883
9221
|
}
|
|
@@ -9010,8 +9348,8 @@ function printPnpmConfigStatus2(result) {
|
|
|
9010
9348
|
console.log(` pnpm config: Added onlyBuiltDependencies [${result.added.join(", ")}]`);
|
|
9011
9349
|
}
|
|
9012
9350
|
}
|
|
9013
|
-
function registerInitCommand(
|
|
9014
|
-
|
|
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) {
|
|
9015
9353
|
await initAction(this, options);
|
|
9016
9354
|
});
|
|
9017
9355
|
}
|
|
@@ -9238,14 +9576,14 @@ async function deleteAction(ids, options) {
|
|
|
9238
9576
|
}
|
|
9239
9577
|
}
|
|
9240
9578
|
}
|
|
9241
|
-
function registerCrudCommands(
|
|
9242
|
-
|
|
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) => {
|
|
9243
9581
|
await showAction(id, options);
|
|
9244
9582
|
});
|
|
9245
|
-
|
|
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) => {
|
|
9246
9584
|
await updateAction(id, options);
|
|
9247
9585
|
});
|
|
9248
|
-
|
|
9586
|
+
program.command("delete <ids...>").description("Soft delete lessons (creates tombstone)").option("--json", "Output as JSON").action(async (ids, options) => {
|
|
9249
9587
|
await deleteAction(ids, options);
|
|
9250
9588
|
});
|
|
9251
9589
|
}
|
|
@@ -9351,8 +9689,8 @@ var STATUS_ICONS = {
|
|
|
9351
9689
|
fail: "FAIL",
|
|
9352
9690
|
warn: "WARN"
|
|
9353
9691
|
};
|
|
9354
|
-
function registerDoctorCommand(
|
|
9355
|
-
|
|
9692
|
+
function registerDoctorCommand(program) {
|
|
9693
|
+
program.command("doctor").description("Verify external dependencies and project health").action(async () => {
|
|
9356
9694
|
const repoRoot = getRepoRoot();
|
|
9357
9695
|
const checks = await runDoctor(repoRoot);
|
|
9358
9696
|
console.log("Compound Agent Health Check:\n");
|
|
@@ -9378,8 +9716,8 @@ function registerDoctorCommand(program2) {
|
|
|
9378
9716
|
|
|
9379
9717
|
// src/commands/management-invalidation.ts
|
|
9380
9718
|
init_storage();
|
|
9381
|
-
function registerInvalidationCommands(
|
|
9382
|
-
|
|
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) {
|
|
9383
9721
|
const repoRoot = getRepoRoot();
|
|
9384
9722
|
const { items } = await readMemoryItems(repoRoot);
|
|
9385
9723
|
const lesson = items.find((l) => l.id === id);
|
|
@@ -9403,7 +9741,7 @@ function registerInvalidationCommands(program2) {
|
|
|
9403
9741
|
console.log(` Reason: ${options.reason}`);
|
|
9404
9742
|
}
|
|
9405
9743
|
});
|
|
9406
|
-
|
|
9744
|
+
program.command("validate <id>").description("Re-enable a previously invalidated lesson").action(async function(id) {
|
|
9407
9745
|
const repoRoot = getRepoRoot();
|
|
9408
9746
|
const { items } = await readMemoryItems(repoRoot);
|
|
9409
9747
|
const lesson = items.find((l) => l.id === id);
|
|
@@ -9500,11 +9838,11 @@ async function importAction(file) {
|
|
|
9500
9838
|
console.log(`Imported ${imported} ${lessonWord}`);
|
|
9501
9839
|
}
|
|
9502
9840
|
}
|
|
9503
|
-
function registerIOCommands(
|
|
9504
|
-
|
|
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) => {
|
|
9505
9843
|
await exportAction(options);
|
|
9506
9844
|
});
|
|
9507
|
-
|
|
9845
|
+
program.command("import <file>").description("Import lessons from a JSONL file").action(async (file) => {
|
|
9508
9846
|
await importAction(file);
|
|
9509
9847
|
});
|
|
9510
9848
|
}
|
|
@@ -9604,14 +9942,14 @@ async function statsAction() {
|
|
|
9604
9942
|
console.log(`Retrievals: ${totalRetrievals} total, ${avgRetrievals} avg per lesson`);
|
|
9605
9943
|
console.log(`Storage: ${formatBytes(totalSize)} (index: ${formatBytes(indexSize)}, data: ${formatBytes(dataSize)})`);
|
|
9606
9944
|
}
|
|
9607
|
-
function registerMaintenanceCommands(
|
|
9608
|
-
|
|
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) => {
|
|
9609
9947
|
await compactAction(options);
|
|
9610
9948
|
});
|
|
9611
|
-
|
|
9949
|
+
program.command("rebuild").description("Rebuild SQLite index from JSONL").option("-f, --force", "Force rebuild even if unchanged").action(async (options) => {
|
|
9612
9950
|
await rebuildAction(options);
|
|
9613
9951
|
});
|
|
9614
|
-
|
|
9952
|
+
program.command("stats").description("Show database health and statistics").action(async () => {
|
|
9615
9953
|
await statsAction();
|
|
9616
9954
|
});
|
|
9617
9955
|
}
|
|
@@ -9731,8 +10069,8 @@ ${formattedLessons}
|
|
|
9731
10069
|
}
|
|
9732
10070
|
return output;
|
|
9733
10071
|
}
|
|
9734
|
-
function registerPrimeCommand(
|
|
9735
|
-
|
|
10072
|
+
function registerPrimeCommand(program) {
|
|
10073
|
+
program.command("prime").description("Output context for Claude Code (guidelines + top lessons)").action(async () => {
|
|
9736
10074
|
const output = await getPrimeContext();
|
|
9737
10075
|
console.log(output);
|
|
9738
10076
|
});
|
|
@@ -9743,8 +10081,8 @@ function formatFinding(finding) {
|
|
|
9743
10081
|
const filePart = finding.file ? ` ${finding.file}` : "";
|
|
9744
10082
|
return `${label} [${finding.source}]${filePart} -- ${finding.issue}`;
|
|
9745
10083
|
}
|
|
9746
|
-
function registerAuditCommands(
|
|
9747
|
-
|
|
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() {
|
|
9748
10086
|
const repoRoot = getRepoRoot();
|
|
9749
10087
|
const { quiet } = getGlobalOpts(this);
|
|
9750
10088
|
const opts = this.opts();
|
|
@@ -9840,8 +10178,8 @@ async function disableReviewer(repoRoot, name) {
|
|
|
9840
10178
|
}
|
|
9841
10179
|
|
|
9842
10180
|
// src/commands/reviewer.ts
|
|
9843
|
-
function registerReviewerCommand(
|
|
9844
|
-
const reviewer =
|
|
10181
|
+
function registerReviewerCommand(program) {
|
|
10182
|
+
const reviewer = program.command("reviewer").description("Manage external code reviewers (gemini, codex)");
|
|
9845
10183
|
reviewer.command("enable <name>").description(`Enable an external reviewer (${VALID_REVIEWERS.join(", ")})`).action(async (name) => {
|
|
9846
10184
|
const repoRoot = getRepoRoot();
|
|
9847
10185
|
try {
|
|
@@ -9890,8 +10228,8 @@ function registerReviewerCommand(program2) {
|
|
|
9890
10228
|
}
|
|
9891
10229
|
});
|
|
9892
10230
|
}
|
|
9893
|
-
function registerRulesCommands(
|
|
9894
|
-
const rulesCmd =
|
|
10231
|
+
function registerRulesCommands(program) {
|
|
10232
|
+
const rulesCmd = program.command("rules").description("Run repository-defined rule checks");
|
|
9895
10233
|
rulesCmd.command("check").description("Check codebase against rules in .claude/rules.json").action(function() {
|
|
9896
10234
|
const repoRoot = getRepoRoot();
|
|
9897
10235
|
const { quiet } = getGlobalOpts(this);
|
|
@@ -10002,8 +10340,8 @@ function formatTestSummary(summary, logPath) {
|
|
|
10002
10340
|
lines.push(`LOG: Full output at ${logPath}`);
|
|
10003
10341
|
return lines.join("\n");
|
|
10004
10342
|
}
|
|
10005
|
-
function registerTestSummaryCommand(
|
|
10006
|
-
|
|
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) => {
|
|
10007
10345
|
const repoRoot = getRepoRoot();
|
|
10008
10346
|
let testCmd = "pnpm test";
|
|
10009
10347
|
if (options.cmd) {
|
|
@@ -10098,8 +10436,8 @@ var STATUS_LABEL = {
|
|
|
10098
10436
|
pass: "PASS",
|
|
10099
10437
|
fail: "FAIL"
|
|
10100
10438
|
};
|
|
10101
|
-
function registerVerifyGatesCommand(
|
|
10102
|
-
|
|
10439
|
+
function registerVerifyGatesCommand(program) {
|
|
10440
|
+
program.command("verify-gates <epic-id>").description("Verify workflow gates are satisfied before epic closure").action(async (epicId) => {
|
|
10103
10441
|
try {
|
|
10104
10442
|
const checks = await runVerifyGates(epicId, { repoRoot: getRepoRoot() });
|
|
10105
10443
|
console.log(`Gate checks for epic ${epicId}:
|
|
@@ -10129,114 +10467,37 @@ function registerVerifyGatesCommand(program2) {
|
|
|
10129
10467
|
}
|
|
10130
10468
|
|
|
10131
10469
|
// src/changelog-data.ts
|
|
10132
|
-
var CHANGELOG_RECENT = `## [1.6.
|
|
10133
|
-
|
|
10134
|
-
### Changed
|
|
10135
|
-
|
|
10136
|
-
- **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.
|
|
10137
|
-
- **Integration test stability**: Reduced integration test parallelism (\`maxForks: 1\`) and increased timeouts to 60s to eliminate non-deterministic ETIMEDOUT failures under load.
|
|
10138
|
-
|
|
10139
|
-
### Added
|
|
10140
|
-
|
|
10141
|
-
- **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\`.
|
|
10142
|
-
- **Hook error visibility**: Hook runners now log errors to stderr when \`CA_DEBUG\` environment variable is set, instead of silently swallowing all failures.
|
|
10143
|
-
- **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.
|
|
10144
|
-
- **Embed lock expiry**: Embedding lock files now expire after 1 hour as a safety valve against zombie processes holding locks indefinitely.
|
|
10145
|
-
- **Phase-state backward compatibility**: Legacy \`lfg_active\` field in phase state files is automatically migrated to \`cookit_active\` on read.
|
|
10146
|
-
- **clean-lessons scope messaging**: \`ca clean-lessons\` now reports when non-lesson items are excluded from analysis.
|
|
10470
|
+
var CHANGELOG_RECENT = `## [1.6.4] - 2026-03-07
|
|
10147
10471
|
|
|
10148
10472
|
### Fixed
|
|
10149
10473
|
|
|
10150
|
-
- **
|
|
10151
|
-
-
|
|
10152
|
-
-
|
|
10153
|
-
-
|
|
10154
|
-
-
|
|
10155
|
-
- **
|
|
10156
|
-
- **
|
|
10157
|
-
|
|
10158
|
-
|
|
10159
|
-
|
|
10160
|
-
|
|
10161
|
-
|
|
10162
|
-
- **\`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.
|
|
10163
|
-
- **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.
|
|
10164
|
-
- **\`/compound:learn-that\` slash command**: Conversation-aware lesson capture with user confirmation before saving
|
|
10165
|
-
- **\`/compound:check-that\` slash command**: Search lessons and proactively apply them to current work
|
|
10166
|
-
- **Eager knowledge embedding**: Knowledge chunks from \`docs/\` are now embedded for semantic search when the model is available
|
|
10167
|
-
- \`ca index-docs --embed\` embeds chunks after indexing
|
|
10168
|
-
- \`ca init\` now downloads the embedding model (with \`--skip-model\` opt-out) and installs the post-commit hook
|
|
10169
|
-
- Background embedding spawns after \`ca init\`/\`ca setup\` so users can start working immediately
|
|
10170
|
-
- PID-based lock file prevents concurrent embedding processes
|
|
10171
|
-
- Status file (\`embed-status.json\`) tracks background embedding progress
|
|
10172
|
-
- **New modules**: \`embed-chunks.ts\`, \`embed-lock.ts\`, \`embed-status.ts\`, \`embed-background.ts\` with full test coverage
|
|
10173
|
-
|
|
10174
|
-
### Removed
|
|
10175
|
-
|
|
10176
|
-
- **\`/compound:learn\` slash command**: Replaced by \`/compound:learn-that\` with conversation-aware capture and user confirmation
|
|
10177
|
-
- **\`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.
|
|
10178
|
-
- **\`/compound:set-worktree\` slash command**: Use Claude Code's native worktree workflow instead.
|
|
10179
|
-
- **Conditional Merge gate in \`verify-gates\`**: Only Review and Compound gates remain.
|
|
10180
|
-
- **\`shortId\` utility**: Dead code after worktree removal, cleaned up.
|
|
10474
|
+
- **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.
|
|
10475
|
+
- \`withEmbedding(fn)\` scoped wrapper guarantees cleanup via try/finally. All 9 command-layer consumers migrated from manual try/finally to this single API.
|
|
10476
|
+
- ESLint rule \`require-embedding-cleanup\` catches any file importing \`embedText\`/\`getEmbedding\` without a cleanup function. Scoped to \`src/commands/\` and \`src/setup/\`.
|
|
10477
|
+
- \`cli-app.ts\` backstop: top-level finally in \`runProgram()\` catches anything the above two miss.
|
|
10478
|
+
- **\`embedText\` probe inside \`withEmbedding\` scope**: \`clean-lessons\` command was calling \`embedText\` outside of \`withEmbedding\`, leaking the model on every invocation.
|
|
10479
|
+
- **Agentic skill report format**: Markdown table was missing \`|---|\` separator row, rendering as plain text in some renderers.
|
|
10480
|
+
- **Agentic skill missing setup remediation**: 5 of 15 principles (P8, P12-P15) had no setup actions. Added concrete remediation guidance for each.
|
|
10481
|
+
- **Agentic skill missing completion gate**: Other skills have phase gates; the agentic skill was missing one. Added Setup Completion Gate with verification steps.
|
|
10482
|
+
- **Agentic skill stack-biased scoring**: Rubric was TypeScript-heavy. Added language-neutral scoring guidance (mypy, clippy, ruff equivalents).
|
|
10483
|
+
- **Agentic skill \`$ARGUMENTS\` dead code**: Mode is set by the calling command (\`/compound:agentic-audit\` or \`/compound:agentic-setup\`), not parsed from \`$ARGUMENTS\`.
|
|
10484
|
+
- **Docs template missing agentic commands**: \`SKILLS.md\` template now lists \`agentic-audit\` and \`agentic-setup\` in the command inventory.
|
|
10181
10485
|
|
|
10182
|
-
|
|
10486
|
+
## [1.6.3] - 2026-03-05
|
|
10183
10487
|
|
|
10184
|
-
|
|
10185
|
-
- **\`ca setup --update\` now cleans deprecated paths**: Automatically removes stale worktree skill/command files from \`.claude/\` and \`.gemini/\` directories.
|
|
10186
|
-
- **\`ca setup\` also cleans deprecated paths**: Fresh setup runs now remove stale files from prior versions.
|
|
10187
|
-
- **SKILLS.md template**: Command inventory now lists all 11 slash commands (was 7).
|
|
10488
|
+
### Changed
|
|
10188
10489
|
|
|
10189
|
-
|
|
10490
|
+
- **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 (\`@@\`).
|
|
10190
10491
|
|
|
10191
|
-
|
|
10192
|
-
- **P0**: Background worker spawn now resolves \`dist/cli.js\` deterministically instead of relying on \`npx ca\` (which failed silently in dev/built contexts)
|
|
10193
|
-
- **P0**: \`embed-worker\` command hidden from \`ca --help\` output
|
|
10194
|
-
- **P1**: Stale lock recovery uses atomic delete-then-\`wx\` to prevent two processes both reclaiming
|
|
10195
|
-
- **P1**: DB connection opened after lock acquisition to prevent leak on contention
|
|
10196
|
-
- **P1**: \`--embed\` now throws when model unavailable (was silently returning 0)
|
|
10197
|
-
- **P2**: Batch embedding (16 chunks per call) with per-batch SQLite transactions (was 1 fsync per row)
|
|
10198
|
-
- **P2**: \`EmbedStatus\` rewritten as discriminated union; removed dead \`chunksTotal\` field
|
|
10199
|
-
- **P2**: \`readLock\` validates JSON shape instead of blind \`as\` cast
|
|
10200
|
-
- **P2**: Vector batch length assertion guards against short responses from embedding backend
|
|
10201
|
-
- **P3**: Extracted \`indexAndSpawnEmbed()\` shared helper \u2014 \`init.ts\` and \`all.ts\` no longer duplicate logic
|
|
10202
|
-
- **P3**: \`ca setup\` now prints feedback when background embedding spawns
|
|
10203
|
-
- **P3**: \`filesErrored\` count shown in \`ca index-docs\` output
|
|
10204
|
-
- **P3**: Barrel re-exports consolidated through \`./memory/knowledge/index.js\`
|
|
10205
|
-
- **\`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\`.
|
|
10206
|
-
- **Stale worktree lesson invalidated**: Memory item \`Ld204372e\` marked invalid to prevent irrelevant context injection.
|
|
10207
|
-
|
|
10208
|
-
### Performance
|
|
10209
|
-
|
|
10210
|
-
- **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
|
|
10211
|
-
- **Bulk-read cached embeddings**: \`getCachedEmbeddingsBulk()\` replaces N individual \`getCachedEmbedding()\` SQLite queries with a single bulk read
|
|
10212
|
-
- **Eliminate redundant JSONL parsing**: \`searchVector()\` and \`findSimilarLessons()\` now use \`readAllFromSqlite()\` after \`syncIfNeeded()\` instead of re-parsing the JSONL file
|
|
10213
|
-
- **Float32Array consistency**: Lesson embedding path now keeps \`Float32Array\` from node-llama-cpp instead of converting via \`Array.from()\` (4x memory savings per vector)
|
|
10214
|
-
- **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
|
|
10215
|
-
- **Graceful embedding fallback**: \`ca search\` falls back to keyword-only search on runtime embedding failures instead of crashing
|
|
10216
|
-
|
|
10217
|
-
## [1.5.0] - 2026-02-24
|
|
10218
|
-
|
|
10219
|
-
### Added
|
|
10220
|
-
|
|
10221
|
-
- **Gemini CLI compatibility adapter**: \`ca setup gemini\` scaffolds \`.gemini/\` directory with hook scripts, TOML slash commands, and inlined skills -- bridging compound-agent to work with Google's Gemini CLI via the Adapter Pattern
|
|
10222
|
-
- **Gemini hooks**: Maps SessionStart, BeforeAgent, BeforeTool, AfterTool to compound-agent's existing hook pipeline (\`ca prime\`, \`ca hooks run user-prompt\`, \`ca hooks run phase-guard\`, \`ca hooks run post-tool-success\`)
|
|
10223
|
-
- **Gemini TOML commands**: Auto-generates \`.gemini/commands/compound/*.toml\` using \`@{path}\` file injection to maintain a single source of truth with Claude commands
|
|
10224
|
-
- **Gemini skills proxying**: Inlines phase and agent role skill content into \`.gemini/skills/\` with YAML frontmatter
|
|
10225
|
-
- **23 integration tests** for the Gemini adapter covering hooks, settings.json, TOML commands, skills, and dry-run mode
|
|
10492
|
+
## [1.6.2] - 2026-03-05
|
|
10226
10493
|
|
|
10227
10494
|
### Fixed
|
|
10228
10495
|
|
|
10229
|
-
- **
|
|
10230
|
-
- **Gemini TOML file injection syntax**: Changed \`@path\` to \`@{path}\` (Gemini CLI requires curly braces)
|
|
10231
|
-
- **Gemini skill file injection**: Skills now inline content instead of using \`@{path}\` which only works in TOML prompt fields, not SKILL.md
|
|
10232
|
-
- **Gemini phase guard always allowing**: Hook now checks \`ca hooks run phase-guard\` exit code and returns structured \`{"decision": "deny"}\` on failure (exit 0, not exit 2, so Gemini parses the reason from stdout)
|
|
10233
|
-
- **Gemini BeforeTool matcher incomplete**: Added \`create_file\` to BeforeTool and AfterTool matchers alongside \`replace\` and \`write_file\`
|
|
10234
|
-
- **TOML description escaping**: \`parseDescription\` now escapes \`\\\` and \`"\` to prevent malformed TOML output
|
|
10235
|
-
- **Flaky embedding test**: Added 15s timeout to \`isModelUsable\` test`;
|
|
10496
|
+
- **Cook-it session banner**: The cook-it skill now instructs Claude to print the "Claude the Cooker" ASCII chef banner at the very start of every cooking session.`;
|
|
10236
10497
|
|
|
10237
10498
|
// src/commands/about.ts
|
|
10238
|
-
function registerAboutCommand(
|
|
10239
|
-
|
|
10499
|
+
function registerAboutCommand(program) {
|
|
10500
|
+
program.command("about").description("Show version, animation, and recent changelog").action(async () => {
|
|
10240
10501
|
if (process.stdout.isTTY) {
|
|
10241
10502
|
await playInstallBanner();
|
|
10242
10503
|
} else {
|
|
@@ -10248,22 +10509,23 @@ function registerAboutCommand(program2) {
|
|
|
10248
10509
|
}
|
|
10249
10510
|
|
|
10250
10511
|
// src/commands/knowledge.ts
|
|
10512
|
+
init_embeddings();
|
|
10251
10513
|
init_sqlite_knowledge();
|
|
10252
10514
|
var MAX_DISPLAY_TEXT = 200;
|
|
10253
|
-
function registerKnowledgeCommand(
|
|
10254
|
-
|
|
10515
|
+
function registerKnowledgeCommand(program) {
|
|
10516
|
+
program.command("knowledge <query>").description("Search docs knowledge base").option("-n, --limit <number>", "Maximum results", "6").action(async function(query, opts) {
|
|
10255
10517
|
const globalOpts = getGlobalOpts(this);
|
|
10518
|
+
let limit;
|
|
10519
|
+
try {
|
|
10520
|
+
limit = parseLimit(opts.limit, "limit");
|
|
10521
|
+
} catch (err) {
|
|
10522
|
+
const message = err instanceof Error ? err.message : "Invalid limit";
|
|
10523
|
+
console.error(formatError("knowledge", "INVALID_LIMIT", message, "Use -n with a positive integer"));
|
|
10524
|
+
process.exitCode = 1;
|
|
10525
|
+
return;
|
|
10526
|
+
}
|
|
10527
|
+
const repoRoot = getRepoRoot();
|
|
10256
10528
|
try {
|
|
10257
|
-
let limit;
|
|
10258
|
-
try {
|
|
10259
|
-
limit = parseLimit(opts.limit, "limit");
|
|
10260
|
-
} catch (err) {
|
|
10261
|
-
const message = err instanceof Error ? err.message : "Invalid limit";
|
|
10262
|
-
console.error(formatError("knowledge", "INVALID_LIMIT", message, "Use -n with a positive integer"));
|
|
10263
|
-
process.exitCode = 1;
|
|
10264
|
-
return;
|
|
10265
|
-
}
|
|
10266
|
-
const repoRoot = getRepoRoot();
|
|
10267
10529
|
openKnowledgeDb(repoRoot);
|
|
10268
10530
|
if (getChunkCount(repoRoot) === 0) {
|
|
10269
10531
|
try {
|
|
@@ -10279,7 +10541,7 @@ function registerKnowledgeCommand(program2) {
|
|
|
10279
10541
|
out.info(`Auto-index failed (${msg}). Run manually: npx ca index-docs`);
|
|
10280
10542
|
}
|
|
10281
10543
|
}
|
|
10282
|
-
const results = await searchKnowledge(repoRoot, query, { limit });
|
|
10544
|
+
const results = await withEmbedding(async () => searchKnowledge(repoRoot, query, { limit }));
|
|
10283
10545
|
if (results.length === 0) {
|
|
10284
10546
|
out.info("No matching results found.");
|
|
10285
10547
|
return;
|
|
@@ -10307,15 +10569,15 @@ function registerKnowledgeCommand(program2) {
|
|
|
10307
10569
|
// src/commands/knowledge-index.ts
|
|
10308
10570
|
init_embeddings();
|
|
10309
10571
|
init_sqlite_knowledge();
|
|
10310
|
-
function registerKnowledgeIndexCommand(
|
|
10311
|
-
|
|
10572
|
+
function registerKnowledgeIndexCommand(program) {
|
|
10573
|
+
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) {
|
|
10312
10574
|
const repoRoot = getRepoRoot();
|
|
10313
10575
|
out.info("Indexing docs/ directory...");
|
|
10314
10576
|
try {
|
|
10315
|
-
const result = await indexDocs(repoRoot, {
|
|
10577
|
+
const result = await withEmbedding(async () => indexDocs(repoRoot, {
|
|
10316
10578
|
force: options.force,
|
|
10317
10579
|
embed: options.embed
|
|
10318
|
-
});
|
|
10580
|
+
}));
|
|
10319
10581
|
const skippedPart = result.filesSkipped > 0 ? ` (${result.filesSkipped} skipped)` : "";
|
|
10320
10582
|
const deletedPart = result.chunksDeleted > 0 ? `, ${result.chunksDeleted} deleted` : "";
|
|
10321
10583
|
const duration = (result.durationMs / 1e3).toFixed(1);
|
|
@@ -10330,11 +10592,10 @@ function registerKnowledgeIndexCommand(program2) {
|
|
|
10330
10592
|
}
|
|
10331
10593
|
out.info(`Duration: ${duration}s`);
|
|
10332
10594
|
} finally {
|
|
10333
|
-
unloadEmbedding();
|
|
10334
10595
|
closeKnowledgeDb();
|
|
10335
10596
|
}
|
|
10336
10597
|
});
|
|
10337
|
-
|
|
10598
|
+
program.command("embed-worker <repoRoot>", { hidden: true }).description("Internal: background embedding worker").action(async (repoRoot) => {
|
|
10338
10599
|
const { runBackgroundEmbed: runBackgroundEmbed2 } = await Promise.resolve().then(() => (init_embed_background(), embed_background_exports));
|
|
10339
10600
|
await runBackgroundEmbed2(repoRoot);
|
|
10340
10601
|
});
|
|
@@ -10401,22 +10662,21 @@ async function cleanLessonsAction() {
|
|
|
10401
10662
|
process.exitCode = 1;
|
|
10402
10663
|
return;
|
|
10403
10664
|
}
|
|
10404
|
-
|
|
10405
|
-
|
|
10406
|
-
|
|
10407
|
-
|
|
10408
|
-
|
|
10409
|
-
|
|
10410
|
-
|
|
10411
|
-
|
|
10412
|
-
|
|
10413
|
-
|
|
10414
|
-
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
|
|
10418
|
-
|
|
10419
|
-
try {
|
|
10665
|
+
await withEmbedding(async () => {
|
|
10666
|
+
try {
|
|
10667
|
+
await embedText("test");
|
|
10668
|
+
} catch (e) {
|
|
10669
|
+
console.error(
|
|
10670
|
+
formatError(
|
|
10671
|
+
"clean-lessons",
|
|
10672
|
+
"MODEL_UNUSABLE",
|
|
10673
|
+
`Embedding model failed to initialize: ${e instanceof Error ? e.message : String(e)}`,
|
|
10674
|
+
"Check model compatibility"
|
|
10675
|
+
)
|
|
10676
|
+
);
|
|
10677
|
+
process.exitCode = 1;
|
|
10678
|
+
return;
|
|
10679
|
+
}
|
|
10420
10680
|
await syncIfNeeded(repoRoot);
|
|
10421
10681
|
const { items } = await readMemoryItems(repoRoot);
|
|
10422
10682
|
const activeItems = items.filter((item) => !item.invalidatedAt && item.type === "lesson");
|
|
@@ -10429,12 +10689,10 @@ async function cleanLessonsAction() {
|
|
|
10429
10689
|
return;
|
|
10430
10690
|
}
|
|
10431
10691
|
printReport(pairs);
|
|
10432
|
-
}
|
|
10433
|
-
unloadEmbedding();
|
|
10434
|
-
}
|
|
10692
|
+
});
|
|
10435
10693
|
}
|
|
10436
|
-
function registerCleanLessonsCommand(
|
|
10437
|
-
|
|
10694
|
+
function registerCleanLessonsCommand(program) {
|
|
10695
|
+
program.command("clean-lessons").description("Analyze lessons for semantic duplicates and contradictions").action(cleanLessonsAction);
|
|
10438
10696
|
}
|
|
10439
10697
|
|
|
10440
10698
|
// src/commands/capture.ts
|
|
@@ -10561,9 +10819,9 @@ async function checkSimilarityPostCapture(repoRoot, item) {
|
|
|
10561
10819
|
if (!isModelAvailable2()) return;
|
|
10562
10820
|
const { syncIfNeeded: syncIfNeeded2 } = await Promise.resolve().then(() => (init_sync(), sync_exports));
|
|
10563
10821
|
const { findSimilarLessons: findSimilarLessons2 } = await Promise.resolve().then(() => (init_vector(), vector_exports));
|
|
10564
|
-
const { embedText: embedText2,
|
|
10822
|
+
const { embedText: embedText2, withEmbedding: withEmbedding2 } = await Promise.resolve().then(() => (init_nomic(), nomic_exports));
|
|
10565
10823
|
const chalk6 = await import('chalk');
|
|
10566
|
-
|
|
10824
|
+
await withEmbedding2(async () => {
|
|
10567
10825
|
await embedText2("test");
|
|
10568
10826
|
await syncIfNeeded2(repoRoot);
|
|
10569
10827
|
const similar = await findSimilarLessons2(repoRoot, item.insight, { excludeId: item.id });
|
|
@@ -10576,9 +10834,7 @@ async function checkSimilarityPostCapture(repoRoot, item) {
|
|
|
10576
10834
|
console.log("");
|
|
10577
10835
|
console.log(`Run ${chalk6.default.bold("'npx ca clean-lessons'")} to review and resolve.`);
|
|
10578
10836
|
}
|
|
10579
|
-
}
|
|
10580
|
-
unloadEmbedding2();
|
|
10581
|
-
}
|
|
10837
|
+
});
|
|
10582
10838
|
} catch (err) {
|
|
10583
10839
|
if (process.env["CA_DEBUG"]) {
|
|
10584
10840
|
process.stderr.write(`[CA_DEBUG] checkSimilarityPostCapture catch: ${err instanceof Error ? err.message : String(err)}
|
|
@@ -10706,17 +10962,18 @@ async function handleCapture(cmd, options) {
|
|
|
10706
10962
|
outputCapturePreview(lesson);
|
|
10707
10963
|
}
|
|
10708
10964
|
}
|
|
10709
|
-
function registerCaptureCommands(
|
|
10710
|
-
|
|
10965
|
+
function registerCaptureCommands(program) {
|
|
10966
|
+
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) {
|
|
10711
10967
|
await handleLearn(this, insight, options);
|
|
10712
10968
|
});
|
|
10713
|
-
|
|
10969
|
+
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) => {
|
|
10714
10970
|
await handleDetect(options);
|
|
10715
10971
|
});
|
|
10716
|
-
|
|
10972
|
+
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) {
|
|
10717
10973
|
await handleCapture(this, options);
|
|
10718
10974
|
});
|
|
10719
10975
|
}
|
|
10976
|
+
init_embeddings();
|
|
10720
10977
|
init_storage();
|
|
10721
10978
|
init_search2();
|
|
10722
10979
|
function parseLimitOrNull(rawLimit, optionName, commandName) {
|
|
@@ -10812,23 +11069,23 @@ async function searchAction(cmd, query, options) {
|
|
|
10812
11069
|
}
|
|
10813
11070
|
const { verbose, quiet } = getGlobalOpts(cmd);
|
|
10814
11071
|
await syncIfNeeded(repoRoot);
|
|
10815
|
-
|
|
10816
|
-
|
|
10817
|
-
|
|
10818
|
-
|
|
10819
|
-
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10826
|
-
|
|
10827
|
-
|
|
11072
|
+
const results = await withEmbedding(async () => {
|
|
11073
|
+
if (isModelAvailable()) {
|
|
11074
|
+
try {
|
|
11075
|
+
const candidateLimit = limit * CANDIDATE_MULTIPLIER;
|
|
11076
|
+
const [vectorResults, keywordResults] = await Promise.all([
|
|
11077
|
+
searchVector(repoRoot, query, { limit: candidateLimit }),
|
|
11078
|
+
searchKeywordScored(repoRoot, query, candidateLimit)
|
|
11079
|
+
]);
|
|
11080
|
+
const merged = mergeHybridResults(vectorResults, keywordResults, { minScore: MIN_HYBRID_SCORE });
|
|
11081
|
+
const ranked = rankLessons(merged);
|
|
11082
|
+
return ranked.slice(0, limit).map((r) => r.lesson);
|
|
11083
|
+
} catch {
|
|
11084
|
+
return await searchKeyword(repoRoot, query, limit);
|
|
11085
|
+
}
|
|
10828
11086
|
}
|
|
10829
|
-
|
|
10830
|
-
|
|
10831
|
-
}
|
|
11087
|
+
return await searchKeyword(repoRoot, query, limit);
|
|
11088
|
+
});
|
|
10832
11089
|
if (results.length > 0) {
|
|
10833
11090
|
incrementRetrievalCount(repoRoot, results.map((lesson) => lesson.id));
|
|
10834
11091
|
}
|
|
@@ -10962,7 +11219,7 @@ async function checkPlanAction(cmd, options) {
|
|
|
10962
11219
|
return;
|
|
10963
11220
|
}
|
|
10964
11221
|
try {
|
|
10965
|
-
const result = await retrieveForPlan(repoRoot, planText, limit);
|
|
11222
|
+
const result = await withEmbedding(async () => retrieveForPlan(repoRoot, planText, limit));
|
|
10966
11223
|
if (options.json) {
|
|
10967
11224
|
outputCheckPlanJson(result.lessons);
|
|
10968
11225
|
return;
|
|
@@ -10986,48 +11243,48 @@ async function checkPlanAction(cmd, options) {
|
|
|
10986
11243
|
process.exitCode = 1;
|
|
10987
11244
|
}
|
|
10988
11245
|
}
|
|
10989
|
-
function registerRetrievalCommands(
|
|
10990
|
-
|
|
11246
|
+
function registerRetrievalCommands(program) {
|
|
11247
|
+
program.command("search <query>").description("Search lessons").option("-n, --limit <number>", "Maximum results", DEFAULT_SEARCH_LIMIT).action(async function(query, options) {
|
|
10991
11248
|
await searchAction(this, query, options);
|
|
10992
11249
|
});
|
|
10993
|
-
|
|
11250
|
+
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) {
|
|
10994
11251
|
await listAction(this, options);
|
|
10995
11252
|
});
|
|
10996
|
-
|
|
11253
|
+
program.command("load-session").description("Load high-severity lessons for session context").option("--json", "Output as JSON").action(async function(options) {
|
|
10997
11254
|
await loadSessionAction(this, options);
|
|
10998
11255
|
});
|
|
10999
|
-
|
|
11256
|
+
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) {
|
|
11000
11257
|
await checkPlanAction(this, options);
|
|
11001
11258
|
});
|
|
11002
11259
|
}
|
|
11003
11260
|
|
|
11004
11261
|
// src/commands/index.ts
|
|
11005
|
-
function registerSetupCommands(
|
|
11006
|
-
registerInitCommand(
|
|
11007
|
-
registerHooksCommand(
|
|
11008
|
-
const setupCommand =
|
|
11262
|
+
function registerSetupCommands(program) {
|
|
11263
|
+
registerInitCommand(program);
|
|
11264
|
+
registerHooksCommand(program);
|
|
11265
|
+
const setupCommand = program.command("setup");
|
|
11009
11266
|
registerSetupAllCommand(setupCommand);
|
|
11010
11267
|
registerClaudeSubcommand(setupCommand);
|
|
11011
11268
|
registerGeminiSubcommand(setupCommand);
|
|
11012
|
-
registerDownloadModelCommand(
|
|
11013
|
-
}
|
|
11014
|
-
function registerManagementCommands(
|
|
11015
|
-
registerInvalidationCommands(
|
|
11016
|
-
registerMaintenanceCommands(
|
|
11017
|
-
registerIOCommands(
|
|
11018
|
-
registerPrimeCommand(
|
|
11019
|
-
registerCrudCommands(
|
|
11020
|
-
registerAuditCommands(
|
|
11021
|
-
registerDoctorCommand(
|
|
11022
|
-
registerReviewerCommand(
|
|
11023
|
-
registerRulesCommands(
|
|
11024
|
-
registerTestSummaryCommand(
|
|
11025
|
-
registerVerifyGatesCommand(
|
|
11026
|
-
registerAboutCommand(
|
|
11027
|
-
registerKnowledgeCommand(
|
|
11028
|
-
registerKnowledgeIndexCommand(
|
|
11029
|
-
registerCleanLessonsCommand(
|
|
11030
|
-
|
|
11269
|
+
registerDownloadModelCommand(program);
|
|
11270
|
+
}
|
|
11271
|
+
function registerManagementCommands(program) {
|
|
11272
|
+
registerInvalidationCommands(program);
|
|
11273
|
+
registerMaintenanceCommands(program);
|
|
11274
|
+
registerIOCommands(program);
|
|
11275
|
+
registerPrimeCommand(program);
|
|
11276
|
+
registerCrudCommands(program);
|
|
11277
|
+
registerAuditCommands(program);
|
|
11278
|
+
registerDoctorCommand(program);
|
|
11279
|
+
registerReviewerCommand(program);
|
|
11280
|
+
registerRulesCommands(program);
|
|
11281
|
+
registerTestSummaryCommand(program);
|
|
11282
|
+
registerVerifyGatesCommand(program);
|
|
11283
|
+
registerAboutCommand(program);
|
|
11284
|
+
registerKnowledgeCommand(program);
|
|
11285
|
+
registerKnowledgeIndexCommand(program);
|
|
11286
|
+
registerCleanLessonsCommand(program);
|
|
11287
|
+
program.command("worktree").description("(removed) Use Claude Code native worktree support").action(() => {
|
|
11031
11288
|
console.error("ca worktree has been removed. Use Claude Code's native EnterWorktree support instead.");
|
|
11032
11289
|
process.exitCode = 1;
|
|
11033
11290
|
});
|
|
@@ -11376,8 +11633,8 @@ async function handleLoop(cmd, options) {
|
|
|
11376
11633
|
out.info("Run it with: " + outputPath);
|
|
11377
11634
|
out.info("Preview with: LOOP_DRY_RUN=1 " + outputPath);
|
|
11378
11635
|
}
|
|
11379
|
-
function registerLoopCommands(
|
|
11380
|
-
|
|
11636
|
+
function registerLoopCommands(program) {
|
|
11637
|
+
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) {
|
|
11381
11638
|
await handleLoop(this, options);
|
|
11382
11639
|
});
|
|
11383
11640
|
}
|
|
@@ -11484,15 +11741,15 @@ async function tailFile(filePath, follow) {
|
|
|
11484
11741
|
const child = spawn("tail", ["-f", "-n", "+1", filePath], { stdio: ["ignore", "pipe", "ignore"] });
|
|
11485
11742
|
const rl2 = createInterface({ input: child.stdout });
|
|
11486
11743
|
rl2.on("line", processLine);
|
|
11487
|
-
const
|
|
11744
|
+
const cleanup = () => {
|
|
11488
11745
|
child.kill("SIGTERM");
|
|
11489
11746
|
};
|
|
11490
|
-
process.on("SIGINT",
|
|
11491
|
-
process.on("SIGTERM",
|
|
11747
|
+
process.on("SIGINT", cleanup);
|
|
11748
|
+
process.on("SIGTERM", cleanup);
|
|
11492
11749
|
return new Promise((done) => {
|
|
11493
11750
|
child.on("close", () => {
|
|
11494
|
-
process.off("SIGINT",
|
|
11495
|
-
process.off("SIGTERM",
|
|
11751
|
+
process.off("SIGINT", cleanup);
|
|
11752
|
+
process.off("SIGTERM", cleanup);
|
|
11496
11753
|
done();
|
|
11497
11754
|
});
|
|
11498
11755
|
});
|
|
@@ -11547,8 +11804,8 @@ async function handleWatch(cmd, options) {
|
|
|
11547
11804
|
out.info(`Watching: ${traceFile}`);
|
|
11548
11805
|
await tailFile(traceFile, follow);
|
|
11549
11806
|
}
|
|
11550
|
-
function registerWatchCommand(
|
|
11551
|
-
|
|
11807
|
+
function registerWatchCommand(program) {
|
|
11808
|
+
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) {
|
|
11552
11809
|
await handleWatch(this, options);
|
|
11553
11810
|
});
|
|
11554
11811
|
}
|
|
@@ -11596,7 +11853,8 @@ function commandNeedsSqlite(cmd) {
|
|
|
11596
11853
|
return false;
|
|
11597
11854
|
}
|
|
11598
11855
|
|
|
11599
|
-
// src/cli.ts
|
|
11856
|
+
// src/cli-app.ts
|
|
11857
|
+
init_embeddings();
|
|
11600
11858
|
init_storage();
|
|
11601
11859
|
function detectPackageManager(cwd) {
|
|
11602
11860
|
if (existsSync(join(cwd, "pnpm-lock.yaml"))) return "pnpm";
|
|
@@ -11660,46 +11918,62 @@ function printBuildToolsHint() {
|
|
|
11660
11918
|
}
|
|
11661
11919
|
}
|
|
11662
11920
|
|
|
11663
|
-
// src/cli.ts
|
|
11664
|
-
function
|
|
11921
|
+
// src/cli-app.ts
|
|
11922
|
+
async function cleanupCliResources() {
|
|
11923
|
+
try {
|
|
11924
|
+
await unloadEmbeddingResources();
|
|
11925
|
+
} catch {
|
|
11926
|
+
}
|
|
11665
11927
|
try {
|
|
11666
11928
|
closeDb();
|
|
11667
11929
|
} catch {
|
|
11668
11930
|
}
|
|
11669
11931
|
}
|
|
11670
|
-
|
|
11671
|
-
|
|
11672
|
-
|
|
11673
|
-
}
|
|
11674
|
-
process.on("
|
|
11675
|
-
|
|
11676
|
-
|
|
11677
|
-
|
|
11678
|
-
|
|
11679
|
-
program.option("-v, --verbose", "Show detailed output").option("-q, --quiet", "Suppress non-essential output");
|
|
11680
|
-
program.name("ca").description("Semantically-intelligent workflow plugin for Claude Code").version(VERSION);
|
|
11681
|
-
registerCaptureCommands(program);
|
|
11682
|
-
registerRetrievalCommands(program);
|
|
11683
|
-
registerManagementCommands(program);
|
|
11684
|
-
registerSetupCommands(program);
|
|
11685
|
-
registerCompoundCommands(program);
|
|
11686
|
-
registerLoopCommands(program);
|
|
11687
|
-
registerWatchCommand(program);
|
|
11688
|
-
registerPhaseCheckCommand(program);
|
|
11689
|
-
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
11690
|
-
|
|
11691
|
-
try {
|
|
11692
|
-
ensureSqliteAvailable();
|
|
11693
|
-
} catch (err) {
|
|
11694
|
-
let root;
|
|
11932
|
+
function attachSignalHandlers() {
|
|
11933
|
+
const handleSignal = (exitCode) => {
|
|
11934
|
+
void cleanupCliResources().finally(() => process.exit(exitCode));
|
|
11935
|
+
};
|
|
11936
|
+
process.on("SIGINT", () => handleSignal(0));
|
|
11937
|
+
process.on("SIGTERM", () => handleSignal(0));
|
|
11938
|
+
}
|
|
11939
|
+
function createProgram() {
|
|
11940
|
+
const program = new Command();
|
|
11941
|
+
program.option("-v, --verbose", "Show detailed output").option("-q, --quiet", "Suppress non-essential output");
|
|
11942
|
+
program.name("ca").description("Semantically-intelligent workflow plugin for Claude Code").version(VERSION);
|
|
11943
|
+
registerCaptureCommands(program);
|
|
11944
|
+
registerRetrievalCommands(program);
|
|
11945
|
+
registerManagementCommands(program);
|
|
11946
|
+
registerSetupCommands(program);
|
|
11947
|
+
registerCompoundCommands(program);
|
|
11948
|
+
registerLoopCommands(program);
|
|
11949
|
+
registerWatchCommand(program);
|
|
11950
|
+
registerPhaseCheckCommand(program);
|
|
11951
|
+
program.hook("preAction", (_thisCommand, actionCommand) => {
|
|
11952
|
+
if (!commandNeedsSqlite(actionCommand)) return;
|
|
11695
11953
|
try {
|
|
11696
|
-
|
|
11697
|
-
} catch {
|
|
11954
|
+
ensureSqliteAvailable();
|
|
11955
|
+
} catch (err) {
|
|
11956
|
+
let root;
|
|
11957
|
+
try {
|
|
11958
|
+
root = getRepoRoot();
|
|
11959
|
+
} catch {
|
|
11960
|
+
}
|
|
11961
|
+
printNativeBuildDiagnostic(err, root);
|
|
11962
|
+
process.exit(1);
|
|
11698
11963
|
}
|
|
11699
|
-
|
|
11700
|
-
|
|
11964
|
+
});
|
|
11965
|
+
return program;
|
|
11966
|
+
}
|
|
11967
|
+
async function runProgram(program, argv = process.argv) {
|
|
11968
|
+
try {
|
|
11969
|
+
await program.parseAsync(argv);
|
|
11970
|
+
} finally {
|
|
11971
|
+
await cleanupCliResources();
|
|
11701
11972
|
}
|
|
11702
|
-
}
|
|
11703
|
-
|
|
11973
|
+
}
|
|
11974
|
+
|
|
11975
|
+
// src/cli.ts
|
|
11976
|
+
attachSignalHandlers();
|
|
11977
|
+
await runProgram(createProgram());
|
|
11704
11978
|
//# sourceMappingURL=cli.js.map
|
|
11705
11979
|
//# sourceMappingURL=cli.js.map
|