@oh-my-pi/pi-coding-agent 13.19.0 → 14.0.2
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 +266 -1
- 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/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 +2 -2
- 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 +2 -2
- 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/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/system/system-prompt.md +2 -1
- package/src/prompts/tools/chunk-edit.md +219 -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
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
export type ExecutionAbortReason = "idle-timeout" | "signal";
|
|
2
|
+
|
|
3
|
+
export interface IdleTimeoutWatchdogOptions {
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
signal?: AbortSignal;
|
|
6
|
+
hardTimeoutGraceMs: number;
|
|
7
|
+
onAbort?: (reason: ExecutionAbortReason) => void;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export class IdleTimeoutWatchdog {
|
|
11
|
+
#abortController = new AbortController();
|
|
12
|
+
#abortReason?: ExecutionAbortReason;
|
|
13
|
+
#hardTimeoutDeferred = Promise.withResolvers<"hard-timeout">();
|
|
14
|
+
#hardTimeoutGraceMs: number;
|
|
15
|
+
#hardTimeoutTimer?: NodeJS.Timeout;
|
|
16
|
+
#idleTimer?: NodeJS.Timeout;
|
|
17
|
+
#onAbort?: (reason: ExecutionAbortReason) => void;
|
|
18
|
+
#signal?: AbortSignal;
|
|
19
|
+
#signalAbortHandler?: () => void;
|
|
20
|
+
#timeoutMs?: number;
|
|
21
|
+
|
|
22
|
+
constructor(options: IdleTimeoutWatchdogOptions) {
|
|
23
|
+
this.#timeoutMs = options.timeoutMs;
|
|
24
|
+
this.#hardTimeoutGraceMs = options.hardTimeoutGraceMs;
|
|
25
|
+
this.#onAbort = options.onAbort;
|
|
26
|
+
this.#signal = options.signal;
|
|
27
|
+
|
|
28
|
+
if (this.#signal) {
|
|
29
|
+
if (this.#signal.aborted) {
|
|
30
|
+
this.#abort("signal");
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this.#signalAbortHandler = () => {
|
|
35
|
+
this.#abort("signal");
|
|
36
|
+
};
|
|
37
|
+
this.#signal.addEventListener("abort", this.#signalAbortHandler, { once: true });
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.touch();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
get abortedBySignal(): boolean {
|
|
44
|
+
return this.#abortReason === "signal";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
get hardTimeoutPromise(): Promise<"hard-timeout"> {
|
|
48
|
+
return this.#hardTimeoutDeferred.promise;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get signal(): AbortSignal {
|
|
52
|
+
return this.#abortController.signal;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
get timedOut(): boolean {
|
|
56
|
+
return this.#abortReason === "idle-timeout";
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
touch(): void {
|
|
60
|
+
if (this.#abortReason || this.#timeoutMs === undefined || this.#timeoutMs <= 0) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (this.#idleTimer) {
|
|
65
|
+
clearTimeout(this.#idleTimer);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
this.#idleTimer = setTimeout(() => {
|
|
69
|
+
this.#abort("idle-timeout");
|
|
70
|
+
}, this.#timeoutMs);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
dispose(): void {
|
|
74
|
+
if (this.#idleTimer) {
|
|
75
|
+
clearTimeout(this.#idleTimer);
|
|
76
|
+
this.#idleTimer = undefined;
|
|
77
|
+
}
|
|
78
|
+
if (this.#hardTimeoutTimer) {
|
|
79
|
+
clearTimeout(this.#hardTimeoutTimer);
|
|
80
|
+
this.#hardTimeoutTimer = undefined;
|
|
81
|
+
}
|
|
82
|
+
if (this.#signal && this.#signalAbortHandler) {
|
|
83
|
+
this.#signal.removeEventListener("abort", this.#signalAbortHandler);
|
|
84
|
+
this.#signalAbortHandler = undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
#abort(reason: ExecutionAbortReason): void {
|
|
89
|
+
if (this.#abortReason) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
this.#abortReason = reason;
|
|
94
|
+
|
|
95
|
+
if (this.#idleTimer) {
|
|
96
|
+
clearTimeout(this.#idleTimer);
|
|
97
|
+
this.#idleTimer = undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
if (!this.#abortController.signal.aborted) {
|
|
101
|
+
this.#abortController.abort(reason);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
this.#onAbort?.(reason);
|
|
105
|
+
this.#armHardTimeout();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
#armHardTimeout(): void {
|
|
109
|
+
if (this.#hardTimeoutTimer || this.#hardTimeoutGraceMs <= 0) {
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
this.#hardTimeoutTimer = setTimeout(() => {
|
|
114
|
+
this.#hardTimeoutDeferred.resolve("hard-timeout");
|
|
115
|
+
}, this.#hardTimeoutGraceMs);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function formatIdleTimeoutMessage(timeoutMs?: number): string {
|
|
120
|
+
if (timeoutMs === undefined) {
|
|
121
|
+
return "Command timed out without output";
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const seconds = Math.max(1, Math.round(timeoutMs / 1000));
|
|
125
|
+
return `Command timed out after ${seconds} seconds without output`;
|
|
126
|
+
}
|
|
@@ -13,6 +13,11 @@ export const NON_INTERACTIVE_ENV: Readonly<Record<string, string>> = {
|
|
|
13
13
|
AWS_PAGER: "",
|
|
14
14
|
HOMEBREW_PAGER: "cat",
|
|
15
15
|
LESS: "FRX",
|
|
16
|
+
// Disable terminal features that can block the process.
|
|
17
|
+
TERM: "dumb",
|
|
18
|
+
GPG_TTY: "not a tty",
|
|
19
|
+
NO_COLOR: "1",
|
|
20
|
+
PYTHONUNBUFFERED: "1",
|
|
16
21
|
// Disable editor and terminal credential prompts.
|
|
17
22
|
GIT_EDITOR: "true",
|
|
18
23
|
VISUAL: "true",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import type { CustomCommand, CustomCommandAPI } from "../../../../extensibility/custom-commands/types";
|
|
3
3
|
import type { HookCommandContext } from "../../../../extensibility/hooks/types";
|
|
4
4
|
import ciGreenRequestTemplate from "../../../../prompts/ci-green-request.md" with { type: "text" };
|
|
@@ -20,6 +20,6 @@ export class GreenCommand implements CustomCommand {
|
|
|
20
20
|
|
|
21
21
|
async execute(_args: string[], _ctx: HookCommandContext): Promise<string> {
|
|
22
22
|
const headTag = await getHeadTag(this.api);
|
|
23
|
-
return
|
|
23
|
+
return prompt.render(ciGreenRequestTemplate, { headTag });
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* rich context for the orchestrating agent to distribute work across
|
|
12
12
|
* multiple reviewer agents based on diff weight and locality.
|
|
13
13
|
*/
|
|
14
|
-
import {
|
|
14
|
+
import { prompt } from "@oh-my-pi/pi-utils";
|
|
15
15
|
import type { CustomCommand, CustomCommandAPI } from "../../../../extensibility/custom-commands/types";
|
|
16
16
|
import type { HookCommandContext } from "../../../../extensibility/hooks/types";
|
|
17
17
|
import reviewRequestTemplate from "../../../../prompts/review-request.md" with { type: "text" };
|
|
@@ -209,7 +209,7 @@ function buildReviewPrompt(mode: string, stats: DiffStats, rawDiff: string): str
|
|
|
209
209
|
hunksPreview: skipDiff ? getDiffPreview(f.hunks, linesPerFile) : "",
|
|
210
210
|
}));
|
|
211
211
|
|
|
212
|
-
return
|
|
212
|
+
return prompt.render(reviewRequestTemplate, {
|
|
213
213
|
mode,
|
|
214
214
|
files: filesWithExt,
|
|
215
215
|
excluded: stats.excluded,
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
-
import * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
10
9
|
import { getAgentDir, getProjectDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
11
10
|
import * as typebox from "@sinclair/typebox";
|
|
12
11
|
import { getConfigDirs } from "../../config";
|
|
@@ -184,7 +183,7 @@ export async function loadCustomCommands(options: LoadCustomCommandsOptions = {}
|
|
|
184
183
|
exec: (command: string, args: string[], execOptions) =>
|
|
185
184
|
execCommand(command, args, execOptions?.cwd ?? cwd, execOptions),
|
|
186
185
|
typebox,
|
|
187
|
-
pi:
|
|
186
|
+
pi: await import("@oh-my-pi/pi-coding-agent"),
|
|
188
187
|
};
|
|
189
188
|
|
|
190
189
|
// 1. Load bundled commands first (lowest priority - can be overridden)
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* to avoid import resolution issues with custom tools loaded from user directories.
|
|
6
6
|
*/
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
-
import
|
|
8
|
+
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
9
9
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
10
10
|
import * as typebox from "@sinclair/typebox";
|
|
11
11
|
import { toolCapability } from "../../capability/tool";
|
|
@@ -14,7 +14,6 @@ import type { ExecOptions } from "../../exec/exec";
|
|
|
14
14
|
import { execCommand } from "../../exec/exec";
|
|
15
15
|
import type { HookUIContext } from "../../extensibility/hooks/types";
|
|
16
16
|
import { getAllPluginToolPaths } from "../../extensibility/plugins/loader";
|
|
17
|
-
import type { PendingActionStore } from "../../tools/pending-action";
|
|
18
17
|
import { createNoOpUIContext, resolvePath } from "../utils";
|
|
19
18
|
import type { CustomToolAPI, CustomToolFactory, LoadedCustomTool, ToolLoadError } from "./types";
|
|
20
19
|
|
|
@@ -85,7 +84,17 @@ export class CustomToolLoader {
|
|
|
85
84
|
#sharedApi: CustomToolAPI;
|
|
86
85
|
#seenNames: Set<string>;
|
|
87
86
|
|
|
88
|
-
constructor(
|
|
87
|
+
constructor(
|
|
88
|
+
pi: typeof import("@oh-my-pi/pi-coding-agent"),
|
|
89
|
+
cwd: string,
|
|
90
|
+
builtInToolNames: string[],
|
|
91
|
+
pushPendingAction?: (action: {
|
|
92
|
+
label: string;
|
|
93
|
+
sourceToolName: string;
|
|
94
|
+
apply(reason: string): Promise<AgentToolResult<unknown>>;
|
|
95
|
+
reject?(reason: string): Promise<AgentToolResult<unknown> | undefined>;
|
|
96
|
+
}) => void,
|
|
97
|
+
) {
|
|
89
98
|
this.#sharedApi = {
|
|
90
99
|
cwd,
|
|
91
100
|
exec: (command: string, args: string[], options?: ExecOptions) =>
|
|
@@ -94,17 +103,16 @@ export class CustomToolLoader {
|
|
|
94
103
|
hasUI: false,
|
|
95
104
|
logger,
|
|
96
105
|
typebox,
|
|
97
|
-
pi
|
|
106
|
+
pi,
|
|
98
107
|
pushPendingAction: action => {
|
|
99
|
-
if (!
|
|
108
|
+
if (!pushPendingAction) {
|
|
100
109
|
throw new Error("Pending action store unavailable for custom tools in this runtime.");
|
|
101
110
|
}
|
|
102
|
-
|
|
111
|
+
pushPendingAction({
|
|
103
112
|
label: action.label,
|
|
104
113
|
sourceToolName: action.sourceToolName ?? "custom_tool",
|
|
105
114
|
apply: action.apply,
|
|
106
115
|
reject: action.reject,
|
|
107
|
-
details: action.details,
|
|
108
116
|
});
|
|
109
117
|
},
|
|
110
118
|
};
|
|
@@ -155,9 +163,19 @@ export async function loadCustomTools(
|
|
|
155
163
|
pathsWithSources: ToolPathWithSource[],
|
|
156
164
|
cwd: string,
|
|
157
165
|
builtInToolNames: string[],
|
|
158
|
-
|
|
166
|
+
pushPendingAction?: (action: {
|
|
167
|
+
label: string;
|
|
168
|
+
sourceToolName: string;
|
|
169
|
+
apply(reason: string): Promise<AgentToolResult<unknown>>;
|
|
170
|
+
reject?(reason: string): Promise<AgentToolResult<unknown> | undefined>;
|
|
171
|
+
}) => void,
|
|
159
172
|
) {
|
|
160
|
-
const loader = new CustomToolLoader(
|
|
173
|
+
const loader = new CustomToolLoader(
|
|
174
|
+
await import("@oh-my-pi/pi-coding-agent"),
|
|
175
|
+
cwd,
|
|
176
|
+
builtInToolNames,
|
|
177
|
+
pushPendingAction,
|
|
178
|
+
);
|
|
161
179
|
await loader.load(pathsWithSources);
|
|
162
180
|
return {
|
|
163
181
|
tools: loader.tools,
|
|
@@ -182,7 +200,12 @@ export async function discoverAndLoadCustomTools(
|
|
|
182
200
|
configuredPaths: string[],
|
|
183
201
|
cwd: string,
|
|
184
202
|
builtInToolNames: string[],
|
|
185
|
-
|
|
203
|
+
pushPendingAction?: (action: {
|
|
204
|
+
label: string;
|
|
205
|
+
sourceToolName: string;
|
|
206
|
+
apply(reason: string): Promise<AgentToolResult<unknown>>;
|
|
207
|
+
reject?(reason: string): Promise<AgentToolResult<unknown> | undefined>;
|
|
208
|
+
}) => void,
|
|
186
209
|
) {
|
|
187
210
|
const allPathsWithSources: ToolPathWithSource[] = [];
|
|
188
211
|
const seen = new Set<string>();
|
|
@@ -216,5 +239,5 @@ export async function discoverAndLoadCustomTools(
|
|
|
216
239
|
addPath(resolvePath(configPath, cwd), { provider: "config", providerName: "Config", level: "project" });
|
|
217
240
|
}
|
|
218
241
|
|
|
219
|
-
return loadCustomTools(allPathsWithSources, cwd, builtInToolNames,
|
|
242
|
+
return loadCustomTools(allPathsWithSources, cwd, builtInToolNames, pushPendingAction);
|
|
220
243
|
}
|
|
@@ -6,7 +6,6 @@ import * as fs from "node:fs/promises";
|
|
|
6
6
|
import * as path from "node:path";
|
|
7
7
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
8
|
import type { ImageContent, Model, TextContent } from "@oh-my-pi/pi-ai";
|
|
9
|
-
import * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
10
9
|
import type { KeyId } from "@oh-my-pi/pi-tui";
|
|
11
10
|
import { hasFsCode, isEacces, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
12
11
|
import type { TSchema } from "@sinclair/typebox";
|
|
@@ -102,7 +101,6 @@ export class ExtensionRuntime implements IExtensionRuntime {
|
|
|
102
101
|
class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
103
102
|
readonly logger = logger;
|
|
104
103
|
readonly typebox = TypeBox;
|
|
105
|
-
readonly pi = piCodingAgent;
|
|
106
104
|
readonly flagValues = new Map<string, boolean | string>();
|
|
107
105
|
readonly pendingProviderRegistrations: Array<{
|
|
108
106
|
name: string;
|
|
@@ -111,6 +109,7 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
|
111
109
|
}> = [];
|
|
112
110
|
|
|
113
111
|
constructor(
|
|
112
|
+
public readonly pi: typeof import("@oh-my-pi/pi-coding-agent"),
|
|
114
113
|
private readonly extension: Extension,
|
|
115
114
|
private readonly runtime: IExtensionRuntime,
|
|
116
115
|
private readonly cwd: string,
|
|
@@ -265,7 +264,13 @@ async function loadExtension(
|
|
|
265
264
|
}
|
|
266
265
|
|
|
267
266
|
const extension = createExtension(extensionPath, resolvedPath);
|
|
268
|
-
const api = new ConcreteExtensionAPI(
|
|
267
|
+
const api = new ConcreteExtensionAPI(
|
|
268
|
+
await import("@oh-my-pi/pi-coding-agent"),
|
|
269
|
+
extension,
|
|
270
|
+
runtime,
|
|
271
|
+
cwd,
|
|
272
|
+
eventBus,
|
|
273
|
+
);
|
|
269
274
|
await factory(api);
|
|
270
275
|
|
|
271
276
|
return { extension, error: null };
|
|
@@ -286,7 +291,7 @@ export async function loadExtensionFromFactory(
|
|
|
286
291
|
name = "<inline>",
|
|
287
292
|
): Promise<Extension> {
|
|
288
293
|
const extension = createExtension(name, name);
|
|
289
|
-
const api = new ConcreteExtensionAPI(extension, runtime, cwd, eventBus);
|
|
294
|
+
const api = new ConcreteExtensionAPI(await import("@oh-my-pi/pi-coding-agent"), extension, runtime, cwd, eventBus);
|
|
290
295
|
await factory(api);
|
|
291
296
|
return extension;
|
|
292
297
|
}
|
|
@@ -262,6 +262,10 @@ export class ExtensionRunner {
|
|
|
262
262
|
return allFlags;
|
|
263
263
|
}
|
|
264
264
|
|
|
265
|
+
getFlagValues(): Map<string, boolean | string> {
|
|
266
|
+
return new Map(this.runtime.flagValues);
|
|
267
|
+
}
|
|
268
|
+
|
|
265
269
|
setFlagValue(name: string, value: boolean | string): void {
|
|
266
270
|
this.runtime.flagValues.set(name, value);
|
|
267
271
|
}
|
|
@@ -695,7 +699,26 @@ export class ExtensionRunner {
|
|
|
695
699
|
|
|
696
700
|
async emitContext(messages: AgentMessage[]): Promise<AgentMessage[]> {
|
|
697
701
|
const ctx = this.createContext();
|
|
698
|
-
|
|
702
|
+
|
|
703
|
+
// Check if any extensions actually have context handlers before cloning
|
|
704
|
+
let hasContextHandlers = false;
|
|
705
|
+
for (const ext of this.extensions) {
|
|
706
|
+
if (ext.handlers.get("context")?.length) {
|
|
707
|
+
hasContextHandlers = true;
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
if (!hasContextHandlers) return messages;
|
|
712
|
+
|
|
713
|
+
let currentMessages: AgentMessage[];
|
|
714
|
+
try {
|
|
715
|
+
currentMessages = structuredClone(messages);
|
|
716
|
+
} catch {
|
|
717
|
+
// Messages may contain non-cloneable objects (e.g. in ToolResultMessage.details
|
|
718
|
+
// or ProviderPayload). Fall back to a shallow array clone — extensions should
|
|
719
|
+
// return new message arrays rather than mutating in place.
|
|
720
|
+
currentMessages = [...messages];
|
|
721
|
+
}
|
|
699
722
|
|
|
700
723
|
for (const ext of this.extensions) {
|
|
701
724
|
const handlers = ext.handlers.get("context");
|
|
@@ -28,11 +28,11 @@ import type { Static, TSchema } from "@sinclair/typebox";
|
|
|
28
28
|
import type { Rule } from "../../capability/rule";
|
|
29
29
|
import type { KeybindingsManager } from "../../config/keybindings";
|
|
30
30
|
import type { ModelRegistry } from "../../config/model-registry";
|
|
31
|
+
import type { EditToolDetails } from "../../edit";
|
|
31
32
|
import type { BashResult } from "../../exec/bash-executor";
|
|
32
33
|
import type { ExecOptions, ExecResult } from "../../exec/exec";
|
|
33
34
|
import type { PythonResult } from "../../ipy/executor";
|
|
34
35
|
import type { Theme } from "../../modes/theme/theme";
|
|
35
|
-
import type { EditToolDetails } from "../../patch";
|
|
36
36
|
import type { CompactionPreparation, CompactionResult } from "../../session/compaction";
|
|
37
37
|
import type { CustomMessage } from "../../session/messages";
|
|
38
38
|
import type {
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
* Hook loader - loads TypeScript hook modules using native Bun import.
|
|
3
3
|
*/
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import * as piCodingAgent from "@oh-my-pi/pi-coding-agent";
|
|
6
5
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
7
6
|
import * as typebox from "@sinclair/typebox";
|
|
8
7
|
import { hookCapability } from "../../capability/hook";
|
|
@@ -87,16 +86,16 @@ export interface LoadHooksResult {
|
|
|
87
86
|
* Create a HookAPI instance that collects handlers, renderers, and commands.
|
|
88
87
|
* Returns the API, maps, and functions to set handlers later.
|
|
89
88
|
*/
|
|
90
|
-
function createHookAPI(
|
|
89
|
+
async function createHookAPI(
|
|
91
90
|
handlers: Map<string, HandlerFn[]>,
|
|
92
91
|
cwd: string,
|
|
93
|
-
): {
|
|
92
|
+
): Promise<{
|
|
94
93
|
api: HookAPI;
|
|
95
94
|
messageRenderers: Map<string, HookMessageRenderer>;
|
|
96
95
|
commands: Map<string, RegisteredCommand>;
|
|
97
96
|
setSendMessageHandler: (handler: SendMessageHandler) => void;
|
|
98
97
|
setAppendEntryHandler: (handler: AppendEntryHandler) => void;
|
|
99
|
-
} {
|
|
98
|
+
}> {
|
|
100
99
|
let sendMessageHandler: SendMessageHandler | null = null;
|
|
101
100
|
let appendEntryHandler: AppendEntryHandler | null = null;
|
|
102
101
|
const messageRenderers = new Map<string, HookMessageRenderer>();
|
|
@@ -137,7 +136,7 @@ function createHookAPI(
|
|
|
137
136
|
},
|
|
138
137
|
logger,
|
|
139
138
|
typebox,
|
|
140
|
-
pi:
|
|
139
|
+
pi: await import("@oh-my-pi/pi-coding-agent"),
|
|
141
140
|
} as HookAPI;
|
|
142
141
|
|
|
143
142
|
return {
|
|
@@ -170,7 +169,7 @@ async function loadHook(hookPath: string, cwd: string): Promise<{ hook: LoadedHo
|
|
|
170
169
|
|
|
171
170
|
// Create handlers map and API
|
|
172
171
|
const handlers = new Map<string, HandlerFn[]>();
|
|
173
|
-
const { api, messageRenderers, commands, setSendMessageHandler, setAppendEntryHandler } = createHookAPI(
|
|
172
|
+
const { api, messageRenderers, commands, setSendMessageHandler, setAppendEntryHandler } = await createHookAPI(
|
|
174
173
|
handlers,
|
|
175
174
|
cwd,
|
|
176
175
|
);
|
|
@@ -9,9 +9,9 @@ import type { ImageContent, Message, Model, TextContent, ToolResultMessage } fro
|
|
|
9
9
|
import type { Component, TUI } from "@oh-my-pi/pi-tui";
|
|
10
10
|
import type { Rule } from "../../capability/rule";
|
|
11
11
|
import type { ModelRegistry } from "../../config/model-registry";
|
|
12
|
+
import type { EditToolDetails } from "../../edit";
|
|
12
13
|
import type { ExecOptions, ExecResult } from "../../exec/exec";
|
|
13
14
|
import type { Theme } from "../../modes/theme/theme";
|
|
14
|
-
import type { EditToolDetails } from "../../patch";
|
|
15
15
|
import type { CompactionPreparation, CompactionResult } from "../../session/compaction";
|
|
16
16
|
import type { HookMessage } from "../../session/messages";
|
|
17
17
|
import type {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { $which } from "@oh-my-pi/pi-utils";
|
|
1
2
|
import { theme } from "../../modes/theme/theme";
|
|
2
3
|
import type { DoctorCheck } from "./types";
|
|
3
4
|
|
|
@@ -12,7 +13,7 @@ export async function runDoctorChecks(): Promise<DoctorCheck[]> {
|
|
|
12
13
|
];
|
|
13
14
|
|
|
14
15
|
for (const tool of tools) {
|
|
15
|
-
const path =
|
|
16
|
+
const path = $which(tool.name);
|
|
16
17
|
checks.push({
|
|
17
18
|
name: tool.name,
|
|
18
19
|
status: path ? "ok" : "warning",
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import type { AutocompleteItem } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import { parseFrontmatter, prompt } from "@oh-my-pi/pi-utils";
|
|
2
3
|
import { slashCommandCapability } from "../capability/slash-command";
|
|
3
|
-
import {
|
|
4
|
-
appendInlineArgsFallback,
|
|
5
|
-
renderPromptTemplate,
|
|
6
|
-
templateUsesInlineArgPlaceholders,
|
|
7
|
-
} from "../config/prompt-templates";
|
|
4
|
+
import { appendInlineArgsFallback, templateUsesInlineArgPlaceholders } from "../config/prompt-templates";
|
|
8
5
|
import type { SlashCommand } from "../discovery";
|
|
9
6
|
import { loadCapability } from "../discovery";
|
|
10
7
|
import {
|
|
@@ -14,7 +11,6 @@ import {
|
|
|
14
11
|
} from "../slash-commands/builtin-registry";
|
|
15
12
|
import { EMBEDDED_COMMAND_TEMPLATES } from "../task/commands";
|
|
16
13
|
import { parseCommandArgs, substituteArgs } from "../utils/command-args";
|
|
17
|
-
import { parseFrontmatter } from "../utils/frontmatter";
|
|
18
14
|
|
|
19
15
|
export type SlashCommandSource = "extension" | "prompt" | "skill";
|
|
20
16
|
|
|
@@ -223,7 +219,7 @@ export function expandSlashCommand(text: string, fileCommands: FileSlashCommand[
|
|
|
223
219
|
const argsText = args.join(" ");
|
|
224
220
|
const usesInlineArgPlaceholders = templateUsesInlineArgPlaceholders(fileCommand.content);
|
|
225
221
|
const substituted = substituteArgs(fileCommand.content, args);
|
|
226
|
-
const rendered =
|
|
222
|
+
const rendered = prompt.render(substituted, { args, ARGUMENTS: argsText, arguments: argsText });
|
|
227
223
|
return appendInlineArgsFallback(rendered, argsText, usesInlineArgPlaceholders);
|
|
228
224
|
}
|
|
229
225
|
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ export type * from "./config/prompt-templates";
|
|
|
16
16
|
export * from "./config/prompt-templates";
|
|
17
17
|
export type { RetrySettings, SkillsSettings } from "./config/settings";
|
|
18
18
|
export { Settings, settings } from "./config/settings";
|
|
19
|
+
export * from "./edit/modes/hashline";
|
|
19
20
|
// Custom commands
|
|
20
21
|
export type * from "./extensibility/custom-commands/types";
|
|
21
22
|
export type * from "./extensibility/custom-tools";
|
|
@@ -37,7 +38,6 @@ export * from "./modes";
|
|
|
37
38
|
export * from "./modes/components";
|
|
38
39
|
// Theme utilities for custom tools
|
|
39
40
|
export * from "./modes/theme/theme";
|
|
40
|
-
export * from "./patch/hashline";
|
|
41
41
|
// SDK for programmatic usage
|
|
42
42
|
export * from "./sdk";
|
|
43
43
|
export * from "./session/agent-session";
|
|
@@ -46,6 +46,7 @@ export * from "./session/auth-storage";
|
|
|
46
46
|
// Compaction
|
|
47
47
|
export * from "./session/compaction";
|
|
48
48
|
export * from "./session/messages";
|
|
49
|
+
export * from "./session/session-dump-format";
|
|
49
50
|
export * from "./session/session-manager";
|
|
50
51
|
export * from "./task/executor";
|
|
51
52
|
export type * from "./task/types";
|