@skaile/workspaces 3.2.1 → 3.4.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 (215) hide show
  1. package/CHANGELOG.md +168 -0
  2. package/dist/{asset-feeds-SEYSNNEM.js → asset-feeds-CBY723RG.js} +11 -11
  3. package/dist/{asset-feeds-SEYSNNEM.js.map → asset-feeds-CBY723RG.js.map} +1 -1
  4. package/dist/asset-manager/catalog-deployer.js +7 -7
  5. package/dist/asset-manager/index.js +10 -10
  6. package/dist/asset-manager/installer.js +7 -7
  7. package/dist/bridge/drivers/claude-sdk.js +8 -8
  8. package/dist/bridge/drivers/codex.js +3 -3
  9. package/dist/bridge/drivers/continue.js +4 -4
  10. package/dist/bridge/drivers/echo.js +3 -3
  11. package/dist/bridge/drivers/gemini.js +5 -5
  12. package/dist/bridge/drivers/goose.js +4 -4
  13. package/dist/bridge/drivers/omp.js +3 -3
  14. package/dist/bridge/drivers/opencode.js +4 -4
  15. package/dist/bridge/drivers/qwen.js +5 -5
  16. package/dist/bridge/index.js +9 -9
  17. package/dist/{chunk-57RFYEVM.js → chunk-2Y2AWWWM.js} +4 -10
  18. package/dist/chunk-2Y2AWWWM.js.map +1 -0
  19. package/dist/{chunk-O6B3ZZ5S.js → chunk-3A3ETJFD.js} +4 -4
  20. package/dist/{chunk-O6B3ZZ5S.js.map → chunk-3A3ETJFD.js.map} +1 -1
  21. package/dist/{chunk-7GOCNYUV.js → chunk-3A5IKBHQ.js} +47 -47
  22. package/dist/{chunk-7GOCNYUV.js.map → chunk-3A5IKBHQ.js.map} +1 -1
  23. package/dist/{chunk-I7S6DFRU.js → chunk-3Q7JDLLH.js} +46 -6
  24. package/dist/chunk-3Q7JDLLH.js.map +1 -0
  25. package/dist/{chunk-PTAUN5CY.js → chunk-3UGP7I2Y.js} +3 -3
  26. package/dist/{chunk-PTAUN5CY.js.map → chunk-3UGP7I2Y.js.map} +1 -1
  27. package/dist/{chunk-CZZRDYT4.js → chunk-4VTBZ2MF.js} +4 -4
  28. package/dist/{chunk-CZZRDYT4.js.map → chunk-4VTBZ2MF.js.map} +1 -1
  29. package/dist/{chunk-U5POE4BA.js → chunk-5Q7HA4JP.js} +3 -3
  30. package/dist/{chunk-U5POE4BA.js.map → chunk-5Q7HA4JP.js.map} +1 -1
  31. package/dist/{chunk-P43HBWKK.js → chunk-6BV24JPZ.js} +36 -7
  32. package/dist/chunk-6BV24JPZ.js.map +1 -0
  33. package/dist/{chunk-AM5LFRXJ.js → chunk-A7XP4C7C.js} +3 -3
  34. package/dist/{chunk-AM5LFRXJ.js.map → chunk-A7XP4C7C.js.map} +1 -1
  35. package/dist/{chunk-ZNIHTT22.js → chunk-AXFOJ2UG.js} +5 -5
  36. package/dist/{chunk-ZNIHTT22.js.map → chunk-AXFOJ2UG.js.map} +1 -1
  37. package/dist/{chunk-PKEAYYEJ.js → chunk-BCXI27BH.js} +219 -4
  38. package/dist/chunk-BCXI27BH.js.map +1 -0
  39. package/dist/{chunk-3HVASHBF.js → chunk-BJ7QIUBM.js} +6 -15
  40. package/dist/chunk-BJ7QIUBM.js.map +1 -0
  41. package/dist/{chunk-CH3UTJBT.js → chunk-BYPQHEI4.js} +6 -6
  42. package/dist/{chunk-CH3UTJBT.js.map → chunk-BYPQHEI4.js.map} +1 -1
  43. package/dist/{chunk-NWFZUQPF.js → chunk-DFZ6QENJ.js} +18 -18
  44. package/dist/{chunk-NWFZUQPF.js.map → chunk-DFZ6QENJ.js.map} +1 -1
  45. package/dist/{chunk-F5VREBV2.js → chunk-ELPR5XBG.js} +40 -3
  46. package/dist/chunk-ELPR5XBG.js.map +1 -0
  47. package/dist/{chunk-MWFYXUFK.js → chunk-G2CXWUO5.js} +4 -4
  48. package/dist/{chunk-MWFYXUFK.js.map → chunk-G2CXWUO5.js.map} +1 -1
  49. package/dist/{chunk-BEAIJRVF.js → chunk-GHWJHOYX.js} +4 -4
  50. package/dist/{chunk-BEAIJRVF.js.map → chunk-GHWJHOYX.js.map} +1 -1
  51. package/dist/{chunk-FLBDLF3I.js → chunk-HGFKNJA5.js} +6 -4
  52. package/dist/chunk-HGFKNJA5.js.map +1 -0
  53. package/dist/{chunk-BK3WL3QK.js → chunk-JAHHMZWG.js} +3 -3
  54. package/dist/{chunk-BK3WL3QK.js.map → chunk-JAHHMZWG.js.map} +1 -1
  55. package/dist/{chunk-UFY2HFLO.js → chunk-KBXYT5HD.js} +4 -4
  56. package/dist/{chunk-UFY2HFLO.js.map → chunk-KBXYT5HD.js.map} +1 -1
  57. package/dist/{chunk-DNYE3SSL.js → chunk-MR3LQTGA.js} +4 -4
  58. package/dist/{chunk-DNYE3SSL.js.map → chunk-MR3LQTGA.js.map} +1 -1
  59. package/dist/{chunk-HCNVX34E.js → chunk-OI36ITDV.js} +8 -8
  60. package/dist/{chunk-HCNVX34E.js.map → chunk-OI36ITDV.js.map} +1 -1
  61. package/dist/{chunk-BEA7RXI3.js → chunk-P6V5GORE.js} +230 -41
  62. package/dist/chunk-P6V5GORE.js.map +1 -0
  63. package/dist/{chunk-2OCYS5EP.js → chunk-PEGIQ67F.js} +4 -4
  64. package/dist/{chunk-2OCYS5EP.js.map → chunk-PEGIQ67F.js.map} +1 -1
  65. package/dist/{chunk-I7MKEZ6J.js → chunk-PHJ2DU6D.js} +3 -3
  66. package/dist/{chunk-I7MKEZ6J.js.map → chunk-PHJ2DU6D.js.map} +1 -1
  67. package/dist/{chunk-NLZYBWVH.js → chunk-POYF2P7E.js} +10 -10
  68. package/dist/{chunk-NLZYBWVH.js.map → chunk-POYF2P7E.js.map} +1 -1
  69. package/dist/{chunk-NU4E7C5I.js → chunk-PW4SJE3X.js} +3 -3
  70. package/dist/{chunk-NU4E7C5I.js.map → chunk-PW4SJE3X.js.map} +1 -1
  71. package/dist/{chunk-Q26C5GLO.js → chunk-RD6MMBHQ.js} +3 -3
  72. package/dist/{chunk-Q26C5GLO.js.map → chunk-RD6MMBHQ.js.map} +1 -1
  73. package/dist/{chunk-46LE3GNY.js → chunk-RUFTB7QN.js} +3 -3
  74. package/dist/{chunk-46LE3GNY.js.map → chunk-RUFTB7QN.js.map} +1 -1
  75. package/dist/{chunk-BKUANJB7.js → chunk-S5N33NGZ.js} +50 -64
  76. package/dist/chunk-S5N33NGZ.js.map +1 -0
  77. package/dist/{chunk-IAIHZRG7.js → chunk-SJQ7544V.js} +7 -7
  78. package/dist/{chunk-IAIHZRG7.js.map → chunk-SJQ7544V.js.map} +1 -1
  79. package/dist/{chunk-VT6HDD2L.js → chunk-SUGDZOYZ.js} +3 -3
  80. package/dist/{chunk-VT6HDD2L.js.map → chunk-SUGDZOYZ.js.map} +1 -1
  81. package/dist/{chunk-XVIFPGYH.js → chunk-U2KIY532.js} +3 -3
  82. package/dist/{chunk-XVIFPGYH.js.map → chunk-U2KIY532.js.map} +1 -1
  83. package/dist/{chunk-HWEW3VII.js → chunk-VFL4STB7.js} +3 -3
  84. package/dist/{chunk-HWEW3VII.js.map → chunk-VFL4STB7.js.map} +1 -1
  85. package/dist/{chunk-DYMWJAL4.js → chunk-VQ4P7UYE.js} +3 -3
  86. package/dist/{chunk-DYMWJAL4.js.map → chunk-VQ4P7UYE.js.map} +1 -1
  87. package/dist/{chunk-KPZZI2KG.js → chunk-ZCIK44M7.js} +3 -3
  88. package/dist/{chunk-KPZZI2KG.js.map → chunk-ZCIK44M7.js.map} +1 -1
  89. package/dist/cli/index.js +396 -409
  90. package/dist/cli/index.js.map +1 -1
  91. package/dist/cli/src/commands/complete-resolvers.d.ts +4 -0
  92. package/dist/cli/src/commands/complete-resolvers.d.ts.map +1 -1
  93. package/dist/cli/src/commands/flow.d.ts +8 -4
  94. package/dist/cli/src/commands/flow.d.ts.map +1 -1
  95. package/dist/cli/src/commands/run.d.ts.map +1 -1
  96. package/dist/cli/src/commands/validate.d.ts.map +1 -1
  97. package/dist/cli/src/flow-discovery.d.ts +31 -15
  98. package/dist/cli/src/flow-discovery.d.ts.map +1 -1
  99. package/dist/cli/src/paths.d.ts +9 -19
  100. package/dist/cli/src/paths.d.ts.map +1 -1
  101. package/dist/connectors/config.js +7 -7
  102. package/dist/connectors/index.js +14 -14
  103. package/dist/core/index.js +6 -6
  104. package/dist/core/logging.js +2 -2
  105. package/dist/core/manifest.js +2 -2
  106. package/dist/core/runtime-assets.js +4 -4
  107. package/dist/core/src/asset-roots.d.ts +74 -0
  108. package/dist/core/src/asset-roots.d.ts.map +1 -0
  109. package/dist/core/src/index.d.ts +1 -0
  110. package/dist/core/src/index.d.ts.map +1 -1
  111. package/dist/core/workspace-config.js +3 -3
  112. package/dist/deploy/index.js +6 -6
  113. package/dist/discovery/index.js +3 -3
  114. package/dist/{ensure-sources-IM3JMW2L.js → ensure-sources-O6AWQXAY.js} +13 -13
  115. package/dist/{ensure-sources-IM3JMW2L.js.map → ensure-sources-O6AWQXAY.js.map} +1 -1
  116. package/dist/factory-assets/connectors/box.js +14 -14
  117. package/dist/factory-assets/connectors/deploy.js +14 -14
  118. package/dist/factory-assets/connectors/devserver.js +14 -14
  119. package/dist/factory-assets/connectors/flow/CONNECTOR.md +42 -9
  120. package/dist/factory-assets/connectors/flow/adapter.d.ts +1 -1
  121. package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
  122. package/dist/factory-assets/connectors/flow/adapter.js +14 -14
  123. package/dist/factory-assets/connectors/flow/engine/index.d.ts +2 -0
  124. package/dist/factory-assets/connectors/flow/engine/index.d.ts.map +1 -1
  125. package/dist/factory-assets/connectors/flow/engine/locate.d.ts +75 -0
  126. package/dist/factory-assets/connectors/flow/engine/locate.d.ts.map +1 -0
  127. package/dist/factory-assets/connectors/flow/engine/node-shape.d.ts +56 -0
  128. package/dist/factory-assets/connectors/flow/engine/node-shape.d.ts.map +1 -1
  129. package/dist/factory-assets/connectors/flow/engine.js +8 -8
  130. package/dist/factory-assets/connectors/flow/index.d.ts +1 -1
  131. package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
  132. package/dist/factory-assets/connectors/flow/node-executor.d.ts +23 -3
  133. package/dist/factory-assets/connectors/flow/node-executor.d.ts.map +1 -1
  134. package/dist/factory-assets/connectors/flow/prompt-fragments.d.ts +4 -0
  135. package/dist/factory-assets/connectors/flow/prompt-fragments.d.ts.map +1 -1
  136. package/dist/factory-assets/connectors/flow/prompt-fragments.js +2 -2
  137. package/dist/factory-assets/connectors/flow/run-flow.d.ts +9 -1
  138. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  139. package/dist/factory-assets/connectors/flow/run-flow.js +16 -16
  140. package/dist/factory-assets/connectors/flow.js +14 -14
  141. package/dist/factory-assets/connectors/git.js +14 -14
  142. package/dist/factory-assets/connectors/gmail.js +14 -14
  143. package/dist/factory-assets/connectors/googledrive.js +14 -14
  144. package/dist/factory-assets/connectors/local.js +14 -14
  145. package/dist/factory-assets/connectors/mattermost.js +14 -14
  146. package/dist/factory-assets/connectors/memory.js +14 -14
  147. package/dist/factory-assets/connectors/minio.js +14 -14
  148. package/dist/factory-assets/connectors/postgres.js +14 -14
  149. package/dist/factory-assets/connectors/s3.js +14 -14
  150. package/dist/factory-assets/connectors/sharepoint.js +14 -14
  151. package/dist/factory-assets/connectors/sqlite.js +14 -14
  152. package/dist/factory-assets/connectors/static-server.js +14 -14
  153. package/dist/factory-assets/connectors/tunnel.js +14 -14
  154. package/dist/factory-assets/connectors/webdav.js +14 -14
  155. package/dist/factory-assets/connectors/xstate-store.js +14 -14
  156. package/dist/factory-assets/connectors/xstate.js +14 -14
  157. package/dist/flows-66NOT5N6.js +20 -0
  158. package/dist/{flows-PBNW6BEH.js.map → flows-66NOT5N6.js.map} +1 -1
  159. package/dist/{helpers-LJFOH4RB.js → helpers-QUGRH2MW.js} +13 -13
  160. package/dist/{helpers-LJFOH4RB.js.map → helpers-QUGRH2MW.js.map} +1 -1
  161. package/dist/library/index.js +8 -8
  162. package/dist/library/install.js +6 -6
  163. package/dist/library/src/config.d.ts +6 -6
  164. package/dist/library/src/config.d.ts.map +1 -1
  165. package/dist/{library-publish-BEFA7OCS.js → library-publish-TCT652H4.js} +18 -18
  166. package/dist/{library-publish-BEFA7OCS.js.map → library-publish-TCT652H4.js.map} +1 -1
  167. package/dist/open-library-6OSZX2O6.js +32 -0
  168. package/dist/{open-library-WJ7P7B4N.js.map → open-library-6OSZX2O6.js.map} +1 -1
  169. package/dist/paths-ESJHWGBR.js +16 -0
  170. package/dist/{paths-2ZZMB7HU.js.map → paths-ESJHWGBR.js.map} +1 -1
  171. package/dist/{plugin-store-EOP3S7OU.js → plugin-store-3BYOBKYT.js} +8 -8
  172. package/dist/{plugin-store-EOP3S7OU.js.map → plugin-store-3BYOBKYT.js.map} +1 -1
  173. package/dist/{project-6RXDBSRV.js → project-5RGSHTZ7.js} +14 -14
  174. package/dist/{project-6RXDBSRV.js.map → project-5RGSHTZ7.js.map} +1 -1
  175. package/dist/resolver/index.js +7 -7
  176. package/dist/runner/index.js +19 -19
  177. package/dist/sdk/asset-manager.js +10 -10
  178. package/dist/sdk/bridge.js +9 -9
  179. package/dist/sdk/core.js +6 -6
  180. package/dist/sdk/flow.js +8 -8
  181. package/dist/sdk/index.js +19 -19
  182. package/dist/sdk/resolver.js +7 -7
  183. package/dist/sdk/runner.js +19 -19
  184. package/dist/sdk/session.js +1 -1
  185. package/dist/session/index.js +1 -1
  186. package/dist/session/src/dispatcher.d.ts +15 -0
  187. package/dist/session/src/dispatcher.d.ts.map +1 -1
  188. package/dist/session/src/workspace-change-digest.d.ts +34 -0
  189. package/dist/session/src/workspace-change-digest.d.ts.map +1 -0
  190. package/dist/{setup-XI7TCIGF.js → setup-X2T3NW7P.js} +11 -11
  191. package/dist/{setup-XI7TCIGF.js.map → setup-X2T3NW7P.js.map} +1 -1
  192. package/dist/skills-TYMTW4V4.js +20 -0
  193. package/dist/{skills-5PJ6YVM7.js.map → skills-TYMTW4V4.js.map} +1 -1
  194. package/dist/{source-TJ457ZRQ.js → source-JS3G5P6Z.js} +17 -17
  195. package/dist/{source-TJ457ZRQ.js.map → source-JS3G5P6Z.js.map} +1 -1
  196. package/dist/{source-manifest-publish-R3Q4MT5W.js → source-manifest-publish-Y7BOFFO4.js} +19 -19
  197. package/dist/{source-manifest-publish-R3Q4MT5W.js.map → source-manifest-publish-Y7BOFFO4.js.map} +1 -1
  198. package/dist/tui/index.js +19 -19
  199. package/dist/workspace-plugin/adapters/mcp.js +11 -11
  200. package/dist/workspace-plugin/adapters/omp.js +7 -7
  201. package/dist/workspace-plugin/index.js +3 -3
  202. package/package.json +1 -1
  203. package/dist/chunk-3HVASHBF.js.map +0 -1
  204. package/dist/chunk-57RFYEVM.js.map +0 -1
  205. package/dist/chunk-BEA7RXI3.js.map +0 -1
  206. package/dist/chunk-BKUANJB7.js.map +0 -1
  207. package/dist/chunk-F5VREBV2.js.map +0 -1
  208. package/dist/chunk-FLBDLF3I.js.map +0 -1
  209. package/dist/chunk-I7S6DFRU.js.map +0 -1
  210. package/dist/chunk-P43HBWKK.js.map +0 -1
  211. package/dist/chunk-PKEAYYEJ.js.map +0 -1
  212. package/dist/flows-PBNW6BEH.js +0 -20
  213. package/dist/open-library-WJ7P7B4N.js +0 -32
  214. package/dist/paths-2ZZMB7HU.js +0 -22
  215. package/dist/skills-5PJ6YVM7.js +0 -20
