taskflow-core 0.2.2 → 0.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +4 -3
  2. package/dist/agents.d.ts +2 -2
  3. package/dist/agents.d.ts.map +1 -1
  4. package/dist/build-info.json +2 -2
  5. package/dist/compile.d.ts +8 -1
  6. package/dist/compile.d.ts.map +1 -1
  7. package/dist/compile.js +75 -9
  8. package/dist/compile.js.map +1 -1
  9. package/dist/detached-control.d.ts +52 -0
  10. package/dist/detached-control.d.ts.map +1 -0
  11. package/dist/detached-control.js +251 -0
  12. package/dist/detached-control.js.map +1 -0
  13. package/dist/detached-runner.js +183 -30
  14. package/dist/detached-runner.js.map +1 -1
  15. package/dist/exec/driver.d.ts +5 -0
  16. package/dist/exec/driver.d.ts.map +1 -1
  17. package/dist/exec/driver.js +98 -52
  18. package/dist/exec/driver.js.map +1 -1
  19. package/dist/exec/kernel-policy.d.ts.map +1 -1
  20. package/dist/exec/kernel-policy.js +20 -20
  21. package/dist/exec/kernel-policy.js.map +1 -1
  22. package/dist/exec/step-kinds.d.ts.map +1 -1
  23. package/dist/exec/step-kinds.js +59 -22
  24. package/dist/exec/step-kinds.js.map +1 -1
  25. package/dist/exec/step.d.ts.map +1 -1
  26. package/dist/exec/step.js +44 -10
  27. package/dist/exec/step.js.map +1 -1
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.d.ts.map +1 -1
  30. package/dist/index.js +2 -0
  31. package/dist/index.js.map +1 -1
  32. package/dist/runner-core.d.ts.map +1 -1
  33. package/dist/runner-core.js +10 -0
  34. package/dist/runner-core.js.map +1 -1
  35. package/dist/runtime.d.ts +13 -0
  36. package/dist/runtime.d.ts.map +1 -1
  37. package/dist/runtime.js +81 -38
  38. package/dist/runtime.js.map +1 -1
  39. package/dist/store.d.ts +41 -2
  40. package/dist/store.d.ts.map +1 -1
  41. package/dist/store.js +489 -180
  42. package/dist/store.js.map +1 -1
  43. package/dist/verifiers/discover.d.ts +44 -0
  44. package/dist/verifiers/discover.d.ts.map +1 -0
  45. package/dist/verifiers/discover.js +152 -0
  46. package/dist/verifiers/discover.js.map +1 -0
  47. package/dist/verifiers/index.d.ts +12 -0
  48. package/dist/verifiers/index.d.ts.map +1 -0
  49. package/dist/verifiers/index.js +12 -0
  50. package/dist/verifiers/index.js.map +1 -0
  51. package/dist/verifiers/script-lint.d.ts +24 -0
  52. package/dist/verifiers/script-lint.d.ts.map +1 -0
  53. package/dist/verifiers/script-lint.js +311 -0
  54. package/dist/verifiers/script-lint.js.map +1 -0
  55. package/dist/verify.d.ts +55 -3
  56. package/dist/verify.d.ts.map +1 -1
  57. package/dist/verify.js +201 -2
  58. package/dist/verify.js.map +1 -1
  59. package/package.json +1 -1
@@ -16,17 +16,85 @@ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExte
16
16
  }
17
17
  return path;
18
18
  };
19
- import { readFileSync, rmdirSync, unlinkSync } from "node:fs";
20
- import { basename, dirname } from "node:path";
19
+ import { existsSync, lstatSync, readFileSync, realpathSync, rmdirSync, unlinkSync } from "node:fs";
20
+ import { tmpdir } from "node:os";
21
+ import { basename, dirname, isAbsolute, join, relative, sep } from "node:path";
21
22
  import { discoverAgents, readSubagentSettings } from "./agents.js";
22
23
  import { executeTaskflow } from "./runtime.js";
23
24
  import { cwdBridgeModeFromEnv } from "./cwd-bridge.js";
