@oh-my-pi/pi-coding-agent 6.2.0 → 6.7.67
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/CHANGELOG.md +60 -0
- package/docs/sdk.md +1 -1
- package/package.json +5 -5
- package/scripts/generate-template.ts +6 -6
- package/src/cli/args.ts +3 -0
- package/src/core/agent-session.ts +39 -0
- package/src/core/bash-executor.ts +3 -3
- package/src/core/cursor/exec-bridge.ts +95 -88
- package/src/core/custom-commands/bundled/review/index.ts +142 -145
- package/src/core/custom-commands/bundled/wt/index.ts +68 -66
- package/src/core/custom-commands/loader.ts +4 -6
- package/src/core/custom-tools/index.ts +2 -2
- package/src/core/custom-tools/loader.ts +66 -61
- package/src/core/custom-tools/types.ts +4 -4
- package/src/core/custom-tools/wrapper.ts +61 -25
- package/src/core/event-bus.ts +19 -47
- package/src/core/extensions/index.ts +8 -4
- package/src/core/extensions/loader.ts +160 -120
- package/src/core/extensions/types.ts +4 -4
- package/src/core/extensions/wrapper.ts +149 -100
- package/src/core/hooks/index.ts +1 -1
- package/src/core/hooks/tool-wrapper.ts +96 -70
- package/src/core/hooks/types.ts +1 -2
- package/src/core/index.ts +1 -0
- package/src/core/mcp/index.ts +6 -2
- package/src/core/mcp/json-rpc.ts +88 -0
- package/src/core/mcp/loader.ts +22 -4
- package/src/core/mcp/manager.ts +202 -48
- package/src/core/mcp/tool-bridge.ts +143 -55
- package/src/core/mcp/tool-cache.ts +122 -0
- package/src/core/python-executor.ts +3 -9
- package/src/core/sdk.ts +33 -32
- package/src/core/session-manager.ts +30 -0
- package/src/core/settings-manager.ts +54 -1
- package/src/core/ssh/ssh-executor.ts +6 -84
- package/src/core/streaming-output.ts +107 -53
- package/src/core/tools/ask.ts +92 -93
- package/src/core/tools/bash.ts +103 -94
- package/src/core/tools/calculator.ts +41 -26
- package/src/core/tools/complete.ts +76 -66
- package/src/core/tools/context.ts +22 -24
- package/src/core/tools/exa/index.ts +1 -1
- package/src/core/tools/exa/mcp-client.ts +56 -101
- package/src/core/tools/find.ts +250 -253
- package/src/core/tools/git.ts +39 -33
- package/src/core/tools/grep.ts +440 -427
- package/src/core/tools/index.ts +63 -61
- package/src/core/tools/ls.ts +119 -114
- package/src/core/tools/lsp/clients/biome-client.ts +5 -7
- package/src/core/tools/lsp/clients/index.ts +4 -4
- package/src/core/tools/lsp/clients/lsp-linter-client.ts +5 -7
- package/src/core/tools/lsp/config.ts +2 -2
- package/src/core/tools/lsp/index.ts +604 -578
- package/src/core/tools/notebook.ts +121 -119
- package/src/core/tools/output.ts +163 -147
- package/src/core/tools/patch/applicator.ts +1100 -0
- package/src/core/tools/patch/diff.ts +362 -0
- package/src/core/tools/patch/fuzzy.ts +647 -0
- package/src/core/tools/patch/index.ts +430 -0
- package/src/core/tools/patch/normalize.ts +220 -0
- package/src/core/tools/patch/normative.ts +73 -0
- package/src/core/tools/patch/parser.ts +528 -0
- package/src/core/tools/patch/shared.ts +257 -0
- package/src/core/tools/patch/types.ts +244 -0
- package/src/core/tools/python.ts +139 -136
- package/src/core/tools/read.ts +239 -216
- package/src/core/tools/render-utils.ts +196 -77
- package/src/core/tools/renderers.ts +6 -2
- package/src/core/tools/ssh.ts +99 -80
- package/src/core/tools/task/executor.ts +11 -7
- package/src/core/tools/task/index.ts +352 -343
- package/src/core/tools/task/worker.ts +13 -23
- package/src/core/tools/todo-write.ts +74 -59
- package/src/core/tools/web-fetch.ts +54 -47
- package/src/core/tools/web-search/index.ts +27 -16
- package/src/core/tools/write.ts +108 -47
- package/src/core/ttsr.ts +106 -152
- package/src/core/voice.ts +49 -39
- package/src/index.ts +16 -12
- package/src/lib/worktree/index.ts +1 -9
- package/src/modes/interactive/components/diff.ts +15 -8
- package/src/modes/interactive/components/settings-defs.ts +42 -0
- package/src/modes/interactive/components/tool-execution.ts +46 -8
- package/src/modes/interactive/controllers/event-controller.ts +6 -19
- package/src/modes/interactive/controllers/input-controller.ts +1 -1
- package/src/modes/interactive/utils/ui-helpers.ts +5 -1
- package/src/modes/rpc/rpc-mode.ts +99 -81
- package/src/prompts/tools/patch.md +76 -0
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/{edit.md → replace.md} +1 -0
- package/src/utils/shell.ts +0 -40
- package/src/core/tools/edit-diff.ts +0 -574
- package/src/core/tools/edit.ts +0 -345
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [6.7.67] - 2026-01-19
|
|
6
|
+
### Added
|
|
7
|
+
|
|
8
|
+
- Added normative rewrite setting to control tool call argument normalization in session history
|
|
9
|
+
- Added read line numbers setting to prepend line numbers to read tool output by default
|
|
10
|
+
- Added streaming preview for edit and write tools with spinner animation
|
|
11
|
+
- Added automatic anchor derivation for normative patches when anchors not specified
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Enhanced edit and write tool renderers to show streaming content preview
|
|
16
|
+
- Updated read tool to respect default line numbers setting
|
|
17
|
+
- Improved normative patch anchor handling to support undefined anchors
|
|
18
|
+
|
|
19
|
+
## [6.7.0] - 2026-01-19
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- Normative patch generation to canonicalize edit tool output with tool call argument rewriting for session history
|
|
24
|
+
- Patch matching fallback variants: trimmed context, collapsed duplicates, single-line reduction, comment-prefix normalization
|
|
25
|
+
- Extended anchor syntax: ellipsis placeholders, `top of file`/`start of file`, `@@ line N`, nested `@@` anchors, space-separated hierarchical contexts
|
|
26
|
+
- Relaxed fuzzy threshold fallback and unique substring acceptance for context matching
|
|
27
|
+
- Added `--no-title` flag to disable automatic session title generation
|
|
28
|
+
- Environment variables for edit tool configuration (OMP_EDIT_VARIANT, OMP_EDIT_FUZZY, OMP_EDIT_FUZZY_THRESHOLD)
|
|
29
|
+
- Configurable fuzzy matching threshold setting (0.85 lenient to 0.98 strict)
|
|
30
|
+
- Apply-patch mode for edit tool (`edit.patchMode` setting) with create, update, delete, and rename operations
|
|
31
|
+
- Added MCP tool caching for faster startup with cached tool definitions
|
|
32
|
+
|
|
33
|
+
### Changed
|
|
34
|
+
|
|
35
|
+
- Patch applicator now supports normalized input, implicit context lines, and improved indentation adjustment
|
|
36
|
+
- Patch operation schema uses 'op' instead of 'operation' and 'rename' instead of 'moveTo'
|
|
37
|
+
- Fuzzy matching tries comment-prefix normalized matches before unicode normalization
|
|
38
|
+
- Updated patch prompts with clearer anchor selection rules and verbatim context requirements
|
|
39
|
+
- Changed default behavior of read tool to omit line numbers by default
|
|
40
|
+
- Changed default edit tool mode to use apply-patch format instead of oldText/newText
|
|
41
|
+
- Converted tool implementations from factory functions to class-based architecture
|
|
42
|
+
- Refactored edit tool with modular patch architecture (moved from `edit/` to `patch/` module)
|
|
43
|
+
- Enhanced patch parsing: unified diff format, Codex-style patches, nested anchors, multi-file markers
|
|
44
|
+
- Improved fuzzy matching with multiple match tracking, ambiguity detection, and out-of-order hunk processing
|
|
45
|
+
- Better diff rendering: smarter truncation, optional line numbers, trailing newline preservation
|
|
46
|
+
- Improved error messages with hierarchical context display using `>` separator
|
|
47
|
+
- Centralized output sanitization in streaming-output module
|
|
48
|
+
- Enhanced MCP startup with deferred tool loading and cached fallback
|
|
49
|
+
|
|
50
|
+
### Fixed
|
|
51
|
+
|
|
52
|
+
- Patch application handles repeated context blocks, preserves original indentation on fuzzy match
|
|
53
|
+
- Ambiguous context matching resolves duplicates using adjacent @@ anchor positioning
|
|
54
|
+
- Patch parser handles bare *** terminators, model hallucination markers, line hint ranges
|
|
55
|
+
- Function context matching handles signatures with and without empty parentheses
|
|
56
|
+
- Fixed session title generation to respect OMP_NO_TITLE environment variable
|
|
57
|
+
- Fixed Python module discovery to use import.meta.dir for ES module compatibility
|
|
58
|
+
- Fixed LSP writethrough batching to flush when delete operations complete a batch
|
|
59
|
+
- Fixed line number validation, BOM detection, and trailing newline preservation in patches
|
|
60
|
+
- Fixed hierarchical context matching and space-separated anchor parsing
|
|
61
|
+
- Fixed fuzzy matching to avoid infinite loops when `allowFuzzy` is disabled
|
|
62
|
+
- Fixed tool completion logic to only mark tools as complete when streaming is not aborted or in error state
|
|
63
|
+
- Fixed MCP tool path formatting to correctly display provider information
|
|
64
|
+
|
|
5
65
|
## [6.2.0] - 2026-01-19
|
|
6
66
|
### Changed
|
|
7
67
|
|
package/docs/sdk.md
CHANGED
|
@@ -942,7 +942,7 @@ createTools // Create all tools from ToolSession
|
|
|
942
942
|
type ToolSession // Session context for tool creation
|
|
943
943
|
|
|
944
944
|
// Individual tool factories
|
|
945
|
-
createReadTool, createBashTool,
|
|
945
|
+
createReadTool, createBashTool, EditTool, createWriteTool
|
|
946
946
|
createGrepTool, createFindTool, createLsTool, createGitTool
|
|
947
947
|
|
|
948
948
|
// Types
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.7.67",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"ompConfig": {
|
|
@@ -40,10 +40,10 @@
|
|
|
40
40
|
"prepublishOnly": "bun run generate-template && bun run clean && bun run build"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@oh-my-pi/pi-agent-core": "6.
|
|
44
|
-
"@oh-my-pi/pi-ai": "6.
|
|
45
|
-
"@oh-my-pi/pi-git-tool": "6.
|
|
46
|
-
"@oh-my-pi/pi-tui": "6.
|
|
43
|
+
"@oh-my-pi/pi-agent-core": "6.7.67",
|
|
44
|
+
"@oh-my-pi/pi-ai": "6.7.67",
|
|
45
|
+
"@oh-my-pi/pi-git-tool": "6.7.67",
|
|
46
|
+
"@oh-my-pi/pi-tui": "6.7.67",
|
|
47
47
|
"@openai/agents": "^0.3.7",
|
|
48
48
|
"@sinclair/typebox": "^0.34.46",
|
|
49
49
|
"ajv": "^8.17.1",
|
|
@@ -13,15 +13,15 @@ const js = await Bun.file(`${dir}template.js`).text();
|
|
|
13
13
|
|
|
14
14
|
// Minify CSS
|
|
15
15
|
const minifiedCss = css
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
17
|
+
.replace(/\s+/g, " ")
|
|
18
|
+
.replace(/\s*([{}:;,])\s*/g, "$1")
|
|
19
|
+
.trim();
|
|
20
20
|
|
|
21
21
|
// Inline everything
|
|
22
22
|
const template = html
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
.replace("<template-css/>", `<style>${minifiedCss}</style>`)
|
|
24
|
+
.replace("<template-js/>", `<script>${js}</script>`);
|
|
25
25
|
|
|
26
26
|
// Write generated file
|
|
27
27
|
const output = `// Auto-generated by scripts/generate-template.ts - DO NOT EDIT
|
package/src/cli/args.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface Args {
|
|
|
40
40
|
noSkills?: boolean;
|
|
41
41
|
skills?: string[];
|
|
42
42
|
listModels?: string | true;
|
|
43
|
+
noTitle?: boolean;
|
|
43
44
|
messages: string[];
|
|
44
45
|
fileArgs: string[];
|
|
45
46
|
/** Unknown flags (potentially extension flags) - map of flag name to value */
|
|
@@ -143,6 +144,8 @@ export function parseArgs(args: string[], extensionFlags?: Map<string, { type: "
|
|
|
143
144
|
result.noExtensions = true;
|
|
144
145
|
} else if (arg === "--no-skills") {
|
|
145
146
|
result.noSkills = true;
|
|
147
|
+
} else if (arg === "--no-title") {
|
|
148
|
+
result.noTitle = true;
|
|
146
149
|
} else if (arg === "--skills" && i + 1 < args.length) {
|
|
147
150
|
// Comma-separated glob patterns for skill filtering
|
|
148
151
|
result.skills = args[++i].split(",").map((s) => s.trim());
|
|
@@ -432,6 +432,18 @@ export class AgentSession {
|
|
|
432
432
|
if (event.message.role === "assistant") {
|
|
433
433
|
this._lastAssistantMessage = event.message;
|
|
434
434
|
}
|
|
435
|
+
|
|
436
|
+
if (event.message.role === "toolResult") {
|
|
437
|
+
const { $normative, toolCallId } = event.message as {
|
|
438
|
+
toolName?: string;
|
|
439
|
+
toolCallId?: string;
|
|
440
|
+
details?: unknown;
|
|
441
|
+
$normative?: Record<string, unknown>;
|
|
442
|
+
};
|
|
443
|
+
if ($normative && toolCallId && this.settingsManager.getNormativeRewrite()) {
|
|
444
|
+
await this._rewriteToolCallArgs(toolCallId, $normative);
|
|
445
|
+
}
|
|
446
|
+
}
|
|
435
447
|
}
|
|
436
448
|
|
|
437
449
|
// Check auto-retry and auto-compaction after agent completes
|
|
@@ -513,6 +525,33 @@ export class AgentSession {
|
|
|
513
525
|
return undefined;
|
|
514
526
|
}
|
|
515
527
|
|
|
528
|
+
/** Rewrite tool call arguments in agent state and persisted session history. */
|
|
529
|
+
private async _rewriteToolCallArgs(toolCallId: string, args: Record<string, unknown>): Promise<void> {
|
|
530
|
+
let updated = false;
|
|
531
|
+
const messages = this.agent.state.messages;
|
|
532
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
533
|
+
const msg = messages[i];
|
|
534
|
+
if (msg.role !== "assistant") continue;
|
|
535
|
+
const assistantMsg = msg as AssistantMessage;
|
|
536
|
+
if (!Array.isArray(assistantMsg.content)) continue;
|
|
537
|
+
for (const block of assistantMsg.content) {
|
|
538
|
+
if (typeof block !== "object" || block === null) continue;
|
|
539
|
+
if (!("type" in block) || (block as { type?: string }).type !== "toolCall") continue;
|
|
540
|
+
const toolCall = block as { id?: string; arguments?: Record<string, unknown> };
|
|
541
|
+
if (toolCall.id === toolCallId) {
|
|
542
|
+
toolCall.arguments = args;
|
|
543
|
+
updated = true;
|
|
544
|
+
break;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
if (updated) break;
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
if (updated) {
|
|
551
|
+
await this.sessionManager.rewriteAssistantToolCallArgs(toolCallId, args);
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
516
555
|
/** Emit extension events based on agent events */
|
|
517
556
|
private async _emitExtensionEvent(event: AgentEvent): Promise<void> {
|
|
518
557
|
if (!this._extensionRunner) return;
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import type { Subprocess } from "bun";
|
|
10
10
|
import { getShellConfig, killProcessTree } from "../utils/shell";
|
|
11
11
|
import { getOrCreateSnapshot, getSnapshotSourceCommand } from "../utils/shell-snapshot";
|
|
12
|
-
import {
|
|
12
|
+
import { OutputSink, pumpStream } from "./streaming-output";
|
|
13
13
|
import type { BashOperations } from "./tools/bash";
|
|
14
14
|
import { DEFAULT_MAX_BYTES } from "./tools/truncate";
|
|
15
15
|
import { ScopeSignal } from "./utils";
|
|
@@ -85,7 +85,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
85
85
|
killProcessTree(child.pid);
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
const sink =
|
|
88
|
+
const sink = new OutputSink(DEFAULT_MAX_BYTES, DEFAULT_MAX_BYTES * 2, options?.onChunk);
|
|
89
89
|
|
|
90
90
|
const writer = sink.getWriter();
|
|
91
91
|
try {
|
|
@@ -128,7 +128,7 @@ export async function executeBashWithOperations(
|
|
|
128
128
|
operations: BashOperations,
|
|
129
129
|
options?: BashExecutorOptions,
|
|
130
130
|
): Promise<BashResult> {
|
|
131
|
-
const sink =
|
|
131
|
+
const sink = new OutputSink(DEFAULT_MAX_BYTES, DEFAULT_MAX_BYTES * 2, options?.onChunk);
|
|
132
132
|
const writer = sink.getWriter();
|
|
133
133
|
|
|
134
134
|
// Create a ReadableStream from the callback-based operations.exec
|
|
@@ -7,7 +7,7 @@ import type {
|
|
|
7
7
|
AgentToolResult,
|
|
8
8
|
AgentToolUpdateCallback,
|
|
9
9
|
} from "@oh-my-pi/pi-agent-core";
|
|
10
|
-
import type {
|
|
10
|
+
import type { CursorMcpCall, CursorExecHandlers as ICursorExecHandlers, ToolResultMessage } from "@oh-my-pi/pi-ai";
|
|
11
11
|
import { resolveToCwd } from "../tools/path-utils";
|
|
12
12
|
|
|
13
13
|
interface CursorExecBridgeOptions {
|
|
@@ -143,92 +143,99 @@ function formatMcpToolErrorMessage(toolName: string, availableTools: string[]):
|
|
|
143
143
|
return `MCP tool "${toolName}" not found. Available tools: ${list}`;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
|
-
export
|
|
147
|
-
|
|
148
|
-
read: async (args) => {
|
|
149
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
150
|
-
const toolResultMessage = await executeTool(options, "read", toolCallId, { path: args.path });
|
|
151
|
-
return toolResultMessage;
|
|
152
|
-
},
|
|
153
|
-
ls: async (args) => {
|
|
154
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
155
|
-
const toolResultMessage = await executeTool(options, "ls", toolCallId, { path: args.path });
|
|
156
|
-
return toolResultMessage;
|
|
157
|
-
},
|
|
158
|
-
grep: async (args) => {
|
|
159
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
160
|
-
const toolResultMessage = await executeTool(options, "grep", toolCallId, {
|
|
161
|
-
pattern: args.pattern,
|
|
162
|
-
path: args.path || undefined,
|
|
163
|
-
glob: args.glob || undefined,
|
|
164
|
-
outputMode: args.outputMode || undefined,
|
|
165
|
-
context: args.context ?? args.contextBefore ?? args.contextAfter ?? undefined,
|
|
166
|
-
ignoreCase: args.caseInsensitive || undefined,
|
|
167
|
-
type: args.type || undefined,
|
|
168
|
-
headLimit: args.headLimit ?? undefined,
|
|
169
|
-
multiline: args.multiline || undefined,
|
|
170
|
-
});
|
|
171
|
-
return toolResultMessage;
|
|
172
|
-
},
|
|
173
|
-
write: async (args) => {
|
|
174
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
175
|
-
const content = args.fileText ?? new TextDecoder().decode(args.fileBytes ?? new Uint8Array());
|
|
176
|
-
const toolResultMessage = await executeTool(options, "write", toolCallId, {
|
|
177
|
-
path: args.path,
|
|
178
|
-
content,
|
|
179
|
-
});
|
|
180
|
-
return toolResultMessage;
|
|
181
|
-
},
|
|
182
|
-
delete: async (args) => {
|
|
183
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
184
|
-
const toolResultMessage = await executeDelete(options, args.path, toolCallId);
|
|
185
|
-
return toolResultMessage;
|
|
186
|
-
},
|
|
187
|
-
shell: async (args) => {
|
|
188
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
189
|
-
const timeoutSeconds =
|
|
190
|
-
args.timeout && args.timeout > 0
|
|
191
|
-
? args.timeout > 1000
|
|
192
|
-
? Math.ceil(args.timeout / 1000)
|
|
193
|
-
: args.timeout
|
|
194
|
-
: undefined;
|
|
195
|
-
const toolResultMessage = await executeTool(options, "bash", toolCallId, {
|
|
196
|
-
command: args.command,
|
|
197
|
-
workdir: args.workingDirectory || undefined,
|
|
198
|
-
timeout: timeoutSeconds,
|
|
199
|
-
});
|
|
200
|
-
return toolResultMessage;
|
|
201
|
-
},
|
|
202
|
-
diagnostics: async (args) => {
|
|
203
|
-
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
204
|
-
const toolResultMessage = await executeTool(options, "lsp", toolCallId, {
|
|
205
|
-
action: "diagnostics",
|
|
206
|
-
file: args.path,
|
|
207
|
-
});
|
|
208
|
-
return toolResultMessage;
|
|
209
|
-
},
|
|
210
|
-
mcp: async (call: CursorMcpCall) => {
|
|
211
|
-
const toolName = call.toolName || call.name;
|
|
212
|
-
const toolCallId = decodeToolCallId(call.toolCallId);
|
|
213
|
-
const tool = options.tools.get(toolName);
|
|
214
|
-
if (!tool) {
|
|
215
|
-
const availableTools = Array.from(options.tools.keys()).filter((name) => name.startsWith("mcp_"));
|
|
216
|
-
const message = formatMcpToolErrorMessage(toolName, availableTools);
|
|
217
|
-
const toolResult: ToolResultMessage = {
|
|
218
|
-
role: "toolResult",
|
|
219
|
-
toolCallId,
|
|
220
|
-
toolName,
|
|
221
|
-
content: [{ type: "text", text: message }],
|
|
222
|
-
details: {},
|
|
223
|
-
isError: true,
|
|
224
|
-
timestamp: Date.now(),
|
|
225
|
-
};
|
|
226
|
-
return toolResult;
|
|
227
|
-
}
|
|
146
|
+
export class CursorExecHandlers implements ICursorExecHandlers {
|
|
147
|
+
constructor(private options: CursorExecBridgeOptions) {}
|
|
228
148
|
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
}
|
|
149
|
+
async read(args: Parameters<NonNullable<ICursorExecHandlers["read"]>>[0]) {
|
|
150
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
151
|
+
const toolResultMessage = await executeTool(this.options, "read", toolCallId, { path: args.path });
|
|
152
|
+
return toolResultMessage;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
async ls(args: Parameters<NonNullable<ICursorExecHandlers["ls"]>>[0]) {
|
|
156
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
157
|
+
const toolResultMessage = await executeTool(this.options, "ls", toolCallId, { path: args.path });
|
|
158
|
+
return toolResultMessage;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
async grep(args: Parameters<NonNullable<ICursorExecHandlers["grep"]>>[0]) {
|
|
162
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
163
|
+
const toolResultMessage = await executeTool(this.options, "grep", toolCallId, {
|
|
164
|
+
pattern: args.pattern,
|
|
165
|
+
path: args.path || undefined,
|
|
166
|
+
glob: args.glob || undefined,
|
|
167
|
+
outputMode: args.outputMode || undefined,
|
|
168
|
+
context: args.context ?? args.contextBefore ?? args.contextAfter ?? undefined,
|
|
169
|
+
ignoreCase: args.caseInsensitive || undefined,
|
|
170
|
+
type: args.type || undefined,
|
|
171
|
+
headLimit: args.headLimit ?? undefined,
|
|
172
|
+
multiline: args.multiline || undefined,
|
|
173
|
+
});
|
|
174
|
+
return toolResultMessage;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async write(args: Parameters<NonNullable<ICursorExecHandlers["write"]>>[0]) {
|
|
178
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
179
|
+
const content = args.fileText ?? new TextDecoder().decode(args.fileBytes ?? new Uint8Array());
|
|
180
|
+
const toolResultMessage = await executeTool(this.options, "write", toolCallId, {
|
|
181
|
+
path: args.path,
|
|
182
|
+
content,
|
|
183
|
+
});
|
|
184
|
+
return toolResultMessage;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async delete(args: Parameters<NonNullable<ICursorExecHandlers["delete"]>>[0]) {
|
|
188
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
189
|
+
const toolResultMessage = await executeDelete(this.options, args.path, toolCallId);
|
|
190
|
+
return toolResultMessage;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async shell(args: Parameters<NonNullable<ICursorExecHandlers["shell"]>>[0]) {
|
|
194
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
195
|
+
const timeoutSeconds =
|
|
196
|
+
args.timeout && args.timeout > 0
|
|
197
|
+
? args.timeout > 1000
|
|
198
|
+
? Math.ceil(args.timeout / 1000)
|
|
199
|
+
: args.timeout
|
|
200
|
+
: undefined;
|
|
201
|
+
const toolResultMessage = await executeTool(this.options, "bash", toolCallId, {
|
|
202
|
+
command: args.command,
|
|
203
|
+
workdir: args.workingDirectory || undefined,
|
|
204
|
+
timeout: timeoutSeconds,
|
|
205
|
+
});
|
|
206
|
+
return toolResultMessage;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
async diagnostics(args: Parameters<NonNullable<ICursorExecHandlers["diagnostics"]>>[0]) {
|
|
210
|
+
const toolCallId = decodeToolCallId(args.toolCallId);
|
|
211
|
+
const toolResultMessage = await executeTool(this.options, "lsp", toolCallId, {
|
|
212
|
+
action: "diagnostics",
|
|
213
|
+
file: args.path,
|
|
214
|
+
});
|
|
215
|
+
return toolResultMessage;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async mcp(call: CursorMcpCall) {
|
|
219
|
+
const toolName = call.toolName || call.name;
|
|
220
|
+
const toolCallId = decodeToolCallId(call.toolCallId);
|
|
221
|
+
const tool = this.options.tools.get(toolName);
|
|
222
|
+
if (!tool) {
|
|
223
|
+
const availableTools = Array.from(this.options.tools.keys()).filter((name) => name.startsWith("mcp_"));
|
|
224
|
+
const message = formatMcpToolErrorMessage(toolName, availableTools);
|
|
225
|
+
const toolResult: ToolResultMessage = {
|
|
226
|
+
role: "toolResult",
|
|
227
|
+
toolCallId,
|
|
228
|
+
toolName,
|
|
229
|
+
content: [{ type: "text", text: message }],
|
|
230
|
+
details: {},
|
|
231
|
+
isError: true,
|
|
232
|
+
timestamp: Date.now(),
|
|
233
|
+
};
|
|
234
|
+
return toolResult;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const args = Object.keys(call.args ?? {}).length > 0 ? call.args : decodeMcpArgs(call.rawArgs ?? {});
|
|
238
|
+
const toolResultMessage = await executeTool(this.options, toolName, toolCallId, args);
|
|
239
|
+
return toolResultMessage;
|
|
240
|
+
}
|
|
234
241
|
}
|