@oh-my-pi/pi-coding-agent 15.10.9 → 15.10.11
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 +117 -0
- package/dist/cli.js +23087 -0
- package/dist/tokenizers.linux-x64-gnu-xcjh3jwk.node +0 -0
- package/dist/types/async/job-manager.d.ts +18 -0
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/cli/dry-balance-cli.d.ts +1 -1
- package/dist/types/cli/gallery-cli.d.ts +1 -1
- package/dist/types/cli/gallery-fixtures/types.d.ts +1 -1
- package/dist/types/cli/usage-cli.d.ts +72 -0
- package/dist/types/commands/launch.d.ts +1 -1
- package/dist/types/commands/read.d.ts +1 -1
- package/dist/types/commands/usage.d.ts +25 -0
- package/dist/types/config/append-only-context-mode.d.ts +2 -1
- package/dist/types/config/model-discovery.d.ts +55 -0
- package/dist/types/config/model-registry.d.ts +20 -219
- package/dist/types/config/model-resolver.d.ts +16 -10
- package/dist/types/config/model-roles.d.ts +28 -0
- package/dist/types/config/models-config-schema.d.ts +523 -42
- package/dist/types/config/models-config.d.ts +385 -0
- package/dist/types/config/settings-schema.d.ts +12 -16
- package/dist/types/config/settings.d.ts +1 -1
- package/dist/types/debug/log-viewer.d.ts +1 -1
- package/dist/types/debug/raw-sse.d.ts +1 -1
- package/dist/types/debug/terminal-info.d.ts +0 -1
- package/dist/types/eval/backend.d.ts +0 -2
- package/dist/types/eval/idle-timeout.d.ts +0 -4
- package/dist/types/eval/js/shared/rewrite-imports.d.ts +6 -6
- package/dist/types/export/html/template.generated.d.ts +1 -1
- package/dist/types/extensibility/extensions/types.d.ts +3 -3
- package/dist/types/hindsight/mental-models.d.ts +17 -8
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/types.d.ts +1 -1
- package/dist/types/lsp/edits.d.ts +9 -0
- package/dist/types/lsp/index.d.ts +2 -2
- package/dist/types/lsp/types.d.ts +2 -0
- package/dist/types/lsp/utils.d.ts +3 -0
- package/dist/types/mcp/json-rpc.d.ts +5 -0
- package/dist/types/mnemopi/state.d.ts +11 -1
- package/dist/types/modes/components/agent-dashboard.d.ts +1 -1
- package/dist/types/modes/components/assistant-message.d.ts +3 -1
- package/dist/types/modes/components/bash-execution.d.ts +1 -1
- package/dist/types/modes/components/copy-selector.d.ts +1 -1
- package/dist/types/modes/components/dynamic-border.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -1
- package/dist/types/modes/components/extensions/extension-list.d.ts +1 -1
- package/dist/types/modes/components/extensions/inspector-panel.d.ts +1 -1
- package/dist/types/modes/components/footer.d.ts +1 -1
- package/dist/types/modes/components/hook-editor.d.ts +5 -0
- package/dist/types/modes/components/hook-input.d.ts +4 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -1
- package/dist/types/modes/components/model-selector.d.ts +1 -1
- package/dist/types/modes/components/plan-review-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-observer-overlay.d.ts +1 -1
- package/dist/types/modes/components/session-selector.d.ts +1 -1
- package/dist/types/modes/components/status-line/component.d.ts +1 -1
- package/dist/types/modes/components/tiny-title-download-progress.d.ts +1 -1
- package/dist/types/modes/components/transcript-container.d.ts +31 -26
- package/dist/types/modes/components/tree-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message-selector.d.ts +1 -1
- package/dist/types/modes/components/user-message.d.ts +2 -1
- package/dist/types/modes/components/visual-truncate.d.ts +1 -1
- package/dist/types/modes/components/welcome.d.ts +19 -3
- package/dist/types/modes/controllers/mcp-command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/streaming-reveal.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/sign-in.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/types.d.ts +1 -1
- package/dist/types/modes/setup-wizard/scenes/web-search.d.ts +1 -1
- package/dist/types/modes/setup-wizard/wizard-overlay.d.ts +1 -1
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/session/agent-session.d.ts +1 -1
- package/dist/types/session/auth-broker-config.d.ts +4 -0
- package/dist/types/session/session-manager.d.ts +1 -1
- package/dist/types/slash-commands/helpers/stats-dashboard.d.ts +13 -0
- package/dist/types/ssh/connection-manager.d.ts +8 -0
- package/dist/types/task/discovery.d.ts +1 -2
- package/dist/types/task/parallel.d.ts +2 -2
- package/dist/types/task/worktree.d.ts +2 -0
- package/dist/types/tiny/title-client.d.ts +1 -1
- package/dist/types/tools/ask.d.ts +4 -0
- package/dist/types/tools/conflict-detect.d.ts +16 -0
- package/dist/types/tools/github-cache.d.ts +7 -0
- package/dist/types/tools/sqlite-reader.d.ts +3 -0
- package/dist/types/tools/todo.d.ts +2 -0
- package/dist/types/tui/output-block.d.ts +3 -3
- package/dist/types/utils/changelog.d.ts +8 -0
- package/dist/types/web/scrapers/readthedocs.d.ts +3 -0
- package/dist/types/web/scrapers/types.d.ts +12 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -1
- package/dist/types/web/search/providers/gemini.d.ts +1 -1
- package/examples/extensions/tools.ts +5 -4
- package/package.json +14 -11
- package/scripts/build-binary.ts +18 -23
- package/scripts/bundle-dist.ts +81 -0
- package/scripts/{dev-launch → omp} +1 -1
- package/scripts/{dev-launch-preload.ts → omp.ts} +1 -1
- package/src/async/job-manager.ts +57 -3
- package/src/autoresearch/dashboard.ts +1 -1
- package/src/autoresearch/prompt-setup.md +6 -6
- package/src/autoresearch/prompt.md +6 -6
- package/src/capability/fs.ts +10 -0
- package/src/cli/args.ts +1 -1
- package/src/cli/auth-gateway-cli.ts +1 -3
- package/src/cli/dry-balance-cli.ts +1 -1
- package/src/cli/gallery-cli.ts +1 -1
- package/src/cli/gallery-fixtures/fs.ts +1 -1
- package/src/cli/gallery-fixtures/types.ts +5 -1
- package/src/cli/list-models.ts +7 -12
- package/src/cli/usage-cli.ts +603 -0
- package/src/cli-commands.ts +1 -0
- package/src/cli.ts +69 -5
- package/src/commands/complete.ts +1 -1
- package/src/commands/launch.ts +1 -1
- package/src/commands/read.ts +6 -3
- package/src/commands/usage.ts +35 -0
- package/src/commit/agentic/agent.ts +1 -1
- package/src/commit/model-selection.ts +1 -1
- package/src/config/append-only-context-mode.ts +6 -12
- package/src/config/model-discovery.ts +554 -0
- package/src/config/model-registry.ts +308 -1025
- package/src/config/model-resolver.ts +113 -156
- package/src/config/model-roles.ts +74 -0
- package/src/config/models-config-schema.ts +57 -8
- package/src/config/models-config.ts +129 -0
- package/src/config/settings-schema.ts +18 -14
- package/src/config/settings.ts +37 -1
- package/src/dap/client.ts +124 -37
- package/src/dap/session.ts +259 -158
- package/src/debug/log-viewer.ts +1 -1
- package/src/debug/raw-sse.ts +1 -1
- package/src/debug/terminal-info.ts +0 -3
- package/src/edit/diff.ts +95 -18
- package/src/edit/hashline/block-resolver.ts +20 -1
- package/src/edit/hashline/diff.ts +36 -1
- package/src/edit/hashline/execute.ts +8 -2
- package/src/edit/index.ts +16 -1
- package/src/edit/modes/patch.ts +52 -0
- package/src/edit/modes/replace.ts +56 -22
- package/src/edit/notebook.ts +22 -2
- package/src/edit/renderer.ts +36 -10
- package/src/eval/__tests__/completion-bridge.test.ts +1 -1
- package/src/eval/backend.ts +0 -2
- package/src/eval/completion-bridge.ts +2 -1
- package/src/eval/idle-timeout.ts +2 -9
- package/src/eval/js/context-manager.ts +6 -8
- package/src/eval/js/executor.ts +6 -2
- package/src/eval/js/index.ts +0 -2
- package/src/eval/js/shared/helpers.ts +5 -6
- package/src/eval/js/shared/local-module-loader.ts +1 -1
- package/src/eval/js/shared/prelude.txt +62 -1
- package/src/eval/js/shared/rewrite-imports.ts +49 -23
- package/src/eval/js/shared/runtime.ts +1 -1
- package/src/eval/py/index.ts +0 -2
- package/src/eval/py/kernel.ts +19 -0
- package/src/eval/py/runner.py +107 -3
- package/src/exec/bash-executor.ts +3 -1
- package/src/export/html/template.generated.ts +1 -1
- package/src/export/html/template.js +3 -1
- package/src/extensibility/extensions/types.ts +3 -2
- package/src/extensibility/plugins/legacy-pi-compat.ts +20 -3
- package/src/hindsight/mental-models.ts +59 -12
- package/src/hindsight/state.ts +6 -1
- package/src/internal-urls/artifact-protocol.ts +11 -2
- package/src/internal-urls/docs-index.generated.ts +10 -10
- package/src/internal-urls/issue-pr-protocol.ts +12 -5
- package/src/internal-urls/router.ts +1 -1
- package/src/internal-urls/types.ts +1 -1
- package/src/lib/xai-http.ts +1 -1
- package/src/lsp/client.ts +118 -38
- package/src/lsp/clients/biome-client.ts +101 -39
- package/src/lsp/edits.ts +143 -95
- package/src/lsp/index.ts +31 -22
- package/src/lsp/render.ts +1 -1
- package/src/lsp/types.ts +2 -0
- package/src/lsp/utils.ts +28 -10
- package/src/main.ts +165 -17
- package/src/mcp/json-rpc.ts +35 -5
- package/src/mcp/transports/stdio.ts +7 -1
- package/src/memories/index.ts +2 -1
- package/src/mnemopi/backend.ts +25 -3
- package/src/mnemopi/state.ts +38 -2
- package/src/modes/components/agent-dashboard.ts +10 -7
- package/src/modes/components/assistant-message.ts +19 -13
- package/src/modes/components/bash-execution.ts +1 -1
- package/src/modes/components/copy-selector.ts +1 -1
- package/src/modes/components/diff.ts +13 -2
- package/src/modes/components/dynamic-border.ts +12 -3
- package/src/modes/components/extensions/extension-dashboard.ts +8 -5
- package/src/modes/components/extensions/extension-list.ts +1 -1
- package/src/modes/components/extensions/inspector-panel.ts +1 -1
- package/src/modes/components/footer.ts +1 -1
- package/src/modes/components/history-search.ts +1 -1
- package/src/modes/components/hook-editor.ts +8 -0
- package/src/modes/components/hook-input.ts +8 -0
- package/src/modes/components/hook-selector.ts +2 -2
- package/src/modes/components/model-selector.ts +66 -54
- package/src/modes/components/plan-review-overlay.ts +1 -1
- package/src/modes/components/session-observer-overlay.ts +2 -2
- package/src/modes/components/session-selector.ts +1 -1
- package/src/modes/components/settings-selector.ts +5 -1
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/tiny-title-download-progress.ts +1 -1
- package/src/modes/components/transcript-container.ts +373 -141
- package/src/modes/components/tree-selector.ts +3 -3
- package/src/modes/components/user-message-selector.ts +1 -1
- package/src/modes/components/user-message.ts +17 -5
- package/src/modes/components/visual-truncate.ts +1 -1
- package/src/modes/components/welcome.ts +108 -26
- package/src/modes/controllers/command-controller.ts +10 -3
- package/src/modes/controllers/event-controller.ts +73 -49
- package/src/modes/controllers/input-controller.ts +5 -5
- package/src/modes/controllers/mcp-command-controller.ts +1 -1
- package/src/modes/controllers/selector-controller.ts +1 -5
- package/src/modes/controllers/streaming-reveal.ts +85 -18
- package/src/modes/interactive-mode.ts +5 -19
- package/src/modes/setup-wizard/scenes/glyph.ts +1 -1
- package/src/modes/setup-wizard/scenes/providers.ts +1 -1
- package/src/modes/setup-wizard/scenes/sign-in.ts +1 -1
- package/src/modes/setup-wizard/scenes/theme.ts +1 -1
- package/src/modes/setup-wizard/scenes/types.ts +1 -1
- package/src/modes/setup-wizard/scenes/web-search.ts +1 -1
- package/src/modes/setup-wizard/wizard-overlay.ts +1 -1
- package/src/modes/types.ts +2 -1
- package/src/prompts/agents/explore.md +2 -2
- package/src/prompts/agents/librarian.md +1 -2
- package/src/prompts/agents/oracle.md +1 -1
- package/src/prompts/agents/plan.md +5 -5
- package/src/prompts/agents/task.md +5 -5
- package/src/prompts/ci-green-request.md +5 -7
- package/src/prompts/goals/goal-budget-limit.md +2 -2
- package/src/prompts/goals/goal-continuation.md +4 -4
- package/src/prompts/goals/goal-mode-active.md +1 -1
- package/src/prompts/memories/read-path.md +1 -1
- package/src/prompts/memories/stage_one_system.md +2 -2
- package/src/prompts/review-custom-request.md +1 -1
- package/src/prompts/system/agent-creation-architect.md +2 -2
- package/src/prompts/system/auto-continue.md +1 -1
- package/src/prompts/system/background-tan-dispatch.md +1 -1
- package/src/prompts/system/btw-user.md +2 -2
- package/src/prompts/system/commit-message-system.md +13 -1
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/eager-todo.md +2 -2
- package/src/prompts/system/irc-incoming.md +1 -1
- package/src/prompts/system/manual-continue.md +1 -1
- package/src/prompts/system/omfg-user.md +3 -4
- package/src/prompts/system/orchestrate-notice.md +9 -9
- package/src/prompts/system/plan-mode-active.md +4 -4
- package/src/prompts/system/plan-mode-subagent.md +4 -5
- package/src/prompts/system/plan-mode-tool-decision-reminder.md +1 -1
- package/src/prompts/system/project-prompt.md +2 -2
- package/src/prompts/system/subagent-system-prompt.md +4 -4
- package/src/prompts/system/system-prompt.md +15 -26
- package/src/prompts/system/title-system.md +2 -2
- package/src/prompts/system/ttsr-tool-reminder.md +1 -1
- package/src/prompts/system/workflow-notice.md +1 -1
- package/src/prompts/tools/ast-edit.md +1 -1
- package/src/prompts/tools/ast-grep.md +2 -2
- package/src/prompts/tools/bash.md +8 -10
- package/src/prompts/tools/browser.md +7 -7
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/eval.md +3 -3
- package/src/prompts/tools/find.md +0 -1
- package/src/prompts/tools/github.md +8 -7
- package/src/prompts/tools/goal.md +1 -1
- package/src/prompts/tools/image-gen.md +1 -1
- package/src/prompts/tools/inspect-image-system.md +1 -1
- package/src/prompts/tools/irc.md +15 -15
- package/src/prompts/tools/lsp.md +2 -2
- package/src/prompts/tools/patch.md +2 -2
- package/src/prompts/tools/read.md +3 -4
- package/src/prompts/tools/recall.md +1 -1
- package/src/prompts/tools/reflect.md +1 -1
- package/src/prompts/tools/render-mermaid.md +2 -2
- package/src/prompts/tools/replace.md +4 -10
- package/src/prompts/tools/rewind.md +2 -2
- package/src/prompts/tools/search-tool-bm25.md +1 -9
- package/src/prompts/tools/search.md +0 -1
- package/src/prompts/tools/ssh.md +0 -4
- package/src/prompts/tools/task.md +2 -3
- package/src/prompts/tools/todo.md +6 -2
- package/src/sdk.ts +23 -10
- package/src/session/agent-session.ts +44 -10
- package/src/session/auth-broker-config.ts +30 -1
- package/src/session/session-manager.ts +2 -2
- package/src/session/streaming-output.ts +23 -2
- package/src/slash-commands/builtin-registry.ts +20 -0
- package/src/slash-commands/helpers/stats-dashboard.ts +85 -0
- package/src/ssh/connection-manager.ts +27 -0
- package/src/task/commands.ts +2 -1
- package/src/task/discovery.ts +17 -24
- package/src/task/executor.ts +61 -53
- package/src/task/index.ts +137 -60
- package/src/task/parallel.ts +3 -3
- package/src/task/render.ts +2 -2
- package/src/task/worktree.ts +64 -56
- package/src/thinking.ts +2 -1
- package/src/tiny/title-client.ts +32 -14
- package/src/tools/archive-reader.ts +30 -2
- package/src/tools/ask.ts +104 -21
- package/src/tools/ast-edit.ts +25 -5
- package/src/tools/auto-generated-guard.ts +20 -3
- package/src/tools/bash-interactive.ts +27 -7
- package/src/tools/bash.ts +54 -13
- package/src/tools/browser/launch.ts +11 -2
- package/src/tools/browser/readable.ts +19 -2
- package/src/tools/browser/registry.ts +4 -1
- package/src/tools/browser/render.ts +2 -2
- package/src/tools/browser/tab-supervisor.ts +55 -16
- package/src/tools/conflict-detect.ts +50 -4
- package/src/tools/debug.ts +1 -1
- package/src/tools/eval-render.ts +5 -5
- package/src/tools/eval.ts +0 -2
- package/src/tools/fetch.ts +33 -10
- package/src/tools/gh-cache-invalidation.ts +63 -8
- package/src/tools/gh-renderer.ts +1 -1
- package/src/tools/gh.ts +172 -29
- package/src/tools/github-cache.ts +70 -6
- package/src/tools/image-gen.ts +3 -9
- package/src/tools/irc.ts +5 -1
- package/src/tools/job.ts +1 -1
- package/src/tools/read.ts +202 -61
- package/src/tools/render-utils.ts +3 -3
- package/src/tools/resolve.ts +1 -1
- package/src/tools/search.ts +92 -29
- package/src/tools/sqlite-reader.ts +17 -5
- package/src/tools/ssh.ts +8 -8
- package/src/tools/todo.ts +51 -12
- package/src/tools/write.ts +118 -18
- package/src/tui/output-block.ts +4 -4
- package/src/utils/changelog.ts +27 -1
- package/src/utils/file-mentions.ts +2 -1
- package/src/web/scrapers/arxiv.ts +1 -1
- package/src/web/scrapers/go-pkg.ts +1 -1
- package/src/web/scrapers/iacr.ts +1 -1
- package/src/web/scrapers/readthedocs.ts +1 -1
- package/src/web/scrapers/twitter.ts +2 -1
- package/src/web/scrapers/types.ts +87 -8
- package/src/web/scrapers/wikipedia.ts +1 -1
- package/src/web/scrapers/youtube.ts +6 -1
- package/src/web/search/index.ts +1 -1
- package/src/web/search/providers/anthropic.ts +8 -2
- package/src/web/search/providers/codex.ts +2 -1
- package/src/web/search/providers/gemini.ts +2 -3
- package/src/web/search/render.ts +8 -6
- package/dist/types/config/model-equivalence.d.ts +0 -24
- package/dist/types/config/model-id-affixes.d.ts +0 -12
- package/dist/types/config/model-provider-priority.d.ts +0 -1
- package/dist/types/exec/idle-timeout-watchdog.d.ts +0 -18
- package/src/config/model-equivalence.ts +0 -875
- package/src/config/model-id-affixes.ts +0 -81
- package/src/config/model-provider-priority.ts +0 -56
- package/src/exec/idle-timeout-watchdog.ts +0 -126
package/src/edit/renderer.ts
CHANGED
|
@@ -261,7 +261,6 @@ function renderEditHeader(
|
|
|
261
261
|
options: {
|
|
262
262
|
icon: "pending" | "success" | "error";
|
|
263
263
|
iconOverride?: string;
|
|
264
|
-
spinnerFrame?: number;
|
|
265
264
|
op?: Operation;
|
|
266
265
|
rawPath: string;
|
|
267
266
|
rename?: string;
|
|
@@ -284,7 +283,6 @@ function renderEditHeader(
|
|
|
284
283
|
{
|
|
285
284
|
icon: options.icon,
|
|
286
285
|
iconOverride: options.iconOverride,
|
|
287
|
-
spinnerFrame: options.spinnerFrame,
|
|
288
286
|
title,
|
|
289
287
|
description,
|
|
290
288
|
},
|
|
@@ -322,6 +320,7 @@ function formatStreamingDiff(
|
|
|
322
320
|
uiTheme: Theme,
|
|
323
321
|
expanded: boolean,
|
|
324
322
|
label = "streaming",
|
|
323
|
+
spinnerFrame?: number,
|
|
325
324
|
): string {
|
|
326
325
|
if (!diff) return "";
|
|
327
326
|
// Collapsed uses a "Cursor" tail window: pin the last
|
|
@@ -342,11 +341,26 @@ function formatStreamingDiff(
|
|
|
342
341
|
text += `${uiTheme.fg("dim", `… (${remainder.join(", ")} above)`)}\n`;
|
|
343
342
|
}
|
|
344
343
|
text += renderDiffColored(visible.join("\n"), { filePath: rawPath });
|
|
345
|
-
|
|
344
|
+
// The animated glyph rides this trailing line — inside the transcript's
|
|
345
|
+
// volatile-tail holdback — never the block header: an animating head row
|
|
346
|
+
// pins the native-scrollback commit boundary at the top of the block, so a
|
|
347
|
+
// tall expanded preview could never scroll-append mid-stream.
|
|
348
|
+
const spinner = spinnerFrame !== undefined ? `${formatStatusIcon("running", uiTheme, spinnerFrame)} ` : "";
|
|
349
|
+
// Expanded approval previews hide the "(preview)" label (#1992) but keep
|
|
350
|
+
// the animated glyph when one is active so the volatile tail stays live.
|
|
351
|
+
const hideLabel = expanded && label === "preview";
|
|
352
|
+
if (spinner || !hideLabel) {
|
|
353
|
+
text += `\n${hideLabel ? spinner.trimEnd() : `${spinner}${uiTheme.fg("dim", `(${label})`)}`}`;
|
|
354
|
+
}
|
|
346
355
|
return text;
|
|
347
356
|
}
|
|
348
357
|
|
|
349
|
-
function formatMultiFileStreamingDiff(
|
|
358
|
+
function formatMultiFileStreamingDiff(
|
|
359
|
+
previews: PerFileDiffPreview[],
|
|
360
|
+
uiTheme: Theme,
|
|
361
|
+
expanded: boolean,
|
|
362
|
+
spinnerFrame?: number,
|
|
363
|
+
): string {
|
|
350
364
|
const parts: string[] = [];
|
|
351
365
|
for (const preview of previews) {
|
|
352
366
|
if (!preview.diff && !preview.error) continue;
|
|
@@ -356,7 +370,13 @@ function formatMultiFileStreamingDiff(previews: PerFileDiffPreview[], uiTheme: T
|
|
|
356
370
|
continue;
|
|
357
371
|
}
|
|
358
372
|
if (preview.diff) {
|
|
359
|
-
|
|
373
|
+
// Only the last file's preview carries the animated streaming glyph;
|
|
374
|
+
// earlier files have settled and must stay byte-stable so their rows
|
|
375
|
+
// can commit to native scrollback mid-stream.
|
|
376
|
+
const isLast = preview === previews[previews.length - 1];
|
|
377
|
+
parts.push(
|
|
378
|
+
`${header}${formatStreamingDiff(preview.diff, preview.path, uiTheme, expanded, "preview", isLast ? spinnerFrame : undefined)}`,
|
|
379
|
+
);
|
|
360
380
|
}
|
|
361
381
|
}
|
|
362
382
|
return parts.join("");
|
|
@@ -368,16 +388,17 @@ function getCallPreview(
|
|
|
368
388
|
uiTheme: Theme,
|
|
369
389
|
renderContext: EditRenderContext | undefined,
|
|
370
390
|
expanded: boolean,
|
|
391
|
+
spinnerFrame?: number,
|
|
371
392
|
): string {
|
|
372
393
|
const multi = renderContext?.perFileDiffPreview;
|
|
373
394
|
if (multi && multi.length > 1 && multi.some(p => p.diff || p.error)) {
|
|
374
|
-
return formatMultiFileStreamingDiff(multi, uiTheme, expanded);
|
|
395
|
+
return formatMultiFileStreamingDiff(multi, uiTheme, expanded, spinnerFrame);
|
|
375
396
|
}
|
|
376
397
|
if (args.previewDiff) {
|
|
377
|
-
return formatStreamingDiff(args.previewDiff, rawPath, uiTheme, expanded, "preview");
|
|
398
|
+
return formatStreamingDiff(args.previewDiff, rawPath, uiTheme, expanded, "preview", spinnerFrame);
|
|
378
399
|
}
|
|
379
400
|
if (args.diff && args.op) {
|
|
380
|
-
return formatStreamingDiff(args.diff, rawPath, uiTheme, expanded);
|
|
401
|
+
return formatStreamingDiff(args.diff, rawPath, uiTheme, expanded, "streaming", spinnerFrame);
|
|
381
402
|
}
|
|
382
403
|
if (args.diff) {
|
|
383
404
|
return renderPlainTextPreview(args.diff, uiTheme, rawPath);
|
|
@@ -554,15 +575,20 @@ export const editToolRenderer = {
|
|
|
554
575
|
fileCount = countEditFiles(editArgs.edits);
|
|
555
576
|
}
|
|
556
577
|
return framedBlock(uiTheme, width => {
|
|
578
|
+
// Static pending icon, never the animated glyph: the header is the
|
|
579
|
+
// head row of the framed block, and native-scrollback commits are
|
|
580
|
+
// prefix-only — an animating head row would pin the commit boundary
|
|
581
|
+
// at the top and keep a tall expanded preview from scroll-appending
|
|
582
|
+
// mid-stream. The liveness cue rides the trailing "(preview)" /
|
|
583
|
+
// "(streaming)" line instead.
|
|
557
584
|
const header = renderEditHeader(width, uiTheme, {
|
|
558
585
|
icon: "pending",
|
|
559
|
-
spinnerFrame: options?.spinnerFrame,
|
|
560
586
|
op,
|
|
561
587
|
rawPath,
|
|
562
588
|
rename,
|
|
563
589
|
extraSuffix: fileCount > 1 ? uiTheme.fg("dim", ` (+${fileCount - 1} more)`) : undefined,
|
|
564
590
|
});
|
|
565
|
-
let body = getCallPreview(editArgs, rawPath, uiTheme, renderContext, options.expanded);
|
|
591
|
+
let body = getCallPreview(editArgs, rawPath, uiTheme, renderContext, options.expanded, options?.spinnerFrame);
|
|
566
592
|
if (applyPatchSummary?.error) {
|
|
567
593
|
body += `\n${uiTheme.fg("error", truncateToWidth(replaceTabs(applyPatchSummary.error, rawPath), Math.max(1, width - 2)))}`;
|
|
568
594
|
}
|
|
@@ -38,7 +38,7 @@ const SLOW = makeModel("p", "slow");
|
|
|
38
38
|
const REASONING_SLOW = makeModel("p", "slow", {
|
|
39
39
|
api: "anthropic-messages",
|
|
40
40
|
reasoning: true,
|
|
41
|
-
thinking: {
|
|
41
|
+
thinking: { efforts: [Effort.Low, Effort.Medium, Effort.High], mode: "anthropic-adaptive" },
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
interface SessionOptions {
|
package/src/eval/backend.ts
CHANGED
|
@@ -20,8 +20,6 @@ export interface ExecutorBackendExecOptions {
|
|
|
20
20
|
*/
|
|
21
21
|
idleTimeoutMs: number;
|
|
22
22
|
reset: boolean;
|
|
23
|
-
artifactPath: string | undefined;
|
|
24
|
-
artifactId: string | undefined;
|
|
25
23
|
onChunk: (chunk: string) => void;
|
|
26
24
|
/**
|
|
27
25
|
* Live status events (read/write/agent/…) delivered as they are emitted,
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* in, text (or, with `schema`, a structured object) out.
|
|
13
13
|
*/
|
|
14
14
|
import { instrumentedCompleteSimple, resolveTelemetry } from "@oh-my-pi/pi-agent-core";
|
|
15
|
-
import { type Api, Effort,
|
|
15
|
+
import { type Api, Effort, type Model, type Tool } from "@oh-my-pi/pi-ai";
|
|
16
|
+
import { getSupportedEfforts } from "@oh-my-pi/pi-catalog/model-thinking";
|
|
16
17
|
import * as z from "zod/v4";
|
|
17
18
|
import { extractTextContent, extractToolCall, parseJsonPayload } from "../commit/utils";
|
|
18
19
|
|
package/src/eval/idle-timeout.ts
CHANGED
|
@@ -6,8 +6,6 @@
|
|
|
6
6
|
* `agent()`/`parallel()`/`completion()` work is ignored completely, then {@link resume}
|
|
7
7
|
* starts a fresh timeout window once the runtime gets control back.
|
|
8
8
|
*
|
|
9
|
-
* The active timer self-reschedules instead of being torn down on every
|
|
10
|
-
* activity event, so frequent activity costs one timestamp write per event.
|
|
11
9
|
* Pause is reference-counted because `parallel()` can have multiple bridge calls
|
|
12
10
|
* in flight at once.
|
|
13
11
|
*/
|
|
@@ -36,11 +34,6 @@ export class IdleTimeout {
|
|
|
36
34
|
return this.#idleMs;
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
/** Record runtime activity, pushing the active deadline forward by `idleMs`. */
|
|
40
|
-
bump(): void {
|
|
41
|
-
if (this.#settled || this.#pauseDepth > 0) return;
|
|
42
|
-
this.#deadlineMs = Date.now() + this.#idleMs;
|
|
43
|
-
}
|
|
44
37
|
/** Suspend timeout accounting while control is delegated to host-side work. */
|
|
45
38
|
pause(): void {
|
|
46
39
|
if (this.#settled) return;
|
|
@@ -86,8 +79,8 @@ export class IdleTimeout {
|
|
|
86
79
|
if (this.#settled || this.#pauseDepth > 0) return;
|
|
87
80
|
const remainingMs = this.#deadlineMs - Date.now();
|
|
88
81
|
if (remainingMs > 0) {
|
|
89
|
-
//
|
|
90
|
-
// out the remaining window instead of firing early.
|
|
82
|
+
// The deadline moved forward (resume re-arming) after this timer was
|
|
83
|
+
// armed; wait out the remaining window instead of firing early.
|
|
91
84
|
this.#arm(remainingMs);
|
|
92
85
|
return;
|
|
93
86
|
}
|
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { logger, Snowflake, workerHostEntry } from "@oh-my-pi/pi-utils";
|
|
2
2
|
import type { ToolSession } from "../../tools";
|
|
3
3
|
import { ToolAbortError, ToolError } from "../../tools/tool-errors";
|
|
4
4
|
import { callSessionTool, type JsStatusEvent } from "./tool-bridge";
|
|
5
5
|
import { WorkerCore } from "./worker-core";
|
|
6
|
-
//
|
|
7
|
-
//
|
|
8
|
-
// Bun's `--compile` bundler discovers, the `new URL` form is what makes dev
|
|
9
|
-
// runs portable across cwds. The worker is registered as an additional
|
|
10
|
-
// `--compile` entrypoint in `scripts/build-binary.ts`.
|
|
6
|
+
// Coding-agent binary/bundle workers route through the CLI entrypoint with a
|
|
7
|
+
// hidden argv mode, so compiled/npm builds only need one JavaScript entry.
|
|
11
8
|
import type {
|
|
12
9
|
JsDisplayOutput,
|
|
13
10
|
RunErrorPayload,
|
|
@@ -384,8 +381,9 @@ async function raceWithTimeout<T>(promise: Promise<T>, timeoutMs: number, reason
|
|
|
384
381
|
|
|
385
382
|
async function spawnJsWorker(): Promise<WorkerHandle> {
|
|
386
383
|
try {
|
|
387
|
-
const
|
|
388
|
-
|
|
384
|
+
const hostEntry = workerHostEntry();
|
|
385
|
+
const worker = hostEntry
|
|
386
|
+
? new Worker(hostEntry, { type: "module", argv: ["__omp_js_eval_worker"] })
|
|
389
387
|
: new Worker(new URL("./worker-entry.ts", import.meta.url).href, { type: "module" });
|
|
390
388
|
return wrapBunWorker(worker);
|
|
391
389
|
} catch (err) {
|
package/src/eval/js/executor.ts
CHANGED
|
@@ -63,9 +63,13 @@ function isTimeoutReason(reason: unknown): boolean {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function formatJsTimeoutAnnotation(timeoutMs: number | undefined): string {
|
|
66
|
-
|
|
66
|
+
// Timeout cancellation force-kills the worker (the only way to interrupt
|
|
67
|
+
// synchronous user code), which discards the persistent VM state. Say so,
|
|
68
|
+
// or the model will keep referencing variables that no longer exist.
|
|
69
|
+
const reset = "The JS worker was force-killed and its VM state was reset; variables from earlier cells are gone.";
|
|
70
|
+
if (timeoutMs === undefined) return `Command timed out. ${reset}`;
|
|
67
71
|
const secs = Math.max(1, Math.round(timeoutMs / 1000));
|
|
68
|
-
return `Command timed out after ${secs} seconds`;
|
|
72
|
+
return `Command timed out after ${secs} seconds. ${reset}`;
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
export async function executeJs(code: string, options: JsExecutorOptions): Promise<JsResult> {
|
package/src/eval/js/index.ts
CHANGED
|
@@ -30,8 +30,6 @@ export default {
|
|
|
30
30
|
sessionId: namespaceSessionId(opts.sessionId),
|
|
31
31
|
sessionFile: opts.sessionFile,
|
|
32
32
|
reset: opts.reset,
|
|
33
|
-
artifactPath: opts.artifactPath,
|
|
34
|
-
artifactId: opts.artifactId,
|
|
35
33
|
onChunk: opts.onChunk,
|
|
36
34
|
onStatus: opts.onStatus,
|
|
37
35
|
session: opts.session,
|
|
@@ -83,12 +83,11 @@ export function createHelpers(ctx: HelperContext): HelperBundle {
|
|
|
83
83
|
},
|
|
84
84
|
append: async (rawPath, content) => {
|
|
85
85
|
const target = resolveHelperPath(ctx, rawPath, "write");
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
);
|
|
86
|
+
// O(1) append; read-all+rewrite both raced concurrent writers and went
|
|
87
|
+
// quadratic when called in a loop. Bun.write creates parent dirs, so
|
|
88
|
+
// keep that behavior for the append path too.
|
|
89
|
+
await fs.promises.mkdir(path.dirname(target), { recursive: true });
|
|
90
|
+
await fs.promises.appendFile(target, content, "utf-8");
|
|
92
91
|
ctx.emitStatus({
|
|
93
92
|
op: "append",
|
|
94
93
|
path: target,
|
|
@@ -102,7 +102,7 @@ export class LocalModuleLoader {
|
|
|
102
102
|
});
|
|
103
103
|
const moduleDir = path.dirname(modulePath);
|
|
104
104
|
const localDeps = new Set<string>();
|
|
105
|
-
for (const specifier of collectModuleSourceSpecifiers(stripped)) {
|
|
105
|
+
for (const specifier of await collectModuleSourceSpecifiers(stripped)) {
|
|
106
106
|
const resolved = resolveImportSpecifier(moduleDir, specifier);
|
|
107
107
|
if (isLocalPathSpecifier(specifier) && isManagedLocalModulePath(resolved)) {
|
|
108
108
|
localDeps.add(resolved);
|
|
@@ -90,15 +90,25 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
90
90
|
const limit = await __concurrencyLimit();
|
|
91
91
|
const concurrency = limit > 0 ? Math.min(limit, list.length) : list.length;
|
|
92
92
|
const results = new Array(list.length);
|
|
93
|
+
// Barrier semantics (mirrors the Python _pool_map): every item settles
|
|
94
|
+
// before we return or throw, then the lowest-index error propagates.
|
|
95
|
+
// Early-rejecting would orphan in-flight thunks (e.g. live agent()
|
|
96
|
+
// subagents) whose worker-side promises would never be observed.
|
|
97
|
+
const errors = new Map();
|
|
93
98
|
let next = 0;
|
|
94
99
|
const worker = async () => {
|
|
95
100
|
while (true) {
|
|
96
101
|
const index = next++;
|
|
97
102
|
if (index >= list.length) return;
|
|
98
|
-
|
|
103
|
+
try {
|
|
104
|
+
results[index] = await fn(list[index], index);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
errors.set(index, error);
|
|
107
|
+
}
|
|
99
108
|
}
|
|
100
109
|
};
|
|
101
110
|
await Promise.all(Array.from({ length: concurrency }, () => worker()));
|
|
111
|
+
if (errors.size > 0) throw errors.get(Math.min(...errors.keys()));
|
|
102
112
|
return results;
|
|
103
113
|
};
|
|
104
114
|
|
|
@@ -148,6 +158,8 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
148
158
|
|
|
149
159
|
const formatArgs = args => args.map(arg => (typeof arg === "string" ? arg : arg));
|
|
150
160
|
|
|
161
|
+
const consoleTimers = new Map();
|
|
162
|
+
const consoleCounts = new Map();
|
|
151
163
|
const consoleBridge = {
|
|
152
164
|
log: (...args) => globalThis.__omp_log__("log", ...formatArgs(args)),
|
|
153
165
|
info: (...args) => globalThis.__omp_log__("info", ...formatArgs(args)),
|
|
@@ -158,6 +170,55 @@ if (!globalThis.__omp_js_prelude_loaded__) {
|
|
|
158
170
|
columns === undefined
|
|
159
171
|
? globalThis.__omp_table__(data)
|
|
160
172
|
: globalThis.__omp_table__(data, columns),
|
|
173
|
+
dir: (value, _options) => globalThis.__omp_log__("log", value),
|
|
174
|
+
dirxml: (...args) => globalThis.__omp_log__("log", ...formatArgs(args)),
|
|
175
|
+
trace: (...args) => {
|
|
176
|
+
const stack = (new Error().stack ?? "").split("\n").slice(2).join("\n");
|
|
177
|
+
globalThis.__omp_log__("log", args.length > 0 ? `Trace: ${formatArgs(args).join(" ")}` : "Trace", `\n${stack}`);
|
|
178
|
+
},
|
|
179
|
+
assert: (condition, ...args) => {
|
|
180
|
+
if (condition) return;
|
|
181
|
+
if (args.length > 0) globalThis.__omp_log__("error", "Assertion failed:", ...formatArgs(args));
|
|
182
|
+
else globalThis.__omp_log__("error", "Assertion failed");
|
|
183
|
+
},
|
|
184
|
+
group: (...args) => {
|
|
185
|
+
if (args.length > 0) globalThis.__omp_log__("log", ...formatArgs(args));
|
|
186
|
+
},
|
|
187
|
+
groupCollapsed: (...args) => {
|
|
188
|
+
if (args.length > 0) globalThis.__omp_log__("log", ...formatArgs(args));
|
|
189
|
+
},
|
|
190
|
+
groupEnd: () => {},
|
|
191
|
+
time: label => {
|
|
192
|
+
consoleTimers.set(String(label ?? "default"), Date.now());
|
|
193
|
+
},
|
|
194
|
+
timeLog: (label, ...args) => {
|
|
195
|
+
const key = String(label ?? "default");
|
|
196
|
+
const start = consoleTimers.get(key);
|
|
197
|
+
if (start === undefined) {
|
|
198
|
+
globalThis.__omp_log__("warn", `Timer '${key}' does not exist`);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
globalThis.__omp_log__("log", `${key}: ${Date.now() - start}ms`, ...formatArgs(args));
|
|
202
|
+
},
|
|
203
|
+
timeEnd: label => {
|
|
204
|
+
const key = String(label ?? "default");
|
|
205
|
+
const start = consoleTimers.get(key);
|
|
206
|
+
if (start === undefined) {
|
|
207
|
+
globalThis.__omp_log__("warn", `Timer '${key}' does not exist`);
|
|
208
|
+
return;
|
|
209
|
+
}
|
|
210
|
+
consoleTimers.delete(key);
|
|
211
|
+
globalThis.__omp_log__("log", `${key}: ${Date.now() - start}ms`);
|
|
212
|
+
},
|
|
213
|
+
count: label => {
|
|
214
|
+
const key = String(label ?? "default");
|
|
215
|
+
const next = (consoleCounts.get(key) ?? 0) + 1;
|
|
216
|
+
consoleCounts.set(key, next);
|
|
217
|
+
globalThis.__omp_log__("log", `${key}: ${next}`);
|
|
218
|
+
},
|
|
219
|
+
countReset: label => {
|
|
220
|
+
consoleCounts.delete(String(label ?? "default"));
|
|
221
|
+
},
|
|
161
222
|
};
|
|
162
223
|
|
|
163
224
|
globalThis.console = consoleBridge;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type * as BabelParser from "@babel/parser";
|
|
2
2
|
|
|
3
3
|
// Static ESM `import` declarations are not valid inside vm.runInContext (script-mode parsing),
|
|
4
4
|
// and dynamic `import(...)` would otherwise resolve specifiers against the worker module's URL
|
|
@@ -64,9 +64,22 @@ type BabelModuleSourceDeclaration = {
|
|
|
64
64
|
|
|
65
65
|
type BabelNode = { type: string; start: number; end: number; [key: string]: unknown };
|
|
66
66
|
|
|
67
|
-
|
|
67
|
+
// @babel/parser sits on the CLI launch graph (tools → eval backend → worker-core →
|
|
68
|
+
// runtime → this module) but only runs when an eval cell executes, so it is loaded
|
|
69
|
+
// lazily and memoized.
|
|
70
|
+
let babelParser: typeof BabelParser | undefined;
|
|
71
|
+
|
|
72
|
+
async function loadBabelParser(): Promise<typeof BabelParser> {
|
|
73
|
+
if (!babelParser) {
|
|
74
|
+
babelParser = await import("@babel/parser");
|
|
75
|
+
}
|
|
76
|
+
return babelParser;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async function parseProgram(code: string): Promise<{ program: { body: ReadonlyArray<BabelProgramNode> } } | null> {
|
|
80
|
+
const { parse } = await loadBabelParser();
|
|
68
81
|
try {
|
|
69
|
-
return
|
|
82
|
+
return parse(code, {
|
|
70
83
|
sourceType: "module",
|
|
71
84
|
allowAwaitOutsideFunction: true,
|
|
72
85
|
allowReturnOutsideFunction: true,
|
|
@@ -82,6 +95,14 @@ function parseProgram(code: string): { program: { body: ReadonlyArray<BabelProgr
|
|
|
82
95
|
}
|
|
83
96
|
}
|
|
84
97
|
|
|
98
|
+
// Callee substituted for dynamic `import(...)` calls. Functions handed to puppeteer
|
|
99
|
+
// (`tab.evaluate`, `page.evaluate`, `waitForFunction`, `$$eval`, ...) are serialized with
|
|
100
|
+
// `Function.prototype.toString()` and re-evaluated inside the browser page, where the
|
|
101
|
+
// worker-injected `__omp_import__` global does not exist. The swap therefore guards on the
|
|
102
|
+
// helper's presence and falls back to native dynamic import, so serialized code keeps
|
|
103
|
+
// working in foreign realms while in-worker code still resolves against the session cwd.
|
|
104
|
+
const DYNAMIC_IMPORT_CALLEE = '(typeof __omp_import__ === "function" ? __omp_import__ : (s, o) => import(s, o))';
|
|
105
|
+
|
|
85
106
|
function buildOmpImportCall(sourceLiteral: string, optionsLiteral: string | undefined): string {
|
|
86
107
|
// Route every static import through the worker-injected `__omp_import__` helper so the
|
|
87
108
|
// specifier resolves against the session cwd (and `with`-attribute imports keep working).
|
|
@@ -154,10 +175,10 @@ function rewriteImportNode(node: BabelImportDeclaration): string {
|
|
|
154
175
|
return `await ${importCall};`;
|
|
155
176
|
}
|
|
156
177
|
|
|
157
|
-
export function rewriteImports(code: string): string {
|
|
178
|
+
export async function rewriteImports(code: string): Promise<string> {
|
|
158
179
|
if (!code.includes("import")) return code;
|
|
159
180
|
|
|
160
|
-
const ast = parseProgram(code);
|
|
181
|
+
const ast = await parseProgram(code);
|
|
161
182
|
if (!ast) {
|
|
162
183
|
// Parser bailed entirely — let the VM surface the real syntax error.
|
|
163
184
|
return code;
|
|
@@ -180,7 +201,7 @@ export function rewriteImports(code: string): string {
|
|
|
180
201
|
const call = node as unknown as { callee?: { type?: string; start?: number; end?: number } };
|
|
181
202
|
const callee = call.callee;
|
|
182
203
|
if (callee?.type !== "Import" || typeof callee.start !== "number" || typeof callee.end !== "number") return;
|
|
183
|
-
edits.push({ start: callee.start, end: callee.end, text:
|
|
204
|
+
edits.push({ start: callee.start, end: callee.end, text: DYNAMIC_IMPORT_CALLEE });
|
|
184
205
|
});
|
|
185
206
|
|
|
186
207
|
if (edits.length === 0) return code;
|
|
@@ -193,8 +214,8 @@ export function rewriteImports(code: string): string {
|
|
|
193
214
|
}
|
|
194
215
|
return result;
|
|
195
216
|
}
|
|
196
|
-
export function collectModuleSourceSpecifiers(code: string): string[] {
|
|
197
|
-
const ast = parseProgram(code);
|
|
217
|
+
export async function collectModuleSourceSpecifiers(code: string): Promise<string[]> {
|
|
218
|
+
const ast = await parseProgram(code);
|
|
198
219
|
if (!ast) return [];
|
|
199
220
|
const sources: string[] = [];
|
|
200
221
|
for (const node of ast.program.body) {
|
|
@@ -210,8 +231,11 @@ export function collectModuleSourceSpecifiers(code: string): string[] {
|
|
|
210
231
|
return sources;
|
|
211
232
|
}
|
|
212
233
|
|
|
213
|
-
export function rewriteModuleSourceSpecifiers(
|
|
214
|
-
|
|
234
|
+
export async function rewriteModuleSourceSpecifiers(
|
|
235
|
+
code: string,
|
|
236
|
+
replacer: (source: string) => string,
|
|
237
|
+
): Promise<string> {
|
|
238
|
+
const ast = await parseProgram(code);
|
|
215
239
|
if (!ast) return code;
|
|
216
240
|
|
|
217
241
|
type Edit = { start: number; end: number; text: string };
|
|
@@ -241,9 +265,9 @@ export function rewriteModuleSourceSpecifiers(code: string, replacer: (source: s
|
|
|
241
265
|
return result;
|
|
242
266
|
}
|
|
243
267
|
|
|
244
|
-
export function rewriteDynamicImports(code: string, callee = "__omp_import__"): string {
|
|
268
|
+
export async function rewriteDynamicImports(code: string, callee = "__omp_import__"): Promise<string> {
|
|
245
269
|
if (!code.includes("import")) return code;
|
|
246
|
-
const ast = parseProgram(code);
|
|
270
|
+
const ast = await parseProgram(code);
|
|
247
271
|
if (!ast) return code;
|
|
248
272
|
|
|
249
273
|
type Edit = { start: number; end: number; text: string };
|
|
@@ -331,10 +355,10 @@ function appendGlobalBindingPublish(source: string, names: readonly string[]): s
|
|
|
331
355
|
* Nested declarations (inside functions, blocks, classes) are left alone \u2014 they're
|
|
332
356
|
* scoped to their enclosing function/block regardless of `var` vs `let`/`const`.
|
|
333
357
|
*/
|
|
334
|
-
function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolean } = {}): string {
|
|
358
|
+
async function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolean } = {}): Promise<string> {
|
|
335
359
|
if (!/\b(?:const|let|class)\b/.test(code)) return code;
|
|
336
360
|
|
|
337
|
-
const ast = parseProgram(code);
|
|
361
|
+
const ast = await parseProgram(code);
|
|
338
362
|
if (!ast) {
|
|
339
363
|
return code;
|
|
340
364
|
}
|
|
@@ -373,8 +397,8 @@ function demoteTopLevelLexicals(code: string, options: { publishGlobals?: boolea
|
|
|
373
397
|
return result;
|
|
374
398
|
}
|
|
375
399
|
|
|
376
|
-
function returnFinalExpression(code: string): { source: string; returned: boolean } {
|
|
377
|
-
const ast = parseProgram(code);
|
|
400
|
+
async function returnFinalExpression(code: string): Promise<{ source: string; returned: boolean }> {
|
|
401
|
+
const ast = await parseProgram(code);
|
|
378
402
|
const body = ast?.program.body;
|
|
379
403
|
if (!body) return { source: code, returned: false };
|
|
380
404
|
let lastIndex = body.length - 1;
|
|
@@ -438,8 +462,8 @@ function containsAsyncWrapperSyntax(value: unknown): boolean {
|
|
|
438
462
|
return false;
|
|
439
463
|
}
|
|
440
464
|
|
|
441
|
-
function requiresAsyncWrapper(code: string): boolean {
|
|
442
|
-
const ast = parseProgram(code);
|
|
465
|
+
async function requiresAsyncWrapper(code: string): Promise<boolean> {
|
|
466
|
+
const ast = await parseProgram(code);
|
|
443
467
|
if (!ast) return false;
|
|
444
468
|
for (const node of ast.program.body) {
|
|
445
469
|
if (containsAsyncWrapperSyntax(node)) return true;
|
|
@@ -486,13 +510,15 @@ export function stripTypeScriptSyntax(
|
|
|
486
510
|
const LOOKS_LIKE_TS =
|
|
487
511
|
/(?:\bimport\s+type\b|\bexport\s+type\b|\b(?:import|export)\s*\{[^}\n]*\btype\s+\w|\binterface\s+\w|\btype\s+\w+\s*=|\b(?:as|satisfies)\s+(?:[A-Z]|\bconst\b)|:\s*(?:string|number|boolean|any|unknown|void|never|object|[A-Z]\w*)\b|<\s*[A-Z]\w*\s*[,>])/;
|
|
488
512
|
|
|
489
|
-
export function wrapCode(
|
|
490
|
-
|
|
513
|
+
export async function wrapCode(
|
|
514
|
+
code: string,
|
|
515
|
+
): Promise<{ source: string; asyncWrapped: boolean; finalExpressionReturned: boolean }> {
|
|
516
|
+
const finalExpression = await returnFinalExpression(code);
|
|
491
517
|
const stripped = stripTypeScript(finalExpression.source);
|
|
492
|
-
const importsRewritten = rewriteImports(stripped);
|
|
493
|
-
const needsAsyncWrapper = requiresAsyncWrapper(importsRewritten);
|
|
518
|
+
const importsRewritten = await rewriteImports(stripped);
|
|
519
|
+
const needsAsyncWrapper = await requiresAsyncWrapper(importsRewritten);
|
|
494
520
|
const rewritten = {
|
|
495
|
-
source: demoteTopLevelLexicals(importsRewritten, { publishGlobals: needsAsyncWrapper }),
|
|
521
|
+
source: await demoteTopLevelLexicals(importsRewritten, { publishGlobals: needsAsyncWrapper }),
|
|
496
522
|
returned: finalExpression.returned,
|
|
497
523
|
};
|
|
498
524
|
if (!needsAsyncWrapper) {
|
|
@@ -181,7 +181,7 @@ export class JsRuntime {
|
|
|
181
181
|
finalExpressionValue: undefined,
|
|
182
182
|
};
|
|
183
183
|
return await this.#als.run(context, async () => {
|
|
184
|
-
const wrapped = wrapCode(code);
|
|
184
|
+
const wrapped = await wrapCode(code);
|
|
185
185
|
const value = indirectEval(wrapped.source, filename);
|
|
186
186
|
if (wrapped.finalExpressionReturned) {
|
|
187
187
|
const awaited = await awaitMaybePromise(value);
|
package/src/eval/py/index.ts
CHANGED
|
@@ -42,8 +42,6 @@ export default {
|
|
|
42
42
|
localRoots: resolveEvalUrlRoots(opts.session),
|
|
43
43
|
kernelOwnerId: opts.kernelOwnerId,
|
|
44
44
|
reset: opts.reset,
|
|
45
|
-
artifactPath: opts.artifactPath,
|
|
46
|
-
artifactId: opts.artifactId,
|
|
47
45
|
onChunk: opts.onChunk,
|
|
48
46
|
onStatus: opts.onStatus,
|
|
49
47
|
toolSession: opts.session,
|
package/src/eval/py/kernel.ts
CHANGED
|
@@ -129,10 +129,29 @@ function throwIfAborted(signal: AbortSignal | undefined, fallbackReason: string)
|
|
|
129
129
|
throw createAbortError("AbortError", typeof reason === "string" ? reason : fallbackReason);
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// Cache successful probes per resolved cwd: every cell otherwise pays one (or
|
|
133
|
+
// two — backend.isAvailable + ensureKernelAvailable) interpreter spawns even
|
|
134
|
+
// when the kernel is already hot. Failures are not cached so installing a
|
|
135
|
+
// Python mid-session is picked up on the next attempt.
|
|
136
|
+
const availabilityCache = new Map<string, Promise<PythonKernelAvailability>>();
|
|
137
|
+
|
|
132
138
|
export async function checkPythonKernelAvailability(cwd: string): Promise<PythonKernelAvailability> {
|
|
133
139
|
if (isBunTestRuntime() || $flag("PI_PYTHON_SKIP_CHECK")) {
|
|
134
140
|
return { ok: true };
|
|
135
141
|
}
|
|
142
|
+
const key = path.resolve(cwd);
|
|
143
|
+
const cached = availabilityCache.get(key);
|
|
144
|
+
if (cached) return await cached;
|
|
145
|
+
const probe = probePythonKernelAvailability(key);
|
|
146
|
+
availabilityCache.set(key, probe);
|
|
147
|
+
const result = await probe;
|
|
148
|
+
if (!result.ok && availabilityCache.get(key) === probe) {
|
|
149
|
+
availabilityCache.delete(key);
|
|
150
|
+
}
|
|
151
|
+
return result;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async function probePythonKernelAvailability(cwd: string): Promise<PythonKernelAvailability> {
|
|
136
155
|
try {
|
|
137
156
|
const settings = await Settings.init();
|
|
138
157
|
const { env } = settings.getShellConfig();
|