24
- import { getFlow, loadRun, saveRun, DEFAULT_KEPT_RUNS, DEFAULT_RUN_AGE_DAYS } from "./store.js";
25
+ import { bumpReuseInSidecar, getFlow, loadRun, runsDir, saveRun, traceFilePath, DEFAULT_KEPT_RUNS, DEFAULT_RUN_AGE_DAYS, } from "./store.js";
26
+ import { clearDetachedCancelRequest, clearDetachedProcessRegistry, DETACHED_CONTROL_CWD_ENV, DETACHED_CONTROL_INSTANCE_ENV, DETACHED_CONTROL_OWNER_PID_ENV, DETACHED_CONTROL_RUN_ID_ENV, DETACHED_CONTROL_SIGNAL_READY_ENV, heartbeatDetachedProcessRegistry, terminateDetachedProcessTrees, watchDetachedCancel, } from "./detached-control.js";
27
+ import { FileTraceSink } from "./trace.js";
28
+ const START_GATE_TIMEOUT_MS = 5_000;
29
+ /**
30
+ * The spawn-only entry consumes and deletes its context file. Refuse arbitrary
31
+ * command-line paths so a direct or malformed invocation cannot turn that
32
+ * one-shot cleanup into an unlink primitive outside Taskflow's private temp
33
+ * directory.
34
+ */
35
+ function isPrivateDetachContextPath(candidate) {
36
+ if (!isAbsolute(candidate) || basename(candidate) !== "context.json")
37
+ return false;
38
+ const parent = dirname(candidate);
39
+ if (!basename(parent).startsWith("taskflow-detach-"))
40
+ return false;
41
+ try {
42
+ const tempRoot = realpathSync(tmpdir());
43
+ const realParent = realpathSync(parent);
44
+ const rel = relative(tempRoot, realParent);
45
+ if (rel === ".." || rel.startsWith(`..${sep}`) || isAbsolute(rel)) {
46
+ return false;
47
+ }
48
+ const parentStat = lstatSync(parent);
49
+ const fileStat = lstatSync(candidate);
50
+ if (!parentStat.isDirectory() || parentStat.isSymbolicLink())
51
+ return false;
52
+ if (!fileStat.isFile() || fileStat.isSymbolicLink())
53
+ return false;
54
+ if (typeof process.getuid === "function") {
55
+ const uid = process.getuid();
56
+ if (parentStat.uid !== uid || fileStat.uid !== uid)
57
+ return false;
58
+ }
59
+ return true;
60
+ }
61
+ catch {
62
+ return false;
63
+ }
64
+ }
65
+ async function waitForStartGate(contextDir) {
66
+ const startPath = join(contextDir, "start");
67
+ const deadline = Date.now() + START_GATE_TIMEOUT_MS;
68
+ while (Date.now() < deadline) {
69
+ if (existsSync(startPath)) {
70
+ try {
71
+ unlinkSync(startPath);
72
+ }
73
+ catch { /* consumed concurrently */ }
74
+ return true;
75
+ }
76
+ await new Promise((resolve) => setTimeout(resolve, 25));
77
+ }
78
+ return false;
79
+ }
80
+ function cleanupContextDir(contextPath) {
81
+ const parent = dirname(contextPath);
82
+ if (basename(parent).startsWith("taskflow-detach-")) {
83
+ try {
84
+ rmdirSync(parent);
85
+ }
86
+ catch { /* not empty / already gone */ }
87
+ }
88
+ }
25
89
  const contextPath = process.argv[2];
26
90
  if (!contextPath) {
27
91
  console.error("[detached-runner] Missing context file path argument");
28
92
  process.exit(1);
29
93
  }
94
+ if (!isPrivateDetachContextPath(contextPath)) {
95
+ console.error("[detached-runner] Refusing context outside a private taskflow-detach temp directory");
96
+ process.exit(1);
97
+ }
30
98
  let ctx;
31
99
  try {
32
100
  ctx = JSON.parse(readFileSync(contextPath, "utf-8"));
@@ -42,37 +110,67 @@ finally {
42
110
  unlinkSync(contextPath);
43
111
  }
44
112
  catch { /* best-effort one-shot file cleanup */ }
45
- const parent = dirname(contextPath);
46
- // Remove only an empty Taskflow temp directory. Recursive deletion here would
47
- // make this public spawn entry capable of deleting unrelated argv-selected
48
- // files merely because their parent happened to share the expected prefix.
49
- if (basename(parent).startsWith("taskflow-detach-")) {
50
- try {
51
- rmdirSync(parent);
52
- }
53
- catch { /* not empty / already gone */ }
54
- }
55
113
  }
