@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
package/server/lib/fs/routes.js
CHANGED
|
@@ -87,7 +87,7 @@ const resolveOutsideFileGrant = async ({ token, targetPath, scope, fsPromises })
|
|
|
87
87
|
};
|
|
88
88
|
|
|
89
89
|
const createCommandTimeoutMs = () => {
|
|
90
|
-
const raw = Number(process.env.
|
|
90
|
+
const raw = Number(process.env.AIWORKER_FS_EXEC_TIMEOUT_MS);
|
|
91
91
|
if (Number.isFinite(raw) && raw > 0) return raw;
|
|
92
92
|
return 5 * 60 * 1000;
|
|
93
93
|
};
|
|
@@ -97,19 +97,19 @@ const createCommandTimeoutMs = () => {
|
|
|
97
97
|
// absorbs the burst of identical lookups a fresh client (e.g. right after a
|
|
98
98
|
// page reload) fires for every project. Set to 0 to disable caching.
|
|
99
99
|
const createGitReadCacheTtlMs = () => {
|
|
100
|
-
const raw = Number(process.env.
|
|
100
|
+
const raw = Number(process.env.AIWORKER_GIT_READ_CACHE_TTL_MS);
|
|
101
101
|
if (Number.isFinite(raw) && raw >= 0) return raw;
|
|
102
102
|
return 30 * 1000;
|
|
103
103
|
};
|
|
104
104
|
|
|
105
105
|
const createGitCheckIgnoreTimeoutMs = () => {
|
|
106
|
-
const raw = Number(process.env.
|
|
106
|
+
const raw = Number(process.env.AIWORKER_GIT_CHECK_IGNORE_TIMEOUT_MS);
|
|
107
107
|
if (Number.isFinite(raw) && raw >= 0) return raw;
|
|
108
108
|
return 2500;
|
|
109
109
|
};
|
|
110
110
|
|
|
111
111
|
const createUploadMaxBytes = () => {
|
|
112
|
-
const raw = Number(process.env.
|
|
112
|
+
const raw = Number(process.env.AIWORKER_FS_UPLOAD_MAX_BYTES);
|
|
113
113
|
if (Number.isFinite(raw) && raw > 0) return Math.floor(raw);
|
|
114
114
|
return 100 * 1024 * 1024;
|
|
115
115
|
};
|
|
@@ -196,7 +196,7 @@ const isPathWithinRoot = (resolvedPath, rootPath, path, os) => {
|
|
|
196
196
|
return true;
|
|
197
197
|
};
|
|
198
198
|
|
|
199
|
-
const resolveWorkspacePath = ({ targetPath, baseDirectory, path, os, normalizeDirectoryPath,
|
|
199
|
+
const resolveWorkspacePath = ({ targetPath, baseDirectory, path, os, normalizeDirectoryPath, managedRoots }) => {
|
|
200
200
|
const normalized = normalizeDirectoryPath(targetPath);
|
|
201
201
|
if (!normalized || typeof normalized !== 'string') {
|
|
202
202
|
return { ok: false, error: 'Path is required' };
|
|
@@ -209,8 +209,12 @@ const resolveWorkspacePath = ({ targetPath, baseDirectory, path, os, normalizeDi
|
|
|
209
209
|
return { ok: true, base: resolvedBase, resolved };
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
|
|
212
|
+
// Managed roots (config root, relocated chats root) stay valid targets
|
|
213
|
+
// even outside the active workspace.
|
|
214
|
+
for (const root of managedRoots) {
|
|
215
|
+
if (isPathWithinRoot(resolved, root, path, os)) {
|
|
216
|
+
return { ok: true, base: path.resolve(root), resolved };
|
|
217
|
+
}
|
|
214
218
|
}
|
|
215
219
|
|
|
216
220
|
return { ok: false, error: 'Path is outside of active workspace' };
|
|
@@ -249,7 +253,7 @@ const resolveWorkspacePathFromWorktrees = async ({ targetPath, baseDirectory, pa
|
|
|
249
253
|
return { ok: false, error: 'Path is outside of active workspace' };
|
|
250
254
|
};
|
|
251
255
|
|
|
252
|
-
const resolveWorkspacePathFromContext = async ({ req, targetPath, resolveProjectDirectory, path, os, normalizeDirectoryPath,
|
|
256
|
+
const resolveWorkspacePathFromContext = async ({ req, targetPath, resolveProjectDirectory, path, os, normalizeDirectoryPath, managedRoots }) => {
|
|
253
257
|
const resolvedProject = await resolveProjectDirectory(req);
|
|
254
258
|
if (!resolvedProject.directory) {
|
|
255
259
|
return { ok: false, error: resolvedProject.error || 'Active workspace is required' };
|
|
@@ -261,7 +265,7 @@ const resolveWorkspacePathFromContext = async ({ req, targetPath, resolveProject
|
|
|
261
265
|
path,
|
|
262
266
|
os,
|
|
263
267
|
normalizeDirectoryPath,
|
|
264
|
-
|
|
268
|
+
managedRoots,
|
|
265
269
|
});
|
|
266
270
|
if (resolved.ok || resolved.error !== 'Path is outside of active workspace') {
|
|
267
271
|
return resolved;
|
|
@@ -281,7 +285,7 @@ const resolveWorkspacePathFromContext = async ({ req, targetPath, resolveProject
|
|
|
281
285
|
path,
|
|
282
286
|
os,
|
|
283
287
|
normalizeDirectoryPath,
|
|
284
|
-
|
|
288
|
+
managedRoots,
|
|
285
289
|
});
|
|
286
290
|
if (lexical.ok) {
|
|
287
291
|
return lexical;
|
|
@@ -412,7 +416,7 @@ const escapeCloneSshKeyPath = (sshKeyPath) => {
|
|
|
412
416
|
return `'${normalized.replace(/'/g, "'\\''")}'`;
|
|
413
417
|
};
|
|
414
418
|
|
|
415
|
-
const resolveReadPathFromContext = async ({ req, targetPath, scope, resolveProjectDirectory, path, os, fsPromises, normalizeDirectoryPath,
|
|
419
|
+
const resolveReadPathFromContext = async ({ req, targetPath, scope, resolveProjectDirectory, path, os, fsPromises, normalizeDirectoryPath, managedRoots }) => {
|
|
416
420
|
if (req.query?.allowOutsideWorkspace === 'true') {
|
|
417
421
|
const normalized = normalizeDirectoryPath(targetPath);
|
|
418
422
|
if (!normalized || typeof normalized !== 'string') {
|
|
@@ -434,7 +438,7 @@ const resolveReadPathFromContext = async ({ req, targetPath, scope, resolveProje
|
|
|
434
438
|
path,
|
|
435
439
|
os,
|
|
436
440
|
normalizeDirectoryPath,
|
|
437
|
-
|
|
441
|
+
managedRoots,
|
|
438
442
|
});
|
|
439
443
|
};
|
|
440
444
|
|
|
@@ -519,8 +523,15 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
519
523
|
resolveProjectDirectory,
|
|
520
524
|
buildAugmentedPath,
|
|
521
525
|
resolveGitBinaryForSpawn,
|
|
522
|
-
|
|
526
|
+
aiworkerUserConfigRoot,
|
|
527
|
+
managedChatsRoot,
|
|
523
528
|
} = dependencies;
|
|
529
|
+
// Chat worktrees may live outside every project workspace; both managed
|
|
530
|
+
// roots stay valid filesystem targets.
|
|
531
|
+
const chatsRoot = typeof managedChatsRoot === 'string' && managedChatsRoot.trim()
|
|
532
|
+
? path.resolve(managedChatsRoot.trim())
|
|
533
|
+
: path.join(aiworkerUserConfigRoot, 'chats');
|
|
534
|
+
const managedRoots = [path.resolve(aiworkerUserConfigRoot), chatsRoot];
|
|
524
535
|
const realpathCache = createRealpathCache({
|
|
525
536
|
realpath: fsPromises.realpath.bind(fsPromises),
|
|
526
537
|
});
|
|
@@ -699,7 +710,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
699
710
|
if (!home || typeof home !== 'string' || home.length === 0) {
|
|
700
711
|
return res.status(500).json({ error: 'Failed to resolve home directory' });
|
|
701
712
|
}
|
|
702
|
-
return res.json({ home });
|
|
713
|
+
return res.json({ home, chatsRoot });
|
|
703
714
|
} catch (error) {
|
|
704
715
|
console.error('Failed to resolve home directory:', error);
|
|
705
716
|
return res.status(500).json({ error: (error && error.message) || 'Failed to resolve home directory' });
|
|
@@ -725,7 +736,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
725
736
|
path,
|
|
726
737
|
os,
|
|
727
738
|
normalizeDirectoryPath,
|
|
728
|
-
|
|
739
|
+
managedRoots,
|
|
729
740
|
});
|
|
730
741
|
if (!resolved.ok) {
|
|
731
742
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -870,7 +881,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
870
881
|
os,
|
|
871
882
|
fsPromises,
|
|
872
883
|
normalizeDirectoryPath,
|
|
873
|
-
|
|
884
|
+
managedRoots,
|
|
874
885
|
});
|
|
875
886
|
if (!resolved.ok) {
|
|
876
887
|
if (req.query?.allowOutsideWorkspace === 'true') {
|
|
@@ -920,7 +931,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
920
931
|
os,
|
|
921
932
|
fsPromises,
|
|
922
933
|
normalizeDirectoryPath,
|
|
923
|
-
|
|
934
|
+
managedRoots,
|
|
924
935
|
});
|
|
925
936
|
if (!resolved.ok) {
|
|
926
937
|
if (req.query?.allowOutsideWorkspace === 'true') {
|
|
@@ -984,7 +995,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
984
995
|
os,
|
|
985
996
|
fsPromises,
|
|
986
997
|
normalizeDirectoryPath,
|
|
987
|
-
|
|
998
|
+
managedRoots,
|
|
988
999
|
});
|
|
989
1000
|
if (!resolved.ok) {
|
|
990
1001
|
if (req.query?.allowOutsideWorkspace === 'true') {
|
|
@@ -1065,7 +1076,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1065
1076
|
path,
|
|
1066
1077
|
os,
|
|
1067
1078
|
normalizeDirectoryPath,
|
|
1068
|
-
|
|
1079
|
+
managedRoots,
|
|
1069
1080
|
});
|
|
1070
1081
|
if (!resolved.ok) {
|
|
1071
1082
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -1117,7 +1128,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1117
1128
|
path,
|
|
1118
1129
|
os,
|
|
1119
1130
|
normalizeDirectoryPath,
|
|
1120
|
-
|
|
1131
|
+
managedRoots,
|
|
1121
1132
|
});
|
|
1122
1133
|
if (!resolved.ok) {
|
|
1123
1134
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -1187,7 +1198,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1187
1198
|
path,
|
|
1188
1199
|
os,
|
|
1189
1200
|
normalizeDirectoryPath,
|
|
1190
|
-
|
|
1201
|
+
managedRoots,
|
|
1191
1202
|
});
|
|
1192
1203
|
if (!resolved.ok) {
|
|
1193
1204
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -1294,7 +1305,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1294
1305
|
path,
|
|
1295
1306
|
os,
|
|
1296
1307
|
normalizeDirectoryPath,
|
|
1297
|
-
|
|
1308
|
+
managedRoots,
|
|
1298
1309
|
});
|
|
1299
1310
|
if (!resolved.ok) {
|
|
1300
1311
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -1332,7 +1343,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1332
1343
|
path,
|
|
1333
1344
|
os,
|
|
1334
1345
|
normalizeDirectoryPath,
|
|
1335
|
-
|
|
1346
|
+
managedRoots,
|
|
1336
1347
|
});
|
|
1337
1348
|
if (!resolvedOld.ok) {
|
|
1338
1349
|
return res.status(400).json({ error: resolvedOld.error });
|
|
@@ -1345,7 +1356,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1345
1356
|
path,
|
|
1346
1357
|
os,
|
|
1347
1358
|
normalizeDirectoryPath,
|
|
1348
|
-
|
|
1359
|
+
managedRoots,
|
|
1349
1360
|
});
|
|
1350
1361
|
if (!resolvedNew.ok) {
|
|
1351
1362
|
return res.status(400).json({ error: resolvedNew.error });
|
|
@@ -1451,7 +1462,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1451
1462
|
path,
|
|
1452
1463
|
os,
|
|
1453
1464
|
normalizeDirectoryPath,
|
|
1454
|
-
|
|
1465
|
+
managedRoots,
|
|
1455
1466
|
});
|
|
1456
1467
|
if (!resolvedForWorkspace.ok) {
|
|
1457
1468
|
console.warn(`Rejected /api/fs/exec outside workspace: ${resolvedForWorkspace.error}`);
|
|
@@ -1689,7 +1700,7 @@ export const registerFsRoutes = (app, dependencies) => {
|
|
|
1689
1700
|
path,
|
|
1690
1701
|
os,
|
|
1691
1702
|
normalizeDirectoryPath,
|
|
1692
|
-
|
|
1703
|
+
managedRoots,
|
|
1693
1704
|
});
|
|
1694
1705
|
if (!resolved.ok) {
|
|
1695
1706
|
return res.status(400).json({ error: resolved.error });
|
|
@@ -116,7 +116,7 @@ const registerExec = ({ spawn }) => {
|
|
|
116
116
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
117
117
|
buildAugmentedPath: () => '/usr/bin',
|
|
118
118
|
resolveGitBinaryForSpawn: () => 'git',
|
|
119
|
-
|
|
119
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
120
120
|
});
|
|
121
121
|
return getRoute('POST', '/api/fs/exec');
|
|
122
122
|
};
|
|
@@ -136,7 +136,7 @@ const registerWrite = (fsPromises) => {
|
|
|
136
136
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
137
137
|
buildAugmentedPath: () => '/usr/bin',
|
|
138
138
|
resolveGitBinaryForSpawn: () => 'git',
|
|
139
|
-
|
|
139
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
140
140
|
});
|
|
141
141
|
return getRoute('POST', '/api/fs/write');
|
|
142
142
|
};
|
|
@@ -160,7 +160,7 @@ const registerUpload = (fsPromises) => {
|
|
|
160
160
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
161
161
|
buildAugmentedPath: () => '/usr/bin',
|
|
162
162
|
resolveGitBinaryForSpawn: () => 'git',
|
|
163
|
-
|
|
163
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
164
164
|
});
|
|
165
165
|
return getRoute('POST', '/api/fs/upload');
|
|
166
166
|
};
|
|
@@ -180,7 +180,7 @@ const registerRead = (fsPromises, resolveProjectDirectory = async () => ({ direc
|
|
|
180
180
|
resolveProjectDirectory,
|
|
181
181
|
buildAugmentedPath: () => '/usr/bin',
|
|
182
182
|
resolveGitBinaryForSpawn: () => 'git',
|
|
183
|
-
|
|
183
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
184
184
|
});
|
|
185
185
|
return getRoute('GET', '/api/fs/read');
|
|
186
186
|
};
|
|
@@ -200,7 +200,7 @@ const registerRaw = (fsPromises) => {
|
|
|
200
200
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
201
201
|
buildAugmentedPath: () => '/usr/bin',
|
|
202
202
|
resolveGitBinaryForSpawn: () => 'git',
|
|
203
|
-
|
|
203
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
204
204
|
});
|
|
205
205
|
return getRoute('GET', '/api/fs/raw');
|
|
206
206
|
};
|
|
@@ -220,7 +220,7 @@ const registerMkdir = (fsPromises) => {
|
|
|
220
220
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
221
221
|
buildAugmentedPath: () => '/usr/bin',
|
|
222
222
|
resolveGitBinaryForSpawn: () => 'git',
|
|
223
|
-
|
|
223
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
224
224
|
});
|
|
225
225
|
return getRoute('POST', '/api/fs/mkdir');
|
|
226
226
|
};
|
|
@@ -241,7 +241,7 @@ const registerReveal = ({ fsPromises, spawn, platform = 'linux' }) => {
|
|
|
241
241
|
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
242
242
|
buildAugmentedPath: () => '/usr/bin',
|
|
243
243
|
resolveGitBinaryForSpawn: () => 'git',
|
|
244
|
-
|
|
244
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
245
245
|
});
|
|
246
246
|
return getRoute('POST', '/api/fs/reveal');
|
|
247
247
|
};
|
|
@@ -482,8 +482,8 @@ describe('fs upload', () => {
|
|
|
482
482
|
});
|
|
483
483
|
|
|
484
484
|
it('cleans up a partial temp file when the configured streaming limit is exceeded', async () => {
|
|
485
|
-
const previous = process.env.
|
|
486
|
-
process.env.
|
|
485
|
+
const previous = process.env.AIWORKER_FS_UPLOAD_MAX_BYTES;
|
|
486
|
+
process.env.AIWORKER_FS_UPLOAD_MAX_BYTES = '5';
|
|
487
487
|
const write = vi.fn(async (_buffer, _offset, length) => ({ bytesWritten: length }));
|
|
488
488
|
const fsPromises = {
|
|
489
489
|
open: vi.fn(async () => ({ write, close: vi.fn(async () => undefined) })),
|
|
@@ -504,14 +504,14 @@ describe('fs upload', () => {
|
|
|
504
504
|
expect(fsPromises.link).not.toHaveBeenCalled();
|
|
505
505
|
expect(fsPromises.unlink).toHaveBeenCalledWith(expect.stringMatching(/^\/repo\/file\.bin\.upload-/));
|
|
506
506
|
} finally {
|
|
507
|
-
if (previous === undefined) delete process.env.
|
|
508
|
-
else process.env.
|
|
507
|
+
if (previous === undefined) delete process.env.AIWORKER_FS_UPLOAD_MAX_BYTES;
|
|
508
|
+
else process.env.AIWORKER_FS_UPLOAD_MAX_BYTES = previous;
|
|
509
509
|
}
|
|
510
510
|
});
|
|
511
511
|
|
|
512
512
|
it('rejects a declared oversized upload before opening a temp file', async () => {
|
|
513
|
-
const previous = process.env.
|
|
514
|
-
process.env.
|
|
513
|
+
const previous = process.env.AIWORKER_FS_UPLOAD_MAX_BYTES;
|
|
514
|
+
process.env.AIWORKER_FS_UPLOAD_MAX_BYTES = '5';
|
|
515
515
|
const fsPromises = {
|
|
516
516
|
open: vi.fn(async () => ({ write: vi.fn(), close: vi.fn() })),
|
|
517
517
|
};
|
|
@@ -523,8 +523,8 @@ describe('fs upload', () => {
|
|
|
523
523
|
expect(res.body).toEqual({ error: 'File exceeds maximum size of 5 bytes' });
|
|
524
524
|
expect(fsPromises.open).not.toHaveBeenCalled();
|
|
525
525
|
} finally {
|
|
526
|
-
if (previous === undefined) delete process.env.
|
|
527
|
-
else process.env.
|
|
526
|
+
if (previous === undefined) delete process.env.AIWORKER_FS_UPLOAD_MAX_BYTES;
|
|
527
|
+
else process.env.AIWORKER_FS_UPLOAD_MAX_BYTES = previous;
|
|
528
528
|
}
|
|
529
529
|
});
|
|
530
530
|
|
|
@@ -843,11 +843,11 @@ describe('fs reveal', () => {
|
|
|
843
843
|
|
|
844
844
|
describe('fs exec git-read cache', () => {
|
|
845
845
|
beforeEach(() => {
|
|
846
|
-
delete process.env.
|
|
846
|
+
delete process.env.AIWORKER_GIT_READ_CACHE_TTL_MS;
|
|
847
847
|
});
|
|
848
848
|
|
|
849
849
|
afterEach(() => {
|
|
850
|
-
delete process.env.
|
|
850
|
+
delete process.env.AIWORKER_GIT_READ_CACHE_TTL_MS;
|
|
851
851
|
});
|
|
852
852
|
|
|
853
853
|
it('rejects background command execution', async () => {
|
|
@@ -956,7 +956,7 @@ describe('fs exec git-read cache', () => {
|
|
|
956
956
|
});
|
|
957
957
|
|
|
958
958
|
it('disables caching when TTL is 0', async () => {
|
|
959
|
-
process.env.
|
|
959
|
+
process.env.AIWORKER_GIT_READ_CACHE_TTL_MS = '0';
|
|
960
960
|
const command = 'git rev-parse --absolute-git-dir';
|
|
961
961
|
const { spawn, calls } = createSpawn({ stdoutByCommand: { [command]: '/repo/.git\n' } });
|
|
962
962
|
const handler = registerExec({ spawn });
|
|
@@ -1062,7 +1062,7 @@ describe('fs list symlink path space (issue 2627)', () => {
|
|
|
1062
1062
|
resolveProjectDirectory: async () => ({ directory: '/workspace' }),
|
|
1063
1063
|
buildAugmentedPath: () => '/usr/bin',
|
|
1064
1064
|
resolveGitBinaryForSpawn: () => 'git',
|
|
1065
|
-
|
|
1065
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
1066
1066
|
});
|
|
1067
1067
|
return getRoute('GET', '/api/fs/list');
|
|
1068
1068
|
};
|
|
@@ -1162,7 +1162,7 @@ describe('fs git-dirs', () => {
|
|
|
1162
1162
|
resolveProjectDirectory: async () => ({ directory: '/workspace' }),
|
|
1163
1163
|
buildAugmentedPath: () => '/usr/bin',
|
|
1164
1164
|
resolveGitBinaryForSpawn: () => 'git',
|
|
1165
|
-
|
|
1165
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
1166
1166
|
});
|
|
1167
1167
|
return { handler: getRoute('GET', '/api/fs/git-dirs'), readdir };
|
|
1168
1168
|
};
|
|
@@ -1393,7 +1393,7 @@ describe('fs stat directory scope (issue 3019)', () => {
|
|
|
1393
1393
|
resolveProjectDirectory: projectDirectoryRuntime.resolveProjectDirectory,
|
|
1394
1394
|
buildAugmentedPath: () => '/usr/bin',
|
|
1395
1395
|
resolveGitBinaryForSpawn: () => 'git',
|
|
1396
|
-
|
|
1396
|
+
aiworkerUserConfigRoot: '/home/user/.config',
|
|
1397
1397
|
});
|
|
1398
1398
|
return getRoute('GET', '/api/fs/stat');
|
|
1399
1399
|
};
|
|
@@ -1429,3 +1429,80 @@ describe('fs stat directory scope (issue 3019)', () => {
|
|
|
1429
1429
|
expect(res.body.isFile).toBe(true);
|
|
1430
1430
|
});
|
|
1431
1431
|
});
|
|
1432
|
+
|
|
1433
|
+
describe('fs managed chats root', () => {
|
|
1434
|
+
const registerWithChatsRoot = ({ managedChatsRoot, fsPromises = {} } = {}) => {
|
|
1435
|
+
const { app, getRoute } = createRouteRegistry();
|
|
1436
|
+
registerFsRoutes(app, {
|
|
1437
|
+
os: { homedir: () => '/home/user' },
|
|
1438
|
+
path: path.posix,
|
|
1439
|
+
fsPromises: {
|
|
1440
|
+
realpath: async (targetPath) => targetPath,
|
|
1441
|
+
mkdir: async () => undefined,
|
|
1442
|
+
...fsPromises,
|
|
1443
|
+
},
|
|
1444
|
+
spawn: vi.fn(),
|
|
1445
|
+
crypto: { randomUUID: () => 'job-0' },
|
|
1446
|
+
normalizeDirectoryPath: (p) => p,
|
|
1447
|
+
resolveProjectDirectory: async () => ({ directory: '/repo' }),
|
|
1448
|
+
buildAugmentedPath: () => '/usr/bin',
|
|
1449
|
+
resolveGitBinaryForSpawn: () => 'git',
|
|
1450
|
+
aiworkerUserConfigRoot: '/home/user/.config/openchamber',
|
|
1451
|
+
managedChatsRoot,
|
|
1452
|
+
});
|
|
1453
|
+
return {
|
|
1454
|
+
home: getRoute('GET', '/api/fs/home'),
|
|
1455
|
+
mkdir: getRoute('POST', '/api/fs/mkdir'),
|
|
1456
|
+
};
|
|
1457
|
+
};
|
|
1458
|
+
|
|
1459
|
+
it('exposes the default chats root next to the home directory', async () => {
|
|
1460
|
+
const { home } = registerWithChatsRoot();
|
|
1461
|
+
|
|
1462
|
+
const res = createMockResponse();
|
|
1463
|
+
await home(undefined, res);
|
|
1464
|
+
|
|
1465
|
+
expect(res.statusCode).toBe(200);
|
|
1466
|
+
expect(res.body.home).toBe('/home/user');
|
|
1467
|
+
expect(res.body.chatsRoot).toBe('/home/user/.config/openchamber/chats');
|
|
1468
|
+
});
|
|
1469
|
+
|
|
1470
|
+
it('exposes a relocated chats root when AIWORKER_CHATS_DIR is configured upstream', async () => {
|
|
1471
|
+
const { home } = registerWithChatsRoot({ managedChatsRoot: '/srv/openchamber-chats' });
|
|
1472
|
+
|
|
1473
|
+
const res = createMockResponse();
|
|
1474
|
+
await home(undefined, res);
|
|
1475
|
+
|
|
1476
|
+
expect(res.statusCode).toBe(200);
|
|
1477
|
+
expect(res.body.chatsRoot).toBe('/srv/openchamber-chats');
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
it('allows mkdir inside the relocated chats root outside the active workspace', async () => {
|
|
1481
|
+
const mkdirCalls = [];
|
|
1482
|
+
const { mkdir } = registerWithChatsRoot({
|
|
1483
|
+
managedChatsRoot: '/srv/openchamber-chats',
|
|
1484
|
+
fsPromises: {
|
|
1485
|
+
mkdir: async (targetPath) => {
|
|
1486
|
+
mkdirCalls.push(targetPath);
|
|
1487
|
+
},
|
|
1488
|
+
},
|
|
1489
|
+
});
|
|
1490
|
+
|
|
1491
|
+
const res = createMockResponse();
|
|
1492
|
+
await mkdir({ body: { path: '/srv/openchamber-chats/2026-08-25/session-a' } }, res);
|
|
1493
|
+
|
|
1494
|
+
expect(res.statusCode).toBe(200);
|
|
1495
|
+
expect(res.body.success).toBe(true);
|
|
1496
|
+
expect(mkdirCalls).toEqual(['/srv/openchamber-chats/2026-08-25/session-a']);
|
|
1497
|
+
});
|
|
1498
|
+
|
|
1499
|
+
it('still rejects mkdir outside the workspace and all managed roots', async () => {
|
|
1500
|
+
const { mkdir } = registerWithChatsRoot({ managedChatsRoot: '/srv/openchamber-chats' });
|
|
1501
|
+
|
|
1502
|
+
const res = createMockResponse();
|
|
1503
|
+
await mkdir({ body: { path: '/etc/passwd-holder' } }, res);
|
|
1504
|
+
|
|
1505
|
+
expect(res.statusCode).toBe(400);
|
|
1506
|
+
expect(res.body).toEqual({ error: 'Path is outside of active workspace' });
|
|
1507
|
+
});
|
|
1508
|
+
});
|
|
@@ -39,6 +39,7 @@ The following functions are exported and used by the web server:
|
|
|
39
39
|
|
|
40
40
|
### Branch Operations
|
|
41
41
|
- `getBranches(directory)`: Get list of local and remote branches (filtered to active remote branches).
|
|
42
|
+
- `getUnpushedBranchCounts(directory, branchNames)`: Count commits ahead of each locally known upstream for up to five supplied local branches. This reads local refs only and omits branches without an upstream.
|
|
42
43
|
- `createBranch(directory, branchName, options)`: Create and checkout a new branch.
|
|
43
44
|
- `checkoutBranch(directory, branchName)`: Checkout an existing branch. A remote-tracking name (`origin/main`, or the `remotes/`-prefixed form) resolves to the local branch of that name, created with `--track` when it does not exist yet, because the branch selector offers remote branches as places to work rather than commits to inspect — a literal checkout of the remote ref would detach HEAD. A local branch whose own name looks like a remote ref wins over that resolution, and anything unresolvable is checked out as requested. The returned `branch` is the branch that was actually checked out, which callers should report instead of the requested name.
|
|
44
45
|
- `deleteBranch(directory, branch, options)`: Delete a branch (supports force flag).
|
|
@@ -48,7 +49,7 @@ The following functions are exported and used by the web server:
|
|
|
48
49
|
### Worktree Operations
|
|
49
50
|
- `getWorktrees(directory)`: List all git worktrees for a repository.
|
|
50
51
|
- `validateWorktreeCreate(directory, input)`: Validate worktree creation parameters (mode, branchName, startRef, upstream config).
|
|
51
|
-
- `createWorktree(directory, input)`: Create a new worktree (supports 'new' and 'existing' modes, upstream setup). After populating the worktree, the repository's `post-checkout` hook runs once with git's standard arguments (null ref as previous HEAD, the checked-out HEAD, and flag `1`) from the worktree directory, mirroring `git worktree add` without `--no-checkout`; a missing or non-executable hook is skipped and a failing hook is logged as a warning, never failing worktree creation or the session bootstrap.
|
|
52
|
+
- `createWorktree(directory, input)`: Create a new worktree (supports 'new' and 'existing' modes, upstream setup). When the current tracked branch has no unpublished commits, the UI supplies its remote-tracking ref and this operation fetches that branch once before creating the worktree. A failed fetch falls back to the local branch and reports `sourceFetchFailed`; other remote start refs still require an existing local ref when their fetch fails. After populating the worktree, the repository's `post-checkout` hook runs once with git's standard arguments (null ref as previous HEAD, the checked-out HEAD, and flag `1`) from the worktree directory, mirroring `git worktree add` without `--no-checkout`; a missing or non-executable hook is skipped and a failing hook is logged as a warning, never failing worktree creation or the session bootstrap.
|
|
52
53
|
- `removeWorktree(directory, input)`: Remove a worktree (optionally delete local branch).
|
|
53
54
|
- `isLinkedWorktree(directory)`: Check if directory is a linked worktree (not primary).
|
|
54
55
|
|
|
@@ -142,6 +143,7 @@ The following functions are internal helpers used by exported functions:
|
|
|
142
143
|
- `path`: Absolute path to worktree directory.
|
|
143
144
|
- `directoryCreated`: Present when create returned after the target directory exists while background Git/bootstrap work continues.
|
|
144
145
|
- `bootstrapStatus`: Background setup state. The legacy `status` remains `pending`, `ready`, or `failed`, while `phase` reports `directory-created`, `git-ready`, or `setup-ready`. Fast create starts at `pending`/`directory-created`; population and upstream Git completion advances to `pending`/`git-ready` before setup/start scripts; completed setup is `ready`/`setup-ready`. A missing in-memory state falls back to `ready`/`setup-ready`; clients continue to accept legacy status responses that omit `phase`.
|
|
146
|
+
- `sourceFetchFailed`: Present when the automatic source-branch fetch failed and creation fell back to the tracked local branch.
|
|
145
147
|
- Fast-create background failures remove OpenCode sandbox metadata for directories that never became Git worktrees, and remove the pre-created directory only if it is still empty. User-created files are never recursively deleted by this cleanup.
|
|
146
148
|
- Worktree removal waits for any active create/bootstrap task for that directory before deleting it, preventing a background Git or setup task from restoring removed state or racing filesystem cleanup.
|
|
147
149
|
- Worktree bootstrap retries transient `index.lock` conflicts. If the lock remains byte-for-byte and metadata-identical across the retry window, it is treated as stale, removed, and population continues automatically; changing locks are left untouched and reported as failures.
|
|
@@ -2,7 +2,7 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
|
|
5
|
-
const STORAGE_DIR = path.join(os.homedir(), '.config', '
|
|
5
|
+
const STORAGE_DIR = path.join(os.homedir(), '.config', 'aiworker');
|
|
6
6
|
const STORAGE_FILE = path.join(STORAGE_DIR, 'git-identities.json');
|
|
7
7
|
|
|
8
8
|
function ensureStorageDir() {
|
|
@@ -12,11 +12,11 @@ import {
|
|
|
12
12
|
} from './service.js';
|
|
13
13
|
|
|
14
14
|
// ---------------------------------------------------------------------------
|
|
15
|
-
// Regression for https://
|
|
15
|
+
// Regression for https://roweb.cn/roweb/openchamber/issues/2746
|
|
16
16
|
//
|
|
17
17
|
// "[Bug] new worktree, Filename too long"
|
|
18
18
|
//
|
|
19
|
-
//
|
|
19
|
+
// AiWorker places worktrees under:
|
|
20
20
|
// <XDG_DATA_HOME>/opencode/worktree/<40-char root commit hash>/<worktree name>
|
|
21
21
|
// and populates them with `git reset --hard`. On Windows, that deep prefix plus
|
|
22
22
|
// a deeply nested repo file (e.g. yudao ~173 chars) exceeds MAX_PATH (260) and
|
|
@@ -95,7 +95,7 @@ describe('issue #2746 - worktree long path support', () => {
|
|
|
95
95
|
const created = await createWorktree(repo, {
|
|
96
96
|
mode: 'new',
|
|
97
97
|
worktreeName: 'issue-2746',
|
|
98
|
-
branchName: '
|
|
98
|
+
branchName: 'aiworker/issue-2746',
|
|
99
99
|
});
|
|
100
100
|
expect(created.directoryCreated).toBe(true);
|
|
101
101
|
|
|
@@ -162,7 +162,7 @@ describe('issue #2746 - worktree long path support', () => {
|
|
|
162
162
|
const created = await createWorktree(repo, {
|
|
163
163
|
mode: 'new',
|
|
164
164
|
worktreeName: 'issue-2746-namemax',
|
|
165
|
-
branchName: '
|
|
165
|
+
branchName: 'aiworker/issue-2746-namemax',
|
|
166
166
|
});
|
|
167
167
|
expect(created.directoryCreated).toBe(true);
|
|
168
168
|
|
package/server/lib/git/routes.js
CHANGED
|
@@ -873,6 +873,22 @@ export function registerGitRoutes(app) {
|
|
|
873
873
|
}
|
|
874
874
|
});
|
|
875
875
|
|
|
876
|
+
app.post('/api/git/branch-push-status', async (req, res) => {
|
|
877
|
+
const { getUnpushedBranchCounts } = await getGitLibraries();
|
|
878
|
+
try {
|
|
879
|
+
const directory = req.query.directory;
|
|
880
|
+
const branches = req.body?.branches;
|
|
881
|
+
if (!directory) return res.status(400).json({ error: 'directory parameter is required' });
|
|
882
|
+
if (!Array.isArray(branches) || branches.some((branch) => typeof branch !== 'string')) {
|
|
883
|
+
return res.status(400).json({ error: 'branches must be an array of branch names' });
|
|
884
|
+
}
|
|
885
|
+
res.json(await getUnpushedBranchCounts(directory, branches));
|
|
886
|
+
} catch (error) {
|
|
887
|
+
console.error('Failed to get branch push status:', error);
|
|
888
|
+
res.status(500).json({ error: error.message || 'Failed to get branch push status' });
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
|
|
876
892
|
app.post('/api/git/branches', async (req, res) => {
|
|
877
893
|
const { createBranch } = await getGitLibraries();
|
|
878
894
|
try {
|
|
@@ -1074,7 +1090,7 @@ export function registerGitRoutes(app) {
|
|
|
1074
1090
|
// Worktrees are an optional feature. Avoid repeated 500s (and repeated client retries)
|
|
1075
1091
|
// when the directory isn't a git repo or uses shell shorthand like "~/".
|
|
1076
1092
|
console.warn('Failed to get worktrees, returning empty list:', error?.message || error);
|
|
1077
|
-
res.setHeader('X-
|
|
1093
|
+
res.setHeader('X-AiWorker-Warning', 'git worktrees unavailable');
|
|
1078
1094
|
res.json([]);
|
|
1079
1095
|
}
|
|
1080
1096
|
});
|