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
package/dist/api/github.d.ts
CHANGED
|
@@ -50,6 +50,29 @@ export declare function getGitHubConfigByProduct(productId: string, verbose?: bo
|
|
|
50
50
|
repo?: string;
|
|
51
51
|
message?: string;
|
|
52
52
|
}>;
|
|
53
|
+
export interface RepositoryBasics {
|
|
54
|
+
teamId: string | null;
|
|
55
|
+
fullName: string | null;
|
|
56
|
+
description: string | null;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Fetch a repository row's team_id, full_name and description (RLS-scoped).
|
|
60
|
+
* Used by repo-scoped analysis to resolve the team (recipes are team-scoped)
|
|
61
|
+
* and to build prompt "product basics" from the repo instead of a product.
|
|
62
|
+
*/
|
|
63
|
+
export declare function getRepositoryBasics(repositoryId: string): Promise<RepositoryBasics>;
|
|
64
|
+
/**
|
|
65
|
+
* Get GitHub config and token by repository ID (no product / issue required).
|
|
66
|
+
* Used for repo-scoped analysis (quality-benchmark / recipes / diagrams running
|
|
67
|
+
* against a single `repositories` row with no product context).
|
|
68
|
+
*/
|
|
69
|
+
export declare function getGitHubConfigByRepository(repositoryId: string, verbose?: boolean): Promise<{
|
|
70
|
+
configured: boolean;
|
|
71
|
+
token?: string;
|
|
72
|
+
owner?: string;
|
|
73
|
+
repo?: string;
|
|
74
|
+
message?: string;
|
|
75
|
+
}>;
|
|
53
76
|
/**
|
|
54
77
|
* Get GitHub config and token in one call
|
|
55
78
|
* This is the main entry point for getting GitHub config
|
package/dist/api/github.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* GitHub API client for accessing GitHub via MCP server
|
|
3
3
|
* Uses product developer configuration from the database
|
|
4
4
|
*/
|
|
5
|
+
import { getSupabase } from '../supabase/client.js';
|
|
5
6
|
import { logDebug, logError, logSuccess, logWarning } from '../utils/logger.js';
|
|
6
7
|
import { callMcpEndpoint } from './mcp-client.js';
|
|
7
8
|
/**
|
|
@@ -98,6 +99,66 @@ export async function getGitHubConfigByProduct(productId, verbose) {
|
|
|
98
99
|
};
|
|
99
100
|
}
|
|
100
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch a repository row's team_id, full_name and description (RLS-scoped).
|
|
104
|
+
* Used by repo-scoped analysis to resolve the team (recipes are team-scoped)
|
|
105
|
+
* and to build prompt "product basics" from the repo instead of a product.
|
|
106
|
+
*/
|
|
107
|
+
export async function getRepositoryBasics(repositoryId) {
|
|
108
|
+
const { data } = await getSupabase()
|
|
109
|
+
.from('repositories')
|
|
110
|
+
.select('team_id, full_name, description')
|
|
111
|
+
.eq('id', repositoryId)
|
|
112
|
+
.maybeSingle();
|
|
113
|
+
return {
|
|
114
|
+
teamId: data?.team_id ?? null,
|
|
115
|
+
fullName: data?.full_name ?? null,
|
|
116
|
+
description: data?.description ?? null,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Get GitHub config and token by repository ID (no product / issue required).
|
|
121
|
+
* Used for repo-scoped analysis (quality-benchmark / recipes / diagrams running
|
|
122
|
+
* against a single `repositories` row with no product context).
|
|
123
|
+
*/
|
|
124
|
+
export async function getGitHubConfigByRepository(repositoryId, verbose) {
|
|
125
|
+
logDebug(`Fetching GitHub config for repository: ${repositoryId}`, verbose);
|
|
126
|
+
try {
|
|
127
|
+
const result = (await callMcpEndpoint('github/config_and_token_by_repository', {
|
|
128
|
+
repository_id: repositoryId,
|
|
129
|
+
}));
|
|
130
|
+
if (verbose) {
|
|
131
|
+
if (result.configured) {
|
|
132
|
+
logSuccess(`GitHub ready: ${result.repository_full_name}`);
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
logWarning(`GitHub not configured: ${result.message}`);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (result.configured && result.token && result.owner && result.repo) {
|
|
139
|
+
return {
|
|
140
|
+
configured: true,
|
|
141
|
+
token: result.token,
|
|
142
|
+
owner: result.owner,
|
|
143
|
+
repo: result.repo,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
configured: false,
|
|
148
|
+
message: result.message ||
|
|
149
|
+
'GitHub not configured for this repository. Connect the repo first.',
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (verbose) {
|
|
154
|
+
logError(`Failed to get GitHub config for repository: ${error instanceof Error ? error.message : String(error)}`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
configured: false,
|
|
158
|
+
message: error instanceof Error ? error.message : 'Failed to get GitHub config',
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
}
|
|
101
162
|
/**
|
|
102
163
|
* Get GitHub config and token in one call
|
|
103
164
|
* This is the main entry point for getting GitHub config
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger architecture-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a component/dependency diagram into the diagrams tables
|
|
4
|
+
* (type='architecture').
|
|
5
|
+
*/
|
|
6
|
+
import { type DiagramCommandOptions } from '../diagram-shared/index.js';
|
|
7
|
+
export type ArchitectureDiagramCliOptions = DiagramCommandOptions;
|
|
8
|
+
export declare function runArchitectureDiagram(productId: string | undefined, options: ArchitectureDiagramCliOptions): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger architecture-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a component/dependency diagram into the diagrams tables
|
|
4
|
+
* (type='architecture').
|
|
5
|
+
*/
|
|
6
|
+
import { runArchitectureDiagramPhase } from '../../phases/architecture-diagram/index.js';
|
|
7
|
+
import { runDiagramCommand, } from '../diagram-shared/index.js';
|
|
8
|
+
export function runArchitectureDiagram(productId, options) {
|
|
9
|
+
return runDiagramCommand('architecture-diagram', productId, options, runArchitectureDiagramPhase);
|
|
10
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger class-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a UML class diagram into the diagrams tables (type='class').
|
|
4
|
+
*/
|
|
5
|
+
import { type DiagramCommandOptions } from '../diagram-shared/index.js';
|
|
6
|
+
export type ClassDiagramCliOptions = DiagramCommandOptions;
|
|
7
|
+
export declare function runClassDiagram(productId: string | undefined, options: ClassDiagramCliOptions): Promise<void>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger class-diagram <productId> --diagram-id <id>
|
|
3
|
+
* Maps a UML class diagram into the diagrams tables (type='class').
|
|
4
|
+
*/
|
|
5
|
+
import { runClassDiagramPhase } from '../../phases/class-diagram/index.js';
|
|
6
|
+
import { runDiagramCommand, } from '../diagram-shared/index.js';
|
|
7
|
+
export function runClassDiagram(productId, options) {
|
|
8
|
+
return runDiagramCommand('class-diagram', productId, options, runClassDiagramPhase);
|
|
9
|
+
}
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command: edsger data-flow <productId> --
|
|
2
|
+
* CLI command: edsger data-flow <productId> --diagram-id <id>
|
|
3
3
|
*
|
|
4
4
|
* Maps the product's data nodes (source/dataset/transform/sink/queue/model)
|
|
5
5
|
* and the connections between them into a structured flow stored in
|
|
6
|
-
*
|
|
6
|
+
* diagrams / diagram_nodes / diagram_edges (rows tagged type='data').
|
|
7
7
|
*
|
|
8
|
-
* The desktop UI creates a pending
|
|
9
|
-
* with --
|
|
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
10
|
* populates the nodes/edges tables.
|
|
11
11
|
*/
|
|
12
12
|
export interface DataFlowCliOptions {
|
|
13
|
-
|
|
13
|
+
diagramId: string;
|
|
14
|
+
/** Repo-only mode: generate against a single repositories row, no product. */
|
|
15
|
+
repoId?: string;
|
|
14
16
|
guidance?: string;
|
|
15
17
|
verbose?: boolean;
|
|
16
18
|
}
|
|
17
|
-
export declare function runDataFlow(productId: string, options: DataFlowCliOptions): Promise<void>;
|
|
19
|
+
export declare function runDataFlow(productId: string | undefined, options: DataFlowCliOptions): Promise<void>;
|
|
@@ -1,31 +1,40 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command: edsger data-flow <productId> --
|
|
2
|
+
* CLI command: edsger data-flow <productId> --diagram-id <id>
|
|
3
3
|
*
|
|
4
4
|
* Maps the product's data nodes (source/dataset/transform/sink/queue/model)
|
|
5
5
|
* and the connections between them into a structured flow stored in
|
|
6
|
-
*
|
|
6
|
+
* diagrams / diagram_nodes / diagram_edges (rows tagged type='data').
|
|
7
7
|
*
|
|
8
|
-
* The desktop UI creates a pending
|
|
9
|
-
* with --
|
|
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
10
|
* populates the nodes/edges tables.
|
|
11
11
|
*/
|
|
12
12
|
import { runDataFlowPhase } from '../../phases/data-flow/index.js';
|
|
13
13
|
import { deregisterSession, registerSession, } from '../../system/session-manager.js';
|
|
14
14
|
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
15
15
|
export async function runDataFlow(productId, options) {
|
|
16
|
-
const {
|
|
17
|
-
if (!productId) {
|
|
18
|
-
throw new Error('
|
|
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 data-flow');
|
|
19
19
|
}
|
|
20
|
-
if (!
|
|
21
|
-
throw new Error('--
|
|
20
|
+
if (!diagramId) {
|
|
21
|
+
throw new Error('--diagram-id is required (the pending diagrams row id)');
|
|
22
|
+
}
|
|
23
|
+
await registerSession({
|
|
24
|
+
command: 'data-flow',
|
|
25
|
+
...(productId ? { productId } : {}),
|
|
26
|
+
});
|
|
27
|
+
if (productId) {
|
|
28
|
+
logInfo(`Starting data flow generation for product ${productId}`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logInfo(`Starting data flow generation for repository ${repoId}`);
|
|
22
32
|
}
|
|
23
|
-
await registerSession({ command: 'data-flow', productId });
|
|
24
|
-
logInfo(`Starting data flow generation for product ${productId}`);
|
|
25
33
|
try {
|
|
26
34
|
const result = await runDataFlowPhase({
|
|
27
35
|
productId,
|
|
28
|
-
|
|
36
|
+
repoId,
|
|
37
|
+
diagramId,
|
|
29
38
|
guidance,
|
|
30
39
|
verbose,
|
|
31
40
|
});
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI command runner for graph diagram phases (state / class /
|
|
3
|
+
* architecture / flowchart). Handles session registration and the
|
|
4
|
+
* success/failure → exit-code mapping; each command just passes its phase
|
|
5
|
+
* runner.
|
|
6
|
+
*/
|
|
7
|
+
import type { DiagramPhaseResult } from '../../phases/diagram-shared/generate.js';
|
|
8
|
+
export interface DiagramCommandOptions {
|
|
9
|
+
diagramId: string;
|
|
10
|
+
/** Repo-only mode: generate against a single repositories row, no product. */
|
|
11
|
+
repoId?: string;
|
|
12
|
+
guidance?: string;
|
|
13
|
+
verbose?: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function runDiagramCommand(command: string, productId: string | undefined, options: DiagramCommandOptions, run: (args: {
|
|
16
|
+
productId?: string;
|
|
17
|
+
repoId?: string;
|
|
18
|
+
diagramId: string;
|
|
19
|
+
guidance?: string;
|
|
20
|
+
verbose?: boolean;
|
|
21
|
+
}) => Promise<DiagramPhaseResult>): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared CLI command runner for graph diagram phases (state / class /
|
|
3
|
+
* architecture / flowchart). Handles session registration and the
|
|
4
|
+
* success/failure → exit-code mapping; each command just passes its phase
|
|
5
|
+
* runner.
|
|
6
|
+
*/
|
|
7
|
+
import { deregisterSession, registerSession, } from '../../system/session-manager.js';
|
|
8
|
+
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
9
|
+
export async function runDiagramCommand(command, productId, options, run) {
|
|
10
|
+
const { diagramId, repoId, guidance, verbose } = options;
|
|
11
|
+
if (!productId && !repoId) {
|
|
12
|
+
throw new Error(`Either a product ID or --repo-id is required for ${command}`);
|
|
13
|
+
}
|
|
14
|
+
if (!diagramId) {
|
|
15
|
+
throw new Error('--diagram-id is required (the pending diagrams row id)');
|
|
16
|
+
}
|
|
17
|
+
await registerSession({ command, ...(productId ? { productId } : {}) });
|
|
18
|
+
logInfo(productId
|
|
19
|
+
? `Starting ${command} for product ${productId}`
|
|
20
|
+
: `Starting ${command} for repository ${repoId}`);
|
|
21
|
+
try {
|
|
22
|
+
const result = await run({ productId, repoId, diagramId, guidance, verbose });
|
|
23
|
+
if (result.status === 'success') {
|
|
24
|
+
logSuccess(result.message);
|
|
25
|
+
if (result.summary) {
|
|
26
|
+
logInfo(`\nSummary: ${result.summary}`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
logError(result.message);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
await deregisterSession();
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger er-diagram <productId> --diagram-id <id>
|
|
3
|
+
*
|
|
4
|
+
* Maps the product's persistence entities (tables / views / enums / junction
|
|
5
|
+
* tables) and the relationships between them into a structured flow stored in
|
|
6
|
+
* diagrams / diagram_nodes / diagram_edges (rows tagged type='er').
|
|
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
|
+
export interface ErDiagramCliOptions {
|
|
13
|
+
diagramId: string;
|
|
14
|
+
/** Repo-only mode: generate against a single repositories row, no product. */
|
|
15
|
+
repoId?: string;
|
|
16
|
+
guidance?: string;
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function runErDiagram(productId: string | undefined, options: ErDiagramCliOptions): Promise<void>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger er-diagram <productId> --diagram-id <id>
|
|
3
|
+
*
|
|
4
|
+
* Maps the product's persistence entities (tables / views / enums / junction
|
|
5
|
+
* tables) and the relationships between them into a structured flow stored in
|
|
6
|
+
* diagrams / diagram_nodes / diagram_edges (rows tagged type='er').
|
|
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 { runErDiagramPhase } from '../../phases/er-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 runErDiagram(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 er-diagram');
|
|
19
|
+
}
|
|
20
|
+
if (!diagramId) {
|
|
21
|
+
throw new Error('--diagram-id is required (the pending diagrams row id)');
|
|
22
|
+
}
|
|
23
|
+
await registerSession({
|
|
24
|
+
command: 'er-diagram',
|
|
25
|
+
...(productId ? { productId } : {}),
|
|
26
|
+
});
|
|
27
|
+
if (productId) {
|
|
28
|
+
logInfo(`Starting ER diagram generation for product ${productId}`);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
logInfo(`Starting ER diagram generation for repository ${repoId}`);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const result = await runErDiagramPhase({
|
|
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,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger flowchart <productId> --diagram-id <id>
|
|
3
|
+
* Maps a process/control-flow flowchart into the diagrams tables
|
|
4
|
+
* (type='flowchart').
|
|
5
|
+
*/
|
|
6
|
+
import { type DiagramCommandOptions } from '../diagram-shared/index.js';
|
|
7
|
+
export type FlowchartCliOptions = DiagramCommandOptions;
|
|
8
|
+
export declare function runFlowchart(productId: string | undefined, options: FlowchartCliOptions): Promise<void>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI command: edsger flowchart <productId> --diagram-id <id>
|
|
3
|
+
* Maps a process/control-flow flowchart into the diagrams tables
|
|
4
|
+
* (type='flowchart').
|
|
5
|
+
*/
|
|
6
|
+
import { runFlowchartPhase } from '../../phases/flowchart/index.js';
|
|
7
|
+
import { runDiagramCommand, } from '../diagram-shared/index.js';
|
|
8
|
+
export function runFlowchart(productId, options) {
|
|
9
|
+
return runDiagramCommand('flowchart', productId, options, runFlowchartPhase);
|
|
10
|
+
}
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
*/
|
|
26
26
|
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
27
27
|
import { dirname, resolve } from 'node:path';
|
|
28
|
-
import { getGitHubConfigByProduct } from '../../api/github.js';
|
|
28
|
+
import { getGitHubConfigByProduct, getGitHubConfigByRepository, getRepositoryBasics, } from '../../api/github.js';
|
|
29
29
|
import { callMcpEndpoint } from '../../api/mcp-client.js';
|
|
30
30
|
import { fetchProductBasics } from '../../phases/find-shared/mcp.js';
|
|
31
31
|
import { runQualityBenchmark, } from '../../phases/quality-benchmark/index.js';
|
|
@@ -34,15 +34,46 @@ import { getSupabase } from '../../supabase/client.js';
|
|
|
34
34
|
import { logError, logInfo, logSuccess, logWarning, } from '../../utils/logger.js';
|
|
35
35
|
export async function runQualityBenchmarkCli(productId, options) {
|
|
36
36
|
const installEnabled = options.install !== false;
|
|
37
|
-
|
|
37
|
+
// Repo-only mode: no product context, benchmark a single repositories row.
|
|
38
|
+
const repoOnly = !productId && Boolean(options.repoId);
|
|
39
|
+
if (repoOnly) {
|
|
40
|
+
logInfo(`Starting quality benchmark for repository ${options.repoId}`);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
logInfo(`Starting quality benchmark for product ${productId}`);
|
|
44
|
+
}
|
|
38
45
|
let repoRoot;
|
|
39
46
|
let resolvedBranch;
|
|
40
47
|
// Recorded on the report so it's scoped to the repo that was benchmarked.
|
|
41
48
|
let repositoryId = options.repoId ?? null;
|
|
49
|
+
// Display name used on the prompt + report (repo full_name in repo-only mode).
|
|
50
|
+
let productName = productId;
|
|
42
51
|
if (options.repo) {
|
|
43
52
|
repoRoot = resolve(options.repo);
|
|
44
53
|
resolvedBranch = options.branch;
|
|
45
54
|
logInfo(`Repo (override): ${repoRoot}`);
|
|
55
|
+
if (repoOnly) {
|
|
56
|
+
const basics = await getRepositoryBasics(options.repoId).catch(() => null);
|
|
57
|
+
productName = basics?.fullName ?? options.repoId;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
else if (repoOnly) {
|
|
61
|
+
const gh = await getGitHubConfigByRepository(options.repoId, options.verbose);
|
|
62
|
+
if (!gh.configured || !gh.token || !gh.owner || !gh.repo) {
|
|
63
|
+
logError(`Cannot run quality benchmark: ${gh.message ??
|
|
64
|
+
'GitHub is not configured for this repository. Connect the repo first.'}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const ws = prepareQualityWorkspace({
|
|
68
|
+
owner: gh.owner,
|
|
69
|
+
repo: gh.repo,
|
|
70
|
+
token: gh.token,
|
|
71
|
+
verbose: options.verbose,
|
|
72
|
+
});
|
|
73
|
+
repoRoot = ws.repoPath;
|
|
74
|
+
resolvedBranch = options.branch ?? ws.branch;
|
|
75
|
+
productName = `${gh.owner}/${gh.repo}`;
|
|
76
|
+
logInfo(`Repo: ${repoRoot} (branch: ${resolvedBranch})`);
|
|
46
77
|
}
|
|
47
78
|
else {
|
|
48
79
|
const gh = await getGitHubConfigByProduct(productId, options.verbose);
|
|
@@ -82,10 +113,12 @@ export async function runQualityBenchmarkCli(productId, options) {
|
|
|
82
113
|
if (!installEnabled) {
|
|
83
114
|
logWarning('Install consent NOT granted (--no-install). Missing tools will be marked unmeasured.');
|
|
84
115
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
116
|
+
if (!repoOnly) {
|
|
117
|
+
const basics = await fetchProductBasics(productId).catch(() => ({
|
|
118
|
+
name: productId,
|
|
119
|
+
}));
|
|
120
|
+
productName = basics.name;
|
|
121
|
+
}
|
|
89
122
|
const onProgress = (event) => {
|
|
90
123
|
if (options.verbose) {
|
|
91
124
|
logInfo(`[${event.phase}] ${event.message}`);
|
|
@@ -100,7 +133,7 @@ export async function runQualityBenchmarkCli(productId, options) {
|
|
|
100
133
|
}
|
|
101
134
|
};
|
|
102
135
|
const outcome = await runQualityBenchmark({
|
|
103
|
-
productId,
|
|
136
|
+
productId: repoOnly ? '' : productId,
|
|
104
137
|
productName,
|
|
105
138
|
repoRoot,
|
|
106
139
|
branch: resolvedBranch,
|
|
@@ -121,7 +154,8 @@ export async function runQualityBenchmarkCli(productId, options) {
|
|
|
121
154
|
resolve(process.cwd(), `quality-report-${outcome.commitSha.slice(0, 8)}.json`);
|
|
122
155
|
const reportEnvelope = {
|
|
123
156
|
run_id: outcome.runId,
|
|
124
|
-
product_id: productId,
|
|
157
|
+
product_id: repoOnly ? null : productId,
|
|
158
|
+
repository_id: repositoryId,
|
|
125
159
|
commit_sha: outcome.commitSha,
|
|
126
160
|
branch: resolvedBranch ?? null,
|
|
127
161
|
started_at: outcome.startedAt,
|
|
@@ -136,7 +170,7 @@ export async function runQualityBenchmarkCli(productId, options) {
|
|
|
136
170
|
if (options.save !== false) {
|
|
137
171
|
try {
|
|
138
172
|
const saved = (await callMcpEndpoint('quality_reports/save', {
|
|
139
|
-
product_id: productId,
|
|
173
|
+
product_id: repoOnly ? null : productId,
|
|
140
174
|
repository_id: repositoryId,
|
|
141
175
|
commit_sha: outcome.commitSha,
|
|
142
176
|
rubric_version: outcome.report.rubric_version,
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
*/
|
|
10
10
|
export interface RecipesCliOptions {
|
|
11
11
|
scanId: string;
|
|
12
|
+
/** Repo-only mode: scan a single repositories row with no product context. */
|
|
13
|
+
repoId?: string;
|
|
12
14
|
guidance?: string;
|
|
13
15
|
verbose?: boolean;
|
|
14
16
|
}
|
|
15
|
-
export declare function runRecipes(productId: string, options: RecipesCliOptions): Promise<void>;
|
|
17
|
+
export declare function runRecipes(productId: string | undefined, options: RecipesCliOptions): Promise<void>;
|
|
@@ -10,16 +10,22 @@
|
|
|
10
10
|
import { runRecipesPhase } from '../../phases/recipes/index.js';
|
|
11
11
|
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
12
12
|
export async function runRecipes(productId, options) {
|
|
13
|
-
const { scanId, guidance, verbose } = options;
|
|
14
|
-
if (!productId) {
|
|
15
|
-
throw new Error('
|
|
13
|
+
const { scanId, repoId, guidance, verbose } = options;
|
|
14
|
+
if (!productId && !repoId) {
|
|
15
|
+
throw new Error('Either a product ID or --repo-id is required for recipes');
|
|
16
16
|
}
|
|
17
17
|
if (!scanId) {
|
|
18
18
|
throw new Error('--scan-id is required (the pending recipe_scans row id)');
|
|
19
19
|
}
|
|
20
|
-
|
|
20
|
+
if (productId) {
|
|
21
|
+
logInfo(`Starting recipes scan for product ${productId}`);
|
|
22
|
+
}
|
|
23
|
+
else {
|
|
24
|
+
logInfo(`Starting recipes scan for repository ${repoId}`);
|
|
25
|
+
}
|
|
21
26
|
const result = await runRecipesPhase({
|
|
22
27
|
productId,
|
|
28
|
+
repoId,
|
|
23
29
|
scanId,
|
|
24
30
|
guidance,
|
|
25
31
|
verbose,
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command: edsger screen-flow <productId> --
|
|
2
|
+
* CLI command: edsger screen-flow <productId> --diagram-id <id>
|
|
3
3
|
*
|
|
4
4
|
* Maps the product's user-facing screens and transitions into a structured
|
|
5
|
-
* flow stored in
|
|
5
|
+
* flow stored in diagrams / diagram_nodes / diagram_edges (rows tagged type='screen').
|
|
6
6
|
*
|
|
7
|
-
* The desktop UI creates a pending
|
|
8
|
-
* with --
|
|
7
|
+
* The desktop UI creates a pending diagrams row first, then invokes the CLI
|
|
8
|
+
* with --diagram-id; the CLI flips status running → success/failed and
|
|
9
9
|
* populates the nodes/edges tables.
|
|
10
10
|
*/
|
|
11
11
|
export interface ScreenFlowCliOptions {
|
|
12
|
-
|
|
12
|
+
diagramId: string;
|
|
13
|
+
/** Repo-only mode: generate against a single repositories row, no product. */
|
|
14
|
+
repoId?: string;
|
|
13
15
|
guidance?: string;
|
|
14
16
|
verbose?: boolean;
|
|
15
17
|
}
|
|
16
|
-
export declare function runScreenFlow(productId: string, options: ScreenFlowCliOptions): Promise<void>;
|
|
18
|
+
export declare function runScreenFlow(productId: string | undefined, options: ScreenFlowCliOptions): Promise<void>;
|
|
@@ -1,30 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* CLI command: edsger screen-flow <productId> --
|
|
2
|
+
* CLI command: edsger screen-flow <productId> --diagram-id <id>
|
|
3
3
|
*
|
|
4
4
|
* Maps the product's user-facing screens and transitions into a structured
|
|
5
|
-
* flow stored in
|
|
5
|
+
* flow stored in diagrams / diagram_nodes / diagram_edges (rows tagged type='screen').
|
|
6
6
|
*
|
|
7
|
-
* The desktop UI creates a pending
|
|
8
|
-
* with --
|
|
7
|
+
* The desktop UI creates a pending diagrams row first, then invokes the CLI
|
|
8
|
+
* with --diagram-id; the CLI flips status running → success/failed and
|
|
9
9
|
* populates the nodes/edges tables.
|
|
10
10
|
*/
|
|
11
11
|
import { runScreenFlowPhase } from '../../phases/screen-flow/index.js';
|
|
12
12
|
import { deregisterSession, registerSession, } from '../../system/session-manager.js';
|
|
13
13
|
import { logError, logInfo, logSuccess } from '../../utils/logger.js';
|
|
14
14
|
export async function runScreenFlow(productId, options) {
|
|
15
|
-
const {
|
|
16
|
-
if (!productId) {
|
|
17
|
-
throw new Error('
|
|
15
|
+
const { diagramId, repoId, guidance, verbose } = options;
|
|
16
|
+
if (!productId && !repoId) {
|
|
17
|
+
throw new Error('Either a product ID or --repo-id is required for screen-flow');
|
|
18
18
|
}
|
|
19
|
-
if (!
|
|
20
|
-
throw new Error('--
|
|
19
|
+
if (!diagramId) {
|
|
20
|
+
throw new Error('--diagram-id is required (the pending diagrams row id)');
|
|
21
|
+
}
|
|
22
|
+
await registerSession({
|
|
23
|
+
command: 'screen-flow',
|
|
24
|
+
...(productId ? { productId } : {}),
|
|
25
|
+
});
|
|
26
|
+
if (productId) {
|
|
27
|
+
logInfo(`Starting screen flow generation for product ${productId}`);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
logInfo(`Starting screen flow generation for repository ${repoId}`);
|
|
21
31
|
}
|
|
22
|
-
await registerSession({ command: 'screen-flow', productId });
|
|
23
|
-
logInfo(`Starting screen flow generation for product ${productId}`);
|
|
24
32
|
try {
|
|
25
33
|
const result = await runScreenFlowPhase({
|
|
26
34
|
productId,
|
|
27
|
-
|
|
35
|
+
repoId,
|
|
36
|
+
diagramId,
|
|
28
37
|
guidance,
|
|
29
38
|
verbose,
|
|
30
39
|
});
|
|
@@ -0,0 +1,19 @@
|
|
|
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
|
+
export interface SequenceDiagramCliOptions {
|
|
13
|
+
diagramId: string;
|
|
14
|
+
/** Repo-only mode: generate against a single repositories row, no product. */
|
|
15
|
+
repoId?: string;
|
|
16
|
+
guidance?: string;
|
|
17
|
+
verbose?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function runSequenceDiagram(productId: string | undefined, options: SequenceDiagramCliOptions): Promise<void>;
|