@limo-labs/limo-cli 0.1.0-alpha.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/README.md +238 -0
- package/dist/agents/analyst.d.ts +24 -0
- package/dist/agents/analyst.js +128 -0
- package/dist/agents/editor.d.ts +26 -0
- package/dist/agents/editor.js +157 -0
- package/dist/agents/planner-validator.d.ts +7 -0
- package/dist/agents/planner-validator.js +125 -0
- package/dist/agents/planner.d.ts +56 -0
- package/dist/agents/planner.js +186 -0
- package/dist/agents/writer.d.ts +25 -0
- package/dist/agents/writer.js +164 -0
- package/dist/commands/analyze.d.ts +14 -0
- package/dist/commands/analyze.js +562 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +41 -0
- package/dist/report/diagrams.d.ts +27 -0
- package/dist/report/diagrams.js +74 -0
- package/dist/report/graphCompiler.d.ts +37 -0
- package/dist/report/graphCompiler.js +277 -0
- package/dist/report/markdownGenerator.d.ts +71 -0
- package/dist/report/markdownGenerator.js +148 -0
- package/dist/tools/additional.d.ts +116 -0
- package/dist/tools/additional.js +349 -0
- package/dist/tools/extended.d.ts +101 -0
- package/dist/tools/extended.js +586 -0
- package/dist/tools/index.d.ts +86 -0
- package/dist/tools/index.js +362 -0
- package/dist/types/agents.types.d.ts +139 -0
- package/dist/types/agents.types.js +6 -0
- package/dist/types/graphSemantics.d.ts +99 -0
- package/dist/types/graphSemantics.js +104 -0
- package/dist/utils/debug.d.ts +28 -0
- package/dist/utils/debug.js +125 -0
- package/dist/utils/limoConfigParser.d.ts +21 -0
- package/dist/utils/limoConfigParser.js +274 -0
- package/dist/utils/reviewMonitor.d.ts +20 -0
- package/dist/utils/reviewMonitor.js +121 -0
- package/package.json +62 -0
- package/prompts/analyst.md +343 -0
- package/prompts/editor.md +196 -0
- package/prompts/planner.md +388 -0
- package/prompts/writer.md +218 -0
|
@@ -0,0 +1,362 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool implementations for Limo CLI
|
|
3
|
+
*/
|
|
4
|
+
import * as fs from 'fs/promises';
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { glob } from 'glob';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { createMemoryTools } from '@limo-labs/deity';
|
|
9
|
+
import { debug } from '../utils/debug.js';
|
|
10
|
+
import { createExtendedTools } from './extended.js';
|
|
11
|
+
import { createAdditionalTools } from './additional.js';
|
|
12
|
+
/**
|
|
13
|
+
* Count words in text, handling both CJK characters and whitespace-separated words.
|
|
14
|
+
* Each CJK character counts as one word; remaining text is split by whitespace.
|
|
15
|
+
*/
|
|
16
|
+
function countWords(text) {
|
|
17
|
+
const cjkChars = text.match(/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g);
|
|
18
|
+
const cjkCount = cjkChars ? cjkChars.length : 0;
|
|
19
|
+
const nonCjkText = text.replace(/[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/g, ' ');
|
|
20
|
+
const nonCjkWords = nonCjkText.split(/\s+/).filter(w => w.length > 0);
|
|
21
|
+
return cjkCount + nonCjkWords.length;
|
|
22
|
+
}
|
|
23
|
+
const FileListInputSchema = z.object({
|
|
24
|
+
root_path: z.string().describe('Root path to start listing from'),
|
|
25
|
+
pattern: z.string().describe('Glob pattern to match files'),
|
|
26
|
+
exclude_pattern: z.string().optional().describe('Glob pattern to exclude files'),
|
|
27
|
+
max_results: z.number().optional().describe('Maximum number of results to return')
|
|
28
|
+
});
|
|
29
|
+
export function createFileListTool(context) {
|
|
30
|
+
return {
|
|
31
|
+
name: 'file_list', // LIMO prefix to avoid conflicts with env tools
|
|
32
|
+
description: 'List files and directories in the project',
|
|
33
|
+
inputSchema: FileListInputSchema,
|
|
34
|
+
execute: async (params) => {
|
|
35
|
+
debug.toolCall('file_list', params);
|
|
36
|
+
const rootPath = path.resolve(context.workspaceRoot, params.root_path || '.');
|
|
37
|
+
const pattern = params.pattern || '**/*';
|
|
38
|
+
const maxResults = params.max_results || 500;
|
|
39
|
+
const files = await glob(pattern, {
|
|
40
|
+
cwd: rootPath,
|
|
41
|
+
ignore: [
|
|
42
|
+
'**/node_modules/**',
|
|
43
|
+
'**/.git/**',
|
|
44
|
+
'**/.limo/**',
|
|
45
|
+
...(params.exclude_pattern ? [params.exclude_pattern] : [])
|
|
46
|
+
],
|
|
47
|
+
nodir: true,
|
|
48
|
+
maxDepth: 10
|
|
49
|
+
});
|
|
50
|
+
const truncated = files.length > maxResults;
|
|
51
|
+
const resultFiles = files.slice(0, maxResults);
|
|
52
|
+
const result = {
|
|
53
|
+
success: true,
|
|
54
|
+
data: {
|
|
55
|
+
files: resultFiles,
|
|
56
|
+
total: resultFiles.length,
|
|
57
|
+
truncated,
|
|
58
|
+
message: truncated ? `Showing ${maxResults} of ${files.length} files (truncated)` : `Found ${files.length} files`
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
debug.toolResult('file_list', result);
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const FileReadInputSchema = z.object({
|
|
67
|
+
file_path: z.string().describe('Path to the file to read')
|
|
68
|
+
});
|
|
69
|
+
export function createFileReadTool(context) {
|
|
70
|
+
return {
|
|
71
|
+
name: 'file_read', // LIMO prefix to avoid conflicts with env tools
|
|
72
|
+
description: 'Read the contents of a file',
|
|
73
|
+
inputSchema: FileReadInputSchema,
|
|
74
|
+
execute: async (params) => {
|
|
75
|
+
const filePath = path.resolve(context.workspaceRoot, params.file_path);
|
|
76
|
+
try {
|
|
77
|
+
const content = await fs.readFile(filePath, 'utf-8');
|
|
78
|
+
const lines = content.split('\n');
|
|
79
|
+
const numberedLines = lines.map((line, idx) => `${idx + 1}\t${line}`).join('\n');
|
|
80
|
+
return { success: true, data: numberedLines };
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
error: `Error reading file: ${error instanceof Error ? error.message : String(error)}`
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
const TaskSchema = z.object({
|
|
92
|
+
task_id: z.string().describe('Unique task identifier (e.g., arch-01, dep-02)'),
|
|
93
|
+
module: z.string().describe('Module type (architecture, dependencies, security, code-quality, database, testing, migration)'),
|
|
94
|
+
title: z.string().describe('Concise task title'),
|
|
95
|
+
description: z.string().describe('Detailed description of what to analyze (2-3 sentences)'),
|
|
96
|
+
required_outputs: z.object({
|
|
97
|
+
report_sections: z.number().describe('Number of report sections (1-3)'),
|
|
98
|
+
code_examples: z.number().describe('Number of code examples (0-5)'),
|
|
99
|
+
diagrams: z.number().describe('Number of diagrams (0-2)'),
|
|
100
|
+
min_word_count: z.number().describe('Minimum word count (600-1200)')
|
|
101
|
+
}).describe('Required output specifications'),
|
|
102
|
+
memory_keys_to_generate: z.array(z.string()).optional().describe('Memory keys to generate (2-5 keys)'),
|
|
103
|
+
dependencies: z.array(z.string()).optional().describe('Task IDs this task depends on'),
|
|
104
|
+
status: z.string().optional().describe('Task status (always pending)')
|
|
105
|
+
});
|
|
106
|
+
const PlanningCreateInputSchema = z.object({
|
|
107
|
+
project_complexity: z.enum(['small', 'medium', 'large']).describe('Project complexity level'),
|
|
108
|
+
estimated_loc: z.number().describe('Estimated lines of code'),
|
|
109
|
+
estimated_files: z.number().describe('Estimated number of files'),
|
|
110
|
+
tasks: z.array(TaskSchema).describe('Array of analysis tasks')
|
|
111
|
+
});
|
|
112
|
+
export function createPlanningCreateTool(context) {
|
|
113
|
+
return {
|
|
114
|
+
name: 'planning_create', // LIMO prefix to avoid conflicts with env tools
|
|
115
|
+
description: 'Create a detailed analysis plan with sub-tasks',
|
|
116
|
+
inputSchema: PlanningCreateInputSchema,
|
|
117
|
+
execute: async (params) => {
|
|
118
|
+
debug.toolCall('planning_create', {
|
|
119
|
+
complexity: params.project_complexity,
|
|
120
|
+
files: params.estimated_files,
|
|
121
|
+
tasks: params.tasks.length
|
|
122
|
+
});
|
|
123
|
+
// Normalize tasks: add missing dependencies and status fields
|
|
124
|
+
const normalizedTasks = params.tasks.map(task => ({
|
|
125
|
+
...task,
|
|
126
|
+
dependencies: task.dependencies || [],
|
|
127
|
+
status: task.status || 'pending'
|
|
128
|
+
}));
|
|
129
|
+
const plan = {
|
|
130
|
+
project_complexity: params.project_complexity,
|
|
131
|
+
estimated_loc: params.estimated_loc,
|
|
132
|
+
estimated_files: params.estimated_files,
|
|
133
|
+
tasks: normalizedTasks, // Use normalized tasks
|
|
134
|
+
total_tasks: normalizedTasks.length,
|
|
135
|
+
created_at: new Date().toISOString(),
|
|
136
|
+
summary: {
|
|
137
|
+
tasks_by_module: normalizedTasks.reduce((acc, task) => {
|
|
138
|
+
acc[task.module] = (acc[task.module] || 0) + 1;
|
|
139
|
+
return acc;
|
|
140
|
+
}, {}),
|
|
141
|
+
total_sections_expected: normalizedTasks.reduce((sum, t) => sum + (t.required_outputs?.report_sections || 1), 0),
|
|
142
|
+
total_diagrams_expected: normalizedTasks.reduce((sum, t) => sum + (t.required_outputs?.diagrams || 0), 0),
|
|
143
|
+
total_words_expected: normalizedTasks.reduce((sum, t) => sum + (t.required_outputs?.min_word_count || 500), 0)
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
context.plan = plan;
|
|
147
|
+
const result = { success: true, data: plan };
|
|
148
|
+
debug.toolResult('planning_create', result);
|
|
149
|
+
return result;
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
const ReportWriteInputSchema = z.object({
|
|
154
|
+
section_id: z.string().describe('Unique section identifier'),
|
|
155
|
+
title: z.string().describe('Section title'),
|
|
156
|
+
content: z.string().describe('Section content in Markdown'),
|
|
157
|
+
level: z.number().optional().describe('Heading level (1-6)')
|
|
158
|
+
});
|
|
159
|
+
export function createReportWriteTool(context) {
|
|
160
|
+
return {
|
|
161
|
+
name: 'report_write', // LIMO prefix to avoid conflicts with env tools
|
|
162
|
+
description: 'Write a section to the analysis report',
|
|
163
|
+
inputSchema: ReportWriteInputSchema,
|
|
164
|
+
execute: async (params) => {
|
|
165
|
+
const level = params.level || 2;
|
|
166
|
+
const markdown = `${'#'.repeat(level)} ${params.title}\n\n${params.content}\n\n---\n\n`;
|
|
167
|
+
context.reportSections.set(params.section_id, markdown);
|
|
168
|
+
return {
|
|
169
|
+
success: true,
|
|
170
|
+
data: {
|
|
171
|
+
section_id: params.section_id,
|
|
172
|
+
word_count: countWords(params.content)
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
const ReportAddDiagramInputSchema = z.object({
|
|
179
|
+
diagram_id: z.string().describe('Unique diagram identifier'),
|
|
180
|
+
title: z.string().describe('Diagram title'),
|
|
181
|
+
description: z.string().optional().describe('Diagram description'),
|
|
182
|
+
section_id: z.string().optional().describe('ID of the report section this diagram belongs to (for embedding diagram in the section)'),
|
|
183
|
+
// PREFERRED: Semantic mode - nodes/edges provided, compile to SVG
|
|
184
|
+
nodes: z.array(z.any()).describe('Array of nodes/components (REQUIRED for semantic diagrams)'),
|
|
185
|
+
edges: z.array(z.any()).describe('Array of edges/relationships (REQUIRED for semantic diagrams)'),
|
|
186
|
+
groups: z.array(z.any()).optional().describe('Optional groups/clusters'),
|
|
187
|
+
// DEPRECATED: Direct source mode (only for SVG passthrough)
|
|
188
|
+
format: z.enum(['svg']).optional().describe('DEPRECATED: Only use "svg" if providing pre-rendered SVG'),
|
|
189
|
+
source: z.string().optional().describe('DEPRECATED: Only use for pre-rendered SVG source'),
|
|
190
|
+
related_files: z.array(z.string()).optional().describe('Related file paths'),
|
|
191
|
+
metadata: z.any().optional().describe('Optional metadata')
|
|
192
|
+
});
|
|
193
|
+
export function createReportAddDiagramTool(context) {
|
|
194
|
+
return {
|
|
195
|
+
name: 'report_add_diagram', // LIMO prefix to avoid conflicts with env tools
|
|
196
|
+
description: 'Add a diagram to the report using semantic structure (nodes + edges). ALWAYS use semantic mode with nodes/edges arrays - DO NOT use mermaid or DOT source code. The system will automatically compile to professional SVG diagrams.',
|
|
197
|
+
inputSchema: ReportAddDiagramInputSchema,
|
|
198
|
+
execute: async (params) => {
|
|
199
|
+
// Import diagram utilities dynamically
|
|
200
|
+
const { compileGraphToSvgSafe } = await import('../report/graphCompiler.js');
|
|
201
|
+
const { validateGraphSemantics } = await import('../types/graphSemantics.js');
|
|
202
|
+
// Legacy source mode (mermaid/dot) - DEPRECATED, return error
|
|
203
|
+
if (params.format && params.format !== 'svg') {
|
|
204
|
+
return {
|
|
205
|
+
success: false,
|
|
206
|
+
error: 'Mermaid and DOT formats are deprecated. Please use semantic structure with nodes/edges arrays instead. See tool description for examples.'
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// SVG passthrough mode (only for pre-rendered SVG)
|
|
210
|
+
if (params.format === 'svg' && params.source) {
|
|
211
|
+
context.diagrams.set(params.diagram_id, {
|
|
212
|
+
id: params.diagram_id,
|
|
213
|
+
title: params.title,
|
|
214
|
+
description: params.description,
|
|
215
|
+
format: 'svg',
|
|
216
|
+
source: params.source,
|
|
217
|
+
relatedFiles: params.related_files,
|
|
218
|
+
metadata: {
|
|
219
|
+
sectionId: params.section_id, // Store section association
|
|
220
|
+
generatedAt: new Date().toISOString()
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
return {
|
|
224
|
+
success: true,
|
|
225
|
+
data: {
|
|
226
|
+
diagram_id: params.diagram_id,
|
|
227
|
+
title: params.title,
|
|
228
|
+
format: 'svg',
|
|
229
|
+
source_length: params.source.length
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
// Semantic mode: nodes/edges provided, compile to SVG (PREFERRED)
|
|
234
|
+
if (!params.nodes || !params.edges) {
|
|
235
|
+
return {
|
|
236
|
+
success: false,
|
|
237
|
+
error: 'Must provide nodes and edges arrays for semantic diagram generation. Do not use format/source (deprecated).'
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
// Construct graph semantics
|
|
241
|
+
const graphSemantics = {
|
|
242
|
+
id: params.diagram_id,
|
|
243
|
+
title: params.title,
|
|
244
|
+
description: params.description,
|
|
245
|
+
nodes: params.nodes.map((n) => ({
|
|
246
|
+
id: n.id,
|
|
247
|
+
label: n.label,
|
|
248
|
+
type: n.type,
|
|
249
|
+
group: n.group,
|
|
250
|
+
description: n.description,
|
|
251
|
+
metadata: n.metadata
|
|
252
|
+
})),
|
|
253
|
+
edges: params.edges.map((e) => ({
|
|
254
|
+
from: e.from,
|
|
255
|
+
to: e.to,
|
|
256
|
+
type: e.type,
|
|
257
|
+
label: e.label,
|
|
258
|
+
bidirectional: e.bidirectional,
|
|
259
|
+
metadata: e.metadata
|
|
260
|
+
})),
|
|
261
|
+
groups: params.groups?.map((g) => ({
|
|
262
|
+
id: g.id,
|
|
263
|
+
label: g.label,
|
|
264
|
+
parent: g.parent,
|
|
265
|
+
type: g.type,
|
|
266
|
+
description: g.description
|
|
267
|
+
})),
|
|
268
|
+
metadata: params.metadata
|
|
269
|
+
};
|
|
270
|
+
// Validate graph semantics
|
|
271
|
+
const validation = validateGraphSemantics(graphSemantics);
|
|
272
|
+
if (!validation.valid) {
|
|
273
|
+
return {
|
|
274
|
+
success: false,
|
|
275
|
+
error: `Graph validation failed: ${validation.errors?.join(', ')}`
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
// Compile directly to SVG (DOT intermediate step is internal)
|
|
279
|
+
const svgResult = await compileGraphToSvgSafe(graphSemantics);
|
|
280
|
+
if (!svgResult.success) {
|
|
281
|
+
return {
|
|
282
|
+
success: false,
|
|
283
|
+
error: svgResult.error || 'Failed to compile graph to SVG'
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// Store diagram with SVG source
|
|
287
|
+
context.diagrams.set(params.diagram_id, {
|
|
288
|
+
id: params.diagram_id,
|
|
289
|
+
title: params.title,
|
|
290
|
+
description: params.description,
|
|
291
|
+
format: 'svg',
|
|
292
|
+
source: svgResult.svg,
|
|
293
|
+
relatedFiles: params.related_files,
|
|
294
|
+
metadata: {
|
|
295
|
+
sectionId: params.section_id, // Store section association
|
|
296
|
+
nodeCount: params.nodes.length,
|
|
297
|
+
edgeCount: params.edges.length,
|
|
298
|
+
generatedAt: new Date().toISOString()
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
return {
|
|
302
|
+
success: true,
|
|
303
|
+
data: {
|
|
304
|
+
diagram_id: params.diagram_id,
|
|
305
|
+
title: params.title,
|
|
306
|
+
nodes: params.nodes.length,
|
|
307
|
+
edges: params.edges.length,
|
|
308
|
+
validation: validation.warnings ? `passed with ${validation.warnings.length} warnings` : 'passed',
|
|
309
|
+
warnings: validation.warnings
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const ReportFinalizeInputSchema = z.object({
|
|
316
|
+
executive_summary: z.string().describe('Executive summary'),
|
|
317
|
+
recommendations: z.array(z.string()).optional().describe('List of recommendations')
|
|
318
|
+
});
|
|
319
|
+
export function createReportFinalizeTool(context) {
|
|
320
|
+
return {
|
|
321
|
+
name: 'report_finalize', // LIMO prefix to avoid conflicts with env tools
|
|
322
|
+
description: 'Finalize the analysis report',
|
|
323
|
+
inputSchema: ReportFinalizeInputSchema,
|
|
324
|
+
execute: async (params) => {
|
|
325
|
+
return {
|
|
326
|
+
success: true,
|
|
327
|
+
data: {
|
|
328
|
+
message: 'Report finalized',
|
|
329
|
+
executive_summary: params.executive_summary,
|
|
330
|
+
recommendations: params.recommendations
|
|
331
|
+
}
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Create all tools including Deity's memory tools
|
|
338
|
+
*
|
|
339
|
+
* @param context Tool context
|
|
340
|
+
* @param ctx ExecutionContext with memory enabled
|
|
341
|
+
* @returns Array of all tools
|
|
342
|
+
*/
|
|
343
|
+
export function createAllTools(context, ctx) {
|
|
344
|
+
// Get Deity's built-in memory tools
|
|
345
|
+
const memoryTools = ctx.memory ? createMemoryTools(ctx) : [];
|
|
346
|
+
return [
|
|
347
|
+
// File operation tools
|
|
348
|
+
createFileListTool(context),
|
|
349
|
+
createFileReadTool(context),
|
|
350
|
+
// Deity memory tools (replaces custom memory_store/memory_recall)
|
|
351
|
+
...memoryTools,
|
|
352
|
+
// Planning and reporting tools
|
|
353
|
+
createPlanningCreateTool(context),
|
|
354
|
+
createReportWriteTool(context),
|
|
355
|
+
createReportAddDiagramTool(context),
|
|
356
|
+
createReportFinalizeTool(context),
|
|
357
|
+
// Extended tools from VSCode extension
|
|
358
|
+
...createExtendedTools(context),
|
|
359
|
+
// Additional tools (UI, code analysis, etc.)
|
|
360
|
+
...createAdditionalTools(context)
|
|
361
|
+
];
|
|
362
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Limo CLI Agent Input/Output Types
|
|
3
|
+
*
|
|
4
|
+
* @deity.schema
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* LIMO.md configuration
|
|
8
|
+
* @zod
|
|
9
|
+
*/
|
|
10
|
+
export interface LimoConfig {
|
|
11
|
+
focusAreas?: string[];
|
|
12
|
+
excludeModules?: string[];
|
|
13
|
+
scopeDescription?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Planner agent input
|
|
17
|
+
* @zod
|
|
18
|
+
*/
|
|
19
|
+
export interface PlannerInput {
|
|
20
|
+
workspaceRoot: string;
|
|
21
|
+
modules?: string[];
|
|
22
|
+
limoConfig?: LimoConfig;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Task required outputs
|
|
26
|
+
* @zod
|
|
27
|
+
*/
|
|
28
|
+
export interface TaskRequiredOutputs {
|
|
29
|
+
report_sections: number;
|
|
30
|
+
code_examples: number;
|
|
31
|
+
diagrams: number;
|
|
32
|
+
min_word_count: number;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Task status
|
|
36
|
+
*/
|
|
37
|
+
export type TaskStatus = 'pending' | 'in_progress' | 'completed' | 'failed';
|
|
38
|
+
/**
|
|
39
|
+
* Project complexity
|
|
40
|
+
*/
|
|
41
|
+
export type ProjectComplexity = 'small' | 'medium' | 'large';
|
|
42
|
+
/**
|
|
43
|
+
* Task in the analysis plan
|
|
44
|
+
* @zod
|
|
45
|
+
*/
|
|
46
|
+
export interface PlanTask {
|
|
47
|
+
task_id: string;
|
|
48
|
+
module: string;
|
|
49
|
+
title: string;
|
|
50
|
+
description: string;
|
|
51
|
+
required_outputs: TaskRequiredOutputs;
|
|
52
|
+
memory_keys_to_generate?: string[];
|
|
53
|
+
dependencies: string[];
|
|
54
|
+
status: TaskStatus;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Plan summary
|
|
58
|
+
* @zod
|
|
59
|
+
*/
|
|
60
|
+
export interface PlanSummary {
|
|
61
|
+
tasks_by_module: Record<string, number>;
|
|
62
|
+
total_sections_expected: number;
|
|
63
|
+
total_diagrams_expected: number;
|
|
64
|
+
total_words_expected: number;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Planner agent output
|
|
68
|
+
* @zod
|
|
69
|
+
*/
|
|
70
|
+
export interface PlannerOutput {
|
|
71
|
+
project_complexity: ProjectComplexity;
|
|
72
|
+
estimated_loc: number;
|
|
73
|
+
estimated_files: number;
|
|
74
|
+
tasks: PlanTask[];
|
|
75
|
+
total_tasks: number;
|
|
76
|
+
estimated_duration_minutes?: number;
|
|
77
|
+
created_at: string;
|
|
78
|
+
summary: PlanSummary;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Analyst agent input
|
|
82
|
+
* @zod
|
|
83
|
+
*/
|
|
84
|
+
export interface AnalystInput {
|
|
85
|
+
task: PlanTask;
|
|
86
|
+
workspaceRoot: string;
|
|
87
|
+
promptsDir: string;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Analyst agent output
|
|
91
|
+
* @zod
|
|
92
|
+
*/
|
|
93
|
+
export interface AnalystOutput {
|
|
94
|
+
taskId: string;
|
|
95
|
+
success: boolean;
|
|
96
|
+
memoriesCreated: number;
|
|
97
|
+
error?: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Writer agent input
|
|
101
|
+
* @zod
|
|
102
|
+
*/
|
|
103
|
+
export interface WriterInput {
|
|
104
|
+
task: PlanTask;
|
|
105
|
+
promptsDir: string;
|
|
106
|
+
reportLanguage?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Writer agent output
|
|
110
|
+
* @zod
|
|
111
|
+
*/
|
|
112
|
+
export interface WriterOutput {
|
|
113
|
+
taskId: string;
|
|
114
|
+
sectionId: string;
|
|
115
|
+
success: boolean;
|
|
116
|
+
wordCount?: number;
|
|
117
|
+
error?: string;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Editor agent input
|
|
121
|
+
* @zod
|
|
122
|
+
*/
|
|
123
|
+
export interface EditorInput {
|
|
124
|
+
projectName: string;
|
|
125
|
+
taskCount: number;
|
|
126
|
+
sectionCount: number;
|
|
127
|
+
diagramCount: number;
|
|
128
|
+
promptsDir: string;
|
|
129
|
+
reportLanguage?: string;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Editor agent output
|
|
133
|
+
* @zod
|
|
134
|
+
*/
|
|
135
|
+
export interface EditorOutput {
|
|
136
|
+
success: boolean;
|
|
137
|
+
summaryGenerated: boolean;
|
|
138
|
+
error?: string;
|
|
139
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Graph Semantic Structure (Intermediate Representation)
|
|
3
|
+
*
|
|
4
|
+
* This IR defines the STRUCTURE of a graph, not its visual representation.
|
|
5
|
+
* LLM outputs this IR, and the code compiles it to DOT deterministically.
|
|
6
|
+
*
|
|
7
|
+
* CRITICAL CONSTRAINTS:
|
|
8
|
+
* - LLM MUST NOT output DOT/Graphviz syntax
|
|
9
|
+
* - LLM MUST NOT specify layout, coordinates, styles, or visual properties
|
|
10
|
+
* - Graph quality depends on structural modeling, not LLM's text expression
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Node type - represents a component, module, or entity
|
|
14
|
+
*/
|
|
15
|
+
export type GraphNodeType = 'component' | 'layer' | 'system' | 'data' | 'process' | 'actor';
|
|
16
|
+
/**
|
|
17
|
+
* Edge type - represents relationship semantics
|
|
18
|
+
*/
|
|
19
|
+
export type GraphEdgeType = 'depends_on' | 'calls' | 'uses' | 'contains' | 'inherits' | 'implements' | 'data_flow' | 'control_flow';
|
|
20
|
+
/**
|
|
21
|
+
* Node in the graph
|
|
22
|
+
*/
|
|
23
|
+
export interface GraphNode {
|
|
24
|
+
readonly id: string;
|
|
25
|
+
readonly label: string;
|
|
26
|
+
readonly type: GraphNodeType;
|
|
27
|
+
readonly group?: string;
|
|
28
|
+
readonly description?: string;
|
|
29
|
+
readonly metadata?: {
|
|
30
|
+
readonly filePath?: string;
|
|
31
|
+
readonly complexity?: 'low' | 'medium' | 'high';
|
|
32
|
+
[key: string]: unknown;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Edge in the graph
|
|
37
|
+
*/
|
|
38
|
+
export interface GraphEdge {
|
|
39
|
+
readonly from: string;
|
|
40
|
+
readonly to: string;
|
|
41
|
+
readonly type: GraphEdgeType;
|
|
42
|
+
readonly label?: string;
|
|
43
|
+
readonly bidirectional?: boolean;
|
|
44
|
+
readonly metadata?: {
|
|
45
|
+
readonly weight?: number;
|
|
46
|
+
readonly conditional?: boolean;
|
|
47
|
+
[key: string]: unknown;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Group/cluster for hierarchical organization
|
|
52
|
+
*/
|
|
53
|
+
export interface GraphGroup {
|
|
54
|
+
readonly id: string;
|
|
55
|
+
readonly label: string;
|
|
56
|
+
readonly parent?: string;
|
|
57
|
+
readonly type?: string;
|
|
58
|
+
readonly description?: string;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Architecture constraint or rule
|
|
62
|
+
*/
|
|
63
|
+
export interface GraphConstraint {
|
|
64
|
+
readonly type: 'allowed' | 'forbidden';
|
|
65
|
+
readonly from: string;
|
|
66
|
+
readonly to: string;
|
|
67
|
+
readonly reason?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Complete graph semantic structure
|
|
71
|
+
* This is what LLM outputs
|
|
72
|
+
*/
|
|
73
|
+
export interface GraphSemantics {
|
|
74
|
+
readonly id: string;
|
|
75
|
+
readonly title: string;
|
|
76
|
+
readonly description?: string;
|
|
77
|
+
readonly nodes: readonly GraphNode[];
|
|
78
|
+
readonly edges: readonly GraphEdge[];
|
|
79
|
+
readonly groups?: readonly GraphGroup[];
|
|
80
|
+
readonly constraints?: readonly GraphConstraint[];
|
|
81
|
+
readonly metadata?: {
|
|
82
|
+
readonly direction?: 'TB' | 'LR' | 'BT' | 'RL';
|
|
83
|
+
readonly focusNodes?: readonly string[];
|
|
84
|
+
readonly hiddenNodes?: readonly string[];
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Validation result for graph semantics
|
|
90
|
+
*/
|
|
91
|
+
export interface GraphValidationResult {
|
|
92
|
+
readonly valid: boolean;
|
|
93
|
+
readonly errors?: readonly string[];
|
|
94
|
+
readonly warnings?: readonly string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Validate graph semantic structure
|
|
98
|
+
*/
|
|
99
|
+
export declare function validateGraphSemantics(graph: GraphSemantics): GraphValidationResult;
|