@deepseek-ai/dsh-workflow-ptc 0.2.0-rc.2 → 0.2.1-alpha.2

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.
package/README.i18n.yaml CHANGED
@@ -21,29 +21,29 @@
21
21
  en: 9c31c6e17ba018ed
22
22
  zh: 85ffe20ce8a5a371
23
23
  /deepseek-ai-dsh-workflow-ptc/use-this-package/results-and-failures:
24
- en: 483134c11525910a
25
- zh: d2ad48023e4a4be9
24
+ en: 0626f232df315a7d
25
+ zh: 573e9a12bc69ac6d
26
26
  /deepseek-ai-dsh-workflow-ptc/use-this-package/file-policy-and-cancellation:
27
- en: abc56c2117c83d1c
28
- zh: 4574a44302f70c20
27
+ en: 3d3dfd0da6975208
28
+ zh: 41a3f05ee9d5616f
29
29
  /deepseek-ai-dsh-workflow-ptc/understand-the-implementation:
30
- en: 52aee3bea250e968
31
- zh: d606ae0fbb5c97b4
30
+ en: ff9de0f5f3423c12
31
+ zh: 4c5ae9845d452cc1
32
32
  /deepseek-ai-dsh-workflow-ptc/understand-the-implementation/design-concept:
33
33
  en: 9b3beda22fb408f7
34
34
  zh: ac8701b4a7591b0e
35
35
  /deepseek-ai-dsh-workflow-ptc/understand-the-implementation/source-map:
36
- en: 5196e336f2c9323c
37
- zh: 6663f239334ee9fe
36
+ en: d94db278c7b67278
37
+ zh: 054d0cf46a8f6f07
38
38
  /deepseek-ai-dsh-workflow-ptc/understand-the-implementation/values-and-child-ownership:
39
- en: 4e866f00a49d76e7
40
- zh: 15a02d9ccc33d08f
39
+ en: dc06a1e03179824e
40
+ zh: 4be1d6bc090f4c03
41
41
  /deepseek-ai-dsh-workflow-ptc/understand-the-implementation/cancellation-and-outcomes:
42
42
  en: 8b8806d701e3d32d
43
43
  zh: cfa21c4962be2fa4
44
44
  /deepseek-ai-dsh-workflow-ptc/further-exploration:
45
- en: 8fa36196dfbb0906
46
- zh: 301c6efb8a7dfffe
45
+ en: 07733b39d2029089
46
+ zh: a4d54dd2fd7d21d3
47
47
  /deepseek-ai-dsh-workflow-ptc/model-experience:
48
48
  en: 215e7ba838619b7b
49
49
  zh: a311da3843709f90
package/README.md CHANGED
@@ -50,13 +50,13 @@ The Node PTC provider's `maxPendingCalls` also limits workflow concurrency: chil
50
50
 
51
51
  ### Results and failures
52
52
 
53
- The script runs with top-level `await`; `meta` and `args` arrive as JSON data. Every `agent()` call uses the configured subagent provider and the run's fixed parent. The final lossless-JSON return value becomes the run result; an ordinary child failure resolves `agent()` to `null`.
53
+ The script runs with top-level `await`; `meta` and `args` arrive as JSON data. Every `agent()` call starts a managed subagent Activation under the run's fixed parent and waits for its text or structured result. The workflow records its own members and collects their results without adding them to the parent's subagent catalog or sending child settlement notices to the parent model. The final lossless-JSON return value becomes the run result; an ordinary child failure resolves `agent()` to `null`.
54
54
 
55
55
  Invalid metadata, an unparseable body, an unavailable provider route or a per-run cap above the ceiling is rejected before a run is published. During execution, hook misuse and tripped cooperative caps fail the workflow. Process failures, unavailable required confinement and PTC output or control limits also fail the run.
56
56
 
57
57
  ### File policy and cancellation
58
58
 
59
- The engine resolves the calling Session's standing file policy and cwd for PTC execution. The VM retains the documented helper API, but it is not a security boundary: code that reaches Node remains subject to the selected OS file policy. The program-visible environment is empty. Network access is not restricted by the file policy.
59
+ The engine captures the calling Session's effective working directory and standing file policy separately. The PTC process and every child started by that workflow retain the captured directory when the parent later moves. The VM retains the documented helper API, but it is not a security boundary: code that reaches Node remains subject to the selected OS file policy. The program-visible environment is empty. Network access is not restricted by the file policy.
60
60
 
61
61
  The workflow requests `timeoutMs: null` from PTC. Its initial VM slice still has `syncTimeoutMs`, and a caller's abort signal still applies, including an enclosing tool deadline. Cancellation immediately aborts the PTC process and pending or active subagents. The caller must dispose every run and await child cleanup; there is no separate workflow cleanup timer.
62
62
 
@@ -68,7 +68,7 @@ The workflow requests `timeoutMs: null` from PTC. Its initial VM slice still has
68
68
  <details>
69
69
  <summary>Implementation internals — click to expand</summary>
70
70
 
71
- The workflow engine owns orchestration; the PTC provider owns process launch, OS confinement, framed transport and managed process cleanup.
71
+ The workflow engine owns orchestration; the PTC provider owns process launch, OS confinement, framed transport and managed process cleanup. Local children remain in the parent subagent catalog after completion, independently of caller-owned result collection; workflow runs add no parent completion notice. Local workflow children use the continuable catalog mode and accept messages while resident; cold continuation requires Session persistence and query, so an ephemeral child returns `NOT_RESUMABLE` after disposal.
72
72
 
73
73
  ### Design concept
74
74
 
@@ -85,13 +85,12 @@ One self-contained guest program runs the existing VM and workflow helpers insid
85
85
  | [`src/runtime.ts`](src/runtime.ts) | VM evaluation, helper contracts and combinators |
86
86
  | [`src/realm.ts`](src/realm.ts) | Lossless-JSON materialization across VM realms |
87
87
  | [`src/meta.ts`](src/meta.ts) | Metadata validation and normalization |
88
- | — | No runtime invariant companion is published; the workflow service owns event pairing and PTC owns managed-process observations. |
89
88
 
90
89
  ### Values and child ownership
91
90
 
92
91
  The guest materializes outbound values as lossless JSON before PTC transport. Exotic prototypes, functions, symbols, cycles, sparse arrays, non-finite numbers and nested `undefined` are rejected. Child results cross back as JSON; same-process observer events retain their own cloning and callback-containment rules.
93
92
 
94
- The host tracks pending provider starts separately from published children. A shared abort signal closes both paths; a child that becomes ready after cancellation is disposed. Each published child's disposal is shared by all cleanup paths. In-flight host bindings remain the workflow adapter's responsibility after PTC stops the program.
93
+ The host tracks pending starts separately from accepted Activations. Cancellation aborts pending starts and disposes accepted Activations; a child that becomes ready after cancellation is also disposed. Each Activation's disposal addresses that execution and is shared by all cleanup paths. In-flight host bindings remain the workflow adapter's responsibility after PTC stops the program.
95
94
 
96
95
  ### Cancellation and outcomes
97
96
 
@@ -110,7 +109,7 @@ Use these references for the shared execution guarantees and workflow contracts.
110
109
  - [Workflow service](../workflow/README.md) — caller-owned runs and cleanup.
111
110
  - [Node PTC runtime](../../ptc-runtime/ptc-runtime-node/README.md) — file policy, process limits and deployment choices.
112
111
  - [workflow tool](../tool-workflow/README.md) — model-facing scripted orchestration.
113
- - [Ralph tool](../tool-ralph/README.md) — opt-in fixed fresh-agent iteration.
112
+ - [Ralph tool](../../experimental/tool-ralph/README.md) — opt-in fixed fresh-agent iteration.
114
113
  - [Workflow sandbox reuse](../../../.agents/notes/implemented/architecture/2026-09-13-workflow-ptc-sandbox-reuse.md) — execution ownership and tradeoffs.
115
114
 
116
115
  -----
package/README.zh.md CHANGED
@@ -50,13 +50,13 @@ Node PTC 提供方的 `maxPendingCalls` 也限制工作流并发:子 agent 启
50
50
 
51
51
  ### 结果与失败
52
52
 
53
- 脚本支持顶层 `await`;`meta` 和 `args` 作为 JSON 数据传入。每次 `agent()` 调用使用配置的 subagent 提供方及运行固定的父级。最终的无损 JSON 返回值成为运行结果;普通子 agent 失败使 `agent()` 以 `null` 兑现。
53
+ 脚本支持顶层 `await`;`meta` 和 `args` 作为 JSON 数据传入。每次 `agent()` 调用都会在本次运行的固定父 agent 下启动受管理的 subagent Activation,并等待其文本或结构化结果。工作流记录自己的成员并收集其结果,不向父级子代理目录添加条目,也不向父模型发送子 agent 结算通知。最终的无损 JSON 返回值成为运行结果;普通子 agent 失败使 `agent()` 以 `null` 兑现。
54
54
 
55
55
  无效元数据、无法解析的正文、不可用的提供方路由或高于上限的单次运行上限,在运行发布前被拒绝。执行期间,钩子误用与超出协作式上限会使工作流失败。进程失败、所需约束不可用,以及超出 PTC 输出或控制限制也会使运行失败。
56
56
 
57
57
  ### 文件策略与取消
58
58
 
59
- 引擎为 PTC 执行解析调用 Session 的常设文件策略与 cwd。VM 保留文档说明的辅助 API,但它不是安全边界:触达 Node 的代码仍受所选 OS 文件策略约束。程序可见的环境为空。文件策略不限制网络访问。
59
+ 引擎分别捕获调用 Session 的有效工作目录与常设文件策略。父级之后切换目录时,PTC 进程及该工作流随后启动的每个子级都保留捕获的目录。VM 保留文档说明的辅助 API,但它不是安全边界:触达 Node 的代码仍受所选 OS 文件策略约束。程序可见的环境为空。文件策略不限制网络访问。
60
60
 
61
61
  工作流向 PTC 请求 `timeoutMs: null`。最初的 VM 片段仍受 `syncTimeoutMs` 限制,调用方的中止信号仍然生效,包括外层工具的截止。取消立即中止 PTC 进程及待启动或活跃的 subagent。调用方必须释放每次运行并等待子 agent 清理;不另设工作流清理定时器。
62
62
 
@@ -68,7 +68,7 @@ Node PTC 提供方的 `maxPendingCalls` 也限制工作流并发:子 agent 启
68
68
  <details>
69
69
  <summary>实现细节——点击展开</summary>
70
70
 
71
- 工作流引擎负责编排;PTC 提供方负责进程启动、OS 约束、分帧传输与受管进程清理。
71
+ 工作流引擎负责编排;PTC 提供方负责进程启动、OS 约束、分帧传输与受管进程清理。本地子级在完成后仍保留于父级 subagent 目录中,与调用方负责的结果收集相互独立;工作流运行不添加父级完成通知。 本地工作流子级使用可续目录模式,驻留时可接收消息;冷续跑需要 Session 持久化与查询,因此临时子级在释放后返回 `NOT_RESUMABLE`。
72
72
 
73
73
  ### 设计理念
74
74
 
@@ -85,13 +85,12 @@ Node PTC 提供方的 `maxPendingCalls` 也限制工作流并发:子 agent 启
85
85
  | [`src/runtime.ts`](src/runtime.ts) | VM 求值、辅助函数约定与组合器 |
86
86
  | [`src/realm.ts`](src/realm.ts) | 跨 VM realm 的无损 JSON 物化 |
87
87
  | [`src/meta.ts`](src/meta.ts) | 元数据校验与规范化 |
88
- | — | 不发布运行时不变式伴生入口;工作流服务负责事件配对,PTC 负责受管进程观测。 |
89
88
 
90
89
  ### 值与子 agent 归属
91
90
 
92
91
  guest 在 PTC 传输前将出站值物化为无损 JSON。特殊原型、函数、symbol、循环、稀疏数组、非有限数与嵌套 `undefined` 被拒绝。子 agent 结果以 JSON 返回;同进程观察事件保留自身的克隆和回调异常隔离规则。
93
92
 
94
- Host 分别跟踪待完成的提供方启动与已发布子 agent。共享中止信号关闭这两条路径;取消后才就绪的子 agent 会被释放。每个已发布子 agent 的资源释放由所有清理路径共享。PTC 停止程序后,进行中的 Host 绑定仍由工作流适配器负责。
93
+ Host 分别跟踪待完成的启动与已接受的 Activation。取消会中止待完成的启动并释放已接受的 Activation;取消后才就绪的子 agent 也会被释放。每个 Activation 的资源释放针对该次执行,并由所有清理路径共享。PTC 停止程序后,进行中的 Host 绑定仍由工作流适配器负责。
95
94
 
96
95
  ### 取消与结果
97
96
 
@@ -110,7 +109,7 @@ Host 分别跟踪待完成的提供方启动与已发布子 agent。共享中止
110
109
  - [工作流服务](../workflow/README.zh.md)——调用方拥有的运行与清理。
111
110
  - [Node PTC 运行时](../../ptc-runtime/ptc-runtime-node/README.zh.md)——文件策略、进程限制与部署选择。
112
111
  - [workflow 工具](../tool-workflow/README.zh.md)——面向模型的脚本编排。
113
- - [Ralph 工具](../tool-ralph/README.zh.md)——需显式启用的固定全新 agent 迭代。
112
+ - [Ralph 工具](../../experimental/tool-ralph/README.zh.md)——需显式启用的固定全新 agent 迭代。
114
113
  - [工作流沙箱复用](../../../.agents/notes/implemented/architecture/2026-09-13-workflow-ptc-sandbox-reuse.zh.md)——执行归属与取舍。
115
114
 
116
115
  -----
package/lib/index.js CHANGED
@@ -9,7 +9,7 @@ import { assertNever, snapshotJsonValue } from "@deepseek-ai/dsh-util-values";
9
9
  //#region lib/types/guest-source.js
10
10
  /** Generated by scripts/gen-workflow-guest.ts. Do not edit directly. */
11
11
  /** Self-contained ESM guest transported into the mounted PTC runtime. */
