@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
package/dist/src/index.js CHANGED
@@ -1105,17 +1105,21 @@ function setGitHubBearerTokenForCurrentProcess(token, projectRoot) {
1105
1105
  const scopedKey = resolve11(projectRoot ?? process.cwd());
1106
1106
  scopedGitHubBearerTokens.set(scopedKey, cleanToken(token ?? undefined));
1107
1107
  }
1108
- function readPrivateRemoteSessionToken(projectRoot) {
1108
+ function readRemoteAuthState(projectRoot) {
1109
1109
  const path = resolve11(projectRoot, ".rig", "state", "github-auth.json");
1110
1110
  if (!existsSync7(path))
1111
1111
  return null;
1112
1112
  try {
1113
1113
  const parsed = JSON.parse(readFileSync4(path, "utf8"));
1114
- return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
1114
+ return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
1115
1115
  } catch {
1116
1116
  return null;
1117
1117
  }
1118
1118
  }
1119
+ function readPrivateRemoteSessionToken(projectRoot) {
1120
+ const parsed = readRemoteAuthState(projectRoot);
1121
+ return parsed ? cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined) : null;
1122
+ }
1119
1123
  function readGitHubBearerTokenForRemote(projectRoot) {
1120
1124
  const scopedKey = resolve11(projectRoot);
1121
1125
  if (scopedGitHubBearerTokens.has(scopedKey))
@@ -1126,15 +1130,25 @@ function readGitHubBearerTokenForRemote(projectRoot) {
1126
1130
  return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
1127
1131
  }
1128
1132
  function readStoredGitHubAuthToken(projectRoot) {
1129
- const path = resolve11(projectRoot, ".rig", "state", "github-auth.json");
1130
- if (!existsSync7(path))
1133
+ const parsed = readRemoteAuthState(projectRoot);
1134
+ return parsed ? cleanToken(typeof parsed.token === "string" ? parsed.token : undefined) : null;
1135
+ }
1136
+ function inferRemoteServerProjectRootFromAuthState(projectRoot) {
1137
+ const repo = readRepoConnection(projectRoot);
1138
+ const slug = repo?.project?.trim();
1139
+ if (!slug || !/^[^/]+\/[^/]+$/.test(slug))
1131
1140
  return null;
1132
- try {
1133
- const parsed = JSON.parse(readFileSync4(path, "utf8"));
1134
- return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
1135
- } catch {
1141
+ const auth = readRemoteAuthState(projectRoot);
1142
+ const authUpdatedAt = typeof auth?.updatedAt === "string" ? Date.parse(auth.updatedAt) : Number.NaN;
1143
+ const repoLinkedAt = typeof repo?.linkedAt === "string" ? Date.parse(repo.linkedAt) : Number.NaN;
1144
+ if (Number.isFinite(authUpdatedAt) && Number.isFinite(repoLinkedAt) && authUpdatedAt + 1000 < repoLinkedAt)
1136
1145
  return null;
1137
- }
1146
+ const checkoutBaseDir = typeof auth?.checkoutBaseDir === "string" && auth.checkoutBaseDir.trim() ? auth.checkoutBaseDir.trim() : null;
1147
+ if (!checkoutBaseDir)
1148
+ return null;
1149
+ const inferred = `${checkoutBaseDir.replace(/\/+$/, "")}/${slug}`;
1150
+ writeRepoServerProjectRoot(projectRoot, inferred);
1151
+ return inferred;
1138
1152
  }
1139
1153
  function readLocalConnectionFallbackToken(projectRoot) {
1140
1154
  return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
@@ -1145,7 +1159,7 @@ async function ensureServerForCli(projectRoot) {
1145
1159
  if (selected?.connection.kind === "remote") {
1146
1160
  reportServerPhase(`Connecting to ${selected.alias}\u2026`);
1147
1161
  const authToken = readGitHubBearerTokenForRemote(projectRoot);
1148
- const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
1162
+ const serverProjectRoot = selected.serverProjectRoot ?? inferRemoteServerProjectRootFromAuthState(projectRoot) ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
1149
1163
  return {
1150
1164
  baseUrl: selected.connection.baseUrl,
1151
1165
  authToken,
@@ -1174,7 +1188,10 @@ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken)
1174
1188
  if (!slug)
1175
1189
  return null;
1176
1190
  try {
1177
- const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
1191
+ const url = new URL(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`);
1192
+ if (authToken && queryAuthFallbackEnabled())
1193
+ url.searchParams.set("rt", authToken);
1194
+ const response = await fetch(url, {
1178
1195
  headers: mergeHeaders(undefined, authToken)
1179
1196
  });
1180
1197
  if (!response.ok)
@@ -1201,10 +1218,23 @@ function appendTaskFilterParams(url, filters) {
1201
1218
  if (filters.limit !== undefined)
1202
1219
  url.searchParams.set("limit", String(filters.limit));
1203
1220
  }
1221
+ function mergeCookie(existing, name, value) {
1222
+ const encoded = `${name}=${encodeURIComponent(value)}`;
1223
+ if (!existing?.trim())
1224
+ return encoded;
1225
+ const parts = existing.split(";").map((part) => part.trim()).filter((part) => part && !part.startsWith(`${name}=`));
1226
+ return [...parts, encoded].join("; ");
1227
+ }
1228
+ function queryAuthFallbackEnabled(env = process.env) {
1229
+ return env.RIG_ENABLE_QUERY_AUTH_FALLBACK === "1" || env.RIG_QUERY_AUTH_FALLBACK === "1";
1230
+ }
1204
1231
  function mergeHeaders(headers, authToken) {
1205
1232
  const merged = new Headers(headers);
1206
1233
  if (authToken) {
1207
- merged.set("authorization", `Bearer ${authToken}`);
1234
+ const bearer = `Bearer ${authToken}`;
1235
+ merged.set("authorization", bearer);
1236
+ merged.set("x-auth", bearer);
1237
+ merged.set("cookie", mergeCookie(merged.get("cookie"), "rig_auth", authToken));
1208
1238
  }
1209
1239
  return merged;
1210
1240
  }
@@ -1264,15 +1294,34 @@ async function buildServerFailureContext(projectRoot, server) {
1264
1294
  hint: "Check the selected server with `rig server status`, or switch with `rig server use <alias|local>`."
1265
1295
  };
1266
1296
  }
1297
+ function isLoopbackRemoteBaseUrl(baseUrl) {
1298
+ try {
1299
+ const host = new URL(baseUrl).hostname.toLowerCase();
1300
+ return host === "localhost" || host === "127.0.0.1" || host === "::1" || host === "[::1]";
1301
+ } catch {
1302
+ return false;
1303
+ }
1304
+ }
1305
+ function canUseRemoteWithoutProjectRoot(pathname) {
1306
+ 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/");
1307
+ }
1267
1308
  async function requestServerJson(context, pathname, init = {}) {
1268
1309
  const server = await ensureServerForCli(context.projectRoot);
1310
+ const requestUrl = new URL(`${server.baseUrl}${pathname}`);
1311
+ if (server.connectionKind === "remote" && !server.serverProjectRoot && !canUseRemoteWithoutProjectRoot(requestUrl.pathname) && (server.authToken || !isLoopbackRemoteBaseUrl(server.baseUrl))) {
1312
+ const repo = readRepoConnection(context.projectRoot);
1313
+ 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." });
1314
+ }
1269
1315
  const headers = mergeHeaders(init.headers, server.authToken);
1270
1316
  if (server.serverProjectRoot)
1271
1317
  headers.set("x-rig-project-root", server.serverProjectRoot);
1318
+ if (server.connectionKind === "remote" && server.authToken && queryAuthFallbackEnabled()) {
1319
+ requestUrl.searchParams.set("rt", server.authToken);
1320
+ }
1272
1321
  reportServerPhase(`${(init.method ?? "GET").toUpperCase()} ${pathname.split("?")[0]}\u2026`);
1273
1322
  let response;
1274
1323
  try {
1275
- response = await fetch(`${server.baseUrl}${pathname}`, {
1324
+ response = await fetch(requestUrl, {
1276
1325
  ...init,
1277
1326
  headers
1278
1327
  });
@@ -1334,11 +1383,26 @@ async function getGitHubAuthStatusViaServer(context) {
1334
1383
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
1335
1384
  }
1336
1385
  async function postGitHubTokenViaServer(context, token, options = {}) {
1337
- const payload = await requestServerJson(context, "/api/github/auth/token", {
1338
- method: "POST",
1339
- headers: { "content-type": "application/json" },
1340
- body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
1341
- });
1386
+ const server = await ensureServerForCli(context.projectRoot);
1387
+ const requestUrl = new URL(`${server.baseUrl}/api/github/auth/token`);
1388
+ reportServerPhase("POST /api/github/auth/token\u2026");
1389
+ let response;
1390
+ try {
1391
+ response = await fetch(requestUrl, {
1392
+ method: "POST",
1393
+ headers: { "content-type": "application/json" },
1394
+ body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot ?? server.serverProjectRoot ?? undefined })
1395
+ });
1396
+ } catch (error) {
1397
+ const failure = await buildServerFailureContext(context.projectRoot, server);
1398
+ throw new CliError(`Rig server auth bootstrap failed: ${error instanceof Error ? error.message : String(error)}
1399
+ ${failure.contextLine}`, 1, { hint: failure.hint });
1400
+ }
1401
+ const payload = await response.json().catch(() => null);
1402
+ if (!response.ok) {
1403
+ const detail = payload && typeof payload === "object" && !Array.isArray(payload) ? String(payload.error ?? JSON.stringify(payload)) : `HTTP ${response.status}`;
1404
+ 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`." });
1405
+ }
1342
1406
  return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
1343
1407
  }
1344
1408
  async function prepareRemoteCheckoutViaServer(context, input) {
@@ -1669,7 +1733,8 @@ async function runFastTaskRunPreflight(context, options = {}) {
1669
1733
  }
1670
1734
  }
1671
1735
  const repo = readRepoConnection(context.projectRoot);
1672
- 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>`."));
1736
+ const remoteWithoutProjectLink = selectedServer?.connectionKind === "remote" && !repo?.project;
1737
+ 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>`."));
1673
1738
  try {
1674
1739
  const auth = await request("/api/github/auth/status");
1675
1740
  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>`."));
@@ -1780,18 +1845,8 @@ import {
1780
1845
  readJsonlFile as readJsonlFile2,
1781
1846
  writeAuthorityRunRecord
1782
1847
  } from "@rig/runtime/control-plane/authority-files";
1783
- function normalizeRuntimeAdapter(value) {
1784
- const normalized = value?.trim().toLowerCase();
1785
- if (!normalized) {
1786
- return "pi";
1787
- }
1788
- if (normalized === "codex" || normalized === "codex-cli" || normalized === "codex-app-server" || normalized === "gpt-codex") {
1789
- return "codex";
1790
- }
1791
- if (normalized === "pi" || normalized === "rig-pi" || normalized === "@rig/pi") {
1792
- return "pi";
1793
- }
1794
- return "claude-code";
1848
+ function normalizeRuntimeAdapter(_value) {
1849
+ return "pi";
1795
1850
  }
1796
1851
  function readLatestBeadRecord(projectRoot, taskId) {
1797
1852
  const issuesPath = resolve12(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
@@ -2713,7 +2768,7 @@ var init__operator_surface = __esm(() => {
2713
2768
  });
2714
2769
 
2715
2770
  // packages/cli/src/commands/_pi-frontend.ts
2716
- import { existsSync as existsSync15, mkdirSync as mkdirSync9, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync6 } from "fs";
2771
+ import { existsSync as existsSync15, mkdirSync as mkdirSync10, mkdtempSync, readFileSync as readFileSync10, rmSync as rmSync5, writeFileSync as writeFileSync7 } from "fs";
2717
2772
  import { homedir as homedir6, tmpdir } from "os";
2718
2773
  import { join as join3 } from "path";
2719
2774
  import { main as runPiMain } from "@earendil-works/pi-coding-agent";
@@ -2745,10 +2800,27 @@ function buildOperatorPiEnv(input) {
2745
2800
  ...input.serverProjectRoot ? { RIG_PROJECT_ROOT: input.serverProjectRoot } : {}
2746
2801
  };
2747
2802
  }
2803
+ function shouldRequireOperatorTranscript(status) {
2804
+ return typeof status === "string" && TERMINAL_RUN_STATUSES.has(status.trim().toLowerCase());
2805
+ }
2806
+ function missingOperatorTranscriptMessage(runId, status) {
2807
+ const shortRun = runId.trim().slice(0, 8) || "unknown";
2808
+ const statusText = typeof status === "string" && status.trim() ? status.trim() : "terminal";
2809
+ 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.`;
2810
+ }
2811
+ function statusFromRunDetails(run) {
2812
+ if (!run || typeof run !== "object" || Array.isArray(run))
2813
+ return;
2814
+ const record = run;
2815
+ if (typeof record.status === "string")
2816
+ return record.status;
2817
+ const nested = record.run;
2818
+ return nested && typeof nested === "object" && !Array.isArray(nested) ? nested.status : undefined;
2819
+ }
2748
2820
  async function prepareOperatorConsole(context, runId, tempSessionDir) {
2749
2821
  const server = await ensureServerForCli(context.projectRoot);
2750
2822
  const localCwd = join3(homedir6(), ".rig", "drones", runId.slice(0, 8));
2751
- mkdirSync9(localCwd, { recursive: true });
2823
+ mkdirSync10(localCwd, { recursive: true });
2752
2824
  trustDroneCwd(localCwd);
2753
2825
  installRigPiTheme();
2754
2826
  let sessionFileArg = [];
@@ -2770,21 +2842,28 @@ async function prepareOperatorConsole(context, runId, tempSessionDir) {
2770
2842
  return line;
2771
2843
  }).join(`
2772
2844
  `);
2773
- writeFileSync6(localSessionPath, content);
2845
+ writeFileSync7(localSessionPath, content);
2774
2846
  sessionFileArg = ["--session", localSessionPath];
2775
2847
  }
2776
2848
  } catch {}
2849
+ if (sessionFileArg.length === 0) {
2850
+ const run = await getRunDetailsViaServer(context, runId).catch(() => null);
2851
+ const status = statusFromRunDetails(run);
2852
+ if (shouldRequireOperatorTranscript(status)) {
2853
+ throw new OperatorTranscriptUnavailableError(missingOperatorTranscriptMessage(runId, status));
2854
+ }
2855
+ }
2777
2856
  return { server, sessionFileArg };
2778
2857
  }
2779
2858
  function trustDroneCwd(localCwd) {
2780
2859
  try {
2781
2860
  const agentDir = join3(homedir6(), ".pi", "agent");
2782
- mkdirSync9(agentDir, { recursive: true });
2861
+ mkdirSync10(agentDir, { recursive: true });
2783
2862
  const trustPath = join3(agentDir, "trust.json");
2784
2863
  const store = existsSync15(trustPath) ? JSON.parse(readFileSync10(trustPath, "utf8")) : {};
2785
2864
  if (store[localCwd] !== true) {
2786
2865
  store[localCwd] = true;
2787
- writeFileSync6(trustPath, `${JSON.stringify(store, null, "\t")}
2866
+ writeFileSync7(trustPath, `${JSON.stringify(store, null, "\t")}
2788
2867
  `);
2789
2868
  }
2790
2869
  } catch {}
@@ -2792,12 +2871,12 @@ function trustDroneCwd(localCwd) {
2792
2871
  function installRigPiTheme() {
2793
2872
  try {
2794
2873
  const themesDir = join3(homedir6(), ".pi", "agent", "themes");
2795
- mkdirSync9(themesDir, { recursive: true });
2874
+ mkdirSync10(themesDir, { recursive: true });
2796
2875
  const themePath = join3(themesDir, "rig.json");
2797
2876
  const next = `${JSON.stringify(RIG_PI_THEME, null, "\t")}
2798
2877
  `;
2799
2878
  if (!existsSync15(themePath) || readFileSync10(themePath, "utf8") !== next) {
2800
- writeFileSync6(themePath, next);
2879
+ writeFileSync7(themePath, next);
2801
2880
  }
2802
2881
  } catch {}
2803
2882
  }
@@ -2817,6 +2896,7 @@ async function attachRunBundledPiFrontend(context, input) {
2817
2896
  let detached = false;
2818
2897
  try {
2819
2898
  await runPiMain([
2899
+ "--offline",
2820
2900
  "--no-extensions",
2821
2901
  "--no-skills",
2822
2902
  "--no-prompt-templates",
@@ -2844,10 +2924,17 @@ async function attachRunBundledPiFrontend(context, input) {
2844
2924
  rendered: "stock Pi operator console with the pi-rig extension"
2845
2925
  };
2846
2926
  }
2847
- var RIG_PI_THEME;
2927
+ var TERMINAL_RUN_STATUSES, OperatorTranscriptUnavailableError, RIG_PI_THEME;
2848
2928
  var init__pi_frontend = __esm(() => {
2849
2929
  init__server_client();
2850
2930
  init__async_ui();
2931
+ TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
2932
+ OperatorTranscriptUnavailableError = class OperatorTranscriptUnavailableError extends Error {
2933
+ constructor(message2) {
2934
+ super(message2);
2935
+ this.name = "OperatorTranscriptUnavailableError";
2936
+ }
2937
+ };
2851
2938
  RIG_PI_THEME = {
2852
2939
  $schema: "https://raw.githubusercontent.com/earendil-works/pi/main/packages/coding-agent/src/modes/interactive/theme/theme-schema.json",
2853
2940
  name: "rig",
@@ -3002,7 +3089,7 @@ async function attachRunOperatorView(context, input) {
3002
3089
  }
3003
3090
  const pollMs = Math.max(250, Math.trunc(input.pollMs ?? 2000));
3004
3091
  let timelineCursor = snapshot.timelineCursor;
3005
- while (!detached && !TERMINAL_RUN_STATUSES.has(runStatusFromPayload(snapshot.run))) {
3092
+ while (!detached && !TERMINAL_RUN_STATUSES2.has(runStatusFromPayload(snapshot.run))) {
3006
3093
  await Bun.sleep(pollMs);
3007
3094
  snapshot = await readOperatorSnapshot(context, input.runId, { timelineCursor });
3008
3095
  timelineCursor = snapshot.timelineCursor;
@@ -3014,13 +3101,13 @@ async function attachRunOperatorView(context, input) {
3014
3101
  }
3015
3102
  return { ...snapshot, steered, detached };
3016
3103
  }
3017
- var TERMINAL_RUN_STATUSES;
3104
+ var TERMINAL_RUN_STATUSES2;
3018
3105
  var init__operator_view = __esm(() => {
3019
3106
  init__server_client();
3020
3107
  init__operator_surface();
3021
3108
  init__pi_frontend();
3022
3109
  init__async_ui();
3023
- TERMINAL_RUN_STATUSES = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
3110
+ TERMINAL_RUN_STATUSES2 = new Set(["completed", "failed", "stopped", "cancelled", "canceled", "closed", "merged", "needs_attention", "needs-attention"]);
3024
3111
  });
3025
3112
 
3026
3113
  // packages/cli/src/commands/_help-catalog.ts
@@ -3377,30 +3464,62 @@ var init__help_catalog = __esm(() => {
3377
3464
  }
3378
3465
  ];
3379
3466
  ADVANCED_GROUPS = [
3380
- { name: "setup", summary: "Bootstrap/check local setup.", usage: ["rig setup <bootstrap|check|preflight>"], commands: [{ command: "bootstrap|check|preflight", description: "Setup helpers." }] },
3381
- { name: "profile", summary: "Runtime profile/model defaults.", usage: ["rig profile <show|set>"], commands: [{ command: "show", description: "Show active profile." }] },
3467
+ {
3468
+ name: "setup",
3469
+ summary: "Bootstrap/check local setup.",
3470
+ usage: ["rig setup <bootstrap|check|preflight>"],
3471
+ commands: [
3472
+ { command: "bootstrap", description: "Bootstrap local setup dependencies.", primary: true },
3473
+ { command: "check", description: "Check local setup state (toolchain, deps, config).", primary: true },
3474
+ { command: "preflight", description: "Run preflight checks before a run.", primary: true }
3475
+ ]
3476
+ },
3477
+ {
3478
+ name: "profile",
3479
+ summary: "Runtime profile/model defaults.",
3480
+ usage: ["rig profile <show|set>"],
3481
+ commands: [
3482
+ { command: "show", description: "Show the active execution profile.", primary: true },
3483
+ { command: "set [--model <model>] [--runtime <runtime>] [--plugin <plugin>]", description: "Set model/runtime/plugin profile defaults.", primary: true }
3484
+ ]
3485
+ },
3382
3486
  {
3383
3487
  name: "review",
3384
3488
  summary: "Inspect or change completion review gate policy.",
3385
3489
  usage: ["rig review <show|set>"],
3386
3490
  commands: [
3387
3491
  { command: "show", description: "Show current review gate settings." },
3388
- { command: "set <off|advisory|required> [--provider greptile]", description: "Change review strictness/provider." }
3492
+ { command: "set <off|advisory|required> [--provider <provider>]", description: "Change review strictness/provider (e.g. --provider greptile)." }
3389
3493
  ],
3390
3494
  examples: ["rig review show", "rig review set required --provider greptile"],
3391
3495
  next: ["Use `rig inbox approvals` for blocked run handoffs."]
3392
3496
  },
3393
3497
  {
3394
3498
  name: "browser",
3395
- summary: "Browser/app diagnostics for browser-required tasks.",
3396
- usage: ["rig browser <help|explain|demo|app|hp-next> [options]"],
3499
+ summary: "Browser workstation actions for browser-required tasks: launch, check, CDP probe, profile reset, and app-specific smokes.",
3500
+ usage: ["rig browser <help|explain|demo|hp-next|cdp-probe|profile-persistence|profile-lock-check|smoke-test> [options]"],
3397
3501
  commands: [
3398
- { command: "help", description: "Rich browser command help (canonical: `rig browser help`)." },
3399
- { command: "explain", description: "Explain the browser-required task contract." },
3400
- { command: "demo", description: "Run browser demo flows against a local page." },
3401
- { command: "app", description: "Launch the Rig Browser workstation app." },
3402
- { command: "hp-next <dev|check|e2e|reset>", description: "Drive the hp-next browser test harness." }
3403
- ]
3502
+ { command: "help", description: "Rich browser command help (canonical: `rig browser help`).", primary: true },
3503
+ { command: "explain", description: "Explain the browser-required task contract and runtime helper commands.", primary: true },
3504
+ { 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 },
3505
+ { command: "hp-next dev", description: "Start hp-next Rig Browser in dev/watch mode.", primary: true },
3506
+ { command: "hp-next start", description: "Build/start the hp-next browser workstation without watch mode.", primary: true },
3507
+ { command: "hp-next check", description: "Validate the hp-next CDP endpoint on the configured port.", primary: true },
3508
+ { command: "hp-next e2e", description: "Run hp-next browser e2e smoke checks through Rig Browser.", primary: true },
3509
+ { command: "hp-next reset", description: "Reset the hp-next browser profile when stale browser state is suspected.", primary: true },
3510
+ { command: "cdp-probe", description: "Run an isolated CDP attach/evaluate/layout probe." },
3511
+ { command: "profile-persistence", description: "Verify a named browser profile persists browser state." },
3512
+ { command: "profile-lock-check", description: "Verify concurrent launches reject the same profile." },
3513
+ { command: "smoke-test", description: "Run the browser package smoke test." }
3514
+ ],
3515
+ examples: [
3516
+ "rig browser help",
3517
+ "rig browser hp-next check",
3518
+ "rig browser hp-next e2e",
3519
+ "rig browser cdp-probe",
3520
+ "rig browser profile-lock-check"
3521
+ ],
3522
+ next: ["Inside a task run, use rig-browser-launch, rig-browser-check, and rig-browser-attach-info from the worker PATH."]
3404
3523
  },
3405
3524
  {
3406
3525
  name: "pi",
@@ -3415,12 +3534,60 @@ var init__help_catalog = __esm(() => {
3415
3534
  examples: ["rig pi search subagents", "rig pi add pi-subagents", "rig pi list"],
3416
3535
  next: ["Config-managed extensions: declare `runtime: { pi: { packages: [...] } }` in rig.config.ts \u2014 workers pick them up automatically."]
3417
3536
  },
3418
- { name: "queue", summary: "Run task queues locally.", usage: ["rig queue run [options]"], commands: [{ command: "run", description: "Process queue work." }] },
3419
- { name: "agent", summary: "Runtime agent workspace helpers.", usage: ["rig agent <list|prepare|run|cleanup>"], commands: [{ command: "list", description: "List prepared agents." }] },
3537
+ {
3538
+ name: "queue",
3539
+ summary: "Run task queues locally.",
3540
+ usage: ["rig queue run [--workers <n>] [--max-tasks <n>] [--action validate|verify|pipeline] [--isolation off|worktree] [--no-runtime-reuse] [--fail-fast] [--skip-project-sync]"],
3541
+ commands: [
3542
+ { 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 }
3543
+ ]
3544
+ },
3545
+ {
3546
+ name: "agent",
3547
+ summary: "Runtime agent workspace helpers.",
3548
+ usage: ["rig agent <list|prepare|run|cleanup>"],
3549
+ commands: [
3550
+ { command: "list", description: "List prepared agent runtimes.", primary: true },
3551
+ { command: "prepare [--id <id>] [--mode <mode>] [--task <task>]", description: "Prepare an isolated agent runtime workspace.", primary: true },
3552
+ { command: "run [--id <id>] [--mode <mode>] [--task <task>] [--skip-project-sync]", description: "Prepare (if needed) and run an agent in its workspace.", primary: true },
3553
+ { command: "cleanup [--all] [--id <id>]", description: "Remove prepared agent workspaces.", primary: true }
3554
+ ]
3555
+ },
3420
3556
  { name: "inspector", summary: "Event stream and drift scanners.", usage: ["rig inspector <stream|scan-upstream-drift>"], commands: [{ command: "stream", description: "Stream events." }] },
3421
- { name: "dist", summary: "Build/install packaged Rig CLI.", usage: ["rig dist <build|install|doctor>"], commands: [{ command: "build", description: "Build distribution." }] },
3557
+ {
3558
+ name: "dist",
3559
+ summary: "Build/install packaged Rig CLI.",
3560
+ usage: ["rig dist <build|install|doctor|rebuild-agent>"],
3561
+ commands: [
3562
+ { command: "build [--output-dir <dir>]", description: "Build the distributable Rig CLI.", primary: true },
3563
+ { command: "install [--scope <scope>] [--path <path>]", description: "Install the built CLI to a scope/path.", primary: true },
3564
+ { command: "doctor", description: "Diagnose the dist toolchain and install state.", primary: true },
3565
+ { command: "rebuild-agent", description: "Rebuild the agent runtime image, pruning stale images.", primary: true }
3566
+ ]
3567
+ },
3422
3568
  { name: "workspace", summary: "Workspace topology/service helpers.", usage: ["rig workspace <summary|topology|remote-hosts>"], commands: [{ command: "summary", description: "Show workspace summary." }] },
3423
- { name: "remote", summary: "Compatibility remote orchestration controls.", usage: ["rig remote <status|watch|pause|resume|...>"], commands: [{ command: "status", description: "Show remote state." }] },
3569
+ {
3570
+ name: "remote",
3571
+ summary: "Compatibility remote orchestration controls.",
3572
+ usage: ["rig remote <status|tasks|watch|pause|resume|continue|stop|refresh|add-iterations|remove-iterations|endpoint ...>"],
3573
+ commands: [
3574
+ { command: "status [--remote <alias>]", description: "Show the remote orchestration state.", primary: true },
3575
+ { command: "tasks [--remote <alias>]", description: "List the remote's tracked tasks.", primary: true },
3576
+ { command: "watch [--remote <alias>] [--seconds <n>] [--event <type>]", description: "Stream remote orchestration events.", primary: true },
3577
+ { command: "pause [--remote <alias>]", description: "Pause the running remote orchestration.", primary: true },
3578
+ { command: "resume [--remote <alias>] [--max-workers <n>] [--max-iterations <n>] [--direct-merge]", description: "Resume the remote with optional tuning.", primary: true },
3579
+ { command: "continue [--remote <alias>]", description: "Continue a paused remote orchestration.", primary: true },
3580
+ { command: "stop [--remote <alias>]", description: "Stop the remote orchestration.", primary: true },
3581
+ { command: "refresh [--remote <alias>]", description: "Refresh remote state.", primary: true },
3582
+ { command: "add-iterations [--count <n>] [--remote <alias>]", description: "Grant the remote more iterations.", primary: true },
3583
+ { command: "remove-iterations [--count <n>] [--remote <alias>]", description: "Reduce the remote's iteration budget.", primary: true },
3584
+ { command: "endpoint list", description: "List configured remote endpoints.", primary: true },
3585
+ { command: "endpoint add --alias <alias> --host <host> --port <n> [--token <token>]", description: "Register a remote endpoint.", primary: true },
3586
+ { command: "endpoint remove --alias <alias>", description: "Remove a remote endpoint.", primary: true },
3587
+ { command: "endpoint test [--alias <alias>]", description: "Test connectivity to a remote endpoint.", primary: true },
3588
+ { command: "endpoint doctor", description: "Diagnose remote endpoint configuration.", primary: true }
3589
+ ]
3590
+ },
3424
3591
  { name: "git", summary: "Pass through to Rig git-flow helper.", usage: ["rig git <args...>"], commands: [{ command: "<args...>", description: "Advanced git flow operations." }] },
3425
3592
  { name: "harness", summary: "Pass through to runtime harness CLI.", usage: ["rig harness <args...>"], commands: [{ command: "<args...>", description: "Advanced harness operations." }] },
3426
3593
  { name: "test", summary: "Project test wrappers.", usage: ["rig test <unit|e2e|all>"], commands: [{ command: "all", description: "Run configured project tests." }] }
@@ -3487,7 +3654,7 @@ var init__task_picker = __esm(() => {
3487
3654
  // packages/cli/src/commands/task.ts
3488
3655
  import { readFileSync as readFileSync11 } from "fs";
3489
3656
  import { spawnSync as spawnSync3 } from "child_process";
3490
- import { resolve as resolve22 } from "path";
3657
+ import { resolve as resolve23 } from "path";
3491
3658
  import {
3492
3659
  taskArtifactDir,
3493
3660
  taskArtifacts,
@@ -3765,7 +3932,7 @@ async function executeTask(context, args, options) {
3765
3932
  const fileFlag = takeOption(rest.slice(1), "--file");
3766
3933
  let content;
3767
3934
  if (fileFlag.value) {
3768
- content = readFileSync11(resolve22(context.projectRoot, fileFlag.value), "utf-8");
3935
+ content = readFileSync11(resolve23(context.projectRoot, fileFlag.value), "utf-8");
3769
3936
  } else {
3770
3937
  content = await readStdin();
3771
3938
  }
@@ -4003,6 +4170,47 @@ var init_task = __esm(() => {
4003
4170
  init__connection_state();
4004
4171
  });
4005
4172
 
4173
+ // packages/cli/src/commands/_server-events.ts
4174
+ import { WsTransport } from "@rig/client";
4175
+ import { RIG_WS_CHANNELS } from "@rig/contracts";
4176
+ function buildRigWebSocketUrl(baseUrl, authToken) {
4177
+ const url = new URL(baseUrl);
4178
+ url.protocol = url.protocol === "https:" ? "wss:" : "ws:";
4179
+ if (authToken)
4180
+ url.searchParams.set("token", authToken);
4181
+ return url.toString();
4182
+ }
4183
+ async function connectRigServerEvents(projectRoot, handlers) {
4184
+ const { baseUrl, authToken } = await ensureServerForCli(projectRoot);
4185
+ const transport = new WsTransport(buildRigWebSocketUrl(baseUrl, authToken));
4186
+ const unsubscribers = [];
4187
+ if (handlers.onSnapshotInvalidated)
4188
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.snapshotInvalidated, handlers.onSnapshotInvalidated));
4189
+ if (handlers.onRunLogAppended)
4190
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.runLogAppended, handlers.onRunLogAppended));
4191
+ if (handlers.onEngineEvent)
4192
+ unsubscribers.push(transport.subscribe(RIG_WS_CHANNELS.event, handlers.onEngineEvent));
4193
+ let status = "connecting";
4194
+ unsubscribers.push(transport.subscribeState((state) => {
4195
+ status = state.status;
4196
+ handlers.onStatus?.(state.status);
4197
+ }));
4198
+ return {
4199
+ connected: () => status === "connected",
4200
+ close: () => {
4201
+ for (const unsubscribe of unsubscribers) {
4202
+ try {
4203
+ unsubscribe();
4204
+ } catch {}
4205
+ }
4206
+ transport.dispose();
4207
+ }
4208
+ };
4209
+ }
4210
+ var init__server_events = __esm(() => {
4211
+ init__server_client();
4212
+ });
4213
+
4006
4214
  // packages/cli/src/app/board.ts
4007
4215
  var exports_board = {};
4008
4216
  __export(exports_board, {
@@ -4841,21 +5049,39 @@ async function runOperatorBoard(context, options = {}) {
4841
5049
  tui.requestRender();
4842
5050
  }
4843
5051
  }, BOARD_TICK_MS);
5052
+ const live = { subscription: null };
5053
+ const refreshActiveView = () => {
5054
+ refresh({ quiet: true });
5055
+ if (view === "tasks")
5056
+ refreshTasks();
5057
+ if (view === "inbox")
5058
+ refreshInbox();
5059
+ };
5060
+ connectRigServerEvents(context.projectRoot, {
5061
+ onSnapshotInvalidated: () => refreshActiveView()
5062
+ }).then((subscription) => {
5063
+ live.subscription = subscription;
5064
+ }).catch(() => {
5065
+ live.subscription = null;
5066
+ });
4844
5067
  const refreshTimer = setInterval(() => {
5068
+ if (live.subscription?.connected())
5069
+ return;
4845
5070
  refresh();
4846
5071
  }, BOARD_REFRESH_MS);
4847
5072
  tui.start();
4848
5073
  refresh({ quiet: true });
4849
- await new Promise((resolve25) => {
5074
+ await new Promise((resolve26) => {
4850
5075
  const poll = setInterval(() => {
4851
5076
  if (stopped) {
4852
5077
  clearInterval(poll);
4853
- resolve25();
5078
+ resolve26();
4854
5079
  }
4855
5080
  }, 50);
4856
5081
  });
4857
5082
  clearInterval(animation);
4858
5083
  clearInterval(refreshTimer);
5084
+ live.subscription?.close();
4859
5085
  return outcome;
4860
5086
  }
4861
5087
  async function runOperatorBoardLoop(context, attach, options = {}) {
@@ -4874,6 +5100,7 @@ var init_board = __esm(() => {
4874
5100
  init__help_catalog();
4875
5101
  init__server_client();
4876
5102
  init__authority_runs();
5103
+ init__server_events();
4877
5104
  init_inbox();
4878
5105
  init_task();
4879
5106
  });
@@ -4884,7 +5111,7 @@ import {
4884
5111
  existsSync as existsSync19,
4885
5112
  readFileSync as readFileSync13
4886
5113
  } from "fs";
4887
- import { resolve as resolve25 } from "path";
5114
+ import { resolve as resolve26 } from "path";
4888
5115
  import { readBuildConfig } from "@rig/runtime/build-time-config";
4889
5116
 
4890
5117
  // packages/cli/src/commands/browser.ts
@@ -9112,14 +9339,64 @@ Usage: rig init`, 1);
9112
9339
  // packages/cli/src/commands/github.ts
9113
9340
  init_runner();
9114
9341
  init__server_client();
9342
+ init__connection_state();
9115
9343
  init__async_ui();
9116
9344
  import { spawnSync as spawnSync2 } from "child_process";
9345
+ import { mkdirSync as mkdirSync9, writeFileSync as writeFileSync6 } from "fs";
9346
+ import { dirname as dirname4, resolve as resolve19 } from "path";
9117
9347
  function printPayload(context, payload, fallback) {
9118
9348
  if (context.outputMode === "json")
9119
9349
  console.log(JSON.stringify(payload, null, 2));
9120
9350
  else
9121
9351
  console.log(fallback);
9122
9352
  }
9353
+ function apiSessionTokenFrom2(payload) {
9354
+ if (!payload || typeof payload !== "object" || Array.isArray(payload))
9355
+ return null;
9356
+ const token = payload.apiSessionToken;
9357
+ return typeof token === "string" && token.trim() ? token.trim() : null;
9358
+ }
9359
+ function payloadString(payload, key) {
9360
+ const value = payload[key];
9361
+ return typeof value === "string" && value.trim() ? value.trim() : null;
9362
+ }
9363
+ function payloadRecord(payload, key) {
9364
+ const value = payload[key];
9365
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
9366
+ }
9367
+ function remoteNamespaceMetadata(result) {
9368
+ const namespace = payloadRecord(result, "userNamespace");
9369
+ return {
9370
+ ...payloadString(result, "login") ? { login: payloadString(result, "login") } : {},
9371
+ ...payloadString(result, "userId") ? { userId: payloadString(result, "userId") } : {},
9372
+ ...namespace && payloadString(namespace, "key") ? { userNamespaceKey: payloadString(namespace, "key") } : {},
9373
+ ...namespace && payloadString(namespace, "root") ? { userNamespaceRoot: payloadString(namespace, "root") } : {},
9374
+ ...namespace && payloadString(namespace, "checkoutBaseDir") ? { checkoutBaseDir: payloadString(namespace, "checkoutBaseDir") } : {},
9375
+ ...namespace && payloadString(namespace, "snapshotBaseDir") ? { snapshotBaseDir: payloadString(namespace, "snapshotBaseDir") } : {}
9376
+ };
9377
+ }
9378
+ function persistRemoteAuthSession(context, source, result, fallbackToken) {
9379
+ const apiSessionToken = apiSessionTokenFrom2(result);
9380
+ setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? fallbackToken, context.projectRoot);
9381
+ if (!apiSessionToken)
9382
+ return;
9383
+ const repo = readRepoConnection(context.projectRoot);
9384
+ const path = resolve19(context.projectRoot, ".rig", "state", "github-auth.json");
9385
+ mkdirSync9(dirname4(path), { recursive: true });
9386
+ writeFileSync6(path, `${JSON.stringify({
9387
+ authenticated: true,
9388
+ source,
9389
+ storedOnServer: true,
9390
+ ...repo?.project ? { selectedRepo: repo.project } : {},
9391
+ ...remoteNamespaceMetadata(result),
9392
+ apiSessionToken,
9393
+ updatedAt: new Date().toISOString()
9394
+ }, null, 2)}
9395
+ `, "utf8");
9396
+ }
9397
+ function isSignedIn(status) {
9398
+ return status.signedIn === true || status.authenticated === true;
9399
+ }
9123
9400
  function readGhToken() {
9124
9401
  const result = spawnSync2("gh", ["auth", "token"], { encoding: "utf8" });
9125
9402
  if (result.status !== 0) {
@@ -9141,7 +9418,7 @@ async function executeGithub(context, args) {
9141
9418
  if (rest.length > 0)
9142
9419
  throw new CliError("Usage: rig github auth status", 1);
9143
9420
  const status = await withSpinner("Checking GitHub auth on the server\u2026", () => getGitHubAuthStatusViaServer(context), { outputMode: context.outputMode });
9144
- printPayload(context, status, `GitHub auth: ${status.authenticated ? "authenticated" : "unauthenticated"}`);
9421
+ printPayload(context, status, `GitHub auth: ${isSignedIn(status) ? "authenticated" : "unauthenticated"}`);
9145
9422
  return { ok: true, group: "github", command: "auth status", details: status };
9146
9423
  }
9147
9424
  case "token": {
@@ -9151,16 +9428,20 @@ async function executeGithub(context, args) {
9151
9428
  const token = parsed.value?.trim();
9152
9429
  if (!token)
9153
9430
  throw new CliError("Missing --token value.", 1, { hint: "Re-run as `rig github auth token --token <token>`." });
9154
- const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token), { outputMode: context.outputMode });
9155
- printPayload(context, result, "GitHub token stored on the selected Rig server.");
9431
+ const repo = readRepoConnection(context.projectRoot);
9432
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, token, repo?.project ? { selectedRepo: repo.project } : {}), { outputMode: context.outputMode });
9433
+ persistRemoteAuthSession(context, "token", result, token);
9434
+ printPayload(context, result, "GitHub token stored on the selected server.");
9156
9435
  return { ok: true, group: "github", command: "auth token", details: result };
9157
9436
  }
9158
9437
  case "import-gh": {
9159
9438
  if (rest.length > 0)
9160
9439
  throw new CliError("Usage: rig github auth import-gh", 1);
9161
9440
  const importedToken = readGhToken();
9162
- const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken), { outputMode: context.outputMode });
9163
- printPayload(context, result, "GitHub token imported from gh and stored on the selected Rig server.");
9441
+ const repo = readRepoConnection(context.projectRoot);
9442
+ const result = await withSpinner("Storing GitHub token on the server\u2026", () => postGitHubTokenViaServer(context, importedToken, repo?.project ? { selectedRepo: repo.project } : {}), { outputMode: context.outputMode });
9443
+ persistRemoteAuthSession(context, "gh", result, importedToken);
9444
+ printPayload(context, result, "GitHub token imported from gh and stored on the selected server.");
9164
9445
  return { ok: true, group: "github", command: "auth import-gh", details: result };
9165
9446
  }
