@relayflows/sdk 2.0.15 → 2.0.17

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 (155) hide show
  1. package/dist/agent-artifacts.d.ts +20 -0
  2. package/dist/agent-artifacts.d.ts.map +1 -0
  3. package/dist/agent-artifacts.js +81 -0
  4. package/dist/agent-artifacts.js.map +1 -0
  5. package/dist/authored-flow-error.d.ts +1 -1
  6. package/dist/authored-flow-error.d.ts.map +1 -1
  7. package/dist/authored-flow-error.js.map +1 -1
  8. package/dist/authored-flow-executor.d.ts +3 -3
  9. package/dist/authored-flow-executor.d.ts.map +1 -1
  10. package/dist/authored-flow-executor.js +93 -7
  11. package/dist/authored-flow-executor.js.map +1 -1
  12. package/dist/authored-flow-lifecycle.d.ts +10 -0
  13. package/dist/authored-flow-lifecycle.d.ts.map +1 -1
  14. package/dist/authored-flow-lifecycle.js +7 -0
  15. package/dist/authored-flow-lifecycle.js.map +1 -1
  16. package/dist/authored-flow-operation.d.ts +11 -0
  17. package/dist/authored-flow-operation.d.ts.map +1 -1
  18. package/dist/authored-flow-operation.js +32 -7
  19. package/dist/authored-flow-operation.js.map +1 -1
  20. package/dist/authored-node-runner.d.ts.map +1 -1
  21. package/dist/authored-node-runner.js +37 -14
  22. package/dist/authored-node-runner.js.map +1 -1
  23. package/dist/authored-step-output.d.ts +2 -0
  24. package/dist/authored-step-output.d.ts.map +1 -1
  25. package/dist/authored-step-output.js +5 -1
  26. package/dist/authored-step-output.js.map +1 -1
  27. package/dist/authored-worker-step.d.ts.map +1 -1
  28. package/dist/authored-worker-step.js +15 -8
  29. package/dist/authored-worker-step.js.map +1 -1
  30. package/dist/cli/check-triggers.d.ts.map +1 -1
  31. package/dist/cli/check-triggers.js +10 -0
  32. package/dist/cli/check-triggers.js.map +1 -1
  33. package/dist/cli/check.d.ts +14 -0
  34. package/dist/cli/check.d.ts.map +1 -1
  35. package/dist/cli/check.js +6 -1
  36. package/dist/cli/check.js.map +1 -1
  37. package/dist/cli/cloud-deploy.d.ts +30 -0
  38. package/dist/cli/cloud-deploy.d.ts.map +1 -0
  39. package/dist/cli/cloud-deploy.js +162 -0
  40. package/dist/cli/cloud-deploy.js.map +1 -0
  41. package/dist/cli/cloud-run.d.ts +3 -1
  42. package/dist/cli/cloud-run.d.ts.map +1 -1
  43. package/dist/cli/cloud-run.js +37 -5
  44. package/dist/cli/cloud-run.js.map +1 -1
  45. package/dist/cli/cloud-schedule.d.ts +29 -0
  46. package/dist/cli/cloud-schedule.d.ts.map +1 -0
  47. package/dist/cli/cloud-schedule.js +131 -0
  48. package/dist/cli/cloud-schedule.js.map +1 -0
  49. package/dist/cli/cloud-sync.d.ts +13 -0
  50. package/dist/cli/cloud-sync.d.ts.map +1 -0
  51. package/dist/cli/cloud-sync.js +39 -0
  52. package/dist/cli/cloud-sync.js.map +1 -0
  53. package/dist/cli/direct-run.js +1 -1
  54. package/dist/cli/direct-run.js.map +1 -1
  55. package/dist/cli/run.d.ts +1 -1
  56. package/dist/cli/run.d.ts.map +1 -1
  57. package/dist/cli/run.js +17 -4
  58. package/dist/cli/run.js.map +1 -1
  59. package/dist/cli.d.ts.map +1 -1
  60. package/dist/cli.js +117 -12
  61. package/dist/cli.js.map +1 -1
  62. package/dist/cloud-deploy.d.ts +70 -0
  63. package/dist/cloud-deploy.d.ts.map +1 -0
  64. package/dist/cloud-deploy.js +192 -0
  65. package/dist/cloud-deploy.js.map +1 -0
  66. package/dist/cloud-http.d.ts +52 -2
  67. package/dist/cloud-http.d.ts.map +1 -1
  68. package/dist/cloud-http.js +135 -9
  69. package/dist/cloud-http.js.map +1 -1
  70. package/dist/cloud-run.d.ts +53 -0
  71. package/dist/cloud-run.d.ts.map +1 -1
  72. package/dist/cloud-run.js +97 -25
  73. package/dist/cloud-run.js.map +1 -1
  74. package/dist/cloud-schedule.d.ts +48 -0
  75. package/dist/cloud-schedule.d.ts.map +1 -0
  76. package/dist/cloud-schedule.js +125 -0
  77. package/dist/cloud-schedule.js.map +1 -0
  78. package/dist/cloud-sync.d.ts +66 -0
  79. package/dist/cloud-sync.d.ts.map +1 -0
  80. package/dist/cloud-sync.js +287 -0
  81. package/dist/cloud-sync.js.map +1 -0
  82. package/dist/failure-kinds.d.ts +10 -3
  83. package/dist/failure-kinds.d.ts.map +1 -1
  84. package/dist/failure-kinds.js +10 -0
  85. package/dist/failure-kinds.js.map +1 -1
  86. package/dist/index.d.ts +5 -0
  87. package/dist/index.d.ts.map +1 -1
  88. package/dist/index.js +5 -0
  89. package/dist/index.js.map +1 -1
  90. package/dist/named-gate-lowering.js +9 -0
  91. package/dist/named-gate-lowering.js.map +1 -1
  92. package/dist/named-gates.d.ts +1 -1
  93. package/dist/named-gates.d.ts.map +1 -1
  94. package/dist/named-gates.js +11 -1
  95. package/dist/named-gates.js.map +1 -1
  96. package/dist/preflight.d.ts.map +1 -1
  97. package/dist/preflight.js +155 -9
  98. package/dist/preflight.js.map +1 -1
  99. package/dist/schedule-trigger.d.ts +35 -0
  100. package/dist/schedule-trigger.d.ts.map +1 -0
  101. package/dist/schedule-trigger.js +53 -0
  102. package/dist/schedule-trigger.js.map +1 -0
  103. package/dist/spec.d.ts +11 -1
  104. package/dist/spec.d.ts.map +1 -1
  105. package/dist/spec.js.map +1 -1
  106. package/dist/trigger-executor.js +1 -1
  107. package/dist/trigger-executor.js.map +1 -1
  108. package/dist/validate.js +1 -1
  109. package/dist/validate.js.map +1 -1
  110. package/dist/worker-cli.d.ts +10 -0
  111. package/dist/worker-cli.d.ts.map +1 -1
  112. package/dist/worker-cli.js +51 -22
  113. package/dist/worker-cli.js.map +1 -1
  114. package/dist/worker.d.ts.map +1 -1
  115. package/dist/worker.js +9 -0
  116. package/dist/worker.js.map +1 -1
  117. package/dist/wrapper-session.d.ts +3 -1
  118. package/dist/wrapper-session.d.ts.map +1 -1
  119. package/dist/wrapper-session.js +6 -3
  120. package/dist/wrapper-session.js.map +1 -1
  121. package/package.json +3 -3
  122. package/src/agent-artifacts.ts +76 -0
  123. package/src/authored-flow-error.ts +1 -0
  124. package/src/authored-flow-executor.ts +95 -8
  125. package/src/authored-flow-lifecycle.ts +7 -0
  126. package/src/authored-flow-operation.ts +35 -10
  127. package/src/authored-node-runner.ts +35 -13
  128. package/src/authored-step-output.ts +6 -1
  129. package/src/authored-worker-step.ts +16 -9
  130. package/src/cli/check-triggers.ts +9 -0
  131. package/src/cli/check.ts +21 -1
  132. package/src/cli/cloud-deploy.ts +157 -0
  133. package/src/cli/cloud-run.ts +37 -6
  134. package/src/cli/cloud-schedule.ts +135 -0
  135. package/src/cli/cloud-sync.ts +37 -0
  136. package/src/cli/direct-run.ts +1 -1
  137. package/src/cli/run.ts +18 -5
  138. package/src/cli.ts +107 -12
  139. package/src/cloud-deploy.ts +247 -0
  140. package/src/cloud-http.ts +173 -9
  141. package/src/cloud-run.ts +143 -24
  142. package/src/cloud-schedule.ts +158 -0
  143. package/src/cloud-sync.ts +315 -0
  144. package/src/failure-kinds.ts +10 -0
  145. package/src/index.ts +14 -0
  146. package/src/named-gate-lowering.ts +9 -0
  147. package/src/named-gates.ts +11 -1
  148. package/src/preflight.ts +132 -9
  149. package/src/schedule-trigger.ts +73 -0
  150. package/src/spec.ts +12 -1
  151. package/src/trigger-executor.ts +1 -1
  152. package/src/validate.ts +1 -1
  153. package/src/worker-cli.ts +41 -0
  154. package/src/worker.ts +9 -0
  155. package/src/wrapper-session.ts +5 -1