56
- if (!ctx)
114
+ if (!ctx) {
115
+ cleanupContextDir(contextPath);
57
116
  process.exit(1);
117
+ }
58
118
  const cleanupConfig = { maxKeep: DEFAULT_KEPT_RUNS, maxAgeDays: DEFAULT_RUN_AGE_DAYS };
119
+ if (ctx.waitForStart && !(await waitForStartGate(dirname(contextPath)))) {
120
+ try {
121
+ const state = loadRun(ctx.cwd, ctx.runId);
122
+ if (state?.status === "running") {
123
+ state.status = "failed";
124
+ state.phases["__detach__"] = {
125
+ id: "__detach__",
126
+ status: "failed",
127
+ endedAt: Date.now(),
128
+ error: `Detached launch gate was not released within ${START_GATE_TIMEOUT_MS}ms.`,
129
+ };
130
+ saveRun(state, cleanupConfig);
131
+ }
132
+ }
133
+ catch { /* best-effort terminalization */ }
134
+ cleanupContextDir(contextPath);
135
+ process.exit(1);
136
+ }
137
+ cleanupContextDir(contextPath);
59
138
  try {
60
139
  const state = loadRun(ctx.cwd, ctx.runId);
61
140
  if (!state) {
62
141
  console.error(`[detached-runner] Run not found: ${ctx.runId}`);
63
142
  process.exit(1);
64
143
  }
65
- // Re-discover agents using the same settings as the host session.
144
+ process.env.TASKFLOW_DETACHED_RUNNER = "1";
145
+ let heartbeatTimer;
146
+ if (ctx.detachedInstanceId) {
147
+ process.env[DETACHED_CONTROL_CWD_ENV] = ctx.cwd;
148
+ process.env[DETACHED_CONTROL_RUN_ID_ENV] = ctx.runId;
149
+ process.env[DETACHED_CONTROL_INSTANCE_ENV] = ctx.detachedInstanceId;
150
+ process.env[DETACHED_CONTROL_OWNER_PID_ENV] = String(process.pid);
151
+ heartbeatDetachedProcessRegistry(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
152
+ heartbeatTimer = setInterval(() => {
153
+ try {
154
+ heartbeatDetachedProcessRegistry(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
155
+ }
156
+ catch { /* best-effort lease */ }
157
+ }, 1_000);
158
+ heartbeatTimer.unref();
159
+ }
160
+ // Prefer the execution context frozen by the parent. Legacy callers without
161
+ // a snapshot retain the old discovery fallback.
66
162
  const settings = readSubagentSettings();
67
- cleanupConfig.maxKeep = settings.taskflow.maxKeptRuns;
68
- cleanupConfig.maxAgeDays = settings.taskflow.maxRunAgeDays;
69
- const scope = state.def.agentScope ?? "user";
70
- const { agents } = discoverAgents(ctx.cwd, scope, settings.modelRoles, settings.taskflow);
163
+ cleanupConfig.maxKeep = ctx.maxKeptRuns ?? state.detachedRetention?.maxKeep ?? settings.taskflow.maxKeptRuns;
164
+ cleanupConfig.maxAgeDays = ctx.maxRunAgeDays ?? state.detachedRetention?.maxAgeDays ?? settings.taskflow.maxRunAgeDays;
165
+ const legacyDefaultScope = ctx.runnerFactoryExport ? "user" : "both";
166
+ const scope = ctx.agentScope ?? state.def.agentScope ?? legacyDefaultScope;
167
+ const agents = ctx.agents ?? discoverAgents(ctx.cwd, scope, settings.modelRoles, settings.taskflow).agents;
71
168
  // The host adapter injects its subagent runner. Core is host-neutral and
72
169
  // CANNOT spawn pi/codex itself, so without this every phase would fail with
73
170
  // "No subagent runner injected". Resolve the runner via a dynamic import of
74
171
  // the module path the host serialized into the context file.
75
- let runTask;
172
+ let injectedRunner;
173
+ let runnerLoadError;
76
174
  if (ctx.runnerModule) {
77
175
  try {
78
176
  const runnerMod = await import(__rewriteRelativeImportExtension(ctx.runnerModule));
@@ -82,14 +180,15 @@ try {
82
180
  ? exported(ctx.runnerConfig)
83
181
  : exported;
84
182
  if (runner && typeof runner.runTask === "function") {
85
- runTask = runner.runTask;
183
+ injectedRunner = runner;
86
184
  }
87
185
  else {
88
186
  console.error(`[detached-runner] '${exportName}' on '${ctx.runnerModule}' is not a SubagentRunner (missing runTask)`);
89
187
  }
90
188
  }
91
189
  catch (e) {
92
- console.error(`[detached-runner] Failed to load runner module '${ctx.runnerModule}': ${e instanceof Error ? e.message : String(e)}`);
190
+ runnerLoadError = e instanceof Error ? e.message : String(e);
191
+ console.error(`[detached-runner] Failed to load runner module '${ctx.runnerModule}': ${runnerLoadError}`);
93
192
  }
94
193
  }
95
194
  else {
@@ -100,30 +199,73 @@ try {
100
199
  // stub — burying the real cause (a bad module path, a compile-time specifier
101
200
  // bug, a missing export). Exiting non-zero here routes the real stderr
102
201
  // message into the host's early-exit crash guard, which persists it on the
103
- // run's synthetic __detach__ phase where it is pollable and debuggable.
104
- if (ctx.runnerModule && !runTask) {
202
+ // run's synthetic __detach__ phase where it is pollable and debuggable. The
203
+ // non-zero exit then lets the parent guard observe that terminal record
204
+ // without overwriting it; detached stdio itself is intentionally ignored.
205
+ if (ctx.runnerModule && !injectedRunner) {
105
206
  state.status = "failed";
106
207
  state.phases["__detach__"] = {
107
208
  id: "__detach__",
108
209
  status: "failed",
109
210
  endedAt: Date.now(),
110
- error: `Runner module failed to load: '${ctx.runnerModule}' (export '${ctx.runnerFactoryExport ?? ctx.runnerExport ?? "piSubagentRunner"}'). See detached-runner stderr for the import error.`,
211
+ error: `Runner module failed to load: '${ctx.runnerModule}' (export '${ctx.runnerFactoryExport ?? ctx.runnerExport ?? "piSubagentRunner"}'): ${runnerLoadError ?? "export is not a SubagentRunner"}`,
111
212
  };
112
213
  saveRun(state, cleanupConfig);
214
+ if (heartbeatTimer)
215
+ clearInterval(heartbeatTimer);
216
+ if (ctx.detachedInstanceId)
217
+ clearDetachedProcessRegistry(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
113
218
  process.exit(1);
114
219
  }
115
- const result = await executeTaskflow(state, {
220
+ const abortController = new AbortController();
221
+ const stopCancelWatch = watchDetachedCancel(ctx.cwd, ctx.runId, abortController, undefined, (request) => {
222
+ state.detachedCancel = request;
223
+ });
224
+ const abortForSignal = () => abortController.abort({ reason: "detached-process-signal" });
225
+ process.once("SIGTERM", abortForSignal);
226
+ process.once("SIGINT", abortForSignal);
227
+ process.once("SIGHUP", abortForSignal);
228
+ process.env[DETACHED_CONTROL_SIGNAL_READY_ENV] = "1";
229
+ const deps = {
116
230
  cwd: ctx.cwd,
117
231
  cwdBridgeMode: cwdBridgeModeFromEnv(),
118
232
  agents,
119
- globalThinking: settings.globalThinking,
233
+ globalThinking: ctx.globalThinking ?? settings.globalThinking,
120
234
  persist: (s) => saveRun(s, cleanupConfig),
121
- runTask,
235
+ runTask: injectedRunner?.runTask,
236
+ usageAccounting: injectedRunner?.usageAccounting,
237
+ signal: abortController.signal,
238
+ trace: new FileTraceSink(traceFilePath(runsDir(ctx.cwd), state.flowName, state.runId)),
122
239
  // No requestApproval — approval phases auto-reject in detached/CI mode
123
240
  // (safety: approval gates are never bypassed; the run records the rejection).
124
241
  loadFlow: (name) => getFlow(ctx.cwd, name)?.def,
125
- });
126
- saveRun(result.state, cleanupConfig);
242
+ };
243
+ if (ctx.incremental === true)
244
+ deps.cacheScopeDefault = "cross-run";
245
+ try {
246
+ const result = await executeTaskflow(state, deps);
247
+ result.state.finalOutput = result.finalOutput;
248
+ result.state.outputSourcePhaseId = result.outputSourcePhaseId;
249
+ saveRun(result.state, cleanupConfig);
250
+ if (result.ok && ctx.reusedSavedName) {
251
+ try {
252
+ bumpReuseInSidecar(ctx.cwd, ctx.reusedSavedName);
253
+ }
254
+ catch { /* best-effort */ }
255
+ }
256
+ }
257
+ finally {
258
+ stopCancelWatch();
259
+ if (heartbeatTimer)
260
+ clearInterval(heartbeatTimer);
261
+ clearDetachedCancelRequest(ctx.cwd, ctx.runId);
262
+ if (ctx.detachedInstanceId)
263
+ clearDetachedProcessRegistry(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
264
+ delete process.env[DETACHED_CONTROL_SIGNAL_READY_ENV];
265
+ process.removeListener("SIGTERM", abortForSignal);
266
+ process.removeListener("SIGINT", abortForSignal);
267
+ process.removeListener("SIGHUP", abortForSignal);
268
+ }
127
269
  }
128
270
  catch (e) {
129
271
  // Top-level catch: persist failure so the host can poll the terminal state.
@@ -133,12 +275,23 @@ catch (e) {
133
275
  const state = loadRun(ctx.cwd, ctx.runId);
134
276
  if (state && state.status === "running") {
135
277
  state.status = "failed";
278
+ state.phases["__detach__"] = {
279
+ id: "__detach__",
280
+ status: "failed",
281
+ endedAt: Date.now(),
282
+ error: message.slice(0, 2_000),
283
+ };
136
284
  saveRun(state, cleanupConfig);
137
285
  }
138
286
  }
139
287
  catch {
140
288
  // Best-effort — if we can't even load the state, there's nothing to persist.
141
289
  }
290
+ if (ctx.detachedInstanceId)
291
+ terminateDetachedProcessTrees(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
292
+ clearDetachedCancelRequest(ctx.cwd, ctx.runId);
293
+ if (ctx.detachedInstanceId)
294
+ clearDetachedProcessRegistry(ctx.cwd, ctx.runId, ctx.detachedInstanceId);
142
295
  process.exit(1);
143
296
  }
144
297
  //# sourceMappingURL=detached-runner.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"detached-runner.js","sourceRoot":"","sources":["../src/detached-runner.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"detached-runner.js","sourceRoot":"","sources":["../src/detached-runner.ts"],"names":[],"mappings":"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"}
@@ -11,6 +11,7 @@ import type { TraceSink } from "../trace.ts";
11
11
  import { EVENT_KERNEL_PHASE_TYPES, type KernelApprovalDecision, type KernelApprovalRequest, type RunTaskFn } from "./step.ts";
12
12
  import type { AgentConfig } from "../agents.ts";
13
13
  import type { UsageStats } from "../usage.ts";
14
+ import type { TaskflowVerifier } from "../verify.ts";
14
15
  import { kernelUnsupportedReason } from "./kernel-policy.ts";
15
16
  export { EVENT_KERNEL_PHASE_TYPES, kernelUnsupportedReason };
16
17
  export interface EventKernelDeps {
@@ -26,6 +27,10 @@ export interface EventKernelDeps {
26
27
  eventKernel?: boolean;
27
28
  requestApproval?: (req: KernelApprovalRequest) => Promise<KernelApprovalDecision>;
28
29
  loadFlow?: (name: string) => Taskflow | undefined;
30
+ /** Caller-supplied zero-token verifiers (see verify.ts). Run in runNested's
31
+ * plugin-error preflight before every child-flow dispatch on this engine, and
32
+ * recursed via the ...deps spread. */
33
+ verifiers?: TaskflowVerifier[];
29
34
  _stack?: string[];
30
35
  _dynamic?: boolean;
31
36
  }
@@ -1 +1 @@
1
- {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/exec/driver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAA2C,KAAK,MAAM,EAAc,KAAK,QAAQ,EAAoB,MAAM,cAAc,CAAC;AAGjI,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EACN,wBAAwB,EAExB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE1B,KAAK,SAAS,EAGd,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAIN,uBAAuB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAClF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;IAClD,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,UAAU,CAAC;IACvB;;;qEAGiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,QAAQ,EACb,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,EACjD,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,EAC7B,eAAe,CAAC,EAAE,MAAM,GACtB,OAAO,CAyCT;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAI3E;AA4DD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CA2SvG"}
1
+ {"version":3,"file":"driver.d.ts","sourceRoot":"","sources":["../../src/exec/driver.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAA2C,KAAK,MAAM,EAAc,KAAK,QAAQ,EAAoB,MAAM,cAAc,CAAC;AAGjI,OAAO,KAAK,EAAc,SAAS,EAAE,MAAM,aAAa,CAAC;AAGzD,OAAO,EACN,wBAAwB,EAExB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAE1B,KAAK,SAAS,EAGd,MAAM,WAAW,CAAC;AAGnB,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAIN,uBAAuB,EACvB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,wBAAwB,EAAE,uBAAuB,EAAE,CAAC;AAE7D,MAAM,WAAW,eAAe;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,OAAO,EAAE,SAAS,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,WAAW,GAAG,aAAa,GAAG,aAAa,CAAC;IAC9D,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACpC,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;IACvC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,qBAAqB,KAAK,OAAO,CAAC,sBAAsB,CAAC,CAAC;IAClF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,CAAC;IAClD;;2CAEuC;IACvC,SAAS,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,iBAAiB;IACjC,KAAK,EAAE,QAAQ,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,EAAE,EAAE,OAAO,CAAC;IACZ,UAAU,EAAE,UAAU,CAAC;IACvB;;;qEAGiE;IACjE,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,qFAAqF;AACrF,wBAAgB,iBAAiB,CAChC,GAAG,EAAE,QAAQ,EACb,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,GAAG,SAAS,EACjD,IAAI,GAAE,GAAG,CAAC,MAAM,CAAa,EAC7B,eAAe,CAAC,EAAE,MAAM,GACtB,OAAO,CAyCT;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,OAAO,CAI3E;AA4DD;;;GAGG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,QAAQ,EAAE,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkXvG"}
@@ -13,6 +13,7 @@ import { safeParse } from "../interpolate.js";
13
13
  import { EVENT_KERNEL_PHASE_TYPES, stepPhase, } from "./step.js";
14
14
  import { foldEvents } from "./fold.js";
15
15
  import { EVENT_SCHEMA_VERSION } from "./events.js";
16
+ import { pluginVerifierErrors } from "../verify.js";
16
17
  import { clampSubFlowBudget, containsInterpolationPlaceholder, depsSatisfied, kernelUnsupportedReason, } from "./kernel-policy.js";
17
18
  export { EVENT_KERNEL_PHASE_TYPES, kernelUnsupportedReason };
18
19
  /** True when types are known AND no advanced features force imperative fall-back. */
@@ -189,6 +190,34 @@ export async function runEventKernel(state, deps) {
189
190
  blocked: false,
190
191
  };
191
192
  }
193
+ // Plugin-error verifier preflight (no-spend gate, zero-token). runNested is
194
+ // the single funnel for BOTH inline-def and saved-use child dispatch on this
195
+ // engine, so centralizing here covers every child flow (review of #84, issue
196
+ // 1). It runs BEFORE childState is created, so a blocked child never
197
+ // dispatches. Verifiers see the DECLARED child def (opts.def), not the
198
+ // budget-clamped effectiveDef, matching what the imperative path's verify
199
+ // sites observe: a budget/concurrency policy verifier must see the same
200
+ // declaration on both engines, or the event kernel would silently let a child
201
+ // it blocks on the imperative path go on to spend.
202
+ //
203
+ // Built-in graph detectors (dead-ends, unreachable, …) are intentionally NOT
204
+ // run here: this is a plugin-only gate, matching the top-level preflight's
205
+ // advisory treatment of built-ins. It costs nothing reachable — the only
206
+ // error-severity built-ins are `unreachable` and self-dependency, and neither
207
+ // can reach a dispatching event-kernel child. A flow nesting an unreachable
208
+ // child is itself kernel-ineligible (concurrent DAG layers), so it runs on the
209
+ // imperative path where the built-in detectors still run; a self-dependency is
210
+ // rejected by validateTaskflow above. (Pinned in verify-pluggable.test.ts.)
211
+ const pluginErrors = pluginVerifierErrors({ name: opts.def.name, phases: opts.def.phases, budget: opts.def.budget, concurrency: opts.def.concurrency }, deps.verifiers);
212
+ if (pluginErrors) {
213
+ return {
214
+ finalOutput: `Nested flow '${effectiveDef.name}' failed verifier preflight: ${pluginErrors.join("; ")}`,
215
+ ok: false,
216
+ usage: emptyUsage(),
217
+ events: [],
218
+ blocked: false,
219
+ };
220
+ }
192
221
  const childState = {
193
222
  // No `/` — validateRunId rejects path separators if ever persisted.
194
223
  runId: `${state.runId}-n-${effectiveDef.name.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 40)}`,
@@ -235,20 +264,12 @@ export async function runEventKernel(state, deps) {
235
264
  for (const layer of layers) {
236
265
  if (deps.signal?.aborted)
237
266
  break;
238
- for (const phase of layer) {
239
- if (deps.signal?.aborted)
240
- break;
241
- let skipReason;
242
- if (gateBlocked)
243
- skipReason = `Gate blocked${gateReason ? `: ${gateReason}` : ""}`;
244
- else if (budgetBlocked)
245
- skipReason = `Budget exceeded${budgetReason ? `: ${budgetReason}` : ""}`;
246
- else {
247
- const dep = depsSatisfied(phase, state.phases, byId);
248
- if (!dep.ok)
249
- skipReason = dep.skipReason;
250
- }
251
- if (skipReason) {
267
+ // --- Pre-layer gate/budget check: skip the entire layer if blocked ---
268
+ if (gateBlocked || budgetBlocked) {
269
+ for (const phase of layer) {
270
+ const skipReason = gateBlocked
271
+ ? `Gate blocked${gateReason ? `: ${gateReason}` : ""}`
272
+ : `Budget exceeded${budgetReason ? `: ${budgetReason}` : ""}`;
252
273
  if (skipReason.startsWith("Budget exceeded")) {
253
274
  budgetBlocked = true;
254
275
  const be = {
@@ -262,24 +283,50 @@ export async function runEventKernel(state, deps) {
262
283
  allEvents.push(be);
263
284
  safeTraceEmit(deps, be);
264
285
  }
265
- const startedAt = Date.now();
266
286
  emitLifecycle(deps, allEvents, state.runId, phase, "skipped", skipReason);
267
287
  state.phases[phase.id] = {
268
288
  id: phase.id,
269
289
  status: "skipped",
270
290
  error: skipReason,
271
- startedAt,
291
+ startedAt: Date.now(),
272
292
  endedAt: Date.now(),
273
293
  usage: emptyUsage(),
274
294
  };
275
- continue;
276
295
  }
296
+ continue;
297
+ }
298
+ const plans = layer.map((phase) => {
299
+ const dep = depsSatisfied(phase, state.phases, byId);
300
+ return { phase, skipReason: dep.ok ? undefined : dep.skipReason };
301
+ });
302
+ // Emit skips for dep-unsatisfied phases (sequential, cheap).
303
+ for (const { phase, skipReason } of plans) {
304
+ if (!skipReason)
305
+ continue;
306
+ emitLifecycle(deps, allEvents, state.runId, phase, "skipped", skipReason);
307
+ state.phases[phase.id] = {
308
+ id: phase.id,
309
+ status: "skipped",
310
+ error: skipReason,
311
+ startedAt: Date.now(),
312
+ endedAt: Date.now(),
313
+ usage: emptyUsage(),
314
+ };
315
+ }
316
+ // --- Execute runnable phases concurrently within the layer ---
317
+ const runnable = plans.filter((p) => !p.skipReason);
318
+ if (runnable.length === 0)
319
+ continue;
320
+ const outcomes = await Promise.all(runnable.map(async ({ phase }) => {
277
321
  const startedAt = Date.now();
278
- state.phases[phase.id] = { id: phase.id, status: "running", startedAt };
279
322
  const readRefs = [];
280
323
  const promptCalls = [];
281
324
  const ctx = { state, deps: stepDeps, steps, args, readRefs, promptCalls };
282
325
  const result = await stepPhase(phase, ctx);
326
+ return { phase, result, startedAt, readRefs, promptCalls };
327
+ }));
328
+ // --- Atomic layer commit: fold all outcomes into state ---
329
+ for (const { phase, result, startedAt, readRefs } of outcomes) {
283
330
  if (!result) {
284
331
  state.phases[phase.id] = {
285
332
  id: phase.id,
@@ -318,18 +365,13 @@ export async function runEventKernel(state, deps) {
318
365
  approval: result.approval,
319
366
  warnings: result.warnings,
320
367
  ...(observedReads.length ? { reads: observedReads } : {}),
321
- // Prompt-size diagnostics (parity with imperative PhaseState.promptStats).
322
368
  ...(result.promptStats ? { promptStats: result.promptStats } : {}),
323
- // Match the imperative audit marker: an idempotent:false phase
324
- // records that its side effect may have fired, unless its guard skipped
325
- // all execution.
326
369
  ...(phase.idempotent === false && result.status !== "skipped" ? { sideEffect: true } : {}),
327
370
  ...(result.status === "timedOut" ? { timedOut: true } : {}),
328
371
  };
329
372
  if (result.status === "done" && result.output !== undefined) {
330
373
  steps[phase.id] = {
331
374
  output: result.output,
332
- // Always best-effort parse so {steps.X.json.field} works for JSON agents
333
375
  json: phaseJson ?? safeParse(result.output),
334
376
  };
335
377
  }
@@ -339,35 +381,37 @@ export async function runEventKernel(state, deps) {
339
381
  gateOutput = result.output ?? "";
340
382
  gatePhaseId = phase.id;
341
383
  }
342
- const ob = runOverBudget(state);
343
- if (ob.over) {
344
- budgetBlocked = true;
345
- budgetReason = ob.reason;
346
- const be = {
347
- v: EVENT_SCHEMA_VERSION,
348
- ts: Date.now(),
349
- runId: state.runId,
350
- phaseId: phase.id,
351
- kind: "decision",
352
- decision: { type: "budget-hit", value: "budget", reason: ob.reason },
353
- };
354
- allEvents.push(be);
355
- safeTraceEmit(deps, be);
356
- // stepPhase already flushed this phase's lifecycle batch.
357
- safeTraceFlush(deps, phase.id);
358
- }
359
- try {
360
- deps.persist?.(state);
361
- }
362
- catch {
363
- /* fail-open */
364
- }
365
- try {
366
- deps.onProgress?.(state);
367
- }
368
- catch {
369
- /* fail-open */
370
- }
384
+ }
385
+ // --- Post-layer budget check ---
386
+ const ob = runOverBudget(state);
387
+ if (ob.over) {
388
+ budgetBlocked = true;
389
+ budgetReason = ob.reason;
390
+ // Attribute the budget-hit to the last phase in the layer.
391
+ const lastPhase = layer[layer.length - 1];
392
+ const be = {
393
+ v: EVENT_SCHEMA_VERSION,
394
+ ts: Date.now(),
395
+ runId: state.runId,
396
+ phaseId: lastPhase.id,
397
+ kind: "decision",
398
+ decision: { type: "budget-hit", value: "budget", reason: ob.reason },
399
+ };
400
+ allEvents.push(be);
401
+ safeTraceEmit(deps, be);
402
+ safeTraceFlush(deps, lastPhase.id);
403
+ }
404
+ try {
405
+ deps.persist?.(state);
406
+ }
407
+ catch {
408
+ /* fail-open */
409
+ }
410
+ try {
411
+ deps.onProgress?.(state);
412
+ }
413
+ catch {
414
+ /* fail-open */
371
415
  }
372
416
  }
373
417
  // Soft fold drift check
@@ -401,6 +445,8 @@ export async function runEventKernel(state, deps) {
401
445
  budget: budgetBlocked,
402
446
  budgetReason,
403
447
  });
448
+ state.finalOutput = finalOutput;
449
+ state.outputSourcePhaseId = outputSourcePhaseId;
404
450
  const totalUsage = aggregateUsage(Object.values(state.phases).map((p) => p.usage ?? emptyUsage()));
405
451
  try {
406
452
  deps.persist?.(state);