@stan-chen/simple-cli 0.2.2 → 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.
- package/README.md +58 -271
- package/dist/anyllm.py +62 -0
- package/dist/builtins.d.ts +726 -0
- package/dist/builtins.js +481 -0
- package/dist/cli.d.ts +0 -4
- package/dist/cli.js +37 -279
- package/dist/engine.d.ts +33 -0
- package/dist/engine.js +138 -0
- package/dist/learnings.d.ts +15 -0
- package/dist/learnings.js +54 -0
- package/dist/llm.d.ts +18 -0
- package/dist/llm.js +66 -0
- package/dist/mcp.d.ts +132 -0
- package/dist/mcp.js +43 -0
- package/dist/skills.d.ts +5 -16
- package/dist/skills.js +91 -253
- package/dist/tui.d.ts +1 -0
- package/dist/tui.js +10 -0
- package/package.json +88 -78
- package/dist/commands/add.d.ts +0 -9
- package/dist/commands/add.js +0 -50
- package/dist/commands/git/commit.d.ts +0 -12
- package/dist/commands/git/commit.js +0 -97
- package/dist/commands/git/status.d.ts +0 -6
- package/dist/commands/git/status.js +0 -42
- package/dist/commands/index.d.ts +0 -16
- package/dist/commands/index.js +0 -376
- package/dist/commands/mcp/status.d.ts +0 -6
- package/dist/commands/mcp/status.js +0 -31
- package/dist/commands/swarm.d.ts +0 -36
- package/dist/commands/swarm.js +0 -236
- package/dist/commands.d.ts +0 -32
- package/dist/commands.js +0 -427
- package/dist/context.d.ts +0 -116
- package/dist/context.js +0 -327
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -109
- package/dist/lib/agent.d.ts +0 -98
- package/dist/lib/agent.js +0 -281
- package/dist/lib/editor.d.ts +0 -74
- package/dist/lib/editor.js +0 -441
- package/dist/lib/git.d.ts +0 -164
- package/dist/lib/git.js +0 -351
- package/dist/lib/ui.d.ts +0 -159
- package/dist/lib/ui.js +0 -252
- package/dist/mcp/client.d.ts +0 -22
- package/dist/mcp/client.js +0 -81
- package/dist/mcp/manager.d.ts +0 -186
- package/dist/mcp/manager.js +0 -446
- package/dist/prompts/provider.d.ts +0 -22
- package/dist/prompts/provider.js +0 -78
- package/dist/providers/index.d.ts +0 -15
- package/dist/providers/index.js +0 -82
- package/dist/providers/multi.d.ts +0 -11
- package/dist/providers/multi.js +0 -28
- package/dist/registry.d.ts +0 -24
- package/dist/registry.js +0 -379
- package/dist/repoMap.d.ts +0 -5
- package/dist/repoMap.js +0 -79
- package/dist/router.d.ts +0 -41
- package/dist/router.js +0 -108
- package/dist/swarm/coordinator.d.ts +0 -86
- package/dist/swarm/coordinator.js +0 -257
- package/dist/swarm/index.d.ts +0 -28
- package/dist/swarm/index.js +0 -29
- package/dist/swarm/task.d.ts +0 -104
- package/dist/swarm/task.js +0 -221
- package/dist/swarm/types.d.ts +0 -132
- package/dist/swarm/types.js +0 -37
- package/dist/swarm/worker.d.ts +0 -107
- package/dist/swarm/worker.js +0 -299
- package/dist/tools/analyzeFile.d.ts +0 -16
- package/dist/tools/analyzeFile.js +0 -43
- package/dist/tools/git.d.ts +0 -40
- package/dist/tools/git.js +0 -236
- package/dist/tools/glob.d.ts +0 -34
- package/dist/tools/glob.js +0 -165
- package/dist/tools/grep.d.ts +0 -53
- package/dist/tools/grep.js +0 -296
- package/dist/tools/linter.d.ts +0 -35
- package/dist/tools/linter.js +0 -349
- package/dist/tools/listDir.d.ts +0 -29
- package/dist/tools/listDir.js +0 -50
- package/dist/tools/memory.d.ts +0 -34
- package/dist/tools/memory.js +0 -215
- package/dist/tools/readFiles.d.ts +0 -25
- package/dist/tools/readFiles.js +0 -31
- package/dist/tools/reloadTools.d.ts +0 -11
- package/dist/tools/reloadTools.js +0 -22
- package/dist/tools/runCommand.d.ts +0 -32
- package/dist/tools/runCommand.js +0 -79
- package/dist/tools/scraper.d.ts +0 -31
- package/dist/tools/scraper.js +0 -211
- package/dist/tools/writeFiles.d.ts +0 -63
- package/dist/tools/writeFiles.js +0 -87
- package/dist/ui/server.d.ts +0 -5
- package/dist/ui/server.js +0 -74
- package/dist/watcher.d.ts +0 -35
- package/dist/watcher.js +0 -164
- /package/{docs/assets → assets}/logo.jpeg +0 -0
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
|