agent-relay 4.0.0 → 4.0.1

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 (137) hide show
  1. package/README.md +5 -5
  2. package/bin/agent-relay-broker-darwin-arm64 +0 -0
  3. package/bin/agent-relay-broker-darwin-x64 +0 -0
  4. package/bin/agent-relay-broker-linux-arm64 +0 -0
  5. package/bin/agent-relay-broker-linux-x64 +0 -0
  6. package/dist/index.cjs +1980 -1024
  7. package/dist/src/cli/commands/core.d.ts.map +1 -1
  8. package/dist/src/cli/commands/core.js +4 -3
  9. package/dist/src/cli/commands/core.js.map +1 -1
  10. package/dist/src/cli/commands/on/relayfile-binary.d.ts +2 -0
  11. package/dist/src/cli/commands/on/relayfile-binary.d.ts.map +1 -0
  12. package/dist/src/cli/commands/on/relayfile-binary.js +208 -0
  13. package/dist/src/cli/commands/on/relayfile-binary.js.map +1 -0
  14. package/dist/src/cli/commands/on/start.d.ts.map +1 -1
  15. package/dist/src/cli/commands/on/start.js +62 -26
  16. package/dist/src/cli/commands/on/start.js.map +1 -1
  17. package/dist/src/cli/commands/on/workspace.d.ts.map +1 -1
  18. package/dist/src/cli/commands/on/workspace.js +4 -0
  19. package/dist/src/cli/commands/on/workspace.js.map +1 -1
  20. package/dist/src/cli/commands/on.js +1 -1
  21. package/dist/src/cli/commands/on.js.map +1 -1
  22. package/dist/src/cli/lib/client-factory.d.ts +2 -2
  23. package/dist/src/cli/lib/client-factory.d.ts.map +1 -1
  24. package/dist/src/cli/lib/client-factory.js.map +1 -1
  25. package/dist/src/cost/pricing.d.ts +18 -0
  26. package/dist/src/cost/pricing.d.ts.map +1 -0
  27. package/dist/src/cost/pricing.js +111 -0
  28. package/dist/src/cost/pricing.js.map +1 -0
  29. package/dist/src/cost/tracker.d.ts +13 -0
  30. package/dist/src/cost/tracker.d.ts.map +1 -0
  31. package/dist/src/cost/tracker.js +152 -0
  32. package/dist/src/cost/tracker.js.map +1 -0
  33. package/dist/src/cost/types.d.ts +23 -0
  34. package/dist/src/cost/types.d.ts.map +1 -0
  35. package/dist/src/cost/types.js +2 -0
  36. package/dist/src/cost/types.js.map +1 -0
  37. package/package.json +10 -10
  38. package/packages/acp-bridge/package.json +2 -2
  39. package/packages/brand/package.json +1 -1
  40. package/packages/cloud/package.json +3 -3
  41. package/packages/config/package.json +1 -1
  42. package/packages/hooks/package.json +4 -4
  43. package/packages/memory/package.json +2 -2
  44. package/packages/openclaw/package.json +2 -2
  45. package/packages/policy/package.json +2 -2
  46. package/packages/sdk/dist/broker-path.d.ts +3 -2
  47. package/packages/sdk/dist/broker-path.d.ts.map +1 -1
  48. package/packages/sdk/dist/broker-path.js +119 -32
  49. package/packages/sdk/dist/broker-path.js.map +1 -1
  50. package/packages/sdk/dist/client.d.ts +12 -2
  51. package/packages/sdk/dist/client.d.ts.map +1 -1
  52. package/packages/sdk/dist/client.js +20 -1
  53. package/packages/sdk/dist/client.js.map +1 -1
  54. package/packages/sdk/dist/index.d.ts +1 -1
  55. package/packages/sdk/dist/index.d.ts.map +1 -1
  56. package/packages/sdk/dist/index.js.map +1 -1
  57. package/packages/sdk/dist/relay.d.ts +2 -1
  58. package/packages/sdk/dist/relay.d.ts.map +1 -1
  59. package/packages/sdk/dist/relay.js +1 -1
  60. package/packages/sdk/dist/relay.js.map +1 -1
  61. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts +2 -0
  62. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.d.ts.map +1 -0
  63. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js +117 -0
  64. package/packages/sdk/dist/workflows/__tests__/channel-messenger.test.js.map +1 -0
  65. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js +4 -3
  66. package/packages/sdk/dist/workflows/__tests__/run-summary-table.test.js.map +1 -1
  67. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts +2 -0
  68. package/packages/sdk/dist/workflows/__tests__/step-executor.test.d.ts.map +1 -0
  69. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js +378 -0
  70. package/packages/sdk/dist/workflows/__tests__/step-executor.test.js.map +1 -0
  71. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts +2 -0
  72. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.d.ts.map +1 -0
  73. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js +145 -0
  74. package/packages/sdk/dist/workflows/__tests__/template-resolver.test.js.map +1 -0
  75. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts +2 -0
  76. package/packages/sdk/dist/workflows/__tests__/verification.test.d.ts.map +1 -0
  77. package/packages/sdk/dist/workflows/__tests__/verification.test.js +170 -0
  78. package/packages/sdk/dist/workflows/__tests__/verification.test.js.map +1 -0
  79. package/packages/sdk/dist/workflows/builder.d.ts +3 -2
  80. package/packages/sdk/dist/workflows/builder.d.ts.map +1 -1
  81. package/packages/sdk/dist/workflows/builder.js +1 -3
  82. package/packages/sdk/dist/workflows/builder.js.map +1 -1
  83. package/packages/sdk/dist/workflows/channel-messenger.d.ts +28 -0
  84. package/packages/sdk/dist/workflows/channel-messenger.d.ts.map +1 -0
  85. package/packages/sdk/dist/workflows/channel-messenger.js +255 -0
  86. package/packages/sdk/dist/workflows/channel-messenger.js.map +1 -0
  87. package/packages/sdk/dist/workflows/index.d.ts +7 -0
  88. package/packages/sdk/dist/workflows/index.d.ts.map +1 -1
  89. package/packages/sdk/dist/workflows/index.js +7 -0
  90. package/packages/sdk/dist/workflows/index.js.map +1 -1
  91. package/packages/sdk/dist/workflows/process-spawner.d.ts +35 -0
  92. package/packages/sdk/dist/workflows/process-spawner.d.ts.map +1 -0
  93. package/packages/sdk/dist/workflows/process-spawner.js +141 -0
  94. package/packages/sdk/dist/workflows/process-spawner.js.map +1 -0
  95. package/packages/sdk/dist/workflows/run.d.ts +2 -1
  96. package/packages/sdk/dist/workflows/run.d.ts.map +1 -1
  97. package/packages/sdk/dist/workflows/run.js.map +1 -1
  98. package/packages/sdk/dist/workflows/runner.d.ts +6 -6
  99. package/packages/sdk/dist/workflows/runner.d.ts.map +1 -1
  100. package/packages/sdk/dist/workflows/runner.js +443 -719
  101. package/packages/sdk/dist/workflows/runner.js.map +1 -1
  102. package/packages/sdk/dist/workflows/step-executor.d.ts +95 -0
  103. package/packages/sdk/dist/workflows/step-executor.d.ts.map +1 -0
  104. package/packages/sdk/dist/workflows/step-executor.js +393 -0
  105. package/packages/sdk/dist/workflows/step-executor.js.map +1 -0
  106. package/packages/sdk/dist/workflows/template-resolver.d.ts +33 -0
  107. package/packages/sdk/dist/workflows/template-resolver.d.ts.map +1 -0
  108. package/packages/sdk/dist/workflows/template-resolver.js +144 -0
  109. package/packages/sdk/dist/workflows/template-resolver.js.map +1 -0
  110. package/packages/sdk/dist/workflows/verification.d.ts +33 -0
  111. package/packages/sdk/dist/workflows/verification.d.ts.map +1 -0
  112. package/packages/sdk/dist/workflows/verification.js +122 -0
  113. package/packages/sdk/dist/workflows/verification.js.map +1 -0
  114. package/packages/sdk/package.json +2 -2
  115. package/packages/sdk/src/broker-path.ts +136 -30
  116. package/packages/sdk/src/client.ts +37 -3
  117. package/packages/sdk/src/index.ts +1 -0
  118. package/packages/sdk/src/relay.ts +6 -2
  119. package/packages/sdk/src/workflows/__tests__/channel-messenger.test.ts +137 -0
  120. package/packages/sdk/src/workflows/__tests__/run-summary-table.test.ts +4 -3
  121. package/packages/sdk/src/workflows/__tests__/step-executor.test.ts +444 -0
  122. package/packages/sdk/src/workflows/__tests__/template-resolver.test.ts +162 -0
  123. package/packages/sdk/src/workflows/__tests__/verification.test.ts +229 -0
  124. package/packages/sdk/src/workflows/builder.ts +6 -6
  125. package/packages/sdk/src/workflows/channel-messenger.ts +314 -0
  126. package/packages/sdk/src/workflows/index.ts +12 -0
  127. package/packages/sdk/src/workflows/process-spawner.ts +201 -0
  128. package/packages/sdk/src/workflows/run.ts +2 -1
  129. package/packages/sdk/src/workflows/runner.ts +636 -951
  130. package/packages/sdk/src/workflows/step-executor.ts +579 -0
  131. package/packages/sdk/src/workflows/template-resolver.ts +180 -0
  132. package/packages/sdk/src/workflows/verification.ts +184 -0
  133. package/packages/sdk-py/pyproject.toml +1 -1
  134. package/packages/telemetry/package.json +1 -1
  135. package/packages/trajectory/package.json +2 -2
  136. package/packages/user-directory/package.json +2 -2
  137. package/packages/utils/package.json +2 -2
package/dist/index.cjs CHANGED
@@ -4531,15 +4531,15 @@ var require_route = __commonJS({
4531
4531
  };
4532
4532
  }
4533
4533
  function wrapConversion(toModel, graph) {
4534
- const path18 = [graph[toModel].parent, toModel];
4534
+ const path19 = [graph[toModel].parent, toModel];
4535
4535
  let fn = conversions[graph[toModel].parent][toModel];
4536
4536
  let cur = graph[toModel].parent;
4537
4537
  while (graph[cur].parent) {
4538
- path18.unshift(graph[cur].parent);
4538
+ path19.unshift(graph[cur].parent);
4539
4539
  fn = link2(conversions[graph[cur].parent][cur], fn);
4540
4540
  cur = graph[cur].parent;
4541
4541
  }
4542
- fn.conversion = path18;
4542
+ fn.conversion = path19;
4543
4543
  return fn;
4544
4544
  }
