@h-rig/cli 0.0.6-alpha.6 → 0.0.6-alpha.60

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 (50) hide show
  1. package/README.md +1 -1
  2. package/dist/bin/rig.js +4184 -1228
  3. package/dist/src/commands/_cli-format.js +369 -0
  4. package/dist/src/commands/_connection-state.js +12 -6
  5. package/dist/src/commands/_doctor-checks.js +79 -34
  6. package/dist/src/commands/_help-catalog.js +445 -0
  7. package/dist/src/commands/_operator-surface.js +220 -0
  8. package/dist/src/commands/_operator-view.js +1124 -64
  9. package/dist/src/commands/_parsers.js +0 -2
  10. package/dist/src/commands/_pi-frontend.js +1080 -0
  11. package/dist/src/commands/_pi-install.js +4 -3
  12. package/dist/src/commands/_pi-remote-session.js +771 -0
  13. package/dist/src/commands/_pi-worker-bridge-extension.js +834 -0
  14. package/dist/src/commands/_policy.js +0 -2
  15. package/dist/src/commands/_preflight.js +98 -116
  16. package/dist/src/commands/_run-driver-helpers.js +34 -2
  17. package/dist/src/commands/_server-client.js +225 -48
  18. package/dist/src/commands/_snapshot-upload.js +74 -30
  19. package/dist/src/commands/_spinner.js +63 -0
  20. package/dist/src/commands/_task-picker.js +44 -16
  21. package/dist/src/commands/agent.js +8 -9
  22. package/dist/src/commands/browser.js +4 -6
  23. package/dist/src/commands/connect.js +134 -26
  24. package/dist/src/commands/dist.js +4 -6
  25. package/dist/src/commands/doctor.js +79 -34
  26. package/dist/src/commands/github.js +76 -32
  27. package/dist/src/commands/inbox.js +410 -31
  28. package/dist/src/commands/init.js +398 -90
  29. package/dist/src/commands/inspect.js +296 -23
  30. package/dist/src/commands/inspector.js +2 -4
  31. package/dist/src/commands/pi.js +168 -0
  32. package/dist/src/commands/plugin.js +81 -22
  33. package/dist/src/commands/profile-and-review.js +8 -10
  34. package/dist/src/commands/queue.js +2 -3
  35. package/dist/src/commands/remote.js +18 -20
  36. package/dist/src/commands/repo-git-harness.js +6 -8
  37. package/dist/src/commands/run.js +1422 -131
  38. package/dist/src/commands/server.js +280 -40
  39. package/dist/src/commands/setup.js +84 -45
  40. package/dist/src/commands/task-report-bug.js +5 -7
  41. package/dist/src/commands/task-run-driver.js +710 -70
  42. package/dist/src/commands/task.js +1861 -260
  43. package/dist/src/commands/test.js +3 -5
  44. package/dist/src/commands/workspace.js +4 -6
  45. package/dist/src/commands.js +4143 -1181
  46. package/dist/src/index.js +4156 -1203
  47. package/dist/src/launcher.js +5 -3
  48. package/dist/src/report-bug.js +3 -3
  49. package/dist/src/runner.js +5 -19
  50. package/package.json +7 -5
@@ -9,8 +9,6 @@ import { resolve as resolve6 } from "path";
9
9
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
10
10
  import { CliError } from "@rig/runtime/control-plane/errors";
11
11
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
12
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
13
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
14
12
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
15
13
  import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
