@h-rig/cli 0.0.6-alpha.82 → 0.0.6-alpha.83

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 (100) hide show
  1. package/dist/bin/build-rig-binaries.js +40 -8
  2. package/dist/bin/rig.js +2798 -1440
  3. package/dist/src/app/board.js +62 -13
  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.js +63 -14
  8. package/dist/src/app-opentui/adapters/fleet.js +84 -20
  9. package/dist/src/app-opentui/adapters/inbox.js +83 -19
  10. package/dist/src/app-opentui/adapters/init.js +87 -23
  11. package/dist/src/app-opentui/adapters/pi-attach.js +96 -34
  12. package/dist/src/app-opentui/adapters/run-detail.js +83 -19
  13. package/dist/src/app-opentui/adapters/server.js +100 -23
  14. package/dist/src/app-opentui/adapters/tasks.d.ts +11 -0
  15. package/dist/src/app-opentui/adapters/tasks.js +742 -94
  16. package/dist/src/app-opentui/bootstrap.d.ts +1 -6
  17. package/dist/src/app-opentui/bootstrap.js +13769 -12368
  18. package/dist/src/app-opentui/command-pty-host.d.ts +62 -0
  19. package/dist/src/app-opentui/command-pty-host.js +248 -0
  20. package/dist/src/app-opentui/events.js +1 -1
  21. package/dist/src/app-opentui/focus-manager.d.ts +14 -0
  22. package/dist/src/app-opentui/focus-manager.js +24 -0
  23. package/dist/src/app-opentui/index.js +3802 -2882
  24. package/dist/src/app-opentui/intent.js +154 -48
  25. package/dist/src/app-opentui/keymap.d.ts +20 -0
  26. package/dist/src/app-opentui/keymap.js +707 -0
  27. package/dist/src/app-opentui/launch-routing.d.ts +16 -0
  28. package/dist/src/app-opentui/launch-routing.js +55 -0
  29. package/dist/src/app-opentui/layout.js +2 -2
  30. package/dist/src/app-opentui/pi-host-child.js +66 -16
  31. package/dist/src/app-opentui/pi-pty-host.d.ts +9 -0
  32. package/dist/src/app-opentui/pi-pty-host.js +9 -11
  33. package/dist/src/app-opentui/registry.js +3231 -2403
  34. package/dist/src/app-opentui/render/ascii-fleet.d.ts +15 -0
  35. package/dist/src/app-opentui/render/ascii-fleet.js +82 -0
  36. package/dist/src/app-opentui/render/graphics.d.ts +1 -1
  37. package/dist/src/app-opentui/render/graphics.js +131 -16
  38. package/dist/src/app-opentui/render/image-visual-layer-worker.js +408 -957
  39. package/dist/src/app-opentui/render/image-visual-layer.d.ts +18 -10
  40. package/dist/src/app-opentui/render/image-visual-layer.js +386 -356
  41. package/dist/src/app-opentui/render/panel-layout.d.ts +38 -0
  42. package/dist/src/app-opentui/render/panel-layout.js +48 -0
  43. package/dist/src/app-opentui/render/panels.d.ts +2 -0
  44. package/dist/src/app-opentui/render/panels.js +62 -29
  45. package/dist/src/app-opentui/render/preloader.d.ts +10 -0
  46. package/dist/src/app-opentui/render/preloader.js +163 -0
  47. package/dist/src/app-opentui/render/scene.d.ts +3 -0
  48. package/dist/src/app-opentui/render/scene.js +12 -0
  49. package/dist/src/app-opentui/render/text.js +5 -1
  50. package/dist/src/app-opentui/render/type-bar.d.ts +2 -1
  51. package/dist/src/app-opentui/render/type-bar.js +51 -16
  52. package/dist/src/app-opentui/runtime-resources.d.ts +16 -0
  53. package/dist/src/app-opentui/runtime-resources.js +62 -0
  54. package/dist/src/app-opentui/runtime.js +2322 -1513
  55. package/dist/src/app-opentui/scenes/command.d.ts +3 -0
  56. package/dist/src/app-opentui/scenes/command.js +103 -0
  57. package/dist/src/app-opentui/scenes/doctor.d.ts +2 -1
  58. package/dist/src/app-opentui/scenes/doctor.js +53 -14
  59. package/dist/src/app-opentui/scenes/error.js +44 -14
  60. package/dist/src/app-opentui/scenes/fleet.js +40 -21
  61. package/dist/src/app-opentui/scenes/handoff.js +142 -27
  62. package/dist/src/app-opentui/scenes/help.js +63 -48
  63. package/dist/src/app-opentui/scenes/inbox.d.ts +2 -1
  64. package/dist/src/app-opentui/scenes/inbox.js +64 -17
  65. package/dist/src/app-opentui/scenes/init.d.ts +2 -1
  66. package/dist/src/app-opentui/scenes/init.js +62 -21
  67. package/dist/src/app-opentui/scenes/main.d.ts +2 -1
  68. package/dist/src/app-opentui/scenes/main.js +80 -24
  69. package/dist/src/app-opentui/scenes/run-detail.d.ts +2 -1
  70. package/dist/src/app-opentui/scenes/run-detail.js +39 -25
  71. package/dist/src/app-opentui/scenes/server.d.ts +2 -1
  72. package/dist/src/app-opentui/scenes/server.js +71 -20
  73. package/dist/src/app-opentui/scenes/tasks.js +44 -22
  74. package/dist/src/app-opentui/state.js +70 -30
  75. package/dist/src/app-opentui/terminal-capabilities.d.ts +7 -0
  76. package/dist/src/app-opentui/terminal-capabilities.js +15 -0
  77. package/dist/src/app-opentui/types.d.ts +10 -2
  78. package/dist/src/commands/_doctor-checks.js +62 -13
  79. package/dist/src/commands/_operator-view.js +63 -13
  80. package/dist/src/commands/_pi-frontend.js +63 -13
  81. package/dist/src/commands/_preflight.js +64 -14
  82. package/dist/src/commands/_server-client.js +82 -18
  83. package/dist/src/commands/_snapshot-upload.js +62 -13
  84. package/dist/src/commands/connect.js +7 -1
  85. package/dist/src/commands/doctor.js +62 -13
  86. package/dist/src/commands/github.js +144 -23
  87. package/dist/src/commands/inbox.js +62 -13
  88. package/dist/src/commands/init.js +82 -18
  89. package/dist/src/commands/inspect.js +62 -13
  90. package/dist/src/commands/run.js +66 -13
  91. package/dist/src/commands/server.js +69 -14
  92. package/dist/src/commands/setup.js +62 -13
  93. package/dist/src/commands/stats.js +62 -13
  94. package/dist/src/commands/task-run-driver.js +62 -13
  95. package/dist/src/commands/task.js +65 -14
  96. package/dist/src/commands.js +227 -92
  97. package/dist/src/index.js +234 -99
  98. package/package.json +8 -9
  99. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.d.ts +0 -2
  100. package/dist/src/app-opentui/render/image-visual-layer-native-canvas.js +0 -1484
