@aiworker/web 1.22.0 → 1.23.0
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/README.md +4 -4
- package/bin/cli.js +14 -4
- package/bin/cli.test.js +165 -73
- package/bin/lib/cli-api-target.js +2 -2
- package/bin/lib/cli-args.js +119 -119
- package/bin/lib/cli-lifecycle.js +9 -9
- package/bin/lib/cli-network.js +3 -3
- package/bin/lib/cli-paths.js +3 -3
- package/bin/lib/cli-ports.js +2 -2
- package/bin/lib/cli-process.js +4 -4
- package/bin/lib/cli-startup.js +64 -15
- package/bin/lib/cli-tunnel-profiles.js +1 -1
- package/bin/lib/cli-tunnel-utils.js +2 -2
- package/bin/lib/commands-connect-url.js +19 -19
- package/bin/lib/commands-lifecycle.js +27 -27
- package/bin/lib/commands-logs.js +5 -5
- package/bin/lib/commands-models.js +1 -1
- package/bin/lib/commands-projects.js +1 -1
- package/bin/lib/commands-schedule.js +1 -1
- package/bin/lib/commands-serve.js +29 -29
- package/bin/lib/commands-session.js +1 -1
- package/bin/lib/commands-startup.js +45 -10
- package/bin/lib/commands-status.js +1 -1
- package/bin/lib/commands-tunnel.js +40 -40
- package/bin/lib/commands-update.js +1 -1
- package/bin/lib/commands-update.test.js +6 -6
- package/dist/assets/{CodeMirrorCommentWidgets-B3u7UIcE.js → CodeMirrorCommentWidgets-B1Gizi3a.js} +1 -1
- package/dist/assets/DiffView-DXjVsEOw.js +4 -0
- package/dist/assets/DirtyBranchSwitchDialog-aig6zJjg.js +1 -0
- package/dist/assets/FilesView-CJdG0-wk.js +17 -0
- package/dist/assets/GitView-BXsS3jG6.js +6 -0
- package/dist/assets/{JsonTreeView-B0BdZEHG.js → JsonTreeView-D_hpXBnF.js} +1 -1
- package/dist/assets/LinearIssuesView-BoUiLQG1.js +1 -0
- package/dist/assets/MarkdownImageGallery-B_B_a9KS.js +1 -0
- package/dist/assets/MarkdownRendererImpl-xgyyLiBM.js +12 -0
- package/dist/assets/OnboardingScreen-DIp84OWt.js +1 -0
- package/dist/assets/{PatchDiff-DvfqDql7.js → PatchDiff-8p6nLJaU.js} +1 -1
- package/dist/assets/PierreDiffViewer-DjC8nTk9.js +161 -0
- package/dist/assets/PlanView-CJTmOF6I.js +5 -0
- package/dist/assets/SettingsView-DD-JqIJx.js +28 -0
- package/dist/assets/{SettingsWindow-i45U1Cy1.js → SettingsWindow-Cpb4hM6q.js} +1 -1
- package/dist/assets/SymbolsNerdFontMono-Regular-aK5vsLov.woff2 +0 -0
- package/dist/assets/{ToolOutputDialog-BTwyh5OF.js → ToolOutputDialog-DfaKZXNU.js} +6 -6
- package/dist/assets/ToolPartDiffPreview-DtZLzrSK.js +8 -0
- package/dist/assets/{VirtualizedFileDiff-DD8lDVej.js → VirtualizedFileDiff-C8i9HpTB.js} +1 -1
- package/dist/assets/WalkthroughView-DeKMvZlL.js +4 -0
- package/dist/assets/{computeVirtualFileMetrics-BMIRgMHv.js → computeVirtualFileMetrics-BBI7ZwrC.js} +2 -2
- package/dist/assets/contextPanelEmbeddedChat-BdA6bdky.js +1 -0
- package/dist/assets/de-DCrsQ5zS.js +10 -0
- package/dist/assets/es-Dwv4YfH6.js +16 -0
- package/dist/assets/fr-BCWg4Cnx.js +14 -0
- package/dist/assets/ghostty-vt-DdA0Zryv.wasm +0 -0
- package/dist/assets/index-B68h5S5B.css +1 -0
- package/dist/assets/index-DVwMarHI.js +39 -0
- package/dist/assets/{index-CODwDsU_.js → index-jXSK5RrB.js} +1 -1
- package/dist/assets/{isDiffPlainText-BqayB8d3.js → isDiffPlainText-B_x_rVon.js} +1 -1
- package/dist/assets/{isFilePlainText-QfoiKJNY.js → isFilePlainText-DW_xMer1.js} +1 -1
- package/dist/assets/ja-Bruw3RYC.js +16 -0
- package/dist/assets/ko-idhXGF8j.js +16 -0
- package/dist/assets/main-BkyaQhJX.js +930 -0
- package/dist/assets/{main-C5DVOxc6.js → main-CzdPuL0s.js} +2 -2
- package/dist/assets/markdownCore-Cn4Tyejo.js +5 -0
- package/dist/assets/{miniChat-DUJ4irZc.js → miniChat-CCkqKOLp.js} +2 -2
- package/dist/assets/{mobile-CcaxB0n4.js → mobile-mvxTo055.js} +2 -2
- package/dist/assets/patchFileDiff-Csk4iNUi.js +13 -0
- package/dist/assets/pl-CGZWUqZJ.js +16 -0
- package/dist/assets/pt-BR-B8V7u7tA.js +16 -0
- package/dist/assets/renderElectronMiniChatApp-BxoyujA5.js +2 -0
- package/dist/assets/renderMobileApp-B48CsP4r.js +25 -0
- package/dist/assets/runtimeEndpointReset-Bg5gx18H.js +17 -0
- package/dist/assets/scheduledTasksApi-BW0Etzwz.js +1 -0
- package/dist/assets/{shikiHighlight-DYOWuY65.js → shikiHighlight-CRl0SUC9.js} +1 -1
- package/dist/assets/surface-oMvhsog3.js +1 -0
- package/dist/assets/tr-BK_KiO2V.js +7 -0
- package/dist/assets/uk-CG74xV8N.js +16 -0
- package/dist/assets/useAppFontEffects-CPKeOpUo.js +7284 -0
- package/dist/assets/useGitComparison-DH220WmO.js +1 -0
- package/dist/assets/useInlineCommentController-BiWz4AVb.js +2 -0
- package/dist/assets/useRootScrollLock-BS4-kr7P.js +1 -0
- package/dist/assets/{vendor-base-ui-BeMD8X_w.js → vendor-base-ui-DdV8vhHn.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-data-DFZik9R2.js → vendor-codemirror-language-data-Bg4AEeCr.js} +2 -2
- package/dist/assets/vendor-zod-BPAANqvH.js +39 -0
- package/dist/assets/{web-components-Bhg83tjf.js → web-components-z7hfnS8n.js} +1 -1
- package/dist/assets/zh-CN-T4AXofZI.js +16 -0
- package/dist/assets/zh-TW-Dte40sxp.js +16 -0
- package/dist/index.html +21 -59
- package/dist/mini-chat.html +7 -7
- package/dist/mobile.html +5 -5
- package/package.json +3 -4
- package/server/index.d.ts +15 -0
- package/server/index.js +158 -89
- package/server/lib/agent-memory/actions.js +2 -2
- package/server/lib/agent-memory/feature-flag.js +1 -1
- package/server/lib/agent-memory/feature-flag.test.js +8 -8
- package/server/lib/agent-memory/routes.js +2 -2
- package/server/lib/agent-tool/runtime.js +37 -54
- package/server/lib/agent-tool/runtime.test.js +59 -59
- package/server/lib/browser-control/broker.js +3 -3
- package/server/lib/browser-control/broker.test.js +1 -1
- package/server/lib/changelog/update-notes.js +82 -0
- package/server/lib/changelog/update-notes.test.js +59 -0
- package/server/lib/client-auth/remote-clients.test.js +5 -5
- package/server/lib/context-obligatory/runtime.js +7 -7
- package/server/lib/context-obligatory/runtime.test.js +5 -5
- package/server/lib/data-dir-migration.js +40 -0
- package/server/lib/data-dir-migration.test.js +59 -0
- package/server/lib/dev-servers/parse.js +2 -2
- package/server/lib/dev-servers/parse.test.js +2 -2
- package/server/lib/dev-servers/routes.js +1 -1
- package/server/lib/dev-tunnel/DOCUMENTATION.md +13 -4
- package/server/lib/dev-tunnel/client.js +1 -1
- package/server/lib/dev-tunnel/runtime.js +5 -5
- package/server/lib/dev-tunnel/tunnel.test.js +21 -1
- package/server/lib/dictation/local/model-catalog.js +1 -1
- package/server/lib/dictation/local/worker-process.js +2 -2
- package/server/lib/event-stream/directory-ws-bridge.js +1 -1
- package/server/lib/event-stream/global-ws-bridge.js +1 -1
- package/server/lib/event-stream/protocol.test.js +4 -4
- package/server/lib/event-stream/runtime.test.js +18 -18
- package/server/lib/fs/DOCUMENTATION.md +5 -0
- package/server/lib/fs/routes.js +68 -26
- package/server/lib/fs/routes.test.js +208 -22
- package/server/lib/git/DOCUMENTATION.md +32 -6
- package/server/lib/git/identity-storage.js +1 -1
- package/server/lib/git/issue-2746-longpaths.test.js +4 -4
- package/server/lib/git/routes.js +41 -5
- package/server/lib/git/service.js +300 -224
- package/server/lib/git/service.test.js +596 -28
- package/server/lib/github/auth.js +8 -8
- package/server/lib/github/pr-status.js +1 -1
- package/server/lib/github/routes.js +2 -2
- package/server/lib/inherited-env.js +17 -10
- package/server/lib/inherited-env.test.js +10 -11
- package/server/lib/linear/auth.js +8 -8
- package/server/lib/linear/auth.test.js +24 -24
- package/server/lib/linear/issues.test.js +6 -6
- package/server/lib/linear/mapping.test.js +4 -4
- package/server/lib/linear/oauth.js +2 -2
- package/server/lib/linear/oauth.test.js +14 -14
- package/server/lib/linear/routes.js +5 -5
- package/server/lib/linear/routes.test.js +16 -16
- package/server/lib/linear/status-runtime.test.js +9 -9
- package/server/lib/linear/status.js +1 -1
- package/server/lib/linear/status.test.js +15 -15
- package/server/lib/linear/teams.test.js +4 -4
- package/server/lib/magic-prompts/routes.js +2 -2
- package/server/lib/mcp-reconnect/DOCUMENTATION.md +55 -0
- package/server/lib/mcp-reconnect/runtime.js +122 -0
- package/server/lib/mcp-reconnect/runtime.test.js +140 -0
- package/server/lib/message-queue/DOCUMENTATION.md +161 -0
- package/server/lib/message-queue/runtime.js +870 -0
- package/server/lib/message-queue/runtime.test.js +482 -0
- package/server/lib/network-defaults.js +23 -0
- package/server/lib/network-defaults.test.js +52 -0
- package/server/lib/notifications/apns-runtime.js +17 -17
- package/server/lib/notifications/apns-runtime.test.js +11 -11
- package/server/lib/notifications/emitter-runtime.js +1 -1
- package/server/lib/notifications/emitter-runtime.test.js +1 -1
- package/server/lib/notifications/push-runtime.js +7 -7
- package/server/lib/notifications/routes.js +1 -1
- package/server/lib/notifications/runtime.js +1 -1
- package/server/lib/openchamber-control/action-resolution.test.js +10 -10
- package/server/lib/openchamber-control/actions.js +24 -24
- package/server/lib/openchamber-control/error.js +4 -4
- package/server/lib/openchamber-control/routes.js +2 -2
- package/server/lib/openchamber-control/routes.test.js +5 -5
- package/server/lib/openchamber-control/screenshots.js +1 -1
- package/server/lib/openchamber-control/screenshots.test.js +1 -1
- package/server/lib/openchamber-control/service.js +50 -50
- package/server/lib/openchamber-control/service.test.js +5 -5
- package/server/lib/openchamber-sessions/routes.js +124 -22
- package/server/lib/openchamber-sessions/routes.test.js +99 -11
- package/server/lib/opencode/DOCUMENTATION.md +30 -6
- package/server/lib/opencode/auth.js +1 -1
- package/server/lib/opencode/bootstrap-runtime.js +8 -6
- package/server/lib/opencode/cli-options.js +8 -8
- package/server/lib/opencode/config-paths.test.js +116 -0
- package/server/lib/opencode/core-routes.js +8 -7
- package/server/lib/opencode/core-routes.test.js +11 -11
- package/server/lib/opencode/env-config.js +5 -5
- package/server/lib/opencode/env-config.test.js +7 -7
- package/server/lib/opencode/env-runtime.js +10 -10
- package/server/lib/opencode/env-runtime.test.js +18 -18
- package/server/lib/opencode/feature-routes-runtime.js +19 -12
- package/server/lib/opencode/hmr-state-runtime.js +2 -2
- package/server/lib/opencode/hmr-state-runtime.test.js +1 -1
- package/server/lib/opencode/input-history-scope.js +14 -0
- package/server/lib/opencode/lifecycle.js +8 -8
- package/server/lib/opencode/lifecycle.test.js +4 -4
- package/server/lib/opencode/managed-plugin-config.js +35 -0
- package/server/lib/opencode/managed-process-registry.js +3 -3
- package/server/lib/opencode/mcp-oauth-callback.test.js +2 -2
- package/server/lib/opencode/openchamber-routes.js +79 -19
- package/server/lib/opencode/openchamber-routes.test.js +139 -12
- package/server/lib/opencode/plugins.js +2 -2
- package/server/lib/opencode/plugins.test.js +1 -1
- package/server/lib/opencode/project-icon-routes.js +2 -2
- package/server/lib/opencode/project-icon-routes.test.js +1 -1
- package/server/lib/opencode/providers.js +44 -2
- package/server/lib/opencode/providers.test.js +131 -4
- package/server/lib/opencode/proxy.js +2 -2
- package/server/lib/opencode/pwa-manifest-routes.js +1 -1
- package/server/lib/opencode/restart-session-recovery.test.js +1 -1
- package/server/lib/opencode/routes-upgrade.test.js +4 -4
- package/server/lib/opencode/routes.js +19 -17
- package/server/lib/opencode/server-startup-runtime.js +6 -6
- package/server/lib/opencode/session-runtime.js +3 -3
- package/server/lib/opencode/session-runtime.test.js +6 -6
- package/server/lib/opencode/settings-files.js +214 -0
- package/server/lib/opencode/settings-helpers.js +116 -44
- package/server/lib/opencode/settings-helpers.test.js +354 -12
- package/server/lib/opencode/settings-registry.json +747 -0
- package/server/lib/opencode/settings-runtime.js +141 -20
- package/server/lib/opencode/settings-runtime.test.js +191 -4
- package/server/lib/opencode/shared.js +5 -2
- package/server/lib/opencode/shared.test.js +7 -7
- package/server/lib/opencode/shutdown-runtime.js +2 -0
- package/server/lib/opencode/skill-routes.js +2 -1
- package/server/lib/opencode/snippets.js +1 -2
- package/server/lib/opencode/startup-performance.js +1 -1
- package/server/lib/opencode/startup-performance.test.js +6 -6
- package/server/lib/opencode/static-routes-runtime.js +8 -8
- package/server/lib/opencode/static-routes-runtime.test.js +7 -7
- package/server/lib/opencode/upgrade-capability.js +2 -2
- package/server/lib/opencode/upgrade-capability.test.js +3 -3
- package/server/lib/package-manager.js +17 -42
- package/server/lib/package-manager.test.js +19 -19
- package/server/lib/permission-auto-accept/runtime.js +1 -1
- package/server/lib/project-context/DOCUMENTATION.md +25 -1
- package/server/lib/project-context/routes.http.test.js +18 -0
- package/server/lib/project-context/routes.js +16 -1
- package/server/lib/project-context/runtime.js +248 -23
- package/server/lib/project-context/runtime.test.js +106 -3
- package/server/lib/projects/DOCUMENTATION.md +76 -0
- package/server/lib/projects/project-config.js +144 -11
- package/server/lib/projects/project-id.js +17 -0
- package/server/lib/projects/project-setup.js +409 -0
- package/server/lib/projects/project-setup.test.js +557 -0
- package/server/lib/projects/routes.js +59 -0
- package/server/lib/quota/DOCUMENTATION.md +40 -2
- package/server/lib/quota/credentials/providers.js +4 -0
- package/server/lib/quota/credentials/store.js +4 -4
- package/server/lib/quota/credentials/store.test.js +8 -8
- package/server/lib/quota/index.js +1 -0
- package/server/lib/quota/providers/cline-pass.js +125 -0
- package/server/lib/quota/providers/cline-pass.test.js +103 -0
- package/server/lib/quota/providers/exe-dev.js +75 -0
- package/server/lib/quota/providers/exe-dev.test.js +47 -0
- package/server/lib/quota/providers/hyper.js +118 -0
- package/server/lib/quota/providers/hyper.test.js +126 -0
- package/server/lib/quota/providers/index.js +22 -0
- package/server/lib/quota/providers/neuralwatt.js +3 -6
- package/server/lib/quota/providers/neuralwatt.test.js +7 -7
- package/server/lib/quota/providers/ollama-cloud.js +32 -1
- package/server/lib/quota/providers/ollama-cloud.test.js +33 -1
- package/server/lib/quota/providers/opencode-go.js +3 -2
- package/server/lib/quota/providers/opencode-go.test.js +35 -6
- package/server/lib/quota/providers/openrouter.js +119 -24
- package/server/lib/quota/providers/openrouter.test.js +330 -0
- package/server/lib/quota/providers/xai.js +1 -1
- package/server/lib/quota/routes.js +2 -0
- package/server/lib/quota/utils/auth.js +1 -1
- package/server/lib/relay/DOCUMENTATION.md +56 -1
- package/server/lib/relay/cross-compat.test.js +26 -0
- package/server/lib/relay/downstream-scheduler.js +154 -0
- package/server/lib/relay/downstream-scheduler.test.js +162 -0
- package/server/lib/relay/e2ee.js +10 -8
- package/server/lib/relay/flow-control.test.js +177 -0
- package/server/lib/relay/host-client.js +38 -9
- package/server/lib/relay/host-client.test.js +9 -1
- package/server/lib/relay/host-lock.js +1 -1
- package/server/lib/relay/service.js +5 -5
- package/server/lib/relay/tunnel-codec.js +9 -0
- package/server/lib/relay/tunnel-host.js +69 -18
- package/server/lib/relay/tunnel-host.test.js +9 -1
- package/server/lib/scheduled-tasks/issue-2710-double-execution.test.js +2 -2
- package/server/lib/scheduled-tasks/routes.js +5 -5
- package/server/lib/scheduled-tasks/service.js +25 -25
- package/server/lib/scheduled-tasks/service.test.js +1 -1
- package/server/lib/security/bind-host.js +4 -4
- package/server/lib/security/bind-host.test.js +1 -1
- package/server/lib/security/request-security.js +11 -5
- package/server/lib/security/request-security.test.js +14 -14
- package/server/lib/session-assist/runtime.js +15 -18
- package/server/lib/session-folders/routes.js +2 -2
- package/server/lib/session-folders/routes.test.js +8 -8
- package/server/lib/session-goal/DOCUMENTATION.md +20 -7
- package/server/lib/session-goal/create.js +4 -2
- package/server/lib/session-goal/create.test.js +1 -1
- package/server/lib/session-goal/objectives.js +4 -4
- package/server/lib/session-goal/routes.js +1 -1
- package/server/lib/session-goal/runtime.js +91 -30
- package/server/lib/session-goal/runtime.test.js +428 -2
- package/server/lib/session-knowledge/runtime.js +11 -11
- package/server/lib/session-knowledge/runtime.test.js +5 -5
- package/server/lib/skills-catalog/DOCUMENTATION.md +1 -1
- package/server/lib/skills-catalog/cache.test.js +2 -2
- package/server/lib/skills-catalog/disk-cache.js +5 -5
- package/server/lib/skills-catalog/github-meta.test.js +2 -2
- package/server/lib/skills-catalog/install.js +3 -2
- package/server/lib/small-model/DOCUMENTATION.md +7 -2
- package/server/lib/small-model/call.js +18 -7
- package/server/lib/small-model/call.test.js +58 -6
- package/server/lib/small-model/index.js +12 -16
- package/server/lib/small-model/index.test.js +1 -1
- package/server/lib/small-model/resolve.js +1 -1
- package/server/lib/small-model/resolve.test.js +1 -1
- package/server/lib/small-model/routes.js +2 -1
- package/server/lib/small-model/runtime-providers.js +15 -7
- package/server/lib/small-model/runtime-providers.test.js +7 -1
- package/server/lib/system-prompt/runtime.js +3 -22
- package/server/lib/system-prompt/runtime.test.js +3 -3
- package/server/lib/terminal/DOCUMENTATION.md +14 -10
- package/server/lib/terminal/runtime.js +190 -31
- package/server/lib/terminal/runtime.test.js +572 -38
- package/server/lib/terminal/shells.js +20 -3
- package/server/lib/terminal/shells.test.js +33 -2
- package/server/lib/tts/base-url.js +3 -3
- package/server/lib/tts/routes.test.js +20 -20
- package/server/lib/ui-auth/ui-auth.js +12 -9
- package/server/lib/ui-auth/ui-auth.test.js +19 -3
- package/server/lib/ui-auth/ui-passkeys.js +7 -7
- package/server/lib/walkthrough/DOCUMENTATION.md +33 -14
- package/server/lib/walkthrough/index.js +1 -0
- package/server/lib/walkthrough/jobs.test.js +1 -1
- package/server/lib/walkthrough/language.test.js +1 -1
- package/server/lib/walkthrough/model-settings.js +11 -15
- package/server/lib/walkthrough/model-settings.test.js +1 -1
- package/server/lib/walkthrough/prompt.js +3 -1
- package/server/lib/walkthrough/pull-request.test.js +5 -5
- package/server/lib/walkthrough/reproduce-2607.test.js +2 -2
- package/server/lib/walkthrough/routes.test.js +26 -5
- package/server/lib/walkthrough/sources.js +23 -2
- package/server/lib/walkthrough/store.js +3 -3
- package/server/lib/walkthrough/store.test.js +1 -1
- package/server/opencode-proxy.test.js +2 -2
- package/server/proxy-headers.js +1 -1
- package/server/sse-routes.test.js +4 -4
- package/README.md.bak +0 -250
- package/bin/lib/DOCUMENTATION.md.bak +0 -163
- package/dist/assets/CommitSection-SGBCAW0w.js +0 -1
- package/dist/assets/DiffView-DluiRSla.js +0 -4
- package/dist/assets/FilesView-Bdq8ppva.js +0 -17
- package/dist/assets/GitView-Znn7VJcP.js +0 -6
- package/dist/assets/LinearIssuesView-jP-hXyac.js +0 -1
- package/dist/assets/MarkdownImageGallery-ClOvuZxC.js +0 -1
- package/dist/assets/MarkdownRendererImpl-Dt9mjTRN.js +0 -12
- package/dist/assets/OnboardingScreen-D2DG7K6b.js +0 -1
- package/dist/assets/PierreDiffViewer-B7m3f0d7.js +0 -157
- package/dist/assets/PlanView-B0F3BtPZ.js +0 -5
- package/dist/assets/SettingsView-BBW-S-gh.js +0 -28
- package/dist/assets/ToolPartDiffPreview-CUNe28U1.js +0 -8
- package/dist/assets/WalkthroughView-egQgxel3.js +0 -4
- package/dist/assets/contextPanelEmbeddedChat-C3fjDbdg.js +0 -1
- package/dist/assets/de-C1P6X5Rs.js +0 -9
- package/dist/assets/es-CDgaF1_t.js +0 -15
- package/dist/assets/fr-Bgxqvvz_.js +0 -13
- package/dist/assets/index-C57jT0Sa.css +0 -1
- package/dist/assets/index-DW_E3rnL.js +0 -7
- package/dist/assets/ja-BDRrEcNP.js +0 -15
- package/dist/assets/ko-Ba8sQV79.js +0 -15
- package/dist/assets/main-Bv5Pkngh.js +0 -928
- package/dist/assets/markdownCore-CZwzz5gw.js +0 -3
- package/dist/assets/patchFileDiff-yNfWXN4E.js +0 -10
- package/dist/assets/pl-Dioz29BI.js +0 -15
- package/dist/assets/pt-BR-DIs6ElwV.js +0 -15
- package/dist/assets/renderElectronMiniChatApp-BcKLHXKe.js +0 -2
- package/dist/assets/renderMobileApp-D9yQJy0L.js +0 -25
- package/dist/assets/runtimeEndpointReset-CjhvxLH0.js +0 -16
- package/dist/assets/scheduledTasksApi-DLW0mkQK.js +0 -1
- package/dist/assets/tr-DFnMlPxY.js +0 -6
- package/dist/assets/uk-ZrCNjM7Y.js +0 -15
- package/dist/assets/useAppFontEffects-CjrntdL0.js +0 -7310
- package/dist/assets/useInlineCommentController-CDEuSlPH.js +0 -2
- package/dist/assets/useRootScrollLock-BHYPkrLv.js +0 -1
- package/dist/assets/vendor-ghostty-web-CrxinGGH.js +0 -13
- package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
- package/dist/assets/zh-CN-iv_AV4EC.js +0 -15
- package/dist/assets/zh-TW-CzEUk38j.js +0 -15
- package/server/index.d.ts.bak +0 -39
- package/server/lib/agent-tool/DOCUMENTATION.md.bak +0 -119
- package/server/lib/browser-control/DOCUMENTATION.md.bak +0 -50
- package/server/lib/context-obligatory/DOCUMENTATION.md.bak +0 -19
- package/server/lib/dev-tunnel/DOCUMENTATION.md.bak +0 -57
- package/server/lib/dictation/DOCUMENTATION.md.bak +0 -100
- package/server/lib/event-stream/DOCUMENTATION.md.bak +0 -62
- package/server/lib/fs/DOCUMENTATION.md.bak +0 -47
- package/server/lib/git/DOCUMENTATION.md.bak +0 -193
- package/server/lib/github/DOCUMENTATION.md.bak +0 -183
- package/server/lib/linear/DOCUMENTATION.md.bak +0 -97
- package/server/lib/linear/OAUTH-BROKER-HANDOFF.md.bak +0 -91
- package/server/lib/markdown-image-grants/DOCUMENTATION.md.bak +0 -40
- package/server/lib/notifications/APNS.md.bak +0 -135
- package/server/lib/notifications/DOCUMENTATION.md.bak +0 -138
- package/server/lib/openchamber-control/DOCUMENTATION.md.bak +0 -64
- package/server/lib/opencode/DOCUMENTATION.md.bak +0 -431
- package/server/lib/opencode/managed-process-registry.d.ts.bak +0 -13
- package/server/lib/opencode/provider-env-aliases.d.ts.bak +0 -3
- package/server/lib/permission-auto-accept/DOCUMENTATION.md.bak +0 -34
- package/server/lib/project-context/DOCUMENTATION.md.bak +0 -160
- package/server/lib/quota/DOCUMENTATION.md.bak +0 -123
- package/server/lib/relay/DOCUMENTATION.md.bak +0 -100
- package/server/lib/scheduled-tasks/DOCUMENTATION.md.bak +0 -182
- package/server/lib/session-assist/DOCUMENTATION.md.bak +0 -66
- package/server/lib/session-goal/DOCUMENTATION.md.bak +0 -213
- package/server/lib/session-knowledge/DOCUMENTATION.md.bak +0 -89
- package/server/lib/skills-catalog/DOCUMENTATION.md.bak +0 -151
- package/server/lib/small-model/DOCUMENTATION.md.bak +0 -212
- package/server/lib/system-prompt/DOCUMENTATION.md.bak +0 -36
- package/server/lib/terminal/DOCUMENTATION.md.bak +0 -50
- package/server/lib/text/DOCUMENTATION.md.bak +0 -35
- package/server/lib/tts/DOCUMENTATION.md.bak +0 -147
- package/server/lib/tunnels/DOCUMENTATION.md.bak +0 -21
- package/server/lib/ui-auth/DOCUMENTATION.md.bak +0 -44
- package/server/lib/walkthrough/DOCUMENTATION.md.bak +0 -411
|
@@ -9,15 +9,77 @@ import {
|
|
|
9
9
|
} from './terminal-ws-protocol.js';
|
|
10
10
|
import { sanitizeTerminalHistoryChunk } from './history.js';
|
|
11
11
|
import { consumeTerminalThemeQueries, terminalThemeModeReport } from './theme-response.js';
|
|
12
|
-
import {
|
|
13
|
-
import { stripAppImageArgv0Leak,
|
|
12
|
+
import { buildTerminalShellLaunch, createTerminalShellResolver, normalizeTerminalShell } from './shells.js';
|
|
13
|
+
import { stripAppImageArgv0Leak, resolvePosixPtyLaunch } from '../inherited-env.js';
|
|
14
14
|
|
|
15
15
|
const MAX_SESSIONS = 20;
|
|
16
16
|
const MAX_HISTORY_BYTES = 512 * 1024;
|
|
17
17
|
const MAX_INPUT_CHARS = 65_536;
|
|
18
18
|
const IDLE_TIMEOUT_MS = 30 * 60 * 1000;
|
|
19
19
|
const TERMINATION_GRACE_MS = 1000;
|
|
20
|
+
const INTERACTIVE_TERMINAL_MODE = 'interactive';
|
|
21
|
+
const COMMAND_TERMINAL_MODE = 'command';
|
|
22
|
+
// Error code the create/restart routes attach when the requested cwd no longer
|
|
23
|
+
// exists. Mirrored by `TERMINAL_CWD_MISSING_CODE` in packages/ui/src/lib/terminalApi.ts.
|
|
24
|
+
const TERMINAL_CWD_MISSING_CODE = 'TERMINAL_CWD_MISSING';
|
|
25
|
+
const TERMINAL_PURPOSE = Object.freeze({ type: 'terminal' });
|
|
26
|
+
const MAX_PURPOSE_ID_CHARS = 128;
|
|
27
|
+
const OBJECT_TAG = '[object Object]';
|
|
20
28
|
const validateSize = (value, max) => Number.isInteger(value) && value >= 1 && value <= max;
|
|
29
|
+
const isString = (value) => String(value) === value;
|
|
30
|
+
const isObjectRecord = (value) => value != null && !Array.isArray(value) && Object.prototype.toString.call(value) === OBJECT_TAG;
|
|
31
|
+
const normalizeCreateMode = ({ mode, command }) => {
|
|
32
|
+
const normalizedMode = mode == null ? INTERACTIVE_TERMINAL_MODE : mode;
|
|
33
|
+
if (normalizedMode !== INTERACTIVE_TERMINAL_MODE && normalizedMode !== COMMAND_TERMINAL_MODE) throw new Error('Invalid terminal mode');
|
|
34
|
+
if (normalizedMode === INTERACTIVE_TERMINAL_MODE) {
|
|
35
|
+
if (command != null) throw new Error('Interactive terminal create does not accept a command');
|
|
36
|
+
return { mode: INTERACTIVE_TERMINAL_MODE, command: null };
|
|
37
|
+
}
|
|
38
|
+
if (!isString(command) || !command.trim()) throw new Error('Terminal command is required');
|
|
39
|
+
const trimmedCommand = command.trim();
|
|
40
|
+
if (trimmedCommand.length > MAX_INPUT_CHARS) throw new Error('Terminal command exceeds the input limit');
|
|
41
|
+
return { mode: COMMAND_TERMINAL_MODE, command: trimmedCommand };
|
|
42
|
+
};
|
|
43
|
+
const normalizePurposeId = (value, errorMessage) => {
|
|
44
|
+
if (!isString(value) || !value.trim()) throw new Error(errorMessage);
|
|
45
|
+
const normalized = value.trim();
|
|
46
|
+
if (normalized.length > MAX_PURPOSE_ID_CHARS) throw new Error(errorMessage);
|
|
47
|
+
return normalized;
|
|
48
|
+
};
|
|
49
|
+
const normalizeTerminalPurpose = (value) => {
|
|
50
|
+
if (value == null) return TERMINAL_PURPOSE;
|
|
51
|
+
if (!isObjectRecord(value)) throw new Error('Invalid terminal purpose');
|
|
52
|
+
if (value.type === 'terminal') return TERMINAL_PURPOSE;
|
|
53
|
+
if (value.type !== 'project-action') throw new Error('Invalid terminal purpose');
|
|
54
|
+
return {
|
|
55
|
+
type: 'project-action',
|
|
56
|
+
actionId: normalizePurposeId(value.actionId, 'Terminal project action id is required'),
|
|
57
|
+
executionId: normalizePurposeId(value.executionId, 'Terminal execution id is required'),
|
|
58
|
+
};
|
|
59
|
+
};
|
|
60
|
+
const getSessionPurpose = (session) => session.purpose ?? TERMINAL_PURPOSE;
|
|
61
|
+
const isPurposeActionMatch = (left, right) => {
|
|
62
|
+
if (left.type !== right.type) return false;
|
|
63
|
+
return left.type !== 'project-action' || left.actionId === right.actionId;
|
|
64
|
+
};
|
|
65
|
+
const findRunningActionSession = (sessions, resolvedCwd, purpose, path) => {
|
|
66
|
+
if (purpose.type !== 'project-action') return null;
|
|
67
|
+
for (const session of sessions.values()) {
|
|
68
|
+
if (session.status !== 'running') continue;
|
|
69
|
+
if (path.resolve(session.cwd) !== resolvedCwd) continue;
|
|
70
|
+
const sessionPurpose = getSessionPurpose(session);
|
|
71
|
+
if (sessionPurpose.type === 'project-action' && sessionPurpose.actionId === purpose.actionId) return session;
|
|
72
|
+
}
|
|
73
|
+
return null;
|
|
74
|
+
};
|
|
75
|
+
const findPendingActionCreate = (pendingSessionCreates, resolvedCwd, purpose) => {
|
|
76
|
+
if (purpose.type !== 'project-action') return null;
|
|
77
|
+
for (const pending of pendingSessionCreates.values()) {
|
|
78
|
+
if (pending.cancelled || pending.cwd !== resolvedCwd) continue;
|
|
79
|
+
if (pending.purpose?.type === 'project-action' && pending.purpose.actionId === purpose.actionId) return pending;
|
|
80
|
+
}
|
|
81
|
+
return null;
|
|
82
|
+
};
|
|
21
83
|
const trimHistory = (history) => {
|
|
22
84
|
const bytes = Buffer.from(history);
|
|
23
85
|
if (bytes.byteLength <= MAX_HISTORY_BYTES) return history;
|
|
@@ -54,25 +116,26 @@ export function createTerminalRuntime({
|
|
|
54
116
|
return ptyProviderPromise;
|
|
55
117
|
};
|
|
56
118
|
|
|
57
|
-
const spawnPty = async ({ cwd, cols, rows, themeMode, shell, loginShell }) => {
|
|
119
|
+
const spawnPty = async ({ cwd, cols, rows, themeMode, shell, loginShell, mode, command }) => {
|
|
58
120
|
const provider = await getPtyProvider();
|
|
59
121
|
const resolvedShell = await shellResolver.resolve(shell);
|
|
60
122
|
let lastError = null;
|
|
61
123
|
for (const executable of resolvedShell.executables) {
|
|
62
|
-
const args = loginShell ? getTerminalShellLoginArgs(executable) : [];
|
|
63
|
-
if (!args) throw new Error(`Terminal shell "${resolvedShell.id}" does not support login mode`);
|
|
64
124
|
try {
|
|
65
125
|
const env = { ...process.env, PATH: buildAugmentedPath(), TERM: 'xterm-256color', COLORTERM: 'truecolor', COLORFGBG: themeMode === 'light' ? '0;15' : '15;0' };
|
|
66
|
-
// The daemon's IPC fd is closed inside the PTY
|
|
67
|
-
//
|
|
68
|
-
env.NODE_CHANNEL_FD
|
|
126
|
+
// The daemon's IPC fd is closed inside the PTY; an inherited NODE_CHANNEL_FD
|
|
127
|
+
// (even an empty one) makes Node CLIs warn about an unparsable IPC channel.
|
|
128
|
+
delete env.NODE_CHANNEL_FD;
|
|
69
129
|
delete env.BASH_XTRACEFD; delete env.BASH_ENV; delete env.ENV; delete env.ELECTRON_RUN_AS_NODE;
|
|
70
130
|
// AppImage exports ARGV0; zsh would otherwise rewrite argv[0] for every command (#2588).
|
|
71
|
-
// bun-pty also merges the native OS environ, so wrap with `env -u ARGV0` on Linux.
|
|
72
131
|
stripAppImageArgv0Leak(env);
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
132
|
+
const shellLaunch = buildTerminalShellLaunch(executable, { mode, command, loginShell });
|
|
133
|
+
// bun-pty merges the native OS environ back in, so the POSIX launch is
|
|
134
|
+
// wrapped with `env -u` for the variables deleted above.
|
|
135
|
+
const launch = resolvePosixPtyLaunch(shellLaunch.executable, shellLaunch.args);
|
|
136
|
+
const options = { name: 'xterm-256color', cwd, cols, rows, env };
|
|
137
|
+
if (process.platform === 'win32') options.useConpty = true;
|
|
138
|
+
return { process: await provider.spawn(launch.executable, launch.args, options), backend: provider.backend, shell: resolvedShell.id, loginShell };
|
|
76
139
|
} catch (error) { lastError = error; }
|
|
77
140
|
}
|
|
78
141
|
throw lastError ?? new Error('No executable shell found');
|
|
@@ -122,7 +185,12 @@ export function createTerminalRuntime({
|
|
|
122
185
|
|
|
123
186
|
const snapshot = (session) => ({
|
|
124
187
|
t: 'snapshot', v: 3, s: session.id, q: session.sequence, history: session.history,
|
|
188
|
+
// The PTY size the history was drawn for: a client replays history at this
|
|
189
|
+
// size before fitting its own viewport, so shell output wrapped for one
|
|
190
|
+
// width never gets re-laid-out at another.
|
|
191
|
+
cols: session.cols, rows: session.rows,
|
|
125
192
|
status: session.status, exitCode: session.exitCode, signal: session.signal,
|
|
193
|
+
mode: session.mode ?? INTERACTIVE_TERMINAL_MODE, purpose: getSessionPurpose(session),
|
|
126
194
|
runtime, ptyBackend: session.backend,
|
|
127
195
|
});
|
|
128
196
|
|
|
@@ -175,11 +243,18 @@ export function createTerminalRuntime({
|
|
|
175
243
|
ptyProcess.onExit(({ exitCode, signal }) => { session.eventQueue.push({ type: 'exit', process: ptyProcess, exitCode, signal }); drainEvents(session); });
|
|
176
244
|
};
|
|
177
245
|
|
|
246
|
+
// A working directory that no longer exists (a deleted worktree) is the one
|
|
247
|
+
// rejection the client can recover from by moving the session to its
|
|
248
|
+
// project, so the response names it. Every other rejection stays generic.
|
|
249
|
+
const invalidWorkingDirectory = (code) => Object.assign(new Error('Invalid working directory'), code ? { code } : {});
|
|
178
250
|
const validateCwd = async (cwd) => {
|
|
179
251
|
if (typeof cwd !== 'string' || !cwd.trim()) throw new Error('cwd is required');
|
|
180
|
-
|
|
181
|
-
|
|
252
|
+
let stats;
|
|
253
|
+
try { stats = await fs.promises.stat(cwd); }
|
|
254
|
+
catch (error) { throw invalidWorkingDirectory(error?.code === 'ENOENT' || error?.code === 'ENOTDIR' ? TERMINAL_CWD_MISSING_CODE : undefined); }
|
|
255
|
+
if (!stats?.isDirectory()) throw invalidWorkingDirectory();
|
|
182
256
|
};
|
|
257
|
+
const errorBody = (error, fallback) => ({ error: error?.message || fallback, ...(typeof error?.code === 'string' ? { code: error.code } : {}) });
|
|
183
258
|
|
|
184
259
|
const applyAppearance = (session, { themeMode, terminalBackground, terminalForeground }) => {
|
|
185
260
|
const previous = [session.themeMode, session.terminalBackground, session.terminalForeground];
|
|
@@ -192,48 +267,87 @@ export function createTerminalRuntime({
|
|
|
192
267
|
}
|
|
193
268
|
};
|
|
194
269
|
|
|
195
|
-
const startSession = async (session, { cwd, cols, rows, themeMode = 'dark', terminalBackground, terminalForeground, shell, loginShell }, clear = true) => {
|
|
270
|
+
const startSession = async (session, { cwd, cols, rows, themeMode = 'dark', terminalBackground, terminalForeground, shell, loginShell, mode = INTERACTIVE_TERMINAL_MODE, command = null, purpose = TERMINAL_PURPOSE }, clear = true) => {
|
|
196
271
|
await validateCwd(cwd);
|
|
197
|
-
const spawned = await spawnPty({ cwd, cols, rows, themeMode, shell, loginShell });
|
|
272
|
+
const spawned = await spawnPty({ cwd, cols, rows, themeMode, shell, loginShell, mode, command });
|
|
198
273
|
if (clear) { session.history = ''; session.pendingHistoryControlSequence = ''; session.pendingThemeControlSequence = ''; session.themeModeEnabled = false; }
|
|
199
274
|
session.cwd = cwd; session.cols = cols; session.rows = rows; session.process = spawned.process;
|
|
200
275
|
session.backend = spawned.backend; session.shell = spawned.shell; session.loginShell = spawned.loginShell; session.status = 'running'; session.exitCode = null; session.signal = null;
|
|
276
|
+
session.mode = mode; session.command = mode === COMMAND_TERMINAL_MODE ? command : null;
|
|
277
|
+
session.purpose = purpose;
|
|
201
278
|
session.themeMode = themeMode === 'light' ? 'light' : 'dark'; session.terminalBackground = terminalBackground; session.terminalForeground = terminalForeground;
|
|
202
279
|
session.lastActivity = Date.now(); session.eventQueue.length = 0;
|
|
203
280
|
wire(session, spawned.process);
|
|
281
|
+
return spawned.process;
|
|
204
282
|
};
|
|
205
283
|
|
|
206
|
-
const createSession = async ({ sessionId, cwd, cols = 80, rows = 24, themeMode, terminalBackground, terminalForeground, shell = 'auto', loginShell = false }) => {
|
|
284
|
+
const createSession = async ({ sessionId, cwd, cols = 80, rows = 24, themeMode, terminalBackground, terminalForeground, shell = 'auto', loginShell = false, mode, command, purpose }) => {
|
|
207
285
|
if (!validateSize(cols, 1000) || !validateSize(rows, 500)) throw new Error('Invalid terminal dimensions');
|
|
208
286
|
if (typeof loginShell !== 'boolean') throw new Error('Invalid terminal login mode');
|
|
209
287
|
const normalizedShell = normalizeTerminalShell(shell);
|
|
210
288
|
if (!normalizedShell) throw new Error('Invalid terminal shell');
|
|
289
|
+
const launchMode = normalizeCreateMode({ mode, command });
|
|
290
|
+
const normalizedPurpose = normalizeTerminalPurpose(purpose);
|
|
211
291
|
const id = typeof sessionId === 'string' && sessionId.trim() ? sessionId.trim() : randomUUID();
|
|
212
292
|
if (id.length > 128) throw new Error('Invalid terminal session id');
|
|
213
293
|
const existing = sessions.get(id);
|
|
214
294
|
const resolvedCwd = path.resolve(cwd);
|
|
215
295
|
if (existing?.status === 'running') {
|
|
216
296
|
if (path.resolve(existing.cwd) !== resolvedCwd) throw new Error('Terminal session belongs to a different working directory');
|
|
297
|
+
if (!isPurposeActionMatch(getSessionPurpose(existing), normalizedPurpose)) throw new Error('Terminal session is already running with a different purpose');
|
|
298
|
+
if (normalizedPurpose.type === 'project-action') { applyAppearance(existing, { themeMode, terminalBackground, terminalForeground }); return existing; }
|
|
299
|
+
if ((existing.mode ?? INTERACTIVE_TERMINAL_MODE) !== launchMode.mode) throw new Error('Terminal session is already running with a different mode');
|
|
300
|
+
if (launchMode.mode === COMMAND_TERMINAL_MODE && existing.command !== launchMode.command) throw new Error('Terminal session is already running with a different command');
|
|
217
301
|
applyAppearance(existing, { themeMode, terminalBackground, terminalForeground });
|
|
218
302
|
return existing;
|
|
219
303
|
}
|
|
304
|
+
const runningActionSession = findRunningActionSession(sessions, resolvedCwd, normalizedPurpose, path);
|
|
305
|
+
if (runningActionSession) {
|
|
306
|
+
applyAppearance(runningActionSession, { themeMode, terminalBackground, terminalForeground });
|
|
307
|
+
return runningActionSession;
|
|
308
|
+
}
|
|
220
309
|
const pending = pendingSessionCreates.get(id);
|
|
221
310
|
if (pending) {
|
|
222
311
|
if (pending.cwd !== resolvedCwd) throw new Error('Terminal session belongs to a different working directory');
|
|
312
|
+
if (!isPurposeActionMatch(pending.purpose, normalizedPurpose)) throw new Error('Terminal session is already being created with a different purpose');
|
|
313
|
+
if (normalizedPurpose.type === 'project-action') return pending.promise;
|
|
223
314
|
if (pending.shell !== normalizedShell) throw new Error('Terminal session is already being created with a different shell');
|
|
224
315
|
if (pending.loginShell !== loginShell) throw new Error('Terminal session is already being created with a different login mode');
|
|
316
|
+
if (pending.mode !== launchMode.mode) throw new Error('Terminal session is already being created with a different mode');
|
|
317
|
+
if (launchMode.mode === COMMAND_TERMINAL_MODE && pending.command !== launchMode.command) throw new Error('Terminal session is already being created with a different command');
|
|
225
318
|
const session = await pending.promise;
|
|
226
319
|
applyAppearance(session, { themeMode, terminalBackground, terminalForeground });
|
|
227
320
|
return session;
|
|
228
321
|
}
|
|
229
|
-
|
|
322
|
+
const pendingActionCreate = findPendingActionCreate(pendingSessionCreates, resolvedCwd, normalizedPurpose);
|
|
323
|
+
if (pendingActionCreate) {
|
|
324
|
+
const session = await pendingActionCreate.promise;
|
|
325
|
+
applyAppearance(session, { themeMode, terminalBackground, terminalForeground });
|
|
326
|
+
return session;
|
|
327
|
+
}
|
|
328
|
+
const superseded = normalizedPurpose.type === 'project-action'
|
|
329
|
+
? [...sessions.values()].filter((session) => session.id !== id && session.status === 'exited'
|
|
330
|
+
&& path.resolve(session.cwd) === resolvedCwd && isPurposeActionMatch(getSessionPurpose(session), normalizedPurpose))
|
|
331
|
+
: [];
|
|
332
|
+
if (!existing && sessions.size - superseded.length + pendingSessionCreates.size >= MAX_SESSIONS) throw new Error('Maximum terminal sessions reached');
|
|
333
|
+
const pendingEntry = { cwd: resolvedCwd, shell: normalizedShell, loginShell, mode: launchMode.mode, command: launchMode.command, purpose: normalizedPurpose, cancelled: false, promise: null };
|
|
230
334
|
const creation = (async () => {
|
|
231
335
|
const session = existing ?? { id, sequence: 0, history: '', pendingHistoryControlSequence: '', pendingThemeControlSequence: '', eventQueue: [], draining: false, createdAt: Date.now() };
|
|
232
|
-
await startSession(session, { cwd, cols, rows, themeMode, terminalBackground, terminalForeground, shell: normalizedShell, loginShell });
|
|
336
|
+
const ptyProcess = await startSession(session, { cwd, cols, rows, themeMode, terminalBackground, terminalForeground, shell: normalizedShell, loginShell, mode: launchMode.mode, command: launchMode.command, purpose: normalizedPurpose });
|
|
337
|
+
if (pendingEntry.cancelled) {
|
|
338
|
+
session.process = null;
|
|
339
|
+
await terminateProcess(ptyProcess, true);
|
|
340
|
+
throw new Error('Terminal session was closed during creation');
|
|
341
|
+
}
|
|
342
|
+
for (const previous of superseded) {
|
|
343
|
+
if (sessions.get(previous.id) !== previous || previous.status !== 'exited') continue;
|
|
344
|
+
sessions.delete(previous.id);
|
|
345
|
+
closeAttachments(previous.id, 'SUPERSEDED', 'Terminal replaced by a new action run');
|
|
346
|
+
}
|
|
233
347
|
sessions.set(id, session);
|
|
234
348
|
return session;
|
|
235
349
|
})();
|
|
236
|
-
|
|
350
|
+
pendingEntry.promise = creation;
|
|
237
351
|
pendingSessionCreates.set(id, pendingEntry);
|
|
238
352
|
try { return await creation; }
|
|
239
353
|
finally { if (pendingSessionCreates.get(id) === pendingEntry) pendingSessionCreates.delete(id); }
|
|
@@ -276,16 +390,39 @@ export function createTerminalRuntime({
|
|
|
276
390
|
|
|
277
391
|
const upgradeHandler = (req, socket, head) => {
|
|
278
392
|
if (parseRequestPathname(req.url) !== TERMINAL_WS_PATH) return;
|
|
279
|
-
|
|
393
|
+
const accept = () => {
|
|
394
|
+
if (!wsServer) { rejectWebSocketUpgrade(socket, 500, 'Terminal WebSocket unavailable'); return; }
|
|
280
395
|
try {
|
|
281
|
-
if (uiAuthController?.enabled) {
|
|
282
|
-
if (!await uiAuthController.ensureSessionToken(req, null)) { rejectWebSocketUpgrade(socket, 401, 'UI authentication required'); return; }
|
|
283
|
-
if (!await isRequestOriginAllowed(req)) { rejectWebSocketUpgrade(socket, 403, 'Invalid origin'); return; }
|
|
284
|
-
}
|
|
285
|
-
if (!wsServer) { rejectWebSocketUpgrade(socket, 500, 'Terminal WebSocket unavailable'); return; }
|
|
286
396
|
wsServer.handleUpgrade(req, socket, head, (ws) => wsServer.emit('connection', ws, req));
|
|
287
397
|
} catch { rejectWebSocketUpgrade(socket, 500, 'Upgrade failed'); }
|
|
288
|
-
}
|
|
398
|
+
};
|
|
399
|
+
const checkOrigin = () => {
|
|
400
|
+
try {
|
|
401
|
+
const result = isRequestOriginAllowed(req);
|
|
402
|
+
if (!(result instanceof Promise)) {
|
|
403
|
+
if (result) accept();
|
|
404
|
+
else rejectWebSocketUpgrade(socket, 403, 'Invalid origin');
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
void result.then((allowed) => {
|
|
408
|
+
if (allowed) accept();
|
|
409
|
+
else rejectWebSocketUpgrade(socket, 403, 'Invalid origin');
|
|
410
|
+
}).catch(() => rejectWebSocketUpgrade(socket, 500, 'Upgrade failed'));
|
|
411
|
+
} catch { rejectWebSocketUpgrade(socket, 500, 'Upgrade failed'); }
|
|
412
|
+
};
|
|
413
|
+
if (!uiAuthController?.enabled) { accept(); return; }
|
|
414
|
+
try {
|
|
415
|
+
const result = uiAuthController.ensureSessionToken(req, null);
|
|
416
|
+
if (!(result instanceof Promise)) {
|
|
417
|
+
if (result) checkOrigin();
|
|
418
|
+
else rejectWebSocketUpgrade(socket, 401, 'UI authentication required');
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
void result.then((sessionToken) => {
|
|
422
|
+
if (sessionToken) checkOrigin();
|
|
423
|
+
else rejectWebSocketUpgrade(socket, 401, 'UI authentication required');
|
|
424
|
+
}).catch(() => rejectWebSocketUpgrade(socket, 500, 'Upgrade failed'));
|
|
425
|
+
} catch { rejectWebSocketUpgrade(socket, 500, 'Upgrade failed'); }
|
|
289
426
|
};
|
|
290
427
|
server.on('upgrade', upgradeHandler);
|
|
291
428
|
|
|
@@ -308,6 +445,8 @@ export function createTerminalRuntime({
|
|
|
308
445
|
cwd: session.cwd,
|
|
309
446
|
status: session.status,
|
|
310
447
|
createdAt: Number.isInteger(session.createdAt) ? session.createdAt : null,
|
|
448
|
+
mode: session.mode ?? INTERACTIVE_TERMINAL_MODE,
|
|
449
|
+
purpose: getSessionPurpose(session),
|
|
311
450
|
});
|
|
312
451
|
}
|
|
313
452
|
res.json({ sessions: list });
|
|
@@ -326,8 +465,18 @@ export function createTerminalRuntime({
|
|
|
326
465
|
res.json({ touched });
|
|
327
466
|
});
|
|
328
467
|
app.post('/api/terminal/create', async (req, res) => {
|
|
329
|
-
try {
|
|
330
|
-
|
|
468
|
+
try {
|
|
469
|
+
const session = await createSession(req.body ?? {});
|
|
470
|
+
res.json({
|
|
471
|
+
sessionId: session.id,
|
|
472
|
+
cols: session.cols,
|
|
473
|
+
rows: session.rows,
|
|
474
|
+
status: session.status,
|
|
475
|
+
mode: session.mode ?? INTERACTIVE_TERMINAL_MODE,
|
|
476
|
+
purpose: getSessionPurpose(session),
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
catch (error) { res.status(error?.message === 'Maximum terminal sessions reached' ? 429 : 400).json(errorBody(error, 'Failed to create terminal session')); }
|
|
331
480
|
});
|
|
332
481
|
app.post('/api/terminal/:sessionId/resize', (req, res) => {
|
|
333
482
|
const session = sessions.get(req.params.sessionId);
|
|
@@ -346,6 +495,7 @@ export function createTerminalRuntime({
|
|
|
346
495
|
app.post('/api/terminal/:sessionId/restart', async (req, res) => {
|
|
347
496
|
const session = sessions.get(req.params.sessionId);
|
|
348
497
|
if (!session) return res.status(404).json({ error: 'Terminal session not found' });
|
|
498
|
+
if ((session.mode ?? INTERACTIVE_TERMINAL_MODE) === COMMAND_TERMINAL_MODE) return res.status(400).json({ error: 'Command-mode terminal sessions cannot be restarted' });
|
|
349
499
|
const cwd = req.body?.cwd ?? session.cwd;
|
|
350
500
|
const cols = req.body?.cols ?? session.cols;
|
|
351
501
|
const rows = req.body?.rows ?? session.rows;
|
|
@@ -370,12 +520,21 @@ export function createTerminalRuntime({
|
|
|
370
520
|
try {
|
|
371
521
|
await restart;
|
|
372
522
|
res.json({ sessionId: session.id, cols, rows, status: session.status });
|
|
373
|
-
} catch (error) { res.status(400).json(
|
|
523
|
+
} catch (error) { res.status(400).json(errorBody(error, 'Failed to restart terminal')); }
|
|
374
524
|
finally { if (pendingSessionRestarts.get(session.id) === restart) pendingSessionRestarts.delete(session.id); }
|
|
375
525
|
});
|
|
376
526
|
app.delete('/api/terminal/:sessionId', async (req, res) => {
|
|
377
527
|
const session = sessions.get(req.params.sessionId);
|
|
378
|
-
if (!session)
|
|
528
|
+
if (!session) {
|
|
529
|
+
const pending = pendingSessionCreates.get(req.params.sessionId);
|
|
530
|
+
if (!pending) return res.status(404).json({ error: 'Terminal session not found' });
|
|
531
|
+
pending.cancelled = true;
|
|
532
|
+
try { await pending.promise; }
|
|
533
|
+
catch (error) {
|
|
534
|
+
if (error?.message !== 'Terminal session was closed during creation') throw error;
|
|
535
|
+
}
|
|
536
|
+
return res.json({ success: true });
|
|
537
|
+
}
|
|
379
538
|
sessions.delete(session.id);
|
|
380
539
|
closeAttachments(session.id, 'CLOSED', 'Terminal closed');
|
|
381
540
|
await terminateProcess(session.process);
|