@skaile/workspaces 4.39.0 → 5.0.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 (337) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/{asset-feeds-KXL45ALC.js → asset-feeds-HIWT4DVT.js} +24 -96
  3. package/dist/asset-feeds-HIWT4DVT.js.map +1 -0
  4. package/dist/asset-manager/catalog-deployer.js +10 -9
  5. package/dist/asset-manager/index.js +15 -14
  6. package/dist/asset-manager/installer.js +10 -9
  7. package/dist/asset-manager/src/catalog-deployer.d.ts +1 -3
  8. package/dist/asset-manager/src/catalog-deployer.d.ts.map +1 -1
  9. package/dist/asset-manager/src/index.d.ts +6 -8
  10. package/dist/asset-manager/src/index.d.ts.map +1 -1
  11. package/dist/bridge/drivers/claude-sdk.js +23 -11
  12. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  13. package/dist/bridge/drivers/codex.js +11 -10
  14. package/dist/bridge/drivers/codex.js.map +1 -1
  15. package/dist/bridge/drivers/continue.js +12 -11
  16. package/dist/bridge/drivers/continue.js.map +1 -1
  17. package/dist/bridge/drivers/echo.js +2 -2
  18. package/dist/bridge/drivers/gemini.js +6 -6
  19. package/dist/bridge/drivers/goose.js +12 -11
  20. package/dist/bridge/drivers/goose.js.map +1 -1
  21. package/dist/bridge/drivers/omp.js +3 -3
  22. package/dist/bridge/drivers/opencode.js +12 -11
  23. package/dist/bridge/drivers/opencode.js.map +1 -1
  24. package/dist/bridge/drivers/qwen.js +6 -6
  25. package/dist/bridge/index.js +13 -12
  26. package/dist/bridge/src/drivers/claude-sdk.d.ts +4 -0
  27. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  28. package/dist/bridge/src/types.d.ts +7 -0
  29. package/dist/bridge/src/types.d.ts.map +1 -1
  30. package/dist/{chunk-7RC37XFW.js → chunk-22DN3DB2.js} +59 -12
  31. package/dist/chunk-22DN3DB2.js.map +1 -0
  32. package/dist/{chunk-SM6EUQMY.js → chunk-32DMH2GD.js} +8 -8
  33. package/dist/{chunk-SM6EUQMY.js.map → chunk-32DMH2GD.js.map} +1 -1
  34. package/dist/{chunk-A5EDMBFG.js → chunk-43ZBF3WH.js} +5 -8
  35. package/dist/chunk-43ZBF3WH.js.map +1 -0
  36. package/dist/{chunk-5RWL4L3X.js → chunk-53WMBXSL.js} +60 -14
  37. package/dist/chunk-53WMBXSL.js.map +1 -0
  38. package/dist/{chunk-YCMZHL4T.js → chunk-7QMRP6BC.js} +4 -4
  39. package/dist/{chunk-YCMZHL4T.js.map → chunk-7QMRP6BC.js.map} +1 -1
  40. package/dist/chunk-A2ULN3KX.js +40 -0
  41. package/dist/chunk-A2ULN3KX.js.map +1 -0
  42. package/dist/{chunk-DSB6X25D.js → chunk-AG44ZJ7W.js} +3 -3
  43. package/dist/{chunk-DSB6X25D.js.map → chunk-AG44ZJ7W.js.map} +1 -1
  44. package/dist/{chunk-SSCPTAFJ.js → chunk-CFL5IJHV.js} +3 -3
  45. package/dist/{chunk-SSCPTAFJ.js.map → chunk-CFL5IJHV.js.map} +1 -1
  46. package/dist/{chunk-36ML6SFP.js → chunk-CGJ7B6MZ.js} +4 -4
  47. package/dist/{chunk-36ML6SFP.js.map → chunk-CGJ7B6MZ.js.map} +1 -1
  48. package/dist/{chunk-6X4DHKHP.js → chunk-CT6NQSA4.js} +3 -3
  49. package/dist/{chunk-6X4DHKHP.js.map → chunk-CT6NQSA4.js.map} +1 -1
  50. package/dist/{chunk-5K2VT6E2.js → chunk-DXUQCMVT.js} +3 -3
  51. package/dist/{chunk-5K2VT6E2.js.map → chunk-DXUQCMVT.js.map} +1 -1
  52. package/dist/{chunk-B4IAZTZZ.js → chunk-EB6OPURC.js} +3 -3
  53. package/dist/{chunk-B4IAZTZZ.js.map → chunk-EB6OPURC.js.map} +1 -1
  54. package/dist/{chunk-252TK4RU.js → chunk-GFPG27HK.js} +12 -14
  55. package/dist/chunk-GFPG27HK.js.map +1 -0
  56. package/dist/{chunk-2EL2PBRC.js → chunk-H4EGUQ7M.js} +3 -3
  57. package/dist/{chunk-2EL2PBRC.js.map → chunk-H4EGUQ7M.js.map} +1 -1
  58. package/dist/{chunk-YQEF36D5.js → chunk-H5G3OYY6.js} +4 -4
  59. package/dist/{chunk-YQEF36D5.js.map → chunk-H5G3OYY6.js.map} +1 -1
  60. package/dist/{chunk-C75VKXAM.js → chunk-HD5K3BYW.js} +3 -3
  61. package/dist/{chunk-C75VKXAM.js.map → chunk-HD5K3BYW.js.map} +1 -1
  62. package/dist/{chunk-VJNTB4DN.js → chunk-HTBGJCKP.js} +4 -4
  63. package/dist/{chunk-VJNTB4DN.js.map → chunk-HTBGJCKP.js.map} +1 -1
  64. package/dist/{chunk-JEPSP6XK.js → chunk-HWE3FXF4.js} +17 -11
  65. package/dist/chunk-HWE3FXF4.js.map +1 -0
  66. package/dist/{chunk-QVLQGXT6.js → chunk-I3ITSUWS.js} +5 -5
  67. package/dist/{chunk-QVLQGXT6.js.map → chunk-I3ITSUWS.js.map} +1 -1
  68. package/dist/{chunk-H7N6RWNF.js → chunk-I7Z4FN52.js} +4 -4
  69. package/dist/{chunk-H7N6RWNF.js.map → chunk-I7Z4FN52.js.map} +1 -1
  70. package/dist/{chunk-WCWFS36P.js → chunk-IGXKUCLI.js} +3 -3
  71. package/dist/{chunk-WCWFS36P.js.map → chunk-IGXKUCLI.js.map} +1 -1
  72. package/dist/{chunk-VXPFSZDT.js → chunk-JFVEX4G5.js} +6 -6
  73. package/dist/{chunk-VXPFSZDT.js.map → chunk-JFVEX4G5.js.map} +1 -1
  74. package/dist/{chunk-YYH5EVPM.js → chunk-JUXQUZOQ.js} +12 -4
  75. package/dist/{chunk-YYH5EVPM.js.map → chunk-JUXQUZOQ.js.map} +1 -1
  76. package/dist/{chunk-M7GPCWEV.js → chunk-KREXWKVX.js} +3 -3
  77. package/dist/{chunk-M7GPCWEV.js.map → chunk-KREXWKVX.js.map} +1 -1
  78. package/dist/{chunk-TQ6XNACF.js → chunk-LHFZTVIM.js} +23 -24
  79. package/dist/chunk-LHFZTVIM.js.map +1 -0
  80. package/dist/{chunk-YV3YI3TA.js → chunk-MBVNMPG7.js} +4 -4
  81. package/dist/{chunk-YV3YI3TA.js.map → chunk-MBVNMPG7.js.map} +1 -1
  82. package/dist/{chunk-3C3ODIDE.js → chunk-MX7IRKTO.js} +6 -6
  83. package/dist/{chunk-3C3ODIDE.js.map → chunk-MX7IRKTO.js.map} +1 -1
  84. package/dist/{chunk-UDFWBALP.js → chunk-NFGRW3L7.js} +3 -3
  85. package/dist/{chunk-UDFWBALP.js.map → chunk-NFGRW3L7.js.map} +1 -1
  86. package/dist/{chunk-5LF27VUB.js → chunk-ODT7HSLI.js} +16 -15
  87. package/dist/chunk-ODT7HSLI.js.map +1 -0
  88. package/dist/{chunk-QBQITQAM.js → chunk-PV4OBVA3.js} +3 -3
  89. package/dist/{chunk-QBQITQAM.js.map → chunk-PV4OBVA3.js.map} +1 -1
  90. package/dist/{chunk-ORH2BZEM.js → chunk-QCI6D7E4.js} +69 -22
  91. package/dist/chunk-QCI6D7E4.js.map +1 -0
  92. package/dist/{chunk-DIQDYNXZ.js → chunk-QZLWJETK.js} +3 -3
  93. package/dist/{chunk-DIQDYNXZ.js.map → chunk-QZLWJETK.js.map} +1 -1
  94. package/dist/{chunk-TSVRKUGV.js → chunk-RP4B4HVX.js} +11 -2
  95. package/dist/chunk-RP4B4HVX.js.map +1 -0
  96. package/dist/{chunk-X4DKUGV4.js → chunk-RSHMAEK3.js} +7 -13
  97. package/dist/chunk-RSHMAEK3.js.map +1 -0
  98. package/dist/chunk-RVRB27AN.js +64 -0
  99. package/dist/chunk-RVRB27AN.js.map +1 -0
  100. package/dist/{chunk-5NYBY6ZE.js → chunk-TVOODIZE.js} +3 -3
  101. package/dist/{chunk-5NYBY6ZE.js.map → chunk-TVOODIZE.js.map} +1 -1
  102. package/dist/{chunk-FTPKMJFD.js → chunk-TVYLXZTT.js} +2 -2
  103. package/dist/{chunk-FTPKMJFD.js.map → chunk-TVYLXZTT.js.map} +1 -1
  104. package/dist/{chunk-EOKAFBJ7.js → chunk-TYUJB336.js} +3 -3
  105. package/dist/{chunk-EOKAFBJ7.js.map → chunk-TYUJB336.js.map} +1 -1
  106. package/dist/{chunk-OLMNDIAU.js → chunk-UVOJSWD2.js} +95 -320
  107. package/dist/chunk-UVOJSWD2.js.map +1 -0
  108. package/dist/{chunk-DOVURNRK.js → chunk-VDJKWKH2.js} +3 -3
  109. package/dist/chunk-VDJKWKH2.js.map +1 -0
  110. package/dist/{chunk-VDBP6Y5M.js → chunk-WCQMXBO5.js} +21 -47
  111. package/dist/chunk-WCQMXBO5.js.map +1 -0
  112. package/dist/{chunk-NLKIW2VI.js → chunk-WOJ4AK3Q.js} +3 -3
  113. package/dist/{chunk-NLKIW2VI.js.map → chunk-WOJ4AK3Q.js.map} +1 -1
  114. package/dist/{chunk-XU7JET5Z.js → chunk-X7MHVL4R.js} +16 -100
  115. package/dist/chunk-X7MHVL4R.js.map +1 -0
  116. package/dist/{chunk-K3IBZ2UZ.js → chunk-XUUYAS3Z.js} +3 -3
  117. package/dist/{chunk-K3IBZ2UZ.js.map → chunk-XUUYAS3Z.js.map} +1 -1
  118. package/dist/{chunk-BCUVRJXV.js → chunk-XWLEXD34.js} +3 -3
  119. package/dist/{chunk-BCUVRJXV.js.map → chunk-XWLEXD34.js.map} +1 -1
  120. package/dist/{chunk-P7BU6DAC.js → chunk-YOWFUJO7.js} +69 -31
  121. package/dist/chunk-YOWFUJO7.js.map +1 -0
  122. package/dist/{chunk-OQRB7JUS.js → chunk-YV4J7V53.js} +3 -3
  123. package/dist/{chunk-OQRB7JUS.js.map → chunk-YV4J7V53.js.map} +1 -1
  124. package/dist/{chunk-JXT46QFC.js → chunk-ZDKJHQY2.js} +2 -2
  125. package/dist/{chunk-JXT46QFC.js.map → chunk-ZDKJHQY2.js.map} +1 -1
  126. package/dist/cli/index.js +375 -699
  127. package/dist/cli/index.js.map +1 -1
  128. package/dist/cli/src/asset-feeds.d.ts +1 -8
  129. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  130. package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
  131. package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
  132. package/dist/cli/src/commands/library-index.d.ts +5 -12
  133. package/dist/cli/src/commands/library-index.d.ts.map +1 -1
  134. package/dist/cli/src/commands/manage.d.ts +74 -58
  135. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  136. package/dist/cli/src/commands/show.d.ts +1 -1
  137. package/dist/cli/src/commands/skailify-lib.d.ts +0 -31
  138. package/dist/cli/src/commands/skailify-lib.d.ts.map +1 -1
  139. package/dist/cli/src/commands/source-manifest.d.ts.map +1 -1
  140. package/dist/cli/src/commands/validate.d.ts +20 -2
  141. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  142. package/dist/cli/src/flow-discovery.d.ts +2 -2
  143. package/dist/cli/src/hooks/pre-commit-version.d.ts +1 -1
  144. package/dist/cli/src/skill-walker.d.ts +7 -10
  145. package/dist/cli/src/skill-walker.d.ts.map +1 -1
  146. package/dist/connectors/config.js +6 -5
  147. package/dist/connectors/index.js +21 -20
  148. package/dist/core/discovery.js +1 -1
  149. package/dist/core/index.js +9 -8
  150. package/dist/core/manifest.js +2 -2
  151. package/dist/core/models.js +1 -1
  152. package/dist/core/plugin-groupings.d.ts +2 -0
  153. package/dist/core/plugin-groupings.js +4 -0
  154. package/dist/core/plugin-groupings.js.map +1 -0
  155. package/dist/core/publish-manifest.js +2 -2
  156. package/dist/core/ref.js +1 -1
  157. package/dist/core/runtime-assets.js +6 -5
  158. package/dist/core/src/discovery.d.ts +11 -51
  159. package/dist/core/src/discovery.d.ts.map +1 -1
  160. package/dist/core/src/index.d.ts +3 -2
  161. package/dist/core/src/index.d.ts.map +1 -1
  162. package/dist/core/src/models.d.ts +6 -33
  163. package/dist/core/src/models.d.ts.map +1 -1
  164. package/dist/core/src/plugin-groupings.d.ts +31 -0
  165. package/dist/core/src/plugin-groupings.d.ts.map +1 -0
  166. package/dist/core/src/repo-manager.d.ts.map +1 -1
  167. package/dist/core/src/settings.d.ts +1 -1
  168. package/dist/core/src/workspace-config.d.ts +1 -1
  169. package/dist/core/workspace-config.js +5 -4
  170. package/dist/deploy/index.js +9 -8
  171. package/dist/deploy/index.js.map +1 -1
  172. package/dist/discovery/index.js +6 -5
  173. package/dist/discovery/src/discover.d.ts +9 -25
  174. package/dist/discovery/src/discover.d.ts.map +1 -1
  175. package/dist/discovery/src/index.d.ts +0 -2
  176. package/dist/discovery/src/index.d.ts.map +1 -1
  177. package/dist/discovery/src/source-config.d.ts +13 -9
  178. package/dist/discovery/src/source-config.d.ts.map +1 -1
  179. package/dist/discovery/src/tree-entries.d.ts +6 -11
  180. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  181. package/dist/{ensure-sources-J5CDTQ36.js → ensure-sources-G4FXTJDB.js} +18 -17
  182. package/dist/ensure-sources-G4FXTJDB.js.map +1 -0
  183. package/dist/factory-assets/README.md +1 -1
  184. package/dist/factory-assets/connectors/box.js +21 -20
  185. package/dist/factory-assets/connectors/deploy.js +21 -20
  186. package/dist/factory-assets/connectors/devserver.js +21 -20
  187. package/dist/factory-assets/connectors/flow/CONNECTOR.md +6 -1
  188. package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
  189. package/dist/factory-assets/connectors/flow/adapter.js +21 -20
  190. package/dist/factory-assets/connectors/flow/contract/flow.v2.schema.json +13 -3
  191. package/dist/factory-assets/connectors/flow/contract/index.d.ts +1 -0
  192. package/dist/factory-assets/connectors/flow/contract/index.d.ts.map +1 -1
  193. package/dist/factory-assets/connectors/flow/contract/output-fields.d.ts +21 -5
  194. package/dist/factory-assets/connectors/flow/contract/output-fields.d.ts.map +1 -1
  195. package/dist/factory-assets/connectors/flow/contract/schema.d.ts +2 -0
  196. package/dist/factory-assets/connectors/flow/contract/schema.d.ts.map +1 -1
  197. package/dist/factory-assets/connectors/flow/contract/sub-flow-output.d.ts +20 -0
  198. package/dist/factory-assets/connectors/flow/contract/sub-flow-output.d.ts.map +1 -0
  199. package/dist/factory-assets/connectors/flow/contract.js +4 -4
  200. package/dist/factory-assets/connectors/flow/engine/bindings.d.ts.map +1 -1
  201. package/dist/factory-assets/connectors/flow/engine/flow-output.d.ts +12 -0
  202. package/dist/factory-assets/connectors/flow/engine/flow-output.d.ts.map +1 -0
  203. package/dist/factory-assets/connectors/flow/engine/index.d.ts +1 -0
  204. package/dist/factory-assets/connectors/flow/engine/index.d.ts.map +1 -1
  205. package/dist/factory-assets/connectors/flow/engine/loader.d.ts +3 -3
  206. package/dist/factory-assets/connectors/flow/engine/locate.d.ts +2 -2
  207. package/dist/factory-assets/connectors/flow/engine/locate.d.ts.map +1 -1
  208. package/dist/factory-assets/connectors/flow/engine/types.d.ts +0 -2
  209. package/dist/factory-assets/connectors/flow/engine/types.d.ts.map +1 -1
  210. package/dist/factory-assets/connectors/flow/engine.js +13 -12
  211. package/dist/factory-assets/connectors/flow/inline-sub-flow-host.d.ts.map +1 -1
  212. package/dist/factory-assets/connectors/flow/prompt-fragments.js +3 -3
  213. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  214. package/dist/factory-assets/connectors/flow/run-flow.js +23 -22
  215. package/dist/factory-assets/connectors/flow/sub-flow-runner.d.ts +6 -5
  216. package/dist/factory-assets/connectors/flow/sub-flow-runner.d.ts.map +1 -1
  217. package/dist/factory-assets/connectors/flow.js +21 -20
  218. package/dist/factory-assets/connectors/git.js +21 -20
  219. package/dist/factory-assets/connectors/gmail.js +21 -20
  220. package/dist/factory-assets/connectors/googledrive.js +21 -20
  221. package/dist/factory-assets/connectors/local.js +21 -20
  222. package/dist/factory-assets/connectors/mattermost.js +21 -20
  223. package/dist/factory-assets/connectors/memory.js +21 -20
  224. package/dist/factory-assets/connectors/minio.js +21 -20
  225. package/dist/factory-assets/connectors/postgres.js +21 -20
  226. package/dist/factory-assets/connectors/s3.js +21 -20
  227. package/dist/factory-assets/connectors/sharepoint.js +21 -20
  228. package/dist/factory-assets/connectors/sqlite.js +21 -20
  229. package/dist/factory-assets/connectors/static-server.js +21 -20
  230. package/dist/factory-assets/connectors/tunnel.js +21 -20
  231. package/dist/factory-assets/connectors/webdav.js +21 -20
  232. package/dist/factory-assets/connectors/xstate-store.js +21 -20
  233. package/dist/factory-assets/connectors/xstate.js +21 -20
  234. package/dist/factory-assets/skills/skaile-author-asset/SKILL.md +37 -26
  235. package/dist/factory-assets/skills/skaile-manage-workspace/SKILL.md +2 -2
  236. package/dist/factory-assets/skills/skailify/SKILL.md +10 -19
  237. package/dist/{flows-PX53XFV7.js → flows-7E2GVW5L.js} +14 -13
  238. package/dist/{flows-PX53XFV7.js.map → flows-7E2GVW5L.js.map} +1 -1
  239. package/dist/{helpers-EP6H3O3S.js → helpers-EVPKJXGS.js} +18 -17
  240. package/dist/{helpers-EP6H3O3S.js.map → helpers-EVPKJXGS.js.map} +1 -1
  241. package/dist/library/index.js +13 -12
  242. package/dist/library/install.js +2 -2
  243. package/dist/library/src/index.d.ts +1 -1
  244. package/dist/library/src/index.d.ts.map +1 -1
  245. package/dist/library/src/local/db.d.ts.map +1 -1
  246. package/dist/library/src/local/library-manager.d.ts.map +1 -1
  247. package/dist/library/src/local/library.d.ts.map +1 -1
  248. package/dist/library/src/local/local-catalog-source.d.ts +0 -9
  249. package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
  250. package/dist/library/src/local/schema.d.ts +1 -20
  251. package/dist/library/src/local/schema.d.ts.map +1 -1
  252. package/dist/library/src/remote/remote-catalog-source.d.ts +1 -11
  253. package/dist/library/src/remote/remote-catalog-source.d.ts.map +1 -1
  254. package/dist/library/src/sync/manifest-writeback.d.ts +5 -5
  255. package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
  256. package/dist/library/src/user-library.d.ts +1 -9
  257. package/dist/library/src/user-library.d.ts.map +1 -1
  258. package/dist/{library-publish-KKT73FJK.js → library-publish-SBEWWTPM.js} +25 -24
  259. package/dist/library-publish-SBEWWTPM.js.map +1 -0
  260. package/dist/open-library-UAZIGZUQ.js +39 -0
  261. package/dist/{open-library-R62UBL6E.js.map → open-library-UAZIGZUQ.js.map} +1 -1
  262. package/dist/paths-U7TA7MTE.js +22 -0
  263. package/dist/{paths-W4LDORQQ.js.map → paths-U7TA7MTE.js.map} +1 -1
  264. package/dist/{plugin-store-D45CREMJ.js → plugin-store-TT45MGQZ.js} +11 -10
  265. package/dist/plugin-store-TT45MGQZ.js.map +1 -0
  266. package/dist/plugins/index.js +1 -1
  267. package/dist/plugins/src/catalog-source.d.ts +4 -55
  268. package/dist/plugins/src/catalog-source.d.ts.map +1 -1
  269. package/dist/plugins/src/index.d.ts +1 -1
  270. package/dist/plugins/src/index.d.ts.map +1 -1
  271. package/dist/{project-GCW5DFAB.js → project-JLD5RCVK.js} +19 -18
  272. package/dist/{project-GCW5DFAB.js.map → project-JLD5RCVK.js.map} +1 -1
  273. package/dist/resolver/index.js +10 -9
  274. package/dist/runner/index.js +32 -31
  275. package/dist/runner/src/compaction/orchestrator.d.ts +2 -1
  276. package/dist/runner/src/compaction/orchestrator.d.ts.map +1 -1
  277. package/dist/runner/src/compaction-gate.d.ts +13 -0
  278. package/dist/runner/src/compaction-gate.d.ts.map +1 -1
  279. package/dist/runner/src/serve.d.ts.map +1 -1
  280. package/dist/sdk/asset-manager.js +15 -14
  281. package/dist/sdk/bridge.js +13 -12
  282. package/dist/sdk/core.js +9 -8
  283. package/dist/sdk/flow.js +13 -12
  284. package/dist/sdk/index.js +32 -31
  285. package/dist/sdk/index.js.map +1 -1
  286. package/dist/sdk/resolver.js +10 -9
  287. package/dist/sdk/runner.js +32 -31
  288. package/dist/secrets/index.js +2 -2
  289. package/dist/{setup-Q3LXY5AE.js → setup-PGZM4SOO.js} +23 -22
  290. package/dist/setup-PGZM4SOO.js.map +1 -0
  291. package/dist/skills-7QVYPIXI.js +26 -0
  292. package/dist/{skills-R3RPIPWP.js.map → skills-7QVYPIXI.js.map} +1 -1
  293. package/dist/source-SDZYXVVV.js +40 -0
  294. package/dist/{source-CFQESKJU.js.map → source-SDZYXVVV.js.map} +1 -1
  295. package/dist/{source-manifest-publish-3TCBA2RV.js → source-manifest-publish-UDLTYV6Y.js} +26 -25
  296. package/dist/source-manifest-publish-UDLTYV6Y.js.map +1 -0
  297. package/dist/tui/index.js +32 -31
  298. package/dist/tui/index.js.map +1 -1
  299. package/dist/workspace-plugin/adapters/mcp.js +16 -15
  300. package/dist/workspace-plugin/adapters/omp.js +13 -13
  301. package/dist/workspace-plugin/adapters/omp.js.map +1 -1
  302. package/dist/workspace-plugin/index.js +1 -1
  303. package/dist/workspace-plugin/src/adapters/mcp.d.ts +4 -4
  304. package/dist/workspace-plugin/src/adapters/mcp.d.ts.map +1 -1
  305. package/dist/workspace-plugin/src/adapters/omp.d.ts +2 -2
  306. package/dist/workspace-plugin/src/tools/skills.d.ts +5 -17
  307. package/dist/workspace-plugin/src/tools/skills.d.ts.map +1 -1
  308. package/package.json +7 -1
  309. package/dist/asset-feeds-KXL45ALC.js.map +0 -1
  310. package/dist/chunk-252TK4RU.js.map +0 -1
  311. package/dist/chunk-5LF27VUB.js.map +0 -1
  312. package/dist/chunk-5RWL4L3X.js.map +0 -1
  313. package/dist/chunk-7RC37XFW.js.map +0 -1
  314. package/dist/chunk-A5EDMBFG.js.map +0 -1
  315. package/dist/chunk-DOVURNRK.js.map +0 -1
  316. package/dist/chunk-JEPSP6XK.js.map +0 -1
  317. package/dist/chunk-OLMNDIAU.js.map +0 -1
  318. package/dist/chunk-ORH2BZEM.js.map +0 -1
  319. package/dist/chunk-P7BU6DAC.js.map +0 -1
  320. package/dist/chunk-QVZA2MDT.js +0 -81
  321. package/dist/chunk-QVZA2MDT.js.map +0 -1
  322. package/dist/chunk-TQ6XNACF.js.map +0 -1
  323. package/dist/chunk-TSVRKUGV.js.map +0 -1
  324. package/dist/chunk-VDBP6Y5M.js.map +0 -1
  325. package/dist/chunk-X4DKUGV4.js.map +0 -1
  326. package/dist/chunk-XU7JET5Z.js.map +0 -1
  327. package/dist/discovery/src/domains.d.ts +0 -149
  328. package/dist/discovery/src/domains.d.ts.map +0 -1
  329. package/dist/ensure-sources-J5CDTQ36.js.map +0 -1
  330. package/dist/library-publish-KKT73FJK.js.map +0 -1
  331. package/dist/open-library-R62UBL6E.js +0 -38
  332. package/dist/paths-W4LDORQQ.js +0 -21
  333. package/dist/plugin-store-D45CREMJ.js.map +0 -1
  334. package/dist/setup-Q3LXY5AE.js.map +0 -1
  335. package/dist/skills-R3RPIPWP.js +0 -25
  336. package/dist/source-CFQESKJU.js +0 -39
  337. package/dist/source-manifest-publish-3TCBA2RV.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../core/src/runtime-assets.ts"],"names":["resolvePath","require"],"mappings":"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","file":"chunk-36ML6SFP.js","sourcesContent":["/**\n * Runtime asset resolution — read `skaile.yaml`, scan all declared repositories\n * (including the built-in `factory-assets/` directory as an implicit default),\n * and produce a unified view of connector catalog entries plus the implicit refs\n * that the `skaile.yaml` `connectors:` section adds to the dependency graph.\n *\n * This module is the single source of truth for \"which connectors does this\n * project see at runtime, and where do their implementations live on disk\".\n * Both the runner (serve, REPL, flow) and the platform's mid-session\n * `add_resource` flow consume `RuntimeAssetsResult.catalogEntries` and pass\n * it into `ConnectorManager` for catalog-based resolution.\n *\n * `factory-assets/` is the single first-party content tree (built-in connectors\n * + first-party skills + bundles) shipped inside the `@skaile/workspaces`\n * package — not a standalone package.\n *\n * It resolves to an **ordered list of roots** ({@link factoryAssetRoots}), not a\n * single dir. The bundled tree is always the baseline; an optional\n * `SKAILE_FACTORY_ASSETS_DIR` (legacy: `SKAILE_BASE_ASSETS_DIR`) is layered\n * **in front** as an additive override source — the agent container points it at\n * `/app/factory-assets/` (or a bind-mounted host dir) to ship updated skills /\n * flows / bundles / connector manifests without rebuilding the image. The two\n * roots resolve uniformly across every consumer (connector catalog scan, skill /\n * flow / completion discovery, the asset-manager factory source):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir, when set and existing (override layer).\n * 2. the bundled tree via {@link resolvePackagedAssetsDir} — the in-repo source\n * `packages/workspaces/factory-assets/` during dev, else the published\n * `dist/factory-assets/` after install (always-present baseline).\n *\n * Override semantics are **env-first**: on a name conflict the env root wins and\n * the bundled root fills the rest. Connector *code* still loads via the package's\n * static `exports` map, so the env root can override/add skills, flows, bundles,\n * and connector **manifests/metadata**, but cannot ship a new executable\n * connector — its `.js` is not on the package's import graph.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { lstat, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { tryWithFsDeadline } from \"./fs-deadline.js\";\nimport { scanDirectory } from \"./manifest.js\";\nimport type { CatalogEntry } from \"./models.js\";\nimport { getGlobalCacheDir, readLinks, sourceCacheKey } from \"./repo-manager.js\";\nimport type { SourceDeclaration, SourceEntry } from \"./workspace-config.js\";\nimport { resolveSkWorkspaceConfig } from \"./workspace-config.js\";\n\n/**\n * Map declared `sources[]` to internal `SourceDeclaration`s keyed by the\n * collision-free {@link sourceCacheKey} (`<host>/<owner>/<repo>`), pointing at\n * the unified machine-cache clone path (`getGlobalCacheDir()/<key>/`). Keyed by\n * the same function every other cache writer/reader uses so the path resolves.\n */\nfunction sourcesToDeclarations(\n sources: SourceEntry[] | undefined,\n): Record<string, SourceDeclaration> {\n const sourcesDir = getGlobalCacheDir();\n const out: Record<string, SourceDeclaration> = {};\n for (const s of sources ?? []) {\n const key = sourceCacheKey(s.url);\n if (out[key]) continue;\n out[key] = { path: join(sourcesDir, key), url: s.url, branch: s.pin };\n }\n return out;\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/**\n * Catalog entry filtered to mount/connector kinds. Same shape as `CatalogEntry`.\n * @docLink packages/core/concepts#runtime-catalog-entry\n */\nexport type RuntimeCatalogEntry = CatalogEntry;\n\n/**\n * Implicit catalog reference derived from a `connectors:` declaration in `skaile.yaml`.\n * Each connector driver becomes an implicit ref that must be resolved in the catalog.\n * @docLink packages/core/concepts#runtime-asset-ref\n */\nexport interface RuntimeAssetRef {\n kind: \"connector\";\n /** Driver name — matches `RuntimeCatalogEntry.name`. */\n name: string;\n /** Source declaration id from `skaile.yaml`. */\n declarationId: string;\n}\n\n/**\n * Aggregated npm packages required by all resolved mount/connector adapters.\n * Populated from `metadata.npm_deps` in each matched catalog entry.\n * @docLink packages/core/concepts#runtime-npm-deps\n */\nexport interface RuntimeNpmDeps {\n required: string[];\n optional: string[];\n}\n\n/**\n * Non-fatal warning emitted during `resolveRuntimeAssets` when a repo is unavailable\n * or a driver is not found in any catalog.\n * @docLink packages/core/concepts#runtime-asset-warning\n */\nexport interface RuntimeAssetWarning {\n /** Stable code for filtering / structured logging. */\n code: \"missing_driver\" | \"repo_unavailable\" | \"invalid_repo_decl\";\n message: string;\n /** Declaration id when applicable. */\n declarationId?: string;\n /** Driver / repository name when applicable. */\n name?: string;\n}\n\n/**\n * Repository name used for the implicit built-in `factory-assets` catalog entry\n * (the in-package connector tree).\n * @docLink packages/core/concepts#factory-assets-repo-name\n */\nexport const FACTORY_ASSETS_REPO_NAME = \"factory-assets\";\n\n/**\n * Repository name for the optional `SKAILE_FACTORY_ASSETS_DIR` override layer,\n * scanned ahead of (and overriding) the bundled {@link FACTORY_ASSETS_REPO_NAME}.\n */\nconst FACTORY_ASSETS_OVERRIDE_REPO_NAME = \"factory-assets:override\";\n\n/**\n * Result of `resolveRuntimeAssets`.\n * The same object is mutated in place by `refresh()`, allowing callers to hold\n * a stable reference and observe updates after a new repository is cloned or\n * a driver is installed mid-session.\n * @docLink packages/core/concepts#runtime-assets-result\n */\nexport interface RuntimeAssetsResult {\n catalogEntries: RuntimeCatalogEntry[];\n implicitRefs: RuntimeAssetRef[];\n requiredNpmDeps: RuntimeNpmDeps;\n warnings: RuntimeAssetWarning[];\n /** Re-scan repositories and re-derive implicit refs. Mutates in place. */\n refresh(): Promise<void>;\n /**\n * Catalog lookup. When `kind` is omitted and multiple entries share the\n * `name`, returns `undefined` (caller must disambiguate).\n */\n findEntry(query: { kind?: \"connector\"; name: string }): RuntimeCatalogEntry | undefined;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Resolve all runtime assets visible to a project by scanning declared repositories.\n *\n * Reads `skaile.yaml`, scans every declared repository (plus the implicit\n * built-in `factory-assets` repo), and derives implicit refs from `mounts:` /\n * `connectors:` declarations. Does not clone or install anything — purely a\n * read-only scan of what is already on disk. URL-only repositories that have\n * not been cloned yet are reported as `repo_unavailable` warnings.\n *\n * @param projectDir - Absolute path to the project workspace root\n * @returns `RuntimeAssetsResult` with catalog entries, implicit refs, npm deps, and warnings\n * @docLink packages/core/concepts#resolve-runtime-assets\n */\nexport async function resolveRuntimeAssets(projectDir: string): Promise<RuntimeAssetsResult> {\n const result: RuntimeAssetsResult = {\n catalogEntries: [],\n implicitRefs: [],\n requiredNpmDeps: { required: [], optional: [] },\n warnings: [],\n refresh: async () => {\n await populate(projectDir, result);\n },\n findEntry: (query) => findCatalogEntry(result.catalogEntries, query),\n };\n\n await populate(projectDir, result);\n return result;\n}\n\n/**\n * Resolve the ordered list of on-disk roots for the built-in `factory-assets`\n * tree (built-in connectors + first-party skills + bundles). This is the single\n * shared resolver every consumer goes through, so the env override and the\n * bundled baseline are honoured uniformly.\n *\n * Order (env-first = override-wins):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir (legacy: `SKAILE_BASE_ASSETS_DIR`),\n * when set and existing — an additive override layer.\n * 2. {@link resolvePackagedAssetsDir} — the bundled tree (in-repo source in dev,\n * `dist/factory-assets/` after install). Always-present baseline.\n *\n * Returns `[]` only when the package cannot be located at all. De-duplicated, so\n * pointing the env var at the bundled dir collapses to one root.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function factoryAssetRoots(): string[] {\n const roots: string[] = [];\n const envDir = process.env.SKAILE_FACTORY_ASSETS_DIR ?? process.env.SKAILE_BASE_ASSETS_DIR;\n // Deliberately still synchronous after #454: both candidates are\n // container-local (the image's `/app/factory-assets/`, or the installed\n // package tree resolved by `resolvePackagedAssetsDir`), never the FUSE\n // workspace mount. The mount-reachable probes on this module's scan path —\n // the project-relative `sources[].path` candidates in `resolveRepoDir` — are\n // async and deadline-bounded.\n if (envDir && existsSync(envDir)) roots.push(resolvePath(envDir));\n const bundled = resolvePackagedAssetsDir(\"factory-assets\");\n if (bundled) roots.push(bundled);\n return [...new Set(roots)];\n}\n\n/**\n * Resolve the primary on-disk root of the `factory-assets` tree — the first of\n * {@link factoryAssetRoots} (the env override when set, else the bundled tree).\n * Prefer {@link factoryAssetRoots} when you need to scan every layer; this\n * single-dir form is for callers that want one canonical path.\n *\n * @returns Absolute path to the highest-precedence `factory-assets` directory\n * @throws When no root can be located\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolveFactoryAssetsRoot(): string {\n const hit = resolveFactoryAssetsRootOrNull();\n if (hit) return hit;\n\n throw new Error(\n `Cannot resolve the factory-assets directory. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR to the on-disk path, ` +\n `ensure @skaile/workspaces is installed, ` +\n `or run from within the @skaile/workspaces package tree.`,\n );\n}\n\n/**\n * Non-throwing variant of {@link resolveFactoryAssetsRoot}: the same\n * env-then-packaged resolution tiers, returning `null` instead of throwing when\n * none locate the directory. Callers that treat a missing factory tree as a\n * soft \"not present\" (e.g. the asset-manager's implicit-source injection) MUST\n * use this so they honour the `SKAILE_FACTORY_ASSETS_DIR` container override\n * identically to the runtime path.\n */\nexport function resolveFactoryAssetsRootOrNull(): string | null {\n return factoryAssetRoots()[0] ?? null;\n}\n\n/**\n * Resolve the `@skaile/workspaces` package root — the directory containing its\n * `package.json`. Tries `require.resolve` first (works when installed as a\n * dependency *and* in-repo via the self-reference), then walks upward from this\n * module looking for a `package.json` whose `name` is `@skaile/workspaces`\n * (bounded to 8 levels). Returns `null` when neither locates it.\n *\n * The single source of truth for finding content shipped inside the package —\n * the unified `factory-assets/` tree (built-in connectors + first-party skills\n * + bundles) resolves through {@link resolvePackagedAssetsDir} on top of this.\n *\n * Memoized: the package location is immutable for the process lifetime, but\n * this sits on the CLI hot path (every `findSkills` / flow / completion call\n * funnels through here), so the `require.resolve` + upward `package.json` walk\n * runs once. `undefined` = not yet computed.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nlet workspacesPackageRootCache: string | null | undefined;\n\nexport function resolveWorkspacesPackageRoot(): string | null {\n if (workspacesPackageRootCache !== undefined) return workspacesPackageRootCache;\n workspacesPackageRootCache = computeWorkspacesPackageRoot();\n return workspacesPackageRootCache;\n}\n\nfunction computeWorkspacesPackageRoot(): string | null {\n try {\n const require = createRequire(import.meta.url);\n return dirname(require.resolve(\"@skaile/workspaces/package.json\"));\n } catch {\n // Fall through to the workspace walk.\n }\n let dir: string;\n try {\n dir = dirname(fileURLToPath(import.meta.url));\n } catch {\n return null;\n }\n for (let i = 0; i < 8; i++) {\n const pkgPath = join(dir, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n if (pkg.name === \"@skaile/workspaces\") return dir;\n } catch {\n // Ignore malformed package.json and keep walking.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Locate a content-asset directory inside the package. Prefers the in-repo\n * **source** dir `<pkgRoot>/<subdir>` when present — in a dev checkout it is the\n * full tree (e.g. `factory-assets/` keeps the connector `.ts` entry files that\n * `dist/` does not) — then the published `dist/<subdir>` copy (what\n * `files: [\"dist\"]` ships, the only one present after `npm i`). Returns `null`\n * when neither exists.\n *\n * `factory-assets/` resolves to the source tree in dev (code + skills + bundles)\n * and to `dist/factory-assets` post-install (compiled connectors + copied\n * manifests/skills/bundles).\n *\n * @param subdir - `\"factory-assets\"` | …\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolvePackagedAssetsDir(subdir: string): string | null {\n const root = resolveWorkspacesPackageRoot();\n if (!root) return null;\n for (const cand of [join(root, subdir), join(root, \"dist\", subdir)]) {\n if (existsSync(cand)) return cand;\n }\n return null;\n}\n\n// ─── Internals ────────────────────────────────────────────────────────────────\n\nasync function populate(projectDir: string, target: RuntimeAssetsResult): Promise<void> {\n target.catalogEntries = [];\n target.implicitRefs = [];\n target.requiredNpmDeps = { required: [], optional: [] };\n target.warnings = [];\n\n const config = resolveSkWorkspaceConfig(projectDir);\n // Connector catalog scan runs over the project's declared sources[] (resolved\n // to their machine-cache clone paths) plus the implicit factory-assets repo.\n const repositories = buildEffectiveRepositories(sourcesToDeclarations(config.sources));\n const links = readLinks(projectDir);\n\n // Scan each repository for connector entries.\n for (const [name, decl] of Object.entries(repositories)) {\n const repoDir = await resolveRepoDir(name, decl, projectDir, links);\n if (!repoDir) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: repoUnavailableMessage(name, decl),\n });\n continue;\n }\n try {\n // Both factory layers carry the same `factory-assets` provenance — the\n // override repo is an internal scan-order device, not a distinct source.\n const repoName = name === FACTORY_ASSETS_OVERRIDE_REPO_NAME ? FACTORY_ASSETS_REPO_NAME : name;\n const scanned = await scanDirectory(repoDir, repoName);\n const entries = scanned.filter((e) => e.kind === \"connector\");\n target.catalogEntries.push(...entries);\n } catch (err) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: `Failed to scan repository \"${name}\" at ${repoDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n });\n }\n }\n\n // De-duplicate by (kind, name), keeping the first occurrence. Scan order is\n // declared sources → env override → bundled baseline, so an env-supplied\n // connector manifest overrides the bundled one and the bundled one fills the\n // rest (the override layer can refresh built-in manifests in place).\n const seen = new Set<string>();\n target.catalogEntries = target.catalogEntries.filter((e) => {\n const key = `${e.kind}:${e.name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n // Derive implicit refs from skaile.yaml connectors.\n for (const c of config.connectors ?? []) {\n target.implicitRefs.push({ kind: \"connector\", name: c.driver, declarationId: c.id });\n }\n\n // Validate refs and aggregate npm deps.\n const requiredSet = new Set<string>();\n const optionalSet = new Set<string>();\n for (const ref of target.implicitRefs) {\n const entry = findCatalogEntry(target.catalogEntries, ref);\n if (!entry) {\n target.warnings.push({\n code: \"missing_driver\",\n declarationId: ref.declarationId,\n name: ref.name,\n message:\n `Unknown ${ref.kind} driver \"${ref.name}\" referenced by ${ref.kind} \"${ref.declarationId}\". ` +\n `Run \\`skaile ${ref.kind} catalog\\` to see available drivers, ` +\n `or declare a repository in skaile.yaml that provides this driver.`,\n });\n continue;\n }\n const npm = (entry.metadata?.npm_deps ?? {}) as { required?: string[]; optional?: string[] };\n for (const p of npm.required ?? []) requiredSet.add(p);\n for (const p of npm.optional ?? []) optionalSet.add(p);\n }\n target.requiredNpmDeps.required = [...requiredSet];\n target.requiredNpmDeps.optional = [...optionalSet];\n}\n\n/**\n * Build the effective `repositories` map: caller's declarations first, then the\n * implicit built-in `factory-assets` repos. Each {@link factoryAssetRoots} layer\n * becomes its own repo, the env override inserted **before** the bundled\n * baseline so its connector entries win on the first-match dedup downstream.\n * When the package cannot be located at all, a path-less sentinel under\n * {@link FACTORY_ASSETS_REPO_NAME} drives the `repo_unavailable` warning.\n */\nfunction buildEffectiveRepositories(\n declared: Record<string, SourceDeclaration> | undefined,\n): Record<string, SourceDeclaration> {\n const result: Record<string, SourceDeclaration> = { ...(declared ?? {}) };\n const roots = factoryAssetRoots();\n if (roots.length === 0) {\n // Surface as a warning during scan rather than throwing here — let the\n // caller decide whether factory-assets is required. resolveRepoDir() /\n // repoUnavailableMessage re-discover the failure and emit it.\n if (!result[FACTORY_ASSETS_REPO_NAME]) result[FACTORY_ASSETS_REPO_NAME] = { path: \"\" };\n return result;\n }\n // override-first when both layers exist, so the env root's entries are scanned\n // (and matched) ahead of the bundled baseline.\n const keys =\n roots.length > 1\n ? [FACTORY_ASSETS_OVERRIDE_REPO_NAME, FACTORY_ASSETS_REPO_NAME]\n : [FACTORY_ASSETS_REPO_NAME];\n roots.forEach((dir, i) => {\n const key = keys[i] ?? `${FACTORY_ASSETS_REPO_NAME}:${i}`;\n if (!result[key]) result[key] = { path: dir };\n });\n return result;\n}\n\n/**\n * Resolve a repository declaration to an on-disk directory. Order:\n * 1. Linked override (`.skaile/links.yaml`).\n * 2. Local `path` — relative to `projectDir`.\n * 3. Cloned URL repo at `.skaile/cache/sources/<name>/` (must already exist).\n *\n * Returns `null` when none of these resolve. Does not clone.\n *\n * **Async and deadline-bounded since #454.** Every candidate here is a\n * project-relative or operator-supplied path, so a `sources[].path` of\n * `workspace/my-assets` resolves onto the rclone FUSE mount — the same tree the\n * scan that follows walks. Probing it with `existsSync`/`lstatSync` would park\n * the `skaile serve` event loop *before* the (now async) scan ever ran, which\n * would leave the H2 fix meaningless on the very declaration that triggers it.\n * A probe that misses its deadline reads as \"unavailable\", which is what the\n * caller already does with an absent path — it becomes a `repo_unavailable`\n * warning rather than a stall.\n */\nasync function resolveRepoDir(\n name: string,\n decl: SourceDeclaration,\n projectDir: string,\n links: Record<string, string>,\n): Promise<string | null> {\n // 1. Linked override\n const linked = links[name];\n if (linked && (await pathExists(linked))) return linked;\n\n // 2. Local path\n if (decl.path) {\n const resolved = resolvePath(projectDir, decl.path);\n return (await pathExists(resolved)) ? resolved : null;\n }\n\n // 3. URL repo cloned to project's .skaile/cache/sources/<name> — the\n // project-local clone dir (often a symlink into the global cache, which\n // lives at getGlobalCacheDir()); NOT the global clone root itself.\n if (decl.url) {\n const projectDest = join(projectDir, \".skaile\", \"cache\", \"sources\", name);\n // One `lstat` answers both questions the pre-#454 `existsSync` + `lstatSync`\n // pair asked, and `lstat` (not `stat`) keeps the \"a symlink into the global\n // cache counts\" behaviour intact.\n const found = await tryWithFsDeadline(\n `lstat ${projectDest}`,\n async () => {\n await lstat(projectDest);\n return true;\n },\n false,\n );\n return found ? projectDest : null;\n }\n\n return null;\n}\n\n/** Deadline-bounded `existsSync` replacement — a wedged mount reads as absent. */\nfunction pathExists(path: string): Promise<boolean> {\n return tryWithFsDeadline(\n `stat ${path}`,\n async () => {\n await stat(path);\n return true;\n },\n false,\n );\n}\n\nfunction repoUnavailableMessage(name: string, decl: SourceDeclaration): string {\n if (name === FACTORY_ASSETS_REPO_NAME && !decl.path && !decl.url) {\n return (\n `Cannot resolve the built-in factory-assets. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR or ensure @skaile/workspaces is installed.`\n );\n }\n if (decl.url) {\n return `Repository \"${name}\" (${decl.url}) is not available. Register it as a Library Source via \\`skaile source add\\`.`;\n }\n if (decl.path) {\n return `Repository \"${name}\" path not found: ${decl.path}`;\n }\n return `Repository \"${name}\" has neither url nor path.`;\n}\n\nfunction findCatalogEntry(\n entries: RuntimeCatalogEntry[],\n query: { kind?: \"connector\"; name: string },\n): RuntimeCatalogEntry | undefined {\n if (query.kind) {\n return entries.find((e) => e.kind === query.kind && e.name === query.name);\n }\n const matches = entries.filter((e) => e.name === query.name);\n if (matches.length === 1) return matches[0];\n // 0 or >1 with no kind — caller must disambiguate.\n return undefined;\n}\n"]}
