@bastani/atomic 0.9.11-alpha.9 → 0.9.11

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 (285) hide show
  1. package/CHANGELOG.md +134 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/intercom/CHANGELOG.md +6 -0
  4. package/dist/builtin/intercom/package.json +1 -1
  5. package/dist/builtin/intercom/subagent-relay.ts +8 -5
  6. package/dist/builtin/mcp/CHANGELOG.md +10 -0
  7. package/dist/builtin/mcp/package.json +1 -1
  8. package/dist/builtin/subagents/CHANGELOG.md +20 -0
  9. package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
  10. package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
  11. package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
  12. package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
  13. package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
  14. package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
  15. package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
  16. package/dist/builtin/subagents/agents/worker.md +2 -2
  17. package/dist/builtin/subagents/package.json +1 -1
  18. package/dist/builtin/subagents/src/extension/notification-content.ts +14 -9
  19. package/dist/builtin/subagents/src/runs/background/notify.ts +20 -4
  20. package/dist/builtin/web-access/CHANGELOG.md +20 -0
  21. package/dist/builtin/web-access/content-tools.ts +1 -0
  22. package/dist/builtin/web-access/flat-string.ts +37 -0
  23. package/dist/builtin/web-access/github-api.ts +2 -1
  24. package/dist/builtin/web-access/github-extract.ts +3 -2
  25. package/dist/builtin/web-access/package.json +2 -2
  26. package/dist/builtin/workflows/CHANGELOG.md +57 -0
  27. package/dist/builtin/workflows/builtin/goal-ledger.ts +6 -4
  28. package/dist/builtin/workflows/builtin/goal-runner.ts +2 -1
  29. package/dist/builtin/workflows/builtin/goal.ts +1 -1
  30. package/dist/builtin/workflows/builtin/ralph-core.ts +8 -9
  31. package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +2 -4
  32. package/dist/builtin/workflows/builtin/ralph-models.ts +4 -4
  33. package/dist/builtin/workflows/builtin/ralph-runner.ts +5 -8
  34. package/dist/builtin/workflows/builtin/ralph.ts +2 -1
  35. package/dist/builtin/workflows/package.json +1 -1
  36. package/dist/builtin/workflows/src/durable/completed-catalog.ts +14 -8
  37. package/dist/builtin/workflows/src/durable/completed-inspection.ts +10 -11
  38. package/dist/builtin/workflows/src/durable/resume-catalog.ts +1 -1
  39. package/dist/builtin/workflows/src/durable/resume-eligibility.ts +42 -0
  40. package/dist/builtin/workflows/src/durable/resume-runtime.ts +36 -37
  41. package/dist/builtin/workflows/src/durable/tool-primitive.ts +10 -2
  42. package/dist/builtin/workflows/src/engine/run.ts +1 -0
  43. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +12 -8
  44. package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +5 -2
  45. package/dist/builtin/workflows/src/extension/index.bundle.mjs +1966 -880
  46. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +6 -3
  47. package/dist/builtin/workflows/src/extension/postmortem-deps.ts +3 -2
  48. package/dist/builtin/workflows/src/extension/render-result.ts +4 -11
  49. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +17 -20
  50. package/dist/builtin/workflows/src/extension/runtime.ts +3 -3
  51. package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +1 -1
  52. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +3 -7
  53. package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +21 -24
  54. package/dist/builtin/workflows/src/extension/workflow-resume-picker-rows.ts +38 -26
  55. package/dist/builtin/workflows/src/extension/workflow-resume-shadow.ts +2 -1
  56. package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +56 -64
  57. package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -2
  58. package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +0 -5
  59. package/dist/builtin/workflows/src/extension/workflow-targets.ts +17 -20
  60. package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +1 -1
  61. package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +24 -51
  62. package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +7 -29
  63. package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +5 -13
  64. package/dist/builtin/workflows/src/extension/workflow-tool.ts +4 -13
  65. package/dist/builtin/workflows/src/runs/background/quit.ts +4 -3
  66. package/dist/builtin/workflows/src/runs/background/run-inspect.ts +8 -8
  67. package/dist/builtin/workflows/src/runs/background/status.ts +2 -1
  68. package/dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts +2 -1
  69. package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
  70. package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +4 -0
  71. package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +2 -0
  72. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +23 -8
  73. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +6 -2
  74. package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +5 -0
  75. package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +56 -10
  76. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +6 -0
  77. package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +137 -6
  78. package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +2 -0
  79. package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +2 -0
  80. package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +159 -10
  81. package/dist/builtin/workflows/src/shared/flat-string.ts +33 -0
  82. package/dist/builtin/workflows/src/shared/graph-store-snapshot.ts +144 -0
  83. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +2 -3
  84. package/dist/builtin/workflows/src/shared/run-id.ts +36 -0
  85. package/dist/builtin/workflows/src/shared/store-internal.ts +32 -3
  86. package/dist/builtin/workflows/src/shared/store-observation.ts +10 -0
  87. package/dist/builtin/workflows/src/shared/store-public-types.ts +8 -0
  88. package/dist/builtin/workflows/src/shared/store-run-methods.ts +14 -0
  89. package/dist/builtin/workflows/src/shared/store-types.ts +4 -0
  90. package/dist/builtin/workflows/src/shared/types.ts +2 -0
  91. package/dist/builtin/workflows/src/shared/workflow-artifacts.ts +261 -0
  92. package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +39 -23
  93. package/dist/builtin/workflows/src/tui/graph-canvas.ts +26 -9
  94. package/dist/builtin/workflows/src/tui/graph-view-constants.ts +3 -0
  95. package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +95 -98
  96. package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -20
  97. package/dist/builtin/workflows/src/tui/graph-view-state.ts +160 -13
  98. package/dist/builtin/workflows/src/tui/layout.ts +8 -2
  99. package/dist/builtin/workflows/src/tui/node-card.ts +57 -45
  100. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -2
  101. package/dist/builtin/workflows/src/tui/prompt-card-render.ts +291 -21
  102. package/dist/builtin/workflows/src/tui/prompt-card.ts +1 -1
  103. package/dist/builtin/workflows/src/tui/renderers.ts +0 -1
  104. package/dist/builtin/workflows/src/tui/run-detail.ts +52 -35
  105. package/dist/builtin/workflows/src/tui/run-identity-rows.ts +97 -0
  106. package/dist/builtin/workflows/src/tui/session-overlays.ts +24 -3
  107. package/dist/builtin/workflows/src/tui/session-picker.ts +94 -41
  108. package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +190 -26
  109. package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +52 -18
  110. package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +9 -5
  111. package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +44 -4
  112. package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +3 -1
  113. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -2
  114. package/dist/builtin/workflows/src/tui/status-list.ts +67 -45
  115. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -6
  116. package/dist/builtin/workflows/src/tui/widget.ts +49 -40
  117. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +15 -10
  118. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +21 -8
  119. package/dist/core/agent-session-accessors.d.ts.map +1 -1
  120. package/dist/core/agent-session-accessors.js +5 -0
  121. package/dist/core/agent-session-accessors.js.map +1 -1
  122. package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
  123. package/dist/core/agent-session-auto-compaction.js +5 -0
  124. package/dist/core/agent-session-auto-compaction.js.map +1 -1
  125. package/dist/core/agent-session-compaction.d.ts.map +1 -1
  126. package/dist/core/agent-session-compaction.js +3 -0
  127. package/dist/core/agent-session-compaction.js.map +1 -1
  128. package/dist/core/agent-session-events.d.ts.map +1 -1
  129. package/dist/core/agent-session-events.js +2 -1
  130. package/dist/core/agent-session-events.js.map +1 -1
  131. package/dist/core/agent-session-message-queue.d.ts +3 -7
  132. package/dist/core/agent-session-message-queue.d.ts.map +1 -1
  133. package/dist/core/agent-session-message-queue.js +27 -13
  134. package/dist/core/agent-session-message-queue.js.map +1 -1
  135. package/dist/core/agent-session-methods.d.ts +5 -3
  136. package/dist/core/agent-session-methods.d.ts.map +1 -1
  137. package/dist/core/agent-session-methods.js.map +1 -1
  138. package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
  139. package/dist/core/agent-session-persistent-custom-messages.js +6 -3
  140. package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
  141. package/dist/core/agent-session-post-tool-compaction.d.ts.map +1 -1
  142. package/dist/core/agent-session-post-tool-compaction.js +11 -2
  143. package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
  144. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  145. package/dist/core/agent-session-runtime.js +5 -3
  146. package/dist/core/agent-session-runtime.js.map +1 -1
  147. package/dist/core/agent-session-tree.d.ts.map +1 -1
  148. package/dist/core/agent-session-tree.js +4 -0
  149. package/dist/core/agent-session-tree.js.map +1 -1
  150. package/dist/core/agent-session-types.d.ts +4 -0
  151. package/dist/core/agent-session-types.d.ts.map +1 -1
  152. package/dist/core/agent-session-types.js.map +1 -1
  153. package/dist/core/agent-session.d.ts +2 -1
  154. package/dist/core/agent-session.d.ts.map +1 -1
  155. package/dist/core/agent-session.js +1 -0
  156. package/dist/core/agent-session.js.map +1 -1
  157. package/dist/core/auth-storage-backends.d.ts.map +1 -1
  158. package/dist/core/auth-storage-backends.js +12 -1
  159. package/dist/core/auth-storage-backends.js.map +1 -1
  160. package/dist/core/bounded-model-refresh.d.ts +14 -0
  161. package/dist/core/bounded-model-refresh.d.ts.map +1 -0
  162. package/dist/core/bounded-model-refresh.js +38 -0
  163. package/dist/core/bounded-model-refresh.js.map +1 -0
  164. package/dist/core/context-tool-pairing.d.ts +4 -4
  165. package/dist/core/context-tool-pairing.js +4 -4
  166. package/dist/core/context-tool-pairing.js.map +1 -1
  167. package/dist/core/http-dispatcher.d.ts.map +1 -1
  168. package/dist/core/http-dispatcher.js +26 -1
  169. package/dist/core/http-dispatcher.js.map +1 -1
  170. package/dist/core/messages.d.ts +18 -6
  171. package/dist/core/messages.d.ts.map +1 -1
  172. package/dist/core/messages.js +46 -18
  173. package/dist/core/messages.js.map +1 -1
  174. package/dist/core/model-refresh-timeout.d.ts +9 -0
  175. package/dist/core/model-refresh-timeout.d.ts.map +1 -0
  176. package/dist/core/model-refresh-timeout.js +9 -0
  177. package/dist/core/model-refresh-timeout.js.map +1 -0
  178. package/dist/core/model-runtime-snapshot.d.ts +3 -0
  179. package/dist/core/model-runtime-snapshot.d.ts.map +1 -1
  180. package/dist/core/model-runtime-snapshot.js +59 -0
  181. package/dist/core/model-runtime-snapshot.js.map +1 -1
  182. package/dist/core/model-runtime.d.ts +7 -1
  183. package/dist/core/model-runtime.d.ts.map +1 -1
  184. package/dist/core/model-runtime.js +72 -17
  185. package/dist/core/model-runtime.js.map +1 -1
  186. package/dist/core/sdk.d.ts.map +1 -1
  187. package/dist/core/sdk.js +4 -3
  188. package/dist/core/sdk.js.map +1 -1
  189. package/dist/core/session-manager-core.d.ts +1 -1
  190. package/dist/core/session-manager-core.d.ts.map +1 -1
  191. package/dist/core/session-manager-core.js +2 -2
  192. package/dist/core/session-manager-core.js.map +1 -1
  193. package/dist/core/session-manager-entries.d.ts +1 -1
  194. package/dist/core/session-manager-entries.d.ts.map +1 -1
  195. package/dist/core/session-manager-entries.js +2 -1
  196. package/dist/core/session-manager-entries.js.map +1 -1
  197. package/dist/core/session-manager-history.d.ts.map +1 -1
  198. package/dist/core/session-manager-history.js +2 -2
  199. package/dist/core/session-manager-history.js.map +1 -1
  200. package/dist/core/session-manager-types.d.ts +3 -0
  201. package/dist/core/session-manager-types.d.ts.map +1 -1
  202. package/dist/core/session-manager-types.js.map +1 -1
  203. package/dist/index.d.ts +1 -1
  204. package/dist/index.d.ts.map +1 -1
  205. package/dist/index.js.map +1 -1
  206. package/dist/main-app-mode.d.ts +1 -0
  207. package/dist/main-app-mode.d.ts.map +1 -1
  208. package/dist/main-app-mode.js +3 -0
  209. package/dist/main-app-mode.js.map +1 -1
  210. package/dist/main.d.ts.map +1 -1
  211. package/dist/main.js +8 -3
  212. package/dist/main.js.map +1 -1
  213. package/dist/modes/interactive/components/chat-session-host-actions.d.ts +7 -2
  214. package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
  215. package/dist/modes/interactive/components/chat-session-host-actions.js +13 -4
  216. package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
  217. package/dist/modes/interactive/components/chat-session-host-editor.d.ts +3 -1
  218. package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
  219. package/dist/modes/interactive/components/chat-session-host-editor.js +2 -2
  220. package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
  221. package/dist/modes/interactive/components/chat-session-host-events.d.ts +3 -0
  222. package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
  223. package/dist/modes/interactive/components/chat-session-host-events.js +5 -4
  224. package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
  225. package/dist/modes/interactive/components/chat-session-host.d.ts +16 -2
  226. package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
  227. package/dist/modes/interactive/components/chat-session-host.js +35 -5
  228. package/dist/modes/interactive/components/chat-session-host.js.map +1 -1
  229. package/dist/modes/interactive/components/index.d.ts +1 -0
  230. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  231. package/dist/modes/interactive/components/index.js.map +1 -1
  232. package/dist/modes/interactive/components/model-selector.d.ts +0 -1
  233. package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
  234. package/dist/modes/interactive/components/model-selector.js +25 -35
  235. package/dist/modes/interactive/components/model-selector.js.map +1 -1
  236. package/dist/modes/interactive/interactive-editor-actions.js +2 -1
  237. package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
  238. package/dist/modes/interactive/interactive-input-handling.js +1 -1
  239. package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
  240. package/dist/modes/interactive/interactive-mode-surface.d.ts +4 -1
  241. package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
  242. package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
  243. package/dist/modes/interactive/interactive-model-routing.js +4 -1
  244. package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
  245. package/dist/modes/interactive/interactive-pause.d.ts +3 -1
  246. package/dist/modes/interactive/interactive-pause.d.ts.map +1 -1
  247. package/dist/modes/interactive/interactive-pause.js +5 -1
  248. package/dist/modes/interactive/interactive-pause.js.map +1 -1
  249. package/dist/modes/interactive/interactive-queueing.js +3 -3
  250. package/dist/modes/interactive/interactive-queueing.js.map +1 -1
  251. package/dist/modes/interactive-engine/engine-health.d.ts +6 -0
  252. package/dist/modes/interactive-engine/engine-health.d.ts.map +1 -1
  253. package/dist/modes/interactive-engine/engine-health.js +15 -1
  254. package/dist/modes/interactive-engine/engine-health.js.map +1 -1
  255. package/dist/modes/interactive-engine/isolated-auth.js +1 -1
  256. package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
  257. package/dist/modes/interactive-engine/isolated-runtime.d.ts +1 -0
  258. package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
  259. package/dist/modes/interactive-engine/isolated-runtime.js +7 -1
  260. package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
  261. package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
  262. package/dist/modes/interactive-engine/remote-model-catalog.js +5 -1
  263. package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
  264. package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
  265. package/dist/modes/rpc/rpc-command-handler.js +23 -7
  266. package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
  267. package/dist/modes/rpc/rpc-input-scheduler.js +1 -1
  268. package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
  269. package/dist/modes/rpc/rpc-types.d.ts +2 -1
  270. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  271. package/dist/modes/rpc/rpc-types.js.map +1 -1
  272. package/docs/custom-provider.md +3 -3
  273. package/docs/extensions.md +3 -1
  274. package/docs/index.md +10 -0
  275. package/docs/keybindings.md +1 -1
  276. package/docs/models.md +2 -0
  277. package/docs/providers.md +7 -3
  278. package/docs/quickstart.md +7 -1
  279. package/docs/session-format.md +2 -0
  280. package/docs/termux.md +3 -1
  281. package/docs/usage.md +3 -2
  282. package/docs/workflows.md +82 -46
  283. package/npm-shrinkwrap.json +59 -27
  284. package/package.json +3 -3
  285. package/dist/builtin/workflows/src/tui/toast.ts +0 -107
