@h-rig/cli 0.0.6-alpha.82 → 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.
Files changed (206) hide show
  1. package/dist/bin/build-rig-binaries.js +40 -8
  2. package/dist/bin/rig.js +23402 -14577
  3. package/dist/src/app/board.js +217 -41
  4. package/dist/src/app-opentui/adapters/command.d.ts +2 -0
  5. package/dist/src/app-opentui/adapters/command.js +329 -0
  6. package/dist/src/app-opentui/adapters/common.js +2 -2
  7. package/dist/src/app-opentui/adapters/doctor.d.ts +0 -2
  8. package/dist/src/app-opentui/adapters/doctor.js +64 -39
  9. package/dist/src/app-opentui/adapters/family.d.ts +62 -0
  10. package/dist/src/app-opentui/adapters/family.js +14305 -0
  11. package/dist/src/app-opentui/adapters/fleet.d.ts +0 -2
  12. package/dist/src/app-opentui/adapters/fleet.js +90 -60
  13. package/dist/src/app-opentui/adapters/inbox.d.ts +12 -2
  14. package/dist/src/app-opentui/adapters/inbox.js +137 -78
  15. package/dist/src/app-opentui/adapters/init.d.ts +0 -2
  16. package/dist/src/app-opentui/adapters/init.js +85 -47
  17. package/dist/src/app-opentui/adapters/inspect.d.ts +52 -0
  18. package/dist/src/app-opentui/adapters/inspect.js +1024 -0
  19. package/dist/src/app-opentui/adapters/pi-attach.d.ts +15 -6
  20. package/dist/src/app-opentui/adapters/pi-attach.js +442 -125
  21. package/dist/src/app-opentui/adapters/pi.d.ts +23 -0
  22. package/dist/src/app-opentui/adapters/pi.js +363 -0
  23. package/dist/src/app-opentui/adapters/plugin.d.ts +84 -0
  24. package/dist/src/app-opentui/adapters/plugin.js +544 -0
  25. package/dist/src/app-opentui/adapters/repo.d.ts +37 -0
  26. package/dist/src/app-opentui/adapters/repo.js +186 -0
  27. package/dist/src/app-opentui/adapters/run-detail.d.ts +9 -2
  28. package/dist/src/app-opentui/adapters/run-detail.js +180 -63
  29. package/dist/src/app-opentui/adapters/server.d.ts +10 -2
  30. package/dist/src/app-opentui/adapters/server.js +191 -45
  31. package/dist/src/app-opentui/adapters/tasks.d.ts +11 -2
  32. package/dist/src/app-opentui/adapters/tasks.js +1123 -143
  33. package/dist/src/app-opentui/adapters/workspace.d.ts +49 -0
  34. package/dist/src/app-opentui/adapters/workspace.js +333 -0
  35. package/dist/src/app-opentui/autocomplete.d.ts +20 -0
  36. package/dist/src/app-opentui/autocomplete.js +576 -0
  37. package/dist/src/app-opentui/bootstrap.d.ts +1 -6
  38. package/dist/src/app-opentui/bootstrap.js +25252 -16474
  39. package/dist/src/app-opentui/command-palette.d.ts +3 -0
  40. package/dist/src/app-opentui/command-palette.js +1010 -0
  41. package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
  42. package/dist/src/app-opentui/command-pty-host.js +248 -0
  43. package/dist/src/app-opentui/drone.js +8 -6
  44. package/dist/src/app-opentui/events.js +1 -1
  45. package/dist/src/app-opentui/fleet-stats.d.ts +32 -0
  46. package/dist/src/app-opentui/fleet-stats.js +114 -0
  47. package/dist/src/app-opentui/focus-manager.d.ts +14 -0
  48. package/dist/src/app-opentui/focus-manager.js +24 -0
  49. package/dist/src/app-opentui/index.js +5431 -2797
  50. package/dist/src/app-opentui/intent.js +179 -50
  51. package/dist/src/app-opentui/keymap.d.ts +21 -0
  52. package/dist/src/app-opentui/keymap.js +1748 -0
  53. package/dist/src/app-opentui/launch-routing.d.ts +16 -0
  54. package/dist/src/app-opentui/launch-routing.js +55 -0
  55. package/dist/src/app-opentui/layout.d.ts +7 -0
  56. package/dist/src/app-opentui/layout.js +13 -6
  57. package/dist/src/app-opentui/list-search.d.ts +24 -0
  58. package/dist/src/app-opentui/list-search.js +88 -1
  59. package/dist/src/app-opentui/pi-host-child.js +99 -17
  60. package/dist/src/app-opentui/pi-pty-host.d.ts +14 -0
  61. package/dist/src/app-opentui/pi-pty-host.js +30 -14
  62. package/dist/src/app-opentui/react/App.d.ts +9 -0
  63. package/dist/src/app-opentui/react/App.js +5144 -0
  64. package/dist/src/app-opentui/react/Backdrop.d.ts +5 -0
  65. package/dist/src/app-opentui/react/Backdrop.js +1834 -0
  66. package/dist/src/app-opentui/react/ChromeHost.d.ts +5 -0
  67. package/dist/src/app-opentui/react/ChromeHost.js +2942 -0
  68. package/dist/src/app-opentui/react/SceneFrameView.d.ts +7 -0
  69. package/dist/src/app-opentui/react/SceneFrameView.js +529 -0
  70. package/dist/src/app-opentui/react/context.d.ts +17 -0
  71. package/dist/src/app-opentui/react/context.js +37 -0
  72. package/dist/src/app-opentui/react/launch.d.ts +2 -0
  73. package/dist/src/app-opentui/react/launch.js +5743 -0
  74. package/dist/src/app-opentui/react/nav.d.ts +18 -0
  75. package/dist/src/app-opentui/react/nav.js +54 -0
  76. package/dist/src/app-opentui/react/scroll.d.ts +12 -0
  77. package/dist/src/app-opentui/react/scroll.js +21 -0
  78. package/dist/src/app-opentui/react/syntax.d.ts +2 -0
  79. package/dist/src/app-opentui/react/syntax.js +64 -0
  80. package/dist/src/app-opentui/registry.js +20428 -4828
  81. package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
  82. package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
  83. package/dist/src/app-opentui/render/constants.d.ts +31 -0
  84. package/dist/src/app-opentui/render/constants.js +66 -0
  85. package/dist/src/app-opentui/render/graphics.d.ts +2 -1
  86. package/dist/src/app-opentui/render/graphics.js +228 -46
  87. package/dist/src/app-opentui/render/image-visual-layer-worker.js +469 -930
  88. package/dist/src/app-opentui/render/image-visual-layer.d.ts +25 -10
  89. package/dist/src/app-opentui/render/image-visual-layer.js +448 -329
  90. package/dist/src/app-opentui/render/native-host.d.ts +37 -0
  91. package/dist/src/app-opentui/render/native-host.js +179 -0
  92. package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
  93. package/dist/src/app-opentui/render/panel-layout.js +48 -0
  94. package/dist/src/app-opentui/render/panels.d.ts +2 -0
  95. package/dist/src/app-opentui/render/panels.js +78 -38
  96. package/dist/src/app-opentui/render/preloader.d.ts +10 -0
  97. package/dist/src/app-opentui/render/preloader.js +165 -0
  98. package/dist/src/app-opentui/render/scene.d.ts +53 -1
  99. package/dist/src/app-opentui/render/scene.js +195 -6
  100. package/dist/src/app-opentui/render/text.d.ts +7 -1
  101. package/dist/src/app-opentui/render/text.js +15 -8
  102. package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
  103. package/dist/src/app-opentui/render/type-bar.js +113 -39
  104. package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
  105. package/dist/src/app-opentui/runtime-resources.js +62 -0
  106. package/dist/src/app-opentui/runtime.d.ts +44 -1
  107. package/dist/src/app-opentui/runtime.js +5415 -2738
  108. package/dist/src/app-opentui/scenes/command.d.ts +3 -0
  109. package/dist/src/app-opentui/scenes/command.js +117 -0
  110. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
  111. package/dist/src/app-opentui/scenes/doctor.js +221 -17
  112. package/dist/src/app-opentui/scenes/error.js +60 -20
  113. package/dist/src/app-opentui/scenes/family-domains/agent.d.ts +2 -0
  114. package/dist/src/app-opentui/scenes/family-domains/agent.js +348 -0
  115. package/dist/src/app-opentui/scenes/family-domains/browser.d.ts +2 -0
  116. package/dist/src/app-opentui/scenes/family-domains/browser.js +195 -0
  117. package/dist/src/app-opentui/scenes/family-domains/dist.d.ts +2 -0
  118. package/dist/src/app-opentui/scenes/family-domains/dist.js +243 -0
  119. package/dist/src/app-opentui/scenes/family-domains/git.d.ts +2 -0
  120. package/dist/src/app-opentui/scenes/family-domains/git.js +195 -0
  121. package/dist/src/app-opentui/scenes/family-domains/github.d.ts +2 -0
  122. package/dist/src/app-opentui/scenes/family-domains/github.js +274 -0
  123. package/dist/src/app-opentui/scenes/family-domains/harness.d.ts +2 -0
  124. package/dist/src/app-opentui/scenes/family-domains/harness.js +152 -0
  125. package/dist/src/app-opentui/scenes/family-domains/index.d.ts +4 -0
  126. package/dist/src/app-opentui/scenes/family-domains/index.js +1679 -0
  127. package/dist/src/app-opentui/scenes/family-domains/kit.d.ts +76 -0
  128. package/dist/src/app-opentui/scenes/family-domains/kit.js +305 -0
  129. package/dist/src/app-opentui/scenes/family-domains/profile.d.ts +2 -0
  130. package/dist/src/app-opentui/scenes/family-domains/profile.js +212 -0
  131. package/dist/src/app-opentui/scenes/family-domains/queue.d.ts +2 -0
  132. package/dist/src/app-opentui/scenes/family-domains/queue.js +146 -0
  133. package/dist/src/app-opentui/scenes/family-domains/remote.d.ts +2 -0
  134. package/dist/src/app-opentui/scenes/family-domains/remote.js +518 -0
  135. package/dist/src/app-opentui/scenes/family-domains/review.d.ts +2 -0
  136. package/dist/src/app-opentui/scenes/family-domains/review.js +280 -0
  137. package/dist/src/app-opentui/scenes/family-domains/setup.d.ts +2 -0
  138. package/dist/src/app-opentui/scenes/family-domains/setup.js +267 -0
  139. package/dist/src/app-opentui/scenes/family-domains/stats.d.ts +2 -0
  140. package/dist/src/app-opentui/scenes/family-domains/stats.js +370 -0
  141. package/dist/src/app-opentui/scenes/family.d.ts +3 -0
  142. package/dist/src/app-opentui/scenes/family.js +2144 -0
  143. package/dist/src/app-opentui/scenes/fleet.js +552 -43
  144. package/dist/src/app-opentui/scenes/handoff.js +342 -35
  145. package/dist/src/app-opentui/scenes/help.js +640 -56
  146. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
  147. package/dist/src/app-opentui/scenes/inbox.js +329 -21
  148. package/dist/src/app-opentui/scenes/init.d.ts +2 -1
  149. package/dist/src/app-opentui/scenes/init.js +120 -34
  150. package/dist/src/app-opentui/scenes/inspect.d.ts +3 -0
  151. package/dist/src/app-opentui/scenes/inspect.js +793 -0
  152. package/dist/src/app-opentui/scenes/main.d.ts +2 -1
  153. package/dist/src/app-opentui/scenes/main.js +264 -29
  154. package/dist/src/app-opentui/scenes/pi.d.ts +3 -0
  155. package/dist/src/app-opentui/scenes/pi.js +508 -0
  156. package/dist/src/app-opentui/scenes/plugin.d.ts +3 -0
  157. package/dist/src/app-opentui/scenes/plugin.js +486 -0
  158. package/dist/src/app-opentui/scenes/repo.d.ts +3 -0
  159. package/dist/src/app-opentui/scenes/repo.js +424 -0
  160. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
  161. package/dist/src/app-opentui/scenes/run-detail.js +362 -35
  162. package/dist/src/app-opentui/scenes/server.d.ts +2 -1
  163. package/dist/src/app-opentui/scenes/server.js +243 -26
  164. package/dist/src/app-opentui/scenes/tasks.js +518 -41
  165. package/dist/src/app-opentui/scenes/workspace.d.ts +3 -0
  166. package/dist/src/app-opentui/scenes/workspace.js +426 -0
  167. package/dist/src/app-opentui/selectable.d.ts +19 -0
  168. package/dist/src/app-opentui/selectable.js +79 -0
  169. package/dist/src/app-opentui/state.js +129 -36
  170. package/dist/src/app-opentui/surface-catalog.d.ts +20 -0
  171. package/dist/src/app-opentui/surface-catalog.js +540 -0
  172. package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
  173. package/dist/src/app-opentui/terminal-capabilities.js +15 -0
  174. package/dist/src/app-opentui/theme.d.ts +28 -6
  175. package/dist/src/app-opentui/theme.js +61 -8
  176. package/dist/src/app-opentui/types.d.ts +130 -5
  177. package/dist/src/commands/_authority-runs.d.ts +1 -1
  178. package/dist/src/commands/_authority-runs.js +2 -12
  179. package/dist/src/commands/_doctor-checks.js +62 -13
  180. package/dist/src/commands/_help-catalog.js +95 -15
  181. package/dist/src/commands/_operator-view.js +97 -15
  182. package/dist/src/commands/_pi-frontend.d.ts +2 -0
  183. package/dist/src/commands/_pi-frontend.js +97 -13
  184. package/dist/src/commands/_preflight.js +64 -14
  185. package/dist/src/commands/_server-client.js +82 -18
  186. package/dist/src/commands/_server-events.d.ts +26 -0
  187. package/dist/src/commands/_server-events.js +310 -0
  188. package/dist/src/commands/_snapshot-upload.js +62 -13
  189. package/dist/src/commands/agent.js +2 -12
  190. package/dist/src/commands/connect.js +7 -1
  191. package/dist/src/commands/doctor.js +62 -13
  192. package/dist/src/commands/github.js +144 -23
  193. package/dist/src/commands/inbox.js +62 -13
  194. package/dist/src/commands/init.js +82 -18
  195. package/dist/src/commands/inspect.js +62 -13
  196. package/dist/src/commands/run.js +100 -15
  197. package/dist/src/commands/server.js +71 -26
  198. package/dist/src/commands/setup.js +62 -13
  199. package/dist/src/commands/stats.js +157 -28
  200. package/dist/src/commands/task-run-driver.js +64 -25
  201. package/dist/src/commands/task.js +196 -43
  202. package/dist/src/commands.js +419 -123
  203. package/dist/src/index.js +426 -130
  204. package/package.json +11 -10
  205. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
  206. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
