@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
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { fetchUpdateNotes, renderUpdateNotes } from './update-notes.js';
|
|
3
|
+
|
|
4
|
+
const compare = (a, b) => {
|
|
5
|
+
const pa = a.split('.').map(Number);
|
|
6
|
+
const pb = b.split('.').map(Number);
|
|
7
|
+
for (let i = 0; i < 3; i += 1) if (pa[i] !== pb[i]) return pa[i] - pb[i];
|
|
8
|
+
return 0;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const index = [
|
|
12
|
+
{ version: '1.2.3', date: '2026-03-03', title: 'Comments everywhere', intro: 'A short intro.', app: { new: ['**Comments:** on code.'], improvements: [], fixes: ['Chat: no freeze.'], misc: [] }, vscode: null },
|
|
13
|
+
{ version: '1.2.2', date: '2026-03-02', title: null, intro: null, app: { new: [], improvements: ['Faster.'], fixes: [], misc: [] }, vscode: null },
|
|
14
|
+
{ version: '1.2.1', date: '2026-03-01', title: 'Old', intro: null, app: { new: ['Older.'], improvements: [], fixes: [], misc: [] }, vscode: null },
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
describe('renderUpdateNotes', () => {
|
|
18
|
+
it('renders the releases after the installed version up to the offered one, newest first', () => {
|
|
19
|
+
expect(renderUpdateNotes(index, '1.2.1', '1.2.3', compare)).toBe(`## [1.2.3] - 2026-03-03
|
|
20
|
+
|
|
21
|
+
**Comments everywhere**
|
|
22
|
+
|
|
23
|
+
A short intro.
|
|
24
|
+
|
|
25
|
+
### New
|
|
26
|
+
|
|
27
|
+
- **Comments:** on code.
|
|
28
|
+
|
|
29
|
+
### Fixes
|
|
30
|
+
|
|
31
|
+
- Chat: no freeze.
|
|
32
|
+
|
|
33
|
+
## [1.2.2] - 2026-03-02
|
|
34
|
+
|
|
35
|
+
### Improvements
|
|
36
|
+
|
|
37
|
+
- Faster.`);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('returns null when nothing lies in the range or the payload is not an index', () => {
|
|
41
|
+
expect(renderUpdateNotes(index, '1.2.3', '1.2.3', compare)).toBe(null);
|
|
42
|
+
expect(renderUpdateNotes({ entries: [] }, '1.0.0', '9.9.9', compare)).toBe(null);
|
|
43
|
+
expect(renderUpdateNotes([{ version: 'nope' }, { version: '1.2.2', date: '2026' }], '1.0.0', '9.9.9', compare)).toBe(null);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('fetchUpdateNotes', () => {
|
|
48
|
+
it('turns a failed request or a thrown fetch into null', async () => {
|
|
49
|
+
const notFound = async () => ({ ok: false });
|
|
50
|
+
expect(await fetchUpdateNotes('1.0.0', '2.0.0', compare, { fetch: notFound })).toBe(null);
|
|
51
|
+
const throwing = async () => { throw new Error('offline'); };
|
|
52
|
+
expect(await fetchUpdateNotes('1.0.0', '2.0.0', compare, { fetch: throwing })).toBe(null);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('renders a successful response', async () => {
|
|
56
|
+
const ok = async () => ({ ok: true, json: async () => index });
|
|
57
|
+
expect(await fetchUpdateNotes('1.2.2', '1.2.3', compare, { fetch: ok })).toMatch(/^## \[1\.2\.3\] - 2026-03-03\n\n\*\*Comments everywhere\*\*/);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -86,15 +86,15 @@ describe('remote client auth runtime', () => {
|
|
|
86
86
|
it('keeps the replaced record label on a dedupe re-mint without an explicit label', async () => {
|
|
87
87
|
const { dir, runtime } = await createRuntime();
|
|
88
88
|
try {
|
|
89
|
-
await runtime.createClient({ label: 'Iryna iPhone', dedupeKey: 'mobile:device-1', fallbackLabel: '
|
|
90
|
-
const remint = await runtime.createClient({ dedupeKey: 'mobile:device-1', fallbackLabel: '
|
|
89
|
+
await runtime.createClient({ label: 'Iryna iPhone', dedupeKey: 'mobile:device-1', fallbackLabel: 'AiWorker Mobile' });
|
|
90
|
+
const remint = await runtime.createClient({ dedupeKey: 'mobile:device-1', fallbackLabel: 'AiWorker Mobile' });
|
|
91
91
|
expect(remint.client.label).toBe('Iryna iPhone');
|
|
92
92
|
|
|
93
|
-
const renamed = await runtime.createClient({ label: 'Work phone', dedupeKey: 'mobile:device-1', fallbackLabel: '
|
|
93
|
+
const renamed = await runtime.createClient({ label: 'Work phone', dedupeKey: 'mobile:device-1', fallbackLabel: 'AiWorker Mobile' });
|
|
94
94
|
expect(renamed.client.label).toBe('Work phone');
|
|
95
95
|
|
|
96
|
-
const fresh = await runtime.createClient({ dedupeKey: 'mobile:device-2', fallbackLabel: '
|
|
97
|
-
expect(fresh.client.label).toBe('
|
|
96
|
+
const fresh = await runtime.createClient({ dedupeKey: 'mobile:device-2', fallbackLabel: 'AiWorker Mobile' });
|
|
97
|
+
expect(fresh.client.label).toBe('AiWorker Mobile');
|
|
98
98
|
} finally {
|
|
99
99
|
await fs.rm(dir, { recursive: true, force: true });
|
|
100
100
|
}
|
|
@@ -5,15 +5,15 @@ const isRecord = (value) => Boolean(value && typeof value === 'object' && !Array
|
|
|
5
5
|
|
|
6
6
|
const readContextState = (session) => {
|
|
7
7
|
const metadata = isRecord(session?.metadata) ? session.metadata : {};
|
|
8
|
-
const
|
|
9
|
-
const messages = Array.isArray(
|
|
10
|
-
?
|
|
8
|
+
const aiworker = isRecord(metadata.aiworker) ? metadata.aiworker : {};
|
|
9
|
+
const messages = Array.isArray(aiworker.context_obligatory_messages)
|
|
10
|
+
? aiworker.context_obligatory_messages.filter((item) =>
|
|
11
11
|
isRecord(item)
|
|
12
12
|
&& typeof item.id === 'string'
|
|
13
13
|
&& typeof item.createdAt === 'number'
|
|
14
14
|
&& (item.role === 'user' || item.role === 'assistant'))
|
|
15
15
|
: [];
|
|
16
|
-
return { metadata,
|
|
16
|
+
return { metadata, aiworker, messages };
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
const buildContextPrompt = (entries) => {
|
|
@@ -89,7 +89,7 @@ export const createContextObligatoryRuntime = ({
|
|
|
89
89
|
const summary = recent.toReversed().find((message) =>
|
|
90
90
|
message?.info?.role === 'assistant' && message.info.summary === true)?.info;
|
|
91
91
|
if (!summary?.id || !summary?.time?.completed) return;
|
|
92
|
-
if (state.
|
|
92
|
+
if (state.aiworker.context_obligatory_last_compaction_message_id === summary.id) return;
|
|
93
93
|
|
|
94
94
|
const fetched = await Promise.allSettled(state.messages.map(async (pinned) => {
|
|
95
95
|
const message = await openCodeFetch(
|
|
@@ -138,8 +138,8 @@ export const createContextObligatoryRuntime = ({
|
|
|
138
138
|
body: {
|
|
139
139
|
metadata: {
|
|
140
140
|
...freshState.metadata,
|
|
141
|
-
|
|
142
|
-
...freshState.
|
|
141
|
+
aiworker: {
|
|
142
|
+
...freshState.aiworker,
|
|
143
143
|
context_obligatory_last_compaction_message_id: summary.id,
|
|
144
144
|
// Recorded together with the cursor: the session now carries this
|
|
145
145
|
// knowledge again, so the next send must not repeat it.
|
|
@@ -23,7 +23,7 @@ describe('context obligatory runtime', () => {
|
|
|
23
23
|
sessionReads += 1;
|
|
24
24
|
return json({
|
|
25
25
|
id: 'ses_1',
|
|
26
|
-
metadata: {
|
|
26
|
+
metadata: { aiworker: { context_obligatory_messages: [
|
|
27
27
|
{ id: 'msg_2', createdAt: 20, role: 'assistant' },
|
|
28
28
|
{ id: 'msg_1', createdAt: 10, role: 'user' },
|
|
29
29
|
] } },
|
|
@@ -58,7 +58,7 @@ describe('context obligatory runtime', () => {
|
|
|
58
58
|
expect(payload.parts[0].text).toContain('Only if no tasks or next steps remain');
|
|
59
59
|
expect(payload.parts[0].text).toContain('no more than one short paragraph');
|
|
60
60
|
const patch = requests.find((request) => request.method === 'PATCH');
|
|
61
|
-
expect(JSON.parse(patch.body).metadata.
|
|
61
|
+
expect(JSON.parse(patch.body).metadata.aiworker.context_obligatory_last_compaction_message_id).toBe('msg_summary');
|
|
62
62
|
expect(sessionReads).toBe(2);
|
|
63
63
|
runtime.stop();
|
|
64
64
|
});
|
|
@@ -75,7 +75,7 @@ describe('context obligatory runtime', () => {
|
|
|
75
75
|
if (url.pathname === '/session/ses_1' && init.method === 'PATCH') return json({});
|
|
76
76
|
if (url.pathname === '/session/ses_1') return json({
|
|
77
77
|
id: 'ses_1',
|
|
78
|
-
metadata: {
|
|
78
|
+
metadata: { aiworker: { knowledge_context_delivered: 'sig-before-compaction' } },
|
|
79
79
|
});
|
|
80
80
|
if (url.pathname === '/session/ses_1/message') return json([
|
|
81
81
|
{ info: { id: 'msg_agent', role: 'assistant', providerID: 'provider', modelID: 'model', agent: 'build' } },
|
|
@@ -112,7 +112,7 @@ describe('context obligatory runtime', () => {
|
|
|
112
112
|
expect(JSON.parse(prompt.body).parts[0].text).toContain('Remember this.');
|
|
113
113
|
const patch = requests.find((request) => request.method === 'PATCH');
|
|
114
114
|
// Recorded with the cursor, so the next ordinary send does not repeat it.
|
|
115
|
-
expect(JSON.parse(patch.body).metadata.
|
|
115
|
+
expect(JSON.parse(patch.body).metadata.aiworker.knowledge_context_delivered).toBe('sig-1');
|
|
116
116
|
});
|
|
117
117
|
|
|
118
118
|
it('sends pinned messages and project knowledge as one message', async () => {
|
|
@@ -123,7 +123,7 @@ describe('context obligatory runtime', () => {
|
|
|
123
123
|
if (url.pathname === '/session/ses_1' && init.method === 'PATCH') return json({});
|
|
124
124
|
if (url.pathname === '/session/ses_1') return json({
|
|
125
125
|
id: 'ses_1',
|
|
126
|
-
metadata: {
|
|
126
|
+
metadata: { aiworker: { context_obligatory_messages: [{ id: 'msg_1', createdAt: 10, role: 'user' }] } },
|
|
127
127
|
});
|
|
128
128
|
if (url.pathname === '/session/ses_1/message') return json([
|
|
129
129
|
{ info: { id: 'msg_agent', role: 'assistant', providerID: 'provider', modelID: 'model', agent: 'build' } },
|
|
@@ -143,7 +143,7 @@ export const parseNetstatListeners = (output) => {
|
|
|
143
143
|
/**
|
|
144
144
|
* Narrows raw listeners to the ones worth offering as a preview target.
|
|
145
145
|
*
|
|
146
|
-
* `ownPorts` removes
|
|
146
|
+
* `ownPorts` removes AiWorker's own listeners — offering the user a preview
|
|
147
147
|
* of the app they are already looking at is pure noise.
|
|
148
148
|
*/
|
|
149
149
|
export const selectDevServerCandidates = (listeners, { ownPorts = [], ownPids = [] } = {}) => {
|
|
@@ -169,7 +169,7 @@ const PROC_LOOPBACK_ADDRESSES = new Set(['0100007F', '00000000000000000000000001
|
|
|
169
169
|
* Parses `/proc/net/tcp` and `/proc/net/tcp6`.
|
|
170
170
|
*
|
|
171
171
|
* The fallback for hosts without `lsof`, which is most containers — and a
|
|
172
|
-
* deployed
|
|
172
|
+
* deployed AiWorker is exactly where a dev server needs discovering. Reads a
|
|
173
173
|
* kernel file rather than shelling out, so it cannot be defeated by a missing
|
|
174
174
|
* binary or a stripped PATH.
|
|
175
175
|
*
|
|
@@ -100,11 +100,11 @@ describe('candidate selection', () => {
|
|
|
100
100
|
const listeners = [
|
|
101
101
|
{ port: 5173, pid: 10, command: 'node' },
|
|
102
102
|
{ port: 5432, pid: 11, command: 'postgres' },
|
|
103
|
-
{ port: 4096, pid: 12, command: '
|
|
103
|
+
{ port: 4096, pid: 12, command: 'aiworker' },
|
|
104
104
|
{ port: 3000, pid: 13, command: 'node' },
|
|
105
105
|
];
|
|
106
106
|
|
|
107
|
-
test('drops
|
|
107
|
+
test('drops AiWorker own ports so the app never offers itself', () => {
|
|
108
108
|
const ports = selectDevServerCandidates(listeners, { ownPorts: [4096] }).map((entry) => entry.port);
|
|
109
109
|
expect(ports).toEqual([5173, 3000]);
|
|
110
110
|
});
|
|
@@ -50,7 +50,7 @@ const runCommand = (spawn, command, args, timeoutMs) => new Promise((resolve) =>
|
|
|
50
50
|
|
|
51
51
|
/**
|
|
52
52
|
* Reads the kernel's socket tables. Containers routinely ship without `lsof`,
|
|
53
|
-
* and a deployed
|
|
53
|
+
* and a deployed AiWorker is precisely where discovery has to work, so this
|
|
54
54
|
* is tried whenever the command is unavailable.
|
|
55
55
|
*/
|
|
56
56
|
const readProcListeners = async (readFile) => {
|
|
@@ -20,7 +20,13 @@ and what made it fragile per framework.
|
|
|
20
20
|
- `client.js` is the local end: it binds a loopback listener on the user's
|
|
21
21
|
machine and pipes each accepted connection through one WebSocket. It lives in
|
|
22
22
|
this package because it needs a WebSocket client the package already depends
|
|
23
|
-
on; the desktop shell drives it over IPC
|
|
23
|
+
on; the desktop shell drives it over IPC for directly reachable HTTP(S)
|
|
24
|
+
runtimes.
|
|
25
|
+
- Relay-only runtimes use `packages/electron/relay-dev-tunnel.mjs` for the local
|
|
26
|
+
listener. Each accepted connection gets an Electron `MessagePort`; the trusted
|
|
27
|
+
renderer carries its bytes through the active E2EE relay. This keeps relay
|
|
28
|
+
credentials and encryption in their existing renderer owner instead of
|
|
29
|
+
duplicating them in Electron main.
|
|
24
30
|
- Port discovery is not owned here. `runtime.js` is given the reachable set by
|
|
25
31
|
the same dev-server discovery the user's own list is built from.
|
|
26
32
|
- The browser panel decides when to tunnel; this module never chooses a target.
|
|
@@ -40,9 +46,12 @@ and what made it fragile per framework.
|
|
|
40
46
|
usual origin allowlist applies unchanged. That check is a CSRF defence: a
|
|
41
47
|
hostile page can make a browser open a WebSocket carrying ambient cookies,
|
|
42
48
|
and the origin is what exposes it.
|
|
43
|
-
- With no `Origin` the request must carry client-token auth
|
|
44
|
-
|
|
45
|
-
|
|
49
|
+
- With no `Origin` the request must carry client-token auth or a short-lived
|
|
50
|
+
URL token. The bearer case is the desktop main process. The URL-token case
|
|
51
|
+
is the trusted renderer carrying the socket through the E2EE relay.
|
|
52
|
+
- Through the E2EE relay, the trusted renderer mints a short-lived URL token
|
|
53
|
+
and includes it in the virtual WebSocket URL. The relay host and URL-token
|
|
54
|
+
allowlists accept exactly `/api/dev-tunnel`, not subpaths.
|
|
46
55
|
- Concurrency is capped per host, not per page, because one page load opens
|
|
47
56
|
many sockets.
|
|
48
57
|
- A connection that cannot be established fails the socket rather than holding
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Local end of the dev-server tunnel.
|
|
3
3
|
*
|
|
4
4
|
* Binds a loopback listener on this machine and pipes every connection to a
|
|
5
|
-
* dev server on the
|
|
5
|
+
* dev server on the AiWorker host. The point of binding a real local port —
|
|
6
6
|
* rather than serving the remote page under a path on some other origin — is
|
|
7
7
|
* that the page then has its own origin at the root of its own host. Absolute
|
|
8
8
|
* URLs resolve, cookies scope correctly, HMR sockets connect, and nothing has
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Raw byte tunnel to a dev server running on the
|
|
2
|
+
* Raw byte tunnel to a dev server running on the AiWorker host.
|
|
3
3
|
*
|
|
4
4
|
* This is what lets a desktop client preview a dev server that lives on another
|
|
5
5
|
* machine without rewriting anything. The client binds its own local port and
|
|
@@ -20,9 +20,9 @@
|
|
|
20
20
|
*
|
|
21
21
|
* - With an `Origin` header, the request came from a browser context and the
|
|
22
22
|
* usual origin check applies unchanged.
|
|
23
|
-
* - With no `Origin`, the request must carry client-token auth
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* - With no `Origin`, the request must carry client-token auth or a short-lived
|
|
24
|
+
* URL token. The URL-token case is used only by the trusted renderer through
|
|
25
|
+
* the E2EE relay; the UI-auth allowlist limits it to this exact path.
|
|
26
26
|
*/
|
|
27
27
|
import net from 'node:net';
|
|
28
28
|
import { WebSocketServer } from 'ws';
|
|
@@ -133,7 +133,7 @@ export function createDevTunnelRuntime({
|
|
|
133
133
|
void (async () => {
|
|
134
134
|
try {
|
|
135
135
|
if (uiAuthController?.enabled) {
|
|
136
|
-
const auth = await uiAuthController.resolveAuthContext(req, null, { allowUrlToken:
|
|
136
|
+
const auth = await uiAuthController.resolveAuthContext(req, null, { allowUrlToken: true });
|
|
137
137
|
if (!auth) {
|
|
138
138
|
rejectWebSocketUpgrade(socket, 401, 'UI authentication required');
|
|
139
139
|
return;
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from 'bun:test';
|
|
2
2
|
import http from 'node:http';
|
|
3
3
|
import net from 'node:net';
|
|
4
|
+
import WebSocket from 'ws';
|
|
4
5
|
|
|
5
6
|
import { createDevTunnelClient } from './client.js';
|
|
6
7
|
import { createDevTunnelRuntime, isDevTunnelPath } from './runtime.js';
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
|
-
* These exercise the real socket path end to end: a dev server, an
|
|
10
|
+
* These exercise the real socket path end to end: a dev server, an AiWorker
|
|
10
11
|
* host tunnelling to it, and a client binding a local port. Anything less would
|
|
11
12
|
* not prove the thing that matters — that a page loads over the tunnel exactly
|
|
12
13
|
* as it does locally.
|
|
@@ -228,6 +229,12 @@ describe('dev tunnel authentication', () => {
|
|
|
228
229
|
enabled: true,
|
|
229
230
|
resolveAuthContext: async () => ({ type: 'session' }),
|
|
230
231
|
};
|
|
232
|
+
const urlTokenAuth = {
|
|
233
|
+
enabled: true,
|
|
234
|
+
resolveAuthContext: async (req, _res, options) => (
|
|
235
|
+
options?.allowUrlToken === true && req.url.includes('oc_url_token=good') ? { type: 'client', token: 'url:authenticated' } : null
|
|
236
|
+
),
|
|
237
|
+
};
|
|
231
238
|
|
|
232
239
|
test('accepts a bearer-authenticated client that sends no origin', async () => {
|
|
233
240
|
const devPort = await startDevServer((_req, res) => res.end('ok'));
|
|
@@ -243,6 +250,19 @@ describe('dev tunnel authentication', () => {
|
|
|
243
250
|
expect((await httpGet(localPort, '/')).body).toBe('ok');
|
|
244
251
|
});
|
|
245
252
|
|
|
253
|
+
test('accepts a URL-token client carried by the E2EE relay', async () => {
|
|
254
|
+
const devPort = await startDevServer((_req, res) => res.end('relay-ok'));
|
|
255
|
+
const host = await startHost({ allowedPorts: [devPort], auth: urlTokenAuth });
|
|
256
|
+
|
|
257
|
+
const body = await new Promise((resolve, reject) => {
|
|
258
|
+
const socket = new WebSocket(`ws://127.0.0.1:${host.port}/api/dev-tunnel?port=${devPort}&oc_url_token=good`);
|
|
259
|
+
socket.on('open', () => socket.send('GET / HTTP/1.1\r\nHost: localhost\r\nConnection: close\r\n\r\n'));
|
|
260
|
+
socket.on('message', (data) => resolve(Buffer.from(data).toString()));
|
|
261
|
+
socket.on('error', reject);
|
|
262
|
+
});
|
|
263
|
+
expect(body).toContain('relay-ok');
|
|
264
|
+
});
|
|
265
|
+
|
|
246
266
|
test('rejects a client with no credentials', async () => {
|
|
247
267
|
const devPort = await startDevServer((_req, res) => res.end('ok'));
|
|
248
268
|
const host = await startHost({ allowedPorts: [devPort], auth: clientAuth });
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Catalog of local sherpa-onnx STT models available for dictation.
|
|
3
3
|
* Models are downloaded on demand from the k2-fsa GitHub releases and
|
|
4
|
-
* extracted under the
|
|
4
|
+
* extracted under the AiWorker speech-models directory.
|
|
5
5
|
*
|
|
6
6
|
* `type` selects the recognizer construction path in the worker:
|
|
7
7
|
* - 'nemo_transducer': encoder/decoder/joiner transducer (Parakeet)
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Dictation local-speech worker process.
|
|
3
3
|
*
|
|
4
4
|
* Hosts the sherpa-onnx native inference (Parakeet STT) in a separate process
|
|
5
|
-
* so ONNX decoding never blocks the main
|
|
5
|
+
* so ONNX decoding never blocks the main AiWorker server. Communicates
|
|
6
6
|
* with the parent over child_process IPC (advanced serialization, so Buffers
|
|
7
7
|
* survive the trip as Uint8Array).
|
|
8
8
|
*
|
|
@@ -24,7 +24,7 @@ import { getLocalSttModelDir, getLocalSttModelSpec } from './model-catalog.js';
|
|
|
24
24
|
import { pcm16ToWav } from '../audio.js';
|
|
25
25
|
import path from 'path';
|
|
26
26
|
|
|
27
|
-
process.title = '
|
|
27
|
+
process.title = 'AiWorker Dictation';
|
|
28
28
|
|
|
29
29
|
const engines = new Map();
|
|
30
30
|
const ttsEngines = new Map();
|
|
@@ -56,7 +56,7 @@ export function acceptDirectoryMessageStreamWsConnection({
|
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
sendMessageStreamWsEvent(socket, { type: '
|
|
59
|
+
sendMessageStreamWsEvent(socket, { type: 'aiworker:heartbeat', timestamp: Date.now() }, { directory: 'global' });
|
|
60
60
|
}, heartbeatIntervalMs);
|
|
61
61
|
|
|
62
62
|
socket.on('close', () => {
|
|
@@ -177,7 +177,7 @@ export function createGlobalMessageStreamWsBridge({
|
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
-
sendMessageStreamWsEvent(socket, { type: '
|
|
180
|
+
sendMessageStreamWsEvent(socket, { type: 'aiworker:heartbeat', timestamp: Date.now() }, { directory: 'global' });
|
|
181
181
|
}, heartbeatIntervalMs);
|
|
182
182
|
|
|
183
183
|
socket.on('close', () => {
|
|
@@ -32,14 +32,14 @@ describe('event stream protocol helpers', () => {
|
|
|
32
32
|
|
|
33
33
|
it('derives directory from payload properties when not wrapped', () => {
|
|
34
34
|
const envelope = parseSseEventEnvelope(
|
|
35
|
-
'data: {"type":"
|
|
35
|
+
'data: {"type":"aiworker:notification","properties":{"directory":"/tmp/project"}}\n'
|
|
36
36
|
);
|
|
37
37
|
|
|
38
38
|
expect(envelope).toEqual({
|
|
39
39
|
eventId: null,
|
|
40
40
|
directory: '/tmp/project',
|
|
41
41
|
payload: {
|
|
42
|
-
type: '
|
|
42
|
+
type: 'aiworker:notification',
|
|
43
43
|
properties: { directory: '/tmp/project' },
|
|
44
44
|
},
|
|
45
45
|
});
|
|
@@ -167,14 +167,14 @@ describe('event stream protocol helpers', () => {
|
|
|
167
167
|
|
|
168
168
|
const sent = sendMessageStreamWsEvent(
|
|
169
169
|
socket,
|
|
170
|
-
{ type: '
|
|
170
|
+
{ type: 'aiworker:heartbeat', timestamp: 1 },
|
|
171
171
|
{ eventId: 'evt-2', directory: '/tmp/project' }
|
|
172
172
|
);
|
|
173
173
|
|
|
174
174
|
expect(sent).toBe(true);
|
|
175
175
|
expect(JSON.parse(rawPayload)).toEqual({
|
|
176
176
|
type: 'event',
|
|
177
|
-
payload: { type: '
|
|
177
|
+
payload: { type: 'aiworker:heartbeat', timestamp: 1 },
|
|
178
178
|
eventId: 'evt-2',
|
|
179
179
|
directory: '/tmp/project',
|
|
180
180
|
});
|
|
@@ -84,18 +84,18 @@ describe('event stream broadcaster', () => {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
|
|
87
|
-
broadcast({ type: '
|
|
87
|
+
broadcast({ type: 'aiworker:session-status' }, { eventId: 'evt-1', directory: '/tmp/project' });
|
|
88
88
|
|
|
89
89
|
expect(sseEvents).toEqual([
|
|
90
90
|
{
|
|
91
91
|
res: sseClient,
|
|
92
|
-
payload: { type: '
|
|
92
|
+
payload: { type: 'aiworker:session-status' },
|
|
93
93
|
},
|
|
94
94
|
]);
|
|
95
95
|
expect(wsPayloads).toEqual([
|
|
96
96
|
{
|
|
97
97
|
type: 'event',
|
|
98
|
-
payload: { type: '
|
|
98
|
+
payload: { type: 'aiworker:session-status' },
|
|
99
99
|
eventId: 'evt-1',
|
|
100
100
|
directory: '/tmp/project',
|
|
101
101
|
},
|
|
@@ -120,7 +120,7 @@ describe('event stream broadcaster', () => {
|
|
|
120
120
|
},
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
broadcast({ type: '
|
|
123
|
+
broadcast({ type: 'aiworker:notification' });
|
|
124
124
|
|
|
125
125
|
expect(wsClients.size).toBe(0);
|
|
126
126
|
});
|
|
@@ -475,7 +475,7 @@ describe('message stream websocket runtime', () => {
|
|
|
475
475
|
getOpenCodeAuthHeaders: () => ({}),
|
|
476
476
|
processForwardedEventPayload(payload, emitSynthetic) {
|
|
477
477
|
if (payload.type === 'session.updated') {
|
|
478
|
-
emitSynthetic({ type: '
|
|
478
|
+
emitSynthetic({ type: 'aiworker:session-status', sessionID: 'ses_1' });
|
|
479
479
|
}
|
|
480
480
|
},
|
|
481
481
|
wsClients,
|
|
@@ -502,7 +502,7 @@ describe('message stream websocket runtime', () => {
|
|
|
502
502
|
});
|
|
503
503
|
expect(socket.sent).toContainEqual({
|
|
504
504
|
type: 'event',
|
|
505
|
-
payload: { type: '
|
|
505
|
+
payload: { type: 'aiworker:session-status', sessionID: 'ses_1' },
|
|
506
506
|
directory: 'global',
|
|
507
507
|
});
|
|
508
508
|
|
|
@@ -40,6 +40,8 @@ Own filesystem API behavior for the web server runtime, including workspace-boun
|
|
|
40
40
|
|
|
41
41
|
## Notes for contributors
|
|
42
42
|
- Keep filesystem policy (workspace root checks, error mapping, exec timeout behavior) inside this module, not in the composition root.
|
|
43
|
+
- Workspace checks accept, besides the active workspace and its worktrees, the **managed roots**: the AiWorker config root and the managed chats root (`managedChatsRoot` dependency; `AIWORKER_CHATS_DIR` upstream, default `<config root>/chats`). Chat worktrees may legitimately live outside every project workspace.
|
|
44
|
+
- `GET /api/fs/home` answers `{ home, chatsRoot }`. `chatsRoot` is the server-resolved managed chats root; clients must use it instead of joining `home` + the well-known segment (a relocated root does not contain that segment).
|
|
43
45
|
- Filesystem `EPERM`/`EACCES` failures use the stable `reason: "os-permission"` response marker. Policy denials such as workspace-boundary or missing-grant failures must not use that marker because a native folder picker cannot remediate them.
|
|
44
46
|
- Read-only routes authorize the requested path against the workspace before resolving symlinks. A symlink reached through the workspace may therefore target a file outside it, while a directly requested outside path still requires an exact-path grant. Write routes keep canonical-target boundary checks.
|
|
45
47
|
- If adding new `/api/fs/*` endpoints, add them in `routes.js` and extend this document.
|