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.
Files changed (83) hide show
  1. package/dist/api/github.d.ts +23 -0
  2. package/dist/api/github.js +61 -0
  3. package/dist/commands/architecture-diagram/index.d.ts +8 -0
  4. package/dist/commands/architecture-diagram/index.js +10 -0
  5. package/dist/commands/class-diagram/index.d.ts +7 -0
  6. package/dist/commands/class-diagram/index.js +9 -0
  7. package/dist/commands/data-flow/index.d.ts +8 -6
  8. package/dist/commands/data-flow/index.js +21 -12
  9. package/dist/commands/diagram-shared/index.d.ts +21 -0
  10. package/dist/commands/diagram-shared/index.js +37 -0
  11. package/dist/commands/er-diagram/index.d.ts +19 -0
  12. package/dist/commands/er-diagram/index.js +55 -0
  13. package/dist/commands/flowchart/index.d.ts +8 -0
  14. package/dist/commands/flowchart/index.js +10 -0
  15. package/dist/commands/quality-benchmark/index.js +43 -9
  16. package/dist/commands/recipes/index.d.ts +3 -1
  17. package/dist/commands/recipes/index.js +10 -4
  18. package/dist/commands/screen-flow/index.d.ts +8 -6
  19. package/dist/commands/screen-flow/index.js +21 -12
  20. package/dist/commands/sequence-diagram/index.d.ts +19 -0
  21. package/dist/commands/sequence-diagram/index.js +55 -0
  22. package/dist/commands/state-diagram/index.d.ts +7 -0
  23. package/dist/commands/state-diagram/index.js +9 -0
  24. package/dist/index.js +144 -14
  25. package/dist/phases/architecture-diagram/index.d.ts +15 -0
  26. package/dist/phases/architecture-diagram/index.js +51 -0
  27. package/dist/phases/class-diagram/index.d.ts +14 -0
  28. package/dist/phases/class-diagram/index.js +76 -0
  29. package/dist/phases/data-flow/index.d.ts +6 -3
  30. package/dist/phases/data-flow/index.js +59 -38
  31. package/dist/phases/data-flow/mcp-server.d.ts +1 -1
  32. package/dist/phases/data-flow/mcp-server.js +2 -2
  33. package/dist/phases/data-flow/types.d.ts +1 -1
  34. package/dist/phases/data-flow/types.js +1 -1
  35. package/dist/phases/diagram-shared/clone-repos.d.ts +63 -0
  36. package/dist/phases/diagram-shared/clone-repos.js +153 -0
  37. package/dist/phases/diagram-shared/generate.d.ts +42 -0
  38. package/dist/phases/diagram-shared/generate.js +162 -0
  39. package/dist/phases/diagram-shared/graph.d.ts +62 -0
  40. package/dist/phases/diagram-shared/graph.js +169 -0
  41. package/dist/phases/diagram-shared/mcp.d.ts +35 -0
  42. package/dist/phases/diagram-shared/mcp.js +68 -0
  43. package/dist/phases/diagram-shared/prompts.d.ts +23 -0
  44. package/dist/phases/diagram-shared/prompts.js +35 -0
  45. package/dist/phases/er-diagram/index.d.ts +28 -0
  46. package/dist/phases/er-diagram/index.js +290 -0
  47. package/dist/phases/er-diagram/mcp-server.d.ts +77 -0
  48. package/dist/phases/er-diagram/mcp-server.js +144 -0
  49. package/dist/phases/er-diagram/prompts.d.ts +14 -0
  50. package/dist/phases/er-diagram/prompts.js +36 -0
  51. package/dist/phases/er-diagram/types.d.ts +76 -0
  52. package/dist/phases/er-diagram/types.js +84 -0
  53. package/dist/phases/flow-shared/clone-repos.d.ts +8 -2
  54. package/dist/phases/flow-shared/clone-repos.js +36 -18
  55. package/dist/phases/flowchart/index.d.ts +15 -0
  56. package/dist/phases/flowchart/index.js +50 -0
  57. package/dist/phases/output-contracts.js +178 -2
  58. package/dist/phases/recipes/index.d.ts +8 -1
  59. package/dist/phases/recipes/index.js +74 -17
  60. package/dist/phases/recipes/mcp-server.d.ts +4 -1
  61. package/dist/phases/recipes/mcp-server.js +43 -18
  62. package/dist/phases/screen-flow/index.d.ts +7 -4
  63. package/dist/phases/screen-flow/index.js +66 -45
  64. package/dist/phases/screen-flow/mcp-server.js +2 -2
  65. package/dist/phases/sequence-diagram/index.d.ts +30 -0
  66. package/dist/phases/sequence-diagram/index.js +290 -0
  67. package/dist/phases/sequence-diagram/mcp-server.d.ts +64 -0
  68. package/dist/phases/sequence-diagram/mcp-server.js +134 -0
  69. package/dist/phases/sequence-diagram/prompts.d.ts +14 -0
  70. package/dist/phases/sequence-diagram/prompts.js +36 -0
  71. package/dist/phases/sequence-diagram/types.d.ts +52 -0
  72. package/dist/phases/sequence-diagram/types.js +93 -0
  73. package/dist/phases/state-diagram/index.d.ts +15 -0
  74. package/dist/phases/state-diagram/index.js +53 -0
  75. package/dist/skills/phase/architecture-diagram/SKILL.md +41 -0
  76. package/dist/skills/phase/class-diagram/SKILL.md +44 -0
  77. package/dist/skills/phase/er-diagram/SKILL.md +71 -0
  78. package/dist/skills/phase/flowchart/SKILL.md +38 -0
  79. package/dist/skills/phase/sequence-diagram/SKILL.md +67 -0
  80. package/dist/skills/phase/state-diagram/SKILL.md +38 -0
  81. package/dist/workspace/session-workspace.d.ts +2 -2
  82. package/dist/workspace/session-workspace.js +2 -2
  83. package/package.json +1 -1
