@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,91 +0,0 @@
1
- /**
2
- * Tool: writeFiles
3
- * Write or update files with search/replace support (Aider-style)
4
- */
5
- import { readFile, writeFile, mkdir } from 'fs/promises';
6
- import { dirname, resolve } from 'path';
7
- import { z } from 'zod';
8
- export const name = 'write_files';
9
- export const description = 'Write or modify files. ALWAYS provide an array of objects in the "files" parameter, even for a single file. Each object must have "path" and either "content" (for full write) or "searchReplace" (for edits).';
10
- export const permission = 'write';
11
- const SearchReplaceSchema = z.object({
12
- search: z.string().describe('Text to search for'),
13
- replace: z.string().describe('Text to replace with')
14
- });
15
- const FileWriteSchema = z.object({
16
- path: z.string().describe('File path to write'),
17
- content: z.string().optional().describe('Full content to write (for new files or full rewrites)'),
18
- searchReplace: z.union([
19
- z.array(SearchReplaceSchema),
20
- SearchReplaceSchema.transform(val => [val])
21
- ]).optional().describe('Array of search/replace operations for targeted edits')
22
- });
23
- export const schema = z.object({
24
- files: z.array(FileWriteSchema).describe('Array of files to write/modify')
25
- });
26
- export const execute = async (args) => {
27
- const parsed = schema.parse(args);
28
- const results = [];
29
- for (const file of parsed.files) {
30
- try {
31
- // Ensure directory exists
32
- await mkdir(dirname(file.path), { recursive: true });
33
- if (file.content !== undefined) {
34
- // Full file write
35
- await writeFile(file.path, file.content, 'utf-8');
36
- const absPath = resolve(file.path);
37
- results.push({
38
- path: file.path,
39
- success: true,
40
- message: `File written successfully to ${absPath}`
41
- });
42
- }
43
- else if (file.searchReplace && file.searchReplace.length > 0) {
44
- // Search/replace operations
45
- let content = await readFile(file.path, 'utf-8');
46
- let changesApplied = 0;
47
- const absPath = resolve(file.path);
48
- for (const { search, replace } of file.searchReplace) {
49
- if (content.includes(search)) {
50
- // Apply replacement to all occurrences
51
- const newContent = content.replace(search, replace);
52
- if (newContent !== content) {
53
- content = newContent;
54
- changesApplied++;
55
- }
56
- }
57
- }
58
- if (changesApplied > 0) {
59
- await writeFile(file.path, content, 'utf-8');
60
- results.push({
61
- path: file.path,
62
- success: true,
63
- message: `Applied ${changesApplied} search/replace operation(s) to ${absPath}`
64
- });
65
- }
66
- else {
67
- results.push({
68
- path: file.path,
69
- success: false,
70
- message: `No matching search patterns found in ${absPath}`
71
- });
72
- }
73
- }
74
- else {
75
- results.push({
76
- path: file.path,
77
- success: false,
78
- message: 'No content or searchReplace provided'
79
- });
80
- }
81
- }
82
- catch (error) {
83
- results.push({
84
- path: file.path,
85
- success: false,
86
- message: error instanceof Error ? error.message : 'Unknown error'
87
- });
88
- }
89
- }
90
- return results;
91
- };
@@ -1,15 +0,0 @@
1
- import { z } from 'zod';
2
- export declare const name = "write_to_file";
3
- export declare const description = "Write content to a single file. Overwrites if it exists.";
4
- export declare const permission: "write";
5
- export declare const schema: z.ZodObject<{
6
- path: z.ZodString;
7
- content: z.ZodString;
8
- }, "strip", z.ZodTypeAny, {
9
- path: string;
10
- content: string;
11
- }, {
12
- path: string;
13
- content: string;
14
- }>;
15
- export declare const execute: (args: Record<string, unknown>) => Promise<string>;
@@ -1,21 +0,0 @@
1
- /**
2
- * Tool: write_to_file
3
- * Simplified file write for single files
4
- */
5
- import { writeFile, mkdir } from 'fs/promises';
6
- import { dirname, resolve } from 'path';
7
- import { z } from 'zod';
8
- export const name = 'write_to_file';
9
- export const description = 'Write content to a single file. Overwrites if it exists.';
10
- export const permission = 'write';
11
- export const schema = z.object({
12
- path: z.string().describe('File path to write'),
13
- content: z.string().describe('Content to write')
14
- });
15
- export const execute = async (args) => {
16
- const { path, content } = schema.parse(args);
17
- const absPath = resolve(path);
18
- await mkdir(dirname(absPath), { recursive: true });
19
- await writeFile(absPath, content, 'utf-8');
20
- return `Successfully wrote to ${path}`;
21
- };
@@ -1,5 +0,0 @@
1
- export interface ServerOptions {
2
- port: number;
3
- host: string;
4
- }
5
- export declare function startServer(options: ServerOptions): Promise<void>;
package/dist/ui/server.js DELETED
@@ -1,74 +0,0 @@
1
- import http from 'http';
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { fileURLToPath } from 'url';
5
- import { getContextManager } from '../context.js';
6
- import { createProvider } from '../providers/index.js';
7
- const __dirname = path.dirname(fileURLToPath(import.meta.url));
8
- export async function startServer(options) {
9
- const { port, host } = options;
10
- // Initialize Simple-CLI core
11
- const ctx = getContextManager();
12
- await ctx.initialize();
13
- const provider = createProvider();
14
- const server = http.createServer(async (req, res) => {
15
- // Basic router
16
- if (req.method === 'GET' && (req.url === '/' || req.url === '/index.html')) {
17
- res.writeHead(200, { 'Content-Type': 'text/html' });
18
- res.end(fs.readFileSync(path.join(__dirname, 'index.html')));
19
- return;
20
- }
21
- if (req.method === 'POST' && req.url === '/api/chat') {
22
- let body = '';
23
- req.on('data', chunk => { body += chunk; });
24
- req.on('end', async () => {
25
- try {
26
- const { message } = JSON.parse(body);
27
- if (!message) {
28
- res.writeHead(400);
29
- res.end(JSON.stringify({ error: 'Message required' }));
30
- return;
31
- }
32
- // Add message to context
33
- ctx.addMessage('user', message);
34
- // Get system prompt and history
35
- const systemPrompt = await ctx.buildSystemPrompt();
36
- const history = ctx.getHistory();
37
- // Generate response
38
- const response = await provider.generateResponse(systemPrompt, history.map(m => ({ role: m.role, content: m.content })));
39
- // Parse response (minimalist version of cli.ts logic)
40
- const thought = response.match(/<thought>([\s\S]*?)<\/thought>/)?.[1]?.trim();
41
- const jsonMatch = response.match(/\{[\s\S]*"tool"[\s\S]*\}/);
42
- let action = { tool: 'none', message: 'No action', args: {} };
43
- if (jsonMatch) {
44
- try {
45
- action = JSON.parse(jsonMatch[0]);
46
- }
47
- catch { /* ignore */ }
48
- }
49
- const messageText = action.message || response.replace(/<thought>[\s\S]*?<\/thought>/, '').replace(/\{[\s\S]*"tool"[\s\S]*\}/, '').trim();
50
- // Update context
51
- ctx.addMessage('assistant', response);
52
- res.writeHead(200, { 'Content-Type': 'application/json' });
53
- res.end(JSON.stringify({
54
- message: messageText,
55
- thought,
56
- action
57
- }));
58
- }
59
- catch (error) {
60
- res.writeHead(500);
61
- res.end(JSON.stringify({ error: error.message }));
62
- }
63
- });
64
- return;
65
- }
66
- // 404
67
- res.writeHead(404);
68
- res.end('Not Found');
69
- });
70
- server.listen(port, host, () => {
71
- console.log(`\n🚀 Simple-CLI UI running at http://${host}:${port}`);
72
- console.log(` Press Ctrl+C to stop\n`);
73
- });
74
- }
package/dist/watcher.d.ts DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * File Watcher - Watch files for changes and AI comments
3
- * Uses chokidar for robust cross-platform watching
4
- */
5
- import { EventEmitter } from 'events';
6
- export interface WatcherOptions {
7
- root: string;
8
- ignorePatterns?: RegExp[];
9
- onFileChange?: (filePath: string, type: 'add' | 'change' | 'unlink') => void;
10
- onAIComment?: (filePath: string, comments: AIComment[]) => void;
11
- verbose?: boolean;
12
- }
13
- export interface AIComment {
14
- line: number;
15
- text: string;
16
- action: 'request' | 'question' | 'note';
17
- }
18
- export declare class FileWatcher extends EventEmitter {
19
- private options;
20
- private watcher;
21
- private watchedFiles;
22
- private ignorePatterns;
23
- private verbose;
24
- constructor(options: WatcherOptions);
25
- start(): void;
26
- stop(): void;
27
- private shouldIgnore;
28
- private handleChange;
29
- private handleUnlink;
30
- private extractAIComments;
31
- hasActionableComments(): boolean;
32
- getActionableCommentsPrompt(): string;
33
- private log;
34
- }
35
- export declare function createFileWatcher(options: WatcherOptions): FileWatcher;
package/dist/watcher.js DELETED
@@ -1,164 +0,0 @@
1
- /**
2
- * File Watcher - Watch files for changes and AI comments
3
- * Uses chokidar for robust cross-platform watching
4
- */
5
- import * as chokidar from 'chokidar';
6
- import { readFile } from 'fs/promises';
7
- import { relative } from 'path';
8
- import { EventEmitter } from 'events';
9
- // AI comment pattern (matches: # ai!, // ai?, -- ai, etc.)
10
- const AI_COMMENT_PATTERN = /(?:#|\/\/|--|;+)\s*(ai\b.*|ai\b.*|.*\bai[?!]?)\s*$/i;
11
- // Default ignore patterns
12
- const IGNORE_PATTERNS = [
13
- /node_modules/,
14
- /\.git/,
15
- /dist\//,
16
- /build\//,
17
- /\.next/,
18
- /\.nuxt/,
19
- /__pycache__/,
20
- /\.pytest_cache/,
21
- /\.venv/,
22
- /venv/,
23
- /\.env$/,
24
- /\.DS_Store/,
25
- /\.swp$/,
26
- /\.swo$/,
27
- /\.bak$/,
28
- /~$/,
29
- /\.tmp$/,
30
- /\.log$/,
31
- ];
32
- const MAX_FILE_SIZE = 1024 * 1024; // 1MB
33
- export class FileWatcher extends EventEmitter {
34
- options;
35
- watcher = null;
36
- watchedFiles = new Map();
37
- ignorePatterns;
38
- verbose;
39
- constructor(options) {
40
- super();
41
- this.options = options;
42
- this.ignorePatterns = [...IGNORE_PATTERNS, ...(options.ignorePatterns || [])];
43
- this.verbose = options.verbose || false;
44
- if (options.onFileChange)
45
- this.on('file-change', options.onFileChange);
46
- if (options.onAIComment)
47
- this.on('ai-comment', options.onAIComment);
48
- }
49
- start() {
50
- if (this.watcher)
51
- return;
52
- this.log(`Starting chokidar watcher on ${this.options.root}`);
53
- this.watcher = chokidar.watch(this.options.root, {
54
- ignored: (path) => this.shouldIgnore(path),
55
- persistent: true,
56
- ignoreInitial: false,
57
- awaitWriteFinish: {
58
- stabilityThreshold: 300,
59
- pollInterval: 100
60
- }
61
- });
62
- this.watcher
63
- .on('add', (path) => this.handleChange(path, 'add'))
64
- .on('change', (path) => this.handleChange(path, 'change'))
65
- .on('unlink', (path) => this.handleUnlink(path));
66
- }
67
- stop() {
68
- if (this.watcher) {
69
- this.watcher.close();
70
- this.watcher = null;
71
- this.log('Watcher stopped');
72
- }
73
- this.watchedFiles.clear();
74
- }
75
- shouldIgnore(path) {
76
- const relPath = relative(this.options.root, path);
77
- // Always include root
78
- if (path === this.options.root)
79
- return false;
80
- return this.ignorePatterns.some(pattern => pattern.test(relPath));
81
- }
82
- async handleChange(path, type) {
83
- const relPath = relative(this.options.root, path);
84
- // Skip large files (chokidar might have already stat-ed, but we want to be safe before reading)
85
- // Note: chokidar doesn't expose stat size in event easily without another stat call or 'add' stats arg
86
- // For simplicity, we just read.
87
- try {
88
- // ... Check size logic could go here if critical
89
- const comments = await this.extractAIComments(path);
90
- const existing = this.watchedFiles.get(path);
91
- const hasNewComments = comments.length > 0 && (!existing || JSON.stringify(comments) !== JSON.stringify(existing.aiComments));
92
- this.watchedFiles.set(path, { path, aiComments: comments });
93
- this.emit('file-change', relPath, type);
94
- if (hasNewComments) {
95
- this.emit('ai-comment', relPath, comments);
96
- }
97
- }
98
- catch (e) {
99
- this.log(`Error processing ${relPath}: ${e}`);
100
- }
101
- }
102
- handleUnlink(path) {
103
- const relPath = relative(this.options.root, path);
104
- this.watchedFiles.delete(path);
105
- this.emit('file-change', relPath, 'unlink');
106
- }
107
- async extractAIComments(filePath) {
108
- try {
109
- const content = await readFile(filePath, 'utf-8');
110
- if (content.length > MAX_FILE_SIZE)
111
- return [];
112
- const lines = content.split('\n');
113
- const comments = [];
114
- for (let i = 0; i < lines.length; i++) {
115
- const match = AI_COMMENT_PATTERN.exec(lines[i]);
116
- if (match) {
117
- const text = match[1].trim();
118
- let action = 'note';
119
- const lower = text.toLowerCase();
120
- if (lower.endsWith('!') || lower.startsWith('ai!'))
121
- action = 'request';
122
- else if (lower.endsWith('?') || lower.startsWith('ai?'))
123
- action = 'question';
124
- comments.push({ line: i + 1, text, action });
125
- }
126
- }
127
- return comments;
128
- }
129
- catch {
130
- return [];
131
- }
132
- }
133
- hasActionableComments() {
134
- for (const [_, file] of this.watchedFiles) {
135
- if (file.aiComments.some(c => c.action === 'request' || c.action === 'question')) {
136
- return true;
137
- }
138
- }
139
- return false;
140
- }
141
- getActionableCommentsPrompt() {
142
- const parts = [];
143
- for (const [path, file] of this.watchedFiles) {
144
- const actionable = file.aiComments.filter(c => c.action === 'request' || c.action === 'question');
145
- if (actionable.length > 0) {
146
- const relPath = relative(this.options.root, path);
147
- parts.push(`\n${relPath}:`);
148
- for (const c of actionable) {
149
- parts.push(` Line ${c.line} [${c.action === 'request' ? '!' : '?'}]: ${c.text}`);
150
- }
151
- }
152
- }
153
- return parts.length > 0 ? `The following AI comments were found in the codebase:${parts.join('\n')}` : '';
154
- }
155
- log(msg) {
156
- if (this.verbose)
157
- console.log(`[Watcher] ${msg}`);
158
- }
159
- }
160
- export function createFileWatcher(options) {
161
- const w = new FileWatcher(options);
162
- w.start();
163
- return w;
164
- }
File without changes