@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
@@ -1,369 +0,0 @@
1
- /**
2
- * Worker - Spawns and manages Simple-CLI worker processes
3
- */
4
- import { spawn } from 'child_process';
5
- import { EventEmitter } from 'events';
6
- import { randomUUID } from 'crypto';
7
- export class Worker extends EventEmitter {
8
- id;
9
- process = null;
10
- state = 'idle';
11
- currentTask = null;
12
- startedAt = 0;
13
- output = '';
14
- options;
15
- isTerminating = false;
16
- onUnexpectedExit = (code) => {
17
- if (!this.isTerminating) {
18
- this.emit('error', new Error(`Worker process exited unexpectedly with code ${code}`));
19
- }
20
- };
21
- constructor(options) {
22
- super();
23
- this.id = `worker-${randomUUID().slice(0, 8)}`;
24
- this.options = options;
25
- }
26
- /**
27
- * Get current worker status
28
- */
29
- getStatus() {
30
- return {
31
- id: this.id,
32
- pid: this.process?.pid,
33
- state: this.state,
34
- currentTask: this.currentTask?.id,
35
- startedAt: this.startedAt || undefined,
36
- completedAt: this.state === 'completed' || this.state === 'failed' ? Date.now() : undefined,
37
- };
38
- }
39
- /**
40
- * Execute a task
41
- */
42
- async execute(task) {
43
- if (this.state === 'running') {
44
- throw new Error(`Worker ${this.id} is already running a task`);
45
- }
46
- this.currentTask = task;
47
- this.state = 'running';
48
- this.startedAt = Date.now();
49
- this.output = '';
50
- return new Promise((resolve, reject) => {
51
- const timeout = task.timeout || this.options.timeout;
52
- let timeoutId = null;
53
- let resolved = false;
54
- const cleanup = () => {
55
- if (timeoutId)
56
- clearTimeout(timeoutId);
57
- this.process = null;
58
- };
59
- const finish = (result) => {
60
- if (resolved)
61
- return;
62
- resolved = true;
63
- cleanup();
64
- this.state = result.success ? 'completed' : 'failed';
65
- this.emit('complete', result);
66
- resolve(result);
67
- };
68
- // Build the prompt from task
69
- const prompt = this.buildPrompt(task);
70
- // Spawn Simple-CLI process
71
- const args = ['--yolo'];
72
- if (this.options.yolo)
73
- args.push('--yolo');
74
- args.push(prompt);
75
- // Use node to run the CLI directly
76
- const cliPath = new URL('../index.js', import.meta.url).pathname;
77
- this.process = spawn('node', [cliPath, ...args], {
78
- cwd: this.options.cwd,
79
- env: {
80
- ...process.env,
81
- ...this.options.env,
82
- SIMPLE_CLI_WORKER: this.id,
83
- SIMPLE_CLI_TASK: task.id,
84
- },
85
- stdio: ['pipe', 'pipe', 'pipe'],
86
- });
87
- this.emit('spawn', this.getStatus());
88
- // Collect output
89
- this.process.stdout?.on('data', (data) => {
90
- this.output += data.toString();
91
- });
92
- this.process.stderr?.on('data', (data) => {
93
- this.output += data.toString();
94
- });
95
- // Handle process exit
96
- this.process.on('close', (code) => {
97
- const duration = Date.now() - this.startedAt;
98
- const success = code === 0;
99
- // Parse output for changed files (simplified)
100
- const filesChanged = this.parseChangedFiles(this.output);
101
- const commitHash = this.parseCommitHash(this.output);
102
- finish({
103
- success,
104
- filesChanged,
105
- commitHash,
106
- error: success ? undefined : `Process exited with code ${code}`,
107
- duration,
108
- output: this.output,
109
- });
110
- });
111
- this.process.on('error', (err) => {
112
- finish({
113
- success: false,
114
- filesChanged: [],
115
- error: err.message,
116
- duration: Date.now() - this.startedAt,
117
- output: this.output,
118
- });
119
- });
120
- // Set timeout
121
- timeoutId = setTimeout(() => {
122
- if (!resolved) {
123
- (async () => {
124
- try {
125
- await this.kill();
126
- }
127
- catch (e) { /* best-effort */ }
128
- finish({
129
- success: false,
130
- filesChanged: [],
131
- error: `Task timed out after ${timeout}ms`,
132
- duration: timeout,
133
- output: this.output,
134
- });
135
- })();
136
- }
137
- }, timeout);
138
- // Send task to stdin and close
139
- this.process.stdin?.write(prompt);
140
- this.process.stdin?.end();
141
- });
142
- }
143
- /**
144
- * Build prompt from task
145
- */
146
- buildPrompt(task) {
147
- let prompt = task.description;
148
- if (task.scope.files && task.scope.files.length > 0) {
149
- prompt += `\n\nFocus on these files: ${task.scope.files.join(', ')}`;
150
- }
151
- if (task.scope.directories && task.scope.directories.length > 0) {
152
- prompt += `\n\nWork in these directories: ${task.scope.directories.join(', ')}`;
153
- }
154
- if (task.scope.pattern) {
155
- prompt += `\n\nApply to files matching: ${task.scope.pattern}`;
156
- }
157
- return prompt;
158
- }
159
- /**
160
- * Parse changed files from output
161
- */
162
- parseChangedFiles(output) {
163
- const files = [];
164
- // Look for common patterns indicating file changes
165
- const patterns = [
166
- /(?:wrote|created|modified|updated)\s+([^\s]+)/gi,
167
- /\[Result\].*(?:wrote|created)\s+([^\s]+)/gi,
168
- ];
169
- for (const pattern of patterns) {
170
- let match;
171
- while ((match = pattern.exec(output)) !== null) {
172
- const file = match[1].replace(/['"`,]/g, '');
173
- if (file && !files.includes(file)) {
174
- files.push(file);
175
- }
176
- }
177
- }
178
- return files;
179
- }
180
- /**
181
- * Parse commit hash from output
182
- */
183
- parseCommitHash(output) {
184
- const match = output.match(/commit\s+([a-f0-9]{7,40})/i);
185
- return match ? match[1] : undefined;
186
- }
187
- /**
188
- * Kill the worker process
189
- */
190
- kill() {
191
- // Keep backwards-compatible signature: return a Promise but allow callers to ignore it.
192
- const graceMs = 5000;
193
- const promise = (async () => {
194
- if (!this.process)
195
- return;
196
- if (this.process.killed)
197
- return;
198
- this.isTerminating = true;
199
- // stop reporting unexpected-exit while we intentionally terminate
200
- try {
201
- this.process.off('exit', this.onUnexpectedExit);
202
- }
203
- catch (e) { }
204
- // If IPC is available, politely ask the child to shutdown
205
- try {
206
- if (this.process.connected) {
207
- try {
208
- this.process.send({ type: 'shutdown' });
209
- }
210
- catch (e) { }
211
- }
212
- }
213
- catch (e) { }
214
- try {
215
- this.process.kill('SIGTERM');
216
- }
217
- catch (e) {
218
- // ignore
219
- }
220
- // wait for exit up to graceMs, otherwise force-kill
221
- await new Promise((resolve) => {
222
- let resolved = false;
223
- const onExit = () => {
224
- if (resolved)
225
- return;
226
- resolved = true;
227
- clearTimeout(timer);
228
- resolve(undefined);
229
- };
230
- const timer = setTimeout(() => {
231
- try {
232
- if (this.process && !this.process.killed)
233
- this.process.kill('SIGKILL');
234
- }
235
- catch (e) { }
236
- // still wait for exit event
237
- }, graceMs);
238
- try {
239
- if (this.process)
240
- this.process.once('exit', onExit);
241
- }
242
- catch (e) {
243
- resolve(undefined);
244
- }
245
- });
246
- try {
247
- this.process = null;
248
- }
249
- catch (e) { }
250
- })();
251
- // Log kill action for auditing
252
- try {
253
- const fs = require('fs');
254
- const path = require('path');
255
- fs.appendFileSync(path.join(process.cwd(), '.worker_kill.log'), `${new Date().toISOString()} kill requested for worker ${this.id}\n`);
256
- }
257
- catch (e) { }
258
- return promise;
259
- }
260
- /**
261
- * Check if worker is busy
262
- */
263
- isBusy() {
264
- return this.state === 'running';
265
- }
266
- /**
267
- * Check if worker is available
268
- */
269
- isAvailable() {
270
- return this.state === 'idle' || this.state === 'completed' || this.state === 'failed';
271
- }
272
- /**
273
- * Reset worker for reuse
274
- */
275
- reset() {
276
- this.state = 'idle';
277
- this.currentTask = null;
278
- this.startedAt = 0;
279
- this.output = '';
280
- this.process = null;
281
- }
282
- /**
283
- * Get task output
284
- */
285
- getOutput() {
286
- return this.output;
287
- }
288
- }
289
- /**
290
- * Worker pool for managing multiple workers
291
- */
292
- export class WorkerPool {
293
- workers = [];
294
- inUse = new Set();
295
- options;
296
- maxWorkers;
297
- constructor(maxWorkers, options) {
298
- this.maxWorkers = maxWorkers;
299
- this.options = options;
300
- }
301
- /**
302
- * Get an available worker (or create one if pool not full)
303
- */
304
- getWorker() {
305
- // Create new worker if pool not full
306
- if (this.workers.length < this.maxWorkers) {
307
- const worker = new Worker(this.options);
308
- this.workers.push(worker);
309
- this.inUse.add(worker.id);
310
- return worker;
311
- }
312
- // Try to find an available worker that's not in use
313
- const available = this.workers.find(w => w.isAvailable() && !this.inUse.has(w.id));
314
- if (available) {
315
- available.reset();
316
- this.inUse.add(available.id);
317
- return available;
318
- }
319
- return null;
320
- }
321
- /**
322
- * Release a worker back to the pool
323
- */
324
- releaseWorker(worker) {
325
- this.inUse.delete(worker.id);
326
- }
327
- /**
328
- * Get all workers
329
- */
330
- getAllWorkers() {
331
- return [...this.workers];
332
- }
333
- /**
334
- * Get worker by ID
335
- */
336
- getWorkerById(id) {
337
- return this.workers.find(w => w.id === id);
338
- }
339
- /**
340
- * Get number of busy workers
341
- */
342
- getBusyCount() {
343
- return this.workers.filter(w => w.isBusy()).length;
344
- }
345
- /**
346
- * Get number of available workers
347
- */
348
- getAvailableCount() {
349
- return Math.max(0, this.maxWorkers - this.getBusyCount());
350
- }
351
- /**
352
- * Kill all workers
353
- */
354
- killAll() {
355
- for (const worker of this.workers) {
356
- worker.kill();
357
- }
358
- }
359
- /**
360
- * Get pool status
361
- */
362
- getStatus() {
363
- return {
364
- total: this.workers.length,
365
- busy: this.getBusyCount(),
366
- available: this.getAvailableCount(),
367
- };
368
- }
369
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * Tool: analyzeFile
3
- * Structured analysis of a Source File (TS/JS) using ts-morph
4
- */
5
- import { z } from 'zod';
6
- export declare const name = "analyzeFile";
7
- export declare const description = "Perform structured analysis of a TypeScript/JavaScript file to extract classes, functions, and interfaces.";
8
- export declare const permission: "read";
9
- export declare const schema: z.ZodObject<{
10
- path: z.ZodString;
11
- }, "strip", z.ZodTypeAny, {
12
- path: string;
13
- }, {
14
- path: string;
15
- }>;
16
- export declare const execute: (args: Record<string, unknown>) => Promise<unknown>;
@@ -1,43 +0,0 @@
1
- /**
2
- * Tool: analyzeFile
3
- * Structured analysis of a Source File (TS/JS) using ts-morph
4
- */
5
- import { Project, ScriptTarget } from 'ts-morph';
6
- import { z } from 'zod';
7
- import { readFile } from 'fs/promises';
8
- export const name = 'analyzeFile';
9
- export const description = 'Perform structured analysis of a TypeScript/JavaScript file to extract classes, functions, and interfaces.';
10
- export const permission = 'read';
11
- export const schema = z.object({
12
- path: z.string().describe('Path to the file to analyze')
13
- });
14
- export const execute = async (args) => {
15
- const parsed = schema.parse(args);
16
- const path = parsed.path;
17
- try {
18
- const content = await readFile(path, 'utf-8');
19
- const project = new Project({
20
- compilerOptions: { target: ScriptTarget.ESNext, allowJs: true },
21
- useInMemoryFileSystem: true
22
- });
23
- const sourceFile = project.createSourceFile(path, content);
24
- return {
25
- path,
26
- classes: sourceFile.getClasses().map(c => ({
27
- name: c.getName(),
28
- methods: c.getMethods().map(m => m.getName()),
29
- properties: c.getProperties().map(p => p.getName())
30
- })),
31
- functions: sourceFile.getFunctions().map(f => ({
32
- name: f.getName(),
33
- params: f.getParameters().map(p => p.getName())
34
- })),
35
- interfaces: sourceFile.getInterfaces().map(i => i.getName()),
36
- types: sourceFile.getTypeAliases().map(t => t.getName()),
37
- exports: sourceFile.getExportedDeclarations().keys()
38
- };
39
- }
40
- catch (error) {
41
- throw new Error(`Failed to analyze file ${path}: ${error instanceof Error ? error.message : error}`);
42
- }
43
- };
@@ -1,16 +0,0 @@
1
- /**
2
- * Tool: analyzeFile
3
- * Structured analysis of a Source File (TS/JS) using ts-morph
4
- */
5
- import { z } from 'zod';
6
- export declare const name = "analyze_file";
7
- export declare const description = "Perform structured analysis of a TypeScript/JavaScript file to extract classes, functions, and interfaces.";
8
- export declare const permission: "read";
9
- export declare const schema: z.ZodObject<{
10
- path: z.ZodString;
11
- }, "strip", z.ZodTypeAny, {
12
- path: string;
13
- }, {
14
- path: string;
15
- }>;
16
- export declare const execute: (args: Record<string, unknown>) => Promise<unknown>;
@@ -1,43 +0,0 @@
1
- /**
2
- * Tool: analyzeFile
3
- * Structured analysis of a Source File (TS/JS) using ts-morph
4
- */
5
- import { Project, ScriptTarget } from 'ts-morph';
6
- import { z } from 'zod';
7
- import { readFile } from 'fs/promises';
8
- export const name = 'analyze_file';
9
- export const description = 'Perform structured analysis of a TypeScript/JavaScript file to extract classes, functions, and interfaces.';
10
- export const permission = 'read';
11
- export const schema = z.object({
12
- path: z.string().describe('Path to the file to analyze')
13
- });
14
- export const execute = async (args) => {
15
- const parsed = schema.parse(args);
16
- const path = parsed.path;
17
- try {
18
- const content = await readFile(path, 'utf-8');
19
- const project = new Project({
20
- compilerOptions: { target: ScriptTarget.ESNext, allowJs: true },
21
- useInMemoryFileSystem: true
22
- });
23
- const sourceFile = project.createSourceFile(path, content);
24
- return {
25
- path,
26
- classes: sourceFile.getClasses().map(c => ({
27
- name: c.getName(),
28
- methods: c.getMethods().map(m => m.getName()),
29
- properties: c.getProperties().map(p => p.getName())
30
- })),
31
- functions: sourceFile.getFunctions().map(f => ({
32
- name: f.getName(),
33
- params: f.getParameters().map(p => p.getName())
34
- })),
35
- interfaces: sourceFile.getInterfaces().map(i => i.getName()),
36
- types: sourceFile.getTypeAliases().map(t => t.getName()),
37
- exports: sourceFile.getExportedDeclarations().keys()
38
- };
39
- }
40
- catch (error) {
41
- throw new Error(`Failed to analyze file ${path}: ${error instanceof Error ? error.message : error}`);
42
- }
43
- };
@@ -1,23 +0,0 @@
1
- /**
2
- * ClawBrain - Agentic Reasoning and Persistence for Autonomous Mode
3
- */
4
- import { z } from 'zod';
5
- import type { Tool } from '../registry.js';
6
- export declare const inputSchema: z.ZodObject<{
7
- action: z.ZodEnum<["set_goal", "update_status", "log_reflection", "get_summary", "prune", "link_files"]>;
8
- content: z.ZodOptional<z.ZodString>;
9
- status: z.ZodOptional<z.ZodEnum<["planning", "executing", "completed", "failed"]>>;
10
- links: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
- }, "strip", z.ZodTypeAny, {
12
- action: "log_reflection" | "get_summary" | "prune" | "set_goal" | "update_status" | "link_files";
13
- status?: "completed" | "failed" | "planning" | "executing" | undefined;
14
- content?: string | undefined;
15
- links?: string[] | undefined;
16
- }, {
17
- action: "log_reflection" | "get_summary" | "prune" | "set_goal" | "update_status" | "link_files";
18
- status?: "completed" | "failed" | "planning" | "executing" | undefined;
19
- content?: string | undefined;
20
- links?: string[] | undefined;
21
- }>;
22
- export declare const execute: (args: Record<string, unknown>, cwd?: string) => Promise<any>;
23
- export declare const tool: Tool;
@@ -1,136 +0,0 @@
1
- /**
2
- * ClawBrain - Agentic Reasoning and Persistence for Autonomous Mode
3
- */
4
- import { z } from 'zod';
5
- import { readFile, writeFile, mkdir } from 'fs/promises';
6
- import { existsSync } from 'fs';
7
- import { join } from 'path';
8
- export const inputSchema = z.object({
9
- action: z.enum(['set_goal', 'update_status', 'log_reflection', 'get_summary', 'prune', 'link_files']),
10
- content: z.string().optional().describe('Text content for the action'),
11
- status: z.enum(['planning', 'executing', 'completed', 'failed']).optional().describe('Current mission status'),
12
- links: z.array(z.string()).optional().describe('Paths or IDs to link in the graph'),
13
- });
14
- const MISSION_FILE = '.simple/workdir/mission.json';
15
- async function loadMission(cwd) {
16
- const path = join(cwd, MISSION_FILE);
17
- if (!existsSync(path)) {
18
- return { goal: 'Unknown', status: 'planning', reflections: [], lastUpdated: Date.now() };
19
- }
20
- try {
21
- return JSON.parse(await readFile(path, 'utf-8'));
22
- }
23
- catch {
24
- return { goal: 'Unknown', status: 'planning', reflections: [], lastUpdated: Date.now() };
25
- }
26
- }
27
- async function saveMission(cwd, mission) {
28
- const path = join(cwd, MISSION_FILE);
29
- await mkdir(join(cwd, '.simple/workdir'), { recursive: true });
30
- mission.lastUpdated = Date.now();
31
- await writeFile(path, JSON.stringify(mission, null, 2));
32
- }
33
- export const execute = async (args, cwd = process.cwd()) => {
34
- const { action, content, status, links } = inputSchema.parse(args);
35
- const mission = await loadMission(cwd);
36
- switch (action) {
37
- case 'set_goal':
38
- mission.goal = content || mission.goal;
39
- if (status)
40
- mission.status = status;
41
- await saveMission(cwd, mission);
42
- return { success: true, message: `Goal set to: ${mission.goal}` };
43
- case 'update_status':
44
- if (status)
45
- mission.status = status;
46
- if (content)
47
- mission.reflections.push(`[Status Update] ${content}`);
48
- await saveMission(cwd, mission);
49
- return { success: true, status: mission.status };
50
- case 'log_reflection':
51
- if (content) {
52
- mission.reflections.push(content);
53
- if (mission.reflections.length > 50)
54
- mission.reflections.shift();
55
- await saveMission(cwd, mission);
56
- // Write to reflections directory for JIT context
57
- const reflectionsDir = join(cwd, '.simple/workdir/memory/reflections');
58
- await mkdir(reflectionsDir, { recursive: true });
59
- const fileName = `reflection-${Date.now()}.md`;
60
- await writeFile(join(reflectionsDir, fileName), content);
61
- }
62
- return { success: true, added: !!content };
63
- case 'link_files':
64
- if (links && links.length > 0) {
65
- const graphDir = join(cwd, '.simple/workdir/memory/graph');
66
- await mkdir(graphDir, { recursive: true });
67
- const graphFile = join(graphDir, 'links.jsonl');
68
- const entry = JSON.stringify({ timestamp: Date.now(), links, goal: mission.goal }) + '\n';
69
- await writeFile(graphFile, entry, { flag: 'a' });
70
- }
71
- return { success: true, linked: links?.length || 0 };
72
- case 'get_summary':
73
- return {
74
- goal: mission.goal,
75
- status: mission.status,
76
- recent_reflections: mission.reflections.slice(-5),
77
- last_updated: new Date(mission.lastUpdated).toISOString()
78
- };
79
- case 'prune': {
80
- const memoryDir = join(cwd, '.simple/workdir/memory');
81
- const notesDir = join(memoryDir, 'notes');
82
- await mkdir(notesDir, { recursive: true });
83
- if (mission.reflections.length === 0) {
84
- return { success: true, message: 'Nothing to prune.' };
85
- }
86
- const archiveFile = join(notesDir, `archive-${Date.now()}.md`);
87
- let consolidated;
88
- try {
89
- const { createProvider } = await import('../providers/index.js');
90
- const provider = createProvider();
91
- const prompt = `Consolidate and summarize the following mission reflections into a concise technical brief.
92
- Keep ONLY unique technical insights, discovered paths, and finalized facts.
93
- Original Goal: ${mission.goal}\n\nReflections:\n${mission.reflections.join('\n')}`;
94
- console.log('🤖 Summarizing reflections for pruning...');
95
- const summary = await provider.generateResponse('You are a technical documentarian.', [
96
- { role: 'user', content: prompt }
97
- ]);
98
- let summaryText = summary;
99
- try {
100
- const parsed = JSON.parse(summary);
101
- summaryText = parsed.thought || parsed.message || summary;
102
- }
103
- catch { /* not JSON */ }
104
- consolidated = [
105
- `# Mission Summary Archive: ${mission.goal}`,
106
- `Status: ${mission.status}`,
107
- `Date: ${new Date().toISOString()}`,
108
- '',
109
- '## Executive Summary',
110
- summaryText
111
- ].join('\n');
112
- }
113
- catch (e) {
114
- // Fallback to basic concatenation if LLM fails
115
- consolidated = mission.reflections.map(r => `- ${r}`).join('\n');
116
- }
117
- await writeFile(archiveFile, consolidated);
118
- mission.reflections = mission.reflections.slice(-3); // Keep only very recent context
119
- await saveMission(cwd, mission);
120
- return {
121
- success: true,
122
- message: 'Memory pruned and summarized with LLM.',
123
- archivePath: archiveFile
124
- };
125
- }
126
- default:
127
- throw new Error(`Invalid action: ${action}`);
128
- }
129
- };
130
- export const tool = {
131
- name: 'clawBrain',
132
- description: 'Manage autonomous mission state and technical reasoning. Use to set goals, log reflections, and track status.',
133
- inputSchema,
134
- permission: 'write',
135
- execute: async (args) => execute(args),
136
- };
@@ -1,23 +0,0 @@
1
- /**
2
- * ClawBrain - Agentic Reasoning and Persistence for Autonomous Mode
3
- */
4
- import { z } from 'zod';
5
- import type { Tool } from '../registry.js';
6
- export declare const inputSchema: z.ZodObject<{
7
- action: z.ZodEnum<["set_goal", "update_status", "log_reflection", "get_summary", "prune", "link_files"]>;
8
- content: z.ZodOptional<z.ZodString>;
9
- status: z.ZodOptional<z.ZodEnum<["planning", "executing", "completed", "failed"]>>;
10
- links: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
- }, "strip", z.ZodTypeAny, {
12
- action: "log_reflection" | "get_summary" | "prune" | "set_goal" | "update_status" | "link_files";
13
- status?: "completed" | "failed" | "planning" | "executing" | undefined;
14
- content?: string | undefined;
15
- links?: string[] | undefined;
16
- }, {
17
- action: "log_reflection" | "get_summary" | "prune" | "set_goal" | "update_status" | "link_files";
18
- status?: "completed" | "failed" | "planning" | "executing" | undefined;
19
- content?: string | undefined;
20
- links?: string[] | undefined;
21
- }>;
22
- export declare const execute: (args: Record<string, unknown>, cwd?: string) => Promise<any>;
23
- export declare const tool: Tool;