@stan-chen/simple-cli 0.2.3 → 0.2.4

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 (136) hide show
  1. package/README.md +62 -63
  2. package/dist/anyllm.py +62 -0
  3. package/dist/builtins.d.ts +726 -0
  4. package/dist/builtins.js +481 -0
  5. package/dist/cli.d.ts +0 -4
  6. package/dist/cli.js +34 -493
  7. package/dist/engine.d.ts +33 -0
  8. package/dist/engine.js +138 -0
  9. package/dist/learnings.d.ts +15 -0
  10. package/dist/learnings.js +54 -0
  11. package/dist/llm.d.ts +18 -0
  12. package/dist/llm.js +66 -0
  13. package/dist/mcp.d.ts +132 -0
  14. package/dist/mcp.js +43 -0
  15. package/dist/skills.d.ts +5 -16
  16. package/dist/skills.js +91 -253
  17. package/dist/tui.d.ts +1 -0
  18. package/dist/tui.js +10 -0
  19. package/package.json +10 -6
  20. package/dist/claw/jit.d.ts +0 -5
  21. package/dist/claw/jit.js +0 -138
  22. package/dist/claw/management.d.ts +0 -3
  23. package/dist/claw/management.js +0 -107
  24. package/dist/commands/add.d.ts +0 -9
  25. package/dist/commands/add.js +0 -50
  26. package/dist/commands/git/commit.d.ts +0 -12
  27. package/dist/commands/git/commit.js +0 -98
  28. package/dist/commands/git/status.d.ts +0 -6
  29. package/dist/commands/git/status.js +0 -42
  30. package/dist/commands/index.d.ts +0 -16
  31. package/dist/commands/index.js +0 -377
  32. package/dist/commands/mcp/status.d.ts +0 -6
  33. package/dist/commands/mcp/status.js +0 -31
  34. package/dist/commands/swarm.d.ts +0 -36
  35. package/dist/commands/swarm.js +0 -236
  36. package/dist/commands.d.ts +0 -32
  37. package/dist/commands.js +0 -427
  38. package/dist/context.d.ts +0 -116
  39. package/dist/context.js +0 -337
  40. package/dist/index.d.ts +0 -6
  41. package/dist/index.js +0 -109
  42. package/dist/lib/agent.d.ts +0 -99
  43. package/dist/lib/agent.js +0 -313
  44. package/dist/lib/editor.d.ts +0 -74
  45. package/dist/lib/editor.js +0 -441
  46. package/dist/lib/git.d.ts +0 -164
  47. package/dist/lib/git.js +0 -356
  48. package/dist/lib/shim.d.ts +0 -4
  49. package/dist/lib/shim.js +0 -30
  50. package/dist/lib/ui.d.ts +0 -159
  51. package/dist/lib/ui.js +0 -277
  52. package/dist/mcp/client.d.ts +0 -22
  53. package/dist/mcp/client.js +0 -81
  54. package/dist/mcp/manager.d.ts +0 -186
  55. package/dist/mcp/manager.js +0 -446
  56. package/dist/prompts/provider.d.ts +0 -22
  57. package/dist/prompts/provider.js +0 -79
  58. package/dist/providers/index.d.ts +0 -31
  59. package/dist/providers/index.js +0 -93
  60. package/dist/providers/multi.d.ts +0 -12
  61. package/dist/providers/multi.js +0 -28
  62. package/dist/registry.d.ts +0 -29
  63. package/dist/registry.js +0 -443
  64. package/dist/repoMap.d.ts +0 -5
  65. package/dist/repoMap.js +0 -79
  66. package/dist/router.d.ts +0 -41
  67. package/dist/router.js +0 -118
  68. package/dist/swarm/coordinator.d.ts +0 -86
  69. package/dist/swarm/coordinator.js +0 -257
  70. package/dist/swarm/index.d.ts +0 -28
  71. package/dist/swarm/index.js +0 -29
  72. package/dist/swarm/task.d.ts +0 -104
  73. package/dist/swarm/task.js +0 -221
  74. package/dist/swarm/types.d.ts +0 -132
  75. package/dist/swarm/types.js +0 -37
  76. package/dist/swarm/worker.d.ts +0 -109
  77. package/dist/swarm/worker.js +0 -369
  78. package/dist/tools/analyzeFile.d.ts +0 -16
  79. package/dist/tools/analyzeFile.js +0 -43
  80. package/dist/tools/analyze_file.d.ts +0 -16
  81. package/dist/tools/analyze_file.js +0 -43
  82. package/dist/tools/clawBrain.d.ts +0 -23
  83. package/dist/tools/clawBrain.js +0 -136
  84. package/dist/tools/claw_brain.d.ts +0 -23
  85. package/dist/tools/claw_brain.js +0 -139
  86. package/dist/tools/deleteFile.d.ts +0 -19
  87. package/dist/tools/deleteFile.js +0 -36
  88. package/dist/tools/delete_file.d.ts +0 -19
  89. package/dist/tools/delete_file.js +0 -36
  90. package/dist/tools/fileOps.d.ts +0 -22
  91. package/dist/tools/fileOps.js +0 -43
  92. package/dist/tools/file_ops.d.ts +0 -22
  93. package/dist/tools/file_ops.js +0 -43
  94. package/dist/tools/git.d.ts +0 -40
  95. package/dist/tools/git.js +0 -236
  96. package/dist/tools/glob.d.ts +0 -34
  97. package/dist/tools/glob.js +0 -165
  98. package/dist/tools/grep.d.ts +0 -53
  99. package/dist/tools/grep.js +0 -296
  100. package/dist/tools/linter.d.ts +0 -35
  101. package/dist/tools/linter.js +0 -407
  102. package/dist/tools/listDir.d.ts +0 -29
  103. package/dist/tools/listDir.js +0 -50
  104. package/dist/tools/list_dir.d.ts +0 -29
  105. package/dist/tools/list_dir.js +0 -50
  106. package/dist/tools/memory.d.ts +0 -34
  107. package/dist/tools/memory.js +0 -215
  108. package/dist/tools/organizer.d.ts +0 -1
  109. package/dist/tools/organizer.js +0 -65
  110. package/dist/tools/readFiles.d.ts +0 -25
  111. package/dist/tools/readFiles.js +0 -31
  112. package/dist/tools/read_files.d.ts +0 -25
  113. package/dist/tools/read_files.js +0 -31
  114. package/dist/tools/reloadTools.d.ts +0 -11
  115. package/dist/tools/reloadTools.js +0 -22
  116. package/dist/tools/reload_tools.d.ts +0 -11
  117. package/dist/tools/reload_tools.js +0 -22
  118. package/dist/tools/runCommand.d.ts +0 -32
  119. package/dist/tools/runCommand.js +0 -79
  120. package/dist/tools/run_command.d.ts +0 -32
  121. package/dist/tools/run_command.js +0 -103
  122. package/dist/tools/scheduler.d.ts +0 -25
  123. package/dist/tools/scheduler.js +0 -65
  124. package/dist/tools/scraper.d.ts +0 -31
  125. package/dist/tools/scraper.js +0 -211
  126. package/dist/tools/writeFiles.d.ts +0 -63
  127. package/dist/tools/writeFiles.js +0 -87
  128. package/dist/tools/write_files.d.ts +0 -84
  129. package/dist/tools/write_files.js +0 -91
  130. package/dist/tools/write_to_file.d.ts +0 -15
  131. package/dist/tools/write_to_file.js +0 -21
  132. package/dist/ui/server.d.ts +0 -5
  133. package/dist/ui/server.js +0 -74
  134. package/dist/watcher.d.ts +0 -35
  135. package/dist/watcher.js +0 -164
  136. /package/{docs/assets → assets}/logo.jpeg +0 -0
