minimal-agent 0.11.0 → 0.13.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 (181) hide show
  1. package/package.json +5 -1
  2. package/plugins/workflow-runner/plugin.js +27 -15
  3. package/plugins/workflow-runner/plugin.ts +34 -20
  4. package/plugins/workflow-runner/src/agentCommon.js +13 -12
  5. package/plugins/workflow-runner/src/agentCommon.ts +22 -13
  6. package/plugins/workflow-runner/src/expressions.js +29 -8
  7. package/plugins/workflow-runner/src/expressions.ts +28 -10
  8. package/plugins/workflow-runner/src/index.js +50 -20
  9. package/plugins/workflow-runner/src/index.ts +75 -31
  10. package/plugins/workflow-runner/src/multimodal.js +2 -1
  11. package/plugins/workflow-runner/src/multimodal.ts +2 -1
  12. package/plugins/workflow-runner/src/recovery.js +9 -2
  13. package/plugins/workflow-runner/src/recovery.ts +9 -2
  14. package/plugins/workflow-runner/src/runner.js +31 -5
  15. package/plugins/workflow-runner/src/runner.ts +33 -5
  16. package/plugins/workflow-runner/src/stepExecutors/assert.js +2 -1
  17. package/plugins/workflow-runner/src/stepExecutors/assert.ts +3 -1
  18. package/plugins/workflow-runner/src/stepExecutors/skill.js +5 -6
  19. package/plugins/workflow-runner/src/stepExecutors/skill.ts +12 -7
  20. package/plugins/workflow-runner/src/stepExecutors/tool.js +91 -61
  21. package/plugins/workflow-runner/src/stepExecutors/tool.ts +111 -71
  22. package/plugins/workflow-runner/src/stepExecutors/verify.js +6 -3
  23. package/plugins/workflow-runner/src/stepExecutors/verify.ts +7 -3
  24. package/plugins/workflow-runner/src/taskIdentity.js +197 -21
  25. package/plugins/workflow-runner/src/taskIdentity.ts +201 -20
  26. package/plugins/workflow-runner/src/toolRuntime.js +48 -0
  27. package/plugins/workflow-runner/src/toolRuntime.ts +64 -0
  28. package/plugins/workflow-runner/src/types.js +113 -7
  29. package/plugins/workflow-runner/src/types.ts +137 -14
  30. package/plugins/workflow-runner/src/workflowState.js +455 -54
  31. package/plugins/workflow-runner/src/workflowState.ts +508 -63
  32. package/plugins/workflow-runner/test/cli.e2e.test.ts +20 -0
  33. package/plugins/workflow-runner/test/context-files.test.ts +47 -16
  34. package/plugins/workflow-runner/test/e2eNewLayout.test.ts +314 -0
  35. package/plugins/workflow-runner/test/engineRobustness.test.ts +9 -1
  36. package/plugins/workflow-runner/test/expressions.test.ts +42 -0
  37. package/plugins/workflow-runner/test/hostCapability.test.ts +9 -3
  38. package/plugins/workflow-runner/test/illustrate.load.test.ts +2 -2
  39. package/plugins/workflow-runner/test/multimodal.test.ts +61 -10
  40. package/plugins/workflow-runner/test/parseWorkflowArgs.test.ts +19 -0
  41. package/plugins/workflow-runner/test/ppt.load.test.ts +15 -15
  42. package/plugins/workflow-runner/test/ralphLoop.e2e.test.ts +3 -2
  43. package/plugins/workflow-runner/test/research.load.test.ts +328 -0
  44. package/plugins/workflow-runner/test/runnerPreflight.test.ts +68 -11
  45. package/plugins/workflow-runner/test/stateLifecycle.test.ts +60 -12
  46. package/plugins/workflow-runner/test/taskArbitration.test.ts +19 -3
  47. package/plugins/workflow-runner/test/taskLifecycle.test.ts +61 -7
  48. package/plugins/workflow-runner/test/toolRuntimeIntegration.test.ts +168 -0
  49. package/plugins/workflow-runner/test/webppt.load.test.ts +4 -4
  50. package/plugins/workflow-runner/test/word.load.test.ts +9 -9
  51. package/skills/skill-creator/scripts/run_eval.py +3 -2
  52. package/src/cli/print.js +36 -4
  53. package/src/cli/print.ts +42 -4
  54. package/src/cli/streamJson.js +19 -4
  55. package/src/cli/streamJson.ts +17 -4
  56. package/src/config/configDefaults.js +25 -0
  57. package/src/config/configDefaults.ts +33 -0
  58. package/src/config/configFile.js +2 -21
  59. package/src/config/configFile.ts +11 -24
  60. package/src/config/configManagement.js +1 -1
  61. package/src/config/configManagement.ts +2 -2
  62. package/src/config/configService.js +24 -0
  63. package/src/config/configService.ts +23 -0
  64. package/src/context/compact.js +4 -0
  65. package/src/context/compact.ts +4 -0
  66. package/src/context/contextBundle.js +38 -13
  67. package/src/context/contextBundle.ts +47 -13
  68. package/src/harness/stallGuard.js +19 -4
  69. package/src/harness/stallGuard.ts +30 -7
  70. package/src/infra/verification.js +25 -18
  71. package/src/infra/verification.ts +50 -18
  72. package/src/loop.js +95 -11
  73. package/src/loop.ts +125 -16
  74. package/src/main.js +8 -1
  75. package/src/main.tsx +7 -1
  76. package/src/memory/constants.js +10 -0
  77. package/src/memory/constants.ts +13 -0
  78. package/src/memory/episodicMemory.js +274 -2
  79. package/src/memory/episodicMemory.ts +306 -1
  80. package/src/memory/fileStore.js +24 -4
  81. package/src/memory/fileStore.ts +22 -2
  82. package/src/memory/memoryService.js +79 -12
  83. package/src/memory/memoryService.ts +108 -9
  84. package/src/memory/repository.js +415 -85
  85. package/src/memory/repository.ts +437 -86
  86. package/src/memory/turnJournal.js +95 -0
  87. package/src/memory/turnJournal.ts +120 -0
  88. package/src/memory/types.ts +16 -0
  89. package/src/plugins/pluginApi.ts +30 -6
  90. package/src/plugins/pluginRunner.js +23 -8
  91. package/src/plugins/pluginRunner.ts +32 -13
  92. package/src/prompts/policyRegistry.js +55 -1
  93. package/src/prompts/policyRegistry.ts +55 -1
  94. package/src/prompts/promptAssembly.js +39 -7
  95. package/src/prompts/promptAssembly.ts +145 -59
  96. package/src/session/runAgentTurn.js +43 -21
  97. package/src/session/runAgentTurn.ts +68 -26
  98. package/src/session/runTurn.js +11 -46
  99. package/src/session/runTurn.ts +12 -46
  100. package/src/session/runtimeStore.js +149 -0
  101. package/src/session/runtimeStore.ts +197 -0
  102. package/src/session/sessionState.js +5 -0
  103. package/src/session/sessionState.ts +14 -0
  104. package/src/tools/advisor/advisor.js +76 -9
  105. package/src/tools/advisor/advisor.ts +79 -9
  106. package/src/tools/agent/agent.js +143 -14
  107. package/src/tools/agent/agent.ts +149 -14
  108. package/src/tools/agent/agentTaskService.js +60 -0
  109. package/src/tools/agent/agentTaskService.ts +113 -0
  110. package/src/tools/agent/agentTypes.js +5 -0
  111. package/src/tools/agent/agentTypes.ts +5 -0
  112. package/src/tools/bash/bash.js +80 -15
  113. package/src/tools/bash/bash.ts +83 -15
  114. package/src/tools/capabilities.js +5 -0
  115. package/src/tools/capabilities.ts +11 -1
  116. package/src/tools/edit/edit.js +7 -4
  117. package/src/tools/edit/edit.ts +7 -4
  118. package/src/tools/edit/multi-edit.js +4 -2
  119. package/src/tools/edit/multi-edit.ts +4 -2
  120. package/src/tools/glob/glob.js +156 -40
  121. package/src/tools/glob/glob.ts +185 -46
  122. package/src/tools/index.js +35 -17
  123. package/src/tools/index.ts +81 -20
  124. package/src/tools/lsp/lsp.js +165 -22
  125. package/src/tools/lsp/lsp.ts +206 -36
  126. package/src/tools/powershell/powershell.js +134 -27
  127. package/src/tools/powershell/powershell.ts +171 -30
  128. package/src/tools/presentresult/presentresult.js +10 -0
  129. package/src/tools/presentresult/presentresult.ts +10 -0
  130. package/src/tools/read/read.js +249 -29
  131. package/src/tools/read/read.ts +396 -59
  132. package/src/tools/shared/diffSummary.js +44 -0
  133. package/src/tools/shared/diffSummary.ts +63 -0
  134. package/src/tools/shared/fileActivity.js +2 -1
  135. package/src/tools/shared/fileActivity.ts +3 -0
  136. package/src/tools/shared/permanentDeleteGuard.js +57 -0
  137. package/src/tools/shared/permanentDeleteGuard.ts +71 -0
  138. package/src/tools/shared/toolOutputStore.js +97 -0
  139. package/src/tools/shared/toolOutputStore.ts +110 -0
  140. package/src/tools/skill/skill.js +86 -0
  141. package/src/tools/skill/skill.ts +94 -0
  142. package/src/tools/snip/snip.js +67 -0
  143. package/src/tools/snip/snip.ts +80 -0
  144. package/src/tools/tasks/backgroundTaskService.js +79 -28
  145. package/src/tools/tasks/backgroundTaskService.ts +165 -49
  146. package/src/tools/tasks/taskManagement.js +163 -0
  147. package/src/tools/tasks/taskManagement.ts +180 -0
  148. package/src/tools/tasks/taskOutput.js +64 -14
  149. package/src/tools/tasks/taskOutput.ts +102 -23
  150. package/src/tools/tasks/taskStop.js +48 -8
  151. package/src/tools/tasks/taskStop.ts +69 -9
  152. package/src/tools/tasks/taskStore.js +46 -0
  153. package/src/tools/tasks/taskStore.ts +77 -0
  154. package/src/tools/terminal/terminalCapture.js +167 -0
  155. package/src/tools/terminal/terminalCapture.ts +179 -0
  156. package/src/tools/trash/trash.js +233 -0
  157. package/src/tools/trash/trash.ts +283 -0
  158. package/src/tools/webbrowser/browserControl.js +5 -1
  159. package/src/tools/webbrowser/browserControl.ts +7 -1
  160. package/src/tools/webbrowser/webbrowser.js +8 -4
  161. package/src/tools/webbrowser/webbrowser.ts +8 -4
  162. package/src/tools/worktree/sessionWorktree.js +128 -0
  163. package/src/tools/worktree/sessionWorktree.ts +158 -0
  164. package/src/tools/write/write.js +6 -2
  165. package/src/tools/write/write.ts +6 -2
  166. package/src/types.ts +22 -4
  167. package/src/ui/hooks/useChat.js +31 -11
  168. package/src/ui/hooks/useChat.ts +31 -13
  169. package/src/web/protocol.ts +78 -3
  170. package/workflows/adaptive-research.yaml +5 -5
  171. package/workflows/book-review-short.yaml +5 -5
  172. package/workflows/e2e-write-greet.yaml +2 -2
  173. package/workflows/illustrate.yaml +12 -12
  174. package/workflows/plan.yaml +18 -18
  175. package/workflows/ppt.yaml +201 -201
  176. package/workflows/ralph-loop.yaml +3 -1
  177. package/workflows/research.md +449 -0
  178. package/workflows/research.yaml +873 -0
  179. package/workflows/webppt.yaml +47 -47
  180. package/workflows/word.yaml +80 -80
  181. package/workflows/youtube-shorts.yaml +25 -25
