@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
|
@@ -3,16 +3,16 @@ import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
|
3
3
|
import { recordStartupPerformance } from './startup-performance.js';
|
|
4
4
|
|
|
5
5
|
describe('startup performance diagnostics', () => {
|
|
6
|
-
const previousValue = process.env.
|
|
6
|
+
const previousValue = process.env.AIWORKER_STARTUP_PERF;
|
|
7
7
|
|
|
8
8
|
afterEach(() => {
|
|
9
|
-
if (previousValue === undefined) delete process.env.
|
|
10
|
-
else process.env.
|
|
9
|
+
if (previousValue === undefined) delete process.env.AIWORKER_STARTUP_PERF;
|
|
10
|
+
else process.env.AIWORKER_STARTUP_PERF = previousValue;
|
|
11
11
|
vi.restoreAllMocks();
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
it('is disabled by default', () => {
|
|
15
|
-
delete process.env.
|
|
15
|
+
delete process.env.AIWORKER_STARTUP_PERF;
|
|
16
16
|
const info = vi.spyOn(console, 'info').mockImplementation(() => {});
|
|
17
17
|
|
|
18
18
|
recordStartupPerformance('opencode.health.ready', { durationMs: 5 });
|
|
@@ -21,7 +21,7 @@ describe('startup performance diagnostics', () => {
|
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
it('records only approved labels and numeric metadata', () => {
|
|
24
|
-
process.env.
|
|
24
|
+
process.env.AIWORKER_STARTUP_PERF = '1';
|
|
25
25
|
const info = vi.spyOn(console, 'info').mockImplementation(() => {});
|
|
26
26
|
|
|
27
27
|
recordStartupPerformance('proxy.readiness-hold', {
|
|
@@ -50,7 +50,7 @@ describe('startup performance diagnostics', () => {
|
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
it('rejects unknown phases and invalid field values', () => {
|
|
53
|
-
process.env.
|
|
53
|
+
process.env.AIWORKER_STARTUP_PERF = 'true';
|
|
54
54
|
const info = vi.spyOn(console, 'info').mockImplementation(() => {});
|
|
55
55
|
|
|
56
56
|
recordStartupPerformance('secret.phase', { durationMs: 1 });
|
|
@@ -16,7 +16,7 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
16
16
|
} = dependencies;
|
|
17
17
|
|
|
18
18
|
const resolveDistPath = () => {
|
|
19
|
-
const env = typeof process.env.
|
|
19
|
+
const env = typeof process.env.AIWORKER_DIST_DIR === 'string' ? process.env.AIWORKER_DIST_DIR.trim() : '';
|
|
20
20
|
if (env) {
|
|
21
21
|
return path.resolve(env);
|
|
22
22
|
}
|
|
@@ -61,7 +61,7 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
61
61
|
|
|
62
62
|
const registerApiOnlyFallbackRoutes = (app) => {
|
|
63
63
|
app.get(/^(?!\/api|\/auth|\/health|\/linear|.*\.(js|css|svg|png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|map)).*$/, (req, res) => {
|
|
64
|
-
const command = '
|
|
64
|
+
const command = 'aiworker connect-url --help';
|
|
65
65
|
res.status(200).format({
|
|
66
66
|
html: () => {
|
|
67
67
|
res.send(`<!doctype html>
|
|
@@ -69,7 +69,7 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
69
69
|
<head>
|
|
70
70
|
<meta charset="utf-8">
|
|
71
71
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
72
|
-
<title>
|
|
72
|
+
<title>AiWorker API-only mode</title>
|
|
73
73
|
<style>
|
|
74
74
|
:root {
|
|
75
75
|
color-scheme: dark;
|
|
@@ -171,7 +171,7 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
171
171
|
</head>
|
|
172
172
|
<body>
|
|
173
173
|
<main>
|
|
174
|
-
<svg class="logo" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="
|
|
174
|
+
<svg class="logo" viewBox="0 0 100 100" fill="none" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="AiWorker logo">
|
|
175
175
|
<path d="M50 50 L8.432 26 L8.432 74 L50 98 Z" fill="currentColor" fill-opacity=".15" stroke="currentColor" stroke-width="2" stroke-linejoin="round"/>
|
|
176
176
|
<path d="M8.432 26 L18.824 32 L18.824 44 L8.432 38 Z" fill="currentColor" fill-opacity=".2"/>
|
|
177
177
|
<path d="M18.824 32 L29.216 38 L29.216 50 L18.824 44 Z" fill="currentColor" fill-opacity=".45"/>
|
|
@@ -212,8 +212,8 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
212
212
|
<path d="M-8 -4 L8 -4 L8 12 L-8 12 Z" fill="currentColor" fill-opacity=".4"/>
|
|
213
213
|
</g>
|
|
214
214
|
</svg>
|
|
215
|
-
<h1>
|
|
216
|
-
<p>This server is ready. Open it from the
|
|
215
|
+
<h1>AiWorker is running in headless mode</h1>
|
|
216
|
+
<p>This server is ready. Open it from the AiWorker desktop or mobile app to use it.</p>
|
|
217
217
|
<div class="command">
|
|
218
218
|
<code id="connect-command">${command}</code>
|
|
219
219
|
<button type="button" id="copy-command" aria-label="Copy command" title="Copy command">
|
|
@@ -249,10 +249,10 @@ export const createStaticRoutesRuntime = (dependencies) => {
|
|
|
249
249
|
</html>`);
|
|
250
250
|
},
|
|
251
251
|
json: () => {
|
|
252
|
-
res.json({ ok: true, mode: 'api-only', message: '
|
|
252
|
+
res.json({ ok: true, mode: 'api-only', message: 'AiWorker is running in API-only mode' });
|
|
253
253
|
},
|
|
254
254
|
default: () => {
|
|
255
|
-
res.type('text/plain').send('
|
|
255
|
+
res.type('text/plain').send('AiWorker is running in API-only mode');
|
|
256
256
|
},
|
|
257
257
|
});
|
|
258
258
|
});
|
|
@@ -25,9 +25,9 @@ describe('static routes runtime', () => {
|
|
|
25
25
|
const response = await request(app).get('/sessions/abc').set('Accept', 'text/html');
|
|
26
26
|
|
|
27
27
|
expect(response.status).toBe(200);
|
|
28
|
-
expect(response.text).toContain('
|
|
29
|
-
expect(response.text).toContain('Open it from the
|
|
30
|
-
expect(response.text).toContain('
|
|
28
|
+
expect(response.text).toContain('AiWorker is running in headless mode');
|
|
29
|
+
expect(response.text).toContain('Open it from the AiWorker desktop or mobile app');
|
|
30
|
+
expect(response.text).toContain('aiworker connect-url --help');
|
|
31
31
|
expect(response.text).toContain('Copy command');
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -41,7 +41,7 @@ describe('static routes runtime', () => {
|
|
|
41
41
|
expect(response.body).toEqual({
|
|
42
42
|
ok: true,
|
|
43
43
|
mode: 'api-only',
|
|
44
|
-
message: '
|
|
44
|
+
message: 'AiWorker is running in API-only mode',
|
|
45
45
|
});
|
|
46
46
|
});
|
|
47
47
|
|
|
@@ -53,8 +53,8 @@ describe('static routes runtime', () => {
|
|
|
53
53
|
const auth = await request(app).get('/auth/session');
|
|
54
54
|
const health = await request(app).get('/health');
|
|
55
55
|
|
|
56
|
-
expect(api.body).not.toEqual({ ok: true, mode: 'api-only', message: '
|
|
57
|
-
expect(auth.body).not.toEqual({ ok: true, mode: 'api-only', message: '
|
|
58
|
-
expect(health.body).not.toEqual({ ok: true, mode: 'api-only', message: '
|
|
56
|
+
expect(api.body).not.toEqual({ ok: true, mode: 'api-only', message: 'AiWorker is running in API-only mode' });
|
|
57
|
+
expect(auth.body).not.toEqual({ ok: true, mode: 'api-only', message: 'AiWorker is running in API-only mode' });
|
|
58
|
+
expect(health.body).not.toEqual({ ok: true, mode: 'api-only', message: 'AiWorker is running in API-only mode' });
|
|
59
59
|
});
|
|
60
60
|
});
|
|
@@ -13,7 +13,7 @@ export const resolveOpenCodeUpgradeCapability = ({
|
|
|
13
13
|
if (isWindowsArm64()) {
|
|
14
14
|
return {
|
|
15
15
|
supported: false,
|
|
16
|
-
manager: '
|
|
16
|
+
manager: 'aiworker',
|
|
17
17
|
reason: 'windows-arm64-workaround',
|
|
18
18
|
};
|
|
19
19
|
}
|
|
@@ -37,7 +37,7 @@ export const resolveOpenCodeUpgradeCapability = ({
|
|
|
37
37
|
if (isBundledBinary(activeBinary)) {
|
|
38
38
|
return {
|
|
39
39
|
supported: false,
|
|
40
|
-
manager: '
|
|
40
|
+
manager: 'aiworker',
|
|
41
41
|
reason: 'bundled',
|
|
42
42
|
};
|
|
43
43
|
}
|
|
@@ -2,17 +2,17 @@ import { describe, expect, it, vi } from 'vitest';
|
|
|
2
2
|
import { resolveOpenCodeUpgradeCapability } from './upgrade-capability.js';
|
|
3
3
|
|
|
4
4
|
describe('OpenCode upgrade capability', () => {
|
|
5
|
-
it('assigns bundled binaries to the
|
|
5
|
+
it('assigns bundled binaries to the AiWorker updater', () => {
|
|
6
6
|
const isBundledBinary = vi.fn(() => true);
|
|
7
7
|
|
|
8
8
|
expect(resolveOpenCodeUpgradeCapability({
|
|
9
9
|
isExternal: false,
|
|
10
10
|
hasManagedProcess: true,
|
|
11
|
-
activeBinary: '/Applications/
|
|
11
|
+
activeBinary: '/Applications/AiWorker.app/Contents/Resources/opencode-cli/opencode',
|
|
12
12
|
isBundledBinary,
|
|
13
13
|
})).toEqual({
|
|
14
14
|
supported: false,
|
|
15
|
-
manager: '
|
|
15
|
+
manager: 'aiworker',
|
|
16
16
|
reason: 'bundled',
|
|
17
17
|
});
|
|
18
18
|
});
|
|
@@ -4,30 +4,30 @@ import fs from 'fs';
|
|
|
4
4
|
import os from 'os';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import { fileURLToPath } from 'url';
|
|
7
|
+
import { fetchUpdateNotes } from './changelog/update-notes.js';
|
|
7
8
|
|
|
8
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
9
10
|
const __dirname = path.dirname(__filename);
|
|
10
11
|
|
|
11
|
-
const PACKAGE_NAME = '@
|
|
12
|
+
const PACKAGE_NAME = '@aiworker/web';
|
|
12
13
|
const PACKAGE_PATH_SEGMENTS = PACKAGE_NAME.split('/');
|
|
13
14
|
const NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}`;
|
|
14
|
-
const
|
|
15
|
-
const GITHUB_RELEASES_URL = 'https://github.com/openchamber/openchamber/releases';
|
|
15
|
+
const GITHUB_RELEASES_URL = 'https://roweb.cn/roweb/openchamber/releases';
|
|
16
16
|
const GITHUB_RELEASES_API_URL = 'https://api.github.com/repos/openchamber/openchamber/releases';
|
|
17
17
|
let cachedDetectedPm = null;
|
|
18
18
|
|
|
19
19
|
function getSpawnSyncBaseOptions() {
|
|
20
20
|
return process.platform === 'win32' ? { windowsHide: true } : {};
|
|
21
21
|
}
|
|
22
|
-
const UPDATE_CHECK_URL = process.env.
|
|
22
|
+
const UPDATE_CHECK_URL = process.env.AIWORKER_UPDATE_API_URL || 'https://api.aiworker.dev/v1/update/check';
|
|
23
23
|
|
|
24
|
-
function
|
|
24
|
+
function getAiWorkerConfigDir() {
|
|
25
25
|
if (process.platform === 'win32') {
|
|
26
26
|
const appData = process.env.APPDATA;
|
|
27
|
-
if (appData) return path.join(appData, '
|
|
27
|
+
if (appData) return path.join(appData, 'aiworker');
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
return path.join(os.homedir(), '.config', '
|
|
30
|
+
return path.join(os.homedir(), '.config', 'aiworker');
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
function sanitizeInstallScope(scope) {
|
|
@@ -36,7 +36,7 @@ function sanitizeInstallScope(scope) {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
function getOrCreateInstallId(scope = 'web') {
|
|
39
|
-
const configDir =
|
|
39
|
+
const configDir = getAiWorkerConfigDir();
|
|
40
40
|
const normalizedScope = sanitizeInstallScope(scope);
|
|
41
41
|
const idPath = path.join(configDir, `install-id-${normalizedScope}`);
|
|
42
42
|
|
|
@@ -113,7 +113,7 @@ async function resolveAndroidApkUrl(version, candidateUrl) {
|
|
|
113
113
|
&& typeof asset.browser_download_url === 'string'
|
|
114
114
|
))
|
|
115
115
|
: [];
|
|
116
|
-
const canonicalAsset = apkAssets.find((asset) => /^
|
|
116
|
+
const canonicalAsset = apkAssets.find((asset) => /^AiWorker-.+-android\.apk$/i.test(asset.name));
|
|
117
117
|
return (canonicalAsset || apkAssets[0])?.browser_download_url;
|
|
118
118
|
} catch {
|
|
119
119
|
return undefined;
|
|
@@ -344,7 +344,7 @@ function getGlobalNodeModulesRoots(pm) {
|
|
|
344
344
|
function getOwnedPackagePathsFromGlobalBins(pm) {
|
|
345
345
|
const packagePaths = [];
|
|
346
346
|
for (const binDir of getGlobalBinDirs(pm)) {
|
|
347
|
-
const binaryName = process.platform === 'win32' ? '
|
|
347
|
+
const binaryName = process.platform === 'win32' ? 'aiworker.cmd' : 'aiworker';
|
|
348
348
|
const binaryPath = path.join(binDir, binaryName);
|
|
349
349
|
if (!fs.existsSync(binaryPath)) continue;
|
|
350
350
|
|
|
@@ -386,7 +386,7 @@ export function detectPackageManagerDetails() {
|
|
|
386
386
|
// dozen spawnSync(pm, ['bin', '-g']) calls with 10s timeouts each; under
|
|
387
387
|
// the in-process server every one blocks the Electron main event loop and
|
|
388
388
|
// manifests as a multi-second UI freeze. Short-circuit here.
|
|
389
|
-
if (process.env.
|
|
389
|
+
if (process.env.AIWORKER_RUNTIME === 'desktop') {
|
|
390
390
|
return {
|
|
391
391
|
packageManager: 'electron',
|
|
392
392
|
reason: 'desktop-runtime',
|
|
@@ -406,7 +406,7 @@ export function detectPackageManagerDetails() {
|
|
|
406
406
|
};
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
const forcedPm = process.env.
|
|
409
|
+
const forcedPm = process.env.AIWORKER_PACKAGE_MANAGER?.trim();
|
|
410
410
|
if (forcedPm && ['npm', 'pnpm', 'yarn', 'bun'].includes(forcedPm)) {
|
|
411
411
|
const forcedPmCommand = resolvePackageManagerCommand(forcedPm);
|
|
412
412
|
if (isCommandAvailable(forcedPmCommand)) {
|
|
@@ -645,7 +645,7 @@ function isPackageInstalledWith(pm) {
|
|
|
645
645
|
});
|
|
646
646
|
|
|
647
647
|
if (result.status !== 0) return false;
|
|
648
|
-
return result.stdout.includes(PACKAGE_NAME) || result.stdout.includes('
|
|
648
|
+
return result.stdout.includes(PACKAGE_NAME) || result.stdout.includes('aiworker');
|
|
649
649
|
} catch {
|
|
650
650
|
return false;
|
|
651
651
|
}
|
|
@@ -737,34 +737,9 @@ function compareVersions(left, right) {
|
|
|
737
737
|
return 0;
|
|
738
738
|
}
|
|
739
739
|
|
|
740
|
-
/**
|
|
741
|
-
* Fetch changelog notes between versions
|
|
742
|
-
*/
|
|
740
|
+
/** Release notes between the installed and the offered version, or undefined. */
|
|
743
741
|
async function fetchChangelogNotes(fromVersion, toVersion) {
|
|
744
|
-
|
|
745
|
-
const response = await fetch(CHANGELOG_URL, {
|
|
746
|
-
signal: AbortSignal.timeout(10000),
|
|
747
|
-
});
|
|
748
|
-
|
|
749
|
-
if (!response.ok) return undefined;
|
|
750
|
-
|
|
751
|
-
const changelog = await response.text();
|
|
752
|
-
const sections = changelog.split(/^## /m).slice(1);
|
|
753
|
-
|
|
754
|
-
const relevantSections = sections.filter((section) => {
|
|
755
|
-
const match = section.match(/^\[(\d+\.\d+\.\d+)\]/);
|
|
756
|
-
if (!match) return false;
|
|
757
|
-
return compareVersions(match[1], fromVersion) > 0 && compareVersions(match[1], toVersion) <= 0;
|
|
758
|
-
});
|
|
759
|
-
|
|
760
|
-
if (relevantSections.length === 0) return undefined;
|
|
761
|
-
|
|
762
|
-
return relevantSections
|
|
763
|
-
.map((s) => '## ' + s.trim())
|
|
764
|
-
.join('\n\n');
|
|
765
|
-
} catch {
|
|
766
|
-
return undefined;
|
|
767
|
-
}
|
|
742
|
+
return (await fetchUpdateNotes(fromVersion, toVersion, compareVersions)) ?? undefined;
|
|
768
743
|
}
|
|
769
744
|
|
|
770
745
|
export async function checkForUpdates(options = {}) {
|
|
@@ -785,7 +760,7 @@ export async function checkForUpdates(options = {}) {
|
|
|
785
760
|
return {
|
|
786
761
|
...remote,
|
|
787
762
|
packageManager: pm,
|
|
788
|
-
updateCommand: '
|
|
763
|
+
updateCommand: 'aiworker update',
|
|
789
764
|
};
|
|
790
765
|
}
|
|
791
766
|
}
|
|
@@ -819,7 +794,7 @@ export async function checkForUpdates(options = {}) {
|
|
|
819
794
|
downloadUrl,
|
|
820
795
|
packageManager: pm,
|
|
821
796
|
// Show our CLI command, not raw package manager command
|
|
822
|
-
updateCommand: '
|
|
797
|
+
updateCommand: 'aiworker update',
|
|
823
798
|
};
|
|
824
799
|
}
|
|
825
800
|
|
|
@@ -55,7 +55,7 @@ describe('checkForUpdates', () => {
|
|
|
55
55
|
|
|
56
56
|
it('returns available=true when both API and npm confirm a newer version', async () => {
|
|
57
57
|
fetchMock
|
|
58
|
-
.when('api.
|
|
58
|
+
.when('api.aiworker.dev', {
|
|
59
59
|
ok: true,
|
|
60
60
|
json: async () => ({
|
|
61
61
|
latestVersion: '1.10.0',
|
|
@@ -85,7 +85,7 @@ describe('checkForUpdates', () => {
|
|
|
85
85
|
|
|
86
86
|
it('returns available=false when API claims update but npm has same version', async () => {
|
|
87
87
|
fetchMock
|
|
88
|
-
.when('api.
|
|
88
|
+
.when('api.aiworker.dev', {
|
|
89
89
|
ok: true,
|
|
90
90
|
json: async () => ({
|
|
91
91
|
latestVersion: '1.10.0',
|
|
@@ -107,7 +107,7 @@ describe('checkForUpdates', () => {
|
|
|
107
107
|
|
|
108
108
|
it('returns available=false when npm only has a prerelease of the current version', async () => {
|
|
109
109
|
fetchMock
|
|
110
|
-
.when('api.
|
|
110
|
+
.when('api.aiworker.dev', Promise.reject(new Error('Network error')))
|
|
111
111
|
.when('registry.npmjs.org', {
|
|
112
112
|
ok: true,
|
|
113
113
|
json: async () => ({
|
|
@@ -122,7 +122,7 @@ describe('checkForUpdates', () => {
|
|
|
122
122
|
|
|
123
123
|
it('accepts electron desktop update claims without npm cross-checking', async () => {
|
|
124
124
|
fetchMock
|
|
125
|
-
.when('api.
|
|
125
|
+
.when('api.aiworker.dev', {
|
|
126
126
|
ok: true,
|
|
127
127
|
json: async () => ({
|
|
128
128
|
latestVersion: '1.10.0',
|
|
@@ -151,12 +151,12 @@ describe('checkForUpdates', () => {
|
|
|
151
151
|
|
|
152
152
|
it('resolves an Android APK asset when the update API returns an AAB', async () => {
|
|
153
153
|
fetchMock
|
|
154
|
-
.when('api.
|
|
154
|
+
.when('api.aiworker.dev', {
|
|
155
155
|
ok: true,
|
|
156
156
|
json: async () => ({
|
|
157
157
|
latestVersion: '1.10.0',
|
|
158
158
|
updateAvailable: true,
|
|
159
|
-
downloadUrl: 'https://
|
|
159
|
+
downloadUrl: 'https://roweb.cn/roweb/openchamber/releases/download/v1.10.0/AiWorker-1.10.0-42-android.aab',
|
|
160
160
|
}),
|
|
161
161
|
})
|
|
162
162
|
.when('api.github.com/repos/openchamber/openchamber/releases/tags/v1.10.0', {
|
|
@@ -164,16 +164,16 @@ describe('checkForUpdates', () => {
|
|
|
164
164
|
json: async () => ({
|
|
165
165
|
assets: [
|
|
166
166
|
{
|
|
167
|
-
name: '
|
|
168
|
-
browser_download_url: 'https://downloads.example/
|
|
167
|
+
name: 'AiWorker-1.10.0-42-android.aab',
|
|
168
|
+
browser_download_url: 'https://downloads.example/AiWorker-1.10.0-42-android.aab',
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
name: 'app-release.apk',
|
|
172
172
|
browser_download_url: 'https://downloads.example/app-release.apk',
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
|
-
name: '
|
|
176
|
-
browser_download_url: 'https://downloads.example/
|
|
175
|
+
name: 'AiWorker-1.10.0-42-android.apk',
|
|
176
|
+
browser_download_url: 'https://downloads.example/AiWorker-1.10.0-42-android.apk',
|
|
177
177
|
},
|
|
178
178
|
],
|
|
179
179
|
}),
|
|
@@ -185,12 +185,12 @@ describe('checkForUpdates', () => {
|
|
|
185
185
|
currentVersion: '1.9.10',
|
|
186
186
|
});
|
|
187
187
|
|
|
188
|
-
expect(result.downloadUrl).toBe('https://downloads.example/
|
|
188
|
+
expect(result.downloadUrl).toBe('https://downloads.example/AiWorker-1.10.0-42-android.apk');
|
|
189
189
|
});
|
|
190
190
|
|
|
191
191
|
it('keeps a direct Android APK URL from the update API', async () => {
|
|
192
|
-
const apkUrl = 'https://
|
|
193
|
-
fetchMock.when('api.
|
|
192
|
+
const apkUrl = 'https://roweb.cn/roweb/openchamber/releases/download/v1.10.0/AiWorker-1.10.0-42-android.apk';
|
|
193
|
+
fetchMock.when('api.aiworker.dev', {
|
|
194
194
|
ok: true,
|
|
195
195
|
json: async () => ({
|
|
196
196
|
latestVersion: '1.10.0',
|
|
@@ -211,7 +211,7 @@ describe('checkForUpdates', () => {
|
|
|
211
211
|
|
|
212
212
|
it('returns available=false when API claims update but npm is behind', async () => {
|
|
213
213
|
fetchMock
|
|
214
|
-
.when('api.
|
|
214
|
+
.when('api.aiworker.dev', {
|
|
215
215
|
ok: true,
|
|
216
216
|
json: async () => ({
|
|
217
217
|
latestVersion: '1.10.0',
|
|
@@ -234,7 +234,7 @@ describe('checkForUpdates', () => {
|
|
|
234
234
|
// --- Scenario: API says no update, npm agrees ---
|
|
235
235
|
|
|
236
236
|
it('returns available=false when API says no update and versions match', async () => {
|
|
237
|
-
fetchMock.when('api.
|
|
237
|
+
fetchMock.when('api.aiworker.dev', {
|
|
238
238
|
ok: true,
|
|
239
239
|
json: async () => ({
|
|
240
240
|
latestVersion: '1.9.10',
|
|
@@ -251,7 +251,7 @@ describe('checkForUpdates', () => {
|
|
|
251
251
|
|
|
252
252
|
it('returns available=true from npm fallback when API is unreachable and npm has newer version', async () => {
|
|
253
253
|
fetchMock
|
|
254
|
-
.when('api.
|
|
254
|
+
.when('api.aiworker.dev', Promise.reject(new Error('Network error')))
|
|
255
255
|
.when('registry.npmjs.org', {
|
|
256
256
|
ok: true,
|
|
257
257
|
json: async () => ({
|
|
@@ -271,7 +271,7 @@ describe('checkForUpdates', () => {
|
|
|
271
271
|
|
|
272
272
|
it('returns available=false from npm fallback when API is unreachable and versions match', async () => {
|
|
273
273
|
fetchMock
|
|
274
|
-
.when('api.
|
|
274
|
+
.when('api.aiworker.dev', Promise.reject(new Error('Network error')))
|
|
275
275
|
.when('registry.npmjs.org', {
|
|
276
276
|
ok: true,
|
|
277
277
|
json: async () => ({
|
|
@@ -288,7 +288,7 @@ describe('checkForUpdates', () => {
|
|
|
288
288
|
|
|
289
289
|
it('returns available=false when API returns non-ok status and versions match on npm', async () => {
|
|
290
290
|
fetchMock
|
|
291
|
-
.when('api.
|
|
291
|
+
.when('api.aiworker.dev', {
|
|
292
292
|
ok: false,
|
|
293
293
|
status: 500,
|
|
294
294
|
json: async () => ({}),
|
|
@@ -309,7 +309,7 @@ describe('checkForUpdates', () => {
|
|
|
309
309
|
|
|
310
310
|
it('returns available=false when both sources are unreachable', async () => {
|
|
311
311
|
fetchMock
|
|
312
|
-
.when('api.
|
|
312
|
+
.when('api.aiworker.dev', Promise.reject(new Error('Network error')))
|
|
313
313
|
.when('registry.npmjs.org', Promise.reject(new Error('Registry unreachable')));
|
|
314
314
|
|
|
315
315
|
const result = await checkForUpdates({ currentVersion: '1.9.10' });
|
|
@@ -63,7 +63,7 @@ export function createPermissionAutoAcceptRuntime({
|
|
|
63
63
|
policy = next;
|
|
64
64
|
loaded = true;
|
|
65
65
|
broadcastGlobalUiEvent?.({
|
|
66
|
-
type: '
|
|
66
|
+
type: 'aiworker:permission-auto-accept.updated',
|
|
67
67
|
properties: snapshot(),
|
|
68
68
|
});
|
|
69
69
|
return snapshot();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* AiWorker project context routes: notes, todos, and plan files.
|
|
3
3
|
*
|
|
4
4
|
* These replace the shared UI's direct `/api/fs/*` access to
|
|
5
5
|
* `~/.config/openchamber/projects/*`. The client no longer resolves the home
|
|
@@ -255,7 +255,7 @@ const normalizeState = (value, fallback) => {
|
|
|
255
255
|
? Math.max(0, Math.round(source.nextRunAt))
|
|
256
256
|
: undefined;
|
|
257
257
|
// Absolute ms of the schedule occurrence last claimed for dispatch. Used so
|
|
258
|
-
// two
|
|
258
|
+
// two AiWorker server instances sharing this config cannot both start a
|
|
259
259
|
// run for the same daily/weekly/cron/once slot (see issue #2710).
|
|
260
260
|
const lastScheduledFor = typeof source.lastScheduledFor === 'number' && Number.isFinite(source.lastScheduledFor)
|
|
261
261
|
? Math.max(0, Math.round(source.lastScheduledFor))
|
|
@@ -717,7 +717,7 @@ export const createProjectConfigRuntime = (deps) => {
|
|
|
717
717
|
* `predicate(currentTask)` is evaluated after the latest on-disk read; when
|
|
718
718
|
* it returns false the write is skipped and `{ updated: false }` is returned.
|
|
719
719
|
* Used by the scheduled-tasks runtime to claim a single schedule occurrence
|
|
720
|
-
* across concurrent
|
|
720
|
+
* across concurrent AiWorker server instances.
|
|
721
721
|
*/
|
|
722
722
|
const updateScheduledTaskStateIf = async (projectID, taskID, predicate, statePatch) => {
|
|
723
723
|
return withProjectWriteLock(projectID, async () => {
|
|
@@ -23,7 +23,9 @@ These provider IDs are currently dispatchable via `fetchQuotaForProvider(provide
|
|
|
23
23
|
| `cursor` | Cursor | `providers/cursor.js` | Environment/token files, AiWorker-managed credentials, or explicit one-time Cursor import |
|
|
24
24
|
| `crof` | CrofAI | `providers/crof.js` | `crof` (API key under `key` or `token`) |
|
|
25
25
|
| `deepseek` | DeepSeek | `providers/deepseek.js` | `deepseek` (API key under `key` or `token`) |
|
|
26
|
+
| `exe-dev` | exe.dev | `providers/exe-dev.js` | Usage API token stored under `~/.config/openchamber/quota/` |
|
|
26
27
|
| `google` | Google | `providers/google/index.js` | `google`, `google.oauth`, Antigravity accounts file |
|
|
28
|
+
| `hyper` | Charm Hyper | `providers/hyper.js` | `hyper` (API key under `key` or `token`) |
|
|
27
29
|
| `github-copilot` | GitHub Copilot | `providers/copilot.js` | `github-copilot`, `copilot` |
|
|
28
30
|
| `github-copilot-addon` | GitHub Copilot Add-on | `providers/copilot.js` | `github-copilot`, `copilot` |
|
|
29
31
|
| `kimi-for-coding` | Kimi for Coding | `providers/kimi.js` | `kimi-for-coding`, `kimi` |
|
|
@@ -51,7 +53,7 @@ All providers should return results via shared helpers to preserve API shape:
|
|
|
51
53
|
Provider modules must export `providerId`, `providerName`, `aliases`, `isConfigured(auth?)`, and `fetchQuota()`.
|
|
52
54
|
`fetchQuota()` should return a quota result with `usage.windows` keyed by window name (for example `5h`, `7d`, `daily`) and optional provider-specific `usage.models` data.
|
|
53
55
|
|
|
54
|
-
Ollama Cloud and Cursor credentials are explicitly managed through Settings. OpenCode Go usage uses `GET https://opencode.ai/zen/go/v1/usage` with the `opencode-go` API key from OpenCode `auth.json` as a bearer token. The server validates managed credentials before atomic `0600` writes and never returns secrets through its API. AiWorker never scans browser cookie stores or automatically reads Cursor storage; Cursor import is an explicit one-time user action and never modifies Cursor's database.
|
|
56
|
+
exe.dev, Ollama Cloud, and Cursor credentials are explicitly managed through Settings. exe.dev usage uses a separately generated HTTPS API token restricted to `billing credits usage` and aggregates every `exe-*` model provider into one monthly credit window. Generate the token with `ssh exe.dev "ssh-key generate-api-key --label=aiworker --exp=30d --cmds='billing credits usage'"`. OpenCode Go usage uses `GET https://opencode.ai/zen/go/v1/usage` with the `opencode-go` API key from OpenCode `auth.json` as a bearer token and the stable `x-opencode-session: openchamber-usage` workload id. The server validates managed credentials before atomic `0600` writes and never returns secrets through its API. AiWorker never scans browser cookie stores or automatically reads Cursor storage; Cursor import is an explicit one-time user action and never modifies Cursor's database.
|
|
55
57
|
|
|
56
58
|
Command Code usage resolves account scope through `GET /alpha/whoami`, then reads server-backed credit balances and five-hour/weekly limits from `GET /alpha/billing/credits?orgId=...`. Personal accounts return `org: null` and use `/alpha/billing/credits` without an `orgId`; organization accounts include their organization id. Web/Electron and VS Code read the standard `command-code` OpenCode auth entry (including OAuth `access`) or `COMMAND_CODE_API_KEY`; credentials remain in the owning runtime and are never returned to shared UI.
|
|
57
59
|
|
|
@@ -89,6 +91,12 @@ In 2025/2026 MiniMax rebranded "Coding Plan" to "Token Plan" alongside the M3 mo
|
|
|
89
91
|
- **model_remains array**: Now contains entries for multiple model categories (chat, speech, video, image). The provider selects the chat-model entry by matching `MiniMax-M*`, then `general`/`chat`/`text` by name, then any entry with a remaining percent.
|
|
90
92
|
- **Window status**: The `current_interval_status` and `current_weekly_status` fields indicate whether a window is active. Status `3` means the window is not applicable for the current plan tier (e.g. legacy plans without weekly limits). The provider omits inactive windows.
|
|
91
93
|
|
|
94
|
+
## Charm Hyper balance semantics
|
|
95
|
+
|
|
96
|
+
`GET https://hyper.charm.land/v1/credits` returns a team's current Hypercredit balance, not a percentage or reset timestamp. The [Hyper FAQ](https://hyper.charm.land/faq) defines one Hypercredit as $0.05. Both runtimes expose `credits_balance` in dollars and `credits` as a numeric label under the UI's localized window title. Keep English unit text out of that numeric label.
|
|
97
|
+
|
|
98
|
+
Web and VS Code accept finite numeric balances and non-empty numeric strings. Missing, blank, or malformed balances remain explicit failures; zero is valid. Credential lookup uses a non-empty string `key`, then `token`, so malformed or blank keys cannot mark the provider configured or hide a valid fallback token. Hyper fetchers accept `readAuth` and `fetchImpl` dependencies for tests without replacing filesystem or auth modules.
|
|
99
|
+
|
|
92
100
|
## Kimi for Coding field semantics
|
|
93
101
|
|
|
94
102
|
`GET https://api.kimi.com/coding/v1/usages` is inconsistent about which field carries consumption:
|
|
@@ -3,6 +3,10 @@ import { deleteQuotaCredential, readQuotaCredential, writeQuotaCredential } from
|
|
|
3
3
|
const clean = (value) => typeof value === 'string' && !/[\r\n]/.test(value) ? value.trim() : '';
|
|
4
4
|
|
|
5
5
|
export const normalizers = {
|
|
6
|
+
'exe-dev': (value) => {
|
|
7
|
+
const usageToken = clean(value?.usageToken);
|
|
8
|
+
return usageToken ? { usageToken } : null;
|
|
9
|
+
},
|
|
6
10
|
'ollama-cloud': (value) => {
|
|
7
11
|
const cookie = clean(value?.cookie);
|
|
8
12
|
return cookie ? { cookie } : null;
|
|
@@ -2,12 +2,12 @@ import fs from 'node:fs';
|
|
|
2
2
|
import os from 'node:os';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
const MANAGED_QUOTA_PROVIDERS = new Set(['ollama-cloud', 'cursor']);
|
|
5
|
+
const MANAGED_QUOTA_PROVIDERS = new Set(['exe-dev', 'ollama-cloud', 'cursor']);
|
|
6
6
|
|
|
7
7
|
const credentialsDirectory = () => path.join(
|
|
8
|
-
process.env.
|
|
9
|
-
? path.resolve(process.env.
|
|
10
|
-
: path.join(os.homedir(), '.config', '
|
|
8
|
+
process.env.AIWORKER_DATA_DIR
|
|
9
|
+
? path.resolve(process.env.AIWORKER_DATA_DIR)
|
|
10
|
+
: path.join(os.homedir(), '.config', 'aiworker'),
|
|
11
11
|
'quota',
|
|
12
12
|
);
|
|
13
13
|
|
|
@@ -4,18 +4,18 @@ import os from 'node:os';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { deleteLegacyOpenCodeGoCredential, deleteQuotaCredential, readQuotaCredential, writeQuotaCredential } from './store.js';
|
|
6
6
|
|
|
7
|
-
const previousDataDir = process.env.
|
|
7
|
+
const previousDataDir = process.env.AIWORKER_DATA_DIR;
|
|
8
8
|
const temporaryDirectory = fs.mkdtempSync(path.join(os.tmpdir(), 'openchamber-quota-store-'));
|
|
9
|
-
process.env.
|
|
9
|
+
process.env.AIWORKER_DATA_DIR = temporaryDirectory;
|
|
10
10
|
|
|
11
11
|
describe('quota credential store', () => {
|
|
12
12
|
it('uses owner-only permissions and rejects arbitrary provider paths', () => {
|
|
13
|
-
writeQuotaCredential('
|
|
13
|
+
writeQuotaCredential('exe-dev', { usageToken: 'secret' });
|
|
14
14
|
expect(fs.statSync(path.join(temporaryDirectory, 'quota')).mode & 0o777).toBe(0o700);
|
|
15
|
-
expect(fs.statSync(path.join(temporaryDirectory, 'quota', '
|
|
16
|
-
expect(readQuotaCredential('
|
|
15
|
+
expect(fs.statSync(path.join(temporaryDirectory, 'quota', 'exe-dev.json')).mode & 0o777).toBe(0o600);
|
|
16
|
+
expect(readQuotaCredential('exe-dev', (value) => value)).toEqual({ usageToken: 'secret' });
|
|
17
17
|
expect(() => writeQuotaCredential('../escape', {})).toThrow('Unsupported credential provider');
|
|
18
|
-
deleteQuotaCredential('
|
|
18
|
+
deleteQuotaCredential('exe-dev');
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
it('removes the obsolete OpenCode Go credential without parsing it', () => {
|
|
@@ -28,7 +28,7 @@ describe('quota credential store', () => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
afterAll(() => {
|
|
31
|
-
if (previousDataDir === undefined) delete process.env.
|
|
32
|
-
else process.env.
|
|
31
|
+
if (previousDataDir === undefined) delete process.env.AIWORKER_DATA_DIR;
|
|
32
|
+
else process.env.AIWORKER_DATA_DIR = previousDataDir;
|
|
33
33
|
fs.rmSync(temporaryDirectory, { recursive: true, force: true });
|
|
34
34
|
});
|