package/dist/lib/agent.js DELETED
@@ -1,313 +0,0 @@
1
- /**
2
- * Agent Core - Main agent loop with reflection and retry
3
- * Implements Aider-style reasoning and error recovery
4
- */
5
- import { applyFileEdits, parseEditBlocks } from './editor.js';
6
- import { generateCommitMessage } from './git.js';
7
- import * as ui from './ui.js';
8
- /**
9
- * Parse LLM response into structured format
10
- */
11
- export function parseResponse(response) {
12
- // Accept either a TypeLLMResponse object or a raw string (tests and some providers pass raw text)
13
- const raw = typeof response === 'string' ? response : (response.raw || '');
14
- // Extract edit blocks - Aider style blocks are within the raw text
15
- const editBlocks = parseEditBlocks(raw);
16
- // If we were given a structured TypeLLMResponse, prefer its typed fields
17
- if (typeof response !== 'string') {
18
- const thought = response.thought;
19
- let tool = response.tool || 'none';
20
- const args = response.args || {};
21
- const message = response.message || '';
22
- // normalize tool name to snake_case
23
- if (tool && tool !== 'none') {
24
- tool = tool.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
25
- }
26
- const action = tool !== 'none'
27
- ? { tool, args }
28
- : { tool: 'none', message: message || (tool === 'none' ? 'No action parsed' : '') };
29
- return { thought, action, editBlocks };
30
- }
31
- // For raw string input, attempt to extract a <thought> block and a JSON action
32
- let thought;
33
- const thoughtMatch = raw.match(/<thought>[\s\S]*?<\/thought>/i);
34
- if (thoughtMatch) {
35
- thought = thoughtMatch[0].replace(/<\/?thought>/gi, '').trim();
36
- }
37
- // Extract first JSON-looking object from the raw text
38
- let action = { tool: 'none', message: 'No action parsed' };
39
- const jsonMatch = raw.match(/\{[\s\S]*\}/);
40
- if (jsonMatch) {
41
- try {
42
- const parsed = JSON.parse(jsonMatch[0]);
43
- let tool = parsed.tool || parsed.command || 'none';
44
- const args = parsed.args || parsed.parameters || {};
45
- if (tool && tool !== 'none') {
46
- // normalize camelCase to snake_case
47
- tool = String(tool).replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
48
- action = { tool, args };
49
- }
50
- else {
51
- action = { tool: 'none', message: parsed.message || 'No action parsed' };
52
- }
53
- }
54
- catch (e) {
55
- // If JSON.parse fails, leave action as 'none'
56
- action = { tool: 'none', message: 'No action parsed' };
57
- }
58
- }
59
- return { thought, action, editBlocks };
60
- }
61
- /**
62
- * Build reflection prompt for retry
63
- */
64
- export function buildReflectionPrompt(context) {
65
- let prompt = `## Reflection (Attempt ${context.attempt})
66
-
67
- Your previous response had errors that need to be fixed.
68
-
69
- ### Previous Error
70
- ${context.previousError}
71
-
72
- `;
73
- if (context.failedEdits.length > 0) {
74
- prompt += `### Failed Edits\n`;
75
- for (const edit of context.failedEdits) {
76
- prompt += `
77
- **File:** ${edit.file}
78
- **Error:** ${edit.error}
79
- ${edit.suggestion ? `**Suggestion:** ${edit.suggestion}` : ''}
80
- `;
81
- }
82
- }
83
- prompt += `
84
- ### Instructions
85
- - Review the error carefully
86
- - The SEARCH block must EXACTLY match existing content
87
- - Include enough context to make the match unique
88
- - Try again with corrected SEARCH/REPLACE blocks
89
- `;
90
- return prompt;
91
- }
92
- /**
93
- * Build lint error prompt
94
- */
95
- export function buildLintErrorPrompt(file, errors) {
96
- return `## Lint Errors Detected
97
-
98
- The file \`${file}\` has syntax errors after your changes:
99
-
100
- \`\`\`
101
- ${errors}
102
- \`\`\`
103
-
104
- Please fix these errors by providing corrected SEARCH/REPLACE blocks.
105
- Focus on the specific lines mentioned in the errors.
106
- `;
107
- }
108
- /**
109
- * Build test failure prompt
110
- */
111
- export function buildTestFailurePrompt(output) {
112
- return `## Test Failure
113
-
114
- The tests failed after your changes:
115
-
116
- \`\`\`
117
- ${output.slice(0, 2000)}${output.length > 2000 ? '\n... (truncated)' : ''}
118
- \`\`\`
119
-
120
- Please analyze the failure and fix the code.
121
- Provide SEARCH/REPLACE blocks for the necessary changes.
122
- `;
123
- }
124
- /**
125
- * Agent class - Main orchestration logic
126
- */
127
- export class Agent {
128
- config;
129
- git;
130
- generateFn;
131
- executeTool;
132
- lintFn;
133
- testFn;
134
- constructor(options) {
135
- this.config = options.config;
136
- this.git = options.git;
137
- this.generateFn = options.generateFn;
138
- this.executeTool = options.executeTool;
139
- this.lintFn = options.lintFn;
140
- this.testFn = options.testFn;
141
- }
142
- /**
143
- * Process a user message with reflection loop
144
- */
145
- async process(userMessage, history, systemPrompt) {
146
- let messages = [
147
- { role: 'system', content: systemPrompt },
148
- ...history,
149
- { role: 'user', content: userMessage },
150
- ];
151
- let attempt = 0;
152
- let editResults = [];
153
- let lintResults = [];
154
- let testResult;
155
- let commitResult;
156
- while (attempt < this.config.maxReflections) {
157
- attempt++;
158
- // Generate response
159
- const llmResponse = await ui.spin(attempt === 1 ? 'Thinking...' : `Reflecting (attempt ${attempt})...`, () => this.generateFn(messages));
160
- // Parse response
161
- const response = parseResponse(llmResponse);
162
- // Show thought if present
163
- if (response.thought) {
164
- ui.showThought(response.thought);
165
- }
166
- // Apply edit blocks if present
167
- if (response.editBlocks && response.editBlocks.length > 0) {
168
- ui.step(`Applying ${response.editBlocks.length} edit(s)...`);
169
- editResults = await applyFileEdits(response.editBlocks);
170
- const failed = editResults.filter(r => !r.success);
171
- const succeeded = editResults.filter(r => r.success);
172
- // Show results
173
- for (const result of succeeded) {
174
- ui.success(`✓ ${result.file}`);
175
- if (result.diff) {
176
- ui.showDiff(result.diff);
177
- }
178
- }
179
- for (const result of failed) {
180
- ui.error(`✗ ${result.file}: ${result.error}`);
181
- if (result.suggestion) {
182
- ui.note(result.suggestion, 'Suggestion');
183
- }
184
- }
185
- // If any edits failed, reflect and retry
186
- if (failed.length > 0 && attempt < this.config.maxReflections) {
187
- const reflectionPrompt = buildReflectionPrompt({
188
- attempt,
189
- previousError: failed.map(f => f.error).join('\n'),
190
- previousResponse: llmResponse.raw || JSON.stringify(llmResponse),
191
- failedEdits: failed,
192
- });
193
- messages = [
194
- ...messages,
195
- { role: 'assistant', content: llmResponse.raw || JSON.stringify(llmResponse) },
196
- { role: 'user', content: reflectionPrompt },
197
- ];
198
- continue;
199
- }
200
- // Run linting if enabled and edits succeeded
201
- if (this.config.autoLint && this.lintFn && succeeded.length > 0) {
202
- const filesToLint = [...new Set(succeeded.map(r => r.file))];
203
- for (const file of filesToLint) {
204
- const lintResult = await ui.spin(`Linting ${file}...`, () => this.lintFn(file));
205
- lintResults.push({ file, ...lintResult });
206
- if (!lintResult.passed && attempt < this.config.maxReflections) {
207
- ui.error(`Lint errors in ${file}`);
208
- const lintPrompt = buildLintErrorPrompt(file, lintResult.output);
209
- messages = [
210
- ...messages,
211
- { role: 'assistant', content: llmResponse.raw || JSON.stringify(llmResponse) },
212
- { role: 'user', content: lintPrompt },
213
- ];
214
- continue;
215
- }
216
- }
217
- }
218
- // Run tests if enabled
219
- if (this.config.autoTest && this.testFn && succeeded.length > 0) {
220
- testResult = await ui.spin('Running tests...', () => this.testFn());
221
- if (!testResult.passed && attempt < this.config.maxReflections) {
222
- ui.error('Tests failed');
223
- const testPrompt = buildTestFailurePrompt(testResult.output);
224
- messages = [
225
- ...messages,
226
- { role: 'assistant', content: llmResponse.raw || JSON.stringify(llmResponse) },
227
- { role: 'user', content: testPrompt },
228
- ];
229
- continue;
230
- }
231
- }
232
- // Auto-commit if enabled and all checks passed
233
- if (this.config.autoCommit && succeeded.length > 0) {
234
- const allLintsPassed = lintResults.every(r => r.passed);
235
- const testsPassed = !testResult || testResult.passed;
236
- if (allLintsPassed && testsPassed) {
237
- const diff = await this.git.diff();
238
- if (diff) {
239
- const commitMessage = await ui.spin('Generating commit message...', () => generateCommitMessage(diff, async (prompt) => {
240
- const res = await this.generateFn([
241
- { role: 'user', content: prompt },
242
- ]);
243
- return res.message || res.thought || res.raw || '';
244
- }));
245
- commitResult = await this.git.commit({
246
- message: commitMessage,
247
- files: succeeded.map(r => r.file),
248
- }) || undefined;
249
- if (commitResult) {
250
- ui.success(`Committed: ${commitResult.hash} ${commitResult.message}`);
251
- }
252
- }
253
- }
254
- }
255
- }
256
- // Execute tool action if not edit blocks
257
- if (response.action && 'tool' in response.action && response.action.tool !== 'none' && !response.editBlocks?.length) {
258
- const { tool, args } = response.action;
259
- ui.showToolCall(tool, args || {});
260
- try {
261
- const result = await this.executeTool(tool, args || {});
262
- const resultStr = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
263
- ui.showToolResult(resultStr);
264
- }
265
- catch (error) {
266
- ui.error(`Tool error: ${error instanceof Error ? error.message : error}`);
267
- }
268
- }
269
- return { response, editResults, lintResults, testResult, commitResult };
270
- }
271
- // Max reflections reached
272
- ui.warning(`Max reflections (${this.config.maxReflections}) reached`);
273
- return {
274
- response: { action: { tool: 'none', message: 'Max reflections reached' } },
275
- editResults,
276
- lintResults,
277
- testResult,
278
- commitResult,
279
- };
280
- }
281
- }
282
- /**
283
- * Summarize conversation history to reduce tokens
284
- */
285
- export async function summarizeHistory(history, generateFn, maxMessages = 10) {
286
- if (history.length <= maxMessages) {
287
- return history;
288
- }
289
- // Keep first message (usually important context) and last few messages
290
- const keepFirst = 1;
291
- const keepLast = maxMessages - 2;
292
- const toSummarize = history.slice(keepFirst, -keepLast);
293
- if (toSummarize.length === 0) {
294
- return history;
295
- }
296
- const summaryPrompt = `Summarize this conversation history concisely, preserving key information:
297
-
298
- ${toSummarize.map(m => `${m.role}: ${m.content}`).join('\n\n')}
299
-
300
- Provide a brief summary that captures:
301
- 1. Main topics discussed
302
- 2. Key decisions made
303
- 3. Important context for future messages`;
304
- const summaryRes = await generateFn([
305
- { role: 'user', content: summaryPrompt },
306
- ]);
307
- const summary = summaryRes.message || summaryRes.thought || summaryRes.raw || 'No summary generated';
308
- return [
309
- history[0], // Keep first
310
- { role: 'system', content: `[Conversation Summary]\n${summary}` },
311
- ...history.slice(-keepLast), // Keep last few
312
- ];
313
- }
@@ -1,74 +0,0 @@
1
- /**
2
- * Intelligent Code Editor using ts-morph and fuzzy matching
3
- * Provides Aider-style SEARCH/REPLACE with smart matching
4
- */
5
- import { SourceFile, Node } from 'ts-morph';
6
- export interface EditBlock {
7
- file: string;
8
- search: string;
9
- replace: string;
10
- }
11
- export interface EditResult {
12
- file: string;
13
- success: boolean;
14
- applied: boolean;
15
- error?: string;
16
- diff?: string;
17
- suggestion?: string;
18
- }
19
- /**
20
- * Apply a single edit to content
21
- */
22
- export declare function applyEdit(content: string, search: string, replace: string): {
23
- success: boolean;
24
- content: string;
25
- method: string;
26
- suggestion?: string;
27
- };
28
- /**
29
- * Apply edits to a file
30
- */
31
- export declare function applyFileEdits(edits: EditBlock[]): Promise<EditResult[]>;
32
- /**
33
- * Parse SEARCH/REPLACE blocks from LLM response
34
- */
35
- export declare function parseEditBlocks(response: string, validFiles?: string[]): EditBlock[];
36
- /**
37
- * TypeScript/JavaScript AST-aware editing using ts-morph
38
- */
39
- export declare class ASTEditor {
40
- private project;
41
- constructor();
42
- /**
43
- * Add a file to the project
44
- */
45
- addFile(path: string, content: string): SourceFile;
46
- /**
47
- * Get or create a source file
48
- */
49
- getSourceFile(path: string, content?: string): SourceFile | undefined;
50
- /**
51
- * Find a function by name
52
- */
53
- findFunction(sourceFile: SourceFile, name: string): Node | undefined;
54
- /**
55
- * Find a class by name
56
- */
57
- findClass(sourceFile: SourceFile, name: string): Node | undefined;
58
- /**
59
- * Rename a symbol across the project
60
- */
61
- renameSymbol(sourceFile: SourceFile, oldName: string, newName: string): boolean;
62
- /**
63
- * Get the modified content of a file
64
- */
65
- getContent(path: string): string | undefined;
66
- /**
67
- * Save all changes
68
- */
69
- saveAll(): Promise<void>;
70
- }
71
- /**
72
- * Create a code editor instance
73
- */
74
- export declare function createEditor(): ASTEditor;