@oh-my-pi/pi-coding-agent 17.2.4 → 17.2.6
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 +69 -0
- package/dist/{CHANGELOG-bpmhv26t.md → CHANGELOG-gs76k6wc.md} +69 -0
- package/dist/cli.js +4438 -3962
- package/dist/{template-8vdv6xb4.js → template-c2hyaytt.js} +8 -26
- 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/gc-cli.d.ts +1 -0
- package/dist/types/cli/help-extra.d.ts +2 -0
- 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 +5 -0
- 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 +69 -21
- package/dist/types/cursor-bridge-tools.d.ts +1 -1
- package/dist/types/cursor.d.ts +7 -4
- 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/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/launch/broker.d.ts +1 -1
- package/dist/types/launch/client.d.ts +15 -4
- package/dist/types/launch/ensure.d.ts +8 -0
- package/dist/types/launch/paths.d.ts +1 -1
- package/dist/types/launch/protocol.d.ts +19 -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/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/btw-panel.d.ts +3 -0
- package/dist/types/modes/components/custom-editor.d.ts +2 -1
- package/dist/types/modes/components/read-tool-group.d.ts +2 -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/btw-controller.d.ts +2 -0
- package/dist/types/modes/controllers/command-controller.d.ts +1 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +5 -1
- package/dist/types/modes/types.d.ts +4 -1
- package/dist/types/modes/workflow.d.ts +2 -1
- package/dist/types/sdk.d.ts +3 -1
- package/dist/types/secrets/index.d.ts +1 -1
- package/dist/types/security/contracts/schemas.d.ts +405 -403
- package/dist/types/session/agent-session-types.d.ts +8 -1
- package/dist/types/session/agent-session.d.ts +26 -2
- package/dist/types/session/indexed-session-storage.d.ts +1 -0
- package/dist/types/session/launch-completion.d.ts +10 -0
- package/dist/types/session/session-advisors.d.ts +1 -1
- package/dist/types/session/session-context.d.ts +2 -1
- package/dist/types/session/session-entries.d.ts +15 -1
- package/dist/types/session/session-maintenance.d.ts +1 -0
- package/dist/types/session/session-manager.d.ts +23 -11
- package/dist/types/session/session-stats.d.ts +10 -0
- package/dist/types/session/session-storage.d.ts +15 -3
- package/dist/types/session/yield-queue.d.ts +6 -1
- package/dist/types/system-prompt.d.ts +4 -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/glob.d.ts +1 -1
- package/dist/types/tools/grep.d.ts +1 -1
- package/dist/types/tools/index.d.ts +9 -0
- 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/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/gc-cli.ts +641 -21
- package/src/cli/help-extra.ts +89 -0
- 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/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 +5 -0
- package/src/config/model-discovery.ts +44 -27
- package/src/config/model-registry.ts +19 -13
- 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 +72 -20
- package/src/config/settings.ts +1 -1
- package/src/cursor-bridge-tools.ts +1 -1
- package/src/cursor.ts +10 -14
- 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/index.ts +10 -3
- package/src/export/html/template.js +8 -26
- package/src/export/share.ts +4 -0
- 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/skills.ts +11 -0
- package/src/extensibility/utils.ts +10 -2
- package/src/launch/broker.ts +223 -7
- package/src/launch/client.ts +192 -21
- package/src/launch/ensure.ts +73 -0
- package/src/launch/paths.ts +1 -1
- package/src/launch/protocol.ts +54 -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 +20 -8
- package/src/mcp/config-writer.ts +1 -1
- package/src/mcp/oauth-flow.ts +11 -1
- package/src/mnemopi/embed-client.ts +49 -2
- package/src/mnemopi/state.ts +57 -23
- package/src/modes/components/assistant-message.ts +11 -0
- package/src/modes/components/btw-panel.ts +41 -4
- package/src/modes/components/chat-transcript-builder.ts +4 -0
- package/src/modes/components/custom-editor.ts +9 -0
- package/src/modes/components/read-tool-group.ts +10 -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 +8 -0
- package/src/modes/components/tree-selector.ts +46 -48
- package/src/modes/controllers/btw-controller.ts +55 -7
- package/src/modes/controllers/command-controller.ts +31 -0
- package/src/modes/controllers/event-controller.ts +17 -0
- package/src/modes/controllers/input-controller.ts +63 -8
- package/src/modes/controllers/mcp-command-controller.ts +11 -5
- package/src/modes/controllers/selector-controller.ts +20 -0
- package/src/modes/interactive-mode.ts +18 -2
- package/src/modes/types.ts +9 -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/session/launch-completion.md +1 -0
- 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/sdk.ts +49 -6
- package/src/secrets/index.ts +1 -1
- package/src/security/contracts/schemas.ts +205 -183
- package/src/security/contracts/validation.ts +5 -1
- package/src/security/store.ts +2 -2
- package/src/session/agent-session-types.ts +9 -1
- package/src/session/agent-session.ts +204 -15
- package/src/session/indexed-session-storage.ts +9 -0
- package/src/session/launch-completion.ts +37 -0
- package/src/session/prewalk.ts +24 -2
- package/src/session/session-advisors.ts +2 -2
- package/src/session/session-context.ts +42 -12
- package/src/session/session-dump-format.ts +1 -1
- package/src/session/session-entries.ts +17 -1
- package/src/session/session-maintenance.ts +38 -4
- package/src/session/session-manager.ts +123 -67
- 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/stream-guards.ts +1 -1
- package/src/session/yield-queue.ts +121 -16
- package/src/slash-commands/builtin-registry.ts +37 -24
- package/src/system-prompt.ts +8 -3
- package/src/task/index.ts +23 -8
- package/src/task/spawn-policy.ts +14 -0
- package/src/thinking.ts +2 -8
- package/src/tools/ast-grep.ts +10 -4
- package/src/tools/browser/cmux/cmux-tab.ts +97 -14
- 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/glob.ts +9 -2
- package/src/tools/grep.ts +12 -6
- package/src/tools/hub/launch.ts +122 -6
- package/src/tools/index.ts +9 -0
- 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 +4 -1
- 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
- package/dist/types/config/file-lock.d.ts +0 -29
- package/src/config/file-lock.ts +0 -164
|
@@ -1,25 +1,38 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DesktopCapabilities } from "@oh-my-pi/pi-natives";
|
|
2
2
|
import { withTimeout } from "@oh-my-pi/pi-utils/async";
|
|
3
3
|
import * as logger from "@oh-my-pi/pi-utils/logger";
|
|
4
|
+
import { Snowflake } from "@oh-my-pi/pi-utils/snowflake";
|
|
4
5
|
import { workerHostEntry } from "@oh-my-pi/pi-utils/worker-host";
|
|
6
|
+
import type { ToolSession } from "../index";
|
|
5
7
|
import { ToolAbortError, ToolError } from "../tool-errors";
|
|
6
8
|
import {
|
|
7
9
|
COMPUTER_WORKER_ARG,
|
|
8
|
-
type
|
|
10
|
+
type ComputerRunOk,
|
|
11
|
+
type ComputerSessionSnapshot,
|
|
9
12
|
type ComputerWorkerInbound,
|
|
10
13
|
type ComputerWorkerOutbound,
|
|
14
|
+
type RunErrorPayload,
|
|
11
15
|
} from "./protocol";
|
|
12
16
|
|
|
13
17
|
const START_TIMEOUT_MS = 10_000;
|
|
14
18
|
const CLOSE_TIMEOUT_MS = 1_500;
|
|
19
|
+
const GRACE_MS = 750;
|
|
15
20
|
const SMOKE_TIMEOUT_MS = 5_000;
|
|
21
|
+
const RESTART_MESSAGE = "computer worker restarted; captures and ax refs were reset";
|
|
16
22
|
|
|
23
|
+
/** Runs desktop scripts and owns their persistent worker session. */
|
|
17
24
|
export interface ComputerController {
|
|
18
|
-
|
|
19
|
-
|
|
25
|
+
run(
|
|
26
|
+
code: string,
|
|
27
|
+
timeoutMs: number,
|
|
28
|
+
snapshot: ComputerSessionSnapshot,
|
|
29
|
+
signal?: AbortSignal,
|
|
30
|
+
): Promise<ComputerRunOk>;
|
|
31
|
+
capabilities(): Promise<DesktopCapabilities | undefined>;
|
|
20
32
|
close(): Promise<void>;
|
|
21
33
|
}
|
|
22
34
|
|
|
35
|
+
/** Minimal Bun worker lifecycle surface used by the supervisor. */
|
|
23
36
|
export interface ComputerWorkerHandle {
|
|
24
37
|
send(message: ComputerWorkerInbound): void;
|
|
25
38
|
onMessage(handler: (message: ComputerWorkerOutbound) => void): () => void;
|
|
@@ -27,6 +40,7 @@ export interface ComputerWorkerHandle {
|
|
|
27
40
|
terminate(): Promise<void>;
|
|
28
41
|
}
|
|
29
42
|
|
|
43
|
+
/** Startup and shutdown deadlines for a computer worker. */
|
|
30
44
|
export interface ComputerSupervisorTimeouts {
|
|
31
45
|
startMs: number;
|
|
32
46
|
closeMs: number;
|
|
@@ -36,13 +50,22 @@ const DEFAULT_TIMEOUTS: ComputerSupervisorTimeouts = {
|
|
|
36
50
|
startMs: START_TIMEOUT_MS,
|
|
37
51
|
closeMs: CLOSE_TIMEOUT_MS,
|
|
38
52
|
};
|
|
53
|
+
|
|
54
|
+
/** Dispatches a tool call requested from desktop JavaScript. */
|
|
55
|
+
export type ComputerSessionToolCaller = (
|
|
56
|
+
name: string,
|
|
57
|
+
args: unknown,
|
|
58
|
+
options: { session: ToolSession; signal?: AbortSignal; emitStatus?: () => void },
|
|
59
|
+
) => Promise<unknown>;
|
|
60
|
+
|
|
61
|
+
/** Creates an isolated computer worker handle. */
|
|
39
62
|
export type ComputerWorkerFactory = () => ComputerWorkerHandle;
|
|
40
63
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
64
|
+
interface PendingRun {
|
|
65
|
+
resolve(value: ComputerRunOk): void;
|
|
66
|
+
reject(error: unknown): void;
|
|
67
|
+
signal?: AbortSignal;
|
|
68
|
+
toolCalls: Map<string, AbortController>;
|
|
46
69
|
}
|
|
47
70
|
|
|
48
71
|
function wrapWorker(worker: Worker): ComputerWorkerHandle {
|
|
@@ -56,10 +79,19 @@ function wrapWorker(worker: Worker): ComputerWorkerHandle {
|
|
|
56
79
|
return () => worker.removeEventListener("message", listener);
|
|
57
80
|
},
|
|
58
81
|
onError(handler) {
|
|
59
|
-
const
|
|
82
|
+
const onError = (event: ErrorEvent): void =>
|
|
60
83
|
handler(event.error instanceof Error ? event.error : new Error(event.message));
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
const onMessageError = (event: MessageEvent): void =>
|
|
85
|
+
handler(new Error(`Computer worker message error: ${String(event.data)}`));
|
|
86
|
+
const onClose = (): void => handler(new Error("Computer worker exited"));
|
|
87
|
+
worker.addEventListener("error", onError);
|
|
88
|
+
worker.addEventListener("messageerror", onMessageError);
|
|
89
|
+
worker.addEventListener("close", onClose);
|
|
90
|
+
return () => {
|
|
91
|
+
worker.removeEventListener("error", onError);
|
|
92
|
+
worker.removeEventListener("messageerror", onMessageError);
|
|
93
|
+
worker.removeEventListener("close", onClose);
|
|
94
|
+
};
|
|
63
95
|
},
|
|
64
96
|
async terminate() {
|
|
65
97
|
worker.terminate();
|
|
@@ -67,6 +99,7 @@ function wrapWorker(worker: Worker): ComputerWorkerHandle {
|
|
|
67
99
|
};
|
|
68
100
|
}
|
|
69
101
|
|
|
102
|
+
/** Spawns the computer worker through the active CLI host when available. */
|
|
70
103
|
export function spawnComputerWorker(): ComputerWorkerHandle {
|
|
71
104
|
const hostEntry = workerHostEntry();
|
|
72
105
|
const worker = hostEntry
|
|
@@ -75,133 +108,116 @@ export function spawnComputerWorker(): ComputerWorkerHandle {
|
|
|
75
108
|
return wrapWorker(worker);
|
|
76
109
|
}
|
|
77
110
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
111
|
+
function errorFromPayload(payload: RunErrorPayload): Error {
|
|
112
|
+
const error = payload.isAbort
|
|
113
|
+
? new ToolAbortError(payload.message)
|
|
114
|
+
: payload.isToolError
|
|
115
|
+
? new ToolError(payload.message)
|
|
116
|
+
: new Error(payload.message);
|
|
117
|
+
error.name = payload.name;
|
|
118
|
+
if (payload.stack) error.stack = payload.stack;
|
|
119
|
+
return error;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function toErrorPayload(error: unknown): RunErrorPayload {
|
|
123
|
+
if (error instanceof Error) {
|
|
124
|
+
return {
|
|
125
|
+
name: error.name,
|
|
126
|
+
message: error.message,
|
|
127
|
+
stack: error.stack,
|
|
128
|
+
isAbort: error.name === "AbortError" || error.name === "ToolAbortError",
|
|
129
|
+
isToolError: error instanceof ToolError || error.name === "ToolError",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
return { name: "Error", message: String(error), isAbort: false, isToolError: false };
|
|
81
133
|
}
|
|
82
134
|
|
|
135
|
+
/** Supervises one lazy, crash-isolated computer worker per agent session. */
|
|
83
136
|
export class ComputerSupervisor implements ComputerController {
|
|
137
|
+
readonly #session: ToolSession;
|
|
138
|
+
readonly #createWorker: ComputerWorkerFactory;
|
|
139
|
+
readonly #callSessionTool: ComputerSessionToolCaller;
|
|
140
|
+
readonly #timeouts: ComputerSupervisorTimeouts;
|
|
84
141
|
#worker?: ComputerWorkerHandle;
|
|
85
142
|
#startPromise?: Promise<void>;
|
|
86
|
-
#
|
|
87
|
-
#
|
|
143
|
+
#startReject?: (error: unknown) => void;
|
|
144
|
+
#startResolve?: () => void;
|
|
145
|
+
#latestCapabilities?: DesktopCapabilities;
|
|
146
|
+
#pending = new Map<string, PendingRun>();
|
|
88
147
|
#nextId = 0;
|
|
89
|
-
#serial: Promise<void> = Promise.resolve();
|
|
90
148
|
#closed = false;
|
|
91
149
|
#unsubscribeMessage?: () => void;
|
|
92
150
|
#unsubscribeError?: () => void;
|
|
93
151
|
|
|
94
152
|
constructor(
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
153
|
+
session: ToolSession,
|
|
154
|
+
createWorker: ComputerWorkerFactory = spawnComputerWorker,
|
|
155
|
+
timeouts: ComputerSupervisorTimeouts = DEFAULT_TIMEOUTS,
|
|
156
|
+
callSessionTool: ComputerSessionToolCaller = async () => {
|
|
157
|
+
throw new ToolError("Computer session tool bridge is unavailable");
|
|
158
|
+
},
|
|
159
|
+
) {
|
|
160
|
+
this.#session = session;
|
|
161
|
+
this.#createWorker = createWorker;
|
|
162
|
+
this.#timeouts = timeouts;
|
|
163
|
+
this.#callSessionTool = callSessionTool;
|
|
102
164
|
}
|
|
103
165
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
const run = (): Promise<DesktopCapture> => this.#execute(actions, signal);
|
|
107
|
-
const result = this.#serial.then(run, run);
|
|
108
|
-
this.#serial = result.then(
|
|
109
|
-
() => undefined,
|
|
110
|
-
() => undefined,
|
|
111
|
-
);
|
|
112
|
-
return result;
|
|
166
|
+
async capabilities(): Promise<DesktopCapabilities | undefined> {
|
|
167
|
+
return this.#latestCapabilities;
|
|
113
168
|
}
|
|
114
169
|
|
|
115
|
-
async
|
|
170
|
+
async run(
|
|
171
|
+
code: string,
|
|
172
|
+
timeoutMs: number,
|
|
173
|
+
snapshot: ComputerSessionSnapshot,
|
|
174
|
+
signal?: AbortSignal,
|
|
175
|
+
): Promise<ComputerRunOk> {
|
|
116
176
|
if (this.#closed) throw new ToolError("Computer session is closed");
|
|
117
177
|
if (signal?.aborted) throw new ToolAbortError();
|
|
118
178
|
await this.#start();
|
|
119
179
|
if (signal?.aborted) throw new ToolAbortError();
|
|
180
|
+
|
|
120
181
|
const id = `computer-${++this.#nextId}`;
|
|
121
|
-
const
|
|
122
|
-
|
|
123
|
-
this.#
|
|
124
|
-
|
|
182
|
+
const { promise, resolve, reject } = Promise.withResolvers<ComputerRunOk>();
|
|
183
|
+
const pending: PendingRun = { resolve, reject, signal, toolCalls: new Map() };
|
|
184
|
+
this.#pending.set(id, pending);
|
|
185
|
+
const abort = (): void => {
|
|
186
|
+
this.#safeSend({ type: "abort", id });
|
|
187
|
+
for (const controller of pending.toolCalls.values()) controller.abort(signal?.reason);
|
|
188
|
+
};
|
|
189
|
+
if (signal?.aborted) abort();
|
|
190
|
+
else signal?.addEventListener("abort", abort, { once: true });
|
|
125
191
|
|
|
126
|
-
const aborted = Promise.withResolvers<never>();
|
|
127
|
-
const onAbort = (): void => aborted.reject(new ToolAbortError());
|
|
128
|
-
signal.addEventListener("abort", onAbort, { once: true });
|
|
129
192
|
try {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
if (error instanceof ToolAbortError) await this.#terminate(error);
|
|
133
|
-
throw error;
|
|
193
|
+
this.#worker?.send({ type: "run", id, code, timeoutMs, session: snapshot });
|
|
194
|
+
return await this.#raceWithGrace(promise, timeoutMs);
|
|
134
195
|
} finally {
|
|
135
|
-
signal
|
|
196
|
+
signal?.removeEventListener("abort", abort);
|
|
197
|
+
this.#pending.delete(id);
|
|
136
198
|
}
|
|
137
199
|
}
|
|
138
200
|
|
|
139
201
|
#start(): Promise<void> {
|
|
140
202
|
if (this.#startPromise) return this.#startPromise;
|
|
141
|
-
const
|
|
203
|
+
const started = Promise.withResolvers<void>();
|
|
204
|
+
this.#startReject = started.reject;
|
|
205
|
+
this.#startResolve = started.resolve;
|
|
142
206
|
try {
|
|
143
|
-
logger.debug("Starting
|
|
144
|
-
|
|
145
|
-
display: this.options.display,
|
|
146
|
-
maxWidth: this.options.maxWidth,
|
|
147
|
-
maxHeight: this.options.maxHeight,
|
|
148
|
-
});
|
|
149
|
-
const worker = this.createWorker();
|
|
207
|
+
logger.debug("Starting computer worker");
|
|
208
|
+
const worker = this.#createWorker();
|
|
150
209
|
this.#worker = worker;
|
|
151
|
-
this.#unsubscribeMessage = worker.onMessage(message =>
|
|
152
|
-
if (message.type === "ready") {
|
|
153
|
-
this.#capabilities = message.capabilities;
|
|
154
|
-
logger.debug("Native computer worker ready", {
|
|
155
|
-
backend: message.capabilities.backend,
|
|
156
|
-
capturePermission: message.capabilities.capturePermission,
|
|
157
|
-
inputPermission: message.capabilities.inputPermission,
|
|
158
|
-
displayCount: message.capabilities.displayCount,
|
|
159
|
-
});
|
|
160
|
-
ready.resolve();
|
|
161
|
-
return;
|
|
162
|
-
}
|
|
163
|
-
if (message.type === "result") {
|
|
164
|
-
this.#capabilities = message.capabilities;
|
|
165
|
-
const pending = this.#pending.get(message.id);
|
|
166
|
-
this.#pending.delete(message.id);
|
|
167
|
-
pending?.resolve(message.capture);
|
|
168
|
-
logger.debug("Native computer capture completed", {
|
|
169
|
-
requestId: message.id,
|
|
170
|
-
backend: message.capture.backend,
|
|
171
|
-
capturePermission: message.capture.capturePermission,
|
|
172
|
-
inputPermission: message.capture.inputPermission,
|
|
173
|
-
width: message.capture.width,
|
|
174
|
-
height: message.capture.height,
|
|
175
|
-
});
|
|
176
|
-
return;
|
|
177
|
-
}
|
|
178
|
-
if (message.type === "error") {
|
|
179
|
-
const error = workerError(message.error);
|
|
180
|
-
logger.warn("Native computer worker request failed", {
|
|
181
|
-
requestId: message.id,
|
|
182
|
-
errorName: message.error.name,
|
|
183
|
-
});
|
|
184
|
-
if (message.id) {
|
|
185
|
-
const pending = this.#pending.get(message.id);
|
|
186
|
-
this.#pending.delete(message.id);
|
|
187
|
-
pending?.reject(error);
|
|
188
|
-
} else {
|
|
189
|
-
ready.reject(error);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
});
|
|
210
|
+
this.#unsubscribeMessage = worker.onMessage(message => this.#handleMessage(message));
|
|
193
211
|
this.#unsubscribeError = worker.onError(error => {
|
|
194
|
-
|
|
195
|
-
void this.#terminate(error);
|
|
212
|
+
void this.#workerFailed(error);
|
|
196
213
|
});
|
|
197
|
-
worker.send({ type: "init", options: this.options });
|
|
198
214
|
} catch (error) {
|
|
199
|
-
|
|
215
|
+
started.reject(error);
|
|
200
216
|
}
|
|
201
217
|
this.#startPromise = withTimeout(
|
|
202
|
-
|
|
203
|
-
this
|
|
204
|
-
"Timed out starting
|
|
218
|
+
started.promise,
|
|
219
|
+
this.#timeouts.startMs,
|
|
220
|
+
"Timed out starting computer worker",
|
|
205
221
|
).catch(async error => {
|
|
206
222
|
await this.#terminate(error);
|
|
207
223
|
throw error;
|
|
@@ -209,21 +225,110 @@ export class ComputerSupervisor implements ComputerController {
|
|
|
209
225
|
return this.#startPromise;
|
|
210
226
|
}
|
|
211
227
|
|
|
228
|
+
#handleMessage(message: ComputerWorkerOutbound): void {
|
|
229
|
+
if (message.type === "ready") {
|
|
230
|
+
this.#startResolve?.();
|
|
231
|
+
this.#startResolve = undefined;
|
|
232
|
+
this.#startReject = undefined;
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
if (message.type === "result") {
|
|
236
|
+
const pending = this.#pending.get(message.id);
|
|
237
|
+
if (!pending) return;
|
|
238
|
+
this.#pending.delete(message.id);
|
|
239
|
+
if (message.ok) {
|
|
240
|
+
this.#latestCapabilities = message.payload.capabilities;
|
|
241
|
+
pending.resolve(message.payload);
|
|
242
|
+
} else {
|
|
243
|
+
pending.reject(errorFromPayload(message.error));
|
|
244
|
+
}
|
|
245
|
+
return;
|
|
246
|
+
}
|
|
247
|
+
if (message.type === "tool-call") {
|
|
248
|
+
void this.#dispatchToolCall(message);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
async #dispatchToolCall(message: Extract<ComputerWorkerOutbound, { type: "tool-call" }>): Promise<void> {
|
|
253
|
+
const pending = this.#pending.get(message.runId);
|
|
254
|
+
if (!pending) {
|
|
255
|
+
this.#safeSend({
|
|
256
|
+
type: "tool-reply",
|
|
257
|
+
id: message.id,
|
|
258
|
+
reply: {
|
|
259
|
+
ok: false,
|
|
260
|
+
error: { name: "ToolError", message: "No active run for tool call", isToolError: true, isAbort: false },
|
|
261
|
+
},
|
|
262
|
+
});
|
|
263
|
+
return;
|
|
264
|
+
}
|
|
265
|
+
const controller = new AbortController();
|
|
266
|
+
pending.toolCalls.set(message.id, controller);
|
|
267
|
+
const onParentAbort = (): void => controller.abort(pending.signal?.reason);
|
|
268
|
+
if (pending.signal?.aborted) onParentAbort();
|
|
269
|
+
else pending.signal?.addEventListener("abort", onParentAbort, { once: true });
|
|
270
|
+
try {
|
|
271
|
+
const value = await this.#callSessionTool(message.name, message.args, {
|
|
272
|
+
session: this.#session,
|
|
273
|
+
signal: controller.signal,
|
|
274
|
+
emitStatus: () => {},
|
|
275
|
+
});
|
|
276
|
+
this.#safeSend({ type: "tool-reply", id: message.id, reply: { ok: true, value } });
|
|
277
|
+
} catch (error) {
|
|
278
|
+
this.#safeSend({ type: "tool-reply", id: message.id, reply: { ok: false, error: toErrorPayload(error) } });
|
|
279
|
+
} finally {
|
|
280
|
+
pending.toolCalls.delete(message.id);
|
|
281
|
+
pending.signal?.removeEventListener("abort", onParentAbort);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
#safeSend(message: ComputerWorkerInbound): void {
|
|
286
|
+
try {
|
|
287
|
+
this.#worker?.send(message);
|
|
288
|
+
} catch (error) {
|
|
289
|
+
logger.debug("Computer worker send failed", {
|
|
290
|
+
error: error instanceof Error ? error.message : String(error),
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
async #raceWithGrace(promise: Promise<ComputerRunOk>, timeoutMs: number): Promise<ComputerRunOk> {
|
|
296
|
+
const timeoutSignal = AbortSignal.timeout(timeoutMs + GRACE_MS);
|
|
297
|
+
const timeout = Promise.withResolvers<never>();
|
|
298
|
+
const onTimeout = (): void => timeout.reject(new ToolError(RESTART_MESSAGE));
|
|
299
|
+
timeoutSignal.addEventListener("abort", onTimeout, { once: true });
|
|
300
|
+
try {
|
|
301
|
+
return await Promise.race([promise, timeout.promise]);
|
|
302
|
+
} catch (error) {
|
|
303
|
+
if (error instanceof ToolError && error.message === RESTART_MESSAGE) await this.#terminate(error);
|
|
304
|
+
throw error;
|
|
305
|
+
} finally {
|
|
306
|
+
timeoutSignal.removeEventListener("abort", onTimeout);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
async #workerFailed(error: Error): Promise<void> {
|
|
311
|
+
logger.warn("Computer worker failed", { error: error.message });
|
|
312
|
+
await this.#terminate(error);
|
|
313
|
+
}
|
|
314
|
+
|
|
212
315
|
async #terminate(reason: unknown): Promise<void> {
|
|
213
|
-
logger.debug("Terminating native computer worker", {
|
|
214
|
-
reason: reason instanceof Error ? reason.name : typeof reason,
|
|
215
|
-
});
|
|
216
316
|
const worker = this.#worker;
|
|
217
317
|
this.#worker = undefined;
|
|
218
318
|
this.#startPromise = undefined;
|
|
219
|
-
this.#
|
|
319
|
+
this.#startReject?.(reason);
|
|
320
|
+
this.#startReject = undefined;
|
|
321
|
+
this.#startResolve = undefined;
|
|
220
322
|
this.#unsubscribeMessage?.();
|
|
221
323
|
this.#unsubscribeMessage = undefined;
|
|
222
324
|
this.#unsubscribeError?.();
|
|
223
325
|
this.#unsubscribeError = undefined;
|
|
224
|
-
for (const pending of this.#pending.values())
|
|
326
|
+
for (const pending of this.#pending.values()) {
|
|
327
|
+
for (const controller of pending.toolCalls.values()) controller.abort(reason);
|
|
328
|
+
pending.reject(reason);
|
|
329
|
+
}
|
|
225
330
|
this.#pending.clear();
|
|
226
|
-
await worker?.terminate();
|
|
331
|
+
await worker?.terminate().catch(() => undefined);
|
|
227
332
|
}
|
|
228
333
|
|
|
229
334
|
async close(): Promise<void> {
|
|
@@ -237,7 +342,7 @@ export class ComputerSupervisor implements ComputerController {
|
|
|
237
342
|
});
|
|
238
343
|
try {
|
|
239
344
|
worker.send({ type: "close" });
|
|
240
|
-
await withTimeout(closed.promise, this
|
|
345
|
+
await withTimeout(closed.promise, this.#timeouts.closeMs, "Timed out closing computer worker");
|
|
241
346
|
} catch {
|
|
242
347
|
// Forced termination below is the bounded close fallback.
|
|
243
348
|
} finally {
|
|
@@ -249,6 +354,7 @@ export class ComputerSupervisor implements ComputerController {
|
|
|
249
354
|
|
|
250
355
|
const ownedSupervisors = new Map<string, Set<ComputerController>>();
|
|
251
356
|
|
|
357
|
+
/** Registers a controller for owner-scoped session cleanup. */
|
|
252
358
|
export function registerComputerController(ownerId: string | undefined, controller: ComputerController): () => void {
|
|
253
359
|
if (!ownerId) return () => {};
|
|
254
360
|
const controllers = ownedSupervisors.get(ownerId) ?? new Set<ComputerController>();
|
|
@@ -260,6 +366,7 @@ export function registerComputerController(ownerId: string | undefined, controll
|
|
|
260
366
|
};
|
|
261
367
|
}
|
|
262
368
|
|
|
369
|
+
/** Closes every computer session owned by an agent session. */
|
|
263
370
|
export async function releaseComputerSessionsForOwner(ownerId: string | undefined): Promise<void> {
|
|
264
371
|
if (!ownerId) return;
|
|
265
372
|
const controllers = ownedSupervisors.get(ownerId);
|
|
@@ -268,24 +375,20 @@ export async function releaseComputerSessionsForOwner(ownerId: string | undefine
|
|
|
268
375
|
await Promise.allSettled(Array.from(controllers, controller => controller.close()));
|
|
269
376
|
}
|
|
270
377
|
|
|
378
|
+
/** Verifies computer worker startup, messaging, and bounded shutdown. */
|
|
271
379
|
export async function smokeTestComputerWorker(
|
|
272
380
|
timeoutMs = SMOKE_TIMEOUT_MS,
|
|
273
381
|
createWorker: ComputerWorkerFactory = spawnComputerWorker,
|
|
274
382
|
): Promise<void> {
|
|
275
383
|
const worker = createWorker();
|
|
276
|
-
const
|
|
277
|
-
message: ComputerWorkerInbound,
|
|
278
|
-
expected: ComputerWorkerOutbound["type"],
|
|
279
|
-
failureMessage: string,
|
|
280
|
-
): Promise<void> => {
|
|
384
|
+
const waitFor = async (expected: ComputerWorkerOutbound["type"], failureMessage: string): Promise<void> => {
|
|
281
385
|
const response = Promise.withResolvers<void>();
|
|
282
386
|
const unsubscribeMessage = worker.onMessage(received => {
|
|
283
387
|
if (received.type === expected) response.resolve();
|
|
284
|
-
else if (received.type === "
|
|
388
|
+
else if (received.type === "result" && !received.ok) response.reject(errorFromPayload(received.error));
|
|
285
389
|
});
|
|
286
390
|
const unsubscribeError = worker.onError(error => response.reject(error));
|
|
287
391
|
try {
|
|
288
|
-
worker.send(message);
|
|
289
392
|
await withTimeout(response.promise, timeoutMs, failureMessage);
|
|
290
393
|
} finally {
|
|
291
394
|
unsubscribeMessage();
|
|
@@ -294,12 +397,12 @@ export async function smokeTestComputerWorker(
|
|
|
294
397
|
};
|
|
295
398
|
|
|
296
399
|
try {
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
);
|
|
302
|
-
await
|
|
400
|
+
const pong = waitFor("pong", "Computer worker smoke ping timed out");
|
|
401
|
+
worker.send({ type: "ping", id: `computer-smoke-${Snowflake.next()}` });
|
|
402
|
+
await pong;
|
|
403
|
+
const closed = waitFor("closed", "Computer worker smoke close timed out");
|
|
404
|
+
worker.send({ type: "close" });
|
|
405
|
+
await closed;
|
|
303
406
|
} finally {
|
|
304
407
|
await worker.terminate();
|
|
305
408
|
}
|
|
@@ -3,9 +3,12 @@ import { consumeWorkerInbox, isWorkerHostSelector } from "@oh-my-pi/pi-utils/wor
|
|
|
3
3
|
import type { ComputerWorkerInbound, ComputerWorkerTransport } from "./protocol";
|
|
4
4
|
import { ComputerWorkerCore } from "./worker";
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
if (!parentPort) throw new Error("computer-worker-entry: missing parentPort");
|
|
6
|
+
let started = false;
|
|
8
7
|
|
|
8
|
+
/** Starts the computer worker once when running inside a Bun worker thread. */
|
|
9
|
+
export function startComputerWorker(): void {
|
|
10
|
+
if (started || !parentPort) return;
|
|
11
|
+
started = true;
|
|
9
12
|
const port = parentPort;
|
|
10
13
|
const inbox = consumeWorkerInbox();
|
|
11
14
|
const transport: ComputerWorkerTransport = {
|
|
@@ -26,9 +29,11 @@ export function startComputerWorker(): void {
|
|
|
26
29
|
new ComputerWorkerCore(transport);
|
|
27
30
|
}
|
|
28
31
|
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
|
|
32
|
+
// Direct-source fallback: loaded as a worker's entry module outside a CLI
|
|
33
|
+
// host there is no selector argv, so start immediately. When any CLI-host
|
|
34
|
+
// worker re-enters cli.ts (which imports this module statically), the
|
|
35
|
+
// selector guard defers to the host's dispatch — an unguarded auto-start
|
|
36
|
+
// would hijack the message port of every other worker kind.
|
|
37
|
+
if (!Bun.argv.some(isWorkerHostSelector)) {
|
|
33
38
|
startComputerWorker();
|
|
34
39
|
}
|