@zaalipro/dsh-workflows 0.1.0-rc.3

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 (229) hide show
  1. package/LICENSE +21 -0
  2. package/NOTICE.md +224 -0
  3. package/README.i18n.yaml +4 -0
  4. package/README.md +109 -0
  5. package/README.zh.md +109 -0
  6. package/cordis.patch.yml +10 -0
  7. package/docs/architecture.i18n.yaml +4 -0
  8. package/docs/architecture.md +177 -0
  9. package/docs/architecture.zh.md +177 -0
  10. package/docs/testing.i18n.yaml +4 -0
  11. package/docs/testing.md +125 -0
  12. package/docs/testing.zh.md +125 -0
  13. package/docs/user-guide.i18n.yaml +4 -0
  14. package/docs/user-guide.md +351 -0
  15. package/docs/user-guide.zh.md +351 -0
  16. package/lib/client-types/WorkflowMemberInspector.d.ts +28 -0
  17. package/lib/client-types/WorkflowMemberInspector.d.ts.map +1 -0
  18. package/lib/client-types/WorkflowMemberInspector.js +181 -0
  19. package/lib/client-types/WorkflowMemberInspector.js.map +1 -0
  20. package/lib/client-types/WorkflowRunPanel.d.ts +43 -0
  21. package/lib/client-types/WorkflowRunPanel.d.ts.map +1 -0
  22. package/lib/client-types/WorkflowRunPanel.js +130 -0
  23. package/lib/client-types/WorkflowRunPanel.js.map +1 -0
  24. package/lib/client-types/WorkflowsDashboard.d.ts +49 -0
  25. package/lib/client-types/WorkflowsDashboard.d.ts.map +1 -0
  26. package/lib/client-types/WorkflowsDashboard.js +942 -0
  27. package/lib/client-types/WorkflowsDashboard.js.map +1 -0
  28. package/lib/client-types/adapter.d.ts +60 -0
  29. package/lib/client-types/adapter.d.ts.map +1 -0
  30. package/lib/client-types/adapter.js +117 -0
  31. package/lib/client-types/adapter.js.map +1 -0
  32. package/lib/client-types/chat-renderer.d.ts +10 -0
  33. package/lib/client-types/chat-renderer.d.ts.map +1 -0
  34. package/lib/client-types/chat-renderer.js +11 -0
  35. package/lib/client-types/chat-renderer.js.map +1 -0
  36. package/lib/client-types/contract.d.ts +210 -0
  37. package/lib/client-types/contract.d.ts.map +1 -0
  38. package/lib/client-types/contract.js +37 -0
  39. package/lib/client-types/contract.js.map +1 -0
  40. package/lib/client-types/controller.d.ts +83 -0
  41. package/lib/client-types/controller.d.ts.map +1 -0
  42. package/lib/client-types/controller.js +705 -0
  43. package/lib/client-types/controller.js.map +1 -0
  44. package/lib/client-types/index.d.ts +19 -0
  45. package/lib/client-types/index.d.ts.map +1 -0
  46. package/lib/client-types/index.js +730 -0
  47. package/lib/client-types/index.js.map +1 -0
  48. package/lib/client-types/locales.d.ts +257 -0
  49. package/lib/client-types/locales.d.ts.map +1 -0
  50. package/lib/client-types/locales.js +270 -0
  51. package/lib/client-types/locales.js.map +1 -0
  52. package/lib/client-types/slot-components.d.ts +38 -0
  53. package/lib/client-types/slot-components.d.ts.map +1 -0
  54. package/lib/client-types/slot-components.js +22 -0
  55. package/lib/client-types/slot-components.js.map +1 -0
  56. package/lib/client-types/store.d.ts +69 -0
  57. package/lib/client-types/store.d.ts.map +1 -0
  58. package/lib/client-types/store.js +135 -0
  59. package/lib/client-types/store.js.map +1 -0
  60. package/lib/client-types/workflow-definition.d.ts +52 -0
  61. package/lib/client-types/workflow-definition.d.ts.map +1 -0
  62. package/lib/client-types/workflow-definition.js +135 -0
  63. package/lib/client-types/workflow-definition.js.map +1 -0
  64. package/lib/client.js +11064 -0
  65. package/lib/client.js.map +1 -0
  66. package/lib/compat-engine/index.js +1926 -0
  67. package/lib/compat-engine/index.js.map +1 -0
  68. package/lib/compat-engine/worker.cjs +1500 -0
  69. package/lib/compat-engine/worker.cjs.map +1 -0
  70. package/lib/typert.host.d.ts +3 -0
  71. package/lib/typert.host.js +1709 -0
  72. package/lib/typert.remote-client.d.ts +57 -0
  73. package/lib/typert.remote-client.js +1662 -0
  74. package/lib/types/commands/aliases.d.ts +4 -0
  75. package/lib/types/commands/aliases.d.ts.map +1 -0
  76. package/lib/types/commands/aliases.js +25 -0
  77. package/lib/types/commands/aliases.js.map +1 -0
  78. package/lib/types/commands/index.d.ts +66 -0
  79. package/lib/types/commands/index.d.ts.map +1 -0
  80. package/lib/types/commands/index.js +550 -0
  81. package/lib/types/commands/index.js.map +1 -0
  82. package/lib/types/commands/parser.d.ts +17 -0
  83. package/lib/types/commands/parser.d.ts.map +1 -0
  84. package/lib/types/commands/parser.js +45 -0
  85. package/lib/types/commands/parser.js.map +1 -0
  86. package/lib/types/config.d.ts +71 -0
  87. package/lib/types/config.d.ts.map +1 -0
  88. package/lib/types/config.js +109 -0
  89. package/lib/types/config.js.map +1 -0
  90. package/lib/types/index.d.ts +41 -0
  91. package/lib/types/index.d.ts.map +1 -0
  92. package/lib/types/index.js +483 -0
  93. package/lib/types/index.js.map +1 -0
  94. package/lib/types/invariant.d.ts +21 -0
  95. package/lib/types/invariant.d.ts.map +1 -0
  96. package/lib/types/invariant.js +85 -0
  97. package/lib/types/invariant.js.map +1 -0
  98. package/lib/types/registry/definition.d.ts +24 -0
  99. package/lib/types/registry/definition.d.ts.map +1 -0
  100. package/lib/types/registry/definition.js +189 -0
  101. package/lib/types/registry/definition.js.map +1 -0
  102. package/lib/types/registry/index.d.ts +100 -0
  103. package/lib/types/registry/index.d.ts.map +1 -0
  104. package/lib/types/registry/index.js +899 -0
  105. package/lib/types/registry/index.js.map +1 -0
  106. package/lib/types/registry/names.d.ts +19 -0
  107. package/lib/types/registry/names.d.ts.map +1 -0
  108. package/lib/types/registry/names.js +69 -0
  109. package/lib/types/registry/names.js.map +1 -0
  110. package/lib/types/registry/remote.d.ts +15 -0
  111. package/lib/types/registry/remote.d.ts.map +1 -0
  112. package/lib/types/registry/remote.js +128 -0
  113. package/lib/types/registry/remote.js.map +1 -0
  114. package/lib/types/registry/roots.d.ts +44 -0
  115. package/lib/types/registry/roots.d.ts.map +1 -0
  116. package/lib/types/registry/roots.js +118 -0
  117. package/lib/types/registry/roots.js.map +1 -0
  118. package/lib/types/registry/types.d.ts +62 -0
  119. package/lib/types/registry/types.d.ts.map +1 -0
  120. package/lib/types/registry/types.js +2 -0
  121. package/lib/types/registry/types.js.map +1 -0
  122. package/lib/types/registry/watchers.d.ts +70 -0
  123. package/lib/types/registry/watchers.d.ts.map +1 -0
  124. package/lib/types/registry/watchers.js +152 -0
  125. package/lib/types/registry/watchers.js.map +1 -0
  126. package/lib/types/remote-events.d.ts +42 -0
  127. package/lib/types/remote-events.d.ts.map +1 -0
  128. package/lib/types/remote-events.js +21 -0
  129. package/lib/types/remote-events.js.map +1 -0
  130. package/lib/types/run-recorder.d.ts +44 -0
  131. package/lib/types/run-recorder.d.ts.map +1 -0
  132. package/lib/types/run-recorder.js +356 -0
  133. package/lib/types/run-recorder.js.map +1 -0
  134. package/lib/types/supervisor/canned-validate.d.ts +25 -0
  135. package/lib/types/supervisor/canned-validate.d.ts.map +1 -0
  136. package/lib/types/supervisor/canned-validate.js +122 -0
  137. package/lib/types/supervisor/canned-validate.js.map +1 -0
  138. package/lib/types/supervisor/completion-notice.d.ts +49 -0
  139. package/lib/types/supervisor/completion-notice.d.ts.map +1 -0
  140. package/lib/types/supervisor/completion-notice.js +281 -0
  141. package/lib/types/supervisor/completion-notice.js.map +1 -0
  142. package/lib/types/supervisor/cursors.d.ts +68 -0
  143. package/lib/types/supervisor/cursors.d.ts.map +1 -0
  144. package/lib/types/supervisor/cursors.js +158 -0
  145. package/lib/types/supervisor/cursors.js.map +1 -0
  146. package/lib/types/supervisor/engine-compat.d.ts +48 -0
  147. package/lib/types/supervisor/engine-compat.d.ts.map +1 -0
  148. package/lib/types/supervisor/engine-compat.js +116 -0
  149. package/lib/types/supervisor/engine-compat.js.map +1 -0
  150. package/lib/types/supervisor/index.d.ts +183 -0
  151. package/lib/types/supervisor/index.d.ts.map +1 -0
  152. package/lib/types/supervisor/index.js +2040 -0
  153. package/lib/types/supervisor/index.js.map +1 -0
  154. package/lib/types/supervisor/parallel-compat.d.ts +36 -0
  155. package/lib/types/supervisor/parallel-compat.d.ts.map +1 -0
  156. package/lib/types/supervisor/parallel-compat.js +180 -0
  157. package/lib/types/supervisor/parallel-compat.js.map +1 -0
  158. package/lib/types/supervisor/remote.d.ts +25 -0
  159. package/lib/types/supervisor/remote.d.ts.map +1 -0
  160. package/lib/types/supervisor/remote.js +478 -0
  161. package/lib/types/supervisor/remote.js.map +1 -0
  162. package/lib/types/supervisor/storage/bounded-file.d.ts +41 -0
  163. package/lib/types/supervisor/storage/bounded-file.d.ts.map +1 -0
  164. package/lib/types/supervisor/storage/bounded-file.js +186 -0
  165. package/lib/types/supervisor/storage/bounded-file.js.map +1 -0
  166. package/lib/types/supervisor/storage/details-codec.d.ts +14 -0
  167. package/lib/types/supervisor/storage/details-codec.d.ts.map +1 -0
  168. package/lib/types/supervisor/storage/details-codec.js +359 -0
  169. package/lib/types/supervisor/storage/details-codec.js.map +1 -0
  170. package/lib/types/supervisor/storage/index.d.ts +26 -0
  171. package/lib/types/supervisor/storage/index.d.ts.map +1 -0
  172. package/lib/types/supervisor/storage/index.js +100 -0
  173. package/lib/types/supervisor/storage/index.js.map +1 -0
  174. package/lib/types/supervisor/storage/lease.d.ts +34 -0
  175. package/lib/types/supervisor/storage/lease.d.ts.map +1 -0
  176. package/lib/types/supervisor/storage/lease.js +289 -0
  177. package/lib/types/supervisor/storage/lease.js.map +1 -0
  178. package/lib/types/supervisor/storage/manifest-codec.d.ts +10 -0
  179. package/lib/types/supervisor/storage/manifest-codec.d.ts.map +1 -0
  180. package/lib/types/supervisor/storage/manifest-codec.js +335 -0
  181. package/lib/types/supervisor/storage/manifest-codec.js.map +1 -0
  182. package/lib/types/supervisor/storage/manifest-store.d.ts +99 -0
  183. package/lib/types/supervisor/storage/manifest-store.d.ts.map +1 -0
  184. package/lib/types/supervisor/storage/manifest-store.js +1606 -0
  185. package/lib/types/supervisor/storage/manifest-store.js.map +1 -0
  186. package/lib/types/supervisor/storage/manifest-types.d.ts +269 -0
  187. package/lib/types/supervisor/storage/manifest-types.d.ts.map +1 -0
  188. package/lib/types/supervisor/storage/manifest-types.js +2 -0
  189. package/lib/types/supervisor/storage/manifest-types.js.map +1 -0
  190. package/lib/types/supervisor/storage/private-root.d.ts +143 -0
  191. package/lib/types/supervisor/storage/private-root.d.ts.map +1 -0
  192. package/lib/types/supervisor/storage/private-root.js +860 -0
  193. package/lib/types/supervisor/storage/private-root.js.map +1 -0
  194. package/lib/types/supervisor/storage/recovery.d.ts +14 -0
  195. package/lib/types/supervisor/storage/recovery.d.ts.map +1 -0
  196. package/lib/types/supervisor/storage/recovery.js +126 -0
  197. package/lib/types/supervisor/storage/recovery.js.map +1 -0
  198. package/lib/types/supervisor/storage/run-files.d.ts +67 -0
  199. package/lib/types/supervisor/storage/run-files.d.ts.map +1 -0
  200. package/lib/types/supervisor/storage/run-files.js +346 -0
  201. package/lib/types/supervisor/storage/run-files.js.map +1 -0
  202. package/lib/types/supervisor/types.d.ts +295 -0
  203. package/lib/types/supervisor/types.d.ts.map +1 -0
  204. package/lib/types/supervisor/types.js +3 -0
  205. package/lib/types/supervisor/types.js.map +1 -0
  206. package/lib/types/supervisor/value-view.d.ts +19 -0
  207. package/lib/types/supervisor/value-view.d.ts.map +1 -0
  208. package/lib/types/supervisor/value-view.js +183 -0
  209. package/lib/types/supervisor/value-view.js.map +1 -0
  210. package/lib/types/tool/index.d.ts +86 -0
  211. package/lib/types/tool/index.d.ts.map +1 -0
  212. package/lib/types/tool/index.js +810 -0
  213. package/lib/types/tool/index.js.map +1 -0
  214. package/lib/types/tool/schema.d.ts +158 -0
  215. package/lib/types/tool/schema.d.ts.map +1 -0
  216. package/lib/types/tool/schema.js +137 -0
  217. package/lib/types/tool/schema.js.map +1 -0
  218. package/lib/types/types.d.ts +9 -0
  219. package/lib/types/types.d.ts.map +1 -0
  220. package/lib/types/types.js +3 -0
  221. package/lib/types/types.js.map +1 -0
  222. package/lib/types/user-questions.d.ts +9 -0
  223. package/lib/types/user-questions.d.ts.map +1 -0
  224. package/lib/types/user-questions.js +91 -0
  225. package/lib/types/user-questions.js.map +1 -0
  226. package/package.json +273 -0
  227. package/skills/create-workflow/SKILL.md +166 -0
  228. package/vendor/workflow-engine/LICENSE +21 -0
  229. package/vendor/workflow-engine/README.md +1 -0
