@bastani/atomic 0.9.18-alpha.2 → 0.9.18-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/builtin/intercom/CHANGELOG.md +8 -0
  3. package/dist/builtin/intercom/README.md +3 -3
  4. package/dist/builtin/intercom/broker/broker.ts +156 -12
  5. package/dist/builtin/intercom/broker/client.ts +89 -49
  6. package/dist/builtin/intercom/broker/pending-question-index.ts +10 -0
  7. package/dist/builtin/intercom/broker/send-handler.ts +32 -17
  8. package/dist/builtin/intercom/index.bundle.mjs +153 -50
  9. package/dist/builtin/intercom/package.json +1 -1
  10. package/dist/builtin/intercom/skills/intercom/SKILL.md +1 -1
  11. package/dist/builtin/intercom/types.ts +30 -2
  12. package/dist/builtin/mcp/package.json +1 -1
  13. package/dist/builtin/subagents/package.json +1 -1
  14. package/dist/builtin/web-access/package.json +1 -1
  15. package/dist/builtin/workflows/CHANGELOG.md +18 -0
  16. package/dist/builtin/workflows/README.md +11 -2
  17. package/dist/builtin/workflows/builtin/{chunk-ngffz3y8.js → chunk-fghhy2a5.js} +1 -1
  18. package/dist/builtin/workflows/builtin/{chunk-6v0yv8tj.js → chunk-h3r2vkzc.js} +1 -1
  19. package/dist/builtin/workflows/builtin/{chunk-brerg33r.js → chunk-n58a7v26.js} +0 -1
  20. package/dist/builtin/workflows/builtin/goal.js +2 -2
  21. package/dist/builtin/workflows/builtin/index.js +3 -3
  22. package/dist/builtin/workflows/builtin/ralph.js +2 -2
  23. package/dist/builtin/workflows/package.json +1 -1
  24. package/dist/builtin/workflows/src/extension/index.bundle.mjs +258 -49
  25. package/dist/builtin/workflows/src/index.js +35 -9
  26. package/docs/intercom.md +7 -5
  27. package/docs/models/artificial-analysis-index.md +2 -1
  28. package/docs/models/model-selection.md +19 -18
  29. package/docs/models/pareto-efficiency.md +36 -29
  30. package/docs/workflows.md +18 -9
  31. package/npm-shrinkwrap.json +32 -32
  32. package/package.json +3 -3
