peaks-loop 4.0.31 → 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 +39 -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
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
* === Source: peaks-rd/references/parallel-review-fanout.md ===
|
|
32
32
|
*
|
|
33
33
|
* Sub-agent 1 contract (Tier 7 v2.11.0): the parent RD loop calls
|
|
34
|
-
* `Agent({ subagent_type: '
|
|
34
|
+
* `Agent({ subagent_type: 'ecc:code-reviewer', ... })`
|
|
35
35
|
* with the diff + handoff in scope, receives the structured envelope,
|
|
36
36
|
* then runs `adaptEccEnvelopeToRdCodeReview(env, { rid, generatedAt })`
|
|
37
37
|
* and writes the resulting body to
|
|
@@ -51,18 +51,43 @@ export interface EccEnvelope {
|
|
|
51
51
|
readonly gateAction: EccGateAction;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
54
|
+
* The real upstream ECC agent name for the code-review role:
|
|
55
|
+
* `~/.peaks/agents/ecc/code-reviewer.md`. Upstream ships `<lang>-reviewer`
|
|
56
|
+
* agents and has NO `code-review.md`, so this is the default the
|
|
57
|
+
* `ready-via-cache` nextActions name when the caller does not pass the
|
|
58
|
+
* output of `resolveMaterializedAgentName(['code-reviewer', 'code-review'])`.
|
|
59
|
+
*/
|
|
60
|
+
export declare const DEFAULT_CACHE_ECC_AGENT_NAME = "code-reviewer";
|
|
61
|
+
/**
|
|
62
|
+
* The native (plugin) ECC agent id dispatched through the Agent tool.
|
|
63
|
+
* Verified upstream: the plugin is named `ecc` (`.claude-plugin/plugin.json`,
|
|
64
|
+
* `marketplace.json`) and the agent's frontmatter `name` is `code-reviewer`
|
|
65
|
+
* (`~/.peaks/agents/ecc/code-reviewer.md`), so the composed id is
|
|
66
|
+
* `ecc:code-reviewer`. The previous id composed the OLD repo name
|
|
67
|
+
* (`everything-claude-code`) with a non-existent `code-review` agent, so it
|
|
68
|
+
* matched no registry entry and the native path silently fell through to
|
|
69
|
+
* inline review.
|
|
70
|
+
*/
|
|
71
|
+
export declare const DEFAULT_NATIVE_ECC_AGENT_ID = "ecc:code-reviewer";
|
|
72
|
+
/**
|
|
73
|
+
* 6-state ECC detection result:
|
|
55
74
|
* - `ready` — ECC plugin is installed and reachable
|
|
56
|
-
* - `
|
|
57
|
-
*
|
|
75
|
+
* - `ready-via-cache` — plugin/agent absent, but the materialized ECC
|
|
76
|
+
* review agent (real name `code-reviewer`, NOT
|
|
77
|
+
* `code-review`) exists under `~/.peaks/agents/ecc/`;
|
|
78
|
+
* dispatch a GENERIC sub-agent with that body
|
|
79
|
+
* - `plugin-missing` — `everything-claude-code` not in skill list and no materialized cache
|
|
80
|
+
* - `agent-missing` — plugin present but `code-review` agent absent and no materialized cache
|
|
58
81
|
* - `dispatch-failed` — Agent tool call threw before returning envelope
|
|
59
82
|
* - `envelope-malformed` — returned value failed `isEccEnvelope` validation
|
|
60
83
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
* the
|
|
84
|
+
* Fallback order (RD fan-out, 2026-09-09-ecc-dynamic): native plugin →
|
|
85
|
+
* cache-backed generic agent → inline. The caller (peaks-rd's sub-agent 1
|
|
86
|
+
* contract) inspects `state` and either proceeds with the envelope or records
|
|
87
|
+
* a degradation note in the request artifact body
|
|
88
|
+
* (`code-review-ecc-degraded-to-inline`).
|
|
64
89
|
*/
|
|
65
|
-
export type EccDetectState = 'ready' | 'plugin-missing' | 'agent-missing' | 'dispatch-failed' | 'envelope-malformed';
|
|
90
|
+
export type EccDetectState = 'ready' | 'ready-via-cache' | 'plugin-missing' | 'agent-missing' | 'dispatch-failed' | 'envelope-malformed';
|
|
66
91
|
export interface EccDetectResult {
|
|
67
92
|
readonly state: EccDetectState;
|
|
68
93
|
readonly pluginInstalled: boolean;
|
|
@@ -105,39 +130,93 @@ export declare function adaptEccEnvelopeToRdCodeReview(env: EccEnvelope, opts: {
|
|
|
105
130
|
generatedAt: string;
|
|
106
131
|
}): RdCodeReviewDoc;
|
|
107
132
|
/**
|
|
108
|
-
*
|
|
133
|
+
* 6-state detector — mirrors `detectOcr`'s shape (state enum + warnings
|
|
109
134
|
* + nextActions). The caller passes in the result of its own probe:
|
|
110
135
|
*
|
|
111
136
|
* - `pluginInstalled`: did the skill list scan find `everything-claude-code`?
|
|
112
137
|
* - `agentAvailable`: did the Agent tool say `code-review` is registered?
|
|
138
|
+
* - `cacheAgentAvailable`: does the resolved materialized agent exist
|
|
139
|
+
* (`~/.peaks/agents/ecc/<cacheAgentName>.md`, default `code-reviewer`)?
|
|
113
140
|
* - `dispatchError`: optional — the Agent tool threw before returning.
|
|
114
141
|
* - `envelope`: optional — what came back (if anything).
|
|
115
142
|
*
|
|
116
|
-
* The detector never blocks: when state
|
|
117
|
-
*
|
|
118
|
-
*
|
|
143
|
+
* The detector never blocks: when the state is not dispatchable
|
|
144
|
+
* (`ready` / `ready-via-cache`), the parent RD loop records a
|
|
145
|
+
* `code-review-ecc-degraded-to-inline` note and falls back to inline
|
|
146
|
+
* review. This matches `detectOcr`'s soft-fail policy.
|
|
147
|
+
*
|
|
148
|
+
* Backward compat: the native id is `DEFAULT_NATIVE_ECC_AGENT_ID`
|
|
149
|
+
* (`ecc:code-reviewer` — plugin `ecc`, agent `code-reviewer`). A registry
|
|
150
|
+
* that still exposes the OLD `everything-claude-code` plugin id will not
|
|
151
|
+
* match it, so the operator should pin the id explicitly. peaks-loop
|
|
152
|
+
* cannot enumerate the user's plugin registry: detection stays
|
|
153
|
+
* caller-supplied (`pluginInstalled` / `agentAvailable`), never probed here.
|
|
119
154
|
*/
|
|
120
155
|
export declare function detectEcc(input: {
|
|
121
156
|
readonly pluginInstalled: boolean;
|
|
122
157
|
readonly agentAvailable: boolean;
|
|
158
|
+
/**
|
|
159
|
+
* Did the caller find the materialized review agent (written by
|
|
160
|
+
* `peaks ecc install` / `materializeEccAgents`) under `~/.peaks/agents/ecc/`?
|
|
161
|
+
* When true and the native plugin path is unavailable, `state` becomes
|
|
162
|
+
* `ready-via-cache` so the RD loop can dispatch a generic sub-agent with
|
|
163
|
+
* the materialized body.
|
|
164
|
+
*/
|
|
165
|
+
readonly cacheAgentAvailable?: boolean;
|
|
166
|
+
/**
|
|
167
|
+
* Resolved materialized agent name — pass
|
|
168
|
+
* `resolveMaterializedAgentName(['code-reviewer', 'code-review'])` from
|
|
169
|
+
* `peaks-loop-mut`. Defaults to `code-reviewer` (the real upstream name);
|
|
170
|
+
* upstream has no `code-review.md`.
|
|
171
|
+
*/
|
|
172
|
+
readonly cacheAgentName?: string;
|
|
123
173
|
readonly dispatchError?: unknown;
|
|
124
174
|
readonly envelope?: unknown;
|
|
125
175
|
}): EccDetectResult;
|
|
126
176
|
/**
|
|
127
177
|
* Convenience: run `detectEcc` and `adaptEccEnvelopeToRdCodeReview`
|
|
128
178
|
* in one call. The parent RD loop calls this after the Agent tool
|
|
129
|
-
* returns. When `detectEcc` returns
|
|
130
|
-
*
|
|
131
|
-
*
|
|
179
|
+
* returns. When `detectEcc` returns a non-dispatchable state
|
|
180
|
+
* (`plugin-missing` / `agent-missing` / `dispatch-failed` /
|
|
181
|
+
* `envelope-malformed`), the caller should NOT call
|
|
182
|
+
* `adaptEccEnvelopeToRdCodeReview` — fall back to inline review instead.
|
|
183
|
+
*
|
|
184
|
+
* Both `ready` (native plugin) and `ready-via-cache` (materialized generic
|
|
185
|
+
* agent) adapt the envelope through the SAME bridge.
|
|
132
186
|
*/
|
|
133
187
|
export declare function runEccCodeReview(input: {
|
|
134
188
|
readonly rid: string;
|
|
135
189
|
readonly generatedAt: string;
|
|
136
190
|
readonly pluginInstalled: boolean;
|
|
137
191
|
readonly agentAvailable: boolean;
|
|
192
|
+
readonly cacheAgentAvailable?: boolean;
|
|
193
|
+
/** Resolved materialized agent name (see `detectEcc`); defaults to `code-reviewer`. */
|
|
194
|
+
readonly cacheAgentName?: string;
|
|
138
195
|
readonly dispatchError?: unknown;
|
|
139
196
|
readonly envelope?: unknown;
|
|
140
197
|
}): {
|
|
141
198
|
detect: EccDetectResult;
|
|
142
199
|
doc: RdCodeReviewDoc | null;
|
|
143
200
|
};
|
|
201
|
+
/**
|
|
202
|
+
* The exact JSON shape the generic (cache-backed) sub-agent MUST return.
|
|
203
|
+
* Kept as a const so the RD reference docs and the prompt builder cannot
|
|
204
|
+
* drift: `isEccEnvelope` is the authoritative validator.
|
|
205
|
+
*/
|
|
206
|
+
export declare const ECC_OUTPUT_CONTRACT: string;
|
|
207
|
+
/**
|
|
208
|
+
* Compose the plugin-free dispatch prompt for sub-agent 1.
|
|
209
|
+
*
|
|
210
|
+
* `instructions` is the body of the materialized review agent
|
|
211
|
+
* (`~/.peaks/agents/ecc/code-reviewer.md` — resolve the real name with
|
|
212
|
+
* `resolveMaterializedAgentName`, never hardcode `code-review.md`);
|
|
213
|
+
* `diff` is the slice diff. The
|
|
214
|
+
* composed prompt is handed to a GENERIC sub-agent (no ECC plugin needed)
|
|
215
|
+
* and its reply is validated with `isEccEnvelope`, then rendered by
|
|
216
|
+
* `adaptEccEnvelopeToRdCodeReview` — the same bridge the native path uses.
|
|
217
|
+
*/
|
|
218
|
+
export declare function buildCacheBackedEccPrompt(input: {
|
|
219
|
+
readonly rid: string;
|
|
220
|
+
readonly instructions: string;
|
|
221
|
+
readonly diff: string;
|
|
222
|
+
}): string;
|
|
@@ -1,3 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The real upstream ECC agent name for the code-review role:
|
|
3
|
+
* `~/.peaks/agents/ecc/code-reviewer.md`. Upstream ships `<lang>-reviewer`
|
|
4
|
+
* agents and has NO `code-review.md`, so this is the default the
|
|
5
|
+
* `ready-via-cache` nextActions name when the caller does not pass the
|
|
6
|
+
* output of `resolveMaterializedAgentName(['code-reviewer', 'code-review'])`.
|
|
7
|
+
*/
|
|
8
|
+
export const DEFAULT_CACHE_ECC_AGENT_NAME = 'code-reviewer';
|
|
9
|
+
/**
|
|
10
|
+
* The native (plugin) ECC agent id dispatched through the Agent tool.
|
|
11
|
+
* Verified upstream: the plugin is named `ecc` (`.claude-plugin/plugin.json`,
|
|
12
|
+
* `marketplace.json`) and the agent's frontmatter `name` is `code-reviewer`
|
|
13
|
+
* (`~/.peaks/agents/ecc/code-reviewer.md`), so the composed id is
|
|
14
|
+
* `ecc:code-reviewer`. The previous id composed the OLD repo name
|
|
15
|
+
* (`everything-claude-code`) with a non-existent `code-review` agent, so it
|
|
16
|
+
* matched no registry entry and the native path silently fell through to
|
|
17
|
+
* inline review.
|
|
18
|
+
*/
|
|
19
|
+
export const DEFAULT_NATIVE_ECC_AGENT_ID = 'ecc:code-reviewer';
|
|
20
|
+
/** Materialized path hint for the cache-backed agent, e.g. `~/.peaks/agents/ecc/code-reviewer.md`. */
|
|
21
|
+
function materializedAgentPath(name) {
|
|
22
|
+
const resolved = name !== undefined && name.length > 0 ? name : DEFAULT_CACHE_ECC_AGENT_NAME;
|
|
23
|
+
return `~/.peaks/agents/ecc/${resolved}.md`;
|
|
24
|
+
}
|
|
1
25
|
/**
|
|
2
26
|
* Validate a raw value as an EccEnvelope. Accepts the strict shape
|
|
3
27
|
* only — extra fields are tolerated (forward-compat for ECC adding
|
|
@@ -82,7 +106,7 @@ export function adaptEccEnvelopeToRdCodeReview(env, opts) {
|
|
|
82
106
|
`## Summary`,
|
|
83
107
|
'',
|
|
84
108
|
`- generatedAt: ${opts.generatedAt}`,
|
|
85
|
-
`- source:
|
|
109
|
+
`- source: ${DEFAULT_NATIVE_ECC_AGENT_ID} (Tier 7 bridge)`,
|
|
86
110
|
`- gateAction: ${env.gateAction}`,
|
|
87
111
|
`- passed: ${env.passed}`,
|
|
88
112
|
`- violations: ${env.violations.length}`,
|
|
@@ -146,43 +170,87 @@ function renderFindings(violations) {
|
|
|
146
170
|
return ['## Findings', '', ...bullets, ''].join('\n');
|
|
147
171
|
}
|
|
148
172
|
/**
|
|
149
|
-
*
|
|
173
|
+
* 6-state detector — mirrors `detectOcr`'s shape (state enum + warnings
|
|
150
174
|
* + nextActions). The caller passes in the result of its own probe:
|
|
151
175
|
*
|
|
152
176
|
* - `pluginInstalled`: did the skill list scan find `everything-claude-code`?
|
|
153
177
|
* - `agentAvailable`: did the Agent tool say `code-review` is registered?
|
|
178
|
+
* - `cacheAgentAvailable`: does the resolved materialized agent exist
|
|
179
|
+
* (`~/.peaks/agents/ecc/<cacheAgentName>.md`, default `code-reviewer`)?
|
|
154
180
|
* - `dispatchError`: optional — the Agent tool threw before returning.
|
|
155
181
|
* - `envelope`: optional — what came back (if anything).
|
|
156
182
|
*
|
|
157
|
-
* The detector never blocks: when state
|
|
158
|
-
*
|
|
159
|
-
*
|
|
183
|
+
* The detector never blocks: when the state is not dispatchable
|
|
184
|
+
* (`ready` / `ready-via-cache`), the parent RD loop records a
|
|
185
|
+
* `code-review-ecc-degraded-to-inline` note and falls back to inline
|
|
186
|
+
* review. This matches `detectOcr`'s soft-fail policy.
|
|
187
|
+
*
|
|
188
|
+
* Backward compat: the native id is `DEFAULT_NATIVE_ECC_AGENT_ID`
|
|
189
|
+
* (`ecc:code-reviewer` — plugin `ecc`, agent `code-reviewer`). A registry
|
|
190
|
+
* that still exposes the OLD `everything-claude-code` plugin id will not
|
|
191
|
+
* match it, so the operator should pin the id explicitly. peaks-loop
|
|
192
|
+
* cannot enumerate the user's plugin registry: detection stays
|
|
193
|
+
* caller-supplied (`pluginInstalled` / `agentAvailable`), never probed here.
|
|
160
194
|
*/
|
|
161
195
|
export function detectEcc(input) {
|
|
162
196
|
const warnings = [];
|
|
163
197
|
const nextActions = [];
|
|
198
|
+
const cacheAgentAvailable = input.cacheAgentAvailable === true;
|
|
199
|
+
const cacheAgentPath = materializedAgentPath(input.cacheAgentName);
|
|
164
200
|
if (!input.pluginInstalled) {
|
|
201
|
+
if (cacheAgentAvailable) {
|
|
202
|
+
return {
|
|
203
|
+
state: 'ready-via-cache',
|
|
204
|
+
pluginInstalled: false,
|
|
205
|
+
agentAvailable: false,
|
|
206
|
+
warnings: [
|
|
207
|
+
'ECC Claude Code plugin is not installed; using the cache-backed generic agent instead.'
|
|
208
|
+
],
|
|
209
|
+
nextActions: [
|
|
210
|
+
`Dispatch a generic sub-agent with the body of \`${cacheAgentPath}\` (see \`buildCacheBackedEccPrompt\`).`,
|
|
211
|
+
'Refresh the materialized copy with `peaks ecc install`.',
|
|
212
|
+
'Install the `ecc` plugin for the native path (optional; native plugin → cache-backed → inline).'
|
|
213
|
+
]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
165
216
|
return {
|
|
166
217
|
state: 'plugin-missing',
|
|
167
218
|
pluginInstalled: false,
|
|
168
219
|
agentAvailable: false,
|
|
169
220
|
warnings,
|
|
170
221
|
nextActions: [
|
|
171
|
-
'Install the `
|
|
172
|
-
'
|
|
222
|
+
'Install the `ecc` plugin (Claude Code marketplace).',
|
|
223
|
+
'Or run `peaks ecc install` to populate the cache-backed generic agent path.',
|
|
224
|
+
'Until one of the two is available, peaks-rd falls back to inline code review (degradation note: code-review-ecc-degraded-to-inline).'
|
|
173
225
|
]
|
|
174
226
|
};
|
|
175
227
|
}
|
|
176
228
|
if (!input.agentAvailable) {
|
|
229
|
+
if (cacheAgentAvailable) {
|
|
230
|
+
return {
|
|
231
|
+
state: 'ready-via-cache',
|
|
232
|
+
pluginInstalled: true,
|
|
233
|
+
agentAvailable: false,
|
|
234
|
+
warnings: [
|
|
235
|
+
'`ecc` is installed but its `code-reviewer` agent is not registered; using the cache-backed generic agent instead.'
|
|
236
|
+
],
|
|
237
|
+
nextActions: [
|
|
238
|
+
`Dispatch a generic sub-agent with the body of \`${cacheAgentPath}\` (see \`buildCacheBackedEccPrompt\`).`,
|
|
239
|
+
'Verify the plugin is enabled in your Claude Code settings (MCP servers / agent registry) to restore the native path.'
|
|
240
|
+
]
|
|
241
|
+
};
|
|
242
|
+
}
|
|
177
243
|
return {
|
|
178
244
|
state: 'agent-missing',
|
|
179
245
|
pluginInstalled: true,
|
|
180
246
|
agentAvailable: false,
|
|
181
247
|
warnings: [
|
|
182
|
-
'`
|
|
248
|
+
'`ecc` is installed but its `code-reviewer` agent is not registered.'
|
|
183
249
|
],
|
|
184
250
|
nextActions: [
|
|
185
251
|
'Verify the plugin is enabled in your Claude Code settings (MCP servers / agent registry).',
|
|
252
|
+
`If your registry still exposes the old \`everything-claude-code\` plugin id, pin the native agent id explicitly (\`${DEFAULT_NATIVE_ECC_AGENT_ID}\`) instead of relying on detection.`,
|
|
253
|
+
'Or run `peaks ecc install` to populate the cache-backed generic agent path.',
|
|
186
254
|
'Until resolved, peaks-rd falls back to inline code review.'
|
|
187
255
|
]
|
|
188
256
|
};
|
|
@@ -226,17 +294,69 @@ export function detectEcc(input) {
|
|
|
226
294
|
/**
|
|
227
295
|
* Convenience: run `detectEcc` and `adaptEccEnvelopeToRdCodeReview`
|
|
228
296
|
* in one call. The parent RD loop calls this after the Agent tool
|
|
229
|
-
* returns. When `detectEcc` returns
|
|
230
|
-
*
|
|
231
|
-
*
|
|
297
|
+
* returns. When `detectEcc` returns a non-dispatchable state
|
|
298
|
+
* (`plugin-missing` / `agent-missing` / `dispatch-failed` /
|
|
299
|
+
* `envelope-malformed`), the caller should NOT call
|
|
300
|
+
* `adaptEccEnvelopeToRdCodeReview` — fall back to inline review instead.
|
|
301
|
+
*
|
|
302
|
+
* Both `ready` (native plugin) and `ready-via-cache` (materialized generic
|
|
303
|
+
* agent) adapt the envelope through the SAME bridge.
|
|
232
304
|
*/
|
|
233
305
|
export function runEccCodeReview(input) {
|
|
234
306
|
const detect = detectEcc(input);
|
|
235
|
-
|
|
307
|
+
const dispatchable = detect.state === 'ready' || detect.state === 'ready-via-cache';
|
|
308
|
+
if (!dispatchable || input.envelope === undefined) {
|
|
236
309
|
return { detect, doc: null };
|
|
237
310
|
}
|
|
238
|
-
//
|
|
311
|
+
// A dispatchable state implies input.envelope passed isEccEnvelope; the runtime
|
|
239
312
|
// type is therefore EccEnvelope, not `unknown`. Cast is justified by detect's contract.
|
|
240
313
|
const env = input.envelope;
|
|
241
314
|
return { detect, doc: adaptEccEnvelopeToRdCodeReview(env, { rid: input.rid, generatedAt: input.generatedAt }) };
|
|
242
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* The exact JSON shape the generic (cache-backed) sub-agent MUST return.
|
|
318
|
+
* Kept as a const so the RD reference docs and the prompt builder cannot
|
|
319
|
+
* drift: `isEccEnvelope` is the authoritative validator.
|
|
320
|
+
*/
|
|
321
|
+
export const ECC_OUTPUT_CONTRACT = [
|
|
322
|
+
'Return ONLY a single JSON object (no prose, no markdown fence) with this exact shape:',
|
|
323
|
+
'{',
|
|
324
|
+
' "passed": boolean,',
|
|
325
|
+
' "violations": [{ "kind": string, "line": number, "snippet": string, "hint": string }],',
|
|
326
|
+
' "gateAction": "pass" | "warn" | "block"',
|
|
327
|
+
'}',
|
|
328
|
+
'`kind` is one of: correctness, type-safety, error-handling, mutation, file-size, naming, dead-code, regression, contract-drift, other.',
|
|
329
|
+
'`gateAction: "block"` requires at least one violation; `pass` requires an empty violations array.'
|
|
330
|
+
].join('\n');
|
|
331
|
+
/**
|
|
332
|
+
* Compose the plugin-free dispatch prompt for sub-agent 1.
|
|
333
|
+
*
|
|
334
|
+
* `instructions` is the body of the materialized review agent
|
|
335
|
+
* (`~/.peaks/agents/ecc/code-reviewer.md` — resolve the real name with
|
|
336
|
+
* `resolveMaterializedAgentName`, never hardcode `code-review.md`);
|
|
337
|
+
* `diff` is the slice diff. The
|
|
338
|
+
* composed prompt is handed to a GENERIC sub-agent (no ECC plugin needed)
|
|
339
|
+
* and its reply is validated with `isEccEnvelope`, then rendered by
|
|
340
|
+
* `adaptEccEnvelopeToRdCodeReview` — the same bridge the native path uses.
|
|
341
|
+
*/
|
|
342
|
+
export function buildCacheBackedEccPrompt(input) {
|
|
343
|
+
return [
|
|
344
|
+
'# Code review (ECC cache-backed generic agent)',
|
|
345
|
+
'',
|
|
346
|
+
`Request: ${input.rid}`,
|
|
347
|
+
'',
|
|
348
|
+
`## Agent instructions (materialized from ${DEFAULT_NATIVE_ECC_AGENT_ID})`,
|
|
349
|
+
'',
|
|
350
|
+
input.instructions.trim(),
|
|
351
|
+
'',
|
|
352
|
+
'## Diff under review',
|
|
353
|
+
'',
|
|
354
|
+
'```diff',
|
|
355
|
+
input.diff.trim(),
|
|
356
|
+
'```',
|
|
357
|
+
'',
|
|
358
|
+
'## Required output',
|
|
359
|
+
'',
|
|
360
|
+
ECC_OUTPUT_CONTRACT
|
|
361
|
+
].join('\n');
|
|
362
|
+
}
|
|
@@ -12,12 +12,6 @@ export type ProjectDashboardOpenSpec = {
|
|
|
12
12
|
count: number;
|
|
13
13
|
changes: OpenSpecChangeSummary[];
|
|
14
14
|
};
|
|
15
|
-
export type ProjectDashboardUnderstand = {
|
|
16
|
-
exists: boolean;
|
|
17
|
-
graphExists: boolean;
|
|
18
|
-
graphPath: string;
|
|
19
|
-
parseError?: string;
|
|
20
|
-
};
|
|
21
15
|
export type ProjectDashboardDoctor = {
|
|
22
16
|
ok: boolean;
|
|
23
17
|
passed: number;
|
|
@@ -69,7 +63,6 @@ export type ProjectDashboard = {
|
|
|
69
63
|
okPolicy: DashboardOkPolicy;
|
|
70
64
|
requests: ProjectDashboardRequests;
|
|
71
65
|
openspec: ProjectDashboardOpenSpec;
|
|
72
|
-
understand: ProjectDashboardUnderstand;
|
|
73
66
|
doctor: ProjectDashboardDoctor;
|
|
74
67
|
runbookHealth: ProjectDashboardRunbookHealth;
|
|
75
68
|
capabilities: ProjectDashboardCapabilities;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { listRequestArtifacts } from '../artifacts/request-artifact-service.js';
|
|
2
2
|
import { scanOpenSpec } from '../openspec/openspec-scan-service.js';
|
|
3
|
-
import { scanUnderstandAnything } from '../understand/understand-scan-service.js';
|
|
4
3
|
import { seedCapabilityItems } from '../recommendations/capability-seed-items.js';
|
|
5
4
|
import { requiredSkillNames } from 'peaks-loop-shared/paths';
|
|
6
5
|
import { getSkillPresence } from '../skills/skill-presence-service.js';
|
|
@@ -107,10 +106,9 @@ export async function loadProjectDashboard(options) {
|
|
|
107
106
|
const clock = options.clock ?? defaultClock;
|
|
108
107
|
const sampleSize = options.sampleCapabilities ?? 8;
|
|
109
108
|
const okPolicy = options.okPolicy ?? 'workspace-only';
|
|
110
|
-
const [items, openspecReport,
|
|
109
|
+
const [items, openspecReport, doctorAndRunbook] = await Promise.all([
|
|
111
110
|
listRequestArtifacts({ projectRoot: options.projectRoot }),
|
|
112
111
|
scanOpenSpec({ openspecRoot: `${options.projectRoot}/openspec` }),
|
|
113
|
-
scanUnderstandAnything({ projectRoot: options.projectRoot }),
|
|
114
112
|
loadDoctorAndRunbookHealth(options.doctorReport, options.runbookHealth)
|
|
115
113
|
]);
|
|
116
114
|
const okVerdict = resolveDashboardOk({
|
|
@@ -133,12 +131,6 @@ export async function loadProjectDashboard(options) {
|
|
|
133
131
|
count: openspecReport.changes.length,
|
|
134
132
|
changes: openspecReport.changes
|
|
135
133
|
},
|
|
136
|
-
understand: {
|
|
137
|
-
exists: understandReport.exists,
|
|
138
|
-
graphExists: understandReport.graph.exists,
|
|
139
|
-
graphPath: understandReport.graph.path,
|
|
140
|
-
...(understandReport.graph.parseError !== undefined ? { parseError: understandReport.graph.parseError } : {})
|
|
141
|
-
},
|
|
142
134
|
doctor: doctorAndRunbook.doctor,
|
|
143
135
|
runbookHealth: doctorAndRunbook.runbookHealth,
|
|
144
136
|
capabilities: buildCapabilitiesSummary(sampleSize),
|
|
@@ -76,7 +76,16 @@ export interface ProjectPreferences {
|
|
|
76
76
|
* dispatch *shape* (worker graph vs flat dispatch).
|
|
77
77
|
*/
|
|
78
78
|
readonly swarmMode: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Legacy UA opt-in prompt decision. The UA knowledge-graph surface was
|
|
81
|
+
* removed in 2026-09-09 (project analysis is codegraph-first); the field
|
|
82
|
+
* is retained only so legacy `.peaks/preferences.json` files keep parsing.
|
|
83
|
+
*/
|
|
79
84
|
readonly uaPrompt: UaPromptDecision;
|
|
85
|
+
/**
|
|
86
|
+
* Legacy AgentShield opt-in prompt decision. The ECC AgentShield
|
|
87
|
+
* subprocess was removed in 4.0.0-beta.11; retained for legacy parse.
|
|
88
|
+
*/
|
|
80
89
|
readonly agentShieldPrompt: UaPromptDecision;
|
|
81
90
|
readonly classifyConservatism: ClassifyConservatism;
|
|
82
91
|
readonly classifyRules: ClassifyRuleOverrides;
|
|
@@ -84,15 +93,15 @@ export interface ProjectPreferences {
|
|
|
84
93
|
/** Loop Autonomous (L4 14.5) toggle. Default: false — never auto-enable. */
|
|
85
94
|
readonly loopAutonomousEnabled: boolean;
|
|
86
95
|
/**
|
|
87
|
-
* L2.3 P2-a: ECC AgentShield subprocess toggle
|
|
96
|
+
* L2.3 P2-a: ECC AgentShield subprocess toggle — **frozen, no-op**.
|
|
88
97
|
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
98
|
+
* Slice 3 of 4.0.0-beta.11 removed the ECC AgentShield subprocess
|
|
99
|
+
* entirely (upstream ships no `ecc-agentshield` binary). The field is
|
|
100
|
+
* retained only so legacy `.peaks/preferences.json` files still parse
|
|
101
|
+
* (`static-service.ts` calls `loadPreferences` for back-compat and
|
|
102
|
+
* ignores the value). Setting it to `true` has no effect.
|
|
92
103
|
*
|
|
93
|
-
*
|
|
94
|
-
* `agentShieldEnabled: true` with ECC missing surfaces a soft
|
|
95
|
-
* "ECC not installed" warning and the audit still completes.
|
|
104
|
+
* Default: false.
|
|
96
105
|
*/
|
|
97
106
|
readonly agentShieldEnabled: boolean;
|
|
98
107
|
/**
|
|
@@ -98,7 +98,6 @@ export const seedCapabilityItems = [
|
|
|
98
98
|
capability('gitnexus.repo-intelligence', 'gitnexus', 'GitNexus Repository Intelligence', 'cli', 'repo-intelligence', ['engineer'], 'medium', 'local-repo-scan', 'Use local project scanning through Peaks RD.', 'Repository Intelligence', '仓库智能分析', 'Repository intelligence should be proxied through Peaks before use.', '仓库智能分析应先通过 Peaks 代理边界再使用。'),
|
|
99
99
|
capability('claude-code-best-practice.workflow-guidance', 'claude-code-best-practice', 'Claude Code Best Practice', 'doc', 'workflow-guidance', ['engineer'], 'low', 'peaks-built-in-rules', 'Use Peaks built-in workflow and review rules.', 'Claude Code Best Practice', 'Claude Code 最佳实践', 'Guidance for Claude Code engineering workflows.', 'Claude Code 工程工作流指导。'),
|
|
100
100
|
capability('superpowers.workflow-methodology', 'superpowers', 'Superpowers Methodology', 'workflow', 'workflow-methodology', ['product', 'engineer'], 'low', 'peaks-workflow-route', 'Use Peaks route/autonomous plans.', 'Superpowers Methodology', 'Superpowers 方法论', 'Workflow and artifact methodology reference.', '工作流与 artifact 方法论参考。'),
|
|
101
|
-
capability('understand-anything.knowledge-graph', 'understand-anything', 'Understand Anything Knowledge Graph', 'skill', 'project-analysis', ['engineer', 'product', 'qa'], 'low', 'peaks-codegraph-or-rd-scan', 'Use peaks codegraph or peaks RD project scan when Understand Anything is not installed. Optionally suggest installing it via Claude Code: /plugin marketplace add Lum1104/Understand-Anything then /plugin install understand-anything.', 'Understand Anything Knowledge Graph', 'Understand Anything 知识图谱', 'Multi-agent project knowledge graph that Peaks reads from .understand-anything/knowledge-graph.json when it has been generated by the Understand Anything plugin in Claude Code.', '通过 Claude Code 的 Understand Anything 插件生成的多 agent 知识图谱,Peaks 在 .understand-anything/knowledge-graph.json 存在时读取它作为项目分析证据。'),
|
|
102
101
|
capability('penpot.design-source', 'penpot', 'Penpot Design Source', 'doc', 'design-source', ['designer', 'engineer'], 'medium', 'manual-design-input', 'Ask for exported design notes or screenshots.', 'Penpot Design Source', 'Penpot 设计来源', 'Design-source reference for UI planning.', '用于 UI 规划的设计来源参考。'),
|
|
103
102
|
capability('gstack.product-stack-guidance', 'gstack', 'Product Stack Guidance', 'doc', 'product-guidance', ['product'], 'low', 'peaks-prd', 'Use peaks-prd for product goals and non-goals.', 'Product Stack Guidance', '产品栈指导', 'Product and startup stack guidance reference.', '产品与创业栈指导参考。'),
|
|
104
103
|
capability('awesome-design-md.design-reference', 'awesome-design-md', 'Design Markdown Reference', 'doc', 'design-reference', ['designer', 'engineer'], 'low', 'peaks-ui-visual-direction', 'Use peaks-ui to define visual direction and interaction constraints.', 'Design Reference', '设计参考', 'Design markdown examples and inspiration.', '设计 markdown 示例与灵感。'),
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only "is this capability already satisfied on this machine?"
|
|
3
|
+
* detector for the capability catalog (`peaks capability status` /
|
|
4
|
+
* `peaks capabilities --source ...`).
|
|
5
|
+
*
|
|
6
|
+
* Slice B1 of 2026-09-09-ecc-dynamic-and-cleanup: the previous
|
|
7
|
+
* `getInstalledCapabilityIds()` returned `[]` unconditionally, so the
|
|
8
|
+
* catalog could never report anything as installed. This module answers
|
|
9
|
+
* the question from evidence that already exists on disk — no install
|
|
10
|
+
* side effect, no network, no subprocess:
|
|
11
|
+
*
|
|
12
|
+
* - `everything-claude-code.*` — satisfied when the ECC cache is
|
|
13
|
+
* populated (`~/.peaks/cache/ecc-installed.json` + at least one
|
|
14
|
+
* cached/materialized agent).
|
|
15
|
+
* - a source that maps to an npm package — satisfied when that package
|
|
16
|
+
* (or its `.bin` shim) is present in the project's `node_modules`.
|
|
17
|
+
*
|
|
18
|
+
* Every probe is fail-soft: a throw degrades to "not installed" so the
|
|
19
|
+
* catalog never breaks because a probe failed.
|
|
20
|
+
*/
|
|
21
|
+
export type InstalledCapabilityProbe = {
|
|
22
|
+
/** Project whose `node_modules` is probed. */
|
|
23
|
+
readonly projectRoot: string;
|
|
24
|
+
/** Override for tests; defaults to `<projectRoot>/node_modules`. */
|
|
25
|
+
readonly nodeModulesDir?: string;
|
|
26
|
+
/** Override for tests; defaults to a live ECC cache probe. */
|
|
27
|
+
readonly eccCacheAvailable?: boolean;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Return the capabilityIds whose acquisition is already satisfied.
|
|
31
|
+
* Sorted + de-duplicated so the JSON envelope is stable across runs.
|
|
32
|
+
*/
|
|
33
|
+
export declare function detectInstalledCapabilityIds(probe: InstalledCapabilityProbe): string[];
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only "is this capability already satisfied on this machine?"
|
|
3
|
+
* detector for the capability catalog (`peaks capability status` /
|
|
4
|
+
* `peaks capabilities --source ...`).
|
|
5
|
+
*
|
|
6
|
+
* Slice B1 of 2026-09-09-ecc-dynamic-and-cleanup: the previous
|
|
7
|
+
* `getInstalledCapabilityIds()` returned `[]` unconditionally, so the
|
|
8
|
+
* catalog could never report anything as installed. This module answers
|
|
9
|
+
* the question from evidence that already exists on disk — no install
|
|
10
|
+
* side effect, no network, no subprocess:
|
|
11
|
+
*
|
|
12
|
+
* - `everything-claude-code.*` — satisfied when the ECC cache is
|
|
13
|
+
* populated (`~/.peaks/cache/ecc-installed.json` + at least one
|
|
14
|
+
* cached/materialized agent).
|
|
15
|
+
* - a source that maps to an npm package — satisfied when that package
|
|
16
|
+
* (or its `.bin` shim) is present in the project's `node_modules`.
|
|
17
|
+
*
|
|
18
|
+
* Every probe is fail-soft: a throw degrades to "not installed" so the
|
|
19
|
+
* catalog never breaks because a probe failed.
|
|
20
|
+
*/
|
|
21
|
+
import { existsSync } from 'node:fs';
|
|
22
|
+
import { join } from 'node:path';
|
|
23
|
+
import { hasMaterializedEccAgents, listCachedAgents } from 'peaks-loop-mut';
|
|
24
|
+
import { seedCapabilityItems } from './capability-seed-items.js';
|
|
25
|
+
const ECC_SOURCE_ID = 'everything-claude-code';
|
|
26
|
+
/**
|
|
27
|
+
* `sourceId` → npm package whose presence in `node_modules` satisfies the
|
|
28
|
+
* item's acquisition. Deliberately explicit: the catalog mixes repos,
|
|
29
|
+
* skills packages, MCP servers, and docs, and only a small subset is
|
|
30
|
+
* actually an npm dependency we can probe. Adding an entry here is the
|
|
31
|
+
* only change needed to make that source's items detectable.
|
|
32
|
+
*/
|
|
33
|
+
const NPM_PACKAGE_BY_SOURCE = {
|
|
34
|
+
codegraph: 'codegraph'
|
|
35
|
+
};
|
|
36
|
+
function packagePresent(nodeModulesDir, packageName) {
|
|
37
|
+
try {
|
|
38
|
+
return (existsSync(join(nodeModulesDir, packageName)) ||
|
|
39
|
+
existsSync(join(nodeModulesDir, '.bin', packageName)));
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function eccCacheAvailable() {
|
|
46
|
+
try {
|
|
47
|
+
// Cached agents imply the manifest + sha dir exist; the materialized
|
|
48
|
+
// plugin-free copy is checked independently so a hand-populated
|
|
49
|
+
// `~/.peaks/agents/ecc/` still counts as satisfied.
|
|
50
|
+
return listCachedAgents().length > 0 || hasMaterializedEccAgents();
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Return the capabilityIds whose acquisition is already satisfied.
|
|
58
|
+
* Sorted + de-duplicated so the JSON envelope is stable across runs.
|
|
59
|
+
*/
|
|
60
|
+
export function detectInstalledCapabilityIds(probe) {
|
|
61
|
+
const nodeModulesDir = probe.nodeModulesDir ?? join(probe.projectRoot, 'node_modules');
|
|
62
|
+
const eccAvailable = probe.eccCacheAvailable ?? eccCacheAvailable();
|
|
63
|
+
const installed = new Set();
|
|
64
|
+
for (const item of seedCapabilityItems) {
|
|
65
|
+
if (item.sourceId === ECC_SOURCE_ID) {
|
|
66
|
+
if (eccAvailable)
|
|
67
|
+
installed.add(item.capabilityId);
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
const packageName = NPM_PACKAGE_BY_SOURCE[item.sourceId];
|
|
71
|
+
if (packageName !== undefined && packagePresent(nodeModulesDir, packageName)) {
|
|
72
|
+
installed.add(item.capabilityId);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return [...installed].sort();
|
|
76
|
+
}
|
|
@@ -26,7 +26,7 @@ const PARENT_COMMANDS = new Set([
|
|
|
26
26
|
'qa', 'sc', 'txt', 'code-review', 'rd', 'sh', 'config', 'audit', 'codegraph',
|
|
27
27
|
'context', 'agent', 'capability', 'classify', 'gstack', 'gate',
|
|
28
28
|
'hook', 'hooks', 'log', 'loop', 'memory', 'perf', 'playwright', 'preferences',
|
|
29
|
-
'project', 'retrospective', 'slice', 'statusline', '
|
|
29
|
+
'project', 'retrospective', 'slice', 'statusline', 'workflow',
|
|
30
30
|
'migrate', 'mcp', 'doctor', 'help'
|
|
31
31
|
]);
|
|
32
32
|
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', 'build', 'coverage']);
|
|
@@ -65,7 +65,6 @@ export async function decompose(rid, prdMarkdown, projectRoot, opts = {}) {
|
|
|
65
65
|
const wantFile = granularity === 'file' || granularity === 'both' || granularity === 'auto';
|
|
66
66
|
const passes = [];
|
|
67
67
|
let codegraph = zeroCodegraph();
|
|
68
|
-
let understandAnything = zeroUnderstand();
|
|
69
68
|
let pass1WorkUnits = [];
|
|
70
69
|
if (wantService) {
|
|
71
70
|
const result1 = await decomposeSlices(rid, prdMarkdown, projectRoot, opts);
|
|
@@ -77,7 +76,6 @@ export async function decompose(rid, prdMarkdown, projectRoot, opts = {}) {
|
|
|
77
76
|
internalEdges: v1EdgesToV2(result1.dependencyDAG.edges)
|
|
78
77
|
});
|
|
79
78
|
codegraph = result1.codegraph;
|
|
80
|
-
understandAnything = result1.understandAnything;
|
|
81
79
|
}
|
|
82
80
|
if (wantFile) {
|
|
83
81
|
if (pass1WorkUnits.length > 0) {
|
|
@@ -115,7 +113,6 @@ export async function decompose(rid, prdMarkdown, projectRoot, opts = {}) {
|
|
|
115
113
|
internalEdges: v1EdgesToV2(result.dependencyDAG.edges)
|
|
116
114
|
});
|
|
117
115
|
codegraph = result.codegraph;
|
|
118
|
-
understandAnything = result.understandAnything;
|
|
119
116
|
}
|
|
120
117
|
}
|
|
121
118
|
let crossPassEdges = [];
|
|
@@ -136,7 +133,6 @@ export async function decompose(rid, prdMarkdown, projectRoot, opts = {}) {
|
|
|
136
133
|
crossPassEdges,
|
|
137
134
|
llmArbitrations,
|
|
138
135
|
codegraph,
|
|
139
|
-
understandAnything,
|
|
140
136
|
partial: false
|
|
141
137
|
};
|
|
142
138
|
}
|
|
@@ -214,12 +210,3 @@ function zeroCodegraph() {
|
|
|
214
210
|
note: 'no decomposition run'
|
|
215
211
|
};
|
|
216
212
|
}
|
|
217
|
-
function zeroUnderstand() {
|
|
218
|
-
return {
|
|
219
|
-
kgNodes: 0,
|
|
220
|
-
kgEdges: 0,
|
|
221
|
-
available: false,
|
|
222
|
-
fallback: 'structural-only',
|
|
223
|
-
note: 'no decomposition run'
|
|
224
|
-
};
|
|
225
|
-
}
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* the 800 LOC cap (mechanical verbatim move). `buildDependencyEdges` is
|
|
5
5
|
* the only exported entry point; the rest are internal helpers.
|
|
6
6
|
*/
|
|
7
|
-
import type { DependencyEdge, ImportEdge,
|
|
8
|
-
export declare function buildDependencyEdges(wus: readonly WorkUnit[], importEdges: readonly ImportEdge[],
|
|
7
|
+
import type { DependencyEdge, ImportEdge, WorkUnit } from './slice-decompose-types.js';
|
|
8
|
+
export declare function buildDependencyEdges(wus: readonly WorkUnit[], importEdges: readonly ImportEdge[], projectRoot: string): DependencyEdge[];
|