@bastani/atomic 0.8.21 → 0.8.22-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +40 -9
- package/dist/builtin/intercom/broker/broker.ts +3 -3
- package/dist/builtin/intercom/config.ts +3 -3
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/ui/compose.ts +2 -2
- package/dist/builtin/mcp/host-html-template.ts +0 -3
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +13 -4
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +9 -9
- package/dist/builtin/subagents/agents/debugger.md +6 -6
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/prompts/parallel-handoff-plan.md +1 -1
- package/dist/builtin/subagents/skills/browser-use/SKILL.md +234 -0
- package/dist/builtin/subagents/skills/browser-use/references/cdp-python.md +76 -0
- package/dist/builtin/subagents/skills/browser-use/references/multi-session.md +92 -0
- package/dist/builtin/subagents/skills/subagent/SKILL.md +4 -4
- package/dist/builtin/subagents/src/agents/skills.ts +19 -1
- package/dist/builtin/subagents/src/extension/index.ts +24 -22
- package/dist/builtin/subagents/src/intercom/intercom-bridge.ts +7 -1
- package/dist/builtin/subagents/src/runs/background/async-execution.ts +23 -7
- package/dist/builtin/subagents/src/runs/background/async-job-tracker.ts +98 -3
- package/dist/builtin/subagents/src/runs/background/async-status.ts +3 -1
- package/dist/builtin/subagents/src/runs/background/run-status.ts +1 -1
- package/dist/builtin/subagents/src/runs/background/stale-run-reconciler.ts +3 -0
- package/dist/builtin/subagents/src/runs/background/subagent-runner.ts +37 -12
- package/dist/builtin/subagents/src/runs/foreground/chain-clarify.ts +15 -15
- package/dist/builtin/subagents/src/runs/foreground/execution.ts +26 -2
- package/dist/builtin/subagents/src/runs/shared/nested-render.ts +1 -1
- package/dist/builtin/subagents/src/runs/shared/parallel-utils.ts +7 -0
- package/dist/builtin/subagents/src/runs/shared/pi-args.ts +28 -1
- package/dist/builtin/subagents/src/shared/fast-mode.ts +80 -0
- package/dist/builtin/subagents/src/shared/formatters.ts +4 -2
- package/dist/builtin/subagents/src/shared/types.ts +4 -2
- package/dist/builtin/subagents/src/shared/utils.ts +3 -61
- package/dist/builtin/subagents/src/tui/render.ts +303 -157
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/CHANGELOG.md +95 -35
- package/dist/builtin/workflows/README.md +228 -41
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +535 -541
- package/dist/builtin/workflows/builtin/goal.ts +39 -25
- package/dist/builtin/workflows/builtin/open-claude-design.ts +66 -69
- package/dist/builtin/workflows/builtin/ralph.ts +21 -21
- package/dist/builtin/workflows/package.json +6 -5
- package/dist/builtin/workflows/skills/research-codebase/SKILL.md +1 -1
- package/dist/builtin/workflows/src/extension/background-ui-adapter.ts +2 -2
- package/dist/builtin/workflows/src/extension/discovery.ts +25 -146
- package/dist/builtin/workflows/src/extension/dispatcher.ts +72 -24
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +363 -0
- package/dist/builtin/workflows/src/extension/index.ts +690 -352
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +99 -62
- package/dist/builtin/workflows/src/extension/render-call.ts +2 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +9 -3
- package/dist/builtin/workflows/src/extension/renderers.ts +5 -3
- package/dist/builtin/workflows/src/extension/runtime.ts +68 -33
- package/dist/builtin/workflows/src/extension/status-writer.ts +1 -1
- package/dist/builtin/workflows/src/extension/wiring.ts +34 -13
- package/dist/builtin/workflows/src/extension/workflow-module-loader.ts +142 -0
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +4 -4
- package/dist/builtin/workflows/src/index.ts +2 -0
- package/dist/builtin/workflows/src/intercom/result-intercom.ts +1 -1
- package/dist/builtin/workflows/src/runs/background/runner.ts +6 -4
- package/dist/builtin/workflows/src/runs/background/status.ts +45 -21
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +624 -52
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +1 -1
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +80 -24
- package/dist/builtin/workflows/src/runs/shared/validate-inputs.ts +61 -24
- package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +32 -10
- package/dist/builtin/workflows/src/sdk-surface.ts +6 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +178 -0
- package/dist/builtin/workflows/src/shared/persistence-restore.ts +92 -12
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +21 -3
- package/dist/builtin/workflows/src/shared/render-inputs-schema.ts +1 -2
- package/dist/builtin/workflows/src/shared/run-visibility.ts +9 -0
- package/dist/builtin/workflows/src/shared/schema-introspection.ts +121 -0
- package/dist/builtin/workflows/src/shared/serializable.ts +132 -0
- package/dist/builtin/workflows/src/shared/stage-ui-broker.ts +91 -9
- package/dist/builtin/workflows/src/shared/store-types.ts +31 -3
- package/dist/builtin/workflows/src/shared/store.ts +58 -14
- package/dist/builtin/workflows/src/shared/types.ts +105 -40
- package/dist/builtin/workflows/src/tui/chat-surface-message.ts +129 -13
- package/dist/builtin/workflows/src/tui/chat-surface.ts +6 -1
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +3 -2
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +1 -1
- package/dist/builtin/workflows/src/tui/graph-view.ts +91 -65
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/inline-form-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-overlay.ts +3 -2
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +8 -7
- package/dist/builtin/workflows/src/tui/keybindings-adapter.ts +2 -0
- package/dist/builtin/workflows/src/tui/node-card.ts +34 -8
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -11
- package/dist/builtin/workflows/src/tui/prompt-card.ts +98 -50
- package/dist/builtin/workflows/src/tui/session-list.ts +7 -2
- package/dist/builtin/workflows/src/tui/session-picker.ts +2 -0
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +226 -55
- package/dist/builtin/workflows/src/tui/status-helpers.ts +2 -0
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +37 -158
- package/dist/builtin/workflows/src/tui/toast.ts +2 -2
- package/dist/builtin/workflows/src/tui/widget.ts +53 -12
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +270 -19
- package/dist/builtin/workflows/src/tui/workflow-notice-card.ts +184 -0
- package/dist/builtin/workflows/src/workflows/define-workflow.ts +138 -43
- package/dist/config.d.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +45 -0
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +27 -9
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +196 -17
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/atomic-guide-command.d.ts.map +1 -1
- package/dist/core/atomic-guide-command.js +2 -2
- package/dist/core/atomic-guide-command.js.map +1 -1
- package/dist/core/codex-fast-mode.d.ts +36 -0
- package/dist/core/codex-fast-mode.d.ts.map +1 -0
- package/dist/core/codex-fast-mode.js +117 -0
- package/dist/core/codex-fast-mode.js.map +1 -0
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/extensions/index.d.ts +4 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js +1 -0
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +7 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +23 -8
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/reactive-widget.d.ts +58 -0
- package/dist/core/extensions/reactive-widget.d.ts.map +1 -0
- package/dist/core/extensions/reactive-widget.js +182 -0
- package/dist/core/extensions/reactive-widget.js.map +1 -0
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +1 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +26 -12
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/messages.d.ts +1 -1
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +8 -2
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-registry.d.ts +4 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +11 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/resource-loader.d.ts +9 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +49 -21
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +22 -13
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts +7 -5
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +5 -3
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +16 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +64 -5
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/system-prompt.d.ts.map +1 -1
- package/dist/core/system-prompt.js +7 -4
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/ask-user-question.js +2 -2
- package/dist/core/tools/ask-user-question/ask-user-question.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +12 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/chat-input-actions.d.ts.map +1 -1
- package/dist/modes/interactive/chat-input-actions.js.map +1 -1
- package/dist/modes/interactive/components/diff.d.ts.map +1 -1
- package/dist/modes/interactive/components/diff.js +0 -1
- package/dist/modes/interactive/components/diff.js.map +1 -1
- package/dist/modes/interactive/components/fast-mode-selector.d.ts +27 -0
- package/dist/modes/interactive/components/fast-mode-selector.d.ts.map +1 -0
- package/dist/modes/interactive/components/fast-mode-selector.js +105 -0
- package/dist/modes/interactive/components/fast-mode-selector.js.map +1 -0
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +7 -12
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +1 -0
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +1 -0
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +4 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +132 -30
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +53 -6
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +3 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/docs/compaction.md +1 -1
- package/docs/custom-provider.md +2 -2
- package/docs/development.md +2 -2
- package/docs/docs.json +2 -2
- package/docs/extensions.md +18 -13
- package/docs/providers.md +5 -1
- package/docs/quickstart.md +5 -3
- package/docs/rpc.md +5 -5
- package/docs/sdk.md +12 -12
- package/docs/settings.md +18 -0
- package/docs/themes.md +6 -6
- package/docs/tui.md +20 -18
- package/docs/usage.md +2 -0
- package/docs/workflows.md +403 -39
- package/examples/extensions/qna.ts +2 -2
- package/package.json +4 -4
- package/dist/builtin/subagents/skills/playwright-cli/SKILL.md +0 -392
- package/dist/builtin/subagents/skills/playwright-cli/references/element-attributes.md +0 -23
- package/dist/builtin/subagents/skills/playwright-cli/references/playwright-tests.md +0 -39
- package/dist/builtin/subagents/skills/playwright-cli/references/request-mocking.md +0 -87
- package/dist/builtin/subagents/skills/playwright-cli/references/running-code.md +0 -241
- package/dist/builtin/subagents/skills/playwright-cli/references/session-management.md +0 -225
- package/dist/builtin/subagents/skills/playwright-cli/references/spec-driven-testing.md +0 -305
- package/dist/builtin/subagents/skills/playwright-cli/references/storage-state.md +0 -275
- package/dist/builtin/subagents/skills/playwright-cli/references/test-generation.md +0 -134
- package/dist/builtin/subagents/skills/playwright-cli/references/tracing.md +0 -139
- package/dist/builtin/subagents/skills/playwright-cli/references/video-recording.md +0 -143
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* - input reuses the host's custom editor factory when one is installed,
|
|
11
11
|
* otherwise `CustomEditor`; tests/headless fall back to the historical
|
|
12
12
|
* one-line editor
|
|
13
|
-
* - workflow notices
|
|
13
|
+
* - workflow notices render as compact workflow-specific cards because they
|
|
14
14
|
* are not coding-agent chat messages
|
|
15
15
|
*
|
|
16
16
|
* Behaviour:
|
|
@@ -66,8 +66,9 @@ import {
|
|
|
66
66
|
import type { PendingPrompt, StageNotice, StageSnapshot, StageStatus } from "../shared/store-types.js";
|
|
67
67
|
import type { GraphTheme } from "./graph-theme.js";
|
|
68
68
|
import type { StageControlHandle } from "../runs/foreground/stage-control-registry.js";
|
|
69
|
-
import { isKeybindingsLike } from "./keybindings-adapter.js";
|
|
69
|
+
import { isKeybindingsLike, type KeybindingsLike } from "./keybindings-adapter.js";
|
|
70
70
|
import { BOLD, RESET, hexBg, hexToAnsi, lerpColor } from "./color-utils.js";
|
|
71
|
+
import { renderWorkflowNoticeCard, type WorkflowNoticeTone } from "./workflow-notice-card.js";
|
|
71
72
|
import { Key, matchesKey, visibleWidth } from "./text-helpers.js";
|
|
72
73
|
import {
|
|
73
74
|
fitStageChatFrame,
|
|
@@ -78,6 +79,7 @@ import {
|
|
|
78
79
|
createPromptCardState,
|
|
79
80
|
defaultResponseFor,
|
|
80
81
|
handlePromptCardInput,
|
|
82
|
+
isPromptEscapeInput,
|
|
81
83
|
renderPromptCard,
|
|
82
84
|
type PromptCardState,
|
|
83
85
|
} from "./prompt-card.js";
|
|
@@ -104,7 +106,7 @@ export interface StageChatViewOpts {
|
|
|
104
106
|
*/
|
|
105
107
|
handle?: StageControlHandle;
|
|
106
108
|
/** Called when the user presses Ctrl+D outside a paused stage (back to graph). */
|
|
107
|
-
onDetach: () => void;
|
|
109
|
+
onDetach: (reason?: StageChatDetachReason, metadata?: StageChatDetachMetadata) => void;
|
|
108
110
|
/** Called when the user presses Escape (close the whole popup). */
|
|
109
111
|
onClose: () => void;
|
|
110
112
|
/** Request a host TUI repaint after SDK events mutate local chat state. */
|
|
@@ -141,6 +143,12 @@ export interface StageChatViewOpts {
|
|
|
141
143
|
getViewportRows?: () => number | undefined;
|
|
142
144
|
/** Broker that routes stage-local custom UI, such as ask_user_question, into this node. */
|
|
143
145
|
stageUiBroker?: StageUiBroker;
|
|
146
|
+
/**
|
|
147
|
+
* Ownership guard for prompt submission. The attach shell uses this to ensure
|
|
148
|
+
* stale/hidden/non-active stage-chat instances cannot settle a prompt unless
|
|
149
|
+
* the user is currently attached to this exact workflow node.
|
|
150
|
+
*/
|
|
151
|
+
canSubmitPrompt?: (runId: string, stageId: string, promptId: string) => boolean;
|
|
144
152
|
}
|
|
145
153
|
|
|
146
154
|
/**
|
|
@@ -148,6 +156,12 @@ export interface StageChatViewOpts {
|
|
|
148
156
|
* that read `_transcript` (tests, future serialisers) can recover the
|
|
149
157
|
* canonical user-visible string without knowing about the Pi-box payload.
|
|
150
158
|
*/
|
|
159
|
+
export type StageChatDetachReason = "user" | "prompt-resolved";
|
|
160
|
+
|
|
161
|
+
export interface StageChatDetachMetadata {
|
|
162
|
+
readonly suppressNextGraphSubmit?: boolean;
|
|
163
|
+
}
|
|
164
|
+
|
|
151
165
|
interface NoticeEntry {
|
|
152
166
|
readonly role: "notice";
|
|
153
167
|
readonly text: string;
|
|
@@ -158,7 +172,6 @@ interface NoticeEntry {
|
|
|
158
172
|
readonly meta?: string;
|
|
159
173
|
}
|
|
160
174
|
type TranscriptEntry = NoticeEntry | ChatMessageEntry;
|
|
161
|
-
type AgentSnapshotMessage = AgentSession["messages"][number];
|
|
162
175
|
|
|
163
176
|
// ---------------------------------------------------------------------------
|
|
164
177
|
// Frame budget
|
|
@@ -193,7 +206,7 @@ export class StageChatView implements Component, Focusable {
|
|
|
193
206
|
private stageId: string;
|
|
194
207
|
private workflowName: string;
|
|
195
208
|
private handle: StageControlHandle | undefined;
|
|
196
|
-
private onDetach: () => void;
|
|
209
|
+
private onDetach: (reason?: StageChatDetachReason, metadata?: StageChatDetachMetadata) => void;
|
|
197
210
|
private onClose: () => void;
|
|
198
211
|
private requestRender: (() => void) | undefined;
|
|
199
212
|
private requestFocus: (() => void) | undefined;
|
|
@@ -205,17 +218,15 @@ export class StageChatView implements Component, Focusable {
|
|
|
205
218
|
private piEditorFactory?: StageChatViewOpts["piEditorFactory"];
|
|
206
219
|
private chatHost: ChatSessionHost<NoticeEntry>;
|
|
207
220
|
private stageUiBroker: StageUiBroker;
|
|
221
|
+
private canSubmitPrompt?: (runId: string, stageId: string, promptId: string) => boolean;
|
|
208
222
|
private mountedCustomUi: MountedStageCustomUi | null = null;
|
|
209
223
|
private mountingRequestId: string | null = null;
|
|
210
224
|
private promptState: PromptCardState | null = null;
|
|
211
225
|
private promptEditor: EditorComponent | null = null;
|
|
212
226
|
private promptEditorPromptId: string | null = null;
|
|
227
|
+
private promptEditorSubmitFromEnter = false;
|
|
213
228
|
private promptScrollOffset = 0;
|
|
214
229
|
private promptMaxScroll = 0;
|
|
215
|
-
private getChatRenderSettings?: () =>
|
|
216
|
-
| Partial<Omit<ChatMessageRenderOptions, "ui" | "cwd">>
|
|
217
|
-
| undefined;
|
|
218
|
-
private footerData?: ReadonlyFooterDataProvider;
|
|
219
230
|
|
|
220
231
|
/** True while a pending pause request is in flight (between ctrl+p and resolve). */
|
|
221
232
|
private localPaused = false;
|
|
@@ -260,9 +271,8 @@ export class StageChatView implements Component, Focusable {
|
|
|
260
271
|
this.piTheme = opts.piTheme;
|
|
261
272
|
this.piKeybindings = opts.piKeybindings;
|
|
262
273
|
this.piEditorFactory = opts.piEditorFactory;
|
|
263
|
-
this.getChatRenderSettings = opts.getChatRenderSettings;
|
|
264
|
-
this.footerData = opts.footerData;
|
|
265
274
|
this.stageUiBroker = opts.stageUiBroker ?? stageUiBroker;
|
|
275
|
+
this.canSubmitPrompt = opts.canSubmitPrompt;
|
|
266
276
|
this.chatHost = new ChatSessionHost<NoticeEntry>({
|
|
267
277
|
style: this._chatHostStyle(),
|
|
268
278
|
commands: {
|
|
@@ -364,7 +374,11 @@ export class StageChatView implements Component, Focusable {
|
|
|
364
374
|
// `stage.setModel`, `stage.compact`, …) so they thread through the
|
|
365
375
|
// transcript without a special render path.
|
|
366
376
|
changed = this._absorbStageNotices(stage) || changed;
|
|
367
|
-
|
|
377
|
+
const promptChanged = this._syncPromptState(stage?.pendingPrompt);
|
|
378
|
+
changed = promptChanged || changed;
|
|
379
|
+
if (promptChanged && this.promptState && this._canSubmitPrompt(this.promptState.prompt.id)) {
|
|
380
|
+
this.requestFocus?.();
|
|
381
|
+
}
|
|
368
382
|
this.chatHost.syncAnimationTick();
|
|
369
383
|
if (changed) this.requestRender?.();
|
|
370
384
|
});
|
|
@@ -406,7 +420,7 @@ export class StageChatView implements Component, Focusable {
|
|
|
406
420
|
this.mountingRequestId = null;
|
|
407
421
|
this.stageUiBroker.reject(
|
|
408
422
|
request,
|
|
409
|
-
new Error("
|
|
423
|
+
new Error("atomic-workflows: stage custom UI cannot mount without attached TUI host"),
|
|
410
424
|
);
|
|
411
425
|
return;
|
|
412
426
|
}
|
|
@@ -425,6 +439,7 @@ export class StageChatView implements Component, Focusable {
|
|
|
425
439
|
this.chatHost.scrollToBottom();
|
|
426
440
|
this.requestRender?.();
|
|
427
441
|
},
|
|
442
|
+
() => this._canSubmitPrompt(request.id),
|
|
428
443
|
);
|
|
429
444
|
// Settled or superseded while mounting: drop the freshly-built component
|
|
430
445
|
// instead of showing a gate the broker has already torn down.
|
|
@@ -494,23 +509,30 @@ export class StageChatView implements Component, Focusable {
|
|
|
494
509
|
|
|
495
510
|
private _syncPromptState(prompt: PendingPrompt | undefined): boolean {
|
|
496
511
|
if (!prompt) {
|
|
497
|
-
const
|
|
512
|
+
const hadLivePrompt =
|
|
513
|
+
this.promptState !== null ||
|
|
514
|
+
this.promptEditor !== null ||
|
|
515
|
+
this.promptEditorPromptId !== null;
|
|
516
|
+
if (!hadLivePrompt) return false;
|
|
498
517
|
this.promptState = null;
|
|
499
518
|
this._disposePromptEditor();
|
|
500
|
-
this.
|
|
501
|
-
|
|
502
|
-
return changed;
|
|
519
|
+
this._resetPromptScroll();
|
|
520
|
+
return true;
|
|
503
521
|
}
|
|
504
522
|
if (!this.promptState || this.promptState.prompt.id !== prompt.id) {
|
|
505
523
|
this.promptState = createPromptCardState(prompt);
|
|
506
524
|
this._resetPromptEditor(prompt);
|
|
507
|
-
this.
|
|
508
|
-
this.promptMaxScroll = 0;
|
|
525
|
+
this._resetPromptScroll();
|
|
509
526
|
return true;
|
|
510
527
|
}
|
|
511
528
|
return false;
|
|
512
529
|
}
|
|
513
530
|
|
|
531
|
+
private _resetPromptScroll(): void {
|
|
532
|
+
this.promptScrollOffset = 0;
|
|
533
|
+
this.promptMaxScroll = 0;
|
|
534
|
+
}
|
|
535
|
+
|
|
514
536
|
private _resetPromptEditor(prompt: PendingPrompt): void {
|
|
515
537
|
this._disposePromptEditor();
|
|
516
538
|
if ((prompt.kind !== "input" && prompt.kind !== "editor") || !this.piTui) return;
|
|
@@ -527,7 +549,9 @@ export class StageChatView implements Component, Focusable {
|
|
|
527
549
|
this.requestRender?.();
|
|
528
550
|
};
|
|
529
551
|
editor.onSubmit = (text: string) => {
|
|
530
|
-
this._resolvePromptResponse(prompt.id, text
|
|
552
|
+
this._resolvePromptResponse(prompt.id, text, {
|
|
553
|
+
suppressNextGraphSubmit: this.promptEditorSubmitFromEnter,
|
|
554
|
+
});
|
|
531
555
|
};
|
|
532
556
|
this.promptEditor = editor;
|
|
533
557
|
this.promptEditorPromptId = prompt.id;
|
|
@@ -541,17 +565,27 @@ export class StageChatView implements Component, Focusable {
|
|
|
541
565
|
disposable?.dispose?.();
|
|
542
566
|
}
|
|
543
567
|
|
|
544
|
-
private _resolvePromptResponse(
|
|
568
|
+
private _resolvePromptResponse(
|
|
569
|
+
promptId: string,
|
|
570
|
+
response: unknown,
|
|
571
|
+
metadata: StageChatDetachMetadata = {},
|
|
572
|
+
): void {
|
|
545
573
|
const prompt = this.promptState?.prompt;
|
|
546
574
|
if (!prompt || prompt.id !== promptId) return;
|
|
575
|
+
if (!this._canSubmitPrompt(promptId)) {
|
|
576
|
+
this.requestRender?.();
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
547
579
|
this.promptState = null;
|
|
548
580
|
this._disposePromptEditor();
|
|
581
|
+
this._resetPromptScroll();
|
|
549
582
|
// A false return means the prompt was already resolved/removed (for
|
|
550
583
|
// example by run abort). The local UI is already stale, so clearing it is
|
|
551
|
-
// the least surprising recovery path
|
|
552
|
-
|
|
584
|
+
// the least surprising recovery path, but it must not trigger graph-mode
|
|
585
|
+
// transition side effects for a prompt this view did not actually settle.
|
|
586
|
+
const resolved = this.store.resolveStagePendingPrompt(this.runId, this.stageId, prompt.id, response);
|
|
553
587
|
this.requestRender?.();
|
|
554
|
-
this.onDetach();
|
|
588
|
+
if (resolved) this.onDetach("prompt-resolved", metadata);
|
|
555
589
|
}
|
|
556
590
|
|
|
557
591
|
// -------------------------------------------------------------------------
|
|
@@ -660,13 +694,12 @@ export class StageChatView implements Component, Focusable {
|
|
|
660
694
|
editorRows: customUiActive ? customUiLines.length : editorLines.length,
|
|
661
695
|
footerRows: footerLines.length,
|
|
662
696
|
});
|
|
663
|
-
const visiblePendingLines = pendingLines
|
|
664
|
-
const visibleWorkingLines = workingLines
|
|
665
|
-
const visibleUsageLines = usageLines
|
|
666
|
-
const
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
const visibleFooterLines = footerLines.slice(0, plan.footerRows);
|
|
697
|
+
const visiblePendingLines = takeRows(pendingLines, plan.pendingRows);
|
|
698
|
+
const visibleWorkingLines = takeRows(workingLines, plan.workingRows);
|
|
699
|
+
const visibleUsageLines = takeRows(usageLines, plan.usageRows);
|
|
700
|
+
const editorSlotLines = customUiActive ? customUiLines : editorLines;
|
|
701
|
+
const visibleEditorLines = takeRows(editorSlotLines, plan.editorRows);
|
|
702
|
+
const visibleFooterLines = takeRows(footerLines, plan.footerRows);
|
|
670
703
|
const bodyBudget = plan.bodyRows;
|
|
671
704
|
if (blocked) this.chatHost.scrollToBottom();
|
|
672
705
|
|
|
@@ -675,6 +708,8 @@ export class StageChatView implements Component, Focusable {
|
|
|
675
708
|
bodyLines = this._renderPromptBody(w, bodyBudget);
|
|
676
709
|
} else if (blocked) {
|
|
677
710
|
bodyLines = this._renderBlockedBody(w, bodyBudget, stage);
|
|
711
|
+
} else if (!readOnlyArchive && this._isPaused(stage)) {
|
|
712
|
+
bodyLines = this._renderPausedBody(w, bodyBudget);
|
|
678
713
|
} else if (readOnlyArchive) {
|
|
679
714
|
bodyLines = this._renderReadOnlyArchiveBody(w, bodyBudget, stage);
|
|
680
715
|
} else {
|
|
@@ -829,6 +864,7 @@ export class StageChatView implements Component, Focusable {
|
|
|
829
864
|
bodyLines.push("");
|
|
830
865
|
bodyLines.push(...new Text(paint("your response", t.textMuted, { bold: true }), 2, 0).render(innerWidth));
|
|
831
866
|
bodyLines.push(...new Text(paint(answer, answer.startsWith("(") ? t.dim : t.text), 4, 0).render(innerWidth));
|
|
867
|
+
bodyLines.push("");
|
|
832
868
|
bodyLines.push(...new Text(
|
|
833
869
|
paint("esc", t.accent, { bold: true }) +
|
|
834
870
|
paint(" close", t.textMuted) +
|
|
@@ -867,6 +903,36 @@ export class StageChatView implements Component, Focusable {
|
|
|
867
903
|
}
|
|
868
904
|
}
|
|
869
905
|
|
|
906
|
+
private _renderPausedBody(width: number, budget: number): string[] {
|
|
907
|
+
const t = this.theme;
|
|
908
|
+
const callout: string[] = [];
|
|
909
|
+
callout.push(this._blank(width));
|
|
910
|
+
callout.push(
|
|
911
|
+
...this._bannerLines(
|
|
912
|
+
width,
|
|
913
|
+
"warning",
|
|
914
|
+
"❚❚",
|
|
915
|
+
"PAUSED",
|
|
916
|
+
"enter resumes · ctrl+d close",
|
|
917
|
+
),
|
|
918
|
+
);
|
|
919
|
+
callout.push(
|
|
920
|
+
...new Text(
|
|
921
|
+
paint("This workflow stage is paused. Type a message below and press Enter to resume.", t.textMuted),
|
|
922
|
+
2,
|
|
923
|
+
0,
|
|
924
|
+
).render(width),
|
|
925
|
+
);
|
|
926
|
+
|
|
927
|
+
const calloutRows = Math.min(callout.length, Math.max(0, budget - 1));
|
|
928
|
+
const transcriptBudget = Math.max(1, budget - calloutRows);
|
|
929
|
+
const lines = this.chatHost.renderBody(width, transcriptBudget);
|
|
930
|
+
lines.push(...callout.slice(0, calloutRows));
|
|
931
|
+
while (lines.length < budget) lines.push(this._blank(width));
|
|
932
|
+
if (lines.length > budget) lines.length = budget;
|
|
933
|
+
return lines;
|
|
934
|
+
}
|
|
935
|
+
|
|
870
936
|
private _renderBlockedBody(
|
|
871
937
|
width: number,
|
|
872
938
|
budget: number,
|
|
@@ -977,17 +1043,20 @@ export class StageChatView implements Component, Focusable {
|
|
|
977
1043
|
}
|
|
978
1044
|
|
|
979
1045
|
private _noticeRow(entry: NoticeEntry): Component {
|
|
980
|
-
const
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1046
|
+
const theme = this.theme;
|
|
1047
|
+
return {
|
|
1048
|
+
render(width: number): string[] {
|
|
1049
|
+
return renderWorkflowNoticeCard({
|
|
1050
|
+
...stageNoticeCard(entry),
|
|
1051
|
+
fallbackText: entry.text,
|
|
1052
|
+
width,
|
|
1053
|
+
theme,
|
|
1054
|
+
});
|
|
1055
|
+
},
|
|
1056
|
+
invalidate() {
|
|
1057
|
+
/* notice entries are immutable */
|
|
1058
|
+
},
|
|
1059
|
+
};
|
|
991
1060
|
}
|
|
992
1061
|
|
|
993
1062
|
// -------------------------------------------------------------------------
|
|
@@ -1072,24 +1141,39 @@ export class StageChatView implements Component, Focusable {
|
|
|
1072
1141
|
return true;
|
|
1073
1142
|
}
|
|
1074
1143
|
|
|
1144
|
+
private _promptKeybindings(): KeybindingsLike | undefined {
|
|
1145
|
+
return isKeybindingsLike(this.piKeybindings) ? this.piKeybindings : undefined;
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
private _canSubmitPrompt(promptId: string): boolean {
|
|
1149
|
+
return this.canSubmitPrompt?.(this.runId, this.stageId, promptId) ?? true;
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1075
1152
|
private _handlePromptInput(data: string): void {
|
|
1076
1153
|
const state = this.promptState;
|
|
1077
1154
|
if (!state) return;
|
|
1078
1155
|
if (this.promptEditor && this.promptEditorPromptId === state.prompt.id) {
|
|
1079
|
-
if (matchesKey(data, Key.
|
|
1080
|
-
this._resolvePromptResponse(state.prompt.id, defaultResponseFor(state.prompt)
|
|
1156
|
+
if (matchesKey(data, Key.ctrl("c"))) {
|
|
1157
|
+
this._resolvePromptResponse(state.prompt.id, defaultResponseFor(state.prompt), {
|
|
1158
|
+
suppressNextGraphSubmit: false,
|
|
1159
|
+
});
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
if (isPromptEscapeInput(data)) {
|
|
1163
|
+
this.requestRender?.();
|
|
1081
1164
|
return;
|
|
1082
1165
|
}
|
|
1083
1166
|
setEditorFocused(this.promptEditor, this.focused);
|
|
1084
|
-
this.
|
|
1167
|
+
this.promptEditorSubmitFromEnter = matchesKey(data, Key.enter);
|
|
1168
|
+
try {
|
|
1169
|
+
this.promptEditor.handleInput(data);
|
|
1170
|
+
} finally {
|
|
1171
|
+
this.promptEditorSubmitFromEnter = false;
|
|
1172
|
+
}
|
|
1085
1173
|
this.requestRender?.();
|
|
1086
1174
|
return;
|
|
1087
1175
|
}
|
|
1088
|
-
const action = handlePromptCardInput(
|
|
1089
|
-
data,
|
|
1090
|
-
state,
|
|
1091
|
-
isKeybindingsLike(this.piKeybindings) ? this.piKeybindings : undefined,
|
|
1092
|
-
);
|
|
1176
|
+
const action = handlePromptCardInput(data, state, this._promptKeybindings());
|
|
1093
1177
|
if (action.kind === "noop") {
|
|
1094
1178
|
this.requestRender?.();
|
|
1095
1179
|
return;
|
|
@@ -1098,7 +1182,9 @@ export class StageChatView implements Component, Focusable {
|
|
|
1098
1182
|
const response = action.kind === "submit"
|
|
1099
1183
|
? action.response
|
|
1100
1184
|
: defaultResponseFor(prompt);
|
|
1101
|
-
this._resolvePromptResponse(prompt.id, response
|
|
1185
|
+
this._resolvePromptResponse(prompt.id, response, {
|
|
1186
|
+
suppressNextGraphSubmit: action.kind === "submit" && matchesKey(data, Key.enter),
|
|
1187
|
+
});
|
|
1102
1188
|
}
|
|
1103
1189
|
|
|
1104
1190
|
// -------------------------------------------------------------------------
|
|
@@ -1107,6 +1193,10 @@ export class StageChatView implements Component, Focusable {
|
|
|
1107
1193
|
|
|
1108
1194
|
handleInput(data: string): boolean {
|
|
1109
1195
|
if (this.mountedCustomUi) {
|
|
1196
|
+
if (!this._canSubmitPrompt(this.mountedCustomUi.request.id)) {
|
|
1197
|
+
this.requestRender?.();
|
|
1198
|
+
return true;
|
|
1199
|
+
}
|
|
1110
1200
|
if (matchesKey(data, Key.ctrl("d"))) {
|
|
1111
1201
|
// Detach stops *viewing* the stage; it does not cancel a pending
|
|
1112
1202
|
// human-input request. Release the local display only — the request
|
|
@@ -1137,7 +1227,10 @@ export class StageChatView implements Component, Focusable {
|
|
|
1137
1227
|
this.requestRender?.();
|
|
1138
1228
|
return true;
|
|
1139
1229
|
}
|
|
1140
|
-
this.
|
|
1230
|
+
const stage = this._currentStage();
|
|
1231
|
+
this._syncPromptState(stage?.pendingPrompt);
|
|
1232
|
+
const readOnlyArchive = this._isReadOnlyArchive(stage);
|
|
1233
|
+
const readOnlyPromptArchive = readOnlyArchive && stage?.promptFootprint !== undefined;
|
|
1141
1234
|
if (matchesKey(data, Key.ctrl("d"))) {
|
|
1142
1235
|
if (!this.promptState && this.chatHost.hasInputText()) return this.chatHost.handleInput(data);
|
|
1143
1236
|
if (this._isPaused()) this.onClose();
|
|
@@ -1149,6 +1242,9 @@ export class StageChatView implements Component, Focusable {
|
|
|
1149
1242
|
this._handlePromptInput(data);
|
|
1150
1243
|
return true;
|
|
1151
1244
|
}
|
|
1245
|
+
if (readOnlyPromptArchive && this._handlePromptScrollInput(data, true)) {
|
|
1246
|
+
return true;
|
|
1247
|
+
}
|
|
1152
1248
|
if (this.chatHost.handleScrollInput(data)) {
|
|
1153
1249
|
return true;
|
|
1154
1250
|
}
|
|
@@ -1167,7 +1263,6 @@ export class StageChatView implements Component, Focusable {
|
|
|
1167
1263
|
this.onClose();
|
|
1168
1264
|
return true;
|
|
1169
1265
|
}
|
|
1170
|
-
const readOnlyArchive = this._isReadOnlyArchive();
|
|
1171
1266
|
if (readOnlyArchive) return true;
|
|
1172
1267
|
const blocked = this._isBlocked();
|
|
1173
1268
|
if (matchesKey(data, Key.ctrl("f"))) {
|
|
@@ -1502,6 +1597,78 @@ function noticeSummary(n: StageNotice): string {
|
|
|
1502
1597
|
return n.from ? `${base} (was ${n.from})` : base;
|
|
1503
1598
|
}
|
|
1504
1599
|
|
|
1600
|
+
function stageNoticeCard(entry: NoticeEntry): {
|
|
1601
|
+
title: string;
|
|
1602
|
+
glyph: string;
|
|
1603
|
+
headline: string;
|
|
1604
|
+
tone: WorkflowNoticeTone;
|
|
1605
|
+
fields: Array<{ label: string; value: string | undefined; tone?: WorkflowNoticeTone | "text" | "muted" }>;
|
|
1606
|
+
} {
|
|
1607
|
+
switch (entry.kind) {
|
|
1608
|
+
case "abort":
|
|
1609
|
+
return {
|
|
1610
|
+
title: "STAGE ABORTED",
|
|
1611
|
+
glyph: "✗",
|
|
1612
|
+
headline: "Stage received an abort notice",
|
|
1613
|
+
tone: "error",
|
|
1614
|
+
fields: stageNoticeFields(entry, "error"),
|
|
1615
|
+
};
|
|
1616
|
+
case "compaction":
|
|
1617
|
+
return {
|
|
1618
|
+
title: "STAGE COMPACTION",
|
|
1619
|
+
glyph: "✓",
|
|
1620
|
+
headline: "Stage context was compacted",
|
|
1621
|
+
tone: "success",
|
|
1622
|
+
fields: stageNoticeFields(entry, "muted"),
|
|
1623
|
+
};
|
|
1624
|
+
case "model":
|
|
1625
|
+
return {
|
|
1626
|
+
title: "STAGE MODEL",
|
|
1627
|
+
glyph: "→",
|
|
1628
|
+
headline: "Stage model changed",
|
|
1629
|
+
tone: "info",
|
|
1630
|
+
fields: stageNoticeFields(entry),
|
|
1631
|
+
};
|
|
1632
|
+
case "thinking":
|
|
1633
|
+
return {
|
|
1634
|
+
title: "STAGE THINKING",
|
|
1635
|
+
glyph: "→",
|
|
1636
|
+
headline: "Stage thinking level changed",
|
|
1637
|
+
tone: "mauve",
|
|
1638
|
+
fields: stageNoticeFields(entry),
|
|
1639
|
+
};
|
|
1640
|
+
case "tree":
|
|
1641
|
+
return {
|
|
1642
|
+
title: "STAGE TREE",
|
|
1643
|
+
glyph: "◆",
|
|
1644
|
+
headline: "Stage branch tree changed",
|
|
1645
|
+
tone: "info",
|
|
1646
|
+
fields: stageNoticeFields(entry, "muted"),
|
|
1647
|
+
};
|
|
1648
|
+
case "mcp":
|
|
1649
|
+
default:
|
|
1650
|
+
return {
|
|
1651
|
+
title: "STAGE NOTICE",
|
|
1652
|
+
glyph: "◆",
|
|
1653
|
+
headline: "Workflow stage notice",
|
|
1654
|
+
tone: "info",
|
|
1655
|
+
fields: stageNoticeFields(entry, "muted"),
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
function stageNoticeFields(
|
|
1661
|
+
entry: NoticeEntry,
|
|
1662
|
+
valueTone: WorkflowNoticeTone | "text" | "muted" = "text",
|
|
1663
|
+
): Array<{ label: string; value: string | undefined; tone?: WorkflowNoticeTone | "text" | "muted" }> {
|
|
1664
|
+
return [
|
|
1665
|
+
{ label: "kind", value: entry.kind, tone: "muted" },
|
|
1666
|
+
{ label: "value", value: entry.value, tone: valueTone },
|
|
1667
|
+
{ label: "from", value: entry.from, tone: "muted" },
|
|
1668
|
+
{ label: "meta", value: entry.meta, tone: "muted" },
|
|
1669
|
+
];
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1505
1672
|
function shortenId(id: string): string {
|
|
1506
1673
|
return id.length > 10 ? id.slice(0, 8) : id;
|
|
1507
1674
|
}
|
|
@@ -1528,6 +1695,10 @@ function editorThemeFromGraphTheme(t: GraphTheme): EditorTheme {
|
|
|
1528
1695
|
} as EditorTheme;
|
|
1529
1696
|
}
|
|
1530
1697
|
|
|
1698
|
+
function takeRows(lines: readonly string[], rows: number): string[] {
|
|
1699
|
+
return lines.slice(0, rows);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1531
1702
|
interface PaintOpts {
|
|
1532
1703
|
bold?: boolean;
|
|
1533
1704
|
italic?: boolean;
|
|
@@ -1545,9 +1716,9 @@ function paint(text: string, fg: string, opts: PaintOpts = {}): string {
|
|
|
1545
1716
|
|
|
1546
1717
|
function renderHintsForPrompt(kind: PendingPrompt["kind"], theme: GraphTheme): string {
|
|
1547
1718
|
if (kind === "input" || kind === "editor") {
|
|
1548
|
-
return `${paint("enter", theme.textMuted, { bold: true })} Submit · ${paint("
|
|
1719
|
+
return `${paint("enter", theme.textMuted, { bold: true })} Submit · ${paint("ctrl+c", theme.textMuted, { bold: true })} Skip`;
|
|
1549
1720
|
}
|
|
1550
|
-
return `${paint("enter", theme.textMuted, { bold: true })} Select · ${paint("
|
|
1721
|
+
return `${paint("enter", theme.textMuted, { bold: true })} Select · ${paint("ctrl+c", theme.textMuted, { bold: true })} Skip`;
|
|
1551
1722
|
}
|
|
1552
1723
|
|
|
1553
1724
|
/**
|