@bastani/atomic 0.8.21 → 0.8.22-0

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 (235) hide show
  1. package/CHANGELOG.md +40 -9
  2. package/dist/builtin/intercom/broker/broker.ts +3 -3
  3. package/dist/builtin/intercom/config.ts +3 -3
  4. package/dist/builtin/intercom/index.ts +1 -1
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/intercom/ui/compose.ts +2 -2
  7. package/dist/builtin/mcp/host-html-template.ts +0 -3
  8. package/dist/builtin/mcp/package.json +1 -1
  9. package/dist/builtin/subagents/CHANGELOG.md +13 -4
  10. package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
  11. package/dist/builtin/subagents/agents/debugger.md +6 -6
  12. package/dist/builtin/subagents/package.json +1 -1
  13. package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
  14. package/dist/builtin/subagents/skills/browser-use/SKILL.md +234 -0
  15. package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +76 -0
  16. package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +92 -0
  17. package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
  18. package/dist/builtin/subagents/src/agents/skills.ts +19 -1
  19. package/dist/builtin/subagents/src/extension/index.ts +24 -22
  20. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +7 -1
  21. package/dist/builtin/subagents/src/runs/background/async-execution.ts +23 -7
  22. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +98 -3
  23. package/dist/builtin/subagents/src/runs/background/async-status.ts +3 -1
  24. package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -1
  25. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +3 -0
  26. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +37 -12
  27. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +15 -15
  28. package/dist/builtin/subagents/src/runs/foreground/execution.ts +26 -2
  29. package/dist/builtin/subagents/src/runs/shared/nested-render.ts +1 -1
  30. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +7 -0
  31. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +28 -1
  32. package/dist/builtin/subagents/src/shared/fast-mode.ts +80 -0
  33. package/dist/builtin/subagents/src/shared/formatters.ts +4 -2
  34. package/dist/builtin/subagents/src/shared/types.ts +4 -2
  35. package/dist/builtin/subagents/src/shared/utils.ts +3 -61
  36. package/dist/builtin/subagents/src/tui/render.ts +303 -157
  37. package/dist/builtin/web-access/package.json +1 -1
  38. package/dist/builtin/workflows/CHANGELOG.md +95 -35
  39. package/dist/builtin/workflows/README.md +228 -41
  40. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +535 -541
  41. package/dist/builtin/workflows/builtin/goal.ts +39 -25
  42. package/dist/builtin/workflows/builtin/open-claude-design.ts +66 -69
  43. package/dist/builtin/workflows/builtin/ralph.ts +21 -21
  44. package/dist/builtin/workflows/package.json +6 -5
  45. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
  46. package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +2 -2
  47. package/dist/builtin/workflows/src/extension/discovery.ts +25 -146
  48. package/dist/builtin/workflows/src/extension/dispatcher.ts +72 -24
  49. package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +363 -0
  50. package/dist/builtin/workflows/src/extension/index.ts +690 -352
  51. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +99 -62
  52. package/dist/builtin/workflows/src/extension/render-call.ts +2 -1
  53. package/dist/builtin/workflows/src/extension/render-result.ts +9 -3
  54. package/dist/builtin/workflows/src/extension/renderers.ts +5 -3
  55. package/dist/builtin/workflows/src/extension/runtime.ts +68 -33
  56. package/dist/builtin/workflows/src/extension/status-writer.ts +1 -1
  57. package/dist/builtin/workflows/src/extension/wiring.ts +34 -13
  58. package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +142 -0
  59. package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -4
  60. package/dist/builtin/workflows/src/index.ts +2 -0
  61. package/dist/builtin/workflows/src/intercom/result-intercom.ts +1 -1
  62. package/dist/builtin/workflows/src/runs/background/runner.ts +6 -4
  63. package/dist/builtin/workflows/src/runs/background/status.ts +45 -21
  64. package/dist/builtin/workflows/src/runs/foreground/executor.ts +624 -52
  65. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +1 -1
  66. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +80 -24
  67. package/dist/builtin/workflows/src/runs/shared/validate-inputs.ts +61 -24
  68. package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +32 -10
  69. package/dist/builtin/workflows/src/sdk-surface.ts +6 -0
  70. package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +178 -0
  71. package/dist/builtin/workflows/src/shared/persistence-restore.ts +92 -12
  72. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +21 -3
  73. package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +1 -2
  74. package/dist/builtin/workflows/src/shared/run-visibility.ts +9 -0
  75. package/dist/builtin/workflows/src/shared/schema-introspection.ts +121 -0
  76. package/dist/builtin/workflows/src/shared/serializable.ts +132 -0
  77. package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +91 -9
  78. package/dist/builtin/workflows/src/shared/store-types.ts +31 -3
  79. package/dist/builtin/workflows/src/shared/store.ts +58 -14
  80. package/dist/builtin/workflows/src/shared/types.ts +105 -40
  81. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +129 -13
  82. package/dist/builtin/workflows/src/tui/chat-surface.ts +6 -1
  83. package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +3 -2
  84. package/dist/builtin/workflows/src/tui/graph-canvas.ts +1 -1
  85. package/dist/builtin/workflows/src/tui/graph-view.ts +91 -65
  86. package/dist/builtin/workflows/src/tui/inline-form-card.ts +1 -1
  87. package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +3 -2
  88. package/dist/builtin/workflows/src/tui/inputs-overlay.ts +3 -2
  89. package/dist/builtin/workflows/src/tui/inputs-picker.ts +8 -7
  90. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
  91. package/dist/builtin/workflows/src/tui/node-card.ts +34 -8
  92. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -11
  93. package/dist/builtin/workflows/src/tui/prompt-card.ts +98 -50
  94. package/dist/builtin/workflows/src/tui/session-list.ts +7 -2
  95. package/dist/builtin/workflows/src/tui/session-picker.ts +2 -0
  96. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +226 -55
  97. package/dist/builtin/workflows/src/tui/status-helpers.ts +2 -0
  98. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +37 -158
  99. package/dist/builtin/workflows/src/tui/toast.ts +2 -2
  100. package/dist/builtin/workflows/src/tui/widget.ts +53 -12
  101. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +270 -19
  102. package/dist/builtin/workflows/src/tui/workflow-notice-card.ts +184 -0
  103. package/dist/builtin/workflows/src/workflows/define-workflow.ts +138 -43
  104. package/dist/config.d.ts +9 -0
  105. package/dist/config.d.ts.map +1 -1
  106. package/dist/config.js +45 -0
  107. package/dist/config.js.map +1 -1
  108. package/dist/core/agent-session.d.ts +27 -9
  109. package/dist/core/agent-session.d.ts.map +1 -1
  110. package/dist/core/agent-session.js +196 -17
  111. package/dist/core/agent-session.js.map +1 -1
  112. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  113. package/dist/core/atomic-guide-command.js +2 -2
  114. package/dist/core/atomic-guide-command.js.map +1 -1
  115. package/dist/core/codex-fast-mode.d.ts +36 -0
  116. package/dist/core/codex-fast-mode.d.ts.map +1 -0
  117. package/dist/core/codex-fast-mode.js +117 -0
  118. package/dist/core/codex-fast-mode.js.map +1 -0
  119. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  120. package/dist/core/compaction/branch-summarization.js +1 -1
  121. package/dist/core/compaction/branch-summarization.js.map +1 -1
  122. package/dist/core/compaction/compaction.d.ts.map +1 -1
  123. package/dist/core/compaction/compaction.js +1 -1
  124. package/dist/core/compaction/compaction.js.map +1 -1
  125. package/dist/core/extensions/index.d.ts +4 -1
  126. package/dist/core/extensions/index.d.ts.map +1 -1
  127. package/dist/core/extensions/index.js +1 -0
  128. package/dist/core/extensions/index.js.map +1 -1
  129. package/dist/core/extensions/loader.d.ts +7 -2
  130. package/dist/core/extensions/loader.d.ts.map +1 -1
  131. package/dist/core/extensions/loader.js +23 -8
  132. package/dist/core/extensions/loader.js.map +1 -1
  133. package/dist/core/extensions/reactive-widget.d.ts +58 -0
  134. package/dist/core/extensions/reactive-widget.d.ts.map +1 -0
  135. package/dist/core/extensions/reactive-widget.js +182 -0
  136. package/dist/core/extensions/reactive-widget.js.map +1 -0
  137. package/dist/core/extensions/runner.d.ts.map +1 -1
  138. package/dist/core/extensions/runner.js +1 -0
  139. package/dist/core/extensions/runner.js.map +1 -1
  140. package/dist/core/extensions/types.d.ts +26 -12
  141. package/dist/core/extensions/types.d.ts.map +1 -1
  142. package/dist/core/extensions/types.js.map +1 -1
  143. package/dist/core/messages.d.ts +1 -1
  144. package/dist/core/messages.d.ts.map +1 -1
  145. package/dist/core/messages.js +8 -2
  146. package/dist/core/messages.js.map +1 -1
  147. package/dist/core/model-registry.d.ts +4 -0
  148. package/dist/core/model-registry.d.ts.map +1 -1
  149. package/dist/core/model-registry.js +11 -0
  150. package/dist/core/model-registry.js.map +1 -1
  151. package/dist/core/resource-loader.d.ts +9 -1
  152. package/dist/core/resource-loader.d.ts.map +1 -1
  153. package/dist/core/resource-loader.js +49 -21
  154. package/dist/core/resource-loader.js.map +1 -1
  155. package/dist/core/sdk.d.ts.map +1 -1
  156. package/dist/core/sdk.js +22 -13
  157. package/dist/core/sdk.js.map +1 -1
  158. package/dist/core/session-manager.d.ts +7 -5
  159. package/dist/core/session-manager.d.ts.map +1 -1
  160. package/dist/core/session-manager.js +5 -3
  161. package/dist/core/session-manager.js.map +1 -1
  162. package/dist/core/settings-manager.d.ts +16 -0
  163. package/dist/core/settings-manager.d.ts.map +1 -1
  164. package/dist/core/settings-manager.js +64 -5
  165. package/dist/core/settings-manager.js.map +1 -1
  166. package/dist/core/slash-commands.d.ts.map +1 -1
  167. package/dist/core/slash-commands.js +1 -0
  168. package/dist/core/slash-commands.js.map +1 -1
  169. package/dist/core/system-prompt.d.ts.map +1 -1
  170. package/dist/core/system-prompt.js +7 -4
  171. package/dist/core/system-prompt.js.map +1 -1
  172. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  173. package/dist/core/tools/ask-user-question/ask-user-question.js +2 -2
  174. package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
  175. package/dist/index.d.ts +4 -3
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +3 -2
  178. package/dist/index.js.map +1 -1
  179. package/dist/main.d.ts +3 -0
  180. package/dist/main.d.ts.map +1 -1
  181. package/dist/main.js +12 -0
  182. package/dist/main.js.map +1 -1
  183. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
  184. package/dist/modes/interactive/chat-input-actions.js.map +1 -1
  185. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  186. package/dist/modes/interactive/components/diff.js +0 -1
  187. package/dist/modes/interactive/components/diff.js.map +1 -1
  188. package/dist/modes/interactive/components/fast-mode-selector.d.ts +27 -0
  189. package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -0
  190. package/dist/modes/interactive/components/fast-mode-selector.js +105 -0
  191. package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -0
  192. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  193. package/dist/modes/interactive/components/footer.js +7 -12
  194. package/dist/modes/interactive/components/footer.js.map +1 -1
  195. package/dist/modes/interactive/components/index.d.ts +1 -0
  196. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  197. package/dist/modes/interactive/components/index.js +1 -0
  198. package/dist/modes/interactive/components/index.js.map +1 -1
  199. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  200. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  201. package/dist/modes/interactive/interactive-mode.js +132 -30
  202. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  203. package/dist/modes/print-mode.d.ts.map +1 -1
  204. package/dist/modes/print-mode.js +53 -6
  205. package/dist/modes/print-mode.js.map +1 -1
  206. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  207. package/dist/modes/rpc/rpc-mode.js +3 -0
  208. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  209. package/docs/compaction.md +1 -1
  210. package/docs/custom-provider.md +2 -2
  211. package/docs/development.md +2 -2
  212. package/docs/docs.json +2 -2
  213. package/docs/extensions.md +18 -13
  214. package/docs/providers.md +5 -1
  215. package/docs/quickstart.md +5 -3
  216. package/docs/rpc.md +5 -5
  217. package/docs/sdk.md +12 -12
  218. package/docs/settings.md +18 -0
  219. package/docs/themes.md +6 -6
  220. package/docs/tui.md +20 -18
  221. package/docs/usage.md +2 -0
  222. package/docs/workflows.md +403 -39
  223. package/examples/extensions/qna.ts +2 -2
  224. package/package.json +4 -4
  225. package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +0 -392
  226. package/dist/builtin/subagents/skills/playwright-cli/references/element-attributes.md +0 -23
  227. package/dist/builtin/subagents/skills/playwright-cli/references/playwright-tests.md +0 -39
  228. package/dist/builtin/subagents/skills/playwright-cli/references/request-mocking.md +0 -87
  229. package/dist/builtin/subagents/skills/playwright-cli/references/running-code.md +0 -241
  230. package/dist/builtin/subagents/skills/playwright-cli/references/session-management.md +0 -225
  231. package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
  232. package/dist/builtin/subagents/skills/playwright-cli/references/storage-state.md +0 -275
  233. package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +0 -134
  234. package/dist/builtin/subagents/skills/playwright-cli/references/tracing.md +0 -139
  235. package/dist/builtin/subagents/skills/playwright-cli/references/video-recording.md +0 -143