@@ -26,6 +26,7 @@ function isSubFlowNode(node) {
26
26
  function isActiveRuntimeNode(node) {
27
27
  return isAgentNode(node) || isFunctionNode(node) || isCheckNode(node) || isSubpromptNode(node) || isGateNode(node) || isRouterNode(node) || isSubFlowNode(node);
28
28
  }
29
+ var isExecutableNode = isActiveRuntimeNode;
29
30
  function nodeIsOptional(node) {
30
31
  return node.control?.optional ?? node.data?.optional ?? false;
31
32
  }
@@ -46,6 +47,42 @@ function nodeAssets(node) {
46
47
  const skill = node.type === "skill" && node.data?.skill ? `skill:${node.data.skill}` : void 0;
47
48
  return skill ? [skill, ...legacyAssets] : legacyAssets;
48
49
  }
50
+ function nodeRunKind(node) {
51
+ return node.run?.kind ?? node.type ?? "unknown";
52
+ }
53
+ function nodeIsInert(node) {
54
+ return node.contract?.requires?.some((r) => r.expr.trim() === "false") ?? false;
55
+ }
56
+ function nodeSkillAsset(node) {
57
+ return nodeAssets(node).find((asset) => asset.startsWith("skill:"));
58
+ }
59
+ function nodeSkillVersionPins(node) {
60
+ const fromAssets = nodeAssets(node).flatMap((asset) => {
61
+ if (!asset.startsWith("skill:")) return [];
62
+ const hashIndex = asset.lastIndexOf("#");
63
+ if (hashIndex <= "skill:".length || hashIndex === asset.length - 1) return [];
64
+ const identity = asset.slice("skill:".length, hashIndex);
65
+ return [
66
+ {
67
+ nodeId: node.id,
68
+ skillId: identity.slice(identity.lastIndexOf("/") + 1),
69
+ requestedVersion: asset.slice(hashIndex + 1)
70
+ }
71
+ ];
72
+ });
73
+ if (fromAssets.length > 0) return fromAssets;
74
+ if (node.type !== "skill" || !node.data?.version) return [];
75
+ return [
76
+ {
77
+ nodeId: node.id,
78
+ skillId: node.data.skill ?? node.id,
79
+ requestedVersion: node.data.version
80
+ }
81
+ ];
82
+ }
83
+ function flowSkillVersionPins(flow) {
84
+ return flow.nodes.flatMap((node) => nodeSkillVersionPins(node));
85
+ }
49
86
  function nodeBindings(node) {
50
87
  if (node.contract?.input) return node.contract.input;
51
88
  return node.data?.parameters ?? {};
@@ -57,6 +94,6 @@ function flowDefaults(flow) {
57
94
  return flow.defaults ?? flow.globals ?? {};
58
95
  }
59
96
 
60
- export { deterministicNodeKindLabel, flowDefaults, isActiveRuntimeNode, isAgentNode, isCheckNode, isFunctionNode, isGateNode, isRouterNode, isSubFlowNode, isSubpromptNode, nodeAssets, nodeBindings, nodeInstruction, nodeIsOptional, nodeLabel, nodeRequiresApproval, nodeSkillId };
61
- //# sourceMappingURL=chunk-F5VREBV2.js.map
62
- //# sourceMappingURL=chunk-F5VREBV2.js.map
97
+ export { deterministicNodeKindLabel, flowDefaults, flowSkillVersionPins, isActiveRuntimeNode, isAgentNode, isCheckNode, isExecutableNode, isFunctionNode, isGateNode, isRouterNode, isSubFlowNode, isSubpromptNode, nodeAssets, nodeBindings, nodeInstruction, nodeIsInert, nodeIsOptional, nodeLabel, nodeRequiresApproval, nodeRunKind, nodeSkillAsset, nodeSkillId, nodeSkillVersionPins };
98
+ //# sourceMappingURL=chunk-ELPR5XBG.js.map
99
+ //# sourceMappingURL=chunk-ELPR5XBG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../factory-assets/connectors/flow/engine/node-shape.ts"],"names":[],"mappings":"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","file":"chunk-ELPR5XBG.js","sourcesContent":["import type { FlowVersionNode } from \"@skaile/workspaces/resolver\";\nimport type { FlowDefinition, FlowNode } from \"./types.js\";\n\n/** Returns whether a node is executable by the currently active agent-turn runtime. */\nexport function isAgentNode(node: FlowNode): boolean {\n return node.type === \"skill\" || node.run?.kind === \"agent\";\n}\n\n/** Returns whether a node executes deterministically through NodeExecutor. */\nexport function isFunctionNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"function\" }> } {\n return node.run?.kind === \"function\";\n}\n\n/** Returns whether a node is a deterministic pass/fail verdict evaluated by the runtime. */\nexport function isCheckNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"check\" }> } {\n return node.run?.kind === \"check\";\n}\n\n/** Returns whether a node is a runtime-owned, isolated model call evaluated outside the session conversation. */\nexport function isSubpromptNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"subprompt\" }> } {\n return node.run?.kind === \"subprompt\";\n}\n\n/** Capitalized label for error/summary text — shared by every deterministic-node message site. */\nexport function deterministicNodeKindLabel(kind: \"function\" | \"check\"): string {\n return kind === \"check\" ? \"Check\" : \"Function\";\n}\n\n/** Returns whether a node is a runtime-owned human decision point. */\nexport function isGateNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"gate\" }> } {\n return node.run?.kind === \"gate\";\n}\n\n/** Returns whether a node deterministically selects one declared branch in the engine. */\nexport function isRouterNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"router\" }> } {\n return node.run?.kind === \"router\";\n}\n\n/** Returns whether a node delegates once to an inline child flow. */\nexport function isSubFlowNode(\n node: FlowNode,\n): node is FlowNode & { run: Extract<NonNullable<FlowNode[\"run\"]>, { kind: \"sub-flow\" }> } {\n return node.run?.kind === \"sub-flow\";\n}\n\n/** Returns whether the current runtime owns the node's execution state. */\nexport function isActiveRuntimeNode(node: FlowNode): boolean {\n return (\n isAgentNode(node) ||\n isFunctionNode(node) ||\n isCheckNode(node) ||\n isSubpromptNode(node) ||\n isGateNode(node) ||\n isRouterNode(node) ||\n isSubFlowNode(node)\n );\n}\n\n/** @deprecated Use {@link isActiveRuntimeNode}; gates are active but nobody executes them. */\nexport const isExecutableNode = isActiveRuntimeNode;\n\n/** Returns the node's optional policy across strict v2 and legacy definitions. */\nexport function nodeIsOptional(node: FlowNode): boolean {\n return node.control?.optional ?? node.data?.optional ?? false;\n}\n\n/** Returns the node's mandatory approval policy across strict v2 and legacy definitions. */\nexport function nodeRequiresApproval(node: FlowNode): boolean {\n return node.gate?.approval === \"mandatory\" || node.data?.approval?.mandatory === true;\n}\n\n/** Returns the first declared skill requirement without making it the node identity. */\nexport function nodeSkillId(node: FlowNode): string {\n if (node.type === \"skill\") return node.data?.skill ?? node.id;\n const skillAsset = node.run?.assets?.find((asset) => asset.startsWith(\"skill:\"));\n return skillAsset?.slice(\"skill:\".length).replace(/#.*$/, \"\") ?? node.id;\n}\n\n/** Returns the user-facing node label across strict v2 and legacy definitions. */\nexport function nodeLabel(node: FlowNode): string {\n return node.label ?? node.data?.label ?? nodeSkillId(node);\n}\n\n/** Returns strict v2 run assets or the equivalent legacy declarations. */\nexport function nodeAssets(node: FlowNode): string[] {\n if (node.run?.assets) return node.run.assets;\n const legacyAssets = Array.isArray(node.data?.assets)\n ? node.data.assets.filter((asset): asset is string => typeof asset === \"string\")\n : [];\n const skill = node.type === \"skill\" && node.data?.skill ? `skill:${node.data.skill}` : undefined;\n return skill ? [skill, ...legacyAssets] : legacyAssets;\n}\n\n/**\n * Returns what executes the node, for display and grouping.\n *\n * Strict v2 `run.kind` wins, and every node reaching this through `loadFlow` has\n * one — normalization erases `type`. The legacy fallback only fires for a node\n * handed over un-normalized, so the result is not restricted to the strict v2\n * kind union. Never empty, so it is safe to render directly.\n *\n * A normalized legacy node reports the placeholder kind it became, not the kind\n * it was authored as; pair with {@link nodeIsInert} before showing it to a human.\n */\nexport function nodeRunKind(node: FlowNode): string {\n return node.run?.kind ?? node.type ?? \"unknown\";\n}\n\n/**\n * Returns whether the node is a permanently-blocked placeholder rather than a\n * step that can ever run.\n *\n * `normalizeV1` rewrites every non-executable legacy node — canvas `group`\n * containers, authored `gate`s, unknown kinds — into a router carrying\n * `contract.requires: [{ expr: \"false\" }]` and `control.optional: true`. Both are\n * normalization artifacts: the row is neither a routing step the author wrote nor\n * a step they marked skippable, so rendering either verbatim states something the\n * flow does not say. The false precondition is the surviving signal, and\n * permanent blocking is already its engine semantics.\n */\nexport function nodeIsInert(node: FlowNode): boolean {\n return node.contract?.requires?.some((r) => r.expr.trim() === \"false\") ?? false;\n}\n\n/**\n * Returns the node's first `skill:` asset reference, `#`-range included, or\n * `undefined` when the node requires no skill.\n *\n * Reads through {@link nodeAssets}, so a legacy `type: \"skill\"` node yields a\n * bare `skill:<id>` — the legacy pin lives in `data.version`, never in the ref.\n * Use {@link nodeSkillVersionPins} to read the pin itself.\n */\nexport function nodeSkillAsset(node: FlowNode): string | undefined {\n return nodeAssets(node).find((asset) => asset.startsWith(\"skill:\"));\n}\n\n/**\n * Returns every skill-version pin the node declares, ready for `validateFlowVersions`.\n *\n * Strict v2 pins ride in `run.assets` as `skill:<identity>#<range>`; the legacy\n * `type: \"skill\"` + `data.version` shape is only consulted when no asset pin is\n * present. A skill requirement without a range is *not* a version claim and\n * yields nothing — returning it would make every unpinned node fail the check.\n *\n * Gotcha: refs are parsed by hand, not through `parseAssetRef`, which throws on\n * an unscoped ref like `skill:analyze#^9.0.0`. `skillId` is the segment after the\n * last `/`, so a scoped `skill:@pub/name#range` pins `name`.\n *\n * The legacy branch is unreachable for anything loaded through `loadFlow`, which\n * normalizes `type`/`data` away. `normalizeV1` can only rebuild a `skill:` ref\n * when the node names a skill, so a legacy node pinning `data.version` with no\n * `data.skill` declares no pin at all once normalized — the same thing `skaile\n * run` has always concluded for it.\n */\nexport function nodeSkillVersionPins(node: FlowNode): FlowVersionNode[] {\n const fromAssets = nodeAssets(node).flatMap((asset) => {\n if (!asset.startsWith(\"skill:\")) return [];\n const hashIndex = asset.lastIndexOf(\"#\");\n if (hashIndex <= \"skill:\".length || hashIndex === asset.length - 1) return [];\n const identity = asset.slice(\"skill:\".length, hashIndex);\n return [\n {\n nodeId: node.id,\n skillId: identity.slice(identity.lastIndexOf(\"/\") + 1),\n requestedVersion: asset.slice(hashIndex + 1),\n },\n ];\n });\n if (fromAssets.length > 0) return fromAssets;\n if (node.type !== \"skill\" || !node.data?.version) return [];\n return [\n {\n nodeId: node.id,\n skillId: node.data.skill ?? node.id,\n requestedVersion: node.data.version,\n },\n ];\n}\n\n/** Every skill-version pin declared across a flow, in node-definition order. */\nexport function flowSkillVersionPins(flow: FlowDefinition): FlowVersionNode[] {\n return flow.nodes.flatMap((node) => nodeSkillVersionPins(node));\n}\n\n/** Returns the binding values already supplied at the node boundary. */\nexport function nodeBindings(node: FlowNode): Record<string, unknown> {\n if (node.contract?.input) return node.contract.input;\n return node.data?.parameters ?? {};\n}\n\n/** Returns the first-class instruction for a strict v2 agent or subprompt node. */\nexport function nodeInstruction(node: FlowNode): string | undefined {\n return node.run?.kind === \"agent\" || node.run?.kind === \"subprompt\"\n ? node.run.instruction\n : undefined;\n}\n\n/** Returns run-scoped defaults across strict v2 and legacy definitions. */\nexport function flowDefaults(flow: FlowDefinition): Record<string, unknown> {\n return flow.defaults ?? flow.globals ?? {};\n}\n"]}
@@ -1,6 +1,6 @@
1
- import { findAiAssetsRoot } from './chunk-BK3WL3QK.js';
1
+ import { findAiAssetsRoot } from './chunk-JAHHMZWG.js';
2
2
  import { okJson, err, ok } from './chunk-X5YPJV4N.js';
3
- import { parseSkillRequirements, validateRequirements, buildRequiresPreamble, parseSkillFrontmatter } from './chunk-CZZRDYT4.js';
3
+ import { parseSkillRequirements, validateRequirements, buildRequiresPreamble, parseSkillFrontmatter } from './chunk-4VTBZ2MF.js';
4
4
  import fs from 'fs/promises';
5
5
  import path from 'path';
6
6
 
@@ -162,5 +162,5 @@ async function skillGetPreamble(projectDir, skillId) {
162
162
  }
163
163
 
164
164
  export { skillCheckRequirements, skillGetPreamble, skillList, skillListDomains, skillSearch, skillShow };
165
- //# sourceMappingURL=chunk-MWFYXUFK.js.map
166
- //# sourceMappingURL=chunk-MWFYXUFK.js.map
165
+ //# sourceMappingURL=chunk-G2CXWUO5.js.map
166
+ //# sourceMappingURL=chunk-G2CXWUO5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../workspace-plugin/src/tools/skills.ts"],"names":[],"mappings":"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","file":"chunk-MWFYXUFK.js","sourcesContent":["// src/tools/skills.ts\n\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n buildRequiresPreamble,\n parseSkillFrontmatter,\n parseSkillRequirements,\n validateRequirements,\n} from \"@skaile/workspaces/resolver\";\nimport type { ToolResult } from \"../types.js\";\nimport { err, ok, okJson } from \"../types.js\";\nimport { findAiAssetsRoot } from \"../utils/ai-assets.js\";\n\ninterface SkillEntry {\n id: string;\n name: string;\n description: string;\n source?: string;\n version?: string;\n keywords?: string[];\n path: string;\n domain: string;\n}\n\nasync function walkForSkillMd(dir: string, domain: string, acc: SkillEntry[]): Promise<void> {\n let entries: Dirent<string>[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n // Check if this directory contains a SKILL.md\n const hasSkillMd = entries.some((e) => e.isFile() && e.name === \"SKILL.md\");\n if (hasSkillMd) {\n const skillMdPath = path.join(dir, \"SKILL.md\");\n try {\n const content = await fs.readFile(skillMdPath, \"utf-8\");\n const fm = parseSkillFrontmatter(content);\n const name = typeof fm.name === \"string\" ? fm.name : path.basename(dir);\n const description = typeof fm.description === \"string\" ? fm.description : \"\";\n const source = typeof fm.source === \"string\" ? fm.source : undefined;\n const version = typeof fm.version === \"string\" ? fm.version : undefined;\n const keywords = Array.isArray(fm.keywords) ? (fm.keywords as string[]) : undefined;\n acc.push({\n id: path.basename(dir),\n name,\n description,\n source,\n version,\n keywords,\n path: skillMdPath,\n domain,\n });\n } catch {\n // skip unreadable files\n }\n return; // don't recurse inside a skill directory\n }\n\n // Recurse into subdirectories\n for (const entry of entries) {\n if (entry.isDirectory()) {\n await walkForSkillMd(path.join(dir, entry.name), domain, acc);\n }\n }\n}\n\nasync function scanSkills(aiAssetsRoot: string, domainFilter?: string): Promise<SkillEntry[]> {\n let domains: string[];\n try {\n const entries = await fs.readdir(aiAssetsRoot, { withFileTypes: true });\n domains = entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .filter((name) => !domainFilter || name === domainFilter);\n } catch {\n return [];\n }\n\n const acc: SkillEntry[] = [];\n for (const domain of domains) {\n const skillsDir = path.join(aiAssetsRoot, domain, \"skills\");\n try {\n await fs.access(skillsDir);\n } catch {\n continue; // no skills/ dir in this domain\n }\n await walkForSkillMd(skillsDir, domain, acc);\n }\n return acc;\n}\n\n// ── Exported tool functions ────────────────────────────────────────────────────\n\n/**\n * List all skills in the `ai-assets` catalog, optionally filtered by domain.\n *\n * Walks every `<domain>/skills/` directory under the `ai-assets` root looking\n * for `SKILL.md` files. Returns a JSON array of skill summaries\n * `{ id, name, description, source, version, keywords, domain }`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param domain - Optional domain name filter (e.g. `\"skaile-development\"`).\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillList(\n projectDir: string,\n domain: string | undefined,\n): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const skills = await scanSkills(aiAssetsRoot, domain);\n return okJson(\n skills.map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n source: s.source,\n version: s.version,\n keywords: s.keywords,\n domain: s.domain,\n })),\n );\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * List all skill domains — the top-level directories under `ai-assets` that\n * contain a `skills/` subdirectory.\n *\n * Returns a JSON array of `{ name, path }` objects.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillListDomains(projectDir: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const entries = await fs.readdir(aiAssetsRoot, { withFileTypes: true });\n const domains = entries\n .filter((e) => e.isDirectory())\n .map((e) => ({ name: e.name, path: path.join(aiAssetsRoot, e.name) }));\n return okJson(domains);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Show the full `SKILL.md` content for a skill.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param skillId - Skill ID (directory name) as returned by {@link skillList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillShow(projectDir: string, skillId: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n return ok(content);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Search skills by name, description, ID, or keywords.\n *\n * Case-insensitive substring match against all text fields in every skill\n * entry. Returns the same summary shape as {@link skillList}.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param query - Search string.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillSearch(projectDir: string, query: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const q = query.toLowerCase();\n const matched = skills.filter(\n (s) =>\n s.name.toLowerCase().includes(q) ||\n s.description.toLowerCase().includes(q) ||\n s.id.toLowerCase().includes(q) ||\n (s.keywords ?? []).some((k) => k.toLowerCase().includes(q)),\n );\n return okJson(\n matched.map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n source: s.source,\n version: s.version,\n keywords: s.keywords,\n domain: s.domain,\n })),\n );\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Validate that all prerequisites declared in a skill's `SKILL.md` are\n * satisfied in `targetDir`.\n *\n * Uses `@skaile/workspaces/resolver` to parse the `REQUIRES` / `READS` / `WRITES`\n * DSL and run the requirement checks against the filesystem. Returns a\n * validation report as JSON.\n *\n * @param projectDir - Absolute path to the skaile project root (for skill lookup).\n * @param skillId - Skill ID as returned by {@link skillList}.\n * @param targetDir - Directory to validate against (typically the user's project).\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillCheckRequirements(\n projectDir: string,\n skillId: string,\n targetDir: string,\n): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n\n const requirements = parseSkillRequirements(content);\n const report = await validateRequirements(skillId, requirements, targetDir);\n return okJson(report);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Get the formatted `REQUIRES`/`INPUT`/`READS`/`WRITES` DSL preamble for a skill.\n *\n * Uses `@skaile/workspaces/resolver` to build the requirements preamble that can be\n * prepended to the skill prompt for injection into the agent's context.\n * Returns `\"(no requirements declared)\"` when the skill has no requirements.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param skillId - Skill ID as returned by {@link skillList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillGetPreamble(projectDir: string, skillId: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n\n const requirements = parseSkillRequirements(content);\n const preamble = buildRequiresPreamble(requirements, skillId);\n return ok(preamble || \"(no requirements declared)\");\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n"]}
1
+ {"version":3,"sources":["../workspace-plugin/src/tools/skills.ts"],"names":[],"mappings":"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","file":"chunk-G2CXWUO5.js","sourcesContent":["// src/tools/skills.ts\n\nimport type { Dirent } from \"node:fs\";\nimport fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport {\n buildRequiresPreamble,\n parseSkillFrontmatter,\n parseSkillRequirements,\n validateRequirements,\n} from \"@skaile/workspaces/resolver\";\nimport type { ToolResult } from \"../types.js\";\nimport { err, ok, okJson } from \"../types.js\";\nimport { findAiAssetsRoot } from \"../utils/ai-assets.js\";\n\ninterface SkillEntry {\n id: string;\n name: string;\n description: string;\n source?: string;\n version?: string;\n keywords?: string[];\n path: string;\n domain: string;\n}\n\nasync function walkForSkillMd(dir: string, domain: string, acc: SkillEntry[]): Promise<void> {\n let entries: Dirent<string>[];\n try {\n entries = await fs.readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n\n // Check if this directory contains a SKILL.md\n const hasSkillMd = entries.some((e) => e.isFile() && e.name === \"SKILL.md\");\n if (hasSkillMd) {\n const skillMdPath = path.join(dir, \"SKILL.md\");\n try {\n const content = await fs.readFile(skillMdPath, \"utf-8\");\n const fm = parseSkillFrontmatter(content);\n const name = typeof fm.name === \"string\" ? fm.name : path.basename(dir);\n const description = typeof fm.description === \"string\" ? fm.description : \"\";\n const source = typeof fm.source === \"string\" ? fm.source : undefined;\n const version = typeof fm.version === \"string\" ? fm.version : undefined;\n const keywords = Array.isArray(fm.keywords) ? (fm.keywords as string[]) : undefined;\n acc.push({\n id: path.basename(dir),\n name,\n description,\n source,\n version,\n keywords,\n path: skillMdPath,\n domain,\n });\n } catch {\n // skip unreadable files\n }\n return; // don't recurse inside a skill directory\n }\n\n // Recurse into subdirectories\n for (const entry of entries) {\n if (entry.isDirectory()) {\n await walkForSkillMd(path.join(dir, entry.name), domain, acc);\n }\n }\n}\n\nasync function scanSkills(aiAssetsRoot: string, domainFilter?: string): Promise<SkillEntry[]> {\n let domains: string[];\n try {\n const entries = await fs.readdir(aiAssetsRoot, { withFileTypes: true });\n domains = entries\n .filter((e) => e.isDirectory())\n .map((e) => e.name)\n .filter((name) => !domainFilter || name === domainFilter);\n } catch {\n return [];\n }\n\n const acc: SkillEntry[] = [];\n for (const domain of domains) {\n const skillsDir = path.join(aiAssetsRoot, domain, \"skills\");\n try {\n await fs.access(skillsDir);\n } catch {\n continue; // no skills/ dir in this domain\n }\n await walkForSkillMd(skillsDir, domain, acc);\n }\n return acc;\n}\n\n// ── Exported tool functions ────────────────────────────────────────────────────\n\n/**\n * List all skills in the `ai-assets` catalog, optionally filtered by domain.\n *\n * Walks every `<domain>/skills/` directory under the `ai-assets` root looking\n * for `SKILL.md` files. Returns a JSON array of skill summaries\n * `{ id, name, description, source, version, keywords, domain }`.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param domain - Optional domain name filter (e.g. `\"skaile-development\"`).\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillList(\n projectDir: string,\n domain: string | undefined,\n): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const skills = await scanSkills(aiAssetsRoot, domain);\n return okJson(\n skills.map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n source: s.source,\n version: s.version,\n keywords: s.keywords,\n domain: s.domain,\n })),\n );\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * List all skill domains — the top-level directories under `ai-assets` that\n * contain a `skills/` subdirectory.\n *\n * Returns a JSON array of `{ name, path }` objects.\n *\n * @param projectDir - Absolute path to the skaile project root.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillListDomains(projectDir: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const entries = await fs.readdir(aiAssetsRoot, { withFileTypes: true });\n const domains = entries\n .filter((e) => e.isDirectory())\n .map((e) => ({ name: e.name, path: path.join(aiAssetsRoot, e.name) }));\n return okJson(domains);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Show the full `SKILL.md` content for a skill.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param skillId - Skill ID (directory name) as returned by {@link skillList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillShow(projectDir: string, skillId: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n return ok(content);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Search skills by name, description, ID, or keywords.\n *\n * Case-insensitive substring match against all text fields in every skill\n * entry. Returns the same summary shape as {@link skillList}.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param query - Search string.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillSearch(projectDir: string, query: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return okJson([]);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const q = query.toLowerCase();\n const matched = skills.filter(\n (s) =>\n s.name.toLowerCase().includes(q) ||\n s.description.toLowerCase().includes(q) ||\n s.id.toLowerCase().includes(q) ||\n (s.keywords ?? []).some((k) => k.toLowerCase().includes(q)),\n );\n return okJson(\n matched.map((s) => ({\n id: s.id,\n name: s.name,\n description: s.description,\n source: s.source,\n version: s.version,\n keywords: s.keywords,\n domain: s.domain,\n })),\n );\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Validate that all prerequisites declared in a skill's `SKILL.md` are\n * satisfied in `targetDir`.\n *\n * Uses `@skaile/workspaces/resolver` to parse the `REQUIRES` / `READS` / `WRITES`\n * DSL and run the requirement checks against the filesystem. Returns a\n * validation report as JSON.\n *\n * @param projectDir - Absolute path to the skaile project root (for skill lookup).\n * @param skillId - Skill ID as returned by {@link skillList}.\n * @param targetDir - Directory to validate against (typically the user's project).\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillCheckRequirements(\n projectDir: string,\n skillId: string,\n targetDir: string,\n): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n\n const requirements = parseSkillRequirements(content);\n const report = await validateRequirements(skillId, requirements, targetDir);\n return okJson(report);\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n\n/**\n * Get the formatted `REQUIRES`/`INPUT`/`READS`/`WRITES` DSL preamble for a skill.\n *\n * Uses `@skaile/workspaces/resolver` to build the requirements preamble that can be\n * prepended to the skill prompt for injection into the agent's context.\n * Returns `\"(no requirements declared)\"` when the skill has no requirements.\n *\n * @param projectDir - Absolute path to the skaile project root.\n * @param skillId - Skill ID as returned by {@link skillList}.\n *\n * @docLink packages/workspace-plugin/concepts#tool-delivery\n */\nexport async function skillGetPreamble(projectDir: string, skillId: string): Promise<ToolResult> {\n try {\n const aiAssetsRoot = await findAiAssetsRoot(projectDir);\n if (!aiAssetsRoot) return err(`Skill not found: ${skillId}`);\n const skills = await scanSkills(aiAssetsRoot, undefined);\n const skill = skills.find((s) => s.id === skillId);\n if (!skill) return err(`Skill not found: ${skillId}`);\n const content = await fs.readFile(skill.path, \"utf-8\");\n\n const requirements = parseSkillRequirements(content);\n const preamble = buildRequiresPreamble(requirements, skillId);\n return ok(preamble || \"(no requirements declared)\");\n } catch (e: unknown) {\n return err(e instanceof Error ? e.message : String(e));\n }\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { tryWithFsDeadline, withFsDeadline, fsDeadlineMs } from './chunk-DYMWJAL4.js';
2
- import { createLogger } from './chunk-7GOCNYUV.js';
1
+ import { tryWithFsDeadline, withFsDeadline, fsDeadlineMs } from './chunk-VQ4P7UYE.js';
2
+ import { createLogger } from './chunk-3A5IKBHQ.js';
3
3
  import { stat, mkdir, cp, writeFile, rm } from 'fs/promises';
4
4
  import { resolve, sep, join } from 'path';
5
5
 
@@ -155,5 +155,5 @@ function resolveFlowSkills(flow, allEntries) {
155
155
  }
156
156
 
157
157
  export { WORKSPACE_MOUNT_ENV_VAR, deployAll, deployCatalogEntry, findAiAssetsRoot, isUnderWorkspaceMount, resolveFlowSkills, undeployCatalogEntry, workspaceMountDirs };
158
- //# sourceMappingURL=chunk-BEAIJRVF.js.map
159
- //# sourceMappingURL=chunk-BEAIJRVF.js.map
158
+ //# sourceMappingURL=chunk-GHWJHOYX.js.map
159
+ //# sourceMappingURL=chunk-GHWJHOYX.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../asset-manager/src/catalog-deployer.ts"],"names":[],"mappings":"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","file":"chunk-BEAIJRVF.js","sourcesContent":["/**\n * Platform-triggered asset deployment.\n *\n * Takes catalog entries (with source_path relative to ai-assets/) and deploys\n * them to a session's .claude/skills/ directory. Handles skill context injection\n * and catalog priority-based name resolution.\n */\n\nimport { cp, mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve, sep } from \"node:path\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"@skaile/workspaces/core\";\nimport { createLogger } from \"@skaile/workspaces/core/logging\";\n\n// ---------------------------------------------------------------------------\n// Types (formerly in catalog-compiler.ts, inlined after tear-out in Task 1.5)\n// ---------------------------------------------------------------------------\n\n/**\n * A single user-facing input parameter declared in a SKILL.md.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface InputSpec {\n /** Input parameter key used in skill invocation. */\n key: string;\n /** Whether the input must be provided before running the skill. */\n required?: boolean;\n /** Question string shown to the user when collecting this input. */\n prompt?: string;\n /** Short display label for UI forms. */\n label?: string;\n /** Input data type hint (e.g. `\"string\"`, `\"number\"`, `\"file\"`). */\n type?: string;\n /** Additional guidance text shown alongside the input field. */\n hint?: string;\n}\n\n/**\n * A compiled catalog entry (skill or flow).\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface CatalogEntryCompiled {\n /** Unique ID in `domain/name` form (e.g. `skaileup-conceptualization/cf_overview`). */\n id: string;\n /** Asset kind. */\n kind: \"skill\" | \"flow\";\n /** Human-readable asset name. */\n name: string;\n /** One-line description. */\n description: string;\n /** Semantic version string. */\n version: string;\n /** Maturity stage. */\n stage: \"alpha\" | \"beta\" | \"stable\";\n /** Searchable keywords. */\n keywords: string[];\n /** User-facing input specifications. */\n inputs: InputSpec[];\n /** Domain directory name. */\n source_domain: string;\n /** Asset path relative to assetsRoot. */\n source_path: string;\n /** Optional icon identifier. */\n icon?: string;\n /** Flow-only: required skill names. */\n required_skills?: string[];\n /** Flow-only: optional skill names. */\n optional_skills?: string[];\n}\n\n/**\n * Options controlling how platform-triggered skill deployment is performed.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface DeployFromCatalogOptions {\n /** Root directory of ai-assets (where `source_path` in catalog entries is relative to). */\n assetsRoot: string;\n /** Target directory for deployed skills (e.g. `/workspace/.claude/skills/`). */\n skillsDir: string;\n /** Optional context markdown appended to the deployed skill directory as `CONTEXT.md`. */\n context?: string;\n}\n\n/**\n * Result of a platform-triggered batch skill deployment.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface DeployResult {\n /** IDs of catalog entries successfully deployed. */\n deployed: string[];\n /** IDs of catalog entries skipped (non-skill kinds). */\n skipped: string[];\n /** Error messages for entries that could not be deployed. */\n errors: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Workspace-mount awareness\n// ---------------------------------------------------------------------------\n\n/**\n * Multiplier applied to the base filesystem deadline for whole-tree operations\n * (recursive copy / remove), which legitimately outlast a single `stat`.\n */\nconst TREE_OP_DEADLINE_FACTOR = 4;\n\n/** Default number of parent levels {@link findAiAssetsRoot} inspects. */\nconst AI_ASSETS_WALK_LEVELS = 6;\n\nlet deployerLogger: ReturnType<typeof createLogger> | undefined;\n\nfunction log(): ReturnType<typeof createLogger> {\n deployerLogger ??= createLogger({ kind: \"runner\", subkind: \"catalog-deployer\" });\n return deployerLogger;\n}\n\n/**\n * Where the agent container binds its rclone FUSE mount. Nothing under this\n * path is a safe place to read an asset tree from: the mount is remote\n * (SharePoint / OneDrive / WebDAV) and can wedge indefinitely.\n */\nconst DEFAULT_WORKSPACE_MOUNT_DIR = \"/skaile/workspace\";\n\n/**\n * Env override for the workspace-mount path(s), comma-separated.\n *\n * Set it when the runner binds the mount somewhere other than\n * {@link DEFAULT_WORKSPACE_MOUNT_DIR}; set it to the empty string to disable\n * the guard entirely (single-machine dev, where nothing is a network mount).\n */\nexport const WORKSPACE_MOUNT_ENV_VAR = \"SKAILE_WORKSPACE_MOUNT_DIR\";\n\n/**\n * Resolve the directories treated as network mounts.\n *\n * Read per call rather than cached: the runner mutates `process.env` while\n * wiring a session, so a module-load snapshot would pin a pre-configuration\n * value.\n *\n * @returns Absolute mount paths; empty when the guard is disabled.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function workspaceMountDirs(): string[] {\n const raw = process.env[WORKSPACE_MOUNT_ENV_VAR];\n if (raw === undefined) return [DEFAULT_WORKSPACE_MOUNT_DIR];\n return raw\n .split(\",\")\n .map((segment) => segment.trim())\n .filter((segment) => segment.length > 0)\n .map((segment) => resolve(segment));\n}\n\n/**\n * Is `candidate` at, or inside, one of the known workspace mount paths?\n *\n * Pure path arithmetic — deliberately no filesystem access, because the whole\n * point is to decide *before* touching a path that might be unresponsive.\n *\n * @param candidate - Path to test.\n * @param mountDirs - Mount roots; defaults to {@link workspaceMountDirs}.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function isUnderWorkspaceMount(\n candidate: string,\n mountDirs: string[] = workspaceMountDirs(),\n): boolean {\n const target = resolve(candidate);\n return mountDirs.some((dir) => {\n const root = resolve(dir);\n return target === root || target.startsWith(root + sep);\n });\n}\n\n/**\n * Walk upward from `startDir` looking for an `ai-assets/` directory.\n *\n * Two properties matter beyond \"find the folder\":\n *\n * 1. **Never synchronous.** The walk probes up to six directories; any one of\n * them can be on a FUSE mount, and the former `existsSync` chain blocked the\n * event loop on the first unresponsive probe. Each probe is now awaited and\n * deadline-bounded, so a wedged mount costs one skipped candidate.\n * 2. **Never resolves onto a mount.** A hit under the workspace mount is\n * skipped with a warning rather than returned: accepting it would wire every\n * later skill deploy — a recursive copy — to a remote filesystem. The walk\n * continues upward, so a legitimate `ai-assets/` in a parent still wins.\n *\n * Only a **directory** counts. An `ai-assets` file would otherwise be returned\n * as a root and every later `join(root, source_path)` would fail with ENOTDIR.\n *\n * @param startDir - Directory to start from (typically the project dir).\n * @param opts - `levels` caps the upward walk; `mountDirs` overrides the mount\n * roots (defaults to {@link workspaceMountDirs}).\n * @returns Absolute path to the `ai-assets/` directory, or `null` if none is\n * reachable within `levels`.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function findAiAssetsRoot(\n startDir: string,\n opts?: { levels?: number; mountDirs?: string[] },\n): Promise<string | null> {\n const mountDirs = opts?.mountDirs ?? workspaceMountDirs();\n const levels = opts?.levels ?? AI_ASSETS_WALK_LEVELS;\n let dir = resolve(startDir);\n // Every level of a `/skaile/workspace/...` start dir is under the mount, so\n // an unconditional warn would fire once per level for one lookup. Collect and\n // report once — the operator needs the fact, not six copies of it.\n const refused: string[] = [];\n\n for (let i = 0; i < levels; i++) {\n const candidate = join(dir, \"ai-assets\");\n if (isUnderWorkspaceMount(candidate, mountDirs)) {\n refused.push(candidate);\n } else {\n const isDir = await tryWithFsDeadline(\n `stat ${candidate}`,\n async () => (await stat(candidate)).isDirectory(),\n false,\n );\n if (isDir) {\n if (refused.length > 0) warnRefused(refused, mountDirs);\n return candidate;\n }\n }\n const parent = resolve(dir, \"..\");\n if (parent === dir) break; // filesystem root — nothing further up\n dir = parent;\n }\n if (refused.length > 0) warnRefused(refused, mountDirs);\n return null;\n}\n\n/** Single warning for every `ai-assets` candidate skipped for sitting on a mount. */\nfunction warnRefused(refused: string[], mountDirs: string[]): void {\n log().warn(\n \"findAiAssetsRoot refused candidates under a workspace mount — deploying skills from a network mount can stall the session\",\n { refused, mountDirs },\n );\n}\n\n/**\n * Deploy a single catalog entry to the session skills directory.\n *\n * Copies the entire skill source directory into `skillsDir/<entry.name>/`.\n * If `context` is provided, a separate `CONTEXT.md` is written alongside\n * `SKILL.md` so the source file is never modified.\n *\n * Only `skill` entries are deployable; other kinds return an error.\n *\n * **Async by necessity.** This runs from the `session_init` command handler\n * with the WebSocket live, and both `assetsRoot` and `skillsDir` can sit on a\n * network mount. The former `cpSync`/`rmSync` pair parked the event loop for\n * the whole copy; every call is now awaited and deadline-bounded, so an\n * unresponsive mount fails one deployment instead of the session.\n *\n * @param entry - Compiled catalog entry to deploy.\n * @param options - Deployment target and optional context.\n * @returns `{ success: true }` on success, `{ success: false, error }` on failure.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function deployCatalogEntry(\n entry: CatalogEntryCompiled,\n options: DeployFromCatalogOptions,\n): Promise<{ success: boolean; error?: string }> {\n const { assetsRoot, skillsDir, context } = options;\n\n if (entry.kind !== \"skill\") {\n return { success: false, error: `Cannot deploy ${entry.kind} directly — only skills` };\n }\n\n const sourcePath = join(assetsRoot, entry.source_path);\n const skillMdPath = join(sourcePath, \"SKILL.md\");\n\n const hasSkillMd = await tryWithFsDeadline(\n `stat ${skillMdPath}`,\n async () => {\n await stat(skillMdPath);\n return true;\n },\n false,\n );\n if (!hasSkillMd) {\n return { success: false, error: `SKILL.md not found at ${skillMdPath}` };\n }\n\n const destDir = join(skillsDir, entry.name);\n\n try {\n await withFsDeadline(`mkdir ${destDir}`, () => mkdir(destDir, { recursive: true }));\n\n // Copy the entire skill directory\n await withFsDeadline(\n `cp ${sourcePath} -> ${destDir}`,\n () => cp(sourcePath, destDir, { recursive: true }),\n fsDeadlineMs() * TREE_OP_DEADLINE_FACTOR,\n );\n\n // Write context to a separate CONTEXT.md — never modify the original SKILL.md.\n // The agent discovers both files in the skill directory.\n const contextPath = join(destDir, \"CONTEXT.md\");\n if (context) {\n await withFsDeadline(`write ${contextPath}`, () =>\n writeFile(contextPath, `# Additional Context\\n\\n${context}\\n`, \"utf8\"),\n );\n } else {\n // `force: true` makes this a single call: a stale CONTEXT.md is removed,\n // an absent one is a no-op. The former existsSync probe only added a\n // second trip to the same possibly-wedged mount.\n await withFsDeadline(`rm ${contextPath}`, () => rm(contextPath, { force: true }));\n }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n return { success: true };\n}\n\n/**\n * Remove a deployed skill directory from the session skills directory.\n *\n * @param name - Skill name (directory basename under `skillsDir`).\n * @param skillsDir - Absolute path to the session skills directory.\n * @returns `true` if the skill was found and removed; `false` if it was not\n * deployed, or if the directory could not be reached within the deadline.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function undeployCatalogEntry(name: string, skillsDir: string): Promise<boolean> {\n const destDir = join(skillsDir, name);\n const exists = await tryWithFsDeadline(\n `stat ${destDir}`,\n async () => {\n await stat(destDir);\n return true;\n },\n false,\n );\n if (!exists) return false;\n await withFsDeadline(\n `rm -r ${destDir}`,\n () => rm(destDir, { recursive: true, force: true }),\n fsDeadlineMs() * TREE_OP_DEADLINE_FACTOR,\n );\n return true;\n}\n\n/**\n * Deploy multiple catalog entries in a single batch operation.\n *\n * Non-skill entries (flows, agents, etc.) are automatically skipped and\n * recorded in `result.skipped`. Deployment failures are collected in\n * `result.errors` without aborting the rest of the batch.\n *\n * @param entries - Compiled catalog entries to deploy.\n * @param options - Deployment target and optional context.\n * @returns Aggregated {@link DeployResult} with deployed, skipped, and error lists.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function deployAll(\n entries: CatalogEntryCompiled[],\n options: DeployFromCatalogOptions,\n): Promise<DeployResult> {\n const result: DeployResult = { deployed: [], skipped: [], errors: [] };\n\n for (const entry of entries) {\n if (entry.kind !== \"skill\") {\n result.skipped.push(entry.id);\n continue;\n }\n\n // Serial on purpose: concurrent recursive copies onto one mount multiply\n // the queue depth on the exact resource that is already the bottleneck.\n const r = await deployCatalogEntry(entry, options);\n if (r.success) {\n result.deployed.push(entry.id);\n } else {\n result.errors.push(`${entry.id}: ${r.error}`);\n }\n }\n\n return result;\n}\n\n/**\n * Resolve a flow's skill dependencies from the full catalog entry list.\n *\n * Partitions `flow.required_skills` and `flow.optional_skills` into resolved\n * entries and a list of names that could not be found. Missing optional skills\n * are silently ignored (they do not appear in `missing`).\n *\n * @param flow - Compiled flow entry whose skill dependencies should be resolved.\n * @param allEntries - Full set of compiled catalog entries to search.\n * @returns Object containing resolved `required` entries, resolved `optional` entries,\n * and `missing` skill names that were listed as required but not found.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function resolveFlowSkills(\n flow: CatalogEntryCompiled,\n allEntries: CatalogEntryCompiled[],\n): { required: CatalogEntryCompiled[]; optional: CatalogEntryCompiled[]; missing: string[] } {\n const skillsByName = new Map<string, CatalogEntryCompiled>();\n for (const e of allEntries) {\n if (e.kind === \"skill\") skillsByName.set(e.name, e);\n }\n\n const required: CatalogEntryCompiled[] = [];\n const optional: CatalogEntryCompiled[] = [];\n const missing: string[] = [];\n\n for (const name of flow.required_skills ?? []) {\n const entry = skillsByName.get(name);\n if (entry) required.push(entry);\n else missing.push(name);\n }\n\n for (const name of flow.optional_skills ?? []) {\n const entry = skillsByName.get(name);\n if (entry) optional.push(entry);\n // Optional skills don't count as missing\n }\n\n return { required, optional, missing };\n}\n"]}
1
+ {"version":3,"sources":["../asset-manager/src/catalog-deployer.ts"],"names":[],"mappings":"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","file":"chunk-GHWJHOYX.js","sourcesContent":["/**\n * Platform-triggered asset deployment.\n *\n * Takes catalog entries (with source_path relative to ai-assets/) and deploys\n * them to a session's .claude/skills/ directory. Handles skill context injection\n * and catalog priority-based name resolution.\n */\n\nimport { cp, mkdir, rm, stat, writeFile } from \"node:fs/promises\";\nimport { join, resolve, sep } from \"node:path\";\nimport { fsDeadlineMs, tryWithFsDeadline, withFsDeadline } from \"@skaile/workspaces/core\";\nimport { createLogger } from \"@skaile/workspaces/core/logging\";\n\n// ---------------------------------------------------------------------------\n// Types (formerly in catalog-compiler.ts, inlined after tear-out in Task 1.5)\n// ---------------------------------------------------------------------------\n\n/**\n * A single user-facing input parameter declared in a SKILL.md.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface InputSpec {\n /** Input parameter key used in skill invocation. */\n key: string;\n /** Whether the input must be provided before running the skill. */\n required?: boolean;\n /** Question string shown to the user when collecting this input. */\n prompt?: string;\n /** Short display label for UI forms. */\n label?: string;\n /** Input data type hint (e.g. `\"string\"`, `\"number\"`, `\"file\"`). */\n type?: string;\n /** Additional guidance text shown alongside the input field. */\n hint?: string;\n}\n\n/**\n * A compiled catalog entry (skill or flow).\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface CatalogEntryCompiled {\n /** Unique ID in `domain/name` form (e.g. `skaileup-conceptualization/cf_overview`). */\n id: string;\n /** Asset kind. */\n kind: \"skill\" | \"flow\";\n /** Human-readable asset name. */\n name: string;\n /** One-line description. */\n description: string;\n /** Semantic version string. */\n version: string;\n /** Maturity stage. */\n stage: \"alpha\" | \"beta\" | \"stable\";\n /** Searchable keywords. */\n keywords: string[];\n /** User-facing input specifications. */\n inputs: InputSpec[];\n /** Domain directory name. */\n source_domain: string;\n /** Asset path relative to assetsRoot. */\n source_path: string;\n /** Optional icon identifier. */\n icon?: string;\n /** Flow-only: required skill names. */\n required_skills?: string[];\n /** Flow-only: optional skill names. */\n optional_skills?: string[];\n}\n\n/**\n * Options controlling how platform-triggered skill deployment is performed.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface DeployFromCatalogOptions {\n /** Root directory of ai-assets (where `source_path` in catalog entries is relative to). */\n assetsRoot: string;\n /** Target directory for deployed skills (e.g. `/workspace/.claude/skills/`). */\n skillsDir: string;\n /** Optional context markdown appended to the deployed skill directory as `CONTEXT.md`. */\n context?: string;\n}\n\n/**\n * Result of a platform-triggered batch skill deployment.\n *\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport interface DeployResult {\n /** IDs of catalog entries successfully deployed. */\n deployed: string[];\n /** IDs of catalog entries skipped (non-skill kinds). */\n skipped: string[];\n /** Error messages for entries that could not be deployed. */\n errors: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Workspace-mount awareness\n// ---------------------------------------------------------------------------\n\n/**\n * Multiplier applied to the base filesystem deadline for whole-tree operations\n * (recursive copy / remove), which legitimately outlast a single `stat`.\n */\nconst TREE_OP_DEADLINE_FACTOR = 4;\n\n/** Default number of parent levels {@link findAiAssetsRoot} inspects. */\nconst AI_ASSETS_WALK_LEVELS = 6;\n\nlet deployerLogger: ReturnType<typeof createLogger> | undefined;\n\nfunction log(): ReturnType<typeof createLogger> {\n deployerLogger ??= createLogger({ kind: \"runner\", subkind: \"catalog-deployer\" });\n return deployerLogger;\n}\n\n/**\n * Where the agent container binds its rclone FUSE mount. Nothing under this\n * path is a safe place to read an asset tree from: the mount is remote\n * (SharePoint / OneDrive / WebDAV) and can wedge indefinitely.\n */\nconst DEFAULT_WORKSPACE_MOUNT_DIR = \"/skaile/workspace\";\n\n/**\n * Env override for the workspace-mount path(s), comma-separated.\n *\n * Set it when the runner binds the mount somewhere other than\n * {@link DEFAULT_WORKSPACE_MOUNT_DIR}; set it to the empty string to disable\n * the guard entirely (single-machine dev, where nothing is a network mount).\n */\nexport const WORKSPACE_MOUNT_ENV_VAR = \"SKAILE_WORKSPACE_MOUNT_DIR\";\n\n/**\n * Resolve the directories treated as network mounts.\n *\n * Read per call rather than cached: the runner mutates `process.env` while\n * wiring a session, so a module-load snapshot would pin a pre-configuration\n * value.\n *\n * @returns Absolute mount paths; empty when the guard is disabled.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function workspaceMountDirs(): string[] {\n const raw = process.env[WORKSPACE_MOUNT_ENV_VAR];\n if (raw === undefined) return [DEFAULT_WORKSPACE_MOUNT_DIR];\n return raw\n .split(\",\")\n .map((segment) => segment.trim())\n .filter((segment) => segment.length > 0)\n .map((segment) => resolve(segment));\n}\n\n/**\n * Is `candidate` at, or inside, one of the known workspace mount paths?\n *\n * Pure path arithmetic — deliberately no filesystem access, because the whole\n * point is to decide *before* touching a path that might be unresponsive.\n *\n * @param candidate - Path to test.\n * @param mountDirs - Mount roots; defaults to {@link workspaceMountDirs}.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function isUnderWorkspaceMount(\n candidate: string,\n mountDirs: string[] = workspaceMountDirs(),\n): boolean {\n const target = resolve(candidate);\n return mountDirs.some((dir) => {\n const root = resolve(dir);\n return target === root || target.startsWith(root + sep);\n });\n}\n\n/**\n * Walk upward from `startDir` looking for an `ai-assets/` directory.\n *\n * Two properties matter beyond \"find the folder\":\n *\n * 1. **Never synchronous.** The walk probes up to six directories; any one of\n * them can be on a FUSE mount, and the former `existsSync` chain blocked the\n * event loop on the first unresponsive probe. Each probe is now awaited and\n * deadline-bounded, so a wedged mount costs one skipped candidate.\n * 2. **Never resolves onto a mount.** A hit under the workspace mount is\n * skipped with a warning rather than returned: accepting it would wire every\n * later skill deploy — a recursive copy — to a remote filesystem. The walk\n * continues upward, so a legitimate `ai-assets/` in a parent still wins.\n *\n * Only a **directory** counts. An `ai-assets` file would otherwise be returned\n * as a root and every later `join(root, source_path)` would fail with ENOTDIR.\n *\n * @param startDir - Directory to start from (typically the project dir).\n * @param opts - `levels` caps the upward walk; `mountDirs` overrides the mount\n * roots (defaults to {@link workspaceMountDirs}).\n * @returns Absolute path to the `ai-assets/` directory, or `null` if none is\n * reachable within `levels`.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function findAiAssetsRoot(\n startDir: string,\n opts?: { levels?: number; mountDirs?: string[] },\n): Promise<string | null> {\n const mountDirs = opts?.mountDirs ?? workspaceMountDirs();\n const levels = opts?.levels ?? AI_ASSETS_WALK_LEVELS;\n let dir = resolve(startDir);\n // Every level of a `/skaile/workspace/...` start dir is under the mount, so\n // an unconditional warn would fire once per level for one lookup. Collect and\n // report once — the operator needs the fact, not six copies of it.\n const refused: string[] = [];\n\n for (let i = 0; i < levels; i++) {\n const candidate = join(dir, \"ai-assets\");\n if (isUnderWorkspaceMount(candidate, mountDirs)) {\n refused.push(candidate);\n } else {\n const isDir = await tryWithFsDeadline(\n `stat ${candidate}`,\n async () => (await stat(candidate)).isDirectory(),\n false,\n );\n if (isDir) {\n if (refused.length > 0) warnRefused(refused, mountDirs);\n return candidate;\n }\n }\n const parent = resolve(dir, \"..\");\n if (parent === dir) break; // filesystem root — nothing further up\n dir = parent;\n }\n if (refused.length > 0) warnRefused(refused, mountDirs);\n return null;\n}\n\n/** Single warning for every `ai-assets` candidate skipped for sitting on a mount. */\nfunction warnRefused(refused: string[], mountDirs: string[]): void {\n log().warn(\n \"findAiAssetsRoot refused candidates under a workspace mount — deploying skills from a network mount can stall the session\",\n { refused, mountDirs },\n );\n}\n\n/**\n * Deploy a single catalog entry to the session skills directory.\n *\n * Copies the entire skill source directory into `skillsDir/<entry.name>/`.\n * If `context` is provided, a separate `CONTEXT.md` is written alongside\n * `SKILL.md` so the source file is never modified.\n *\n * Only `skill` entries are deployable; other kinds return an error.\n *\n * **Async by necessity.** This runs from the `session_init` command handler\n * with the WebSocket live, and both `assetsRoot` and `skillsDir` can sit on a\n * network mount. The former `cpSync`/`rmSync` pair parked the event loop for\n * the whole copy; every call is now awaited and deadline-bounded, so an\n * unresponsive mount fails one deployment instead of the session.\n *\n * @param entry - Compiled catalog entry to deploy.\n * @param options - Deployment target and optional context.\n * @returns `{ success: true }` on success, `{ success: false, error }` on failure.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function deployCatalogEntry(\n entry: CatalogEntryCompiled,\n options: DeployFromCatalogOptions,\n): Promise<{ success: boolean; error?: string }> {\n const { assetsRoot, skillsDir, context } = options;\n\n if (entry.kind !== \"skill\") {\n return { success: false, error: `Cannot deploy ${entry.kind} directly — only skills` };\n }\n\n const sourcePath = join(assetsRoot, entry.source_path);\n const skillMdPath = join(sourcePath, \"SKILL.md\");\n\n const hasSkillMd = await tryWithFsDeadline(\n `stat ${skillMdPath}`,\n async () => {\n await stat(skillMdPath);\n return true;\n },\n false,\n );\n if (!hasSkillMd) {\n return { success: false, error: `SKILL.md not found at ${skillMdPath}` };\n }\n\n const destDir = join(skillsDir, entry.name);\n\n try {\n await withFsDeadline(`mkdir ${destDir}`, () => mkdir(destDir, { recursive: true }));\n\n // Copy the entire skill directory\n await withFsDeadline(\n `cp ${sourcePath} -> ${destDir}`,\n () => cp(sourcePath, destDir, { recursive: true }),\n fsDeadlineMs() * TREE_OP_DEADLINE_FACTOR,\n );\n\n // Write context to a separate CONTEXT.md — never modify the original SKILL.md.\n // The agent discovers both files in the skill directory.\n const contextPath = join(destDir, \"CONTEXT.md\");\n if (context) {\n await withFsDeadline(`write ${contextPath}`, () =>\n writeFile(contextPath, `# Additional Context\\n\\n${context}\\n`, \"utf8\"),\n );\n } else {\n // `force: true` makes this a single call: a stale CONTEXT.md is removed,\n // an absent one is a no-op. The former existsSync probe only added a\n // second trip to the same possibly-wedged mount.\n await withFsDeadline(`rm ${contextPath}`, () => rm(contextPath, { force: true }));\n }\n } catch (err) {\n return { success: false, error: err instanceof Error ? err.message : String(err) };\n }\n\n return { success: true };\n}\n\n/**\n * Remove a deployed skill directory from the session skills directory.\n *\n * @param name - Skill name (directory basename under `skillsDir`).\n * @param skillsDir - Absolute path to the session skills directory.\n * @returns `true` if the skill was found and removed; `false` if it was not\n * deployed, or if the directory could not be reached within the deadline.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function undeployCatalogEntry(name: string, skillsDir: string): Promise<boolean> {\n const destDir = join(skillsDir, name);\n const exists = await tryWithFsDeadline(\n `stat ${destDir}`,\n async () => {\n await stat(destDir);\n return true;\n },\n false,\n );\n if (!exists) return false;\n await withFsDeadline(\n `rm -r ${destDir}`,\n () => rm(destDir, { recursive: true, force: true }),\n fsDeadlineMs() * TREE_OP_DEADLINE_FACTOR,\n );\n return true;\n}\n\n/**\n * Deploy multiple catalog entries in a single batch operation.\n *\n * Non-skill entries (flows, agents, etc.) are automatically skipped and\n * recorded in `result.skipped`. Deployment failures are collected in\n * `result.errors` without aborting the rest of the batch.\n *\n * @param entries - Compiled catalog entries to deploy.\n * @param options - Deployment target and optional context.\n * @returns Aggregated {@link DeployResult} with deployed, skipped, and error lists.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport async function deployAll(\n entries: CatalogEntryCompiled[],\n options: DeployFromCatalogOptions,\n): Promise<DeployResult> {\n const result: DeployResult = { deployed: [], skipped: [], errors: [] };\n\n for (const entry of entries) {\n if (entry.kind !== \"skill\") {\n result.skipped.push(entry.id);\n continue;\n }\n\n // Serial on purpose: concurrent recursive copies onto one mount multiply\n // the queue depth on the exact resource that is already the bottleneck.\n const r = await deployCatalogEntry(entry, options);\n if (r.success) {\n result.deployed.push(entry.id);\n } else {\n result.errors.push(`${entry.id}: ${r.error}`);\n }\n }\n\n return result;\n}\n\n/**\n * Resolve a flow's skill dependencies from the full catalog entry list.\n *\n * Partitions `flow.required_skills` and `flow.optional_skills` into resolved\n * entries and a list of names that could not be found. Missing optional skills\n * are silently ignored (they do not appear in `missing`).\n *\n * @param flow - Compiled flow entry whose skill dependencies should be resolved.\n * @param allEntries - Full set of compiled catalog entries to search.\n * @returns Object containing resolved `required` entries, resolved `optional` entries,\n * and `missing` skill names that were listed as required but not found.\n * @docLink packages/asset-manager/concepts#catalog-deployer\n */\nexport function resolveFlowSkills(\n flow: CatalogEntryCompiled,\n allEntries: CatalogEntryCompiled[],\n): { required: CatalogEntryCompiled[]; optional: CatalogEntryCompiled[]; missing: string[] } {\n const skillsByName = new Map<string, CatalogEntryCompiled>();\n for (const e of allEntries) {\n if (e.kind === \"skill\") skillsByName.set(e.name, e);\n }\n\n const required: CatalogEntryCompiled[] = [];\n const optional: CatalogEntryCompiled[] = [];\n const missing: string[] = [];\n\n for (const name of flow.required_skills ?? []) {\n const entry = skillsByName.get(name);\n if (entry) required.push(entry);\n else missing.push(name);\n }\n\n for (const name of flow.optional_skills ?? []) {\n const entry = skillsByName.get(name);\n if (entry) optional.push(entry);\n // Optional skills don't count as missing\n }\n\n return { required, optional, missing };\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { isAgentNode, isGateNode, nodeIsOptional, nodeRequiresApproval, nodeLabel, flowDefaults } from './chunk-F5VREBV2.js';
1
+ import { isAgentNode, isGateNode, nodeIsOptional, nodeRequiresApproval, nodeLabel, flowDefaults } from './chunk-ELPR5XBG.js';
2
2
 
3
3
  // factory-assets/connectors/flow/prompt-fragments.ts
4
4
  function renderStimulusPrompt(stimulus) {
@@ -160,7 +160,9 @@ function renderSubpromptPrompt(instruction, outputSchema) {
160
160
 
161
161
  Respond with a single JSON object matching this JSON Schema, and nothing else \u2014 no markdown code fences, no commentary before or after it:
162
162
 
163
- ${JSON.stringify(outputSchema, null, 2)}`;
163
+ ${JSON.stringify(outputSchema, null, 2)}
164
+
165
+ Reply with the object only. The first character of your reply must be \`{\` and the last must be \`}\` \u2014 no explanation, no restatement, no code fence.`;
164
166
  }
165
167
  function describeStimulus(stimulus) {
166
168
  switch (stimulus.kind) {
@@ -184,5 +186,5 @@ function describeStimulus(stimulus) {
184
186
  }
185
187
 
186
188
  export { buildOrchestratorPrompt, describeStimulus, renderStimulusPrompt, renderSubpromptPrompt };
187
- //# sourceMappingURL=chunk-FLBDLF3I.js.map
188
- //# sourceMappingURL=chunk-FLBDLF3I.js.map
189
+ //# sourceMappingURL=chunk-HGFKNJA5.js.map
190
+ //# sourceMappingURL=chunk-HGFKNJA5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../factory-assets/connectors/flow/prompt-fragments.ts"],"names":[],"mappings":"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","file":"chunk-HGFKNJA5.js","sourcesContent":["/**\n * Prompt fragments for the flow connector.\n *\n * Pure functions that translate a {@link TurnStimulus} into the strings the\n * runner's flow orchestrator splices into the per-turn agent prompt.\n * Extracted from `runner/src/flow-orchestrator.ts` in Phase 3 of the\n * flow-connector extraction (2026-05-08) so the connector owns its\n * prompt-rendering surface without a runtime dep on the orchestrator.\n *\n * The contract is byte-identical to the previous inline implementation —\n * any divergence is a regression.\n *\n * @docLink packages/factory-assets/flow#prompt-fragments\n */\n\nimport type { FlowExecution } from \"@skaile/workspaces/types\";\nimport type { FlowDefinition } from \"./engine/types.js\";\nimport {\n flowDefaults,\n isAgentNode,\n isGateNode,\n nodeIsOptional,\n nodeLabel,\n nodeRequiresApproval,\n} from \"./engine/node-shape.js\";\n\n/**\n * Reasons why a new turn is starting. The flow orchestrator's prompt template\n * renders a stimulus-specific paragraph (via {@link renderStimulusPrompt}) so\n * the agent knows exactly why it has been invoked.\n *\n * @docLink packages/factory-assets/flow#turn-stimulus\n */\nexport type TurnStimulus =\n | { kind: \"flow_started\" }\n | {\n kind: \"approval_received\";\n nodeId: string;\n decision: \"approved\" | \"rejected\";\n feedback?: string;\n decidedBy: string;\n }\n | { kind: \"input_received\"; nodeId: string; response: unknown; providedBy: string }\n | { kind: \"retry_requested\"; nodeId: string; requestedBy: string }\n | { kind: \"user_message\"; text: string; senderId: string }\n | { kind: \"resumed_after_hibernation\" }\n | { kind: \"cancelled\" }\n | { kind: \"state_changed\" };\n\n/**\n * Render the stimulus paragraph the agent sees at turn start.\n *\n * The output is a single paragraph (one or more sentences, no surrounding\n * whitespace) describing why the runner has woken the agent. Spliced into\n * the orchestrator prompt under the `## Why this turn is happening` heading.\n *\n * @docLink packages/factory-assets/flow#render-stimulus-prompt\n */\nexport function renderStimulusPrompt(stimulus: TurnStimulus): string {\n switch (stimulus.kind) {\n case \"flow_started\":\n return \"The user just started this flow. Begin with the first available node — call `get_available`, then `build_handoff` for your chosen node, then `start_node`.\";\n case \"approval_received\": {\n const { nodeId, decision, decidedBy, feedback } = stimulus;\n if (decision === \"approved\") {\n return `Node \\`${nodeId}\\` was **approved** by ${decidedBy}. Call \\`complete_node\\` for this node with the approved output, then advance to the next available node.`;\n }\n const fb = feedback ? ` Feedback: \"${feedback}\".` : \"\";\n return `Node \\`${nodeId}\\` was **rejected** by ${decidedBy}.${fb} Decide how to proceed: retry the node (the engine returned it to \\`available\\`), ask clarifying questions via \\`request_input\\`, or call \\`fail_node(..., recoverable: false)\\` if the issue cannot be addressed.`;\n }\n case \"input_received\":\n return `The user just provided input for node \\`${stimulus.nodeId}\\` (provided by ${stimulus.providedBy}). The node has returned to its prior status. Continue executing the node with this input.`;\n case \"retry_requested\":\n return `A user requested a retry of node \\`${stimulus.nodeId}\\` (requested by ${stimulus.requestedBy}). The node has been returned to \\`available\\` with its prior error preserved in history. Start a fresh attempt — review the error context if relevant and try a different approach.`;\n case \"user_message\":\n return `A user sent a message: \"${stimulus.text}\" (from ${stimulus.senderId}). You can respond directly without touching the flow, continue flow work, or both. If the message is a question about the flow, answer it; if it signals a new direction, consider whether to pause.`;\n case \"resumed_after_hibernation\":\n return \"This session was hibernated and has just resumed. Review the current state above and continue where you left off. No state was lost.\";\n case \"cancelled\":\n return \"The user has cancelled this flow. Wrap up cleanly: do not start any new nodes. You may record a short summary if relevant, then stop.\";\n case \"state_changed\":\n return \"The flow state changed. Review the current state above and continue work accordingly.\";\n }\n}\n\n/**\n * Build the full agent-orchestrator prompt for a flow turn.\n *\n * Reassembles the five-section prompt from the current FlowExecution snapshot\n * and the supplied stimulus:\n *\n * 1. Flow definition (markdown table of nodes)\n * 2. Current state (progress, available/blocked, interaction pointers)\n * 3. Why this turn is happening (stimulus-specific paragraph)\n * 4. Flow tools available (static documentation)\n * 5. Rules\n *\n * Originally a byte-identical lift of the (since-deleted)\n * `FlowOrchestrator.buildOrchestratorPrompt`; the contract now is simply\n * this function's own output. When strict v2 defaults or legacy globals are\n * non-empty, a `## Flow globals` section exposes those run-scoped values. The\n * flow-wide active-node table stays bounded to selection metadata; `build_handoff`\n * supplies a selected agent node's execution payload. First-class gates appear\n * as runtime-owned state but never as agent-executable work.\n * Pure — depends only on its inputs.\n *\n * @docLink packages/factory-assets/flow#build-orchestrator-prompt\n * @since 2.2.0\n */\nexport function buildOrchestratorPrompt(\n flowDef: FlowDefinition,\n state: FlowExecution,\n stimulus: TurnStimulus,\n): string {\n const agentNodes = flowDef.nodes.filter(isAgentNode);\n const gateNodes = flowDef.nodes.filter(isGateNode);\n const promptNodes = flowDef.nodes.filter((node) => isAgentNode(node) || isGateNode(node));\n const agentNodeIds = new Set(agentNodes.map((node) => node.id));\n const promptNodeIds = new Set(promptNodes.map((node) => node.id));\n\n // ── Section 1: definition table ──\n const nodeRows = promptNodes\n .map((n) => {\n const deps =\n flowDef.edges\n .filter((e) => e.target === n.id && e.type === \"flow\")\n .map((e) => e.source)\n .join(\", \") || \"—\";\n const required = nodeIsOptional(n) ? \"optional\" : \"required\";\n const gate = isGateNode(n) ? \"first-class\" : nodeRequiresApproval(n) ? \"mandatory\" : \"—\";\n const nodeState = state.nodes[n.id];\n const status = nodeState?.status ?? \"not_started\";\n const description = (n.description ?? n.data?.description ?? \"—\")\n .replace(/\\s+/g, \" \")\n .replaceAll(\"|\", \"\\\\|\");\n return `| ${n.id} | ${nodeLabel(n)} | ${description} | ${required} | ${gate} | ${status} | ${deps} |`;\n })\n .join(\"\\n\");\n\n // ── Section 2: current state summary ──\n const nodesByStatus = (s: string) =>\n Object.values(state.nodes)\n .filter((n) => promptNodeIds.has(n.id) && n.status === s)\n .map((n) => n.id);\n const available = nodesByStatus(\"available\");\n const awaitingApproval = nodesByStatus(\"awaiting_approval\");\n const awaitingInput = nodesByStatus(\"awaiting_input\");\n const running = nodesByStatus(\"running\");\n const failed = nodesByStatus(\"failed\");\n const completed = nodesByStatus(\"complete\");\n const totalRequired = promptNodes.filter((n) => !nodeIsOptional(n)).length;\n\n const stateSummary = [\n `- Run ID: ${state.runId}`,\n `- Status: ${state.status}`,\n `- Autonomous mode: ${state.autonomousMode}`,\n `- Progress: ${completed.length} / ${totalRequired} required nodes complete`,\n `- Available now: ${available.join(\", \") || \"(none)\"}`,\n `- Currently running: ${running.join(\", \") || \"(none)\"}`,\n `- Awaiting approval: ${awaitingApproval.join(\", \") || \"(none)\"}`,\n `- Awaiting input: ${awaitingInput.join(\", \") || \"(none)\"}`,\n `- Failed: ${failed.join(\", \") || \"(none)\"}`,\n ].join(\"\\n\");\n\n const outputCorrections = Object.values(state.nodes)\n .filter(\n (node) =>\n agentNodeIds.has(node.id) &&\n node.outputCorrection &&\n node.status !== \"complete\" &&\n node.status !== \"failed\",\n )\n .map(\n (node) =>\n `- Node \\`${node.id}\\`: ${node.outputCorrection?.issues.join(\"; \") ?? \"unknown issue\"}`,\n );\n const correctionSection =\n outputCorrections.length > 0\n ? `## Output correction required\n\nThe following node has already used its single corrective reprompt. Submit one corrected \\`complete_node\\` call that fixes every issue; a second mismatch fails the node.\n\n${outputCorrections.join(\"\\n\")}\n\n`\n : \"\";\n\n const rejectedGates = gateNodes.flatMap((node) => {\n const approval = state.nodes[node.id]?.approval;\n if (approval?.decision !== \"rejected\") return [];\n return [\n `- \\`${node.id}\\` — rejected by ${approval.decidedBy ?? \"unknown reviewer\"}: ${\n approval.feedback ?? \"(no feedback provided)\"\n }`,\n ];\n });\n const rejectedGateSection =\n rejectedGates.length > 0\n ? `## Rejected first-class gates requiring revision\n\n${rejectedGates.join(\"\\n\")}\n\nRevise the surrounding work in conversation, then re-request each gate with \\`request_approval(nodeId, summary, artifacts)\\`. Every gate remains parked until its new human decision; do not start, complete, skip, or fail a first-class gate.\n\n`\n : \"\";\n\n // ── Section 2b: flow globals (additive — omitted entirely when empty so\n // flows without globals keep the byte-identical Phase 3 prompt) ──\n const globals = flowDefaults(flowDef);\n const globalsSection =\n Object.keys(globals).length > 0\n ? `## Flow globals\n\nRun-scoped parameters set by the flow author or by the host that started this run. When \\`run_input\\` is present it carries the payload this run was started with (e.g. a scheduled or webhook-triggered run) — treat it as the run's initial input instead of asking the user for it.\n\n\\`\\`\\`json\n${JSON.stringify(globals, null, 2)}\n\\`\\`\\`\n\n`\n : \"\";\n\n // ── Section 3: stimulus paragraph ──\n const stimulusNode =\n stimulus.kind === \"approval_received\"\n ? flowDef.nodes.find((node) => node.id === stimulus.nodeId)\n : undefined;\n let stimulusParagraph = renderStimulusPrompt(stimulus);\n if (stimulus.kind === \"approval_received\" && stimulusNode && isGateNode(stimulusNode)) {\n if (stimulus.decision === \"approved\") {\n const availableSuccessors = agentNodes\n .filter((node) => state.nodes[node.id]?.status === \"available\")\n .map((node) => `\\`${node.id}\\``);\n stimulusParagraph = `Gate node \\`${stimulus.nodeId}\\` is already \\`complete\\` after approval by ${stimulus.decidedBy}. Do not call \\`complete_node\\` for the gate. Advance to successor work${\n availableSuccessors.length > 0\n ? `; available agent nodes: ${availableSuccessors.join(\", \")}`\n : \"\"\n } — call \\`get_available\\`, then \\`build_handoff\\` and \\`start_node\\` for the chosen agent node.`;\n } else {\n stimulusParagraph = `Gate node \\`${stimulus.nodeId}\\` was **rejected** by ${stimulus.decidedBy}.${\n stimulus.feedback ? ` Feedback: \"${stimulus.feedback}\".` : \"\"\n } Revise the work in conversation and follow the rejected-gate instructions above.`;\n }\n }\n\n // ── Section 4+5: static tool surface and rules ──\n return `# Flow Execution Context\n\nYou are orchestrating the flow **${flowDef.name}** (${flowDef.id} v${flowDef.version}). This is a governed flow execution: your job is to run nodes through the flow tools, summarize their outputs for human review, and yield control at approval gates.\n\n## Flow definition\n\n| ID | Label | Description | Required | Gate | Status | Depends on |\n|----|-------|-------------|----------|------|--------|------------|\n${nodeRows}\n\nNodes with **Gate = mandatory** are hard approval gates: they always require \\`request_approval\\` and a human decision, even when autonomous mode is on. They cannot be skipped — \\`request_approval\\` → approval is their only completion path.\nNodes with **Gate = first-class** are runtime-owned human decisions. The runtime parks them automatically and completes them directly on approval; the agent never executes them.\n\n## Current state\n\n${stateSummary}\n\n${globalsSection}${correctionSection}${rejectedGateSection}## Why this turn is happening\n\n${stimulusParagraph}\n\n## Flow tools available\n\nAll tools are exposed by the \\`flow\\` connector:\n\n- \\`get_available()\\` — list node IDs that are ready to start\n- \\`get_state()\\` — full current state including approvals, inputs, outputs\n- \\`get_globals()\\` — the flow's run-scoped globals (e.g. the \\`run_input\\` payload for scheduled/params-bound runs)\n- \\`build_handoff(nodeId)\\` — selected node instruction, supplied bindings, required assets, and upstream context\n- \\`start_node(nodeId)\\` — transition an agent node from \\`available\\` → \\`running\\`; call before executing it. Never start a first-class gate.\n- \\`request_approval(nodeId, summary, artifacts)\\` — transition a running agent node to \\`awaiting_approval\\`, or replace a rejected first-class gate's decision with a fresh pending request. **This ends your turn.**\n- \\`request_input(nodeId, prompt, schema)\\` — transition to \\`awaiting_input\\`. **This ends your turn.** Legal from \\`available\\`, \\`running\\`, or \\`awaiting_approval\\`.\n- \\`complete_node(nodeId, summary, fields?, artifacts?, concerns?)\\` — complete an agent node. When downstream nodes consume declared output fields, include a conforming JSON object. The first mismatch gets one corrective call; the second fails the node. Valid only if the agent node was approved, OR autonomousMode is true and it does not require mandatory approval. First-class gates are completed by the runtime on approval; never call this tool for them.\n- \\`fail_node(nodeId, message, recoverable)\\` — transition to \\`failed\\`, or to \\`skipped\\` if the node is optional. \\`recoverable=true\\` returns the node to \\`available\\` instead.\n- \\`skip_node(nodeId)\\` — transition to \\`skipped\\`. Only valid for optional nodes.\n\n## Rules\n\n1. Before executing an agent node, call \\`build_handoff(nodeId)\\` and follow its instruction with the supplied bindings, assets, and upstream context; then call \\`start_node(nodeId)\\`.\n2. After executing the node, call \\`request_approval\\` unless \\`autonomousMode\\` is true — in which case call \\`complete_node\\` directly. Exception: nodes marked **Gate = mandatory** always require \\`request_approval\\` and a human decision, even in autonomous mode.\n3. First-class nodes marked **Gate = first-class** are runtime-owned. Never start, complete, skip, fail, or request input for them. After rejection, revise in conversation and only call \\`request_approval\\` to create the next attempt.\n4. If you need information from the user before or during agent execution, call \\`request_input\\`. This ends your turn until the user responds.\n5. On unrecoverable agent failure, call \\`fail_node(..., recoverable: false)\\`; an optional node ends \\`skipped\\` rather than \\`failed\\`, so the run continues past it. On recoverable failure, call \\`fail_node(..., recoverable: true)\\` and the engine returns the node to \\`available\\`.\n6. When all required nodes are \\`complete\\` or \\`skipped\\`, stop. The runner marks the flow done automatically.\n7. Free-chat user messages do not require flow action. Respond directly, continue flow work, or both — your call.\n`;\n}\n\n/**\n * Render the full prompt sent to a subprompt node's isolated driver instance.\n *\n * `instruction` is already interpolated with the node's resolved bindings\n * (the same `interpolateNodeInstruction` step an agent handoff uses) — this\n * function only adds the typed-response directive when the node declares an\n * output contract. There is no corrective reprompt for a subprompt (it has no\n * conversation to reprompt in), so the directive is the runtime's only lever\n * for getting parseable JSON back; a malformed or non-conforming reply is an\n * ordinary node failure handled by the caller, never retried in-band here.\n *\n * The object-only constraint is therefore stated twice, before and after the\n * schema: the serialized schema is a large blob, so a directive placed only\n * ahead of it is not the last thing the model reads.\n *\n * @docLink packages/factory-assets/flow#render-subprompt-prompt\n */\nexport function renderSubpromptPrompt(\n instruction: string,\n outputSchema: Record<string, unknown> | undefined,\n): string {\n if (!outputSchema) return instruction;\n return `${instruction}\\n\\nRespond with a single JSON object matching this JSON Schema, and nothing else — no markdown code fences, no commentary before or after it:\\n\\n${JSON.stringify(outputSchema, null, 2)}\\n\\nReply with the object only. The first character of your reply must be \\`{\\` and the last must be \\`}\\` — no explanation, no restatement, no code fence.`;\n}\n\n/**\n * Single-line tag suitable for telemetry / logging. Derives a short, stable\n * summary of a stimulus that's safe to attach to spans, log entries, and\n * trace events. The kind is always included; node-specific stimuli also\n * include their `nodeId` so log queries can pivot on it.\n *\n * @docLink packages/factory-assets/flow#describe-stimulus\n */\nexport function describeStimulus(stimulus: TurnStimulus): string {\n switch (stimulus.kind) {\n case \"flow_started\":\n return \"flow_started\";\n case \"approval_received\":\n return `approval_received:${stimulus.nodeId}:${stimulus.decision}`;\n case \"input_received\":\n return `input_received:${stimulus.nodeId}`;\n case \"retry_requested\":\n return `retry_requested:${stimulus.nodeId}`;\n case \"user_message\":\n return `user_message:${stimulus.senderId}`;\n case \"resumed_after_hibernation\":\n return \"resumed_after_hibernation\";\n case \"cancelled\":\n return \"cancelled\";\n case \"state_changed\":\n return \"state_changed\";\n }\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { findAiAssetsRoot } from './chunk-BEAIJRVF.js';
1
+ import { findAiAssetsRoot } from './chunk-GHWJHOYX.js';
2
2
 
3
3
  // workspace-plugin/src/utils/ai-assets.ts
4
4
  function findAiAssetsRoot2(startDir) {
@@ -6,5 +6,5 @@ function findAiAssetsRoot2(startDir) {
6
6
  }
7
7
 
8
8
  export { findAiAssetsRoot2 as findAiAssetsRoot };
9
- //# sourceMappingURL=chunk-BK3WL3QK.js.map
10
- //# sourceMappingURL=chunk-BK3WL3QK.js.map
9
+ //# sourceMappingURL=chunk-JAHHMZWG.js.map
10
+ //# sourceMappingURL=chunk-JAHHMZWG.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../workspace-plugin/src/utils/ai-assets.ts"],"names":["findAiAssetsRoot"],"mappings":";;;AA+BO,SAASA,kBAAiB,QAAA,EAA0C;AACzE,EAAA,OAAO,iBAAuB,QAAQ,CAAA;AACxC","file":"chunk-BK3WL3QK.js","sourcesContent":["// utils/ai-assets.ts\n// Shared utility for locating the ai-assets root directory.\n//\n// This is NOT a startup path (an earlier comment here claimed it was). Every\n// caller is an agent-invokable tool in `tools/flows.ts` / `tools/skills.ts`, so\n// the walk runs on a request path inside the long-lived `skaile serve` process,\n// once per tool invocation. With `projectDir = /skaile` the upward walk passes\n// directly beside the rclone FUSE workspace mount, so a synchronous `statSync`\n// here parks the whole event loop when that mount wedges — the failure mode\n// behind the 2026-08-07 outages. See issue #454.\nimport { findAiAssetsRoot as findAiAssetsRootShared } from \"@skaile/workspaces/asset-manager/catalog-deployer\";\n\n/**\n * Walk up from `startDir` looking for an `ai-assets/` directory.\n *\n * Delegates to the shared implementation in `asset-manager/catalog-deployer`,\n * which is async, deadline-bounded, level-capped, and refuses a candidate that\n * resolves at or under a workspace mount (continuing upward so a legitimate\n * parent still wins).\n *\n * @param startDir - Absolute path to begin the upward search from (typically\n * the skaile `projectDir`).\n * Note the upward walk is now level-capped rather than running to the\n * filesystem root. Six levels covers every real layout and stops an\n * unbounded climb across mount boundaries.\n *\n * @returns Absolute path to the first usable `ai-assets/` directory found, or\n * `null` if no match exists within the cap.\n *\n * @docLink packages/workspace-plugin/concepts#workspaceplugin-lifecycle\n */\nexport function findAiAssetsRoot(startDir: string): Promise<string | null> {\n return findAiAssetsRootShared(startDir);\n}\n"]}
1
+ {"version":3,"sources":["../workspace-plugin/src/utils/ai-assets.ts"],"names":["findAiAssetsRoot"],"mappings":";;;AA+BO,SAASA,kBAAiB,QAAA,EAA0C;AACzE,EAAA,OAAO,iBAAuB,QAAQ,CAAA;AACxC","file":"chunk-JAHHMZWG.js","sourcesContent":["// utils/ai-assets.ts\n// Shared utility for locating the ai-assets root directory.\n//\n// This is NOT a startup path (an earlier comment here claimed it was). Every\n// caller is an agent-invokable tool in `tools/flows.ts` / `tools/skills.ts`, so\n// the walk runs on a request path inside the long-lived `skaile serve` process,\n// once per tool invocation. With `projectDir = /skaile` the upward walk passes\n// directly beside the rclone FUSE workspace mount, so a synchronous `statSync`\n// here parks the whole event loop when that mount wedges — the failure mode\n// behind the 2026-08-07 outages. See issue #454.\nimport { findAiAssetsRoot as findAiAssetsRootShared } from \"@skaile/workspaces/asset-manager/catalog-deployer\";\n\n/**\n * Walk up from `startDir` looking for an `ai-assets/` directory.\n *\n * Delegates to the shared implementation in `asset-manager/catalog-deployer`,\n * which is async, deadline-bounded, level-capped, and refuses a candidate that\n * resolves at or under a workspace mount (continuing upward so a legitimate\n * parent still wins).\n *\n * @param startDir - Absolute path to begin the upward search from (typically\n * the skaile `projectDir`).\n * Note the upward walk is now level-capped rather than running to the\n * filesystem root. Six levels covers every real layout and stops an\n * unbounded climb across mount boundaries.\n *\n * @returns Absolute path to the first usable `ai-assets/` directory found, or\n * `null` if no match exists within the cap.\n *\n * @docLink packages/workspace-plugin/concepts#workspaceplugin-lifecycle\n */\nexport function findAiAssetsRoot(startDir: string): Promise<string | null> {\n return findAiAssetsRootShared(startDir);\n}\n"]}
@@ -1,5 +1,5 @@
1
- import { resolveSkWorkspaceConfig, readLinks, getGlobalCacheDir, sourceCacheKey } from './chunk-Q26C5GLO.js';
2
- import { scanDirectory, tryWithFsDeadline } from './chunk-DYMWJAL4.js';
1
+ import { resolveSkWorkspaceConfig, readLinks, getGlobalCacheDir, sourceCacheKey } from './chunk-RD6MMBHQ.js';
2
+ import { scanDirectory, tryWithFsDeadline } from './chunk-VQ4P7UYE.js';
3
3
  import { existsSync, readFileSync } from 'fs';
4
4
  import { lstat, stat } from 'fs/promises';
5
5
  import { createRequire } from 'module';
@@ -219,5 +219,5 @@ function findCatalogEntry(entries, query) {
219
219
  }
220
220
 
221
221
  export { FACTORY_ASSETS_REPO_NAME, factoryAssetRoots, resolveFactoryAssetsRoot, resolveFactoryAssetsRootOrNull, resolvePackagedAssetsDir, resolveRuntimeAssets, resolveWorkspacesPackageRoot };
222
- //# sourceMappingURL=chunk-UFY2HFLO.js.map
223
- //# sourceMappingURL=chunk-UFY2HFLO.js.map
222
+ //# sourceMappingURL=chunk-KBXYT5HD.js.map
223
+ //# sourceMappingURL=chunk-KBXYT5HD.js.map