@bastani/atomic 0.9.11-alpha.9 → 0.9.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +134 -0
- package/README.md +1 -1
- package/dist/builtin/intercom/CHANGELOG.md +6 -0
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/subagent-relay.ts +8 -5
- package/dist/builtin/mcp/CHANGELOG.md +10 -0
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/subagents/CHANGELOG.md +20 -0
- package/dist/builtin/subagents/agents/code-simplifier.md +2 -2
- package/dist/builtin/subagents/agents/codebase-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-locator.md +2 -2
- package/dist/builtin/subagents/agents/codebase-online-researcher.md +2 -2
- package/dist/builtin/subagents/agents/codebase-pattern-finder.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-analyzer.md +2 -2
- package/dist/builtin/subagents/agents/codebase-research-locator.md +2 -2
- package/dist/builtin/subagents/agents/worker.md +2 -2
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/extension/notification-content.ts +14 -9
- package/dist/builtin/subagents/src/runs/background/notify.ts +20 -4
- package/dist/builtin/web-access/CHANGELOG.md +20 -0
- package/dist/builtin/web-access/content-tools.ts +1 -0
- package/dist/builtin/web-access/flat-string.ts +37 -0
- package/dist/builtin/web-access/github-api.ts +2 -1
- package/dist/builtin/web-access/github-extract.ts +3 -2
- package/dist/builtin/web-access/package.json +2 -2
- package/dist/builtin/workflows/CHANGELOG.md +57 -0
- package/dist/builtin/workflows/builtin/goal-ledger.ts +6 -4
- package/dist/builtin/workflows/builtin/goal-runner.ts +2 -1
- package/dist/builtin/workflows/builtin/goal.ts +1 -1
- package/dist/builtin/workflows/builtin/ralph-core.ts +8 -9
- package/dist/builtin/workflows/builtin/ralph-forked-prompts.ts +2 -4
- package/dist/builtin/workflows/builtin/ralph-models.ts +4 -4
- package/dist/builtin/workflows/builtin/ralph-runner.ts +5 -8
- package/dist/builtin/workflows/builtin/ralph.ts +2 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/src/durable/completed-catalog.ts +14 -8
- package/dist/builtin/workflows/src/durable/completed-inspection.ts +10 -11
- package/dist/builtin/workflows/src/durable/resume-catalog.ts +1 -1
- package/dist/builtin/workflows/src/durable/resume-eligibility.ts +42 -0
- package/dist/builtin/workflows/src/durable/resume-runtime.ts +36 -37
- package/dist/builtin/workflows/src/durable/tool-primitive.ts +10 -2
- package/dist/builtin/workflows/src/engine/run.ts +1 -0
- package/dist/builtin/workflows/src/extension/extension-runtime-state.ts +12 -8
- package/dist/builtin/workflows/src/extension/hil-answer-notifications.ts +5 -2
- package/dist/builtin/workflows/src/extension/index.bundle.mjs +1966 -880
- package/dist/builtin/workflows/src/extension/lifecycle-notifications.ts +6 -3
- package/dist/builtin/workflows/src/extension/postmortem-deps.ts +3 -2
- package/dist/builtin/workflows/src/extension/render-result.ts +4 -11
- package/dist/builtin/workflows/src/extension/runtime-durable-resume.ts +17 -20
- package/dist/builtin/workflows/src/extension/runtime.ts +3 -3
- package/dist/builtin/workflows/src/extension/workflow-command-completions.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-command-registration.ts +3 -7
- package/dist/builtin/workflows/src/extension/workflow-durable-resume-command.ts +21 -24
- package/dist/builtin/workflows/src/extension/workflow-resume-picker-rows.ts +38 -26
- package/dist/builtin/workflows/src/extension/workflow-resume-shadow.ts +2 -1
- package/dist/builtin/workflows/src/extension/workflow-run-control-command.ts +56 -64
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +2 -2
- package/dist/builtin/workflows/src/extension/workflow-status-summary.ts +0 -5
- package/dist/builtin/workflows/src/extension/workflow-targets.ts +17 -20
- package/dist/builtin/workflows/src/extension/workflow-tool-content.ts +1 -1
- package/dist/builtin/workflows/src/extension/workflow-tool-control.ts +24 -51
- package/dist/builtin/workflows/src/extension/workflow-tool-inspection.ts +7 -29
- package/dist/builtin/workflows/src/extension/workflow-tool-send.ts +5 -13
- package/dist/builtin/workflows/src/extension/workflow-tool.ts +4 -13
- package/dist/builtin/workflows/src/runs/background/quit.ts +4 -3
- package/dist/builtin/workflows/src/runs/background/run-inspect.ts +8 -8
- package/dist/builtin/workflows/src/runs/background/status.ts +2 -1
- package/dist/builtin/workflows/src/runs/background/workflow-lifecycle-aggregate.ts +2 -1
- package/dist/builtin/workflows/src/runs/foreground/executor-direct-helpers.ts +5 -5
- package/dist/builtin/workflows/src/runs/foreground/executor-lifecycle.ts +4 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-scheduler.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-call.ts +23 -8
- package/dist/builtin/workflows/src/runs/foreground/executor-stage-factory.ts +6 -2
- package/dist/builtin/workflows/src/runs/foreground/executor-task-prompts.ts +5 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-context.ts +56 -10
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-controller.ts +6 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner-output.ts +137 -6
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.d.ts +2 -0
- package/dist/builtin/workflows/src/shared/authoring-contract-ui.ts +2 -0
- package/dist/builtin/workflows/src/shared/expanded-workflow-graph.ts +159 -10
- package/dist/builtin/workflows/src/shared/flat-string.ts +33 -0
- package/dist/builtin/workflows/src/shared/graph-store-snapshot.ts +144 -0
- package/dist/builtin/workflows/src/shared/persistence-session-entries.ts +2 -3
- package/dist/builtin/workflows/src/shared/run-id.ts +36 -0
- package/dist/builtin/workflows/src/shared/store-internal.ts +32 -3
- package/dist/builtin/workflows/src/shared/store-observation.ts +10 -0
- package/dist/builtin/workflows/src/shared/store-public-types.ts +8 -0
- package/dist/builtin/workflows/src/shared/store-run-methods.ts +14 -0
- package/dist/builtin/workflows/src/shared/store-types.ts +4 -0
- package/dist/builtin/workflows/src/shared/types.ts +2 -0
- package/dist/builtin/workflows/src/shared/workflow-artifacts.ts +261 -0
- package/dist/builtin/workflows/src/tui/dispatch-confirm.ts +39 -23
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +26 -9
- package/dist/builtin/workflows/src/tui/graph-view-constants.ts +3 -0
- package/dist/builtin/workflows/src/tui/graph-view-graph-render.ts +95 -98
- package/dist/builtin/workflows/src/tui/graph-view-render.ts +7 -20
- package/dist/builtin/workflows/src/tui/graph-view-state.ts +160 -13
- package/dist/builtin/workflows/src/tui/layout.ts +8 -2
- package/dist/builtin/workflows/src/tui/node-card.ts +57 -45
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +4 -2
- package/dist/builtin/workflows/src/tui/prompt-card-render.ts +291 -21
- package/dist/builtin/workflows/src/tui/prompt-card.ts +1 -1
- package/dist/builtin/workflows/src/tui/renderers.ts +0 -1
- package/dist/builtin/workflows/src/tui/run-detail.ts +52 -35
- package/dist/builtin/workflows/src/tui/run-identity-rows.ts +97 -0
- package/dist/builtin/workflows/src/tui/session-overlays.ts +24 -3
- package/dist/builtin/workflows/src/tui/session-picker.ts +94 -41
- package/dist/builtin/workflows/src/tui/stage-chat-view-archive-history.ts +190 -26
- package/dist/builtin/workflows/src/tui/stage-chat-view-footer-status.ts +52 -18
- package/dist/builtin/workflows/src/tui/stage-chat-view-input.ts +9 -5
- package/dist/builtin/workflows/src/tui/stage-chat-view-state.ts +44 -4
- package/dist/builtin/workflows/src/tui/stage-chat-view-types.ts +3 -1
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +3 -2
- package/dist/builtin/workflows/src/tui/status-list.ts +67 -45
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -6
- package/dist/builtin/workflows/src/tui/widget.ts +49 -40
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +15 -10
- package/dist/builtin/workflows/src/tui/workflow-resume-selector.ts +21 -8
- package/dist/core/agent-session-accessors.d.ts.map +1 -1
- package/dist/core/agent-session-accessors.js +5 -0
- package/dist/core/agent-session-accessors.js.map +1 -1
- package/dist/core/agent-session-auto-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-auto-compaction.js +5 -0
- package/dist/core/agent-session-auto-compaction.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +3 -0
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-events.d.ts.map +1 -1
- package/dist/core/agent-session-events.js +2 -1
- package/dist/core/agent-session-events.js.map +1 -1
- package/dist/core/agent-session-message-queue.d.ts +3 -7
- package/dist/core/agent-session-message-queue.d.ts.map +1 -1
- package/dist/core/agent-session-message-queue.js +27 -13
- package/dist/core/agent-session-message-queue.js.map +1 -1
- package/dist/core/agent-session-methods.d.ts +5 -3
- package/dist/core/agent-session-methods.d.ts.map +1 -1
- package/dist/core/agent-session-methods.js.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.d.ts.map +1 -1
- package/dist/core/agent-session-persistent-custom-messages.js +6 -3
- package/dist/core/agent-session-persistent-custom-messages.js.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-post-tool-compaction.js +11 -2
- package/dist/core/agent-session-post-tool-compaction.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +5 -3
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session-tree.d.ts.map +1 -1
- package/dist/core/agent-session-tree.js +4 -0
- package/dist/core/agent-session-tree.js.map +1 -1
- package/dist/core/agent-session-types.d.ts +4 -0
- package/dist/core/agent-session-types.d.ts.map +1 -1
- package/dist/core/agent-session-types.js.map +1 -1
- package/dist/core/agent-session.d.ts +2 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +1 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage-backends.d.ts.map +1 -1
- package/dist/core/auth-storage-backends.js +12 -1
- package/dist/core/auth-storage-backends.js.map +1 -1
- package/dist/core/bounded-model-refresh.d.ts +14 -0
- package/dist/core/bounded-model-refresh.d.ts.map +1 -0
- package/dist/core/bounded-model-refresh.js +38 -0
- package/dist/core/bounded-model-refresh.js.map +1 -0
- package/dist/core/context-tool-pairing.d.ts +4 -4
- package/dist/core/context-tool-pairing.js +4 -4
- package/dist/core/context-tool-pairing.js.map +1 -1
- package/dist/core/http-dispatcher.d.ts.map +1 -1
- package/dist/core/http-dispatcher.js +26 -1
- package/dist/core/http-dispatcher.js.map +1 -1
- package/dist/core/messages.d.ts +18 -6
- package/dist/core/messages.d.ts.map +1 -1
- package/dist/core/messages.js +46 -18
- package/dist/core/messages.js.map +1 -1
- package/dist/core/model-refresh-timeout.d.ts +9 -0
- package/dist/core/model-refresh-timeout.d.ts.map +1 -0
- package/dist/core/model-refresh-timeout.js +9 -0
- package/dist/core/model-refresh-timeout.js.map +1 -0
- package/dist/core/model-runtime-snapshot.d.ts +3 -0
- package/dist/core/model-runtime-snapshot.d.ts.map +1 -1
- package/dist/core/model-runtime-snapshot.js +59 -0
- package/dist/core/model-runtime-snapshot.js.map +1 -1
- package/dist/core/model-runtime.d.ts +7 -1
- package/dist/core/model-runtime.d.ts.map +1 -1
- package/dist/core/model-runtime.js +72 -17
- package/dist/core/model-runtime.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +4 -3
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager-core.d.ts +1 -1
- package/dist/core/session-manager-core.d.ts.map +1 -1
- package/dist/core/session-manager-core.js +2 -2
- package/dist/core/session-manager-core.js.map +1 -1
- package/dist/core/session-manager-entries.d.ts +1 -1
- package/dist/core/session-manager-entries.d.ts.map +1 -1
- package/dist/core/session-manager-entries.js +2 -1
- package/dist/core/session-manager-entries.js.map +1 -1
- package/dist/core/session-manager-history.d.ts.map +1 -1
- package/dist/core/session-manager-history.js +2 -2
- package/dist/core/session-manager-history.js.map +1 -1
- package/dist/core/session-manager-types.d.ts +3 -0
- package/dist/core/session-manager-types.d.ts.map +1 -1
- package/dist/core/session-manager-types.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/main-app-mode.d.ts +1 -0
- package/dist/main-app-mode.d.ts.map +1 -1
- package/dist/main-app-mode.js +3 -0
- package/dist/main-app-mode.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -3
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts +7 -2
- package/dist/modes/interactive/components/chat-session-host-actions.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-actions.js +13 -4
- package/dist/modes/interactive/components/chat-session-host-actions.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts +3 -1
- package/dist/modes/interactive/components/chat-session-host-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-editor.js +2 -2
- package/dist/modes/interactive/components/chat-session-host-editor.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.d.ts +3 -0
- package/dist/modes/interactive/components/chat-session-host-events.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host-events.js +5 -4
- package/dist/modes/interactive/components/chat-session-host-events.js.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.d.ts +16 -2
- package/dist/modes/interactive/components/chat-session-host.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-session-host.js +35 -5
- package/dist/modes/interactive/components/chat-session-host.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.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +0 -1
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js +25 -35
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/interactive-editor-actions.js +2 -1
- package/dist/modes/interactive/interactive-editor-actions.js.map +1 -1
- package/dist/modes/interactive/interactive-input-handling.js +1 -1
- package/dist/modes/interactive/interactive-input-handling.js.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts +4 -1
- package/dist/modes/interactive/interactive-mode-surface.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode-surface.js.map +1 -1
- package/dist/modes/interactive/interactive-model-routing.js +4 -1
- package/dist/modes/interactive/interactive-model-routing.js.map +1 -1
- package/dist/modes/interactive/interactive-pause.d.ts +3 -1
- package/dist/modes/interactive/interactive-pause.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-pause.js +5 -1
- package/dist/modes/interactive/interactive-pause.js.map +1 -1
- package/dist/modes/interactive/interactive-queueing.js +3 -3
- package/dist/modes/interactive/interactive-queueing.js.map +1 -1
- package/dist/modes/interactive-engine/engine-health.d.ts +6 -0
- package/dist/modes/interactive-engine/engine-health.d.ts.map +1 -1
- package/dist/modes/interactive-engine/engine-health.js +15 -1
- package/dist/modes/interactive-engine/engine-health.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js +1 -1
- package/dist/modes/interactive-engine/isolated-auth.js.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.d.ts +1 -0
- package/dist/modes/interactive-engine/isolated-runtime.d.ts.map +1 -1
- package/dist/modes/interactive-engine/isolated-runtime.js +7 -1
- package/dist/modes/interactive-engine/isolated-runtime.js.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.d.ts.map +1 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js +5 -1
- package/dist/modes/interactive-engine/remote-model-catalog.js.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-command-handler.js +23 -7
- package/dist/modes/rpc/rpc-command-handler.js.map +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js +1 -1
- package/dist/modes/rpc/rpc-input-scheduler.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +2 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/custom-provider.md +3 -3
- package/docs/extensions.md +3 -1
- package/docs/index.md +10 -0
- package/docs/keybindings.md +1 -1
- package/docs/models.md +2 -0
- package/docs/providers.md +7 -3
- package/docs/quickstart.md +7 -1
- package/docs/session-format.md +2 -0
- package/docs/termux.md +3 -1
- package/docs/usage.md +3 -2
- package/docs/workflows.md +82 -46
- package/npm-shrinkwrap.json +59 -27
- package/package.json +3 -3
- package/dist/builtin/workflows/src/tui/toast.ts +0 -107
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
* Visual contract:
|
|
6
6
|
* - One rounded `DISPATCHED` panel.
|
|
7
7
|
* - One status-coloured rounded run card:
|
|
8
|
-
* title:
|
|
8
|
+
* title: full runId · workflowName · ● running
|
|
9
9
|
* body: compact `k=v · k=v · +N more` input summary when present
|
|
10
|
-
* - One compact next-step hint:
|
|
11
|
-
* ▸ /workflow connect <id> see agents working · chat with and steer each stage
|
|
12
10
|
*
|
|
13
11
|
* What we deliberately do NOT emit (was in the legacy 7-row layout):
|
|
14
12
|
* - the `✓ submitted · /workflow <name>` echo line — pi already shows
|
|
@@ -16,8 +14,8 @@
|
|
|
16
14
|
* - the `[ DISPATCHED ]` band — a single-card surface doesn't need a
|
|
17
15
|
* band wrapper (bands frame multi-card surfaces like BACKGROUND /
|
|
18
16
|
* WORKFLOWS);
|
|
19
|
-
* - the `run id` muted caption
|
|
20
|
-
*
|
|
17
|
+
* - the `run id` muted caption — the bare identifier row already
|
|
18
|
+
* communicates identity without restoring legacy chrome;
|
|
21
19
|
* - the `status starting…` body row — the `● running` badge on row 1
|
|
22
20
|
* occupies the same semantic slot;
|
|
23
21
|
* - the second hint row `▸ /workflow status` — that is a separate intent
|
|
@@ -34,13 +32,13 @@
|
|
|
34
32
|
*/
|
|
35
33
|
|
|
36
34
|
import type { WorkflowInputValues } from "../shared/types.js";
|
|
37
|
-
import { chatWidth, ELLIPSIS,
|
|
35
|
+
import { chatWidth, ELLIPSIS, renderRoundedBox } from "./chat-surface.js";
|
|
38
36
|
import { hexToAnsi, RESET } from "./color-utils.js";
|
|
39
37
|
import type { GraphTheme } from "./graph-theme.js";
|
|
38
|
+
import { wrapIdentifierLines } from "./run-identity-rows.js";
|
|
40
39
|
import { truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
41
40
|
|
|
42
41
|
const INLINE_INPUT_LIMIT = 3;
|
|
43
|
-
const SHORT_ID_LEN = 8;
|
|
44
42
|
|
|
45
43
|
/**
|
|
46
44
|
* Below this many cells, inline inputs on row 1 are unreadable. We wrap
|
|
@@ -51,9 +49,9 @@ const SHORT_ID_LEN = 8;
|
|
|
51
49
|
const MIN_INLINE_INPUT_BUDGET = 16;
|
|
52
50
|
|
|
53
51
|
export interface RenderDispatchConfirmOpts {
|
|
54
|
-
/** Registered workflow name
|
|
52
|
+
/** Registered workflow name rendered beside the full run-id body row. */
|
|
55
53
|
workflowName: string;
|
|
56
|
-
/** Real run UUID;
|
|
54
|
+
/** Real run UUID; every rendered occurrence keeps the complete value. */
|
|
57
55
|
runId: string;
|
|
58
56
|
/** Inputs merged from CLI tokens + picker output. */
|
|
59
57
|
inputs: Readonly<WorkflowInputValues>;
|
|
@@ -72,8 +70,7 @@ export function renderDispatchConfirm(opts: RenderDispatchConfirmOpts): string {
|
|
|
72
70
|
const width = effectiveWidth(opts.width);
|
|
73
71
|
const theme = opts.theme;
|
|
74
72
|
const accent = theme?.warning ?? "#000000";
|
|
75
|
-
const tag =
|
|
76
|
-
|
|
73
|
+
const tag = opts.runId;
|
|
77
74
|
// Status badge — anchored to the right of row 1, in the running hue.
|
|
78
75
|
// Mirrors the `● running` glyph used by every other live-run surface.
|
|
79
76
|
const trailing = theme ? { text: "● running", fg: theme.warning } : { text: "● running" };
|
|
@@ -117,34 +114,53 @@ export function renderDispatchConfirm(opts: RenderDispatchConfirmOpts): string {
|
|
|
117
114
|
// the full body interior (width - body chrome) as the wider canvas.
|
|
118
115
|
if (hasInputs && titleSuffix === undefined) {
|
|
119
116
|
const BODY_PREFIX_W = 4; // " " — see renderTaggedCard body prefix
|
|
120
|
-
const bodyBudget = Math.max(0, width -
|
|
117
|
+
const bodyBudget = Math.max(0, width - 2 - BODY_PREFIX_W);
|
|
121
118
|
const overflowSeg = renderInputsSegment(opts.inputs, bodyBudget, theme);
|
|
122
119
|
if (overflowSeg) bodyRows.push(overflowSeg.rendered);
|
|
123
120
|
}
|
|
124
121
|
|
|
125
122
|
const inputRows =
|
|
126
123
|
bodyRows.length > 0 ? bodyRows.map((row) => ` ${row} `) : [` ${titleSuffix ?? "started in background"} `];
|
|
127
|
-
const
|
|
124
|
+
const identifierRows = renderIdentifierRows(opts.runId, width - 2, theme);
|
|
125
|
+
const titleLine = ` ● ${opts.workflowName} ${trailing.text} `;
|
|
128
126
|
|
|
129
|
-
const hints =
|
|
130
|
-
[{ command: `/workflow connect ${tag}`, hint: "see agents working · chat with and steer each stage" }],
|
|
131
|
-
theme,
|
|
132
|
-
)
|
|
133
|
-
.split("\n")
|
|
134
|
-
.map((line) => ` ${line} `);
|
|
127
|
+
const hints = renderDispatchHintRows(opts.runId, width - 4, theme).map((line) => ` ${line} `);
|
|
135
128
|
|
|
136
129
|
return renderRoundedBox({
|
|
137
130
|
title: "DISPATCHED",
|
|
138
|
-
bodyLines: [titleLine, ...inputRows, "", ...hints],
|
|
131
|
+
bodyLines: [...identifierRows, titleLine, ...inputRows, "", ...hints],
|
|
139
132
|
accent,
|
|
140
133
|
theme,
|
|
141
134
|
width,
|
|
142
135
|
});
|
|
143
136
|
}
|
|
144
137
|
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
function renderIdentifierRows(id: string, width: number, theme?: GraphTheme): string[] {
|
|
139
|
+
const rows = wrapIdentifierLines(id, width, " ", " ");
|
|
140
|
+
if (!theme) return rows.map((row) => `${row.prefix}${row.chunk}`);
|
|
141
|
+
const accent = hexToAnsi(theme.accent);
|
|
142
|
+
return rows.map((row) => `${row.prefix}${accent}${row.chunk}${RESET}`);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function renderDispatchHintRows(id: string, width: number, theme?: GraphTheme): string[] {
|
|
146
|
+
const budget = Math.max(1, width);
|
|
147
|
+
const prefix = "▸ /workflow connect ";
|
|
148
|
+
const continuation = " ";
|
|
149
|
+
const rows = wrapIdentifierLines(id, budget, prefix, continuation);
|
|
150
|
+
const suffix = " see agents working · chat with and steer each stage";
|
|
151
|
+
const last = rows[rows.length - 1]!;
|
|
152
|
+
if (visibleWidth(`${last.prefix}${last.chunk}${suffix}`) <= budget) {
|
|
153
|
+
last.chunk += suffix;
|
|
154
|
+
} else {
|
|
155
|
+
rows.push({
|
|
156
|
+
prefix: continuation,
|
|
157
|
+
chunk: truncateToWidth(suffix.trimStart(), Math.max(1, budget - visibleWidth(continuation)), ELLIPSIS),
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
if (!theme) return rows.map((row) => `${row.prefix}${row.chunk}`);
|
|
161
|
+
const dim = hexToAnsi(theme.dim);
|
|
162
|
+
const accent = hexToAnsi(theme.accent);
|
|
163
|
+
return rows.map((row) => `${dim}${row.prefix}${RESET}${accent}${row.chunk}${RESET}`);
|
|
148
164
|
}
|
|
149
165
|
|
|
150
166
|
interface InputsSegment {
|
|
@@ -70,14 +70,27 @@ function glyphForDirs(dirs: Set<Dir>): string {
|
|
|
70
70
|
return " ";
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
+
export interface GraphCanvasBounds {
|
|
74
|
+
top: number;
|
|
75
|
+
bottom: number;
|
|
76
|
+
left: number;
|
|
77
|
+
right: number;
|
|
78
|
+
}
|
|
79
|
+
|
|
73
80
|
export class GraphCanvas {
|
|
74
|
-
/** rowIdx → colIdx → Cell. Sparse — empty cells render as a single space. */
|
|
75
81
|
private rows: Map<number, Map<number, Cell>> = new Map();
|
|
76
82
|
private maxRow = -1;
|
|
77
83
|
private maxCol = -1;
|
|
78
84
|
|
|
85
|
+
constructor(private readonly bounds?: GraphCanvasBounds) {}
|
|
79
86
|
setCell(row: number, col: number, ch: string, fg: string | null): void {
|
|
80
87
|
if (row < 0 || col < 0) return;
|
|
88
|
+
if (
|
|
89
|
+
this.bounds &&
|
|
90
|
+
(row < this.bounds.top || row >= this.bounds.bottom || col < this.bounds.left || col >= this.bounds.right)
|
|
91
|
+
) {
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
81
94
|
let cols = this.rows.get(row);
|
|
82
95
|
if (!cols) {
|
|
83
96
|
cols = new Map();
|
|
@@ -116,34 +129,38 @@ export class GraphCanvas {
|
|
|
116
129
|
* different glyph at the final column (e.g. `>`-style arrowhead).
|
|
117
130
|
*/
|
|
118
131
|
hline(row: number, fromCol: number, toCol: number, fg: string | null): void {
|
|
119
|
-
|
|
120
|
-
const
|
|
132
|
+
if (this.bounds && (row < this.bounds.top || row >= this.bounds.bottom)) return;
|
|
133
|
+
const lo = Math.max(Math.min(fromCol, toCol), this.bounds?.left ?? 0);
|
|
134
|
+
const hi = Math.min(Math.max(fromCol, toCol), (this.bounds?.right ?? Number.POSITIVE_INFINITY) - 1);
|
|
121
135
|
for (let c = lo; c <= hi; c++) this.mergeCell(row, c, ["l", "r"], fg);
|
|
122
136
|
}
|
|
123
137
|
|
|
124
138
|
vline(col: number, fromRow: number, toRow: number, fg: string | null): void {
|
|
125
|
-
|
|
126
|
-
const
|
|
139
|
+
if (this.bounds && (col < this.bounds.left || col >= this.bounds.right)) return;
|
|
140
|
+
const lo = Math.max(Math.min(fromRow, toRow), this.bounds?.top ?? 0);
|
|
141
|
+
const hi = Math.min(Math.max(fromRow, toRow), (this.bounds?.bottom ?? Number.POSITIVE_INFINITY) - 1);
|
|
127
142
|
for (let r = lo; r <= hi; r++) this.mergeCell(r, col, ["u", "d"], fg);
|
|
128
143
|
}
|
|
129
144
|
|
|
130
145
|
/** Materialise the canvas as one ANSI-styled string per row. */
|
|
131
146
|
toLines(): string[] {
|
|
132
|
-
|
|
147
|
+
const top = this.bounds?.top ?? 0;
|
|
148
|
+
const bottom = this.bounds?.bottom ?? this.maxRow + 1;
|
|
149
|
+
const left = this.bounds?.left ?? 0;
|
|
150
|
+
if (bottom <= top) return [];
|
|
133
151
|
const lines: string[] = [];
|
|
134
|
-
for (let r =
|
|
152
|
+
for (let r = top; r < bottom; r++) {
|
|
135
153
|
const cols = this.rows.get(r);
|
|
136
154
|
if (!cols || cols.size === 0) {
|
|
137
155
|
lines.push("");
|
|
138
156
|
continue;
|
|
139
157
|
}
|
|
140
158
|
let buf = "";
|
|
141
|
-
let cursorCol =
|
|
159
|
+
let cursorCol = left;
|
|
142
160
|
let activeFg: string | null = null;
|
|
143
161
|
const sortedCols = Array.from(cols.keys()).sort((a, b) => a - b);
|
|
144
162
|
for (const c of sortedCols) {
|
|
145
163
|
if (c > cursorCol) {
|
|
146
|
-
// Reset before emitting the gap so trailing styles don't bleed.
|
|
147
164
|
if (activeFg !== null) {
|
|
148
165
|
buf += RESET;
|
|
149
166
|
activeFg = null;
|
|
@@ -37,6 +37,9 @@ export const OVERLAY_VERTICAL_MARGIN_ROWS = 1;
|
|
|
37
37
|
* and the running-stage border lerps between `borderDim` and
|
|
38
38
|
* `warning` without a key press. The host-supplied `requestRender`
|
|
39
39
|
* gate prevents work while the overlay is hidden or unfocused.
|
|
40
|
+
* GraphView also skips ticks when nothing is animating — no running or
|
|
41
|
+
* awaiting_input stage and no prompt caret — so large idle graphs do not
|
|
42
|
+
* burn ~10 full paints/sec (#2100).
|
|
40
43
|
*/
|
|
41
44
|
export const ANIMATION_TICK_MS = 100;
|
|
42
45
|
|
|
@@ -18,16 +18,14 @@ export abstract class GraphViewGraphRenderer extends GraphViewRenderHelpers {
|
|
|
18
18
|
if (!run || this.cachedLayout.length === 0) {
|
|
19
19
|
this.lastGraphViewport = null;
|
|
20
20
|
this.graphNodeHitRects = [];
|
|
21
|
+
this.lastGraphTotalRows = 1;
|
|
21
22
|
const dim = hexToAnsi(this.graphTheme.dim);
|
|
22
23
|
return [this._centerCanvasContent(`${dim}waiting for stage events…${RESET}`, width)];
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const graphInner = Math.max(1, width - 4);
|
|
26
|
-
const canvasWidth
|
|
27
|
-
|
|
28
|
-
// small gutter and reveal focused nodes by horizontally scrolling the
|
|
29
|
-
// graph canvas. Do not switch to a compact list: the orchestrator pane
|
|
30
|
-
// should always preserve the node-card graph view.
|
|
27
|
+
const { canvasWidth, totalRows, bands, edges } = this.cachedRenderGeometry;
|
|
28
|
+
this.lastGraphTotalRows = totalRows;
|
|
31
29
|
const leftMargin = Math.max(2, canvasWidth <= graphInner ? Math.floor((graphInner - canvasWidth) / 2) : 2);
|
|
32
30
|
const viewportWidth = Math.max(1, width - leftMargin);
|
|
33
31
|
const fullCanvasWidth = Math.max(canvasWidth, viewportWidth);
|
|
@@ -37,73 +35,83 @@ export abstract class GraphViewGraphRenderer extends GraphViewRenderHelpers {
|
|
|
37
35
|
this._scrollFocusedColumnIntoView(viewportWidth, fullCanvasWidth);
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
const bodyRows = this._overlayBodyRows(this._overlayPanelLineCount());
|
|
39
|
+
if (totalRows > bodyRows) {
|
|
40
|
+
this._clampGraphScroll(totalRows, bodyRows);
|
|
41
|
+
if (this.pendingEnsureFocusedVisible) this._scrollFocusedIntoView(width, bodyRows, totalRows);
|
|
42
|
+
this._clampGraphScroll(totalRows, bodyRows);
|
|
43
|
+
} else {
|
|
44
|
+
this.graphScrollOffset = 0;
|
|
45
|
+
}
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
47
|
+
const viewportTop = this.graphScrollOffset;
|
|
48
|
+
const viewportBottom = Math.min(totalRows, viewportTop + bodyRows);
|
|
49
|
+
const viewportLeft = this.graphScrollColOffset;
|
|
50
|
+
const viewportRight = viewportLeft + viewportWidth;
|
|
51
|
+
const pulsePhase = (Date.now() % PULSE_PERIOD_MS) / PULSE_PERIOD_MS;
|
|
52
|
+
const edgeCanvas = new GraphCanvas({
|
|
53
|
+
top: viewportTop,
|
|
54
|
+
bottom: viewportBottom,
|
|
55
|
+
left: viewportLeft,
|
|
56
|
+
right: viewportRight,
|
|
57
|
+
});
|
|
50
58
|
const edgeColor = this.graphTheme.borderDim;
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
for (const edge of edges) {
|
|
60
|
+
if (
|
|
61
|
+
edge.bottom <= viewportTop ||
|
|
62
|
+
edge.top >= viewportBottom ||
|
|
63
|
+
edge.right <= viewportLeft ||
|
|
64
|
+
edge.left >= viewportRight
|
|
65
|
+
) {
|
|
66
|
+
continue;
|
|
57
67
|
}
|
|
68
|
+
this._plotEdge(edgeCanvas, edge.parentX, edge.parentY, edge.childX, edge.childY, edgeColor);
|
|
58
69
|
}
|
|
59
70
|
const edgeLines = edgeCanvas.toLines();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
71
|
+
const placements = new Map<number, Placement[]>();
|
|
72
|
+
for (let bandIndex = this._firstVisibleLayoutBand(viewportTop); bandIndex < bands.length; bandIndex++) {
|
|
73
|
+
const band = bands[bandIndex]!;
|
|
74
|
+
if (band.top >= viewportBottom) break;
|
|
75
|
+
for (const ni of band.nodeIndices) {
|
|
76
|
+
const node = this.cachedLayout[ni]!;
|
|
77
|
+
if (node.x + NODE_W <= viewportLeft || node.x >= viewportRight) continue;
|
|
78
|
+
const cardLines = renderNodeCard(node.stage, {
|
|
79
|
+
width: NODE_W,
|
|
80
|
+
height: NODE_H,
|
|
81
|
+
focused: ni === this.focusedIndex,
|
|
82
|
+
pulsePhase,
|
|
83
|
+
theme: this.graphTheme,
|
|
84
|
+
stages: this.cachedDisplayStages,
|
|
85
|
+
queuedMessageCount: this._stageQueuedMessageCount(node.stage),
|
|
86
|
+
});
|
|
87
|
+
const visibleLeft = Math.max(node.x, viewportLeft);
|
|
88
|
+
const visibleRight = Math.min(node.x + NODE_W, viewportRight);
|
|
89
|
+
for (let li = 0; li < cardLines.length; li++) {
|
|
90
|
+
const globalRow = node.y + li;
|
|
91
|
+
if (globalRow < viewportTop || globalRow >= viewportBottom) continue;
|
|
92
|
+
const localRow = globalRow - viewportTop;
|
|
93
|
+
let bucket = placements.get(localRow);
|
|
94
|
+
if (!bucket) {
|
|
95
|
+
bucket = [];
|
|
96
|
+
placements.set(localRow, bucket);
|
|
97
|
+
}
|
|
98
|
+
bucket.push({
|
|
99
|
+
startCol: visibleLeft - viewportLeft,
|
|
100
|
+
width: visibleRight - visibleLeft,
|
|
101
|
+
line: this._sliceColumns(cardLines[li]!, visibleLeft - node.x, visibleRight - node.x),
|
|
102
|
+
});
|
|
81
103
|
}
|
|
82
|
-
bucket.push({ startCol: node.x, width: NODE_W, line: cardLines[li]! });
|
|
83
104
|
}
|
|
84
105
|
}
|
|
85
106
|
|
|
86
|
-
// 3. Compose each output row by interleaving edge segments with the
|
|
87
|
-
// card placements at their assigned columns.
|
|
88
|
-
const totalRows = Math.max(edgeLines.length, ...this.cachedLayout.map((n) => n.y + NODE_H));
|
|
89
|
-
const composed: string[] = [];
|
|
90
|
-
for (let rowIdx = 0; rowIdx < totalRows; rowIdx++) {
|
|
91
|
-
const edgeRowChars = this._edgeRowToCells(edgeLines[rowIdx] ?? "");
|
|
92
|
-
const cards = placements.get(rowIdx) ?? [];
|
|
93
|
-
composed.push(this._composeRow(edgeRowChars, cards, edgeColor));
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
// Pad the full graph canvas, then crop a horizontal viewport when the
|
|
97
|
-
// fan-out is wider than the terminal. Cards/edges only paint cells they
|
|
98
|
-
// occupy; everywhere else needs explicit bg so default terminal colours
|
|
99
|
-
// never leak through.
|
|
100
107
|
const bg = hexBg(this.graphTheme.bg);
|
|
101
108
|
const leftPad = `${bg}${" ".repeat(leftMargin)}${RESET}`;
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
const
|
|
105
|
-
|
|
106
|
-
}
|
|
109
|
+
const composed: string[] = [];
|
|
110
|
+
for (let localRow = 0; localRow < viewportBottom - viewportTop; localRow++) {
|
|
111
|
+
const line = this._composeRow(edgeLines[localRow] ?? "", placements.get(localRow) ?? [], edgeColor);
|
|
112
|
+
composed.push(`${leftPad}${this._padCanvas(line, viewportWidth)}`);
|
|
113
|
+
}
|
|
114
|
+
return composed;
|
|
107
115
|
}
|
|
108
116
|
|
|
109
117
|
protected _recordGraphNodeHitRects(graphStartRow: number, visibleRowCount: number): void {
|
|
@@ -118,52 +126,41 @@ export abstract class GraphViewGraphRenderer extends GraphViewRenderHelpers {
|
|
|
118
126
|
const viewportLeft = viewport.leftMargin;
|
|
119
127
|
const viewportRight = viewport.leftMargin + viewport.viewportWidth;
|
|
120
128
|
const rects: typeof this.graphNodeHitRects = [];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
const
|
|
126
|
-
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
right: clippedRight
|
|
139
|
-
}
|
|
129
|
+
const viewportTop = this.graphScrollOffset;
|
|
130
|
+
const viewportBottom = viewportTop + visibleRowCount;
|
|
131
|
+
const { bands } = this.cachedRenderGeometry;
|
|
132
|
+
for (let bandIndex = this._firstVisibleLayoutBand(viewportTop); bandIndex < bands.length; bandIndex++) {
|
|
133
|
+
const band = bands[bandIndex]!;
|
|
134
|
+
if (band.top >= viewportBottom) break;
|
|
135
|
+
for (const index of band.nodeIndices) {
|
|
136
|
+
const node = this.cachedLayout[index]!;
|
|
137
|
+
const top = graphStartRow + node.y - viewportTop;
|
|
138
|
+
const bottom = top + NODE_H;
|
|
139
|
+
const left = viewport.leftMargin + node.x - this.graphScrollColOffset;
|
|
140
|
+
const right = left + NODE_W;
|
|
141
|
+
const clippedTop = Math.max(visibleTop, top);
|
|
142
|
+
const clippedBottom = Math.min(visibleBottom, bottom);
|
|
143
|
+
const clippedLeft = Math.max(viewportLeft, left);
|
|
144
|
+
const clippedRight = Math.min(viewportRight, right);
|
|
145
|
+
if (clippedTop >= clippedBottom || clippedLeft >= clippedRight) continue;
|
|
146
|
+
rects.push({ index, top: clippedTop, bottom: clippedBottom, left: clippedLeft, right: clippedRight });
|
|
147
|
+
}
|
|
140
148
|
}
|
|
141
149
|
this.graphNodeHitRects = rects;
|
|
142
150
|
}
|
|
143
151
|
|
|
144
152
|
protected _visibleGraphLines(
|
|
145
153
|
graphLines: string[],
|
|
146
|
-
|
|
154
|
+
_frameWidth: number,
|
|
147
155
|
bodyRows: number,
|
|
148
156
|
): { lines: string[]; topPad: number } {
|
|
149
|
-
|
|
150
|
-
this.graphScrollOffset = 0;
|
|
151
|
-
this.pendingEnsureFocusedVisible = false;
|
|
152
|
-
return {
|
|
153
|
-
lines: graphLines,
|
|
154
|
-
topPad: Math.min(3, Math.max(0, Math.floor((bodyRows - graphLines.length) / 2))),
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
this._clampGraphScroll(graphLines.length, bodyRows);
|
|
159
|
-
if (this.pendingEnsureFocusedVisible) {
|
|
160
|
-
this._scrollFocusedIntoView(frameWidth, bodyRows, graphLines.length);
|
|
161
|
-
this.pendingEnsureFocusedVisible = false;
|
|
162
|
-
}
|
|
163
|
-
this._clampGraphScroll(graphLines.length, bodyRows);
|
|
157
|
+
this.pendingEnsureFocusedVisible = false;
|
|
164
158
|
return {
|
|
165
|
-
lines: graphLines
|
|
166
|
-
topPad:
|
|
159
|
+
lines: graphLines,
|
|
160
|
+
topPad:
|
|
161
|
+
this.lastGraphTotalRows <= bodyRows
|
|
162
|
+
? Math.min(3, Math.max(0, Math.floor((bodyRows - this.lastGraphTotalRows) / 2)))
|
|
163
|
+
: 0,
|
|
167
164
|
};
|
|
168
165
|
}
|
|
169
166
|
}
|
|
@@ -4,8 +4,6 @@ import { GraphViewGraphRenderer } from "./graph-view-graph-render.js";
|
|
|
4
4
|
import { renderHeader, renderOutlinePill } from "./header.js";
|
|
5
5
|
import { renderPromptCard } from "./prompt-card.js";
|
|
6
6
|
import { renderSwitcher } from "./switcher.js";
|
|
7
|
-
import { truncateToWidth } from "./text-helpers.js";
|
|
8
|
-
import { renderToasts } from "./toast.js";
|
|
9
7
|
|
|
10
8
|
/** Overlay/widget rendering orchestration for GraphView. */
|
|
11
9
|
export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
@@ -68,7 +66,6 @@ export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
|
68
66
|
|
|
69
67
|
this._renderSwitcherOverlay(lines, run, frameWidth, bodyTarget);
|
|
70
68
|
this._renderPromptOverlay(lines, frameWidth, bodyTarget);
|
|
71
|
-
this._renderToastOverlay(lines, frameWidth);
|
|
72
69
|
|
|
73
70
|
// 5. Three-row statusline pinned to the bottom.
|
|
74
71
|
lines.push(...this._renderStatusline(frameWidth));
|
|
@@ -146,37 +143,27 @@ export abstract class GraphViewRenderer extends GraphViewGraphRenderer {
|
|
|
146
143
|
// surface that interacts with the prompt. When the stage switcher is
|
|
147
144
|
// open it owns the body/input, so hide the prompt card until it closes.
|
|
148
145
|
if (!this.promptState || this.switcherOpen) return;
|
|
149
|
-
|
|
146
|
+
const run = this._getCurrentRun();
|
|
150
147
|
const cardWidth = Math.min(72, Math.max(40, frameWidth - 6));
|
|
151
148
|
const cardLines = renderPromptCard({
|
|
152
149
|
state: this.promptState,
|
|
153
150
|
theme: this.graphTheme,
|
|
154
151
|
width: cardWidth,
|
|
155
152
|
cursorOn: ((Date.now() / 530) | 0) % 2 === 0,
|
|
153
|
+
identity: run ? { runId: run.id, name: run.name } : undefined,
|
|
154
|
+
maxRows: bodyTarget,
|
|
156
155
|
});
|
|
157
156
|
const bodyStart = 3;
|
|
158
|
-
const bodyEnd =
|
|
157
|
+
const bodyEnd = bodyStart + bodyTarget;
|
|
159
158
|
const slot = Math.max(bodyStart, bodyStart + Math.floor((bodyTarget - cardLines.length) / 2));
|
|
159
|
+
// The card renderer owns row budgeting, but keep this composition boundary
|
|
160
|
+
// defensive: a complete card fits wholly in the body or is not painted.
|
|
161
|
+
if (cardLines.length > bodyTarget || slot + cardLines.length > bodyEnd) return;
|
|
160
162
|
const leftPad = Math.max(0, Math.floor((frameWidth - cardWidth) / 2));
|
|
161
163
|
for (let i = 0; i < cardLines.length; i++) {
|
|
162
164
|
const lineIdx = slot + i;
|
|
163
|
-
if (lineIdx >= bodyEnd) break;
|
|
164
165
|
const base = lines[lineIdx] ?? this._blankRow(frameWidth);
|
|
165
166
|
lines[lineIdx] = this._overlayCard(base, cardLines[i]!, leftPad, frameWidth);
|
|
166
167
|
}
|
|
167
168
|
}
|
|
168
|
-
|
|
169
|
-
private _renderToastOverlay(lines: string[], frameWidth: number): void {
|
|
170
|
-
// Toast overlay — top-right of header band.
|
|
171
|
-
const toastLines = renderToasts(this.toastManager.active(), {
|
|
172
|
-
theme: this.graphTheme,
|
|
173
|
-
});
|
|
174
|
-
if (toastLines.length === 0) return;
|
|
175
|
-
|
|
176
|
-
for (let i = 0; i < toastLines.length && i < lines.length; i++) {
|
|
177
|
-
const existing = lines[i] ?? "";
|
|
178
|
-
const merged = `${existing} ${toastLines[i]}`;
|
|
179
|
-
lines[i] = truncateToWidth(merged, frameWidth, "", true);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
169
|
}
|