@oh-my-pi/pi-coding-agent 17.2.10 → 17.2.12
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 +53 -0
- package/dist/{CHANGELOG-rhwzpexa.md → CHANGELOG-k9ghy5sn.md} +53 -0
- package/dist/cli.js +10775 -10762
- package/dist/types/advisor/runtime.d.ts +1 -1
- package/dist/types/capability/mcp.d.ts +11 -0
- package/dist/types/capability/skill.d.ts +6 -0
- package/dist/types/cli/command-help.d.ts +3 -0
- package/dist/types/commands/share.d.ts +25 -0
- package/dist/types/commit/agentic/index.d.ts +3 -1
- package/dist/types/commit/execute.d.ts +32 -0
- package/dist/types/commit/index.d.ts +2 -1
- package/dist/types/commit/pipeline.d.ts +7 -1
- package/dist/types/config/custom-models.d.ts +31 -0
- package/dist/types/config/model-config-values.d.ts +19 -0
- package/dist/types/config/model-patch.d.ts +93 -0
- package/dist/types/config/model-provider-discovery.d.ts +51 -0
- package/dist/types/config/model-registry.d.ts +9 -52
- package/dist/types/config/settings-schema.d.ts +1 -34
- package/dist/types/config/settings.d.ts +5 -3
- package/dist/types/debug/raw-sse-buffer.d.ts +9 -0
- package/dist/types/discovery/agent-plugin-format.d.ts +136 -0
- package/dist/types/discovery/agent-plugins.d.ts +1 -0
- package/dist/types/discovery/contained-path.d.ts +33 -0
- package/dist/types/discovery/index.d.ts +1 -0
- package/dist/types/eval/executor-base.d.ts +8 -2
- package/dist/types/eval/kernel-session-registry.d.ts +60 -0
- package/dist/types/export/share.d.ts +1 -1
- package/dist/types/extensibility/custom-tools/types.d.ts +2 -2
- package/dist/types/extensibility/extensions/loader.d.ts +7 -0
- package/dist/types/extensibility/extensions/types.d.ts +11 -0
- package/dist/types/extensibility/shared-events.d.ts +3 -2
- package/dist/types/extensibility/skills.d.ts +5 -0
- package/dist/types/lsp/diagnostics.d.ts +96 -0
- package/dist/types/lsp/index.d.ts +7 -128
- package/dist/types/lsp/servers.d.ts +72 -0
- package/dist/types/lsp/tool.d.ts +42 -0
- package/dist/types/lsp/workspace-diagnostics.d.ts +12 -0
- package/dist/types/lsp/writethrough.d.ts +33 -0
- package/dist/types/mcp/transports/header-policy.d.ts +46 -0
- package/dist/types/mcp/types.d.ts +15 -0
- package/dist/types/modes/components/agent-hub-projection.d.ts +2 -7
- package/dist/types/modes/components/agent-hub-renderer.d.ts +0 -7
- package/dist/types/modes/components/agent-hub.d.ts +2 -0
- package/dist/types/modes/components/agent-transcript-viewer.d.ts +2 -0
- package/dist/types/modes/components/chat-transcript-builder.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +1 -2
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/theme/color.d.ts +19 -0
- package/dist/types/modes/theme/loader.d.ts +19 -0
- package/dist/types/modes/theme/schema.d.ts +175 -0
- package/dist/types/modes/theme/symbols.d.ts +28 -0
- package/dist/types/modes/theme/theme-class.d.ts +244 -0
- package/dist/types/modes/theme/theme.d.ts +9 -280
- package/dist/types/modes/theme/tui-adapters.d.ts +13 -0
- package/dist/types/modes/utils/transcript-render-helpers.d.ts +3 -2
- package/dist/types/registry/agent-registry.d.ts +1 -3
- package/dist/types/secrets/index.d.ts +26 -2
- package/dist/types/secrets/message-transform.d.ts +40 -0
- package/dist/types/secrets/obfuscator.d.ts +0 -108
- package/dist/types/secrets/placeholder-scan.d.ts +95 -0
- package/dist/types/secrets/placeholder.d.ts +94 -0
- package/dist/types/secrets/replacement.d.ts +82 -0
- package/dist/types/session/agent-session-events.d.ts +2 -2
- package/dist/types/session/agent-session-types.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +2 -2
- package/dist/types/session/messages.d.ts +1 -0
- package/dist/types/session/prewalk.d.ts +3 -1
- package/dist/types/session/session-handoff.d.ts +3 -3
- package/dist/types/session/session-manager.d.ts +32 -0
- package/dist/types/session/session-provider-boundary.d.ts +1 -1
- package/dist/types/session/session-tools.d.ts +8 -0
- package/dist/types/session/turn-recovery.d.ts +9 -4
- package/dist/types/slash-commands/builtin-collaboration.d.ts +2 -0
- package/dist/types/slash-commands/builtin-completions.d.ts +36 -0
- package/dist/types/slash-commands/builtin-control.d.ts +2 -0
- package/dist/types/slash-commands/builtin-lifecycle.d.ts +3 -0
- package/dist/types/slash-commands/builtin-marketplace.d.ts +11 -0
- package/dist/types/slash-commands/builtin-modes.d.ts +5 -0
- package/dist/types/slash-commands/builtin-registry.d.ts +1 -1
- package/dist/types/slash-commands/builtin-session.d.ts +2 -0
- package/dist/types/task/index.d.ts +2 -0
- package/dist/types/tools/gh-common.d.ts +69 -0
- package/dist/types/tools/gh-pr-checkout.d.ts +84 -0
- package/dist/types/tools/gh-pr-diff.d.ts +102 -0
- package/dist/types/tools/gh-run-watch.d.ts +78 -0
- package/dist/types/tools/gh-search.d.ts +61 -0
- package/dist/types/tools/gh-types.d.ts +340 -0
- package/dist/types/tools/gh-view.d.ts +88 -0
- package/dist/types/tools/gh.d.ts +4 -201
- package/dist/types/tools/read-archive.d.ts +16 -0
- package/dist/types/tools/read-format.d.ts +104 -0
- package/dist/types/tools/read-path-resolution.d.ts +19 -0
- package/dist/types/tools/read-pdf-images.d.ts +12 -0
- package/dist/types/tools/read-renderer.d.ts +24 -0
- package/dist/types/tools/read-selector.d.ts +27 -0
- package/dist/types/tools/read-sqlite.d.ts +16 -0
- package/dist/types/tools/read-summary.d.ts +19 -0
- package/dist/types/tools/read.d.ts +1 -23
- package/dist/types/tools/shell-tokenize.d.ts +18 -1
- package/dist/types/utils/changelog.d.ts +0 -5
- package/package.json +13 -13
- package/scripts/legacy-pi-virtual-module.ts +4 -1
- package/src/advisor/runtime.ts +12 -7
- package/src/capability/mcp.ts +11 -0
- package/src/capability/skill.ts +6 -0
- package/src/cli/command-help.ts +4 -0
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli-commands.ts +5 -0
- package/src/commands/commit.ts +16 -3
- package/src/commands/share.ts +71 -0
- package/src/commit/agentic/index.ts +39 -21
- package/src/commit/execute.ts +56 -0
- package/src/commit/index.ts +2 -1
- package/src/commit/pipeline.ts +20 -7
- package/src/config/custom-models.ts +188 -0
- package/src/config/model-config-values.ts +128 -0
- package/src/config/model-discovery.ts +1 -1
- package/src/config/model-patch.ts +252 -0
- package/src/config/model-provider-discovery.ts +132 -0
- package/src/config/model-registry.ts +84 -704
- package/src/config/settings-schema.ts +2 -33
- package/src/config/settings.ts +53 -3
- package/src/debug/raw-sse-buffer.ts +20 -0
- package/src/discovery/agent-plugin-format.ts +551 -0
- package/src/discovery/agent-plugins.ts +341 -0
- package/src/discovery/claude-plugins.ts +21 -5
- package/src/discovery/contained-path.ts +75 -0
- package/src/discovery/helpers.ts +23 -9
- package/src/discovery/index.ts +1 -0
- package/src/discovery/omp-plugins.ts +20 -7
- package/src/edit/hashline/diff.ts +5 -1
- package/src/eval/executor-base.ts +39 -6
- package/src/eval/jl/executor.ts +82 -371
- package/src/eval/kernel-session-registry.ts +398 -0
- package/src/eval/py/executor.ts +53 -261
- package/src/eval/rb/executor.ts +36 -279
- package/src/exec/non-interactive-env.ts +1 -0
- package/src/export/share.ts +2 -1
- package/src/extensibility/custom-tools/types.ts +2 -2
- package/src/extensibility/extensions/loader.ts +78 -14
- package/src/extensibility/extensions/runner.ts +6 -0
- package/src/extensibility/extensions/types.ts +12 -0
- package/src/extensibility/plugins/marketplace/manager.ts +2 -1
- package/src/extensibility/shared-events.ts +3 -2
- package/src/extensibility/skills.ts +9 -0
- package/src/internal-urls/skill-protocol.ts +14 -0
- package/src/internal-urls/vault-protocol.ts +2 -2
- package/src/launch/client.ts +11 -1
- package/src/launch/protocol.ts +7 -2
- package/src/lsp/diagnostics.ts +516 -0
- package/src/lsp/index.ts +20 -2819
- package/src/lsp/servers.ts +296 -0
- package/src/lsp/tool.ts +1352 -0
- package/src/lsp/workspace-diagnostics.ts +170 -0
- package/src/lsp/writethrough.ts +561 -0
- package/src/main.ts +3 -2
- package/src/mcp/config.ts +3 -0
- package/src/mcp/manager.ts +12 -9
- package/src/mcp/transports/header-policy.ts +95 -0
- package/src/mcp/transports/http.ts +35 -52
- package/src/mcp/transports/sse.ts +20 -27
- package/src/mcp/types.ts +15 -0
- package/src/modes/acp/acp-agent.ts +15 -4
- package/src/modes/components/agent-dashboard.ts +2 -0
- package/src/modes/components/agent-hub-projection.ts +2 -2
- package/src/modes/components/agent-hub-renderer.ts +3 -7
- package/src/modes/components/agent-hub.ts +5 -0
- package/src/modes/components/agent-transcript-viewer.ts +3 -0
- package/src/modes/components/chat-transcript-builder.ts +3 -0
- package/src/modes/components/custom-editor.ts +0 -9
- package/src/modes/components/status-line/component.ts +1 -0
- package/src/modes/components/status-line/segments.ts +6 -4
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/tool-execution.ts +13 -16
- package/src/modes/components/tree-selector.ts +62 -3
- package/src/modes/controllers/command-controller.ts +8 -2
- package/src/modes/controllers/event-controller.ts +15 -15
- package/src/modes/controllers/input-controller.ts +20 -2
- package/src/modes/controllers/selector-controller.ts +1 -0
- package/src/modes/theme/color.ts +133 -0
- package/src/modes/theme/loader.ts +178 -0
- package/src/modes/theme/schema.ts +263 -0
- package/src/modes/theme/symbols.ts +1000 -0
- package/src/modes/theme/theme-class.ts +611 -0
- package/src/modes/theme/theme.ts +27 -2453
- package/src/modes/theme/tui-adapters.ts +279 -0
- package/src/modes/utils/transcript-render-helpers.ts +4 -2
- package/src/modes/utils/ui-helpers.ts +1 -0
- package/src/registry/agent-registry.ts +2 -2
- package/src/sdk.ts +6 -49
- package/src/secrets/index.ts +51 -6
- package/src/secrets/message-transform.ts +287 -0
- package/src/secrets/obfuscator.ts +39 -1303
- package/src/secrets/placeholder-scan.ts +506 -0
- package/src/secrets/placeholder.ts +309 -0
- package/src/secrets/replacement.ts +216 -0
- package/src/session/agent-session-events.ts +2 -2
- package/src/session/agent-session-types.ts +6 -0
- package/src/session/agent-session.ts +146 -21
- package/src/session/indexed-session-storage.ts +7 -2
- package/src/session/messages.ts +1 -0
- package/src/session/prewalk.ts +57 -17
- package/src/session/session-advisors.ts +32 -34
- package/src/session/session-context.ts +3 -5
- package/src/session/session-handoff.ts +39 -16
- package/src/session/session-manager.ts +67 -3
- package/src/session/session-provider-boundary.ts +3 -6
- package/src/session/session-tools.ts +37 -3
- package/src/session/todo-tracker.ts +11 -1
- package/src/session/turn-recovery.ts +115 -84
- package/src/slash-commands/builtin-collaboration.ts +504 -0
- package/src/slash-commands/builtin-completions.ts +291 -0
- package/src/slash-commands/builtin-control.ts +78 -0
- package/src/slash-commands/builtin-lifecycle.ts +506 -0
- package/src/slash-commands/builtin-marketplace.ts +567 -0
- package/src/slash-commands/builtin-modes.ts +518 -0
- package/src/slash-commands/builtin-registry.ts +21 -2996
- package/src/slash-commands/builtin-session.ts +592 -0
- package/src/task/executor.ts +17 -14
- package/src/task/index.ts +21 -6
- package/src/tools/bash-skill-urls.ts +15 -0
- package/src/tools/bash.ts +10 -11
- package/src/tools/debug.ts +1 -1
- package/src/tools/gh-common.ts +288 -0
- package/src/tools/gh-pr-checkout.ts +679 -0
- package/src/tools/gh-pr-diff.ts +473 -0
- package/src/tools/gh-run-watch.ts +1015 -0
- package/src/tools/gh-search.ts +500 -0
- package/src/tools/gh-types.ts +379 -0
- package/src/tools/gh-view.ts +612 -0
- package/src/tools/gh.ts +109 -3821
- package/src/tools/jtd-to-json-schema.ts +123 -21
- package/src/tools/read-archive.ts +209 -0
- package/src/tools/read-format.ts +593 -0
- package/src/tools/read-path-resolution.ts +36 -0
- package/src/tools/read-pdf-images.ts +250 -0
- package/src/tools/read-renderer.ts +289 -0
- package/src/tools/read-selector.ts +84 -0
- package/src/tools/read-sqlite.ts +215 -0
- package/src/tools/read-summary.ts +199 -0
- package/src/tools/read.ts +82 -1824
- package/src/tools/shell-tokenize.ts +99 -1
- package/src/utils/changelog.ts +1 -1
- package/src/utils/title-generator.ts +3 -1
- package/src/web/search/providers/exa.ts +1 -1
- package/src/web/search/providers/zai.ts +12 -3
package/src/eval/rb/executor.ts
CHANGED
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import * as fs from "node:fs";
|
|
2
|
-
import * as path from "node:path";
|
|
3
2
|
|
|
4
3
|
import { getProjectDir, logger } from "@oh-my-pi/pi-utils";
|
|
5
4
|
import type { ToolSession } from "../../tools";
|
|
6
5
|
import {
|
|
7
|
-
attachSessionOwner,
|
|
8
6
|
buildManagedKernelEnv,
|
|
9
7
|
buildManagedKernelEnvPatch,
|
|
10
8
|
createCancelledKernelResult,
|
|
11
9
|
executeWithKernelBase,
|
|
12
10
|
getExecutionDeadlineMs,
|
|
13
|
-
getRemainingTimeoutMs,
|
|
14
11
|
isCancellationError,
|
|
15
12
|
isTimedOutCancellation,
|
|
16
|
-
resolveOwnerScopedSessionKey,
|
|
17
13
|
waitForPromiseWithCancellation,
|
|
18
14
|
} from "../executor-base";
|
|
19
15
|
import type { JsStatusEvent } from "../js/shared/types";
|
|
16
|
+
import {
|
|
17
|
+
createKernelSessionRegistry,
|
|
18
|
+
formatSessionKernelTimeoutAnnotation,
|
|
19
|
+
formatSessionTimeoutAnnotation,
|
|
20
|
+
type KernelSession,
|
|
21
|
+
normalizeKernelSessionCwd,
|
|
22
|
+
requireRemainingKernelTimeoutMs,
|
|
23
|
+
} from "../kernel-session-registry";
|
|
20
24
|
import { ensurePyToolBridge } from "../py/tool-bridge";
|
|
21
25
|
import {
|
|
22
26
|
checkRubyKernelAvailability,
|
|
@@ -97,39 +101,6 @@ export interface RubyResult {
|
|
|
97
101
|
stdinRequested: boolean;
|
|
98
102
|
}
|
|
99
103
|
|
|
100
|
-
// ---------------------------------------------------------------------------
|
|
101
|
-
// Session bookkeeping
|
|
102
|
-
//
|
|
103
|
-
// One RubyKernel subprocess per (session id, cwd, interpreter) tuple. The
|
|
104
|
-
// runner mutates process-global cwd/$LOAD_PATH/ENV during execution, so
|
|
105
|
-
// cross-directory work must never share a live kernel. Multiple agent owners can
|
|
106
|
-
// register against the same tuple; the kernel stays alive until the last owner detaches.
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
|
|
109
|
-
interface RubySessionOwners {
|
|
110
|
-
ownerIds: Set<string>;
|
|
111
|
-
hasFallbackOwner: boolean;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
interface RubySession extends RubySessionOwners {
|
|
115
|
-
sessionKey: string;
|
|
116
|
-
sessionId: string;
|
|
117
|
-
cwd: string;
|
|
118
|
-
kernel: RubyKernel;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
interface StartingRubySession extends RubySessionOwners {
|
|
122
|
-
promise: Promise<RubySession>;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
const sessions = new Map<string, RubySession>();
|
|
126
|
-
const startingSessions = new Map<string, StartingRubySession>();
|
|
127
|
-
const resettingSessions = new Map<string, Promise<void>>();
|
|
128
|
-
|
|
129
|
-
function normalizeSessionCwd(cwd: string): string {
|
|
130
|
-
return path.resolve(cwd);
|
|
131
|
-
}
|
|
132
|
-
|
|
133
104
|
function normalizeExplicitInterpreter(cwd: string, interpreter: string | undefined): string {
|
|
134
105
|
if (interpreter === undefined) return "";
|
|
135
106
|
const resolved = resolveExplicitRubyRuntime(interpreter, cwd, {}).rubyPath;
|
|
@@ -140,11 +111,6 @@ function normalizeExplicitInterpreter(cwd: string, interpreter: string | undefin
|
|
|
140
111
|
}
|
|
141
112
|
}
|
|
142
113
|
|
|
143
|
-
function buildSessionKey(sessionId: string, cwd: string, interpreter: string | undefined): string {
|
|
144
|
-
const normalizedCwd = normalizeSessionCwd(cwd);
|
|
145
|
-
return `${sessionId}\0${normalizedCwd}\0${normalizeExplicitInterpreter(normalizedCwd, interpreter)}`;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
114
|
// ---------------------------------------------------------------------------
|
|
149
115
|
// Cancellation plumbing
|
|
150
116
|
// ---------------------------------------------------------------------------
|
|
@@ -160,32 +126,16 @@ class RubyExecutionCancelledError extends Error {
|
|
|
160
126
|
}
|
|
161
127
|
|
|
162
128
|
function requireRemainingTimeoutMs(deadlineMs?: number): number | undefined {
|
|
163
|
-
|
|
164
|
-
if (remainingMs === undefined) return undefined;
|
|
165
|
-
if (remainingMs <= 0) {
|
|
166
|
-
throw new RubyExecutionCancelledError(true);
|
|
167
|
-
}
|
|
168
|
-
return remainingMs;
|
|
129
|
+
return requireRemainingKernelTimeoutMs(deadlineMs, RubyExecutionCancelledError);
|
|
169
130
|
}
|
|
170
131
|
|
|
171
132
|
// ---------------------------------------------------------------------------
|
|
172
133
|
// Result formatting
|
|
173
134
|
// ---------------------------------------------------------------------------
|
|
174
135
|
|
|
175
|
-
|
|
176
|
-
if (timeoutMs === undefined) return "Command timed out";
|
|
177
|
-
const secs = Math.max(1, Math.round(timeoutMs / 1000));
|
|
178
|
-
return `Command timed out after ${secs} seconds`;
|
|
179
|
-
}
|
|
136
|
+
const formatTimeoutAnnotation = formatSessionTimeoutAnnotation;
|
|
180
137
|
|
|
181
|
-
|
|
182
|
-
const secs = timeoutMs === undefined ? undefined : Math.max(1, Math.round(timeoutMs / 1000));
|
|
183
|
-
if (kernelKilled) {
|
|
184
|
-
return "eval cell timed out and the kernel was unresponsive to interrupt; the kernel has been killed and will be recreated on the next call.";
|
|
185
|
-
}
|
|
186
|
-
const duration = secs === undefined ? "the configured timeout" : `${secs}s`;
|
|
187
|
-
return `eval cell timed out after ${duration}; kernel interrupted but remains running. Reset the kernel via { reset: true } if state appears corrupted.`;
|
|
188
|
-
}
|
|
138
|
+
const formatKernelTimeoutAnnotation = formatSessionKernelTimeoutAnnotation;
|
|
189
139
|
|
|
190
140
|
function createCancelledRubyResult(timedOut: boolean, timeoutMs?: number): RubyResult {
|
|
191
141
|
const output = timedOut ? (formatTimeoutAnnotation(timeoutMs) ?? "Command timed out") : "";
|
|
@@ -207,161 +157,6 @@ async function startKernel(cwd: string, options: RubyExecutorOptions): Promise<R
|
|
|
207
157
|
});
|
|
208
158
|
}
|
|
209
159
|
|
|
210
|
-
async function acquireSession(
|
|
211
|
-
sessionKey: string,
|
|
212
|
-
sessionId: string,
|
|
213
|
-
cwd: string,
|
|
214
|
-
options: RubyExecutorOptions,
|
|
215
|
-
): Promise<RubySession> {
|
|
216
|
-
const existing = sessions.get(sessionKey);
|
|
217
|
-
if (existing) {
|
|
218
|
-
attachSessionOwner(existing, sessionId, options.kernelOwnerId);
|
|
219
|
-
return existing;
|
|
220
|
-
}
|
|
221
|
-
const starting = startingSessions.get(sessionKey);
|
|
222
|
-
if (starting) {
|
|
223
|
-
attachSessionOwner(starting, sessionId, options.kernelOwnerId);
|
|
224
|
-
return await starting.promise;
|
|
225
|
-
}
|
|
226
|
-
let startingSession!: StartingRubySession;
|
|
227
|
-
const startup = (async () => {
|
|
228
|
-
const kernel = await startKernel(cwd, options);
|
|
229
|
-
const session: RubySession = {
|
|
230
|
-
sessionKey,
|
|
231
|
-
sessionId,
|
|
232
|
-
cwd,
|
|
233
|
-
kernel,
|
|
234
|
-
ownerIds: new Set(startingSession.ownerIds),
|
|
235
|
-
hasFallbackOwner: startingSession.hasFallbackOwner,
|
|
236
|
-
};
|
|
237
|
-
if (startingSessions.get(sessionKey) === startingSession) {
|
|
238
|
-
sessions.set(sessionKey, session);
|
|
239
|
-
}
|
|
240
|
-
return session;
|
|
241
|
-
})();
|
|
242
|
-
startingSession = {
|
|
243
|
-
ownerIds: new Set(),
|
|
244
|
-
hasFallbackOwner: false,
|
|
245
|
-
promise: startup,
|
|
246
|
-
};
|
|
247
|
-
attachSessionOwner(startingSession, sessionId, options.kernelOwnerId);
|
|
248
|
-
startingSessions.set(sessionKey, startingSession);
|
|
249
|
-
try {
|
|
250
|
-
return await startup;
|
|
251
|
-
} finally {
|
|
252
|
-
if (startingSessions.get(sessionKey) === startingSession) startingSessions.delete(sessionKey);
|
|
253
|
-
}
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
async function replaceSessionKernel(session: RubySession, cwd: string, options: RubyExecutorOptions): Promise<void> {
|
|
257
|
-
const old = session.kernel;
|
|
258
|
-
const remaining = getRemainingTimeoutMs(options.deadlineMs);
|
|
259
|
-
await old
|
|
260
|
-
.shutdown(remaining !== undefined ? { timeoutMs: Math.max(0, remaining) } : undefined)
|
|
261
|
-
.catch(() => undefined);
|
|
262
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
263
|
-
throw new RubyExecutionCancelledError(false);
|
|
264
|
-
}
|
|
265
|
-
requireRemainingTimeoutMs(options.deadlineMs);
|
|
266
|
-
const next = await startKernel(cwd, options);
|
|
267
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
268
|
-
await next.shutdown().catch(() => undefined);
|
|
269
|
-
throw new RubyExecutionCancelledError(false);
|
|
270
|
-
}
|
|
271
|
-
session.kernel = next;
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
async function resetSession(sessionKey: string): Promise<void> {
|
|
275
|
-
const existing =
|
|
276
|
-
sessions.get(sessionKey) ?? (await startingSessions.get(sessionKey)?.promise.catch(() => undefined));
|
|
277
|
-
if (!existing) return;
|
|
278
|
-
sessions.delete(sessionKey);
|
|
279
|
-
await existing.kernel.shutdown().catch(() => undefined);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
// ---------------------------------------------------------------------------
|
|
283
|
-
// Public dispose entry points
|
|
284
|
-
// ---------------------------------------------------------------------------
|
|
285
|
-
|
|
286
|
-
export async function disposeAllRubyKernelSessions(): Promise<void> {
|
|
287
|
-
const pending = [...startingSessions.values()].map(starting => starting.promise);
|
|
288
|
-
startingSessions.clear();
|
|
289
|
-
const started = await Promise.allSettled(pending);
|
|
290
|
-
const all = [...sessions.entries()];
|
|
291
|
-
for (const result of started) {
|
|
292
|
-
if (result.status !== "fulfilled") continue;
|
|
293
|
-
if (!all.some(([, session]) => session === result.value)) {
|
|
294
|
-
all.push([result.value.sessionKey, result.value]);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
for (const [id, session] of all) {
|
|
298
|
-
if (sessions.get(id) === session) sessions.delete(id);
|
|
299
|
-
}
|
|
300
|
-
const results = await Promise.allSettled(all.map(([, session]) => session.kernel.shutdown()));
|
|
301
|
-
for (let i = 0; i < all.length; i += 1) {
|
|
302
|
-
const [id, session] = all[i];
|
|
303
|
-
const result = results[i];
|
|
304
|
-
if (result.status === "fulfilled" && result.value?.confirmed !== false) continue;
|
|
305
|
-
const reason = result.status === "rejected" ? result.reason : "not confirmed";
|
|
306
|
-
logger.warn("Ruby kernel shutdown not confirmed", {
|
|
307
|
-
sessionId: session.sessionId,
|
|
308
|
-
sessionKey: id,
|
|
309
|
-
cwd: session.cwd,
|
|
310
|
-
reason,
|
|
311
|
-
});
|
|
312
|
-
if (!sessions.has(id)) sessions.set(id, session);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
export async function disposeRubyKernelSessionsByOwner(ownerId: string): Promise<void> {
|
|
317
|
-
const toShutdown: RubySession[] = [];
|
|
318
|
-
const startingToShutdown: StartingRubySession[] = [];
|
|
319
|
-
for (const session of [...sessions.values()]) {
|
|
320
|
-
if (!session.ownerIds.has(ownerId)) continue;
|
|
321
|
-
if (session.ownerIds.size === 1) {
|
|
322
|
-
toShutdown.push(session);
|
|
323
|
-
continue;
|
|
324
|
-
}
|
|
325
|
-
session.ownerIds.delete(ownerId);
|
|
326
|
-
}
|
|
327
|
-
for (const [sessionKey, starting] of [...startingSessions.entries()]) {
|
|
328
|
-
if (sessions.has(sessionKey) || !starting.ownerIds.has(ownerId)) continue;
|
|
329
|
-
if (starting.ownerIds.size === 1) {
|
|
330
|
-
startingSessions.delete(sessionKey);
|
|
331
|
-
startingToShutdown.push(starting);
|
|
332
|
-
continue;
|
|
333
|
-
}
|
|
334
|
-
starting.ownerIds.delete(ownerId);
|
|
335
|
-
}
|
|
336
|
-
for (const session of toShutdown) {
|
|
337
|
-
if (sessions.get(session.sessionKey) === session) sessions.delete(session.sessionKey);
|
|
338
|
-
}
|
|
339
|
-
const started = await Promise.allSettled(startingToShutdown.map(starting => starting.promise));
|
|
340
|
-
for (const result of started) {
|
|
341
|
-
if (result.status !== "fulfilled") continue;
|
|
342
|
-
const session = result.value;
|
|
343
|
-
if (sessions.get(session.sessionKey) === session) sessions.delete(session.sessionKey);
|
|
344
|
-
toShutdown.push(session);
|
|
345
|
-
}
|
|
346
|
-
const results = await Promise.allSettled(toShutdown.map(session => session.kernel.shutdown()));
|
|
347
|
-
for (let i = 0; i < toShutdown.length; i += 1) {
|
|
348
|
-
const session = toShutdown[i];
|
|
349
|
-
const result = results[i];
|
|
350
|
-
if (result.status === "fulfilled" && result.value?.confirmed !== false) {
|
|
351
|
-
session.ownerIds.delete(ownerId);
|
|
352
|
-
continue;
|
|
353
|
-
}
|
|
354
|
-
const reason = result.status === "rejected" ? result.reason : "not confirmed";
|
|
355
|
-
logger.warn("Ruby kernel shutdown not confirmed", {
|
|
356
|
-
sessionId: session.sessionId,
|
|
357
|
-
sessionKey: session.sessionKey,
|
|
358
|
-
cwd: session.cwd,
|
|
359
|
-
reason,
|
|
360
|
-
});
|
|
361
|
-
if (!sessions.has(session.sessionKey)) sessions.set(session.sessionKey, session);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
|
|
365
160
|
// ---------------------------------------------------------------------------
|
|
366
161
|
// Execution
|
|
367
162
|
// ---------------------------------------------------------------------------
|
|
@@ -406,67 +201,29 @@ async function ensureToolBridge(options: RubyExecutorOptions): Promise<void> {
|
|
|
406
201
|
}
|
|
407
202
|
}
|
|
408
203
|
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
} finally {
|
|
433
|
-
resettingSessions.delete(sessionKey);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
} else {
|
|
437
|
-
const inFlight = resettingSessions.get(sessionKey);
|
|
438
|
-
if (inFlight) await inFlight.catch(() => undefined);
|
|
439
|
-
}
|
|
440
|
-
const session = await acquireSession(sessionKey, sessionId, cwd, options);
|
|
441
|
-
if (options.signal?.aborted) {
|
|
442
|
-
throw new RubyExecutionCancelledError(
|
|
443
|
-
isTimedOutCancellation(options.signal.reason, RubyExecutionCancelledError, options.signal),
|
|
444
|
-
);
|
|
445
|
-
}
|
|
446
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
447
|
-
throw new RubyExecutionCancelledError(false);
|
|
448
|
-
}
|
|
449
|
-
if (!session.kernel.isAlive()) {
|
|
450
|
-
await replaceSessionKernel(session, cwd, options);
|
|
451
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
452
|
-
throw new RubyExecutionCancelledError(false);
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
const runOptions = { ...options, cwd };
|
|
456
|
-
try {
|
|
457
|
-
return await executeWithKernel(session.kernel, code, runOptions);
|
|
458
|
-
} catch (err) {
|
|
459
|
-
if (isCancellationError(err, RubyExecutionCancelledError) || options.signal?.aborted) throw err;
|
|
460
|
-
if (session.kernel.isAlive()) throw err;
|
|
461
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
462
|
-
throw new RubyExecutionCancelledError(false);
|
|
463
|
-
}
|
|
464
|
-
await replaceSessionKernel(session, cwd, options);
|
|
465
|
-
if (sessions.get(session.sessionKey) !== session) {
|
|
466
|
-
throw new RubyExecutionCancelledError(false);
|
|
467
|
-
}
|
|
468
|
-
return await executeWithKernel(session.kernel, code, runOptions);
|
|
469
|
-
}
|
|
204
|
+
const sessionRegistry = createKernelSessionRegistry<
|
|
205
|
+
RubyKernel,
|
|
206
|
+
RubyExecutorOptions,
|
|
207
|
+
RubyResult,
|
|
208
|
+
KernelSession<RubyKernel>
|
|
209
|
+
>({
|
|
210
|
+
languageLabel: "Ruby",
|
|
211
|
+
cancelledErrorClass: RubyExecutionCancelledError,
|
|
212
|
+
buildSessionKey: (sessionId, cwd, interpreter) => {
|
|
213
|
+
const normalizedCwd = normalizeKernelSessionCwd(cwd);
|
|
214
|
+
return `${sessionId}\0${normalizedCwd}\0${normalizeExplicitInterpreter(normalizedCwd, interpreter)}`;
|
|
215
|
+
},
|
|
216
|
+
createSession: session => session,
|
|
217
|
+
startKernel,
|
|
218
|
+
executeWithKernel,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
export async function disposeAllRubyKernelSessions(): Promise<void> {
|
|
222
|
+
await sessionRegistry.disposeAll();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export async function disposeRubyKernelSessionsByOwner(ownerId: string): Promise<void> {
|
|
226
|
+
await sessionRegistry.disposeByOwner(ownerId);
|
|
470
227
|
}
|
|
471
228
|
|
|
472
229
|
export async function executeRubyWithKernel(
|
|
@@ -478,7 +235,7 @@ export async function executeRubyWithKernel(
|
|
|
478
235
|
}
|
|
479
236
|
|
|
480
237
|
export async function executeRuby(code: string, options?: RubyExecutorOptions): Promise<RubyResult> {
|
|
481
|
-
const cwd =
|
|
238
|
+
const cwd = normalizeKernelSessionCwd(options?.cwd ?? getProjectDir());
|
|
482
239
|
const deadlineMs = getExecutionDeadlineMs(options);
|
|
483
240
|
const executionOptions: RubyExecutorOptions = {
|
|
484
241
|
...(options ?? {}),
|
|
@@ -499,7 +256,7 @@ export async function executeRuby(code: string, options?: RubyExecutorOptions):
|
|
|
499
256
|
}
|
|
500
257
|
await ensureKernelAvailable(cwd, executionOptions);
|
|
501
258
|
await ensureToolBridge(executionOptions);
|
|
502
|
-
return await executeOnSession(code, cwd, executionOptions);
|
|
259
|
+
return await sessionRegistry.executeOnSession(code, cwd, executionOptions);
|
|
503
260
|
} catch (err) {
|
|
504
261
|
if (isCancellationError(err, RubyExecutionCancelledError) || executionOptions.signal?.aborted) {
|
|
505
262
|
return createCancelledRubyResult(
|
|
@@ -24,6 +24,7 @@ export const NON_INTERACTIVE_ENV: Readonly<Record<string, string>> = {
|
|
|
24
24
|
GIT_TERMINAL_PROMPT: "0",
|
|
25
25
|
SSH_ASKPASS: "/usr/bin/false",
|
|
26
26
|
CI: "1",
|
|
27
|
+
AGENT: "1",
|
|
27
28
|
// Package manager defaults for unattended execution.
|
|
28
29
|
npm_config_yes: "true",
|
|
29
30
|
npm_config_update_notifier: "false",
|
package/src/export/share.ts
CHANGED
|
@@ -24,7 +24,8 @@ import type { AssistantMessage, ImageContent, TextContent } from "@oh-my-pi/pi-a
|
|
|
24
24
|
import { $which, logger } from "@oh-my-pi/pi-utils";
|
|
25
25
|
import { DEFAULT_SHARE_URL } from "@oh-my-pi/pi-wire";
|
|
26
26
|
import { $ } from "bun";
|
|
27
|
-
import { obfuscateToolArguments
|
|
27
|
+
import { obfuscateToolArguments } from "../secrets/message-transform";
|
|
28
|
+
import type { SecretObfuscator } from "../secrets/obfuscator";
|
|
28
29
|
import { type SessionEntry, type SessionHeader, TITLE_CHANGE_ENTRY_TYPE } from "../session/session-entries";
|
|
29
30
|
import type { SessionManager } from "../session/session-manager";
|
|
30
31
|
import type { OutputMeta } from "../tools/output-meta";
|
|
@@ -30,7 +30,7 @@ import type { LocalProtocolOptions } from "../../internal-urls/local-protocol";
|
|
|
30
30
|
import type { Theme } from "../../modes/theme/theme";
|
|
31
31
|
import type { ReadonlySessionManager } from "../../session/session-manager";
|
|
32
32
|
import type { TodoItem } from "../../tools/todo";
|
|
33
|
-
import type {
|
|
33
|
+
import type { RetryErrorUpdate } from "../shared-events";
|
|
34
34
|
|
|
35
35
|
/** Alias for clarity */
|
|
36
36
|
export type CustomToolUIContext = HookUIContext;
|
|
@@ -139,7 +139,7 @@ export type CustomToolSessionEvent =
|
|
|
139
139
|
success: boolean;
|
|
140
140
|
attempt: number;
|
|
141
141
|
finalError?: string;
|
|
142
|
-
|
|
142
|
+
retryErrors?: RetryErrorUpdate[];
|
|
143
143
|
}
|
|
144
144
|
| {
|
|
145
145
|
reason: "ttsr_triggered";
|
|
@@ -73,6 +73,15 @@ export class ExtensionRuntime implements IExtensionRuntime {
|
|
|
73
73
|
flagValues = new Map<string, boolean | string>();
|
|
74
74
|
pendingProviderRegistrations: Array<{ name: string; config: ProviderConfig; sourceId: string }> = [];
|
|
75
75
|
|
|
76
|
+
registerProvider(name: string, config: ProviderConfig, sourceId: string): void {
|
|
77
|
+
this.pendingProviderRegistrations.push({ name, config, sourceId });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
unregisterProvider(name: string): void {
|
|
81
|
+
const remaining = this.pendingProviderRegistrations.filter(registration => registration.name !== name);
|
|
82
|
+
this.pendingProviderRegistrations.splice(0, this.pendingProviderRegistrations.length, ...remaining);
|
|
83
|
+
}
|
|
84
|
+
|
|
76
85
|
sendMessage(): void {
|
|
77
86
|
throw new ExtensionRuntimeNotInitializedError();
|
|
78
87
|
}
|
|
@@ -290,7 +299,11 @@ class ConcreteExtensionAPI implements ExtensionAPI, IExtensionRuntime {
|
|
|
290
299
|
}
|
|
291
300
|
|
|
292
301
|
registerProvider(name: string, config: ProviderConfig): void {
|
|
293
|
-
this.runtime.
|
|
302
|
+
this.runtime.registerProvider(name, config, this.extension.path);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
unregisterProvider(name: string): void {
|
|
306
|
+
this.runtime.unregisterProvider(name, this.extension.path);
|
|
294
307
|
}
|
|
295
308
|
}
|
|
296
309
|
|
|
@@ -311,12 +324,37 @@ function createExtension(extensionPath: string, resolvedPath: string): Extension
|
|
|
311
324
|
};
|
|
312
325
|
}
|
|
313
326
|
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
327
|
+
/**
|
|
328
|
+
* Runs an extension factory with provider registration rollback on failure.
|
|
329
|
+
* Restores the complete registration queue when the factory throws because an
|
|
330
|
+
* extension may unregister entries queued by an earlier extension.
|
|
331
|
+
*/
|
|
332
|
+
async function runExtensionFactory(
|
|
333
|
+
factory: ExtensionFactory,
|
|
334
|
+
api: ExtensionAPI,
|
|
318
335
|
runtime: IExtensionRuntime,
|
|
319
|
-
): Promise<
|
|
336
|
+
): Promise<void> {
|
|
337
|
+
const providerRegistrationCheckpoint = [...runtime.pendingProviderRegistrations];
|
|
338
|
+
|
|
339
|
+
try {
|
|
340
|
+
await factory(api);
|
|
341
|
+
} catch (error) {
|
|
342
|
+
runtime.pendingProviderRegistrations.splice(
|
|
343
|
+
0,
|
|
344
|
+
runtime.pendingProviderRegistrations.length,
|
|
345
|
+
...providerRegistrationCheckpoint,
|
|
346
|
+
);
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
interface ImportedExtensionModule {
|
|
352
|
+
factory: ExtensionFactory | null;
|
|
353
|
+
resolvedPath: string;
|
|
354
|
+
error: string | null;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
async function importExtensionModule(extensionPath: string, cwd: string): Promise<ImportedExtensionModule> {
|
|
320
358
|
const resolvedPath = resolvePath(extensionPath, cwd);
|
|
321
359
|
try {
|
|
322
360
|
const module = (await withHostGuard(() => loadLegacyPiModule(resolvedPath))) as LoadedExtensionModule;
|
|
@@ -324,16 +362,34 @@ async function loadExtension(
|
|
|
324
362
|
|
|
325
363
|
if (typeof factory !== "function") {
|
|
326
364
|
return {
|
|
327
|
-
|
|
365
|
+
factory: null,
|
|
366
|
+
resolvedPath,
|
|
328
367
|
error: `Extension does not export a valid factory function: ${extensionPath}`,
|
|
329
368
|
};
|
|
330
369
|
}
|
|
331
370
|
|
|
332
|
-
|
|
371
|
+
return { factory, resolvedPath, error: null };
|
|
372
|
+
} catch (err) {
|
|
373
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
374
|
+
return { factory: null, resolvedPath, error: `Failed to load extension: ${message}` };
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
async function bindExtension(
|
|
379
|
+
extensionPath: string,
|
|
380
|
+
imported: ImportedExtensionModule,
|
|
381
|
+
cwd: string,
|
|
382
|
+
eventBus: EventBus,
|
|
383
|
+
runtime: IExtensionRuntime,
|
|
384
|
+
): Promise<{ extension: Extension | null; error: string | null }> {
|
|
385
|
+
const factory = imported.factory;
|
|
386
|
+
if (imported.error !== null || factory === null) {
|
|
387
|
+
return { extension: null, error: imported.error };
|
|
388
|
+
}
|
|
389
|
+
try {
|
|
390
|
+
const extension = createExtension(extensionPath, imported.resolvedPath);
|
|
333
391
|
const api = new ConcreteExtensionAPI(PiCodingAgent, extension, runtime, cwd, eventBus);
|
|
334
|
-
await withHostGuard(
|
|
335
|
-
await factory(api);
|
|
336
|
-
});
|
|
392
|
+
await withHostGuard(() => runExtensionFactory(factory, api, runtime));
|
|
337
393
|
|
|
338
394
|
return { extension, error: null };
|
|
339
395
|
} catch (err) {
|
|
@@ -354,12 +410,17 @@ export async function loadExtensionFromFactory(
|
|
|
354
410
|
): Promise<Extension> {
|
|
355
411
|
const extension = createExtension(name, name);
|
|
356
412
|
const api = new ConcreteExtensionAPI(PiCodingAgent, extension, runtime, cwd, eventBus);
|
|
357
|
-
await factory
|
|
413
|
+
await runExtensionFactory(factory, api, runtime);
|
|
358
414
|
return extension;
|
|
359
415
|
}
|
|
360
416
|
|
|
361
417
|
/**
|
|
362
418
|
* Load extensions from paths.
|
|
419
|
+
*
|
|
420
|
+
* Module import (the dominant cold-start cost — file I/O plus module
|
|
421
|
+
* evaluation) runs concurrently across extensions; factory binding then runs
|
|
422
|
+
* sequentially in the original path order, so registration semantics
|
|
423
|
+
* (last-wins collisions, shared runtime flag defaults) stay deterministic.
|
|
363
424
|
*/
|
|
364
425
|
export async function loadExtensions(paths: string[], cwd: string, eventBus?: EventBus): Promise<LoadExtensionsResult> {
|
|
365
426
|
const extensions: Extension[] = [];
|
|
@@ -367,8 +428,11 @@ export async function loadExtensions(paths: string[], cwd: string, eventBus?: Ev
|
|
|
367
428
|
const resolvedEventBus = eventBus ?? new EventBus();
|
|
368
429
|
const runtime = new ExtensionRuntime();
|
|
369
430
|
|
|
370
|
-
|
|
371
|
-
|
|
431
|
+
const imported = await Promise.all(paths.map(extPath => importExtensionModule(extPath, cwd)));
|
|
432
|
+
|
|
433
|
+
for (let i = 0; i < paths.length; i++) {
|
|
434
|
+
const extPath = paths[i]!;
|
|
435
|
+
const { extension, error } = await bindExtension(extPath, imported[i]!, cwd, resolvedEventBus, runtime);
|
|
372
436
|
|
|
373
437
|
if (error) {
|
|
374
438
|
errors.push({ path: extPath, error });
|
|
@@ -530,6 +530,12 @@ export class ExtensionRunner {
|
|
|
530
530
|
this.runtime.setServiceTier = actions.setServiceTier ?? throwUnsupportedServiceTierAction;
|
|
531
531
|
this.runtime.getSessionName = actions.getSessionName;
|
|
532
532
|
this.runtime.setSessionName = actions.setSessionName;
|
|
533
|
+
this.runtime.registerProvider = (name, config, sourceId) => {
|
|
534
|
+
this.modelRegistry.registerProvider(name, config, sourceId);
|
|
535
|
+
};
|
|
536
|
+
this.runtime.unregisterProvider = name => {
|
|
537
|
+
this.modelRegistry.unregisterProvider(name);
|
|
538
|
+
};
|
|
533
539
|
|
|
534
540
|
// Context actions (required)
|
|
535
541
|
this.#getModel = contextActions.getModel;
|
|
@@ -1373,6 +1373,14 @@ export interface ExtensionAPI {
|
|
|
1373
1373
|
*/
|
|
1374
1374
|
registerProvider(name: string, config: ProviderConfig): void;
|
|
1375
1375
|
|
|
1376
|
+
/**
|
|
1377
|
+
* Unregister a provider previously registered by an extension.
|
|
1378
|
+
*
|
|
1379
|
+
* Removes extension-provided models and restores overridden built-in models.
|
|
1380
|
+
* Has no effect when the provider is not registered.
|
|
1381
|
+
*/
|
|
1382
|
+
unregisterProvider(name: string): void;
|
|
1383
|
+
|
|
1376
1384
|
/** Shared event bus for extension communication. */
|
|
1377
1385
|
events: EventBus;
|
|
1378
1386
|
}
|
|
@@ -1516,6 +1524,10 @@ export interface ExtensionRuntimeState {
|
|
|
1516
1524
|
flagValues: Map<string, boolean | string>;
|
|
1517
1525
|
/** Provider registrations queued during extension loading, processed during session initialization */
|
|
1518
1526
|
pendingProviderRegistrations: Array<{ name: string; config: ProviderConfig; sourceId: string }>;
|
|
1527
|
+
/** Queue a provider registration until initialization, then apply it immediately. */
|
|
1528
|
+
registerProvider(name: string, config: ProviderConfig, sourceId: string): void;
|
|
1529
|
+
/** Remove a queued or initialized provider registration. */
|
|
1530
|
+
unregisterProvider(name: string, sourceId: string): void;
|
|
1519
1531
|
}
|
|
1520
1532
|
|
|
1521
1533
|
/** Action implementations for ExtensionAPI methods. */
|
|
@@ -408,7 +408,7 @@ export class MarketplaceManager {
|
|
|
408
408
|
/**
|
|
409
409
|
* Resolve plugin version from multiple sources:
|
|
410
410
|
* 1. Catalog entry version (if set)
|
|
411
|
-
* 2. Plugin manifest (.claude-plugin/plugin.json or package.json)
|
|
411
|
+
* 2. Plugin manifest (.claude-plugin/plugin.json, Agent Plugins root plugin.json, or package.json)
|
|
412
412
|
* 3. Git SHA from source (truncated to 7 chars)
|
|
413
413
|
* 4. Fallback "0.0.0"
|
|
414
414
|
*/
|
|
@@ -419,6 +419,7 @@ export class MarketplaceManager {
|
|
|
419
419
|
// 2. Plugin manifest
|
|
420
420
|
for (const manifestPath of [
|
|
421
421
|
path.join(sourcePath, ".claude-plugin", "plugin.json"),
|
|
422
|
+
path.join(sourcePath, "plugin.json"),
|
|
422
423
|
path.join(sourcePath, "package.json"),
|
|
423
424
|
]) {
|
|
424
425
|
try {
|
|
@@ -249,7 +249,8 @@ export interface AutoRetryStartEvent {
|
|
|
249
249
|
errorId?: number;
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
|
|
252
|
+
/** Persisted retry error whose transcript presentation changed when the retry saga settled. */
|
|
253
|
+
export interface RetryErrorUpdate {
|
|
253
254
|
entryId: string;
|
|
254
255
|
persistenceKey?: string;
|
|
255
256
|
note: string;
|
|
@@ -262,7 +263,7 @@ export interface AutoRetryEndEvent {
|
|
|
262
263
|
success: boolean;
|
|
263
264
|
attempt: number;
|
|
264
265
|
finalError?: string;
|
|
265
|
-
|
|
266
|
+
retryErrors?: RetryErrorUpdate[];
|
|
266
267
|
}
|
|
267
268
|
|
|
268
269
|
// ============================================================================
|