@bastani/atomic 0.9.13-alpha.2 → 0.9.13-alpha.3

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 (255) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/README.md +1 -1
  3. package/dist/builtin/i-have-adhd/package.json +1 -1
  4. package/dist/builtin/intercom/CHANGELOG.md +14 -0
  5. package/dist/builtin/intercom/README.md +12 -12
  6. package/dist/builtin/intercom/incoming-message-delivery.ts +1 -1
  7. package/dist/builtin/intercom/index.ts +1 -1
  8. package/dist/builtin/intercom/intercom-tool.ts +1 -1
  9. package/dist/builtin/intercom/intercom-utils.ts +3 -6
  10. package/dist/builtin/intercom/package.json +1 -1
  11. package/dist/builtin/intercom/result-renderers.ts +1 -1
  12. package/dist/builtin/intercom/session-target.ts +1 -15
  13. package/dist/builtin/intercom/skills/intercom/SKILL.md +6 -6
  14. package/dist/builtin/intercom/terminal-ordering-barrier.ts +2 -2
  15. package/dist/builtin/intercom/ui/inline-message.ts +7 -5
  16. package/dist/builtin/intercom/ui/session-list.ts +23 -10
  17. package/dist/builtin/mcp/package.json +1 -1
  18. package/dist/builtin/subagents/CHANGELOG.md +19 -0
  19. package/dist/builtin/subagents/README.md +29 -73
  20. package/dist/builtin/subagents/package.json +2 -2
  21. package/dist/builtin/subagents/prompts/parallel-cleanup.md +1 -1
  22. package/dist/builtin/subagents/prompts/parallel-review.md +1 -1
  23. package/dist/builtin/subagents/prompts/review-loop.md +2 -2
  24. package/dist/builtin/subagents/skills/subagent/SKILL.md +23 -59
  25. package/dist/builtin/subagents/skills/tmux/SKILL.md +1 -1
  26. package/dist/builtin/subagents/src/extension/control-notices.ts +2 -3
  27. package/dist/builtin/subagents/src/extension/doctor.ts +2 -14
  28. package/dist/builtin/subagents/src/extension/fanout-child.ts +1 -17
  29. package/dist/builtin/subagents/src/extension/index.ts +9 -70
  30. package/dist/builtin/subagents/src/extension/notification-content.ts +1 -1
  31. package/dist/builtin/subagents/src/extension/prompt-guidance.ts +2 -2
  32. package/dist/builtin/subagents/src/extension/schemas.ts +2 -8
  33. package/dist/builtin/subagents/src/extension/tool-description.ts +2 -3
  34. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +1 -1
  35. package/dist/builtin/subagents/src/intercom/result-intercom.ts +5 -46
  36. package/dist/builtin/subagents/src/runs/{background → foreground}/completion-notification.ts +2 -2
  37. package/dist/builtin/subagents/src/runs/foreground/inprocess-run-sync.ts +25 -88
  38. package/dist/builtin/subagents/src/runs/{background → foreground}/notify.ts +5 -5
  39. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-context.ts +11 -28
  40. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel-task.ts +3 -0
  41. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-parallel.ts +2 -0
  42. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-runtime.ts +0 -5
  43. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-single.ts +30 -20
  44. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-status.ts +4 -4
  45. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-types.ts +0 -13
  46. package/dist/builtin/subagents/src/runs/foreground/subagent-executor.ts +104 -48
  47. package/dist/builtin/subagents/src/runs/inprocess/index.ts +1 -1
  48. package/dist/builtin/subagents/src/runs/inprocess/runner.ts +5 -5
  49. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-api.ts +0 -7
  50. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-core.ts +0 -10
  51. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-projection.ts +3 -108
  52. package/dist/builtin/subagents/src/runs/inprocess/runtime-support/nested-sanitize.ts +0 -4
  53. package/dist/builtin/subagents/src/runs/shared/subagent-control.ts +1 -1
  54. package/dist/builtin/subagents/src/shared/formatters.ts +3 -5
  55. package/dist/builtin/subagents/src/shared/model-resolution.ts +78 -0
  56. package/dist/builtin/subagents/src/shared/status-format.ts +4 -11
  57. package/dist/builtin/subagents/src/shared/types-config.ts +10 -9
  58. package/dist/builtin/subagents/src/shared/types-nested.ts +127 -0
  59. package/dist/builtin/subagents/src/shared/types-results.ts +2 -8
  60. package/dist/builtin/subagents/src/shared/types-runtime.ts +0 -9
  61. package/dist/builtin/subagents/src/shared/types.ts +1 -1
  62. package/dist/builtin/subagents/src/shared/utils.ts +1 -109
  63. package/dist/builtin/subagents/src/slash/slash-commands.ts +7 -17
  64. package/dist/builtin/subagents/src/tui/render-event-formatting.ts +2 -252
  65. package/dist/builtin/subagents/src/tui/render-layout.ts +4 -4
  66. package/dist/builtin/subagents/src/tui/render-result.ts +0 -9
  67. package/dist/builtin/subagents/src/tui/render-stable-output.ts +1 -34
  68. package/dist/builtin/subagents/src/tui/render.ts +0 -2
  69. package/dist/builtin/web-access/package.json +1 -1
  70. package/dist/builtin/workflows/CHANGELOG.md +12 -0
  71. package/dist/builtin/workflows/README.md +3 -3
  72. package/dist/builtin/workflows/package.json +1 -1
  73. package/dist/builtin/workflows/src/durable/backend.ts +11 -0
  74. package/dist/builtin/workflows/src/durable/completed-catalog-stage-groups.ts +63 -25
  75. package/dist/builtin/workflows/src/durable/completed-catalog.ts +166 -25
  76. package/dist/builtin/workflows/src/durable/dbos-backend.ts +42 -24
  77. package/dist/builtin/workflows/src/durable/dbos-envelope.ts +2 -1
  78. package/dist/builtin/workflows/src/durable/run-timing.ts +28 -7
  79. package/dist/builtin/workflows/src/durable/scoped-backend.ts +4 -0
  80. package/dist/builtin/workflows/src/durable/targeted-inspection.ts +110 -0
  81. package/dist/builtin/workflows/src/engine/run-durable-stage-session.ts +2 -2
  82. package/dist/builtin/workflows/src/engine/runtime.ts +19 -2
  83. package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +3 -0
  84. package/dist/builtin/workflows/src/extension/index.bundle.mjs +680 -152
  85. package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +6 -0
  86. package/dist/builtin/workflows/src/extension/ui-surface.ts +2 -0
  87. package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +6 -1
  88. package/dist/builtin/workflows/src/extension/workflow-targets.ts +18 -10
  89. package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +31 -16
  90. package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +75 -3
  91. package/dist/builtin/workflows/src/extension/workflow-tool.ts +53 -6
  92. package/dist/builtin/workflows/src/runs/background/run-inspect.ts +5 -1
  93. package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +94 -60
  94. package/dist/builtin/workflows/src/runs/foreground/executor-stage-context.ts +1 -1
  95. package/dist/builtin/workflows/src/runs/foreground/executor-stage-control.ts +7 -7
  96. package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +25 -4
  97. package/dist/builtin/workflows/src/runs/foreground/executor-stage-types.ts +4 -1
  98. package/dist/builtin/workflows/src/runs/foreground/executor-types.ts +2 -0
  99. package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +142 -4
  100. package/dist/builtin/workflows/src/runs/foreground/stage-runner-types.ts +2 -0
  101. package/dist/builtin/workflows/src/runs/foreground/stage-session-heartbeat.ts +88 -0
  102. package/dist/builtin/workflows/src/tui/run-detail.ts +25 -12
  103. package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +1 -0
  104. package/dist/core/agent-session-events.d.ts.map +1 -1
  105. package/dist/core/agent-session-events.js +16 -5
  106. package/dist/core/agent-session-events.js.map +1 -1
  107. package/dist/core/agent-session-export.d.ts.map +1 -1
  108. package/dist/core/agent-session-export.js +2 -1
  109. package/dist/core/agent-session-export.js.map +1 -1
  110. package/dist/core/agent-session-methods.d.ts +8 -4
  111. package/dist/core/agent-session-methods.d.ts.map +1 -1
  112. package/dist/core/agent-session-methods.js.map +1 -1
  113. package/dist/core/agent-session-prompt.d.ts.map +1 -1
  114. package/dist/core/agent-session-prompt.js +5 -0
  115. package/dist/core/agent-session-prompt.js.map +1 -1
  116. package/dist/core/agent-session-summary.d.ts +21 -0
  117. package/dist/core/agent-session-summary.d.ts.map +1 -0
  118. package/dist/core/agent-session-summary.js +156 -0
  119. package/dist/core/agent-session-summary.js.map +1 -0
  120. package/dist/core/agent-session-tool-registry.d.ts.map +1 -1
  121. package/dist/core/agent-session-tool-registry.js +0 -4
  122. package/dist/core/agent-session-tool-registry.js.map +1 -1
  123. package/dist/core/agent-session-transfer.d.ts.map +1 -1
  124. package/dist/core/agent-session-transfer.js +0 -2
  125. package/dist/core/agent-session-transfer.js.map +1 -1
  126. package/dist/core/agent-session-tree.d.ts.map +1 -1
  127. package/dist/core/agent-session-tree.js +6 -0
  128. package/dist/core/agent-session-tree.js.map +1 -1
  129. package/dist/core/agent-session.d.ts +7 -3
  130. package/dist/core/agent-session.d.ts.map +1 -1
  131. package/dist/core/agent-session.js +8 -5
  132. package/dist/core/agent-session.js.map +1 -1
  133. package/dist/core/atomic-guide-command.js +2 -2
  134. package/dist/core/atomic-guide-command.js.map +1 -1
  135. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  136. package/dist/core/compaction/branch-summarization.js +1 -0
  137. package/dist/core/compaction/branch-summarization.js.map +1 -1
  138. package/dist/core/compaction/index.d.ts +1 -0
  139. package/dist/core/compaction/index.d.ts.map +1 -1
  140. package/dist/core/compaction/index.js +1 -0
  141. package/dist/core/compaction/index.js.map +1 -1
  142. package/dist/core/compaction/session-summarization.d.ts +41 -0
  143. package/dist/core/compaction/session-summarization.d.ts.map +1 -0
  144. package/dist/core/compaction/session-summarization.js +97 -0
  145. package/dist/core/compaction/session-summarization.js.map +1 -0
  146. package/dist/core/extensions/ui-types.d.ts +2 -0
  147. package/dist/core/extensions/ui-types.d.ts.map +1 -1
  148. package/dist/core/extensions/ui-types.js.map +1 -1
  149. package/dist/core/session-manager-core.d.ts +3 -1
  150. package/dist/core/session-manager-core.d.ts.map +1 -1
  151. package/dist/core/session-manager-core.js +9 -1
  152. package/dist/core/session-manager-core.js.map +1 -1
  153. package/dist/core/session-manager-entries.d.ts +24 -1
  154. package/dist/core/session-manager-entries.d.ts.map +1 -1
  155. package/dist/core/session-manager-entries.js +48 -0
  156. package/dist/core/session-manager-entries.js.map +1 -1
  157. package/dist/core/session-manager-list.d.ts.map +1 -1
  158. package/dist/core/session-manager-list.js +10 -0
  159. package/dist/core/session-manager-list.js.map +1 -1
  160. package/dist/core/session-manager-types.d.ts +10 -1
  161. package/dist/core/session-manager-types.d.ts.map +1 -1
  162. package/dist/core/session-manager-types.js.map +1 -1
  163. package/dist/core/settings-manager-basic-accessors.d.ts +3 -0
  164. package/dist/core/settings-manager-basic-accessors.d.ts.map +1 -1
  165. package/dist/core/settings-manager-basic-accessors.js +5 -0
  166. package/dist/core/settings-manager-basic-accessors.js.map +1 -1
  167. package/dist/core/settings-manager.d.ts +1 -1
  168. package/dist/core/settings-manager.d.ts.map +1 -1
  169. package/dist/core/settings-manager.js.map +1 -1
  170. package/dist/core/settings-types.d.ts +4 -0
  171. package/dist/core/settings-types.d.ts.map +1 -1
  172. package/dist/core/settings-types.js.map +1 -1
  173. package/dist/core/slash-commands.js +2 -2
  174. package/dist/core/slash-commands.js.map +1 -1
  175. package/dist/core/tools/bash.d.ts +0 -15
  176. package/dist/core/tools/bash.d.ts.map +1 -1
  177. package/dist/core/tools/bash.js +3 -81
  178. package/dist/core/tools/bash.js.map +1 -1
  179. package/dist/core/tools/fetch-url.d.ts +12 -0
  180. package/dist/core/tools/fetch-url.d.ts.map +1 -1
  181. package/dist/core/tools/fetch-url.js +76 -10
  182. package/dist/core/tools/fetch-url.js.map +1 -1
  183. package/dist/core/tools/index.js +4 -4
  184. package/dist/core/tools/index.js.map +1 -1
  185. package/dist/core/tools/session-temp-dir.d.ts +2 -2
  186. package/dist/core/tools/session-temp-dir.d.ts.map +1 -1
  187. package/dist/core/tools/session-temp-dir.js +6 -7
  188. package/dist/core/tools/session-temp-dir.js.map +1 -1
  189. package/dist/core/usage-totals.js +1 -1
  190. package/dist/core/usage-totals.js.map +1 -1
  191. package/dist/modes/interactive/components/footer.js +1 -1
  192. package/dist/modes/interactive/components/footer.js.map +1 -1
  193. package/dist/modes/interactive/components/host-session-picker.d.ts.map +1 -1
  194. package/dist/modes/interactive/components/host-session-picker.js +1 -0
  195. package/dist/modes/interactive/components/host-session-picker.js.map +1 -1
  196. package/dist/modes/interactive/components/session-selector-list.d.ts.map +1 -1
  197. package/dist/modes/interactive/components/session-selector-list.js +29 -4
  198. package/dist/modes/interactive/components/session-selector-list.js.map +1 -1
  199. package/dist/modes/interactive/components/session-selector-search.js +1 -1
  200. package/dist/modes/interactive/components/session-selector-search.js.map +1 -1
  201. package/dist/modes/interactive/components/tree-selector-content.d.ts.map +1 -1
  202. package/dist/modes/interactive/components/tree-selector-content.js +6 -0
  203. package/dist/modes/interactive/components/tree-selector-content.js.map +1 -1
  204. package/dist/modes/interactive-engine/protocol.d.ts.map +1 -1
  205. package/dist/modes/interactive-engine/protocol.js +4 -1
  206. package/dist/modes/interactive-engine/protocol.js.map +1 -1
  207. package/docs/environment-variables.md +1 -1
  208. package/docs/intercom.md +20 -21
  209. package/docs/quickstart.md +5 -1
  210. package/docs/sdk.md +1 -1
  211. package/docs/session-format.md +15 -0
  212. package/docs/sessions.md +8 -0
  213. package/docs/settings.md +6 -0
  214. package/docs/subagents.md +19 -31
  215. package/docs/tools.md +3 -5
  216. package/docs/usage.md +1 -1
  217. package/docs/windows.md +1 -1
  218. package/docs/workflows.md +60 -32
  219. package/npm-shrinkwrap.json +29 -29
  220. package/package.json +2 -2
  221. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +0 -331
  222. package/dist/builtin/subagents/src/runs/foreground/subagent-executor-async.ts +0 -161
  223. package/dist/builtin/subagents/src/runs/inprocess/background-single.ts +0 -195
  224. package/dist/builtin/subagents/src/runs/inprocess/background.ts +0 -90
  225. package/dist/builtin/subagents/src/shared/types-async.ts +0 -247
  226. package/dist/builtin/subagents/src/tui/render-widget-graph.ts +0 -217
  227. package/dist/builtin/subagents/src/tui/render-widget.ts +0 -366
  228. package/dist/core/async/format.d.ts +0 -3
  229. package/dist/core/async/format.d.ts.map +0 -1
  230. package/dist/core/async/format.js +0 -52
  231. package/dist/core/async/format.js.map +0 -1
  232. package/dist/core/async/job-manager.d.ts +0 -40
  233. package/dist/core/async/job-manager.d.ts.map +0 -1
  234. package/dist/core/async/job-manager.js +0 -293
  235. package/dist/core/async/job-manager.js.map +0 -1
  236. package/dist/core/async/session-manager.d.ts +0 -16
  237. package/dist/core/async/session-manager.d.ts.map +0 -1
  238. package/dist/core/async/session-manager.js +0 -34
  239. package/dist/core/async/session-manager.js.map +0 -1
  240. package/dist/core/async/types.d.ts +0 -23
  241. package/dist/core/async/types.d.ts.map +0 -1
  242. package/dist/core/async/types.js +0 -2
  243. package/dist/core/async/types.js.map +0 -1
  244. package/dist/core/tools/bash-async-execution.d.ts +0 -27
  245. package/dist/core/tools/bash-async-execution.d.ts.map +0 -1
  246. package/dist/core/tools/bash-async-execution.js +0 -81
  247. package/dist/core/tools/bash-async-execution.js.map +0 -1
  248. package/dist/core/tools/bash-async-jobs.d.ts +0 -30
  249. package/dist/core/tools/bash-async-jobs.d.ts.map +0 -1
  250. package/dist/core/tools/bash-async-jobs.js +0 -87
  251. package/dist/core/tools/bash-async-jobs.js.map +0 -1
  252. package/dist/core/tools/bash-async-output.d.ts +0 -13
  253. package/dist/core/tools/bash-async-output.d.ts.map +0 -1
  254. package/dist/core/tools/bash-async-output.js +0 -122
  255. package/dist/core/tools/bash-async-output.js.map +0 -1
