@h-rig/cli 0.0.6-alpha.3 → 0.0.6-alpha.4

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.
package/dist/bin/rig.js CHANGED
@@ -3446,6 +3446,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3446
3446
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
3447
3447
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
3448
3448
  const next = {
3449
+ ...existing ?? {},
3449
3450
  runId: input.runId,
3450
3451
  projectRoot,
3451
3452
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -6118,6 +6119,7 @@ import {
6118
6119
  listOpenEpics,
6119
6120
  resolveDefaultEpic,
6120
6121
  runResume,
6122
+ runRestart,
6121
6123
  runStatus,
6122
6124
  runStop,
6123
6125
  startRun,
@@ -6226,6 +6228,17 @@ async function attachRunOperatorView(context, input) {
6226
6228
  }
6227
6229
 
6228
6230
  // packages/cli/src/commands/run.ts
6231
+ function normalizeRemoteRunDetails(payload) {
6232
+ const run = payload.run;
6233
+ if (!run || typeof run !== "object" || Array.isArray(run))
6234
+ return null;
6235
+ return {
6236
+ ...run,
6237
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
6238
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
6239
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6240
+ };
6241
+ }
6229
6242
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6230
6243
  if (noEpicPrompt) {
6231
6244
  return false;
@@ -6364,7 +6377,7 @@ async function executeRun(context, args) {
6364
6377
  if (!run.value) {
6365
6378
  throw new CliError2("run show requires --run <id>.");
6366
6379
  }
6367
- const record = readAuthorityRun4(context.projectRoot, run.value);
6380
+ const record = readAuthorityRun4(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
6368
6381
  if (!record) {
6369
6382
  throw new CliError2(`Run not found: ${run.value}`, 2);
6370
6383
  }
@@ -6545,6 +6558,20 @@ async function executeRun(context, args) {
6545
6558
  }
6546
6559
  return { ok: true, group: "run", command, details: resumed };
6547
6560
  }
6561
+ case "restart": {
6562
+ requireNoExtraArgs(rest, "bun run rig run restart");
6563
+ if (context.dryRun) {
6564
+ if (context.outputMode === "text") {
6565
+ console.log("[dry-run] rig run restart");
6566
+ }
6567
+ return { ok: true, group: "run", command };
6568
+ }
6569
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
6570
+ if (context.outputMode === "text") {
6571
+ console.log(`Restarted run: ${restarted.runId}`);
6572
+ }
6573
+ return { ok: true, group: "run", command, details: restarted };
6574
+ }
6548
6575
  case "stop": {
6549
6576
  const runOption = takeOption(rest, "--run");
6550
6577
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -7945,6 +7972,8 @@ function stringArrayField(record, key) {
7945
7972
  }
7946
7973
  async function executeRigOwnedTaskRun(context, input) {
7947
7974
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7975
+ const existingRunRecord = readAuthorityRun5(context.projectRoot, input.runId);
7976
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
7948
7977
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7949
7978
  let prompt = buildRunPrompt({
7950
7979
  projectRoot: context.projectRoot,
@@ -8000,14 +8029,14 @@ async function executeRigOwnedTaskRun(context, input) {
8000
8029
  taskId: runtimeTaskId,
8001
8030
  createdAt: startedAt,
8002
8031
  runtimeAdapter: input.runtimeAdapter,
8003
- status: "created"
8032
+ status: resumeMode ? "preparing" : "created"
8004
8033
  });
8005
8034
  patchAuthorityRun(context.projectRoot, input.runId, {
8006
8035
  status: "preparing",
8007
8036
  startedAt,
8008
8037
  completedAt: null,
8009
8038
  errorText: null,
8010
- artifactRoot: null,
8039
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
8011
8040
  runtimeAdapter: input.runtimeAdapter,
8012
8041
  runtimeMode: input.runtimeMode,
8013
8042
  interactionMode: input.interactionMode,
@@ -8023,9 +8052,9 @@ async function executeRigOwnedTaskRun(context, input) {
8023
8052
  detail: input.taskId ?? input.title ?? runtimeTaskId
8024
8053
  });
8025
8054
  appendRunLog(context.projectRoot, input.runId, {
8026
- id: `log:${input.runId}:start`,
8027
- title: "Rig task run started",
8028
- detail: input.taskId ?? input.title ?? runtimeTaskId,
8055
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
8056
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
8057
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
8029
8058
  tone: "info",
8030
8059
  status: "preparing",
8031
8060
  createdAt: startedAt
@@ -8103,11 +8132,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8103
8132
  let reviewAction;
8104
8133
  let verificationStarted = false;
8105
8134
  let reviewStarted = false;
8106
- let latestRuntimeWorkspace = null;
8107
- let latestSessionDir = null;
8108
- let latestLogsDir = null;
8135
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
8136
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve22(existingRunRecord.sessionPath, "..") : null;
8137
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
8109
8138
  let latestProviderCommand = null;
8110
- let latestRuntimeBranch = null;
8139
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
8111
8140
  let snapshotSidecarPromise = null;
8112
8141
  let dirtyBaselineApplied = false;
8113
8142
  const childEnv = {
@@ -8125,7 +8154,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8125
8154
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
8126
8155
  RIG_SERVER_RUN_ID: input.runId
8127
8156
  },
8128
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
8157
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
8158
+ ...resumeMode ? {
8159
+ RIG_RUN_RESUME: "1",
8160
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
8161
+ } : {}
8129
8162
  };
8130
8163
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
8131
8164
  Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
@@ -8431,7 +8464,25 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8431
8464
  let reviewFailureDetail = null;
8432
8465
  const stderrLines = [];
8433
8466
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
8434
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
8467
+ if (resumeMode && latestRuntimeWorkspace) {
8468
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
8469
+ taskId: input.taskId ?? runtimeTaskId,
8470
+ workspaceDir: latestRuntimeWorkspace
8471
+ });
8472
+ if (acceptedArtifactState.accepted) {
8473
+ appendRunLog(context.projectRoot, input.runId, {
8474
+ id: `log:${input.runId}:resume-accepted-artifacts`,
8475
+ title: "Resume found accepted artifacts; continuing closeout",
8476
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
8477
+ tone: "info",
8478
+ status: "validating",
8479
+ createdAt: new Date().toISOString()
8480
+ });
8481
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
8482
+ exit = { code: 0, signal: null };
8483
+ }
8484
+ }
8485
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8435
8486
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8436
8487
  const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8437
8488
  cwd: context.projectRoot,
@@ -67,6 +67,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
67
67
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
68
68
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
69
69
  const next = {
70
+ ...existing ?? {},
70
71
  runId: input.runId,
71
72
  projectRoot,
72
73
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -126,6 +126,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
126
126
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
127
127
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
128
128
  const next = {
129
+ ...existing ?? {},
129
130
  runId: input.runId,
130
131
  projectRoot,
131
132
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -64,6 +64,7 @@ import {
64
64
  listOpenEpics,
65
65
  resolveDefaultEpic,
66
66
  runResume,
67
+ runRestart,
67
68
  runStatus,
68
69
  runStop,
69
70
  startRun,
@@ -406,6 +407,17 @@ async function attachRunOperatorView(context, input) {
406
407
  }
407
408
 
408
409
  // packages/cli/src/commands/run.ts
410
+ function normalizeRemoteRunDetails(payload) {
411
+ const run = payload.run;
412
+ if (!run || typeof run !== "object" || Array.isArray(run))
413
+ return null;
414
+ return {
415
+ ...run,
416
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
417
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
418
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
419
+ };
420
+ }
409
421
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
410
422
  if (noEpicPrompt) {
411
423
  return false;
@@ -544,7 +556,7 @@ async function executeRun(context, args) {
544
556
  if (!run.value) {
545
557
  throw new CliError2("run show requires --run <id>.");
546
558
  }
547
- const record = readAuthorityRun(context.projectRoot, run.value);
559
+ const record = readAuthorityRun(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
548
560
  if (!record) {
549
561
  throw new CliError2(`Run not found: ${run.value}`, 2);
550
562
  }
@@ -725,6 +737,20 @@ async function executeRun(context, args) {
725
737
  }
726
738
  return { ok: true, group: "run", command, details: resumed };
727
739
  }
740
+ case "restart": {
741
+ requireNoExtraArgs(rest, "bun run rig run restart");
742
+ if (context.dryRun) {
743
+ if (context.outputMode === "text") {
744
+ console.log("[dry-run] rig run restart");
745
+ }
746
+ return { ok: true, group: "run", command };
747
+ }
748
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
749
+ if (context.outputMode === "text") {
750
+ console.log(`Restarted run: ${restarted.runId}`);
751
+ }
752
+ return { ok: true, group: "run", command, details: restarted };
753
+ }
728
754
  case "stop": {
729
755
  const runOption = takeOption(rest, "--run");
730
756
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -135,6 +135,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
135
135
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
136
136
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
137
137
  const next = {
138
+ ...existing ?? {},
138
139
  runId: input.runId,
139
140
  projectRoot,
140
141
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -1081,6 +1082,8 @@ function stringArrayField(record, key) {
1081
1082
  }
1082
1083
  async function executeRigOwnedTaskRun(context, input) {
1083
1084
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
1085
+ const existingRunRecord = readAuthorityRun3(context.projectRoot, input.runId);
1086
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
1084
1087
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
1085
1088
  let prompt = buildRunPrompt({
1086
1089
  projectRoot: context.projectRoot,
@@ -1136,14 +1139,14 @@ async function executeRigOwnedTaskRun(context, input) {
1136
1139
  taskId: runtimeTaskId,
1137
1140
  createdAt: startedAt,
1138
1141
  runtimeAdapter: input.runtimeAdapter,
1139
- status: "created"
1142
+ status: resumeMode ? "preparing" : "created"
1140
1143
  });
1141
1144
  patchAuthorityRun(context.projectRoot, input.runId, {
1142
1145
  status: "preparing",
1143
1146
  startedAt,
1144
1147
  completedAt: null,
1145
1148
  errorText: null,
1146
- artifactRoot: null,
1149
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
1147
1150
  runtimeAdapter: input.runtimeAdapter,
1148
1151
  runtimeMode: input.runtimeMode,
1149
1152
  interactionMode: input.interactionMode,
@@ -1159,9 +1162,9 @@ async function executeRigOwnedTaskRun(context, input) {
1159
1162
  detail: input.taskId ?? input.title ?? runtimeTaskId
1160
1163
  });
1161
1164
  appendRunLog(context.projectRoot, input.runId, {
1162
- id: `log:${input.runId}:start`,
1163
- title: "Rig task run started",
1164
- detail: input.taskId ?? input.title ?? runtimeTaskId,
1165
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
1166
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
1167
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
1165
1168
  tone: "info",
1166
1169
  status: "preparing",
1167
1170
  createdAt: startedAt
@@ -1239,11 +1242,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
1239
1242
  let reviewAction;
1240
1243
  let verificationStarted = false;
1241
1244
  let reviewStarted = false;
1242
- let latestRuntimeWorkspace = null;
1243
- let latestSessionDir = null;
1244
- let latestLogsDir = null;
1245
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
1246
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve4(existingRunRecord.sessionPath, "..") : null;
1247
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
1245
1248
  let latestProviderCommand = null;
1246
- let latestRuntimeBranch = null;
1249
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
1247
1250
  let snapshotSidecarPromise = null;
1248
1251
  let dirtyBaselineApplied = false;
1249
1252
  const childEnv = {
@@ -1261,7 +1264,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
1261
1264
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
1262
1265
  RIG_SERVER_RUN_ID: input.runId
1263
1266
  },
1264
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
1267
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
1268
+ ...resumeMode ? {
1269
+ RIG_RUN_RESUME: "1",
1270
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
1271
+ } : {}
1265
1272
  };
1266
1273
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
1267
1274
  Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
@@ -1567,7 +1574,25 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
1567
1574
  let reviewFailureDetail = null;
1568
1575
  const stderrLines = [];
1569
1576
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
1570
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
1577
+ if (resumeMode && latestRuntimeWorkspace) {
1578
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
1579
+ taskId: input.taskId ?? runtimeTaskId,
1580
+ workspaceDir: latestRuntimeWorkspace
1581
+ });
1582
+ if (acceptedArtifactState.accepted) {
1583
+ appendRunLog(context.projectRoot, input.runId, {
1584
+ id: `log:${input.runId}:resume-accepted-artifacts`,
1585
+ title: "Resume found accepted artifacts; continuing closeout",
1586
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
1587
+ tone: "info",
1588
+ status: "validating",
1589
+ createdAt: new Date().toISOString()
1590
+ });
1591
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
1592
+ exit = { code: 0, signal: null };
1593
+ }
1594
+ }
1595
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
1571
1596
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
1572
1597
  const child = spawn(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
1573
1598
  cwd: context.projectRoot,
@@ -3240,6 +3240,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3240
3240
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
3241
3241
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
3242
3242
  const next = {
3243
+ ...existing ?? {},
3243
3244
  runId: input.runId,
3244
3245
  projectRoot,
3245
3246
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -5912,6 +5913,7 @@ import {
5912
5913
  listOpenEpics,
5913
5914
  resolveDefaultEpic,
5914
5915
  runResume,
5916
+ runRestart,
5915
5917
  runStatus,
5916
5918
  runStop,
5917
5919
  startRun,
@@ -6020,6 +6022,17 @@ async function attachRunOperatorView(context, input) {
6020
6022
  }
6021
6023
 
6022
6024
  // packages/cli/src/commands/run.ts
6025
+ function normalizeRemoteRunDetails(payload) {
6026
+ const run = payload.run;
6027
+ if (!run || typeof run !== "object" || Array.isArray(run))
6028
+ return null;
6029
+ return {
6030
+ ...run,
6031
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
6032
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
6033
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6034
+ };
6035
+ }
6023
6036
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6024
6037
  if (noEpicPrompt) {
6025
6038
  return false;
@@ -6158,7 +6171,7 @@ async function executeRun(context, args) {
6158
6171
  if (!run.value) {
6159
6172
  throw new CliError2("run show requires --run <id>.");
6160
6173
  }
6161
- const record = readAuthorityRun4(context.projectRoot, run.value);
6174
+ const record = readAuthorityRun4(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
6162
6175
  if (!record) {
6163
6176
  throw new CliError2(`Run not found: ${run.value}`, 2);
6164
6177
  }
@@ -6339,6 +6352,20 @@ async function executeRun(context, args) {
6339
6352
  }
6340
6353
  return { ok: true, group: "run", command, details: resumed };
6341
6354
  }
6355
+ case "restart": {
6356
+ requireNoExtraArgs(rest, "bun run rig run restart");
6357
+ if (context.dryRun) {
6358
+ if (context.outputMode === "text") {
6359
+ console.log("[dry-run] rig run restart");
6360
+ }
6361
+ return { ok: true, group: "run", command };
6362
+ }
6363
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
6364
+ if (context.outputMode === "text") {
6365
+ console.log(`Restarted run: ${restarted.runId}`);
6366
+ }
6367
+ return { ok: true, group: "run", command, details: restarted };
6368
+ }
6342
6369
  case "stop": {
6343
6370
  const runOption = takeOption(rest, "--run");
6344
6371
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -7739,6 +7766,8 @@ function stringArrayField(record, key) {
7739
7766
  }
7740
7767
  async function executeRigOwnedTaskRun(context, input) {
7741
7768
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7769
+ const existingRunRecord = readAuthorityRun5(context.projectRoot, input.runId);
7770
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
7742
7771
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7743
7772
  let prompt = buildRunPrompt({
7744
7773
  projectRoot: context.projectRoot,
@@ -7794,14 +7823,14 @@ async function executeRigOwnedTaskRun(context, input) {
7794
7823
  taskId: runtimeTaskId,
7795
7824
  createdAt: startedAt,
7796
7825
  runtimeAdapter: input.runtimeAdapter,
7797
- status: "created"
7826
+ status: resumeMode ? "preparing" : "created"
7798
7827
  });
7799
7828
  patchAuthorityRun(context.projectRoot, input.runId, {
7800
7829
  status: "preparing",
7801
7830
  startedAt,
7802
7831
  completedAt: null,
7803
7832
  errorText: null,
7804
- artifactRoot: null,
7833
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
7805
7834
  runtimeAdapter: input.runtimeAdapter,
7806
7835
  runtimeMode: input.runtimeMode,
7807
7836
  interactionMode: input.interactionMode,
@@ -7817,9 +7846,9 @@ async function executeRigOwnedTaskRun(context, input) {
7817
7846
  detail: input.taskId ?? input.title ?? runtimeTaskId
7818
7847
  });
7819
7848
  appendRunLog(context.projectRoot, input.runId, {
7820
- id: `log:${input.runId}:start`,
7821
- title: "Rig task run started",
7822
- detail: input.taskId ?? input.title ?? runtimeTaskId,
7849
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
7850
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
7851
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
7823
7852
  tone: "info",
7824
7853
  status: "preparing",
7825
7854
  createdAt: startedAt
@@ -7897,11 +7926,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
7897
7926
  let reviewAction;
7898
7927
  let verificationStarted = false;
7899
7928
  let reviewStarted = false;
7900
- let latestRuntimeWorkspace = null;
7901
- let latestSessionDir = null;
7902
- let latestLogsDir = null;
7929
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
7930
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve21(existingRunRecord.sessionPath, "..") : null;
7931
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
7903
7932
  let latestProviderCommand = null;
7904
- let latestRuntimeBranch = null;
7933
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
7905
7934
  let snapshotSidecarPromise = null;
7906
7935
  let dirtyBaselineApplied = false;
7907
7936
  const childEnv = {
@@ -7919,7 +7948,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
7919
7948
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
7920
7949
  RIG_SERVER_RUN_ID: input.runId
7921
7950
  },
7922
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
7951
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
7952
+ ...resumeMode ? {
7953
+ RIG_RUN_RESUME: "1",
7954
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
7955
+ } : {}
7923
7956
  };
7924
7957
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
7925
7958
  Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
@@ -8225,7 +8258,25 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8225
8258
  let reviewFailureDetail = null;
8226
8259
  const stderrLines = [];
8227
8260
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
8228
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
8261
+ if (resumeMode && latestRuntimeWorkspace) {
8262
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
8263
+ taskId: input.taskId ?? runtimeTaskId,
8264
+ workspaceDir: latestRuntimeWorkspace
8265
+ });
8266
+ if (acceptedArtifactState.accepted) {
8267
+ appendRunLog(context.projectRoot, input.runId, {
8268
+ id: `log:${input.runId}:resume-accepted-artifacts`,
8269
+ title: "Resume found accepted artifacts; continuing closeout",
8270
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
8271
+ tone: "info",
8272
+ status: "validating",
8273
+ createdAt: new Date().toISOString()
8274
+ });
8275
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
8276
+ exit = { code: 0, signal: null };
8277
+ }
8278
+ }
8279
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8229
8280
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8230
8281
  const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8231
8282
  cwd: context.projectRoot,
package/dist/src/index.js CHANGED
@@ -3442,6 +3442,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
3442
3442
  const runtimeAdapter = normalizeRuntimeAdapter(input.runtimeAdapter ?? existing?.runtimeAdapter ?? "claude-code");
3443
3443
  const title = resolveTaskTitleForAuthorityRun(projectRoot, input.taskId) ?? input.taskId;
3444
3444
  const next = {
3445
+ ...existing ?? {},
3445
3446
  runId: input.runId,
3446
3447
  projectRoot,
3447
3448
  workspaceId: existing?.workspaceId ?? RIG_WORKSPACE_ID,
@@ -6114,6 +6115,7 @@ import {
6114
6115
  listOpenEpics,
6115
6116
  resolveDefaultEpic,
6116
6117
  runResume,
6118
+ runRestart,
6117
6119
  runStatus,
6118
6120
  runStop,
6119
6121
  startRun,
@@ -6222,6 +6224,17 @@ async function attachRunOperatorView(context, input) {
6222
6224
  }
6223
6225
 
6224
6226
  // packages/cli/src/commands/run.ts
6227
+ function normalizeRemoteRunDetails(payload) {
6228
+ const run = payload.run;
6229
+ if (!run || typeof run !== "object" || Array.isArray(run))
6230
+ return null;
6231
+ return {
6232
+ ...run,
6233
+ ...Array.isArray(payload.timeline) ? { timeline: payload.timeline } : {},
6234
+ ...Array.isArray(payload.approvals) ? { approvals: payload.approvals } : {},
6235
+ ...Array.isArray(payload.userInputs) ? { userInputs: payload.userInputs } : {}
6236
+ };
6237
+ }
6225
6238
  function shouldPromptForEpicSelection(context, command, promptEpic, noEpicPrompt) {
6226
6239
  if (noEpicPrompt) {
6227
6240
  return false;
@@ -6360,7 +6373,7 @@ async function executeRun(context, args) {
6360
6373
  if (!run.value) {
6361
6374
  throw new CliError2("run show requires --run <id>.");
6362
6375
  }
6363
- const record = readAuthorityRun4(context.projectRoot, run.value);
6376
+ const record = readAuthorityRun4(context.projectRoot, run.value) ?? normalizeRemoteRunDetails(await getRunDetailsViaServer(context, run.value).catch(() => ({})));
6364
6377
  if (!record) {
6365
6378
  throw new CliError2(`Run not found: ${run.value}`, 2);
6366
6379
  }
@@ -6541,6 +6554,20 @@ async function executeRun(context, args) {
6541
6554
  }
6542
6555
  return { ok: true, group: "run", command, details: resumed };
6543
6556
  }
6557
+ case "restart": {
6558
+ requireNoExtraArgs(rest, "bun run rig run restart");
6559
+ if (context.dryRun) {
6560
+ if (context.outputMode === "text") {
6561
+ console.log("[dry-run] rig run restart");
6562
+ }
6563
+ return { ok: true, group: "run", command };
6564
+ }
6565
+ const restarted = await runRestart(context.projectRoot, runtimeContext);
6566
+ if (context.outputMode === "text") {
6567
+ console.log(`Restarted run: ${restarted.runId}`);
6568
+ }
6569
+ return { ok: true, group: "run", command, details: restarted };
6570
+ }
6544
6571
  case "stop": {
6545
6572
  const runOption = takeOption(rest, "--run");
6546
6573
  const positionalRunId = runOption.rest.length > 0 ? runOption.rest[0] : undefined;
@@ -7941,6 +7968,8 @@ function stringArrayField(record, key) {
7941
7968
  }
7942
7969
  async function executeRigOwnedTaskRun(context, input) {
7943
7970
  const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
7971
+ const existingRunRecord = readAuthorityRun5(context.projectRoot, input.runId);
7972
+ const resumeMode = process.env.RIG_RUN_RESUME === "1";
7944
7973
  const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
7945
7974
  let prompt = buildRunPrompt({
7946
7975
  projectRoot: context.projectRoot,
@@ -7996,14 +8025,14 @@ async function executeRigOwnedTaskRun(context, input) {
7996
8025
  taskId: runtimeTaskId,
7997
8026
  createdAt: startedAt,
7998
8027
  runtimeAdapter: input.runtimeAdapter,
7999
- status: "created"
8028
+ status: resumeMode ? "preparing" : "created"
8000
8029
  });
8001
8030
  patchAuthorityRun(context.projectRoot, input.runId, {
8002
8031
  status: "preparing",
8003
8032
  startedAt,
8004
8033
  completedAt: null,
8005
8034
  errorText: null,
8006
- artifactRoot: null,
8035
+ artifactRoot: resumeMode ? existingRunRecord?.artifactRoot ?? null : null,
8007
8036
  runtimeAdapter: input.runtimeAdapter,
8008
8037
  runtimeMode: input.runtimeMode,
8009
8038
  interactionMode: input.interactionMode,
@@ -8019,9 +8048,9 @@ async function executeRigOwnedTaskRun(context, input) {
8019
8048
  detail: input.taskId ?? input.title ?? runtimeTaskId
8020
8049
  });
8021
8050
  appendRunLog(context.projectRoot, input.runId, {
8022
- id: `log:${input.runId}:start`,
8023
- title: "Rig task run started",
8024
- detail: input.taskId ?? input.title ?? runtimeTaskId,
8051
+ id: `log:${input.runId}:${resumeMode ? "resume" : "start"}`,
8052
+ title: resumeMode ? "Rig task run resumed" : "Rig task run started",
8053
+ detail: resumeMode ? `Continuing the same run lifecycle for ${input.taskId ?? input.title ?? runtimeTaskId}.` : input.taskId ?? input.title ?? runtimeTaskId,
8025
8054
  tone: "info",
8026
8055
  status: "preparing",
8027
8056
  createdAt: startedAt
@@ -8099,11 +8128,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8099
8128
  let reviewAction;
8100
8129
  let verificationStarted = false;
8101
8130
  let reviewStarted = false;
8102
- let latestRuntimeWorkspace = null;
8103
- let latestSessionDir = null;
8104
- let latestLogsDir = null;
8131
+ let latestRuntimeWorkspace = resumeMode && typeof existingRunRecord?.worktreePath === "string" ? existingRunRecord.worktreePath : null;
8132
+ let latestSessionDir = resumeMode && typeof existingRunRecord?.sessionPath === "string" ? resolve22(existingRunRecord.sessionPath, "..") : null;
8133
+ let latestLogsDir = resumeMode && typeof existingRunRecord?.logRoot === "string" ? existingRunRecord.logRoot : null;
8105
8134
  let latestProviderCommand = null;
8106
- let latestRuntimeBranch = null;
8135
+ let latestRuntimeBranch = resumeMode && typeof existingRunRecord?.branch === "string" ? existingRunRecord.branch : null;
8107
8136
  let snapshotSidecarPromise = null;
8108
8137
  let dirtyBaselineApplied = false;
8109
8138
  const childEnv = {
@@ -8121,7 +8150,11 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8121
8150
  RIG_RUNTIME_ADAPTER: input.runtimeAdapter,
8122
8151
  RIG_SERVER_RUN_ID: input.runId
8123
8152
  },
8124
- ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
8153
+ ...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {},
8154
+ ...resumeMode ? {
8155
+ RIG_RUN_RESUME: "1",
8156
+ RIG_RUNTIME_ARTIFACT_CLEANUP: "preserve"
8157
+ } : {}
8125
8158
  };
8126
8159
  Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
8127
8160
  Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
@@ -8427,7 +8460,25 @@ ${planningClassification.planningRequired ? `Before implementing, write a concis
8427
8460
  let reviewFailureDetail = null;
8428
8461
  const stderrLines = [];
8429
8462
  const piAcceptedArtifactExitGraceMs = resolvePiAcceptedArtifactExitGraceMs(childEnv);
8430
- for (let attempt = 1;attempt <= maxAttempts; attempt += 1) {
8463
+ if (resumeMode && latestRuntimeWorkspace) {
8464
+ const acceptedArtifactState = readTaskRunAcceptedArtifactState({
8465
+ taskId: input.taskId ?? runtimeTaskId,
8466
+ workspaceDir: latestRuntimeWorkspace
8467
+ });
8468
+ if (acceptedArtifactState.accepted) {
8469
+ appendRunLog(context.projectRoot, input.runId, {
8470
+ id: `log:${input.runId}:resume-accepted-artifacts`,
8471
+ title: "Resume found accepted artifacts; continuing closeout",
8472
+ detail: acceptedArtifactState.reason ?? "Accepted task artifacts are present from the previous run process.",
8473
+ tone: "info",
8474
+ status: "validating",
8475
+ createdAt: new Date().toISOString()
8476
+ });
8477
+ emitServerRunEvent({ type: "log", runId: input.runId, title: "Resume found accepted artifacts; continuing closeout" });
8478
+ exit = { code: 0, signal: null };
8479
+ }
8480
+ }
8481
+ for (let attempt = 1;!exit && attempt <= maxAttempts; attempt += 1) {
8431
8482
  const attemptHostAgentCommand = buildHostAgentCommand(currentPrompt);
8432
8483
  const child = spawn2(attemptHostAgentCommand[0], attemptHostAgentCommand.slice(1), {
8433
8484
  cwd: context.projectRoot,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@h-rig/cli",
3
- "version": "0.0.6-alpha.3",
3
+ "version": "0.0.6-alpha.4",
4
4
  "type": "module",
5
5
  "description": "Rig package",
6
6
  "license": "UNLICENSED",
@@ -23,9 +23,9 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@clack/prompts": "^1.2.0",
26
- "@rig/core": "npm:@h-rig/core@0.0.6-alpha.3",
27
- "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.3",
28
- "@rig/client": "npm:@h-rig/client@0.0.6-alpha.3",
26
+ "@rig/core": "npm:@h-rig/core@0.0.6-alpha.4",
27
+ "@rig/runtime": "npm:@h-rig/runtime@0.0.6-alpha.4",
28
+ "@rig/client": "npm:@h-rig/client@0.0.6-alpha.4",
29
29
  "picocolors": "^1.1.1"
30
30
  }
31
31
  }