@skaile/workspaces 2.8.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +17 -6
  3. package/dist/{asset-feeds-23CP6YUY.js → asset-feeds-XKPJZ6QT.js} +4 -4
  4. package/dist/{asset-feeds-23CP6YUY.js.map → asset-feeds-XKPJZ6QT.js.map} +1 -1
  5. package/dist/asset-manager/index.js +1 -1
  6. package/dist/bridge/drivers/claude-sdk.js +2 -2
  7. package/dist/bridge/drivers/codex.js +2 -2
  8. package/dist/bridge/drivers/continue.js +2 -2
  9. package/dist/bridge/drivers/echo.js +1 -1
  10. package/dist/bridge/drivers/gemini.js +4 -4
  11. package/dist/bridge/drivers/goose.js +2 -2
  12. package/dist/bridge/drivers/omp.js +1 -1
  13. package/dist/bridge/drivers/opencode.js +2 -2
  14. package/dist/bridge/drivers/qwen.js +4 -4
  15. package/dist/bridge/index.js +3 -3
  16. package/dist/bridge/src/models.d.ts +59 -0
  17. package/dist/bridge/src/models.d.ts.map +1 -1
  18. package/dist/{chunk-XJ74XFIZ.js → chunk-5QGMEPUX.js} +27 -18
  19. package/dist/chunk-5QGMEPUX.js.map +1 -0
  20. package/dist/{chunk-ONUDDQGS.js → chunk-7HXS7WZF.js} +2 -2
  21. package/dist/{chunk-ONUDDQGS.js.map → chunk-7HXS7WZF.js.map} +1 -1
  22. package/dist/{chunk-SCR3WGW7.js → chunk-7KFN2EPR.js} +12 -4
  23. package/dist/chunk-7KFN2EPR.js.map +1 -0
  24. package/dist/{chunk-L3TS7ZO4.js → chunk-BJDACPWZ.js} +3 -3
  25. package/dist/{chunk-L3TS7ZO4.js.map → chunk-BJDACPWZ.js.map} +1 -1
  26. package/dist/{chunk-JIA2S3T2.js → chunk-EH7BCJF4.js} +6 -6
  27. package/dist/{chunk-JIA2S3T2.js.map → chunk-EH7BCJF4.js.map} +1 -1
  28. package/dist/{chunk-TUYN2HDT.js → chunk-F5VREBV2.js} +14 -5
  29. package/dist/chunk-F5VREBV2.js.map +1 -0
  30. package/dist/{chunk-OAUKA7VT.js → chunk-JQMULHO6.js} +24 -12
  31. package/dist/chunk-JQMULHO6.js.map +1 -0
  32. package/dist/{chunk-ZR2X4SIG.js → chunk-KXWUCKP5.js} +5 -5
  33. package/dist/{chunk-ZR2X4SIG.js.map → chunk-KXWUCKP5.js.map} +1 -1
  34. package/dist/{chunk-IWUIXNMF.js → chunk-N4GFUWWC.js} +3 -3
  35. package/dist/{chunk-IWUIXNMF.js.map → chunk-N4GFUWWC.js.map} +1 -1
  36. package/dist/{chunk-ZJOEU5GP.js → chunk-NMKTM55X.js} +2 -2
  37. package/dist/{chunk-ZJOEU5GP.js.map → chunk-NMKTM55X.js.map} +1 -1
  38. package/dist/{chunk-XTFZOYNY.js → chunk-P2J3MLTW.js} +3 -3
  39. package/dist/{chunk-XTFZOYNY.js.map → chunk-P2J3MLTW.js.map} +1 -1
  40. package/dist/{chunk-VNIKF66R.js → chunk-P5W6JVD4.js} +4 -4
  41. package/dist/{chunk-VNIKF66R.js.map → chunk-P5W6JVD4.js.map} +1 -1
  42. package/dist/{chunk-6AYGXPPF.js → chunk-Q6O53D5Q.js} +2 -2
  43. package/dist/{chunk-6AYGXPPF.js.map → chunk-Q6O53D5Q.js.map} +1 -1
  44. package/dist/{chunk-ZJ7MRR2R.js → chunk-QGDQHNYC.js} +4 -4
  45. package/dist/{chunk-ZJ7MRR2R.js.map → chunk-QGDQHNYC.js.map} +1 -1
  46. package/dist/{chunk-E4AVJMOJ.js → chunk-S5FV6ISY.js} +89 -6
  47. package/dist/chunk-S5FV6ISY.js.map +1 -0
  48. package/dist/{chunk-HY3MBSNC.js → chunk-SR6NBBWT.js} +2 -2
  49. package/dist/{chunk-HY3MBSNC.js.map → chunk-SR6NBBWT.js.map} +1 -1
  50. package/dist/{chunk-AZ44F3AT.js → chunk-TXTCW7V6.js} +6 -6
  51. package/dist/{chunk-AZ44F3AT.js.map → chunk-TXTCW7V6.js.map} +1 -1
  52. package/dist/{chunk-BMQKMOQY.js → chunk-V34ZEXSE.js} +61 -3
  53. package/dist/chunk-V34ZEXSE.js.map +1 -0
  54. package/dist/{chunk-FW2C6JJP.js → chunk-WECBTWWZ.js} +3 -3
  55. package/dist/{chunk-FW2C6JJP.js.map → chunk-WECBTWWZ.js.map} +1 -1
  56. package/dist/{chunk-P3DUVOAW.js → chunk-XJECOBCO.js} +16 -7
  57. package/dist/chunk-XJECOBCO.js.map +1 -0
  58. package/dist/{chunk-HVQWLYZB.js → chunk-ZO7KL7GN.js} +731 -85
  59. package/dist/chunk-ZO7KL7GN.js.map +1 -0
  60. package/dist/cli/index.js +38 -38
  61. package/dist/connectors/index.js +11 -5
  62. package/dist/{ensure-sources-N7B7657V.js → ensure-sources-D6R57GAP.js} +4 -4
  63. package/dist/{ensure-sources-N7B7657V.js.map → ensure-sources-D6R57GAP.js.map} +1 -1
  64. package/dist/factory-assets/connectors/box.js +11 -5
  65. package/dist/factory-assets/connectors/deploy.js +11 -5
  66. package/dist/factory-assets/connectors/devserver.js +11 -5
  67. package/dist/factory-assets/connectors/flow/CONNECTOR.md +80 -11
  68. package/dist/factory-assets/connectors/flow/adapter.d.ts +97 -5
  69. package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
  70. package/dist/factory-assets/connectors/flow/adapter.js +11 -5
  71. package/dist/factory-assets/connectors/flow/contract/expression.d.ts +2 -24
  72. package/dist/factory-assets/connectors/flow/contract/expression.d.ts.map +1 -1
  73. package/dist/factory-assets/connectors/flow/contract/flow.v2.schema.json +0 -6
  74. package/dist/factory-assets/connectors/flow/contract/normalize.d.ts.map +1 -1
  75. package/dist/factory-assets/connectors/flow/contract/schema.d.ts +0 -4
  76. package/dist/factory-assets/connectors/flow/contract/schema.d.ts.map +1 -1
  77. package/dist/factory-assets/connectors/flow/contract.js +2 -2
  78. package/dist/factory-assets/connectors/flow/engine/bindings.d.ts.map +1 -1
  79. package/dist/factory-assets/connectors/flow/engine/check-provenance.d.ts +47 -0
  80. package/dist/factory-assets/connectors/flow/engine/check-provenance.d.ts.map +1 -0
  81. package/dist/factory-assets/connectors/flow/engine/index.d.ts +3 -0
  82. package/dist/factory-assets/connectors/flow/engine/index.d.ts.map +1 -1
  83. package/dist/factory-assets/connectors/flow/engine/node-attempts.d.ts +68 -0
  84. package/dist/factory-assets/connectors/flow/engine/node-attempts.d.ts.map +1 -0
  85. package/dist/factory-assets/connectors/flow/engine/node-deadline.d.ts +44 -0
  86. package/dist/factory-assets/connectors/flow/engine/node-deadline.d.ts.map +1 -0
  87. package/dist/factory-assets/connectors/flow/engine/node-shape.d.ts +15 -1
  88. package/dist/factory-assets/connectors/flow/engine/node-shape.d.ts.map +1 -1
  89. package/dist/factory-assets/connectors/flow/engine/types.d.ts +16 -15
  90. package/dist/factory-assets/connectors/flow/engine/types.d.ts.map +1 -1
  91. package/dist/factory-assets/connectors/flow/engine.js +3 -3
  92. package/dist/factory-assets/connectors/flow/index.d.ts +2 -1
  93. package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
  94. package/dist/factory-assets/connectors/flow/inline-sub-flow-host.d.ts +3 -0
  95. package/dist/factory-assets/connectors/flow/inline-sub-flow-host.d.ts.map +1 -1
  96. package/dist/factory-assets/connectors/flow/node-executor.d.ts +10 -4
  97. package/dist/factory-assets/connectors/flow/node-executor.d.ts.map +1 -1
  98. package/dist/factory-assets/connectors/flow/prompt-fragments.d.ts +14 -0
  99. package/dist/factory-assets/connectors/flow/prompt-fragments.d.ts.map +1 -1
  100. package/dist/factory-assets/connectors/flow/prompt-fragments.js +2 -2
  101. package/dist/factory-assets/connectors/flow/run-flow.d.ts.map +1 -1
  102. package/dist/factory-assets/connectors/flow/run-flow.js +12 -6
  103. package/dist/factory-assets/connectors/flow/subprompt-runner.d.ts +99 -0
  104. package/dist/factory-assets/connectors/flow/subprompt-runner.d.ts.map +1 -0
  105. package/dist/factory-assets/connectors/flow.js +11 -5
  106. package/dist/factory-assets/connectors/git.js +11 -5
  107. package/dist/factory-assets/connectors/gmail.js +11 -5
  108. package/dist/factory-assets/connectors/googledrive.js +11 -5
  109. package/dist/factory-assets/connectors/local.js +11 -5
  110. package/dist/factory-assets/connectors/mattermost.js +11 -5
  111. package/dist/factory-assets/connectors/memory.js +11 -5
  112. package/dist/factory-assets/connectors/minio.js +11 -5
  113. package/dist/factory-assets/connectors/postgres.js +11 -5
  114. package/dist/factory-assets/connectors/s3.js +11 -5
  115. package/dist/factory-assets/connectors/sharepoint.js +11 -5
  116. package/dist/factory-assets/connectors/sqlite.js +11 -5
  117. package/dist/factory-assets/connectors/static-server.js +11 -5
  118. package/dist/factory-assets/connectors/tunnel.js +11 -5
  119. package/dist/factory-assets/connectors/webdav.js +11 -5
  120. package/dist/factory-assets/connectors/xstate-store.js +11 -5
  121. package/dist/factory-assets/connectors/xstate.js +11 -5
  122. package/dist/{flows-K7B253U6.js → flows-LQSVM45J.js} +3 -3
  123. package/dist/{flows-K7B253U6.js.map → flows-LQSVM45J.js.map} +1 -1
  124. package/dist/{helpers-PXEHIKF7.js → helpers-IS4MSEOQ.js} +4 -4
  125. package/dist/{helpers-PXEHIKF7.js.map → helpers-IS4MSEOQ.js.map} +1 -1
  126. package/dist/{library-publish-3Z33J2ZY.js → library-publish-QJACP6FW.js} +9 -9
  127. package/dist/{library-publish-3Z33J2ZY.js.map → library-publish-QJACP6FW.js.map} +1 -1
  128. package/dist/{open-library-Y5SKFAMK.js → open-library-3FMLAU3F.js} +8 -8
  129. package/dist/{open-library-Y5SKFAMK.js.map → open-library-3FMLAU3F.js.map} +1 -1
  130. package/dist/{project-DQRC6J6M.js → project-KEAAGHSX.js} +5 -5
  131. package/dist/{project-DQRC6J6M.js.map → project-KEAAGHSX.js.map} +1 -1
  132. package/dist/runner/index.js +15 -15
  133. package/dist/runner/src/serve.d.ts.map +1 -1
  134. package/dist/sdk/asset-manager.js +1 -1
  135. package/dist/sdk/bridge.js +3 -3
  136. package/dist/sdk/flow.js +3 -3
  137. package/dist/sdk/index.js +15 -15
  138. package/dist/sdk/runner.js +15 -15
  139. package/dist/{setup-RHWARBBB.js → setup-VX6EPF5P.js} +5 -5
  140. package/dist/{setup-RHWARBBB.js.map → setup-VX6EPF5P.js.map} +1 -1
  141. package/dist/{source-XBJ5KTAV.js → source-45XHQSBF.js} +9 -9
  142. package/dist/{source-XBJ5KTAV.js.map → source-45XHQSBF.js.map} +1 -1
  143. package/dist/{source-manifest-publish-Q7TXBMCW.js → source-manifest-publish-M34SKD46.js} +10 -10
  144. package/dist/{source-manifest-publish-Q7TXBMCW.js.map → source-manifest-publish-M34SKD46.js.map} +1 -1
  145. package/dist/tui/index.js +15 -15
  146. package/dist/types/src/flow.d.ts +128 -0
  147. package/dist/types/src/flow.d.ts.map +1 -1
  148. package/dist/types/src/index.d.ts +1 -1
  149. package/dist/types/src/index.d.ts.map +1 -1
  150. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  151. package/dist/workspace-plugin/adapters/omp.js +3 -3
  152. package/dist/workspace-plugin/index.js +1 -1
  153. package/package.json +1 -1
  154. package/dist/chunk-BMQKMOQY.js.map +0 -1
  155. package/dist/chunk-E4AVJMOJ.js.map +0 -1
  156. package/dist/chunk-HVQWLYZB.js.map +0 -1
  157. package/dist/chunk-OAUKA7VT.js.map +0 -1
  158. package/dist/chunk-P3DUVOAW.js.map +0 -1
  159. package/dist/chunk-SCR3WGW7.js.map +0 -1
  160. package/dist/chunk-TUYN2HDT.js.map +0 -1
  161. package/dist/chunk-XJ74XFIZ.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## 3.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - [#515](https://github.com/skaile-ai/workspaces/pull/515) [`ff160e9`](https://github.com/skaile-ai/workspaces/commit/ff160e92dc97fce2cfdaae5c75b9add9fc8553dc) Thanks [@peteralbert](https://github.com/peteralbert)! - Remove the inert `control.subagent` and `defaults.subagentMode` fields from the Flow v2 contract.
