@h-rig/cli 0.0.6-alpha.83 → 0.0.6-alpha.84
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/dist/bin/rig.js +22085 -14618
- package/dist/src/app/board.js +155 -28
- package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
- package/dist/src/app-opentui/adapters/doctor.js +1 -25
- package/dist/src/app-opentui/adapters/family.d.ts +62 -0
- package/dist/src/app-opentui/adapters/family.js +14305 -0
- package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
- package/dist/src/app-opentui/adapters/fleet.js +6 -40
- package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
- package/dist/src/app-opentui/adapters/inbox.js +54 -59
- package/dist/src/app-opentui/adapters/init.d.ts +0 -2
- package/dist/src/app-opentui/adapters/init.js +0 -26
- package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
- package/dist/src/app-opentui/adapters/inspect.js +1024 -0
- package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
- package/dist/src/app-opentui/adapters/pi-attach.js +348 -93
- package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
- package/dist/src/app-opentui/adapters/pi.js +363 -0
- package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
- package/dist/src/app-opentui/adapters/plugin.js +544 -0
- package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
- package/dist/src/app-opentui/adapters/repo.js +186 -0
- package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
- package/dist/src/app-opentui/adapters/run-detail.js +97 -44
- package/dist/src/app-opentui/adapters/server.d.ts +10 -2
- package/dist/src/app-opentui/adapters/server.js +96 -27
- package/dist/src/app-opentui/adapters/tasks.d.ts +0 -2
- package/dist/src/app-opentui/adapters/tasks.js +437 -105
- package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
- package/dist/src/app-opentui/adapters/workspace.js +333 -0
- package/dist/src/app-opentui/autocomplete.d.ts +20 -0
- package/dist/src/app-opentui/autocomplete.js +576 -0
- package/dist/src/app-opentui/bootstrap.js +24296 -16919
- package/dist/src/app-opentui/command-palette.d.ts +3 -0
- package/dist/src/app-opentui/command-palette.js +1010 -0
- package/dist/src/app-opentui/drone.js +8 -6
- package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
- package/dist/src/app-opentui/fleet-stats.js +114 -0
- package/dist/src/app-opentui/index.js +3438 -1724
- package/dist/src/app-opentui/intent.js +71 -48
- package/dist/src/app-opentui/keymap.d.ts +6 -5
- package/dist/src/app-opentui/keymap.js +1064 -23
- package/dist/src/app-opentui/layout.d.ts +7 -0
- package/dist/src/app-opentui/layout.js +13 -6
- package/dist/src/app-opentui/list-search.d.ts +24 -0
- package/dist/src/app-opentui/list-search.js +88 -1
- package/dist/src/app-opentui/pi-host-child.js +33 -1
- package/dist/src/app-opentui/pi-pty-host.d.ts +5 -0
- package/dist/src/app-opentui/pi-pty-host.js +21 -3
- package/dist/src/app-opentui/react/App.d.ts +9 -0
- package/dist/src/app-opentui/react/App.js +5144 -0
- package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
- package/dist/src/app-opentui/react/Backdrop.js +1834 -0
- package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
- package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
- package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
- package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
- package/dist/src/app-opentui/react/context.d.ts +17 -0
- package/dist/src/app-opentui/react/context.js +37 -0
- package/dist/src/app-opentui/react/launch.d.ts +2 -0
- package/dist/src/app-opentui/react/launch.js +5743 -0
- package/dist/src/app-opentui/react/nav.d.ts +18 -0
- package/dist/src/app-opentui/react/nav.js +54 -0
- package/dist/src/app-opentui/react/scroll.d.ts +12 -0
- package/dist/src/app-opentui/react/scroll.js +21 -0
- package/dist/src/app-opentui/react/syntax.d.ts +2 -0
- package/dist/src/app-opentui/react/syntax.js +64 -0
- package/dist/src/app-opentui/registry.js +19923 -5151
- package/dist/src/app-opentui/render/constants.d.ts +31 -0
- package/dist/src/app-opentui/render/constants.js +66 -0
- package/dist/src/app-opentui/render/graphics.d.ts +2 -1
- package/dist/src/app-opentui/render/graphics.js +106 -39
- package/dist/src/app-opentui/render/image-visual-layer-worker.js +108 -20
- package/dist/src/app-opentui/render/image-visual-layer.d.ts +7 -0
- package/dist/src/app-opentui/render/image-visual-layer.js +109 -20
- package/dist/src/app-opentui/render/native-host.d.ts +37 -0
- package/dist/src/app-opentui/render/native-host.js +179 -0
- package/dist/src/app-opentui/render/panels.js +18 -11
- package/dist/src/app-opentui/render/preloader.js +8 -6
- package/dist/src/app-opentui/render/scene.d.ts +50 -1
- package/dist/src/app-opentui/render/scene.js +183 -6
- package/dist/src/app-opentui/render/text.d.ts +7 -1
- package/dist/src/app-opentui/render/text.js +10 -7
- package/dist/src/app-opentui/render/type-bar.js +69 -30
- package/dist/src/app-opentui/runtime.d.ts +44 -1
- package/dist/src/app-opentui/runtime.js +3231 -1363
- package/dist/src/app-opentui/scenes/command.js +20 -6
- package/dist/src/app-opentui/scenes/doctor.js +176 -11
- package/dist/src/app-opentui/scenes/error.js +20 -10
- package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
- package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
- package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
- package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
- package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
- package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
- package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
- package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
- package/dist/src/app-opentui/scenes/family.d.ts +3 -0
- package/dist/src/app-opentui/scenes/family.js +2144 -0
- package/dist/src/app-opentui/scenes/fleet.js +521 -31
- package/dist/src/app-opentui/scenes/handoff.js +204 -12
- package/dist/src/app-opentui/scenes/help.js +609 -40
- package/dist/src/app-opentui/scenes/inbox.js +278 -17
- package/dist/src/app-opentui/scenes/init.js +84 -39
- package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
- package/dist/src/app-opentui/scenes/inspect.js +793 -0
- package/dist/src/app-opentui/scenes/main.js +218 -39
- package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
- package/dist/src/app-opentui/scenes/pi.js +508 -0
- package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
- package/dist/src/app-opentui/scenes/plugin.js +486 -0
- package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
- package/dist/src/app-opentui/scenes/repo.js +424 -0
- package/dist/src/app-opentui/scenes/run-detail.js +333 -20
- package/dist/src/app-opentui/scenes/server.js +181 -15
- package/dist/src/app-opentui/scenes/tasks.js +486 -31
- package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
- package/dist/src/app-opentui/scenes/workspace.js +426 -0
- package/dist/src/app-opentui/selectable.d.ts +19 -0
- package/dist/src/app-opentui/selectable.js +79 -0
- package/dist/src/app-opentui/state.js +83 -30
- package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
- package/dist/src/app-opentui/surface-catalog.js +540 -0
- package/dist/src/app-opentui/theme.d.ts +28 -6
- package/dist/src/app-opentui/theme.js +61 -8
- package/dist/src/app-opentui/types.d.ts +121 -4
- package/dist/src/commands/_authority-runs.d.ts +1 -1
- package/dist/src/commands/_authority-runs.js +2 -12
- package/dist/src/commands/_help-catalog.js +95 -15
- package/dist/src/commands/_operator-view.js +34 -2
- package/dist/src/commands/_pi-frontend.d.ts +2 -0
- package/dist/src/commands/_pi-frontend.js +34 -0
- package/dist/src/commands/_server-events.d.ts +26 -0
- package/dist/src/commands/_server-events.js +310 -0
- package/dist/src/commands/agent.js +2 -12
- package/dist/src/commands/run.js +34 -2
- package/dist/src/commands/server.js +2 -12
- package/dist/src/commands/stats.js +95 -15
- package/dist/src/commands/task-run-driver.js +2 -12
- package/dist/src/commands/task.js +131 -29
- package/dist/src/commands.js +192 -31
- package/dist/src/index.js +192 -31
- package/package.json +11 -9
|
@@ -8,7 +8,14 @@ export type StageLayout = {
|
|
|
8
8
|
readonly typeBarTop: number;
|
|
9
9
|
readonly footerTop: number;
|
|
10
10
|
readonly compact: boolean;
|
|
11
|
+
/** Raw terminal is below the usable threshold; render a guidance message
|
|
12
|
+
* instead of a scene that would clip into nothing (#18). */
|
|
13
|
+
readonly tooSmall: boolean;
|
|
11
14
|
};
|
|
15
|
+
/** Below these raw dimensions, ad-terminal panels collapse below their 4×4
|
|
16
|
+
* floor and the UI would blank silently. We show a "resize me" card instead. */
|
|
17
|
+
export declare const MIN_TERMINAL_WIDTH = 48;
|
|
18
|
+
export declare const MIN_TERMINAL_HEIGHT = 16;
|
|
12
19
|
export declare function computeStageLayout(width: number, height: number): StageLayout;
|
|
13
20
|
export declare function visibleWidth(text: string): number;
|
|
14
21
|
export declare function alignText(text: string, width: number, align?: "left" | "center" | "right"): string;
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/cli/src/app-opentui/layout.ts
|
|
3
|
+
var MIN_TERMINAL_WIDTH = 48;
|
|
4
|
+
var MIN_TERMINAL_HEIGHT = 16;
|
|
3
5
|
function computeStageLayout(width, height) {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
+
const rawWidth = Math.trunc(width || 80);
|
|
7
|
+
const rawHeight = Math.trunc(height || 24);
|
|
8
|
+
const tooSmall = rawWidth < MIN_TERMINAL_WIDTH || rawHeight < MIN_TERMINAL_HEIGHT;
|
|
9
|
+
const safeWidth = Math.max(40, rawWidth);
|
|
10
|
+
const safeHeight = Math.max(18, rawHeight);
|
|
6
11
|
const compact = safeWidth < 92 || safeHeight < 30;
|
|
7
12
|
const horizontalGutter = compact ? 1 : 2;
|
|
8
13
|
const centerWidth = Math.max(36, safeWidth - horizontalGutter * 2);
|
|
9
14
|
const centerLeft = horizontalGutter;
|
|
10
15
|
const footerTop = Math.max(0, safeHeight - 1);
|
|
11
|
-
const typeBarTop = footerTop;
|
|
16
|
+
const typeBarTop = Math.max(0, footerTop - 1);
|
|
12
17
|
const centerTop = compact ? 1 : Math.max(1, Math.floor(safeHeight * 0.055));
|
|
13
|
-
const centerHeight = Math.max(
|
|
14
|
-
return { width: safeWidth, height: safeHeight, centerWidth, centerLeft, centerTop, centerHeight, typeBarTop, footerTop, compact };
|
|
18
|
+
const centerHeight = Math.max(6, typeBarTop - centerTop);
|
|
19
|
+
return { width: safeWidth, height: safeHeight, centerWidth, centerLeft, centerTop, centerHeight, typeBarTop, footerTop, compact, tooSmall };
|
|
15
20
|
}
|
|
16
21
|
function visibleWidth(text) {
|
|
17
22
|
return [...text].length;
|
|
@@ -40,5 +45,7 @@ export {
|
|
|
40
45
|
visibleWidth,
|
|
41
46
|
truncateText,
|
|
42
47
|
computeStageLayout,
|
|
43
|
-
alignText
|
|
48
|
+
alignText,
|
|
49
|
+
MIN_TERMINAL_WIDTH,
|
|
50
|
+
MIN_TERMINAL_HEIGHT
|
|
44
51
|
};
|
|
@@ -6,3 +6,27 @@ export declare function listSearchQuery(state: AppState): string;
|
|
|
6
6
|
export declare function filterRunsForSearch(runs: readonly AppRunRecord[], query: string): AppRunRecord[];
|
|
7
7
|
export declare function filterTasksForSearch(tasks: readonly AppTaskRecord[], query: string): AppTaskRecord[];
|
|
8
8
|
export declare function searchSummary(kind: "runs" | "tasks", query: string, visible: number, total: number): string;
|
|
9
|
+
export type SortDir = "asc" | "desc";
|
|
10
|
+
export type RunSortKey = "status" | "runId" | "title" | "age";
|
|
11
|
+
export type RunSortSpec = {
|
|
12
|
+
readonly key: RunSortKey;
|
|
13
|
+
readonly dir: SortDir;
|
|
14
|
+
};
|
|
15
|
+
export type TaskSortKey = "status" | "id" | "priority" | "assignee" | "title";
|
|
16
|
+
export type TaskSortSpec = {
|
|
17
|
+
readonly key: TaskSortKey;
|
|
18
|
+
readonly dir: SortDir;
|
|
19
|
+
};
|
|
20
|
+
/** Read a typed run sort spec off the data bag, narrowing the `unknown` slice. */
|
|
21
|
+
export declare function runSortSpec(value: unknown): RunSortSpec | null;
|
|
22
|
+
/** Read a typed task sort spec off the data bag, narrowing the `unknown` slice. */
|
|
23
|
+
export declare function taskSortSpec(value: unknown): TaskSortSpec | null;
|
|
24
|
+
/** Cycle a column's sort: clicking the active column flips asc→desc→default;
|
|
25
|
+
* clicking a new column starts it ascending. `null` means "back to default". */
|
|
26
|
+
export declare function cycleRunSort(current: RunSortSpec | null, key: RunSortKey): RunSortSpec | null;
|
|
27
|
+
export declare function cycleTaskSort(current: TaskSortSpec | null, key: TaskSortKey): TaskSortSpec | null;
|
|
28
|
+
/** Sort runs by a column. `spec === null` returns the input order unchanged. */
|
|
29
|
+
export declare function sortRuns(runs: readonly AppRunRecord[], spec: RunSortSpec | null): AppRunRecord[];
|
|
30
|
+
/** Sort tasks by a column, client-side over already-fetched records. `spec ===
|
|
31
|
+
* null` returns the input order unchanged (server/adapter order is preserved). */
|
|
32
|
+
export declare function sortTasks(tasks: readonly AppTaskRecord[], spec: TaskSortSpec | null): AppTaskRecord[];
|
|
@@ -34,10 +34,97 @@ function filterTasksForSearch(tasks, query) {
|
|
|
34
34
|
function searchSummary(kind, query, visible, total) {
|
|
35
35
|
return query.trim() ? `search ${JSON.stringify(query)} \xB7 ${visible}/${total} ${kind}` : `${total} ${kind}`;
|
|
36
36
|
}
|
|
37
|
+
function runSortSpec(value) {
|
|
38
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
39
|
+
return null;
|
|
40
|
+
const record = value;
|
|
41
|
+
const key = record.key;
|
|
42
|
+
const dir = record.dir;
|
|
43
|
+
if ((key === "status" || key === "runId" || key === "title" || key === "age") && (dir === "asc" || dir === "desc")) {
|
|
44
|
+
return { key, dir };
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function taskSortSpec(value) {
|
|
49
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
50
|
+
return null;
|
|
51
|
+
const record = value;
|
|
52
|
+
const key = record.key;
|
|
53
|
+
const dir = record.dir;
|
|
54
|
+
if ((key === "status" || key === "id" || key === "priority" || key === "assignee" || key === "title") && (dir === "asc" || dir === "desc")) {
|
|
55
|
+
return { key, dir };
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
function cycleRunSort(current, key) {
|
|
60
|
+
if (!current || current.key !== key)
|
|
61
|
+
return { key, dir: "asc" };
|
|
62
|
+
if (current.dir === "asc")
|
|
63
|
+
return { key, dir: "desc" };
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function cycleTaskSort(current, key) {
|
|
67
|
+
if (!current || current.key !== key)
|
|
68
|
+
return { key, dir: "asc" };
|
|
69
|
+
if (current.dir === "asc")
|
|
70
|
+
return { key, dir: "desc" };
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
function ageValue(updatedAt) {
|
|
74
|
+
const parsed = Date.parse(updatedAt ?? "");
|
|
75
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
76
|
+
}
|
|
77
|
+
function applyDir(rows, compare, dir) {
|
|
78
|
+
const sorted = [...rows].sort(compare);
|
|
79
|
+
return dir === "desc" ? sorted.reverse() : sorted;
|
|
80
|
+
}
|
|
81
|
+
function sortRuns(runs, spec) {
|
|
82
|
+
if (!spec)
|
|
83
|
+
return [...runs];
|
|
84
|
+
const { key, dir } = spec;
|
|
85
|
+
if (key === "age") {
|
|
86
|
+
const byNewest = applyDir(runs, (a, b) => ageValue(b.updatedAt) - ageValue(a.updatedAt) || a.runId.localeCompare(b.runId), "asc");
|
|
87
|
+
return dir === "asc" ? byNewest : [...byNewest].reverse();
|
|
88
|
+
}
|
|
89
|
+
const compare = (a, b) => {
|
|
90
|
+
if (key === "status")
|
|
91
|
+
return a.status.localeCompare(b.status) || a.runId.localeCompare(b.runId);
|
|
92
|
+
if (key === "title")
|
|
93
|
+
return a.title.localeCompare(b.title, undefined, { sensitivity: "base" }) || a.runId.localeCompare(b.runId);
|
|
94
|
+
return a.runId.localeCompare(b.runId, undefined, { numeric: true });
|
|
95
|
+
};
|
|
96
|
+
return applyDir(runs, compare, dir);
|
|
97
|
+
}
|
|
98
|
+
function sortTasks(tasks, spec) {
|
|
99
|
+
if (!spec)
|
|
100
|
+
return [...tasks];
|
|
101
|
+
const { key, dir } = spec;
|
|
102
|
+
const compare = (a, b) => {
|
|
103
|
+
if (key === "status")
|
|
104
|
+
return a.status.localeCompare(b.status) || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
105
|
+
if (key === "priority") {
|
|
106
|
+
const left = a.priority ?? Number.NEGATIVE_INFINITY;
|
|
107
|
+
const right = b.priority ?? Number.NEGATIVE_INFINITY;
|
|
108
|
+
return right - left || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
109
|
+
}
|
|
110
|
+
if (key === "assignee")
|
|
111
|
+
return (a.assignees[0] ?? "").localeCompare(b.assignees[0] ?? "") || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
112
|
+
if (key === "title")
|
|
113
|
+
return a.title.localeCompare(b.title, undefined, { sensitivity: "base" }) || a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
114
|
+
return a.id.localeCompare(b.id, undefined, { numeric: true });
|
|
115
|
+
};
|
|
116
|
+
return applyDir(tasks, compare, dir);
|
|
117
|
+
}
|
|
37
118
|
export {
|
|
119
|
+
taskSortSpec,
|
|
120
|
+
sortTasks,
|
|
121
|
+
sortRuns,
|
|
38
122
|
searchSummary,
|
|
123
|
+
runSortSpec,
|
|
39
124
|
listSearchQuery,
|
|
40
125
|
isListSearchScene,
|
|
41
126
|
filterTasksForSearch,
|
|
42
|
-
filterRunsForSearch
|
|
127
|
+
filterRunsForSearch,
|
|
128
|
+
cycleTaskSort,
|
|
129
|
+
cycleRunSort
|
|
43
130
|
};
|
|
@@ -587,6 +587,14 @@ async function withSpinner(label, work, options = {}) {
|
|
|
587
587
|
}
|
|
588
588
|
|
|
589
589
|
// packages/cli/src/commands/_pi-frontend.ts
|
|
590
|
+
var TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
|
|
591
|
+
|
|
592
|
+
class OperatorTranscriptUnavailableError extends Error {
|
|
593
|
+
constructor(message) {
|
|
594
|
+
super(message);
|
|
595
|
+
this.name = "OperatorTranscriptUnavailableError";
|
|
596
|
+
}
|
|
597
|
+
}
|
|
590
598
|
function setTemporaryEnv(updates) {
|
|
591
599
|
const previous = new Map;
|
|
592
600
|
for (const [key, value] of Object.entries(updates)) {
|
|
@@ -614,6 +622,23 @@ function buildOperatorPiEnv(input) {
|
|
|
614
622
|
...input.serverProjectRoot ? { RIG_PROJECT_ROOT: input.serverProjectRoot } : {}
|
|
615
623
|
};
|
|
616
624
|
}
|
|
625
|
+
function shouldRequireOperatorTranscript(status) {
|
|
626
|
+
return typeof status === "string" && TERMINAL_RUN_STATUSES.has(status.trim().toLowerCase());
|
|
627
|
+
}
|
|
628
|
+
function missingOperatorTranscriptMessage(runId, status) {
|
|
629
|
+
const shortRun = runId.trim().slice(0, 8) || "unknown";
|
|
630
|
+
const statusText = typeof status === "string" && status.trim() ? status.trim() : "terminal";
|
|
631
|
+
return `Run ${shortRun} is ${statusText}, but no worker Pi session transcript is recorded for this run. It likely failed before Pi started or predates full-session capture. Use \`rig run show ${runId}\` and \`rig run logs ${runId}\` for the lifecycle details.`;
|
|
632
|
+
}
|
|
633
|
+
function statusFromRunDetails(run) {
|
|
634
|
+
if (!run || typeof run !== "object" || Array.isArray(run))
|
|
635
|
+
return;
|
|
636
|
+
const record = run;
|
|
637
|
+
if (typeof record.status === "string")
|
|
638
|
+
return record.status;
|
|
639
|
+
const nested = record.run;
|
|
640
|
+
return nested && typeof nested === "object" && !Array.isArray(nested) ? nested.status : undefined;
|
|
641
|
+
}
|
|
617
642
|
async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
618
643
|
const server = await ensureServerForCli(context.projectRoot);
|
|
619
644
|
const localCwd = join(homedir2(), ".rig", "drones", runId.slice(0, 8));
|
|
@@ -643,6 +668,13 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
|
|
|
643
668
|
sessionFileArg = ["--session", localSessionPath];
|
|
644
669
|
}
|
|
645
670
|
} catch {}
|
|
671
|
+
if (sessionFileArg.length === 0) {
|
|
672
|
+
const run = await getRunDetailsViaServer(context, runId).catch(() => null);
|
|
673
|
+
const status = statusFromRunDetails(run);
|
|
674
|
+
if (shouldRequireOperatorTranscript(status)) {
|
|
675
|
+
throw new OperatorTranscriptUnavailableError(missingOperatorTranscriptMessage(runId, status));
|
|
676
|
+
}
|
|
677
|
+
}
|
|
646
678
|
return { server, sessionFileArg };
|
|
647
679
|
}
|
|
648
680
|
var RIG_PI_THEME = {
|
|
@@ -815,7 +847,7 @@ if (import.meta.main) {
|
|
|
815
847
|
try {
|
|
816
848
|
await runOpenTuiPiHostChild();
|
|
817
849
|
} catch (error) {
|
|
818
|
-
const message = error instanceof Error ? error.stack || error.message : String(error);
|
|
850
|
+
const message = error instanceof Error ? error.name === "OperatorTranscriptUnavailableError" ? error.message : error.stack || error.message : String(error);
|
|
819
851
|
process.stderr.write(`
|
|
820
852
|
Pi host failed:
|
|
821
853
|
${message}
|
|
@@ -17,6 +17,7 @@ export type PiPtyHostSnapshot = {
|
|
|
17
17
|
readonly lines: readonly string[];
|
|
18
18
|
readonly styledLines?: readonly StyledText[];
|
|
19
19
|
readonly message?: string;
|
|
20
|
+
readonly resizeError?: string;
|
|
20
21
|
readonly exitCode?: number;
|
|
21
22
|
readonly signal?: string | null;
|
|
22
23
|
};
|
|
@@ -49,9 +50,13 @@ export declare class PiPtyHost {
|
|
|
49
50
|
private cols;
|
|
50
51
|
private rows;
|
|
51
52
|
private message;
|
|
53
|
+
private lastResizeError;
|
|
52
54
|
private exitCode;
|
|
53
55
|
private signal;
|
|
54
56
|
private notifyTimer;
|
|
57
|
+
/** Last streamed buffer content, so the onWriteParsed handler only emits a
|
|
58
|
+
* snapshot when the rendered content actually changed. */
|
|
59
|
+
private lastStreamKey;
|
|
55
60
|
private _disposed;
|
|
56
61
|
constructor(options: PiPtyHostOptions);
|
|
57
62
|
get disposed(): boolean;
|
|
@@ -158,9 +158,11 @@ class PiPtyHost {
|
|
|
158
158
|
cols;
|
|
159
159
|
rows;
|
|
160
160
|
message = "starting bundled Pi";
|
|
161
|
+
lastResizeError = null;
|
|
161
162
|
exitCode;
|
|
162
163
|
signal;
|
|
163
164
|
notifyTimer = null;
|
|
165
|
+
lastStreamKey = "";
|
|
164
166
|
_disposed = false;
|
|
165
167
|
constructor(options) {
|
|
166
168
|
this.runId = options.runId;
|
|
@@ -177,6 +179,17 @@ class PiPtyHost {
|
|
|
177
179
|
scrollback: 1000
|
|
178
180
|
});
|
|
179
181
|
this.registerTerminalResponders();
|
|
182
|
+
this.disposables.push(this.terminal.onWriteParsed(() => {
|
|
183
|
+
if (this._disposed)
|
|
184
|
+
return;
|
|
185
|
+
const snapshot = this.createSnapshot();
|
|
186
|
+
const key = snapshot.lines.join(`
|
|
187
|
+
`);
|
|
188
|
+
if (key === this.lastStreamKey)
|
|
189
|
+
return;
|
|
190
|
+
this.lastStreamKey = key;
|
|
191
|
+
this.onSnapshot?.(snapshot);
|
|
192
|
+
}));
|
|
180
193
|
}
|
|
181
194
|
get disposed() {
|
|
182
195
|
return this._disposed;
|
|
@@ -263,7 +276,10 @@ class PiPtyHost {
|
|
|
263
276
|
this.terminal.resize(nextCols, nextRows);
|
|
264
277
|
try {
|
|
265
278
|
this.pty?.resize(nextCols, nextRows);
|
|
266
|
-
|
|
279
|
+
this.lastResizeError = null;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
this.lastResizeError = error instanceof Error ? error.message : String(error);
|
|
282
|
+
}
|
|
267
283
|
this.emitSnapshotSoon(0);
|
|
268
284
|
}
|
|
269
285
|
detach() {
|
|
@@ -305,7 +321,7 @@ class PiPtyHost {
|
|
|
305
321
|
return;
|
|
306
322
|
const text = this.decoder.decode(data, { stream: true });
|
|
307
323
|
this.respondToRawTerminalQueries(text);
|
|
308
|
-
this.terminal.write(data
|
|
324
|
+
this.terminal.write(data);
|
|
309
325
|
}
|
|
310
326
|
emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS) {
|
|
311
327
|
if (this._disposed || this.notifyTimer)
|
|
@@ -334,6 +350,7 @@ class PiPtyHost {
|
|
|
334
350
|
lines.push("");
|
|
335
351
|
styledLines[lines.length - 1] = new StyledText([{ __isChunk: true, text: "" }]);
|
|
336
352
|
}
|
|
353
|
+
const resolvedMessage = this.lastResizeError ? `resize degraded: ${this.lastResizeError}` : message;
|
|
337
354
|
return {
|
|
338
355
|
runId: this.runId,
|
|
339
356
|
status: this.status,
|
|
@@ -341,7 +358,8 @@ class PiPtyHost {
|
|
|
341
358
|
rows: this.rows,
|
|
342
359
|
lines,
|
|
343
360
|
styledLines,
|
|
344
|
-
message,
|
|
361
|
+
message: resolvedMessage,
|
|
362
|
+
...this.lastResizeError ? { resizeError: this.lastResizeError } : {},
|
|
345
363
|
...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
|
|
346
364
|
...this.signal !== undefined ? { signal: this.signal } : {}
|
|
347
365
|
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { computeStageLayout } from "../layout";
|
|
2
|
+
import { entryIntentForScene } from "../runtime";
|
|
3
|
+
import { PRIMARY_NAV } from "./nav";
|
|
4
|
+
import type { AppSceneFrame, AppSceneId, AppState } from "../types";
|
|
5
|
+
type SceneRenderer = (state: AppState, layout: ReturnType<typeof computeStageLayout>) => AppSceneFrame;
|
|
6
|
+
export declare function App(props: {
|
|
7
|
+
sceneRenderers?: Partial<Record<AppSceneId, SceneRenderer>>;
|
|
8
|
+
}): React.ReactNode;
|
|
9
|
+
export { PRIMARY_NAV, entryIntentForScene };
|