@@ -3,13 +3,14 @@
3
3
  * src/tools/glob.ts —— Glob 工具(按文件名模式匹配)
4
4
  * ------------------------------------------------------------
5
5
  * 对应 kakadeai 主仓库的 GlobTool。
6
- * 实现用 fast-glob(npm 包),默认按 mtime 倒序排列(新文件在前)。
6
+ * 实现用 fast-glob(npm 包),默认按发现顺序流式返回。
7
7
  * 支持限制候选数量,并通过结构化元数据返回大小和修改时间。
8
8
  * ============================================================
9
9
  */
10
10
 
11
11
  import { isAbsolute, relative, resolve, sep } from 'node:path';
12
12
  import fg from 'fast-glob';
13
+ import { stat } from 'node:fs/promises';
13
14
  import { z } from 'zod';
14
15
 
15
16
  import { getWorkingDir } from '../../bootstrap/workingDir.js';
@@ -26,11 +27,37 @@ const inputSchema = z.object({
26
27
  path: z
27
28
  .string()
28
29
  .optional()
29
- .describe('搜索的根目录(默认当前工作目录);省略时不要传 "undefined" 字符串'),
30
- sort_by: z.enum(['modified', 'path']).default('modified').optional().describe('排序字段,默认 modified'),
31
- order: z.enum(['asc', 'desc']).default('desc').optional().describe('排序方向,默认 desc(最新在前)'),
32
- offset: z.number().int().min(0).optional().describe('跳过前 N 个结果,默认 0'),
33
- limit: z.number().int().min(0).max(10_000).optional().describe('最多返回多少个候选文件;默认 200,0 表示不限制'),
30
+ .describe(
31
+ '搜索的根目录(默认当前工作目录);省略时不要传 "undefined" 字符串',
32
+ ),
33
+ strategy: z
34
+ .enum(['fast', 'complete'])
35
+ .default('fast')
36
+ .optional()
37
+ .describe('fast 在收集够分页候选后提前停止;完整排序请用 complete'),
38
+ sort_by: z
39
+ .enum(['discovery', 'modified', 'path'])
40
+ .default('discovery')
41
+ .optional()
42
+ .describe('排序字段,默认 discovery'),
43
+ order: z
44
+ .enum(['asc', 'desc'])
45
+ .default('desc')
46
+ .optional()
47
+ .describe('排序方向,默认 desc(最新在前)'),
48
+ offset: z
49
+ .number()
50
+ .int()
51
+ .min(0)
52
+ .optional()
53
+ .describe('跳过前 N 个结果,默认 0'),
54
+ limit: z
55
+ .number()
56
+ .int()
57
+ .min(0)
58
+ .max(10_000)
59
+ .optional()
60
+ .describe('最多返回多少个候选文件;默认 200,0 表示不限制'),
34
61
  });