4545
4545
  module2.exports = function(fromModel) {
@@ -5285,17 +5285,17 @@ var require_visit = __commonJS({
5285
5285
  visit.BREAK = BREAK;
5286
5286
  visit.SKIP = SKIP;
5287
5287
  visit.REMOVE = REMOVE;
5288
- function visit_(key, node, visitor, path18) {
5289
- const ctrl = callVisitor(key, node, visitor, path18);
5288
+ function visit_(key, node, visitor, path19) {
5289
+ const ctrl = callVisitor(key, node, visitor, path19);
5290
5290
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
5291
- replaceNode(key, path18, ctrl);
5292
- return visit_(key, ctrl, visitor, path18);
5291
+ replaceNode(key, path19, ctrl);
5292
+ return visit_(key, ctrl, visitor, path19);
5293
5293
  }
5294
5294
  if (typeof ctrl !== "symbol") {
5295
5295
  if (identity.isCollection(node)) {
5296
- path18 = Object.freeze(path18.concat(node));
5296
+ path19 = Object.freeze(path19.concat(node));
5297
5297
  for (let i = 0; i < node.items.length; ++i) {
5298
- const ci = visit_(i, node.items[i], visitor, path18);
5298
+ const ci = visit_(i, node.items[i], visitor, path19);
5299
5299
  if (typeof ci === "number")
5300
5300
  i = ci - 1;
5301
5301
  else if (ci === BREAK)
@@ -5306,13 +5306,13 @@ var require_visit = __commonJS({
5306
5306
  }
5307
5307
  }
5308
5308
  } else if (identity.isPair(node)) {
5309
- path18 = Object.freeze(path18.concat(node));
5310
- const ck = visit_("key", node.key, visitor, path18);
5309
+ path19 = Object.freeze(path19.concat(node));
5310
+ const ck = visit_("key", node.key, visitor, path19);
5311
5311
  if (ck === BREAK)
5312
5312
  return BREAK;
5313
5313
  else if (ck === REMOVE)
5314
5314
  node.key = null;
5315
- const cv = visit_("value", node.value, visitor, path18);
5315
+ const cv = visit_("value", node.value, visitor, path19);
5316
5316
  if (cv === BREAK)
5317
5317
  return BREAK;
5318
5318
  else if (cv === REMOVE)
@@ -5333,17 +5333,17 @@ var require_visit = __commonJS({
5333
5333
  visitAsync.BREAK = BREAK;
5334
5334
  visitAsync.SKIP = SKIP;
5335
5335
  visitAsync.REMOVE = REMOVE;
5336
- async function visitAsync_(key, node, visitor, path18) {
5337
- const ctrl = await callVisitor(key, node, visitor, path18);
5336
+ async function visitAsync_(key, node, visitor, path19) {
5337
+ const ctrl = await callVisitor(key, node, visitor, path19);
5338
5338
  if (identity.isNode(ctrl) || identity.isPair(ctrl)) {
5339
- replaceNode(key, path18, ctrl);
5340
- return visitAsync_(key, ctrl, visitor, path18);
5339
+ replaceNode(key, path19, ctrl);
5340
+ return visitAsync_(key, ctrl, visitor, path19);
5341
5341
  }
5342
5342
  if (typeof ctrl !== "symbol") {
5343
5343
  if (identity.isCollection(node)) {
5344
- path18 = Object.freeze(path18.concat(node));
5344
+ path19 = Object.freeze(path19.concat(node));
5345
5345
  for (let i = 0; i < node.items.length; ++i) {
5346
- const ci = await visitAsync_(i, node.items[i], visitor, path18);
5346
+ const ci = await visitAsync_(i, node.items[i], visitor, path19);
5347
5347
  if (typeof ci === "number")
5348
5348
  i = ci - 1;
5349
5349
  else if (ci === BREAK)
@@ -5354,13 +5354,13 @@ var require_visit = __commonJS({
5354
5354
  }
5355
5355
  }
5356
5356
  } else if (identity.isPair(node)) {
5357
- path18 = Object.freeze(path18.concat(node));
5358
- const ck = await visitAsync_("key", node.key, visitor, path18);
5357
+ path19 = Object.freeze(path19.concat(node));
5358
+ const ck = await visitAsync_("key", node.key, visitor, path19);
5359
5359
  if (ck === BREAK)
5360
5360
  return BREAK;
5361
5361
  else if (ck === REMOVE)
5362
5362
  node.key = null;
5363
- const cv = await visitAsync_("value", node.value, visitor, path18);
5363
+ const cv = await visitAsync_("value", node.value, visitor, path19);
5364
5364
  if (cv === BREAK)
5365
5365
  return BREAK;
5366
5366
  else if (cv === REMOVE)
@@ -5387,23 +5387,23 @@ var require_visit = __commonJS({
5387
5387
  }
5388
5388
  return visitor;
5389
5389
  }
5390
- function callVisitor(key, node, visitor, path18) {
5390
+ function callVisitor(key, node, visitor, path19) {
5391
5391
  if (typeof visitor === "function")
5392
- return visitor(key, node, path18);
5392
+ return visitor(key, node, path19);
5393
5393
  if (identity.isMap(node))
5394
- return visitor.Map?.(key, node, path18);
5394
+ return visitor.Map?.(key, node, path19);
5395
5395
  if (identity.isSeq(node))
5396
- return visitor.Seq?.(key, node, path18);
5396
+ return visitor.Seq?.(key, node, path19);
5397
5397
  if (identity.isPair(node))
5398
- return visitor.Pair?.(key, node, path18);
5398
+ return visitor.Pair?.(key, node, path19);
5399
5399
  if (identity.isScalar(node))
5400
- return visitor.Scalar?.(key, node, path18);
5400
+ return visitor.Scalar?.(key, node, path19);
5401
5401
  if (identity.isAlias(node))
5402
- return visitor.Alias?.(key, node, path18);
5402
+ return visitor.Alias?.(key, node, path19);
5403
5403
  return void 0;
5404
5404
  }
5405
- function replaceNode(key, path18, node) {
5406
- const parent = path18[path18.length - 1];
5405
+ function replaceNode(key, path19, node) {
5406
+ const parent = path19[path19.length - 1];
5407
5407
  if (identity.isCollection(parent)) {
5408
5408
  parent.items[key] = node;
5409
5409
  } else if (identity.isPair(parent)) {
@@ -6011,10 +6011,10 @@ var require_Collection = __commonJS({
6011
6011
  var createNode = require_createNode();
6012
6012
  var identity = require_identity();
6013
6013
  var Node = require_Node();
6014
- function collectionFromPath(schema, path18, value) {
6014
+ function collectionFromPath(schema, path19, value) {
6015
6015
  let v = value;
6016
- for (let i = path18.length - 1; i >= 0; --i) {
6017
- const k = path18[i];
6016
+ for (let i = path19.length - 1; i >= 0; --i) {
6017
+ const k = path19[i];
6018
6018
  if (typeof k === "number" && Number.isInteger(k) && k >= 0) {
6019
6019
  const a = [];
6020
6020
  a[k] = v;
@@ -6033,7 +6033,7 @@ var require_Collection = __commonJS({
6033
6033
  sourceObjects: /* @__PURE__ */ new Map()
6034
6034
  });
6035
6035
  }
6036
- var isEmptyPath = (path18) => path18 == null || typeof path18 === "object" && !!path18[Symbol.iterator]().next().done;
6036
+ var isEmptyPath = (path19) => path19 == null || typeof path19 === "object" && !!path19[Symbol.iterator]().next().done;
6037
6037
  var Collection = class extends Node.NodeBase {
6038
6038
  constructor(type, schema) {
6039
6039
  super(type);
@@ -6063,11 +6063,11 @@ var require_Collection = __commonJS({
6063
6063
  * be a Pair instance or a `{ key, value }` object, which may not have a key
6064
6064
  * that already exists in the map.
6065
6065
  */
6066
- addIn(path18, value) {
6067
- if (isEmptyPath(path18))
6066
+ addIn(path19, value) {
6067
+ if (isEmptyPath(path19))
6068
6068
  this.add(value);
6069
6069
  else {
6070
- const [key, ...rest] = path18;
6070
+ const [key, ...rest] = path19;
6071
6071
  const node = this.get(key, true);
6072
6072
  if (identity.isCollection(node))
6073
6073
  node.addIn(rest, value);
@@ -6081,8 +6081,8 @@ var require_Collection = __commonJS({
6081
6081
  * Removes a value from the collection.
6082
6082
  * @returns `true` if the item was found and removed.
6083
6083
  */
6084
- deleteIn(path18) {
6085
- const [key, ...rest] = path18;
6084
+ deleteIn(path19) {
6085
+ const [key, ...rest] = path19;
6086
6086
  if (rest.length === 0)
6087
6087
  return this.delete(key);
6088
6088
  const node = this.get(key, true);
@@ -6096,8 +6096,8 @@ var require_Collection = __commonJS({
6096
6096
  * scalar values from their surrounding node; to disable set `keepScalar` to
6097
6097
  * `true` (collections are always returned intact).
6098
6098
  */
6099
- getIn(path18, keepScalar) {
6100
- const [key, ...rest] = path18;
6099
+ getIn(path19, keepScalar) {
6100
+ const [key, ...rest] = path19;
6101
6101
  const node = this.get(key, true);
6102
6102
  if (rest.length === 0)
6103
6103
  return !keepScalar && identity.isScalar(node) ? node.value : node;
@@ -6115,8 +6115,8 @@ var require_Collection = __commonJS({
6115
6115
  /**
6116
6116
  * Checks if the collection includes a value with the key `key`.
6117
6117
  */
6118
- hasIn(path18) {
6119
- const [key, ...rest] = path18;
6118
+ hasIn(path19) {
6119
+ const [key, ...rest] = path19;
6120
6120
  if (rest.length === 0)
6121
6121
  return this.has(key);
6122
6122
  const node = this.get(key, true);
@@ -6126,8 +6126,8 @@ var require_Collection = __commonJS({
6126
6126
  * Sets a value in this collection. For `!!set`, `value` needs to be a
6127
6127
  * boolean to add/remove the item from the set.
6128
6128
  */
6129
- setIn(path18, value) {
6130
- const [key, ...rest] = path18;
6129
+ setIn(path19, value) {
6130
+ const [key, ...rest] = path19;
6131
6131
  if (rest.length === 0) {
6132
6132
  this.set(key, value);
6133
6133
  } else {
@@ -8639,9 +8639,9 @@ var require_Document = __commonJS({
8639
8639
  this.contents.add(value);
8640
8640
  }
8641
8641
  /** Adds a value to the document. */
8642
- addIn(path18, value) {
8642
+ addIn(path19, value) {
8643
8643
  if (assertCollection(this.contents))
8644
- this.contents.addIn(path18, value);
8644
+ this.contents.addIn(path19, value);
8645
8645
  }
8646
8646
  /**
8647
8647
  * Create a new `Alias` node, ensuring that the target `node` has the required anchor.
@@ -8716,14 +8716,14 @@ var require_Document = __commonJS({
8716
8716
  * Removes a value from the document.
8717
8717
  * @returns `true` if the item was found and removed.
8718
8718
  */
8719
- deleteIn(path18) {
8720
- if (Collection.isEmptyPath(path18)) {
8719
+ deleteIn(path19) {
8720
+ if (Collection.isEmptyPath(path19)) {
8721
8721
  if (this.contents == null)
8722
8722
  return false;
8723
8723
  this.contents = null;
8724
8724
  return true;
8725
8725
  }
8726
- return assertCollection(this.contents) ? this.contents.deleteIn(path18) : false;
8726
+ return assertCollection(this.contents) ? this.contents.deleteIn(path19) : false;
8727
8727
  }
8728
8728
  /**
8729
8729
  * Returns item at `key`, or `undefined` if not found. By default unwraps
@@ -8738,10 +8738,10 @@ var require_Document = __commonJS({
8738
8738
  * scalar values from their surrounding node; to disable set `keepScalar` to
8739
8739
  * `true` (collections are always returned intact).
8740
8740
  */
8741
- getIn(path18, keepScalar) {
8742
- if (Collection.isEmptyPath(path18))
8741
+ getIn(path19, keepScalar) {
8742
+ if (Collection.isEmptyPath(path19))
8743
8743
  return !keepScalar && identity.isScalar(this.contents) ? this.contents.value : this.contents;
8744
- return identity.isCollection(this.contents) ? this.contents.getIn(path18, keepScalar) : void 0;
8744
+ return identity.isCollection(this.contents) ? this.contents.getIn(path19, keepScalar) : void 0;
8745
8745
  }
8746
8746
  /**
8747
8747
  * Checks if the document includes a value with the key `key`.
@@ -8752,10 +8752,10 @@ var require_Document = __commonJS({
8752
8752
  /**
8753
8753
  * Checks if the document includes a value at `path`.
8754
8754
  */
8755
- hasIn(path18) {
8756
- if (Collection.isEmptyPath(path18))
8755
+ hasIn(path19) {
8756
+ if (Collection.isEmptyPath(path19))
8757
8757
  return this.contents !== void 0;
8758
- return identity.isCollection(this.contents) ? this.contents.hasIn(path18) : false;
8758
+ return identity.isCollection(this.contents) ? this.contents.hasIn(path19) : false;
8759
8759
  }
8760
8760
  /**
8761
8761
  * Sets a value in this document. For `!!set`, `value` needs to be a
@@ -8772,13 +8772,13 @@ var require_Document = __commonJS({
8772
8772
  * Sets a value in this document. For `!!set`, `value` needs to be a
8773
8773
  * boolean to add/remove the item from the set.
8774
8774
  */
8775
- setIn(path18, value) {
8776
- if (Collection.isEmptyPath(path18)) {
8775
+ setIn(path19, value) {
8776
+ if (Collection.isEmptyPath(path19)) {
8777
8777
  this.contents = value;
8778
8778
  } else if (this.contents == null) {
8779
- this.contents = Collection.collectionFromPath(this.schema, Array.from(path18), value);
8779
+ this.contents = Collection.collectionFromPath(this.schema, Array.from(path19), value);
8780
8780
  } else if (assertCollection(this.contents)) {
8781
- this.contents.setIn(path18, value);
8781
+ this.contents.setIn(path19, value);
8782
8782
  }
8783
8783
  }
8784
8784
  /**
@@ -10735,9 +10735,9 @@ var require_cst_visit = __commonJS({
10735
10735
  visit.BREAK = BREAK;
10736
10736
  visit.SKIP = SKIP;
10737
10737
  visit.REMOVE = REMOVE;
10738
- visit.itemAtPath = (cst, path18) => {
10738
+ visit.itemAtPath = (cst, path19) => {
10739
10739
  let item = cst;
10740
- for (const [field, index] of path18) {
10740
+ for (const [field, index] of path19) {
10741
10741
  const tok = item?.[field];
10742
10742
  if (tok && "items" in tok) {
10743
10743
  item = tok.items[index];
@@ -10746,23 +10746,23 @@ var require_cst_visit = __commonJS({
10746
10746
  }
10747
10747
  return item;
10748
10748
  };
10749
- visit.parentCollection = (cst, path18) => {
10750
- const parent = visit.itemAtPath(cst, path18.slice(0, -1));
10751
- const field = path18[path18.length - 1][0];
10749
+ visit.parentCollection = (cst, path19) => {
10750
+ const parent = visit.itemAtPath(cst, path19.slice(0, -1));
10751
+ const field = path19[path19.length - 1][0];
10752
10752
  const coll = parent?.[field];
10753
10753
  if (coll && "items" in coll)
10754
10754
  return coll;
10755
10755
  throw new Error("Parent collection not found");
10756
10756
  };
10757
- function _visit(path18, item, visitor) {
10758
- let ctrl = visitor(item, path18);
10757
+ function _visit(path19, item, visitor) {
10758
+ let ctrl = visitor(item, path19);
10759
10759
  if (typeof ctrl === "symbol")
10760
10760
  return ctrl;
10761
10761
  for (const field of ["key", "value"]) {
10762
10762
  const token = item[field];
10763
10763
  if (token && "items" in token) {
10764
10764
  for (let i = 0; i < token.items.length; ++i) {
10765
- const ci = _visit(Object.freeze(path18.concat([[field, i]])), token.items[i], visitor);
10765
+ const ci = _visit(Object.freeze(path19.concat([[field, i]])), token.items[i], visitor);
10766
10766
  if (typeof ci === "number")
10767
10767
  i = ci - 1;
10768
10768
  else if (ci === BREAK)
@@ -10773,10 +10773,10 @@ var require_cst_visit = __commonJS({
10773
10773
  }
10774
10774
  }
10775
10775
  if (typeof ctrl === "function" && field === "key")
10776
- ctrl = ctrl(item, path18);
10776
+ ctrl = ctrl(item, path19);
10777
10777
  }
10778
10778
  }
10779
- return typeof ctrl === "function" ? ctrl(item, path18) : ctrl;
10779
+ return typeof ctrl === "function" ? ctrl(item, path19) : ctrl;
10780
10780
  }
10781
10781
  exports2.visit = visit;
10782
10782
  }
@@ -16162,7 +16162,7 @@ __export(dist_exports, {
16162
16162
  cloneObject: () => cloneObject,
16163
16163
  color: () => color,
16164
16164
  createWritable: () => createWritable,
16165
- delay: () => delay,
16165
+ delay: () => delay2,
16166
16166
  figures: () => figures,
16167
16167
  getRenderer: () => getRenderer,
16168
16168
  getRendererClass: () => getRendererClass,
@@ -16246,9 +16246,9 @@ function assertFunctionOrSelf(functionOrSelf, ...args) {
16246
16246
  function cloneObject(obj) {
16247
16247
  return clone2(obj);
16248
16248
  }
16249
- function delay(time3) {
16250
- return new Promise((resolve3) => {
16251
- setTimeout(resolve3, time3);
16249
+ function delay2(time3) {
16250
+ return new Promise((resolve4) => {
16251
+ setTimeout(resolve4, time3);
16252
16252
  });
16253
16253
  }
16254
16254
  var import_node_util3, import_util6, import_os, import_string_decoder, import_stream2, import_rfdc, import_crypto, ANSI_ESCAPE2, ANSI_ESCAPE_CODES, ListrEnvironmentVariables, ListrErrorTypes, ListrEventType, ListrRendererSelection, ListrTaskEventType, ListrTaskState, EventManager, BaseEventMap, CLEAR_LINE_REGEX, BELL_REGEX, color, FIGURES_MAIN, FIGURES_FALLBACK, figures, ListrLogLevels, LISTR_LOGGER_STYLE, LISTR_LOGGER_STDERR_LEVELS, ListrLogger, ProcessOutputBuffer, ProcessOutputStream, ProcessOutput, ListrPromptAdapter, Spinner, ListrDefaultRendererLogLevels, LISTR_DEFAULT_RENDERER_STYLE, PRESET_TIMER, PRESET_TIMESTAMP, DefaultRenderer, SilentRenderer, SimpleRenderer, TestRendererSerializer, TestRenderer, VerboseRenderer, RENDERERS, clone2, Concurrency, ListrError, ListrRendererError, PromptError, TaskWrapper, ListrTaskEventManager, Task, ListrEventManager, Listr;
@@ -17434,8 +17434,8 @@ var init_dist = __esm({
17434
17434
  }
17435
17435
  add(fn) {
17436
17436
  if (this.count < this.concurrency) return this.run(fn);
17437
- return new Promise((resolve3) => {
17438
- const callback = () => resolve3(this.run(fn));
17437
+ return new Promise((resolve4) => {
17438
+ const callback = () => resolve4(this.run(fn));
17439
17439
  this.queue.add(callback);
17440
17440
  });
17441
17441
  }
@@ -17767,7 +17767,7 @@ var init_dist = __esm({
17767
17767
  const state = this.state;
17768
17768
  this.state$ = ListrTaskState.PAUSED;
17769
17769
  this.message$ = { paused: Date.now() + time3 };
17770
- await delay(time3);
17770
+ await delay2(time3);
17771
17771
  this.state$ = state;
17772
17772
  this.message$ = { paused: null };
17773
17773
  }
@@ -17785,20 +17785,20 @@ var init_dist = __esm({
17785
17785
  this.emit(ListrTaskEventType.SUBTASK, this.subtasks);
17786
17786
  result = result.run(context);
17787
17787
  } else if (result instanceof Promise) result = result.then(handleResult2);
17788
- else if (isReadable(result)) result = new Promise((resolve3, reject) => {
17788
+ else if (isReadable(result)) result = new Promise((resolve4, reject) => {
17789
17789
  result.on("data", (data) => {
17790
17790
  this.output$ = data.toString();
17791
17791
  });
17792
17792
  result.on("error", (error48) => reject(error48));
17793
- result.on("end", () => resolve3(null));
17793
+ result.on("end", () => resolve4(null));
17794
17794
  });
17795
- else if (isObservable(result)) result = new Promise((resolve3, reject) => {
17795
+ else if (isObservable(result)) result = new Promise((resolve4, reject) => {
17796
17796
  result.subscribe({
17797
17797
  next: (data) => {
17798
17798
  this.output$ = data;
17799
17799
  },
17800
17800
  error: reject,
17801
- complete: resolve3
17801
+ complete: resolve4
17802
17802
  });
17803
17803
  });
17804
17804
  return result;
@@ -18031,8 +18031,8 @@ function createWorkflowRenderer() {
18031
18031
  const stepHandles = /* @__PURE__ */ new Map();
18032
18032
  let resolveWorkflow;
18033
18033
  let rejectWorkflow;
18034
- const workflowDone = new Promise((resolve3, reject) => {
18035
- resolveWorkflow = resolve3;
18034
+ const workflowDone = new Promise((resolve4, reject) => {
18035
+ resolveWorkflow = resolve4;
18036
18036
  rejectWorkflow = reject;
18037
18037
  });
18038
18038
  workflowDone.catch(() => {
@@ -18085,8 +18085,8 @@ function createWorkflowRenderer() {
18085
18085
  let rejectStep;
18086
18086
  let taskRef = null;
18087
18087
  let skipped = false;
18088
- const done = new Promise((resolve3, reject) => {
18089
- resolveStep = resolve3;
18088
+ const done = new Promise((resolve4, reject) => {
18089
+ resolveStep = resolve4;
18090
18090
  rejectStep = reject;
18091
18091
  });
18092
18092
  done.catch(() => {
@@ -18803,8 +18803,8 @@ var init_supermemory = __esm({
18803
18803
  /**
18804
18804
  * Make a fetch request to the Supermemory API
18805
18805
  */
18806
- async fetch(path18, options) {
18807
- const url2 = `${this.endpoint}${path18}`;
18806
+ async fetch(path19, options) {
18807
+ const url2 = `${this.endpoint}${path19}`;
18808
18808
  const controller = new AbortController();
18809
18809
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
18810
18810
  try {
@@ -19697,6 +19697,7 @@ __export(index_exports, {
19697
19697
  COMMON_SEARCH_PATHS: () => COMMON_SEARCH_PATHS,
19698
19698
  CURSOR_MODEL_OPTIONS: () => CURSOR_MODEL_OPTIONS,
19699
19699
  CUSTOM_STEPS_FILE: () => CUSTOM_STEPS_FILE,
19700
+ ChannelMessenger: () => ChannelMessenger,
19700
19701
  ClaudeModels: () => ClaudeModels,
19701
19702
  CodexModels: () => CodexModels,
19702
19703
  ConsensusEngine: () => ConsensusEngine,
@@ -19726,24 +19727,33 @@ __export(index_exports, {
19726
19727
  ShadowManager: () => ShadowManager,
19727
19728
  StateStore: () => StateStore,
19728
19729
  StaticPatterns: () => StaticPatterns,
19730
+ StepExecutor: () => StepExecutor,
19729
19731
  SupermemoryAdapter: () => SupermemoryAdapter,
19730
19732
  SwarmCoordinator: () => SwarmCoordinator,
19731
19733
  SwarmPatterns: () => SwarmPatterns,
19732
19734
  TemplateRegistry: () => TemplateRegistry,
19735
+ TemplateResolver: () => TemplateResolver,
19733
19736
  TracedError: () => TracedError,
19734
19737
  WorkflowBuilder: () => WorkflowBuilder,
19738
+ WorkflowCompletionError: () => WorkflowCompletionError,
19735
19739
  WorkflowRunner: () => WorkflowRunner,
19740
+ WorkflowStepLifecycleExecutor: () => StepExecutor,
19736
19741
  WorkflowTrajectory: () => WorkflowTrajectory,
19737
19742
  benchmarkPatterns: () => benchmarkPatterns,
19738
19743
  brokerLog: () => brokerLog,
19739
19744
  buildBlockReason: () => buildBlockReason,
19745
+ buildCommand: () => buildCommand,
19740
19746
  buildModelSwitchCommand: () => buildModelSwitchCommand,
19747
+ checkExitCode: () => checkExitCode,
19748
+ checkFileExists: () => checkFileExists,
19741
19749
  checkForUpdates: () => checkForUpdates,
19742
19750
  checkForUpdatesInBackground: () => checkForUpdatesInBackground,
19751
+ checkOutputContains: () => checkOutputContains,
19743
19752
  cleanLines: () => cleanLines,
19744
19753
  clearBinaryCache: () => clearBinaryCache,
19745
19754
  clearResolveCache: () => clearResolveCache,
19746
19755
  collectCliSession: () => collectCliSession,
19756
+ collectOutput: () => collectOutput,
19747
19757
  commandExists: () => commandExists,
19748
19758
  connectionLog: () => connectionLog,
19749
19759
  countMessages: () => countMessages,
@@ -19755,12 +19765,14 @@ __export(index_exports, {
19755
19765
  createMemoryAdapter: () => createMemoryAdapter,
19756
19766
  createMemoryHooks: () => createMemoryHooks,
19757
19767
  createMemoryService: () => createMemoryService,
19768
+ createProcessSpawner: () => createProcessSpawner,
19758
19769
  createRequestEnvelope: () => createRequestEnvelope,
19759
19770
  createRequestHandler: () => createRequestHandler,
19760
19771
  createTraceableError: () => createTraceableError,
19761
19772
  createTrajectoryHooks: () => createTrajectoryHooks,
19762
19773
  createWorkflowRenderer: () => createWorkflowRenderer,
19763
19774
  customStepsFileExists: () => customStepsFileExists,
19775
+ detectCompletion: () => detectCompletion,
19764
19776
  estimateContextTokens: () => estimateContextTokens,
19765
19777
  estimateTokens: () => estimateTokens,
19766
19778
  executeApiStep: () => executeApiStep,
@@ -19768,10 +19780,12 @@ __export(index_exports, {
19768
19780
  findRelayPtyBinary: () => findRelayPtyBinary,
19769
19781
  followLogs: () => followLogs,
19770
19782
  formatDryRunReport: () => formatDryRunReport,
19783
+ formatError: () => formatError2,
19771
19784
  formatMessagePreview: () => formatMessagePreview,
19772
19785
  formatProposalMessage: () => formatProposalMessage,
19773
19786
  formatResultMessage: () => formatResultMessage,
19774
19787
  formatRunSummaryTable: () => formatRunSummaryTable,
19788
+ formatStepOutput: () => formatStepOutput,
19775
19789
  generateAgentName: () => generateAgentName,
19776
19790
  generateErrorId: () => generateErrorId,
19777
19791
  generateRequestId: () => generateRequestId,
@@ -19801,6 +19815,7 @@ __export(index_exports, {
19801
19815
  hasRelayPtyBinary: () => hasRelayPtyBinary,
19802
19816
  hasUnreadMessages: () => hasUnreadMessages,
19803
19817
  inboxExists: () => inboxExists,
19818
+ interpolateStepTask: () => interpolateStepTask,
19804
19819
  isAgentStep: () => isAgentStep,
19805
19820
  isConsensusCommand: () => isConsensusCommand,
19806
19821
  isCustomStep: () => isCustomStep,
@@ -19833,15 +19848,28 @@ __export(index_exports, {
19833
19848
  resolveCliSync: () => resolveCliSync,
19834
19849
  resolveCommand: () => resolveCommand,
19835
19850
  resolveCustomStep: () => resolveCustomStep,
19851
+ resolveDotPath: () => resolveDotPath,
19836
19852
  resolveSpawnPolicy: () => resolveSpawnPolicy,
19853
+ resolveStepOutputRef: () => resolveStepOutputRef,
19854
+ resolveTemplate: () => resolveTemplate,
19855
+ resolveTemplateForShell: () => resolveTemplateForShell,
19856
+ resolveVariables: () => resolveVariables,
19837
19857
  routerLog: () => routerLog,
19858
+ runVerification: () => runVerification,
19838
19859
  runWorkflow: () => runWorkflow,
19860
+ scrubForChannel: () => scrubForChannel,
19861
+ scrubSecrets: () => scrubSecrets,
19862
+ sendToChannel: () => sendToChannel,
19863
+ shellEscape: () => shellEscape,
19839
19864
  spawnFromEnv: () => spawnFromEnv,
19865
+ spawnProcess: () => spawnProcess,
19840
19866
  stripAnsi: () => stripAnsi,
19841
19867
  stripAnsiFast: () => stripAnsiFast,
19868
+ stripInjectedTaskEcho: () => stripInjectedTaskEcho,
19842
19869
  toReleaseResult: () => toReleaseResult,
19843
19870
  toSpawnResult: () => toSpawnResult,
19844
19871
  trackPatternPerformance: () => trackPatternPerformance,
19872
+ truncateMessage: () => truncateMessage,
19845
19873
  unescapeFenceMarkersFast: () => unescapeFenceMarkersFast,
19846
19874
  validateCustomStepsUsage: () => validateCustomStepsUsage,
19847
19875
  validateModelForCli: () => validateModelForCli,
@@ -19902,7 +19930,7 @@ var BrokerTransport = class {
19902
19930
  return this.baseUrl.replace(/^http/, "ws") + "/ws";
19903
19931
  }
19904
19932
  // ── HTTP ─────────────────────────────────────────────────────────────
19905
- async request(path18, init) {
19933
+ async request(path19, init) {
19906
19934
  const headers = new Headers(init?.headers);
19907
19935
  if (!headers.has("Content-Type")) {
19908
19936
  headers.set("Content-Type", "application/json");
@@ -19911,7 +19939,7 @@ var BrokerTransport = class {
19911
19939
  headers.set("X-API-Key", this.apiKey);
19912
19940
  }
19913
19941
  const signal = init?.signal ?? AbortSignal.timeout(this.requestTimeoutMs);
19914
- const res = await fetch(`${this.baseUrl}${path18}`, { ...init, headers, signal });
19942
+ const res = await fetch(`${this.baseUrl}${path19}`, { ...init, headers, signal });
19915
19943
  if (!res.ok) {
19916
19944
  let body;
19917
19945
  try {
@@ -20040,38 +20068,122 @@ var import_node_child_process = require("node:child_process");
20040
20068
  var import_node_module = require("node:module");
20041
20069
  var import_node_url = require("node:url");
20042
20070
  var BROKER_NAME = "agent-relay-broker";
20043
- function getBrokerBinaryPath() {
20044
- let binDir = null;
20071
+ function addUniquePath(paths, candidate) {
20072
+ if (!candidate || paths.includes(candidate)) {
20073
+ return;
20074
+ }
20075
+ paths.push(candidate);
20076
+ }
20077
+ function getImportMetaUrl() {
20045
20078
  try {
20046
- const esmRequire = (0, import_node_module.createRequire)(import_meta_url);
20047
- const sdkEntry = esmRequire.resolve("@agent-relay/sdk");
20048
- binDir = (0, import_node_path.join)((0, import_node_path.dirname)(sdkEntry), "..", "bin");
20079
+ return import_meta_url;
20049
20080
  } catch {
20081
+ return null;
20082
+ }
20083
+ }
20084
+ function getCurrentModuleDir() {
20085
+ if (typeof __dirname === "string" && __dirname) {
20086
+ return __dirname;
20087
+ }
20088
+ if (typeof __filename === "string" && __filename) {
20089
+ return (0, import_node_path.dirname)(__filename);
20090
+ }
20091
+ const importMetaUrl = getImportMetaUrl();
20092
+ if (!importMetaUrl) {
20093
+ return null;
20094
+ }
20095
+ try {
20096
+ return (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
20097
+ } catch {
20098
+ return null;
20099
+ }
20100
+ }
20101
+ function getCurrentModuleReference() {
20102
+ if (typeof __filename === "string" && __filename) {
20103
+ return __filename;
20104
+ }
20105
+ if (typeof __dirname === "string" && __dirname) {
20106
+ return (0, import_node_path.join)(__dirname, "broker-path.js");
20107
+ }
20108
+ return getImportMetaUrl();
20109
+ }
20110
+ function getSdkBinDirs() {
20111
+ const binDirs = [];
20112
+ const currentModuleDir = getCurrentModuleDir();
20113
+ if (currentModuleDir) {
20114
+ addUniquePath(binDirs, (0, import_node_path.resolve)(currentModuleDir, "..", "bin"));
20115
+ }
20116
+ const currentModuleReference = getCurrentModuleReference();
20117
+ if (currentModuleReference) {
20050
20118
  try {
20051
- binDir = (0, import_node_path.join)((0, import_node_path.dirname)((0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta_url))), "bin");
20119
+ const sdkEntry = (0, import_node_module.createRequire)(currentModuleReference).resolve("@agent-relay/sdk");
20120
+ addUniquePath(binDirs, (0, import_node_path.resolve)((0, import_node_path.dirname)(sdkEntry), "..", "bin"));
20052
20121
  } catch {
20053
20122
  }
20054
20123
  }
20055
- if (!binDir)
20056
- return null;
20057
- const ext = process.platform === "win32" ? ".exe" : "";
20058
- const exactPath = (0, import_node_path.join)(binDir, `${BROKER_NAME}${ext}`);
20059
- if ((0, import_node_fs.existsSync)(exactPath)) {
20060
- return exactPath;
20124
+ const importMetaUrl = getImportMetaUrl();
20125
+ if (importMetaUrl) {
20126
+ try {
20127
+ addUniquePath(binDirs, (0, import_node_path.resolve)((0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl)), "..", "bin"));
20128
+ } catch {
20129
+ }
20130
+ }
20131
+ return binDirs;
20132
+ }
20133
+ function getDevelopmentBinaryPaths(ext, binDirs) {
20134
+ const binaryPaths = [];
20135
+ const repoRoots = /* @__PURE__ */ new Set();
20136
+ const addRepoRoot = (candidate) => {
20137
+ if (!candidate) {
20138
+ return;
20139
+ }
20140
+ const repoRoot = (0, import_node_path.resolve)(candidate);
20141
+ if (repoRoots.has(repoRoot)) {
20142
+ return;
20143
+ }
20144
+ repoRoots.add(repoRoot);
20145
+ addUniquePath(binaryPaths, (0, import_node_path.join)(repoRoot, "target", "release", `${BROKER_NAME}${ext}`));
20146
+ addUniquePath(binaryPaths, (0, import_node_path.join)(repoRoot, "target", "debug", `${BROKER_NAME}${ext}`));
20147
+ };
20148
+ addRepoRoot(process.cwd());
20149
+ const currentModuleDir = getCurrentModuleDir();
20150
+ if (currentModuleDir) {
20151
+ addRepoRoot((0, import_node_path.resolve)(currentModuleDir, "..", "..", ".."));
20152
+ }
20153
+ for (const binDir of binDirs) {
20154
+ addRepoRoot((0, import_node_path.resolve)(binDir, "..", "..", ".."));
20061
20155
  }
20156
+ return binaryPaths;
20157
+ }
20158
+ function getBrokerBinaryPath() {
20159
+ const ext = process.platform === "win32" ? ".exe" : "";
20160
+ const binDirs = getSdkBinDirs();
20062
20161
  const platformSpecific = `${BROKER_NAME}-${process.platform}-${process.arch}${ext}`;
20063
- const platformPath = (0, import_node_path.join)(binDir, platformSpecific);
20064
- if ((0, import_node_fs.existsSync)(platformPath)) {
20065
- return platformPath;
20162
+ for (const binDir of binDirs) {
20163
+ const exactPath = (0, import_node_path.join)(binDir, `${BROKER_NAME}${ext}`);
20164
+ if ((0, import_node_fs.existsSync)(exactPath)) {
20165
+ return exactPath;
20166
+ }
20167
+ }
20168
+ for (const binDir of binDirs) {
20169
+ const platformPath = (0, import_node_path.join)(binDir, platformSpecific);
20170
+ if ((0, import_node_fs.existsSync)(platformPath)) {
20171
+ return platformPath;
20172
+ }
20173
+ }
20174
+ for (const developmentPath of getDevelopmentBinaryPaths(ext, binDirs)) {
20175
+ if ((0, import_node_fs.existsSync)(developmentPath)) {
20176
+ return developmentPath;
20177
+ }
20066
20178
  }
20067
20179
  try {
20068
20180
  const cmd = process.platform === "win32" ? "where" : "which";
20069
- const result = (0, import_node_child_process.execSync)(`${cmd} ${BROKER_NAME}`, {
20181
+ const result = (0, import_node_child_process.execFileSync)(cmd, [BROKER_NAME], {
20070
20182
  encoding: "utf-8",
20071
20183
  stdio: ["pipe", "pipe", "pipe"]
20072
20184
  }).trim();
20073
20185
  if (result) {
20074
- return result.split("\n")[0].trim();
20186
+ return result.split(/\r?\n/u)[0].trim();
20075
20187
  }
20076
20188
  } catch {
20077
20189
  }
@@ -20096,6 +20208,25 @@ function isProcessRunning(pid) {
20096
20208
  return error48.code === "EPERM";
20097
20209
  }
20098
20210
  }
20211
+ function buildBrokerInitArgs(args) {
20212
+ if (!args) {
20213
+ return [];
20214
+ }
20215
+ const cliArgs = [];
20216
+ if (args.persist) {
20217
+ cliArgs.push("--persist");
20218
+ }
20219
+ if (args.apiPort !== void 0) {
20220
+ cliArgs.push("--api-port", String(args.apiPort));
20221
+ }
20222
+ if (args.apiBind !== void 0) {
20223
+ cliArgs.push("--api-bind", args.apiBind);
20224
+ }
20225
+ if (args.stateDir !== void 0) {
20226
+ cliArgs.push("--state-dir", args.stateDir);
20227
+ }
20228
+ return cliArgs;
20229
+ }
20099
20230
  var AgentRelayClient = class _AgentRelayClient {
20100
20231
  transport;
20101
20232
  /** Set after spawn() — the managed child process. */
@@ -20157,7 +20288,7 @@ var AgentRelayClient = class _AgentRelayClient {
20157
20288
  const brokerName = options?.brokerName ?? (import_node_path2.default.basename(cwd) || "project");
20158
20289
  const channels = options?.channels ?? ["general"];
20159
20290
  const timeoutMs = options?.startupTimeoutMs ?? 15e3;
20160
- const userArgs = options?.binaryArgs ?? [];
20291
+ const userArgs = buildBrokerInitArgs(options?.binaryArgs);
20161
20292
  const apiKey = `br_${(0, import_node_crypto.randomBytes)(16).toString("hex")}`;
20162
20293
  const env = {
20163
20294
  ...process.env,
@@ -20408,7 +20539,7 @@ var AgentRelayClient = class _AgentRelayClient {
20408
20539
  };
20409
20540
  async function waitForApiUrl(child, timeoutMs) {
20410
20541
  const { createInterface: createInterface2 } = await import("node:readline");
20411
- return new Promise((resolve3, reject) => {
20542
+ return new Promise((resolve4, reject) => {
20412
20543
  if (!child.stdout) {
20413
20544
  reject(new Error("Broker stdout not available"));
20414
20545
  return;
@@ -20446,24 +20577,24 @@ async function waitForApiUrl(child, timeoutMs) {
20446
20577
  resolved = true;
20447
20578
  clearTimeout(timer);
20448
20579
  rl.close();
20449
- resolve3(match[1]);
20580
+ resolve4(match[1]);
20450
20581
  }
20451
20582
  });
20452
20583
  });
20453
20584
  }
20454
20585
  function waitForExit(child, timeoutMs) {
20455
- return new Promise((resolve3) => {
20586
+ return new Promise((resolve4) => {
20456
20587
  if (child.exitCode !== null) {
20457
- resolve3();
20588
+ resolve4();
20458
20589
  return;
20459
20590
  }
20460
20591
  const timer = setTimeout(() => {
20461
20592
  child.kill("SIGKILL");
20462
- resolve3();
20593
+ resolve4();
20463
20594
  }, timeoutMs);
20464
20595
  child.on("exit", () => {
20465
20596
  clearTimeout(timer);
20466
- resolve3();
20597
+ resolve4();
20467
20598
  });
20468
20599
  });
20469
20600
  }
@@ -20984,8 +21115,8 @@ function getErrorMap() {
20984
21115
 
20985
21116
  // node_modules/zod/v3/helpers/parseUtil.js
20986
21117
  var makeIssue = (params) => {
20987
- const { data, path: path18, errorMaps, issueData } = params;
20988
- const fullPath = [...path18, ...issueData.path || []];
21118
+ const { data, path: path19, errorMaps, issueData } = params;
21119
+ const fullPath = [...path19, ...issueData.path || []];
20989
21120
  const fullIssue = {
20990
21121
  ...issueData,
20991
21122
  path: fullPath
@@ -21101,11 +21232,11 @@ var errorUtil;
21101
21232
 
21102
21233
  // node_modules/zod/v3/types.js
21103
21234
  var ParseInputLazyPath = class {
21104
- constructor(parent, value, path18, key) {
21235
+ constructor(parent, value, path19, key) {
21105
21236
  this._cachedPath = [];
21106
21237
  this.parent = parent;
21107
21238
  this.data = value;
21108
- this._path = path18;
21239
+ this._path = path19;
21109
21240
  this._key = key;
21110
21241
  }
21111
21242
  get path() {
@@ -27416,10 +27547,10 @@ function mergeDefs(...defs) {
27416
27547
  function cloneDef(schema) {
27417
27548
  return mergeDefs(schema._zod.def);
27418
27549
  }
27419
- function getElementAtPath(obj, path18) {
27420
- if (!path18)
27550
+ function getElementAtPath(obj, path19) {
27551
+ if (!path19)
27421
27552
  return obj;
27422
- return path18.reduce((acc, key) => acc?.[key], obj);
27553
+ return path19.reduce((acc, key) => acc?.[key], obj);
27423
27554
  }
27424
27555
  function promiseAllObject(promisesObj) {
27425
27556
  const keys = Object.keys(promisesObj);
@@ -27802,11 +27933,11 @@ function aborted(x, startIndex = 0) {
27802
27933
  }
27803
27934
  return false;
27804
27935
  }
27805
- function prefixIssues(path18, issues) {
27936
+ function prefixIssues(path19, issues) {
27806
27937
  return issues.map((iss) => {
27807
27938
  var _a2;
27808
27939
  (_a2 = iss).path ?? (_a2.path = []);
27809
- iss.path.unshift(path18);
27940
+ iss.path.unshift(path19);
27810
27941
  return iss;
27811
27942
  });
27812
27943
  }
@@ -27989,7 +28120,7 @@ function formatError(error48, mapper = (issue2) => issue2.message) {
27989
28120
  }
27990
28121
  function treeifyError(error48, mapper = (issue2) => issue2.message) {
27991
28122
  const result = { errors: [] };
27992
- const processError = (error49, path18 = []) => {
28123
+ const processError = (error49, path19 = []) => {
27993
28124
  var _a2, _b;
27994
28125
  for (const issue2 of error49.issues) {
27995
28126
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -27999,7 +28130,7 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
27999
28130
  } else if (issue2.code === "invalid_element") {
28000
28131
  processError({ issues: issue2.issues }, issue2.path);
28001
28132
  } else {
28002
- const fullpath = [...path18, ...issue2.path];
28133
+ const fullpath = [...path19, ...issue2.path];
28003
28134
  if (fullpath.length === 0) {
28004
28135
  result.errors.push(mapper(issue2));
28005
28136
  continue;
@@ -28031,8 +28162,8 @@ function treeifyError(error48, mapper = (issue2) => issue2.message) {
28031
28162
  }
28032
28163
  function toDotPath(_path) {
28033
28164
  const segs = [];
28034
- const path18 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
28035
- for (const seg of path18) {
28165
+ const path19 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
28166
+ for (const seg of path19) {
28036
28167
  if (typeof seg === "number")
28037
28168
  segs.push(`[${seg}]`);
28038
28169
  else if (typeof seg === "symbol")
@@ -40009,13 +40140,13 @@ function resolveRef(ref, ctx) {
40009
40140
  if (!ref.startsWith("#")) {
40010
40141
  throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
40011
40142
  }
40012
- const path18 = ref.slice(1).split("/").filter(Boolean);
40013
- if (path18.length === 0) {
40143
+ const path19 = ref.slice(1).split("/").filter(Boolean);
40144
+ if (path19.length === 0) {
40014
40145
  return ctx.rootSchema;
40015
40146
  }
40016
40147
  const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
40017
- if (path18[0] === defsKey) {
40018
- const key = path18[1];
40148
+ if (path19[0] === defsKey) {
40149
+ const key = path19[1];
40019
40150
  if (!key || !ctx.defs[key]) {
40020
40151
  throw new Error(`Reference not found: ${ref}`);
40021
40152
  }
@@ -41660,11 +41791,11 @@ var WsClient = class {
41660
41791
  this.reconnectAttempt += 1;
41661
41792
  const reconnectingEvent = { type: "reconnecting", attempt: this.reconnectAttempt };
41662
41793
  this.emit("reconnecting", reconnectingEvent);
41663
- const delay2 = this.computeReconnectDelayMs(this.reconnectAttempt);
41794
+ const delay3 = this.computeReconnectDelayMs(this.reconnectAttempt);
41664
41795
  this.reconnectTimer = setTimeout(() => {
41665
41796
  this.reconnectTimer = null;
41666
41797
  this.connect();
41667
- }, delay2);
41798
+ }, delay3);
41668
41799
  }
41669
41800
  };
41670
41801
 
@@ -42074,7 +42205,7 @@ function withInternalOrigin(options, origin) {
42074
42205
  return copy;
42075
42206
  }
42076
42207
  function sleep(ms) {
42077
- return new Promise((resolve3) => setTimeout(resolve3, ms));
42208
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
42078
42209
  }
42079
42210
  var DEFAULT_RETRY_POLICY = {
42080
42211
  maxRetries: 3,
@@ -42165,8 +42296,8 @@ var HttpClient = class _HttpClient {
42165
42296
  version: this._originVersion
42166
42297
  }));
42167
42298
  }
42168
- async request(method, path18, body, query, options) {
42169
- const url2 = new URL(path18, this._baseUrl);
42299
+ async request(method, path19, body, query, options) {
42300
+ const url2 = new URL(path19, this._baseUrl);
42170
42301
  if (query) {
42171
42302
  for (const [k, v] of Object.entries(query)) {
42172
42303
  if (v !== void 0)
@@ -42236,20 +42367,20 @@ var HttpClient = class _HttpClient {
42236
42367
  return camelizeKeys(parsedData);
42237
42368
  }
42238
42369
  }
42239
- get(path18, query, options) {
42240
- return this.request("GET", path18, void 0, query, options);
42370
+ get(path19, query, options) {
42371
+ return this.request("GET", path19, void 0, query, options);
42241
42372
  }
42242
- post(path18, body, options) {
42243
- return this.request("POST", path18, body, void 0, options);
42373
+ post(path19, body, options) {
42374
+ return this.request("POST", path19, body, void 0, options);
42244
42375
  }
42245
- patch(path18, body, options) {
42246
- return this.request("PATCH", path18, body, void 0, options);
42376
+ patch(path19, body, options) {
42377
+ return this.request("PATCH", path19, body, void 0, options);
42247
42378
  }
42248
- put(path18, body, options) {
42249
- return this.request("PUT", path18, body, void 0, options);
42379
+ put(path19, body, options) {
42380
+ return this.request("PUT", path19, body, void 0, options);
42250
42381
  }
42251
- async delete(path18, options) {
42252
- await this.request("DELETE", path18, void 0, void 0, options);
42382
+ async delete(path19, options) {
42383
+ await this.request("DELETE", path19, void 0, void 0, options);
42253
42384
  }
42254
42385
  };
42255
42386
 
@@ -43162,7 +43293,7 @@ var AgentRelay = class {
43162
43293
  if (!result.targets.length) {
43163
43294
  return { eventId: result.event_id, status: "failed", targets: [] };
43164
43295
  }
43165
- return new Promise((resolve3) => {
43296
+ return new Promise((resolve4) => {
43166
43297
  let resolved = false;
43167
43298
  const ackedTargets = /* @__PURE__ */ new Set();
43168
43299
  let unsubscribe;
@@ -43170,7 +43301,7 @@ var AgentRelay = class {
43170
43301
  if (!resolved) {
43171
43302
  resolved = true;
43172
43303
  unsubscribe?.();
43173
- resolve3({ eventId: result.event_id, status: "timeout", targets: result.targets });
43304
+ resolve4({ eventId: result.event_id, status: "timeout", targets: result.targets });
43174
43305
  }
43175
43306
  }, timeoutMs);
43176
43307
  unsubscribe = client.onEvent((event) => {
@@ -43182,14 +43313,14 @@ var AgentRelay = class {
43182
43313
  resolved = true;
43183
43314
  clearTimeout(timer);
43184
43315
  unsubscribe?.();
43185
- resolve3({ eventId: result.event_id, status: "ack", targets: result.targets });
43316
+ resolve4({ eventId: result.event_id, status: "ack", targets: result.targets });
43186
43317
  }
43187
43318
  }
43188
43319
  if (event.kind === "delivery_failed" && event.event_id === result.event_id && result.targets.includes(event.name)) {
43189
43320
  resolved = true;
43190
43321
  clearTimeout(timer);
43191
43322
  unsubscribe?.();
43192
- resolve3({ eventId: result.event_id, status: "failed", targets: result.targets });
43323
+ resolve4({ eventId: result.event_id, status: "failed", targets: result.targets });
43193
43324
  }
43194
43325
  });
43195
43326
  });
@@ -43308,7 +43439,7 @@ var AgentRelay = class {
43308
43439
  if (existing && this.readyAgents.has(name)) {
43309
43440
  return existing;
43310
43441
  }
43311
- return new Promise((resolve3, reject) => {
43442
+ return new Promise((resolve4, reject) => {
43312
43443
  let settled = false;
43313
43444
  let timeout;
43314
43445
  const cleanup = () => {
@@ -43323,7 +43454,7 @@ var AgentRelay = class {
43323
43454
  return;
43324
43455
  settled = true;
43325
43456
  cleanup();
43326
- resolve3(agent);
43457
+ resolve4(agent);
43327
43458
  };
43328
43459
  const rejectWith = (error48) => {
43329
43460
  if (settled)
@@ -43356,7 +43487,7 @@ var AgentRelay = class {
43356
43487
  if (existing && this.messageReadyAgents.has(name)) {
43357
43488
  return existing;
43358
43489
  }
43359
- return new Promise((resolve3, reject) => {
43490
+ return new Promise((resolve4, reject) => {
43360
43491
  let settled = false;
43361
43492
  let timeout;
43362
43493
  const cleanup = () => {
@@ -43371,7 +43502,7 @@ var AgentRelay = class {
43371
43502
  return;
43372
43503
  settled = true;
43373
43504
  cleanup();
43374
- resolve3(agent);
43505
+ resolve4(agent);
43375
43506
  };
43376
43507
  const rejectWith = (error48) => {
43377
43508
  if (settled)
@@ -43786,13 +43917,13 @@ var AgentRelay = class {
43786
43917
  await relay.waitForAgentReady(name, timeoutMs);
43787
43918
  },
43788
43919
  waitForExit(timeoutMs) {
43789
- return new Promise((resolve3) => {
43920
+ return new Promise((resolve4) => {
43790
43921
  if (!relay.knownAgents.has(name)) {
43791
- resolve3("exited");
43922
+ resolve4("exited");
43792
43923
  return;
43793
43924
  }
43794
43925
  if (timeoutMs === 0) {
43795
- resolve3("timeout");
43926
+ resolve4("timeout");
43796
43927
  return;
43797
43928
  }
43798
43929
  let timer;
@@ -43801,7 +43932,7 @@ var AgentRelay = class {
43801
43932
  resolve(reason) {
43802
43933
  if (timer)
43803
43934
  clearTimeout(timer);
43804
- resolve3(reason);
43935
+ resolve4(reason);
43805
43936
  },
43806
43937
  token
43807
43938
  });
@@ -43811,19 +43942,19 @@ var AgentRelay = class {
43811
43942
  if (current?.token === token) {
43812
43943
  relay.exitResolvers.delete(name);
43813
43944
  }
43814
- resolve3("timeout");
43945
+ resolve4("timeout");
43815
43946
  }, timeoutMs);
43816
43947
  }
43817
43948
  });
43818
43949
  },
43819
43950
  waitForIdle(timeoutMs) {
43820
- return new Promise((resolve3) => {
43951
+ return new Promise((resolve4) => {
43821
43952
  if (!relay.knownAgents.has(name)) {
43822
- resolve3("exited");
43953
+ resolve4("exited");
43823
43954
  return;
43824
43955
  }
43825
43956
  if (timeoutMs === 0) {
43826
- resolve3("timeout");
43957
+ resolve4("timeout");
43827
43958
  return;
43828
43959
  }
43829
43960
  let timer;
@@ -43832,7 +43963,7 @@ var AgentRelay = class {
43832
43963
  resolve(reason) {
43833
43964
  if (timer)
43834
43965
  clearTimeout(timer);
43835
- resolve3(reason);
43966
+ resolve4(reason);
43836
43967
  },
43837
43968
  token
43838
43969
  });
@@ -43842,7 +43973,7 @@ var AgentRelay = class {
43842
43973
  if (current?.token === token) {
43843
43974
  relay.idleResolvers.delete(name);
43844
43975
  }
43845
- resolve3("timeout");
43976
+ resolve4("timeout");
43846
43977
  }, timeoutMs);
43847
43978
  }
43848
43979
  });
@@ -44826,12 +44957,12 @@ function isAgentStep(step) {
44826
44957
  }
44827
44958
 
44828
44959
  // packages/sdk/dist/workflows/runner.js
44829
- var import_node_child_process5 = require("node:child_process");
44960
+ var import_node_child_process6 = require("node:child_process");
44830
44961
  var import_node_crypto5 = require("node:crypto");
44831
- var import_node_fs10 = require("node:fs");
44962
+ var import_node_fs11 = require("node:fs");
44832
44963
  var import_promises5 = require("node:fs/promises");
44833
44964
  var import_node_os7 = require("node:os");
44834
- var import_node_path13 = __toESM(require("node:path"), 1);
44965
+ var import_node_path14 = __toESM(require("node:path"), 1);
44835
44966
  var import_chalk = __toESM(require_source(), 1);
44836
44967
  var import_yaml2 = __toESM(require_dist(), 1);
44837
44968
 
@@ -45089,9 +45220,9 @@ async function resolveCli(cli) {
45089
45220
  for (const binary of def.binaries) {
45090
45221
  try {
45091
45222
  const { stdout } = await execFileAsync("which", [binary]);
45092
- const path18 = stdout.trim();
45093
- if (path18) {
45094
- const result = { binary, path: path18 };
45223
+ const path19 = stdout.trim();
45224
+ if (path19) {
45225
+ const result = { binary, path: path19 };
45095
45226
  resolveCache.set(cli, result);
45096
45227
  return result;
45097
45228
  }
@@ -45124,13 +45255,13 @@ function resolveCliSync(cli) {
45124
45255
  const def = getCliDefinition(cli);
45125
45256
  if (!def)
45126
45257
  return void 0;
45127
- const { execFileSync } = require("node:child_process");
45258
+ const { execFileSync: execFileSync2 } = require("node:child_process");
45128
45259
  for (const binary of def.binaries) {
45129
45260
  try {
45130
- const stdout = execFileSync("which", [binary], { stdio: ["pipe", "pipe", "ignore"] });
45131
- const path18 = stdout.toString().trim();
45132
- if (path18) {
45133
- const result = { binary, path: path18 };
45261
+ const stdout = execFileSync2("which", [binary], { stdio: ["pipe", "pipe", "ignore"] });
45262
+ const path19 = stdout.toString().trim();
45263
+ if (path19) {
45264
+ const result = { binary, path: path19 };
45134
45265
  resolveCache.set(cli, result);
45135
45266
  return result;
45136
45267
  }
@@ -46282,6 +46413,224 @@ async function executeApiStep(model, task, options = {}) {
46282
46413
  return response.content;
46283
46414
  }
46284
46415
 
46416
+ // packages/sdk/dist/workflows/channel-messenger.js
46417
+ async function sendToChannel(relay, channel, message) {
46418
+ await relay.send(channel, message);
46419
+ }
46420
+ function truncateMessage(message, maxLength) {
46421
+ if (maxLength <= 0)
46422
+ return "";
46423
+ return message.length > maxLength ? message.slice(-maxLength) : message;
46424
+ }
46425
+ function formatStepOutput(stepName, output, maxLength = 2e3) {
46426
+ const scrubbed = scrubForChannel(output);
46427
+ if (scrubbed.length === 0) {
46428
+ return `**[${stepName}]** Step completed \u2014 output written to disk`;
46429
+ }
46430
+ const preview = truncateMessage(scrubbed, maxLength);
46431
+ return `**[${stepName}] Output:**
46432
+ \`\`\`
46433
+ ${preview}
46434
+ \`\`\``;
46435
+ }
46436
+ function formatError2(stepName, error48) {
46437
+ const raw = error48 instanceof Error ? error48.message : String(error48);
46438
+ const message = raw.replace(/(?:\/[\w.-]+){3,}/g, "[path]");
46439
+ return `**[${stepName}]** Failed: ${message}`;
46440
+ }
46441
+ var SECRET_PATTERNS = [
46442
+ /(?:api[_-]?key|apikey|secret[_-]?key|access[_-]?token|auth[_-]?token|bearer)\s*[:=]\s*\S+/gi,
46443
+ /(?:sk|pk|rk|ak)[-_][a-zA-Z0-9]{20,}/g,
46444
+ /ghp_[a-zA-Z0-9]{36,}/g,
46445
+ /gho_[a-zA-Z0-9]{36,}/g,
46446
+ /github_pat_[a-zA-Z0-9_]{22,}/g,
46447
+ /xox[bpors]-[a-zA-Z0-9-]+/g,
46448
+ /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----[\s\S]*?-----END/g
46449
+ ];
46450
+ var SPINNER = "\\u2756\\u2738\\u2739\\u273a\\u273b\\u273c\\u273d\\u2731\\u2732\\u2733\\u2734\\u2735\\u2736\\u2737\\u2743\\u2745\\u2746\\u25d6\\u25d7\\u25d8\\u25d9\\u2022\\u25cf\\u25cb\\u25a0\\u25a1\\u25b6\\u25c0\\u23f5\\u23f6\\u23f7\\u23f8\\u23f9\\u25e2\\u25e3\\u25e4\\u25e5\\u2597\\u2596\\u2598\\u259d\\u2bc8\\u2bc7\\u2bc5\\u2bc6\\u00b7\\u2590\\u258c\\u2588\\u2584\\u2580\\u259a\\u259e\\u2b21\\u2b22";
46451
+ var SPINNER_RE = new RegExp(`[${SPINNER}]`, "gu");
46452
+ var SPINNER_CLASS_RE = new RegExp(`^[\\s${SPINNER}]*$`, "u");
46453
+ var BOX_DRAWING_ONLY_RE = /^[\s\u2500-\u257f\u2580-\u259f\u25a0-\u25ff\-_=~]{3,}$/u;
46454
+ var BROKER_LOG_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s+(?:INFO|WARN|ERROR|DEBUG)\s/u;
46455
+ var CLAUDE_HEADER_RE = /^(?:[\s\u2580-\u259f✢*·▗▖▘▝]+\s*)?(?:Claude\s+Code(?:\s+v?[\d.]+)?|(?:Sonnet|Haiku|Opus)\s*[\d.]+|claude-(?:sonnet|haiku|opus)-[\w.-]+|Running\s+on\s+claude)/iu;
46456
+ var DIR_BREADCRUMB_RE = /^\s*~[\\/]/u;
46457
+ var UI_HINT_RE = /\b(?:Press\s+up\s+to\s+edit|tab\s+to\s+queue|bypass\s+permissions|esc\s+to\s+interrupt)\b/iu;
46458
+ var THINKING_LINE_RE = new RegExp(`^[\\s${SPINNER}]*\\s*\\w[\\w\\s]*\\u2026\\s*$`, "u");
46459
+ var CURSOR_ONLY_RE = /^[\s❯⎿›»◀▶←→↑↓⟨⟩⟪⟫·]+$/u;
46460
+ var CURSOR_AGENT_RE = /^(?:Cursor Agent|[\s⬡⬢]*Generating[.\s]|\[Pasted text|Auto-run all|Add a follow-up|ctrl\+c to stop|shift\+tab|Auto$|\/\s*commands|@\s*files|!\s*shell|follow-ups?\s|The user ha)/iu;
46461
+ var SLASH_COMMAND_RE = /^\/\w+\s*$/u;
46462
+ var MCP_JSON_KV_RE = /^\s*"(?:type|method|params|result|id|jsonrpc|tool|name|arguments|content|role|metadata)"\s*:/u;
46463
+ var MEANINGFUL_CONTENT_RE = /[a-zA-Z0-9]/u;
46464
+ function scrubSecrets(text) {
46465
+ let result = text;
46466
+ for (const pattern of SECRET_PATTERNS) {
46467
+ result = result.replace(pattern, "[REDACTED]");
46468
+ }
46469
+ return result;
46470
+ }
46471
+ function scrubForChannel(text) {
46472
+ let withoutSystemReminders = text;
46473
+ const openTag = "<system-reminder>";
46474
+ const closeTag = "</system-reminder>";
46475
+ let idx;
46476
+ while ((idx = withoutSystemReminders.toLowerCase().indexOf(openTag)) !== -1) {
46477
+ const closeIdx = withoutSystemReminders.toLowerCase().indexOf(closeTag, idx + openTag.length);
46478
+ if (closeIdx !== -1) {
46479
+ withoutSystemReminders = withoutSystemReminders.slice(0, idx) + withoutSystemReminders.slice(closeIdx + closeTag.length);
46480
+ } else {
46481
+ withoutSystemReminders = withoutSystemReminders.slice(0, idx);
46482
+ break;
46483
+ }
46484
+ }
46485
+ const normalized = withoutSystemReminders.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
46486
+ const ansiStripped = stripAnsi(normalized);
46487
+ const secretsRedacted = scrubSecrets(ansiStripped);
46488
+ const countJsonDepth = (line) => {
46489
+ let depth = 0;
46490
+ for (const ch of line) {
46491
+ if (ch === "{" || ch === "[")
46492
+ depth += 1;
46493
+ if (ch === "}" || ch === "]")
46494
+ depth -= 1;
46495
+ }
46496
+ return depth;
46497
+ };
46498
+ const lines = secretsRedacted.split("\n");
46499
+ const meaningful = [];
46500
+ let jsonDepth = 0;
46501
+ for (const line of lines) {
46502
+ const trimmed = line.trim();
46503
+ if (jsonDepth > 0) {
46504
+ jsonDepth += countJsonDepth(line);
46505
+ if (jsonDepth <= 0)
46506
+ jsonDepth = 0;
46507
+ continue;
46508
+ }
46509
+ if (trimmed.length === 0)
46510
+ continue;
46511
+ if (trimmed.startsWith("{") || /^\[\s*\{/.test(trimmed)) {
46512
+ jsonDepth = Math.max(countJsonDepth(line), 0);
46513
+ continue;
46514
+ }
46515
+ if (MCP_JSON_KV_RE.test(line))
46516
+ continue;
46517
+ if (SPINNER_CLASS_RE.test(trimmed))
46518
+ continue;
46519
+ if (BOX_DRAWING_ONLY_RE.test(trimmed))
46520
+ continue;
46521
+ if (BROKER_LOG_RE.test(trimmed))
46522
+ continue;
46523
+ if (CLAUDE_HEADER_RE.test(trimmed))
46524
+ continue;
46525
+ if (DIR_BREADCRUMB_RE.test(trimmed))
46526
+ continue;
46527
+ if (UI_HINT_RE.test(trimmed))
46528
+ continue;
46529
+ if (THINKING_LINE_RE.test(trimmed))
46530
+ continue;
46531
+ if (CURSOR_ONLY_RE.test(trimmed))
46532
+ continue;
46533
+ if (CURSOR_AGENT_RE.test(trimmed))
46534
+ continue;
46535
+ if (SLASH_COMMAND_RE.test(trimmed))
46536
+ continue;
46537
+ if (!MEANINGFUL_CONTENT_RE.test(trimmed))
46538
+ continue;
46539
+ const alphanum = trimmed.replace(SPINNER_RE, "").replace(/\s+/g, "");
46540
+ if (alphanum.replace(/[^a-zA-Z0-9]/g, "").length <= 3)
46541
+ continue;
46542
+ meaningful.push(line);
46543
+ }
46544
+ return meaningful.join("\n").replace(/\n{3,}/g, "\n\n").trim();
46545
+ }
46546
+ var ChannelMessenger = class {
46547
+ postFn;
46548
+ constructor(options = {}) {
46549
+ this.postFn = options.postFn;
46550
+ }
46551
+ buildNonInteractiveAwareness(agentMap, stepStates) {
46552
+ const nonInteractive = [...agentMap.values()].filter((agent) => agent.interactive === false);
46553
+ if (nonInteractive.length === 0)
46554
+ return void 0;
46555
+ const agentToSteps = /* @__PURE__ */ new Map();
46556
+ for (const [stepName, state] of stepStates) {
46557
+ const agentName = state.row.agentName;
46558
+ if (!agentName)
46559
+ continue;
46560
+ if (!agentToSteps.has(agentName))
46561
+ agentToSteps.set(agentName, []);
46562
+ agentToSteps.get(agentName).push(stepName);
46563
+ }
46564
+ const lines = nonInteractive.map((agent) => {
46565
+ const stepRefs = (agentToSteps.get(agent.name) ?? []).map((stepName) => `{{steps.${stepName}.output}}`);
46566
+ return `- ${agent.name} (${agent.cli}) \u2014 will return output when complete` + (stepRefs.length > 0 ? `. Access via: ${stepRefs.join(", ")}` : "");
46567
+ });
46568
+ return "\n\n---\nNote: The following agents are non-interactive workers and cannot receive messages:\n" + lines.join("\n") + "\nDo NOT attempt to message these agents. Use the {{steps.<name>.output}} references above to access their results.";
46569
+ }
46570
+ buildRelayRegistrationNote(cli, agentName) {
46571
+ if (cli === "claude")
46572
+ return "";
46573
+ return `---
46574
+ RELAY SETUP \u2014 do this FIRST before any other relay tool:
46575
+ 1. Call: register(name="${agentName}")
46576
+ This authenticates you in the Relaycast workspace.
46577
+ ALL relay tools (mcp__relaycast__message_dm_send, mcp__relaycast__message_inbox_check, mcp__relaycast__message_post, etc.) require
46578
+ registration first \u2014 they will fail with "Not registered" otherwise.
46579
+ 2. Your agent name is "${agentName}" \u2014 use this exact name when registering.`;
46580
+ }
46581
+ buildDelegationGuidance(cli, timeoutMs) {
46582
+ const timeoutNote = timeoutMs ? `You have approximately ${Math.round(timeoutMs / 6e4)} minutes before this step times out. Plan accordingly \u2014 delegate early if the work is substantial.
46583
+
46584
+ ` : "";
46585
+ const subAgentOption = cli === "claude" ? "Option 2 \u2014 Use built-in sub-agents (Task tool) for research or scoped work:\n - Good for exploring code, reading files, or making targeted changes\n - Can run multiple sub-agents in parallel\n\n" : "";
46586
+ return "---\nAUTONOMOUS DELEGATION \u2014 READ THIS BEFORE STARTING:\n" + timeoutNote + 'Before diving in, assess whether this task is too large or complex for a single agent. If it involves multiple independent subtasks, touches many files, or could take a long time, you should break it down and delegate to helper agents to avoid timeouts.\n\nOption 1 \u2014 Spawn relay agents (for real parallel coding work):\n - mcp__relaycast__agent_add(name="helper-1", cli="claude", task="Specific subtask description")\n - Coordinate via mcp__relaycast__message_dm_send(to="helper-1", text="...")\n - Check on them with mcp__relaycast__message_inbox_check()\n - Clean up when done: mcp__relaycast__agent_remove(name="helper-1")\n\n' + subAgentOption + `Guidelines:
46587
+ - You are the lead \u2014 delegate but stay in control, track progress, integrate results
46588
+ - Give each helper a clear, self-contained task with enough context to work independently
46589
+ - For simple or quick work, just do it yourself \u2014 don't over-delegate
46590
+ - Always release spawned relay agents when their work is complete
46591
+ - When spawning non-claude agents (codex, gemini, etc.), prepend to their task:
46592
+ "RELAY SETUP: First call register(name='<exact-agent-name>') before any other relay tool."`;
46593
+ }
46594
+ postCompletionReport(workflowName, outcomes, summary, confidence) {
46595
+ const completed = outcomes.filter((outcome) => outcome.status === "completed");
46596
+ const skipped = outcomes.filter((outcome) => outcome.status === "skipped");
46597
+ const retried = outcomes.filter((outcome) => outcome.attempts > 1);
46598
+ const lines = [
46599
+ `## Workflow **${workflowName}** \u2014 Complete`,
46600
+ "",
46601
+ summary,
46602
+ `Confidence: ${Math.round(confidence * 100)}%`,
46603
+ "",
46604
+ "### Steps",
46605
+ ...completed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) \u2014 passed${outcome.verificationPassed ? " (verified)" : ""}${outcome.attempts > 1 ? ` after ${outcome.attempts} attempts` : ""}`),
46606
+ ...skipped.map((outcome) => `- **${outcome.name}** \u2014 skipped`)
46607
+ ];
46608
+ if (retried.length > 0) {
46609
+ lines.push("", "### Retries");
46610
+ for (const outcome of retried) {
46611
+ lines.push(`- ${outcome.name}: ${outcome.attempts} attempts`);
46612
+ }
46613
+ }
46614
+ this.postFn?.(lines.join("\n"));
46615
+ }
46616
+ postFailureReport(workflowName, outcomes, errorMsg) {
46617
+ const completed = outcomes.filter((outcome) => outcome.status === "completed");
46618
+ const failed = outcomes.filter((outcome) => outcome.status === "failed");
46619
+ const skipped = outcomes.filter((outcome) => outcome.status === "skipped");
46620
+ const lines = [
46621
+ `## Workflow **${workflowName}** \u2014 Failed`,
46622
+ "",
46623
+ `${completed.length}/${outcomes.length} steps passed. Error: ${errorMsg}`,
46624
+ "",
46625
+ "### Steps",
46626
+ ...completed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) \u2014 passed`),
46627
+ ...failed.map((outcome) => `- **${outcome.name}** (${outcome.agent}) \u2014 FAILED: ${outcome.error ?? "unknown"}`),
46628
+ ...skipped.map((outcome) => `- **${outcome.name}** \u2014 skipped`)
46629
+ ];
46630
+ this.postFn?.(lines.join("\n"));
46631
+ }
46632
+ };
46633
+
46285
46634
  // packages/sdk/dist/workflows/memory-db.js
46286
46635
  var InMemoryWorkflowDb = class {
46287
46636
  runs = /* @__PURE__ */ new Map();
@@ -46312,6 +46661,265 @@ var InMemoryWorkflowDb = class {
46312
46661
  }
46313
46662
  };
46314
46663
 
46664
+ // packages/sdk/dist/workflows/process-spawner.js
46665
+ var import_node_child_process5 = require("node:child_process");
46666
+
46667
+ // packages/sdk/dist/workflows/verification.js
46668
+ var import_node_fs9 = require("node:fs");
46669
+ var import_node_path12 = __toESM(require("node:path"), 1);
46670
+ var WorkflowCompletionError = class extends Error {
46671
+ completionReason;
46672
+ constructor(message, completionReason) {
46673
+ super(message);
46674
+ this.name = "WorkflowCompletionError";
46675
+ this.completionReason = completionReason;
46676
+ }
46677
+ };
46678
+ function runVerification(check2, output, stepName, injectedTaskText, options = {}, sideEffects = {}) {
46679
+ const cwd = options.cwd ?? process.cwd();
46680
+ const fail = (message) => {
46681
+ const observedAt2 = (/* @__PURE__ */ new Date()).toISOString();
46682
+ sideEffects.recordStepToolSideEffect?.(stepName, {
46683
+ type: "verification_observed",
46684
+ detail: message,
46685
+ observedAt: observedAt2,
46686
+ raw: { passed: false, type: check2.type, value: check2.value }
46687
+ });
46688
+ sideEffects.getOrCreateStepEvidenceRecord?.(stepName).evidence.coordinationSignals.push({
46689
+ kind: "verification_failed",
46690
+ source: "verification",
46691
+ text: message,
46692
+ observedAt: observedAt2,
46693
+ value: check2.value
46694
+ });
46695
+ if (options.allowFailure) {
46696
+ return {
46697
+ passed: false,
46698
+ completionReason: "failed_verification",
46699
+ error: message
46700
+ };
46701
+ }
46702
+ throw new WorkflowCompletionError(message, "failed_verification");
46703
+ };
46704
+ switch (check2.type) {
46705
+ case "output_contains": {
46706
+ const token = check2.value;
46707
+ if (!checkOutputContains(output, token, injectedTaskText)) {
46708
+ return fail(`Verification failed for "${stepName}": output does not contain "${token}"`);
46709
+ }
46710
+ break;
46711
+ }
46712
+ case "exit_code":
46713
+ if (!checkExitCode(check2.value)) {
46714
+ return fail(`Verification failed for "${stepName}": exit code did not match "${check2.value}"`);
46715
+ }
46716
+ break;
46717
+ case "file_exists":
46718
+ if (!checkFileExists(check2.value, cwd)) {
46719
+ return fail(`Verification failed for "${stepName}": file "${check2.value}" does not exist`);
46720
+ }
46721
+ break;
46722
+ case "custom":
46723
+ return { passed: false };
46724
+ default:
46725
+ break;
46726
+ }
46727
+ if (options.completionMarkerFound === false) {
46728
+ sideEffects.log?.(`[${stepName}] Verification passed without legacy STEP_COMPLETE marker; allowing completion`);
46729
+ }
46730
+ const observedAt = (/* @__PURE__ */ new Date()).toISOString();
46731
+ const successMessage = options.completionMarkerFound === false ? "Verification passed without legacy STEP_COMPLETE marker" : "Verification passed";
46732
+ sideEffects.recordStepToolSideEffect?.(stepName, {
46733
+ type: "verification_observed",
46734
+ detail: successMessage,
46735
+ observedAt,
46736
+ raw: { passed: true, type: check2.type, value: check2.value }
46737
+ });
46738
+ sideEffects.getOrCreateStepEvidenceRecord?.(stepName).evidence.coordinationSignals.push({
46739
+ kind: "verification_passed",
46740
+ source: "verification",
46741
+ text: successMessage,
46742
+ observedAt,
46743
+ value: check2.value
46744
+ });
46745
+ return {
46746
+ passed: true,
46747
+ completionReason: "completed_verified"
46748
+ };
46749
+ }
46750
+ function stripInjectedTaskEcho(output, injectedTaskText) {
46751
+ if (!injectedTaskText) {
46752
+ return output;
46753
+ }
46754
+ const candidates = [
46755
+ injectedTaskText,
46756
+ injectedTaskText.replace(/\r\n/g, "\n"),
46757
+ injectedTaskText.replace(/\n/g, "\r\n")
46758
+ ].filter((candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index);
46759
+ for (const candidate of candidates) {
46760
+ const start = output.indexOf(candidate);
46761
+ if (start !== -1) {
46762
+ return output.slice(0, start) + output.slice(start + candidate.length);
46763
+ }
46764
+ }
46765
+ return output;
46766
+ }
46767
+ function checkExitCode(_expectedExitCode) {
46768
+ return true;
46769
+ }
46770
+ function checkOutputContains(output, token, injectedTaskText) {
46771
+ if (!token) {
46772
+ return false;
46773
+ }
46774
+ return stripInjectedTaskEcho(output, injectedTaskText).includes(token);
46775
+ }
46776
+ function checkFileExists(filePath, cwd = process.cwd()) {
46777
+ const normalizedCwd = import_node_path12.default.resolve(cwd);
46778
+ const resolved = import_node_path12.default.resolve(normalizedCwd, filePath);
46779
+ if (!resolved.startsWith(normalizedCwd + import_node_path12.default.sep) && resolved !== normalizedCwd) {
46780
+ return false;
46781
+ }
46782
+ return (0, import_node_fs9.existsSync)(resolved);
46783
+ }
46784
+
46785
+ // packages/sdk/dist/workflows/process-spawner.js
46786
+ function resolveNonInteractiveCli(cli) {
46787
+ if (cli !== "cursor") {
46788
+ return cli;
46789
+ }
46790
+ const resolved = resolveCliSync("cursor");
46791
+ return resolved?.binary ?? "agent";
46792
+ }
46793
+ function buildCommand(cli, extraArgs = [], task) {
46794
+ if (cli === "api") {
46795
+ throw new Error('cli "api" uses direct API calls, not a subprocess command');
46796
+ }
46797
+ const resolvedCli = resolveNonInteractiveCli(cli);
46798
+ const definition = getCliDefinition(resolvedCli);
46799
+ if (!definition || definition.binaries.length === 0) {
46800
+ throw new Error(`Unknown or non-executable CLI: ${resolvedCli}`);
46801
+ }
46802
+ return [definition.binaries[0], ...definition.nonInteractiveArgs(task, extraArgs)];
46803
+ }
46804
+ function spawnProcess(command, options) {
46805
+ const [bin, ...args] = command;
46806
+ return (0, import_node_child_process5.spawn)(bin, args, options);
46807
+ }
46808
+ function collectOutput(process8) {
46809
+ return new Promise((resolve4, reject) => {
46810
+ let settled = false;
46811
+ const stdout = [];
46812
+ const stderr = [];
46813
+ process8.stdout?.on("data", (chunk) => {
46814
+ stdout.push(chunk.toString());
46815
+ });
46816
+ process8.stderr?.on("data", (chunk) => {
46817
+ stderr.push(chunk.toString());
46818
+ });
46819
+ process8.once("error", (err) => {
46820
+ if (!settled) {
46821
+ settled = true;
46822
+ reject(err);
46823
+ }
46824
+ });
46825
+ process8.once("close", () => {
46826
+ if (!settled) {
46827
+ settled = true;
46828
+ resolve4(`${stdout.join("")}${stderr.join("")}`);
46829
+ }
46830
+ });
46831
+ });
46832
+ }
46833
+ function detectCompletion(output, verification) {
46834
+ if (/OWNER_DECISION:\s*(?:INCOMPLETE_RETRY|INCOMPLETE_FAIL|NEEDS_CLARIFICATION)\b/i.test(output)) {
46835
+ return false;
46836
+ }
46837
+ if (/OWNER_DECISION:\s*COMPLETE\b/i.test(output)) {
46838
+ return true;
46839
+ }
46840
+ if (/\bSTEP_COMPLETE:([A-Za-z0-9_.:-]+)/.test(output)) {
46841
+ return true;
46842
+ }
46843
+ if (!verification) {
46844
+ return false;
46845
+ }
46846
+ return runVerification(verification, output, "process", void 0, { allowFailure: true }).passed;
46847
+ }
46848
+ async function runCommand(command, opts) {
46849
+ const child = spawnProcess([command.bin, ...command.args], {
46850
+ cwd: opts.cwd,
46851
+ env: { ...process.env, ...command.env },
46852
+ stdio: "pipe"
46853
+ });
46854
+ const outputPromise = collectOutput(child);
46855
+ const exitPromise = new Promise((resolve4, reject) => {
46856
+ let timedOut = false;
46857
+ let timer;
46858
+ let killTimer;
46859
+ if (opts.timeoutMs) {
46860
+ timer = setTimeout(() => {
46861
+ timedOut = true;
46862
+ child.kill("SIGTERM");
46863
+ killTimer = setTimeout(() => child.kill("SIGKILL"), 5e3);
46864
+ }, opts.timeoutMs);
46865
+ }
46866
+ const clearTimer = () => {
46867
+ if (timer)
46868
+ clearTimeout(timer);
46869
+ if (killTimer)
46870
+ clearTimeout(killTimer);
46871
+ };
46872
+ child.once("error", (error48) => {
46873
+ clearTimer();
46874
+ reject(error48);
46875
+ });
46876
+ child.once("close", (exitCode, exitSignal) => {
46877
+ clearTimer();
46878
+ if (timedOut) {
46879
+ reject(new Error(`Process timed out after ${opts.timeoutMs ?? "unknown"}ms`));
46880
+ return;
46881
+ }
46882
+ resolve4({
46883
+ exitCode: exitCode ?? void 0,
46884
+ exitSignal: exitSignal ?? void 0
46885
+ });
46886
+ });
46887
+ });
46888
+ const [outputResult, exitResult] = await Promise.allSettled([outputPromise, exitPromise]);
46889
+ const output = outputResult.status === "fulfilled" ? outputResult.value : "";
46890
+ if (exitResult.status === "rejected") {
46891
+ const err = exitResult.reason instanceof Error ? exitResult.reason : new Error(String(exitResult.reason));
46892
+ err.partialOutput = output;
46893
+ throw err;
46894
+ }
46895
+ return {
46896
+ output,
46897
+ exitCode: exitResult.value.exitCode,
46898
+ exitSignal: exitResult.value.exitSignal
46899
+ };
46900
+ }
46901
+ function createProcessSpawner(deps) {
46902
+ const buildAgentCommand = (agent, task) => {
46903
+ const extraArgs = agent.constraints?.model ? ["--model", agent.constraints.model] : [];
46904
+ const [bin, ...args] = buildCommand(agent.cli, extraArgs, task);
46905
+ return { bin, args };
46906
+ };
46907
+ return {
46908
+ async spawnShell(command, opts) {
46909
+ return runCommand({ bin: "sh", args: ["-c", command] }, { ...opts, cwd: opts.cwd ?? deps.cwd });
46910
+ },
46911
+ async spawnAgent(agent, task, opts) {
46912
+ return runCommand(buildAgentCommand(agent, task), { ...opts, cwd: opts.cwd ?? deps.cwd });
46913
+ },
46914
+ async spawnInteractive(agent, task, opts) {
46915
+ return runCommand(buildAgentCommand(agent, task), { ...opts, cwd: opts.cwd ?? deps.cwd });
46916
+ },
46917
+ buildCommand(agent, task) {
46918
+ return buildAgentCommand(agent, task);
46919
+ }
46920
+ };
46921
+ }
46922
+
46315
46923
  // packages/sdk/dist/workflows/run-summary-table.js
46316
46924
  function formatCurrency(value) {
46317
46925
  return typeof value === "number" ? `$${value.toFixed(2)}` : "--";
@@ -46403,11 +47011,528 @@ function formatRunSummaryTable(outcomes, reports) {
46403
47011
  return lines.map((line) => ` ${line}`).join("\n");
46404
47012
  }
46405
47013
 
47014
+ // packages/sdk/dist/workflows/template-resolver.js
47015
+ function shellEscape(value) {
47016
+ return "'" + value.replace(/'/g, "'\\''") + "'";
47017
+ }
47018
+ var TEMPLATE_VARIABLE_PATTERN = /\{\{([\w][\w.\-]*)\}\}/g;
47019
+ var STEP_OUTPUT_TEMPLATE_PATTERN = /\{\{(steps\.[\w\-]+\.output)\}\}/g;
47020
+ var STEP_OUTPUT_REF_PATTERN = /^steps\.([\w\-]+)\.output$/;
47021
+ function resolveVariables(config2, vars) {
47022
+ const resolved = structuredClone(config2);
47023
+ for (const agent of resolved.agents) {
47024
+ if (agent.task) {
47025
+ agent.task = resolveTemplate(agent.task, vars);
47026
+ }
47027
+ }
47028
+ if (resolved.workflows) {
47029
+ for (const workflow2 of resolved.workflows) {
47030
+ for (const step of workflow2.steps) {
47031
+ if (step.task) {
47032
+ step.task = resolveTemplate(step.task, vars);
47033
+ }
47034
+ if (step.command) {
47035
+ step.command = resolveTemplateForShell(step.command, vars);
47036
+ }
47037
+ if (step.params && typeof step.params === "object") {
47038
+ for (const key of Object.keys(step.params)) {
47039
+ const value = step.params[key];
47040
+ if (typeof value === "string") {
47041
+ step.params[key] = resolveTemplate(value, vars);
47042
+ }
47043
+ }
47044
+ }
47045
+ }
47046
+ }
47047
+ }
47048
+ return resolved;
47049
+ }
47050
+ function resolveTemplate(template, context) {
47051
+ return template.replace(TEMPLATE_VARIABLE_PATTERN, (match, key) => {
47052
+ if (key.startsWith("steps.")) {
47053
+ return match;
47054
+ }
47055
+ const value = resolveDotPath(key, context);
47056
+ if (value === void 0) {
47057
+ throw new Error(`Unresolved variable: {{${key}}}`);
47058
+ }
47059
+ return String(value);
47060
+ });
47061
+ }
47062
+ function resolveTemplateForShell(template, context) {
47063
+ return template.replace(TEMPLATE_VARIABLE_PATTERN, (match, key) => {
47064
+ if (key.startsWith("steps.")) {
47065
+ return match;
47066
+ }
47067
+ const value = resolveDotPath(key, context);
47068
+ if (value === void 0) {
47069
+ throw new Error(`Unresolved variable: {{${key}}}`);
47070
+ }
47071
+ return shellEscape(String(value));
47072
+ });
47073
+ }
47074
+ function resolveDotPath(key, context) {
47075
+ if (!key.includes(".")) {
47076
+ return toTemplateScalar(context[key]);
47077
+ }
47078
+ const parts = key.split(".");
47079
+ let current = context;
47080
+ for (const part of parts) {
47081
+ if (current === null || current === void 0 || typeof current !== "object") {
47082
+ return void 0;
47083
+ }
47084
+ current = current[part];
47085
+ }
47086
+ return toTemplateScalar(current);
47087
+ }
47088
+ function resolveStepOutputRef(ref, stepOutputs) {
47089
+ const normalizedRef = ref.startsWith("{{") && ref.endsWith("}}") ? ref.slice(2, -2).trim() : ref;
47090
+ const match = STEP_OUTPUT_REF_PATTERN.exec(normalizedRef);
47091
+ if (!match) {
47092
+ throw new Error(`Invalid step output reference: ${ref}`);
47093
+ }
47094
+ const stepOutput = stepOutputs.get(match[1]);
47095
+ if (stepOutput === void 0) {
47096
+ throw new Error(`Unresolved step output reference: ${ref}`);
47097
+ }
47098
+ return stepOutput;
47099
+ }
47100
+ function interpolateStepTask(template, context) {
47101
+ const stepOutputs = buildStepOutputMap(context);
47102
+ return template.replace(STEP_OUTPUT_TEMPLATE_PATTERN, (match, ref) => {
47103
+ try {
47104
+ return resolveStepOutputRef(ref, stepOutputs);
47105
+ } catch {
47106
+ return match;
47107
+ }
47108
+ });
47109
+ }
47110
+ function buildStepOutputMap(context) {
47111
+ const stepOutputs = /* @__PURE__ */ new Map();
47112
+ const steps = context.steps;
47113
+ if (!steps || typeof steps !== "object") {
47114
+ return stepOutputs;
47115
+ }
47116
+ for (const [stepName, stepState] of Object.entries(steps)) {
47117
+ if (!stepState || typeof stepState !== "object") {
47118
+ continue;
47119
+ }
47120
+ const output = toTemplateScalar(stepState.output);
47121
+ if (output !== void 0) {
47122
+ stepOutputs.set(stepName, String(output));
47123
+ }
47124
+ }
47125
+ return stepOutputs;
47126
+ }
47127
+ function toTemplateScalar(value) {
47128
+ if (value === void 0 || value === null)
47129
+ return void 0;
47130
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
47131
+ return value;
47132
+ }
47133
+ return String(value);
47134
+ }
47135
+ var TemplateResolver = class {
47136
+ resolveVariables(config2, vars) {
47137
+ return resolveVariables(config2, vars);
47138
+ }
47139
+ interpolate(template, vars) {
47140
+ return resolveTemplate(template, vars);
47141
+ }
47142
+ resolveDotPath(key, vars) {
47143
+ return resolveDotPath(key, vars);
47144
+ }
47145
+ interpolateStepTask(template, context) {
47146
+ return interpolateStepTask(template, context);
47147
+ }
47148
+ };
47149
+
47150
+ // packages/sdk/dist/workflows/step-executor.js
47151
+ var StepExecutor = class {
47152
+ deps;
47153
+ templateResolver;
47154
+ channelMessenger;
47155
+ verificationRunner;
47156
+ constructor(deps) {
47157
+ this.deps = deps;
47158
+ this.templateResolver = deps.templateResolver ?? new TemplateResolver();
47159
+ this.channelMessenger = deps.channelMessenger ?? new ChannelMessenger({ postFn: deps.postToChannel });
47160
+ this.verificationRunner = deps.verificationRunner ?? runVerification;
47161
+ }
47162
+ findReady(steps, statuses) {
47163
+ return steps.filter((step) => {
47164
+ const state = statuses.get(step.name);
47165
+ const status = this.getStatus(state);
47166
+ if (status !== "pending")
47167
+ return false;
47168
+ return (step.dependsOn ?? []).every((dependency) => {
47169
+ const depState = statuses.get(dependency);
47170
+ const depStatus = this.getStatus(depState);
47171
+ return depStatus === "completed" || depStatus === "skipped";
47172
+ });
47173
+ });
47174
+ }
47175
+ /** @deprecated Use {@link findReady} instead. This is an alias kept for backward compatibility. */
47176
+ findReadySteps(steps, statuses) {
47177
+ return this.findReady(steps, statuses);
47178
+ }
47179
+ scheduleStep(step, options = {}) {
47180
+ return {
47181
+ step,
47182
+ readyAt: options.readyAt ?? Date.now(),
47183
+ staggerDelay: options.staggerDelay ?? 0
47184
+ };
47185
+ }
47186
+ async startStep(step, state, startMessage) {
47187
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
47188
+ state.row.status = "running";
47189
+ state.row.error = void 0;
47190
+ state.row.completionReason = void 0;
47191
+ state.row.startedAt = startedAt;
47192
+ await this.deps.persistStepRow?.(state.row.id, {
47193
+ status: "running",
47194
+ error: void 0,
47195
+ completionReason: void 0,
47196
+ startedAt,
47197
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
47198
+ });
47199
+ if (startMessage) {
47200
+ this.deps.postToChannel?.(startMessage);
47201
+ }
47202
+ await this.deps.onStepStarted?.(step, state);
47203
+ }
47204
+ async retryStep(step, state, attempt, maxRetries) {
47205
+ state.row.retryCount = attempt;
47206
+ await this.deps.persistStepRow?.(state.row.id, {
47207
+ retryCount: attempt,
47208
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
47209
+ });
47210
+ await this.deps.onStepRetried?.(step, state, attempt, maxRetries);
47211
+ }
47212
+ async completeStep(step, state, result) {
47213
+ const completedAt = (/* @__PURE__ */ new Date()).toISOString();
47214
+ const finalResult = {
47215
+ status: result.status ?? "completed",
47216
+ output: result.output ?? "",
47217
+ exitCode: result.exitCode,
47218
+ exitSignal: result.exitSignal,
47219
+ duration: result.duration ?? 0,
47220
+ retries: result.retries ?? state.row.retryCount,
47221
+ completionReason: result.completionReason,
47222
+ error: result.error
47223
+ };
47224
+ state.row.status = finalResult.status;
47225
+ state.row.output = finalResult.output;
47226
+ state.row.error = finalResult.error;
47227
+ state.row.completionReason = finalResult.completionReason;
47228
+ state.row.completedAt = completedAt;
47229
+ await this.deps.persistStepRow?.(state.row.id, {
47230
+ status: finalResult.status,
47231
+ output: finalResult.output,
47232
+ error: finalResult.error,
47233
+ completionReason: finalResult.completionReason,
47234
+ completedAt,
47235
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
47236
+ });
47237
+ if (finalResult.status === "completed" && this.deps.runId && finalResult.output) {
47238
+ await this.deps.persistStepOutput?.(this.deps.runId, step.name, finalResult.output);
47239
+ }
47240
+ if (finalResult.status === "failed") {
47241
+ await this.deps.onStepFailed?.(step, state, finalResult);
47242
+ } else {
47243
+ await this.deps.onStepCompleted?.(step, state, finalResult);
47244
+ }
47245
+ return finalResult;
47246
+ }
47247
+ async monitorStep(step, state, options) {
47248
+ const maxRetries = options.maxRetries ?? 0;
47249
+ const retryDelayMs = options.retryDelayMs ?? 1e3;
47250
+ let lastError;
47251
+ for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
47252
+ this.deps.checkAborted?.();
47253
+ await this.deps.waitIfPaused?.();
47254
+ if (attempt > 0) {
47255
+ await this.retryStep(step, state, attempt, maxRetries);
47256
+ await options.onRetry?.(attempt, maxRetries, state);
47257
+ if (retryDelayMs > 0) {
47258
+ await delay(retryDelayMs);
47259
+ }
47260
+ }
47261
+ const attemptStartedAt = Date.now();
47262
+ await this.startStep(step, state, options.startMessage);
47263
+ await options.onStart?.(attempt, state);
47264
+ try {
47265
+ const rawResult = await options.execute(attempt, state);
47266
+ const completion = options.toCompletionResult(rawResult, attempt, state);
47267
+ return await this.completeStep(step, state, {
47268
+ ...completion,
47269
+ duration: completion.duration ?? Date.now() - attemptStartedAt,
47270
+ retries: completion.retries ?? attempt
47271
+ });
47272
+ } catch (error48) {
47273
+ lastError = error48;
47274
+ await options.onAttemptFailed?.(error48, attempt, state);
47275
+ }
47276
+ }
47277
+ const failure = options.getFailureResult?.(lastError, maxRetries, state) ?? {
47278
+ status: "failed",
47279
+ output: "",
47280
+ error: lastError instanceof Error ? lastError.message : String(lastError ?? "Unknown error"),
47281
+ retries: maxRetries
47282
+ };
47283
+ return this.completeStep(step, state, {
47284
+ ...failure,
47285
+ status: "failed"
47286
+ });
47287
+ }
47288
+ async executeAll(steps, agentMap, errorHandling, providedStates) {
47289
+ const states = providedStates ?? this.createEphemeralStates(steps);
47290
+ const strategy = normalizeStrategy(errorHandling?.strategy ?? "fail-fast");
47291
+ const results = /* @__PURE__ */ new Map();
47292
+ while (true) {
47293
+ this.deps.checkAborted?.();
47294
+ await this.deps.waitIfPaused?.();
47295
+ const readySteps = this.findReady(steps, states);
47296
+ if (readySteps.length === 0)
47297
+ break;
47298
+ const schedules = readySteps.map((step, index) => this.scheduleStep(step, {
47299
+ readyAt: Date.now(),
47300
+ staggerDelay: readySteps.length > 3 ? index * 2e3 : 0
47301
+ }));
47302
+ if (schedules.length > 1) {
47303
+ await this.deps.onBeginTrack?.(readySteps);
47304
+ }
47305
+ const settled = await Promise.allSettled(schedules.map(async (schedule) => {
47306
+ if (schedule.staggerDelay > 0) {
47307
+ await delay(schedule.staggerDelay);
47308
+ }
47309
+ return this.executeScheduledStep(schedule.step, states, agentMap, errorHandling);
47310
+ }));
47311
+ const batchOutcomes = [];
47312
+ for (let index = 0; index < settled.length; index += 1) {
47313
+ const settledResult = settled[index];
47314
+ const step = readySteps[index];
47315
+ const state = states.get(step.name);
47316
+ if (settledResult.status === "fulfilled") {
47317
+ const result = settledResult.value;
47318
+ const outcomeStatus = result.status === "completed" || result.status === "skipped" ? result.status : "failed";
47319
+ results.set(step.name, result);
47320
+ batchOutcomes.push({
47321
+ name: step.name,
47322
+ agent: step.agent ?? "deterministic",
47323
+ status: outcomeStatus,
47324
+ attempts: result.retries + 1,
47325
+ output: result.output,
47326
+ error: result.error,
47327
+ verificationPassed: outcomeStatus === "completed" && step.verification !== void 0,
47328
+ completionMode: result.completionReason !== void 0 ? this.deps.buildCompletionMode?.(step.name, result.completionReason) : void 0
47329
+ });
47330
+ if (result.status === "failed") {
47331
+ await this.deps.markDownstreamSkipped?.(step.name);
47332
+ if (strategy === "fail-fast") {
47333
+ throw new Error(`Step "${step.name}" failed: ${result.error ?? "unknown error"}`);
47334
+ }
47335
+ }
47336
+ continue;
47337
+ }
47338
+ const error48 = settledResult.reason instanceof Error ? settledResult.reason.message : String(settledResult.reason);
47339
+ if (state) {
47340
+ const failed = state.row.status === "failed" ? {
47341
+ status: "failed",
47342
+ output: state.row.output ?? "",
47343
+ duration: 0,
47344
+ retries: state.row.retryCount,
47345
+ completionReason: state.row.completionReason,
47346
+ error: state.row.error ?? error48
47347
+ } : await this.completeStep(step, state, {
47348
+ status: "failed",
47349
+ output: "",
47350
+ error: error48,
47351
+ retries: state.row.retryCount
47352
+ });
47353
+ results.set(step.name, failed);
47354
+ }
47355
+ batchOutcomes.push({
47356
+ name: step.name,
47357
+ agent: step.agent ?? "deterministic",
47358
+ status: "failed",
47359
+ attempts: (state?.row.retryCount ?? 0) + 1,
47360
+ error: error48
47361
+ });
47362
+ await this.deps.markDownstreamSkipped?.(step.name);
47363
+ if (strategy === "fail-fast") {
47364
+ throw new Error(`Step "${step.name}" failed: ${error48}`);
47365
+ }
47366
+ }
47367
+ if (readySteps.length > 1 && batchOutcomes.length > 0) {
47368
+ await this.deps.onConverge?.(readySteps, batchOutcomes);
47369
+ }
47370
+ }
47371
+ return results;
47372
+ }
47373
+ async executeOne(step, agentMap, errorHandling, providedState) {
47374
+ const state = providedState ?? this.createEphemeralState(step);
47375
+ if (this.deps.executeStep) {
47376
+ const result = await this.deps.executeStep(step, state, agentMap, errorHandling);
47377
+ if (state.row.status !== "pending" && state.row.status !== "running") {
47378
+ return {
47379
+ status: state.row.status,
47380
+ output: state.row.output ?? "",
47381
+ duration: result?.duration ?? 0,
47382
+ retries: result?.retries ?? state.row.retryCount,
47383
+ exitCode: result?.exitCode,
47384
+ exitSignal: result?.exitSignal,
47385
+ completionReason: state.row.completionReason ?? result?.completionReason,
47386
+ error: state.row.error ?? result?.error
47387
+ };
47388
+ }
47389
+ return this.completeStep(step, state, {
47390
+ status: result?.status ?? "completed",
47391
+ output: result?.output ?? "",
47392
+ exitCode: result?.exitCode,
47393
+ exitSignal: result?.exitSignal,
47394
+ completionReason: result?.completionReason,
47395
+ retries: result?.retries ?? state.row.retryCount,
47396
+ duration: result?.duration ?? 0,
47397
+ error: result?.error
47398
+ });
47399
+ }
47400
+ return this.executeWithProcessSpawner(step, state, agentMap, errorHandling);
47401
+ }
47402
+ async markFailed(stepName, error48) {
47403
+ this.deps.postToChannel?.(`**[${stepName}]** Failed: ${error48}`);
47404
+ }
47405
+ buildStepOutputContext(stepStates) {
47406
+ const steps = {};
47407
+ for (const [name, state] of stepStates) {
47408
+ if (state.row.status === "completed" && state.row.output !== void 0) {
47409
+ steps[name] = { output: state.row.output };
47410
+ continue;
47411
+ }
47412
+ if (state.row.status === "completed" && this.deps.runId) {
47413
+ const persisted = this.deps.loadStepOutput?.(this.deps.runId, name);
47414
+ if (persisted !== void 0) {
47415
+ state.row.output = persisted;
47416
+ steps[name] = { output: persisted };
47417
+ }
47418
+ }
47419
+ }
47420
+ return steps;
47421
+ }
47422
+ resolveStepTemplate(template, context) {
47423
+ if (this.deps.resolveTemplate) {
47424
+ return this.deps.resolveTemplate(template, context);
47425
+ }
47426
+ return this.templateResolver.interpolateStepTask(template, context);
47427
+ }
47428
+ getChannelMessenger() {
47429
+ return this.channelMessenger;
47430
+ }
47431
+ runVerification(check2, output, stepName, injectedTaskText, options) {
47432
+ return this.verificationRunner(check2, output, stepName, injectedTaskText, {
47433
+ ...options,
47434
+ cwd: options?.cwd ?? this.deps.cwd
47435
+ });
47436
+ }
47437
+ async executeScheduledStep(step, states, agentMap, errorHandling) {
47438
+ const state = states.get(step.name) ?? this.createEphemeralState(step);
47439
+ if (!states.has(step.name)) {
47440
+ states.set(step.name, state);
47441
+ }
47442
+ return this.executeOne(step, agentMap, errorHandling, state);
47443
+ }
47444
+ async executeWithProcessSpawner(step, state, agentMap, errorHandling) {
47445
+ const spawner = this.deps.processSpawner;
47446
+ if (!spawner) {
47447
+ throw new Error(`No step execution callback or process spawner configured for step "${step.name}"`);
47448
+ }
47449
+ const maxRetries = step.retries ?? errorHandling?.maxRetries ?? 0;
47450
+ return this.monitorStep(step, state, {
47451
+ maxRetries,
47452
+ retryDelayMs: errorHandling?.retryDelayMs ?? 1e3,
47453
+ startMessage: `**[${step.name}]** Started`,
47454
+ onRetry: (attempt, total) => {
47455
+ this.deps.postToChannel?.(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${total + 1})`);
47456
+ },
47457
+ execute: async () => {
47458
+ if (step.type === "deterministic") {
47459
+ const command = step.command ?? "";
47460
+ return spawner.spawnShell(command, { cwd: this.deps.cwd, timeoutMs: step.timeoutMs });
47461
+ }
47462
+ const agent = step.agent ? agentMap.get(step.agent) : void 0;
47463
+ if (!agent) {
47464
+ throw new Error(`Agent "${step.agent ?? "(missing)"}" not found in config`);
47465
+ }
47466
+ const task = step.task ?? "";
47467
+ if (agent.interactive === false) {
47468
+ return spawner.spawnAgent(agent, task, { cwd: this.deps.cwd, timeoutMs: step.timeoutMs });
47469
+ }
47470
+ return spawner.spawnInteractive(agent, task, { cwd: this.deps.cwd, timeoutMs: step.timeoutMs });
47471
+ },
47472
+ toCompletionResult: (spawnResult, attempt) => {
47473
+ const failOnError = step.failOnError !== false;
47474
+ const failed = failOnError && ((spawnResult.exitCode ?? 0) !== 0 || spawnResult.exitCode === void 0 && spawnResult.exitSignal !== void 0);
47475
+ const output = step.captureOutput === false ? `Command completed (exit code ${spawnResult.exitCode ?? 0})` : spawnResult.output;
47476
+ if (failed) {
47477
+ return {
47478
+ status: "failed",
47479
+ output,
47480
+ exitCode: spawnResult.exitCode,
47481
+ exitSignal: spawnResult.exitSignal,
47482
+ retries: attempt,
47483
+ error: spawnResult.output || `Command failed with exit code ${spawnResult.exitCode ?? "unknown"}`
47484
+ };
47485
+ }
47486
+ return {
47487
+ status: "completed",
47488
+ output,
47489
+ exitCode: spawnResult.exitCode,
47490
+ exitSignal: spawnResult.exitSignal,
47491
+ retries: attempt
47492
+ };
47493
+ }
47494
+ });
47495
+ }
47496
+ createEphemeralStates(steps) {
47497
+ return new Map(steps.map((step) => [step.name, this.createEphemeralState(step)]));
47498
+ }
47499
+ createEphemeralState(step) {
47500
+ return {
47501
+ row: {
47502
+ id: `step-${step.name}`,
47503
+ runId: this.deps.runId ?? "run",
47504
+ stepName: step.name,
47505
+ agentName: step.agent ?? null,
47506
+ stepType: step.type ?? "agent",
47507
+ status: "pending",
47508
+ task: step.task ?? step.command ?? step.branch ?? "",
47509
+ dependsOn: step.dependsOn ?? [],
47510
+ retryCount: 0,
47511
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
47512
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString()
47513
+ }
47514
+ };
47515
+ }
47516
+ getStatus(state) {
47517
+ if (typeof state === "string")
47518
+ return state;
47519
+ return state?.row.status;
47520
+ }
47521
+ };
47522
+ function normalizeStrategy(strategy) {
47523
+ if (strategy === "continue")
47524
+ return "continue";
47525
+ return "fail-fast";
47526
+ }
47527
+ function delay(ms) {
47528
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
47529
+ }
47530
+
46406
47531
  // packages/sdk/dist/workflows/trajectory.js
46407
47532
  var import_node_crypto4 = require("node:crypto");
46408
- var import_node_fs9 = require("node:fs");
47533
+ var import_node_fs10 = require("node:fs");
46409
47534
  var import_promises4 = require("node:fs/promises");
46410
- var import_node_path12 = __toESM(require("node:path"), 1);
47535
+ var import_node_path13 = __toESM(require("node:path"), 1);
46411
47536
  function classifyFailure(error48) {
46412
47537
  const e = error48.toLowerCase();
46413
47538
  if (e.includes("timed out") || e.includes("timeout"))
@@ -46459,7 +47584,7 @@ var WorkflowTrajectory = class {
46459
47584
  this.reflectOnConverge = cfg.reflectOnConverge !== false;
46460
47585
  this.autoDecisions = cfg.autoDecisions !== false;
46461
47586
  this.runId = runId;
46462
- this.dataDir = process.env.TRAJECTORIES_DATA_DIR ?? import_node_path12.default.join(cwd, ".trajectories");
47587
+ this.dataDir = process.env.TRAJECTORIES_DATA_DIR ?? import_node_path13.default.join(cwd, ".trajectories");
46463
47588
  }
46464
47589
  // ── Lifecycle ──────────────────────────────────────────────────────────────
46465
47590
  /** Start the trajectory (called at run:started). */
@@ -46868,9 +47993,9 @@ var WorkflowTrajectory = class {
46868
47993
  if (!this.trajectory)
46869
47994
  return;
46870
47995
  try {
46871
- const activeDir = import_node_path12.default.join(this.dataDir, "active");
47996
+ const activeDir = import_node_path13.default.join(this.dataDir, "active");
46872
47997
  await (0, import_promises4.mkdir)(activeDir, { recursive: true });
46873
- const filePath = import_node_path12.default.join(activeDir, `${this.trajectory.id}.json`);
47998
+ const filePath = import_node_path13.default.join(activeDir, `${this.trajectory.id}.json`);
46874
47999
  await (0, import_promises4.writeFile)(filePath, JSON.stringify(this.trajectory, null, 2), "utf-8");
46875
48000
  } catch {
46876
48001
  }
@@ -46879,12 +48004,12 @@ var WorkflowTrajectory = class {
46879
48004
  if (!this.trajectory)
46880
48005
  return;
46881
48006
  try {
46882
- const activeDir = import_node_path12.default.join(this.dataDir, "active");
46883
- const completedDir = import_node_path12.default.join(this.dataDir, "completed");
48007
+ const activeDir = import_node_path13.default.join(this.dataDir, "active");
48008
+ const completedDir = import_node_path13.default.join(this.dataDir, "completed");
46884
48009
  await (0, import_promises4.mkdir)(completedDir, { recursive: true });
46885
- const activePath = import_node_path12.default.join(activeDir, `${this.trajectory.id}.json`);
46886
- const completedPath = import_node_path12.default.join(completedDir, `${this.trajectory.id}.json`);
46887
- if ((0, import_node_fs9.existsSync)(activePath)) {
48010
+ const activePath = import_node_path13.default.join(activeDir, `${this.trajectory.id}.json`);
48011
+ const completedPath = import_node_path13.default.join(completedDir, `${this.trajectory.id}.json`);
48012
+ if ((0, import_node_fs10.existsSync)(activePath)) {
46888
48013
  await (0, import_promises4.rename)(activePath, completedPath);
46889
48014
  }
46890
48015
  } catch {
@@ -46893,6 +48018,53 @@ var WorkflowTrajectory = class {
46893
48018
  };
46894
48019
 
46895
48020
  // packages/sdk/dist/workflows/runner.js
48021
+ var ENV_ALLOWLIST = /* @__PURE__ */ new Set([
48022
+ "PATH",
48023
+ "HOME",
48024
+ "USER",
48025
+ "SHELL",
48026
+ "LANG",
48027
+ "TERM",
48028
+ "TMPDIR",
48029
+ "TZ",
48030
+ "NODE_ENV",
48031
+ "NODE_PATH",
48032
+ "NODE_OPTIONS",
48033
+ "NODE_EXTRA_CA_CERTS",
48034
+ "RUST_LOG",
48035
+ "RUST_BACKTRACE",
48036
+ "RELAY_API_KEY",
48037
+ "RELAYCAST_BASE_URL",
48038
+ "AGENT_RELAY_DASHBOARD_PORT",
48039
+ "AGENT_RELAY_RUN_ID_FILE",
48040
+ "EDITOR",
48041
+ "VISUAL",
48042
+ "GIT_AUTHOR_NAME",
48043
+ "GIT_AUTHOR_EMAIL",
48044
+ "GIT_COMMITTER_NAME",
48045
+ "GIT_COMMITTER_EMAIL",
48046
+ "HTTPS_PROXY",
48047
+ "HTTP_PROXY",
48048
+ "NO_PROXY",
48049
+ "https_proxy",
48050
+ "http_proxy",
48051
+ "no_proxy",
48052
+ "XDG_CONFIG_HOME",
48053
+ "XDG_DATA_HOME",
48054
+ "XDG_CACHE_HOME"
48055
+ ]);
48056
+ function filteredEnv(extra) {
48057
+ const env = {};
48058
+ for (const key of ENV_ALLOWLIST) {
48059
+ if (process.env[key] !== void 0) {
48060
+ env[key] = process.env[key];
48061
+ }
48062
+ }
48063
+ if (extra) {
48064
+ Object.assign(env, extra);
48065
+ }
48066
+ return env;
48067
+ }
46896
48068
  var SpawnExitError = class extends Error {
46897
48069
  exitCode;
46898
48070
  exitSignal;
@@ -46903,14 +48075,6 @@ var SpawnExitError = class extends Error {
46903
48075
  this.exitSignal = exitSignal ?? void 0;
46904
48076
  }
46905
48077
  };
46906
- var WorkflowCompletionError = class extends Error {
46907
- completionReason;
46908
- constructor(message, completionReason) {
46909
- super(message);
46910
- this.name = "WorkflowCompletionError";
46911
- this.completionReason = completionReason;
46912
- }
46913
- };
46914
48078
  function resolveCursorCli() {
46915
48079
  const resolved = resolveCliSync("cursor");
46916
48080
  return resolved?.binary ?? "agent";
@@ -46923,6 +48087,8 @@ var WorkflowRunner = class _WorkflowRunner {
46923
48087
  summaryDir;
46924
48088
  executor;
46925
48089
  envSecrets;
48090
+ templateResolver;
48091
+ channelMessenger;
46926
48092
  /** @internal exposed for CLI signal-handler shutdown only */
46927
48093
  relay;
46928
48094
  relaycast;
@@ -46982,10 +48148,12 @@ var WorkflowRunner = class _WorkflowRunner {
46982
48148
  this.workspaceId = options.workspaceId ?? "local";
46983
48149
  this.relayOptions = options.relay ?? {};
46984
48150
  this.cwd = options.cwd ?? process.cwd();
46985
- this.summaryDir = options.summaryDir ?? import_node_path13.default.join(this.cwd, ".relay", "summaries");
46986
- this.workersPath = import_node_path13.default.join(this.cwd, ".agent-relay", "team", "workers.json");
48151
+ this.summaryDir = options.summaryDir ?? import_node_path14.default.join(this.cwd, ".relay", "summaries");
48152
+ this.workersPath = import_node_path14.default.join(this.cwd, ".agent-relay", "team", "workers.json");
46987
48153
  this.executor = options.executor;
46988
48154
  this.envSecrets = options.envSecrets;
48155
+ this.templateResolver = new TemplateResolver();
48156
+ this.channelMessenger = new ChannelMessenger({ postFn: (text) => this.postToChannel(text) });
46989
48157
  }
46990
48158
  // ── Path resolution ─────────────────────────────────────────────────────
46991
48159
  /** Expand environment variables like $HOME or $VAR in a path string. */
@@ -47013,10 +48181,10 @@ var WorkflowRunner = class _WorkflowRunner {
47013
48181
  }
47014
48182
  seenNames.add(pd.name);
47015
48183
  const expanded = _WorkflowRunner.resolveEnvVars(pd.path);
47016
- const abs = import_node_path13.default.resolve(baseCwd, expanded);
48184
+ const abs = import_node_path14.default.resolve(baseCwd, expanded);
47017
48185
  resolved.set(pd.name, abs);
47018
48186
  const isRequired = pd.required !== false;
47019
- if (!(0, import_node_fs10.existsSync)(abs)) {
48187
+ if (!(0, import_node_fs11.existsSync)(abs)) {
47020
48188
  if (isRequired) {
47021
48189
  errors.push(`Path "${pd.name}" resolves to "${abs}" which does not exist (required)`);
47022
48190
  } else {
@@ -47039,7 +48207,7 @@ var WorkflowRunner = class _WorkflowRunner {
47039
48207
  return resolved;
47040
48208
  }
47041
48209
  if (agent.cwd) {
47042
- return import_node_path13.default.resolve(this.cwd, agent.cwd);
48210
+ return import_node_path14.default.resolve(this.cwd, agent.cwd);
47043
48211
  }
47044
48212
  return this.cwd;
47045
48213
  }
@@ -47058,7 +48226,7 @@ var WorkflowRunner = class _WorkflowRunner {
47058
48226
  }
47059
48227
  resolveEffectiveCwd(step, agentDef) {
47060
48228
  if (step.cwd) {
47061
- return import_node_path13.default.resolve(this.cwd, step.cwd);
48229
+ return import_node_path14.default.resolve(this.cwd, step.cwd);
47062
48230
  }
47063
48231
  return this.resolveStepWorkdir(step) ?? (agentDef ? this.resolveAgentCwd(agentDef) : this.cwd);
47064
48232
  }
@@ -47352,16 +48520,18 @@ ${next}` : next;
47352
48520
  return void 0;
47353
48521
  }
47354
48522
  uniqueEvidenceRoots(roots) {
47355
- return [...new Set(roots.filter((root) => Boolean(root)).map((root) => import_node_path13.default.resolve(root)))];
48523
+ return [
48524
+ ...new Set(roots.filter((root) => Boolean(root)).map((root) => import_node_path14.default.resolve(root)))
48525
+ ];
47356
48526
  }
47357
48527
  captureFileSnapshot(root) {
47358
48528
  const snapshot = /* @__PURE__ */ new Map();
47359
- if (!(0, import_node_fs10.existsSync)(root))
48529
+ if (!(0, import_node_fs11.existsSync)(root))
47360
48530
  return snapshot;
47361
48531
  const visit = (currentPath) => {
47362
48532
  let entries;
47363
48533
  try {
47364
- entries = (0, import_node_fs10.readdirSync)(currentPath, { withFileTypes: true });
48534
+ entries = (0, import_node_fs11.readdirSync)(currentPath, { withFileTypes: true });
47365
48535
  } catch {
47366
48536
  return;
47367
48537
  }
@@ -47369,13 +48539,13 @@ ${next}` : next;
47369
48539
  if (entry.isDirectory() && _WorkflowRunner.EVIDENCE_IGNORED_DIRS.has(entry.name)) {
47370
48540
  continue;
47371
48541
  }
47372
- const fullPath = import_node_path13.default.join(currentPath, entry.name);
48542
+ const fullPath = import_node_path14.default.join(currentPath, entry.name);
47373
48543
  if (entry.isDirectory()) {
47374
48544
  visit(fullPath);
47375
48545
  continue;
47376
48546
  }
47377
48547
  try {
47378
- const stats = (0, import_node_fs10.statSync)(fullPath);
48548
+ const stats = (0, import_node_fs11.statSync)(fullPath);
47379
48549
  if (!stats.isFile())
47380
48550
  continue;
47381
48551
  snapshot.set(fullPath, { mtimeMs: stats.mtimeMs, size: stats.size });
@@ -47384,7 +48554,7 @@ ${next}` : next;
47384
48554
  }
47385
48555
  };
47386
48556
  try {
47387
- const stats = (0, import_node_fs10.statSync)(root);
48557
+ const stats = (0, import_node_fs11.statSync)(root);
47388
48558
  if (stats.isFile()) {
47389
48559
  snapshot.set(root, { mtimeMs: stats.mtimeMs, size: stats.size });
47390
48560
  return snapshot;
@@ -47421,9 +48591,9 @@ ${next}` : next;
47421
48591
  return changes.sort((a, b) => a.path.localeCompare(b.path));
47422
48592
  }
47423
48593
  normalizeEvidencePath(filePath) {
47424
- const relative = import_node_path13.default.relative(this.cwd, filePath);
48594
+ const relative = import_node_path14.default.relative(this.cwd, filePath);
47425
48595
  if (!relative || relative === "")
47426
- return import_node_path13.default.basename(filePath);
48596
+ return import_node_path14.default.basename(filePath);
47427
48597
  return relative.startsWith("..") ? filePath : relative;
47428
48598
  }
47429
48599
  buildStepCompletionDecision(stepName, completionReason) {
@@ -47540,7 +48710,7 @@ ${next}` : next;
47540
48710
  return this.relayOptions.env;
47541
48711
  }
47542
48712
  return {
47543
- ...this.relayOptions.env ?? process.env,
48713
+ ...this.relayOptions.env ?? filteredEnv(),
47544
48714
  RELAY_API_KEY: this.relayApiKey
47545
48715
  };
47546
48716
  }
@@ -47631,7 +48801,7 @@ ${next}` : next;
47631
48801
  // ── Parsing & validation ────────────────────────────────────────────────
47632
48802
  /** Parse a relay.yaml file from disk. */
47633
48803
  async parseYamlFile(filePath) {
47634
- const absPath = import_node_path13.default.resolve(this.cwd, filePath);
48804
+ const absPath = import_node_path14.default.resolve(this.cwd, filePath);
47635
48805
  const raw = await (0, import_promises5.readFile)(absPath, "utf-8");
47636
48806
  return this.parseYamlString(raw, absPath);
47637
48807
  }
@@ -47785,15 +48955,15 @@ ${err.suggestion}`);
47785
48955
  }
47786
48956
  for (const agent of resolved.agents) {
47787
48957
  if (agent.cwd) {
47788
- const resolvedCwd = import_node_path13.default.resolve(this.cwd, agent.cwd);
47789
- if (!(0, import_node_fs10.existsSync)(resolvedCwd)) {
48958
+ const resolvedCwd = import_node_path14.default.resolve(this.cwd, agent.cwd);
48959
+ if (!(0, import_node_fs11.existsSync)(resolvedCwd)) {
47790
48960
  warnings.push(`Agent "${agent.name}" cwd "${agent.cwd}" resolves to "${resolvedCwd}" which does not exist`);
47791
48961
  }
47792
48962
  }
47793
48963
  if (agent.additionalPaths) {
47794
48964
  for (const ap of agent.additionalPaths) {
47795
- const resolvedPath = import_node_path13.default.resolve(this.cwd, ap);
47796
- if (!(0, import_node_fs10.existsSync)(resolvedPath)) {
48965
+ const resolvedPath = import_node_path14.default.resolve(this.cwd, ap);
48966
+ if (!(0, import_node_fs11.existsSync)(resolvedPath)) {
47797
48967
  warnings.push(`Agent "${agent.name}" additionalPath "${ap}" resolves to "${resolvedPath}" which does not exist`);
47798
48968
  }
47799
48969
  }
@@ -48034,65 +49204,13 @@ ${err.suggestion}`);
48034
49204
  // ── Template variable resolution ────────────────────────────────────────
48035
49205
  /** Resolve {{variable}} placeholders in all task strings. */
48036
49206
  resolveVariables(config2, vars) {
48037
- const resolved = structuredClone(config2);
48038
- for (const agent of resolved.agents) {
48039
- if (agent.task) {
48040
- agent.task = this.interpolate(agent.task, vars);
48041
- }
48042
- }
48043
- if (resolved.workflows) {
48044
- for (const wf of resolved.workflows) {
48045
- for (const step of wf.steps) {
48046
- if (step.task) {
48047
- step.task = this.interpolate(step.task, vars);
48048
- }
48049
- if (step.command) {
48050
- step.command = this.interpolate(step.command, vars);
48051
- }
48052
- if (step.params && typeof step.params === "object") {
48053
- for (const key of Object.keys(step.params)) {
48054
- const val = step.params[key];
48055
- if (typeof val === "string") {
48056
- step.params[key] = this.interpolate(val, vars);
48057
- }
48058
- }
48059
- }
48060
- }
48061
- }
48062
- }
48063
- return resolved;
49207
+ return this.templateResolver.resolveVariables(config2, vars);
48064
49208
  }
48065
49209
  interpolate(template, vars) {
48066
- return template.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
48067
- if (key.startsWith("steps.")) {
48068
- return _match;
48069
- }
48070
- const value = this.resolveDotPath(key, vars);
48071
- if (value === void 0) {
48072
- throw new Error(`Unresolved variable: {{${key}}}`);
48073
- }
48074
- return String(value);
48075
- });
49210
+ return resolveTemplate(template, vars);
48076
49211
  }
48077
49212
  resolveDotPath(key, vars) {
48078
- if (!key.includes(".")) {
48079
- return vars[key];
48080
- }
48081
- const parts = key.split(".");
48082
- let current = vars;
48083
- for (const part of parts) {
48084
- if (current === null || current === void 0 || typeof current !== "object") {
48085
- return void 0;
48086
- }
48087
- current = current[part];
48088
- }
48089
- if (current === void 0 || current === null) {
48090
- return void 0;
48091
- }
48092
- if (typeof current === "string" || typeof current === "number" || typeof current === "boolean") {
48093
- return current;
48094
- }
48095
- return String(current);
49213
+ return resolveDotPath(key, vars);
48096
49214
  }
48097
49215
  /** Build a nested context from completed step outputs for {{steps.X.output}} resolution. */
48098
49216
  buildStepOutputContext(stepStates, runId) {
@@ -48112,13 +49230,80 @@ ${err.suggestion}`);
48112
49230
  }
48113
49231
  /** Interpolate step-output variables, silently skipping unresolved ones (they may be user vars). */
48114
49232
  interpolateStepTask(template, context) {
48115
- return template.replace(/\{\{(steps\.[\w\-]+\.output)\}\}/g, (_match, key) => {
48116
- const value = this.resolveDotPath(key, context);
48117
- if (value === void 0) {
48118
- return _match;
48119
- }
48120
- return String(value);
48121
- });
49233
+ return interpolateStepTask(template, context);
49234
+ }
49235
+ createStepLifecycleExecutor(workflow2, stepStates, agentMap, errorHandling, runId) {
49236
+ let lifecycle;
49237
+ const deps = {
49238
+ cwd: this.cwd,
49239
+ runId,
49240
+ templateResolver: this.templateResolver,
49241
+ channelMessenger: this.channelMessenger,
49242
+ verificationRunner: (check2, output, stepName, injectedTaskText, options) => this.runVerification(check2, output, stepName, injectedTaskText, options),
49243
+ postToChannel: (text) => this.postToChannel(text),
49244
+ persistStepRow: async (stepId, patch) => this.db.updateStep(stepId, patch),
49245
+ persistStepOutput: async (lifecycleRunId, stepName, output) => this.persistStepOutput(lifecycleRunId, stepName, output),
49246
+ loadStepOutput: (lifecycleRunId, stepName) => this.loadStepOutput(lifecycleRunId, stepName),
49247
+ checkAborted: () => this.checkAborted(),
49248
+ waitIfPaused: () => this.waitIfPaused(),
49249
+ log: (message) => this.log(message),
49250
+ onStepStarted: async (step) => {
49251
+ this.emit({ type: "step:started", runId, stepName: step.name });
49252
+ },
49253
+ onStepCompleted: async (step, state, result) => {
49254
+ this.emit({
49255
+ type: "step:completed",
49256
+ runId,
49257
+ stepName: step.name,
49258
+ output: result.output,
49259
+ exitCode: result.exitCode,
49260
+ exitSignal: result.exitSignal
49261
+ });
49262
+ this.finalizeStepEvidence(step.name, result.status, state.row.completedAt, result.completionReason);
49263
+ },
49264
+ onStepFailed: async (step, state, result) => {
49265
+ this.captureStepTerminalEvidence(step.name, {}, {
49266
+ exitCode: result.exitCode,
49267
+ exitSignal: result.exitSignal
49268
+ });
49269
+ this.emit({
49270
+ type: "step:failed",
49271
+ runId,
49272
+ stepName: step.name,
49273
+ error: result.error ?? "Unknown error",
49274
+ exitCode: result.exitCode,
49275
+ exitSignal: result.exitSignal
49276
+ });
49277
+ this.finalizeStepEvidence(step.name, "failed", state.row.completedAt, result.completionReason);
49278
+ },
49279
+ executeStep: async (step, state) => {
49280
+ await this.executeStep(step, state, stepStates, agentMap, errorHandling, runId, lifecycle);
49281
+ return {
49282
+ status: state.row.status,
49283
+ output: state.row.output ?? "",
49284
+ completionReason: state.row.completionReason,
49285
+ retries: state.row.retryCount,
49286
+ error: state.row.error
49287
+ };
49288
+ },
49289
+ onBeginTrack: async (steps) => {
49290
+ if (steps.length > 1 && this.trajectory) {
49291
+ await this.trajectory.beginTrack(steps.map((step) => step.name).join(", "));
49292
+ }
49293
+ },
49294
+ onConverge: async (readySteps, batchOutcomes) => {
49295
+ if (readySteps.length <= 1 || !this.trajectory?.shouldReflectOnConverge()) {
49296
+ return;
49297
+ }
49298
+ const completedNames = new Set(batchOutcomes.filter((outcome) => outcome.status === "completed").map((outcome) => outcome.name));
49299
+ const unblocked = workflow2.steps.filter((step) => step.dependsOn?.some((dependency) => completedNames.has(dependency))).filter((step) => stepStates.get(step.name)?.row.status === "pending").map((step) => step.name);
49300
+ await this.trajectory.synthesizeAndReflect(readySteps.map((step) => step.name).join(" + "), batchOutcomes, unblocked.length > 0 ? unblocked : void 0);
49301
+ },
49302
+ markDownstreamSkipped: async (failedStepName) => this.markDownstreamSkipped(failedStepName, workflow2.steps, stepStates, runId),
49303
+ buildCompletionMode: (stepName, completionReason) => completionReason ? this.buildStepCompletionDecision(stepName, completionReason)?.mode : void 0
49304
+ };
49305
+ lifecycle = new StepExecutor(deps);
49306
+ return lifecycle;
48122
49307
  }
48123
49308
  // ── Execution ───────────────────────────────────────────────────────────
48124
49309
  /** Execute a named workflow from a validated config. */
@@ -48324,7 +49509,7 @@ ${err.suggestion}`);
48324
49509
  }
48325
49510
  }
48326
49511
  this.log("Starting broker...");
48327
- const brokerBaseName = import_node_path13.default.basename(this.cwd) || "workflow";
49512
+ const brokerBaseName = import_node_path14.default.basename(this.cwd) || "workflow";
48328
49513
  const brokerName = `${brokerBaseName}-${runId.slice(0, 8)}`;
48329
49514
  this.relay = new AgentRelay({
48330
49515
  ...this.relayOptions,
@@ -48346,7 +49531,7 @@ ${err.suggestion}`);
48346
49531
  if (/Read\(/.test(stripped)) {
48347
49532
  const m = stripped.match(/Read\(\s*~?([^\s)"']{8,})/);
48348
49533
  if (m) {
48349
- const base = import_node_path13.default.basename(m[1]);
49534
+ const base = import_node_path14.default.basename(m[1]);
48350
49535
  activity = base.length >= 3 ? `Reading ${base}` : "Reading file...";
48351
49536
  } else {
48352
49537
  activity = "Reading file...";
@@ -48354,7 +49539,7 @@ ${err.suggestion}`);
48354
49539
  } else if (/Edit\(/.test(stripped)) {
48355
49540
  const m = stripped.match(/Edit\(\s*~?([^\s)"']{8,})/);
48356
49541
  if (m) {
48357
- const base = import_node_path13.default.basename(m[1]);
49542
+ const base = import_node_path14.default.basename(m[1]);
48358
49543
  activity = base.length >= 3 ? `Editing ${base}` : "Editing file...";
48359
49544
  } else {
48360
49545
  activity = "Editing file...";
@@ -48635,72 +49820,11 @@ ${err.suggestion}`);
48635
49820
  async executeSteps(workflow2, stepStates, agentMap, errorHandling, runId) {
48636
49821
  const rawStrategy = errorHandling?.strategy ?? workflow2.onError ?? "fail-fast";
48637
49822
  const strategy = rawStrategy === "fail" ? "fail-fast" : rawStrategy === "skip" ? "continue" : rawStrategy === "retry" ? "fail-fast" : rawStrategy;
48638
- while (true) {
48639
- this.checkAborted();
48640
- await this.waitIfPaused();
48641
- const readySteps = this.findReadySteps(workflow2.steps, stepStates);
48642
- if (readySteps.length === 0) {
48643
- break;
48644
- }
48645
- if (readySteps.length > 1 && this.trajectory) {
48646
- const trackNames = readySteps.map((s) => s.name).join(", ");
48647
- await this.trajectory.beginTrack(trackNames);
48648
- }
48649
- const STAGGER_THRESHOLD = 3;
48650
- const STAGGER_DELAY_MS = 2e3;
48651
- const results = await Promise.allSettled(readySteps.map((step, i) => {
48652
- const delay2 = readySteps.length > STAGGER_THRESHOLD ? i * STAGGER_DELAY_MS : 0;
48653
- if (delay2 === 0) {
48654
- return this.executeStep(step, stepStates, agentMap, errorHandling, runId);
48655
- }
48656
- return new Promise((resolve3) => setTimeout(resolve3, delay2)).then(() => this.executeStep(step, stepStates, agentMap, errorHandling, runId));
48657
- }));
48658
- const batchOutcomes = [];
48659
- for (let i = 0; i < results.length; i++) {
48660
- const result = results[i];
48661
- const step = readySteps[i];
48662
- const state = stepStates.get(step.name);
48663
- if (result.status === "rejected") {
48664
- const error48 = result.reason instanceof Error ? result.reason.message : String(result.reason);
48665
- if (state && state.row.status !== "failed") {
48666
- await this.markStepFailed(state, error48, runId);
48667
- }
48668
- batchOutcomes.push({
48669
- name: step.name,
48670
- agent: step.agent ?? "deterministic",
48671
- status: "failed",
48672
- attempts: (state?.row.retryCount ?? 0) + 1,
48673
- error: error48
48674
- });
48675
- if (strategy === "fail-fast") {
48676
- await this.markDownstreamSkipped(step.name, workflow2.steps, stepStates, runId);
48677
- throw new Error(`Step "${step.name}" failed: ${error48}`);
48678
- }
48679
- if (strategy === "continue") {
48680
- await this.markDownstreamSkipped(step.name, workflow2.steps, stepStates, runId);
48681
- }
48682
- } else {
48683
- batchOutcomes.push({
48684
- name: step.name,
48685
- agent: step.agent ?? "deterministic",
48686
- status: state?.row.status === "completed" ? "completed" : "failed",
48687
- attempts: (state?.row.retryCount ?? 0) + 1,
48688
- output: state?.row.output,
48689
- verificationPassed: state?.row.status === "completed" && step.verification !== void 0,
48690
- completionMode: state?.row.completionReason ? this.buildStepCompletionDecision(step.name, state.row.completionReason)?.mode : void 0
48691
- });
48692
- }
48693
- }
48694
- if (readySteps.length > 1 && this.trajectory?.shouldReflectOnConverge()) {
48695
- const label = readySteps.map((s) => s.name).join(" + ");
48696
- const completedNames = new Set(batchOutcomes.filter((o) => o.status === "completed").map((o) => o.name));
48697
- const unblocked = workflow2.steps.filter((s) => s.dependsOn?.some((dep) => completedNames.has(dep))).filter((s) => {
48698
- const st = stepStates.get(s.name);
48699
- return st && st.row.status === "pending";
48700
- }).map((s) => s.name);
48701
- await this.trajectory.synthesizeAndReflect(label, batchOutcomes, unblocked.length > 0 ? unblocked : void 0);
48702
- }
48703
- }
49823
+ const lifecycle = this.createStepLifecycleExecutor(workflow2, stepStates, agentMap, errorHandling, runId);
49824
+ await lifecycle.executeAll(workflow2.steps, agentMap, {
49825
+ ...errorHandling ?? { strategy: "fail-fast" },
49826
+ strategy
49827
+ }, stepStates);
48704
49828
  }
48705
49829
  findReadySteps(steps, stepStates) {
48706
49830
  return steps.filter((step) => {
@@ -48725,11 +49849,11 @@ ${err.suggestion}`);
48725
49849
  const description = check2.description ?? check2.command.slice(0, 50);
48726
49850
  this.postToChannel(`**[preflight]** ${description}`);
48727
49851
  try {
48728
- const output = await new Promise((resolve3, reject) => {
48729
- const child = (0, import_node_child_process5.spawn)("sh", ["-c", check2.command], {
49852
+ const output = await new Promise((resolve4, reject) => {
49853
+ const child = (0, import_node_child_process6.spawn)("sh", ["-c", check2.command], {
48730
49854
  stdio: "pipe",
48731
49855
  cwd: this.cwd,
48732
- env: { ...process.env }
49856
+ env: filteredEnv()
48733
49857
  });
48734
49858
  const stdoutChunks = [];
48735
49859
  const stderrChunks = [];
@@ -48765,7 +49889,7 @@ ${err.suggestion}`);
48765
49889
  reject(new Error(`Preflight check failed (exit ${code})${stderr ? `: ${stderr.slice(0, 200)}` : ""}`));
48766
49890
  return;
48767
49891
  }
48768
- resolve3(stdoutChunks.join(""));
49892
+ resolve4(stdoutChunks.join(""));
48769
49893
  });
48770
49894
  child.on("error", (err) => {
48771
49895
  clearTimeout(timer);
@@ -48818,15 +49942,15 @@ ${trimmedOutput.slice(0, 200)}`);
48818
49942
  isIntegrationStep(step) {
48819
49943
  return step.type === "integration";
48820
49944
  }
48821
- async executeStep(step, stepStates, agentMap, errorHandling, runId) {
49945
+ async executeStep(step, state, stepStates, agentMap, errorHandling, runId, lifecycle) {
48822
49946
  if (this.isDeterministicStep(step)) {
48823
- return this.executeDeterministicStep(step, stepStates, runId, errorHandling);
49947
+ return this.executeDeterministicStep(step, state, stepStates, runId, errorHandling, lifecycle);
48824
49948
  }
48825
49949
  if (this.isWorktreeStep(step)) {
48826
- return this.executeWorktreeStep(step, stepStates, runId);
49950
+ return this.executeWorktreeStep(step, state, stepStates, runId, lifecycle);
48827
49951
  }
48828
49952
  if (this.isIntegrationStep(step)) {
48829
- return this.executeIntegrationStep(step, stepStates, runId);
49953
+ return this.executeIntegrationStep(step, state, stepStates, runId, lifecycle);
48830
49954
  }
48831
49955
  return this.executeAgentStep(step, stepStates, agentMap, errorHandling, runId);
48832
49956
  }
@@ -48834,92 +49958,213 @@ ${trimmedOutput.slice(0, 200)}`);
48834
49958
  * Execute a deterministic step (shell command).
48835
49959
  * Fast, reliable, $0 LLM cost.
48836
49960
  */
48837
- async executeDeterministicStep(step, stepStates, runId, errorHandling) {
48838
- const state = stepStates.get(step.name);
48839
- if (!state)
48840
- throw new Error(`Step state not found: ${step.name}`);
49961
+ async executeDeterministicStep(step, state, stepStates, runId, errorHandling, lifecycle) {
48841
49962
  const maxRetries = step.retries ?? errorHandling?.maxRetries ?? 0;
48842
49963
  const retryDelay = errorHandling?.retryDelayMs ?? 1e3;
48843
- let lastError;
49964
+ let lastError = "Unknown error";
48844
49965
  let lastCompletionReason;
48845
49966
  let lastExitCode;
48846
49967
  let lastExitSignal;
48847
- for (let attempt = 0; attempt <= maxRetries; attempt += 1) {
48848
- this.checkAborted();
48849
- lastExitCode = void 0;
48850
- lastExitSignal = void 0;
48851
- if (attempt > 0) {
49968
+ const result = await lifecycle.monitorStep(step, state, {
49969
+ maxRetries,
49970
+ retryDelayMs: retryDelay,
49971
+ startMessage: `**[${step.name}]** Started (deterministic)`,
49972
+ onRetry: async (attempt, total) => {
48852
49973
  this.emit({ type: "step:retrying", runId, stepName: step.name, attempt });
48853
- this.postToChannel(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${maxRetries + 1})`);
49974
+ this.postToChannel(`**[${step.name}]** Retrying (attempt ${attempt + 1}/${total + 1})`);
48854
49975
  this.recordStepToolSideEffect(step.name, {
48855
49976
  type: "retry",
48856
- detail: `Retrying attempt ${attempt + 1}/${maxRetries + 1}`,
48857
- raw: { attempt, maxRetries }
49977
+ detail: `Retrying attempt ${attempt + 1}/${total + 1}`,
49978
+ raw: { attempt, maxRetries: total }
48858
49979
  });
48859
- state.row.retryCount = attempt;
48860
- await this.db.updateStep(state.row.id, {
48861
- retryCount: attempt,
48862
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49980
+ },
49981
+ execute: async () => {
49982
+ const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
49983
+ let resolvedCommand = this.interpolateStepTask(step.command ?? "", stepOutputContext);
49984
+ resolvedCommand = resolvedCommand.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
49985
+ if (key.startsWith("steps."))
49986
+ return _match;
49987
+ const value = this.resolveDotPath(key, stepOutputContext);
49988
+ return value !== void 0 ? String(value) : _match;
48863
49989
  });
48864
- await this.delay(retryDelay);
48865
- }
48866
- state.row.status = "running";
48867
- state.row.error = void 0;
48868
- state.row.completionReason = void 0;
48869
- state.row.startedAt = (/* @__PURE__ */ new Date()).toISOString();
48870
- await this.db.updateStep(state.row.id, {
48871
- status: "running",
48872
- error: void 0,
48873
- completionReason: void 0,
48874
- startedAt: state.row.startedAt,
48875
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
48876
- });
48877
- this.emit({ type: "step:started", runId, stepName: step.name });
48878
- this.postToChannel(`**[${step.name}]** Started (deterministic)`);
48879
- const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
48880
- let resolvedCommand = this.interpolateStepTask(step.command ?? "", stepOutputContext);
48881
- resolvedCommand = resolvedCommand.replace(/\{\{([\w][\w.\-]*)\}\}/g, (_match, key) => {
48882
- if (key.startsWith("steps."))
48883
- return _match;
48884
- const value = this.resolveDotPath(key, stepOutputContext);
48885
- return value !== void 0 ? String(value) : _match;
48886
- });
48887
- const stepCwd = this.resolveEffectiveCwd(step);
48888
- this.beginStepEvidence(step.name, [stepCwd], state.row.startedAt);
48889
- try {
49990
+ const stepCwd = this.resolveEffectiveCwd(step);
49991
+ this.beginStepEvidence(step.name, [stepCwd], state.row.startedAt);
48890
49992
  if (this.executor?.executeDeterministicStep) {
48891
- const result = await this.executor.executeDeterministicStep(step, resolvedCommand, stepCwd);
48892
- lastExitCode = result.exitCode;
49993
+ const executorResult = await this.executor.executeDeterministicStep(step, resolvedCommand, stepCwd);
49994
+ lastExitCode = executorResult.exitCode;
49995
+ lastExitSignal = void 0;
48893
49996
  const failOnError = step.failOnError !== false;
48894
- if (failOnError && result.exitCode !== 0) {
48895
- throw new Error(`Command failed with exit code ${result.exitCode}: ${result.output.slice(0, 500)}`);
49997
+ if (failOnError && executorResult.exitCode !== 0) {
49998
+ throw new Error(`Command failed with exit code ${executorResult.exitCode}: ${executorResult.output.slice(0, 500)}`);
48896
49999
  }
48897
- const output2 = step.captureOutput !== false ? result.output : `Command completed (exit code ${result.exitCode})`;
48898
- this.captureStepTerminalEvidence(step.name, { stdout: result.output, combined: result.output }, { exitCode: result.exitCode });
50000
+ const output2 = step.captureOutput !== false ? executorResult.output : `Command completed (exit code ${executorResult.exitCode})`;
50001
+ this.captureStepTerminalEvidence(step.name, { stdout: executorResult.output, combined: executorResult.output }, { exitCode: executorResult.exitCode });
48899
50002
  const verificationResult2 = step.verification ? this.runVerification(step.verification, output2, step.name) : void 0;
48900
- state.row.status = "completed";
48901
- state.row.output = output2;
48902
- state.row.completionReason = verificationResult2?.completionReason;
48903
- state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
48904
- await this.db.updateStep(state.row.id, {
48905
- status: "completed",
50003
+ return {
48906
50004
  output: output2,
48907
- completionReason: verificationResult2?.completionReason,
48908
- completedAt: state.row.completedAt,
48909
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
50005
+ completionReason: verificationResult2?.completionReason
50006
+ };
50007
+ }
50008
+ let commandStdout = "";
50009
+ let commandStderr = "";
50010
+ const output = await new Promise((resolve4, reject) => {
50011
+ const child = (0, import_node_child_process6.spawn)("sh", ["-c", resolvedCommand], {
50012
+ stdio: "pipe",
50013
+ cwd: stepCwd,
50014
+ env: filteredEnv()
48910
50015
  });
48911
- await this.persistStepOutput(runId, step.name, output2);
48912
- this.emit({ type: "step:completed", runId, stepName: step.name, output: output2 });
48913
- this.finalizeStepEvidence(step.name, "completed", state.row.completedAt, verificationResult2?.completionReason);
48914
- return;
50016
+ const stdoutChunks = [];
50017
+ const stderrChunks = [];
50018
+ const abortSignal = this.abortController?.signal;
50019
+ let abortHandler;
50020
+ if (abortSignal && !abortSignal.aborted) {
50021
+ abortHandler = () => {
50022
+ child.kill("SIGTERM");
50023
+ setTimeout(() => child.kill("SIGKILL"), 5e3);
50024
+ };
50025
+ abortSignal.addEventListener("abort", abortHandler, { once: true });
50026
+ }
50027
+ let timedOut = false;
50028
+ let timer;
50029
+ if (step.timeoutMs) {
50030
+ timer = setTimeout(() => {
50031
+ timedOut = true;
50032
+ child.kill("SIGTERM");
50033
+ setTimeout(() => child.kill("SIGKILL"), 5e3);
50034
+ }, step.timeoutMs);
50035
+ }
50036
+ child.stdout?.on("data", (chunk) => {
50037
+ stdoutChunks.push(chunk.toString());
50038
+ });
50039
+ child.stderr?.on("data", (chunk) => {
50040
+ stderrChunks.push(chunk.toString());
50041
+ });
50042
+ child.on("close", (code, signal) => {
50043
+ if (timer)
50044
+ clearTimeout(timer);
50045
+ if (abortHandler && abortSignal) {
50046
+ abortSignal.removeEventListener("abort", abortHandler);
50047
+ }
50048
+ if (abortSignal?.aborted) {
50049
+ reject(new Error(`Step "${step.name}" aborted`));
50050
+ return;
50051
+ }
50052
+ if (timedOut) {
50053
+ reject(new Error(`Step "${step.name}" timed out (no step timeout set, check global swarm.timeoutMs)`));
50054
+ return;
50055
+ }
50056
+ const stdout = stdoutChunks.join("");
50057
+ const stderr = stderrChunks.join("");
50058
+ commandStdout = stdout;
50059
+ commandStderr = stderr;
50060
+ lastExitCode = code ?? void 0;
50061
+ lastExitSignal = signal ?? void 0;
50062
+ const failOnError = step.failOnError !== false;
50063
+ if (failOnError && code !== 0 && code !== null) {
50064
+ reject(new Error(`Command failed with exit code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`));
50065
+ return;
50066
+ }
50067
+ resolve4(step.captureOutput !== false ? stdout : `Command completed (exit code ${code ?? 0})`);
50068
+ });
50069
+ child.on("error", (err) => {
50070
+ if (timer)
50071
+ clearTimeout(timer);
50072
+ if (abortHandler && abortSignal) {
50073
+ abortSignal.removeEventListener("abort", abortHandler);
50074
+ }
50075
+ reject(new Error(`Failed to execute command: ${err.message}`));
50076
+ });
50077
+ });
50078
+ this.captureStepTerminalEvidence(step.name, {
50079
+ stdout: commandStdout || output,
50080
+ stderr: commandStderr,
50081
+ combined: [commandStdout || output, commandStderr].filter(Boolean).join("\n")
50082
+ }, { exitCode: lastExitCode, exitSignal: lastExitSignal });
50083
+ const verificationResult = step.verification ? this.runVerification(step.verification, output, step.name) : void 0;
50084
+ return {
50085
+ output,
50086
+ completionReason: verificationResult?.completionReason
50087
+ };
50088
+ },
50089
+ toCompletionResult: ({ output, completionReason }, attempt) => ({
50090
+ status: "completed",
50091
+ output,
50092
+ completionReason,
50093
+ retries: attempt,
50094
+ exitCode: lastExitCode,
50095
+ exitSignal: lastExitSignal
50096
+ }),
50097
+ onAttemptFailed: async (error48) => {
50098
+ lastError = error48 instanceof Error ? error48.message : String(error48);
50099
+ lastCompletionReason = error48 instanceof WorkflowCompletionError ? error48.completionReason : void 0;
50100
+ },
50101
+ getFailureResult: () => ({
50102
+ status: "failed",
50103
+ output: "",
50104
+ error: lastError,
50105
+ retries: state.row.retryCount,
50106
+ exitCode: lastExitCode,
50107
+ exitSignal: lastExitSignal,
50108
+ completionReason: lastCompletionReason
50109
+ })
50110
+ });
50111
+ if (result.status === "failed") {
50112
+ this.postToChannel(`**[${step.name}]** Failed: ${result.error ?? "Unknown error"}`);
50113
+ throw new Error(`Step "${step.name}" failed: ${result.error ?? "Unknown error"}`);
50114
+ }
50115
+ }
50116
+ /**
50117
+ * Execute a worktree step (git worktree setup).
50118
+ * Fast, reliable, $0 LLM cost.
50119
+ * Outputs the worktree path for downstream steps to use.
50120
+ */
50121
+ async executeWorktreeStep(step, state, stepStates, runId, lifecycle) {
50122
+ let lastExitCode;
50123
+ let lastExitSignal;
50124
+ let worktreeBranch = "";
50125
+ let createdBranch = false;
50126
+ const result = await lifecycle.monitorStep(step, state, {
50127
+ startMessage: `**[${step.name}]** Started (worktree setup)`,
50128
+ execute: async () => {
50129
+ const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
50130
+ const branch = this.interpolateStepTask(step.branch ?? "", stepOutputContext);
50131
+ const baseBranch = step.baseBranch ? this.interpolateStepTask(step.baseBranch, stepOutputContext) : "HEAD";
50132
+ const worktreePath = step.path ? this.interpolateStepTask(step.path, stepOutputContext) : import_node_path14.default.join(".worktrees", step.name);
50133
+ const createBranch = step.createBranch !== false;
50134
+ const stepCwd = this.resolveStepWorkdir(step) ?? this.cwd;
50135
+ this.beginStepEvidence(step.name, [stepCwd], state.row.startedAt);
50136
+ if (!branch) {
50137
+ throw new Error('Worktree step missing required "branch" field');
50138
+ }
50139
+ const absoluteWorktreePath = import_node_path14.default.resolve(stepCwd, worktreePath);
50140
+ let branchExists = false;
50141
+ await new Promise((resolve4) => {
50142
+ const checkChild = (0, import_node_child_process6.spawn)("git", ["rev-parse", "--verify", "--quiet", branch], {
50143
+ stdio: "pipe",
50144
+ cwd: stepCwd,
50145
+ env: filteredEnv()
50146
+ });
50147
+ checkChild.on("close", (code) => {
50148
+ branchExists = code === 0;
50149
+ resolve4();
50150
+ });
50151
+ checkChild.on("error", () => resolve4());
50152
+ });
50153
+ let worktreeArgs;
50154
+ if (branchExists) {
50155
+ worktreeArgs = ["worktree", "add", absoluteWorktreePath, branch];
50156
+ } else if (createBranch) {
50157
+ worktreeArgs = ["worktree", "add", "-b", branch, absoluteWorktreePath, baseBranch];
50158
+ } else {
50159
+ throw new Error(`Branch "${branch}" does not exist and createBranch is false`);
48915
50160
  }
48916
50161
  let commandStdout = "";
48917
50162
  let commandStderr = "";
48918
- const output = await new Promise((resolve3, reject) => {
48919
- const child = (0, import_node_child_process5.spawn)("sh", ["-c", resolvedCommand], {
50163
+ const output = await new Promise((resolve4, reject) => {
50164
+ const child = (0, import_node_child_process6.spawn)("git", worktreeArgs, {
48920
50165
  stdio: "pipe",
48921
50166
  cwd: stepCwd,
48922
- env: { ...process.env }
50167
+ env: filteredEnv()
48923
50168
  });
48924
50169
  const stdoutChunks = [];
48925
50170
  const stderrChunks = [];
@@ -48961,18 +50206,15 @@ ${trimmedOutput.slice(0, 200)}`);
48961
50206
  reject(new Error(`Step "${step.name}" timed out (no step timeout set, check global swarm.timeoutMs)`));
48962
50207
  return;
48963
50208
  }
48964
- const stdout = stdoutChunks.join("");
48965
- const stderr = stderrChunks.join("");
48966
- commandStdout = stdout;
48967
- commandStderr = stderr;
50209
+ commandStdout = stdoutChunks.join("");
50210
+ commandStderr = stderrChunks.join("");
48968
50211
  lastExitCode = code ?? void 0;
48969
50212
  lastExitSignal = signal ?? void 0;
48970
- const failOnError = step.failOnError !== false;
48971
- if (failOnError && code !== 0 && code !== null) {
48972
- reject(new Error(`Command failed with exit code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`));
50213
+ if (code !== 0 && code !== null) {
50214
+ reject(new Error(`git worktree add failed with exit code ${code}${commandStderr ? `: ${commandStderr.slice(0, 500)}` : ""}`));
48973
50215
  return;
48974
50216
  }
48975
- resolve3(step.captureOutput !== false ? stdout : `Command completed (exit code ${code ?? 0})`);
50217
+ resolve4(absoluteWorktreePath);
48976
50218
  });
48977
50219
  child.on("error", (err) => {
48978
50220
  if (timer)
@@ -48980,7 +50222,7 @@ ${trimmedOutput.slice(0, 200)}`);
48980
50222
  if (abortHandler && abortSignal) {
48981
50223
  abortSignal.removeEventListener("abort", abortHandler);
48982
50224
  }
48983
- reject(new Error(`Failed to execute command: ${err.message}`));
50225
+ reject(new Error(`Failed to execute git worktree command: ${err.message}`));
48984
50226
  });
48985
50227
  });
48986
50228
  this.captureStepTerminalEvidence(step.name, {
@@ -48988,253 +50230,78 @@ ${trimmedOutput.slice(0, 200)}`);
48988
50230
  stderr: commandStderr,
48989
50231
  combined: [commandStdout || output, commandStderr].filter(Boolean).join("\n")
48990
50232
  }, { exitCode: lastExitCode, exitSignal: lastExitSignal });
48991
- const verificationResult = step.verification ? this.runVerification(step.verification, output, step.name) : void 0;
48992
- state.row.status = "completed";
48993
- state.row.output = output;
48994
- state.row.completionReason = verificationResult?.completionReason;
48995
- state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
48996
- await this.db.updateStep(state.row.id, {
48997
- status: "completed",
48998
- output,
48999
- completionReason: verificationResult?.completionReason,
49000
- completedAt: state.row.completedAt,
49001
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49002
- });
49003
- await this.persistStepOutput(runId, step.name, output);
49004
- this.emit({ type: "step:completed", runId, stepName: step.name, output });
49005
- this.finalizeStepEvidence(step.name, "completed", state.row.completedAt, verificationResult?.completionReason);
49006
- return;
49007
- } catch (err) {
49008
- lastError = err instanceof Error ? err.message : String(err);
49009
- lastCompletionReason = err instanceof WorkflowCompletionError ? err.completionReason : void 0;
49010
- }
49011
- }
49012
- const errorMsg = lastError ?? "Unknown error";
49013
- this.postToChannel(`**[${step.name}]** Failed: ${errorMsg}`);
49014
- await this.markStepFailed(state, errorMsg, runId, { exitCode: lastExitCode, exitSignal: lastExitSignal }, lastCompletionReason);
49015
- throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
49016
- }
49017
- /**
49018
- * Execute a worktree step (git worktree setup).
49019
- * Fast, reliable, $0 LLM cost.
49020
- * Outputs the worktree path for downstream steps to use.
49021
- */
49022
- async executeWorktreeStep(step, stepStates, runId) {
49023
- const state = stepStates.get(step.name);
49024
- if (!state)
49025
- throw new Error(`Step state not found: ${step.name}`);
49026
- let lastExitCode;
49027
- let lastExitSignal;
49028
- this.checkAborted();
49029
- state.row.status = "running";
49030
- state.row.error = void 0;
49031
- state.row.completionReason = void 0;
49032
- state.row.startedAt = (/* @__PURE__ */ new Date()).toISOString();
49033
- await this.db.updateStep(state.row.id, {
49034
- status: "running",
49035
- error: void 0,
49036
- completionReason: void 0,
49037
- startedAt: state.row.startedAt,
49038
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49039
- });
49040
- this.emit({ type: "step:started", runId, stepName: step.name });
49041
- this.postToChannel(`**[${step.name}]** Started (worktree setup)`);
49042
- const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
49043
- const branch = this.interpolateStepTask(step.branch ?? "", stepOutputContext);
49044
- const baseBranch = step.baseBranch ? this.interpolateStepTask(step.baseBranch, stepOutputContext) : "HEAD";
49045
- const worktreePath = step.path ? this.interpolateStepTask(step.path, stepOutputContext) : import_node_path13.default.join(".worktrees", step.name);
49046
- const createBranch = step.createBranch !== false;
49047
- const stepCwd = this.resolveStepWorkdir(step) ?? this.cwd;
49048
- this.beginStepEvidence(step.name, [stepCwd], state.row.startedAt);
49049
- if (!branch) {
49050
- const errorMsg = 'Worktree step missing required "branch" field';
49051
- await this.markStepFailed(state, errorMsg, runId);
49052
- throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
49053
- }
49054
- try {
49055
- const absoluteWorktreePath = import_node_path13.default.resolve(stepCwd, worktreePath);
49056
- const checkBranchCmd = `git rev-parse --verify --quiet ${branch} 2>/dev/null`;
49057
- let branchExists = false;
49058
- await new Promise((resolve3) => {
49059
- const checkChild = (0, import_node_child_process5.spawn)("sh", ["-c", checkBranchCmd], {
49060
- stdio: "pipe",
49061
- cwd: stepCwd,
49062
- env: { ...process.env }
49063
- });
49064
- checkChild.on("close", (code) => {
49065
- branchExists = code === 0;
49066
- resolve3();
49067
- });
49068
- checkChild.on("error", () => resolve3());
49069
- });
49070
- let worktreeCmd;
49071
- if (branchExists) {
49072
- worktreeCmd = `git worktree add "${absoluteWorktreePath}" ${branch}`;
49073
- } else if (createBranch) {
49074
- worktreeCmd = `git worktree add -b ${branch} "${absoluteWorktreePath}" ${baseBranch}`;
49075
- } else {
49076
- const errorMsg = `Branch "${branch}" does not exist and createBranch is false`;
49077
- await this.markStepFailed(state, errorMsg, runId);
49078
- throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
49079
- }
49080
- let commandStdout = "";
49081
- let commandStderr = "";
49082
- let commandExitCode;
49083
- let commandExitSignal;
49084
- const output = await new Promise((resolve3, reject) => {
49085
- const child = (0, import_node_child_process5.spawn)("sh", ["-c", worktreeCmd], {
49086
- stdio: "pipe",
49087
- cwd: stepCwd,
49088
- env: { ...process.env }
49089
- });
49090
- const stdoutChunks = [];
49091
- const stderrChunks = [];
49092
- const abortSignal = this.abortController?.signal;
49093
- let abortHandler;
49094
- if (abortSignal && !abortSignal.aborted) {
49095
- abortHandler = () => {
49096
- child.kill("SIGTERM");
49097
- setTimeout(() => child.kill("SIGKILL"), 5e3);
49098
- };
49099
- abortSignal.addEventListener("abort", abortHandler, { once: true });
49100
- }
49101
- let timedOut = false;
49102
- let timer;
49103
- if (step.timeoutMs) {
49104
- timer = setTimeout(() => {
49105
- timedOut = true;
49106
- child.kill("SIGTERM");
49107
- setTimeout(() => child.kill("SIGKILL"), 5e3);
49108
- }, step.timeoutMs);
49109
- }
49110
- child.stdout?.on("data", (chunk) => {
49111
- stdoutChunks.push(chunk.toString());
49112
- });
49113
- child.stderr?.on("data", (chunk) => {
49114
- stderrChunks.push(chunk.toString());
49115
- });
49116
- child.on("close", (code, signal) => {
49117
- if (timer)
49118
- clearTimeout(timer);
49119
- if (abortHandler && abortSignal) {
49120
- abortSignal.removeEventListener("abort", abortHandler);
49121
- }
49122
- if (abortSignal?.aborted) {
49123
- reject(new Error(`Step "${step.name}" aborted`));
49124
- return;
49125
- }
49126
- if (timedOut) {
49127
- reject(new Error(`Step "${step.name}" timed out (no step timeout set, check global swarm.timeoutMs)`));
49128
- return;
49129
- }
49130
- commandStdout = stdoutChunks.join("");
49131
- const stderr = stderrChunks.join("");
49132
- commandStderr = stderr;
49133
- commandExitCode = code ?? void 0;
49134
- commandExitSignal = signal ?? void 0;
49135
- lastExitCode = commandExitCode;
49136
- lastExitSignal = commandExitSignal;
49137
- if (code !== 0 && code !== null) {
49138
- reject(new Error(`git worktree add failed with exit code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`));
49139
- return;
49140
- }
49141
- resolve3(absoluteWorktreePath);
49142
- });
49143
- child.on("error", (err) => {
49144
- if (timer)
49145
- clearTimeout(timer);
49146
- if (abortHandler && abortSignal) {
49147
- abortSignal.removeEventListener("abort", abortHandler);
49148
- }
49149
- reject(new Error(`Failed to execute git worktree command: ${err.message}`));
49150
- });
49151
- });
49152
- this.captureStepTerminalEvidence(step.name, {
49153
- stdout: commandStdout || output,
49154
- stderr: commandStderr,
49155
- combined: [commandStdout || output, commandStderr].filter(Boolean).join("\n")
49156
- }, { exitCode: commandExitCode, exitSignal: commandExitSignal });
49157
- state.row.status = "completed";
49158
- state.row.output = output;
49159
- state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
49160
- await this.db.updateStep(state.row.id, {
50233
+ worktreeBranch = branch;
50234
+ createdBranch = !branchExists && createBranch;
50235
+ return { output };
50236
+ },
50237
+ toCompletionResult: ({ output }, attempt) => ({
49161
50238
  status: "completed",
49162
50239
  output,
49163
- completedAt: state.row.completedAt,
49164
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49165
- });
49166
- await this.persistStepOutput(runId, step.name, output);
49167
- this.emit({ type: "step:completed", runId, stepName: step.name, output });
49168
- this.postToChannel(`**[${step.name}]** Worktree created at: ${output}
49169
- Branch: ${branch}${!branchExists && createBranch ? " (created)" : ""}`);
49170
- this.recordStepToolSideEffect(step.name, {
49171
- type: "worktree_created",
49172
- detail: `Worktree created at ${output}`,
49173
- raw: { branch, createdBranch: !branchExists && createBranch }
49174
- });
49175
- this.finalizeStepEvidence(step.name, "completed", state.row.completedAt);
49176
- } catch (err) {
49177
- const errorMsg = err instanceof Error ? err.message : String(err);
49178
- this.postToChannel(`**[${step.name}]** Failed: ${errorMsg}`);
49179
- await this.markStepFailed(state, errorMsg, runId, {
50240
+ retries: attempt,
49180
50241
  exitCode: lastExitCode,
49181
50242
  exitSignal: lastExitSignal
49182
- });
49183
- throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
50243
+ }),
50244
+ getFailureResult: (error48) => ({
50245
+ status: "failed",
50246
+ output: "",
50247
+ error: error48 instanceof Error ? error48.message : String(error48),
50248
+ retries: state.row.retryCount,
50249
+ exitCode: lastExitCode,
50250
+ exitSignal: lastExitSignal
50251
+ })
50252
+ });
50253
+ if (result.status === "failed") {
50254
+ this.postToChannel(`**[${step.name}]** Failed: ${result.error ?? "Unknown error"}`);
50255
+ throw new Error(`Step "${step.name}" failed: ${result.error ?? "Unknown error"}`);
49184
50256
  }
50257
+ this.postToChannel(`**[${step.name}]** Worktree created at: ${result.output}
50258
+ Branch: ${worktreeBranch}${createdBranch ? " (created)" : ""}`);
50259
+ this.recordStepToolSideEffect(step.name, {
50260
+ type: "worktree_created",
50261
+ detail: `Worktree created at ${result.output}`,
50262
+ raw: { branch: worktreeBranch, createdBranch }
50263
+ });
49185
50264
  }
49186
50265
  /**
49187
50266
  * Execute an integration step (external service interaction via executor).
49188
50267
  */
49189
- async executeIntegrationStep(step, stepStates, runId) {
49190
- const state = stepStates.get(step.name);
49191
- if (!state)
49192
- throw new Error(`Step state not found: ${step.name}`);
49193
- this.checkAborted();
49194
- state.row.status = "running";
49195
- state.row.error = void 0;
49196
- state.row.completionReason = void 0;
49197
- state.row.startedAt = (/* @__PURE__ */ new Date()).toISOString();
49198
- await this.db.updateStep(state.row.id, {
49199
- status: "running",
49200
- error: void 0,
49201
- completionReason: void 0,
49202
- startedAt: state.row.startedAt,
49203
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49204
- });
49205
- this.emit({ type: "step:started", runId, stepName: step.name });
49206
- this.postToChannel(`**[${step.name}]** Started (integration: ${step.integration}.${step.action})`);
49207
- const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
49208
- const resolvedParams = {};
49209
- for (const [key, value] of Object.entries(step.params ?? {})) {
49210
- resolvedParams[key] = this.interpolateStepTask(value, stepOutputContext);
49211
- }
49212
- try {
49213
- if (!this.executor?.executeIntegrationStep) {
49214
- throw new Error(`Integration steps require a cloud executor. Step "${step.name}" cannot run locally. Use "cloud run" to execute workflows with integration steps.`);
49215
- }
49216
- const result = await this.executor.executeIntegrationStep(step, resolvedParams, { workspaceId: this.workspaceId });
49217
- if (!result.success) {
49218
- throw new Error(`Integration step "${step.name}" failed: ${result.output}`);
49219
- }
49220
- state.row.status = "completed";
49221
- state.row.output = result.output;
49222
- state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
49223
- await this.db.updateStep(state.row.id, {
50268
+ async executeIntegrationStep(step, state, stepStates, runId, lifecycle) {
50269
+ const result = await lifecycle.monitorStep(step, state, {
50270
+ startMessage: `**[${step.name}]** Started (integration: ${step.integration}.${step.action})`,
50271
+ execute: async () => {
50272
+ const stepOutputContext = this.buildStepOutputContext(stepStates, runId);
50273
+ const resolvedParams = {};
50274
+ for (const [key, value] of Object.entries(step.params ?? {})) {
50275
+ resolvedParams[key] = this.interpolateStepTask(value, stepOutputContext);
50276
+ }
50277
+ if (!this.executor?.executeIntegrationStep) {
50278
+ throw new Error(`Integration steps require a cloud executor. Step "${step.name}" cannot run locally. Use "cloud run" to execute workflows with integration steps.`);
50279
+ }
50280
+ const integrationResult = await this.executor.executeIntegrationStep(step, resolvedParams, {
50281
+ workspaceId: this.workspaceId
50282
+ });
50283
+ if (!integrationResult.success) {
50284
+ throw new Error(`Integration step "${step.name}" failed: ${integrationResult.output}`);
50285
+ }
50286
+ return { output: integrationResult.output };
50287
+ },
50288
+ toCompletionResult: ({ output }, attempt) => ({
49224
50289
  status: "completed",
49225
- output: result.output,
49226
- completedAt: state.row.completedAt,
49227
- updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49228
- });
49229
- await this.persistStepOutput(runId, step.name, result.output);
49230
- this.emit({ type: "step:completed", runId, stepName: step.name, output: result.output });
49231
- this.postToChannel(`**[${step.name}]** Completed (integration: ${step.integration}.${step.action})`);
49232
- } catch (err) {
49233
- const errorMsg = err instanceof Error ? err.message : String(err);
49234
- this.postToChannel(`**[${step.name}]** Failed: ${errorMsg}`);
49235
- await this.markStepFailed(state, errorMsg, runId);
49236
- throw new Error(`Step "${step.name}" failed: ${errorMsg}`);
50290
+ output,
50291
+ retries: attempt
50292
+ }),
50293
+ getFailureResult: (error48) => ({
50294
+ status: "failed",
50295
+ output: "",
50296
+ error: error48 instanceof Error ? error48.message : String(error48),
50297
+ retries: state.row.retryCount
50298
+ })
50299
+ });
50300
+ if (result.status === "failed") {
50301
+ this.postToChannel(`**[${step.name}]** Failed: ${result.error ?? "Unknown error"}`);
50302
+ throw new Error(`Step "${step.name}" failed: ${result.error ?? "Unknown error"}`);
49237
50303
  }
50304
+ this.postToChannel(`**[${step.name}]** Completed (integration: ${step.integration}.${step.action})`);
49238
50305
  }
49239
50306
  /**
49240
50307
  * Execute an agent step (LLM-powered).
@@ -49265,7 +50332,11 @@ ${trimmedOutput.slice(0, 200)}`);
49265
50332
  this.emit({ type: "step:started", runId, stepName: step.name });
49266
50333
  this.postToChannel(`**[${step.name}]** Started (api)`);
49267
50334
  try {
49268
- const output = await executeApiStep(specialistDef.constraints?.model ?? "claude-sonnet-4-20250514", resolvedTask, { envSecrets: this.envSecrets, skills: specialistDef.skills, defaultMaxTokens: specialistDef.constraints?.maxTokens });
50335
+ const output = await executeApiStep(specialistDef.constraints?.model ?? "claude-sonnet-4-20250514", resolvedTask, {
50336
+ envSecrets: this.envSecrets,
50337
+ skills: specialistDef.skills,
50338
+ defaultMaxTokens: specialistDef.constraints?.maxTokens
50339
+ });
49269
50340
  state.row.status = "completed";
49270
50341
  state.row.output = output;
49271
50342
  state.row.completedAt = (/* @__PURE__ */ new Date()).toISOString();
@@ -49514,7 +50585,14 @@ ${resolvedTask}`;
49514
50585
  updatedAt: (/* @__PURE__ */ new Date()).toISOString()
49515
50586
  });
49516
50587
  await this.persistStepOutput(runId, step.name, combinedOutput);
49517
- this.emit({ type: "step:completed", runId, stepName: step.name, output: combinedOutput, exitCode: lastExitCode, exitSignal: lastExitSignal });
50588
+ this.emit({
50589
+ type: "step:completed",
50590
+ runId,
50591
+ stepName: step.name,
50592
+ output: combinedOutput,
50593
+ exitCode: lastExitCode,
50594
+ exitSignal: lastExitSignal
50595
+ });
49518
50596
  this.finalizeStepEvidence(step.name, "completed", state.row.completedAt, completionReason);
49519
50597
  await this.trajectory?.stepCompleted(step, combinedOutput, attempt + 1);
49520
50598
  return;
@@ -49668,8 +50746,8 @@ WORKER COMPLETION CONTRACT:
49668
50746
  let workerReleased = false;
49669
50747
  let resolveWorkerSpawn;
49670
50748
  let rejectWorkerSpawn;
49671
- const workerReady = new Promise((resolve3, reject) => {
49672
- resolveWorkerSpawn = resolve3;
50749
+ const workerReady = new Promise((resolve4, reject) => {
50750
+ resolveWorkerSpawn = resolve4;
49673
50751
  rejectWorkerSpawn = reject;
49674
50752
  });
49675
50753
  const specialistTask = this.buildWorkerHandoffTask(step, resolvedTask, supervised);
@@ -49944,7 +51022,7 @@ WORKER COMPLETION CONTRACT:
49944
51022
  }
49945
51023
  hasOwnerCompletionMarker(step, output, injectedTaskText) {
49946
51024
  const marker = `STEP_COMPLETE:${step.name}`;
49947
- const strippedOutput = this.stripInjectedTaskEcho(output, injectedTaskText);
51025
+ const strippedOutput = stripInjectedTaskEcho(output, injectedTaskText);
49948
51026
  if (strippedOutput.includes(marker)) {
49949
51027
  return true;
49950
51028
  }
@@ -49994,28 +51072,11 @@ WORKER COMPLETION CONTRACT:
49994
51072
  stripEchoedPromptLines(output, patterns) {
49995
51073
  return output.split("\n").map((line) => line.trim()).filter(Boolean).filter((line) => patterns.every((pattern) => !pattern.test(line))).join("\n");
49996
51074
  }
49997
- stripInjectedTaskEcho(output, injectedTaskText) {
49998
- if (!injectedTaskText) {
49999
- return output;
50000
- }
50001
- const candidates = [
50002
- injectedTaskText,
50003
- injectedTaskText.replace(/\r\n/g, "\n"),
50004
- injectedTaskText.replace(/\n/g, "\r\n")
50005
- ].filter((candidate, index, all) => candidate.length > 0 && all.indexOf(candidate) === index);
50006
- for (const candidate of candidates) {
50007
- const start = output.indexOf(candidate);
50008
- if (start !== -1) {
50009
- return output.slice(0, start) + output.slice(start + candidate.length);
50010
- }
50011
- }
50012
- return output;
50013
- }
50014
51075
  outputContainsVerificationToken(output, token, injectedTaskText) {
50015
51076
  if (!token) {
50016
51077
  return false;
50017
51078
  }
50018
- return this.stripInjectedTaskEcho(output, injectedTaskText).includes(token);
51079
+ return stripInjectedTaskEcho(output, injectedTaskText).includes(token);
50019
51080
  }
50020
51081
  prepareInteractiveSpawnTask(agentName, taskText) {
50021
51082
  if (Buffer.byteLength(taskText, "utf8") <= _WorkflowRunner.PTY_TASK_ARG_SIZE_LIMIT) {
@@ -50024,9 +51085,9 @@ WORKER COMPLETION CONTRACT:
50024
51085
  promptTaskText: taskText
50025
51086
  };
50026
51087
  }
50027
- const taskTmpDir = (0, import_node_fs10.mkdtempSync)(import_node_path13.default.join((0, import_node_os7.tmpdir)(), "relay-pty-task-"));
50028
- const taskTmpFile = import_node_path13.default.join(taskTmpDir, `${agentName}-${Date.now()}.txt`);
50029
- (0, import_node_fs10.writeFileSync)(taskTmpFile, taskText, { encoding: "utf8", mode: 384, flag: "wx" });
51088
+ const taskTmpDir = (0, import_node_fs11.mkdtempSync)(import_node_path14.default.join((0, import_node_os7.tmpdir)(), "relay-pty-task-"));
51089
+ const taskTmpFile = import_node_path14.default.join(taskTmpDir, `${agentName}-${Date.now()}.txt`);
51090
+ (0, import_node_fs11.writeFileSync)(taskTmpFile, taskText, { encoding: "utf8", mode: 384, flag: "wx" });
50030
51091
  const promptTaskText = `TASK_FILE:${taskTmpFile}
50031
51092
  Read that file completely before taking any action.
50032
51093
  Treat the file contents as the full workflow task and follow them exactly.
@@ -50362,17 +51423,10 @@ ${review}
50362
51423
  * Delegates to the consolidated CLI registry for per-CLI arg formats.
50363
51424
  */
50364
51425
  static buildNonInteractiveCommand(cli, task, extraArgs = []) {
50365
- if (cli === "api") {
50366
- throw new Error('cli "api" uses direct API calls, not a subprocess command');
50367
- }
50368
- const resolvedCli = cli === "cursor" ? resolveCursorCli() : cli;
50369
- const def = getCliDefinition(resolvedCli);
50370
- if (!def || def.binaries.length === 0) {
50371
- throw new Error(`Unknown or non-executable CLI: ${resolvedCli}`);
50372
- }
51426
+ const [cmd, ...args] = buildCommand(cli, extraArgs, task);
50373
51427
  return {
50374
- cmd: def.binaries[0],
50375
- args: def.nonInteractiveArgs(task, extraArgs)
51428
+ cmd,
51429
+ args
50376
51430
  };
50377
51431
  }
50378
51432
  /**
@@ -50438,8 +51492,8 @@ DO NOT:
50438
51492
  - Output only status messages without the actual deliverable content`;
50439
51493
  const { cmd, args } = _WorkflowRunner.buildNonInteractiveCommand(agentDef.cli, taskWithDeliverable, modelArgs);
50440
51494
  const logsDir = this.getWorkerLogsDir();
50441
- const logPath = import_node_path13.default.join(logsDir, `${agentName}.log`);
50442
- const logStream = (0, import_node_fs10.createWriteStream)(logPath, { flags: "a" });
51495
+ const logPath = import_node_path14.default.join(logsDir, `${agentName}.log`);
51496
+ const logStream = (0, import_node_fs11.createWriteStream)(logPath, { flags: "a" });
50443
51497
  this.registerWorker(agentName, agentDef.cli, step.task ?? "", void 0, false);
50444
51498
  let stopHeartbeat;
50445
51499
  if (this.relayApiKey) {
@@ -50455,11 +51509,11 @@ DO NOT:
50455
51509
  const stdoutChunks = [];
50456
51510
  const stderrChunks = [];
50457
51511
  try {
50458
- const { stdout: output, exitCode, exitSignal } = await new Promise((resolve3, reject) => {
50459
- const child = (0, import_node_child_process5.spawn)(cmd, args, {
51512
+ const { stdout: output, exitCode, exitSignal } = await new Promise((resolve4, reject) => {
51513
+ const child = spawnProcess([cmd, ...args], {
50460
51514
  stdio: ["ignore", "pipe", "pipe"],
50461
51515
  cwd: this.resolveEffectiveCwd(step, agentDef),
50462
- env: this.getRelayEnv() ?? { ...process.env }
51516
+ env: this.getRelayEnv() ?? filteredEnv()
50463
51517
  });
50464
51518
  this.registerWorker(agentName, agentDef.cli, step.task ?? "", child.pid, false);
50465
51519
  const abortSignal = this.abortController?.signal;
@@ -50523,7 +51577,7 @@ DO NOT:
50523
51577
  reject(new SpawnExitError(`Step "${step.name}" exited with code ${code}${stderr ? `: ${stderr.slice(0, 500)}` : ""}`, code, signal));
50524
51578
  return;
50525
51579
  }
50526
- resolve3({
51580
+ resolve4({
50527
51581
  stdout,
50528
51582
  exitCode: code ?? void 0,
50529
51583
  exitSignal: signal ?? void 0
@@ -50577,7 +51631,7 @@ DO NOT:
50577
51631
  const preparedTask = this.prepareInteractiveSpawnTask(agentName, taskWithExit);
50578
51632
  this.ptyOutputBuffers.set(agentName, []);
50579
51633
  const logsDir = this.getWorkerLogsDir();
50580
- const logStream = (0, import_node_fs10.createWriteStream)(import_node_path13.default.join(logsDir, `${agentName}.log`), { flags: "a" });
51634
+ const logStream = (0, import_node_fs11.createWriteStream)(import_node_path14.default.join(logsDir, `${agentName}.log`), { flags: "a" });
50581
51635
  this.ptyLogStreams.set(agentName, logStream);
50582
51636
  this.ptyListeners.set(agentName, (chunk) => {
50583
51637
  const stripped = _WorkflowRunner.stripAnsi(chunk);
@@ -50612,18 +51666,18 @@ DO NOT:
50612
51666
  const oldName = agentName;
50613
51667
  this.ptyOutputBuffers.set(agent.name, this.ptyOutputBuffers.get(oldName) ?? []);
50614
51668
  this.ptyOutputBuffers.delete(oldName);
50615
- const oldLogPath = import_node_path13.default.join(logsDir, `${oldName}.log`);
50616
- const newLogPath = import_node_path13.default.join(logsDir, `${agent.name}.log`);
51669
+ const oldLogPath = import_node_path14.default.join(logsDir, `${oldName}.log`);
51670
+ const newLogPath = import_node_path14.default.join(logsDir, `${agent.name}.log`);
50617
51671
  const oldLogStream = this.ptyLogStreams.get(oldName);
50618
51672
  if (oldLogStream) {
50619
51673
  oldLogStream.end();
50620
51674
  this.ptyLogStreams.delete(oldName);
50621
51675
  try {
50622
- (0, import_node_fs10.renameSync)(oldLogPath, newLogPath);
51676
+ (0, import_node_fs11.renameSync)(oldLogPath, newLogPath);
50623
51677
  } catch {
50624
51678
  }
50625
51679
  }
50626
- const newLogStream = (0, import_node_fs10.createWriteStream)(newLogPath, { flags: "a" });
51680
+ const newLogStream = (0, import_node_fs11.createWriteStream)(newLogPath, { flags: "a" });
50627
51681
  this.ptyLogStreams.set(agent.name, newLogStream);
50628
51682
  const oldListener = this.ptyListeners.get(oldName);
50629
51683
  if (oldListener) {
@@ -50682,12 +51736,12 @@ DO NOT:
50682
51736
  if (verificationResult.passed) {
50683
51737
  this.log(`[${step.name}] Agent timed out but verification passed \u2014 treating as complete`);
50684
51738
  this.postToChannel(`**[${step.name}]** Agent idle after completing work \u2014 verification passed, releasing`);
50685
- await agent.release();
51739
+ await agent.release().catch(() => void 0);
50686
51740
  timeoutRecovered = true;
50687
51741
  }
50688
51742
  }
50689
51743
  if (!timeoutRecovered) {
50690
- await agent.release();
51744
+ await agent.release().catch(() => void 0);
50691
51745
  throw new Error(`Step "${step.name}" timed out after ${timeoutMs ?? "unknown"}ms`);
50692
51746
  }
50693
51747
  }
@@ -50730,8 +51784,8 @@ DO NOT:
50730
51784
  if (ptyChunks.length > 0) {
50731
51785
  output = ptyChunks.join("");
50732
51786
  } else {
50733
- const summaryPath = import_node_path13.default.join(this.summaryDir, `${step.name}.md`);
50734
- output = (0, import_node_fs10.existsSync)(summaryPath) ? await (0, import_promises5.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
51787
+ const summaryPath = import_node_path14.default.join(this.summaryDir, `${step.name}.md`);
51788
+ output = (0, import_node_fs11.existsSync)(summaryPath) ? await (0, import_promises5.readFile)(summaryPath, "utf-8") : exitResult === "timeout" ? "Agent completed (released after idle timeout)" : exitResult === "released" ? "Agent completed (idle \u2014 treated as done)" : `Agent exited (${exitResult})`;
50735
51789
  }
50736
51790
  if (ptyChunks.length === 0) {
50737
51791
  this.captureStepTerminalEvidence(evidenceStepName, { stdout: output, combined: output }, { exitCode: agent?.exitCode, exitSignal: agent?.exitSignal }, {
@@ -50827,13 +51881,13 @@ DO NOT:
50827
51881
  }
50828
51882
  this.log(`[${step.name}] Agent "${agent.name}" still idle after ${idleGraceSecs}s grace \u2014 releasing`);
50829
51883
  this.postToChannel(`**[${step.name}]** Agent \`${agent.name}\` idle \u2014 releasing (verification pending)`);
50830
- await agent.release();
51884
+ await agent.release().catch(() => void 0);
50831
51885
  return "released";
50832
51886
  }
50833
51887
  }
50834
51888
  this.log(`[${step.name}] Agent "${agent.name}" went idle \u2014 treating as complete`);
50835
51889
  this.postToChannel(`**[${step.name}]** Agent \`${agent.name}\` idle \u2014 treating as complete`);
50836
- await agent.release();
51890
+ await agent.release().catch(() => void 0);
50837
51891
  return "released";
50838
51892
  }
50839
51893
  return result.result;
@@ -50877,7 +51931,7 @@ DO NOT:
50877
51931
  }
50878
51932
  this.postToChannel(`**[${step.name}]** Agent \`${agent.name}\` still idle after ${nudgeCount} nudge(s) \u2014 force-releasing`);
50879
51933
  this.emit({ type: "step:force-released", runId: this.currentRunId ?? "", stepName: step.name });
50880
- await agent.release();
51934
+ await agent.release().catch(() => void 0);
50881
51935
  return "force-released";
50882
51936
  }
50883
51937
  }
@@ -50933,70 +51987,11 @@ DO NOT:
50933
51987
  }
50934
51988
  // ── Verification ────────────────────────────────────────────────────────
50935
51989
  runVerification(check2, output, stepName, injectedTaskText, options) {
50936
- const fail = (message) => {
50937
- const observedAt2 = (/* @__PURE__ */ new Date()).toISOString();
50938
- this.recordStepToolSideEffect(stepName, {
50939
- type: "verification_observed",
50940
- detail: message,
50941
- observedAt: observedAt2,
50942
- raw: { passed: false, type: check2.type, value: check2.value }
50943
- });
50944
- this.getOrCreateStepEvidenceRecord(stepName).evidence.coordinationSignals.push({
50945
- kind: "verification_failed",
50946
- source: "verification",
50947
- text: message,
50948
- observedAt: observedAt2,
50949
- value: check2.value
50950
- });
50951
- if (options?.allowFailure) {
50952
- return {
50953
- passed: false,
50954
- completionReason: "failed_verification",
50955
- error: message
50956
- };
50957
- }
50958
- throw new WorkflowCompletionError(message, "failed_verification");
50959
- };
50960
- switch (check2.type) {
50961
- case "output_contains": {
50962
- const token = check2.value;
50963
- if (!this.outputContainsVerificationToken(output, token, injectedTaskText)) {
50964
- return fail(`Verification failed for "${stepName}": output does not contain "${token}"`);
50965
- }
50966
- break;
50967
- }
50968
- case "exit_code":
50969
- break;
50970
- case "file_exists":
50971
- if (!(0, import_node_fs10.existsSync)(import_node_path13.default.resolve(this.cwd, check2.value))) {
50972
- return fail(`Verification failed for "${stepName}": file "${check2.value}" does not exist`);
50973
- }
50974
- break;
50975
- case "custom":
50976
- return { passed: false };
50977
- }
50978
- if (options?.completionMarkerFound === false) {
50979
- this.log(`[${stepName}] Verification passed without legacy STEP_COMPLETE marker; allowing completion`);
50980
- }
50981
- const successMessage = options?.completionMarkerFound === false ? `Verification passed without legacy STEP_COMPLETE marker` : `Verification passed`;
50982
- const observedAt = (/* @__PURE__ */ new Date()).toISOString();
50983
- this.recordStepToolSideEffect(stepName, {
50984
- type: "verification_observed",
50985
- detail: successMessage,
50986
- observedAt,
50987
- raw: { passed: true, type: check2.type, value: check2.value }
51990
+ return runVerification(check2, output, stepName, injectedTaskText, { ...options, cwd: this.cwd }, {
51991
+ recordStepToolSideEffect: (name, effect) => this.recordStepToolSideEffect(name, effect),
51992
+ getOrCreateStepEvidenceRecord: (name) => this.getOrCreateStepEvidenceRecord(name),
51993
+ log: (message) => this.log(message)
50988
51994
  });
50989
- this.getOrCreateStepEvidenceRecord(stepName).evidence.coordinationSignals.push({
50990
- kind: "verification_passed",
50991
- source: "verification",
50992
- text: successMessage,
50993
- observedAt,
50994
- value: check2.value
50995
- });
50996
- return {
50997
- passed: true,
50998
- completionReason: "completed_verified"
50999
- };
51000
51995
  }
51001
51996
  // ── State helpers ─────────────────────────────────────────────────────
51002
51997
  async updateRunStatus(runId, status, error48) {
@@ -51117,12 +52112,12 @@ DO NOT:
51117
52112
  async waitIfPaused() {
51118
52113
  if (!this.paused)
51119
52114
  return;
51120
- await new Promise((resolve3) => {
51121
- this.pauseResolver = resolve3;
52115
+ await new Promise((resolve4) => {
52116
+ this.pauseResolver = resolve4;
51122
52117
  });
51123
52118
  }
51124
52119
  delay(ms) {
51125
- return new Promise((resolve3) => setTimeout(resolve3, ms));
52120
+ return new Promise((resolve4) => setTimeout(resolve4, ms));
51126
52121
  }
51127
52122
  // ── Channel messaging ──────────────────────────────────────────────────
51128
52123
  /**
@@ -51130,24 +52125,7 @@ DO NOT:
51130
52125
  * Returns undefined if there are no non-interactive agents.
51131
52126
  */
51132
52127
  buildNonInteractiveAwareness(agentMap, stepStates) {
51133
- const nonInteractive = [...agentMap.values()].filter((a) => a.interactive === false);
51134
- if (nonInteractive.length === 0)
51135
- return void 0;
51136
- const agentToSteps = /* @__PURE__ */ new Map();
51137
- for (const [stepName, state] of stepStates) {
51138
- const agentName = state.row.agentName;
51139
- if (!agentName)
51140
- continue;
51141
- if (!agentToSteps.has(agentName))
51142
- agentToSteps.set(agentName, []);
51143
- agentToSteps.get(agentName).push(stepName);
51144
- }
51145
- const lines = nonInteractive.map((a) => {
51146
- const steps = agentToSteps.get(a.name) ?? [];
51147
- const stepRefs = steps.map((s) => `{{steps.${s}.output}}`).join(", ");
51148
- return `- ${a.name} (${a.cli}) \u2014 will return output when complete${stepRefs ? `. Access via: ${stepRefs}` : ""}`;
51149
- });
51150
- return "\n\n---\nNote: The following agents are non-interactive workers and cannot receive messages:\n" + lines.join("\n") + "\nDo NOT attempt to message these agents. Use the {{steps.<name>.output}} references above to access their results.";
52128
+ return this.channelMessenger.buildNonInteractiveAwareness(agentMap, stepStates);
51151
52129
  }
51152
52130
  /**
51153
52131
  * Build guidance that encourages agents to autonomously delegate subtasks
@@ -51162,28 +52140,10 @@ DO NOT:
51162
52140
  * key, but they won't call `register` unless explicitly told to.
51163
52141
  */
51164
52142
  buildRelayRegistrationNote(cli, agentName) {
51165
- if (cli === "claude")
51166
- return "";
51167
- return `---
51168
- RELAY SETUP \u2014 do this FIRST before any other relay tool:
51169
- 1. Call: register(name="${agentName}")
51170
- This authenticates you in the Relaycast workspace.
51171
- ALL relay tools (mcp__relaycast__message_dm_send, mcp__relaycast__message_inbox_check, mcp__relaycast__message_post, etc.) require
51172
- registration first \u2014 they will fail with "Not registered" otherwise.
51173
- 2. Your agent name is "${agentName}" \u2014 use this exact name when registering.`;
52143
+ return this.channelMessenger.buildRelayRegistrationNote(cli, agentName);
51174
52144
  }
51175
52145
  buildDelegationGuidance(cli, timeoutMs) {
51176
- const timeoutNote = timeoutMs ? `You have approximately ${Math.round(timeoutMs / 6e4)} minutes before this step times out. Plan accordingly \u2014 delegate early if the work is substantial.
51177
-
51178
- ` : "";
51179
- const subAgentOption = cli === "claude" ? "Option 2 \u2014 Use built-in sub-agents (Task tool) for research or scoped work:\n - Good for exploring code, reading files, or making targeted changes\n - Can run multiple sub-agents in parallel\n\n" : "";
51180
- return "---\nAUTONOMOUS DELEGATION \u2014 READ THIS BEFORE STARTING:\n" + timeoutNote + 'Before diving in, assess whether this task is too large or complex for a single agent. If it involves multiple independent subtasks, touches many files, or could take a long time, you should break it down and delegate to helper agents to avoid timeouts.\n\nOption 1 \u2014 Spawn relay agents (for real parallel coding work):\n - mcp__relaycast__agent_add(name="helper-1", cli="claude", task="Specific subtask description")\n - Coordinate via mcp__relaycast__message_dm_send(to="helper-1", text="...")\n - Check on them with mcp__relaycast__message_inbox_check()\n - Clean up when done: mcp__relaycast__agent_remove(name="helper-1")\n\n' + subAgentOption + `Guidelines:
51181
- - You are the lead \u2014 delegate but stay in control, track progress, integrate results
51182
- - Give each helper a clear, self-contained task with enough context to work independently
51183
- - For simple or quick work, just do it yourself \u2014 don't over-delegate
51184
- - Always release spawned relay agents when their work is complete
51185
- - When spawning non-claude agents (codex, gemini, etc.), prepend to their task:
51186
- "RELAY SETUP: First call register(name='<exact-agent-name>') before any other relay tool."`;
52146
+ return this.channelMessenger.buildDelegationGuidance(cli, timeoutMs);
51187
52147
  }
51188
52148
  /** Post a message to the workflow channel. Fire-and-forget — never throws or blocks. */
51189
52149
  postToChannel(text, options = {}) {
@@ -51208,43 +52168,11 @@ RELAY SETUP \u2014 do this FIRST before any other relay tool:
51208
52168
  }
51209
52169
  /** Post a rich completion report to the channel. */
51210
52170
  postCompletionReport(workflowName, outcomes, summary, confidence) {
51211
- const completed = outcomes.filter((o) => o.status === "completed");
51212
- const skipped = outcomes.filter((o) => o.status === "skipped");
51213
- const retried = outcomes.filter((o) => o.attempts > 1);
51214
- const lines = [
51215
- `## Workflow **${workflowName}** \u2014 Complete`,
51216
- "",
51217
- summary,
51218
- `Confidence: ${Math.round(confidence * 100)}%`,
51219
- "",
51220
- "### Steps",
51221
- ...completed.map((o) => `- **${o.name}** (${o.agent}) \u2014 passed${o.verificationPassed ? " (verified)" : ""}${o.attempts > 1 ? ` after ${o.attempts} attempts` : ""}`),
51222
- ...skipped.map((o) => `- **${o.name}** \u2014 skipped`)
51223
- ];
51224
- if (retried.length > 0) {
51225
- lines.push("", "### Retries");
51226
- for (const o of retried) {
51227
- lines.push(`- ${o.name}: ${o.attempts} attempts`);
51228
- }
51229
- }
51230
- this.postToChannel(lines.join("\n"));
52171
+ this.channelMessenger.postCompletionReport(workflowName, outcomes, summary, confidence);
51231
52172
  }
51232
52173
  /** Post a failure report to the channel. */
51233
52174
  postFailureReport(workflowName, outcomes, errorMsg) {
51234
- const completed = outcomes.filter((o) => o.status === "completed");
51235
- const failed = outcomes.filter((o) => o.status === "failed");
51236
- const skipped = outcomes.filter((o) => o.status === "skipped");
51237
- const lines = [
51238
- `## Workflow **${workflowName}** \u2014 Failed`,
51239
- "",
51240
- `${completed.length}/${outcomes.length} steps passed. Error: ${errorMsg}`,
51241
- "",
51242
- "### Steps",
51243
- ...completed.map((o) => `- **${o.name}** (${o.agent}) \u2014 passed`),
51244
- ...failed.map((o) => `- **${o.name}** (${o.agent}) \u2014 FAILED: ${o.error ?? "unknown"}`),
51245
- ...skipped.map((o) => `- **${o.name}** \u2014 skipped`)
51246
- ];
51247
- this.postToChannel(lines.join("\n"));
52175
+ this.channelMessenger.postFailureReport(workflowName, outcomes, errorMsg);
51248
52176
  }
51249
52177
  /**
51250
52178
  * Log a human-readable run summary to the console after completion or failure.
@@ -51276,7 +52204,7 @@ RELAY SETUP \u2014 do this FIRST before any other relay tool:
51276
52204
  }
51277
52205
  }
51278
52206
  const outputDir = this.getStepOutputDir(runId);
51279
- const logsDir = import_node_path13.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
52207
+ const logsDir = import_node_path14.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
51280
52208
  console.log("");
51281
52209
  console.log(` Run ID: ${runId}`);
51282
52210
  console.log(` Step output: ${outputDir}`);
@@ -51362,8 +52290,8 @@ ${excerpt}` : "";
51362
52290
  if (!target)
51363
52291
  return;
51364
52292
  try {
51365
- (0, import_node_fs10.mkdirSync)(import_node_path13.default.dirname(target), { recursive: true });
51366
- (0, import_node_fs10.writeFileSync)(target, runId + "\n", "utf8");
52293
+ (0, import_node_fs11.mkdirSync)(import_node_path14.default.dirname(target), { recursive: true });
52294
+ (0, import_node_fs11.writeFileSync)(target, runId + "\n", "utf8");
51367
52295
  } catch {
51368
52296
  }
51369
52297
  }
@@ -51387,15 +52315,15 @@ ${excerpt}` : "";
51387
52315
  const withoutSystemReminders = text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/giu, "").replace(/<system-reminder>[\s\S]*/giu, "");
51388
52316
  const normalized = withoutSystemReminders.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
51389
52317
  const ansiStripped = stripAnsi(normalized);
51390
- const SPINNER = "\\u2756\\u2738\\u2739\\u273a\\u273b\\u273c\\u273d\\u2731\\u2732\\u2733\\u2734\\u2735\\u2736\\u2737\\u2743\\u2745\\u2746\\u25d6\\u25d7\\u25d8\\u25d9\\u2022\\u25cf\\u25cb\\u25a0\\u25a1\\u25b6\\u25c0\\u23f5\\u23f6\\u23f7\\u23f8\\u23f9\\u25e2\\u25e3\\u25e4\\u25e5\\u2597\\u2596\\u2598\\u259d\\u2bc8\\u2bc7\\u2bc5\\u2bc6\\u00b7\\u2590\\u258c\\u2588\\u2584\\u2580\\u259a\\u259e\\u2b21\\u2b22";
51391
- const spinnerRe = new RegExp(`[${SPINNER}]`, "gu");
51392
- const spinnerClassRe = new RegExp(`^[\\s${SPINNER}]*$`, "u");
52318
+ const SPINNER2 = "\\u2756\\u2738\\u2739\\u273a\\u273b\\u273c\\u273d\\u2731\\u2732\\u2733\\u2734\\u2735\\u2736\\u2737\\u2743\\u2745\\u2746\\u25d6\\u25d7\\u25d8\\u25d9\\u2022\\u25cf\\u25cb\\u25a0\\u25a1\\u25b6\\u25c0\\u23f5\\u23f6\\u23f7\\u23f8\\u23f9\\u25e2\\u25e3\\u25e4\\u25e5\\u2597\\u2596\\u2598\\u259d\\u2bc8\\u2bc7\\u2bc5\\u2bc6\\u00b7\\u2590\\u258c\\u2588\\u2584\\u2580\\u259a\\u259e\\u2b21\\u2b22";
52319
+ const spinnerRe = new RegExp(`[${SPINNER2}]`, "gu");
52320
+ const spinnerClassRe = new RegExp(`^[\\s${SPINNER2}]*$`, "u");
51393
52321
  const boxDrawingOnlyRe = /^[\s\u2500-\u257f\u2580-\u259f\u25a0-\u25ff\-_=~]{3,}$/u;
51394
52322
  const brokerLogRe = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d+Z\s+(?:INFO|WARN|ERROR|DEBUG)\s/u;
51395
52323
  const claudeHeaderRe = /^(?:[\s\u2580-\u259f✢*·▗▖▘▝]+\s*)?(?:Claude\s+Code(?:\s+v?[\d.]+)?|(?:Sonnet|Haiku|Opus)\s*[\d.]+|claude-(?:sonnet|haiku|opus)-[\w.-]+|Running\s+on\s+claude)/iu;
51396
52324
  const dirBreadcrumbRe = /^\s*~[\\/]/u;
51397
52325
  const uiHintRe = /\b(?:Press\s+up\s+to\s+edit|tab\s+to\s+queue|bypass\s+permissions|esc\s+to\s+interrupt)\b/iu;
51398
- const thinkingLineRe = new RegExp(`^[\\s${SPINNER}]*\\s*\\w[\\w\\s]*\\u2026\\s*$`, "u");
52326
+ const thinkingLineRe = new RegExp(`^[\\s${SPINNER2}]*\\s*\\w[\\w\\s]*\\u2026\\s*$`, "u");
51399
52327
  const cursorOnlyRe = /^[\s❯⎿›»◀▶←→↑↓⟨⟩⟪⟫·]+$/u;
51400
52328
  const cursorAgentRe = /^(?:Cursor Agent|[\s⬡⬢]*Generating[.\s]|\[Pasted text|Auto-run all|Add a follow-up|ctrl\+c to stop|shift\+tab|Auto$|\/\s*commands|@\s*files|!\s*shell|follow-ups?\s|The user ha)/iu;
51401
52329
  const slashCommandRe = /^\/\w+\s*$/u;
@@ -51472,14 +52400,14 @@ ${excerpt}` : "";
51472
52400
  /** Directory for persisted step outputs: .agent-relay/step-outputs/{runId}/ */
51473
52401
  getStepOutputDir(runId) {
51474
52402
  this.validateRunId(runId);
51475
- return import_node_path13.default.join(this.cwd, ".agent-relay", "step-outputs", runId);
52403
+ return import_node_path14.default.join(this.cwd, ".agent-relay", "step-outputs", runId);
51476
52404
  }
51477
52405
  /** Persist step output to disk and post full output as a channel message. */
51478
52406
  async persistStepOutput(runId, stepName, output) {
51479
- const outputPath = import_node_path13.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
52407
+ const outputPath = import_node_path14.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
51480
52408
  try {
51481
52409
  const dir = this.getStepOutputDir(runId);
51482
- (0, import_node_fs10.mkdirSync)(dir, { recursive: true });
52410
+ (0, import_node_fs11.mkdirSync)(dir, { recursive: true });
51483
52411
  const cleaned = _WorkflowRunner.stripAnsi(output);
51484
52412
  await (0, import_promises5.writeFile)(outputPath, cleaned);
51485
52413
  } catch {
@@ -51502,9 +52430,9 @@ ${preview}
51502
52430
  \`\`\``, { stepName });
51503
52431
  }
51504
52432
  async persistAgentReport(runId, stepName, report) {
51505
- const reportPath = import_node_path13.default.join(this.getStepOutputDir(runId), `${stepName}.report.json`);
52433
+ const reportPath = import_node_path14.default.join(this.getStepOutputDir(runId), `${stepName}.report.json`);
51506
52434
  try {
51507
- (0, import_node_fs10.mkdirSync)(this.getStepOutputDir(runId), { recursive: true });
52435
+ (0, import_node_fs11.mkdirSync)(this.getStepOutputDir(runId), { recursive: true });
51508
52436
  await (0, import_promises5.writeFile)(reportPath, JSON.stringify(report, null, 2), "utf8");
51509
52437
  } catch {
51510
52438
  }
@@ -51512,18 +52440,18 @@ ${preview}
51512
52440
  /** Scan .agent-relay/step-outputs/ for the most recent run directory containing the needed steps. */
51513
52441
  findMostRecentRunWithSteps(stepNames) {
51514
52442
  try {
51515
- const baseDir = import_node_path13.default.join(this.cwd, ".agent-relay", "step-outputs");
51516
- if (!(0, import_node_fs10.existsSync)(baseDir))
52443
+ const baseDir = import_node_path14.default.join(this.cwd, ".agent-relay", "step-outputs");
52444
+ if (!(0, import_node_fs11.existsSync)(baseDir))
51517
52445
  return void 0;
51518
- const entries = (0, import_node_fs10.readdirSync)(baseDir);
52446
+ const entries = (0, import_node_fs11.readdirSync)(baseDir);
51519
52447
  let best;
51520
52448
  for (const entry of entries) {
51521
- const dirPath = import_node_path13.default.join(baseDir, entry);
52449
+ const dirPath = import_node_path14.default.join(baseDir, entry);
51522
52450
  try {
51523
- const stat2 = (0, import_node_fs10.statSync)(dirPath);
52451
+ const stat2 = (0, import_node_fs11.statSync)(dirPath);
51524
52452
  if (!stat2.isDirectory())
51525
52453
  continue;
51526
- const hasAny = [...stepNames].some((name) => (0, import_node_fs10.existsSync)(import_node_path13.default.join(dirPath, `${name}.md`)));
52454
+ const hasAny = [...stepNames].some((name) => (0, import_node_fs11.existsSync)(import_node_path14.default.join(dirPath, `${name}.md`)));
51527
52455
  if (!hasAny)
51528
52456
  continue;
51529
52457
  if (!best || stat2.mtimeMs > best.mtime) {
@@ -51541,10 +52469,10 @@ ${preview}
51541
52469
  /** Load persisted step output from disk. */
51542
52470
  loadStepOutput(runId, stepName) {
51543
52471
  try {
51544
- const filePath = import_node_path13.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
51545
- if (!(0, import_node_fs10.existsSync)(filePath))
52472
+ const filePath = import_node_path14.default.join(this.getStepOutputDir(runId), `${stepName}.md`);
52473
+ if (!(0, import_node_fs11.existsSync)(filePath))
51546
52474
  return void 0;
51547
- return (0, import_node_fs10.readFileSync)(filePath, "utf-8");
52475
+ return (0, import_node_fs11.readFileSync)(filePath, "utf-8");
51548
52476
  } catch {
51549
52477
  return void 0;
51550
52478
  }
@@ -51566,14 +52494,14 @@ ${preview}
51566
52494
  }
51567
52495
  reconstructRunFromCache(runId, config2) {
51568
52496
  const stepOutputDir = this.getStepOutputDir(runId);
51569
- if (!(0, import_node_fs10.existsSync)(stepOutputDir))
52497
+ if (!(0, import_node_fs11.existsSync)(stepOutputDir))
51570
52498
  return null;
51571
52499
  let resumeConfig = config2 ?? this.currentConfig;
51572
52500
  if (!resumeConfig) {
51573
- const yamlPath = import_node_path13.default.join(this.cwd, "relay.yaml");
51574
- if ((0, import_node_fs10.existsSync)(yamlPath)) {
52501
+ const yamlPath = import_node_path14.default.join(this.cwd, "relay.yaml");
52502
+ if ((0, import_node_fs11.existsSync)(yamlPath)) {
51575
52503
  try {
51576
- const raw = (0, import_node_fs10.readFileSync)(yamlPath, "utf-8");
52504
+ const raw = (0, import_node_fs11.readFileSync)(yamlPath, "utf-8");
51577
52505
  resumeConfig = this.parseYamlString(raw, yamlPath);
51578
52506
  } catch {
51579
52507
  return null;
@@ -51584,7 +52512,7 @@ ${preview}
51584
52512
  }
51585
52513
  let entries;
51586
52514
  try {
51587
- entries = (0, import_node_fs10.readdirSync)(stepOutputDir, { withFileTypes: true });
52515
+ entries = (0, import_node_fs11.readdirSync)(stepOutputDir, { withFileTypes: true });
51588
52516
  } catch {
51589
52517
  return null;
51590
52518
  }
@@ -51599,10 +52527,10 @@ ${preview}
51599
52527
  let earliestMtime = Date.now();
51600
52528
  for (const stepName of cachedStepNames) {
51601
52529
  try {
51602
- const mdPath = import_node_path13.default.join(stepOutputDir, `${stepName}.md`);
51603
- const reportPath = import_node_path13.default.join(stepOutputDir, `${stepName}.report.json`);
51604
- const mdStat = (0, import_node_fs10.existsSync)(mdPath) ? (0, import_node_fs10.statSync)(mdPath) : null;
51605
- const reportStat = (0, import_node_fs10.existsSync)(reportPath) ? (0, import_node_fs10.statSync)(reportPath) : null;
52530
+ const mdPath = import_node_path14.default.join(stepOutputDir, `${stepName}.md`);
52531
+ const reportPath = import_node_path14.default.join(stepOutputDir, `${stepName}.report.json`);
52532
+ const mdStat = (0, import_node_fs11.existsSync)(mdPath) ? (0, import_node_fs11.statSync)(mdPath) : null;
52533
+ const reportStat = (0, import_node_fs11.existsSync)(reportPath) ? (0, import_node_fs11.statSync)(reportPath) : null;
51606
52534
  const mtime = Math.max(mdStat?.mtimeMs ?? 0, reportStat?.mtimeMs ?? 0);
51607
52535
  if (mtime > 0) {
51608
52536
  stepMtimes.set(stepName, new Date(mtime).toISOString());
@@ -51654,8 +52582,8 @@ ${preview}
51654
52582
  }
51655
52583
  /** Get or create the worker logs directory (.agent-relay/team/worker-logs) */
51656
52584
  getWorkerLogsDir() {
51657
- const logsDir = import_node_path13.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
51658
- (0, import_node_fs10.mkdirSync)(logsDir, { recursive: true });
52585
+ const logsDir = import_node_path14.default.join(this.cwd, ".agent-relay", "team", "worker-logs");
52586
+ (0, import_node_fs11.mkdirSync)(logsDir, { recursive: true });
51659
52587
  return logsDir;
51660
52588
  }
51661
52589
  /** Register a spawned agent in workers.json so `agents:kill` can find it. */
@@ -51666,12 +52594,12 @@ ${preview}
51666
52594
  spawnedAt: Date.now(),
51667
52595
  pid,
51668
52596
  interactive,
51669
- logFile: import_node_path13.default.join(this.getWorkerLogsDir(), `${agentName}.log`)
52597
+ logFile: import_node_path14.default.join(this.getWorkerLogsDir(), `${agentName}.log`)
51670
52598
  };
51671
52599
  this.activeWorkers.set(agentName, workerEntry);
51672
52600
  this.workersFileLock = this.workersFileLock.then(() => {
51673
52601
  try {
51674
- (0, import_node_fs10.mkdirSync)(import_node_path13.default.dirname(this.workersPath), { recursive: true });
52602
+ (0, import_node_fs11.mkdirSync)(import_node_path14.default.dirname(this.workersPath), { recursive: true });
51675
52603
  const existing = this.readWorkers().filter((w) => w.name !== agentName);
51676
52604
  existing.push({ name: agentName, ...workerEntry });
51677
52605
  this.writeWorkers(existing);
@@ -51693,22 +52621,22 @@ ${preview}
51693
52621
  }
51694
52622
  readWorkers() {
51695
52623
  try {
51696
- if (!(0, import_node_fs10.existsSync)(this.workersPath))
52624
+ if (!(0, import_node_fs11.existsSync)(this.workersPath))
51697
52625
  return [];
51698
- const raw = JSON.parse((0, import_node_fs10.readFileSync)(this.workersPath, "utf-8"));
52626
+ const raw = JSON.parse((0, import_node_fs11.readFileSync)(this.workersPath, "utf-8"));
51699
52627
  return Array.isArray(raw?.workers) ? raw.workers : [];
51700
52628
  } catch {
51701
52629
  return [];
51702
52630
  }
51703
52631
  }
51704
52632
  writeWorkers(workers) {
51705
- (0, import_node_fs10.writeFileSync)(this.workersPath, JSON.stringify({ workers }, null, 2));
52633
+ (0, import_node_fs11.writeFileSync)(this.workersPath, JSON.stringify({ workers }, null, 2));
51706
52634
  }
51707
52635
  };
51708
52636
 
51709
52637
  // packages/sdk/dist/workflows/file-db.js
51710
- var import_node_fs11 = require("node:fs");
51711
- var import_node_path14 = __toESM(require("node:path"), 1);
52638
+ var import_node_fs12 = require("node:fs");
52639
+ var import_node_path15 = __toESM(require("node:path"), 1);
51712
52640
  var JsonFileWorkflowDb = class {
51713
52641
  filePath;
51714
52642
  /** Whether the storage directory is writable. False = silent no-op mode. */
@@ -51718,7 +52646,7 @@ var JsonFileWorkflowDb = class {
51718
52646
  this.filePath = filePath;
51719
52647
  let writable = false;
51720
52648
  try {
51721
- (0, import_node_fs11.mkdirSync)(import_node_path14.default.dirname(filePath), { recursive: true });
52649
+ (0, import_node_fs12.mkdirSync)(import_node_path15.default.dirname(filePath), { recursive: true });
51722
52650
  writable = true;
51723
52651
  } catch {
51724
52652
  }
@@ -51730,8 +52658,8 @@ var JsonFileWorkflowDb = class {
51730
52658
  }
51731
52659
  hasStepOutputs(runId) {
51732
52660
  try {
51733
- const dir = import_node_path14.default.join(import_node_path14.default.dirname(this.filePath), "step-outputs", runId);
51734
- return (0, import_node_fs11.existsSync)(dir) && (0, import_node_fs11.readdirSync)(dir).length > 0;
52661
+ const dir = import_node_path15.default.join(import_node_path15.default.dirname(this.filePath), "step-outputs", runId);
52662
+ return (0, import_node_fs12.existsSync)(dir) && (0, import_node_fs12.readdirSync)(dir).length > 0;
51735
52663
  } catch {
51736
52664
  return false;
51737
52665
  }
@@ -51741,7 +52669,7 @@ var JsonFileWorkflowDb = class {
51741
52669
  if (!this.writable)
51742
52670
  return;
51743
52671
  try {
51744
- (0, import_node_fs11.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", "utf8");
52672
+ (0, import_node_fs12.appendFileSync)(this.filePath, JSON.stringify(entry) + "\n", "utf8");
51745
52673
  } catch (err) {
51746
52674
  if (!this.appendFailedOnce) {
51747
52675
  this.appendFailedOnce = true;
@@ -51755,7 +52683,7 @@ var JsonFileWorkflowDb = class {
51755
52683
  const steps = /* @__PURE__ */ new Map();
51756
52684
  let raw = "";
51757
52685
  try {
51758
- raw = (0, import_node_fs11.readFileSync)(this.filePath, "utf8");
52686
+ raw = (0, import_node_fs12.readFileSync)(this.filePath, "utf8");
51759
52687
  } catch {
51760
52688
  return { runs, steps };
51761
52689
  }
@@ -53197,8 +54125,8 @@ var StateStore = class extends import_node_events4.EventEmitter {
53197
54125
  };
53198
54126
 
53199
54127
  // packages/sdk/dist/workflows/templates.js
53200
- var import_node_fs12 = require("node:fs");
53201
- var import_node_path15 = __toESM(require("node:path"), 1);
54128
+ var import_node_fs13 = require("node:fs");
54129
+ var import_node_path16 = __toESM(require("node:path"), 1);
53202
54130
  var import_node_url2 = require("node:url");
53203
54131
  var import_yaml4 = __toESM(require_dist(), 1);
53204
54132
  var YAML_EXTENSIONS = [".yaml", ".yml"];
@@ -53223,7 +54151,7 @@ var TemplateRegistry = class {
53223
54151
  fetcher;
53224
54152
  constructor(options = {}) {
53225
54153
  this.builtInTemplatesDir = this.resolveBuiltInTemplatesDir(options.builtInTemplatesDir);
53226
- this.customTemplatesDir = options.customTemplatesDir ? import_node_path15.default.resolve(options.customTemplatesDir) : import_node_path15.default.resolve(options.workspaceDir ?? process.cwd(), ".relay/workflows");
54154
+ this.customTemplatesDir = options.customTemplatesDir ? import_node_path16.default.resolve(options.customTemplatesDir) : import_node_path16.default.resolve(options.workspaceDir ?? process.cwd(), ".relay/workflows");
53227
54155
  this.fetcher = options.fetcher ?? fetch;
53228
54156
  }
53229
54157
  listBuiltInTemplates() {
@@ -53297,13 +54225,13 @@ var TemplateRegistry = class {
53297
54225
  if (!templateName) {
53298
54226
  throw new Error('Template name is required. Provide name explicitly or include a string "name" field.');
53299
54227
  }
53300
- if (templateName.includes("/") || templateName.includes("\\") || templateName.includes("..") || import_node_path15.default.isAbsolute(templateName)) {
54228
+ if (templateName.includes("/") || templateName.includes("\\") || templateName.includes("..") || import_node_path16.default.isAbsolute(templateName)) {
53301
54229
  throw new Error(`Invalid template name: "${templateName}" contains path separators or traversal sequences`);
53302
54230
  }
53303
54231
  this.validateRelayConfig(parsed, url2);
53304
- await import_node_fs12.promises.mkdir(this.customTemplatesDir, { recursive: true });
53305
- const targetPath = import_node_path15.default.join(this.customTemplatesDir, `${templateName}.yaml`);
53306
- await import_node_fs12.promises.writeFile(targetPath, (0, import_yaml4.stringify)(parsed), "utf-8");
54232
+ await import_node_fs13.promises.mkdir(this.customTemplatesDir, { recursive: true });
54233
+ const targetPath = import_node_path16.default.join(this.customTemplatesDir, `${templateName}.yaml`);
54234
+ await import_node_fs13.promises.writeFile(targetPath, (0, import_yaml4.stringify)(parsed), "utf-8");
53307
54235
  return targetPath;
53308
54236
  }
53309
54237
  isTemplateShorthand(input) {
@@ -53324,15 +54252,15 @@ var TemplateRegistry = class {
53324
54252
  }
53325
54253
  resolveBuiltInTemplatesDir(explicitDir) {
53326
54254
  if (explicitDir) {
53327
- return import_node_path15.default.resolve(explicitDir);
54255
+ return import_node_path16.default.resolve(explicitDir);
53328
54256
  }
53329
- const currentDir = import_node_path15.default.dirname((0, import_node_url2.fileURLToPath)(import_meta_url));
54257
+ const currentDir = import_node_path16.default.dirname((0, import_node_url2.fileURLToPath)(import_meta_url));
53330
54258
  const candidates = [
53331
- import_node_path15.default.resolve(currentDir, "builtin-templates"),
53332
- import_node_path15.default.resolve(currentDir, "../workflows/builtin-templates")
54259
+ import_node_path16.default.resolve(currentDir, "builtin-templates"),
54260
+ import_node_path16.default.resolve(currentDir, "../workflows/builtin-templates")
53333
54261
  ];
53334
54262
  for (const candidate of candidates) {
53335
- if ((0, import_node_fs12.existsSync)(candidate)) {
54263
+ if ((0, import_node_fs13.existsSync)(candidate)) {
53336
54264
  return candidate;
53337
54265
  }
53338
54266
  }
@@ -53352,9 +54280,9 @@ var TemplateRegistry = class {
53352
54280
  }
53353
54281
  async findTemplatePath(directory, templateName) {
53354
54282
  for (const ext of YAML_EXTENSIONS) {
53355
- const candidate = import_node_path15.default.join(directory, `${templateName}${ext}`);
54283
+ const candidate = import_node_path16.default.join(directory, `${templateName}${ext}`);
53356
54284
  try {
53357
- const stat2 = await import_node_fs12.promises.stat(candidate);
54285
+ const stat2 = await import_node_fs13.promises.stat(candidate);
53358
54286
  if (stat2.isFile()) {
53359
54287
  return candidate;
53360
54288
  }
@@ -53364,7 +54292,7 @@ var TemplateRegistry = class {
53364
54292
  return void 0;
53365
54293
  }
53366
54294
  async readTemplateFile(templatePath) {
53367
- const raw = await import_node_fs12.promises.readFile(templatePath, "utf-8");
54295
+ const raw = await import_node_fs13.promises.readFile(templatePath, "utf-8");
53368
54296
  const parsed = (0, import_yaml4.parse)(raw);
53369
54297
  if (!isRecord(parsed)) {
53370
54298
  throw new Error(`Template at ${templatePath} is not a YAML object`);
@@ -53557,7 +54485,7 @@ var TemplateRegistry = class {
53557
54485
  }
53558
54486
  async safeReadDir(directory) {
53559
54487
  try {
53560
- return await import_node_fs12.promises.readdir(directory);
54488
+ return await import_node_fs13.promises.readdir(directory);
53561
54489
  } catch {
53562
54490
  return [];
53563
54491
  }
@@ -53724,8 +54652,8 @@ function isValidAgentName(name) {
53724
54652
  }
53725
54653
 
53726
54654
  // packages/utils/dist/logger.js
53727
- var import_node_fs13 = __toESM(require("node:fs"), 1);
53728
- var import_node_path16 = __toESM(require("node:path"), 1);
54655
+ var import_node_fs14 = __toESM(require("node:fs"), 1);
54656
+ var import_node_path17 = __toESM(require("node:path"), 1);
53729
54657
  function getLogFile() {
53730
54658
  return process.env.AGENT_RELAY_LOG_FILE;
53731
54659
  }
@@ -53743,9 +54671,9 @@ var LEVEL_PRIORITY = {
53743
54671
  };
53744
54672
  var createdLogDirs = /* @__PURE__ */ new Set();
53745
54673
  function ensureLogDir(logFile) {
53746
- const logDir = import_node_path16.default.dirname(logFile);
53747
- if (!createdLogDirs.has(logDir) && !import_node_fs13.default.existsSync(logDir)) {
53748
- import_node_fs13.default.mkdirSync(logDir, { recursive: true });
54674
+ const logDir = import_node_path17.default.dirname(logFile);
54675
+ if (!createdLogDirs.has(logDir) && !import_node_fs14.default.existsSync(logDir)) {
54676
+ import_node_fs14.default.mkdirSync(logDir, { recursive: true });
53749
54677
  createdLogDirs.add(logDir);
53750
54678
  }
53751
54679
  }
@@ -53774,7 +54702,7 @@ function log(level, component, msg, extra) {
53774
54702
  const logFile = getLogFile();
53775
54703
  if (logFile) {
53776
54704
  ensureLogDir(logFile);
53777
- import_node_fs13.default.appendFileSync(logFile, formatted + "\n");
54705
+ import_node_fs14.default.appendFileSync(logFile, formatted + "\n");
53778
54706
  return;
53779
54707
  }
53780
54708
  if (level === "ERROR" || level === "WARN") {
@@ -54044,14 +54972,14 @@ function benchmarkPatterns(iterations = 1e4) {
54044
54972
  }
54045
54973
 
54046
54974
  // packages/utils/dist/command-resolver.js
54047
- var import_node_child_process6 = require("node:child_process");
54048
- var import_node_fs14 = __toESM(require("node:fs"), 1);
54975
+ var import_node_child_process7 = require("node:child_process");
54976
+ var import_node_fs15 = __toESM(require("node:fs"), 1);
54049
54977
  function resolveCommand(command) {
54050
54978
  if (command.startsWith("/")) {
54051
54979
  return resolveSymlinks(command);
54052
54980
  }
54053
54981
  try {
54054
- const output = (0, import_node_child_process6.execSync)(`which ${command}`, {
54982
+ const output = (0, import_node_child_process7.execSync)(`which ${command}`, {
54055
54983
  encoding: "utf-8",
54056
54984
  stdio: ["pipe", "pipe", "pipe"],
54057
54985
  // Ensure we have a reasonable PATH
@@ -54071,7 +54999,7 @@ function resolveCommand(command) {
54071
54999
  }
54072
55000
  function resolveSymlinks(filePath) {
54073
55001
  try {
54074
- const resolved = import_node_fs14.default.realpathSync(filePath);
55002
+ const resolved = import_node_fs15.default.realpathSync(filePath);
54075
55003
  if (resolved !== filePath && process.env.DEBUG_SPAWN === "1") {
54076
55004
  console.log(`[command-resolver] Resolved symlink: ${filePath} -> ${resolved}`);
54077
55005
  }
@@ -54085,7 +55013,7 @@ function resolveSymlinks(filePath) {
54085
55013
  }
54086
55014
  function commandExists(command) {
54087
55015
  try {
54088
- (0, import_node_child_process6.execSync)(`which ${command}`, {
55016
+ (0, import_node_child_process7.execSync)(`which ${command}`, {
54089
55017
  encoding: "utf-8",
54090
55018
  stdio: ["pipe", "pipe", "pipe"]
54091
55019
  });
@@ -54097,8 +55025,8 @@ function commandExists(command) {
54097
55025
 
54098
55026
  // packages/utils/dist/git-remote.js
54099
55027
  var fs6 = __toESM(require("node:fs"), 1);
54100
- var path14 = __toESM(require("node:path"), 1);
54101
- var import_node_child_process7 = require("node:child_process");
55028
+ var path15 = __toESM(require("node:path"), 1);
55029
+ var import_node_child_process8 = require("node:child_process");
54102
55030
  function parseGitRemoteUrl(url2) {
54103
55031
  if (!url2)
54104
55032
  return null;
@@ -54114,11 +55042,11 @@ function parseGitRemoteUrl(url2) {
54114
55042
  }
54115
55043
  function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
54116
55044
  try {
54117
- const gitDir = path14.join(workingDirectory, ".git");
55045
+ const gitDir = path15.join(workingDirectory, ".git");
54118
55046
  if (!fs6.existsSync(gitDir)) {
54119
55047
  return null;
54120
55048
  }
54121
- const result = (0, import_node_child_process7.execSync)(`git remote get-url ${remoteName}`, {
55049
+ const result = (0, import_node_child_process8.execSync)(`git remote get-url ${remoteName}`, {
54122
55050
  cwd: workingDirectory,
54123
55051
  encoding: "utf-8",
54124
55052
  timeout: 5e3,
@@ -54127,7 +55055,7 @@ function getGitRemoteUrl(workingDirectory, remoteName = "origin") {
54127
55055
  return result.trim() || null;
54128
55056
  } catch {
54129
55057
  try {
54130
- const configPath = path14.join(workingDirectory, ".git", "config");
55058
+ const configPath = path15.join(workingDirectory, ".git", "config");
54131
55059
  if (!fs6.existsSync(configPath)) {
54132
55060
  return null;
54133
55061
  }
@@ -54148,13 +55076,13 @@ function getRepoFullName(workingDirectory) {
54148
55076
  return parseGitRemoteUrl(remoteUrl);
54149
55077
  }
54150
55078
  function findGitRoot(startPath) {
54151
- let currentPath = path14.resolve(startPath);
54152
- const root = path14.parse(currentPath).root;
55079
+ let currentPath = path15.resolve(startPath);
55080
+ const root = path15.parse(currentPath).root;
54153
55081
  while (currentPath !== root) {
54154
- if (fs6.existsSync(path14.join(currentPath, ".git"))) {
55082
+ if (fs6.existsSync(path15.join(currentPath, ".git"))) {
54155
55083
  return currentPath;
54156
55084
  }
54157
- currentPath = path14.dirname(currentPath);
55085
+ currentPath = path15.dirname(currentPath);
54158
55086
  }
54159
55087
  return null;
54160
55088
  }
@@ -54171,8 +55099,8 @@ function getRepoFullNameFromPath(workingDirectory) {
54171
55099
  }
54172
55100
 
54173
55101
  // packages/utils/dist/update-checker.js
54174
- var import_node_fs15 = __toESM(require("node:fs"), 1);
54175
- var import_node_path17 = __toESM(require("node:path"), 1);
55102
+ var import_node_fs16 = __toESM(require("node:fs"), 1);
55103
+ var import_node_path18 = __toESM(require("node:path"), 1);
54176
55104
  var import_node_https = __toESM(require("node:https"), 1);
54177
55105
  var import_node_os9 = __toESM(require("node:os"), 1);
54178
55106
  var import_compare_versions = __toESM(require_umd(), 1);
@@ -54180,15 +55108,15 @@ var PACKAGE_NAME = "agent-relay";
54180
55108
  var CHECK_INTERVAL_MS = 60 * 60 * 1e3;
54181
55109
  var NPM_REGISTRY_URL = `https://registry.npmjs.org/${PACKAGE_NAME}/latest`;
54182
55110
  function getCachePath() {
54183
- const cacheDir = import_node_path17.default.join(import_node_os9.default.homedir(), ".agent-relay");
54184
- return import_node_path17.default.join(cacheDir, "update-cache.json");
55111
+ const cacheDir = import_node_path18.default.join(import_node_os9.default.homedir(), ".agent-relay");
55112
+ return import_node_path18.default.join(cacheDir, "update-cache.json");
54185
55113
  }
54186
55114
  function readCache() {
54187
55115
  try {
54188
55116
  const cachePath = getCachePath();
54189
- if (!import_node_fs15.default.existsSync(cachePath))
55117
+ if (!import_node_fs16.default.existsSync(cachePath))
54190
55118
  return null;
54191
- const data = import_node_fs15.default.readFileSync(cachePath, "utf-8");
55119
+ const data = import_node_fs16.default.readFileSync(cachePath, "utf-8");
54192
55120
  return JSON.parse(data);
54193
55121
  } catch {
54194
55122
  return null;
@@ -54197,27 +55125,27 @@ function readCache() {
54197
55125
  function writeCache(cache) {
54198
55126
  try {
54199
55127
  const cachePath = getCachePath();
54200
- const cacheDir = import_node_path17.default.dirname(cachePath);
54201
- if (!import_node_fs15.default.existsSync(cacheDir)) {
54202
- import_node_fs15.default.mkdirSync(cacheDir, { recursive: true });
55128
+ const cacheDir = import_node_path18.default.dirname(cachePath);
55129
+ if (!import_node_fs16.default.existsSync(cacheDir)) {
55130
+ import_node_fs16.default.mkdirSync(cacheDir, { recursive: true });
54203
55131
  }
54204
- import_node_fs15.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
55132
+ import_node_fs16.default.writeFileSync(cachePath, JSON.stringify(cache, null, 2));
54205
55133
  } catch {
54206
55134
  }
54207
55135
  }
54208
55136
  function fetchLatestVersion() {
54209
- return new Promise((resolve3, reject) => {
55137
+ return new Promise((resolve4, reject) => {
54210
55138
  const req = import_node_https.default.get(NPM_REGISTRY_URL, { timeout: 5e3 }, (res) => {
54211
55139
  if (res.statusCode === 301 || res.statusCode === 302) {
54212
55140
  const location = res.headers.location;
54213
55141
  if (location) {
54214
55142
  import_node_https.default.get(location, { timeout: 5e3 }, (redirectRes) => {
54215
- handleResponse(redirectRes, resolve3, reject);
55143
+ handleResponse(redirectRes, resolve4, reject);
54216
55144
  }).on("error", reject);
54217
55145
  return;
54218
55146
  }
54219
55147
  }
54220
- handleResponse(res, resolve3, reject);
55148
+ handleResponse(res, resolve4, reject);
54221
55149
  });
54222
55150
  req.on("error", reject);
54223
55151
  req.on("timeout", () => {
@@ -54226,7 +55154,7 @@ function fetchLatestVersion() {
54226
55154
  });
54227
55155
  });
54228
55156
  }
54229
- function handleResponse(res, resolve3, reject) {
55157
+ function handleResponse(res, resolve4, reject) {
54230
55158
  if (res.statusCode !== 200) {
54231
55159
  reject(new Error(`HTTP ${res.statusCode}`));
54232
55160
  return;
@@ -54239,7 +55167,7 @@ function handleResponse(res, resolve3, reject) {
54239
55167
  try {
54240
55168
  const json2 = JSON.parse(data);
54241
55169
  if (json2.version) {
54242
- resolve3(json2.version);
55170
+ resolve4(json2.version);
54243
55171
  } else {
54244
55172
  reject(new Error("No version in response"));
54245
55173
  }
@@ -54480,9 +55408,9 @@ function validateModelForCli(cli, model) {
54480
55408
  }
54481
55409
 
54482
55410
  // packages/utils/dist/relay-pty-path.js
54483
- var import_node_fs16 = __toESM(require("node:fs"), 1);
55411
+ var import_node_fs17 = __toESM(require("node:fs"), 1);
54484
55412
  var import_node_os10 = __toESM(require("node:os"), 1);
54485
- var import_node_path18 = __toESM(require("node:path"), 1);
55413
+ var import_node_path19 = __toESM(require("node:path"), 1);
54486
55414
  var SUPPORTED_PLATFORMS = {
54487
55415
  darwin: {
54488
55416
  arm64: "relay-pty-darwin-arm64",
@@ -54530,23 +55458,23 @@ function findRelayPtyBinary(callerDirname) {
54530
55458
  const scopedMatch = normalizedCaller.match(/^(.+?\/node_modules)\/@agent-relay\//);
54531
55459
  const directMatch = normalizedCaller.match(/^(.+?\/node_modules\/agent-relay)/);
54532
55460
  if (scopedMatch) {
54533
- packageRoots.push(import_node_path18.default.join(scopedMatch[1], "agent-relay"));
55461
+ packageRoots.push(import_node_path19.default.join(scopedMatch[1], "agent-relay"));
54534
55462
  }
54535
55463
  if (directMatch) {
54536
55464
  packageRoots.push(directMatch[1]);
54537
55465
  }
54538
55466
  if (!normalizedCaller.includes("node_modules")) {
54539
- packageRoots.push(import_node_path18.default.join(callerDirname, "..", "..", ".."));
55467
+ packageRoots.push(import_node_path19.default.join(callerDirname, "..", "..", ".."));
54540
55468
  }
54541
55469
  const home = process.env.HOME || process.env.USERPROFILE || "";
54542
55470
  if (home) {
54543
- const npxCacheBase = import_node_path18.default.join(home, ".npm", "_npx");
54544
- if (import_node_fs16.default.existsSync(npxCacheBase)) {
55471
+ const npxCacheBase = import_node_path19.default.join(home, ".npm", "_npx");
55472
+ if (import_node_fs17.default.existsSync(npxCacheBase)) {
54545
55473
  try {
54546
- const entries = import_node_fs16.default.readdirSync(npxCacheBase);
55474
+ const entries = import_node_fs17.default.readdirSync(npxCacheBase);
54547
55475
  for (const entry of entries) {
54548
- const npxPackage = import_node_path18.default.join(npxCacheBase, entry, "node_modules", "agent-relay");
54549
- if (import_node_fs16.default.existsSync(npxPackage)) {
55476
+ const npxPackage = import_node_path19.default.join(npxCacheBase, entry, "node_modules", "agent-relay");
55477
+ if (import_node_fs17.default.existsSync(npxPackage)) {
54550
55478
  packageRoots.push(npxPackage);
54551
55479
  }
54552
55480
  }
@@ -54554,42 +55482,42 @@ function findRelayPtyBinary(callerDirname) {
54554
55482
  }
54555
55483
  }
54556
55484
  }
54557
- packageRoots.push(import_node_path18.default.join(process.cwd(), "node_modules", "agent-relay"));
55485
+ packageRoots.push(import_node_path19.default.join(process.cwd(), "node_modules", "agent-relay"));
54558
55486
  if (home) {
54559
- packageRoots.push(import_node_path18.default.join(home, ".nvm", "versions", "node", process.version, "lib", "node_modules", "agent-relay"));
54560
- packageRoots.push(import_node_path18.default.join(home, ".volta", "tools", "image", "packages", "agent-relay", "lib", "node_modules", "agent-relay"));
54561
- packageRoots.push(import_node_path18.default.join(home, ".fnm", "node-versions", process.version, "installation", "lib", "node_modules", "agent-relay"));
54562
- packageRoots.push(import_node_path18.default.join(home, "n", "lib", "node_modules", "agent-relay"));
54563
- packageRoots.push(import_node_path18.default.join(home, ".asdf", "installs", "nodejs", process.version.replace("v", ""), "lib", "node_modules", "agent-relay"));
54564
- packageRoots.push(import_node_path18.default.join(home, ".local", "share", "pnpm", "global", "node_modules", "agent-relay"));
54565
- packageRoots.push(import_node_path18.default.join(home, ".config", "yarn", "global", "node_modules", "agent-relay"));
54566
- packageRoots.push(import_node_path18.default.join(home, ".yarn", "global", "node_modules", "agent-relay"));
54567
- }
54568
- const bashInstallerDir = process.env.AGENT_RELAY_INSTALL_DIR ? import_node_path18.default.join(process.env.AGENT_RELAY_INSTALL_DIR, "bin") : home ? import_node_path18.default.join(home, ".agent-relay", "bin") : null;
54569
- const bashInstallerBinDir = process.env.AGENT_RELAY_BIN_DIR || (home ? import_node_path18.default.join(home, ".local", "bin") : null);
54570
- const nodePrefix = import_node_path18.default.resolve(import_node_path18.default.dirname(process.execPath), "..");
54571
- packageRoots.push(import_node_path18.default.join(nodePrefix, "lib", "node_modules", "agent-relay"));
55487
+ packageRoots.push(import_node_path19.default.join(home, ".nvm", "versions", "node", process.version, "lib", "node_modules", "agent-relay"));
55488
+ packageRoots.push(import_node_path19.default.join(home, ".volta", "tools", "image", "packages", "agent-relay", "lib", "node_modules", "agent-relay"));
55489
+ packageRoots.push(import_node_path19.default.join(home, ".fnm", "node-versions", process.version, "installation", "lib", "node_modules", "agent-relay"));
55490
+ packageRoots.push(import_node_path19.default.join(home, "n", "lib", "node_modules", "agent-relay"));
55491
+ packageRoots.push(import_node_path19.default.join(home, ".asdf", "installs", "nodejs", process.version.replace("v", ""), "lib", "node_modules", "agent-relay"));
55492
+ packageRoots.push(import_node_path19.default.join(home, ".local", "share", "pnpm", "global", "node_modules", "agent-relay"));
55493
+ packageRoots.push(import_node_path19.default.join(home, ".config", "yarn", "global", "node_modules", "agent-relay"));
55494
+ packageRoots.push(import_node_path19.default.join(home, ".yarn", "global", "node_modules", "agent-relay"));
55495
+ }
55496
+ const bashInstallerDir = process.env.AGENT_RELAY_INSTALL_DIR ? import_node_path19.default.join(process.env.AGENT_RELAY_INSTALL_DIR, "bin") : home ? import_node_path19.default.join(home, ".agent-relay", "bin") : null;
55497
+ const bashInstallerBinDir = process.env.AGENT_RELAY_BIN_DIR || (home ? import_node_path19.default.join(home, ".local", "bin") : null);
55498
+ const nodePrefix = import_node_path19.default.resolve(import_node_path19.default.dirname(process.execPath), "..");
55499
+ packageRoots.push(import_node_path19.default.join(nodePrefix, "lib", "node_modules", "agent-relay"));
54572
55500
  packageRoots.push("/usr/local/lib/node_modules/agent-relay");
54573
55501
  packageRoots.push("/opt/homebrew/lib/node_modules/agent-relay");
54574
55502
  packageRoots.push("/usr/lib/node_modules/agent-relay");
54575
55503
  const candidates = [];
54576
55504
  for (const root of packageRoots) {
54577
55505
  if (platformBinary) {
54578
- candidates.push(import_node_path18.default.join(root, "bin", platformBinary));
55506
+ candidates.push(import_node_path19.default.join(root, "bin", platformBinary));
54579
55507
  }
54580
- candidates.push(import_node_path18.default.join(root, "bin", "relay-pty"));
55508
+ candidates.push(import_node_path19.default.join(root, "bin", "relay-pty"));
54581
55509
  }
54582
55510
  if (bashInstallerDir) {
54583
55511
  if (platformBinary) {
54584
- candidates.push(import_node_path18.default.join(bashInstallerDir, platformBinary));
55512
+ candidates.push(import_node_path19.default.join(bashInstallerDir, platformBinary));
54585
55513
  }
54586
- candidates.push(import_node_path18.default.join(bashInstallerDir, "relay-pty"));
55514
+ candidates.push(import_node_path19.default.join(bashInstallerDir, "relay-pty"));
54587
55515
  }
54588
55516
  if (bashInstallerBinDir) {
54589
55517
  if (platformBinary) {
54590
- candidates.push(import_node_path18.default.join(bashInstallerBinDir, platformBinary));
55518
+ candidates.push(import_node_path19.default.join(bashInstallerBinDir, platformBinary));
54591
55519
  }
54592
- candidates.push(import_node_path18.default.join(bashInstallerBinDir, "relay-pty"));
55520
+ candidates.push(import_node_path19.default.join(bashInstallerBinDir, "relay-pty"));
54593
55521
  }
54594
55522
  candidates.push("/app/bin/relay-pty");
54595
55523
  candidates.push("/usr/local/bin/relay-pty");
@@ -54604,7 +55532,7 @@ function findRelayPtyBinary(callerDirname) {
54604
55532
  }
54605
55533
  function isExecutable(filePath) {
54606
55534
  try {
54607
- import_node_fs16.default.accessSync(filePath, import_node_fs16.default.constants.X_OK);
55535
+ import_node_fs17.default.accessSync(filePath, import_node_fs17.default.constants.X_OK);
54608
55536
  return true;
54609
55537
  } catch {
54610
55538
  return false;
@@ -54613,9 +55541,9 @@ function isExecutable(filePath) {
54613
55541
  function isPlatformCompatibleBinary(filePath) {
54614
55542
  let fd;
54615
55543
  try {
54616
- fd = import_node_fs16.default.openSync(filePath, "r");
55544
+ fd = import_node_fs17.default.openSync(filePath, "r");
54617
55545
  const header = Buffer.alloc(4);
54618
- const bytesRead = import_node_fs16.default.readSync(fd, header, 0, 4, 0);
55546
+ const bytesRead = import_node_fs17.default.readSync(fd, header, 0, 4, 0);
54619
55547
  if (bytesRead < 4) {
54620
55548
  return false;
54621
55549
  }
@@ -54633,7 +55561,7 @@ function isPlatformCompatibleBinary(filePath) {
54633
55561
  } finally {
54634
55562
  if (fd !== void 0) {
54635
55563
  try {
54636
- import_node_fs16.default.closeSync(fd);
55564
+ import_node_fs17.default.closeSync(fd);
54637
55565
  } catch {
54638
55566
  }
54639
55567
  }
@@ -54714,16 +55642,16 @@ function isMatchingResponse(response, requestId, correlationId) {
54714
55642
  const ackPayload = response.type === "ACK" ? response.payload : null;
54715
55643
  return response.id === requestId || responsePayload?.replyTo === requestId || !!correlationId && (responsePayload?.correlationId === correlationId || ackPayload?.correlationId === correlationId);
54716
55644
  }
54717
- function handleResponse2(response, resolve3, reject) {
55645
+ function handleResponse2(response, resolve4, reject) {
54718
55646
  const responsePayload = response.payload;
54719
55647
  if (response.type === "ERROR") {
54720
55648
  reject(new Error(responsePayload?.message || responsePayload?.code || "Unknown error"));
54721
55649
  } else if (response.type === "ACK" || response.type === "SPAWN_RESULT" || response.type === "RELEASE_RESULT") {
54722
- resolve3(response.payload);
55650
+ resolve4(response.payload);
54723
55651
  } else if (responsePayload?.error && !responsePayload?.success) {
54724
55652
  reject(new Error(responsePayload.error));
54725
55653
  } else {
54726
- resolve3(response.payload);
55654
+ resolve4(response.payload);
54727
55655
  }
54728
55656
  }
54729
55657
  function createRequestEnvelope(type, payload, requestId, options) {
@@ -54757,7 +55685,7 @@ function toReleaseResult(payload) {
54757
55685
  };
54758
55686
  }
54759
55687
  function createRequestHandler(socketPath, envelope, options) {
54760
- return new Promise((resolve3, reject) => {
55688
+ return new Promise((resolve4, reject) => {
54761
55689
  const correlationId = options.payloadMeta?.sync?.correlationId;
54762
55690
  let timedOut = false;
54763
55691
  const parser = new FrameParser();
@@ -54779,7 +55707,7 @@ function createRequestHandler(socketPath, envelope, options) {
54779
55707
  if (isMatchingResponse(response, envelope.id, correlationId)) {
54780
55708
  clearTimeout(timeoutId);
54781
55709
  socket.end();
54782
- handleResponse2(response, resolve3, reject);
55710
+ handleResponse2(response, resolve4, reject);
54783
55711
  return;
54784
55712
  }
54785
55713
  }
@@ -55249,12 +56177,12 @@ var HookRegistry = class {
55249
56177
  };
55250
56178
 
55251
56179
  // packages/trajectory/dist/integration.js
55252
- var import_node_child_process8 = require("node:child_process");
56180
+ var import_node_child_process9 = require("node:child_process");
55253
56181
 
55254
56182
  // packages/config/dist/project-namespace.js
55255
56183
  var import_node_crypto13 = __toESM(require("node:crypto"), 1);
55256
- var import_node_path19 = __toESM(require("node:path"), 1);
55257
- var import_node_fs17 = __toESM(require("node:fs"), 1);
56184
+ var import_node_path20 = __toESM(require("node:path"), 1);
56185
+ var import_node_fs18 = __toESM(require("node:fs"), 1);
55258
56186
  var import_node_os11 = __toESM(require("node:os"), 1);
55259
56187
  function getGlobalBaseDir2() {
55260
56188
  if (process.env.AGENT_RELAY_DATA_DIR) {
@@ -55262,65 +56190,65 @@ function getGlobalBaseDir2() {
55262
56190
  }
55263
56191
  const xdgDataHome = process.env.XDG_DATA_HOME;
55264
56192
  if (xdgDataHome) {
55265
- return import_node_path19.default.join(xdgDataHome, "agent-relay");
56193
+ return import_node_path20.default.join(xdgDataHome, "agent-relay");
55266
56194
  }
55267
- return import_node_path19.default.join(import_node_os11.default.homedir(), ".agent-relay");
56195
+ return import_node_path20.default.join(import_node_os11.default.homedir(), ".agent-relay");
55268
56196
  }
55269
56197
  var GLOBAL_BASE_DIR2 = getGlobalBaseDir2();
55270
56198
  var PROJECT_DATA_DIR = ".agent-relay";
55271
56199
  function hashPath(projectPath) {
55272
- const normalized = import_node_path19.default.resolve(projectPath);
56200
+ const normalized = import_node_path20.default.resolve(projectPath);
55273
56201
  const hash2 = import_node_crypto13.default.createHash("sha256").update(normalized).digest("hex");
55274
56202
  return hash2.substring(0, 12);
55275
56203
  }
55276
56204
  function findProjectRoot(startDir = process.cwd()) {
55277
56205
  if (process.env.AGENT_RELAY_PROJECT) {
55278
- return import_node_path19.default.resolve(process.env.AGENT_RELAY_PROJECT);
56206
+ return import_node_path20.default.resolve(process.env.AGENT_RELAY_PROJECT);
55279
56207
  }
55280
- let current = import_node_path19.default.resolve(startDir);
55281
- const root = import_node_path19.default.parse(current).root;
56208
+ let current = import_node_path20.default.resolve(startDir);
56209
+ const root = import_node_path20.default.parse(current).root;
55282
56210
  const markers = [".git", "package.json", "Cargo.toml", "go.mod", "pyproject.toml", ".agent-relay"];
55283
56211
  while (current !== root) {
55284
56212
  for (const marker of markers) {
55285
- if (import_node_fs17.default.existsSync(import_node_path19.default.join(current, marker))) {
56213
+ if (import_node_fs18.default.existsSync(import_node_path20.default.join(current, marker))) {
55286
56214
  return current;
55287
56215
  }
55288
56216
  }
55289
- current = import_node_path19.default.dirname(current);
56217
+ current = import_node_path20.default.dirname(current);
55290
56218
  }
55291
- return import_node_path19.default.resolve(startDir);
56219
+ return import_node_path20.default.resolve(startDir);
55292
56220
  }
55293
56221
  function getProjectPaths2(projectRoot) {
55294
56222
  const root = projectRoot ?? findProjectRoot();
55295
56223
  const projectId = hashPath(root);
55296
- const dataDir = import_node_path19.default.join(root, PROJECT_DATA_DIR);
56224
+ const dataDir = import_node_path20.default.join(root, PROJECT_DATA_DIR);
55297
56225
  return {
55298
56226
  dataDir,
55299
- teamDir: import_node_path19.default.join(dataDir, "team"),
55300
- dbPath: import_node_path19.default.join(dataDir, "messages.sqlite"),
55301
- socketPath: import_node_path19.default.join(dataDir, "relay.sock"),
56227
+ teamDir: import_node_path20.default.join(dataDir, "team"),
56228
+ dbPath: import_node_path20.default.join(dataDir, "messages.sqlite"),
56229
+ socketPath: import_node_path20.default.join(dataDir, "relay.sock"),
55302
56230
  projectRoot: root,
55303
56231
  projectId
55304
56232
  };
55305
56233
  }
55306
56234
 
55307
56235
  // packages/config/dist/trajectory-config.js
55308
- var import_node_fs18 = require("node:fs");
55309
- var import_node_path20 = require("node:path");
56236
+ var import_node_fs19 = require("node:fs");
56237
+ var import_node_path21 = require("node:path");
55310
56238
  var import_node_os12 = require("node:os");
55311
56239
  var import_node_crypto14 = require("node:crypto");
55312
56240
  function getAgentRelayConfigDir() {
55313
- return process.env.AGENT_RELAY_CONFIG_DIR ?? (0, import_node_path20.join)((0, import_node_os12.homedir)(), ".config", "agent-relay");
56241
+ return process.env.AGENT_RELAY_CONFIG_DIR ?? (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".config", "agent-relay");
55314
56242
  }
55315
56243
  var configCache = null;
55316
56244
  function getRelayConfigPath(_projectRoot) {
55317
- return (0, import_node_path20.join)(getAgentRelayConfigDir(), "relay.json");
56245
+ return (0, import_node_path21.join)(getAgentRelayConfigDir(), "relay.json");
55318
56246
  }
55319
56247
  function readRelayConfig(projectRoot) {
55320
56248
  const configPath = getRelayConfigPath(projectRoot);
55321
56249
  if (configCache && configCache.path === configPath) {
55322
56250
  try {
55323
- const stat2 = (0, import_node_fs18.statSync)(configPath);
56251
+ const stat2 = (0, import_node_fs19.statSync)(configPath);
55324
56252
  if (stat2.mtimeMs === configCache.mtime) {
55325
56253
  return configCache.config;
55326
56254
  }
@@ -55328,13 +56256,13 @@ function readRelayConfig(projectRoot) {
55328
56256
  }
55329
56257
  }
55330
56258
  try {
55331
- if (!(0, import_node_fs18.existsSync)(configPath)) {
56259
+ if (!(0, import_node_fs19.existsSync)(configPath)) {
55332
56260
  return {};
55333
56261
  }
55334
- const content = (0, import_node_fs18.readFileSync)(configPath, "utf-8");
56262
+ const content = (0, import_node_fs19.readFileSync)(configPath, "utf-8");
55335
56263
  const config2 = JSON.parse(content);
55336
56264
  try {
55337
- const stat2 = (0, import_node_fs18.statSync)(configPath);
56265
+ const stat2 = (0, import_node_fs19.statSync)(configPath);
55338
56266
  configCache = { path: configPath, config: config2, mtime: stat2.mtimeMs };
55339
56267
  } catch {
55340
56268
  }
@@ -55354,12 +56282,12 @@ function getProjectHash(projectRoot) {
55354
56282
  }
55355
56283
  function getUserTrajectoriesDir(projectRoot) {
55356
56284
  const projectHash = getProjectHash(projectRoot);
55357
- const configDir = process.env.XDG_CONFIG_HOME || (0, import_node_path20.join)((0, import_node_os12.homedir)(), ".config");
55358
- return (0, import_node_path20.join)(configDir, "agent-relay", "trajectories", projectHash);
56285
+ const configDir = process.env.XDG_CONFIG_HOME || (0, import_node_path21.join)((0, import_node_os12.homedir)(), ".config");
56286
+ return (0, import_node_path21.join)(configDir, "agent-relay", "trajectories", projectHash);
55359
56287
  }
55360
56288
  function getRepoTrajectoriesDir(projectRoot) {
55361
56289
  const root = projectRoot ?? getProjectPaths2().projectRoot;
55362
- return (0, import_node_path20.join)(root, ".trajectories");
56290
+ return (0, import_node_path21.join)(root, ".trajectories");
55363
56291
  }
55364
56292
  function getPrimaryTrajectoriesDir(projectRoot) {
55365
56293
  if (shouldStoreInRepo(projectRoot)) {
@@ -55376,9 +56304,9 @@ function getTrajectoryEnvVars(projectRoot) {
55376
56304
 
55377
56305
  // packages/trajectory/dist/integration.js
55378
56306
  async function runTrail(args) {
55379
- return new Promise((resolve3) => {
56307
+ return new Promise((resolve4) => {
55380
56308
  const trajectoryEnv = getTrajectoryEnvVars();
55381
- const proc = (0, import_node_child_process8.spawn)("trail", args, {
56309
+ const proc = (0, import_node_child_process9.spawn)("trail", args, {
55382
56310
  cwd: getProjectPaths2().projectRoot,
55383
56311
  env: { ...process.env, ...trajectoryEnv },
55384
56312
  stdio: ["pipe", "pipe", "pipe"]
@@ -55392,13 +56320,13 @@ async function runTrail(args) {
55392
56320
  stderr += data.toString();
55393
56321
  });
55394
56322
  proc.on("error", (err) => {
55395
- resolve3({ success: false, output: "", error: `Failed to run trail: ${err.message}` });
56323
+ resolve4({ success: false, output: "", error: `Failed to run trail: ${err.message}` });
55396
56324
  });
55397
56325
  proc.on("close", (code) => {
55398
56326
  if (code === 0) {
55399
- resolve3({ success: true, output: stdout.trim() });
56327
+ resolve4({ success: true, output: stdout.trim() });
55400
56328
  } else {
55401
- resolve3({ success: false, output: stdout.trim(), error: stderr.trim() || `Exit code: ${code}` });
56329
+ resolve4({ success: false, output: stdout.trim(), error: stderr.trim() || `Exit code: ${code}` });
55402
56330
  }
55403
56331
  });
55404
56332
  });
@@ -55649,7 +56577,7 @@ var TrajectoryIntegration = class {
55649
56577
  */
55650
56578
  isTrailInstalledSync() {
55651
56579
  try {
55652
- (0, import_node_child_process8.execSync)("which trail", { stdio: "pipe" });
56580
+ (0, import_node_child_process9.execSync)("which trail", { stdio: "pipe" });
55653
56581
  return true;
55654
56582
  } catch {
55655
56583
  return false;
@@ -55999,8 +56927,8 @@ var HookEmitter = class {
55999
56927
  };
56000
56928
 
56001
56929
  // packages/hooks/dist/inbox-check/utils.js
56002
- var import_node_fs19 = require("node:fs");
56003
- var import_node_path21 = require("node:path");
56930
+ var import_node_fs20 = require("node:fs");
56931
+ var import_node_path22 = require("node:path");
56004
56932
  var DEFAULT_INBOX_DIR = "/tmp/agent-relay";
56005
56933
  function getAgentName() {
56006
56934
  return process.env.AGENT_RELAY_NAME;
@@ -56010,16 +56938,16 @@ function getInboxPath(config2) {
56010
56938
  if (!agentName) {
56011
56939
  throw new Error("Agent name not configured. Set AGENT_RELAY_NAME env var.");
56012
56940
  }
56013
- return (0, import_node_path21.join)(config2.inboxDir, agentName, "inbox.md");
56941
+ return (0, import_node_path22.join)(config2.inboxDir, agentName, "inbox.md");
56014
56942
  }
56015
56943
  function inboxExists(inboxPath) {
56016
- return (0, import_node_fs19.existsSync)(inboxPath);
56944
+ return (0, import_node_fs20.existsSync)(inboxPath);
56017
56945
  }
56018
56946
  function readInbox(inboxPath) {
56019
56947
  if (!inboxExists(inboxPath)) {
56020
56948
  return "";
56021
56949
  }
56022
- return (0, import_node_fs19.readFileSync)(inboxPath, "utf-8");
56950
+ return (0, import_node_fs20.readFileSync)(inboxPath, "utf-8");
56023
56951
  }
56024
56952
  function hasUnreadMessages(inboxPath) {
56025
56953
  const content = readInbox(inboxPath);
@@ -56092,6 +57020,7 @@ init_dist2();
56092
57020
  COMMON_SEARCH_PATHS,
56093
57021
  CURSOR_MODEL_OPTIONS,
56094
57022
  CUSTOM_STEPS_FILE,
57023
+ ChannelMessenger,
56095
57024
  ClaudeModels,
56096
57025
  CodexModels,
56097
57026
  ConsensusEngine,
@@ -56121,24 +57050,33 @@ init_dist2();
56121
57050
  ShadowManager,
56122
57051
  StateStore,
56123
57052
  StaticPatterns,
57053
+ StepExecutor,
56124
57054
  SupermemoryAdapter,
56125
57055
  SwarmCoordinator,
56126
57056
  SwarmPatterns,
56127
57057
  TemplateRegistry,
57058
+ TemplateResolver,
56128
57059
  TracedError,
56129
57060
  WorkflowBuilder,
57061
+ WorkflowCompletionError,
56130
57062
  WorkflowRunner,
57063
+ WorkflowStepLifecycleExecutor,
56131
57064
  WorkflowTrajectory,
56132
57065
  benchmarkPatterns,
56133
57066
  brokerLog,
56134
57067
  buildBlockReason,
57068
+ buildCommand,
56135
57069
  buildModelSwitchCommand,
57070
+ checkExitCode,
57071
+ checkFileExists,
56136
57072
  checkForUpdates,
56137
57073
  checkForUpdatesInBackground,
57074
+ checkOutputContains,
56138
57075
  cleanLines,
56139
57076
  clearBinaryCache,
56140
57077
  clearResolveCache,
56141
57078
  collectCliSession,
57079
+ collectOutput,
56142
57080
  commandExists,
56143
57081
  connectionLog,
56144
57082
  countMessages,
@@ -56150,12 +57088,14 @@ init_dist2();
56150
57088
  createMemoryAdapter,
56151
57089
  createMemoryHooks,
56152
57090
  createMemoryService,
57091
+ createProcessSpawner,
56153
57092
  createRequestEnvelope,
56154
57093
  createRequestHandler,
56155
57094
  createTraceableError,
56156
57095
  createTrajectoryHooks,
56157
57096
  createWorkflowRenderer,
56158
57097
  customStepsFileExists,
57098
+ detectCompletion,
56159
57099
  estimateContextTokens,
56160
57100
  estimateTokens,
56161
57101
  executeApiStep,
@@ -56163,10 +57103,12 @@ init_dist2();
56163
57103
  findRelayPtyBinary,
56164
57104
  followLogs,
56165
57105
  formatDryRunReport,
57106
+ formatError,
56166
57107
  formatMessagePreview,
56167
57108
  formatProposalMessage,
56168
57109
  formatResultMessage,
56169
57110
  formatRunSummaryTable,
57111
+ formatStepOutput,
56170
57112
  generateAgentName,
56171
57113
  generateErrorId,
56172
57114
  generateRequestId,
@@ -56196,6 +57138,7 @@ init_dist2();
56196
57138
  hasRelayPtyBinary,
56197
57139
  hasUnreadMessages,
56198
57140
  inboxExists,
57141
+ interpolateStepTask,
56199
57142
  isAgentStep,
56200
57143
  isConsensusCommand,
56201
57144
  isCustomStep,
@@ -56228,15 +57171,28 @@ init_dist2();
56228
57171
  resolveCliSync,
56229
57172
  resolveCommand,
56230
57173
  resolveCustomStep,
57174
+ resolveDotPath,
56231
57175
  resolveSpawnPolicy,
57176
+ resolveStepOutputRef,
57177
+ resolveTemplate,
57178
+ resolveTemplateForShell,
57179
+ resolveVariables,
56232
57180
  routerLog,
57181
+ runVerification,
56233
57182
  runWorkflow,
57183
+ scrubForChannel,
57184
+ scrubSecrets,
57185
+ sendToChannel,
57186
+ shellEscape,
56234
57187
  spawnFromEnv,
57188
+ spawnProcess,
56235
57189
  stripAnsi,
56236
57190
  stripAnsiFast,
57191
+ stripInjectedTaskEcho,
56237
57192
  toReleaseResult,
56238
57193
  toSpawnResult,
56239
57194
  trackPatternPerformance,
57195
+ truncateMessage,
56240
57196
  unescapeFenceMarkersFast,
56241
57197
  validateCustomStepsUsage,
56242
57198
  validateModelForCli,