@oh-my-pi/pi-coding-agent 17.2.3 → 17.2.5
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 +92 -0
- package/dist/{CHANGELOG-c5hpqt9r.md → CHANGELOG-q2w43aw3.md} +92 -0
- package/dist/cli.js +3979 -3548
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- package/dist/types/advisor/advise-tool.d.ts +6 -0
- package/dist/types/advisor/runtime.d.ts +4 -4
- package/dist/types/capability/mcp.d.ts +9 -0
- package/dist/types/cli/args.d.ts +4 -1
- package/dist/types/cli/browser-relay-cli.d.ts +15 -0
- package/dist/types/cli/command-help.d.ts +99 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- package/dist/types/cli/models-cli.d.ts +1 -1
- package/dist/types/cli/thinking-levels.d.ts +5 -0
- package/dist/types/cli/update-cli.d.ts +13 -0
- package/dist/types/commands/browser-relay.d.ts +38 -0
- package/dist/types/commands/commit.d.ts +3 -0
- package/dist/types/commands/complete.d.ts +1 -1
- package/dist/types/commands/completions.d.ts +6 -0
- package/dist/types/commands/grep.d.ts +3 -0
- package/dist/types/commands/join.d.ts +4 -0
- package/dist/types/commands/launch-help.d.ts +171 -0
- package/dist/types/commands/launch.d.ts +5 -1
- package/dist/types/commands/models.d.ts +3 -0
- package/dist/types/commands/say.d.ts +10 -0
- package/dist/types/commands/worktree.d.ts +3 -0
- package/dist/types/config/keybindings.d.ts +6 -1
- package/dist/types/config/model-discovery.d.ts +2 -2
- package/dist/types/config/models-config-schema-bundle.d.ts +3 -0
- package/dist/types/config/models-config-schema.d.ts +2 -0
- package/dist/types/config/models-config.d.ts +1 -0
- package/dist/types/config/service-tier.d.ts +2 -0
- package/dist/types/config/settings-schema.d.ts +70 -22
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- package/dist/types/discovery/helpers.d.ts +6 -0
- package/dist/types/discovery/omp-extension-roots.d.ts +21 -2
- package/dist/types/edit/index.d.ts +3 -3
- package/dist/types/edit/modes/replace.d.ts +22 -15
- package/dist/types/edit/renderer.d.ts +1 -1
- package/dist/types/eval/py/kernel.d.ts +3 -1
- package/dist/types/eval/py/spawn-options.d.ts +12 -16
- package/dist/types/extensibility/extensions/loader.d.ts +6 -2
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +8 -1
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +1 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +2 -0
- package/dist/types/extensibility/plugins/marketplace/registry.d.ts +2 -2
- package/dist/types/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +6 -3
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +3 -2
- package/dist/types/launch/protocol.d.ts +2 -2
- package/dist/types/lsp/client.d.ts +2 -0
- package/dist/types/lsp/mux/daemon.d.ts +15 -0
- package/dist/types/lsp/mux/protocol.d.ts +57 -0
- package/dist/types/lsp/mux/server.d.ts +18 -0
- package/dist/types/lsp/types.d.ts +22 -2
- package/dist/types/main.d.ts +2 -0
- package/dist/types/mcp/request-id.d.ts +19 -0
- package/dist/types/mcp/types.d.ts +14 -0
- package/dist/types/memory-backend/index.d.ts +1 -0
- package/dist/types/memory-backend/messages.d.ts +15 -0
- package/dist/types/mnemopi/embed-client.d.ts +1 -1
- package/dist/types/mnemopi/state.d.ts +0 -23
- package/dist/types/modes/components/assistant-message.d.ts +2 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/model-browser.d.ts +7 -5
- package/dist/types/modes/components/model-picker.d.ts +9 -3
- package/dist/types/modes/components/read-tool-group.d.ts +11 -0
- package/dist/types/modes/components/stripped-tool-calls-placeholder.d.ts +12 -0
- package/dist/types/modes/components/tool-execution.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +1 -0
- package/dist/types/modes/types.d.ts +2 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/registry/agent-lifecycle.d.ts +14 -5
- package/dist/types/registry/agent-registry.d.ts +4 -3
- package/dist/types/sdk.d.ts +4 -2
- package/dist/types/secrets/index.d.ts +7 -9
- package/dist/types/session/agent-session-types.d.ts +3 -1
- package/dist/types/session/agent-session.d.ts +6 -1
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/model-controls.d.ts +0 -1
- package/dist/types/session/session-advisors.d.ts +8 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-maintenance.d.ts +2 -0
- package/dist/types/session/session-manager.d.ts +16 -5
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/system-prompt.d.ts +6 -1
- package/dist/types/task/index.d.ts +2 -1
- package/dist/types/task/spawn-policy.d.ts +5 -0
- package/dist/types/thinking.d.ts +1 -7
- package/dist/types/tools/ast-grep.d.ts +1 -1
- package/dist/types/tools/browser/registry.d.ts +2 -1
- package/dist/types/tools/browser/relay/bridge.d.ts +35 -0
- package/dist/types/tools/browser/relay/daemon.d.ts +16 -0
- package/dist/types/tools/browser/relay/kind.d.ts +19 -0
- package/dist/types/tools/browser/relay/protocol.d.ts +97 -0
- package/dist/types/tools/browser/relay/server.d.ts +35 -0
- package/dist/types/tools/browser/render.d.ts +1 -0
- package/dist/types/tools/browser.d.ts +3 -0
- package/dist/types/tools/computer/exposure.d.ts +9 -7
- package/dist/types/tools/computer/protocol.d.ts +70 -17
- package/dist/types/tools/computer/supervisor.d.ts +23 -10
- package/dist/types/tools/computer/worker-entry.d.ts +1 -0
- package/dist/types/tools/computer/worker.d.ts +42 -7
- package/dist/types/tools/computer-renderer.d.ts +7 -5
- package/dist/types/tools/computer.d.ts +25 -44
- package/dist/types/tools/context.d.ts +3 -0
- package/dist/types/tools/default-renderer.d.ts +3 -0
- package/dist/types/tools/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/render-utils.d.ts +2 -0
- package/dist/types/tools/{browser/run-cancellation.d.ts → run-scope.d.ts} +8 -8
- package/dist/types/tools/tool-timeouts.d.ts +5 -0
- package/dist/types/tools/xdev.d.ts +8 -0
- package/dist/types/utils/clipboard.d.ts +2 -2
- package/dist/types/web/kagi.d.ts +1 -0
- package/dist/types/web/search/index.d.ts +1 -1
- package/dist/types/web/search/providers/anthropic.d.ts +1 -0
- package/dist/types/web/search/providers/base.d.ts +2 -0
- package/dist/types/web/search/providers/brave.d.ts +1 -0
- package/dist/types/web/search/providers/browser-page.d.ts +1 -0
- package/dist/types/web/search/providers/codex.d.ts +1 -0
- package/dist/types/web/search/providers/exa.d.ts +1 -0
- package/dist/types/web/search/providers/firecrawl.d.ts +1 -0
- package/dist/types/web/search/providers/gemini.d.ts +1 -0
- package/dist/types/web/search/providers/jina.d.ts +1 -0
- package/dist/types/web/search/providers/kagi.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +1 -0
- package/dist/types/web/search/providers/parallel.d.ts +1 -0
- package/dist/types/web/search/providers/perplexity.d.ts +1 -0
- package/dist/types/web/search/providers/searxng.d.ts +1 -0
- package/dist/types/web/search/providers/tavily.d.ts +1 -0
- package/dist/types/web/search/providers/tinyfish.d.ts +1 -0
- package/dist/types/web/search/providers/utils.d.ts +6 -9
- package/dist/types/web/search/providers/zai.d.ts +1 -0
- package/dist/types/web/search/types.d.ts +4 -0
- package/package.json +12 -12
- package/scripts/legacy-pi-virtual-module.ts +12 -2
- package/src/advisor/advise-tool.ts +18 -0
- package/src/advisor/runtime.ts +6 -6
- package/src/capability/mcp.ts +7 -0
- package/src/cli/args.ts +7 -87
- package/src/cli/browser-relay-cli.ts +119 -0
- package/src/cli/command-help.ts +103 -0
- package/src/cli/completion-gen.ts +5 -5
- package/src/cli/flag-tables.ts +9 -0
- package/src/cli/help-extra.ts +89 -0
- package/src/cli/models-cli.ts +13 -16
- package/src/cli/setup-cli.ts +13 -21
- package/src/cli/thinking-levels.ts +7 -0
- package/src/cli/update-cli.ts +26 -7
- package/src/cli-commands.ts +170 -33
- package/src/cli.ts +17 -5
- package/src/collab/host.ts +1 -1
- package/src/commands/acp.ts +3 -1
- package/src/commands/agents.ts +3 -2
- package/src/commands/auth-broker.ts +3 -2
- package/src/commands/auth-gateway.ts +3 -2
- package/src/commands/bench.ts +2 -3
- package/src/commands/browser-relay.ts +53 -0
- package/src/commands/cleanse.ts +2 -2
- package/src/commands/commit.ts +3 -2
- package/src/commands/complete.ts +2 -1
- package/src/commands/completions.ts +3 -2
- package/src/commands/config.ts +3 -2
- package/src/commands/dry-balance.ts +2 -2
- package/src/commands/gallery.ts +3 -2
- package/src/commands/gc.ts +3 -2
- package/src/commands/grep.ts +3 -2
- package/src/commands/grievances.ts +3 -2
- package/src/commands/install.ts +2 -2
- package/src/commands/join.ts +3 -2
- package/src/commands/launch-help.ts +116 -0
- package/src/commands/launch.ts +7 -191
- package/src/commands/models.ts +3 -2
- package/src/commands/plugin.ts +3 -2
- package/src/commands/read.ts +3 -2
- package/src/commands/say.ts +3 -2
- package/src/commands/setup.ts +3 -2
- package/src/commands/shell.ts +3 -2
- package/src/commands/ssh.ts +3 -2
- package/src/commands/stats.ts +3 -2
- package/src/commands/tiny-models.ts +2 -2
- package/src/commands/token.ts +2 -2
- package/src/commands/ttsr.ts +2 -2
- package/src/commands/update.ts +3 -2
- package/src/commands/usage.ts +3 -2
- package/src/commands/web-search.ts +3 -2
- package/src/commands/worktree.ts +3 -2
- package/src/config/keybindings.ts +19 -9
- package/src/config/mcp-schema.json +5 -0
- package/src/config/model-discovery.ts +30 -13
- package/src/config/model-registry.ts +16 -6
- package/src/config/models-config-schema-bundle.ts +9 -0
- package/src/config/resolve-config-value.ts +2 -1
- package/src/config/service-tier.ts +5 -0
- package/src/config/settings-schema.ts +73 -21
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- package/src/discovery/builtin.ts +10 -0
- package/src/discovery/helpers.ts +10 -0
- package/src/discovery/mcp-json.ts +11 -1
- package/src/discovery/omp-extension-roots.ts +79 -20
- package/src/discovery/omp-plugins.ts +10 -1
- package/src/edit/diff.ts +17 -8
- package/src/edit/index.ts +20 -7
- package/src/edit/modes/replace.ts +93 -40
- package/src/edit/renderer.ts +1 -1
- package/src/edit/streaming.ts +14 -17
- package/src/eval/py/kernel.ts +2 -1
- package/src/eval/py/spawn-options.ts +24 -29
- package/src/export/html/template.js +8 -26
- package/src/extensibility/extensions/loader.ts +66 -28
- package/src/extensibility/extensions/wrapper.ts +1 -0
- package/src/extensibility/legacy-pi-ai-shim.ts +22 -1
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +7 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +124 -57
- package/src/extensibility/plugins/marketplace/registry.ts +4 -8
- package/src/extensibility/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +1 -1
- package/src/launch/client.ts +32 -13
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +3 -6
- package/src/launch/protocol.ts +2 -2
- package/src/lsp/client.ts +23 -2
- package/src/lsp/index.ts +8 -0
- package/src/lsp/mux/daemon.ts +348 -0
- package/src/lsp/mux/protocol.ts +96 -0
- package/src/lsp/mux/server.ts +797 -0
- package/src/lsp/types.ts +28 -2
- package/src/main.ts +31 -24
- package/src/mcp/config.ts +1 -0
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mcp/request-id.ts +24 -0
- package/src/mcp/transports/http.ts +4 -2
- package/src/mcp/transports/sse.ts +4 -2
- package/src/mcp/transports/stdio.ts +4 -2
- package/src/mcp/types.ts +15 -0
- package/src/memory-backend/index.ts +1 -0
- package/src/memory-backend/messages.ts +19 -0
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/agent-hub.ts +1 -1
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +10 -1
- package/src/modes/components/model-browser.ts +25 -17
- package/src/modes/components/model-picker.ts +10 -6
- package/src/modes/components/read-tool-group.ts +36 -0
- package/src/modes/components/status-line/component.ts +1 -1
- package/src/modes/components/stripped-tool-calls-placeholder.ts +35 -0
- package/src/modes/components/tool-execution.ts +85 -20
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/command-controller.ts +2 -2
- package/src/modes/controllers/event-controller.ts +199 -10
- package/src/modes/controllers/input-controller.ts +39 -1
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +47 -6
- package/src/modes/interactive-mode.ts +2 -0
- package/src/modes/types.ts +6 -1
- package/src/modes/utils/hotkeys-markdown.ts +1 -0
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/modes/utils/ui-helpers.ts +6 -10
- package/src/modes/workflow.ts +8 -2
- package/src/prompts/agents/init.md +1 -1
- package/src/prompts/system/plan-mode-active.md +2 -2
- package/src/prompts/system/system-prompt.md +26 -52
- package/src/prompts/system/workflow-notice.md +3 -3
- package/src/prompts/tools/ast-grep.md +1 -1
- package/src/prompts/tools/bash.md +1 -1
- package/src/prompts/tools/browser.md +1 -0
- package/src/prompts/tools/computer.md +21 -21
- package/src/prompts/tools/glob.md +1 -1
- package/src/prompts/tools/grep.md +1 -1
- package/src/prompts/tools/replace.md +5 -4
- package/src/prompts/tools/task.md +4 -4
- package/src/registry/agent-lifecycle.ts +36 -11
- package/src/registry/agent-registry.ts +12 -5
- package/src/sdk.ts +102 -35
- package/src/secrets/index.ts +16 -18
- package/src/session/agent-session-types.ts +3 -1
- package/src/session/agent-session.ts +23 -2
- package/src/session/agent-storage.ts +6 -4
- package/src/session/history-storage.ts +4 -2
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/messages.ts +31 -7
- package/src/session/model-controls.ts +0 -1
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +21 -3
- package/src/session/session-context.ts +16 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-maintenance.ts +41 -4
- package/src/session/session-manager.ts +181 -94
- package/src/session/session-paths.ts +118 -55
- package/src/session/session-stats.ts +48 -3
- package/src/session/session-storage.ts +30 -22
- package/src/session/session-tools.ts +25 -23
- package/src/session/stream-guards.ts +1 -1
- package/src/slash-commands/builtin-registry.ts +29 -26
- package/src/system-prompt.ts +14 -4
- package/src/task/executor.ts +8 -1
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tiny/text.ts +12 -0
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +5 -10
- package/src/tools/browser/cmux/rpc.ts +2 -8
- package/src/tools/browser/registry.ts +53 -2
- package/src/tools/browser/relay/bridge.ts +945 -0
- package/src/tools/browser/relay/daemon.ts +117 -0
- package/src/tools/browser/relay/extension-assets/background.js.txt +242 -0
- package/src/tools/browser/relay/extension-assets/manifest.json.txt +14 -0
- package/src/tools/browser/relay/extension-assets/options.html.txt +53 -0
- package/src/tools/browser/relay/extension-assets/options.js.txt +23 -0
- package/src/tools/browser/relay/kind.ts +41 -0
- package/src/tools/browser/relay/protocol.ts +54 -0
- package/src/tools/browser/relay/server.ts +141 -0
- package/src/tools/browser/render.ts +4 -1
- package/src/tools/browser/shared-daemon.ts +7 -58
- package/src/tools/browser/tab-supervisor.ts +5 -4
- package/src/tools/browser/tab-worker.ts +33 -12
- package/src/tools/browser.ts +26 -1
- package/src/tools/computer/exposure.ts +11 -35
- package/src/tools/computer/protocol.ts +51 -10
- package/src/tools/computer/supervisor.ts +227 -124
- package/src/tools/computer/worker-entry.ts +11 -6
- package/src/tools/computer/worker.ts +695 -81
- package/src/tools/computer-renderer.ts +104 -65
- package/src/tools/computer.ts +134 -428
- package/src/tools/context.ts +3 -0
- package/src/tools/default-renderer.ts +19 -4
- package/src/tools/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/index.ts +10 -6
- package/src/tools/inspect-image.ts +32 -6
- package/src/tools/render-utils.ts +2 -0
- package/src/tools/{browser/run-cancellation.ts → run-scope.ts} +11 -11
- package/src/tools/tool-timeouts.ts +1 -0
- package/src/tools/xdev.ts +29 -2
- package/src/utils/clipboard.ts +40 -14
- package/src/utils/command-args.ts +26 -28
- package/src/utils/tool-choice.ts +0 -13
- package/src/web/kagi.ts +2 -1
- package/src/web/search/index.ts +18 -2
- package/src/web/search/providers/anthropic.ts +7 -2
- package/src/web/search/providers/base.ts +2 -0
- package/src/web/search/providers/brave.ts +3 -1
- package/src/web/search/providers/browser-page.ts +6 -4
- package/src/web/search/providers/codex.ts +4 -1
- package/src/web/search/providers/duckduckgo.ts +2 -1
- package/src/web/search/providers/ecosia.ts +2 -1
- package/src/web/search/providers/exa.ts +4 -2
- package/src/web/search/providers/firecrawl.ts +3 -1
- package/src/web/search/providers/gemini.ts +8 -2
- package/src/web/search/providers/google.ts +2 -1
- package/src/web/search/providers/jina.ts +12 -2
- package/src/web/search/providers/kagi.ts +3 -0
- package/src/web/search/providers/kimi.ts +5 -1
- package/src/web/search/providers/mojeek.ts +2 -1
- package/src/web/search/providers/parallel.ts +5 -1
- package/src/web/search/providers/perplexity.ts +6 -3
- package/src/web/search/providers/public.ts +1 -1
- package/src/web/search/providers/searxng.ts +11 -5
- package/src/web/search/providers/startpage.ts +10 -4
- package/src/web/search/providers/synthetic.ts +11 -5
- package/src/web/search/providers/tavily.ts +3 -1
- package/src/web/search/providers/tinyfish.ts +3 -1
- package/src/web/search/providers/utils.ts +12 -10
- package/src/web/search/providers/xai.ts +2 -2
- package/src/web/search/providers/zai.ts +18 -3
- package/src/web/search/types.ts +6 -0
|
@@ -665,7 +665,6 @@ const bareRequireResolutionCache = new Map<string, Promise<string | null>>();
|
|
|
665
665
|
const realpathCache = new Map<string, Promise<string>>();
|
|
666
666
|
const nativeAddonResolutionCache = new Map<string, Promise<string | null>>();
|
|
667
667
|
const nativeAddonRequireScanCache = new Map<string, Promise<boolean>>();
|
|
668
|
-
const nativeAddonLoaderModulePaths = new Set<string>();
|
|
669
668
|
|
|
670
669
|
function clearLegacyPiResolutionCaches(): void {
|
|
671
670
|
resolvedSpecifierFallbacks.clear();
|
|
@@ -677,7 +676,6 @@ function clearLegacyPiResolutionCaches(): void {
|
|
|
677
676
|
bareRequireResolutionCache.clear();
|
|
678
677
|
nativeAddonResolutionCache.clear();
|
|
679
678
|
nativeAddonRequireScanCache.clear();
|
|
680
|
-
nativeAddonLoaderModulePaths.clear();
|
|
681
679
|
realpathCache.clear();
|
|
682
680
|
}
|
|
683
681
|
|
|
@@ -1076,6 +1074,23 @@ async function resolveSourceModuleFile(basePath: string): Promise<string | null>
|
|
|
1076
1074
|
return null;
|
|
1077
1075
|
}
|
|
1078
1076
|
|
|
1077
|
+
async function resolveRelativeCommonJsRequire(specifier: string, importerPath: string): Promise<string | null> {
|
|
1078
|
+
const candidate = path.resolve(path.dirname(importerPath), specifier);
|
|
1079
|
+
try {
|
|
1080
|
+
const stats = await fs.promises.stat(candidate);
|
|
1081
|
+
if (stats.isDirectory()) {
|
|
1082
|
+
const manifest = await readPackageManifest(candidate);
|
|
1083
|
+
if (typeof manifest?.main === "string") {
|
|
1084
|
+
const main = await resolveSourceModuleFile(path.resolve(candidate, manifest.main));
|
|
1085
|
+
if (main) return main;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
} catch {
|
|
1089
|
+
// Missing candidates fall through to extension and index resolution.
|
|
1090
|
+
}
|
|
1091
|
+
return resolveSourceModuleFile(candidate);
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1079
1094
|
function isPathInsideRoot(rootPath: string, candidatePath: string): boolean {
|
|
1080
1095
|
const relative = path.relative(rootPath, candidatePath);
|
|
1081
1096
|
return relative === "" || (relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative));
|
|
@@ -1255,7 +1270,7 @@ function isBareExtensionDependencySpecifier(specifier: string): boolean {
|
|
|
1255
1270
|
return false;
|
|
1256
1271
|
}
|
|
1257
1272
|
const packageName = specifier.startsWith("@") ? specifier.split("/").slice(0, 2).join("/") : specifier.split("/")[0];
|
|
1258
|
-
return Boolean(packageName && !isBuiltin(
|
|
1273
|
+
return Boolean(packageName && !isBuiltin(specifier));
|
|
1259
1274
|
}
|
|
1260
1275
|
|
|
1261
1276
|
interface BarePackageSpecifier {
|
|
@@ -1319,7 +1334,6 @@ async function readPackageManifestUncached(packageRoot: string): Promise<Record<
|
|
|
1319
1334
|
}
|
|
1320
1335
|
|
|
1321
1336
|
type ExtensionModuleKind = "commonjs" | "esm";
|
|
1322
|
-
class ExtensionModuleKindConflictError extends Error {}
|
|
1323
1337
|
|
|
1324
1338
|
async function isCommonJsModulePath(
|
|
1325
1339
|
modulePath: string,
|
|
@@ -1440,7 +1454,7 @@ async function resolveNodePackageFallback(
|
|
|
1440
1454
|
subpath: string | null,
|
|
1441
1455
|
manifest: Record<string, unknown>,
|
|
1442
1456
|
): Promise<string | null> {
|
|
1443
|
-
if (subpath
|
|
1457
|
+
if (subpath) {
|
|
1444
1458
|
return resolvePackageSourceTarget(packageRoot, path.join(packageRoot, subpath));
|
|
1445
1459
|
}
|
|
1446
1460
|
for (const field of ["module", "main"]) {
|
|
@@ -1476,7 +1490,7 @@ async function resolveNodePackageRequire(specifier: string, importerPath: string
|
|
|
1476
1490
|
if (Object.hasOwn(manifest, "exports")) {
|
|
1477
1491
|
return resolveNodePackageExport(packageRoot, parsed.subpath, manifest, SUPPORTED_PACKAGE_REQUIRE_CONDITIONS);
|
|
1478
1492
|
}
|
|
1479
|
-
if (parsed.subpath
|
|
1493
|
+
if (parsed.subpath) {
|
|
1480
1494
|
return resolvePackageSourceTarget(packageRoot, path.join(packageRoot, parsed.subpath));
|
|
1481
1495
|
}
|
|
1482
1496
|
const main = manifest.main;
|
|
@@ -1638,6 +1652,9 @@ async function resolveExtensionBareRequire(specifier: string, importerPath: stri
|
|
|
1638
1652
|
}
|
|
1639
1653
|
|
|
1640
1654
|
async function resolveExtensionCommonJsRequire(specifier: string, importerPath: string): Promise<string | null> {
|
|
1655
|
+
if (specifier.startsWith(".")) {
|
|
1656
|
+
return resolveRelativeCommonJsRequire(specifier, importerPath);
|
|
1657
|
+
}
|
|
1641
1658
|
const remappedSpecifier = remapLegacyPiSpecifier(specifier);
|
|
1642
1659
|
if (remappedSpecifier) {
|
|
1643
1660
|
try {
|
|
@@ -1757,6 +1774,7 @@ const extensionGraphCacheBustResolvedImportModules = new Map<string, Set<string>
|
|
|
1757
1774
|
const commonJsModuleSources = new Map<string, string>();
|
|
1758
1775
|
const commonJsFallbackModulePaths = new Map<string, string>();
|
|
1759
1776
|
const extensionSynchronousSpecifierTargets = new Map<string, Map<string, string>>();
|
|
1777
|
+
const synchronousModuleSources = new Map<string, string>();
|
|
1760
1778
|
const commonJsGraphModulePaths = new Set<string>();
|
|
1761
1779
|
const COMMONJS_REQUIRE_GLOBAL = "__ompLegacyPiRequireGraphModule";
|
|
1762
1780
|
const commonJsModuleDefinitions = new Map<string, { source: string; filename: string; dirname: string }>();
|
|
@@ -1886,6 +1904,7 @@ interface ExtensionModuleGraph {
|
|
|
1886
1904
|
readonly modules: Map<string, string>;
|
|
1887
1905
|
readonly cacheBustResolvedImportModules: Set<string>;
|
|
1888
1906
|
readonly commonJsPaths: Set<string>;
|
|
1907
|
+
readonly synchronousSourcePaths: Set<string>;
|
|
1889
1908
|
}
|
|
1890
1909
|
|
|
1891
1910
|
/**
|
|
@@ -1901,6 +1920,7 @@ interface ExtensionModuleGraph {
|
|
|
1901
1920
|
async function collectExtensionModules(entryRealPath: string): Promise<ExtensionModuleGraph> {
|
|
1902
1921
|
const modules = new Map<string, string>();
|
|
1903
1922
|
const commonJsPaths = new Set<string>();
|
|
1923
|
+
const synchronousSourcePaths = new Set<string>();
|
|
1904
1924
|
const queuedCacheBustResolvedImports = new Map<string, boolean>([[entryRealPath, true]]);
|
|
1905
1925
|
const queuedModuleKinds = new Map<string, ExtensionModuleKind>([[entryRealPath, "esm"]]);
|
|
1906
1926
|
const queuedEsmBranchPaths = new Set<string>();
|
|
@@ -1949,10 +1969,14 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
1949
1969
|
let resolvedModuleKind: ExtensionModuleKind | undefined;
|
|
1950
1970
|
let resolvedEsmBranch = false;
|
|
1951
1971
|
let requiresNativeAddonRewrite = false;
|
|
1972
|
+
let requiresSynchronousSourceHook = false;
|
|
1973
|
+
let synchronousSourceUpgraded = false;
|
|
1952
1974
|
const isRequired = reference.kind === "require";
|
|
1953
1975
|
if (specifier.startsWith(".")) {
|
|
1954
|
-
const candidate =
|
|
1955
|
-
|
|
1976
|
+
const candidate = isRequired
|
|
1977
|
+
? await resolveRelativeCommonJsRequire(specifier, file)
|
|
1978
|
+
: Bun.resolveSync(specifier, dir);
|
|
1979
|
+
if (candidate && hasSourceModuleExtension(candidate)) {
|
|
1956
1980
|
const inheritedTargetKind = isRequired
|
|
1957
1981
|
? sourceIsCommonJs
|
|
1958
1982
|
? "commonjs"
|
|
@@ -1966,10 +1990,11 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
1966
1990
|
const isCommonJsDescendant = isRequired && sourceIsCommonJs && targetIsCommonJs;
|
|
1967
1991
|
requiresNativeAddonRewrite =
|
|
1968
1992
|
isRequired && !isCommonJsDescendant && (await moduleRequiresNativeAddon(candidate));
|
|
1969
|
-
if (!isRequired || isCommonJsDescendant || requiresNativeAddonRewrite) {
|
|
1993
|
+
if (!isRequired || isCommonJsDescendant || requiresNativeAddonRewrite || !targetIsCommonJs) {
|
|
1970
1994
|
resolved = await realpathOrSelf(candidate);
|
|
1971
1995
|
resolvedModuleKind = targetIsCommonJs ? "commonjs" : "esm";
|
|
1972
1996
|
resolvedEsmBranch = !targetIsCommonJs && esmBranch;
|
|
1997
|
+
requiresSynchronousSourceHook = isRequired && !targetIsCommonJs;
|
|
1973
1998
|
}
|
|
1974
1999
|
}
|
|
1975
2000
|
} else if (specifier.startsWith("#")) {
|
|
@@ -1988,10 +2013,11 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
1988
2013
|
const isCommonJsDescendant = isRequired && sourceIsCommonJs && targetIsCommonJs;
|
|
1989
2014
|
requiresNativeAddonRewrite =
|
|
1990
2015
|
isRequired && !isCommonJsDescendant && (await moduleRequiresNativeAddon(candidate));
|
|
1991
|
-
if (!isRequired || isCommonJsDescendant || requiresNativeAddonRewrite) {
|
|
2016
|
+
if (!isRequired || isCommonJsDescendant || requiresNativeAddonRewrite || !targetIsCommonJs) {
|
|
1992
2017
|
resolved = candidate;
|
|
1993
2018
|
resolvedModuleKind = targetIsCommonJs ? "commonjs" : "esm";
|
|
1994
2019
|
resolvedEsmBranch = !targetIsCommonJs && esmBranch;
|
|
2020
|
+
requiresSynchronousSourceHook = isRequired && !targetIsCommonJs;
|
|
1995
2021
|
}
|
|
1996
2022
|
}
|
|
1997
2023
|
} else if (
|
|
@@ -2022,6 +2048,9 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
2022
2048
|
: false;
|
|
2023
2049
|
if (isHookableEntry && dependencyEntry && (!isRequired || (sourceIsCommonJs && isCommonJsEntry))) {
|
|
2024
2050
|
resolved = await realpathOrSelf(dependencyEntry);
|
|
2051
|
+
} else if (isHookableEntry && dependencyEntry && isRequired && !isCommonJsEntry) {
|
|
2052
|
+
resolved = await realpathOrSelf(dependencyEntry);
|
|
2053
|
+
requiresSynchronousSourceHook = true;
|
|
2025
2054
|
} else if (isHookableEntry && dependencyEntry && isRequired) {
|
|
2026
2055
|
requiresNativeAddonRewrite = await moduleRequiresNativeAddon(dependencyEntry);
|
|
2027
2056
|
if (requiresNativeAddonRewrite) {
|
|
@@ -2034,26 +2063,37 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
2034
2063
|
}
|
|
2035
2064
|
nextCacheBustResolvedImports = false;
|
|
2036
2065
|
}
|
|
2037
|
-
if (
|
|
2038
|
-
|
|
2066
|
+
if (
|
|
2067
|
+
resolved &&
|
|
2068
|
+
(requiresNativeAddonRewrite ||
|
|
2069
|
+
requiresSynchronousSourceHook ||
|
|
2070
|
+
(synchronousSourcePaths.has(file) && resolvedModuleKind === "esm"))
|
|
2071
|
+
) {
|
|
2072
|
+
synchronousSourceUpgraded = !synchronousSourcePaths.has(resolved);
|
|
2073
|
+
synchronousSourcePaths.add(resolved);
|
|
2039
2074
|
}
|
|
2040
2075
|
if (resolved) {
|
|
2041
2076
|
const queuedCacheBust = queuedCacheBustResolvedImports.get(resolved) ?? false;
|
|
2042
2077
|
const mergedCacheBust = queuedCacheBust || nextCacheBustResolvedImports;
|
|
2043
2078
|
queuedCacheBustResolvedImports.set(resolved, mergedCacheBust);
|
|
2044
2079
|
const queuedModuleKind = queuedModuleKinds.get(resolved);
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2080
|
+
const mergedEsmBranch = queuedEsmBranchPaths.has(resolved) || resolvedEsmBranch;
|
|
2081
|
+
const mergedModuleKind =
|
|
2082
|
+
queuedModuleKind && resolvedModuleKind && queuedModuleKind !== resolvedModuleKind
|
|
2083
|
+
? mergedEsmBranch
|
|
2084
|
+
? "esm"
|
|
2085
|
+
: "commonjs"
|
|
2086
|
+
: (queuedModuleKind ?? resolvedModuleKind);
|
|
2051
2087
|
if (mergedModuleKind) {
|
|
2052
2088
|
queuedModuleKinds.set(resolved, mergedModuleKind);
|
|
2053
2089
|
}
|
|
2054
|
-
if (
|
|
2090
|
+
if (mergedEsmBranch) {
|
|
2055
2091
|
queuedEsmBranchPaths.add(resolved);
|
|
2056
2092
|
}
|
|
2093
|
+
if (modules.has(resolved) && (queuedModuleKind !== mergedModuleKind || synchronousSourceUpgraded)) {
|
|
2094
|
+
modules.delete(resolved);
|
|
2095
|
+
commonJsPaths.delete(resolved);
|
|
2096
|
+
}
|
|
2057
2097
|
if (!modules.has(resolved)) {
|
|
2058
2098
|
queue.push({
|
|
2059
2099
|
file: resolved,
|
|
@@ -2063,22 +2103,22 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
2063
2103
|
});
|
|
2064
2104
|
}
|
|
2065
2105
|
}
|
|
2066
|
-
} catch
|
|
2067
|
-
if (error instanceof ExtensionModuleKindConflictError) {
|
|
2068
|
-
throw error;
|
|
2069
|
-
}
|
|
2106
|
+
} catch {
|
|
2070
2107
|
// Unresolvable import (e.g. a type-only path); skip it.
|
|
2071
2108
|
}
|
|
2072
2109
|
}
|
|
2073
2110
|
}
|
|
2074
2111
|
for (const [modulePath, source] of modules) {
|
|
2075
|
-
if (commonJsPaths.has(modulePath)
|
|
2076
|
-
modules.set(modulePath, await rewriteExtensionSpecifiers(source, modulePath,
|
|
2112
|
+
if (commonJsPaths.has(modulePath)) {
|
|
2113
|
+
modules.set(modulePath, await rewriteExtensionSpecifiers(source, modulePath, true));
|
|
2114
|
+
} else if (synchronousSourcePaths.has(modulePath)) {
|
|
2115
|
+
modules.set(modulePath, await rewriteLegacyExtensionSource(source, modulePath));
|
|
2077
2116
|
}
|
|
2078
2117
|
}
|
|
2079
2118
|
return {
|
|
2080
2119
|
modules,
|
|
2081
2120
|
commonJsPaths,
|
|
2121
|
+
synchronousSourcePaths,
|
|
2082
2122
|
cacheBustResolvedImportModules: new Set(
|
|
2083
2123
|
[...queuedCacheBustResolvedImports]
|
|
2084
2124
|
.filter(([modulePath, enabled]) => enabled && modules.has(modulePath))
|
|
@@ -2087,6 +2127,15 @@ async function collectExtensionModules(entryRealPath: string): Promise<Extension
|
|
|
2087
2127
|
};
|
|
2088
2128
|
}
|
|
2089
2129
|
|
|
2130
|
+
/** Test seam for compiled-binary dependency graph discovery and rewriting. */
|
|
2131
|
+
export async function __collectLegacyPiExtensionSourcesForTests(
|
|
2132
|
+
entryPath: string,
|
|
2133
|
+
): Promise<ReadonlyMap<string, string>> {
|
|
2134
|
+
const entryRealPath = await realpathOrSelf(path.resolve(entryPath));
|
|
2135
|
+
const graph = await collectExtensionModules(entryRealPath);
|
|
2136
|
+
return graph.modules;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2090
2139
|
/**
|
|
2091
2140
|
* Discovers CommonJS export names Bun normally exposes to ESM importers. The
|
|
2092
2141
|
* bridge must declare them statically because its default export is synthetic.
|
|
@@ -2252,19 +2301,15 @@ async function installExtensionGraphHook(
|
|
|
2252
2301
|
entryRealPath: string,
|
|
2253
2302
|
modules: Map<string, string>,
|
|
2254
2303
|
commonJsPaths: Set<string>,
|
|
2304
|
+
synchronousSourcePaths: ReadonlySet<string>,
|
|
2255
2305
|
cacheBustResolvedImportModules: ReadonlySet<string>,
|
|
2256
|
-
): Promise<{ asyncModules: Map<string, string
|
|
2306
|
+
): Promise<{ asyncModules: Map<string, string> }> {
|
|
2257
2307
|
const asyncModules = new Map<string, string>();
|
|
2258
|
-
const syncSourceModules = new Map<string, string>();
|
|
2259
2308
|
for (const [modulePath, source] of modules) {
|
|
2260
|
-
if (commonJsPaths.has(modulePath)) {
|
|
2309
|
+
if (commonJsPaths.has(modulePath) || synchronousSourcePaths.has(modulePath)) {
|
|
2261
2310
|
continue;
|
|
2262
2311
|
}
|
|
2263
|
-
|
|
2264
|
-
syncSourceModules.set(modulePath, source);
|
|
2265
|
-
} else {
|
|
2266
|
-
asyncModules.set(modulePath, source);
|
|
2267
|
-
}
|
|
2312
|
+
asyncModules.set(modulePath, source);
|
|
2268
2313
|
}
|
|
2269
2314
|
|
|
2270
2315
|
if (asyncModules.size > 0) {
|
|
@@ -2274,24 +2319,35 @@ async function installExtensionGraphHook(
|
|
|
2274
2319
|
Bun.plugin({
|
|
2275
2320
|
name: `omp:legacy-pi-ext:${hookId}`,
|
|
2276
2321
|
setup(build) {
|
|
2277
|
-
build.onLoad({ filter, namespace: "file" },
|
|
2322
|
+
build.onLoad({ filter, namespace: "file" }, args => {
|
|
2278
2323
|
const queryIndex = args.path.indexOf("?mtime=");
|
|
2279
2324
|
const sourcePath = queryIndex >= 0 ? args.path.slice(0, queryIndex) : args.path;
|
|
2280
2325
|
const mtimeTag = queryIndex >= 0 ? args.path.slice(queryIndex + "?mtime=".length) : null;
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2326
|
+
// A later reload can upgrade this module to synchronous loading (a
|
|
2327
|
+
// new `require()` edge reaches it) without re-registering hooks:
|
|
2328
|
+
// this filter keeps matching and `require()` rejects async onLoad
|
|
2329
|
+
// results, so serve the pre-rewritten synchronous source inline.
|
|
2330
|
+
// `ensureExtensionGraphHook` refreshes it on every (re)load.
|
|
2331
|
+
const synchronousSource = synchronousModuleSources.get(sourcePath);
|
|
2332
|
+
if (synchronousSource !== undefined) {
|
|
2333
|
+
return { contents: synchronousSource, loader: getLoader(sourcePath) };
|
|
2289
2334
|
}
|
|
2335
|
+
const cached = asyncModules.get(sourcePath);
|
|
2290
2336
|
const resolvedImportMtimeTag = cacheBustResolvedImportModules.has(sourcePath) ? mtimeTag : null;
|
|
2291
|
-
return {
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2337
|
+
return (async () => {
|
|
2338
|
+
let raw: string;
|
|
2339
|
+
if (cached !== undefined) {
|
|
2340
|
+
// consume-once: preserves ?mtime edit-pickup for re-imports
|
|
2341
|
+
asyncModules.delete(sourcePath);
|
|
2342
|
+
raw = cached;
|
|
2343
|
+
} else {
|
|
2344
|
+
raw = await Bun.file(sourcePath).text();
|
|
2345
|
+
}
|
|
2346
|
+
return {
|
|
2347
|
+
contents: await rewriteLegacyExtensionSource(raw, sourcePath, mtimeTag, resolvedImportMtimeTag),
|
|
2348
|
+
loader: getLoader(sourcePath),
|
|
2349
|
+
};
|
|
2350
|
+
})();
|
|
2295
2351
|
});
|
|
2296
2352
|
},
|
|
2297
2353
|
});
|
|
@@ -2319,28 +2375,26 @@ async function installExtensionGraphHook(
|
|
|
2319
2375
|
});
|
|
2320
2376
|
}
|
|
2321
2377
|
|
|
2322
|
-
if (
|
|
2323
|
-
const alternation = [...
|
|
2378
|
+
if (synchronousSourcePaths.size > 0) {
|
|
2379
|
+
const alternation = [...synchronousSourcePaths].map(escapeRegExp).join("|");
|
|
2324
2380
|
const filter = new RegExp(`^(?:${alternation})(?:\\?mtime=\\d+)?$`);
|
|
2325
|
-
const hookId = Bun.hash(`${entryRealPath}\0sync-source\0${[...
|
|
2326
|
-
36,
|
|
2327
|
-
);
|
|
2381
|
+
const hookId = Bun.hash(`${entryRealPath}\0sync-source\0${[...synchronousSourcePaths].join("\0")}`).toString(36);
|
|
2328
2382
|
Bun.plugin({
|
|
2329
2383
|
name: `omp:legacy-pi-ext:${hookId}`,
|
|
2330
2384
|
setup(build) {
|
|
2331
2385
|
build.onLoad({ filter, namespace: "file" }, args => {
|
|
2332
2386
|
const queryIndex = args.path.indexOf("?mtime=");
|
|
2333
2387
|
const sourcePath = queryIndex >= 0 ? args.path.slice(0, queryIndex) : args.path;
|
|
2334
|
-
const source =
|
|
2388
|
+
const source = synchronousModuleSources.get(sourcePath);
|
|
2335
2389
|
if (source === undefined) {
|
|
2336
|
-
throw new Error(`Missing pre-rewritten
|
|
2390
|
+
throw new Error(`Missing pre-rewritten synchronous extension source: ${sourcePath}`);
|
|
2337
2391
|
}
|
|
2338
2392
|
return { contents: source, loader: getLoader(sourcePath) };
|
|
2339
2393
|
});
|
|
2340
2394
|
},
|
|
2341
2395
|
});
|
|
2342
2396
|
}
|
|
2343
|
-
return { asyncModules
|
|
2397
|
+
return { asyncModules };
|
|
2344
2398
|
}
|
|
2345
2399
|
|
|
2346
2400
|
/**
|
|
@@ -2356,6 +2410,7 @@ async function ensureExtensionGraphHook(entryRealPath: string): Promise<{ clear(
|
|
|
2356
2410
|
modules: currentModules,
|
|
2357
2411
|
commonJsPaths,
|
|
2358
2412
|
cacheBustResolvedImportModules: discoveredCacheBustModules,
|
|
2413
|
+
synchronousSourcePaths,
|
|
2359
2414
|
} = await collectExtensionModules(entryRealPath);
|
|
2360
2415
|
let cacheBustResolvedImportModules = extensionGraphCacheBustResolvedImportModules.get(entryRealPath);
|
|
2361
2416
|
if (!cacheBustResolvedImportModules) {
|
|
@@ -2370,6 +2425,15 @@ async function ensureExtensionGraphHook(entryRealPath: string): Promise<{ clear(
|
|
|
2370
2425
|
commonJsModuleSources.set(modulePath, await prepareCommonJsDefaultModule(modulePath, source));
|
|
2371
2426
|
commonJsGraphModulePaths.add(modulePath);
|
|
2372
2427
|
}
|
|
2428
|
+
if (synchronousSourcePaths.has(modulePath)) {
|
|
2429
|
+
synchronousModuleSources.set(modulePath, source);
|
|
2430
|
+
} else if (synchronousModuleSources.has(modulePath)) {
|
|
2431
|
+
// The path lost its require() edges on this walk, but the permanent
|
|
2432
|
+
// hooks installed while it was synchronous still serve it from this
|
|
2433
|
+
// map — keep the pre-rewritten bytes fresh instead of serving the
|
|
2434
|
+
// stale snapshot from the walk that flagged it.
|
|
2435
|
+
synchronousModuleSources.set(modulePath, await rewriteLegacyExtensionSource(source, modulePath));
|
|
2436
|
+
}
|
|
2373
2437
|
}
|
|
2374
2438
|
let hookedModules = extensionGraphHookModules.get(entryRealPath);
|
|
2375
2439
|
if (!hookedModules) {
|
|
@@ -2379,12 +2443,16 @@ async function ensureExtensionGraphHook(entryRealPath: string): Promise<{ clear(
|
|
|
2379
2443
|
|
|
2380
2444
|
const pendingModules = new Map<string, string>();
|
|
2381
2445
|
const pendingCommonJsPaths = new Set<string>();
|
|
2446
|
+
const pendingSynchronousSourcePaths = new Set<string>();
|
|
2382
2447
|
for (const [modulePath, source] of currentModules) {
|
|
2383
2448
|
if (!hookedModules.has(modulePath)) {
|
|
2384
2449
|
pendingModules.set(modulePath, source);
|
|
2385
2450
|
if (commonJsPaths.has(modulePath)) {
|
|
2386
2451
|
pendingCommonJsPaths.add(modulePath);
|
|
2387
2452
|
}
|
|
2453
|
+
if (synchronousSourcePaths.has(modulePath)) {
|
|
2454
|
+
pendingSynchronousSourcePaths.add(modulePath);
|
|
2455
|
+
}
|
|
2388
2456
|
}
|
|
2389
2457
|
}
|
|
2390
2458
|
if (pendingModules.size === 0 && commonJsPaths.size === 0) {
|
|
@@ -2392,12 +2460,12 @@ async function ensureExtensionGraphHook(entryRealPath: string): Promise<{ clear(
|
|
|
2392
2460
|
}
|
|
2393
2461
|
|
|
2394
2462
|
let asyncModules = new Map<string, string>();
|
|
2395
|
-
let syncSourceModules = new Map<string, string>();
|
|
2396
2463
|
if (pendingModules.size > 0) {
|
|
2397
|
-
({ asyncModules
|
|
2464
|
+
({ asyncModules } = await installExtensionGraphHook(
|
|
2398
2465
|
entryRealPath,
|
|
2399
2466
|
pendingModules,
|
|
2400
2467
|
pendingCommonJsPaths,
|
|
2468
|
+
pendingSynchronousSourcePaths,
|
|
2401
2469
|
cacheBustResolvedImportModules,
|
|
2402
2470
|
));
|
|
2403
2471
|
for (const modulePath of pendingModules.keys()) {
|
|
@@ -2407,7 +2475,6 @@ async function ensureExtensionGraphHook(entryRealPath: string): Promise<{ clear(
|
|
|
2407
2475
|
return {
|
|
2408
2476
|
clear() {
|
|
2409
2477
|
asyncModules.clear();
|
|
2410
|
-
syncSourceModules.clear();
|
|
2411
2478
|
for (const modulePath of commonJsPaths) {
|
|
2412
2479
|
commonJsModuleSources.delete(modulePath);
|
|
2413
2480
|
commonJsModuleDefinitions.delete(modulePath);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Registry read/write operations for the marketplace plugin system.
|
|
3
3
|
*
|
|
4
4
|
* Two registries:
|
|
5
|
-
* - marketplaces.json
|
|
5
|
+
* - marketplaces.json at getMarketplacesRegistryPath() — which catalogs the user has added
|
|
6
6
|
* - installed_plugins.json under getPluginsDir() — which plugins are installed
|
|
7
7
|
*
|
|
8
8
|
* Read/write functions accept explicit file paths so callers control the
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
import * as fs from "node:fs/promises";
|
|
16
16
|
import * as path from "node:path";
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { getPluginsDir, isEnoent, logger, tryParseJson } from "@oh-my-pi/pi-utils";
|
|
19
|
+
|
|
20
|
+
export { getMarketplacesRegistryPath } from "@oh-my-pi/pi-utils";
|
|
19
21
|
|
|
20
22
|
import type {
|
|
21
23
|
InstalledPluginEntry,
|
|
@@ -24,12 +26,6 @@ import type {
|
|
|
24
26
|
MarketplacesRegistry,
|
|
25
27
|
} from "./types";
|
|
26
28
|
|
|
27
|
-
// ── Path helpers ─────────────────────────────────────────────────────
|
|
28
|
-
|
|
29
|
-
export function getMarketplacesRegistryPath(): string {
|
|
30
|
-
return path.join(getConfigRootDir(), "marketplaces.json");
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
export function getInstalledPluginsRegistryPath(): string {
|
|
34
30
|
return path.join(getPluginsDir(), "installed_plugins.json");
|
|
35
31
|
}
|
|
@@ -302,6 +302,17 @@ export async function loadSkills(options: LoadSkillsOptions = {}): Promise<LoadS
|
|
|
302
302
|
|
|
303
303
|
const existing = skillMap.get(skill.name);
|
|
304
304
|
if (existing) {
|
|
305
|
+
// A skill name claimed by a DEFAULT-path provider (e.g.
|
|
306
|
+
// ~/.claude/skills/<name>) yields to the explicitly configured
|
|
307
|
+
// skills.customDirectories entry — the user's custom dir is the
|
|
308
|
+
// higher-priority source (issue #7190). Only same-source custom
|
|
309
|
+
// duplicates keep first-wins.
|
|
310
|
+
const isCustomExisting = existing.source.startsWith("custom:");
|
|
311
|
+
if (!isCustomExisting) {
|
|
312
|
+
skillMap.set(skill.name, skill);
|
|
313
|
+
realPathSet.add(resolvedPath);
|
|
314
|
+
continue;
|
|
315
|
+
}
|
|
305
316
|
collisionWarnings.push({
|
|
306
317
|
skillPath: skill.filePath,
|
|
307
318
|
message: `name collision: "${skill.name}" already loaded from ${existing.filePath}, skipping this one`,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as path from "node:path";
|
|
2
|
+
import { postmortem } from "@oh-my-pi/pi-utils";
|
|
2
3
|
import { theme } from "../modes/theme/theme";
|
|
3
4
|
import { expandPath, normalizeLocalScheme } from "../tools/path-utils";
|
|
4
5
|
import type { HookUIContext } from "./hooks/types";
|
|
@@ -115,12 +116,19 @@ function guardedExit(alias: ExitAliasName): (code?: number | string) => never {
|
|
|
115
116
|
|
|
116
117
|
export async function withHostGuard<T>(fn: () => Promise<T>): Promise<T> {
|
|
117
118
|
if (hostGuardDepth === 0) {
|
|
119
|
+
// Stamp each throwing replacement with the native primitive it shadows so
|
|
120
|
+
// host-owned shutdown (postmortem's signal/fatal handlers) can still exit
|
|
121
|
+
// through the real exit even while this guard window is open (#6488).
|
|
118
122
|
hostGuardOriginalProcessExit = process.exit;
|
|
119
|
-
|
|
123
|
+
const processExitGuard = guardedExit("process.exit") as typeof process.exit;
|
|
124
|
+
Reflect.set(processExitGuard, postmortem.NATIVE_PROCESS_EXIT, hostGuardOriginalProcessExit);
|
|
125
|
+
process.exit = processExitGuard;
|
|
120
126
|
|
|
121
127
|
if (typeof process.reallyExit === "function") {
|
|
122
128
|
hostGuardOriginalReallyExit = process.reallyExit;
|
|
123
|
-
|
|
129
|
+
const reallyExitGuard = guardedExit("process.reallyExit") as typeof process.reallyExit;
|
|
130
|
+
Reflect.set(reallyExitGuard, postmortem.NATIVE_PROCESS_EXIT, hostGuardOriginalReallyExit);
|
|
131
|
+
process.reallyExit = reallyExitGuard;
|
|
124
132
|
}
|
|
125
133
|
|
|
126
134
|
const stdin = process.stdin;
|
package/src/launch/broker.ts
CHANGED
|
@@ -1124,7 +1124,7 @@ class DaemonBroker {
|
|
|
1124
1124
|
}
|
|
1125
1125
|
}
|
|
1126
1126
|
|
|
1127
|
-
/** Start the detached
|
|
1127
|
+
/** Start the detached project or global daemon broker selected by the CLI worker host. */
|
|
1128
1128
|
export async function startDaemonBrokerFromEnvironment(): Promise<void> {
|
|
1129
1129
|
const projectDir = process.env[DAEMON_PROJECT_DIR_ENV];
|
|
1130
1130
|
const runtimeDir = process.env[DAEMON_RUNTIME_DIR_ENV];
|
package/src/launch/client.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as fs from "node:fs/promises";
|
|
|
2
2
|
import * as net from "node:net";
|
|
3
3
|
import * as os from "node:os";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import { isEexist, isEisdir, isEnoent, postmortem } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { getGlobalDaemonRuntimeDir, isEexist, isEisdir, isEnoent, postmortem } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import { hostHasInheritableConsole } from "../eval/py/spawn-options";
|
|
7
7
|
import { resolveWorkerSpawnCmd, workerEnvFromParent } from "../subprocess/worker-client";
|
|
8
8
|
import { daemonBrokerEndpoint, daemonRuntimeDir } from "./paths";
|
|
@@ -43,8 +43,9 @@ export interface DaemonBrokerClientOptions {
|
|
|
43
43
|
idleGraceMs?: number;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/** Persistent per-process connection to one project
|
|
46
|
+
/** Persistent per-process connection to one project or global daemon broker. */
|
|
47
47
|
export interface DaemonBrokerClient {
|
|
48
|
+
/** Canonical project directory or synthetic directory identifying a global scope. */
|
|
48
49
|
readonly projectDir: string;
|
|
49
50
|
request(operation: DaemonOperation, signal?: AbortSignal): Promise<DaemonRpcResult>;
|
|
50
51
|
close(): void;
|
|
@@ -299,7 +300,19 @@ class SocketDaemonClient implements DaemonBrokerClient {
|
|
|
299
300
|
const sharedClients = new Map<string, Promise<DaemonBrokerClient>>();
|
|
300
301
|
let cancelExitCleanup: (() => void) | undefined;
|
|
301
302
|
|
|
302
|
-
|
|
303
|
+
function sharedDaemonClient(key: string, create: () => Promise<DaemonBrokerClient>): Promise<DaemonBrokerClient> {
|
|
304
|
+
let pending = sharedClients.get(key);
|
|
305
|
+
if (!pending) {
|
|
306
|
+
pending = create();
|
|
307
|
+
sharedClients.set(key, pending);
|
|
308
|
+
if (!cancelExitCleanup) {
|
|
309
|
+
cancelExitCleanup = postmortem.register("daemon-broker-clients", () => closeDaemonClients());
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return pending;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/** Create an independent socket connection to one daemon broker scope. */
|
|
303
316
|
export async function createDaemonBrokerClient(
|
|
304
317
|
projectDir: string,
|
|
305
318
|
options: DaemonBrokerClientOptions = {},
|
|
@@ -313,18 +326,24 @@ export async function createDaemonBrokerClient(
|
|
|
313
326
|
/** Get the process-shared daemon broker client for one canonical project directory. */
|
|
314
327
|
export async function daemonClientForProject(projectDir: string): Promise<DaemonBrokerClient> {
|
|
315
328
|
const canonical = await canonicalProjectDir(projectDir);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
329
|
+
return sharedDaemonClient(`project:${canonical}`, () => createDaemonBrokerClient(canonical));
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
/** Get the process-shared client that leases one profile-independent, machine-global daemon broker. */
|
|
333
|
+
export async function daemonClientForGlobal(service: string): Promise<DaemonBrokerClient> {
|
|
334
|
+
const runtimeDir = getGlobalDaemonRuntimeDir(service);
|
|
335
|
+
// Canonicalize only after creation so the first caller and later callers
|
|
336
|
+
// derive the same Windows pipe key even when an ancestor is a symlink.
|
|
337
|
+
await fs.mkdir(runtimeDir, { recursive: true, mode: 0o700 });
|
|
338
|
+
const canonical = await fs.realpath(runtimeDir);
|
|
339
|
+
return sharedDaemonClient(`global:${canonical}`, () =>
|
|
340
|
+
createDaemonBrokerClient(canonical, {
|
|
341
|
+
runtimeDir: canonical,
|
|
342
|
+
}),
|
|
343
|
+
);
|
|
325
344
|
}
|
|
326
345
|
|
|
327
|
-
/** Close every project broker connection held by this omp process. */
|
|
346
|
+
/** Close every project and machine-global broker connection held by this omp process. */
|
|
328
347
|
export async function closeDaemonClients(): Promise<void> {
|
|
329
348
|
const pending = [...sharedClients.values()];
|
|
330
349
|
sharedClients.clear();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Quiet daemon-broker ensure helpers shared by broker-owned singleton daemons
|
|
3
|
+
* (shared Chromium, browser relay, LSP mux). Each treats broker/daemon errors
|
|
4
|
+
* as "absent" so ensure loops can retry or adopt a cross-process race winner
|
|
5
|
+
* instead of failing the caller.
|
|
6
|
+
*/
|
|
7
|
+
import { logger } from "@oh-my-pi/pi-utils";
|
|
8
|
+
import { throwIfAborted } from "../tools/tool-errors";
|
|
9
|
+
import type { DaemonBrokerClient } from "./client";
|
|
10
|
+
import type { DaemonSnapshot } from "./protocol";
|
|
11
|
+
|
|
12
|
+
const DEFAULT_READY_TIMEOUT_MS = 30_000;
|
|
13
|
+
const STOP_TIMEOUT_MS = 5_000;
|
|
14
|
+
|
|
15
|
+
/** Snapshot a broker daemon, treating "unknown daemon" and broker errors as absent. */
|
|
16
|
+
export async function describeQuietly(
|
|
17
|
+
client: DaemonBrokerClient,
|
|
18
|
+
name: string,
|
|
19
|
+
label: string,
|
|
20
|
+
signal?: AbortSignal,
|
|
21
|
+
): Promise<DaemonSnapshot | undefined> {
|
|
22
|
+
try {
|
|
23
|
+
const result = await client.request({ op: "describe", name }, signal);
|
|
24
|
+
return result.op === "describe" ? result.daemon : undefined;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
throwIfAborted(signal);
|
|
27
|
+
logger.debug(`${label} describe failed`, {
|
|
28
|
+
name,
|
|
29
|
+
error: error instanceof Error ? error.message : String(error),
|
|
30
|
+
});
|
|
31
|
+
return undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** Block until the daemon reports ready; undefined on timeout or pre-ready exit. */
|
|
36
|
+
export async function waitReady(
|
|
37
|
+
client: DaemonBrokerClient,
|
|
38
|
+
name: string,
|
|
39
|
+
label: string,
|
|
40
|
+
signal?: AbortSignal,
|
|
41
|
+
timeoutMs: number = DEFAULT_READY_TIMEOUT_MS,
|
|
42
|
+
): Promise<DaemonSnapshot | undefined> {
|
|
43
|
+
try {
|
|
44
|
+
const result = await client.request({ op: "wait", name, for: "ready", timeoutMs }, signal);
|
|
45
|
+
if (result.op !== "wait" || result.timedOut) return undefined;
|
|
46
|
+
return result.daemon;
|
|
47
|
+
} catch (error) {
|
|
48
|
+
throwIfAborted(signal);
|
|
49
|
+
logger.debug(`${label} ready wait failed`, {
|
|
50
|
+
name,
|
|
51
|
+
error: error instanceof Error ? error.message : String(error),
|
|
52
|
+
});
|
|
53
|
+
return undefined;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Best-effort stop before replacing a wedged or endpoint-less daemon. */
|
|
58
|
+
export async function stopQuietly(
|
|
59
|
+
client: DaemonBrokerClient,
|
|
60
|
+
name: string,
|
|
61
|
+
label: string,
|
|
62
|
+
signal?: AbortSignal,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
try {
|
|
65
|
+
await client.request({ op: "stop", name, timeoutMs: STOP_TIMEOUT_MS }, signal);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
throwIfAborted(signal);
|
|
68
|
+
logger.debug(`${label} stop failed`, {
|
|
69
|
+
name,
|
|
70
|
+
error: error instanceof Error ? error.message : String(error),
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|