@oh-my-pi/pi-coding-agent 13.19.0 → 14.0.3
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 +277 -2
- package/package.json +86 -20
- package/scripts/format-prompts.ts +2 -2
- package/src/autoresearch/apply-contract-to-state.ts +24 -0
- package/src/autoresearch/contract.ts +0 -44
- package/src/autoresearch/dashboard.ts +1 -2
- package/src/autoresearch/git.ts +91 -0
- package/src/autoresearch/helpers.ts +49 -0
- package/src/autoresearch/index.ts +28 -187
- package/src/autoresearch/prompt.md +26 -9
- package/src/autoresearch/state.ts +0 -6
- package/src/autoresearch/tools/init-experiment.ts +202 -117
- package/src/autoresearch/tools/log-experiment.ts +83 -125
- package/src/autoresearch/tools/run-experiment.ts +48 -10
- package/src/autoresearch/types.ts +2 -2
- package/src/capability/index.ts +4 -2
- package/src/cli/file-processor.ts +3 -3
- package/src/cli/grep-cli.ts +8 -8
- package/src/cli/grievances-cli.ts +78 -0
- package/src/cli/read-cli.ts +67 -0
- package/src/cli/setup-cli.ts +4 -4
- package/src/cli/update-cli.ts +3 -3
- package/src/cli.ts +2 -0
- package/src/commands/grep.ts +6 -1
- package/src/commands/grievances.ts +20 -0
- package/src/commands/read.ts +33 -0
- package/src/commit/agentic/agent.ts +5 -5
- package/src/commit/agentic/index.ts +3 -4
- package/src/commit/agentic/tools/analyze-file.ts +3 -3
- package/src/commit/agentic/validation.ts +1 -1
- package/src/commit/analysis/conventional.ts +4 -4
- package/src/commit/analysis/summary.ts +3 -3
- package/src/commit/changelog/generate.ts +4 -4
- package/src/commit/map-reduce/map-phase.ts +4 -4
- package/src/commit/map-reduce/reduce-phase.ts +4 -4
- package/src/commit/pipeline.ts +3 -4
- package/src/config/model-registry.ts +17 -3
- package/src/config/prompt-templates.ts +44 -226
- package/src/config/resolve-config-value.ts +4 -2
- package/src/config/settings-schema.ts +54 -2
- package/src/config/settings.ts +25 -26
- package/src/dap/client.ts +674 -0
- package/src/dap/config.ts +150 -0
- package/src/dap/defaults.json +211 -0
- package/src/dap/index.ts +4 -0
- package/src/dap/session.ts +1255 -0
- package/src/dap/types.ts +600 -0
- package/src/debug/log-viewer.ts +3 -2
- package/src/discovery/builtin.ts +1 -2
- package/src/discovery/codex.ts +2 -2
- package/src/discovery/github.ts +2 -1
- package/src/discovery/helpers.ts +2 -2
- package/src/discovery/opencode.ts +2 -2
- package/src/edit/diff.ts +818 -0
- package/src/edit/index.ts +309 -0
- package/src/edit/line-hash.ts +67 -0
- package/src/edit/modes/chunk.ts +454 -0
- package/src/{patch → edit/modes}/hashline.ts +741 -361
- package/src/{patch/applicator.ts → edit/modes/patch.ts} +420 -117
- package/src/{patch/fuzzy.ts → edit/modes/replace.ts} +519 -197
- package/src/{patch → edit}/normalize.ts +97 -76
- package/src/{patch/shared.ts → edit/renderer.ts} +181 -108
- package/src/exec/bash-executor.ts +4 -2
- package/src/exec/idle-timeout-watchdog.ts +126 -0
- package/src/exec/non-interactive-env.ts +5 -0
- package/src/extensibility/custom-commands/bundled/ci-green/index.ts +2 -2
- package/src/extensibility/custom-commands/bundled/review/index.ts +36 -15
- package/src/extensibility/custom-commands/loader.ts +1 -2
- package/src/extensibility/custom-tools/loader.ts +34 -11
- package/src/extensibility/extensions/loader.ts +9 -4
- package/src/extensibility/extensions/runner.ts +24 -1
- package/src/extensibility/extensions/types.ts +1 -1
- package/src/extensibility/hooks/loader.ts +5 -6
- package/src/extensibility/hooks/types.ts +1 -1
- package/src/extensibility/plugins/doctor.ts +2 -1
- package/src/extensibility/slash-commands.ts +3 -7
- package/src/index.ts +2 -1
- package/src/internal-urls/docs-index.generated.ts +11 -11
- package/src/ipy/executor.ts +58 -17
- package/src/ipy/gateway-coordinator.ts +6 -4
- package/src/ipy/kernel.ts +45 -22
- package/src/ipy/runtime.ts +2 -2
- package/src/lsp/client.ts +7 -4
- package/src/lsp/clients/lsp-linter-client.ts +4 -4
- package/src/lsp/config.ts +20 -4
- package/src/lsp/defaults.json +688 -154
- package/src/lsp/index.ts +234 -45
- package/src/lsp/lspmux.ts +2 -2
- package/src/lsp/startup-events.ts +13 -0
- package/src/lsp/types.ts +12 -1
- package/src/lsp/utils.ts +8 -1
- package/src/main.ts +102 -46
- package/src/memories/index.ts +4 -5
- package/src/modes/acp/acp-agent.ts +563 -163
- package/src/modes/acp/acp-event-mapper.ts +9 -1
- package/src/modes/acp/acp-mode.ts +4 -2
- package/src/modes/components/agent-dashboard.ts +3 -4
- package/src/modes/components/diff.ts +6 -7
- package/src/modes/components/read-tool-group.ts +6 -12
- package/src/modes/components/session-observer-overlay.ts +21 -12
- package/src/modes/components/settings-defs.ts +5 -0
- package/src/modes/components/tool-execution.ts +1 -1
- package/src/modes/components/welcome.ts +1 -1
- package/src/modes/controllers/btw-controller.ts +2 -2
- package/src/modes/controllers/command-controller.ts +3 -2
- package/src/modes/controllers/input-controller.ts +12 -8
- package/src/modes/index.ts +20 -2
- package/src/modes/interactive-mode.ts +94 -37
- package/src/modes/rpc/host-tools.ts +186 -0
- package/src/modes/rpc/rpc-client.ts +178 -13
- package/src/modes/rpc/rpc-mode.ts +73 -3
- package/src/modes/rpc/rpc-types.ts +53 -1
- package/src/modes/theme/theme.ts +80 -8
- package/src/modes/types.ts +2 -2
- package/src/prompts/review-request.md +6 -0
- package/src/prompts/system/system-prompt.md +2 -1
- package/src/prompts/tools/chunk-edit.md +223 -0
- package/src/prompts/tools/debug.md +43 -0
- package/src/prompts/tools/grep.md +3 -0
- package/src/prompts/tools/lsp.md +5 -5
- package/src/prompts/tools/read-chunk.md +17 -0
- package/src/prompts/tools/read.md +19 -5
- package/src/sdk.ts +190 -154
- package/src/secrets/obfuscator.ts +1 -1
- package/src/session/agent-session.ts +306 -256
- package/src/session/agent-storage.ts +12 -12
- package/src/session/compaction/branch-summarization.ts +3 -3
- package/src/session/compaction/compaction.ts +5 -6
- package/src/session/compaction/utils.ts +3 -3
- package/src/session/history-storage.ts +62 -19
- package/src/session/messages.ts +3 -3
- package/src/session/session-dump-format.ts +203 -0
- package/src/session/session-storage.ts +4 -2
- package/src/session/streaming-output.ts +1 -1
- package/src/session/tool-choice-queue.ts +213 -0
- package/src/slash-commands/builtin-registry.ts +56 -8
- package/src/ssh/connection-manager.ts +2 -2
- package/src/ssh/sshfs-mount.ts +5 -5
- package/src/stt/downloader.ts +4 -4
- package/src/stt/recorder.ts +4 -4
- package/src/stt/transcriber.ts +2 -2
- package/src/system-prompt.ts +21 -13
- package/src/task/agents.ts +5 -6
- package/src/task/commands.ts +2 -5
- package/src/task/executor.ts +4 -4
- package/src/task/index.ts +3 -4
- package/src/task/template.ts +2 -2
- package/src/task/worktree.ts +4 -4
- package/src/tools/ask.ts +2 -3
- package/src/tools/ast-edit.ts +7 -7
- package/src/tools/ast-grep.ts +7 -7
- package/src/tools/auto-generated-guard.ts +36 -41
- package/src/tools/await-tool.ts +2 -2
- package/src/tools/bash.ts +5 -23
- package/src/tools/browser.ts +4 -5
- package/src/tools/calculator.ts +2 -3
- package/src/tools/cancel-job.ts +2 -2
- package/src/tools/checkpoint.ts +3 -3
- package/src/tools/debug.ts +1007 -0
- package/src/tools/exit-plan-mode.ts +2 -3
- package/src/tools/fetch.ts +67 -3
- package/src/tools/find.ts +4 -5
- package/src/tools/fs-cache-invalidation.ts +5 -0
- package/src/tools/gemini-image.ts +13 -5
- package/src/tools/gh.ts +10 -11
- package/src/tools/grep.ts +57 -9
- package/src/tools/index.ts +44 -22
- package/src/tools/inspect-image.ts +4 -4
- package/src/tools/output-meta.ts +1 -1
- package/src/tools/python.ts +19 -6
- package/src/tools/read.ts +198 -67
- package/src/tools/render-mermaid.ts +2 -3
- package/src/tools/render-utils.ts +20 -6
- package/src/tools/renderers.ts +3 -1
- package/src/tools/report-tool-issue.ts +80 -0
- package/src/tools/resolve.ts +70 -39
- package/src/tools/search-tool-bm25.ts +2 -2
- package/src/tools/ssh.ts +2 -2
- package/src/tools/todo-write.ts +2 -2
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/write.ts +5 -6
- package/src/tui/tree-list.ts +3 -1
- package/src/utils/clipboard.ts +80 -0
- package/src/utils/commit-message-generator.ts +2 -3
- package/src/utils/edit-mode.ts +49 -0
- package/src/utils/file-display-mode.ts +6 -5
- package/src/utils/file-mentions.ts +8 -7
- package/src/utils/git.ts +4 -4
- package/src/utils/image-loading.ts +98 -0
- package/src/utils/title-generator.ts +2 -3
- package/src/utils/tools-manager.ts +6 -6
- package/src/web/scrapers/choosealicense.ts +1 -1
- package/src/web/search/index.ts +3 -3
- package/src/autoresearch/command-initialize.md +0 -34
- package/src/patch/diff.ts +0 -433
- package/src/patch/index.ts +0 -888
- package/src/patch/parser.ts +0 -532
- package/src/patch/types.ts +0 -292
- package/src/prompts/agents/oracle.md +0 -77
- package/src/tools/pending-action.ts +0 -49
- package/src/utils/child-process.ts +0 -88
- package/src/utils/frontmatter.ts +0 -117
- package/src/utils/image-input.ts +0 -274
- package/src/utils/mime.ts +0 -53
- package/src/utils/prompt-format.ts +0 -170
package/src/task/worktree.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as fs from "node:fs/promises";
|
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
5
|
import { projfsOverlayStart, projfsOverlayStop } from "@oh-my-pi/pi-natives";
|
|
6
|
-
import { getWorktreeDir, isEnoent, logger, Snowflake } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import { $which, getWorktreeDir, isEnoent, logger, Snowflake } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { $ } from "bun";
|
|
8
8
|
import * as git from "../utils/git";
|
|
9
9
|
|
|
@@ -348,7 +348,7 @@ export async function ensureFuseOverlay(baseCwd: string, id: string): Promise<st
|
|
|
348
348
|
const mergedDir = path.join(baseDir, "merged");
|
|
349
349
|
|
|
350
350
|
// Clean up any stale mount at this path (linux only)
|
|
351
|
-
const fusermount =
|
|
351
|
+
const fusermount = $which("fusermount3") ?? $which("fusermount");
|
|
352
352
|
if (fusermount) {
|
|
353
353
|
await $`${fusermount} -u ${mergedDir}`.quiet().nothrow();
|
|
354
354
|
}
|
|
@@ -358,7 +358,7 @@ export async function ensureFuseOverlay(baseCwd: string, id: string): Promise<st
|
|
|
358
358
|
await fs.mkdir(workDir, { recursive: true });
|
|
359
359
|
await fs.mkdir(mergedDir, { recursive: true });
|
|
360
360
|
|
|
361
|
-
const binary =
|
|
361
|
+
const binary = $which("fuse-overlayfs");
|
|
362
362
|
if (!binary) {
|
|
363
363
|
await fs.rm(baseDir, { recursive: true, force: true });
|
|
364
364
|
throw new Error(
|
|
@@ -380,7 +380,7 @@ export async function ensureFuseOverlay(baseCwd: string, id: string): Promise<st
|
|
|
380
380
|
|
|
381
381
|
export async function cleanupFuseOverlay(mergedDir: string): Promise<void> {
|
|
382
382
|
try {
|
|
383
|
-
const fusermount =
|
|
383
|
+
const fusermount = $which("fusermount3") ?? $which("fusermount");
|
|
384
384
|
if (fusermount) {
|
|
385
385
|
await $`${fusermount} -u ${mergedDir}`.quiet().nothrow();
|
|
386
386
|
}
|
package/src/tools/ask.ts
CHANGED
|
@@ -17,9 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
19
19
|
import { type Component, Container, Markdown, renderInlineMarkdown, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
20
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
20
|
+
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
21
21
|
import { type Static, Type } from "@sinclair/typebox";
|
|
22
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
23
22
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
24
23
|
import { getMarkdownTheme, type Theme, theme } from "../modes/theme/theme";
|
|
25
24
|
import askDescription from "../prompts/tools/ask.md" with { type: "text" };
|
|
@@ -385,7 +384,7 @@ export class AskTool implements AgentTool<typeof askSchema, AskToolDetails> {
|
|
|
385
384
|
readonly strict = true;
|
|
386
385
|
|
|
387
386
|
constructor(private readonly session: ToolSession) {
|
|
388
|
-
this.description =
|
|
387
|
+
this.description = prompt.render(askDescription);
|
|
389
388
|
}
|
|
390
389
|
|
|
391
390
|
static createIf(session: ToolSession): AskTool | null {
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -3,12 +3,11 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
3
3
|
import { type AstReplaceChange, astEdit } from "@oh-my-pi/pi-natives";
|
|
4
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
8
|
-
import {
|
|
8
|
+
import { computeLineHash } from "../edit/line-hash";
|
|
9
9
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
10
|
import type { Theme } from "../modes/theme/theme";
|
|
11
|
-
import { computeLineHash } from "../patch/hashline";
|
|
12
11
|
import astEditDescription from "../prompts/tools/ast-edit.md" with { type: "text" };
|
|
13
12
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
14
13
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
@@ -31,6 +30,7 @@ import {
|
|
|
31
30
|
PARSE_ERRORS_LIMIT,
|
|
32
31
|
PREVIEW_LIMITS,
|
|
33
32
|
} from "./render-utils";
|
|
33
|
+
import { queueResolveHandler } from "./resolve";
|
|
34
34
|
import { ToolError } from "./tool-errors";
|
|
35
35
|
import { toolResult } from "./tool-result";
|
|
36
36
|
|
|
@@ -71,7 +71,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
71
71
|
readonly strict = true;
|
|
72
72
|
readonly deferrable = true;
|
|
73
73
|
constructor(private readonly session: ToolSession) {
|
|
74
|
-
this.description =
|
|
74
|
+
this.description = prompt.render(astEditDescription);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
async execute(
|
|
@@ -201,7 +201,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
201
201
|
filesSearched: result.filesSearched,
|
|
202
202
|
applied: result.applied,
|
|
203
203
|
limitReached: result.limitReached,
|
|
204
|
-
parseErrors: dedupedParseErrors,
|
|
204
|
+
...(dedupedParseErrors.length > 0 ? { parseErrors: dedupedParseErrors } : {}),
|
|
205
205
|
scopePath,
|
|
206
206
|
files: fileList,
|
|
207
207
|
fileReplacements: [],
|
|
@@ -289,7 +289,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
289
289
|
if (!result.applied && result.totalReplacements > 0) {
|
|
290
290
|
const previewReplacementPlural = result.totalReplacements !== 1 ? "s" : "";
|
|
291
291
|
const previewFilePlural = result.filesTouched !== 1 ? "s" : "";
|
|
292
|
-
this.session
|
|
292
|
+
queueResolveHandler(this.session, {
|
|
293
293
|
label: `AST Edit: ${result.totalReplacements} replacement${previewReplacementPlural} in ${result.filesTouched} file${previewFilePlural}`,
|
|
294
294
|
sourceToolName: this.name,
|
|
295
295
|
apply: async (_reason: string) => {
|
|
@@ -311,7 +311,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
311
311
|
filesSearched: applyResult.filesSearched,
|
|
312
312
|
applied: applyResult.applied,
|
|
313
313
|
limitReached: applyResult.limitReached,
|
|
314
|
-
parseErrors: dedupedApplyParseErrors,
|
|
314
|
+
...(dedupedApplyParseErrors.length > 0 ? { parseErrors: dedupedApplyParseErrors } : {}),
|
|
315
315
|
scopePath,
|
|
316
316
|
files: fileList,
|
|
317
317
|
fileReplacements,
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -3,12 +3,11 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
3
3
|
import { type AstFindMatch, astGrep } from "@oh-my-pi/pi-natives";
|
|
4
4
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
5
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
6
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
6
|
+
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
7
|
import { type Static, Type } from "@sinclair/typebox";
|
|
8
|
-
import {
|
|
8
|
+
import { computeLineHash } from "../edit/line-hash";
|
|
9
9
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
10
10
|
import type { Theme } from "../modes/theme/theme";
|
|
11
|
-
import { computeLineHash } from "../patch/hashline";
|
|
12
11
|
import astGrepDescription from "../prompts/tools/ast-grep.md" with { type: "text" };
|
|
13
12
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, renderTreeList, truncateToWidth } from "../tui";
|
|
14
13
|
import { resolveFileDisplayMode } from "../utils/file-display-mode";
|
|
@@ -65,7 +64,7 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
65
64
|
readonly strict = true;
|
|
66
65
|
|
|
67
66
|
constructor(private readonly session: ToolSession) {
|
|
68
|
-
this.description =
|
|
67
|
+
this.description = prompt.render(astGrepDescription);
|
|
69
68
|
}
|
|
70
69
|
|
|
71
70
|
async execute(
|
|
@@ -188,7 +187,7 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
188
187
|
fileCount: result.filesWithMatches,
|
|
189
188
|
filesSearched: result.filesSearched,
|
|
190
189
|
limitReached: result.limitReached,
|
|
191
|
-
parseErrors: dedupedParseErrors,
|
|
190
|
+
...(dedupedParseErrors.length > 0 ? { parseErrors: dedupedParseErrors } : {}),
|
|
192
191
|
scopePath,
|
|
193
192
|
files: fileList,
|
|
194
193
|
fileMatches: [],
|
|
@@ -213,12 +212,13 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
213
212
|
const lineNumbers = matchLines.map((_, index) => match.startLine + index);
|
|
214
213
|
const lineWidth = Math.max(...lineNumbers.map(value => value.toString().length));
|
|
215
214
|
const formatLine = (lineNumber: number, line: string, isMatch: boolean): string => {
|
|
215
|
+
const separator = isMatch ? ":" : "-";
|
|
216
216
|
if (useHashLines) {
|
|
217
217
|
const ref = `${lineNumber}#${computeLineHash(lineNumber, line)}`;
|
|
218
|
-
return
|
|
218
|
+
return `${ref}${separator}${line}`;
|
|
219
219
|
}
|
|
220
220
|
const padded = lineNumber.toString().padStart(lineWidth, " ");
|
|
221
|
-
return
|
|
221
|
+
return `${padded}${separator}${line}`;
|
|
222
222
|
};
|
|
223
223
|
for (let index = 0; index < matchLines.length; index++) {
|
|
224
224
|
outputLines.push(formatLine(match.startLine + index, matchLines[index], index === 0));
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Prevents editing of files that appear to be automatically generated
|
|
5
5
|
* by code generation tools (protoc, sqlc, buf, swagger, etc.).
|
|
6
6
|
*/
|
|
7
|
-
import * as fs from "node:fs/promises";
|
|
8
7
|
import * as path from "node:path";
|
|
8
|
+
import { isEnoent, peekFile } from "@oh-my-pi/pi-utils";
|
|
9
|
+
import { LRUCache } from "lru-cache/raw";
|
|
9
10
|
import { settings } from "../config/settings";
|
|
10
11
|
import { ToolError } from "./tool-errors";
|
|
11
12
|
|
|
@@ -209,40 +210,19 @@ function isAutoGeneratedFileName(filePath: string): boolean {
|
|
|
209
210
|
|
|
210
211
|
/**
|
|
211
212
|
* Check if leading header comments contain auto-generated markers.
|
|
212
|
-
* Returns the matched marker text if found,
|
|
213
|
+
* Returns the matched marker text if found, undefined otherwise.
|
|
213
214
|
*/
|
|
214
|
-
function detectAutoGeneratedMarker(content: string, filePath: string): string |
|
|
215
|
+
function detectAutoGeneratedMarker(content: string, filePath: string): string | undefined {
|
|
215
216
|
const commentStyles = getCommentStylesForPath(filePath);
|
|
216
217
|
const headerCommentText = extractLeadingHeaderCommentText(content, commentStyles);
|
|
217
|
-
if (!headerCommentText) return
|
|
218
|
+
if (!headerCommentText) return undefined;
|
|
218
219
|
|
|
219
220
|
for (const markerPattern of AUTO_GENERATED_HEADER_MARKERS) {
|
|
220
221
|
const match = markerPattern.exec(headerCommentText);
|
|
221
222
|
if (match?.[0]) return match[0];
|
|
222
223
|
}
|
|
223
224
|
|
|
224
|
-
return
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
/**
|
|
228
|
-
* Read the first N bytes of a file as a UTF-8 string.
|
|
229
|
-
* More efficient than reading the entire file.
|
|
230
|
-
*/
|
|
231
|
-
async function readFilePrefix(filePath: string, bytes: number): Promise<string | null> {
|
|
232
|
-
const handle = await fs.open(filePath, "r").catch(() => null);
|
|
233
|
-
if (!handle) {
|
|
234
|
-
return null;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
try {
|
|
238
|
-
const buffer = Buffer.allocUnsafe(bytes);
|
|
239
|
-
const { bytesRead } = await handle.read(buffer, 0, bytes, 0);
|
|
240
|
-
return buffer.toString("utf-8", 0, bytesRead);
|
|
241
|
-
} catch {
|
|
242
|
-
return null;
|
|
243
|
-
} finally {
|
|
244
|
-
await handle.close();
|
|
245
|
-
}
|
|
225
|
+
return undefined;
|
|
246
226
|
}
|
|
247
227
|
|
|
248
228
|
/**
|
|
@@ -259,6 +239,33 @@ function buildAutoGeneratedError(displayPath: string, detected: string): ToolErr
|
|
|
259
239
|
);
|
|
260
240
|
}
|
|
261
241
|
|
|
242
|
+
const decoder = new TextDecoder("utf-8");
|
|
243
|
+
|
|
244
|
+
const autoGeneratedMap = new LRUCache<string, { marker: string | undefined }>({ max: 10 });
|
|
245
|
+
|
|
246
|
+
async function getAutoGeneratedMarker(filePath: string): Promise<string | undefined> {
|
|
247
|
+
if (isAutoGeneratedFileName(filePath)) {
|
|
248
|
+
return filePath.split("/").pop() ?? "";
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
const cached = autoGeneratedMap.get(filePath);
|
|
252
|
+
if (cached) return cached.marker;
|
|
253
|
+
|
|
254
|
+
let marker: string | undefined;
|
|
255
|
+
try {
|
|
256
|
+
const content = await peekFile(filePath, CHECK_BYTE_COUNT, header => decoder.decode(header));
|
|
257
|
+
marker = detectAutoGeneratedMarker(content, filePath);
|
|
258
|
+
} catch (err) {
|
|
259
|
+
if (isEnoent(err)) {
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
262
|
+
throw err;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
autoGeneratedMap.set(filePath, { marker });
|
|
266
|
+
return marker;
|
|
267
|
+
}
|
|
268
|
+
|
|
262
269
|
/**
|
|
263
270
|
* Check if a file is auto-generated by examining its content.
|
|
264
271
|
* Throws ToolError if the file appears to be auto-generated.
|
|
@@ -266,24 +273,12 @@ function buildAutoGeneratedError(displayPath: string, detected: string): ToolErr
|
|
|
266
273
|
* @param absolutePath - Absolute path to the file
|
|
267
274
|
* @param displayPath - Path to show in error messages (relative or as provided)
|
|
268
275
|
*/
|
|
269
|
-
export async function
|
|
276
|
+
export async function assertEditableFile(absolutePath: string, displayPath?: string) {
|
|
270
277
|
if (!settings.get("edit.blockAutoGenerated")) {
|
|
271
278
|
return;
|
|
272
279
|
}
|
|
273
|
-
|
|
274
280
|
const pathForDisplay = displayPath ?? absolutePath;
|
|
275
|
-
|
|
276
|
-
if (isAutoGeneratedFileName(absolutePath)) {
|
|
277
|
-
const fileName = absolutePath.split("/").pop() ?? "";
|
|
278
|
-
throw buildAutoGeneratedError(pathForDisplay, fileName);
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
const content = await readFilePrefix(absolutePath, CHECK_BYTE_COUNT);
|
|
282
|
-
if (content === null) {
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
const marker = detectAutoGeneratedMarker(content, absolutePath);
|
|
281
|
+
const marker = await getAutoGeneratedMarker(absolutePath);
|
|
287
282
|
if (marker) {
|
|
288
283
|
throw buildAutoGeneratedError(pathForDisplay, marker);
|
|
289
284
|
}
|
|
@@ -297,7 +292,7 @@ export async function checkAutoGeneratedFile(absolutePath: string, displayPath?:
|
|
|
297
292
|
* @param content - File content to check (can be full content or prefix)
|
|
298
293
|
* @param displayPath - Path to show in error messages
|
|
299
294
|
*/
|
|
300
|
-
export
|
|
295
|
+
export function assertEditableFileContent(content: string, displayPath: string): void {
|
|
301
296
|
if (!settings.get("edit.blockAutoGenerated")) {
|
|
302
297
|
return;
|
|
303
298
|
}
|
package/src/tools/await-tool.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
3
|
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
4
4
|
import awaitDescription from "../prompts/tools/await.md" with { type: "text" };
|
|
5
5
|
import type { ToolSession } from "./index";
|
|
6
6
|
|
|
@@ -36,7 +36,7 @@ export class AwaitTool implements AgentTool<typeof awaitSchema, AwaitToolDetails
|
|
|
36
36
|
readonly strict = true;
|
|
37
37
|
|
|
38
38
|
constructor(private readonly session: ToolSession) {
|
|
39
|
-
this.description =
|
|
39
|
+
this.description = prompt.render(awaitDescription);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
static createIf(session: ToolSession): AwaitTool | null {
|
package/src/tools/bash.ts
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
2
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
4
3
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
5
4
|
import { ImageProtocol, TERMINAL, Text } from "@oh-my-pi/pi-tui";
|
|
6
|
-
import { $env, getProjectDir, isEnoent } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { $env, getProjectDir, isEnoent, prompt } from "@oh-my-pi/pi-utils";
|
|
7
6
|
import { Type } from "@sinclair/typebox";
|
|
8
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
9
7
|
import { type BashResult, executeBash } from "../exec/bash-executor";
|
|
10
8
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
11
9
|
import { truncateToVisualLines } from "../modes/components/visual-truncate";
|
|
@@ -22,7 +20,7 @@ import { applyHeadTail } from "./bash-normalize";
|
|
|
22
20
|
import { expandInternalUrls, type InternalUrlExpansionOptions } from "./bash-skill-urls";
|
|
23
21
|
import { formatStyledTruncationWarning, type OutputMeta } from "./output-meta";
|
|
24
22
|
import { resolveToCwd } from "./path-utils";
|
|
25
|
-
import { replaceTabs } from "./render-utils";
|
|
23
|
+
import { formatToolWorkingDirectory, replaceTabs } from "./render-utils";
|
|
26
24
|
import { ToolAbortError, ToolError } from "./tool-errors";
|
|
27
25
|
import { toolResult } from "./tool-result";
|
|
28
26
|
import { clampTimeout } from "./tool-timeouts";
|
|
@@ -218,7 +216,7 @@ export class BashTool implements AgentTool<BashToolSchema, BashToolDetails> {
|
|
|
218
216
|
constructor(private readonly session: ToolSession) {
|
|
219
217
|
this.#asyncEnabled = this.session.settings.get("async.enabled");
|
|
220
218
|
this.parameters = this.#asyncEnabled ? bashSchemaWithAsync : bashSchemaBase;
|
|
221
|
-
this.description =
|
|
219
|
+
this.description = prompt.render(bashDescription, {
|
|
222
220
|
asyncEnabled: this.#asyncEnabled,
|
|
223
221
|
hasAstGrep: this.session.settings.get("astGrep.enabled"),
|
|
224
222
|
hasAstEdit: this.session.settings.get("astEdit.enabled"),
|
|
@@ -481,26 +479,10 @@ interface BashRenderContext {
|
|
|
481
479
|
}
|
|
482
480
|
|
|
483
481
|
function formatBashCommand(args: BashRenderArgs): string {
|
|
484
|
-
const command = args.command || "…";
|
|
482
|
+
const command = replaceTabs(args.command || "…");
|
|
485
483
|
const prompt = "$";
|
|
486
484
|
const cwd = getProjectDir();
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if (displayWorkdir) {
|
|
490
|
-
const resolvedCwd = path.resolve(cwd);
|
|
491
|
-
const resolvedWorkdir = path.resolve(displayWorkdir);
|
|
492
|
-
if (resolvedWorkdir === resolvedCwd) {
|
|
493
|
-
displayWorkdir = undefined;
|
|
494
|
-
} else {
|
|
495
|
-
const relativePath = path.relative(resolvedCwd, resolvedWorkdir);
|
|
496
|
-
const isWithinCwd =
|
|
497
|
-
relativePath && !relativePath.startsWith("..") && !relativePath.startsWith(`..${path.sep}`);
|
|
498
|
-
if (isWithinCwd) {
|
|
499
|
-
displayWorkdir = relativePath;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
|
|
485
|
+
const displayWorkdir = formatToolWorkingDirectory(args.cwd, cwd);
|
|
504
486
|
const renderedCommand = [formatBashEnvAssignments(getBashEnvForDisplay(args)), command].filter(Boolean).join(" ");
|
|
505
487
|
return displayWorkdir ? `${prompt} cd ${displayWorkdir} && ${renderedCommand}` : `${prompt} ${renderedCommand}`;
|
|
506
488
|
}
|
package/src/tools/browser.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as path from "node:path";
|
|
|
4
4
|
import { Readability } from "@mozilla/readability";
|
|
5
5
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
6
6
|
import { StringEnum } from "@oh-my-pi/pi-ai";
|
|
7
|
-
import { getPuppeteerDir, logger, Snowflake, untilAborted } from "@oh-my-pi/pi-utils";
|
|
7
|
+
import { $which, getPuppeteerDir, logger, prompt, Snowflake, untilAborted } from "@oh-my-pi/pi-utils";
|
|
8
8
|
import { type Static, Type } from "@sinclair/typebox";
|
|
9
9
|
import { type HTMLElement, parseHTML } from "linkedom";
|
|
10
10
|
import type {
|
|
@@ -16,7 +16,6 @@ import type {
|
|
|
16
16
|
default as Puppeteer,
|
|
17
17
|
SerializedAXNode,
|
|
18
18
|
} from "puppeteer";
|
|
19
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
20
19
|
import browserDescription from "../prompts/tools/browser.md" with { type: "text" };
|
|
21
20
|
import type { ToolSession } from "../sdk";
|
|
22
21
|
import { resizeImage } from "../utils/image-resize";
|
|
@@ -88,8 +87,8 @@ function resolveSystemChromium(): string | undefined {
|
|
|
88
87
|
return undefined;
|
|
89
88
|
}
|
|
90
89
|
const candidates = [
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
$which("chromium"),
|
|
91
|
+
$which("chromium-browser"),
|
|
93
92
|
path.join(os.homedir(), ".nix-profile/bin/chromium"),
|
|
94
93
|
"/run/current-system/sw/bin/chromium",
|
|
95
94
|
];
|
|
@@ -539,7 +538,7 @@ export class BrowserTool implements AgentTool<typeof browserSchema, BrowserToolD
|
|
|
539
538
|
readonly #patchedClients = new WeakSet<object>();
|
|
540
539
|
|
|
541
540
|
constructor(private readonly session: ToolSession) {
|
|
542
|
-
this.description =
|
|
541
|
+
this.description = prompt.render(browserDescription, {});
|
|
543
542
|
}
|
|
544
543
|
|
|
545
544
|
async #closeBrowser(): Promise<void> {
|
package/src/tools/calculator.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
2
2
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
3
3
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
4
|
-
import { untilAborted } from "@oh-my-pi/pi-utils";
|
|
4
|
+
import { prompt, untilAborted } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import { type Static, Type } from "@sinclair/typebox";
|
|
6
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
7
6
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
8
7
|
import type { Theme } from "../modes/theme/theme";
|
|
9
8
|
import calculatorDescription from "../prompts/tools/calculator.md" with { type: "text" };
|
|
@@ -402,7 +401,7 @@ export class CalculatorTool implements AgentTool<typeof calculatorSchema, Calcul
|
|
|
402
401
|
readonly strict = true;
|
|
403
402
|
|
|
404
403
|
constructor(_session: ToolSession) {
|
|
405
|
-
this.description =
|
|
404
|
+
this.description = prompt.render(calculatorDescription);
|
|
406
405
|
}
|
|
407
406
|
|
|
408
407
|
async execute(
|
package/src/tools/cancel-job.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
3
|
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
4
4
|
import cancelJobDescription from "../prompts/tools/cancel-job.md" with { type: "text" };
|
|
5
5
|
import type { ToolSession } from "./index";
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ export class CancelJobTool implements AgentTool<typeof cancelJobSchema, CancelJo
|
|
|
23
23
|
readonly strict = true;
|
|
24
24
|
|
|
25
25
|
constructor(private readonly session: ToolSession) {
|
|
26
|
-
this.description =
|
|
26
|
+
this.description = prompt.render(cancelJobDescription);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
static createIf(session: ToolSession): CancelJobTool | null {
|
package/src/tools/checkpoint.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core";
|
|
2
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
3
|
import { type Static, Type } from "@sinclair/typebox";
|
|
3
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
4
4
|
import checkpointDescription from "../prompts/tools/checkpoint.md" with { type: "text" };
|
|
5
5
|
import rewindDescription from "../prompts/tools/rewind.md" with { type: "text" };
|
|
6
6
|
import type { ToolSession } from ".";
|
|
@@ -54,7 +54,7 @@ export class CheckpointTool implements AgentTool<typeof checkpointSchema, Checkp
|
|
|
54
54
|
readonly strict = true;
|
|
55
55
|
|
|
56
56
|
constructor(private readonly session: ToolSession) {
|
|
57
|
-
this.description =
|
|
57
|
+
this.description = prompt.render(checkpointDescription);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
static createIf(session: ToolSession): CheckpointTool | null {
|
|
@@ -96,7 +96,7 @@ export class RewindTool implements AgentTool<typeof rewindSchema, RewindToolDeta
|
|
|
96
96
|
readonly strict = true;
|
|
97
97
|
|
|
98
98
|
constructor(private readonly session: ToolSession) {
|
|
99
|
-
this.description =
|
|
99
|
+
this.description = prompt.render(rewindDescription);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
static createIf(session: ToolSession): RewindTool | null {
|