@@ -0,0 +1,329 @@
1
+ // @bun
2
+ // packages/cli/src/app-opentui/adapters/common.ts
3
+ function projectRootOf(ctx) {
4
+ const root = ctx.rig?.projectRoot ?? ctx.projectRoot ?? ctx.getState().projectRoot;
5
+ if (typeof root === "string" && root.trim())
6
+ return root;
7
+ throw new Error("App adapter requires a projectRoot.");
8
+ }
9
+ function normalizeAppError(error) {
10
+ const message = error instanceof Error ? error.message : String(error);
11
+ const rawHint = error instanceof Error ? error.hint : undefined;
12
+ return {
13
+ message,
14
+ ...typeof rawHint === "string" && rawHint.trim() ? { hint: rawHint.trim() } : {}
15
+ };
16
+ }
17
+ function emitStarted(ctx, label, optimistic) {
18
+ ctx.emit({ type: "action.started", label, ...optimistic ? { optimistic } : {} });
19
+ }
20
+ function emitCompleted(ctx, label, data) {
21
+ ctx.emit({ type: "action.completed", label, ...data ? { data } : {} });
22
+ }
23
+ function emitFailed(ctx, label, error, data) {
24
+ if (data)
25
+ patchData(ctx, data);
26
+ const normalized = normalizeAppError(error);
27
+ ctx.emit({
28
+ type: "action.failed",
29
+ label,
30
+ message: normalized.message,
31
+ ...normalized.hint ? { hint: normalized.hint } : {},
32
+ cause: error
33
+ });
34
+ }
35
+ function patchData(ctx, data) {
36
+ ctx.emit({ type: "data.patch", data });
37
+ }
38
+ function patchFooter(ctx, footer) {
39
+ ctx.emit({ type: "footer.patch", footer });
40
+ }
41
+
42
+ // packages/cli/src/app-opentui/command-pty-host.ts
43
+ import { basename } from "path";
44
+ import { fileURLToPath } from "url";
45
+ import { Terminal as XtermTerminal } from "@xterm/headless";
46
+ var MIN_COLS = 40;
47
+ var MIN_ROWS = 10;
48
+ var MAX_ROWS = 300;
49
+ var MAX_SNAPSHOT_LINES = 420;
50
+ var SNAPSHOT_DELAY_MS = 80;
51
+ var fallbackCliScriptPath = fileURLToPath(new URL("../../bin/rig.ts", import.meta.url));
52
+ var activeHost = null;
53
+ function clampCols(cols) {
54
+ return Math.max(MIN_COLS, Math.trunc(cols || 120));
55
+ }
56
+ function clampRows(rows) {
57
+ return Math.max(MIN_ROWS, Math.min(MAX_ROWS, Math.trunc(rows || 36)));
58
+ }
59
+ function childCommandPrefix() {
60
+ const execName = basename(process.execPath).toLowerCase();
61
+ const currentEntry = process.argv[1];
62
+ if (execName === "bun" || execName === "bun.exe") {
63
+ return currentEntry ? [process.execPath, currentEntry] : [process.execPath, fallbackCliScriptPath];
64
+ }
65
+ return [process.execPath];
66
+ }
67
+ function withEnv(base) {
68
+ const env = {};
69
+ for (const [key, value] of Object.entries(base ?? process.env)) {
70
+ if (key === "NO_COLOR")
71
+ continue;
72
+ if (typeof value === "string")
73
+ env[key] = value;
74
+ }
75
+ return {
76
+ ...env,
77
+ TERM: "xterm-256color",
78
+ COLORTERM: "truecolor",
79
+ FORCE_COLOR: env.FORCE_COLOR ?? "1",
80
+ RIG_PLAIN: "1",
81
+ RIG_OPENTUI_COMMAND_HOST: "1",
82
+ RIG_CLI_PLAIN_HELP: env.RIG_CLI_PLAIN_HELP ?? "1"
83
+ };
84
+ }
85
+ function commandLabel(argv, fallback) {
86
+ const command = argv.join(" ").trim();
87
+ return fallback?.trim() || (command ? `rig ${command}` : "rig");
88
+ }
89
+ async function startCommandPtyHost(options) {
90
+ activeHost?.dispose("replace");
91
+ const host = new CommandPtyHost(options);
92
+ activeHost = host;
93
+ await host.start();
94
+ return host;
95
+ }
96
+
97
+ class CommandPtyHost {
98
+ argv;
99
+ projectRoot;
100
+ label;
101
+ env;
102
+ onSnapshot;
103
+ onExit;
104
+ onError;
105
+ terminal;
106
+ decoder = new TextDecoder("utf-8");
107
+ proc = null;
108
+ pty = null;
109
+ status = "starting";
110
+ cols;
111
+ rows;
112
+ message = "starting command";
113
+ exitCode;
114
+ signal;
115
+ notifyTimer = null;
116
+ _disposed = false;
117
+ constructor(options) {
118
+ this.argv = [...options.argv];
119
+ this.projectRoot = options.projectRoot;
120
+ this.label = commandLabel(options.argv, options.label);
121
+ this.env = options.env;
122
+ this.cols = clampCols(options.cols);
123
+ this.rows = clampRows(options.rows);
124
+ this.onSnapshot = options.onSnapshot;
125
+ this.onExit = options.onExit;
126
+ this.onError = options.onError;
127
+ this.terminal = new XtermTerminal({ allowProposedApi: true, cols: this.cols, rows: this.rows, scrollback: 2000 });
128
+ }
129
+ get disposed() {
130
+ return this._disposed;
131
+ }
132
+ get snapshot() {
133
+ return this.createSnapshot();
134
+ }
135
+ async start() {
136
+ if (this._disposed)
137
+ throw new Error("Command PTY host is disposed.");
138
+ if (typeof Bun.Terminal !== "function") {
139
+ throw new Error("Bun native PTY is unavailable in this runtime. Command host requires Bun.Terminal.");
140
+ }
141
+ const spawnOptions = {
142
+ cwd: this.projectRoot,
143
+ env: withEnv(this.env),
144
+ terminal: {
145
+ cols: this.cols,
146
+ rows: this.rows,
147
+ name: "xterm-256color",
148
+ data: (_terminal, data) => this.handlePtyData(data)
149
+ }
150
+ };
151
+ const proc = Bun.spawn([...childCommandPrefix(), ...this.argv], spawnOptions);
152
+ if (!proc.terminal)
153
+ throw new Error("Bun did not attach a terminal to the command child process.");
154
+ this.proc = proc;
155
+ this.pty = proc.terminal;
156
+ this.status = "running";
157
+ this.message = "running";
158
+ this.emitSnapshotSoon(0);
159
+ proc.exited.then((exitCode) => {
160
+ if (this._disposed)
161
+ return;
162
+ this.status = exitCode === 0 ? "exited" : "failed";
163
+ this.exitCode = exitCode;
164
+ this.signal = null;
165
+ this.message = exitCode === 0 ? "completed" : `exited with code ${exitCode}`;
166
+ const snapshot = this.createSnapshot();
167
+ this.onSnapshot?.(snapshot);
168
+ this.onExit?.(snapshot);
169
+ if (activeHost === this)
170
+ activeHost = null;
171
+ this.dispose("exit", { kill: false, notify: false });
172
+ }).catch((error) => {
173
+ if (this._disposed)
174
+ return;
175
+ this.status = "failed";
176
+ this.message = error instanceof Error ? error.message : String(error);
177
+ const snapshot = this.createSnapshot();
178
+ this.onSnapshot?.(snapshot);
179
+ this.onError?.(error, snapshot);
180
+ if (activeHost === this)
181
+ activeHost = null;
182
+ this.dispose("error", { kill: false, notify: false });
183
+ });
184
+ }
185
+ write(data) {
186
+ if (this._disposed || !this.pty)
187
+ return;
188
+ try {
189
+ this.pty.write(data);
190
+ } catch (error) {
191
+ this.status = "failed";
192
+ this.message = error instanceof Error ? error.message : String(error);
193
+ const snapshot = this.createSnapshot();
194
+ this.onSnapshot?.(snapshot);
195
+ this.onError?.(error, snapshot);
196
+ }
197
+ }
198
+ resize(cols, rows) {
199
+ const nextCols = clampCols(cols);
200
+ const nextRows = clampRows(rows);
201
+ if (nextCols === this.cols && nextRows === this.rows)
202
+ return;
203
+ this.cols = nextCols;
204
+ this.rows = nextRows;
205
+ this.terminal.resize(nextCols, nextRows);
206
+ try {
207
+ this.pty?.resize(nextCols, nextRows);
208
+ } catch {}
209
+ this.emitSnapshotSoon(0);
210
+ }
211
+ dispose(reason = "dispose", options = {}) {
212
+ if (this._disposed)
213
+ return;
214
+ this._disposed = true;
215
+ if (this.notifyTimer)
216
+ clearTimeout(this.notifyTimer);
217
+ this.notifyTimer = null;
218
+ if (options.kill !== false) {
219
+ try {
220
+ this.proc?.kill("SIGTERM");
221
+ } catch {}
222
+ }
223
+ try {
224
+ this.pty?.close();
225
+ } catch {}
226
+ try {
227
+ this.terminal.dispose();
228
+ } catch {}
229
+ if (activeHost === this)
230
+ activeHost = null;
231
+ if (options.notify) {
232
+ this.message = reason;
233
+ this.onSnapshot?.(this.createSnapshot(reason));
234
+ }
235
+ }
236
+ handlePtyData(data) {
237
+ if (this._disposed)
238
+ return;
239
+ this.decoder.decode(data, { stream: true });
240
+ this.terminal.write(data, () => this.emitSnapshotSoon());
241
+ }
242
+ emitSnapshotSoon(delayMs = SNAPSHOT_DELAY_MS) {
243
+ if (this._disposed || this.notifyTimer)
244
+ return;
245
+ this.notifyTimer = setTimeout(() => {
246
+ this.notifyTimer = null;
247
+ if (this._disposed)
248
+ return;
249
+ this.onSnapshot?.(this.createSnapshot());
250
+ }, delayMs);
251
+ }
252
+ createSnapshot(message = this.message) {
253
+ const buffer = this.terminal.buffer.active;
254
+ const end = buffer.length;
255
+ const start = Math.max(0, end - MAX_SNAPSHOT_LINES);
256
+ const lines = [];
257
+ for (let row = start;row < end; row += 1) {
258
+ const line = buffer.getLine(row);
259
+ lines.push((line?.translateToString(false) ?? "").slice(0, this.cols));
260
+ }
261
+ while (lines.length < this.rows)
262
+ lines.push("");
263
+ return {
264
+ command: this.argv,
265
+ label: this.label,
266
+ status: this.status,
267
+ cols: this.cols,
268
+ rows: this.rows,
269
+ lines,
270
+ message,
271
+ ...this.exitCode !== undefined ? { exitCode: this.exitCode } : {},
272
+ ...this.signal !== undefined ? { signal: this.signal } : {}
273
+ };
274
+ }
275
+ }
276
+
277
+ // packages/cli/src/app-opentui/adapters/command.ts
278
+ function commandLabel2(argv) {
279
+ const command = argv.join(" ").trim();
280
+ return command ? `rig ${command}` : "rig";
281
+ }
282
+ async function runCommandInAppPty(ctx, argv) {
283
+ const label = commandLabel2(argv);
284
+ emitStarted(ctx, label, { command: { label, argv, status: "starting" } });
285
+ patchData(ctx, {
286
+ command: { label, argv, status: "starting" },
287
+ commandTerminal: {
288
+ command: argv,
289
+ label,
290
+ status: "starting",
291
+ cols: 120,
292
+ rows: 32,
293
+ lines: [],
294
+ message: "starting"
295
+ }
296
+ });
297
+ patchFooter(ctx, { message: label });
298
+ try {
299
+ const host = await startCommandPtyHost({
300
+ argv,
301
+ projectRoot: projectRootOf(ctx),
302
+ cols: 120,
303
+ rows: 32,
304
+ label,
305
+ onSnapshot(snapshot) {
306
+ patchData(ctx, { commandTerminal: snapshot, command: { label, argv, status: snapshot.status, message: snapshot.message } });
307
+ patchFooter(ctx, { message: `${label} \xB7 ${snapshot.message ?? snapshot.status}` });
308
+ },
309
+ onExit(snapshot) {
310
+ patchData(ctx, { commandTerminal: snapshot, command: { label, argv, status: snapshot.status, message: snapshot.message } });
311
+ if (snapshot.status === "exited")
312
+ emitCompleted(ctx, label, { exitCode: snapshot.exitCode ?? 0 });
313
+ else
314
+ emitFailed(ctx, label, new Error(snapshot.message ?? "Command failed"), { commandTerminal: snapshot });
315
+ },
316
+ onError(error, snapshot) {
317
+ patchData(ctx, { commandTerminal: snapshot, command: { label, argv, status: "failed", message: snapshot.message } });
318
+ emitFailed(ctx, label, error, { commandTerminal: snapshot });
319
+ }
320
+ });
321
+ patchData(ctx, { commandTerminal: host.snapshot });
322
+ } catch (error) {
323
+ emitFailed(ctx, label, error);
324
+ throw error;
325
+ }
326
+ }
327
+ export {
328
+ runCommandInAppPty
329
+ };
@@ -13,7 +13,7 @@ function projectRootOf(ctx) {
13
13
  const root = ctx.rig?.projectRoot ?? ctx.projectRoot ?? ctx.getState().projectRoot;
14
14
  if (typeof root === "string" && root.trim())
15
15
  return root;
16
- throw new Error("Rig app adapter requires a projectRoot.");
16
+ throw new Error("App adapter requires a projectRoot.");
17
17
  }