package/src/spec.ts CHANGED
@@ -82,7 +82,18 @@ export interface RegexMatchGate {
82
82
  flags?: string;
83
83
  }
84
84
 
85
- export type NamedDataGate = ReferencesInputGate | SubprocessGate | WordCountBoundsGate | RegexMatchGate;
85
+ /**
86
+ * Passes when the step's journaled `output.artifacts` lists `path`: a file the
87
+ * agent's worker measured as created or changed under its working directory.
88
+ * Reads the journal, never the disk, so replay and resume see the same verdict.
89
+ */
90
+ export interface ArtifactExistsGate {
91
+ type: 'artifact_exists';
92
+ /** Working-directory-relative POSIX path, as the worker journals it. */
93
+ path: string;
94
+ }
95
+
96
+ export type NamedDataGate = ReferencesInputGate | SubprocessGate | WordCountBoundsGate | RegexMatchGate | ArtifactExistsGate;
86
97
  export type OutputVerificationSpec = OutputContainsGate | JsonSchemaGate | NamedDataGate;
87
98
  export type VerificationSpec = ExitCodeGate | OutputVerificationSpec;
88
99
 
@@ -3,7 +3,7 @@ import type { TriggerSpec } from './spec.js';
3
3
 
4
4
  /** Lower a surface subscription to the existing inbox executor contract. */
