@bastani/atomic 0.8.21 → 0.8.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/CHANGELOG.md +66 -9
  2. package/dist/builtin/intercom/broker/broker.ts +3 -3
  3. package/dist/builtin/intercom/config.ts +3 -3
  4. package/dist/builtin/intercom/index.ts +1 -1
  5. package/dist/builtin/intercom/package.json +1 -1
  6. package/dist/builtin/intercom/ui/compose.ts +2 -2
  7. package/dist/builtin/mcp/host-html-template.ts +0 -3
  8. package/dist/builtin/mcp/package.json +1 -1
  9. package/dist/builtin/subagents/CHANGELOG.md +20 -4
  10. package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
  11. package/dist/builtin/subagents/agents/debugger.md +6 -6
  12. package/dist/builtin/subagents/package.json +1 -1
  13. package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
  14. package/dist/builtin/subagents/skills/browser-use/SKILL.md +234 -0
  15. package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +76 -0
  16. package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +92 -0
  17. package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
  18. package/dist/builtin/subagents/src/agents/skills.ts +19 -1
  19. package/dist/builtin/subagents/src/extension/index.ts +24 -22
  20. package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +7 -1
  21. package/dist/builtin/subagents/src/runs/background/async-execution.ts +23 -7
  22. package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +98 -3
  23. package/dist/builtin/subagents/src/runs/background/async-status.ts +3 -1
  24. package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -1
  25. package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +3 -0
  26. package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +37 -12
  27. package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +15 -15
  28. package/dist/builtin/subagents/src/runs/foreground/execution.ts +26 -2
  29. package/dist/builtin/subagents/src/runs/shared/nested-render.ts +1 -1
  30. package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +7 -0
  31. package/dist/builtin/subagents/src/runs/shared/pi-args.ts +28 -1
  32. package/dist/builtin/subagents/src/shared/fast-mode.ts +80 -0
  33. package/dist/builtin/subagents/src/shared/formatters.ts +4 -2
  34. package/dist/builtin/subagents/src/shared/types.ts +4 -2
  35. package/dist/builtin/subagents/src/shared/utils.ts +3 -61
  36. package/dist/builtin/subagents/src/tui/render.ts +303 -157
  37. package/dist/builtin/web-access/package.json +1 -1
  38. package/dist/builtin/workflows/CHANGELOG.md +113 -35
  39. package/dist/builtin/workflows/README.md +228 -41
  40. package/dist/builtin/workflows/builtin/deep-research-codebase.ts +535 -541
  41. package/dist/builtin/workflows/builtin/goal.ts +39 -25
  42. package/dist/builtin/workflows/builtin/open-claude-design.ts +66 -69
  43. package/dist/builtin/workflows/builtin/ralph.ts +21 -21
  44. package/dist/builtin/workflows/package.json +6 -5
  45. package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
  46. package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +2 -2
  47. package/dist/builtin/workflows/src/extension/discovery.ts +25 -146
  48. package/dist/builtin/workflows/src/extension/dispatcher.ts +72 -24
  49. package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +363 -0
  50. package/dist/builtin/workflows/src/extension/index.ts +690 -352
  51. package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +99 -62
  52. package/dist/builtin/workflows/src/extension/render-call.ts +2 -1
  53. package/dist/builtin/workflows/src/extension/render-result.ts +9 -3
  54. package/dist/builtin/workflows/src/extension/renderers.ts +5 -3
  55. package/dist/builtin/workflows/src/extension/runtime.ts +68 -33
  56. package/dist/builtin/workflows/src/extension/status-writer.ts +1 -1
  57. package/dist/builtin/workflows/src/extension/wiring.ts +34 -13
  58. package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +142 -0
  59. package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -4
  60. package/dist/builtin/workflows/src/index.ts +2 -0
  61. package/dist/builtin/workflows/src/intercom/result-intercom.ts +1 -1
  62. package/dist/builtin/workflows/src/runs/background/runner.ts +6 -4
  63. package/dist/builtin/workflows/src/runs/background/status.ts +45 -21
  64. package/dist/builtin/workflows/src/runs/foreground/executor.ts +624 -52
  65. package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +1 -1
  66. package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +80 -24
  67. package/dist/builtin/workflows/src/runs/shared/validate-inputs.ts +61 -24
  68. package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +32 -10
  69. package/dist/builtin/workflows/src/sdk-surface.ts +6 -0
  70. package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +178 -0
  71. package/dist/builtin/workflows/src/shared/persistence-restore.ts +92 -12
  72. package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +21 -3
  73. package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +1 -2
  74. package/dist/builtin/workflows/src/shared/run-visibility.ts +9 -0
  75. package/dist/builtin/workflows/src/shared/schema-introspection.ts +121 -0
  76. package/dist/builtin/workflows/src/shared/serializable.ts +132 -0
  77. package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +91 -9
  78. package/dist/builtin/workflows/src/shared/store-types.ts +31 -3
  79. package/dist/builtin/workflows/src/shared/store.ts +58 -14
  80. package/dist/builtin/workflows/src/shared/types.ts +105 -40
  81. package/dist/builtin/workflows/src/tui/chat-surface-message.ts +129 -13
  82. package/dist/builtin/workflows/src/tui/chat-surface.ts +6 -1
  83. package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +3 -2
  84. package/dist/builtin/workflows/src/tui/graph-canvas.ts +1 -1
  85. package/dist/builtin/workflows/src/tui/graph-view.ts +91 -65
  86. package/dist/builtin/workflows/src/tui/inline-form-card.ts +1 -1
  87. package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +3 -2
  88. package/dist/builtin/workflows/src/tui/inputs-overlay.ts +3 -2
  89. package/dist/builtin/workflows/src/tui/inputs-picker.ts +8 -7
  90. package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
  91. package/dist/builtin/workflows/src/tui/node-card.ts +34 -8
  92. package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -11
  93. package/dist/builtin/workflows/src/tui/prompt-card.ts +98 -50
  94. package/dist/builtin/workflows/src/tui/session-list.ts +7 -2
  95. package/dist/builtin/workflows/src/tui/session-picker.ts +2 -0
  96. package/dist/builtin/workflows/src/tui/stage-chat-view.ts +226 -55
  97. package/dist/builtin/workflows/src/tui/status-helpers.ts +2 -0
  98. package/dist/builtin/workflows/src/tui/store-widget-installer.ts +37 -158
  99. package/dist/builtin/workflows/src/tui/toast.ts +2 -2
  100. package/dist/builtin/workflows/src/tui/widget.ts +53 -12
  101. package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +270 -19
  102. package/dist/builtin/workflows/src/tui/workflow-notice-card.ts +184 -0
  103. package/dist/builtin/workflows/src/workflows/define-workflow.ts +138 -43
  104. package/dist/config.d.ts +9 -0
  105. package/dist/config.d.ts.map +1 -1
  106. package/dist/config.js +45 -0
  107. package/dist/config.js.map +1 -1
  108. package/dist/core/agent-session.d.ts +27 -9
  109. package/dist/core/agent-session.d.ts.map +1 -1
  110. package/dist/core/agent-session.js +196 -17
  111. package/dist/core/agent-session.js.map +1 -1
  112. package/dist/core/atomic-guide-command.d.ts.map +1 -1
  113. package/dist/core/atomic-guide-command.js +2 -2
  114. package/dist/core/atomic-guide-command.js.map +1 -1
  115. package/dist/core/codex-fast-mode.d.ts +36 -0
  116. package/dist/core/codex-fast-mode.d.ts.map +1 -0
  117. package/dist/core/codex-fast-mode.js +117 -0
  118. package/dist/core/codex-fast-mode.js.map +1 -0
  119. package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
  120. package/dist/core/compaction/branch-summarization.js +1 -1
  121. package/dist/core/compaction/branch-summarization.js.map +1 -1
  122. package/dist/core/compaction/compaction.d.ts.map +1 -1
  123. package/dist/core/compaction/compaction.js +1 -1
  124. package/dist/core/compaction/compaction.js.map +1 -1
  125. package/dist/core/extensions/index.d.ts +4 -1
  126. package/dist/core/extensions/index.d.ts.map +1 -1
  127. package/dist/core/extensions/index.js +1 -0
  128. package/dist/core/extensions/index.js.map +1 -1
  129. package/dist/core/extensions/loader.d.ts +7 -2
  130. package/dist/core/extensions/loader.d.ts.map +1 -1
  131. package/dist/core/extensions/loader.js +23 -8
  132. package/dist/core/extensions/loader.js.map +1 -1
  133. package/dist/core/extensions/reactive-widget.d.ts +58 -0
  134. package/dist/core/extensions/reactive-widget.d.ts.map +1 -0
  135. package/dist/core/extensions/reactive-widget.js +182 -0
  136. package/dist/core/extensions/reactive-widget.js.map +1 -0
  137. package/dist/core/extensions/runner.d.ts.map +1 -1
  138. package/dist/core/extensions/runner.js +1 -0
  139. package/dist/core/extensions/runner.js.map +1 -1
  140. package/dist/core/extensions/types.d.ts +26 -12
  141. package/dist/core/extensions/types.d.ts.map +1 -1
  142. package/dist/core/extensions/types.js.map +1 -1
  143. package/dist/core/messages.d.ts +1 -1
  144. package/dist/core/messages.d.ts.map +1 -1
  145. package/dist/core/messages.js +8 -2
  146. package/dist/core/messages.js.map +1 -1
  147. package/dist/core/model-registry.d.ts +4 -0
  148. package/dist/core/model-registry.d.ts.map +1 -1
  149. package/dist/core/model-registry.js +11 -0
  150. package/dist/core/model-registry.js.map +1 -1
  151. package/dist/core/resource-loader.d.ts +9 -1
  152. package/dist/core/resource-loader.d.ts.map +1 -1
  153. package/dist/core/resource-loader.js +49 -21
  154. package/dist/core/resource-loader.js.map +1 -1
  155. package/dist/core/sdk.d.ts.map +1 -1
  156. package/dist/core/sdk.js +22 -13
  157. package/dist/core/sdk.js.map +1 -1
  158. package/dist/core/session-manager.d.ts +7 -5
  159. package/dist/core/session-manager.d.ts.map +1 -1
  160. package/dist/core/session-manager.js +5 -3
  161. package/dist/core/session-manager.js.map +1 -1
  162. package/dist/core/settings-manager.d.ts +16 -0
  163. package/dist/core/settings-manager.d.ts.map +1 -1
  164. package/dist/core/settings-manager.js +64 -5
  165. package/dist/core/settings-manager.js.map +1 -1
  166. package/dist/core/slash-commands.d.ts.map +1 -1
  167. package/dist/core/slash-commands.js +1 -0
  168. package/dist/core/slash-commands.js.map +1 -1
  169. package/dist/core/system-prompt.d.ts.map +1 -1
  170. package/dist/core/system-prompt.js +7 -4
  171. package/dist/core/system-prompt.js.map +1 -1
  172. package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
  173. package/dist/core/tools/ask-user-question/ask-user-question.js +2 -2
  174. package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
  175. package/dist/index.d.ts +4 -3
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +3 -2
  178. package/dist/index.js.map +1 -1
  179. package/dist/main.d.ts +3 -0
  180. package/dist/main.d.ts.map +1 -1
  181. package/dist/main.js +12 -0
  182. package/dist/main.js.map +1 -1
  183. package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
  184. package/dist/modes/interactive/chat-input-actions.js.map +1 -1
  185. package/dist/modes/interactive/components/diff.d.ts.map +1 -1
  186. package/dist/modes/interactive/components/diff.js +0 -1
  187. package/dist/modes/interactive/components/diff.js.map +1 -1
  188. package/dist/modes/interactive/components/fast-mode-selector.d.ts +27 -0
  189. package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -0
  190. package/dist/modes/interactive/components/fast-mode-selector.js +105 -0
  191. package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -0
  192. package/dist/modes/interactive/components/footer.d.ts.map +1 -1
  193. package/dist/modes/interactive/components/footer.js +7 -12
  194. package/dist/modes/interactive/components/footer.js.map +1 -1
  195. package/dist/modes/interactive/components/index.d.ts +1 -0
  196. package/dist/modes/interactive/components/index.d.ts.map +1 -1
  197. package/dist/modes/interactive/components/index.js +1 -0
  198. package/dist/modes/interactive/components/index.js.map +1 -1
  199. package/dist/modes/interactive/interactive-mode.d.ts +4 -0
  200. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  201. package/dist/modes/interactive/interactive-mode.js +132 -30
  202. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  203. package/dist/modes/print-mode.d.ts.map +1 -1
  204. package/dist/modes/print-mode.js +53 -6
  205. package/dist/modes/print-mode.js.map +1 -1
  206. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  207. package/dist/modes/rpc/rpc-mode.js +3 -0
  208. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  209. package/docs/compaction.md +1 -1
  210. package/docs/custom-provider.md +2 -2
  211. package/docs/development.md +2 -2
  212. package/docs/docs.json +2 -2
  213. package/docs/extensions.md +18 -13
  214. package/docs/providers.md +5 -1
  215. package/docs/quickstart.md +5 -3
  216. package/docs/rpc.md +5 -5
  217. package/docs/sdk.md +12 -12
  218. package/docs/settings.md +18 -0
  219. package/docs/themes.md +6 -6
  220. package/docs/tui.md +20 -18
  221. package/docs/usage.md +2 -0
  222. package/docs/workflows.md +403 -39
  223. package/examples/extensions/qna.ts +2 -2
  224. package/package.json +4 -4
  225. package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +0 -392
  226. package/dist/builtin/subagents/skills/playwright-cli/references/element-attributes.md +0 -23
  227. package/dist/builtin/subagents/skills/playwright-cli/references/playwright-tests.md +0 -39
  228. package/dist/builtin/subagents/skills/playwright-cli/references/request-mocking.md +0 -87
  229. package/dist/builtin/subagents/skills/playwright-cli/references/running-code.md +0 -241
  230. package/dist/builtin/subagents/skills/playwright-cli/references/session-management.md +0 -225
  231. package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
  232. package/dist/builtin/subagents/skills/playwright-cli/references/storage-state.md +0 -275
  233. package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +0 -134
  234. package/dist/builtin/subagents/skills/playwright-cli/references/tracing.md +0 -139
  235. package/dist/builtin/subagents/skills/playwright-cli/references/video-recording.md +0 -143