12
- const WORKFLOW_GUEST_SOURCE = "import * as vm from \"node:vm\";\n//#region packages/workflow/workflow-ptc/src/realm.ts\n/**\n* Materializes script VM values as plain JSON and renders thrown values.\n* Getters and proxy traps may execute inside the confined Node process;\n* process isolation and cancellation belong to PTC, not the VM.\n* @module @deepseek-ai/dsh-workflow-ptc/realm\n*/\n/** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */\nvar MaterializeError = class extends Error {\n path;\n reason;\n constructor(path, reason) {\n super(`${path}: ${reason}`);\n this.path = path;\n this.reason = reason;\n this.name = \"MaterializeError\";\n }\n};\n/**\n* Render a thrown value to failure text without ever throwing: prefer the\n* `stack` (host or realm — a realm error's `stack` is a plain string read),\n* fall back to `message`, then `String()`. Reading those properties MAY run\n* script code; if that code itself throws, a fixed label is returned instead.\n* @param error - any value thrown in the host or guest realm.\n* @returns human-readable text for the failure report; prefers the stack.\n*/\nfunction renderThrown(error) {\n try {\n const stack = error?.stack;\n if (typeof stack === \"string\" && stack.length > 0) return stack;\n const message = error?.message;\n if (typeof message === \"string\" && message.length > 0) return message;\n return String(error);\n } catch {\n return \"[unrenderable thrown value]\";\n }\n}\n/**\n* Whether an object's prototype chain represents a plain data object: `null`, or a prototype\n* whose own prototype is `null` (the realm's `Object.prototype` — which we\n* cannot compare by identity across realms). A `Date`/`Map`/class instance\n* has a longer chain and is rejected.\n*/\nfunction hasPlainPrototype(value) {\n const proto = Object.getPrototypeOf(value);\n if (proto === null) return true;\n return Object.getPrototypeOf(proto) === null;\n}\n/**\n* Copy `value` (typically from the vm realm) into plain host JSON data. Root `undefined` is\n* returned unchanged; nested `undefined` and values JSON cannot represent losslessly fail\n* with the offending path. Property accessors run normally, and a throwing read is wrapped\n* with its rendered failure.\n*\n* @param value - the realm value to materialize.\n* @param root - the path label for the root value (error messages).\n* @returns the host-realm copy (plain objects/arrays/scalars only).\n* @throws {@link MaterializeError} for unsupported values, cycles, sparse arrays, exotic\n* prototypes, or property reads that throw.\n*/\nfunction materializeFromRealm(value, root = \"value\") {\n if (value === void 0) return void 0;\n try {\n return materialize(value, root, /* @__PURE__ */ new Set());\n } catch (error) {\n if (error instanceof MaterializeError) throw error;\n throw new MaterializeError(root, `reading the value threw: ${renderThrown(error)}`);\n }\n}\nfunction materialize(value, path, seen) {\n switch (typeof value) {\n case \"boolean\":\n case \"string\": return value;\n case \"number\":\n if (!Number.isFinite(value)) throw new MaterializeError(path, \"non-finite numbers are not JSON data\");\n return value;\n case \"bigint\": throw new MaterializeError(path, \"bigints are not JSON data\");\n case \"function\": throw new MaterializeError(path, \"functions are not plain JSON data\");\n case \"symbol\": throw new MaterializeError(path, \"symbols are not plain JSON data\");\n case \"undefined\": throw new MaterializeError(path, \"undefined is not JSON data\");\n case \"object\": break;\n }\n if (value === null) return null;\n const objectValue = value;\n if (seen.has(objectValue)) throw new MaterializeError(path, \"circular references are not JSON data\");\n seen.add(objectValue);\n try {\n if (Array.isArray(objectValue)) return materializeArray(objectValue, path, seen);\n return materializeObject(objectValue, path, seen);\n } finally {\n seen.delete(objectValue);\n }\n}\nfunction materializeArray(value, path, seen) {\n const out = [];\n for (let index = 0; index < value.length; index++) {\n if (!(index in value)) throw new MaterializeError(`${path}[${index}]`, \"sparse arrays are not JSON data\");\n out.push(materialize(value[index], `${path}[${index}]`, seen));\n }\n for (const key of Object.keys(value)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0 || index >= value.length) throw new MaterializeError(`${path}.${key}`, \"arrays with non-index properties are not JSON data\");\n }\n if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n return out;\n}\nfunction materializeObject(value, path, seen) {\n if (!hasPlainPrototype(value)) throw new MaterializeError(path, \"only plain objects and arrays are JSON data (exotic prototype)\");\n if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n const out = {};\n for (const key of Object.keys(value)) Object.defineProperty(out, key, {\n value: materialize(value[key], `${path}.${key}`, seen),\n enumerable: true,\n writable: true,\n configurable: true\n });\n return out;\n}\n//#endregion\n//#region packages/util/brand/src/index.ts\n/**\n* Apply a compile-time string brand without changing the value.\n* @param value - string admitted by the domain that owns the target brand.\n* @returns the same string with the requested compile-time brand.\n*/\nfunction brandString(value) {\n return value;\n}\n//#endregion\n//#region packages/llm/llm/src/error.ts\n/**\n* Harness error base with a stable machine-routable code and chained cause.\n* Package errors extend it so tool results and replay can retain failure class.\n* @module @deepseek-ai/dsh-llm/error\n*/\n/**\n* Base class for all harness errors. Carries a `code` (stable, programmatic —\n* e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the\n* human-readable `message`, and supports `cause` chaining via the standard\n* `ErrorOptions`. `name` defaults to the subclass constructor name.\n*/\nvar HarnessError = class extends Error {\n /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */\n code;\n constructor(message, code, options) {\n super(message, options);\n this.code = code;\n this.name = new.target.name;\n }\n};\nnew RegExp(String.raw`(?:^|[^a-z0-9])context[\\s_-](?:length|window)[\\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\\s_-]exceeded)(?:$|[^a-z0-9])`, \"i\");\nnew RegExp(String.raw`\\b(?:request|prompt|input|messages?)\\s+(?:is\\s+|are\\s+)?` + String.raw`too\\s+(?:large|long)\\s+for\\s+(?:(?:this|the)\\s+)?` + String.raw`(?:model(?:'s)?\\s+)?context(?:\\s+window)?\\b`, \"i\");\nnew RegExp(String.raw`\\b(?:input|prompt|request|messages?)\\b.{0,40}` + String.raw`\\b(?:exceed(?:s|ed)?|overflows?|is\\s+larger\\s+than)\\b.{0,40}` + String.raw`\\b(?:the\\s+)?(?:model(?:'s)?\\s+)?context(?:\\s+(?:length|window))?\\b`, \"i\");\n//#endregion\n//#region packages/util/values/src/index.ts\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n const rendered = JSON.stringify(value) ?? String(value);\n throw new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor$1(prototype, name) {\n const constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n if (typeof constructor !== \"function\") return false;\n try {\n return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n } catch {\n return false;\n }\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype$1(value) {\n return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor$1(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype$1(value) {\n const prototype = Object.getPrototypeOf(value);\n if (!Array.isArray(prototype) || !hasIntrinsicConstructor$1(prototype, \"Array\")) return false;\n const objectPrototype = Object.getPrototypeOf(prototype);\n return typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype$1(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype$1(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n const keys = Reflect.ownKeys(value);\n if (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n return keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n const ancestors = /* @__PURE__ */ new Set();\n let root;\n const assign = (destination, item) => {\n if (destination === void 0) return;\n if (destination.kind === \"root\") root = item;\n else if (destination.kind === \"array\") destination.target[destination.index] = item;\n else Object.defineProperty(destination.target, destination.key, {\n value: item,\n enumerable: true,\n configurable: true,\n writable: true\n });\n };\n const tasks = [{\n kind: \"visit\",\n value,\n ...detach ? { destination: { kind: \"root\" } } : {}\n }];\n for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n if (task.kind === \"leave\") {\n ancestors.delete(task.source);\n continue;\n }\n if (task.kind === \"array-item\") {\n if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n tasks.push({\n kind: \"visit\",\n value: task.source[task.index],\n ...task.target === void 0 ? {} : { destination: {\n kind: \"array\",\n target: task.target,\n index: task.index\n } }\n });\n continue;\n }\n if (task.kind === \"object-property\") {\n tasks.push({\n kind: \"visit\",\n value: task.source[task.key],\n ...task.target === void 0 ? {} : { destination: {\n kind: \"object\",\n target: task.target,\n key: task.key\n } }\n });\n continue;\n }\n const current = task.value;\n if (current === null) {\n assign(task.destination, null);\n continue;\n }\n if (typeof current === \"boolean\" || typeof current === \"string\") {\n assign(task.destination, current);\n continue;\n }\n if (typeof current === \"number\") {\n if (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n assign(task.destination, current);\n continue;\n }\n if (typeof current !== \"object\") return void 0;\n if (ancestors.has(current)) return void 0;\n if (Array.isArray(current)) {\n if (!hasPlainArrayPrototype$1(current)) return void 0;\n const length = current.length;\n if (Reflect.ownKeys(current).length !== length + 1) return void 0;\n const target = detach ? [] : void 0;\n if (target !== void 0) assign(task.destination, target);\n ancestors.add(current);\n tasks.push({\n kind: \"leave\",\n source: current\n });\n for (let index = length - 1; index >= 0; index--) tasks.push({\n kind: \"array-item\",\n source: current,\n index,\n ...target === void 0 ? {} : { target }\n });\n continue;\n }\n if (!hasPlainObjectPrototype(current)) return void 0;\n const keys = enumerableStringKeys(current);\n if (keys === void 0) return void 0;\n const target = detach ? {} : void 0;\n if (target !== void 0) assign(task.destination, target);\n ancestors.add(current);\n tasks.push({\n kind: \"leave\",\n source: current\n });\n for (let index = keys.length - 1; index >= 0; index--) {\n const key = keys[index];\n /* v8 ignore next -- the loop is bounded by the captured key count. */\n if (key === void 0) return void 0;\n tasks.push({\n kind: \"object-property\",\n source: current,\n key,\n ...target === void 0 ? {} : { target }\n });\n }\n }\n return detach ? root : true;\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n return walkJsonValue(value, false) === true;\n}\n//#endregion\n//#region packages/core/tools/src/json-schema.ts\n/**\n* Enforced JSON Schema subset shared by tool outputs, generated PTC mode\n* types, subagents, and workflows. The subset accepts any JSON root, an\n* annotation-only schema for unconstrained JSON, one scalar `type`, object\n* `properties`/`required`/boolean `additionalProperties`, array `items`,\n* type-correct scalar `enum`/`const`, and exact-one `oneOf`.\n*\n* Unsupported or misplaced keywords reject rather than being accepted without\n* enforcement. Consumers that require an object root apply\n* {@link assertObjectJsonSchema} before accepting input.\n* @module dsh-tools/json-schema\n*/\n/**\n* Thrown when a raw schema falls outside the enforced subset. `violations`\n* lists every offending path instead of stopping at the first author error.\n*/\nvar JsonSchemaError = class extends HarnessError {\n /** Individual schema violations in walk order. */\n violations;\n constructor(violations) {\n super(`unsupported JSON schema: ${violations.join(\"; \")}`, \"UNSUPPORTED_SCHEMA\");\n this.name = \"JsonSchemaError\";\n this.violations = violations;\n }\n};\nconst CONSTRAINT_KEYWORDS = new Set([\n \"type\",\n \"oneOf\",\n \"properties\",\n \"required\",\n \"additionalProperties\",\n \"items\",\n \"enum\",\n \"const\"\n]);\nconst ANNOTATION_KEYWORDS = new Set([\n \"description\",\n \"title\",\n \"default\",\n \"examples\"\n]);\nconst SCHEMA_TYPES = [\n \"object\",\n \"array\",\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n];\n/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */\nfunction hasIntrinsicConstructor(prototype, name) {\n const constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n if (typeof constructor !== \"function\") return false;\n try {\n return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`;\n } catch {\n return false;\n }\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/**\n* Test for a realm-agnostic plain JSON record without accepting arrays or\n* exotic objects.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the value has a plain-object prototype chain.\n*/\nfunction isPlainJsonRecord(value) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n try {\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n } catch {\n return false;\n }\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`. */\nfunction hasPlainArrayPrototype(value) {\n const prototype = Object.getPrototypeOf(value);\n if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n const objectPrototype = Object.getPrototypeOf(prototype);\n return typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Return whether a record contains only own enumerable string keys. */\nfunction hasOnlyEnumerableStringKeys(value) {\n try {\n return Reflect.ownKeys(value).every((key) => typeof key === \"string\" && Object.prototype.propertyIsEnumerable.call(value, key));\n } catch {\n return false;\n }\n}\n/**\n* Test for an ordinary schema record whose keys survive JSON projection.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the record has an intrinsic prototype and only own enumerable string keys.\n*/\nfunction isJsonSchemaRecord(value) {\n return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value);\n}\n/**\n* Test for a dense ordinary array with no JSON-invisible decorations.\n* @param value - candidate array from any JavaScript realm.\n* @returns Whether the array is intrinsic, dense, and undecorated.\n*/\nfunction isPlainJsonArray(value) {\n if (!Array.isArray(value)) return false;\n try {\n if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false;\n for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false;\n return true;\n } catch {\n return false;\n }\n}\n/** Lossless finite JSON number, excluding negative zero. */\nfunction isJsonNumber(value) {\n return typeof value === \"number\" && Number.isFinite(value) && !Object.is(value, -0);\n}\n/** Whether a scalar is valid for one declared schema type. */\nfunction scalarMatches(type, value) {\n switch (type) {\n case \"string\": return typeof value === \"string\";\n case \"number\": return isJsonNumber(value);\n case \"integer\": return isJsonNumber(value) && Number.isInteger(value);\n case \"boolean\": return typeof value === \"boolean\";\n case \"null\": return value === null;\n /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */\n default: return assertNever(type, \"JsonSchemaType\");\n }\n}\n/** Keywords that are invalid beside `oneOf`. */\nconst ONE_OF_SIBLING_KEYWORDS = [\n \"properties\",\n \"required\",\n \"additionalProperties\",\n \"items\",\n \"enum\",\n \"const\"\n];\n/** Validate object-only fields after its property schemas have been visited. */\nfunction checkObjectSchemaTail(node, path, properties, violations) {\n const hasRequired = Object.hasOwn(node, \"required\");\n const required = hasRequired ? node.required : void 0;\n if (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== \"string\")) violations.push(`${path}.required must be an array of strings`);\n else {\n const declared = isJsonSchemaRecord(properties) ? properties : {};\n for (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names \"${key}\" which is not in properties`);\n }\n if (Object.hasOwn(node, \"additionalProperties\") && typeof node.additionalProperties !== \"boolean\") violations.push(`${path}.additionalProperties must be a boolean`);\n}\n/** Collect every violation for one raw schema tree without using the JavaScript call stack. */\nfunction checkSchemaNode(root, rootPath, violations, seen) {\n const tasks = [{\n kind: \"enter\",\n node: root,\n path: rootPath\n }];\n for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n if (task.kind === \"leave\") {\n seen.delete(task.node);\n continue;\n }\n if (task.kind === \"one-of-tail\") {\n for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`);\n continue;\n }\n if (task.kind === \"object-tail\") {\n checkObjectSchemaTail(task.node, task.path, task.properties, violations);\n continue;\n }\n const { node, path } = task;\n if (!isJsonSchemaRecord(node)) {\n violations.push(`${path} must be a schema object`);\n continue;\n }\n if (seen.has(node)) {\n violations.push(`${path} is circular`);\n continue;\n }\n seen.add(node);\n tasks.push({\n kind: \"leave\",\n node\n });\n for (const key of Object.keys(node)) {\n if (CONSTRAINT_KEYWORDS.has(key)) continue;\n if (ANNOTATION_KEYWORDS.has(key)) {\n try {\n if (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`);\n } catch {\n violations.push(`${path}.${key} annotation must be lossless JSON data`);\n }\n continue;\n }\n violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`);\n }\n if (Object.hasOwn(node, \"description\") && typeof node.description !== \"string\") violations.push(`${path}.description must be a string`);\n if (Object.hasOwn(node, \"title\") && typeof node.title !== \"string\") violations.push(`${path}.title must be a string`);\n const hasType = Object.hasOwn(node, \"type\");\n const hasOneOf = Object.hasOwn(node, \"oneOf\");\n if (hasType && hasOneOf) {\n violations.push(`${path} cannot declare both type and oneOf`);\n continue;\n }\n if (!hasType && !hasOneOf) {\n for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`);\n continue;\n }\n if (hasOneOf) {\n const oneOf = node.oneOf;\n tasks.push({\n kind: \"one-of-tail\",\n node,\n path\n });\n if (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`);\n else for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({\n kind: \"enter\",\n node: oneOf[index],\n path: `${path}.oneOf[${index}]`\n });\n continue;\n }\n const type = node.type;\n if (typeof type !== \"string\" || !SCHEMA_TYPES.includes(type)) {\n violations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join(\"/\")}`);\n continue;\n }\n const schemaType = type;\n for (const [key, types] of Object.entries({\n properties: [\"object\"],\n required: [\"object\"],\n additionalProperties: [\"object\"],\n items: [\"array\"],\n enum: [\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n ],\n const: [\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n ]\n })) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type \"${schemaType}\"`);\n switch (schemaType) {\n case \"object\": {\n const properties = Object.hasOwn(node, \"properties\") ? node.properties : void 0;\n tasks.push({\n kind: \"object-tail\",\n node,\n path,\n properties\n });\n if (Object.hasOwn(node, \"properties\")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`);\n else {\n const entries = Object.entries(properties);\n for (let index = entries.length - 1; index >= 0; index--) {\n const entry = entries[index];\n /* v8 ignore next -- the loop is bounded by the captured entry count. */\n if (entry === void 0) continue;\n tasks.push({\n kind: \"enter\",\n node: entry[1],\n path: `${path}.properties.${entry[0]}`\n });\n }\n }\n break;\n }\n case \"array\":\n if (Object.hasOwn(node, \"items\")) tasks.push({\n kind: \"enter\",\n node: node.items,\n path: `${path}.items`\n });\n break;\n case \"string\":\n case \"number\":\n case \"integer\":\n case \"boolean\":\n case \"null\": {\n const hasEnum = Object.hasOwn(node, \"enum\");\n const allowed = hasEnum ? node.enum : void 0;\n const enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry));\n if (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`);\n const hasConst = Object.hasOwn(node, \"const\");\n const declaredConst = hasConst ? node.const : void 0;\n const constValid = scalarMatches(schemaType, declaredConst);\n if (hasConst) {\n if (!constValid) violations.push(`${path}.const must be a ${schemaType} value`);\n else if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`);\n }\n break;\n }\n /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */\n default: assertNever(schemaType, \"JsonSchemaType\");\n }\n }\n}\n/**\n* Assert the enforced subset plus the object-root constraint retained by\n* subagent and workflow structured outputs.\n* @param schema - untrusted caller-supplied schema.\n* @returns Assertion that the schema belongs to the supported subset and has an object root.\n*/\nfunction assertObjectJsonSchema(schema) {\n const violations = [];\n checkSchemaNode(schema, \"schema\", violations, /* @__PURE__ */ new Set());\n if (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, \"type\") || schema.type !== \"object\")) violations.push(\"schema.type must be \\\"object\\\" (structured output is object-rooted)\");\n if (violations.length > 0) throw new JsonSchemaError(violations);\n}\n//#endregion\n//#region packages/workflow/workflow/src/index.ts\n/**\n* Typed error for workflow-seam failures. Extends {@link HarnessError}, so the\n* `code` is machine-routable taxonomy. `fatal` drives the combinator\n* discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd\n* option or a tripped cap must kill the script loudly), and reserve the\n* per-item `null` for child-run failures and ordinary in-stage script errors.\n* Every {@link WorkflowErrorCode} is fatal; the flag exists so the\n* distinction is explicit at every catch site rather than implied.\n*/\nvar WorkflowError = class extends HarnessError {\n /** Whether combinators must propagate this error instead of nulling the item. */\n fatal;\n constructor(message, code, options) {\n super(message, code, options);\n this.name = \"WorkflowError\";\n this.fatal = options?.fatal ?? true;\n }\n};\n/**\n* Whether combinators must re-throw `error` instead of mapping the item to `null`.\n* @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).\n* @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.\n*/\nfunction isFatalWorkflowError(error) {\n return error instanceof WorkflowError && error.fatal;\n}\n//#endregion\n//#region packages/workflow/workflow-ptc/src/runtime.ts\n/**\n* Workflow VM hooks, child callbacks, ordinary concurrency limits and result serialization.\n* PTC owns process confinement and cancellation. Fatal hook and provider failures propagate\n* through combinators; ordinary child failures and stage errors become per-item nulls.\n* @module @deepseek-ai/dsh-workflow-ptc/runtime\n*/\n/** The `agent()` options the script may pass; everything else rejects loud. */\nconst SUPPORTED_AGENT_OPTIONS = new Set([\n \"label\",\n \"phase\",\n \"schema\",\n \"provider\",\n \"model\"\n]);\n/** Deferred Claude Code options we name explicitly in the rejection message. */\nconst DEFERRED_AGENT_OPTIONS = new Set([\n \"effort\",\n \"isolation\",\n \"agentType\"\n]);\n/** Flatten a child's final output blocks to text (the non-schema `agent()` result). */\nfunction outputText(blocks) {\n return blocks.filter((block) => block.type === \"text\").map((block) => block.text).join(\"\");\n}\n/** A short display label derived from the prompt when the script passes none. */\nfunction defaultLabel(prompt) {\n const newline = prompt.indexOf(\"\\n\");\n const line = newline === -1 ? prompt : prompt.slice(0, newline);\n return line.length <= 48 ? line : `${line.slice(0, 47)}…`;\n}\n/**\n* One script execution inside the confined Node process. The host owns\n* cancellation and cleanup of any dropped child work.\n*/\nvar WorkflowExecution = class {\n limits;\n observer;\n children;\n /** 1-based count of `agent()` calls started (the `agentsStarted` result field). */\n started = 0;\n activeSlots = 0;\n slotWaiters = [];\n currentPhase;\n context;\n compiled;\n constructor(meta, body, args, limits, observer, children) {\n this.limits = limits;\n this.observer = observer;\n this.children = children;\n try {\n this.compiled = new vm.Script(`(async () => {\\n${body}\\n})()`, {\n filename: `workflow:${meta.name}`,\n lineOffset: -1\n });\n } catch (error) {\n throw new WorkflowError(`workflow script does not parse: ${String(error)}`, \"SCRIPT_PARSE\", { cause: error });\n }\n this.context = vm.createContext({}, { name: `workflow:${meta.name}` });\n const globals = {\n agent: (prompt, opts) => this.contain(this.agent(prompt, opts)),\n parallel: (thunks) => this.contain(this.parallel(thunks)),\n pipeline: (items, ...stages) => this.contain(this.pipeline(items, stages)),\n phase: (title) => {\n this.phase(title);\n },\n log: (message) => {\n this.log(message);\n },\n args\n };\n for (const [key, value] of Object.entries(globals)) this.context[key] = typeof value === \"function\" ? Object.freeze(value) : value;\n }\n /**\n * Run the script and materialize its JSON return value.\n * @returns A completed or error result; script failures never reject.\n */\n async drive() {\n try {\n const scriptPromise = this.compiled.runInContext(this.context, { timeout: this.limits.syncTimeoutMs });\n const raw = await this.contain(Promise.resolve(scriptPromise));\n return {\n value: raw === void 0 ? null : this.materializeResult(raw),\n stopReason: \"completed\",\n agentsStarted: this.started\n };\n } catch (error) {\n return {\n value: null,\n stopReason: \"error\",\n error: renderThrown(error),\n agentsStarted: this.started\n };\n }\n }\n /**\n * Attach a no-op rejection consumer WITHOUT changing what the caller\n * receives: if the script drops the promise, a host rejection cannot become\n * an unhandled rejection that kills the process; if\n * the script does await it, it still observes the rejection.\n */\n contain(promise) {\n promise.catch(() => {});\n return promise;\n }\n /** Materialize the script's return value; violations become RESULT_UNSERIALIZABLE. */\n materializeResult(raw) {\n try {\n return materializeFromRealm(raw, \"workflow result\");\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n if (!(error instanceof MaterializeError)) throw error;\n throw new WorkflowError(`the workflow's return value is not plain JSON data — ${error.message}. Return only JSON-serializable objects/arrays/scalars.`, \"RESULT_UNSERIALIZABLE\", { cause: error });\n }\n }\n /** Acquire one concurrency slot in FIFO order. */\n acquireSlot() {\n if (this.activeSlots < this.limits.maxConcurrentAgents) {\n this.activeSlots += 1;\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n this.slotWaiters.push(() => {\n this.activeSlots += 1;\n resolve();\n });\n });\n }\n releaseSlot() {\n this.activeSlots -= 1;\n const next = this.slotWaiters.shift();\n if (next) next();\n }\n /** The `agent(prompt, opts)` hook. */\n async agent(rawPrompt, rawOpts) {\n if (typeof rawPrompt !== \"string\" || rawPrompt.length === 0) throw new WorkflowError(\"agent() requires a non-empty prompt string\", \"INVALID_ARGUMENT\");\n const opts = this.readAgentOptions(rawOpts);\n if (this.started >= this.limits.maxTotalAgents) throw new WorkflowError(`this run reached its total agent cap (${this.limits.maxTotalAgents}) — a runaway-loop backstop; raise the applicable maxTotalAgents limit if the scale is intentional`, \"AGENT_CAP\");\n this.started += 1;\n const seq = this.started;\n const label = opts.label ?? defaultLabel(rawPrompt);\n const phase = opts.phase ?? this.currentPhase;\n await this.acquireSlot();\n try {\n let run;\n try {\n run = await this.children.startAgent({\n prompt: rawPrompt,\n ...opts.schema !== void 0 ? { schema: opts.schema } : {},\n ...opts.provider !== void 0 ? { provider: opts.provider } : {},\n ...opts.model !== void 0 ? { model: opts.model } : {}\n });\n } catch (error) {\n throw new WorkflowError(`agent() could not start a child: ${renderThrown(error)}`, \"AGENT_START\", { cause: error });\n }\n const info = {\n seq,\n label,\n ...phase !== void 0 ? { phase } : {},\n childId: brandString(run.id)\n };\n this.observer.agentStart(info);\n try {\n let result;\n try {\n result = await run.result;\n } catch (error) {\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n throw new WorkflowError(`child agent run failed: ${renderThrown(error)}`, \"AGENT_RESULT\", { cause: error });\n }\n if (result.stopReason === \"completed\") {\n if (opts.schema !== void 0) {\n if (result.structured === void 0) {\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n return null;\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"completed\"\n });\n return result.structured;\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"completed\"\n });\n return outputText(result.output);\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n return null;\n } finally {\n await run.dispose();\n }\n } finally {\n this.releaseSlot();\n }\n }\n /** Materialize + validate the `agent()` options bag from the realm. */\n readAgentOptions(rawOpts) {\n if (rawOpts === void 0) return {};\n let opts;\n try {\n opts = materializeFromRealm(rawOpts, \"agent() options\");\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n if (!(error instanceof MaterializeError)) throw error;\n throw new WorkflowError(`agent() options must be plain JSON data — ${error.message}`, \"INVALID_ARGUMENT\", { cause: error });\n }\n if (typeof opts !== \"object\" || opts === null || Array.isArray(opts)) throw new WorkflowError(\"agent() options must be an object\", \"INVALID_ARGUMENT\");\n const record = opts;\n for (const key of Object.keys(record)) {\n if (SUPPORTED_AGENT_OPTIONS.has(key)) continue;\n if (DEFERRED_AGENT_OPTIONS.has(key)) throw new WorkflowError(`agent() option \"${key}\" is deferred and not supported by this engine (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n throw new WorkflowError(`agent() option \"${key}\" is not recognized (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n }\n for (const key of [\n \"label\",\n \"phase\",\n \"provider\",\n \"model\"\n ]) if (record[key] !== void 0 && typeof record[key] !== \"string\") throw new WorkflowError(`agent() option \"${key}\" must be a string`, \"INVALID_ARGUMENT\");\n let schema;\n if (record.schema !== void 0) try {\n assertObjectJsonSchema(record.schema);\n schema = record.schema;\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */\n if (!(error instanceof JsonSchemaError)) throw error;\n throw new WorkflowError(`agent() schema is outside the supported subset — ${error.message}`, \"UNSUPPORTED_SCHEMA\", { cause: error });\n }\n return {\n ...record.label !== void 0 ? { label: record.label } : {},\n ...record.phase !== void 0 ? { phase: record.phase } : {},\n ...record.provider !== void 0 ? { provider: record.provider } : {},\n ...record.model !== void 0 ? { model: record.model } : {},\n ...schema !== void 0 ? { schema } : {}\n };\n }\n /** The `parallel(thunks)` hook: each thunk caught → `null`; fatal errors propagate. */\n async parallel(rawThunks) {\n if (!Array.isArray(rawThunks)) throw new WorkflowError(\"parallel() requires an array of zero-argument functions\", \"INVALID_ARGUMENT\");\n this.assertItemCap(rawThunks.length, \"parallel()\");\n const thunks = rawThunks.map((thunk, index) => {\n if (typeof thunk !== \"function\") throw new WorkflowError(`parallel() item ${index} is not a function`, \"INVALID_ARGUMENT\");\n return thunk;\n });\n return Promise.all(thunks.map(async (thunk) => {\n try {\n return await thunk();\n } catch (error) {\n if (isFatalWorkflowError(error)) throw error;\n return null;\n }\n }));\n }\n /** The `pipeline(items, ...stages)` hook: per-item stage chains, NO cross-stage barrier. */\n async pipeline(rawItems, rawStages) {\n if (!Array.isArray(rawItems)) throw new WorkflowError(\"pipeline() requires an items array\", \"INVALID_ARGUMENT\");\n this.assertItemCap(rawItems.length, \"pipeline()\");\n if (rawStages.length === 0) throw new WorkflowError(\"pipeline() requires at least one stage function\", \"INVALID_ARGUMENT\");\n const stages = rawStages.map((stage, index) => {\n if (typeof stage !== \"function\") throw new WorkflowError(`pipeline() stage ${index} is not a function`, \"INVALID_ARGUMENT\");\n return stage;\n });\n return Promise.all(rawItems.map(async (item, index) => {\n let value = item;\n try {\n for (const stage of stages) value = await stage(value, item, index);\n return value;\n } catch (error) {\n if (isFatalWorkflowError(error)) throw error;\n return null;\n }\n }));\n }\n assertItemCap(length, hook) {\n if (length > this.limits.maxItemsPerCall) throw new WorkflowError(`${hook} received ${length} items — over the per-call cap (${this.limits.maxItemsPerCall}); split the work or raise maxItemsPerCall in the engine config`, \"ITEM_CAP\");\n }\n /** The `phase(title)` hook: sets the current label for subsequent `agent()` calls and notifies observers. */\n phase(title) {\n if (typeof title !== \"string\" || title.length === 0) throw new WorkflowError(\"phase() requires a non-empty title string\", \"INVALID_ARGUMENT\");\n this.currentPhase = title;\n this.observer.phase(title);\n }\n /** The `log(message)` hook: narration to observers. */\n log(message) {\n if (typeof message !== \"string\") throw new WorkflowError(\"log() requires a message string\", \"INVALID_ARGUMENT\");\n this.observer.log(message);\n }\n};\n//#endregion\n//#region packages/workflow/workflow-ptc/src/guest.ts\n/**\n* Run a workflow with one progress batch in flight. Drain progress before child\n* disposal and the terminal result; PTC and the host own cancellation and cleanup.\n* @param host - JSON callbacks owned by this workflow run.\n* @returns The script result after progress delivery; initialization failures reject.\n*/\nasync function runWorkflowGuest(host) {\n const init = await host.begin({});\n let queued = [];\n let inFlight;\n let progressError;\n const flush = () => {\n if (inFlight !== void 0 || queued.length === 0) return;\n const batch = queued;\n queued = [];\n inFlight = host.progress(batch).then(() => {\n inFlight = void 0;\n flush();\n }, (error) => {\n progressError = renderThrown(error);\n queued = [];\n inFlight = void 0;\n });\n };\n const send = (event) => {\n if (progressError !== void 0) return;\n queued.push(event);\n flush();\n };\n const drain = async () => {\n while (inFlight !== void 0) await inFlight;\n };\n const result = await new WorkflowExecution(init.meta, init.body, init.args, init.limits, {\n phase: (title) => {\n send({\n type: \"phase\",\n title\n });\n },\n log: (message) => {\n send({\n type: \"log\",\n message\n });\n },\n agentStart: (info) => {\n send({\n type: \"agent-start\",\n info\n });\n },\n agentEnd: (info) => {\n send({\n type: \"agent-end\",\n info\n });\n }\n }, { async startAgent(request) {\n const { callId, childId } = await host.startChild(request);\n const result = host.childResult({ callId });\n result.catch(() => {});\n return {\n id: childId,\n result,\n async dispose() {\n await drain();\n await host.disposeChild({ callId });\n }\n };\n } }).drive();\n await drain();\n return progressError === void 0 ? result : {\n value: null,\n stopReason: \"error\",\n error: progressError,\n agentsStarted: result.agentsStarted\n };\n}\n//#endregion\nexport { runWorkflowGuest };\n//# sourceURL=dsh-workflow-guest.js\n";
12
+ const WORKFLOW_GUEST_SOURCE = "import * as vm from \"node:vm\";\n//#region packages/workflow/workflow-ptc/src/realm.ts\n/**\n* Materializes script VM values as plain JSON and renders thrown values.\n* Getters and proxy traps may execute inside the confined Node process;\n* process isolation and cancellation belong to PTC, not the VM.\n* @module @deepseek-ai/dsh-workflow-ptc/realm\n*/\n/** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */\nvar MaterializeError = class extends Error {\n path;\n reason;\n constructor(path, reason) {\n super(`${path}: ${reason}`);\n this.path = path;\n this.reason = reason;\n this.name = \"MaterializeError\";\n }\n};\n/**\n* Render a thrown value to failure text without ever throwing: prefer the\n* `stack` (host or realm — a realm error's `stack` is a plain string read),\n* fall back to `message`, then `String()`. Reading those properties MAY run\n* script code; if that code itself throws, a fixed label is returned instead.\n* @param error - any value thrown in the host or guest realm.\n* @returns human-readable text for the failure report; prefers the stack.\n*/\nfunction renderThrown(error) {\n try {\n const stack = error?.stack;\n if (typeof stack === \"string\" && stack.length > 0) return stack;\n const message = error?.message;\n if (typeof message === \"string\" && message.length > 0) return message;\n return String(error);\n } catch {\n return \"[unrenderable thrown value]\";\n }\n}\n/**\n* Whether an object's prototype chain represents a plain data object: `null`, or a prototype\n* whose own prototype is `null` (the realm's `Object.prototype` — which we\n* cannot compare by identity across realms). A `Date`/`Map`/class instance\n* has a longer chain and is rejected.\n*/\nfunction hasPlainPrototype(value) {\n const proto = Object.getPrototypeOf(value);\n if (proto === null) return true;\n return Object.getPrototypeOf(proto) === null;\n}\n/**\n* Copy `value` (typically from the vm realm) into plain host JSON data. Root `undefined` is\n* returned unchanged; nested `undefined` and values JSON cannot represent losslessly fail\n* with the offending path. Property accessors run normally, and a throwing read is wrapped\n* with its rendered failure.\n*\n* @param value - the realm value to materialize.\n* @param root - the path label for the root value (error messages).\n* @returns the host-realm copy (plain objects/arrays/scalars only).\n* @throws {@link MaterializeError} for unsupported values, cycles, sparse arrays, exotic\n* prototypes, or property reads that throw.\n*/\nfunction materializeFromRealm(value, root = \"value\") {\n if (value === void 0) return void 0;\n try {\n return materialize(value, root, /* @__PURE__ */ new Set());\n } catch (error) {\n if (error instanceof MaterializeError) throw error;\n throw new MaterializeError(root, `reading the value threw: ${renderThrown(error)}`);\n }\n}\nfunction materialize(value, path, seen) {\n switch (typeof value) {\n case \"boolean\":\n case \"string\": return value;\n case \"number\":\n if (!Number.isFinite(value)) throw new MaterializeError(path, \"non-finite numbers are not JSON data\");\n return value;\n case \"bigint\": throw new MaterializeError(path, \"bigints are not JSON data\");\n case \"function\": throw new MaterializeError(path, \"functions are not plain JSON data\");\n case \"symbol\": throw new MaterializeError(path, \"symbols are not plain JSON data\");\n case \"undefined\": throw new MaterializeError(path, \"undefined is not JSON data\");\n case \"object\": break;\n }\n if (value === null) return null;\n const objectValue = value;\n if (seen.has(objectValue)) throw new MaterializeError(path, \"circular references are not JSON data\");\n seen.add(objectValue);\n try {\n if (Array.isArray(objectValue)) return materializeArray(objectValue, path, seen);\n return materializeObject(objectValue, path, seen);\n } finally {\n seen.delete(objectValue);\n }\n}\nfunction materializeArray(value, path, seen) {\n const out = [];\n for (let index = 0; index < value.length; index++) {\n if (!(index in value)) throw new MaterializeError(`${path}[${index}]`, \"sparse arrays are not JSON data\");\n out.push(materialize(value[index], `${path}[${index}]`, seen));\n }\n for (const key of Object.keys(value)) {\n const index = Number(key);\n if (!Number.isInteger(index) || index < 0 || index >= value.length) throw new MaterializeError(`${path}.${key}`, \"arrays with non-index properties are not JSON data\");\n }\n if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n return out;\n}\nfunction materializeObject(value, path, seen) {\n if (!hasPlainPrototype(value)) throw new MaterializeError(path, \"only plain objects and arrays are JSON data (exotic prototype)\");\n if (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n const out = {};\n for (const key of Object.keys(value)) Object.defineProperty(out, key, {\n value: materialize(value[key], `${path}.${key}`, seen),\n enumerable: true,\n writable: true,\n configurable: true\n });\n return out;\n}\n//#endregion\n//#region packages/util/brand/src/index.ts\n/**\n* Apply a compile-time string brand without changing the value.\n* @param value - string admitted by the domain that owns the target brand.\n* @returns the same string with the requested compile-time brand.\n*/\nfunction brandString(value) {\n return value;\n}\n//#endregion\n//#region packages/llm/llm/src/error.ts\n/**\n* Harness error base with a stable machine-routable code and chained cause.\n* Package errors extend it so tool results and replay can retain failure class.\n* @module @deepseek-ai/dsh-llm/error\n*/\n/**\n* Base class for all harness errors. Carries a `code` (stable, programmatic —\n* e.g. `NO_ADAPTER`, `INVALID_ARGS`) distinct from the\n* human-readable `message`, and supports `cause` chaining via the standard\n* `ErrorOptions`. `name` defaults to the subclass constructor name.\n*/\nvar HarnessError = class extends Error {\n /** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */\n code;\n constructor(message, code, options) {\n super(message, options);\n this.code = code;\n this.name = new.target.name;\n }\n};\nnew RegExp(String.raw`(?:^|[^a-z0-9])context[\\s_-](?:length|window)[\\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\\s_-]exceeded)(?:$|[^a-z0-9])`, \"i\");\nnew RegExp(String.raw`\\b(?:request|prompt|input|messages?)\\s+(?:is\\s+|are\\s+)?` + String.raw`too\\s+(?:large|long)\\s+for\\s+(?:(?:this|the)\\s+)?` + String.raw`(?:model(?:'s)?\\s+)?context(?:\\s+window)?\\b`, \"i\");\nnew RegExp(String.raw`\\b(?:input|prompt|request|messages?)\\b.{0,40}` + String.raw`\\b(?:exceed(?:s|ed)?|overflows?|is\\s+larger\\s+than)\\b.{0,40}` + String.raw`\\b(?:the\\s+)?(?:model(?:'s)?\\s+)?context(?:\\s+(?:length|window))?\\b`, \"i\");\n//#endregion\n//#region packages/util/values/src/index.ts\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n const rendered = JSON.stringify(value) ?? String(value);\n throw new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor$1(prototype, name) {\n const constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n if (typeof constructor !== \"function\") return false;\n try {\n return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n } catch {\n return false;\n }\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype$1(value) {\n return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor$1(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype$1(value) {\n const prototype = Object.getPrototypeOf(value);\n if (!Array.isArray(prototype) || !hasIntrinsicConstructor$1(prototype, \"Array\")) return false;\n const objectPrototype = Object.getPrototypeOf(prototype);\n return typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype$1(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype$1(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n const keys = Reflect.ownKeys(value);\n if (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n return keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n const ancestors = /* @__PURE__ */ new Set();\n let root;\n const assign = (destination, item) => {\n if (destination === void 0) return;\n if (destination.kind === \"root\") root = item;\n else if (destination.kind === \"array\") destination.target[destination.index] = item;\n else Object.defineProperty(destination.target, destination.key, {\n value: item,\n enumerable: true,\n configurable: true,\n writable: true\n });\n };\n const tasks = [{\n kind: \"visit\",\n value,\n ...detach ? { destination: { kind: \"root\" } } : {}\n }];\n for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n if (task.kind === \"leave\") {\n ancestors.delete(task.source);\n continue;\n }\n if (task.kind === \"array-item\") {\n if (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n tasks.push({\n kind: \"visit\",\n value: task.source[task.index],\n ...task.target === void 0 ? {} : { destination: {\n kind: \"array\",\n target: task.target,\n index: task.index\n } }\n });\n continue;\n }\n if (task.kind === \"object-property\") {\n tasks.push({\n kind: \"visit\",\n value: task.source[task.key],\n ...task.target === void 0 ? {} : { destination: {\n kind: \"object\",\n target: task.target,\n key: task.key\n } }\n });\n continue;\n }\n const current = task.value;\n if (current === null) {\n assign(task.destination, null);\n continue;\n }\n if (typeof current === \"boolean\" || typeof current === \"string\") {\n assign(task.destination, current);\n continue;\n }\n if (typeof current === \"number\") {\n if (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n assign(task.destination, current);\n continue;\n }\n if (typeof current !== \"object\") return void 0;\n if (ancestors.has(current)) return void 0;\n if (Array.isArray(current)) {\n if (!hasPlainArrayPrototype$1(current)) return void 0;\n const length = current.length;\n if (Reflect.ownKeys(current).length !== length + 1) return void 0;\n const target = detach ? [] : void 0;\n if (target !== void 0) assign(task.destination, target);\n ancestors.add(current);\n tasks.push({\n kind: \"leave\",\n source: current\n });\n for (let index = length - 1; index >= 0; index--) tasks.push({\n kind: \"array-item\",\n source: current,\n index,\n ...target === void 0 ? {} : { target }\n });\n continue;\n }\n if (!hasPlainObjectPrototype(current)) return void 0;\n const keys = enumerableStringKeys(current);\n if (keys === void 0) return void 0;\n const target = detach ? {} : void 0;\n if (target !== void 0) assign(task.destination, target);\n ancestors.add(current);\n tasks.push({\n kind: \"leave\",\n source: current\n });\n for (let index = keys.length - 1; index >= 0; index--) {\n const key = keys[index];\n /* v8 ignore next -- the loop is bounded by the captured key count. */\n if (key === void 0) return void 0;\n tasks.push({\n kind: \"object-property\",\n source: current,\n key,\n ...target === void 0 ? {} : { target }\n });\n }\n }\n return detach ? root : true;\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n return walkJsonValue(value, false) === true;\n}\n//#endregion\n//#region packages/core/tools/src/json-schema.ts\n/**\n* Enforced JSON Schema subset shared by tool outputs, generated PTC mode\n* types, subagents, and workflows. The subset accepts any JSON root, an\n* annotation-only schema for unconstrained JSON, one scalar `type`, object\n* `properties`/`required`/boolean `additionalProperties`, array `items`,\n* type-correct scalar `enum`/`const`, and exact-one `oneOf`.\n*\n* Unsupported or misplaced keywords reject rather than being accepted without\n* enforcement. Consumers that require an object root apply\n* {@link assertObjectJsonSchema} before accepting input.\n* @module dsh-tools/json-schema\n*/\n/**\n* Thrown when a raw schema falls outside the enforced subset. `violations`\n* lists every offending path instead of stopping at the first author error.\n*/\nvar JsonSchemaError = class extends HarnessError {\n /** Individual schema violations in walk order. */\n violations;\n constructor(violations) {\n super(`unsupported JSON schema: ${violations.join(\"; \")}`, \"UNSUPPORTED_SCHEMA\");\n this.name = \"JsonSchemaError\";\n this.violations = violations;\n }\n};\nconst CONSTRAINT_KEYWORDS = new Set([\n \"type\",\n \"oneOf\",\n \"properties\",\n \"required\",\n \"additionalProperties\",\n \"items\",\n \"enum\",\n \"const\"\n]);\nconst ANNOTATION_KEYWORDS = new Set([\n \"description\",\n \"title\",\n \"default\",\n \"examples\"\n]);\nconst SCHEMA_TYPES = [\n \"object\",\n \"array\",\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n];\n/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */\nfunction hasIntrinsicConstructor(prototype, name) {\n const constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n if (typeof constructor !== \"function\") return false;\n try {\n return constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`;\n } catch {\n return false;\n }\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n return Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/**\n* Test for a realm-agnostic plain JSON record without accepting arrays or\n* exotic objects.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the value has a plain-object prototype chain.\n*/\nfunction isPlainJsonRecord(value) {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n try {\n const prototype = Object.getPrototypeOf(value);\n return prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n } catch {\n return false;\n }\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`. */\nfunction hasPlainArrayPrototype(value) {\n const prototype = Object.getPrototypeOf(value);\n if (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n const objectPrototype = Object.getPrototypeOf(prototype);\n return typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Return whether a record contains only own enumerable string keys. */\nfunction hasOnlyEnumerableStringKeys(value) {\n try {\n return Reflect.ownKeys(value).every((key) => typeof key === \"string\" && Object.prototype.propertyIsEnumerable.call(value, key));\n } catch {\n return false;\n }\n}\n/**\n* Test for an ordinary schema record whose keys survive JSON projection.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the record has an intrinsic prototype and only own enumerable string keys.\n*/\nfunction isJsonSchemaRecord(value) {\n return isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value);\n}\n/**\n* Test for a dense ordinary array with no JSON-invisible decorations.\n* @param value - candidate array from any JavaScript realm.\n* @returns Whether the array is intrinsic, dense, and undecorated.\n*/\nfunction isPlainJsonArray(value) {\n if (!Array.isArray(value)) return false;\n try {\n if (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false;\n for (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false;\n return true;\n } catch {\n return false;\n }\n}\n/** Lossless finite JSON number, excluding negative zero. */\nfunction isJsonNumber(value) {\n return typeof value === \"number\" && Number.isFinite(value) && !Object.is(value, -0);\n}\n/** Whether a scalar is valid for one declared schema type. */\nfunction scalarMatches(type, value) {\n switch (type) {\n case \"string\": return typeof value === \"string\";\n case \"number\": return isJsonNumber(value);\n case \"integer\": return isJsonNumber(value) && Number.isInteger(value);\n case \"boolean\": return typeof value === \"boolean\";\n case \"null\": return value === null;\n /* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */\n default: return assertNever(type, \"JsonSchemaType\");\n }\n}\n/** Keywords that are invalid beside `oneOf`. */\nconst ONE_OF_SIBLING_KEYWORDS = [\n \"properties\",\n \"required\",\n \"additionalProperties\",\n \"items\",\n \"enum\",\n \"const\"\n];\n/** Validate object-only fields after its property schemas have been visited. */\nfunction checkObjectSchemaTail(node, path, properties, violations) {\n const hasRequired = Object.hasOwn(node, \"required\");\n const required = hasRequired ? node.required : void 0;\n if (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== \"string\")) violations.push(`${path}.required must be an array of strings`);\n else {\n const declared = isJsonSchemaRecord(properties) ? properties : {};\n for (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names \"${key}\" which is not in properties`);\n }\n if (Object.hasOwn(node, \"additionalProperties\") && typeof node.additionalProperties !== \"boolean\") violations.push(`${path}.additionalProperties must be a boolean`);\n}\n/** Collect every violation for one raw schema tree without using the JavaScript call stack. */\nfunction checkSchemaNode(root, rootPath, violations, seen) {\n const tasks = [{\n kind: \"enter\",\n node: root,\n path: rootPath\n }];\n for (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n if (task.kind === \"leave\") {\n seen.delete(task.node);\n continue;\n }\n if (task.kind === \"one-of-tail\") {\n for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`);\n continue;\n }\n if (task.kind === \"object-tail\") {\n checkObjectSchemaTail(task.node, task.path, task.properties, violations);\n continue;\n }\n const { node, path } = task;\n if (!isJsonSchemaRecord(node)) {\n violations.push(`${path} must be a schema object`);\n continue;\n }\n if (seen.has(node)) {\n violations.push(`${path} is circular`);\n continue;\n }\n seen.add(node);\n tasks.push({\n kind: \"leave\",\n node\n });\n for (const key of Object.keys(node)) {\n if (CONSTRAINT_KEYWORDS.has(key)) continue;\n if (ANNOTATION_KEYWORDS.has(key)) {\n try {\n if (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`);\n } catch {\n violations.push(`${path}.${key} annotation must be lossless JSON data`);\n }\n continue;\n }\n violations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`);\n }\n if (Object.hasOwn(node, \"description\") && typeof node.description !== \"string\") violations.push(`${path}.description must be a string`);\n if (Object.hasOwn(node, \"title\") && typeof node.title !== \"string\") violations.push(`${path}.title must be a string`);\n const hasType = Object.hasOwn(node, \"type\");\n const hasOneOf = Object.hasOwn(node, \"oneOf\");\n if (hasType && hasOneOf) {\n violations.push(`${path} cannot declare both type and oneOf`);\n continue;\n }\n if (!hasType && !hasOneOf) {\n for (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`);\n continue;\n }\n if (hasOneOf) {\n const oneOf = node.oneOf;\n tasks.push({\n kind: \"one-of-tail\",\n node,\n path\n });\n if (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`);\n else for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({\n kind: \"enter\",\n node: oneOf[index],\n path: `${path}.oneOf[${index}]`\n });\n continue;\n }\n const type = node.type;\n if (typeof type !== \"string\" || !SCHEMA_TYPES.includes(type)) {\n violations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join(\"/\")}`);\n continue;\n }\n const schemaType = type;\n for (const [key, types] of Object.entries({\n properties: [\"object\"],\n required: [\"object\"],\n additionalProperties: [\"object\"],\n items: [\"array\"],\n enum: [\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n ],\n const: [\n \"string\",\n \"number\",\n \"integer\",\n \"boolean\",\n \"null\"\n ]\n })) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type \"${schemaType}\"`);\n switch (schemaType) {\n case \"object\": {\n const properties = Object.hasOwn(node, \"properties\") ? node.properties : void 0;\n tasks.push({\n kind: \"object-tail\",\n node,\n path,\n properties\n });\n if (Object.hasOwn(node, \"properties\")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`);\n else {\n const entries = Object.entries(properties);\n for (let index = entries.length - 1; index >= 0; index--) {\n const entry = entries[index];\n /* v8 ignore next -- the loop is bounded by the captured entry count. */\n if (entry === void 0) continue;\n tasks.push({\n kind: \"enter\",\n node: entry[1],\n path: `${path}.properties.${entry[0]}`\n });\n }\n }\n break;\n }\n case \"array\":\n if (Object.hasOwn(node, \"items\")) tasks.push({\n kind: \"enter\",\n node: node.items,\n path: `${path}.items`\n });\n break;\n case \"string\":\n case \"number\":\n case \"integer\":\n case \"boolean\":\n case \"null\": {\n const hasEnum = Object.hasOwn(node, \"enum\");\n const allowed = hasEnum ? node.enum : void 0;\n const enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry));\n if (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`);\n const hasConst = Object.hasOwn(node, \"const\");\n const declaredConst = hasConst ? node.const : void 0;\n const constValid = scalarMatches(schemaType, declaredConst);\n if (hasConst) {\n if (!constValid) violations.push(`${path}.const must be a ${schemaType} value`);\n else if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`);\n }\n break;\n }\n /* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */\n default: assertNever(schemaType, \"JsonSchemaType\");\n }\n }\n}\n/**\n* Assert the enforced subset plus the object-root constraint retained by\n* subagent and workflow structured outputs.\n* @param schema - untrusted caller-supplied schema.\n* @returns Assertion that the schema belongs to the supported subset and has an object root.\n*/\nfunction assertObjectJsonSchema(schema) {\n const violations = [];\n checkSchemaNode(schema, \"schema\", violations, /* @__PURE__ */ new Set());\n if (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, \"type\") || schema.type !== \"object\")) violations.push(\"schema.type must be \\\"object\\\" (structured output is object-rooted)\");\n if (violations.length > 0) throw new JsonSchemaError(violations);\n}\n//#endregion\n//#region packages/workflow/workflow/src/index.ts\n/**\n* Typed error for workflow-seam failures. Extends {@link HarnessError}, so the\n* `code` is machine-routable taxonomy. `fatal` drives the combinator\n* discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd\n* option or a tripped cap must kill the script loudly), and reserve the\n* per-item `null` for child-run failures and ordinary in-stage script errors.\n* Every {@link WorkflowErrorCode} is fatal; the flag exists so the\n* distinction is explicit at every catch site rather than implied.\n*/\nvar WorkflowError = class extends HarnessError {\n /** Whether combinators must propagate this error instead of nulling the item. */\n fatal;\n constructor(message, code, options) {\n super(message, code, options);\n this.name = \"WorkflowError\";\n this.fatal = options?.fatal ?? true;\n }\n};\n/**\n* Whether combinators must re-throw `error` instead of mapping the item to `null`.\n* @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).\n* @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.\n*/\nfunction isFatalWorkflowError(error) {\n return error instanceof WorkflowError && error.fatal;\n}\n//#endregion\n//#region packages/workflow/workflow-ptc/src/runtime.ts\n/**\n* Workflow VM hooks, child callbacks, ordinary concurrency limits and result serialization.\n* PTC owns process confinement and cancellation. Fatal hook and provider failures propagate\n* through combinators; ordinary child failures and stage errors become per-item nulls.\n* @module @deepseek-ai/dsh-workflow-ptc/runtime\n*/\n/** The `agent()` options the script may pass; everything else rejects loud. */\nconst SUPPORTED_AGENT_OPTIONS = new Set([\n \"label\",\n \"phase\",\n \"schema\",\n \"provider\",\n \"model\"\n]);\n/** Deferred Claude Code options we name explicitly in the rejection message. */\nconst DEFERRED_AGENT_OPTIONS = new Set([\n \"effort\",\n \"isolation\",\n \"agentType\"\n]);\n/** Flatten a child's final output blocks to text (the non-schema `agent()` result). */\nfunction outputText(blocks) {\n return blocks.filter((block) => block.type === \"text\").map((block) => block.text).join(\"\");\n}\n/** A short display label derived from the prompt when the script passes none. */\nfunction defaultLabel(prompt) {\n const newline = prompt.indexOf(\"\\n\");\n const line = newline === -1 ? prompt : prompt.slice(0, newline);\n return line.length <= 48 ? line : `${line.slice(0, 47)}…`;\n}\n/**\n* One script execution inside the confined Node process. The host owns\n* cancellation and cleanup of any dropped child work.\n*/\nvar WorkflowExecution = class {\n limits;\n observer;\n children;\n /** 1-based count of `agent()` calls started (the `agentsStarted` result field). */\n started = 0;\n activeSlots = 0;\n slotWaiters = [];\n currentPhase;\n context;\n compiled;\n constructor(meta, body, args, limits, observer, children) {\n this.limits = limits;\n this.observer = observer;\n this.children = children;\n try {\n this.compiled = new vm.Script(`(async () => {\\n${body}\\n})()`, {\n filename: `workflow:${meta.name}`,\n lineOffset: -1\n });\n } catch (error) {\n throw new WorkflowError(`workflow script does not parse: ${String(error)}`, \"SCRIPT_PARSE\", { cause: error });\n }\n this.context = vm.createContext({}, { name: `workflow:${meta.name}` });\n const globals = {\n agent: (prompt, opts) => this.contain(this.agent(prompt, opts)),\n parallel: (thunks) => this.contain(this.parallel(thunks)),\n pipeline: (items, ...stages) => this.contain(this.pipeline(items, stages)),\n phase: (title) => {\n this.phase(title);\n },\n log: (message) => {\n this.log(message);\n },\n args\n };\n for (const [key, value] of Object.entries(globals)) this.context[key] = typeof value === \"function\" ? Object.freeze(value) : value;\n }\n /**\n * Run the script and materialize its JSON return value.\n * @returns A completed or error result; script failures never reject.\n */\n async drive() {\n try {\n const scriptPromise = this.compiled.runInContext(this.context, { timeout: this.limits.syncTimeoutMs });\n const raw = await this.contain(Promise.resolve(scriptPromise));\n return {\n value: raw === void 0 ? null : this.materializeResult(raw),\n stopReason: \"completed\",\n agentsStarted: this.started\n };\n } catch (error) {\n return {\n value: null,\n stopReason: \"error\",\n error: renderThrown(error),\n agentsStarted: this.started\n };\n }\n }\n /**\n * Attach a no-op rejection consumer WITHOUT changing what the caller\n * receives: if the script drops the promise, a host rejection cannot become\n * an unhandled rejection that kills the process; if\n * the script does await it, it still observes the rejection.\n */\n contain(promise) {\n promise.catch(() => {});\n return promise;\n }\n /** Materialize the script's return value; violations become RESULT_UNSERIALIZABLE. */\n materializeResult(raw) {\n try {\n return materializeFromRealm(raw, \"workflow result\");\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n if (!(error instanceof MaterializeError)) throw error;\n throw new WorkflowError(`the workflow's return value is not plain JSON data — ${error.message}. Return only JSON-serializable objects/arrays/scalars.`, \"RESULT_UNSERIALIZABLE\", { cause: error });\n }\n }\n /** Acquire one concurrency slot in FIFO order. */\n acquireSlot() {\n if (this.activeSlots < this.limits.maxConcurrentAgents) {\n this.activeSlots += 1;\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n this.slotWaiters.push(() => {\n this.activeSlots += 1;\n resolve();\n });\n });\n }\n releaseSlot() {\n this.activeSlots -= 1;\n const next = this.slotWaiters.shift();\n if (next) next();\n }\n /** The `agent(prompt, opts)` hook. */\n async agent(rawPrompt, rawOpts) {\n if (typeof rawPrompt !== \"string\" || rawPrompt.length === 0) throw new WorkflowError(\"agent() requires a non-empty prompt string\", \"INVALID_ARGUMENT\");\n const opts = this.readAgentOptions(rawOpts);\n if (this.started >= this.limits.maxTotalAgents) throw new WorkflowError(`this run reached its total agent cap (${this.limits.maxTotalAgents}) — a runaway-loop backstop; raise the applicable maxTotalAgents limit if the scale is intentional`, \"AGENT_CAP\");\n this.started += 1;\n const seq = this.started;\n const label = opts.label ?? defaultLabel(rawPrompt);\n const phase = opts.phase ?? this.currentPhase;\n await this.acquireSlot();\n try {\n let run;\n try {\n run = await this.children.startAgent({\n prompt: rawPrompt,\n ...opts.schema !== void 0 ? { schema: opts.schema } : {},\n ...opts.provider !== void 0 ? { provider: opts.provider } : {},\n ...opts.model !== void 0 ? { model: opts.model } : {}\n });\n } catch (error) {\n throw new WorkflowError(`agent() could not start a child: ${renderThrown(error)}`, \"AGENT_START\", { cause: error });\n }\n const info = {\n seq,\n label,\n ...phase !== void 0 ? { phase } : {},\n childId: brandString(run.id)\n };\n this.observer.agentStart(info);\n try {\n let result;\n try {\n result = await run.result;\n } catch (error) {\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n throw new WorkflowError(`child agent run failed: ${renderThrown(error)}`, \"AGENT_RESULT\", { cause: error });\n }\n if (result.stopReason === \"completed\") {\n if (opts.schema !== void 0) {\n if (result.structured === void 0) {\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n return null;\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"completed\"\n });\n return result.structured;\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"completed\"\n });\n return outputText(result.output);\n }\n this.observer.agentEnd({\n ...info,\n outcome: \"failed\"\n });\n return null;\n } finally {\n await run.dispose();\n }\n } finally {\n this.releaseSlot();\n }\n }\n /** Materialize + validate the `agent()` options bag from the realm. */\n readAgentOptions(rawOpts) {\n if (rawOpts === void 0) return {};\n let opts;\n try {\n opts = materializeFromRealm(rawOpts, \"agent() options\");\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n if (!(error instanceof MaterializeError)) throw error;\n throw new WorkflowError(`agent() options must be plain JSON data — ${error.message}`, \"INVALID_ARGUMENT\", { cause: error });\n }\n if (typeof opts !== \"object\" || opts === null || Array.isArray(opts)) throw new WorkflowError(\"agent() options must be an object\", \"INVALID_ARGUMENT\");\n const record = opts;\n for (const key of Object.keys(record)) {\n if (SUPPORTED_AGENT_OPTIONS.has(key)) continue;\n if (DEFERRED_AGENT_OPTIONS.has(key)) throw new WorkflowError(`agent() option \"${key}\" is deferred and not supported by this engine (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n throw new WorkflowError(`agent() option \"${key}\" is not recognized (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n }\n for (const key of [\n \"label\",\n \"phase\",\n \"provider\",\n \"model\"\n ]) if (record[key] !== void 0 && typeof record[key] !== \"string\") throw new WorkflowError(`agent() option \"${key}\" must be a string`, \"INVALID_ARGUMENT\");\n let schema;\n if (record.schema !== void 0) try {\n assertObjectJsonSchema(record.schema);\n schema = record.schema;\n } catch (error) {\n /* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */\n if (!(error instanceof JsonSchemaError)) throw error;\n throw new WorkflowError(`agent() schema is outside the supported subset — ${error.message}`, \"UNSUPPORTED_SCHEMA\", { cause: error });\n }\n return {\n ...record.label !== void 0 ? { label: record.label } : {},\n ...record.phase !== void 0 ? { phase: record.phase } : {},\n ...record.provider !== void 0 ? { provider: record.provider } : {},\n ...record.model !== void 0 ? { model: record.model } : {},\n ...schema !== void 0 ? { schema } : {}\n };\n }\n /** The `parallel(thunks)` hook: each thunk caught → `null`; fatal errors propagate. */\n async parallel(rawThunks) {\n if (!Array.isArray(rawThunks)) throw new WorkflowError(\"parallel() requires an array of zero-argument functions\", \"INVALID_ARGUMENT\");\n this.assertItemCap(rawThunks.length, \"parallel()\");\n const thunks = rawThunks.map((thunk, index) => {\n if (typeof thunk !== \"function\") throw new WorkflowError(`parallel() item ${index} is not a function`, \"INVALID_ARGUMENT\");\n return thunk;\n });\n return Promise.all(thunks.map(async (thunk) => {\n try {\n return await thunk();\n } catch (error) {\n if (isFatalWorkflowError(error)) throw error;\n return null;\n }\n }));\n }\n /** The `pipeline(items, ...stages)` hook: per-item stage chains, NO cross-stage barrier. */\n async pipeline(rawItems, rawStages) {\n if (!Array.isArray(rawItems)) throw new WorkflowError(\"pipeline() requires an items array\", \"INVALID_ARGUMENT\");\n this.assertItemCap(rawItems.length, \"pipeline()\");\n if (rawStages.length === 0) throw new WorkflowError(\"pipeline() requires at least one stage function\", \"INVALID_ARGUMENT\");\n const stages = rawStages.map((stage, index) => {\n if (typeof stage !== \"function\") throw new WorkflowError(`pipeline() stage ${index} is not a function`, \"INVALID_ARGUMENT\");\n return stage;\n });\n return Promise.all(rawItems.map(async (item, index) => {\n let value = item;\n try {\n for (const stage of stages) value = await stage(value, item, index);\n return value;\n } catch (error) {\n if (isFatalWorkflowError(error)) throw error;\n return null;\n }\n }));\n }\n assertItemCap(length, hook) {\n if (length > this.limits.maxItemsPerCall) throw new WorkflowError(`${hook} received ${length} items — over the per-call cap (${this.limits.maxItemsPerCall}); split the work or raise maxItemsPerCall in the engine config`, \"ITEM_CAP\");\n }\n /** The `phase(title)` hook: sets the current label for subsequent `agent()` calls and notifies observers. */\n phase(title) {\n if (typeof title !== \"string\" || title.length === 0) throw new WorkflowError(\"phase() requires a non-empty title string\", \"INVALID_ARGUMENT\");\n this.currentPhase = title;\n this.observer.phase(title);\n }\n /** The `log(message)` hook: narration to observers. */\n log(message) {\n if (typeof message !== \"string\") throw new WorkflowError(\"log() requires a message string\", \"INVALID_ARGUMENT\");\n this.observer.log(message);\n }\n};\n//#endregion\n//#region packages/workflow/workflow-ptc/src/guest.ts\n/**\n* Run a workflow with one progress batch in flight. Drain progress before child\n* disposal and the terminal result; PTC and the host own cancellation and cleanup.\n* @param host - JSON callbacks owned by this workflow run.\n* @returns The script result after progress delivery; initialization failures reject.\n*/\nasync function runWorkflowGuest(host) {\n const init = await host.begin({});\n let queued = [];\n let inFlight;\n let progressError;\n const flush = () => {\n if (inFlight !== void 0 || queued.length === 0) return;\n const batch = queued;\n queued = [];\n inFlight = host.progress(batch).then(() => {\n inFlight = void 0;\n flush();\n }, (error) => {\n progressError = renderThrown(error);\n queued = [];\n inFlight = void 0;\n });\n };\n const send = (event) => {\n if (progressError !== void 0) return;\n queued.push(event);\n flush();\n };\n const drain = async () => {\n while (inFlight !== void 0) await inFlight;\n };\n const result = await new WorkflowExecution(init.meta, init.body, init.args, init.limits, {\n phase: (title) => {\n send({\n type: \"phase\",\n title\n });\n },\n log: (message) => {\n send({\n type: \"log\",\n message\n });\n },\n agentStart: (info) => {\n send({\n type: \"agent-start\",\n info\n });\n },\n agentEnd: (info) => {\n send({\n type: \"agent-end\",\n info\n });\n }\n }, { async startAgent(request) {\n const { callId, childId } = await host.startChild(request);\n const result = host.childResult({ callId });\n result.catch(() => {});\n return {\n id: childId,\n result,\n async dispose() {\n await drain();\n await host.disposeChild({ callId });\n }\n };\n } }).drive();\n await drain();\n return progressError === void 0 ? result : {\n value: null,\n stopReason: \"error\",\n error: progressError,\n agentsStarted: result.agentsStarted\n };\n}\n//#endregion\nexport { runWorkflowGuest };\n//# sourceURL=dsh-workflow-guest.js\n";
13
13
  //#endregion
