@skaile/workspaces 0.50.0 → 0.52.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 (180) hide show
  1. package/CHANGELOG.md +226 -0
  2. package/dist/asset-feeds-OEGJ6NOF.js +205 -0
  3. package/dist/asset-feeds-OEGJ6NOF.js.map +1 -0
  4. package/dist/asset-manager/index.js +8 -8
  5. package/dist/asset-manager/installer.js +7 -7
  6. package/dist/asset-manager/src/index.d.ts +83 -7
  7. package/dist/asset-manager/src/index.d.ts.map +1 -1
  8. package/dist/asset-manager/src/installer.d.ts.map +1 -1
  9. package/dist/{chunk-P4BDTJMI.js → chunk-2D5YE3FL.js} +4 -4
  10. package/dist/{chunk-P4BDTJMI.js.map → chunk-2D5YE3FL.js.map} +1 -1
  11. package/dist/{chunk-4IGNQG6E.js → chunk-2ZK7M2SG.js} +3 -3
  12. package/dist/{chunk-4IGNQG6E.js.map → chunk-2ZK7M2SG.js.map} +1 -1
  13. package/dist/{chunk-SXT6BAQJ.js → chunk-3IHBGDCG.js} +2 -2
  14. package/dist/{chunk-SXT6BAQJ.js.map → chunk-3IHBGDCG.js.map} +1 -1
  15. package/dist/{chunk-SDAKQCOB.js → chunk-3KPNDTMR.js} +3 -3
  16. package/dist/{chunk-SDAKQCOB.js.map → chunk-3KPNDTMR.js.map} +1 -1
  17. package/dist/{chunk-H74X4TSR.js → chunk-6K4RVXAM.js} +6 -6
  18. package/dist/{chunk-H74X4TSR.js.map → chunk-6K4RVXAM.js.map} +1 -1
  19. package/dist/{chunk-2Y4HIITD.js → chunk-7ZWLZ5H3.js} +13 -9
  20. package/dist/chunk-7ZWLZ5H3.js.map +1 -0
  21. package/dist/{chunk-6IDBWPK2.js → chunk-BQCGFPHW.js} +4 -3
  22. package/dist/chunk-BQCGFPHW.js.map +1 -0
  23. package/dist/chunk-BXC5547R.js +377 -0
  24. package/dist/chunk-BXC5547R.js.map +1 -0
  25. package/dist/{chunk-3A3OACI2.js → chunk-EOINYN5T.js} +2 -2
  26. package/dist/{chunk-3A3OACI2.js.map → chunk-EOINYN5T.js.map} +1 -1
  27. package/dist/{chunk-XGCXFX7X.js → chunk-F3HNW354.js} +3 -3
  28. package/dist/{chunk-XGCXFX7X.js.map → chunk-F3HNW354.js.map} +1 -1
  29. package/dist/{chunk-33WB7VFV.js → chunk-LKOMH3QC.js} +3 -3
  30. package/dist/{chunk-33WB7VFV.js.map → chunk-LKOMH3QC.js.map} +1 -1
  31. package/dist/{chunk-O4JH3KUE.js → chunk-MENCWIHW.js} +11 -3
  32. package/dist/chunk-MENCWIHW.js.map +1 -0
  33. package/dist/{chunk-LV73DB4G.js → chunk-MGB657EG.js} +16 -21
  34. package/dist/chunk-MGB657EG.js.map +1 -0
  35. package/dist/{chunk-PBO6SCT2.js → chunk-NXC6IEL4.js} +37 -14
  36. package/dist/chunk-NXC6IEL4.js.map +1 -0
  37. package/dist/{chunk-EBSIZYM6.js → chunk-QLLFCQU5.js} +12 -12
  38. package/dist/chunk-QLLFCQU5.js.map +1 -0
  39. package/dist/{chunk-X46FY45B.js → chunk-SKADPHAM.js} +12 -8
  40. package/dist/chunk-SKADPHAM.js.map +1 -0
  41. package/dist/{chunk-C5RYGUF4.js → chunk-TCNYSHPM.js} +157 -31
  42. package/dist/chunk-TCNYSHPM.js.map +1 -0
  43. package/dist/{chunk-JXHULIOA.js → chunk-UTHEIPEY.js} +387 -42
  44. package/dist/chunk-UTHEIPEY.js.map +1 -0
  45. package/dist/{chunk-ZJ3VRPOI.js → chunk-VE2UIJ7Y.js} +11 -15
  46. package/dist/chunk-VE2UIJ7Y.js.map +1 -0
  47. package/dist/{chunk-WBF7JLTY.js → chunk-W53D5Q52.js} +4 -4
  48. package/dist/{chunk-WBF7JLTY.js.map → chunk-W53D5Q52.js.map} +1 -1
  49. package/dist/{chunk-HNORRENR.js → chunk-WD2NRI3T.js} +5 -5
  50. package/dist/{chunk-HNORRENR.js.map → chunk-WD2NRI3T.js.map} +1 -1
  51. package/dist/cli/index.js +679 -477
  52. package/dist/cli/index.js.map +1 -1
  53. package/dist/cli/src/asset-feeds.d.ts +17 -3
  54. package/dist/cli/src/asset-feeds.d.ts.map +1 -1
  55. package/dist/cli/src/commands/catalog.d.ts +3 -2
  56. package/dist/cli/src/commands/catalog.d.ts.map +1 -1
  57. package/dist/cli/src/commands/manage.d.ts +47 -8
  58. package/dist/cli/src/commands/manage.d.ts.map +1 -1
  59. package/dist/cli/src/commands/project.d.ts.map +1 -1
  60. package/dist/cli/src/commands/source.d.ts +32 -0
  61. package/dist/cli/src/commands/source.d.ts.map +1 -1
  62. package/dist/cli/src/commands/update.d.ts +7 -0
  63. package/dist/cli/src/commands/update.d.ts.map +1 -1
  64. package/dist/connectors/config.js +7 -7
  65. package/dist/connectors/index.js +9 -9
  66. package/dist/connectors/src/config.d.ts +5 -13
  67. package/dist/connectors/src/config.d.ts.map +1 -1
  68. package/dist/connectors/src/index.d.ts +1 -1
  69. package/dist/connectors/src/index.d.ts.map +1 -1
  70. package/dist/core/driver-targets.js +1 -1
  71. package/dist/core/index.js +6 -6
  72. package/dist/core/manifest.js +1 -1
  73. package/dist/core/runtime-assets.js +4 -3
  74. package/dist/core/src/cache-paths.d.ts +6 -0
  75. package/dist/core/src/cache-paths.d.ts.map +1 -1
  76. package/dist/core/src/driver-targets.d.ts +12 -7
  77. package/dist/core/src/driver-targets.d.ts.map +1 -1
  78. package/dist/core/src/index.d.ts +3 -3
  79. package/dist/core/src/index.d.ts.map +1 -1
  80. package/dist/core/src/manifest.d.ts +6 -6
  81. package/dist/core/src/manifest.d.ts.map +1 -1
  82. package/dist/core/src/workspace-config.d.ts +36 -0
  83. package/dist/core/src/workspace-config.d.ts.map +1 -1
  84. package/dist/core/store.js +2 -2
  85. package/dist/core/workspace-config.js +3 -2
  86. package/dist/deploy/index.js +6 -6
  87. package/dist/discovery/index.js +2 -2
  88. package/dist/discovery/src/atomization-conventions.d.ts +30 -0
  89. package/dist/discovery/src/atomization-conventions.d.ts.map +1 -0
  90. package/dist/discovery/src/builtin-providers.d.ts.map +1 -1
  91. package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
  92. package/dist/discovery/src/discover.d.ts +38 -0
  93. package/dist/discovery/src/discover.d.ts.map +1 -1
  94. package/dist/discovery/src/index.d.ts +5 -2
  95. package/dist/discovery/src/index.d.ts.map +1 -1
  96. package/dist/discovery/src/reference-lint.d.ts +112 -0
  97. package/dist/discovery/src/reference-lint.d.ts.map +1 -0
  98. package/dist/discovery/src/requires-graph.d.ts +1 -1
  99. package/dist/discovery/src/tree-entries.d.ts +9 -1
  100. package/dist/discovery/src/tree-entries.d.ts.map +1 -1
  101. package/dist/{ensure-sources-EE7Z2HKS.js → ensure-sources-GJOXWVWO.js} +8 -8
  102. package/dist/{ensure-sources-EE7Z2HKS.js.map → ensure-sources-GJOXWVWO.js.map} +1 -1
  103. package/dist/factory-assets/connectors/deploy.js +9 -9
  104. package/dist/factory-assets/connectors/devserver.js +9 -9
  105. package/dist/factory-assets/connectors/flow/adapter.js +9 -9
  106. package/dist/factory-assets/connectors/flow/engine/flow-kind-provider.d.ts +1 -1
  107. package/dist/factory-assets/connectors/flow/engine/flow-kind-provider.d.ts.map +1 -1
  108. package/dist/factory-assets/connectors/flow/engine.js +7 -7
  109. package/dist/factory-assets/connectors/flow/run-flow.js +10 -10
  110. package/dist/factory-assets/connectors/flow.js +9 -9
  111. package/dist/factory-assets/connectors/git.js +9 -9
  112. package/dist/factory-assets/connectors/gmail/adapter.d.ts.map +1 -1
  113. package/dist/factory-assets/connectors/gmail.js +9 -9
  114. package/dist/factory-assets/connectors/googledrive.js +9 -9
  115. package/dist/factory-assets/connectors/local.js +9 -9
  116. package/dist/factory-assets/connectors/mattermost/adapter.d.ts.map +1 -1
  117. package/dist/factory-assets/connectors/mattermost.js +9 -9
  118. package/dist/factory-assets/connectors/memory.js +9 -9
  119. package/dist/factory-assets/connectors/minio/adapter.d.ts.map +1 -1
  120. package/dist/factory-assets/connectors/minio.js +9 -9
  121. package/dist/factory-assets/connectors/postgres/adapter.d.ts.map +1 -1
  122. package/dist/factory-assets/connectors/postgres.js +9 -9
  123. package/dist/factory-assets/connectors/s3/driver.d.ts.map +1 -1
  124. package/dist/factory-assets/connectors/s3.js +9 -9
  125. package/dist/factory-assets/connectors/sharepoint.js +9 -9
  126. package/dist/factory-assets/connectors/sqlite/adapter.d.ts.map +1 -1
  127. package/dist/factory-assets/connectors/sqlite.js +9 -9
  128. package/dist/factory-assets/connectors/static-server.js +9 -9
  129. package/dist/factory-assets/connectors/tunnel.js +9 -9
  130. package/dist/factory-assets/connectors/webdav.js +9 -9
  131. package/dist/factory-assets/connectors/xstate-store.js +9 -9
  132. package/dist/factory-assets/connectors/xstate.js +9 -9
  133. package/dist/{flows-AAHXXXCH.js → flows-AGPIE6JM.js} +3 -3
  134. package/dist/{flows-AAHXXXCH.js.map → flows-AGPIE6JM.js.map} +1 -1
  135. package/dist/library/index.js +8 -8
  136. package/dist/library/install.js +6 -6
  137. package/dist/open-library-ERKRGH4B.js +23 -0
  138. package/dist/{open-library-TXJMFG34.js.map → open-library-ERKRGH4B.js.map} +1 -1
  139. package/dist/paths-D6RUQ522.js +15 -0
  140. package/dist/{paths-OMVC4UWY.js.map → paths-D6RUQ522.js.map} +1 -1
  141. package/dist/{plugin-store-JWJHIPUT.js → plugin-store-SGNJTBYS.js} +8 -8
  142. package/dist/{plugin-store-JWJHIPUT.js.map → plugin-store-SGNJTBYS.js.map} +1 -1
  143. package/dist/runner/index.js +11 -11
  144. package/dist/runner/src/serve.d.ts.map +1 -1
  145. package/dist/sdk/asset-manager.js +8 -8
  146. package/dist/sdk/core.js +6 -6
  147. package/dist/sdk/flow.js +7 -7
  148. package/dist/sdk/index.js +17 -11
  149. package/dist/sdk/index.js.map +1 -1
  150. package/dist/sdk/runner.js +11 -11
  151. package/dist/sdk/src/transport.d.ts +2 -0
  152. package/dist/sdk/src/transport.d.ts.map +1 -1
  153. package/dist/{setup-ETNBVZQA.js → setup-IV2JFW3T.js} +8 -8
  154. package/dist/{setup-ETNBVZQA.js.map → setup-IV2JFW3T.js.map} +1 -1
  155. package/dist/source-FGOMQMZT.js +24 -0
  156. package/dist/source-FGOMQMZT.js.map +1 -0
  157. package/dist/store-client-GJT2XQ5Z.js +15 -0
  158. package/dist/{store-client-SLFAAKSV.js.map → store-client-GJT2XQ5Z.js.map} +1 -1
  159. package/dist/tui/index.js +11 -11
  160. package/dist/types/src/transport.d.ts +12 -0
  161. package/dist/types/src/transport.d.ts.map +1 -1
  162. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  163. package/dist/workspace-plugin/adapters/omp.js +3 -3
  164. package/dist/workspace-plugin/index.js +1 -1
  165. package/package.json +1 -1
  166. package/dist/asset-feeds-O6R6J4RI.js +0 -128
  167. package/dist/asset-feeds-O6R6J4RI.js.map +0 -1
  168. package/dist/chunk-2Y4HIITD.js.map +0 -1
  169. package/dist/chunk-6IDBWPK2.js.map +0 -1
  170. package/dist/chunk-C5RYGUF4.js.map +0 -1
  171. package/dist/chunk-EBSIZYM6.js.map +0 -1
  172. package/dist/chunk-JXHULIOA.js.map +0 -1
  173. package/dist/chunk-LV73DB4G.js.map +0 -1
  174. package/dist/chunk-O4JH3KUE.js.map +0 -1
  175. package/dist/chunk-PBO6SCT2.js.map +0 -1
  176. package/dist/chunk-X46FY45B.js.map +0 -1
  177. package/dist/chunk-ZJ3VRPOI.js.map +0 -1
  178. package/dist/open-library-TXJMFG34.js +0 -23
  179. package/dist/paths-OMVC4UWY.js +0 -15
  180. package/dist/store-client-SLFAAKSV.js +0 -15
