peaks-loop 4.0.32 → 4.0.33
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 +19 -0
- package/README-en.md +3 -4
- package/README.md +20 -28
- package/dist/cli/commands/_register.js +4 -3
- package/dist/cli/commands/audit-commands.js +12 -39
- package/dist/cli/commands/capability-commands.d.ts +6 -0
- package/dist/cli/commands/capability-commands.js +20 -2
- package/dist/cli/commands/ecc-commands.js +3 -2
- package/dist/cli/commands/project-commands.js +1 -1
- package/dist/cli/commands/shadcn-commands.d.ts +32 -0
- package/dist/cli/commands/shadcn-commands.js +120 -0
- package/dist/cli/commands/slice-commands.js +1 -4
- package/dist/services/audit/static-service.d.ts +1 -1
- package/dist/services/audit/static-service.js +1 -1
- package/dist/services/code-review/ecc-bridge.d.ts +94 -15
- package/dist/services/code-review/ecc-bridge.js +133 -13
- package/dist/services/dashboard/project-dashboard-service.d.ts +0 -7
- package/dist/services/dashboard/project-dashboard-service.js +1 -9
- package/dist/services/preferences/preferences-types.d.ts +16 -7
- package/dist/services/recommendations/capability-seed-items.js +0 -1
- package/dist/services/recommendations/installed-capability-detector.d.ts +33 -0
- package/dist/services/recommendations/installed-capability-detector.js +76 -0
- package/dist/services/scan/orphan-service.js +1 -1
- package/dist/services/slice/multi-pass-orchestrator.js +0 -13
- package/dist/services/slice/slice-decompose-import-edges.d.ts +2 -2
- package/dist/services/slice/slice-decompose-import-edges.js +1 -29
- package/dist/services/slice/slice-decompose-runners.d.ts +2 -4
- package/dist/services/slice/slice-decompose-runners.js +1 -23
- package/dist/services/slice/slice-decompose-service.d.ts +3 -4
- package/dist/services/slice/slice-decompose-service.js +10 -29
- package/dist/services/slice/slice-decompose-types.d.ts +6 -47
- package/dist/services/slice/slice-decompose-types.js +3 -2
- package/dist/services/slice/slice-topology-types.d.ts +2 -3
- package/package.json +5 -5
- package/schemas/decomposition-v1.json +0 -12
- package/schemas/decomposition-v2.json +1 -15
- package/skills/bee/peaks-prd/SKILL.md +0 -1
- package/skills/bee/peaks-rd/SKILL.md +1 -1
- package/skills/bee/peaks-rd/references/external-references.md +1 -3
- package/skills/bee/peaks-rd/references/parallel-review-fanout.md +7 -2
- package/skills/bee/peaks-rd/references/rd-fanout-contracts.md +22 -8
- package/skills/bee/peaks-rd/references/rd-runbook.md +0 -2
- package/skills/bee/peaks-txt/SKILL.md +0 -12
- package/skills/peaks-doctor/SKILL.md +1 -1
- package/skills/peaks-slice-decompose/SKILL.md +0 -1
- package/skills/peaks-slice-decompose/references/v2-schema.md +1 -12
- package/dist/cli/commands/understand-commands.d.ts +0 -3
- package/dist/cli/commands/understand-commands.js +0 -148
- package/dist/services/understand/hybrid-types.d.ts +0 -32
- package/dist/services/understand/hybrid-types.js +0 -1
- package/dist/services/understand/understand-hybrid-service.d.ts +0 -10
- package/dist/services/understand/understand-hybrid-service.js +0 -100
- package/dist/services/understand/understand-scan-service.d.ts +0 -28
- package/dist/services/understand/understand-scan-service.js +0 -170
- package/dist/services/understand/understand-types.d.ts +0 -50
- package/dist/services/understand/understand-types.js +0 -1
|
@@ -55,38 +55,10 @@ function collectImportEdges(importEdges, fileToWu, projectRoot, collector) {
|
|
|
55
55
|
pushIfNew(collector, edge);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
function
|
|
59
|
-
for (const e of kg.edges) {
|
|
60
|
-
if (e.type !== 'contains_flow' && e.type !== 'flow_step')
|
|
61
|
-
continue;
|
|
62
|
-
const fromNode = kg.nodes.find((n) => n.id === e.source);
|
|
63
|
-
const toNode = kg.nodes.find((n) => n.id === e.target);
|
|
64
|
-
if (!fromNode?.filePath || !toNode?.filePath)
|
|
65
|
-
continue;
|
|
66
|
-
const fromWu = fileToWu.get(fromNode.filePath);
|
|
67
|
-
const toWu = fileToWu.get(toNode.filePath);
|
|
68
|
-
if (!fromWu || !toWu || fromWu === toWu)
|
|
69
|
-
continue;
|
|
70
|
-
const weight = e.type === 'flow_step' ? 0.05 : 0.1;
|
|
71
|
-
const edge = {
|
|
72
|
-
from: fromWu,
|
|
73
|
-
to: toWu,
|
|
74
|
-
kind: e.type,
|
|
75
|
-
weight,
|
|
76
|
-
evidence: `understand-anything: ${e.type} ${e.source}->${e.target}`,
|
|
77
|
-
isSemantic: true,
|
|
78
|
-
confidence: 'semantic'
|
|
79
|
-
};
|
|
80
|
-
pushIfNew(collector, edge);
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
export function buildDependencyEdges(wus, importEdges, kg, projectRoot) {
|
|
58
|
+
export function buildDependencyEdges(wus, importEdges, projectRoot) {
|
|
84
59
|
const fileToWu = indexFilesToWorkUnits(wus);
|
|
85
60
|
const collector = { edges: [], seen: new Set() };
|
|
86
61
|
collectImportEdges(importEdges, fileToWu, projectRoot, collector);
|
|
87
|
-
if (kg !== null) {
|
|
88
|
-
collectSemanticEdges(kg, fileToWu, collector);
|
|
89
|
-
}
|
|
90
62
|
return collector.edges;
|
|
91
63
|
}
|
|
92
64
|
function resolveRelativeImport(projectRoot, sourceFile, evidence) {
|
|
@@ -7,17 +7,15 @@
|
|
|
7
7
|
* does not inject fakes via `DecomposeOptions`. The 6-stage pure
|
|
8
8
|
* algorithm itself lives in `slice-decompose-service.ts`.
|
|
9
9
|
*
|
|
10
|
-
* Public surface (
|
|
10
|
+
* Public surface (2 exported factories):
|
|
11
11
|
*
|
|
12
12
|
* defaultCodegraphRunner() -- spawns `npx codegraph <cmd>`
|
|
13
|
-
* defaultUnderstandRunner() -- reads .understand-anything/knowledge-graph.json
|
|
14
13
|
* defaultImportEdgeRunner() -- reads source files for import statements
|
|
15
14
|
*
|
|
16
15
|
* v2.18.3 file-split: this module is the extracted sub-tree of the
|
|
17
16
|
* pre-split `slice-decompose-service.ts`. Function signatures are
|
|
18
17
|
* unchanged (verbatim move).
|
|
19
18
|
*/
|
|
20
|
-
import type { CodegraphRunner, ImportEdgeRunner
|
|
19
|
+
import type { CodegraphRunner, ImportEdgeRunner } from './slice-decompose-types.js';
|
|
21
20
|
export declare function defaultCodegraphRunner(): CodegraphRunner;
|
|
22
|
-
export declare function defaultUnderstandRunner(): UnderstandRunner;
|
|
23
21
|
export declare function defaultImportEdgeRunner(): ImportEdgeRunner;
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* does not inject fakes via `DecomposeOptions`. The 6-stage pure
|
|
8
8
|
* algorithm itself lives in `slice-decompose-service.ts`.
|
|
9
9
|
*
|
|
10
|
-
* Public surface (
|
|
10
|
+
* Public surface (2 exported factories):
|
|
11
11
|
*
|
|
12
12
|
* defaultCodegraphRunner() -- spawns `npx codegraph <cmd>`
|
|
13
|
-
* defaultUnderstandRunner() -- reads .understand-anything/knowledge-graph.json
|
|
14
13
|
* defaultImportEdgeRunner() -- reads source files for import statements
|
|
15
14
|
*
|
|
16
15
|
* v2.18.3 file-split: this module is the extracted sub-tree of the
|
|
@@ -121,27 +120,6 @@ function runCodegraph(args, projectRoot) {
|
|
|
121
120
|
throw error;
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
|
-
export function defaultUnderstandRunner() {
|
|
125
|
-
return {
|
|
126
|
-
async read(projectRoot) {
|
|
127
|
-
const kgPath = join(projectRoot, '.understand-anything', 'knowledge-graph.json');
|
|
128
|
-
if (!existsSync(kgPath))
|
|
129
|
-
return null;
|
|
130
|
-
try {
|
|
131
|
-
const raw = readFileSync(kgPath, 'utf8');
|
|
132
|
-
const parsed = JSON.parse(raw);
|
|
133
|
-
return {
|
|
134
|
-
nodes: parsed.nodes ?? [],
|
|
135
|
-
edges: parsed.edges ?? [],
|
|
136
|
-
layers: parsed.layers ?? []
|
|
137
|
-
};
|
|
138
|
-
}
|
|
139
|
-
catch { // TODO(g2): legacy silent catch — grace: 1 minor release (v2.14.0)
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
123
|
export function defaultImportEdgeRunner() {
|
|
146
124
|
return {
|
|
147
125
|
async importsOf(projectRoot, files) {
|
|
@@ -12,13 +12,12 @@
|
|
|
12
12
|
* Default runners (CLI-mode, real shell-outs):
|
|
13
13
|
*
|
|
14
14
|
* defaultCodegraphRunner() -- spawns `npx codegraph <cmd>`
|
|
15
|
-
* defaultUnderstandRunner() -- reads .understand-anything/knowledge-graph.json
|
|
16
15
|
* defaultImportEdgeRunner() -- reads source files for import statements
|
|
17
16
|
*
|
|
18
|
-
* Tests inject fakes via the `codegraphRunner
|
|
19
|
-
*
|
|
17
|
+
* Tests inject fakes via the `codegraphRunner` and `importEdgeRunner`
|
|
18
|
+
* fields of `DecomposeOptions`.
|
|
20
19
|
*/
|
|
21
20
|
import type { DecomposeOptions, DecompositionResult } from './slice-decompose-types.js';
|
|
22
21
|
export type { DecomposeOptions };
|
|
23
22
|
export declare function decomposeSlices(rid: string, prdMarkdown: string, projectRoot: string, options?: DecomposeOptions): Promise<DecompositionResult>;
|
|
24
|
-
export { defaultCodegraphRunner,
|
|
23
|
+
export { defaultCodegraphRunner, defaultImportEdgeRunner } from './slice-decompose-runners.js';
|
|
@@ -12,11 +12,10 @@
|
|
|
12
12
|
* Default runners (CLI-mode, real shell-outs):
|
|
13
13
|
*
|
|
14
14
|
* defaultCodegraphRunner() -- spawns `npx codegraph <cmd>`
|
|
15
|
-
* defaultUnderstandRunner() -- reads .understand-anything/knowledge-graph.json
|
|
16
15
|
* defaultImportEdgeRunner() -- reads source files for import statements
|
|
17
16
|
*
|
|
18
|
-
* Tests inject fakes via the `codegraphRunner
|
|
19
|
-
*
|
|
17
|
+
* Tests inject fakes via the `codegraphRunner` and `importEdgeRunner`
|
|
18
|
+
* fields of `DecomposeOptions`.
|
|
20
19
|
*/
|
|
21
20
|
import { basename } from 'node:path';
|
|
22
21
|
import { calibrate } from './calibration-store.js';
|
|
@@ -48,8 +47,6 @@ function createInitialState(rid, prdMarkdown, projectRoot, runners) {
|
|
|
48
47
|
cgStatus: null,
|
|
49
48
|
workUnits: [],
|
|
50
49
|
depEdges: [],
|
|
51
|
-
kg: null,
|
|
52
|
-
understandAvailable: false,
|
|
53
50
|
codegraphAffectedCrossFile: false,
|
|
54
51
|
scc: null,
|
|
55
52
|
criticalPath: null,
|
|
@@ -84,7 +81,6 @@ async function runStage(state, stage) {
|
|
|
84
81
|
function resolveRunners(options) {
|
|
85
82
|
return {
|
|
86
83
|
cg: options.codegraphRunner ?? defaultCodegraphRunner(),
|
|
87
|
-
ur: options.understandRunner ?? defaultUnderstandRunner(),
|
|
88
84
|
ier: options.importEdgeRunner ?? defaultImportEdgeRunner()
|
|
89
85
|
};
|
|
90
86
|
}
|
|
@@ -172,15 +168,13 @@ function matchAcToHit(ac, hits) {
|
|
|
172
168
|
// Stage 2: dependency DAG
|
|
173
169
|
// =====================================================================
|
|
174
170
|
async function buildDepDagStage(state) {
|
|
175
|
-
const kg = await state.runners.ur.read(state.projectRoot);
|
|
176
|
-
const understandAvailable = kg !== null;
|
|
177
171
|
const fileSet = await collectFileSet(state.workUnits, state.runners.ier, state.projectRoot);
|
|
178
172
|
const allFiles = Array.from(fileSet);
|
|
179
173
|
const codegraphAffectedCrossFile = await probeCrossFileAffected(allFiles, state.runners.cg, state.projectRoot);
|
|
180
174
|
const workUnits = applyImplicitWuFallback(state.workUnits, allFiles);
|
|
181
175
|
const importEdges = await state.runners.ier.importsOf(state.projectRoot, allFiles);
|
|
182
|
-
const depEdges = buildDependencyEdges(workUnits, importEdges,
|
|
183
|
-
return { ...state,
|
|
176
|
+
const depEdges = buildDependencyEdges(workUnits, importEdges, state.projectRoot);
|
|
177
|
+
return { ...state, codegraphAffectedCrossFile, workUnits, depEdges };
|
|
184
178
|
}
|
|
185
179
|
async function collectFileSet(workUnits, ier, projectRoot) {
|
|
186
180
|
const explicitFiles = workUnits.flatMap((w) => w.files);
|
|
@@ -362,10 +356,10 @@ function backtrackPath(endNode, prev) {
|
|
|
362
356
|
function minCutStage(state) {
|
|
363
357
|
if (state.criticalPath === null)
|
|
364
358
|
return state;
|
|
365
|
-
const minCut = findMinCut(state.workUnits, state.depEdges, state.criticalPath
|
|
359
|
+
const minCut = findMinCut(state.workUnits, state.depEdges, state.criticalPath);
|
|
366
360
|
return { ...state, minCut };
|
|
367
361
|
}
|
|
368
|
-
function findMinCut(_wus, edges, criticalPath
|
|
362
|
+
function findMinCut(_wus, edges, criticalPath) {
|
|
369
363
|
const cpSet = new Set(criticalPath.nodes);
|
|
370
364
|
const nonCpEdges = edges.filter((e) => !cpSet.has(e.from) || !cpSet.has(e.to));
|
|
371
365
|
const sorted = [...nonCpEdges].sort((a, b) => a.weight - b.weight);
|
|
@@ -405,7 +399,7 @@ function partitionEstimateEmitStage(state) {
|
|
|
405
399
|
...b,
|
|
406
400
|
slices: b.slices.map((s) => ({
|
|
407
401
|
...s,
|
|
408
|
-
estimate: estimateSlice(s
|
|
402
|
+
estimate: estimateSlice(s)
|
|
409
403
|
}))
|
|
410
404
|
}));
|
|
411
405
|
const result = buildDecompositionResult(state, batchesWithEstimates);
|
|
@@ -416,12 +410,10 @@ function buildDecompositionResult(state, batchesWithEstimates) {
|
|
|
416
410
|
const totalSlices = batchesWithEstimates.reduce((sum, b) => sum + b.slices.length, 0);
|
|
417
411
|
const pickHint = buildPickHint(totalSlices);
|
|
418
412
|
const codegraphEnvelope = buildCodegraphEnvelope(state);
|
|
419
|
-
const understandEnvelope = buildUnderstandEnvelope(state);
|
|
420
413
|
return {
|
|
421
414
|
rid: state.rid,
|
|
422
415
|
generatedAt: new Date().toISOString(),
|
|
423
416
|
codegraph: codegraphEnvelope,
|
|
424
|
-
understandAnything: understandEnvelope,
|
|
425
417
|
workUnits: state.workUnits,
|
|
426
418
|
dependencyDAG: { edges: state.depEdges },
|
|
427
419
|
sccAnalysis: state.scc,
|
|
@@ -460,18 +452,7 @@ function buildCodegraphEnvelope(state) {
|
|
|
460
452
|
: 'codegraph.affected returned 0 cross-file dependents (v0.7.10 limitation); used real import edges'
|
|
461
453
|
};
|
|
462
454
|
}
|
|
463
|
-
function
|
|
464
|
-
return {
|
|
465
|
-
kgNodes: state.kg?.nodes.length ?? 0,
|
|
466
|
-
kgEdges: state.kg?.edges.length ?? 0,
|
|
467
|
-
available: state.understandAvailable,
|
|
468
|
-
fallback: state.understandAvailable ? 'semantic' : 'structural-only',
|
|
469
|
-
note: state.understandAvailable
|
|
470
|
-
? 'read from .understand-anything/knowledge-graph.json'
|
|
471
|
-
: '.understand-anything/knowledge-graph.json not found; algorithm falls back to structural cuts'
|
|
472
|
-
};
|
|
473
|
-
}
|
|
474
|
-
function estimateSlice(slice, _kg) {
|
|
455
|
+
function estimateSlice(slice) {
|
|
475
456
|
const sampleSize = 0;
|
|
476
457
|
const complexitySum = 0;
|
|
477
458
|
return calibrate(complexitySum, slice.estimate.testCount, slice.estimate.locSum, sampleSize);
|
|
@@ -569,5 +550,5 @@ function wuToSlice(wu) {
|
|
|
569
550
|
// `slice-decompose-runners.ts` module — see v2.18.3 file-split for
|
|
570
551
|
// the rationale. Function signatures and behaviour are unchanged
|
|
571
552
|
// (verbatim move).
|
|
572
|
-
import { defaultCodegraphRunner,
|
|
573
|
-
export { defaultCodegraphRunner,
|
|
553
|
+
import { defaultCodegraphRunner, defaultImportEdgeRunner } from './slice-decompose-runners.js';
|
|
554
|
+
export { defaultCodegraphRunner, defaultImportEdgeRunner } from './slice-decompose-runners.js';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The slice-decomposition algorithm is a 6-stage deterministic function
|
|
5
5
|
* (see `peaks-code/references/slice-algorithm.md` for the full spec):
|
|
6
6
|
*
|
|
7
|
-
* 1. workUnitResolution -- codegraph.query
|
|
7
|
+
* 1. workUnitResolution -- codegraph.query
|
|
8
8
|
* 2. buildDependencyDAG -- real import edges + codegraph.affected fallback
|
|
9
9
|
* 3. scc + criticalPath -- Tarjan + longest_path on the condensation
|
|
10
10
|
* 4. minCut -- Stoer-Wagner with semantic-preference weights
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* - `peaks-rd` and `peaks-qa` in unit tests
|
|
22
22
|
* - user inspection via `cat .peaks/sc/slice-decomposition/<rid>.json`
|
|
23
23
|
*
|
|
24
|
-
*
|
|
24
|
+
* Project analysis is codegraph-first; structural import edges are the
|
|
25
|
+
* fallback. Codegraph is local project-analysis evidence; its output is
|
|
25
26
|
* **untrusted supporting evidence**, never authoritative for QA verdict.
|
|
26
27
|
* DecompositionResult fields derived from codegraph are tagged with
|
|
27
28
|
* `confidence: 'semantic' | 'structural'` so downstream consumers can
|
|
@@ -57,9 +58,9 @@ export interface DependencyEdge {
|
|
|
57
58
|
weight: number;
|
|
58
59
|
/** Human-readable evidence: the actual import statement or graph edge. */
|
|
59
60
|
evidence: string;
|
|
60
|
-
/** True iff kind is contains_flow or flow_step (
|
|
61
|
+
/** True iff kind is contains_flow or flow_step (semantic flow edges). */
|
|
61
62
|
isSemantic: boolean;
|
|
62
|
-
/** 'semantic'
|
|
63
|
+
/** 'semantic' for flow edges; 'structural' for import-grep / codegraph edges. */
|
|
63
64
|
confidence: 'semantic' | 'structural';
|
|
64
65
|
}
|
|
65
66
|
export interface WorkEstimate {
|
|
@@ -77,7 +78,7 @@ export interface SliceCandidate {
|
|
|
77
78
|
files: readonly string[];
|
|
78
79
|
testsAdded?: readonly string[];
|
|
79
80
|
estimate: WorkEstimate;
|
|
80
|
-
/** Domain anchor; "
|
|
81
|
+
/** Domain anchor; always "file:<path>" (codegraph / structural evidence). */
|
|
81
82
|
semanticAnchor: string;
|
|
82
83
|
}
|
|
83
84
|
export interface ParallelBatch {
|
|
@@ -126,19 +127,11 @@ export interface CodegraphEnvelope {
|
|
|
126
127
|
affectedCrossFile: boolean;
|
|
127
128
|
note: string;
|
|
128
129
|
}
|
|
129
|
-
export interface UnderstandAnythingEnvelope {
|
|
130
|
-
kgNodes: number;
|
|
131
|
-
kgEdges: number;
|
|
132
|
-
available: boolean;
|
|
133
|
-
fallback: 'semantic' | 'structural-only';
|
|
134
|
-
note: string;
|
|
135
|
-
}
|
|
136
130
|
export interface DecompositionResult {
|
|
137
131
|
rid: string;
|
|
138
132
|
/** ISO 8601 UTC, e.g. "2026-06-13T12:00:00.000Z". */
|
|
139
133
|
generatedAt: string;
|
|
140
134
|
codegraph: CodegraphEnvelope;
|
|
141
|
-
understandAnything: UnderstandAnythingEnvelope;
|
|
142
135
|
workUnits: readonly WorkUnit[];
|
|
143
136
|
dependencyDAG: {
|
|
144
137
|
edges: readonly DependencyEdge[];
|
|
@@ -182,11 +175,6 @@ export interface DecomposeOptions {
|
|
|
182
175
|
* Tests pass a function-returning-promise fake.
|
|
183
176
|
*/
|
|
184
177
|
codegraphRunner?: CodegraphRunner;
|
|
185
|
-
/**
|
|
186
|
-
* Inject an understand-anything shell replacement. Default reads
|
|
187
|
-
* `.understand-anything/knowledge-graph.json` if present.
|
|
188
|
-
*/
|
|
189
|
-
understandRunner?: UnderstandRunner;
|
|
190
178
|
/**
|
|
191
179
|
* Inject a function that returns the real import-edge set for a list of files.
|
|
192
180
|
* Default: spawns `git grep` + parses output. Tests pass a synchronous fake.
|
|
@@ -218,35 +206,6 @@ export interface CodegraphAffectedResult {
|
|
|
218
206
|
affectedTests: readonly string[];
|
|
219
207
|
totalDependentsTraversed: number;
|
|
220
208
|
}
|
|
221
|
-
export interface UnderstandRunner {
|
|
222
|
-
/** Returns the parsed knowledge graph, or null if not indexed. */
|
|
223
|
-
read(projectRoot: string): Promise<KnowledgeGraph | null>;
|
|
224
|
-
}
|
|
225
|
-
export interface KnowledgeGraph {
|
|
226
|
-
nodes: readonly KgNode[];
|
|
227
|
-
edges: readonly KgEdge[];
|
|
228
|
-
layers: readonly {
|
|
229
|
-
id: string;
|
|
230
|
-
name: string;
|
|
231
|
-
nodeIds: readonly string[];
|
|
232
|
-
}[];
|
|
233
|
-
}
|
|
234
|
-
export type KgNodeType = 'file' | 'function' | 'class' | 'module' | 'concept' | 'config' | 'document' | 'service' | 'table' | 'endpoint' | 'pipeline' | 'schema' | 'resource' | 'domain' | 'flow' | 'step';
|
|
235
|
-
export interface KgNode {
|
|
236
|
-
id: string;
|
|
237
|
-
type: KgNodeType;
|
|
238
|
-
name: string;
|
|
239
|
-
filePath?: string;
|
|
240
|
-
summary?: string;
|
|
241
|
-
tags: readonly string[];
|
|
242
|
-
complexity?: number;
|
|
243
|
-
}
|
|
244
|
-
export interface KgEdge {
|
|
245
|
-
source: string;
|
|
246
|
-
target: string;
|
|
247
|
-
type: string;
|
|
248
|
-
weight?: number;
|
|
249
|
-
}
|
|
250
209
|
export interface ImportEdgeRunner {
|
|
251
210
|
/**
|
|
252
211
|
* Returns real static import edges for the given file paths.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* The slice-decomposition algorithm is a 6-stage deterministic function
|
|
5
5
|
* (see `peaks-code/references/slice-algorithm.md` for the full spec):
|
|
6
6
|
*
|
|
7
|
-
* 1. workUnitResolution -- codegraph.query
|
|
7
|
+
* 1. workUnitResolution -- codegraph.query
|
|
8
8
|
* 2. buildDependencyDAG -- real import edges + codegraph.affected fallback
|
|
9
9
|
* 3. scc + criticalPath -- Tarjan + longest_path on the condensation
|
|
10
10
|
* 4. minCut -- Stoer-Wagner with semantic-preference weights
|
|
@@ -21,7 +21,8 @@
|
|
|
21
21
|
* - `peaks-rd` and `peaks-qa` in unit tests
|
|
22
22
|
* - user inspection via `cat .peaks/sc/slice-decomposition/<rid>.json`
|
|
23
23
|
*
|
|
24
|
-
*
|
|
24
|
+
* Project analysis is codegraph-first; structural import edges are the
|
|
25
|
+
* fallback. Codegraph is local project-analysis evidence; its output is
|
|
25
26
|
* **untrusted supporting evidence**, never authoritative for QA verdict.
|
|
26
27
|
* DecompositionResult fields derived from codegraph are tagged with
|
|
27
28
|
* `confidence: 'semantic' | 'structural'` so downstream consumers can
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* `'llm'` because LLM-arbitrated edges are neither — they were guessed
|
|
18
18
|
* by an LLM and must carry the arbitration trace via `arbitratedBy`.
|
|
19
19
|
*/
|
|
20
|
-
import type { CodegraphEnvelope
|
|
20
|
+
import type { CodegraphEnvelope } from './slice-decompose-types.js';
|
|
21
21
|
/** Schema discriminator. v1 files do NOT carry a `schemaVersion` field. */
|
|
22
22
|
export type SchemaVersion = 'v1' | 'v2';
|
|
23
23
|
/** How coarse a slice is. */
|
|
@@ -51,7 +51,7 @@ export interface SliceV2 {
|
|
|
51
51
|
readonly loc: number;
|
|
52
52
|
/** Parent slice id from the previous pass, or null for Pass 1. */
|
|
53
53
|
readonly parentSliceId: string | null;
|
|
54
|
-
/** Domain anchor; "
|
|
54
|
+
/** Domain anchor; always "file:<path>" (codegraph / structural evidence). */
|
|
55
55
|
readonly semanticAnchor: string;
|
|
56
56
|
}
|
|
57
57
|
/** Edge connecting two slices within the same pass. */
|
|
@@ -109,7 +109,6 @@ export interface DecompositionResultV2 {
|
|
|
109
109
|
readonly crossPassEdges: readonly CrossPassEdge[];
|
|
110
110
|
readonly llmArbitrations: readonly LlmArbitration[];
|
|
111
111
|
readonly codegraph: CodegraphEnvelope;
|
|
112
|
-
readonly understandAnything: UnderstandAnythingEnvelope;
|
|
113
112
|
/** True iff any pass failed to complete and the result is a partial. */
|
|
114
113
|
readonly partial: boolean;
|
|
115
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "peaks-loop",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.33",
|
|
4
4
|
"description": "Loop Engineering CLI — workflow primitive / loop guards / evaluators / slice orchestration",
|
|
5
5
|
"author": "SquabbyZ",
|
|
6
6
|
"keywords": [
|
|
@@ -101,10 +101,10 @@
|
|
|
101
101
|
"fzf": "^0.5.2",
|
|
102
102
|
"yaml": "^2.9.0",
|
|
103
103
|
"zod": "^4.4.3",
|
|
104
|
-
"peaks-loop-internal-runtime": "0.0.
|
|
105
|
-
"peaks-loop-shared
|
|
106
|
-
"peaks-loop-mut": "0.1.
|
|
107
|
-
"peaks-loop-shared": "0.0.
|
|
104
|
+
"peaks-loop-internal-runtime": "0.0.18",
|
|
105
|
+
"peaks-loop-shared": "0.0.67",
|
|
106
|
+
"peaks-loop-mut": "0.1.31",
|
|
107
|
+
"peaks-loop-shared-channel": "0.0.35"
|
|
108
108
|
},
|
|
109
109
|
"devDependencies": {
|
|
110
110
|
"@changesets/cli": "2.31.1",
|
|
@@ -8,7 +8,6 @@
|
|
|
8
8
|
"rid",
|
|
9
9
|
"generatedAt",
|
|
10
10
|
"codegraph",
|
|
11
|
-
"understandAnything",
|
|
12
11
|
"workUnits",
|
|
13
12
|
"dependencyDAG",
|
|
14
13
|
"sccAnalysis",
|
|
@@ -38,17 +37,6 @@
|
|
|
38
37
|
"note": { "type": "string" }
|
|
39
38
|
}
|
|
40
39
|
},
|
|
41
|
-
"understandAnything": {
|
|
42
|
-
"type": "object",
|
|
43
|
-
"required": ["kgNodes", "kgEdges", "available", "fallback", "note"],
|
|
44
|
-
"properties": {
|
|
45
|
-
"kgNodes": { "type": "integer", "minimum": 0 },
|
|
46
|
-
"kgEdges": { "type": "integer", "minimum": 0 },
|
|
47
|
-
"available": { "type": "boolean" },
|
|
48
|
-
"fallback": { "type": "string", "enum": ["semantic", "structural-only"] },
|
|
49
|
-
"note": { "type": "string" }
|
|
50
|
-
}
|
|
51
|
-
},
|
|
52
40
|
"workUnits": {
|
|
53
41
|
"type": "array",
|
|
54
42
|
"items": { "$ref": "#/$defs/WorkUnit" }
|
|
@@ -12,7 +12,6 @@
|
|
|
12
12
|
"crossPassEdges",
|
|
13
13
|
"llmArbitrations",
|
|
14
14
|
"codegraph",
|
|
15
|
-
"understandAnything",
|
|
16
15
|
"partial"
|
|
17
16
|
],
|
|
18
17
|
"properties": {
|
|
@@ -45,7 +44,6 @@
|
|
|
45
44
|
"items": { "$ref": "#/$defs/LlmArbitration" }
|
|
46
45
|
},
|
|
47
46
|
"codegraph": { "$ref": "#/$defs/CodegraphEnvelope" },
|
|
48
|
-
"understandAnything": { "$ref": "#/$defs/UnderstandAnythingEnvelope" },
|
|
49
47
|
"partial": {
|
|
50
48
|
"type": "boolean",
|
|
51
49
|
"description": "True iff any pass failed to complete and the result is a partial decomposition."
|
|
@@ -88,7 +86,7 @@
|
|
|
88
86
|
},
|
|
89
87
|
"semanticAnchor": {
|
|
90
88
|
"type": "string",
|
|
91
|
-
"description": "Domain anchor; \"
|
|
89
|
+
"description": "Domain anchor; always \"file:<path>\" (codegraph / structural evidence)."
|
|
92
90
|
}
|
|
93
91
|
}
|
|
94
92
|
},
|
|
@@ -176,18 +174,6 @@
|
|
|
176
174
|
"affectedCrossFile": { "type": "boolean" },
|
|
177
175
|
"note": { "type": "string" }
|
|
178
176
|
}
|
|
179
|
-
},
|
|
180
|
-
"UnderstandAnythingEnvelope": {
|
|
181
|
-
"type": "object",
|
|
182
|
-
"description": "Understand-anything knowledge-graph envelope. `available: false` means semantic-only downstream behaviour is disabled.",
|
|
183
|
-
"required": ["kgNodes", "kgEdges", "available", "fallback", "note"],
|
|
184
|
-
"properties": {
|
|
185
|
-
"kgNodes": { "type": "integer", "minimum": 0 },
|
|
186
|
-
"kgEdges": { "type": "integer", "minimum": 0 },
|
|
187
|
-
"available": { "type": "boolean" },
|
|
188
|
-
"fallback": { "type": "string", "enum": ["semantic", "structural-only"] },
|
|
189
|
-
"note": { "type": "string" }
|
|
190
|
-
}
|
|
191
177
|
}
|
|
192
178
|
}
|
|
193
179
|
}
|
|
@@ -157,7 +157,6 @@ peaks openspec list --project <repo> --json
|
|
|
157
157
|
peaks openspec show <change-id> --project <repo> --json # when relevant
|
|
158
158
|
|
|
159
159
|
# 4. surface optional project-analysis evidence for the PRD body
|
|
160
|
-
peaks understand status --project <repo> --json # Chrome Code plugin output
|
|
161
160
|
peaks codegraph status --project <repo> # local index status
|
|
162
161
|
|
|
163
162
|
# 5. write goals / non-goals / acceptance into the artifact body, then hand off
|
|
@@ -217,7 +217,7 @@ Codegraph is local project-analysis evidence, scoped to red-line scope boundarie
|
|
|
217
217
|
|
|
218
218
|
## Matt Pocock skills integration
|
|
219
219
|
|
|
220
|
-
Matt Pocock skills (`diagnose` / `triage` / `tdd` / `improve-codebase-architecture` / `prototype`): engineering references only. Inspect before applying; Peaks-Loop RD gates remain authoritative.
|
|
220
|
+
Matt Pocock skills (`diagnose` / `triage` / `tdd` / `improve-codebase-architecture` / `prototype`): engineering references only. Inspect before applying; Peaks-Loop RD gates remain authoritative. Codegraph: project analysis is codegraph-first (`peaks codegraph context/affected`), structural import edges as the fallback; local analysis only, never commit `.codegraph/` artifacts. Other external resources: `peaks capabilities --source access-repo/mcp-server --json` for capability discovery.
|
|
221
221
|
|
|
222
222
|
→ see `references/external-references.md` + `references/matt-pocock-integration.md` + `references/codegraph-project-analysis.md`.
|
|
223
223
|
|
|
@@ -2,9 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> Body of `## External references`. **Matt Pocock skills** (`diagnose`, `triage`, `tdd`, `improve-codebase-architecture`, `prototype`): Engineering references only. Inspect before applying; Peaks-Loop RD gates remain authoritative.
|
|
4
4
|
|
|
5
|
-
**
|
|
6
|
-
|
|
7
|
-
**Codegraph**: Optional local analysis via `peaks codegraph context/affected`. Output as untrusted supporting evidence; never commit `.codegraph/` artifacts.
|
|
5
|
+
**Codegraph**: Project analysis is codegraph-first (`peaks codegraph context/affected`). Output as untrusted supporting evidence; never commit `.codegraph/` artifacts. When codegraph is unavailable, fall back to structural analysis (import edges + local project scan).
|
|
8
6
|
|
|
9
7
|
**Other external resources** (Context7, SearchCode, everything-claude-code, GitNexus, etc.): Use `peaks capabilities --source access-repo/mcp-server --json` for capability discovery before recommending. References only — do not execute upstream installers, do not install upstream resources, do not persist sensitive examples. Peaks-Loop RD gates remain authoritative.
|
|
10
8
|
|
|
@@ -46,7 +46,12 @@ Note: sub-agent 1 (code-reviewer) and sub-agent 3 (karpathy-reviewer) write to `
|
|
|
46
46
|
- Inspect for: correctness, type safety, error handling, mutation patterns, file-size, naming, dead code, regressions, contract drift.
|
|
47
47
|
- Output: `.peaks/_runtime/<sessionId>/rd/code-review.md` with sections: Summary, Findings, Required Fixes, Recommended, Verdict.
|
|
48
48
|
- Required for Gate B3.
|
|
49
|
-
- **v2.11.0 Tier 7 (Group D):** the code-reviewer dispatch goes through the **ECC bridge** (`src/services/code-review/ecc-bridge.ts`).
|
|
49
|
+
- **v2.11.0 Tier 7 (Group D) + 2026-09-09-ecc-dynamic:** the code-reviewer dispatch goes through the **ECC bridge** (`src/services/code-review/ecc-bridge.ts`). Fallback order is **native plugin → cache-backed generic agent → inline**:
|
|
50
|
+
1. **Native plugin** (`detectEcc` state `ready`): invoke the Agent tool with `subagent_type: "ecc:code-reviewer"` (plugin `ecc` + agent `code-reviewer`; see `DEFAULT_NATIVE_ECC_AGENT_ID`); it returns the structured envelope `{ passed, violations[], gateAction }`.
|
|
51
|
+
2. **Cache-backed generic agent** (`detectEcc` state `ready-via-cache` — plugin or its review agent absent, but a materialized ECC agent exists under `~/.peaks/agents/ecc/`): resolve the agent's REAL name first — `resolveMaterializedAgentName(['code-reviewer', 'code-review'])` from `peaks-loop-mut` (upstream ships `code-reviewer.md`; a hardcoded `code-review.md` never resolves). Read `~/.peaks/agents/ecc/<resolved>.md`, pass the name through as `detectEcc({ ..., cacheAgentName: resolved })`, build the prompt with `buildCacheBackedEccPrompt({ rid, instructions, diff })` (agent body + diff + `ECC_OUTPUT_CONTRACT`), dispatch a **generic** sub-agent, and validate its reply with `isEccEnvelope`. No ECC plugin required. If the cache is empty, run `peaks ecc install` first (dynamic acquisition); if that fails offline, degrade to inline.
|
|
52
|
+
3. **Inline** (`detectEcc` states `plugin-missing` / `agent-missing` / `dispatch-failed` / `envelope-malformed`): fall back to inline review — TXT note `code-review-ecc-degraded-to-inline`.
|
|
53
|
+
|
|
54
|
+
In all dispatchable cases the envelope is rendered by the SAME bridge adapter (`adaptEccEnvelopeToRdCodeReview`) into the canonical `rd/code-review.md` markdown shape that Gate B3 reads (`mustContain: ['## Findings', 'CRITICAL']`). The materialized copy lives under `~/.peaks/agents/ecc/` — peaks-loop NEVER writes into `~/.claude/`.
|
|
50
55
|
|
|
51
56
|
**Sub-agent 2 — qa-test-cases-writer (always runs for feature / refactor / bugfix):**
|
|
52
57
|
- Read the git diff and the PRD acceptance criteria.
|
|
@@ -82,7 +87,7 @@ Note: sub-agent 1 (code-reviewer) and sub-agent 3 (karpathy-reviewer) write to `
|
|
|
82
87
|
|
|
83
88
|
**Degradation when a sub-agent fails or returns blocked:**
|
|
84
89
|
- code-review sub-agent fails: fall back to inline RD code review. TXT handoff note: `code-review-subagent-degraded-to-inline`.
|
|
85
|
-
- code-review sub-agent runs the ECC bridge but
|
|
90
|
+
- code-review sub-agent runs the ECC bridge but neither the native plugin nor the cache-backed path is available (plugin-missing / agent-missing / dispatch-failed / envelope-malformed per `detectEcc`): fall back to inline RD code review. TXT handoff note: `code-review-ecc-degraded-to-inline`.
|
|
86
91
|
- qa-test-cases sub-agent fails: fall back to inline QA test-case drafting at the start of QA's main loop. TXT note: `qa-test-cases-subagent-degraded-to-inline-qa-draft`.
|
|
87
92
|
- karpathy-reviewer sub-agent fails: NOT degradeable — its failure blocks qa-handoff. Per karpathy §1 Think Before Coding + §3 Surgical Changes, the file MUST exist with the gate header + at least one guideline marker.
|
|
88
93
|
- 2 or more fail: do not hand off as clean; transition to `qa-handoff` with `--allow-incomplete --reason "<degradation>"` OR block.
|
|
@@ -29,14 +29,28 @@ end of implementation, RD fires 3 sub-agents in parallel via
|
|
|
29
29
|
> **Karpathy pointer (Slice 1/6):** Each of the 3 sub-agents below operates under the 4 Karpathy guidelines. The canonical reference is `andrej-karpathy-skills:karpathy-guidelines` (full text) and `peaks-rd/SKILL.md` §"Karpathy enforcement". The dispatch primitive also injects the verbatim context block from `rd-sub-agent-dispatch.md` §"Karpathy-guidelines context" into every sub-agent prompt. Sub-agents MUST NOT silently drop the block.
|
|
30
30
|
|
|
31
31
|
- **Sub-agent 1 — code-reviewer** runs `code-review` against the diff and
|
|
32
|
-
writes `rd/code-review.md`. **v2.11.0 Tier 7 (Group D)
|
|
33
|
-
through the **ECC bridge** (`src/services/code-review/ecc-bridge.ts`)
|
|
34
|
-
|
|
35
|
-
`{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
32
|
+
writes `rd/code-review.md`. **v2.11.0 Tier 7 (Group D) + 2026-09-09-ecc-dynamic:**
|
|
33
|
+
the dispatch goes through the **ECC bridge** (`src/services/code-review/ecc-bridge.ts`)
|
|
34
|
+
with fallback order **native plugin → cache-backed generic agent → inline**:
|
|
35
|
+
- `detectEcc` state `ready` → `Agent({ subagent_type: 'ecc:code-reviewer', ... })`
|
|
36
|
+
(`DEFAULT_NATIVE_ECC_AGENT_ID` — plugin `ecc` + agent `code-reviewer`)
|
|
37
|
+
returns `{ passed, violations[], gateAction }`.
|
|
38
|
+
- `detectEcc` state `ready-via-cache` → resolve the materialized agent's REAL
|
|
39
|
+
name with `resolveMaterializedAgentName(['code-reviewer', 'code-review'])`
|
|
40
|
+
(upstream ships `code-reviewer.md`; a hardcoded `code-review.md` never
|
|
41
|
+
resolves), read `~/.peaks/agents/ecc/<resolved>.md`, pass it through as
|
|
42
|
+
`detectEcc({ ..., cacheAgentName: resolved })`, compose the prompt with
|
|
43
|
+
`buildCacheBackedEccPrompt({ rid, instructions, diff })`,
|
|
44
|
+
dispatch a **generic** sub-agent, and validate the reply with `isEccEnvelope`.
|
|
45
|
+
If the cache is empty, run `peaks ecc install` first (dynamic acquisition);
|
|
46
|
+
offline → inline.
|
|
47
|
+
- Any other state (plugin-missing / agent-missing / dispatch-failed /
|
|
48
|
+
envelope-malformed) → inline review; the `code-review-ecc-degraded-to-inline`
|
|
49
|
+
TXT note records the fallback.
|
|
50
|
+
|
|
51
|
+
Every dispatchable envelope is rendered by the SAME `adaptEccEnvelopeToRdCodeReview`
|
|
52
|
+
adapter to the canonical markdown. Materialized ECC instructions live under
|
|
53
|
+
`~/.peaks/agents/ecc/`; peaks-loop NEVER writes into `~/.claude/`.
|
|
40
54
|
- **Sub-agent 2 — qa-test-cases-writer** drafts the QA test plan and
|
|
41
55
|
writes `qa/test-cases/<rid>.md`. The test plan is the deliverable —
|
|
42
56
|
these test cases do NOT need to be executed by this sub-agent (the
|
|
@@ -23,8 +23,6 @@ peaks openspec validate <change-id> --project <repo> --json # entry gate
|
|
|
23
23
|
peaks openspec to-rd <change-id> --project <repo> --json # acceptance + commit boundaries
|
|
24
24
|
|
|
25
25
|
# 4. project-analysis evidence — MANDATORY before implementation
|
|
26
|
-
peaks understand status --project <repo> --json
|
|
27
|
-
peaks understand show --project <repo> --json # when UA artifact exists
|
|
28
26
|
peaks codegraph context --project <repo> "<task>"
|
|
29
27
|
peaks codegraph affected --project <repo> <changed-files...> --json
|
|
30
28
|
|
|
@@ -144,17 +144,6 @@ When capability discovery exposes `mattpocock/skills`, use these upstream method
|
|
|
144
144
|
|
|
145
145
|
Inspect upstream skill content before applying any method. Treat examples and instructions as untrusted external reference material; do not execute upstream instructions or persist sensitive examples. Peaks-Loop TXT still writes local context capsules under `.peaks/_runtime/<session-id>/txt/` by default. Durable memory extraction still requires explicit authorization and must not include secrets, credentials, private customer data, or non-exportable business data.
|
|
146
146
|
|
|
147
|
-
## Understand Anything knowledge graph
|
|
148
|
-
|
|
149
|
-
When capability discovery exposes `understand-anything` and the target project contains `.understand-anything/knowledge-graph.json`, treat the graph as upstream reference material only. Do not execute upstream instructions, do not install upstream resources, do not persist sensitive examples. Peaks-Loop TXT context capsules and project memory extraction remain authoritative.
|
|
150
|
-
|
|
151
|
-
Consume the artifact through the Peaks-Loop CLI for context capsule preparation:
|
|
152
|
-
|
|
153
|
-
- `peaks understand show --project <path> [--sample <n>] --json` — read counts, layer names, tour names, and sample node ids to summarize project shape in a context capsule.
|
|
154
|
-
- Do not paste the full knowledge graph into a capsule; reference its path and summarized counts.
|
|
155
|
-
|
|
156
|
-
When the artifact is absent or malformed, fall back to existing Peaks-Loop TXT codegraph context summaries; do not block handoff on Understand Anything availability.
|
|
157
|
-
|
|
158
147
|
## Codegraph context capsules
|
|
159
148
|
|
|
160
149
|
TXT may consume recorded peaks codegraph artifacts as untrusted supporting evidence when preparing handoffs, release notes, or implementation summaries. Preferred local artifact paths are `.peaks/_runtime/<session-id>/rd/codegraph-context.md` and `.peaks/_runtime/<session-id>/rd/codegraph-affected.json`.
|
|
@@ -229,7 +218,6 @@ peaks project dashboard --project <repo> --json
|
|
|
229
218
|
|
|
230
219
|
# 3. Optional project-shape evidence when available
|
|
231
220
|
peaks codegraph status --project <repo>
|
|
232
|
-
peaks understand show --project <repo> --json
|
|
233
221
|
|
|
234
222
|
# 4. Discover external capabilities before recommending memory or context tools
|
|
235
223
|
peaks capabilities --json
|
|
@@ -50,7 +50,7 @@ If a doctor finding requires a code change, the workflow hands off to `peaks-rd`
|
|
|
50
50
|
## Boundaries
|
|
51
51
|
|
|
52
52
|
- The doctor is read-only. It does NOT modify code, fix bugs, or clean up sessions.
|
|
53
|
-
- The doctor does NOT install
|
|
53
|
+
- The doctor does NOT install any third-party tool. It just reports state.
|
|
54
54
|
- The doctor does NOT generate change records automatically; it surfaces findings + the LLM calls `peaks openspec from-doctor` to generate them.
|
|
55
55
|
|
|
56
56
|
## References
|
|
@@ -84,7 +84,6 @@ The envelope is a `DecompositionResultV2` (see `references/v2-schema.md`):
|
|
|
84
84
|
| `crossPassEdges` | Edges spanning passes (see `references/cross-pass-edge-interpretation.md`). |
|
|
85
85
|
| `llmArbitrations` | Trace of every LLM call made during decomposition (capped at 2 per invocation). |
|
|
86
86
|
| `codegraph` | `CodegraphEnvelope` — nodes/edges/dbMB/freshness/affectedCrossFile/note. |
|
|
87
|
-
| `understandAnything` | `UnderstandAnythingEnvelope` — kgNodes/kgEdges/available/fallback/note. |
|
|
88
87
|
| `partial` | `true` iff any pass failed to complete. |
|
|
89
88
|
|
|
90
89
|
The file is pretty-printed (`JSON.stringify(result, null, 2)`). Size scales with `passes.length * slices.length` plus the arbitration trace; typical runs are 5–80 KB.
|