@oh-my-pi/pi-coding-agent 16.2.12 → 16.3.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.
- package/CHANGELOG.md +115 -7
- package/dist/cli.js +5996 -5945
- package/dist/types/advisor/config.d.ts +4 -2
- package/dist/types/collab/host.d.ts +16 -0
- package/dist/types/collab/protocol.d.ts +9 -3
- package/dist/types/commit/model-selection.d.ts +5 -0
- package/dist/types/config/model-resolver.d.ts +12 -10
- package/dist/types/config/models-config-schema.d.ts +12 -0
- package/dist/types/config/models-config.d.ts +9 -0
- package/dist/types/config/settings-schema.d.ts +28 -5
- package/dist/types/edit/modes/patch.d.ts +11 -0
- package/dist/types/eval/agent-bridge.d.ts +5 -1
- package/dist/types/exec/bash-executor.d.ts +1 -0
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +86 -2
- package/dist/types/extensibility/skills.d.ts +2 -1
- package/dist/types/mnemopi/state.d.ts +12 -0
- package/dist/types/modes/components/agent-hub.d.ts +9 -5
- package/dist/types/modes/components/status-line/component.test.d.ts +1 -0
- package/dist/types/modes/components/usage-row.d.ts +1 -1
- package/dist/types/modes/controllers/command-controller.d.ts +0 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +6 -0
- package/dist/types/modes/controllers/streaming-reveal.d.ts +17 -1
- package/dist/types/modes/controllers/tool-args-reveal.d.ts +30 -3
- package/dist/types/modes/interactive-mode.d.ts +12 -7
- package/dist/types/modes/rpc/rpc-client.d.ts +5 -0
- package/dist/types/modes/rpc/rpc-mode.d.ts +64 -1
- package/dist/types/modes/session-teardown.d.ts +63 -0
- package/dist/types/modes/session-teardown.test.d.ts +1 -0
- package/dist/types/modes/theme/theme.d.ts +9 -4
- package/dist/types/modes/types.d.ts +2 -3
- package/dist/types/modes/utils/copy-targets.d.ts +2 -0
- package/dist/types/plan-mode/approved-plan-prompt.test.d.ts +1 -0
- package/dist/types/sdk.d.ts +9 -0
- package/dist/types/session/agent-session.d.ts +46 -13
- package/dist/types/session/exit-diagnostics.d.ts +48 -0
- package/dist/types/session/session-loader.d.ts +5 -0
- package/dist/types/task/executor.d.ts +12 -5
- package/dist/types/task/parallel.d.ts +1 -0
- package/dist/types/task/render.test.d.ts +1 -0
- package/dist/types/thinking.d.ts +2 -0
- package/dist/types/tools/checkpoint.d.ts +8 -0
- package/dist/types/tools/eval-render.d.ts +1 -0
- package/dist/types/tools/fetch.d.ts +11 -1
- package/dist/types/tools/index.d.ts +3 -1
- package/dist/types/tools/irc.d.ts +1 -0
- package/dist/types/tools/output-meta.d.ts +7 -0
- package/dist/types/tools/output-schema-validator.d.ts +7 -4
- package/dist/types/tools/path-utils.d.ts +16 -0
- package/dist/types/tools/render-utils.d.ts +4 -1
- package/dist/types/utils/git.d.ts +47 -2
- package/dist/types/web/search/provider.d.ts +7 -0
- package/dist/types/web/search/types.d.ts +1 -1
- package/package.json +12 -12
- package/src/advisor/config.ts +4 -2
- package/src/cli/bench-cli.ts +7 -2
- package/src/collab/guest.ts +94 -5
- package/src/collab/host.ts +80 -3
- package/src/collab/protocol.ts +9 -2
- package/src/commit/model-selection.ts +8 -2
- package/src/config/keybindings.ts +3 -1
- package/src/config/model-discovery.ts +66 -2
- package/src/config/model-registry.ts +7 -3
- package/src/config/model-resolver.ts +51 -23
- package/src/config/models-config-schema.ts +13 -0
- package/src/config/settings-schema.ts +44 -14
- package/src/edit/hashline/diff.ts +13 -2
- package/src/edit/index.ts +58 -8
- package/src/edit/modes/patch.ts +53 -18
- package/src/edit/streaming.ts +7 -6
- package/src/eval/__tests__/agent-bridge.test.ts +57 -1
- package/src/eval/agent-bridge.ts +15 -5
- package/src/exec/bash-executor.ts +7 -12
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +534 -16
- package/src/extensibility/skills.ts +29 -6
- package/src/goals/guided-setup.ts +4 -3
- package/src/internal-urls/docs-index.generated.txt +1 -1
- package/src/lsp/client.ts +11 -14
- package/src/main.ts +38 -10
- package/src/mnemopi/state.ts +43 -7
- package/src/modes/acp/acp-agent.ts +1 -1
- package/src/modes/components/agent-hub.ts +10 -2
- package/src/modes/components/agent-transcript-viewer.ts +39 -7
- package/src/modes/components/assistant-message.ts +16 -10
- package/src/modes/components/chat-transcript-builder.ts +11 -1
- package/src/modes/components/custom-editor.test.ts +20 -0
- package/src/modes/components/hook-selector.ts +44 -25
- package/src/modes/components/model-selector.ts +1 -1
- package/src/modes/components/status-line/component.test.ts +44 -0
- package/src/modes/components/status-line/component.ts +9 -1
- package/src/modes/components/status-line/segments.ts +3 -3
- package/src/modes/components/usage-row.ts +16 -2
- package/src/modes/controllers/command-controller.ts +6 -21
- package/src/modes/controllers/event-controller.ts +11 -9
- package/src/modes/controllers/extension-ui-controller.ts +84 -3
- package/src/modes/controllers/input-controller.ts +16 -13
- package/src/modes/controllers/selector-controller.ts +3 -8
- package/src/modes/controllers/streaming-reveal.ts +75 -53
- package/src/modes/controllers/tool-args-reveal.ts +340 -10
- package/src/modes/interactive-mode.ts +122 -79
- package/src/modes/rpc/rpc-client.ts +21 -0
- package/src/modes/rpc/rpc-mode.ts +197 -46
- package/src/modes/session-teardown.test.ts +219 -0
- package/src/modes/session-teardown.ts +82 -0
- package/src/modes/setup-wizard/scenes/theme.ts +2 -2
- package/src/modes/skill-command.ts +7 -20
- package/src/modes/theme/theme.ts +29 -15
- package/src/modes/types.ts +2 -3
- package/src/modes/utils/copy-targets.ts +12 -0
- package/src/modes/utils/ui-helpers.ts +19 -2
- package/src/plan-mode/approved-plan-prompt.test.ts +36 -0
- package/src/prompts/advisor/system.md +1 -1
- package/src/prompts/agents/tester.md +6 -2
- package/src/prompts/skills/autoload.md +8 -0
- package/src/prompts/skills/user-invocation.md +11 -0
- package/src/prompts/steering/parent-irc.md +5 -0
- package/src/prompts/system/irc-incoming.md +2 -0
- package/src/prompts/system/mid-run-todo-nudge.md +3 -0
- package/src/prompts/system/plan-mode-approved.md +7 -10
- package/src/prompts/system/plan-mode-compact-instructions.md +2 -1
- package/src/prompts/system/plan-mode-reference.md +3 -4
- package/src/prompts/system/rewind-report.md +6 -0
- package/src/prompts/system/subagent-system-prompt.md +3 -0
- package/src/prompts/tools/irc.md +2 -1
- package/src/prompts/tools/job.md +2 -2
- package/src/prompts/tools/rewind.md +3 -2
- package/src/prompts/tools/ssh.md +1 -0
- package/src/prompts/tools/task.md +4 -0
- package/src/sdk.ts +18 -4
- package/src/session/agent-session.ts +660 -114
- package/src/session/exit-diagnostics.ts +202 -0
- package/src/session/session-context.ts +25 -13
- package/src/session/session-loader.ts +58 -25
- package/src/session/session-manager.ts +0 -1
- package/src/session/session-persistence.ts +30 -4
- package/src/session/settings-stream-fn.ts +14 -0
- package/src/slash-commands/builtin-registry.ts +35 -3
- package/src/system-prompt.ts +15 -1
- package/src/task/executor.ts +31 -8
- package/src/task/index.ts +31 -9
- package/src/task/isolation-runner.ts +18 -2
- package/src/task/parallel.ts +7 -2
- package/src/task/render.test.ts +121 -0
- package/src/task/render.ts +48 -2
- package/src/task/worktree.ts +12 -13
- package/src/task/yield-assembly.ts +8 -5
- package/src/thinking.ts +5 -0
- package/src/tools/ask.ts +188 -9
- package/src/tools/ast-edit.ts +7 -0
- package/src/tools/ast-grep.ts +11 -0
- package/src/tools/bash.ts +6 -30
- package/src/tools/checkpoint.ts +15 -1
- package/src/tools/eval-render.ts +15 -0
- package/src/tools/fetch.ts +82 -18
- package/src/tools/gh.ts +1 -1
- package/src/tools/grep.ts +45 -27
- package/src/tools/index.ts +3 -1
- package/src/tools/irc.ts +24 -9
- package/src/tools/output-meta.ts +50 -0
- package/src/tools/output-schema-validator.ts +152 -15
- package/src/tools/path-utils.ts +55 -10
- package/src/tools/read.ts +1 -1
- package/src/tools/render-utils.ts +5 -3
- package/src/tools/ssh.ts +8 -1
- package/src/tools/yield.ts +41 -1
- package/src/utils/commit-message-generator.ts +2 -2
- package/src/utils/git.ts +271 -29
- package/src/utils/thinking-display.ts +13 -0
- package/src/web/search/index.ts +9 -28
- package/src/web/search/provider.ts +26 -1
- package/src/web/search/providers/duckduckgo.ts +1 -1
- package/src/web/search/types.ts +5 -1
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Uses brush-core via native bindings for shell execution.
|
|
5
5
|
*/
|
|
6
|
-
import * as fs from "node:fs/promises";
|
|
7
6
|
import { ExponentialYield } from "@oh-my-pi/pi-agent-core/utils/yield";
|
|
8
7
|
import { executeShell, type MinimizerOptions, Shell, type ShellRunResult } from "@oh-my-pi/pi-natives";
|
|
9
8
|
import { isExecutable, type ShellConfig } from "@oh-my-pi/pi-utils/procmgr";
|
|
@@ -51,6 +50,7 @@ export interface BashResult {
|
|
|
51
50
|
outputLines: number;
|
|
52
51
|
outputBytes: number;
|
|
53
52
|
artifactId?: string;
|
|
53
|
+
workingDir?: string;
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
const shellSessions = new Map<string, Shell>();
|
|
@@ -115,16 +115,10 @@ function quarantineShellSession(
|
|
|
115
115
|
.catch(() => undefined);
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
// Brush preserves the working directory string verbatim, so resolve symlinks
|
|
123
|
-
// up front to keep `pwd` aligned with tools like `git worktree list`.
|
|
124
|
-
return await fs.realpath(cwd);
|
|
125
|
-
} catch {
|
|
126
|
-
return cwd;
|
|
127
|
-
}
|
|
118
|
+
function resolveShellCwd(cwd: string | undefined): string | undefined {
|
|
119
|
+
// Preserve the caller's logical cwd string. Brush uses this value to update `PWD` and its
|
|
120
|
+
// internal working directory, so realpathing here collapses symlinks before the shell sees them.
|
|
121
|
+
return cwd;
|
|
128
122
|
}
|
|
129
123
|
|
|
130
124
|
/** Translate `ShellMinimizerSettings` into native `MinimizerOptions`, or `undefined` when disabled. */
|
|
@@ -219,7 +213,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
219
213
|
|
|
220
214
|
const minimizer = buildMinimizerOptions(settings.getGroup("shellMinimizer"));
|
|
221
215
|
|
|
222
|
-
const commandCwd =
|
|
216
|
+
const commandCwd = resolveShellCwd(options?.cwd);
|
|
223
217
|
const commandEnv = buildNonInteractiveEnv(options?.env);
|
|
224
218
|
|
|
225
219
|
// Apply command prefix if configured
|
|
@@ -429,6 +423,7 @@ export async function executeBash(command: string, options?: BashExecutorOptions
|
|
|
429
423
|
return {
|
|
430
424
|
exitCode: winner.result.exitCode,
|
|
431
425
|
cancelled: false,
|
|
426
|
+
workingDir: winner.result.workingDir,
|
|
432
427
|
...(await sink.dump()),
|
|
433
428
|
};
|
|
434
429
|
} catch (err) {
|
|
@@ -12,21 +12,140 @@
|
|
|
12
12
|
* the same module identity as a direct `@oh-my-pi/pi-coding-agent` import.
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
|
-
import
|
|
15
|
+
import * as fs from "node:fs/promises";
|
|
16
|
+
import * as path from "node:path";
|
|
17
|
+
import type { AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
16
18
|
import type { TSchema } from "@oh-my-pi/pi-ai";
|
|
19
|
+
import { Text } from "@oh-my-pi/pi-tui";
|
|
17
20
|
import { parseFrontmatter as parseOmpFrontmatter } from "@oh-my-pi/pi-utils";
|
|
18
|
-
import { Settings } from "../config/settings";
|
|
19
|
-
import {
|
|
21
|
+
import { type SettingPath, Settings } from "../config/settings";
|
|
22
|
+
import { EditTool } from "../edit";
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_MAX_BYTES,
|
|
25
|
+
DEFAULT_MAX_LINES,
|
|
26
|
+
type TruncationResult,
|
|
27
|
+
truncateHead,
|
|
28
|
+
truncateTail,
|
|
29
|
+
} from "../session/streaming-output";
|
|
30
|
+
import type { Tool, ToolSession } from "../tools";
|
|
31
|
+
import { BashTool } from "../tools/bash";
|
|
32
|
+
import { GlobTool } from "../tools/glob";
|
|
33
|
+
import { GrepTool } from "../tools/grep";
|
|
34
|
+
import { ReadTool } from "../tools/read";
|
|
35
|
+
import { formatBytes } from "../tools/render-utils";
|
|
36
|
+
import { WriteTool } from "../tools/write";
|
|
20
37
|
import type { ToolDefinition } from "./extensions/types";
|
|
21
38
|
import { Type } from "./typebox";
|
|
22
39
|
|
|
23
40
|
const TOOL_DEFINITION_MARKER = "__isToolDefinition";
|
|
24
41
|
const LEGACY_BUILTIN_TOOL_MARKER = "__ompLegacyBuiltinTool";
|
|
25
42
|
const LEGACY_CODING_TOOL_NAMES = ["read", "bash", "edit", "write"] as const;
|
|
43
|
+
const LEGACY_READ_ONLY_TOOL_NAMES = ["read", "grep", "find", "ls"] as const;
|
|
26
44
|
|
|
27
45
|
type LegacyCodingToolName = (typeof LEGACY_CODING_TOOL_NAMES)[number];
|
|
46
|
+
type LegacyRegistryToolName = LegacyCodingToolName | "grep" | "glob";
|
|
28
47
|
type LegacyBuiltinToolDefinition = ToolDefinition & { [LEGACY_BUILTIN_TOOL_MARKER]: true };
|
|
29
48
|
|
|
49
|
+
type LegacySettingOverrides = Partial<Record<SettingPath, unknown>>;
|
|
50
|
+
|
|
51
|
+
interface LegacyThemeLike {
|
|
52
|
+
fg(color: string, text: string): string;
|
|
53
|
+
bold(text: string): string;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export interface BashSpawnContext {
|
|
57
|
+
command: string;
|
|
58
|
+
cwd: string;
|
|
59
|
+
env: NodeJS.ProcessEnv;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export type BashSpawnHook = (context: BashSpawnContext) => BashSpawnContext;
|
|
63
|
+
|
|
64
|
+
export interface BashOperations {
|
|
65
|
+
exec: (
|
|
66
|
+
command: string,
|
|
67
|
+
cwd: string,
|
|
68
|
+
options: {
|
|
69
|
+
onData: (data: Buffer) => void;
|
|
70
|
+
signal?: AbortSignal;
|
|
71
|
+
timeout?: number;
|
|
72
|
+
env?: NodeJS.ProcessEnv;
|
|
73
|
+
},
|
|
74
|
+
) => Promise<{ exitCode: number | null }>;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface BashToolOptions {
|
|
78
|
+
operations?: BashOperations;
|
|
79
|
+
commandPrefix?: string;
|
|
80
|
+
spawnHook?: BashSpawnHook;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface ReadToolOptions {
|
|
84
|
+
/** Auto-resize large images; maps onto the `images.autoResize` setting. Default: true. */
|
|
85
|
+
autoResizeImages?: boolean;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export interface GrepToolOptions {
|
|
89
|
+
/**
|
|
90
|
+
* Unsupported. The historical grep operations seam (isDirectory/readFile for
|
|
91
|
+
* context lines) never delegated the search itself — ripgrep always ran
|
|
92
|
+
* locally — and the built-in native grep tool exposes no filesystem seam at
|
|
93
|
+
* all. Supplying operations throws at tool creation instead of silently
|
|
94
|
+
* searching the local filesystem.
|
|
95
|
+
*/
|
|
96
|
+
operations?: unknown;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface FindOperations {
|
|
100
|
+
exists: (absolutePath: string) => Promise<boolean> | boolean;
|
|
101
|
+
glob: (pattern: string, cwd: string, options: { ignore: string[]; limit: number }) => Promise<string[]> | string[];
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export interface FindToolOptions {
|
|
105
|
+
operations?: FindOperations;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface LsOperations {
|
|
109
|
+
exists: (absolutePath: string) => Promise<boolean> | boolean;
|
|
110
|
+
stat: (absolutePath: string) => Promise<{ isDirectory(): boolean }> | { isDirectory(): boolean };
|
|
111
|
+
readdir: (absolutePath: string) => Promise<string[]> | string[];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface LsToolOptions {
|
|
115
|
+
operations?: LsOperations;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const legacyBashSchema = Type.Object({
|
|
119
|
+
command: Type.String({ description: "Bash command to execute" }),
|
|
120
|
+
timeout: Type.Optional(Type.Number({ description: "Timeout in seconds" })),
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
const legacyReadSchema = Type.Object({
|
|
124
|
+
path: Type.String({ description: "Path to read" }),
|
|
125
|
+
offset: Type.Optional(Type.Number({ description: "1-based line offset" })),
|
|
126
|
+
limit: Type.Optional(Type.Number({ description: "Maximum lines to read" })),
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
const legacyGrepSchema = Type.Object({
|
|
130
|
+
pattern: Type.String({ description: "Search pattern" }),
|
|
131
|
+
path: Type.Optional(Type.String({ description: "Directory or file to search" })),
|
|
132
|
+
glob: Type.Optional(Type.String({ description: "Glob filter" })),
|
|
133
|
+
ignoreCase: Type.Optional(Type.Boolean({ description: "Case-insensitive search" })),
|
|
134
|
+
literal: Type.Optional(Type.Boolean({ description: "Treat pattern as a literal string" })),
|
|
135
|
+
context: Type.Optional(Type.Number({ description: "Context lines" })),
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const legacyFindSchema = Type.Object({
|
|
139
|
+
pattern: Type.String({ description: "Glob pattern to match files" }),
|
|
140
|
+
path: Type.Optional(Type.String({ description: "Directory to search" })),
|
|
141
|
+
limit: Type.Optional(Type.Number({ description: "Maximum results" })),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const legacyLsSchema = Type.Object({
|
|
145
|
+
path: Type.Optional(Type.String({ description: "Directory to list" })),
|
|
146
|
+
limit: Type.Optional(Type.Number({ description: "Maximum entries" })),
|
|
147
|
+
});
|
|
148
|
+
|
|
30
149
|
function markToolDefinition<TParams extends TSchema, TDetails>(
|
|
31
150
|
tool: ToolDefinition<TParams, TDetails>,
|
|
32
151
|
): ToolDefinition<TParams, TDetails> {
|
|
@@ -38,25 +157,37 @@ function markToolDefinition<TParams extends TSchema, TDetails>(
|
|
|
38
157
|
});
|
|
39
158
|
return tool;
|
|
40
159
|
}
|
|
41
|
-
|
|
160
|
+
|
|
161
|
+
function legacyToolSession(cwd: string, settingOverrides?: LegacySettingOverrides): ToolSession {
|
|
42
162
|
return {
|
|
43
163
|
cwd,
|
|
44
164
|
hasUI: false,
|
|
45
165
|
getSessionFile: () => null,
|
|
46
166
|
getSessionSpawns: () => null,
|
|
47
|
-
settings: Settings.isolated(),
|
|
167
|
+
settings: Settings.isolated(settingOverrides),
|
|
48
168
|
};
|
|
49
169
|
}
|
|
50
170
|
|
|
51
|
-
function
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
171
|
+
function createRegistryTool(
|
|
172
|
+
cwd: string,
|
|
173
|
+
name: LegacyRegistryToolName,
|
|
174
|
+
settingOverrides?: LegacySettingOverrides,
|
|
175
|
+
): Tool {
|
|
176
|
+
const session = legacyToolSession(cwd, settingOverrides);
|
|
177
|
+
switch (name) {
|
|
178
|
+
case "bash":
|
|
179
|
+
return new BashTool(session);
|
|
180
|
+
case "edit":
|
|
181
|
+
return new EditTool(session);
|
|
182
|
+
case "glob":
|
|
183
|
+
return new GlobTool(session);
|
|
184
|
+
case "grep":
|
|
185
|
+
return new GrepTool(session);
|
|
186
|
+
case "read":
|
|
187
|
+
return new ReadTool(session);
|
|
188
|
+
case "write":
|
|
189
|
+
return new WriteTool(session);
|
|
58
190
|
}
|
|
59
|
-
return tool;
|
|
60
191
|
}
|
|
61
192
|
|
|
62
193
|
async function executeBuiltinTool(
|
|
@@ -67,12 +198,12 @@ async function executeBuiltinTool(
|
|
|
67
198
|
signal: AbortSignal | undefined,
|
|
68
199
|
onUpdate: AgentToolUpdateCallback | undefined,
|
|
69
200
|
) {
|
|
70
|
-
const tool =
|
|
201
|
+
const tool = createRegistryTool(cwd, name);
|
|
71
202
|
return tool.execute(toolCallId, params, signal, onUpdate);
|
|
72
203
|
}
|
|
73
204
|
|
|
74
205
|
function legacyBuiltinTool(cwd: string, name: LegacyCodingToolName): ToolDefinition {
|
|
75
|
-
const tool =
|
|
206
|
+
const tool = createRegistryTool(cwd, name);
|
|
76
207
|
const definition: LegacyBuiltinToolDefinition = {
|
|
77
208
|
name: tool.name,
|
|
78
209
|
label: tool.label,
|
|
@@ -88,11 +219,144 @@ function legacyBuiltinTool(cwd: string, name: LegacyCodingToolName): ToolDefinit
|
|
|
88
219
|
return markToolDefinition(definition);
|
|
89
220
|
}
|
|
90
221
|
|
|
222
|
+
function stringField(value: unknown, key: string): string | undefined {
|
|
223
|
+
if (value === null || typeof value !== "object") return undefined;
|
|
224
|
+
const field = Reflect.get(value, key);
|
|
225
|
+
return typeof field === "string" ? field : undefined;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function numberField(value: unknown, key: string): number | undefined {
|
|
229
|
+
if (value === null || typeof value !== "object") return undefined;
|
|
230
|
+
const field = Reflect.get(value, key);
|
|
231
|
+
return typeof field === "number" ? field : undefined;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
function booleanField(value: unknown, key: string): boolean | undefined {
|
|
235
|
+
if (value === null || typeof value !== "object") return undefined;
|
|
236
|
+
const field = Reflect.get(value, key);
|
|
237
|
+
return typeof field === "boolean" ? field : undefined;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function isLegacyThemeLike(value: unknown): value is LegacyThemeLike {
|
|
241
|
+
if (value === null || typeof value !== "object") return false;
|
|
242
|
+
return typeof Reflect.get(value, "fg") === "function" && typeof Reflect.get(value, "bold") === "function";
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function renderTheme(second: unknown, third: unknown): LegacyThemeLike | undefined {
|
|
246
|
+
if (isLegacyThemeLike(second)) return second;
|
|
247
|
+
if (isLegacyThemeLike(third)) return third;
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function themedTitle(theme: LegacyThemeLike | undefined, title: string): string {
|
|
252
|
+
return theme ? theme.fg("toolTitle", theme.bold(title)) : title;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function themedMuted(theme: LegacyThemeLike | undefined, text: string): string {
|
|
256
|
+
return theme ? theme.fg("toolOutput", text) : text;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function textResult(result: AgentToolResult<unknown> | undefined): string {
|
|
260
|
+
return result?.content.find(block => block.type === "text")?.text ?? "";
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function legacyRenderResult(result: AgentToolResult<unknown>, _options: unknown, themeArg: unknown): Text {
|
|
264
|
+
const theme = renderTheme(themeArg, undefined);
|
|
265
|
+
const output = textResult(result);
|
|
266
|
+
return new Text(output ? `\n${themedMuted(theme, output)}` : "", 0, 0);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
function lineRangePath(readPath: string, offset: number | undefined, limit: number | undefined): string {
|
|
270
|
+
if (offset === undefined && limit === undefined) return readPath;
|
|
271
|
+
const start = Math.max(1, Math.floor(offset ?? 1));
|
|
272
|
+
if (limit === undefined) return `${readPath}:${start}`;
|
|
273
|
+
const end = Math.max(start, start + Math.max(1, Math.floor(limit)) - 1);
|
|
274
|
+
return `${readPath}:${start}-${end}`;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function escapeRegexLiteral(value: string): string {
|
|
278
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function joinLegacyGlob(searchPath: string, pattern: string): string {
|
|
282
|
+
if (path.isAbsolute(pattern)) return pattern;
|
|
283
|
+
if (!searchPath || searchPath === ".") return pattern;
|
|
284
|
+
return path.join(searchPath, pattern);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function normalizeLegacyLimit(limit: number | undefined, fallback: number): number {
|
|
288
|
+
if (limit === undefined || !Number.isFinite(limit)) return fallback;
|
|
289
|
+
return Math.max(1, Math.floor(limit));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function appendStatus(text: string, status: string): string {
|
|
293
|
+
return text ? `${text}\n\n${status}` : status;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function legacyBashSnapshot(output: string): { text: string; details?: { truncation: TruncationResult } } {
|
|
297
|
+
const truncation = truncateTail(output, { maxLines: DEFAULT_MAX_LINES, maxBytes: DEFAULT_MAX_BYTES });
|
|
298
|
+
if (!truncation.truncated) {
|
|
299
|
+
return { text: truncation.content };
|
|
300
|
+
}
|
|
301
|
+
const startLine = truncation.totalLines - (truncation.outputLines ?? 0) + 1;
|
|
302
|
+
const note =
|
|
303
|
+
truncation.truncatedBy === "lines"
|
|
304
|
+
? `Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}`
|
|
305
|
+
: `Showing lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines} (${formatBytes(DEFAULT_MAX_BYTES)} limit)`;
|
|
306
|
+
return {
|
|
307
|
+
text: `${truncation.content}\n\n[${note}]`,
|
|
308
|
+
details: { truncation },
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
async function executeLegacyBashOperations(
|
|
313
|
+
operations: BashOperations,
|
|
314
|
+
spawn: BashSpawnContext,
|
|
315
|
+
timeout: number | undefined,
|
|
316
|
+
signal: AbortSignal | undefined,
|
|
317
|
+
onUpdate: AgentToolUpdateCallback | undefined,
|
|
318
|
+
): Promise<AgentToolResult> {
|
|
319
|
+
let output = "";
|
|
320
|
+
const onData = (data: Buffer) => {
|
|
321
|
+
output += data.toString("utf8");
|
|
322
|
+
if (onUpdate) {
|
|
323
|
+
const snapshot = legacyBashSnapshot(output);
|
|
324
|
+
onUpdate({ content: [{ type: "text", text: snapshot.text }], details: snapshot.details });
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
try {
|
|
328
|
+
const result = await operations.exec(spawn.command, spawn.cwd, {
|
|
329
|
+
onData,
|
|
330
|
+
signal,
|
|
331
|
+
timeout,
|
|
332
|
+
env: spawn.env,
|
|
333
|
+
});
|
|
334
|
+
const snapshot = legacyBashSnapshot(output);
|
|
335
|
+
const text = snapshot.text || "(no output)";
|
|
336
|
+
if (result.exitCode !== 0 && result.exitCode !== null) {
|
|
337
|
+
throw new Error(appendStatus(text, `Command exited with code ${result.exitCode}`));
|
|
338
|
+
}
|
|
339
|
+
return { content: [{ type: "text", text }], details: snapshot.details };
|
|
340
|
+
} catch (err) {
|
|
341
|
+
const snapshot = legacyBashSnapshot(output);
|
|
342
|
+
const text = snapshot.text;
|
|
343
|
+
if (err instanceof Error && err.message === "aborted") {
|
|
344
|
+
throw new Error(appendStatus(text, "Command aborted"));
|
|
345
|
+
}
|
|
346
|
+
if (err instanceof Error && err.message.startsWith("timeout:")) {
|
|
347
|
+
throw new Error(appendStatus(text, `Command timed out after ${err.message.slice("timeout:".length)} seconds`));
|
|
348
|
+
}
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
/** Parse frontmatter using the historical Pi package-root helper. */
|
|
91
354
|
export interface ParsedFrontmatter<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
92
355
|
frontmatter: T;
|
|
93
356
|
body: string;
|
|
94
357
|
}
|
|
95
358
|
|
|
359
|
+
/** Parse YAML frontmatter and throw on invalid metadata. */
|
|
96
360
|
export function parseFrontmatter<T extends Record<string, unknown> = Record<string, unknown>>(
|
|
97
361
|
content: string,
|
|
98
362
|
): ParsedFrontmatter<T> {
|
|
@@ -100,20 +364,273 @@ export function parseFrontmatter<T extends Record<string, unknown> = Record<stri
|
|
|
100
364
|
return { frontmatter: frontmatter as T, body };
|
|
101
365
|
}
|
|
102
366
|
|
|
367
|
+
/** Return content without YAML frontmatter. */
|
|
103
368
|
export function stripFrontmatter(content: string): string {
|
|
104
369
|
return parseFrontmatter(content).body;
|
|
105
370
|
}
|
|
106
371
|
|
|
372
|
+
/** Mark an extension-authored tool as a Pi-compatible tool definition. */
|
|
107
373
|
export function defineTool<TParams extends TSchema = TSchema, TDetails = unknown>(
|
|
108
374
|
tool: ToolDefinition<TParams, TDetails>,
|
|
109
375
|
): ToolDefinition<TParams, TDetails> {
|
|
110
376
|
return markToolDefinition(tool);
|
|
111
377
|
}
|
|
112
378
|
|
|
379
|
+
/** Create the legacy read tool definition. */
|
|
380
|
+
export function createReadToolDefinition(cwd: string, options?: ReadToolOptions): ToolDefinition {
|
|
381
|
+
const tool = createRegistryTool(
|
|
382
|
+
cwd,
|
|
383
|
+
"read",
|
|
384
|
+
options?.autoResizeImages === undefined ? undefined : { "images.autoResize": options.autoResizeImages },
|
|
385
|
+
);
|
|
386
|
+
return markToolDefinition({
|
|
387
|
+
name: "read",
|
|
388
|
+
label: "Read",
|
|
389
|
+
description: tool.description,
|
|
390
|
+
parameters: legacyReadSchema,
|
|
391
|
+
approval: "read",
|
|
392
|
+
renderCall: (params, options, themeArg) => {
|
|
393
|
+
const theme = renderTheme(options, themeArg);
|
|
394
|
+
const readPath = stringField(params, "path") ?? "";
|
|
395
|
+
return new Text(`${themedTitle(theme, "read")} ${themedMuted(theme, readPath)}`, 0, 0);
|
|
396
|
+
},
|
|
397
|
+
renderResult: legacyRenderResult,
|
|
398
|
+
execute: (toolCallId, params, signal, onUpdate) => {
|
|
399
|
+
const readPath = stringField(params, "path") ?? "";
|
|
400
|
+
const pathWithRange = lineRangePath(readPath, numberField(params, "offset"), numberField(params, "limit"));
|
|
401
|
+
return tool.execute(toolCallId, { path: pathWithRange }, signal, onUpdate);
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
/** Create the legacy read tool. */
|
|
407
|
+
export function createReadTool(cwd: string, options?: ReadToolOptions): ToolDefinition {
|
|
408
|
+
return createReadToolDefinition(cwd, options);
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/** Create the legacy bash tool definition. */
|
|
412
|
+
export function createBashToolDefinition(cwd: string, options?: BashToolOptions): ToolDefinition {
|
|
413
|
+
const tool = createRegistryTool(cwd, "bash");
|
|
414
|
+
return markToolDefinition({
|
|
415
|
+
name: "bash",
|
|
416
|
+
label: "Bash",
|
|
417
|
+
description: tool.description,
|
|
418
|
+
parameters: legacyBashSchema,
|
|
419
|
+
approval: "exec",
|
|
420
|
+
renderCall: (params, optionsArg, themeArg) => {
|
|
421
|
+
const theme = renderTheme(optionsArg, themeArg);
|
|
422
|
+
const command = stringField(params, "command") ?? "";
|
|
423
|
+
return new Text(`${themedTitle(theme, "bash")} ${themedMuted(theme, command)}`, 0, 0);
|
|
424
|
+
},
|
|
425
|
+
renderResult: legacyRenderResult,
|
|
426
|
+
execute: (toolCallId, params, signal, onUpdate) => {
|
|
427
|
+
const rawCommand = stringField(params, "command") ?? "";
|
|
428
|
+
const command = options?.commandPrefix ? `${options.commandPrefix}\n${rawCommand}` : rawCommand;
|
|
429
|
+
const timeout = numberField(params, "timeout");
|
|
430
|
+
const spawn = options?.spawnHook?.({ command, cwd, env: process.env });
|
|
431
|
+
if (options?.operations) {
|
|
432
|
+
return executeLegacyBashOperations(
|
|
433
|
+
options.operations,
|
|
434
|
+
{ command: spawn?.command ?? command, cwd: spawn?.cwd ?? cwd, env: spawn?.env ?? process.env },
|
|
435
|
+
timeout,
|
|
436
|
+
signal,
|
|
437
|
+
onUpdate,
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
return tool.execute(
|
|
441
|
+
toolCallId,
|
|
442
|
+
{
|
|
443
|
+
command: spawn?.command ?? command,
|
|
444
|
+
cwd: spawn?.cwd ?? cwd,
|
|
445
|
+
env: spawn?.env,
|
|
446
|
+
timeout,
|
|
447
|
+
},
|
|
448
|
+
signal,
|
|
449
|
+
onUpdate,
|
|
450
|
+
);
|
|
451
|
+
},
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
/** Create the legacy bash tool. */
|
|
456
|
+
export function createBashTool(cwd: string, options?: BashToolOptions): ToolDefinition {
|
|
457
|
+
return createBashToolDefinition(cwd, options);
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/** Create the legacy grep tool definition. */
|
|
461
|
+
export function createGrepToolDefinition(cwd: string, options?: GrepToolOptions): ToolDefinition {
|
|
462
|
+
if (options?.operations) {
|
|
463
|
+
throw new Error(
|
|
464
|
+
"Legacy GrepToolOptions.operations is not supported: the built-in grep tool searches the local " +
|
|
465
|
+
"filesystem natively and exposes no pluggable filesystem seam (the historical seam only customized " +
|
|
466
|
+
"context-line reads; the search itself always ran locally). Register a custom grep tool via " +
|
|
467
|
+
"defineTool() instead of passing operations to createGrepTool()/createGrepToolDefinition().",
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
const tool = createRegistryTool(cwd, "grep");
|
|
471
|
+
return markToolDefinition({
|
|
472
|
+
name: "grep",
|
|
473
|
+
label: "grep",
|
|
474
|
+
description: "Search file contents for a pattern.",
|
|
475
|
+
parameters: legacyGrepSchema,
|
|
476
|
+
approval: "read",
|
|
477
|
+
renderCall: (params, optionsArg, themeArg) => {
|
|
478
|
+
const theme = renderTheme(optionsArg, themeArg);
|
|
479
|
+
const pattern = stringField(params, "pattern") ?? "";
|
|
480
|
+
const searchPath = stringField(params, "path") ?? ".";
|
|
481
|
+
return new Text(`${themedTitle(theme, "grep")} ${themedMuted(theme, `/${pattern}/ in ${searchPath}`)}`, 0, 0);
|
|
482
|
+
},
|
|
483
|
+
renderResult: legacyRenderResult,
|
|
484
|
+
execute: (toolCallId, params, signal, onUpdate) => {
|
|
485
|
+
const rawPattern = stringField(params, "pattern") ?? "";
|
|
486
|
+
const pattern = booleanField(params, "literal") ? escapeRegexLiteral(rawPattern) : rawPattern;
|
|
487
|
+
const searchPath = stringField(params, "path") ?? ".";
|
|
488
|
+
const glob = stringField(params, "glob");
|
|
489
|
+
const context = numberField(params, "context");
|
|
490
|
+
// The new grep reads context from settings fixed at construction; build a
|
|
491
|
+
// per-call tool when the model passes an explicit legacy `context`.
|
|
492
|
+
const grepTool =
|
|
493
|
+
context === undefined
|
|
494
|
+
? tool
|
|
495
|
+
: createRegistryTool(cwd, "grep", {
|
|
496
|
+
"grep.contextBefore": Math.max(0, Math.floor(context)),
|
|
497
|
+
"grep.contextAfter": Math.max(0, Math.floor(context)),
|
|
498
|
+
});
|
|
499
|
+
return grepTool.execute(
|
|
500
|
+
toolCallId,
|
|
501
|
+
{
|
|
502
|
+
pattern,
|
|
503
|
+
paths: glob ? joinLegacyGlob(searchPath, glob) : searchPath,
|
|
504
|
+
case: booleanField(params, "ignoreCase") ? false : undefined,
|
|
505
|
+
},
|
|
506
|
+
signal,
|
|
507
|
+
onUpdate,
|
|
508
|
+
);
|
|
509
|
+
},
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/** Create the legacy grep tool. */
|
|
514
|
+
export function createGrepTool(cwd: string, options?: GrepToolOptions): ToolDefinition {
|
|
515
|
+
return createGrepToolDefinition(cwd, options);
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/** Create the legacy find tool definition. */
|
|
519
|
+
export function createFindToolDefinition(cwd: string, options?: FindToolOptions): ToolDefinition {
|
|
520
|
+
const tool = createRegistryTool(cwd, "glob");
|
|
521
|
+
return markToolDefinition({
|
|
522
|
+
name: "find",
|
|
523
|
+
label: "find",
|
|
524
|
+
description: "Find files by glob pattern.",
|
|
525
|
+
parameters: legacyFindSchema,
|
|
526
|
+
approval: "read",
|
|
527
|
+
renderCall: (params, optionsArg, themeArg) => {
|
|
528
|
+
const theme = renderTheme(optionsArg, themeArg);
|
|
529
|
+
const pattern = stringField(params, "pattern") ?? "";
|
|
530
|
+
const searchPath = stringField(params, "path") ?? ".";
|
|
531
|
+
return new Text(`${themedTitle(theme, "find")} ${themedMuted(theme, `${pattern} in ${searchPath}`)}`, 0, 0);
|
|
532
|
+
},
|
|
533
|
+
renderResult: legacyRenderResult,
|
|
534
|
+
execute: async (toolCallId, params, signal, onUpdate) => {
|
|
535
|
+
const pattern = stringField(params, "pattern") ?? "*";
|
|
536
|
+
const searchPath = stringField(params, "path") ?? ".";
|
|
537
|
+
const limit = normalizeLegacyLimit(numberField(params, "limit"), 1000);
|
|
538
|
+
const absolutePath = path.resolve(cwd, searchPath);
|
|
539
|
+
if (options?.operations) {
|
|
540
|
+
if (!(await options.operations.exists(absolutePath))) {
|
|
541
|
+
throw new Error(`Path not found: ${absolutePath}`);
|
|
542
|
+
}
|
|
543
|
+
const matches = await options.operations.glob(pattern, absolutePath, {
|
|
544
|
+
ignore: ["**/node_modules/**", "**/.git/**"],
|
|
545
|
+
limit,
|
|
546
|
+
});
|
|
547
|
+
const output = matches
|
|
548
|
+
.map(match => {
|
|
549
|
+
const rel = path.isAbsolute(match) ? path.relative(absolutePath, match) : match;
|
|
550
|
+
return rel.split(path.sep).join("/");
|
|
551
|
+
})
|
|
552
|
+
.join("\n");
|
|
553
|
+
const truncation = truncateHead(output, { maxLines: Number.MAX_SAFE_INTEGER });
|
|
554
|
+
return {
|
|
555
|
+
content: [{ type: "text", text: truncation.content || "No files found matching pattern" }],
|
|
556
|
+
details: truncation.truncated ? { truncation } : undefined,
|
|
557
|
+
};
|
|
558
|
+
}
|
|
559
|
+
return tool.execute(
|
|
560
|
+
toolCallId,
|
|
561
|
+
{ paths: [joinLegacyGlob(searchPath, pattern)], hidden: true, gitignore: true, limit },
|
|
562
|
+
signal,
|
|
563
|
+
onUpdate,
|
|
564
|
+
);
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
/** Create the legacy find tool. */
|
|
570
|
+
export function createFindTool(cwd: string, options?: FindToolOptions): ToolDefinition {
|
|
571
|
+
return createFindToolDefinition(cwd, options);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/** Create the legacy ls tool definition. */
|
|
575
|
+
export function createLsToolDefinition(cwd: string, options?: LsToolOptions): ToolDefinition {
|
|
576
|
+
return markToolDefinition({
|
|
577
|
+
name: "ls",
|
|
578
|
+
label: "ls",
|
|
579
|
+
description: "List directory entries.",
|
|
580
|
+
parameters: legacyLsSchema,
|
|
581
|
+
approval: "read",
|
|
582
|
+
renderCall: (params, optionsArg, themeArg) => {
|
|
583
|
+
const theme = renderTheme(optionsArg, themeArg);
|
|
584
|
+
return new Text(`${themedTitle(theme, "ls")} ${themedMuted(theme, stringField(params, "path") ?? ".")}`, 0, 0);
|
|
585
|
+
},
|
|
586
|
+
renderResult: legacyRenderResult,
|
|
587
|
+
execute: async (_toolCallId, params, _signal, _onUpdate) => {
|
|
588
|
+
const rawPath = stringField(params, "path") ?? ".";
|
|
589
|
+
const limit = normalizeLegacyLimit(numberField(params, "limit"), 500);
|
|
590
|
+
const absolutePath = path.resolve(cwd, rawPath);
|
|
591
|
+
const ops = options?.operations;
|
|
592
|
+
const exists = ops
|
|
593
|
+
? await ops.exists(absolutePath)
|
|
594
|
+
: await fs.stat(absolutePath).then(
|
|
595
|
+
() => true,
|
|
596
|
+
() => false,
|
|
597
|
+
);
|
|
598
|
+
if (!exists) throw new Error(`Path not found: ${absolutePath}`);
|
|
599
|
+
const stat = ops ? await ops.stat(absolutePath) : await fs.stat(absolutePath);
|
|
600
|
+
if (!stat.isDirectory()) {
|
|
601
|
+
return { content: [{ type: "text", text: rawPath }] };
|
|
602
|
+
}
|
|
603
|
+
const entries = ops ? await ops.readdir(absolutePath) : await fs.readdir(absolutePath);
|
|
604
|
+
const sorted = [...entries].sort((a, b) => a.localeCompare(b));
|
|
605
|
+
const limited = sorted.slice(0, limit);
|
|
606
|
+
const output = limited.join("\n");
|
|
607
|
+
const details = sorted.length > limited.length ? { entryLimitReached: limit } : undefined;
|
|
608
|
+
const suffix = details ? `\n\n[${limit} entries limit reached]` : "";
|
|
609
|
+
return { content: [{ type: "text", text: `${output}${suffix}` }], details };
|
|
610
|
+
},
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
/** Create the legacy ls tool. */
|
|
615
|
+
export function createLsTool(cwd: string, options?: LsToolOptions): ToolDefinition {
|
|
616
|
+
return createLsToolDefinition(cwd, options);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
/** Create legacy read, bash, edit, and write tools. */
|
|
113
620
|
export function createCodingTools(cwd: string): ToolDefinition[] {
|
|
114
621
|
return LEGACY_CODING_TOOL_NAMES.map(name => legacyBuiltinTool(cwd, name));
|
|
115
622
|
}
|
|
116
623
|
|
|
624
|
+
/** Create legacy read, grep, find, and ls tools. */
|
|
625
|
+
export function createReadOnlyTools(cwd: string): ToolDefinition[] {
|
|
626
|
+
return LEGACY_READ_ONLY_TOOL_NAMES.map(name => {
|
|
627
|
+
if (name === "read") return createReadTool(cwd);
|
|
628
|
+
if (name === "grep") return createGrepTool(cwd);
|
|
629
|
+
if (name === "find") return createFindTool(cwd);
|
|
630
|
+
return createLsTool(cwd);
|
|
631
|
+
});
|
|
632
|
+
}
|
|
633
|
+
|
|
117
634
|
export const SettingsManager = {
|
|
118
635
|
create(cwd: string, agentDir?: string): Promise<Settings> {
|
|
119
636
|
return Settings.init({ cwd, agentDir });
|
|
@@ -125,4 +642,5 @@ export const SettingsManager = {
|
|
|
125
642
|
} as const;
|
|
126
643
|
|
|
127
644
|
export * from "../index";
|
|
128
|
-
export {
|
|
645
|
+
export { formatBytes as formatSize } from "../tools/render-utils";
|
|
646
|
+
export { Type } from "./typebox";
|