@@ -1,4 +1,5 @@
1
1
  import { getDurableBackend } from "../durable/factory.js";
2
+ import { isWorkflowRunResumable } from "../durable/resume-eligibility.js";
2
3
  import type { ResumableWorkflowEntry } from "../durable/types.js";
3
4
  import { hasPendingDurableResumeTransition } from "../runs/background/durable-resume-transition.js";
4
5
  import { quitAllRuns, quitRun } from "../runs/background/quit.js";
@@ -6,6 +7,7 @@ import { interruptAllRuns, interruptRun, pauseRun, resumeRun } from "../runs/bac
6
7
  import { workflowHasPausedStages, workflowHasPausedState } from "../runs/background/workflow-lifecycle-aggregate.js";
7
8
  import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
8
9
  import { store } from "../shared/store.js";
10
+ import { workflowRunResumeCandidate } from "../shared/workflow-artifacts.js";
9
11
  import { deriveGraphTheme } from "../tui/graph-theme.js";
10
12
  import { renderSessionList } from "../tui/session-list.js";
11
13
  import { openSessionPicker } from "../tui/session-overlays.js";
@@ -28,7 +30,7 @@ import {
28
30
  resumePickerLiveUpdateOptions,
29
31
  } from "./workflow-resume-picker-rows.js";
