@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.
Files changed (442) hide show
  1. package/README.md +32 -24
  2. package/bin/cli.js +1 -3
  3. package/bin/cli.test.js +40 -16
  4. package/bin/lib/DOCUMENTATION.md +6 -5
  5. package/bin/lib/cli-args.js +6 -1
  6. package/bin/lib/cli-args.test.js +34 -0
  7. package/bin/lib/cli-lifecycle.js +0 -1
  8. package/bin/lib/cli-network.js +8 -2
  9. package/bin/lib/cli-process.js +1 -1
  10. package/bin/lib/cli-settings-accessors.test.js +21 -13
  11. package/bin/lib/cli-startup.js +17 -11
  12. package/bin/lib/cli-startup.test.js +92 -2
  13. package/bin/lib/commands-connect-url.js +8 -1
  14. package/bin/lib/commands-schedule.js +8 -2
  15. package/bin/lib/commands-serve.js +15 -21
  16. package/bin/lib/commands-update.js +12 -24
  17. package/bin/lib/commands-update.test.js +14 -46
  18. package/dist/assets/DiffView-Cv9MSXl1.js +4 -0
  19. package/dist/assets/FilePreviewCommentMenu-D4kLseHj.js +4 -0
  20. package/dist/assets/FilesView-BVoD8I2x.js +14 -0
  21. package/dist/assets/{GitView-DzuzhIPx.js → GitView-Bzb8p-ew.js} +4 -4
  22. package/dist/assets/GuestSurfacePane-Crdbvsxo.js +1 -0
  23. package/dist/assets/InProgressOperationBanner-CwMjNQgk.js +2 -0
  24. package/dist/assets/{JsonTreeView-B_EPRjzy.js → JsonTreeView-DRKHZfsn.js} +1 -1
  25. package/dist/assets/MarkdownImageGallery-DZtqT1Zn.js +1 -0
  26. package/dist/assets/MarkdownRendererImpl-CqG7HCNd.js +10 -0
  27. package/dist/assets/OnboardingScreen-DMIxwYK5.js +1 -0
  28. package/dist/assets/{PatchDiff-6yh1csza.js → PatchDiff-CUcCg1jk.js} +1 -1
  29. package/dist/assets/PierreDiffViewer-CnnR-dnD.js +228 -0
  30. package/dist/assets/PlanView-RCBadcY7.js +5 -0
  31. package/dist/assets/SettingsView-CjBjZFRO.js +30 -0
  32. package/dist/assets/SettingsWindow-DyM7QuhI.js +1 -0
  33. package/dist/assets/SubmoduleDiffSummary-BWIfgMED.js +1 -0
  34. package/dist/assets/ToolOutputDialog-Q0P3FuAi.js +15 -0
  35. package/dist/assets/ToolPartDiffPreview-p7qR9FpU.js +8 -0
  36. package/dist/assets/{VirtualizedFileDiff-BTJVRkyo.js → VirtualizedFileDiff-CFpjL8Ns.js} +3 -3
  37. package/dist/assets/{Virtualizer-xCEYz34p.js → Virtualizer-C0IsclZn.js} +1 -1
  38. package/dist/assets/WalkthroughView-DI31zD02.js +4 -0
  39. package/dist/assets/appThemeRegistry-B9gkFq9i.js +1 -0
  40. package/dist/assets/{computeVirtualFileMetrics-CmPe29DM.js → computeVirtualFileMetrics-C2WM6JC2.js} +2 -2
  41. package/dist/assets/de-YKfk5MmC.js +14 -0
  42. package/dist/assets/es-_gwT0kr-.js +20 -0
  43. package/dist/assets/fileTreeStatus-D438yi8M.js +1 -0
  44. package/dist/assets/fr-DqzvXmIm.js +18 -0
  45. package/dist/assets/index-BLaHKdtx.js +1 -0
  46. package/dist/assets/index-BkMXRrVQ.css +1 -0
  47. package/dist/assets/index-DxNa7xYB.js +65 -0
  48. package/dist/assets/initializeSharedPreferences-Bck5EAWP.js +1 -0
  49. package/dist/assets/{isDiffPlainText-CQmDCnEv.js → isDiffPlainText-Dgbw8VKk.js} +1 -1
  50. package/dist/assets/{isFilePlainText-CYBUzW4I.js → isFilePlainText-_ZS5UYRj.js} +1 -1
  51. package/dist/assets/ja-B-GFYhQE.js +20 -0
  52. package/dist/assets/ko-mzksfqDC.js +20 -0
  53. package/dist/assets/main-C5Xx8dn_.js +2 -0
  54. package/dist/assets/main-CfBSQM1H.js +990 -0
  55. package/dist/assets/markdownCore-BmWwW1ll.js +7 -0
  56. package/dist/assets/miniChat-mnKwy4vQ.js +2 -0
  57. package/dist/assets/mobile-DeEQd0wZ.js +2 -0
  58. package/dist/assets/nl-CWQr6NSq.js +20 -0
  59. package/dist/assets/{parseDiffFromFile-Cy0PNxun.js → parseDiffFromFile-BUgn-T9p.js} +2 -2
  60. package/dist/assets/patchFileDiff-Dt8LhgBh.js +13 -0
  61. package/dist/assets/pl-UmRcDUX2.js +20 -0
  62. package/dist/assets/pt-BR-BSLybvVF.js +20 -0
  63. package/dist/assets/relocateRestoredSession-B5E9xb3T.js +1 -0
  64. package/dist/assets/renderElectronMiniChatApp-C0a9A5_J.js +2 -0
  65. package/dist/assets/renderMobileApp-BNncg3Pk.js +25 -0
  66. package/dist/assets/runtimeEndpointReset-CZ5aafpl.js +62 -0
  67. package/dist/assets/{selectionMarkdown-TkYk5h9l.js → selectionMarkdown-CUN3wUld.js} +9 -9
  68. package/dist/assets/{sessionOwnership-Bs1xbRfB.js → sessionOwnership-BSuxCEhb.js} +1 -1
  69. package/dist/assets/shikiHighlight-DHDx-6eM.js +1 -0
  70. package/dist/assets/space-apply-DM_2pRW7.js +1 -0
  71. package/dist/assets/space-close-Bpomt8z0.js +1 -0
  72. package/dist/assets/{surface-B6n7wJtt.js → surface-C-jQaGnL.js} +1 -1
  73. package/dist/assets/{textMateThemeFromAppTheme-CDlKffWz.js → textMateThemeFromAppTheme-DlsTphbY.js} +1 -1
  74. package/dist/assets/tr-gaTrX_HK.js +11 -0
  75. package/dist/assets/uk-CnJF6ykl.js +20 -0
  76. package/dist/assets/{useAppFontEffects-DCqCVGlT.js → useAppFontEffects-DGlvOqP_.js} +194 -233
  77. package/dist/assets/useInlineCommentController-kMN4Wg_D.js +2 -0
  78. package/dist/assets/{useRootScrollLock-BowwS8kq.js → useRootScrollLock-DMPpvpNP.js} +2 -2
  79. package/dist/assets/{vendor-base-ui-DX96QhTP.js → vendor-base-ui-Det7U81h.js} +1 -1
  80. package/dist/assets/{vendor-codemirror-autocomplete-DW1FQz9_.js → vendor-codemirror-autocomplete-BSHQHbKu.js} +1 -1
  81. package/dist/assets/{vendor-codemirror-commands-DpmhalwN.js → vendor-codemirror-commands-C4G_dPWe.js} +1 -1
  82. package/dist/assets/{vendor-codemirror-lang-angular-BqExbN1M.js → vendor-codemirror-lang-angular-B6LbBGHB.js} +1 -1
  83. package/dist/assets/{vendor-codemirror-lang-cpp-DZA36HfS.js → vendor-codemirror-lang-cpp-BWWXBx7W.js} +1 -1
  84. package/dist/assets/{vendor-codemirror-lang-css-B07blnnZ.js → vendor-codemirror-lang-css-Cayfb29q.js} +1 -1
  85. package/dist/assets/{vendor-codemirror-lang-go-BM8K9D1-.js → vendor-codemirror-lang-go-BoKlCNKw.js} +1 -1
  86. package/dist/assets/{vendor-codemirror-lang-html-DaH9adfE.js → vendor-codemirror-lang-html-BQWerHsJ.js} +1 -1
  87. package/dist/assets/{vendor-codemirror-lang-java-CsdC0viz.js → vendor-codemirror-lang-java-DWX7Fq_K.js} +1 -1
  88. package/dist/assets/{vendor-codemirror-lang-javascript-CpGYXGuo.js → vendor-codemirror-lang-javascript-DbpEcZM0.js} +2 -2
  89. package/dist/assets/{vendor-codemirror-lang-jinja-BBeGzXw5.js → vendor-codemirror-lang-jinja-D1JIJRA7.js} +1 -1
  90. package/dist/assets/{vendor-codemirror-lang-json-58T70Hqs.js → vendor-codemirror-lang-json-BzgckzmB.js} +1 -1
  91. package/dist/assets/{vendor-codemirror-lang-less-BI-xCA59.js → vendor-codemirror-lang-less-B9EpDXFi.js} +1 -1
  92. package/dist/assets/{vendor-codemirror-lang-liquid-zEcMa-zy.js → vendor-codemirror-lang-liquid-9U7kRbSf.js} +1 -1
  93. package/dist/assets/{vendor-codemirror-lang-markdown-BLKnlLP4.js → vendor-codemirror-lang-markdown-D2TEBIvZ.js} +1 -1
  94. package/dist/assets/{vendor-codemirror-lang-php-9f35M83-.js → vendor-codemirror-lang-php-BT6sDVzE.js} +1 -1
  95. package/dist/assets/vendor-codemirror-lang-python-jAMtYiA9.js +3 -0
  96. package/dist/assets/{vendor-codemirror-lang-rust-MNDL_jZQ.js → vendor-codemirror-lang-rust-CVO56EiL.js} +1 -1
  97. package/dist/assets/{vendor-codemirror-lang-sass-p9epsSNm.js → vendor-codemirror-lang-sass-DZlOoUWu.js} +1 -1
  98. package/dist/assets/{vendor-codemirror-lang-sql-Bqzh0EXX.js → vendor-codemirror-lang-sql-fZ6t1DPw.js} +1 -1
  99. package/dist/assets/{vendor-codemirror-lang-vue-BnNUWV-p.js → vendor-codemirror-lang-vue-DxbqrLiE.js} +1 -1
  100. package/dist/assets/{vendor-codemirror-lang-wast-C2a-oLmk.js → vendor-codemirror-lang-wast-DyU1Gt-I.js} +1 -1
  101. package/dist/assets/vendor-codemirror-lang-xml-C9a_K5_p.js +1 -0
  102. package/dist/assets/{vendor-codemirror-lang-yaml-C0sjswB0.js → vendor-codemirror-lang-yaml-Cptq8l0e.js} +1 -1
  103. package/dist/assets/{vendor-codemirror-language-ByBn5zIW.js → vendor-codemirror-language-DufXoQvE.js} +2 -2
  104. package/dist/assets/vendor-codemirror-language-data-CtwSWKtX.js +2 -0
  105. package/dist/assets/{vendor-codemirror-search-ib-sHD5W.js → vendor-codemirror-search-CvXM_pZg.js} +1 -1
  106. package/dist/assets/{vendor-codemirror-state-G3UuR-be.js → vendor-codemirror-state-Dek9sMtw.js} +1 -1
  107. package/dist/assets/{vendor-codemirror-view-Bniqp7p5.js → vendor-codemirror-view-1e0FQ6Wn.js} +1 -1
  108. package/dist/assets/vendor-framer-motion-DxDVhOLc.js +9 -0
  109. package/dist/assets/vendor-katex-CuQvj9-L.js +257 -0
  110. package/dist/assets/vendor-katex-DdZNUVNG.css +1 -0
  111. package/dist/assets/{vendor-motion-dom-DcCgeG69.js → vendor-motion-dom-HXPOMxb7.js} +1 -1
  112. package/dist/assets/{vendor-opencode-client-DHzhmLwV.js → vendor-opencode-client-BmFcUkbQ.js} +1 -1
  113. package/dist/assets/{vendor-replit-codemirror-vim-DkzqxN2H.js → vendor-replit-codemirror-vim-BlJRn-cW.js} +2 -2
  114. package/dist/assets/{vendor-tanstack-react-virtual-H_JmXOFV.js → vendor-tanstack-react-virtual-CvuLsk7D.js} +1 -1
  115. package/dist/assets/{vendor-tanstack-virtual-core-Dxc8hSTB.js → vendor-tanstack-virtual-core-DPaNcJcT.js} +1 -1
  116. package/dist/assets/zh-CN-t2vigSB1.js +20 -0
  117. package/dist/assets/zh-TW-jAgqBokB.js +20 -0
  118. package/dist/index.html +6 -6
  119. package/dist/mini-chat.html +6 -6
  120. package/dist/mobile.html +6 -6
  121. package/package.json +8 -5
  122. package/server/index.js +80 -36
  123. package/server/lib/agent-memory/actions.js +1 -6
  124. package/server/lib/agent-memory/routes.js +1 -2
  125. package/server/lib/agent-memory/runtime.js +1 -8
  126. package/server/lib/agent-tool/DOCUMENTATION.md +7 -3
  127. package/server/lib/agent-tool/runtime.js +3 -6
  128. package/server/lib/agent-tool/runtime.test.js +0 -2
  129. package/server/lib/browser-control/DOCUMENTATION.md +6 -0
  130. package/server/lib/changelog/update-notes.js +1 -1
  131. package/server/lib/context-obligatory/runtime.js +1 -2
  132. package/server/lib/dev-tunnel/DOCUMENTATION.md +8 -0
  133. package/server/lib/dev-tunnel/client.js +21 -10
  134. package/server/lib/dev-tunnel/tunnel.test.js +34 -0
  135. package/server/lib/dispatch-results/runtime.js +1 -1
  136. package/server/lib/enterprise-mode.d.ts +1 -0
  137. package/server/lib/enterprise-mode.js +13 -2
  138. package/server/lib/enterprise-mode.test.js +21 -0
  139. package/server/lib/event-stream/DOCUMENTATION.md +2 -2
  140. package/server/lib/event-stream/index.js +1 -3
  141. package/server/lib/event-stream/translate-v2.js +1 -9
  142. package/server/lib/event-stream/translate-v2.test.js +0 -11
  143. package/server/lib/fs/DOCUMENTATION.md +5 -2
  144. package/server/lib/fs/routes.js +62 -15
  145. package/server/lib/fs/routes.test.js +278 -48
  146. package/server/lib/fs/workspace-file-names.js +104 -0
  147. package/server/lib/fs/workspace-file-names.test.js +62 -0
  148. package/server/lib/git/DOCUMENTATION.md +17 -5
  149. package/server/lib/git/contributor-provenance-storage.js +9 -6
  150. package/server/lib/git/contributor-provenance-storage.test.js +29 -0
  151. package/server/lib/git/credential-broker.js +1 -1
  152. package/server/lib/git/credential-resolver.js +1 -4
  153. package/server/lib/git/credentials.js +1 -0
  154. package/server/lib/git/discovery-endpoint.js +1 -1
  155. package/server/lib/git/identity-provisioning.js +2 -1
  156. package/server/lib/git/identity-storage.js +3 -4
  157. package/server/lib/git/lfs-discovery.js +14 -14
  158. package/server/lib/git/lfs-discovery.test.js +16 -6
  159. package/server/lib/git/network-operation-plan.js +50 -62
  160. package/server/lib/git/network-operation-plan.test.js +103 -1
  161. package/server/lib/git/network-operation-registry.js +4 -6
  162. package/server/lib/git/network-operation-storage.js +4 -6
  163. package/server/lib/git/network-operations.js +12 -4
  164. package/server/lib/git/network-operations.test.js +19 -6
  165. package/server/lib/git/redaction.js +2 -1
  166. package/server/lib/git/repository-credential-runtime.js +5 -3
  167. package/server/lib/git/repository-credential-runtime.test.js +22 -0
  168. package/server/lib/git/routes.js +31 -137
  169. package/server/lib/git/routes.test.js +2 -2
  170. package/server/lib/git/service.js +143 -27
  171. package/server/lib/git/service.test.js +215 -1
  172. package/server/lib/git/ssh-credential-storage.js +1 -4
  173. package/server/lib/git/submodule-discovery.js +1 -1
  174. package/server/lib/git/worktree-bootstrap-storage.js +3 -4
  175. package/server/lib/git/worktree-bootstrap-storage.test.js +15 -0
  176. package/server/lib/git/worktree-creation.js +194 -0
  177. package/server/lib/git/worktree-creation.test.js +155 -0
  178. package/server/lib/github/DOCUMENTATION.md +11 -6
  179. package/server/lib/github/auth.js +2 -4
  180. package/server/lib/github/device-flow.js +2 -2
  181. package/server/lib/github/gh-cli-credential.js +1 -0
  182. package/server/lib/github/octokit.js +31 -0
  183. package/server/lib/github/pr-status.js +35 -18
  184. package/server/lib/github/pr-status.test.js +271 -3
  185. package/server/lib/github/reference-search.js +102 -13
  186. package/server/lib/github/reference-search.test.js +48 -7
  187. package/server/lib/github/routes.auth.test.js +18 -0
  188. package/server/lib/github/routes.js +360 -6
  189. package/server/lib/github/routes.mutations.test.js +239 -0
  190. package/server/lib/github/routes.test.js +134 -2
  191. package/server/lib/gitlab/DOCUMENTATION.md +5 -1
  192. package/server/lib/gitlab/auth-storage.test.js +1 -0
  193. package/server/lib/gitlab/mappers.js +30 -1
  194. package/server/lib/gitlab/resources.js +230 -6
  195. package/server/lib/gitlab/resources.test.js +179 -0
  196. package/server/lib/gitlab/routes.js +200 -6
  197. package/server/lib/gitlab/routes.test.js +186 -2
  198. package/server/lib/gitlab/validation.js +1 -5
  199. package/server/lib/guests/DOCUMENTATION.md +1 -1
  200. package/server/lib/guests/oauth.js +2 -2
  201. package/server/lib/guests/service.js +1 -1
  202. package/server/lib/guests/sockets.js +1 -1
  203. package/server/lib/injected-env.d.ts +8 -0
  204. package/server/lib/injected-env.js +50 -0
  205. package/server/lib/injected-env.test.js +56 -0
  206. package/server/lib/linear/DOCUMENTATION.md +5 -6
  207. package/server/lib/linear/issues.js +62 -4
  208. package/server/lib/linear/issues.test.js +68 -0
  209. package/server/lib/linear/oauth.js +5 -5
  210. package/server/lib/linear/parse.js +2 -9
  211. package/server/lib/message-queue/DOCUMENTATION.md +23 -1
  212. package/server/lib/message-queue/runtime.js +85 -12
  213. package/server/lib/message-queue/runtime.test.js +172 -2
  214. package/server/lib/notifications/apns-runtime.js +5 -6
  215. package/server/lib/notifications/apns-runtime.test.js +20 -4
  216. package/server/lib/openchamber-control/DOCUMENTATION.md +19 -1
  217. package/server/lib/openchamber-control/actions.js +2 -1
  218. package/server/lib/openchamber-control/service.js +119 -20
  219. package/server/lib/openchamber-control/service.test.js +166 -0
  220. package/server/lib/openchamber-sessions/archive-store.js +1 -6
  221. package/server/lib/openchamber-sessions/routes.js +47 -12
  222. package/server/lib/openchamber-sessions/routes.test.js +65 -2
  223. package/server/lib/openchamber-sessions/session-metadata-store.js +1 -6
  224. package/server/lib/opencode/DOCUMENTATION.md +22 -8
  225. package/server/lib/opencode/agents.js +62 -0
  226. package/server/lib/opencode/auth-state-runtime.js +3 -1
  227. package/server/lib/opencode/auth.d.ts +1 -1
  228. package/server/lib/opencode/auth.js +8 -0
  229. package/server/lib/opencode/auth.test.js +31 -0
  230. package/server/lib/opencode/config-entity-routes.js +16 -0
  231. package/server/lib/opencode/config-entity-v2.test.js +16 -1
  232. package/server/lib/opencode/config-paths.test.js +2 -2
  233. package/server/lib/opencode/config-v2.js +2 -4
  234. package/server/lib/opencode/feature-routes-runtime.js +89 -49
  235. package/server/lib/opencode/lifecycle.js +41 -21
  236. package/server/lib/opencode/lifecycle.test.js +50 -2
  237. package/server/lib/opencode/model-discovery.js +1 -1
  238. package/server/lib/opencode/model-discovery.test.js +17 -0
  239. package/server/lib/opencode/models-metadata.js +0 -2
  240. package/server/lib/opencode/openchamber-routes.test.js +3 -3
  241. package/server/lib/opencode/plugins.js +6 -9
  242. package/server/lib/opencode/provider-source-route.test.js +101 -3
  243. package/server/lib/opencode/providers-disabled.test.js +59 -0
  244. package/server/lib/opencode/providers.js +34 -0
  245. package/server/lib/opencode/proxy.js +11 -3
  246. package/server/lib/opencode/routes.js +40 -2
  247. package/server/lib/opencode/settings-helpers.js +27 -1
  248. package/server/lib/opencode/settings-helpers.test.js +19 -7
  249. package/server/lib/opencode/settings-registry.json +27 -16
  250. package/server/lib/opencode/settings-runtime.test.js +18 -0
  251. package/server/lib/opencode/shared-service-runtime.js +23 -104
  252. package/server/lib/opencode/shared.js +77 -46
  253. package/server/lib/opencode/shared.test.js +12 -12
  254. package/server/lib/opencode/shutdown-runtime.test.js +2 -3
  255. package/server/lib/opencode/skill-routes.js +123 -38
  256. package/server/lib/opencode/skill-routes.test.js +201 -0
  257. package/server/lib/opencode/skills.js +81 -34
  258. package/server/lib/opencode/skills.test.js +176 -21
  259. package/server/lib/opencode/startup-pipeline-runtime.js +6 -3
  260. package/server/lib/opencode/startup-pipeline-runtime.test.js +2 -1
  261. package/server/lib/opencode/watcher.test.js +0 -54
  262. package/server/lib/outbound-proxy.js +52 -0
  263. package/server/lib/outbound-proxy.test.js +55 -0
  264. package/server/lib/package-manager.js +23 -17
  265. package/server/lib/package-manager.test.js +5 -18
  266. package/server/lib/permission-auto-accept/DOCUMENTATION.md +1 -1
  267. package/server/lib/permission-auto-accept/runtime.js +19 -47
  268. package/server/lib/permission-auto-accept/runtime.test.js +2 -2
  269. package/server/lib/project-context/DOCUMENTATION.md +7 -1
  270. package/server/lib/project-context/routes.js +1 -2
  271. package/server/lib/project-context/runtime.js +12 -14
  272. package/server/lib/project-context/runtime.test.js +78 -2
  273. package/server/lib/projects/project-config.js +30 -15
  274. package/server/lib/projects/project-config.test.js +30 -0
  275. package/server/lib/projects/project-setup.js +1 -2
  276. package/server/lib/projects/routes.js +1 -2
  277. package/server/lib/quota/DOCUMENTATION.md +35 -7
  278. package/server/lib/quota/index.js +1 -0
  279. package/server/lib/quota/providers/claude/index.js +1 -1
  280. package/server/lib/quota/providers/cline-pass.js +1 -1
  281. package/server/lib/quota/providers/exe-dev.js +1 -1
  282. package/server/lib/quota/providers/google/index.js +1 -1
  283. package/server/lib/quota/providers/hyper.js +1 -1
  284. package/server/lib/quota/providers/kimi.js +116 -36
  285. package/server/lib/quota/providers/kimi.test.js +128 -3
  286. package/server/lib/quota/providers/opencode-go.js +144 -21
  287. package/server/lib/quota/providers/opencode-go.test.js +229 -6
  288. package/server/lib/quota/providers/openrouter.js +1 -1
  289. package/server/lib/quota/providers/zenmux.js +1 -1
  290. package/server/lib/quota/utils/auth.js +1 -0
  291. package/server/lib/quota/utils/transformers.js +2 -6
  292. package/server/lib/relay/DOCUMENTATION.md +18 -3
  293. package/server/lib/relay/e2ee.js +7 -7
  294. package/server/lib/relay/host-client.js +84 -13
  295. package/server/lib/relay/host-client.test.js +201 -1
  296. package/server/lib/relay/identity.js +6 -29
  297. package/server/lib/relay/identity.test.js +18 -28
  298. package/server/lib/relay/key-store.js +141 -0
  299. package/server/lib/relay/key-store.test.js +138 -0
  300. package/server/lib/relay/service.js +8 -8
  301. package/server/lib/relay/service.test.js +10 -5
  302. package/server/lib/relay/signing-key.js +13 -36
  303. package/server/lib/relay/tunnel-codec.js +10 -10
  304. package/server/lib/route-module-exports.test.js +22 -0
  305. package/server/lib/routing/DOCUMENTATION.md +23 -3
  306. package/server/lib/routing/cache.js +87 -0
  307. package/server/lib/routing/defaults.js +11 -0
  308. package/server/lib/routing/history.js +12 -4
  309. package/server/lib/routing/runtime.js +39 -3
  310. package/server/lib/routing/runtime.test.js +81 -2
  311. package/server/lib/routing/store.js +12 -1
  312. package/server/lib/routing/store.test.js +13 -0
  313. package/server/lib/scheduled-tasks/DOCUMENTATION.md +59 -1
  314. package/server/lib/scheduled-tasks/existing-session.js +119 -0
  315. package/server/lib/scheduled-tasks/existing-session.test.js +350 -0
  316. package/server/lib/scheduled-tasks/loops.js +1 -8
  317. package/server/lib/scheduled-tasks/routes.js +8 -8
  318. package/server/lib/scheduled-tasks/runtime.js +103 -13
  319. package/server/lib/scheduled-tasks/runtime.test.js +48 -0
  320. package/server/lib/scheduled-tasks/service.js +33 -11
  321. package/server/lib/scheduled-tasks/service.test.js +128 -2
  322. package/server/lib/scheduled-tasks/session-defaults.js +27 -0
  323. package/server/lib/scheduled-tasks/session-defaults.test.js +19 -0
  324. package/server/lib/session-assist/context.js +1 -0
  325. package/server/lib/session-folders/routes.js +2 -2
  326. package/server/lib/session-goal/objectives.js +1 -1
  327. package/server/lib/session-knowledge/routes.js +2 -2
  328. package/server/lib/session-knowledge/runtime.js +1 -2
  329. package/server/lib/session-work/DOCUMENTATION.md +39 -14
  330. package/server/lib/session-work/questions.js +31 -2
  331. package/server/lib/session-work/runtime.js +22 -13
  332. package/server/lib/session-work/runtime.test.js +43 -26
  333. package/server/lib/session-work/state.js +10 -4
  334. package/server/lib/session-work/state.test.js +8 -1
  335. package/server/lib/shared/DOCUMENTATION.md +89 -0
  336. package/server/lib/shared/guards.js +53 -0
  337. package/server/lib/shared/guards.test.js +112 -0
  338. package/server/lib/skills-catalog/DOCUMENTATION.md +10 -8
  339. package/server/lib/skills-catalog/cache.js +3 -2
  340. package/server/lib/skills-catalog/curated-sources.js +5 -1
  341. package/server/lib/skills-catalog/git.js +107 -20
  342. package/server/lib/skills-catalog/git.test.js +78 -0
  343. package/server/lib/skills-catalog/install.js +21 -12
  344. package/server/lib/skills-catalog/scan.js +25 -15
  345. package/server/lib/skills-catalog/source.js +26 -1
  346. package/server/lib/skills-catalog/source.test.js +27 -0
  347. package/server/lib/source-control/DOCUMENTATION.md +2 -1
  348. package/server/lib/source-control/audit-storage.js +7 -6
  349. package/server/lib/source-control/audit-storage.test.js +11 -0
  350. package/server/lib/source-control/binding-service.js +2 -5
  351. package/server/lib/source-control/change-request-worktree.js +90 -0
  352. package/server/lib/source-control/change-request-worktree.test.js +121 -0
  353. package/server/lib/source-control/mutation-executor.js +1 -1
  354. package/server/lib/source-control/mutation-storage.js +11 -5
  355. package/server/lib/source-control/provider-instance.js +1 -2
  356. package/server/lib/source-control/repository-identity.js +1 -1
  357. package/server/lib/source-control/routes.js +14 -2
  358. package/server/lib/spaces/DOCUMENTATION.md +42 -17
  359. package/server/lib/spaces/command-stream.test.js +15 -0
  360. package/server/lib/spaces/dispatcher.js +7 -0
  361. package/server/lib/spaces/dispatcher.test.js +17 -0
  362. package/server/lib/spaces/hardening.js +2 -2
  363. package/server/lib/spaces/hardening.test.js +1 -1
  364. package/server/lib/spaces/host.js +2 -0
  365. package/server/lib/spaces/journey.js +66 -5
  366. package/server/lib/spaces/journey.test.js +95 -4
  367. package/server/lib/spaces/layout.js +1 -1
  368. package/server/lib/spaces/places/docker-disk.js +38 -14
  369. package/server/lib/spaces/places/docker-disk.test.js +80 -1
  370. package/server/lib/spaces/places/docker.js +35 -11
  371. package/server/lib/spaces/places/fake-docker.js +22 -3
  372. package/server/lib/spaces/places/memory-place.js +3 -0
  373. package/server/lib/spaces/places/packed.docker.live.test.js +1 -1
  374. package/server/lib/spaces/routes.js +5 -0
  375. package/server/lib/spaces/routes.test.js +4 -2
  376. package/server/lib/spaces/run-command.js +9 -2
  377. package/server/lib/spaces/tools.js +4 -5
  378. package/server/lib/spaces/tools.test.js +2 -2
  379. package/server/lib/terminal/runtime.js +18 -6
  380. package/server/lib/terminal/runtime.test.js +66 -0
  381. package/server/lib/tts/index.js +3 -0
  382. package/server/lib/tts/service.js +4 -2
  383. package/server/lib/walkthrough/DOCUMENTATION.md +3 -1
  384. package/server/lib/walkthrough/index.js +2 -3
  385. package/server/lib/walkthrough/pr-source.test.js +22 -0
  386. package/server/lib/walkthrough/sources.js +6 -1
  387. package/server/opencode-proxy.test.js +127 -0
  388. package/bin/lib/commands-startup.test.js +0 -15
  389. package/dist/assets/CodeMirrorCommentWidgets-CVDSjcrP.js +0 -1
  390. package/dist/assets/DiffView-Ct7vL3fD.js +0 -4
  391. package/dist/assets/FilesView-DT0uEYgT.js +0 -17
  392. package/dist/assets/GuestSurfacePane-DVvk1VPu.js +0 -1
  393. package/dist/assets/LinearIssuesView-C10MwA9h.js +0 -1
  394. package/dist/assets/MarkdownImageGallery-BbN_K_3d.js +0 -1
  395. package/dist/assets/MarkdownRendererImpl-BLt2Tkk9.js +0 -10
  396. package/dist/assets/OnboardingScreen-Bgp5A3WB.js +0 -1
  397. package/dist/assets/PierreDiffViewer-CWJLj-S-.js +0 -210
  398. package/dist/assets/PlanView-DsRWnsOI.js +0 -5
  399. package/dist/assets/PublishDialog-CCeKloRu.js +0 -2
  400. package/dist/assets/SettingsView-BuPPsNPp.js +0 -30
  401. package/dist/assets/SettingsWindow-CM5fL8Ot.js +0 -1
  402. package/dist/assets/SubmoduleDiffSummary-CfsMcfiQ.js +0 -1
  403. package/dist/assets/ToolOutputDialog-mZrfSofz.js +0 -15
  404. package/dist/assets/ToolPartDiffPreview-BUGCRYEL.js +0 -8
  405. package/dist/assets/WalkthroughView-ClBo7PPd.js +0 -4
  406. package/dist/assets/appThemeRegistry-CxzMxR-H.js +0 -1
  407. package/dist/assets/de-CBla4hjd.js +0 -14
  408. package/dist/assets/es-BmnZtxTD.js +0 -20
  409. package/dist/assets/fileTreeStatus-BSHFIGEg.js +0 -1
  410. package/dist/assets/fr-OVKIBUZO.js +0 -18
  411. package/dist/assets/index-CKCFKmjF.js +0 -1
  412. package/dist/assets/index-Dbx4V4GN.css +0 -1
  413. package/dist/assets/index-vQ1Pg1cr.js +0 -61
  414. package/dist/assets/ja-6v-yr-gE.js +0 -20
  415. package/dist/assets/ko-I_ZLvgQ9.js +0 -20
  416. package/dist/assets/main-CmO4dRtR.js +0 -2
  417. package/dist/assets/main-b9vqhlYM.js +0 -999
  418. package/dist/assets/markdownCore-BPEZRQfP.js +0 -7
  419. package/dist/assets/miniChat-B5Oi7B-6.js +0 -2
  420. package/dist/assets/mobile-CVtShif9.js +0 -2
  421. package/dist/assets/nl-DcvIJf46.js +0 -20
  422. package/dist/assets/patchFileDiff-CW3wCH1O.js +0 -13
  423. package/dist/assets/pl-JxCUl0sd.js +0 -20
  424. package/dist/assets/pt-BR-L89mjja2.js +0 -20
  425. package/dist/assets/relocateRestoredSession-DYh_9oBa.js +0 -1
  426. package/dist/assets/renderElectronMiniChatApp-BD-1JHSg.js +0 -2
  427. package/dist/assets/renderMobileApp-7s5InXt1.js +0 -25
  428. package/dist/assets/runtimeEndpointReset-DqLJC6L1.js +0 -53
  429. package/dist/assets/shikiHighlight-CXgZnvHh.js +0 -1
  430. package/dist/assets/space-apply-1trGVIl8.js +0 -1
  431. package/dist/assets/space-close-y7j-NuBv.js +0 -1
  432. package/dist/assets/tr-ka5J1flt.js +0 -11
  433. package/dist/assets/uk-PyGe6Q_u.js +0 -20
  434. package/dist/assets/useInlineCommentController-CrjSGCpi.js +0 -2
  435. package/dist/assets/vendor-codemirror-lang-python-B7ClrMIT.js +0 -3
  436. package/dist/assets/vendor-codemirror-lang-xml-C8tGnS64.js +0 -1
  437. package/dist/assets/vendor-codemirror-language-data-q2bKO1EM.js +0 -2
  438. package/dist/assets/vendor-framer-motion-Bq3iTZ6r.js +0 -1
  439. package/dist/assets/vendor-katex-CHD9BdDO.js +0 -257
  440. package/dist/assets/vendor-katex-Cp579UoJ.css +0 -1
  441. package/dist/assets/zh-CN-B0P2tybJ.js +0 -20
  442. package/dist/assets/zh-TW-Bs9C5cN8.js +0 -20