35
62
  type GlobInput = z.infer<typeof inputSchema>;
36
63
 
@@ -41,13 +68,17 @@ const parameters = toToolParameters(inputSchema);
41
68
  const description = `- Fast file pattern matching tool that works with any codebase size
42
69
  - Supports glob patterns like "**/*.js" or "src/**/*.ts"
43
70
  - Returns structured file candidates with path, size, and modification time
44
- - Defaults to modification time descending, which is useful for requests like "find the latest contract"
71
+ - Defaults to streaming discovery order; request sort_by=modified with strategy=complete for newest-file queries
45
72
  - Discovery does not present files to the user; use Read for selected source files and PresentResult for delivered files
46
73
  - Use this tool when you need to find files by name patterns
47
74
  - When you need to do an open ended search that may require multiple rounds, prefer the Grep tool for content search`;
48
75
 
49
76
  // ---------------- 4. call() ----------------
50
- async function call(input: GlobInput, runCwd = getWorkingDir()): Promise<ToolResult> {
77
+ async function call(
78
+ input: GlobInput,
79
+ runCwd = getWorkingDir(),
80
+ signal?: AbortSignal,
81
+ ): Promise<ToolResult> {
51
82
  // 以 getWorkingDir() 为锚,而非裸 resolve()(同 grep.ts 的坑:后者落回 process.cwd(),
52
83
  // 多工作区宿主进程里会与当前工作区脱节)。resolve 对绝对路径行为不变。
53
84
  const cwd = input.path ? resolve(runCwd, input.path) : runCwd;
@@ -57,48 +88,147 @@ async function call(input: GlobInput, runCwd = getWorkingDir()): Promise<ToolRes
57
88
  // (cwd 用原生路径没问题;fast-glob 内部会处理)
58
89
  const pattern = input.pattern.replace(/\\/g, '/');
59
90
 
60
- // fast-glob 自带 ignore 一部分(node_modules 之类还是要显式排除)
61
- let matches: fg.Entry[];
91
+ const offset = input.offset ?? 0,
92
+ limit = input.limit ?? 200,
93
+ strategy = input.strategy ?? 'fast',
94
+ sortBy = input.sort_by ?? 'discovery';
95
+ const needed = limit === 0 ? Number.POSITIVE_INFINITY : offset + limit + 1;
96
+ const ignore = ['node_modules', '.git', '.svn', '.hg', '.jj', '.sl', 'dist']
97
+ .filter((name) => !pattern.split('/').includes(name))
98
+ .map((name) => `**/${name}/**`);
99
+ type Candidate = {
100
+ path: string;
101
+ mtime: number;
102
+ size: number;
103
+ discovery: number;
104
+ };
105
+ const candidates: Candidate[] = [];
106
+ let scanned = 0;
107
+ let stoppedEarly = false;
108
+ const effectiveOrder =
109
+ input.order ?? (sortBy === 'discovery' ? 'asc' : 'desc');
110
+ const compare = (a: Candidate, b: Candidate): number => {
111
+ const value =
112
+ sortBy === 'path'
113
+ ? a.path.localeCompare(b.path)
114
+ : sortBy === 'modified'
115
+ ? a.mtime - b.mtime
116
+ : a.discovery - b.discovery;
117
+ return value * (effectiveOrder === 'desc' ? -1 : 1);
118
+ };
119
+ // 最大堆的根始终是当前保留集合里“最差”的候选,完整扫描只占 O(offset+limit) 内存。
120
+ const bubbleUp = (index: number) => {
121
+ while (index > 0) {
122
+ const parent = Math.floor((index - 1) / 2);
123
+ if (compare(candidates[parent]!, candidates[index]!) >= 0) break;
124
+ [candidates[parent], candidates[index]] = [
125
+ candidates[index]!,
126
+ candidates[parent]!,
127
+ ];
128
+ index = parent;
129
+ }
130
+ };
131
+ const bubbleDown = (index: number) => {
132
+ while (true) {
133
+ const left = index * 2 + 1,
134
+ right = left + 1;
135
+ let worst = index;
136
+ if (
137
+ left < candidates.length &&
138
+ compare(candidates[left]!, candidates[worst]!) > 0
139
+ )
140
+ worst = left;
141
+ if (
142
+ right < candidates.length &&
143
+ compare(candidates[right]!, candidates[worst]!) > 0
144
+ )
145
+ worst = right;
146
+ if (worst === index) break;
147
+ [candidates[index], candidates[worst]] = [
148
+ candidates[worst]!,
149
+ candidates[index]!,
150
+ ];
151
+ index = worst;
152
+ }
153
+ };
154
+ const retain = (item: Candidate) => {
155
+ if (limit === 0) {
156
+ candidates.push(item);
157
+ return;
158
+ }
159
+ if (candidates.length < needed) {
160
+ candidates.push(item);
161
+ bubbleUp(candidates.length - 1);
162
+ } else if (compare(item, candidates[0]!) < 0) {
163
+ candidates[0] = item;
164
+ bubbleDown(0);
165
+ }
166
+ };
62
167
  try {
63
- matches = await fg(pattern, {
168
+ const stream = fg.stream(pattern, {
64
169
  cwd,
65
170
  dot: true,
66
171
  onlyFiles: true,
67
172
  followSymbolicLinks: false,
68
- // Explicit patterns win over defaults (fast-glob ignore otherwise always wins).
69
- ignore: ['node_modules', '.git', '.svn', '.hg', '.jj', '.sl', 'dist']
70
- .filter((name) => !pattern.split('/').includes(name))
71
- .map((name) => `**/${name}/**`),
173
+ ignore,
72
174
  absolute: false,
73
- stats: true,
74
175
  });
176
+ for await (const raw of stream) {
177
+ if (signal?.aborted) {
178
+ (stream as unknown as { destroy?: () => void }).destroy?.();
179
+ throw new Error('aborted');
180
+ }
181
+ const path = Buffer.isBuffer(raw) ? raw.toString('utf8') : String(raw);
182
+ scanned++;
183
+ if (strategy === 'fast' && sortBy === 'discovery') {
184
+ candidates.push({ path, mtime: 0, size: 0, discovery: scanned });
185
+ if (candidates.length >= needed) {
186
+ stoppedEarly = true;
187
+ (stream as unknown as { destroy?: () => void }).destroy?.();
188
+ break;
189
+ }
190
+ continue;
191
+ }
192
+ const info =
193
+ sortBy === 'modified'
194
+ ? await stat(resolve(cwd, path))
195
+ : { mtimeMs: 0, size: 0 };
196
+ const item = {
197
+ path,
198
+ mtime: info.mtimeMs,
199
+ size: info.size,
200
+ discovery: scanned,
201
+ };
202
+ retain(item);
203
+ }
75
204
  } catch (e) {
76
205
  return { ok: false, error: `glob 失败:${(e as Error).message}` };
77
206
  }
78
207
 
79
- if (matches.length === 0) {
80
- return { ok: true, content: `(no files matched pattern "${pattern}" in ${cwd})` };
208
+ if (candidates.length === 0) {
209
+ return {
210
+ ok: true,
211
+ content: `(no files matched pattern "${pattern}" in ${cwd})`,
212
+ };
81
213
  }
82
214
 
83
215
  // 候选携带稳定元数据。发现候选本身不代表文件已经成为会话上下文。
84
- const withMtime = await Promise.all(
85
- matches.map(async (entry) => ({
86
- path: entry.path,
87
- mtime: entry.stats?.mtimeMs ?? 0,
88
- size: entry.stats?.size ?? 0,
89
- })),
90
- );
91
- const direction = (input.order ?? 'desc') === 'desc' ? -1 : 1;
92
- withMtime.sort((a, b) => {
93
- const compared = (input.sort_by ?? 'modified') === 'path'
94
- ? a.path.localeCompare(b.path)
95
- : a.mtime - b.mtime;
96
- return compared * direction;
97
- });
98
- const offset = input.offset ?? 0;
99
- const limit = input.limit ?? 200;
100
- const selected = limit === 0 ? withMtime.slice(offset) : withMtime.slice(offset, offset + limit);
101
- const truncated = offset + selected.length < withMtime.length;
216
+ const withMtime = candidates;
217
+ withMtime.sort(compare);
218
+ const selected =
219
+ limit === 0
220
+ ? withMtime.slice(offset)
221
+ : withMtime.slice(offset, offset + limit);
222
+ const truncated = stoppedEarly || offset + selected.length < withMtime.length;
223
+ for (const item of selected) {
224
+ if (item.size === 0 && item.mtime === 0) {
225
+ const info = await stat(resolve(cwd, item.path)).catch(() => undefined);
226
+ if (info) {
227
+ item.size = info.size;
228
+ item.mtime = info.mtimeMs;
229
+ }
230
+ }
231
+ }
102
232
 
103
233
  // 输出:每行一个相对路径
104
234
  let content = selected.map((m) => m.path).join('\n');
@@ -107,23 +237,31 @@ async function call(input: GlobInput, runCwd = getWorkingDir()): Promise<ToolRes
107
237
  if (content.length > DEFAULT_MAX_RESULT_SIZE_CHARS) {
108
238
  content =
109
239
  content.slice(0, DEFAULT_MAX_RESULT_SIZE_CHARS) +
110
- `\n\n... (共 ${withMtime.length} 个文件,输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符,已截断)`;
240
+ `\n\n... (输出超过 ${DEFAULT_MAX_RESULT_SIZE_CHARS} 字符,已截断)`;
111
241
  }
112
242
  const workspaceRoot = resolve(runCwd);
113
243
  return {
114
244
  ok: true,
115
- content: `${content}\n\n(匹配 ${withMtime.length} 个,返回 ${selected.length} 个,offset=${offset}${truncated ? ',仍有后续结果' : ''},按 ${input.sort_by ?? 'modified'} ${input.order ?? 'desc'} 排序)`,
245
+ content: `${content}\n\n(${stoppedEarly ? `至少扫描 ${scanned} 个` : `匹配 ${scanned} 个`},返回 ${selected.length} 个,offset=${offset}${truncated ? ',仍有后续结果' : ''},按 ${sortBy} ${effectiveOrder} 排序)`,
116
246
  metadata: {
117
247
  kind: 'file_discovery',
118
248
  files: selected.flatMap((entry) => {
119
249
  const absolute = resolve(cwd, entry.path);
120
250
  const rel = relative(workspaceRoot, absolute);
121
- if (!rel || rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel)) return [];
122
- return [{
123
- relativePath: rel.split(sep).join('/'),
124
- size: entry.size,
125
- modifiedAt: entry.mtime,
126
- }];
251
+ if (
252
+ !rel ||
253
+ rel === '..' ||
254
+ rel.startsWith(`..${sep}`) ||
255
+ isAbsolute(rel)
256
+ )
257
+ return [];
258
+ return [
259
+ {
260
+ relativePath: rel.split(sep).join('/'),
261
+ size: entry.size,
262
+ modifiedAt: entry.mtime,
263
+ },
264
+ ];
127
265
  }),
128
266
  },
129
267
  };
@@ -139,6 +277,7 @@ export const globTool: Tool<GlobInput> = {
139
277
  isConcurrencySafe: true,
140
278
  maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
141
279
  interruptBehavior: () => 'cancel',
142
- call: (input) => call(input),
143
- callWithContext: (input, _signal, context: ToolCallContext) => call(input, context.cwd),
280
+ call: (input, signal) => call(input, undefined, signal),
281
+ callWithContext: (input, signal, context: ToolCallContext) =>
282
+ call(input, context.cwd, signal),
144
283
  };
@@ -19,6 +19,8 @@ import { advisorTool } from './advisor/advisor.js';
19
19
  import { agentTool } from './agent/agent.js';
20
20
  import { askUserQuestionTool } from './ask/ask.js';
21
21
  import { bashTool } from './bash/bash.js';
22
+ import { assertCapabilityRegistry } from './capabilities.js';
23
+ import { computerUseTool } from './computeruse/computeruse.js';
22
24
  import { downloadTool } from './download/download.js';
23
25
  import { editTool } from './edit/edit.js';
24
26
  import { multiEditTool } from './edit/multi-edit.js';
@@ -26,20 +28,24 @@ import { genImageTool } from './genimage/genimage.js';
26
28
  import { generateSpeechTool } from './genspeech/genspeech.js';
27
29
  import { globTool } from './glob/glob.js';
28
30
  import { grepTool } from './grep/grep.js';
29
- import { readTool } from './read/read.js';
30
- import { presentResultTool } from './presentresult/presentresult.js';
31
- import { clearPersonaTool, confirmMemoryTool, forgetMemoryTool, listMemoriesTool, recallMemoryTool, rememberMemoryTool, reviewMemoriesTool, searchConversationsTool, setPersonaTool, updateMemoryTool, } from './memory/memory.js';
32
- import { webfetchTool } from './webfetch/webfetch.js';
33
- import { webbrowserTool } from './webbrowser/webbrowser.js';
34
- import { webSearchTool } from './websearch/websearch.js';
35
- import { writeTool } from './write/write.js';
36
- import { computerUseTool } from './computeruse/computeruse.js';
37
- import { assertCapabilityRegistry } from './capabilities.js';
38
31
  import { lspTool } from './lsp/lsp.js';
32
+ import { clearPersonaTool, confirmMemoryTool, forgetMemoryTool, listMemoriesTool, recallMemoryTool, rememberMemoryTool, reviewMemoriesTool, searchConversationsTool, setPersonaTool, updateMemoryTool, } from './memory/memory.js';
39
33
  import { notebookEditTool } from './notebook/notebookEdit.js';
40
34
  import { powerShellTool } from './powershell/powershell.js';
35
+ import { presentResultTool } from './presentresult/presentresult.js';
36
+ import { readTool } from './read/read.js';
37
+ import { skillTool } from './skill/skill.js';
38
+ import { snipTool } from './snip/snip.js';
39
+ import { taskCreateTool, taskGetTool, taskListTool, taskUpdateTool, } from './tasks/taskManagement.js';
41
40
  import { taskOutputTool } from './tasks/taskOutput.js';
42
41
  import { taskStopTool } from './tasks/taskStop.js';
42
+ import { terminalCaptureTool } from './terminal/terminalCapture.js';
43
+ import { trashTool } from './trash/trash.js';
44
+ import { webbrowserTool } from './webbrowser/webbrowser.js';
45
+ import { webfetchTool } from './webfetch/webfetch.js';
46
+ import { webSearchTool } from './websearch/websearch.js';
47
+ import { enterWorktreeTool, exitWorktreeTool, } from './worktree/sessionWorktree.js';
48
+ import { writeTool } from './write/write.js';
43
49
  /** 所有内置工具(顺序 = 给 LLM 呈现的顺序,不影响代码执行,但会影响模型的优先级直觉) */
44
50
  export const ALL_TOOLS = [
45
51
  readTool,
@@ -76,6 +82,17 @@ export const ALL_TOOLS = [
76
82
  computerUseTool,
77
83
  // 追加在末尾:主循环 tools schema 的原有前缀字节不动(提示词缓存友好)
78
84
  agentTool,
85
+ // Product tools append at the end to preserve the existing schema prefix cache.
86
+ trashTool,
87
+ taskCreateTool,
88
+ taskGetTool,
89
+ taskUpdateTool,
90
+ taskListTool,
91
+ skillTool,
92
+ enterWorktreeTool,
93
+ exitWorktreeTool,
94
+ terminalCaptureTool,
95
+ snipTool,
79
96
  ];
80
97
  assertCapabilityRegistry(ALL_TOOLS.map((tool) => tool.name));
81
98
  /** 按名字查表 */
@@ -157,12 +174,7 @@ export async function executeTool(name, rawArguments, signal, ctx) {
157
174
  .join('\n');
158
175
  return {
159
176
  ok: false,
160
- error: `工具 ${name} 参数校验失败,**请按下面逐条改正后重新调用**:\n${issues}\n\n`
161
- + '通用修法:\n'
162
- + ' · **只填你这次确实要用的字段**。可选字段不要用 ""、0、{} 之类的默认值占位 ——\n'
163
- + ' 留空不填即可;填了占位值反而会被当成"你要用它"而触发校验。\n'
164
- + ' · 枚举字段只能取列出的值;数值字段注意上下限。\n'
165
- + ' · 改完直接重发这次调用,不要因为这个错误就换一条完全不同的路子。',
177
+ error: `工具 ${name} 参数校验失败,**请按下面逐条改正后重新调用**:\n${issues}\n\n通用修法:\n · **只填你这次确实要用的字段**。可选字段不要用 ""、0、{} 之类的默认值占位 ——\n 留空不填即可;填了占位值反而会被当成"你要用它"而触发校验。\n · 枚举字段只能取列出的值;数值字段注意上下限。\n · 改完直接重发这次调用,不要因为这个错误就换一条完全不同的路子。`,
166
178
  };
167
179
  }
168
180
  // 4. 调用 call(),捕获意外异常
@@ -180,16 +192,22 @@ export async function executeTool(name, rawArguments, signal, ctx) {
180
192
  }
181
193
  }
182
194
  // 导出每个工具,方便测试单独 import
183
- export { readTool, editTool, writeTool, globTool, grepTool, webSearchTool, webfetchTool, webbrowserTool, computerUseTool, downloadTool, presentResultTool, bashTool, askUserQuestionTool };
195
+ export { readTool, editTool, writeTool, globTool, grepTool, webSearchTool, webfetchTool, webbrowserTool, computerUseTool, downloadTool, presentResultTool, bashTool, askUserQuestionTool, };
184
196
  export { clearPersonaTool, confirmMemoryTool, forgetMemoryTool, listMemoriesTool, recallMemoryTool, rememberMemoryTool, reviewMemoriesTool, searchConversationsTool, setPersonaTool, updateMemoryTool, } from './memory/memory.js';
185
197
  export { multiEditTool } from './edit/multi-edit.js';
186
198
  export { genImageTool } from './genimage/genimage.js';
187
199
  export { advisorTool } from './advisor/advisor.js';
188
200
  export { agentTool } from './agent/agent.js';
189
- export { createGenerateSpeechTool, generateSpeechTool } from './genspeech/genspeech.js';
201
+ export { createGenerateSpeechTool, generateSpeechTool, } from './genspeech/genspeech.js';
190
202
  export { createWebSearchTool } from './websearch/websearch.js';
191
203
  export { lspTool } from './lsp/lsp.js';
192
204
  export { notebookEditTool } from './notebook/notebookEdit.js';
193
205
  export { powerShellTool } from './powershell/powershell.js';
194
206
  export { taskOutputTool } from './tasks/taskOutput.js';
195
207
  export { taskStopTool } from './tasks/taskStop.js';
208
+ export { taskCreateTool, taskGetTool, taskUpdateTool, taskListTool, } from './tasks/taskManagement.js';
209
+ export { trashTool } from './trash/trash.js';
210
+ export { skillTool } from './skill/skill.js';
211
+ export { snipTool } from './snip/snip.js';
212
+ export { enterWorktreeTool, exitWorktreeTool, } from './worktree/sessionWorktree.js';
213
+ export { terminalCaptureTool, installTerminalCapture, } from './terminal/terminalCapture.js';
@@ -21,6 +21,8 @@ import { advisorTool } from './advisor/advisor.js';
21
21
  import { agentTool } from './agent/agent.js';
22
22
  import { askUserQuestionTool } from './ask/ask.js';
23
23
  import { bashTool } from './bash/bash.js';
24
+ import { assertCapabilityRegistry } from './capabilities.js';
25
+ import { computerUseTool } from './computeruse/computeruse.js';
24
26
  import { downloadTool } from './download/download.js';
25
27
  import { editTool } from './edit/edit.js';
26
28
  import { multiEditTool } from './edit/multi-edit.js';
@@ -28,8 +30,7 @@ import { genImageTool } from './genimage/genimage.js';
28
30
  import { generateSpeechTool } from './genspeech/genspeech.js';
29
31
  import { globTool } from './glob/glob.js';
30
32
  import { grepTool } from './grep/grep.js';
31
- import { readTool } from './read/read.js';
32
- import { presentResultTool } from './presentresult/presentresult.js';
33
+ import { lspTool } from './lsp/lsp.js';
33
34
  import {
34
35
  clearPersonaTool,
35
36
  confirmMemoryTool,
@@ -42,17 +43,30 @@ import {
42
43
  setPersonaTool,
43
44
  updateMemoryTool,
44
45
  } from './memory/memory.js';
45
- import { webfetchTool } from './webfetch/webfetch.js';
46
- import { webbrowserTool } from './webbrowser/webbrowser.js';
47
- import { webSearchTool } from './websearch/websearch.js';
48
- import { writeTool } from './write/write.js';
49
- import { computerUseTool } from './computeruse/computeruse.js';
50
- import { assertCapabilityRegistry } from './capabilities.js';
51
- import { lspTool } from './lsp/lsp.js';
52
46
  import { notebookEditTool } from './notebook/notebookEdit.js';
53
47
  import { powerShellTool } from './powershell/powershell.js';
48
+ import { presentResultTool } from './presentresult/presentresult.js';
49
+ import { readTool } from './read/read.js';
50
+ import { skillTool } from './skill/skill.js';
51
+ import { snipTool } from './snip/snip.js';
52
+ import {
53
+ taskCreateTool,
54
+ taskGetTool,
55
+ taskListTool,
56
+ taskUpdateTool,
57
+ } from './tasks/taskManagement.js';
54
58
  import { taskOutputTool } from './tasks/taskOutput.js';
55
59
  import { taskStopTool } from './tasks/taskStop.js';
60
+ import { terminalCaptureTool } from './terminal/terminalCapture.js';
61
+ import { trashTool } from './trash/trash.js';
62
+ import { webbrowserTool } from './webbrowser/webbrowser.js';
63
+ import { webfetchTool } from './webfetch/webfetch.js';
64
+ import { webSearchTool } from './websearch/websearch.js';
65
+ import {
66
+ enterWorktreeTool,
67
+ exitWorktreeTool,
68
+ } from './worktree/sessionWorktree.js';
69
+ import { writeTool } from './write/write.js';
56
70
 
57
71
  /** 所有内置工具(顺序 = 给 LLM 呈现的顺序,不影响代码执行,但会影响模型的优先级直觉) */
58
72
  export const ALL_TOOLS: Tool[] = [
@@ -90,6 +104,17 @@ export const ALL_TOOLS: Tool[] = [
90
104
  computerUseTool,
91
105
  // 追加在末尾:主循环 tools schema 的原有前缀字节不动(提示词缓存友好)
92
106
  agentTool,
107
+ // Product tools append at the end to preserve the existing schema prefix cache.
108
+ trashTool,
109
+ taskCreateTool,
110
+ taskGetTool,
111
+ taskUpdateTool,
112
+ taskListTool,
113
+ skillTool,
114
+ enterWorktreeTool,
115
+ exitWorktreeTool,
116
+ terminalCaptureTool,
117
+ snipTool,
93
118
  ];
94
119
 
95
120
  assertCapabilityRegistry(ALL_TOOLS.map((tool) => tool.name));
@@ -103,7 +128,14 @@ export function getToolGateDetails(
103
128
  name: string,
104
129
  rawArguments: string,
105
130
  context: ToolCallContext,
106
- ): Partial<Pick<import('../toolGate.js').ToolGateRequest, 'isReadOnly' | 'runContext' | 'action'>> | undefined {
131
+ ):
132
+ | Partial<
133
+ Pick<
134
+ import('../toolGate.js').ToolGateRequest,
135
+ 'isReadOnly' | 'runContext' | 'action'
136
+ >
137
+ >
138
+ | undefined {
107
139
  const tool = getToolByName(name);
108
140
  if (!tool?.gateRequest) return undefined;
109
141
  let parsed: unknown;
@@ -182,20 +214,15 @@ export async function executeTool(
182
214
  .join('\n');
183
215
  return {
184
216
  ok: false,
185
- error:
186
- `工具 ${name} 参数校验失败,**请按下面逐条改正后重新调用**:\n${issues}\n\n`
187
- + '通用修法:\n'
188
- + ' · **只填你这次确实要用的字段**。可选字段不要用 ""、0、{} 之类的默认值占位 ——\n'
189
- + ' 留空不填即可;填了占位值反而会被当成"你要用它"而触发校验。\n'
190
- + ' · 枚举字段只能取列出的值;数值字段注意上下限。\n'
191
- + ' · 改完直接重发这次调用,不要因为这个错误就换一条完全不同的路子。',
217
+ error: `工具 ${name} 参数校验失败,**请按下面逐条改正后重新调用**:\n${issues}\n\n通用修法:\n · **只填你这次确实要用的字段**。可选字段不要用 ""、0、{} 之类的默认值占位 ——\n 留空不填即可;填了占位值反而会被当成"你要用它"而触发校验。\n · 枚举字段只能取列出的值;数值字段注意上下限。\n · 改完直接重发这次调用,不要因为这个错误就换一条完全不同的路子。`,
192
218
  };
193
219
  }
194
220
 
195
221
  // 4. 调用 call(),捕获意外异常
196
222
  //
197
223
  try {
198
- if (tool.callWithContext) return await tool.callWithContext(checked.data, signal, ctx ?? {});
224
+ if (tool.callWithContext)
225
+ return await tool.callWithContext(checked.data, signal, ctx ?? {});
199
226
  return await tool.call(checked.data, signal);
200
227
  } catch (e) {
201
228
  return {
@@ -206,7 +233,21 @@ export async function executeTool(
206
233
  }
207
234
 
208
235
  // 导出每个工具,方便测试单独 import
209
- export { readTool, editTool, writeTool, globTool, grepTool, webSearchTool, webfetchTool, webbrowserTool, computerUseTool, downloadTool, presentResultTool, bashTool, askUserQuestionTool };
236
+ export {
237
+ readTool,
238
+ editTool,
239
+ writeTool,
240
+ globTool,
241
+ grepTool,
242
+ webSearchTool,
243
+ webfetchTool,
244
+ webbrowserTool,
245
+ computerUseTool,
246
+ downloadTool,
247
+ presentResultTool,
248
+ bashTool,
249
+ askUserQuestionTool,
250
+ };
210
251
  export {
211
252
  clearPersonaTool,
212
253
  confirmMemoryTool,
@@ -223,10 +264,30 @@ export { multiEditTool } from './edit/multi-edit.js';
223
264
  export { genImageTool } from './genimage/genimage.js';
224
265
  export { advisorTool } from './advisor/advisor.js';
225
266
  export { agentTool } from './agent/agent.js';
226
- export { createGenerateSpeechTool, generateSpeechTool } from './genspeech/genspeech.js';
267
+ export {
268
+ createGenerateSpeechTool,
269
+ generateSpeechTool,
270
+ } from './genspeech/genspeech.js';
227
271
  export { createWebSearchTool } from './websearch/websearch.js';
228
272
  export { lspTool } from './lsp/lsp.js';
229
273
  export { notebookEditTool } from './notebook/notebookEdit.js';
230
274
  export { powerShellTool } from './powershell/powershell.js';
231
275
  export { taskOutputTool } from './tasks/taskOutput.js';
232
276
  export { taskStopTool } from './tasks/taskStop.js';
277
+ export {
278
+ taskCreateTool,
279
+ taskGetTool,
280
+ taskUpdateTool,
281
+ taskListTool,
282
+ } from './tasks/taskManagement.js';
283
+ export { trashTool } from './trash/trash.js';
284
+ export { skillTool } from './skill/skill.js';
285
+ export { snipTool } from './snip/snip.js';
286
+ export {
287
+ enterWorktreeTool,
288
+ exitWorktreeTool,
289
+ } from './worktree/sessionWorktree.js';
290
+ export {
291
+ terminalCaptureTool,
292
+ installTerminalCapture,
293
+ } from './terminal/terminalCapture.js';