@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
package/README.md
ADDED
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# Limo CLI
|
|
2
|
+
|
|
3
|
+
Command-line interface for Limo - AI-powered codebase analysis and migration planning tool.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🤖 **Multi-Agent Analysis** - Planner, Analyst, Writer, and Editor agents collaborate
|
|
8
|
+
- 📊 **Professional Reports** - Executive summaries, diagrams, and detailed analysis
|
|
9
|
+
- 🎯 **LIMO.md Support** - Customize analysis scope with LIMO.md configuration
|
|
10
|
+
- 📈 **Semantic Diagrams** - Type-safe architecture diagrams with nodes and edges
|
|
11
|
+
- 🌍 **Multi-language** - Supports English, 简体中文, 日本語, and more
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install
|
|
17
|
+
npm run build
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
### Basic Analysis
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
node dist/index.js analyze /path/to/project
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### With Options
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Specify language
|
|
32
|
+
node dist/index.js analyze /path/to/project --lang 简体中文
|
|
33
|
+
|
|
34
|
+
# Verbose mode (show AI thinking)
|
|
35
|
+
node dist/index.js analyze /path/to/project --verbose
|
|
36
|
+
|
|
37
|
+
# Custom modules
|
|
38
|
+
node dist/index.js analyze /path/to/project --modules architecture,security,dependencies
|
|
39
|
+
|
|
40
|
+
# Custom output directory
|
|
41
|
+
node dist/index.js analyze /path/to/project --output .limo-reports
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## LIMO.md Configuration
|
|
45
|
+
|
|
46
|
+
Create a `LIMO.md` file in your project root to customize the analysis:
|
|
47
|
+
|
|
48
|
+
```markdown
|
|
49
|
+
# LIMO Configuration
|
|
50
|
+
|
|
51
|
+
## Focus Areas
|
|
52
|
+
- security
|
|
53
|
+
- architecture
|
|
54
|
+
- dependencies
|
|
55
|
+
|
|
56
|
+
## Exclude
|
|
57
|
+
- testing
|
|
58
|
+
- migration
|
|
59
|
+
|
|
60
|
+
## Analysis Scope
|
|
61
|
+
Focus on the authentication and authorization modules.
|
|
62
|
+
|
|
63
|
+
## Company Context
|
|
64
|
+
This is a financial institution with strict security requirements.
|
|
65
|
+
|
|
66
|
+
## Constraints
|
|
67
|
+
- Must use Java 17
|
|
68
|
+
- Cannot use external dependencies
|
|
69
|
+
- Must maintain backward compatibility
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The CLI will automatically detect and parse LIMO.md, adjusting the analysis accordingly.
|
|
73
|
+
|
|
74
|
+
## Architecture
|
|
75
|
+
|
|
76
|
+
### 4-Phase Analysis Workflow
|
|
77
|
+
|
|
78
|
+
1. **Planning** - Planner creates comprehensive analysis plan
|
|
79
|
+
2. **Analysis** - Analyst performs deep code exploration
|
|
80
|
+
3. **Writing** - Writer generates detailed report sections
|
|
81
|
+
4. **Editing** - Editor creates executive summary and finalizes report
|
|
82
|
+
|
|
83
|
+
### Report Structure
|
|
84
|
+
|
|
85
|
+
```markdown
|
|
86
|
+
# Analysis Report - Project Name
|
|
87
|
+
|
|
88
|
+
**Generated**: February 21, 2026, 12:00:00 AM
|
|
89
|
+
**Project**: /path/to/project
|
|
90
|
+
**AI Model**: claude-opus-4.6
|
|
91
|
+
**Analysis Modules**: architecture, security, dependencies
|
|
92
|
+
|
|
93
|
+
**Statistics**:
|
|
94
|
+
- Report Sections: 15
|
|
95
|
+
- Diagrams: 8
|
|
96
|
+
- Key Findings: 42
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 📊 Executive Summary
|
|
101
|
+
|
|
102
|
+
[Overall analysis summary...]
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## Architecture Analysis
|
|
107
|
+
|
|
108
|
+
[Detailed content...]
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
*Diagram: System architecture showing main components*
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## Security Analysis
|
|
117
|
+
|
|
118
|
+
[Detailed content...]
|
|
119
|
+
|
|
120
|
+

