@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
|
@@ -5,7 +5,7 @@ import { beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
5
5
|
const createWorktreeMock = vi.fn(async () => ({
|
|
6
6
|
head: 'abc123',
|
|
7
7
|
name: 'side-task',
|
|
8
|
-
branch: '
|
|
8
|
+
branch: 'aiworker/side-task',
|
|
9
9
|
path: '/repo/worktrees/side-task',
|
|
10
10
|
}));
|
|
11
11
|
const getWorktreeBootstrapStatusMock = vi.fn(async () => ({
|
|
@@ -17,6 +17,7 @@ const getWorktreeBootstrapStatusMock = vi.fn(async () => ({
|
|
|
17
17
|
const sessionCreateMock = vi.fn(async () => ({ data: { id: 'ses_123' } }));
|
|
18
18
|
const sessionForkMock = vi.fn(async () => ({ data: { id: 'ses_fork', title: 'Forked session' } }));
|
|
19
19
|
const sessionMessagesMock = vi.fn(async () => ({ data: [] }));
|
|
20
|
+
const sessionUpdateMock = vi.fn(async ({ sessionID }) => ({ data: { id: sessionID, time: { archived: 1 } } }));
|
|
20
21
|
|
|
21
22
|
let existingSessionMessages = [];
|
|
22
23
|
let dispatchedUserMessageSeq = 0;
|
|
@@ -66,10 +67,10 @@ const selectionInputResponse = (url) => {
|
|
|
66
67
|
};
|
|
67
68
|
const sessionCommandMock = vi.fn(async () => ({ data: {} }));
|
|
68
69
|
const commandListMock = vi.fn(async () => ({ data: [] }));
|
|
69
|
-
globalThis.
|
|
70
|
-
globalThis.
|
|
70
|
+
globalThis.__aiworkerCreateWorktreeMock = createWorktreeMock;
|
|
71
|
+
globalThis.__aiworkerGetWorktreeBootstrapStatusMock = getWorktreeBootstrapStatusMock;
|
|
71
72
|
|
|
72
|
-
let
|
|
73
|
+
let registerAiWorkerSessionRoutes;
|
|
73
74
|
|
|
74
75
|
vi.mock('@opencode-ai/sdk/v2', () => ({
|
|
75
76
|
createOpencodeClient: () => ({
|
|
@@ -78,6 +79,7 @@ vi.mock('@opencode-ai/sdk/v2', () => ({
|
|
|
78
79
|
fork: sessionForkMock,
|
|
79
80
|
messages: sessionMessagesMock,
|
|
80
81
|
command: sessionCommandMock,
|
|
82
|
+
update: sessionUpdateMock,
|
|
81
83
|
},
|
|
82
84
|
command: {
|
|
83
85
|
list: commandListMock,
|
|
@@ -86,8 +88,8 @@ vi.mock('@opencode-ai/sdk/v2', () => ({
|
|
|
86
88
|
}));
|
|
87
89
|
|
|
88
90
|
vi.mock('../git/index.js', () => ({
|
|
89
|
-
createWorktree: (...args) => globalThis.
|
|
90
|
-
getWorktreeBootstrapStatus: (...args) => globalThis.
|
|
91
|
+
createWorktree: (...args) => globalThis.__aiworkerCreateWorktreeMock(...args),
|
|
92
|
+
getWorktreeBootstrapStatus: (...args) => globalThis.__aiworkerGetWorktreeBootstrapStatusMock(...args),
|
|
91
93
|
}));
|
|
92
94
|
|
|
93
95
|
const createApp = (overrides = {}, options = {}) => {
|
|
@@ -96,7 +98,7 @@ const createApp = (overrides = {}, options = {}) => {
|
|
|
96
98
|
app.use(express.json());
|
|
97
99
|
}
|
|
98
100
|
const calls = [];
|
|
99
|
-
|
|
101
|
+
registerAiWorkerSessionRoutes(app, {
|
|
100
102
|
readSettingsFromDiskMigrated: async () => ({ projects: [{ id: 'proj_1', path: '/repo/app' }] }),
|
|
101
103
|
sanitizeProjects: (projects) => projects,
|
|
102
104
|
validateDirectoryPath: async (directory) => ({ ok: true, directory }),
|
|
@@ -108,9 +110,9 @@ const createApp = (overrides = {}, options = {}) => {
|
|
|
108
110
|
return { app, calls };
|
|
109
111
|
};
|
|
110
112
|
|
|
111
|
-
describe('
|
|
113
|
+
describe('aiworker session routes', () => {
|
|
112
114
|
beforeAll(async () => {
|
|
113
|
-
({
|
|
115
|
+
({ registerAiWorkerSessionRoutes } = await import('./routes.js'));
|
|
114
116
|
});
|
|
115
117
|
|
|
116
118
|
beforeEach(() => {
|
|
@@ -132,6 +134,92 @@ describe('openchamber session routes', () => {
|
|
|
132
134
|
sessionCommandMock.mockResolvedValue({ data: {} });
|
|
133
135
|
commandListMock.mockReset();
|
|
134
136
|
commandListMock.mockResolvedValue({ data: [] });
|
|
137
|
+
sessionUpdateMock.mockReset();
|
|
138
|
+
sessionUpdateMock.mockImplementation(async ({ sessionID }) => ({ data: { id: sessionID, time: { archived: 1 } } }));
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('archiving a batch of sessions', () => {
|
|
142
|
+
it('archives every id against the resolved directory and returns the archived sessions', async () => {
|
|
143
|
+
const { app } = createApp();
|
|
144
|
+
const response = await request(app)
|
|
145
|
+
.post('/api/openchamber/sessions/archive')
|
|
146
|
+
.send({ directory: '/repo/app', ids: ['ses_a', 'ses_b'], archivedAt: 1700 })
|
|
147
|
+
.expect(200);
|
|
148
|
+
|
|
149
|
+
expect(response.body.directory).toBe('/repo/app');
|
|
150
|
+
expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a', 'ses_b']);
|
|
151
|
+
expect(response.body.failedIds).toEqual([]);
|
|
152
|
+
expect(sessionUpdateMock).toHaveBeenCalledTimes(2);
|
|
153
|
+
expect(sessionUpdateMock).toHaveBeenCalledWith({
|
|
154
|
+
sessionID: 'ses_a',
|
|
155
|
+
directory: '/repo/app',
|
|
156
|
+
time: { archived: 1700 },
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
it('keeps archiving after a failed session and reports it as failed', async () => {
|
|
161
|
+
sessionUpdateMock.mockImplementation(async ({ sessionID }) => {
|
|
162
|
+
if (sessionID === 'ses_b') throw new Error('session.update failed');
|
|
163
|
+
return { data: { id: sessionID } };
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const { app } = createApp();
|
|
167
|
+
const response = await request(app)
|
|
168
|
+
.post('/api/openchamber/sessions/archive')
|
|
169
|
+
.send({ directory: '/repo/app', ids: ['ses_a', 'ses_b', 'ses_c'] })
|
|
170
|
+
.expect(200);
|
|
171
|
+
|
|
172
|
+
expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a', 'ses_c']);
|
|
173
|
+
expect(response.body.failedIds).toEqual(['ses_b']);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('reports a session the server did not confirm as failed instead of archived', async () => {
|
|
177
|
+
sessionUpdateMock.mockImplementation(async ({ sessionID }) => (
|
|
178
|
+
sessionID === 'ses_b' ? { data: null } : { data: { id: sessionID } }
|
|
179
|
+
));
|
|
180
|
+
|
|
181
|
+
const { app } = createApp();
|
|
182
|
+
const response = await request(app)
|
|
183
|
+
.post('/api/openchamber/sessions/archive')
|
|
184
|
+
.send({ directory: '/repo/app', ids: ['ses_a', 'ses_b'] })
|
|
185
|
+
.expect(200);
|
|
186
|
+
|
|
187
|
+
expect(response.body.archived.map((session) => session.id)).toEqual(['ses_a']);
|
|
188
|
+
expect(response.body.failedIds).toEqual(['ses_b']);
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('rejects an empty batch, an oversized batch, and non-string ids', async () => {
|
|
192
|
+
const { app } = createApp();
|
|
193
|
+
|
|
194
|
+
await request(app).post('/api/openchamber/sessions/archive').send({ directory: '/repo/app', ids: [] }).expect(400);
|
|
195
|
+
await request(app)
|
|
196
|
+
.post('/api/openchamber/sessions/archive')
|
|
197
|
+
.send({ directory: '/repo/app', ids: Array.from({ length: 501 }, (_, index) => `ses_${index}`) })
|
|
198
|
+
.expect(400);
|
|
199
|
+
await request(app)
|
|
200
|
+
.post('/api/openchamber/sessions/archive')
|
|
201
|
+
.send({ directory: '/repo/app', ids: ['ses_a', ''] })
|
|
202
|
+
.expect(400);
|
|
203
|
+
await request(app)
|
|
204
|
+
.post('/api/openchamber/sessions/archive')
|
|
205
|
+
.send({ directory: '/repo/app', ids: ['ses_a'], archivedAt: -1 })
|
|
206
|
+
.expect(400);
|
|
207
|
+
|
|
208
|
+
expect(sessionUpdateMock).not.toHaveBeenCalled();
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it('rejects a directory the runtime does not accept', async () => {
|
|
212
|
+
const { app } = createApp({
|
|
213
|
+
validateDirectoryPath: async () => ({ ok: false, error: 'Invalid directory' }),
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
await request(app)
|
|
217
|
+
.post('/api/openchamber/sessions/archive')
|
|
218
|
+
.send({ directory: '/elsewhere', ids: ['ses_a'] })
|
|
219
|
+
.expect(400);
|
|
220
|
+
|
|
221
|
+
expect(sessionUpdateMock).not.toHaveBeenCalled();
|
|
222
|
+
});
|
|
135
223
|
});
|
|
136
224
|
|
|
137
225
|
it('creates a session for a directory', async () => {
|
|
@@ -379,7 +467,7 @@ describe('openchamber session routes', () => {
|
|
|
379
467
|
.post('/api/openchamber/sessions')
|
|
380
468
|
.send({
|
|
381
469
|
directory: '/repo/app',
|
|
382
|
-
worktree: { name: 'side-task', branchName: '
|
|
470
|
+
worktree: { name: 'side-task', branchName: 'aiworker/side-task', startRef: 'main' },
|
|
383
471
|
setUpstream: false,
|
|
384
472
|
prompt: 'Run this',
|
|
385
473
|
model: 'openai/gpt-5.5',
|
|
@@ -389,7 +477,7 @@ describe('openchamber session routes', () => {
|
|
|
389
477
|
expect(createWorktreeMock).toHaveBeenCalledWith('/repo/app', {
|
|
390
478
|
mode: 'new',
|
|
391
479
|
name: 'side-task',
|
|
392
|
-
branchName: '
|
|
480
|
+
branchName: 'aiworker/side-task',
|
|
393
481
|
startRef: 'main',
|
|
394
482
|
setUpstream: false,
|
|
395
483
|
});
|
|
@@ -34,6 +34,8 @@ This module provides OpenCode server integration utilities for the web server ru
|
|
|
34
34
|
- `packages/web/server/lib/opencode/startup-performance.js`: opt-in startup phase diagnostics with fixed labels and numeric metadata allowlists.
|
|
35
35
|
- `packages/web/server/lib/agent-tool/runtime.js`: managed OpenCode custom-tool materialization, environment injection, loopback authentication, and fixed CLI action dispatch.
|
|
36
36
|
- `packages/web/server/lib/system-prompt/runtime.js`: opt-in managed OpenCode system-prompt optimizer materialization and plugin injection.
|
|
37
|
+
- `packages/web/server/lib/mcp-reconnect/runtime.js`: always-on managed OpenCode plugin that reconnects MCP servers OpenCode marked `failed`, with per-server backoff.
|
|
38
|
+
- `packages/web/server/lib/opencode/managed-plugin-config.js`: the one `OPENCODE_CONFIG_CONTENT` merge every managed plugin (agent tools, system prompt optimizer, MCP reconnect) appends itself through.
|
|
37
39
|
- `packages/web/server/lib/opencode/server-utils-runtime.js`: shared server runtime utilities for OpenCode proxy wiring, OpenCode port/readiness helpers, and snapshot fetchers.
|
|
38
40
|
- `packages/web/server/lib/opencode/openchamber-routes.js`: AiWorker update and models metadata route registration.
|
|
39
41
|
- `packages/web/server/lib/opencode/pwa-manifest-routes.js`: PWA manifest route registration with recent-session shortcut resolution and short-lived caching.
|
|
@@ -61,12 +63,12 @@ This module provides OpenCode server integration utilities for the web server ru
|
|
|
61
63
|
|
|
62
64
|
## Public exports (providers.js)
|
|
63
65
|
- `getProviderSources(providerId, workingDirectory)`: Resolves which OpenCode config layers define a provider.
|
|
64
|
-
- `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom
|
|
65
|
-
- `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, http(s) base URL, models, credentials via `env` or `hasStoredAuth`).
|
|
66
|
+
- `upsertProviderConfig(providerId, config, workingDirectory, scope?, options?)`: Validates and writes a custom provider block (`npm`, `name`, `options.baseURL`, `models`, optional `env`/`headers`) into the user/project/custom config layer. The adapter may be OpenAI Chat Completions, OpenAI Responses, or Anthropic Messages. Existing provider, option, and retained-model fields not managed by the form are preserved; omitted models, headers, and env credentials remain explicit removals. Updating a legacy `providers` entry migrates it to the canonical `provider` key. Does not store API keys. Requires `config.env` or `options.hasStoredAuth` (auth already written via OpenCode `auth.set`). Edit flows must pass the provider's effective existing layer (`custom` > `project` > `user`) so updates do not create a global user override.
|
|
67
|
+
- `validateCustomProviderConfig(providerId, config, options?)`: Structural validation for custom provider payloads (id format, adapter allowlist `@ai-sdk/openai-compatible`/`@ai-sdk/openai`/`@ai-sdk/anthropic`, http(s) base URL, models, credentials via `env` or `hasStoredAuth`).
|
|
66
68
|
- `removeProviderConfig(providerId, workingDirectory, scope?)`: Removes a provider block from the selected config layer.
|
|
67
69
|
|
|
68
70
|
## Public exports (shared.js)
|
|
69
|
-
- `OPENCODE_CONFIG_DIR`, `AGENT_DIR`, `COMMAND_DIR`, `SKILL_DIR`, `CONFIG_FILE`: Path constants. `OPENCODE_CONFIG` is resolved at call time for the custom config layer
|
|
71
|
+
- `OPENCODE_CONFIG_DIR`, `AGENT_DIR`, `COMMAND_DIR`, `SKILL_DIR`, `CONFIG_FILE`: Path constants rooted at `$XDG_CONFIG_HOME/opencode` when `XDG_CONFIG_HOME` is non-empty, otherwise `~/.config/opencode`. These constants are evaluated when the module loads; no files are migrated. `OPENCODE_CONFIG` remains a separate explicit config-file path and is resolved at call time for the custom config layer; it does not replace the global config directory.
|
|
70
72
|
- `AGENT_SCOPE`, `COMMAND_SCOPE`, `SKILL_SCOPE`: Scope constants with USER and PROJECT values.
|
|
71
73
|
- `ensureDirs()`: Creates required OpenCode directories.
|
|
72
74
|
- `parseMdFile(filePath)`, `writeMdFile(filePath, frontmatter, body)`: Markdown file operations with YAML frontmatter.
|
|
@@ -130,7 +132,8 @@ The runtime maintains active-session count incrementally from idempotent activit
|
|
|
130
132
|
- `killProcessOnPort(port)`
|
|
131
133
|
|
|
132
134
|
Managed OpenCode launch also merges the environment returned by the agent-tool
|
|
133
|
-
runtime
|
|
135
|
+
runtime, the opt-in system prompt optimizer, and the always-on MCP reconnect
|
|
136
|
+
plugin, each appending its `file://` entry to the previous one's config. PATH and `OPENCODE_SERVER_PASSWORD` remain lifecycle-owned and cannot
|
|
134
137
|
be replaced by injected values. External OpenCode processes receive no
|
|
135
138
|
AiWorker tool injection. Managed launch env strips AppImage `ARGV0` before
|
|
136
139
|
spawn so zsh-backed OpenCode tools do not rewrite child argv[0] to the AppImage
|
|
@@ -208,7 +211,13 @@ Managed health failures are classified as `timeout`, `connection_refused`, `conn
|
|
|
208
211
|
- `writeSettingsToDisk(settings)`
|
|
209
212
|
- `persistSettings(changes)`
|
|
210
213
|
- Persistent permission auto-accept policy is stored under `permissionAutoAccept`; execution ownership lives in `lib/permission-auto-accept/`.
|
|
211
|
-
-
|
|
214
|
+
- Queued follow-up messages live in `<data-dir>/message-queue.json`, not in settings; execution ownership lives in `lib/message-queue/`.
|
|
215
|
+
- Shared sidebar preferences are stored as validated top-level fields: `sidebarProjectDisplayMode`, `sidebarSessionGroupingMode`, `sidebarProjectSortOrder`, and `sidebarShowRecentSection`. Device-local picker selection and sticky-header state do not enter either settings file.
|
|
216
|
+
- Two files (`settings-files.js`): `settings.json` holds instance facts and any legacy or unknown keys; `preferences.json` beside it holds every key the generated registry snapshot (`settings-registry.json`) marks `profile`, as `{ version: 1, fields: { key: { value, updatedAt, surfaces? } } }`. Keys the snapshot marks `perSurface` are stored per surface kind: `GET`/`PUT /api/config/settings` read the client's kind from the `surface` query parameter (`settingsSurfaceOf`; the legacy `x-openchamber-surface` header is still honoured, but a header forces a CORS preflight that cross-origin shells and older instances refuse, so clients must not send one) (`web`, `desktop`, `vscode`, `mobile`; anything else means base), `persistSettings(changes, { surface })` writes a changed per-surface key under `surfaces[surface]` and never touches its base, and `readSettingsFromDisk({ surface })` resolves that kind's value first, the base otherwise. Callers without a surface (migrations, the seed, server-side feature writers) read and write the base. `readSettingsFromDisk()` returns the merged document and seeds `preferences.json` once from an existing `settings.json` (which it leaves intact). An existing `preferences.json` that fails to parse is a failure, not an empty profile: it is never seeded or overwritten, the merged read serves the instance part, and `persistSettings` drops profile keys with a warning until the file is fixed or removed. `writeSettingsToDisk(document)` splits by scope and writes `settings.json` as the instance part plus a copy of the profile's base values (`legacySettingsDocumentOf`): a build from before the split reads only that file, so a rollback keeps the user's preferences, while current builds ignore the copy because `preferences.json` wins in the merge; device keys are dropped from writes. Modules that read one profile key off the disk on a hot path use `readMergedSettingsSync`.
|
|
217
|
+
|
|
218
|
+
## Public exports (settings-files.js)
|
|
219
|
+
- `parsePreferencesDocument(raw)`, `serializePreferencesDocument(fields)`, `flattenPreferences(fields)`, `buildPreferencesFields(previousFields, document, now)`, `instancePartOf(document)`, `seedPreferencesFrom(document, now)`, `readMergedSettingsSync({ fs, path, settingsFilePath })`, `getSettingsScope(key)`, `isProfileSettingsKey(key)`, `isDeviceSettingsKey(key)`, `preferencesFilePathFor(settingsFilePath, path)`.
|
|
220
|
+
- The VS Code extension host writes the same two files with the same shape (`packages/vscode/src/settings-files.ts`); format changes go to both.
|
|
212
221
|
|
|
213
222
|
## Public exports (settings-helpers.js)
|
|
214
223
|
- `createSettingsHelpers(dependencies)`: creates settings helper runtime for settings request/response shaping.
|
|
@@ -359,9 +368,20 @@ before starting managed OpenCode. The managed custom tool therefore receives
|
|
|
359
368
|
an authoritative loopback callback URL even when AiWorker binds port `0`.
|
|
360
369
|
|
|
361
370
|
## Public exports (openchamber-routes.js)
|
|
371
|
+
Browser completion checks use `appType=web&updateStatus=true` to stay on the
|
|
372
|
+
Desktop Host's native updater. A rejected native restart is retained in the
|
|
373
|
+
server process and returned to these polls as `DESKTOP_UPDATE_RESTART_FAILED`;
|
|
374
|
+
ordinary availability checks remain usable so a browser reload can offer a
|
|
375
|
+
retry. Starting another installation clears the previous restart error.
|
|
376
|
+
The shared UI's `lib/web-update.ts` parses install/check responses and waits
|
|
377
|
+
for the installed native target version, rather than treating absence of a
|
|
378
|
+
newer release as installation success. Poll requests have individual deadlines
|
|
379
|
+
within a ten-minute overall deadline.
|
|
380
|
+
|
|
362
381
|
- `registerAiWorkerRoutes(app, dependencies)`: registers AiWorker endpoints:
|
|
363
382
|
- `GET /api/openchamber/update-check`
|
|
364
383
|
- `POST /api/openchamber/update-install`
|
|
384
|
+
- Desktop-managed hosts delegate authenticated Web update requests to the Electron main process, which checks, downloads, and applies the update through `electron-updater` before restarting the host.
|
|
365
385
|
- Foreground servers running under a systemd user unit queue installation in
|
|
366
386
|
a separate transient unit and restart the configured service afterwards.
|
|
367
387
|
`AIWORKER_SYSTEMD_UNIT` overrides the default `aiworker.service`.
|
|
@@ -417,7 +437,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
|
|
|
417
437
|
|
|
418
438
|
## Storage and configuration
|
|
419
439
|
- Provider auth: `~/.local/share/opencode/auth.json`.
|
|
420
|
-
- User config: `~/.config/opencode/opencode.json
|
|
440
|
+
- User config: `$XDG_CONFIG_HOME/opencode/opencode.json`, falling back to `~/.config/opencode/opencode.json` when unset or blank.
|
|
421
441
|
- Project config: `<workingDirectory>/.opencode/opencode.json` or `opencode.json`.
|
|
422
442
|
- Custom config: `OPENCODE_CONFIG` env var path.
|
|
423
443
|
- Rate limit config: `AIWORKER_RATE_LIMIT_MAX_ATTEMPTS`, `AIWORKER_RATE_LIMIT_NO_IP_MAX_ATTEMPTS` env vars.
|
|
@@ -429,3 +449,7 @@ an authoritative loopback callback URL even when AiWorker binds port `0`.
|
|
|
429
449
|
- Config merging follows priority: custom > project > user.
|
|
430
450
|
- UI auth uses scrypt for password hashing with constant-time comparison.
|
|
431
451
|
- Tunnel auth treats `host.docker.internal` as local-only when the socket remote IP is private/loopback.
|
|
452
|
+
|
|
453
|
+
The behavior `GET /api/behavior/agents-md` response includes `path`, the effective
|
|
454
|
+
server-side filename, whether or not the file exists. Settings displays this
|
|
455
|
+
path without deriving a directory from the browser environment.
|
|
@@ -30,7 +30,7 @@ function writeAuthFile(auth) {
|
|
|
30
30
|
if (process.platform !== 'win32') fs.chmodSync(OPENCODE_DATA_DIR, 0o700);
|
|
31
31
|
|
|
32
32
|
if (fs.existsSync(AUTH_FILE)) {
|
|
33
|
-
const backupFile = `${AUTH_FILE}.
|
|
33
|
+
const backupFile = `${AUTH_FILE}.aiworker.backup`;
|
|
34
34
|
fs.copyFileSync(AUTH_FILE, backupFile);
|
|
35
35
|
if (process.platform !== 'win32') fs.chmodSync(backupFile, 0o600);
|
|
36
36
|
console.log(`Created auth backup: ${backupFile}`);
|
|
@@ -6,7 +6,7 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
6
6
|
registerAuthAndAccessRoutes,
|
|
7
7
|
registerTtsRoutes,
|
|
8
8
|
registerNotificationRoutes,
|
|
9
|
-
|
|
9
|
+
registerAiWorkerRoutes,
|
|
10
10
|
registerAgentToolRoutes = () => {},
|
|
11
11
|
express,
|
|
12
12
|
} = dependencies;
|
|
@@ -14,7 +14,7 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
14
14
|
const setupBaseRoutes = (app, options) => {
|
|
15
15
|
const {
|
|
16
16
|
process,
|
|
17
|
-
|
|
17
|
+
aiworkerVersion,
|
|
18
18
|
runtimeName,
|
|
19
19
|
serverStartedAt,
|
|
20
20
|
gracefulShutdown,
|
|
@@ -56,13 +56,14 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
56
56
|
path,
|
|
57
57
|
server,
|
|
58
58
|
__dirname,
|
|
59
|
-
|
|
59
|
+
aiworkerDataDir,
|
|
60
60
|
modelsDevApiUrl,
|
|
61
61
|
modelsMetadataCacheTtl,
|
|
62
62
|
fetchFreeZenModels,
|
|
63
63
|
getCachedZenModels,
|
|
64
64
|
setAutoAcceptSession,
|
|
65
65
|
agentToolRuntime,
|
|
66
|
+
desktopUpdater,
|
|
66
67
|
} = options;
|
|
67
68
|
|
|
68
69
|
const uiAuthController = createUiAuth({
|
|
@@ -77,7 +78,7 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
77
78
|
registerServerStatusRoutes(app, {
|
|
78
79
|
express,
|
|
79
80
|
process,
|
|
80
|
-
|
|
81
|
+
aiworkerVersion,
|
|
81
82
|
runtimeName,
|
|
82
83
|
serverStartedAt,
|
|
83
84
|
gracefulShutdown,
|
|
@@ -140,19 +141,20 @@ export const createBootstrapRuntime = (dependencies) => {
|
|
|
140
141
|
setAutoAcceptSession,
|
|
141
142
|
});
|
|
142
143
|
|
|
143
|
-
|
|
144
|
+
registerAiWorkerRoutes(app, {
|
|
144
145
|
fs,
|
|
145
146
|
os,
|
|
146
147
|
path,
|
|
147
148
|
process,
|
|
148
149
|
server,
|
|
149
150
|
__dirname,
|
|
150
|
-
|
|
151
|
+
aiworkerDataDir,
|
|
151
152
|
modelsDevApiUrl,
|
|
152
153
|
modelsMetadataCacheTtl,
|
|
153
154
|
readSettingsFromDiskMigrated,
|
|
154
155
|
fetchFreeZenModels,
|
|
155
156
|
getCachedZenModels,
|
|
157
|
+
desktopUpdater,
|
|
156
158
|
});
|
|
157
159
|
|
|
158
160
|
return {
|
|
@@ -7,19 +7,19 @@ export const parseServeCliOptions = ({
|
|
|
7
7
|
}) => {
|
|
8
8
|
const args = Array.isArray(argv) ? [...argv] : [];
|
|
9
9
|
const envPassword =
|
|
10
|
-
env.
|
|
10
|
+
env.AIWORKER_UI_PASSWORD ||
|
|
11
11
|
env.OPENCODE_UI_PASSWORD ||
|
|
12
12
|
null;
|
|
13
|
-
const envCfTunnel = env.
|
|
14
|
-
const envTunnelProvider = env.
|
|
15
|
-
const envTunnelMode = env.
|
|
16
|
-
const envTunnelConfigRaw = env.
|
|
13
|
+
const envCfTunnel = env.AIWORKER_TRY_CF_TUNNEL === 'true';
|
|
14
|
+
const envTunnelProvider = env.AIWORKER_TUNNEL_PROVIDER || undefined;
|
|
15
|
+
const envTunnelMode = env.AIWORKER_TUNNEL_MODE || undefined;
|
|
16
|
+
const envTunnelConfigRaw = env.AIWORKER_TUNNEL_CONFIG;
|
|
17
17
|
const envTunnelConfig = typeof envTunnelConfigRaw === 'string'
|
|
18
18
|
? (envTunnelConfigRaw.trim().length > 0 ? envTunnelConfigRaw.trim() : null)
|
|
19
19
|
: undefined;
|
|
20
|
-
const envTunnelToken = env.
|
|
21
|
-
const envTunnelHostname = env.
|
|
22
|
-
const envApiOnly = env.
|
|
20
|
+
const envTunnelToken = env.AIWORKER_TUNNEL_TOKEN || undefined;
|
|
21
|
+
const envTunnelHostname = env.AIWORKER_TUNNEL_HOSTNAME || undefined;
|
|
22
|
+
const envApiOnly = env.AIWORKER_API_ONLY === '1' || env.AIWORKER_API_ONLY === 'true';
|
|
23
23
|
|
|
24
24
|
const options = {
|
|
25
25
|
port: defaultPort,
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
|
|
6
|
+
const originalXdgConfigHome = process.env.XDG_CONFIG_HOME;
|
|
7
|
+
const originalOpenCodeConfig = process.env.OPENCODE_CONFIG;
|
|
8
|
+
|
|
9
|
+
afterEach(() => {
|
|
10
|
+
if (originalXdgConfigHome === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
11
|
+
else process.env.XDG_CONFIG_HOME = originalXdgConfigHome;
|
|
12
|
+
if (originalOpenCodeConfig === undefined) delete process.env.OPENCODE_CONFIG;
|
|
13
|
+
else process.env.OPENCODE_CONFIG = originalOpenCodeConfig;
|
|
14
|
+
vi.resetModules();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
async function loadOpenCodeModules() {
|
|
18
|
+
vi.resetModules();
|
|
19
|
+
return Promise.all([
|
|
20
|
+
import('./shared.js'),
|
|
21
|
+
import('./agents.js'),
|
|
22
|
+
import('./commands.js'),
|
|
23
|
+
import('./skills.js'),
|
|
24
|
+
import('./snippets.js'),
|
|
25
|
+
import('./plugins.js'),
|
|
26
|
+
import('./routes.js'),
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
describe('OpenCode global config paths', () => {
|
|
31
|
+
it('derives all shared constants from a non-empty XDG_CONFIG_HOME', async () => {
|
|
32
|
+
const xdgConfigHome = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-xdg-'));
|
|
33
|
+
process.env.XDG_CONFIG_HOME = xdgConfigHome;
|
|
34
|
+
|
|
35
|
+
const [{ OPENCODE_CONFIG_DIR, AGENT_DIR, COMMAND_DIR, SKILL_DIR, CONFIG_FILE }] = await loadOpenCodeModules();
|
|
36
|
+
const configDir = path.join(xdgConfigHome, 'opencode');
|
|
37
|
+
expect(OPENCODE_CONFIG_DIR).toBe(configDir);
|
|
38
|
+
expect(AGENT_DIR).toBe(path.join(configDir, 'agents'));
|
|
39
|
+
expect(COMMAND_DIR).toBe(path.join(configDir, 'commands'));
|
|
40
|
+
expect(SKILL_DIR).toBe(path.join(configDir, 'skills'));
|
|
41
|
+
expect(CONFIG_FILE).toBe(path.join(configDir, 'config.json'));
|
|
42
|
+
|
|
43
|
+
fs.rmSync(xdgConfigHome, { recursive: true, force: true });
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it.each([undefined, ' '])('falls back to ~/.config/opencode when XDG_CONFIG_HOME is %s', async (xdgConfigHome) => {
|
|
47
|
+
if (xdgConfigHome === undefined) delete process.env.XDG_CONFIG_HOME;
|
|
48
|
+
else process.env.XDG_CONFIG_HOME = xdgConfigHome;
|
|
49
|
+
|
|
50
|
+
const [{ OPENCODE_CONFIG_DIR }] = await loadOpenCodeModules();
|
|
51
|
+
expect(OPENCODE_CONFIG_DIR).toBe(path.join(os.homedir(), '.config', 'opencode'));
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('keeps global CRUD below XDG_CONFIG_HOME while project files stay in the project', async () => {
|
|
55
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-config-paths-'));
|
|
56
|
+
const xdgConfigHome = path.join(root, 'xdg');
|
|
57
|
+
const projectDir = path.join(root, 'project');
|
|
58
|
+
process.env.XDG_CONFIG_HOME = xdgConfigHome;
|
|
59
|
+
delete process.env.OPENCODE_CONFIG;
|
|
60
|
+
|
|
61
|
+
const [, agents, commands, skills, snippets, plugins] = await loadOpenCodeModules();
|
|
62
|
+
agents.createAgent('global-agent', { description: 'Global', prompt: 'Global prompt' }, projectDir, 'user');
|
|
63
|
+
commands.createCommand('global-command', { description: 'Global', template: 'Global template' }, projectDir, 'user');
|
|
64
|
+
skills.createSkill('global-skill', { description: 'Global', instructions: 'Global instructions' }, projectDir, 'user');
|
|
65
|
+
snippets.createSnippet('global-snippet', { content: 'Global snippet' }, projectDir, 'global');
|
|
66
|
+
plugins.createPluginEntry({ spec: 'global-plugin', scope: 'user' }, projectDir);
|
|
67
|
+
|
|
68
|
+
const configDir = path.join(xdgConfigHome, 'opencode');
|
|
69
|
+
expect(fs.existsSync(path.join(configDir, 'agents', 'global-agent.md'))).toBe(true);
|
|
70
|
+
expect(fs.existsSync(path.join(configDir, 'commands', 'global-command.md'))).toBe(true);
|
|
71
|
+
expect(fs.existsSync(path.join(configDir, 'skills', 'global-skill', 'SKILL.md'))).toBe(true);
|
|
72
|
+
expect(fs.existsSync(path.join(configDir, 'snippet', 'global-snippet.md'))).toBe(true);
|
|
73
|
+
expect(JSON.parse(fs.readFileSync(path.join(configDir, 'config.json'), 'utf8')).plugin).toEqual(['global-plugin']);
|
|
74
|
+
|
|
75
|
+
agents.createAgent('project-agent', { description: 'Project', prompt: 'Project prompt' }, projectDir, 'project');
|
|
76
|
+
commands.createCommand('project-command', { description: 'Project', template: 'Project template' }, projectDir, 'project');
|
|
77
|
+
skills.createSkill('project-skill', { description: 'Project', instructions: 'Project instructions' }, projectDir, 'project');
|
|
78
|
+
|
|
79
|
+
expect(fs.existsSync(path.join(projectDir, '.opencode', 'agents', 'project-agent.md'))).toBe(true);
|
|
80
|
+
expect(fs.existsSync(path.join(projectDir, '.opencode', 'commands', 'project-command.md'))).toBe(true);
|
|
81
|
+
expect(fs.existsSync(path.join(projectDir, '.opencode', 'skills', 'project-skill', 'SKILL.md'))).toBe(true);
|
|
82
|
+
|
|
83
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('writes global AGENTS.md below XDG_CONFIG_HOME', async () => {
|
|
87
|
+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-agents-md-'));
|
|
88
|
+
process.env.XDG_CONFIG_HOME = path.join(root, 'xdg');
|
|
89
|
+
delete process.env.OPENCODE_CONFIG;
|
|
90
|
+
|
|
91
|
+
const [, , , , , , routes] = await loadOpenCodeModules();
|
|
92
|
+
const handlers = new Map();
|
|
93
|
+
const app = {
|
|
94
|
+
get(route, ...callbacks) { handlers.set(`GET ${route}`, callbacks.at(-1)); },
|
|
95
|
+
put(route, ...callbacks) { handlers.set(`PUT ${route}`, callbacks.at(-1)); },
|
|
96
|
+
post() {},
|
|
97
|
+
delete() {},
|
|
98
|
+
};
|
|
99
|
+
routes.registerOpenCodeRoutes(app, {});
|
|
100
|
+
|
|
101
|
+
const response = { json: vi.fn(), status: vi.fn(() => response) };
|
|
102
|
+
await handlers.get('GET /api/behavior/agents-md')({}, response);
|
|
103
|
+
expect(response.json).toHaveBeenLastCalledWith({
|
|
104
|
+
content: '', exists: false, path: path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'),
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
await handlers.get('PUT /api/behavior/agents-md')({ body: { content: 'Global behavior' } }, response);
|
|
108
|
+
|
|
109
|
+
expect(fs.readFileSync(path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'), 'utf8')).toBe('Global behavior');
|
|
110
|
+
await handlers.get('GET /api/behavior/agents-md')({}, response);
|
|
111
|
+
expect(response.json).toHaveBeenLastCalledWith({
|
|
112
|
+
content: 'Global behavior', exists: true, path: path.join(process.env.XDG_CONFIG_HOME, 'opencode', 'AGENTS.md'),
|
|
113
|
+
});
|
|
114
|
+
fs.rmSync(root, { recursive: true, force: true });
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -28,12 +28,12 @@ export const registerServerStatusRoutes = (app, dependencies) => {
|
|
|
28
28
|
const {
|
|
29
29
|
express,
|
|
30
30
|
process,
|
|
31
|
-
|
|
31
|
+
aiworkerVersion,
|
|
32
32
|
runtimeName,
|
|
33
33
|
serverStartedAt,
|
|
34
34
|
gracefulShutdown,
|
|
35
35
|
getHealthSnapshot,
|
|
36
|
-
// Port this
|
|
36
|
+
// Port this AiWorker instance serves on and the tunnel public URL (if
|
|
37
37
|
// a tunnel is active). Exposed on /api/system/info so the UI can surface
|
|
38
38
|
// the active instance's service URLs. Optional: older wiring omits them
|
|
39
39
|
// and the endpoint reports null.
|
|
@@ -101,7 +101,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
|
|
|
101
101
|
const isDevShutdownAllowed = () => {
|
|
102
102
|
// Dev-only escape hatch: allow terminating the whole dev process group.
|
|
103
103
|
// This should never be enabled in production runtimes.
|
|
104
|
-
return process.env.
|
|
104
|
+
return process.env.AIWORKER_DEV_SHUTDOWN === 'true';
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
const isSameOriginRequest = (req) => {
|
|
@@ -209,7 +209,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
|
|
|
209
209
|
res.json({
|
|
210
210
|
status: 'ok',
|
|
211
211
|
timestamp: new Date().toISOString(),
|
|
212
|
-
|
|
212
|
+
aiworkerVersion,
|
|
213
213
|
runtime: runtimeName,
|
|
214
214
|
compatibility,
|
|
215
215
|
...(serverId ? { serverId } : {}),
|
|
@@ -221,7 +221,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
|
|
|
221
221
|
const serverId = await resolveServerId();
|
|
222
222
|
res.json({
|
|
223
223
|
status: 'ok',
|
|
224
|
-
|
|
224
|
+
aiworkerVersion,
|
|
225
225
|
runtime: runtimeName,
|
|
226
226
|
startedAt: serverStartedAt,
|
|
227
227
|
compatibility,
|
|
@@ -324,7 +324,7 @@ export const registerServerStatusRoutes = (app, dependencies) => {
|
|
|
324
324
|
|
|
325
325
|
app.get('/api/system/info', (_req, res) => {
|
|
326
326
|
res.json({
|
|
327
|
-
|
|
327
|
+
aiworkerVersion,
|
|
328
328
|
runtime: runtimeName,
|
|
329
329
|
pid: process.pid,
|
|
330
330
|
startedAt: serverStartedAt,
|
|
@@ -376,7 +376,7 @@ export const registerAuthAndAccessRoutes = (app, dependencies) => {
|
|
|
376
376
|
getServerId = async () => null,
|
|
377
377
|
// Display name a paired device shows for THIS server (issuing machine's
|
|
378
378
|
// hostname), distinct from the per-device pairing label typed by the operator.
|
|
379
|
-
getServerLabel = () => '
|
|
379
|
+
getServerLabel = () => 'AiWorker',
|
|
380
380
|
} = dependencies;
|
|
381
381
|
const PAIRING_REDEEM_RATE_LIMIT_WINDOW_MS = 5 * 60 * 1000;
|
|
382
382
|
const PAIRING_REDEEM_RATE_LIMIT_MAX_ATTEMPTS = 10;
|
|
@@ -1065,6 +1065,7 @@ export const registerCommonRequestMiddleware = (app, dependencies) => {
|
|
|
1065
1065
|
req.path.startsWith('/api/push') ||
|
|
1066
1066
|
req.path.startsWith('/api/notifications') ||
|
|
1067
1067
|
req.path.startsWith('/api/permission-auto-accept') ||
|
|
1068
|
+
req.path.startsWith('/api/message-queue') ||
|
|
1068
1069
|
req.path.startsWith('/api/provider') ||
|
|
1069
1070
|
req.path.startsWith('/api/session-folders') ||
|
|
1070
1071
|
req.path.startsWith('/api/small-model') ||
|
|
@@ -17,7 +17,7 @@ describe('core-routes', () => {
|
|
|
17
17
|
shutdownOpts = opts;
|
|
18
18
|
}),
|
|
19
19
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
20
|
-
|
|
20
|
+
aiworkerVersion: '1.0.0',
|
|
21
21
|
runtimeName: 'test',
|
|
22
22
|
express,
|
|
23
23
|
};
|
|
@@ -35,7 +35,7 @@ describe('core-routes', () => {
|
|
|
35
35
|
const dependencies = {
|
|
36
36
|
gracefulShutdown: vi.fn(async () => {}),
|
|
37
37
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
38
|
-
|
|
38
|
+
aiworkerVersion: '1.0.0',
|
|
39
39
|
runtimeName: 'test',
|
|
40
40
|
express,
|
|
41
41
|
tunnelAuthController: {
|
|
@@ -62,7 +62,7 @@ describe('core-routes', () => {
|
|
|
62
62
|
const dependencies = {
|
|
63
63
|
gracefulShutdown: vi.fn(async () => {}),
|
|
64
64
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
65
|
-
|
|
65
|
+
aiworkerVersion: '1.0.0',
|
|
66
66
|
runtimeName: 'test',
|
|
67
67
|
express,
|
|
68
68
|
tunnelAuthController: {
|
|
@@ -89,7 +89,7 @@ describe('core-routes', () => {
|
|
|
89
89
|
const dependencies = {
|
|
90
90
|
gracefulShutdown: vi.fn(async () => {}),
|
|
91
91
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
92
|
-
|
|
92
|
+
aiworkerVersion: '1.0.0',
|
|
93
93
|
runtimeName: 'test',
|
|
94
94
|
express,
|
|
95
95
|
tunnelAuthController: {
|
|
@@ -438,7 +438,7 @@ describe('core-routes', () => {
|
|
|
438
438
|
expect(response.headers['cache-control']).toBe('no-store');
|
|
439
439
|
expect(response.body).toMatchObject({
|
|
440
440
|
ok: true,
|
|
441
|
-
server: { label: '
|
|
441
|
+
server: { label: 'AiWorker', url: 'http://runtime.example', fingerprint: 'ABCD-1234' },
|
|
442
442
|
client: { id: 'client-1', authMethod: 'pairing' },
|
|
443
443
|
clientToken: 'oc_client_token',
|
|
444
444
|
});
|
|
@@ -690,7 +690,7 @@ describe('client auth routes', () => {
|
|
|
690
690
|
|
|
691
691
|
const current = await request(app)
|
|
692
692
|
.post('/api/client-auth/clients')
|
|
693
|
-
.send({ label: '
|
|
693
|
+
.send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
|
|
694
694
|
const other = await request(app)
|
|
695
695
|
.post('/api/client-auth/clients')
|
|
696
696
|
.send({ label: 'Other device' });
|
|
@@ -725,7 +725,7 @@ describe('client auth routes', () => {
|
|
|
725
725
|
|
|
726
726
|
const desktop = await request(app)
|
|
727
727
|
.post('/api/client-auth/clients')
|
|
728
|
-
.send({ label: '
|
|
728
|
+
.send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
|
|
729
729
|
const other = await request(app)
|
|
730
730
|
.post('/api/client-auth/clients')
|
|
731
731
|
.send({ label: 'Other device' });
|
|
@@ -758,7 +758,7 @@ describe('client auth routes', () => {
|
|
|
758
758
|
|
|
759
759
|
const desktop = await request(app)
|
|
760
760
|
.post('/api/client-auth/clients')
|
|
761
|
-
.send({ label: '
|
|
761
|
+
.send({ label: 'AiWorker Desktop', clientKind: 'desktop-local' });
|
|
762
762
|
const remote = await request(app)
|
|
763
763
|
.post('/api/client-auth/clients')
|
|
764
764
|
.send({ label: 'Phone' });
|
|
@@ -827,14 +827,14 @@ describe('client auth routes', () => {
|
|
|
827
827
|
serverStartedAt: '2026-01-01T00:00:00.000Z',
|
|
828
828
|
gracefulShutdown: vi.fn(async () => {}),
|
|
829
829
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
830
|
-
|
|
830
|
+
aiworkerVersion: '1.0.0',
|
|
831
831
|
runtimeName: 'test',
|
|
832
832
|
express,
|
|
833
833
|
});
|
|
834
834
|
|
|
835
835
|
const response = await request(app).get('/api/system/info');
|
|
836
836
|
expect(response.status).toBe(200);
|
|
837
|
-
expect(response.body.
|
|
837
|
+
expect(response.body.aiworkerVersion).toBe('1.0.0');
|
|
838
838
|
expect(response.body.runtime).toBe('test');
|
|
839
839
|
expect(response.body.pid).toBeTypeOf('number');
|
|
840
840
|
expect(response.body.startedAt).toBeTypeOf('string');
|
|
@@ -849,7 +849,7 @@ describe('client auth routes', () => {
|
|
|
849
849
|
serverStartedAt: '2026-01-01T00:00:00.000Z',
|
|
850
850
|
gracefulShutdown: vi.fn(async () => {}),
|
|
851
851
|
getHealthSnapshot: () => ({ status: 'ok' }),
|
|
852
|
-
|
|
852
|
+
aiworkerVersion: '1.0.0',
|
|
853
853
|
runtimeName: 'test',
|
|
854
854
|
express,
|
|
855
855
|
getServerPort: () => 9988,
|