@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.
Files changed (42) hide show
  1. package/README.md +238 -0
  2. package/dist/agents/analyst.d.ts +24 -0
  3. package/dist/agents/analyst.js +128 -0
  4. package/dist/agents/editor.d.ts +26 -0
  5. package/dist/agents/editor.js +157 -0
  6. package/dist/agents/planner-validator.d.ts +7 -0
  7. package/dist/agents/planner-validator.js +125 -0
  8. package/dist/agents/planner.d.ts +56 -0
  9. package/dist/agents/planner.js +186 -0
  10. package/dist/agents/writer.d.ts +25 -0
  11. package/dist/agents/writer.js +164 -0
  12. package/dist/commands/analyze.d.ts +14 -0
  13. package/dist/commands/analyze.js +562 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +41 -0
  16. package/dist/report/diagrams.d.ts +27 -0
  17. package/dist/report/diagrams.js +74 -0
  18. package/dist/report/graphCompiler.d.ts +37 -0
  19. package/dist/report/graphCompiler.js +277 -0
  20. package/dist/report/markdownGenerator.d.ts +71 -0
  21. package/dist/report/markdownGenerator.js +148 -0
  22. package/dist/tools/additional.d.ts +116 -0
  23. package/dist/tools/additional.js +349 -0
  24. package/dist/tools/extended.d.ts +101 -0
  25. package/dist/tools/extended.js +586 -0
  26. package/dist/tools/index.d.ts +86 -0
  27. package/dist/tools/index.js +362 -0
  28. package/dist/types/agents.types.d.ts +139 -0
  29. package/dist/types/agents.types.js +6 -0
  30. package/dist/types/graphSemantics.d.ts +99 -0
  31. package/dist/types/graphSemantics.js +104 -0
  32. package/dist/utils/debug.d.ts +28 -0
  33. package/dist/utils/debug.js +125 -0
  34. package/dist/utils/limoConfigParser.d.ts +21 -0
  35. package/dist/utils/limoConfigParser.js +274 -0
  36. package/dist/utils/reviewMonitor.d.ts +20 -0
  37. package/dist/utils/reviewMonitor.js +121 -0
  38. package/package.json +62 -0
  39. package/prompts/analyst.md +343 -0
  40. package/prompts/editor.md +196 -0
  41. package/prompts/planner.md +388 -0
  42. 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,6 @@
1
+ /**
2
+ * Limo CLI Agent Input/Output Types
3
+ *
4
+ * @deity.schema
5
+ */
6
+ export {};
@@ -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;