kode-sdk 2.7.0

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 (169) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +74 -0
  3. package/dist/core/agent/breakpoint-manager.d.ts +16 -0
  4. package/dist/core/agent/breakpoint-manager.js +36 -0
  5. package/dist/core/agent/message-queue.d.ts +26 -0
  6. package/dist/core/agent/message-queue.js +47 -0
  7. package/dist/core/agent/permission-manager.d.ts +9 -0
  8. package/dist/core/agent/permission-manager.js +32 -0
  9. package/dist/core/agent/todo-manager.d.ts +26 -0
  10. package/dist/core/agent/todo-manager.js +91 -0
  11. package/dist/core/agent/tool-runner.d.ts +9 -0
  12. package/dist/core/agent/tool-runner.js +45 -0
  13. package/dist/core/agent.d.ts +271 -0
  14. package/dist/core/agent.js +2334 -0
  15. package/dist/core/checkpointer.d.ts +96 -0
  16. package/dist/core/checkpointer.js +57 -0
  17. package/dist/core/checkpointers/file.d.ts +20 -0
  18. package/dist/core/checkpointers/file.js +153 -0
  19. package/dist/core/checkpointers/index.d.ts +3 -0
  20. package/dist/core/checkpointers/index.js +9 -0
  21. package/dist/core/checkpointers/redis.d.ts +35 -0
  22. package/dist/core/checkpointers/redis.js +113 -0
  23. package/dist/core/compression/ai-strategy.d.ts +53 -0
  24. package/dist/core/compression/ai-strategy.js +298 -0
  25. package/dist/core/compression/index.d.ts +12 -0
  26. package/dist/core/compression/index.js +27 -0
  27. package/dist/core/compression/prompts.d.ts +35 -0
  28. package/dist/core/compression/prompts.js +114 -0
  29. package/dist/core/compression/simple-strategy.d.ts +44 -0
  30. package/dist/core/compression/simple-strategy.js +240 -0
  31. package/dist/core/compression/token-estimator.d.ts +42 -0
  32. package/dist/core/compression/token-estimator.js +121 -0
  33. package/dist/core/compression/types.d.ts +140 -0
  34. package/dist/core/compression/types.js +9 -0
  35. package/dist/core/config.d.ts +10 -0
  36. package/dist/core/config.js +2 -0
  37. package/dist/core/context-manager.d.ts +115 -0
  38. package/dist/core/context-manager.js +107 -0
  39. package/dist/core/errors.d.ts +6 -0
  40. package/dist/core/errors.js +17 -0
  41. package/dist/core/events.d.ts +49 -0
  42. package/dist/core/events.js +312 -0
  43. package/dist/core/file-pool.d.ts +43 -0
  44. package/dist/core/file-pool.js +120 -0
  45. package/dist/core/hooks.d.ts +23 -0
  46. package/dist/core/hooks.js +71 -0
  47. package/dist/core/permission-modes.d.ts +31 -0
  48. package/dist/core/permission-modes.js +61 -0
  49. package/dist/core/pool.d.ts +31 -0
  50. package/dist/core/pool.js +87 -0
  51. package/dist/core/room.d.ts +15 -0
  52. package/dist/core/room.js +57 -0
  53. package/dist/core/scheduler.d.ts +33 -0
  54. package/dist/core/scheduler.js +58 -0
  55. package/dist/core/template.d.ts +69 -0
  56. package/dist/core/template.js +35 -0
  57. package/dist/core/time-bridge.d.ts +18 -0
  58. package/dist/core/time-bridge.js +100 -0
  59. package/dist/core/todo.d.ts +34 -0
  60. package/dist/core/todo.js +89 -0
  61. package/dist/core/types.d.ts +380 -0
  62. package/dist/core/types.js +3 -0
  63. package/dist/index.d.ts +51 -0
  64. package/dist/index.js +147 -0
  65. package/dist/infra/provider.d.ts +144 -0
  66. package/dist/infra/provider.js +294 -0
  67. package/dist/infra/sandbox-factory.d.ts +10 -0
  68. package/dist/infra/sandbox-factory.js +21 -0
  69. package/dist/infra/sandbox.d.ts +87 -0
  70. package/dist/infra/sandbox.js +255 -0
  71. package/dist/infra/store.d.ts +154 -0
  72. package/dist/infra/store.js +584 -0
  73. package/dist/skills/index.d.ts +12 -0
  74. package/dist/skills/index.js +36 -0
  75. package/dist/skills/injector.d.ts +29 -0
  76. package/dist/skills/injector.js +96 -0
  77. package/dist/skills/loader.d.ts +59 -0
  78. package/dist/skills/loader.js +215 -0
  79. package/dist/skills/manager.d.ts +85 -0
  80. package/dist/skills/manager.js +221 -0
  81. package/dist/skills/parser.d.ts +40 -0
  82. package/dist/skills/parser.js +107 -0
  83. package/dist/skills/types.d.ts +107 -0
  84. package/dist/skills/types.js +7 -0
  85. package/dist/skills/validator.d.ts +30 -0
  86. package/dist/skills/validator.js +121 -0
  87. package/dist/store.d.ts +1 -0
  88. package/dist/store.js +5 -0
  89. package/dist/tools/bash_kill/index.d.ts +1 -0
  90. package/dist/tools/bash_kill/index.js +35 -0
  91. package/dist/tools/bash_kill/prompt.d.ts +2 -0
  92. package/dist/tools/bash_kill/prompt.js +14 -0
  93. package/dist/tools/bash_logs/index.d.ts +1 -0
  94. package/dist/tools/bash_logs/index.js +40 -0
  95. package/dist/tools/bash_logs/prompt.d.ts +2 -0
  96. package/dist/tools/bash_logs/prompt.js +14 -0
  97. package/dist/tools/bash_run/index.d.ts +16 -0
  98. package/dist/tools/bash_run/index.js +61 -0
  99. package/dist/tools/bash_run/prompt.d.ts +2 -0
  100. package/dist/tools/bash_run/prompt.js +18 -0
  101. package/dist/tools/builtin.d.ts +9 -0
  102. package/dist/tools/builtin.js +27 -0
  103. package/dist/tools/define.d.ts +101 -0
  104. package/dist/tools/define.js +214 -0
  105. package/dist/tools/fs_edit/index.d.ts +1 -0
  106. package/dist/tools/fs_edit/index.js +62 -0
  107. package/dist/tools/fs_edit/prompt.d.ts +2 -0
  108. package/dist/tools/fs_edit/prompt.js +15 -0
  109. package/dist/tools/fs_glob/index.d.ts +1 -0
  110. package/dist/tools/fs_glob/index.js +60 -0
  111. package/dist/tools/fs_glob/prompt.d.ts +2 -0
  112. package/dist/tools/fs_glob/prompt.js +18 -0
  113. package/dist/tools/fs_grep/index.d.ts +1 -0
  114. package/dist/tools/fs_grep/index.js +66 -0
  115. package/dist/tools/fs_grep/prompt.d.ts +2 -0
  116. package/dist/tools/fs_grep/prompt.js +16 -0
  117. package/dist/tools/fs_multi_edit/index.d.ts +1 -0
  118. package/dist/tools/fs_multi_edit/index.js +106 -0
  119. package/dist/tools/fs_multi_edit/prompt.d.ts +2 -0
  120. package/dist/tools/fs_multi_edit/prompt.js +16 -0
  121. package/dist/tools/fs_read/index.d.ts +1 -0
  122. package/dist/tools/fs_read/index.js +40 -0
  123. package/dist/tools/fs_read/prompt.d.ts +2 -0
  124. package/dist/tools/fs_read/prompt.js +16 -0
  125. package/dist/tools/fs_rm/index.d.ts +1 -0
  126. package/dist/tools/fs_rm/index.js +41 -0
  127. package/dist/tools/fs_rm/prompt.d.ts +2 -0
  128. package/dist/tools/fs_rm/prompt.js +14 -0
  129. package/dist/tools/fs_write/index.d.ts +1 -0
  130. package/dist/tools/fs_write/index.js +40 -0
  131. package/dist/tools/fs_write/prompt.d.ts +2 -0
  132. package/dist/tools/fs_write/prompt.js +15 -0
  133. package/dist/tools/index.d.ts +9 -0
  134. package/dist/tools/index.js +56 -0
  135. package/dist/tools/mcp.d.ts +73 -0
  136. package/dist/tools/mcp.js +198 -0
  137. package/dist/tools/registry.d.ts +29 -0
  138. package/dist/tools/registry.js +26 -0
  139. package/dist/tools/skill_activate/index.d.ts +5 -0
  140. package/dist/tools/skill_activate/index.js +63 -0
  141. package/dist/tools/skill_list/index.d.ts +5 -0
  142. package/dist/tools/skill_list/index.js +48 -0
  143. package/dist/tools/skill_resource/index.d.ts +5 -0
  144. package/dist/tools/skill_resource/index.js +82 -0
  145. package/dist/tools/task_run/index.d.ts +7 -0
  146. package/dist/tools/task_run/index.js +60 -0
  147. package/dist/tools/task_run/prompt.d.ts +5 -0
  148. package/dist/tools/task_run/prompt.js +29 -0
  149. package/dist/tools/todo_read/index.d.ts +1 -0
  150. package/dist/tools/todo_read/index.js +29 -0
  151. package/dist/tools/todo_read/prompt.d.ts +2 -0
  152. package/dist/tools/todo_read/prompt.js +18 -0
  153. package/dist/tools/todo_write/index.d.ts +1 -0
  154. package/dist/tools/todo_write/index.js +42 -0
  155. package/dist/tools/todo_write/prompt.d.ts +2 -0
  156. package/dist/tools/todo_write/prompt.js +23 -0
  157. package/dist/tools/tool.d.ts +43 -0
  158. package/dist/tools/tool.js +104 -0
  159. package/dist/tools/toolkit.d.ts +69 -0
  160. package/dist/tools/toolkit.js +98 -0
  161. package/dist/tools/type-inference.d.ts +127 -0
  162. package/dist/tools/type-inference.js +207 -0
  163. package/dist/utils/agent-id.d.ts +1 -0
  164. package/dist/utils/agent-id.js +28 -0
  165. package/dist/utils/session-id.d.ts +21 -0
  166. package/dist/utils/session-id.js +64 -0
  167. package/dist/utils/unicode.d.ts +17 -0
  168. package/dist/utils/unicode.js +62 -0
  169. package/package.json +117 -0
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.builtin = void 0;
4
+ const fs_read_1 = require("./fs_read");
5
+ const fs_write_1 = require("./fs_write");
6
+ const fs_edit_1 = require("./fs_edit");
7
+ const fs_glob_1 = require("./fs_glob");
8
+ const fs_grep_1 = require("./fs_grep");
9
+ const fs_multi_edit_1 = require("./fs_multi_edit");
10
+ const fs_rm_1 = require("./fs_rm");
11
+ const bash_run_1 = require("./bash_run");
12
+ const bash_logs_1 = require("./bash_logs");
13
+ const bash_kill_1 = require("./bash_kill");
14
+ const todo_read_1 = require("./todo_read");
15
+ const todo_write_1 = require("./todo_write");
16
+ const task_run_1 = require("./task_run");
17
+ exports.builtin = {
18
+ fs: () => [fs_read_1.FsRead, fs_write_1.FsWrite, fs_edit_1.FsEdit, fs_glob_1.FsGlob, fs_grep_1.FsGrep, fs_multi_edit_1.FsMultiEdit, fs_rm_1.FsRm],
19
+ bash: () => [bash_run_1.BashRun, bash_logs_1.BashLogs, bash_kill_1.BashKill],
20
+ todo: () => [todo_read_1.TodoRead, todo_write_1.TodoWrite],
21
+ task: (templates) => {
22
+ if (!templates || templates.length === 0) {
23
+ return null;
24
+ }
25
+ return (0, task_run_1.createTaskRunTool)(templates);
26
+ },
27
+ };
@@ -0,0 +1,101 @@
1
+ /**
2
+ * 简化的工具定义 API - 提供更好的开发体验
3
+ *
4
+ * 设计目标:
5
+ * 1. 自动从 TypeScript 类型生成 input_schema
6
+ * 2. 简化 metadata 为 readonly/noEffect 布尔值
7
+ * 3. 支持工具内发射自定义事件
8
+ */
9
+ import { ToolContext } from '../core/types';
10
+ import { ToolInstance } from './registry';
11
+ export interface ToolAttributes {
12
+ /** 工具是否为只读(不修改任何状态) */
13
+ readonly?: boolean;
14
+ /** 工具是否无副作用(可安全重试) */
15
+ noEffect?: boolean;
16
+ }
17
+ export interface ParamDef {
18
+ type: 'string' | 'number' | 'boolean' | 'object' | 'array';
19
+ description?: string;
20
+ required?: boolean;
21
+ default?: any;
22
+ enum?: any[];
23
+ items?: ParamDef;
24
+ properties?: Record<string, ParamDef>;
25
+ }
26
+ export interface EnhancedToolContext extends ToolContext {
27
+ /** 发射自定义事件(会自动添加到 monitor 通道) */
28
+ emit(eventType: string, data?: any): void;
29
+ }
30
+ export interface SimpleToolDef<TArgs = any, TResult = any> {
31
+ /** 工具名称 */
32
+ name: string;
33
+ /** 工具描述 */
34
+ description: string;
35
+ /** 参数定义(可选,如果提供则自动生成 schema) */
36
+ params?: Record<string, ParamDef>;
37
+ /** 或者直接提供 JSON Schema(兼容老方式) */
38
+ input_schema?: any;
39
+ /** 工具属性 */
40
+ attributes?: ToolAttributes;
41
+ /** Prompt 说明书 */
42
+ prompt?: string;
43
+ /** 执行函数 */
44
+ exec(args: TArgs, ctx: EnhancedToolContext): Promise<TResult> | TResult;
45
+ }
46
+ /**
47
+ * 定义工具(简化版)
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * const greet = defineTool({
52
+ * name: 'greet',
53
+ * description: 'Greet a person',
54
+ * params: {
55
+ * name: { type: 'string', description: 'Person name' },
56
+ * formal: { type: 'boolean', description: 'Use formal greeting', required: false }
57
+ * },
58
+ * attributes: { readonly: true, noEffect: true },
59
+ * async exec(args, ctx) {
60
+ * const greeting = args.formal ? `Good day, ${args.name}` : `Hi ${args.name}!`;
61
+ *
62
+ * // 自定义事件
63
+ * ctx.emit('greeting_sent', { name: args.name, greeting });
64
+ *
65
+ * return { greeting };
66
+ * }
67
+ * });
68
+ * ```
69
+ */
70
+ export declare function defineTool<TArgs = any, TResult = any>(def: SimpleToolDef<TArgs, TResult>, options?: {
71
+ autoRegister?: boolean;
72
+ }): ToolInstance;
73
+ /**
74
+ * 批量定义工具
75
+ */
76
+ export declare function defineTools(defs: SimpleToolDef[]): ToolInstance[];
77
+ /**
78
+ * 工具装饰器(实验性 - 需要 experimentalDecorators)
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * class MyTools {
83
+ * @tool({
84
+ * description: 'Calculate sum',
85
+ * params: {
86
+ * a: { type: 'number' },
87
+ * b: { type: 'number' }
88
+ * },
89
+ * attributes: { readonly: true, noEffect: true }
90
+ * })
91
+ * async sum(args: { a: number; b: number }, ctx: EnhancedToolContext) {
92
+ * return args.a + args.b;
93
+ * }
94
+ * }
95
+ * ```
96
+ */
97
+ export declare function tool(config: Omit<SimpleToolDef, 'name' | 'exec'>): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
98
+ /**
99
+ * 从带装饰器的类提取所有工具
100
+ */
101
+ export declare function extractTools(instance: any): ToolInstance[];
@@ -0,0 +1,214 @@
1
+ "use strict";
2
+ /**
3
+ * 简化的工具定义 API - 提供更好的开发体验
4
+ *
5
+ * 设计目标:
6
+ * 1. 自动从 TypeScript 类型生成 input_schema
7
+ * 2. 简化 metadata 为 readonly/noEffect 布尔值
8
+ * 3. 支持工具内发射自定义事件
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.defineTool = defineTool;
12
+ exports.defineTools = defineTools;
13
+ exports.tool = tool;
14
+ exports.extractTools = extractTools;
15
+ const registry_1 = require("./registry");
16
+ /**
17
+ * 从参数定义自动生成 JSON Schema
18
+ */
19
+ function generateSchema(params) {
20
+ if (!params) {
21
+ return { type: 'object', properties: {} };
22
+ }
23
+ const properties = {};
24
+ const required = [];
25
+ for (const [key, def] of Object.entries(params)) {
26
+ const prop = { type: def.type };
27
+ if (def.description)
28
+ prop.description = def.description;
29
+ if (def.enum)
30
+ prop.enum = def.enum;
31
+ if (def.default !== undefined)
32
+ prop.default = def.default;
33
+ if (def.type === 'array' && def.items) {
34
+ prop.items = generateSchemaProp(def.items);
35
+ }
36
+ if (def.type === 'object' && def.properties) {
37
+ const nested = generateSchema(def.properties);
38
+ prop.properties = nested.properties;
39
+ if (nested.required?.length > 0) {
40
+ prop.required = nested.required;
41
+ }
42
+ }
43
+ properties[key] = prop;
44
+ if (def.required !== false) { // default required
45
+ required.push(key);
46
+ }
47
+ }
48
+ return {
49
+ type: 'object',
50
+ properties,
51
+ ...(required.length > 0 ? { required } : {}),
52
+ };
53
+ }
54
+ function generateSchemaProp(def) {
55
+ const prop = { type: def.type };
56
+ if (def.description)
57
+ prop.description = def.description;
58
+ if (def.enum)
59
+ prop.enum = def.enum;
60
+ if (def.type === 'array' && def.items) {
61
+ prop.items = generateSchemaProp(def.items);
62
+ }
63
+ if (def.type === 'object' && def.properties) {
64
+ const nested = generateSchema(def.properties);
65
+ prop.properties = nested.properties;
66
+ if (nested.required?.length > 0) {
67
+ prop.required = nested.required;
68
+ }
69
+ }
70
+ return prop;
71
+ }
72
+ /**
73
+ * 定义工具(简化版)
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * const greet = defineTool({
78
+ * name: 'greet',
79
+ * description: 'Greet a person',
80
+ * params: {
81
+ * name: { type: 'string', description: 'Person name' },
82
+ * formal: { type: 'boolean', description: 'Use formal greeting', required: false }
83
+ * },
84
+ * attributes: { readonly: true, noEffect: true },
85
+ * async exec(args, ctx) {
86
+ * const greeting = args.formal ? `Good day, ${args.name}` : `Hi ${args.name}!`;
87
+ *
88
+ * // 自定义事件
89
+ * ctx.emit('greeting_sent', { name: args.name, greeting });
90
+ *
91
+ * return { greeting };
92
+ * }
93
+ * });
94
+ * ```
95
+ */
96
+ function defineTool(def, options) {
97
+ // 自动生成 schema 或使用提供的
98
+ const input_schema = def.input_schema || generateSchema(def.params);
99
+ const toolInstance = {
100
+ name: def.name,
101
+ description: def.description,
102
+ input_schema,
103
+ prompt: def.prompt,
104
+ async exec(args, ctx) {
105
+ // 增强上下文,添加 emit 方法
106
+ const enhancedCtx = {
107
+ ...ctx,
108
+ emit(eventType, data) {
109
+ // 发射自定义事件到 monitor 通道
110
+ ctx.agent?.events?.emitMonitor({
111
+ type: 'tool_custom_event',
112
+ toolName: def.name,
113
+ eventType,
114
+ data,
115
+ timestamp: Date.now(),
116
+ });
117
+ },
118
+ };
119
+ return await def.exec(args, enhancedCtx);
120
+ },
121
+ toDescriptor() {
122
+ const metadata = {
123
+ tuned: false,
124
+ };
125
+ // 转换简化的 attributes 为内部 metadata
126
+ if (def.attributes?.readonly) {
127
+ metadata.access = 'read';
128
+ metadata.mutates = false;
129
+ }
130
+ else {
131
+ metadata.access = 'write';
132
+ metadata.mutates = true;
133
+ }
134
+ if (def.attributes?.noEffect !== undefined) {
135
+ metadata.safe = def.attributes.noEffect;
136
+ }
137
+ if (def.prompt) {
138
+ metadata.prompt = def.prompt;
139
+ }
140
+ return {
141
+ source: 'registered',
142
+ name: def.name,
143
+ registryId: def.name,
144
+ metadata,
145
+ };
146
+ },
147
+ };
148
+ // 自动注册到全局 registry (支持 Resume)
149
+ if (options?.autoRegister !== false) {
150
+ registry_1.globalToolRegistry.register(def.name, (_config) => {
151
+ // 工厂函数:根据 config 重建工具实例
152
+ // 注意:使用 autoRegister: false 避免重复注册
153
+ return defineTool(def, { autoRegister: false });
154
+ });
155
+ }
156
+ return toolInstance;
157
+ }
158
+ /**
159
+ * 批量定义工具
160
+ */
161
+ function defineTools(defs) {
162
+ return defs.map((def) => defineTool(def));
163
+ }
164
+ /**
165
+ * 工具装饰器(实验性 - 需要 experimentalDecorators)
166
+ *
167
+ * @example
168
+ * ```ts
169
+ * class MyTools {
170
+ * @tool({
171
+ * description: 'Calculate sum',
172
+ * params: {
173
+ * a: { type: 'number' },
174
+ * b: { type: 'number' }
175
+ * },
176
+ * attributes: { readonly: true, noEffect: true }
177
+ * })
178
+ * async sum(args: { a: number; b: number }, ctx: EnhancedToolContext) {
179
+ * return args.a + args.b;
180
+ * }
181
+ * }
182
+ * ```
183
+ */
184
+ function tool(config) {
185
+ return function (target, propertyKey, descriptor) {
186
+ const originalMethod = descriptor.value;
187
+ // 存储工具配置到类的元数据
188
+ if (!target.constructor._toolConfigs) {
189
+ target.constructor._toolConfigs = new Map();
190
+ }
191
+ target.constructor._toolConfigs.set(propertyKey, {
192
+ ...config,
193
+ name: propertyKey,
194
+ exec: originalMethod,
195
+ });
196
+ };
197
+ }
198
+ /**
199
+ * 从带装饰器的类提取所有工具
200
+ */
201
+ function extractTools(instance) {
202
+ const configs = instance.constructor._toolConfigs;
203
+ if (!configs)
204
+ return [];
205
+ const tools = [];
206
+ for (const [_methodName, config] of configs) {
207
+ tools.push(defineTool({
208
+ ...config,
209
+ exec: config.exec.bind(instance),
210
+ }, { autoRegister: true } // 装饰器定义的工具也自动注册
211
+ ));
212
+ }
213
+ return tools;
214
+ }
@@ -0,0 +1 @@
1
+ export declare const FsEdit: import("..").ToolInstance;
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FsEdit = void 0;
4
+ const tool_1 = require("../tool");
5
+ const zod_1 = require("zod");
6
+ const type_inference_1 = require("../type-inference");
7
+ const prompt_1 = require("./prompt");
8
+ exports.FsEdit = (0, tool_1.tool)({
9
+ name: 'fs_edit',
10
+ description: prompt_1.DESCRIPTION,
11
+ parameters: zod_1.z.object({
12
+ path: type_inference_1.patterns.filePath('Path to file within the sandbox'),
13
+ old_string: zod_1.z.string().describe('String to replace'),
14
+ new_string: zod_1.z.string().describe('Replacement string'),
15
+ replace_all: zod_1.z.boolean().optional().describe('Replace all occurrences (default: false)'),
16
+ }),
17
+ async execute(args, ctx) {
18
+ const { path, old_string, new_string, replace_all = false } = args;
19
+ const content = await ctx.sandbox.fs.read(path);
20
+ if (replace_all) {
21
+ const occurrences = content.split(old_string).length - 1;
22
+ if (occurrences === 0) {
23
+ return { ok: false, error: 'old_string not found in file' };
24
+ }
25
+ const updated = content.split(old_string).join(new_string);
26
+ await ctx.sandbox.fs.write(path, updated);
27
+ await ctx.services?.filePool?.recordEdit(path);
28
+ return {
29
+ ok: true,
30
+ path,
31
+ replacements: occurrences,
32
+ lines: updated.split('\n').length,
33
+ };
34
+ }
35
+ else {
36
+ const occurrences = content.split(old_string).length - 1;
37
+ if (occurrences === 0) {
38
+ return { ok: false, error: 'old_string not found in file' };
39
+ }
40
+ if (occurrences > 1) {
41
+ return {
42
+ ok: false,
43
+ error: `old_string appears ${occurrences} times; set replace_all=true or provide more specific text`,
44
+ };
45
+ }
46
+ const updated = content.replace(old_string, new_string);
47
+ await ctx.sandbox.fs.write(path, updated);
48
+ await ctx.services?.filePool?.recordEdit(path);
49
+ return {
50
+ ok: true,
51
+ path,
52
+ replacements: 1,
53
+ lines: updated.split('\n').length,
54
+ };
55
+ }
56
+ },
57
+ metadata: {
58
+ readonly: false,
59
+ version: '1.0',
60
+ },
61
+ });
62
+ exports.FsEdit.prompt = prompt_1.PROMPT;
@@ -0,0 +1,2 @@
1
+ export declare const DESCRIPTION = "Edit a file by replacing old_string with new_string";
2
+ export declare const PROMPT = "Use this tool for precise in-place edits.\n\nGuidelines:\n- Provide a unique \"old_string\" snippet to replace. If multiple matches exist, set \"replace_all\" to true.\n- Combine with fs_read to confirm the current file state before editing.\n- The tool integrates with FilePool to ensure the file has not changed externally.\n- If old_string is not unique, the tool will reject the operation unless replace_all is true.\n\nSafety/Limitations:\n- Single replacements require exact unique matches to avoid unintended changes.\n- Freshness validation prevents conflicts with external modifications.";
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT = exports.DESCRIPTION = void 0;
4
+ exports.DESCRIPTION = 'Edit a file by replacing old_string with new_string';
5
+ exports.PROMPT = `Use this tool for precise in-place edits.
6
+
7
+ Guidelines:
8
+ - Provide a unique "old_string" snippet to replace. If multiple matches exist, set "replace_all" to true.
9
+ - Combine with fs_read to confirm the current file state before editing.
10
+ - The tool integrates with FilePool to ensure the file has not changed externally.
11
+ - If old_string is not unique, the tool will reject the operation unless replace_all is true.
12
+
13
+ Safety/Limitations:
14
+ - Single replacements require exact unique matches to avoid unintended changes.
15
+ - Freshness validation prevents conflicts with external modifications.`;
@@ -0,0 +1 @@
1
+ export declare const FsGlob: import("..").ToolInstance;
@@ -0,0 +1,60 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FsGlob = void 0;
4
+ const tool_1 = require("../tool");
5
+ const zod_1 = require("zod");
6
+ const type_inference_1 = require("../type-inference");
7
+ const prompt_1 = require("./prompt");
8
+ exports.FsGlob = (0, tool_1.tool)({
9
+ name: 'fs_glob',
10
+ description: prompt_1.DESCRIPTION,
11
+ parameters: zod_1.z.object({
12
+ pattern: zod_1.z.string().describe('Glob pattern to match'),
13
+ cwd: type_inference_1.patterns.optionalString('Optional directory to resolve from'),
14
+ dot: zod_1.z.boolean().optional().describe('Include dotfiles (default: false)'),
15
+ limit: type_inference_1.patterns.optionalNumber('Maximum number of results (default: 200)'),
16
+ }),
17
+ async execute(args, ctx) {
18
+ const { pattern, cwd, dot = false, limit = 200 } = args;
19
+ const matches = await ctx.sandbox.fs.glob(pattern, {
20
+ cwd,
21
+ dot,
22
+ absolute: false,
23
+ });
24
+ // Heuristic: Next.js dynamic route segments use "[id]" which is interpreted as a glob character class.
25
+ // If the user/model passes patterns like "app/**/[id]/route.ts", the match set will be empty.
26
+ // Auto-retry with escaped brackets to improve UX.
27
+ let usedPattern = pattern;
28
+ let effectiveMatches = matches;
29
+ if (matches.length === 0) {
30
+ const escaped = escapeNextRouteSegments(pattern);
31
+ if (escaped !== pattern) {
32
+ const retry = await ctx.sandbox.fs.glob(escaped, { cwd, dot, absolute: false });
33
+ if (retry.length > 0) {
34
+ usedPattern = escaped;
35
+ effectiveMatches = retry;
36
+ }
37
+ }
38
+ }
39
+ const truncated = effectiveMatches.length > limit;
40
+ const results = effectiveMatches.slice(0, limit);
41
+ return {
42
+ ok: true,
43
+ pattern,
44
+ usedPattern: usedPattern === pattern ? undefined : usedPattern,
45
+ cwd: cwd || '.',
46
+ truncated,
47
+ count: effectiveMatches.length,
48
+ matches: results,
49
+ };
50
+ },
51
+ metadata: {
52
+ readonly: true,
53
+ version: '1.0',
54
+ },
55
+ });
56
+ exports.FsGlob.prompt = prompt_1.PROMPT;
57
+ function escapeNextRouteSegments(pattern) {
58
+ // Match "[id]" style segments (letters/numbers/underscore only) and escape them as "[[]id[]]".
59
+ return pattern.replace(/\[([A-Za-z0-9_]+)\]/g, (_m, name) => `[[]${name}[]]`);
60
+ }
@@ -0,0 +1,2 @@
1
+ export declare const DESCRIPTION = "List files matching glob patterns";
2
+ export declare const PROMPT = "Use this tool to locate files with glob patterns (e.g. \"src/**/*.ts\").\n\nGuidelines:\n- It respects sandbox boundaries and returns relative paths by default.\n- Use standard glob syntax: * (any chars), ** (recursive directories), ? (single char).\n- Square brackets are special in glob patterns. To match a literal Next.js dynamic segment like \"[id]\", escape it:\n - Recommended: \"[[]id[]]\" (micromatch/fast-glob compatible)\n - Alternative: \"\\\\[id\\\\]\"\n- Set \"dot\" to true to include hidden files (starting with .).\n- Results are limited to prevent overwhelming responses.\n\nSafety/Limitations:\n- All paths are restricted to the sandbox root directory.\n- Large result sets are truncated with a warning.";
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT = exports.DESCRIPTION = void 0;
4
+ exports.DESCRIPTION = 'List files matching glob patterns';
5
+ exports.PROMPT = `Use this tool to locate files with glob patterns (e.g. "src/**/*.ts").
6
+
7
+ Guidelines:
8
+ - It respects sandbox boundaries and returns relative paths by default.
9
+ - Use standard glob syntax: * (any chars), ** (recursive directories), ? (single char).
10
+ - Square brackets are special in glob patterns. To match a literal Next.js dynamic segment like "[id]", escape it:
11
+ - Recommended: "[[]id[]]" (micromatch/fast-glob compatible)
12
+ - Alternative: "\\\\[id\\\\]"
13
+ - Set "dot" to true to include hidden files (starting with .).
14
+ - Results are limited to prevent overwhelming responses.
15
+
16
+ Safety/Limitations:
17
+ - All paths are restricted to the sandbox root directory.
18
+ - Large result sets are truncated with a warning.`;
@@ -0,0 +1 @@
1
+ export declare const FsGrep: import("..").ToolInstance;
@@ -0,0 +1,66 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FsGrep = void 0;
4
+ const tool_1 = require("../tool");
5
+ const zod_1 = require("zod");
6
+ const type_inference_1 = require("../type-inference");
7
+ const prompt_1 = require("./prompt");
8
+ exports.FsGrep = (0, tool_1.tool)({
9
+ name: 'fs_grep',
10
+ description: prompt_1.DESCRIPTION,
11
+ parameters: zod_1.z.object({
12
+ pattern: zod_1.z.string().describe('String or regular expression to search for'),
13
+ path: zod_1.z.string().describe('File path or glob pattern'),
14
+ regex: zod_1.z.boolean().optional().describe('Interpret pattern as regular expression (default: false)'),
15
+ case_sensitive: zod_1.z.boolean().optional().describe('Case sensitive search (default: true)'),
16
+ max_results: type_inference_1.patterns.optionalNumber('Maximum matches to return (default: 200)'),
17
+ }),
18
+ async execute(args, ctx) {
19
+ const { pattern, path, regex = false, case_sensitive = true, max_results = 200 } = args;
20
+ if (!pattern) {
21
+ return { ok: false, error: 'pattern must not be empty' };
22
+ }
23
+ const files = await ctx.sandbox.fs.glob(path, { absolute: false, dot: true });
24
+ const regexPattern = regex
25
+ ? new RegExp(pattern, case_sensitive ? 'g' : 'gi')
26
+ : new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), case_sensitive ? 'g' : 'gi');
27
+ const matches = [];
28
+ for (const file of files) {
29
+ if (matches.length >= max_results)
30
+ break;
31
+ const content = await ctx.sandbox.fs.read(file);
32
+ const lines = content.split('\n');
33
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
34
+ if (matches.length >= max_results)
35
+ break;
36
+ const line = lines[lineIndex];
37
+ regexPattern.lastIndex = 0;
38
+ let match;
39
+ while ((match = regexPattern.exec(line))) {
40
+ matches.push({
41
+ path: file,
42
+ line: lineIndex + 1,
43
+ column: match.index + 1,
44
+ preview: line.trim().slice(0, 200),
45
+ });
46
+ if (matches.length >= max_results)
47
+ break;
48
+ if (!regex)
49
+ break;
50
+ }
51
+ }
52
+ }
53
+ return {
54
+ ok: true,
55
+ pattern,
56
+ path,
57
+ matches,
58
+ truncated: matches.length >= max_results && files.length > 0,
59
+ };
60
+ },
61
+ metadata: {
62
+ readonly: true,
63
+ version: '1.0',
64
+ },
65
+ });
66
+ exports.FsGrep.prompt = prompt_1.PROMPT;
@@ -0,0 +1,2 @@
1
+ export declare const DESCRIPTION = "Search for text patterns inside files";
2
+ export declare const PROMPT = "Search one or more files for a literal string or regular expression.\n\nGuidelines:\n- Use this to locate references before editing.\n- The \"path\" parameter can be a specific file or a glob pattern (e.g., \"src/**/*.ts\").\n- Set \"regex\" to true to interpret the pattern as a regular expression.\n- Case-sensitive by default; set \"case_sensitive\" to false for case-insensitive search.\n- Results include file path, line number, column number, and a preview of the match.\n\nSafety/Limitations:\n- Result sets are limited to prevent overwhelming responses.\n- Search is constrained to the sandbox directory.";
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PROMPT = exports.DESCRIPTION = void 0;
4
+ exports.DESCRIPTION = 'Search for text patterns inside files';
5
+ exports.PROMPT = `Search one or more files for a literal string or regular expression.
6
+
7
+ Guidelines:
8
+ - Use this to locate references before editing.
9
+ - The "path" parameter can be a specific file or a glob pattern (e.g., "src/**/*.ts").
10
+ - Set "regex" to true to interpret the pattern as a regular expression.
11
+ - Case-sensitive by default; set "case_sensitive" to false for case-insensitive search.
12
+ - Results include file path, line number, column number, and a preview of the match.
13
+
14
+ Safety/Limitations:
15
+ - Result sets are limited to prevent overwhelming responses.
16
+ - Search is constrained to the sandbox directory.`;
@@ -0,0 +1 @@
1
+ export declare const FsMultiEdit: import("..").ToolInstance;