|
|
121
|
+
|
|
122
|
+
*Diagram: Authentication and authorization flow*
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
## Report Output
|
|
126
|
+
|
|
127
|
+
Reports are saved to `.limo/reports/{uuid}/`:
|
|
128
|
+
- `report.md` - Final markdown report
|
|
129
|
+
- `memory.json` - Analysis memories
|
|
130
|
+
- `plan.json` - Analysis plan
|
|
131
|
+
|
|
132
|
+
## Development
|
|
133
|
+
|
|
134
|
+
### Build
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npm run build
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Watch Mode
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
npm run watch
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Debug
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
# Enable debug logging
|
|
150
|
+
LIMO_DEBUG=true node dist/index.js analyze /path/to/project
|
|
151
|
+
|
|
152
|
+
# Enable API debug logging
|
|
153
|
+
LIMO_DEBUG_API=true node dist/index.js analyze /path/to/project
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Requirements
|
|
157
|
+
|
|
158
|
+
- Node.js 18+
|
|
159
|
+
- GitHub Copilot subscription (for AI analysis)
|
|
160
|
+
- `gh` CLI installed and authenticated
|
|
161
|
+
|
|
162
|
+
## Project Structure
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
src/
|
|
166
|
+
├── index.ts # CLI entry point
|
|
167
|
+
├── commands/
|
|
168
|
+
│ └── analyze.ts # Main analysis command
|
|
169
|
+
├── agents/
|
|
170
|
+
│ ├── planner.ts # Planning agent
|
|
171
|
+
│ ├── analyst.ts # Analysis agent
|
|
172
|
+
│ ├── writer.ts # Writing agent
|
|
173
|
+
│ └── editor.ts # Editing agent
|
|
174
|
+
├── tools/
|
|
175
|
+
│ ├── index.ts # Core tools
|
|
176
|
+
│ ├── extended.ts # Extended tools
|
|
177
|
+
│ └── additional.ts # Additional tools
|
|
178
|
+
├── report/
|
|
179
|
+
│ ├── markdownGenerator.ts # Report generation
|
|
180
|
+
│ ├── diagrams.ts # Diagram embedding
|
|
181
|
+
│ └── graphCompiler.ts # Graph to SVG compilation
|
|
182
|
+
├── utils/
|
|
183
|
+
│ ├── debug.ts # Debug utilities
|
|
184
|
+
│ └── limoConfigParser.ts # LIMO.md parser
|
|
185
|
+
└── types/
|
|
186
|
+
└── graphSemantics.ts # Graph type definitions
|
|
187
|
+
|
|
188
|
+
prompts/
|
|
189
|
+
├── planner.md # Planner agent prompt
|
|
190
|
+
├── analyst.md # Analyst agent prompt
|
|
191
|
+
├── writer.md # Writer agent prompt
|
|
192
|
+
└── editor.md # Editor agent prompt
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
## Key Features
|
|
196
|
+
|
|
197
|
+
### Semantic Diagrams
|
|
198
|
+
|
|
199
|
+
Uses type-safe graph semantics for diagrams:
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
{
|
|
203
|
+
"diagram_id": "architecture",
|
|
204
|
+
"title": "System Architecture",
|
|
205
|
+
"nodes": [
|
|
206
|
+
{ "id": "web", "label": "Web Layer", "type": "layer" },
|
|
207
|
+
{ "id": "api", "label": "API Layer", "type": "layer" },
|
|
208
|
+
{ "id": "data", "label": "Data Layer", "type": "layer" }
|
|
209
|
+
],
|
|
210
|
+
"edges": [
|
|
211
|
+
{ "from": "web", "to": "api", "type": "calls" },
|
|
212
|
+
{ "from": "api", "to": "data", "type": "calls" }
|
|
213
|
+
]
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Available node types: `component`, `layer`, `system`, `data`, `process`, `actor`, `external`
|
|
218
|
+
Available edge types: `dependency`, `calls`, `uses`, `contains`, `inherits`, `implements`, `data_flow`, `control_flow`, `stored_in`, `manages`
|
|
219
|
+
|
|
220
|
+
### LIMO.md Parser
|
|
221
|
+
|
|
222
|
+
Automatically parses LIMO.md with smart detection:
|
|
223
|
+
- **Structured Markdown** - Sections with headings and lists
|
|
224
|
+
- **Natural Language** - Keywords like "focus on", "skip", "must"
|
|
225
|
+
- **Module Validation** - Validates against known modules
|
|
226
|
+
- **Constraints Extraction** - Finds "must", "cannot", "should not" statements
|
|
227
|
+
|
|
228
|
+
## License
|
|
229
|
+
|
|
230
|
+
MIT
|
|
231
|
+
|
|
232
|
+
## Contributing
|
|
233
|
+
|
|
234
|
+
Contributions welcome! Please open an issue or PR.
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
**Built with ❤️ using GitHub Copilot and Claude**
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyst Agent - Performs deep code analysis based on plan tasks
|
|
3
|
+
* Using declarative TSX syntax
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { type AgentNode } from '@limo-labs/deity';
|
|
7
|
+
declare const AnalystInputSchema: z.ZodObject<{
|
|
8
|
+
task: z.ZodAny;
|
|
9
|
+
workspaceRoot: z.ZodString;
|
|
10
|
+
promptsDir: z.ZodString;
|
|
11
|
+
}, z.core.$strip>;
|
|
12
|
+
type AnalystInput = z.infer<typeof AnalystInputSchema>;
|
|
13
|
+
declare const AnalystOutputSchema: z.ZodObject<{
|
|
14
|
+
taskId: z.ZodString;
|
|
15
|
+
success: z.ZodBoolean;
|
|
16
|
+
memoriesCreated: z.ZodNumber;
|
|
17
|
+
error: z.ZodOptional<z.ZodString>;
|
|
18
|
+
}, z.core.$strip>;
|
|
19
|
+
type AnalystOutput = z.infer<typeof AnalystOutputSchema>;
|
|
20
|
+
/**
|
|
21
|
+
* Create Analyst Agent using declarative TSX syntax
|
|
22
|
+
*/
|
|
23
|
+
export declare function createAnalystAgent(promptsDir: string): AgentNode<AnalystInput, AnalystOutput>;
|
|
24
|
+
export {};
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@limo-labs/deity/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Analyst Agent - Performs deep code analysis based on plan tasks
|
|
4
|
+
* Using declarative TSX syntax
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { Agent, Prompt, System, User, Result, Validate, Retry } from '@limo-labs/deity';
|
|
8
|
+
import { countToolCalls } from '@limo-labs/deity';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
// Input schema
|
|
12
|
+
const AnalystInputSchema = z.object({
|
|
13
|
+
task: z.any(), // Task object from plan
|
|
14
|
+
workspaceRoot: z.string(),
|
|
15
|
+
promptsDir: z.string()
|
|
16
|
+
});
|
|
17
|
+
// Output schema
|
|
18
|
+
const AnalystOutputSchema = z.object({
|
|
19
|
+
taskId: z.string(),
|
|
20
|
+
success: z.boolean(),
|
|
21
|
+
memoriesCreated: z.number(),
|
|
22
|
+
error: z.string().optional()
|
|
23
|
+
});
|
|
24
|
+
/**
|
|
25
|
+
* Build system prompt by loading from prompts directory
|
|
26
|
+
*/
|
|
27
|
+
async function buildSystemPrompt(promptsDir) {
|
|
28
|
+
const promptPath = path.join(promptsDir, 'analyst.md');
|
|
29
|
+
// Verify prompt file exists before reading
|
|
30
|
+
try {
|
|
31
|
+
await fs.access(promptPath);
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`Critical: Analyst prompt file not found at ${promptPath}\n` +
|
|
35
|
+
`Please ensure prompts are copied from VSCode extension or run 'npm run sync-prompts'`);
|
|
36
|
+
}
|
|
37
|
+
return await fs.readFile(promptPath, 'utf-8');
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Build user message with analysis task details
|
|
41
|
+
*/
|
|
42
|
+
function buildUserMessage(ctx) {
|
|
43
|
+
const { task, workspaceRoot } = ctx.inputs;
|
|
44
|
+
return `**Analysis Task**: ${task.title}
|
|
45
|
+
|
|
46
|
+
**Module**: ${task.module}
|
|
47
|
+
|
|
48
|
+
**Description**: ${task.description}
|
|
49
|
+
|
|
50
|
+
**Project Path**: ${workspaceRoot}
|
|
51
|
+
|
|
52
|
+
**Required Memory Keys** (suggestions - create these or similar):
|
|
53
|
+
${(task.memory_keys_to_generate || []).map((k) => `- ${k}`).join('\n')}
|
|
54
|
+
|
|
55
|
+
**Required Outputs**:
|
|
56
|
+
- Minimum word count: ${task.required_outputs?.min_word_count || 600}
|
|
57
|
+
- Code examples: ${task.required_outputs?.code_examples || 2}
|
|
58
|
+
- Diagrams: ${task.required_outputs?.diagrams || 0}
|
|
59
|
+
|
|
60
|
+
**Instructions**:
|
|
61
|
+
1. Use file_list to discover relevant files in the project
|
|
62
|
+
2. Use file_read to examine key files (pom.xml, source code, config files)
|
|
63
|
+
3. Extract and analyze: architecture patterns, tech stack, code quality, dependencies
|
|
64
|
+
4. Store ALL findings using memory_store with appropriate importance levels (7-10 for key discoveries)
|
|
65
|
+
5. Create ${(task.memory_keys_to_generate || []).length} or more detailed memory entries
|
|
66
|
+
|
|
67
|
+
Focus on discovering actual project specifics - file names, class names, versions, patterns from THIS project.
|
|
68
|
+
|
|
69
|
+
**Task Completion**: Your analysis is complete when you have stored ${(task.memory_keys_to_generate || []).length} or more memory entries with detailed findings.`;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract analyst output from LLM result
|
|
73
|
+
*/
|
|
74
|
+
function extractAnalystOutput(ctx, llmResult) {
|
|
75
|
+
// Count successful memory_store tool calls using utility
|
|
76
|
+
const memoriesCreated = countToolCalls(llmResult, 'memory_store', (result) => {
|
|
77
|
+
return result?.success === true;
|
|
78
|
+
});
|
|
79
|
+
const taskId = ctx.inputs.task.task_id;
|
|
80
|
+
if (memoriesCreated === 0) {
|
|
81
|
+
return {
|
|
82
|
+
taskId,
|
|
83
|
+
success: false,
|
|
84
|
+
memoriesCreated: 0,
|
|
85
|
+
error: 'Analyst did not store any memories - no analysis was performed'
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
taskId,
|
|
90
|
+
success: true,
|
|
91
|
+
memoriesCreated
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Create Analyst Agent using declarative TSX syntax
|
|
96
|
+
*/
|
|
97
|
+
export function createAnalystAgent(promptsDir) {
|
|
98
|
+
return (_jsxs(Agent, { id: "analyst", input: AnalystInputSchema, output: AnalystOutputSchema, children: [_jsxs(Prompt, { children: [_jsx(System, { children: async () => buildSystemPrompt(promptsDir) }), _jsx(User, { children: (ctx) => buildUserMessage(ctx) })] }), _jsx(Result, { children: (ctx, llmResult) => extractAnalystOutput(ctx, llmResult) }), _jsx(Validate, { children: (output, ctx) => {
|
|
99
|
+
const { task } = ctx.inputs;
|
|
100
|
+
const typedOutput = output;
|
|
101
|
+
const rules = [];
|
|
102
|
+
if (!typedOutput.success) {
|
|
103
|
+
if (!typedOutput.error) {
|
|
104
|
+
rules.push({
|
|
105
|
+
check: false,
|
|
106
|
+
error: 'Failed analysis must include error message'
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
return { rules };
|
|
110
|
+
}
|
|
111
|
+
// Check if memories were created
|
|
112
|
+
if (typedOutput.memoriesCreated === 0) {
|
|
113
|
+
rules.push({
|
|
114
|
+
check: false,
|
|
115
|
+
error: 'Analyst must store findings in memory'
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
// Check if required memory keys were generated
|
|
119
|
+
const requiredKeys = task.memory_keys_to_generate || [];
|
|
120
|
+
if (requiredKeys.length > 0 && typedOutput.memoriesCreated < requiredKeys.length) {
|
|
121
|
+
rules.push({
|
|
122
|
+
check: false,
|
|
123
|
+
error: `Expected at least ${requiredKeys.length} memory entries for keys: ${requiredKeys.join(', ')}`
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
return { rules };
|
|
127
|
+
} }), _jsx(Retry, { maxAttempts: 2, feedbackOnError: true })] }));
|
|
128
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Editor Agent - Generates executive summary and finalizes report
|
|
3
|
+
* Using declarative TSX syntax
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
import { type AgentNode } from '@limo-labs/deity';
|
|
7
|
+
declare const EditorInputSchema: z.ZodObject<{
|
|
8
|
+
projectName: z.ZodString;
|
|
9
|
+
taskCount: z.ZodNumber;
|
|
10
|
+
sectionCount: z.ZodNumber;
|
|
11
|
+
diagramCount: z.ZodNumber;
|
|
12
|
+
promptsDir: z.ZodString;
|
|
13
|
+
reportLanguage: z.ZodOptional<z.ZodString>;
|
|
14
|
+
}, z.core.$strip>;
|
|
15
|
+
type EditorInput = z.infer<typeof EditorInputSchema>;
|
|
16
|
+
declare const EditorOutputSchema: z.ZodObject<{
|
|
17
|
+
success: z.ZodBoolean;
|
|
18
|
+
summaryGenerated: z.ZodBoolean;
|
|
19
|
+
error: z.ZodOptional<z.ZodString>;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type EditorOutput = z.infer<typeof EditorOutputSchema>;
|
|
22
|
+
/**
|
|
23
|
+
* Create Editor Agent using declarative TSX syntax
|
|
24
|
+
*/
|
|
25
|
+
export declare function createEditorAgent(promptsDir: string): AgentNode<EditorInput, EditorOutput>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "@limo-labs/deity/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Editor Agent - Generates executive summary and finalizes report
|
|
4
|
+
* Using declarative TSX syntax
|
|
5
|
+
*/
|
|
6
|
+
import { z } from 'zod';
|
|
7
|
+
import { Agent, Prompt, System, User, Result, Validate, Retry } from '@limo-labs/deity';
|
|
8
|
+
import { extractAllToolResults } from '@limo-labs/deity';
|
|
9
|
+
import * as fs from 'fs/promises';
|
|
10
|
+
import * as path from 'path';
|
|
11
|
+
// Input schema
|
|
12
|
+
const EditorInputSchema = z.object({
|
|
13
|
+
projectName: z.string(),
|
|
14
|
+
taskCount: z.number(),
|
|
15
|
+
sectionCount: z.number(),
|
|
16
|
+
diagramCount: z.number(),
|
|
17
|
+
promptsDir: z.string(),
|
|
18
|
+
reportLanguage: z.string().optional()
|
|
19
|
+
});
|
|
20
|
+
// Output schema
|
|
21
|
+
const EditorOutputSchema = z.object({
|
|
22
|
+
success: z.boolean(),
|
|
23
|
+
summaryGenerated: z.boolean(),
|
|
24
|
+
error: z.string().optional()
|
|
25
|
+
});
|
|
26
|
+
/**
|
|
27
|
+
* Build system prompt by loading from prompts directory
|
|
28
|
+
*/
|
|
29
|
+
async function buildSystemPrompt(promptsDir, reportLanguage) {
|
|
30
|
+
const promptPath = path.join(promptsDir, 'editor.md');
|
|
31
|
+
// Verify prompt file exists before reading
|
|
32
|
+
try {
|
|
33
|
+
await fs.access(promptPath);
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
throw new Error(`Critical: Editor prompt file not found at ${promptPath}\n` +
|
|
37
|
+
`Please ensure prompts are copied from VSCode extension or run 'npm run sync-prompts'`);
|
|
38
|
+
}
|
|
39
|
+
let systemPrompt = await fs.readFile(promptPath, 'utf-8');
|
|
40
|
+
// Inject language instruction if reportLanguage is provided
|
|
41
|
+
if (reportLanguage && reportLanguage !== 'English') {
|
|
42
|
+
const languageInstruction = `
|
|
43
|
+
|
|
44
|
+
## CRITICAL: Output Language Requirement
|
|
45
|
+
|
|
46
|
+
**YOU MUST write ALL content in ${reportLanguage}.**
|
|
47
|
+
|
|
48
|
+
This applies to:
|
|
49
|
+
- Executive summary
|
|
50
|
+
- Section titles and headings
|
|
51
|
+
- All descriptions and findings
|
|
52
|
+
- Recommendations
|
|
53
|
+
|
|
54
|
+
IMPORTANT Guidelines:
|
|
55
|
+
1. Write naturally in ${reportLanguage}, not as a direct translation
|
|
56
|
+
2. Use appropriate technical terminology for ${reportLanguage}
|
|
57
|
+
3. Preserve code snippets and technical identifiers in their original language
|
|
58
|
+
4. Memory keys must remain in English (system requirement)
|
|
59
|
+
|
|
60
|
+
`;
|
|
61
|
+
systemPrompt = systemPrompt + languageInstruction;
|
|
62
|
+
}
|
|
63
|
+
return systemPrompt;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build user message with editing task details
|
|
67
|
+
*/
|
|
68
|
+
function buildUserMessage(ctx) {
|
|
69
|
+
const { projectName, taskCount, sectionCount, diagramCount } = ctx.inputs;
|
|
70
|
+
return `**Report Finalization Task**: Generate Executive Summary
|
|
71
|
+
|
|
72
|
+
**Project**: ${projectName}
|
|
73
|
+
**Analysis Scope**:
|
|
74
|
+
- ${taskCount} analysis tasks completed
|
|
75
|
+
- ${sectionCount} report sections generated
|
|
76
|
+
- ${diagramCount} diagrams created
|
|
77
|
+
|
|
78
|
+
**Your Responsibilities**:
|
|
79
|
+
|
|
80
|
+
1. **Generate Executive Summary** (MANDATORY)
|
|
81
|
+
- Recall all key memories to understand the full analysis
|
|
82
|
+
- Create a comprehensive overview (200-400 words) covering:
|
|
83
|
+
* What the project is (brief description)
|
|
84
|
+
* Key findings from the analysis
|
|
85
|
+
* Architecture highlights and patterns
|
|
86
|
+
* Main recommendations for improvement
|
|
87
|
+
- Use section_id "executive_summary" when calling report_write
|
|
88
|
+
|
|
89
|
+
2. **Review Report Quality**
|
|
90
|
+
- Ensure all sections are cohesive
|
|
91
|
+
- Check that findings are actionable
|
|
92
|
+
- Verify diagrams support the narrative
|
|
93
|
+
|
|
94
|
+
**Instructions**:
|
|
95
|
+
1. Use memory_list or memory_search to discover all analysis findings
|
|
96
|
+
2. Recall key memories across different areas (architecture, code quality, testing, etc.)
|
|
97
|
+
3. Synthesize findings into a coherent executive summary
|
|
98
|
+
4. MUST call report_write with section_id "executive_summary" (THIS IS MANDATORY!)
|
|
99
|
+
|
|
100
|
+
The executive summary should give readers a clear understanding of:
|
|
101
|
+
- What was analyzed
|
|
102
|
+
- What was discovered
|
|
103
|
+
- What should be done next
|
|
104
|
+
|
|
105
|
+
Write based on ACTUAL analysis findings - be specific and actionable.`;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Extract editor output from LLM result
|
|
109
|
+
*/
|
|
110
|
+
function extractEditorOutput(_ctx, llmResult) {
|
|
111
|
+
// Extract all report_write results using utility
|
|
112
|
+
const allReports = extractAllToolResults(llmResult, 'report_write', {
|
|
113
|
+
unwrap: true,
|
|
114
|
+
required: false
|
|
115
|
+
});
|
|
116
|
+
if (allReports.length === 0) {
|
|
117
|
+
return {
|
|
118
|
+
success: false,
|
|
119
|
+
summaryGenerated: false,
|
|
120
|
+
error: 'Editor did not call report_write - no executive summary was generated'
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
// Check if executive_summary section was created
|
|
124
|
+
const execSummaryCreated = allReports.some((report) => report?.section_id === 'executive_summary');
|
|
125
|
+
return {
|
|
126
|
+
success: true,
|
|
127
|
+
summaryGenerated: execSummaryCreated
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create Editor Agent using declarative TSX syntax
|
|
132
|
+
*/
|
|
133
|
+
export function createEditorAgent(promptsDir) {
|
|
134
|
+
return (_jsxs(Agent, { id: "editor", input: EditorInputSchema, output: EditorOutputSchema, children: [_jsxs(Prompt, { children: [_jsx(System, { children: async (ctx) => {
|
|
135
|
+
const reportLanguage = ctx.inputs.reportLanguage;
|
|
136
|
+
return buildSystemPrompt(promptsDir, reportLanguage);
|
|
137
|
+
} }), _jsx(User, { children: (ctx) => buildUserMessage(ctx) })] }), _jsx(Result, { children: (ctx, llmResult) => extractEditorOutput(ctx, llmResult) }), _jsx(Validate, { children: (output) => {
|
|
138
|
+
const typedOutput = output;
|
|
139
|
+
const rules = [];
|
|
140
|
+
if (!typedOutput.success) {
|
|
141
|
+
if (!typedOutput.error) {
|
|
142
|
+
rules.push({
|
|
143
|
+
check: false,
|
|
144
|
+
error: 'Failed task must include error message'
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return { rules };
|
|
148
|
+
}
|
|
149
|
+
if (!typedOutput.summaryGenerated) {
|
|
150
|
+
rules.push({
|
|
151
|
+
check: false,
|
|
152
|
+
error: 'Editor must generate executive summary (section_id: "executive_summary")'
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
return { rules };
|
|
156
|
+
} }), _jsx(Retry, { maxAttempts: 2, feedbackOnError: true })] }));
|
|
157
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner Validator - Validates that planner created a comprehensive analysis plan
|
|
3
|
+
*/
|
|
4
|
+
import type { Validator, ValidationResult, LLMLoopState, ExecutionContext } from '@limo-labs/deity';
|
|
5
|
+
export declare class PlannerValidator implements Validator {
|
|
6
|
+
validate(ctx: ExecutionContext, loopState: LLMLoopState): Promise<ValidationResult>;
|
|
7
|
+
}
|