@oh-my-pi/pi-coding-agent 17.2.6 → 17.2.7
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 +17 -1
- package/dist/{CHANGELOG-gs76k6wc.md → CHANGELOG-1p8yvde7.md} +17 -1
- package/dist/cli.js +3645 -3689
- package/dist/types/advisor/advise-tool.d.ts +10 -4
- package/dist/types/autoresearch/tools/init-experiment.d.ts +19 -7
- package/dist/types/autoresearch/tools/log-experiment.d.ts +19 -11
- package/dist/types/autoresearch/tools/run-experiment.d.ts +4 -2
- package/dist/types/autoresearch/tools/update-notes.d.ts +5 -2
- package/dist/types/commit/agentic/tools/analyze-file.d.ts +5 -2
- package/dist/types/commit/agentic/tools/git-file-diff.d.ts +5 -2
- package/dist/types/commit/agentic/tools/git-hunk.d.ts +6 -2
- package/dist/types/commit/agentic/tools/git-overview.d.ts +5 -2
- package/dist/types/commit/agentic/tools/propose-changelog.d.ts +29 -7
- package/dist/types/commit/agentic/tools/propose-commit.d.ts +14 -4
- package/dist/types/commit/agentic/tools/recent-commits.d.ts +4 -2
- package/dist/types/commit/agentic/tools/schemas.d.ts +7 -3
- package/dist/types/commit/agentic/tools/split-commit.d.ts +37 -10
- package/dist/types/commit/changelog/generate.d.ts +13 -3
- package/dist/types/commit/shared-llm.d.ts +13 -4
- package/dist/types/config/config-file.d.ts +1 -1
- package/dist/types/config/models-config-schema-bundle.d.ts +1992 -981
- package/dist/types/config/models-config-schema.d.ts +1201 -580
- package/dist/types/config/models-config.d.ts +355 -371
- package/dist/types/edit/hashline/params.d.ts +4 -2
- package/dist/types/edit/modes/apply-patch.d.ts +4 -2
- package/dist/types/edit/modes/patch.d.ts +16 -5
- package/dist/types/edit/modes/replace.d.ts +8 -3
- package/dist/types/eval/bridge-timeout.d.ts +5 -2
- package/dist/types/eval/completion-bridge.d.ts +13 -0
- package/dist/types/eval/py/tool-bridge.d.ts +12 -0
- package/dist/types/extensibility/custom-commands/types.d.ts +4 -4
- package/dist/types/extensibility/custom-tools/types.d.ts +4 -4
- package/dist/types/extensibility/extensions/types.d.ts +4 -4
- package/dist/types/extensibility/hooks/types.d.ts +4 -4
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +1 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/legacy-typebox.d.ts +8 -0
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +6 -13
- package/dist/types/goals/tools/goal-tool.d.ts +12 -4
- package/dist/types/lsp/index.d.ts +15 -5
- package/dist/types/lsp/types.d.ts +15 -5
- package/dist/types/security/contracts/schemas.d.ts +985 -409
- package/dist/types/security/publication.d.ts +92 -34
- package/dist/types/session/agent-session-types.d.ts +1 -1
- package/dist/types/session/session-entries.d.ts +1 -1
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/task/types.d.ts +63 -18
- package/dist/types/tools/ask.d.ts +34 -8
- package/dist/types/tools/ast-edit.d.ts +16 -4
- package/dist/types/tools/ast-grep.d.ts +12 -4
- package/dist/types/tools/bash.d.ts +20 -11
- package/dist/types/tools/browser.d.ts +64 -20
- package/dist/types/tools/checkpoint.d.ts +16 -8
- package/dist/types/tools/computer.d.ts +1 -1
- package/dist/types/tools/debug.d.ts +118 -48
- package/dist/types/tools/eval.d.ts +11 -5
- package/dist/types/tools/gh.d.ts +74 -26
- package/dist/types/tools/glob.d.ts +16 -6
- package/dist/types/tools/grep.d.ts +18 -6
- package/dist/types/tools/hub/index.d.ts +116 -46
- package/dist/types/tools/image-gen.d.ts +25 -8
- package/dist/types/tools/inspect-image.d.ts +10 -4
- package/dist/types/tools/learn.d.ts +26 -8
- package/dist/types/tools/manage-skill.d.ts +16 -6
- package/dist/types/tools/memory-edit.d.ts +18 -6
- package/dist/types/tools/memory-recall.d.ts +8 -4
- package/dist/types/tools/memory-reflect.d.ts +10 -4
- package/dist/types/tools/memory-retain.d.ts +14 -4
- package/dist/types/tools/read.d.ts +8 -4
- package/dist/types/tools/security-scan.d.ts +82 -30
- package/dist/types/tools/todo.d.ts +30 -10
- package/dist/types/tools/tts.d.ts +12 -5
- package/dist/types/tools/vibe.d.ts +42 -18
- package/dist/types/tools/write.d.ts +10 -4
- package/dist/types/web/search/index.d.ts +20 -6
- package/package.json +13 -13
- package/scripts/legacy-pi-virtual-module.ts +2 -2
- package/src/advisor/advise-tool.ts +1 -1
- package/src/advisor/config.ts +1 -1
- package/src/autoresearch/tools/init-experiment.ts +1 -2
- package/src/autoresearch/tools/log-experiment.ts +1 -2
- package/src/autoresearch/tools/run-experiment.ts +1 -1
- package/src/autoresearch/tools/update-notes.ts +1 -1
- package/src/commit/agentic/tools/analyze-file.ts +1 -1
- package/src/commit/agentic/tools/git-file-diff.ts +1 -1
- package/src/commit/agentic/tools/git-hunk.ts +1 -1
- package/src/commit/agentic/tools/git-overview.ts +1 -1
- package/src/commit/agentic/tools/propose-changelog.ts +1 -1
- package/src/commit/agentic/tools/propose-commit.ts +1 -1
- package/src/commit/agentic/tools/recent-commits.ts +1 -1
- package/src/commit/agentic/tools/schemas.ts +1 -1
- package/src/commit/agentic/tools/split-commit.ts +1 -1
- package/src/commit/analysis/summary.ts +1 -1
- package/src/commit/changelog/generate.ts +1 -1
- package/src/config/config-file.ts +2 -2
- package/src/config/models-config-schema-bundle.ts +1 -8
- package/src/discovery/codex.ts +22 -9
- package/src/edit/hashline/params.ts +1 -1
- package/src/edit/modes/apply-patch.ts +1 -1
- package/src/edit/modes/patch.ts +1 -1
- package/src/edit/modes/replace.ts +2 -1
- package/src/eval/agent-bridge.ts +4 -2
- package/src/eval/bridge-timeout.ts +5 -2
- package/src/eval/completion-bridge.ts +3 -2
- package/src/eval/executor-base.ts +20 -1
- package/src/eval/js/context-manager.ts +94 -6
- package/src/eval/py/tool-bridge.ts +29 -9
- package/src/extensibility/custom-commands/loader.ts +3 -3
- package/src/extensibility/custom-commands/types.ts +4 -4
- package/src/extensibility/custom-tools/loader.ts +3 -3
- package/src/extensibility/custom-tools/types.ts +5 -4
- package/src/extensibility/extensions/loader.ts +3 -3
- package/src/extensibility/extensions/types.ts +5 -4
- package/src/extensibility/hooks/loader.ts +3 -3
- package/src/extensibility/hooks/types.ts +4 -4
- package/src/extensibility/legacy-pi-ai-shim.ts +1 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +2 -2
- package/src/extensibility/legacy-typebox.ts +101 -0
- package/src/extensibility/plugins/legacy-pi-compat.ts +13 -22
- package/src/goals/tools/goal-tool.ts +1 -1
- package/src/lsp/types.ts +1 -1
- package/src/modes/theme/theme.ts +3 -3
- package/src/security/contracts/schemas.ts +1 -5
- package/src/security/contracts/validation.ts +1 -1
- package/src/security/publication.ts +1 -1
- package/src/session/agent-session-types.ts +1 -1
- package/src/session/agent-session.ts +1 -2
- package/src/session/session-context.ts +3 -3
- package/src/session/session-entries.ts +1 -1
- package/src/session/session-manager.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +3 -4
- package/src/task/types.ts +1 -1
- package/src/tools/ask.ts +1 -1
- package/src/tools/ast-edit.ts +1 -1
- package/src/tools/ast-grep.ts +1 -1
- package/src/tools/bash.ts +61 -3
- package/src/tools/browser.ts +1 -1
- package/src/tools/checkpoint.ts +1 -1
- package/src/tools/computer.ts +1 -1
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval.ts +1 -1
- package/src/tools/gh.ts +1 -2
- package/src/tools/glob.ts +1 -1
- package/src/tools/grep.ts +1 -1
- package/src/tools/hub/index.ts +1 -1
- package/src/tools/image-gen.ts +1 -1
- package/src/tools/inspect-image.ts +1 -1
- package/src/tools/learn.ts +1 -1
- package/src/tools/manage-skill.ts +1 -1
- package/src/tools/memory-edit.ts +1 -1
- package/src/tools/memory-recall.ts +1 -1
- package/src/tools/memory-reflect.ts +1 -1
- package/src/tools/memory-retain.ts +1 -1
- package/src/tools/read.ts +1 -1
- package/src/tools/security-scan.ts +1 -1
- package/src/tools/todo.ts +1 -1
- package/src/tools/tts.ts +1 -1
- package/src/tools/vibe.ts +2 -1
- package/src/tools/write.ts +1 -1
- package/src/web/search/index.ts +2 -1
- package/dist/types/extensibility/typebox.d.ts +0 -181
- package/src/extensibility/typebox.ts +0 -958
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { type } from "@oh-my-pi/omptype";
|
|
1
2
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
3
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
3
4
|
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
5
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { type } from "arktype";
|
|
6
6
|
import summarySystemPrompt from "../../commit/prompts/summary-system.md" with { type: "text" };
|
|
7
7
|
import summaryUserPrompt from "../../commit/prompts/summary-user.md" with { type: "text" };
|
|
8
8
|
import type { CommitSummary } from "../../commit/types";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { type } from "@oh-my-pi/omptype";
|
|
1
2
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
2
3
|
import type { Api, ApiKey, AssistantMessage, Model } from "@oh-my-pi/pi-ai";
|
|
3
4
|
import { completeSimple, validateToolCall } from "@oh-my-pi/pi-ai";
|
|
4
5
|
import { prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
-
import { type } from "arktype";
|
|
6
6
|
import changelogSystemPrompt from "../../commit/prompts/changelog-system.md" with { type: "text" };
|
|
7
7
|
import changelogUserPrompt from "../../commit/prompts/changelog-user.md" with { type: "text" };
|
|
8
8
|
import type { ChangelogGenerationResult } from "../../commit/types";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
+
import { OmpErrors, type Type } from "@oh-my-pi/omptype";
|
|
3
4
|
import { getAgentDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
4
|
-
import { ArkErrors, type Type } from "arktype";
|
|
5
5
|
import { JSONC, YAML } from "bun";
|
|
6
6
|
|
|
7
7
|
/** Minimal subset of the AJV ConfigSchemaError shape this module actually relies on. */
|
|
@@ -252,7 +252,7 @@ export class ConfigFile<T> implements IConfigFile<T> {
|
|
|
252
252
|
}
|
|
253
253
|
|
|
254
254
|
const checked = this.schema(parsed);
|
|
255
|
-
if (checked instanceof
|
|
255
|
+
if (checked instanceof OmpErrors) {
|
|
256
256
|
const schemaErrors: ConfigSchemaError[] = checked.map(error => ({
|
|
257
257
|
instancePath: error.path.length === 0 ? "root" : error.path.join("."),
|
|
258
258
|
message: error.problem,
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
+
import { type } from "@oh-my-pi/omptype";
|
|
1
2
|
import { once } from "@oh-my-pi/pi-utils";
|
|
2
|
-
import { scope } from "arktype";
|
|
3
3
|
|
|
4
4
|
export const getModelsConfigSchemaBundle = once(() => {
|
|
5
|
-
// Config schemas validate at most a handful of times per process (on config
|
|
6
|
-
// load), so the eager JIT codegen ArkType runs at definition time is pure
|
|
7
|
-
// startup tax. A local jitless scope skips that codegen and falls back to
|
|
8
|
-
// interpreted traversal — ~65% cheaper to construct, validation correctness
|
|
9
|
-
// unchanged. (No `name`: duplicate module instances would collide.)
|
|
10
|
-
const { type } = scope({}, { jitless: true });
|
|
11
|
-
|
|
12
5
|
const OpenRouterRoutingSchema = type({
|
|
13
6
|
"only?": "string[]",
|
|
14
7
|
"order?": "string[]",
|
package/src/discovery/codex.ts
CHANGED
|
@@ -87,23 +87,28 @@ async function loadMCPServers(ctx: LoadContext): Promise<LoadResult<MCPServer>>
|
|
|
87
87
|
]);
|
|
88
88
|
|
|
89
89
|
const items: MCPServer[] = [];
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
// Capability dedupe is first-wins, including suppressed items claiming their
|
|
91
|
+
// key. Load project entries first so a project `enabled = false` keeps a
|
|
92
|
+
// same-named user server disabled.
|
|
93
|
+
if (projectConfig) {
|
|
94
|
+
const servers = extractMCPServersFromToml(projectConfig, path.dirname(projectConfigPath));
|
|
95
|
+
for (const name in servers) {
|
|
96
|
+
const config = servers[name];
|
|
93
97
|
items.push({
|
|
94
98
|
name,
|
|
95
99
|
...config,
|
|
96
|
-
_source: createSourceMeta(PROVIDER_ID,
|
|
100
|
+
_source: createSourceMeta(PROVIDER_ID, projectConfigPath, "project"),
|
|
97
101
|
});
|
|
98
102
|
}
|
|
99
103
|
}
|
|
100
|
-
if (
|
|
101
|
-
const servers = extractMCPServersFromToml(
|
|
102
|
-
for (const
|
|
104
|
+
if (userConfig) {
|
|
105
|
+
const servers = extractMCPServersFromToml(userConfig, path.dirname(userConfigPath));
|
|
106
|
+
for (const name in servers) {
|
|
107
|
+
const config = servers[name];
|
|
103
108
|
items.push({
|
|
104
109
|
name,
|
|
105
110
|
...config,
|
|
106
|
-
_source: createSourceMeta(PROVIDER_ID,
|
|
111
|
+
_source: createSourceMeta(PROVIDER_ID, userConfigPath, "user"),
|
|
107
112
|
});
|
|
108
113
|
}
|
|
109
114
|
}
|
|
@@ -125,6 +130,7 @@ async function loadTomlConfig(_ctx: LoadContext, path: string): Promise<Record<s
|
|
|
125
130
|
|
|
126
131
|
/** Codex MCP server config format (from config.toml) */
|
|
127
132
|
interface CodexMCPConfig {
|
|
133
|
+
enabled?: boolean;
|
|
128
134
|
command?: string;
|
|
129
135
|
args?: string[];
|
|
130
136
|
env?: Record<string, string>;
|
|
@@ -152,13 +158,20 @@ function extractMCPServersFromToml(
|
|
|
152
158
|
const codexServers = toml.mcp_servers as Record<string, CodexMCPConfig>;
|
|
153
159
|
const result: Record<string, Partial<MCPServer>> = {};
|
|
154
160
|
|
|
155
|
-
for (const
|
|
161
|
+
for (const name in codexServers) {
|
|
162
|
+
const config = codexServers[name];
|
|
156
163
|
// Root relative cwd/command against the Codex config directory. Codex
|
|
157
164
|
// spawns the process with the resolved cwd, so a relative command is
|
|
158
165
|
// resolved by the OS from there — pass "cwd" so e.g. cwd="server",
|
|
159
166
|
// command="./bin/mcp" resolves to <configDir>/server/bin/mcp.
|
|
160
167
|
const rooted = resolvePluginStdioPaths({ command: config.command, cwd: config.cwd }, configDir, "cwd");
|
|
161
168
|
const server: Partial<MCPServer> = {
|
|
169
|
+
// Carry `enabled: false` through rather than dropping the entry: the
|
|
170
|
+
// central MCP loader (`loadAllMCPConfigs`) suppresses disabled servers
|
|
171
|
+
// so they still claim their dedupe key (keeping a same-named,
|
|
172
|
+
// lower-priority source disabled) and remain overridable via the user
|
|
173
|
+
// force-enable allowlist. Dropping here would defeat both.
|
|
174
|
+
...(config.enabled === false && { enabled: false }),
|
|
162
175
|
...(rooted.command !== undefined && { command: rooted.command }),
|
|
163
176
|
args: config.args,
|
|
164
177
|
url: config.url,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
* deliberately permissive (allows extra keys) so providers can attach extra
|
|
4
4
|
* keys without rejection; only `input` is required.
|
|
5
5
|
*/
|
|
6
|
-
import { type } from "
|
|
6
|
+
import { type } from "@oh-my-pi/omptype";
|
|
7
7
|
|
|
8
8
|
export const hashlineEditParamsSchema = type({
|
|
9
9
|
input: "string",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* the `patch` mode.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { type } from "
|
|
11
|
+
import { type } from "@oh-my-pi/omptype";
|
|
12
12
|
import { parseApplyPatch, parseApplyPatchStreaming } from "../apply-patch/parser";
|
|
13
13
|
import { ApplyPatchError } from "../diff";
|
|
14
14
|
import type { PatchEditEntry } from "./patch";
|
package/src/edit/modes/patch.ts
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
import * as fs from "node:fs";
|
|
9
9
|
import * as path from "node:path";
|
|
10
|
+
import { type } from "@oh-my-pi/omptype";
|
|
10
11
|
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
11
12
|
import { isEnoent } from "@oh-my-pi/pi-utils";
|
|
12
|
-
import { type } from "arktype";
|
|
13
13
|
import {
|
|
14
14
|
type FileDiagnosticsResult,
|
|
15
15
|
flushLspWritethroughBatch,
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
* Provides both character-level and line-level fuzzy matching with progressive
|
|
5
5
|
* fallback strategies for finding text in files.
|
|
6
6
|
*/
|
|
7
|
+
|
|
8
|
+
import { type } from "@oh-my-pi/omptype";
|
|
7
9
|
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
8
|
-
import { type } from "arktype";
|
|
9
10
|
import type { FileDiagnosticsResult, WritethroughCallback, WritethroughDeferredHandle } from "../../lsp";
|
|
10
11
|
import type { ToolSession } from "../../tools";
|
|
11
12
|
import { routeWriteThroughBridge } from "../../tools/acp-bridge";
|
package/src/eval/agent-bridge.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Host-side handler for the eval `agent()` helper.
|
|
3
3
|
*/
|
|
4
|
-
import { type } from "
|
|
4
|
+
import { type } from "@oh-my-pi/omptype";
|
|
5
5
|
import {
|
|
6
6
|
buildStructuredSubagentRecoveryHint,
|
|
7
7
|
runStructuredSubagent,
|
|
@@ -155,7 +155,9 @@ export async function runEvalAgent(args: unknown, options: EvalAgentBridgeOption
|
|
|
155
155
|
...(isolation ? { isolation } : {}),
|
|
156
156
|
...(parsed.handle ? { retainArtifacts: true } : {}),
|
|
157
157
|
keepAlive: false,
|
|
158
|
-
maxRuntimeMs:
|
|
158
|
+
// `maxRuntimeMs` is intentionally omitted: the executor then inherits
|
|
159
|
+
// `task.maxRuntimeMs`, matching the task tool. Pinning it to 0 here
|
|
160
|
+
// silently overrode the user's wall-clock cap for eval fan-outs.
|
|
159
161
|
shareEvalSession: false,
|
|
160
162
|
...(options.signal !== undefined ? { signal: options.signal } : {}),
|
|
161
163
|
...(options.emitStatus
|
|
@@ -29,8 +29,11 @@ export function isEvalTimeoutControlEvent(event: JsStatusEvent): boolean {
|
|
|
29
29
|
/** Optional behavior for a timeout pause around a host bridge call. */
|
|
30
30
|
export interface BridgeTimeoutPauseOptions {
|
|
31
31
|
/**
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
* Holds an external eval abort back from the *kernel* until this bridge call
|
|
33
|
+
* settles, so the runtime is never torn down mid-phase (`agent()` isolation
|
|
34
|
+
* worktree setup and merge/cherry-pick). It does not shield the delegated
|
|
35
|
+
* work itself: the bridge hands subagents the caller's real signal, so a
|
|
36
|
+
* turn cancel still stops them immediately.
|
|
34
37
|
*/
|
|
35
38
|
deferExternalAbort?: boolean;
|
|
36
39
|
}
|
|
@@ -11,10 +11,11 @@
|
|
|
11
11
|
* The call is oneshot and toolless from the model's perspective — pure text
|
|
12
12
|
* in, text (or, with `schema`, a structured object) out.
|
|
13
13
|
*/
|
|
14
|
+
|
|
15
|
+
import { type } from "@oh-my-pi/omptype";
|
|
14
16
|
import { instrumentedCompleteSimple, resolveTelemetry } from "@oh-my-pi/pi-agent-core";
|
|
15
17
|
import { type Api, Effort, type Model, type Tool } from "@oh-my-pi/pi-ai";
|
|
16
18
|
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
17
|
-
import { type } from "arktype";
|
|
18
19
|
import { extractTextContent, extractToolCall, parseJsonPayload } from "../commit/utils";
|
|
19
20
|
|
|
20
21
|
import {
|
|
@@ -46,7 +47,7 @@ const completionArgsSchema = type({
|
|
|
46
47
|
prompt: "string>0",
|
|
47
48
|
"model?": "'smol'|'default'|'slow'",
|
|
48
49
|
"system?": "string",
|
|
49
|
-
"schema?": "
|
|
50
|
+
"schema?": { "[string]": "unknown" },
|
|
50
51
|
});
|
|
51
52
|
|
|
52
53
|
export interface EvalCompletionBridgeOptions {
|
|
@@ -158,6 +158,15 @@ export async function waitForPromiseWithCancellation<T>(
|
|
|
158
158
|
return await resultPromise;
|
|
159
159
|
}
|
|
160
160
|
|
|
161
|
+
/**
|
|
162
|
+
* Derived abort signal for the kernel, holding back an external abort while a
|
|
163
|
+
* bridge call marked `deferExternalAbort` is in flight.
|
|
164
|
+
*
|
|
165
|
+
* Scope is deliberately narrow: only `kernel.execute` consumes
|
|
166
|
+
* {@link BridgeAbortShield.signal}. Work dispatched through the tool bridge
|
|
167
|
+
* keeps the caller's real signal so a turn cancel reaches spawned subagents
|
|
168
|
+
* immediately — deferral protects the runtime, never the delegated work.
|
|
169
|
+
*/
|
|
161
170
|
interface BridgeAbortShield {
|
|
162
171
|
signal: AbortSignal | undefined;
|
|
163
172
|
abortRequested: boolean;
|
|
@@ -428,11 +437,21 @@ export async function executeWithKernelBase<
|
|
|
428
437
|
const emitStatus: (event: JsStatusEvent) => void =
|
|
429
438
|
options?.emitStatus ?? (event => collectDisplay({ type: "status", event }));
|
|
430
439
|
const runId = `${runIdPrefix}-${crypto.randomUUID()}`;
|
|
440
|
+
// Two aborts cross the bridge, and conflating them is what let a cancelled
|
|
441
|
+
// turn keep working. Delegated work (above all the subagents `agent()`
|
|
442
|
+
// spawns) gets the caller's real signal so it dies with the turn — shielding
|
|
443
|
+
// it here made Python/Ruby/Julia fan-outs outlive a cancel indefinitely,
|
|
444
|
+
// while JS cells, which never route through this shield, stopped fine. The
|
|
445
|
+
// shielded signal only governs how long the host waits on a call, holding
|
|
446
|
+
// the cell open across a critical phase (isolation worktree setup,
|
|
447
|
+
// merge/cherry-pick) so a cancel can't settle it on top of a half-applied
|
|
448
|
+
// git operation.
|
|
431
449
|
const unregisterBridge =
|
|
432
450
|
options?.toolSession && options?.bridgeSessionId
|
|
433
451
|
? registerPyToolBridge(options.bridgeSessionId, runId, {
|
|
434
452
|
toolSession: options.toolSession,
|
|
435
|
-
signal:
|
|
453
|
+
signal: options.signal,
|
|
454
|
+
shieldedSignal: abortShield.signal,
|
|
436
455
|
emitStatus,
|
|
437
456
|
abortRequested: () => {
|
|
438
457
|
return abortShield.abortRequested;
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import type { ToolSession } from "../../tools";
|
|
9
9
|
import { ToolAbortError, ToolError } from "../../tools/tool-errors";
|
|
10
10
|
import { safeSend as safeSendIpc } from "../../utils/ipc";
|
|
11
|
+
import { EVAL_TIMEOUT_PAUSE_OP, EVAL_TIMEOUT_RESUME_OP } from "../bridge-timeout";
|
|
11
12
|
import { attachSessionOwner, resolveOwnerScopedSessionKey, type SessionOwners } from "../executor-base";
|
|
12
13
|
import { shouldDetachKernel } from "../py/spawn-options";
|
|
13
14
|
import { callSessionTool, type JsStatusEvent } from "./tool-bridge";
|
|
@@ -48,6 +49,26 @@ interface PendingRun {
|
|
|
48
49
|
resolve(value: { value: unknown }): void;
|
|
49
50
|
reject(error: Error): void;
|
|
50
51
|
toolCalls: Map<string, AbortController>;
|
|
52
|
+
/**
|
|
53
|
+
* Host calls currently inside a `deferExternalAbort` phase — `agent()`
|
|
54
|
+
* isolation worktree setup and merge/cherry-pick, which ignore their abort
|
|
55
|
+
* once started. Settling the run while one is live would return the cell on
|
|
56
|
+
* top of a git operation still rewriting the repo, so the abort path drains
|
|
57
|
+
* this first. Mirrors the Python bridge's shielded-signal contract.
|
|
58
|
+
*/
|
|
59
|
+
deferDepth: number;
|
|
60
|
+
/** Resolves once {@link deferDepth} falls back to zero. */
|
|
61
|
+
deferDrained?: PromiseWithResolvers<void>;
|
|
62
|
+
/** Set once the turn was cancelled; blocks new bridge calls during the drain. */
|
|
63
|
+
aborted: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* A worker `result` withheld because the cell still has bridge calls in
|
|
66
|
+
* flight. `#runOne` reports a finished run without awaiting its pending
|
|
67
|
+
* tools, so a floated or caught `agent()` would otherwise settle the run —
|
|
68
|
+
* tearing down the abort listener — while the subagent kept going with
|
|
69
|
+
* nothing left able to cancel it. Delivered once the last call drains.
|
|
70
|
+
*/
|
|
71
|
+
heldResult?: Extract<WorkerOutbound, { type: "result" }>;
|
|
51
72
|
settled: boolean;
|
|
52
73
|
}
|
|
53
74
|
|
|
@@ -267,6 +288,8 @@ async function runOnce(
|
|
|
267
288
|
resolve,
|
|
268
289
|
reject,
|
|
269
290
|
toolCalls: new Map(),
|
|
291
|
+
deferDepth: 0,
|
|
292
|
+
aborted: false,
|
|
270
293
|
settled: false,
|
|
271
294
|
};
|
|
272
295
|
session.pending.set(runId, pending);
|
|
@@ -274,9 +297,21 @@ async function runOnce(
|
|
|
274
297
|
const onAbort = (): void => {
|
|
275
298
|
const reason = options.runState.signal?.reason;
|
|
276
299
|
const abortError = reasonToError(reason, "Execution aborted");
|
|
277
|
-
//
|
|
300
|
+
// Stop delegated work at once — this is what kills spawned subagents —
|
|
301
|
+
// and refuse further bridge calls so the drain below stays bounded to
|
|
302
|
+
// phases that had already started.
|
|
303
|
+
pending.aborted = true;
|
|
278
304
|
for (const ctrl of pending.toolCalls.values()) ctrl.abort(abortError);
|
|
279
|
-
//
|
|
305
|
+
// A critical host phase ignores its abort once started (isolation
|
|
306
|
+
// worktree setup, merge/cherry-pick). Killing the worker now would
|
|
307
|
+
// settle the cell on top of a git operation still in progress, so wait
|
|
308
|
+
// for it. Hard-kill is still the only way to interrupt synchronous user
|
|
309
|
+
// code, hence it stays the terminal step either way.
|
|
310
|
+
const drained = pending.deferDepth > 0 ? pending.deferDrained?.promise : undefined;
|
|
311
|
+
if (drained) {
|
|
312
|
+
void drained.then(() => killSessionFor(session, abortError, { force: true }));
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
280
315
|
void killSessionFor(session, abortError, { force: true });
|
|
281
316
|
};
|
|
282
317
|
|
|
@@ -458,6 +493,25 @@ function handleSessionMessage(session: JsSession, msg: WorkerOutbound): void {
|
|
|
458
493
|
}
|
|
459
494
|
}
|
|
460
495
|
|
|
496
|
+
/**
|
|
497
|
+
* Maintain {@link PendingRun.deferDepth} from the bridge's pause/resume status
|
|
498
|
+
* events so an abort can wait out a critical `agent()` phase instead of
|
|
499
|
+
* settling the cell over a half-applied merge.
|
|
500
|
+
*/
|
|
501
|
+
function trackDeferPhase(pending: PendingRun, event: JsStatusEvent): void {
|
|
502
|
+
if (event.deferExternalAbort !== true) return;
|
|
503
|
+
if (event.op === EVAL_TIMEOUT_PAUSE_OP) {
|
|
504
|
+
pending.deferDepth++;
|
|
505
|
+
pending.deferDrained ??= Promise.withResolvers<void>();
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (event.op !== EVAL_TIMEOUT_RESUME_OP || pending.deferDepth === 0) return;
|
|
509
|
+
pending.deferDepth--;
|
|
510
|
+
if (pending.deferDepth > 0) return;
|
|
511
|
+
pending.deferDrained?.resolve();
|
|
512
|
+
pending.deferDrained = undefined;
|
|
513
|
+
}
|
|
514
|
+
|
|
461
515
|
async function handleToolCall(session: JsSession, msg: Extract<WorkerOutbound, { type: "tool-call" }>): Promise<void> {
|
|
462
516
|
const pending = session.pending.get(msg.runId);
|
|
463
517
|
if (!pending) {
|
|
@@ -468,26 +522,42 @@ async function handleToolCall(session: JsSession, msg: Extract<WorkerOutbound, {
|
|
|
468
522
|
});
|
|
469
523
|
return;
|
|
470
524
|
}
|
|
525
|
+
if (pending.aborted) {
|
|
526
|
+
safeSend(session, {
|
|
527
|
+
type: "tool-reply",
|
|
528
|
+
id: msg.id,
|
|
529
|
+
reply: { ok: false, error: { message: "Run was interrupted" } },
|
|
530
|
+
});
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
471
533
|
const ctrl = new AbortController();
|
|
472
534
|
pending.toolCalls.set(msg.id, ctrl);
|
|
473
535
|
try {
|
|
474
536
|
const value = await callSessionTool(msg.name, msg.args, {
|
|
475
537
|
session: pending.toolSession,
|
|
476
538
|
signal: ctrl.signal,
|
|
477
|
-
emitStatus: (event: JsStatusEvent) =>
|
|
539
|
+
emitStatus: (event: JsStatusEvent) => {
|
|
540
|
+
trackDeferPhase(pending, event);
|
|
541
|
+
pending.runState.onDisplay?.({ type: "status", event });
|
|
542
|
+
},
|
|
478
543
|
});
|
|
479
544
|
safeSend(session, { type: "tool-reply", id: msg.id, reply: { ok: true, value } });
|
|
480
545
|
} catch (error) {
|
|
481
546
|
safeSend(session, { type: "tool-reply", id: msg.id, reply: { ok: false, error: toErrorPayload(error) } });
|
|
482
547
|
} finally {
|
|
483
548
|
pending.toolCalls.delete(msg.id);
|
|
549
|
+
// Last call of a run whose worker result was withheld: settle it now.
|
|
550
|
+
const held = pending.heldResult;
|
|
551
|
+
if (held && !pending.settled && !pending.aborted && pending.toolCalls.size === 0) {
|
|
552
|
+
finishPending(pending, held);
|
|
553
|
+
}
|
|
484
554
|
}
|
|
485
555
|
}
|
|
486
556
|
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
if (!pending || pending.settled) return;
|
|
557
|
+
/** Deliver a worker `result` to the waiting {@link runOnce}. */
|
|
558
|
+
function finishPending(pending: PendingRun, msg: Extract<WorkerOutbound, { type: "result" }>): void {
|
|
490
559
|
pending.settled = true;
|
|
560
|
+
pending.heldResult = undefined;
|
|
491
561
|
if (msg.ok) {
|
|
492
562
|
pending.resolve({ value: undefined });
|
|
493
563
|
return;
|
|
@@ -495,6 +565,24 @@ function settlePending(session: JsSession, msg: Extract<WorkerOutbound, { type:
|
|
|
495
565
|
pending.reject(errorFromPayload(msg.error));
|
|
496
566
|
}
|
|
497
567
|
|
|
568
|
+
function settlePending(session: JsSession, msg: Extract<WorkerOutbound, { type: "result" }>): void {
|
|
569
|
+
const pending = session.pending.get(msg.runId);
|
|
570
|
+
if (!pending || pending.settled) return;
|
|
571
|
+
// Once the turn is cancelled the scheduled kill is the sole settler, so a
|
|
572
|
+
// late worker result can't cut the abort drain short.
|
|
573
|
+
if (pending.aborted) return;
|
|
574
|
+
// A cell owns every bridge call it starts. The worker finishes a run without
|
|
575
|
+
// awaiting its outstanding tool calls, so `agent(...)` that is floated or
|
|
576
|
+
// caught would settle the run here — `runOnce` then drops the abort listener
|
|
577
|
+
// and the pending entry, leaving the subagent running with nothing able to
|
|
578
|
+
// cancel it. Hold the result until the last call drains.
|
|
579
|
+
if (pending.toolCalls.size > 0) {
|
|
580
|
+
pending.heldResult = msg;
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
finishPending(pending, msg);
|
|
584
|
+
}
|
|
585
|
+
|
|
498
586
|
async function killSessionFor(session: JsSession, error: Error, options: { force: boolean }): Promise<void> {
|
|
499
587
|
if (sessions.get(session.sessionKey) === session) {
|
|
500
588
|
sessions.delete(session.sessionKey);
|
|
@@ -13,7 +13,19 @@ import { callSessionTool, type JsStatusEvent } from "../js/tool-bridge";
|
|
|
13
13
|
|
|
14
14
|
export interface PyToolBridgeEntry {
|
|
15
15
|
toolSession: ToolSession;
|
|
16
|
+
/**
|
|
17
|
+
* Turn-cancel handed to the tool implementation. Raw and never deferred, so
|
|
18
|
+
* delegated work — above all the subagents `agent()` spawns — stops at once.
|
|
19
|
+
*/
|
|
16
20
|
signal?: AbortSignal;
|
|
21
|
+
/**
|
|
22
|
+
* Kernel-side abort, held back while a critical `agent()` phase (isolation
|
|
23
|
+
* worktree setup, merge/cherry-pick) is in flight. Decides only when the host
|
|
24
|
+
* may stop waiting on a call and let the kernel unwind; it is never given to
|
|
25
|
+
* a tool. Keeping these separate is what stops a cancel from settling the
|
|
26
|
+
* cell on top of a still-running, abort-insensitive merge.
|
|
27
|
+
*/
|
|
28
|
+
shieldedSignal?: AbortSignal;
|
|
17
29
|
emitStatus?: (event: JsStatusEvent) => void;
|
|
18
30
|
abortRequested?: () => boolean;
|
|
19
31
|
}
|
|
@@ -32,16 +44,24 @@ const registrations = new Map<string, PyToolBridgeEntry>();
|
|
|
32
44
|
let serverPromise: Promise<BridgeServer> | null = null;
|
|
33
45
|
|
|
34
46
|
/**
|
|
35
|
-
* Forward a bridge call to {@link callSessionTool}
|
|
36
|
-
*
|
|
47
|
+
* Forward a bridge call to {@link callSessionTool}, failing fast once the cell
|
|
48
|
+
* has been interrupted.
|
|
37
49
|
*
|
|
38
50
|
* Python invokes this bridge with blocking `urllib` requests from worker threads
|
|
39
|
-
* (each `agent()` / `tool.*` call).
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
51
|
+
* (each `agent()` / `tool.*` call). Two different aborts meet here:
|
|
52
|
+
*
|
|
53
|
+
* - {@link PyToolBridgeEntry.signal} goes to the tool, so a turn cancel tears
|
|
54
|
+
* down delegated work — subagents included — instead of leaving it running
|
|
55
|
+
* past the cell.
|
|
56
|
+
* - {@link PyToolBridgeEntry.shieldedSignal} decides when we may stop waiting.
|
|
57
|
+
* It is deferred across a critical `agent()` phase, so a cancel landing
|
|
58
|
+
* mid-merge cannot return early and let the cell settle while an
|
|
59
|
+
* abort-insensitive cherry-pick is still rewriting the repo.
|
|
60
|
+
*
|
|
61
|
+
* Calls arriving after an abort are rejected before starting. Otherwise the
|
|
62
|
+
* usual path is that the tool observes its own abort and rejects; the race only
|
|
63
|
+
* matters for tools that ignore the signal, keeping the kernel unwinding
|
|
64
|
+
* promptly instead of being hard-killed.
|
|
45
65
|
*/
|
|
46
66
|
async function callSessionToolPromptOnAbort(name: string, args: unknown, entry: PyToolBridgeEntry): Promise<unknown> {
|
|
47
67
|
if (entry.abortRequested?.()) {
|
|
@@ -52,7 +72,7 @@ async function callSessionToolPromptOnAbort(name: string, args: unknown, entry:
|
|
|
52
72
|
signal: entry.signal,
|
|
53
73
|
emitStatus: entry.emitStatus,
|
|
54
74
|
});
|
|
55
|
-
const signal = entry.signal;
|
|
75
|
+
const signal = entry.shieldedSignal ?? entry.signal;
|
|
56
76
|
if (!signal) return await call;
|
|
57
77
|
if (signal.aborted) {
|
|
58
78
|
void call.catch(() => {});
|
|
@@ -6,14 +6,14 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import * as fs from "node:fs";
|
|
8
8
|
import * as path from "node:path";
|
|
9
|
+
import * as arktype from "@oh-my-pi/omptype";
|
|
10
|
+
import * as zodModule from "@oh-my-pi/omptype/zod";
|
|
9
11
|
import { getAgentDir, getProjectDir, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import * as arktype from "arktype";
|
|
11
|
-
import * as zodModule from "zod/v4";
|
|
12
12
|
import { getConfigDirs } from "../../config";
|
|
13
13
|
import { execCommand } from "../../exec/exec";
|
|
14
14
|
// Runtime self-reference: dereference this namespace only inside loader functions to keep the index.ts cycle safe.
|
|
15
15
|
import * as PiCodingAgent from "../../index";
|
|
16
|
-
import * as typebox from "../typebox";
|
|
16
|
+
import * as typebox from "../legacy-typebox";
|
|
17
17
|
import { GreenCommand } from "./bundled/ci-green";
|
|
18
18
|
import { ReviewCommand } from "./bundled/review";
|
|
19
19
|
import type {
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
* Unlike markdown commands which expand to prompts, custom commands can execute
|
|
6
6
|
* arbitrary logic with full access to the hook context.
|
|
7
7
|
*/
|
|
8
|
-
import type * as arktype from "
|
|
9
|
-
import type * as
|
|
8
|
+
import type * as arktype from "@oh-my-pi/omptype";
|
|
9
|
+
import type * as TypeBox from "@oh-my-pi/omptype/typebox";
|
|
10
|
+
import type * as zod from "@oh-my-pi/omptype/zod";
|
|
10
11
|
import type { ExecOptions, ExecResult, HookCommandContext } from "../../extensibility/hooks/types";
|
|
11
12
|
import type * as PiCodingAgent from "../../index";
|
|
12
|
-
import type * as TypeBox from "../typebox";
|
|
13
13
|
|
|
14
14
|
// Re-export for custom commands to use
|
|
15
15
|
export type { ExecOptions, ExecResult, HookCommandContext };
|
|
@@ -27,7 +27,7 @@ export interface CustomCommandAPI {
|
|
|
27
27
|
typebox: typeof TypeBox;
|
|
28
28
|
/** Injected arktype module for validation in custom commands. */
|
|
29
29
|
arktype: typeof arktype;
|
|
30
|
-
/** Injected zod
|
|
30
|
+
/** Injected omptype-backed zod facade for command validation. */
|
|
31
31
|
zod: typeof zod;
|
|
32
32
|
/** Injected pi-coding-agent exports */
|
|
33
33
|
pi: typeof PiCodingAgent;
|
|
@@ -5,10 +5,10 @@
|
|
|
5
5
|
* CustomToolAPI to avoid import resolution issues with custom tools loaded from user directories.
|
|
6
6
|
*/
|
|
7
7
|
import * as path from "node:path";
|
|
8
|
+
import { type } from "@oh-my-pi/omptype";
|
|
9
|
+
import * as zodModule from "@oh-my-pi/omptype/zod";
|
|
8
10
|
import type { AgentToolResult } from "@oh-my-pi/pi-agent-core";
|
|
9
11
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
10
|
-
import { type } from "arktype";
|
|
11
|
-
import * as zodModule from "zod/v4";
|
|
12
12
|
import { toolCapability } from "../../capability/tool";
|
|
13
13
|
import { type CustomTool, loadCapability } from "../../discovery";
|
|
14
14
|
import type { ExecOptions } from "../../exec/exec";
|
|
@@ -17,7 +17,7 @@ import type { HookUIContext } from "../../extensibility/hooks/types";
|
|
|
17
17
|
import { getAllPluginToolPaths } from "../../extensibility/plugins/loader";
|
|
18
18
|
// Runtime self-reference: dereference this namespace only inside loader functions to keep the index.ts cycle safe.
|
|
19
19
|
import * as PiCodingAgent from "../../index";
|
|
20
|
-
import * as typebox from "../typebox";
|
|
20
|
+
import * as typebox from "../legacy-typebox";
|
|
21
21
|
import { createNoOpUIContext, resolvePath, withHostGuard } from "../utils";
|
|
22
22
|
import type { CustomToolAPI, CustomToolFactory, LoadedCustomTool, ToolLoadError } from "./types";
|
|
23
23
|
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
* Custom tools are TypeScript modules that define additional tools for the agent.
|
|
5
5
|
* They can provide custom rendering for tool calls and results in the TUI.
|
|
6
6
|
*/
|
|
7
|
+
|
|
8
|
+
import type { type as ArkType } from "@oh-my-pi/omptype";
|
|
9
|
+
import type * as TypeBox from "@oh-my-pi/omptype/typebox";
|
|
10
|
+
import type * as zod from "@oh-my-pi/omptype/zod";
|
|
7
11
|
import type {
|
|
8
12
|
AgentToolResult,
|
|
9
13
|
AgentToolUpdateCallback,
|
|
@@ -16,8 +20,6 @@ import type { CompactionResult } from "@oh-my-pi/pi-agent-core/compaction";
|
|
|
16
20
|
import type { FetchImpl, Model, Static, TSchema } from "@oh-my-pi/pi-ai";
|
|
17
21
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
18
22
|
import type { logger as PiLogger } from "@oh-my-pi/pi-utils";
|
|
19
|
-
import type { type as ArkType } from "arktype";
|
|
20
|
-
import type * as zod from "zod/v4";
|
|
21
23
|
import type { Rule } from "../../capability/rule";
|
|
22
24
|
import type { ModelRegistry } from "../../config/model-registry";
|
|
23
25
|
import type { Settings } from "../../config/settings";
|
|
@@ -29,7 +31,6 @@ import type { Theme } from "../../modes/theme/theme";
|
|
|
29
31
|
import type { ReadonlySessionManager } from "../../session/session-manager";
|
|
30
32
|
import type { TodoItem } from "../../tools/todo";
|
|
31
33
|
import type { RecoveredRetryError } from "../shared-events";
|
|
32
|
-
import type * as TypeBox from "../typebox";
|
|
33
34
|
|
|
34
35
|
/** Alias for clarity */
|
|
35
36
|
export type CustomToolUIContext = HookUIContext;
|
|
@@ -69,7 +70,7 @@ export interface CustomToolAPI {
|
|
|
69
70
|
typebox: typeof TypeBox;
|
|
70
71
|
/** Injected arktype module for arktype-authored custom tools. */
|
|
71
72
|
arktype: typeof ArkType;
|
|
72
|
-
/** Injected zod
|
|
73
|
+
/** Injected omptype-backed zod facade for parameter schemas. */
|
|
73
74
|
zod: typeof zod;
|
|
74
75
|
/** Injected pi-coding-agent exports */
|
|
75
76
|
pi: typeof PiCodingAgent;
|
|
@@ -4,6 +4,8 @@
|
|
|
4
4
|
import type * as fs1 from "node:fs";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
+
import { Type } from "@oh-my-pi/omptype";
|
|
8
|
+
import * as zodModule from "@oh-my-pi/omptype/zod";
|
|
7
9
|
import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core";
|
|
8
10
|
import type {
|
|
9
11
|
ImageContent,
|
|
@@ -16,8 +18,6 @@ import type {
|
|
|
16
18
|
} from "@oh-my-pi/pi-ai";
|
|
17
19
|
import type { KeyId } from "@oh-my-pi/pi-tui";
|
|
18
20
|
import { hasFsCode, isEacces, isEnoent, logger } from "@oh-my-pi/pi-utils";
|
|
19
|
-
import { Type } from "arktype";
|
|
20
|
-
import * as zodModule from "zod/v4";
|
|
21
21
|
import { type ExtensionModule, extensionModuleCapability } from "../../capability/extension-module";
|
|
22
22
|
import { type Hook, hookCapability } from "../../capability/hook";
|
|
23
23
|
import { isServiceTierFamily, isServiceTierForFamily } from "../../config/service-tier";
|
|
@@ -29,9 +29,9 @@ import { execCommand } from "../../exec/exec";
|
|
|
29
29
|
import * as PiCodingAgent from "../../index";
|
|
30
30
|
import type { CustomMessagePayload } from "../../session/messages";
|
|
31
31
|
import { EventBus } from "../../utils/event-bus";
|
|
32
|
+
import * as TypeBox from "../legacy-typebox";
|
|
32
33
|
import { installLegacyPiSpecifierShim, loadLegacyPiModule } from "../plugins/legacy-pi-compat";
|
|
33
34
|
import { getAllPluginExtensionPaths } from "../plugins/loader";
|
|
34
|
-
import * as TypeBox from "../typebox";
|
|
35
35
|
|
|
36
36
|
import { resolvePath, withHostGuard } from "../utils";
|
|
37
37
|
import type {
|