@bastani/atomic 0.8.21-0 → 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 +46 -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 +101 -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
@@ -0,0 +1,363 @@
1
+ import type {
2
+ ExtensionAPI,
3
+ PiMessageRenderComponent,
4
+ PiMessageRenderer,
5
+ } from "./index.js";
6
+ import type { Store } from "../shared/store.js";
7
+ import type {
8
+ PendingPrompt,
9
+ PromptKind,
10
+ RunSnapshot,
11
+ StageInputKind,
12
+ StageInputRequest,
13
+ StageSnapshot,
14
+ StoreSnapshot,
15
+ } from "../shared/store-types.js";
16
+ import type { StageUiBroker } from "../shared/stage-ui-broker.js";
17
+ import { deriveGraphThemeFromPiTheme, type GraphTheme } from "../tui/graph-theme.js";
18
+ import { renderWorkflowNoticeCard } from "../tui/workflow-notice-card.js";
19
+
20
+ export const HIL_ANSWER_NOTICE_CUSTOM_TYPE = "workflows:hil-answer-notice";
21
+ const HIL_ANSWER_SNIPPET_LIMIT = 1000;
22
+
23
+ export type WorkflowHilAnswerPromptKind = PromptKind | StageInputKind;
24
+
25
+ export interface WorkflowHilAnswerNoticeDetails {
26
+ readonly kind: "hil_answered";
27
+ readonly scope: "stage";
28
+ readonly runId: string;
29
+ readonly workflowName: string;
30
+ readonly stageId: string;
31
+ readonly stageName?: string;
32
+ readonly promptId?: string;
33
+ readonly promptKind?: WorkflowHilAnswerPromptKind;
34
+ readonly promptMessage?: string;
35
+ readonly answeredAt: number;
36
+ readonly answerAvailable: true;
37
+ readonly answerIncluded: true;
38
+ readonly answerSummary: string;
39
+ }
40
+
41
+ export interface WorkflowHilAnswerNotificationState {
42
+ readonly deliveredAnswerPrompts: Set<string>;
43
+ }
44
+
45
+ export interface WorkflowHilAnswerNotificationOptions {
46
+ readonly store: Store;
47
+ readonly stageUiBroker?: Pick<StageUiBroker, "onStagePromptResolved">;
48
+ readonly sendMessage?: ExtensionAPI["sendMessage"];
49
+ readonly registerMessageRenderer?: ExtensionAPI["registerMessageRenderer"];
50
+ readonly rendererHost?: object;
51
+ readonly state?: WorkflowHilAnswerNotificationState;
52
+ }
53
+
54
+ type RawRenderer = PiMessageRenderer;
55
+
56
+ const rendererRegisteredHosts = new WeakSet<object>();
57
+
58
+ export function createWorkflowHilAnswerNotificationState(): WorkflowHilAnswerNotificationState {
59
+ return {
60
+ deliveredAnswerPrompts: new Set<string>(),
61
+ };
62
+ }
63
+
64
+ export function resetWorkflowHilAnswerNotificationState(
65
+ state: WorkflowHilAnswerNotificationState,
66
+ ): void {
67
+ state.deliveredAnswerPrompts.clear();
68
+ }
69
+
70
+ export function installWorkflowHilAnswerNotifications(
71
+ options: WorkflowHilAnswerNotificationOptions,
72
+ ): () => void {
73
+ registerHilAnswerNoticeRenderer(options);
74
+
75
+ const send = options.sendMessage;
76
+ if (typeof send !== "function") return () => undefined;
77
+
78
+ const state = options.state ?? createWorkflowHilAnswerNotificationState();
79
+ let previousSnapshot = options.store.snapshot();
80
+
81
+ const emitOnce = (details: WorkflowHilAnswerNoticeDetails): void => {
82
+ const key = answerNoticeKey(details.runId, details.stageId, details.promptId, details.promptKind);
83
+ if (state.deliveredAnswerPrompts.has(key)) return;
84
+
85
+ state.deliveredAnswerPrompts.add(key);
86
+ sendHilAnswerNotice(send, details);
87
+ };
88
+
89
+ const inspectSimplePromptAnswers = (snapshot: StoreSnapshot): void => {
90
+ for (const previousRun of previousSnapshot.runs) {
91
+ const currentRun = snapshot.runs.find((run) => run.id === previousRun.id);
92
+ if (currentRun === undefined) continue;
93
+
94
+ for (const previousStage of previousRun.stages) {
95
+ const answeredPrompt = simplePromptAnswer(previousStage, currentRun);
96
+ if (answeredPrompt === undefined) continue;
97
+ const answerRecord = options.store.getStagePromptAnswer(currentRun.id, answeredPrompt.stage.id);
98
+ if (answerRecord?.answerSource === "workflow_tool") continue;
99
+ emitOnce(makeSimplePromptAnswerNotice(currentRun, answeredPrompt.stage, answeredPrompt.prompt, answerRecord?.value));
100
+ }
101
+ }
102
+ previousSnapshot = snapshot;
103
+ };
104
+
105
+ const unsubscribeStore = options.store.subscribe(inspectSimplePromptAnswers);
106
+ const unsubscribeBroker = options.stageUiBroker?.onStagePromptResolved((event) => {
107
+ if (event.answerSource === "workflow_tool") return;
108
+ const answeredStage = findStageSnapshot(options.store.snapshot(), event.runId, event.stageId);
109
+ if (answeredStage === undefined) return;
110
+
111
+ emitOnce(makeBrokerPromptAnswerNotice(answeredStage.run, answeredStage.stage, event.prompt, event.answer, event.answeredAt));
112
+ });
113
+
114
+ return () => {
115
+ unsubscribeStore();
116
+ unsubscribeBroker?.();
117
+ };
118
+ }
119
+
120
+ export function registerHilAnswerNoticeRenderer(
121
+ options: Pick<WorkflowHilAnswerNotificationOptions, "registerMessageRenderer" | "rendererHost">,
122
+ ): void {
123
+ const register = options.registerMessageRenderer;
124
+ if (typeof register !== "function") return;
125
+
126
+ const host = options.rendererHost ?? register;
127
+ if (rendererRegisteredHosts.has(host)) return;
128
+
129
+ const renderer: RawRenderer = (raw, _options, piTheme) => {
130
+ const details = readHilAnswerNoticeDetails(raw);
131
+ if (details === undefined) return undefined;
132
+ return makeNoticeComponent(details, themeFromRenderer(piTheme));
133
+ };
134
+
135
+ register(HIL_ANSWER_NOTICE_CUSTOM_TYPE, renderer);
136
+ rendererRegisteredHosts.add(host);
137
+ }
138
+
139
+ export function formatWorkflowHilAnswerNoticeText(details: WorkflowHilAnswerNoticeDetails): string {
140
+ const workflowName = escapeQuotedText(details.workflowName);
141
+ const stage = details.stageName ?? details.stageId;
142
+ const prompt = details.promptId ? `, prompt ${details.promptId}` : "";
143
+ const question = details.promptMessage ? ` Question: ${details.promptMessage}` : "";
144
+ const subject = `Workflow "${workflowName}" received the user's response for its pending human-in-the-loop prompt`;
145
+ const location = `(run ${details.runId}, stage ${stage}${prompt})`;
146
+ const instruction =
147
+ "Do not ask the same question again. No main-chat action is needed; do not answer any other workflow human-in-the-loop prompt unless the user explicitly provides that answer.";
148
+ return `✓ ${subject} ${location}.${question} User responded with: ${details.answerSummary}. ${instruction}`;
149
+ }
150
+
151
+ export function formatWorkflowHilAnswerInterruptAbortText(details: WorkflowHilAnswerNoticeDetails): string {
152
+ const workflowName = escapeQuotedText(details.workflowName);
153
+ const stage = details.stageName ?? details.stageId;
154
+ const prompt = details.promptId ? `, prompt ${details.promptId}` : "";
155
+ return `The main-chat question was dismissed because the user responded in the workflow chat for workflow "${workflowName}" (run ${details.runId}, stage ${stage}${prompt}). User responded with: ${details.answerSummary}. Do not ask the same question again.`;
156
+ }
157
+
158
+ function sendHilAnswerNotice(
159
+ send: NonNullable<ExtensionAPI["sendMessage"]>,
160
+ details: WorkflowHilAnswerNoticeDetails,
161
+ ): void {
162
+ const content = formatWorkflowHilAnswerNoticeText(details);
163
+ try {
164
+ void Promise.resolve(
165
+ send(
166
+ {
167
+ customType: HIL_ANSWER_NOTICE_CUSTOM_TYPE,
168
+ content,
169
+ display: true,
170
+ details,
171
+ },
172
+ {
173
+ triggerTurn: false,
174
+ excludeFromContext: true,
175
+ },
176
+ ),
177
+ ).catch((error: unknown) => warnHilAnswerSendFailure(error));
178
+ } catch (error) {
179
+ warnHilAnswerSendFailure(error);
180
+ }
181
+ }
182
+
183
+ function simplePromptAnswer(
184
+ previousStage: StageSnapshot,
185
+ currentRun: RunSnapshot,
186
+ ): { stage: StageSnapshot; prompt: PendingPrompt } | undefined {
187
+ const prompt = previousStage.pendingPrompt;
188
+ if (prompt === undefined) return undefined;
189
+ const currentStage = currentRun.stages.find((stage) => stage.id === previousStage.id);
190
+ if (currentStage === undefined) return undefined;
191
+ if (currentStage.pendingPrompt !== undefined) return undefined;
192
+ if (currentStage.promptAnswerState !== "available") return undefined;
193
+ return { stage: currentStage, prompt };
194
+ }
195
+
196
+ function findStageSnapshot(
197
+ snapshot: StoreSnapshot,
198
+ runId: string,
199
+ stageId: string,
200
+ ): { run: RunSnapshot; stage: StageSnapshot } | undefined {
201
+ const run = snapshot.runs.find((candidate) => candidate.id === runId);
202
+ const stage = run?.stages.find((candidate) => candidate.id === stageId);
203
+ if (run === undefined || stage === undefined) return undefined;
204
+ return { run, stage };
205
+ }
206
+
207
+ function readHilAnswerNoticeDetails(raw: unknown): WorkflowHilAnswerNoticeDetails | undefined {
208
+ if (typeof raw !== "object" || raw === null || !("details" in raw)) return undefined;
209
+ const message = raw as { details?: WorkflowHilAnswerNoticeDetails };
210
+ return message.details;
211
+ }
212
+
213
+ function makeSimplePromptAnswerNotice(
214
+ run: RunSnapshot,
215
+ stage: StageSnapshot,
216
+ prompt: PendingPrompt,
217
+ answer: unknown,
218
+ ): WorkflowHilAnswerNoticeDetails {
219
+ return {
220
+ kind: "hil_answered",
221
+ scope: "stage",
222
+ runId: run.id,
223
+ workflowName: run.name,
224
+ stageId: stage.id,
225
+ stageName: stage.name,
226
+ promptId: prompt.id,
227
+ promptKind: prompt.kind,
228
+ promptMessage: truncateAnswerSnippet(prompt.message),
229
+ answeredAt: Date.now(),
230
+ answerAvailable: true,
231
+ answerIncluded: true,
232
+ answerSummary: formatAnswerSummary(answer),
233
+ };
234
+ }
235
+
236
+ function makeBrokerPromptAnswerNotice(
237
+ run: RunSnapshot,
238
+ stage: StageSnapshot,
239
+ prompt: StageInputRequest,
240
+ answer: unknown,
241
+ answeredAt: number,
242
+ ): WorkflowHilAnswerNoticeDetails {
243
+ return {
244
+ kind: "hil_answered",
245
+ scope: "stage",
246
+ runId: run.id,
247
+ workflowName: run.name,
248
+ stageId: stage.id,
249
+ stageName: stage.name,
250
+ promptId: prompt.id,
251
+ promptKind: prompt.kind,
252
+ promptMessage: truncateAnswerSnippet(prompt.questions.map((question) => question.question).join(" | ")),
253
+ answeredAt,
254
+ answerAvailable: true,
255
+ answerIncluded: true,
256
+ answerSummary: formatAnswerSummary(answer),
257
+ };
258
+ }
259
+
260
+ function formatAnswerSummary(answer: unknown): string {
261
+ const questionnaire = formatQuestionnaireAnswer(answer);
262
+ if (questionnaire !== undefined) return questionnaire;
263
+ if (typeof answer === "string") return truncateAnswerSnippet(answer);
264
+ if (typeof answer === "number" || typeof answer === "boolean" || typeof answer === "bigint") {
265
+ return String(answer);
266
+ }
267
+ if (answer === null) return "null";
268
+ if (answer === undefined) return "(answer unavailable)";
269
+ try {
270
+ return truncateAnswerSnippet(JSON.stringify(answer));
271
+ } catch {
272
+ return truncateAnswerSnippet(String(answer));
273
+ }
274
+ }
275
+
276
+ function formatQuestionnaireAnswer(answer: unknown): string | undefined {
277
+ if (typeof answer !== "object" || answer === null || !("answers" in answer)) return undefined;
278
+ const answers = (answer as { answers?: unknown }).answers;
279
+ if (!Array.isArray(answers)) return undefined;
280
+ const parts = answers.map(formatQuestionnaireAnswerPart).filter((part) => part.length > 0);
281
+ if (parts.length > 0) return truncateAnswerSnippet(parts.join("; "));
282
+ const cancelled = (answer as { cancelled?: unknown }).cancelled === true;
283
+ return cancelled ? "(cancelled)" : "(no answer)";
284
+ }
285
+
286
+ function formatQuestionnaireAnswerPart(value: unknown): string {
287
+ if (typeof value !== "object" || value === null) return "";
288
+ const record = value as { question?: unknown; answer?: unknown; selected?: unknown; kind?: unknown };
289
+ const question = typeof record.question === "string" && record.question.trim().length > 0
290
+ ? record.question.trim()
291
+ : "Question";
292
+ const selected = Array.isArray(record.selected)
293
+ ? record.selected.filter((item): item is string => typeof item === "string" && item.length > 0).join(", ")
294
+ : "";
295
+ const answer = typeof record.answer === "string" && record.answer.length > 0
296
+ ? record.answer
297
+ : selected.length > 0
298
+ ? selected
299
+ : typeof record.kind === "string"
300
+ ? `(${record.kind})`
301
+ : "(no answer)";
302
+ return `${question} → ${answer}`;
303
+ }
304
+
305
+ function truncateAnswerSnippet(value: string): string {
306
+ const normalized = value.replace(/\s+/g, " ").trim();
307
+ if (normalized.length <= HIL_ANSWER_SNIPPET_LIMIT) return normalized;
308
+ return `${normalized.slice(0, HIL_ANSWER_SNIPPET_LIMIT - 1)}…`;
309
+ }
310
+
311
+ function answerNoticeKey(
312
+ runId: string,
313
+ stageId: string,
314
+ promptId: string | undefined,
315
+ promptKind: WorkflowHilAnswerPromptKind | undefined,
316
+ ): string {
317
+ return `hil_answered:${runId}:stage:${stageId}:${promptKind ?? "unknown"}:${promptId ?? "unknown"}`;
318
+ }
319
+
320
+ function warnHilAnswerSendFailure(error: unknown): void {
321
+ if (process.env.ATOMIC_WORKFLOW_DEBUG !== "1") return;
322
+ const message = error instanceof Error ? error.message : String(error);
323
+ console.warn("[workflows] workflow HiL answer notice send failed", message);
324
+ }
325
+
326
+ function escapeQuotedText(value: string): string {
327
+ return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
328
+ }
329
+
330
+ function makeNoticeComponent(
331
+ details: WorkflowHilAnswerNoticeDetails,
332
+ theme: GraphTheme | undefined,
333
+ ): PiMessageRenderComponent {
334
+ const text = formatWorkflowHilAnswerNoticeText(details);
335
+ return {
336
+ render(width: number): string[] {
337
+ return renderWorkflowNoticeCard({
338
+ title: "HIL ANSWERED",
339
+ glyph: "✓",
340
+ headline: `Workflow "${details.workflowName}" received the user's response`,
341
+ tone: "success",
342
+ fields: [
343
+ { label: "workflow", value: details.workflowName },
344
+ { label: "run", value: details.runId },
345
+ { label: "stage", value: details.stageName ?? details.stageId },
346
+ { label: "prompt", value: details.promptMessage, tone: "muted" },
347
+ { label: "answer", value: details.answerSummary },
348
+ ],
349
+ footer: "No main-chat action is needed; do not answer other workflow prompts unless the user explicitly provides that answer.",
350
+ fallbackText: text,
351
+ width,
352
+ ...(theme ? { theme } : {}),
353
+ });
354
+ },
355
+ invalidate() {
356
+ /* stored HiL-answer notices are immutable */
357
+ },
358
+ };
359
+ }
360
+
361
+ function themeFromRenderer(piTheme: unknown): GraphTheme | undefined {
362
+ return piTheme === undefined ? undefined : deriveGraphThemeFromPiTheme(piTheme);
363
+ }