@relayflows/sdk 2.0.6 → 2.0.8

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.
@@ -1,5 +1,5 @@
1
1
  import type { CompletionReason as ProtocolCompletionReason, RunCompletionReason as ProtocolRunCompletionReason } from './protocol.js';
2
- export type AuthoredFlowExecutionErrorCode = 'duplicate_completion' | 'journal_protocol_violation' | 'missing_completion' | 'operation_after_completion' | 'operation_callback_failed' | 'step_failed' | 'unsupported_completion' | 'unsupported_gate' | 'unsupported_header' | 'unsettled_derived_work' | 'unsupported_promise_lifecycle' | 'unawaited_step' | 'unsupported_verb';
2
+ export type AuthoredFlowExecutionErrorCode = 'agent_cli_unresolved' | 'agent_parked' | 'duplicate_completion' | 'journal_protocol_violation' | 'missing_completion' | 'operation_after_completion' | 'operation_callback_failed' | 'step_failed' | 'unsupported_completion' | 'unsupported_gate' | 'unsupported_header' | 'unsettled_derived_work' | 'unsupported_promise_lifecycle' | 'unsupported_workspace_permission' | 'unawaited_step' | 'unsupported_verb';
3
3
  export declare class AuthoredFlowExecutionError extends Error {
4
4
  readonly code: AuthoredFlowExecutionErrorCode;
5
5
  readonly completionReason?: (ProtocolCompletionReason | ProtocolRunCompletionReason) | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-error.d.ts","sourceRoot":"","sources":["../src/authored-flow-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,IAAI,wBAAwB,EAC5C,mBAAmB,IAAI,2BAA2B,EACnD,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,8BAA8B,GACtC,sBAAsB,GACtB,4BAA4B,GAC5B,oBAAoB,GACpB,4BAA4B,GAC5B,2BAA2B,GAC3B,aAAa,GACb,wBAAwB,GACxB,kBAAkB,GAClB,oBAAoB,GACpB,wBAAwB,GACxB,+BAA+B,GAC/B,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,IAAI,EAAE,8BAA8B;IAE7C,QAAQ,CAAC,gBAAgB,CAAC,GAAE,wBAAwB,GAAG,2BAA2B;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;gBAHd,IAAI,EAAE,8BAA8B,EAC7C,OAAO,EAAE,MAAM,EACN,gBAAgB,CAAC,GAAE,wBAAwB,GAAG,2BAA2B,aAAA,EACzE,KAAK,CAAC,EAAE,MAAM,YAAA;CAK1B"}
1
+ {"version":3,"file":"authored-flow-error.d.ts","sourceRoot":"","sources":["../src/authored-flow-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,IAAI,wBAAwB,EAC5C,mBAAmB,IAAI,2BAA2B,EACnD,MAAM,eAAe,CAAC;AAEvB,MAAM,MAAM,8BAA8B,GACtC,sBAAsB,GACtB,cAAc,GACd,sBAAsB,GACtB,4BAA4B,GAC5B,oBAAoB,GACpB,4BAA4B,GAC5B,2BAA2B,GAC3B,aAAa,GACb,wBAAwB,GACxB,kBAAkB,GAClB,oBAAoB,GACpB,wBAAwB,GACxB,+BAA+B,GAC/B,kCAAkC,GAClC,gBAAgB,GAChB,kBAAkB,CAAC;AAEvB,qBAAa,0BAA2B,SAAQ,KAAK;IAEjD,QAAQ,CAAC,IAAI,EAAE,8BAA8B;IAE7C,QAAQ,CAAC,gBAAgB,CAAC,GAAE,wBAAwB,GAAG,2BAA2B;IAClF,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM;gBAHd,IAAI,EAAE,8BAA8B,EAC7C,OAAO,EAAE,MAAM,EACN,gBAAgB,CAAC,GAAE,wBAAwB,GAAG,2BAA2B,aAAA,EACzE,KAAK,CAAC,EAAE,MAAM,YAAA;CAK1B"}
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-error.js","sourceRoot":"","sources":["../src/authored-flow-error.ts"],"names":[],"mappings":"AAoBA,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAExC;IAEA;IACA;IAJX,YACW,IAAoC,EAC7C,OAAe,EACN,gBAAyE,EACzE,KAAc;QAEvB,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QALpB,SAAI,GAAJ,IAAI,CAAgC;QAEpC,qBAAgB,GAAhB,gBAAgB,CAAyD;QACzE,UAAK,GAAL,KAAK,CAAS;QAGvB,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF"}
1
+ {"version":3,"file":"authored-flow-error.js","sourceRoot":"","sources":["../src/authored-flow-error.ts"],"names":[],"mappings":"AAuBA,MAAM,OAAO,0BAA2B,SAAQ,KAAK;IAExC;IAEA;IACA;IAJX,YACW,IAAoC,EAC7C,OAAe,EACN,gBAAyE,EACzE,KAAc;QAEvB,KAAK,CAAC,GAAG,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;QALpB,SAAI,GAAJ,IAAI,CAAgC;QAEpC,qBAAgB,GAAhB,gBAAgB,CAAyD;QACzE,UAAK,GAAL,KAAK,CAAS;QAGvB,IAAI,CAAC,IAAI,GAAG,4BAA4B,CAAC;IAC3C,CAAC;CACF"}
@@ -1,4 +1,6 @@
1
1
  import type { FlowHandle } from '@relayflows/surface/runtime';
2
+ import type { GetFlowDefinition } from './authored-flow-loader.js';
3
+ import { type RunLifecycleOptions } from './cli/run.js';
2
4
  import { AuthoredFlowExecutionError, type AuthoredFlowExecutionErrorCode } from './authored-flow-error.js';
3
5
  import { JournalClient } from './journal-client.js';
4
6
  import type { CompletionReason as ProtocolCompletionReason, RunCompletionReason as ProtocolRunCompletionReason } from './protocol.js';
@@ -24,5 +26,29 @@ export interface AuthoredFlowExecutionResult {
24
26
  * `JournalClient`; values are read back from `step.completed` journal entries.
25
27
  * Unsupported headers, verbs, gates, or completion lowering fail closed.
26
28
  */
27
- export declare function executeAuthoredFlow<Input = undefined>(handle: FlowHandle, journal: JournalClient, input?: Input): Promise<AuthoredFlowExecutionResult>;
29
+ export interface ExecuteAuthoredFlowOptions {
30
+ /**
31
+ * Defaults to this package's own static import — correct for every
32
+ * existing (internal, single-instance) caller. A flow loaded from an
33
+ * external path via `loadAuthoredFlow` must pass ITS resolved
34
+ * `getDefinition` instead; see authored-flow-loader.ts's comment on why.
35
+ */
36
+ readonly getDefinition?: GetFlowDefinition;
37
+ /**
38
+ * The flow file's own path — passed straight to `checkAuthoredFlow`
39
+ * (cli/check.ts) so `f.agent` resolves a CLI the same way a declarative
40
+ * `type: agent` step does: nearest `flows.json`, real auth/model probing,
41
+ * canonicalized path. `checkAuthoredFlow` always does `dirname()` on this,
42
+ * matching `checkFlow`'s real `flows check <file>` contract — pass a FILE
43
+ * path, not a directory, or the search starts one level too high. Defaults
44
+ * to a synthetic `flow.ts` under `process.cwd()` for exactly this reason:
45
+ * `process.cwd()` itself is a directory, and `dirname(process.cwd())`
46
+ * would search cwd's PARENT.
47
+ */
48
+ readonly flowPath?: string;
49
+ /** Passed straight through to classifyOutcome (cli/run.ts) for f.agent's wait. */
50
+ readonly signal?: RunLifecycleOptions['signal'];
51
+ readonly onWait?: RunLifecycleOptions['onWait'];
52
+ }
53
+ export declare function executeAuthoredFlow<Input = undefined>(handle: FlowHandle, journal: JournalClient, input?: Input, options?: ExecuteAuthoredFlowOptions): Promise<AuthoredFlowExecutionResult>;
28
54
  //# sourceMappingURL=authored-flow-executor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-executor.d.ts","sourceRoot":"","sources":["../src/authored-flow-executor.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,EACL,0BAA0B,EAC1B,KAAK,8BAA8B,EACpC,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EACV,gBAAgB,IAAI,wBAAwB,EAC5C,mBAAmB,IAAI,2BAA2B,EAEnD,MAAM,eAAe,CAAC;AAqBvB,OAAO,EAAE,0BAA0B,EAAE,KAAK,8BAA8B,EAAE,CAAC;AAE3E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;CACrD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;IACvD,QAAQ,CAAC,YAAY,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC3D;AASD;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,GAAG,SAAS,EACzD,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,aAAa,EACtB,KAAK,CAAC,EAAE,KAAK,GACZ,OAAO,CAAC,2BAA2B,CAAC,CAwJtC"}
1
+ {"version":3,"file":"authored-flow-executor.d.ts","sourceRoot":"","sources":["../src/authored-flow-executor.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAI9D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAEnE,OAAO,EAAmB,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEzE,OAAO,EACL,0BAA0B,EAC1B,KAAK,8BAA8B,EACpC,MAAM,0BAA0B,CAAC;AAOlC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,KAAK,EACV,gBAAgB,IAAI,wBAAwB,EAC5C,mBAAmB,IAAI,2BAA2B,EAEnD,MAAM,eAAe,CAAC;AAqBvB,OAAO,EAAE,0BAA0B,EAAE,KAAK,8BAA8B,EAAE,CAAC;AAW3E,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,EAAE,wBAAwB,CAAC;CACrD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,EAAE,2BAA2B,CAAC;IACvD,QAAQ,CAAC,YAAY,EAAE,SAAS,uBAAuB,EAAE,CAAC;CAC3D;AASD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;;;OAKG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,iBAAiB,CAAC;IAC3C;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IAChD,QAAQ,CAAC,MAAM,CAAC,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CAAC;CACjD;AAED,wBAAsB,mBAAmB,CAAC,KAAK,GAAG,SAAS,EACzD,MAAM,EAAE,UAAU,EAClB,OAAO,EAAE,aAAa,EACtB,KAAK,CAAC,EAAE,KAAK,EACb,OAAO,GAAE,0BAA+B,GACvC,OAAO,CAAC,2BAA2B,CAAC,CA6PtC"}
@@ -1,24 +1,32 @@
1
1
  import { COMPLETION_REASONS, RUN_COMPLETION_REASONS, } from '@relayflows/surface';
2
+ import { join } from 'node:path';
2
3
  import { compileSpec, toKernelSpec } from './compile.js';
3
4
  import { getAuthoredFlowDefinition } from './authored-flow.js';
5
+ import { checkAuthoredFlow } from './cli/check.js';
6
+ import { classifyOutcome } from './cli/run.js';
4
7
  import { AuthoredFlowExecutionError, } from './authored-flow-error.js';
5
8
  import { AuthoredFlowOperation, stopAuthoredOperations, verifyAuthoredOperations, } from './authored-flow-operation.js';
6
9
  import { AuthoredFlowLifecycle } from './authored-flow-lifecycle.js';
7
10
  import { SPEC_SCHEMA_VERSION } from './spec.js';
8
11
  export { AuthoredFlowExecutionError };
9
12
  /**
10
- * Exercise the internal authored-flow lowering seam through protocol v0.
11
- *
12
- * This is deliberately not exported by the SDK package: without a durable
13
- * authored root, it is not a resumable public runner. The seam is narrow: an
14
- * empty-header flow may await plain `f.run(...)` steps and must finish with
15
- * `f.done("success")`. Every run and
16
- * the terminal marker is a compiled deterministic spec submitted through
17
- * `JournalClient`; values are read back from `step.completed` journal entries.
18
- * Unsupported headers, verbs, gates, or completion lowering fail closed.
13
+ * Matches the `"path/glob: readonly"` / `"path/glob: readwrite"` shorthand
14
+ * shown in docs/SURFACE.md and the examples — the only shape a workspace
15
+ * string could plausibly declare a permission in. No parser anywhere in this
16
+ * package turns that annotation into a real restriction, so `lowerAgent`
17
+ * refuses rather than silently accepting and ignoring it.
19
18
  */
20
- export async function executeAuthoredFlow(handle, journal, input) {
21
- const definition = getAuthoredFlowDefinition(handle);
19
+ const WORKSPACE_PERMISSION_ANNOTATION = /:\s*(readonly|readwrite)\s*$/i;
20
+ export async function executeAuthoredFlow(handle, journal, input, options = {}) {
21
+ const getDefinition = options.getDefinition ?? getAuthoredFlowDefinition;
22
+ const flowPath = options.flowPath ?? join(process.cwd(), 'flow.ts');
23
+ // Named separately from `options` because `lowerAgent` below has its own,
24
+ // differently-typed `options: AgentOptions` parameter that shadows this one.
25
+ const waitOptions = {
26
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
27
+ ...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
28
+ };
29
+ const definition = getDefinition(handle);
22
30
  const headerFields = Object.keys(definition.header);
23
31
  if (headerFields.length > 0) {
24
32
  throw new AuthoredFlowExecutionError('unsupported_header', `flow "${definition.name}" uses unsupported header fields: ${headerFields.join(', ')}`);
@@ -37,6 +45,74 @@ export async function executeAuthoredFlow(handle, journal, input) {
37
45
  const outcome = await journal.runStart(spec);
38
46
  return readSuccessfulOutput(journal, outcome, id, journalSteps);
39
47
  };
48
+ // `name` (the first f.agent argument, e.g. "fixer") is not wired to the
49
+ // kernel's `agent` field: that field selects a NAMED declaration from
50
+ // `FlowSpec.agents`, and this executor refuses every non-empty header
51
+ // (see the top of this function) — an authored flow has no way to declare
52
+ // one today. `name` is kept only for step-id readability; CLI selection
53
+ // goes through the project's flows.json default below, same as it does
54
+ // for a bare `type: agent` YAML step with no explicit `cli`.
55
+ const lowerAgent = async (id, options) => {
56
+ if (options.workspace !== undefined && WORKSPACE_PERMISSION_ANNOTATION.test(options.workspace)) {
57
+ throw new AuthoredFlowExecutionError('unsupported_workspace_permission', `flow "${definition.name}" step "${id}": workspace "${options.workspace}" declares a `
58
+ + 'permission annotation ("...: readonly" / "...: readwrite"), but nothing enforces it — '
59
+ + 'no parser anywhere in this package turns that annotation into a real restriction '
60
+ + '(kernel/DAEMON-LIFECYCLE.md\'s permission model is untouched by f.agent). '
61
+ + 'Silently accepting and ignoring it would let a flow believe a restriction is in effect '
62
+ + "when it is not. Declare a bare surface name (no trailing \": readonly\"/\": readwrite\") "
63
+ + 'if you do not need enforcement, or use the declarative spec\'s `permissions` field, which is real.');
64
+ }
65
+ const authoring = {
66
+ version: SPEC_SCHEMA_VERSION,
67
+ name: `${definition.name}/${id}`,
68
+ steps: [{
69
+ id,
70
+ type: 'agent',
71
+ instruction: options.task,
72
+ ...(options.workspace === undefined ? {} : {
73
+ surfaces: { workspace: [{ surface: options.workspace }] },
74
+ }),
75
+ }],
76
+ };
77
+ // The kernel never resolves a `cli` on its own — every declarative
78
+ // `flows run`/`flows check` binds it first via this exact function
79
+ // (cli/check.ts), searching for the nearest flows.json from `flowPath`
80
+ // and real-probing auth/model readiness. An authored agent step gets
81
+ // nothing for free just because it was declared in TS instead of YAML.
82
+ const { report, flow: resolved } = checkAuthoredFlow(authoring, flowPath);
83
+ if (!report.ok || resolved === undefined) {
84
+ const refusal = report.diagnostics.find((diagnostic) => diagnostic.severity === 'refusal');
85
+ throw new AuthoredFlowExecutionError('agent_cli_unresolved', refusal?.message
86
+ ?? `flow "${definition.name}" step "${id}": no CLI could be resolved for f.agent `
87
+ + `(searched for flows.json from "${flowPath}")`);
88
+ }
89
+ const spec = toKernelSpec(resolved);
90
+ const outcome = await journal.runStart(spec);
91
+ // Reuse the declarative CLI's own wait/classification (cli/run.ts) rather
92
+ // than a hand-rolled poll: `step.completed` and the run's own terminal
93
+ // state are appended as two SEPARATE actions (kernel/relayflowd-core/src/machine.rs
94
+ // completion_actions vs complete_run_actions), so a naive read right
95
+ // after runStart can race a real, valid completion — and a genuinely
96
+ // long-running agent has no reason to be bounded by anything other than
97
+ // its own worker's lease, which classifyOutcome already follows
98
+ // (renewing as the lease renews, per docs/SURFACE.md §5's WAITING
99
+ // [worker_lease] contract), never an unrelated fixed deadline.
100
+ const execution = await classifyOutcome(journal, 'run', outcome, report, '', waitOptions);
101
+ if (execution.exitCode === 3) {
102
+ const parked = execution.report.parkedStep;
103
+ throw new AuthoredFlowExecutionError('agent_parked', execution.report.diagnostics.at(-1)?.message
104
+ ?? `flow "${definition.name}" step "${id}" parked`
105
+ + (parked !== undefined ? ` (${parked.type})` : '')
106
+ + ': no worker is attached to run it.', undefined, outcome.run_id);
107
+ }
108
+ if (execution.exitCode !== 0) {
109
+ const reason = execution.report.completionReason;
110
+ throw new AuthoredFlowExecutionError('step_failed', execution.report.diagnostics.at(-1)?.message
111
+ ?? `flow "${definition.name}" step "${id}" did not complete successfully `
112
+ + `(status: ${execution.report.status ?? 'unknown'})`, isSurfaceCompletionReason(reason) ? reason : undefined, outcome.run_id);
113
+ }
114
+ return readSuccessfulAgentOutput(journal, outcome.run_id, id, journalSteps);
115
+ };
40
116
  const context = {
41
117
  run(command) {
42
118
  assertOperationAllowed('run', definition.name, requestedCompletion);
@@ -48,10 +124,11 @@ export async function executeAuthoredFlow(handle, journal, input) {
48
124
  const id = `llm-${nextStep++}`;
49
125
  return trackStep(authoredSteps, unsupportedStep(id, 'llm', () => assertOperationAllowed('llm', definition.name, requestedCompletion), lifecycle));
50
126
  },
51
- agent() {
127
+ agent(name, options) {
52
128
  assertOperationAllowed('agent', definition.name, requestedCompletion);
129
+ void name; // step-id readability only — see the comment on lowerAgent.
53
130
  const id = `agent-${nextStep++}`;
54
- return trackStep(authoredSteps, unsupportedStep(id, 'agent', () => assertOperationAllowed('agent', definition.name, requestedCompletion), lifecycle));
131
+ return trackStep(authoredSteps, new AuthoredFlowOperation(id, 'agent', () => assertOperationAllowed('agent', definition.name, requestedCompletion), () => lowerAgent(id, options), lifecycle));
55
132
  },
56
133
  human() {
57
134
  assertOperationAllowed('human', definition.name, requestedCompletion);
@@ -157,26 +234,66 @@ function unsupportedCloud(assertOpen) {
157
234
  },
158
235
  });
159
236
  }
160
- async function readSuccessfulOutput(journal, outcome, stepId, journalSteps) {
161
- const entries = (await journal.journalRead(outcome.run_id, 1)).entries;
237
+ /**
238
+ * Shared by every `f.*` verb that lowers to one kernel step run in isolation:
239
+ * find its `step.completed` entry, record it, and refuse anything but a
240
+ * clean success before handing the raw `output` back for verb-specific
241
+ * extraction (a plain string for `f.run`, an `AgentResult` for `f.agent`).
242
+ *
243
+ * Callers are responsible for having already established that the RUN
244
+ * reached a terminal, successful state before calling this — `f.run`'s
245
+ * caller relies on `runStart`'s own immediate response (the kernel drives a
246
+ * deterministic step to completion inline, no race); `f.agent`'s caller
247
+ * relies on `classifyOutcome` (cli/run.ts) having already polled to a true
248
+ * terminal state. Given that, a single read from the start of this run's
249
+ * (small, single-step) journal is enough — no polling here, and no run
250
+ * outcome ever needs re-checking.
251
+ */
252
+ async function readCompletedStepOutput(journal, runId, stepId, journalSteps) {
253
+ const entries = (await journal.journalRead(runId, 1)).entries;
162
254
  const completed = entries.find((entry) => isStepCompleted(entry, stepId));
163
255
  if (!isStepCompleted(completed, stepId)) {
164
- throw protocolViolation(outcome.run_id, `journal has no step.completed for "${stepId}"`);
256
+ throw protocolViolation(runId, `journal has no step.completed for "${stepId}"`);
165
257
  }
166
258
  const reason = completed.payload.completionReason;
167
- journalSteps.push(Object.freeze({ id: stepId, runId: outcome.run_id, completionReason: reason }));
259
+ journalSteps.push(Object.freeze({ id: stepId, runId, completionReason: reason }));
168
260
  if (reason !== 'success') {
169
- throw new AuthoredFlowExecutionError('step_failed', `journal step "${stepId}" completed with ${reason}`, reason, outcome.run_id);
261
+ throw new AuthoredFlowExecutionError('step_failed', `journal step "${stepId}" completed with ${reason}`, reason, runId);
170
262
  }
171
- if (outcome.status !== 'completed' || outcome.completion_reason !== 'success') {
172
- throw protocolViolation(outcome.run_id, `successful step entry conflicts with run outcome ${outcome.status}/${String(outcome.completion_reason)}`);
173
- }
174
- const output = completed.payload.output;
263
+ return completed.payload.output;
264
+ }
265
+ async function readSuccessfulOutput(journal, outcome, stepId, journalSteps) {
266
+ const output = await readCompletedStepOutput(journal, outcome.run_id, stepId, journalSteps);
175
267
  if (!isRecord(output) || typeof output['stdout_tail'] !== 'string') {
176
268
  throw protocolViolation(outcome.run_id, `step "${stepId}" has no string stdout_tail`);
177
269
  }
178
270
  return output['stdout_tail'];
179
271
  }
272
+ /**
273
+ * The kernel journals an agent step's raw `CliResult` shape
274
+ * (`exit_code`/`stdout_tail`/`stderr_tail`) — same as a deterministic step —
275
+ * UNLESS the CLI's stdout parsed as JSON, in which case `output` is that
276
+ * parsed object directly (worker.ts: `parseJsonOutput(result.stdout_tail) ??
277
+ * result`). Neither shape carries a real `artifacts` list today: nothing in
278
+ * the kernel or worker enumerates files an agent wrote, and `f.agent`'s
279
+ * `AgentOptions` has no `output` schema parameter for a CLI to target either
280
+ * (unlike the declarative `AgentStepSpec.output` field). `artifacts` is
281
+ * therefore always empty here — honest about what data exists, not a
282
+ * placeholder for something not yet wired.
283
+ */
284
+ async function readSuccessfulAgentOutput(journal, runId, stepId, journalSteps) {
285
+ const output = await readCompletedStepOutput(journal, runId, stepId, journalSteps);
286
+ if (!isRecord(output)) {
287
+ throw protocolViolation(runId, `step "${stepId}" produced a non-object output`);
288
+ }
289
+ if (typeof output['stdout_tail'] === 'string') {
290
+ return { summary: output['stdout_tail'], artifacts: [] };
291
+ }
292
+ // The CLI's stdout parsed as JSON, so `output` is that value, not a
293
+ // CliResult. Fall back to a stable, inspectable summary rather than
294
+ // refusing a run whose agent step genuinely succeeded.
295
+ return { summary: JSON.stringify(output), artifacts: [] };
296
+ }
180
297
  function isStepCompleted(value, stepId) {
181
298
  if (!isRecord(value) || value['entry_type'] !== 'step.completed' || value['step_id'] !== stepId) {
182
299
  return false;
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-executor.js","sourceRoot":"","sources":["../src/authored-flow-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"authored-flow-executor.js","sourceRoot":"","sources":["../src/authored-flow-executor.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,21 @@
1
- import { type FlowHandle } from './authored-flow.js';
1
+ import { getAuthoredFlowDefinition, type AuthoredFlowDefinition, type FlowHandle } from './authored-flow.js';
2
2
  export declare class AuthoredFlowLoadError extends Error {
3
3
  constructor(message: string);
4
4
  }
5
+ /** Same signature as `getAuthoredFlowDefinition`, resolved from wherever a flow was loaded. */
6
+ export type GetFlowDefinition = <Input = unknown>(handle: FlowHandle) => AuthoredFlowDefinition<Input>;
7
+ export interface LoadedAuthoredFlow {
8
+ readonly handle: FlowHandle;
9
+ /**
10
+ * Bound to the SAME `@relayflows/surface` module instance the flow file
11
+ * itself imported `flow` from — see the comment on
12
+ * {@link resolveGetFlowDefinition}. Callers that go on to execute the flow
13
+ * (not just validate it) must keep using this, not the SDK's own static
14
+ * `getAuthoredFlowDefinition` import.
15
+ */
16
+ readonly getDefinition: GetFlowDefinition;
17
+ }
5
18
  /** Import and validate a direct-run module without executing its authored body. */
6
- export declare function loadAuthoredFlow(path: string): Promise<FlowHandle>;
19
+ export declare function loadAuthoredFlow(path: string): Promise<LoadedAuthoredFlow>;
20
+ export { getAuthoredFlowDefinition };
7
21
  //# sourceMappingURL=authored-flow-loader.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-loader.d.ts","sourceRoot":"","sources":["../src/authored-flow-loader.ts"],"names":[],"mappings":"AAGA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEhF,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BxE"}
1
+ {"version":3,"file":"authored-flow-loader.d.ts","sourceRoot":"","sources":["../src/authored-flow-loader.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,yBAAyB,EACzB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EAChB,MAAM,oBAAoB,CAAC;AAE5B,qBAAa,qBAAsB,SAAQ,KAAK;gBAClC,OAAO,EAAE,MAAM;CAI5B;AAED,+FAA+F;AAC/F,MAAM,MAAM,iBAAiB,GAAG,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,EAAE,UAAU,KAAK,sBAAsB,CAAC,KAAK,CAAC,CAAC;AAEvG,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,aAAa,EAAE,iBAAiB,CAAC;CAC3C;AAED,mFAAmF;AACnF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA2BhF;AAoDD,OAAO,EAAE,yBAAyB,EAAE,CAAC"}
@@ -1,7 +1,8 @@
1
1
  import { accessSync, constants } from 'node:fs';
2
+ import { createRequire } from 'node:module';
2
3
  import { resolve } from 'node:path';
3
4
  import { pathToFileURL } from 'node:url';
4
- import { getAuthoredFlowDefinition } from './authored-flow.js';
5
+ import { getAuthoredFlowDefinition, } from './authored-flow.js';
5
6
  export class AuthoredFlowLoadError extends Error {
6
7
  constructor(message) {
7
8
  super(message);
@@ -24,15 +25,58 @@ export async function loadAuthoredFlow(path) {
24
25
  catch (error) {
25
26
  throw new AuthoredFlowLoadError(`Flow "${path}" could not be imported: ${errorMessage(error)}`);
26
27
  }
28
+ const getDefinition = await resolveGetFlowDefinition(absolutePath, path);
27
29
  const handle = authoredModule['default'];
28
30
  try {
29
- getAuthoredFlowDefinition(handle);
31
+ getDefinition(handle);
30
32
  }
31
33
  catch (error) {
32
34
  throw new AuthoredFlowLoadError(`Flow "${path}" must default-export flow(...): ${errorMessage(error)}`);
33
35
  }
34
- return handle;
36
+ return { handle, getDefinition };
35
37
  }
38
+ /**
39
+ * `getFlowDefinition` recognizes a handle by object identity in a `WeakMap`
40
+ * scoped to whichever copy of `@relayflows/surface` created it — deliberately:
41
+ * that is what makes a handle unforgeable (surface/tests/flow.test.ts
42
+ * "refuses malformed and forged handles at the runtime boundary" locks this
43
+ * in, including against a well-known-symbol forgery, so this must not be
44
+ * "fixed" by switching that map to a symbol-tagged property instead).
45
+ *
46
+ * An author's `.flow.ts` almost never lives inside this monorepo. It
47
+ * resolves `@relayflows/surface` from ITS OWN `node_modules` — a physically
48
+ * different module instance than the one this SDK package statically
49
+ * imports for itself, so the SDK's own copy's `WeakMap` never has the
50
+ * entry the flow file's copy wrote. The fix is not a new identity
51
+ * mechanism; it is asking the SAME question Node itself would ask: resolve
52
+ * `@relayflows/surface/runtime` from the flow file's own location, exactly
53
+ * as the flow file's `import { flow } from "@relayflows/surface"`
54
+ * already did, and use THAT copy's `getFlowDefinition`. Since the flow
55
+ * module already imported successfully (by the time this runs), a
56
+ * compatible `@relayflows/surface` is provably resolvable from this same
57
+ * anchor.
58
+ */
59
+ async function resolveGetFlowDefinition(absolutePath, displayPath) {
60
+ const require = createRequire(pathToFileURL(absolutePath));
61
+ let resolvedRuntimePath;
62
+ try {
63
+ resolvedRuntimePath = require.resolve('@relayflows/surface/runtime');
64
+ }
65
+ catch (error) {
66
+ throw new AuthoredFlowLoadError(`Flow "${displayPath}" imports @relayflows/surface, but @relayflows/surface/runtime `
67
+ + `could not be resolved from the same location: ${errorMessage(error)}`);
68
+ }
69
+ const runtimeModule = await import(pathToFileURL(resolvedRuntimePath).href);
70
+ if (typeof runtimeModule.getFlowDefinition !== 'function') {
71
+ throw new AuthoredFlowLoadError(`Flow "${displayPath}": the @relayflows/surface/runtime resolved from its location `
72
+ + 'does not export getFlowDefinition — check its @relayflows/surface version.');
73
+ }
74
+ return runtimeModule.getFlowDefinition;
75
+ }
76
+ // Exported for callers (internal SDK tests, and any co-located flow that is
77
+ // provably the same `@relayflows/surface` instance as this package) that
78
+ // have no need to resolve a separate copy.
79
+ export { getAuthoredFlowDefinition };
36
80
  function errorMessage(error) {
37
81
  return error instanceof Error ? error.message : 'unknown authored-flow error';
38
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"authored-flow-loader.js","sourceRoot":"","sources":["../src/authored-flow-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,yBAAyB,EAAmB,MAAM,oBAAoB,CAAC;AAEhF,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,CAAC,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,qBAAqB,CAAC,SAAS,IAAI,oBAAoB,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,cAAuC,CAAC;IAC5C,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAA4B,CAAC;IAC7F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAC7B,SAAS,IAAI,4BAA4B,YAAY,CAAC,KAAK,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAe,CAAC;IACvD,IAAI,CAAC;QACH,yBAAyB,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAC7B,SAAS,IAAI,oCAAoC,YAAY,CAAC,KAAK,CAAC,EAAE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;AAChF,CAAC"}
1
+ {"version":3,"file":"authored-flow-loader.js","sourceRoot":"","sources":["../src/authored-flow-loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,yBAAyB,GAG1B,MAAM,oBAAoB,CAAC;AAE5B,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;IACtC,CAAC;CACF;AAiBD,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAY;IACjD,MAAM,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,CAAC,YAAY,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,qBAAqB,CAAC,SAAS,IAAI,oBAAoB,CAAC,CAAC;IACrE,CAAC;IAED,IAAI,cAAuC,CAAC;IAC5C,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,IAAI,CAA4B,CAAC;IAC7F,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAC7B,SAAS,IAAI,4BAA4B,YAAY,CAAC,KAAK,CAAC,EAAE,CAC/D,CAAC;IACJ,CAAC;IAED,MAAM,aAAa,GAAG,MAAM,wBAAwB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACzE,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAe,CAAC;IACvD,IAAI,CAAC;QACH,aAAa,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAC7B,SAAS,IAAI,oCAAoC,YAAY,CAAC,KAAK,CAAC,EAAE,CACvE,CAAC;IACJ,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,CAAC;AACnC,CAAC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,KAAK,UAAU,wBAAwB,CACrC,YAAoB,EACpB,WAAmB;IAEnB,MAAM,OAAO,GAAG,aAAa,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAC3D,IAAI,mBAA2B,CAAC;IAChC,IAAI,CAAC;QACH,mBAAmB,GAAG,OAAO,CAAC,OAAO,CAAC,6BAA6B,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,qBAAqB,CAC7B,SAAS,WAAW,iEAAiE;cACjF,iDAAiD,YAAY,CAAC,KAAK,CAAC,EAAE,CAC3E,CAAC;IACJ,CAAC;IACD,MAAM,aAAa,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAEzE,CAAC;IACF,IAAI,OAAO,aAAa,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC1D,MAAM,IAAI,qBAAqB,CAC7B,SAAS,WAAW,gEAAgE;cAChF,4EAA4E,CACjF,CAAC;IACJ,CAAC;IACD,OAAO,aAAa,CAAC,iBAAsC,CAAC;AAC9D,CAAC;AAED,4EAA4E;AAC5E,yEAAyE;AACzE,2CAA2C;AAC3C,OAAO,EAAE,yBAAyB,EAAE,CAAC;AAErC,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,6BAA6B,CAAC;AAChF,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"direct-run.d.ts","sourceRoot":"","sources":["../../src/cli/direct-run.ts"],"names":[],"mappings":"AAQA,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAEzB,MAAM,UAAU,CAAC;AAElB,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CA6DvB"}
1
+ {"version":3,"file":"direct-run.d.ts","sourceRoot":"","sources":["../../src/cli/direct-run.ts"],"names":[],"mappings":"AAQA,OAAO,EAML,KAAK,YAAY,EACjB,KAAK,mBAAmB,EAEzB,MAAM,UAAU,CAAC;AAElB,wBAAsB,aAAa,CACjC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,YAAY,CAAC,CAgGvB"}
@@ -26,8 +26,13 @@ export async function runDirectFlow(path, inputArgument, dataDir, options = {})
26
26
  if (connected !== undefined)
27
27
  return connected;
28
28
  try {
29
- const handle = await loadAuthoredFlow(path);
30
- const result = await executeAuthoredFlow(handle, client, input);
29
+ const { handle, getDefinition } = await loadAuthoredFlow(path);
30
+ const result = await executeAuthoredFlow(handle, client, input, {
31
+ getDefinition,
32
+ flowPath: path,
33
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
34
+ ...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
35
+ });
31
36
  const terminal = result.journalSteps.at(-1);
32
37
  if (terminal === undefined) {
33
38
  return protocolFailure('run', base, socketPath, new Error(`authored flow "${result.name}" completed without a journal step`));
@@ -46,8 +51,21 @@ export async function runDirectFlow(path, inputArgument, dataDir, options = {})
46
51
  };
47
52
  }
48
53
  catch (error) {
54
+ // `agent_cli_unresolved` and `unsupported_workspace_permission` are
55
+ // preflight-shaped refusals, not protocol failures — `flows check`
56
+ // returns exit 2 for the equivalent declarative-spec failures, and this
57
+ // path should match it. Known gap, not solved here: if a `f.run` before
58
+ // the failing `f.agent` already journaled real work, this still reports
59
+ // as a clean refusal — true upfront preflight would need to know every
60
+ // `f.agent` call an imperative TS body will make before running any of
61
+ // it, which isn't knowable without running the body (see the comment on
62
+ // ExecuteAuthoredFlowOptions and this project's own examples/README for
63
+ // the same limitation already documented elsewhere).
49
64
  if (error instanceof AuthoredFlowLoadError
50
- || (error instanceof AuthoredFlowExecutionError && error.code === 'unsupported_header')) {
65
+ || (error instanceof AuthoredFlowExecutionError
66
+ && (error.code === 'unsupported_header'
67
+ || error.code === 'agent_cli_unresolved'
68
+ || error.code === 'unsupported_workspace_permission'))) {
51
69
  return {
52
70
  exitCode: 2,
53
71
  report: {
@@ -59,6 +77,23 @@ export async function runDirectFlow(path, inputArgument, dataDir, options = {})
59
77
  },
60
78
  };
61
79
  }
80
+ if (error instanceof AuthoredFlowExecutionError && error.code === 'agent_parked') {
81
+ return {
82
+ exitCode: 3,
83
+ report: {
84
+ ...base,
85
+ ok: false,
86
+ runId: error.runId,
87
+ socketPath,
88
+ status: 'parked',
89
+ diagnostics: [...base.diagnostics, {
90
+ severity: 'parked',
91
+ kind: 'run_parked',
92
+ message: error.message,
93
+ }],
94
+ },
95
+ };
96
+ }
62
97
  const runId = error instanceof AuthoredFlowExecutionError ? error.runId : undefined;
63
98
  return protocolFailure('run', base, socketPath, error, runId);
64
99
  }
@@ -1 +1 @@
1
- {"version":3,"file":"direct-run.js","sourceRoot":"","sources":["../../src/cli/direct-run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"direct-run.js","sourceRoot":"","sources":["../../src/cli/direct-run.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@relayflows/sdk",
3
- "version": "2.0.6",
3
+ "version": "2.0.8",
4
4
  "description": "TypeScript-first authoring SDK for Relayflows. Compiles specs; speaks the journal protocol.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "license": "Apache-2.0",
32
32
  "dependencies": {
33
- "@relayflows/surface": "2.0.6",
33
+ "@relayflows/surface": "2.0.8",
34
34
  "@types/js-yaml": "^4.0.9",
35
35
  "ajv": "^8.17.1",
36
36
  "ajv-draft-04": "^1.0.0",
@@ -4,6 +4,8 @@ import type {
4
4
  } from './protocol.js';
5
5
 
6
6
  export type AuthoredFlowExecutionErrorCode =
7
+ | 'agent_cli_unresolved'
8
+ | 'agent_parked'
7
9
  | 'duplicate_completion'
8
10
  | 'journal_protocol_violation'
9
11
  | 'missing_completion'
@@ -15,6 +17,7 @@ export type AuthoredFlowExecutionErrorCode =
15
17
  | 'unsupported_header'
16
18
  | 'unsettled_derived_work'
17
19
  | 'unsupported_promise_lifecycle'
20
+ | 'unsupported_workspace_permission'
18
21
  | 'unawaited_step'
19
22
  | 'unsupported_verb';
20
23
 
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  COMPLETION_REASONS,
3
3
  RUN_COMPLETION_REASONS,
4
+ type AgentOptions,
4
5
  type AgentResult,
5
6
  type CloudHelper,
6
7
  type CompletionReason as SurfaceCompletionReason,
@@ -9,8 +10,13 @@ import {
9
10
  type Step,
10
11
  } from '@relayflows/surface';
11
12
  import type { FlowHandle } from '@relayflows/surface/runtime';
13
+ import { join } from 'node:path';
12
14
  import { compileSpec, toKernelSpec } from './compile.js';
13
15
  import { getAuthoredFlowDefinition } from './authored-flow.js';
16
+ import type { GetFlowDefinition } from './authored-flow-loader.js';
17
+ import { checkAuthoredFlow } from './cli/check.js';
18
+ import { classifyOutcome, type RunLifecycleOptions } from './cli/run.js';
19
+ import type { PreflightDiagnostic } from './preflight.js';
14
20
  import {
15
21
  AuthoredFlowExecutionError,
16
22
  type AuthoredFlowExecutionErrorCode,
@@ -27,7 +33,7 @@ import type {
27
33
  RunCompletionReason as ProtocolRunCompletionReason,
28
34
  RunOutcome,
29
35
  } from './protocol.js';
30
- import { SPEC_SCHEMA_VERSION } from './spec.js';
36
+ import { SPEC_SCHEMA_VERSION, type FlowSpec } from './spec.js';
31
37
 
32
38
  type Assert<T extends true> = T;
33
39
  type Equal<A, B> = [A] extends [B]
@@ -49,6 +55,15 @@ type EveryRunCompletionReasonIsAcceptedByDone = Assert<
49
55
 
50
56
  export { AuthoredFlowExecutionError, type AuthoredFlowExecutionErrorCode };
51
57
 
58
+ /**
59
+ * Matches the `"path/glob: readonly"` / `"path/glob: readwrite"` shorthand
60
+ * shown in docs/SURFACE.md and the examples — the only shape a workspace
61
+ * string could plausibly declare a permission in. No parser anywhere in this
62
+ * package turns that annotation into a real restriction, so `lowerAgent`
63
+ * refuses rather than silently accepting and ignoring it.
64
+ */
65
+ const WORKSPACE_PERMISSION_ANNOTATION = /:\s*(readonly|readwrite)\s*$/i;
66
+
52
67
  export interface AuthoredFlowJournalStep {
53
68
  readonly id: string;
54
69
  readonly runId: string;
@@ -79,12 +94,46 @@ type JournalStepUsesStepCompletionReason = Assert<
79
94
  * `JournalClient`; values are read back from `step.completed` journal entries.
80
95
  * Unsupported headers, verbs, gates, or completion lowering fail closed.
81
96
  */
97
+ export interface ExecuteAuthoredFlowOptions {
98
+ /**
99
+ * Defaults to this package's own static import — correct for every
100
+ * existing (internal, single-instance) caller. A flow loaded from an
101
+ * external path via `loadAuthoredFlow` must pass ITS resolved
102
+ * `getDefinition` instead; see authored-flow-loader.ts's comment on why.
103
+ */
104
+ readonly getDefinition?: GetFlowDefinition;
105
+ /**
106
+ * The flow file's own path — passed straight to `checkAuthoredFlow`
107
+ * (cli/check.ts) so `f.agent` resolves a CLI the same way a declarative
108
+ * `type: agent` step does: nearest `flows.json`, real auth/model probing,
109
+ * canonicalized path. `checkAuthoredFlow` always does `dirname()` on this,
110
+ * matching `checkFlow`'s real `flows check <file>` contract — pass a FILE
111
+ * path, not a directory, or the search starts one level too high. Defaults
112
+ * to a synthetic `flow.ts` under `process.cwd()` for exactly this reason:
113
+ * `process.cwd()` itself is a directory, and `dirname(process.cwd())`
114
+ * would search cwd's PARENT.
115
+ */
116
+ readonly flowPath?: string;
117
+ /** Passed straight through to classifyOutcome (cli/run.ts) for f.agent's wait. */
118
+ readonly signal?: RunLifecycleOptions['signal'];
119
+ readonly onWait?: RunLifecycleOptions['onWait'];
120
+ }
121
+
82
122
  export async function executeAuthoredFlow<Input = undefined>(
83
123
  handle: FlowHandle,
84
124
  journal: JournalClient,
85
125
  input?: Input,
126
+ options: ExecuteAuthoredFlowOptions = {},
86
127
  ): Promise<AuthoredFlowExecutionResult> {
87
- const definition = getAuthoredFlowDefinition<Input>(handle);
128
+ const getDefinition = options.getDefinition ?? getAuthoredFlowDefinition;
129
+ const flowPath = options.flowPath ?? join(process.cwd(), 'flow.ts');
130
+ // Named separately from `options` because `lowerAgent` below has its own,
131
+ // differently-typed `options: AgentOptions` parameter that shadows this one.
132
+ const waitOptions: RunLifecycleOptions = {
133
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
134
+ ...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
135
+ };
136
+ const definition = getDefinition<Input>(handle);
88
137
  const headerFields = Object.keys(definition.header);
89
138
  if (headerFields.length > 0) {
90
139
  throw new AuthoredFlowExecutionError(
@@ -112,6 +161,97 @@ export async function executeAuthoredFlow<Input = undefined>(
112
161
  return readSuccessfulOutput(journal, outcome, id, journalSteps);
113
162
  };
114
163
 
164
+ // `name` (the first f.agent argument, e.g. "fixer") is not wired to the
165
+ // kernel's `agent` field: that field selects a NAMED declaration from
166
+ // `FlowSpec.agents`, and this executor refuses every non-empty header
167
+ // (see the top of this function) — an authored flow has no way to declare
168
+ // one today. `name` is kept only for step-id readability; CLI selection
169
+ // goes through the project's flows.json default below, same as it does
170
+ // for a bare `type: agent` YAML step with no explicit `cli`.
171
+ const lowerAgent = async (
172
+ id: string,
173
+ options: AgentOptions,
174
+ ): Promise<AgentResult> => {
175
+ if (options.workspace !== undefined && WORKSPACE_PERMISSION_ANNOTATION.test(options.workspace)) {
176
+ throw new AuthoredFlowExecutionError(
177
+ 'unsupported_workspace_permission',
178
+ `flow "${definition.name}" step "${id}": workspace "${options.workspace}" declares a `
179
+ + 'permission annotation ("...: readonly" / "...: readwrite"), but nothing enforces it — '
180
+ + 'no parser anywhere in this package turns that annotation into a real restriction '
181
+ + '(kernel/DAEMON-LIFECYCLE.md\'s permission model is untouched by f.agent). '
182
+ + 'Silently accepting and ignoring it would let a flow believe a restriction is in effect '
183
+ + "when it is not. Declare a bare surface name (no trailing \": readonly\"/\": readwrite\") "
184
+ + 'if you do not need enforcement, or use the declarative spec\'s `permissions` field, which is real.',
185
+ );
186
+ }
187
+ const authoring: FlowSpec = {
188
+ version: SPEC_SCHEMA_VERSION,
189
+ name: `${definition.name}/${id}`,
190
+ steps: [{
191
+ id,
192
+ type: 'agent',
193
+ instruction: options.task,
194
+ ...(options.workspace === undefined ? {} : {
195
+ surfaces: { workspace: [{ surface: options.workspace }] },
196
+ }),
197
+ }],
198
+ };
199
+ // The kernel never resolves a `cli` on its own — every declarative
200
+ // `flows run`/`flows check` binds it first via this exact function
201
+ // (cli/check.ts), searching for the nearest flows.json from `flowPath`
202
+ // and real-probing auth/model readiness. An authored agent step gets
203
+ // nothing for free just because it was declared in TS instead of YAML.
204
+ const { report, flow: resolved } = checkAuthoredFlow(authoring, flowPath);
205
+ if (!report.ok || resolved === undefined) {
206
+ const refusal = report.diagnostics.find(
207
+ (diagnostic): diagnostic is PreflightDiagnostic & { severity: 'refusal' } =>
208
+ diagnostic.severity === 'refusal',
209
+ );
210
+ throw new AuthoredFlowExecutionError(
211
+ 'agent_cli_unresolved',
212
+ refusal?.message
213
+ ?? `flow "${definition.name}" step "${id}": no CLI could be resolved for f.agent `
214
+ + `(searched for flows.json from "${flowPath}")`,
215
+ );
216
+ }
217
+ const spec = toKernelSpec(resolved);
218
+ const outcome = await journal.runStart(spec);
219
+ // Reuse the declarative CLI's own wait/classification (cli/run.ts) rather
220
+ // than a hand-rolled poll: `step.completed` and the run's own terminal
221
+ // state are appended as two SEPARATE actions (kernel/relayflowd-core/src/machine.rs
222
+ // completion_actions vs complete_run_actions), so a naive read right
223
+ // after runStart can race a real, valid completion — and a genuinely
224
+ // long-running agent has no reason to be bounded by anything other than
225
+ // its own worker's lease, which classifyOutcome already follows
226
+ // (renewing as the lease renews, per docs/SURFACE.md §5's WAITING
227
+ // [worker_lease] contract), never an unrelated fixed deadline.
228
+ const execution = await classifyOutcome(journal, 'run', outcome, report, '', waitOptions);
229
+ if (execution.exitCode === 3) {
230
+ const parked = execution.report.parkedStep;
231
+ throw new AuthoredFlowExecutionError(
232
+ 'agent_parked',
233
+ execution.report.diagnostics.at(-1)?.message
234
+ ?? `flow "${definition.name}" step "${id}" parked`
235
+ + (parked !== undefined ? ` (${parked.type})` : '')
236
+ + ': no worker is attached to run it.',
237
+ undefined,
238
+ outcome.run_id,
239
+ );
240
+ }
241
+ if (execution.exitCode !== 0) {
242
+ const reason = execution.report.completionReason;
243
+ throw new AuthoredFlowExecutionError(
244
+ 'step_failed',
245
+ execution.report.diagnostics.at(-1)?.message
246
+ ?? `flow "${definition.name}" step "${id}" did not complete successfully `
247
+ + `(status: ${execution.report.status ?? 'unknown'})`,
248
+ isSurfaceCompletionReason(reason) ? reason : undefined,
249
+ outcome.run_id,
250
+ );
251
+ }
252
+ return readSuccessfulAgentOutput(journal, outcome.run_id, id, journalSteps);
253
+ };
254
+
115
255
  const context: Ctx = {
116
256
  run(command) {
117
257
  assertOperationAllowed('run', definition.name, requestedCompletion);
@@ -134,13 +274,15 @@ export async function executeAuthoredFlow<Input = undefined>(
134
274
  lifecycle,
135
275
  ));
136
276
  },
137
- agent() {
277
+ agent(name, options) {
138
278
  assertOperationAllowed('agent', definition.name, requestedCompletion);
279
+ void name; // step-id readability only — see the comment on lowerAgent.
139
280
  const id = `agent-${nextStep++}`;
140
- return trackStep(authoredSteps, unsupportedStep<AgentResult>(
281
+ return trackStep(authoredSteps, new AuthoredFlowOperation(
141
282
  id,
142
283
  'agent',
143
284
  () => assertOperationAllowed('agent', definition.name, requestedCompletion),
285
+ () => lowerAgent(id, options),
144
286
  lifecycle,
145
287
  ));
146
288
  },
@@ -286,42 +428,90 @@ function unsupportedCloud(assertOpen: () => void): CloudHelper {
286
428
  }) as CloudHelper;
287
429
  }
288
430
 
289
- async function readSuccessfulOutput(
431
+ /**
432
+ * Shared by every `f.*` verb that lowers to one kernel step run in isolation:
433
+ * find its `step.completed` entry, record it, and refuse anything but a
434
+ * clean success before handing the raw `output` back for verb-specific
435
+ * extraction (a plain string for `f.run`, an `AgentResult` for `f.agent`).
436
+ *
437
+ * Callers are responsible for having already established that the RUN
438
+ * reached a terminal, successful state before calling this — `f.run`'s
439
+ * caller relies on `runStart`'s own immediate response (the kernel drives a
440
+ * deterministic step to completion inline, no race); `f.agent`'s caller
441
+ * relies on `classifyOutcome` (cli/run.ts) having already polled to a true
442
+ * terminal state. Given that, a single read from the start of this run's
443
+ * (small, single-step) journal is enough — no polling here, and no run
444
+ * outcome ever needs re-checking.
445
+ */
446
+ async function readCompletedStepOutput(
290
447
  journal: JournalClient,
291
- outcome: RunOutcome,
448
+ runId: string,
292
449
  stepId: string,
293
450
  journalSteps: AuthoredFlowJournalStep[],
294
- ): Promise<string> {
295
- const entries = (await journal.journalRead(outcome.run_id, 1)).entries;
451
+ ): Promise<unknown> {
452
+ const entries = (await journal.journalRead(runId, 1)).entries;
296
453
  const completed = entries.find((entry) => isStepCompleted(entry, stepId));
297
454
  if (!isStepCompleted(completed, stepId)) {
298
- throw protocolViolation(outcome.run_id, `journal has no step.completed for "${stepId}"`);
455
+ throw protocolViolation(runId, `journal has no step.completed for "${stepId}"`);
299
456
  }
300
457
 
301
458
  const reason = completed.payload.completionReason;
302
- journalSteps.push(Object.freeze({ id: stepId, runId: outcome.run_id, completionReason: reason }));
459
+ journalSteps.push(Object.freeze({ id: stepId, runId, completionReason: reason }));
303
460
  if (reason !== 'success') {
304
461
  throw new AuthoredFlowExecutionError(
305
462
  'step_failed',
306
463
  `journal step "${stepId}" completed with ${reason}`,
307
464
  reason,
308
- outcome.run_id,
309
- );
310
- }
311
- if (outcome.status !== 'completed' || outcome.completion_reason !== 'success') {
312
- throw protocolViolation(
313
- outcome.run_id,
314
- `successful step entry conflicts with run outcome ${outcome.status}/${String(outcome.completion_reason)}`,
465
+ runId,
315
466
  );
316
467
  }
468
+ return completed.payload.output;
469
+ }
317
470
 
318
- const output = completed.payload.output;
471
+ async function readSuccessfulOutput(
472
+ journal: JournalClient,
473
+ outcome: RunOutcome,
474
+ stepId: string,
475
+ journalSteps: AuthoredFlowJournalStep[],
476
+ ): Promise<string> {
477
+ const output = await readCompletedStepOutput(journal, outcome.run_id, stepId, journalSteps);
319
478
  if (!isRecord(output) || typeof output['stdout_tail'] !== 'string') {
320
479
  throw protocolViolation(outcome.run_id, `step "${stepId}" has no string stdout_tail`);
321
480
  }
322
481
  return output['stdout_tail'];
323
482
  }
324
483
 
484
+ /**
485
+ * The kernel journals an agent step's raw `CliResult` shape
486
+ * (`exit_code`/`stdout_tail`/`stderr_tail`) — same as a deterministic step —
487
+ * UNLESS the CLI's stdout parsed as JSON, in which case `output` is that
488
+ * parsed object directly (worker.ts: `parseJsonOutput(result.stdout_tail) ??
489
+ * result`). Neither shape carries a real `artifacts` list today: nothing in
490
+ * the kernel or worker enumerates files an agent wrote, and `f.agent`'s
491
+ * `AgentOptions` has no `output` schema parameter for a CLI to target either
492
+ * (unlike the declarative `AgentStepSpec.output` field). `artifacts` is
493
+ * therefore always empty here — honest about what data exists, not a
494
+ * placeholder for something not yet wired.
495
+ */
496
+ async function readSuccessfulAgentOutput(
497
+ journal: JournalClient,
498
+ runId: string,
499
+ stepId: string,
500
+ journalSteps: AuthoredFlowJournalStep[],
501
+ ): Promise<AgentResult> {
502
+ const output = await readCompletedStepOutput(journal, runId, stepId, journalSteps);
503
+ if (!isRecord(output)) {
504
+ throw protocolViolation(runId, `step "${stepId}" produced a non-object output`);
505
+ }
506
+ if (typeof output['stdout_tail'] === 'string') {
507
+ return { summary: output['stdout_tail'], artifacts: [] };
508
+ }
509
+ // The CLI's stdout parsed as JSON, so `output` is that value, not a
510
+ // CliResult. Fall back to a stable, inspectable summary rather than
511
+ // refusing a run whose agent step genuinely succeeded.
512
+ return { summary: JSON.stringify(output), artifacts: [] };
513
+ }
514
+
325
515
  interface StepCompletedEntry {
326
516
  entry_type: 'step.completed';
327
517
  step_id: string;
@@ -1,7 +1,12 @@
1
1
  import { accessSync, constants } from 'node:fs';
2
+ import { createRequire } from 'node:module';
2
3
  import { resolve } from 'node:path';
3
4
  import { pathToFileURL } from 'node:url';
4
- import { getAuthoredFlowDefinition, type FlowHandle } from './authored-flow.js';
5
+ import {
6
+ getAuthoredFlowDefinition,
7
+ type AuthoredFlowDefinition,
8
+ type FlowHandle,
9
+ } from './authored-flow.js';
5
10
 
6
11
  export class AuthoredFlowLoadError extends Error {
7
12
  constructor(message: string) {
@@ -10,8 +15,23 @@ export class AuthoredFlowLoadError extends Error {
10
15
  }
11
16
  }
12
17
 
18
+ /** Same signature as `getAuthoredFlowDefinition`, resolved from wherever a flow was loaded. */
19
+ export type GetFlowDefinition = <Input = unknown>(handle: FlowHandle) => AuthoredFlowDefinition<Input>;
20
+
21
+ export interface LoadedAuthoredFlow {
22
+ readonly handle: FlowHandle;
23
+ /**
24
+ * Bound to the SAME `@relayflows/surface` module instance the flow file
25
+ * itself imported `flow` from — see the comment on
26
+ * {@link resolveGetFlowDefinition}. Callers that go on to execute the flow
27
+ * (not just validate it) must keep using this, not the SDK's own static
28
+ * `getAuthoredFlowDefinition` import.
29
+ */
30
+ readonly getDefinition: GetFlowDefinition;
31
+ }
32
+
13
33
  /** Import and validate a direct-run module without executing its authored body. */
14
- export async function loadAuthoredFlow(path: string): Promise<FlowHandle> {
34
+ export async function loadAuthoredFlow(path: string): Promise<LoadedAuthoredFlow> {
15
35
  const absolutePath = resolve(path);
16
36
  try {
17
37
  accessSync(absolutePath, constants.R_OK);
@@ -28,17 +48,70 @@ export async function loadAuthoredFlow(path: string): Promise<FlowHandle> {
28
48
  );
29
49
  }
30
50
 
51
+ const getDefinition = await resolveGetFlowDefinition(absolutePath, path);
31
52
  const handle = authoredModule['default'] as FlowHandle;
32
53
  try {
33
- getAuthoredFlowDefinition(handle);
54
+ getDefinition(handle);
34
55
  } catch (error) {
35
56
  throw new AuthoredFlowLoadError(
36
57
  `Flow "${path}" must default-export flow(...): ${errorMessage(error)}`,
37
58
  );
38
59
  }
39
- return handle;
60
+ return { handle, getDefinition };
61
+ }
62
+
63
+ /**
64
+ * `getFlowDefinition` recognizes a handle by object identity in a `WeakMap`
65
+ * scoped to whichever copy of `@relayflows/surface` created it — deliberately:
66
+ * that is what makes a handle unforgeable (surface/tests/flow.test.ts
67
+ * "refuses malformed and forged handles at the runtime boundary" locks this
68
+ * in, including against a well-known-symbol forgery, so this must not be
69
+ * "fixed" by switching that map to a symbol-tagged property instead).
70
+ *
71
+ * An author's `.flow.ts` almost never lives inside this monorepo. It
72
+ * resolves `@relayflows/surface` from ITS OWN `node_modules` — a physically
73
+ * different module instance than the one this SDK package statically
74
+ * imports for itself, so the SDK's own copy's `WeakMap` never has the
75
+ * entry the flow file's copy wrote. The fix is not a new identity
76
+ * mechanism; it is asking the SAME question Node itself would ask: resolve
77
+ * `@relayflows/surface/runtime` from the flow file's own location, exactly
78
+ * as the flow file's `import { flow } from "@relayflows/surface"`
79
+ * already did, and use THAT copy's `getFlowDefinition`. Since the flow
80
+ * module already imported successfully (by the time this runs), a
81
+ * compatible `@relayflows/surface` is provably resolvable from this same
82
+ * anchor.
83
+ */
84
+ async function resolveGetFlowDefinition(
85
+ absolutePath: string,
86
+ displayPath: string,
87
+ ): Promise<GetFlowDefinition> {
88
+ const require = createRequire(pathToFileURL(absolutePath));
89
+ let resolvedRuntimePath: string;
90
+ try {
91
+ resolvedRuntimePath = require.resolve('@relayflows/surface/runtime');
92
+ } catch (error) {
93
+ throw new AuthoredFlowLoadError(
94
+ `Flow "${displayPath}" imports @relayflows/surface, but @relayflows/surface/runtime `
95
+ + `could not be resolved from the same location: ${errorMessage(error)}`,
96
+ );
97
+ }
98
+ const runtimeModule = await import(pathToFileURL(resolvedRuntimePath).href) as {
99
+ getFlowDefinition?: unknown;
100
+ };
101
+ if (typeof runtimeModule.getFlowDefinition !== 'function') {
102
+ throw new AuthoredFlowLoadError(
103
+ `Flow "${displayPath}": the @relayflows/surface/runtime resolved from its location `
104
+ + 'does not export getFlowDefinition — check its @relayflows/surface version.',
105
+ );
106
+ }
107
+ return runtimeModule.getFlowDefinition as GetFlowDefinition;
40
108
  }
41
109
 
110
+ // Exported for callers (internal SDK tests, and any co-located flow that is
111
+ // provably the same `@relayflows/surface` instance as this package) that
112
+ // have no need to resolve a separate copy.
113
+ export { getAuthoredFlowDefinition };
114
+
42
115
  function errorMessage(error: unknown): string {
43
116
  return error instanceof Error ? error.message : 'unknown authored-flow error';
44
117
  }
@@ -44,8 +44,13 @@ export async function runDirectFlow(
44
44
  if (connected !== undefined) return connected;
45
45
 
46
46
  try {
47
- const handle = await loadAuthoredFlow(path);
48
- const result = await executeAuthoredFlow(handle, client, input);
47
+ const { handle, getDefinition } = await loadAuthoredFlow(path);
48
+ const result = await executeAuthoredFlow(handle, client, input, {
49
+ getDefinition,
50
+ flowPath: path,
51
+ ...(options.signal !== undefined ? { signal: options.signal } : {}),
52
+ ...(options.onWait !== undefined ? { onWait: options.onWait } : {}),
53
+ });
49
54
  const terminal = result.journalSteps.at(-1);
50
55
  if (terminal === undefined) {
51
56
  return protocolFailure('run', base, socketPath, new Error(
@@ -65,8 +70,21 @@ export async function runDirectFlow(
65
70
  },
66
71
  };
67
72
  } catch (error) {
73
+ // `agent_cli_unresolved` and `unsupported_workspace_permission` are
74
+ // preflight-shaped refusals, not protocol failures — `flows check`
75
+ // returns exit 2 for the equivalent declarative-spec failures, and this
76
+ // path should match it. Known gap, not solved here: if a `f.run` before
77
+ // the failing `f.agent` already journaled real work, this still reports
78
+ // as a clean refusal — true upfront preflight would need to know every
79
+ // `f.agent` call an imperative TS body will make before running any of
80
+ // it, which isn't knowable without running the body (see the comment on
81
+ // ExecuteAuthoredFlowOptions and this project's own examples/README for
82
+ // the same limitation already documented elsewhere).
68
83
  if (error instanceof AuthoredFlowLoadError
69
- || (error instanceof AuthoredFlowExecutionError && error.code === 'unsupported_header')) {
84
+ || (error instanceof AuthoredFlowExecutionError
85
+ && (error.code === 'unsupported_header'
86
+ || error.code === 'agent_cli_unresolved'
87
+ || error.code === 'unsupported_workspace_permission'))) {
70
88
  return {
71
89
  exitCode: 2,
72
90
  report: {
@@ -78,6 +96,23 @@ export async function runDirectFlow(
78
96
  },
79
97
  };
80
98
  }
99
+ if (error instanceof AuthoredFlowExecutionError && error.code === 'agent_parked') {
100
+ return {
101
+ exitCode: 3,
102
+ report: {
103
+ ...base,
104
+ ok: false,
105
+ runId: error.runId,
106
+ socketPath,
107
+ status: 'parked',
108
+ diagnostics: [...base.diagnostics, {
109
+ severity: 'parked',
110
+ kind: 'run_parked',
111
+ message: error.message,
112
+ }],
113
+ },
114
+ };
115
+ }
81
116
  const runId = error instanceof AuthoredFlowExecutionError ? error.runId : undefined;
82
117
  return protocolFailure('run', base, socketPath, error, runId);
83
118
  } finally {