@@ -192,17 +192,21 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
192
192
  const scopedKey = resolve2(projectRoot ?? process.cwd());
193
193
  scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
194
194
  }
195
- function readPrivateRemoteSessionToken(projectRoot) {
195
+ function readRemoteAuthState(projectRoot) {
196
196
  const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
197
197
  if (!existsSync2(path))
198
198
  return null;
199
199
  try {
200
200
  const parsed = JSON.parse(readFileSync2(path, "utf8"));
201
- return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
201
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
202
202
  } catch {
203
203
  return null;
204
204
  }
205
205
  }
206
+ function readPrivateRemoteSessionToken(projectRoot) {
207
+ const parsed = readRemoteAuthState(projectRoot);
208
+ return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
209
+ }
206
210
  function readGitHubBearerTokenForRemote(projectRoot) {
207
211
  const scopedKey = resolve2(projectRoot);
208
212
  if (scopedGitHubBearerTokens.has(scopedKey))
@@ -213,15 +217,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
213
217
  return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
214
218
  }
215
219
  function readStoredGitHubAuthToken(projectRoot) {
216
- const path = resolve2(projectRoot, ".rig", "state", "github-auth.json");
217
- if (!existsSync2(path))
220
+ const parsed = readRemoteAuthState(projectRoot);
221
+ return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
222
+ }
223
+ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
224
+ const repo = readRepoConnection(projectRoot);
225
+ const slug = repo?.project?.trim();
226
+ if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
218
227
  return null;
219
- try {
220
- const parsed = JSON.parse(readFileSync2(path, "utf8"));
221
- return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
222
- } catch {
228
+ const auth = readRemoteAuthState(projectRoot);
229
+ const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
230
+ const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
231
+ if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
223
232
  return null;
224
- }
233
+ const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
234
+ if (!checkoutBaseDir)
235
+ return null;
236
+ const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
237
+ writeRepoServerProjectRoot(projectRoot, inferred);
238
+ return inferred;
225
239
  }
