agent-tempo 1.7.0 → 2.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/CLAUDE.md +10 -13
  2. package/README.md +21 -15
  3. package/dashboard/dist/assets/index-BbR7zIdK.js.map +1 -1
  4. package/dashboard/package.json +1 -1
  5. package/dist/activities/hard-terminate.d.ts +2 -2
  6. package/dist/activities/hard-terminate.js +3 -9
  7. package/dist/activities/maestro.d.ts +8 -13
  8. package/dist/activities/maestro.js +3 -10
  9. package/dist/activities/outbox.js +16 -2
  10. package/dist/activities/resolve.d.ts +18 -7
  11. package/dist/activities/resolve.js +58 -46
  12. package/dist/adapters/base.js +3 -0
  13. package/dist/adapters/claude-code/adapter.js +7 -0
  14. package/dist/cli/command-center-command.js +15 -1
  15. package/dist/cli/commands.d.ts +8 -0
  16. package/dist/cli/commands.js +79 -11
  17. package/dist/cli/daemon-command.js +19 -33
  18. package/dist/cli/help-text.js +9 -7
  19. package/dist/cli/home-command.d.ts +26 -0
  20. package/dist/cli/home-command.js +156 -0
  21. package/dist/cli/removed-verbs.d.ts +0 -4
  22. package/dist/cli/removed-verbs.js +23 -12
  23. package/dist/cli/sa-preflight.d.ts +0 -14
  24. package/dist/cli/sa-preflight.js +1 -17
  25. package/dist/cli/startup.d.ts +1 -10
  26. package/dist/cli/startup.js +0 -40
  27. package/dist/cli.js +34 -80
  28. package/dist/client/core.js +13 -15
  29. package/dist/client/index.d.ts +2 -1
  30. package/dist/client/interface.d.ts +5 -14
  31. package/dist/client/with-spawn.d.ts +9 -4
  32. package/dist/client/with-spawn.js +7 -10
  33. package/dist/config.d.ts +14 -13
  34. package/dist/config.js +14 -0
  35. package/dist/constants.d.ts +50 -0
  36. package/dist/constants.js +60 -1
  37. package/dist/daemon.js +81 -0
  38. package/dist/http/auth.d.ts +3 -21
  39. package/dist/http/auth.js +10 -31
  40. package/dist/http/event-types.d.ts +38 -4
  41. package/dist/http/orphans.d.ts +3 -3
  42. package/dist/http/orphans.js +3 -3
  43. package/dist/http/server.d.ts +0 -5
  44. package/dist/http/server.js +79 -29
  45. package/dist/http/snapshot.js +3 -0
  46. package/dist/http/writes.d.ts +1 -1
  47. package/dist/http/writes.js +25 -2
  48. package/dist/observability/nondeterminism-alarm.d.ts +113 -0
  49. package/dist/observability/nondeterminism-alarm.js +162 -0
  50. package/dist/palette/index.d.ts +6 -7
  51. package/dist/palette/index.js +6 -7
  52. package/dist/pi/mission-control/actions.d.ts +67 -1
  53. package/dist/pi/mission-control/actions.js +61 -0
  54. package/dist/pi/mission-control/extension.d.ts +77 -0
  55. package/dist/pi/mission-control/extension.js +171 -0
  56. package/dist/pi/workflow-client.d.ts +14 -16
  57. package/dist/pi/workflow-client.js +18 -44
  58. package/dist/server-tools.js +30 -29
  59. package/dist/server.js +42 -0
  60. package/dist/tools/action-guard.d.ts +23 -0
  61. package/dist/tools/action-guard.js +33 -0
  62. package/dist/tools/coat-check.d.ts +20 -0
  63. package/dist/tools/coat-check.js +129 -0
  64. package/dist/tools/gate.d.ts +13 -0
  65. package/dist/tools/gate.js +88 -0
  66. package/dist/tools/schedule.d.ts +18 -0
  67. package/dist/tools/schedule.js +93 -1
  68. package/dist/tools/stage.d.ts +17 -0
  69. package/dist/tools/stage.js +85 -1
  70. package/dist/tools/state.d.ts +14 -0
  71. package/dist/tools/state.js +95 -0
  72. package/dist/types.d.ts +54 -7
  73. package/dist/upgrade/boot-guard.d.ts +95 -0
  74. package/dist/upgrade/boot-guard.js +88 -0
  75. package/dist/upgrade/from-upgrade.d.ts +95 -0
  76. package/dist/upgrade/from-upgrade.js +330 -0
  77. package/dist/upgrade/phase-engine.js +4 -1
  78. package/dist/utils/duration.d.ts +3 -6
  79. package/dist/utils/duration.js +3 -6
  80. package/dist/utils/format-hosts.d.ts +1 -1
  81. package/dist/utils/format-hosts.js +0 -2
  82. package/dist/utils/grpc-shutdown-guard.js +0 -4
  83. package/dist/utils/hosts.d.ts +4 -10
  84. package/dist/utils/hosts.js +12 -28
  85. package/dist/utils/orphan-guard.d.ts +37 -0
  86. package/dist/utils/orphan-guard.js +26 -0
  87. package/dist/utils/search-attributes.d.ts +28 -18
  88. package/dist/utils/search-attributes.js +48 -18
  89. package/dist/utils/visibility-deadline.d.ts +16 -0
  90. package/dist/utils/visibility-deadline.js +16 -0
  91. package/dist/workflows/maestro-signals.d.ts +0 -13
  92. package/dist/workflows/maestro-signals.js +6 -14
  93. package/dist/workflows/maestro.js +27 -32
  94. package/dist/workflows/scheduler.js +7 -1
  95. package/dist/workflows/session.js +237 -153
  96. package/dist/workflows/signals.d.ts +9 -1
  97. package/dist/workflows/signals.js +8 -6
  98. package/package.json +1 -6
  99. package/workflow-bundle.js +478 -225
  100. package/dist/cli/legacy-migration.d.ts +0 -35
  101. package/dist/cli/legacy-migration.js +0 -341
  102. package/dist/client/ensure-conductor-spawned.d.ts +0 -35
  103. package/dist/client/ensure-conductor-spawned.js +0 -48
  104. package/dist/tui/App.d.ts +0 -85
  105. package/dist/tui/App.js +0 -1791
  106. package/dist/tui/bootstrap-types.d.ts +0 -46
  107. package/dist/tui/bootstrap-types.js +0 -7
  108. package/dist/tui/commands.d.ts +0 -71
  109. package/dist/tui/commands.js +0 -1375
  110. package/dist/tui/components/ChatView.d.ts +0 -35
  111. package/dist/tui/components/ChatView.js +0 -54
  112. package/dist/tui/components/CommandPalette.d.ts +0 -21
  113. package/dist/tui/components/CommandPalette.js +0 -67
  114. package/dist/tui/components/ConversationStream.d.ts +0 -114
  115. package/dist/tui/components/ConversationStream.js +0 -307
  116. package/dist/tui/components/CreateEnsembleWizard.d.ts +0 -19
  117. package/dist/tui/components/CreateEnsembleWizard.js +0 -223
  118. package/dist/tui/components/DestroyConfirmModal.d.ts +0 -17
  119. package/dist/tui/components/DestroyConfirmModal.js +0 -62
  120. package/dist/tui/components/ErrorView.d.ts +0 -31
  121. package/dist/tui/components/ErrorView.js +0 -129
  122. package/dist/tui/components/HomeView.d.ts +0 -54
  123. package/dist/tui/components/HomeView.js +0 -306
  124. package/dist/tui/components/LoadLineupModal.d.ts +0 -18
  125. package/dist/tui/components/LoadLineupModal.js +0 -79
  126. package/dist/tui/components/MainView.d.ts +0 -21
  127. package/dist/tui/components/MainView.js +0 -107
  128. package/dist/tui/components/NewEnsembleModal.d.ts +0 -9
  129. package/dist/tui/components/NewEnsembleModal.js +0 -73
  130. package/dist/tui/components/Picker.d.ts +0 -23
  131. package/dist/tui/components/Picker.js +0 -70
  132. package/dist/tui/components/PlayerDetailView.d.ts +0 -26
  133. package/dist/tui/components/PlayerDetailView.js +0 -118
  134. package/dist/tui/components/PromptArea.d.ts +0 -50
  135. package/dist/tui/components/PromptArea.js +0 -303
  136. package/dist/tui/components/RecruitWizard.d.ts +0 -17
  137. package/dist/tui/components/RecruitWizard.js +0 -221
  138. package/dist/tui/components/RestoreConfirmModal.d.ts +0 -18
  139. package/dist/tui/components/RestoreConfirmModal.js +0 -71
  140. package/dist/tui/components/ScheduleWizard.d.ts +0 -19
  141. package/dist/tui/components/ScheduleWizard.js +0 -259
  142. package/dist/tui/components/Splash.d.ts +0 -23
  143. package/dist/tui/components/Splash.js +0 -221
  144. package/dist/tui/components/StatusBar.d.ts +0 -48
  145. package/dist/tui/components/StatusBar.js +0 -128
  146. package/dist/tui/components/StatusOverlay.d.ts +0 -15
  147. package/dist/tui/components/StatusOverlay.js +0 -76
  148. package/dist/tui/components/TitleBar.d.ts +0 -10
  149. package/dist/tui/components/TitleBar.js +0 -21
  150. package/dist/tui/index.d.ts +0 -15
  151. package/dist/tui/index.js +0 -162
  152. package/dist/tui/ink-context.d.ts +0 -18
  153. package/dist/tui/ink-context.js +0 -59
  154. package/dist/tui/ink-loader.d.ts +0 -26
  155. package/dist/tui/ink-loader.js +0 -42
  156. package/dist/tui/removed-commands.d.ts +0 -9
  157. package/dist/tui/removed-commands.js +0 -22
  158. package/dist/tui/sse-handler.d.ts +0 -52
  159. package/dist/tui/sse-handler.js +0 -157
  160. package/dist/tui/store.d.ts +0 -598
  161. package/dist/tui/store.js +0 -753
  162. package/dist/tui/utils/format.d.ts +0 -56
  163. package/dist/tui/utils/format.js +0 -155
  164. package/dist/tui/utils/fullscreen.d.ts +0 -23
  165. package/dist/tui/utils/fullscreen.js +0 -71
  166. package/dist/tui/utils/history.d.ts +0 -10
  167. package/dist/tui/utils/history.js +0 -85
  168. package/dist/tui/utils/platform.d.ts +0 -45
  169. package/dist/tui/utils/platform.js +0 -258
  170. package/dist/tui/utils/theme.d.ts +0 -21
  171. package/dist/tui/utils/theme.js +0 -24