30
32
  import { classifyDurableResumeShadow, reconcileDurableResumeShadow } from "./workflow-resume-shadow.js";
31
- import { overlaySurfaceFromContext, resolveRunIdPrefix, resolveStageTarget } from "./workflow-targets.js";
33
+ import { overlaySurfaceFromContext, resolveRunId, resolveStageTarget } from "./workflow-targets.js";
32
34
 
33
35
  export type { WorkflowRunControlDeps } from "./workflow-durable-resume-command.js";
34
36
 
@@ -56,10 +58,10 @@ export async function handleRunControlCommand(
56
58
  const theme = deriveGraphTheme({});
57
59
  const failHeadlessAttachCommand = (targetAction: "connect" | "attach", runId: string, stageId?: string): boolean => {
58
60
  if (policy.allowInputPicker) return false;
59
- const displayTarget = stageId ? `${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}` : runId.slice(0, 8);
61
+ const displayTarget = stageId ? `${runId} stage ${stageId}` : runId;
60
62
  fail(
61
63
  `/workflow ${targetAction} requires an interactive UI surface and cannot attach in non-interactive mode. ` +
62
- `Target: ${displayTarget}. Use /workflow status ${runId.slice(0, 8)} or the workflow tool's status/stages/transcript actions for non-interactive inspection.`,
64
+ `Target: ${displayTarget}. Use /workflow status ${runId} or the workflow tool's status/stages/transcript actions for non-interactive inspection.`,
63
65
  );
64
66
  return true;
65
67
  };
@@ -82,20 +84,18 @@ export async function handleRunControlCommand(
82
84
  }
83
85
  return true;
84
86
  }