@@ -0,0 +1,1500 @@
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+ //#endregion
23
+ let node_worker_threads = require("node:worker_threads");
24
+ let _deepseek_ai_dsh_workflow = require("@deepseek-ai/dsh-workflow");
25
+ let _deepseek_ai_dsh_llm = require("@deepseek-ai/dsh-llm");
26
+ let _deepseek_ai_dsh_session = require("@deepseek-ai/dsh-session");
27
+ let _deepseek_ai_dsh_tools = require("@deepseek-ai/dsh-tools");
28
+ let node_async_hooks = require("node:async_hooks");
29
+ let node_crypto = require("node:crypto");
30
+ let node_vm = require("node:vm");
31
+ node_vm = __toESM(node_vm, 1);
32
+ //#region vendor/workflow-engine/realm.ts
33
+ /**
34
+ * Materializes values leaving the script vm into plain JSON before they cross the worker
35
+ * boundary, and renders thrown script values without rejecting the run. The walk rejects
36
+ * values that JSON cannot preserve but trusts model-written workflow scripts: getters and proxy traps may
37
+ * run, and the vm is not a security boundary. The worker provides host-loop isolation and
38
+ * forced termination, not hostile-value containment. See
39
+ * .agents/notes/implemented/feature/2026-07-05-dynamic-workflows.md for the isolation rationale.
40
+ * @module @deepseek-ai/dsh-workflow-worker-thread/realm
41
+ */
42
+ /** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */
43
+ var MaterializeError = class extends Error {
44
+ constructor(path, reason) {
45
+ super(`${path}: ${reason}`);
46
+ this.path = path;
47
+ this.reason = reason;
48
+ this.name = "MaterializeError";
49
+ }
50
+ };
51
+ /**
52
+ * Render a thrown value to failure text without ever throwing: prefer the
53
+ * `stack` (host or realm — a realm error's `stack` is a plain string read),
54
+ * fall back to `message`, then `String()`. Reading those properties MAY run
55
+ * script code (a getter, `toString`) — accepted under the module's trust
56
+ * premise; if that code itself throws, a fixed label is returned instead.
57
+ * @param error - any value thrown in the host or worker realm.
58
+ * @returns human-readable text for the failure report; prefers the stack.
59
+ */
60
+ function renderThrown(error) {
61
+ try {
62
+ const stack = error?.stack;
63
+ if (typeof stack === "string" && stack.length > 0) return stack;
64
+ const message = error?.message;
65
+ if (typeof message === "string" && message.length > 0) return message;
66
+ return String(error);
67
+ } catch {
68
+ return "[unrenderable thrown value]";
69
+ }
70
+ }
71
+ /**
72
+ * Whether an object's prototype chain represents a plain data object: `null`, or a prototype
73
+ * whose own prototype is `null` (the realm's `Object.prototype` — which we
74
+ * cannot compare by identity across realms). A `Date`/`Map`/class instance
75
+ * has a longer chain and is rejected.
76
+ */
77
+ function hasPlainPrototype(value) {
78
+ const proto = Object.getPrototypeOf(value);
79
+ if (proto === null) return true;
80
+ return Object.getPrototypeOf(proto) === null;
81
+ }
82
+ /**
83
+ * Copy `value` (typically from the vm realm) into plain host JSON data. Root `undefined` is
84
+ * returned unchanged; nested `undefined` and values JSON cannot represent losslessly fail
85
+ * with the offending path. Property accessors run normally, and a throwing read is wrapped
86
+ * with its rendered failure.
87
+ *
88
+ * @param value - the realm value to materialize.
89
+ * @param root - the path label for the root value (error messages).
90
+ * @returns the host-realm copy (plain objects/arrays/scalars only).
91
+ * @throws {@link MaterializeError} for unsupported values, cycles, sparse arrays, exotic
92
+ * prototypes, or property reads that throw.
93
+ */
94
+ function materializeFromRealm(value, root = "value") {
95
+ if (value === void 0) return void 0;
96
+ try {
97
+ return materialize(value, root, /* @__PURE__ */ new Set());
98
+ } catch (error) {
99
+ if (error instanceof MaterializeError) throw error;
100
+ throw new MaterializeError(root, `reading the value threw: ${renderThrown(error)}`);
101
+ }
102
+ }
103
+ function materialize(value, path, seen) {
104
+ switch (typeof value) {
105
+ case "boolean":
106
+ case "string": return value;
107
+ case "number":
108
+ if (!Number.isFinite(value)) throw new MaterializeError(path, "non-finite numbers are not JSON data");
109
+ return value;
110
+ case "bigint": throw new MaterializeError(path, "bigints are not JSON data");
111
+ case "function": throw new MaterializeError(path, "functions are not plain JSON data");
112
+ case "symbol": throw new MaterializeError(path, "symbols are not plain JSON data");
113
+ case "undefined": throw new MaterializeError(path, "undefined is not JSON data");
114
+ }
115
+ if (value === null) return null;
116
+ const objectValue = value;
117
+ if (seen.has(objectValue)) throw new MaterializeError(path, "circular references are not JSON data");
118
+ seen.add(objectValue);
119
+ try {
120
+ if (Array.isArray(objectValue)) return materializeArray(objectValue, path, seen);
121
+ return materializeObject(objectValue, path, seen);
122
+ } finally {
123
+ seen.delete(objectValue);
124
+ }
125
+ }
126
+ function materializeArray(value, path, seen) {
127
+ const out = [];
128
+ for (let index = 0; index < value.length; index++) {
129
+ if (!(index in value)) throw new MaterializeError(`${path}[${index}]`, "sparse arrays are not JSON data");
130
+ out.push(materialize(value[index], `${path}[${index}]`, seen));
131
+ }
132
+ for (const key of Object.keys(value)) {
133
+ const index = Number(key);
134
+ if (!Number.isInteger(index) || index < 0 || index >= value.length) throw new MaterializeError(`${path}.${key}`, "arrays with non-index properties are not JSON data");
135
+ }
136
+ if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, "symbol-keyed properties are not plain JSON data");
137
+ return out;
138
+ }
139
+ function materializeObject(value, path, seen) {
140
+ if (!hasPlainPrototype(value)) throw new MaterializeError(path, "only plain objects and arrays are JSON data (exotic prototype)");
141
+ if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, "symbol-keyed properties are not plain JSON data");
142
+ const out = {};
143
+ for (const key of Object.keys(value)) Object.defineProperty(out, key, {
144
+ value: materialize(value[key], `${path}.${key}`, seen),
145
+ enumerable: true,
146
+ writable: true,
147
+ configurable: true
148
+ });
149
+ return out;
150
+ }
151
+ //#endregion
152
+ //#region vendor/workflow-engine/compat-seam.ts
153
+ /** Local extensions deliberately absent from the official 0.1.1-rc.2 seam. */
154
+ const WorkflowError$1 = _deepseek_ai_dsh_workflow.WorkflowError;
155
+ //#endregion
156
+ //#region vendor/workflow-engine/runtime.ts
157
+ /**
158
+ * Per-run worker-side vm hooks, child RPC, concurrency/caps, cancellation, and result serialization; it
159
+ * never touches Cordis. Script values leaving the realm are materialized as plain JSON before
160
+ * messaging. Values entering the trusted model-written realm are passed directly; `args` alone is
161
+ * cloned so script mutation cannot alter initialization data. See `./realm.ts` for the trust model.
162
+ *
163
+ * Fatal workflow errors—bad hook arguments, unsupported schemas/options, caps, start failures, and
164
+ * cancellation—propagate through combinators. Only child failures and ordinary stage errors become
165
+ * per-item nulls. Every returned promise has a rejection consumer so dropped script promises cannot
166
+ * kill the worker. A cancelled script that never settles emits nothing; the host force-settles the
167
+ * run within grace and terminates the thread.
168
+ * @module @deepseek-ai/dsh-workflow-worker-thread/runtime
169
+ */
170
+ /**
171
+ * Build a callable/constructable global that fails before exposing ambient
172
+ * process state. The vm is not a security boundary, but ordinary authored
173
+ * workflows must not accidentally make resumed control flow depend on the
174
+ * clock, randomness, garbage collection, or timer-like atomics.
175
+ */
176
+ function unavailableNondeterministicGlobal(name) {
177
+ const fail = () => {
178
+ throw new WorkflowError$1(`${name} is unavailable in workflow scripts because runs must derive control flow from args and committed host results`, "INVALID_ARGUMENT");
179
+ };
180
+ /* v8 ignore next -- every call/construct/property operation is intercepted by the Proxy traps below */
181
+ const target = Object.freeze(function unavailableWorkflowGlobal() {
182
+ return fail();
183
+ });
184
+ return Object.freeze(new Proxy(target, {
185
+ apply: fail,
186
+ construct: fail,
187
+ get: fail,
188
+ set: fail
189
+ }));
190
+ }
191
+ /** Clone the deterministic Math surface while replacing its random source. */
192
+ function deterministicMath() {
193
+ const descriptors = Object.getOwnPropertyDescriptors(Math);
194
+ descriptors.random = {
195
+ ...descriptors.random,
196
+ value: Object.freeze(() => {
197
+ throw new WorkflowError$1("Math.random() is unavailable in workflow scripts because runs must derive control flow from args and committed host results", "INVALID_ARGUMENT");
198
+ })
199
+ };
200
+ return Object.freeze(Object.defineProperties(Object.create(Reflect.getPrototypeOf(Math)), descriptors));
201
+ }
202
+ /** Define one JSON object key without giving `__proto__` assignment semantics. */
203
+ function defineJsonProperty(target, key, value) {
204
+ Object.defineProperty(target, key, {
205
+ configurable: true,
206
+ enumerable: true,
207
+ writable: true,
208
+ value
209
+ });
210
+ }
211
+ /** Copy one generated JSON object while retaining every key as data. */
212
+ function copyJsonObject(source) {
213
+ const copy = {};
214
+ for (const [key, value] of Object.entries(source)) defineJsonProperty(copy, key, value);
215
+ return copy;
216
+ }
217
+ /** Define a schema key without giving `__proto__` assignment semantics. */
218
+ function defineSchemaProperty(target, key, value) {
219
+ Object.defineProperty(target, key, {
220
+ configurable: true,
221
+ enumerable: true,
222
+ writable: true,
223
+ value
224
+ });
225
+ }
226
+ /** Whether a bound is a lossless, non-negative safe integer (including rejecting `-0`). */
227
+ function isArrayBound(value) {
228
+ return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 && !Object.is(value, -0);
229
+ }
230
+ /**
231
+ * Validate the plugin's two forward-compatible schema keywords and produce
232
+ * the projection accepted by stock RC2. Traversal follows schema-bearing
233
+ * locations only: annotation payloads are data and must not be rewritten.
234
+ */
235
+ function prepareObjectSchema(authored) {
236
+ const boundViolations = [];
237
+ const visit = (rawNode, path) => {
238
+ if (typeof rawNode !== "object" || rawNode === null || Array.isArray(rawNode)) return rawNode;
239
+ const node = rawNode;
240
+ const provider = {};
241
+ const hasMin = Object.hasOwn(node, "minItems");
242
+ const hasMax = Object.hasOwn(node, "maxItems");
243
+ const hasOneOf = Object.hasOwn(node, "oneOf");
244
+ for (const keyword of ["minItems", "maxItems"]) {
245
+ if (!Object.hasOwn(node, keyword)) continue;
246
+ if (hasOneOf) boundViolations.push(`${path}.${keyword} is not supported beside oneOf`);
247
+ else if (node.type !== "array") boundViolations.push(Object.hasOwn(node, "type") ? `${path}.${keyword} is not supported on type ${JSON.stringify(node.type)}` : `${path}.${keyword} requires type or oneOf`);
248
+ }
249
+ let minimum;
250
+ let maximum;
251
+ if (!hasOneOf && node.type === "array") {
252
+ if (hasMin) {
253
+ if (!isArrayBound(node.minItems)) boundViolations.push(`${path}.minItems must be a non-negative safe integer`);
254
+ else minimum = node.minItems;
255
+ }
256
+ if (hasMax) {
257
+ if (!isArrayBound(node.maxItems)) boundViolations.push(`${path}.maxItems must be a non-negative safe integer`);
258
+ else maximum = node.maxItems;
259
+ }
260
+ if (minimum !== void 0 && maximum !== void 0 && minimum > maximum) boundViolations.push(`${path}.minItems must not exceed ${path}.maxItems`);
261
+ }
262
+ for (const [key, value] of Object.entries(node)) {
263
+ if (key === "minItems" || key === "maxItems") continue;
264
+ if (key === "items") {
265
+ defineSchemaProperty(provider, key, visit(value, `${path}.items`));
266
+ continue;
267
+ }
268
+ if (key === "oneOf" && Array.isArray(value)) {
269
+ defineSchemaProperty(provider, key, value.map((branch, index) => visit(branch, `${path}.oneOf[${index}]`)));
270
+ continue;
271
+ }
272
+ if (key === "properties" && typeof value === "object" && value !== null && !Array.isArray(value)) {
273
+ const properties = {};
274
+ for (const [name, child] of Object.entries(value)) defineSchemaProperty(properties, name, visit(child, `${path}.properties.${name}`));
275
+ defineSchemaProperty(provider, key, properties);
276
+ continue;
277
+ }
278
+ defineSchemaProperty(provider, key, value);
279
+ }
280
+ return provider;
281
+ };
282
+ const provider = visit(authored, "schema");
283
+ let stockViolations = [];
284
+ try {
285
+ (0, _deepseek_ai_dsh_tools.assertObjectJsonSchema)(provider);
286
+ } catch (error) {
287
+ /* v8 ignore next -- assertObjectJsonSchema only throws JsonSchemaError */
288
+ if (!(error instanceof _deepseek_ai_dsh_tools.JsonSchemaError)) throw error;
289
+ stockViolations = error.violations;
290
+ }
291
+ const violations = [...boundViolations, ...stockViolations];
292
+ if (violations.length > 0) throw new _deepseek_ai_dsh_tools.JsonSchemaError(violations);
293
+ return {
294
+ authored,
295
+ provider
296
+ };
297
+ }
298
+ /**
299
+ * Validate against the authored extended subset while continuing to delegate
300
+ * all ordinary JSON/type/scalar checks to RC2's shared validator. Object and
301
+ * array children are walked here so bounds can participate in exact-one
302
+ * `oneOf` matching instead of the stripped provider branches becoming
303
+ * spuriously overlapping.
304
+ */
305
+ function schemaValueMatches(schema, value) {
306
+ if (schema.oneOf !== void 0) {
307
+ let matches = 0;
308
+ for (const branch of schema.oneOf) {
309
+ if (schemaValueMatches(branch, value)) matches += 1;
310
+ if (matches > 1) return false;
311
+ }
312
+ return matches === 1;
313
+ }
314
+ if (schema.type === "object") {
315
+ if ((0, _deepseek_ai_dsh_tools.validateJsonSchemaValue)({ type: "object" }, value).length > 0) return false;
316
+ const record = value;
317
+ const properties = schema.properties ?? {};
318
+ for (const required of schema.required ?? []) if (!Object.hasOwn(record, required)) return false;
319
+ if (schema.additionalProperties === false) {
320
+ for (const key of Object.keys(record)) if (!Object.hasOwn(properties, key)) return false;
321
+ }
322
+ for (const [key, childSchema] of Object.entries(properties)) if (Object.hasOwn(record, key) && !schemaValueMatches(childSchema, record[key])) return false;
323
+ return true;
324
+ }
325
+ if (schema.type === "array") {
326
+ if ((0, _deepseek_ai_dsh_tools.validateJsonSchemaValue)({ type: "array" }, value).length > 0) return false;
327
+ const array = value;
328
+ const bounded = schema;
329
+ if (bounded.minItems !== void 0 && array.length < bounded.minItems) return false;
330
+ if (bounded.maxItems !== void 0 && array.length > bounded.maxItems) return false;
331
+ if (schema.items !== void 0) {
332
+ for (const item of array) if (!schemaValueMatches(schema.items, item)) return false;
333
+ }
334
+ return true;
335
+ }
336
+ return (0, _deepseek_ai_dsh_tools.validateJsonSchemaValue)(schema, value).length === 0;
337
+ }
338
+ /** Deterministic unconstrained candidates used to disambiguate exact-one unions. */
339
+ const ANY_JSON_CANDIDATES = [
340
+ null,
341
+ false,
342
+ true,
343
+ 0,
344
+ .5,
345
+ "",
346
+ "value",
347
+ [],
348
+ {}
349
+ ];
350
+ /** Count serialized JSON nodes up to a configured smoke-host work limit. */
351
+ function jsonNodeCount(value, limit) {
352
+ let count = 0;
353
+ const pending = [value];
354
+ for (let current = pending.pop(); current !== void 0; current = pending.pop()) {
355
+ count += 1;
356
+ if (count > limit) return count;
357
+ if (Array.isArray(current)) for (const child of current) pending.push(child);
358
+ else if (typeof current === "object" && current !== null) for (const child of Object.values(current)) pending.push(child);
359
+ }
360
+ return count;
361
+ }
362
+ /**
363
+ * Produce deterministic candidates for one already-validated schema node.
364
+ * Returned candidates satisfy the node; an empty list means the supported
365
+ * exact-one vocabulary has no value this smoke host can construct.
366
+ */
367
+ function cannedSchemaCandidates(schema, maxArrayItems) {
368
+ let candidates;
369
+ if (schema.oneOf !== void 0) {
370
+ candidates = [];
371
+ for (const branch of schema.oneOf) {
372
+ for (const candidate of cannedSchemaCandidates(branch, maxArrayItems)) {
373
+ if (candidates.length >= maxArrayItems) break;
374
+ candidates.push(candidate);
375
+ }
376
+ if (candidates.length >= maxArrayItems) break;
377
+ }
378
+ for (const candidate of ANY_JSON_CANDIDATES) {
379
+ if (candidates.length >= maxArrayItems) break;
380
+ candidates.push(candidate);
381
+ }
382
+ } else if (Object.hasOwn(schema, "const")) candidates = [schema.const];
383
+ else if (schema.enum !== void 0) candidates = [...schema.enum];
384
+ else switch (schema.type) {
385
+ case "object": {
386
+ const properties = schema.properties ?? {};
387
+ const required = schema.required ?? [];
388
+ const base = {};
389
+ const requiredCandidates = /* @__PURE__ */ new Map();
390
+ for (const key of required) {
391
+ const values = cannedSchemaCandidates(properties[key], maxArrayItems);
392
+ if (values.length === 0) return [];
393
+ requiredCandidates.set(key, values);
394
+ defineJsonProperty(base, key, values[0]);
395
+ }
396
+ candidates = [base];
397
+ for (const [key, values] of requiredCandidates) for (const value of values.slice(1)) {
398
+ if (candidates.length >= maxArrayItems) break;
399
+ const alternate = copyJsonObject(base);
400
+ defineJsonProperty(alternate, key, value);
401
+ candidates.push(alternate);
402
+ }
403
+ const optional = Object.entries(properties).filter(([key]) => !requiredCandidates.has(key));
404
+ const withAllOptional = copyJsonObject(base);
405
+ let hasAllOptional = false;
406
+ for (const [key, childSchema] of optional) {
407
+ const values = cannedSchemaCandidates(childSchema, maxArrayItems);
408
+ for (const value of values) {
409
+ if (candidates.length >= maxArrayItems) break;
410
+ const alternate = copyJsonObject(base);
411
+ defineJsonProperty(alternate, key, value);
412
+ candidates.push(alternate);
413
+ }
414
+ if (values[0] !== void 0) {
415
+ defineJsonProperty(withAllOptional, key, values[0]);
416
+ hasAllOptional = true;
417
+ }
418
+ }
419
+ if (hasAllOptional) candidates.push(withAllOptional);
420
+ break;
421
+ }
422
+ case "array": {
423
+ const arraySchema = schema;
424
+ const minimum = arraySchema.minItems ?? 0;
425
+ if (minimum > maxArrayItems) return [];
426
+ const mayContainItem = arraySchema.maxItems === void 0 || arraySchema.maxItems > 0;
427
+ const itemCandidates = schema.items === void 0 ? [null] : cannedSchemaCandidates(schema.items, maxArrayItems);
428
+ candidates = minimum === 0 ? [[]] : [];
429
+ for (const value of itemCandidates) if (minimum > 0 && 1 + minimum * jsonNodeCount(value, maxArrayItems) <= maxArrayItems) candidates.push(Array.from({ length: minimum }, () => value));
430
+ else if (mayContainItem) candidates.push([value]);
431
+ break;
432
+ }
433
+ case "string":
434
+ candidates = ["", "value"];
435
+ break;
436
+ case "number":
437
+ candidates = [
438
+ 0,
439
+ .5,
440
+ 1,
441
+ -1
442
+ ];
443
+ break;
444
+ case "integer":
445
+ candidates = [
446
+ 0,
447
+ 1,
448
+ -1
449
+ ];
450
+ break;
451
+ case "boolean":
452
+ candidates = [false, true];
453
+ break;
454
+ case "null":
455
+ candidates = [null];
456
+ break;
457
+ case void 0:
458
+ candidates = [...ANY_JSON_CANDIDATES];
459
+ break;
460
+ /* v8 ignore next -- assertObjectJsonSchema validated the closed schema vocabulary recursively. */
461
+ default: return [];
462
+ }
463
+ return candidates.filter((candidate) => jsonNodeCount(candidate, maxArrayItems) <= maxArrayItems).filter((candidate) => schemaValueMatches(schema, candidate)).slice(0, maxArrayItems);
464
+ }
465
+ /** Synthesize one schema-conforming structured result for `validate_only`. */
466
+ function cannedSchemaValue(schema, maxArrayItems) {
467
+ const candidate = cannedSchemaCandidates(schema, maxArrayItems)[0];
468
+ if (candidate !== void 0) return candidate;
469
+ throw new WorkflowError$1("validate_only could not synthesize a canned result that conforms to the agent() schema", "UNSUPPORTED_SCHEMA");
470
+ }
471
+ /** The `agent()` options the script may pass; everything else rejects loud. */
472
+ const SUPPORTED_AGENT_OPTIONS = /* @__PURE__ */ new Set([
473
+ "label",
474
+ "phase",
475
+ "schema",
476
+ "provider",
477
+ "model"
478
+ ]);
479
+ /** Deferred Claude Code options we name explicitly in the rejection message. */
480
+ const DEFERRED_AGENT_OPTIONS = /* @__PURE__ */ new Set([
481
+ "effort",
482
+ "isolation",
483
+ "agentType"
484
+ ]);
485
+ /** Flatten a child's final output blocks to text (the non-schema `agent()` result). */
486
+ function outputText(blocks) {
487
+ return blocks.filter((block) => block.type === "text").map((block) => block.text).join("");
488
+ }
489
+ /** A short display label derived from the prompt when the script passes none. */
490
+ function defaultLabel(prompt) {
491
+ const newline = prompt.indexOf("\n");
492
+ const line = newline === -1 ? prompt : prompt.slice(0, newline);
493
+ return line.length <= 48 ? line : `${line.slice(0, 47)}…`;
494
+ }
495
+ /**
496
+ * One live script execution inside the worker. Constructed per run by the
497
+ * session; `drive()` is called exactly once and NEVER rejects — every failure
498
+ * becomes a {@link WorkflowResult} with a non-`completed` stop reason. The
499
+ * host owns cancellation and cleanup of any dropped child work.
500
+ */
501
+ var WorkflowExecution = class {
502
+ constructor(meta, body, args, limits, observer, children, journal, validateOnly = false, initialAgentSpend = 0, initialAgentSeq = initialAgentSpend) {
503
+ this.limits = limits;
504
+ this.observer = observer;
505
+ this.children = children;
506
+ this.validateOnly = validateOnly;
507
+ this.activeSlots = 0;
508
+ this.slotWaiters = [];
509
+ this.completionGate = Promise.withResolvers();
510
+ this.replayedJournalCallIds = /* @__PURE__ */ new Set();
511
+ this.callScopes = new node_async_hooks.AsyncLocalStorage();
512
+ this.rootScope = {
513
+ path: [],
514
+ nextNode: 0
515
+ };
516
+ try {
517
+ this.compiled = new node_vm.Script(`(async () => {\n${body}\n})()`, {
518
+ filename: `workflow:${meta.name}`,
519
+ lineOffset: -1
520
+ });
521
+ } catch (error) {
522
+ throw new WorkflowError$1(`workflow script does not parse: ${String(error)}`, "SCRIPT_PARSE", { cause: error });
523
+ }
524
+ const committedAgents = (journal ?? []).filter((entry) => entry.kind === "agent");
525
+ this.started = Math.max(initialAgentSpend, committedAgents.length);
526
+ let journalMaximum = 0;
527
+ let ordinalMaximum = 0;
528
+ for (const entry of committedAgents) journalMaximum = Math.max(journalMaximum, entry.seq);
529
+ for (const entry of journal ?? []) ordinalMaximum = Math.max(ordinalMaximum, entry.ordinal);
530
+ this.nextAgentSeq = Math.max(initialAgentSeq, this.started, journalMaximum);
531
+ this.nextJournalOrdinal = ordinalMaximum;
532
+ this.journal = indexJournal(journal);
533
+ this.context = node_vm.createContext({}, { name: `workflow:${meta.name}` });
534
+ const globals = {
535
+ agent: (prompt, opts) => this.contain(this.agent(prompt, opts)),
536
+ parallel: (items) => this.contain(this.parallel(items)),
537
+ pipeline: (items, ...stages) => this.contain(this.pipeline(items, stages)),
538
+ phase: (title) => {
539
+ this.phase(title);
540
+ },
541
+ log: (message) => {
542
+ this.log(message);
543
+ },
544
+ complete: (value) => {
545
+ this.complete(value);
546
+ },
547
+ pause: (kind, message) => this.contain(this.gate(kind, message, false)),
548
+ await_user: (kind, message) => this.contain(this.gate(kind, message, true)),
549
+ budget: () => this.budget(),
550
+ write_scratch_file: (name, content) => this.contain(this.writeScratch(name, content)),
551
+ read_scratch_file: (name) => this.contain(this.readScratch(name)),
552
+ Date: unavailableNondeterministicGlobal("Date"),
553
+ Math: deterministicMath(),
554
+ Atomics: unavailableNondeterministicGlobal("Atomics"),
555
+ SharedArrayBuffer: unavailableNondeterministicGlobal("SharedArrayBuffer"),
556
+ WeakRef: unavailableNondeterministicGlobal("WeakRef"),
557
+ FinalizationRegistry: unavailableNondeterministicGlobal("FinalizationRegistry"),
558
+ args
559
+ };
560
+ for (const [key, value] of Object.entries(globals)) this.context[key] = typeof value === "function" ? Object.freeze(value) : value;
561
+ }
562
+ /** Release the gate the script is parked on, if any. */
563
+ resume() {
564
+ this.gateResume?.();
565
+ }
566
+ /**
567
+ * Whether the run has been cancelled. A METHOD, not an inline property
568
+ * read: `cancel()` mutates `cancelReason` concurrently (the session's
569
+ * message handler), and an inline read after an `await` gets narrowed by
570
+ * control flow into an always-false comparison.
571
+ */
572
+ isCancelled() {
573
+ return this.cancelReason !== void 0;
574
+ }
575
+ /**
576
+ * Shared hook entry guard: after {@link cancel}, EVERY hook throws
577
+ * `CANCELLED` at its next call — cancellation is the next HOOK boundary,
578
+ * not just the next `agent()`, so a script that caught one cancelled
579
+ * rejection cannot keep emitting progress through `phase`/`log` or enter a
580
+ * combinator.
581
+ */
582
+ throwIfCancelled() {
583
+ if (this.completed !== void 0 || this.completionError !== void 0) throw COMPLETE_SENTINEL;
584
+ if (this.isCancelled()) throw this.cancelledError();
585
+ }
586
+ /**
587
+ * Cancel the run: waiting `agent()` slots reject and every future hook call
588
+ * throws `CANCELLED` — the script dies at its next await. A script that
589
+ * never settles anyway (parked on a promise no hook owns) is the HOST's
590
+ * problem: its grace timer force-settles the run and terminates the
591
+ * worker. Idempotent; the first reason wins.
592
+ * @param reason - human-readable cause carried on the CANCELLED error. The
593
+ * host independently aborts the required signal shared by every child.
594
+ */
595
+ cancel(reason) {
596
+ if (this.cancelReason !== void 0) return;
597
+ this.cancelReason = reason;
598
+ this.cancelError = new WorkflowError$1(`workflow run cancelled: ${this.cancelReason}`, "CANCELLED");
599
+ for (const waiter of this.slotWaiters.splice(0)) waiter.reject(this.cancelledError());
600
+ this.gateResume?.();
601
+ }
602
+ /**
603
+ * Run the script to settlement. Resolves — never rejects — with the run's
604
+ * {@link WorkflowResult}: the materialized return value on `completed`, the
605
+ * failure message on `error`, and `cancelled` when the script died of
606
+ * cancellation. This method only chooses the result; the session publishes
607
+ * it and the host owns terminal child cancellation.
608
+ * @returns the settled outcome — this promise NEVER rejects (the seam's
609
+ * `result`-never-rejects contract); every failure maps to a variant.
610
+ */
611
+ async drive() {
612
+ try {
613
+ if (this.isCancelled()) throw this.cancelledError();
614
+ const scriptPromise = this.callScopes.run(this.rootScope, () => this.compiled.runInContext(this.context, { timeout: this.limits.syncTimeoutMs }));
615
+ const scriptResult = this.contain(Promise.resolve(scriptPromise)).then((value) => ({
616
+ kind: "script",
617
+ value
618
+ }));
619
+ const completed = this.completionGate.promise.then(() => ({ kind: "complete" }));
620
+ const settled = await Promise.race([scriptResult, completed]);
621
+ if (settled.kind === "complete") return this.completedResult();
622
+ const raw = settled.value;
623
+ /* v8 ignore next -- complete() resolves completionGate before a caught sentinel can settle scriptPromise */
624
+ if (this.completed !== void 0 || this.completionError !== void 0) return this.completedResult();
625
+ if (this.isCancelled()) throw this.cancelledError();
626
+ const value = raw === void 0 ? null : this.materializeResult(raw);
627
+ const missingReplay = this.unreplayedJournalError();
628
+ if (missingReplay !== void 0) throw missingReplay;
629
+ return {
630
+ value,
631
+ stopReason: "completed",
632
+ agentsStarted: this.started
633
+ };
634
+ } catch (error) {
635
+ /* v8 ignore next -- completionGate wins the race whenever complete() has claimed a terminal */
636
+ if (this.completed !== void 0 || this.completionError !== void 0) return this.completedResult();
637
+ if (this.isCancelled()) return {
638
+ value: null,
639
+ stopReason: "cancelled",
640
+ error: this.cancelledError().message,
641
+ errorCode: "CANCELLED",
642
+ agentsStarted: this.started
643
+ };
644
+ /* v8 ignore next -- the out-of-band completionGate always wins before the sentinel reaches drive() */
645
+ if (error === COMPLETE_SENTINEL) return this.completedResult();
646
+ return {
647
+ value: null,
648
+ stopReason: "error",
649
+ error: renderThrown(error),
650
+ ...error instanceof WorkflowError$1 ? { errorCode: error.code } : {},
651
+ agentsStarted: this.started
652
+ };
653
+ }
654
+ }
655
+ /** Materialize and report the `complete(value)` terminal. */
656
+ completedResult() {
657
+ if (this.completionError !== void 0) return {
658
+ value: null,
659
+ stopReason: "error",
660
+ error: this.completionError.message,
661
+ errorCode: this.completionError.code,
662
+ agentsStarted: this.started
663
+ };
664
+ const missingReplay = this.unreplayedJournalError();
665
+ if (missingReplay !== void 0) return {
666
+ value: null,
667
+ stopReason: "error",
668
+ error: missingReplay.message,
669
+ errorCode: missingReplay.code,
670
+ agentsStarted: this.started
671
+ };
672
+ return {
673
+ value: this.completed.value,
674
+ stopReason: "completed",
675
+ agentsStarted: this.started
676
+ };
677
+ }
678
+ /**
679
+ * Attach a no-op rejection consumer WITHOUT changing what the caller
680
+ * receives: if the script drops the promise (no await), cancellation cannot
681
+ * become an unhandled rejection (which would kill the worker thread); if
682
+ * the script does await it, it still observes the rejection.
683
+ */
684
+ contain(promise) {
685
+ promise.catch(() => {});
686
+ return promise;
687
+ }
688
+ cancelledError() {
689
+ /* v8 ignore next */
690
+ return this.cancelError ?? new WorkflowError$1("workflow run cancelled", "CANCELLED");
691
+ }
692
+ /** Materialize the script's return value; violations become RESULT_UNSERIALIZABLE. */
693
+ materializeResult(raw) {
694
+ try {
695
+ return materializeFromRealm(raw, "workflow result");
696
+ } catch (error) {
697
+ /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */
698
+ if (!(error instanceof MaterializeError)) throw error;
699
+ throw new WorkflowError$1(`the workflow's return value is not plain JSON data — ${error.message}. Return only JSON-serializable objects/arrays/scalars.`, "RESULT_UNSERIALIZABLE", { cause: error });
700
+ }
701
+ }
702
+ /**
703
+ * Acquire one concurrency slot (FIFO). Cancellation rejects QUEUED waiters
704
+ * (see {@link cancel}); the callers guard their own entry and post-acquire
705
+ * windows, so no cancelled-precheck is duplicated here.
706
+ */
707
+ acquireSlot() {
708
+ if (this.activeSlots < this.limits.maxConcurrentAgents) {
709
+ this.activeSlots += 1;
710
+ return Promise.resolve();
711
+ }
712
+ return new Promise((resolve, reject) => {
713
+ this.slotWaiters.push({
714
+ resolve: () => {
715
+ this.activeSlots += 1;
716
+ resolve();
717
+ },
718
+ reject
719
+ });
720
+ });
721
+ }
722
+ releaseSlot() {
723
+ this.activeSlots -= 1;
724
+ const next = this.slotWaiters.shift();
725
+ if (next) next.resolve();
726
+ }
727
+ /** Claim the next deterministic node under the current combinator branch. */
728
+ claimCallId(_kind) {
729
+ const scope = this.currentScope();
730
+ scope.nextNode += 1;
731
+ return [...scope.path, scope.nextNode];
732
+ }
733
+ /** Resolve and verify one committed replay entry for the current call. */
734
+ replayEntry(callId, kind, fingerprint) {
735
+ const key = callId.join(".");
736
+ const replay = this.journal.get(key);
737
+ if (replay === void 0) return void 0;
738
+ if (replay.kind !== kind || replay.fingerprint !== fingerprint) throw new WorkflowError$1(`workflow journal diverged at ${callId}: the replayed ${kind} request does not match the committed request`, "JOURNAL_DIVERGENCE");
739
+ this.replayedJournalCallIds.add(key);
740
+ return replay;
741
+ }
742
+ /** Detect a resumed path that skipped a previously committed host call. */
743
+ unreplayedJournalError() {
744
+ for (const callId of this.journal.keys()) if (!this.replayedJournalCallIds.has(callId)) return new WorkflowError$1(`workflow journal diverged: the resumed path did not replay committed call ${callId}`, "JOURNAL_DIVERGENCE");
745
+ }
746
+ /** Append one completed host call unless this is a non-persistent smoke check. */
747
+ commitJournal(entry) {
748
+ if (this.validateOnly) return;
749
+ this.nextJournalOrdinal += 1;
750
+ this.observer.journalCommit({
751
+ ...entry,
752
+ ordinal: this.nextJournalOrdinal
753
+ });
754
+ }
755
+ /** Atomically admit one direct-agent reservation for every new panel item. */
756
+ reservePanel(scopes) {
757
+ const reservations = scopes.flatMap((scope) => scope.reservation === void 0 ? [] : [scope.reservation]);
758
+ if (this.started + reservations.length > this.limits.maxTotalAgents) throw this.agentCapError(reservations.length);
759
+ this.started += reservations.length;
760
+ }
761
+ /** Consume a panel reservation or admit one standalone/nested agent call. */
762
+ spendAgentBudget() {
763
+ const reservation = this.callScopes.getStore()?.reservation;
764
+ if (reservation !== void 0 && reservation.available) {
765
+ reservation.available = false;
766
+ this.nextAgentSeq += 1;
767
+ return this.nextAgentSeq;
768
+ }
769
+ if (this.started >= this.limits.maxTotalAgents) throw this.agentCapError(1);
770
+ this.started += 1;
771
+ this.nextAgentSeq += 1;
772
+ return this.nextAgentSeq;
773
+ }
774
+ /** Build the fatal error for a budget admission that would exceed the cap. */
775
+ agentCapError(requested) {
776
+ return new WorkflowError$1(`this run cannot admit ${requested} agent${requested === 1 ? "" : "s"}: ${this.started} of ${this.limits.maxTotalAgents} logical-agent budget is already spent and the total agent cap (${this.limits.maxTotalAgents}) would be exceeded — raise the applicable maxTotalAgents limit if the scale is intentional`, "AGENT_CAP");
777
+ }
778
+ /** The `agent(prompt, opts)` hook. */
779
+ async agent(rawPrompt, rawOpts) {
780
+ this.throwIfCancelled();
781
+ if (typeof rawPrompt !== "string" || rawPrompt.length === 0) throw new WorkflowError$1("agent() requires a non-empty prompt string", "INVALID_ARGUMENT");
782
+ const prepared = this.readAgentOptions(rawOpts);
783
+ const opts = prepared.options;
784
+ const label = opts.label ?? defaultLabel(rawPrompt);
785
+ const phase = opts.phase ?? this.currentScope().currentPhase;
786
+ const callId = this.claimCallId("agent");
787
+ const fingerprint = fingerprintHostCall("agent", {
788
+ prompt: rawPrompt,
789
+ options: {
790
+ ...opts,
791
+ label,
792
+ ...phase === void 0 ? {} : { phase }
793
+ }
794
+ });
795
+ const replay = this.replayEntry(callId, "agent", fingerprint);
796
+ if (replay !== void 0) return replay.result;
797
+ const seq = this.spendAgentBudget();
798
+ if (this.validateOnly) return opts.schema !== void 0 ? cannedSchemaValue(opts.schema, this.limits.maxItemsPerCall) : "";
799
+ await this.acquireSlot();
800
+ try {
801
+ this.throwIfCancelled();
802
+ let run;
803
+ try {
804
+ run = await this.children.startAgent({
805
+ prompt: rawPrompt,
806
+ ...prepared.providerSchema !== void 0 ? { schema: prepared.providerSchema } : {},
807
+ ...opts.provider !== void 0 ? { provider: opts.provider } : {},
808
+ ...opts.model !== void 0 ? { model: opts.model } : {}
809
+ });
810
+ } catch (error) {
811
+ if (this.isCancelled()) throw this.cancelledError();
812
+ throw new WorkflowError$1(`agent() could not start a child: ${renderThrown(error)}`, "AGENT_START", { cause: error });
813
+ }
814
+ if (this.isCancelled()) {
815
+ await run.dispose();
816
+ throw this.cancelledError();
817
+ }
818
+ const info = {
819
+ seq,
820
+ label,
821
+ ...phase !== void 0 ? { phase } : {},
822
+ childId: (0, _deepseek_ai_dsh_session.SessionId)(run.id)
823
+ };
824
+ this.observer.agentStart(info);
825
+ try {
826
+ let result;
827
+ try {
828
+ result = await run.result;
829
+ } catch (error) {
830
+ if (this.isCancelled()) {
831
+ this.observer.agentEnd({
832
+ ...info,
833
+ outcome: "cancelled"
834
+ });
835
+ throw this.cancelledError();
836
+ }
837
+ this.observer.agentEnd({
838
+ ...info,
839
+ outcome: "failed"
840
+ });
841
+ throw new WorkflowError$1(`child agent run failed: ${renderThrown(error)}`, "AGENT_RESULT", { cause: error });
842
+ }
843
+ if (this.isCancelled()) {
844
+ this.observer.agentEnd({
845
+ ...info,
846
+ outcome: "cancelled"
847
+ });
848
+ throw this.cancelledError();
849
+ }
850
+ if (result.stopReason === "completed") {
851
+ if (opts.schema !== void 0) {
852
+ if (result.structured === void 0) {
853
+ this.commitJournal({
854
+ kind: "agent",
855
+ seq,
856
+ callId,
857
+ fingerprint,
858
+ result: null
859
+ });
860
+ this.observer.agentEnd({
861
+ ...info,
862
+ outcome: "failed"
863
+ });
864
+ return null;
865
+ }
866
+ const structured = result.structured;
867
+ if (!schemaValueMatches(opts.schema, structured)) {
868
+ this.commitJournal({
869
+ kind: "agent",
870
+ seq,
871
+ callId,
872
+ fingerprint,
873
+ result: null
874
+ });
875
+ this.observer.agentEnd({
876
+ ...info,
877
+ outcome: "failed"
878
+ });
879
+ return null;
880
+ }
881
+ this.commitJournal({
882
+ kind: "agent",
883
+ seq,
884
+ callId,
885
+ fingerprint,
886
+ result: structured
887
+ });
888
+ this.observer.agentEnd({
889
+ ...info,
890
+ outcome: "completed"
891
+ });
892
+ return result.structured;
893
+ }
894
+ const text = outputText(result.output);
895
+ this.commitJournal({
896
+ kind: "agent",
897
+ seq,
898
+ callId,
899
+ fingerprint,
900
+ result: text
901
+ });
902
+ this.observer.agentEnd({
903
+ ...info,
904
+ outcome: "completed"
905
+ });
906
+ return text;
907
+ }
908
+ this.commitJournal({
909
+ kind: "agent",
910
+ seq,
911
+ callId,
912
+ fingerprint,
913
+ result: null
914
+ });
915
+ this.observer.agentEnd({
916
+ ...info,
917
+ outcome: "failed"
918
+ });
919
+ return null;
920
+ } finally {
921
+ await run.dispose();
922
+ }
923
+ } finally {
924
+ this.releaseSlot();
925
+ }
926
+ }
927
+ /** Materialize + validate the `agent()` options bag from the realm. */
928
+ readAgentOptions(rawOpts) {
929
+ if (rawOpts === void 0) return { options: {} };
930
+ let opts;
931
+ try {
932
+ opts = materializeFromRealm(rawOpts, "agent() options");
933
+ } catch (error) {
934
+ /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */
935
+ if (!(error instanceof MaterializeError)) throw error;
936
+ throw new WorkflowError$1(`agent() options must be plain JSON data — ${error.message}`, "INVALID_ARGUMENT", { cause: error });
937
+ }
938
+ if (typeof opts !== "object" || opts === null || Array.isArray(opts)) throw new WorkflowError$1("agent() options must be an object", "INVALID_ARGUMENT");
939
+ const record = opts;
940
+ for (const key of Object.keys(record)) {
941
+ if (SUPPORTED_AGENT_OPTIONS.has(key)) continue;
942
+ if (DEFERRED_AGENT_OPTIONS.has(key)) throw new WorkflowError$1(`agent() option "${key}" is deferred and not supported by this engine (supported: label, phase, schema, provider, model)`, "UNSUPPORTED_OPTION");
943
+ throw new WorkflowError$1(`agent() option "${key}" is not recognized (supported: label, phase, schema, provider, model)`, "UNSUPPORTED_OPTION");
944
+ }
945
+ for (const key of [
946
+ "label",
947
+ "phase",
948
+ "provider",
949
+ "model"
950
+ ]) if (record[key] !== void 0 && typeof record[key] !== "string") throw new WorkflowError$1(`agent() option "${key}" must be a string`, "INVALID_ARGUMENT");
951
+ let schema;
952
+ let providerSchema;
953
+ if (record.schema !== void 0) try {
954
+ const prepared = prepareObjectSchema(record.schema);
955
+ schema = prepared.authored;
956
+ providerSchema = prepared.provider;
957
+ } catch (error) {
958
+ /* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */
959
+ if (!(error instanceof _deepseek_ai_dsh_tools.JsonSchemaError)) throw error;
960
+ throw new WorkflowError$1(`agent() schema is outside the supported subset — ${error.message}`, "UNSUPPORTED_SCHEMA", { cause: error });
961
+ }
962
+ return {
963
+ options: {
964
+ ...record.label !== void 0 ? { label: record.label } : {},
965
+ ...record.phase !== void 0 ? { phase: record.phase } : {},
966
+ ...record.provider !== void 0 ? { provider: record.provider } : {},
967
+ ...record.model !== void 0 ? { model: record.model } : {},
968
+ ...schema !== void 0 ? { schema } : {}
969
+ },
970
+ ...providerSchema !== void 0 ? { providerSchema } : {}
971
+ };
972
+ }
973
+ /**
974
+ * The `parallel(items)` hook. Declarative job maps preflight and reserve as
975
+ * one atomic panel; arbitrary thunks admit their unknowable agent calls at
976
+ * execution time. Every item is a barrier slot; ordinary failures become
977
+ * `null` and fatal workflow errors propagate.
978
+ */
979
+ async parallel(rawItems) {
980
+ this.throwIfCancelled();
981
+ if (!Array.isArray(rawItems)) throw new WorkflowError$1("parallel() requires an array of zero-argument functions or job maps", "INVALID_ARGUMENT");
982
+ this.assertItemCap(rawItems.length, "parallel()");
983
+ const panelPath = this.claimCallId("parallel");
984
+ const items = rawItems.map((item, index) => this.parallelItem(item, index, [
985
+ ...panelPath,
986
+ index + 1,
987
+ 1
988
+ ]));
989
+ if (items.some((item) => item.kind === "job") && items.some((item) => item.kind === "thunk")) throw new WorkflowError$1("parallel() cannot mix function thunks and declarative job maps in one panel", "INVALID_ARGUMENT");
990
+ const inheritedPhase = this.currentScope().currentPhase;
991
+ const branches = items.map((item, index) => ({
992
+ item,
993
+ scope: {
994
+ path: [...panelPath, index + 1],
995
+ nextNode: 0,
996
+ ...inheritedPhase === void 0 ? {} : { currentPhase: inheritedPhase },
997
+ ...item.reservesAgent ? { reservation: { available: true } } : {}
998
+ }
999
+ }));
1000
+ this.reservePanel(branches.map((branch) => branch.scope));
1001
+ return Promise.all(branches.map(({ item, scope }) => this.callScopes.run(scope, async () => {
1002
+ try {
1003
+ return await item.run();
1004
+ } catch (error) {
1005
+ if ((0, _deepseek_ai_dsh_workflow.isFatalWorkflowError)(error)) throw error;
1006
+ return null;
1007
+ }
1008
+ })));
1009
+ }
1010
+ /** Accept one `parallel()` item as a zero-arg thunk or a Grok job map `{ prompt, ...opts }`. */
1011
+ parallelItem(item, index, callId) {
1012
+ if (typeof item === "function") return {
1013
+ run: item,
1014
+ kind: "thunk",
1015
+ reservesAgent: false
1016
+ };
1017
+ let job;
1018
+ try {
1019
+ job = materializeFromRealm(item, `parallel() item ${index}`);
1020
+ } catch (error) {
1021
+ /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */
1022
+ if (!(error instanceof MaterializeError)) throw error;
1023
+ throw new WorkflowError$1(`parallel() item ${index} must be a function or plain job map — ${error.message}`, "INVALID_ARGUMENT", { cause: error });
1024
+ }
1025
+ if (typeof job !== "object" || job === null || Array.isArray(job)) throw new WorkflowError$1(`parallel() item ${index} is not a function or job map`, "INVALID_ARGUMENT");
1026
+ const record = job;
1027
+ const prompt = record.prompt;
1028
+ if (typeof prompt !== "string" || prompt.length === 0) throw new WorkflowError$1(`parallel() job ${index} requires a non-empty "prompt" string`, "INVALID_ARGUMENT");
1029
+ const rawOpts = {};
1030
+ for (const key of Object.keys(record)) {
1031
+ if (key === "prompt") continue;
1032
+ rawOpts[key] = record[key];
1033
+ }
1034
+ const opts = this.readAgentOptions(rawOpts).options;
1035
+ const label = opts.label ?? defaultLabel(prompt);
1036
+ const phase = opts.phase ?? this.currentScope().currentPhase;
1037
+ const effectiveOptions = {
1038
+ ...opts,
1039
+ label,
1040
+ ...phase === void 0 ? {} : { phase }
1041
+ };
1042
+ return {
1043
+ run: () => this.agent(prompt, effectiveOptions),
1044
+ kind: "job",
1045
+ reservesAgent: this.replayEntry(callId, "agent", fingerprintHostCall("agent", {
1046
+ prompt,
1047
+ options: effectiveOptions
1048
+ })) === void 0
1049
+ };
1050
+ }
1051
+ /** The `pipeline(items, ...stages)` hook: per-item stage chains, NO cross-stage barrier. */
1052
+ async pipeline(rawItems, rawStages) {
1053
+ this.throwIfCancelled();
1054
+ if (!Array.isArray(rawItems)) throw new WorkflowError$1("pipeline() requires an items array", "INVALID_ARGUMENT");
1055
+ this.assertItemCap(rawItems.length, "pipeline()");
1056
+ if (rawStages.length === 0) throw new WorkflowError$1("pipeline() requires at least one stage function", "INVALID_ARGUMENT");
1057
+ const stages = rawStages.map((stage, index) => {
1058
+ if (typeof stage !== "function") throw new WorkflowError$1(`pipeline() stage ${index} is not a function`, "INVALID_ARGUMENT");
1059
+ return stage;
1060
+ });
1061
+ const pipelinePath = this.claimCallId("pipeline");
1062
+ const inheritedPhase = this.currentScope().currentPhase;
1063
+ return Promise.all(rawItems.map((item, index) => this.callScopes.run({
1064
+ path: [...pipelinePath, index + 1],
1065
+ nextNode: 0,
1066
+ ...inheritedPhase === void 0 ? {} : { currentPhase: inheritedPhase }
1067
+ }, async () => {
1068
+ let value = item;
1069
+ try {
1070
+ for (const stage of stages) value = await stage(value, item, index);
1071
+ return value;
1072
+ } catch (error) {
1073
+ if ((0, _deepseek_ai_dsh_workflow.isFatalWorkflowError)(error)) throw error;
1074
+ return null;
1075
+ }
1076
+ })));
1077
+ }
1078
+ assertItemCap(length, hook) {
1079
+ if (length > this.limits.maxItemsPerCall) throw new WorkflowError$1(`${hook} received ${length} items — over the per-call cap (${this.limits.maxItemsPerCall}); split the work or raise maxItemsPerCall in the engine config`, "ITEM_CAP");
1080
+ }
1081
+ /** The `phase(title)` hook: sets the current label for subsequent `agent()` calls and notifies observers. */
1082
+ phase(title) {
1083
+ this.throwIfCancelled();
1084
+ if (typeof title !== "string" || title.length === 0) throw new WorkflowError$1("phase() requires a non-empty title string", "INVALID_ARGUMENT");
1085
+ const callId = this.claimCallId("phase");
1086
+ const fingerprint = fingerprintHostCall("phase", { title });
1087
+ const replay = this.replayEntry(callId, "phase", fingerprint);
1088
+ this.currentScope().currentPhase = title;
1089
+ if (replay !== void 0) return;
1090
+ this.observer.phase(title);
1091
+ this.commitJournal({
1092
+ kind: "phase",
1093
+ callId,
1094
+ fingerprint,
1095
+ title
1096
+ });
1097
+ }
1098
+ /** The `log(message)` hook: narration to observers. */
1099
+ log(message) {
1100
+ this.throwIfCancelled();
1101
+ if (typeof message !== "string") throw new WorkflowError$1("log() requires a message string", "INVALID_ARGUMENT");
1102
+ const callId = this.claimCallId("log");
1103
+ const fingerprint = fingerprintHostCall("log", { message });
1104
+ if (this.replayEntry(callId, "log", fingerprint) !== void 0) return;
1105
+ this.observer.log(message);
1106
+ this.commitJournal({
1107
+ kind: "log",
1108
+ callId,
1109
+ fingerprint,
1110
+ message
1111
+ });
1112
+ }
1113
+ /** Resolve the deterministic call scope for a root hook or combinator branch. */
1114
+ currentScope() {
1115
+ return this.callScopes.getStore();
1116
+ }
1117
+ /** The `complete(value)` hook: terminate the run successfully with a JSON value. */
1118
+ complete(value) {
1119
+ this.throwIfCancelled();
1120
+ try {
1121
+ this.completed = { value: value === void 0 ? null : this.materializeResult(value) };
1122
+ } catch (error) {
1123
+ /* v8 ignore next -- materializeResult totalizes every failure as WorkflowError. */
1124
+ if (!(error instanceof WorkflowError$1)) throw new Error("materializing a workflow result threw outside the documented error type", { cause: error });
1125
+ this.completionError = error;
1126
+ }
1127
+ this.completionGate.resolve();
1128
+ throw COMPLETE_SENTINEL;
1129
+ }
1130
+ /** The `budget()` hook: this run's logical agent budget and its spend. */
1131
+ budget() {
1132
+ this.throwIfCancelled();
1133
+ const total = this.limits.maxTotalAgents;
1134
+ const spent = this.started;
1135
+ return {
1136
+ total,
1137
+ spent,
1138
+ reserved: 0,
1139
+ remaining: Math.max(0, total - spent)
1140
+ };
1141
+ }
1142
+ /** The `pause()`/`await_user()` gate: park the run until a resume message releases it. */
1143
+ async gate(rawKind, rawMessage, resumable) {
1144
+ this.throwIfCancelled();
1145
+ if (typeof rawKind !== "string" || rawKind.length === 0) throw new WorkflowError$1(`${resumable ? "await_user" : "pause"}() requires a non-empty kind string`, "INVALID_ARGUMENT");
1146
+ const kind = this.readGateKind(rawKind, resumable);
1147
+ const message = rawMessage === void 0 ? "" : typeof rawMessage === "string" ? rawMessage : void 0;
1148
+ if (message === void 0) throw new WorkflowError$1(`${resumable ? "await_user" : "pause"}() message must be a string`, "INVALID_ARGUMENT");
1149
+ if (this.validateOnly) {
1150
+ const diagnostic = `would ${resumable ? "await_user" : "pause"} (${kind}): ${message}`;
1151
+ this.observer.log(diagnostic);
1152
+ this.complete(diagnostic);
1153
+ }
1154
+ const callId = resumable ? this.claimCallId("await-user") : void 0;
1155
+ const fingerprint = resumable ? fingerprintHostCall("await-user", {
1156
+ kind,
1157
+ message
1158
+ }) : void 0;
1159
+ if (callId !== void 0 && fingerprint !== void 0 && this.replayEntry(callId, "await-user", fingerprint) !== void 0) return;
1160
+ if (this.gateResume !== void 0) throw new WorkflowError$1("workflow scripts may park on only one pause()/await_user() gate at a time", "INVALID_ARGUMENT");
1161
+ while (true) {
1162
+ this.throwIfCancelled();
1163
+ const gate = {
1164
+ kind,
1165
+ message,
1166
+ resumable
1167
+ };
1168
+ this.observer.gate(gate);
1169
+ await new Promise((resolve) => {
1170
+ this.gateResume = resolve;
1171
+ });
1172
+ this.gateResume = void 0;
1173
+ this.throwIfCancelled();
1174
+ if (resumable) {
1175
+ this.commitJournal({
1176
+ kind: "await-user",
1177
+ callId,
1178
+ fingerprint
1179
+ });
1180
+ return;
1181
+ }
1182
+ }
1183
+ }
1184
+ /** Normalize a gate kind with its `backoff`/`blocked` aliases. */
1185
+ readGateKind(rawKind, resumable) {
1186
+ switch (rawKind) {
1187
+ case "user":
1188
+ case "back_off":
1189
+ case "backoff":
1190
+ case "no_progress":
1191
+ case "verification":
1192
+ case "blocked":
1193
+ case "infra": break;
1194
+ default: throw new WorkflowError$1(`${resumable ? "await_user" : "pause"}() kind "${rawKind}" is not recognized (user, back_off, no_progress, verification, infra)`, "INVALID_ARGUMENT");
1195
+ }
1196
+ return rawKind === "backoff" ? "back_off" : rawKind === "blocked" ? "verification" : rawKind;
1197
+ }
1198
+ /** The `write_scratch_file(name, content)` hook: write one single-component scratch file. */
1199
+ async writeScratch(rawName, rawContent) {
1200
+ this.throwIfCancelled();
1201
+ const name = this.readScratchName(rawName);
1202
+ if (typeof rawContent !== "string") throw new WorkflowError$1("write_scratch_file() content must be a string", "INVALID_ARGUMENT");
1203
+ const callId = this.claimCallId("scratch-write");
1204
+ const fingerprint = fingerprintHostCall("scratch-write", {
1205
+ name,
1206
+ content: rawContent
1207
+ });
1208
+ if (this.replayEntry(callId, "scratch-write", fingerprint) !== void 0) return;
1209
+ await this.children.writeScratch(name, rawContent);
1210
+ this.commitJournal({
1211
+ kind: "scratch-write",
1212
+ callId,
1213
+ fingerprint
1214
+ });
1215
+ }
1216
+ /** The `read_scratch_file(name)` hook: read one single-component scratch file. */
1217
+ async readScratch(rawName) {
1218
+ this.throwIfCancelled();
1219
+ const name = this.readScratchName(rawName);
1220
+ const callId = this.claimCallId("scratch-read");
1221
+ const fingerprint = fingerprintHostCall("scratch-read", { name });
1222
+ const replay = this.replayEntry(callId, "scratch-read", fingerprint);
1223
+ if (replay !== void 0) return replay.content;
1224
+ const content = await this.children.readScratch(name);
1225
+ this.commitJournal({
1226
+ kind: "scratch-read",
1227
+ callId,
1228
+ fingerprint,
1229
+ ...content === void 0 ? {} : { content }
1230
+ });
1231
+ return content;
1232
+ }
1233
+ /** Validate a single-component scratch file name (no separators or traversal). */
1234
+ readScratchName(rawName) {
1235
+ if (typeof rawName !== "string" || !SCRATCH_NAME.test(rawName)) throw new WorkflowError$1("scratch file name must be a single component (letters, digits, . _ -)", "INVALID_ARGUMENT");
1236
+ return rawName;
1237
+ }
1238
+ };
1239
+ /** Index a journal while rejecting ambiguous replay identities. */
1240
+ function indexJournal(entries) {
1241
+ const byCallId = /* @__PURE__ */ new Map();
1242
+ const agentSequences = /* @__PURE__ */ new Set();
1243
+ let priorOrdinal = 0;
1244
+ for (const entry of entries ?? []) {
1245
+ if (!Number.isSafeInteger(entry.ordinal) || entry.ordinal !== priorOrdinal + 1) throw new WorkflowError$1("workflow journal entry ordinal must be the next positive safe integer", "JOURNAL_DIVERGENCE");
1246
+ priorOrdinal = entry.ordinal;
1247
+ if (!Array.isArray(entry.callId) || entry.callId.length === 0 || entry.callId.some((part) => !Number.isSafeInteger(part) || part <= 0) || byCallId.has(entry.callId.join("."))) throw new WorkflowError$1(`workflow journal repeats or omits call identity ${JSON.stringify(entry.callId)}`, "JOURNAL_DIVERGENCE");
1248
+ if (entry.kind === "agent" && (!Number.isSafeInteger(entry.seq) || entry.seq < 1)) throw new WorkflowError$1("workflow journal agent seq must be a positive safe integer", "JOURNAL_DIVERGENCE");
1249
+ if (entry.kind === "agent" && agentSequences.has(entry.seq)) throw new WorkflowError$1(`workflow journal repeats agent sequence ${entry.seq}`, "JOURNAL_DIVERGENCE");
1250
+ if (!/^[a-f0-9]{64}$/u.test(entry.fingerprint)) throw new WorkflowError$1("workflow journal fingerprint must be a lowercase SHA-256 digest", "JOURNAL_DIVERGENCE");
1251
+ byCallId.set(entry.callId.join("."), entry);
1252
+ if (entry.kind === "agent") agentSequences.add(entry.seq);
1253
+ }
1254
+ return byCallId;
1255
+ }
1256
+ /** SHA-256 one canonical effective host request for journal replay validation. */
1257
+ function fingerprintHostCall(kind, request) {
1258
+ return (0, node_crypto.createHash)("sha256").update(canonicalJson({
1259
+ kind,
1260
+ request
1261
+ })).digest("hex");
1262
+ }
1263
+ /** Serialize JSON-like data with recursively sorted object keys. */
1264
+ function canonicalJson(value) {
1265
+ if (value === null || typeof value !== "object") return JSON.stringify(value);
1266
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
1267
+ return `{${Object.entries(value).filter(([, child]) => child !== void 0).sort(([left], [right]) => left < right ? -1 : 1).map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`).join(",")}}`;
1268
+ }
1269
+ /** Single-component scratch file name grammar. */
1270
+ const SCRATCH_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
1271
+ /** Sentinel thrown by `complete()`; drive() recognizes it to terminate successfully. */
1272
+ const COMPLETE_SENTINEL = /* @__PURE__ */ new Error("workflow completed");
1273
+ //#endregion
1274
+ //#region vendor/workflow-engine/session.ts
1275
+ /**
1276
+ * The worker-side handle for one started child agent ({@link ChildHandle}):
1277
+ * every member is an RPC to the host keyed by this call's `callId`, resolved
1278
+ * by the session's message handler through the bridge's pending entry.
1279
+ */
1280
+ var RpcChildHandle = class {
1281
+ constructor(post, callId, entry, id) {
1282
+ this.post = post;
1283
+ this.callId = callId;
1284
+ this.entry = entry;
1285
+ this.id = id;
1286
+ this.result = entry.settled.promise;
1287
+ }
1288
+ dispose() {
1289
+ this.post("child-dispose", { callId: this.callId });
1290
+ return this.entry.disposed.promise;
1291
+ }
1292
+ };
1293
+ /**
1294
+ * The worker-side child-RPC bridge ({@link ChildPort}): allocates callIds,
1295
+ * posts the start/dispose RPCs, and owns the per-call pending
1296
+ * book-keeping the session's message handler settles via the `onChild*`
1297
+ * entry points.
1298
+ */
1299
+ var ChildRpcBridge = class {
1300
+ constructor(post) {
1301
+ this.post = post;
1302
+ this.nextCallId = 0;
1303
+ this.pending = /* @__PURE__ */ new Map();
1304
+ this.pendingScratch = /* @__PURE__ */ new Map();
1305
+ }
1306
+ async startAgent(request) {
1307
+ this.nextCallId += 1;
1308
+ const callId = this.nextCallId;
1309
+ const entry = {
1310
+ started: Promise.withResolvers(),
1311
+ settled: Promise.withResolvers(),
1312
+ disposed: Promise.withResolvers()
1313
+ };
1314
+ entry.settled.promise.catch(() => {});
1315
+ this.pending.set(callId, entry);
1316
+ this.post("child-start", {
1317
+ callId,
1318
+ request
1319
+ });
1320
+ const childId = await entry.started.promise;
1321
+ return new RpcChildHandle(this.post, callId, entry, childId);
1322
+ }
1323
+ async writeScratch(name, content) {
1324
+ const callId = this.claimCallId();
1325
+ const resolve = Promise.withResolvers();
1326
+ this.pendingScratch.set(callId, resolve);
1327
+ this.post("scratch-write", {
1328
+ callId,
1329
+ name,
1330
+ content
1331
+ });
1332
+ await resolve.promise;
1333
+ }
1334
+ async readScratch(name) {
1335
+ const callId = this.claimCallId();
1336
+ const resolve = Promise.withResolvers();
1337
+ this.pendingScratch.set(callId, resolve);
1338
+ this.post("scratch-read", {
1339
+ callId,
1340
+ name
1341
+ });
1342
+ return (await resolve.promise).content;
1343
+ }
1344
+ claimCallId() {
1345
+ this.nextCallId += 1;
1346
+ return this.nextCallId;
1347
+ }
1348
+ /** The host established a published child; releases the `startAgent` await. */
1349
+ onChildStarted(callId, childId) {
1350
+ this.pending.get(callId)?.started.resolve(childId);
1351
+ }
1352
+ /** Asynchronous provider start failed; reject and retire the pending RPC. */
1353
+ onChildStartError(callId, rendered) {
1354
+ const entry = this.pending.get(callId);
1355
+ this.pending.delete(callId);
1356
+ entry?.started.reject(new Error(rendered));
1357
+ }
1358
+ /** The child's terminal result arrived. */
1359
+ onChildSettled(callId, result) {
1360
+ this.pending.get(callId)?.settled.resolve(result);
1361
+ }
1362
+ /** The child's `result` rejected host-side (an infrastructure fault, relayed as fatal). */
1363
+ onChildFailed(callId, rendered) {
1364
+ this.pending.get(callId)?.settled.reject(new Error(rendered));
1365
+ }
1366
+ /** The host acked the dispose; the call's book-keeping is complete. */
1367
+ onChildDisposed(callId) {
1368
+ const entry = this.pending.get(callId);
1369
+ this.pending.delete(callId);
1370
+ entry?.disposed.resolve();
1371
+ }
1372
+ /** The host completed a scratch write. */
1373
+ onScratchWritten(callId) {
1374
+ const entry = this.pendingScratch.get(callId);
1375
+ this.pendingScratch.delete(callId);
1376
+ entry?.resolve({});
1377
+ }
1378
+ /** The host completed a scratch read (content absent = file missing). */
1379
+ onScratchReadResult(callId, content) {
1380
+ const entry = this.pendingScratch.get(callId);
1381
+ this.pendingScratch.delete(callId);
1382
+ entry?.resolve({ ...content !== void 0 ? { content } : {} });
1383
+ }
1384
+ };
1385
+ /**
1386
+ * Narrow the nullable `parentPort` the bootstrap reads from
1387
+ * `node:worker_threads`.
1388
+ * @param port - `parentPort` as imported (null on the main thread).
1389
+ * @returns the port, non-null.
1390
+ */
1391
+ function requireParentPort(port) {
1392
+ if (port === null) throw new Error("the workflow worker entry must be loaded inside a worker thread (no parentPort)");
1393
+ return port;
1394
+ }
1395
+ /**
1396
+ * Run one workflow script to settlement against `port`, posting the terminal result message
1397
+ * exactly once; resolves after that post (stray children may still be winding down through the
1398
+ * port — the host owns their teardown and ultimately terminates the thread). It never rejects:
1399
+ * constructor failure becomes an error result. Host pre-parse makes syntax failure here a likely
1400
+ * Node-version skew, but the session still reports it instead of dying silently.
1401
+ * @param port - the channel to the host (the real `parentPort`, or one side
1402
+ * of an in-process `MessageChannel` in tests).
1403
+ * @param init - the run payload the host provided as `workerData`.
1404
+ */
1405
+ async function runWorkerSession(port, init) {
1406
+ const post = (type, payload) => {
1407
+ port.postMessage({
1408
+ type,
1409
+ ...payload
1410
+ });
1411
+ };
1412
+ const children = new ChildRpcBridge(post);
1413
+ const observer = {
1414
+ phase: (title) => {
1415
+ post("phase", { title });
1416
+ },
1417
+ log: (message) => {
1418
+ post("log", { message });
1419
+ },
1420
+ agentStart: (info) => {
1421
+ post("agent-start", { info });
1422
+ },
1423
+ agentEnd: (info) => {
1424
+ post("agent-end", { info });
1425
+ },
1426
+ gate: (gate) => {
1427
+ post("gate", { gate });
1428
+ },
1429
+ journalCommit: (entry) => {
1430
+ post("journal-commit", { entry });
1431
+ }
1432
+ };
1433
+ let execution;
1434
+ try {
1435
+ execution = new WorkflowExecution(init.meta, init.body, init.args, init.limits, observer, children, init.journal, init.validateOnly, init.initialAgentSpend, init.initialAgentSeq);
1436
+ } catch (error) {
1437
+ post("ready", {});
1438
+ post("result", { result: {
1439
+ value: null,
1440
+ stopReason: "error",
1441
+ error: renderThrown(error),
1442
+ ...error instanceof _deepseek_ai_dsh_workflow.WorkflowError ? { errorCode: error.code } : {},
1443
+ agentsStarted: Math.max(init.initialAgentSpend ?? 0, init.journal?.filter((entry) => entry.kind === "agent").length ?? 0)
1444
+ } });
1445
+ return;
1446
+ }
1447
+ const gate = Promise.withResolvers();
1448
+ port.on("message", (message) => {
1449
+ switch (message.type) {
1450
+ case "go":
1451
+ gate.resolve();
1452
+ break;
1453
+ case "cancel":
1454
+ execution.cancel(message.reason);
1455
+ gate.resolve();
1456
+ break;
1457
+ case "resume":
1458
+ execution.resume();
1459
+ break;
1460
+ case "child-started":
1461
+ children.onChildStarted(message.callId, message.childId);
1462
+ break;
1463
+ case "child-start-error":
1464
+ children.onChildStartError(message.callId, message.rendered);
1465
+ break;
1466
+ case "child-settled":
1467
+ children.onChildSettled(message.callId, message.result);
1468
+ break;
1469
+ case "child-failed":
1470
+ children.onChildFailed(message.callId, message.rendered);
1471
+ break;
1472
+ case "child-disposed":
1473
+ children.onChildDisposed(message.callId);
1474
+ break;
1475
+ case "scratch-written":
1476
+ children.onScratchWritten(message.callId);
1477
+ break;
1478
+ case "scratch-read-result":
1479
+ children.onScratchReadResult(message.callId, message.content);
1480
+ break;
1481
+ /* v8 ignore next 2 -- closed engine-owned union; the arm only makes adding a message type a compile error */
1482
+ default: (0, _deepseek_ai_dsh_llm.assertNever)(message, "host-to-worker message");
1483
+ }
1484
+ });
1485
+ post("ready", {});
1486
+ await gate.promise;
1487
+ post("result", { result: await execution.drive() });
1488
+ }
1489
+ //#endregion
1490
+ //#region vendor/workflow-engine/worker.ts
1491
+ /**
1492
+ * Single-statement worker entry that boots `runWorkerSession` on real `parentPort`. Logic remains in
1493
+ * the session module for in-process MessageChannel coverage; importing this entry on the main thread
1494
+ * exercises `requireParentPort`'s failure path.
1495
+ * @module @deepseek-ai/dsh-workflow-worker-thread/worker
1496
+ */
1497
+ runWorkerSession(requireParentPort(node_worker_threads.parentPort), node_worker_threads.workerData);
1498
+ //#endregion
1499
+
1500
+ //# sourceMappingURL=worker.cjs.map