5
5
  export function webhookTriggerSpec(id: string, source: TriggerSource): TriggerSpec {
6
- if (source.kind !== 'webhook') throw new TypeError('unsupported trigger kind');
6
+ if (source.kind !== 'webhook') throw new TypeError('unsupported trigger kind: use scheduleTriggerSpec for schedule sources');
7
7
  const trigger = webhook(source.name, source.filter);
8
8
  return {
9
9
  id,
package/src/validate.ts CHANGED
@@ -446,7 +446,7 @@ class Validator {
446
446
  } else if (Object.hasOwn(NAMED_GATE_KEYS, gate.type)) {
447
447
  for (const error of namedGateErrors(v, input, at)) this.fail(error);
448
448
  } else {
449
- this.fail(`${at}.type: unknown_gate_kind: expected exit_code | output_contains | json_schema | references_input | subprocess_gate | word_count_bounds | regex_match`);
449
+ this.fail(`${at}.type: unknown_gate_kind: expected exit_code | output_contains | json_schema | references_input | subprocess_gate | word_count_bounds | regex_match | artifact_exists`);
450
450
  }
451
451
  }
452
452
 
package/src/worker-cli.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { resolve } from 'node:path';
2
+ import { diffWorkspaceFiles, snapshotWorkspaceFiles } from './agent-artifacts.js';
1
3
  import { decodeProviderResult, decodeWrapperResult, requirePricedUsage } from './worker-usage.js';
2
4
  import { openSidechannel, type SidechannelContext } from './pty-sidechannel.js';
3
5
  import { spawn } from 'node:child_process';
@@ -38,6 +40,16 @@ export interface WorkerCliResult {
38
40
  exit_code: number | null;
39
41
  stdout_tail: string;
40
42
  stderr_tail: string;
43
+ /**
44
+ * Files the agent created or changed under its working directory,
45
+ * cwd-relative POSIX paths, sorted. Measured by the worker that spawned the
46
+ * CLI — the one process provably sharing the agent's filesystem — as a
47
+ * content-hash diff of the directory before and after the run, so it is a
48
+ * journaled fact rather than a later guess. Present for every direct agent
49
+ * execution; absent for `llm` mode and for the relay transport, where the
50
+ * agent runs on another host.
51
+ */
52
+ artifacts?: string[];
41
53
  }
42
54
 
43
55
  /**
@@ -75,6 +87,22 @@ export async function runAgentCli(
75
87
  return runViaAgentRelay(kind, instruction, wakeContext, effectiveModel, relayContext, cwd, signal);
76
88
  }
77
89
 
90
+ // Artifact detection brackets the spawn: the directory the CLI runs in is
91
+ // snapshotted before and diffed after, by this process, on this
92
+ // filesystem. Only an agent execution writes artifacts; an llm step has no
93
+ // workspace to change. Executions sharing a working directory are
94
+ // serialized around their snapshot-spawn-snapshot interval, so one agent's
95
+ // writes are never attributed to a concurrent one in the same directory.
96
+ const artifactRoot = mode === 'agent' ? resolve(cwd ?? process.cwd()) : undefined;
97
+ return artifactRoot === undefined
98
+ ? execute()
99
+ : serializedByDirectory(artifactRoot, async () => {
100
+ const before = await snapshotWorkspaceFiles(artifactRoot);
101
+ const result = await execute();
102
+ return { ...result, artifacts: diffWorkspaceFiles(before, await snapshotWorkspaceFiles(artifactRoot)) };
103
+ });
104
+
105
+ async function execute(): Promise<WorkerCliResult> {
78
106
  if (kind === 'relayflows-wrapper-v1') {
79
107
  return requirePricedUsage(decodeWrapperResult(await runWrapperSession(
80
108
  cli,
@@ -84,6 +112,7 @@ export async function runAgentCli(
84
112
  wrapperEnvironment(process.env),
85
113
  wrapperLimits,
86
114
  signal,
115
+ cwd,
87
116
  )), effectiveModel);
88
117
  }
89
118
 
@@ -109,6 +138,18 @@ export async function runAgentCli(
109
138
  const args = [...invocation.args];
110
139
  args.splice(args.length - 1, 0, ...(kind === 'claude' ? ['--output-format', 'json'] : ['--json']));
111
140
  return requirePricedUsage(decodeProviderResult(await spawnInvocation(cli, { ...invocation, args }, env, signal, sidechannel, cwd), kind), effectiveModel);
141
+ }
142
+ }
143
+
144
+ /** One agent at a time per canonical working directory, for the artifact interval. */
145
+ const directoryQueues = new Map<string, Promise<unknown>>();
146
+ function serializedByDirectory<T>(directory: string, task: () => Promise<T>): Promise<T> {
147
+ const previous = directoryQueues.get(directory) ?? Promise.resolve();
148
+ const run = previous.then(task, task);
149
+ const settled = run.then(() => undefined, () => undefined);
150
+ directoryQueues.set(directory, settled);
151
+ void settled.then(() => { if (directoryQueues.get(directory) === settled) directoryQueues.delete(directory); });
152
+ return run;
112
153
  }
113
154
 
114
155
  /** Wait under the same worker lease for an authoritative task receipt. */
package/src/worker.ts CHANGED
@@ -133,6 +133,15 @@ export class AgentWorker extends EventEmitter {
133
133
  // emitting an error JSON with exit 0. `completionReason` is
134
134
  // derived from exit code, so a CLI that exits 0 while emitting
135
135
  // `{"error":...}` will report success with an error payload.
136
+ //
137
+ // `artifacts` (worker-cli.ts) rides inside the CliResult wrapper, so on
138
+ // the wrapper path it is journaled in `output`, where the kernel's output
139
+ // binding — and therefore an `artifact_exists` gate — can read it. On the
140
+ // JSON path the author's object IS the output and is left exactly as the
141
+ // agent emitted it: no key is added that a schema, a downstream binding
142
+ // or `summary` never asked for. An agent that answers with a JSON object
143
+ // therefore journals no artifacts; gate such a step on a deterministic
144
+ // check instead. The relay transport reports none (the agent ran elsewhere).
136
145
  const output = result.relay_task?.status === 'completed' && result.exit_code === 0
137
146
  ? result.relay_task.output : parseJsonOutput(result.stdout_tail) ?? result;
138
147
 
@@ -49,6 +49,8 @@ export function runWrapperSession(
49
49
  env: NodeJS.ProcessEnv,
50
50
  overrides: Partial<WrapperSessionLimits> = {},
51
51
  signal?: AbortSignal,
52
+ /** Working directory for the wrapper process; the artifact scanner uses the same root. */
53
+ cwd?: string,
52
54
  ): Promise<WrapperSessionResult> {
53
55
  if (signal?.aborted) return Promise.reject(signal.reason);
54
56
  if (signal !== undefined && process.platform === 'win32') {
@@ -77,7 +79,7 @@ export function runWrapperSession(
77
79
  ));
78
80
  }
79
81
 
80
- return executePinnedWrapper(cli, identity, request, env, limits, signal);
82
+ return executePinnedWrapper(cli, identity, request, env, limits, signal, cwd);
81
83
  }
82
84
 
83
85
  function executePinnedWrapper(
@@ -87,6 +89,7 @@ function executePinnedWrapper(
87
89
  env: NodeJS.ProcessEnv,
88
90
  limits: WrapperSessionLimits,
89
91
  signal?: AbortSignal,
92
+ cwd?: string,
90
93
  ): Promise<WrapperSessionResult> {
91
94
  return new Promise((resolve) => {
92
95
  const ownsGroup = ownsProcessGroup(signal);
@@ -94,6 +97,7 @@ function executePinnedWrapper(
94
97
  stdio: ['pipe', 'pipe', 'pipe'],
95
98
  env,
96
99
  detached: ownsGroup,
100
+ ...(cwd === undefined ? {} : { cwd }),
97
101
  });
98
102
  const stop = childStop(child, ownsGroup);
99
103
  const stdout: string[] = [];