openhorse 0.2.21 → 0.2.23
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/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -1
- package/dist/commands/index.d.ts.map +1 -1
- package/dist/commands/index.js +189 -49
- package/dist/commands/index.js.map +1 -1
- package/dist/commands/parser.d.ts.map +1 -1
- package/dist/commands/parser.js +8 -3
- package/dist/commands/parser.js.map +1 -1
- package/dist/commands/types.d.ts +2 -0
- package/dist/commands/types.d.ts.map +1 -1
- package/dist/commands/types.js.map +1 -1
- package/dist/core/cost-tracker.d.ts +45 -5
- package/dist/core/cost-tracker.d.ts.map +1 -1
- package/dist/core/cost-tracker.js +78 -13
- package/dist/core/cost-tracker.js.map +1 -1
- package/dist/framework/index.d.ts +1 -1
- package/dist/framework/index.d.ts.map +1 -1
- package/dist/framework/index.js.map +1 -1
- package/dist/framework/query.d.ts +25 -0
- package/dist/framework/query.d.ts.map +1 -1
- package/dist/framework/query.js +196 -49
- package/dist/framework/query.js.map +1 -1
- package/dist/framework/store.d.ts +6 -1
- package/dist/framework/store.d.ts.map +1 -1
- package/dist/framework/store.js +10 -1
- package/dist/framework/store.js.map +1 -1
- package/dist/harness/capsule.d.ts +1 -0
- package/dist/harness/capsule.d.ts.map +1 -1
- package/dist/harness/capsule.js +38 -9
- package/dist/harness/capsule.js.map +1 -1
- package/dist/harness/contract.d.ts +2 -0
- package/dist/harness/contract.d.ts.map +1 -1
- package/dist/harness/contract.js +78 -14
- package/dist/harness/contract.js.map +1 -1
- package/dist/harness/index.d.ts +2 -2
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +4 -1
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/ledger.d.ts.map +1 -1
- package/dist/harness/ledger.js +6 -2
- package/dist/harness/ledger.js.map +1 -1
- package/dist/harness/state.d.ts.map +1 -1
- package/dist/harness/state.js +37 -7
- package/dist/harness/state.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.d.ts.map +1 -1
- package/dist/ink-ui/components/StatusLine.js +0 -2
- package/dist/ink-ui/components/StatusLine.js.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
- package/dist/ink-ui/screens/ReplScreen.js +12 -5
- package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
- package/dist/runtime/agent-runtime-controller.d.ts.map +1 -1
- package/dist/runtime/agent-runtime-controller.js +11 -1
- package/dist/runtime/agent-runtime-controller.js.map +1 -1
- package/dist/runtime/aggregate-tool-presenter.d.ts +13 -0
- package/dist/runtime/aggregate-tool-presenter.d.ts.map +1 -0
- package/dist/runtime/aggregate-tool-presenter.js +44 -0
- package/dist/runtime/aggregate-tool-presenter.js.map +1 -0
- package/dist/runtime/chat-controller.d.ts +9 -2
- package/dist/runtime/chat-controller.d.ts.map +1 -1
- package/dist/runtime/chat-controller.js +345 -90
- package/dist/runtime/chat-controller.js.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts +1 -1
- package/dist/runtime/rich-text/ansi-parser.d.ts.map +1 -1
- package/dist/runtime/rich-text/ansi-parser.js +93 -55
- package/dist/runtime/rich-text/ansi-parser.js.map +1 -1
- package/dist/runtime/rich-text/layout.d.ts +2 -11
- package/dist/runtime/rich-text/layout.d.ts.map +1 -1
- package/dist/runtime/rich-text/layout.js +280 -245
- package/dist/runtime/rich-text/layout.js.map +1 -1
- package/dist/runtime/rich-text/markdown-parser.js +31 -24
- package/dist/runtime/rich-text/markdown-parser.js.map +1 -1
- package/dist/runtime/rich-text/types.d.ts +1 -1
- package/dist/runtime/rich-text/types.d.ts.map +1 -1
- package/dist/runtime/subagents/production.d.ts.map +1 -1
- package/dist/runtime/subagents/production.js +28 -3
- package/dist/runtime/subagents/production.js.map +1 -1
- package/dist/runtime/subagents/result-parser.d.ts.map +1 -1
- package/dist/runtime/subagents/result-parser.js +54 -40
- package/dist/runtime/subagents/result-parser.js.map +1 -1
- package/dist/runtime/subagents/types.d.ts +2 -0
- package/dist/runtime/subagents/types.d.ts.map +1 -1
- package/dist/runtime/subagents/types.js +5 -1
- package/dist/runtime/subagents/types.js.map +1 -1
- package/dist/runtime/tool-detail-repository.d.ts +45 -0
- package/dist/runtime/tool-detail-repository.d.ts.map +1 -0
- package/dist/runtime/tool-detail-repository.js +131 -0
- package/dist/runtime/tool-detail-repository.js.map +1 -0
- package/dist/runtime/tool-output-presentation.d.ts +89 -0
- package/dist/runtime/tool-output-presentation.d.ts.map +1 -0
- package/dist/runtime/tool-output-presentation.js +329 -0
- package/dist/runtime/tool-output-presentation.js.map +1 -0
- package/dist/runtime/ui-events.d.ts +17 -0
- package/dist/runtime/ui-events.d.ts.map +1 -1
- package/dist/runtime/ui-events.js.map +1 -1
- package/dist/runtime/ui-view-model.d.ts +9 -0
- package/dist/runtime/ui-view-model.d.ts.map +1 -1
- package/dist/runtime/ui-view-model.js +59 -37
- package/dist/runtime/ui-view-model.js.map +1 -1
- package/dist/services/compact/auto-compact.d.ts +15 -2
- package/dist/services/compact/auto-compact.d.ts.map +1 -1
- package/dist/services/compact/auto-compact.js +56 -24
- package/dist/services/compact/auto-compact.js.map +1 -1
- package/dist/services/compact/compact.d.ts +2 -0
- package/dist/services/compact/compact.d.ts.map +1 -1
- package/dist/services/compact/compact.js +22 -5
- package/dist/services/compact/compact.js.map +1 -1
- package/dist/services/compact/coordinator.d.ts +26 -0
- package/dist/services/compact/coordinator.d.ts.map +1 -0
- package/dist/services/compact/coordinator.js +44 -0
- package/dist/services/compact/coordinator.js.map +1 -0
- package/dist/services/compact/index.d.ts +1 -0
- package/dist/services/compact/index.d.ts.map +1 -1
- package/dist/services/compact/index.js +3 -1
- package/dist/services/compact/index.js.map +1 -1
- package/dist/services/compact/summary-generator.d.ts +6 -2
- package/dist/services/compact/summary-generator.d.ts.map +1 -1
- package/dist/services/compact/summary-generator.js +73 -31
- package/dist/services/compact/summary-generator.js.map +1 -1
- package/dist/services/config-dir.d.ts +11 -1
- package/dist/services/config-dir.d.ts.map +1 -1
- package/dist/services/config-dir.js +19 -2
- package/dist/services/config-dir.js.map +1 -1
- package/dist/services/config.d.ts +4 -2
- package/dist/services/config.d.ts.map +1 -1
- package/dist/services/config.js +40 -0
- package/dist/services/config.js.map +1 -1
- package/dist/services/doctor.d.ts +2 -0
- package/dist/services/doctor.d.ts.map +1 -1
- package/dist/services/doctor.js +8 -1
- package/dist/services/doctor.js.map +1 -1
- package/dist/services/global-config.d.ts +10 -0
- package/dist/services/global-config.d.ts.map +1 -1
- package/dist/services/global-config.js.map +1 -1
- package/dist/services/llm.d.ts +21 -4
- package/dist/services/llm.d.ts.map +1 -1
- package/dist/services/llm.js +66 -8
- package/dist/services/llm.js.map +1 -1
- package/dist/services/model-context.d.ts +36 -0
- package/dist/services/model-context.d.ts.map +1 -1
- package/dist/services/model-context.js +245 -32
- package/dist/services/model-context.js.map +1 -1
- package/dist/services/redaction.js +1 -1
- package/dist/services/redaction.js.map +1 -1
- package/dist/services/session-storage.d.ts +42 -1
- package/dist/services/session-storage.d.ts.map +1 -1
- package/dist/services/session-storage.js +175 -54
- package/dist/services/session-storage.js.map +1 -1
- package/dist/services/storage-maintenance.d.ts.map +1 -1
- package/dist/services/storage-maintenance.js +3 -2
- package/dist/services/storage-maintenance.js.map +1 -1
- package/dist/services/usage-state.d.ts +55 -5
- package/dist/services/usage-state.d.ts.map +1 -1
- package/dist/services/usage-state.js +185 -59
- package/dist/services/usage-state.js.map +1 -1
- package/dist/services/verification-profile.d.ts.map +1 -1
- package/dist/services/verification-profile.js +3 -2
- package/dist/services/verification-profile.js.map +1 -1
- package/dist/services/workspace-diff.d.ts.map +1 -1
- package/dist/services/workspace-diff.js +34 -3
- package/dist/services/workspace-diff.js.map +1 -1
- package/dist/services/yaml-config.js +1 -1
- package/dist/skills/runtime.d.ts +9 -5
- package/dist/skills/runtime.d.ts.map +1 -1
- package/dist/skills/runtime.js +157 -12
- package/dist/skills/runtime.js.map +1 -1
- package/dist/terminal-ui/editor.d.ts.map +1 -1
- package/dist/terminal-ui/editor.js +14 -3
- package/dist/terminal-ui/editor.js.map +1 -1
- package/dist/terminal-ui/launch.d.ts +21 -0
- package/dist/terminal-ui/launch.d.ts.map +1 -1
- package/dist/terminal-ui/launch.js +203 -45
- package/dist/terminal-ui/launch.js.map +1 -1
- package/dist/terminal-ui/output-queue.d.ts +43 -0
- package/dist/terminal-ui/output-queue.d.ts.map +1 -0
- package/dist/terminal-ui/output-queue.js +139 -0
- package/dist/terminal-ui/output-queue.js.map +1 -0
- package/dist/terminal-ui/raw-editor.d.ts +42 -0
- package/dist/terminal-ui/raw-editor.d.ts.map +1 -1
- package/dist/terminal-ui/raw-editor.js +337 -41
- package/dist/terminal-ui/raw-editor.js.map +1 -1
- package/dist/tools/bash_security.d.ts.map +1 -1
- package/dist/tools/bash_security.js +14 -5
- package/dist/tools/bash_security.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +176 -73
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/plan.d.ts.map +1 -1
- package/dist/tools/plan.js +7 -0
- package/dist/tools/plan.js.map +1 -1
- package/dist/tools/web.d.ts +10 -0
- package/dist/tools/web.d.ts.map +1 -1
- package/dist/tools/web.js +81 -1
- package/dist/tools/web.js.map +1 -1
- package/dist/tui-core/input-parser.d.ts +9 -2
- package/dist/tui-core/input-parser.d.ts.map +1 -1
- package/dist/tui-core/input-parser.js +57 -3
- package/dist/tui-core/input-parser.js.map +1 -1
- package/dist/tui-core/style.d.ts +16 -0
- package/dist/tui-core/style.d.ts.map +1 -1
- package/dist/tui-core/style.js +22 -1
- package/dist/tui-core/style.js.map +1 -1
- package/dist/tui-ui/inline-surface.d.ts +69 -12
- package/dist/tui-ui/inline-surface.d.ts.map +1 -1
- package/dist/tui-ui/inline-surface.js +366 -94
- package/dist/tui-ui/inline-surface.js.map +1 -1
- package/dist/tui-ui/input-ownership.d.ts +46 -0
- package/dist/tui-ui/input-ownership.d.ts.map +1 -0
- package/dist/tui-ui/input-ownership.js +74 -0
- package/dist/tui-ui/input-ownership.js.map +1 -0
- package/dist/tui-ui/launch.d.ts +2 -0
- package/dist/tui-ui/launch.d.ts.map +1 -1
- package/dist/tui-ui/launch.js +289 -43
- package/dist/tui-ui/launch.js.map +1 -1
- package/dist/tui-ui/layout.d.ts +52 -2
- package/dist/tui-ui/layout.d.ts.map +1 -1
- package/dist/tui-ui/layout.js +230 -76
- package/dist/tui-ui/layout.js.map +1 -1
- package/dist/tui-ui/runner.d.ts +101 -8
- package/dist/tui-ui/runner.d.ts.map +1 -1
- package/dist/tui-ui/runner.js +843 -51
- package/dist/tui-ui/runner.js.map +1 -1
- package/dist/tui-ui/state.d.ts +70 -4
- package/dist/tui-ui/state.d.ts.map +1 -1
- package/dist/tui-ui/state.js +251 -20
- package/dist/tui-ui/state.js.map +1 -1
- package/dist/tui-ui/theme-profile.d.ts +25 -0
- package/dist/tui-ui/theme-profile.d.ts.map +1 -0
- package/dist/tui-ui/theme-profile.js +130 -0
- package/dist/tui-ui/theme-profile.js.map +1 -0
- package/dist/tui-ui/theme.d.ts +13 -0
- package/dist/tui-ui/theme.d.ts.map +1 -0
- package/dist/tui-ui/theme.js +20 -0
- package/dist/tui-ui/theme.js.map +1 -0
- package/dist/tui-ui/transcript-cache.d.ts +5 -3
- package/dist/tui-ui/transcript-cache.d.ts.map +1 -1
- package/dist/tui-ui/transcript-cache.js +16 -9
- package/dist/tui-ui/transcript-cache.js.map +1 -1
- package/dist/tui-ui/transcript-inspector-layout.d.ts +9 -0
- package/dist/tui-ui/transcript-inspector-layout.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector-layout.js +97 -0
- package/dist/tui-ui/transcript-inspector-layout.js.map +1 -0
- package/dist/tui-ui/transcript-inspector-surface.d.ts +18 -0
- package/dist/tui-ui/transcript-inspector-surface.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector-surface.js +88 -0
- package/dist/tui-ui/transcript-inspector-surface.js.map +1 -0
- package/dist/tui-ui/transcript-inspector.d.ts +35 -0
- package/dist/tui-ui/transcript-inspector.d.ts.map +1 -0
- package/dist/tui-ui/transcript-inspector.js +128 -0
- package/dist/tui-ui/transcript-inspector.js.map +1 -0
- package/dist/tui-ui/transcript-layout.d.ts +22 -0
- package/dist/tui-ui/transcript-layout.d.ts.map +1 -0
- package/dist/tui-ui/transcript-layout.js +439 -0
- package/dist/tui-ui/transcript-layout.js.map +1 -0
- package/dist/ui/status-bar.d.ts +1 -1
- package/dist/ui/status-bar.d.ts.map +1 -1
- package/dist/ui/status-bar.js +2 -15
- package/dist/ui/status-bar.js.map +1 -1
- package/dist/ui-v2/components/shell.d.ts.map +1 -1
- package/dist/ui-v2/components/shell.js +0 -8
- package/dist/ui-v2/components/shell.js.map +1 -1
- package/package.json +1 -1
|
@@ -195,15 +195,24 @@ function isReadOnlyCommand(cmd) {
|
|
|
195
195
|
// Check if command starts with a read-only command
|
|
196
196
|
const baseCmd = trimmedCmd.split(' ')[0];
|
|
197
197
|
if (exports.READ_ONLY_COMMANDS.includes(baseCmd)) {
|
|
198
|
-
// Additional checks for commands that might modify files
|
|
198
|
+
// Additional checks for commands that might modify files or execute code.
|
|
199
199
|
if (baseCmd === 'sed' && trimmedCmd.includes('-i')) {
|
|
200
200
|
return false; // sed -i modifies files
|
|
201
201
|
}
|
|
202
|
-
if (baseCmd === 'curl' && trimmedCmd.includes('>')) {
|
|
203
|
-
return false; // curl with output
|
|
202
|
+
if (baseCmd === 'curl' && (trimmedCmd.includes('>') || /(^|\s)-o\b/.test(trimmedCmd) || /(^|\s)--output\b/.test(trimmedCmd))) {
|
|
203
|
+
return false; // curl with file output (-o/--output/>) writes a file
|
|
204
204
|
}
|
|
205
|
-
if (baseCmd === 'wget' &&
|
|
206
|
-
return false; // wget
|
|
205
|
+
if (baseCmd === 'wget' && (trimmedCmd.includes('>') || /(^|\s)-O\b/.test(trimmedCmd) || /(^|\s)--output-document\b/.test(trimmedCmd))) {
|
|
206
|
+
return false; // wget with file output writes a file
|
|
207
|
+
}
|
|
208
|
+
if (baseCmd === 'find' && /(^|\s)-(exec|execdir|ok|okdir|delete)\b/.test(trimmedCmd)) {
|
|
209
|
+
return false; // find -exec/-ok runs arbitrary commands; -delete removes files
|
|
210
|
+
}
|
|
211
|
+
if (baseCmd === 'awk' && (/\bsystem\s*\(/.test(trimmedCmd) || /\bgetline\b/.test(trimmedCmd) || trimmedCmd.includes('>'))) {
|
|
212
|
+
return false; // awk can exec (system/getline) or write files (>)
|
|
213
|
+
}
|
|
214
|
+
if (baseCmd === 'sort' && (/(^|\s)-o\b/.test(trimmedCmd) || trimmedCmd.includes('>'))) {
|
|
215
|
+
return false; // sort -o / redirect writes a file
|
|
207
216
|
}
|
|
208
217
|
return true;
|
|
209
218
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bash_security.js","sourceRoot":"","sources":["../../src/tools/bash_security.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;AAmMH,
|
|
1
|
+
{"version":3,"file":"bash_security.js","sourceRoot":"","sources":["../../src/tools/bash_security.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/tools/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAaH,OAAO,EAEL,KAAK,aAAa,EAElB,KAAK,WAAW,EACjB,MAAM,mBAAmB,CAAC;AAsD3B,eAAO,MAAM,KAAK,EAAE,aAAa,EAmxBhC,CAAC;AAEF;;;;;;GAMG;AACH,wBAAgB,eAAe,IAAI,aAAa,EAAE,CAEjD;AAqZD,MAAM,WAAW,oBAAoB;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,OAAO,CAAC;CACvB;AAmrBD;;;GAGG;AACH,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,WAAW,CAAC,EAAE,WAAW,EACzB,WAAW,CAAC,EAAE,WAAW,GACxB,OAAO,CAAC,MAAM,CAAC,CAmDjB;AAcD;;GAEG;AACH,wBAAgB,YAAY,IAAI,MAAM,CAIrC;AAGD,OAAO,EACL,kBAAkB,EAClB,kBAAkB,EAClB,gCAAgC,EAChC,iBAAiB,EACjB,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,cAAc,EACd,KAAK,cAAc,EACnB,uBAAuB,GACxB,MAAM,iBAAiB,CAAC"}
|
package/dist/tools/index.js
CHANGED
|
@@ -75,7 +75,7 @@ exports.TOOLS = [
|
|
|
75
75
|
// File tools
|
|
76
76
|
(0, tool_1.buildTool)({
|
|
77
77
|
name: 'read_file',
|
|
78
|
-
description: '
|
|
78
|
+
description: '读取文件内容,支持从指定行开始分页。返回文件内容字符串。',
|
|
79
79
|
parameters: {
|
|
80
80
|
type: 'object',
|
|
81
81
|
properties: {
|
|
@@ -87,6 +87,10 @@ exports.TOOLS = [
|
|
|
87
87
|
type: 'number',
|
|
88
88
|
description: '最大读取行数(可选,默认 500 行)',
|
|
89
89
|
},
|
|
90
|
+
offset: {
|
|
91
|
+
type: 'number',
|
|
92
|
+
description: '开始读取的行号(可选,1-based,默认第 1 行)',
|
|
93
|
+
},
|
|
90
94
|
},
|
|
91
95
|
required: ['path'],
|
|
92
96
|
},
|
|
@@ -96,11 +100,19 @@ exports.TOOLS = [
|
|
|
96
100
|
if (!path || typeof path !== 'string') {
|
|
97
101
|
return { success: false, output: '', error: 'read_file requires a path parameter' };
|
|
98
102
|
}
|
|
99
|
-
|
|
103
|
+
const maxLines = readPositiveInteger(args.maxLines, 'maxLines', 500);
|
|
104
|
+
if (typeof maxLines === 'string') {
|
|
105
|
+
return { success: false, output: '', error: maxLines };
|
|
106
|
+
}
|
|
107
|
+
const offset = readPositiveInteger(args.offset, 'offset', 1);
|
|
108
|
+
if (typeof offset === 'string') {
|
|
109
|
+
return { success: false, output: '', error: offset };
|
|
110
|
+
}
|
|
111
|
+
return readFileSync_(path, maxLines, offset, context.cwd);
|
|
100
112
|
},
|
|
101
113
|
isReadOnly: () => true,
|
|
102
114
|
isConcurrencySafe: () => true,
|
|
103
|
-
userFacingName:
|
|
115
|
+
userFacingName: args => `Read ${args.path}`,
|
|
104
116
|
getSummary: (args, result) => {
|
|
105
117
|
const path = args.path;
|
|
106
118
|
if (!result.success)
|
|
@@ -144,7 +156,7 @@ exports.TOOLS = [
|
|
|
144
156
|
// Destructive operation - ask for confirmation in default mode
|
|
145
157
|
return { behavior: 'ask', reason: 'Write operation may modify existing files' };
|
|
146
158
|
},
|
|
147
|
-
userFacingName:
|
|
159
|
+
userFacingName: args => `Write ${args.path}`,
|
|
148
160
|
getSummary: (args, result) => {
|
|
149
161
|
const path = args.path;
|
|
150
162
|
if (!result.success)
|
|
@@ -180,7 +192,7 @@ exports.TOOLS = [
|
|
|
180
192
|
},
|
|
181
193
|
isReadOnly: () => true,
|
|
182
194
|
isConcurrencySafe: () => true,
|
|
183
|
-
userFacingName:
|
|
195
|
+
userFacingName: args => `List ${args.path}`,
|
|
184
196
|
getSummary: (args, result) => {
|
|
185
197
|
const path = args.path;
|
|
186
198
|
if (!result.success)
|
|
@@ -223,7 +235,7 @@ exports.TOOLS = [
|
|
|
223
235
|
// Issue #32 #3.2: 传递 abortSignal
|
|
224
236
|
return execCommand_(command, args.cwd, args.timeout, args.maxOutput, context.abortSignal, context.cwd);
|
|
225
237
|
},
|
|
226
|
-
isDestructive:
|
|
238
|
+
isDestructive: args => {
|
|
227
239
|
const cmd = args.command || '';
|
|
228
240
|
return /(rm\s+-rf|mkfs|dd\s)/.test(cmd);
|
|
229
241
|
},
|
|
@@ -232,7 +244,10 @@ exports.TOOLS = [
|
|
|
232
244
|
// Use the bash_security module for comprehensive checks
|
|
233
245
|
const security = (0, bash_security_1.assessCommandSecurity)(cmd);
|
|
234
246
|
if (security.level === 'blocked') {
|
|
235
|
-
return {
|
|
247
|
+
return {
|
|
248
|
+
behavior: 'deny',
|
|
249
|
+
reason: security.reason || `Command blocked by safety policy: ${cmd.slice(0, 50)}`,
|
|
250
|
+
};
|
|
236
251
|
}
|
|
237
252
|
if (security.level === 'safe' && security.isReadOnly) {
|
|
238
253
|
return { behavior: 'allow' };
|
|
@@ -243,15 +258,15 @@ exports.TOOLS = [
|
|
|
243
258
|
// Default: ask for confirmation
|
|
244
259
|
return { behavior: 'ask', reason: 'Command requires confirmation' };
|
|
245
260
|
},
|
|
246
|
-
isReadOnly:
|
|
261
|
+
isReadOnly: args => {
|
|
247
262
|
const cmd = args.command || '';
|
|
248
263
|
return (0, bash_security_1.isReadOnlyCommand)(cmd);
|
|
249
264
|
},
|
|
250
|
-
isConcurrencySafe:
|
|
265
|
+
isConcurrencySafe: args => {
|
|
251
266
|
const cmd = args.command || '';
|
|
252
267
|
return (0, bash_security_1.isReadOnlyCommand)(cmd);
|
|
253
268
|
},
|
|
254
|
-
userFacingName:
|
|
269
|
+
userFacingName: args => `Exec ${compactOneLine(args.command || '', 80)}`,
|
|
255
270
|
getSummary: (args, result) => {
|
|
256
271
|
const command = args.command || '';
|
|
257
272
|
const commandSummary = command ? `\n $ ${compactOneLine(command, 160)}` : '';
|
|
@@ -327,7 +342,7 @@ exports.TOOLS = [
|
|
|
327
342
|
checkPermissions: (_args, _context) => {
|
|
328
343
|
return { behavior: 'ask', reason: 'Edit operation modifies file contents' };
|
|
329
344
|
},
|
|
330
|
-
userFacingName:
|
|
345
|
+
userFacingName: args => `Edit ${args.path}`,
|
|
331
346
|
getSummary: (args, result) => {
|
|
332
347
|
const path = args.path;
|
|
333
348
|
if (!result.success)
|
|
@@ -363,7 +378,7 @@ exports.TOOLS = [
|
|
|
363
378
|
},
|
|
364
379
|
isReadOnly: () => true,
|
|
365
380
|
isConcurrencySafe: () => true,
|
|
366
|
-
userFacingName:
|
|
381
|
+
userFacingName: args => `Glob ${args.pattern}`,
|
|
367
382
|
getSummary: (args, result) => {
|
|
368
383
|
const pattern = args.pattern;
|
|
369
384
|
if (!result.success)
|
|
@@ -407,7 +422,7 @@ exports.TOOLS = [
|
|
|
407
422
|
},
|
|
408
423
|
isReadOnly: () => true,
|
|
409
424
|
isConcurrencySafe: () => true,
|
|
410
|
-
userFacingName:
|
|
425
|
+
userFacingName: args => `Grep ${args.pattern}`,
|
|
411
426
|
getSummary: (args, result) => {
|
|
412
427
|
const pattern = args.pattern;
|
|
413
428
|
if (!result.success)
|
|
@@ -445,7 +460,7 @@ exports.TOOLS = [
|
|
|
445
460
|
execute: async (args, context) => executeBatchRead(args, context),
|
|
446
461
|
isReadOnly: () => true,
|
|
447
462
|
isConcurrencySafe: () => true,
|
|
448
|
-
userFacingName:
|
|
463
|
+
userFacingName: args => {
|
|
449
464
|
const count = Array.isArray(args.steps) ? args.steps.length : 0;
|
|
450
465
|
return `Batch read ${count} steps`;
|
|
451
466
|
},
|
|
@@ -492,7 +507,11 @@ exports.TOOLS = [
|
|
|
492
507
|
return { success: false, output: '', error: 'memory_save requires a name parameter' };
|
|
493
508
|
}
|
|
494
509
|
if (!type || !['user', 'feedback', 'project', 'reference'].includes(type)) {
|
|
495
|
-
return {
|
|
510
|
+
return {
|
|
511
|
+
success: false,
|
|
512
|
+
output: '',
|
|
513
|
+
error: 'memory_save requires a valid type: user, feedback, project, or reference',
|
|
514
|
+
};
|
|
496
515
|
}
|
|
497
516
|
if (!content || typeof content !== 'string') {
|
|
498
517
|
return { success: false, output: '', error: 'memory_save requires a content parameter' };
|
|
@@ -521,7 +540,7 @@ exports.TOOLS = [
|
|
|
521
540
|
}
|
|
522
541
|
},
|
|
523
542
|
isReadOnly: () => false,
|
|
524
|
-
userFacingName:
|
|
543
|
+
userFacingName: args => `Memory save ${args.name}`,
|
|
525
544
|
getSummary: (args, result) => {
|
|
526
545
|
const name = args.name;
|
|
527
546
|
const type = args.type;
|
|
@@ -609,7 +628,7 @@ exports.TOOLS = [
|
|
|
609
628
|
}
|
|
610
629
|
},
|
|
611
630
|
isReadOnly: () => true,
|
|
612
|
-
userFacingName:
|
|
631
|
+
userFacingName: args => `Memory recall ${args.query || 'all'}`,
|
|
613
632
|
getSummary: (args, result) => {
|
|
614
633
|
const query = args.query || 'all';
|
|
615
634
|
if (!result.success)
|
|
@@ -661,7 +680,7 @@ exports.TOOLS = [
|
|
|
661
680
|
}
|
|
662
681
|
},
|
|
663
682
|
isReadOnly: () => false,
|
|
664
|
-
userFacingName:
|
|
683
|
+
userFacingName: args => `Memory forget ${args.name}`,
|
|
665
684
|
getSummary: (args, result) => {
|
|
666
685
|
const name = args.name;
|
|
667
686
|
if (!result.success)
|
|
@@ -756,7 +775,7 @@ exports.TOOLS = [
|
|
|
756
775
|
}
|
|
757
776
|
},
|
|
758
777
|
isReadOnly: () => true,
|
|
759
|
-
userFacingName:
|
|
778
|
+
userFacingName: args => `History search ${args.query}`,
|
|
760
779
|
getSummary: (args, result) => {
|
|
761
780
|
const query = args.query;
|
|
762
781
|
if (!result.success)
|
|
@@ -808,21 +827,43 @@ function normalizeToolPath(input) {
|
|
|
808
827
|
return decodeURIComponent(new URL(value).pathname);
|
|
809
828
|
}
|
|
810
829
|
catch {
|
|
811
|
-
|
|
830
|
+
return value.replace(/^file:\/\//u, '');
|
|
812
831
|
}
|
|
813
832
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
catch {
|
|
818
|
-
return value;
|
|
819
|
-
}
|
|
833
|
+
// Plain filesystem paths are not URLs: do NOT percent-decode them, or a
|
|
834
|
+
// literal filename like "lit%41.txt" is silently rewritten to "litA.txt".
|
|
835
|
+
return value;
|
|
820
836
|
}
|
|
821
837
|
/** Resolve tool path parameters relative to the current tool cwd. */
|
|
822
838
|
function safePath(input, cwd = process.cwd()) {
|
|
823
839
|
return (0, path_1.resolve)(cwd, normalizeToolPath(input));
|
|
824
840
|
}
|
|
825
|
-
|
|
841
|
+
/**
|
|
842
|
+
* Truncate text to at most maxBytes UTF-8 bytes, cutting on a character
|
|
843
|
+
* boundary (never inside a multi-byte sequence or surrogate pair). Returns the
|
|
844
|
+
* truncated text and the byte length it was cut at. String.slice counts UTF-16
|
|
845
|
+
* code units, not bytes, so it is wrong for enforcing a byte budget on CJK or
|
|
846
|
+
* emoji content and can split a surrogate pair.
|
|
847
|
+
*/
|
|
848
|
+
function truncateToBytes(text, maxBytes) {
|
|
849
|
+
const buf = Buffer.from(text, 'utf-8');
|
|
850
|
+
if (buf.length <= maxBytes)
|
|
851
|
+
return { text, bytes: buf.length };
|
|
852
|
+
let cut = maxBytes;
|
|
853
|
+
// Walk back past UTF-8 continuation bytes (0x80-0xBF) to a lead-byte boundary.
|
|
854
|
+
while (cut > 0 && (buf[cut] & 0xc0) === 0x80)
|
|
855
|
+
cut--;
|
|
856
|
+
return { text: buf.subarray(0, cut).toString('utf-8'), bytes: cut };
|
|
857
|
+
}
|
|
858
|
+
function readPositiveInteger(value, name, defaultValue) {
|
|
859
|
+
if (value === undefined)
|
|
860
|
+
return defaultValue;
|
|
861
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
|
|
862
|
+
return `read_file ${name} must be a positive integer`;
|
|
863
|
+
}
|
|
864
|
+
return value;
|
|
865
|
+
}
|
|
866
|
+
async function readFileSync_(path, maxLines, offset, cwd) {
|
|
826
867
|
try {
|
|
827
868
|
const normalizedPath = normalizeToolPath(path);
|
|
828
869
|
const resolved = safePath(path, cwd);
|
|
@@ -830,30 +871,48 @@ async function readFileSync_(path, maxLines, cwd) {
|
|
|
830
871
|
return { success: false, output: '', error: `File not found: ${normalizedPath}` };
|
|
831
872
|
}
|
|
832
873
|
if ((0, fs_1.statSync)(resolved).isDirectory()) {
|
|
833
|
-
return {
|
|
874
|
+
return {
|
|
875
|
+
success: false,
|
|
876
|
+
output: '',
|
|
877
|
+
error: `Path is a directory, not a file: ${normalizedPath}`,
|
|
878
|
+
};
|
|
834
879
|
}
|
|
835
880
|
const content = (0, fs_1.readFileSync)(resolved, 'utf-8');
|
|
836
881
|
const lines = content.split('\n');
|
|
837
|
-
const limit = maxLines ?? 500;
|
|
838
882
|
const maxBytes = 51200; // 50KB byte limit
|
|
839
|
-
if (lines.length
|
|
840
|
-
const truncated = lines.slice(0, limit).join('\n');
|
|
841
|
-
const byteLen = Buffer.byteLength(truncated, 'utf8');
|
|
842
|
-
const notice = `\n\n[... truncated, ${lines.length - limit} more lines]`;
|
|
883
|
+
if (offset > lines.length) {
|
|
843
884
|
return {
|
|
844
|
-
success:
|
|
845
|
-
output:
|
|
885
|
+
success: false,
|
|
886
|
+
output: '',
|
|
887
|
+
error: `read_file offset ${offset} is beyond the file (${lines.length} lines)`,
|
|
846
888
|
};
|
|
847
889
|
}
|
|
848
|
-
|
|
849
|
-
const
|
|
890
|
+
const startIndex = offset - 1;
|
|
891
|
+
const selectedLines = lines.slice(startIndex, startIndex + maxLines);
|
|
892
|
+
const selected = selectedLines.join('\n');
|
|
893
|
+
const remainingLines = Math.max(0, lines.length - startIndex - selectedLines.length);
|
|
894
|
+
if (remainingLines > 0) {
|
|
895
|
+
const byteLen = Buffer.byteLength(selected, 'utf8');
|
|
896
|
+
const notice = `\n\n[... truncated, ${remainingLines} more lines; showing lines ${offset}-${offset + selectedLines.length - 1} of ${lines.length}]`;
|
|
897
|
+
if (byteLen > maxBytes) {
|
|
898
|
+
const cut = truncateToBytes(selected, maxBytes);
|
|
899
|
+
return {
|
|
900
|
+
success: true,
|
|
901
|
+
output: cut.text + `\n\n[... truncated at ${cut.bytes}B]`,
|
|
902
|
+
};
|
|
903
|
+
}
|
|
904
|
+
return { success: true, output: selected + notice };
|
|
905
|
+
}
|
|
906
|
+
// Also apply byte limit to the selected page.
|
|
907
|
+
const byteLen = Buffer.byteLength(selected, 'utf8');
|
|
850
908
|
if (byteLen > maxBytes) {
|
|
909
|
+
const cut = truncateToBytes(selected, maxBytes);
|
|
851
910
|
return {
|
|
852
911
|
success: true,
|
|
853
|
-
output:
|
|
912
|
+
output: cut.text + `\n\n[... truncated at ${cut.bytes}B of ${byteLen}B]`,
|
|
854
913
|
};
|
|
855
914
|
}
|
|
856
|
-
return { success: true, output:
|
|
915
|
+
return { success: true, output: selected };
|
|
857
916
|
}
|
|
858
917
|
catch (err) {
|
|
859
918
|
return { success: false, output: '', error: String(err.message) };
|
|
@@ -864,7 +923,10 @@ async function writeFileSync_(path, content, cwd) {
|
|
|
864
923
|
const normalizedPath = normalizeToolPath(path);
|
|
865
924
|
const resolved = safePath(path, cwd);
|
|
866
925
|
(0, fs_1.writeFileSync)(resolved, content, 'utf-8');
|
|
867
|
-
return {
|
|
926
|
+
return {
|
|
927
|
+
success: true,
|
|
928
|
+
output: `Wrote ${content.split('\n').length} lines to ${normalizedPath}`,
|
|
929
|
+
};
|
|
868
930
|
}
|
|
869
931
|
catch (err) {
|
|
870
932
|
return { success: false, output: '', error: String(err.message) };
|
|
@@ -908,14 +970,15 @@ async function listFiles_(path, maxDepth, cwd) {
|
|
|
908
970
|
// Limit output to 500 entries
|
|
909
971
|
const maxEntries = 500;
|
|
910
972
|
const output = results.length > maxEntries
|
|
911
|
-
? results.slice(0, maxEntries).join('\n') +
|
|
973
|
+
? results.slice(0, maxEntries).join('\n') +
|
|
974
|
+
`\n\n[... truncated, ${results.length - maxEntries} more entries]`
|
|
912
975
|
: results.join('\n');
|
|
913
976
|
return { success: true, output };
|
|
914
977
|
}
|
|
915
978
|
// Issue #32 #3.2: execCommand_ 支持 abortSignal
|
|
916
979
|
async function execCommand_(command, cwd, timeout, maxOutput, abortSignal, baseCwd) {
|
|
917
|
-
return new Promise(
|
|
918
|
-
const workdir = cwd ? safePath(cwd, baseCwd) : baseCwd ?? process.cwd();
|
|
980
|
+
return new Promise(resolve => {
|
|
981
|
+
const workdir = cwd ? safePath(cwd, baseCwd) : (baseCwd ?? process.cwd());
|
|
919
982
|
const timeoutMs = timeout ?? 30000;
|
|
920
983
|
const maxBytes = maxOutput ?? 51200; // Default 50KB, Issue #28 fix
|
|
921
984
|
// Use spawn for streaming output with truncation support
|
|
@@ -1025,7 +1088,7 @@ async function execCommand_(command, cwd, timeout, maxOutput, abortSignal, baseC
|
|
|
1025
1088
|
}
|
|
1026
1089
|
}
|
|
1027
1090
|
});
|
|
1028
|
-
child.on('close',
|
|
1091
|
+
child.on('close', code => {
|
|
1029
1092
|
if (interrupted === 'aborted') {
|
|
1030
1093
|
finish({
|
|
1031
1094
|
success: false,
|
|
@@ -1060,11 +1123,13 @@ async function execCommand_(command, cwd, timeout, maxOutput, abortSignal, baseC
|
|
|
1060
1123
|
finish({
|
|
1061
1124
|
success: true,
|
|
1062
1125
|
output: finalOutput || '(no output)',
|
|
1063
|
-
error: stderrTruncated
|
|
1126
|
+
error: stderrTruncated
|
|
1127
|
+
? errOutput + '\n\n[... stderr truncated]'
|
|
1128
|
+
: errOutput || undefined,
|
|
1064
1129
|
});
|
|
1065
1130
|
}
|
|
1066
1131
|
});
|
|
1067
|
-
child.on('error',
|
|
1132
|
+
child.on('error', err => {
|
|
1068
1133
|
finish({
|
|
1069
1134
|
success: false,
|
|
1070
1135
|
output: '',
|
|
@@ -1136,7 +1201,10 @@ function formatEditPreview(params) {
|
|
|
1136
1201
|
*/
|
|
1137
1202
|
function fuzzyMatch(content, oldString) {
|
|
1138
1203
|
// Strategy 1: Line-by-line matching (allow different indentation)
|
|
1139
|
-
const oldLines = oldString
|
|
1204
|
+
const oldLines = oldString
|
|
1205
|
+
.split('\n')
|
|
1206
|
+
.map(l => l.trim())
|
|
1207
|
+
.filter(Boolean);
|
|
1140
1208
|
const contentLines = content.split('\n');
|
|
1141
1209
|
const lineMatches = [];
|
|
1142
1210
|
for (let i = 0; i <= contentLines.length - oldLines.length; i++) {
|
|
@@ -1186,7 +1254,11 @@ async function editFile_(path, old_string, new_string, replace_all, fuzzy_match,
|
|
|
1186
1254
|
return { success: false, output: '', error: `File not found: ${normalizedPath}` };
|
|
1187
1255
|
}
|
|
1188
1256
|
if ((0, fs_1.statSync)(resolved).isDirectory()) {
|
|
1189
|
-
return {
|
|
1257
|
+
return {
|
|
1258
|
+
success: false,
|
|
1259
|
+
output: '',
|
|
1260
|
+
error: `Path is a directory, not a file: ${normalizedPath}`,
|
|
1261
|
+
};
|
|
1190
1262
|
}
|
|
1191
1263
|
const content = (0, fs_1.readFileSync)(resolved, 'utf-8');
|
|
1192
1264
|
// Check if old_string exists exactly
|
|
@@ -1224,7 +1296,11 @@ async function editFile_(path, old_string, new_string, replace_all, fuzzy_match,
|
|
|
1224
1296
|
// Try fuzzy match strategies
|
|
1225
1297
|
const fuzzyResult = fuzzyMatch(content, old_string);
|
|
1226
1298
|
if (fuzzyResult === null) {
|
|
1227
|
-
return {
|
|
1299
|
+
return {
|
|
1300
|
+
success: false,
|
|
1301
|
+
output: '',
|
|
1302
|
+
error: `old_string not found in file: ${old_string.slice(0, 100)}...`,
|
|
1303
|
+
};
|
|
1228
1304
|
}
|
|
1229
1305
|
if (preview) {
|
|
1230
1306
|
return {
|
|
@@ -1251,7 +1327,10 @@ async function editFile_(path, old_string, new_string, replace_all, fuzzy_match,
|
|
|
1251
1327
|
return {
|
|
1252
1328
|
success: false,
|
|
1253
1329
|
output: '',
|
|
1254
|
-
error: `Fuzzy match found ${fuzzyResult.matches.length} candidates. Provide a more specific string. First 3 candidates:\n${fuzzyResult.matches
|
|
1330
|
+
error: `Fuzzy match found ${fuzzyResult.matches.length} candidates. Provide a more specific string. First 3 candidates:\n${fuzzyResult.matches
|
|
1331
|
+
.slice(0, 3)
|
|
1332
|
+
.map((m, i) => ` ${i + 1}: "${m.slice(0, 80)}..."`)
|
|
1333
|
+
.join('\n')}`,
|
|
1255
1334
|
};
|
|
1256
1335
|
}
|
|
1257
1336
|
// Use the single fuzzy match only.
|
|
@@ -1305,18 +1384,26 @@ function escapeRegExp(str) {
|
|
|
1305
1384
|
*/
|
|
1306
1385
|
async function glob_(pattern, basePath, cwd) {
|
|
1307
1386
|
try {
|
|
1308
|
-
const normalizedBasePath = basePath ? normalizeToolPath(basePath) : cwd ?? process.cwd();
|
|
1309
|
-
const base = basePath ? safePath(basePath, cwd) : cwd ?? process.cwd();
|
|
1387
|
+
const normalizedBasePath = basePath ? normalizeToolPath(basePath) : (cwd ?? process.cwd());
|
|
1388
|
+
const base = basePath ? safePath(basePath, cwd) : (cwd ?? process.cwd());
|
|
1310
1389
|
if (!(0, fs_1.existsSync)(base)) {
|
|
1311
1390
|
return { success: false, output: '', error: `Path not found: ${normalizedBasePath}` };
|
|
1312
1391
|
}
|
|
1313
1392
|
if (!(0, fs_1.statSync)(base).isDirectory()) {
|
|
1314
|
-
return {
|
|
1393
|
+
return {
|
|
1394
|
+
success: false,
|
|
1395
|
+
output: '',
|
|
1396
|
+
error: `Path is not a directory: ${normalizedBasePath}`,
|
|
1397
|
+
};
|
|
1315
1398
|
}
|
|
1316
1399
|
const results = [];
|
|
1317
|
-
// Convert glob pattern to regex
|
|
1400
|
+
// Convert glob pattern to regex.
|
|
1401
|
+
// Escape ALL regex metacharacters first, then translate glob wildcards.
|
|
1402
|
+
// Escaping only `.` (the old behavior) left parens/brackets/+/^/$/| as
|
|
1403
|
+
// regex syntax: a literal "(group)" became a capture group (so the real
|
|
1404
|
+
// file stopped matching) and an unbalanced "[" made new RegExp throw.
|
|
1318
1405
|
function globToRegex(pat) {
|
|
1319
|
-
// Use placeholders
|
|
1406
|
+
// Use placeholders for glob wildcards so escaping does not touch them.
|
|
1320
1407
|
let regex = pat;
|
|
1321
1408
|
// **/ at start - matches optional path (including empty)
|
|
1322
1409
|
regex = regex.replace(/^\*\*\//, '<<STARSTAR_SLASH_START>>');
|
|
@@ -1324,8 +1411,9 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1324
1411
|
regex = regex.replace(/\*\*\//g, '<<STARSTAR_SLASH>>');
|
|
1325
1412
|
// standalone ** - matches anything
|
|
1326
1413
|
regex = regex.replace(/\*\*/g, '<<STARSTAR>>');
|
|
1327
|
-
//
|
|
1328
|
-
|
|
1414
|
+
// Escape every regex metacharacter in the remaining literal text.
|
|
1415
|
+
// NOTE: * and ? are glob wildcards, handled below - do not escape them.
|
|
1416
|
+
regex = regex.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
1329
1417
|
// * matches anything except /
|
|
1330
1418
|
regex = regex.replace(/\*/g, '[^/]*');
|
|
1331
1419
|
// ? matches single char except /
|
|
@@ -1337,8 +1425,12 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1337
1425
|
return new RegExp(`^${regex}$`);
|
|
1338
1426
|
}
|
|
1339
1427
|
const regex = globToRegex(pattern);
|
|
1340
|
-
// Recursive walk
|
|
1341
|
-
|
|
1428
|
+
// Recursive walk with a depth cap so a pathological tree (or symlink loop)
|
|
1429
|
+
// cannot hang or OOM the tool.
|
|
1430
|
+
const MAX_DEPTH = 16;
|
|
1431
|
+
function walk(dir, prefix, depth) {
|
|
1432
|
+
if (depth > MAX_DEPTH)
|
|
1433
|
+
return;
|
|
1342
1434
|
try {
|
|
1343
1435
|
const entries = (0, fs_1.readdirSync)(dir, { withFileTypes: true });
|
|
1344
1436
|
for (const entry of entries) {
|
|
@@ -1346,7 +1438,7 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1346
1438
|
continue;
|
|
1347
1439
|
const relPath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
1348
1440
|
if (entry.isDirectory()) {
|
|
1349
|
-
walk((0, path_1.join)(dir, entry.name), relPath);
|
|
1441
|
+
walk((0, path_1.join)(dir, entry.name), relPath, depth + 1);
|
|
1350
1442
|
}
|
|
1351
1443
|
else {
|
|
1352
1444
|
if (regex.test(relPath)) {
|
|
@@ -1359,7 +1451,7 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1359
1451
|
// skip unreadable directories
|
|
1360
1452
|
}
|
|
1361
1453
|
}
|
|
1362
|
-
walk(base, '');
|
|
1454
|
+
walk(base, '', 0);
|
|
1363
1455
|
if (results.length === 0) {
|
|
1364
1456
|
return { success: true, output: 'No files found matching pattern' };
|
|
1365
1457
|
}
|
|
@@ -1367,7 +1459,8 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1367
1459
|
const maxMatches = 200;
|
|
1368
1460
|
const sorted = results.sort();
|
|
1369
1461
|
const output = sorted.length > maxMatches
|
|
1370
|
-
? sorted.slice(0, maxMatches).join('\n') +
|
|
1462
|
+
? sorted.slice(0, maxMatches).join('\n') +
|
|
1463
|
+
`\n\n[... truncated, ${sorted.length - maxMatches} more matches]`
|
|
1371
1464
|
: sorted.join('\n');
|
|
1372
1465
|
return { success: true, output };
|
|
1373
1466
|
}
|
|
@@ -1380,8 +1473,8 @@ async function glob_(pattern, basePath, cwd) {
|
|
|
1380
1473
|
*/
|
|
1381
1474
|
async function grep_(pattern, basePath, globPattern, contextLines, cwd) {
|
|
1382
1475
|
try {
|
|
1383
|
-
const normalizedBasePath = basePath ? normalizeToolPath(basePath) : cwd ?? process.cwd();
|
|
1384
|
-
const base = basePath ? safePath(basePath, cwd) : cwd ?? process.cwd();
|
|
1476
|
+
const normalizedBasePath = basePath ? normalizeToolPath(basePath) : (cwd ?? process.cwd());
|
|
1477
|
+
const base = basePath ? safePath(basePath, cwd) : (cwd ?? process.cwd());
|
|
1385
1478
|
if (!(0, fs_1.existsSync)(base)) {
|
|
1386
1479
|
return { success: false, output: '', error: `Path not found: ${normalizedBasePath}` };
|
|
1387
1480
|
}
|
|
@@ -1437,10 +1530,10 @@ async function grep_(pattern, basePath, globPattern, contextLines, cwd) {
|
|
|
1437
1530
|
});
|
|
1438
1531
|
const lines = [];
|
|
1439
1532
|
const relPath = (0, path_1.relative)(base, file);
|
|
1440
|
-
rl.on('line',
|
|
1533
|
+
rl.on('line', line => {
|
|
1441
1534
|
lines.push(line);
|
|
1442
1535
|
});
|
|
1443
|
-
await new Promise(
|
|
1536
|
+
await new Promise(resolve => {
|
|
1444
1537
|
rl.on('close', resolve);
|
|
1445
1538
|
});
|
|
1446
1539
|
// Search for matches
|
|
@@ -1513,7 +1606,9 @@ function parseBatchReadSteps(rawSteps) {
|
|
|
1513
1606
|
stepArgs = JSON.parse(stepArgs);
|
|
1514
1607
|
}
|
|
1515
1608
|
catch {
|
|
1516
|
-
return {
|
|
1609
|
+
return {
|
|
1610
|
+
error: `batch_read step ${i + 1} args must be an object or valid JSON object string`,
|
|
1611
|
+
};
|
|
1517
1612
|
}
|
|
1518
1613
|
}
|
|
1519
1614
|
if (!isRecord(stepArgs)) {
|
|
@@ -1526,7 +1621,9 @@ function parseBatchReadSteps(rawSteps) {
|
|
|
1526
1621
|
function buildBatchReadPayload(success, summary, steps, error) {
|
|
1527
1622
|
const payload = {
|
|
1528
1623
|
success,
|
|
1529
|
-
output: steps
|
|
1624
|
+
output: steps
|
|
1625
|
+
.map(step => `${step.index}. ${step.tool}: ${step.summary || (step.success ? 'ok' : step.error || 'error')}`)
|
|
1626
|
+
.join('\n'),
|
|
1530
1627
|
summary,
|
|
1531
1628
|
steps,
|
|
1532
1629
|
};
|
|
@@ -1551,25 +1648,29 @@ async function executeBatchRead(args, context) {
|
|
|
1551
1648
|
const tool = runtimeTools.find(t => t.name === step.tool);
|
|
1552
1649
|
if (!BATCH_READ_ALLOWED_TOOLS.has(step.tool)) {
|
|
1553
1650
|
const error = `Tool ${step.tool} is not allowed in batch_read`;
|
|
1554
|
-
return buildBatchReadPayload(false, error, [
|
|
1651
|
+
return buildBatchReadPayload(false, error, [
|
|
1652
|
+
{
|
|
1555
1653
|
index: i + 1,
|
|
1556
1654
|
tool: step.tool,
|
|
1557
1655
|
args: step.args,
|
|
1558
1656
|
success: false,
|
|
1559
1657
|
error,
|
|
1560
1658
|
output: '',
|
|
1561
|
-
}
|
|
1659
|
+
},
|
|
1660
|
+
], error);
|
|
1562
1661
|
}
|
|
1563
1662
|
if (!tool || tool.isReadOnly?.(step.args) !== true) {
|
|
1564
1663
|
const error = `Tool ${step.tool} is unavailable or not read-only`;
|
|
1565
|
-
return buildBatchReadPayload(false, error, [
|
|
1664
|
+
return buildBatchReadPayload(false, error, [
|
|
1665
|
+
{
|
|
1566
1666
|
index: i + 1,
|
|
1567
1667
|
tool: step.tool,
|
|
1568
1668
|
args: step.args,
|
|
1569
1669
|
success: false,
|
|
1570
1670
|
error,
|
|
1571
1671
|
output: '',
|
|
1572
|
-
}
|
|
1672
|
+
},
|
|
1673
|
+
], error);
|
|
1573
1674
|
}
|
|
1574
1675
|
}
|
|
1575
1676
|
const stepResults = [];
|
|
@@ -1671,7 +1772,9 @@ function summarizeToolResult(tool, args, result) {
|
|
|
1671
1772
|
* 获取可用工具名称列表
|
|
1672
1773
|
*/
|
|
1673
1774
|
function getToolNames() {
|
|
1674
|
-
return getRuntimeTools()
|
|
1775
|
+
return getRuntimeTools()
|
|
1776
|
+
.map(t => t.name)
|
|
1777
|
+
.join(', ');
|
|
1675
1778
|
}
|
|
1676
1779
|
// Re-export bash_security module
|
|
1677
1780
|
var bash_security_2 = require("./bash_security");
|