@stan-chen/simple-cli 0.2.1 → 0.2.3
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 +55 -238
- package/dist/claw/jit.d.ts +5 -0
- package/dist/claw/jit.js +138 -0
- package/dist/claw/management.d.ts +3 -0
- package/dist/claw/management.js +107 -0
- package/dist/cli.js +306 -61
- package/dist/commands/git/commit.js +2 -1
- package/dist/commands/index.js +3 -2
- package/dist/context.js +13 -3
- package/dist/lib/agent.d.ts +4 -3
- package/dist/lib/agent.js +49 -17
- package/dist/lib/git.js +6 -1
- package/dist/lib/shim.d.ts +4 -0
- package/dist/lib/shim.js +30 -0
- package/dist/lib/ui.js +25 -0
- package/dist/mcp/manager.js +5 -1
- package/dist/prompts/provider.js +1 -0
- package/dist/providers/index.d.ts +21 -5
- package/dist/providers/index.js +75 -64
- package/dist/providers/multi.d.ts +2 -1
- package/dist/registry.d.ts +5 -0
- package/dist/registry.js +86 -22
- package/dist/repoMap.js +18 -18
- package/dist/router.js +21 -11
- package/dist/skills.js +10 -10
- package/dist/swarm/worker.d.ts +2 -0
- package/dist/swarm/worker.js +85 -15
- package/dist/tools/analyze_file.d.ts +16 -0
- package/dist/tools/analyze_file.js +43 -0
- package/dist/tools/clawBrain.d.ts +23 -0
- package/dist/tools/clawBrain.js +136 -0
- package/dist/tools/claw_brain.d.ts +23 -0
- package/dist/tools/claw_brain.js +139 -0
- package/dist/tools/deleteFile.d.ts +19 -0
- package/dist/tools/deleteFile.js +36 -0
- package/dist/tools/delete_file.d.ts +19 -0
- package/dist/tools/delete_file.js +36 -0
- package/dist/tools/fileOps.d.ts +22 -0
- package/dist/tools/fileOps.js +43 -0
- package/dist/tools/file_ops.d.ts +22 -0
- package/dist/tools/file_ops.js +43 -0
- package/dist/tools/grep.d.ts +2 -2
- package/dist/tools/linter.js +85 -27
- package/dist/tools/list_dir.d.ts +29 -0
- package/dist/tools/list_dir.js +50 -0
- package/dist/tools/organizer.d.ts +1 -0
- package/dist/tools/organizer.js +65 -0
- package/dist/tools/read_files.d.ts +25 -0
- package/dist/tools/read_files.js +31 -0
- package/dist/tools/reload_tools.d.ts +11 -0
- package/dist/tools/reload_tools.js +22 -0
- package/dist/tools/run_command.d.ts +32 -0
- package/dist/tools/run_command.js +103 -0
- package/dist/tools/scheduler.d.ts +25 -0
- package/dist/tools/scheduler.js +65 -0
- package/dist/tools/writeFiles.js +1 -1
- package/dist/tools/write_files.d.ts +84 -0
- package/dist/tools/write_files.js +91 -0
- package/dist/tools/write_to_file.d.ts +15 -0
- package/dist/tools/write_to_file.js +21 -0
- package/package.json +84 -78
|
@@ -0,0 +1,136 @@
|
|
|
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
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
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;
|
|
@@ -0,0 +1,139 @@
|
|
|
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.message || summary.thought || summary.raw || '';
|
|
99
|
+
try {
|
|
100
|
+
// Try parsing raw if it looks like JSON and primary fields are empty
|
|
101
|
+
if (!summaryText && summary.raw && (summary.raw.startsWith('{') || summary.raw.startsWith('['))) {
|
|
102
|
+
const parsed = JSON.parse(summary.raw);
|
|
103
|
+
summaryText = parsed.thought || parsed.message || summary.raw;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch { /* not JSON */ }
|
|
107
|
+
consolidated = [
|
|
108
|
+
`# Mission Summary Archive: ${mission.goal}`,
|
|
109
|
+
`Status: ${mission.status}`,
|
|
110
|
+
`Date: ${new Date().toISOString()}`,
|
|
111
|
+
'',
|
|
112
|
+
'## Executive Summary',
|
|
113
|
+
summaryText
|
|
114
|
+
].join('\n');
|
|
115
|
+
}
|
|
116
|
+
catch (e) {
|
|
117
|
+
// Fallback to basic concatenation if LLM fails
|
|
118
|
+
consolidated = mission.reflections.map(r => `- ${r}`).join('\n');
|
|
119
|
+
}
|
|
120
|
+
await writeFile(archiveFile, consolidated);
|
|
121
|
+
mission.reflections = mission.reflections.slice(-3); // Keep only very recent context
|
|
122
|
+
await saveMission(cwd, mission);
|
|
123
|
+
return {
|
|
124
|
+
success: true,
|
|
125
|
+
message: 'Memory pruned and summarized with LLM.',
|
|
126
|
+
archivePath: archiveFile
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
default:
|
|
130
|
+
throw new Error(`Invalid action: ${action}`);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
export const tool = {
|
|
134
|
+
name: 'claw_brain',
|
|
135
|
+
description: 'Manage autonomous mission state and technical reasoning. Use to set goals, log reflections, and track status.',
|
|
136
|
+
inputSchema,
|
|
137
|
+
permission: 'write',
|
|
138
|
+
execute: async (args) => execute(args),
|
|
139
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: delete_file
|
|
3
|
+
* Safely delete files
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
export declare const name = "delete_file";
|
|
7
|
+
export declare const description = "Delete a file from the filesystem. Use with caution.";
|
|
8
|
+
export declare const permission: "write";
|
|
9
|
+
export declare const schema: z.ZodObject<{
|
|
10
|
+
path: z.ZodString;
|
|
11
|
+
confirm: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
path: string;
|
|
14
|
+
confirm: boolean;
|
|
15
|
+
}, {
|
|
16
|
+
path: string;
|
|
17
|
+
confirm?: boolean | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const execute: (args: Record<string, unknown>) => Promise<string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: delete_file
|
|
3
|
+
* Safely delete files
|
|
4
|
+
*/
|
|
5
|
+
import { unlink, stat } from 'fs/promises';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
export const name = 'delete_file';
|
|
10
|
+
export const description = 'Delete a file from the filesystem. Use with caution.';
|
|
11
|
+
export const permission = 'write';
|
|
12
|
+
export const schema = z.object({
|
|
13
|
+
path: z.string().describe('Path to the file to delete'),
|
|
14
|
+
confirm: z.boolean().optional().default(false).describe('Confirmation flag (must be true to execute)')
|
|
15
|
+
});
|
|
16
|
+
export const execute = async (args) => {
|
|
17
|
+
const { path, confirm } = schema.parse(args);
|
|
18
|
+
if (!confirm) {
|
|
19
|
+
throw new Error('Deletion requires explicit confirmation. Set confirm=true to proceed.');
|
|
20
|
+
}
|
|
21
|
+
const fullPath = resolve(path);
|
|
22
|
+
if (!existsSync(fullPath)) {
|
|
23
|
+
throw new Error(`File not found: ${fullPath}`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const stats = await stat(fullPath);
|
|
27
|
+
if (stats.isDirectory()) {
|
|
28
|
+
throw new Error(`Path is a directory, not a file: ${fullPath}. Use a different tool for directories.`);
|
|
29
|
+
}
|
|
30
|
+
await unlink(fullPath);
|
|
31
|
+
return `Successfully deleted ${path}`;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`Failed to delete file: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: delete_file
|
|
3
|
+
* Safely delete files
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
export declare const name = "delete_file";
|
|
7
|
+
export declare const description = "Delete a file from the filesystem. Use with caution.";
|
|
8
|
+
export declare const permission: "write";
|
|
9
|
+
export declare const schema: z.ZodObject<{
|
|
10
|
+
path: z.ZodString;
|
|
11
|
+
confirm: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
12
|
+
}, "strip", z.ZodTypeAny, {
|
|
13
|
+
path: string;
|
|
14
|
+
confirm: boolean;
|
|
15
|
+
}, {
|
|
16
|
+
path: string;
|
|
17
|
+
confirm?: boolean | undefined;
|
|
18
|
+
}>;
|
|
19
|
+
export declare const execute: (args: Record<string, unknown>) => Promise<string>;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: delete_file
|
|
3
|
+
* Safely delete files
|
|
4
|
+
*/
|
|
5
|
+
import { unlink, stat } from 'fs/promises';
|
|
6
|
+
import { resolve } from 'path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
export const name = 'delete_file';
|
|
10
|
+
export const description = 'Delete a file from the filesystem. Use with caution.';
|
|
11
|
+
export const permission = 'write';
|
|
12
|
+
export const schema = z.object({
|
|
13
|
+
path: z.string().describe('Path to the file to delete'),
|
|
14
|
+
confirm: z.boolean().optional().default(false).describe('Confirmation flag (must be true to execute)')
|
|
15
|
+
});
|
|
16
|
+
export const execute = async (args) => {
|
|
17
|
+
const { path, confirm } = schema.parse(args);
|
|
18
|
+
if (!confirm) {
|
|
19
|
+
throw new Error('Deletion requires explicit confirmation. Set confirm=true to proceed.');
|
|
20
|
+
}
|
|
21
|
+
const fullPath = resolve(path);
|
|
22
|
+
if (!existsSync(fullPath)) {
|
|
23
|
+
throw new Error(`File not found: ${fullPath}`);
|
|
24
|
+
}
|
|
25
|
+
try {
|
|
26
|
+
const stats = await stat(fullPath);
|
|
27
|
+
if (stats.isDirectory()) {
|
|
28
|
+
throw new Error(`Path is a directory, not a file: ${fullPath}. Use a different tool for directories.`);
|
|
29
|
+
}
|
|
30
|
+
await unlink(fullPath);
|
|
31
|
+
return `Successfully deleted ${path}`;
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
throw new Error(`Failed to delete file: ${error instanceof Error ? error.message : String(error)}`);
|
|
35
|
+
}
|
|
36
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: move_file
|
|
3
|
+
* Move or rename files safely
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
export declare const name = "move_file";
|
|
7
|
+
export declare const description = "Move or rename a file from source to destination. Creates destination directory if it does not exist.";
|
|
8
|
+
export declare const permission: "write";
|
|
9
|
+
export declare const schema: z.ZodObject<{
|
|
10
|
+
source: z.ZodString;
|
|
11
|
+
destination: z.ZodString;
|
|
12
|
+
overwrite: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
overwrite: boolean;
|
|
15
|
+
source: string;
|
|
16
|
+
destination: string;
|
|
17
|
+
}, {
|
|
18
|
+
source: string;
|
|
19
|
+
destination: string;
|
|
20
|
+
overwrite?: boolean | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
export declare const execute: (args: Record<string, unknown>) => Promise<string>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: move_file
|
|
3
|
+
* Move or rename files safely
|
|
4
|
+
*/
|
|
5
|
+
import { rename, stat, mkdir } from 'fs/promises';
|
|
6
|
+
import { resolve, dirname } from 'path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
export const name = 'move_file';
|
|
10
|
+
export const description = 'Move or rename a file from source to destination. Creates destination directory if it does not exist.';
|
|
11
|
+
export const permission = 'write';
|
|
12
|
+
export const schema = z.object({
|
|
13
|
+
source: z.string().describe('Source file path'),
|
|
14
|
+
destination: z.string().describe('Destination file path'),
|
|
15
|
+
overwrite: z.boolean().optional().default(false).describe('Overwrite if destination exists')
|
|
16
|
+
});
|
|
17
|
+
export const execute = async (args) => {
|
|
18
|
+
const { source, destination, overwrite } = schema.parse(args);
|
|
19
|
+
const srcPath = resolve(source);
|
|
20
|
+
const destPath = resolve(destination);
|
|
21
|
+
try {
|
|
22
|
+
// Check if source exists
|
|
23
|
+
await stat(srcPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error(`Source file not found: ${srcPath}`);
|
|
27
|
+
}
|
|
28
|
+
// Check if destination exists
|
|
29
|
+
if (existsSync(destPath) && !overwrite) {
|
|
30
|
+
throw new Error(`Destination already exists: ${destPath}. Set overwrite=true to force.`);
|
|
31
|
+
}
|
|
32
|
+
// Ensure destination directory exists
|
|
33
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
34
|
+
try {
|
|
35
|
+
await rename(srcPath, destPath);
|
|
36
|
+
return `Successfully moved ${source} to ${destination}`;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// If cross-device link error (EXDEV), we might need copy+unlink, but Node's rename usually handles this or throws.
|
|
40
|
+
// For simplicity in this tool, we report the error.
|
|
41
|
+
throw new Error(`Failed to move file: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: move_file
|
|
3
|
+
* Move or rename files safely
|
|
4
|
+
*/
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
export declare const name = "move_file";
|
|
7
|
+
export declare const description = "Move or rename a file from source to destination. Creates destination directory if it does not exist.";
|
|
8
|
+
export declare const permission: "write";
|
|
9
|
+
export declare const schema: z.ZodObject<{
|
|
10
|
+
source: z.ZodString;
|
|
11
|
+
destination: z.ZodString;
|
|
12
|
+
overwrite: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
13
|
+
}, "strip", z.ZodTypeAny, {
|
|
14
|
+
overwrite: boolean;
|
|
15
|
+
source: string;
|
|
16
|
+
destination: string;
|
|
17
|
+
}, {
|
|
18
|
+
source: string;
|
|
19
|
+
destination: string;
|
|
20
|
+
overwrite?: boolean | undefined;
|
|
21
|
+
}>;
|
|
22
|
+
export declare const execute: (args: Record<string, unknown>) => Promise<string>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool: move_file
|
|
3
|
+
* Move or rename files safely
|
|
4
|
+
*/
|
|
5
|
+
import { rename, stat, mkdir } from 'fs/promises';
|
|
6
|
+
import { resolve, dirname } from 'path';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { existsSync } from 'fs';
|
|
9
|
+
export const name = 'move_file';
|
|
10
|
+
export const description = 'Move or rename a file from source to destination. Creates destination directory if it does not exist.';
|
|
11
|
+
export const permission = 'write';
|
|
12
|
+
export const schema = z.object({
|
|
13
|
+
source: z.string().describe('Source file path'),
|
|
14
|
+
destination: z.string().describe('Destination file path'),
|
|
15
|
+
overwrite: z.boolean().optional().default(false).describe('Overwrite if destination exists')
|
|
16
|
+
});
|
|
17
|
+
export const execute = async (args) => {
|
|
18
|
+
const { source, destination, overwrite } = schema.parse(args);
|
|
19
|
+
const srcPath = resolve(source);
|
|
20
|
+
const destPath = resolve(destination);
|
|
21
|
+
try {
|
|
22
|
+
// Check if source exists
|
|
23
|
+
await stat(srcPath);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error(`Source file not found: ${srcPath}`);
|
|
27
|
+
}
|
|
28
|
+
// Check if destination exists
|
|
29
|
+
if (existsSync(destPath) && !overwrite) {
|
|
30
|
+
throw new Error(`Destination already exists: ${destPath}. Set overwrite=true to force.`);
|
|
31
|
+
}
|
|
32
|
+
// Ensure destination directory exists
|
|
33
|
+
await mkdir(dirname(destPath), { recursive: true });
|
|
34
|
+
try {
|
|
35
|
+
await rename(srcPath, destPath);
|
|
36
|
+
return `Successfully moved ${source} to ${destination}`;
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
// If cross-device link error (EXDEV), we might need copy+unlink, but Node's rename usually handles this or throws.
|
|
40
|
+
// For simplicity in this tool, we report the error.
|
|
41
|
+
throw new Error(`Failed to move file: ${error instanceof Error ? error.message : String(error)}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
package/dist/tools/grep.d.ts
CHANGED
|
@@ -20,12 +20,12 @@ export declare const inputSchema: z.ZodObject<{
|
|
|
20
20
|
contextLines: number;
|
|
21
21
|
filesOnly: boolean;
|
|
22
22
|
includeHidden: boolean;
|
|
23
|
-
glob?: string | undefined;
|
|
24
23
|
path?: string | undefined;
|
|
24
|
+
glob?: string | undefined;
|
|
25
25
|
}, {
|
|
26
26
|
pattern: string;
|
|
27
|
-
glob?: string | undefined;
|
|
28
27
|
path?: string | undefined;
|
|
28
|
+
glob?: string | undefined;
|
|
29
29
|
ignoreCase?: boolean | undefined;
|
|
30
30
|
maxResults?: number | undefined;
|
|
31
31
|
contextLines?: number | undefined;
|