@@ -1,221 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.Splash = Splash;
37
- /**
38
- * Splash screen — landing/home screen with animated metronome, connection
39
- * status, and ensemble picker.
40
- *
41
- * Uses a single Text element with nested virtual-text nodes to minimize
42
- * Yoga layout nodes (target: <10 total).
43
- */
44
- const react_1 = __importStar(require("react"));
45
- const ink_context_1 = require("../ink-context");
46
- const platform_1 = require("../utils/platform");
47
- const theme_1 = require("../utils/theme");
48
- const SPINNER_FRAMES = ['\u280B', '\u2819', '\u2839', '\u2838', '\u283C', '\u2834', '\u2826', '\u2827', '\u2807', '\u280F'];
49
- const PING_PONG = [0, 1, 2, 1];
50
- const MAX_ENSEMBLES_SHOWN = 5;
51
- function Splash({ status, version, connected, ensembles, onContinue, onCreateEnsemble }) {
52
- const { Text, useInput } = (0, ink_context_1.useInk)();
53
- const [metronomeTick, setMetronomeTick] = (0, react_1.useState)(0);
54
- const [spinnerTick, setSpinnerTick] = (0, react_1.useState)(0);
55
- const [selectedIdx, setSelectedIdx] = (0, react_1.useState)(0);
56
- const brailleFrames = (0, react_1.useMemo)(() => (0, platform_1.metronomeBrailleFrames)(), []);
57
- const ensembleCount = ensembles?.length ?? 0;
58
- // Total selectable items: ensembles + "create new" item (when loaded)
59
- const totalItems = ensembles !== undefined ? ensembleCount + 1 : (ensembleCount || 1);
60
- const hasNavigation = totalItems > 1;
61
- const isCreateSelected = ensembles !== undefined && selectedIdx === ensembleCount;
62
- // Handle keys: ↑↓ to select, Enter to continue/create
63
- const inputRef = react_1.default.useRef({ connected, onContinue, onCreateEnsemble, ensembles, selectedIdx, isCreateSelected, totalItems });
64
- inputRef.current = { connected, onContinue, onCreateEnsemble, ensembles, selectedIdx, isCreateSelected, totalItems };
65
- useInput(react_1.default.useCallback((_input, key) => {
66
- const r = inputRef.current;
67
- if (!r.connected)
68
- return;
69
- if (key.return) {
70
- if (r.isCreateSelected) {
71
- r.onCreateEnsemble?.();
72
- }
73
- else {
74
- const selected = r.ensembles?.[r.selectedIdx]?.name;
75
- r.onContinue?.(selected);
76
- }
77
- return;
78
- }
79
- if (key.upArrow) {
80
- setSelectedIdx(i => Math.max(0, i - 1));
81
- return;
82
- }
83
- if (key.downArrow) {
84
- setSelectedIdx(i => Math.min(r.totalItems - 1, i + 1));
85
- return;
86
- }
87
- }, []));
88
- // Metronome animation — cleanup stops timer on unmount/transition
89
- (0, react_1.useEffect)(() => {
90
- const timer = setInterval(() => {
91
- setMetronomeTick((t) => (t + 1) % PING_PONG.length);
92
- }, 300);
93
- return () => clearInterval(timer);
94
- }, []);
95
- // Spinner animation — stops once connected
96
- (0, react_1.useEffect)(() => {
97
- if (connected)
98
- return;
99
- const timer = setInterval(() => {
100
- setSpinnerTick((t) => (t + 1) % SPINNER_FRAMES.length);
101
- }, 80);
102
- return () => clearInterval(timer);
103
- }, [connected]);
104
- // ── Metronome frame (needed for line count) ──
105
- const frameIndex = PING_PONG[metronomeTick];
106
- const frame = brailleFrames[frameIndex];
107
- // ── Centering calculations ──
108
- const cols = process.stdout.columns || 80;
109
- const rows = process.stdout.rows || 24;
110
- /** Center a string horizontally based on its visible width. */
111
- const center = (text) => {
112
- const pad = Math.max(0, Math.floor((cols - text.length) / 2));
113
- return ' '.repeat(pad) + text;
114
- };
115
- // Count actual content lines for accurate vertical centering
116
- const metroLines = frame.length; // ~10 lines
117
- const titleLines = 5; // 2 blank + title + tagline + version
118
- const statusLines = 3; // 2 blank + status line
119
- const ensembleLines = connected && ensembles !== undefined
120
- ? 1 + Math.min(ensembleCount, MAX_ENSEMBLES_SHOWN) + 1 + (ensembleCount === 0 ? 1 : 0) // gap + items + create + optional "none"
121
- : (connected ? 3 : 0); // loading or not connected
122
- const promptLines = 3; // 2 blank + prompt
123
- const contentHeight = metroLines + titleLines + statusLines + ensembleLines + promptLines;
124
- const vPad = Math.max(0, Math.floor((rows - contentHeight - 3) / 2));
125
- // ── Build single Text element with all content as nested virtual-text ──
126
- const children = [];
127
- // Vertical centering
128
- for (let i = 0; i < vPad; i++)
129
- children.push('\n');
130
- // Metronome logo (braille characters as nested Text — 0 Yoga nodes)
131
- for (let li = 0; li < frame.length; li++) {
132
- if (li > 0)
133
- children.push('\n');
134
- const lineWidth = frame[li].reduce((w, seg) => w + seg.char.length, 0);
135
- const metroPad = ' '.repeat(Math.max(0, Math.floor((cols - lineWidth) / 2)));
136
- children.push(metroPad);
137
- for (let si = 0; si < frame[li].length; si++) {
138
- const seg = frame[li][si];
139
- children.push(react_1.default.createElement(Text, { key: `m-${li}-${si}`, color: seg.color || undefined }, seg.char));
140
- }
141
- }
142
- // Title + tagline + version
143
- children.push('\n\n');
144
- children.push(react_1.default.createElement(Text, { key: 'title', bold: true, color: theme_1.THEME.accent }, center('agent-tempo')));
145
- children.push('\n');
146
- children.push(react_1.default.createElement(Text, { key: 'tagline', color: theme_1.THEME.dim }, center('Multi-session orchestration via Temporal')));
147
- children.push('\n');
148
- children.push(react_1.default.createElement(Text, { key: 'version', color: theme_1.THEME.muted }, center(`v${version}`)));
149
- // Connection status
150
- children.push('\n\n');
151
- if (connected) {
152
- children.push(react_1.default.createElement(Text, { key: 'status', color: theme_1.THEME.success }, center('\u2713 Connected')));
153
- }
154
- else {
155
- children.push(react_1.default.createElement(Text, { key: 'status', color: theme_1.THEME.warning }, center(`${SPINNER_FRAMES[spinnerTick]} ${status}`)));
156
- }
157
- // Ensemble list + create option (when connected)
158
- if (connected && ensembles !== undefined) {
159
- children.push('\n');
160
- if (ensembles.length > 0) {
161
- let startIdx = 0;
162
- if (ensembles.length > MAX_ENSEMBLES_SHOWN) {
163
- startIdx = Math.max(0, Math.min(selectedIdx - Math.floor(MAX_ENSEMBLES_SHOWN / 2), ensembles.length - MAX_ENSEMBLES_SHOWN));
164
- }
165
- const visible = ensembles.slice(startIdx, startIdx + MAX_ENSEMBLES_SHOWN);
166
- if (startIdx > 0) {
167
- children.push('\n');
168
- children.push(react_1.default.createElement(Text, { key: 'sup', color: theme_1.THEME.dim }, center(`\u2191 ${startIdx} more`)));
169
- }
170
- for (let i = 0; i < visible.length; i++) {
171
- const ens = visible[i];
172
- const actualIdx = startIdx + i;
173
- const isSelected = actualIdx === selectedIdx;
174
- const icon = ens.hasConductor ? '\u2605' : '\u2022';
175
- const indicator = isSelected ? '\u25B8 ' : ' ';
176
- children.push('\n');
177
- children.push(react_1.default.createElement(Text, {
178
- key: `ens-${ens.name}`,
179
- color: isSelected ? theme_1.THEME.accent : theme_1.THEME.textMuted,
180
- bold: isSelected,
181
- }, center(`${indicator}${icon} ${ens.name} (${ens.playerCount} player${ens.playerCount !== 1 ? 's' : ''})`)));
182
- }
183
- if (startIdx + MAX_ENSEMBLES_SHOWN < ensembles.length) {
184
- children.push('\n');
185
- children.push(react_1.default.createElement(Text, { key: 'sdn', color: theme_1.THEME.dim }, center(`\u2193 ${ensembles.length - startIdx - MAX_ENSEMBLES_SHOWN} more`)));
186
- }
187
- }
188
- else {
189
- // Loaded but empty
190
- children.push('\n');
191
- children.push(react_1.default.createElement(Text, { key: 'none', color: theme_1.THEME.dim }, center('No ensembles running.')));
192
- }
193
- // "+ Create new ensemble" — always selectable
194
- children.push('\n');
195
- const createIndicator = isCreateSelected ? '\u25B8 ' : ' ';
196
- children.push(react_1.default.createElement(Text, {
197
- key: 'create',
198
- color: isCreateSelected ? theme_1.THEME.accent : theme_1.THEME.dim,
199
- bold: isCreateSelected,
200
- }, center(`${createIndicator}+ Create new ensemble`)));
201
- }
202
- else if (connected) {
203
- // Connected but ensembles not yet loaded
204
- children.push('\n\n');
205
- children.push(react_1.default.createElement(Text, { key: 'loading', color: theme_1.THEME.dim }, center('\u27F3 Discovering ensembles...')));
206
- }
207
- // Bottom prompt
208
- children.push('\n\n');
209
- if (connected) {
210
- children.push(react_1.default.createElement(Text, { key: 'prompt', bold: true, color: theme_1.THEME.accent }, ensembles === undefined
211
- ? center('Press Ctrl+C to exit')
212
- : hasNavigation
213
- ? center('\u2191\u2193 to select, Enter to continue')
214
- : center('Press Enter to continue')));
215
- }
216
- else {
217
- children.push(react_1.default.createElement(Text, { key: 'prompt', color: theme_1.THEME.muted }, center('Press Ctrl+C to cancel')));
218
- }
219
- // Single Text element wrapping everything (1 Yoga node)
220
- return react_1.default.createElement(Text, null, ...children);
221
- }
@@ -1,48 +0,0 @@
1
- /**
2
- * StatusBar — persistent one-line status summary.
3
- * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
4
- */
5
- import React from 'react';
6
- import type { MaestroPlayerInfo } from '../../types';
7
- export interface StatusBarProps {
8
- ensemble: string | null;
9
- players: MaestroPlayerInfo[];
10
- /** True after the first player poll completes. False = still loading. */
11
- playersLoaded: boolean;
12
- scheduleCount: number;
13
- connected: boolean;
14
- /**
15
- * Bug B: Whether the active ensemble's maestro hub is paused. Drives a
16
- * yellow "paused" segment so users see why a conductor is silently
17
- * swallowing typed messages (the session-level `paused` flag gates the
18
- * outbox dispatcher).
19
- */
20
- ensemblePaused?: boolean;
21
- /**
22
- * #306 follow-up: Whether at least one session in the active ensemble
23
- * has its outbox locked (`held`). Drives a yellow "held" segment.
24
- * Independent of `ensemblePaused` because `/load_lineup` flips both
25
- * flags at once but `/play` only clears pause — users would otherwise
26
- * see "no paused indicator" and assume the ensemble is fully resumed
27
- * when held players were still frozen behind the locked outbox.
28
- */
29
- ensembleHeld?: boolean;
30
- }
31
- /**
32
- * One rendered text segment of the status bar. Returned by
33
- * {@link buildStatusBarSegments} so tests can inspect the bar's contents
34
- * without spinning up Ink. Each segment becomes a nested ink-virtual-text
35
- * inside the single outer Text element.
36
- */
37
- export interface StatusBarSegment {
38
- key: string;
39
- color: string;
40
- text: string;
41
- }
42
- /**
43
- * Pure helper: compute the StatusBar's segment list from props. Keeps the
44
- * render-path logic testable without an Ink context. The component below
45
- * just maps each segment to a `<Text>` element.
46
- */
47
- export declare function buildStatusBarSegments(props: StatusBarProps): StatusBarSegment[];
48
- export declare function StatusBar(props: StatusBarProps): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
@@ -1,128 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.buildStatusBarSegments = buildStatusBarSegments;
7
- exports.StatusBar = StatusBar;
8
- /**
9
- * StatusBar — persistent one-line status summary.
10
- * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
11
- */
12
- const react_1 = __importDefault(require("react"));
13
- const ink_context_1 = require("../ink-context");
14
- const theme_1 = require("../utils/theme");
15
- const format_1 = require("../utils/format");
16
- /**
17
- * Pure helper: compute the StatusBar's segment list from props. Keeps the
18
- * render-path logic testable without an Ink context. The component below
19
- * just maps each segment to a `<Text>` element.
20
- */
21
- function buildStatusBarSegments(props) {
22
- const { ensemble, players, playersLoaded, scheduleCount, connected, ensemblePaused, ensembleHeld } = props;
23
- const healthColor = connected ? theme_1.THEME.success : theme_1.THEME.error;
24
- const healthDot = connected ? '●' : '○';
25
- const healthLabel = connected ? 'Connected' : 'Disconnected';
26
- const ensembleLabel = ensemble || 'no ensemble';
27
- const segments = [
28
- { key: 'lead', color: theme_1.THEME.dim, text: ' ' },
29
- { key: 'ens', color: ensemble ? theme_1.THEME.accent : theme_1.THEME.dim, text: ensembleLabel },
30
- { key: 's1', color: theme_1.THEME.dim, text: ' · ' },
31
- ];
32
- if (ensemble && !playersLoaded) {
33
- // Still loading — don't show incorrect counts
34
- segments.push({ key: 'pl', color: theme_1.THEME.dim, text: 'Loading...' });
35
- }
36
- else {
37
- // Exclude the maestro session from headline counts — it is the TUI's own
38
- // dashboard attachment, not a peer agent. The full list (including the
39
- // maestro) is still surfaced in `/players` and the status overlay so the
40
- // user can see internal state honestly.
41
- const realPlayers = (0, format_1.filterRealPlayers)(players);
42
- // Player breakdown by phase label (Option-B five buckets collapsed to four
43
- // meaningful ones for the bar — `gone` players are terminal and not
44
- // shown in the ensemble list).
45
- let active = 0;
46
- let idle = 0;
47
- let disconnected = 0;
48
- let pending = 0;
49
- for (const p of realPlayers) {
50
- switch ((0, format_1.phaseToLabel)(p.phase)) {
51
- case 'active':
52
- active++;
53
- break;
54
- case 'idle':
55
- idle++;
56
- break;
57
- case 'disconnected':
58
- disconnected++;
59
- break;
60
- case 'pending':
61
- pending++;
62
- break;
63
- // 'gone' / 'unknown' intentionally not counted in the summary line.
64
- }
65
- }
66
- const parts = [];
67
- if (active > 0)
68
- parts.push(`${active} active`);
69
- if (idle > 0)
70
- parts.push(`${idle} idle`);
71
- if (disconnected > 0)
72
- parts.push(`${disconnected} disconnected`);
73
- if (pending > 0)
74
- parts.push(`${pending} pending`);
75
- const breakdown = parts.length > 0 ? ` (${parts.join(', ')})` : '';
76
- const playerLabel = `${realPlayers.length} player${realPlayers.length !== 1 ? 's' : ''}${breakdown}`;
77
- segments.push({ key: 'pl', color: theme_1.THEME.dim, text: playerLabel });
78
- if (scheduleCount > 0) {
79
- segments.push({ key: 's2', color: theme_1.THEME.dim, text: ' · ' }, { key: 'sc', color: theme_1.THEME.dim, text: `${scheduleCount} schedule${scheduleCount !== 1 ? 's' : ''}` });
80
- }
81
- // Bug B + #306 follow-up: yellow `paused`/`held`/`paused + held` segment
82
- // when the maestro hub is paused or any session has its outbox locked
83
- // (or both — `/load_lineup` flips both flags at once). Placed before
84
- // the "No conductor" warning so the most actionable state reads first
85
- // when both apply. The same guard (`ensemble && …`) keeps the segment
86
- // off the home view.
87
- //
88
- // Combined-glyph variant for paused + held picks `⏸⊕ paused + held`
89
- // over two separate segments — scans cleaner at terminal density and
90
- // lets the matching tip below the input ("Tip: type /play to unpause
91
- // + /go to release held players.") read as one instruction.
92
- if (ensemble && (ensemblePaused || ensembleHeld)) {
93
- let label;
94
- if (ensemblePaused && ensembleHeld) {
95
- label = '⏸⊕ paused + held';
96
- }
97
- else if (ensemblePaused) {
98
- // U+23F8 PAUSE SYMBOL — single glyph, mirrors the U+26A0 warning below.
99
- label = '⏸ paused';
100
- }
101
- else {
102
- // U+2295 CIRCLED PLUS — distinct from pause, suggests "more buffered".
103
- label = '⊕ held';
104
- }
105
- segments.push({ key: 'sp', color: theme_1.THEME.dim, text: ' · ' }, { key: 'pa', color: theme_1.THEME.warning, text: label });
106
- }
107
- // #358: derive from `players` (single source of truth) so the badge
108
- // updates on incremental SSE events (`player.added`/`player.removed`)
109
- // without waiting for the next snapshot. Pre-#358 this depended on a
110
- // separate `conductorName` cache populated only by the snapshot path,
111
- // so a `/destroy conductor` mid-session left "No conductor" stuck off
112
- // until the next snapshot intervened.
113
- if (ensemble && !players.some(p => p.isConductor)) {
114
- segments.push({ key: 's3', color: theme_1.THEME.dim, text: ' · ' }, { key: 'nc', color: theme_1.THEME.warning, text: '⚠ No conductor' });
115
- }
116
- }
117
- segments.push({ key: 's4', color: theme_1.THEME.dim, text: ' · ' }, { key: 'hd', color: healthColor, text: healthDot }, { key: 'hl', color: theme_1.THEME.dim, text: ` ${healthLabel}` });
118
- return segments;
119
- }
120
- function StatusBar(props) {
121
- const { Text } = (0, ink_context_1.useInk)();
122
- const segments = buildStatusBarSegments(props);
123
- // Single Text element — all children are ink-virtual-text (0 Yoga nodes)
124
- const children = segments.map((s) => s.key === 'lead'
125
- ? s.text
126
- : react_1.default.createElement(Text, { key: s.key, color: s.color }, s.text));
127
- return react_1.default.createElement(Text, null, ...children);
128
- }
@@ -1,15 +0,0 @@
1
- /**
2
- * StatusOverlay — dismissible overlay showing ensemble player cards.
3
- *
4
- * Performance: Single <Text> root with nested virtual-text children.
5
- * Zero Yoga <Box> nodes.
6
- */
7
- import React from 'react';
8
- import type { MaestroPlayerInfo } from '../../types';
9
- export interface StatusOverlayProps {
10
- players: MaestroPlayerInfo[];
11
- ensemble: string;
12
- scrollOffset: number;
13
- contentHeight: number;
14
- }
15
- export declare function StatusOverlay({ players, ensemble, scrollOffset, contentHeight }: StatusOverlayProps): React.CElement<{}, React.Component<{}, any, any>>;
@@ -1,76 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.StatusOverlay = StatusOverlay;
7
- /**
8
- * StatusOverlay — dismissible overlay showing ensemble player cards.
9
- *
10
- * Performance: Single <Text> root with nested virtual-text children.
11
- * Zero Yoga <Box> nodes.
12
- */
13
- const react_1 = __importDefault(require("react"));
14
- const ink_context_1 = require("../ink-context");
15
- const theme_1 = require("../utils/theme");
16
- const format_1 = require("../utils/format");
17
- const platform_1 = require("../utils/platform");
18
- function StatusOverlay({ players, ensemble, scrollOffset, contentHeight }) {
19
- const { Text } = (0, ink_context_1.useInk)();
20
- const icons = (0, platform_1.statusIcons)((0, platform_1.supportsUnicode)());
21
- const cols = process.stdout.columns || 80;
22
- const indent = 4;
23
- const maxWidth = Math.max(20, cols - indent);
24
- const wrap = (text) => {
25
- if (text.length <= maxWidth)
26
- return text;
27
- const prefix = ' '.repeat(indent);
28
- const chunks = [];
29
- let rem = text;
30
- while (rem.length > maxWidth) {
31
- let brk = rem.lastIndexOf(' ', maxWidth);
32
- if (brk <= 0)
33
- brk = maxWidth;
34
- chunks.push(rem.slice(0, brk));
35
- rem = rem.slice(brk).trimStart();
36
- }
37
- if (rem)
38
- chunks.push(rem);
39
- return chunks.join('\n' + prefix);
40
- };
41
- const maxVisible = Math.max(2, Math.floor((contentHeight - 3) / 4));
42
- const clampedOffset = Math.min(scrollOffset, Math.max(0, players.length - maxVisible));
43
- const visiblePlayers = players.slice(clampedOffset, clampedOffset + maxVisible);
44
- const children = [];
45
- children.push(react_1.default.createElement(Text, { key: 'h', bold: true, color: theme_1.THEME.accent }, ` Ensemble: ${ensemble} (${players.length} player${players.length !== 1 ? 's' : ''})`));
46
- if (clampedOffset > 0) {
47
- children.push('\n');
48
- children.push(react_1.default.createElement(Text, { key: 'sup', color: theme_1.THEME.dim }, ` \u2191 ${clampedOffset} more above`));
49
- }
50
- for (const p of visiblePlayers) {
51
- // Attachment-phase → icon/color lookup (post-#177 Option-B mapping).
52
- const icon = icons[(0, format_1.phaseToIconName)(p.phase)];
53
- const iconColor = (0, format_1.phaseToColor)(p.phase);
54
- const conductor = p.isConductor ? ' \u2605' : '';
55
- children.push('\n\n');
56
- children.push(react_1.default.createElement(react_1.default.Fragment, { key: `${p.playerId}-1` }, react_1.default.createElement(Text, { color: iconColor }, ` ${icon} `), react_1.default.createElement(Text, { bold: true, color: theme_1.THEME.text }, p.playerId), conductor ? react_1.default.createElement(Text, { color: theme_1.THEME.warning }, conductor) : null));
57
- const details = [(0, format_1.phaseToLabel)(p.phase)];
58
- if (p.gitBranch)
59
- details.push(p.gitBranch);
60
- if (p.playerType || p.agentType)
61
- details.push(p.playerType || p.agentType || '');
62
- children.push('\n');
63
- children.push(react_1.default.createElement(Text, { key: `${p.playerId}-2`, color: theme_1.THEME.dim }, ` ${wrap(details.join(' \u00B7 '))}`));
64
- if (p.part) {
65
- children.push('\n');
66
- children.push(react_1.default.createElement(Text, { key: `${p.playerId}-3`, color: theme_1.THEME.textMuted }, ` ${wrap(p.part)}`));
67
- }
68
- }
69
- if (clampedOffset + maxVisible < players.length) {
70
- children.push('\n\n');
71
- children.push(react_1.default.createElement(Text, { key: 'sdn', color: theme_1.THEME.dim }, ` \u2193 ${players.length - clampedOffset - maxVisible} more below`));
72
- }
73
- children.push('\n\n');
74
- children.push(react_1.default.createElement(Text, { key: 'hint', color: theme_1.THEME.dim }, ' \u2191\u2193 scroll, Esc to dismiss'));
75
- return react_1.default.createElement(Text, null, ...children);
76
- }
@@ -1,10 +0,0 @@
1
- /**
2
- * TitleBar — pinned top bar for the TUI shell.
3
- * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
4
- */
5
- import React from 'react';
6
- export interface TitleBarProps {
7
- /** Context text displayed on the right side. */
8
- context: string;
9
- }
10
- export declare function TitleBar({ context }: TitleBarProps): React.DetailedReactHTMLElement<React.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>;
@@ -1,21 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.TitleBar = TitleBar;
7
- /**
8
- * TitleBar — pinned top bar for the TUI shell.
9
- * Renders as a SINGLE Text element (1 Yoga node). Nested Text = ink-virtual-text (0 nodes).
10
- */
11
- const react_1 = __importDefault(require("react"));
12
- const ink_context_1 = require("../ink-context");
13
- const theme_1 = require("../utils/theme");
14
- function TitleBar({ context }) {
15
- const { Text } = (0, ink_context_1.useInk)();
16
- const cols = process.stdout.columns || 80;
17
- const left = 'agent-tempo';
18
- // Pad between left and right to push context to the right edge
19
- const padding = Math.max(1, cols - left.length - context.length - 4); // -4 for paddingX
20
- return react_1.default.createElement(Text, null, ' ', react_1.default.createElement(Text, { bold: true, color: theme_1.THEME.accent }, left), ' '.repeat(padding), react_1.default.createElement(Text, { color: theme_1.THEME.dim }, context));
21
- }
@@ -1,15 +0,0 @@
1
- import { Config } from '../config';
2
- import type { BootstrapResult } from '../cli/startup';
3
- export interface TuiOpts {
4
- config: Config;
5
- /** If provided, start in single-ensemble view. If omitted, start in home (multi-ensemble) view. */
6
- ensemble?: string;
7
- /**
8
- * #289: pre-computed bootstrap result fed in from the CLI default path.
9
- * When present, the TUI skips its own daemon/connection probing and
10
- * hands the result straight to HomeView as initial props (S5 / #290).
11
- * Absent for the subcommand paths that don't run bootstrap.
12
- */
13
- bootstrap?: BootstrapResult;
14
- }
15
- export declare function run(opts: TuiOpts): Promise<void>;