14
14
  //#region lib/types/realm.js
15
15
  /**
@@ -246,6 +246,7 @@ var PtcWorkflowRun = class {
246
246
  cancelReason;
247
247
  disposed;
248
248
  externalAbort;
249
+ cwd;
249
250
  constructor(ctx, subagents, runtime, id, meta, parent, init, provider, policy, observer, signal) {
250
251
  this.ctx = ctx;
251
252
  this.subagents = subagents;
@@ -263,6 +264,7 @@ var PtcWorkflowRun = class {
263
264
  };
264
265
  if (signal?.aborted) this.externalAbort();
265
266
  else signal?.addEventListener("abort", this.externalAbort, { once: true });
267
+ this.cwd = ctx.workingDirectory.ensure(parent, this.controller.signal);
266
268
  this.result = Promise.resolve().then(() => this.drive());
267
269
  }
268
270
  /**
@@ -325,18 +327,24 @@ var PtcWorkflowRun = class {
325
327
  async startChild(request) {
326
328
  this.requireActive();
327
329
  const callId = ++this.started;
328
- const run = await this.subagents.start(this.provider, {
329
- prompt: [{
330
- type: "text",
331
- text: request.prompt
332
- }],
333
- parent: this.parent,
330
+ const run = await this.subagents.startActivation({
331
+ provider: this.provider,
332
+ label: `${this.meta.name} child ${callId}`,
333
+ delivery: "caller",
334
334
  signal: this.controller.signal,
335
- ...request.schema === void 0 ? {} : { outputSchema: request.schema },
336
- ...request.provider === void 0 && request.model === void 0 ? {} : { agentOptions: {
337
- ...request.provider === void 0 ? {} : { provider: request.provider },
338
- ...request.model === void 0 ? {} : { model: request.model }
339
- } }
335
+ request: {
336
+ cwd: await this.cwd,
337
+ prompt: [{
338
+ type: "text",
339
+ text: request.prompt
340
+ }],
341
+ parent: this.parent,
342
+ ...request.schema === void 0 ? {} : { outputSchema: request.schema },
343
+ ...request.provider === void 0 && request.model === void 0 ? {} : { agentOptions: {
344
+ ...request.provider === void 0 ? {} : { provider: request.provider },
345
+ ...request.model === void 0 ? {} : { model: request.model }
346
+ } }
347
+ }
340
348
  });
341
349
  const record = {
342
350
  callId,
@@ -349,7 +357,7 @@ var PtcWorkflowRun = class {
349
357
  }
350
358
  return {
351
359
  callId,
352
- childId: run.id
360
+ childId: run.childId
353
361
  };
354
362
  }
355
363
  async childResult(record) {
@@ -414,13 +422,15 @@ var PtcWorkflowRun = class {
414
422
  async drive() {
415
423
  let result;
416
424
  try {
425
+ const cwd = await this.cwd;
426
+ this.requireActive();
417
427
  const outcome = await this.runtime.run(this.runtime.resolve({
418
428
  program: PROGRAM,
419
429
  bindings: [{
420
430
  global: "workflowHost",
421
431
  functions: this.bindings()
422
432
  }],
423
- cwd: this.policy.workspaceRoot,
433
+ cwd,
424
434
  sandboxPolicy: this.policy,
425
435
  timeoutMs: null,
426
436
  signal: this.controller.signal
@@ -580,7 +590,8 @@ var PtcWorkflowEngine = class extends WorkflowEngine {
580
590
  static inject = [
581
591
  "subagents",
582
592
  "ptcRuntime",
583
- "sandboxPolicy"
593
+ "sandboxPolicy",
594
+ "workingDirectory"
584
595
  ];
585
596
  static Config = z.object({
586
597
  provider: z.string().default("spawn"),
@@ -1,4 +1,4 @@
1
1
  /** Generated by scripts/gen-workflow-guest.ts. Do not edit directly. */
