@bastani/atomic 0.8.4-0 → 0.8.5-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 +16 -0
- package/README.md +24 -23
- package/dist/builtin/intercom/README.md +5 -5
- package/dist/builtin/intercom/index.ts +1 -1
- package/dist/builtin/intercom/package.json +1 -1
- package/dist/builtin/intercom/ui/compose.ts +19 -1
- package/dist/builtin/intercom/ui/session-list.ts +19 -1
- package/dist/builtin/mcp/README.md +3 -3
- package/dist/builtin/mcp/commands.ts +1 -1
- package/dist/builtin/mcp/host-html-template.ts +1 -1
- package/dist/builtin/mcp/mcp-panel.ts +14 -14
- package/dist/builtin/mcp/mcp-setup-panel.ts +4 -4
- package/dist/builtin/mcp/package.json +1 -1
- package/dist/builtin/mcp/tool-result-renderer.ts +1 -1
- package/dist/builtin/subagents/README.md +3 -3
- package/dist/builtin/subagents/package.json +1 -1
- package/dist/builtin/subagents/src/tui/render.ts +1844 -1062
- package/dist/builtin/web-access/README.md +1 -1
- package/dist/builtin/web-access/curator-page.ts +2 -2
- package/dist/builtin/web-access/index.ts +1 -1
- package/dist/builtin/web-access/package.json +1 -1
- package/dist/builtin/workflows/README.md +34 -7
- package/dist/builtin/workflows/builtin/deep-research-codebase.ts +23 -4
- package/dist/builtin/workflows/builtin/ralph.ts +1 -1
- package/dist/builtin/workflows/package.json +1 -1
- package/dist/builtin/workflows/skills/workflow/SKILL.md +75 -16
- package/dist/builtin/workflows/skills/workflow/references/running-workflows.md +34 -11
- package/dist/builtin/workflows/skills/workflow/references/sdk-authoring.md +111 -20
- package/dist/builtin/workflows/src/extension/discovery.ts +32 -4
- package/dist/builtin/workflows/src/extension/index.ts +347 -63
- package/dist/builtin/workflows/src/extension/render-call.ts +3 -1
- package/dist/builtin/workflows/src/extension/render-result.ts +7 -0
- package/dist/builtin/workflows/src/extension/runtime.ts +4 -2
- package/dist/builtin/workflows/src/extension/wiring.ts +32 -8
- package/dist/builtin/workflows/src/extension/workflow-schema.ts +36 -14
- package/dist/builtin/workflows/src/runs/background/runner.ts +2 -2
- package/dist/builtin/workflows/src/runs/background/status.ts +89 -0
- package/dist/builtin/workflows/src/runs/foreground/executor.ts +338 -78
- package/dist/builtin/workflows/src/runs/foreground/stage-control-registry.ts +2 -0
- package/dist/builtin/workflows/src/runs/foreground/stage-runner.ts +55 -7
- package/dist/builtin/workflows/src/runs/shared/workflow-runner.ts +146 -10
- package/dist/builtin/workflows/src/shared/store.ts +29 -0
- package/dist/builtin/workflows/src/shared/types.ts +25 -4
- package/dist/builtin/workflows/src/tui/graph-canvas.ts +69 -2
- package/dist/builtin/workflows/src/tui/graph-view.ts +97 -182
- package/dist/builtin/workflows/src/tui/header.ts +36 -20
- package/dist/builtin/workflows/src/tui/inline-form-card.ts +129 -46
- package/dist/builtin/workflows/src/tui/inline-form-editor.ts +111 -36
- package/dist/builtin/workflows/src/tui/inputs-picker.ts +311 -91
- package/dist/builtin/workflows/src/tui/layout.ts +1 -1
- package/dist/builtin/workflows/src/tui/node-card.ts +66 -37
- package/dist/builtin/workflows/src/tui/overlay-adapter.ts +20 -6
- package/dist/builtin/workflows/src/tui/prompt-card.ts +262 -85
- package/dist/builtin/workflows/src/tui/run-detail.ts +50 -31
- package/dist/builtin/workflows/src/tui/session-confirm.ts +21 -14
- package/dist/builtin/workflows/src/tui/session-picker.ts +35 -26
- package/dist/builtin/workflows/src/tui/stage-chat-view.ts +531 -960
- package/dist/builtin/workflows/src/tui/status-helpers.ts +6 -0
- package/dist/builtin/workflows/src/tui/status-list.ts +8 -4
- package/dist/builtin/workflows/src/tui/store-widget-installer.ts +7 -2
- package/dist/builtin/workflows/src/tui/switcher.ts +55 -25
- package/dist/builtin/workflows/src/tui/workflow-attach-pane.ts +33 -1
- package/dist/builtin/workflows/src/tui/workflow-list.ts +10 -6
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +1 -1
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +20 -6
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session-services.d.ts +3 -3
- package/dist/core/agent-session-services.d.ts.map +1 -1
- package/dist/core/agent-session-services.js.map +1 -1
- package/dist/core/agent-session.d.ts +7 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +2 -2
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +3 -3
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
- package/dist/core/export-html/tool-renderer.js.map +1 -1
- package/dist/core/extensions/loader.d.ts +3 -2
- package/dist/core/extensions/loader.d.ts.map +1 -1
- package/dist/core/extensions/loader.js +24 -12
- package/dist/core/extensions/loader.js.map +1 -1
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +6 -0
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +28 -17
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/package-manager.d.ts +1 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +65 -28
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +13 -5
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/sdk.d.ts +3 -3
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +1 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- 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 -1
- 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 +5 -3
- package/dist/core/system-prompt.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js +1 -1
- package/dist/core/tools/ask-user-question/view/components/preview/preview-block-renderer.js.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts +8 -8
- package/dist/core/tools/ask-user-question/view/dialog-builder.d.ts.map +1 -1
- package/dist/core/tools/ask-user-question/view/dialog-builder.js +6 -6
- package/dist/core/tools/ask-user-question/view/dialog-builder.js.map +1 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +1 -1
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js +7 -4
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/index.d.ts +3 -2
- package/dist/core/tools/index.d.ts.map +1 -1
- package/dist/core/tools/index.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +3 -2
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +2 -2
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +2 -1
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/todos.d.ts.map +1 -1
- package/dist/core/tools/todos.js +1 -1
- package/dist/core/tools/todos.js.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.d.ts +4 -3
- package/dist/core/tools/tool-definition-wrapper.d.ts.map +1 -1
- package/dist/core/tools/tool-definition-wrapper.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +1 -1
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +2 -2
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/assistant-message.js +3 -3
- package/dist/modes/interactive/components/assistant-message.js.map +1 -1
- package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/bash-execution.js +3 -3
- package/dist/modes/interactive/components/bash-execution.js.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js +1 -1
- package/dist/modes/interactive/components/branch-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts +2 -1
- package/dist/modes/interactive/components/chat-message-renderer.d.ts.map +1 -1
- package/dist/modes/interactive/components/chat-message-renderer.js.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js +1 -1
- package/dist/modes/interactive/components/compaction-summary-message.js.map +1 -1
- package/dist/modes/interactive/components/config-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/config-selector.js +1 -1
- package/dist/modes/interactive/components/config-selector.js.map +1 -1
- package/dist/modes/interactive/components/custom-editor.d.ts +3 -0
- package/dist/modes/interactive/components/custom-editor.d.ts.map +1 -1
- package/dist/modes/interactive/components/custom-editor.js +13 -3
- package/dist/modes/interactive/components/custom-editor.js.map +1 -1
- package/dist/modes/interactive/components/footer.d.ts.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/index.d.ts +2 -1
- package/dist/modes/interactive/components/index.d.ts.map +1 -1
- package/dist/modes/interactive/components/index.js +2 -1
- package/dist/modes/interactive/components/index.js.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.d.ts +1 -0
- package/dist/modes/interactive/components/keybinding-hints.d.ts.map +1 -1
- package/dist/modes/interactive/components/keybinding-hints.js +47 -5
- package/dist/modes/interactive/components/keybinding-hints.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +5 -5
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/model-selector.d.ts +3 -3
- package/dist/modes/interactive/components/model-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/model-selector.js.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.d.ts +2 -2
- package/dist/modes/interactive/components/scoped-models-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/scoped-models-selector.js +7 -7
- package/dist/modes/interactive/components/scoped-models-selector.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +8 -8
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/settings-selector.js +3 -3
- package/dist/modes/interactive/components/settings-selector.js.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.d.ts.map +1 -1
- package/dist/modes/interactive/components/skill-invocation-message.js +2 -2
- package/dist/modes/interactive/components/skill-invocation-message.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts +10 -12
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +3 -3
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/components/working-status.d.ts +25 -0
- package/dist/modes/interactive/components/working-status.d.ts.map +1 -0
- package/dist/modes/interactive/components/working-status.js +28 -0
- package/dist/modes/interactive/components/working-status.js.map +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +8 -7
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +8 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +5 -5
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/utils/tools-manager.d.ts.map +1 -1
- package/dist/utils/tools-manager.js.map +1 -1
- package/docs/development.md +2 -2
- package/docs/extensions.md +7 -7
- package/docs/packages.md +11 -8
- package/docs/quickstart.md +2 -2
- package/docs/rpc.md +1 -1
- package/docs/sdk.md +14 -11
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +10 -10
- package/docs/settings.md +1 -1
- package/docs/terminal-setup.md +9 -9
- package/docs/tmux.md +10 -10
- package/docs/tui.md +2 -2
- package/docs/usage.md +9 -9
- package/package.json +6 -1
|
@@ -24,6 +24,7 @@ import { renderBandHeader } from "./header.js";
|
|
|
24
24
|
import type { BandBadge } from "./header.js";
|
|
25
25
|
import { fmtDuration, statusIcon, statusColor } from "./status-helpers.js";
|
|
26
26
|
import { hexToAnsi, RESET, BOLD } from "./color-utils.js";
|
|
27
|
+
import { truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
27
28
|
|
|
28
29
|
const SHORT_ID_LEN = 6;
|
|
29
30
|
const STAGE_NAME_COL = 14;
|
|
@@ -34,6 +35,8 @@ export interface RenderRunDetailOpts {
|
|
|
34
35
|
theme?: GraphTheme;
|
|
35
36
|
/** Optional clock override for tests. */
|
|
36
37
|
now?: number;
|
|
38
|
+
/** Optional render width (cells) for truncating long/wide values. */
|
|
39
|
+
width?: number;
|
|
37
40
|
}
|
|
38
41
|
|
|
39
42
|
/**
|
|
@@ -44,15 +47,16 @@ export function renderRunDetail(
|
|
|
44
47
|
opts: RenderRunDetailOpts = {},
|
|
45
48
|
): string {
|
|
46
49
|
const now = opts.now ?? Date.now();
|
|
47
|
-
|
|
48
|
-
return
|
|
50
|
+
const width = Math.max(32, opts.width ?? 80);
|
|
51
|
+
if (opts.theme === undefined) return renderPlain(detail, now, width);
|
|
52
|
+
return renderThemed(detail, now, opts.theme, width);
|
|
49
53
|
}
|
|
50
54
|
|
|
51
55
|
// ---------------------------------------------------------------------------
|
|
52
56
|
// Plain renderer — used by tests and headless consumers
|
|
53
57
|
// ---------------------------------------------------------------------------
|
|
54
58
|
|
|
55
|
-
function renderPlain(detail: RunDetail, now: number): string {
|
|
59
|
+
function renderPlain(detail: RunDetail, now: number, width: number): string {
|
|
56
60
|
const out: string[] = [];
|
|
57
61
|
|
|
58
62
|
const sid = shortId(detail.runId);
|
|
@@ -60,14 +64,17 @@ function renderPlain(detail: RunDetail, now: number): string {
|
|
|
60
64
|
const innerLabel = ` RUN ${sid} `;
|
|
61
65
|
const inner = "─".repeat(innerLabel.length);
|
|
62
66
|
out.push(` ╭${inner}╮`);
|
|
63
|
-
|
|
67
|
+
const headerTailW = visibleWidth(` │${innerLabel}│ `) + visibleWidth(` ${stateBadge}`);
|
|
68
|
+
const headerName = truncateToWidth(detail.name, Math.max(1, width - headerTailW), "…");
|
|
69
|
+
out.push(` │${innerLabel}│ ${headerName} ${stateBadge}`);
|
|
64
70
|
out.push(` ╰${inner}╯`);
|
|
65
71
|
out.push("");
|
|
66
72
|
|
|
67
73
|
// Summary key/value lines
|
|
68
74
|
for (const [k, v] of summaryRows(detail, now)) {
|
|
69
75
|
if (v === undefined) continue;
|
|
70
|
-
|
|
76
|
+
const value = truncateToWidth(v, Math.max(1, width - 2 - KEY_COL), "…");
|
|
77
|
+
out.push(` ${pad(k, KEY_COL)}${value}`);
|
|
71
78
|
}
|
|
72
79
|
out.push("");
|
|
73
80
|
|
|
@@ -78,9 +85,10 @@ function renderPlain(detail: RunDetail, now: number): string {
|
|
|
78
85
|
out.push(" (no stages recorded yet)");
|
|
79
86
|
} else {
|
|
80
87
|
for (const stage of detail.stages) {
|
|
81
|
-
out.push(` ${stageLinePlain(stage, now)}`);
|
|
88
|
+
out.push(` ${stageLinePlain(stage, now, width - 2)}`);
|
|
82
89
|
if (stage.error) {
|
|
83
|
-
|
|
90
|
+
const err = truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - STAGE_NAME_COL - 11), "…");
|
|
91
|
+
out.push(` ${" ".repeat(STAGE_NAME_COL + 2)}error ${err}`);
|
|
84
92
|
}
|
|
85
93
|
}
|
|
86
94
|
}
|
|
@@ -92,16 +100,16 @@ function renderPlain(detail: RunDetail, now: number): string {
|
|
|
92
100
|
out.push("▎ ARTIFACTS");
|
|
93
101
|
out.push("");
|
|
94
102
|
for (const [k, v] of artifactRows) {
|
|
95
|
-
out.push(` ${pad(k, KEY_COL)}${v}`);
|
|
103
|
+
out.push(` ${pad(k, KEY_COL)}${truncateToWidth(v, Math.max(1, width - 2 - KEY_COL), "…")}`);
|
|
96
104
|
}
|
|
97
105
|
out.push("");
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
// Action hints
|
|
101
109
|
if (detail.endedAt === undefined) {
|
|
102
|
-
out.push(` ▸ workflow interrupt id=${sid} cancel
|
|
110
|
+
out.push(truncateToWidth(` ▸ workflow interrupt id=${sid} cancel`, width, "…"));
|
|
103
111
|
} else {
|
|
104
|
-
out.push(` ▸ workflow resume id=${sid} reopen graph
|
|
112
|
+
out.push(truncateToWidth(` ▸ workflow resume id=${sid} reopen graph`, width, "…"));
|
|
105
113
|
}
|
|
106
114
|
|
|
107
115
|
return out.join("\n");
|
|
@@ -111,7 +119,7 @@ function renderPlain(detail: RunDetail, now: number): string {
|
|
|
111
119
|
// Themed renderer — ANSI Catppuccin chrome
|
|
112
120
|
// ---------------------------------------------------------------------------
|
|
113
121
|
|
|
114
|
-
function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string {
|
|
122
|
+
function renderThemed(detail: RunDetail, now: number, theme: GraphTheme, width: number): string {
|
|
115
123
|
const out: string[] = [];
|
|
116
124
|
const mauve = hexToAnsi(theme.mauve);
|
|
117
125
|
const muted = hexToAnsi(theme.textMuted);
|
|
@@ -128,7 +136,7 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string
|
|
|
128
136
|
label: `RUN ${sid}`,
|
|
129
137
|
subtitle: detail.name,
|
|
130
138
|
badges,
|
|
131
|
-
width: 64,
|
|
139
|
+
width: Math.min(64, width),
|
|
132
140
|
theme,
|
|
133
141
|
}));
|
|
134
142
|
out.push("");
|
|
@@ -136,7 +144,8 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string
|
|
|
136
144
|
// Summary key/value
|
|
137
145
|
for (const [k, v] of summaryRows(detail, now)) {
|
|
138
146
|
if (v === undefined) continue;
|
|
139
|
-
|
|
147
|
+
const value = truncateToWidth(v, Math.max(1, width - 2 - KEY_COL), "…");
|
|
148
|
+
out.push(` ${muted}${pad(k, KEY_COL)}${RESET}${text}${value}${RESET}`);
|
|
140
149
|
}
|
|
141
150
|
out.push("");
|
|
142
151
|
|
|
@@ -147,11 +156,12 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string
|
|
|
147
156
|
out.push(` ${dim}(no stages recorded yet)${RESET}`);
|
|
148
157
|
} else {
|
|
149
158
|
for (const stage of detail.stages) {
|
|
150
|
-
out.push(" " + stageLineThemed(stage, now, theme));
|
|
159
|
+
out.push(" " + stageLineThemed(stage, now, theme, width - 2));
|
|
151
160
|
if (stage.error) {
|
|
152
161
|
const errFg = hexToAnsi(theme.error);
|
|
162
|
+
const err = truncateToWidth(stage.error.split("\n")[0] ?? "", Math.max(1, width - STAGE_NAME_COL - 13), "…");
|
|
153
163
|
out.push(
|
|
154
|
-
` ${" ".repeat(STAGE_NAME_COL + 2)}${muted}error${RESET} ${errFg}${
|
|
164
|
+
` ${" ".repeat(STAGE_NAME_COL + 2)}${muted}error${RESET} ${errFg}${err}${RESET}`,
|
|
155
165
|
);
|
|
156
166
|
}
|
|
157
167
|
}
|
|
@@ -164,7 +174,7 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string
|
|
|
164
174
|
out.push(`${mauve}▎${RESET} ${muted}${BOLD}ARTIFACTS${RESET}`);
|
|
165
175
|
out.push("");
|
|
166
176
|
for (const [k, v] of artifactRows) {
|
|
167
|
-
out.push(` ${muted}${pad(k, KEY_COL)}${RESET}${dim}${v}${RESET}`);
|
|
177
|
+
out.push(` ${muted}${pad(k, KEY_COL)}${RESET}${dim}${truncateToWidth(v, Math.max(1, width - 2 - KEY_COL), "…")}${RESET}`);
|
|
168
178
|
}
|
|
169
179
|
out.push("");
|
|
170
180
|
}
|
|
@@ -172,11 +182,11 @@ function renderThemed(detail: RunDetail, now: number, theme: GraphTheme): string
|
|
|
172
182
|
// Action hints
|
|
173
183
|
if (detail.endedAt === undefined) {
|
|
174
184
|
out.push(
|
|
175
|
-
` ${dim}▸${RESET} ${accent}workflow interrupt id=${sid}${RESET}${dim} cancel${RESET}`,
|
|
185
|
+
truncateToWidth(` ${dim}▸${RESET} ${accent}workflow interrupt id=${sid}${RESET}${dim} cancel${RESET}`, width, "…"),
|
|
176
186
|
);
|
|
177
187
|
} else {
|
|
178
188
|
out.push(
|
|
179
|
-
` ${dim}▸${RESET} ${accent}workflow resume id=${sid}${RESET}${dim} reopen graph${RESET}`,
|
|
189
|
+
truncateToWidth(` ${dim}▸${RESET} ${accent}workflow resume id=${sid}${RESET}${dim} reopen graph${RESET}`, width, "…"),
|
|
180
190
|
);
|
|
181
191
|
}
|
|
182
192
|
|
|
@@ -206,7 +216,7 @@ function summaryRows(detail: RunDetail, now: number): Array<[string, string | un
|
|
|
206
216
|
rows.push(["elapsed", fmtDuration(duration)]);
|
|
207
217
|
}
|
|
208
218
|
if (detail.error) {
|
|
209
|
-
rows.push(["error", detail.error.split("\n")[0]
|
|
219
|
+
rows.push(["error", detail.error.split("\n")[0] ?? ""]);
|
|
210
220
|
}
|
|
211
221
|
return rows;
|
|
212
222
|
}
|
|
@@ -214,7 +224,7 @@ function summaryRows(detail: RunDetail, now: number): Array<[string, string | un
|
|
|
214
224
|
function artifactRowsFor(detail: RunDetail): Array<[string, string]> {
|
|
215
225
|
const rows: Array<[string, string]> = [];
|
|
216
226
|
if (detail.result !== undefined && Object.keys(detail.result).length > 0) {
|
|
217
|
-
rows.push(["result", JSON.stringify(detail.result)
|
|
227
|
+
rows.push(["result", JSON.stringify(detail.result)]);
|
|
218
228
|
}
|
|
219
229
|
const inputKeys = Object.keys(detail.inputs);
|
|
220
230
|
if (inputKeys.length > 0) {
|
|
@@ -223,20 +233,22 @@ function artifactRowsFor(detail: RunDetail): Array<[string, string]> {
|
|
|
223
233
|
return rows;
|
|
224
234
|
}
|
|
225
235
|
|
|
226
|
-
function stageLinePlain(stage: StageSnapshot, now: number): string {
|
|
236
|
+
function stageLinePlain(stage: StageSnapshot, now: number, width: number): string {
|
|
227
237
|
const icon = statusIcon(stage.status);
|
|
228
238
|
const dur = stageDurationString(stage, now);
|
|
229
239
|
const activity = stageActivityString(stage);
|
|
240
|
+
const name = truncateToWidth(`${icon} ${stage.name}`, STAGE_NAME_COL + 2, "…");
|
|
241
|
+
const activityText = activity ? truncateToWidth(activity, 16, "…") : undefined;
|
|
230
242
|
const parts = [
|
|
231
|
-
pad(
|
|
243
|
+
pad(name, STAGE_NAME_COL + 2),
|
|
232
244
|
pad(stage.status, 10),
|
|
233
245
|
];
|
|
234
|
-
if (
|
|
246
|
+
if (activityText) parts.push(pad(activityText, 16));
|
|
235
247
|
if (dur) parts.push(dur);
|
|
236
|
-
return parts.join("");
|
|
248
|
+
return truncateToWidth(parts.join(""), width, "…");
|
|
237
249
|
}
|
|
238
250
|
|
|
239
|
-
function stageLineThemed(stage: StageSnapshot, now: number, theme: GraphTheme): string {
|
|
251
|
+
function stageLineThemed(stage: StageSnapshot, now: number, theme: GraphTheme, width: number): string {
|
|
240
252
|
const icon = statusIcon(stage.status);
|
|
241
253
|
const iconFg = hexToAnsi(statusColor(stage.status, theme));
|
|
242
254
|
const text = hexToAnsi(theme.text);
|
|
@@ -247,14 +259,20 @@ function stageLineThemed(stage: StageSnapshot, now: number, theme: GraphTheme):
|
|
|
247
259
|
const activity = stageActivityString(stage);
|
|
248
260
|
const dur = stageDurationString(stage, now);
|
|
249
261
|
|
|
250
|
-
const
|
|
262
|
+
const nameText = truncateToWidth(stage.name, STAGE_NAME_COL, "…");
|
|
263
|
+
const namePad = pad(nameText, STAGE_NAME_COL);
|
|
251
264
|
const statePad = pad(stage.status, 10);
|
|
252
|
-
const
|
|
253
|
-
|
|
265
|
+
const activityText = activity ? truncateToWidth(activity, 16, "…") : undefined;
|
|
266
|
+
const activitySeg = activityText
|
|
267
|
+
? `${muted}${pad(activityText, 16)}${RESET}`
|
|
254
268
|
: " ".repeat(16);
|
|
255
269
|
const durSeg = dur ? `${dim}${dur}${RESET}` : "";
|
|
256
270
|
|
|
257
|
-
return
|
|
271
|
+
return truncateToWidth(
|
|
272
|
+
`${iconFg}${icon}${RESET} ${text}${namePad}${RESET} ${stateFg}${statePad}${RESET}${activitySeg}${durSeg}`,
|
|
273
|
+
width,
|
|
274
|
+
"…",
|
|
275
|
+
);
|
|
258
276
|
}
|
|
259
277
|
|
|
260
278
|
function stageDurationString(stage: StageSnapshot, now: number): string | undefined {
|
|
@@ -322,8 +340,9 @@ function shortId(id: string): string {
|
|
|
322
340
|
}
|
|
323
341
|
|
|
324
342
|
function pad(s: string, n: number): string {
|
|
325
|
-
|
|
326
|
-
|
|
343
|
+
const width = visibleWidth(s);
|
|
344
|
+
if (width >= n) return s;
|
|
345
|
+
return s + " ".repeat(n - width);
|
|
327
346
|
}
|
|
328
347
|
|
|
329
348
|
function formatTime(ms: number): string {
|
|
@@ -18,11 +18,12 @@
|
|
|
18
18
|
* - DESIGN.md §5 Components — destructive button
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
import { keyText } from "@bastani/atomic";
|
|
21
22
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
22
23
|
import type { GraphTheme } from "./graph-theme.js";
|
|
23
24
|
import { fmtDuration } from "./status-helpers.js";
|
|
24
25
|
import { hexToAnsi, hexBg, RESET, BOLD } from "./color-utils.js";
|
|
25
|
-
import { visibleWidth } from "./text-helpers.js";
|
|
26
|
+
import { truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
26
27
|
|
|
27
28
|
export interface KillConfirmState {
|
|
28
29
|
/** 0 = Cancel (focused by default), 1 = Kill. */
|
|
@@ -67,17 +68,18 @@ function renderFooter(width: number, theme: GraphTheme): string {
|
|
|
67
68
|
const text = hexToAnsi(theme.text);
|
|
68
69
|
const muted = hexToAnsi(theme.textMuted);
|
|
69
70
|
const sep = `${dim} \u00b7 ${RESET}`;
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const line = parts.join(sep);
|
|
71
|
+
const hint = (key: string, label: string) => `${text}${key}${RESET} ${muted}${label}${RESET}`;
|
|
72
|
+
const line = [
|
|
73
|
+
hint("y", "Kill"),
|
|
74
|
+
hint("n", "Cancel"),
|
|
75
|
+
hint(keyText("tui.select.confirm"), "Confirm"),
|
|
76
|
+
hint(keyText("tui.select.cancel"), "Cancel"),
|
|
77
|
+
].join(sep);
|
|
78
78
|
const leftRule = "\u2500\u2500 ";
|
|
79
|
-
const
|
|
80
|
-
const
|
|
79
|
+
const lineBudget = Math.max(1, inner - visibleWidth(leftRule) - 1);
|
|
80
|
+
const clippedLine = truncateToWidth(line, lineBudget, "…");
|
|
81
|
+
const padLen = Math.max(1, inner - visibleWidth(leftRule) - visibleWidth(clippedLine) - 1);
|
|
82
|
+
const innerContent = `${border}${leftRule}${RESET}${clippedLine}${border}${" ".repeat(padLen)}${RESET}`;
|
|
81
83
|
return `${border}\u2570${RESET}${padTo(innerContent, inner)}${border}\u256f${RESET}`;
|
|
82
84
|
}
|
|
83
85
|
|
|
@@ -131,9 +133,14 @@ export function renderKillConfirm(opts: KillConfirmRenderOpts): string[] {
|
|
|
131
133
|
lines.push(renderHeader(width, theme));
|
|
132
134
|
lines.push(renderBlankRow(inner, theme));
|
|
133
135
|
|
|
134
|
-
// Identity row: ⚠ <name> · <idShort
|
|
136
|
+
// Identity row: ⚠ <name> · <idShort>. Keep the destructive dialog
|
|
137
|
+
// width-safe even for wide workflow names.
|
|
138
|
+
const identityPrefixW = visibleWidth(" ⚠ ");
|
|
139
|
+
const identitySuffixW = visibleWidth(` · ${idShort}`);
|
|
140
|
+
const nameBudget = Math.max(1, inner - identityPrefixW - identitySuffixW);
|
|
141
|
+
const name = truncateToWidth(run.name, nameBudget, "…");
|
|
135
142
|
const identity =
|
|
136
|
-
` ${warning}\u26a0${RESET}${panelBg} ${text}${BOLD}${
|
|
143
|
+
` ${warning}\u26a0${RESET}${panelBg} ${text}${BOLD}${name}${RESET}${panelBg} ${dim}\u00b7${RESET}${panelBg} ${muted}${idShort}${RESET}`;
|
|
137
144
|
lines.push(renderTextRow(inner, theme, identity));
|
|
138
145
|
|
|
139
146
|
// Status sub-line.
|
|
@@ -152,7 +159,7 @@ export function renderKillConfirm(opts: KillConfirmRenderOpts): string[] {
|
|
|
152
159
|
lines.push(renderTextRow(
|
|
153
160
|
inner,
|
|
154
161
|
theme,
|
|
155
|
-
` ${muted}
|
|
162
|
+
` ${muted}Removes the run from live history/status.${RESET}`,
|
|
156
163
|
));
|
|
157
164
|
lines.push(renderBlankRow(inner, theme));
|
|
158
165
|
|
|
@@ -20,9 +20,10 @@
|
|
|
20
20
|
|
|
21
21
|
import type { RunSnapshot } from "../shared/store-types.js";
|
|
22
22
|
import type { GraphTheme } from "./graph-theme.js";
|
|
23
|
+
import { keyText } from "@bastani/atomic";
|
|
23
24
|
import { fmtDuration, statusIcon, statusColor } from "./status-helpers.js";
|
|
24
25
|
import { hexToAnsi, hexBg, RESET, BOLD } from "./color-utils.js";
|
|
25
|
-
import { visibleWidth } from "./text-helpers.js";
|
|
26
|
+
import { truncateToWidth, visibleWidth } from "./text-helpers.js";
|
|
26
27
|
|
|
27
28
|
// ---------------------------------------------------------------------------
|
|
28
29
|
// State + filtering
|
|
@@ -141,32 +142,32 @@ function renderHintsRow(width: number, theme: GraphTheme, state: SessionPickerSt
|
|
|
141
142
|
const text = hexToAnsi(theme.text);
|
|
142
143
|
const muted = hexToAnsi(theme.textMuted);
|
|
143
144
|
const sep = `${dim} · ${RESET}`;
|
|
145
|
+
const hint = (key: string, label: string) => `${text}${key}${RESET} ${muted}${label}${RESET}`;
|
|
144
146
|
|
|
145
|
-
const
|
|
147
|
+
const parts: string[] = state.filterFocused
|
|
146
148
|
? [
|
|
147
|
-
|
|
148
|
-
|
|
149
|
+
hint(keyText("tui.select.confirm"), "Submit"),
|
|
150
|
+
hint(keyText("tui.select.cancel"), "Exit Filter"),
|
|
149
151
|
]
|
|
150
152
|
: [
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
hint(`${keyText("tui.select.up")}/${keyText("tui.select.down")}`, "Navigate"),
|
|
154
|
+
hint(keyText("tui.select.confirm"), "Connect"),
|
|
155
|
+
hint("x", "Kill"),
|
|
156
|
+
hint("a", state.includeAll ? "Active Only" : "All"),
|
|
157
|
+
hint("/", "Filter"),
|
|
158
|
+
hint(keyText("tui.select.cancel"), "Close"),
|
|
157
159
|
];
|
|
158
160
|
|
|
159
|
-
const parts = hints.map(([k, l]) => `${text}${k}${RESET} ${muted}${l}${RESET}`);
|
|
160
161
|
// Two-space indent matches `renderEmptyState` and the section-row
|
|
161
162
|
// chrome, keeping the hint glyphs aligned with the panel interior
|
|
162
163
|
// even though they live outside the box border.
|
|
163
164
|
const line = " " + parts.join(sep);
|
|
164
|
-
//
|
|
165
|
-
//
|
|
166
|
-
|
|
167
|
-
const lineWidth = visibleWidth(
|
|
168
|
-
if (lineWidth >= width) return
|
|
169
|
-
return
|
|
165
|
+
// Keep test-time render() output width-safe even before the overlay host
|
|
166
|
+
// gets a chance to composite/truncate it.
|
|
167
|
+
const clipped = truncateToWidth(line, width, "…");
|
|
168
|
+
const lineWidth = visibleWidth(clipped);
|
|
169
|
+
if (lineWidth >= width) return clipped;
|
|
170
|
+
return clipped + " ".repeat(width - lineWidth);
|
|
170
171
|
}
|
|
171
172
|
|
|
172
173
|
function renderBlankRow(inner: number, theme: GraphTheme): string {
|
|
@@ -193,9 +194,13 @@ function renderFilterRow(inner: number, theme: GraphTheme, state: SessionPickerS
|
|
|
193
194
|
const accent = hexToAnsi(theme.accent);
|
|
194
195
|
const cursor = state.filterFocused ? `${accent}▌${RESET}${panelBg}` : "";
|
|
195
196
|
const label = state.filterFocused ? `${accent}filter` : `${muted}filter`;
|
|
197
|
+
const prefixPlain = " ▎ filter ";
|
|
198
|
+
const valueBudget = Math.max(1, inner - visibleWidth(prefixPlain) - (state.filterFocused ? 1 : 0));
|
|
199
|
+
const rawValue = state.query || "(type to filter by name or id)";
|
|
200
|
+
const shownValue = truncateToWidth(rawValue, valueBudget, "…");
|
|
196
201
|
const value = state.query
|
|
197
|
-
? `${text}${
|
|
198
|
-
: `${muted}
|
|
202
|
+
? `${text}${shownValue}${RESET}${panelBg}`
|
|
203
|
+
: `${muted}${shownValue}${RESET}${panelBg}`;
|
|
199
204
|
const content = ` ${mauve}▎${RESET}${panelBg} ${label}${RESET}${panelBg} ${value}${cursor}`;
|
|
200
205
|
return `${border}│${RESET}${panelBg}${padTo(content, inner)}${RESET}${border}│${RESET}`;
|
|
201
206
|
}
|
|
@@ -232,15 +237,21 @@ function renderRunRow(
|
|
|
232
237
|
const elapsed = fmtElapsed(run, now);
|
|
233
238
|
const progress = stageProgress(run);
|
|
234
239
|
|
|
235
|
-
// Layout columns: glyph(1) idShort(8) name(flex) elapsed(R) progress(R)
|
|
240
|
+
// Layout columns: glyph(1) idShort(8) name(flex) elapsed(R) progress(R).
|
|
241
|
+
// Name budgeting is done by visible cell width so wide workflow names
|
|
242
|
+
// cannot push the elapsed/progress columns through the right border.
|
|
236
243
|
const elapsedCol = elapsed.padStart(8, " ");
|
|
237
244
|
const progressCol = progress.padStart(10, " ");
|
|
245
|
+
const rightPlain = `${elapsedCol} ${progressCol} `;
|
|
246
|
+
const namePrefixW = visibleWidth(` ${icon} ${idShort} `);
|
|
247
|
+
const nameBudget = Math.max(1, inner - namePrefixW - visibleWidth(rightPlain) - 1);
|
|
248
|
+
const name = truncateToWidth(run.name, nameBudget, "…");
|
|
238
249
|
|
|
239
250
|
if (isSelected) {
|
|
240
251
|
const pillBg = hexBg(theme.accent);
|
|
241
252
|
const pillFg = hexToAnsi(theme.backgroundElement);
|
|
242
|
-
const left = ` ${icon} ${idShort} ${
|
|
243
|
-
const right =
|
|
253
|
+
const left = ` ${icon} ${idShort} ${name}`;
|
|
254
|
+
const right = rightPlain;
|
|
244
255
|
const gap = Math.max(1, inner - visibleWidth(left) - visibleWidth(right));
|
|
245
256
|
const content = `${left}${" ".repeat(gap)}${right}`;
|
|
246
257
|
return `${border}│${RESET}${pillBg}${pillFg}${BOLD}${padTo(content, inner)}${RESET}${border}│${RESET}`;
|
|
@@ -253,11 +264,9 @@ function renderRunRow(
|
|
|
253
264
|
const muted = hexToAnsi(theme.textMuted);
|
|
254
265
|
|
|
255
266
|
const left =
|
|
256
|
-
` ${iconColor}${icon}${RESET}${panelBg} ${dim}${idShort}${RESET}${panelBg} ${text}${
|
|
267
|
+
` ${iconColor}${icon}${RESET}${panelBg} ${dim}${idShort}${RESET}${panelBg} ${text}${name}${RESET}${panelBg}`;
|
|
257
268
|
const right = `${muted}${elapsedCol}${RESET}${panelBg} ${dim}${progressCol}${RESET}${panelBg} `;
|
|
258
|
-
const
|
|
259
|
-
const visRight = visibleWidth(elapsedCol) + 3 + visibleWidth(progressCol) + 1;
|
|
260
|
-
const gap = Math.max(1, inner - visLeft - visRight);
|
|
269
|
+
const gap = Math.max(1, inner - visibleWidth(left) - visibleWidth(right));
|
|
261
270
|
const content = `${left}${" ".repeat(gap)}${right}`;
|
|
262
271
|
return `${border}│${RESET}${panelBg}${padTo(content, inner)}${RESET}${border}│${RESET}`;
|
|
263
272
|
}
|