8
+
9
+ Both were carried through v1 normalization while it was open whether a later node kind would consume them; nothing ever read either. They meant "run this skill in a fresh conversation context" — which is what a `sub-flow` already does, not the single isolated model call a `subprompt` performs — so wiring them to `subprompt` would have silently changed what authored flows do.
10
+
11
+ **Breaking:** both keys are gone from the strict v2 schema, so a v2 document carrying either is now rejected with an authored path. Only the v1 normalizer ever produced them and it no longer does; a v1 document may still carry them and both are dropped. Dropping `subagent_mode` is explicit rather than a deleted key mapping, because `defaults.parameters` is an open passthrough bag — an unmapped key would have survived as `defaults.parameters.subagent_mode`, a rename rather than a removal.
12
+
13
+ ### Minor Changes
14
+
15
+ - [#515](https://github.com/skaile-ai/workspaces/pull/515) [`ff160e9`](https://github.com/skaile-ai/workspaces/commit/ff160e92dc97fce2cfdaae5c75b9add9fc8553dc) Thanks [@peteralbert](https://github.com/peteralbert)! - Activate Flow v2 `subprompt` nodes — the last of the seven Flow v2 kinds. A subprompt is `function`-shaped for everything except how the work is performed and how its output provenance is classified: instead of `NodeExecutor`, it hands its interpolated instruction to a `SubpromptRunner`, whose production implementation (`SessionSubpromptRunner`) constructs a second, isolated `AgentDriver` instance per call — same backend, provider, resolved model, and credentials as the session driver, but no Skaile system prompt, no MCP servers, no connector capabilities, no access to the session conversation, and bounded to a single turn. It does retain the backend's own native tool surface rooted at the session workspace — isolation here is a separate conversation, not a sandbox. `run.model` (`"small" | "default" | "deep"`) resolves through a new pure `resolveModelTier` in `bridge/src/models.ts`: a host-configured override first, then `PROVIDER_MODEL_TIERS`, a new built-in per-provider table of direct provider-API ids (consulted only on the direct API, since a gateway transport renames them) whose every entry is pinned by test to also exist in `STATIC_MODELS`. `default` and an absent tier inherit the session model — the one id known to work for this deployment, already carrying whatever gateway translation the host configured; `small` and `deep` instead raise the new `ModelTierResolutionError` and fail the node, so an explicit request for a cheap or a strong model is never silently served by whichever model the session happened to start with. With no declared output contract the response is prose; with one declared, the response is additionally parsed as JSON and validated through the same `validateConsumedNodeOutput` path every kind uses — there is no corrective reprompt, so a parse or validation failure consumes `control.retries` like any ordinary failure. The reply is carried verbatim as the node's `summary` in both cases, since `fields` reaches a consumer only through an expression binding and `build_handoff` renders a predecessor's summary/artifacts/concerns but never its `fields`. `control.optional`, `control.retries`, and `control.timeoutSec` behave as they do for a `function` node, except that an optional subprompt whose retry budget is exhausted becomes `skipped` rather than `failed` — matching `sub-flow`, because only `complete` and `skipped` satisfy a hard `flow` edge, so leaving it `failed` would permanently block its dependents. A subprompt inside an inline `sub-flow` child reaches the same runner as one in the parent. A subprompt's output is classified `obtainedBy: "agent"` (fixing a provenance hole: a downstream `check` consuming it now always derives `"asserted"`, never `"verified"`). `raceWithTimeout` does not cancel the underlying driver call on timeout — a known, documented cost this change does not address.
16
+
17
+ ## 2.9.0
18
+
19
+ ### Minor Changes
20
+
21
+ - [#511](https://github.com/skaile-ai/workspaces/pull/511) [`90a3476`](https://github.com/skaile-ai/workspaces/commit/90a34763f64b1ca3f22699a1c807ed793c0c14db) Thanks [@peteralbert](https://github.com/peteralbert)! - Enforce Flow v2's `control.optional`, `control.retries`, and `control.timeoutSec` node controls, previously declared in the contract but read by nothing. `retries: N` bounds an automatic retry (first attempt plus N automatic retries) that composes with the existing `doFailNode(recoverable: true)` self-retry and the manual `retryNode` operator override, which remains outside the automatic budget. `timeoutSec` covers active execution only, pausing during approval/input waits; a `gate` node never times out. `function` and `sub-flow` nodes enforce it by racing their existing await; `agent` nodes have no await to wrap, so their deadline is derived from `startedAt` plus recorded approval/input history and re-evaluated by an opportunistic wake timer while connected. Late settlement after a timeout, cancel, hydrate, or start is rejected via `executionGeneration`, now checked consistently at every await site (previously only the sub-flow branch checked it). `NodeExecution` gains an additive `outputHistory: NodeExecutionAttempt[]` — an append-only record of every attempt, numbered from 1 and resuming at `max + 1` after hydration — while `output`/`error`/timestamps remain latest-pointer compatibility fields. A sub-flow node's own automatic retry now actually retries (previously the node could wedge `available` forever). The agent's own recoverable self-retry (`fail_node(recoverable: true)`) also appends an `outputHistory` entry now, marked `NodeExecutionAttempt.selfRetry: true` so it is never counted against the automatic `control.retries` budget. A delegated sub-flow child's own `error.at` is now preserved on the parent's failure instead of being overwritten by the parent's `completedAt`; the child's own `error.recoverable` remains intentionally not propagated — the parent's recoverability continues to follow only the parent node's own `control.retries`.
22
+
23
+ - [#513](https://github.com/skaile-ai/workspaces/pull/513) [`50d50b5`](https://github.com/skaile-ai/workspaces/commit/50d50b5304bf566490f04612ff3792d1e7034e22) Thanks [@peteralbert](https://github.com/peteralbert)! - Activate Flow v2 `check` nodes. A check runs the same deterministic process as a function node through `NodeExecutor`, but its exit status is a pass/fail verdict: a pass completes dark like a function, while a fail verdict derives evidence (compared values; provenance — "verified" when every compared value's _immediate_ origin was runtime-obtained, "asserted" otherwise, absent when there were no compared values; "live" vs. "flow-local" inputs, "live" being the floor) and, once `control.retries` is exhausted, either fails the node (`run.onFail: "fail"`) or parks it `awaiting_approval` with that evidence (`run.onFail: "escalate"`, the default). Escalation is a one-way door: `applyApproval` rejects an `"approved"` decision on a check outright, and `"rejected"` ends the node terminally `failed` with no revision path. A `check` node cannot declare `control.optional` — rejected at parse time. A spawn failure or timeout produces no verdict and always fails the node directly, with no evidence and no escalation. `NodeExecutionAttempt` gains an optional `check?: CheckEvidence`; `CheckEvidence` and its companion types (`CheckProvenance`, `CheckInputCurrency`, `CheckComparedValue`) plus `BindingOrigin` are now canonical in and exported from `@skaile/workspaces/types`.
24
+
3
25
  ## 2.8.0
4
26
 
5
27
  ### Minor Changes
package/README.md CHANGED
@@ -105,11 +105,22 @@ Explicit legacy `type: skill` and exact `type: sub-flow` nodes normalize to
105
105
  their executable v2 kinds; every other legacy kind remains an inert
106
106
  compatibility placeholder with its IDs, parameters, assets, and dependency
107
107
  semantics retained.
108
- The runtime activates `agent`, `function`, `gate`, `router`, and `sub-flow`.
108
+ The runtime activates all seven kinds: `agent`, `subprompt`, `function`,
109
+ `check`, `gate`, `router`, and `sub-flow`.
109
110
  Interpolated agent instructions, resolved values, and origins reach the session
110
- agent through `build_handoff(nodeId)`; function nodes run shell, Node, or Python
111
- commands in the existing session workspace without a model turn, with resolved
112
- values exported as environment variables. Gate nodes
111
+ agent through `build_handoff(nodeId)`; function and check nodes run shell,
112
+ Node, or Python commands in the existing session workspace without a model
113
+ turn, with resolved values exported as environment variables a check's exit
114
+ status is a pass/fail verdict rather than a plain success/failure. Subprompt
115
+ nodes are `function`-shaped except for how the work runs: a second, isolated
116
+ `AgentDriver` instance per call, with no Skaile system prompt, no MCP servers, no connector capabilities, and no access to the session conversation, bounded to a single turn. It does retain the backend's own native tool surface (a coding backend keeps its file and shell tools, rooted at the session workspace) — isolation here means a separate conversation, not a sandbox, resolving its declared `run.model` tier via a pure
117
+ `resolveModelTier` against per-provider built-in tiers, failing the node
118
+ rather than substituting a model when a tier cannot be served. A declared output contract drives a JSON-response request and
119
+ response parsing through the same consumed-output validation every kind uses;
120
+ there is no corrective reprompt, so a parse or validation failure is an
121
+ ordinary node failure. A subprompt's output is classified agent-obtained, so a
122
+ downstream check always derives "asserted" provenance over it, never
123
+ "verified". Gate nodes
113
124
  park immediately through the durable approval state, complete on approval, and
114
125
  preserve rejection feedback for revision and a later approval re-request.
115
126
  Router nodes evaluate ordered bounded expressions only after admission. The first
@@ -130,8 +141,8 @@ durable corrective call; deterministic functions fail directly. Unconsumed schem
130
141
  remain prose-only.
131
142
  Skills, connectors, mounts, MCP servers, and knowledge stay reusable
132
143
  `run.assets` requirements, and shared refs are deduplicated in the dependency
133
- graph. This release activates `agent`, `function`, `gate`, `router`, and
134
- `sub-flow`; other current kinds remain inert for later releases.
144
+ graph. All seven current kinds — `agent`, `subprompt`, `function`, `check`,
145
+ `gate`, `router`, and `sub-flow` are active.
135
146
  `FlowDefinition` is the strict authored-v2 type; parser results use the wider
136
147
  `ParsedFlowDefinition` so unknown legacy edge kinds and their metadata can be
137
148
  retained inertly without weakening authored validation.
@@ -65,7 +65,7 @@ async function libraryAssets() {
65
65
  const domains = [];
66
66
  try {
67
67
  const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([
68
- import('./open-library-Y5SKFAMK.js'),
68
+ import('./open-library-3FMLAU3F.js'),
69
69
  import('./library/index.js'),
70
70
  import('./core/index.js')
71
71
  ]);
@@ -98,7 +98,7 @@ async function libraryAssets() {
98
98
  async function storeAssets(projectDir) {
99
99
  const notes = [];
100
100
  try {
101
- const { resolveCatalogSource } = await import('./open-library-Y5SKFAMK.js');
101
+ const { resolveCatalogSource } = await import('./open-library-3FMLAU3F.js');
102
102
  const { source, close } = await resolveCatalogSource({ projectDir });
103
103
  try {
104
104
  const assets = await source.listAssets();
@@ -202,5 +202,5 @@ function dedupeBySlug(domains) {
202
202
  }
203
203
 
204
204
  export { gatherAssetFeeds };
205
- //# sourceMappingURL=asset-feeds-23CP6YUY.js.map
206
- //# sourceMappingURL=asset-feeds-23CP6YUY.js.map
205
+ //# sourceMappingURL=asset-feeds-XKPJZ6QT.js.map
206
+ //# sourceMappingURL=asset-feeds-XKPJZ6QT.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;AAqFA,SAAS,QAAQ,CAAA,EAAmB;AAClC,EAAA,OAAO,CAAA,CAAE,KAAA,CAAW,IAAA,CAAA,GAAG,CAAA,CAAE,KAAK,GAAG,CAAA;AACnC;AAGA,eAAe,cAAc,IAAA,EAAmC;AAC9D,EAAA,MAAM,MAAkB,EAAC;AACzB,EAAA,WAAA,MAAiB,EAAE,IAAA,EAAM,QAAA,EAAU,MAAK,IAAK,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC1D,IAAA,IAAI,SAAS,kBAAA,EAAoB;AACjC,IAAA,IAAI;AACF,MAAA,MAAM,EAAE,IAAA,EAAK,GAAI,iBAAiB,YAAA,CAAa,QAAA,EAAU,MAAM,CAAC,CAAA;AAChE,MAAA,GAAA,CAAI,IAAA,CAAK,cAAc,OAAA,CAAa,IAAA,CAAA,QAAA,CAAS,MAAM,QAAQ,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,IACtE,CAAA,CAAA,MAAQ;AAAA,IAAC;AAAA,EACX;AACA,EAAA,OAAO,GAAA;AACT;AAcA,eAAe,YAAA,CACb,IAAA,EACA,YAAA,EACA,OAAA,EACA,qBAAqB,IAAA,EACK;AAC1B,EAAA,MAAM,SAAA,GAAY,MAAM,aAAA,CAAc,IAAI,CAAA;AAC1C,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,GAAA,CAAI,CAAC,KAAA,MAAW;AAAA,IAC1C,KAAA;AAAA,IACA,KAAK,CAAA,EAAG,KAAA,CAAM,IAAI,CAAA,CAAA,EAAI,MAAM,IAAI,CAAA,CAAA;AAAA,IAChC,cAAc,OAAA,CAAa,IAAA,CAAA,QAAA,CAAS,IAAA,EAAM,KAAA,CAAM,MAAM,CAAC;AAAA,GACzD,CAAE,CAAA;AAEF,EAAA,IAAI,YAAA,GAAe,KAAA;AACnB,EAAA,KAAA,MAAW,KAAK,WAAA,EAAa;AAC3B,IAAA,MAAM,IAAA,GAAO,YAAA,CAAa,CAAA,CAAE,YAAA,EAAc,SAAS,CAAA;AACnD,IAAA,IAAI,IAAA,EAAM,CAAA,CAAE,KAAA,CAAM,UAAA,GAAa,IAAA;AAAA,SAAA,IACtB,kBAAA,EAAoB;AAC3B,MAAA,CAAA,CAAE,MAAM,UAAA,GAAa,YAAA;AACrB,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB,CAAA,MAAO,CAAA,CAAE,KAAA,CAAM,UAAA,GAAa,EAAA;AAAA,EAC9B;AAEA,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,gBAAA,CAAiB,aAAa,SAAS,CAAA;AACzD,EAAA,MAAM,UAA2B,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,IAChE,MAAM,CAAA,CAAE,IAAA;AAAA,IACR,OAAO,CAAA,CAAE,KAAA;AAAA,IACT,GAAI,EAAE,WAAA,GAAc,EAAE,aAAa,CAAA,CAAE,WAAA,KAAgB,EAAC;AAAA,IACtD,GAAI,EAAE,QAAA,GAAW,EAAE,UAAU,CAAA,CAAE,QAAA,KAAa,EAAC;AAAA,IAC7C,GAAI,EAAE,KAAA,KAAU,MAAA,GAAY,EAAE,KAAA,EAAO,CAAA,CAAE,KAAA,EAAM,GAAI,EAAC;AAAA,IAClD,GAAI,CAAA,CAAE,WAAA,CAAY,CAAC,CAAA,GAAI,EAAE,cAAA,EAAgB,CAAA,CAAE,WAAA,CAAY,CAAC,CAAA,EAAE,GAAI;AAAC,GACjE,CAAE,CAAA;AACF,EAAA,IAAI,YAAA,UAAsB,IAAA,CAAK,EAAE,MAAM,YAAA,EAAc,KAAA,EAAO,cAAc,CAAA;AAC1E,EAAA,OAAO,OAAA;AACT;AAUA,eAAe,aAAA,GAIZ;AACD,EAAA,MAAM,QAAoB,EAAC;AAC3B,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,IAAI;AACF,IAAA,MAAM,CAAC,EAAE,kBAAA,EAAmB,EAAG,EAAE,aAAA,EAAc,EAAG,EAAE,iBAAA,EAAmB,CAAA,GAAI,MAAM,QAAQ,GAAA,CAAI;AAAA,MAC3F,OAAO,4BAAmB,CAAA;AAAA,MAC1B,OAAO,oBAA4B,CAAA;AAAA,MACnC,OAAO,iBAAyB;AAAA,KACjC,CAAA;AACD,IAAA,MAAM,EAAE,OAAA,EAAS,KAAA,EAAM,GAAI,MAAM,kBAAA,EAAmB;AACpD,IAAA,IAAI;AAIF,MAAA,MAAM,UAAU,iBAAA,EAAkB;AAClC,MAAA,MAAM,UAAA,GAAkB,IAAA,CAAA,IAAA,CAAK,aAAA,EAAc,EAAG,SAAS,CAAA;AACvD,MAAA,MAAM,IAAA,GAAA,CAAQ,MAAM,OAAA,CAAQ,aAAA,EAAc,EAAG,MAAA;AAAA,QAC3C,CAAC,CAAA,KAAM,CAAC,CAAA,CAAE,IAAA,CAAK,UAAA,CAAW,OAAO,CAAA,IAAK,CAAC,CAAA,CAAE,IAAA,CAAK,UAAA,CAAW,UAAU;AAAA,OACrE;AACA,MAAA,MAAM,UAAyB,EAAC;AAChC,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,IAAI,CAAC,UAAA,CAAW,GAAA,CAAI,IAAI,CAAA,EAAG;AAI3B,QAAA,MAAM,UAAA,GAAa,CAAC,GAAI,MAAM,SAAS,GAAA,CAAI,IAAA,EAAM,GAAA,CAAI,IAAI,CAAE,CAAA;AAC3D,QAAA,OAAA,CAAQ,IAAA,CAAK,GAAI,MAAM,YAAA,CAAa,GAAA,CAAI,MAAM,GAAA,CAAI,IAAA,EAAM,UAAA,EAAY,KAAK,CAAE,CAAA;AAC3E,QAAA,KAAA,MAAW,KAAA,IAAS,UAAA,EAAY,OAAA,CAAQ,IAAA,CAAK,EAAE,MAAA,EAAQ,SAAA,EAAW,KAAA,EAAO,KAAA,EAAO,GAAA,CAAI,IAAA,EAAM,CAAA;AAAA,MAC5F;AACA,MAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAM;AAAA,IACnC,CAAA,SAAE;AACA,MAAA,KAAA,EAAM;AAAA,IACR;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,IAAA,EAAM,WAAA;AAAA,MACN,SAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACzD,CAAA;AACD,IAAA,OAAO,EAAE,OAAA,EAAS,EAAC,EAAG,SAAS,KAAA,EAAM;AAAA,EACvC;AACF;AAYA,eAAe,YAAY,UAAA,EAIxB;AACD,EAAA,MAAM,QAAoB,EAAC;AAC3B,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,oBAAA,EAAqB,GAAI,MAAM,OAAO,4BAAmB,CAAA;AACjE,IAAA,MAAM,EAAE,QAAQ,KAAA,EAAM,GAAI,MAAM,oBAAA,CAAqB,EAAE,YAAY,CAAA;AACnE,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,GAAS,MAAM,MAAA,CAAO,UAAA,EAAW;AACvC,MAAA,MAAM,OAAA,GAA0B,MAAA,CAAO,GAAA,CAAI,CAAC,CAAA,MAAO;AAAA,QACjD,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,IAAA,EAAO,EAAE,IAAA,IAAsB,OAAA;AAAA,QAC/B,WAAA,EAAa,EAAE,WAAA,IAAe,EAAA;AAAA,QAC9B,MAAA,EAAQ,CAAA,QAAA,EAAW,CAAA,CAAE,EAAE,CAAA,CAAA;AAAA,QACvB,WAAW,CAAA,CAAE,SAAA;AAAA,QACb,MAAM,CAAA,CAAE,IAAA;AAAA,QACR,YAAY,CAAA,CAAE,UAAA;AAAA,QACd,UAAU,CAAA,CAAE,QAAA;AAAA,QACZ,SAAS,CAAA,CAAE,OAAA;AAAA,QACX,UAAU,EAAC;AAAA,QACX,cAAc;AAAC,OACjB,CAAE,CAAA;AAIF,MAAA,MAAM,OAAA,GAAU,MAAM,WAAA,CAAY,MAAM,CAAA;AACxC,MAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAM;AAAA,IACnC,CAAA,SAAE;AACA,MAAA,KAAA,EAAM;AAAA,IACR;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,MAAM,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG,CAAA;AAG3D,IAAA,IAAI,CAAC,QAAA,CAAS,IAAA,CAAK,GAAG,CAAA,EAAG;AACvB,MAAA,KAAA,CAAM,KAAK,EAAE,IAAA,EAAM,OAAA,EAAS,OAAA,EAAS,KAAK,CAAA;AAAA,IAC5C;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,IAAI,OAAA,EAAS,IAAI,KAAA,EAAM;AAAA,EAC3C;AACF;AAGA,eAAe,YAAY,MAAA,EAA2C;AACpE,EAAA,MAAM,KAAM,MAAA,CAA4D,WAAA;AACxE,EAAA,IAAI,OAAO,EAAA,KAAO,UAAA,EAAY,OAAO,EAAC;AACtC,EAAA,MAAM,OAAA,GAAU,MAAM,EAAA,CAAG,IAAA,CAAK,MAAM,CAAA;AACpC,EAAA,OAAO,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,GAAI,UAAU,EAAC;AAC7C;AAcA,eAAe,aACb,EAAA,EAC+D;AAI/D,EAAA,MAAM,eAAA,GAAkB,iBAAA,EAAkB,CAAE,GAAA,CAAI,CAAC,CAAA,KAAO,CAAA,CAAE,QAAA,CAAc,IAAA,CAAA,GAAG,CAAA,GAAI,CAAA,GAAI,CAAA,GAAS,IAAA,CAAA,GAAI,CAAA;AAChG,EAAA,MAAM,gBAAgB,CAAC,CAAA,KACrB,eAAA,CAAgB,IAAA,CAAK,CAAC,EAAA,KAAO,CAAA,KAAM,EAAA,CAAG,KAAA,CAAM,GAAG,EAAE,CAAA,IAAK,CAAA,CAAE,UAAA,CAAW,EAAE,CAAC,CAAA;AAExE,EAAA,MAAM,GAAA,GAAA,CAAO,MAAM,EAAA,CAAG,MAAA,EAAO,EAAG,MAAA,CAAO,CAAC,CAAA,KAAM,CAAC,aAAA,CAAc,CAAA,CAAE,MAAM,CAAC,CAAA;AACtE,EAAA,MAAM,UAAyB,EAAC;AAChC,EAAA,MAAM,UAA2B,EAAC;AAMlC,EAAA,KAAA,MAAW,EAAE,QAAA,EAAU,IAAA,EAAK,IAAK,EAAA,CAAG,iBAAgB,EAAG;AACrD,IAAA,IAAI,aAAA,CAAc,IAAI,CAAA,EAAG;AACzB,IAAA,MAAM,SAAS,IAAA,CAAK,QAAA,CAAc,IAAA,CAAA,GAAG,CAAA,GAAI,OAAO,IAAA,GAAY,IAAA,CAAA,GAAA;AAC5D,IAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,CAAA,CAAE,MAAA,KAAW,IAAA,IAAQ,CAAA,CAAE,MAAA,CAAO,UAAA,CAAW,MAAM,CAAC,CAAA;AAChF,IAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACxB,IAAA,MAAM,aAAa,QAAA,CAAS,KAAA,CAAM,GAAG,CAAA,CAAE,KAAI,IAAK,QAAA;AAGhD,IAAA,OAAA,CAAQ,IAAA,CAAK,GAAI,MAAM,YAAA,CAAa,MAAM,UAAA,EAAY,KAAA,EAAO,KAAK,CAAE,CAAA;AACpE,IAAA,KAAA,MAAW,KAAA,IAAS,KAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,EAAE,QAAQ,QAAA,EAAU,KAAA,EAAO,KAAA,EAAO,UAAA,EAAY,CAAA;AAAA,EACxF;AACA,EAAA,OAAO,EAAE,SAAS,OAAA,EAAQ;AAC5B;AAUA,eAAe,aAAA,GAIZ;AACD,EAAA,MAAM,QAAoB,EAAC;AAC3B,EAAA,MAAM,UAA2B,EAAC;AAClC,EAAA,IAAI;AACF,IAAA,MAAM,UAA0B,EAAC;AACjC,IAAA,KAAA,MAAW,IAAA,IAAQ,mBAAkB,EAAG;AACtC,MAAA,MAAM,cAAc,CAAC,GAAI,MAAM,QAAA,CAAS,IAAA,EAAM,gBAAgB,CAAE,CAAA;AAChE,MAAA,OAAA,CAAQ,KAAK,GAAI,MAAM,aAAa,IAAA,EAAM,gBAAA,EAAkB,WAAW,CAAE,CAAA;AACzE,MAAA,OAAA,CAAQ,IAAA,CAAK,GAAG,WAAW,CAAA;AAAA,IAC7B;AACA,IAAA,OAAO,EAAE,OAAA,EAAS,OAAA,EAAS,KAAA,EAAM;AAAA,EACnC,SAAS,GAAA,EAAK;AACZ,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,IAAA,EAAM,SAAA;AAAA,MACN,SAAS,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,OAAO,GAAG;AAAA,KACzD,CAAA;AACD,IAAA,OAAO,EAAE,OAAA,EAAS,EAAC,EAAG,SAAS,KAAA,EAAM;AAAA,EACvC;AACF;AAGA,SAAS,GAAA,CAAI,QAAqB,OAAA,EAAwC;AACxE,EAAA,OAAO,QAAQ,GAAA,CAAI,CAAC,WAAW,EAAE,MAAA,EAAQ,OAAM,CAAE,CAAA;AACnD;AASA,eAAsB,gBAAA,CACpB,IACA,UAAA,EAC0B;AAC1B,EAAA,MAAM,CAAC,IAAA,EAAM,KAAK,CAAA,GAAI,MAAM,OAAA,CAAQ,GAAA,CAAI,CAAC,aAAA,EAAc,EAAG,WAAA,CAAY,UAAU,CAAC,CAAC,CAAA;AAClF,EAAA,MAAM,OAAA,GAAU,MAAM,aAAA,EAAc;AACpC,EAAA,MAAM,GAAA,GAAM,MAAM,YAAA,CAAa,EAAE,CAAA;AACjC,EAAA,OAAO;AAAA,IACL,OAAA,EAAS;AAAA,MACP,GAAG,GAAA,CAAI,OAAA;AAAA,MACP,GAAG,IAAA,CAAK,OAAA;AAAA,MACR,GAAG,GAAA,CAAI,SAAA,EAAW,OAAA,CAAQ,OAAO,CAAA;AAAA,MACjC,GAAG,GAAA,CAAI,OAAA,EAAS,KAAA,CAAM,OAAO;AAAA,KAC/B;AAAA;AAAA;AAAA,IAGA,OAAA,EAAS,YAAA,CAAa,CAAC,GAAG,MAAM,OAAA,EAAS,GAAG,GAAA,CAAI,OAAA,EAAS,GAAG,IAAA,CAAK,OAAA,EAAS,GAAG,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA,IAC7F,KAAA,EAAO,CAAC,GAAG,IAAA,CAAK,KAAA,EAAO,GAAG,KAAA,CAAM,KAAA,EAAO,GAAG,OAAA,CAAQ,KAAK;AAAA,GACzD;AACF;AAGA,SAAS,aAAa,OAAA,EAA2C;AAC/D,EAAA,MAAM,IAAA,uBAAW,GAAA,EAAY;AAC7B,EAAA,MAAM,MAAuB,EAAC;AAC9B,EAAA,KAAA,MAAW,KAAK,OAAA,EAAS;AACvB,IAAA,IAAI,IAAA,CAAK,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,EAAG;AACtB,IAAA,IAAA,CAAK,GAAA,CAAI,EAAE,IAAI,CAAA;AACf,IAAA,GAAA,CAAI,KAAK,CAAC,CAAA;AAAA,EACZ;AACA,EAAA,OAAO,GAAA;AACT","file":"asset-feeds-23CP6YUY.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nasync function loadDomainMds(root: string): Promise<DomainMd[]> {\n const out: DomainMd[] = [];\n for await (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nasync function stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): Promise<CatalogDomain[]> {\n const domainMds = await loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...(await scanRepo(lib.path, lib.name))];\n domains.push(...(await stampDomains(lib.path, lib.name, libEntries, false)));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => Promise<CatalogEntry[]>;\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nasync function sourceAssets(\n am: AssetManagerLike,\n): Promise<{ entries: OriginEntry[]; domains: CatalogDomain[] }> {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = (await am.search()).filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...(await stampDomains(root, sourceName, owned, false)));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Local disk only, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nasync function factoryAssets(): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...(await scanRepo(root, \"skaile-factory\"))];\n domains.push(...(await stampDomains(root, \"skaile-factory\", rootEntries)));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local disk only, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = await factoryAssets();\n const src = await sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
1
+ {"version":3,"sources":["../cli/src/asset-feeds.ts"],"names":[],"mappings":"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","file":"asset-feeds-XKPJZ6QT.js","sourcesContent":["/**\n * asset-feeds.ts — gather installable assets from every feed the manage TUI\n * surfaces.\n *\n * Four feeds, normalized into `CatalogEntry`:\n * - **Project sources** — `skaile.yaml` `sources:` entries (scanned via\n * `AssetManager.search()`; the new `sources:` field is merged into the\n * legacy repositories map in `AssetManager.loadConfig`).\n * - **Local libraries** — user authoring places from `LocalIndex` (filesystem\n * scan of each library's `path`).\n * - **Factory assets** — the bundled first-party `factory-assets` tree\n * (`factoryAssetRoots()`), scanned from disk. Always present; no network.\n * - **Remote store** — the configured catalog source when `catalog.url` is\n * not `local`. Failures are non-fatal — they surface as notes.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport * as path from \"node:path\";\nimport {\n type AssetKind,\n type CatalogDomain,\n type CatalogEntry,\n factoryAssetRoots,\n parseFrontmatter,\n scanRepo,\n walkDir,\n} from \"@skaile/workspaces/core\";\nimport {\n assignDomain,\n buildDomainIndex,\n DOMAIN_MD_FILENAME,\n type DomainMd,\n parseDomainMd,\n} from \"@skaile/workspaces/discovery\";\n\n/** One non-fatal note returned to the caller for surfacing in the UI. */\nexport interface FeedNote {\n feed: \"sources\" | \"libraries\" | \"store\" | \"factory\";\n message: string;\n}\n\n/**\n * Which feed an asset came from. This is the top-level grouping axis in the\n * manage TUI (\"where is this skill coming from?\") and is intentionally distinct\n * from `publisher` (asset-intrinsic identity): the same publisher can legitimately\n * appear under more than one origin (e.g. a github repo you added as a `source`\n * that is also listed in the remote `store`).\n */\nexport type AssetOrigin = \"source\" | \"library\" | \"factory\" | \"store\";\n\n/** A catalog entry tagged with the feed it was gathered from. */\nexport interface OriginEntry {\n origin: AssetOrigin;\n entry: CatalogEntry;\n /**\n * Second-level grouping label for the manage tree. Defaults (when unset) to the\n * entry's `publisher`; the source feed sets it to the source's short repo name\n * so the Sources band groups by source — \"which repo did this come from\" — not\n * by the asset-intrinsic publisher.\n */\n group?: string;\n}\n\nexport interface AssetFeedResult {\n entries: OriginEntry[];\n /**\n * Display-only domain metadata, keyed (by the consumer) on `slug`. Populated\n * from the store's `catalog.listDomains` when the connected catalog source\n * exposes it; empty otherwise. The manage TUI joins `entry.domainSlug` → a\n * domain for grouping headers, descriptions, and relation badges.\n */\n domains: CatalogDomain[];\n notes: FeedNote[];\n}\n\n// ── Domain stamping (on-disk feeds) ──────────────────────────────────────────\n//\n// `scanRepo` (the source / library / factory scan path) does not read the\n// `DOMAIN.md` sidecars, so its entries arrive with no `domainSlug` and render\n// flat under their publisher band. We re-derive the grouping here from the\n// root's `DOMAIN.md` files (the same sidecars the remote store computes\n// server-side), and fall back to the repo/source name for any entry no domain\n// claims so it still groups instead of landing in the synthetic \"no domain\" pile.\n\n/** Repo-relative POSIX path (DOMAIN.md slugs are matched whole-segment, `/`-joined). */\nfunction toPosix(p: string): string {\n return p.split(path.sep).join(\"/\");\n}\n\n/** Parse every `DOMAIN.md` sidecar under `root` into a {@link DomainMd}. */\nasync function loadDomainMds(root: string): Promise<DomainMd[]> {\n const out: DomainMd[] = [];\n for await (const { path: filePath, name } of walkDir(root)) {\n if (name !== DOMAIN_MD_FILENAME) continue;\n try {\n const { data } = parseFrontmatter(readFileSync(filePath, \"utf8\"));\n out.push(parseDomainMd(toPosix(path.relative(root, filePath)), data));\n } catch {}\n }\n return out;\n}\n\n/**\n * Stamp `domainSlug` onto every entry scanned from `root` using the root's\n * `DOMAIN.md` sidecars. Returns the `CatalogDomain` registry for the real\n * domains, plus a synthetic fallback domain when any entry used the fallback.\n * Mutates `entries` in place (sets `entry.domainSlug`).\n *\n * `synthesizeFallback` (default true): entries no domain claims fall back to\n * `fallbackSlug` (the repo/source name). Pass `false` when the caller already\n * groups these entries one level up (e.g. the source feed groups by source\n * node) — unmatched entries then get no domain (`\"\"`) and hang directly under\n * that parent, instead of nesting under a same-named fallback domain.\n */\nasync function stampDomains(\n root: string,\n fallbackSlug: string,\n entries: CatalogEntry[],\n synthesizeFallback = true,\n): Promise<CatalogDomain[]> {\n const domainMds = await loadDomainMds(root);\n const assignables = entries.map((entry) => ({\n entry,\n ref: `${entry.kind}:${entry.name}`,\n relativePath: toPosix(path.relative(root, entry.source)),\n }));\n\n let usedFallback = false;\n for (const a of assignables) {\n const slug = assignDomain(a.relativePath, domainMds);\n if (slug) a.entry.domainSlug = slug;\n else if (synthesizeFallback) {\n a.entry.domainSlug = fallbackSlug;\n usedFallback = true;\n } else a.entry.domainSlug = \"\";\n }\n\n const { index } = buildDomainIndex(assignables, domainMds);\n const catalog: CatalogDomain[] = Object.values(index).map((d) => ({\n slug: d.slug,\n title: d.title,\n ...(d.description ? { description: d.description } : {}),\n ...(d.relation ? { relation: d.relation } : {}),\n ...(d.order !== undefined ? { order: d.order } : {}),\n ...(d.recommended[0] ? { recommendedRef: d.recommended[0] } : {}),\n }));\n if (usedFallback) catalog.push({ slug: fallbackSlug, title: fallbackSlug });\n return catalog;\n}\n\n/**\n * Pull assets from local libraries (the authoring places under\n * `~/.skaile/libraries/<name>/`, not the `~/.skaile/cache/sources/` cache). Each\n * library's `path` is scanned with `scanRepo` and grouped under the bare library\n * name (`group: <name>`) so the manage TUI shows a clean `<name>` band — no\n * `library:` prefix and no redundant same-named fallback domain (mirrors the\n * source feed).\n */\nasync function libraryAssets(): Promise<{\n entries: OriginEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const [{ openLibraryManager }, { skaileHomeDir }, { getGlobalCacheDir }] = await Promise.all([\n import(\"./open-library.ts\"),\n import(\"@skaile/workspaces/library\"),\n import(\"@skaile/workspaces/core\"),\n ]);\n const { manager, close } = await openLibraryManager();\n try {\n // Authoring libraries are the rows that are NOT source clones. index.db\n // rows predating the cache migration still carry the legacy\n // ~/.skaile/sources path, so exclude both roots.\n const newRoot = getGlobalCacheDir();\n const legacyRoot = path.join(skaileHomeDir(), \"sources\");\n const libs = (await manager.listLibraries()).filter(\n (l) => !l.path.startsWith(newRoot) && !l.path.startsWith(legacyRoot),\n );\n const entries: OriginEntry[] = [];\n for (const lib of libs) {\n if (!existsSync(lib.path)) continue;\n // Scan + group under the bare library name. `synthesizeFallback: false`\n // (as the source feed does) keeps domainless assets directly under the\n // library band instead of a redundant same-named fallback domain.\n const libEntries = [...(await scanRepo(lib.path, lib.name))];\n domains.push(...(await stampDomains(lib.path, lib.name, libEntries, false)));\n for (const entry of libEntries) entries.push({ origin: \"library\", entry, group: lib.name });\n }\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n notes.push({\n feed: \"libraries\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/**\n * Pull a (best-effort) snapshot of the connected remote store catalog.\n *\n * - Returns no entries when the resolved catalog is local-only or the host\n * is unreachable (the failure becomes a note, not an exception).\n * - Maps `CatalogAsset` → `CatalogEntry`, carrying `publisher`, `repo`, and\n * `category` straight through and using `source = \"store://<id>\"`; per-file\n * `source` paths are not available for remote assets so the canonical ref is\n * a stable placeholder.\n */\nasync function storeAssets(projectDir: string): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n try {\n const { resolveCatalogSource } = await import(\"./open-library.ts\");\n const { source, close } = await resolveCatalogSource({ projectDir });\n try {\n const assets = await source.listAssets();\n const entries: CatalogEntry[] = assets.map((a) => ({\n name: a.name,\n kind: (a.kind as AssetKind) ?? \"skill\",\n description: a.description ?? \"\",\n source: `store://${a.id}`,\n publisher: a.publisher,\n repo: a.repo,\n domainSlug: a.domainSlug,\n category: a.category,\n version: a.version,\n requires: [],\n dependencies: [],\n }));\n // Domains are optional on the catalog source — only the store backend\n // (post Part 4 `catalog.listDomains`) exposes them. Duck-type the call so\n // older sources and the local catalog degrade to no domains, not an error.\n const domains = await loadDomains(source);\n return { entries, domains, notes };\n } finally {\n close();\n }\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n // Local-only catalog throws a recognizable message — silence it; absence\n // is the user's choice, not an error.\n if (!/local/i.test(msg)) {\n notes.push({ feed: \"store\", message: msg });\n }\n return { entries: [], domains: [], notes };\n }\n}\n\n/** Optional `listDomains` capability — returns `[]` when the source lacks it. */\nasync function loadDomains(source: unknown): Promise<CatalogDomain[]> {\n const fn = (source as { listDomains?: () => Promise<CatalogDomain[]> }).listDomains;\n if (typeof fn !== \"function\") return [];\n const domains = await fn.call(source);\n return Array.isArray(domains) ? domains : [];\n}\n\n/** The slice of `AssetManager` the source feed needs (kept narrow for tests). */\ninterface AssetManagerLike {\n search: () => Promise<CatalogEntry[]>;\n searchRepoRoots: () => { repoName: string; root: string }[];\n}\n\n/**\n * Project-source feed: leans on `AssetManager.search()`, which now merges\n * `skaile.yaml`'s `sources:` field into the repositories map, then stamps\n * `DOMAIN.md`-derived domain grouping onto the scanned entries via\n * `searchRepoRoots()`.\n */\nasync function sourceAssets(\n am: AssetManagerLike,\n): Promise<{ entries: OriginEntry[]; domains: CatalogDomain[] }> {\n // The bundled factory tree is injected into the repositories map as an implicit\n // source, so `am.search()` returns it too. It has its own `factory` origin band,\n // so drop it here — otherwise the same first-party skills list twice under Sources.\n const factoryPrefixes = factoryAssetRoots().map((r) => (r.endsWith(path.sep) ? r : r + path.sep));\n const isFactoryPath = (p: string) =>\n factoryPrefixes.some((fp) => p === fp.slice(0, -1) || p.startsWith(fp));\n\n const all = (await am.search()).filter((e) => !isFactoryPath(e.source));\n const entries: OriginEntry[] = [];\n const domains: CatalogDomain[] = [];\n // Group each source's entries under the source node (its short repo name), not\n // the publisher: under Sources the navigational question is \"which repo did\n // this come from\". Each entry's `source` (absolute manifest path) lives under\n // exactly one declared root, so group + stamp by prefix. The cache slug is\n // URL-keyed `github.com/<org>/<repo>` — take the trailing segment.\n for (const { repoName, root } of am.searchRepoRoots()) {\n if (isFactoryPath(root)) continue;\n const prefix = root.endsWith(path.sep) ? root : root + path.sep;\n const owned = all.filter((e) => e.source === root || e.source.startsWith(prefix));\n if (owned.length === 0) continue;\n const sourceName = repoName.split(\"/\").pop() || repoName;\n // No synthetic fallback domain — the source node already groups these, so a\n // same-named fallback would just nest the source under itself.\n domains.push(...(await stampDomains(root, sourceName, owned, false)));\n for (const entry of owned) entries.push({ origin: \"source\", entry, group: sourceName });\n }\n return { entries, domains };\n}\n\n/**\n * Factory-asset feed: scan the bundled first-party `factory-assets` tree(s)\n * resolved by `factoryAssetRoots()` (the `SKAILE_FACTORY_ASSETS_DIR` override\n * layer ahead of the bundled tree). Local disk only, no network — the entries are\n * the built-in skills / connectors / bundles that ship with `@skaile/workspaces`.\n * `factoryAssetRoots()` already dedupes, so the env override pointing at the\n * bundled dir collapses to one root.\n */\nasync function factoryAssets(): Promise<{\n entries: CatalogEntry[];\n domains: CatalogDomain[];\n notes: FeedNote[];\n}> {\n const notes: FeedNote[] = [];\n const domains: CatalogDomain[] = [];\n try {\n const entries: CatalogEntry[] = [];\n for (const root of factoryAssetRoots()) {\n const rootEntries = [...(await scanRepo(root, \"skaile-factory\"))];\n domains.push(...(await stampDomains(root, \"skaile-factory\", rootEntries)));\n entries.push(...rootEntries);\n }\n return { entries, domains, notes };\n } catch (err) {\n notes.push({\n feed: \"factory\",\n message: err instanceof Error ? err.message : String(err),\n });\n return { entries: [], domains, notes };\n }\n}\n\n/** Tag a flat entry list with a single origin. */\nfunction tag(origin: AssetOrigin, entries: CatalogEntry[]): OriginEntry[] {\n return entries.map((entry) => ({ origin, entry }));\n}\n\n/**\n * Run all feeds and return a single normalized result.\n *\n * Feeds run in parallel where possible — the store fetch is the slow one\n * (one HTTP call) and is fired alongside the local library walk. The factory\n * scan is local disk only, so it runs inline.\n */\nexport async function gatherAssetFeeds(\n am: AssetManagerLike,\n projectDir: string,\n): Promise<AssetFeedResult> {\n const [libs, store] = await Promise.all([libraryAssets(), storeAssets(projectDir)]);\n const factory = await factoryAssets();\n const src = await sourceAssets(am);\n return {\n entries: [\n ...src.entries,\n ...libs.entries,\n ...tag(\"factory\", factory.entries),\n ...tag(\"store\", store.entries),\n ],\n // Store domains first (server-curated), then the on-disk feeds; dedupe by\n // slug, first-wins, so a store-served domain shadows a same-slug local one.\n domains: dedupeBySlug([...store.domains, ...src.domains, ...libs.domains, ...factory.domains]),\n notes: [...libs.notes, ...store.notes, ...factory.notes],\n };\n}\n\n/** First-wins dedupe of a domain list by `slug`. */\nfunction dedupeBySlug(domains: CatalogDomain[]): CatalogDomain[] {\n const seen = new Set<string>();\n const out: CatalogDomain[] = [];\n for (const d of domains) {\n if (seen.has(d.slug)) continue;\n seen.add(d.slug);\n out.push(d);\n }\n return out;\n}\n"]}
@@ -1,4 +1,4 @@
1
- export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName } from '../chunk-6AYGXPPF.js';
1
+ export { AssetManager, FACTORY_SOURCE_URL, MissingManifestError, NON_DEPLOYABLE_KINDS, normalizeRepoUrl, parseCanonicalLockKey, parseRefTolerant, renderMcpServerConfig, softDepName } from '../chunk-Q6O53D5Q.js';
2
2
  import '../chunk-3HVASHBF.js';
3
3
  import '../chunk-NU4E7C5I.js';
4
4
  import '../chunk-UKJMQZV6.js';
@@ -1,8 +1,8 @@
1
1
  import { SUPPORTED_CLOUDS, buildClaudeCloudEnv } from '../../chunk-ISQWMBKD.js';
2
2
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
3
- import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
3
+ import { fetchProviderModels } from '../../chunk-V34ZEXSE.js';
4
4
  import { AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable, AccountUnavailableError } from '../../chunk-GAH4YRCI.js';
5
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
5
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-P43HBWKK.js';
8
8
  import '../../chunk-F3HNW354.js';
@@ -1,6 +1,6 @@
1
- import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
1
+ import { fetchProviderModels } from '../../chunk-V34ZEXSE.js';
2
2
  import { classifyGenericErrorMessage } from '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
3
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-U5POE4BA.js';
6
6
  import '../../chunk-7GOCNYUV.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-L3TS7ZO4.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-BJDACPWZ.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-U5POE4BA.js';
6
6
  import '../../chunk-7GOCNYUV.js';
@@ -1,5 +1,5 @@
1
1
  import { dispatchCapability } from '../../chunk-RRVQAE5D.js';
2
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
2
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
3
3
  import '../../chunk-6E6PKKAD.js';
4
4
  import '../../chunk-U5POE4BA.js';
5
5
  import '../../chunk-7GOCNYUV.js';
@@ -1,8 +1,8 @@
1
- export { GeminiDriver, GeminiFamilyDriver, geminiDriverTarget } from '../../chunk-ZR2X4SIG.js';
2
- import '../../chunk-L3TS7ZO4.js';
3
- import '../../chunk-BMQKMOQY.js';
1
+ export { GeminiDriver, GeminiFamilyDriver, geminiDriverTarget } from '../../chunk-KXWUCKP5.js';
2
+ import '../../chunk-BJDACPWZ.js';
3
+ import '../../chunk-V34ZEXSE.js';
4
4
  import '../../chunk-GAH4YRCI.js';
5
- import '../../chunk-HY3MBSNC.js';
5
+ import '../../chunk-SR6NBBWT.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-U5POE4BA.js';
8
8
  import '../../chunk-7GOCNYUV.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-L3TS7ZO4.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-BJDACPWZ.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-U5POE4BA.js';
6
6
  import '../../chunk-7GOCNYUV.js';
@@ -1,5 +1,5 @@
1
1
  import { classifyGenericErrorMessage } from '../../chunk-GAH4YRCI.js';
2
- import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
2
+ import { BUILTIN_DRIVER_CATALOG, AgentDriver, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
3
3
  import '../../chunk-6E6PKKAD.js';
4
4
  import '../../chunk-U5POE4BA.js';
5
5
  import '../../chunk-7GOCNYUV.js';
@@ -1,6 +1,6 @@
1
- import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-L3TS7ZO4.js';
1
+ import { SubprocessCliDriver, mapApiKeysToEnv, extractText, extractCost, extractTokens } from '../../chunk-BJDACPWZ.js';
2
2
  import '../../chunk-GAH4YRCI.js';
3
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
3
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
4
4
  import '../../chunk-6E6PKKAD.js';
5
5
  import '../../chunk-U5POE4BA.js';
6
6
  import '../../chunk-7GOCNYUV.js';
@@ -1,8 +1,8 @@
1
- import { GeminiFamilyDriver } from '../../chunk-ZR2X4SIG.js';
2
- import '../../chunk-L3TS7ZO4.js';
3
- import { fetchProviderModels } from '../../chunk-BMQKMOQY.js';
1
+ import { GeminiFamilyDriver } from '../../chunk-KXWUCKP5.js';
2
+ import '../../chunk-BJDACPWZ.js';
3
+ import { fetchProviderModels } from '../../chunk-V34ZEXSE.js';
4
4
  import '../../chunk-GAH4YRCI.js';
5
- import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-HY3MBSNC.js';
5
+ import { BUILTIN_DRIVER_CATALOG, getBridgeLogger } from '../../chunk-SR6NBBWT.js';
6
6
  import '../../chunk-6E6PKKAD.js';
7
7
  import '../../chunk-U5POE4BA.js';
8
8
  import '../../chunk-7GOCNYUV.js';
@@ -1,9 +1,9 @@
1
- export { BridgeRuntime, EventNormalizer, createRuntime, detectFileChange, detectFileChanges, summarizeToolCall, summarizeToolResult, validateApiKey } from '../chunk-VNIKF66R.js';
1
+ export { BridgeRuntime, EventNormalizer, createRuntime, detectFileChange, detectFileChanges, summarizeToolCall, summarizeToolResult, validateApiKey } from '../chunk-P5W6JVD4.js';
2
2
  export { CLOUD_SECRET_ENV_KEYS, SUPPORTED_CLOUDS, buildClaudeCloudEnv } from '../chunk-ISQWMBKD.js';
3
3
  export { dispatchCapability, filterRenderCapabilities, renderFallback } from '../chunk-RRVQAE5D.js';
4
- export { STATIC_MODELS, fetchProviderModels, getModels, getStaticModels } from '../chunk-BMQKMOQY.js';
4
+ export { ModelTierResolutionError, PROVIDER_MODEL_TIERS, STATIC_MODELS, fetchProviderModels, getModels, getStaticModels, resolveModelTier } from '../chunk-V34ZEXSE.js';
5
5
  export { AccountUnavailableError, AuthError, classifyClaudeSdkError, reclassifyAuthAsAccountUnavailable } from '../chunk-GAH4YRCI.js';
6
- export { AgentDriver, BUILTIN_DRIVER_CATALOG, DRIVER_CATALOG, createDriver, getBridgeLogger, listDrivers, listModelsForDriver, registerBuiltinDrivers } from '../chunk-HY3MBSNC.js';
6
+ export { AgentDriver, BUILTIN_DRIVER_CATALOG, DRIVER_CATALOG, createDriver, getBridgeLogger, listDrivers, listModelsForDriver, registerBuiltinDrivers } from '../chunk-SR6NBBWT.js';
7
7
  import '../chunk-6E6PKKAD.js';
8
8
  import '../chunk-U5POE4BA.js';
9
9
  import '../chunk-7GOCNYUV.js';
@@ -87,4 +87,63 @@ export declare const STATIC_MODELS: Record<string, ModelEntry[]>;
87
87
  * @docLink packages/bridge/api-reference#models
88
88
  */
89
89
  export declare function getStaticModels(provider: string): ModelEntry[];
90
+ /** Per-tier concrete model ids for one provider. */
91
+ export interface ModelTierOverrides {
92
+ small?: string;
93
+ default?: string;
94
+ deep?: string;
95
+ }
96
+ /**
97
+ * Built-in tier→model mapping per provider. This is the point of the closed
98
+ * `small | default | deep` vocabulary: an authored flow names an intent and the
99
+ * runtime owns which concrete model serves it, so flows stay portable across
100
+ * model-lineup changes.
101
+ *
102
+ * These are **direct provider-API ids**. A gateway transport (Bedrock, Vertex,
103
+ * Azure) addresses the same models by different ids — Bedrock prefixes
104
+ * `us.anthropic.`, for instance — and that translation belongs to whoever owns
105
+ * the deployment, not here. {@link resolveModelTier} therefore consults this
106
+ * table only on the direct API and demands an explicit override otherwise,
107
+ * rather than handing a gateway an id it cannot serve.
108
+ *
109
+ * Every id here must also appear in {@link STATIC_MODELS} — a test asserts it,
110
+ * so the two cannot drift into naming a model the catalog disowns. That check
111
+ * proves internal consistency only; it cannot tell you an id is still current
112
+ * with a provider's live lineup.
113
+ *
114
+ * Where a provider's lineup has no genuinely distinct model for a tier, the
115
+ * entry deliberately repeats the neighbouring one. That is a reviewable
116
+ * property of that lineup, unlike inheriting whatever model the session
117
+ * happened to start with — which is how `small` could silently mean Opus.
118
+ */
119
+ export declare const PROVIDER_MODEL_TIERS: Record<string, Required<ModelTierOverrides>>;
120
+ /** Raised when a tier names an intent this provider cannot serve. */
121
+ export declare class ModelTierResolutionError extends Error {
122
+ readonly tier: "small" | "deep";
123
+ readonly provider: string | undefined;
124
+ constructor(tier: "small" | "deep", provider: string | undefined);
125
+ }
126
+ /**
127
+ * Resolve a Flow v2 `run.model` tier to a concrete model id.
128
+ *
129
+ * `"default"` and an absent tier **inherit `sessionModel` first**. The session
130
+ * model is the one id known to work for this deployment — it already carries
131
+ * whatever provider, lineup and gateway translation the host configured — so
132
+ * preferring a built-in over it would silently downgrade a configured model
133
+ * and, on a gateway transport, substitute an id that provider cannot serve.
134
+ *
135
+ * `"small"` and `"deep"` never fall back to `sessionModel`: they resolve from
136
+ * an override, then from {@link PROVIDER_MODEL_TIERS} on the direct provider
137
+ * API, and otherwise throw {@link ModelTierResolutionError}. Inheriting there
138
+ * would run an arbitrary model behind an author's explicit request for a cheap
139
+ * or a strong one — a cost or quality surprise that shows up only in the bill
140
+ * or the output. Failing names it at the node instead.
141
+ *
142
+ * Pure: no I/O, no environment reads.
143
+ */
144
+ export declare function resolveModelTier(tier: "small" | "default" | "deep" | undefined, sessionModel: string | undefined, options?: {
145
+ provider?: string;
146
+ cloud?: string;
147
+ overrides?: ModelTierOverrides;
148
+ }): string | undefined;
90
149
  //# sourceMappingURL=models.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../bridge/src/models.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AA6GD;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkB7F;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAgEtD,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAE9D"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../../bridge/src/models.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH;;;;;;;GAOG;AACH,MAAM,WAAW,UAAU;IACzB,yFAAyF;IACzF,EAAE,EAAE,MAAM,CAAC;IACX,iFAAiF;IACjF,IAAI,EAAE,MAAM,CAAC;CACd;AA6GD;;;;;;;;GAQG;AACH,MAAM,WAAW,iBAAiB;IAChC,iEAAiE;IACjE,EAAE,EAAE,OAAO,CAAC;IACZ,4CAA4C;IAC5C,MAAM,EAAE,UAAU,EAAE,CAAC;IACrB,6DAA6D;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,EAAE,KAAK,GAAG,QAAQ,CAAC;CAC1B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,GACb,OAAO,CAAC,iBAAiB,CAAC,CA+C5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkB7F;AAMD;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,CAgEtD,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE,CAE9D;AAMD,oDAAoD;AACpD,MAAM,WAAW,kBAAkB;IACjC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,kBAAkB,CAAC,CAmC7E,CAAC;AAEF,qEAAqE;AACrE,qBAAa,wBAAyB,SAAQ,KAAK;IAE/C,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS;gBAD5B,IAAI,EAAE,OAAO,GAAG,MAAM,EACtB,QAAQ,EAAE,MAAM,GAAG,SAAS;CAQxC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,EAC9C,YAAY,EAAE,MAAM,GAAG,SAAS,EAChC,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,kBAAkB,CAAA;CAAO,GAClF,MAAM,GAAG,SAAS,CAWpB"}
@@ -600,8 +600,7 @@ var NodeControlSchema = z.strictObject({
600
600
  optional: z.boolean().optional(),
601
601
  retries: z.number().int().min(0).optional(),
602
602
  timeoutSec: z.number().positive().optional(),
603
- parallelGroup: nonEmptyString.optional(),
604
- subagent: z.boolean().optional()
603
+ parallelGroup: nonEmptyString.optional()
605
604
  });
606
605
  var runAssets = { assets: z.array(nonEmptyString).optional() };
607
606
  var modelTier = z.enum(["small", "default", "deep"]);
@@ -712,7 +711,6 @@ var FlowDefaultsSchema = z.strictObject({
712
711
  approval: z.enum(["checkpoint", "auto", "manual"]).optional(),
713
712
  researchDepth: nonEmptyString.optional(),
714
713
  autoReview: z.boolean().optional(),
715
- subagentMode: z.boolean().optional(),
716
714
  verbosity: nonEmptyString.optional(),
717
715
  cliMode: z.boolean().optional(),
718
716
  run_input: z.json().optional(),
@@ -769,6 +767,16 @@ function knownNonBooleanType(schema) {
769
767
  }
770
768
  return void 0;
771
769
  }
770
+ function optionalRefusalReason(node) {
771
+ if (node.run.kind === "gate") return "a first-class gate node cannot be optional";
772
+ if (node.run.kind === "check") {
773
+ return "a check node cannot be optional \u2014 an optional verification either hides a false green (escalate) or hangs the run forever (fail); reject the check entirely if it should not gate the run";
774
+ }
775
+ if (node.gate?.approval === "mandatory") {
776
+ return "a node cannot be both optional and a mandatory approval gate";
777
+ }
778
+ return void 0;
779
+ }
772
780
  var FlowDefinitionSchema = FlowDefinitionObjectSchema.superRefine((flow, context) => {
773
781
  const nodeIds = /* @__PURE__ */ new Set();
774
782
  for (const [index, node] of flow.nodes.entries()) {
@@ -780,12 +788,15 @@ var FlowDefinitionSchema = FlowDefinitionObjectSchema.superRefine((flow, context
780
788
  });
781
789
  }
782
790
  nodeIds.add(node.id);
783
- if (node.control?.optional === true && (node.gate?.approval === "mandatory" || node.run.kind === "gate")) {
784
- context.addIssue({
785
- code: "custom",
786
- path: ["nodes", index, "control", "optional"],
787
- message: node.run.kind === "gate" ? "a first-class gate node cannot be optional" : "a node cannot be both optional and a mandatory approval gate"
788
- });
791
+ if (node.control?.optional === true) {
792
+ const refusal = optionalRefusalReason(node);
793
+ if (refusal !== void 0) {
794
+ context.addIssue({
795
+ code: "custom",
796
+ path: ["nodes", index, "control", "optional"],
797
+ message: refusal
798
+ });
799
+ }
789
800
  }
790
801
  }
791
802
  if (flow.entry !== void 0 && !nodeIds.has(flow.entry)) {
@@ -997,7 +1008,6 @@ var LegacyNodeDataSchema = z.looseObject({
997
1008
  parallel_group: z.string().min(1).optional(),
998
1009
  flow: z.string().min(1).optional(),
999
1010
  pass_context: z.boolean().optional(),
1000
- subagent: z.boolean().optional(),
1001
1011
  message: z.string().min(1).optional(),
1002
1012
  routes: z.array(LegacyRouteSchema).optional(),
1003
1013
  assets: z.array(z.string().min(1)).optional()
@@ -1047,16 +1057,17 @@ var LEGACY_DEFAULT_KEYS = {
1047
1057
  approval_mode: "approval",
1048
1058
  research_depth: "researchDepth",
1049
1059
  auto_review: "autoReview",
1050
- subagent_mode: "subagentMode",
1051
1060
  verbosity: "verbosity",
1052
1061
  cli_mode: "cliMode",
1053
1062
  run_input: "run_input"
1054
1063
  };
1064
+ var DROPPED_LEGACY_DEFAULT_KEYS = /* @__PURE__ */ new Set(["subagent_mode"]);
1055
1065
  function normalizeDefaults(globals) {
1056
1066
  if (!globals) return void 0;
1057
1067
  const known = {};
1058
1068
  const parameters = {};
1059
1069
  for (const [key, value] of Object.entries(globals)) {
1070
+ if (DROPPED_LEGACY_DEFAULT_KEYS.has(key)) continue;
1060
1071
  const normalizedKey = LEGACY_DEFAULT_KEYS[key];
1061
1072
  if (normalizedKey) {
1062
1073
  known[normalizedKey] = key === "approval_mode" && value === "auto_approve" ? "auto" : value;
@@ -1129,8 +1140,7 @@ function normalizeV1(data) {
1129
1140
  const parameters2 = data2.parameters ?? {};
1130
1141
  const control2 = {
1131
1142
  optional: data2.optional,
1132
- parallelGroup: data2.parallel_group,
1133
- subagent: data2.subagent
1143
+ parallelGroup: data2.parallel_group
1134
1144
  };
1135
1145
  nodes.push({
1136
1146
  id: node.id,
@@ -1168,7 +1178,7 @@ function normalizeV1(data) {
1168
1178
  requires: [{ expr: "false" }],
1169
1179
  input: Object.keys(parameters2).length > 0 ? normalizeLegacyBinding(parameters2) : void 0
1170
1180
  },
1171
- control: { optional: true, parallelGroup: data2.parallel_group, subagent: data2.subagent }
1181
+ control: { optional: true, parallelGroup: data2.parallel_group }
1172
1182
  });
1173
1183
  continue;
1174
1184
  }
@@ -1181,8 +1191,7 @@ function normalizeV1(data) {
1181
1191
  const assets = [...skillAsset ? [skillAsset] : [], ...data2.assets ?? []];
1182
1192
  const control = {
1183
1193
  optional: data2.optional,
1184
- parallelGroup: data2.parallel_group,
1185
- subagent: data2.subagent
1194
+ parallelGroup: data2.parallel_group
1186
1195
  };
1187
1196
  nodes.push({
1188
1197
  id: node.id,
@@ -1243,5 +1252,5 @@ function parseFlowDefinition(data) {
1243
1252
  }
1244
1253
 
1245
1254
  export { FLOW_EXPRESSION_LIMITS, FlowDefinitionSchema, FlowExpressionError, collectFlowBindingExpressions, evaluate, evaluateFlowExpression, inspectFlowExpression, normalizeV1, parseFlowDefinition, resolveFlowBindings, stableFlowJson };
1246
- //# sourceMappingURL=chunk-XJ74XFIZ.js.map
1247
- //# sourceMappingURL=chunk-XJ74XFIZ.js.map
1255
+ //# sourceMappingURL=chunk-5QGMEPUX.js.map
1256
+ //# sourceMappingURL=chunk-5QGMEPUX.js.map