9166
9447
  default:
@@ -9190,7 +9471,7 @@ init_runner();
9190
9471
  init__authority_runs();
9191
9472
  init__paths();
9192
9473
  import { readFileSync as readFileSync8 } from "fs";
9193
- import { resolve as resolve19 } from "path";
9474
+ import { resolve as resolve20 } from "path";
9194
9475
  import {
9195
9476
  appendRunJournalEvent,
9196
9477
  appendRunLogEntry,
@@ -9227,7 +9508,7 @@ function touchAuthorityRun(projectRoot, runId) {
9227
9508
  if (!current) {
9228
9509
  return;
9229
9510
  }
9230
- writeJsonFile3(resolve19(resolveAuthorityRunDir(projectRoot, runId), "run.json"), {
9511
+ writeJsonFile3(resolve20(resolveAuthorityRunDir(projectRoot, runId), "run.json"), {
9231
9512
  ...current,
9232
9513
  updatedAt: new Date().toISOString()
9233
9514
  });
@@ -9465,7 +9746,7 @@ init_runner();
9465
9746
  init__server_client();
9466
9747
  init__async_ui();
9467
9748
  import { existsSync as existsSync13, readFileSync as readFileSync9 } from "fs";
9468
- import { resolve as resolve20 } from "path";
9749
+ import { resolve as resolve21 } from "path";
9469
9750
  import {
9470
9751
  listAuthorityRuns,
9471
9752
  readAuthorityRun as readAuthorityRun3,
@@ -9509,7 +9790,7 @@ async function executeInspect(context, args) {
9509
9790
  }
9510
9791
  return { ok: true, group: "inspect", command, details: { task: requiredTask, runId: fallback.runId, source: "server", entries } };
9511
9792
  }
9512
- const logsPath = resolve20(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
9793
+ const logsPath = resolve21(resolveAuthorityRunDir2(context.projectRoot, latestRun.runId), "logs.jsonl");
9513
9794
  if (!existsSync13(logsPath)) {
9514
9795
  throw new CliError(`No logs found for run ${latestRun.runId}.`, 1, { hint: `Try \`rig run show ${latestRun.runId}\` or \`rig run replay ${latestRun.runId}\`.` });
9515
9796
  }
@@ -9597,7 +9878,7 @@ async function executeInspect(context, args) {
9597
9878
  return { ok: true, group: "inspect", command };
9598
9879
  case "audit": {
9599
9880
  requireNoExtraArgs(rest, "rig inspect audit");
9600
- const auditPath = resolve20(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
9881
+ const auditPath = resolve21(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
9601
9882
  if (!existsSync13(auditPath)) {
9602
9883
  console.log("No audit log found.");
9603
9884
  } else {
@@ -10256,7 +10537,7 @@ import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/co
10256
10537
 
10257
10538
  // packages/cli/src/commands/_run-replay.ts
10258
10539
  import { existsSync as existsSync14, readdirSync as readdirSync2 } from "fs";
10259
- import { join as join2, resolve as resolve21 } from "path";
10540
+ import { join as join2, resolve as resolve22 } from "path";
10260
10541
  import {
10261
10542
  readAuthorityRun as readAuthorityRun4,
10262
10543
  readJsonlFile as readJsonlFile3,
@@ -10349,7 +10630,7 @@ function resolveRunSessionFile(record) {
10349
10630
  const sessionId = text(piSession.sessionId);
10350
10631
  if (!cwd || !sessionId)
10351
10632
  return null;
10352
- const sessionDir = resolve21(cwd, ".rig", "session");
10633
+ const sessionDir = resolve22(cwd, ".rig", "session");
10353
10634
  try {
10354
10635
  const match = readdirSync2(sessionDir).find((name) => name.endsWith(`_${sessionId}.jsonl`));
10355
10636
  return match ? join2(sessionDir, match) : null;
@@ -10847,6 +11128,9 @@ async function executeRun(context, args) {
10847
11128
  console.log(`Stop requested: ${runId}`);
10848
11129
  return { ok: true, group: "run", command, details: stopped };
10849
11130
  }
11131
+ if (isRemoteConnectionSelected(context.projectRoot)) {
11132
+ throw new CliError("Remote run stop requires an explicit run id.", 2, { hint: "Run `rig run list`, then `rig run stop <run-id>`." });
11133
+ }
10850
11134
  const result = await runStop(context.projectRoot);
10851
11135
  if (result.remaining.length > 0) {
10852
11136
  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." });
@@ -10963,7 +11247,13 @@ async function executeConnectionCommand(context, args, options) {
10963
11247
  if (!state.connections[alias])
10964
11248
  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>`." });
10965
11249
  }
10966
- const repoState = { selected: alias, linkedAt: new Date().toISOString() };
11250
+ const previousRepo = readRepoConnection(context.projectRoot);
11251
+ const repoState = {
11252
+ selected: alias,
11253
+ ...previousRepo?.project ? { project: previousRepo.project } : {},
11254
+ linkedAt: new Date().toISOString(),
11255
+ ...previousRepo?.serverProjectRoot && previousRepo.selected === alias ? { serverProjectRoot: previousRepo.serverProjectRoot } : {}
11256
+ };
10967
11257
  writeRepoConnection(context.projectRoot, repoState);
10968
11258
  printJsonOrText(context, repoState, formatSuccessCard("Rig server selected", [
10969
11259
  ["selected", alias],
@@ -11198,8 +11488,8 @@ init_task();
11198
11488
 
11199
11489
  // packages/cli/src/commands/task-run-driver.ts
11200
11490
  init_runner();
11201
- import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync10, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync7 } from "fs";
11202
- import { resolve as resolve23 } from "path";
11491
+ import { copyFileSync as copyFileSync3, existsSync as existsSync16, mkdirSync as mkdirSync11, readFileSync as readFileSync12, statSync as statSync2, writeFileSync as writeFileSync8 } from "fs";
11492
+ import { resolve as resolve24 } from "path";
11203
11493
  import { spawn as spawn2, spawnSync as spawnSync4 } from "child_process";
11204
11494
  import { createInterface as createLineInterface } from "readline";
11205
11495
  import { loadConfig as loadConfig2 } from "@rig/core/load-config";
@@ -11298,12 +11588,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
11298
11588
  return 0;
11299
11589
  let copied = 0;
11300
11590
  for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
11301
- const sourcePath = resolve23(sourceRoot, relativePath);
11302
- const targetPath = resolve23(targetRoot, relativePath);
11591
+ const sourcePath = resolve24(sourceRoot, relativePath);
11592
+ const targetPath = resolve24(targetRoot, relativePath);
11303
11593
  try {
11304
11594
  if (!statSync2(sourcePath).isFile())
11305
11595
  continue;
11306
- mkdirSync10(resolve23(targetPath, ".."), { recursive: true });
11596
+ mkdirSync11(resolve24(targetPath, ".."), { recursive: true });
11307
11597
  copyFileSync3(sourcePath, targetPath);
11308
11598
  copied += 1;
11309
11599
  } catch {}
@@ -11342,7 +11632,7 @@ function buildDirtyBaselineHandshakeEnv(input) {
11342
11632
  return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
11343
11633
  return {
11344
11634
  RIG_BASELINE_MODE: "dirty-snapshot",
11345
- RIG_DIRTY_BASELINE_READY_FILE: resolve23(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
11635
+ RIG_DIRTY_BASELINE_READY_FILE: resolve24(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
11346
11636
  };
11347
11637
  }
11348
11638
  function positiveInt(value, fallback) {
@@ -11447,9 +11737,9 @@ function createCommandRunner(binary) {
11447
11737
  const stderrChunks = [];
11448
11738
  child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
11449
11739
  child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
11450
- return await new Promise((resolve24) => {
11451
- child.once("error", (error) => resolve24({ exitCode: 1, stderr: error.message }));
11452
- child.once("close", (code) => resolve24({
11740
+ return await new Promise((resolve25) => {
11741
+ child.once("error", (error) => resolve25({ exitCode: 1, stderr: error.message }));
11742
+ child.once("close", (code) => resolve25({
11453
11743
  exitCode: code ?? 1,
11454
11744
  stdout: Buffer.concat(stdoutChunks).toString("utf8"),
11455
11745
  stderr: Buffer.concat(stderrChunks).toString("utf8")
@@ -11523,7 +11813,7 @@ async function runTaskRunPostValidationLifecycle(input) {
11523
11813
  config,
11524
11814
  sourceTask: input.sourceTask,
11525
11815
  uploadedSnapshot: input.uploadedSnapshot,
11526
- artifactRoot: resolve23(input.projectRoot, "artifacts", taskId3),
11816
+ artifactRoot: resolve24(input.projectRoot, "artifacts", taskId3),
11527
11817
  command: ghCommand,
11528
11818
  gitCommand,
11529
11819
  steerPi,
@@ -11653,7 +11943,7 @@ function summarizeValidationFailure(projectRoot, taskId3) {
11653
11943
  return null;
11654
11944
  }
11655
11945
  for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId3)) {
11656
- const summary = readJsonFile3(resolve23(artifactDir, "validation-summary.json"), null);
11946
+ const summary = readJsonFile3(resolve24(artifactDir, "validation-summary.json"), null);
11657
11947
  if (!summary || summary.status !== "fail") {
11658
11948
  continue;
11659
11949
  }
@@ -11734,9 +12024,9 @@ function readTaskRunAcceptedArtifactState(input) {
11734
12024
  if (!input.taskId || !input.workspaceDir) {
11735
12025
  return { accepted: false, reason: null };
11736
12026
  }
11737
- const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
11738
- const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
11739
- const taskResultPath = resolve23(artifactDir, "task-result.json");
12027
+ const artifactDir = resolve24(input.workspaceDir, "artifacts", input.taskId);
12028
+ const reviewStatusPath = resolve24(artifactDir, "review-status.txt");
12029
+ const taskResultPath = resolve24(artifactDir, "task-result.json");
11740
12030
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
11741
12031
  if (reviewStatus !== "APPROVED") {
11742
12032
  return { accepted: false, reason: null };
@@ -11773,12 +12063,12 @@ function resolveTaskRunRetryContext(input) {
11773
12063
  if (!input.taskId || !input.workspaceDir) {
11774
12064
  return { shouldRetry: false, failureDetail: null, nextPrompt: null };
11775
12065
  }
11776
- const artifactDir = resolve23(input.workspaceDir, "artifacts", input.taskId);
11777
- const reviewStatePath = resolve23(artifactDir, "review-state.json");
11778
- const reviewFeedbackPath = resolve23(artifactDir, "review-feedback.md");
11779
- const reviewStatusPath = resolve23(artifactDir, "review-status.txt");
11780
- const failedApproachesPath = resolve23(input.workspaceDir, ".rig", "state", "failed_approaches.md");
11781
- const validationSummaryPath = resolve23(artifactDir, "validation-summary.json");
12066
+ const artifactDir = resolve24(input.workspaceDir, "artifacts", input.taskId);
12067
+ const reviewStatePath = resolve24(artifactDir, "review-state.json");
12068
+ const reviewFeedbackPath = resolve24(artifactDir, "review-feedback.md");
12069
+ const reviewStatusPath = resolve24(artifactDir, "review-status.txt");
12070
+ const failedApproachesPath = resolve24(input.workspaceDir, ".rig", "state", "failed_approaches.md");
12071
+ const validationSummaryPath = resolve24(artifactDir, "validation-summary.json");
11782
12072
  const reviewState = readJsonFile3(reviewStatePath, null);
11783
12073
  const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
11784
12074
  const reviewRejected = isTaskRunReviewRejected(reviewState);
@@ -12188,15 +12478,15 @@ async function executeRigOwnedTaskRun(context, input) {
12188
12478
  const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
12189
12479
  const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
12190
12480
  const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
12191
- const planningArtifactPath = resolve23("artifacts", runtimeTaskId, "implementation-plan.md");
12481
+ const planningArtifactPath = resolve24("artifacts", runtimeTaskId, "implementation-plan.md");
12192
12482
  const persistedPlanning = {
12193
12483
  ...planningClassification,
12194
12484
  classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
12195
12485
  artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
12196
12486
  classifiedAt: new Date().toISOString()
12197
12487
  };
12198
- mkdirSync10(resolve23(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
12199
- writeFileSync7(resolve23(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
12488
+ mkdirSync11(resolve24(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
12489
+ writeFileSync8(resolve24(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
12200
12490
  `, "utf8");
12201
12491
  patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
12202
12492
  prompt = `${prompt}
@@ -12246,7 +12536,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12246
12536
  let verificationStarted = false;
12247
12537
  let reviewStarted = false;
12248
12538
  let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
12249
- let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve23(existingRunRecord.sessionPath, "..") : null;
12539
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve24(existingRunRecord.sessionPath, "..") : null;
12250
12540
  let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
12251
12541
  let latestProviderCommand = null;
12252
12542
  let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
@@ -12332,10 +12622,10 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12332
12622
  setRunStatusOrFail(context.projectRoot, input.runId, "running");
12333
12623
  patchAuthorityRun(context.projectRoot, input.runId, {
12334
12624
  worktreePath: latestRuntimeWorkspace,
12335
- artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve23(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
12625
+ artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve24(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
12336
12626
  logRoot: latestLogsDir,
12337
- sessionPath: latestSessionDir ? resolve23(latestSessionDir, "session.json") : null,
12338
- sessionLogPath: latestLogsDir ? resolve23(latestLogsDir, "agent-stdout.log") : null,
12627
+ sessionPath: latestSessionDir ? resolve24(latestSessionDir, "session.json") : null,
12628
+ sessionLogPath: latestLogsDir ? resolve24(latestLogsDir, "agent-stdout.log") : null,
12339
12629
  branch: runtimeId
12340
12630
  });
12341
12631
  if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
@@ -12343,8 +12633,8 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12343
12633
  const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
12344
12634
  const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
12345
12635
  if (readyFile) {
12346
- mkdirSync10(resolve23(readyFile, ".."), { recursive: true });
12347
- writeFileSync7(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
12636
+ mkdirSync11(resolve24(readyFile, ".."), { recursive: true });
12637
+ writeFileSync8(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
12348
12638
  `, "utf8");
12349
12639
  }
12350
12640
  appendRunLog(context.projectRoot, input.runId, {
@@ -12740,7 +13030,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12740
13030
  let acceptedArtifactObservedAt = null;
12741
13031
  let acceptedArtifactPollTimer = null;
12742
13032
  let acceptedArtifactKillTimer = null;
12743
- const attemptExit = await new Promise((resolve24) => {
13033
+ const attemptExit = await new Promise((resolve25) => {
12744
13034
  let settled = false;
12745
13035
  const settle = (result) => {
12746
13036
  if (settled)
@@ -12748,7 +13038,7 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
12748
13038
  settled = true;
12749
13039
  if (acceptedArtifactPollTimer)
12750
13040
  clearInterval(acceptedArtifactPollTimer);
12751
- resolve24(result);
13041
+ resolve25(result);
12752
13042
  };
12753
13043
  const pollAcceptedArtifacts = () => {
12754
13044
  const artifactState = readTaskRunAcceptedArtifactState({
@@ -12951,7 +13241,7 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
12951
13241
  }
12952
13242
  if (planningClassification.planningRequired) {
12953
13243
  const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
12954
- const expectedPlanPath = resolve23(planWorkspace, planningArtifactPath);
13244
+ const expectedPlanPath = resolve24(planWorkspace, planningArtifactPath);
12955
13245
  if (!existsSync16(expectedPlanPath)) {
12956
13246
  const failedAt = new Date().toISOString();
12957
13247
  const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
@@ -13121,9 +13411,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
13121
13411
  });
13122
13412
  emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
13123
13413
  });
13124
- const exitCode = await new Promise((resolve24) => {
13125
- child.once("error", () => resolve24(1));
13126
- child.once("close", (code) => resolve24(code ?? 1));
13414
+ const exitCode = await new Promise((resolve25) => {
13415
+ child.once("error", () => resolve25(1));
13416
+ child.once("close", (code) => resolve25(code ?? 1));
13127
13417
  });
13128
13418
  for (const pendingLog of flushPendingClaudeToolUseLogs({
13129
13419
  runId: input.runId,
@@ -13264,8 +13554,8 @@ async function executeTest(context, args) {
13264
13554
  init_runner();
13265
13555
  init__parsers();
13266
13556
  init__paths();
13267
- import { existsSync as existsSync17, mkdirSync as mkdirSync11, readdirSync as readdirSync3, writeFileSync as writeFileSync8 } from "fs";
13268
- import { resolve as resolve24 } from "path";
13557
+ import { existsSync as existsSync17, mkdirSync as mkdirSync12, readdirSync as readdirSync3, writeFileSync as writeFileSync9 } from "fs";
13558
+ import { resolve as resolve25 } from "path";
13269
13559
  import { createPluginHost } from "@rig/core";
13270
13560
  import {
13271
13561
  isSupportedBunVersion as isSupportedBunVersion2,
@@ -13320,12 +13610,12 @@ function runSetupInit(projectRoot) {
13320
13610
  const stateDir = resolveControlPlaneHostStateDir(projectRoot);
13321
13611
  const logsDir = resolveControlPlaneHostLogsDir(projectRoot);
13322
13612
  const artifactsDir = resolveControlPlaneArtifactsDir(projectRoot);
13323
- mkdirSync11(stateDir, { recursive: true });
13324
- mkdirSync11(logsDir, { recursive: true });
13325
- mkdirSync11(artifactsDir, { recursive: true });
13326
- const failuresPath = resolve24(stateDir, "failed_approaches.md");
13613
+ mkdirSync12(stateDir, { recursive: true });
13614
+ mkdirSync12(logsDir, { recursive: true });
13615
+ mkdirSync12(artifactsDir, { recursive: true });
13616
+ const failuresPath = resolve25(stateDir, "failed_approaches.md");
13327
13617
  if (!existsSync17(failuresPath)) {
13328
- writeFileSync8(failuresPath, `# Failed Approaches
13618
+ writeFileSync9(failuresPath, `# Failed Approaches
13329
13619
 
13330
13620
  `, "utf-8");
13331
13621
  }
@@ -13342,17 +13632,17 @@ async function runSetupCheck(projectRoot, outputMode = "text") {
13342
13632
  }
13343
13633
  async function runSetupPreflight(projectRoot, outputMode = "text") {
13344
13634
  await runSetupCheck(projectRoot, outputMode);
13345
- const validationRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
13635
+ const validationRoot = resolve25(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
13346
13636
  if (existsSync17(validationRoot)) {
13347
13637
  const validators = readdirSync3(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
13348
13638
  for (const validator of validators) {
13349
- const script = resolve24(validationRoot, validator.name, "validate.sh");
13639
+ const script = resolve25(validationRoot, validator.name, "validate.sh");
13350
13640
  if (existsSync17(script)) {
13351
13641
  console.log(`OK: validator script ${script}`);
13352
13642
  }
13353
13643
  }
13354
13644
  }
13355
- const hooksRoot = resolve24(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
13645
+ const hooksRoot = resolve25(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
13356
13646
  if (existsSync17(hooksRoot)) {
13357
13647
  const hooks = readdirSync3(hooksRoot).filter((name) => name.endsWith(".sh"));
13358
13648
  for (const hook of hooks) {
@@ -13499,7 +13789,7 @@ var PROJECT_REQUIRED_GROUPS = new Set([
13499
13789
  ]);
13500
13790
  var RIG_CONFIG_FILENAMES = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
13501
13791
  function hasInitializedRigProject(projectRoot) {
13502
- return RIG_CONFIG_FILENAMES.some((name) => existsSync19(resolve25(projectRoot, name))) || existsSync19(resolve25(projectRoot, ".rig"));
13792
+ return RIG_CONFIG_FILENAMES.some((name) => existsSync19(resolve26(projectRoot, name))) || existsSync19(resolve26(projectRoot, ".rig"));
13503
13793
  }
13504
13794
  function requireInitializedRigProject(context, group) {
13505
13795
  if (hasInitializedRigProject(context.projectRoot)) {
@@ -13553,7 +13843,7 @@ function resolveTopLevelLaunchState(context) {
13553
13843
  let selectedServer = null;
13554
13844
  if (projectInitialized) {
13555
13845
  try {
13556
- const statePath = resolve25(context.projectRoot, ".rig", "state", "connection.json");
13846
+ const statePath = resolve26(context.projectRoot, ".rig", "state", "connection.json");
13557
13847
  if (existsSync19(statePath)) {
13558
13848
  const parsed = JSON.parse(readFileSync13(statePath, "utf-8"));
13559
13849
  selectedServer = parsed.remoteUrl || parsed.url || parsed.selected || null;
@@ -13562,8 +13852,14 @@ function resolveTopLevelLaunchState(context) {
13562
13852
  }
13563
13853
  return { projectInitialized, selectedServer, version: process.env.RIG_CLI_VERSION || readBuildConfig().RIG_CLI_VERSION || undefined };
13564
13854
  }
13855
+ function envTruthy(value) {
13856
+ if (!value)
13857
+ return false;
13858
+ const normalized = value.trim().toLowerCase();
13859
+ return normalized !== "0" && normalized !== "false" && normalized !== "no";
13860
+ }
13565
13861
  function shouldOpenApp(context) {
13566
- return context.outputMode === "text" && Boolean(process.stdin.isTTY && process.stdout.isTTY) && process.env.RIG_CLI_PLAIN_HELP !== "1";
13862
+ 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);
13567
13863
  }
13568
13864
  async function openApp(context, options = {}) {
13569
13865
  const { runOperatorBoardLoop: runOperatorBoardLoop2 } = await Promise.resolve().then(() => (init_board(), exports_board));
@@ -13772,7 +14068,7 @@ var __testOnly = {
13772
14068
  };
13773
14069
  // packages/cli/src/launcher.ts
13774
14070
  import { existsSync as existsSync20 } from "fs";
13775
- import { basename as basename3, resolve as resolve26 } from "path";
14071
+ import { basename as basename3, resolve as resolve27 } from "path";
13776
14072
  import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
13777
14073
  import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
13778
14074
 
@@ -13836,7 +14132,7 @@ function parsePolicyMode(value) {
13836
14132
  throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
13837
14133
  }
13838
14134
  function hasRigProjectMarker(candidate) {
13839
- return existsSync20(resolve26(candidate, RIG_DEFINITION_DIRNAME)) || existsSync20(resolve26(candidate, RIG_STATE_DIRNAME)) || existsSync20(resolve26(candidate, "rig.config.ts")) || existsSync20(resolve26(candidate, "rig.config.json")) || existsSync20(resolve26(candidate, ".git"));
14135
+ return existsSync20(resolve27(candidate, RIG_DEFINITION_DIRNAME)) || existsSync20(resolve27(candidate, RIG_STATE_DIRNAME)) || existsSync20(resolve27(candidate, "rig.config.ts")) || existsSync20(resolve27(candidate, "rig.config.json")) || existsSync20(resolve27(candidate, ".git"));
13840
14136
  }
13841
14137
  function resolveProjectRoot({
13842
14138
  envProjectRoot,
@@ -13845,19 +14141,19 @@ function resolveProjectRoot({
13845
14141
  cwd = process.cwd()
13846
14142
  }) {
13847
14143
  if (envProjectRoot) {
13848
- return resolve26(cwd, envProjectRoot);
14144
+ return resolve27(cwd, envProjectRoot);
13849
14145
  }
13850
14146
  const fallbackImportDir = importDir ?? cwd;
13851
14147
  const execName = basename3(execPath).toLowerCase();
13852
- const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve26(execPath, "..", "..")] : [];
13853
- const candidates = [cwd, ...execCandidates, resolve26(fallbackImportDir, "..")];
14148
+ const execCandidates = execName === "rig" || execName === "rig.exe" ? [resolve27(execPath, "..", "..")] : [];
14149
+ const candidates = [cwd, ...execCandidates, resolve27(fallbackImportDir, "..")];
13854
14150
  for (const candidate of candidates) {
13855
14151
  const nearest = resolveNearestRigProjectRoot(candidate);
13856
14152
  if (hasRigProjectMarker(nearest)) {
13857
14153
  return nearest;
13858
14154
  }
13859
14155
  }
13860
- return resolve26(cwd);
14156
+ return resolve27(cwd);
13861
14157
  }
13862
14158
  function normalizeCliErrorCode(message2, isCliError) {
13863
14159
  if (message2.startsWith("Invalid --policy-mode value:")) {
@@ -13931,7 +14227,7 @@ async function runRigCli(module, options = {}) {
13931
14227
  runId: context.runId,
13932
14228
  outcome,
13933
14229
  eventsFile: context.eventBus.getEventsFile(),
13934
- policyFile: resolve26(projectRoot, "rig", "policy", "policy.json"),
14230
+ policyFile: resolve27(projectRoot, "rig", "policy", "policy.json"),
13935
14231
  policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
13936
14232
  }, null, 2));
13937
14233
  }