@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
|
@@ -200,7 +200,7 @@ const resolveGitBinary = () => {
|
|
|
200
200
|
return resolvedGitBinary;
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
-
const explicit = [process.env.GIT_BINARY, process.env.
|
|
203
|
+
const explicit = [process.env.GIT_BINARY, process.env.AIWORKER_GIT_BINARY]
|
|
204
204
|
.map((value) => (typeof value === 'string' ? value.trim() : ''))
|
|
205
205
|
.filter(Boolean);
|
|
206
206
|
for (const candidate of explicit) {
|
|
@@ -364,7 +364,7 @@ const createGit = async (directory, { allowUnsafeSshCommand = false } = {}) => {
|
|
|
364
364
|
}
|
|
365
365
|
: undefined;
|
|
366
366
|
// Always pin simple-git to an explicit working directory. Omitting baseDir
|
|
367
|
-
// makes simple-git use process.cwd(), which breaks when the
|
|
367
|
+
// makes simple-git use process.cwd(), which breaks when the AiWorker
|
|
368
368
|
// server was launched from a neutral directory (e.g. $HOME) and the opened
|
|
369
369
|
// project lives elsewhere — session/project discovery then sees spurious
|
|
370
370
|
// "not a git repository" errors and can abort enumeration.
|
|
@@ -684,6 +684,15 @@ const parseWorktreePorcelain = (raw) => {
|
|
|
684
684
|
const branchRef = line.substring('branch '.length).trim();
|
|
685
685
|
current.branchRef = branchRef;
|
|
686
686
|
current.branch = cleanBranchName(branchRef);
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// git marks a worktree whose directory is gone (deleted outside git) as
|
|
691
|
+
// prunable; it stays registered until `git worktree prune`. The sidebar
|
|
692
|
+
// needs that distinction: the directory is missing, but the sessions that
|
|
693
|
+
// lived there are not.
|
|
694
|
+
if (line === 'prunable' || line.startsWith('prunable ')) {
|
|
695
|
+
current.prunable = true;
|
|
687
696
|
}
|
|
688
697
|
}
|
|
689
698
|
|
|
@@ -991,7 +1000,7 @@ const getFileIdentity = async (filePath) => {
|
|
|
991
1000
|
}
|
|
992
1001
|
};
|
|
993
1002
|
|
|
994
|
-
//
|
|
1003
|
+
// AiWorker places managed worktrees under a deep data-dir path
|
|
995
1004
|
// (`<XDG_DATA_HOME>/opencode/worktree/<40-char project id>/<name>/`). On
|
|
996
1005
|
// Windows that prefix plus a deeply nested repo file routinely exceeds
|
|
997
1006
|
// MAX_PATH (260). Git can check those paths out when core.longpaths is
|
|
@@ -1009,7 +1018,7 @@ const formatWorktreePopulateError = (message) => {
|
|
|
1009
1018
|
return [
|
|
1010
1019
|
text,
|
|
1011
1020
|
'The worktree checkout path exceeds this system\'s path-length limit.',
|
|
1012
|
-
'
|
|
1021
|
+
'AiWorker enables Git `core.longpaths` for worktree population; if this still fails on Windows, enable OS long paths (LongPathsEnabled) or open the repository from a shorter absolute path.',
|
|
1013
1022
|
].join('\n');
|
|
1014
1023
|
};
|
|
1015
1024
|
|
|
@@ -1019,7 +1028,7 @@ export const ensureWorktreeLongpaths = async (directory) => {
|
|
|
1019
1028
|
return;
|
|
1020
1029
|
}
|
|
1021
1030
|
// Local config is shared across linked worktrees via the common git dir, so
|
|
1022
|
-
// subsequent
|
|
1031
|
+
// subsequent AiWorker and CLI git operations in this repo also get long
|
|
1023
1032
|
// path support. Failures here are non-fatal: populate still passes
|
|
1024
1033
|
// `-c core.longpaths=true` on reset.
|
|
1025
1034
|
await runGitCommand(directory, ['config', 'core.longpaths', 'true']);
|
|
@@ -1309,7 +1318,7 @@ export async function computeIntegratePlan(input = {}) {
|
|
|
1309
1318
|
}
|
|
1310
1319
|
|
|
1311
1320
|
const createIntegrateTempWorktree = async (repoRoot, targetBranch) => {
|
|
1312
|
-
const tmpParent = path.join(os.homedir(), '.config', '
|
|
1321
|
+
const tmpParent = path.join(os.homedir(), '.config', 'aiworker', 'tmp');
|
|
1313
1322
|
await fsp.mkdir(tmpParent, { recursive: true });
|
|
1314
1323
|
const tmpDir = await fsp.mkdtemp(path.join(tmpParent, 'oc-integrate-'));
|
|
1315
1324
|
try {
|
|
@@ -1622,7 +1631,7 @@ const resolveCandidateDirectory = async (worktreeRoot, preferredName, explicitBr
|
|
|
1622
1631
|
return { name, directory, branch: explicitBranchName };
|
|
1623
1632
|
}
|
|
1624
1633
|
|
|
1625
|
-
const branch = `
|
|
1634
|
+
const branch = `aiworker/${name}`;
|
|
1626
1635
|
const branchRef = `refs/heads/${branch}`;
|
|
1627
1636
|
const branchExists = await runGitCommand(primaryWorktree, ['show-ref', '--verify', '--quiet', branchRef]);
|
|
1628
1637
|
if (branchExists.success) {
|
|
@@ -1742,7 +1751,7 @@ const loadProjectStartCommand = async (projectID) => {
|
|
|
1742
1751
|
|
|
1743
1752
|
// OpenCode owns its own project/sandbox registry. It records a worktree as a
|
|
1744
1753
|
// sandbox itself when an instance boots for that directory, and filters entries
|
|
1745
|
-
// whose directory no longer exists when reading them back.
|
|
1754
|
+
// whose directory no longer exists when reading them back. AiWorker used to
|
|
1746
1755
|
// write that state directly into OpenCode's storage JSON and SQLite database,
|
|
1747
1756
|
// behind the back of the running process: the row changed but the server was
|
|
1748
1757
|
// never told, so a worktree created while OpenCode was running stayed unknown
|
|
@@ -3248,7 +3257,7 @@ export async function stashPush(directory, options = {}) {
|
|
|
3248
3257
|
const { git } = await createRepositoryGitContext(directory);
|
|
3249
3258
|
const message = typeof options.message === 'string' && options.message.trim()
|
|
3250
3259
|
? options.message.trim()
|
|
3251
|
-
: `
|
|
3260
|
+
: `AiWorker stash ${new Date().toISOString()}`;
|
|
3252
3261
|
const output = await git.raw(['stash', 'push', '--include-untracked', '-m', message]);
|
|
3253
3262
|
return {
|
|
3254
3263
|
success: true,
|
|
@@ -3687,6 +3696,35 @@ export async function getBranches(directory) {
|
|
|
3687
3696
|
}
|
|
3688
3697
|
}
|
|
3689
3698
|
|
|
3699
|
+
/**
|
|
3700
|
+
* Counts locally unpushed commits for a small caller-supplied set of local
|
|
3701
|
+
* branches. This deliberately reads only local refs: the branch picker calls
|
|
3702
|
+
* it when opened, never polls, and never fetches a remote behind the user's
|
|
3703
|
+
* back. Unknown, remote, and upstream-less branches are omitted.
|
|
3704
|
+
*/
|
|
3705
|
+
export async function getUnpushedBranchCounts(directory, branchNames) {
|
|
3706
|
+
const { git } = await createRepositoryGitContext(directory);
|
|
3707
|
+
const requested = [...new Set(Array.isArray(branchNames) ? branchNames : [])]
|
|
3708
|
+
.filter((name) => typeof name === 'string' && name.length > 0)
|
|
3709
|
+
.slice(0, 5);
|
|
3710
|
+
if (requested.length === 0) return { counts: {} };
|
|
3711
|
+
|
|
3712
|
+
const local = new Set((await git.branchLocal()).all);
|
|
3713
|
+
const counts = {};
|
|
3714
|
+
await Promise.all(requested.map(async (branch) => {
|
|
3715
|
+
if (!local.has(branch)) return;
|
|
3716
|
+
const upstream = await git.raw(['rev-parse', '--abbrev-ref', '--symbolic-full-name', `${branch}@{upstream}`])
|
|
3717
|
+
.then((value) => value.trim())
|
|
3718
|
+
.catch(() => '');
|
|
3719
|
+
if (!upstream) return;
|
|
3720
|
+
const count = await git.raw(['rev-list', '--count', `${upstream}..${branch}`])
|
|
3721
|
+
.then((value) => Number.parseInt(value.trim(), 10))
|
|
3722
|
+
.catch(() => 0);
|
|
3723
|
+
if (Number.isFinite(count) && count > 0) counts[branch] = count;
|
|
3724
|
+
}));
|
|
3725
|
+
return { counts };
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3690
3728
|
async function getRemoteDefaultBranches(git) {
|
|
3691
3729
|
let defaults = {};
|
|
3692
3730
|
|
|
@@ -4007,6 +4045,7 @@ export async function getWorktrees(directory) {
|
|
|
4007
4045
|
name: path.basename(entry.worktree || ''),
|
|
4008
4046
|
branch: entry.branch || '',
|
|
4009
4047
|
path: entry.worktree,
|
|
4048
|
+
prunable: entry.prunable === true,
|
|
4010
4049
|
}));
|
|
4011
4050
|
} catch (error) {
|
|
4012
4051
|
// Worktrees are an optional feature. When the caller passes a directory
|
|
@@ -4266,6 +4305,7 @@ async function attachGitWorktreeToCandidate(context, candidate, input = {}) {
|
|
|
4266
4305
|
|
|
4267
4306
|
const parsedRemoteStartRef = await resolveRemoteBranchRef(context.primaryWorktree, startRef);
|
|
4268
4307
|
if (parsedRemoteStartRef) {
|
|
4308
|
+
worktreeAddArgs.splice(2, 0, '--no-track');
|
|
4269
4309
|
inferredUpstream = {
|
|
4270
4310
|
remote: parsedRemoteStartRef.remote,
|
|
4271
4311
|
branch: parsedRemoteStartRef.branch,
|
|
@@ -4273,24 +4313,17 @@ async function attachGitWorktreeToCandidate(context, candidate, input = {}) {
|
|
|
4273
4313
|
}
|
|
4274
4314
|
}
|
|
4275
4315
|
|
|
4276
|
-
if (ensureRemoteName && ensureRemoteUrl) {
|
|
4316
|
+
if (mode === 'existing' && ensureRemoteName && ensureRemoteUrl) {
|
|
4277
4317
|
await ensureRemoteWithUrl(context.primaryWorktree, ensureRemoteName, ensureRemoteUrl);
|
|
4278
4318
|
}
|
|
4279
4319
|
|
|
4280
|
-
if (mode === 'new') {
|
|
4281
|
-
const parsedRemoteStartRef = await resolveRemoteBranchRef(context.primaryWorktree, startRef);
|
|
4282
|
-
if (parsedRemoteStartRef) {
|
|
4283
|
-
await fetchRemoteBranchRef(context.primaryWorktree, parsedRemoteStartRef.remote, parsedRemoteStartRef.branch);
|
|
4284
|
-
}
|
|
4285
|
-
}
|
|
4286
|
-
|
|
4287
4320
|
await runGitCommandOrThrow(context.primaryWorktree, worktreeAddArgs, 'Failed to create git worktree');
|
|
4288
4321
|
|
|
4289
4322
|
const upstreamRemote = shouldSetUpstream
|
|
4290
|
-
? String(
|
|
4323
|
+
? String(input?.upstreamRemote || inferredUpstream?.remote || '').trim()
|
|
4291
4324
|
: '';
|
|
4292
4325
|
const upstreamBranch = shouldSetUpstream
|
|
4293
|
-
? String(
|
|
4326
|
+
? String(input?.upstreamBranch || inferredUpstream?.branch || '').trim()
|
|
4294
4327
|
: '';
|
|
4295
4328
|
|
|
4296
4329
|
const bootstrapStatus = setWorktreeBootstrapState(
|
|
@@ -4325,6 +4358,50 @@ async function attachGitWorktreeToCandidate(context, candidate, input = {}) {
|
|
|
4325
4358
|
};
|
|
4326
4359
|
}
|
|
4327
4360
|
|
|
4361
|
+
const prepareWorktreeCreateSource = async (context, input = {}) => {
|
|
4362
|
+
if (input?.mode === 'existing') {
|
|
4363
|
+
return { input, sourceFetchFailed: false };
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
const startRef = normalizeStartRef(input?.startRef);
|
|
4367
|
+
const remoteStartRef = await resolveRemoteBranchRef(context.primaryWorktree, startRef);
|
|
4368
|
+
if (!remoteStartRef) {
|
|
4369
|
+
return { input, sourceFetchFailed: false };
|
|
4370
|
+
}
|
|
4371
|
+
|
|
4372
|
+
const status = await getStatus(context.primaryWorktree, { mode: 'light' }).catch(() => null);
|
|
4373
|
+
const trackingRef = status?.tracking
|
|
4374
|
+
? await resolveRemoteBranchRef(context.primaryWorktree, status.tracking)
|
|
4375
|
+
: null;
|
|
4376
|
+
const canFallbackToLocal = Boolean(
|
|
4377
|
+
status?.current
|
|
4378
|
+
&& status.ahead === 0
|
|
4379
|
+
&& trackingRef?.fullRef === remoteStartRef.fullRef
|
|
4380
|
+
);
|
|
4381
|
+
|
|
4382
|
+
try {
|
|
4383
|
+
await fetchRemoteBranchRef(context.primaryWorktree, remoteStartRef.remote, remoteStartRef.branch);
|
|
4384
|
+
return { input, sourceFetchFailed: false };
|
|
4385
|
+
} catch (error) {
|
|
4386
|
+
if (canFallbackToLocal) {
|
|
4387
|
+
return {
|
|
4388
|
+
input: { ...input, startRef: status.current },
|
|
4389
|
+
sourceFetchFailed: true,
|
|
4390
|
+
};
|
|
4391
|
+
}
|
|
4392
|
+
|
|
4393
|
+
const refExists = await runGitCommand(
|
|
4394
|
+
context.primaryWorktree,
|
|
4395
|
+
['show-ref', '--verify', '--quiet', remoteStartRef.fullRef]
|
|
4396
|
+
);
|
|
4397
|
+
if (!refExists.success) {
|
|
4398
|
+
throw error;
|
|
4399
|
+
}
|
|
4400
|
+
console.warn(`Worktree create: failed to refresh ${remoteStartRef.remote}/${remoteStartRef.branch}, proceeding with the existing remote-tracking ref`);
|
|
4401
|
+
return { input, sourceFetchFailed: false };
|
|
4402
|
+
}
|
|
4403
|
+
};
|
|
4404
|
+
|
|
4328
4405
|
export async function createWorktree(directory, input = {}) {
|
|
4329
4406
|
const mode = input?.mode === 'existing' ? 'existing' : 'new';
|
|
4330
4407
|
const context = await resolveWorktreeProjectContext(directory);
|
|
@@ -4333,10 +4410,18 @@ export async function createWorktree(directory, input = {}) {
|
|
|
4333
4410
|
await assertWorktreeCreatePreflight(directory, input);
|
|
4334
4411
|
}
|
|
4335
4412
|
|
|
4413
|
+
const ensureRemoteName = String(input?.ensureRemoteName || '').trim();
|
|
4414
|
+
const ensureRemoteUrl = String(input?.ensureRemoteUrl || '').trim();
|
|
4415
|
+
if (ensureRemoteName && ensureRemoteUrl) {
|
|
4416
|
+
await ensureRemoteWithUrl(context.primaryWorktree, ensureRemoteName, ensureRemoteUrl);
|
|
4417
|
+
}
|
|
4418
|
+
const prepared = await prepareWorktreeCreateSource(context, input);
|
|
4419
|
+
const preparedInput = prepared.input;
|
|
4420
|
+
|
|
4336
4421
|
await fsp.mkdir(context.worktreeRoot, { recursive: true });
|
|
4337
4422
|
|
|
4338
|
-
const preferredName = String(
|
|
4339
|
-
const preferredBranchName = cleanBranchName(String(
|
|
4423
|
+
const preferredName = String(preparedInput?.worktreeName || preparedInput?.name || '').trim();
|
|
4424
|
+
const preferredBranchName = cleanBranchName(String(preparedInput?.branchName || '').trim());
|
|
4340
4425
|
|
|
4341
4426
|
const candidate = await resolveCandidateDirectory(
|
|
4342
4427
|
context.worktreeRoot,
|
|
@@ -4345,7 +4430,7 @@ export async function createWorktree(directory, input = {}) {
|
|
|
4345
4430
|
context.primaryWorktree
|
|
4346
4431
|
);
|
|
4347
4432
|
|
|
4348
|
-
if (
|
|
4433
|
+
if (preparedInput?.returnAfterDirectoryCreated === true) {
|
|
4349
4434
|
await fsp.mkdir(candidate.directory, { recursive: false });
|
|
4350
4435
|
|
|
4351
4436
|
const bootstrapStatus = setWorktreeBootstrapState(
|
|
@@ -4354,10 +4439,10 @@ export async function createWorktree(directory, input = {}) {
|
|
|
4354
4439
|
WORKTREE_BOOTSTRAP_PHASE_DIRECTORY_CREATED
|
|
4355
4440
|
);
|
|
4356
4441
|
const localBranch = mode === 'existing'
|
|
4357
|
-
? cleanBranchName(String(
|
|
4442
|
+
? cleanBranchName(String(preparedInput?.branchName || preparedInput?.existingBranch || candidate.branch || '').trim())
|
|
4358
4443
|
: candidate.branch;
|
|
4359
4444
|
|
|
4360
|
-
const task = attachGitWorktreeToCandidate(context, candidate,
|
|
4445
|
+
const task = attachGitWorktreeToCandidate(context, candidate, preparedInput).catch(async (error) => {
|
|
4361
4446
|
setWorktreeBootstrapState(
|
|
4362
4447
|
candidate.directory,
|
|
4363
4448
|
WORKTREE_BOOTSTRAP_FAILED,
|
|
@@ -4369,7 +4454,7 @@ export async function createWorktree(directory, input = {}) {
|
|
|
4369
4454
|
});
|
|
4370
4455
|
trackWorktreeBootstrapTask(candidate.directory, task);
|
|
4371
4456
|
|
|
4372
|
-
|
|
4457
|
+
const result = {
|
|
4373
4458
|
head: '',
|
|
4374
4459
|
name: candidate.name,
|
|
4375
4460
|
branch: localBranch,
|
|
@@ -4377,9 +4462,14 @@ export async function createWorktree(directory, input = {}) {
|
|
|
4377
4462
|
directoryCreated: true,
|
|
4378
4463
|
bootstrapStatus,
|
|
4379
4464
|
};
|
|
4465
|
+
if (prepared.sourceFetchFailed) {
|
|
4466
|
+
result.sourceFetchFailed = true;
|
|
4467
|
+
}
|
|
4468
|
+
return result;
|
|
4380
4469
|
}
|
|
4381
4470
|
|
|
4382
|
-
|
|
4471
|
+
const result = await attachGitWorktreeToCandidate(context, candidate, preparedInput);
|
|
4472
|
+
return prepared.sourceFetchFailed ? { ...result, sourceFetchFailed: true } : result;
|
|
4383
4473
|
}
|
|
4384
4474
|
|
|
4385
4475
|
export async function getWorktreeBootstrapStatus(directory) {
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
createWorktree,
|
|
13
13
|
getWorktreeBootstrapStatus,
|
|
14
14
|
getBranches,
|
|
15
|
+
getUnpushedBranchCounts,
|
|
15
16
|
getRangeDiff,
|
|
16
17
|
getStatus,
|
|
17
18
|
getWorktrees,
|
|
@@ -54,6 +55,14 @@ const runGit = (cwd, args) =>
|
|
|
54
55
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
55
56
|
});
|
|
56
57
|
|
|
58
|
+
const readBranchConfig = (cwd, branch, key) => {
|
|
59
|
+
try {
|
|
60
|
+
return runGit(cwd, ['config', '--get', `branch.${branch}.${key}`]).trim();
|
|
61
|
+
} catch {
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
57
66
|
/**
|
|
58
67
|
* A repository on `next` whose only remote publishes `defaultBranch` and has it
|
|
59
68
|
* recorded as that remote's HEAD — the shape of every repository whose default
|
|
@@ -508,6 +517,24 @@ describe('getWorktrees', () => {
|
|
|
508
517
|
expect(Array.isArray(result)).toBe(true);
|
|
509
518
|
expect(warnSpy).not.toHaveBeenCalled();
|
|
510
519
|
});
|
|
520
|
+
it('flags a worktree whose directory was deleted outside git as prunable', async () => {
|
|
521
|
+
const repo = createTempDir();
|
|
522
|
+
runGit(repo, ['init', '-b', 'main']);
|
|
523
|
+
runGit(repo, ['config', 'user.email', 'test@example.com']);
|
|
524
|
+
runGit(repo, ['config', 'user.name', 'Test User']);
|
|
525
|
+
runGit(repo, ['commit', '--allow-empty', '-m', 'init']);
|
|
526
|
+
const worktreePath = path.join(createTempDir(), 'feature');
|
|
527
|
+
runGit(repo, ['worktree', 'add', worktreePath, '-b', 'feature']);
|
|
528
|
+
|
|
529
|
+
const before = await getWorktrees(repo);
|
|
530
|
+
expect(before.find((entry) => entry.branch === 'feature')).toMatchObject({ prunable: false });
|
|
531
|
+
|
|
532
|
+
fs.rmSync(worktreePath, { recursive: true, force: true });
|
|
533
|
+
|
|
534
|
+
const after = await getWorktrees(repo);
|
|
535
|
+
expect(after.find((entry) => entry.branch === 'feature')).toMatchObject({ path: expect.any(String), prunable: true });
|
|
536
|
+
expect(after.find((entry) => entry.branch === 'main')).toMatchObject({ prunable: false });
|
|
537
|
+
});
|
|
511
538
|
});
|
|
512
539
|
|
|
513
540
|
// ---------------------------------------------------------------------------
|
|
@@ -622,7 +649,7 @@ describe('createWorktree', () => {
|
|
|
622
649
|
const created = await createWorktree(repo, {
|
|
623
650
|
mode: 'new',
|
|
624
651
|
worktreeName: 'hook-test',
|
|
625
|
-
branchName: '
|
|
652
|
+
branchName: 'aiworker/hook-test',
|
|
626
653
|
returnAfterDirectoryCreated: true,
|
|
627
654
|
});
|
|
628
655
|
|
|
@@ -674,7 +701,7 @@ describe('createWorktree', () => {
|
|
|
674
701
|
const created = await createWorktree(repo, {
|
|
675
702
|
mode: 'new',
|
|
676
703
|
worktreeName: 'hook-skip-test',
|
|
677
|
-
branchName: '
|
|
704
|
+
branchName: 'aiworker/hook-skip-test',
|
|
678
705
|
returnAfterDirectoryCreated: true,
|
|
679
706
|
});
|
|
680
707
|
|
|
@@ -717,7 +744,7 @@ describe('createWorktree', () => {
|
|
|
717
744
|
const created = await createWorktree(repo, {
|
|
718
745
|
mode: 'new',
|
|
719
746
|
worktreeName: 'hook-fail-test',
|
|
720
|
-
branchName: '
|
|
747
|
+
branchName: 'aiworker/hook-fail-test',
|
|
721
748
|
returnAfterDirectoryCreated: true,
|
|
722
749
|
});
|
|
723
750
|
|
|
@@ -854,6 +881,135 @@ describe('createWorktree', () => {
|
|
|
854
881
|
}
|
|
855
882
|
}
|
|
856
883
|
});
|
|
884
|
+
|
|
885
|
+
it('does not auto-track the remote start ref when creating a new branch from it', async () => {
|
|
886
|
+
if (!canRunGit()) return;
|
|
887
|
+
|
|
888
|
+
const previousXdgDataHome = process.env.XDG_DATA_HOME;
|
|
889
|
+
const dataHome = createTempDir();
|
|
890
|
+
process.env.XDG_DATA_HOME = dataHome;
|
|
891
|
+
|
|
892
|
+
try {
|
|
893
|
+
const { repository } = createRepositoryWithRemote({ defaultBranch: 'main' });
|
|
894
|
+
|
|
895
|
+
const created = await createWorktree(repository, {
|
|
896
|
+
mode: 'new',
|
|
897
|
+
branchName: 'aiworker/feature',
|
|
898
|
+
worktreeName: 'feature-wt',
|
|
899
|
+
startRef: 'remotes/origin/main',
|
|
900
|
+
setUpstream: true,
|
|
901
|
+
upstreamRemote: 'origin',
|
|
902
|
+
upstreamBranch: 'aiworker/feature',
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
expect(created.branch).toBe('aiworker/feature');
|
|
906
|
+
|
|
907
|
+
await expect.poll(
|
|
908
|
+
() => getWorktreeBootstrapStatus(created.path).then((status) => status.status === 'ready' || status.status === 'failed'),
|
|
909
|
+
{ timeout: 5_000 }
|
|
910
|
+
).toBe(true);
|
|
911
|
+
|
|
912
|
+
expect(readBranchConfig(created.path, 'aiworker/feature', 'remote')).toBe('');
|
|
913
|
+
expect(readBranchConfig(created.path, 'aiworker/feature', 'merge')).toBe('');
|
|
914
|
+
} finally {
|
|
915
|
+
if (previousXdgDataHome === undefined) {
|
|
916
|
+
delete process.env.XDG_DATA_HOME;
|
|
917
|
+
} else {
|
|
918
|
+
process.env.XDG_DATA_HOME = previousXdgDataHome;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}, 30_000);
|
|
922
|
+
|
|
923
|
+
it('falls back to the remote start ref for upstream tracking when no explicit keys are given', async () => {
|
|
924
|
+
if (!canRunGit()) return;
|
|
925
|
+
|
|
926
|
+
const previousXdgDataHome = process.env.XDG_DATA_HOME;
|
|
927
|
+
const dataHome = createTempDir();
|
|
928
|
+
process.env.XDG_DATA_HOME = dataHome;
|
|
929
|
+
|
|
930
|
+
try {
|
|
931
|
+
const { repository } = createRepositoryWithRemote({ defaultBranch: 'main' });
|
|
932
|
+
|
|
933
|
+
const created = await createWorktree(repository, {
|
|
934
|
+
mode: 'new',
|
|
935
|
+
branchName: 'aiworker/fallback-wt',
|
|
936
|
+
worktreeName: 'fallback-wt',
|
|
937
|
+
startRef: 'remotes/origin/main',
|
|
938
|
+
setUpstream: true,
|
|
939
|
+
});
|
|
940
|
+
|
|
941
|
+
await expect.poll(
|
|
942
|
+
() => readBranchConfig(created.path, 'aiworker/fallback-wt', 'merge'),
|
|
943
|
+
{ timeout: 5_000 }
|
|
944
|
+
).toBe('refs/heads/main');
|
|
945
|
+
expect(readBranchConfig(created.path, 'aiworker/fallback-wt', 'remote')).toBe('origin');
|
|
946
|
+
} finally {
|
|
947
|
+
if (previousXdgDataHome === undefined) {
|
|
948
|
+
delete process.env.XDG_DATA_HOME;
|
|
949
|
+
} else {
|
|
950
|
+
process.env.XDG_DATA_HOME = previousXdgDataHome;
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
}, 30_000);
|
|
954
|
+
|
|
955
|
+
it('falls back to the tracked local branch when the source fetch fails', async () => {
|
|
956
|
+
if (!canRunGit()) return;
|
|
957
|
+
|
|
958
|
+
const previousXdgDataHome = process.env.XDG_DATA_HOME;
|
|
959
|
+
const dataHome = createTempDir();
|
|
960
|
+
process.env.XDG_DATA_HOME = dataHome;
|
|
961
|
+
|
|
962
|
+
try {
|
|
963
|
+
const { repository } = createRepositoryWithRemote({ defaultBranch: 'main' });
|
|
964
|
+
runGit(repository, ['branch', '--set-upstream-to=origin/main', 'next']);
|
|
965
|
+
runGit(repository, ['remote', 'set-url', 'origin', '/nonexistent/openchamber-unreachable.git']);
|
|
966
|
+
|
|
967
|
+
const created = await createWorktree(repository, {
|
|
968
|
+
mode: 'new',
|
|
969
|
+
branchName: 'aiworker/stale-ref-wt',
|
|
970
|
+
worktreeName: 'stale-ref-wt',
|
|
971
|
+
startRef: 'remotes/origin/main',
|
|
972
|
+
});
|
|
973
|
+
|
|
974
|
+
expect(created.branch).toBe('aiworker/stale-ref-wt');
|
|
975
|
+
expect(created.sourceFetchFailed).toBe(true);
|
|
976
|
+
const expectedHead = runGit(repository, ['rev-parse', 'next']).trim();
|
|
977
|
+
expect(runGit(created.path, ['rev-parse', 'HEAD']).trim()).toBe(expectedHead);
|
|
978
|
+
} finally {
|
|
979
|
+
if (previousXdgDataHome === undefined) {
|
|
980
|
+
delete process.env.XDG_DATA_HOME;
|
|
981
|
+
} else {
|
|
982
|
+
process.env.XDG_DATA_HOME = previousXdgDataHome;
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
}, 30_000);
|
|
986
|
+
|
|
987
|
+
it('rejects creation from a remote start ref that was never fetched and cannot be fetched', async () => {
|
|
988
|
+
if (!canRunGit()) return;
|
|
989
|
+
|
|
990
|
+
const previousXdgDataHome = process.env.XDG_DATA_HOME;
|
|
991
|
+
const dataHome = createTempDir();
|
|
992
|
+
process.env.XDG_DATA_HOME = dataHome;
|
|
993
|
+
|
|
994
|
+
try {
|
|
995
|
+
const { repository } = createRepositoryWithRemote({ defaultBranch: 'main' });
|
|
996
|
+
runGit(repository, ['update-ref', '-d', 'refs/remotes/origin/main']);
|
|
997
|
+
runGit(repository, ['remote', 'set-url', 'origin', '/nonexistent/openchamber-unreachable.git']);
|
|
998
|
+
|
|
999
|
+
await expect(createWorktree(repository, {
|
|
1000
|
+
mode: 'new',
|
|
1001
|
+
branchName: 'aiworker/never-fetched-wt',
|
|
1002
|
+
worktreeName: 'never-fetched-wt',
|
|
1003
|
+
startRef: 'remotes/origin/main',
|
|
1004
|
+
})).rejects.toThrow(/does not appear to be a git repository|Could not read from remote repository/i);
|
|
1005
|
+
} finally {
|
|
1006
|
+
if (previousXdgDataHome === undefined) {
|
|
1007
|
+
delete process.env.XDG_DATA_HOME;
|
|
1008
|
+
} else {
|
|
1009
|
+
process.env.XDG_DATA_HOME = previousXdgDataHome;
|
|
1010
|
+
}
|
|
1011
|
+
}
|
|
1012
|
+
}, 30_000);
|
|
857
1013
|
});
|
|
858
1014
|
|
|
859
1015
|
// ---------------------------------------------------------------------------
|
|
@@ -1498,6 +1654,21 @@ describe.runIf(canRunGit())('getBranches', () => {
|
|
|
1498
1654
|
});
|
|
1499
1655
|
});
|
|
1500
1656
|
|
|
1657
|
+
describe.runIf(canRunGit())('getUnpushedBranchCounts', () => {
|
|
1658
|
+
it('counts only commits ahead of a locally known upstream', async () => {
|
|
1659
|
+
const { repository } = createRepositoryWithRemote();
|
|
1660
|
+
runGit(repository, ['branch', '--set-upstream-to=origin/react', 'next']);
|
|
1661
|
+
fs.writeFileSync(path.join(repository, 'ahead.txt'), 'ahead\n');
|
|
1662
|
+
runGit(repository, ['add', 'ahead.txt']);
|
|
1663
|
+
runGit(repository, ['commit', '-m', 'ahead']);
|
|
1664
|
+
runGit(repository, ['checkout', '-b', 'no-upstream']);
|
|
1665
|
+
|
|
1666
|
+
await expect(getUnpushedBranchCounts(repository, ['next', 'no-upstream', 'remotes/origin/react'])).resolves.toEqual({
|
|
1667
|
+
counts: { next: 1 },
|
|
1668
|
+
});
|
|
1669
|
+
});
|
|
1670
|
+
});
|
|
1671
|
+
|
|
1501
1672
|
describe.runIf(canRunGit())('getRangeDiff', () => {
|
|
1502
1673
|
it('resolves a base that exists only on a remote other than origin', async () => {
|
|
1503
1674
|
const { repository } = createRepositoryWithRemote({ remoteName: 'upstream', defaultBranch: 'react' });
|
|
@@ -2,13 +2,13 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import os from 'os';
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
? path.resolve(process.env.
|
|
7
|
-
: path.join(os.homedir(), '.config', '
|
|
5
|
+
const AIWORKER_DATA_DIR = process.env.AIWORKER_DATA_DIR
|
|
6
|
+
? path.resolve(process.env.AIWORKER_DATA_DIR)
|
|
7
|
+
: path.join(os.homedir(), '.config', 'aiworker');
|
|
8
8
|
|
|
9
|
-
const STORAGE_DIR =
|
|
9
|
+
const STORAGE_DIR = AIWORKER_DATA_DIR;
|
|
10
10
|
const STORAGE_FILE = path.join(STORAGE_DIR, 'github-auth.json');
|
|
11
|
-
const SETTINGS_FILE = path.join(
|
|
11
|
+
const SETTINGS_FILE = path.join(AIWORKER_DATA_DIR, 'settings.json');
|
|
12
12
|
|
|
13
13
|
const DEFAULT_GITHUB_CLIENT_ID = 'Ov23lizomPOC3eFYo56r';
|
|
14
14
|
const DEFAULT_GITHUB_SCOPES = 'repo read:org workflow read:user user:email';
|
|
@@ -45,7 +45,7 @@ function readJsonFile() {
|
|
|
45
45
|
function writeJsonFile(payload) {
|
|
46
46
|
ensureStorageDir();
|
|
47
47
|
|
|
48
|
-
// Atomic write so multiple
|
|
48
|
+
// Atomic write so multiple AiWorker instances can safely share the same file.
|
|
49
49
|
const tmpFile = `${STORAGE_FILE}.${process.pid}.${Date.now()}.tmp`;
|
|
50
50
|
fs.writeFileSync(tmpFile, JSON.stringify(payload, null, 2), 'utf8');
|
|
51
51
|
try {
|
|
@@ -299,7 +299,7 @@ export function clearGitHubAuth() {
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
export function getGitHubClientId() {
|
|
302
|
-
const raw = process.env.
|
|
302
|
+
const raw = process.env.AIWORKER_GITHUB_CLIENT_ID;
|
|
303
303
|
const clientId = typeof raw === 'string' ? raw.trim() : '';
|
|
304
304
|
if (clientId) return clientId;
|
|
305
305
|
|
|
@@ -317,7 +317,7 @@ export function getGitHubClientId() {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
export function getGitHubScopes() {
|
|
320
|
-
const raw = process.env.
|
|
320
|
+
const raw = process.env.AIWORKER_GITHUB_SCOPES;
|
|
321
321
|
const fromEnv = typeof raw === 'string' ? raw.trim() : '';
|
|
322
322
|
if (fromEnv) return fromEnv;
|
|
323
323
|
|
|
@@ -339,7 +339,7 @@ const repoPullsCache = new Map();
|
|
|
339
339
|
// head, and while that one is open the open-PR path wins and never reads this
|
|
340
340
|
// cache at all. "No history yet" is the volatile answer, since closing or
|
|
341
341
|
// merging a PR elsewhere flips it, so it expires far sooner. Either way, doing
|
|
342
|
-
// it from
|
|
342
|
+
// it from AiWorker invalidates the entry immediately.
|
|
343
343
|
const HISTORICAL_PR_FOUND_TTL_MS = 6 * 60 * 60 * 1000;
|
|
344
344
|
const HISTORICAL_PR_ABSENT_TTL_MS = 10 * 60 * 1000;
|
|
345
345
|
const HISTORICAL_PR_CACHE_MAX_ENTRIES = 500;
|
|
@@ -281,7 +281,7 @@ export function registerGitHubRoutes(app) {
|
|
|
281
281
|
const clientId = getGitHubClientId();
|
|
282
282
|
if (!clientId) {
|
|
283
283
|
return res.status(400).json({
|
|
284
|
-
error: 'GitHub OAuth client not configured. Set
|
|
284
|
+
error: 'GitHub OAuth client not configured. Set AIWORKER_GITHUB_CLIENT_ID.',
|
|
285
285
|
});
|
|
286
286
|
}
|
|
287
287
|
|
|
@@ -313,7 +313,7 @@ export function registerGitHubRoutes(app) {
|
|
|
313
313
|
const clientId = getGitHubClientId();
|
|
314
314
|
if (!clientId) {
|
|
315
315
|
return res.status(400).json({
|
|
316
|
-
error: 'GitHub OAuth client not configured. Set
|
|
316
|
+
error: 'GitHub OAuth client not configured. Set AIWORKER_GITHUB_CLIENT_ID.',
|
|
317
317
|
});
|
|
318
318
|
}
|
|
319
319
|
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* external command it spawns, which corrupts Python venv detection and any
|
|
7
7
|
* other program that reads argv[0]/$0 while leaving `/proc/self/exe` correct.
|
|
8
8
|
*
|
|
9
|
-
* See
|
|
9
|
+
* See aiworker/openchamber#2588 and pingdotgg/t3code#2509.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { createRequire } from 'node:module';
|
|
@@ -9,7 +9,7 @@ describe('stripAppImageArgv0Leak', () => {
|
|
|
9
9
|
it('removes ARGV0 from a child env object', () => {
|
|
10
10
|
const env = {
|
|
11
11
|
PATH: '/usr/bin',
|
|
12
|
-
ARGV0: '/path/to/
|
|
12
|
+
ARGV0: '/path/to/AiWorker-1.17.2-linux-x86_64.AppImage',
|
|
13
13
|
SHELL: '/bin/zsh',
|
|
14
14
|
};
|
|
15
15
|
|
|
@@ -35,7 +35,7 @@ describe('stripAppImageArgv0Leak', () => {
|
|
|
35
35
|
describe('clearAppImageArgv0FromProcessEnv', () => {
|
|
36
36
|
it('removes ARGV0 from process.env', () => {
|
|
37
37
|
const previous = process.env.ARGV0;
|
|
38
|
-
process.env.ARGV0 = '/path/to/
|
|
38
|
+
process.env.ARGV0 = '/path/to/AiWorker.AppImage';
|
|
39
39
|
try {
|
|
40
40
|
clearAppImageArgv0FromProcessEnv();
|
|
41
41
|
expect(process.env.ARGV0).toBeUndefined();
|