@stan-chen/simple-cli 0.2.3 → 0.2.5

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 +73 -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 +15 -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
@@ -0,0 +1,481 @@
1
+ import { readFile, writeFile, readdir, unlink, mkdir, stat } from 'fs/promises';
2
+ import { existsSync } from 'fs';
3
+ import { join, resolve, relative, extname } from 'path';
4
+ import { exec } from 'child_process';
5
+ import { promisify } from 'util';
6
+ import { z } from 'zod';
7
+ import glob from 'fast-glob';
8
+ const execAsync = promisify(exec);
9
+ export const readFiles = {
10
+ name: 'read_files',
11
+ description: 'Read contents of one or more files',
12
+ inputSchema: z.object({ paths: z.array(z.string()) }),
13
+ execute: async (args) => {
14
+ let paths = args.paths;
15
+ if (!paths) {
16
+ if (args.path)
17
+ paths = [args.path];
18
+ else if (args.file)
19
+ paths = [args.file];
20
+ else if (args.filename)
21
+ paths = [args.filename];
22
+ }
23
+ if (!paths || !Array.isArray(paths)) {
24
+ return [{ error: "Invalid arguments: 'paths' array is required." }];
25
+ }
26
+ const results = [];
27
+ for (const p of paths) {
28
+ try {
29
+ if (existsSync(p)) {
30
+ const content = await readFile(p, 'utf-8');
31
+ results.push({ path: p, content });
32
+ }
33
+ else {
34
+ results.push({ path: p, error: `File not found: ${p}` });
35
+ }
36
+ }
37
+ catch (e) {
38
+ results.push({ path: p, error: e.message });
39
+ }
40
+ }
41
+ return results;
42
+ }
43
+ };
44
+ export const writeFiles = {
45
+ name: 'write_files',
46
+ description: 'Write or modify files. Use SEARCH/REPLACE blocks for partial edits.',
47
+ inputSchema: z.object({
48
+ files: z.array(z.object({
49
+ path: z.string(),
50
+ content: z.string().optional(),
51
+ searchReplace: z.array(z.object({
52
+ search: z.string(),
53
+ replace: z.string()
54
+ })).optional()
55
+ }))
56
+ }),
57
+ execute: async (args) => {
58
+ let files = args.files;
59
+ // Fallback: if agent passed single file attributes directly
60
+ if (!files) {
61
+ if (args.path)
62
+ files = [args];
63
+ else if (args.file)
64
+ files = [{ ...args, path: args.file }];
65
+ else if (args.filename)
66
+ files = [{ ...args, path: args.filename }];
67
+ }
68
+ else if (typeof files === 'object' && !Array.isArray(files)) {
69
+ // Handle dictionary format: { "file.txt": { content: "..." } }
70
+ files = Object.entries(files).map(([key, val]) => ({
71
+ path: key,
72
+ ...val
73
+ }));
74
+ }
75
+ if (!files || !Array.isArray(files)) {
76
+ throw new Error(`Invalid arguments for write_files: ${JSON.stringify(args)}`);
77
+ }
78
+ const results = [];
79
+ for (const f of files) {
80
+ // Fix: Map 'name' to 'path' if path is missing (common hallucination)
81
+ if (!f.path && f.name)
82
+ f.path = f.name;
83
+ try {
84
+ if (!f.path) {
85
+ results.push({ success: false, message: 'File path missing' });
86
+ continue;
87
+ }
88
+ const dir = resolve(f.path, '..');
89
+ if (!existsSync(dir)) {
90
+ await mkdir(dir, { recursive: true });
91
+ }
92
+ if (f.content !== undefined) {
93
+ await writeFile(f.path, f.content);
94
+ results.push({ path: f.path, success: true });
95
+ }
96
+ else if (f.searchReplace) {
97
+ if (!existsSync(f.path)) {
98
+ results.push({ path: f.path, success: false, message: `File not found: ${f.path}` });
99
+ continue;
100
+ }
101
+ let content = await readFile(f.path, 'utf-8');
102
+ for (const { search, replace } of f.searchReplace) {
103
+ if (!content.includes(search)) {
104
+ throw new Error(`Search pattern not found in ${f.path}: "${search}"`);
105
+ }
106
+ content = content.split(search).join(replace);
107
+ }
108
+ await writeFile(f.path, content);
109
+ results.push({ path: f.path, success: true });
110
+ }
111
+ else {
112
+ results.push({ path: f.path, success: false, message: 'No content or searchReplace provided' });
113
+ }
114
+ }
115
+ catch (e) {
116
+ results.push({ path: f.path, success: false, message: e.message });
117
+ }
118
+ }
119
+ return results;
120
+ }
121
+ };
122
+ export const createTool = {
123
+ name: 'create_tool',
124
+ description: 'Create a new tool from a script file',
125
+ inputSchema: z.object({
126
+ source_path: z.string(),
127
+ name: z.string(),
128
+ description: z.string(),
129
+ usage: z.string(),
130
+ scope: z.enum(['local', 'global']).default('local')
131
+ }),
132
+ execute: async ({ source_path, name, description, usage, scope }) => {
133
+ if (!existsSync(source_path))
134
+ return `Source file not found: ${source_path}`;
135
+ const content = await readFile(source_path, 'utf-8');
136
+ const ext = extname(source_path);
137
+ const filename = `${name}${ext}`;
138
+ let header = '';
139
+ if (ext === '.js' || ext === '.ts') {
140
+ header = `/**\n * ${name}\n * ${description}\n * Usage: ${usage}\n */\n\n`;
141
+ }
142
+ else if (ext === '.py') {
143
+ header = `"""\n${name}\n${description}\nUsage: ${usage}\n"""\n\n`;
144
+ }
145
+ const targetDir = scope === 'global'
146
+ ? join(process.env.HOME || process.cwd(), '.agent', 'tools')
147
+ : join(process.cwd(), '.agent', 'tools');
148
+ await mkdir(targetDir, { recursive: true });
149
+ const targetPath = join(targetDir, filename);
150
+ await writeFile(targetPath, header + content);
151
+ return `Tool ${name} successfully saved to ${targetPath}`;
152
+ }
153
+ };
154
+ export const scrapeUrl = {
155
+ name: 'scrape_url',
156
+ description: 'Scrape content from a URL',
157
+ inputSchema: z.object({
158
+ url: z.string().url(),
159
+ convertToMarkdown: z.boolean().default(true),
160
+ timeout: z.number().optional()
161
+ }),
162
+ execute: async ({ url, convertToMarkdown, timeout }) => {
163
+ try {
164
+ const controller = new AbortController();
165
+ const id = timeout ? setTimeout(() => controller.abort(), timeout) : undefined;
166
+ let res;
167
+ try {
168
+ res = await fetch(url, { signal: controller.signal });
169
+ }
170
+ finally {
171
+ if (id)
172
+ clearTimeout(id);
173
+ }
174
+ if (!res.ok)
175
+ throw new Error(`Failed to fetch ${url}: ${res.status} ${res.statusText}`);
176
+ const type = res.headers.get('content-type') || '';
177
+ let content = await res.text();
178
+ if (convertToMarkdown && type.includes('text/html')) {
179
+ content = content
180
+ .replace(/<script\b[^>]*>[\s\S]*?<\/script>/gmi, "")
181
+ .replace(/<style\b[^>]*>[\s\S]*?<\/style>/gmi, "")
182
+ .replace(/<pre><code[^>]*>([\s\S]*?)<\/code><\/pre>/gi, '```\n$1\n```\n')
183
+ .replace(/<h1[^>]*>(.*?)<\/h1>/gi, '# $1\n')
184
+ .replace(/<h2[^>]*>(.*?)<\/h2>/gi, '## $1\n')
185
+ .replace(/<h3[^>]*>(.*?)<\/h3>/gi, '### $1\n')
186
+ .replace(/<p[^>]*>(.*?)<\/p>/gi, '$1\n\n')
187
+ .replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)')
188
+ .replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**')
189
+ .replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*')
190
+ .replace(/<code[^>]*>(.*?)<\/code>/gi, '`$1`')
191
+ .replace(/<[^>]+>/g, '')
192
+ .replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&').replace(/&quot;/g, '"')
193
+ .trim();
194
+ }
195
+ return { url, content, contentType: type };
196
+ }
197
+ catch (e) {
198
+ return { url, error: e.message };
199
+ }
200
+ }
201
+ };
202
+ export const listFiles = {
203
+ name: 'list_files',
204
+ description: 'List files using glob patterns. Supports recursive matching.',
205
+ inputSchema: z.object({
206
+ pattern: z.string().describe('Glob pattern (e.g. **/*.ts)'),
207
+ path: z.string().default('.').describe('Base directory'),
208
+ ignore: z.array(z.string()).default(['**/node_modules/**', '**/.git/**']),
209
+ includeDirectories: z.boolean().default(false),
210
+ maxResults: z.number().optional()
211
+ }),
212
+ execute: async ({ pattern, path, ignore, includeDirectories, maxResults }) => {
213
+ const files = await glob(pattern, {
214
+ cwd: path,
215
+ ignore: ignore,
216
+ onlyFiles: !includeDirectories,
217
+ dot: true,
218
+ absolute: false
219
+ });
220
+ const truncated = maxResults && files.length > maxResults;
221
+ const resultFiles = maxResults ? files.slice(0, maxResults) : files;
222
+ return {
223
+ matches: resultFiles,
224
+ count: resultFiles.length,
225
+ truncated: !!truncated
226
+ };
227
+ }
228
+ };
229
+ export const searchFiles = {
230
+ name: 'search_files',
231
+ description: 'Search for patterns in files (grep-like).',
232
+ inputSchema: z.object({
233
+ pattern: z.string().describe('Regex pattern to search for'),
234
+ path: z.string().default('.').describe('Directory or file to search'),
235
+ glob: z.string().default('**/*').describe('Glob pattern to filter files'),
236
+ ignoreCase: z.boolean().default(false),
237
+ contextLines: z.number().default(0),
238
+ maxResults: z.number().optional(),
239
+ filesOnly: z.boolean().default(false)
240
+ }),
241
+ execute: async ({ pattern, path, glob: globPattern, ignoreCase, contextLines, maxResults, filesOnly }) => {
242
+ let files = [];
243
+ try {
244
+ const stats = await stat(path);
245
+ if (stats.isFile()) {
246
+ files = [path];
247
+ }
248
+ else {
249
+ files = await glob(globPattern, {
250
+ cwd: path,
251
+ ignore: ['**/node_modules/**', '**/.git/**'],
252
+ onlyFiles: true,
253
+ absolute: true
254
+ });
255
+ }
256
+ }
257
+ catch (e) {
258
+ return { matches: [], count: 0, error: 'Path not found' };
259
+ }
260
+ const lineRegex = new RegExp(pattern, ignoreCase ? 'gi' : 'g');
261
+ const matches = [];
262
+ const matchedFiles = new Set();
263
+ let count = 0;
264
+ let truncated = false;
265
+ for (const file of files) {
266
+ try {
267
+ const content = await readFile(file, 'utf-8');
268
+ if (content.includes('\0'))
269
+ continue;
270
+ if (filesOnly) {
271
+ lineRegex.lastIndex = 0;
272
+ if (lineRegex.test(content)) {
273
+ matchedFiles.add(relative(process.cwd(), file));
274
+ if (maxResults && matchedFiles.size >= maxResults) {
275
+ truncated = true;
276
+ break;
277
+ }
278
+ }
279
+ continue;
280
+ }
281
+ const lines = content.split('\n');
282
+ for (let i = 0; i < lines.length; i++) {
283
+ const line = lines[i];
284
+ lineRegex.lastIndex = 0;
285
+ const matchesOnLine = [...line.matchAll(lineRegex)];
286
+ for (const m of matchesOnLine) {
287
+ if (maxResults && count >= maxResults) {
288
+ truncated = true;
289
+ break;
290
+ }
291
+ const match = {
292
+ file: relative(process.cwd(), file),
293
+ line: i + 1,
294
+ text: line,
295
+ match: m[0]
296
+ };
297
+ if (contextLines > 0) {
298
+ match.contextBefore = lines.slice(Math.max(0, i - contextLines), i);
299
+ match.contextAfter = lines.slice(i + 1, i + 1 + contextLines);
300
+ }
301
+ matches.push(match);
302
+ matchedFiles.add(match.file);
303
+ count++;
304
+ }
305
+ if (truncated)
306
+ break;
307
+ }
308
+ }
309
+ catch (e) {
310
+ // Ignore read errors
311
+ }
312
+ if (truncated)
313
+ break;
314
+ }
315
+ return {
316
+ matches: matches,
317
+ count: filesOnly ? matchedFiles.size : matches.length,
318
+ files: Array.from(matchedFiles),
319
+ truncated: !!truncated
320
+ };
321
+ }
322
+ };
323
+ export const listDir = {
324
+ name: 'list_dir',
325
+ description: 'List contents of a directory',
326
+ inputSchema: z.object({ path: z.string().default('.') }),
327
+ execute: async ({ path }) => {
328
+ const items = await readdir(path, { withFileTypes: true });
329
+ return items.map(i => ({ name: i.name, isDir: i.isDirectory() }));
330
+ }
331
+ };
332
+ export const runCommand = {
333
+ name: 'run_command',
334
+ description: 'Run a shell command',
335
+ inputSchema: z.object({ command: z.string(), timeout: z.number().optional() }),
336
+ execute: async ({ command, timeout }) => {
337
+ try {
338
+ const { stdout, stderr } = await execAsync(command, { timeout });
339
+ return { stdout, stderr, exitCode: 0, timedOut: false };
340
+ }
341
+ catch (e) {
342
+ const timedOut = e.killed && e.signal === 'SIGTERM';
343
+ return {
344
+ error: e.message,
345
+ stdout: e.stdout || '',
346
+ stderr: e.stderr || '',
347
+ exitCode: e.code || 1,
348
+ timedOut
349
+ };
350
+ }
351
+ }
352
+ };
353
+ export const deleteFile = {
354
+ name: 'delete_file',
355
+ description: 'Delete a file',
356
+ inputSchema: z.object({ path: z.string() }),
357
+ execute: async (args) => {
358
+ const path = args.path || args.file || args.filename;
359
+ if (!path)
360
+ return "Error: 'path' argument required";
361
+ if (existsSync(path)) {
362
+ await unlink(path);
363
+ return `Deleted ${path}`;
364
+ }
365
+ return `File not found: ${path}`;
366
+ }
367
+ };
368
+ export const gitTool = {
369
+ name: 'git',
370
+ description: 'Run git operations',
371
+ inputSchema: z.object({
372
+ operation: z.enum(['status', 'add', 'commit', 'diff', 'log', 'branch']),
373
+ cwd: z.string().default('.'),
374
+ files: z.array(z.string()).optional(),
375
+ message: z.string().optional()
376
+ }),
377
+ execute: async ({ operation, cwd, files, message }) => {
378
+ const run = async (cmd) => {
379
+ try {
380
+ const { stdout } = await execAsync(cmd, { cwd });
381
+ return { success: true, output: stdout.trim() };
382
+ }
383
+ catch (e) {
384
+ return { success: false, error: e.message };
385
+ }
386
+ };
387
+ if (operation === 'status') {
388
+ return run('git status -s');
389
+ }
390
+ if (operation === 'add') {
391
+ if (!files || files.length === 0)
392
+ return { success: false, error: 'No files specified for add' };
393
+ return run(`git add ${files.join(' ')}`);
394
+ }
395
+ if (operation === 'commit') {
396
+ if (!message)
397
+ return { success: false, error: 'No commit message specified' };
398
+ return run(`git commit -m "${message}"`);
399
+ }
400
+ if (operation === 'diff') {
401
+ return run('git diff');
402
+ }
403
+ if (operation === 'log') {
404
+ return run('git log --oneline -n 10');
405
+ }
406
+ if (operation === 'branch') {
407
+ return run('git branch');
408
+ }
409
+ return { success: false, error: 'Unknown operation' };
410
+ }
411
+ };
412
+ export const linter = {
413
+ name: 'lint',
414
+ description: 'Lint a file',
415
+ inputSchema: z.object({ path: z.string() }),
416
+ execute: async ({ path }) => {
417
+ if (!existsSync(path))
418
+ return { passed: false, errors: [{ message: 'File not found' }] };
419
+ const ext = extname(path);
420
+ let cmd = '';
421
+ if (ext === '.js' || ext === '.ts')
422
+ cmd = `node --check "${path}"`;
423
+ else if (ext === '.py')
424
+ cmd = `python3 -m py_compile "${path}"`;
425
+ else if (ext === '.sh')
426
+ cmd = `shellcheck "${path}"`;
427
+ else
428
+ return { passed: true, language: 'unknown', errors: [], warnings: [], output: 'No linter for this file type' };
429
+ let language = 'unknown';
430
+ if (ext === '.js')
431
+ language = 'javascript';
432
+ if (ext === '.ts')
433
+ language = 'typescript';
434
+ if (ext === '.py')
435
+ language = 'python';
436
+ if (ext === '.sh')
437
+ language = 'shell';
438
+ try {
439
+ await execAsync(cmd);
440
+ return { passed: true, language, errors: [], warnings: [], output: 'Lint passed', file: path };
441
+ }
442
+ catch (e) {
443
+ const stderr = e.stderr || e.message;
444
+ const lineMatch = stderr.match(/line\s+(\d+)/i) || stderr.match(/:(\d+):/);
445
+ const line = lineMatch ? parseInt(lineMatch[1]) : 0;
446
+ return { passed: false, language, errors: [{ message: stderr, line }], warnings: [], output: stderr, file: path };
447
+ }
448
+ }
449
+ };
450
+ // Git helpers
451
+ export const getCurrentBranch = async (cwd) => {
452
+ try {
453
+ const { stdout } = await execAsync('git rev-parse --abbrev-ref HEAD', { cwd });
454
+ return stdout.trim();
455
+ }
456
+ catch {
457
+ return null;
458
+ }
459
+ };
460
+ export const getChangedFiles = async (cwd) => {
461
+ try {
462
+ const { stdout: diff } = await execAsync('git diff --name-only', { cwd });
463
+ const { stdout: untracked } = await execAsync('git ls-files --others --exclude-standard', { cwd });
464
+ const { stdout: staged } = await execAsync('git diff --cached --name-only', { cwd });
465
+ const all = [diff, untracked, staged].map(s => s.trim()).join('\n');
466
+ return [...new Set(all.split('\n').filter(Boolean))];
467
+ }
468
+ catch {
469
+ return [];
470
+ }
471
+ };
472
+ export const getTrackedFiles = async (cwd) => {
473
+ try {
474
+ const { stdout } = await execAsync('git ls-files', { cwd });
475
+ return stdout.trim().split('\n').filter(Boolean);
476
+ }
477
+ catch {
478
+ return [];
479
+ }
480
+ };
481
+ export const allBuiltins = [readFiles, writeFiles, createTool, scrapeUrl, listFiles, searchFiles, listDir, runCommand, deleteFile, gitTool, linter];
package/dist/cli.d.ts CHANGED
@@ -1,6 +1,2 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * Simple-CLI - Premium TUI agentic coding assistant
4
- * Powered by @clack/prompts.
5
- */
6
2
  import 'dotenv/config';