@@ -1,7 +1,7 @@
1
1
  import type {
2
2
  ExtensionAPI,
3
3
  PiMessageRenderComponent,
4
- PiMessageRendererResult,
4
+ PiMessageRenderer,
5
5
  } from "./index.js";
6
6
  import type { Store } from "../shared/store.js";
7
7
  import type {
@@ -9,11 +9,14 @@ import type {
9
9
  PromptKind,
10
10
  RunSnapshot,
11
11
  RunStatus,
12
+ StageInputKind,
12
13
  StageSnapshot,
13
14
  StageStatus,
14
15
  StoreSnapshot,
15
16
  } from "../shared/store-types.js";
16
- import { wrapPlainText } from "../tui/text-helpers.js";
17
+ import { isTopLevelWorkflowRun } from "../shared/run-visibility.js";
18
+ import { deriveGraphThemeFromPiTheme, type GraphTheme } from "../tui/graph-theme.js";
19
+ import { renderWorkflowNoticeCard, type WorkflowNoticeTone } from "../tui/workflow-notice-card.js";
17
20
 
18
21
  export const LIFECYCLE_NOTICE_CUSTOM_TYPE = "workflows:lifecycle-notice";
19
22
  export const LIFECYCLE_NOTICE_SNIPPET_LIMIT = 240;
@@ -40,7 +43,7 @@ export interface WorkflowLifecycleNoticeDetails {
40
43
  readonly stageId?: string;
41
44
  readonly stageName?: string;
42
45
  readonly promptId?: string;
43
- readonly promptKind?: PromptKind;
46
+ readonly promptKind?: PromptKind | StageInputKind;
44
47
  readonly promptMessage?: string;
45
48
  readonly error?: string;
46
49
  readonly failedStageId?: string;
@@ -64,7 +67,7 @@ export interface WorkflowLifecycleNotificationOptions {
64
67
  readonly seedExisting?: boolean;
65
68
  }
66
69
 
67
- type RawRenderer = (payload: unknown) => PiMessageRendererResult;
70
+ type RawRenderer = PiMessageRenderer;
68
71
 
69
72
  // Process-lifetime registration dedupe: extension hosts are object identities
70
73
  // and may be garbage-collected, but renderer registrations are not unregistered.
@@ -91,6 +94,7 @@ export function seedWorkflowLifecycleNotificationState(
91
94
  snapshot: StoreSnapshot,
92
95
  ): void {
93
96
  for (const run of snapshot.runs) {
97
+ if (!isTopLevelWorkflowRun(run)) continue;
94
98
  if ((run.status === "completed" || run.status === "failed") && run.endedAt !== undefined) {
95
99
  state.deliveredTerminalRuns.add(terminalRunKey(run.status, run.id));
96
100
  }
@@ -124,6 +128,24 @@ export function withWorkflowLifecycleNotificationsSuppressed<T>(
124
128
  }
125
129
  }
126
130
 
131
+ /**
132
+ * Async-safe companion to {@link withWorkflowLifecycleNotificationsSuppressed}.
133
+ * Keeps suppression active until the awaited operation settles, so terminal
134
+ * store updates produced by background jobs cannot race an awaited headless
135
+ * workflow dispatch and trigger an extra steer turn before the caller returns.
136
+ */
137
+ export async function withWorkflowLifecycleNotificationsSuppressedAsync<T>(
138
+ state: WorkflowLifecycleNotificationState,
139
+ fn: () => Promise<T>,
140
+ ): Promise<T> {
141
+ state.suppressionDepth += 1;
142
+ try {
143
+ return await fn();
144
+ } finally {
145
+ state.suppressionDepth -= 1;
146
+ }
147
+ }
148
+
127
149
  export function installWorkflowLifecycleNotifications(
128
150
  options: WorkflowLifecycleNotificationOptions,
129
151
  ): () => void {
@@ -141,6 +163,7 @@ export function installWorkflowLifecycleNotifications(
141
163
 
142
164
  const emit = (details: WorkflowLifecycleNoticeDetails): void => {
143
165
  const content = formatWorkflowLifecycleNoticeText(details);
166
+ const deliveryOptions = { triggerTurn: true, deliverAs: "steer" as const };
144
167
  try {
145
168
  // Store subscribers are notified in a tight loop. A lifecycle notice
146
169
  // failure must never abort sibling subscribers such as status writers.
@@ -152,7 +175,7 @@ export function installWorkflowLifecycleNotifications(
152
175
  display: true,
153
176
  details,
154
177
  },
155
- { triggerTurn: true, deliverAs: "steer" },
178
+ deliveryOptions,
156
179
  ),
157
180
  ).catch((error: unknown) => warnLifecycleSendFailure(error));
158
181
  } catch (error) {
@@ -187,8 +210,9 @@ export function installWorkflowLifecycleNotifications(
187
210
  if (state.deliveredInputPrompts.has(key)) return;
188
211
 
189
212
  state.deliveredInputPrompts.add(key);
190
- if (state.suppressionDepth > 0) return;
191
- emit(makeStageAwaitingInputNotice(run, stage));
213
+ // Awaiting-input states are tracked for dedupe/restore, but must not enqueue
214
+ // a main-chat steer turn. Waking the active agent with an actionable prompt
215
+ // can let the model answer workflow HIL without a deliberate user action.
192
216
  };
193
217
 
194
218
  const emitRunAwaitingInputNoticeOnce = (run: RunSnapshot): void => {
@@ -198,12 +222,13 @@ export function installWorkflowLifecycleNotifications(
198
222
  if (state.deliveredInputPrompts.has(key)) return;
199
223
 
200
224
  state.deliveredInputPrompts.add(key);
201
- if (state.suppressionDepth > 0) return;
202
- emit(makeRunAwaitingInputNotice(run, run.pendingPrompt));
225
+ // See stage-level awaiting-input handling above: prompt state remains visible
226
+ // through workflow status/connect surfaces instead of the main chat context.
203
227
  };
204
228
 
205
229
  const inspect = (snapshot: StoreSnapshot): void => {
206
230
  for (const run of snapshot.runs) {
231
+ if (!isTopLevelWorkflowRun(run)) continue;
207
232
  emitTerminalNoticeOnce(run, "completed");
208
233
  emitTerminalNoticeOnce(run, "failed");
209
234
 
@@ -227,10 +252,10 @@ export function registerLifecycleNoticeRenderer(
227
252
  const host = options.rendererHost ?? register;
228
253
  if (rendererRegisteredHosts.has(host)) return;
229
254
 
230
- const renderer: RawRenderer = (raw) => {
255
+ const renderer: RawRenderer = (raw, _options, piTheme) => {
231
256
  const message = raw as { details?: WorkflowLifecycleNoticeDetails };
232
257
  if (!message.details) return undefined;
233
- return makeNoticeComponent(message.details);
258
+ return makeNoticeComponent(message.details, themeFromRenderer(piTheme));
234
259
  };
235
260
 
236
261
  register(LIFECYCLE_NOTICE_CUSTOM_TYPE, renderer);
@@ -240,23 +265,23 @@ export function registerLifecycleNoticeRenderer(
240
265
  export function formatWorkflowLifecycleNoticeText(details: WorkflowLifecycleNoticeDetails): string {
241
266
  const workflowName = escapeQuotedText(details.workflowName);
242
267
  if (details.kind === "completed") {
243
- return `✅ Workflow "${workflowName}" completed (run ${details.runId}). Inspect: /workflow status ${details.runId}`;
268
+ return `✓ Workflow "${workflowName}" completed (run ${details.runId}). Inspect: /workflow status ${details.runId}`;
244
269
  }
245
270
  if (details.kind === "failed") {
246
271
  const stage = details.stageName ?? details.failedStageId;
247
272
  const stageText = stage ? `, stage ${stage}` : "";
248
273
  const errorText = details.error ? `: ${details.error}` : "";
249
- return `❌ Workflow "${workflowName}" failed (run ${details.runId}${stageText})${errorText}. Inspect: /workflow status ${details.runId}`;
274
+ return `✗ Workflow "${workflowName}" failed (run ${details.runId}${stageText})${errorText}. Inspect: /workflow status ${details.runId}`;
250
275
  }
251
276
  const prompt = details.promptMessage ? ` Prompt: ${details.promptMessage}` : "";
252
277
  if (details.scope === "run") {
253
- return `❓ Workflow "${workflowName}" needs input (run ${details.runId}).${prompt} Respond: /workflow connect ${details.runId} to answer this run-level prompt.`;
278
+ return `? Workflow "${workflowName}" needs input (run ${details.runId}).${prompt} Respond: /workflow connect ${details.runId} to answer this run-level prompt.`;
254
279
  }
255
280
  const stage = details.stageName ?? details.stageId ?? "unknown";
256
281
  const responseHint = details.stageId && details.promptId
257
282
  ? `/workflow connect ${details.runId} or workflow({ action: "send", runId: ${jsonString(details.runId)}, stageId: ${jsonString(details.stageId)}, promptId: ${jsonString(details.promptId)}, response: ... })`
258
283
  : `/workflow connect ${details.runId}`;
259
- return `❓ Workflow "${workflowName}" needs input (run ${details.runId}, stage ${stage}).${prompt} Respond: ${responseHint}.`;
284
+ return `? Workflow "${workflowName}" needs input (run ${details.runId}, stage ${stage}).${prompt} Respond: ${responseHint}.`;
260
285
  }
261
286
 
262
287
  function makeTerminalNotice(
@@ -281,34 +306,6 @@ function makeTerminalNotice(
281
306
  };
282
307
  }
283
308
 
284
- function makeStageAwaitingInputNotice(run: RunSnapshot, stage: StageSnapshot): WorkflowLifecycleNoticeDetails {
285
- const prompt = stage.pendingPrompt;
286
- return {
287
- kind: "awaiting_input",
288
- scope: "stage",
289
- runId: run.id,
290
- workflowName: run.name,
291
- status: stage.status,
292
- stageId: stage.id,
293
- stageName: stage.name,
294
- ...(prompt ? promptFields(prompt) : {}),
295
- // Normal store paths stamp awaitingInputSince; Date.now() is defensive for malformed restored snapshots.
296
- createdAt: prompt?.createdAt ?? stage.awaitingInputSince ?? Date.now(),
297
- };
298
- }
299
-
300
- function makeRunAwaitingInputNotice(run: RunSnapshot, prompt: PendingPrompt): WorkflowLifecycleNoticeDetails {
301
- return {
302
- kind: "awaiting_input",
303
- scope: "run",
304
- runId: run.id,
305
- workflowName: run.name,
306
- status: run.status,
307
- ...promptFields(prompt),
308
- createdAt: prompt.createdAt,
309
- };
310
- }
311
-
312
309
  function warnLifecycleSendFailure(error: unknown): void {
313
310
  if (process.env.ATOMIC_WORKFLOW_DEBUG !== "1") return;
314
311
  const message = error instanceof Error ? error.message : String(error);
@@ -327,18 +324,8 @@ function terminalRunKey(kind: "completed" | "failed", runId: string): string {
327
324
  return `${kind}:${runId}`;
328
325
  }
329
326
 
330
- function promptFields(
331
- prompt: PendingPrompt,
332
- ): Pick<WorkflowLifecycleNoticeDetails, "promptId" | "promptKind" | "promptMessage"> {
333
- return {
334
- promptId: prompt.id,
335
- promptKind: prompt.kind,
336
- promptMessage: truncateSnippet(prompt.message),
337
- };
338
- }
339
-
340
327
  function awaitingInputKey(runId: string, stage: StageSnapshot): string {
341
- const promptId = stage.pendingPrompt?.id;
328
+ const promptId = stage.pendingPrompt?.id ?? stage.inputRequest?.id;
342
329
  if (promptId) return `awaiting_input:${runId}:stage:${stage.id}:${promptId}`;
343
330
  return `awaiting_input:${runId}:stage:${stage.id}:${stage.awaitingInputSince ?? "active"}`;
344
331
  }
@@ -353,20 +340,70 @@ function truncateSnippet(value: string): string {
353
340
  return `${normalized.slice(0, LIFECYCLE_NOTICE_SNIPPET_LIMIT - 1)}…`;
354
341
  }
355
342
 
356
- function makeNoticeComponent(details: WorkflowLifecycleNoticeDetails): PiMessageRenderComponent {
343
+ function makeNoticeComponent(
344
+ details: WorkflowLifecycleNoticeDetails,
345
+ theme: GraphTheme | undefined,
346
+ ): PiMessageRenderComponent {
357
347
  const text = formatWorkflowLifecycleNoticeText(details);
358
348
  return {
359
349
  render(width: number): string[] {
360
- // Wrap to the render width so a long run id / workflow name never emits a
361
- // line wider than the terminal. pi-tui hard-throws ("Rendered line N
362
- // exceeds terminal width") on any over-wide rendered line, which would
363
- // crash the whole TUI on narrow terminals or after a resize (#1109).
364
- // `wrapPlainText` hard-breaks long unbreakable tokens (e.g. UUIDs), so
365
- // every returned line is guaranteed to fit within `width`.
366
- return wrapPlainText(text, width);
350
+ // Width < 32 cannot carry rounded card chrome without exceeding the
351
+ // terminal, so the card helper falls back to wrapped plain text there.
352
+ return renderLifecycleNoticeCard(details, { width, theme, fallbackText: text });
367
353
  },
368
354
  invalidate() {
369
355
  /* stored lifecycle notices are immutable */
370
356
  },
371
357
  };
372
358
  }
359
+
360
+ function renderLifecycleNoticeCard(
361
+ details: WorkflowLifecycleNoticeDetails,
362
+ opts: { width: number; theme?: GraphTheme; fallbackText: string },
363
+ ): string[] {
364
+ const tone: WorkflowNoticeTone = details.kind === "failed" ? "error" : details.kind === "awaiting_input" ? "warning" : "success";
365
+ const title = details.kind === "failed"
366
+ ? "WORKFLOW FAILED"
367
+ : details.kind === "awaiting_input"
368
+ ? "WORKFLOW INPUT"
369
+ : "WORKFLOW COMPLETE";
370
+ const glyph = details.kind === "failed" ? "✗" : details.kind === "awaiting_input" ? "?" : "✓";
371
+ const stage = details.stageName ?? details.failedStageId ?? details.stageId;
372
+ const headline = details.kind === "failed"
373
+ ? `Workflow "${details.workflowName}" failed`
374
+ : details.kind === "awaiting_input"
375
+ ? `Workflow "${details.workflowName}" needs input`
376
+ : `Workflow "${details.workflowName}" completed`;
377
+ return renderWorkflowNoticeCard({
378
+ title,
379
+ glyph,
380
+ headline,
381
+ tone,
382
+ fields: [
383
+ { label: "workflow", value: details.workflowName },
384
+ { label: "run", value: details.runId },
385
+ { label: "stage", value: stage },
386
+ { label: "prompt", value: details.promptMessage, tone: "muted" },
387
+ { label: "error", value: details.error, tone: "error" },
388
+ { label: "duration", value: formatDurationMs(details.durationMs), tone: "muted" },
389
+ ],
390
+ hints: [details.kind === "awaiting_input" ? `/workflow connect ${details.runId}` : `/workflow status ${details.runId}`],
391
+ fallbackText: opts.fallbackText,
392
+ width: opts.width,
393
+ ...(opts.theme ? { theme: opts.theme } : {}),
394
+ });
395
+ }
396
+
397
+ function formatDurationMs(durationMs: number | undefined): string | undefined {
398
+ if (durationMs === undefined) return undefined;
399
+ if (durationMs < 1000) return `${durationMs}ms`;
400
+ const seconds = durationMs / 1000;
401
+ if (seconds < 60) return `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;
402
+ const minutes = Math.floor(seconds / 60);
403
+ const remainder = Math.round(seconds % 60);
404
+ return `${minutes}m ${remainder}s`;
405
+ }
406
+
407
+ function themeFromRenderer(piTheme: unknown): GraphTheme | undefined {
408
+ return piTheme === undefined ? undefined : deriveGraphThemeFromPiTheme(piTheme);
409
+ }
@@ -4,11 +4,12 @@
4
4
  */
5
5
 
6
6
  import { truncateToWidth } from "../tui/text-helpers.js";
7
+ import type { WorkflowInputValues } from "../shared/types.js";
7
8
 
8
9
  /** Renderer-only subset of the canonical WorkflowToolArgs from index.ts. */
9
10
  export interface WorkflowToolArgs {
10
11
  workflow?: string;
11
- inputs?: Record<string, unknown>;
12
+ inputs?: WorkflowInputValues;
12
13
  action?:
13
14
  | "run"
14
15
  | "list"
@@ -20,6 +20,7 @@ import { renderRunDetail } from "../tui/run-detail.js";
20
20
  import { renderWorkflowList } from "../tui/workflow-list.js";
21
21
  import { deriveGraphTheme } from "../tui/graph-theme.js";
22
22
  import { renderDispatchConfirm } from "../tui/dispatch-confirm.js";
23
+ import type { WorkflowInputValues, WorkflowOutputValues } from "../shared/types.js";
23
24
  import { renderRoundedBox } from "../tui/chat-surface.js";
24
25
  import { truncateToWidth } from "../tui/text-helpers.js";
25
26
 
@@ -87,7 +88,7 @@ type RunResult = {
87
88
  name?: string;
88
89
  runId: string;
89
90
  status: string;
90
- result?: Record<string, unknown>;
91
+ result?: WorkflowOutputValues;
91
92
  details?: WorkflowDetails;
92
93
  error?: string;
93
94
  stages?: StageSnapshot[];
@@ -104,13 +105,15 @@ type StageListItem = {
104
105
  status: StageStatus;
105
106
  sessionId?: string;
106
107
  sessionFile?: string;
108
+ transcriptPath?: string;
107
109
  error?: string;
108
110
  awaitingInputSince?: number;
109
111
  pendingPrompt?: PendingPrompt;
110
112
  inputRequest?: StageInputRequest;
111
113
  };
112
114
  type StageListResult = { action: "stages"; runId: string; filter: string; stages: StageListItem[]; error?: string };
113
- type StageDetailResult = { action: "stage"; runId: string; stage?: StageSnapshot; error?: string };
115
+ type StageDetailItem = StageSnapshot & { transcriptPath?: string };
116
+ type StageDetailResult = { action: "stage"; runId: string; stage?: StageDetailItem; error?: string };
114
117
  type TranscriptEntry = { role: string; text?: string; toolName?: string; output?: string; timestamp?: number };
115
118
  type TranscriptResult = {
116
119
  action: "transcript";
@@ -119,8 +122,11 @@ type TranscriptResult = {
119
122
  source: "live" | "snapshot" | "error";
120
123
  entries: TranscriptEntry[];
121
124
  truncated: boolean;
125
+ entryCount?: number;
126
+ entryLimit?: number;
122
127
  sessionId?: string;
123
128
  sessionFile?: string;
129
+ transcriptPath?: string;
124
130
  };
125
131
  type SendResult = { action: "send"; runId: string; stageId: string; delivery: string; status: "ok" | "noop"; message: string };
126
132
  type PauseResult = { action: "pause"; runId: string; status: string; message: string };
@@ -156,7 +162,7 @@ export interface RenderResultOpts {
156
162
  width?: number;
157
163
  /** Original workflow inputs from the tool call, used to render the same
158
164
  * dispatch confirmation card as `/workflow <name> ...` for background runs. */
159
- runInputs?: Readonly<Record<string, unknown>>;
165
+ runInputs?: Readonly<WorkflowInputValues>;
160
166
  /**
161
167
  * Suppress ANSI colour output (CLI flag paths / non-TTY consumers).
162
168
  * When false/undefined the canonical Catppuccin chrome is rendered.
@@ -8,6 +8,8 @@
8
8
  * cross-ref: spec §5.6 Persistence renderers (registration only)
9
9
  */
10
10
 
11
+ import type { WorkflowInputValues, WorkflowOutputValues } from "../shared/types.js";
12
+
11
13
  // ---------------------------------------------------------------------------
12
14
  // Entry payload shapes (matches pi.appendEntry call signatures from §5.6)
13
15
  // ---------------------------------------------------------------------------
@@ -15,7 +17,7 @@
15
17
  export interface RunStartPayload {
16
18
  runId: string;
17
19
  name: string;
18
- inputs?: Record<string, unknown>;
20
+ inputs?: WorkflowInputValues;
19
21
  ts?: number;
20
22
  }
21
23
 
@@ -46,7 +48,7 @@ export interface StageEndPayload {
46
48
  export interface RunEndPayload {
47
49
  runId: string;
48
50
  status: "ok" | "error" | "killed" | string;
49
- result?: Record<string, unknown>;
51
+ result?: WorkflowOutputValues;
50
52
  ts?: number;
51
53
  }
52
54
 
@@ -82,6 +84,6 @@ export function renderStageResult(payload: StageEndPayload): string {
82
84
 
83
85
  /** Render workflow.run.end entry. */
84
86
  export function renderRunSummary(payload: RunEndPayload): string {
85
- const icon = payload.status === "ok" ? "" : "";
87
+ const icon = payload.status === "ok" ? "" : "";
86
88
  return `${icon} workflow [${payload.runId}] ${payload.status}`;
87
89
  }
@@ -12,19 +12,21 @@
12
12
 
13
13
  import { createRegistry } from "../workflows/registry.js";
14
14
  import type { WorkflowRegistry } from "../workflows/registry.js";
15
- import type {
16
- WorkflowDefinition,
17
- WorkflowPersistencePort,
18
- WorkflowMcpPort,
19
- WorkflowRuntimeConfig,
20
- WorkflowDetails,
21
- WorkflowDirectOptions,
22
- WorkflowDirectTaskItem,
23
- WorkflowChainStep,
24
- WorkflowModelCatalogPort,
15
+ import {
16
+ INTERACTIVE_WORKFLOW_POLICY,
17
+ type WorkflowDefinition,
18
+ type WorkflowPersistencePort,
19
+ type WorkflowMcpPort,
20
+ type WorkflowRuntimeConfig,
21
+ type WorkflowDetails,
22
+ type WorkflowDirectOptions,
23
+ type WorkflowDirectTaskItem,
24
+ type WorkflowChainStep,
25
+ type WorkflowModelCatalogPort,
26
+ type WorkflowExecutionPolicy,
25
27
  } from "../shared/types.js";
26
28
  import type { StageAdapters } from "../runs/foreground/stage-runner.js";
27
- import { resolveInputs, runChain, runParallel, runTask, type RunOpts } from "../runs/foreground/executor.js";
29
+ import { resolveAndValidateInputs, runChain, runParallel, runTask, type RunOpts } from "../runs/foreground/executor.js";
28
30
  import type { Store } from "../shared/store.js";
29
31
  import type { RunSnapshot } from "../shared/store-types.js";
30
32
  import type { CancellationRegistry } from "../runs/background/cancellation-registry.js";
@@ -41,6 +43,7 @@ import {
41
43
  } from "../intercom/result-intercom.js";
42
44
  import { validateWorkflowModels } from "../runs/shared/model-fallback.js";
43
45
  import { runDetached } from "../runs/background/runner.js";
46
+ import type { JobTracker } from "../runs/background/job-tracker.js";
44
47
  import { classifyWorkflowFailure } from "../shared/workflow-failures.js";
45
48
 
46
49
  // ---------------------------------------------------------------------------
@@ -78,6 +81,10 @@ export interface ExtensionRuntimeOpts {
78
81
  config?: WorkflowRuntimeConfig;
79
82
  /** Optional model catalog forwarded to workflow runs for fallback resolution. */
80
83
  models?: WorkflowModelCatalogPort;
84
+ /** Job tracker forwarded to named detached runs. */
85
+ jobs?: JobTracker;
86
+ /** Invocation cwd used for workflow execution. Defaults to process.cwd(). */
87
+ cwd?: string;
81
88
  }
82
89
 
83
90
  // ---------------------------------------------------------------------------
@@ -99,13 +106,17 @@ export interface ExtensionRuntime {
99
106
  * Dispatch a `list`, `inputs`, or `run` action.
100
107
  * For `status`, `kill`, and `resume` use the runs/background/status module directly.
101
108
  */
102
- dispatch(args: WorkflowToolArgs): Promise<WorkflowToolResult>;
109
+ dispatch(args: WorkflowToolArgs, options?: RuntimeDispatchOptions): Promise<WorkflowToolResult>;
103
110
 
104
111
  /** Execute direct single/parallel/chain workflow tool modes. */
105
- runDirect(args: WorkflowToolArgs): Promise<WorkflowDetails>;
112
+ runDirect(args: WorkflowToolArgs, options?: RuntimeDispatchOptions): Promise<WorkflowDetails>;
106
113
 
107
114
  /** Start a linked continuation for a failed resumable named workflow run. */
108
- resumeFailedRun(sourceRunId: string, stageId?: string): ResumeFailedRunResult;
115
+ resumeFailedRun(sourceRunId: string, stageId?: string, options?: RuntimeDispatchOptions): ResumeFailedRunResult;
116
+ }
117
+
118
+ export interface RuntimeDispatchOptions {
119
+ readonly policy?: WorkflowExecutionPolicy;
109
120
  }
110
121
 
111
122
  // ---------------------------------------------------------------------------
@@ -135,8 +146,10 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
135
146
  const config = opts.config;
136
147
  const intercom = opts.intercom;
137
148
  const models = opts.models;
149
+ const jobs = opts.jobs;
150
+ const runtimeCwd = opts.cwd ?? process.cwd();
138
151
 
139
- function runOptions(args: WorkflowToolArgs): RunOpts {
152
+ function runOptions(args: WorkflowToolArgs, policy?: WorkflowExecutionPolicy): RunOpts {
140
153
  const argConcurrency =
141
154
  typeof args.concurrency === "number" && Number.isFinite(args.concurrency)
142
155
  ? Math.max(1, Math.floor(args.concurrency))
@@ -160,6 +173,9 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
160
173
  mcp,
161
174
  config: effectiveConfig,
162
175
  models,
176
+ ...(policy !== undefined ? { executionMode: policy.mode } : {}),
177
+ registry,
178
+ cwd: runtimeCwd,
163
179
  };
164
180
  }
165
181
 
@@ -309,19 +325,25 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
309
325
  });
310
326
  }
311
327
 
312
- function runDirectForeground(args: WorkflowToolArgs, runId?: string): Promise<WorkflowDetails> {
313
- const baseRunOptions = runOptions(args);
328
+ function runDirectForeground(
329
+ args: WorkflowToolArgs,
330
+ runId?: string,
331
+ policy?: WorkflowExecutionPolicy,
332
+ ): Promise<WorkflowDetails> {
333
+ const directRunOptions = directOptions(args);
334
+ const baseRunOptions = runOptions(args, policy);
314
335
  const effectiveRunOptions = runId === undefined
315
336
  ? baseRunOptions
316
337
  : { ...baseRunOptions, runId };
338
+
317
339
  if (Array.isArray(args.chain)) {
318
- return runChain(args.chain, directOptions(args), effectiveRunOptions);
340
+ return runChain(args.chain, directRunOptions, effectiveRunOptions);
319
341
  }
320
342
  if (Array.isArray(args.tasks)) {
321
- return runParallel(args.tasks, directOptions(args), effectiveRunOptions);
343
+ return runParallel(args.tasks, directRunOptions, effectiveRunOptions);
322
344
  }
323
345
  if (args.task !== undefined && typeof args.task === "object") {
324
- return runTask(args.task, directOptions(args), effectiveRunOptions);
346
+ return runTask(args.task, directRunOptions, effectiveRunOptions);
325
347
  }
326
348
  throw new Error("WorkflowRuntime.runDirect: no direct execution mode supplied");
327
349
  }
@@ -367,7 +389,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
367
389
  return { ok: true, stageId: failedStageId };
368
390
  }
369
391
 
370
- function resumeFailedRun(sourceRunId: string, stageId?: string): ResumeFailedRunResult {
392
+ function resumeFailedRun(sourceRunId: string, stageId?: string, options?: RuntimeDispatchOptions): ResumeFailedRunResult {
371
393
  const source = activeStore.runs().find((run) => run.id === sourceRunId);
372
394
  if (source === undefined) {
373
395
  return { ok: false, reason: "run_not_found", message: `run not found: ${sourceRunId}` };
@@ -385,12 +407,12 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
385
407
  }
386
408
  const sourceInputs = { ...source.inputs };
387
409
  try {
388
- resolveInputs(def.inputs, sourceInputs);
410
+ resolveAndValidateInputs(def.inputs, sourceInputs, `workflow "${def.name}"`);
389
411
  } catch (err) {
390
412
  return { ok: false, reason: "insufficient_state", message: `insufficient_state: ${err instanceof Error ? err.message : String(err)}` };
391
413
  }
392
414
  const accepted = runDetached(def, sourceInputs, {
393
- ...runOptions({ workflow: def.name, inputs: sourceInputs }),
415
+ ...runOptions({ workflow: def.name, inputs: sourceInputs }, options?.policy),
394
416
  continuation: { source, resumeFromStageId: resolvedStage.stageId },
395
417
  });
396
418
  return {
@@ -402,7 +424,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
402
424
  };
403
425
  }
404
426
 
405
- async function runDirectAsync(args: WorkflowToolArgs): Promise<WorkflowDetails> {
427
+ async function runDirectAsync(args: WorkflowToolArgs, policy?: WorkflowExecutionPolicy): Promise<WorkflowDetails> {
406
428
  const runId = crypto.randomUUID();
407
429
  const mode = directMode(args);
408
430
  const delivery = effectiveIntercomDelivery(args, mode);
@@ -411,7 +433,7 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
411
433
  try {
412
434
  warnings = await validateWorkflowModels({
413
435
  requests: directModelRequests(args),
414
- catalog: runOptions(args).models,
436
+ catalog: models,
415
437
  });
416
438
  } catch (error: unknown) {
417
439
  return withIntercomSummary({
@@ -423,10 +445,10 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
423
445
  error: classifyWorkflowFailure(error).userMessage,
424
446
  }, delivery, parentSession);
425
447
  }
426
- const background = runDirectForeground(args, runId);
448
+ const background = runDirectForeground(args, runId, policy);
427
449
  void background.then(
428
450
  (details) => {
429
- emitDirectIntercom(withIntercomSummary(details, delivery, parentSession), delivery, parentSession);
451
+ emitDirectIntercom(details, delivery, parentSession);
430
452
  },
431
453
  (error: unknown) => {
432
454
  const details: WorkflowDetails = withIntercomSummary({
@@ -455,18 +477,31 @@ export function createExtensionRuntime(opts: ExtensionRuntimeOpts = {}): Extensi
455
477
  return registry;
456
478
  },
457
479
 
458
- dispatch(args: WorkflowToolArgs): Promise<WorkflowToolResult> {
459
- return dispatch(args, { registry, adapters, store: activeStore, cancellation, persistence, mcp, config, models });
480
+ dispatch(args: WorkflowToolArgs, options?: RuntimeDispatchOptions): Promise<WorkflowToolResult> {
481
+ return dispatch(args, {
482
+ registry,
483
+ adapters,
484
+ store: activeStore,
485
+ cancellation,
486
+ jobs,
487
+ persistence,
488
+ mcp,
489
+ config,
490
+ models,
491
+ policy: options?.policy,
492
+ cwd: runtimeCwd,
493
+ });
460
494
  },
461
495
 
462
- runDirect(args: WorkflowToolArgs): Promise<WorkflowDetails> {
463
- if (args.async === true) {
464
- return runDirectAsync(args);
496
+ runDirect(args: WorkflowToolArgs, options?: RuntimeDispatchOptions): Promise<WorkflowDetails> {
497
+ const policy = options?.policy ?? INTERACTIVE_WORKFLOW_POLICY;
498
+ if (args.async === true && policy.awaitTerminalRun !== true) {
499
+ return runDirectAsync(args, policy);
465
500
  }
466
501
  const mode = directMode(args);
467
502
  const delivery = effectiveIntercomDelivery(args, mode);
468
503
  const parentSession = intercomParentSession(args);
469
- return runDirectForeground(args).then((details) => {
504
+ return runDirectForeground(args, undefined, policy).then((details) => {
470
505
  const summarized = withIntercomSummary(details, delivery, parentSession);
471
506
  emitDirectIntercom(summarized, delivery, parentSession);
472
507
  return summarized;
@@ -129,7 +129,7 @@ export function createStatusWriter(
129
129
  store.recordNotice({
130
130
  id: `status-writer-error-${Date.now()}`,
131
131
  level: "warning",
132
- message: `pi-workflows: status file write failed (${filePath}): ${msg}`,
132
+ message: `atomic-workflows: status file write failed (${filePath}): ${msg}`,
133
133
  createdAt: Date.now(),
134
134
  });
135
135
  }