@@ -2,7 +2,13 @@ import * as fs from "node:fs";
2
2
  import * as os from "node:os";
3
3
  import * as path from "node:path";
4
4
  import { fileURLToPath } from "node:url";
5
- import { APP_NAME, getEnvValue } from "@bastani/atomic";
5
+ import {
6
+ APP_NAME,
7
+ ENV_CODEX_FAST_MODE,
8
+ getEnvValue,
9
+ type CodexFastModeResolvedSettings,
10
+ type CodexFastModeScope,
11
+ } from "@bastani/atomic";
6
12
  import { encodeNestedPathEnv, parseNestedPathEnv, type NestedPathEntry } from "./nested-path.ts";
7
13
  import { resolveMcpDirectToolNames } from "./mcp-direct-tool-allowlist.ts";
8
14
 
@@ -60,6 +66,8 @@ interface BuildPiArgsInput {
60
66
  parentDepth?: number;
61
67
  parentPath?: NestedPathEntry[];
62
68
  parentCapabilityToken?: string;
69
+ codexFastModeSettings?: CodexFastModeResolvedSettings;
70
+ codexFastModeScope?: CodexFastModeScope;
63
71
  }
64
72
 
65
73
  interface BuildPiArgsResult {
@@ -75,6 +83,20 @@ export function applyThinkingSuffix(model: string | undefined, thinking: string
75
83
  return `${model}:${thinking}`;
76
84
  }
77
85
 
86
+ function serializeChildCodexFastModeSettings(settings: CodexFastModeResolvedSettings): string {
87
+ return `chat=${settings.chat ? "1" : "0"};workflow=${settings.workflow ? "1" : "0"}`;
88
+ }
89
+
90
+ function mapChildCodexFastModeSettings(
91
+ settings: CodexFastModeResolvedSettings,
92
+ scope: CodexFastModeScope,
93
+ ): CodexFastModeResolvedSettings {
94
+ return {
95
+ chat: settings[scope],
96
+ workflow: settings.workflow,
97
+ };
98
+ }
99
+
78
100
  export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
79
101
  const args = [...input.baseArgs];
80
102
 
@@ -155,6 +177,11 @@ export function buildPiArgs(input: BuildPiArgsInput): BuildPiArgsResult {
155
177
  const env: Record<string, string | undefined> = {};
156
178
  env[SUBAGENT_CHILD_ENV] = "1";
157
179
  env[SUBAGENT_FANOUT_CHILD_ENV] = fanoutAuthorized ? "1" : "0";
180
+ if (input.codexFastModeSettings) {
181
+ env[ENV_CODEX_FAST_MODE] = serializeChildCodexFastModeSettings(
182
+ mapChildCodexFastModeSettings(input.codexFastModeSettings, input.codexFastModeScope ?? "chat"),
183
+ );
184
+ }
158
185
  const parentEventSinkEnv = getEnvValue(SUBAGENT_PARENT_EVENT_SINK_ENV);
159
186
  const parentControlInboxEnv = getEnvValue(SUBAGENT_PARENT_CONTROL_INBOX_ENV);
160
187
  const parentRootRunIdEnv = getEnvValue(SUBAGENT_PARENT_ROOT_RUN_ID_ENV);
@@ -0,0 +1,80 @@
1
+ import {
2
+ SettingsManager,
3
+ isCodexFastModeCandidateModelId,
4
+ shouldApplyCodexFastModeForScope,
5
+ type CodexFastModeResolvedSettings,
6
+ type CodexFastModeScope,
7
+ } from "@bastani/atomic";
8
+ import { splitKnownThinkingSuffix } from "./model-info.ts";
9
+
10
+ export interface ResolveSubagentModelFastModeInput {
11
+ model?: string;
12
+ cwd: string;
13
+ settings?: CodexFastModeResolvedSettings;
14
+ scope?: CodexFastModeScope;
15
+ }
16
+
17
+ export interface ResolveSubagentModelFastModeMapInput {
18
+ models: readonly (string | undefined)[];
19
+ cwd: string;
20
+ settings?: CodexFastModeResolvedSettings;
21
+ scope?: CodexFastModeScope;
22
+ }
23
+
24
+ export interface ResolveSubagentModelFastModeMetadataInput {
25
+ model?: string;
26
+ modelCandidates: readonly (string | undefined)[];
27
+ cwd: string;
28
+ settings?: CodexFastModeResolvedSettings;
29
+ scope?: CodexFastModeScope;
30
+ }
31
+
32
+ export interface SubagentModelFastModeMetadata {
33
+ fastMode?: true;
34
+ modelFastModes: Record<string, boolean>;
35
+ }
36
+
37
+ export function getSubagentCodexFastModeSettings(cwd: string): CodexFastModeResolvedSettings {
38
+ try {
39
+ return SettingsManager.create(cwd).getCodexFastModeSettings();
40
+ } catch {
41
+ return { chat: false, workflow: false };
42
+ }
43
+ }
44
+
45
+ function providerFromModelId(model: string | undefined): string | undefined {
46
+ if (!model) return undefined;
47
+ const { baseModel } = splitKnownThinkingSuffix(model);
48
+ if (!isCodexFastModeCandidateModelId(baseModel)) return undefined;
49
+ return baseModel.split("/", 1)[0];
50
+ }
51
+
52
+ export function resolveSubagentCodexFastModeScope(workflowStageSubagentGuard: boolean | undefined): CodexFastModeScope {
53
+ return workflowStageSubagentGuard ? "workflow" : "chat";
54
+ }
55
+
56
+ export function resolveSubagentModelFastMode(input: ResolveSubagentModelFastModeInput): boolean {
57
+ const provider = providerFromModelId(input.model);
58
+ if (!provider) return false;
59
+ const settings = input.settings ?? getSubagentCodexFastModeSettings(input.cwd);
60
+ return shouldApplyCodexFastModeForScope({ provider }, settings, input.scope ?? "chat");
61
+ }
62
+
63
+ export function resolveSubagentModelFastModeMap(input: ResolveSubagentModelFastModeMapInput): Record<string, boolean> {
64
+ const settings = input.settings ?? getSubagentCodexFastModeSettings(input.cwd);
65
+ const fastModes: Record<string, boolean> = {};
66
+ for (const model of input.models) {
67
+ if (!model || Object.prototype.hasOwnProperty.call(fastModes, model)) continue;
68
+ fastModes[model] = resolveSubagentModelFastMode({ model, cwd: input.cwd, settings, scope: input.scope });
69
+ }
70
+ return fastModes;
71
+ }
72
+
73
+ export function resolveSubagentModelFastModeMetadata(input: ResolveSubagentModelFastModeMetadataInput): SubagentModelFastModeMetadata {
74
+ const settings = input.settings ?? getSubagentCodexFastModeSettings(input.cwd);
75
+ const fastMode = resolveSubagentModelFastMode({ model: input.model, cwd: input.cwd, settings, scope: input.scope });
76
+ return {
77
+ ...(fastMode ? { fastMode: true as const } : {}),
78
+ modelFastModes: resolveSubagentModelFastModeMap({ models: input.modelCandidates, cwd: input.cwd, settings, scope: input.scope }),
79
+ };
80
+ }
@@ -16,7 +16,7 @@ export function formatTokens(n: number): string {
16
16
  return n < 1000 ? String(n) : n < 10000 ? `${(n / 1000).toFixed(1)}k` : `${Math.round(n / 1000)}k`;
17
17
  }
18
18
 
19
- export function formatModelThinking(model?: string, thinking?: string): string {
19
+ export function formatModelThinking(model?: string, thinking?: string, fastMode?: boolean): string {
20
20
  const parsed = model ? splitKnownThinkingSuffix(model) : undefined;
21
21
  let displayModel = parsed?.baseModel ?? model;
22
22
  const explicitThinking = THINKING_LEVELS.find((level) => level === thinking?.trim());
@@ -25,7 +25,9 @@ export function formatModelThinking(model?: string, thinking?: string): string {
25
25
  const slashIdx = displayModel.lastIndexOf("/");
26
26
  if (slashIdx !== -1) displayModel = displayModel.slice(slashIdx + 1);
27
27
  }
28
- return [displayModel, displayThinking ? `thinking ${displayThinking}` : undefined].filter(Boolean).join(" · ");
28
+ const parts = [displayModel, displayThinking ? `thinking ${displayThinking}` : undefined].filter(Boolean);
29
+ if (fastMode && parts.length > 0) parts.push("fast");
30
+ return parts.join(" · ");
29
31
  }
30
32
 
31
33
  /**
@@ -211,6 +211,7 @@ export interface SingleResult {
211
211
  messages?: Message[];
212
212
  usage: Usage;
213
213
  model?: string;
214
+ fastMode?: boolean;
214
215
  attemptedModels?: string[];
215
216
  modelAttempts?: ModelAttempt[];
216
217
  controlEvents?: ControlEvent[];
@@ -416,6 +417,7 @@ export interface AsyncStatus {
416
417
  skills?: string[];
417
418
  model?: string;
418
419
  thinking?: string;
420
+ fastMode?: boolean;
419
421
  attemptedModels?: string[];
420
422
  modelAttempts?: ModelAttempt[];
421
423
  error?: string;
@@ -522,8 +524,8 @@ export interface SubagentState {
522
524
  // Display
523
525
  // ============================================================================
524
526
 
525
- export type DisplayItem =
526
- | { type: "text"; text: string }
527
+ export type DisplayItem =
528
+ | { type: "text"; text: string }
527
529
  | { type: "tool"; name: string; args: Record<string, unknown> };
528
530
 
529
531
  // ============================================================================
@@ -3,10 +3,9 @@
3
3
  */
4
4
 
5
5
  import * as fs from "node:fs";
6
- import * as os from "node:os";
7
6
  import * as path from "node:path";
8
7
  import type { Message } from "@earendil-works/pi-ai";
9
- import { APP_NAME, getAgentDir as getAtomicAgentDir } from "@bastani/atomic";
8
+ import { getAgentDir as getAtomicAgentDir } from "@bastani/atomic";
10
9
  import { formatToolCall } from "./formatters.ts";
11
10
  import type { AgentProgress, AsyncStatus, Details, DisplayItem, ErrorInfo, SingleResult, ToolCallSummary } from "./types.ts";
12
11
 
@@ -84,53 +83,6 @@ export function readStatus(asyncDir: string): AsyncStatus | null {
84
83
  return status;
85
84
  }
86
85
 
87
- const outputTailCache = new Map<string, { mtime: number; size: number; lines: string[] }>();
88
-
89
- /**
90
- * Get the last N lines from an output file (with mtime/size-based caching)
91
- */
92
- function getOutputTail(outputFile: string | undefined, maxLines: number = 3): string[] {
93
- if (!outputFile) return [];
94
- let fd: number | null = null;
95
- try {
96
- const stat = fs.statSync(outputFile);
97
- if (stat.size === 0) return [];
98
-
99
- const cached = outputTailCache.get(outputFile);
100
- if (cached && cached.mtime === stat.mtimeMs && cached.size === stat.size) {
101
- return cached.lines;
102
- }
103
-
104
- const tailBytes = 4096;
105
- const start = Math.max(0, stat.size - tailBytes);
106
- fd = fs.openSync(outputFile, "r");
107
- const buffer = Buffer.alloc(Math.min(tailBytes, stat.size));
108
- fs.readSync(fd, buffer, 0, buffer.length, start);
109
- const content = buffer.toString("utf-8");
110
- const allLines = content.split("\n").filter((l) => l.trim());
111
- const lines = allLines.slice(-maxLines).map((l) => l.slice(0, 120) + (l.length > 120 ? "..." : ""));
112
-
113
- outputTailCache.set(outputFile, { mtime: stat.mtimeMs, size: stat.size, lines });
114
- if (outputTailCache.size > 20) {
115
- const firstKey = outputTailCache.keys().next().value;
116
- if (firstKey) outputTailCache.delete(firstKey);
117
- }
118
-
119
- return lines;
120
- } catch {
121
- // Output tails are UI-only hints; unreadable or missing files should render as no tail.
122
- return [];
123
- } finally {
124
- if (fd !== null) {
125
- try {
126
- fs.closeSync(fd);
127
- } catch {
128
- // Closing the best-effort tail file handle should not surface over the main status view.
129
- }
130
- }
131
- }
132
- }
133
-
134
86
  /**
135
87
  * Get human-readable last activity time for a file
136
88
  */
@@ -166,16 +118,6 @@ export function findLatestSessionFile(sessionDir: string): string | null {
166
118
  return files.length > 0 ? files[0].path : null;
167
119
  }
168
120
 
169
- /**
170
- * Write a prompt to a temporary file
171
- */
172
- function writePrompt(agent: string, prompt: string): { dir: string; path: string } {
173
- const dir = fs.mkdtempSync(path.join(os.tmpdir(), `${APP_NAME}-subagent-`));
174
- const p = path.join(dir, `${agent.replace(/[^\w.-]/g, "_")}.md`);
175
- fs.writeFileSync(p, prompt, { mode: 0o600 });
176
- return { dir, path: p };
177
- }
178
-
179
121
  // ============================================================================
180
122
  // Message Parsing Utilities
181
123
  // ============================================================================
@@ -390,7 +332,7 @@ export function extractToolArgsPreview(args: Record<string, unknown>): string {
390
332
  const urlsPreview = previewArray(args.urls);
391
333
  if (urlsPreview) return truncatePreview(urlsPreview, 60);
392
334
  if (typeof args.prompt === "string" && args.prompt.trim().length > 0) return truncatePreview(args.prompt, 60);
393
-
335
+
394
336
  const previewKeys = ["command", "path", "file_path", "pattern", "query", "url", "task", "describe", "search"];
395
337
  for (const key of previewKeys) {
396
338
  if (args[key] && typeof args[key] === "string") {
@@ -398,7 +340,7 @@ export function extractToolArgsPreview(args: Record<string, unknown>): string {
398
340
  return truncatePreview(value, 60);
399
341
  }
400
342
  }
401
-
343
+
402
344
  // Fallback: show first string value found
403
345
  for (const [key, value] of Object.entries(args)) {
404
346
  const arrayPreview = previewArray(value);