85
- const resolved = resolveRunIdPrefix(target);
86
- if (resolved.kind === "not_found") {
87
- fail(`Run not found: ${target}\n\n${renderSessionList(store.runs(), { theme, includeAll: true })}`);
87
+ const resolved = resolveRunId(target);
88
+ if (resolved.kind === "malformed") {
89
+ fail(resolved.message);
88
90
  return true;
89
91
  }
90
- if (resolved.kind === "ambiguous") {
91
- fail(`Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`);
92
+ if (resolved.kind === "not_found") {
93
+ fail(`Run not found: ${target}\n\n${renderSessionList(store.runs(), { theme, includeAll: true })}`);
92
94
  return true;
93
95
  }
94
96
  if (failHeadlessAttachCommand("connect", resolved.runId)) return true;
95
97
  if (policy.allowInputPicker) deps.overlay.open(resolved.runId, overlaySurfaceFromContext(ctx));
96
- print(
97
- `Connected to ${resolved.runId.slice(0, 8)}. h hide · ctrl+x leave graph · return to main chat · esc close.`,
98
- );
98
+ print(`Connected to ${resolved.runId}. h hide · ctrl+x leave graph · return to main chat · esc close.`);
99
99
  return true;
100
100
  }
101
101
 
@@ -123,7 +123,7 @@ export async function handleRunControlCommand(
123
123
  }
124
124
  if (action === "interrupt" && !yes && confirmationPrompt) {
125
125
  const title = `Interrupt all ${inFlight.length} in-flight workflow runs?`;
126
- const body = `Pauses: ${inFlight.map((run) => `${run.name} (${run.id.slice(0, 8)})`).join(", ")}`;
126
+ const body = `Pauses: ${inFlight.map((run) => `${run.name} (${run.id})`).join(", ")}`;
127
127
  if (!(await confirmationPrompt(title, body))) {
128
128
  print("Cancelled.");
129
129
  return true;
@@ -155,29 +155,27 @@ export async function handleRunControlCommand(
155
155
  }
156
156
  return true;
157
157
  }
158
- const resolved = resolveRunIdPrefix(target!);
159
- if (resolved.kind === "not_found") {
160
- fail(`Run not found: ${target}`);
158
+ const resolved = resolveRunId(target!);
159
+ if (resolved.kind === "malformed") {
160
+ fail(resolved.message);
161
161
  return true;
162
162
  }
163
- if (resolved.kind === "ambiguous") {
164
- fail(
165
- `Ambiguous run prefix "${target}" matches multiple runs: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
166
- );
163
+ if (resolved.kind === "not_found") {
164
+ fail(`Run not found: ${target}`);
167
165
  return true;
168
166
  }
169
167
  const run = store.runs().find((candidate) => candidate.id === resolved.runId);
170
168
  if (action === "quit") {
171
169
  if (run?.endedAt !== undefined) {
172
- print(`Run ${resolved.runId.slice(0, 8)} already ended.`);
170
+ print(`Run ${resolved.runId} already ended.`);
173
171
  return true;
174
172
  }
175
173
  try {
176
174
  const result = await quitRun(resolved.runId);
177
- if (result.ok) print(`Run ${result.runId.slice(0, 8)} quit and can be resumed with /workflow resume.`);
178
- else if (result.reason === "already_ended") print(`Run ${result.runId.slice(0, 8)} already ended.`);
175
+ if (result.ok) print(`Run ${result.runId} quit and can be resumed with /workflow resume.`);
176
+ else if (result.reason === "already_ended") print(`Run ${result.runId} already ended.`);
179
177
  else if (result.reason === "no_active_stages") {
180
- fail(`No controllable stages on run ${result.runId.slice(0, 8)}; the run remains active.`);
178
+ fail(`No controllable stages on run ${result.runId}; the run remains active.`);
181
179
  } else fail(`Run not found: ${target}`);
182
180
  } catch (error) {
183
181
  fail(`Failed to quit run ${resolved.runId}: ${error instanceof Error ? error.message : String(error)}`);
@@ -186,17 +184,17 @@ export async function handleRunControlCommand(
186
184
  }
187
185
  if (!yes && run && run.endedAt === undefined && confirmationPrompt) {
188
186
  const confirmed = await confirmationPrompt(
189
- `Interrupt workflow run ${run.name} (${run.id.slice(0, 8)})?`,
187
+ `Interrupt workflow run ${run.name} (${run.id})?`,
190
188
  "Pauses live work so it can be resumed later.",
191
189
  );
192
190
  if (!confirmed) {
193
- print(`Cancelled. Run ${resolved.runId.slice(0, 8)} is still active.`);
191
+ print(`Cancelled. Run ${resolved.runId} is still active.`);
194
192
  return true;
195
193
  }
196
194
  }
197
195
  try {
198
196
  const result = await interruptRun(resolved.runId);
199
- if (result.ok) print(`Run ${result.runId.slice(0, 8)} interrupted and can be resumed.`);
197
+ if (result.ok) print(`Run ${result.runId} interrupted and can be resumed.`);
200
198
  else
201
199
  fail(
202
200
  result.reason === "not_found"
@@ -204,8 +202,8 @@ export async function handleRunControlCommand(
204
202
  : result.reason === "already_ended"
205
203
  ? `Run already ended: ${target}`
206
204
  : result.reason === "stage_not_found"
207
- ? `Stage not found for run ${resolved.runId.slice(0, 8)}.`
208
- : `No active stages to interrupt on run ${resolved.runId.slice(0, 8)}.`,
205
+ ? `Stage not found for run ${resolved.runId}.`
206
+ : `No active stages to interrupt on run ${resolved.runId}.`,
209
207
  );
210
208
  } catch (error) {
211
209
  fail(`Failed to interrupt run ${resolved.runId}: ${error instanceof Error ? error.message : String(error)}`);
@@ -225,7 +223,7 @@ export async function handleRunControlCommand(
225
223
  fail(
226
224
  active.length === 0
227
225
  ? "No active runs to pause."
228
- : `Picker requires an interactive UI surface. Active runs:\n${active.map((r) => ` ${r.id.slice(0, 8)} ${r.name}`).join("\n")}\n\nUsage: /workflow pause <runId> [stageId]`,
226
+ : `Picker requires an interactive UI surface. Active runs:\n${active.map((r) => ` ${r.id} ${r.name}`).join("\n")}\n\nUsage: /workflow pause <runId> [stageId]`,
229
227
  );
230
228
  } else if (action === "attach") {
231
229
  fail(
@@ -246,7 +244,7 @@ export async function handleRunControlCommand(
246
244
  const runtime = deps.runtimeForContext(ctx);
247
245
  const hydrate = async (): Promise<ResumePickerCatalogRows> => {
248
246
  await ensureWorkflowResourcesVisible();
249
- const catalog = await prepareWorkflowResumeCatalog(runtime, initial.activeLiveIds);
247
+ const catalog = await prepareWorkflowResumeCatalog(runtime, initial.suppressedLiveIds);
250
248
  return { durable: catalog.resumable, completed: catalog.completed };
251
249
  };
252
250
  let picked: Awaited<ReturnType<typeof openWorkflowResumeSelector>>;
@@ -270,20 +268,18 @@ export async function handleRunControlCommand(
270
268
  });
271
269
  }
272
270
  if (picked.result.kind === "live") {
273
- const resolved = resolveRunIdPrefix(picked.result.runId);
271
+ const resolved = resolveRunId(picked.result.runId);
274
272
  if (resolved.kind !== "exact") {
275
273
  fail(`Run not found: ${picked.result.runId}`);
276
274
  return true;
277
275
  }
278
276
  const run = store.runs().find((r) => r.id === resolved.runId);
279
- const isPaused = run?.status === "paused" || (run?.stages.some((s) => s.status === "paused") ?? false);
277
+ const isPaused = run !== undefined && workflowHasPausedState(store, resolved.runId);
280
278
  const isResumableContinuation =
281
279
  run !== undefined &&
282
280
  !isPaused &&
283
- ((run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
284
- (run.endedAt === undefined &&
285
- run.resumable === true &&
286
- run.failureRecoverability === "recoverable"));
281
+ run.exitReason !== "quit" &&
282
+ isWorkflowRunResumable(workflowRunResumeCandidate(run));
287
283
  if (isResumableContinuation) {
288
284
  await ensureWorkflowResourcesVisible();
289
285
  const continuation = await deps
@@ -302,7 +298,7 @@ export async function handleRunControlCommand(
302
298
  if (result.ok && policy.allowInputPicker)
303
299
  deps.overlay.open(result.runId, overlaySurfaceFromContext(ctx));
304
300
  result.ok
305
- ? print(result.message ?? `Resumed ${result.runId.slice(0, 8)}`)
301
+ ? print(result.message ?? `Resumed ${result.runId}`)
306
302
  : fail(`Run not found: ${picked.result.runId}`);
307
303
  }
308
304
  } catch (error) {
@@ -319,7 +315,7 @@ export async function handleRunControlCommand(
319
315
  runId = picked.runId;
320
316
  } else if (action === "resume") {
321
317
  const backend = getDurableBackend();
322
- const localResolution = resolveRunIdPrefix(target);
318
+ const localResolution = resolveRunId(target);
323
319
  const localBeforePreparation =
324
320
  localResolution.kind === "exact" ? store.runs().find((run) => run.id === localResolution.runId) : undefined;
325
321
  const exactBeforePreparation = localBeforePreparation?.id === target ? localBeforePreparation : undefined;
@@ -352,7 +348,7 @@ export async function handleRunControlCommand(
352
348
  !hasPendingDurableResumeTransition(exactBeforePreparation.id);
353
349
  if (exactIsActivelyRunning) {
354
350
  fail(
355
- `Workflow ${exactBeforePreparation.id.slice(0, 8)} is already running in this session. Attach with \`/workflow connect ${exactBeforePreparation.id.slice(0, 8)}\` instead of resuming.`,
351
+ `Workflow ${exactBeforePreparation.id} is already running in this session. Attach with \`/workflow connect ${exactBeforePreparation.id}\` instead of resuming.`,
356
352
  );
357
353
  return true;
358
354
  }
@@ -393,10 +389,8 @@ export async function handleRunControlCommand(
393
389
  durable,
394
390
  backend.listCompletedWorkflows(),
395
391
  );
396
- if (combined.kind === "ambiguous") {
397
- fail(
398
- `Ambiguous workflow prefix "${target}" matches: ${combined.matches.map((match) => `${match.name} (${match.workflowId.slice(0, 8)})`).join(", ")}`,
399
- );
392
+ if (combined.kind === "malformed") {
393
+ fail(combined.message);
400
394
  return true;
401
395
  }
402
396
  if (combined.kind === "completed" || combined.kind === "durable") {
@@ -412,15 +406,13 @@ export async function handleRunControlCommand(
412
406
  }
413
407
  }
414
408
  } else {
415
- const resolved = resolveRunIdPrefix(target);
416
- if (resolved.kind === "not_found") {
417
- fail(`Run not found: ${target}`);
409
+ const resolved = resolveRunId(target);
410
+ if (resolved.kind === "malformed") {
411
+ fail(resolved.message);
418
412
  return true;
419
413
  }
420
- if (resolved.kind === "ambiguous") {
421
- fail(
422
- `Ambiguous run prefix "${target}" matches: ${resolved.matches.map((id) => id.slice(0, 12)).join(", ")}`,
423
- );
414
+ if (resolved.kind === "not_found") {
415
+ fail(`Run not found: ${target}`);
424
416
  return true;
425
417
  }
426
418
  runId = resolved.runId;
@@ -437,8 +429,8 @@ export async function handleRunControlCommand(
437
429
  if (policy.allowInputPicker) deps.overlay.open(runId, overlaySurfaceFromContext(ctx), stageId, stageRunId);
438
430
  print(
439
431
  stageId
440
- ? `Attached to ${runId.slice(0, 8)} stage ${stageId.slice(0, 8)}. ctrl+x return to graph · esc close.`
441
- : `Attached to ${runId.slice(0, 8)}. ↵ chat · ctrl+x leave graph · return to main chat.`,
432
+ ? `Attached to ${runId} stage ${stageId}. ctrl+x return to graph · esc close.`
433
+ : `Attached to ${runId}. ↵ chat · ctrl+x leave graph · return to main chat.`,
442
434
  );
443
435
  return true;
444
436
  }
@@ -455,11 +447,11 @@ export async function handleRunControlCommand(
455
447
  if (!result.ok) {
456
448
  fail(
457
449
  result.reason === "not_found"
458
- ? `Run not found: ${stageRunId.slice(0, 8)}`
450
+ ? `Run not found: ${stageRunId}`
459
451
  : result.reason === "already_ended"
460
- ? `Run ${stageRunId.slice(0, 8)} already ended.`
452
+ ? `Run ${stageRunId} already ended.`
461
453
  : result.reason === "no_active_stages"
462
- ? `No pausable stages on run ${stageRunId.slice(0, 8)}.`
454
+ ? `No pausable stages on run ${stageRunId}.`
463
455
  : `Stage not found: ${stageTarget ?? "(unknown)"}`,
464
456
  );
465
457
  return true;
@@ -467,8 +459,8 @@ export async function handleRunControlCommand(
467
459
  if (policy.allowInputPicker) deps.overlay.open(runId, overlaySurfaceFromContext(ctx), stageId, stageRunId);
468
460
  print(
469
461
  result.paused.length === 0
470
- ? `No stages were paused on run ${stageRunId.slice(0, 8)}.`
471
- : `Paused ${result.paused.length} stage(s) on run ${stageRunId.slice(0, 8)}: ${result.paused.map((stage) => stage.name).join(", ")}`,
462
+ ? `No stages were paused on run ${stageRunId}.`
463
+ : `Paused ${result.paused.length} stage(s) on run ${stageRunId}: ${result.paused.map((stage) => stage.name).join(", ")}`,
472
464
  );
473
465
  } catch (error) {
474
466
  fail(`Failed to pause run ${stageRunId}: ${error instanceof Error ? error.message : String(error)}`);
@@ -482,8 +474,8 @@ export async function handleRunControlCommand(
482
474
  const isResumableContinuation =
483
475
  run !== undefined &&
484
476
  !isPaused &&
485
- ((run.status === "failed" && run.endedAt !== undefined && run.resumable !== false) ||
486
- (run.endedAt === undefined && run.resumable === true && run.failureRecoverability === "recoverable"));
477
+ run.exitReason !== "quit" &&
478
+ isWorkflowRunResumable(workflowRunResumeCandidate(run));
487
479
  const isActivelyRunning =
488
480
  run !== undefined &&
489
481
  run.endedAt === undefined &&
@@ -497,7 +489,7 @@ export async function handleRunControlCommand(
497
489
  !hasPendingDurableResumeTransition(stageRunId)
498
490
  ) {
499
491
  fail(
500
- `Workflow ${stageRunId.slice(0, 8)} is already running in this session. Attach with \`/workflow connect ${stageRunId.slice(0, 8)}\` instead of resuming.`,
492
+ `Workflow ${stageRunId} is already running in this session. Attach with \`/workflow connect ${stageRunId}\` instead of resuming.`,
501
493
  );
502
494
  return true;
503
495
  }
@@ -521,7 +513,7 @@ export async function handleRunControlCommand(
521
513
  return true;
522
514
  }
523
515
  if (!result.ok) {
524
- fail(`Run not found: ${stageRunId.slice(0, 8)}`);
516
+ fail(`Run not found: ${stageRunId}`);
525
517
  return true;
526
518
  }
527
519
  if (result.mode === "partial") {
@@ -546,11 +538,11 @@ export async function handleRunControlCommand(
546
538
  const runLevelResumed =
547
539
  hadPausedRunState && !hadPausedStageState && stageId === undefined && result.snapshot.status === "running";
548
540
  if (result.message !== undefined) print(result.message);
549
- else if (runLevelResumed) print(`Resumed run ${stageRunId.slice(0, 8)}.`);
550
- else fail(`No paused stages on run ${stageRunId.slice(0, 8)}.`);
541
+ else if (runLevelResumed) print(`Resumed run ${stageRunId}.`);
542
+ else fail(`No paused stages on run ${stageRunId}.`);
551
543
  } else {
552
544
  print(
553
- `Resumed ${result.resumed.length} stage(s) on run ${stageRunId.slice(0, 8)}${message ? ` with message: "${message}"` : ""}.`,
545
+ `Resumed ${result.resumed.length} stage(s) on run ${stageRunId}${message ? ` with message: "${message}"` : ""}.`,
554
546
  );
555
547
  }
556
548
  return true;
@@ -41,7 +41,7 @@ export const WorkflowParametersSchema = Type.Object(
41
41
  runId: Type.Optional(
42
42
  Type.String({
43
43
  description:
44
- "Run identifier or unique prefix for status/stages/stage/transcript/send/pause/resume/interrupt/quit. Omit runId with action 'status' to list all session runs and their statuses. Use '--all' or all:true for supported bulk run-control actions.",
44
+ "Full 36-character run UUID for status/stages/stage/transcript/send/pause/resume/interrupt/quit. Prefixes are not accepted; pass the id exactly as displayed. Omit runId with action 'status' to list all session runs and their statuses. Use '--all' or all:true for supported bulk run-control actions.",
45
45
  }),
46
46
  ),
47
47
  all: Type.Optional(
@@ -53,7 +53,7 @@ export const WorkflowParametersSchema = Type.Object(
53
53
  stageId: Type.Optional(
54
54
  Type.String({
55
55
  description:
56
- "Stage id, unique prefix, or stage name for stage-scoped inspection, transcript, send, pause, or resume. For interrupt and quit it may also name an in-flight ctx.tool node by its tool:<argsHash> id or tool name, which aborts that single call.",
56
+ "Exact stage id or exact stage name for stage-scoped inspection, transcript, send, pause, or resume. Prefixes and partial names are not accepted. A nested stage id is the full 'runId:stageId' composite. For interrupt and quit it may also name an in-flight ctx.tool node by its exact tool:<argsHash> id or tool name, which aborts that single call.",
57
57
  }),
58
58
  ),
59
59
  message: Type.Optional(
@@ -33,8 +33,6 @@ import { elapsedRunMs } from "../shared/timing.js";
33
33
  */
34
34
  export type WorkflowRunStatusFilter = StageStatus | RunStatus | "all";
35
35
 
36
- const RUN_ID_PREFIX_LEN = 8;
37
-
38
36
  /** A currently active (running or awaiting-input) stage within a run. */
39
37
  export interface WorkflowStatusActiveStage {
40
38
  /** Expanded-graph stage id; valid for stage-scoped send/pause/resume. */
@@ -81,8 +79,6 @@ export interface WorkflowStatusToolNode {
81
79
  */
82
80
  export interface WorkflowRunStatusSummary {
83
81
  readonly runId: string;
84
- /** Abbreviated run id as printed by status surfaces; a valid prefix input. */
85
- readonly runIdPrefix: string;
86
82
  /** Workflow/run name. */
87
83
  readonly name: string;
88
84
  readonly status: RunStatus;
@@ -152,7 +148,6 @@ export function summarizeRunSnapshot(run: RunSnapshot, now = Date.now()): Workfl
152
148
  const awaitingInput = awaitingInputEntries(run);
153
149
  return {
154
150
  runId: run.id,
155
- runIdPrefix: run.id.slice(0, RUN_ID_PREFIX_LEN),
156
151
  name: run.name,
157
152
  status: effectiveRunStatus(run),
158
153
  startedAt: run.startedAt,
@@ -5,15 +5,17 @@ import {
5
5
  expandWorkflowGraph,
6
6
  stageMatchesExpandedIdentifier,
7
7
  } from "../shared/expanded-workflow-graph.js";
8
+ import { isFullRunId, malformedRunIdMessage, RUN_ID_LENGTH } from "../shared/run-id.js";
8
9
  import { topLevelWorkflowRuns } from "../shared/run-visibility.js";
9
10
  import { store } from "../shared/store.js";
11
+ import { readGraphStoreSnapshot } from "../shared/store-observation.js";
10
12
  import type { RunStatus } from "../shared/store-types.js";
11
13
  import type { OverlayPiSurface } from "../tui/overlay-adapter.js";
12
14
  import type { PiExecuteContext, WorkflowToolArgs } from "./public-types.js";
13
15
  import type { PiUISurface } from "./wiring.js";
14
16
 
15
17
  export function formatAlreadyEndedRetainedMessage(runId: string): string {
16
- return `Run ${runId.slice(0, 8)} already ended; retained for inspection.`;
18
+ return `Run ${runId} already ended; retained for inspection.`;
17
19
  }
18
20
 
19
21
  export function stageFailureMessage(runId: string, resultReason: string, action: "pause" | "interrupt"): string {
@@ -78,25 +80,24 @@ export function isRunStatus(value: string): value is RunStatus {
78
80
  }
79
81
  }
80
82
 
83
+ export { isFullRunId, malformedRunIdMessage, RUN_ID_LENGTH };
84
+
81
85
  export type RunIdResolution =
82
86
  | { kind: "exact"; runId: string }
83
- | { kind: "ambiguous"; matches: string[] }
87
+ | { kind: "malformed"; message: string }
84
88
  | { kind: "not_found" };
85
89
 
86
- export function resolveRunIdPrefix(target: string): RunIdResolution {
87
- const runs = store.runs();
88
- const exact = runs.find((r) => r.id === target);
90
+ export function resolveRunId(target: string): RunIdResolution {
91
+ if (!isFullRunId(target)) return { kind: "malformed", message: malformedRunIdMessage(target) };
92
+ const exact = store.runs().find((r) => r.id === target);
89
93
  if (exact) return { kind: "exact", runId: exact.id };
90
- const prefixed = runs.filter((r) => r.id.startsWith(target));
91
- if (prefixed.length === 0) return { kind: "not_found" };
92
- if (prefixed.length === 1) return { kind: "exact", runId: prefixed[0]!.id };
93
- return { kind: "ambiguous", matches: prefixed.map((r) => r.id) };
94
+ return { kind: "not_found" };
94
95
  }
95
96
 
96
97
  export type ToolRunTarget =
97
98
  | { kind: "all" }
98
99
  | { kind: "run"; runId: string }
99
- | { kind: "ambiguous"; target: string; matches: string[] }
100
+ | { kind: "malformed"; target: string; message: string }
100
101
  | { kind: "not_found"; target: string; message: string };
101
102
 
102
103
  export function resolveToolRunTarget(args: WorkflowToolArgs, emptyMessage: string): ToolRunTarget {
@@ -104,9 +105,9 @@ export function resolveToolRunTarget(args: WorkflowToolArgs, emptyMessage: strin
104
105
  if (args.all === true || rawTarget === "--all") return { kind: "all" };
105
106
  const target = rawTarget || store.activeRunId() || "";
106
107
  if (!target) return { kind: "not_found", target: rawTarget, message: emptyMessage };
107
- const resolved = resolveRunIdPrefix(target);
108
+ const resolved = resolveRunId(target);
108
109
  if (resolved.kind === "exact") return { kind: "run", runId: resolved.runId };
109
- if (resolved.kind === "ambiguous") return { kind: "ambiguous", target, matches: resolved.matches };
110
+ if (resolved.kind === "malformed") return { kind: "malformed", target, message: resolved.message };
110
111
  return { kind: "not_found", target, message: `Run not found: ${target}` };
111
112
  }
112
113
 
@@ -115,7 +116,7 @@ export type ToolStageTarget = { ok: true; runId?: string; stageId?: string } | {
115
116
  export function resolveStageTarget(runId: string, stageTarget?: string): ToolStageTarget {
116
117
  const target = stageTarget?.trim();
117
118
  if (!target) return { ok: true, runId };
118
- const graph = expandWorkflowGraph(store.snapshot(), runId);
119
+ const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
119
120
  const exactVirtualIds = graph.stages.filter((stage) => stage.id === target);
120
121
  if (exactVirtualIds.length === 1) return resolvedStageTarget(exactVirtualIds[0]!);
121
122
  if (exactVirtualIds.length > 1) return ambiguousStageTarget(target, exactVirtualIds);
@@ -126,7 +127,7 @@ export function resolveStageTarget(runId: string, stageTarget?: string): ToolSta
126
127
  if (exactNames.length === 1) return resolvedStageTarget(exactNames[0]!);
127
128
  if (exactNames.length > 1) return ambiguousStageTarget(target, exactNames);
128
129
  const matches = graph.stages.filter((stage) => stageMatchesExpandedIdentifier(stage, target));
129
- if (matches.length === 0) return { ok: false, message: `Stage not found in run ${runId.slice(0, 8)}: ${target}` };
130
+ if (matches.length === 0) return { ok: false, message: `Stage not found in run ${runId}: ${target}` };
130
131
  if (matches.length > 1) return ambiguousStageTarget(target, matches);
131
132
  return resolvedStageTarget(matches[0]!);
132
133
  }
@@ -166,7 +167,7 @@ export type ControlNodeTarget =
166
167
  export function resolveControlNodeTarget(runId: string, stageTarget?: string): ControlNodeTarget {
167
168
  const target = stageTarget?.trim();
168
169
  if (!target) return { ok: true, kind: "run" };
169
- const graph = expandWorkflowGraph(store.snapshot(), runId);
170
+ const graph = expandWorkflowGraph(readGraphStoreSnapshot(store), runId);
170
171
  const nodes = graph.renderStages;
171
172
  const candidates: Array<readonly ExpandedWorkflowStage[]> = [
172
173
  nodes.filter((node) => node.id === target),
@@ -182,7 +183,7 @@ export function resolveControlNodeTarget(runId: string, stageTarget?: string): C
182
183
  message: `Ambiguous stage identifier "${target}" matches: ${matches.map(expandedStageLabel).join(", ")}`,
183
184
  };
184
185
  }
185
- return { ok: false, message: `Stage not found in run ${runId.slice(0, 8)}: ${target}` };
186
+ return { ok: false, message: `Stage not found in run ${runId}: ${target}` };
186
187
  }
187
188
 
188
189
  function resolvedControlNodeTarget(node: ExpandedWorkflowStage): ControlNodeTarget {
@@ -196,10 +197,6 @@ export function toolNodePauseRejectionMessage(name: string, nodeId: string): str
196
197
  return `Tool nodes cannot be paused; ctx.tool ${name} (${nodeId}) has no turn boundary. Use interrupt or quit to abort it.`;
197
198
  }
198
199
 
199
- export function ambiguousRunMessage(target: string, matches: readonly string[]): string {
200
- return `Ambiguous run prefix "${target}" matches: ${matches.map((id) => id.slice(0, 12)).join(", ")}`;
201
- }
202
-
203
200
  export function overlaySurfaceFromContext(ctx?: { ui?: PiUISurface }): OverlayPiSurface | undefined {
204
201
  return typeof ctx?.ui?.custom === "function" ? { ui: ctx.ui } : undefined;
205
202
  }
@@ -81,7 +81,7 @@ function renderStatusToolContent(result: Extract<WorkflowToolResult, { action: "
81
81
  const hint = statusRunHint(run);
82
82
  const summaryLine = [
83
83
  `[${index + 1}]`,
84
- run.runIdPrefix,
84
+ run.runId,
85
85
  run.name,
86
86
  run.status,
87
87
  fmtDuration(run.elapsedMs),