1
+ {"version":3,"sources":["../core/src/runtime-assets.ts"],"names":["resolvePath","require"],"mappings":"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","file":"chunk-CGJ7B6MZ.js","sourcesContent":["/**\n * Runtime asset resolution — read `skaile.yaml`, scan all declared repositories\n * (including the built-in `factory-assets/` directory as an implicit default),\n * and produce a unified view of connector catalog entries plus the implicit refs\n * that the `skaile.yaml` `connectors:` section adds to the dependency graph.\n *\n * This module is the single source of truth for \"which connectors does this\n * project see at runtime, and where do their implementations live on disk\".\n * Both the runner (serve, REPL, flow) and the platform's mid-session\n * `add_resource` flow consume `RuntimeAssetsResult.catalogEntries` and pass\n * it into `ConnectorManager` for catalog-based resolution.\n *\n * `factory-assets/` is the single first-party content tree (built-in connectors\n * + first-party skills + bundles) shipped inside the `@skaile/workspaces`\n * package — not a standalone package.\n *\n * It resolves to an **ordered list of roots** ({@link factoryAssetRoots}), not a\n * single dir. The bundled tree is always the baseline; an optional\n * `SKAILE_FACTORY_ASSETS_DIR` (legacy: `SKAILE_BASE_ASSETS_DIR`) is layered\n * **in front** as an additive override source — the agent container points it at\n * `/app/factory-assets/` (or a bind-mounted host dir) to ship updated skills /\n * flows / bundles / connector manifests without rebuilding the image. The two\n * roots resolve uniformly across every consumer (connector catalog scan, skill /\n * flow / completion discovery, the asset-manager factory source):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir, when set and existing (override layer).\n * 2. the bundled tree via {@link resolvePackagedAssetsDir} — the in-repo source\n * `packages/workspaces/factory-assets/` during dev, else the published\n * `dist/factory-assets/` after install (always-present baseline).\n *\n * Override semantics are **env-first**: on a name conflict the env root wins and\n * the bundled root fills the rest. Connector *code* still loads via the package's\n * static `exports` map, so the env root can override/add skills, flows, bundles,\n * and connector **manifests/metadata**, but cannot ship a new executable\n * connector — its `.js` is not on the package's import graph.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { lstat, stat } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport { dirname, join, resolve as resolvePath } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { tryWithFsDeadline } from \"./fs-deadline.js\";\nimport { scanDirectory } from \"./manifest.js\";\nimport type { CatalogEntry } from \"./models.js\";\nimport { getGlobalCacheDir, readLinks, sourceCacheKey } from \"./repo-manager.js\";\nimport type { SourceDeclaration, SourceEntry } from \"./workspace-config.js\";\nimport { resolveSkWorkspaceConfig } from \"./workspace-config.js\";\n\n/**\n * Map declared `sources[]` to internal `SourceDeclaration`s keyed by the\n * collision-free {@link sourceCacheKey} (`<host>/<owner>/<repo>`), pointing at\n * the unified machine-cache clone path (`getGlobalCacheDir()/<key>/`). Keyed by\n * the same function every other cache writer/reader uses so the path resolves.\n */\nfunction sourcesToDeclarations(\n sources: SourceEntry[] | undefined,\n): Record<string, SourceDeclaration> {\n const sourcesDir = getGlobalCacheDir();\n const out: Record<string, SourceDeclaration> = {};\n for (const s of sources ?? []) {\n const key = sourceCacheKey(s.url);\n if (out[key]) continue;\n out[key] = { path: join(sourcesDir, key), url: s.url, branch: s.pin };\n }\n return out;\n}\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\n/**\n * Catalog entry filtered to mount/connector kinds. Same shape as `CatalogEntry`.\n * @docLink packages/core/concepts#runtime-catalog-entry\n */\nexport type RuntimeCatalogEntry = CatalogEntry;\n\n/**\n * Implicit catalog reference derived from a `connectors:` declaration in `skaile.yaml`.\n * Each connector driver becomes an implicit ref that must be resolved in the catalog.\n * @docLink packages/core/concepts#runtime-asset-ref\n */\nexport interface RuntimeAssetRef {\n kind: \"connector\";\n /** Driver name — matches `RuntimeCatalogEntry.name`. */\n name: string;\n /** Source declaration id from `skaile.yaml`. */\n declarationId: string;\n}\n\n/**\n * Aggregated npm packages required by all resolved mount/connector adapters.\n * Populated from `metadata.npm_deps` in each matched catalog entry.\n * @docLink packages/core/concepts#runtime-npm-deps\n */\nexport interface RuntimeNpmDeps {\n required: string[];\n optional: string[];\n}\n\n/**\n * Non-fatal warning emitted during `resolveRuntimeAssets` when a repo is unavailable\n * or a driver is not found in any catalog.\n * @docLink packages/core/concepts#runtime-asset-warning\n */\nexport interface RuntimeAssetWarning {\n /** Stable code for filtering / structured logging. */\n code: \"missing_driver\" | \"repo_unavailable\" | \"invalid_repo_decl\";\n message: string;\n /** Declaration id when applicable. */\n declarationId?: string;\n /** Driver / repository name when applicable. */\n name?: string;\n}\n\n/**\n * Repository name used for the implicit built-in `factory-assets` catalog entry\n * (the in-package connector tree).\n * @docLink packages/core/concepts#factory-assets-repo-name\n */\nexport const FACTORY_ASSETS_REPO_NAME = \"factory-assets\";\n\n/**\n * Repository name for the optional `SKAILE_FACTORY_ASSETS_DIR` override layer,\n * scanned ahead of (and overriding) the bundled {@link FACTORY_ASSETS_REPO_NAME}.\n */\nconst FACTORY_ASSETS_OVERRIDE_REPO_NAME = \"factory-assets:override\";\n\n/**\n * Result of `resolveRuntimeAssets`.\n * The same object is mutated in place by `refresh()`, allowing callers to hold\n * a stable reference and observe updates after a new repository is cloned or\n * a driver is installed mid-session.\n * @docLink packages/core/concepts#runtime-assets-result\n */\nexport interface RuntimeAssetsResult {\n catalogEntries: RuntimeCatalogEntry[];\n implicitRefs: RuntimeAssetRef[];\n requiredNpmDeps: RuntimeNpmDeps;\n warnings: RuntimeAssetWarning[];\n /** Re-scan repositories and re-derive implicit refs. Mutates in place. */\n refresh(): Promise<void>;\n /**\n * Catalog lookup. When `kind` is omitted and multiple entries share the\n * `name`, returns `undefined` (caller must disambiguate).\n */\n findEntry(query: { kind?: \"connector\"; name: string }): RuntimeCatalogEntry | undefined;\n}\n\n// ─── Public API ───────────────────────────────────────────────────────────────\n\n/**\n * Resolve all runtime assets visible to a project by scanning declared repositories.\n *\n * Reads `skaile.yaml`, scans every declared repository (plus the implicit\n * built-in `factory-assets` repo), and derives implicit refs from `mounts:` /\n * `connectors:` declarations. Does not clone or install anything — purely a\n * read-only scan of what is already on disk. URL-only repositories that have\n * not been cloned yet are reported as `repo_unavailable` warnings.\n *\n * @param projectDir - Absolute path to the project workspace root\n * @returns `RuntimeAssetsResult` with catalog entries, implicit refs, npm deps, and warnings\n * @docLink packages/core/concepts#resolve-runtime-assets\n */\nexport async function resolveRuntimeAssets(projectDir: string): Promise<RuntimeAssetsResult> {\n const result: RuntimeAssetsResult = {\n catalogEntries: [],\n implicitRefs: [],\n requiredNpmDeps: { required: [], optional: [] },\n warnings: [],\n refresh: async () => {\n await populate(projectDir, result);\n },\n findEntry: (query) => findCatalogEntry(result.catalogEntries, query),\n };\n\n await populate(projectDir, result);\n return result;\n}\n\n/**\n * Resolve the ordered list of on-disk roots for the built-in `factory-assets`\n * tree (built-in connectors + first-party skills + bundles). This is the single\n * shared resolver every consumer goes through, so the env override and the\n * bundled baseline are honoured uniformly.\n *\n * Order (env-first = override-wins):\n * 1. `SKAILE_FACTORY_ASSETS_DIR` env dir (legacy: `SKAILE_BASE_ASSETS_DIR`),\n * when set and existing — an additive override layer.\n * 2. {@link resolvePackagedAssetsDir} — the bundled tree (in-repo source in dev,\n * `dist/factory-assets/` after install). Always-present baseline.\n *\n * Returns `[]` only when the package cannot be located at all. De-duplicated, so\n * pointing the env var at the bundled dir collapses to one root.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function factoryAssetRoots(): string[] {\n const roots: string[] = [];\n const envDir = process.env.SKAILE_FACTORY_ASSETS_DIR ?? process.env.SKAILE_BASE_ASSETS_DIR;\n // Deliberately still synchronous after #454: both candidates are\n // container-local (the image's `/app/factory-assets/`, or the installed\n // package tree resolved by `resolvePackagedAssetsDir`), never the FUSE\n // workspace mount. The mount-reachable probes on this module's scan path —\n // the project-relative `sources[].path` candidates in `resolveRepoDir` — are\n // async and deadline-bounded.\n if (envDir && existsSync(envDir)) roots.push(resolvePath(envDir));\n const bundled = resolvePackagedAssetsDir(\"factory-assets\");\n if (bundled) roots.push(bundled);\n return [...new Set(roots)];\n}\n\n/**\n * Resolve the primary on-disk root of the `factory-assets` tree — the first of\n * {@link factoryAssetRoots} (the env override when set, else the bundled tree).\n * Prefer {@link factoryAssetRoots} when you need to scan every layer; this\n * single-dir form is for callers that want one canonical path.\n *\n * @returns Absolute path to the highest-precedence `factory-assets` directory\n * @throws When no root can be located\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolveFactoryAssetsRoot(): string {\n const hit = resolveFactoryAssetsRootOrNull();\n if (hit) return hit;\n\n throw new Error(\n `Cannot resolve the factory-assets directory. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR to the on-disk path, ` +\n `ensure @skaile/workspaces is installed, ` +\n `or run from within the @skaile/workspaces package tree.`,\n );\n}\n\n/**\n * Non-throwing variant of {@link resolveFactoryAssetsRoot}: the same\n * env-then-packaged resolution tiers, returning `null` instead of throwing when\n * none locate the directory. Callers that treat a missing factory tree as a\n * soft \"not present\" (e.g. the asset-manager's implicit-source injection) MUST\n * use this so they honour the `SKAILE_FACTORY_ASSETS_DIR` container override\n * identically to the runtime path.\n */\nexport function resolveFactoryAssetsRootOrNull(): string | null {\n return factoryAssetRoots()[0] ?? null;\n}\n\n/**\n * Resolve the `@skaile/workspaces` package root — the directory containing its\n * `package.json`. Tries `require.resolve` first (works when installed as a\n * dependency *and* in-repo via the self-reference), then walks upward from this\n * module looking for a `package.json` whose `name` is `@skaile/workspaces`\n * (bounded to 8 levels). Returns `null` when neither locates it.\n *\n * The single source of truth for finding content shipped inside the package —\n * the unified `factory-assets/` tree (built-in connectors + first-party skills\n * + bundles) resolves through {@link resolvePackagedAssetsDir} on top of this.\n *\n * Memoized: the package location is immutable for the process lifetime, but\n * this sits on the CLI hot path (every `findSkills` / flow / completion call\n * funnels through here), so the `require.resolve` + upward `package.json` walk\n * runs once. `undefined` = not yet computed.\n *\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nlet workspacesPackageRootCache: string | null | undefined;\n\nexport function resolveWorkspacesPackageRoot(): string | null {\n if (workspacesPackageRootCache !== undefined) return workspacesPackageRootCache;\n workspacesPackageRootCache = computeWorkspacesPackageRoot();\n return workspacesPackageRootCache;\n}\n\nfunction computeWorkspacesPackageRoot(): string | null {\n try {\n const require = createRequire(import.meta.url);\n return dirname(require.resolve(\"@skaile/workspaces/package.json\"));\n } catch {\n // Fall through to the workspace walk.\n }\n let dir: string;\n try {\n dir = dirname(fileURLToPath(import.meta.url));\n } catch {\n return null;\n }\n for (let i = 0; i < 8; i++) {\n const pkgPath = join(dir, \"package.json\");\n if (existsSync(pkgPath)) {\n try {\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\")) as { name?: string };\n if (pkg.name === \"@skaile/workspaces\") return dir;\n } catch {\n // Ignore malformed package.json and keep walking.\n }\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Locate a content-asset directory inside the package. Prefers the in-repo\n * **source** dir `<pkgRoot>/<subdir>` when present — in a dev checkout it is the\n * full tree (e.g. `factory-assets/` keeps the connector `.ts` entry files that\n * `dist/` does not) — then the published `dist/<subdir>` copy (what\n * `files: [\"dist\"]` ships, the only one present after `npm i`). Returns `null`\n * when neither exists.\n *\n * `factory-assets/` resolves to the source tree in dev (code + skills + bundles)\n * and to `dist/factory-assets` post-install (compiled connectors + copied\n * manifests/skills/bundles).\n *\n * @param subdir - `\"factory-assets\"` | …\n * @docLink packages/core/concepts#resolve-factory-assets-root\n */\nexport function resolvePackagedAssetsDir(subdir: string): string | null {\n const root = resolveWorkspacesPackageRoot();\n if (!root) return null;\n for (const cand of [join(root, subdir), join(root, \"dist\", subdir)]) {\n if (existsSync(cand)) return cand;\n }\n return null;\n}\n\n// ─── Internals ────────────────────────────────────────────────────────────────\n\nasync function populate(projectDir: string, target: RuntimeAssetsResult): Promise<void> {\n target.catalogEntries = [];\n target.implicitRefs = [];\n target.requiredNpmDeps = { required: [], optional: [] };\n target.warnings = [];\n\n const config = resolveSkWorkspaceConfig(projectDir);\n // Connector catalog scan runs over the project's declared sources[] (resolved\n // to their machine-cache clone paths) plus the implicit factory-assets repo.\n const repositories = buildEffectiveRepositories(sourcesToDeclarations(config.sources));\n const links = readLinks(projectDir);\n\n // Scan each repository for connector entries.\n for (const [name, decl] of Object.entries(repositories)) {\n const repoDir = await resolveRepoDir(name, decl, projectDir, links);\n if (!repoDir) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: repoUnavailableMessage(name, decl),\n });\n continue;\n }\n try {\n // Both factory layers carry the same `factory-assets` provenance — the\n // override repo is an internal scan-order device, not a distinct source.\n const repoName = name === FACTORY_ASSETS_OVERRIDE_REPO_NAME ? FACTORY_ASSETS_REPO_NAME : name;\n const scanned = await scanDirectory(repoDir, repoName);\n const entries = scanned.filter((e) => e.kind === \"connector\");\n target.catalogEntries.push(...entries);\n } catch (err) {\n target.warnings.push({\n code: \"repo_unavailable\",\n name,\n message: `Failed to scan repository \"${name}\" at ${repoDir}: ${\n err instanceof Error ? err.message : String(err)\n }`,\n });\n }\n }\n\n // De-duplicate by (kind, name), keeping the first occurrence. Scan order is\n // declared sources → env override → bundled baseline, so an env-supplied\n // connector manifest overrides the bundled one and the bundled one fills the\n // rest (the override layer can refresh built-in manifests in place).\n const seen = new Set<string>();\n target.catalogEntries = target.catalogEntries.filter((e) => {\n const key = `${e.kind}:${e.name}`;\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n\n // Derive implicit refs from skaile.yaml connectors.\n for (const c of config.connectors ?? []) {\n target.implicitRefs.push({ kind: \"connector\", name: c.driver, declarationId: c.id });\n }\n\n // Validate refs and aggregate npm deps.\n const requiredSet = new Set<string>();\n const optionalSet = new Set<string>();\n for (const ref of target.implicitRefs) {\n const entry = findCatalogEntry(target.catalogEntries, ref);\n if (!entry) {\n target.warnings.push({\n code: \"missing_driver\",\n declarationId: ref.declarationId,\n name: ref.name,\n message:\n `Unknown ${ref.kind} driver \"${ref.name}\" referenced by ${ref.kind} \"${ref.declarationId}\". ` +\n `Run \\`skaile ${ref.kind} catalog\\` to see available drivers, ` +\n `or declare a repository in skaile.yaml that provides this driver.`,\n });\n continue;\n }\n const npm = (entry.metadata?.npm_deps ?? {}) as { required?: string[]; optional?: string[] };\n for (const p of npm.required ?? []) requiredSet.add(p);\n for (const p of npm.optional ?? []) optionalSet.add(p);\n }\n target.requiredNpmDeps.required = [...requiredSet];\n target.requiredNpmDeps.optional = [...optionalSet];\n}\n\n/**\n * Build the effective `repositories` map: caller's declarations first, then the\n * implicit built-in `factory-assets` repos. Each {@link factoryAssetRoots} layer\n * becomes its own repo, the env override inserted **before** the bundled\n * baseline so its connector entries win on the first-match dedup downstream.\n * When the package cannot be located at all, a path-less sentinel under\n * {@link FACTORY_ASSETS_REPO_NAME} drives the `repo_unavailable` warning.\n */\nfunction buildEffectiveRepositories(\n declared: Record<string, SourceDeclaration> | undefined,\n): Record<string, SourceDeclaration> {\n const result: Record<string, SourceDeclaration> = { ...(declared ?? {}) };\n const roots = factoryAssetRoots();\n if (roots.length === 0) {\n // Surface as a warning during scan rather than throwing here — let the\n // caller decide whether factory-assets is required. resolveRepoDir() /\n // repoUnavailableMessage re-discover the failure and emit it.\n if (!result[FACTORY_ASSETS_REPO_NAME]) result[FACTORY_ASSETS_REPO_NAME] = { path: \"\" };\n return result;\n }\n // override-first when both layers exist, so the env root's entries are scanned\n // (and matched) ahead of the bundled baseline.\n const keys =\n roots.length > 1\n ? [FACTORY_ASSETS_OVERRIDE_REPO_NAME, FACTORY_ASSETS_REPO_NAME]\n : [FACTORY_ASSETS_REPO_NAME];\n roots.forEach((dir, i) => {\n const key = keys[i] ?? `${FACTORY_ASSETS_REPO_NAME}:${i}`;\n if (!result[key]) result[key] = { path: dir };\n });\n return result;\n}\n\n/**\n * Resolve a repository declaration to an on-disk directory. Order:\n * 1. Linked override (`.skaile/links.yaml`).\n * 2. Local `path` — relative to `projectDir`.\n * 3. Cloned URL repo at `.skaile/cache/sources/<name>/` (must already exist).\n *\n * Returns `null` when none of these resolve. Does not clone.\n *\n * **Async and deadline-bounded since #454.** Every candidate here is a\n * project-relative or operator-supplied path, so a `sources[].path` of\n * `workspace/my-assets` resolves onto the rclone FUSE mount — the same tree the\n * scan that follows walks. Probing it with `existsSync`/`lstatSync` would park\n * the `skaile serve` event loop *before* the (now async) scan ever ran, which\n * would leave the H2 fix meaningless on the very declaration that triggers it.\n * A probe that misses its deadline reads as \"unavailable\", which is what the\n * caller already does with an absent path — it becomes a `repo_unavailable`\n * warning rather than a stall.\n */\nasync function resolveRepoDir(\n name: string,\n decl: SourceDeclaration,\n projectDir: string,\n links: Record<string, string>,\n): Promise<string | null> {\n // 1. Linked override\n const linked = links[name];\n if (linked && (await pathExists(linked))) return linked;\n\n // 2. Local path\n if (decl.path) {\n const resolved = resolvePath(projectDir, decl.path);\n return (await pathExists(resolved)) ? resolved : null;\n }\n\n // 3. URL repo cloned to project's .skaile/cache/sources/<name> — the\n // project-local clone dir (often a symlink into the global cache, which\n // lives at getGlobalCacheDir()); NOT the global clone root itself.\n if (decl.url) {\n const projectDest = join(projectDir, \".skaile\", \"cache\", \"sources\", name);\n // One `lstat` answers both questions the pre-#454 `existsSync` + `lstatSync`\n // pair asked, and `lstat` (not `stat`) keeps the \"a symlink into the global\n // cache counts\" behaviour intact.\n const found = await tryWithFsDeadline(\n `lstat ${projectDest}`,\n async () => {\n await lstat(projectDest);\n return true;\n },\n false,\n );\n return found ? projectDest : null;\n }\n\n return null;\n}\n\n/** Deadline-bounded `existsSync` replacement — a wedged mount reads as absent. */\nfunction pathExists(path: string): Promise<boolean> {\n return tryWithFsDeadline(\n `stat ${path}`,\n async () => {\n await stat(path);\n return true;\n },\n false,\n );\n}\n\nfunction repoUnavailableMessage(name: string, decl: SourceDeclaration): string {\n if (name === FACTORY_ASSETS_REPO_NAME && !decl.path && !decl.url) {\n return (\n `Cannot resolve the built-in factory-assets. ` +\n `Set SKAILE_FACTORY_ASSETS_DIR or ensure @skaile/workspaces is installed.`\n );\n }\n if (decl.url) {\n return `Repository \"${name}\" (${decl.url}) is not available. Register it as a Library Source via \\`skaile source add\\`.`;\n }\n if (decl.path) {\n return `Repository \"${name}\" path not found: ${decl.path}`;\n }\n return `Repository \"${name}\" has neither url nor path.`;\n}\n\nfunction findCatalogEntry(\n entries: RuntimeCatalogEntry[],\n query: { kind?: \"connector\"; name: string },\n): RuntimeCatalogEntry | undefined {\n if (query.kind) {\n return entries.find((e) => e.kind === query.kind && e.name === query.name);\n }\n const matches = entries.filter((e) => e.name === query.name);\n if (matches.length === 1) return matches[0];\n // 0 or >1 with no kind — caller must disambiguate.\n return undefined;\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { FlowDefinitionSchema } from './chunk-ORH2BZEM.js';
1
+ import { FlowDefinitionSchema } from './chunk-QCI6D7E4.js';
2
2
  import * as z from 'zod';
3
3
 
4
4
  // factory-assets/connectors/flow/contract/hash.ts
@@ -85,5 +85,5 @@ function generateFlowDefinitionJsonSchema() {
85
85
  }
86
86
 
87
87
  export { FLOW_DEFINITION_JSON_SCHEMA_ID, canonicalizeFlowDefinition, generateFlowDefinitionJsonSchema, hashFlowDefinition };
88
- //# sourceMappingURL=chunk-6X4DHKHP.js.map
89
- //# sourceMappingURL=chunk-6X4DHKHP.js.map
88
+ //# sourceMappingURL=chunk-CT6NQSA4.js.map
89
+ //# sourceMappingURL=chunk-CT6NQSA4.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../factory-assets/connectors/flow/contract/hash.ts","../factory-assets/connectors/flow/contract/json-schema.ts"],"names":[],"mappings":"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","file":"chunk-6X4DHKHP.js","sourcesContent":["import type { ParsedFlowDefinition } from \"./normalize.js\";\n\nfunction semanticHashInput(definition: ParsedFlowDefinition): ParsedFlowDefinition {\n const defaults = definition.defaults ? { ...definition.defaults } : undefined;\n if (defaults?.parameters && Object.keys(defaults.parameters).length === 0) {\n delete defaults.parameters;\n }\n\n const meta = definition.meta ? { ...definition.meta } : undefined;\n if (meta?.tags?.length === 0) delete meta.tags;\n\n const normalized: ParsedFlowDefinition = {\n ...definition,\n nodes: definition.nodes.map((node) => {\n const run: Record<string, unknown> = { ...node.run };\n if (node.run.assets) {\n const assets = [...new Set(node.run.assets)].sort();\n if (assets.length > 0) run.assets = assets;\n else delete run.assets;\n }\n if (\n \"capture\" in node.run &&\n node.run.capture !== undefined &&\n Object.keys(node.run.capture).length === 0\n ) {\n delete run.capture;\n }\n // \"default\" inherits rather than naming a model, so it is the no-op value for\n // this field on the kinds where that semantics is defined — strip it like the\n // other default-valued control fields below. Kind-scoped so a future run kind\n // whose \"default\" is not a no-op is never silently stripped from identity.\n if (\n (node.run.kind === \"agent\" || node.run.kind === \"subprompt\") &&\n \"model\" in node.run &&\n node.run.model === \"default\"\n ) {\n delete run.model;\n }\n\n const control = node.control ? { ...node.control } : undefined;\n if (control?.optional === false) delete control.optional;\n if (control?.retries === 0) delete control.retries;\n\n const contract = node.contract ? { ...node.contract } : undefined;\n if (contract?.requires?.length === 0) delete contract.requires;\n if (contract?.input && Object.keys(contract.input).length === 0) delete contract.input;\n if (contract?.output) {\n const output = { ...contract.output };\n if (output.artifacts?.length === 0) delete output.artifacts;\n contract.output = Object.keys(output).length > 0 ? output : undefined;\n }\n\n const normalizedNode: Record<string, unknown> = { ...node, run };\n if (control && Object.keys(control).length > 0) normalizedNode.control = control;\n else delete normalizedNode.control;\n if (contract && Object.values(contract).some((value) => value !== undefined)) {\n normalizedNode.contract = contract;\n } else {\n delete normalizedNode.contract;\n }\n if (node.gate?.approval === \"none\") delete normalizedNode.gate;\n return normalizedNode as ParsedFlowDefinition[\"nodes\"][number];\n }),\n };\n normalized.defaults = defaults && Object.keys(defaults).length > 0 ? defaults : undefined;\n normalized.meta = meta && Object.keys(meta).length > 0 ? meta : undefined;\n return normalized;\n}\n\nfunction canonicalize(value: unknown): string | undefined {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n return `[${value.map((item) => canonicalize(item) ?? \"null\").join(\",\")}]`;\n }\n const object = value as Record<string, unknown>;\n const entries: string[] = [];\n for (const key of Object.keys(object).sort()) {\n const serialized = canonicalize(object[key]);\n if (serialized !== undefined) entries.push(`${JSON.stringify(key)}:${serialized}`);\n }\n return `{${entries.join(\",\")}}`;\n}\n\n/** Gives equivalent definitions identical bytes while preserving content-significant array order. */\nexport function canonicalizeFlowDefinition(definition: ParsedFlowDefinition): string {\n return canonicalize(semanticHashInput(definition)) ?? \"null\";\n}\n\n/** Creates a browser-safe content identity for caching, pinning, and change detection. */\nexport async function hashFlowDefinition(definition: ParsedFlowDefinition): Promise<string> {\n const bytes = new TextEncoder().encode(canonicalizeFlowDefinition(definition));\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","import * as z from \"zod\";\nimport { FlowDefinitionSchema } from \"./schema.js\";\n\n/** Canonical URI editors can use to identify the published Flow v2 vocabulary. */\nexport const FLOW_DEFINITION_JSON_SCHEMA_ID = \"https://skaile.ai/schemas/flow/v2.json\";\n\n/** Keeps editor tooling downstream of Zod so the checked-in artifact cannot become an authority. */\nexport function generateFlowDefinitionJsonSchema(): z.core.JSONSchema.JSONSchema {\n return {\n $id: FLOW_DEFINITION_JSON_SCHEMA_ID,\n ...z.toJSONSchema(FlowDefinitionSchema, {\n target: \"draft-2020-12\",\n io: \"input\",\n reused: \"inline\",\n }),\n };\n}\n"]}
1
+ {"version":3,"sources":["../factory-assets/connectors/flow/contract/hash.ts","../factory-assets/connectors/flow/contract/json-schema.ts"],"names":[],"mappings":";;;;AAEA,SAAS,kBAAkB,UAAA,EAAwD;AACjF,EAAA,MAAM,WAAW,UAAA,CAAW,QAAA,GAAW,EAAE,GAAG,UAAA,CAAW,UAAS,GAAI,MAAA;AACpE,EAAA,IAAI,QAAA,EAAU,cAAc,MAAA,CAAO,IAAA,CAAK,SAAS,UAAU,CAAA,CAAE,WAAW,CAAA,EAAG;AACzE,IAAA,OAAO,QAAA,CAAS,UAAA;AAAA,EAClB;AAEA,EAAA,MAAM,OAAO,UAAA,CAAW,IAAA,GAAO,EAAE,GAAG,UAAA,CAAW,MAAK,GAAI,MAAA;AACxD,EAAA,IAAI,IAAA,EAAM,IAAA,EAAM,MAAA,KAAW,CAAA,SAAU,IAAA,CAAK,IAAA;AAE1C,EAAA,MAAM,UAAA,GAAmC;AAAA,IACvC,GAAG,UAAA;AAAA,IACH,KAAA,EAAO,UAAA,CAAW,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS;AACpC,MAAA,MAAM,GAAA,GAA+B,EAAE,GAAG,IAAA,CAAK,GAAA,EAAI;AACnD,MAAA,IAAI,IAAA,CAAK,IAAI,MAAA,EAAQ;AACnB,QAAA,MAAM,MAAA,GAAS,CAAC,GAAG,IAAI,GAAA,CAAI,KAAK,GAAA,CAAI,MAAM,CAAC,CAAA,CAAE,IAAA,EAAK;AAClD,QAAA,IAAI,MAAA,CAAO,MAAA,GAAS,CAAA,EAAG,GAAA,CAAI,MAAA,GAAS,MAAA;AAAA,oBACxB,GAAA,CAAI,MAAA;AAAA,MAClB;AACA,MAAA,IACE,SAAA,IAAa,IAAA,CAAK,GAAA,IAClB,IAAA,CAAK,IAAI,OAAA,KAAY,MAAA,IACrB,MAAA,CAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,OAAO,CAAA,CAAE,WAAW,CAAA,EACzC;AACA,QAAA,OAAO,GAAA,CAAI,OAAA;AAAA,MACb;AAKA,MAAA,IAAA,CACG,IAAA,CAAK,GAAA,CAAI,IAAA,KAAS,OAAA,IAAW,KAAK,GAAA,CAAI,IAAA,KAAS,WAAA,KAChD,OAAA,IAAW,IAAA,CAAK,GAAA,IAChB,IAAA,CAAK,GAAA,CAAI,UAAU,SAAA,EACnB;AACA,QAAA,OAAO,GAAA,CAAI,KAAA;AAAA,MACb;AAEA,MAAA,MAAM,UAAU,IAAA,CAAK,OAAA,GAAU,EAAE,GAAG,IAAA,CAAK,SAAQ,GAAI,MAAA;AACrD,MAAA,IAAI,OAAA,EAAS,QAAA,KAAa,KAAA,EAAO,OAAO,OAAA,CAAQ,QAAA;AAChD,MAAA,IAAI,OAAA,EAAS,OAAA,KAAY,CAAA,EAAG,OAAO,OAAA,CAAQ,OAAA;AAE3C,MAAA,MAAM,WAAW,IAAA,CAAK,QAAA,GAAW,EAAE,GAAG,IAAA,CAAK,UAAS,GAAI,MAAA;AACxD,MAAA,IAAI,QAAA,EAAU,QAAA,EAAU,MAAA,KAAW,CAAA,SAAU,QAAA,CAAS,QAAA;AACtD,MAAA,IAAI,QAAA,EAAU,KAAA,IAAS,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS,KAAK,CAAA,CAAE,MAAA,KAAW,CAAA,EAAG,OAAO,QAAA,CAAS,KAAA;AACjF,MAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,QAAA,MAAM,MAAA,GAAS,EAAE,GAAG,QAAA,CAAS,MAAA,EAAO;AACpC,QAAA,IAAI,MAAA,CAAO,SAAA,EAAW,MAAA,KAAW,CAAA,SAAU,MAAA,CAAO,SAAA;AAClD,QAAA,QAAA,CAAS,SAAS,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAA,GAAS,IAAI,MAAA,GAAS,MAAA;AAAA,MAC9D;AAEA,MAAA,MAAM,cAAA,GAA0C,EAAE,GAAG,IAAA,EAAM,GAAA,EAAI;AAC/D,MAAA,IAAI,OAAA,IAAW,OAAO,IAAA,CAAK,OAAO,EAAE,MAAA,GAAS,CAAA,iBAAkB,OAAA,GAAU,OAAA;AAAA,kBAC7D,cAAA,CAAe,OAAA;AAC3B,MAAA,IAAI,QAAA,IAAY,MAAA,CAAO,MAAA,CAAO,QAAQ,CAAA,CAAE,KAAK,CAAC,KAAA,KAAU,KAAA,KAAU,MAAS,CAAA,EAAG;AAC5E,QAAA,cAAA,CAAe,QAAA,GAAW,QAAA;AAAA,MAC5B,CAAA,MAAO;AACL,QAAA,OAAO,cAAA,CAAe,QAAA;AAAA,MACxB;AACA,MAAA,IAAI,IAAA,CAAK,IAAA,EAAM,QAAA,KAAa,MAAA,SAAe,cAAA,CAAe,IAAA;AAC1D,MAAA,OAAO,cAAA;AAAA,IACT,CAAC;AAAA,GACH;AACA,EAAA,UAAA,CAAW,QAAA,GAAW,YAAY,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,GAAS,IAAI,QAAA,GAAW,MAAA;AAChF,EAAA,UAAA,CAAW,IAAA,GAAO,QAAQ,MAAA,CAAO,IAAA,CAAK,IAAI,CAAA,CAAE,MAAA,GAAS,IAAI,IAAA,GAAO,MAAA;AAChE,EAAA,OAAO,UAAA;AACT;AAEA,SAAS,aAAa,KAAA,EAAoC;AACxD,EAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC5E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,CAAA,CAAA,EAAI,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,YAAA,CAAa,IAAI,CAAA,IAAK,MAAM,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,EACxE;AACA,EAAA,MAAM,MAAA,GAAS,KAAA;AACf,EAAA,MAAM,UAAoB,EAAC;AAC3B,EAAA,KAAA,MAAW,OAAO,MAAA,CAAO,IAAA,CAAK,MAAM,CAAA,CAAE,MAAK,EAAG;AAC5C,IAAA,MAAM,UAAA,GAAa,YAAA,CAAa,MAAA,CAAO,GAAG,CAAC,CAAA;AAC3C,IAAA,IAAI,UAAA,KAAe,MAAA,EAAW,OAAA,CAAQ,IAAA,CAAK,CAAA,EAAG,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA,EAAI,UAAU,CAAA,CAAE,CAAA;AAAA,EACnF;AACA,EAAA,OAAO,CAAA,CAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAC9B;AAGO,SAAS,2BAA2B,UAAA,EAA0C;AACnF,EAAA,OAAO,YAAA,CAAa,iBAAA,CAAkB,UAAU,CAAC,CAAA,IAAK,MAAA;AACxD;AAGA,eAAsB,mBAAmB,UAAA,EAAmD;AAC1F,EAAA,MAAM,QAAQ,IAAI,WAAA,GAAc,MAAA,CAAO,0BAAA,CAA2B,UAAU,CAAC,CAAA;AAC7E,EAAA,MAAM,SAAS,MAAM,UAAA,CAAW,OAAO,MAAA,CAAO,MAAA,CAAO,WAAW,KAAK,CAAA;AACrE,EAAA,OAAO,MAAM,IAAA,CAAK,IAAI,WAAW,MAAM,CAAA,EAAG,CAAC,IAAA,KAAS,IAAA,CAAK,QAAA,CAAS,EAAE,EAAE,QAAA,CAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AACjG;ACzFO,IAAM,8BAAA,GAAiC;AAGvC,SAAS,gCAAA,GAAiE;AAC/E,EAAA,OAAO;AAAA,IACL,GAAA,EAAK,8BAAA;AAAA,IACL,GAAK,eAAa,oBAAA,EAAsB;AAAA,MACtC,MAAA,EAAQ,eAAA;AAAA,MACR,EAAA,EAAI,OAAA;AAAA,MACJ,MAAA,EAAQ;AAAA,KACT;AAAA,GACH;AACF","file":"chunk-CT6NQSA4.js","sourcesContent":["import type { ParsedFlowDefinition } from \"./normalize.js\";\n\nfunction semanticHashInput(definition: ParsedFlowDefinition): ParsedFlowDefinition {\n const defaults = definition.defaults ? { ...definition.defaults } : undefined;\n if (defaults?.parameters && Object.keys(defaults.parameters).length === 0) {\n delete defaults.parameters;\n }\n\n const meta = definition.meta ? { ...definition.meta } : undefined;\n if (meta?.tags?.length === 0) delete meta.tags;\n\n const normalized: ParsedFlowDefinition = {\n ...definition,\n nodes: definition.nodes.map((node) => {\n const run: Record<string, unknown> = { ...node.run };\n if (node.run.assets) {\n const assets = [...new Set(node.run.assets)].sort();\n if (assets.length > 0) run.assets = assets;\n else delete run.assets;\n }\n if (\n \"capture\" in node.run &&\n node.run.capture !== undefined &&\n Object.keys(node.run.capture).length === 0\n ) {\n delete run.capture;\n }\n // \"default\" inherits rather than naming a model, so it is the no-op value for\n // this field on the kinds where that semantics is defined — strip it like the\n // other default-valued control fields below. Kind-scoped so a future run kind\n // whose \"default\" is not a no-op is never silently stripped from identity.\n if (\n (node.run.kind === \"agent\" || node.run.kind === \"subprompt\") &&\n \"model\" in node.run &&\n node.run.model === \"default\"\n ) {\n delete run.model;\n }\n\n const control = node.control ? { ...node.control } : undefined;\n if (control?.optional === false) delete control.optional;\n if (control?.retries === 0) delete control.retries;\n\n const contract = node.contract ? { ...node.contract } : undefined;\n if (contract?.requires?.length === 0) delete contract.requires;\n if (contract?.input && Object.keys(contract.input).length === 0) delete contract.input;\n if (contract?.output) {\n const output = { ...contract.output };\n if (output.artifacts?.length === 0) delete output.artifacts;\n contract.output = Object.keys(output).length > 0 ? output : undefined;\n }\n\n const normalizedNode: Record<string, unknown> = { ...node, run };\n if (control && Object.keys(control).length > 0) normalizedNode.control = control;\n else delete normalizedNode.control;\n if (contract && Object.values(contract).some((value) => value !== undefined)) {\n normalizedNode.contract = contract;\n } else {\n delete normalizedNode.contract;\n }\n if (node.gate?.approval === \"none\") delete normalizedNode.gate;\n return normalizedNode as ParsedFlowDefinition[\"nodes\"][number];\n }),\n };\n normalized.defaults = defaults && Object.keys(defaults).length > 0 ? defaults : undefined;\n normalized.meta = meta && Object.keys(meta).length > 0 ? meta : undefined;\n return normalized;\n}\n\nfunction canonicalize(value: unknown): string | undefined {\n if (value === null || typeof value !== \"object\") return JSON.stringify(value);\n if (Array.isArray(value)) {\n return `[${value.map((item) => canonicalize(item) ?? \"null\").join(\",\")}]`;\n }\n const object = value as Record<string, unknown>;\n const entries: string[] = [];\n for (const key of Object.keys(object).sort()) {\n const serialized = canonicalize(object[key]);\n if (serialized !== undefined) entries.push(`${JSON.stringify(key)}:${serialized}`);\n }\n return `{${entries.join(\",\")}}`;\n}\n\n/** Gives equivalent definitions identical bytes while preserving content-significant array order. */\nexport function canonicalizeFlowDefinition(definition: ParsedFlowDefinition): string {\n return canonicalize(semanticHashInput(definition)) ?? \"null\";\n}\n\n/** Creates a browser-safe content identity for caching, pinning, and change detection. */\nexport async function hashFlowDefinition(definition: ParsedFlowDefinition): Promise<string> {\n const bytes = new TextEncoder().encode(canonicalizeFlowDefinition(definition));\n const digest = await globalThis.crypto.subtle.digest(\"SHA-256\", bytes);\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n","import * as z from \"zod\";\nimport { FlowDefinitionSchema } from \"./schema.js\";\n\n/** Canonical URI editors can use to identify the published Flow v2 vocabulary. */\nexport const FLOW_DEFINITION_JSON_SCHEMA_ID = \"https://skaile.ai/schemas/flow/v2.json\";\n\n/** Keeps editor tooling downstream of Zod so the checked-in artifact cannot become an authority. */\nexport function generateFlowDefinitionJsonSchema(): z.core.JSONSchema.JSONSchema {\n return {\n $id: FLOW_DEFINITION_JSON_SCHEMA_ID,\n ...z.toJSONSchema(FlowDefinitionSchema, {\n target: \"draft-2020-12\",\n io: \"input\",\n reused: \"inline\",\n }),\n };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { parseDep, isValidAssetName, slugifyAssetName } from './chunk-A5EDMBFG.js';
1
+ import { parseDep, isValidAssetName, slugifyAssetName } from './chunk-43ZBF3WH.js';
2
2
  import { createLogger } from './chunk-BOFL7GIF.js';
3
3
  import { stat, readFile, opendir } from 'fs/promises';
4
4
  import { basename, dirname, join } from 'path';
@@ -549,5 +549,5 @@ async function scanDirectory(root, repoName, options = {}) {
549
549
  }
550
550
 
551
551
  export { DEFAULT_FS_DEADLINE_MS, DEFAULT_WALK_BUDGET_MS, DEFAULT_WALK_MAX_DEPTH, DEFAULT_WALK_MAX_ENTRIES, FS_DEADLINE_ENV_VAR, FsDeadlineError, WALK_BUDGET_MS_ENV_VAR, WALK_MAX_DEPTH_ENV_VAR, WALK_MAX_ENTRIES_ENV_VAR, bundleDepRefs, fromAgentMd, fromAgentYaml, fromBundleYaml, fromConnectorMd, fromContractMd, fromFlowYaml, fromKnowledgeYaml, fromMcpServerMd, fromMcpServerMdContent, fromPromptMd, fromSkillMd, fsDeadlineMs, parseFrontmatter, parseRequires, scanDirectory, tryWithFsDeadline, walkDir, withFsDeadline };
552
- //# sourceMappingURL=chunk-5K2VT6E2.js.map
553
- //# sourceMappingURL=chunk-5K2VT6E2.js.map
552
+ //# sourceMappingURL=chunk-DXUQCMVT.js.map
553
+ //# sourceMappingURL=chunk-DXUQCMVT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../core/src/fs-deadline.ts","../core/src/manifest.ts"],"names":[],"mappings":"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","file":"chunk-5K2VT6E2.js","sourcesContent":["/**\n * Deadline guards for filesystem work that can land on a network mount.\n *\n * Inside the agent container `/skaile/workspace` **is** an rclone FUSE mount\n * (SharePoint / OneDrive / WebDAV). When the host rclone process wedges, a\n * filesystem call against that path parks in an uninterruptible kernel wait.\n * A **synchronous** call there stops the entire single-threaded event loop —\n * the whole `skaile serve` process stops serving, and the platform reads the\n * session as dead or idle. A hang is not an error, so `try/catch` never fires.\n *\n * Two rules follow, and both matter:\n *\n * 1. **Never touch a mount synchronously.** Async `node:fs/promises` keeps the\n * loop free, so a wedged mount degrades to one stuck request instead of a\n * dead session. This is the actual fix.\n * 2. **Bound the wait.** {@link withFsDeadline} converts an unbounded wait into\n * a bounded failure so the requester gets an error rather than nothing.\n *\n * `withFsDeadline` does **not** cancel the underlying operation — Node cannot\n * abort a syscall already in the kernel. The losing promise stays pending until\n * the mount recovers or the process exits. That is acceptable precisely because\n * rule 1 holds: a pending promise costs one handle, not the event loop.\n *\n * Modelled on `connectors/src/fleet-utils.ts` (`ensureFleetMounted`), which\n * already does async-stat-with-deadline correctly.\n */\n\n/** Default deadline for a single filesystem operation on a possibly-networked mount. */\nexport const DEFAULT_FS_DEADLINE_MS = 15_000;\n\n/**\n * Env override for {@link DEFAULT_FS_DEADLINE_MS}, in milliseconds.\n *\n * A cloud-backed mount over a slow link can legitimately need longer than the\n * default; operators raise this rather than patching call sites.\n */\nexport const FS_DEADLINE_ENV_VAR = \"SKAILE_FS_DEADLINE_MS\";\n\n/**\n * Thrown when a filesystem operation misses its deadline.\n *\n * Distinct from a plain `Error` so callers can tell \"the mount is wedged\" apart\n * from \"the file does not exist\" and surface the right message to the frontend.\n */\nexport class FsDeadlineError extends Error {\n readonly timeoutMs: number;\n readonly operation: string;\n\n constructor(operation: string, timeoutMs: number) {\n super(\n `filesystem operation \"${operation}\" exceeded ${timeoutMs}ms — the mount may be unresponsive`,\n );\n this.name = \"FsDeadlineError\";\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Resolve the effective filesystem deadline.\n *\n * Reads {@link FS_DEADLINE_ENV_VAR} on every call rather than caching it: the\n * runner mutates `process.env` while wiring a session, so a module-load-time\n * snapshot would pin the value set before configuration ran.\n *\n * @param fallback - Deadline to use when the env var is absent or unusable.\n * @returns The deadline in milliseconds.\n */\nexport function fsDeadlineMs(fallback: number = DEFAULT_FS_DEADLINE_MS): number {\n const raw = process.env[FS_DEADLINE_ENV_VAR];\n if (raw === undefined) return fallback;\n const parsed = Number.parseInt(raw, 10);\n // A non-positive or non-numeric override would disable the guard entirely,\n // which is exactly the failure mode this module exists to prevent.\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\n/**\n * Run an async filesystem operation under a deadline.\n *\n * @param operation - Short label used in the timeout message (e.g. `\"readdir /skaile/workspace\"`).\n * @param fn - Thunk performing the operation. Called immediately.\n * @param timeoutMs - Deadline override; defaults to {@link fsDeadlineMs}.\n * @returns The operation's result.\n * @throws {FsDeadlineError} when the deadline elapses first.\n * @throws Whatever `fn` rejects with, unchanged, when it loses no race.\n * @docLink packages/core/api-reference#with-fs-deadline\n */\nexport async function withFsDeadline<T>(\n operation: string,\n fn: () => Promise<T>,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n fn(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new FsDeadlineError(operation, timeoutMs)), timeoutMs);\n // Never hold the process open on the guard alone — without unref a\n // pending deadline would keep `skaile serve` alive after shutdown.\n timer.unref?.();\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\n/**\n * Run an async filesystem operation under a deadline, mapping every failure to\n * `fallback`.\n *\n * For best-effort probes that previously used `existsSync` — a missing file, an\n * unreadable file, and a wedged mount are all \"nothing usable here\", and the\n * caller has no better move than to continue without it.\n *\n * @param operation - Short label used in the timeout message.\n * @param fn - Thunk performing the operation.\n * @param fallback - Value returned when `fn` rejects or the deadline elapses.\n * @param timeoutMs - Deadline override; defaults to {@link fsDeadlineMs}.\n */\nexport async function tryWithFsDeadline<T>(\n operation: string,\n fn: () => Promise<T>,\n fallback: T,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<T> {\n try {\n return await withFsDeadline(operation, fn, timeoutMs);\n } catch {\n return fallback;\n }\n}\n","/**\n * Manifest parsing — reads SKILL.md, AGENT.md, agent.yaml, CONTRACT.md,\n * CONNECTOR.md, *.prompt.md, *.flow.yaml, *.bundle.yaml files and\n * produces CatalogEntry objects.\n * Used by @skaile/asset-manager for on-demand repo scanning.\n *\n * **All filesystem access here is async and bounded** (issue #454). A repo root\n * can resolve onto the rclone FUSE mount at `/skaile/workspace` — either\n * directly (a `sources[].path` pointing into the workspace) or indirectly, since\n * the walk follows symlinks and an off-mount tree can link into one. A\n * synchronous `readdirSync`/`statSync`/`readFileSync` there parks the whole\n * `skaile serve` event loop in an uninterruptible kernel wait, and a hang is not\n * an error so `try/catch` never fires. Every call goes through\n * {@link withFsDeadline}/{@link tryWithFsDeadline}, and the walk itself is\n * bounded by depth, entry count, a wall-clock budget, and an ancestor-inode set.\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { opendir, readFile, stat } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"./fs-deadline.js\";\nimport { createLogger } from \"./logging/create-logger.js\";\nimport type { AssetKind, CatalogEntry, Dependency } from \"./models.js\";\nimport { isValidAssetName, parseDep, slugifyAssetName } from \"./models.js\";\n\n// ── Bounded manifest I/O ──────────────────────────────────────────────────────\n\n/**\n * Read one manifest file under a deadline.\n *\n * @param filePath - Absolute path to the manifest.\n * @param timeoutMs - Per-operation deadline; defaults to {@link fsDeadlineMs}.\n * @throws {import(\"./fs-deadline.js\").FsDeadlineError} when the read outlives the deadline.\n */\nfunction readManifestFile(filePath: string, timeoutMs?: number): Promise<string> {\n return withFsDeadline(`readFile ${filePath}`, () => readFile(filePath, \"utf8\"), timeoutMs);\n}\n\n/**\n * Read one manifest file under a deadline, degrading an unreadable/slow file to\n * an empty document. Mirrors the pre-#454 `try { readFileSync } catch {}` shape\n * of the YAML parsers: a file we cannot read yields `{}` metadata rather than\n * aborting the caller.\n */\nfunction readManifestFileOrEmpty(filePath: string, timeoutMs?: number): Promise<string> {\n return tryWithFsDeadline(`readFile ${filePath}`, () => readFile(filePath, \"utf8\"), \"\", timeoutMs);\n}\n\n// ── Frontmatter helpers ───────────────────────────────────────────────────────\n\n/**\n * Result of parsing YAML frontmatter from a markdown file.\n * @docLink packages/core/concepts#frontmatter-result\n */\nexport interface FrontmatterResult {\n /** Parsed YAML data. Empty object if no frontmatter block is present. */\n data: Record<string, unknown>;\n /** Markdown body below the frontmatter block (trimmed). */\n body: string;\n}\n\n/**\n * Parse YAML frontmatter from a markdown file (`---` delimited).\n * Returns `{ data: {}, body: text }` when no frontmatter block is present.\n *\n * @param text - Raw file contents\n * @returns Parsed frontmatter data and the remaining body text\n * @docLink packages/core/concepts#parse-frontmatter\n */\nexport function parseFrontmatter(text: string): FrontmatterResult {\n const m = text.match(/^---\\s*\\n([\\s\\S]*?)\\n---/);\n if (!m) return { data: {}, body: text.trim() };\n try {\n const data = (parse(m[1]!) as Record<string, unknown>) ?? {};\n const body = text.slice(m[0].length).trim();\n return { data, body };\n } catch {\n return { data: {}, body: text.trim() };\n }\n}\n\n/** Extract version from frontmatter, checking both top-level and metadata.version. */\nfunction extractVersion(meta: Record<string, unknown>): string {\n return String(\n meta.version ?? (meta.metadata as Record<string, unknown> | undefined)?.version ?? \"\",\n );\n}\n\n/**\n * Parse the `requires:` field from manifest frontmatter into typed `Dependency` objects.\n * Accepts a comma-separated string or an array of `\"kind:name\"` strings. Reads from either\n * the root or `metadata.requires` (matching `extractVersion`'s dual-location behavior) so\n * skill authors can follow the agentskills.io convention of placing skaile extensions under\n * `metadata:` while remaining backward-compatible with root-level declarations.\n *\n * @param meta - Parsed frontmatter data object\n * @returns Array of `Dependency` objects (empty when `requires` is absent)\n * @docLink packages/core/concepts#parse-requires\n */\nexport function parseRequires(meta: Record<string, unknown>): Dependency[] {\n const raw = meta.requires ?? (meta.metadata as Record<string, unknown> | undefined)?.requires;\n if (!raw) return [];\n const list =\n typeof raw === \"string\"\n ? raw.split(\",\").map((s) => s.trim())\n : Array.isArray(raw)\n ? (raw as string[])\n : [];\n return list.filter(Boolean).map(parseDep);\n}\n\n// ── agent.yaml dependency collectors ───────────────────────────────────────────\n\n/**\n * Collect named sub-agent dependencies from an `agent.yaml` array field.\n * Each `{name, ...}` object entry becomes an `{kind: \"agent\", name}` dependency.\n * Covers both the new `requires[]` and legacy `dependencies[]` formats.\n */\nfunction collectAgentDeps(raw: unknown, out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const d of raw) {\n if (typeof d === \"object\" && d !== null && \"name\" in d) {\n out.push({ kind: \"agent\", name: String((d as Record<string, unknown>).name) });\n }\n }\n}\n\n/**\n * Collect string refs from an `agent.yaml` array field (`abilities[]`,\n * `contracts[]`) as `{kind, name}` dependencies, skipping empty entries.\n */\nfunction collectStringRefs(raw: unknown, kind: Dependency[\"kind\"], out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const r of raw) {\n if (typeof r === \"string\" && r) out.push({ kind, name: r });\n }\n}\n\n/**\n * Collect catalog refs from an `agent.yaml` mixin field (`persona`, `rules`,\n * `knowledge`) as requires so `skaile install` pulls them automatically. Local\n * paths (`.`/`/`) are skipped — not catalog assets. Refs without a `kind:`\n * prefix get `defaultKind` injected; the publisher scope and `#pin` are stripped\n * so only `kind:name` is tracked.\n */\nfunction collectMixinRefs(raw: unknown, defaultKind: string, out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const r of raw) {\n if (typeof r !== \"string\" || !r) continue;\n if (r.startsWith(\".\") || r.startsWith(\"/\")) continue; // local path — skip\n // Normalize: if no kind: prefix, inject the default kind\n const normalized = r.includes(\":\") ? r : `${defaultKind}:${r}`;\n // Only kind:name matters for requires — strip the publisher scope and #pin.\n const colonIdx = normalized.indexOf(\":\");\n const kind = normalized.slice(0, colonIdx).trim();\n let rest = normalized.slice(colonIdx + 1).trim();\n const hashIdx = rest.indexOf(\"#\");\n if (hashIdx !== -1) rest = rest.slice(0, hashIdx).trim();\n let name: string;\n if (rest.startsWith(\"@\")) {\n // Scoped form @publisher/name → name is the segment after the slash.\n const slashIdx = rest.indexOf(\"/\");\n name = slashIdx !== -1 ? rest.slice(slashIdx + 1).trim() : \"\";\n } else {\n // Legacy name@publisher (deprecated) or a bare name.\n const atIdx = rest.indexOf(\"@\");\n name = atIdx !== -1 ? rest.slice(0, atIdx).trim() : rest;\n }\n if (name) out.push({ kind, name });\n }\n}\n\n// ── Manifest parsers ──────────────────────────────────────────────────────────\n\n/**\n * Parse a `SKILL.md` file into a `CatalogEntry`.\n * The `kind` field defaults to `\"skill\"` but can be overridden to `\"agent\"` or `\"prompt\"`\n * via the `type:` frontmatter key. Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `SKILL.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind, name, description, version, and requires\n * @docLink packages/core/concepts#from-skill-md\n */\nexport async function fromSkillMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromSkillMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromSkillMd} core over already-read content (no I/O). */\nfunction fromSkillMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n let kind = String(meta.type ?? \"skill\") as AssetKind;\n if (![\"skill\", \"agent\", \"prompt\", \"persona\", \"ruleset\", \"knowledge\"].includes(kind))\n kind = \"skill\";\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind,\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `AGENT.md` file into a `CatalogEntry` with `kind: \"agent\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `AGENT.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"agent\"`\n * @docLink packages/core/concepts#from-agent-md\n */\nexport async function fromAgentMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromAgentMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromAgentMd} core over already-read content (no I/O). */\nfunction fromAgentMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"agent\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `agent.yaml` file into a `CatalogEntry` with `kind: \"agent\"`.\n * Collects sub-agent dependencies from `requires[]` (new format) and `dependencies[]`\n * (legacy format), skill abilities from `abilities[]`, and contracts from `contracts[]`.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `agent.yaml` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"agent\"` and full dependency graph\n * @docLink packages/core/concepts#from-agent-yaml\n */\nexport async function fromAgentYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromAgentYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromAgentYaml} core over already-read content (no I/O). */\nfunction fromAgentYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const requires: Dependency[] = [];\n\n // Sub-agent dependencies from requires[] (new format: {name, source, ...})\n collectAgentDeps(meta.requires, requires);\n // Legacy sub-agent dependencies from dependencies[] (old format: {name, ...})\n collectAgentDeps(meta.dependencies, requires);\n // Skill abilities referenced in the system prompt\n collectStringRefs(meta.abilities, \"skill\", requires);\n // Contracts referenced in the system prompt (co-located in skills dir)\n collectStringRefs(meta.contracts, \"contract\", requires);\n\n // Mixin composition fields — track catalog refs as requires so `skaile install`\n // automatically pulls them. Local paths (. or /) are skipped — not catalog assets.\n for (const [field, defaultKind] of [\n [\"persona\", \"persona\"],\n [\"rules\", \"ruleset\"],\n [\"knowledge\", \"knowledge\"],\n ] as const) {\n collectMixinRefs(meta[field], defaultKind, requires);\n }\n\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"agent\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires,\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.prompt.md` file into a `CatalogEntry` with `kind: \"prompt\"`.\n * The name defaults to the filename stem (without the `.prompt.md` suffix)\n * when no `name:` frontmatter key is present.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `.prompt.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"prompt\"`\n * @docLink packages/core/concepts#from-prompt-md\n */\nexport async function fromPromptMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromPromptMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromPromptMd} core over already-read content (no I/O). */\nfunction fromPromptMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n const name = String(meta.name ?? basename(filePath).replace(/\\.prompt\\.md$/, \"\"));\n return {\n name,\n kind: \"prompt\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.flow.yaml` or `*.flow.json` file into a `CatalogEntry` with `kind: \"flow\"`.\n * The name resolves from `name:` or `id:` frontmatter, falling back to the filename stem.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the flow definition file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"flow\"`\n * @docLink packages/core/concepts#from-flow-yaml\n */\nexport async function fromFlowYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromFlowYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromFlowYaml} core over already-read content (no I/O). */\nfunction fromFlowYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const stem = basename(filePath)\n .replace(/\\.flow\\.yaml$/, \"\")\n .replace(/\\.flow\\.json$/, \"\");\n return {\n name: String(meta.name ?? meta.id ?? stem),\n kind: \"flow\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.bundle.yaml` file into a `CatalogEntry` with `kind: \"bundle\"`.\n * Bundles declare a flat list of string `dependencies` (asset refs) rather than\n * typed `Dependency` objects; both `requires` and `dependencies` are populated.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the bundle YAML file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"bundle\"`\n * @docLink packages/core/concepts#from-bundle-yaml\n */\nexport async function fromBundleYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromBundleYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromBundleYaml} core over already-read content (no I/O). */\nfunction fromBundleYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const name = String(meta.name ?? basename(filePath).replace(/\\.bundle\\.yaml$/, \"\"));\n\n const deps = meta.dependencies;\n const dependencies = Array.isArray(deps) ? (deps as string[]).filter(Boolean) : [];\n\n return {\n name,\n kind: \"bundle\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies,\n };\n}\n\n/**\n * Extract a bundle's raw transitive dependency ref strings from its manifest\n * file — the union of its `requires` and `dependencies` lists, kept verbatim\n * (publisher/pin qualifiers preserved, comments dropped by the parser).\n *\n * Supports `*.bundle.yaml` / `*.flow.{yaml,json}` (top-level\n * `requires`/`dependencies`) and the `BUNDLE.md` frontmatter layout\n * (`requires`/`dependencies`, incl. nested under `metadata`). Unlike\n * {@link parseRequires}, refs are returned as-is — the resolver needs the full\n * `kind:name@<publisher>[#pin]` form, not a publisher-stripped {@link Dependency}.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to a `.bundle.yaml`, `.flow.{yaml,json}`, or `BUNDLE.md`.\n * @returns Deduped list of ref strings; `[]` on parse failure or no deps.\n * @docLink packages/core/concepts#bundle-dep-refs\n */\nexport async function bundleDepRefs(filePath: string): Promise<string[]> {\n return bundleDepRefsFromContent(await readManifestFileOrEmpty(filePath), filePath);\n}\n\n/** Pure {@link bundleDepRefs} core over already-read content (no I/O). */\nfunction bundleDepRefsFromContent(content: string, filePath: string): string[] {\n // `.bundle.yaml` / `.flow.yaml` / `.flow.json` carry their dep list as a\n // top-level document key (`requires`/`dependencies`); `BUNDLE.md` carries it\n // in frontmatter. YAML is a JSON superset, so `parse` reads `.flow.json` too.\n const wholeDoc = /\\.(bundle\\.yaml|flow\\.yaml|flow\\.json)$/.test(filePath);\n let meta: Record<string, unknown> = {};\n try {\n meta = wholeDoc\n ? ((parse(content) as Record<string, unknown>) ?? {})\n : parseFrontmatter(content).data;\n } catch {\n return [];\n }\n const out: string[] = [];\n const collect = (v: unknown) => {\n if (Array.isArray(v))\n for (const x of v) if (typeof x === \"string\" && x.trim()) out.push(x.trim());\n };\n collect(meta.requires);\n collect((meta.metadata as Record<string, unknown> | undefined)?.requires);\n collect(meta.dependencies);\n return [...new Set(out)];\n}\n\n/**\n * Parse a `CONTRACT.md` file into a `CatalogEntry` with `kind: \"contract\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `CONTRACT.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"contract\"`\n * @docLink packages/core/concepts#from-contract-md\n */\nexport async function fromContractMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromContractMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromContractMd} core over already-read content (no I/O). */\nfunction fromContractMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"contract\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `MCP.md` file into a `CatalogEntry` with `kind: \"mcp-server\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Frontmatter fields (catalog identity):\n * - `name` — server name (default: parent dir name)\n * - `description` — short description\n * - `version` — semver\n * - `keywords` — array of discovery tags\n *\n * Frontmatter fields (runtime defaults, stored in `metadata`):\n * - `transport` — \"stdio\" | \"sse\" | \"http\" (default: \"stdio\")\n * - `command` — command to execute (stdio)\n * - `args` — command arguments (stdio)\n * - `env` — environment variables (stdio)\n * - `url` — server URL (sse/http)\n * - `headers` — HTTP headers (sse/http)\n *\n * When `mcp:name` appears in `skaile.yaml` `dependencies`, the runner reads\n * these defaults from `metadata` to build a `McpServerDeclaration` without\n * requiring verbose inline config.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `MCP.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"mcp-server\"`\n * @docLink packages/core/concepts#from-mcp-server-md\n */\nexport async function fromMcpServerMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromMcpServerMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/**\n * Parse pre-read MCP.md content into a `CatalogEntry`.\n * Callers that already hold the file content (e.g. to avoid a second read) use\n * this directly; `fromMcpServerMd` is a thin wrapper that reads then delegates here.\n *\n * @param content - UTF-8 content of the `MCP.md` file\n * @param repoName - Repository name used as the `publisher` field of the entry\n * @param filePath - Absolute path (used as `source` and for name fallback)\n * @returns Populated `CatalogEntry` with kind `\"mcp-server\"`\n */\nexport function fromMcpServerMdContent(\n content: string,\n repoName: string,\n filePath: string,\n): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n\n // Extract runtime defaults into metadata\n const metadata: Record<string, unknown> = {};\n if (meta.transport) metadata.transport = String(meta.transport);\n if (meta.command) metadata.command = String(meta.command);\n if (Array.isArray(meta.args)) metadata.args = meta.args.map(String);\n if (meta.env && typeof meta.env === \"object\" && !Array.isArray(meta.env)) {\n metadata.env = meta.env as Record<string, string>;\n }\n if (meta.url) metadata.url = String(meta.url);\n if (typeof meta.ca === \"string\") metadata.ca = meta.ca;\n if (meta.headers && typeof meta.headers === \"object\" && !Array.isArray(meta.headers)) {\n metadata.headers = meta.headers as Record<string, string>;\n }\n if (meta.recipe && typeof meta.recipe === \"object\" && !Array.isArray(meta.recipe)) {\n metadata.recipe = meta.recipe;\n }\n\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"mcp-server\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n}\n\n/**\n * Parse a `knowledge.yaml` file into a `CatalogEntry` with `kind: \"knowledge\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `knowledge.yaml` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"knowledge\"`\n * @docLink packages/core/concepts#from-knowledge-yaml\n */\nexport async function fromKnowledgeYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromKnowledgeYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromKnowledgeYaml} core over already-read content (no I/O). */\nfunction fromKnowledgeYamlContent(\n content: string,\n repoName: string,\n filePath: string,\n): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"knowledge\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `CONNECTOR.md` file into a `CatalogEntry` with `kind: \"connector\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Frontmatter fields (catalog identity):\n * - `name` — connector name (default: parent dir name)\n * - `description` — short description\n * - `version` — semver\n *\n * Frontmatter fields (runtime defaults, stored in `metadata`):\n * - `entry` — adapter entry point (default: \"./adapter.ts\")\n * - `npm_deps` — npm dependencies required by the adapter\n * - `fields` — configuration fields the adapter expects\n * - `health_check` — whether to run a health check on connect\n *\n * The markdown body (below the frontmatter) is stored in `metadata.body`\n * so the runner can inject the connector's skill description into the\n * system prompt when `expose_as_skill` is enabled.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `CONNECTOR.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"connector\"`\n * @docLink packages/core/concepts#from-connector-md\n */\nexport async function fromConnectorMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromConnectorMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromConnectorMd} core over already-read content (no I/O). */\nfunction fromConnectorMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta, body } = parseFrontmatter(content);\n const name = String(meta.name ?? basename(dirname(filePath)));\n return {\n name,\n kind: \"connector\" as AssetKind,\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n metadata: {\n entry: meta.entry ?? \"./adapter.ts\",\n npm_deps: meta.npm_deps ?? {},\n fields: meta.fields ?? [],\n health_check: meta.health_check ?? null,\n body,\n },\n };\n}\n\n// ── Recursive walker ──────────────────────────────────────────────────────────\n\ninterface WalkEntry {\n path: string;\n name: string;\n}\n\n/** Default maximum directory nesting the walk descends into. */\nexport const DEFAULT_WALK_MAX_DEPTH = 32;\n\n/** Default maximum number of directory entries a single walk may examine. */\nexport const DEFAULT_WALK_MAX_ENTRIES = 50_000;\n\n/** Default wall-clock budget for one whole walk / scan pass, in milliseconds. */\nexport const DEFAULT_WALK_BUDGET_MS = 60_000;\n\n/** Env override for {@link DEFAULT_WALK_MAX_DEPTH}. */\nexport const WALK_MAX_DEPTH_ENV_VAR = \"SKAILE_SCAN_MAX_DEPTH\";\n\n/** Env override for {@link DEFAULT_WALK_MAX_ENTRIES}. */\nexport const WALK_MAX_ENTRIES_ENV_VAR = \"SKAILE_SCAN_MAX_ENTRIES\";\n\n/** Env override for {@link DEFAULT_WALK_BUDGET_MS}. */\nexport const WALK_BUDGET_MS_ENV_VAR = \"SKAILE_SCAN_DEADLINE_MS\";\n\n/** Read a positive-integer env override, falling back when absent or unusable. */\nfunction envInt(name: string, fallback: number): number {\n const raw = process.env[name];\n if (raw === undefined) return fallback;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\n/**\n * Why a walk stopped early. Every one of these means the returned entries are a\n * **partial** view of the tree — never present a truncated walk as complete.\n *\n * @docLink packages/core/concepts#walk-dir\n */\nexport interface WalkTruncation {\n reason: \"depth\" | \"entries\" | \"budget\" | \"cycle\" | \"unreadable\";\n /** Directory (or symlink) at which the bound was hit. */\n path: string;\n /** The bound that was hit, when the reason has a numeric limit. */\n limit?: number;\n}\n\n/**\n * Bounds for {@link walkDir} / {@link scanDirectory}.\n *\n * @docLink packages/core/concepts#walk-dir\n */\nexport interface WalkOptions {\n /** Maximum nesting depth below the root. Default {@link DEFAULT_WALK_MAX_DEPTH}. */\n maxDepth?: number;\n /** Maximum directory entries examined across the whole walk. Default {@link DEFAULT_WALK_MAX_ENTRIES}. */\n maxEntries?: number;\n /**\n * Wall-clock budget for the whole walk. Default {@link DEFAULT_WALK_BUDGET_MS}.\n * The check is inclusive, so `0` yields no entries at all.\n */\n budgetMs?: number;\n /** Per-`opendir`/`stat`/`readFile` deadline. Default {@link fsDeadlineMs}. */\n opTimeoutMs?: number;\n /**\n * Called once per distinct truncation reason. Defaults to a `warn` on the\n * core logger — override to route the signal somewhere the caller can act on.\n */\n onTruncate?: (info: WalkTruncation) => void;\n}\n\n/** Mutable bookkeeping threaded through one walk. */\ninterface WalkState {\n maxDepth: number;\n maxEntries: number;\n opTimeoutMs: number | undefined;\n deadlineAt: number;\n examined: number;\n /**\n * `dev:ino` of the directories on the **current path from the root** — an\n * ancestor stack, not an ever-visited set. Re-entering an ancestor is a cycle;\n * re-reaching a directory off the current path is a diamond, and must be walked.\n */\n ancestors: Set<string>;\n reported: Set<WalkTruncation[\"reason\"]>;\n onTruncate: (info: WalkTruncation) => void;\n}\n\nlet walkLogger: ReturnType<typeof createLogger> | undefined;\n\n/** Default truncation sink — a structured warning naming the bound that was hit. */\nfunction warnTruncation(info: WalkTruncation): void {\n walkLogger ??= createLogger({ kind: \"runner\", subkind: \"asset-scan\" });\n walkLogger.warn(`asset scan truncated (${info.reason}) — results are incomplete`, {\n ...info,\n });\n}\n\n/** Record a truncation once per reason so a wide tree does not spam the log. */\nfunction truncate(state: WalkState, info: WalkTruncation): void {\n if (state.reported.has(info.reason)) return;\n state.reported.add(info.reason);\n state.onTruncate(info);\n}\n\n/**\n * Stable identity (`dev:ino`) of the directory `path` resolves to, or `null`\n * when it cannot be stat'ed within the deadline. Used to terminate symlink\n * cycles — the pre-#454 walker recursed forever on `a/link -> a`.\n */\nasync function dirIdentity(path: string, timeoutMs: number | undefined): Promise<string | null> {\n const st = await tryWithFsDeadline(`stat ${path}`, () => stat(path), null, timeoutMs);\n return st ? `${st.dev}:${st.ino}` : null;\n}\n\n/**\n * Read one directory's entries under a deadline, capped at the walk's remaining\n * entry budget. Uses `opendir` rather than `readdir` so a pathological directory\n * streams instead of materialising in full; entries are collected and sorted\n * because the `scanDirectory` dedup rule (\"alphabetically later source wins\")\n * depends on a deterministic per-level order.\n */\nasync function readDirEntries(\n dir: string,\n state: WalkState,\n): Promise<{ entries: Dirent[]; capped: boolean } | null> {\n const remaining = state.maxEntries - state.examined;\n if (remaining <= 0) return { entries: [], capped: true };\n try {\n return await withFsDeadline(\n `opendir ${dir}`,\n async () => {\n const handle = await opendir(dir);\n const entries: Dirent[] = [];\n let capped = false;\n for await (const e of handle) {\n // Stop *before* keeping the over-budget entry, so `capped` means \"an\n // entry was actually dropped\". Breaking after the push instead marked\n // a directory of exactly `remaining` entries as truncated — and since\n // `truncate()` reports once per reason for the whole walk, that\n // spurious first report swallowed a later genuine one.\n if (entries.length >= remaining) {\n capped = true;\n break;\n }\n entries.push(e);\n }\n entries.sort((a, b) => (a.name < b.name ? -1 : 1));\n return { entries, capped };\n },\n state.opTimeoutMs,\n );\n } catch {\n // Unreadable (permissions, vanished mid-walk) or the mount missed its\n // deadline. Either way this subtree contributes nothing; keep walking.\n truncate(state, { reason: \"unreadable\", path: dir });\n return null;\n }\n}\n\n/**\n * Recursively yield every file entry under `dir`, sorted alphabetically at each\n * level. Skips `.git` and `node_modules` directories and follows symlinks\n * (resolving to the stat target). `node_modules` is excluded because Bun's\n * `node_modules/.bun/...` layout contains symlink farms that form cycles when\n * packages reference each other transitively.\n *\n * **Async and bounded since #454.** A repo root can resolve onto the rclone FUSE\n * mount, where the previous synchronous `readdirSync`/`statSync` walk parked the\n * whole event loop. Four bounds now hold, and hitting any of them reports a\n * {@link WalkTruncation} — a truncated walk is never presented as a complete one:\n *\n * - **depth** ({@link WalkOptions.maxDepth}) — also the backstop for a cycle no\n * inode check can see, e.g. a bind mount of the root inside itself.\n * - **entry count** ({@link WalkOptions.maxEntries}) — total directory entries\n * examined, so an enormous tree cannot run unbounded.\n * - **wall-clock budget** ({@link WalkOptions.budgetMs}) — a wedged mount that\n * times out one operation at a time cannot add up to an unbounded scan.\n * - **ancestor inodes** — the `dev:ino` of every directory on the path from the\n * root is held while its subtree is walked, so `a/link -> a` terminates\n * instead of recursing forever. Two sibling symlinks onto one shared\n * directory are a diamond, not a cycle: both are walked, at the price of\n * visiting the shared subtree twice — bounded by the entry and time budgets.\n *\n * @param dir - Absolute path to the directory to walk\n * @param options - Bounds and truncation sink; see {@link WalkOptions}\n * @docLink packages/core/concepts#walk-dir\n */\nexport async function* walkDir(dir: string, options: WalkOptions = {}): AsyncGenerator<WalkEntry> {\n const state: WalkState = {\n maxDepth: options.maxDepth ?? envInt(WALK_MAX_DEPTH_ENV_VAR, DEFAULT_WALK_MAX_DEPTH),\n maxEntries: options.maxEntries ?? envInt(WALK_MAX_ENTRIES_ENV_VAR, DEFAULT_WALK_MAX_ENTRIES),\n opTimeoutMs: options.opTimeoutMs,\n deadlineAt:\n Date.now() + (options.budgetMs ?? envInt(WALK_BUDGET_MS_ENV_VAR, DEFAULT_WALK_BUDGET_MS)),\n examined: 0,\n ancestors: new Set<string>(),\n reported: new Set<WalkTruncation[\"reason\"]>(),\n onTruncate: options.onTruncate ?? warnTruncation,\n };\n // The root is an ancestor of everything, so it is seeded here and never\n // popped — a self-referential `root/link -> root` is caught on first descent.\n const rootId = await dirIdentity(dir, state.opTimeoutMs);\n if (rootId) state.ancestors.add(rootId);\n yield* walkFrom(dir, 0, state);\n}\n\nasync function* walkFrom(dir: string, depth: number, state: WalkState): AsyncGenerator<WalkEntry> {\n if (depth > state.maxDepth) {\n truncate(state, { reason: \"depth\", path: dir, limit: state.maxDepth });\n return;\n }\n if (Date.now() >= state.deadlineAt) {\n truncate(state, { reason: \"budget\", path: dir });\n return;\n }\n\n const read = await readDirEntries(dir, state);\n if (!read) return;\n if (read.capped) truncate(state, { reason: \"entries\", path: dir, limit: state.maxEntries });\n\n for (const e of read.entries) {\n if (state.examined >= state.maxEntries) {\n truncate(state, { reason: \"entries\", path: dir, limit: state.maxEntries });\n return;\n }\n if (Date.now() >= state.deadlineAt) {\n truncate(state, { reason: \"budget\", path: dir });\n return;\n }\n state.examined++;\n const full = join(dir, e.name);\n\n if (e.isSymbolicLink()) {\n // A symlink is the only way a cycle can enter this walk, so identity is\n // resolved here and nowhere else — one extra stat per link, none per\n // ordinary directory.\n const st = await tryWithFsDeadline(`stat ${full}`, () => stat(full), null, state.opTimeoutMs);\n if (!st) continue;\n if (st.isDirectory()) {\n if (e.name === \".git\" || e.name === \"node_modules\") continue;\n const id = `${st.dev}:${st.ino}`;\n // Only an *ancestor* is a cycle. A target already walked elsewhere in\n // the tree is a diamond (`a/link -> shared`, `b/link -> shared`) and\n // dropping it would silently lose that subtree from the scan.\n if (state.ancestors.has(id)) {\n truncate(state, { reason: \"cycle\", path: full });\n continue;\n }\n state.ancestors.add(id);\n try {\n yield* walkFrom(full, depth + 1, state);\n } finally {\n // finally, not a trailing delete: an early `return` from the bounds\n // checks — or an abandoned consumer — would otherwise leave the\n // ancestor stack holding a directory the walk has already left.\n state.ancestors.delete(id);\n }\n } else {\n yield { path: full, name: e.name };\n }\n } else if (e.isDirectory()) {\n if (e.name !== \".git\" && e.name !== \"node_modules\") yield* walkFrom(full, depth + 1, state);\n } else if (e.isFile()) {\n yield { path: full, name: e.name };\n }\n }\n}\n\n// ── Public scanner ────────────────────────────────────────────────────────────\n\n/**\n * Coerce a scanned entry's `name` to a canonical asset name in place. When the\n * raw name is already canonical this is a no-op; otherwise the original is stashed\n * on `metadata.displayName` (only when not already set) so callers keep the pretty\n * label for display while identity uses the slug. A name that slugifies to empty\n * is left untouched — `parseAssetRef` will reject it downstream with its full hint.\n */\nfunction normalizeEntryName(e: CatalogEntry): void {\n if (isValidAssetName(e.name)) return;\n let slug: string;\n try {\n slug = slugifyAssetName(e.name);\n } catch {\n return;\n }\n const original = e.name;\n e.name = slug;\n if (e.metadata?.displayName === undefined) {\n e.metadata = { ...e.metadata, displayName: original };\n }\n}\n\n/**\n * Build a `CatalogEntry` from an already-read manifest, dispatching on filename.\n * Returns `null` when the filename is not a recognized manifest.\n */\nfunction entryFromManifest(\n name: string,\n content: string,\n filePath: string,\n repoName: string,\n): CatalogEntry | null {\n if (name === \"SKILL.md\") return fromSkillMdContent(content, repoName, filePath);\n if (name === \"AGENT.md\") return fromAgentMdContent(content, repoName, filePath);\n if (name === \"agent.yaml\") return fromAgentYamlContent(content, repoName, filePath);\n if (name === \"CONTRACT.md\") return fromContractMdContent(content, repoName, filePath);\n if (name === \"MCP.md\") return fromMcpServerMdContent(content, repoName, filePath);\n if (name === \"CONNECTOR.md\") return fromConnectorMdContent(content, repoName, filePath);\n if (name === \"knowledge.yaml\") return fromKnowledgeYamlContent(content, repoName, filePath);\n if (name.endsWith(\".prompt.md\")) return fromPromptMdContent(content, repoName, filePath);\n if (name.endsWith(\".bundle.yaml\")) return fromBundleYamlContent(content, repoName, filePath);\n if (name.endsWith(\".flow.yaml\") || name.endsWith(\".flow.json\"))\n return fromFlowYamlContent(content, repoName, filePath);\n return null;\n}\n\n/** Filenames {@link scanDirectory} recognises as asset manifests. */\nfunction isManifestName(name: string): boolean {\n return (\n name === \"SKILL.md\" ||\n name === \"AGENT.md\" ||\n name === \"agent.yaml\" ||\n name === \"CONTRACT.md\" ||\n name === \"MCP.md\" ||\n name === \"CONNECTOR.md\" ||\n name === \"knowledge.yaml\" ||\n name.endsWith(\".prompt.md\") ||\n name.endsWith(\".bundle.yaml\") ||\n name.endsWith(\".flow.yaml\") ||\n name.endsWith(\".flow.json\")\n );\n}\n\n/**\n * Walk `root` recursively and return a `CatalogEntry` for every recognized asset manifest found.\n *\n * Recognized filenames: `SKILL.md`, `AGENT.md`, `agent.yaml`, `CONTRACT.md`, `MCP.md`,\n * `CONNECTOR.md`, `knowledge.yaml`, `*.prompt.md`, `*.bundle.yaml`, `*.flow.yaml`, `*.flow.json`.\n *\n * When two entries share the same `kind:name` key, the one with the alphabetically\n * later source path wins (consistent with catalog precedence rules).\n *\n * **Async and bounded since #454.** `root` can resolve onto the rclone FUSE mount\n * (a `sources[].path` under `/skaile/workspace`), and the walk follows symlinks, so\n * even an off-mount root can descend into one. Every `opendir`/`stat`/`readFile`\n * is deadline-bounded and the walk is capped by depth, entry count, a wall-clock\n * budget, and an ancestor-inode set — see {@link walkDir}. Hitting any bound reports\n * a {@link WalkTruncation} through {@link WalkOptions.onTruncate} (a `warn` by\n * default); the returned array is then a **partial** scan, never a complete one.\n *\n * A manifest that cannot be read within its deadline is skipped rather than\n * failing the whole scan — one unreachable file must not cost the whole catalog.\n *\n * @param root - Absolute path to the directory tree to scan\n * @param repoName - Repository name attached to every produced entry\n * @param options - Walk bounds and truncation sink; see {@link WalkOptions}\n * @returns Array of deduplicated `CatalogEntry` objects, one per manifest file\n * @docLink packages/core/concepts#scan-directory\n */\nexport async function scanDirectory(\n root: string,\n repoName: string,\n options: WalkOptions = {},\n): Promise<CatalogEntry[]> {\n const entries = new Map<string, CatalogEntry>();\n const onTruncate = options.onTruncate ?? warnTruncation;\n const reported = new Set<WalkTruncation[\"reason\"]>();\n const relay = (info: WalkTruncation) => {\n reported.add(info.reason);\n onTruncate(info);\n };\n const opTimeoutMs = options.opTimeoutMs ?? fsDeadlineMs();\n\n function add(e: CatalogEntry): void {\n // Boundary normalization: a third-party source we don't control may name an\n // asset with a human-styled identity (\"Complex App\"). Slugify it to a\n // canonical name so the ref it produces parses, preserving the original on\n // `metadata.displayName` for display. No-op for already-canonical names.\n normalizeEntryName(e);\n const key = `${e.kind}:${e.name}`;\n const existing = entries.get(key);\n if (!existing) {\n entries.set(key, e);\n return;\n }\n // Among duplicates, alphabetically later source path wins\n if (e.source > existing.source) entries.set(key, e);\n }\n\n for await (const { path: filePath, name } of walkDir(root, {\n ...options,\n opTimeoutMs,\n onTruncate: relay,\n })) {\n if (!isManifestName(name)) continue;\n const content = await tryWithFsDeadline(\n `readFile ${filePath}`,\n () => readFile(filePath, \"utf8\"),\n null,\n opTimeoutMs,\n );\n if (content === null) {\n // Unreadable or past its deadline — the catalog loses this asset, not the\n // whole scan. Reported once so a wedged mount is visible in the logs.\n if (!reported.has(\"unreadable\")) relay({ reason: \"unreadable\", path: filePath });\n continue;\n }\n try {\n const entry = entryFromManifest(name, content, filePath, repoName);\n if (entry) add(entry);\n } catch {}\n }\n\n return [...entries.values()];\n}\n"]}
1
+ {"version":3,"sources":["../core/src/fs-deadline.ts","../core/src/manifest.ts"],"names":[],"mappings":";;;;;;;AA4BO,IAAM,sBAAA,GAAyB;AAQ/B,IAAM,mBAAA,GAAsB;AAQ5B,IAAM,eAAA,GAAN,cAA8B,KAAA,CAAM;AAAA,EAChC,SAAA;AAAA,EACA,SAAA;AAAA,EAET,WAAA,CAAY,WAAmB,SAAA,EAAmB;AAChD,IAAA,KAAA;AAAA,MACE,CAAA,sBAAA,EAAyB,SAAS,CAAA,WAAA,EAAc,SAAS,CAAA,uCAAA;AAAA,KAC3D;AACA,IAAA,IAAA,CAAK,IAAA,GAAO,iBAAA;AACZ,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AAAA,EACnB;AACF;AAYO,SAAS,YAAA,CAAa,WAAmB,sBAAA,EAAgC;AAC9E,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,CAAI,mBAAmB,CAAA;AAC3C,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,QAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AAGtC,EAAA,OAAO,OAAO,QAAA,CAAS,MAAM,CAAA,IAAK,MAAA,GAAS,IAAI,MAAA,GAAS,QAAA;AAC1D;AAaA,eAAsB,cAAA,CACpB,SAAA,EACA,EAAA,EACA,SAAA,GAAoB,cAAa,EACrB;AACZ,EAAA,IAAI,KAAA;AACJ,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,QAAQ,IAAA,CAAK;AAAA,MACxB,EAAA,EAAG;AAAA,MACH,IAAI,OAAA,CAAe,CAAC,QAAA,EAAU,MAAA,KAAW;AACvC,QAAA,KAAA,GAAQ,UAAA,CAAW,MAAM,MAAA,CAAO,IAAI,gBAAgB,SAAA,EAAW,SAAS,CAAC,CAAA,EAAG,SAAS,CAAA;AAGrF,QAAA,KAAA,CAAM,KAAA,IAAQ;AAAA,MAChB,CAAC;AAAA,KACF,CAAA;AAAA,EACH,CAAA,SAAE;AACA,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAAA,EAC7C;AACF;AAeA,eAAsB,kBACpB,SAAA,EACA,EAAA,EACA,QAAA,EACA,SAAA,GAAoB,cAAa,EACrB;AACZ,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,cAAA,CAAe,SAAA,EAAW,EAAA,EAAI,SAAS,CAAA;AAAA,EACtD,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,QAAA;AAAA,EACT;AACF;;;AClGA,SAAS,gBAAA,CAAiB,UAAkB,SAAA,EAAqC;AAC/E,EAAA,OAAO,cAAA,CAAe,YAAY,QAAQ,CAAA,CAAA,EAAI,MAAM,QAAA,CAAS,QAAA,EAAU,MAAM,CAAA,EAAG,SAAS,CAAA;AAC3F;AAQA,SAAS,uBAAA,CAAwB,UAAkB,SAAA,EAAqC;AACtF,EAAA,OAAO,iBAAA,CAAkB,CAAA,SAAA,EAAY,QAAQ,CAAA,CAAA,EAAI,MAAM,SAAS,QAAA,EAAU,MAAM,CAAA,EAAG,EAAA,EAAI,SAAS,CAAA;AAClG;AAuBO,SAAS,iBAAiB,IAAA,EAAiC;AAChE,EAAA,MAAM,CAAA,GAAI,IAAA,CAAK,KAAA,CAAM,0BAA0B,CAAA;AAC/C,EAAA,IAAI,CAAC,CAAA,EAAG,OAAO,EAAE,IAAA,EAAM,EAAC,EAAG,IAAA,EAAM,IAAA,CAAK,IAAA,EAAK,EAAE;AAC7C,EAAA,IAAI;AACF,IAAA,MAAM,OAAQ,KAAA,CAAM,CAAA,CAAE,CAAC,CAAE,KAAiC,EAAC;AAC3D,IAAA,MAAM,IAAA,GAAO,KAAK,KAAA,CAAM,CAAA,CAAE,CAAC,CAAA,CAAE,MAAM,EAAE,IAAA,EAAK;AAC1C,IAAA,OAAO,EAAE,MAAM,IAAA,EAAK;AAAA,EACtB,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAE,IAAA,EAAM,IAAI,IAAA,EAAM,IAAA,CAAK,MAAK,EAAE;AAAA,EACvC;AACF;AAGA,SAAS,eAAe,IAAA,EAAuC;AAC7D,EAAA,OAAO,MAAA;AAAA,IACL,IAAA,CAAK,OAAA,IAAY,IAAA,CAAK,QAAA,EAAkD,OAAA,IAAW;AAAA,GACrF;AACF;AAaO,SAAS,cAAc,IAAA,EAA6C;AACzE,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,QAAA,IAAa,IAAA,CAAK,QAAA,EAAkD,QAAA;AACrF,EAAA,IAAI,CAAC,GAAA,EAAK,OAAO,EAAC;AAClB,EAAA,MAAM,IAAA,GACJ,OAAO,GAAA,KAAQ,QAAA,GACX,IAAI,KAAA,CAAM,GAAG,EAAE,GAAA,CAAI,CAAC,MAAM,CAAA,CAAE,IAAA,EAAM,CAAA,GAClC,KAAA,CAAM,QAAQ,GAAG,CAAA,GACd,MACD,EAAC;AACT,EAAA,OAAO,IAAA,CAAK,MAAA,CAAO,OAAO,CAAA,CAAE,IAAI,QAAQ,CAAA;AAC1C;AASA,SAAS,gBAAA,CAAiB,KAAc,GAAA,EAAyB;AAC/D,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACzB,EAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACnB,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,KAAM,IAAA,IAAQ,UAAU,CAAA,EAAG;AACtD,MAAA,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,MAAM,MAAA,CAAQ,CAAA,CAA8B,IAAI,CAAA,EAAG,CAAA;AAAA,IAC/E;AAAA,EACF;AACF;AAMA,SAAS,iBAAA,CAAkB,GAAA,EAAc,IAAA,EAA0B,GAAA,EAAyB;AAC1F,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACzB,EAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACnB,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,EAAG,GAAA,CAAI,KAAK,EAAE,IAAA,EAAM,IAAA,EAAM,CAAA,EAAG,CAAA;AAAA,EAC5D;AACF;AASA,SAAS,gBAAA,CAAiB,GAAA,EAAc,WAAA,EAAqB,GAAA,EAAyB;AACpF,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACzB,EAAA,KAAA,MAAW,KAAK,GAAA,EAAK;AACnB,IAAA,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAC,CAAA,EAAG;AACjC,IAAA,IAAI,EAAE,UAAA,CAAW,GAAG,KAAK,CAAA,CAAE,UAAA,CAAW,GAAG,CAAA,EAAG;AAE5C,IAAA,MAAM,UAAA,GAAa,EAAE,QAAA,CAAS,GAAG,IAAI,CAAA,GAAI,CAAA,EAAG,WAAW,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA;AAE5D,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,OAAA,CAAQ,GAAG,CAAA;AACvC,IAAA,MAAM,OAAO,UAAA,CAAW,KAAA,CAAM,CAAA,EAAG,QAAQ,EAAE,IAAA,EAAK;AAChD,IAAA,IAAI,OAAO,UAAA,CAAW,KAAA,CAAM,QAAA,GAAW,CAAC,EAAE,IAAA,EAAK;AAC/C,IAAA,MAAM,OAAA,GAAU,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAChC,IAAA,IAAI,OAAA,KAAY,IAAI,IAAA,GAAO,IAAA,CAAK,MAAM,CAAA,EAAG,OAAO,EAAE,IAAA,EAAK;AACvD,IAAA,IAAI,IAAA;AACJ,IAAA,IAAI,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,EAAG;AAExB,MAAA,MAAM,QAAA,GAAW,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACjC,MAAA,IAAA,GAAO,QAAA,KAAa,KAAK,IAAA,CAAK,KAAA,CAAM,WAAW,CAAC,CAAA,CAAE,MAAK,GAAI,EAAA;AAAA,IAC7D,CAAA,MAAO;AAEL,MAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AAC9B,MAAA,IAAA,GAAO,KAAA,KAAU,KAAK,IAAA,CAAK,KAAA,CAAM,GAAG,KAAK,CAAA,CAAE,MAAK,GAAI,IAAA;AAAA,IACtD;AACA,IAAA,IAAI,MAAM,GAAA,CAAI,IAAA,CAAK,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EACnC;AACF;AAgBA,eAAsB,WAAA,CAAY,UAAkB,QAAA,EAAyC;AAC3F,EAAA,OAAO,mBAAmB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AAChF;AAGA,SAAS,kBAAA,CAAmB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAC7F,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AAC/C,EAAA,IAAI,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,IAAA,IAAQ,OAAO,CAAA;AACtC,EAAA,IAAI,CAAC,CAAC,OAAA,EAAS,OAAA,EAAS,QAAA,EAAU,WAAW,SAAA,EAAW,WAAW,CAAA,CAAE,QAAA,CAAS,IAAI,CAAA;AAChF,IAAA,IAAA,GAAO,OAAA;AACT,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA;AAAA,IACA,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AAaA,eAAsB,WAAA,CAAY,UAAkB,QAAA,EAAyC;AAC3F,EAAA,OAAO,mBAAmB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AAChF;AAGA,SAAS,kBAAA,CAAmB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAC7F,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AAC/C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA,EAAM,OAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AAcA,eAAsB,aAAA,CAAc,UAAkB,QAAA,EAAyC;AAC7F,EAAA,OAAO,qBAAqB,MAAM,uBAAA,CAAwB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACzF;AAGA,SAAS,oBAAA,CAAqB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAC/F,EAAA,IAAI,OAAgC,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,IAAA,GAAQ,KAAA,CAAM,OAAO,CAAA,IAAiC,EAAC;AAAA,EACzD,CAAA,CAAA,MAAQ;AAAA,EAAC;AAET,EAAA,MAAM,WAAyB,EAAC;AAGhC,EAAA,gBAAA,CAAiB,IAAA,CAAK,UAAU,QAAQ,CAAA;AAExC,EAAA,gBAAA,CAAiB,IAAA,CAAK,cAAc,QAAQ,CAAA;AAE5C,EAAA,iBAAA,CAAkB,IAAA,CAAK,SAAA,EAAW,OAAA,EAAS,QAAQ,CAAA;AAEnD,EAAA,iBAAA,CAAkB,IAAA,CAAK,SAAA,EAAW,UAAA,EAAY,QAAQ,CAAA;AAItD,EAAA,KAAA,MAAW,CAAC,KAAA,EAAO,WAAW,CAAA,IAAK;AAAA,IACjC,CAAC,WAAW,SAAS,CAAA;AAAA,IACrB,CAAC,SAAS,SAAS,CAAA;AAAA,IACnB,CAAC,aAAa,WAAW;AAAA,GAC3B,EAAY;AACV,IAAA,gBAAA,CAAiB,IAAA,CAAK,KAAK,CAAA,EAAG,WAAA,EAAa,QAAQ,CAAA;AAAA,EACrD;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA,EAAM,OAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAAA,IAClC,QAAA;AAAA,IACA,cAAc;AAAC,GACjB;AACF;AAcA,eAAsB,YAAA,CAAa,UAAkB,QAAA,EAAyC;AAC5F,EAAA,OAAO,oBAAoB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACjF;AAGA,SAAS,mBAAA,CAAoB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAC9F,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AAC/C,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,IAAA,IAAQ,QAAA,CAAS,QAAQ,CAAA,CAAE,OAAA,CAAQ,eAAA,EAAiB,EAAE,CAAC,CAAA;AAChF,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,IAAA,EAAM,QAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AAaA,eAAsB,YAAA,CAAa,UAAkB,QAAA,EAAyC;AAC5F,EAAA,OAAO,oBAAoB,MAAM,uBAAA,CAAwB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACxF;AAGA,SAAS,mBAAA,CAAoB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAC9F,EAAA,IAAI,OAAgC,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,IAAA,GAAQ,KAAA,CAAM,OAAO,CAAA,IAAiC,EAAC;AAAA,EACzD,CAAA,CAAA,MAAQ;AAAA,EAAC;AAET,EAAA,MAAM,IAAA,GAAO,QAAA,CAAS,QAAQ,CAAA,CAC3B,OAAA,CAAQ,iBAAiB,EAAE,CAAA,CAC3B,OAAA,CAAQ,eAAA,EAAiB,EAAE,CAAA;AAC9B,EAAA,OAAO;AAAA,IACL,MAAM,MAAA,CAAO,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IACzC,IAAA,EAAM,MAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAAA,IAClC,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AAcA,eAAsB,cAAA,CAAe,UAAkB,QAAA,EAAyC;AAC9F,EAAA,OAAO,sBAAsB,MAAM,uBAAA,CAAwB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AAC1F;AAGA,SAAS,qBAAA,CAAsB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAChG,EAAA,IAAI,OAAgC,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,IAAA,GAAQ,KAAA,CAAM,OAAO,CAAA,IAAiC,EAAC;AAAA,EACzD,CAAA,CAAA,MAAQ;AAAA,EAAC;AAET,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,IAAA,IAAQ,QAAA,CAAS,QAAQ,CAAA,CAAE,OAAA,CAAQ,iBAAA,EAAmB,EAAE,CAAC,CAAA;AAElF,EAAA,MAAM,OAAO,IAAA,CAAK,YAAA;AAClB,EAAA,MAAM,YAAA,GAAe,MAAM,OAAA,CAAQ,IAAI,IAAK,IAAA,CAAkB,MAAA,CAAO,OAAO,CAAA,GAAI,EAAC;AAEjF,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,IAAA,EAAM,QAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAAA,IAClC,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B;AAAA,GACF;AACF;AAmBA,eAAsB,cAAc,QAAA,EAAqC;AACvE,EAAA,OAAO,wBAAA,CAAyB,MAAM,uBAAA,CAAwB,QAAQ,GAAG,QAAQ,CAAA;AACnF;AAGA,SAAS,wBAAA,CAAyB,SAAiB,QAAA,EAA4B;AAI7E,EAAA,MAAM,QAAA,GAAW,yCAAA,CAA0C,IAAA,CAAK,QAAQ,CAAA;AACxE,EAAA,IAAI,OAAgC,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,QAAA,GACD,MAAM,OAAO,CAAA,IAAiC,EAAC,GACjD,gBAAA,CAAiB,OAAO,CAAA,CAAE,IAAA;AAAA,EAChC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,MAAM,MAAgB,EAAC;AACvB,EAAA,MAAM,OAAA,GAAU,CAAC,CAAA,KAAe;AAC9B,IAAA,IAAI,KAAA,CAAM,QAAQ,CAAC,CAAA,EAAA;AACjB,MAAA,KAAA,MAAW,CAAA,IAAK,CAAA,EAAG,IAAI,OAAO,CAAA,KAAM,QAAA,IAAY,CAAA,CAAE,IAAA,EAAK,EAAG,GAAA,CAAI,IAAA,CAAK,CAAA,CAAE,MAAM,CAAA;AAAA,IAAA;AAAA,EAC/E,CAAA;AACA,EAAA,OAAA,CAAQ,KAAK,QAAQ,CAAA;AACrB,EAAA,OAAA,CAAS,IAAA,CAAK,UAAkD,QAAQ,CAAA;AACxE,EAAA,OAAA,CAAQ,KAAK,YAAY,CAAA;AACzB,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,GAAG,CAAC,CAAA;AACzB;AAaA,eAAsB,cAAA,CAAe,UAAkB,QAAA,EAAyC;AAC9F,EAAA,OAAO,sBAAsB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACnF;AAGA,SAAS,qBAAA,CAAsB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AAChG,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AAC/C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA,EAAM,UAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AA+BA,eAAsB,eAAA,CAAgB,UAAkB,QAAA,EAAyC;AAC/F,EAAA,OAAO,uBAAuB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACpF;AAYO,SAAS,sBAAA,CACd,OAAA,EACA,QAAA,EACA,QAAA,EACc;AACd,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AAG/C,EAAA,MAAM,WAAoC,EAAC;AAC3C,EAAA,IAAI,KAAK,SAAA,EAAW,QAAA,CAAS,SAAA,GAAY,MAAA,CAAO,KAAK,SAAS,CAAA;AAC9D,EAAA,IAAI,KAAK,OAAA,EAAS,QAAA,CAAS,OAAA,GAAU,MAAA,CAAO,KAAK,OAAO,CAAA;AACxD,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,IAAI,CAAA,WAAY,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,GAAA,CAAI,MAAM,CAAA;AAClE,EAAA,IAAI,IAAA,CAAK,GAAA,IAAO,OAAO,IAAA,CAAK,GAAA,KAAQ,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,GAAG,CAAA,EAAG;AACxE,IAAA,QAAA,CAAS,MAAM,IAAA,CAAK,GAAA;AAAA,EACtB;AACA,EAAA,IAAI,KAAK,GAAA,EAAK,QAAA,CAAS,GAAA,GAAM,MAAA,CAAO,KAAK,GAAG,CAAA;AAC5C,EAAA,IAAI,OAAO,IAAA,CAAK,EAAA,KAAO,QAAA,EAAU,QAAA,CAAS,KAAK,IAAA,CAAK,EAAA;AACpD,EAAA,IAAI,IAAA,CAAK,OAAA,IAAW,OAAO,IAAA,CAAK,OAAA,KAAY,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,OAAO,CAAA,EAAG;AACpF,IAAA,QAAA,CAAS,UAAU,IAAA,CAAK,OAAA;AAAA,EAC1B;AACA,EAAA,IAAI,IAAA,CAAK,MAAA,IAAU,OAAO,IAAA,CAAK,MAAA,KAAW,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA,EAAG;AACjF,IAAA,QAAA,CAAS,SAAS,IAAA,CAAK,MAAA;AAAA,EACzB;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA,EAAM,YAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc,EAAC;AAAA,IACf,UAAU,MAAA,CAAO,IAAA,CAAK,QAAQ,CAAA,CAAE,MAAA,GAAS,IAAI,QAAA,GAAW;AAAA,GAC1D;AACF;AAaA,eAAsB,iBAAA,CAAkB,UAAkB,QAAA,EAAyC;AACjG,EAAA,OAAO,yBAAyB,MAAM,uBAAA,CAAwB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AAC7F;AAGA,SAAS,wBAAA,CACP,OAAA,EACA,QAAA,EACA,QAAA,EACc;AACd,EAAA,IAAI,OAAgC,EAAC;AACrC,EAAA,IAAI;AACF,IAAA,IAAA,GAAQ,KAAA,CAAM,OAAO,CAAA,IAAiC,EAAC;AAAA,EACzD,CAAA,CAAA,MAAQ;AAAA,EAAC;AACT,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAAA,IACrD,IAAA,EAAM,WAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,MAAA,CAAO,IAAA,CAAK,OAAA,IAAW,EAAE,CAAA;AAAA,IAClC,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc;AAAC,GACjB;AACF;AA4BA,eAAsB,eAAA,CAAgB,UAAkB,QAAA,EAAyC;AAC/F,EAAA,OAAO,uBAAuB,MAAM,gBAAA,CAAiB,QAAQ,CAAA,EAAG,UAAU,QAAQ,CAAA;AACpF;AAGA,SAAS,sBAAA,CAAuB,OAAA,EAAiB,QAAA,EAAkB,QAAA,EAAgC;AACjG,EAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAK,GAAI,iBAAiB,OAAO,CAAA;AACrD,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,CAAK,IAAA,IAAQ,SAAS,OAAA,CAAQ,QAAQ,CAAC,CAAC,CAAA;AAC5D,EAAA,OAAO;AAAA,IACL,IAAA;AAAA,IACA,IAAA,EAAM,WAAA;AAAA,IACN,WAAA,EAAa,MAAA,CAAO,IAAA,CAAK,WAAA,IAAe,EAAE,CAAA;AAAA,IAC1C,MAAA,EAAQ,QAAA;AAAA,IACR,SAAA,EAAW,QAAA;AAAA,IACX,OAAA,EAAS,eAAe,IAAI,CAAA;AAAA,IAC5B,QAAA,EAAU,cAAc,IAAI,CAAA;AAAA,IAC5B,cAAc,EAAC;AAAA,IACf,QAAA,EAAU;AAAA,MACR,KAAA,EAAO,KAAK,KAAA,IAAS,cAAA;AAAA,MACrB,QAAA,EAAU,IAAA,CAAK,QAAA,IAAY,EAAC;AAAA,MAC5B,MAAA,EAAQ,IAAA,CAAK,MAAA,IAAU,EAAC;AAAA,MACxB,YAAA,EAAc,KAAK,YAAA,IAAgB,IAAA;AAAA,MACnC;AAAA;AACF,GACF;AACF;AAUO,IAAM,sBAAA,GAAyB;AAG/B,IAAM,wBAAA,GAA2B;AAGjC,IAAM,sBAAA,GAAyB;AAG/B,IAAM,sBAAA,GAAyB;AAG/B,IAAM,wBAAA,GAA2B;AAGjC,IAAM,sBAAA,GAAyB;AAGtC,SAAS,MAAA,CAAO,MAAc,QAAA,EAA0B;AACtD,EAAA,MAAM,GAAA,GAAM,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA;AAC5B,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,QAAA;AAC9B,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,GAAA,EAAK,EAAE,CAAA;AACtC,EAAA,OAAO,OAAO,QAAA,CAAS,MAAM,CAAA,IAAK,MAAA,GAAS,IAAI,MAAA,GAAS,QAAA;AAC1D;AAyDA,IAAI,UAAA;AAGJ,SAAS,eAAe,IAAA,EAA4B;AAClD,EAAA,UAAA,KAAe,aAAa,EAAE,IAAA,EAAM,QAAA,EAAU,OAAA,EAAS,cAAc,CAAA;AACrE,EAAA,UAAA,CAAW,IAAA,CAAK,CAAA,sBAAA,EAAyB,IAAA,CAAK,MAAM,CAAA,+BAAA,CAAA,EAA8B;AAAA,IAChF,GAAG;AAAA,GACJ,CAAA;AACH;AAGA,SAAS,QAAA,CAAS,OAAkB,IAAA,EAA4B;AAC9D,EAAA,IAAI,KAAA,CAAM,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA,EAAG;AACrC,EAAA,KAAA,CAAM,QAAA,CAAS,GAAA,CAAI,IAAA,CAAK,MAAM,CAAA;AAC9B,EAAA,KAAA,CAAM,WAAW,IAAI,CAAA;AACvB;AAOA,eAAe,WAAA,CAAY,MAAc,SAAA,EAAuD;AAC9F,EAAA,MAAM,EAAA,GAAK,MAAM,iBAAA,CAAkB,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAI,MAAM,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,EAAM,SAAS,CAAA;AACpF,EAAA,OAAO,KAAK,CAAA,EAAG,EAAA,CAAG,GAAG,CAAA,CAAA,EAAI,EAAA,CAAG,GAAG,CAAA,CAAA,GAAK,IAAA;AACtC;AASA,eAAe,cAAA,CACb,KACA,KAAA,EACwD;AACxD,EAAA,MAAM,SAAA,GAAY,KAAA,CAAM,UAAA,GAAa,KAAA,CAAM,QAAA;AAC3C,EAAA,IAAI,SAAA,IAAa,GAAG,OAAO,EAAE,SAAS,EAAC,EAAG,QAAQ,IAAA,EAAK;AACvD,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,cAAA;AAAA,MACX,WAAW,GAAG,CAAA,CAAA;AAAA,MACd,YAAY;AACV,QAAA,MAAM,MAAA,GAAS,MAAM,OAAA,CAAQ,GAAG,CAAA;AAChC,QAAA,MAAM,UAAoB,EAAC;AAC3B,QAAA,IAAI,MAAA,GAAS,KAAA;AACb,QAAA,WAAA,MAAiB,KAAK,MAAA,EAAQ;AAM5B,UAAA,IAAI,OAAA,CAAQ,UAAU,SAAA,EAAW;AAC/B,YAAA,MAAA,GAAS,IAAA;AACT,YAAA;AAAA,UACF;AACA,UAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,QAChB;AACA,QAAA,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,EAAG,CAAA,KAAO,EAAE,IAAA,GAAO,CAAA,CAAE,IAAA,GAAO,CAAA,CAAA,GAAK,CAAE,CAAA;AACjD,QAAA,OAAO,EAAE,SAAS,MAAA,EAAO;AAAA,MAC3B,CAAA;AAAA,MACA,KAAA,CAAM;AAAA,KACR;AAAA,EACF,CAAA,CAAA,MAAQ;AAGN,IAAA,QAAA,CAAS,OAAO,EAAE,MAAA,EAAQ,YAAA,EAAc,IAAA,EAAM,KAAK,CAAA;AACnD,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AA8BA,gBAAuB,OAAA,CAAQ,GAAA,EAAa,OAAA,GAAuB,EAAC,EAA8B;AAChG,EAAA,MAAM,KAAA,GAAmB;AAAA,IACvB,QAAA,EAAU,OAAA,CAAQ,QAAA,IAAY,MAAA,CAAO,wBAAwB,sBAAsB,CAAA;AAAA,IACnF,UAAA,EAAY,OAAA,CAAQ,UAAA,IAAc,MAAA,CAAO,0BAA0B,wBAAwB,CAAA;AAAA,IAC3F,aAAa,OAAA,CAAQ,WAAA;AAAA,IACrB,UAAA,EACE,KAAK,GAAA,EAAI,IAAK,QAAQ,QAAA,IAAY,MAAA,CAAO,wBAAwB,sBAAsB,CAAA,CAAA;AAAA,IACzF,QAAA,EAAU,CAAA;AAAA,IACV,SAAA,sBAAe,GAAA,EAAY;AAAA,IAC3B,QAAA,sBAAc,GAAA,EAA8B;AAAA,IAC5C,UAAA,EAAY,QAAQ,UAAA,IAAc;AAAA,GACpC;AAGA,EAAA,MAAM,MAAA,GAAS,MAAM,WAAA,CAAY,GAAA,EAAK,MAAM,WAAW,CAAA;AACvD,EAAA,IAAI,MAAA,EAAQ,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,MAAM,CAAA;AACtC,EAAA,OAAO,QAAA,CAAS,GAAA,EAAK,CAAA,EAAG,KAAK,CAAA;AAC/B;AAEA,gBAAgB,QAAA,CAAS,GAAA,EAAa,KAAA,EAAe,KAAA,EAA6C;AAChG,EAAA,IAAI,KAAA,GAAQ,MAAM,QAAA,EAAU;AAC1B,IAAA,QAAA,CAAS,KAAA,EAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,MAAM,GAAA,EAAK,KAAA,EAAO,KAAA,CAAM,QAAA,EAAU,CAAA;AACrE,IAAA;AAAA,EACF;AACA,EAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,UAAA,EAAY;AAClC,IAAA,QAAA,CAAS,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,IAAA,EAAM,KAAK,CAAA;AAC/C,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,IAAA,GAAO,MAAM,cAAA,CAAe,GAAA,EAAK,KAAK,CAAA;AAC5C,EAAA,IAAI,CAAC,IAAA,EAAM;AACX,EAAA,IAAI,IAAA,CAAK,MAAA,EAAQ,QAAA,CAAS,KAAA,EAAO,EAAE,MAAA,EAAQ,SAAA,EAAW,IAAA,EAAM,GAAA,EAAK,KAAA,EAAO,KAAA,CAAM,UAAA,EAAY,CAAA;AAE1F,EAAA,KAAA,MAAW,CAAA,IAAK,KAAK,OAAA,EAAS;AAC5B,IAAA,IAAI,KAAA,CAAM,QAAA,IAAY,KAAA,CAAM,UAAA,EAAY;AACtC,MAAA,QAAA,CAAS,KAAA,EAAO,EAAE,MAAA,EAAQ,SAAA,EAAW,MAAM,GAAA,EAAK,KAAA,EAAO,KAAA,CAAM,UAAA,EAAY,CAAA;AACzE,MAAA;AAAA,IACF;AACA,IAAA,IAAI,IAAA,CAAK,GAAA,EAAI,IAAK,KAAA,CAAM,UAAA,EAAY;AAClC,MAAA,QAAA,CAAS,OAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,IAAA,EAAM,KAAK,CAAA;AAC/C,MAAA;AAAA,IACF;AACA,IAAA,KAAA,CAAM,QAAA,EAAA;AACN,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,GAAA,EAAK,CAAA,CAAE,IAAI,CAAA;AAE7B,IAAA,IAAI,CAAA,CAAE,gBAAe,EAAG;AAItB,MAAA,MAAM,EAAA,GAAK,MAAM,iBAAA,CAAkB,CAAA,KAAA,EAAQ,IAAI,CAAA,CAAA,EAAI,MAAM,IAAA,CAAK,IAAI,CAAA,EAAG,IAAA,EAAM,KAAA,CAAM,WAAW,CAAA;AAC5F,MAAA,IAAI,CAAC,EAAA,EAAI;AACT,MAAA,IAAI,EAAA,CAAG,aAAY,EAAG;AACpB,QAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,CAAA,CAAE,SAAS,cAAA,EAAgB;AACpD,QAAA,MAAM,KAAK,CAAA,EAAG,EAAA,CAAG,GAAG,CAAA,CAAA,EAAI,GAAG,GAAG,CAAA,CAAA;AAI9B,QAAA,IAAI,KAAA,CAAM,SAAA,CAAU,GAAA,CAAI,EAAE,CAAA,EAAG;AAC3B,UAAA,QAAA,CAAS,OAAO,EAAE,MAAA,EAAQ,OAAA,EAAS,IAAA,EAAM,MAAM,CAAA;AAC/C,UAAA;AAAA,QACF;AACA,QAAA,KAAA,CAAM,SAAA,CAAU,IAAI,EAAE,CAAA;AACtB,QAAA,IAAI;AACF,UAAA,OAAO,QAAA,CAAS,IAAA,EAAM,KAAA,GAAQ,CAAA,EAAG,KAAK,CAAA;AAAA,QACxC,CAAA,SAAE;AAIA,UAAA,KAAA,CAAM,SAAA,CAAU,OAAO,EAAE,CAAA;AAAA,QAC3B;AAAA,MACF,CAAA,MAAO;AACL,QAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,EAAE,IAAA,EAAK;AAAA,MACnC;AAAA,IACF,CAAA,MAAA,IAAW,CAAA,CAAE,WAAA,EAAY,EAAG;AAC1B,MAAA,IAAI,CAAA,CAAE,IAAA,KAAS,MAAA,IAAU,CAAA,CAAE,IAAA,KAAS,cAAA,EAAgB,OAAO,QAAA,CAAS,IAAA,EAAM,KAAA,GAAQ,CAAA,EAAG,KAAK,CAAA;AAAA,IAC5F,CAAA,MAAA,IAAW,CAAA,CAAE,MAAA,EAAO,EAAG;AACrB,MAAA,MAAM,EAAE,IAAA,EAAM,IAAA,EAAM,IAAA,EAAM,EAAE,IAAA,EAAK;AAAA,IACnC;AAAA,EACF;AACF;AAWA,SAAS,mBAAmB,CAAA,EAAuB;AACjD,EAAA,IAAI,gBAAA,CAAiB,CAAA,CAAE,IAAI,CAAA,EAAG;AAC9B,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,gBAAA,CAAiB,EAAE,IAAI,CAAA;AAAA,EAChC,CAAA,CAAA,MAAQ;AACN,IAAA;AAAA,EACF;AACA,EAAA,MAAM,WAAW,CAAA,CAAE,IAAA;AACnB,EAAA,CAAA,CAAE,IAAA,GAAO,IAAA;AACT,EAAA,IAAI,CAAA,CAAE,QAAA,EAAU,WAAA,KAAgB,MAAA,EAAW;AACzC,IAAA,CAAA,CAAE,WAAW,EAAE,GAAG,CAAA,CAAE,QAAA,EAAU,aAAa,QAAA,EAAS;AAAA,EACtD;AACF;AAMA,SAAS,iBAAA,CACP,IAAA,EACA,OAAA,EACA,QAAA,EACA,QAAA,EACqB;AACrB,EAAA,IAAI,SAAS,UAAA,EAAY,OAAO,kBAAA,CAAmB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAC9E,EAAA,IAAI,SAAS,UAAA,EAAY,OAAO,kBAAA,CAAmB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAC9E,EAAA,IAAI,SAAS,YAAA,EAAc,OAAO,oBAAA,CAAqB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAClF,EAAA,IAAI,SAAS,aAAA,EAAe,OAAO,qBAAA,CAAsB,OAAA,EAAS,UAAU,QAAQ,CAAA;AACpF,EAAA,IAAI,SAAS,QAAA,EAAU,OAAO,sBAAA,CAAuB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAChF,EAAA,IAAI,SAAS,cAAA,EAAgB,OAAO,sBAAA,CAAuB,OAAA,EAAS,UAAU,QAAQ,CAAA;AACtF,EAAA,IAAI,SAAS,gBAAA,EAAkB,OAAO,wBAAA,CAAyB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAC1F,EAAA,IAAI,IAAA,CAAK,SAAS,YAAY,CAAA,SAAU,mBAAA,CAAoB,OAAA,EAAS,UAAU,QAAQ,CAAA;AACvF,EAAA,IAAI,IAAA,CAAK,SAAS,cAAc,CAAA,SAAU,qBAAA,CAAsB,OAAA,EAAS,UAAU,QAAQ,CAAA;AAC3F,EAAA,IAAI,KAAK,QAAA,CAAS,YAAY,CAAA,IAAK,IAAA,CAAK,SAAS,YAAY,CAAA;AAC3D,IAAA,OAAO,mBAAA,CAAoB,OAAA,EAAS,QAAA,EAAU,QAAQ,CAAA;AACxD,EAAA,OAAO,IAAA;AACT;AAGA,SAAS,eAAe,IAAA,EAAuB;AAC7C,EAAA,OACE,IAAA,KAAS,UAAA,IACT,IAAA,KAAS,UAAA,IACT,IAAA,KAAS,YAAA,IACT,IAAA,KAAS,aAAA,IACT,IAAA,KAAS,QAAA,IACT,IAAA,KAAS,cAAA,IACT,IAAA,KAAS,gBAAA,IACT,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA,IAC1B,IAAA,CAAK,QAAA,CAAS,cAAc,CAAA,IAC5B,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA,IAC1B,IAAA,CAAK,QAAA,CAAS,YAAY,CAAA;AAE9B;AA4BA,eAAsB,aAAA,CACpB,IAAA,EACA,QAAA,EACA,OAAA,GAAuB,EAAC,EACC;AACzB,EAAA,MAAM,OAAA,uBAAc,GAAA,EAA0B;AAC9C,EAAA,MAAM,UAAA,GAAa,QAAQ,UAAA,IAAc,cAAA;AACzC,EAAA,MAAM,QAAA,uBAAe,GAAA,EAA8B;AACnD,EAAA,MAAM,KAAA,GAAQ,CAAC,IAAA,KAAyB;AACtC,IAAA,QAAA,CAAS,GAAA,CAAI,KAAK,MAAM,CAAA;AACxB,IAAA,UAAA,CAAW,IAAI,CAAA;AAAA,EACjB,CAAA;AACA,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,WAAA,IAAe,YAAA,EAAa;AAExD,EAAA,SAAS,IAAI,CAAA,EAAuB;AAKlC,IAAA,kBAAA,CAAmB,CAAC,CAAA;AACpB,IAAA,MAAM,MAAM,CAAA,EAAG,CAAA,CAAE,IAAI,CAAA,CAAA,EAAI,EAAE,IAAI,CAAA,CAAA;AAC/B,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA;AAChC,IAAA,IAAI,CAAC,QAAA,EAAU;AACb,MAAA,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAC,CAAA;AAClB,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,EAAE,MAAA,GAAS,QAAA,CAAS,QAAQ,OAAA,CAAQ,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,WAAA,MAAiB,EAAE,IAAA,EAAM,QAAA,EAAU,IAAA,EAAK,IAAK,QAAQ,IAAA,EAAM;AAAA,IACzD,GAAG,OAAA;AAAA,IACH,WAAA;AAAA,IACA,UAAA,EAAY;AAAA,GACb,CAAA,EAAG;AACF,IAAA,IAAI,CAAC,cAAA,CAAe,IAAI,CAAA,EAAG;AAC3B,IAAA,MAAM,UAAU,MAAM,iBAAA;AAAA,MACpB,YAAY,QAAQ,CAAA,CAAA;AAAA,MACpB,MAAM,QAAA,CAAS,QAAA,EAAU,MAAM,CAAA;AAAA,MAC/B,IAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAI,YAAY,IAAA,EAAM;AAGpB,MAAA,IAAI,CAAC,QAAA,CAAS,GAAA,CAAI,YAAY,CAAA,EAAG,KAAA,CAAM,EAAE,MAAA,EAAQ,YAAA,EAAc,IAAA,EAAM,QAAA,EAAU,CAAA;AAC/E,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,MAAM,KAAA,GAAQ,iBAAA,CAAkB,IAAA,EAAM,OAAA,EAAS,UAAU,QAAQ,CAAA;AACjE,MAAA,IAAI,KAAA,MAAW,KAAK,CAAA;AAAA,IACtB,CAAA,CAAA,MAAQ;AAAA,IAAC;AAAA,EACX;AAEA,EAAA,OAAO,CAAC,GAAG,OAAA,CAAQ,MAAA,EAAQ,CAAA;AAC7B","file":"chunk-DXUQCMVT.js","sourcesContent":["/**\n * Deadline guards for filesystem work that can land on a network mount.\n *\n * Inside the agent container `/skaile/workspace` **is** an rclone FUSE mount\n * (SharePoint / OneDrive / WebDAV). When the host rclone process wedges, a\n * filesystem call against that path parks in an uninterruptible kernel wait.\n * A **synchronous** call there stops the entire single-threaded event loop —\n * the whole `skaile serve` process stops serving, and the platform reads the\n * session as dead or idle. A hang is not an error, so `try/catch` never fires.\n *\n * Two rules follow, and both matter:\n *\n * 1. **Never touch a mount synchronously.** Async `node:fs/promises` keeps the\n * loop free, so a wedged mount degrades to one stuck request instead of a\n * dead session. This is the actual fix.\n * 2. **Bound the wait.** {@link withFsDeadline} converts an unbounded wait into\n * a bounded failure so the requester gets an error rather than nothing.\n *\n * `withFsDeadline` does **not** cancel the underlying operation — Node cannot\n * abort a syscall already in the kernel. The losing promise stays pending until\n * the mount recovers or the process exits. That is acceptable precisely because\n * rule 1 holds: a pending promise costs one handle, not the event loop.\n *\n * Modelled on `connectors/src/fleet-utils.ts` (`ensureFleetMounted`), which\n * already does async-stat-with-deadline correctly.\n */\n\n/** Default deadline for a single filesystem operation on a possibly-networked mount. */\nexport const DEFAULT_FS_DEADLINE_MS = 15_000;\n\n/**\n * Env override for {@link DEFAULT_FS_DEADLINE_MS}, in milliseconds.\n *\n * A cloud-backed mount over a slow link can legitimately need longer than the\n * default; operators raise this rather than patching call sites.\n */\nexport const FS_DEADLINE_ENV_VAR = \"SKAILE_FS_DEADLINE_MS\";\n\n/**\n * Thrown when a filesystem operation misses its deadline.\n *\n * Distinct from a plain `Error` so callers can tell \"the mount is wedged\" apart\n * from \"the file does not exist\" and surface the right message to the frontend.\n */\nexport class FsDeadlineError extends Error {\n readonly timeoutMs: number;\n readonly operation: string;\n\n constructor(operation: string, timeoutMs: number) {\n super(\n `filesystem operation \"${operation}\" exceeded ${timeoutMs}ms — the mount may be unresponsive`,\n );\n this.name = \"FsDeadlineError\";\n this.operation = operation;\n this.timeoutMs = timeoutMs;\n }\n}\n\n/**\n * Resolve the effective filesystem deadline.\n *\n * Reads {@link FS_DEADLINE_ENV_VAR} on every call rather than caching it: the\n * runner mutates `process.env` while wiring a session, so a module-load-time\n * snapshot would pin the value set before configuration ran.\n *\n * @param fallback - Deadline to use when the env var is absent or unusable.\n * @returns The deadline in milliseconds.\n */\nexport function fsDeadlineMs(fallback: number = DEFAULT_FS_DEADLINE_MS): number {\n const raw = process.env[FS_DEADLINE_ENV_VAR];\n if (raw === undefined) return fallback;\n const parsed = Number.parseInt(raw, 10);\n // A non-positive or non-numeric override would disable the guard entirely,\n // which is exactly the failure mode this module exists to prevent.\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\n/**\n * Run an async filesystem operation under a deadline.\n *\n * @param operation - Short label used in the timeout message (e.g. `\"readdir /skaile/workspace\"`).\n * @param fn - Thunk performing the operation. Called immediately.\n * @param timeoutMs - Deadline override; defaults to {@link fsDeadlineMs}.\n * @returns The operation's result.\n * @throws {FsDeadlineError} when the deadline elapses first.\n * @throws Whatever `fn` rejects with, unchanged, when it loses no race.\n * @docLink packages/core/api-reference#with-fs-deadline\n */\nexport async function withFsDeadline<T>(\n operation: string,\n fn: () => Promise<T>,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<T> {\n let timer: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n fn(),\n new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => reject(new FsDeadlineError(operation, timeoutMs)), timeoutMs);\n // Never hold the process open on the guard alone — without unref a\n // pending deadline would keep `skaile serve` alive after shutdown.\n timer.unref?.();\n }),\n ]);\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\n/**\n * Run an async filesystem operation under a deadline, mapping every failure to\n * `fallback`.\n *\n * For best-effort probes that previously used `existsSync` — a missing file, an\n * unreadable file, and a wedged mount are all \"nothing usable here\", and the\n * caller has no better move than to continue without it.\n *\n * @param operation - Short label used in the timeout message.\n * @param fn - Thunk performing the operation.\n * @param fallback - Value returned when `fn` rejects or the deadline elapses.\n * @param timeoutMs - Deadline override; defaults to {@link fsDeadlineMs}.\n */\nexport async function tryWithFsDeadline<T>(\n operation: string,\n fn: () => Promise<T>,\n fallback: T,\n timeoutMs: number = fsDeadlineMs(),\n): Promise<T> {\n try {\n return await withFsDeadline(operation, fn, timeoutMs);\n } catch {\n return fallback;\n }\n}\n","/**\n * Manifest parsing — reads SKILL.md, AGENT.md, agent.yaml, CONTRACT.md,\n * CONNECTOR.md, *.prompt.md, *.flow.yaml, *.bundle.yaml files and\n * produces CatalogEntry objects.\n * Used by @skaile/asset-manager for on-demand repo scanning.\n *\n * **All filesystem access here is async and bounded** (issue #454). A repo root\n * can resolve onto the rclone FUSE mount at `/skaile/workspace` — either\n * directly (a `sources[].path` pointing into the workspace) or indirectly, since\n * the walk follows symlinks and an off-mount tree can link into one. A\n * synchronous `readdirSync`/`statSync`/`readFileSync` there parks the whole\n * `skaile serve` event loop in an uninterruptible kernel wait, and a hang is not\n * an error so `try/catch` never fires. Every call goes through\n * {@link withFsDeadline}/{@link tryWithFsDeadline}, and the walk itself is\n * bounded by depth, entry count, a wall-clock budget, and an ancestor-inode set.\n */\n\nimport type { Dirent } from \"node:fs\";\nimport { opendir, readFile, stat } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\nimport { parse } from \"yaml\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"./fs-deadline.js\";\nimport { createLogger } from \"./logging/create-logger.js\";\nimport type { AssetKind, CatalogEntry, Dependency } from \"./models.js\";\nimport { isValidAssetName, parseDep, slugifyAssetName } from \"./models.js\";\n\n// ── Bounded manifest I/O ──────────────────────────────────────────────────────\n\n/**\n * Read one manifest file under a deadline.\n *\n * @param filePath - Absolute path to the manifest.\n * @param timeoutMs - Per-operation deadline; defaults to {@link fsDeadlineMs}.\n * @throws {import(\"./fs-deadline.js\").FsDeadlineError} when the read outlives the deadline.\n */\nfunction readManifestFile(filePath: string, timeoutMs?: number): Promise<string> {\n return withFsDeadline(`readFile ${filePath}`, () => readFile(filePath, \"utf8\"), timeoutMs);\n}\n\n/**\n * Read one manifest file under a deadline, degrading an unreadable/slow file to\n * an empty document. Mirrors the pre-#454 `try { readFileSync } catch {}` shape\n * of the YAML parsers: a file we cannot read yields `{}` metadata rather than\n * aborting the caller.\n */\nfunction readManifestFileOrEmpty(filePath: string, timeoutMs?: number): Promise<string> {\n return tryWithFsDeadline(`readFile ${filePath}`, () => readFile(filePath, \"utf8\"), \"\", timeoutMs);\n}\n\n// ── Frontmatter helpers ───────────────────────────────────────────────────────\n\n/**\n * Result of parsing YAML frontmatter from a markdown file.\n * @docLink packages/core/concepts#frontmatter-result\n */\nexport interface FrontmatterResult {\n /** Parsed YAML data. Empty object if no frontmatter block is present. */\n data: Record<string, unknown>;\n /** Markdown body below the frontmatter block (trimmed). */\n body: string;\n}\n\n/**\n * Parse YAML frontmatter from a markdown file (`---` delimited).\n * Returns `{ data: {}, body: text }` when no frontmatter block is present.\n *\n * @param text - Raw file contents\n * @returns Parsed frontmatter data and the remaining body text\n * @docLink packages/core/concepts#parse-frontmatter\n */\nexport function parseFrontmatter(text: string): FrontmatterResult {\n const m = text.match(/^---\\s*\\n([\\s\\S]*?)\\n---/);\n if (!m) return { data: {}, body: text.trim() };\n try {\n const data = (parse(m[1]!) as Record<string, unknown>) ?? {};\n const body = text.slice(m[0].length).trim();\n return { data, body };\n } catch {\n return { data: {}, body: text.trim() };\n }\n}\n\n/** Extract version from frontmatter, checking both top-level and metadata.version. */\nfunction extractVersion(meta: Record<string, unknown>): string {\n return String(\n meta.version ?? (meta.metadata as Record<string, unknown> | undefined)?.version ?? \"\",\n );\n}\n\n/**\n * Parse the `requires:` field from manifest frontmatter into typed `Dependency` objects.\n * Accepts a comma-separated string or an array of `\"kind:name\"` strings. Reads from either\n * the root or `metadata.requires` (matching `extractVersion`'s dual-location behavior) so\n * skill authors can follow the agentskills.io convention of placing skaile extensions under\n * `metadata:` while remaining backward-compatible with root-level declarations.\n *\n * @param meta - Parsed frontmatter data object\n * @returns Array of `Dependency` objects (empty when `requires` is absent)\n * @docLink packages/core/concepts#parse-requires\n */\nexport function parseRequires(meta: Record<string, unknown>): Dependency[] {\n const raw = meta.requires ?? (meta.metadata as Record<string, unknown> | undefined)?.requires;\n if (!raw) return [];\n const list =\n typeof raw === \"string\"\n ? raw.split(\",\").map((s) => s.trim())\n : Array.isArray(raw)\n ? (raw as string[])\n : [];\n return list.filter(Boolean).map(parseDep);\n}\n\n// ── agent.yaml dependency collectors ───────────────────────────────────────────\n\n/**\n * Collect named sub-agent dependencies from an `agent.yaml` array field.\n * Each `{name, ...}` object entry becomes an `{kind: \"agent\", name}` dependency.\n * Covers both the new `requires[]` and legacy `dependencies[]` formats.\n */\nfunction collectAgentDeps(raw: unknown, out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const d of raw) {\n if (typeof d === \"object\" && d !== null && \"name\" in d) {\n out.push({ kind: \"agent\", name: String((d as Record<string, unknown>).name) });\n }\n }\n}\n\n/**\n * Collect string refs from an `agent.yaml` array field (`abilities[]`,\n * `contracts[]`) as `{kind, name}` dependencies, skipping empty entries.\n */\nfunction collectStringRefs(raw: unknown, kind: Dependency[\"kind\"], out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const r of raw) {\n if (typeof r === \"string\" && r) out.push({ kind, name: r });\n }\n}\n\n/**\n * Collect catalog refs from an `agent.yaml` mixin field (`persona`, `rules`,\n * `knowledge`) as requires so `skaile install` pulls them automatically. Local\n * paths (`.`/`/`) are skipped — not catalog assets. Refs without a `kind:`\n * prefix get `defaultKind` injected; the publisher scope and `#pin` are stripped\n * so only `kind:name` is tracked.\n */\nfunction collectMixinRefs(raw: unknown, defaultKind: string, out: Dependency[]): void {\n if (!Array.isArray(raw)) return;\n for (const r of raw) {\n if (typeof r !== \"string\" || !r) continue;\n if (r.startsWith(\".\") || r.startsWith(\"/\")) continue; // local path — skip\n // Normalize: if no kind: prefix, inject the default kind\n const normalized = r.includes(\":\") ? r : `${defaultKind}:${r}`;\n // Only kind:name matters for requires — strip the publisher scope and #pin.\n const colonIdx = normalized.indexOf(\":\");\n const kind = normalized.slice(0, colonIdx).trim();\n let rest = normalized.slice(colonIdx + 1).trim();\n const hashIdx = rest.indexOf(\"#\");\n if (hashIdx !== -1) rest = rest.slice(0, hashIdx).trim();\n let name: string;\n if (rest.startsWith(\"@\")) {\n // Scoped form @publisher/name → name is the segment after the slash.\n const slashIdx = rest.indexOf(\"/\");\n name = slashIdx !== -1 ? rest.slice(slashIdx + 1).trim() : \"\";\n } else {\n // Legacy name@publisher (deprecated) or a bare name.\n const atIdx = rest.indexOf(\"@\");\n name = atIdx !== -1 ? rest.slice(0, atIdx).trim() : rest;\n }\n if (name) out.push({ kind, name });\n }\n}\n\n// ── Manifest parsers ──────────────────────────────────────────────────────────\n\n/**\n * Parse a `SKILL.md` file into a `CatalogEntry`.\n * The `kind` field defaults to `\"skill\"` but can be overridden to `\"agent\"` or `\"prompt\"`\n * via the `type:` frontmatter key. Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `SKILL.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind, name, description, version, and requires\n * @docLink packages/core/concepts#from-skill-md\n */\nexport async function fromSkillMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromSkillMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromSkillMd} core over already-read content (no I/O). */\nfunction fromSkillMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n let kind = String(meta.type ?? \"skill\") as AssetKind;\n if (![\"skill\", \"agent\", \"prompt\", \"persona\", \"ruleset\", \"knowledge\"].includes(kind))\n kind = \"skill\";\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind,\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `AGENT.md` file into a `CatalogEntry` with `kind: \"agent\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `AGENT.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"agent\"`\n * @docLink packages/core/concepts#from-agent-md\n */\nexport async function fromAgentMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromAgentMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromAgentMd} core over already-read content (no I/O). */\nfunction fromAgentMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"agent\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `agent.yaml` file into a `CatalogEntry` with `kind: \"agent\"`.\n * Collects sub-agent dependencies from `requires[]` (new format) and `dependencies[]`\n * (legacy format), skill abilities from `abilities[]`, and contracts from `contracts[]`.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `agent.yaml` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"agent\"` and full dependency graph\n * @docLink packages/core/concepts#from-agent-yaml\n */\nexport async function fromAgentYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromAgentYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromAgentYaml} core over already-read content (no I/O). */\nfunction fromAgentYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const requires: Dependency[] = [];\n\n // Sub-agent dependencies from requires[] (new format: {name, source, ...})\n collectAgentDeps(meta.requires, requires);\n // Legacy sub-agent dependencies from dependencies[] (old format: {name, ...})\n collectAgentDeps(meta.dependencies, requires);\n // Skill abilities referenced in the system prompt\n collectStringRefs(meta.abilities, \"skill\", requires);\n // Contracts referenced in the system prompt (co-located in skills dir)\n collectStringRefs(meta.contracts, \"contract\", requires);\n\n // Mixin composition fields — track catalog refs as requires so `skaile install`\n // automatically pulls them. Local paths (. or /) are skipped — not catalog assets.\n for (const [field, defaultKind] of [\n [\"persona\", \"persona\"],\n [\"rules\", \"ruleset\"],\n [\"knowledge\", \"knowledge\"],\n ] as const) {\n collectMixinRefs(meta[field], defaultKind, requires);\n }\n\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"agent\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires,\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.prompt.md` file into a `CatalogEntry` with `kind: \"prompt\"`.\n * The name defaults to the filename stem (without the `.prompt.md` suffix)\n * when no `name:` frontmatter key is present.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `.prompt.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"prompt\"`\n * @docLink packages/core/concepts#from-prompt-md\n */\nexport async function fromPromptMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromPromptMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromPromptMd} core over already-read content (no I/O). */\nfunction fromPromptMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n const name = String(meta.name ?? basename(filePath).replace(/\\.prompt\\.md$/, \"\"));\n return {\n name,\n kind: \"prompt\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.flow.yaml` or `*.flow.json` file into a `CatalogEntry` with `kind: \"flow\"`.\n * The name resolves from `name:` or `id:` frontmatter, falling back to the filename stem.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the flow definition file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"flow\"`\n * @docLink packages/core/concepts#from-flow-yaml\n */\nexport async function fromFlowYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromFlowYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromFlowYaml} core over already-read content (no I/O). */\nfunction fromFlowYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const stem = basename(filePath)\n .replace(/\\.flow\\.yaml$/, \"\")\n .replace(/\\.flow\\.json$/, \"\");\n return {\n name: String(meta.name ?? meta.id ?? stem),\n kind: \"flow\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `*.bundle.yaml` file into a `CatalogEntry` with `kind: \"bundle\"`.\n * Bundles declare a flat list of string `dependencies` (asset refs) rather than\n * typed `Dependency` objects; both `requires` and `dependencies` are populated.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the bundle YAML file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"bundle\"`\n * @docLink packages/core/concepts#from-bundle-yaml\n */\nexport async function fromBundleYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromBundleYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromBundleYaml} core over already-read content (no I/O). */\nfunction fromBundleYamlContent(content: string, repoName: string, filePath: string): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n\n const name = String(meta.name ?? basename(filePath).replace(/\\.bundle\\.yaml$/, \"\"));\n\n const deps = meta.dependencies;\n const dependencies = Array.isArray(deps) ? (deps as string[]).filter(Boolean) : [];\n\n return {\n name,\n kind: \"bundle\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies,\n };\n}\n\n/**\n * Extract a bundle's raw transitive dependency ref strings from its manifest\n * file — the union of its `requires` and `dependencies` lists, kept verbatim\n * (publisher/pin qualifiers preserved, comments dropped by the parser).\n *\n * Supports `*.bundle.yaml` / `*.flow.{yaml,json}` (top-level\n * `requires`/`dependencies`) and the `BUNDLE.md` frontmatter layout\n * (`requires`/`dependencies`, incl. nested under `metadata`). Unlike\n * {@link parseRequires}, refs are returned as-is — the resolver needs the full\n * `kind:name@<publisher>[#pin]` form, not a publisher-stripped {@link Dependency}.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to a `.bundle.yaml`, `.flow.{yaml,json}`, or `BUNDLE.md`.\n * @returns Deduped list of ref strings; `[]` on parse failure or no deps.\n * @docLink packages/core/concepts#bundle-dep-refs\n */\nexport async function bundleDepRefs(filePath: string): Promise<string[]> {\n return bundleDepRefsFromContent(await readManifestFileOrEmpty(filePath), filePath);\n}\n\n/** Pure {@link bundleDepRefs} core over already-read content (no I/O). */\nfunction bundleDepRefsFromContent(content: string, filePath: string): string[] {\n // `.bundle.yaml` / `.flow.yaml` / `.flow.json` carry their dep list as a\n // top-level document key (`requires`/`dependencies`); `BUNDLE.md` carries it\n // in frontmatter. YAML is a JSON superset, so `parse` reads `.flow.json` too.\n const wholeDoc = /\\.(bundle\\.yaml|flow\\.yaml|flow\\.json)$/.test(filePath);\n let meta: Record<string, unknown> = {};\n try {\n meta = wholeDoc\n ? ((parse(content) as Record<string, unknown>) ?? {})\n : parseFrontmatter(content).data;\n } catch {\n return [];\n }\n const out: string[] = [];\n const collect = (v: unknown) => {\n if (Array.isArray(v))\n for (const x of v) if (typeof x === \"string\" && x.trim()) out.push(x.trim());\n };\n collect(meta.requires);\n collect((meta.metadata as Record<string, unknown> | undefined)?.requires);\n collect(meta.dependencies);\n return [...new Set(out)];\n}\n\n/**\n * Parse a `CONTRACT.md` file into a `CatalogEntry` with `kind: \"contract\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `CONTRACT.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"contract\"`\n * @docLink packages/core/concepts#from-contract-md\n */\nexport async function fromContractMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromContractMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromContractMd} core over already-read content (no I/O). */\nfunction fromContractMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"contract\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse an `MCP.md` file into a `CatalogEntry` with `kind: \"mcp-server\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Frontmatter fields (catalog identity):\n * - `name` — server name (default: parent dir name)\n * - `description` — short description\n * - `version` — semver\n * - `keywords` — array of discovery tags\n *\n * Frontmatter fields (runtime defaults, stored in `metadata`):\n * - `transport` — \"stdio\" | \"sse\" | \"http\" (default: \"stdio\")\n * - `command` — command to execute (stdio)\n * - `args` — command arguments (stdio)\n * - `env` — environment variables (stdio)\n * - `url` — server URL (sse/http)\n * - `headers` — HTTP headers (sse/http)\n *\n * When `mcp:name` appears in `skaile.yaml` `dependencies`, the runner reads\n * these defaults from `metadata` to build a `McpServerDeclaration` without\n * requiring verbose inline config.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `MCP.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"mcp-server\"`\n * @docLink packages/core/concepts#from-mcp-server-md\n */\nexport async function fromMcpServerMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromMcpServerMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/**\n * Parse pre-read MCP.md content into a `CatalogEntry`.\n * Callers that already hold the file content (e.g. to avoid a second read) use\n * this directly; `fromMcpServerMd` is a thin wrapper that reads then delegates here.\n *\n * @param content - UTF-8 content of the `MCP.md` file\n * @param repoName - Repository name used as the `publisher` field of the entry\n * @param filePath - Absolute path (used as `source` and for name fallback)\n * @returns Populated `CatalogEntry` with kind `\"mcp-server\"`\n */\nexport function fromMcpServerMdContent(\n content: string,\n repoName: string,\n filePath: string,\n): CatalogEntry {\n const { data: meta } = parseFrontmatter(content);\n\n // Extract runtime defaults into metadata\n const metadata: Record<string, unknown> = {};\n if (meta.transport) metadata.transport = String(meta.transport);\n if (meta.command) metadata.command = String(meta.command);\n if (Array.isArray(meta.args)) metadata.args = meta.args.map(String);\n if (meta.env && typeof meta.env === \"object\" && !Array.isArray(meta.env)) {\n metadata.env = meta.env as Record<string, string>;\n }\n if (meta.url) metadata.url = String(meta.url);\n if (typeof meta.ca === \"string\") metadata.ca = meta.ca;\n if (meta.headers && typeof meta.headers === \"object\" && !Array.isArray(meta.headers)) {\n metadata.headers = meta.headers as Record<string, string>;\n }\n if (meta.recipe && typeof meta.recipe === \"object\" && !Array.isArray(meta.recipe)) {\n metadata.recipe = meta.recipe;\n }\n\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"mcp-server\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n metadata: Object.keys(metadata).length > 0 ? metadata : undefined,\n };\n}\n\n/**\n * Parse a `knowledge.yaml` file into a `CatalogEntry` with `kind: \"knowledge\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `knowledge.yaml` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"knowledge\"`\n * @docLink packages/core/concepts#from-knowledge-yaml\n */\nexport async function fromKnowledgeYaml(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromKnowledgeYamlContent(await readManifestFileOrEmpty(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromKnowledgeYaml} core over already-read content (no I/O). */\nfunction fromKnowledgeYamlContent(\n content: string,\n repoName: string,\n filePath: string,\n): CatalogEntry {\n let meta: Record<string, unknown> = {};\n try {\n meta = (parse(content) as Record<string, unknown>) ?? {};\n } catch {}\n return {\n name: String(meta.name ?? basename(dirname(filePath))),\n kind: \"knowledge\",\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: String(meta.version ?? \"\"),\n requires: parseRequires(meta),\n dependencies: [],\n };\n}\n\n/**\n * Parse a `CONNECTOR.md` file into a `CatalogEntry` with `kind: \"connector\"`.\n * Falls back to the parent directory name when `name:` is absent.\n *\n * Frontmatter fields (catalog identity):\n * - `name` — connector name (default: parent dir name)\n * - `description` — short description\n * - `version` — semver\n *\n * Frontmatter fields (runtime defaults, stored in `metadata`):\n * - `entry` — adapter entry point (default: \"./adapter.ts\")\n * - `npm_deps` — npm dependencies required by the adapter\n * - `fields` — configuration fields the adapter expects\n * - `health_check` — whether to run a health check on connect\n *\n * The markdown body (below the frontmatter) is stored in `metadata.body`\n * so the runner can inject the connector's skill description into the\n * system prompt when `expose_as_skill` is enabled.\n *\n * Async since #454 — the file may live on the FUSE workspace mount.\n *\n * @param filePath - Absolute path to the `CONNECTOR.md` file\n * @param repoName - Repository name used as the `repository` field of the entry\n * @returns Populated `CatalogEntry` with kind `\"connector\"`\n * @docLink packages/core/concepts#from-connector-md\n */\nexport async function fromConnectorMd(filePath: string, repoName: string): Promise<CatalogEntry> {\n return fromConnectorMdContent(await readManifestFile(filePath), repoName, filePath);\n}\n\n/** Pure {@link fromConnectorMd} core over already-read content (no I/O). */\nfunction fromConnectorMdContent(content: string, repoName: string, filePath: string): CatalogEntry {\n const { data: meta, body } = parseFrontmatter(content);\n const name = String(meta.name ?? basename(dirname(filePath)));\n return {\n name,\n kind: \"connector\" as AssetKind,\n description: String(meta.description ?? \"\"),\n source: filePath,\n publisher: repoName,\n version: extractVersion(meta),\n requires: parseRequires(meta),\n dependencies: [],\n metadata: {\n entry: meta.entry ?? \"./adapter.ts\",\n npm_deps: meta.npm_deps ?? {},\n fields: meta.fields ?? [],\n health_check: meta.health_check ?? null,\n body,\n },\n };\n}\n\n// ── Recursive walker ──────────────────────────────────────────────────────────\n\ninterface WalkEntry {\n path: string;\n name: string;\n}\n\n/** Default maximum directory nesting the walk descends into. */\nexport const DEFAULT_WALK_MAX_DEPTH = 32;\n\n/** Default maximum number of directory entries a single walk may examine. */\nexport const DEFAULT_WALK_MAX_ENTRIES = 50_000;\n\n/** Default wall-clock budget for one whole walk / scan pass, in milliseconds. */\nexport const DEFAULT_WALK_BUDGET_MS = 60_000;\n\n/** Env override for {@link DEFAULT_WALK_MAX_DEPTH}. */\nexport const WALK_MAX_DEPTH_ENV_VAR = \"SKAILE_SCAN_MAX_DEPTH\";\n\n/** Env override for {@link DEFAULT_WALK_MAX_ENTRIES}. */\nexport const WALK_MAX_ENTRIES_ENV_VAR = \"SKAILE_SCAN_MAX_ENTRIES\";\n\n/** Env override for {@link DEFAULT_WALK_BUDGET_MS}. */\nexport const WALK_BUDGET_MS_ENV_VAR = \"SKAILE_SCAN_DEADLINE_MS\";\n\n/** Read a positive-integer env override, falling back when absent or unusable. */\nfunction envInt(name: string, fallback: number): number {\n const raw = process.env[name];\n if (raw === undefined) return fallback;\n const parsed = Number.parseInt(raw, 10);\n return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;\n}\n\n/**\n * Why a walk stopped early. Every one of these means the returned entries are a\n * **partial** view of the tree — never present a truncated walk as complete.\n *\n * @docLink packages/core/concepts#walk-dir\n */\nexport interface WalkTruncation {\n reason: \"depth\" | \"entries\" | \"budget\" | \"cycle\" | \"unreadable\";\n /** Directory (or symlink) at which the bound was hit. */\n path: string;\n /** The bound that was hit, when the reason has a numeric limit. */\n limit?: number;\n}\n\n/**\n * Bounds for {@link walkDir} / {@link scanDirectory}.\n *\n * @docLink packages/core/concepts#walk-dir\n */\nexport interface WalkOptions {\n /** Maximum nesting depth below the root. Default {@link DEFAULT_WALK_MAX_DEPTH}. */\n maxDepth?: number;\n /** Maximum directory entries examined across the whole walk. Default {@link DEFAULT_WALK_MAX_ENTRIES}. */\n maxEntries?: number;\n /**\n * Wall-clock budget for the whole walk. Default {@link DEFAULT_WALK_BUDGET_MS}.\n * The check is inclusive, so `0` yields no entries at all.\n */\n budgetMs?: number;\n /** Per-`opendir`/`stat`/`readFile` deadline. Default {@link fsDeadlineMs}. */\n opTimeoutMs?: number;\n /**\n * Called once per distinct truncation reason. Defaults to a `warn` on the\n * core logger — override to route the signal somewhere the caller can act on.\n */\n onTruncate?: (info: WalkTruncation) => void;\n}\n\n/** Mutable bookkeeping threaded through one walk. */\ninterface WalkState {\n maxDepth: number;\n maxEntries: number;\n opTimeoutMs: number | undefined;\n deadlineAt: number;\n examined: number;\n /**\n * `dev:ino` of the directories on the **current path from the root** — an\n * ancestor stack, not an ever-visited set. Re-entering an ancestor is a cycle;\n * re-reaching a directory off the current path is a diamond, and must be walked.\n */\n ancestors: Set<string>;\n reported: Set<WalkTruncation[\"reason\"]>;\n onTruncate: (info: WalkTruncation) => void;\n}\n\nlet walkLogger: ReturnType<typeof createLogger> | undefined;\n\n/** Default truncation sink — a structured warning naming the bound that was hit. */\nfunction warnTruncation(info: WalkTruncation): void {\n walkLogger ??= createLogger({ kind: \"runner\", subkind: \"asset-scan\" });\n walkLogger.warn(`asset scan truncated (${info.reason}) — results are incomplete`, {\n ...info,\n });\n}\n\n/** Record a truncation once per reason so a wide tree does not spam the log. */\nfunction truncate(state: WalkState, info: WalkTruncation): void {\n if (state.reported.has(info.reason)) return;\n state.reported.add(info.reason);\n state.onTruncate(info);\n}\n\n/**\n * Stable identity (`dev:ino`) of the directory `path` resolves to, or `null`\n * when it cannot be stat'ed within the deadline. Used to terminate symlink\n * cycles — the pre-#454 walker recursed forever on `a/link -> a`.\n */\nasync function dirIdentity(path: string, timeoutMs: number | undefined): Promise<string | null> {\n const st = await tryWithFsDeadline(`stat ${path}`, () => stat(path), null, timeoutMs);\n return st ? `${st.dev}:${st.ino}` : null;\n}\n\n/**\n * Read one directory's entries under a deadline, capped at the walk's remaining\n * entry budget. Uses `opendir` rather than `readdir` so a pathological directory\n * streams instead of materialising in full; entries are collected and sorted\n * because the `scanDirectory` dedup rule (\"alphabetically later source wins\")\n * depends on a deterministic per-level order.\n */\nasync function readDirEntries(\n dir: string,\n state: WalkState,\n): Promise<{ entries: Dirent[]; capped: boolean } | null> {\n const remaining = state.maxEntries - state.examined;\n if (remaining <= 0) return { entries: [], capped: true };\n try {\n return await withFsDeadline(\n `opendir ${dir}`,\n async () => {\n const handle = await opendir(dir);\n const entries: Dirent[] = [];\n let capped = false;\n for await (const e of handle) {\n // Stop *before* keeping the over-budget entry, so `capped` means \"an\n // entry was actually dropped\". Breaking after the push instead marked\n // a directory of exactly `remaining` entries as truncated — and since\n // `truncate()` reports once per reason for the whole walk, that\n // spurious first report swallowed a later genuine one.\n if (entries.length >= remaining) {\n capped = true;\n break;\n }\n entries.push(e);\n }\n entries.sort((a, b) => (a.name < b.name ? -1 : 1));\n return { entries, capped };\n },\n state.opTimeoutMs,\n );\n } catch {\n // Unreadable (permissions, vanished mid-walk) or the mount missed its\n // deadline. Either way this subtree contributes nothing; keep walking.\n truncate(state, { reason: \"unreadable\", path: dir });\n return null;\n }\n}\n\n/**\n * Recursively yield every file entry under `dir`, sorted alphabetically at each\n * level. Skips `.git` and `node_modules` directories and follows symlinks\n * (resolving to the stat target). `node_modules` is excluded because Bun's\n * `node_modules/.bun/...` layout contains symlink farms that form cycles when\n * packages reference each other transitively.\n *\n * **Async and bounded since #454.** A repo root can resolve onto the rclone FUSE\n * mount, where the previous synchronous `readdirSync`/`statSync` walk parked the\n * whole event loop. Four bounds now hold, and hitting any of them reports a\n * {@link WalkTruncation} — a truncated walk is never presented as a complete one:\n *\n * - **depth** ({@link WalkOptions.maxDepth}) — also the backstop for a cycle no\n * inode check can see, e.g. a bind mount of the root inside itself.\n * - **entry count** ({@link WalkOptions.maxEntries}) — total directory entries\n * examined, so an enormous tree cannot run unbounded.\n * - **wall-clock budget** ({@link WalkOptions.budgetMs}) — a wedged mount that\n * times out one operation at a time cannot add up to an unbounded scan.\n * - **ancestor inodes** — the `dev:ino` of every directory on the path from the\n * root is held while its subtree is walked, so `a/link -> a` terminates\n * instead of recursing forever. Two sibling symlinks onto one shared\n * directory are a diamond, not a cycle: both are walked, at the price of\n * visiting the shared subtree twice — bounded by the entry and time budgets.\n *\n * @param dir - Absolute path to the directory to walk\n * @param options - Bounds and truncation sink; see {@link WalkOptions}\n * @docLink packages/core/concepts#walk-dir\n */\nexport async function* walkDir(dir: string, options: WalkOptions = {}): AsyncGenerator<WalkEntry> {\n const state: WalkState = {\n maxDepth: options.maxDepth ?? envInt(WALK_MAX_DEPTH_ENV_VAR, DEFAULT_WALK_MAX_DEPTH),\n maxEntries: options.maxEntries ?? envInt(WALK_MAX_ENTRIES_ENV_VAR, DEFAULT_WALK_MAX_ENTRIES),\n opTimeoutMs: options.opTimeoutMs,\n deadlineAt:\n Date.now() + (options.budgetMs ?? envInt(WALK_BUDGET_MS_ENV_VAR, DEFAULT_WALK_BUDGET_MS)),\n examined: 0,\n ancestors: new Set<string>(),\n reported: new Set<WalkTruncation[\"reason\"]>(),\n onTruncate: options.onTruncate ?? warnTruncation,\n };\n // The root is an ancestor of everything, so it is seeded here and never\n // popped — a self-referential `root/link -> root` is caught on first descent.\n const rootId = await dirIdentity(dir, state.opTimeoutMs);\n if (rootId) state.ancestors.add(rootId);\n yield* walkFrom(dir, 0, state);\n}\n\nasync function* walkFrom(dir: string, depth: number, state: WalkState): AsyncGenerator<WalkEntry> {\n if (depth > state.maxDepth) {\n truncate(state, { reason: \"depth\", path: dir, limit: state.maxDepth });\n return;\n }\n if (Date.now() >= state.deadlineAt) {\n truncate(state, { reason: \"budget\", path: dir });\n return;\n }\n\n const read = await readDirEntries(dir, state);\n if (!read) return;\n if (read.capped) truncate(state, { reason: \"entries\", path: dir, limit: state.maxEntries });\n\n for (const e of read.entries) {\n if (state.examined >= state.maxEntries) {\n truncate(state, { reason: \"entries\", path: dir, limit: state.maxEntries });\n return;\n }\n if (Date.now() >= state.deadlineAt) {\n truncate(state, { reason: \"budget\", path: dir });\n return;\n }\n state.examined++;\n const full = join(dir, e.name);\n\n if (e.isSymbolicLink()) {\n // A symlink is the only way a cycle can enter this walk, so identity is\n // resolved here and nowhere else — one extra stat per link, none per\n // ordinary directory.\n const st = await tryWithFsDeadline(`stat ${full}`, () => stat(full), null, state.opTimeoutMs);\n if (!st) continue;\n if (st.isDirectory()) {\n if (e.name === \".git\" || e.name === \"node_modules\") continue;\n const id = `${st.dev}:${st.ino}`;\n // Only an *ancestor* is a cycle. A target already walked elsewhere in\n // the tree is a diamond (`a/link -> shared`, `b/link -> shared`) and\n // dropping it would silently lose that subtree from the scan.\n if (state.ancestors.has(id)) {\n truncate(state, { reason: \"cycle\", path: full });\n continue;\n }\n state.ancestors.add(id);\n try {\n yield* walkFrom(full, depth + 1, state);\n } finally {\n // finally, not a trailing delete: an early `return` from the bounds\n // checks — or an abandoned consumer — would otherwise leave the\n // ancestor stack holding a directory the walk has already left.\n state.ancestors.delete(id);\n }\n } else {\n yield { path: full, name: e.name };\n }\n } else if (e.isDirectory()) {\n if (e.name !== \".git\" && e.name !== \"node_modules\") yield* walkFrom(full, depth + 1, state);\n } else if (e.isFile()) {\n yield { path: full, name: e.name };\n }\n }\n}\n\n// ── Public scanner ────────────────────────────────────────────────────────────\n\n/**\n * Coerce a scanned entry's `name` to a canonical asset name in place. When the\n * raw name is already canonical this is a no-op; otherwise the original is stashed\n * on `metadata.displayName` (only when not already set) so callers keep the pretty\n * label for display while identity uses the slug. A name that slugifies to empty\n * is left untouched — `parseAssetRef` will reject it downstream with its full hint.\n */\nfunction normalizeEntryName(e: CatalogEntry): void {\n if (isValidAssetName(e.name)) return;\n let slug: string;\n try {\n slug = slugifyAssetName(e.name);\n } catch {\n return;\n }\n const original = e.name;\n e.name = slug;\n if (e.metadata?.displayName === undefined) {\n e.metadata = { ...e.metadata, displayName: original };\n }\n}\n\n/**\n * Build a `CatalogEntry` from an already-read manifest, dispatching on filename.\n * Returns `null` when the filename is not a recognized manifest.\n */\nfunction entryFromManifest(\n name: string,\n content: string,\n filePath: string,\n repoName: string,\n): CatalogEntry | null {\n if (name === \"SKILL.md\") return fromSkillMdContent(content, repoName, filePath);\n if (name === \"AGENT.md\") return fromAgentMdContent(content, repoName, filePath);\n if (name === \"agent.yaml\") return fromAgentYamlContent(content, repoName, filePath);\n if (name === \"CONTRACT.md\") return fromContractMdContent(content, repoName, filePath);\n if (name === \"MCP.md\") return fromMcpServerMdContent(content, repoName, filePath);\n if (name === \"CONNECTOR.md\") return fromConnectorMdContent(content, repoName, filePath);\n if (name === \"knowledge.yaml\") return fromKnowledgeYamlContent(content, repoName, filePath);\n if (name.endsWith(\".prompt.md\")) return fromPromptMdContent(content, repoName, filePath);\n if (name.endsWith(\".bundle.yaml\")) return fromBundleYamlContent(content, repoName, filePath);\n if (name.endsWith(\".flow.yaml\") || name.endsWith(\".flow.json\"))\n return fromFlowYamlContent(content, repoName, filePath);\n return null;\n}\n\n/** Filenames {@link scanDirectory} recognises as asset manifests. */\nfunction isManifestName(name: string): boolean {\n return (\n name === \"SKILL.md\" ||\n name === \"AGENT.md\" ||\n name === \"agent.yaml\" ||\n name === \"CONTRACT.md\" ||\n name === \"MCP.md\" ||\n name === \"CONNECTOR.md\" ||\n name === \"knowledge.yaml\" ||\n name.endsWith(\".prompt.md\") ||\n name.endsWith(\".bundle.yaml\") ||\n name.endsWith(\".flow.yaml\") ||\n name.endsWith(\".flow.json\")\n );\n}\n\n/**\n * Walk `root` recursively and return a `CatalogEntry` for every recognized asset manifest found.\n *\n * Recognized filenames: `SKILL.md`, `AGENT.md`, `agent.yaml`, `CONTRACT.md`, `MCP.md`,\n * `CONNECTOR.md`, `knowledge.yaml`, `*.prompt.md`, `*.bundle.yaml`, `*.flow.yaml`, `*.flow.json`.\n *\n * When two entries share the same `kind:name` key, the one with the alphabetically\n * later source path wins (consistent with catalog precedence rules).\n *\n * **Async and bounded since #454.** `root` can resolve onto the rclone FUSE mount\n * (a `sources[].path` under `/skaile/workspace`), and the walk follows symlinks, so\n * even an off-mount root can descend into one. Every `opendir`/`stat`/`readFile`\n * is deadline-bounded and the walk is capped by depth, entry count, a wall-clock\n * budget, and an ancestor-inode set — see {@link walkDir}. Hitting any bound reports\n * a {@link WalkTruncation} through {@link WalkOptions.onTruncate} (a `warn` by\n * default); the returned array is then a **partial** scan, never a complete one.\n *\n * A manifest that cannot be read within its deadline is skipped rather than\n * failing the whole scan — one unreachable file must not cost the whole catalog.\n *\n * @param root - Absolute path to the directory tree to scan\n * @param repoName - Repository name attached to every produced entry\n * @param options - Walk bounds and truncation sink; see {@link WalkOptions}\n * @returns Array of deduplicated `CatalogEntry` objects, one per manifest file\n * @docLink packages/core/concepts#scan-directory\n */\nexport async function scanDirectory(\n root: string,\n repoName: string,\n options: WalkOptions = {},\n): Promise<CatalogEntry[]> {\n const entries = new Map<string, CatalogEntry>();\n const onTruncate = options.onTruncate ?? warnTruncation;\n const reported = new Set<WalkTruncation[\"reason\"]>();\n const relay = (info: WalkTruncation) => {\n reported.add(info.reason);\n onTruncate(info);\n };\n const opTimeoutMs = options.opTimeoutMs ?? fsDeadlineMs();\n\n function add(e: CatalogEntry): void {\n // Boundary normalization: a third-party source we don't control may name an\n // asset with a human-styled identity (\"Complex App\"). Slugify it to a\n // canonical name so the ref it produces parses, preserving the original on\n // `metadata.displayName` for display. No-op for already-canonical names.\n normalizeEntryName(e);\n const key = `${e.kind}:${e.name}`;\n const existing = entries.get(key);\n if (!existing) {\n entries.set(key, e);\n return;\n }\n // Among duplicates, alphabetically later source path wins\n if (e.source > existing.source) entries.set(key, e);\n }\n\n for await (const { path: filePath, name } of walkDir(root, {\n ...options,\n opTimeoutMs,\n onTruncate: relay,\n })) {\n if (!isManifestName(name)) continue;\n const content = await tryWithFsDeadline(\n `readFile ${filePath}`,\n () => readFile(filePath, \"utf8\"),\n null,\n opTimeoutMs,\n );\n if (content === null) {\n // Unreadable or past its deadline — the catalog loses this asset, not the\n // whole scan. Reported once so a wedged mount is visible in the logs.\n if (!reported.has(\"unreadable\")) relay({ reason: \"unreadable\", path: filePath });\n continue;\n }\n try {\n const entry = entryFromManifest(name, content, filePath, repoName);\n if (entry) add(entry);\n } catch {}\n }\n\n return [...entries.values()];\n}\n"]}