@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
@@ -916,17 +916,21 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
916
916
  const scopedKey = resolve10(projectRoot ?? process.cwd());
917
917
  scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
918
918
  }
919
- function readPrivateRemoteSessionToken(projectRoot) {
919
+ function readRemoteAuthState(projectRoot) {
920
920
  const path = resolve10(projectRoot, ".rig", "state", "github-auth.json");
921
921
  if (!existsSync6(path))
922
922
  return null;
923
923
  try {
924
924
  const parsed = JSON.parse(readFileSync4(path, "utf8"));
925
- return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
925
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
926
926
  } catch {
927
927
  return null;
928
928
  }
929
929
  }
930
+ function readPrivateRemoteSessionToken(projectRoot) {
931
+ const parsed = readRemoteAuthState(projectRoot);
932
+ return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
933
+ }
930
934
  function readGitHubBearerTokenForRemote(projectRoot) {
931
935
  const scopedKey = resolve10(projectRoot);
932
936
  if (scopedGitHubBearerTokens.has(scopedKey))
@@ -937,15 +941,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
937
941
  return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
938
942
  }
939
943
  function readStoredGitHubAuthToken(projectRoot) {
940
- const path = resolve10(projectRoot, ".rig", "state", "github-auth.json");
941
- if (!existsSync6(path))
944
+ const parsed = readRemoteAuthState(projectRoot);
945
+ return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
946
+ }
947
+ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
948
+ const repo = readRepoConnection(projectRoot);
949
+ const slug = repo?.project?.trim();
950
+ if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
942
951
  return null;
943
- try {
944
- const parsed = JSON.parse(readFileSync4(path, "utf8"));
945
- return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
946
- } catch {
952
+ const auth = readRemoteAuthState(projectRoot);
953
+ const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
954
+ const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
955
+ if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
947
956
  return null;
948
- }
957
+ const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
958
+ if (!checkoutBaseDir)
959
+ return null;
960
+ const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
961
+ writeRepoServerProjectRoot(projectRoot, inferred);
962
+ return inferred;
949
963
  }