2
2
  /** Self-contained ESM guest transported into the mounted PTC runtime. */
3
- export declare const WORKFLOW_GUEST_SOURCE = "import * as vm from \"node:vm\";\n//#region packages/workflow/workflow-ptc/src/realm.ts\n/**\n* Materializes script VM values as plain JSON and renders thrown values.\n* Getters and proxy traps may execute inside the confined Node process;\n* process isolation and cancellation belong to PTC, not the VM.\n* @module @deepseek-ai/dsh-workflow-ptc/realm\n*/\n/** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */\nvar MaterializeError = class extends Error {\n\tpath;\n\treason;\n\tconstructor(path, reason) {\n\t\tsuper(`${path}: ${reason}`);\n\t\tthis.path = path;\n\t\tthis.reason = reason;\n\t\tthis.name = \"MaterializeError\";\n\t}\n};\n/**\n* Render a thrown value to failure text without ever throwing: prefer the\n* `stack` (host or realm \u2014 a realm error's `stack` is a plain string read),\n* fall back to `message`, then `String()`. Reading those properties MAY run\n* script code; if that code itself throws, a fixed label is returned instead.\n* @param error - any value thrown in the host or guest realm.\n* @returns human-readable text for the failure report; prefers the stack.\n*/\nfunction renderThrown(error) {\n\ttry {\n\t\tconst stack = error?.stack;\n\t\tif (typeof stack === \"string\" && stack.length > 0) return stack;\n\t\tconst message = error?.message;\n\t\tif (typeof message === \"string\" && message.length > 0) return message;\n\t\treturn String(error);\n\t} catch {\n\t\treturn \"[unrenderable thrown value]\";\n\t}\n}\n/**\n* Whether an object's prototype chain represents a plain data object: `null`, or a prototype\n* whose own prototype is `null` (the realm's `Object.prototype` \u2014 which we\n* cannot compare by identity across realms). A `Date`/`Map`/class instance\n* has a longer chain and is rejected.\n*/\nfunction hasPlainPrototype(value) {\n\tconst proto = Object.getPrototypeOf(value);\n\tif (proto === null) return true;\n\treturn Object.getPrototypeOf(proto) === null;\n}\n/**\n* Copy `value` (typically from the vm realm) into plain host JSON data. Root `undefined` is\n* returned unchanged; nested `undefined` and values JSON cannot represent losslessly fail\n* with the offending path. Property accessors run normally, and a throwing read is wrapped\n* with its rendered failure.\n*\n* @param value - the realm value to materialize.\n* @param root - the path label for the root value (error messages).\n* @returns the host-realm copy (plain objects/arrays/scalars only).\n* @throws {@link MaterializeError} for unsupported values, cycles, sparse arrays, exotic\n* prototypes, or property reads that throw.\n*/\nfunction materializeFromRealm(value, root = \"value\") {\n\tif (value === void 0) return void 0;\n\ttry {\n\t\treturn materialize(value, root, /* @__PURE__ */ new Set());\n\t} catch (error) {\n\t\tif (error instanceof MaterializeError) throw error;\n\t\tthrow new MaterializeError(root, `reading the value threw: ${renderThrown(error)}`);\n\t}\n}\nfunction materialize(value, path, seen) {\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\tcase \"string\": return value;\n\t\tcase \"number\":\n\t\t\tif (!Number.isFinite(value)) throw new MaterializeError(path, \"non-finite numbers are not JSON data\");\n\t\t\treturn value;\n\t\tcase \"bigint\": throw new MaterializeError(path, \"bigints are not JSON data\");\n\t\tcase \"function\": throw new MaterializeError(path, \"functions are not plain JSON data\");\n\t\tcase \"symbol\": throw new MaterializeError(path, \"symbols are not plain JSON data\");\n\t\tcase \"undefined\": throw new MaterializeError(path, \"undefined is not JSON data\");\n\t\tcase \"object\": break;\n\t}\n\tif (value === null) return null;\n\tconst objectValue = value;\n\tif (seen.has(objectValue)) throw new MaterializeError(path, \"circular references are not JSON data\");\n\tseen.add(objectValue);\n\ttry {\n\t\tif (Array.isArray(objectValue)) return materializeArray(objectValue, path, seen);\n\t\treturn materializeObject(objectValue, path, seen);\n\t} finally {\n\t\tseen.delete(objectValue);\n\t}\n}\nfunction materializeArray(value, path, seen) {\n\tconst out = [];\n\tfor (let index = 0; index < value.length; index++) {\n\t\tif (!(index in value)) throw new MaterializeError(`${path}[${index}]`, \"sparse arrays are not JSON data\");\n\t\tout.push(materialize(value[index], `${path}[${index}]`, seen));\n\t}\n\tfor (const key of Object.keys(value)) {\n\t\tconst index = Number(key);\n\t\tif (!Number.isInteger(index) || index < 0 || index >= value.length) throw new MaterializeError(`${path}.${key}`, \"arrays with non-index properties are not JSON data\");\n\t}\n\tif (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n\treturn out;\n}\nfunction materializeObject(value, path, seen) {\n\tif (!hasPlainPrototype(value)) throw new MaterializeError(path, \"only plain objects and arrays are JSON data (exotic prototype)\");\n\tif (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n\tconst out = {};\n\tfor (const key of Object.keys(value)) Object.defineProperty(out, key, {\n\t\tvalue: materialize(value[key], `${path}.${key}`, seen),\n\t\tenumerable: true,\n\t\twritable: true,\n\t\tconfigurable: true\n\t});\n\treturn out;\n}\n//#endregion\n//#region packages/util/brand/src/index.ts\n/**\n* Apply a compile-time string brand without changing the value.\n* @param value - string admitted by the domain that owns the target brand.\n* @returns the same string with the requested compile-time brand.\n*/\nfunction brandString(value) {\n\treturn value;\n}\n//#endregion\n//#region packages/llm/llm/src/error.ts\n/**\n* Harness error base with a stable machine-routable code and chained cause.\n* Package errors extend it so tool results and replay can retain failure class.\n* @module @deepseek-ai/dsh-llm/error\n*/\n/**\n* Base class for all harness errors. Carries a `code` (stable, programmatic \u2014\n* e.g. `NO_ADAPTER`, `INVALID_ARGS`, `INVARIANT`) distinct from the\n* human-readable `message`, and supports `cause` chaining via the standard\n* `ErrorOptions`. `name` defaults to the subclass constructor name.\n*/\nvar HarnessError = class extends Error {\n\t/** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */\n\tcode;\n\tconstructor(message, code, options) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t\tthis.name = new.target.name;\n\t}\n};\nnew RegExp(String.raw`(?:^|[^a-z0-9])context[\\s_-](?:length|window)[\\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\\s_-]exceeded)(?:$|[^a-z0-9])`, \"i\");\nnew RegExp(String.raw`\\b(?:request|prompt|input|messages?)\\s+(?:is\\s+|are\\s+)?` + String.raw`too\\s+(?:large|long)\\s+for\\s+(?:(?:this|the)\\s+)?` + String.raw`(?:model(?:'s)?\\s+)?context(?:\\s+window)?\\b`, \"i\");\nnew RegExp(String.raw`\\b(?:input|prompt|request|messages?)\\b.{0,40}` + String.raw`\\b(?:exceed(?:s|ed)?|overflows?|is\\s+larger\\s+than)\\b.{0,40}` + String.raw`\\b(?:the\\s+)?(?:model(?:'s)?\\s+)?context(?:\\s+(?:length|window))?\\b`, \"i\");\n//#endregion\n//#region packages/util/values/src/index.ts\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n\tconst rendered = JSON.stringify(value) ?? String(value);\n\tthrow new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor$1(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype$1(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor$1(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype$1(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor$1(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype$1(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype$1(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n\tconst keys = Reflect.ownKeys(value);\n\tif (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n\treturn keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n\tconst ancestors = /* @__PURE__ */ new Set();\n\tlet root;\n\tconst assign = (destination, item) => {\n\t\tif (destination === void 0) return;\n\t\tif (destination.kind === \"root\") root = item;\n\t\telse if (destination.kind === \"array\") destination.target[destination.index] = item;\n\t\telse Object.defineProperty(destination.target, destination.key, {\n\t\t\tvalue: item,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\twritable: true\n\t\t});\n\t};\n\tconst tasks = [{\n\t\tkind: \"visit\",\n\t\tvalue,\n\t\t...detach ? { destination: { kind: \"root\" } } : {}\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tancestors.delete(task.source);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"array-item\") {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.index],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"array\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tindex: task.index\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-property\") {\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.key],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"object\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tkey: task.key\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = task.value;\n\t\tif (current === null) {\n\t\t\tassign(task.destination, null);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"boolean\" || typeof current === \"string\") {\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"number\") {\n\t\t\tif (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current !== \"object\") return void 0;\n\t\tif (ancestors.has(current)) return void 0;\n\t\tif (Array.isArray(current)) {\n\t\t\tif (!hasPlainArrayPrototype$1(current)) return void 0;\n\t\t\tconst length = current.length;\n\t\t\tif (Reflect.ownKeys(current).length !== length + 1) return void 0;\n\t\t\tconst target = detach ? [] : void 0;\n\t\t\tif (target !== void 0) assign(task.destination, target);\n\t\t\tancestors.add(current);\n\t\t\ttasks.push({\n\t\t\t\tkind: \"leave\",\n\t\t\t\tsource: current\n\t\t\t});\n\t\t\tfor (let index = length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"array-item\",\n\t\t\t\tsource: current,\n\t\t\t\tindex,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasPlainObjectPrototype(current)) return void 0;\n\t\tconst keys = enumerableStringKeys(current);\n\t\tif (keys === void 0) return void 0;\n\t\tconst target = detach ? {} : void 0;\n\t\tif (target !== void 0) assign(task.destination, target);\n\t\tancestors.add(current);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tsource: current\n\t\t});\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"object-property\",\n\t\t\t\tsource: current,\n\t\t\t\tkey,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t}\n\t}\n\treturn detach ? root : true;\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n\treturn walkJsonValue(value, false) === true;\n}\n//#endregion\n//#region packages/core/tools/src/json-schema.ts\n/**\n* Enforced JSON Schema subset shared by tool outputs, generated PTC mode\n* types, subagents, and workflows. The subset accepts any JSON root, an\n* annotation-only schema for unconstrained JSON, one scalar `type`, object\n* `properties`/`required`/boolean `additionalProperties`, array `items`,\n* type-correct scalar `enum`/`const`, and exact-one `oneOf`.\n*\n* Unsupported or misplaced keywords reject rather than being accepted without\n* enforcement. Consumers that require an object root apply\n* {@link assertObjectJsonSchema} before accepting input.\n* @module dsh-tools/json-schema\n*/\n/**\n* Thrown when a raw schema falls outside the enforced subset. `violations`\n* lists every offending path instead of stopping at the first author error.\n*/\nvar JsonSchemaError = class extends HarnessError {\n\t/** Individual schema violations in walk order. */\n\tviolations;\n\tconstructor(violations) {\n\t\tsuper(`unsupported JSON schema: ${violations.join(\"; \")}`, \"UNSUPPORTED_SCHEMA\");\n\t\tthis.name = \"JsonSchemaError\";\n\t\tthis.violations = violations;\n\t}\n};\nconst CONSTRAINT_KEYWORDS = new Set([\n\t\"type\",\n\t\"oneOf\",\n\t\"properties\",\n\t\"required\",\n\t\"additionalProperties\",\n\t\"items\",\n\t\"enum\",\n\t\"const\"\n]);\nconst ANNOTATION_KEYWORDS = new Set([\n\t\"description\",\n\t\"title\",\n\t\"default\",\n\t\"examples\"\n]);\nconst SCHEMA_TYPES = [\n\t\"object\",\n\t\"array\",\n\t\"string\",\n\t\"number\",\n\t\"integer\",\n\t\"boolean\",\n\t\"null\"\n];\n/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */\nfunction hasIntrinsicConstructor(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`;\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/**\n* Test for a realm-agnostic plain JSON record without accepting arrays or\n* exotic objects.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the value has a plain-object prototype chain.\n*/\nfunction isPlainJsonRecord(value) {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\ttry {\n\t\tconst prototype = Object.getPrototypeOf(value);\n\t\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`. */\nfunction hasPlainArrayPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Return whether a record contains only own enumerable string keys. */\nfunction hasOnlyEnumerableStringKeys(value) {\n\ttry {\n\t\treturn Reflect.ownKeys(value).every((key) => typeof key === \"string\" && Object.prototype.propertyIsEnumerable.call(value, key));\n\t} catch {\n\t\treturn false;\n\t}\n}\n/**\n* Test for an ordinary schema record whose keys survive JSON projection.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the record has an intrinsic prototype and only own enumerable string keys.\n*/\nfunction isJsonSchemaRecord(value) {\n\treturn isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value);\n}\n/**\n* Test for a dense ordinary array with no JSON-invisible decorations.\n* @param value - candidate array from any JavaScript realm.\n* @returns Whether the array is intrinsic, dense, and undecorated.\n*/\nfunction isPlainJsonArray(value) {\n\tif (!Array.isArray(value)) return false;\n\ttry {\n\t\tif (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false;\n\t\tfor (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false;\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Lossless finite JSON number, excluding negative zero. */\nfunction isJsonNumber(value) {\n\treturn typeof value === \"number\" && Number.isFinite(value) && !Object.is(value, -0);\n}\n/** Whether a scalar is valid for one declared schema type. */\nfunction scalarMatches(type, value) {\n\tswitch (type) {\n\t\tcase \"string\": return typeof value === \"string\";\n\t\tcase \"number\": return isJsonNumber(value);\n\t\tcase \"integer\": return isJsonNumber(value) && Number.isInteger(value);\n\t\tcase \"boolean\": return typeof value === \"boolean\";\n\t\tcase \"null\": return value === null;\n\t\t/* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */\n\t\tdefault: return assertNever(type, \"JsonSchemaType\");\n\t}\n}\n/** Keywords that are invalid beside `oneOf`. */\nconst ONE_OF_SIBLING_KEYWORDS = [\n\t\"properties\",\n\t\"required\",\n\t\"additionalProperties\",\n\t\"items\",\n\t\"enum\",\n\t\"const\"\n];\n/** Validate object-only fields after its property schemas have been visited. */\nfunction checkObjectSchemaTail(node, path, properties, violations) {\n\tconst hasRequired = Object.hasOwn(node, \"required\");\n\tconst required = hasRequired ? node.required : void 0;\n\tif (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== \"string\")) violations.push(`${path}.required must be an array of strings`);\n\telse {\n\t\tconst declared = isJsonSchemaRecord(properties) ? properties : {};\n\t\tfor (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names \"${key}\" which is not in properties`);\n\t}\n\tif (Object.hasOwn(node, \"additionalProperties\") && typeof node.additionalProperties !== \"boolean\") violations.push(`${path}.additionalProperties must be a boolean`);\n}\n/** Collect every violation for one raw schema tree without using the JavaScript call stack. */\nfunction checkSchemaNode(root, rootPath, violations, seen) {\n\tconst tasks = [{\n\t\tkind: \"enter\",\n\t\tnode: root,\n\t\tpath: rootPath\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tseen.delete(task.node);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"one-of-tail\") {\n\t\t\tfor (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-tail\") {\n\t\t\tcheckObjectSchemaTail(task.node, task.path, task.properties, violations);\n\t\t\tcontinue;\n\t\t}\n\t\tconst { node, path } = task;\n\t\tif (!isJsonSchemaRecord(node)) {\n\t\t\tviolations.push(`${path} must be a schema object`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(node)) {\n\t\t\tviolations.push(`${path} is circular`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(node);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tnode\n\t\t});\n\t\tfor (const key of Object.keys(node)) {\n\t\t\tif (CONSTRAINT_KEYWORDS.has(key)) continue;\n\t\t\tif (ANNOTATION_KEYWORDS.has(key)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`);\n\t\t\t\t} catch {\n\t\t\t\t\tviolations.push(`${path}.${key} annotation must be lossless JSON data`);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tviolations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`);\n\t\t}\n\t\tif (Object.hasOwn(node, \"description\") && typeof node.description !== \"string\") violations.push(`${path}.description must be a string`);\n\t\tif (Object.hasOwn(node, \"title\") && typeof node.title !== \"string\") violations.push(`${path}.title must be a string`);\n\t\tconst hasType = Object.hasOwn(node, \"type\");\n\t\tconst hasOneOf = Object.hasOwn(node, \"oneOf\");\n\t\tif (hasType && hasOneOf) {\n\t\t\tviolations.push(`${path} cannot declare both type and oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasType && !hasOneOf) {\n\t\t\tfor (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (hasOneOf) {\n\t\t\tconst oneOf = node.oneOf;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"one-of-tail\",\n\t\t\t\tnode,\n\t\t\t\tpath\n\t\t\t});\n\t\t\tif (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`);\n\t\t\telse for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"enter\",\n\t\t\t\tnode: oneOf[index],\n\t\t\t\tpath: `${path}.oneOf[${index}]`\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = node.type;\n\t\tif (typeof type !== \"string\" || !SCHEMA_TYPES.includes(type)) {\n\t\t\tviolations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join(\"/\")}`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst schemaType = type;\n\t\tfor (const [key, types] of Object.entries({\n\t\t\tproperties: [\"object\"],\n\t\t\trequired: [\"object\"],\n\t\t\tadditionalProperties: [\"object\"],\n\t\t\titems: [\"array\"],\n\t\t\tenum: [\n\t\t\t\t\"string\",\n\t\t\t\t\"number\",\n\t\t\t\t\"integer\",\n\t\t\t\t\"boolean\",\n\t\t\t\t\"null\"\n\t\t\t],\n\t\t\tconst: [\n\t\t\t\t\"string\",\n\t\t\t\t\"number\",\n\t\t\t\t\"integer\",\n\t\t\t\t\"boolean\",\n\t\t\t\t\"null\"\n\t\t\t]\n\t\t})) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type \"${schemaType}\"`);\n\t\tswitch (schemaType) {\n\t\t\tcase \"object\": {\n\t\t\t\tconst properties = Object.hasOwn(node, \"properties\") ? node.properties : void 0;\n\t\t\t\ttasks.push({\n\t\t\t\t\tkind: \"object-tail\",\n\t\t\t\t\tnode,\n\t\t\t\t\tpath,\n\t\t\t\t\tproperties\n\t\t\t\t});\n\t\t\t\tif (Object.hasOwn(node, \"properties\")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`);\n\t\t\t\telse {\n\t\t\t\t\tconst entries = Object.entries(properties);\n\t\t\t\t\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\t\t\t\t\tconst entry = entries[index];\n\t\t\t\t\t\t/* v8 ignore next -- the loop is bounded by the captured entry count. */\n\t\t\t\t\t\tif (entry === void 0) continue;\n\t\t\t\t\t\ttasks.push({\n\t\t\t\t\t\t\tkind: \"enter\",\n\t\t\t\t\t\t\tnode: entry[1],\n\t\t\t\t\t\t\tpath: `${path}.properties.${entry[0]}`\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"array\":\n\t\t\t\tif (Object.hasOwn(node, \"items\")) tasks.push({\n\t\t\t\t\tkind: \"enter\",\n\t\t\t\t\tnode: node.items,\n\t\t\t\t\tpath: `${path}.items`\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"string\":\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\tcase \"boolean\":\n\t\t\tcase \"null\": {\n\t\t\t\tconst hasEnum = Object.hasOwn(node, \"enum\");\n\t\t\t\tconst allowed = hasEnum ? node.enum : void 0;\n\t\t\t\tconst enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry));\n\t\t\t\tif (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`);\n\t\t\t\tconst hasConst = Object.hasOwn(node, \"const\");\n\t\t\t\tconst declaredConst = hasConst ? node.const : void 0;\n\t\t\t\tconst constValid = scalarMatches(schemaType, declaredConst);\n\t\t\t\tif (hasConst) {\n\t\t\t\t\tif (!constValid) violations.push(`${path}.const must be a ${schemaType} value`);\n\t\t\t\t\telse if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */\n\t\t\tdefault: assertNever(schemaType, \"JsonSchemaType\");\n\t\t}\n\t}\n}\n/**\n* Assert the enforced subset plus the object-root constraint retained by\n* subagent and workflow structured outputs.\n* @param schema - untrusted caller-supplied schema.\n* @returns Assertion that the schema belongs to the supported subset and has an object root.\n*/\nfunction assertObjectJsonSchema(schema) {\n\tconst violations = [];\n\tcheckSchemaNode(schema, \"schema\", violations, /* @__PURE__ */ new Set());\n\tif (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, \"type\") || schema.type !== \"object\")) violations.push(\"schema.type must be \\\"object\\\" (structured output is object-rooted)\");\n\tif (violations.length > 0) throw new JsonSchemaError(violations);\n}\n//#endregion\n//#region packages/workflow/workflow/src/index.ts\n/**\n* Typed error for workflow-seam failures. Extends {@link HarnessError}, so the\n* `code` is machine-routable taxonomy. `fatal` drives the combinator\n* discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd\n* option or a tripped cap must kill the script loudly), and reserve the\n* per-item `null` for child-run failures and ordinary in-stage script errors.\n* Every {@link WorkflowErrorCode} is fatal; the flag exists so the\n* distinction is explicit at every catch site rather than implied.\n*/\nvar WorkflowError = class extends HarnessError {\n\t/** Whether combinators must propagate this error instead of nulling the item. */\n\tfatal;\n\tconstructor(message, code, options) {\n\t\tsuper(message, code, options);\n\t\tthis.name = \"WorkflowError\";\n\t\tthis.fatal = options?.fatal ?? true;\n\t}\n};\n/**\n* Whether combinators must re-throw `error` instead of mapping the item to `null`.\n* @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).\n* @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.\n*/\nfunction isFatalWorkflowError(error) {\n\treturn error instanceof WorkflowError && error.fatal;\n}\n//#endregion\n//#region packages/workflow/workflow-ptc/src/runtime.ts\n/**\n* Workflow VM hooks, child callbacks, ordinary concurrency limits and result serialization.\n* PTC owns process confinement and cancellation. Fatal hook and provider failures propagate\n* through combinators; ordinary child failures and stage errors become per-item nulls.\n* @module @deepseek-ai/dsh-workflow-ptc/runtime\n*/\n/** The `agent()` options the script may pass; everything else rejects loud. */\nconst SUPPORTED_AGENT_OPTIONS = new Set([\n\t\"label\",\n\t\"phase\",\n\t\"schema\",\n\t\"provider\",\n\t\"model\"\n]);\n/** Deferred Claude Code options we name explicitly in the rejection message. */\nconst DEFERRED_AGENT_OPTIONS = new Set([\n\t\"effort\",\n\t\"isolation\",\n\t\"agentType\"\n]);\n/** Flatten a child's final output blocks to text (the non-schema `agent()` result). */\nfunction outputText(blocks) {\n\treturn blocks.filter((block) => block.type === \"text\").map((block) => block.text).join(\"\");\n}\n/** A short display label derived from the prompt when the script passes none. */\nfunction defaultLabel(prompt) {\n\tconst newline = prompt.indexOf(\"\\n\");\n\tconst line = newline === -1 ? prompt : prompt.slice(0, newline);\n\treturn line.length <= 48 ? line : `${line.slice(0, 47)}\u2026`;\n}\n/**\n* One script execution inside the confined Node process. The host owns\n* cancellation and cleanup of any dropped child work.\n*/\nvar WorkflowExecution = class {\n\tlimits;\n\tobserver;\n\tchildren;\n\t/** 1-based count of `agent()` calls started (the `agentsStarted` result field). */\n\tstarted = 0;\n\tactiveSlots = 0;\n\tslotWaiters = [];\n\tcurrentPhase;\n\tcontext;\n\tcompiled;\n\tconstructor(meta, body, args, limits, observer, children) {\n\t\tthis.limits = limits;\n\t\tthis.observer = observer;\n\t\tthis.children = children;\n\t\ttry {\n\t\t\tthis.compiled = new vm.Script(`(async () => {\\n${body}\\n})()`, {\n\t\t\t\tfilename: `workflow:${meta.name}`,\n\t\t\t\tlineOffset: -1\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow new WorkflowError(`workflow script does not parse: ${String(error)}`, \"SCRIPT_PARSE\", { cause: error });\n\t\t}\n\t\tthis.context = vm.createContext({}, { name: `workflow:${meta.name}` });\n\t\tconst globals = {\n\t\t\tagent: (prompt, opts) => this.contain(this.agent(prompt, opts)),\n\t\t\tparallel: (thunks) => this.contain(this.parallel(thunks)),\n\t\t\tpipeline: (items, ...stages) => this.contain(this.pipeline(items, stages)),\n\t\t\tphase: (title) => {\n\t\t\t\tthis.phase(title);\n\t\t\t},\n\t\t\tlog: (message) => {\n\t\t\t\tthis.log(message);\n\t\t\t},\n\t\t\targs\n\t\t};\n\t\tfor (const [key, value] of Object.entries(globals)) this.context[key] = typeof value === \"function\" ? Object.freeze(value) : value;\n\t}\n\t/**\n\t* Run the script and materialize its JSON return value.\n\t* @returns A completed or error result; script failures never reject.\n\t*/\n\tasync drive() {\n\t\ttry {\n\t\t\tconst scriptPromise = this.compiled.runInContext(this.context, { timeout: this.limits.syncTimeoutMs });\n\t\t\tconst raw = await this.contain(Promise.resolve(scriptPromise));\n\t\t\treturn {\n\t\t\t\tvalue: raw === void 0 ? null : this.materializeResult(raw),\n\t\t\t\tstopReason: \"completed\",\n\t\t\t\tagentsStarted: this.started\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tvalue: null,\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terror: renderThrown(error),\n\t\t\t\tagentsStarted: this.started\n\t\t\t};\n\t\t}\n\t}\n\t/**\n\t* Attach a no-op rejection consumer WITHOUT changing what the caller\n\t* receives: if the script drops the promise, a host rejection cannot become\n\t* an unhandled rejection that kills the process; if\n\t* the script does await it, it still observes the rejection.\n\t*/\n\tcontain(promise) {\n\t\tpromise.catch(() => {});\n\t\treturn promise;\n\t}\n\t/** Materialize the script's return value; violations become RESULT_UNSERIALIZABLE. */\n\tmaterializeResult(raw) {\n\t\ttry {\n\t\t\treturn materializeFromRealm(raw, \"workflow result\");\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n\t\t\tif (!(error instanceof MaterializeError)) throw error;\n\t\t\tthrow new WorkflowError(`the workflow's return value is not plain JSON data \u2014 ${error.message}. Return only JSON-serializable objects/arrays/scalars.`, \"RESULT_UNSERIALIZABLE\", { cause: error });\n\t\t}\n\t}\n\t/** Acquire one concurrency slot in FIFO order. */\n\tacquireSlot() {\n\t\tif (this.activeSlots < this.limits.maxConcurrentAgents) {\n\t\t\tthis.activeSlots += 1;\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.slotWaiters.push(() => {\n\t\t\t\tthis.activeSlots += 1;\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\treleaseSlot() {\n\t\tthis.activeSlots -= 1;\n\t\tconst next = this.slotWaiters.shift();\n\t\tif (next) next();\n\t}\n\t/** The `agent(prompt, opts)` hook. */\n\tasync agent(rawPrompt, rawOpts) {\n\t\tif (typeof rawPrompt !== \"string\" || rawPrompt.length === 0) throw new WorkflowError(\"agent() requires a non-empty prompt string\", \"INVALID_ARGUMENT\");\n\t\tconst opts = this.readAgentOptions(rawOpts);\n\t\tif (this.started >= this.limits.maxTotalAgents) throw new WorkflowError(`this run reached its total agent cap (${this.limits.maxTotalAgents}) \u2014 a runaway-loop backstop; raise the applicable maxTotalAgents limit if the scale is intentional`, \"AGENT_CAP\");\n\t\tthis.started += 1;\n\t\tconst seq = this.started;\n\t\tconst label = opts.label ?? defaultLabel(rawPrompt);\n\t\tconst phase = opts.phase ?? this.currentPhase;\n\t\tawait this.acquireSlot();\n\t\ttry {\n\t\t\tlet run;\n\t\t\ttry {\n\t\t\t\trun = await this.children.startAgent({\n\t\t\t\t\tprompt: rawPrompt,\n\t\t\t\t\t...opts.schema !== void 0 ? { schema: opts.schema } : {},\n\t\t\t\t\t...opts.provider !== void 0 ? { provider: opts.provider } : {},\n\t\t\t\t\t...opts.model !== void 0 ? { model: opts.model } : {}\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthrow new WorkflowError(`agent() could not start a child: ${renderThrown(error)}`, \"AGENT_START\", { cause: error });\n\t\t\t}\n\t\t\tconst info = {\n\t\t\t\tseq,\n\t\t\t\tlabel,\n\t\t\t\t...phase !== void 0 ? { phase } : {},\n\t\t\t\tchildId: brandString(run.id)\n\t\t\t};\n\t\t\tthis.observer.agentStart(info);\n\t\t\ttry {\n\t\t\t\tlet result;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await run.result;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t\t});\n\t\t\t\t\tthrow new WorkflowError(`child agent run failed: ${renderThrown(error)}`, \"AGENT_RESULT\", { cause: error });\n\t\t\t\t}\n\t\t\t\tif (result.stopReason === \"completed\") {\n\t\t\t\t\tif (opts.schema !== void 0) {\n\t\t\t\t\t\tif (result.structured === void 0) {\n\t\t\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\toutcome: \"completed\"\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn result.structured;\n\t\t\t\t\t}\n\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\toutcome: \"completed\"\n\t\t\t\t\t});\n\t\t\t\t\treturn outputText(result.output);\n\t\t\t\t}\n\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t...info,\n\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t} finally {\n\t\t\t\tawait run.dispose();\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.releaseSlot();\n\t\t}\n\t}\n\t/** Materialize + validate the `agent()` options bag from the realm. */\n\treadAgentOptions(rawOpts) {\n\t\tif (rawOpts === void 0) return {};\n\t\tlet opts;\n\t\ttry {\n\t\t\topts = materializeFromRealm(rawOpts, \"agent() options\");\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n\t\t\tif (!(error instanceof MaterializeError)) throw error;\n\t\t\tthrow new WorkflowError(`agent() options must be plain JSON data \u2014 ${error.message}`, \"INVALID_ARGUMENT\", { cause: error });\n\t\t}\n\t\tif (typeof opts !== \"object\" || opts === null || Array.isArray(opts)) throw new WorkflowError(\"agent() options must be an object\", \"INVALID_ARGUMENT\");\n\t\tconst record = opts;\n\t\tfor (const key of Object.keys(record)) {\n\t\t\tif (SUPPORTED_AGENT_OPTIONS.has(key)) continue;\n\t\t\tif (DEFERRED_AGENT_OPTIONS.has(key)) throw new WorkflowError(`agent() option \"${key}\" is deferred and not supported by this engine (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n\t\t\tthrow new WorkflowError(`agent() option \"${key}\" is not recognized (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n\t\t}\n\t\tfor (const key of [\n\t\t\t\"label\",\n\t\t\t\"phase\",\n\t\t\t\"provider\",\n\t\t\t\"model\"\n\t\t]) if (record[key] !== void 0 && typeof record[key] !== \"string\") throw new WorkflowError(`agent() option \"${key}\" must be a string`, \"INVALID_ARGUMENT\");\n\t\tlet schema;\n\t\tif (record.schema !== void 0) try {\n\t\t\tassertObjectJsonSchema(record.schema);\n\t\t\tschema = record.schema;\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */\n\t\t\tif (!(error instanceof JsonSchemaError)) throw error;\n\t\t\tthrow new WorkflowError(`agent() schema is outside the supported subset \u2014 ${error.message}`, \"UNSUPPORTED_SCHEMA\", { cause: error });\n\t\t}\n\t\treturn {\n\t\t\t...record.label !== void 0 ? { label: record.label } : {},\n\t\t\t...record.phase !== void 0 ? { phase: record.phase } : {},\n\t\t\t...record.provider !== void 0 ? { provider: record.provider } : {},\n\t\t\t...record.model !== void 0 ? { model: record.model } : {},\n\t\t\t...schema !== void 0 ? { schema } : {}\n\t\t};\n\t}\n\t/** The `parallel(thunks)` hook: each thunk caught \u2192 `null`; fatal errors propagate. */\n\tasync parallel(rawThunks) {\n\t\tif (!Array.isArray(rawThunks)) throw new WorkflowError(\"parallel() requires an array of zero-argument functions\", \"INVALID_ARGUMENT\");\n\t\tthis.assertItemCap(rawThunks.length, \"parallel()\");\n\t\tconst thunks = rawThunks.map((thunk, index) => {\n\t\t\tif (typeof thunk !== \"function\") throw new WorkflowError(`parallel() item ${index} is not a function`, \"INVALID_ARGUMENT\");\n\t\t\treturn thunk;\n\t\t});\n\t\treturn Promise.all(thunks.map(async (thunk) => {\n\t\t\ttry {\n\t\t\t\treturn await thunk();\n\t\t\t} catch (error) {\n\t\t\t\tif (isFatalWorkflowError(error)) throw error;\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}));\n\t}\n\t/** The `pipeline(items, ...stages)` hook: per-item stage chains, NO cross-stage barrier. */\n\tasync pipeline(rawItems, rawStages) {\n\t\tif (!Array.isArray(rawItems)) throw new WorkflowError(\"pipeline() requires an items array\", \"INVALID_ARGUMENT\");\n\t\tthis.assertItemCap(rawItems.length, \"pipeline()\");\n\t\tif (rawStages.length === 0) throw new WorkflowError(\"pipeline() requires at least one stage function\", \"INVALID_ARGUMENT\");\n\t\tconst stages = rawStages.map((stage, index) => {\n\t\t\tif (typeof stage !== \"function\") throw new WorkflowError(`pipeline() stage ${index} is not a function`, \"INVALID_ARGUMENT\");\n\t\t\treturn stage;\n\t\t});\n\t\treturn Promise.all(rawItems.map(async (item, index) => {\n\t\t\tlet value = item;\n\t\t\ttry {\n\t\t\t\tfor (const stage of stages) value = await stage(value, item, index);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tif (isFatalWorkflowError(error)) throw error;\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}));\n\t}\n\tassertItemCap(length, hook) {\n\t\tif (length > this.limits.maxItemsPerCall) throw new WorkflowError(`${hook} received ${length} items \u2014 over the per-call cap (${this.limits.maxItemsPerCall}); split the work or raise maxItemsPerCall in the engine config`, \"ITEM_CAP\");\n\t}\n\t/** The `phase(title)` hook: sets the current label for subsequent `agent()` calls and notifies observers. */\n\tphase(title) {\n\t\tif (typeof title !== \"string\" || title.length === 0) throw new WorkflowError(\"phase() requires a non-empty title string\", \"INVALID_ARGUMENT\");\n\t\tthis.currentPhase = title;\n\t\tthis.observer.phase(title);\n\t}\n\t/** The `log(message)` hook: narration to observers. */\n\tlog(message) {\n\t\tif (typeof message !== \"string\") throw new WorkflowError(\"log() requires a message string\", \"INVALID_ARGUMENT\");\n\t\tthis.observer.log(message);\n\t}\n};\n//#endregion\n//#region packages/workflow/workflow-ptc/src/guest.ts\n/**\n* Run a workflow with one progress batch in flight. Drain progress before child\n* disposal and the terminal result; PTC and the host own cancellation and cleanup.\n* @param host - JSON callbacks owned by this workflow run.\n* @returns The script result after progress delivery; initialization failures reject.\n*/\nasync function runWorkflowGuest(host) {\n\tconst init = await host.begin({});\n\tlet queued = [];\n\tlet inFlight;\n\tlet progressError;\n\tconst flush = () => {\n\t\tif (inFlight !== void 0 || queued.length === 0) return;\n\t\tconst batch = queued;\n\t\tqueued = [];\n\t\tinFlight = host.progress(batch).then(() => {\n\t\t\tinFlight = void 0;\n\t\t\tflush();\n\t\t}, (error) => {\n\t\t\tprogressError = renderThrown(error);\n\t\t\tqueued = [];\n\t\t\tinFlight = void 0;\n\t\t});\n\t};\n\tconst send = (event) => {\n\t\tif (progressError !== void 0) return;\n\t\tqueued.push(event);\n\t\tflush();\n\t};\n\tconst drain = async () => {\n\t\twhile (inFlight !== void 0) await inFlight;\n\t};\n\tconst result = await new WorkflowExecution(init.meta, init.body, init.args, init.limits, {\n\t\tphase: (title) => {\n\t\t\tsend({\n\t\t\t\ttype: \"phase\",\n\t\t\t\ttitle\n\t\t\t});\n\t\t},\n\t\tlog: (message) => {\n\t\t\tsend({\n\t\t\t\ttype: \"log\",\n\t\t\t\tmessage\n\t\t\t});\n\t\t},\n\t\tagentStart: (info) => {\n\t\t\tsend({\n\t\t\t\ttype: \"agent-start\",\n\t\t\t\tinfo\n\t\t\t});\n\t\t},\n\t\tagentEnd: (info) => {\n\t\t\tsend({\n\t\t\t\ttype: \"agent-end\",\n\t\t\t\tinfo\n\t\t\t});\n\t\t}\n\t}, { async startAgent(request) {\n\t\tconst { callId, childId } = await host.startChild(request);\n\t\tconst result = host.childResult({ callId });\n\t\tresult.catch(() => {});\n\t\treturn {\n\t\t\tid: childId,\n\t\t\tresult,\n\t\t\tasync dispose() {\n\t\t\t\tawait drain();\n\t\t\t\tawait host.disposeChild({ callId });\n\t\t\t}\n\t\t};\n\t} }).drive();\n\tawait drain();\n\treturn progressError === void 0 ? result : {\n\t\tvalue: null,\n\t\tstopReason: \"error\",\n\t\terror: progressError,\n\t\tagentsStarted: result.agentsStarted\n\t};\n}\n//#endregion\nexport { runWorkflowGuest };\n//# sourceURL=dsh-workflow-guest.js\n";
3
+ export declare const WORKFLOW_GUEST_SOURCE = "import * as vm from \"node:vm\";\n//#region packages/workflow/workflow-ptc/src/realm.ts\n/**\n* Materializes script VM values as plain JSON and renders thrown values.\n* Getters and proxy traps may execute inside the confined Node process;\n* process isolation and cancellation belong to PTC, not the VM.\n* @module @deepseek-ai/dsh-workflow-ptc/realm\n*/\n/** Thrown by {@link materializeFromRealm}; the caller wraps it into the right `WorkflowError` code. */\nvar MaterializeError = class extends Error {\n\tpath;\n\treason;\n\tconstructor(path, reason) {\n\t\tsuper(`${path}: ${reason}`);\n\t\tthis.path = path;\n\t\tthis.reason = reason;\n\t\tthis.name = \"MaterializeError\";\n\t}\n};\n/**\n* Render a thrown value to failure text without ever throwing: prefer the\n* `stack` (host or realm \u2014 a realm error's `stack` is a plain string read),\n* fall back to `message`, then `String()`. Reading those properties MAY run\n* script code; if that code itself throws, a fixed label is returned instead.\n* @param error - any value thrown in the host or guest realm.\n* @returns human-readable text for the failure report; prefers the stack.\n*/\nfunction renderThrown(error) {\n\ttry {\n\t\tconst stack = error?.stack;\n\t\tif (typeof stack === \"string\" && stack.length > 0) return stack;\n\t\tconst message = error?.message;\n\t\tif (typeof message === \"string\" && message.length > 0) return message;\n\t\treturn String(error);\n\t} catch {\n\t\treturn \"[unrenderable thrown value]\";\n\t}\n}\n/**\n* Whether an object's prototype chain represents a plain data object: `null`, or a prototype\n* whose own prototype is `null` (the realm's `Object.prototype` \u2014 which we\n* cannot compare by identity across realms). A `Date`/`Map`/class instance\n* has a longer chain and is rejected.\n*/\nfunction hasPlainPrototype(value) {\n\tconst proto = Object.getPrototypeOf(value);\n\tif (proto === null) return true;\n\treturn Object.getPrototypeOf(proto) === null;\n}\n/**\n* Copy `value` (typically from the vm realm) into plain host JSON data. Root `undefined` is\n* returned unchanged; nested `undefined` and values JSON cannot represent losslessly fail\n* with the offending path. Property accessors run normally, and a throwing read is wrapped\n* with its rendered failure.\n*\n* @param value - the realm value to materialize.\n* @param root - the path label for the root value (error messages).\n* @returns the host-realm copy (plain objects/arrays/scalars only).\n* @throws {@link MaterializeError} for unsupported values, cycles, sparse arrays, exotic\n* prototypes, or property reads that throw.\n*/\nfunction materializeFromRealm(value, root = \"value\") {\n\tif (value === void 0) return void 0;\n\ttry {\n\t\treturn materialize(value, root, /* @__PURE__ */ new Set());\n\t} catch (error) {\n\t\tif (error instanceof MaterializeError) throw error;\n\t\tthrow new MaterializeError(root, `reading the value threw: ${renderThrown(error)}`);\n\t}\n}\nfunction materialize(value, path, seen) {\n\tswitch (typeof value) {\n\t\tcase \"boolean\":\n\t\tcase \"string\": return value;\n\t\tcase \"number\":\n\t\t\tif (!Number.isFinite(value)) throw new MaterializeError(path, \"non-finite numbers are not JSON data\");\n\t\t\treturn value;\n\t\tcase \"bigint\": throw new MaterializeError(path, \"bigints are not JSON data\");\n\t\tcase \"function\": throw new MaterializeError(path, \"functions are not plain JSON data\");\n\t\tcase \"symbol\": throw new MaterializeError(path, \"symbols are not plain JSON data\");\n\t\tcase \"undefined\": throw new MaterializeError(path, \"undefined is not JSON data\");\n\t\tcase \"object\": break;\n\t}\n\tif (value === null) return null;\n\tconst objectValue = value;\n\tif (seen.has(objectValue)) throw new MaterializeError(path, \"circular references are not JSON data\");\n\tseen.add(objectValue);\n\ttry {\n\t\tif (Array.isArray(objectValue)) return materializeArray(objectValue, path, seen);\n\t\treturn materializeObject(objectValue, path, seen);\n\t} finally {\n\t\tseen.delete(objectValue);\n\t}\n}\nfunction materializeArray(value, path, seen) {\n\tconst out = [];\n\tfor (let index = 0; index < value.length; index++) {\n\t\tif (!(index in value)) throw new MaterializeError(`${path}[${index}]`, \"sparse arrays are not JSON data\");\n\t\tout.push(materialize(value[index], `${path}[${index}]`, seen));\n\t}\n\tfor (const key of Object.keys(value)) {\n\t\tconst index = Number(key);\n\t\tif (!Number.isInteger(index) || index < 0 || index >= value.length) throw new MaterializeError(`${path}.${key}`, \"arrays with non-index properties are not JSON data\");\n\t}\n\tif (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n\treturn out;\n}\nfunction materializeObject(value, path, seen) {\n\tif (!hasPlainPrototype(value)) throw new MaterializeError(path, \"only plain objects and arrays are JSON data (exotic prototype)\");\n\tif (Object.getOwnPropertySymbols(value).length > 0) throw new MaterializeError(path, \"symbol-keyed properties are not plain JSON data\");\n\tconst out = {};\n\tfor (const key of Object.keys(value)) Object.defineProperty(out, key, {\n\t\tvalue: materialize(value[key], `${path}.${key}`, seen),\n\t\tenumerable: true,\n\t\twritable: true,\n\t\tconfigurable: true\n\t});\n\treturn out;\n}\n//#endregion\n//#region packages/util/brand/src/index.ts\n/**\n* Apply a compile-time string brand without changing the value.\n* @param value - string admitted by the domain that owns the target brand.\n* @returns the same string with the requested compile-time brand.\n*/\nfunction brandString(value) {\n\treturn value;\n}\n//#endregion\n//#region packages/llm/llm/src/error.ts\n/**\n* Harness error base with a stable machine-routable code and chained cause.\n* Package errors extend it so tool results and replay can retain failure class.\n* @module @deepseek-ai/dsh-llm/error\n*/\n/**\n* Base class for all harness errors. Carries a `code` (stable, programmatic \u2014\n* e.g. `NO_ADAPTER`, `INVALID_ARGS`) distinct from the\n* human-readable `message`, and supports `cause` chaining via the standard\n* `ErrorOptions`. `name` defaults to the subclass constructor name.\n*/\nvar HarnessError = class extends Error {\n\t/** Stable machine-routable failure class (e.g. `RATE_LIMIT`); route on this, never by parsing `message`. */\n\tcode;\n\tconstructor(message, code, options) {\n\t\tsuper(message, options);\n\t\tthis.code = code;\n\t\tthis.name = new.target.name;\n\t}\n};\nnew RegExp(String.raw`(?:^|[^a-z0-9])context[\\s_-](?:length|window)[\\s_-]` + String.raw`(?:exceed(?:ed|s)?|overflow(?:ed)?|limit[\\s_-]exceeded)(?:$|[^a-z0-9])`, \"i\");\nnew RegExp(String.raw`\\b(?:request|prompt|input|messages?)\\s+(?:is\\s+|are\\s+)?` + String.raw`too\\s+(?:large|long)\\s+for\\s+(?:(?:this|the)\\s+)?` + String.raw`(?:model(?:'s)?\\s+)?context(?:\\s+window)?\\b`, \"i\");\nnew RegExp(String.raw`\\b(?:input|prompt|request|messages?)\\b.{0,40}` + String.raw`\\b(?:exceed(?:s|ed)?|overflows?|is\\s+larger\\s+than)\\b.{0,40}` + String.raw`\\b(?:the\\s+)?(?:model(?:'s)?\\s+)?context(?:\\s+(?:length|window))?\\b`, \"i\");\n//#endregion\n//#region packages/util/values/src/index.ts\n/**\n* Mark an unreachable closed-union branch.\n* @param value - impossible value; an unhandled typed variant fails at the call site.\n* @param context - optional switch-site label included in the failure message.\n* @returns never; a runtime value that escaped its type always throws.\n*/\nfunction assertNever(value, context) {\n\tconst rendered = JSON.stringify(value) ?? String(value);\n\tthrow new Error(`unreachable variant${context ? ` in ${context}` : \"\"}: ${rendered}`);\n}\n/** Whether a realm-owned intrinsic prototype has a native constructor matching this engine's representation. */\nfunction hasIntrinsicConstructor$1(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === Function.prototype.toString.call(name === \"Array\" ? Array : Object);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype$1(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor$1(value, \"Object\");\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`, not a subclass or forged prototype. */\nfunction hasPlainArrayPrototype$1(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor$1(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype$1(objectPrototype);\n}\n/** Whether an object is a plain or null-prototype record from any JavaScript realm. */\nfunction hasPlainObjectPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype$1(prototype);\n}\n/** Return every JSON-visible object key, or reject own data JSON would discard. */\nfunction enumerableStringKeys(value) {\n\tconst keys = Reflect.ownKeys(value);\n\tif (keys.some((key) => typeof key !== \"string\" || !Object.prototype.propertyIsEnumerable.call(value, key))) return void 0;\n\treturn keys;\n}\n/** Validate lossless JSON iteratively, optionally materializing a detached snapshot. */\nfunction walkJsonValue(value, detach) {\n\tconst ancestors = /* @__PURE__ */ new Set();\n\tlet root;\n\tconst assign = (destination, item) => {\n\t\tif (destination === void 0) return;\n\t\tif (destination.kind === \"root\") root = item;\n\t\telse if (destination.kind === \"array\") destination.target[destination.index] = item;\n\t\telse Object.defineProperty(destination.target, destination.key, {\n\t\t\tvalue: item,\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\t\t\twritable: true\n\t\t});\n\t};\n\tconst tasks = [{\n\t\tkind: \"visit\",\n\t\tvalue,\n\t\t...detach ? { destination: { kind: \"root\" } } : {}\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tancestors.delete(task.source);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"array-item\") {\n\t\t\tif (!Object.prototype.hasOwnProperty.call(task.source, task.index)) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.index],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"array\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tindex: task.index\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-property\") {\n\t\t\ttasks.push({\n\t\t\t\tkind: \"visit\",\n\t\t\t\tvalue: task.source[task.key],\n\t\t\t\t...task.target === void 0 ? {} : { destination: {\n\t\t\t\t\tkind: \"object\",\n\t\t\t\t\ttarget: task.target,\n\t\t\t\t\tkey: task.key\n\t\t\t\t} }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst current = task.value;\n\t\tif (current === null) {\n\t\t\tassign(task.destination, null);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"boolean\" || typeof current === \"string\") {\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current === \"number\") {\n\t\t\tif (!Number.isFinite(current) || Object.is(current, -0)) return void 0;\n\t\t\tassign(task.destination, current);\n\t\t\tcontinue;\n\t\t}\n\t\tif (typeof current !== \"object\") return void 0;\n\t\tif (ancestors.has(current)) return void 0;\n\t\tif (Array.isArray(current)) {\n\t\t\tif (!hasPlainArrayPrototype$1(current)) return void 0;\n\t\t\tconst length = current.length;\n\t\t\tif (Reflect.ownKeys(current).length !== length + 1) return void 0;\n\t\t\tconst target = detach ? [] : void 0;\n\t\t\tif (target !== void 0) assign(task.destination, target);\n\t\t\tancestors.add(current);\n\t\t\ttasks.push({\n\t\t\t\tkind: \"leave\",\n\t\t\t\tsource: current\n\t\t\t});\n\t\t\tfor (let index = length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"array-item\",\n\t\t\t\tsource: current,\n\t\t\t\tindex,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasPlainObjectPrototype(current)) return void 0;\n\t\tconst keys = enumerableStringKeys(current);\n\t\tif (keys === void 0) return void 0;\n\t\tconst target = detach ? {} : void 0;\n\t\tif (target !== void 0) assign(task.destination, target);\n\t\tancestors.add(current);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tsource: current\n\t\t});\n\t\tfor (let index = keys.length - 1; index >= 0; index--) {\n\t\t\tconst key = keys[index];\n\t\t\t/* v8 ignore next -- the loop is bounded by the captured key count. */\n\t\t\tif (key === void 0) return void 0;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"object-property\",\n\t\t\t\tsource: current,\n\t\t\t\tkey,\n\t\t\t\t...target === void 0 ? {} : { target }\n\t\t\t});\n\t\t}\n\t}\n\treturn detach ? root : true;\n}\n/**\n* Test the same lossless JSON rules as {@link snapshotJsonValue} without detaching the value.\n* @param value - candidate value to test.\n* @returns whether the value survives a JSON round trip without loss.\n*/\nfunction isJsonValue(value) {\n\treturn walkJsonValue(value, false) === true;\n}\n//#endregion\n//#region packages/core/tools/src/json-schema.ts\n/**\n* Enforced JSON Schema subset shared by tool outputs, generated PTC mode\n* types, subagents, and workflows. The subset accepts any JSON root, an\n* annotation-only schema for unconstrained JSON, one scalar `type`, object\n* `properties`/`required`/boolean `additionalProperties`, array `items`,\n* type-correct scalar `enum`/`const`, and exact-one `oneOf`.\n*\n* Unsupported or misplaced keywords reject rather than being accepted without\n* enforcement. Consumers that require an object root apply\n* {@link assertObjectJsonSchema} before accepting input.\n* @module dsh-tools/json-schema\n*/\n/**\n* Thrown when a raw schema falls outside the enforced subset. `violations`\n* lists every offending path instead of stopping at the first author error.\n*/\nvar JsonSchemaError = class extends HarnessError {\n\t/** Individual schema violations in walk order. */\n\tviolations;\n\tconstructor(violations) {\n\t\tsuper(`unsupported JSON schema: ${violations.join(\"; \")}`, \"UNSUPPORTED_SCHEMA\");\n\t\tthis.name = \"JsonSchemaError\";\n\t\tthis.violations = violations;\n\t}\n};\nconst CONSTRAINT_KEYWORDS = new Set([\n\t\"type\",\n\t\"oneOf\",\n\t\"properties\",\n\t\"required\",\n\t\"additionalProperties\",\n\t\"items\",\n\t\"enum\",\n\t\"const\"\n]);\nconst ANNOTATION_KEYWORDS = new Set([\n\t\"description\",\n\t\"title\",\n\t\"default\",\n\t\"examples\"\n]);\nconst SCHEMA_TYPES = [\n\t\"object\",\n\t\"array\",\n\t\"string\",\n\t\"number\",\n\t\"integer\",\n\t\"boolean\",\n\t\"null\"\n];\n/** Whether a realm-owned intrinsic prototype is backed by its native constructor. */\nfunction hasIntrinsicConstructor(prototype, name) {\n\tconst constructor = Object.getOwnPropertyDescriptor(prototype, \"constructor\")?.value;\n\tif (typeof constructor !== \"function\") return false;\n\ttry {\n\t\treturn constructor.name === name && constructor.prototype === prototype && Function.prototype.toString.call(constructor) === `function ${name}() { [native code] }`;\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether a candidate is one realm's intrinsic `Object.prototype`. */\nfunction isIntrinsicObjectPrototype(value) {\n\treturn Object.getPrototypeOf(value) === null && hasIntrinsicConstructor(value, \"Object\");\n}\n/**\n* Test for a realm-agnostic plain JSON record without accepting arrays or\n* exotic objects.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the value has a plain-object prototype chain.\n*/\nfunction isPlainJsonRecord(value) {\n\tif (typeof value !== \"object\" || value === null || Array.isArray(value)) return false;\n\ttry {\n\t\tconst prototype = Object.getPrototypeOf(value);\n\t\treturn prototype === null || typeof prototype === \"object\" && isIntrinsicObjectPrototype(prototype);\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Whether an array uses one realm's intrinsic `Array.prototype`. */\nfunction hasPlainArrayPrototype(value) {\n\tconst prototype = Object.getPrototypeOf(value);\n\tif (!Array.isArray(prototype) || !hasIntrinsicConstructor(prototype, \"Array\")) return false;\n\tconst objectPrototype = Object.getPrototypeOf(prototype);\n\treturn typeof objectPrototype === \"object\" && objectPrototype !== null && isIntrinsicObjectPrototype(objectPrototype);\n}\n/** Return whether a record contains only own enumerable string keys. */\nfunction hasOnlyEnumerableStringKeys(value) {\n\ttry {\n\t\treturn Reflect.ownKeys(value).every((key) => typeof key === \"string\" && Object.prototype.propertyIsEnumerable.call(value, key));\n\t} catch {\n\t\treturn false;\n\t}\n}\n/**\n* Test for an ordinary schema record whose keys survive JSON projection.\n* @param value - candidate record from any JavaScript realm.\n* @returns Whether the record has an intrinsic prototype and only own enumerable string keys.\n*/\nfunction isJsonSchemaRecord(value) {\n\treturn isPlainJsonRecord(value) && hasOnlyEnumerableStringKeys(value);\n}\n/**\n* Test for a dense ordinary array with no JSON-invisible decorations.\n* @param value - candidate array from any JavaScript realm.\n* @returns Whether the array is intrinsic, dense, and undecorated.\n*/\nfunction isPlainJsonArray(value) {\n\tif (!Array.isArray(value)) return false;\n\ttry {\n\t\tif (!hasPlainArrayPrototype(value) || Reflect.ownKeys(value).length !== value.length + 1) return false;\n\t\tfor (let index = 0; index < value.length; index++) if (!Object.hasOwn(value, index)) return false;\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n/** Lossless finite JSON number, excluding negative zero. */\nfunction isJsonNumber(value) {\n\treturn typeof value === \"number\" && Number.isFinite(value) && !Object.is(value, -0);\n}\n/** Whether a scalar is valid for one declared schema type. */\nfunction scalarMatches(type, value) {\n\tswitch (type) {\n\t\tcase \"string\": return typeof value === \"string\";\n\t\tcase \"number\": return isJsonNumber(value);\n\t\tcase \"integer\": return isJsonNumber(value) && Number.isInteger(value);\n\t\tcase \"boolean\": return typeof value === \"boolean\";\n\t\tcase \"null\": return value === null;\n\t\t/* v8 ignore next -- JsonSchemaScalarType is closed; this retains compile-time exhaustiveness. */\n\t\tdefault: return assertNever(type, \"JsonSchemaType\");\n\t}\n}\n/** Keywords that are invalid beside `oneOf`. */\nconst ONE_OF_SIBLING_KEYWORDS = [\n\t\"properties\",\n\t\"required\",\n\t\"additionalProperties\",\n\t\"items\",\n\t\"enum\",\n\t\"const\"\n];\n/** Validate object-only fields after its property schemas have been visited. */\nfunction checkObjectSchemaTail(node, path, properties, violations) {\n\tconst hasRequired = Object.hasOwn(node, \"required\");\n\tconst required = hasRequired ? node.required : void 0;\n\tif (hasRequired) if (!isPlainJsonArray(required) || required.some((entry) => typeof entry !== \"string\")) violations.push(`${path}.required must be an array of strings`);\n\telse {\n\t\tconst declared = isJsonSchemaRecord(properties) ? properties : {};\n\t\tfor (const key of required) if (!Object.hasOwn(declared, key)) violations.push(`${path}.required names \"${key}\" which is not in properties`);\n\t}\n\tif (Object.hasOwn(node, \"additionalProperties\") && typeof node.additionalProperties !== \"boolean\") violations.push(`${path}.additionalProperties must be a boolean`);\n}\n/** Collect every violation for one raw schema tree without using the JavaScript call stack. */\nfunction checkSchemaNode(root, rootPath, violations, seen) {\n\tconst tasks = [{\n\t\tkind: \"enter\",\n\t\tnode: root,\n\t\tpath: rootPath\n\t}];\n\tfor (let task = tasks.pop(); task !== void 0; task = tasks.pop()) {\n\t\tif (task.kind === \"leave\") {\n\t\t\tseen.delete(task.node);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"one-of-tail\") {\n\t\t\tfor (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(task.node, key)) violations.push(`${task.path}.${key} is not supported beside oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (task.kind === \"object-tail\") {\n\t\t\tcheckObjectSchemaTail(task.node, task.path, task.properties, violations);\n\t\t\tcontinue;\n\t\t}\n\t\tconst { node, path } = task;\n\t\tif (!isJsonSchemaRecord(node)) {\n\t\t\tviolations.push(`${path} must be a schema object`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (seen.has(node)) {\n\t\t\tviolations.push(`${path} is circular`);\n\t\t\tcontinue;\n\t\t}\n\t\tseen.add(node);\n\t\ttasks.push({\n\t\t\tkind: \"leave\",\n\t\t\tnode\n\t\t});\n\t\tfor (const key of Object.keys(node)) {\n\t\t\tif (CONSTRAINT_KEYWORDS.has(key)) continue;\n\t\t\tif (ANNOTATION_KEYWORDS.has(key)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!isJsonValue(node[key])) violations.push(`${path}.${key} annotation must be lossless JSON data`);\n\t\t\t\t} catch {\n\t\t\t\t\tviolations.push(`${path}.${key} annotation must be lossless JSON data`);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tviolations.push(`${path}.${key} is not a supported keyword (subset: type/oneOf/properties/required/additionalProperties/items/enum/const + annotations)`);\n\t\t}\n\t\tif (Object.hasOwn(node, \"description\") && typeof node.description !== \"string\") violations.push(`${path}.description must be a string`);\n\t\tif (Object.hasOwn(node, \"title\") && typeof node.title !== \"string\") violations.push(`${path}.title must be a string`);\n\t\tconst hasType = Object.hasOwn(node, \"type\");\n\t\tconst hasOneOf = Object.hasOwn(node, \"oneOf\");\n\t\tif (hasType && hasOneOf) {\n\t\t\tviolations.push(`${path} cannot declare both type and oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!hasType && !hasOneOf) {\n\t\t\tfor (const key of ONE_OF_SIBLING_KEYWORDS) if (Object.hasOwn(node, key)) violations.push(`${path}.${key} requires type or oneOf`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (hasOneOf) {\n\t\t\tconst oneOf = node.oneOf;\n\t\t\ttasks.push({\n\t\t\t\tkind: \"one-of-tail\",\n\t\t\t\tnode,\n\t\t\t\tpath\n\t\t\t});\n\t\t\tif (!isPlainJsonArray(oneOf) || oneOf.length < 2) violations.push(`${path}.oneOf must be an array of at least two schemas`);\n\t\t\telse for (let index = oneOf.length - 1; index >= 0; index--) tasks.push({\n\t\t\t\tkind: \"enter\",\n\t\t\t\tnode: oneOf[index],\n\t\t\t\tpath: `${path}.oneOf[${index}]`\n\t\t\t});\n\t\t\tcontinue;\n\t\t}\n\t\tconst type = node.type;\n\t\tif (typeof type !== \"string\" || !SCHEMA_TYPES.includes(type)) {\n\t\t\tviolations.push(Array.isArray(type) ? `${path}.type must be a single type string (type arrays are not supported)` : `${path}.type must be one of ${SCHEMA_TYPES.join(\"/\")}`);\n\t\t\tcontinue;\n\t\t}\n\t\tconst schemaType = type;\n\t\tfor (const [key, types] of Object.entries({\n\t\t\tproperties: [\"object\"],\n\t\t\trequired: [\"object\"],\n\t\t\tadditionalProperties: [\"object\"],\n\t\t\titems: [\"array\"],\n\t\t\tenum: [\n\t\t\t\t\"string\",\n\t\t\t\t\"number\",\n\t\t\t\t\"integer\",\n\t\t\t\t\"boolean\",\n\t\t\t\t\"null\"\n\t\t\t],\n\t\t\tconst: [\n\t\t\t\t\"string\",\n\t\t\t\t\"number\",\n\t\t\t\t\"integer\",\n\t\t\t\t\"boolean\",\n\t\t\t\t\"null\"\n\t\t\t]\n\t\t})) if (Object.hasOwn(node, key) && !types.includes(schemaType)) violations.push(`${path}.${key} is not supported on type \"${schemaType}\"`);\n\t\tswitch (schemaType) {\n\t\t\tcase \"object\": {\n\t\t\t\tconst properties = Object.hasOwn(node, \"properties\") ? node.properties : void 0;\n\t\t\t\ttasks.push({\n\t\t\t\t\tkind: \"object-tail\",\n\t\t\t\t\tnode,\n\t\t\t\t\tpath,\n\t\t\t\t\tproperties\n\t\t\t\t});\n\t\t\t\tif (Object.hasOwn(node, \"properties\")) if (!isJsonSchemaRecord(properties)) violations.push(`${path}.properties must be an object of schemas`);\n\t\t\t\telse {\n\t\t\t\t\tconst entries = Object.entries(properties);\n\t\t\t\t\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\t\t\t\t\tconst entry = entries[index];\n\t\t\t\t\t\t/* v8 ignore next -- the loop is bounded by the captured entry count. */\n\t\t\t\t\t\tif (entry === void 0) continue;\n\t\t\t\t\t\ttasks.push({\n\t\t\t\t\t\t\tkind: \"enter\",\n\t\t\t\t\t\t\tnode: entry[1],\n\t\t\t\t\t\t\tpath: `${path}.properties.${entry[0]}`\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"array\":\n\t\t\t\tif (Object.hasOwn(node, \"items\")) tasks.push({\n\t\t\t\t\tkind: \"enter\",\n\t\t\t\t\tnode: node.items,\n\t\t\t\t\tpath: `${path}.items`\n\t\t\t\t});\n\t\t\t\tbreak;\n\t\t\tcase \"string\":\n\t\t\tcase \"number\":\n\t\t\tcase \"integer\":\n\t\t\tcase \"boolean\":\n\t\t\tcase \"null\": {\n\t\t\t\tconst hasEnum = Object.hasOwn(node, \"enum\");\n\t\t\t\tconst allowed = hasEnum ? node.enum : void 0;\n\t\t\t\tconst enumValid = isPlainJsonArray(allowed) && allowed.length > 0 && allowed.every((entry) => scalarMatches(schemaType, entry));\n\t\t\t\tif (hasEnum && !enumValid) violations.push(`${path}.enum must be a non-empty array of ${schemaType} values`);\n\t\t\t\tconst hasConst = Object.hasOwn(node, \"const\");\n\t\t\t\tconst declaredConst = hasConst ? node.const : void 0;\n\t\t\t\tconst constValid = scalarMatches(schemaType, declaredConst);\n\t\t\t\tif (hasConst) {\n\t\t\t\t\tif (!constValid) violations.push(`${path}.const must be a ${schemaType} value`);\n\t\t\t\t\telse if (enumValid && !allowed.includes(declaredConst)) violations.push(`${path}.const must be one of ${path}.enum when both are declared`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\t/* v8 ignore next -- schemaType was narrowed from the closed SCHEMA_TYPES table above. */\n\t\t\tdefault: assertNever(schemaType, \"JsonSchemaType\");\n\t\t}\n\t}\n}\n/**\n* Assert the enforced subset plus the object-root constraint retained by\n* subagent and workflow structured outputs.\n* @param schema - untrusted caller-supplied schema.\n* @returns Assertion that the schema belongs to the supported subset and has an object root.\n*/\nfunction assertObjectJsonSchema(schema) {\n\tconst violations = [];\n\tcheckSchemaNode(schema, \"schema\", violations, /* @__PURE__ */ new Set());\n\tif (violations.length === 0 && (!isJsonSchemaRecord(schema) || !Object.hasOwn(schema, \"type\") || schema.type !== \"object\")) violations.push(\"schema.type must be \\\"object\\\" (structured output is object-rooted)\");\n\tif (violations.length > 0) throw new JsonSchemaError(violations);\n}\n//#endregion\n//#region packages/workflow/workflow/src/index.ts\n/**\n* Typed error for workflow-seam failures. Extends {@link HarnessError}, so the\n* `code` is machine-routable taxonomy. `fatal` drives the combinator\n* discipline: `parallel()`/`pipeline()` re-throw a fatal error (a typo'd\n* option or a tripped cap must kill the script loudly), and reserve the\n* per-item `null` for child-run failures and ordinary in-stage script errors.\n* Every {@link WorkflowErrorCode} is fatal; the flag exists so the\n* distinction is explicit at every catch site rather than implied.\n*/\nvar WorkflowError = class extends HarnessError {\n\t/** Whether combinators must propagate this error instead of nulling the item. */\n\tfatal;\n\tconstructor(message, code, options) {\n\t\tsuper(message, code, options);\n\t\tthis.name = \"WorkflowError\";\n\t\tthis.fatal = options?.fatal ?? true;\n\t}\n};\n/**\n* Whether combinators must re-throw `error` instead of mapping the item to `null`.\n* @param error - any thrown value; fatality is host `instanceof` (unforgeable from a script realm).\n* @returns true iff `error` is a {@link WorkflowError} whose `fatal` flag is set.\n*/\nfunction isFatalWorkflowError(error) {\n\treturn error instanceof WorkflowError && error.fatal;\n}\n//#endregion\n//#region packages/workflow/workflow-ptc/src/runtime.ts\n/**\n* Workflow VM hooks, child callbacks, ordinary concurrency limits and result serialization.\n* PTC owns process confinement and cancellation. Fatal hook and provider failures propagate\n* through combinators; ordinary child failures and stage errors become per-item nulls.\n* @module @deepseek-ai/dsh-workflow-ptc/runtime\n*/\n/** The `agent()` options the script may pass; everything else rejects loud. */\nconst SUPPORTED_AGENT_OPTIONS = new Set([\n\t\"label\",\n\t\"phase\",\n\t\"schema\",\n\t\"provider\",\n\t\"model\"\n]);\n/** Deferred Claude Code options we name explicitly in the rejection message. */\nconst DEFERRED_AGENT_OPTIONS = new Set([\n\t\"effort\",\n\t\"isolation\",\n\t\"agentType\"\n]);\n/** Flatten a child's final output blocks to text (the non-schema `agent()` result). */\nfunction outputText(blocks) {\n\treturn blocks.filter((block) => block.type === \"text\").map((block) => block.text).join(\"\");\n}\n/** A short display label derived from the prompt when the script passes none. */\nfunction defaultLabel(prompt) {\n\tconst newline = prompt.indexOf(\"\\n\");\n\tconst line = newline === -1 ? prompt : prompt.slice(0, newline);\n\treturn line.length <= 48 ? line : `${line.slice(0, 47)}\u2026`;\n}\n/**\n* One script execution inside the confined Node process. The host owns\n* cancellation and cleanup of any dropped child work.\n*/\nvar WorkflowExecution = class {\n\tlimits;\n\tobserver;\n\tchildren;\n\t/** 1-based count of `agent()` calls started (the `agentsStarted` result field). */\n\tstarted = 0;\n\tactiveSlots = 0;\n\tslotWaiters = [];\n\tcurrentPhase;\n\tcontext;\n\tcompiled;\n\tconstructor(meta, body, args, limits, observer, children) {\n\t\tthis.limits = limits;\n\t\tthis.observer = observer;\n\t\tthis.children = children;\n\t\ttry {\n\t\t\tthis.compiled = new vm.Script(`(async () => {\\n${body}\\n})()`, {\n\t\t\t\tfilename: `workflow:${meta.name}`,\n\t\t\t\tlineOffset: -1\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthrow new WorkflowError(`workflow script does not parse: ${String(error)}`, \"SCRIPT_PARSE\", { cause: error });\n\t\t}\n\t\tthis.context = vm.createContext({}, { name: `workflow:${meta.name}` });\n\t\tconst globals = {\n\t\t\tagent: (prompt, opts) => this.contain(this.agent(prompt, opts)),\n\t\t\tparallel: (thunks) => this.contain(this.parallel(thunks)),\n\t\t\tpipeline: (items, ...stages) => this.contain(this.pipeline(items, stages)),\n\t\t\tphase: (title) => {\n\t\t\t\tthis.phase(title);\n\t\t\t},\n\t\t\tlog: (message) => {\n\t\t\t\tthis.log(message);\n\t\t\t},\n\t\t\targs\n\t\t};\n\t\tfor (const [key, value] of Object.entries(globals)) this.context[key] = typeof value === \"function\" ? Object.freeze(value) : value;\n\t}\n\t/**\n\t* Run the script and materialize its JSON return value.\n\t* @returns A completed or error result; script failures never reject.\n\t*/\n\tasync drive() {\n\t\ttry {\n\t\t\tconst scriptPromise = this.compiled.runInContext(this.context, { timeout: this.limits.syncTimeoutMs });\n\t\t\tconst raw = await this.contain(Promise.resolve(scriptPromise));\n\t\t\treturn {\n\t\t\t\tvalue: raw === void 0 ? null : this.materializeResult(raw),\n\t\t\t\tstopReason: \"completed\",\n\t\t\t\tagentsStarted: this.started\n\t\t\t};\n\t\t} catch (error) {\n\t\t\treturn {\n\t\t\t\tvalue: null,\n\t\t\t\tstopReason: \"error\",\n\t\t\t\terror: renderThrown(error),\n\t\t\t\tagentsStarted: this.started\n\t\t\t};\n\t\t}\n\t}\n\t/**\n\t* Attach a no-op rejection consumer WITHOUT changing what the caller\n\t* receives: if the script drops the promise, a host rejection cannot become\n\t* an unhandled rejection that kills the process; if\n\t* the script does await it, it still observes the rejection.\n\t*/\n\tcontain(promise) {\n\t\tpromise.catch(() => {});\n\t\treturn promise;\n\t}\n\t/** Materialize the script's return value; violations become RESULT_UNSERIALIZABLE. */\n\tmaterializeResult(raw) {\n\t\ttry {\n\t\t\treturn materializeFromRealm(raw, \"workflow result\");\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n\t\t\tif (!(error instanceof MaterializeError)) throw error;\n\t\t\tthrow new WorkflowError(`the workflow's return value is not plain JSON data \u2014 ${error.message}. Return only JSON-serializable objects/arrays/scalars.`, \"RESULT_UNSERIALIZABLE\", { cause: error });\n\t\t}\n\t}\n\t/** Acquire one concurrency slot in FIFO order. */\n\tacquireSlot() {\n\t\tif (this.activeSlots < this.limits.maxConcurrentAgents) {\n\t\t\tthis.activeSlots += 1;\n\t\t\treturn Promise.resolve();\n\t\t}\n\t\treturn new Promise((resolve) => {\n\t\t\tthis.slotWaiters.push(() => {\n\t\t\t\tthis.activeSlots += 1;\n\t\t\t\tresolve();\n\t\t\t});\n\t\t});\n\t}\n\treleaseSlot() {\n\t\tthis.activeSlots -= 1;\n\t\tconst next = this.slotWaiters.shift();\n\t\tif (next) next();\n\t}\n\t/** The `agent(prompt, opts)` hook. */\n\tasync agent(rawPrompt, rawOpts) {\n\t\tif (typeof rawPrompt !== \"string\" || rawPrompt.length === 0) throw new WorkflowError(\"agent() requires a non-empty prompt string\", \"INVALID_ARGUMENT\");\n\t\tconst opts = this.readAgentOptions(rawOpts);\n\t\tif (this.started >= this.limits.maxTotalAgents) throw new WorkflowError(`this run reached its total agent cap (${this.limits.maxTotalAgents}) \u2014 a runaway-loop backstop; raise the applicable maxTotalAgents limit if the scale is intentional`, \"AGENT_CAP\");\n\t\tthis.started += 1;\n\t\tconst seq = this.started;\n\t\tconst label = opts.label ?? defaultLabel(rawPrompt);\n\t\tconst phase = opts.phase ?? this.currentPhase;\n\t\tawait this.acquireSlot();\n\t\ttry {\n\t\t\tlet run;\n\t\t\ttry {\n\t\t\t\trun = await this.children.startAgent({\n\t\t\t\t\tprompt: rawPrompt,\n\t\t\t\t\t...opts.schema !== void 0 ? { schema: opts.schema } : {},\n\t\t\t\t\t...opts.provider !== void 0 ? { provider: opts.provider } : {},\n\t\t\t\t\t...opts.model !== void 0 ? { model: opts.model } : {}\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tthrow new WorkflowError(`agent() could not start a child: ${renderThrown(error)}`, \"AGENT_START\", { cause: error });\n\t\t\t}\n\t\t\tconst info = {\n\t\t\t\tseq,\n\t\t\t\tlabel,\n\t\t\t\t...phase !== void 0 ? { phase } : {},\n\t\t\t\tchildId: brandString(run.id)\n\t\t\t};\n\t\t\tthis.observer.agentStart(info);\n\t\t\ttry {\n\t\t\t\tlet result;\n\t\t\t\ttry {\n\t\t\t\t\tresult = await run.result;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t\t});\n\t\t\t\t\tthrow new WorkflowError(`child agent run failed: ${renderThrown(error)}`, \"AGENT_RESULT\", { cause: error });\n\t\t\t\t}\n\t\t\t\tif (result.stopReason === \"completed\") {\n\t\t\t\t\tif (opts.schema !== void 0) {\n\t\t\t\t\t\tif (result.structured === void 0) {\n\t\t\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\treturn null;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t\t...info,\n\t\t\t\t\t\t\toutcome: \"completed\"\n\t\t\t\t\t\t});\n\t\t\t\t\t\treturn result.structured;\n\t\t\t\t\t}\n\t\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t\t...info,\n\t\t\t\t\t\toutcome: \"completed\"\n\t\t\t\t\t});\n\t\t\t\t\treturn outputText(result.output);\n\t\t\t\t}\n\t\t\t\tthis.observer.agentEnd({\n\t\t\t\t\t...info,\n\t\t\t\t\toutcome: \"failed\"\n\t\t\t\t});\n\t\t\t\treturn null;\n\t\t\t} finally {\n\t\t\t\tawait run.dispose();\n\t\t\t}\n\t\t} finally {\n\t\t\tthis.releaseSlot();\n\t\t}\n\t}\n\t/** Materialize + validate the `agent()` options bag from the realm. */\n\treadAgentOptions(rawOpts) {\n\t\tif (rawOpts === void 0) return {};\n\t\tlet opts;\n\t\ttry {\n\t\t\topts = materializeFromRealm(rawOpts, \"agent() options\");\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: materializeFromRealm only throws MaterializeError */\n\t\t\tif (!(error instanceof MaterializeError)) throw error;\n\t\t\tthrow new WorkflowError(`agent() options must be plain JSON data \u2014 ${error.message}`, \"INVALID_ARGUMENT\", { cause: error });\n\t\t}\n\t\tif (typeof opts !== \"object\" || opts === null || Array.isArray(opts)) throw new WorkflowError(\"agent() options must be an object\", \"INVALID_ARGUMENT\");\n\t\tconst record = opts;\n\t\tfor (const key of Object.keys(record)) {\n\t\t\tif (SUPPORTED_AGENT_OPTIONS.has(key)) continue;\n\t\t\tif (DEFERRED_AGENT_OPTIONS.has(key)) throw new WorkflowError(`agent() option \"${key}\" is deferred and not supported by this engine (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n\t\t\tthrow new WorkflowError(`agent() option \"${key}\" is not recognized (supported: label, phase, schema, provider, model)`, \"UNSUPPORTED_OPTION\");\n\t\t}\n\t\tfor (const key of [\n\t\t\t\"label\",\n\t\t\t\"phase\",\n\t\t\t\"provider\",\n\t\t\t\"model\"\n\t\t]) if (record[key] !== void 0 && typeof record[key] !== \"string\") throw new WorkflowError(`agent() option \"${key}\" must be a string`, \"INVALID_ARGUMENT\");\n\t\tlet schema;\n\t\tif (record.schema !== void 0) try {\n\t\t\tassertObjectJsonSchema(record.schema);\n\t\t\tschema = record.schema;\n\t\t} catch (error) {\n\t\t\t/* v8 ignore next -- defensive rethrow arm: assertObjectJsonSchema only throws JsonSchemaError */\n\t\t\tif (!(error instanceof JsonSchemaError)) throw error;\n\t\t\tthrow new WorkflowError(`agent() schema is outside the supported subset \u2014 ${error.message}`, \"UNSUPPORTED_SCHEMA\", { cause: error });\n\t\t}\n\t\treturn {\n\t\t\t...record.label !== void 0 ? { label: record.label } : {},\n\t\t\t...record.phase !== void 0 ? { phase: record.phase } : {},\n\t\t\t...record.provider !== void 0 ? { provider: record.provider } : {},\n\t\t\t...record.model !== void 0 ? { model: record.model } : {},\n\t\t\t...schema !== void 0 ? { schema } : {}\n\t\t};\n\t}\n\t/** The `parallel(thunks)` hook: each thunk caught \u2192 `null`; fatal errors propagate. */\n\tasync parallel(rawThunks) {\n\t\tif (!Array.isArray(rawThunks)) throw new WorkflowError(\"parallel() requires an array of zero-argument functions\", \"INVALID_ARGUMENT\");\n\t\tthis.assertItemCap(rawThunks.length, \"parallel()\");\n\t\tconst thunks = rawThunks.map((thunk, index) => {\n\t\t\tif (typeof thunk !== \"function\") throw new WorkflowError(`parallel() item ${index} is not a function`, \"INVALID_ARGUMENT\");\n\t\t\treturn thunk;\n\t\t});\n\t\treturn Promise.all(thunks.map(async (thunk) => {\n\t\t\ttry {\n\t\t\t\treturn await thunk();\n\t\t\t} catch (error) {\n\t\t\t\tif (isFatalWorkflowError(error)) throw error;\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}));\n\t}\n\t/** The `pipeline(items, ...stages)` hook: per-item stage chains, NO cross-stage barrier. */\n\tasync pipeline(rawItems, rawStages) {\n\t\tif (!Array.isArray(rawItems)) throw new WorkflowError(\"pipeline() requires an items array\", \"INVALID_ARGUMENT\");\n\t\tthis.assertItemCap(rawItems.length, \"pipeline()\");\n\t\tif (rawStages.length === 0) throw new WorkflowError(\"pipeline() requires at least one stage function\", \"INVALID_ARGUMENT\");\n\t\tconst stages = rawStages.map((stage, index) => {\n\t\t\tif (typeof stage !== \"function\") throw new WorkflowError(`pipeline() stage ${index} is not a function`, \"INVALID_ARGUMENT\");\n\t\t\treturn stage;\n\t\t});\n\t\treturn Promise.all(rawItems.map(async (item, index) => {\n\t\t\tlet value = item;\n\t\t\ttry {\n\t\t\t\tfor (const stage of stages) value = await stage(value, item, index);\n\t\t\t\treturn value;\n\t\t\t} catch (error) {\n\t\t\t\tif (isFatalWorkflowError(error)) throw error;\n\t\t\t\treturn null;\n\t\t\t}\n\t\t}));\n\t}\n\tassertItemCap(length, hook) {\n\t\tif (length > this.limits.maxItemsPerCall) throw new WorkflowError(`${hook} received ${length} items \u2014 over the per-call cap (${this.limits.maxItemsPerCall}); split the work or raise maxItemsPerCall in the engine config`, \"ITEM_CAP\");\n\t}\n\t/** The `phase(title)` hook: sets the current label for subsequent `agent()` calls and notifies observers. */\n\tphase(title) {\n\t\tif (typeof title !== \"string\" || title.length === 0) throw new WorkflowError(\"phase() requires a non-empty title string\", \"INVALID_ARGUMENT\");\n\t\tthis.currentPhase = title;\n\t\tthis.observer.phase(title);\n\t}\n\t/** The `log(message)` hook: narration to observers. */\n\tlog(message) {\n\t\tif (typeof message !== \"string\") throw new WorkflowError(\"log() requires a message string\", \"INVALID_ARGUMENT\");\n\t\tthis.observer.log(message);\n\t}\n};\n//#endregion\n//#region packages/workflow/workflow-ptc/src/guest.ts\n/**\n* Run a workflow with one progress batch in flight. Drain progress before child\n* disposal and the terminal result; PTC and the host own cancellation and cleanup.\n* @param host - JSON callbacks owned by this workflow run.\n* @returns The script result after progress delivery; initialization failures reject.\n*/\nasync function runWorkflowGuest(host) {\n\tconst init = await host.begin({});\n\tlet queued = [];\n\tlet inFlight;\n\tlet progressError;\n\tconst flush = () => {\n\t\tif (inFlight !== void 0 || queued.length === 0) return;\n\t\tconst batch = queued;\n\t\tqueued = [];\n\t\tinFlight = host.progress(batch).then(() => {\n\t\t\tinFlight = void 0;\n\t\t\tflush();\n\t\t}, (error) => {\n\t\t\tprogressError = renderThrown(error);\n\t\t\tqueued = [];\n\t\t\tinFlight = void 0;\n\t\t});\n\t};\n\tconst send = (event) => {\n\t\tif (progressError !== void 0) return;\n\t\tqueued.push(event);\n\t\tflush();\n\t};\n\tconst drain = async () => {\n\t\twhile (inFlight !== void 0) await inFlight;\n\t};\n\tconst result = await new WorkflowExecution(init.meta, init.body, init.args, init.limits, {\n\t\tphase: (title) => {\n\t\t\tsend({\n\t\t\t\ttype: \"phase\",\n\t\t\t\ttitle\n\t\t\t});\n\t\t},\n\t\tlog: (message) => {\n\t\t\tsend({\n\t\t\t\ttype: \"log\",\n\t\t\t\tmessage\n\t\t\t});\n\t\t},\n\t\tagentStart: (info) => {\n\t\t\tsend({\n\t\t\t\ttype: \"agent-start\",\n\t\t\t\tinfo\n\t\t\t});\n\t\t},\n\t\tagentEnd: (info) => {\n\t\t\tsend({\n\t\t\t\ttype: \"agent-end\",\n\t\t\t\tinfo\n\t\t\t});\n\t\t}\n\t}, { async startAgent(request) {\n\t\tconst { callId, childId } = await host.startChild(request);\n\t\tconst result = host.childResult({ callId });\n\t\tresult.catch(() => {});\n\t\treturn {\n\t\t\tid: childId,\n\t\t\tresult,\n\t\t\tasync dispose() {\n\t\t\t\tawait drain();\n\t\t\t\tawait host.disposeChild({ callId });\n\t\t\t}\n\t\t};\n\t} }).drive();\n\tawait drain();\n\treturn progressError === void 0 ? result : {\n\t\tvalue: null,\n\t\tstopReason: \"error\",\n\t\terror: progressError,\n\t\tagentsStarted: result.agentsStarted\n\t};\n}\n//#endregion\nexport { runWorkflowGuest };\n//# sourceURL=dsh-workflow-guest.js\n";
4
4
  //# sourceMappingURL=guest-source.d.ts.map
@@ -34,6 +34,7 @@ export declare class PtcWorkflowRun implements WorkflowRun {
34
34
  private cancelReason;
35
35
  private disposed;
36
36
  private readonly externalAbort;
37
+ private readonly cwd;
37
38
  constructor(ctx: Context, subagents: SubagentRuntime, runtime: PtcRuntime, id: WorkflowRunId, meta: WorkflowMeta, parent: Agent, init: WorkerInit, provider: string, policy: SandboxExecutionPolicy, observer: ExecutionObserver, signal?: AbortSignal | undefined);
38
39
  /**
39
40
  * Stop the script and abort pending and published children.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@deepseek-ai/dsh-workflow-ptc",
3
3
  "description": "Workflow orchestration in the shared sandboxed Node PTC runtime",
4
- "version": "0.2.0-rc.2",
4
+ "version": "0.2.1-alpha.2",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,46 +27,48 @@
27
27
  ],
28
28
  "license": "MIT",
29
29
  "peerDependencies": {
30
- "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
31
- "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
32
- "@deepseek-ai/cordis": "~4.0.4",
33
- "@deepseek-ai/dsh-subagent": "0.2.0-rc.2",
34
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
35
- "@deepseek-ai/dsh-workflow": "0.2.0-rc.2",
36
- "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2",
37
- "@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.2",
38
- "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2",
39
- "@deepseek-ai/dsh-session": "0.2.0-rc.2"
30
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1",
31
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
32
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.2",
33
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
34
+ "@deepseek-ai/dsh-subagent": "0.2.1-alpha.2",
35
+ "@deepseek-ai/dsh-tools": "0.2.1-alpha.2",
36
+ "@deepseek-ai/dsh-workflow": "0.2.1-alpha.2",
37
+ "@deepseek-ai/dsh-ptc-runtime": "0.2.1-alpha.2",
38
+ "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.2",
39
+ "@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.2",
40
+ "@deepseek-ai/dsh-working-directory": "0.2.1-alpha.2"
40
41
  },
41
42
  "dependencies": {
42
- "@deepseek-ai/dsh-brand": "0.2.0-rc.2",
43
- "@deepseek-ai/dsh-util-values": "0.2.0-rc.2",
44
- "@deepseek-ai/schemastery": "~3.18.4"
43
+ "@deepseek-ai/dsh-brand": "0.2.1-alpha.2",
44
+ "@deepseek-ai/dsh-util-values": "0.2.1-alpha.2",
45
+ "@deepseek-ai/schemastery": "~3.18.5-alpha.1"
45
46
  },
46
47
  "devDependencies": {
47
- "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.0-rc.2",
48
- "@deepseek-ai/cordis": "~4.0.4",
49
- "@deepseek-ai/dsh-agent": "0.2.0-rc.2",
50
- "@deepseek-ai/dsh-agent-loop": "0.2.0-rc.2",
51
- "@deepseek-ai/dsh-agent-loop-testkit": "0.2.0-rc.2",
52
- "@deepseek-ai/dsh-invariants": "0.2.0-rc.2",
53
- "@deepseek-ai/dsh-llm": "0.2.0-rc.2",
54
- "@deepseek-ai/dsh-session": "0.2.0-rc.2",
55
- "@deepseek-ai/dsh-session-projection": "0.2.0-rc.2",
56
- "@deepseek-ai/dsh-subagent": "0.2.0-rc.2",
57
- "@deepseek-ai/dsh-subagent-spawn-in-process": "0.2.0-rc.2",
58
- "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
59
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
60
- "@deepseek-ai/dsh-workflow": "0.2.0-rc.2",
61
- "@deepseek-ai/dsh-http-proxy": "0.2.0-rc.2",
62
- "@deepseek-ai/dsh-ptc-runtime": "0.2.0-rc.2",
63
- "@deepseek-ai/dsh-sandbox": "0.2.0-rc.2",
64
- "@deepseek-ai/dsh-sandbox-policy": "0.2.0-rc.2",
65
- "@deepseek-ai/dsh-ptc-runtime-node": "0.2.0-rc.2",
66
- "@deepseek-ai/dsh-fs": "0.2.0-rc.2",
67
- "@deepseek-ai/dsh-fs-local": "0.2.0-rc.2",
68
- "@deepseek-ai/dsh-subprocess": "0.2.0-rc.2",
69
- "@deepseek-ai/dsh-subprocess-local": "0.2.0-rc.2",
70
- "@deepseek-ai/dsh-sandbox-local": "0.2.0-rc.2"
48
+ "@deepseek-ai/dsh-llm-deepseek-api-key": "0.2.1-alpha.2",
49
+ "@deepseek-ai/cordis": "~4.0.5-alpha.1",
50
+ "@deepseek-ai/dsh-agent": "0.2.1-alpha.2",
51
+ "@deepseek-ai/dsh-agent-loop": "0.2.1-alpha.2",
52
+ "@deepseek-ai/dsh-agent-loop-testkit": "0.2.1-alpha.2",
53
+ "@deepseek-ai/dsh-llm": "0.2.1-alpha.2",
54
+ "@deepseek-ai/dsh-session": "0.2.1-alpha.2",
55
+ "@deepseek-ai/dsh-session-projection": "0.2.1-alpha.2",
56
+ "@deepseek-ai/dsh-subagent": "0.2.1-alpha.2",
57
+ "@deepseek-ai/dsh-subagent-spawn-in-process": "0.2.1-alpha.2",
58
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-alpha.2",
59
+ "@deepseek-ai/dsh-tools": "0.2.1-alpha.2",
60
+ "@deepseek-ai/dsh-workflow": "0.2.1-alpha.2",
61
+ "@deepseek-ai/dsh-http-proxy": "0.2.1-alpha.2",
62
+ "@deepseek-ai/dsh-ptc-runtime": "0.2.1-alpha.2",
63
+ "@deepseek-ai/dsh-sandbox": "0.2.1-alpha.2",
64
+ "@deepseek-ai/dsh-sandbox-policy": "0.2.1-alpha.2",
65
+ "@deepseek-ai/dsh-ptc-runtime-node": "0.2.1-alpha.2",
66
+ "@deepseek-ai/dsh-fs": "0.2.1-alpha.2",
67
+ "@deepseek-ai/dsh-fs-local": "0.2.1-alpha.2",
68
+ "@deepseek-ai/dsh-subprocess": "0.2.1-alpha.2",
69
+ "@deepseek-ai/dsh-subprocess-local": "0.2.1-alpha.2",
70
+ "@deepseek-ai/dsh-sandbox-local": "0.2.1-alpha.2",
71
+ "@deepseek-ai/dsh-session-persistence-jsonl": "0.2.1-alpha.2",
72
+ "@deepseek-ai/dsh-working-directory": "0.2.1-alpha.2"
71
73
  }
72
74
  }