16
14
  function requireNoExtraArgs(args, usage) {
@@ -102,7 +100,8 @@ function resolveControlPlaneDefinitionRoot(projectRoot) {
102
100
  import { existsSync, readFileSync, rmSync } from "fs";
103
101
  import { homedir } from "os";
104
102
  import { resolve as resolve2 } from "path";
105
- var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
103
+ var PI_RIG_PACKAGE_NAME = "@h-rig/pi-rig";
104
+ var LEGACY_PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
106
105
  async function defaultCommandRunner(command, options = {}) {
107
106
  const proc = Bun.spawn(command, { cwd: options.cwd, stdout: "pipe", stderr: "pipe" });
108
107
  const [stdout, stderr, exitCode] = await Promise.all([
@@ -121,7 +120,7 @@ function resolvePiHomeDir(inputHomeDir) {
121
120
  function piListContainsPiRig(output) {
122
121
  return output.split(/\r?\n/).some((line) => {
123
122
  const normalized = line.trim();
124
- return normalized.includes(PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
123
+ return normalized.includes(PI_RIG_PACKAGE_NAME) || normalized.includes(LEGACY_PI_RIG_PACKAGE_NAME) || /(?:^|[\\/])packages[\\/]pi-rig(?:$|\s)/.test(normalized);
125
124
  });
126
125
  }
127
126
  async function safeRun(runner, command, options) {
@@ -200,6 +199,11 @@ function readJsonFile(path) {
200
199
  throw new CliError2(`Invalid Rig connection state at ${path}: ${error instanceof Error ? error.message : String(error)}`, 1);
201
200
  }
202
201
  }
202
+ function writeJsonFile(path, value) {
203
+ mkdirSync(dirname(path), { recursive: true });
204
+ writeFileSync(path, `${JSON.stringify(value, null, 2)}
205
+ `, "utf8");
206
+ }
203
207
  function normalizeConnection(value) {
204
208
  if (!value || typeof value !== "object" || Array.isArray(value))
205
209
  return null;
@@ -240,29 +244,38 @@ function readRepoConnection(projectRoot) {
240
244
  return {
241
245
  selected,
242
246
  project: typeof record.project === "string" ? record.project : undefined,
243
- linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined
247
+ linkedAt: typeof record.linkedAt === "string" ? record.linkedAt : undefined,
248
+ serverProjectRoot: typeof record.serverProjectRoot === "string" && record.serverProjectRoot.trim() ? record.serverProjectRoot.trim() : undefined
244
249
  };
245
250
  }
251
+ function writeRepoConnection(projectRoot, state) {
252
+ writeJsonFile(resolveRepoConnectionPath(projectRoot), state);
253
+ }
246
254
  function resolveSelectedConnection(projectRoot, options = {}) {
247
255
  const repo = readRepoConnection(projectRoot);
248
256
  if (!repo)
249
257
  return null;
250
258
  if (repo.selected === "local")
251
- return { alias: "local", connection: { kind: "local", mode: "auto" } };
259
+ return { alias: "local", connection: { kind: "local", mode: "auto" }, serverProjectRoot: repo.serverProjectRoot };
252
260
  const global = readGlobalConnections(options);
253
261
  const connection = global.connections[repo.selected];
254
262
  if (!connection) {
255
- throw new CliError2(`Selected Rig connection "${repo.selected}" was not found. Run \`rig connect list\` or \`rig connect use local\`.`, 1);
263
+ throw new CliError2(`Selected Rig server "${repo.selected}" was not found. Run \`rig server list\` or \`rig server use local\`.`, 1);
256
264
  }
257
- return { alias: repo.selected, connection };
265
+ return { alias: repo.selected, connection, serverProjectRoot: repo.serverProjectRoot };
266
+ }
267
+ function writeRepoServerProjectRoot(projectRoot, serverProjectRoot) {
268
+ const repo = readRepoConnection(projectRoot);
269
+ if (!repo)
270
+ return;
271
+ writeRepoConnection(projectRoot, { ...repo, serverProjectRoot });
258
272
  }
259
273
 
260
274
  // packages/cli/src/commands/_server-client.ts
261
- import { spawnSync } from "child_process";
262
275
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
263
276
  import { resolve as resolve4 } from "path";
264
277
  import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
265
- var cachedGitHubBearerToken;
278
+ var scopedGitHubBearerTokens = new Map;
266
279
  function cleanToken(value) {
267
280
  const trimmed = value?.trim();
268
281
  return trimmed ? trimmed : null;
@@ -279,41 +292,47 @@ function readPrivateRemoteSessionToken(projectRoot) {
279
292
  }
280
293
  }
281
294
  function readGitHubBearerTokenForRemote(projectRoot) {
282
- if (cachedGitHubBearerToken !== undefined)
283
- return cachedGitHubBearerToken;
295
+ const scopedKey = resolve4(projectRoot);
296
+ if (scopedGitHubBearerTokens.has(scopedKey))
297
+ return scopedGitHubBearerTokens.get(scopedKey) ?? null;
284
298
  const privateSession = readPrivateRemoteSessionToken(projectRoot);
285
- if (privateSession) {
286
- cachedGitHubBearerToken = privateSession;
287
- return cachedGitHubBearerToken;
288
- }
289
- const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
290
- if (envToken) {
291
- cachedGitHubBearerToken = envToken;
292
- return cachedGitHubBearerToken;
293
- }
294
- const result = spawnSync("gh", ["auth", "token"], {
295
- encoding: "utf8",
296
- timeout: 5000,
297
- stdio: ["ignore", "pipe", "ignore"]
298
- });
299
- cachedGitHubBearerToken = result.status === 0 ? cleanToken(result.stdout) : null;
300
- return cachedGitHubBearerToken;
299
+ if (privateSession)
300
+ return privateSession;
301
+ return cleanToken(process.env.RIG_SERVER_AUTH_TOKEN) ?? cleanToken(process.env.RIG_REMOTE_AUTH_TOKEN);
302
+ }
303
+ function readStoredGitHubAuthToken(projectRoot) {
304
+ const path = resolve4(projectRoot, ".rig", "state", "github-auth.json");
305
+ if (!existsSync3(path))
306
+ return null;
307
+ try {
308
+ const parsed = JSON.parse(readFileSync3(path, "utf8"));
309
+ return cleanToken(typeof parsed.token === "string" ? parsed.token : undefined);
310
+ } catch {
311
+ return null;
312
+ }
313
+ }
314
+ function readLocalConnectionFallbackToken(projectRoot) {
315
+ return readGitHubBearerTokenForRemote(projectRoot) ?? cleanToken(process.env.RIG_GITHUB_TOKEN) ?? readStoredGitHubAuthToken(projectRoot);
301
316
  }
302
317
  async function ensureServerForCli(projectRoot) {
303
318
  try {
304
319
  const selected = resolveSelectedConnection(projectRoot);
305
320
  if (selected?.connection.kind === "remote") {
321
+ const authToken = readGitHubBearerTokenForRemote(projectRoot);
322
+ const serverProjectRoot = selected.serverProjectRoot ?? await backfillRemoteServerProjectRoot(projectRoot, selected.connection.baseUrl, authToken);
306
323
  return {
307
324
  baseUrl: selected.connection.baseUrl,
308
- authToken: readGitHubBearerTokenForRemote(projectRoot),
309
- connectionKind: "remote"
325
+ authToken,
326
+ connectionKind: "remote",
327
+ serverProjectRoot
310
328
  };
311
329
  }
312
330
  const connection = await ensureLocalRigServerConnection(projectRoot);
313
331
  return {
314
332
  baseUrl: connection.baseUrl,
315
- authToken: connection.authToken,
316
- connectionKind: "local"
333
+ authToken: connection.authToken ?? readLocalConnectionFallbackToken(projectRoot),
334
+ connectionKind: "local",
335
+ serverProjectRoot: resolve4(projectRoot)
317
336
  };
318
337
  } catch (error) {
319
338
  if (error instanceof Error) {
@@ -322,6 +341,29 @@ async function ensureServerForCli(projectRoot) {
322
341
  throw error;
323
342
  }
324
343
  }
344
+ async function backfillRemoteServerProjectRoot(projectRoot, baseUrl, authToken) {
345
+ const repo = readRepoConnection(projectRoot);
346
+ const slug = repo?.project?.trim();
347
+ if (!slug)
348
+ return null;
349
+ try {
350
+ const response = await fetch(`${baseUrl}/api/projects/${encodeURIComponent(slug)}`, {
351
+ headers: mergeHeaders(undefined, authToken)
352
+ });
353
+ if (!response.ok)
354
+ return null;
355
+ const payload = await response.json();
356
+ const project = payload.project && typeof payload.project === "object" && !Array.isArray(payload.project) ? payload.project : null;
357
+ const checkouts = Array.isArray(project?.checkouts) ? project.checkouts : [];
358
+ const latestCheckout = [...checkouts].reverse().find((entry) => Boolean(entry && typeof entry === "object" && !Array.isArray(entry) && typeof entry.path === "string"));
359
+ const path = typeof latestCheckout?.path === "string" && latestCheckout.path.trim() ? latestCheckout.path.trim() : null;
360
+ if (path)
361
+ writeRepoServerProjectRoot(projectRoot, path);
362
+ return path;
363
+ } catch {
364
+ return null;
365
+ }
366
+ }
325
367
  function mergeHeaders(headers, authToken) {
326
368
  const merged = new Headers(headers);
327
369
  if (authToken) {
@@ -346,9 +388,12 @@ function diagnosticMessage(payload) {
346
388
  }
347
389
  async function requestServerJson(context, pathname, init = {}) {
348
390
  const server = await ensureServerForCli(context.projectRoot);
391
+ const headers = mergeHeaders(init.headers, server.authToken);
392
+ if (server.serverProjectRoot)
393
+ headers.set("x-rig-project-root", server.serverProjectRoot);
349
394
  const response = await fetch(`${server.baseUrl}${pathname}`, {
350
395
  ...init,
351
- headers: mergeHeaders(init.headers, server.authToken)
396
+ headers
352
397
  });
353
398
  const text = await response.text();
354
399
  const payload = text.trim().length > 0 ? (() => {
@@ -493,7 +538,7 @@ async function runRigDoctorChecks(options) {
493
538
  const taskSourceKind = config?.taskSource?.kind;
494
539
  checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
495
540
  const repo = readRepoConnection(projectRoot);
496
- checks.push(repo ? check("project-link", "repo selected Rig connection", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig connection", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig connect use <alias|local>`."));
541
+ checks.push(repo ? check("project-link", "repo selected Rig server", repo.project ? "pass" : "warn", `${repo.selected}${repo.project ? ` -> ${repo.project}` : ""}`, "Run `rig init --yes --repo owner/repo` to link this checkout to a GitHub repo slug.") : check("project-link", "repo selected Rig server", "fail", "missing .rig/state/connection.json", "Run `rig init` or `rig server use <alias|local>`."));
497
542
  const selected = (() => {
498
543
  try {
499
544
  return resolveSelectedConnection(projectRoot);
@@ -501,7 +546,7 @@ async function runRigDoctorChecks(options) {
501
546
  return null;
502
547
  }
503
548
  })();
504
- checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server connection", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig connect list` and `rig connect use <alias|local>`." : undefined));
549
+ checks.push(selected ? check("connection", "selected server connection", "pass", selected.connection.kind === "remote" ? selected.connection.baseUrl : "local auto") : check("connection", "selected server", repo ? "fail" : "warn", repo ? "selected alias is missing" : "will auto-start local server", repo ? "Run `rig server list` and `rig server use <alias|local>`." : undefined));
505
550
  let server = null;
506
551
  try {
507
552
  server = await (options.resolveServer ?? ensureServerForCli)(projectRoot);
@@ -587,7 +632,7 @@ async function executeSetup(context, args) {
587
632
  const [command = "check", ...rest] = args;
588
633
  switch (command) {
589
634
  case "bootstrap":
590
- requireNoExtraArgs(rest, "bun run rig setup bootstrap");
635
+ requireNoExtraArgs(rest, "rig setup bootstrap");
591
636
  {
592
637
  const hostBash = Bun.which("bash") || "/bin/bash";
593
638
  const env = { ...process.env };
@@ -610,25 +655,19 @@ async function executeSetup(context, args) {
610
655
  }
611
656
  return { ok: true, group: "setup", command };
612
657
  case "check":
613
- requireNoExtraArgs(rest, `bun run rig setup ${command}`);
658
+ requireNoExtraArgs(rest, `rig setup ${command}`);
614
659
  {
615
660
  const checks = await withMutedConsole(context.outputMode === "json", () => runSetupCheck(context.projectRoot));
616
661
  return { ok: true, group: "setup", command, details: { checks, failures: countDoctorFailures(checks) } };
617
662
  }
618
663
  case "setup":
619
- requireNoExtraArgs(rest, "bun run rig setup setup");
664
+ requireNoExtraArgs(rest, "rig setup setup");
620
665
  withMutedConsole(context.outputMode === "json", () => runSetupInit(context.projectRoot));
621
666
  return { ok: true, group: "setup", command };
622
667
  case "preflight":
623
- requireNoExtraArgs(rest, "bun run rig setup preflight");
668
+ requireNoExtraArgs(rest, "rig setup preflight");
624
669
  await withMutedConsole(context.outputMode === "json", () => runSetupPreflight(context.projectRoot));
625
670
  return { ok: true, group: "setup", command };
626
- case "install-agent-shell":
627
- requireNoExtraArgs(rest, "bun run rig setup install-agent-shell");
628
- if (context.outputMode === "text") {
629
- console.log("install-agent-shell is deprecated. Runtime shells now use compiled rig-agent directly.");
630
- }
631
- return { ok: true, group: "setup", command };
632
671
  default:
633
672
  throw new CliError2(`Unknown setup command: ${command}`);
634
673
  }
@@ -9,8 +9,6 @@ import pc from "picocolors";
9
9
  import { EventBus } from "@rig/runtime/control-plane/runtime/events";
10
10
  import { CliError } from "@rig/runtime/control-plane/errors";
11
11
  import { evaluate, loadPolicy, resolveAction } from "@rig/runtime/control-plane/runtime/guard";
12
- import { PluginManager } from "@rig/runtime/control-plane/runtime/plugins";
13
- import { loadRuntimeContextFromEnv } from "@rig/runtime/control-plane/runtime/context";
14
12
  import { buildBinary } from "@rig/runtime/control-plane/runtime/isolation";
15
13
  import { CliError as CliError2 } from "@rig/runtime/control-plane/errors";
16
14
  function formatCommand(parts) {
@@ -241,15 +239,15 @@ function buildBugReportMarkdown(input, browser, screenshots, assets) {
241
239
  ...input.issueId ? [
242
240
  `- Canonical task assets live under \`artifacts/${input.issueId}/bug-report/\`.`,
243
241
  `- Start with \`artifacts/${input.issueId}/bug-report/task.md\` and the files in \`artifacts/${input.issueId}/bug-report/assets/\`.`,
244
- browserRequired ? `- Run \`bun run rig task info --task ${input.issueId}\` to confirm browser wiring before debugging.` : `- Run \`bun run rig task info --task ${input.issueId}\` to confirm scope and artifact links before debugging.`
242
+ browserRequired ? `- Run \`rig task info --task ${input.issueId}\` to confirm browser wiring before debugging.` : `- Run \`rig task info --task ${input.issueId}\` to confirm scope and artifact links before debugging.`
245
243
  ] : [
246
- "- Draft-only report: convert this into a beads task before assigning it to an agent run."
244
+ "- Draft-only report: convert this into a Rig task before assigning it to an agent run."
247
245
  ],
248
246
  "",
249
247
  "## Validation",
250
248
  "",
251
249
  "```bash",
252
- ...input.issueId ? [`bun run rig task validate --task ${input.issueId}`] : [],
250
+ ...input.issueId ? [`rig task validate --task ${input.issueId}`] : [],
253
251
  ...browserRequired ? [
254
252
  "bun run app:check:browser:hp-next",
255
253
  "bun run app:e2e:browser:hp-next"
@@ -396,7 +394,7 @@ async function executeTaskReportBug(context, args) {
396
394
  pending = outputRootResult.rest;
397
395
  const slugResult = takeOption(pending, "--slug");
398
396
  pending = slugResult.rest;
399
- requireNoExtraArgs(pending, "bun run rig report-bug [--no-prompt] [--no-beads] [--browser|--no-browser] --title <text> --url <url> [--asset <dragged-file>]");
397
+ requireNoExtraArgs(pending, "rig report-bug [--no-prompt] [--no-beads] [--browser|--no-browser] --title <text> --url <url> [--asset <dragged-file>]");
400
398
  let draft = {
401
399
  outputRoot: outputRootResult.value || "",
402
400
  title: titleResult.value,
@@ -501,7 +499,7 @@ async function executeTaskReportBug(context, args) {
501
499
  console.log(`Evidence assets: ${result.assetDir}`);
502
500
  if (taskConfigPath) {
503
501
  console.log(`Task config: ${taskConfigPath}`);
504
- console.log(`Run: bun run rig task info --task ${issueId}`);
502
+ console.log(`Run: rig task info --task ${issueId}`);
505
503
  }
506
504
  }
507
505
  return {