@@ -36322,7 +36322,6 @@ function compactStage(stage) {
36322
36322
  inputRequest,
36323
36323
  notices,
36324
36324
  mcpScope: _mcpScope,
36325
- pendingStageDeliveryAvailable: _pendingStageDeliveryAvailable,
36326
36325
  attemptedModels: _attemptedModels,
36327
36326
  modelAttempts: _modelAttempts,
36328
36327
  result: _result,
@@ -38144,6 +38143,31 @@ function effectiveWidth(width) {
38144
38143
  return chatWidth(width);
38145
38144
  }
38146
38145
 
38146
+ // dist/builtin/workflows/src/shared/pending-stage-status.ts
38147
+ function pendingStageTarget(runId, stage) {
38148
+ return "workflowGraphTarget" in stage ? stage.workflowGraphTarget : { runId, stageId: stage.id };
38149
+ }
38150
+ function pendingWorkflowStageStatus(run, stage, resolveOwningRunStatus) {
38151
+ if (stage.status !== "pending")
38152
+ return;
38153
+ const identity = pendingStageTarget(run.id, stage);
38154
+ const owningRunStatus = identity.runId === run.id ? run.status : resolveOwningRunStatus?.(identity.runId);
38155
+ const pendingStageDeliveryAvailable = owningRunStatus !== undefined && owningRunStatus !== "crashed" && !isTerminalRunStatus(owningRunStatus) && stage.pendingStageDeliveryAvailable === true;
38156
+ return {
38157
+ stageId: identity.stageId,
38158
+ name: stage.name,
38159
+ lifecycle: "pending",
38160
+ pendingStageDeliveryAvailable,
38161
+ ...pendingStageDeliveryAvailable ? { target: `${identity.runId}:${identity.stageId}` } : {}
38162
+ };
38163
+ }
38164
+ function pendingWorkflowStageStatuses(run, resolveOwningRunStatus) {
38165
+ return run.stages.flatMap((stage) => {
38166
+ const pending = pendingWorkflowStageStatus(run, stage, resolveOwningRunStatus);
38167
+ return pending === undefined ? [] : [pending];
38168
+ });
38169
+ }
38170
+
38147
38171
  // dist/builtin/workflows/src/tui/status-helpers.ts
38148
38172
  function statusColor(status, theme) {
38149
38173
  switch (status) {
@@ -38222,10 +38246,10 @@ function renderRunDetail(detail, opts = {}) {
38222
38246
  const now = opts.now ?? Date.now();
38223
38247
  const width = Math.max(32, opts.width ?? 80);
38224
38248
  if (opts.theme === undefined)
38225
- return renderPlain(detail, now, width);
38226
- return renderThemed(detail, now, opts.theme, width);
38249
+ return renderPlain(detail, now, width, opts.owningRunStatus);
38250
+ return renderThemed(detail, now, opts.theme, width, opts.owningRunStatus);
38227
38251
  }
38228
- function renderPlain(detail, now, width) {
38252
+ function renderPlain(detail, now, width, resolveOwningRunStatus) {
38229
38253
  const out = [];
38230
38254
  const stateBadge = stateLabel(detail);
38231
38255
  out.push(...renderIdentifierRows2(detail.runId, width - 2));
@@ -38244,7 +38268,7 @@ function renderPlain(detail, now, width) {
38244
38268
  out.push(" (no stages recorded yet) ");
38245
38269
  else
38246
38270
  for (const stage of detail.stages)
38247
- out.push(...renderStageRowsPlain(stage, now, width - 4));
38271
+ out.push(...renderStageRowsPlain(detail.runId, detail.status, stage, now, width - 4, resolveOwningRunStatus));
38248
38272
  out.push("");
38249
38273
  }
38250
38274
  if (tools.length > 0) {
@@ -38268,7 +38292,7 @@ function renderPlain(detail, now, width) {
38268
38292
  width
38269
38293
  });
38270
38294
  }
38271
- function renderThemed(detail, now, theme, width) {
38295
+ function renderThemed(detail, now, theme, width, resolveOwningRunStatus) {
38272
38296
  const out = [];
38273
38297
  const muted = hexToAnsi(theme.textMuted);
38274
38298
  const dim = hexToAnsi(theme.dim);
@@ -38290,7 +38314,7 @@ function renderThemed(detail, now, theme, width) {
38290
38314
  out.push(` ${dim}(no stages recorded yet)${RESET} `);
38291
38315
  else
38292
38316
  for (const stage of detail.stages)
38293
- out.push(...renderStageRowsThemed(stage, now, theme, width - 4));
38317
+ out.push(...renderStageRowsThemed(detail.runId, detail.status, stage, now, theme, width - 4, resolveOwningRunStatus));
38294
38318
  out.push("");
38295
38319
  }
38296
38320
  if (tools.length > 0) {
@@ -38383,16 +38407,37 @@ function stageLineThemed(stage, now, theme, width) {
38383
38407
  const durSeg = dur ? `${dim}${dur}${RESET}` : "";
38384
38408
  return truncateToWidth(`${iconFg}${icon}${RESET} ${text}${namePad}${RESET} ${stateFg}${statePad}${RESET}${activitySeg}${durSeg}`, width, "…");
38385
38409
  }
38386
- function renderStageRowsPlain(stage, now, width) {
38387
- const rows = [` ${stageLinePlain(stage, now, Math.max(1, width - 2))} `];
38410
+ function pendingStageRows(runId, runStatus, stage, width, theme, resolveOwningRunStatus) {
38411
+ const pending = pendingWorkflowStageStatus({ id: runId, status: runStatus }, stage, resolveOwningRunStatus);
38412
+ if (pending === undefined)
38413
+ return [];
38414
+ const value2 = pending.target ?? `${pending.stageId} · delivery unavailable`;
38415
+ const label = pending.target === undefined ? "pending id" : "pending target";
38416
+ const firstPrefix = ` ${pad(label, 16)}`;
38417
+ const continuationPrefix = " ".repeat(19);
38418
+ const wrapped = wrapIdentifierLines(value2, Math.max(1, width - 1), firstPrefix, continuationPrefix);
38419
+ if (theme === undefined)
38420
+ return wrapped.map(({ prefix, chunk }) => `${prefix}${chunk} `);
38421
+ const muted = hexToAnsi(theme.textMuted);
38422
+ const text = hexToAnsi(theme.text);
38423
+ return wrapped.map(({ prefix, chunk }, index) => index === 0 ? ` ${muted}${pad(label, 16)}${RESET}${text}${chunk}${RESET} ` : `${prefix}${text}${chunk}${RESET} `);
38424
+ }
38425
+ function renderStageRowsPlain(runId, runStatus, stage, now, width, resolveOwningRunStatus) {
38426
+ const rows = [
38427
+ ` ${stageLinePlain(stage, now, Math.max(1, width - 2))} `,
38428
+ ...pendingStageRows(runId, runStatus, stage, width, undefined, resolveOwningRunStatus)
38429
+ ];
38388
38430
  if (stage.error) {
38389
38431
  rows.push(` error ${truncateToWidth(stage.error.split(`
38390
38432
  `)[0] ?? "", Math.max(1, width - 10), "…")} `);
38391
38433
  }
38392
38434
  return rows;
38393
38435
  }
38394
- function renderStageRowsThemed(stage, now, theme, width) {
38395
- const rows = [` ${stageLineThemed(stage, now, theme, Math.max(1, width - 2))} `];
38436
+ function renderStageRowsThemed(runId, runStatus, stage, now, theme, width, resolveOwningRunStatus) {
38437
+ const rows = [
38438
+ ` ${stageLineThemed(stage, now, theme, Math.max(1, width - 2))} `,
38439
+ ...pendingStageRows(runId, runStatus, stage, width, theme, resolveOwningRunStatus)
38440
+ ];
38396
38441
  if (stage.error) {
38397
38442
  const errFg = hexToAnsi(theme.error);
38398
38443
  rows.push(` ${hexToAnsi(theme.textMuted)}error${RESET} ${errFg}${truncateToWidth(stage.error.split(`
@@ -38708,7 +38753,7 @@ function renderStatusList(runs, opts = {}) {
38708
38753
  for (let i = 0;i < sorted.length; i++) {
38709
38754
  if (i > 0)
38710
38755
  body.push("");
38711
- body.push(...renderRunEntry(sorted[i], now, cardWidth, opts.theme, opts.allRuns ?? runs, opts.indicatorStatuses));
38756
+ body.push(...renderRunEntry(sorted[i], now, cardWidth, opts.theme, opts.allRuns ?? runs, opts.indicatorStatuses, opts.owningRunStatus));
38712
38757
  }
38713
38758
  }
38714
38759
  if (opts.showDetailHint !== false && sorted.length > 0) {
@@ -38723,7 +38768,7 @@ function renderStatusList(runs, opts = {}) {
38723
38768
  width
38724
38769
  });
38725
38770
  }
38726
- function renderRunEntry(run, now, width, theme, allRuns, indicatorStatuses) {
38771
+ function renderRunEntry(run, now, width, theme, allRuns, indicatorStatuses, resolveOwningRunStatus) {
38727
38772
  const bodyWidth = effectiveWidth2(width);
38728
38773
  const interior = Math.max(8, bodyWidth - 4);
38729
38774
  const indicatorStatus = indicatorStatuses?.[run.id] ?? runIndicatorStatus(run, allRuns);
@@ -38762,7 +38807,56 @@ function renderRunEntry(run, now, width, theme, allRuns, indicatorStatuses) {
38762
38807
  const modeSeg = theme ? `${muted}${mode}${reset}` : mode;
38763
38808
  const metaSeg = theme ? `${dim}${meta}${reset}` : meta;
38764
38809
  const metaLine = ` ${modeSeg} ${strip}${" ".repeat(gap)}${metaSeg} `;
38765
- return [...identityRows, identity, metaLine];
38810
+ return [...identityRows, identity, metaLine, ...pendingStageLines(run, interior, theme, resolveOwningRunStatus)];
38811
+ }
38812
+ var MAX_PENDING_STAGE_ROWS = 3;
38813
+ function pendingStageIdentityLines(stage, width, suffix = "") {
38814
+ const full = ` pending: ${stage.name} (${stage.stageId})${suffix}`;
38815
+ if (visibleWidth(full) <= width)
38816
+ return [full];
38817
+ const labelledPrefix = " pending: ";
38818
+ const prefix = visibleWidth(labelledPrefix) < width ? labelledPrefix : width > 3 ? " " : "";
38819
+ const continuation = width > 3 ? " " : "";
38820
+ const rows = wrapIdentifierLines(stage.stageId, width, prefix, continuation).map(({ prefix: rowPrefix, chunk }) => `${rowPrefix}${chunk}`);
38821
+ if (suffix.length === 0)
38822
+ return rows;
38823
+ const last = rows.at(-1);
38824
+ if (visibleWidth(`${last}${suffix}`) <= width)
38825
+ rows[rows.length - 1] = `${last}${suffix}`;
38826
+ else
38827
+ rows.push(`${continuation}${suffix.trim()}`);
38828
+ return rows;
38829
+ }
38830
+ function pendingStageLines(run, width, theme, resolveOwningRunStatus) {
38831
+ const stages = pendingWorkflowStageStatuses(run, resolveOwningRunStatus);
38832
+ const visible = stages.slice(0, MAX_PENDING_STAGE_ROWS).flatMap((stage) => {
38833
+ const prefix = ` pending: ${stage.name} (${stage.stageId})`;
38834
+ if (stage.target === undefined) {
38835
+ const unavailable = `${prefix} · delivery unavailable`;
38836
+ if (visibleWidth(unavailable) <= width)
38837
+ return [pendingStageLine(unavailable, width, theme)];
38838
+ return [
38839
+ ...pendingStageIdentityLines(stage, width).map((line) => pendingStageLine(line, width, theme)),
38840
+ pendingStageLine(" delivery unavailable", width, theme)
38841
+ ];
38842
+ }
38843
+ const inline = `${prefix} → ${stage.target}`;
38844
+ if (visibleWidth(inline) <= width)
38845
+ return [pendingStageLine(inline, width, theme)];
38846
+ const labelRows = pendingStageIdentityLines(stage, width, " →").map((line) => pendingStageLine(line, width, theme));
38847
+ const targetRows = wrapIdentifierLines(stage.target, width, " ", " ").map(({ prefix: prefix2, chunk }) => pendingStageLine(`${prefix2}${chunk}`, width, theme));
38848
+ return [...labelRows, ...targetRows];
38849
+ });
38850
+ if (stages.length > MAX_PENDING_STAGE_ROWS) {
38851
+ const omitted = stages.length - MAX_PENDING_STAGE_ROWS;
38852
+ const line = truncateToWidth(` … ${omitted} more pending stage${omitted === 1 ? "" : "s"}`, width, ELLIPSIS);
38853
+ visible.push(theme === undefined ? line : `${hexToAnsi(theme.dim)}${line}${RESET}`);
38854
+ }
38855
+ return visible;
38856
+ }
38857
+ function pendingStageLine(line, width, theme) {
38858
+ const visible = truncateToWidth(line, width, ELLIPSIS);
38859
+ return theme === undefined ? visible : `${hexToAnsi(theme.textMuted)}${visible}${RESET}`;
38766
38860
  }
38767
38861
  function runAccent(run, theme, indicatorStatus) {
38768
38862
  if (!theme)
@@ -39188,7 +39282,12 @@ function renderChatSurfacePlainText(payload, options = {}) {
39188
39282
  `);
39189
39283
  }
39190
39284
  case "detail": {
39191
- const rendered = renderRunDetail(payload.detail, { width, now, ...themed });
39285
+ const rendered = renderRunDetail(payload.detail, {
39286
+ width,
39287
+ now,
39288
+ ...themed,
39289
+ owningRunStatus: (runId) => payload.owningRunStatuses?.[runId]
39290
+ });
39192
39291
  const lines = [
39193
39292
  rendered,
39194
39293
  `run id: ${payload.detail.runId}`,
@@ -39269,7 +39368,12 @@ function renderPayload(payload, theme, width, now) {
39269
39368
  case "list":
39270
39369
  return renderWorkflowList(payload.entries, { theme, width });
39271
39370
  case "detail":
39272
- return renderRunDetail(payload.detail, { theme, width, now });
39371
+ return renderRunDetail(payload.detail, {
39372
+ theme,
39373
+ width,
39374
+ now,
39375
+ owningRunStatus: (runId) => payload.owningRunStatuses?.[runId]
39376
+ });
39273
39377
  }
39274
39378
  }
39275
39379
 
@@ -48234,7 +48338,30 @@ function activeToolLabel(run) {
48234
48338
  const details = nodes.map((node) => `${node.name} · ${node.status}`).join(", ");
48235
48339
  return nodes.length === 1 ? details : `${nodes.length} tools · ${details}`;
48236
48340
  }
48237
- function metaLine(run, now) {
48341
+ var MAX_PENDING_WIDGET_ITEMS = 2;
48342
+ function pendingStageLabel(run, width = Number.POSITIVE_INFINITY) {
48343
+ const stages = pendingWorkflowStageStatuses(run);
48344
+ if (stages.length === 0)
48345
+ return;
48346
+ const maxItems = Math.min(MAX_PENDING_WIDGET_ITEMS, stages.length);
48347
+ for (let count = maxItems;count >= 1; count--) {
48348
+ let combinations = [[]];
48349
+ for (const stage of stages.slice(0, count)) {
48350
+ const exact = stage.target === undefined ? `${stage.name} (${stage.stageId}) · unavailable` : `${stage.name} (${stage.stageId}) → ${stage.target}`;
48351
+ const variants = stage.target === undefined ? [exact] : [exact, `${stage.name} · stage ${stage.stageId}`];
48352
+ combinations = combinations.flatMap((labels) => variants.map((variant) => [...labels, variant]));
48353
+ }
48354
+ for (const labels of combinations) {
48355
+ const omitted = stages.length - count;
48356
+ const visible = omitted > 0 ? [...labels, `… ${omitted} more`] : labels;
48357
+ const label = `pending: ${visible.join(", ")}`;
48358
+ if (visibleWidth(label) <= width)
48359
+ return label;
48360
+ }
48361
+ }
48362
+ return;
48363
+ }
48364
+ function metaLine(run, now, width = Number.POSITIVE_INFINITY) {
48238
48365
  if (run.endedAt !== undefined) {
48239
48366
  return elapsedLabel(run, now);
48240
48367
  }
@@ -48242,17 +48369,21 @@ function metaLine(run, now) {
48242
48369
  return "quit · resumable via /workflow resume";
48243
48370
  if (effectiveRunStatus(run) === "blocked")
48244
48371
  return "blocked · resumable via /workflow resume";
48245
- const parts = [modeLabel(run)];
48372
+ const prefix = [modeLabel(run)];
48246
48373
  const prog = progressLabel(run);
48247
48374
  if (prog)
48248
- parts.push(prog);
48375
+ prefix.push(prog);
48376
+ const suffix = [];
48249
48377
  const tools = activeToolLabel(run);
48250
48378
  if (tools)
48251
- parts.push(tools);
48379
+ suffix.push(tools);
48252
48380
  const elapsed = elapsedLabel(run, now);
48253
48381
  if (elapsed)
48254
- parts.push(elapsed);
48255
- return parts.join(" · ");
48382
+ suffix.push(elapsed);
48383
+ const otherParts = [...prefix, ...suffix];
48384
+ const pendingWidth = Math.max(0, width - otherParts.reduce((total, part) => total + visibleWidth(part), 0) - otherParts.length * 3);
48385
+ const pending = pendingStageLabel(run, pendingWidth);
48386
+ return [...prefix, ...pending === undefined ? [] : [pending], ...suffix].join(" · ");
48256
48387
  }
48257
48388
  function countBadges(counts, theme) {
48258
48389
  const badges = [];
@@ -48290,8 +48421,12 @@ function formatTitleBadges(badges, theme, themed) {
48290
48421
  const fallbackFg = hexToAnsi(theme.border);
48291
48422
  return badges.map((b) => `${b.fg ? hexToAnsi(b.fg) : fallbackFg}${b.text}${RESET}${fallbackFg}`).join(" ");
48292
48423
  }
48293
- function themedRunLines(run, now, theme, allRuns) {
48294
- const meta = metaLine(run, now);
48424
+ function runMetaWidth(run, width) {
48425
+ const inner = Math.max(2, Math.max(32, width) - 2);
48426
+ return Math.max(0, inner - visibleWidth(` ${run.name} · `));
48427
+ }
48428
+ function themedRunLines(run, now, theme, allRuns, width) {
48429
+ const meta = metaLine(run, now, runMetaWidth(run, width));
48295
48430
  const metaColor = effectiveRunStatus(run) === "running" ? theme.textMuted : theme.dim;
48296
48431
  return renderRunIdentityRows({
48297
48432
  runId: run.id,
@@ -48303,11 +48438,11 @@ function themedRunLines(run, now, theme, allRuns) {
48303
48438
  theme
48304
48439
  });
48305
48440
  }
48306
- function plainRunLines(run, now, allRuns) {
48441
+ function plainRunLines(run, now, allRuns, width) {
48307
48442
  return renderRunIdentityRows({
48308
48443
  runId: run.id,
48309
48444
  name: run.name,
48310
- meta: metaLine(run, now),
48445
+ meta: metaLine(run, now, runMetaWidth(run, width)),
48311
48446
  glyph: statusGlyph2(run, allRuns)
48312
48447
  });
48313
48448
  }
@@ -48362,7 +48497,7 @@ function buildThemedWidgetLines(snap, piTheme, width = 120, now = Date.now()) {
48362
48497
  const body = [];
48363
48498
  for (let i = 0;i < display.length; i++) {
48364
48499
  const run = display[i];
48365
- const runLines = themed ? themedRunLines(run, now, graphTheme, snap.runs) : plainRunLines(run, now, snap.runs);
48500
+ const runLines = themed ? themedRunLines(run, now, graphTheme, snap.runs, width) : plainRunLines(run, now, snap.runs, width);
48366
48501
  body.push(...runLines);
48367
48502
  if (i < display.length - 1)
48368
48503
  body.push("");
@@ -49341,6 +49476,7 @@ function encodeCheckpoint(checkpoint) {
49341
49476
  version: s.topology.version,
49342
49477
  stageId: s.topology.stageId,
49343
49478
  parentIds: [...s.topology.parentIds],
49479
+ ...s.topology.intercomGroup !== undefined ? { intercomGroup: s.topology.intercomGroup } : {},
49344
49480
  ...s.topology.sourceOrder !== undefined ? { sourceOrder: s.topology.sourceOrder } : {},
49345
49481
  ...s.topology.occurrenceKey !== undefined ? { occurrenceKey: s.topology.occurrenceKey } : {},
49346
49482
  ...s.topology.status !== undefined ? { status: s.topology.status } : {},
@@ -49473,7 +49609,7 @@ function stageTopology(value2) {
49473
49609
  if (typeof value2 !== "object" || value2 === null || Array.isArray(value2))
49474
49610
  return;
49475
49611
  const record = value2;
49476
- if (record.version !== DURABLE_STAGE_TOPOLOGY_VERSION || typeof record.stageId !== "string" || !isStringArray(record.parentIds) || !isOptionalSourceOrder(record.sourceOrder) || record.occurrenceKey !== undefined && typeof record.occurrenceKey !== "string" || record.status !== undefined && !isStageLifecycleStatus(record.status))
49612
+ if (record.version !== DURABLE_STAGE_TOPOLOGY_VERSION || typeof record.stageId !== "string" || !isStringArray(record.parentIds) || !isOptionalSourceOrder(record.sourceOrder) || record.intercomGroup !== undefined && typeof record.intercomGroup !== "string" || record.occurrenceKey !== undefined && typeof record.occurrenceKey !== "string" || record.status !== undefined && !isStageLifecycleStatus(record.status))
49477
49613
  return;
49478
49614
  const run = stageRunTopology(record.run);
49479
49615
  if (record.run !== undefined && run === undefined)
@@ -49485,6 +49621,7 @@ function stageTopology(value2) {
49485
49621
  version: DURABLE_STAGE_TOPOLOGY_VERSION,
49486
49622
  stageId: record.stageId,
49487
49623
  parentIds: record.parentIds,
49624
+ ...typeof record.intercomGroup === "string" ? { intercomGroup: record.intercomGroup } : {},
49488
49625
  ...typeof record.sourceOrder === "number" ? { sourceOrder: record.sourceOrder } : {},
49489
49626
  ...typeof record.occurrenceKey === "string" ? { occurrenceKey: record.occurrenceKey } : {},
49490
49627
  ...isStageLifecycleStatus(record.status) ? { status: record.status } : {},
@@ -54052,6 +54189,7 @@ function durableStageCheckpointMetadata(stage, run, sourceOrder) {
54052
54189
  version: DURABLE_STAGE_TOPOLOGY_VERSION,
54053
54190
  stageId: stage.id,
54054
54191
  parentIds: [...stage.parentIds],
54192
+ ...stage.intercomGroup !== undefined ? { intercomGroup: stage.intercomGroup } : {},
54055
54193
  ...stage.executionOrder !== undefined ? { order: stage.executionOrder } : {},
54056
54194
  ...sourceOrder !== undefined && sourceOrder >= 0 ? { sourceOrder } : {},
54057
54195
  ...stage.promptFootprint !== undefined ? { occurrenceKey: stage.id } : {},
@@ -54784,11 +54922,13 @@ function createDurableStagePrimitive(input) {
54784
54922
  const isMidSessionResume = session?.sessionFile !== undefined;
54785
54923
  const topology = activeStageTopology(input.backend, input.workflowId, replayKey);
54786
54924
  const durableStageId = topology?.stageId ?? pendingStageIdForReplay(input.backend, input.workflowId, replayKey, name);
54925
+ const durableIntercomGroup = topology?.intercomGroup ?? input.durableIntercomGroup?.(replayKey, durableStageId);
54787
54926
  const liveOptions = {
54788
54927
  ...options ?? {},
54789
54928
  durableReplayKey: replayKey,
54790
54929
  ...durableStageId !== undefined ? { durableStageId } : {},
54791
54930
  ...topology !== undefined ? { durableParentIds: [...topology.parentIds] } : {},
54931
+ ...durableIntercomGroup !== undefined ? { durableIntercomGroup } : {},
54792
54932
  ...isMidSessionResume ? {
54793
54933
  resumeFromSessionFile: session.sessionFile,
54794
54934
  durableAccumulatedDurationMs: session.durationMs ?? 0
@@ -54817,6 +54957,7 @@ function createDurableTaskPrimitive(input) {
54817
54957
  }
54818
54958
  const session = input.backend.getStageSession(input.workflowId, replayKey);
54819
54959
  const topology = activeStageTopology(input.backend, input.workflowId, replayKey);
54960
+ const durableIntercomGroup = topology?.intercomGroup ?? input.durableIntercomGroup?.(replayKey, topology?.stageId);
54820
54961
  const taskOptions = {
54821
54962
  ...options,
54822
54963
  durableReplayKey: replayKey,
@@ -54824,6 +54965,7 @@ function createDurableTaskPrimitive(input) {
54824
54965
  durableStageId: topology.stageId,
54825
54966
  durableParentIds: [...topology.parentIds]
54826
54967
  } : {},
54968
+ ...durableIntercomGroup !== undefined ? { durableIntercomGroup } : {},
54827
54969
  ...session?.sessionFile !== undefined ? {
54828
54970
  resumeFromSessionFile: session.sessionFile,
54829
54971
  durableAccumulatedDurationMs: session.durationMs ?? 0
@@ -55486,6 +55628,7 @@ function appendStageStart(api, payload) {
55486
55628
  name: payload.name,
55487
55629
  parentIds: [...payload.parentIds],
55488
55630
  ...payload.model !== undefined ? { model: payload.model } : {},
55631
+ ...payload.intercomGroup !== undefined ? { intercomGroup: payload.intercomGroup } : {},
55489
55632
  ...payload.pendingStageDeliveryAvailable !== undefined ? { pendingStageDeliveryAvailable: payload.pendingStageDeliveryAvailable } : {},
55490
55633
  ...payload.replayKey !== undefined ? { replayKey: payload.replayKey } : {},
55491
55634
  ...payload.replayedFromStageId !== undefined ? { replayedFromStageId: payload.replayedFromStageId } : {},
@@ -56030,6 +56173,7 @@ function installCompactionHook(api, store2) {
56030
56173
  stageId: stage.id,
56031
56174
  name: stage.name,
56032
56175
  parentIds: [...stage.parentIds],
56176
+ intercomGroup: stage.intercomGroup,
56033
56177
  pendingStageDeliveryAvailable: stage.pendingStageDeliveryAvailable,
56034
56178
  ts: stage.startedAt ?? now
56035
56179
  });
@@ -57157,7 +57301,9 @@ function fallbackRunDetailFromResult(workflowName, inputs, result) {
57157
57301
  function emitTerminalRunDetailSurface(pi, workflowName, inputs, result) {
57158
57302
  const inspected = inspectRun(result.runId);
57159
57303
  const detail = inspected.ok ? inspected.detail : fallbackRunDetailFromResult(workflowName, inputs, result);
57160
- emitChatSurface(pi, { kind: "detail", detail }, { content: renderRunDetail(detail, { width: 100 }) });
57304
+ const owningRunStatuses = Object.fromEntries(store.graphSnapshot().runs.map((run) => [run.id, run.status]));
57305
+ const owningRunStatus = (runId) => owningRunStatuses[runId];
57306
+ emitChatSurface(pi, { kind: "detail", detail, owningRunStatuses }, { content: renderRunDetail(detail, { width: 100, owningRunStatus }) });
57161
57307
  }
57162
57308
  function formatWorkflowResourceLoadWarning(error) {
57163
57309
  const message = error instanceof Error ? error.message : String(error);
@@ -69037,18 +69183,28 @@ function resolveStageGroup(stageOptions, workflowGroup) {
69037
69183
  const group = stageOptions.group;
69038
69184
  if (group === undefined)
69039
69185
  return workflowGroup;
69040
- if (group === true)
69041
- return randomUUID5();
69042
- const trimmed = group.trim();
69043
- return trimmed.length > 0 ? trimmed : undefined;
69186
+ const authored = group === true ? randomUUID5() : group.trim();
69187
+ if (authored.length === 0)
69188
+ return;
69189
+ if (workflowGroup === undefined || authored === DEFAULT_INTERCOM_GROUP)
69190
+ return authored;
69191
+ const owner2 = normalizeGroup(workflowGroup);
69192
+ if (authored === owner2 || authored.startsWith(`${owner2}/`))
69193
+ return authored;
69194
+ return `${owner2}/${authored}`;
69195
+ }
69196
+ function workflowInvocationOwnsGroup(workflowGroup, candidate) {
69197
+ if (workflowGroup === undefined || candidate === undefined)
69198
+ return false;
69199
+ const owner2 = normalizeGroup(workflowGroup);
69200
+ const group = normalizeGroup(candidate);
69201
+ return group === owner2 || group.startsWith(`${owner2}/`);
69044
69202
  }
69045
69203
  function stageHasIntercomAccess(_stageOptions) {
69046
69204
  return true;
69047
69205
  }
69048
69206
  function stageCanUseWorkflowPendingStageRoute(stageOptions, workflowGroup) {
69049
- if (!stageHasIntercomAccess(stageOptions) || stageOptions?.group === true)
69050
- return false;
69051
- return normalizeGroup(resolveStageGroup(stageOptions, workflowGroup)) === normalizeGroup(workflowGroup);
69207
+ return stageHasIntercomAccess(stageOptions) && workflowInvocationOwnsGroup(workflowGroup, resolveStageGroup(stageOptions, workflowGroup));
69052
69208
  }
69053
69209
 
69054
69210
  // dist/builtin/workflows/src/shared/budget-meter.ts
@@ -73200,6 +73356,7 @@ function stripWorkflowOnlyOptions(options, defaultSessionDir, meta2, pendingStag
73200
73356
  durableReplayKey: _durableReplayKey,
73201
73357
  durableAccumulatedDurationMs: _durableAccumulatedDurationMs,
73202
73358
  durableStageId: _durableStageId,
73359
+ durableIntercomGroup: _durableIntercomGroup,
73203
73360
  durableParentIds: _durableParentIds,
73204
73361
  sessionDir,
73205
73362
  gitWorktreeDir: _gitWorktreeDir,
@@ -75322,15 +75479,18 @@ function createWorkflowStageFactory(input) {
75322
75479
  const replaySource = replayDecision.kind === "replay" ? replayDecision.source : undefined;
75323
75480
  const executeReplaySource = replayDecision.kind === "execute" ? replayDecision.source : undefined;
75324
75481
  const shouldReplay = replaySource !== undefined;
75325
- const stageOptionsForContext = executeReplaySource?.sessionFile === undefined ? options : {
75482
+ const replayStageOptions = executeReplaySource?.sessionFile === undefined ? options : {
75326
75483
  ...options ?? {},
75327
75484
  context: options?.context ?? "fork",
75328
75485
  forkFromSessionFile: options?.forkFromSessionFile ?? executeReplaySource.sessionFile
75329
75486
  };
75487
+ const intercomGroup = options?.durableIntercomGroup ?? resolveStageGroup(replayStageOptions, input.workflowIntercomGroup);
75488
+ const stageOptionsForContext = replayStageOptions?.group === undefined || intercomGroup === undefined ? replayStageOptions : { ...replayStageOptions, group: intercomGroup };
75330
75489
  const pendingStageDeliveryAvailable = stageCanUseWorkflowPendingStageRoute(stageOptionsForContext, input.workflowIntercomGroup);
75331
75490
  const stageSnapshot = {
75332
75491
  id: stageId,
75333
75492
  name,
75493
+ ...intercomGroup === undefined ? {} : { intercomGroup },
75334
75494
  replayKey,
75335
75495
  status: shouldReplay ? "completed" : "pending",
75336
75496
  parentIds: Object.freeze(parentIds),
@@ -75529,6 +75689,7 @@ function createWorkflowStageFactory(input) {
75529
75689
  name,
75530
75690
  parentIds: stageSnapshot.parentIds,
75531
75691
  ...stageReplayFields(stageSnapshot),
75692
+ ...intercomGroup === undefined ? {} : { intercomGroup },
75532
75693
  pendingStageDeliveryAvailable,
75533
75694
  ts: stageSnapshot.startedAt ?? Date.now()
75534
75695
  });
@@ -76210,11 +76371,16 @@ async function run(def, inputs, opts = {}) {
76210
76371
  completedStageReplayKeys,
76211
76372
  sourceToReplayedNodeIds: sourceToContinuationNodeIds
76212
76373
  });
76374
+ const durableIntercomGroup = (replayKey, stageId) => {
76375
+ const stages = activeStore.runs().find((candidate) => candidate.id === runId)?.stages ?? [];
76376
+ return stages.find((stage) => stageId !== undefined && stage.id === stageId || stage.replayKey === replayKey)?.intercomGroup;
76377
+ };
76213
76378
  let observedTaskTailQuit;
76214
76379
  const durableTask = createDurableTaskPrimitive({
76215
76380
  workflowId: runId,
76216
76381
  backend: durableBackend,
76217
76382
  nextReplayKey: (stageName3) => stageReplayKeyGenerator(stageName3),
76383
+ durableIntercomGroup,
76218
76384
  task: taskRunners.task,
76219
76385
  recordCachedTask: cachedStage.record,
76220
76386
  signal: ownController.signal,
@@ -76263,6 +76429,7 @@ async function run(def, inputs, opts = {}) {
76263
76429
  workflowId: runId,
76264
76430
  backend: durableBackend,
76265
76431
  nextReplayKey: (stageName3) => stageReplayKeyGenerator(stageName3),
76432
+ durableIntercomGroup,
76266
76433
  recordCachedStage: cachedStage.record,
76267
76434
  stage: (name, options, replayKey) => {
76268
76435
  const stage = runtime.stage(name, options);
@@ -79172,7 +79339,15 @@ function registerPendingStageIntercomBridge(pi, activeStore) {
79172
79339
  pi.events?.emit?.(PENDING_STAGE_ROUTE_EVENT, {
79173
79340
  runId: run2.id,
79174
79341
  group: workflowInvocationIntercomGroup(rootRunId),
79175
- capability: workflowPendingStageRouteCapability(activeStore, run2.id)
79342
+ capability: workflowPendingStageRouteCapability(activeStore, run2.id),
79343
+ stages: run2.stages.filter((stage) => stage.pendingStageDeliveryAvailable === true && (stage.status === "pending" || stage.status === "running" || stage.status === "awaiting_input" || stage.status === "paused" || stage.status === "blocked")).map((stage) => ({
79344
+ stageId: stage.id,
79345
+ stageName: stage.name,
79346
+ target: `${run2.id}:${stage.id}`,
79347
+ lifecycle: stage.sessionId === undefined && stage.sessionFile === undefined ? "pending" : "running",
79348
+ routeEligible: true,
79349
+ group: stage.intercomGroup ?? workflowInvocationIntercomGroup(rootRunId)
79350
+ }))
79176
79351
  });
79177
79352
  }
79178
79353
  sweepPromise = sweepPromise.then(() => settleUndeliverablePendingStageMessages(activeStore, notifyUndeliverable)).then(() => {
@@ -79268,7 +79443,8 @@ async function queueAndPersist(activeStore, event, runGroup, pendingStageDeliver
79268
79443
  const backend = durableBackendForRun(rootBackend, activeStore.runs(), event.runId);
79269
79444
  if (backend === undefined)
79270
79445
  return { outcome: "refused", reason: "Session not found" };
79271
- const result = await activeStore.queueStageMessage(request, event.from.group, runGroup, backend);
79446
+ const senderGroup = event.from.groups?.includes(runGroup) === true ? runGroup : event.from.group;
79447
+ const result = await activeStore.queueStageMessage(request, senderGroup, runGroup, backend);
79272
79448
  if (result === undefined)
79273
79449
  return { outcome: "refused", reason: "Session not found" };
79274
79450
  if (!result.ok) {
@@ -81642,7 +81818,8 @@ Available: ${formatAvailableWorkflowNames(deps.runtimeProxy.registry.names())}`)
81642
81818
  const inspected = inspectRun(resolved.runId, { toolControlRegistry });
81643
81819
  if (!inspected.ok)
81644
81820
  return fail(`Run not found: ${target}`);
81645
- emitChatSurface(pi, { kind: "detail", detail: inspected.detail });
81821
+ const owningRunStatuses = Object.fromEntries(store.graphSnapshot().runs.map((run2) => [run2.id, run2.status]));
81822
+ emitChatSurface(pi, { kind: "detail", detail: inspected.detail, owningRunStatuses });
81646
81823
  return;
81647
81824
  }
81648
81825
  const capturedRuns = store.graphSnapshot().runs;
@@ -81861,6 +82038,7 @@ function summarizeRunSnapshot(run2, now = Date.now(), options) {
81861
82038
  name: stage.name,
81862
82039
  status: stage.status
81863
82040
  })),
82041
+ pendingStages: pendingWorkflowStageStatuses(run2, options?.owningRunStatus),
81864
82042
  tools: (run2.toolNodes ?? []).map((tool) => {
81865
82043
  const owner2 = tool;
81866
82044
  return {
@@ -82056,6 +82234,7 @@ function compactWorkflowToolMessage(result) {
82056
82234
  return `${result.action}:${target ? ` ${target}` : ""} ${result.status} — ${result.message}`;
82057
82235
  }
82058
82236
  var STATUS_MESSAGE_CHAR_LIMIT = 120;
82237
+ var STATUS_PENDING_STAGE_LIMIT = 10;
82059
82238
  function truncateStatusText(text) {
82060
82239
  const flattened = text.replace(/\s+/g, " ").trim();
82061
82240
  return flattened.length > STATUS_MESSAGE_CHAR_LIMIT ? `${flattened.slice(0, STATUS_MESSAGE_CHAR_LIMIT - 1)}…` : flattened;
@@ -82093,6 +82272,9 @@ function statusAwaitingInputLine(entry) {
82093
82272
  const message = entry.message !== undefined ? ` — "${truncateStatusText(entry.message)}"` : "";
82094
82273
  return ` awaiting input: ${target}${prompt}${message}`;
82095
82274
  }
82275
+ function statusPendingStageLine(stage) {
82276
+ return ` pending stage: ${stage.name} (${stage.stageId}) lifecycle=${stage.lifecycle} pendingStageDeliveryAvailable=${stage.pendingStageDeliveryAvailable} Intercom target=${stage.target ?? "unavailable"}`;
82277
+ }
82096
82278
  function statusRunIcon(run2, snapshot, allRuns) {
82097
82279
  if (snapshot === undefined)
82098
82280
  return statusIcon(run2.status);
@@ -82127,8 +82309,15 @@ function renderStatusToolContent(result) {
82127
82309
  lines.push(` runId: ${run2.runId}`);
82128
82310
  for (const entry of run2.awaitingInput)
82129
82311
  lines.push(statusAwaitingInputLine(entry));
82312
+ for (const stage of run2.pendingStages.slice(0, STATUS_PENDING_STAGE_LIMIT)) {
82313
+ lines.push(statusPendingStageLine(stage));
82314
+ }
82315
+ if (run2.pendingStages.length > STATUS_PENDING_STAGE_LIMIT) {
82316
+ const omitted = run2.pendingStages.length - STATUS_PENDING_STAGE_LIMIT;
82317
+ lines.push(` … ${omitted} more pending stage${omitted === 1 ? "" : "s"}; use status with runId`);
82318
+ }
82130
82319
  });
82131
- lines.push("hint: status with runId returns full run detail; workflow answer answers pending prompts using runId/stageId/promptId; workflow resume controls paused runs; pause/interrupt/quit also accept runId. Ordinary Intercom handles free-form workflow-stage communication at <runId>:<stageKey>: live delivery is immediate, known unstarted stages queue before their first model turn. Use Intercom ask once a reply-capable live session exists.");
82320
+ lines.push("hint: status with runId returns full run detail; workflow answer answers pending prompts using runId/stageId/promptId; workflow resume controls paused runs; pause/interrupt/quit also accept runId. Ordinary Intercom handles free-form workflow-stage communication at <runId>:<stageKey>: live stage delivery is immediate; a known pending stage `send` queues before its first model turn; `ask` requires a live reply-capable stage.");
82132
82321
  return lines.join(`
82133
82322
  `);
82134
82323
  }
@@ -83119,11 +83308,23 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
83119
83308
  const durable = await awaitRequest(getRuntime().inspectDurableWorkflow(target));
83120
83309
  return durable.kind === "found" ? { action: "statusDetail", runId: target, detail: durable.detail } : { action: "statusDetail", runId: target, error: durable.message };
83121
83310
  }
83122
- const result2 = inspectRun(resolved.runId, { toolControlRegistry });
83123
- return result2.ok ? { action: "statusDetail", runId: result2.runId, detail: result2.detail } : { action: "statusDetail", runId: target, error: `run not found: ${target}` };
83311
+ const inspected = inspectRun(resolved.runId, { toolControlRegistry });
83312
+ if (!inspected.ok) {
83313
+ return { action: "statusDetail", runId: target, error: `run not found: ${target}` };
83314
+ }
83315
+ const detailResult = {
83316
+ action: "statusDetail",
83317
+ runId: inspected.runId,
83318
+ detail: inspected.detail
83319
+ };
83320
+ setWorkflowStatusRenderRuns(detailResult, store.graphSnapshot().runs);
83321
+ return detailResult;
83124
83322
  }
83323
+ const capturedRuns = store.graphSnapshot().runs;
83324
+ const statusByRunId = new Map(capturedRuns.map((run2) => [run2.id, run2.status]));
83125
83325
  const listing = buildWorkflowStatusListing(topLevelExpandedSnapshots(), args.statusFilter ?? "all", Date.now(), {
83126
- toolControlRegistry
83326
+ toolControlRegistry,
83327
+ owningRunStatus: (owningRunId) => statusByRunId.get(owningRunId)
83127
83328
  });
83128
83329
  const result = {
83129
83330
  action: "status",
@@ -83131,7 +83332,7 @@ function makeExecuteWorkflowTool(runtime, reloadWorkflowResources, ensureWorkflo
83131
83332
  runs: listing.runs,
83132
83333
  snapshots: listing.snapshots
83133
83334
  };
83134
- setWorkflowStatusRenderRuns(result, store.graphSnapshot().runs);
83335
+ setWorkflowStatusRenderRuns(result, capturedRuns);
83135
83336
  return result;
83136
83337
  }
83137
83338
  case "stages":
@@ -83306,11 +83507,14 @@ function renderResult(result, opts) {
83306
83507
  }
83307
83508
  case "status": {
83308
83509
  const r = result;
83510
+ const allRuns = opts?.allRuns ?? getWorkflowStatusRenderRuns(r) ?? r.snapshots;
83511
+ const statusByRunId = new Map(allRuns.map((run2) => [run2.id, run2.status]));
83309
83512
  return renderStatusList(r.snapshots, {
83310
83513
  theme: themed ? deriveGraphTheme({}) : undefined,
83311
83514
  width: opts?.width,
83312
83515
  now: opts?.now,
83313
- allRuns: opts?.allRuns ?? getWorkflowStatusRenderRuns(r) ?? r.snapshots
83516
+ allRuns,
83517
+ owningRunStatus: (runId) => statusByRunId.get(runId)
83314
83518
  });
83315
83519
  }
83316
83520
  case "statusDetail": {
@@ -83319,10 +83523,13 @@ function renderResult(result, opts) {
83319
83523
  return renderNotice("WORKFLOW STATUS", `id=${r2.runId}: ${r2.error}`, opts, themed);
83320
83524
  }
83321
83525
  const r = result;
83526
+ const allRuns = opts?.allRuns ?? getWorkflowStatusRenderRuns(r);
83527
+ const statusByRunId = new Map(allRuns?.map((run2) => [run2.id, run2.status]) ?? []);
83322
83528
  return renderRunDetail(r.detail, {
83323
83529
  theme: themed ? deriveGraphTheme({}) : undefined,
83324
83530
  width: opts?.width,
83325
- now: opts?.now
83531
+ now: opts?.now,
83532
+ owningRunStatus: (runId) => statusByRunId.get(runId)
83326
83533
  });
83327
83534
  }
83328
83535
  case "inputs": {
@@ -83493,8 +83700,10 @@ var DEFAULT_PROMPT_GUIDANCE = [
83493
83700
  `**Workflow authoring and handoffs**:
83494
83701
  - When a user asks to create or edit a workflow, clarify only unresolved requirements that materially affect its purpose, inputs, stages, handoffs, validation, success criteria, or starter pattern. Read the workflow docs/examples, implement the TypeScript definition with normal coding tools, reload it, and run representative test inputs before presenting it. Use the create-spec skill when it adds value; it is not mandatory when context is already sufficient.
83495
83702
  - After creating and reloading a newly authored custom workflow, close the loop by stating the folder containing the workflow file just written, for example \`.atomic/workflows/\`, in this shape: \`Custom workflow created. You can inspect its code at: <workflow-folder-path>\`. Do this only for newly created custom workflows, never builtin or pre-existing workflows.
83496
- - Keep a small, readable workflow in one entry file. Do not split short one-use prompts, create one file per stage, add wrapper-only modules, hide the graph across files, or use line counts alone as a module boundary.
83703
+ - Keep a small, readable workflow in one entry file and write it for human maintainers. Keep the graph and control flow visible in the top-level workflow entry file, use stage names that state each stage's responsibility, and make its inputs, outputs, evidence, and success contract explicit. A developer reading the entry file from top to bottom should be able to identify the graph, branches, gates, artifacts, and stop conditions. Avoid both monolithic prompt blobs and gratuitous fragmentation. Do not split short one-use prompts, create one file per stage, add wrapper-only modules, hide the graph across files, or use line counts alone as a module boundary.
83497
83704
  - When a meaningful source boundary improves clarity, reuse, ownership, or testability, keep the graph and control flow in the top-level workflow entry file and extract cohesive concerns such as long or reused prompt builders, shared TypeBox schemas and workflow-specific types, model-policy constants shared by several stages, deterministic helpers with their own testable behavior, or reusable child workflow definitions into a subdirectory below the top-level discovery directory — either one owned by a single workflow or a shared support directory. Project and user discovery scans only top-level \`.ts\`/\`.js\`/\`.mjs\`/\`.cjs\` files in the workflow directory, so those support modules are not scanned as extra top-level workflow candidates; use \`.js\` import extensions from TypeScript source.
83705
+ - Evaluate Atomic extension hooks when a workflow needs fine-grained, cross-cutting tool or session event control. Workflow TypeScript owns the inspectable DAG, stages, handoffs, durable \`ctx.tool\` side effects, and gates; extension hooks own cross-cutting session and model-tool policy such as \`tool_call\` interception, input mutation, or blocking, \`tool_result\` transformation, context and provider hooks, lifecycle observation, or reusable custom tools. Use hooks only when cross-stage or cross-workflow event control is materially clearer than embedding the policy in each stage; do not prescribe a companion extension for ordinary workflow logic. Consult \`packages/coding-agent/docs/extensions.md#events\` for the authoritative hook contracts.
83706
+ - When a workflow depends on a companion extension, make the dependency explicit, package and document it with the workflow, include any extension-provided custom tools in stage \`tools\` allowlists, and document hook-driven behavior so the workflow remains inspectable.
83498
83707
  - When creating or editing a workflow that pins an explicit stage \`model\` or \`fallbackModels\`, consult \`packages/coding-agent/docs/models/model-selection.md\` for role-based recommendations, treating benchmark thinking levels as measurement configurations rather than universal workflow defaults, then call \`workflow({ action: "models" })\` to see the models actually present in the user's configured catalog. Use only the catalog's returned \`fullId\` values as model strings, and append a thinking suffix only when that exact level appears in the entry's \`availableThinkingLevels\`; apply the stage role and failure-cost policy independently to the primary and every fallback; treat an absent or empty \`availableThinkingLevels\` as no suffix support rather than inferring one. If a guide-recommended model for the role is unavailable, try another guide-recommended model that is present in the catalog. If the selected model does not support the role's level, choose another catalog model that does or leave the stage unpinned rather than inventing or silently promoting a level. An explicit user request for a level overrides the role default, but never fabricate an unsupported catalog level. If no recommendation intersects with the catalog, leave the stage unpinned rather than inventing a substitute, and mention the limitation, asking the user only if the workflow requires an explicit model choice. If the catalog is empty, continue with unpinned stages, state that no configured models were returned, and do not fabricate model IDs. Do not inspect or infer credentials, environment variables, auth files, token validity, entitlements, or the reason a model is absent; \`isCurrent\` marks the active selection, not a quality recommendation.
83499
83708
  - Consult docs/workflows.md and its starter patterns (Classify-and-act, Fan-out-and-synthesize, Adversarial verification, Generate-and-filter, Tournament, Loop until done, and Stacked implementation slices) when designing a stage graph.
83500
83709
  - Treat workflow composition as a first-class authoring option. Before duplicating stages, inspect reusable workflow modules and builtin exports; import their definitions and invoke them with \`ctx.workflow(...)\`, mapping typed inputs and consuming only declared outputs. Nested workflows can themselves import children, so combine small reusable graphs into a richer parent while respecting \`maxDepth\`.
@@ -83505,7 +83714,7 @@ var DEFAULT_PROMPT_GUIDANCE = [
83505
83714
  - Cyclic workflow graphs are unsupported. Workflow authors and coding agents MUST NOT create self-edges or dependency edges from the current frontier to an existing ancestor. Every materialized execution topology must remain a DAG. Redesign or stop before launch if a cycle cannot be removed.
83506
83715
  - Bounded loops must create distinct tracked work for every iteration; never reopen an ancestor below its downstream work. Stacked implementation slices are unrolled, not looped: each slice gets a fresh child boundary and distinct tracked nodes, and no slice may add an edge back to the current frontier, itself, or an ancestor. If a retained session receives follow-up without new dependency work, keep it as non-topological activity metadata rather than adding a back-edge. Before launch, sketch nodes and dependencies for every branch and loop and reject any proposed parent edge to the node itself or an ancestor.
83507
83716
  - Treat dynamic graph validation during execution, replay, and DBOS hydration as the authoritative cycle boundary. If runtime topology code changes, require incremental edge checks and DBOS hydration validation; prompt guidance and TypeScript types cannot replace those runtime checks.
83508
- - Every workflow invocation automatically receives one stable, non-default Intercom group named \`workflow:<rootRunId>\`. Every model stage inherits it because ordinary \`intercom\` is mandatory even under tool and extension restrictions; nested workflows keep the top-level invocation group, and subagents inherit their launching stage's group. Do not mint or thread group names through ordinary workflow definitions. Use an explicit \`group\` only for an intentional override: a named group or \`group: true\` creates a subgroup, while \`group: "default"\` opts into the shared default group. \`contact_supervisor\` still crosses group boundaries only for authorized subagent escalation.
83717
+ - Every workflow invocation receives the stable control group \`workflow:<rootRunId>\`. Stages inherit it unless an intentional explicit group is authored. Named groups and \`group: true\` become invocation-owned subgroups under \`workflow:<rootRunId>/...\`, so repeated names cannot collide across runs. The invocation context may list and exactly send/ask live stages in its owned subgroups and queue send to known pending stages; this authority is directional and does not let subgroup siblings see or reach each other. Pending ask remains unsupported. \`group: "default"\` is the explicit non-owned shared-group escape and does not receive pending invocation routing. Do not mint root group names manually.
83509
83718
  - Prefer \`ctx.tool(name, args, fn)\` for workflow-owned TypeScript operations with side effects, such as filesystem writes, network mutations, and external API actions. It creates a tracked, non-attachable durable graph node before invoking \`fn\`; it may be used before, between, after, or without model stages. A completed \`ctx.tool\` call is durably checkpointed with its serializable result, so resume replays that result without rerunning \`fn\`. For checks that may fail during a bounded repair loop, opt into \`failureMode: "return"\`, branch on the typed outcome, and pass only the needed error fields to the repair stage or artifact yourself; Atomic does not inject failure evidence into later prompts. Retries do not bound a hung callback, so every \`ctx.tool\` callback that starts a child process or performs network I/O MUST set an explicit positive finite \`timeoutMs\` and forward the supplied \`signal\` to cancellable work. A timeout applies per attempt, aborts that attempt's signal, and gives retries a fresh deadline and signal. Cancellation and storage faults still throw. Keep pure computation and side-effect-free transformations as ordinary TypeScript. Do not wrap agent-stage internals or every function call indiscriminately; this rule applies to side effects orchestrated directly by the workflow definition.
83510
83719
  - Pass large stage context through files/artifacts and \`reads\` with an explicit \`Read the file at <path>...\` prompt rather than large \`previous\` payloads or injected session history.
83511
83720
  - Wrap critical stage-prompt content in \`<keepContext>\` / \`</keepContext>\`. Tagged content survives compression verbatim regardless of the compression ratio, and every line of the span including the tag lines is protected. A long-running stage will be compacted, and compaction ranks lines individually: an objective is verbose and restated while the constraint that narrows it is usually one line, so the constraint is the cheaper deletion and what survives reads as broader permission than intended. Tag role constraints that bound a stage to part of the work, acceptance criteria and immutable contracts, explicit prohibitions, and identifiers a stage must not lose such as a target branch, worktree path, or run ID. Do not tag bulk context: protected lines count against the keep target rather than raising it, so a large protected span makes the surrounding transcript compress harder — tag the constraint, not the material it applies to.