@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
|
@@ -48,8 +48,72 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
48
48
|
fetchGitHubRepoMetas,
|
|
49
49
|
getProfiles,
|
|
50
50
|
getProfile,
|
|
51
|
+
createHttpsCredentialReference,
|
|
52
|
+
resolveSourceControlAccount,
|
|
53
|
+
credentialResolver,
|
|
51
54
|
} = dependencies;
|
|
52
55
|
|
|
56
|
+
const resolveCatalogGitIdentity = async (identityId, source) => {
|
|
57
|
+
if (!identityId || identityId === 'global') return { ok: true, identity: null };
|
|
58
|
+
|
|
59
|
+
const profile = getProfile(identityId);
|
|
60
|
+
if (!profile) {
|
|
61
|
+
return { ok: false, error: { kind: 'authRequired', message: 'Selected Git identity is unavailable' } };
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const transport = profile.transport ?? 'system';
|
|
65
|
+
if (transport === 'system') return { ok: true, identity: null };
|
|
66
|
+
if (transport === 'anonymous') return { ok: true, identity: { anonymous: true, transport } };
|
|
67
|
+
|
|
68
|
+
const parsed = parseSkillRepoSource(source);
|
|
69
|
+
if (!parsed.ok) return { ok: true, identity: null };
|
|
70
|
+
|
|
71
|
+
if (transport === 'ssh') {
|
|
72
|
+
return {
|
|
73
|
+
ok: true,
|
|
74
|
+
identity: {
|
|
75
|
+
transport,
|
|
76
|
+
credentialId: profile.sshCredentialId,
|
|
77
|
+
endpoint: parsed.cloneUrlSsh,
|
|
78
|
+
},
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if (transport === 'account' && profile.account && resolveSourceControlAccount && createHttpsCredentialReference) {
|
|
83
|
+
const account = await resolveSourceControlAccount(profile.account);
|
|
84
|
+
if (account?.credentialId !== profile.account.accountId
|
|
85
|
+
|| account.status !== 'valid'
|
|
86
|
+
|| !Number.isSafeInteger(account.credentialRevision)
|
|
87
|
+
|| account.credentialRevision < 1) {
|
|
88
|
+
return { ok: false, error: { kind: 'authRequired', message: 'Selected Git identity is unavailable' } };
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
let credentialId;
|
|
92
|
+
try {
|
|
93
|
+
credentialId = createHttpsCredentialReference({
|
|
94
|
+
provider: profile.account.provider,
|
|
95
|
+
instance: profile.account.instance,
|
|
96
|
+
credentialId: account.credentialId,
|
|
97
|
+
credentialRevision: account.credentialRevision,
|
|
98
|
+
providerUserId: account.providerUserId,
|
|
99
|
+
});
|
|
100
|
+
} catch {
|
|
101
|
+
return { ok: false, error: { kind: 'authRequired', message: 'Selected Git identity is unavailable' } };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return {
|
|
105
|
+
ok: true,
|
|
106
|
+
identity: {
|
|
107
|
+
transport: 'https',
|
|
108
|
+
credentialId,
|
|
109
|
+
endpoint: parsed.cloneUrlHttps,
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return { ok: false, error: { kind: 'authRequired', message: 'Selected Git identity is unavailable' } };
|
|
115
|
+
};
|
|
116
|
+
|
|
53
117
|
const findWorktreeRootForSkills = (workingDirectory) => {
|
|
54
118
|
if (!workingDirectory) return null;
|
|
55
119
|
let current = path.resolve(workingDirectory);
|
|
@@ -87,7 +151,10 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
87
151
|
return normalizedCandidate === normalizedParent || normalizedCandidate.startsWith(`${normalizedParent}${path.sep}`);
|
|
88
152
|
};
|
|
89
153
|
|
|
90
|
-
|
|
154
|
+
// `projectAncestors` is `getSkillProjectAncestors(workingDirectory)`, worked
|
|
155
|
+
// out once per list: it probes the disk up to the repository root, and a
|
|
156
|
+
// list has hundreds of skills.
|
|
157
|
+
const inferSkillScopeAndSourceFromPath = (skillPath, projectAncestors) => {
|
|
91
158
|
const resolvedPath = typeof skillPath === 'string' ? path.resolve(skillPath) : '';
|
|
92
159
|
const home = os.homedir();
|
|
93
160
|
const source = resolvedPath.includes(`${path.sep}.agents${path.sep}skills${path.sep}`)
|
|
@@ -96,7 +163,6 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
96
163
|
? 'claude'
|
|
97
164
|
: 'opencode';
|
|
98
165
|
|
|
99
|
-
const projectAncestors = getSkillProjectAncestors(workingDirectory);
|
|
100
166
|
const isProjectScoped = projectAncestors.some((ancestor) => {
|
|
101
167
|
const candidates = [
|
|
102
168
|
path.join(ancestor, '.opencode'),
|
|
@@ -151,6 +217,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
151
217
|
return null;
|
|
152
218
|
}
|
|
153
219
|
|
|
220
|
+
const projectAncestors = getSkillProjectAncestors(workingDirectory);
|
|
154
221
|
return payload
|
|
155
222
|
.map((item) => {
|
|
156
223
|
const name = typeof item?.name === 'string' ? item.name.trim() : '';
|
|
@@ -176,7 +243,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
176
243
|
content,
|
|
177
244
|
};
|
|
178
245
|
}
|
|
179
|
-
const inferred = inferSkillScopeAndSourceFromPath(location,
|
|
246
|
+
const inferred = inferSkillScopeAndSourceFromPath(location, projectAncestors);
|
|
180
247
|
const skill = {
|
|
181
248
|
name,
|
|
182
249
|
path: location,
|
|
@@ -205,22 +272,6 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
205
272
|
}
|
|
206
273
|
};
|
|
207
274
|
|
|
208
|
-
const resolveGitIdentity = (profileId) => {
|
|
209
|
-
if (!profileId) {
|
|
210
|
-
return null;
|
|
211
|
-
}
|
|
212
|
-
try {
|
|
213
|
-
const profile = getProfile(profileId);
|
|
214
|
-
const sshKey = profile?.sshKey;
|
|
215
|
-
if (typeof sshKey === 'string' && sshKey.trim()) {
|
|
216
|
-
return { sshKey: sshKey.trim() };
|
|
217
|
-
}
|
|
218
|
-
} catch {
|
|
219
|
-
// ignore
|
|
220
|
-
}
|
|
221
|
-
return null;
|
|
222
|
-
};
|
|
223
|
-
|
|
224
275
|
// Prefer an explicit request directory, then soft-fallback to the active
|
|
225
276
|
// project / lastDirectory so repository-local skills stay visible when the
|
|
226
277
|
// client omits `directory` (create already used resolveProjectDirectory).
|
|
@@ -252,13 +303,18 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
252
303
|
return res.status(400).json({ error });
|
|
253
304
|
}
|
|
254
305
|
const openCodeSkills = await fetchOpenCodeDiscoveredSkills(directory);
|
|
255
|
-
const localSkills = discoverSkills(directory);
|
|
306
|
+
const localSkills = await discoverSkills(directory);
|
|
256
307
|
const skills = mergeDiscoveredSkills(openCodeSkills ?? [], localSkills);
|
|
257
308
|
|
|
258
|
-
|
|
259
|
-
|
|
309
|
+
// One skill at a time: each await hands the event loop back, so other
|
|
310
|
+
// requests are served while hundreds of skills are read.
|
|
311
|
+
const enrichedSkills = [];
|
|
312
|
+
for (const skill of skills) {
|
|
313
|
+
// The list carries no supporting files; the skill page reads them
|
|
314
|
+
// from GET /api/config/skills/:name.
|
|
315
|
+
const sources = await getSkillSources(skill.name, directory, skill, { includeSupportingFiles: false });
|
|
260
316
|
const skillPath = typeof skill.path === 'string' ? skill.path : null;
|
|
261
|
-
|
|
317
|
+
enrichedSkills.push({
|
|
262
318
|
...skill,
|
|
263
319
|
sources,
|
|
264
320
|
renamable: Boolean(
|
|
@@ -266,8 +322,8 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
266
322
|
&& skillPath !== '<built-in>'
|
|
267
323
|
&& isManagedSkillPath(skillPath, directory)
|
|
268
324
|
),
|
|
269
|
-
};
|
|
270
|
-
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
271
327
|
|
|
272
328
|
// OpenCode decides which external skill roots it loads from process
|
|
273
329
|
// env, and the browser cannot read that. Report the flags alongside the
|
|
@@ -383,7 +439,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
383
439
|
|
|
384
440
|
const resolvedDiscovered = mergeDiscoveredSkills(
|
|
385
441
|
(await fetchOpenCodeDiscoveredSkills(directory)) ?? [],
|
|
386
|
-
discoverSkills(directory),
|
|
442
|
+
await discoverSkills(directory),
|
|
387
443
|
);
|
|
388
444
|
const installedByName = new Map(resolvedDiscovered.map((s) => [s.name, s]));
|
|
389
445
|
|
|
@@ -395,9 +451,17 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
395
451
|
const effectiveSubpath = src.defaultSubpath || parsed.effectiveSubpath || null;
|
|
396
452
|
const cacheKey = getCacheKey({
|
|
397
453
|
normalizedRepo: parsed.normalizedRepo,
|
|
454
|
+
ref: parsed.ref,
|
|
398
455
|
subpath: effectiveSubpath || '',
|
|
399
456
|
identityId: src.gitIdentityId || '',
|
|
400
457
|
});
|
|
458
|
+
const resolvedIdentity = await resolveCatalogGitIdentity(src.gitIdentityId, src.source);
|
|
459
|
+
if (!resolvedIdentity.ok) {
|
|
460
|
+
return res.status(401).json({
|
|
461
|
+
ok: false,
|
|
462
|
+
error: { ...resolvedIdentity.error, identities: listGitIdentitiesForResponse() },
|
|
463
|
+
});
|
|
464
|
+
}
|
|
401
465
|
|
|
402
466
|
const scanResult = await scanWithCache(
|
|
403
467
|
cacheKey,
|
|
@@ -405,12 +469,19 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
405
469
|
source: src.source,
|
|
406
470
|
subpath: src.defaultSubpath,
|
|
407
471
|
defaultSubpath: src.defaultSubpath,
|
|
408
|
-
identity:
|
|
472
|
+
identity: resolvedIdentity.identity,
|
|
473
|
+
credentialResolver,
|
|
409
474
|
}),
|
|
410
475
|
{ refresh },
|
|
411
476
|
);
|
|
412
477
|
|
|
413
478
|
if (!scanResult.ok) {
|
|
479
|
+
if (scanResult.error?.kind === 'authRequired') {
|
|
480
|
+
return res.status(401).json({
|
|
481
|
+
ok: false,
|
|
482
|
+
error: { ...scanResult.error, identities: listGitIdentitiesForResponse() },
|
|
483
|
+
});
|
|
484
|
+
}
|
|
414
485
|
return res.status(500).json({ ok: false, error: scanResult.error });
|
|
415
486
|
}
|
|
416
487
|
|
|
@@ -440,12 +511,19 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
440
511
|
app.post('/api/config/skills/scan', async (req, res) => {
|
|
441
512
|
try {
|
|
442
513
|
const { source, subpath, gitIdentityId } = req.body || {};
|
|
443
|
-
const
|
|
514
|
+
const resolvedIdentity = await resolveCatalogGitIdentity(gitIdentityId, source);
|
|
515
|
+
if (!resolvedIdentity.ok) {
|
|
516
|
+
return res.status(401).json({
|
|
517
|
+
ok: false,
|
|
518
|
+
error: { ...resolvedIdentity.error, identities: listGitIdentitiesForResponse() },
|
|
519
|
+
});
|
|
520
|
+
}
|
|
444
521
|
|
|
445
522
|
const result = await scanSkillsRepository({
|
|
446
523
|
source,
|
|
447
524
|
subpath,
|
|
448
|
-
identity,
|
|
525
|
+
identity: resolvedIdentity.identity,
|
|
526
|
+
credentialResolver,
|
|
449
527
|
});
|
|
450
528
|
|
|
451
529
|
if (!result.ok) {
|
|
@@ -494,12 +572,19 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
494
572
|
workingDirectory = resolved.directory;
|
|
495
573
|
}
|
|
496
574
|
|
|
497
|
-
const
|
|
575
|
+
const resolvedIdentity = await resolveCatalogGitIdentity(gitIdentityId, source);
|
|
576
|
+
if (!resolvedIdentity.ok) {
|
|
577
|
+
return res.status(401).json({
|
|
578
|
+
ok: false,
|
|
579
|
+
error: { ...resolvedIdentity.error, identities: listGitIdentitiesForResponse() },
|
|
580
|
+
});
|
|
581
|
+
}
|
|
498
582
|
|
|
499
583
|
const result = await installSkillsFromRepository({
|
|
500
584
|
source,
|
|
501
585
|
subpath,
|
|
502
|
-
identity,
|
|
586
|
+
identity: resolvedIdentity.identity,
|
|
587
|
+
credentialResolver,
|
|
503
588
|
scope,
|
|
504
589
|
targetSource,
|
|
505
590
|
workingDirectory,
|
|
@@ -557,7 +642,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
557
642
|
}
|
|
558
643
|
const discoveredSkill = ((await fetchOpenCodeDiscoveredSkills(directory)) ?? [])
|
|
559
644
|
.find((skill) => skill.name === skillName) || null;
|
|
560
|
-
const sources = getSkillSources(skillName, directory, discoveredSkill);
|
|
645
|
+
const sources = await getSkillSources(skillName, directory, discoveredSkill);
|
|
561
646
|
|
|
562
647
|
res.json({
|
|
563
648
|
name: skillName,
|
|
@@ -586,7 +671,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
586
671
|
|
|
587
672
|
const discoveredSkill = ((await fetchOpenCodeDiscoveredSkills(directory)) ?? [])
|
|
588
673
|
.find((skill) => skill.name === skillName) || null;
|
|
589
|
-
const sources = getSkillSources(skillName, directory, discoveredSkill);
|
|
674
|
+
const sources = await getSkillSources(skillName, directory, discoveredSkill);
|
|
590
675
|
if (!sources.md.exists || !sources.md.dir) {
|
|
591
676
|
return res.status(404).json({ error: 'Skill not found' });
|
|
592
677
|
}
|
|
@@ -620,7 +705,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
620
705
|
console.log('[Server] Creating skill:', skillName);
|
|
621
706
|
console.log('[Server] Scope:', scope, 'Working directory:', directory);
|
|
622
707
|
|
|
623
|
-
createSkill(skillName, { ...config, source: skillSource }, directory, scope);
|
|
708
|
+
await createSkill(skillName, { ...config, source: skillSource }, directory, scope);
|
|
624
709
|
res.json(buildAppliedResponse(
|
|
625
710
|
`Skill ${skillName} created successfully.`,
|
|
626
711
|
));
|
|
@@ -643,7 +728,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
643
728
|
const newName = updates.renameTo.trim();
|
|
644
729
|
console.log(`[Server] Renaming skill: ${skillName} -> ${newName}`);
|
|
645
730
|
console.log('[Server] Working directory:', directory);
|
|
646
|
-
renameSkill(skillName, newName, directory);
|
|
731
|
+
await renameSkill(skillName, newName, directory);
|
|
647
732
|
// OpenCode 2 watches the skills directories: the renamed folder is
|
|
648
733
|
// picked up like any other write, no restart and no client reload.
|
|
649
734
|
return res.json({
|
|
@@ -655,7 +740,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
655
740
|
console.log(`[Server] Updating skill: ${skillName}`);
|
|
656
741
|
console.log('[Server] Working directory:', directory);
|
|
657
742
|
|
|
658
|
-
updateSkill(skillName, updates, directory, updates?.targetPath);
|
|
743
|
+
await updateSkill(skillName, updates, directory, updates?.targetPath);
|
|
659
744
|
res.json(buildAppliedResponse(
|
|
660
745
|
`Skill ${skillName} updated successfully.`,
|
|
661
746
|
));
|
|
@@ -680,7 +765,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
680
765
|
|
|
681
766
|
const discoveredSkill = ((await fetchOpenCodeDiscoveredSkills(directory)) ?? [])
|
|
682
767
|
.find((skill) => skill.name === skillName) || null;
|
|
683
|
-
const sources = getSkillSources(skillName, directory, discoveredSkill);
|
|
768
|
+
const sources = await getSkillSources(skillName, directory, discoveredSkill);
|
|
684
769
|
if (!sources.md.exists || !sources.md.dir) {
|
|
685
770
|
return res.status(404).json({ error: 'Skill not found' });
|
|
686
771
|
}
|
|
@@ -714,7 +799,7 @@ export const registerSkillRoutes = (app, dependencies) => {
|
|
|
714
799
|
|
|
715
800
|
const discoveredSkill = ((await fetchOpenCodeDiscoveredSkills(directory)) ?? [])
|
|
716
801
|
.find((skill) => skill.name === skillName) || null;
|
|
717
|
-
const sources = getSkillSources(skillName, directory, discoveredSkill);
|
|
802
|
+
const sources = await getSkillSources(skillName, directory, discoveredSkill);
|
|
718
803
|
if (!sources.md.exists || !sources.md.dir) {
|
|
719
804
|
return res.status(404).json({ error: 'Skill not found' });
|
|
720
805
|
}
|
|
@@ -315,6 +315,32 @@ describe('skill-routes directory soft fallback', () => {
|
|
|
315
315
|
expect(catalogPayload.sources[0]).not.toHaveProperty('excludedSkills');
|
|
316
316
|
});
|
|
317
317
|
|
|
318
|
+
it('leaves supporting files out of the list and keeps them in the skill detail', async () => {
|
|
319
|
+
projectRoot = createTempProject();
|
|
320
|
+
const skillDir = path.join(projectRoot, '.agents', 'skills', 'files-skill');
|
|
321
|
+
fs.mkdirSync(path.join(skillDir, 'references'), { recursive: true });
|
|
322
|
+
fs.writeFileSync(
|
|
323
|
+
path.join(skillDir, 'SKILL.md'),
|
|
324
|
+
'---\nname: files-skill\ndescription: Has files\n---\nBody\n',
|
|
325
|
+
);
|
|
326
|
+
fs.writeFileSync(path.join(skillDir, 'references', 'guide.md'), '# Guide\n');
|
|
327
|
+
|
|
328
|
+
appHandle = startSkillsApp({ projectRoot });
|
|
329
|
+
const query = `?directory=${encodeURIComponent(projectRoot)}`;
|
|
330
|
+
|
|
331
|
+
const list = await (await fetch(`${appHandle.baseUrl}/api/config/skills${query}`)).json();
|
|
332
|
+
const listed = list.skills.find((skill) => skill.name === 'files-skill');
|
|
333
|
+
expect(listed.sources.md.description).toBe('Has files');
|
|
334
|
+
expect(listed.sources.md).not.toHaveProperty('supportingFiles');
|
|
335
|
+
|
|
336
|
+
const detail = await (await fetch(`${appHandle.baseUrl}/api/config/skills/files-skill${query}`)).json();
|
|
337
|
+
expect(detail.sources.md.supportingFiles).toEqual([{
|
|
338
|
+
name: 'guide.md',
|
|
339
|
+
path: path.join('references', 'guide.md'),
|
|
340
|
+
fullPath: path.join(skillDir, 'references', 'guide.md'),
|
|
341
|
+
}]);
|
|
342
|
+
});
|
|
343
|
+
|
|
318
344
|
it('flags the list as partial when OpenCode skill list fails, and not when it succeeds', async () => {
|
|
319
345
|
projectRoot = createTempProject();
|
|
320
346
|
fs.mkdirSync(path.join(projectRoot, '.agents', 'skills', 'disk-skill'), { recursive: true });
|
|
@@ -359,4 +385,179 @@ describe('skill-routes directory soft fallback', () => {
|
|
|
359
385
|
stubServer.close();
|
|
360
386
|
}
|
|
361
387
|
});
|
|
388
|
+
|
|
389
|
+
it('resolves account-token identities for scan and install', async () => {
|
|
390
|
+
projectRoot = createTempProject();
|
|
391
|
+
const account = { provider: 'github', instance: 'github.com', accountId: 'account-one' };
|
|
392
|
+
const profile = { id: 'work', transport: 'account', account };
|
|
393
|
+
const credentialResolver = { resolve: async () => ({}) };
|
|
394
|
+
const resolved = [];
|
|
395
|
+
const scanResponse = { ok: true, items: [] };
|
|
396
|
+
const installResponse = { ok: true, installed: [], skipped: [] };
|
|
397
|
+
appHandle = startSkillsApp({
|
|
398
|
+
projectRoot,
|
|
399
|
+
overrides: {
|
|
400
|
+
getProfile: () => profile,
|
|
401
|
+
resolveSourceControlAccount: async (input) => {
|
|
402
|
+
expect(input).toEqual(account);
|
|
403
|
+
return {
|
|
404
|
+
credentialId: 'account-one',
|
|
405
|
+
credentialRevision: 3,
|
|
406
|
+
providerUserId: 'github.com#42',
|
|
407
|
+
status: 'valid',
|
|
408
|
+
};
|
|
409
|
+
},
|
|
410
|
+
createHttpsCredentialReference: (input) => {
|
|
411
|
+
expect(input).toEqual({
|
|
412
|
+
provider: 'github',
|
|
413
|
+
instance: 'github.com',
|
|
414
|
+
credentialId: 'account-one',
|
|
415
|
+
credentialRevision: 3,
|
|
416
|
+
providerUserId: 'github.com#42',
|
|
417
|
+
});
|
|
418
|
+
return 'managed-account-reference';
|
|
419
|
+
},
|
|
420
|
+
credentialResolver,
|
|
421
|
+
parseSkillRepoSource: () => ({
|
|
422
|
+
ok: true,
|
|
423
|
+
host: 'github.com',
|
|
424
|
+
cloneUrlSsh: 'git@github.com:owner/private.git',
|
|
425
|
+
cloneUrlHttps: 'https://github.com/owner/private.git',
|
|
426
|
+
}),
|
|
427
|
+
scanSkillsRepository: async (input) => {
|
|
428
|
+
resolved.push(input);
|
|
429
|
+
return scanResponse;
|
|
430
|
+
},
|
|
431
|
+
installSkillsFromRepository: async (input) => {
|
|
432
|
+
resolved.push(input);
|
|
433
|
+
return installResponse;
|
|
434
|
+
},
|
|
435
|
+
},
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const scan = await fetch(`${appHandle.baseUrl}/api/config/skills/scan`, {
|
|
439
|
+
method: 'POST',
|
|
440
|
+
headers: { 'Content-Type': 'application/json' },
|
|
441
|
+
body: JSON.stringify({ source: 'owner/private', gitIdentityId: 'work' }),
|
|
442
|
+
});
|
|
443
|
+
expect(scan.status).toBe(200);
|
|
444
|
+
|
|
445
|
+
const install = await fetch(`${appHandle.baseUrl}/api/config/skills/install`, {
|
|
446
|
+
method: 'POST',
|
|
447
|
+
headers: { 'Content-Type': 'application/json' },
|
|
448
|
+
body: JSON.stringify({
|
|
449
|
+
source: 'owner/private',
|
|
450
|
+
gitIdentityId: 'work',
|
|
451
|
+
scope: 'user',
|
|
452
|
+
selections: [{ skillDir: 'skills/private-skill' }],
|
|
453
|
+
}),
|
|
454
|
+
});
|
|
455
|
+
expect(install.status).toBe(200);
|
|
456
|
+
expect(resolved).toHaveLength(2);
|
|
457
|
+
for (const input of resolved) {
|
|
458
|
+
expect(input.identity).toEqual({
|
|
459
|
+
transport: 'https',
|
|
460
|
+
credentialId: 'managed-account-reference',
|
|
461
|
+
endpoint: 'https://github.com/owner/private.git',
|
|
462
|
+
});
|
|
463
|
+
expect(input.credentialResolver).toBe(credentialResolver);
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('uses the managed SSH identity and endpoint for catalog scans', async () => {
|
|
468
|
+
projectRoot = createTempProject();
|
|
469
|
+
let scanInput;
|
|
470
|
+
appHandle = startSkillsApp({
|
|
471
|
+
projectRoot,
|
|
472
|
+
overrides: {
|
|
473
|
+
getProfile: () => ({
|
|
474
|
+
id: 'deploy',
|
|
475
|
+
transport: 'ssh',
|
|
476
|
+
sshCredentialId: 'ocgit:v1:ssh:key-one',
|
|
477
|
+
}),
|
|
478
|
+
parseSkillRepoSource: () => ({
|
|
479
|
+
ok: true,
|
|
480
|
+
host: 'git.example.com',
|
|
481
|
+
cloneUrlSsh: 'git@git.example.com:owner/private.git',
|
|
482
|
+
cloneUrlHttps: 'https://git.example.com/owner/private.git',
|
|
483
|
+
}),
|
|
484
|
+
scanSkillsRepository: async (input) => {
|
|
485
|
+
scanInput = input;
|
|
486
|
+
return { ok: true, items: [] };
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
const response = await fetch(`${appHandle.baseUrl}/api/config/skills/scan`, {
|
|
492
|
+
method: 'POST',
|
|
493
|
+
headers: { 'Content-Type': 'application/json' },
|
|
494
|
+
body: JSON.stringify({ source: 'git@git.example.com:owner/private.git', gitIdentityId: 'deploy' }),
|
|
495
|
+
});
|
|
496
|
+
expect(response.status).toBe(200);
|
|
497
|
+
expect(scanInput.identity).toEqual({
|
|
498
|
+
transport: 'ssh',
|
|
499
|
+
credentialId: 'ocgit:v1:ssh:key-one',
|
|
500
|
+
endpoint: 'git@git.example.com:owner/private.git',
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
it('keeps the System identity on the server Git configuration', async () => {
|
|
505
|
+
projectRoot = createTempProject();
|
|
506
|
+
let scanInput;
|
|
507
|
+
appHandle = startSkillsApp({
|
|
508
|
+
projectRoot,
|
|
509
|
+
overrides: {
|
|
510
|
+
parseSkillRepoSource: () => ({
|
|
511
|
+
ok: true,
|
|
512
|
+
cloneUrlSsh: 'git@github.com:owner/repo.git',
|
|
513
|
+
cloneUrlHttps: 'https://github.com/owner/repo.git',
|
|
514
|
+
}),
|
|
515
|
+
scanSkillsRepository: async (input) => {
|
|
516
|
+
scanInput = input;
|
|
517
|
+
return { ok: true, items: [] };
|
|
518
|
+
},
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
|
|
522
|
+
const response = await fetch(`${appHandle.baseUrl}/api/config/skills/scan`, {
|
|
523
|
+
method: 'POST',
|
|
524
|
+
headers: { 'Content-Type': 'application/json' },
|
|
525
|
+
body: JSON.stringify({ source: 'owner/repo', gitIdentityId: 'global' }),
|
|
526
|
+
});
|
|
527
|
+
expect(response.status).toBe(200);
|
|
528
|
+
expect(scanInput.identity).toBeNull();
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
it('refuses to fall back when the selected account identity is unavailable', async () => {
|
|
532
|
+
projectRoot = createTempProject();
|
|
533
|
+
let scanned = false;
|
|
534
|
+
appHandle = startSkillsApp({
|
|
535
|
+
projectRoot,
|
|
536
|
+
overrides: {
|
|
537
|
+
getProfile: () => ({
|
|
538
|
+
id: 'work',
|
|
539
|
+
transport: 'account',
|
|
540
|
+
account: { provider: 'github', instance: 'github.com', accountId: 'account-one' },
|
|
541
|
+
}),
|
|
542
|
+
resolveSourceControlAccount: async () => null,
|
|
543
|
+
parseSkillRepoSource: () => ({
|
|
544
|
+
ok: true,
|
|
545
|
+
cloneUrlSsh: 'git@github.com:owner/private.git',
|
|
546
|
+
cloneUrlHttps: 'https://github.com/owner/private.git',
|
|
547
|
+
}),
|
|
548
|
+
scanSkillsRepository: async () => {
|
|
549
|
+
scanned = true;
|
|
550
|
+
return { ok: true, items: [] };
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
});
|
|
554
|
+
|
|
555
|
+
const response = await fetch(`${appHandle.baseUrl}/api/config/skills/scan`, {
|
|
556
|
+
method: 'POST',
|
|
557
|
+
headers: { 'Content-Type': 'application/json' },
|
|
558
|
+
body: JSON.stringify({ source: 'owner/private', gitIdentityId: 'work' }),
|
|
559
|
+
});
|
|
560
|
+
expect(response.status).toBe(401);
|
|
561
|
+
expect(scanned).toBe(false);
|
|
562
|
+
});
|
|
362
563
|
});
|