@@ -9,11 +9,7 @@ import { isSupportedOpenCodeVersion, readOpenCodeInfo } from './compatibility.js
9
9
 
10
10
  const endpointSchema = z.object({
11
11
  url: z.string(),
12
- auth: z.object({
13
- type: z.literal('basic'),
14
- username: z.string(),
15
- password: z.string(),
16
- }).optional(),
12
+ auth: z.object({ type: z.literal('basic'), username: z.string(), password: z.string() }).optional(),
17
13
  });
18
14
 
19
15
  const createConnectionError = (code, message, details = {}, cause) => {
@@ -22,134 +18,57 @@ const createConnectionError = (code, message, details = {}, cause) => {
22
18
  Object.assign(error, details);
23
19
  return error;
24
20
  };
25
-
26
- const unavailableError = (message, cause) => createConnectionError(
27
- 'OPENCODE_SERVICE_UNAVAILABLE',
28
- message,
29
- {},
30
- cause,
31
- );
32
-
21
+ const unavailableError = (message, cause) => createConnectionError('OPENCODE_SERVICE_UNAVAILABLE', message, {}, cause);
33
22
  const normalizeEndpoint = (endpoint) => {
34
23
  const parsed = endpointSchema.safeParse(endpoint);
35
- if (!parsed.success) {
36
- throw unavailableError('OpenCode shared service did not return an endpoint');
37
- }
38
-
24
+ if (!parsed.success) throw unavailableError('OpenCode shared service did not return an endpoint');
39
25
  let url;
40
- try {
41
- url = new URL(parsed.data.url);
42
- } catch (cause) {
43
- throw unavailableError('OpenCode shared service returned an invalid URL', cause);
44
- }
45
- if ((url.protocol !== 'http:' && url.protocol !== 'https:') || !url.hostname) {
46
- throw unavailableError('OpenCode shared service returned an unsupported URL');
47
- }
48
-
26
+ try { url = new URL(parsed.data.url); } catch (cause) { throw unavailableError('OpenCode shared service returned an invalid URL', cause); }
27
+ if (!['http:', 'https:'].includes(url.protocol) || !url.hostname) throw unavailableError('OpenCode shared service returned an unsupported URL');
49
28
  return { ...parsed.data, url: url.origin };
50
29
  };
51
-
52
- const defaultRegistrationFile = () => join(
53
- process.env.XDG_STATE_HOME ?? join(homedir(), '.local', 'state'),
54
- 'opencode',
55
- 'service.json',
56
- );
57
-
30
+ const defaultRegistrationFile = () => join(process.env.XDG_STATE_HOME ?? join(homedir(), '.local', 'state'), 'opencode', 'service.json');
58
31
  const registrationExists = async (options = {}) => {
59
- try {
60
- await access(options.file ?? defaultRegistrationFile());
61
- return true;
62
- } catch (error) {
63
- if (error?.code === 'ENOENT') return false;
64
- throw error;
65
- }
32
+ try { await access(options.file ?? defaultRegistrationFile()); return true; }
33
+ catch (error) { if (error?.code === 'ENOENT') return false; throw error; }
66
34
  };
67
35
 
68
36
  export const createSharedOpenCodeServiceRuntime = ({
69
- service = Service,
70
- fetchImpl = fetch,
71
- ensureOptions,
72
- readInfo = readOpenCodeInfo,
73
- isSupportedVersion = isSupportedOpenCodeVersion,
74
- hasRegistration = registrationExists,
37
+ service = Service, fetchImpl = fetch, ensureOptions, readInfo = readOpenCodeInfo,
38
+ isSupportedVersion = isSupportedOpenCodeVersion, hasRegistration = registrationExists,
75
39
  }) => {
76
40
  let activeConnection = null;
77
-
78
41
  const resolveEndpoint = async () => {
79
42
  let discovered;
80
- try {
81
- discovered = await service.discover(ensureOptions);
82
- } catch (cause) {
83
- throw unavailableError('Could not discover the OpenCode shared service', cause);
84
- }
43
+ try { discovered = await service.discover(ensureOptions); } catch (cause) { throw unavailableError('Could not discover the OpenCode shared service', cause); }
85
44
  if (discovered) return normalizeEndpoint(discovered);
86
-
87
45
  try {
88
- if (await hasRegistration(ensureOptions)) {
89
- throw unavailableError(
90
- 'An incompatible or unhealthy OpenCode shared service is already registered',
91
- );
92
- }
46
+ if (await hasRegistration(ensureOptions)) throw unavailableError('An incompatible or unhealthy OpenCode shared service is already registered');
93
47
  } catch (cause) {
94
48
  if (cause?.code === 'OPENCODE_SERVICE_UNAVAILABLE') throw cause;
95
49
  throw unavailableError('Could not inspect the OpenCode shared service registration', cause);
96
50
  }
97
- try {
98
- return normalizeEndpoint(await service.ensure(ensureOptions));
99
- } catch (cause) {
51
+ try { return normalizeEndpoint(await service.ensure(ensureOptions)); }
52
+ catch (cause) {
100
53
  if (cause?.code === 'OPENCODE_SERVICE_UNAVAILABLE') throw cause;
101
54
  throw unavailableError('Could not start the OpenCode shared service', cause);
102
55
  }
103
56
  };
104
-
105
57
  const probe = async (endpoint) => {
106
58
  let headers;
107
- try {
108
- headers = { ...(service.headers(endpoint) ?? {}) };
109
- } catch (cause) {
110
- throw unavailableError('Could not authenticate with the OpenCode shared service', cause);
111
- }
59
+ try { headers = { ...(service.headers(endpoint) ?? {}) }; } catch (cause) { throw unavailableError('Could not authenticate with the OpenCode shared service', cause); }
112
60
  let info;
113
- try {
114
- const response = await fetchImpl(new URL('/api/info', endpoint.url), {
115
- headers: { Accept: 'application/json', ...headers },
116
- });
117
- info = await readInfo(response);
118
- } catch (cause) {
119
- throw unavailableError('Could not reach the OpenCode shared service', cause);
120
- }
121
- if (!info) {
122
- throw unavailableError('OpenCode shared service did not return valid service information');
123
- }
124
- if (!isSupportedVersion(info.version)) {
125
- throw createConnectionError(
126
- 'OPENCODE_INCOMPATIBLE',
127
- `OpenCode shared service version ${info.version} is incompatible`,
128
- { foundVersion: info.version },
129
- );
130
- }
131
-
132
- return {
133
- kind: 'shared-local',
134
- endpoint,
135
- version: info.version,
136
- };
61
+ try { info = await readInfo(await fetchImpl(new URL('/api/info', endpoint.url), { headers: { Accept: 'application/json', ...headers } })); }
62
+ catch (cause) { throw unavailableError('Could not reach the OpenCode shared service', cause); }
63
+ if (!info) throw unavailableError('OpenCode shared service did not return valid service information');
64
+ if (!isSupportedVersion(info.version)) throw createConnectionError('OPENCODE_INCOMPATIBLE', `OpenCode shared service version ${info.version} is incompatible`, { foundVersion: info.version });
65
+ return { kind: 'shared-local', endpoint, version: info.version };
137
66
  };
138
-
139
- const establishConnection = async () => {
140
- const replacement = await probe(await resolveEndpoint());
141
- activeConnection = replacement;
142
- return replacement;
143
- };
144
-
67
+ const establishConnection = async () => { const replacement = await probe(await resolveEndpoint()); activeConnection = replacement; return replacement; };
145
68
  return {
146
- connect: establishConnection,
147
- recover: establishConnection,
148
- getConnection: () => activeConnection,
69
+ connect: establishConnection, recover: establishConnection, getConnection: () => activeConnection,
149
70
  getBaseUrl: () => activeConnection?.endpoint.url ?? null,
150
71
  getHeaders: () => activeConnection ? { ...(service.headers(activeConnection.endpoint) ?? {}) } : {},
151
- dispose: async () => {
152
- activeConnection = null;
153
- },
72
+ dispose: async () => { activeConnection = null; },
154
73
  };
155
74
  };
@@ -87,7 +87,14 @@ function sanitizeFrontmatter(frontmatter) {
87
87
  }
88
88
 
89
89
  function parseMdFile(filePath) {
90
- const rawContent = fs.readFileSync(filePath, 'utf8');
90
+ return parseMdContent(fs.readFileSync(filePath, 'utf8'), filePath);
91
+ }
92
+
93
+ async function parseMdFileAsync(filePath) {
94
+ return parseMdContent(await fs.promises.readFile(filePath, 'utf8'), filePath);
95
+ }
96
+
97
+ function parseMdContent(rawContent, filePath) {
91
98
  // Strip a UTF-8 BOM so frontmatter is recognized regardless of the editor
92
99
  // that saved the file.
93
100
  const content = rawContent.charCodeAt(0) === 0xfeff ? rawContent.slice(1) : rawContent;
@@ -119,16 +126,19 @@ function parseMdFile(filePath) {
119
126
  return { frontmatter, body };
120
127
  }
121
128
 
122
- function writeMdFile(filePath, frontmatter, body) {
129
+ // `flag: 'wx'` creates the file and fails with EEXIST when it is already
130
+ // there; that error is passed on as is so a caller can tell it apart.
131
+ function writeMdFile(filePath, frontmatter, body, { flag = 'w' } = {}) {
123
132
  try {
124
133
  const cleanedFrontmatter = Object.fromEntries(
125
134
  Object.entries(frontmatter).filter(([, value]) => value != null)
126
135
  );
127
136
  const yamlStr = yaml.stringify(cleanedFrontmatter);
128
137
  const content = `---\n${yamlStr}---\n\n${body}`;
129
- fs.writeFileSync(filePath, content, 'utf8');
138
+ fs.writeFileSync(filePath, content, { encoding: 'utf8', flag });
130
139
  console.log(`Successfully wrote markdown file: ${filePath}`);
131
140
  } catch (error) {
141
+ if (error?.code === 'EEXIST') throw error;
132
142
  console.error(`Failed to write markdown file ${filePath}:`, error);
133
143
  throw new Error('Failed to write agent markdown file');
134
144
  }
@@ -703,34 +713,62 @@ function writePromptFile(filePath, content) {
703
713
 
704
714
  // ============== SKILL FILE OPERATIONS ==============
705
715
 
706
- function walkSkillMdFiles(rootDir) {
707
- if (!rootDir || !fs.existsSync(rootDir)) return [];
716
+ async function pathExists(target) {
717
+ try {
718
+ await fs.promises.access(target);
719
+ return true;
720
+ } catch {
721
+ return false;
722
+ }
723
+ }
724
+
725
+ // At most this many file-system calls of one walk are in flight at once.
726
+ const SKILL_WALK_CONCURRENCY = 8;
727
+
728
+ // Async so a skills tree with tens of thousands of entries (a bundled `.venv`
729
+ // or `node_modules`) does not hold the server's event loop for seconds.
730
+ // Sibling directories are read in parallel, a few calls at a time, and their
731
+ // results are joined in readdir order, so the order matches the old
732
+ // synchronous depth-first walk exactly.
733
+ async function walkSkillMdFiles(rootDir) {
734
+ if (!rootDir || !(await pathExists(rootDir))) return [];
708
735
 
709
- const results = [];
710
- // Real paths of the directories on the current walk path. Links (symlinks and
711
- // Windows junctions) are followed at any depth; a link back to one of its own
712
- // ancestors is skipped instead of recursing forever. Two links to the same
713
- // target elsewhere in the tree are both walked, as the top level always did.
714
- const ancestors = new Set();
715
- const walk = (dir) => {
736
+ let active = 0;
737
+ const waiting = [];
738
+ const limited = async (call) => {
739
+ if (active >= SKILL_WALK_CONCURRENCY) await new Promise((resolve) => waiting.push(resolve));
740
+ active += 1;
741
+ try {
742
+ return await call();
743
+ } finally {
744
+ active -= 1;
745
+ waiting.shift()?.();
746
+ }
747
+ };
748
+
749
+ // `ancestors` holds the real paths of the directories on the path to `dir`.
750
+ // Links (symlinks and Windows junctions) are followed at any depth; a link
751
+ // back to one of its own ancestors is skipped instead of recursing forever.
752
+ // Two links to the same target elsewhere in the tree are both walked, as the
753
+ // top level always did.
754
+ const walk = async (dir, ancestors) => {
716
755
  let realDir;
717
756
  try {
718
- realDir = fs.realpathSync(dir);
757
+ realDir = await limited(() => fs.promises.realpath(dir));
719
758
  } catch {
720
- return;
759
+ return [];
721
760
  }
722
- if (ancestors.has(realDir)) return;
761
+ if (ancestors.has(realDir)) return [];
723
762
 
724
763
  let entries = [];
725
764
  try {
726
- entries = fs.readdirSync(dir, { withFileTypes: true });
765
+ entries = await limited(() => fs.promises.readdir(dir, { withFileTypes: true }));
727
766
  } catch {
728
- return;
767
+ return [];
729
768
  }
730
769
 
731
- ancestors.add(realDir);
732
-
733
- for (const entry of entries) {
770
+ const childAncestors = new Set(ancestors).add(realDir);
771
+ const found = await Promise.all(entries.map(async (entry) => {
734
772
  const fullPath = path.join(dir, entry.name);
735
773
  // Junctions report as links, not directories. A link whose target cannot be
736
774
  // stat'ed is skipped, the way an unreadable directory is, instead of failing
@@ -739,33 +777,26 @@ function walkSkillMdFiles(rootDir) {
739
777
  let isFileEntry = entry.isFile();
740
778
  if (entry.isSymbolicLink()) {
741
779
  try {
742
- const target = fs.statSync(fullPath);
780
+ const target = await limited(() => fs.promises.stat(fullPath));
743
781
  isDirectoryEntry = target.isDirectory();
744
782
  isFileEntry = target.isFile();
745
783
  } catch {
746
- continue;
784
+ return [];
747
785
  }
748
786
  }
749
- if (isDirectoryEntry) {
750
- walk(fullPath);
751
- continue;
752
- }
753
- if (isFileEntry && entry.name === 'SKILL.md') {
754
- results.push(fullPath);
755
- }
756
- }
757
- ancestors.delete(realDir);
787
+ if (isDirectoryEntry) return walk(fullPath, childAncestors);
788
+ return isFileEntry && entry.name === 'SKILL.md' ? [fullPath] : [];
789
+ }));
790
+ return found.flat();
758
791
  };
759
792
 
760
- walk(rootDir);
761
- return results;
793
+ return walk(rootDir, new Set());
762
794
  }
763
795
 
764
- function addSkillFromMdFile(skillsMap, skillMdPath, scope, source) {
765
- let parsed;
766
- try {
767
- parsed = parseMdFile(skillMdPath);
768
- } catch {
796
+ // `parsed` is what `parseMdFileAsync(skillMdPath)` resolved to, or null when
797
+ // the file could not be read; an unreadable file adds nothing.
798
+ function addSkillFromMdFile(skillsMap, skillMdPath, parsed, scope, source) {
799
+ if (!parsed) {
769
800
  return;
770
801
  }
771
802
 
@@ -818,21 +849,21 @@ function resolveSkillSearchDirectories(workingDirectory) {
818
849
  return directories;
819
850
  }
820
851
 
821
- function listSkillSupportingFiles(skillDir) {
822
- if (!fs.existsSync(skillDir)) {
852
+ async function listSkillSupportingFiles(skillDir) {
853
+ if (!(await pathExists(skillDir))) {
823
854
  return [];
824
855
  }
825
856
 
826
857
  const files = [];
827
858
 
828
- function walkDir(dir, relativePath = '') {
829
- const entries = fs.readdirSync(dir, { withFileTypes: true });
859
+ async function walkDir(dir, relativePath = '') {
860
+ const entries = await fs.promises.readdir(dir, { withFileTypes: true });
830
861
  for (const entry of entries) {
831
862
  const fullPath = path.join(dir, entry.name);
832
863
  const relPath = relativePath ? path.join(relativePath, entry.name) : entry.name;
833
864
 
834
865
  if (entry.isDirectory()) {
835
- walkDir(fullPath, relPath);
866
+ await walkDir(fullPath, relPath);
836
867
  } else if (entry.name !== 'SKILL.md') {
837
868
  files.push({
838
869
  name: entry.name,
@@ -843,7 +874,7 @@ function listSkillSupportingFiles(skillDir) {
843
874
  }
844
875
  }
845
876
 
846
- walkDir(skillDir);
877
+ await walkDir(skillDir);
847
878
  return files;
848
879
  }
849
880
 
@@ -910,6 +941,7 @@ export {
910
941
  SKILL_SCOPE,
911
942
  ensureDirs,
912
943
  parseMdFile,
944
+ parseMdFileAsync,
913
945
  writeMdFile,
914
946
  readConfigFile,
915
947
  readConfigLayer,
@@ -919,7 +951,6 @@ export {
919
951
  readWorktreeDirectorySetting,
920
952
  getConfigForPath,
921
953
  writeConfig,
922
- lookupSectionEntry,
923
954
  getJsonEntrySource,
924
955
  getJsonWriteTarget,
925
956
  getAncestors,
@@ -933,5 +964,5 @@ export {
933
964
  listSkillSupportingFiles,
934
965
  readSkillSupportingFile,
935
966
  writeSkillSupportingFile,
936
- deleteSkillSupportingFile,
967
+ deleteSkillSupportingFile
937
968
  };
@@ -404,19 +404,19 @@ describe('walkSkillMdFiles', () => {
404
404
  // the type argument is ignored on POSIX.
405
405
  const linkDirectory = (target, relativeLink) =>
406
406
  fs.symlinkSync(target, path.join(FIXTURE_DIR, relativeLink), process.platform === 'win32' ? 'junction' : 'dir');
407
- const foundRelative = () =>
408
- walkSkillMdFiles(FIXTURE_DIR)
407
+ const foundRelative = async () =>
408
+ (await walkSkillMdFiles(FIXTURE_DIR))
409
409
  .map((found) => path.relative(FIXTURE_DIR, found).split(path.sep).join('/'))
410
410
  .sort();
411
411
 
412
- it('walks a skill deployed as a link inside the scanned root', () => {
412
+ it('walks a skill deployed as a link inside the scanned root', async () => {
413
413
  writeSkill('real-skill');
414
414
  fs.mkdirSync(path.join(FIXTURE_DIR, 'collection'), { recursive: true });
415
415
  writeSkill(path.join('collection', 'nested-skill'));
416
416
  linkDirectory(path.join(FIXTURE_DIR, 'real-skill'), 'linked-skill');
417
417
  linkDirectory(path.join(FIXTURE_DIR, 'collection'), 'collection-link');
418
418
 
419
- expect(foundRelative()).toEqual([
419
+ expect(await foundRelative()).toEqual([
420
420
  'collection-link/nested-skill/SKILL.md',
421
421
  'collection/nested-skill/SKILL.md',
422
422
  'linked-skill/SKILL.md',
@@ -424,24 +424,24 @@ describe('walkSkillMdFiles', () => {
424
424
  ]);
425
425
  });
426
426
 
427
- it('ends on a link that points back into the scanned tree', () => {
427
+ it('ends on a link that points back into the scanned tree', async () => {
428
428
  fs.mkdirSync(path.join(FIXTURE_DIR, 'loopdir'), { recursive: true });
429
429
  writeSkill('loopdir');
430
430
  linkDirectory(FIXTURE_DIR, path.join('loopdir', 'back'));
431
431
 
432
- expect(foundRelative()).toEqual(['loopdir/SKILL.md']);
432
+ expect(await foundRelative()).toEqual(['loopdir/SKILL.md']);
433
433
  });
434
434
 
435
- it('skips a link whose target is gone and keeps the rest of the scan', () => {
435
+ it('skips a link whose target is gone and keeps the rest of the scan', async () => {
436
436
  writeSkill('real-skill');
437
437
  fs.mkdirSync(path.join(FIXTURE_DIR, 'gone-skill'), { recursive: true });
438
438
  linkDirectory(path.join(FIXTURE_DIR, 'gone-skill'), 'dangling-link');
439
439
  fs.rmSync(path.join(FIXTURE_DIR, 'gone-skill'), { recursive: true, force: true });
440
440
 
441
- expect(foundRelative()).toEqual(['real-skill/SKILL.md']);
441
+ expect(await foundRelative()).toEqual(['real-skill/SKILL.md']);
442
442
  });
443
443
 
444
- it('follows a link nested below the top level of the scanned root', () => {
444
+ it('follows a link nested below the top level of the scanned root', async () => {
445
445
  const outside = `${FIXTURE_DIR}-outside`;
446
446
  fs.rmSync(outside, { recursive: true, force: true });
447
447
  fs.mkdirSync(path.join(outside, 'deep-skill'), { recursive: true });
@@ -449,20 +449,20 @@ describe('walkSkillMdFiles', () => {
449
449
  fs.mkdirSync(path.join(FIXTURE_DIR, 'group'), { recursive: true });
450
450
  try {
451
451
  linkDirectory(path.join(outside, 'deep-skill'), path.join('group', 'linked'));
452
- expect(foundRelative()).toEqual(['group/linked/SKILL.md']);
452
+ expect(await foundRelative()).toEqual(['group/linked/SKILL.md']);
453
453
  } finally {
454
454
  fs.rmSync(outside, { recursive: true, force: true });
455
455
  }
456
456
  });
457
457
 
458
- it('ends on a nested link loop between two directories', () => {
458
+ it('ends on a nested link loop between two directories', async () => {
459
459
  fs.mkdirSync(path.join(FIXTURE_DIR, 'a'), { recursive: true });
460
460
  fs.mkdirSync(path.join(FIXTURE_DIR, 'b'), { recursive: true });
461
461
  writeSkill('a');
462
462
  linkDirectory(path.join(FIXTURE_DIR, 'b'), path.join('a', 'to-b'));
463
463
  linkDirectory(path.join(FIXTURE_DIR, 'a'), path.join('b', 'to-a'));
464
464
 
465
- expect(foundRelative()).toEqual(['a/SKILL.md', 'b/to-a/SKILL.md']);
465
+ expect(await foundRelative()).toEqual(['a/SKILL.md', 'b/to-a/SKILL.md']);
466
466
  });
467
467
  });
468
468
 
@@ -67,8 +67,7 @@ describe('graceful shutdown runtime', () => {
67
67
  const runtime = createRuntime(server);
68
68
  await runtime.gracefulShutdown({ exitProcess: false });
69
69
 
70
- vi.advanceTimersByTime(1000);
71
- await Promise.resolve();
70
+ await vi.advanceTimersByTime(1000);
72
71
 
73
72
  expect(warnSpy).not.toHaveBeenCalledWith('Server close timeout reached, forcing shutdown');
74
73
  expect(vi.getTimerCount()).toBe(0);
@@ -317,7 +316,7 @@ describe('graceful shutdown runtime', () => {
317
316
  await first;
318
317
  await runtime.gracefulShutdown();
319
318
  expect(order).toEqual(['gate', 'viewers', 'proxy', 'relay', 'dictation', 'guests']);
320
- await vi.advanceTimersByTimeAsync(200);
319
+ await vi.advanceTimersByTime(200);
321
320
  expect(reconcile).not.toHaveBeenCalled();
322
321
  expect(vi.getTimerCount()).toBe(0);
323
322
  });