950
964
  function readLocalConnectionFallbackToken(projectRoot) {
951
965
  return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
@@ -956,7 +970,7 @@ async function ensureServerForCli(projectRoot) {
956
970
  if (selected?.connection.kind === "remote") {
957
971
  reportServerPhase(`Connecting to ${selected.alias}\u2026`);
958
972
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
959
- const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
973
+ const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
960
974
  return {
961
975
  baseUrl: selected.connection.baseUrl,
962
976
  authToken,
@@ -985,7 +999,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
985
999
  if (!slug)
986
1000
  return null;
987
1001
  try {
988
- const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
1002
+ const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
1003
+ if (authToken && queryAuthFallbackEnabled())
1004
+ url.searchParams.set("rt", authToken);
1005
+ const response = await fetch(url, {
989
1006
  headers: mergeHeaders(undefined, authToken)
990
1007
  });
991
1008
  if (!response.ok)
@@ -1012,10 +1029,23 @@ function appendTaskFilterParams(url, filters) {
1012
1029
  if (filters.limit !== undefined)
1013
1030
  url.searchParams.set("limit", String(filters.limit));
1014
1031
  }
1032
+ function mergeCookie(existing, name, value) {
1033
+ const encoded = `${name}=${encodeURIComponent(value)}`;
1034
+ if (!existing?.trim())
1035
+ return encoded;
1036
+ const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
1037
+ return [...parts, encoded].join("; ");
1038
+ }
1039
+ function queryAuthFallbackEnabled(env = process.env) {
1040
+ return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
1041
+ }
1015
1042
  function mergeHeaders(headers, authToken) {
1016
1043
  const merged = new Headers(headers);
1017
1044
  if (authToken) {
1018
- merged.set("authorization", `Bearer ${authToken}`);
1045
+ const bearer = `Bearer ${authToken}`;
1046
+ merged.set("authorization", bearer);
1047
+ merged.set("x-auth", bearer);
1048
+ merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
1019
1049
  }
1020
1050
  return merged;
1021
1051
  }
@@ -1075,15 +1105,34 @@ async function buildServerFailureContext(projectRoot, server) {
1075
1105
  hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
1076
1106
  };
1077
1107
  }
1108
+ function isLoopbackRemoteBaseUrl(baseUrl) {
1109
+ try {
1110
+ const host = new URL(baseUrl).hostname.toLowerCase();
1111
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
1112
+ } catch {
1113
+ return false;
1114
+ }
1115
+ }
1116
+ function canUseRemoteWithoutProjectRoot(pathname) {
1117
+ 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/");
1118
+ }
1078
1119
  async function requestServerJson(context, pathname, init = {}) {
1079
1120
  const server = await ensureServerForCli(context.projectRoot);
1121
+ const requestUrl = new URL(`${server.baseUrl}${pathname}`);
1122
+ if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
1123
+ const repo = readRepoConnection(context.projectRoot);
1124
+ 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." });
1125
+ }
1080
1126
  const headers = mergeHeaders(init.headers, server.authToken);
1081
1127
  if (server.serverProjectRoot)
1082
1128
  headers.set("x-rig-project-root", server.serverProjectRoot);
1129
+ if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
1130
+ requestUrl.searchParams.set("rt", server.authToken);
1131
+ }
1083
1132
  reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
1084
1133
  let response;
1085
1134
  try {
1086
- response = await fetch(`${server.baseUrl}${pathname}`, {
1135
+ response = await fetch(requestUrl, {
1087
1136
  ...init,
1088
1137
  headers
1089
1138
  });
@@ -1145,11 +1194,26 @@ async function getGitHubAuthStatusViaServer(context) {
1145
1194
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
1146
1195
  }
1147
1196
  async function postGitHubTokenViaServer(context, token, options = {}) {
1148
- const payload = await requestServerJson(context, "/api/github/auth/token", {
1149
- method: "POST",
1150
- headers: { "content-type": "application/json" },
1151
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
1152
- });
1197
+ const server = await ensureServerForCli(context.projectRoot);
1198
+ const requestUrl = new URL(`${server.baseUrl}/api/github/auth/token`);
1199
+ reportServerPhase("POST /api/github/auth/token\u2026");
1200
+ let response;
1201
+ try {
1202
+ response = await fetch(requestUrl, {
1203
+ method: "POST",
1204
+ headers: { "content-type": "application/json" },
1205
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
1206
+ });
1207
+ } catch (error) {
1208
+ const failure = await buildServerFailureContext(context.projectRoot, server);
1209
+ throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
1210
+ ${failure.contextLine}`, 1, { hint: failure.hint });
1211
+ }
1212
+ const payload = await response.json().catch(() => null);
1213
+ if (!response.ok) {
1214
+ const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
1215
+ 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`." });
1216
+ }
1153
1217
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
1154
1218
  }
1155
1219
  async function prepareRemoteCheckoutViaServer(context, input) {
@@ -1480,7 +1544,8 @@ async function runFastTaskRunPreflight(context, options = {}) {
1480
1544
  }
1481
1545
  }
1482
1546
  const repo = readRepoConnection(context.projectRoot);
1483
- checks.push(repo ? preflightCheck("project-link", "project linked to Rig server", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to Rig server", legacyServerCompatibility ? "warn" : "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
1547
+ const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
1548
+ checks.push(repo ? preflightCheck("project-link", "project linked to selected server", repo.project ? "pass" : remoteWithoutProjectLink ? "fail" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : " (missing project link)"}`, remoteWithoutProjectLink ? "Run `rig init --repair` or `rig init --yes --repo owner/repo --server remote` to restore the remote project link." : "Run `rig init --yes --repo owner/repo` to record the GitHub repo slug.") : preflightCheck("project-link", "project linked to selected server", legacyServerCompatibility ? "warn" : "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
1484
1549
  try {
1485
1550
  const auth = await request("/api/github/auth/status");
1486
1551
  checks.push(isAuthenticated(auth) ? preflightCheck("github-auth", "GitHub auth valid", "pass") : preflightCheck("github-auth", "GitHub auth valid", legacyServerCompatibility ? "warn" : "fail", "not authenticated", "Run `rig github auth import-gh` or `rig github auth token --token <token>`."));
@@ -1591,18 +1656,8 @@ import {
1591
1656
  readJsonlFile as readJsonlFile2,
1592
1657
  writeAuthorityRunRecord
1593
1658
  } from "@rig/runtime/control-plane/authority-files";
1594
- function normalizeRuntimeAdapter(value) {
1595
- const normalized = value?.trim().toLowerCase();
1596
- if (!normalized) {
1597
- return "pi";
1598
- }
1599
- if (normalized === "codex" || normalized === "codex-cli" || normalized === "codex-app-server" || normalized === "gpt-codex") {
1600
- return "codex";
1601
- }
1602
- if (normalized === "pi" || normalized === "rig-pi" || normalized === "@rig/pi") {
1603
- return "pi";
1604
- }
1605
- return "claude-code";
1659
+ function normalizeRuntimeAdapter(_value) {
1660
+ return "pi";
1606
1661
  }
1607
1662
  function readLatestBeadRecord(projectRoot, taskId) {
1608
1663
  const issuesPath = resolve11(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
@@ -2524,7 +2579,7 @@ var init__operator_surface = __esm(() => {
2524
2579
  });
2525
2580
 
2526
2581
  // packages/cli/src/commands/_pi-frontend.ts
2527
- import { existsSync as existsSync14, mkdirSync as mkdirSync8, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
2582
+ import { existsSync as existsSync14, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
2528
2583
  import { homedir as homedir6, tmpdir } from "os";
2529
2584
  import { join as join3 } from "path";
2530
2585
  import { main as runPiMain } from "@earendil-works/pi-coding-agent";
@@ -2556,10 +2611,27 @@ function buildOperatorPiEnv(input) {
2556
2611
  ...input.serverProjectRoot ? { RIG_PROJECT_ROOT: input.serverProjectRoot } : {}
2557
2612
  };
2558
2613
  }
2614
+ function shouldRequireOperatorTranscript(status) {
2615
+ return typeof status === "string" && TERMINAL_RUN_STATUSES.has(status.trim().toLowerCase());
2616
+ }
2617
+ function missingOperatorTranscriptMessage(runId, status) {
2618
+ const shortRun = runId.trim().slice(0, 8) || "unknown";
2619
+ const statusText = typeof status === "string" && status.trim() ? status.trim() : "terminal";
2620
+ 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.`;
2621
+ }
2622
+ function statusFromRunDetails(run) {
2623
+ if (!run || typeof run !== "object" || Array.isArray(run))
2624
+ return;
2625
+ const record = run;
2626
+ if (typeof record.status === "string")
2627
+ return record.status;
2628
+ const nested = record.run;
2629
+ return nested && typeof nested === "object" && !Array.isArray(nested) ? nested.status : undefined;
2630
+ }
2559
2631
  async function prepareOperatorConsole(context, runId, tempSessionDir) {
2560
2632
  const server = await ensureServerForCli(context.projectRoot);
2561
2633
  const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
2562
- mkdirSync8(localCwd, { recursive: true });
2634
+ mkdirSync9(localCwd, { recursive: true });
2563
2635
  trustDroneCwd(localCwd);
2564
2636
  installRigPiTheme();
2565
2637
  let sessionFileArg = [];
@@ -2581,21 +2653,28 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
2581
2653
  return line;
2582
2654
  }).join(`
2583
2655
  `);
2584
- writeFileSync6(localSessionPath, content);
2656
+ writeFileSync7(localSessionPath, content);
2585
2657
  sessionFileArg = ["--session", localSessionPath];
2586
2658
  }
2587
2659
  } catch {}
2660
+ if (sessionFileArg.length === 0) {
2661
+ const run = await getRunDetailsViaServer(context, runId).catch(() => null);
2662
+ const status = statusFromRunDetails(run);
2663
+ if (shouldRequireOperatorTranscript(status)) {
2664
+ throw new OperatorTranscriptUnavailableError(missingOperatorTranscriptMessage(runId, status));
2665
+ }
2666
+ }
2588
2667
  return { server, sessionFileArg };
2589
2668
  }
2590
2669
  function trustDroneCwd(localCwd) {
2591
2670
  try {
2592
2671
  const agentDir = join3(homedir6(), ".pi", "agent");
2593
- mkdirSync8(agentDir, { recursive: true });
2672
+ mkdirSync9(agentDir, { recursive: true });
2594
2673
  const trustPath = join3(agentDir, "trust.json");
2595
2674
  const store = existsSync14(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
2596
2675
  if (store[localCwd] !== true) {
2597
2676
  store[localCwd] = true;
2598
- writeFileSync6(trustPath, `${JSON.stringify(store, null, "\t")}
2677
+ writeFileSync7(trustPath, `${JSON.stringify(store, null, "\t")}
2599
2678
  `);
2600
2679
  }
2601
2680
  } catch {}
@@ -2603,12 +2682,12 @@ function trustDroneCwd(localCwd) {
2603
2682
  function installRigPiTheme() {
2604
2683
  try {
2605
2684
  const themesDir = join3(homedir6(), ".pi", "agent", "themes");
2606
- mkdirSync8(themesDir, { recursive: true });
2685
+ mkdirSync9(themesDir, { recursive: true });
2607
2686
  const themePath = join3(themesDir, "rig.json");
2608
2687
  const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
2609
2688
  `;
2610
2689
  if (!existsSync14(themePath) || readFileSync10(themePath, "utf8") !== next) {
2611
- writeFileSync6(themePath, next);
2690
+ writeFileSync7(themePath, next);
2612
2691
  }
2613
2692
  } catch {}
2614
2693
  }
@@ -2628,6 +2707,7 @@ async function attachRunBundledPiFrontend(context, input) {
2628
2707
  let detached = false;
2629
2708
  try {
2630
2709
  await runPiMain([
2710
+ "--offline",
2631
2711
  "--no-extensions",
2632
2712
  "--no-skills",
2633
2713
  "--no-prompt-templates",
@@ -2655,10 +2735,17 @@ async function attachRunBundledPiFrontend(context, input) {
2655
2735
  rendered: "stock Pi operator console with the pi-rig extension"
2656
2736
  };
2657
2737
  }
2658
- var RIG_PI_THEME;
2738
+ var TERMINAL_RUN_STATUSES, OperatorTranscriptUnavailableError, RIG_PI_THEME;
2659
2739
  var init__pi_frontend = __esm(() => {
2660
2740
  init__server_client();
2661
2741
  init__async_ui();
2742
+ TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
2743
+ OperatorTranscriptUnavailableError = class OperatorTranscriptUnavailableError extends Error {
2744
+ constructor(message2) {
2745
+ super(message2);
2746
+ this.name = "OperatorTranscriptUnavailableError";
2747
+ }
2748
+ };
2662
2749
  RIG_PI_THEME = {
2663
2750
  $schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
2664
2751
  name: "rig",
@@ -2813,7 +2900,7 @@ async function attachRunOperatorView(context, input) {
2813
2900
  }
2814
2901
  const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
2815
2902
  let timelineCursor = snapshot.timelineCursor;
2816
- while (!detached && !TERMINAL_RUN_STATUSES.has(runStatusFromPayload(snapshot.run))) {
2903
+ while (!detached && !TERMINAL_RUN_STATUSES2.has(runStatusFromPayload(snapshot.run))) {
2817
2904
  await Bun.sleep(pollMs);
2818
2905
  snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
2819
2906
  timelineCursor = snapshot.timelineCursor;
@@ -2825,13 +2912,13 @@ async function attachRunOperatorView(context, input) {
2825
2912
  }
2826
2913
  return { ...snapshot, steered, detached };
2827
2914
  }
2828
- var TERMINAL_RUN_STATUSES;
2915
+ var TERMINAL_RUN_STATUSES2;
2829
2916
  var init__operator_view = __esm(() => {
2830
2917
  init__server_client();
2831
2918
  init__operator_surface();
2832
2919
  init__pi_frontend();
2833
2920
  init__async_ui();
2834
- TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
2921
+ TERMINAL_RUN_STATUSES2 = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
2835
2922
  });
2836
2923
 
2837
2924
  // packages/cli/src/commands/_help-catalog.ts
@@ -3188,30 +3275,62 @@ var init__help_catalog = __esm(() => {
3188
3275
  }
3189
3276
  ];
3190
3277
  ADVANCED_GROUPS = [
3191
- { name: "setup", summary: "Bootstrap/check local setup.", usage: ["rig setup <bootstrap|check|preflight>"], commands: [{ command: "bootstrap|check|preflight", description: "Setup helpers." }] },
3192
- { name: "profile", summary: "Runtime profile/model defaults.", usage: ["rig profile <show|set>"], commands: [{ command: "show", description: "Show active profile." }] },
3278
+ {
3279
+ name: "setup",
3280
+ summary: "Bootstrap/check local setup.",
3281
+ usage: ["rig setup <bootstrap|check|preflight>"],
3282
+ commands: [
3283
+ { command: "bootstrap", description: "Bootstrap local setup dependencies.", primary: true },
3284
+ { command: "check", description: "Check local setup state (toolchain, deps, config).", primary: true },
3285
+ { command: "preflight", description: "Run preflight checks before a run.", primary: true }
3286
+ ]
3287
+ },
3288
+ {
3289
+ name: "profile",
3290
+ summary: "Runtime profile/model defaults.",
3291
+ usage: ["rig profile <show|set>"],
3292
+ commands: [
3293
+ { command: "show", description: "Show the active execution profile.", primary: true },
3294
+ { command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
3295
+ ]
3296
+ },
3193
3297
  {
3194
3298
  name: "review",
3195
3299
  summary: "Inspect or change completion review gate policy.",
3196
3300
  usage: ["rig review <show|set>"],
3197
3301
  commands: [
3198
3302
  { command: "show", description: "Show current review gate settings." },
3199
- { command: "set <off|advisory|required> [--provider greptile]", description: "Change review strictness/provider." }
3303
+ { command: "set <off|advisory|required> [--provider <provider>]", description: "Change review strictness/provider (e.g. --provider greptile)." }
3200
3304
  ],
3201
3305
  examples: ["rig review show", "rig review set required --provider greptile"],
3202
3306
  next: ["Use `rig inbox approvals` for blocked run handoffs."]
3203
3307
  },
3204
3308
  {
3205
3309
  name: "browser",
3206
- summary: "Browser/app diagnostics for browser-required tasks.",
3207
- usage: ["rig browser <help|explain|demo|app|hp-next> [options]"],
3310
+ summary: "Browser workstation actions for browser-required tasks: launch, check, CDP probe, profile reset, and app-specific smokes.",
3311
+ usage: ["rig browser <help|explain|demo|hp-next|cdp-probe|profile-persistence|profile-lock-check|smoke-test> [options]"],
3208
3312
  commands: [
3209
- { command: "help", description: "Rich browser command help (canonical: `rig browser help`)." },
3210
- { command: "explain", description: "Explain the browser-required task contract." },
3211
- { command: "demo", description: "Run browser demo flows against a local page." },
3212
- { command: "app", description: "Launch the Rig Browser workstation app." },
3213
- { command: "hp-next <dev|check|e2e|reset>", description: "Drive the hp-next browser test harness." }
3214
- ]
3313
+ { command: "help", description: "Rich browser command help (canonical: `rig browser help`).", primary: true },
3314
+ { command: "explain", description: "Explain the browser-required task contract and runtime helper commands.", primary: true },
3315
+ { command: "demo [--port <n>] [--profile <name>] [--state-dir <path>] [--target-url <url>] [--keep-open] [--no-build]", description: "Run a guided real browser/agent demo flow.", primary: true },
3316
+ { command: "hp-next dev", description: "Start hp-next Rig Browser in dev/watch mode.", primary: true },
3317
+ { command: "hp-next start", description: "Build/start the hp-next browser workstation without watch mode.", primary: true },
3318
+ { command: "hp-next check", description: "Validate the hp-next CDP endpoint on the configured port.", primary: true },
3319
+ { command: "hp-next e2e", description: "Run hp-next browser e2e smoke checks through Rig Browser.", primary: true },
3320
+ { command: "hp-next reset", description: "Reset the hp-next browser profile when stale browser state is suspected.", primary: true },
3321
+ { command: "cdp-probe", description: "Run an isolated CDP attach/evaluate/layout probe." },
3322
+ { command: "profile-persistence", description: "Verify a named browser profile persists browser state." },
3323
+ { command: "profile-lock-check", description: "Verify concurrent launches reject the same profile." },
3324
+ { command: "smoke-test", description: "Run the browser package smoke test." }
3325
+ ],
3326
+ examples: [
3327
+ "rig browser help",
3328
+ "rig browser hp-next check",
3329
+ "rig browser hp-next e2e",
3330
+ "rig browser cdp-probe",
3331
+ "rig browser profile-lock-check"
3332
+ ],
3333
+ next: ["Inside a task run, use rig-browser-launch, rig-browser-check, and rig-browser-attach-info from the worker PATH."]
3215
3334
  },
3216
3335
  {
3217
3336
  name: "pi",
@@ -3226,12 +3345,60 @@ var init__help_catalog = __esm(() => {
3226
3345
  examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
3227
3346
  next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
3228
3347
  },
3229
- { name: "queue", summary: "Run task queues locally.", usage: ["rig queue run [options]"], commands: [{ command: "run", description: "Process queue work." }] },
3230
- { name: "agent", summary: "Runtime agent workspace helpers.", usage: ["rig agent <list|prepare|run|cleanup>"], commands: [{ command: "list", description: "List prepared agents." }] },
3348
+ {
3349
+ name: "queue",
3350
+ summary: "Run task queues locally.",
3351
+ usage: ["rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]"],
3352
+ commands: [
3353
+ { command: "run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]", description: "Process queue work: drain matching tasks with N workers, optional per-task action and isolation.", primary: true }
3354
+ ]
3355
+ },
3356
+ {
3357
+ name: "agent",
3358
+ summary: "Runtime agent workspace helpers.",
3359
+ usage: ["rig agent <list|prepare|run|cleanup>"],
3360
+ commands: [
3361
+ { command: "list", description: "List prepared agent runtimes.", primary: true },
3362
+ { command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
3363
+ { command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
3364
+ { command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
3365
+ ]
3366
+ },
3231
3367
  { name: "inspector", summary: "Event stream and drift scanners.", usage: ["rig inspector <stream|scan-upstream-drift>"], commands: [{ command: "stream", description: "Stream events." }] },
3232
- { name: "dist", summary: "Build/install packaged Rig CLI.", usage: ["rig dist <build|install|doctor>"], commands: [{ command: "build", description: "Build distribution." }] },
3368
+ {
3369
+ name: "dist",
3370
+ summary: "Build/install packaged Rig CLI.",
3371
+ usage: ["rig dist <build|install|doctor|rebuild-agent>"],
3372
+ commands: [
3373
+ { command: "build [--output-dir <dir>]", description: "Build the distributable Rig CLI.", primary: true },
3374
+ { command: "install [--scope <scope>] [--path <path>]", description: "Install the built CLI to a scope/path.", primary: true },
3375
+ { command: "doctor", description: "Diagnose the dist toolchain and install state.", primary: true },
3376
+ { command: "rebuild-agent", description: "Rebuild the agent runtime image, pruning stale images.", primary: true }
3377
+ ]
3378
+ },
3233
3379
  { name: "workspace", summary: "Workspace topology/service helpers.", usage: ["rig workspace <summary|topology|remote-hosts>"], commands: [{ command: "summary", description: "Show workspace summary." }] },
3234
- { name: "remote", summary: "Compatibility remote orchestration controls.", usage: ["rig remote <status|watch|pause|resume|...>"], commands: [{ command: "status", description: "Show remote state." }] },
3380
+ {
3381
+ name: "remote",
3382
+ summary: "Compatibility remote orchestration controls.",
3383
+ usage: ["rig remote <status|tasks|watch|pause|resume|continue|stop|refresh|add-iterations|remove-iterations|endpoint ...>"],
3384
+ commands: [
3385
+ { command: "status [--remote <alias>]", description: "Show the remote orchestration state.", primary: true },
3386
+ { command: "tasks [--remote <alias>]", description: "List the remote's tracked tasks.", primary: true },
3387
+ { command: "watch [--remote <alias>] [--seconds <n>] [--event <type>]", description: "Stream remote orchestration events.", primary: true },
3388
+ { command: "pause [--remote <alias>]", description: "Pause the running remote orchestration.", primary: true },
3389
+ { command: "resume [--remote <alias>] [--max-workers <n>] [--max-iterations <n>] [--direct-merge]", description: "Resume the remote with optional tuning.", primary: true },
3390
+ { command: "continue [--remote <alias>]", description: "Continue a paused remote orchestration.", primary: true },
3391
+ { command: "stop [--remote <alias>]", description: "Stop the remote orchestration.", primary: true },
3392
+ { command: "refresh [--remote <alias>]", description: "Refresh remote state.", primary: true },
3393
+ { command: "add-iterations [--count <n>] [--remote <alias>]", description: "Grant the remote more iterations.", primary: true },
3394
+ { command: "remove-iterations [--count <n>] [--remote <alias>]", description: "Reduce the remote's iteration budget.", primary: true },
3395
+ { command: "endpoint list", description: "List configured remote endpoints.", primary: true },
3396
+ { command: "endpoint add --alias <alias> --host <host> --port <n> [--token <token>]", description: "Register a remote endpoint.", primary: true },
3397
+ { command: "endpoint remove --alias <alias>", description: "Remove a remote endpoint.", primary: true },
3398
+ { command: "endpoint test [--alias <alias>]", description: "Test connectivity to a remote endpoint.", primary: true },
3399
+ { command: "endpoint doctor", description: "Diagnose remote endpoint configuration.", primary: true }
3400
+ ]
3401
+ },
3235
3402
  { name: "git", summary: "Pass through to Rig git-flow helper.", usage: ["rig git <args...>"], commands: [{ command: "<args...>", description: "Advanced git flow operations." }] },
3236
3403
  { name: "harness", summary: "Pass through to runtime harness CLI.", usage: ["rig harness <args...>"], commands: [{ command: "<args...>", description: "Advanced harness operations." }] },
3237
3404
  { name: "test", summary: "Project test wrappers.", usage: ["rig test <unit|e2e|all>"], commands: [{ command: "all", description: "Run configured project tests." }] }
@@ -3298,7 +3465,7 @@ var init__task_picker = __esm(() => {
3298
3465
  // packages/cli/src/commands/task.ts
3299
3466
  import { readFileSync as readFileSync11 } from "fs";
3300
3467
  import { spawnSync as spawnSync3 } from "child_process";
3301
- import { resolve as resolve21 } from "path";
3468
+ import { resolve as resolve22 } from "path";
3302
3469
  import {
3303
3470
  taskArtifactDir,
3304
3471
  taskArtifacts,
@@ -3576,7 +3743,7 @@ async function executeTask(context, args, options) {
3576
3743
  const fileFlag = takeOption(rest.slice(1), "--file");
3577
3744
  let content;
3578
3745
  if (fileFlag.value) {
3579
- content = readFileSync11(resolve21(context.projectRoot, fileFlag.value), "utf-8");
3746
+ content = readFileSync11(resolve22(context.projectRoot, fileFlag.value), "utf-8");
3580
3747
  } else {
3581
3748
  content = await readStdin();
3582
3749
  }
@@ -3814,6 +3981,47 @@ var init_task = __esm(() => {
3814
3981
  init__connection_state();
3815
3982
  });
3816
3983
 
3984
+ // packages/cli/src/commands/_server-events.ts
3985
+ import { WsTransport } from "@rig/client";
3986
+ import { RIG_WS_CHANNELS } from "@rig/contracts";
3987
+ function buildRigWebSocketUrl(baseUrl, authToken) {
3988
+ const url = new URL(baseUrl);
3989
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
3990
+ if (authToken)
3991
+ url.searchParams.set("token", authToken);
3992
+ return url.toString();
3993
+ }
3994
+ async function connectRigServerEvents(projectRoot, handlers) {
3995
+ const { baseUrl, authToken } = await ensureServerForCli(projectRoot);
3996
+ const transport = new WsTransport(buildRigWebSocketUrl(baseUrl, authToken));
3997
+ const unsubscribers = [];
3998
+ if (handlers.onSnapshotInvalidated)
3999
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.snapshotInvalidated, handlers.onSnapshotInvalidated));
4000
+ if (handlers.onRunLogAppended)
4001
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.runLogAppended, handlers.onRunLogAppended));
4002
+ if (handlers.onEngineEvent)
4003
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.event, handlers.onEngineEvent));
4004
+ let status = "connecting";
4005
+ unsubscribers.push(transport.subscribeState((state) => {
4006
+ status = state.status;
4007
+ handlers.onStatus?.(state.status);
4008
+ }));
4009
+ return {
4010
+ connected: () => status === "connected",
4011
+ close: () => {
4012
+ for (const unsubscribe of unsubscribers) {
4013
+ try {
4014
+ unsubscribe();
4015
+ } catch {}
4016
+ }
4017
+ transport.dispose();
4018
+ }
4019
+ };
4020
+ }
4021
+ var init__server_events = __esm(() => {
4022
+ init__server_client();
4023
+ });
4024
+
3817
4025
  // packages/cli/src/app/board.ts
3818
4026
  var exports_board = {};
3819
4027
  __export(exports_board, {
@@ -4652,21 +4860,39 @@ async function runOperatorBoard(context, options = {}) {
4652
4860
  tui.requestRender();
4653
4861
  }
4654
4862
  }, BOARD_TICK_MS);
4863
+ const live = { subscription: null };
4864
+ const refreshActiveView = () => {
4865
+ refresh({ quiet: true });
4866
+ if (view === "tasks")
4867
+ refreshTasks();
4868
+ if (view === "inbox")
4869
+ refreshInbox();
4870
+ };
4871
+ connectRigServerEvents(context.projectRoot, {
4872
+ onSnapshotInvalidated: () => refreshActiveView()
4873
+ }).then((subscription) => {
4874
+ live.subscription = subscription;
4875
+ }).catch(() => {
4876
+ live.subscription = null;
4877
+ });
4655
4878
  const refreshTimer = setInterval(() => {
4879
+ if (live.subscription?.connected())
4880
+ return;
4656
4881
  refresh();
4657
4882
  }, BOARD_REFRESH_MS);
4658
4883
  tui.start();
4659
4884
  refresh({ quiet: true });
4660
- await new Promise((resolve24) => {
4885
+ await new Promise((resolve25) => {
4661
4886
  const poll = setInterval(() => {
4662
4887
  if (stopped) {
4663
4888
  clearInterval(poll);
4664
- resolve24();
4889
+ resolve25();
4665
4890
  }
4666
4891
  }, 50);
4667
4892
  });
4668
4893
  clearInterval(animation);
4669
4894
  clearInterval(refreshTimer);
4895
+ live.subscription?.close();
4670
4896
  return outcome;
4671
4897
  }
4672
4898
  async function runOperatorBoardLoop(context, attach, options = {}) {
@@ -4685,6 +4911,7 @@ var init_board = __esm(() => {
4685
4911
  init__help_catalog();
4686
4912
  init__server_client();
4687
4913
  init__authority_runs();
4914
+ init__server_events();
4688
4915
  init_inbox();
4689
4916
  init_task();
4690
4917
  });
@@ -4695,7 +4922,7 @@ import {
4695
4922
  existsSync as existsSync18,
4696
4923
  readFileSync as readFileSync13
4697
4924
  } from "fs";
4698
- import { resolve as resolve24 } from "path";
4925
+ import { resolve as resolve25 } from "path";
4699
4926
  import { readBuildConfig } from "@rig/runtime/build-time-config";
4700
4927
 
4701
4928
  // packages/cli/src/commands/browser.ts
@@ -8923,14 +9150,64 @@ Usage: rig init`, 1);
8923
9150
  // packages/cli/src/commands/github.ts
8924
9151
  init_runner();
8925
9152
  init__server_client();
9153
+ init__connection_state();
8926
9154
  init__async_ui();
8927
9155
  import { spawnSync as spawnSync2 } from "child_process";
9156
+ import { mkdirSync as mkdirSync8, writeFileSync as writeFileSync6 } from "fs";
9157
+ import { dirname as dirname4, resolve as resolve18 } from "path";
8928
9158
  function printPayload(context, payload, fallback) {
8929
9159
  if (context.outputMode === "json")
8930
9160
  console.log(JSON.stringify(payload, null, 2));
8931
9161
  else
8932
9162
  console.log(fallback);
8933
9163
  }
9164
+ function apiSessionTokenFrom2(payload) {
9165
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
9166
+ return null;
9167
+ const token = payload.apiSessionToken;
9168
+ return typeof token === "string" && token.trim() ? token.trim() : null;
9169
+ }
9170
+ function payloadString(payload, key) {
9171
+ const value = payload[key];
9172
+ return typeof value === "string" && value.trim() ? value.trim() : null;
9173
+ }
9174
+ function payloadRecord(payload, key) {
9175
+ const value = payload[key];
9176
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9177
+ }
9178
+ function remoteNamespaceMetadata(result) {
9179
+ const namespace = payloadRecord(result, "userNamespace");
9180
+ return {
9181
+ ...payloadString(result, "login") ? { login: payloadString(result, "login") } : {},
9182
+ ...payloadString(result, "userId") ? { userId: payloadString(result, "userId") } : {},
9183
+ ...namespace && payloadString(namespace, "key") ? { userNamespaceKey: payloadString(namespace, "key") } : {},
9184
+ ...namespace && payloadString(namespace, "root") ? { userNamespaceRoot: payloadString(namespace, "root") } : {},
9185
+ ...namespace && payloadString(namespace, "checkoutBaseDir") ? { checkoutBaseDir: payloadString(namespace, "checkoutBaseDir") } : {},
9186
+ ...namespace && payloadString(namespace, "snapshotBaseDir") ? { snapshotBaseDir: payloadString(namespace, "snapshotBaseDir") } : {}
9187
+ };
9188
+ }
9189
+ function persistRemoteAuthSession(context, source, result, fallbackToken) {
9190
+ const apiSessionToken = apiSessionTokenFrom2(result);
9191
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? fallbackToken, context.projectRoot);
9192
+ if (!apiSessionToken)
9193
+ return;
9194
+ const repo = readRepoConnection(context.projectRoot);
9195
+ const path = resolve18(context.projectRoot, ".rig", "state", "github-auth.json");
9196
+ mkdirSync8(dirname4(path), { recursive: true });
9197
+ writeFileSync6(path, `${JSON.stringify({
9198
+ authenticated: true,
9199
+ source,
9200
+ storedOnServer: true,
9201
+ ...repo?.project ? { selectedRepo: repo.project } : {},
9202
+ ...remoteNamespaceMetadata(result),
9203
+ apiSessionToken,
9204
+ updatedAt: new Date().toISOString()
9205
+ }, null, 2)}
9206
+ `, "utf8");
9207
+ }
9208
+ function isSignedIn(status) {
9209
+ return status.signedIn === true || status.authenticated === true;
9210
+ }
8934
9211
  function readGhToken() {
8935
9212
  const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
8936
9213
  if (result.status !== 0) {
@@ -8952,7 +9229,7 @@ async function executeGithub(context, args) {
8952
9229
  if (rest.length > 0)
8953
9230
  throw new CliError("Usage: rig github auth status", 1);
8954
9231
  const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
8955
- printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
9232
+ printPayload(context, status, `GitHub auth: ${isSignedIn(status) ? "authenticated" : "unauthenticated"}`);
8956
9233
  return { ok: true, group: "github", command: "auth status", details: status };
8957
9234
  }
8958
9235
  case "token": {
@@ -8962,16 +9239,20 @@ async function executeGithub(context, args) {
8962
9239
  const token = parsed.value?.trim();
8963
9240
  if (!token)
8964
9241
  throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
8965
- const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
8966
- printPayload(context, result, "GitHub token stored on the selected Rig server.");
9242
+ const repo = readRepoConnection(context.projectRoot);
9243
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token, repo?.project ? { selectedRepo: repo.project } : {}), { outputMode: context.outputMode });
9244
+ persistRemoteAuthSession(context, "token", result, token);
9245
+ printPayload(context, result, "GitHub token stored on the selected server.");
8967
9246
  return { ok: true, group: "github", command: "auth token", details: result };
8968
9247
  }
8969
9248
  case "import-gh": {
8970
9249
  if (rest.length > 0)
8971
9250
  throw new CliError("Usage: rig github auth import-gh", 1);
8972
9251
  const importedToken = readGhToken();
8973
- const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
8974
- printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
9252
+ const repo = readRepoConnection(context.projectRoot);
9253
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken, repo?.project ? { selectedRepo: repo.project } : {}), { outputMode: context.outputMode });
9254
+ persistRemoteAuthSession(context, "gh", result, importedToken);
9255
+ printPayload(context, result, "GitHub token imported from gh and stored on the selected server.");
8975
9256
  return { ok: true, group: "github", command: "auth import-gh", details: result };
8976
9257
  }
8977
9258
  default:
@@ -9001,7 +9282,7 @@ init_runner();
9001
9282
  init__authority_runs();
9002
9283
  init__paths();
9003
9284
  import { readFileSync as readFileSync8 } from "fs";
9004
- import { resolve as resolve18 } from "path";
9285
+ import { resolve as resolve19 } from "path";
9005
9286
  import {
9006
9287
  appendRunJournalEvent,
9007
9288
  appendRunLogEntry,
@@ -9038,7 +9319,7 @@ function touchAuthorityRun(projectRoot, runId) {
9038
9319
  if (!current) {
9039
9320
  return;
9040
9321
  }
9041
- writeJsonFile3(resolve18(resolveAuthorityRunDir(projectRoot, runId), "run.json"), {
9322
+ writeJsonFile3(resolve19(resolveAuthorityRunDir(projectRoot, runId), "run.json"), {
9042
9323
  ...current,
9043
9324
  updatedAt: new Date().toISOString()
9044
9325
  });
@@ -9276,7 +9557,7 @@ init_runner();
9276
9557
  init__server_client();
9277
9558
  init__async_ui();
9278
9559
  import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
9279
- import { resolve as resolve19 } from "path";
9560
+ import { resolve as resolve20 } from "path";
9280
9561
  import {
9281
9562
  listAuthorityRuns,
9282
9563
  readAuthorityRun as readAuthorityRun3,
@@ -9320,7 +9601,7 @@ async function executeInspect(context, args) {
9320
9601
  }
9321
9602
  return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
9322
9603
  }
9323
- const logsPath = resolve19(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
9604
+ const logsPath = resolve20(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
9324
9605
  if (!existsSync12(logsPath)) {
9325
9606
  throw new CliError(`No logs found for run ${latestRun.runId}.`, 1, { hint: `Try \`rig run show ${latestRun.runId}\` or \`rig run replay ${latestRun.runId}\`.` });
9326
9607
  }
@@ -9408,7 +9689,7 @@ async function executeInspect(context, args) {
9408
9689
  return { ok: true, group: "inspect", command };
9409
9690
  case "audit": {
9410
9691
  requireNoExtraArgs(rest, "rig inspect audit");
9411
- const auditPath = resolve19(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
9692
+ const auditPath = resolve20(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
9412
9693
  if (!existsSync12(auditPath)) {
9413
9694
  console.log("No audit log found.");
9414
9695
  } else {
@@ -10067,7 +10348,7 @@ import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/co
10067
10348
 
10068
10349
  // packages/cli/src/commands/_run-replay.ts
10069
10350
  import { existsSync as existsSync13, readdirSync as readdirSync2 } from "fs";
10070
- import { join as join2, resolve as resolve20 } from "path";
10351
+ import { join as join2, resolve as resolve21 } from "path";
10071
10352
  import {
10072
10353
  readAuthorityRun as readAuthorityRun4,
10073
10354
  readJsonlFile as readJsonlFile3,
@@ -10160,7 +10441,7 @@ function resolveRunSessionFile(record) {
10160
10441
  const sessionId = text(piSession.sessionId);
10161
10442
  if (!cwd || !sessionId)
10162
10443
  return null;
10163
- const sessionDir = resolve20(cwd, ".rig", "session");
10444
+ const sessionDir = resolve21(cwd, ".rig", "session");
10164
10445
  try {
10165
10446
  const match = readdirSync2(sessionDir).find((name) => name.endsWith(`_${sessionId}.jsonl`));
10166
10447
  return match ? join2(sessionDir, match) : null;
@@ -10658,6 +10939,9 @@ async function executeRun(context, args) {
10658
10939
  console.log(`Stop requested: ${runId}`);
10659
10940
  return { ok: true, group: "run", command, details: stopped };
10660
10941
  }
10942
+ if (isRemoteConnectionSelected(context.projectRoot)) {
10943
+ throw new CliError("Remote run stop requires an explicit run id.", 2, { hint: "Run `rig run list`, then `rig run stop <run-id>`." });
10944
+ }
10661
10945
  const result = await runStop(context.projectRoot);
10662
10946
  if (result.remaining.length > 0) {
10663
10947
  throw new CliError(`Failed to stop run(s): ${result.remaining.join(", ")}`, 1, { hint: "Check `rig run status`, then retry `rig run stop <run-id>` for the remaining runs." });
@@ -10774,7 +11058,13 @@ async function executeConnectionCommand(context, args, options) {
10774
11058
  if (!state.connections[alias])
10775
11059
  throw new CliError(`Unknown Rig server: ${alias}`, 1, { hint: "Run `rig server list` to see saved aliases, or save one with `rig server add <alias> <url>`." });
10776
11060
  }
10777
- const repoState = { selected: alias, linkedAt: new Date().toISOString() };
11061
+ const previousRepo = readRepoConnection(context.projectRoot);
11062
+ const repoState = {
11063
+ selected: alias,
11064
+ ...previousRepo?.project ? { project: previousRepo.project } : {},
11065
+ linkedAt: new Date().toISOString(),
11066
+ ...previousRepo?.serverProjectRoot && previousRepo.selected === alias ? { serverProjectRoot: previousRepo.serverProjectRoot } : {}
11067
+ };
10778
11068
  writeRepoConnection(context.projectRoot, repoState);
10779
11069
  printJsonOrText(context, repoState, formatSuccessCard("Rig server selected", [
10780
11070
  ["selected", alias],
@@ -11009,8 +11299,8 @@ init_task();
11009
11299
 
11010
11300
  // packages/cli/src/commands/task-run-driver.ts
11011
11301
  init_runner();
11012
- import { copyFileSync as copyFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
11013
- import { resolve as resolve22 } from "path";
11302
+ import { copyFileSync as copyFileSync3, existsSync as existsSync15, mkdirSync as mkdirSync10, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
11303
+ import { resolve as resolve23 } from "path";
11014
11304
  import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
11015
11305
  import { createInterface as createLineInterface } from "readline";
11016
11306
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
@@ -11109,12 +11399,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
11109
11399
  return 0;
11110
11400
  let copied = 0;
11111
11401
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
11112
- const sourcePath = resolve22(sourceRoot, relativePath);
11113
- const targetPath = resolve22(targetRoot, relativePath);
11402
+ const sourcePath = resolve23(sourceRoot, relativePath);
11403
+ const targetPath = resolve23(targetRoot, relativePath);
11114
11404
  try {
11115
11405
  if (!statSync2(sourcePath).isFile())
11116
11406
  continue;
11117
- mkdirSync9(resolve22(targetPath, ".."), { recursive: true });
11407
+ mkdirSync10(resolve23(targetPath, ".."), { recursive: true });
11118
11408
  copyFileSync3(sourcePath, targetPath);
11119
11409
  copied += 1;
11120
11410
  } catch {}
@@ -11153,7 +11443,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
11153
11443
  return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
11154
11444
  return {
11155
11445
  RIG_BASELINE_MODE: "dirty-snapshot",
11156
- RIG_DIRTY_BASELINE_READY_FILE: resolve22(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
11446
+ RIG_DIRTY_BASELINE_READY_FILE: resolve23(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
11157
11447
  };
11158
11448
  }
11159
11449
  function positiveInt(value, fallback) {
@@ -11258,9 +11548,9 @@ function createCommandRunner(binary) {
11258
11548
  const stderrChunks = [];
11259
11549
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
11260
11550
  child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
11261
- return await new Promise((resolve23) => {
11262
- child.once("error", (error) => resolve23({ exitCode: 1, stderr: error.message }));
11263
- child.once("close", (code) => resolve23({
11551
+ return await new Promise((resolve24) => {
11552
+ child.once("error", (error) => resolve24({ exitCode: 1, stderr: error.message }));
11553
+ child.once("close", (code) => resolve24({
11264
11554
  exitCode: code ?? 1,
11265
11555
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
11266
11556
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -11334,7 +11624,7 @@ async function runTaskRunPostValidationLifecycle(input) {
11334
11624
  config,
11335
11625
  sourceTask: input.sourceTask,
11336
11626
  uploadedSnapshot: input.uploadedSnapshot,
11337
- artifactRoot: resolve22(input.projectRoot, "artifacts", taskId3),
11627
+ artifactRoot: resolve23(input.projectRoot, "artifacts", taskId3),
11338
11628
  command: ghCommand,
11339
11629
  gitCommand,
11340
11630
  steerPi,
@@ -11464,7 +11754,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
11464
11754
  return null;
11465
11755
  }
11466
11756
  for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
11467
- const summary = readJsonFile3(resolve22(artifactDir, "validation-summary.json"), null);
11757
+ const summary = readJsonFile3(resolve23(artifactDir, "validation-summary.json"), null);
11468
11758
  if (!summary || summary.status !== "fail") {
11469
11759
  continue;
11470
11760
  }
@@ -11545,9 +11835,9 @@ function readTaskRunAcceptedArtifactState(input) {
11545
11835
  if (!input.taskId || !input.workspaceDir) {
11546
11836
  return { accepted: false, reason: null };
11547
11837
  }
11548
- const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
11549
- const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
11550
- const taskResultPath = resolve22(artifactDir, "task-result.json");
11838
+ const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
11839
+ const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
11840
+ const taskResultPath = resolve23(artifactDir, "task-result.json");
11551
11841
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
11552
11842
  if (reviewStatus !== "APPROVED") {
11553
11843
  return { accepted: false, reason: null };
@@ -11584,12 +11874,12 @@ function resolveTaskRunRetryContext(input) {
11584
11874
  if (!input.taskId || !input.workspaceDir) {
11585
11875
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
11586
11876
  }
11587
- const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
11588
- const reviewStatePath = resolve22(artifactDir, "review-state.json");
11589
- const reviewFeedbackPath = resolve22(artifactDir, "review-feedback.md");
11590
- const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
11591
- const failedApproachesPath = resolve22(input.workspaceDir, ".rig", "state", "failed_approaches.md");
11592
- const validationSummaryPath = resolve22(artifactDir, "validation-summary.json");
11877
+ const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
11878
+ const reviewStatePath = resolve23(artifactDir, "review-state.json");
11879
+ const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
11880
+ const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
11881
+ const failedApproachesPath = resolve23(input.workspaceDir, ".rig", "state", "failed_approaches.md");
11882
+ const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
11593
11883
  const reviewState = readJsonFile3(reviewStatePath, null);
11594
11884
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
11595
11885
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -11999,15 +12289,15 @@ async function executeRigOwnedTaskRun(context, input) {
11999
12289
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
12000
12290
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
12001
12291
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
12002
- const planningArtifactPath = resolve22("artifacts", runtimeTaskId, "implementation-plan.md");
12292
+ const planningArtifactPath = resolve23("artifacts", runtimeTaskId, "implementation-plan.md");
12003
12293
  const persistedPlanning = {
12004
12294
  ...planningClassification,
12005
12295
  classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
12006
12296
  artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
12007
12297
  classifiedAt: new Date().toISOString()
12008
12298
  };
12009
- mkdirSync9(resolve22(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
12010
- writeFileSync7(resolve22(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
12299
+ mkdirSync10(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
12300
+ writeFileSync8(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
12011
12301
  `, "utf8");
12012
12302
  patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
12013
12303
  prompt = `${prompt}
@@ -12057,7 +12347,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12057
12347
  let verificationStarted = false;
12058
12348
  let reviewStarted = false;
12059
12349
  let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
12060
- let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve22(existingRunRecord.sessionPath, "..") : null;
12350
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve23(existingRunRecord.sessionPath, "..") : null;
12061
12351
  let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
12062
12352
  let latestProviderCommand = null;
12063
12353
  let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
@@ -12143,10 +12433,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12143
12433
  setRunStatusOrFail(context.projectRoot, input.runId, "running");
12144
12434
  patchAuthorityRun(context.projectRoot, input.runId, {
12145
12435
  worktreePath: latestRuntimeWorkspace,
12146
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve22(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
12436
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve23(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
12147
12437
  logRoot: latestLogsDir,
12148
- sessionPath: latestSessionDir ? resolve22(latestSessionDir, "session.json") : null,
12149
- sessionLogPath: latestLogsDir ? resolve22(latestLogsDir, "agent-stdout.log") : null,
12438
+ sessionPath: latestSessionDir ? resolve23(latestSessionDir, "session.json") : null,
12439
+ sessionLogPath: latestLogsDir ? resolve23(latestLogsDir, "agent-stdout.log") : null,
12150
12440
  branch: runtimeId
12151
12441
  });
12152
12442
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
@@ -12154,8 +12444,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12154
12444
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
12155
12445
  const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
12156
12446
  if (readyFile) {
12157
- mkdirSync9(resolve22(readyFile, ".."), { recursive: true });
12158
- writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
12447
+ mkdirSync10(resolve23(readyFile, ".."), { recursive: true });
12448
+ writeFileSync8(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
12159
12449
  `, "utf8");
12160
12450
  }
12161
12451
  appendRunLog(context.projectRoot, input.runId, {
@@ -12551,7 +12841,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12551
12841
  let acceptedArtifactObservedAt = null;
12552
12842
  let acceptedArtifactPollTimer = null;
12553
12843
  let acceptedArtifactKillTimer = null;
12554
- const attemptExit = await new Promise((resolve23) => {
12844
+ const attemptExit = await new Promise((resolve24) => {
12555
12845
  let settled = false;
12556
12846
  const settle = (result) => {
12557
12847
  if (settled)
@@ -12559,7 +12849,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12559
12849
  settled = true;
12560
12850
  if (acceptedArtifactPollTimer)
12561
12851
  clearInterval(acceptedArtifactPollTimer);
12562
- resolve23(result);
12852
+ resolve24(result);
12563
12853
  };
12564
12854
  const pollAcceptedArtifacts = () => {
12565
12855
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -12762,7 +13052,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
12762
13052
  }
12763
13053
  if (planningClassification.planningRequired) {
12764
13054
  const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
12765
- const expectedPlanPath = resolve22(planWorkspace, planningArtifactPath);
13055
+ const expectedPlanPath = resolve23(planWorkspace, planningArtifactPath);
12766
13056
  if (!existsSync15(expectedPlanPath)) {
12767
13057
  const failedAt = new Date().toISOString();
12768
13058
  const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
@@ -12932,9 +13222,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
12932
13222
  });
12933
13223
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
12934
13224
  });
12935
- const exitCode = await new Promise((resolve23) => {
12936
- child.once("error", () => resolve23(1));
12937
- child.once("close", (code) => resolve23(code ?? 1));
13225
+ const exitCode = await new Promise((resolve24) => {
13226
+ child.once("error", () => resolve24(1));
13227
+ child.once("close", (code) => resolve24(code ?? 1));
12938
13228
  });
12939
13229
  for (const pendingLog of flushPendingClaudeToolUseLogs({
12940
13230
  runId: input.runId,
@@ -13075,8 +13365,8 @@ async function executeTest(context, args) {
13075
13365
  init_runner();
13076
13366
  init__parsers();
13077
13367
  init__paths();
13078
- import { existsSync as existsSync16, mkdirSync as mkdirSync10, readdirSync as readdirSync3, writeFileSync as writeFileSync8 } from "fs";
13079
- import { resolve as resolve23 } from "path";
13368
+ import { existsSync as existsSync16, mkdirSync as mkdirSync11, readdirSync as readdirSync3, writeFileSync as writeFileSync9 } from "fs";
13369
+ import { resolve as resolve24 } from "path";
13080
13370
  import { createPluginHost } from "@rig/core";
13081
13371
  import {
13082
13372
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -13131,12 +13421,12 @@ function runSetupInit(projectRoot) {
13131
13421
  const stateDir = resolveControlPlaneHostStateDir(projectRoot);
13132
13422
  const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
13133
13423
  const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
13134
- mkdirSync10(stateDir, { recursive: true });
13135
- mkdirSync10(logsDir, { recursive: true });
13136
- mkdirSync10(artifactsDir, { recursive: true });
13137
- const failuresPath = resolve23(stateDir, "failed_approaches.md");
13424
+ mkdirSync11(stateDir, { recursive: true });
13425
+ mkdirSync11(logsDir, { recursive: true });
13426
+ mkdirSync11(artifactsDir, { recursive: true });
13427
+ const failuresPath = resolve24(stateDir, "failed_approaches.md");
13138
13428
  if (!existsSync16(failuresPath)) {
13139
- writeFileSync8(failuresPath, `# Failed Approaches
13429
+ writeFileSync9(failuresPath, `# Failed Approaches
13140
13430
 
13141
13431
  `, "utf-8");
13142
13432
  }
@@ -13153,17 +13443,17 @@ async function runSetupCheck(projectRoot, outputMode = "text") {
13153
13443
  }
13154
13444
  async function runSetupPreflight(projectRoot, outputMode = "text") {
13155
13445
  await runSetupCheck(projectRoot, outputMode);
13156
- const validationRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
13446
+ const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
13157
13447
  if (existsSync16(validationRoot)) {
13158
13448
  const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
13159
13449
  for (const validator of validators) {
13160
- const script = resolve23(validationRoot, validator.name, "validate.sh");
13450
+ const script = resolve24(validationRoot, validator.name, "validate.sh");
13161
13451
  if (existsSync16(script)) {
13162
13452
  console.log(`OK: validator script ${script}`);
13163
13453
  }
13164
13454
  }
13165
13455
  }
13166
- const hooksRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
13456
+ const hooksRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
13167
13457
  if (existsSync16(hooksRoot)) {
13168
13458
  const hooks = readdirSync3(hooksRoot).filter((name) => name.endsWith(".sh"));
13169
13459
  for (const hook of hooks) {
@@ -13310,7 +13600,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
13310
13600
  ]);
13311
13601
  var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
13312
13602
  function hasInitializedRigProject(projectRoot) {
13313
- return RIG_CONFIG_FILENAMES.some((name) => existsSync18(resolve24(projectRoot, name))) || existsSync18(resolve24(projectRoot, ".rig"));
13603
+ return RIG_CONFIG_FILENAMES.some((name) => existsSync18(resolve25(projectRoot, name))) || existsSync18(resolve25(projectRoot, ".rig"));
13314
13604
  }
13315
13605
  function requireInitializedRigProject(context, group) {
13316
13606
  if (hasInitializedRigProject(context.projectRoot)) {
@@ -13364,7 +13654,7 @@ function resolveTopLevelLaunchState(context) {
13364
13654
  let selectedServer = null;
13365
13655
  if (projectInitialized) {
13366
13656
  try {
13367
- const statePath = resolve24(context.projectRoot, ".rig", "state", "connection.json");
13657
+ const statePath = resolve25(context.projectRoot, ".rig", "state", "connection.json");
13368
13658
  if (existsSync18(statePath)) {
13369
13659
  const parsed = JSON.parse(readFileSync13(statePath, "utf-8"));
13370
13660
  selectedServer = parsed.remoteUrl || parsed.url || parsed.selected || null;
@@ -13373,8 +13663,14 @@ function resolveTopLevelLaunchState(context) {
13373
13663
  }
13374
13664
  return { projectInitialized, selectedServer, version: process.env.RIG_CLI_VERSION || readBuildConfig().RIG_CLI_VERSION || undefined };
13375
13665
  }
13666
+ function envTruthy(value) {
13667
+ if (!value)
13668
+ return false;
13669
+ const normalized = value.trim().toLowerCase();
13670
+ return normalized !== "0" && normalized !== "false" && normalized !== "no";
13671
+ }
13376
13672
  function shouldOpenApp(context) {
13377
- return context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
13673
+ return context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1" && process.env.RIG_PLAIN !== "1" && !envTruthy(process.env.CI);
13378
13674
  }
13379
13675
  async function openApp(context, options = {}) {
13380
13676
  const { runOperatorBoardLoop: runOperatorBoardLoop2 } = await Promise.resolve().then(() => (init_board(), exports_board));