@@ -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
@@ -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> --flow-id <id>
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
- * flows / flow_nodes / flow_edges (rows tagged type='data').
6
+ * diagrams / diagram_nodes / diagram_edges (rows tagged type='data').
7
7
  *
8
- * The desktop UI creates a pending flows row first, then invokes the CLI
9
- * with --flow-id; the CLI flips status running → success/failed and
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
- flowId: string;
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> --flow-id <id>
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
- * flows / flow_nodes / flow_edges (rows tagged type='data').
6
+ * diagrams / diagram_nodes / diagram_edges (rows tagged type='data').
7
7
  *
8
- * The desktop UI creates a pending flows row first, then invokes the CLI
9
- * with --flow-id; the CLI flips status running → success/failed and
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 { flowId, guidance, verbose } = options;
17
- if (!productId) {
18
- throw new Error('Product ID is required for data-flow');
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 (!flowId) {
21
- throw new Error('--flow-id is required (the pending flows row id)');
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
- flowId,
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
- logInfo(`Starting quality benchmark for product ${productId}`);
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
- const basics = await fetchProductBasics(productId).catch(() => ({
86
- name: productId,
87
- }));
88
- const productName = basics.name;
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('Product ID is required for recipes');
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
- logInfo(`Starting recipes scan for product ${productId}`);
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> --flow-id <id>
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 flows / flow_nodes / flow_edges (rows tagged type='screen').
5
+ * flow stored in diagrams / diagram_nodes / diagram_edges (rows tagged type='screen').
6
6
  *
7
- * The desktop UI creates a pending flows row first, then invokes the CLI
8
- * with --flow-id; the CLI flips status running → success/failed and
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
- flowId: string;
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> --flow-id <id>
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 flows / flow_nodes / flow_edges (rows tagged type='screen').
5
+ * flow stored in diagrams / diagram_nodes / diagram_edges (rows tagged type='screen').
6
6
  *
7
- * The desktop UI creates a pending flows row first, then invokes the CLI
8
- * with --flow-id; the CLI flips status running → success/failed and
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 { flowId, guidance, verbose } = options;
16
- if (!productId) {
17
- throw new Error('Product ID is required for screen-flow');
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 (!flowId) {
20
- throw new Error('--flow-id is required (the pending flows row id)');
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
- flowId,
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>;