edsger 0.68.0 → 0.70.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/github.d.ts +23 -0
- package/dist/api/github.js +61 -0
- package/dist/commands/architecture-diagram/index.d.ts +8 -0
- package/dist/commands/architecture-diagram/index.js +10 -0
- package/dist/commands/class-diagram/index.d.ts +7 -0
- package/dist/commands/class-diagram/index.js +9 -0
- package/dist/commands/data-flow/index.d.ts +8 -6
- package/dist/commands/data-flow/index.js +21 -12
- package/dist/commands/diagram-shared/index.d.ts +21 -0
- package/dist/commands/diagram-shared/index.js +37 -0
- package/dist/commands/er-diagram/index.d.ts +19 -0
- package/dist/commands/er-diagram/index.js +55 -0
- package/dist/commands/flowchart/index.d.ts +8 -0
- package/dist/commands/flowchart/index.js +10 -0
- package/dist/commands/quality-benchmark/index.js +43 -9
- package/dist/commands/recipes/index.d.ts +3 -1
- package/dist/commands/recipes/index.js +10 -4
- package/dist/commands/screen-flow/index.d.ts +8 -6
- package/dist/commands/screen-flow/index.js +21 -12
- package/dist/commands/sequence-diagram/index.d.ts +19 -0
- package/dist/commands/sequence-diagram/index.js +55 -0
- package/dist/commands/state-diagram/index.d.ts +7 -0
- package/dist/commands/state-diagram/index.js +9 -0
- package/dist/index.js +144 -14
- package/dist/phases/architecture-diagram/index.d.ts +15 -0
- package/dist/phases/architecture-diagram/index.js +51 -0
- package/dist/phases/class-diagram/index.d.ts +14 -0
- package/dist/phases/class-diagram/index.js +76 -0
- package/dist/phases/data-flow/index.d.ts +6 -3
- package/dist/phases/data-flow/index.js +59 -38
- package/dist/phases/data-flow/mcp-server.d.ts +1 -1
- package/dist/phases/data-flow/mcp-server.js +2 -2
- package/dist/phases/data-flow/types.d.ts +1 -1
- package/dist/phases/data-flow/types.js +1 -1
- package/dist/phases/diagram-shared/clone-repos.d.ts +63 -0
- package/dist/phases/diagram-shared/clone-repos.js +153 -0
- package/dist/phases/diagram-shared/generate.d.ts +42 -0
- package/dist/phases/diagram-shared/generate.js +162 -0
- package/dist/phases/diagram-shared/graph.d.ts +62 -0
- package/dist/phases/diagram-shared/graph.js +169 -0
- package/dist/phases/diagram-shared/mcp.d.ts +35 -0
- package/dist/phases/diagram-shared/mcp.js +68 -0
- package/dist/phases/diagram-shared/prompts.d.ts +23 -0
- package/dist/phases/diagram-shared/prompts.js +35 -0
- package/dist/phases/er-diagram/index.d.ts +28 -0
- package/dist/phases/er-diagram/index.js +290 -0
- package/dist/phases/er-diagram/mcp-server.d.ts +77 -0
- package/dist/phases/er-diagram/mcp-server.js +144 -0
- package/dist/phases/er-diagram/prompts.d.ts +14 -0
- package/dist/phases/er-diagram/prompts.js +36 -0
- package/dist/phases/er-diagram/types.d.ts +76 -0
- package/dist/phases/er-diagram/types.js +84 -0
- package/dist/phases/flow-shared/clone-repos.d.ts +8 -2
- package/dist/phases/flow-shared/clone-repos.js +36 -18
- package/dist/phases/flowchart/index.d.ts +15 -0
- package/dist/phases/flowchart/index.js +50 -0
- package/dist/phases/output-contracts.js +178 -2
- package/dist/phases/recipes/index.d.ts +8 -1
- package/dist/phases/recipes/index.js +74 -17
- package/dist/phases/recipes/mcp-server.d.ts +4 -1
- package/dist/phases/recipes/mcp-server.js +43 -18
- package/dist/phases/screen-flow/index.d.ts +7 -4
- package/dist/phases/screen-flow/index.js +66 -45
- package/dist/phases/screen-flow/mcp-server.js +2 -2
- package/dist/phases/sequence-diagram/index.d.ts +30 -0
- package/dist/phases/sequence-diagram/index.js +290 -0
- package/dist/phases/sequence-diagram/mcp-server.d.ts +64 -0
- package/dist/phases/sequence-diagram/mcp-server.js +134 -0
- package/dist/phases/sequence-diagram/prompts.d.ts +14 -0
- package/dist/phases/sequence-diagram/prompts.js +36 -0
- package/dist/phases/sequence-diagram/types.d.ts +52 -0
- package/dist/phases/sequence-diagram/types.js +93 -0
- package/dist/phases/state-diagram/index.d.ts +15 -0
- package/dist/phases/state-diagram/index.js +53 -0
- package/dist/skills/phase/architecture-diagram/SKILL.md +41 -0
- package/dist/skills/phase/class-diagram/SKILL.md +44 -0
- package/dist/skills/phase/er-diagram/SKILL.md +71 -0
- package/dist/skills/phase/flowchart/SKILL.md +38 -0
- package/dist/skills/phase/sequence-diagram/SKILL.md +67 -0
- package/dist/skills/phase/state-diagram/SKILL.md +38 -0
- package/dist/workspace/session-workspace.d.ts +2 -2
- package/dist/workspace/session-workspace.js +2 -2
- package/package.json +1 -1
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger sequence-diagram <productId> --diagram-id <id>
|
|
3
|
+
*
|
|
4
|
+
* Traces one scenario through the product's code and maps the participants
|
|
5
|
+
* and the ordered messages between them into a structured flow stored in
|
|
6
|
+
* diagrams / diagram_nodes / diagram_edges (rows tagged type='sequence').
|
|
7
|
+
*
|
|
8
|
+
* The desktop UI creates a pending diagrams row first, then invokes the CLI
|
|
9
|
+
* with --diagram-id; the CLI flips status running → success/failed and
|
|
10
|
+
* populates the nodes/edges tables.
|
|
11
|
+
*/
|
|
12
|
+
import { runSequenceDiagramPhase } from '../../phases/sequence-diagram/index.js';
|
|
13
|
+
import { deregisterSession, registerSession, } from '../../system/session-manager.js';
|
|
14
|
+
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
15
|
+
export async function runSequenceDiagram(productId, options) {
|
|
16
|
+
const { diagramId, repoId, guidance, verbose } = options;
|
|
17
|
+
if (!productId && !repoId) {
|
|
18
|
+
throw new Error('Either a product ID or --repo-id is required for sequence-diagram');
|
|
19
|
+
}
|
|
20
|
+
if (!diagramId) {
|
|
21
|
+
throw new Error('--diagram-id is required (the pending diagrams row id)');
|
|
22
|
+
}
|
|
23
|
+
await registerSession({
|
|
24
|
+
command: 'sequence-diagram',
|
|
25
|
+
...(productId ? { productId } : {}),
|
|
26
|
+
});
|
|
27
|
+
if (productId) {
|
|
28
|
+
logInfo(`Starting sequence diagram generation for product ${productId}`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logInfo(`Starting sequence diagram generation for repository ${repoId}`);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const result = await runSequenceDiagramPhase({
|
|
35
|
+
productId,
|
|
36
|
+
repoId,
|
|
37
|
+
diagramId,
|
|
38
|
+
guidance,
|
|
39
|
+
verbose,
|
|
40
|
+
});
|
|
41
|
+
if (result.status === 'success') {
|
|
42
|
+
logSuccess(result.message);
|
|
43
|
+
if (result.summary) {
|
|
44
|
+
logInfo(`\nSummary: ${result.summary}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
logError(result.message);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
await deregisterSession();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger state-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a state machine into the diagrams tables (type='state').
|
|
4
|
+
*/
|
|
5
|
+
import { type DiagramCommandOptions } from '../diagram-shared/index.js';
|
|
6
|
+
export type StateDiagramCliOptions = DiagramCommandOptions;
|
|
7
|
+
export declare function runStateDiagram(productId: string | undefined, options: StateDiagramCliOptions): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger state-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a state machine into the diagrams tables (type='state').
|
|
4
|
+
*/
|
|
5
|
+
import { runStateDiagramPhase } from '../../phases/state-diagram/index.js';
|
|
6
|
+
import { runDiagramCommand, } from '../diagram-shared/index.js';
|
|
7
|
+
export function runStateDiagram(productId, options) {
|
|
8
|
+
return runDiagramCommand('state-diagram', productId, options, runStateDiagramPhase);
|
|
9
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -9,17 +9,21 @@ import { runLogin, runLogout, runStatus } from './auth/login.js';
|
|
|
9
9
|
import { runAgentWorkflow } from './commands/agent-workflow/index.js';
|
|
10
10
|
import { runAnalyzeLogs } from './commands/analyze-logs/index.js';
|
|
11
11
|
import { runAppStoreGeneration } from './commands/app-store/index.js';
|
|
12
|
+
import { runArchitectureDiagram } from './commands/architecture-diagram/index.js';
|
|
12
13
|
import { runBuild } from './commands/build/index.js';
|
|
13
14
|
import { runChatServeCommand } from './commands/chat-serve/index.js';
|
|
14
15
|
import { runChecklists } from './commands/checklists/index.js';
|
|
16
|
+
import { runClassDiagram } from './commands/class-diagram/index.js';
|
|
15
17
|
import { runCodeReview } from './commands/code-review/index.js';
|
|
16
18
|
import { runConfigGet, runConfigList, runConfigSet, runConfigUnset, } from './commands/config/index.js';
|
|
17
19
|
import { runDataFlow } from './commands/data-flow/index.js';
|
|
20
|
+
import { runErDiagram } from './commands/er-diagram/index.js';
|
|
18
21
|
import { runFinancingDeck } from './commands/financing-deck/index.js';
|
|
19
22
|
import { runFindArchitecture } from './commands/find-architecture/index.js';
|
|
20
23
|
import { runFindBugs } from './commands/find-bugs/index.js';
|
|
21
24
|
import { runFindFeatures } from './commands/find-features/index.js';
|
|
22
25
|
import { parseCategoriesOption, runFindSmells, } from './commands/find-smells/index.js';
|
|
26
|
+
import { runFlowchart } from './commands/flowchart/index.js';
|
|
23
27
|
import { runGrowthAnalysis } from './commands/growth-analysis/index.js';
|
|
24
28
|
import { runInit } from './commands/init/index.js';
|
|
25
29
|
import { runIntelligence } from './commands/intelligence/index.js';
|
|
@@ -33,9 +37,11 @@ import { runRefactor } from './commands/refactor/refactor.js';
|
|
|
33
37
|
import { runReleaseSyncCommand } from './commands/release-sync/index.js';
|
|
34
38
|
import { runRunSheetCommand } from './commands/run-sheet/index.js';
|
|
35
39
|
import { runScreenFlow } from './commands/screen-flow/index.js';
|
|
40
|
+
import { runSequenceDiagram } from './commands/sequence-diagram/index.js';
|
|
36
41
|
import { runSessionServeCommand } from './commands/session-serve/index.js';
|
|
37
42
|
import { runSessionTurnCommand } from './commands/session-turn/index.js';
|
|
38
43
|
import { runSmokeTestCommand } from './commands/smoke-test/index.js';
|
|
44
|
+
import { runStateDiagram } from './commands/state-diagram/index.js';
|
|
39
45
|
import { runSyncAws } from './commands/sync-aws/index.js';
|
|
40
46
|
import { runSyncDatadog } from './commands/sync-datadog/index.js';
|
|
41
47
|
import { runSyncGithubIssues } from './commands/sync-github-issues/index.js';
|
|
@@ -172,15 +178,20 @@ program
|
|
|
172
178
|
// Subcommand: edsger screen-flow <productId>
|
|
173
179
|
// ============================================================
|
|
174
180
|
program
|
|
175
|
-
.command('screen-flow
|
|
176
|
-
.description('Generate a structured screen flow (screens + transitions) for a product from its source code')
|
|
177
|
-
.requiredOption('--
|
|
181
|
+
.command('screen-flow [productId]')
|
|
182
|
+
.description('Generate a structured screen flow (screens + transitions) for a product (or standalone repository) from its source code')
|
|
183
|
+
.requiredOption('--diagram-id <id>', 'Pending diagrams row id to populate')
|
|
184
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
178
185
|
.option('-g, --guidance <text>', 'Human direction for the AI (focus areas, exclusions)')
|
|
179
186
|
.option('-v, --verbose', 'Verbose output')
|
|
180
187
|
.action(async (productId, opts) => {
|
|
181
188
|
try {
|
|
189
|
+
if (!productId && !opts.repoId) {
|
|
190
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for screen-flow');
|
|
191
|
+
}
|
|
182
192
|
await runScreenFlow(productId, {
|
|
183
|
-
|
|
193
|
+
diagramId: opts.diagramId,
|
|
194
|
+
repoId: opts.repoId,
|
|
184
195
|
guidance: opts.guidance,
|
|
185
196
|
verbose: opts.verbose,
|
|
186
197
|
});
|
|
@@ -194,15 +205,74 @@ program
|
|
|
194
205
|
// Subcommand: edsger data-flow <productId>
|
|
195
206
|
// ============================================================
|
|
196
207
|
program
|
|
197
|
-
.command('data-flow
|
|
198
|
-
.description('Generate a structured data flow (sources, datasets, transforms, sinks, queues, models) for a product from its source code')
|
|
199
|
-
.requiredOption('--
|
|
208
|
+
.command('data-flow [productId]')
|
|
209
|
+
.description('Generate a structured data flow (sources, datasets, transforms, sinks, queues, models) for a product (or standalone repository) from its source code')
|
|
210
|
+
.requiredOption('--diagram-id <id>', 'Pending diagrams row id to populate')
|
|
211
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
200
212
|
.option('-g, --guidance <text>', 'Human direction for the AI (focus areas, exclusions)')
|
|
201
213
|
.option('-v, --verbose', 'Verbose output')
|
|
202
214
|
.action(async (productId, opts) => {
|
|
203
215
|
try {
|
|
216
|
+
if (!productId && !opts.repoId) {
|
|
217
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for data-flow');
|
|
218
|
+
}
|
|
204
219
|
await runDataFlow(productId, {
|
|
205
|
-
|
|
220
|
+
diagramId: opts.diagramId,
|
|
221
|
+
repoId: opts.repoId,
|
|
222
|
+
guidance: opts.guidance,
|
|
223
|
+
verbose: opts.verbose,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
catch (error) {
|
|
227
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
// ============================================================
|
|
232
|
+
// Subcommand: edsger er-diagram <productId>
|
|
233
|
+
// ============================================================
|
|
234
|
+
program
|
|
235
|
+
.command('er-diagram [productId]')
|
|
236
|
+
.description('Generate a structured entity-relationship diagram (tables, views, enums, junctions + their relationships) for a product (or standalone repository) from its schema source')
|
|
237
|
+
.requiredOption('--diagram-id <id>', 'Pending diagrams row id to populate')
|
|
238
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
239
|
+
.option('-g, --guidance <text>', 'Human direction for the AI (focus areas, exclusions)')
|
|
240
|
+
.option('-v, --verbose', 'Verbose output')
|
|
241
|
+
.action(async (productId, opts) => {
|
|
242
|
+
try {
|
|
243
|
+
if (!productId && !opts.repoId) {
|
|
244
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for er-diagram');
|
|
245
|
+
}
|
|
246
|
+
await runErDiagram(productId, {
|
|
247
|
+
diagramId: opts.diagramId,
|
|
248
|
+
repoId: opts.repoId,
|
|
249
|
+
guidance: opts.guidance,
|
|
250
|
+
verbose: opts.verbose,
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
255
|
+
process.exit(1);
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
// ============================================================
|
|
259
|
+
// Subcommand: edsger sequence-diagram <productId>
|
|
260
|
+
// ============================================================
|
|
261
|
+
program
|
|
262
|
+
.command('sequence-diagram [productId]')
|
|
263
|
+
.description('Generate a structured sequence diagram (participants + ordered messages for one scenario) for a product (or standalone repository) from its source code')
|
|
264
|
+
.requiredOption('--diagram-id <id>', 'Pending diagrams row id to populate')
|
|
265
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
266
|
+
.option('-g, --guidance <text>', 'Human direction for the AI — the scenario to map (e.g. "user checkout")')
|
|
267
|
+
.option('-v, --verbose', 'Verbose output')
|
|
268
|
+
.action(async (productId, opts) => {
|
|
269
|
+
try {
|
|
270
|
+
if (!productId && !opts.repoId) {
|
|
271
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for sequence-diagram');
|
|
272
|
+
}
|
|
273
|
+
await runSequenceDiagram(productId, {
|
|
274
|
+
diagramId: opts.diagramId,
|
|
275
|
+
repoId: opts.repoId,
|
|
206
276
|
guidance: opts.guidance,
|
|
207
277
|
verbose: opts.verbose,
|
|
208
278
|
});
|
|
@@ -212,6 +282,58 @@ program
|
|
|
212
282
|
process.exit(1);
|
|
213
283
|
}
|
|
214
284
|
});
|
|
285
|
+
const diagramSubcommands = [
|
|
286
|
+
{
|
|
287
|
+
name: 'state-diagram',
|
|
288
|
+
description: 'Generate a state diagram (states + transitions for one lifecycle) for a product (or standalone repository) from its source code',
|
|
289
|
+
guidance: 'Human direction for the AI — the lifecycle to map',
|
|
290
|
+
run: runStateDiagram,
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
name: 'class-diagram',
|
|
294
|
+
description: 'Generate a UML class diagram (types + relationships) for a product (or standalone repository) from its source code',
|
|
295
|
+
guidance: 'Human direction for the AI (focus areas, exclusions)',
|
|
296
|
+
run: runClassDiagram,
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
name: 'architecture-diagram',
|
|
300
|
+
description: 'Generate an architecture/component diagram (components + dependencies) for a product (or standalone repository) from its source code',
|
|
301
|
+
guidance: 'Human direction for the AI (focus areas, exclusions)',
|
|
302
|
+
run: runArchitectureDiagram,
|
|
303
|
+
},
|
|
304
|
+
{
|
|
305
|
+
name: 'flowchart',
|
|
306
|
+
description: 'Generate a flowchart (control flow of one process/function) for a product (or standalone repository) from its source code',
|
|
307
|
+
guidance: 'Human direction for the AI — the process to map',
|
|
308
|
+
run: runFlowchart,
|
|
309
|
+
},
|
|
310
|
+
];
|
|
311
|
+
for (const sub of diagramSubcommands) {
|
|
312
|
+
program
|
|
313
|
+
.command(`${sub.name} [productId]`)
|
|
314
|
+
.description(sub.description)
|
|
315
|
+
.requiredOption('--diagram-id <id>', 'Pending diagrams row id to populate')
|
|
316
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
317
|
+
.option('-g, --guidance <text>', sub.guidance)
|
|
318
|
+
.option('-v, --verbose', 'Verbose output')
|
|
319
|
+
.action(async (productId, opts) => {
|
|
320
|
+
try {
|
|
321
|
+
if (!productId && !opts.repoId) {
|
|
322
|
+
throw new Error(`Provide a productId or --repo-id (repo-only mode) for ${sub.name}`);
|
|
323
|
+
}
|
|
324
|
+
await sub.run(productId, {
|
|
325
|
+
diagramId: opts.diagramId,
|
|
326
|
+
repoId: opts.repoId,
|
|
327
|
+
guidance: opts.guidance,
|
|
328
|
+
verbose: opts.verbose,
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
catch (error) {
|
|
332
|
+
logError(error instanceof Error ? error.message : String(error));
|
|
333
|
+
process.exit(1);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
215
337
|
// ============================================================
|
|
216
338
|
// Subcommand: edsger user-psychology <productId>
|
|
217
339
|
// ============================================================
|
|
@@ -646,10 +768,10 @@ program
|
|
|
646
768
|
// Subcommand: edsger quality-benchmark <productId>
|
|
647
769
|
// ============================================================
|
|
648
770
|
program
|
|
649
|
-
.command('quality-benchmark
|
|
650
|
-
.description("Run an industrial-grade code quality benchmark against the product's GitHub repo")
|
|
771
|
+
.command('quality-benchmark [productId]')
|
|
772
|
+
.description("Run an industrial-grade code quality benchmark against the product's (or a standalone repository's) GitHub repo")
|
|
651
773
|
.option('--repo <path>', "Override the auto-clone with a local checkout (default: clone the product's repo into ~/edsger/quality-<owner>-<repo>)")
|
|
652
|
-
.option('--repo-id <id>',
|
|
774
|
+
.option('--repo-id <id>', 'Benchmark a specific repository (id). With a productId, targets that linked repo; without a productId, runs in repo-only mode (no product)')
|
|
653
775
|
.option('--branch <name>', 'Override the detected default branch on the report envelope')
|
|
654
776
|
.option('--pkg-manager <name>', 'npm | pnpm | yarn (auto-detected if absent)')
|
|
655
777
|
.option('--no-install', 'Refuse to install missing tools; mark them unmeasured')
|
|
@@ -659,7 +781,10 @@ program
|
|
|
659
781
|
.option('-v, --verbose', 'Print every progress event')
|
|
660
782
|
.action(async (productId, opts) => {
|
|
661
783
|
try {
|
|
662
|
-
|
|
784
|
+
if (!productId && !opts.repoId) {
|
|
785
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for quality-benchmark');
|
|
786
|
+
}
|
|
787
|
+
await runQualityBenchmarkCli(productId ?? '', opts);
|
|
663
788
|
}
|
|
664
789
|
catch (error) {
|
|
665
790
|
logError(error instanceof Error ? error.message : String(error));
|
|
@@ -888,15 +1013,20 @@ program
|
|
|
888
1013
|
// Subcommand: edsger recipes <productId>
|
|
889
1014
|
// ============================================================
|
|
890
1015
|
program
|
|
891
|
-
.command('recipes
|
|
892
|
-
.description("Scan a product's repo for the implementation recipes it uses (which services/tools are chained together to deliver each capability) and persist them via the recipes / product_recipes tables. Writes against the pending recipe_scans row identified by --scan-id.")
|
|
1016
|
+
.command('recipes [productId]')
|
|
1017
|
+
.description("Scan a product's (or standalone repository's) repo for the implementation recipes it uses (which services/tools are chained together to deliver each capability) and persist them via the recipes / product_recipes (or repository_recipes) tables. Writes against the pending recipe_scans row identified by --scan-id.")
|
|
893
1018
|
.requiredOption('--scan-id <id>', 'Pending recipe_scans row id to drive (created by the desktop UI before invocation)')
|
|
1019
|
+
.option('--repo-id <id>', 'Run in repo-only mode against a single repositories row (no product context)')
|
|
894
1020
|
.option('-g, --guidance <text>', 'Human direction for the AI (focus areas, exclusions)')
|
|
895
1021
|
.option('-v, --verbose', 'Verbose output')
|
|
896
1022
|
.action(async (productId, opts) => {
|
|
897
1023
|
try {
|
|
1024
|
+
if (!productId && !opts.repoId) {
|
|
1025
|
+
throw new Error('Provide a productId or --repo-id (repo-only mode) for recipes');
|
|
1026
|
+
}
|
|
898
1027
|
await runRecipes(productId, {
|
|
899
1028
|
scanId: opts.scanId,
|
|
1029
|
+
repoId: opts.repoId,
|
|
900
1030
|
guidance: opts.guidance,
|
|
901
1031
|
verbose: opts.verbose,
|
|
902
1032
|
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* architecture-diagram phase: map a component/dependency diagram (C4-ish) —
|
|
3
|
+
* the modules / services / packages / datastores / external systems that make
|
|
4
|
+
* up the product and how they depend on one another. Persisted to the
|
|
5
|
+
* diagrams tables with `type = 'architecture'`.
|
|
6
|
+
*/
|
|
7
|
+
import { type DiagramPhaseResult } from '../diagram-shared/generate.js';
|
|
8
|
+
export interface ArchitectureDiagramPhaseOptions {
|
|
9
|
+
productId?: string;
|
|
10
|
+
repoId?: string;
|
|
11
|
+
diagramId: string;
|
|
12
|
+
guidance?: string;
|
|
13
|
+
verbose?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function runArchitectureDiagramPhase(options: ArchitectureDiagramPhaseOptions): Promise<DiagramPhaseResult>;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* architecture-diagram phase: map a component/dependency diagram (C4-ish) —
|
|
3
|
+
* the modules / services / packages / datastores / external systems that make
|
|
4
|
+
* up the product and how they depend on one another. Persisted to the
|
|
5
|
+
* diagrams tables with `type = 'architecture'`.
|
|
6
|
+
*/
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { generateDiagram, } from '../diagram-shared/generate.js';
|
|
9
|
+
import { buildDiagramSystemPrompt, buildDiagramUserPrompt, } from '../diagram-shared/prompts.js';
|
|
10
|
+
const archNode = z.object({
|
|
11
|
+
slug: z.string().min(1),
|
|
12
|
+
name: z.string().min(1),
|
|
13
|
+
kind: z.enum(['module', 'service', 'package', 'ui', 'datastore', 'external']),
|
|
14
|
+
file: z.string().optional(),
|
|
15
|
+
description: z.string().optional(),
|
|
16
|
+
tech: z.string().optional(),
|
|
17
|
+
responsibilities: z.array(z.string()).optional(),
|
|
18
|
+
});
|
|
19
|
+
const archEdge = z.object({
|
|
20
|
+
fromSlug: z.string().min(1),
|
|
21
|
+
toSlug: z.string().min(1),
|
|
22
|
+
kind: z.enum(['depends-on', 'calls', 'imports', 'data']),
|
|
23
|
+
label: z.string().optional(),
|
|
24
|
+
sourceFile: z.string().optional(),
|
|
25
|
+
});
|
|
26
|
+
export function runArchitectureDiagramPhase(options) {
|
|
27
|
+
return generateDiagram({
|
|
28
|
+
...options,
|
|
29
|
+
workspaceKey: 'architecture-diagram',
|
|
30
|
+
fenceName: 'architecture_diagram',
|
|
31
|
+
nounPlural: 'components',
|
|
32
|
+
edgeNounPlural: 'dependencies',
|
|
33
|
+
mcpConfig: {
|
|
34
|
+
name: 'architecture-diagram',
|
|
35
|
+
toolName: 'architecture_diagram',
|
|
36
|
+
summaryDescribe: '1-3 sentence narrative of the system architecture and its main building blocks.',
|
|
37
|
+
nodesSchema: z.array(archNode),
|
|
38
|
+
nodesDescribe: 'Every component: module / service / package / ui / datastore / external. slug MUST be unique.',
|
|
39
|
+
edgesSchema: z.array(archEdge),
|
|
40
|
+
edgesDescribe: 'Dependencies. kind = depends-on / calls / imports / data. fromSlug is the depender. Endpoints MUST reference emitted components.',
|
|
41
|
+
},
|
|
42
|
+
buildSystemPrompt: (a) => buildDiagramSystemPrompt('phase/architecture-diagram', 'architecture-diagram', a),
|
|
43
|
+
buildUserPrompt: (a) => buildDiagramUserPrompt({
|
|
44
|
+
...a,
|
|
45
|
+
task: 'Map the architecture (component & dependency) diagram for',
|
|
46
|
+
mcpName: 'architecture-diagram',
|
|
47
|
+
toolName: 'architecture_diagram',
|
|
48
|
+
process: 'Detect the stack and the top-level structure (workspaces/packages, service boundaries, top-level src dirs, deployment units). Treat each meaningful unit as a component of the right kind (a UI/front-end, backend services, internal modules/packages, datastores, third-party/external systems). Wire dependency edges from the import graph, cross-service calls, and datastore/external access. Aim for a readable ~10-25 components — group leaf files into their module; do not draw a file-level graph.',
|
|
49
|
+
}),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* class-diagram phase: map a UML class diagram — classes / interfaces / enums
|
|
3
|
+
* with their members, and the inheritance / composition / association edges
|
|
4
|
+
* between them. Persisted to the diagrams tables with `type = 'class'`.
|
|
5
|
+
*/
|
|
6
|
+
import { type DiagramPhaseResult } from '../diagram-shared/generate.js';
|
|
7
|
+
export interface ClassDiagramPhaseOptions {
|
|
8
|
+
productId?: string;
|
|
9
|
+
repoId?: string;
|
|
10
|
+
diagramId: string;
|
|
11
|
+
guidance?: string;
|
|
12
|
+
verbose?: boolean;
|
|
13
|
+
}
|
|
14
|
+
export declare function runClassDiagramPhase(options: ClassDiagramPhaseOptions): Promise<DiagramPhaseResult>;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* class-diagram phase: map a UML class diagram — classes / interfaces / enums
|
|
3
|
+
* with their members, and the inheritance / composition / association edges
|
|
4
|
+
* between them. Persisted to the diagrams tables with `type = 'class'`.
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { generateDiagram, } from '../diagram-shared/generate.js';
|
|
8
|
+
import { buildDiagramSystemPrompt, buildDiagramUserPrompt, } from '../diagram-shared/prompts.js';
|
|
9
|
+
const visibility = z.enum(['public', 'private', 'protected']);
|
|
10
|
+
const classNode = z.object({
|
|
11
|
+
slug: z.string().min(1),
|
|
12
|
+
name: z.string().min(1),
|
|
13
|
+
kind: z.enum(['class', 'interface', 'abstract', 'enum']),
|
|
14
|
+
file: z.string().optional(),
|
|
15
|
+
description: z.string().optional(),
|
|
16
|
+
stereotype: z.string().optional(),
|
|
17
|
+
attributes: z
|
|
18
|
+
.array(z.object({
|
|
19
|
+
name: z.string(),
|
|
20
|
+
type: z.string().optional(),
|
|
21
|
+
visibility: visibility.optional(),
|
|
22
|
+
isStatic: z.boolean().optional(),
|
|
23
|
+
}))
|
|
24
|
+
.optional(),
|
|
25
|
+
methods: z
|
|
26
|
+
.array(z.object({
|
|
27
|
+
name: z.string(),
|
|
28
|
+
params: z.string().optional(),
|
|
29
|
+
returnType: z.string().optional(),
|
|
30
|
+
visibility: visibility.optional(),
|
|
31
|
+
isStatic: z.boolean().optional(),
|
|
32
|
+
isAbstract: z.boolean().optional(),
|
|
33
|
+
}))
|
|
34
|
+
.optional(),
|
|
35
|
+
});
|
|
36
|
+
const classEdge = z.object({
|
|
37
|
+
fromSlug: z.string().min(1),
|
|
38
|
+
toSlug: z.string().min(1),
|
|
39
|
+
kind: z.enum([
|
|
40
|
+
'inheritance',
|
|
41
|
+
'implementation',
|
|
42
|
+
'composition',
|
|
43
|
+
'aggregation',
|
|
44
|
+
'association',
|
|
45
|
+
'dependency',
|
|
46
|
+
]),
|
|
47
|
+
/** Role name or multiplicity, e.g. "1..*", "owns". */
|
|
48
|
+
label: z.string().optional(),
|
|
49
|
+
sourceFile: z.string().optional(),
|
|
50
|
+
});
|
|
51
|
+
export function runClassDiagramPhase(options) {
|
|
52
|
+
return generateDiagram({
|
|
53
|
+
...options,
|
|
54
|
+
workspaceKey: 'class-diagram',
|
|
55
|
+
fenceName: 'class_diagram',
|
|
56
|
+
nounPlural: 'classes',
|
|
57
|
+
edgeNounPlural: 'relationships',
|
|
58
|
+
mcpConfig: {
|
|
59
|
+
name: 'class-diagram',
|
|
60
|
+
toolName: 'class_diagram',
|
|
61
|
+
summaryDescribe: '1-3 sentence narrative of the core types and how they relate.',
|
|
62
|
+
nodesSchema: z.array(classNode),
|
|
63
|
+
nodesDescribe: 'Every class / interface / abstract / enum with its key attributes and methods. slug MUST be unique.',
|
|
64
|
+
edgesSchema: z.array(classEdge),
|
|
65
|
+
edgesDescribe: 'Relationships. kind = inheritance / implementation / composition / aggregation / association / dependency. fromSlug is the child / owner / dependent side. Endpoints MUST reference emitted classes.',
|
|
66
|
+
},
|
|
67
|
+
buildSystemPrompt: (a) => buildDiagramSystemPrompt('phase/class-diagram', 'class-diagram', a),
|
|
68
|
+
buildUserPrompt: (a) => buildDiagramUserPrompt({
|
|
69
|
+
...a,
|
|
70
|
+
task: 'Map a UML class diagram for',
|
|
71
|
+
mcpName: 'class-diagram',
|
|
72
|
+
toolName: 'class_diagram',
|
|
73
|
+
process: 'Detect the language/OO model, then map the core domain types — classes, interfaces, abstract base types, enums — capturing each one\'s defining attributes and methods (visibility + static/abstract where it matters; you need not list every member of huge types). Wire edges: `inheritance` (extends), `implementation` (implements), `composition`/`aggregation` (owns/holds), `association` (references), `dependency` (uses). Prefer the ~30 most important types if there are many.',
|
|
74
|
+
}),
|
|
75
|
+
});
|
|
76
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* data-flow phase: clone the product's repo, ask Claude to map every data
|
|
3
3
|
* node (source / dataset / transform / sink / queue / model) and the
|
|
4
4
|
* connections between them into a structured DataFlowExtraction, then
|
|
5
|
-
* persist the result to
|
|
5
|
+
* persist the result to diagrams / diagram_nodes / diagram_edges (rows tagged
|
|
6
6
|
* `type = 'data'`) via the Supabase SDK.
|
|
7
7
|
*
|
|
8
8
|
* Companion to screen-flow: same generation pattern (workspace clone +
|
|
@@ -10,8 +10,11 @@
|
|
|
10
10
|
* domain.
|
|
11
11
|
*/
|
|
12
12
|
export interface DataFlowPhaseOptions {
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/** Product-scoped flow. Mutually exclusive with `repoId`. */
|
|
14
|
+
productId?: string;
|
|
15
|
+
/** Repo-only flow: a single repositories row, no product context. */
|
|
16
|
+
repoId?: string;
|
|
17
|
+
diagramId: string;
|
|
15
18
|
guidance?: string;
|
|
16
19
|
verbose?: boolean;
|
|
17
20
|
}
|