@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
@@ -1,103 +0,0 @@
1
- /**
2
- * Tool: runCommand
3
- * Execute shell commands in a sandboxed environment
4
- */
5
- import { spawn } from 'child_process';
6
- import { z } from 'zod';
7
- export const name = 'run_command';
8
- export const description = 'Execute a shell command with timeout and environment restrictions';
9
- export const permission = 'execute';
10
- export const schema = z.object({
11
- command: z.string().describe('The shell command to execute'),
12
- cwd: z.string().optional().describe('Working directory for the command'),
13
- timeout: z.number().optional().describe('Timeout in milliseconds (default: 30000)'),
14
- env: z.record(z.string()).optional().describe('Additional environment variables')
15
- });
16
- // Restricted environment - remove sensitive variables
17
- const createSafeEnv = (additionalEnv) => {
18
- // Start from a minimal safe copy to avoid leaking secrets
19
- const rawEnv = { ...process.env };
20
- const sensitivePattern = /(API_KEY$|_KEY$|TOKEN|SECRET|PASSWORD|VLM_API|OPENAI_API|GEMINI_API|NPM_ACCESS_TOKEN)/i;
21
- const env = {};
22
- for (const [k, v] of Object.entries(rawEnv)) {
23
- if (!k)
24
- continue;
25
- if (sensitivePattern.test(k))
26
- continue; // skip sensitive keys
27
- env[k] = v;
28
- }
29
- // Add any additional env vars provided explicitly, but still filter them
30
- if (additionalEnv) {
31
- for (const [k, v] of Object.entries(additionalEnv)) {
32
- if (!k)
33
- continue;
34
- if (sensitivePattern.test(k))
35
- continue; // never allow sensitive keys
36
- env[k] = v;
37
- }
38
- }
39
- return env;
40
- };
41
- export const execute = async (args) => {
42
- const parsed = schema.parse(args);
43
- const timeout = parsed.timeout || 30000;
44
- const env = createSafeEnv(parsed.env);
45
- return new Promise((resolve) => {
46
- let stdout = '';
47
- let stderr = '';
48
- let timedOut = false;
49
- // Quick heuristic: detect obviously unbalanced quotes and treat as syntax error
50
- const singleQuotes = (parsed.command.match(/'/g) || []).length;
51
- const doubleQuotes = (parsed.command.match(/"/g) || []).length;
52
- if (singleQuotes % 2 !== 0 || doubleQuotes % 2 !== 0) {
53
- return resolve({ exitCode: 1, stdout: '', stderr: 'Invalid shell syntax (unbalanced quotes)', timedOut: false });
54
- }
55
- const child = spawn(parsed.command, {
56
- shell: true,
57
- cwd: parsed.cwd || process.cwd(),
58
- env,
59
- stdio: ['ignore', 'pipe', 'pipe']
60
- });
61
- const timer = setTimeout(() => {
62
- timedOut = true;
63
- child.kill('SIGTERM');
64
- setTimeout(() => child.kill('SIGKILL'), 1000);
65
- }, timeout);
66
- child.stdout?.on('data', (data) => {
67
- stdout += data.toString();
68
- // Limit output size
69
- if (stdout.length > 100000) {
70
- stdout = stdout.slice(0, 100000) + '\n... (output truncated)';
71
- child.kill('SIGTERM');
72
- }
73
- });
74
- child.stderr?.on('data', (data) => {
75
- stderr += data.toString();
76
- if (stderr.length > 50000) {
77
- stderr = stderr.slice(0, 50000) + '\n... (output truncated)';
78
- }
79
- });
80
- child.on('close', (code) => {
81
- clearTimeout(timer);
82
- // If command failed but provided no stderr, include the command for diagnostics
83
- if ((code ?? 0) !== 0 && !stderr) {
84
- stderr = `Command failed: ${parsed.command}`;
85
- }
86
- resolve({
87
- exitCode: code ?? 1,
88
- stdout: stdout.trim(),
89
- stderr: stderr.trim(),
90
- timedOut
91
- });
92
- });
93
- child.on('error', (error) => {
94
- clearTimeout(timer);
95
- resolve({
96
- exitCode: 1,
97
- stdout: '',
98
- stderr: error.message,
99
- timedOut: false
100
- });
101
- });
102
- });
103
- };
@@ -1,25 +0,0 @@
1
- /**
2
- * Tool: scheduler
3
- * Manage Ghost Tasks (scheduled executions) using crontab or schtasks
4
- */
5
- import { z } from 'zod';
6
- export declare const name = "scheduler";
7
- export declare const description = "Schedule a task to run automatically at intervals. CRITICAL for fulfilling \"Every X minutes\" or \"Every day\" intents. Tasks run in --ghost mode.";
8
- export declare const permission: "execute";
9
- export declare const schema: z.ZodObject<{
10
- intent: z.ZodString;
11
- schedule: z.ZodString;
12
- name: z.ZodOptional<z.ZodString>;
13
- targetDir: z.ZodOptional<z.ZodString>;
14
- }, "strip", z.ZodTypeAny, {
15
- intent: string;
16
- schedule: string;
17
- name?: string | undefined;
18
- targetDir?: string | undefined;
19
- }, {
20
- intent: string;
21
- schedule: string;
22
- name?: string | undefined;
23
- targetDir?: string | undefined;
24
- }>;
25
- export declare const execute: (args: Record<string, unknown>) => Promise<string>;
@@ -1,65 +0,0 @@
1
- /**
2
- * Tool: scheduler
3
- * Manage Ghost Tasks (scheduled executions) using crontab or schtasks
4
- */
5
- import { execSync } from 'child_process';
6
- import { platform } from 'os';
7
- import { z } from 'zod';
8
- import { resolve, join } from 'path';
9
- export const name = 'scheduler';
10
- export const description = 'Schedule a task to run automatically at intervals. CRITICAL for fulfilling "Every X minutes" or "Every day" intents. Tasks run in --ghost mode.';
11
- export const permission = 'execute';
12
- export const schema = z.object({
13
- intent: z.string().describe('The task description/intent to execute'),
14
- schedule: z.string().describe('Cron expression (e.g. "0 * * * *") or interval in minutes'),
15
- name: z.string().optional().describe('Unique name for the task'),
16
- targetDir: z.string().optional().describe('Working directory for the task')
17
- });
18
- export const execute = async (args) => {
19
- const { intent, schedule, name: taskName, targetDir } = schema.parse(args);
20
- const isWindows = platform() === 'win32';
21
- const cwd = resolve(targetDir || process.cwd());
22
- const id = taskName || `ghost-${Date.now()}`;
23
- // Path to simple-cli. We assume it's installed globally or use the current one.
24
- // For local dev, we use the absolute path to dist/cli.js
25
- const cliPath = resolve(join(process.cwd(), 'dist', 'cli.js'));
26
- const command = `node "${cliPath}" "${cwd}" -claw "${intent}" --ghost --yolo`;
27
- try {
28
- if (isWindows) {
29
- const interval = parseInt(schedule) || 60;
30
- const escapedCommand = command.replace(/"/g, '\\"');
31
- try {
32
- execSync(`schtasks /create /sc minute /mo ${interval} /tn "${id}" /tr "${escapedCommand}" /f`);
33
- return `Task scheduled on Windows: ${id} Every ${interval} minutes.`;
34
- }
35
- catch (e) {
36
- return `Error scheduling on Windows: ${e.message}`;
37
- }
38
- }
39
- else {
40
- try {
41
- // Determine cron expression
42
- let cronExpr = schedule;
43
- if (!schedule.includes('*')) {
44
- const mins = parseInt(schedule) || 60;
45
- cronExpr = `*/${mins} * * * *`;
46
- }
47
- const cronEntry = `${cronExpr} ${command} # ${id}`;
48
- let currentCron = '';
49
- try {
50
- currentCron = execSync('crontab -l', { encoding: 'utf-8' });
51
- }
52
- catch (e) { /* ignore empty crontab */ }
53
- const newCron = currentCron.trim() + '\n' + cronEntry + '\n';
54
- execSync(`echo "${newCron}" | crontab -`);
55
- return `Task scheduled on Linux/Mac: ${id} with schedule ${cronExpr}`;
56
- }
57
- catch (e) {
58
- return `Error scheduling on Linux/Mac: ${e.message}`;
59
- }
60
- }
61
- }
62
- catch (error) {
63
- throw new Error(`Failed to schedule task: ${error instanceof Error ? error.message : error}`);
64
- }
65
- };
@@ -1,31 +0,0 @@
1
- /**
2
- * Web Scraper Tool - Fetches and converts web content to markdown
3
- * Uses turndown for robust HTML to Markdown conversion (with regex fallback)
4
- */
5
- import { z } from 'zod';
6
- import type { Tool } from '../registry.js';
7
- export declare const inputSchema: z.ZodObject<{
8
- url: z.ZodString;
9
- convertToMarkdown: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
10
- verifySSL: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
11
- timeout: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
12
- }, "strip", z.ZodTypeAny, {
13
- url: string;
14
- timeout: number;
15
- convertToMarkdown: boolean;
16
- verifySSL: boolean;
17
- }, {
18
- url: string;
19
- timeout?: number | undefined;
20
- convertToMarkdown?: boolean | undefined;
21
- verifySSL?: boolean | undefined;
22
- }>;
23
- type ScraperInput = z.infer<typeof inputSchema>;
24
- export declare function execute(input: ScraperInput): Promise<{
25
- url: string;
26
- content: string;
27
- contentType: string;
28
- error?: string;
29
- }>;
30
- export declare const tool: Tool;
31
- export {};
@@ -1,211 +0,0 @@
1
- /**
2
- * Web Scraper Tool - Fetches and converts web content to markdown
3
- * Uses turndown for robust HTML to Markdown conversion (with regex fallback)
4
- */
5
- import { z } from 'zod';
6
- // Input schema
7
- export const inputSchema = z.object({
8
- url: z.string().url().describe('URL to scrape'),
9
- convertToMarkdown: z.boolean().optional().default(true).describe('Convert HTML to Markdown'),
10
- verifySSL: z.boolean().optional().default(true).describe('Verify SSL certificates'),
11
- timeout: z.number().optional().default(30000).describe('Timeout in milliseconds'),
12
- });
13
- // Cached turndown instance
14
- let turndownInstance = null;
15
- let turndownLoaded = false;
16
- // Get or create turndown instance (lazy load)
17
- async function getTurndown() {
18
- if (!turndownLoaded) {
19
- turndownLoaded = true;
20
- try {
21
- const mod = await import('turndown');
22
- const TurndownService = mod.default;
23
- turndownInstance = new TurndownService({
24
- headingStyle: 'atx',
25
- hr: '---',
26
- bulletListMarker: '-',
27
- codeBlockStyle: 'fenced',
28
- emDelimiter: '*',
29
- strongDelimiter: '**',
30
- linkStyle: 'inlined',
31
- });
32
- // Remove script and style elements
33
- turndownInstance.remove(['script', 'style', 'noscript', 'iframe', 'svg']);
34
- // Custom rule for code blocks with language hints
35
- turndownInstance.addRule('codeBlock', {
36
- filter: (node) => {
37
- return (node.nodeName === 'PRE' &&
38
- node.firstChild !== null &&
39
- node.firstChild.nodeName === 'CODE');
40
- },
41
- replacement: (_content, node) => {
42
- const codeNode = node.firstChild;
43
- const className = codeNode.getAttribute?.('class') || '';
44
- const langMatch = className.match(/language-(\w+)/);
45
- const lang = langMatch ? langMatch[1] : '';
46
- const code = codeNode.textContent || '';
47
- return `\n\n\`\`\`${lang}\n${code.trim()}\n\`\`\`\n\n`;
48
- },
49
- });
50
- }
51
- catch {
52
- // turndown not installed, will use fallback
53
- }
54
- }
55
- return turndownInstance;
56
- }
57
- // Fallback regex-based HTML to Markdown conversion
58
- function htmlToMarkdownFallback(html) {
59
- let md = html;
60
- // Remove script and style tags
61
- md = md.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '');
62
- md = md.replace(/<style\b[^<]*(?:(?!<\/style>)<[^<]*)*<\/style>/gi, '');
63
- // Convert headings
64
- md = md.replace(/<h1[^>]*>(.*?)<\/h1>/gi, '\n# $1\n');
65
- md = md.replace(/<h2[^>]*>(.*?)<\/h2>/gi, '\n## $1\n');
66
- md = md.replace(/<h3[^>]*>(.*?)<\/h3>/gi, '\n### $1\n');
67
- md = md.replace(/<h4[^>]*>(.*?)<\/h4>/gi, '\n#### $1\n');
68
- md = md.replace(/<h5[^>]*>(.*?)<\/h5>/gi, '\n##### $1\n');
69
- md = md.replace(/<h6[^>]*>(.*?)<\/h6>/gi, '\n###### $1\n');
70
- // Convert paragraphs
71
- md = md.replace(/<p[^>]*>(.*?)<\/p>/gis, '\n$1\n');
72
- // Convert links
73
- md = md.replace(/<a[^>]*href="([^"]*)"[^>]*>(.*?)<\/a>/gi, '[$2]($1)');
74
- // Convert images
75
- md = md.replace(/<img[^>]*src="([^"]*)"[^>]*alt="([^"]*)"[^>]*\/?>/gi, '![$2]($1)');
76
- md = md.replace(/<img[^>]*src="([^"]*)"[^>]*\/?>/gi, '![]($1)');
77
- // Convert bold
78
- md = md.replace(/<strong[^>]*>(.*?)<\/strong>/gi, '**$1**');
79
- md = md.replace(/<b[^>]*>(.*?)<\/b>/gi, '**$1**');
80
- // Convert italic
81
- md = md.replace(/<em[^>]*>(.*?)<\/em>/gi, '*$1*');
82
- md = md.replace(/<i[^>]*>(.*?)<\/i>/gi, '*$1*');
83
- // Convert inline code
84
- md = md.replace(/<code[^>]*>(.*?)<\/code>/gi, '`$1`');
85
- // Convert code blocks
86
- md = md.replace(/<pre[^>]*><code[^>]*>(.*?)<\/code><\/pre>/gis, '\n```\n$1\n```\n');
87
- md = md.replace(/<pre[^>]*>(.*?)<\/pre>/gis, '\n```\n$1\n```\n');
88
- // Convert lists
89
- md = md.replace(/<ul[^>]*>(.*?)<\/ul>/gis, (_, content) => {
90
- return content.replace(/<li[^>]*>(.*?)<\/li>/gi, '- $1\n');
91
- });
92
- md = md.replace(/<ol[^>]*>(.*?)<\/ol>/gis, (_, content) => {
93
- let i = 1;
94
- return content.replace(/<li[^>]*>(.*?)<\/li>/gi, () => `${i++}. $1\n`);
95
- });
96
- // Convert blockquotes
97
- md = md.replace(/<blockquote[^>]*>(.*?)<\/blockquote>/gis, (_, content) => {
98
- return content.split('\n').map((line) => `> ${line}`).join('\n');
99
- });
100
- // Convert line breaks
101
- md = md.replace(/<br\s*\/?>/gi, '\n');
102
- // Convert horizontal rules
103
- md = md.replace(/<hr\s*\/?>/gi, '\n---\n');
104
- // Remove remaining HTML tags
105
- md = md.replace(/<[^>]+>/g, '');
106
- // Decode HTML entities
107
- md = md.replace(/&nbsp;/g, ' ');
108
- md = md.replace(/&amp;/g, '&');
109
- md = md.replace(/&lt;/g, '<');
110
- md = md.replace(/&gt;/g, '>');
111
- md = md.replace(/&quot;/g, '"');
112
- md = md.replace(/&#39;/g, "'");
113
- // Clean up whitespace
114
- md = md.replace(/\n{3,}/g, '\n\n');
115
- md = md.trim();
116
- return md;
117
- }
118
- // Slim down HTML by removing unnecessary elements before conversion
119
- function slimDownHtml(html) {
120
- let slim = html;
121
- // Remove SVG elements
122
- slim = slim.replace(/<svg\b[^<]*(?:(?!<\/svg>)<[^<]*)*<\/svg>/gi, '');
123
- // Remove data: URLs (large embedded content)
124
- slim = slim.replace(/\s*(?:href|src)=["']data:[^"']*["']/gi, '');
125
- // Remove inline styles
126
- slim = slim.replace(/\s*style=["'][^"']*["']/gi, '');
127
- // Remove tracking pixels and tiny images
128
- slim = slim.replace(/<img[^>]*(?:width|height)=["']?[01](?:px)?["']?[^>]*>/gi, '');
129
- return slim;
130
- }
131
- // Check if content looks like HTML
132
- function looksLikeHtml(content) {
133
- const htmlPatterns = [
134
- /<!DOCTYPE\s+html/i,
135
- /<html/i,
136
- /<head/i,
137
- /<body/i,
138
- /<div/i,
139
- /<p>/i,
140
- /<a\s+href=/i,
141
- ];
142
- return htmlPatterns.some(pattern => pattern.test(content));
143
- }
144
- // Convert HTML to Markdown using turndown or fallback
145
- async function htmlToMarkdown(html) {
146
- const turndown = await getTurndown();
147
- if (turndown) {
148
- try {
149
- return turndown.turndown(html);
150
- }
151
- catch {
152
- // Fall through to regex fallback
153
- }
154
- }
155
- return htmlToMarkdownFallback(html);
156
- }
157
- // Execute scraping
158
- export async function execute(input) {
159
- const { url, convertToMarkdown, verifySSL, timeout } = inputSchema.parse(input);
160
- try {
161
- const controller = new AbortController();
162
- const timeoutId = setTimeout(() => controller.abort(), timeout);
163
- const response = await fetch(url, {
164
- signal: controller.signal,
165
- headers: {
166
- 'User-Agent': 'simplecli/0.2.1 (+https://github.com/stancsz/simple-cli)',
167
- 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
168
- },
169
- });
170
- clearTimeout(timeoutId);
171
- if (!response.ok) {
172
- return {
173
- url,
174
- content: '',
175
- contentType: '',
176
- error: `HTTP ${response.status}: ${response.statusText}`,
177
- };
178
- }
179
- const contentType = response.headers.get('content-type') || '';
180
- let content = await response.text();
181
- // Convert HTML to Markdown if requested
182
- if (convertToMarkdown && (contentType.includes('text/html') || looksLikeHtml(content))) {
183
- content = slimDownHtml(content);
184
- content = await htmlToMarkdown(content);
185
- // Clean up excessive whitespace
186
- content = content.replace(/\n{3,}/g, '\n\n').trim();
187
- }
188
- return {
189
- url,
190
- content,
191
- contentType,
192
- };
193
- }
194
- catch (error) {
195
- const errorMessage = error instanceof Error ? error.message : String(error);
196
- return {
197
- url,
198
- content: '',
199
- contentType: '',
200
- error: errorMessage.includes('abort') ? 'Request timed out' : errorMessage,
201
- };
202
- }
203
- }
204
- // Tool definition
205
- export const tool = {
206
- name: 'scrapeUrl',
207
- description: 'Fetch a URL and convert its content to markdown. Useful for reading web pages, documentation, or API responses.',
208
- inputSchema,
209
- permission: 'read',
210
- execute: async (args) => execute(args),
211
- };
@@ -1,63 +0,0 @@
1
- /**
2
- * Tool: writeFiles
3
- * Write or update files with search/replace support (Aider-style)
4
- */
5
- import { z } from 'zod';
6
- export declare const name = "writeFiles";
7
- export declare 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).";
8
- export declare const permission: "write";
9
- export declare const schema: z.ZodObject<{
10
- files: z.ZodArray<z.ZodObject<{
11
- path: z.ZodString;
12
- content: z.ZodOptional<z.ZodString>;
13
- searchReplace: z.ZodOptional<z.ZodArray<z.ZodObject<{
14
- search: z.ZodString;
15
- replace: z.ZodString;
16
- }, "strip", z.ZodTypeAny, {
17
- replace: string;
18
- search: string;
19
- }, {
20
- replace: string;
21
- search: string;
22
- }>, "many">>;
23
- }, "strip", z.ZodTypeAny, {
24
- path: string;
25
- content?: string | undefined;
26
- searchReplace?: {
27
- replace: string;
28
- search: string;
29
- }[] | undefined;
30
- }, {
31
- path: string;
32
- content?: string | undefined;
33
- searchReplace?: {
34
- replace: string;
35
- search: string;
36
- }[] | undefined;
37
- }>, "many">;
38
- }, "strip", z.ZodTypeAny, {
39
- files: {
40
- path: string;
41
- content?: string | undefined;
42
- searchReplace?: {
43
- replace: string;
44
- search: string;
45
- }[] | undefined;
46
- }[];
47
- }, {
48
- files: {
49
- path: string;
50
- content?: string | undefined;
51
- searchReplace?: {
52
- replace: string;
53
- search: string;
54
- }[] | undefined;
55
- }[];
56
- }>;
57
- interface WriteResult {
58
- path: string;
59
- success: boolean;
60
- message: string;
61
- }
62
- export declare const execute: (args: Record<string, unknown>) => Promise<WriteResult[]>;
63
- export {};
@@ -1,87 +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 = 'writeFiles';
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 FileWriteSchema = z.object({
12
- path: z.string().describe('File path to write'),
13
- content: z.string().optional().describe('Full content to write (for new files or full rewrites)'),
14
- searchReplace: z.array(z.object({
15
- search: z.string().describe('Text to search for'),
16
- replace: z.string().describe('Text to replace with')
17
- })).optional().describe('Array of search/replace operations for targeted edits')
18
- });
19
- export const schema = z.object({
20
- files: z.array(FileWriteSchema).describe('Array of files to write/modify')
21
- });
22
- export const execute = async (args) => {
23
- const parsed = schema.parse(args);
24
- const results = [];
25
- for (const file of parsed.files) {
26
- try {
27
- // Ensure directory exists
28
- await mkdir(dirname(file.path), { recursive: true });
29
- if (file.content !== undefined) {
30
- // Full file write
31
- await writeFile(file.path, file.content, 'utf-8');
32
- const absPath = resolve(file.path);
33
- results.push({
34
- path: file.path,
35
- success: true,
36
- message: `File written successfully to ${absPath}`
37
- });
38
- }
39
- else if (file.searchReplace && file.searchReplace.length > 0) {
40
- // Search/replace operations
41
- let content = await readFile(file.path, 'utf-8');
42
- let changesApplied = 0;
43
- const absPath = resolve(file.path);
44
- for (const { search, replace } of file.searchReplace) {
45
- if (content.includes(search)) {
46
- // Apply replacement to all occurrences
47
- const newContent = content.replace(search, replace);
48
- if (newContent !== content) {
49
- content = newContent;
50
- changesApplied++;
51
- }
52
- }
53
- }
54
- if (changesApplied > 0) {
55
- await writeFile(file.path, content, 'utf-8');
56
- results.push({
57
- path: file.path,
58
- success: true,
59
- message: `Applied ${changesApplied} search/replace operation(s) to ${absPath}`
60
- });
61
- }
62
- else {
63
- results.push({
64
- path: file.path,
65
- success: false,
66
- message: `No matching search patterns found in ${absPath}`
67
- });
68
- }
69
- }
70
- else {
71
- results.push({
72
- path: file.path,
73
- success: false,
74
- message: 'No content or searchReplace provided'
75
- });
76
- }
77
- }
78
- catch (error) {
79
- results.push({
80
- path: file.path,
81
- success: false,
82
- message: error instanceof Error ? error.message : 'Unknown error'
83
- });
84
- }
85
- }
86
- return results;
87
- };
@@ -1,84 +0,0 @@
1
- /**
2
- * Tool: writeFiles
3
- * Write or update files with search/replace support (Aider-style)
4
- */
5
- import { z } from 'zod';
6
- export declare const name = "write_files";
7
- export declare 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).";
8
- export declare const permission: "write";
9
- export declare const schema: z.ZodObject<{
10
- files: z.ZodArray<z.ZodObject<{
11
- path: z.ZodString;
12
- content: z.ZodOptional<z.ZodString>;
13
- searchReplace: z.ZodOptional<z.ZodUnion<[z.ZodArray<z.ZodObject<{
14
- search: z.ZodString;
15
- replace: z.ZodString;
16
- }, "strip", z.ZodTypeAny, {
17
- replace: string;
18
- search: string;
19
- }, {
20
- replace: string;
21
- search: string;
22
- }>, "many">, z.ZodEffects<z.ZodObject<{
23
- search: z.ZodString;
24
- replace: z.ZodString;
25
- }, "strip", z.ZodTypeAny, {
26
- replace: string;
27
- search: string;
28
- }, {
29
- replace: string;
30
- search: string;
31
- }>, {
32
- replace: string;
33
- search: string;
34
- }[], {
35
- replace: string;
36
- search: string;
37
- }>]>>;
38
- }, "strip", z.ZodTypeAny, {
39
- path: string;
40
- content?: string | undefined;
41
- searchReplace?: {
42
- replace: string;
43
- search: string;
44
- }[] | undefined;
45
- }, {
46
- path: string;
47
- content?: string | undefined;
48
- searchReplace?: {
49
- replace: string;
50
- search: string;
51
- } | {
52
- replace: string;
53
- search: string;
54
- }[] | undefined;
55
- }>, "many">;
56
- }, "strip", z.ZodTypeAny, {
57
- files: {
58
- path: string;
59
- content?: string | undefined;
60
- searchReplace?: {
61
- replace: string;
62
- search: string;
63
- }[] | undefined;
64
- }[];
65
- }, {
66
- files: {
67
- path: string;
68
- content?: string | undefined;
69
- searchReplace?: {
70
- replace: string;
71
- search: string;
72
- } | {
73
- replace: string;
74
- search: string;
75
- }[] | undefined;
76
- }[];
77
- }>;
78
- interface WriteResult {
79
- path: string;
80
- success: boolean;
81
- message: string;
82
- }
83
- export declare const execute: (args: Record<string, unknown>) => Promise<WriteResult[]>;
84
- export {};