@aiworker/web 1.22.0 → 1.22.2
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 +7 -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-CSICpWQD.js} +1 -1
- package/dist/assets/{DiffView-DluiRSla.js → DiffView-hDBKesA_.js} +3 -3
- package/dist/assets/DirtyBranchSwitchDialog-C22HdWj4.js +1 -0
- package/dist/assets/FilesView-CdWzeOp9.js +17 -0
- package/dist/assets/GitView-VQQkYuUw.js +6 -0
- package/dist/assets/{JsonTreeView-B0BdZEHG.js → JsonTreeView-6lrhwD3q.js} +1 -1
- package/dist/assets/LinearIssuesView-Ba6Q9569.js +1 -0
- package/dist/assets/{MarkdownImageGallery-ClOvuZxC.js → MarkdownImageGallery-Czv_mhvS.js} +1 -1
- package/dist/assets/MarkdownRendererImpl-BrMcswiy.js +12 -0
- package/dist/assets/{OnboardingScreen-D2DG7K6b.js → OnboardingScreen-ChxQoAkx.js} +1 -1
- package/dist/assets/{PatchDiff-DvfqDql7.js → PatchDiff-BzcZPlOq.js} +1 -1
- package/dist/assets/{PierreDiffViewer-B7m3f0d7.js → PierreDiffViewer-BchBtZlp.js} +2 -2
- package/dist/assets/PlanView-DyDt_nZ_.js +5 -0
- package/dist/assets/SettingsView-BKf5xBsP.js +28 -0
- package/dist/assets/{SettingsWindow-i45U1Cy1.js → SettingsWindow-DDQYaKWQ.js} +1 -1
- package/dist/assets/{ToolOutputDialog-BTwyh5OF.js → ToolOutputDialog-iYF8Y2bz.js} +6 -6
- package/dist/assets/ToolPartDiffPreview-CdjbOVMM.js +8 -0
- package/dist/assets/{VirtualizedFileDiff-DD8lDVej.js → VirtualizedFileDiff-fFFm2QgH.js} +1 -1
- package/dist/assets/{WalkthroughView-egQgxel3.js → WalkthroughView-DOeCsMju.js} +2 -2
- package/dist/assets/{computeVirtualFileMetrics-BMIRgMHv.js → computeVirtualFileMetrics-CzgLum_K.js} +2 -2
- package/dist/assets/{contextPanelEmbeddedChat-C3fjDbdg.js → contextPanelEmbeddedChat-C0ZLAepL.js} +1 -1
- package/dist/assets/{de-C1P6X5Rs.js → de-B5JaA3SA.js} +6 -5
- package/dist/assets/{es-CDgaF1_t.js → es-EPIH88ii.js} +6 -5
- package/dist/assets/{fr-Bgxqvvz_.js → fr-CAMfxUdZ.js} +6 -5
- package/dist/assets/{index-CODwDsU_.js → index-Bl3LSbjn.js} +1 -1
- package/dist/assets/index-DF5kMP-i.js +39 -0
- package/dist/assets/index-Dl3xbAB_.css +1 -0
- package/dist/assets/{isDiffPlainText-BqayB8d3.js → isDiffPlainText-Dx-dB_8l.js} +1 -1
- package/dist/assets/{isFilePlainText-QfoiKJNY.js → isFilePlainText-CWFPwmnU.js} +1 -1
- package/dist/assets/{ja-BDRrEcNP.js → ja-CifOE1VN.js} +7 -6
- package/dist/assets/{ko-Ba8sQV79.js → ko-BBDyAyYQ.js} +7 -6
- package/dist/assets/{main-C5DVOxc6.js → main-DnBAoktx.js} +2 -2
- package/dist/assets/main-MhSaOZoB.js +930 -0
- package/dist/assets/{markdownCore-CZwzz5gw.js → markdownCore-BrBwOOMn.js} +2 -2
- package/dist/assets/{miniChat-DUJ4irZc.js → miniChat-BKyvLseN.js} +2 -2
- package/dist/assets/{mobile-CcaxB0n4.js → mobile-DKjeFgMN.js} +2 -2
- package/dist/assets/{patchFileDiff-yNfWXN4E.js → patchFileDiff-o8ms1me8.js} +1 -1
- package/dist/assets/pl-DgEHYfFM.js +16 -0
- package/dist/assets/{pt-BR-DIs6ElwV.js → pt-BR-DuWHojUw.js} +6 -5
- package/dist/assets/{renderElectronMiniChatApp-BcKLHXKe.js → renderElectronMiniChatApp-CDgBwwCS.js} +2 -2
- package/dist/assets/renderMobileApp-DJIKIK1r.js +25 -0
- package/dist/assets/runtimeEndpointReset-CYJ9O_xX.js +17 -0
- package/dist/assets/{scheduledTasksApi-DLW0mkQK.js → scheduledTasksApi-D8yamh1b.js} +1 -1
- package/dist/assets/{shikiHighlight-DYOWuY65.js → shikiHighlight-TEQCmzW8.js} +1 -1
- package/dist/assets/tr-D5m2yIWL.js +7 -0
- package/dist/assets/{uk-ZrCNjM7Y.js → uk-D_q60oog.js} +6 -5
- package/dist/assets/{useAppFontEffects-CjrntdL0.js → useAppFontEffects-D7sNpuL2.js} +161 -190
- package/dist/assets/useInlineCommentController-Brz_cLcQ.js +2 -0
- package/dist/assets/{useRootScrollLock-BHYPkrLv.js → useRootScrollLock-lXEnWlaU.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-data-DFZik9R2.js → vendor-codemirror-language-data-Dp3KMRQG.js} +2 -2
- package/dist/assets/vendor-zod-CK21ihK-.js +39 -0
- package/dist/assets/{web-components-Bhg83tjf.js → web-components-_mNEMjFY.js} +1 -1
- package/dist/assets/{zh-CN-iv_AV4EC.js → zh-CN-D8QvsVeg.js} +6 -5
- package/dist/assets/{zh-TW-CzEUk38j.js → zh-TW-B9t7rQQO.js} +6 -5
- package/dist/index.html +22 -22
- package/dist/mini-chat.html +7 -7
- package/dist/mobile.html +5 -5
- package/package.json +3 -3
- package/server/index.js +118 -85
- 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/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 +6 -6
- package/server/lib/fs/DOCUMENTATION.md +2 -0
- package/server/lib/fs/routes.js +37 -26
- package/server/lib/fs/routes.test.js +98 -21
- package/server/lib/git/DOCUMENTATION.md +3 -1
- 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 +17 -1
- package/server/lib/git/service.js +116 -26
- package/server/lib/git/service.test.js +174 -3
- 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 +1 -1
- package/server/lib/inherited-env.test.js +2 -2
- 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 +158 -0
- package/server/lib/message-queue/runtime.js +870 -0
- package/server/lib/message-queue/runtime.test.js +482 -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 +13 -5
- package/server/lib/opencode/auth.js +1 -1
- package/server/lib/opencode/bootstrap-runtime.js +6 -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 +17 -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 +15 -15
- package/server/lib/opencode/openchamber-routes.test.js +11 -11
- 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 +14 -14
- 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-helpers.js +31 -3
- package/server/lib/opencode/settings-helpers.test.js +189 -12
- package/server/lib/opencode/settings-runtime.js +2 -2
- package/server/lib/opencode/settings-runtime.test.js +29 -0
- 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/routes.js +1 -1
- package/server/lib/projects/project-config.js +2 -2
- package/server/lib/quota/DOCUMENTATION.md +9 -1
- 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/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 +15 -0
- package/server/lib/quota/providers/ollama-cloud.js +1 -1
- package/server/lib/quota/providers/opencode-go.js +2 -1
- package/server/lib/quota/providers/opencode-go.test.js +9 -5
- 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 +1 -1
- package/server/lib/relay/host-client.js +1 -1
- 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-host.js +3 -1
- 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 +10 -9
- 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 +88 -22
- 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 +4 -0
- package/server/lib/small-model/call.js +9 -3
- package/server/lib/small-model/call.test.js +29 -6
- package/server/lib/small-model/index.js +8 -7
- 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/system-prompt/runtime.js +3 -22
- package/server/lib/system-prompt/runtime.test.js +3 -3
- package/server/lib/terminal/DOCUMENTATION.md +11 -7
- package/server/lib/terminal/runtime.js +180 -26
- package/server/lib/terminal/runtime.test.js +554 -27
- 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/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 +3 -3
- package/server/lib/walkthrough/model-settings.test.js +1 -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/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/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/MarkdownRendererImpl-Dt9mjTRN.js +0 -12
- 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/index-C57jT0Sa.css +0 -1
- package/dist/assets/index-DW_E3rnL.js +0 -7
- package/dist/assets/main-Bv5Pkngh.js +0 -928
- package/dist/assets/pl-Dioz29BI.js +0 -15
- package/dist/assets/renderMobileApp-D9yQJy0L.js +0 -25
- package/dist/assets/runtimeEndpointReset-CjhvxLH0.js +0 -16
- package/dist/assets/tr-DFnMlPxY.js +0 -6
- package/dist/assets/useInlineCommentController-CDEuSlPH.js +0 -2
- package/dist/assets/vendor-zod-BLfBSgBh.js +0 -39
- 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
|
@@ -22,8 +22,8 @@ export const createServerStartupRuntime = (dependencies) => {
|
|
|
22
22
|
|
|
23
23
|
const resolveBindHost = (host) =>
|
|
24
24
|
host
|
|
25
|
-
|| (typeof process.env.
|
|
26
|
-
? process.env.
|
|
25
|
+
|| (typeof process.env.AIWORKER_HOST === 'string' && process.env.AIWORKER_HOST.trim().length > 0
|
|
26
|
+
? process.env.AIWORKER_HOST.trim()
|
|
27
27
|
: '127.0.0.1');
|
|
28
28
|
|
|
29
29
|
const startListeningAndMaybeTunnel = async ({
|
|
@@ -48,12 +48,12 @@ export const createServerStartupRuntime = (dependencies) => {
|
|
|
48
48
|
|
|
49
49
|
if (typeof process.send === 'function') {
|
|
50
50
|
if (!process.connected) {
|
|
51
|
-
throw new Error('
|
|
51
|
+
throw new Error('AiWorker startup IPC channel disconnected before ready notification');
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
await new Promise((resolveReadyNotification, rejectReadyNotification) => {
|
|
55
55
|
try {
|
|
56
|
-
process.send({ type: '
|
|
56
|
+
process.send({ type: 'aiworker:ready', port: activePort }, (error) => {
|
|
57
57
|
if (error) {
|
|
58
58
|
rejectReadyNotification(error);
|
|
59
59
|
return;
|
|
@@ -69,7 +69,7 @@ export const createServerStartupRuntime = (dependencies) => {
|
|
|
69
69
|
const displayHost = (bindHost === '0.0.0.0' || bindHost === '::' || bindHost === '[::]')
|
|
70
70
|
? 'localhost'
|
|
71
71
|
: (bindHost.includes(':') ? `[${bindHost}]` : bindHost);
|
|
72
|
-
console.log(`
|
|
72
|
+
console.log(`AiWorker server listening on ${bindHost}:${activePort}`);
|
|
73
73
|
console.log(`Health check: http://${displayHost}:${activePort}/health`);
|
|
74
74
|
console.log(`Web interface: http://${displayHost}:${activePort}`);
|
|
75
75
|
|
|
@@ -138,7 +138,7 @@ export const createServerStartupRuntime = (dependencies) => {
|
|
|
138
138
|
// Cover every signal a shell or dev harness may use to stop/restart us, so
|
|
139
139
|
// the managed OpenCode child is always torn down gracefully instead of
|
|
140
140
|
// orphaned: SIGINT/SIGQUIT (Ctrl+C/Ctrl+\), SIGTERM (kill/default), SIGHUP
|
|
141
|
-
// (terminal close), SIGUSR2 (nodemon restart
|
|
141
|
+
// (terminal close), SIGUSR2 (nodemon restart outside Windows).
|
|
142
142
|
process.on('SIGTERM', handleSignal);
|
|
143
143
|
process.on('SIGINT', handleSignal);
|
|
144
144
|
process.on('SIGQUIT', handleSignal);
|
|
@@ -98,7 +98,7 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
98
98
|
|
|
99
99
|
if (typeof broadcastEvent === 'function') {
|
|
100
100
|
broadcastEvent({
|
|
101
|
-
type: '
|
|
101
|
+
type: 'aiworker:session-activity',
|
|
102
102
|
properties: {
|
|
103
103
|
sessionId,
|
|
104
104
|
phase,
|
|
@@ -149,7 +149,7 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
149
149
|
if (!existing || existing.status !== status || attentionChanged || isRestartInterruption) {
|
|
150
150
|
const state = sessionStates.get(sessionId);
|
|
151
151
|
const syntheticPayload = {
|
|
152
|
-
type: '
|
|
152
|
+
type: 'aiworker:session-status',
|
|
153
153
|
properties: {
|
|
154
154
|
sessionID: sessionId,
|
|
155
155
|
status: state.status,
|
|
@@ -207,7 +207,7 @@ export const createSessionRuntime = ({ writeSseEvent, getNotificationClients, br
|
|
|
207
207
|
state.needsAttention = false;
|
|
208
208
|
|
|
209
209
|
const syntheticPayload = {
|
|
210
|
-
type: '
|
|
210
|
+
type: 'aiworker:session-status',
|
|
211
211
|
properties: {
|
|
212
212
|
sessionID: sessionId,
|
|
213
213
|
status: state.status,
|
|
@@ -47,7 +47,7 @@ describe('session runtime', () => {
|
|
|
47
47
|
runtime.markSessionViewed('session-1', 'client-1');
|
|
48
48
|
|
|
49
49
|
expect(events).toContainEqual({
|
|
50
|
-
type: '
|
|
50
|
+
type: 'aiworker:session-status',
|
|
51
51
|
properties: expect.objectContaining({
|
|
52
52
|
sessionID: 'session-1',
|
|
53
53
|
status: 'idle',
|
|
@@ -55,7 +55,7 @@ describe('session runtime', () => {
|
|
|
55
55
|
}),
|
|
56
56
|
});
|
|
57
57
|
expect(events.at(-1)).toEqual({
|
|
58
|
-
type: '
|
|
58
|
+
type: 'aiworker:session-status',
|
|
59
59
|
properties: {
|
|
60
60
|
sessionID: 'session-1',
|
|
61
61
|
status: 'idle',
|
|
@@ -90,7 +90,7 @@ describe('session runtime', () => {
|
|
|
90
90
|
});
|
|
91
91
|
|
|
92
92
|
expect(events).toContainEqual({
|
|
93
|
-
type: '
|
|
93
|
+
type: 'aiworker:session-status',
|
|
94
94
|
properties: expect.objectContaining({
|
|
95
95
|
sessionID: 'legacy-session-1',
|
|
96
96
|
status: 'busy',
|
|
@@ -132,7 +132,7 @@ describe('session runtime', () => {
|
|
|
132
132
|
});
|
|
133
133
|
|
|
134
134
|
const activityPhases = () => events
|
|
135
|
-
.filter((event) => event.type === '
|
|
135
|
+
.filter((event) => event.type === 'aiworker:session-activity')
|
|
136
136
|
.map((event) => event.properties.phase);
|
|
137
137
|
|
|
138
138
|
expect(activityPhases()).toEqual(['busy', 'cooldown']);
|
|
@@ -224,12 +224,12 @@ describe('session runtime', () => {
|
|
|
224
224
|
});
|
|
225
225
|
|
|
226
226
|
const terminalEvents = events.filter((event) => (
|
|
227
|
-
event.type === '
|
|
227
|
+
event.type === 'aiworker:session-status' || event.type === 'session.error'
|
|
228
228
|
));
|
|
229
229
|
expect(terminalEvents).toHaveLength(6);
|
|
230
230
|
for (const sessionId of ['session-busy-1', 'session-busy-2', 'session-busy-3']) {
|
|
231
231
|
expect(terminalEvents).toContainEqual({
|
|
232
|
-
type: '
|
|
232
|
+
type: 'aiworker:session-status',
|
|
233
233
|
properties: expect.objectContaining({
|
|
234
234
|
sessionID: sessionId,
|
|
235
235
|
status: 'idle',
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { isAgentMemoryFeatureAvailable } from '../agent-memory/feature-flag.js';
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_INPUT_HISTORY_LIMIT,
|
|
4
|
+
DEFAULT_INPUT_HISTORY_SCOPE,
|
|
5
|
+
isInputHistoryLimit,
|
|
6
|
+
isInputHistoryScope,
|
|
7
|
+
} from './input-history-scope.js';
|
|
2
8
|
|
|
3
9
|
export const createSettingsHelpers = (dependencies) => {
|
|
4
10
|
const {
|
|
@@ -140,6 +146,12 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
140
146
|
if (typeof candidate.themeVariant === 'string' && (candidate.themeVariant === 'light' || candidate.themeVariant === 'dark')) {
|
|
141
147
|
result.themeVariant = candidate.themeVariant;
|
|
142
148
|
}
|
|
149
|
+
if (typeof candidate.inputHistoryScope === 'string' && isInputHistoryScope(candidate.inputHistoryScope)) {
|
|
150
|
+
result.inputHistoryScope = candidate.inputHistoryScope;
|
|
151
|
+
}
|
|
152
|
+
if (isInputHistoryLimit(candidate.inputHistoryLimit)) {
|
|
153
|
+
result.inputHistoryLimit = candidate.inputHistoryLimit;
|
|
154
|
+
}
|
|
143
155
|
if (typeof candidate.useSystemTheme === 'boolean') {
|
|
144
156
|
result.useSystemTheme = candidate.useSystemTheme;
|
|
145
157
|
}
|
|
@@ -519,6 +531,12 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
519
531
|
if (typeof candidate.inputSpellcheckEnabled === 'boolean') {
|
|
520
532
|
result.inputSpellcheckEnabled = candidate.inputSpellcheckEnabled;
|
|
521
533
|
}
|
|
534
|
+
if (candidate.enterToSend === true || candidate.enterToSend === false) {
|
|
535
|
+
result.enterToSend = candidate.enterToSend;
|
|
536
|
+
}
|
|
537
|
+
if (candidate.enterToSendConfigured === true || candidate.enterToSendConfigured === false) {
|
|
538
|
+
result.enterToSendConfigured = candidate.enterToSendConfigured;
|
|
539
|
+
}
|
|
522
540
|
if (typeof candidate.showOpenCodeUpdateNotifications === 'boolean') {
|
|
523
541
|
result.showOpenCodeUpdateNotifications = candidate.showOpenCodeUpdateNotifications;
|
|
524
542
|
}
|
|
@@ -687,6 +705,12 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
687
705
|
result.gitChangesViewMode = mode;
|
|
688
706
|
}
|
|
689
707
|
}
|
|
708
|
+
if (typeof candidate.toolJsonViewMode === 'string') {
|
|
709
|
+
const mode = candidate.toolJsonViewMode.trim();
|
|
710
|
+
if (mode === 'summary' || mode === 'formatted' || mode === 'raw') {
|
|
711
|
+
result.toolJsonViewMode = mode;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
690
714
|
if (typeof candidate.directoryShowHidden === 'boolean') {
|
|
691
715
|
result.directoryShowHidden = candidate.directoryShowHidden;
|
|
692
716
|
}
|
|
@@ -927,6 +951,8 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
927
951
|
const pwaAppName = normalizePwaAppName(settings?.pwaAppName, '');
|
|
928
952
|
const pwaOrientation = normalizePwaOrientation(settings?.pwaOrientation, 'system');
|
|
929
953
|
const mobileKeyboardMode = normalizeMobileKeyboardMode(settings?.mobileKeyboardMode, 'native');
|
|
954
|
+
const inputHistoryScope = sanitized.inputHistoryScope ?? DEFAULT_INPUT_HISTORY_SCOPE;
|
|
955
|
+
const inputHistoryLimit = sanitized.inputHistoryLimit ?? DEFAULT_INPUT_HISTORY_LIMIT;
|
|
930
956
|
|
|
931
957
|
return {
|
|
932
958
|
...sanitized,
|
|
@@ -937,14 +963,16 @@ export const createSettingsHelpers = (dependencies) => {
|
|
|
937
963
|
...(pwaAppName ? { pwaAppName } : {}),
|
|
938
964
|
pwaOrientation,
|
|
939
965
|
mobileKeyboardMode,
|
|
966
|
+
inputHistoryScope,
|
|
967
|
+
inputHistoryLimit,
|
|
940
968
|
securityScopedBookmarks: bookmarks,
|
|
941
969
|
pinnedDirectories: normalizeStringArray(settings.pinnedDirectories),
|
|
942
970
|
typographySizes: sanitizeTypographySizesPartial(settings.typographySizes),
|
|
943
|
-
...(process.env.
|
|
971
|
+
...(process.env.AIWORKER_RUNTIME === 'desktop'
|
|
944
972
|
? {
|
|
945
|
-
desktopLanAccessActive: process.env.
|
|
973
|
+
desktopLanAccessActive: process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE === 'true',
|
|
946
974
|
desktopLanAccessBlockedReason:
|
|
947
|
-
process.env.
|
|
975
|
+
process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON === 'missing-password'
|
|
948
976
|
? 'missing-password'
|
|
949
977
|
: null,
|
|
950
978
|
}
|
|
@@ -1,8 +1,19 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import { mkdirSync, mkdtempSync, readdirSync, rmSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { dirname, join } from 'node:path';
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
1
6
|
import { describe, expect, it } from 'vitest';
|
|
2
7
|
|
|
8
|
+
import {
|
|
9
|
+
DEFAULT_INPUT_HISTORY_LIMIT,
|
|
10
|
+
} from './input-history-scope.js';
|
|
3
11
|
import { createSettingsHelpers } from './settings-helpers.js';
|
|
4
12
|
import { createSettingsNormalizationRuntime } from './settings-normalization-runtime.js';
|
|
5
13
|
|
|
14
|
+
const testFilePath = fileURLToPath(import.meta.url);
|
|
15
|
+
const packagesWebDir = join(dirname(testFilePath), '..', '..', '..');
|
|
16
|
+
|
|
6
17
|
const createTestHelpers = () => createSettingsHelpers({
|
|
7
18
|
normalizePathForPersistence: (value) => value,
|
|
8
19
|
normalizeDirectoryPath: (value) => value,
|
|
@@ -58,6 +69,66 @@ const createTestHelpersWithRealSanitizers = () => {
|
|
|
58
69
|
};
|
|
59
70
|
|
|
60
71
|
describe('settings helpers', () => {
|
|
72
|
+
it('imports from the packed @aiworker/web tarball without escaping the published package', async () => {
|
|
73
|
+
const tempRoot = mkdtempSync(join(tmpdir(), 'settings-helpers-pack-'));
|
|
74
|
+
const packDir = join(tempRoot, 'pack');
|
|
75
|
+
const extractDir = join(tempRoot, 'extract');
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
mkdirSync(packDir);
|
|
79
|
+
mkdirSync(extractDir);
|
|
80
|
+
execFileSync('npm', ['pack', '--silent', '--pack-destination', packDir], {
|
|
81
|
+
cwd: packagesWebDir,
|
|
82
|
+
stdio: 'pipe',
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
const tarballName = readdirSync(packDir).find((entry) => entry.endsWith('.tgz'));
|
|
86
|
+
expect(tarballName).toBeTruthy();
|
|
87
|
+
|
|
88
|
+
execFileSync('tar', ['-xzf', join(packDir, tarballName), '-C', extractDir], {
|
|
89
|
+
stdio: 'pipe',
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const extractedModule = await import(
|
|
93
|
+
pathToFileURL(join(extractDir, 'package', 'server', 'lib', 'opencode', 'settings-helpers.js')).href
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
const helpers = extractedModule.createSettingsHelpers({
|
|
97
|
+
normalizePathForPersistence: (value) => value,
|
|
98
|
+
normalizeDirectoryPath: (value) => value,
|
|
99
|
+
normalizeTunnelBootstrapTtlMs: (value) => value,
|
|
100
|
+
normalizeTunnelSessionTtlMs: (value) => value,
|
|
101
|
+
normalizeTunnelProvider: (value) => value,
|
|
102
|
+
normalizeTunnelMode: (value) => value,
|
|
103
|
+
normalizeOptionalPath: (value) => value,
|
|
104
|
+
normalizeManagedRemoteTunnelHostname: (value) => value,
|
|
105
|
+
normalizeManagedRemoteTunnelPresets: () => undefined,
|
|
106
|
+
normalizeManagedRemoteTunnelPresetTokens: () => undefined,
|
|
107
|
+
sanitizeTypographySizesPartial: () => undefined,
|
|
108
|
+
normalizeStringArray: (input) => input,
|
|
109
|
+
sanitizeModelRefs: () => undefined,
|
|
110
|
+
sanitizeSkillCatalogs: () => undefined,
|
|
111
|
+
sanitizeProjects: () => undefined,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'global' })).toEqual({
|
|
115
|
+
inputHistoryScope: 'global',
|
|
116
|
+
});
|
|
117
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'session' })).toEqual({
|
|
118
|
+
inputHistoryScope: 'session',
|
|
119
|
+
});
|
|
120
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 40 })).toEqual({
|
|
121
|
+
inputHistoryLimit: 40,
|
|
122
|
+
});
|
|
123
|
+
expect(helpers.formatSettingsResponse({})).toMatchObject({
|
|
124
|
+
inputHistoryScope: 'session',
|
|
125
|
+
inputHistoryLimit: DEFAULT_INPUT_HISTORY_LIMIT,
|
|
126
|
+
});
|
|
127
|
+
} finally {
|
|
128
|
+
rmSync(tempRoot, { recursive: true, force: true });
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
61
132
|
it('accepts only booleans for draft starter visibility', () => {
|
|
62
133
|
const helpers = createTestHelpers();
|
|
63
134
|
|
|
@@ -66,6 +137,14 @@ describe('settings helpers', () => {
|
|
|
66
137
|
expect(helpers.sanitizeSettingsUpdate({ draftStartersVisible: 'false' })).toEqual({});
|
|
67
138
|
});
|
|
68
139
|
|
|
140
|
+
it('sanitizes both Enter settings independently', () => {
|
|
141
|
+
const helpers = createTestHelpers();
|
|
142
|
+
|
|
143
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: true })).toEqual({ enterToSend: true });
|
|
144
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: false })).toEqual({ enterToSendConfigured: false });
|
|
145
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: 'true', enterToSendConfigured: 1 })).toEqual({});
|
|
146
|
+
});
|
|
147
|
+
|
|
69
148
|
it('sanitizes shared sidebar display preferences', () => {
|
|
70
149
|
const helpers = createTestHelpers();
|
|
71
150
|
|
|
@@ -88,6 +167,15 @@ describe('settings helpers', () => {
|
|
|
88
167
|
})).toEqual({});
|
|
89
168
|
});
|
|
90
169
|
|
|
170
|
+
it('persists valid tool JSON view modes', () => {
|
|
171
|
+
const helpers = createTestHelpers();
|
|
172
|
+
|
|
173
|
+
expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'summary' })).toEqual({ toolJsonViewMode: 'summary' });
|
|
174
|
+
expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'formatted' })).toEqual({ toolJsonViewMode: 'formatted' });
|
|
175
|
+
expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'raw' })).toEqual({ toolJsonViewMode: 'raw' });
|
|
176
|
+
expect(helpers.sanitizeSettingsUpdate({ toolJsonViewMode: 'unknown' })).toEqual({});
|
|
177
|
+
});
|
|
178
|
+
|
|
91
179
|
it('accepts only booleans for wide chat layout', () => {
|
|
92
180
|
const helpers = createTestHelpers();
|
|
93
181
|
|
|
@@ -134,6 +222,74 @@ describe('settings helpers', () => {
|
|
|
134
222
|
expect(helpers.sanitizeSettingsUpdate({ messageStreamTransport: 'websocket' })).toEqual({});
|
|
135
223
|
});
|
|
136
224
|
|
|
225
|
+
it('accepts inputHistoryScope as a persisted shared setting', () => {
|
|
226
|
+
const helpers = createTestHelpers();
|
|
227
|
+
|
|
228
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'global' })).toEqual({
|
|
229
|
+
inputHistoryScope: 'global',
|
|
230
|
+
});
|
|
231
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'session' })).toEqual({
|
|
232
|
+
inputHistoryScope: 'session',
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('accepts valid inputHistoryLimit values as a persisted shared setting', () => {
|
|
237
|
+
const helpers = createTestHelpers();
|
|
238
|
+
|
|
239
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 1 })).toEqual({
|
|
240
|
+
inputHistoryLimit: 1,
|
|
241
|
+
});
|
|
242
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 40 })).toEqual({
|
|
243
|
+
inputHistoryLimit: 40,
|
|
244
|
+
});
|
|
245
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 100 })).toEqual({
|
|
246
|
+
inputHistoryLimit: 100,
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('rejects invalid inputHistoryLimit values', () => {
|
|
251
|
+
const helpers = createTestHelpers();
|
|
252
|
+
|
|
253
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 0 })).toEqual({});
|
|
254
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 101 })).toEqual({});
|
|
255
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: 1.5 })).toEqual({});
|
|
256
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: '40' })).toEqual({});
|
|
257
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.NaN })).toEqual({});
|
|
258
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.POSITIVE_INFINITY })).toEqual({});
|
|
259
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryLimit: Number.NEGATIVE_INFINITY })).toEqual({});
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
it('rejects invalid inputHistoryScope values', () => {
|
|
263
|
+
const helpers = createTestHelpers();
|
|
264
|
+
|
|
265
|
+
expect(helpers.sanitizeSettingsUpdate({ inputHistoryScope: 'workspace' })).toEqual({});
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it('defaults inputHistoryScope to session in formatted settings responses', () => {
|
|
269
|
+
const helpers = createTestHelpers();
|
|
270
|
+
|
|
271
|
+
expect(helpers.formatSettingsResponse({ inputHistoryScope: 'global' })).toMatchObject({
|
|
272
|
+
inputHistoryScope: 'global',
|
|
273
|
+
});
|
|
274
|
+
expect(helpers.formatSettingsResponse({})).toMatchObject({
|
|
275
|
+
inputHistoryScope: 'session',
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('defaults missing inputHistoryLimit to 40 in formatted settings responses and preserves valid values', () => {
|
|
280
|
+
const helpers = createTestHelpers();
|
|
281
|
+
|
|
282
|
+
expect(helpers.formatSettingsResponse({})).toMatchObject({
|
|
283
|
+
inputHistoryLimit: DEFAULT_INPUT_HISTORY_LIMIT,
|
|
284
|
+
});
|
|
285
|
+
expect(helpers.formatSettingsResponse({ inputHistoryLimit: 1 })).toMatchObject({
|
|
286
|
+
inputHistoryLimit: 1,
|
|
287
|
+
});
|
|
288
|
+
expect(helpers.formatSettingsResponse({ inputHistoryLimit: 100 })).toMatchObject({
|
|
289
|
+
inputHistoryLimit: 100,
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
|
|
137
293
|
it('sanitizes the persisted terminal shell', () => {
|
|
138
294
|
const helpers = createTestHelpers();
|
|
139
295
|
|
|
@@ -316,6 +472,27 @@ describe('settings helpers', () => {
|
|
|
316
472
|
});
|
|
317
473
|
});
|
|
318
474
|
|
|
475
|
+
it('accepts and rejects invalid Enter-to-send preference values', () => {
|
|
476
|
+
const helpers = createTestHelpers();
|
|
477
|
+
|
|
478
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: true, enterToSendConfigured: true })).toEqual({
|
|
479
|
+
enterToSend: true,
|
|
480
|
+
enterToSendConfigured: true,
|
|
481
|
+
});
|
|
482
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: false, enterToSendConfigured: true })).toEqual({
|
|
483
|
+
enterToSend: false,
|
|
484
|
+
enterToSendConfigured: true,
|
|
485
|
+
});
|
|
486
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: false, enterToSendConfigured: false })).toEqual({
|
|
487
|
+
enterToSend: false,
|
|
488
|
+
enterToSendConfigured: false,
|
|
489
|
+
});
|
|
490
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: 'true' })).toEqual({});
|
|
491
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSend: 1 })).toEqual({});
|
|
492
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: 'true' })).toEqual({});
|
|
493
|
+
expect(helpers.sanitizeSettingsUpdate({ enterToSendConfigured: 1 })).toEqual({});
|
|
494
|
+
});
|
|
495
|
+
|
|
319
496
|
it('accepts dismissed OpenCode update toast version as a persisted shared setting', () => {
|
|
320
497
|
const helpers = createTestHelpers();
|
|
321
498
|
|
|
@@ -353,24 +530,24 @@ describe('settings helpers', () => {
|
|
|
353
530
|
|
|
354
531
|
it('includes transient desktop LAN access runtime status in desktop settings response', () => {
|
|
355
532
|
const helpers = createTestHelpers();
|
|
356
|
-
const previousRuntime = process.env.
|
|
357
|
-
const previousActive = process.env.
|
|
358
|
-
const previousReason = process.env.
|
|
533
|
+
const previousRuntime = process.env.AIWORKER_RUNTIME;
|
|
534
|
+
const previousActive = process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE;
|
|
535
|
+
const previousReason = process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
|
|
359
536
|
try {
|
|
360
|
-
process.env.
|
|
361
|
-
process.env.
|
|
362
|
-
process.env.
|
|
537
|
+
process.env.AIWORKER_RUNTIME = 'desktop';
|
|
538
|
+
process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE = 'false';
|
|
539
|
+
process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = 'missing-password';
|
|
363
540
|
|
|
364
541
|
const response = helpers.formatSettingsResponse({ desktopLanAccessEnabled: true });
|
|
365
542
|
expect(response.desktopLanAccessActive).toBe(false);
|
|
366
543
|
expect(response.desktopLanAccessBlockedReason).toBe('missing-password');
|
|
367
544
|
} finally {
|
|
368
|
-
if (typeof previousRuntime === 'string') process.env.
|
|
369
|
-
else delete process.env.
|
|
370
|
-
if (typeof previousActive === 'string') process.env.
|
|
371
|
-
else delete process.env.
|
|
372
|
-
if (typeof previousReason === 'string') process.env.
|
|
373
|
-
else delete process.env.
|
|
545
|
+
if (typeof previousRuntime === 'string') process.env.AIWORKER_RUNTIME = previousRuntime;
|
|
546
|
+
else delete process.env.AIWORKER_RUNTIME;
|
|
547
|
+
if (typeof previousActive === 'string') process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE = previousActive;
|
|
548
|
+
else delete process.env.AIWORKER_DESKTOP_LAN_ACCESS_ACTIVE;
|
|
549
|
+
if (typeof previousReason === 'string') process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON = previousReason;
|
|
550
|
+
else delete process.env.AIWORKER_DESKTOP_LAN_ACCESS_BLOCKED_REASON;
|
|
374
551
|
}
|
|
375
552
|
});
|
|
376
553
|
|
|
@@ -692,8 +692,8 @@ export const createSettingsRuntime = (deps) => {
|
|
|
692
692
|
return { settings, changed: false };
|
|
693
693
|
}
|
|
694
694
|
|
|
695
|
-
const defaultLight = '
|
|
696
|
-
const defaultDark = '
|
|
695
|
+
const defaultLight = 'openchamber-light';
|
|
696
|
+
const defaultDark = 'openchamber-dark';
|
|
697
697
|
|
|
698
698
|
let nextLightThemeId = hasLight ? settings.lightThemeId : undefined;
|
|
699
699
|
let nextDarkThemeId = hasDark ? settings.darkThemeId : undefined;
|
|
@@ -39,6 +39,35 @@ const createRuntime = async () => {
|
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
describe('settings runtime', () => {
|
|
42
|
+
it('uses AiWorker themes when a new install has no theme preferences', async () => {
|
|
43
|
+
const { runtime, cleanup } = await createRuntime();
|
|
44
|
+
try {
|
|
45
|
+
await expect(runtime.readSettingsFromDiskMigrated()).resolves.toMatchObject({
|
|
46
|
+
lightThemeId: 'openchamber-light',
|
|
47
|
+
darkThemeId: 'openchamber-dark',
|
|
48
|
+
});
|
|
49
|
+
} finally {
|
|
50
|
+
await cleanup();
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('preserves existing theme preferences during theme migration', async () => {
|
|
55
|
+
const { runtime, settingsFilePath, cleanup } = await createRuntime();
|
|
56
|
+
try {
|
|
57
|
+
await fsPromises.writeFile(settingsFilePath, JSON.stringify({
|
|
58
|
+
lightThemeId: 'flexoki-light',
|
|
59
|
+
darkThemeId: 'flexoki-dark',
|
|
60
|
+
}), 'utf8');
|
|
61
|
+
|
|
62
|
+
await expect(runtime.readSettingsFromDiskMigrated()).resolves.toMatchObject({
|
|
63
|
+
lightThemeId: 'flexoki-light',
|
|
64
|
+
darkThemeId: 'flexoki-dark',
|
|
65
|
+
});
|
|
66
|
+
} finally {
|
|
67
|
+
await cleanup();
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
|
|
42
71
|
it('round-trips shared sidebar preferences through settings.json', async () => {
|
|
43
72
|
const { runtime, settingsFilePath, cleanup } = await createRuntime();
|
|
44
73
|
const preferences = {
|
|
@@ -6,7 +6,10 @@ import { parse as parseJsonc, printParseErrorCode } from 'jsonc-parser';
|
|
|
6
6
|
|
|
7
7
|
// ============== PATH CONSTANTS ==============
|
|
8
8
|
|
|
9
|
-
const OPENCODE_CONFIG_DIR = path.join(
|
|
9
|
+
const OPENCODE_CONFIG_DIR = path.join(
|
|
10
|
+
process.env.XDG_CONFIG_HOME?.trim() || path.join(os.homedir(), '.config'),
|
|
11
|
+
'opencode',
|
|
12
|
+
);
|
|
10
13
|
const AGENT_DIR = path.join(OPENCODE_CONFIG_DIR, 'agents');
|
|
11
14
|
const COMMAND_DIR = path.join(OPENCODE_CONFIG_DIR, 'commands');
|
|
12
15
|
const SKILL_DIR = path.join(OPENCODE_CONFIG_DIR, 'skills');
|
|
@@ -320,7 +323,7 @@ function writeConfig(config, filePath = CONFIG_FILE) {
|
|
|
320
323
|
parseConfigObject(existing, filePath);
|
|
321
324
|
}
|
|
322
325
|
|
|
323
|
-
const backupFile = `${filePath}.
|
|
326
|
+
const backupFile = `${filePath}.aiworker.backup`;
|
|
324
327
|
fs.copyFileSync(filePath, backupFile);
|
|
325
328
|
console.log(`Created config backup: ${backupFile}`);
|
|
326
329
|
}
|
|
@@ -49,7 +49,7 @@ describe('parseMdFile', () => {
|
|
|
49
49
|
});
|
|
50
50
|
|
|
51
51
|
it('parses frontmatter whose closing --- is at end-of-file without a trailing newline', () => {
|
|
52
|
-
// gray-matter (used by OpenCode) accepts this shape;
|
|
52
|
+
// gray-matter (used by OpenCode) accepts this shape; AiWorker must too,
|
|
53
53
|
// otherwise a later save duplicates the YAML block.
|
|
54
54
|
const file = writeFixture('eof-close.md', [
|
|
55
55
|
'---',
|
|
@@ -147,7 +147,7 @@ describe('updateAgent frontmatter preservation', () => {
|
|
|
147
147
|
|
|
148
148
|
it('updates the model in place without duplicating YAML for a file with EOF-closed frontmatter', () => {
|
|
149
149
|
// Repro of OPE-178: the file's closing --- sits at EOF (no trailing
|
|
150
|
-
// newline). OpenCode parses it;
|
|
150
|
+
// newline). OpenCode parses it; AiWorker previously treated the whole
|
|
151
151
|
// file as the prompt body and prepended a second frontmatter block on save.
|
|
152
152
|
const projectDir = path.join(FIXTURE_DIR, 'project');
|
|
153
153
|
const agentPath = path.join(projectDir, '.opencode', 'agents', 'strateg.md');
|
|
@@ -305,7 +305,7 @@ describe('readConfigFile / writeConfig JSONC safety (issue #2923)', () => {
|
|
|
305
305
|
/cannot be loaded safely/,
|
|
306
306
|
);
|
|
307
307
|
expect(fs.readFileSync(file, 'utf8')).toBe(PARTIAL_PARSE_CONFIG);
|
|
308
|
-
expect(fs.existsSync(`${file}.
|
|
308
|
+
expect(fs.existsSync(`${file}.aiworker.backup`)).toBe(false);
|
|
309
309
|
});
|
|
310
310
|
|
|
311
311
|
it('preserves a valid config across MCP updates', () => {
|
|
@@ -318,7 +318,7 @@ describe('readConfigFile / writeConfig JSONC safety (issue #2923)', () => {
|
|
|
318
318
|
expect(rewritten.plugin).toEqual(['opencode-see-image']);
|
|
319
319
|
expect(rewritten.provider['ollama-cloud'].name).toBe('Ollama Cloud');
|
|
320
320
|
expect(rewritten.mcp.openproject.enabled).toBe(false);
|
|
321
|
-
expect(fs.readFileSync(`${file}.
|
|
321
|
+
expect(fs.readFileSync(`${file}.aiworker.backup`, 'utf8')).toBe(VALID_CONFIG);
|
|
322
322
|
});
|
|
323
323
|
|
|
324
324
|
it('does not wipe an unparseable user config during MCP mutation attempts', () => {
|
|
@@ -331,7 +331,7 @@ describe('readConfigFile / writeConfig JSONC safety (issue #2923)', () => {
|
|
|
331
331
|
/cannot be loaded safely/,
|
|
332
332
|
);
|
|
333
333
|
expect(fs.readFileSync(file, 'utf8')).toBe(PARTIAL_PARSE_CONFIG);
|
|
334
|
-
expect(fs.existsSync(`${file}.
|
|
334
|
+
expect(fs.existsSync(`${file}.aiworker.backup`)).toBe(false);
|
|
335
335
|
} finally {
|
|
336
336
|
if (previousOpenCodeConfig === undefined) delete process.env.OPENCODE_CONFIG;
|
|
337
337
|
else process.env.OPENCODE_CONFIG = previousOpenCodeConfig;
|
|
@@ -350,7 +350,7 @@ describe('readConfigFile / writeConfig JSONC safety (issue #2923)', () => {
|
|
|
350
350
|
/cannot be loaded safely/,
|
|
351
351
|
);
|
|
352
352
|
expect(fs.readFileSync(yamlish, 'utf8')).toBe('mcp:\n openproject:\n type: remote\n');
|
|
353
|
-
expect(fs.existsSync(`${yamlish}.
|
|
353
|
+
expect(fs.existsSync(`${yamlish}.aiworker.backup`)).toBe(false);
|
|
354
354
|
});
|
|
355
355
|
|
|
356
356
|
it('keeps a valid custom layer readable when a project layer is unparseable', () => {
|
|
@@ -377,7 +377,7 @@ describe('readConfigFile / writeConfig JSONC safety (issue #2923)', () => {
|
|
|
377
377
|
expect(rewritten.plugin).toEqual(['opencode-see-image']);
|
|
378
378
|
expect(rewritten.mcp.openproject.enabled).toBe(false);
|
|
379
379
|
expect(fs.readFileSync(projectFile, 'utf8')).toBe(PARTIAL_PARSE_CONFIG);
|
|
380
|
-
expect(fs.existsSync(`${projectFile}.
|
|
380
|
+
expect(fs.existsSync(`${projectFile}.aiworker.backup`)).toBe(false);
|
|
381
381
|
} finally {
|
|
382
382
|
if (previousOpenCodeConfig === undefined) delete process.env.OPENCODE_CONFIG;
|
|
383
383
|
else process.env.OPENCODE_CONFIG = previousOpenCodeConfig;
|
|
@@ -11,6 +11,7 @@ export const createGracefulShutdownRuntime = (dependencies) => {
|
|
|
11
11
|
sessionAssistRuntime,
|
|
12
12
|
sessionGoalRuntime,
|
|
13
13
|
contextObligatoryRuntime,
|
|
14
|
+
messageQueueRuntime,
|
|
14
15
|
scheduledTasksRuntime,
|
|
15
16
|
getHealthCheckInterval,
|
|
16
17
|
clearHealthCheckInterval,
|
|
@@ -47,6 +48,7 @@ export const createGracefulShutdownRuntime = (dependencies) => {
|
|
|
47
48
|
sessionAssistRuntime?.stop?.();
|
|
48
49
|
sessionGoalRuntime?.stop?.();
|
|
49
50
|
contextObligatoryRuntime?.stop?.();
|
|
51
|
+
messageQueueRuntime?.stop?.();
|
|
50
52
|
scheduledTasksRuntime?.stop?.();
|
|
51
53
|
|
|
52
54
|
const healthCheckInterval = getHealthCheckInterval();
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createOpencodeClient } from '@opencode-ai/sdk/v2';
|
|
2
2
|
import { buildDeferredRestartResponse } from './config-mutation-response.js';
|
|
3
|
+
import { OPENCODE_CONFIG_DIR } from './shared.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Matches how OpenCode reads its own boolean env flags: any value other than
|
|
@@ -110,7 +111,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
110
111
|
}
|
|
111
112
|
|
|
112
113
|
const userRoots = [
|
|
113
|
-
|
|
114
|
+
OPENCODE_CONFIG_DIR,
|
|
114
115
|
path.join(home, '.opencode'),
|
|
115
116
|
path.join(home, '.claude', 'skills'),
|
|
116
117
|
path.join(home, '.agents', 'skills'),
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import fs from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
|
-
import os from 'os';
|
|
4
3
|
import yaml from 'yaml';
|
|
4
|
+
import { OPENCODE_CONFIG_DIR } from './shared.js';
|
|
5
5
|
|
|
6
|
-
const OPENCODE_CONFIG_DIR = path.join(os.homedir(), '.config', 'opencode');
|
|
7
6
|
const GLOBAL_SNIPPET_DIR = path.join(OPENCODE_CONFIG_DIR, 'snippet');
|
|
8
7
|
const GLOBAL_SNIPPET_DIR_ALT = path.join(OPENCODE_CONFIG_DIR, 'snippets');
|
|
9
8
|
const SNIPPET_EXTENSION = '.md';
|
|
@@ -21,7 +21,7 @@ const finiteNonNegative = (value) => Number.isFinite(value) && value >= 0 ? valu
|
|
|
21
21
|
const nonNegativeInteger = (value) => Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
22
22
|
|
|
23
23
|
const isStartupPerformanceEnabled = () => (
|
|
24
|
-
ENABLED_VALUES.has(String(process.env.
|
|
24
|
+
ENABLED_VALUES.has(String(process.env.AIWORKER_STARTUP_PERF ?? '').toLowerCase())
|
|
25
25
|
);
|
|
26
26
|
|
|
27
27
|
export const recordStartupPerformance = (phase, details = {}) => {
|