226
240
  function readLocalConnectionFallbackToken(projectRoot) {
227
241
  return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
@@ -232,7 +246,7 @@ async function ensureServerForCli(projectRoot) {
232
246
  if (selected?.connection.kind === "remote") {
233
247
  reportServerPhase(`Connecting to ${selected.alias}\u2026`);
234
248
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
235
- const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
249
+ const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
236
250
  return {
237
251
  baseUrl: selected.connection.baseUrl,
238
252
  authToken,
@@ -261,7 +275,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
261
275
  if (!slug)
262
276
  return null;
263
277
  try {
264
- const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
278
+ const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
279
+ if (authToken && queryAuthFallbackEnabled())
280
+ url.searchParams.set("rt", authToken);
281
+ const response = await fetch(url, {
265
282
  headers: mergeHeaders(undefined, authToken)
266
283
  });
267
284
  if (!response.ok)
@@ -288,10 +305,23 @@ function appendTaskFilterParams(url, filters) {
288
305
  if (filters.limit !== undefined)
289
306
  url.searchParams.set("limit", String(filters.limit));
290
307
  }
308
+ function mergeCookie(existing, name, value) {
309
+ const encoded = `${name}=${encodeURIComponent(value)}`;
310
+ if (!existing?.trim())
311
+ return encoded;
312
+ const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
313
+ return [...parts, encoded].join("; ");
314
+ }
315
+ function queryAuthFallbackEnabled(env = process.env) {
316
+ return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
317
+ }
291
318
  function mergeHeaders(headers, authToken) {
292
319
  const merged = new Headers(headers);
293
320
  if (authToken) {
294
- merged.set("authorization", `Bearer ${authToken}`);
321
+ const bearer = `Bearer ${authToken}`;
322
+ merged.set("authorization", bearer);
323
+ merged.set("x-auth", bearer);
324
+ merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
295
325
  }
296
326
  return merged;
297
327
  }
@@ -351,15 +381,34 @@ async function buildServerFailureContext(projectRoot, server) {
351
381
  hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
352
382
  };
353
383
  }
384
+ function isLoopbackRemoteBaseUrl(baseUrl) {
385
+ try {
386
+ const host = new URL(baseUrl).hostname.toLowerCase();
387
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
388
+ } catch {
389
+ return false;
390
+ }
391
+ }
392
+ function canUseRemoteWithoutProjectRoot(pathname) {
393
+ 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/");
394
+ }
354
395
  async function requestServerJson(context, pathname, init = {}) {
355
396
  const server = await ensureServerForCli(context.projectRoot);
397
+ const requestUrl = new URL(`${server.baseUrl}${pathname}`);
398
+ if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
399
+ const repo = readRepoConnection(context.projectRoot);
400
+ 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." });
401
+ }
356
402
  const headers = mergeHeaders(init.headers, server.authToken);
357
403
  if (server.serverProjectRoot)
358
404
  headers.set("x-rig-project-root", server.serverProjectRoot);
405
+ if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
406
+ requestUrl.searchParams.set("rt", server.authToken);
407
+ }
359
408
  reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
360
409
  let response;
361
410
  try {
362
- response = await fetch(`${server.baseUrl}${pathname}`, {
411
+ response = await fetch(requestUrl, {
363
412
  ...init,
364
413
  headers
365
414
  });
@@ -421,11 +470,26 @@ async function getGitHubAuthStatusViaServer(context) {
421
470
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
422
471
  }
423
472
  async function postGitHubTokenViaServer(context, token, options = {}) {
424
- const payload = await requestServerJson(context, "/api/github/auth/token", {
425
- method: "POST",
426
- headers: { "content-type": "application/json" },
427
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
428
- });
473
+ const server = await ensureServerForCli(context.projectRoot);
474
+ const requestUrl = new URL(`${server.baseUrl}/api/github/auth/token`);
475
+ reportServerPhase("POST /api/github/auth/token\u2026");
476
+ let response;
477
+ try {
478
+ response = await fetch(requestUrl, {
479
+ method: "POST",
480
+ headers: { "content-type": "application/json" },
481
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
482
+ });
483
+ } catch (error) {
484
+ const failure = await buildServerFailureContext(context.projectRoot, server);
485
+ throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
486
+ ${failure.contextLine}`, 1, { hint: failure.hint });
487
+ }
488
+ const payload = await response.json().catch(() => null);
489
+ if (!response.ok) {
490
+ const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
491
+ throw new CliError(`Rig server auth bootstrap failed (${response.status}): ${detail}`, 1, { hint: "Re-run `rig github auth import-gh`, or check the selected server with `rig server status`." });
492
+ }
429
493
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
430
494
  }
431
495
  async function prepareRemoteCheckoutViaServer(context, input) {
@@ -716,7 +780,7 @@ function projectRootOf(ctx) {
716
780
  const root = ctx.rig?.projectRoot ?? ctx.projectRoot ?? ctx.getState().projectRoot;
717
781
  if (typeof root === "string" && root.trim())
718
782
  return root;
719
- throw new Error("Rig app adapter requires a projectRoot.");
783
+ throw new Error("App adapter requires a projectRoot.");
720
784
  }
721
785
  function emitStarted(ctx, label, optimistic) {
722
786
  ctx.emit({ type: "action.started", label, ...optimistic ? { optimistic } : {} });
@@ -749,22 +813,35 @@ function createServerAdapter() {
749
813
  }
750
814
  };
751
815
  }
816
+ function withTimeout(promise, ms, label) {
817
+ return new Promise((resolve3, reject) => {
818
+ const timer = setTimeout(() => reject(new Error(`${label} timed out after ${ms}ms`)), ms);
819
+ promise.then((value) => {
820
+ clearTimeout(timer);
821
+ resolve3(value);
822
+ }, (error) => {
823
+ clearTimeout(timer);
824
+ reject(error);
825
+ });
826
+ });
827
+ }
752
828
  async function refreshServerStatus(ctx) {
753
829
  const label = "Checking server";
754
830
  emitStarted(ctx, label);
831
+ patchData(ctx, { server: { label: "checking selected server", reachable: false, error: "checking selected server\u2026" } });
755
832
  const started = Date.now();
756
833
  try {
757
834
  const { ensureServerForCli: ensureServerForCli2, requestServerJson: requestServerJson2, resolveServerConnectionLabel: resolveServerConnectionLabel2 } = await Promise.resolve().then(() => (init__server_client(), exports__server_client));
758
835
  const projectRoot = projectRootOf(ctx);
759
- emitProgress(ctx, label, "resolving selected Rig server");
836
+ emitProgress(ctx, label, "resolving selected server");
760
837
  const [connectionLabel, server] = await Promise.all([
761
838
  resolveServerConnectionLabel2(projectRoot),
762
- ensureServerForCli2(projectRoot)
839
+ withTimeout(ensureServerForCli2(projectRoot), 5000, "server connection")
763
840
  ]);
764
841
  emitProgress(ctx, label, "requesting server status", { baseUrl: server.baseUrl, kind: server.connectionKind });
765
842
  const [status, auth] = await Promise.all([
766
- requestServerJson2({ projectRoot }, "/api/server/status").catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) })),
767
- requestServerJson2({ projectRoot }, "/api/github/auth/status").catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }))
843
+ withTimeout(requestServerJson2({ projectRoot }, "/api/server/status"), 5000, "server status").catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) })),
844
+ withTimeout(requestServerJson2({ projectRoot }, "/api/github/auth/status"), 5000, "github auth status").catch((error) => ({ ok: false, error: error instanceof Error ? error.message : String(error) }))
768
845
  ]);
769
846
  const state = {
770
847
  label: connectionLabel,
@@ -11,6 +11,11 @@ export type AppTaskFilters = {
11
11
  readonly label?: string;
12
12
  readonly search?: string;
13
13
  };
14
+ export type AppTaskActiveRun = {
15
+ readonly runId: string;
16
+ readonly status?: string;
17
+ readonly stage?: string;
18
+ };
14
19
  export type AppTaskRecord = {
15
20
  readonly id: string;
16
21
  readonly status: string;
@@ -20,6 +25,7 @@ export type AppTaskRecord = {
20
25
  readonly createdAt?: string;
21
26
  readonly labels: readonly string[];
22
27
  readonly assignees: readonly string[];
28
+ readonly activeRun?: AppTaskActiveRun;
23
29
  readonly raw: Record<string, unknown>;
24
30
  };
25
31
  export type AppTaskViewState = {
@@ -31,6 +37,8 @@ export type AppTaskViewState = {
31
37
  readonly totalCount: number;
32
38
  readonly visibleCount: number;
33
39
  };
40
+ export declare function activeRunIdFromTaskLike(task: Record<string, unknown>): string | undefined;
41
+ export declare function activeRunIdFromTaskRunError(error: unknown): string | null;
34
42
  export declare function normalizeTaskRecord(record: Record<string, unknown>): AppTaskRecord | null;
35
43
  export declare function refreshTasks(ctx: AppAdapterContext, input?: AppTaskFilters & {
36
44
  readonly sort?: AppTaskSort | string;
@@ -40,6 +48,7 @@ export declare function submitTaskRun(ctx: AppAdapterContext, input?: {
40
48
  readonly title?: string;
41
49
  readonly initialPrompt?: string;
42
50
  readonly runId?: string;
51
+ readonly detach?: boolean;
43
52
  }): Promise<{
44
53
  runId: string;
45
54
  }>;
@@ -47,6 +56,8 @@ export declare function submitNextTaskRun(ctx: AppAdapterContext, filters?: {
47
56
  readonly assignee?: string;
48
57
  readonly state?: string;
49
58
  readonly status?: string;
59
+ }, options?: {
60
+ readonly detach?: boolean;
50
61
  }): Promise<{
51
62
  runId: string;
52
63
  task: AppTaskRecord | null;