@@ -232,12 +232,16 @@ var flowKindProvider = {
232
232
  const nodes = manifest.nodes;
233
233
  if (Array.isArray(nodes)) {
234
234
  for (const node of nodes) {
235
- if (typeof node === "object" && node !== null && "skill" in node && typeof node.skill === "string") {
236
- edges.push({
237
- from: assetRef,
238
- to: node.skill,
239
- field: "nodes[].skill"
240
- });
235
+ if (typeof node !== "object" || node === null) continue;
236
+ const n = node;
237
+ const data = typeof n.data === "object" && n.data !== null ? n.data : {};
238
+ const skill = typeof data.skill === "string" ? data.skill : n.skill;
239
+ if (typeof skill === "string") {
240
+ edges.push({ from: assetRef, to: skill, field: "nodes[].data.skill" });
241
+ }
242
+ const subFlow = typeof data.flow === "string" ? data.flow : n.flow;
243
+ if (typeof subFlow === "string") {
244
+ edges.push({ from: assetRef, to: subFlow, field: "nodes[].data.flow" });
241
245
  }
242
246
  }
243
247
  }
@@ -284,5 +288,5 @@ function loadAllFlows(aiResourcesRoot) {
284
288
  }
285
289
 
286
290
  export { FlowManifestSchema, computeFlowState, computeFlowStateFromSnapshots, computeSkippable, flowKindProvider, isBlocking, loadAllFlows, loadFlow, loadFlowsFromDir, resolveNextNodes, validateFlow };
287
- //# sourceMappingURL=chunk-X46FY45B.js.map
288
- //# sourceMappingURL=chunk-X46FY45B.js.map
291
+ //# sourceMappingURL=chunk-SKADPHAM.js.map
292
+ //# sourceMappingURL=chunk-SKADPHAM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../factory-assets/connectors/flow/engine/engine.ts","../factory-assets/connectors/flow/engine/flow-manifest.ts","../factory-assets/connectors/flow/engine/flow-kind-provider.ts","../factory-assets/connectors/flow/engine/loader.ts"],"names":["path","parseYaml"],"mappings":"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","file":"chunk-SKADPHAM.js","sourcesContent":["import type {\n FlowDefinition,\n FlowEdge,\n FlowNode,\n FlowState,\n NodeExecutionSnapshot,\n NodeState,\n NodeStatus,\n} from \"./types.js\";\n\n// ---------------------------------------------------------------------------\n// Core engine — stateless, pure functions\n// ---------------------------------------------------------------------------\n\n/** Return only skill nodes (exclude groups) */\nfunction skillNodes(flow: FlowDefinition): FlowNode[] {\n return flow.nodes.filter((n) => n.type === \"skill\");\n}\n\n/** Build adjacency: target → sources[] (incoming edges per node) */\nfunction buildIncoming(edges: FlowEdge[]): Map<string, FlowEdge[]> {\n const map = new Map<string, FlowEdge[]>();\n for (const edge of edges) {\n if (!map.has(edge.target)) map.set(edge.target, []);\n map.get(edge.target)!.push(edge);\n }\n return map;\n}\n\n/** Build adjacency: source → targets[] (outgoing edges per node) */\nfunction buildOutgoing(edges: FlowEdge[]): Map<string, FlowEdge[]> {\n const map = new Map<string, FlowEdge[]>();\n for (const edge of edges) {\n if (!map.has(edge.source)) map.set(edge.source, []);\n map.get(edge.source)!.push(edge);\n }\n return map;\n}\n\n/**\n * Compute the full {@link FlowState} from a flow definition and caller-supplied node ID sets.\n *\n * This is the primary engine function. It is stateless and side-effect-free — calling it\n * twice with the same arguments always returns an equivalent result.\n *\n * Edge semantics applied during computation:\n * - `'flow'` — hard dependency: target cannot start until source is `complete` or `skipped`.\n * - `'parallel'` — soft dependency: target may run while source is still running.\n * - `'optional'` — advisory: target can start regardless of source state.\n *\n * A node is `available` when every incoming `'flow'`-type edge has a complete or skipped source.\n * A node is `not_started` when at least one hard predecessor is still pending.\n * The flow is `done` when every non-optional node is `complete` or `skipped`.\n *\n * Prefer {@link computeFlowStateFromSnapshots} for callers that track full `NodeExecution`\n * state (interaction statuses such as `awaiting_approval`, `awaiting_input`, `failed`).\n *\n * @param flow - The parsed flow definition.\n * @param completedIds - Set of node IDs that have finished successfully.\n * @param runningIds - Set of node IDs currently executing. Defaults to an empty set.\n * @param skippedIds - Set of node IDs that were explicitly skipped. Skipped nodes count\n * as satisfied for downstream dependency checks. Defaults to an empty set.\n * @returns A {@link FlowState} describing the current status of every skill node.\n * @docLink packages/flow-engine/concepts#compute-flow-state\n */\nexport function computeFlowState(\n flow: FlowDefinition,\n completedIds: Set<string>,\n runningIds: Set<string> = new Set(),\n skippedIds: Set<string> = new Set(),\n): FlowState {\n const nodes = skillNodes(flow);\n const incoming = buildIncoming(flow.edges);\n\n const nodeStates: NodeState[] = nodes.map((node) => {\n const optional = node.data?.optional ?? false;\n const skillId = node.data?.skill ?? node.id;\n const label = node.data?.label ?? skillId;\n\n if (completedIds.has(node.id)) {\n return {\n nodeId: node.id,\n skillId,\n label,\n status: \"complete\",\n optional,\n canRun: false,\n blockers: [],\n };\n }\n if (runningIds.has(node.id)) {\n return {\n nodeId: node.id,\n skillId,\n label,\n status: \"running\",\n optional,\n canRun: false,\n blockers: [],\n };\n }\n if (skippedIds.has(node.id)) {\n return {\n nodeId: node.id,\n skillId,\n label,\n status: \"skipped\",\n optional,\n canRun: false,\n blockers: [],\n };\n }\n\n const edges = incoming.get(node.id) ?? [];\n\n // Hard blockers: flow-type edges whose source is neither complete nor skipped\n const hardBlockers = edges\n .filter((e) => e.type === \"flow\")\n .filter((e) => !completedIds.has(e.source) && !skippedIds.has(e.source))\n .map((e) => e.source);\n\n const canRun = hardBlockers.length === 0;\n\n let status: NodeStatus;\n if (!canRun) {\n status = \"not_started\";\n } else {\n status = \"available\";\n }\n\n return { nodeId: node.id, skillId, label, status, optional, canRun, blockers: hardBlockers };\n });\n\n const _stateMap = new Map(nodeStates.map((s) => [s.nodeId, s]));\n\n const available = nodeStates.filter((s) => s.status === \"available\").map((s) => s.nodeId);\n const completed = nodeStates.filter((s) => s.status === \"complete\").map((s) => s.nodeId);\n const focus = nodeStates\n .filter(\n (s) =>\n s.status === \"running\" || s.status === \"awaiting_approval\" || s.status === \"awaiting_input\",\n )\n .map((s) => s.nodeId);\n\n // Flow is done when all required nodes are complete or skipped\n const requiredNodes = nodes.filter((n) => !(n.data?.optional ?? false));\n const done = requiredNodes.every((n) => completedIds.has(n.id) || skippedIds.has(n.id));\n\n return { flowId: flow.id, nodes: nodeStates, available, completed, focus, done };\n}\n\n/**\n * Snapshot-based variant of {@link computeFlowState}.\n *\n * Accepts a map of `NodeExecutionSnapshot` values carrying the current status and\n * interaction metadata for every node the caller knows about. Nodes absent from the\n * map are treated as `not_started`.\n *\n * This is the preferred API for the turn-based runner, which has a full `FlowExecution`\n * and needs to convey richer statuses (`awaiting_approval`, `awaiting_input`, `failed`)\n * back to the engine so downstream availability is computed correctly.\n *\n * Engine semantics:\n * - A node is `available` when all its incoming `'flow'`-type predecessors are `complete`\n * or `skipped`. Any other upstream status — including `awaiting_approval`,\n * `awaiting_input`, and `failed` — is treated as blocking.\n * - A `failed` optional node does **not** block its dependents.\n * - The flow is `done` when every non-optional node is `complete` or `skipped`. A single\n * required node stuck in `failed` keeps `done` false.\n *\n * @param flow - The parsed flow definition.\n * @param snapshots - Map from node ID to its current {@link NodeExecutionSnapshot}.\n * Missing entries default to `not_started` with no interaction metadata.\n * @returns A {@link FlowState} describing the current status of every skill node,\n * including interaction fields (`approval`, `input`, `output`, `error`) copied\n * from the matching snapshot.\n * @docLink packages/flow-engine/concepts#compute-flow-state-from-snapshots\n */\nexport function computeFlowStateFromSnapshots(\n flow: FlowDefinition,\n snapshots: Map<string, NodeExecutionSnapshot>,\n): FlowState {\n const nodes = skillNodes(flow);\n const incoming = buildIncoming(flow.edges);\n\n /** Resolve the effective status for a node — defaulting to `not_started`. */\n const statusFor = (nodeId: string): NodeStatus => snapshots.get(nodeId)?.status ?? \"not_started\";\n\n /** A predecessor \"passes\" when it is complete or skipped. */\n const passed = (nodeId: string): boolean => {\n const s = statusFor(nodeId);\n return s === \"complete\" || s === \"skipped\";\n };\n\n const nodeStates: NodeState[] = nodes.map((node) => {\n const snapshot = snapshots.get(node.id);\n const optional = node.data?.optional ?? false;\n const skillId = node.data?.skill ?? node.id;\n const label = node.data?.label ?? skillId;\n const status = snapshot?.status ?? \"not_started\";\n\n const edges = incoming.get(node.id) ?? [];\n const flowPreds = edges.filter((e) => e.type === \"flow\");\n const hardBlockers = flowPreds.filter((e) => !passed(e.source)).map((e) => e.source);\n\n // For `not_started` nodes, elevate to `available` once blockers clear.\n let effectiveStatus: NodeStatus = status;\n if (status === \"not_started\" && hardBlockers.length === 0) {\n effectiveStatus = \"available\";\n }\n\n return {\n nodeId: node.id,\n skillId,\n label,\n status: effectiveStatus,\n optional,\n canRun: hardBlockers.length === 0 && effectiveStatus === \"available\",\n blockers: hardBlockers,\n approval: snapshot?.approval,\n input: snapshot?.input,\n output: snapshot?.output,\n error: snapshot?.error,\n };\n });\n\n const available = nodeStates.filter((s) => s.status === \"available\").map((s) => s.nodeId);\n const completed = nodeStates.filter((s) => s.status === \"complete\").map((s) => s.nodeId);\n const focus = nodeStates\n .filter(\n (s) =>\n s.status === \"running\" || s.status === \"awaiting_approval\" || s.status === \"awaiting_input\",\n )\n .map((s) => s.nodeId);\n\n const requiredNodes = nodes.filter((n) => !(n.data?.optional ?? false));\n const done = requiredNodes.every((n) => {\n const s = statusFor(n.id);\n return s === \"complete\" || s === \"skipped\";\n });\n\n return { flowId: flow.id, nodes: nodeStates, available, completed, focus, done };\n}\n\n/**\n * Returns `true` when the given status prevents downstream nodes from starting.\n *\n * Only `'complete'` and `'skipped'` satisfy a hard (`'flow'`-type) edge dependency.\n * All other statuses — including `'awaiting_approval'`, `'awaiting_input'`, and\n * `'failed'` — are considered blocking.\n *\n * Use this helper in the FlowAdapter and the turn-based orchestrator instead of\n * hard-coding the two-value whitelist inline.\n *\n * @param status - The {@link NodeStatus} to evaluate.\n * @returns `true` if the status prevents dependents from becoming `available`.\n * @docLink packages/flow-engine/concepts#is-blocking\n */\nexport function isBlocking(status: NodeStatus): boolean {\n return status !== \"complete\" && status !== \"skipped\";\n}\n\n/**\n * Returns the IDs of nodes that become newly `available` after a specific node completes.\n *\n * More efficient than recomputing the full {@link FlowState} when only the downstream\n * impact of a single completion is needed. Only the direct successors of `justCompleted`\n * are evaluated — the rest of the graph is untouched.\n *\n * @param flow - The parsed flow definition.\n * @param justCompleted - ID of the node that just finished (will be added to the\n * effective completed set before evaluating successors).\n * @param completedIds - Set of node IDs already known to be complete before this call.\n * @param skippedIds - Set of node IDs that were explicitly skipped. Defaults to an empty set.\n * @returns Array of node IDs whose hard dependencies are now fully satisfied and that\n * were not already available before `justCompleted` finished.\n * @docLink packages/flow-engine/concepts#resolve-next-nodes\n */\nexport function resolveNextNodes(\n flow: FlowDefinition,\n justCompleted: string,\n completedIds: Set<string>,\n skippedIds: Set<string> = new Set(),\n): string[] {\n const outgoing = buildOutgoing(flow.edges);\n const incoming = buildIncoming(flow.edges);\n const candidates = (outgoing.get(justCompleted) ?? []).map((e) => e.target);\n\n const nextCompleted = new Set([...completedIds, justCompleted]);\n const result: string[] = [];\n\n for (const candidateId of candidates) {\n const edges = incoming.get(candidateId) ?? [];\n const hardBlockers = edges\n .filter((e) => e.type === \"flow\")\n .filter((e) => !nextCompleted.has(e.source) && !skippedIds.has(e.source));\n if (hardBlockers.length === 0) {\n result.push(candidateId);\n }\n }\n\n return result;\n}\n\n/**\n * Returns the IDs of optional nodes that have not yet started and can be safely skipped.\n *\n * A node is skippable when it is:\n * 1. Not yet complete (absent from `completedIds`).\n * 2. Marked `optional` (`FlowNode.data.optional === true`).\n * 3. Not connected via a `'flow'`-type edge to any non-optional downstream node\n * (i.e. skipping it cannot starve a required node of a hard dependency).\n *\n * The runner may call this to present the user with a list of nodes they can bypass\n * without breaking the flow's required path.\n *\n * @param flow - The parsed flow definition.\n * @param completedIds - Set of node IDs that have already completed (excluded from results).\n * @returns Array of node IDs that are safe to skip at this point in the execution.\n * @docLink packages/flow-engine/concepts#compute-skippable\n */\nexport function computeSkippable(flow: FlowDefinition, completedIds: Set<string>): string[] {\n const nodes = skillNodes(flow);\n const outgoing = buildOutgoing(flow.edges);\n\n return nodes\n .filter((n) => !completedIds.has(n.id))\n .filter((n) => n.data?.optional ?? false)\n .filter((n) => {\n // A node is skippable if none of its outgoing flow-type edges go to a required node\n const deps = (outgoing.get(n.id) ?? []).filter((e) => e.type === \"flow\");\n return deps.every((e) => {\n const target = flow.nodes.find((t) => t.id === e.target);\n return target?.data?.optional ?? false;\n });\n })\n .map((n) => n.id);\n}\n","/**\n * Flow manifest schema and validation.\n *\n * Moved from @skaile/workspaces/types/manifests/flow.ts in Phase 1.7.3.\n * This is now the canonical location for flow manifest validation.\n */\n\nimport * as z from \"zod\";\n\n// ---------------------------------------------------------------------------\n// Validation result (inline — avoids importing from types/manifests/_shared)\n// ---------------------------------------------------------------------------\n\nexport interface ManifestValidationSuccess<T> {\n ok: true;\n data: T;\n}\n\nexport interface ManifestValidationFailure {\n ok: false;\n errors: Array<{ path: string; message: string }>;\n}\n\nexport type ManifestValidationResult<T> = ManifestValidationSuccess<T> | ManifestValidationFailure;\n\n// ---------------------------------------------------------------------------\n// Schema\n// ---------------------------------------------------------------------------\n\nconst FlowNodeSchema = z.looseObject({\n id: z.string().min(1),\n skill: z.string().optional(),\n type: z.string().optional(),\n label: z.string().optional(),\n description: z.string().optional(),\n});\n\nconst FlowEdgeSchema = z.looseObject({\n id: z.string().optional(),\n source: z.string().min(1),\n target: z.string().min(1),\n condition: z.string().optional(),\n});\n\nexport const FlowManifestSchema = z.looseObject({\n id: z.string().min(1),\n version: z.string().optional(),\n name: z.string().min(1),\n description: z.string().optional(),\n metadata: z\n .looseObject({\n tags: z.array(z.string()).optional(),\n stage: z.string().optional(),\n icon: z.string().optional(),\n category: z.string().optional(),\n onboarding: z.record(z.string(), z.unknown()).optional(),\n })\n .optional(),\n globals: z.record(z.string(), z.unknown()).optional(),\n modes: z.record(z.string(), z.unknown()).optional(),\n tier_presets: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),\n artifact_handoff: z.unknown().optional(),\n entry: z.string().optional(),\n nodes: z.array(FlowNodeSchema).optional(),\n edges: z.array(FlowEdgeSchema).optional(),\n});\n\nexport type FlowManifest = z.infer<typeof FlowManifestSchema>;\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nexport function validateFlow(data: unknown): ManifestValidationResult<FlowManifest> {\n const result = FlowManifestSchema.safeParse(data);\n if (result.success) {\n return { ok: true, data: result.data };\n }\n return {\n ok: false,\n errors: result.error.issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n })),\n };\n}\n","/**\n * Flow asset kind provider.\n *\n * Exported from @skaile/workspaces/factory-assets/connectors/flow/engine for explicit registration\n * by the CLI at bootstrap. Discovery does NOT auto-include this provider\n * (discovery must stay a leaf — no flow-engine imports).\n *\n * Implements IAssetKindProvider with flow-specific:\n * - Discovery patterns: *.flow.yaml, *.flow.json\n * - Manifest validation via FlowManifestSchema\n * - Requires extraction: nodes[].data.skill / nodes[].data.flow references\n * - File filter: just the manifest file (flows are single-file)\n */\n\nimport * as path from \"node:path\";\nimport type {\n AssetKindFileFilter,\n AssetKindRequiresEdge,\n IAssetKindProvider,\n} from \"@skaile/workspaces/plugins\";\nimport { validateFlow } from \"./flow-manifest.js\";\n\n// ---------------------------------------------------------------------------\n// Provider\n// ---------------------------------------------------------------------------\n\nexport const flowKindProvider: IAssetKindProvider = {\n kind: \"flow\",\n displayName: \"Flow\",\n providerVersion: \"1.0.0\",\n discoveryPatterns: [\"**/*.flow.yaml\", \"**/*.flow.json\"],\n\n matchesPath(relativePath: string): boolean {\n return relativePath.endsWith(\".flow.yaml\") || relativePath.endsWith(\".flow.json\");\n },\n\n validateManifest(data: unknown) {\n return validateFlow(data);\n },\n\n defaultFileFilter(manifestPath: string): AssetKindFileFilter {\n return {\n assetRoot: path.dirname(manifestPath),\n files: [path.basename(manifestPath)],\n };\n },\n\n extractRequires(assetRef: string, manifest: Record<string, unknown>): AssetKindRequiresEdge[] {\n const edges: AssetKindRequiresEdge[] = [];\n\n // The skill a node runs lives under node.data.skill (engine reads\n // node.data?.skill ?? node.id); the top-level node.skill fallback covers\n // any legacy flat-shaped manifest. Sub-flow nodes carry node.data.flow.\n const nodes = manifest.nodes;\n if (Array.isArray(nodes)) {\n for (const node of nodes) {\n if (typeof node !== \"object\" || node === null) continue;\n const n = node as Record<string, unknown>;\n const data = (\n typeof n.data === \"object\" && n.data !== null ? (n.data as Record<string, unknown>) : {}\n ) as Record<string, unknown>;\n\n const skill = typeof data.skill === \"string\" ? data.skill : n.skill;\n if (typeof skill === \"string\") {\n edges.push({ from: assetRef, to: skill, field: \"nodes[].data.skill\" });\n }\n\n const subFlow = typeof data.flow === \"string\" ? data.flow : n.flow;\n if (typeof subFlow === \"string\") {\n edges.push({ from: assetRef, to: subFlow, field: \"nodes[].data.flow\" });\n }\n }\n }\n\n return edges;\n },\n};\n","import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { assetSearchDirs } from \"@skaile/workspaces/core\";\nimport { parse as parseYaml } from \"yaml\";\nimport type { FlowDefinition } from \"./types.js\";\n\n/**\n * Load a single {@link FlowDefinition} from a YAML or JSON file on disk.\n *\n * Format detection is based on file extension:\n * - `.yaml` / `.yml` — parsed with the `yaml` library.\n * - Everything else — parsed as JSON.\n *\n * @param filePath - Absolute path to the flow file.\n * @returns The parsed {@link FlowDefinition}.\n * @throws {Error} If the file does not exist, cannot be read, or fails to parse.\n * @docLink packages/flow-engine/concepts#flow-loading\n */\nexport function loadFlow(filePath: string): FlowDefinition {\n const raw = fs.readFileSync(filePath, \"utf-8\");\n const ext = path.extname(filePath).toLowerCase();\n if (ext === \".yaml\" || ext === \".yml\") {\n return parseYaml(raw) as FlowDefinition;\n }\n return JSON.parse(raw) as FlowDefinition;\n}\n\n/**\n * Load all `*.flow.yaml` and legacy `*.flow.json` / `*.json` flow files from a directory.\n *\n * Files that fail to parse are skipped with a warning written to `stderr` — they do not\n * cause the function to throw. Files whose name starts with `_` are skipped entirely\n * (treated as drafts or disabled flows). Files missing the required `id`, `nodes`, or\n * `edges` fields are also discarded silently.\n *\n * @param dirPath - Absolute path to the directory to scan.\n * @returns Array of successfully parsed {@link FlowDefinition} objects. Empty if the\n * directory does not exist or contains no valid flow files.\n * @docLink packages/flow-engine/concepts#flow-loading\n */\nexport function loadFlowsFromDir(dirPath: string): FlowDefinition[] {\n if (!fs.existsSync(dirPath)) return [];\n\n const files = fs.readdirSync(dirPath).filter((f) => {\n if (f.startsWith(\"_\")) return false;\n return f.endsWith(\".flow.yaml\") || f.endsWith(\".flow.json\") || f.endsWith(\".json\");\n });\n\n const flows: FlowDefinition[] = [];\n\n for (const file of files) {\n try {\n const def = loadFlow(path.join(dirPath, file));\n if (def.id && def.nodes && def.edges) {\n flows.push(def);\n }\n } catch (err) {\n process.stderr.write(`[agent-flow-engine] skipping ${file}: ${(err as Error).message}\\n`);\n }\n }\n\n return flows;\n}\n\n/**\n * Discover and load all flow definitions from every domain under an `ai-assets` root.\n *\n * Walks the top-level subdirectories of `aiResourcesRoot`, looks for a `flows/`\n * subdirectory inside each domain, and delegates to {@link loadFlowsFromDir} for\n * each one found. Files prefixed with `_` are skipped (draft/disabled).\n *\n * @param aiResourcesRoot - Absolute path to the `ai-assets/` directory (or equivalent\n * resource root). Typically the `ai-assets/` folder at the monorepo root.\n * @returns Flat array of all successfully parsed {@link FlowDefinition} objects across\n * all domains. Empty if the root directory does not exist.\n * @docLink packages/flow-engine/concepts#flow-loading\n */\nexport function loadAllFlows(aiResourcesRoot: string): FlowDefinition[] {\n if (!fs.existsSync(aiResourcesRoot)) return [];\n\n // `assetSearchDirs` covers both the flat (`<root>/flows/`) and domain-nested\n // (`<root>/<domain>/flows/`) layouts via the one shared layout primitive.\n // De-dupe by id (first dir wins) so a root that happens to define a flow in\n // both layouts surfaces it once.\n const byId = new Map<string, FlowDefinition>();\n for (const { dir } of assetSearchDirs(aiResourcesRoot, \"flows\")) {\n for (const flow of loadFlowsFromDir(dir)) {\n if (!byId.has(flow.id)) byId.set(flow.id, flow);\n }\n }\n return [...byId.values()];\n}\n"]}
@@ -1,15 +1,15 @@
1
- import { deployAll, removeAsset, createScaffold } from './chunk-2Y4HIITD.js';
2
- import { writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-SDAKQCOB.js';
3
- import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-WBF7JLTY.js';
4
- import { migrateLegacyDir, resolveSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, resolveAll, buildProvenanceIndex, ensureRepo, sourceShortName, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, readLinks } from './chunk-PBO6SCT2.js';
1
+ import { deployAll, removeAsset, createScaffold } from './chunk-7ZWLZ5H3.js';
2
+ import { writeLock, buildLockFile, readLock, verifyLock, extractForPatch, generatePatch, savePatch, applyPatch } from './chunk-3KPNDTMR.js';
3
+ import { resolveRuntimeAssets, factoryAssetRoots } from './chunk-W53D5Q52.js';
4
+ import { globalSkaileDir, resolveGlobalBackends, globalCacheRoot, migrateLegacyDir, resolveGlobalSkWorkspaceConfig, resolveSkWorkspaceConfig, getGlobalCacheDir, sourceCacheKey, getRepoCommit, resolveAll, buildProvenanceIndex, ensureRepo, sourceShortName, scanRepo, SKAILE_YAML_DEFAULT, checkRepoStatus, resolveAsset, readLinks } from './chunk-NXC6IEL4.js';
5
5
  import { parseAssetRef } from './chunk-GEEW6SY2.js';
6
- import { deployedBase, isDeployed, deployedDir } from './chunk-XGCXFX7X.js';
6
+ import { deployedBase, isDeployed, deployedDir } from './chunk-F3HNW354.js';
7
7
  import { appendHistory, getRecentHistory, clearHistory } from './chunk-KTBKW2FI.js';
8
8
  import { commitChanges } from './chunk-UQ6LFBPZ.js';
9
9
  import { spawnSync } from 'child_process';
10
- import { existsSync, readdirSync, rmSync, lstatSync, unlinkSync, readFileSync, writeFileSync } from 'fs';
10
+ import { existsSync, readdirSync, rmSync, lstatSync, unlinkSync, mkdirSync, writeFileSync, readFileSync } from 'fs';
11
11
  import { resolve, join, sep, dirname } from 'path';
12
- import { parse, stringify } from 'yaml';
12
+ import { stringify, parse } from 'yaml';
13
13
 
14
14
  function normalizeRepoUrl(url) {
15
15
  return url.trim().replace(/^git@([^:]+):/, "https://$1/").replace(/^[a-z]+:\/\//i, "").replace(/\.git$/i, "").replace(/\/+$/, "").toLowerCase();
@@ -143,6 +143,8 @@ var AssetManager = class {
143
143
  driverTarget;
144
144
  /** Whether this instance operates in global-install mode. */
145
145
  global;
146
+ /** Explicit global-backend override (global mode only); else auto-resolved. */
147
+ backendsOverride;
146
148
  /** Injected catalog fetcher (tests / custom); falls back to a built one. */
147
149
  injectedStoreFetcher;
148
150
  /** Injected byte fetcher for store staging; falls back to GitHub. */
@@ -153,17 +155,39 @@ var AssetManager = class {
153
155
  this.projectDir = resolve(opts.projectDir);
154
156
  this.driverTarget = opts.driverTarget ?? "claude-code";
155
157
  this.global = opts.global ?? false;
158
+ this.backendsOverride = opts.backends;
156
159
  this.injectedStoreFetcher = opts.storeFetcher;
157
160
  this.injectedAssetFetcher = opts.assetFetcher;
158
161
  this.catalogUrlOverride = opts.catalogUrl;
159
162
  }
163
+ /**
164
+ * Root for this manager's **state** — config SSOT, lock, cache, history.
165
+ * `~/.skaile` in global mode (the cross-backend SSOT), else the project dir.
166
+ * Deploy dirs are unaffected; they come from `DRIVER_TARGETS[target]`.
167
+ */
168
+ get stateRoot() {
169
+ return this.global ? globalSkaileDir() : this.projectDir;
170
+ }
171
+ /**
172
+ * The backends a global deploy fans out to: the explicit `backends` override
173
+ * (a `--backend` filter), else `resolveGlobalBackends()`. In project mode this
174
+ * is exactly `[driverTarget]`, so the shared fan-out loop degenerates to the
175
+ * single-target path.
176
+ */
177
+ targetBackends() {
178
+ if (!this.global) return [this.driverTarget];
179
+ if (this.backendsOverride && this.backendsOverride.length > 0) return this.backendsOverride;
180
+ return resolveGlobalBackends();
181
+ }
160
182
  get storeCacheDir() {
183
+ if (this.global) return join(globalCacheRoot(), "store");
161
184
  return migrateLegacyDir(
162
185
  join(this.projectDir, ".skaile", "cache", "store"),
163
186
  join(this.projectDir, ".skaile", "store-cache")
164
187
  );
165
188
  }
166
189
  get reposDir() {
190
+ if (this.global) return join(globalCacheRoot(), "sources");
167
191
  return migrateLegacyDir(
168
192
  join(this.projectDir, ".skaile", "cache", "sources"),
169
193
  join(this.projectDir, ".skaile", "repos")
@@ -178,20 +202,18 @@ var AssetManager = class {
178
202
  return { store: this.storeCacheDir, sources: this.reposDir };
179
203
  }
180
204
  get lockPath() {
181
- return join(this.projectDir, "skaile.lock.yaml");
205
+ return join(this.stateRoot, "skaile.lock.yaml");
182
206
  }
183
207
  get patchDir() {
184
208
  return join(this.projectDir, ".skaile", "patches");
185
209
  }
186
- get deployOpts() {
187
- return { driverTarget: this.driverTarget, global: this.global, cwd: this.projectDir };
188
- }
189
- /** {@link deployOpts} with an explicit `link` opt-in for the symlink dev-loop. */
190
- deployOptsWith(link) {
191
- return { ...this.deployOpts, link: link === true };
210
+ /** Deploy options for one backend. In global mode, `driverTarget` is the
211
+ * fan-out target (not the constructor's `driverTarget`, which is project-only). */
212
+ deployOptsFor(target, link) {
213
+ return { driverTarget: target, global: this.global, cwd: this.projectDir, link: link === true };
192
214
  }
193
215
  loadConfig() {
194
- const config = resolveSkWorkspaceConfig(this.projectDir);
216
+ const config = this.global ? resolveGlobalSkWorkspaceConfig() : resolveSkWorkspaceConfig(this.projectDir);
195
217
  const sources = config.sources ?? [];
196
218
  const stores = config.stores ?? [];
197
219
  const dependencies = config.dependencies ?? [];
@@ -258,8 +280,10 @@ var AssetManager = class {
258
280
  }
259
281
  }
260
282
  if (!cloneDir || !slug) return null;
261
- const mdName = MD_BY_KIND[c.kind];
262
- const mdRel = c.files.find((f) => mdName ? f.path.endsWith(mdName) : false)?.path;
283
+ const mdRel = matchManifestPath(
284
+ c.kind,
285
+ c.files.map((f) => f.path)
286
+ ) ?? c.files[0]?.path;
263
287
  const source = mdRel ? join(cloneDir, mdRel) : cloneDir;
264
288
  const entry = {
265
289
  name: c.name,
@@ -489,7 +513,13 @@ var AssetManager = class {
489
513
  });
490
514
  const removed = this.reconcileRemovedAssets(resolved);
491
515
  const entries = await this.buildCatalogEntries(resolved, repositories);
492
- const deployed = deployAll(entries, repositories, patches, this.deployOptsWith(opts?.link));
516
+ const deployed = [
517
+ ...new Set(
518
+ this.targetBackends().flatMap(
519
+ (t) => deployAll(entries, repositories, patches, this.deployOptsFor(t, opts?.link))
520
+ )
521
+ )
522
+ ];
493
523
  writeLock(this.lockPath, buildLockFile(resolved, overridesApplied));
494
524
  this.recordInstallHistory(deployed, removed);
495
525
  const { npmInstalled, npmFailed } = await this.installRuntimeAssetDeps();
@@ -534,7 +564,7 @@ var AssetManager = class {
534
564
  if (!resolvedRefs.has(ref)) {
535
565
  const { kind, name } = parseCanonicalLockKey(ref);
536
566
  if (kind && name) {
537
- removeAsset(kind, name, this.deployOpts);
567
+ for (const t of this.targetBackends()) removeAsset(kind, name, this.deployOptsFor(t));
538
568
  removed.push(ref);
539
569
  }
540
570
  }
@@ -672,7 +702,13 @@ var AssetManager = class {
672
702
  });
673
703
  if (!repositories[slug]) repositories[slug] = { url: entry.source.url, path: cloneDir };
674
704
  }
675
- const deployed = deployAll(resolved, repositories, patches, this.deployOpts);
705
+ const deployed = [
706
+ ...new Set(
707
+ this.targetBackends().flatMap(
708
+ (t) => deployAll(resolved, repositories, patches, this.deployOptsFor(t))
709
+ )
710
+ )
711
+ ];
676
712
  return { deployed, removed: [], missing: [], lockWritten: false };
677
713
  }
678
714
  /**
@@ -712,7 +748,13 @@ var AssetManager = class {
712
748
  );
713
749
  }
714
750
  const entries = await this.buildCatalogEntries(resolved, repositories);
715
- const deployed = deployAll(entries, repositories, patches, this.deployOptsWith(opts?.link));
751
+ const deployed = [
752
+ ...new Set(
753
+ this.targetBackends().flatMap(
754
+ (t) => deployAll(entries, repositories, patches, this.deployOptsFor(t, opts?.link))
755
+ )
756
+ )
757
+ ];
716
758
  this.addDependencyToConfig(ref);
717
759
  for (const d of deployed) {
718
760
  appendHistory(this.projectDir, {
@@ -732,7 +774,10 @@ var AssetManager = class {
732
774
  */
733
775
  remove(ref) {
734
776
  const parsed = parseAssetRef(ref);
735
- const ok = removeAsset(parsed.kind, parsed.name, this.deployOpts);
777
+ let ok = false;
778
+ for (const t of this.targetBackends()) {
779
+ if (removeAsset(parsed.kind, parsed.name, this.deployOptsFor(t))) ok = true;
780
+ }
736
781
  if (ok) {
737
782
  const depRef = `${parsed.kind}:${parsed.name}`;
738
783
  this.removeDependencyFromConfig(depRef);
@@ -772,6 +817,22 @@ var AssetManager = class {
772
817
  }
773
818
  return all;
774
819
  }
820
+ /**
821
+ * On-disk root + config slug for every declared (and the implicit factory)
822
+ * source that has a local clone. Companion to {@link search}: callers that
823
+ * need to relate a scanned entry back to its source root (e.g. to stamp
824
+ * `DOMAIN.md`-derived domain grouping) can't recover the root from the flat
825
+ * {@link CatalogEntry} list `search` returns.
826
+ */
827
+ searchRepoRoots() {
828
+ const { repositories } = this.loadConfig();
829
+ const out = [];
830
+ for (const [name, decl] of Object.entries(repositories)) {
831
+ const repoDir = this.resolveRepoDir(decl, name);
832
+ if (repoDir) out.push({ repoName: name, root: repoDir });
833
+ }
834
+ return out;
835
+ }
775
836
  /**
776
837
  * Look up a single asset's full catalog entry.
777
838
  *
@@ -895,6 +956,60 @@ var AssetManager = class {
895
956
  }
896
957
  return out;
897
958
  }
959
+ /**
960
+ * Per-backend reconciliation of the **global** declared deps
961
+ * (`~/.skaile/skaile.yaml`) against each global backend's deploy dir. The
962
+ * global twin of {@link listDeclared}: the same `declared` / `installed` /
963
+ * `drift` / `invalid` vocabulary, but one row **per (ref, backend)** so an
964
+ * asset can be `installed` for `claude-code` and `drift`/`declared` for
965
+ * `codex` at once.
966
+ *
967
+ * Reads the SSOT + the global lock (`~/.skaile/skaile.lock.yaml`) — construct
968
+ * the manager with `global: true`. Unlike `listDeclared`, a missing SSOT is
969
+ * **not** an error: it yields an empty list (a fresh machine has no globals).
970
+ *
971
+ * @param opts.backend - Reconcile against this one backend only (the
972
+ * `--backend` filter); omit for every backend in {@link targetBackends}.
973
+ * @param opts.kind - Filter by asset kind.
974
+ * @returns One {@link BackendDeclaredAsset} per declared dep × backend.
975
+ * @throws {Error} on legacy keys in `~/.skaile/skaile.yaml` (migration hint).
976
+ */
977
+ globalState(opts) {
978
+ const dependencies = resolveGlobalSkWorkspaceConfig().dependencies ?? [];
979
+ const lock = this.tryReadLock();
980
+ const lockKeys = lock ? Object.keys(lock.assets).map(parseCanonicalLockKey) : [];
981
+ const backends = opts?.backend ? [opts.backend] : this.targetBackends();
982
+ const out = [];
983
+ for (const ref of dependencies) {
984
+ let parsed;
985
+ try {
986
+ parsed = parseAssetRef(ref);
987
+ } catch {
988
+ if (!opts?.kind) {
989
+ for (const backend of backends)
990
+ out.push({ ref, kind: "", name: ref, state: "invalid", backend });
991
+ }
992
+ continue;
993
+ }
994
+ if (opts?.kind && parsed.kind !== opts.kind) continue;
995
+ const locked = lockKeys.some(
996
+ (k) => k.kind === parsed.kind && k.name === parsed.name && (!parsed.publisher || k.publisher === parsed.publisher)
997
+ );
998
+ for (const backend of backends) {
999
+ let state;
1000
+ if (!locked) {
1001
+ state = "declared";
1002
+ } else if (NON_DEPLOYABLE_KINDS.has(parsed.kind)) {
1003
+ state = "installed";
1004
+ } else {
1005
+ const onDisk = isDeployed(parsed.kind, parsed.name, backend, true);
1006
+ state = onDisk ? "installed" : "drift";
1007
+ }
1008
+ out.push({ ref, kind: parsed.kind, name: parsed.name, state, backend });
1009
+ }
1010
+ }
1011
+ return out;
1012
+ }
898
1013
  /**
899
1014
  * Build an aggregated workspace overview with domain grouping and sync status.
900
1015
  *
@@ -1300,11 +1415,20 @@ var AssetManager = class {
1300
1415
  }
1301
1416
  }
1302
1417
  // ── Helpers ────────────────────────────────────────────────────────────
1303
- /** Add a dependency ref to skaile.yaml if not already present. */
1418
+ /**
1419
+ * Add a dependency ref to the manifest `dependencies:` if not already present.
1420
+ * Project mode edits `<projectDir>/skaile.yaml`; global mode edits the
1421
+ * user-scope SSOT `~/.skaile/skaile.yaml`, **bootstrapping** the file (and its
1422
+ * parent dir) when absent so `skaile add --global` works on a fresh machine.
1423
+ */
1304
1424
  addDependencyToConfig(ref) {
1305
- if (this.global) return;
1306
- const configPath = join(this.projectDir, "skaile.yaml");
1307
- if (!existsSync(configPath)) return;
1425
+ const configPath = join(this.stateRoot, "skaile.yaml");
1426
+ if (!existsSync(configPath)) {
1427
+ if (!this.global) return;
1428
+ mkdirSync(this.stateRoot, { recursive: true });
1429
+ writeFileSync(configPath, stringify({ dependencies: [ref] }, { lineWidth: 120 }));
1430
+ return;
1431
+ }
1308
1432
  const raw = parse(readFileSync(configPath, "utf8")) ?? {};
1309
1433
  if (!raw.dependencies) raw.dependencies = [];
1310
1434
  if (!raw.dependencies.includes(ref)) {
@@ -1312,10 +1436,12 @@ var AssetManager = class {
1312
1436
  writeFileSync(configPath, stringify(raw, { lineWidth: 120 }));
1313
1437
  }
1314
1438
  }
1315
- /** Remove a dependency ref from skaile.yaml. */
1439
+ /**
1440
+ * Remove a dependency ref from the manifest `dependencies:`. Targets the same
1441
+ * file as {@link addDependencyToConfig} (`~/.skaile/skaile.yaml` in global mode).
1442
+ */
1316
1443
  removeDependencyFromConfig(ref) {
1317
- if (this.global) return;
1318
- const configPath = join(this.projectDir, "skaile.yaml");
1444
+ const configPath = join(this.stateRoot, "skaile.yaml");
1319
1445
  if (!existsSync(configPath)) return;
1320
1446
  const raw = parse(readFileSync(configPath, "utf8")) ?? {};
1321
1447
  if (!raw.dependencies) return;
@@ -1343,5 +1469,5 @@ var AssetManager = class {
1343
1469
  };
1344
1470
 
1345
1471
  export { AssetManager, MissingManifestError, NON_DEPLOYABLE_KINDS, parseCanonicalLockKey };
1346
- //# sourceMappingURL=chunk-C5RYGUF4.js.map
1347
- //# sourceMappingURL=chunk-C5RYGUF4.js.map
1472
+ //# sourceMappingURL=chunk-TCNYSHPM.js.map
1473
+ //# sourceMappingURL=chunk-TCNYSHPM.js.map