18
18
  async function runtimeOf(ctx) {
19
19
  if (ctx.rig && "runId" in ctx.rig && ctx.ensureRuntime === undefined) {
@@ -21,7 +21,7 @@ async function runtimeOf(ctx) {
21
21
  }
22
22
  if (ctx.ensureRuntime)
23
23
  return ctx.ensureRuntime();
24
- throw new Error("Rig app adapter requires ensureRuntime() before this action can run.");
24
+ throw new Error("App adapter requires ensureRuntime() before this action can run.");
25
25
  }
26
26
  function normalizeAppError(error) {
27
27
  const message = error instanceof Error ? error.message : String(error);
@@ -1,6 +1,4 @@
1
- import type { AppAdapter } from "../types";
2
1
  import { type AppAdapterContext } from "./common";
3
- export declare function createDoctorAdapter(): AppAdapter;
4
2
  export type AppDoctorCheck = {
5
3
  readonly id: string;
6
4
  readonly label: string;
@@ -145,17 +145,21 @@ function cleanToken(value) {
145
145
  const trimmed = value?.trim();
146
146
  return trimmed ? trimmed : null;
147
147
  }
148
- function readPrivateRemoteSessionToken(projectRoot) {
148
+ function readRemoteAuthState(projectRoot) {
149
149
  const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
150
150
  if (!existsSync2(path))
151
151
  return null;
152
152
  try {
153
153
  const parsed = JSON.parse(readFileSync2(path, "utf8"));
154
- return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
154
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
155
155
  } catch {
156
156
  return null;
157
157
  }
158
158
  }
159
+ function readPrivateRemoteSessionToken(projectRoot) {
160
+ const parsed = readRemoteAuthState(projectRoot);
161
+ return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
162
+ }
159
163
  function readGitHubBearerTokenForRemote(projectRoot) {
160
164
  const scopedKey = resolve2(projectRoot);
161
165
  if (scopedGitHubBearerTokens.has(scopedKey))
@@ -166,15 +170,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
166
170
  return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
167
171
  }
168
172
  function readStoredGitHubAuthToken(projectRoot) {
169
- const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
170
- if (!existsSync2(path))
173
+ const parsed = readRemoteAuthState(projectRoot);
174
+ return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
175
+ }
176
+ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
177
+ const repo = readRepoConnection(projectRoot);
178
+ const slug = repo?.project?.trim();
179
+ if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
171
180
  return null;
172
- try {
173
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
174
- return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
175
- } catch {
181
+ const auth = readRemoteAuthState(projectRoot);
182
+ const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
183
+ const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
184
+ if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
176
185
  return null;
177
- }
186
+ const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
187
+ if (!checkoutBaseDir)
188
+ return null;
189
+ const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
190
+ writeRepoServerProjectRoot(projectRoot, inferred);
191
+ return inferred;
178
192
  }
179
193
  function readLocalConnectionFallbackToken(projectRoot) {
180
194
  return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
@@ -185,7 +199,7 @@ async function ensureServerForCli(projectRoot) {
185
199
  if (selected?.connection.kind === "remote") {
186
200
  reportServerPhase(`Connecting to ${selected.alias}\u2026`);
187
201
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
188
- const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
202
+ const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
189
203
  return {
190
204
  baseUrl: selected.connection.baseUrl,
191
205
  authToken,
@@ -214,7 +228,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
214
228
  if (!slug)
215
229
  return null;
216
230
  try {
217
- const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
231
+ const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
232
+ if (authToken && queryAuthFallbackEnabled())
233
+ url.searchParams.set("rt", authToken);
234
+ const response = await fetch(url, {
218
235
  headers: mergeHeaders(undefined, authToken)
219
236
  });
220
237
  if (!response.ok)
@@ -231,10 +248,23 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
231
248
  return null;
232
249
  }
233
250
  }
251
+ function mergeCookie(existing, name, value) {
252
+ const encoded = `${name}=${encodeURIComponent(value)}`;
253
+ if (!existing?.trim())
254
+ return encoded;
255
+ const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
256
+ return [...parts, encoded].join("; ");
257
+ }
258
+ function queryAuthFallbackEnabled(env = process.env) {
259
+ return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
260
+ }
234
261
  function mergeHeaders(headers, authToken) {
235
262
  const merged = new Headers(headers);
236
263
  if (authToken) {
237
- merged.set("authorization", `Bearer ${authToken}`);
264
+ const bearer = `Bearer ${authToken}`;
265
+ merged.set("authorization", bearer);
266
+ merged.set("x-auth", bearer);
267
+ merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
238
268
  }
239
269
  return merged;
240
270
  }
@@ -294,15 +324,34 @@ async function buildServerFailureContext(projectRoot, server) {
294
324
  hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
295
325
  };
296
326
  }
327
+ function isLoopbackRemoteBaseUrl(baseUrl) {
328
+ try {
329
+ const host = new URL(baseUrl).hostname.toLowerCase();
330
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
331
+ } catch {
332
+ return false;
333
+ }
334
+ }
335
+ function canUseRemoteWithoutProjectRoot(pathname) {
336
+ return pathname === "/health" || pathname === "/api/health" || pathname === "/api/server/status" || pathname === "/api/server/project-root" || pathname.startsWith("/api/github/auth/") || pathname === "/api/projects" || pathname.startsWith("/api/projects/");
337
+ }
297
338
  async function requestServerJson(context, pathname, init = {}) {
298
339
  const server = await ensureServerForCli(context.projectRoot);
340
+ const requestUrl = new URL(`${server.baseUrl}${pathname}`);
341
+ if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
342
+ const repo = readRepoConnection(context.projectRoot);
343
+ throw new CliError(`Remote server is selected for ${repo?.project ?? "this repo"}, but this checkout has no server-host project root link.`, 1, { hint: "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to repair the remote project link before task/run commands." });
344
+ }
299
345
  const headers = mergeHeaders(init.headers, server.authToken);
300
346
  if (server.serverProjectRoot)
301
347
  headers.set("x-rig-project-root", server.serverProjectRoot);
348
+ if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
349
+ requestUrl.searchParams.set("rt", server.authToken);
350
+ }
302
351
  reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
303
352
  let response;
304
353
  try {
305
- response = await fetch(`${server.baseUrl}${pathname}`, {
354
+ response = await fetch(requestUrl, {
306
355
  ...init,
307
356
  headers
308
357
  });
@@ -686,20 +735,11 @@ var init__doctor_checks = __esm(() => {
686
735
  });
687
736
 
688
737
  // packages/cli/src/app-opentui/adapters/common.ts
689
- function adapterContextFromRuntime(runtime, renderer) {
690
- return {
691
- projectRoot: runtime.getState().projectRoot,
692
- renderer,
693
- ensureRuntime: () => runtime.getRunnerContext(),
694
- emit: (event) => runtime.emit(event),
695
- getState: () => runtime.getState()
696
- };
697
- }
698
738
  function projectRootOf(ctx) {
699
739
  const root = ctx.rig?.projectRoot ?? ctx.projectRoot ?? ctx.getState().projectRoot;
700
740
  if (typeof root === "string" && root.trim())
701
741
  return root;
702
- throw new Error("Rig app adapter requires a projectRoot.");
742
+ throw new Error("App adapter requires a projectRoot.");
703
743
  }
704
744
  function normalizeAppError(error) {
705
745
  const message = error instanceof Error ? error.message : String(error);
@@ -735,20 +775,6 @@ function patchData(ctx, data) {
735
775
  }
736
776
 
737
777
  // packages/cli/src/app-opentui/adapters/doctor.ts
738
- function createDoctorAdapter() {
739
- return {
740
- id: "doctor",
741
- async handleIntent(runtime, intent) {
742
- if (intent.scene !== "doctor" && intent.action.kind !== "doctor-run")
743
- return false;
744
- if (intent.action.kind === "doctor-run" || intent.action.kind === "refresh" || intent.action.kind === "navigate") {
745
- await runDoctorChecksForApp(adapterContextFromRuntime(runtime));
746
- return true;
747
- }
748
- return false;
749
- }
750
- };
751
- }
752
778
  async function runDoctorChecksForApp(ctx) {
753
779
  const label = "Running doctor";
754
780
  emitStarted(ctx, label);
@@ -775,6 +801,5 @@ async function runDoctorChecksForApp(ctx) {
775
801
  }
776
802
  }
777
803
  export {
778
- runDoctorChecksForApp,
779
- createDoctorAdapter
804
+ runDoctorChecksForApp
780
805
  };
@@ -0,0 +1,62 @@
1
+ import type { AppIntent } from "../types";
2
+ import { type AppAdapterContext } from "./common";
3
+ /** A subcommand's flag/option/positional adapted into a typed UI field. */
4
+ export type AppFamilyField = {
5
+ readonly kind: "flag";
6
+ readonly name: string;
7
+ readonly token: string;
8
+ } | {
9
+ readonly kind: "value";
10
+ readonly name: string;
11
+ readonly token: string;
12
+ readonly placeholder: string;
13
+ readonly required: boolean;
14
+ } | {
15
+ readonly kind: "select";
16
+ readonly name: string;
17
+ readonly token: string;
18
+ readonly choices: readonly string[];
19
+ readonly required: boolean;
20
+ } | {
21
+ readonly kind: "positional";
22
+ readonly name: string;
23
+ readonly placeholder: string;
24
+ readonly required: boolean;
25
+ readonly repeatable: boolean;
26
+ };
27
+ /** A catalog subcommand parsed into its base words + adapted fields. */
28
+ export type AppFamilySubcommand = {
29
+ readonly id: string;
30
+ readonly template: string;
31
+ readonly description: string;
32
+ /** The words before the first placeholder/flag — the command's verb path. */
33
+ readonly base: readonly string[];
34
+ readonly fields: readonly AppFamilyField[];
35
+ /** No fields at all → safe to run directly with one Enter. */
36
+ readonly direct: boolean;
37
+ readonly primary: boolean;
38
+ };
39
+ export type AppFamilySnapshot = {
40
+ readonly family: string;
41
+ readonly summary: string;
42
+ readonly usage: readonly string[];
43
+ readonly subcommands: readonly AppFamilySubcommand[];
44
+ /** Captured live state from the family's safe list/status subcommand. */
45
+ readonly state: {
46
+ readonly subcommand: readonly string[] | null;
47
+ readonly ran: boolean;
48
+ readonly ok: boolean;
49
+ readonly lines: readonly string[];
50
+ readonly details: Record<string, unknown> | null;
51
+ };
52
+ readonly refreshedAt: number;
53
+ };
54
+ /** In-progress form: which subcommand is open and the value/flag selections. */
55
+ export type AppFamilyForm = {
56
+ readonly family: string;
57
+ readonly subId: string | null;
58
+ /** flag/positional/value name → set value. Flags store "on"; cleared = unset. */
59
+ readonly values: Record<string, string>;
60
+ };
61
+ export declare function familyCatalog(family: string): AppFamilySnapshot["subcommands"];
62
+ export declare function refreshFamily(ctx: AppAdapterContext, intent?: AppIntent): Promise<AppFamilySnapshot>;