@@ -1,217 +0,0 @@
1
- import { keyHintIfBound } from "@bastani/atomic";
2
- import type { AsyncJobState } from "../shared/types.ts";
3
- import {
4
- formatNestedWidgetLines,
5
- modelThinkingBadge,
6
- widgetActivity,
7
- widgetJobName,
8
- widgetStats,
9
- widgetStatusGlyph,
10
- widgetStepActivity,
11
- widgetStepActivityLine,
12
- widgetStepPulseGlyph,
13
- widgetStepStats,
14
- widgetStepStatus,
15
- } from "./render-event-formatting.ts";
16
- import { getTermWidth, type Theme, truncLine } from "./render-layout.ts";
17
- import { buildLiveStatusLine, themeBold } from "./render-status-progress.ts";
18
-
19
- export function widgetParallelAgentDetails(
20
- job: AsyncJobState,
21
- theme: Theme,
22
- expanded = false,
23
- width = getTermWidth(),
24
- _now?: number,
25
- pulseFrame?: number,
26
- ): string[] {
27
- if (!job.steps?.length) return [];
28
- if (job.mode !== "parallel") return [];
29
- const total = job.stepsTotal ?? job.steps.length;
30
- const lines: string[] = [];
31
- for (const [index, step] of job.steps.entries()) {
32
- const marker = index === job.steps.length - 1 ? "└" : "├";
33
- const activity = widgetStepActivity(step, job.updatedAt);
34
- const itemTitle = "Agent";
35
- const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking, step.fastMode);
36
- lines.push(
37
- ` ${theme.fg("dim", `${marker} ${widgetStepPulseGlyph(step.status, theme, pulseFrame)} ${itemTitle} ${index + 1}/${total}: ${step.agent} · ${widgetStepStatus(step.status, theme)}${modelDisplay}${activity ? ` · ${activity}` : ""}`)}`,
38
- );
39
- for (const nestedLine of formatNestedWidgetLines(
40
- step.children,
41
- theme,
42
- width,
43
- expanded,
44
- job.updatedAt,
45
- expanded ? 8 : 1,
46
- pulseFrame,
47
- ))
48
- lines.push(` ${nestedLine}`);
49
- }
50
- return lines;
51
- }
52
-
53
- export function foregroundStyleWidgetStepLines(
54
- job: AsyncJobState,
55
- theme: Theme,
56
- step: NonNullable<AsyncJobState["steps"]>[number],
57
- itemTitle: "Agent" | "Step",
58
- index: number,
59
- total: number,
60
- expanded: boolean,
61
- width: number,
62
- pulseFrame?: number,
63
- ): string[] {
64
- const status = widgetStepStatus(step.status, theme);
65
- const stats = widgetStepStats(theme, step);
66
- const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking, step.fastMode);
67
- const lines = [
68
- ` ${widgetStepPulseGlyph(step.status, theme, pulseFrame)} ${itemTitle} ${index}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
69
- ];
70
- const activity = widgetStepActivityLine(step, width, expanded, job.updatedAt);
71
- if (activity) lines.push(` ${theme.fg("dim", `⎿ ${activity}`)}`);
72
- for (const nestedLine of formatNestedWidgetLines(
73
- step.children,
74
- theme,
75
- width,
76
- expanded,
77
- job.updatedAt,
78
- undefined,
79
- pulseFrame,
80
- )) {
81
- lines.push(` ${nestedLine}`);
82
- }
83
- if (step.status === "running") {
84
- const expandHint = keyHintIfBound("app.tools.expand", "for live detail");
85
- if (!expanded && expandHint) lines.push(` ${theme.fg("accent", `Press ${expandHint}`)}`);
86
- if (expanded) {
87
- const liveStatus = buildLiveStatusLine(step, job.updatedAt);
88
- if (liveStatus && liveStatus !== activity) lines.push(` ${theme.fg("accent", liveStatus)}`);
89
- for (const tool of step.recentTools?.slice(-3) ?? []) {
90
- const maxArgsLen = Math.max(40, width - 30);
91
- const argsPreview = tool.args.length <= maxArgsLen ? tool.args : `${tool.args.slice(0, maxArgsLen)}...`;
92
- lines.push(` ${theme.fg("dim", `${tool.tool}${argsPreview ? `: ${argsPreview}` : ""}`)}`);
93
- }
94
- for (const line of step.recentOutput?.slice(-5) ?? []) {
95
- lines.push(` ${theme.fg("dim", line)}`);
96
- }
97
- }
98
- }
99
- return lines;
100
- }
101
-
102
- export function foregroundStyleWidgetDetails(
103
- job: AsyncJobState,
104
- theme: Theme,
105
- expanded: boolean,
106
- width: number,
107
- pulseFrame?: number,
108
- ): string[] {
109
- if (!job.steps?.length)
110
- return [
111
- ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
112
- ...formatNestedWidgetLines(
113
- job.nestedChildren,
114
- theme,
115
- width,
116
- expanded,
117
- job.updatedAt,
118
- undefined,
119
- pulseFrame,
120
- ).map((line) => ` ${line}`),
121
- ];
122
- const total = job.stepsTotal ?? job.steps.length;
123
- const itemTitle = job.mode === "parallel" ? "Agent" : "Step";
124
- const lines: string[] = [];
125
- for (const [index, step] of job.steps.entries()) {
126
- lines.push(
127
- ...foregroundStyleWidgetStepLines(job, theme, step, itemTitle, index + 1, total, expanded, width, pulseFrame),
128
- );
129
- }
130
- const attached = new Set(job.steps.flatMap((step) => step.children?.map((child) => child.id) ?? []));
131
- const unattached = job.nestedChildren?.filter((child) => !attached.has(child.id)) ?? [];
132
- for (const nestedLine of formatNestedWidgetLines(
133
- unattached,
134
- theme,
135
- width,
136
- expanded,
137
- job.updatedAt,
138
- undefined,
139
- pulseFrame,
140
- )) {
141
- lines.push(` ${nestedLine}`);
142
- }
143
- return lines;
144
- }
145
-
146
- export function buildSingleWidgetLines(
147
- job: AsyncJobState,
148
- theme: Theme,
149
- width: number,
150
- expanded: boolean,
151
- _now?: number,
152
- pulseFrame?: number,
153
- ): string[] {
154
- const stats = widgetStats(job, theme);
155
- const count = job.stepsTotal ?? job.agents?.length ?? job.steps?.length;
156
- const mode = widgetJobName(job);
157
- const title = `async subagent ${mode}${count && count > 1 ? ` (${count})` : ""}`;
158
- return [
159
- `${theme.fg("toolTitle", themeBold(theme, title))} ${theme.fg("dim", "· background")}`,
160
- `${widgetStatusGlyph(job, theme, pulseFrame)} ${themeBold(theme, mode)}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
161
- ...foregroundStyleWidgetDetails(job, theme, expanded, width, pulseFrame),
162
- ].map((line) => truncLine(line, width));
163
- }
164
-
165
- export function compactSingleWidgetLines(
166
- job: AsyncJobState,
167
- theme: Theme,
168
- width: number,
169
- _now?: number,
170
- pulseFrame?: number,
171
- ): string[] {
172
- const fullLines = buildSingleWidgetLines(job, theme, width, false, _now, pulseFrame);
173
- if (fullLines.length <= 10 || !job.steps?.length || job.mode !== "parallel") return fullLines;
174
-
175
- const total = job.stepsTotal ?? job.steps.length;
176
- const itemTitle = "Agent";
177
- const lines = fullLines.slice(0, 2);
178
- for (const [index, step] of job.steps.entries()) {
179
- const status = widgetStepStatus(step.status, theme);
180
- const activity = widgetStepActivityLine(step, width, false, job.updatedAt);
181
- const stepStats = widgetStepStats(theme, step);
182
- const activitySuffix = activity ? ` ${theme.fg("dim", "·")} ${theme.fg("dim", activity)}` : "";
183
- const modelDisplay = modelThinkingBadge(theme, step.model, step.thinking, step.fastMode);
184
- lines.push(
185
- ` ${widgetStepPulseGlyph(step.status, theme, pulseFrame)} ${itemTitle} ${index + 1}/${total}: ${themeBold(theme, step.agent)} ${theme.fg("dim", "·")} ${status}${modelDisplay}${activitySuffix}${stepStats ? ` ${theme.fg("dim", "·")} ${stepStats}` : ""}`,
186
- );
187
- for (const nestedLine of formatNestedWidgetLines(
188
- step.children,
189
- theme,
190
- width,
191
- false,
192
- job.updatedAt,
193
- undefined,
194
- pulseFrame,
195
- ))
196
- lines.push(` ${nestedLine}`);
197
- }
198
- const expandHint = keyHintIfBound("app.tools.expand", "for live detail");
199
- if (expandHint && job.steps.some((step) => step.status === "running"))
200
- lines.push(theme.fg("accent", ` Press ${expandHint}`));
201
- return lines.map((line) => truncLine(line, width));
202
- }
203
-
204
- export function fitWidgetLineBudget(lines: string[], theme: Theme, width: number, expanded: boolean): string[] {
205
- const rows = process.stdout.rows || 30;
206
- const budget = expanded
207
- ? Math.max(12, Math.min(24, Math.floor(rows * 0.55)))
208
- : Math.max(10, Math.min(14, Math.floor(rows * 0.35)));
209
- if (lines.length <= budget) return lines;
210
- const visibleLines = Math.max(1, budget - 1);
211
- const hiddenCount = lines.length - visibleLines;
212
- const expandHint = keyHintIfBound("app.tools.expand", "expands");
213
- const hint = expanded
214
- ? `… ${hiddenCount} live-detail lines hidden`
215
- : `… ${hiddenCount} lines hidden${expandHint ? ` · ${expandHint}` : ""}`;
216
- return [...lines.slice(0, visibleLines), truncLine(theme.fg("dim", hint), width)];
217
- }
@@ -1,366 +0,0 @@
1
- import * as path from "node:path";
2
- import type { ExtensionContext } from "@bastani/atomic";
3
- import { type Component, Container, Text } from "@earendil-works/pi-tui";
4
- import { type AsyncJobState, MAX_WIDGET_JOBS, WIDGET_KEY } from "../shared/types.ts";
5
- import { widgetActivity, widgetJobName, widgetStats, widgetStatusGlyph } from "./render-event-formatting.ts";
6
- import { getTermWidth, runningPulseGlyph, type Theme, truncLine } from "./render-layout.ts";
7
- import { advanceResultPulseFrame } from "./render-result-animation.ts";
8
- import { widgetRenderKey } from "./render-stable-output.ts";
9
- import { themeBold } from "./render-status-progress.ts";
10
- import {
11
- buildSingleWidgetLines,
12
- compactSingleWidgetLines,
13
- fitWidgetLineBudget,
14
- widgetParallelAgentDetails,
15
- } from "./render-widget-graph.ts";
16
-
17
- class LiveWidgetComponent implements Component {
18
- private readonly container = new Container();
19
-
20
- constructor(
21
- private readonly getJobs: () => AsyncJobState[],
22
- private readonly theme: Theme,
23
- private readonly getExpanded: () => boolean,
24
- private readonly getNow: () => number,
25
- private readonly getPulseFrame: () => number | undefined,
26
- ) {}
27
-
28
- render(width: number): string[] {
29
- const jobs = this.getJobs();
30
- const expanded = this.getExpanded();
31
- const now = this.getNow();
32
- const pulseFrame = this.getPulseFrame();
33
- const lines = this.buildLines(jobs, width, expanded, now, pulseFrame);
34
- this.container.clear();
35
- for (const line of fitWidgetLineBudget(lines, this.theme, width, expanded))
36
- this.container.addChild(new Text(line, 1, 0));
37
- return this.container.render(width);
38
- }
39
-
40
- private buildLines(
41
- jobs: AsyncJobState[],
42
- width: number,
43
- expanded: boolean,
44
- now: number,
45
- pulseFrame: number | undefined,
46
- ): string[] {
47
- if (expanded) return buildWidgetLines(jobs, this.theme, width, true, now, pulseFrame);
48
- if (jobs.length === 1) return compactSingleWidgetLines(jobs[0]!, this.theme, width, now, pulseFrame);
49
- return buildWidgetLines(jobs, this.theme, width, false, now, pulseFrame);
50
- }
51
-
52
- invalidate(): void {
53
- this.container.invalidate();
54
- }
55
- }
56
-
57
- function buildWidgetComponent(
58
- getJobs: () => AsyncJobState[],
59
- getExpanded: () => boolean,
60
- getNow: () => number,
61
- getPulseFrame: () => number | undefined,
62
- ): (_tui: unknown, theme: Theme) => Component {
63
- return (_tui, theme) => new LiveWidgetComponent(getJobs, theme, getExpanded, getNow, getPulseFrame);
64
- }
65
-
66
- interface RenderRequestingContext {
67
- ui: ExtensionContext["ui"] & { requestRender?: () => void };
68
- }
69
-
70
- interface WidgetAnimationState {
71
- latestCtx?: ExtensionContext;
72
- latestJobs: AsyncJobState[];
73
- frameNow: number;
74
- expanded: boolean;
75
- snapshotKey?: string;
76
- pulseFrame?: number;
77
- mountedCtx?: ExtensionContext;
78
- mountedOwnerKey?: string;
79
- surfaceKey?: object;
80
- mounted: boolean;
81
- }
82
-
83
- interface WidgetSurfaceState {
84
- activeOwner?: object;
85
- }
86
-
87
- interface WidgetRegistry {
88
- states: WeakMap<object, WidgetAnimationState>;
89
- surfaces: WeakMap<object, WidgetSurfaceState>;
90
- }
91
-
92
- const defaultWidgetOwner = {};
93
-
94
- function getWidgetRegistry(): WidgetRegistry {
95
- const key = "__piSubagentWidgetRegistry";
96
- const globalStore = globalThis as Record<string, unknown>;
97
- const existing = globalStore[key] as WidgetRegistry | undefined;
98
- if (existing?.states instanceof WeakMap && existing.surfaces instanceof WeakMap) return existing;
99
- const registry: WidgetRegistry = { states: new WeakMap(), surfaces: new WeakMap() };
100
- globalStore[key] = registry;
101
- return registry;
102
- }
103
-
104
- function getWidgetState(owner: object): WidgetAnimationState {
105
- const registry = getWidgetRegistry();
106
- const existing = registry.states.get(owner);
107
- if (existing) return existing;
108
- const state: WidgetAnimationState = {
109
- latestJobs: [],
110
- frameNow: 0,
111
- expanded: false,
112
- mounted: false,
113
- };
114
- registry.states.set(owner, state);
115
- return state;
116
- }
117
-
118
- function getSurfaceState(surfaceKey: object): WidgetSurfaceState {
119
- const registry = getWidgetRegistry();
120
- const existing = registry.surfaces.get(surfaceKey);
121
- if (existing) return existing;
122
- const surface = {};
123
- registry.surfaces.set(surfaceKey, surface);
124
- return surface;
125
- }
126
-
127
- function getExpanded(state: WidgetAnimationState): boolean {
128
- if (!state.latestCtx?.hasUI) return state.expanded;
129
- const expanded = state.latestCtx.ui.getToolsExpanded?.();
130
- if (typeof expanded === "boolean") state.expanded = expanded;
131
- return state.expanded;
132
- }
133
-
134
- function clearWidgetState(state: WidgetAnimationState): void {
135
- state.latestCtx = undefined;
136
- state.latestJobs = [];
137
- state.frameNow = 0;
138
- state.expanded = false;
139
- state.snapshotKey = undefined;
140
- state.pulseFrame = undefined;
141
- state.mountedCtx = undefined;
142
- state.mountedOwnerKey = undefined;
143
- state.surfaceKey = undefined;
144
- state.mounted = false;
145
- }
146
-
147
- function getWidgetOwnerKey(ctx: ExtensionContext): string {
148
- const resolvedCwd = ctx.cwd ? path.resolve(ctx.cwd) : undefined;
149
- const cwdOwner = resolvedCwd ?? "cwd:unknown";
150
- let sessionOwner = "session:unknown";
151
- try {
152
- const sessionFile = ctx.sessionManager.getSessionFile?.();
153
- if (sessionFile) {
154
- const resolvedSessionFile = resolvedCwd ? path.resolve(resolvedCwd, sessionFile) : path.resolve(sessionFile);
155
- sessionOwner = `sessionFile:${resolvedSessionFile}`;
156
- }
157
- } catch {
158
- // Fall through to the session id fallback below.
159
- }
160
- if (sessionOwner === "session:unknown") {
161
- try {
162
- const sessionId = ctx.sessionManager.getSessionId?.();
163
- if (sessionId) sessionOwner = `sessionId:${sessionId}`;
164
- } catch {
165
- // Keep the unknown marker; cwd still scopes ownership.
166
- }
167
- }
168
- // If no session identifier is available, cwd is the best available owner
169
- // boundary and may intentionally coalesce concurrent sessions in one folder.
170
- return `${sessionOwner}|cwd:${cwdOwner}`;
171
- }
172
-
173
- function requestWidgetRender(ctx: ExtensionContext): void {
174
- (ctx as RenderRequestingContext).ui.requestRender?.();
175
- }
176
-
177
- function unmountWidgetBestEffort(ctx: ExtensionContext | undefined): void {
178
- if (!ctx?.hasUI) return;
179
- try {
180
- ctx.ui.setWidget(WIDGET_KEY, undefined);
181
- } catch {
182
- // Best-effort teardown only: stale host contexts can reject cleanup during
183
- // reload/session rebinding, but local state still needs to move on so the
184
- // next status update can mount cleanly on the active UI context.
185
- }
186
- try {
187
- ctx.ui.setStatus?.(WIDGET_KEY, undefined);
188
- } catch {
189
- // Status mirroring cleanup must never block primary widget teardown.
190
- }
191
- }
192
-
193
- function widgetSnapshotKey(jobs: AsyncJobState[]): string {
194
- return jobs.map(widgetRenderKey).join("\n");
195
- }
196
-
197
- function refreshWidgetSnapshot(state: WidgetAnimationState, jobs: AsyncJobState[]): void {
198
- const snapshotKey = widgetSnapshotKey(jobs);
199
- if (snapshotKey === state.snapshotKey) return;
200
- state.snapshotKey = snapshotKey;
201
- state.frameNow = Date.now();
202
- state.pulseFrame = advanceResultPulseFrame(state.pulseFrame);
203
- }
204
-
205
- function releaseMountedWidget(state: WidgetAnimationState, owner: object): void {
206
- if (state.mounted) unmountWidgetBestEffort(state.mountedCtx);
207
- if (state.surfaceKey) {
208
- const surface = getSurfaceState(state.surfaceKey);
209
- if (surface.activeOwner === owner) surface.activeOwner = undefined;
210
- }
211
- clearWidgetState(state);
212
- }
213
-
214
- // Full teardown. Explicit API ownership is authoritative; logical context
215
- // matching only protects context-driven teardown from stale session wrappers.
216
- export function stopWidgetAnimation(ownerCtx?: ExtensionContext, owner: object = defaultWidgetOwner): void {
217
- const state = getWidgetState(owner);
218
- if (ownerCtx && state.mounted && state.mountedOwnerKey !== getWidgetOwnerKey(ownerCtx)) return;
219
- if (state.surfaceKey && getSurfaceState(state.surfaceKey).activeOwner !== owner) {
220
- clearWidgetState(state);
221
- return;
222
- }
223
- releaseMountedWidget(state, owner);
224
- }
225
-
226
- export function buildWidgetLines(
227
- jobs: AsyncJobState[],
228
- theme: Theme,
229
- width = getTermWidth(),
230
- expanded = false,
231
- now: number = Date.now(),
232
- pulseFrame?: number,
233
- ): string[] {
234
- if (jobs.length === 0) return [];
235
- if (jobs.length === 1) return buildSingleWidgetLines(jobs[0]!, theme, width, expanded, now, pulseFrame);
236
- const running = jobs.filter((job) => job.status === "running");
237
- const queued = jobs.filter((job) => job.status === "queued");
238
- const finished = jobs.filter((job) => job.status !== "running" && job.status !== "queued");
239
-
240
- const lines: string[] = [];
241
- const hasActive = running.length > 0 || queued.length > 0;
242
- const headerGlyph = running.length > 0 ? runningPulseGlyph(pulseFrame) : hasActive ? "●" : "○";
243
- lines.push(
244
- truncLine(
245
- `${theme.fg(hasActive ? "accent" : "dim", headerGlyph)} ${theme.fg(hasActive ? "accent" : "dim", "Async agents")} ${theme.fg("dim", "· background")}`,
246
- width,
247
- ),
248
- );
249
-
250
- const items: string[][] = [];
251
- let hiddenRunning = 0;
252
- let hiddenFinished = 0;
253
- let queuedSummaryShown = false;
254
- let slots = MAX_WIDGET_JOBS;
255
-
256
- for (const job of running) {
257
- if (slots <= 0) {
258
- hiddenRunning++;
259
- continue;
260
- }
261
- const stats = widgetStats(job, theme);
262
- items.push([
263
- `${widgetStatusGlyph(job, theme, pulseFrame)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
264
- ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
265
- ...widgetParallelAgentDetails(job, theme, expanded, width, now, pulseFrame),
266
- ]);
267
- slots--;
268
- }
269
-
270
- if (queued.length > 0 && slots > 0) {
271
- items.push([`${theme.fg("muted", "◦")} ${theme.fg("dim", `${queued.length} queued`)}`]);
272
- queuedSummaryShown = true;
273
- slots--;
274
- }
275
-
276
- for (const job of finished) {
277
- if (slots <= 0) {
278
- hiddenFinished++;
279
- continue;
280
- }
281
- const stats = widgetStats(job, theme);
282
- items.push([
283
- `${widgetStatusGlyph(job, theme, pulseFrame)} ${themeBold(theme, widgetJobName(job))}${stats ? ` ${theme.fg("dim", "·")} ${stats}` : ""}`,
284
- ` ${theme.fg("dim", `⎿ ${widgetActivity(job)}`)}`,
285
- ...widgetParallelAgentDetails(job, theme, expanded, width, now, pulseFrame),
286
- ]);
287
- slots--;
288
- }
289
-
290
- const hiddenQueued = queued.length > 0 && !queuedSummaryShown ? queued.length : 0;
291
- const hiddenTotal = hiddenRunning + hiddenFinished + hiddenQueued;
292
- if (hiddenTotal > 0) {
293
- const parts: string[] = [];
294
- if (hiddenRunning > 0) parts.push(`${hiddenRunning} running`);
295
- if (hiddenQueued > 0) parts.push(`${hiddenQueued} queued`);
296
- if (hiddenFinished > 0) parts.push(`${hiddenFinished} finished`);
297
- items.push([theme.fg("dim", `+${hiddenTotal} more (${parts.join(", ")})`)]);
298
- }
299
-
300
- for (let i = 0; i < items.length; i++) {
301
- const item = items[i]!;
302
- const last = i === items.length - 1;
303
- const branch = last ? "└─" : "├─";
304
- const continuation = last ? " " : "│ ";
305
- lines.push(truncLine(`${theme.fg("dim", branch)} ${item[0]}`, width));
306
- for (const detail of item.slice(1)) {
307
- lines.push(truncLine(`${theme.fg("dim", continuation)} ${detail}`, width));
308
- }
309
- }
310
-
311
- return lines;
312
- }
313
-
314
- /** Render the async jobs widget for one ExtensionAPI owner. */
315
- export function renderWidget(ctx: ExtensionContext, jobs: AsyncJobState[], owner: object = defaultWidgetOwner): void {
316
- const state = getWidgetState(owner);
317
- const ownerKey = getWidgetOwnerKey(ctx);
318
- const requestedSurfaceKey = ctx.ui.setWidget;
319
- const requestedSurface = getSurfaceState(requestedSurfaceKey);
320
- if (jobs.length === 0) {
321
- if (requestedSurface.activeOwner && requestedSurface.activeOwner !== owner) return;
322
- if (state.surfaceKey && getSurfaceState(state.surfaceKey).activeOwner !== owner) return;
323
- if (state.mounted && state.mountedOwnerKey !== ownerKey) return;
324
- stopWidgetAnimation(ctx, owner);
325
- return;
326
- }
327
- if (!ctx.hasUI) {
328
- stopWidgetAnimation(ctx, owner);
329
- return;
330
- }
331
- // Workflow stages forward the host's setWidget function, which identifies the
332
- // shared widget surface. A stage cannot replace a parent already active there.
333
- if (!state.mounted && requestedSurface.activeOwner && requestedSurface.activeOwner !== owner) return;
334
- state.latestCtx = ctx;
335
- state.latestJobs = [...jobs];
336
- refreshWidgetSnapshot(state, jobs);
337
- if (state.mounted && state.mountedOwnerKey !== ownerKey) {
338
- releaseMountedWidget(state, owner);
339
- state.latestCtx = ctx;
340
- state.latestJobs = [...jobs];
341
- refreshWidgetSnapshot(state, jobs);
342
- }
343
- if (!state.mounted) {
344
- const surface = getSurfaceState(requestedSurfaceKey);
345
- if (surface.activeOwner && surface.activeOwner !== owner) return;
346
- ctx.ui.setWidget(
347
- WIDGET_KEY,
348
- buildWidgetComponent(
349
- () => state.latestJobs,
350
- () => getExpanded(state),
351
- () => state.frameNow,
352
- () => state.pulseFrame,
353
- ),
354
- { placement: "belowEditor" },
355
- );
356
- state.mountedCtx = ctx;
357
- state.mountedOwnerKey = ownerKey;
358
- state.surfaceKey = requestedSurfaceKey;
359
- state.mounted = true;
360
- surface.activeOwner = owner;
361
- } else {
362
- state.mountedCtx = ctx;
363
- state.mountedOwnerKey = ownerKey;
364
- requestWidgetRender(ctx);
365
- }
366
- }
@@ -1,3 +0,0 @@
1
- import type { AsyncJobDeliveryMessage, ManagedAsyncBashJob } from "./types.js";
2
- export declare function formatAsyncResultForFollowUp(job: ManagedAsyncBashJob): AsyncJobDeliveryMessage;
3
- //# sourceMappingURL=format.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../src/core/async/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAwB/E,wBAAgB,4BAA4B,CAAC,GAAG,EAAE,mBAAmB,GAAG,uBAAuB,CA6B9F"}
@@ -1,52 +0,0 @@
1
- const INLINE_OUTPUT_LIMIT = 12_000;
2
- const LARGE_OUTPUT_PREVIEW_LIMIT = 4_000;
3
- function truncateText(text, maxChars) {
4
- if (text.length <= maxChars)
5
- return text;
6
- return text.slice(0, maxChars).trimEnd();
7
- }
8
- function jobOutput(job) {
9
- const output = job.output.trimEnd();
10
- if (output.length > 0)
11
- return output;
12
- return job.error ? `(no output)\n\n${job.error}` : "(no output)";
13
- }
14
- function statusLine(job) {
15
- if (job.error)
16
- return `Error: ${job.error}`;
17
- if (job.exitCode !== undefined && job.exitCode !== null && job.exitCode !== 0) {
18
- return `Command exited with code ${job.exitCode}`;
19
- }
20
- return undefined;
21
- }
22
- export function formatAsyncResultForFollowUp(job) {
23
- const elapsedMs = (job.endedAt ?? Date.now()) - job.startedAt;
24
- const header = `Async bash job ${job.jobId} ${job.status}: ${job.command}`;
25
- const body = jobOutput(job);
26
- const status = statusLine(job);
27
- const inline = [header, body, status]
28
- .filter((part) => part !== undefined && part.length > 0)
29
- .join("\n\n");
30
- let content = inline;
31
- if (inline.length > INLINE_OUTPUT_LIMIT && job.fullOutputPath) {
32
- const preview = truncateText(body, LARGE_OUTPUT_PREVIEW_LIMIT);
33
- content = [header, preview, `[Output truncated for async follow-up. Full output: ${job.fullOutputPath}]`, status]
34
- .filter((part) => part !== undefined && part.length > 0)
35
- .join("\n\n");
36
- }
37
- return {
38
- customType: "async-job-result",
39
- content,
40
- display: true,
41
- details: {
42
- jobId: job.jobId,
43
- type: "bash",
44
- status: job.status,
45
- command: job.command,
46
- exitCode: job.exitCode,
47
- fullOutputPath: job.fullOutputPath,
48
- wallTimeMs: elapsedMs,
49
- },
50
- };
51
- }
52
- //# sourceMappingURL=format.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../../../src/core/async/format.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GAAG,MAAM,CAAC;AACnC,MAAM,0BAA0B,GAAG,KAAK,CAAC;AAEzC,SAAS,YAAY,CAAC,IAAY,EAAE,QAAgB;IACnD,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ;QAAE,OAAO,IAAI,CAAC;IACzC,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;AAC1C,CAAC;AAED,SAAS,SAAS,CAAC,GAAwB;IAC1C,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,MAAM,CAAC;IACrC,OAAO,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,kBAAkB,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;AAClE,CAAC;AAED,SAAS,UAAU,CAAC,GAAwB;IAC3C,IAAI,GAAG,CAAC,KAAK;QAAE,OAAO,UAAU,GAAG,CAAC,KAAK,EAAE,CAAC;IAC5C,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,QAAQ,KAAK,IAAI,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;QAC/E,OAAO,4BAA4B,GAAG,CAAC,QAAQ,EAAE,CAAC;IACnD,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,GAAwB;IACpE,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC,GAAG,GAAG,CAAC,SAAS,CAAC;IAC9D,MAAM,MAAM,GAAG,kBAAkB,GAAG,CAAC,KAAK,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;IAC3E,MAAM,IAAI,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;IAC5B,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC;SACnC,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;SACvE,IAAI,CAAC,MAAM,CAAC,CAAC;IACf,IAAI,OAAO,GAAG,MAAM,CAAC;IACrB,IAAI,MAAM,CAAC,MAAM,GAAG,mBAAmB,IAAI,GAAG,CAAC,cAAc,EAAE,CAAC;QAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,EAAE,0BAA0B,CAAC,CAAC;QAC/D,OAAO,GAAG,CAAC,MAAM,EAAE,OAAO,EAAE,uDAAuD,GAAG,CAAC,cAAc,GAAG,EAAE,MAAM,CAAC;aAC/G,MAAM,CAAC,CAAC,IAAI,EAAkB,EAAE,CAAC,IAAI,KAAK,SAAS,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;aACvE,IAAI,CAAC,MAAM,CAAC,CAAC;IAChB,CAAC;IACD,OAAO;QACN,UAAU,EAAE,kBAAkB;QAC9B,OAAO;QACP,OAAO,EAAE,IAAI;QACb,OAAO,EAAE;YACR,KAAK,EAAE,GAAG,CAAC,KAAK;YAChB,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,QAAQ,EAAE,GAAG,CAAC,QAAQ;YACtB,cAAc,EAAE,GAAG,CAAC,cAAc;YAClC,UAAU,EAAE,SAAS;SACrB;KACD,CAAC;AACH,CAAC","sourcesContent":["import type { AsyncJobDeliveryMessage, ManagedAsyncBashJob } from \"./types.js\";\n\nconst INLINE_OUTPUT_LIMIT = 12_000;\nconst LARGE_OUTPUT_PREVIEW_LIMIT = 4_000;\n\nfunction truncateText(text: string, maxChars: number): string {\n\tif (text.length <= maxChars) return text;\n\treturn text.slice(0, maxChars).trimEnd();\n}\n\nfunction jobOutput(job: ManagedAsyncBashJob): string {\n\tconst output = job.output.trimEnd();\n\tif (output.length > 0) return output;\n\treturn job.error ? `(no output)\\n\\n${job.error}` : \"(no output)\";\n}\n\nfunction statusLine(job: ManagedAsyncBashJob): string | undefined {\n\tif (job.error) return `Error: ${job.error}`;\n\tif (job.exitCode !== undefined && job.exitCode !== null && job.exitCode !== 0) {\n\t\treturn `Command exited with code ${job.exitCode}`;\n\t}\n\treturn undefined;\n}\n\nexport function formatAsyncResultForFollowUp(job: ManagedAsyncBashJob): AsyncJobDeliveryMessage {\n\tconst elapsedMs = (job.endedAt ?? Date.now()) - job.startedAt;\n\tconst header = `Async bash job ${job.jobId} ${job.status}: ${job.command}`;\n\tconst body = jobOutput(job);\n\tconst status = statusLine(job);\n\tconst inline = [header, body, status]\n\t\t.filter((part): part is string => part !== undefined && part.length > 0)\n\t\t.join(\"\\n\\n\");\n\tlet content = inline;\n\tif (inline.length > INLINE_OUTPUT_LIMIT && job.fullOutputPath) {\n\t\tconst preview = truncateText(body, LARGE_OUTPUT_PREVIEW_LIMIT);\n\t\tcontent = [header, preview, `[Output truncated for async follow-up. Full output: ${job.fullOutputPath}]`, status]\n\t\t\t.filter((part): part is string => part !== undefined && part.length > 0)\n\t\t\t.join(\"\\n\\n\");\n\t}\n\treturn {\n\t\tcustomType: \"async-job-result\",\n\t\tcontent,\n\t\tdisplay: true,\n\t\tdetails: {\n\t\t\tjobId: job.jobId,\n\t\t\ttype: \"bash\",\n\t\t\tstatus: job.status,\n\t\t\tcommand: job.command,\n\t\t\texitCode: job.exitCode,\n\t\t\tfullOutputPath: job.fullOutputPath,\n\t\t\twallTimeMs: elapsedMs,\n\t\t},\n\t};\n}\n"]}
@@ -1,40 +0,0 @@
1
- import { type ManagedBashJob } from "../tools/bash-async-jobs.js";
2
- import type { AsyncJobDeliveryCallback, AsyncJobDeliveryHandler } from "./types.js";
3
- interface AsyncJobManagerOptions {
4
- onJobComplete: AsyncJobDeliveryCallback;
5
- maxRunningJobs?: number;
6
- maxRetainedJobs?: number;
7
- completedJobTtlMs?: number;
8
- }
9
- export declare class AsyncJobManager {
10
- #private;
11
- static instance(): AsyncJobManager | undefined;
12
- static setInstance(value: AsyncJobManager | undefined): void;
13
- static resetForTests(): void;
14
- constructor(options: AsyncJobManagerOptions);
15
- get disposed(): boolean;
16
- get atCapacity(): boolean;
17
- registerSession(): symbol;
18
- releaseSession(sessionId: symbol): void;
19
- transferSessionDeliveries(sourceId: symbol, targetId: symbol, handler: AsyncJobDeliveryHandler): void;
20
- isSessionDisposed(sessionId: symbol): boolean;
21
- registerBashJob(job: ManagedBashJob, onComplete?: AsyncJobDeliveryHandler, sessionId?: symbol): void;
22
- completeBashJob(job: ManagedBashJob): void;
23
- acknowledgeDeliveries(jobIds: readonly string[]): void;
24
- isDeliverySuppressed(jobId: string): boolean;
25
- deliveryState(): {
26
- queued: number;
27
- delivering: boolean;
28
- pendingJobIds: string[];
29
- };
30
- retentionState(): {
31
- jobs: number;
32
- suppressions: number;
33
- handlers: number;
34
- queued: number;
35
- sessions: number;
36
- };
37
- dispose(): void;
38
- }
39
- export {};
40
- //# sourceMappingURL=job-manager.d.ts.map