@vantran-se/openchamber-web 2.1.1 → 2.2.0
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 +32 -24
- package/bin/cli.js +1 -3
- package/bin/cli.test.js +40 -16
- package/bin/lib/DOCUMENTATION.md +6 -5
- package/bin/lib/cli-args.js +6 -1
- package/bin/lib/cli-args.test.js +34 -0
- package/bin/lib/cli-lifecycle.js +0 -1
- package/bin/lib/cli-network.js +8 -2
- package/bin/lib/cli-process.js +1 -1
- package/bin/lib/cli-settings-accessors.test.js +21 -13
- package/bin/lib/cli-startup.js +17 -11
- package/bin/lib/cli-startup.test.js +92 -2
- package/bin/lib/commands-connect-url.js +8 -1
- package/bin/lib/commands-schedule.js +8 -2
- package/bin/lib/commands-serve.js +15 -21
- package/bin/lib/commands-update.js +12 -24
- package/bin/lib/commands-update.test.js +14 -46
- package/dist/assets/DiffView-Cv9MSXl1.js +4 -0
- package/dist/assets/FilePreviewCommentMenu-D4kLseHj.js +4 -0
- package/dist/assets/FilesView-BVoD8I2x.js +14 -0
- package/dist/assets/{GitView-DzuzhIPx.js → GitView-Bzb8p-ew.js} +4 -4
- package/dist/assets/GuestSurfacePane-Crdbvsxo.js +1 -0
- package/dist/assets/InProgressOperationBanner-CwMjNQgk.js +2 -0
- package/dist/assets/{JsonTreeView-B_EPRjzy.js → JsonTreeView-DRKHZfsn.js} +1 -1
- package/dist/assets/MarkdownImageGallery-DZtqT1Zn.js +1 -0
- package/dist/assets/MarkdownRendererImpl-CqG7HCNd.js +10 -0
- package/dist/assets/OnboardingScreen-DMIxwYK5.js +1 -0
- package/dist/assets/{PatchDiff-6yh1csza.js → PatchDiff-CUcCg1jk.js} +1 -1
- package/dist/assets/PierreDiffViewer-CnnR-dnD.js +228 -0
- package/dist/assets/PlanView-RCBadcY7.js +5 -0
- package/dist/assets/SettingsView-CjBjZFRO.js +30 -0
- package/dist/assets/SettingsWindow-DyM7QuhI.js +1 -0
- package/dist/assets/SubmoduleDiffSummary-BWIfgMED.js +1 -0
- package/dist/assets/ToolOutputDialog-Q0P3FuAi.js +15 -0
- package/dist/assets/ToolPartDiffPreview-p7qR9FpU.js +8 -0
- package/dist/assets/{VirtualizedFileDiff-BTJVRkyo.js → VirtualizedFileDiff-CFpjL8Ns.js} +3 -3
- package/dist/assets/{Virtualizer-xCEYz34p.js → Virtualizer-C0IsclZn.js} +1 -1
- package/dist/assets/WalkthroughView-DI31zD02.js +4 -0
- package/dist/assets/appThemeRegistry-B9gkFq9i.js +1 -0
- package/dist/assets/{computeVirtualFileMetrics-CmPe29DM.js → computeVirtualFileMetrics-C2WM6JC2.js} +2 -2
- package/dist/assets/de-YKfk5MmC.js +14 -0
- package/dist/assets/es-_gwT0kr-.js +20 -0
- package/dist/assets/fileTreeStatus-D438yi8M.js +1 -0
- package/dist/assets/fr-DqzvXmIm.js +18 -0
- package/dist/assets/index-BLaHKdtx.js +1 -0
- package/dist/assets/index-BkMXRrVQ.css +1 -0
- package/dist/assets/index-DxNa7xYB.js +65 -0
- package/dist/assets/initializeSharedPreferences-Bck5EAWP.js +1 -0
- package/dist/assets/{isDiffPlainText-CQmDCnEv.js → isDiffPlainText-Dgbw8VKk.js} +1 -1
- package/dist/assets/{isFilePlainText-CYBUzW4I.js → isFilePlainText-_ZS5UYRj.js} +1 -1
- package/dist/assets/ja-B-GFYhQE.js +20 -0
- package/dist/assets/ko-mzksfqDC.js +20 -0
- package/dist/assets/main-C5Xx8dn_.js +2 -0
- package/dist/assets/main-CfBSQM1H.js +990 -0
- package/dist/assets/markdownCore-BmWwW1ll.js +7 -0
- package/dist/assets/miniChat-mnKwy4vQ.js +2 -0
- package/dist/assets/mobile-DeEQd0wZ.js +2 -0
- package/dist/assets/nl-CWQr6NSq.js +20 -0
- package/dist/assets/{parseDiffFromFile-Cy0PNxun.js → parseDiffFromFile-BUgn-T9p.js} +2 -2
- package/dist/assets/patchFileDiff-Dt8LhgBh.js +13 -0
- package/dist/assets/pl-UmRcDUX2.js +20 -0
- package/dist/assets/pt-BR-BSLybvVF.js +20 -0
- package/dist/assets/relocateRestoredSession-B5E9xb3T.js +1 -0
- package/dist/assets/renderElectronMiniChatApp-C0a9A5_J.js +2 -0
- package/dist/assets/renderMobileApp-BNncg3Pk.js +25 -0
- package/dist/assets/runtimeEndpointReset-CZ5aafpl.js +62 -0
- package/dist/assets/{selectionMarkdown-TkYk5h9l.js → selectionMarkdown-CUN3wUld.js} +9 -9
- package/dist/assets/{sessionOwnership-Bs1xbRfB.js → sessionOwnership-BSuxCEhb.js} +1 -1
- package/dist/assets/shikiHighlight-DHDx-6eM.js +1 -0
- package/dist/assets/space-apply-DM_2pRW7.js +1 -0
- package/dist/assets/space-close-Bpomt8z0.js +1 -0
- package/dist/assets/{surface-B6n7wJtt.js → surface-C-jQaGnL.js} +1 -1
- package/dist/assets/{textMateThemeFromAppTheme-CDlKffWz.js → textMateThemeFromAppTheme-DlsTphbY.js} +1 -1
- package/dist/assets/tr-gaTrX_HK.js +11 -0
- package/dist/assets/uk-CnJF6ykl.js +20 -0
- package/dist/assets/{useAppFontEffects-DCqCVGlT.js → useAppFontEffects-DGlvOqP_.js} +194 -233
- package/dist/assets/useInlineCommentController-kMN4Wg_D.js +2 -0
- package/dist/assets/{useRootScrollLock-BowwS8kq.js → useRootScrollLock-DMPpvpNP.js} +2 -2
- package/dist/assets/{vendor-base-ui-DX96QhTP.js → vendor-base-ui-Det7U81h.js} +1 -1
- package/dist/assets/{vendor-codemirror-autocomplete-DW1FQz9_.js → vendor-codemirror-autocomplete-BSHQHbKu.js} +1 -1
- package/dist/assets/{vendor-codemirror-commands-DpmhalwN.js → vendor-codemirror-commands-C4G_dPWe.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-angular-BqExbN1M.js → vendor-codemirror-lang-angular-B6LbBGHB.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-cpp-DZA36HfS.js → vendor-codemirror-lang-cpp-BWWXBx7W.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-css-B07blnnZ.js → vendor-codemirror-lang-css-Cayfb29q.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-go-BM8K9D1-.js → vendor-codemirror-lang-go-BoKlCNKw.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-html-DaH9adfE.js → vendor-codemirror-lang-html-BQWerHsJ.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-java-CsdC0viz.js → vendor-codemirror-lang-java-DWX7Fq_K.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-javascript-CpGYXGuo.js → vendor-codemirror-lang-javascript-DbpEcZM0.js} +2 -2
- package/dist/assets/{vendor-codemirror-lang-jinja-BBeGzXw5.js → vendor-codemirror-lang-jinja-D1JIJRA7.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-json-58T70Hqs.js → vendor-codemirror-lang-json-BzgckzmB.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-less-BI-xCA59.js → vendor-codemirror-lang-less-B9EpDXFi.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-liquid-zEcMa-zy.js → vendor-codemirror-lang-liquid-9U7kRbSf.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-markdown-BLKnlLP4.js → vendor-codemirror-lang-markdown-D2TEBIvZ.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-php-9f35M83-.js → vendor-codemirror-lang-php-BT6sDVzE.js} +1 -1
- package/dist/assets/vendor-codemirror-lang-python-jAMtYiA9.js +3 -0
- package/dist/assets/{vendor-codemirror-lang-rust-MNDL_jZQ.js → vendor-codemirror-lang-rust-CVO56EiL.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-sass-p9epsSNm.js → vendor-codemirror-lang-sass-DZlOoUWu.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-sql-Bqzh0EXX.js → vendor-codemirror-lang-sql-fZ6t1DPw.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-vue-BnNUWV-p.js → vendor-codemirror-lang-vue-DxbqrLiE.js} +1 -1
- package/dist/assets/{vendor-codemirror-lang-wast-C2a-oLmk.js → vendor-codemirror-lang-wast-DyU1Gt-I.js} +1 -1
- package/dist/assets/vendor-codemirror-lang-xml-C9a_K5_p.js +1 -0
- package/dist/assets/{vendor-codemirror-lang-yaml-C0sjswB0.js → vendor-codemirror-lang-yaml-Cptq8l0e.js} +1 -1
- package/dist/assets/{vendor-codemirror-language-ByBn5zIW.js → vendor-codemirror-language-DufXoQvE.js} +2 -2
- package/dist/assets/vendor-codemirror-language-data-CtwSWKtX.js +2 -0
- package/dist/assets/{vendor-codemirror-search-ib-sHD5W.js → vendor-codemirror-search-CvXM_pZg.js} +1 -1
- package/dist/assets/{vendor-codemirror-state-G3UuR-be.js → vendor-codemirror-state-Dek9sMtw.js} +1 -1
- package/dist/assets/{vendor-codemirror-view-Bniqp7p5.js → vendor-codemirror-view-1e0FQ6Wn.js} +1 -1
- package/dist/assets/vendor-framer-motion-DxDVhOLc.js +9 -0
- package/dist/assets/vendor-katex-CuQvj9-L.js +257 -0
- package/dist/assets/vendor-katex-DdZNUVNG.css +1 -0
- package/dist/assets/{vendor-motion-dom-DcCgeG69.js → vendor-motion-dom-HXPOMxb7.js} +1 -1
- package/dist/assets/{vendor-opencode-client-DHzhmLwV.js → vendor-opencode-client-BmFcUkbQ.js} +1 -1
- package/dist/assets/{vendor-replit-codemirror-vim-DkzqxN2H.js → vendor-replit-codemirror-vim-BlJRn-cW.js} +2 -2
- package/dist/assets/{vendor-tanstack-react-virtual-H_JmXOFV.js → vendor-tanstack-react-virtual-CvuLsk7D.js} +1 -1
- package/dist/assets/{vendor-tanstack-virtual-core-Dxc8hSTB.js → vendor-tanstack-virtual-core-DPaNcJcT.js} +1 -1
- package/dist/assets/zh-CN-t2vigSB1.js +20 -0
- package/dist/assets/zh-TW-jAgqBokB.js +20 -0
- package/dist/index.html +6 -6
- package/dist/mini-chat.html +6 -6
- package/dist/mobile.html +6 -6
- package/package.json +8 -5
- package/server/index.js +80 -36
- package/server/lib/agent-memory/actions.js +1 -6
- package/server/lib/agent-memory/routes.js +1 -2
- package/server/lib/agent-memory/runtime.js +1 -8
- package/server/lib/agent-tool/DOCUMENTATION.md +7 -3
- package/server/lib/agent-tool/runtime.js +3 -6
- package/server/lib/agent-tool/runtime.test.js +0 -2
- package/server/lib/browser-control/DOCUMENTATION.md +6 -0
- package/server/lib/changelog/update-notes.js +1 -1
- package/server/lib/context-obligatory/runtime.js +1 -2
- package/server/lib/dev-tunnel/DOCUMENTATION.md +8 -0
- package/server/lib/dev-tunnel/client.js +21 -10
- package/server/lib/dev-tunnel/tunnel.test.js +34 -0
- package/server/lib/dispatch-results/runtime.js +1 -1
- package/server/lib/enterprise-mode.d.ts +1 -0
- package/server/lib/enterprise-mode.js +13 -2
- package/server/lib/enterprise-mode.test.js +21 -0
- package/server/lib/event-stream/DOCUMENTATION.md +2 -2
- package/server/lib/event-stream/index.js +1 -3
- package/server/lib/event-stream/translate-v2.js +1 -9
- package/server/lib/event-stream/translate-v2.test.js +0 -11
- package/server/lib/fs/DOCUMENTATION.md +5 -2
- package/server/lib/fs/routes.js +62 -15
- package/server/lib/fs/routes.test.js +278 -48
- package/server/lib/fs/workspace-file-names.js +104 -0
- package/server/lib/fs/workspace-file-names.test.js +62 -0
- package/server/lib/git/DOCUMENTATION.md +17 -5
- package/server/lib/git/contributor-provenance-storage.js +9 -6
- package/server/lib/git/contributor-provenance-storage.test.js +29 -0
- package/server/lib/git/credential-broker.js +1 -1
- package/server/lib/git/credential-resolver.js +1 -4
- package/server/lib/git/credentials.js +1 -0
- package/server/lib/git/discovery-endpoint.js +1 -1
- package/server/lib/git/identity-provisioning.js +2 -1
- package/server/lib/git/identity-storage.js +3 -4
- package/server/lib/git/lfs-discovery.js +14 -14
- package/server/lib/git/lfs-discovery.test.js +16 -6
- package/server/lib/git/network-operation-plan.js +50 -62
- package/server/lib/git/network-operation-plan.test.js +103 -1
- package/server/lib/git/network-operation-registry.js +4 -6
- package/server/lib/git/network-operation-storage.js +4 -6
- package/server/lib/git/network-operations.js +12 -4
- package/server/lib/git/network-operations.test.js +19 -6
- package/server/lib/git/redaction.js +2 -1
- package/server/lib/git/repository-credential-runtime.js +5 -3
- package/server/lib/git/repository-credential-runtime.test.js +22 -0
- package/server/lib/git/routes.js +31 -137
- package/server/lib/git/routes.test.js +2 -2
- package/server/lib/git/service.js +143 -27
- package/server/lib/git/service.test.js +215 -1
- package/server/lib/git/ssh-credential-storage.js +1 -4
- package/server/lib/git/submodule-discovery.js +1 -1
- package/server/lib/git/worktree-bootstrap-storage.js +3 -4
- package/server/lib/git/worktree-bootstrap-storage.test.js +15 -0
- package/server/lib/git/worktree-creation.js +194 -0
- package/server/lib/git/worktree-creation.test.js +155 -0
- package/server/lib/github/DOCUMENTATION.md +11 -6
- package/server/lib/github/auth.js +2 -4
- package/server/lib/github/device-flow.js +2 -2
- package/server/lib/github/gh-cli-credential.js +1 -0
- package/server/lib/github/octokit.js +31 -0
- package/server/lib/github/pr-status.js +35 -18
- package/server/lib/github/pr-status.test.js +271 -3
- package/server/lib/github/reference-search.js +102 -13
- package/server/lib/github/reference-search.test.js +48 -7
- package/server/lib/github/routes.auth.test.js +18 -0
- package/server/lib/github/routes.js +360 -6
- package/server/lib/github/routes.mutations.test.js +239 -0
- package/server/lib/github/routes.test.js +134 -2
- package/server/lib/gitlab/DOCUMENTATION.md +5 -1
- package/server/lib/gitlab/auth-storage.test.js +1 -0
- package/server/lib/gitlab/mappers.js +30 -1
- package/server/lib/gitlab/resources.js +230 -6
- package/server/lib/gitlab/resources.test.js +179 -0
- package/server/lib/gitlab/routes.js +200 -6
- package/server/lib/gitlab/routes.test.js +186 -2
- package/server/lib/gitlab/validation.js +1 -5
- package/server/lib/guests/DOCUMENTATION.md +1 -1
- package/server/lib/guests/oauth.js +2 -2
- package/server/lib/guests/service.js +1 -1
- package/server/lib/guests/sockets.js +1 -1
- package/server/lib/injected-env.d.ts +8 -0
- package/server/lib/injected-env.js +50 -0
- package/server/lib/injected-env.test.js +56 -0
- package/server/lib/linear/DOCUMENTATION.md +5 -6
- package/server/lib/linear/issues.js +62 -4
- package/server/lib/linear/issues.test.js +68 -0
- package/server/lib/linear/oauth.js +5 -5
- package/server/lib/linear/parse.js +2 -9
- package/server/lib/message-queue/DOCUMENTATION.md +23 -1
- package/server/lib/message-queue/runtime.js +85 -12
- package/server/lib/message-queue/runtime.test.js +172 -2
- package/server/lib/notifications/apns-runtime.js +5 -6
- package/server/lib/notifications/apns-runtime.test.js +20 -4
- package/server/lib/openchamber-control/DOCUMENTATION.md +19 -1
- package/server/lib/openchamber-control/actions.js +2 -1
- package/server/lib/openchamber-control/service.js +119 -20
- package/server/lib/openchamber-control/service.test.js +166 -0
- package/server/lib/openchamber-sessions/archive-store.js +1 -6
- package/server/lib/openchamber-sessions/routes.js +47 -12
- package/server/lib/openchamber-sessions/routes.test.js +65 -2
- package/server/lib/openchamber-sessions/session-metadata-store.js +1 -6
- package/server/lib/opencode/DOCUMENTATION.md +22 -8
- package/server/lib/opencode/agents.js +62 -0
- package/server/lib/opencode/auth-state-runtime.js +3 -1
- package/server/lib/opencode/auth.d.ts +1 -1
- package/server/lib/opencode/auth.js +8 -0
- package/server/lib/opencode/auth.test.js +31 -0
- package/server/lib/opencode/config-entity-routes.js +16 -0
- package/server/lib/opencode/config-entity-v2.test.js +16 -1
- package/server/lib/opencode/config-paths.test.js +2 -2
- package/server/lib/opencode/config-v2.js +2 -4
- package/server/lib/opencode/feature-routes-runtime.js +89 -49
- package/server/lib/opencode/lifecycle.js +41 -21
- package/server/lib/opencode/lifecycle.test.js +50 -2
- package/server/lib/opencode/model-discovery.js +1 -1
- package/server/lib/opencode/model-discovery.test.js +17 -0
- package/server/lib/opencode/models-metadata.js +0 -2
- package/server/lib/opencode/openchamber-routes.test.js +3 -3
- package/server/lib/opencode/plugins.js +6 -9
- package/server/lib/opencode/provider-source-route.test.js +101 -3
- package/server/lib/opencode/providers-disabled.test.js +59 -0
- package/server/lib/opencode/providers.js +34 -0
- package/server/lib/opencode/proxy.js +11 -3
- package/server/lib/opencode/routes.js +40 -2
- package/server/lib/opencode/settings-helpers.js +27 -1
- package/server/lib/opencode/settings-helpers.test.js +19 -7
- package/server/lib/opencode/settings-registry.json +27 -16
- package/server/lib/opencode/settings-runtime.test.js +18 -0
- package/server/lib/opencode/shared-service-runtime.js +23 -104
- package/server/lib/opencode/shared.js +77 -46
- package/server/lib/opencode/shared.test.js +12 -12
- package/server/lib/opencode/shutdown-runtime.test.js +2 -3
- package/server/lib/opencode/skill-routes.js +123 -38
- package/server/lib/opencode/skill-routes.test.js +201 -0
- package/server/lib/opencode/skills.js +81 -34
- package/server/lib/opencode/skills.test.js +176 -21
- package/server/lib/opencode/startup-pipeline-runtime.js +6 -3
- package/server/lib/opencode/startup-pipeline-runtime.test.js +2 -1
- package/server/lib/opencode/watcher.test.js +0 -54
- package/server/lib/outbound-proxy.js +52 -0
- package/server/lib/outbound-proxy.test.js +55 -0
- package/server/lib/package-manager.js +23 -17
- package/server/lib/package-manager.test.js +5 -18
- package/server/lib/permission-auto-accept/DOCUMENTATION.md +1 -1
- package/server/lib/permission-auto-accept/runtime.js +19 -47
- package/server/lib/permission-auto-accept/runtime.test.js +2 -2
- package/server/lib/project-context/DOCUMENTATION.md +7 -1
- package/server/lib/project-context/routes.js +1 -2
- package/server/lib/project-context/runtime.js +12 -14
- package/server/lib/project-context/runtime.test.js +78 -2
- package/server/lib/projects/project-config.js +30 -15
- package/server/lib/projects/project-config.test.js +30 -0
- package/server/lib/projects/project-setup.js +1 -2
- package/server/lib/projects/routes.js +1 -2
- package/server/lib/quota/DOCUMENTATION.md +35 -7
- package/server/lib/quota/index.js +1 -0
- package/server/lib/quota/providers/claude/index.js +1 -1
- package/server/lib/quota/providers/cline-pass.js +1 -1
- package/server/lib/quota/providers/exe-dev.js +1 -1
- package/server/lib/quota/providers/google/index.js +1 -1
- package/server/lib/quota/providers/hyper.js +1 -1
- package/server/lib/quota/providers/kimi.js +116 -36
- package/server/lib/quota/providers/kimi.test.js +128 -3
- package/server/lib/quota/providers/opencode-go.js +144 -21
- package/server/lib/quota/providers/opencode-go.test.js +229 -6
- package/server/lib/quota/providers/openrouter.js +1 -1
- package/server/lib/quota/providers/zenmux.js +1 -1
- package/server/lib/quota/utils/auth.js +1 -0
- package/server/lib/quota/utils/transformers.js +2 -6
- package/server/lib/relay/DOCUMENTATION.md +18 -3
- package/server/lib/relay/e2ee.js +7 -7
- package/server/lib/relay/host-client.js +84 -13
- package/server/lib/relay/host-client.test.js +201 -1
- package/server/lib/relay/identity.js +6 -29
- package/server/lib/relay/identity.test.js +18 -28
- package/server/lib/relay/key-store.js +141 -0
- package/server/lib/relay/key-store.test.js +138 -0
- package/server/lib/relay/service.js +8 -8
- package/server/lib/relay/service.test.js +10 -5
- package/server/lib/relay/signing-key.js +13 -36
- package/server/lib/relay/tunnel-codec.js +10 -10
- package/server/lib/route-module-exports.test.js +22 -0
- package/server/lib/routing/DOCUMENTATION.md +23 -3
- package/server/lib/routing/cache.js +87 -0
- package/server/lib/routing/defaults.js +11 -0
- package/server/lib/routing/history.js +12 -4
- package/server/lib/routing/runtime.js +39 -3
- package/server/lib/routing/runtime.test.js +81 -2
- package/server/lib/routing/store.js +12 -1
- package/server/lib/routing/store.test.js +13 -0
- package/server/lib/scheduled-tasks/DOCUMENTATION.md +59 -1
- package/server/lib/scheduled-tasks/existing-session.js +119 -0
- package/server/lib/scheduled-tasks/existing-session.test.js +350 -0
- package/server/lib/scheduled-tasks/loops.js +1 -8
- package/server/lib/scheduled-tasks/routes.js +8 -8
- package/server/lib/scheduled-tasks/runtime.js +103 -13
- package/server/lib/scheduled-tasks/runtime.test.js +48 -0
- package/server/lib/scheduled-tasks/service.js +33 -11
- package/server/lib/scheduled-tasks/service.test.js +128 -2
- package/server/lib/scheduled-tasks/session-defaults.js +27 -0
- package/server/lib/scheduled-tasks/session-defaults.test.js +19 -0
- package/server/lib/session-assist/context.js +1 -0
- package/server/lib/session-folders/routes.js +2 -2
- package/server/lib/session-goal/objectives.js +1 -1
- package/server/lib/session-knowledge/routes.js +2 -2
- package/server/lib/session-knowledge/runtime.js +1 -2
- package/server/lib/session-work/DOCUMENTATION.md +39 -14
- package/server/lib/session-work/questions.js +31 -2
- package/server/lib/session-work/runtime.js +22 -13
- package/server/lib/session-work/runtime.test.js +43 -26
- package/server/lib/session-work/state.js +10 -4
- package/server/lib/session-work/state.test.js +8 -1
- package/server/lib/shared/DOCUMENTATION.md +89 -0
- package/server/lib/shared/guards.js +53 -0
- package/server/lib/shared/guards.test.js +112 -0
- package/server/lib/skills-catalog/DOCUMENTATION.md +10 -8
- package/server/lib/skills-catalog/cache.js +3 -2
- package/server/lib/skills-catalog/curated-sources.js +5 -1
- package/server/lib/skills-catalog/git.js +107 -20
- package/server/lib/skills-catalog/git.test.js +78 -0
- package/server/lib/skills-catalog/install.js +21 -12
- package/server/lib/skills-catalog/scan.js +25 -15
- package/server/lib/skills-catalog/source.js +26 -1
- package/server/lib/skills-catalog/source.test.js +27 -0
- package/server/lib/source-control/DOCUMENTATION.md +2 -1
- package/server/lib/source-control/audit-storage.js +7 -6
- package/server/lib/source-control/audit-storage.test.js +11 -0
- package/server/lib/source-control/binding-service.js +2 -5
- package/server/lib/source-control/change-request-worktree.js +90 -0
- package/server/lib/source-control/change-request-worktree.test.js +121 -0
- package/server/lib/source-control/mutation-executor.js +1 -1
- package/server/lib/source-control/mutation-storage.js +11 -5
- package/server/lib/source-control/provider-instance.js +1 -2
- package/server/lib/source-control/repository-identity.js +1 -1
- package/server/lib/source-control/routes.js +14 -2
- package/server/lib/spaces/DOCUMENTATION.md +42 -17
- package/server/lib/spaces/command-stream.test.js +15 -0
- package/server/lib/spaces/dispatcher.js +7 -0
- package/server/lib/spaces/dispatcher.test.js +17 -0
- package/server/lib/spaces/hardening.js +2 -2
- package/server/lib/spaces/hardening.test.js +1 -1
- package/server/lib/spaces/host.js +2 -0
- package/server/lib/spaces/journey.js +66 -5
- package/server/lib/spaces/journey.test.js +95 -4
- package/server/lib/spaces/layout.js +1 -1
- package/server/lib/spaces/places/docker-disk.js +38 -14
- package/server/lib/spaces/places/docker-disk.test.js +80 -1
- package/server/lib/spaces/places/docker.js +35 -11
- package/server/lib/spaces/places/fake-docker.js +22 -3
- package/server/lib/spaces/places/memory-place.js +3 -0
- package/server/lib/spaces/places/packed.docker.live.test.js +1 -1
- package/server/lib/spaces/routes.js +5 -0
- package/server/lib/spaces/routes.test.js +4 -2
- package/server/lib/spaces/run-command.js +9 -2
- package/server/lib/spaces/tools.js +4 -5
- package/server/lib/spaces/tools.test.js +2 -2
- package/server/lib/terminal/runtime.js +18 -6
- package/server/lib/terminal/runtime.test.js +66 -0
- package/server/lib/tts/index.js +3 -0
- package/server/lib/tts/service.js +4 -2
- package/server/lib/walkthrough/DOCUMENTATION.md +3 -1
- package/server/lib/walkthrough/index.js +2 -3
- package/server/lib/walkthrough/pr-source.test.js +22 -0
- package/server/lib/walkthrough/sources.js +6 -1
- package/server/opencode-proxy.test.js +127 -0
- package/bin/lib/commands-startup.test.js +0 -15
- package/dist/assets/CodeMirrorCommentWidgets-CVDSjcrP.js +0 -1
- package/dist/assets/DiffView-Ct7vL3fD.js +0 -4
- package/dist/assets/FilesView-DT0uEYgT.js +0 -17
- package/dist/assets/GuestSurfacePane-DVvk1VPu.js +0 -1
- package/dist/assets/LinearIssuesView-C10MwA9h.js +0 -1
- package/dist/assets/MarkdownImageGallery-BbN_K_3d.js +0 -1
- package/dist/assets/MarkdownRendererImpl-BLt2Tkk9.js +0 -10
- package/dist/assets/OnboardingScreen-Bgp5A3WB.js +0 -1
- package/dist/assets/PierreDiffViewer-CWJLj-S-.js +0 -210
- package/dist/assets/PlanView-DsRWnsOI.js +0 -5
- package/dist/assets/PublishDialog-CCeKloRu.js +0 -2
- package/dist/assets/SettingsView-BuPPsNPp.js +0 -30
- package/dist/assets/SettingsWindow-CM5fL8Ot.js +0 -1
- package/dist/assets/SubmoduleDiffSummary-CfsMcfiQ.js +0 -1
- package/dist/assets/ToolOutputDialog-mZrfSofz.js +0 -15
- package/dist/assets/ToolPartDiffPreview-BUGCRYEL.js +0 -8
- package/dist/assets/WalkthroughView-ClBo7PPd.js +0 -4
- package/dist/assets/appThemeRegistry-CxzMxR-H.js +0 -1
- package/dist/assets/de-CBla4hjd.js +0 -14
- package/dist/assets/es-BmnZtxTD.js +0 -20
- package/dist/assets/fileTreeStatus-BSHFIGEg.js +0 -1
- package/dist/assets/fr-OVKIBUZO.js +0 -18
- package/dist/assets/index-CKCFKmjF.js +0 -1
- package/dist/assets/index-Dbx4V4GN.css +0 -1
- package/dist/assets/index-vQ1Pg1cr.js +0 -61
- package/dist/assets/ja-6v-yr-gE.js +0 -20
- package/dist/assets/ko-I_ZLvgQ9.js +0 -20
- package/dist/assets/main-CmO4dRtR.js +0 -2
- package/dist/assets/main-b9vqhlYM.js +0 -999
- package/dist/assets/markdownCore-BPEZRQfP.js +0 -7
- package/dist/assets/miniChat-B5Oi7B-6.js +0 -2
- package/dist/assets/mobile-CVtShif9.js +0 -2
- package/dist/assets/nl-DcvIJf46.js +0 -20
- package/dist/assets/patchFileDiff-CW3wCH1O.js +0 -13
- package/dist/assets/pl-JxCUl0sd.js +0 -20
- package/dist/assets/pt-BR-L89mjja2.js +0 -20
- package/dist/assets/relocateRestoredSession-DYh_9oBa.js +0 -1
- package/dist/assets/renderElectronMiniChatApp-BD-1JHSg.js +0 -2
- package/dist/assets/renderMobileApp-7s5InXt1.js +0 -25
- package/dist/assets/runtimeEndpointReset-DqLJC6L1.js +0 -53
- package/dist/assets/shikiHighlight-CXgZnvHh.js +0 -1
- package/dist/assets/space-apply-1trGVIl8.js +0 -1
- package/dist/assets/space-close-y7j-NuBv.js +0 -1
- package/dist/assets/tr-ka5J1flt.js +0 -11
- package/dist/assets/uk-PyGe6Q_u.js +0 -20
- package/dist/assets/useInlineCommentController-CrjSGCpi.js +0 -2
- package/dist/assets/vendor-codemirror-lang-python-B7ClrMIT.js +0 -3
- package/dist/assets/vendor-codemirror-lang-xml-C8tGnS64.js +0 -1
- package/dist/assets/vendor-codemirror-language-data-q2bKO1EM.js +0 -2
- package/dist/assets/vendor-framer-motion-Bq3iTZ6r.js +0 -1
- package/dist/assets/vendor-katex-CHD9BdDO.js +0 -257
- package/dist/assets/vendor-katex-Cp579UoJ.css +0 -1
- package/dist/assets/zh-CN-B0P2tybJ.js +0 -20
- package/dist/assets/zh-TW-Bs9C5cN8.js +0 -20
|
@@ -461,8 +461,15 @@ const toSimpleGitEnv = (env) => {
|
|
|
461
461
|
// Transport configuration is owned by repository bindings and the credential
|
|
462
462
|
// broker, so no caller needs simple-git's unsafe SSH-command or
|
|
463
463
|
// credential-helper escapes any more.
|
|
464
|
-
const createGit = async (directory, { stallTimeoutMs = 0 } = {}) => {
|
|
464
|
+
const createGit = async (directory, { stallTimeoutMs = 0, optionalLocks = true } = {}) => {
|
|
465
465
|
const env = await buildGitEnv(directory);
|
|
466
|
+
// `git status` holds `.git/index.lock` while it refreshes the index, and a
|
|
467
|
+
// `git commit` the user runs in a terminal at that moment fails with
|
|
468
|
+
// "index.lock: File exists" (#2229). Read-only callers opt out of that
|
|
469
|
+
// refresh; commands that write the index still take the lock.
|
|
470
|
+
if (!optionalLocks) {
|
|
471
|
+
env.GIT_OPTIONAL_LOCKS = '0';
|
|
472
|
+
}
|
|
466
473
|
const spawnOptions = { windowsHide: true };
|
|
467
474
|
// simple-git's block timeout kills the process once it has produced no
|
|
468
475
|
// output for this long. Opt-in per caller: a background read must never hold
|
|
@@ -878,6 +885,14 @@ const parseWorktreePorcelain = (raw) => {
|
|
|
878
885
|
continue;
|
|
879
886
|
}
|
|
880
887
|
|
|
888
|
+
// A bare repository lists itself as a worktree with a `bare` attribute
|
|
889
|
+
// and no HEAD or branch; without a working tree it is not a checkout a
|
|
890
|
+
// session can run in.
|
|
891
|
+
if (line === 'bare') {
|
|
892
|
+
current.bare = true;
|
|
893
|
+
continue;
|
|
894
|
+
}
|
|
895
|
+
|
|
881
896
|
// git marks a worktree whose directory is gone (deleted outside git) as
|
|
882
897
|
// prunable; it stays registered until `git worktree prune`. The sidebar
|
|
883
898
|
// needs that distinction: the directory is missing, but the sessions that
|
|
@@ -1465,12 +1480,15 @@ export async function resolveRepositoryGitPaths(directory) {
|
|
|
1465
1480
|
* `git remote get-url [--push]` reports them: the first URL of several, and a
|
|
1466
1481
|
* remote with no URL read as a URL equal to its name, as Git does. Lines may
|
|
1467
1482
|
* end in CRLF (Git for Windows); a kept `\r` would match no line and read
|
|
1468
|
-
* every remote as URL-less.
|
|
1483
|
+
* every remote as URL-less. Anything after the URL-kind marker — Git 2.54+
|
|
1484
|
+
* appends the partial-clone filter there as `[blob:none]` — is decoration
|
|
1485
|
+
* about the remote, never part of the URL, and is ignored whether or not its
|
|
1486
|
+
* shape is recognized.
|
|
1469
1487
|
*/
|
|
1470
1488
|
export function parseRemoteListing(names, listing) {
|
|
1471
1489
|
const urls = new Map();
|
|
1472
1490
|
for (const line of String(listing || '').split(/\r?\n/)) {
|
|
1473
|
-
const match = line.match(/^([^\t]+)\t(.*) \((fetch|push)\)
|
|
1491
|
+
const match = line.match(/^([^\t]+)\t(.*) \((fetch|push)\)/);
|
|
1474
1492
|
if (!match) continue;
|
|
1475
1493
|
const entry = urls.get(match[1]) ?? {};
|
|
1476
1494
|
if (entry[match[3]] === undefined) entry[match[3]] = match[2];
|
|
@@ -1518,6 +1536,7 @@ export async function resolveWorktreeTopLevel(directory) {
|
|
|
1518
1536
|
return { root: root || directory };
|
|
1519
1537
|
}
|
|
1520
1538
|
|
|
1539
|
+
/** @public */
|
|
1521
1540
|
export async function getCommitSummaries(directory, shas) {
|
|
1522
1541
|
const commits = Array.isArray(shas)
|
|
1523
1542
|
? shas.map((sha) => String(sha || '').trim()).filter(Boolean)
|
|
@@ -1629,6 +1648,7 @@ const ensureLocalIntegrateBranch = async (repoRoot, candidate) => {
|
|
|
1629
1648
|
return raw;
|
|
1630
1649
|
};
|
|
1631
1650
|
|
|
1651
|
+
/** @public */
|
|
1632
1652
|
export async function computeIntegratePlan(input = {}) {
|
|
1633
1653
|
const repoRoot = normalizeIntegratePath(input.repoRoot, 'repoRoot');
|
|
1634
1654
|
const sourceBranch = normalizeIntegrateBranch(input.sourceBranch, 'sourceBranch');
|
|
@@ -1682,6 +1702,7 @@ const maybeFastForwardIntegrateUpstream = async (tmpDir) => {
|
|
|
1682
1702
|
}
|
|
1683
1703
|
};
|
|
1684
1704
|
|
|
1705
|
+
/** @public */
|
|
1685
1706
|
export async function getIntegrateConflictDetails(tmpDir) {
|
|
1686
1707
|
const target = normalizeIntegratePath(tmpDir, 'tempWorktreePath');
|
|
1687
1708
|
const [status, unmerged, diff, meta, patch] = await Promise.all([
|
|
@@ -1701,6 +1722,7 @@ export async function getIntegrateConflictDetails(tmpDir) {
|
|
|
1701
1722
|
};
|
|
1702
1723
|
}
|
|
1703
1724
|
|
|
1725
|
+
/** @public */
|
|
1704
1726
|
export async function isCherryPickInProgress(tmpDir) {
|
|
1705
1727
|
const target = normalizeIntegratePath(tmpDir, 'tempWorktreePath');
|
|
1706
1728
|
const head = await runGitCommand(target, ['rev-parse', '--verify', '--quiet', 'CHERRY_PICK_HEAD']);
|
|
@@ -1752,6 +1774,7 @@ const normalizeIntegrateState = (state = {}) => ({
|
|
|
1752
1774
|
currentCommit: normalizeIntegrateSha(state.currentCommit),
|
|
1753
1775
|
});
|
|
1754
1776
|
|
|
1777
|
+
/** @public */
|
|
1755
1778
|
export async function integrateWorktreeCommits(inputPlan = {}) {
|
|
1756
1779
|
const plan = await normalizeIntegratePlan(inputPlan);
|
|
1757
1780
|
if (plan.commits.length === 0) {
|
|
@@ -1815,6 +1838,7 @@ export async function integrateWorktreeCommits(inputPlan = {}) {
|
|
|
1815
1838
|
}
|
|
1816
1839
|
}
|
|
1817
1840
|
|
|
1841
|
+
/** @public */
|
|
1818
1842
|
export async function abortIntegrate(stateInput = {}) {
|
|
1819
1843
|
const state = normalizeIntegrateState(stateInput);
|
|
1820
1844
|
await runGitCommand(state.tempWorktreePath, ['cherry-pick', '--abort']).catch(() => undefined);
|
|
@@ -1822,6 +1846,7 @@ export async function abortIntegrate(stateInput = {}) {
|
|
|
1822
1846
|
return { success: true };
|
|
1823
1847
|
}
|
|
1824
1848
|
|
|
1849
|
+
/** @public */
|
|
1825
1850
|
export async function continueIntegrate(stateInput = {}) {
|
|
1826
1851
|
const state = normalizeIntegrateState(stateInput);
|
|
1827
1852
|
const cont = await runGitCommand(state.tempWorktreePath, ['cherry-pick', '--continue']);
|
|
@@ -1906,12 +1931,13 @@ const resolveWorktreeProjectContext = async (directory, options = {}) => {
|
|
|
1906
1931
|
throw new Error('Directory is required');
|
|
1907
1932
|
}
|
|
1908
1933
|
|
|
1909
|
-
const topResult = await
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1934
|
+
const topResult = await runGitCommand(directoryPath, ['rev-parse', '--show-toplevel']);
|
|
1935
|
+
// A bare repository has no work tree, so `--show-toplevel` fails there; the
|
|
1936
|
+
// bare directory itself still answers the object-level commands worktree
|
|
1937
|
+
// creation runs against it.
|
|
1938
|
+
const sandbox = topResult.success
|
|
1939
|
+
? path.resolve(directoryPath, normalizeGitOutputPath(topResult.stdout.trim()))
|
|
1940
|
+
: directoryPath;
|
|
1915
1941
|
|
|
1916
1942
|
const commonResult = await runGitCommandOrThrow(
|
|
1917
1943
|
sandbox,
|
|
@@ -1919,7 +1945,10 @@ const resolveWorktreeProjectContext = async (directory, options = {}) => {
|
|
|
1919
1945
|
'Failed to resolve git common directory'
|
|
1920
1946
|
);
|
|
1921
1947
|
const commonDir = path.resolve(sandbox, normalizeGitOutputPath(commonResult.stdout.trim()));
|
|
1922
|
-
|
|
1948
|
+
// `<root>/.git` resolves to the primary checkout; any other layout (a bare
|
|
1949
|
+
// repository, a separate git dir) has no primary worktree, and the sandbox
|
|
1950
|
+
// directory is the closest thing to one.
|
|
1951
|
+
const primaryWorktree = derivePrimaryWorktreeRootFromGitDir(commonDir) || sandbox;
|
|
1923
1952
|
const projectID = await ensureOpenCodeProjectId(primaryWorktree);
|
|
1924
1953
|
// OpenCode's `worktree.directory` is read from the canonical checkout so a
|
|
1925
1954
|
// linked worktree still sees the project's saved configuration. When unset,
|
|
@@ -2893,6 +2922,33 @@ export async function isAncestorOfHead(directory, sha) {
|
|
|
2893
2922
|
return result.success;
|
|
2894
2923
|
}
|
|
2895
2924
|
|
|
2925
|
+
const PATCH_EQUIVALENCE_TIMEOUT_MS = 5_000;
|
|
2926
|
+
|
|
2927
|
+
// Whether a commit has an equivalent patch reachable from the checked-out HEAD.
|
|
2928
|
+
// Missing objects and ambiguous prefixes cannot prove it.
|
|
2929
|
+
export async function isPatchEquivalentOfHead(directory, sha) {
|
|
2930
|
+
const normalizedDirectory = normalizeDirectoryPath(directory);
|
|
2931
|
+
const normalizedSha = String(sha ?? '').trim();
|
|
2932
|
+
if (!normalizedDirectory || !/^[0-9a-f]{7,64}$/i.test(normalizedSha)) {
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
|
|
2936
|
+
const cherry = await runGitCommand(
|
|
2937
|
+
normalizedDirectory,
|
|
2938
|
+
['cherry', 'HEAD', normalizedSha, `${normalizedSha}^`],
|
|
2939
|
+
{ timeoutMs: PATCH_EQUIVALENCE_TIMEOUT_MS },
|
|
2940
|
+
);
|
|
2941
|
+
if (!cherry.success) {
|
|
2942
|
+
return false;
|
|
2943
|
+
}
|
|
2944
|
+
|
|
2945
|
+
const expectedPrefix = normalizedSha.toLowerCase();
|
|
2946
|
+
return cherry.stdout.split(/\r?\n/).some((line) => {
|
|
2947
|
+
const match = line.match(/^-\s+([0-9a-f]{40,64})$/i);
|
|
2948
|
+
return Boolean(match?.[1]) && match[1].toLowerCase().startsWith(expectedPrefix);
|
|
2949
|
+
});
|
|
2950
|
+
}
|
|
2951
|
+
|
|
2896
2952
|
async function readStatus(normalizedDirectory, lightMode) {
|
|
2897
2953
|
try {
|
|
2898
2954
|
// Prefer an explicit non-repo check before simple-git status so a missing
|
|
@@ -2903,6 +2959,7 @@ async function readStatus(normalizedDirectory, lightMode) {
|
|
|
2903
2959
|
|
|
2904
2960
|
const { directoryPath, repoRoot, git } = await createRepositoryGitContext(normalizedDirectory, {
|
|
2905
2961
|
stallTimeoutMs: GIT_STATUS_STALL_TIMEOUT_MS,
|
|
2962
|
+
optionalLocks: false,
|
|
2906
2963
|
});
|
|
2907
2964
|
|
|
2908
2965
|
// `-unormal` lists a directory with no tracked files as one `dir/` entry
|
|
@@ -2916,12 +2973,15 @@ async function readStatus(normalizedDirectory, lightMode) {
|
|
|
2916
2973
|
// Light mode: skip numstat + new-file line counting for faster response.
|
|
2917
2974
|
// Staged (`--cached`: HEAD -> index) and working (`--numstat`: index -> worktree)
|
|
2918
2975
|
// stay in separate maps. A partially staged file has an entry in both, and the
|
|
2919
|
-
// UI shows each row's own scope instead of a combined total.
|
|
2976
|
+
// UI shows each row's own scope instead of a combined total. The working
|
|
2977
|
+
// side uses `diff-files`: `git diff` rewrites a stale index under
|
|
2978
|
+
// `index.lock` even with GIT_OPTIONAL_LOCKS=0. `-M` keeps the rename
|
|
2979
|
+
// detection `git diff` does by default.
|
|
2920
2980
|
const [stagedStatsRaw, workingStatsRaw] = lightMode
|
|
2921
2981
|
? ['', '']
|
|
2922
2982
|
: await Promise.all([
|
|
2923
2983
|
git.raw(['diff', '--cached', '--numstat']).catch(() => ''),
|
|
2924
|
-
git.raw(['diff', '--numstat']).catch(() => ''),
|
|
2984
|
+
git.raw(['diff-files', '-M', '--numstat']).catch(() => ''),
|
|
2925
2985
|
]);
|
|
2926
2986
|
|
|
2927
2987
|
const stagedDiffStats = {};
|
|
@@ -3955,7 +4015,7 @@ export async function applyHunk(directory, filePath, options = {}) {
|
|
|
3955
4015
|
});
|
|
3956
4016
|
}
|
|
3957
4017
|
|
|
3958
|
-
|
|
4018
|
+
async function collectDiffs(directory, files = []) {
|
|
3959
4019
|
const results = [];
|
|
3960
4020
|
for (const filePath of files) {
|
|
3961
4021
|
try {
|
|
@@ -3970,6 +4030,7 @@ export async function collectDiffs(directory, files = []) {
|
|
|
3970
4030
|
return results;
|
|
3971
4031
|
}
|
|
3972
4032
|
|
|
4033
|
+
/** @public */
|
|
3973
4034
|
export async function listStashes(directory) {
|
|
3974
4035
|
const { git } = await createRepositoryGitContext(directory);
|
|
3975
4036
|
const output = await git.raw(['stash', 'list', '--format=%gd%x1f%gs%x1f%cr%x1f%H']);
|
|
@@ -3984,6 +4045,7 @@ export async function listStashes(directory) {
|
|
|
3984
4045
|
.filter((entry) => entry.ref);
|
|
3985
4046
|
}
|
|
3986
4047
|
|
|
4048
|
+
/** @public */
|
|
3987
4049
|
export async function countStashFiles(directory, refs = []) {
|
|
3988
4050
|
const { git } = await createRepositoryGitContext(directory);
|
|
3989
4051
|
const uniqueRefs = Array.from(new Set((Array.isArray(refs) ? refs : []).map((ref) => String(ref || '').trim()).filter(Boolean)));
|
|
@@ -4007,6 +4069,7 @@ export async function countStashFiles(directory, refs = []) {
|
|
|
4007
4069
|
await Promise.all(Array.from({ length: Math.min(concurrency, uniqueRefs.length) }, () => worker()));
|
|
4008
4070
|
return counts;
|
|
4009
4071
|
}
|
|
4072
|
+
/** @public */
|
|
4010
4073
|
export async function stashPush(directory, options = {}) {
|
|
4011
4074
|
const { git } = await createRepositoryGitContext(directory);
|
|
4012
4075
|
const message = typeof options.message === 'string' && options.message.trim()
|
|
@@ -4021,6 +4084,7 @@ export async function stashPush(directory, options = {}) {
|
|
|
4021
4084
|
};
|
|
4022
4085
|
}
|
|
4023
4086
|
|
|
4087
|
+
/** @public */
|
|
4024
4088
|
export async function stashApply(directory, options = {}) {
|
|
4025
4089
|
const { git } = await createRepositoryGitContext(directory);
|
|
4026
4090
|
const ref = typeof options.ref === 'string' && options.ref.trim() ? options.ref.trim() : 'stash@{0}';
|
|
@@ -4033,6 +4097,7 @@ export async function stashApply(directory, options = {}) {
|
|
|
4033
4097
|
return { success: true, ref };
|
|
4034
4098
|
}
|
|
4035
4099
|
|
|
4100
|
+
/** @public */
|
|
4036
4101
|
export async function stashDrop(directory, options = {}) {
|
|
4037
4102
|
const { git } = await createRepositoryGitContext(directory);
|
|
4038
4103
|
const ref = typeof options.ref === 'string' && options.ref.trim() ? options.ref.trim() : 'stash@{0}';
|
|
@@ -4040,6 +4105,7 @@ export async function stashDrop(directory, options = {}) {
|
|
|
4040
4105
|
return { success: true, ref };
|
|
4041
4106
|
}
|
|
4042
4107
|
|
|
4108
|
+
/** @public */
|
|
4043
4109
|
export async function stashPop(directory, options = {}) {
|
|
4044
4110
|
const ref = typeof options.ref === 'string' && options.ref.trim() ? options.ref.trim() : 'stash@{0}';
|
|
4045
4111
|
await stashApply(directory, { ref });
|
|
@@ -4047,7 +4113,7 @@ export async function stashPop(directory, options = {}) {
|
|
|
4047
4113
|
return { success: true, ref };
|
|
4048
4114
|
}
|
|
4049
4115
|
|
|
4050
|
-
|
|
4116
|
+
async function stageFile(directory, filePath) {
|
|
4051
4117
|
await stageFiles(directory, [filePath]);
|
|
4052
4118
|
}
|
|
4053
4119
|
|
|
@@ -4095,7 +4161,7 @@ export async function stageFiles(directory, paths) {
|
|
|
4095
4161
|
});
|
|
4096
4162
|
}
|
|
4097
4163
|
|
|
4098
|
-
|
|
4164
|
+
async function unstageFile(directory, filePath) {
|
|
4099
4165
|
await unstageFiles(directory, [filePath]);
|
|
4100
4166
|
}
|
|
4101
4167
|
|
|
@@ -4431,6 +4497,7 @@ async function filterActiveRemoteBranches(git, directory, remoteBranches) {
|
|
|
4431
4497
|
}
|
|
4432
4498
|
}
|
|
4433
4499
|
|
|
4500
|
+
/** @public */
|
|
4434
4501
|
export async function createBranch(directory, branchName, options = {}) {
|
|
4435
4502
|
const { git } = await createRepositoryGitContext(directory);
|
|
4436
4503
|
|
|
@@ -4617,26 +4684,46 @@ export async function resetToCommit(directory, hash, mode, force = false) {
|
|
|
4617
4684
|
}
|
|
4618
4685
|
}
|
|
4619
4686
|
|
|
4687
|
+
// `git worktree list` answers from any directory of a repository, but the
|
|
4688
|
+
// repository root resolution behind it (`--show-toplevel`) has no answer in a
|
|
4689
|
+
// bare repository: "this operation must be run in a work tree". A bare
|
|
4690
|
+
// checkout used as the project directory would otherwise read as a failure
|
|
4691
|
+
// and show no worktrees at all, so fall back to listing from the directory
|
|
4692
|
+
// itself when it is still a git directory.
|
|
4693
|
+
const resolveWorktreeListingDirectory = async (directoryPath) => {
|
|
4694
|
+
try {
|
|
4695
|
+
const directoryGit = await createGit(directoryPath);
|
|
4696
|
+
return await resolveGitRepositoryRoot(directoryPath, directoryGit);
|
|
4697
|
+
} catch (error) {
|
|
4698
|
+
const probe = await runGitCommand(directoryPath, ['rev-parse', '--git-dir']);
|
|
4699
|
+
if (probe.success) {
|
|
4700
|
+
return directoryPath;
|
|
4701
|
+
}
|
|
4702
|
+
throw error;
|
|
4703
|
+
}
|
|
4704
|
+
};
|
|
4705
|
+
|
|
4620
4706
|
export async function getWorktrees(directory) {
|
|
4621
4707
|
const directoryPath = normalizeDirectoryPath(directory);
|
|
4622
4708
|
if (!directoryPath || !fs.existsSync(directoryPath)) {
|
|
4623
4709
|
return [];
|
|
4624
4710
|
}
|
|
4625
4711
|
try {
|
|
4626
|
-
const
|
|
4627
|
-
const repoRoot = await resolveGitRepositoryRoot(directoryPath, directoryGit);
|
|
4712
|
+
const listingDirectory = await resolveWorktreeListingDirectory(directoryPath);
|
|
4628
4713
|
const result = await runGitCommandOrThrow(
|
|
4629
|
-
|
|
4714
|
+
listingDirectory,
|
|
4630
4715
|
['worktree', 'list', '--porcelain'],
|
|
4631
4716
|
'Failed to list git worktrees'
|
|
4632
4717
|
);
|
|
4633
|
-
return parseWorktreePorcelain(result.stdout)
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
4638
|
-
|
|
4639
|
-
|
|
4718
|
+
return parseWorktreePorcelain(result.stdout)
|
|
4719
|
+
.filter((entry) => entry.bare !== true)
|
|
4720
|
+
.map((entry) => ({
|
|
4721
|
+
head: entry.head || '',
|
|
4722
|
+
name: path.basename(entry.worktree || ''),
|
|
4723
|
+
branch: entry.branch || '',
|
|
4724
|
+
path: entry.worktree,
|
|
4725
|
+
prunable: entry.prunable === true,
|
|
4726
|
+
}));
|
|
4640
4727
|
} catch (error) {
|
|
4641
4728
|
// Worktrees are an optional feature. When the caller passes a directory
|
|
4642
4729
|
// that is not inside any git repository (for example, the managed
|
|
@@ -5951,6 +6038,7 @@ export async function snapshotWorktree(directory, input = {}) {
|
|
|
5951
6038
|
}
|
|
5952
6039
|
}
|
|
5953
6040
|
|
|
6041
|
+
/** @public */
|
|
5954
6042
|
export async function deleteBranch(directory, branch, options = {}) {
|
|
5955
6043
|
const { git } = await createRepositoryGitContext(directory);
|
|
5956
6044
|
|
|
@@ -6173,6 +6261,7 @@ export async function getLog(directory, options = {}) {
|
|
|
6173
6261
|
}
|
|
6174
6262
|
}
|
|
6175
6263
|
|
|
6264
|
+
/** @public */
|
|
6176
6265
|
export async function isLinkedWorktree(directory) {
|
|
6177
6266
|
const git = await createGit(directory);
|
|
6178
6267
|
try {
|
|
@@ -6187,6 +6276,7 @@ export async function isLinkedWorktree(directory) {
|
|
|
6187
6276
|
}
|
|
6188
6277
|
}
|
|
6189
6278
|
|
|
6279
|
+
/** @public */
|
|
6190
6280
|
export async function validateWorktreeDirectory(directory, worktreeRoot) {
|
|
6191
6281
|
const directoryPath = normalizeDirectoryPath(directory);
|
|
6192
6282
|
const rootPath = normalizeDirectoryPath(worktreeRoot);
|
|
@@ -6223,6 +6313,7 @@ export async function validateWorktreeDirectory(directory, worktreeRoot) {
|
|
|
6223
6313
|
};
|
|
6224
6314
|
}
|
|
6225
6315
|
|
|
6316
|
+
/** @public */
|
|
6226
6317
|
export async function canonicalizeWorktreeState(directory) {
|
|
6227
6318
|
const directoryPath = normalizeDirectoryPath(directory);
|
|
6228
6319
|
|
|
@@ -6384,6 +6475,7 @@ export async function getCommitFiles(directory, commitHash) {
|
|
|
6384
6475
|
return { files };
|
|
6385
6476
|
}
|
|
6386
6477
|
|
|
6478
|
+
/** @public */
|
|
6387
6479
|
export async function renameBranch(directory, oldName, newName) {
|
|
6388
6480
|
const { git, repoRoot } = await createRepositoryGitContext(directory);
|
|
6389
6481
|
|
|
@@ -6400,9 +6492,30 @@ export async function renameBranch(directory, oldName, newName) {
|
|
|
6400
6492
|
.then((value) => String(value || '').trim())
|
|
6401
6493
|
.catch(() => '');
|
|
6402
6494
|
|
|
6403
|
-
//
|
|
6495
|
+
// git refuses a taken name with a bare "already exists"; say where the
|
|
6496
|
+
// name is in use so a worktree rename that collides is understandable.
|
|
6497
|
+
const worktrees = await listWorktreeEntries(repoRoot).catch(() => []);
|
|
6498
|
+
const takenBy = worktrees.find((entry) => entry.branch === normalizedNewName);
|
|
6499
|
+
if (takenBy) {
|
|
6500
|
+
const error = new Error(`Branch ${normalizedNewName} is already checked out in ${takenBy.worktree}`);
|
|
6501
|
+
error.statusCode = 409;
|
|
6502
|
+
throw error;
|
|
6503
|
+
}
|
|
6504
|
+
const existing = await runGitCommand(repoRoot, ['show-ref', '--verify', '--quiet', `refs/heads/${normalizedNewName}`]);
|
|
6505
|
+
if (existing.success) {
|
|
6506
|
+
const error = new Error(`A branch named ${normalizedNewName} already exists`);
|
|
6507
|
+
error.statusCode = 409;
|
|
6508
|
+
throw error;
|
|
6509
|
+
}
|
|
6510
|
+
|
|
6404
6511
|
await git.raw(['branch', '-m', oldName, newName]);
|
|
6405
6512
|
|
|
6513
|
+
// A worktree's branch lives in a file the topology watcher does not see,
|
|
6514
|
+
// so tell the sidebar directly when the renamed branch is checked out.
|
|
6515
|
+
if (worktrees.some((entry) => entry.branch === normalizedOldName)) {
|
|
6516
|
+
await publishWorktreeTopologyChange(repoRoot);
|
|
6517
|
+
}
|
|
6518
|
+
|
|
6406
6519
|
if (previousRemote && previousMerge && normalizedNewName) {
|
|
6407
6520
|
const previousMergeBranch = cleanBranchName(previousMerge);
|
|
6408
6521
|
const nextMergeBranch =
|
|
@@ -6426,7 +6539,7 @@ export async function renameBranch(directory, oldName, newName) {
|
|
|
6426
6539
|
|
|
6427
6540
|
return { success: true, branch: newName };
|
|
6428
6541
|
} catch (error) {
|
|
6429
|
-
console.error('Failed to rename branch:', error);
|
|
6542
|
+
if (error.statusCode !== 409) console.error('Failed to rename branch:', error);
|
|
6430
6543
|
throw error;
|
|
6431
6544
|
}
|
|
6432
6545
|
}
|
|
@@ -6507,6 +6620,7 @@ export async function rebase(directory, options = {}) {
|
|
|
6507
6620
|
}
|
|
6508
6621
|
}
|
|
6509
6622
|
|
|
6623
|
+
/** @public */
|
|
6510
6624
|
export async function abortRebase(directory) {
|
|
6511
6625
|
const { git } = await createRepositoryGitContext(directory);
|
|
6512
6626
|
|
|
@@ -6555,6 +6669,7 @@ export async function merge(directory, options = {}) {
|
|
|
6555
6669
|
}
|
|
6556
6670
|
}
|
|
6557
6671
|
|
|
6672
|
+
/** @public */
|
|
6558
6673
|
export async function abortMerge(directory) {
|
|
6559
6674
|
const { git } = await createRepositoryGitContext(directory);
|
|
6560
6675
|
|
|
@@ -6712,6 +6827,7 @@ export async function getConflictDetails(directory) {
|
|
|
6712
6827
|
}
|
|
6713
6828
|
}
|
|
6714
6829
|
|
|
6830
|
+
/** @public */
|
|
6715
6831
|
export async function getCommitFileDiff(directory, hash, filePath, isBinary) {
|
|
6716
6832
|
if (!directory || !hash || !filePath) {
|
|
6717
6833
|
throw new Error('directory, hash, and path are required for getCommitFileDiff');
|