@delete101020/aidlc 4.0.45 → 4.0.47

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 (3) hide show
  1. package/README.md +9 -0
  2. package/dist/bundle.js +260 -108
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -469,6 +469,15 @@ and approval — a `pass` advances the step, a `reject` stops with a rerun hint.
469
469
  With `--auto-approve` it also clears `human_review` gates without pausing — a
470
470
  single command then drives the entire pipeline end-to-end.
471
471
 
472
+ An `autopilot: true` pipeline refuses to start on uncommitted changes, with
473
+ one exception: when a step stopped short (a non-zero exit such as the account
474
+ running out of usage, its `timeout_minutes`, a "stop now"), the run records
475
+ what it left in the working tree, and `run exec` carries on from exactly that
476
+ tree — switch accounts and run it again. The next attempt is told to finish
477
+ the half-written changes rather than start over. If the tree has changed
478
+ since, or the agent was killed before anything could be recorded, pass
479
+ `--allow-dirty` to start anyway.
480
+
472
481
  **`run request-update`** reopens an already-approved step (bumps its revision,
473
482
  resets downstream steps), mirroring the extension's "Request update" action.
474
483
 
package/dist/bundle.js CHANGED
@@ -21157,6 +21157,7 @@ var require_runProgress = __commonJS({
21157
21157
  exports2.isStepOptional = isStepOptional;
21158
21158
  exports2.deriveRunProgress = deriveRunProgress;
21159
21159
  exports2.isRunComplete = isRunComplete2;
21160
+ exports2.nextRunnableStep = nextRunnableStep;
21160
21161
  exports2.weighStepProgress = weighStepProgress2;
21161
21162
  var WorkspaceSchema_1 = require_WorkspaceSchema();
21162
21163
  var ACTIVE = /* @__PURE__ */ new Set([
@@ -21228,6 +21229,48 @@ var require_runProgress = __commonJS({
21228
21229
  return s.status === "rejected" || s.status === "pending";
21229
21230
  });
21230
21231
  }
21232
+ function nextRunnableStep(state, pipeline, untilIdx = -1) {
21233
+ if (!usesDag(pipeline)) {
21234
+ return state.currentStepIdx;
21235
+ }
21236
+ const skipped = deadEndPeersOfApproved(state, pipeline);
21237
+ if (untilIdx >= 0) {
21238
+ skipped.delete(untilIdx);
21239
+ const onPath = ancestorsOf(pipeline, untilIdx);
21240
+ onPath.add(untilIdx);
21241
+ state.steps.forEach((_, i) => {
21242
+ if (!onPath.has(i)) {
21243
+ skipped.add(i);
21244
+ }
21245
+ });
21246
+ }
21247
+ const runnable = (i) => isActiveStatus(state.steps[i]?.status ?? "pending") && !skipped.has(i);
21248
+ if (runnable(state.currentStepIdx)) {
21249
+ return state.currentStepIdx;
21250
+ }
21251
+ return state.steps.findIndex((_, i) => runnable(i));
21252
+ }
21253
+ function ancestorsOf(pipeline, idx) {
21254
+ const normalized = pipeline.steps.map(WorkspaceSchema_1.normalizeStep);
21255
+ const idxByDagId = /* @__PURE__ */ new Map();
21256
+ normalized.forEach((s, i) => {
21257
+ idxByDagId.set(s.name ?? s.agent, i);
21258
+ });
21259
+ const found = /* @__PURE__ */ new Set();
21260
+ const queue = [idx];
21261
+ while (queue.length > 0) {
21262
+ const cur = queue.pop();
21263
+ for (const dep of normalized[cur]?.depends_on ?? []) {
21264
+ const di = idxByDagId.get(dep);
21265
+ if (di === void 0 || found.has(di) || di === idx) {
21266
+ continue;
21267
+ }
21268
+ found.add(di);
21269
+ queue.push(di);
21270
+ }
21271
+ }
21272
+ return found;
21273
+ }
21231
21274
  function deadEndPeersOfApproved(state, pipeline) {
21232
21275
  const normalized = state.steps.map((s, i) => (0, WorkspaceSchema_1.normalizeStep)(pipeline.steps[i] ?? { agent: s.agent }));
21233
21276
  const ids = normalized.map((n) => n.name ?? n.agent);
@@ -31152,6 +31195,120 @@ var require_commandBodyFreshness = __commonJS({
31152
31195
  }
31153
31196
  });
31154
31197
 
31198
+ // ../core/dist/runs/codeFingerprint.js
31199
+ var require_codeFingerprint = __commonJS({
31200
+ "../core/dist/runs/codeFingerprint.js"(exports2) {
31201
+ "use strict";
31202
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
31203
+ if (k2 === void 0) k2 = k;
31204
+ var desc = Object.getOwnPropertyDescriptor(m, k);
31205
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
31206
+ desc = { enumerable: true, get: function() {
31207
+ return m[k];
31208
+ } };
31209
+ }
31210
+ Object.defineProperty(o, k2, desc);
31211
+ } : function(o, m, k, k2) {
31212
+ if (k2 === void 0) k2 = k;
31213
+ o[k2] = m[k];
31214
+ });
31215
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
31216
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
31217
+ } : function(o, v) {
31218
+ o["default"] = v;
31219
+ });
31220
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
31221
+ var ownKeys = function(o) {
31222
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
31223
+ var ar = [];
31224
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
31225
+ return ar;
31226
+ };
31227
+ return ownKeys(o);
31228
+ };
31229
+ return function(mod) {
31230
+ if (mod && mod.__esModule) return mod;
31231
+ var result = {};
31232
+ if (mod != null) {
31233
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31234
+ }
31235
+ __setModuleDefault(result, mod);
31236
+ return result;
31237
+ };
31238
+ }();
31239
+ Object.defineProperty(exports2, "__esModule", { value: true });
31240
+ exports2.codeFingerprint = codeFingerprint;
31241
+ exports2.uncommittedPaths = uncommittedPaths;
31242
+ var child_process_1 = require("child_process");
31243
+ var fs14 = __importStar(require("fs"));
31244
+ var os3 = __importStar(require("os"));
31245
+ var path17 = __importStar(require("path"));
31246
+ function codeFingerprint(root, exclude) {
31247
+ const git = (args, env) => (0, child_process_1.execFileSync)("git", args, {
31248
+ cwd: root,
31249
+ encoding: "utf8",
31250
+ env: env ? { ...process.env, ...env } : process.env,
31251
+ stdio: ["ignore", "pipe", "ignore"],
31252
+ maxBuffer: 64 * 1024 * 1024
31253
+ }).trim();
31254
+ let realIndex;
31255
+ try {
31256
+ realIndex = path17.resolve(root, git(["rev-parse", "--git-path", "index"]));
31257
+ } catch {
31258
+ return null;
31259
+ }
31260
+ const dir = fs14.mkdtempSync(path17.join(os3.tmpdir(), "aidlc-fp-"));
31261
+ const index = path17.join(dir, "index");
31262
+ try {
31263
+ if (fs14.existsSync(realIndex)) {
31264
+ fs14.copyFileSync(realIndex, index);
31265
+ }
31266
+ const env = { GIT_INDEX_FILE: index };
31267
+ git(["add", "-A", "--", "."], env);
31268
+ const skip = exclude.filter((p) => p && !p.startsWith(".."));
31269
+ if (skip.length > 0) {
31270
+ git(["rm", "-r", "-q", "--cached", "--ignore-unmatch", "--", ...skip], env);
31271
+ }
31272
+ return git(["write-tree"], env);
31273
+ } catch {
31274
+ return null;
31275
+ } finally {
31276
+ fs14.rmSync(dir, { recursive: true, force: true });
31277
+ }
31278
+ }
31279
+ function uncommittedPaths(root, exclude) {
31280
+ let out2;
31281
+ try {
31282
+ out2 = (0, child_process_1.execFileSync)("git", ["status", "--porcelain=v1", "-z", "--untracked-files=all"], {
31283
+ cwd: root,
31284
+ encoding: "utf8",
31285
+ stdio: ["ignore", "pipe", "ignore"],
31286
+ maxBuffer: 64 * 1024 * 1024
31287
+ });
31288
+ } catch {
31289
+ return [];
31290
+ }
31291
+ const skip = exclude.map((p) => p.split(path17.sep).join("/")).filter((p) => p && !p.startsWith(".."));
31292
+ return statusPaths(out2).filter((p) => !skip.some((s) => p === s || p.startsWith(`${s}/`)));
31293
+ }
31294
+ function statusPaths(out2) {
31295
+ const parts = out2.split("\0");
31296
+ const paths = [];
31297
+ for (let i = 0; i < parts.length; i++) {
31298
+ const entry = parts[i];
31299
+ if (entry.length < 4) {
31300
+ continue;
31301
+ }
31302
+ paths.push(entry.slice(3));
31303
+ if (entry[0] === "R" || entry[0] === "C") {
31304
+ i++;
31305
+ }
31306
+ }
31307
+ return paths;
31308
+ }
31309
+ }
31310
+ });
31311
+
31155
31312
  // ../core/dist/runs/autopilotPreflight.js
31156
31313
  var require_autopilotPreflight = __commonJS({
31157
31314
  "../core/dist/runs/autopilotPreflight.js"(exports2) {
@@ -31204,6 +31361,7 @@ var require_autopilotPreflight = __commonJS({
31204
31361
  var os3 = __importStar(require("os"));
31205
31362
  var path17 = __importStar(require("path"));
31206
31363
  var claudeHome_1 = require_claudeHome();
31364
+ var codeFingerprint_1 = require_codeFingerprint();
31207
31365
  var EpicScaffold_1 = require_EpicScaffold();
31208
31366
  var WorkspaceSchema_1 = require_WorkspaceSchema();
31209
31367
  exports2.APPROVAL_GATE_SCRIPT = "aidlc-approval-gate";
@@ -31282,14 +31440,25 @@ var require_autopilotPreflight = __commonJS({
31282
31440
  } else if (protectedBranches.has(branch)) {
31283
31441
  problems.push(`You are on "${branch}". Autopilot does not commit to it \u2014 switch to a branch for this epic (git switch -c <branch>).`);
31284
31442
  }
31285
- const skip = [
31443
+ const exclude = [
31286
31444
  toPosix(path17.relative(root, path17.join((0, EpicScaffold_1.epicsRoot)(root, config), state.runId))),
31287
31445
  ".aidlc"
31288
31446
  ];
31289
- const dirty = dirtyPaths(git(["status", "--porcelain=v1", "-z", "--untracked-files=all"]) ?? "").filter((p) => !skip.some((s) => p === s || p.startsWith(`${s}/`)));
31447
+ const dirty = (0, codeFingerprint_1.uncommittedPaths)(root, exclude);
31290
31448
  if (dirty.length > 0) {
31291
- const shown = dirty.slice(0, 5).join(", ") + (dirty.length > 5 ? `, and ${dirty.length - 5} more` : "");
31292
- problems.push(`The working tree has uncommitted changes (${shown}). Commit or stash them first: the agent would build on them, and its own changes would be mixed in with them.`);
31449
+ const shown = listPaths(dirty);
31450
+ const left = state.steps.filter((s) => s.leftover);
31451
+ const tree = left.length > 0 ? (0, codeFingerprint_1.codeFingerprint)(root, exclude) : null;
31452
+ const own = tree ? left.find((s) => s.leftover.tree === tree) : void 0;
31453
+ if (own) {
31454
+ args.onNote?.(`Carrying on from what "${own.name ?? own.agent}" left uncommitted when it ${leftoverWhy(own)} (${shown}). Nothing else has changed since.`);
31455
+ } else if (args.allowDirty) {
31456
+ args.onNote?.(`--allow-dirty: starting on top of uncommitted changes (${shown}).`);
31457
+ } else {
31458
+ args.onDirty?.(dirty);
31459
+ const changed = left.length > 0 ? ` They are not what "${left.map((s) => s.name ?? s.agent).join('", "')}" left when it stopped \u2014 something has changed since.` : "";
31460
+ problems.push(`The working tree has uncommitted changes (${shown}). Commit or stash them first: the agent would build on them, and its own changes would be mixed in with them.${changed} If they are this run's own unfinished work, run again with --allow-dirty.`);
31461
+ }
31293
31462
  }
31294
31463
  }
31295
31464
  const claudeSteps = new Set(state.steps.filter((s) => s.status !== "approved").map((s) => config.agents.find((a) => a.id === s.agent)).filter((a) => a?.runner === "default").map((a) => a.id));
@@ -31325,20 +31494,18 @@ var require_autopilotPreflight = __commonJS({
31325
31494
  function emptyCiChecksMessage2(runner, step) {
31326
31495
  return `${runner} has no commands in CHECKS, so it passes whatever "${step}" builds. Add your lint, typecheck and test commands to it before leaving a run alone.`;
31327
31496
  }
31328
- function dirtyPaths(out2) {
31329
- const parts = out2.split("\0");
31330
- const paths = [];
31331
- for (let i = 0; i < parts.length; i++) {
31332
- const entry = parts[i];
31333
- if (entry.length < 4) {
31334
- continue;
31335
- }
31336
- paths.push(entry.slice(3));
31337
- if (entry[0] === "R" || entry[0] === "C") {
31338
- i++;
31339
- }
31497
+ function listPaths(paths) {
31498
+ return paths.slice(0, 5).join(", ") + (paths.length > 5 ? `, and ${paths.length - 5} more` : "");
31499
+ }
31500
+ function leftoverWhy(step) {
31501
+ switch (step.leftover.why) {
31502
+ case "timeout":
31503
+ return "ran past its timeout_minutes";
31504
+ case "stopped":
31505
+ return "was stopped";
31506
+ default:
31507
+ return "failed";
31340
31508
  }
31341
- return paths;
31342
31509
  }
31343
31510
  function matcherCoversBash(matcher) {
31344
31511
  if (!matcher || matcher === "*") {
@@ -32164,89 +32331,6 @@ var require_runLock = __commonJS({
32164
32331
  }
32165
32332
  });
32166
32333
 
32167
- // ../core/dist/runs/codeFingerprint.js
32168
- var require_codeFingerprint = __commonJS({
32169
- "../core/dist/runs/codeFingerprint.js"(exports2) {
32170
- "use strict";
32171
- var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
32172
- if (k2 === void 0) k2 = k;
32173
- var desc = Object.getOwnPropertyDescriptor(m, k);
32174
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
32175
- desc = { enumerable: true, get: function() {
32176
- return m[k];
32177
- } };
32178
- }
32179
- Object.defineProperty(o, k2, desc);
32180
- } : function(o, m, k, k2) {
32181
- if (k2 === void 0) k2 = k;
32182
- o[k2] = m[k];
32183
- });
32184
- var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
32185
- Object.defineProperty(o, "default", { enumerable: true, value: v });
32186
- } : function(o, v) {
32187
- o["default"] = v;
32188
- });
32189
- var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
32190
- var ownKeys = function(o) {
32191
- ownKeys = Object.getOwnPropertyNames || function(o2) {
32192
- var ar = [];
32193
- for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
32194
- return ar;
32195
- };
32196
- return ownKeys(o);
32197
- };
32198
- return function(mod) {
32199
- if (mod && mod.__esModule) return mod;
32200
- var result = {};
32201
- if (mod != null) {
32202
- for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32203
- }
32204
- __setModuleDefault(result, mod);
32205
- return result;
32206
- };
32207
- }();
32208
- Object.defineProperty(exports2, "__esModule", { value: true });
32209
- exports2.codeFingerprint = codeFingerprint;
32210
- var child_process_1 = require("child_process");
32211
- var fs14 = __importStar(require("fs"));
32212
- var os3 = __importStar(require("os"));
32213
- var path17 = __importStar(require("path"));
32214
- function codeFingerprint(root, exclude) {
32215
- const git = (args, env) => (0, child_process_1.execFileSync)("git", args, {
32216
- cwd: root,
32217
- encoding: "utf8",
32218
- env: env ? { ...process.env, ...env } : process.env,
32219
- stdio: ["ignore", "pipe", "ignore"],
32220
- maxBuffer: 64 * 1024 * 1024
32221
- }).trim();
32222
- let realIndex;
32223
- try {
32224
- realIndex = path17.resolve(root, git(["rev-parse", "--git-path", "index"]));
32225
- } catch {
32226
- return null;
32227
- }
32228
- const dir = fs14.mkdtempSync(path17.join(os3.tmpdir(), "aidlc-fp-"));
32229
- const index = path17.join(dir, "index");
32230
- try {
32231
- if (fs14.existsSync(realIndex)) {
32232
- fs14.copyFileSync(realIndex, index);
32233
- }
32234
- const env = { GIT_INDEX_FILE: index };
32235
- git(["add", "-A", "--", "."], env);
32236
- const skip = exclude.filter((p) => p && !p.startsWith(".."));
32237
- if (skip.length > 0) {
32238
- git(["rm", "-r", "-q", "--cached", "--ignore-unmatch", "--", ...skip], env);
32239
- }
32240
- return git(["write-tree"], env);
32241
- } catch {
32242
- return null;
32243
- } finally {
32244
- fs14.rmSync(dir, { recursive: true, force: true });
32245
- }
32246
- }
32247
- }
32248
- });
32249
-
32250
32334
  // ../core/dist/runs/batchStatus.js
32251
32335
  var require_batchStatus = __commonJS({
32252
32336
  "../core/dist/runs/batchStatus.js"(exports2) {
@@ -32438,16 +32522,27 @@ var require_execEngine = __commonJS({
32438
32522
  const batchesRun = /* @__PURE__ */ new Map();
32439
32523
  if (initialPipeline.autopilot && !opts.dryRun) {
32440
32524
  let problems;
32525
+ let dirty;
32441
32526
  try {
32442
32527
  const ws = WorkspaceLoader_1.WorkspaceLoader.load(root);
32443
- problems = (0, autopilotPreflight_1.autopilotPreflight)({ root, state: initialState, pipeline: initialPipeline, config: ws.config });
32528
+ problems = (0, autopilotPreflight_1.autopilotPreflight)({
32529
+ root,
32530
+ state: initialState,
32531
+ pipeline: initialPipeline,
32532
+ config: ws.config,
32533
+ allowDirty: opts.allowDirty,
32534
+ onNote: (m) => hooks.onPreflightNote?.(m),
32535
+ onDirty: (paths) => {
32536
+ dirty = paths;
32537
+ }
32538
+ });
32444
32539
  } catch (err) {
32445
32540
  problems = [`Could not check the workspace: ${errMsg(err)}`];
32446
32541
  }
32447
32542
  if (problems.length > 0) {
32448
32543
  hooks.onRunFailed?.(`Pipeline "${initialPipeline.id}" is an autopilot pipeline, and it is not safe to leave this run alone yet:
32449
32544
  ` + problems.map((p) => ` - ${p}`).join("\n"));
32450
- return { kind: "error" };
32545
+ return dirty && problems.length === 1 ? { kind: "error", dirty } : { kind: "error" };
32451
32546
  }
32452
32547
  }
32453
32548
  while (true) {
@@ -32468,6 +32563,26 @@ var require_execEngine = __commonJS({
32468
32563
  hooks.onRunFailed?.("Run failed.");
32469
32564
  return { kind: "error" };
32470
32565
  }
32566
+ const atIdx = state.currentStepIdx;
32567
+ if (state.steps[atIdx] && state.steps[atIdx].status !== "rejected") {
32568
+ const pick = (0, runProgress_1.nextRunnableStep)(state, initialPipeline, untilIdx);
32569
+ if (pick >= 0 && pick !== atIdx) {
32570
+ hooks.onStepBypassed?.({
32571
+ stepIdx: atIdx,
32572
+ label: stepLabel3(state.steps[atIdx]),
32573
+ nextStepIdx: pick,
32574
+ nextLabel: stepLabel3(state.steps[pick]),
32575
+ runId
32576
+ });
32577
+ state.currentStepIdx = pick;
32578
+ if (!opts.dryRun) {
32579
+ persist(root, state);
32580
+ }
32581
+ } else if (pick < 0 && untilIdx >= 0 && (0, runProgress_1.isActiveStatus)(state.steps[atIdx].status)) {
32582
+ hooks.onUntilStop?.({ untilIdx });
32583
+ return { kind: "until" };
32584
+ }
32585
+ }
32471
32586
  const step = state.steps[state.currentStepIdx];
32472
32587
  if (step.status === "awaiting_auto_review") {
32473
32588
  const proceed = await runAutoReviewStep(root, runId, hooks);
@@ -32706,7 +32821,8 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32706
32821
  }
32707
32822
  const batchNo = report ? batchesOf(stepRec).length + 1 : 0;
32708
32823
  const batchNote = report ? batchInstructions(report, batchNo, stepRec.revision) : null;
32709
- const userMessage = [baseMessage, feedback, batchNote].filter(Boolean).join("\n\n");
32824
+ const leftoverNote = leftoverInstructions(stepRec);
32825
+ const userMessage = [baseMessage, feedback, leftoverNote, batchNote].filter(Boolean).join("\n\n");
32710
32826
  if (opts.dryRun) {
32711
32827
  hooks.onDryRunPreview?.({
32712
32828
  skills: skillIds.join(", "),
@@ -32768,6 +32884,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32768
32884
  }
32769
32885
  if (stop.signal.aborted) {
32770
32886
  recordInterrupted(root, runId, stepIdx, timedOut ? { why: "timeout", minutes } : { why: "stopped" });
32887
+ recordLeftover(root, runId, stepIdx, timedOut ? "timeout" : "stopped", codeExclude);
32771
32888
  if (timedOut) {
32772
32889
  hooks.onStepFailed?.({
32773
32890
  stepIdx,
@@ -32781,6 +32898,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32781
32898
  return "stopped";
32782
32899
  }
32783
32900
  if (!result || !result.success) {
32901
+ recordLeftover(root, runId, stepIdx, "failed", codeExclude);
32784
32902
  hooks.onStepFailed?.({ stepIdx, agent: agentId, label: stepLabel3(stepRec), message: `Step "${agentId}" failed (non-zero exit).` });
32785
32903
  return "failed";
32786
32904
  }
@@ -32836,6 +32954,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32836
32954
  return "failed";
32837
32955
  }
32838
32956
  recordProvenance(rec, { agent, resolvedModel, agentModel, skillIds, alternatives, modelOpts });
32957
+ delete rec.leftover;
32839
32958
  const cost = addBatchCost(rec, batchNo, result, batchCost(result, ws, agent.runner, resolvedModel ?? agentModel));
32840
32959
  rec.history = [...rec.history ?? [], {
32841
32960
  kind: "batch",
@@ -32864,6 +32983,7 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32864
32983
  freshState = RunStateStore_1.RunStateStore.load(root, runId);
32865
32984
  const rec = freshState.steps[stepIdx];
32866
32985
  recordProvenance(rec, { agent, resolvedModel, agentModel, skillIds, alternatives, modelOpts });
32986
+ delete rec.leftover;
32867
32987
  addBatchCost(rec, batchNo, result, batchCost(result, ws, agent.runner, resolvedModel ?? agentModel));
32868
32988
  next = (0, PipelineRunner_1.markStepDone)({ state: freshState, pipeline, workspaceRoot: root });
32869
32989
  } catch (err) {
@@ -32992,6 +33112,29 @@ About these inputs: ${(0, inheritedContext_1.inheritedContextNote)(epicRoot)}` :
32992
33112
  }];
32993
33113
  RunStateStore_1.RunStateStore.save(root, fresh);
32994
33114
  }
33115
+ function recordLeftover(root, runId, stepIdx, why, exclude) {
33116
+ const fresh = RunStateStore_1.RunStateStore.load(root, runId);
33117
+ const rec = fresh?.steps[stepIdx];
33118
+ if (!fresh || !rec) {
33119
+ return;
33120
+ }
33121
+ const paths = (0, codeFingerprint_1.uncommittedPaths)(root, exclude);
33122
+ const tree = paths.length > 0 ? (0, codeFingerprint_1.codeFingerprint)(root, exclude) : null;
33123
+ if (tree) {
33124
+ rec.leftover = { at: (/* @__PURE__ */ new Date()).toISOString(), revision: rec.revision, why, tree, paths };
33125
+ } else {
33126
+ delete rec.leftover;
33127
+ }
33128
+ RunStateStore_1.RunStateStore.save(root, fresh);
33129
+ }
33130
+ function leftoverInstructions(rec) {
33131
+ const l = rec.leftover;
33132
+ if (!l || l.revision !== rec.revision) {
33133
+ return null;
33134
+ }
33135
+ const shown = l.paths.slice(0, 20).join(", ") + (l.paths.length > 20 ? `, and ${l.paths.length - 20} more` : "");
33136
+ return `A previous attempt at this revision stopped before it finished. Its unfinished changes are still in the working tree, uncommitted: ${shown}. Read them first and carry on from there \u2014 keep what is right, finish what is missing \u2014 rather than starting over.`;
33137
+ }
32995
33138
  async function runAutoReviewStep(root, runId, hooks) {
32996
33139
  const state = RunStateStore_1.RunStateStore.load(root, runId);
32997
33140
  if (!state) {
@@ -35463,9 +35606,9 @@ var require_dist = __commonJS({
35463
35606
  exports2.readUserConfig = exports2.readGitUserName = exports2.ensureUserConfigIgnored = exports2.USER_CONFIG_RELPATH = exports2.USER_CONFIG_IGNORE_LINE = exports2.suggestEpicId = exports2.resolveEpicIdPrefixChain = exports2.resolveEpicIdPrefix = exports2.epicIdDateStamp = exports2.deriveEpicIdPrefix = exports2.EPIC_ID_PREFIX_PATTERN = exports2.EPIC_ID_PREFIX_KEY = exports2.resolveArtifactLanguage = exports2.commandBodyPredatesArtifactLanguage = exports2.artifactLanguageSection = exports2.ARTIFACT_LANGUAGE_HEADING = exports2.stripPersonaDirectives = exports2.composeAgentPrompt = exports2.PROJECT_INSTRUCTION_FILES = exports2.findProjectInstructions = exports2.stripPersonaMetadata = exports2.PersonaLoader = exports2.SkillNotFoundError = exports2.SkillLoader = exports2.EnvVarMissingError = exports2.EnvResolver = exports2.epicPipelineReport = exports2.planEpicPipelineExtraction = exports2.epicOwningPipeline = exports2.unstageEpicPipeline = exports2.stageEpicPipeline = exports2.writeEpicPipelines = exports2.splitEpicPipelines = exports2.mergeEpicPipelines = exports2.epicPipelinePath = exports2.EPIC_PIPELINE_FILENAME = exports2.unusedAfterStepRemoval = exports2.skillReferences = exports2.agentReferences = exports2.renameSkillRefs = exports2.renameAgentRefs = exports2.dropRecipesForPipeline = exports2.dropRecipeStep = exports2.recipesDrawingFrom = exports2.WORKSPACE_DIR = exports2.WORKSPACE_FILENAME = exports2.WorkspaceParseError = exports2.WorkspaceNotFoundError = exports2.WorkspaceLoader = exports2.renderPlanMarkdown = void 0;
35464
35607
  exports2.hasEmptyCiChecks = exports2.findApprovalGate = exports2.autopilotPreflight = exports2.STOP_GRACE_MS = exports2.stopProcessTree = exports2.stopOnAbort = exports2.processGroupSpawnOptions = exports2.claudeModelArg = exports2.DefaultRunner = exports2.RunnerRegistry = exports2.targetPath = exports2.scopePaths = exports2.discoverAssets = exports2.commandBodyIsStale = exports2.readEpicTags = exports2.normalizeTags = exports2.normalizeTag = exports2.epicMatchesTags = exports2.applyTagEdit = exports2.MAX_TAG_LENGTH = exports2.EPIC_TAGS_KEY = exports2.inheritedContextNote = exports2.INHERITED_CONTEXT_MARKER = exports2.strictModeSection = exports2.resolveEpicStrictMode = exports2.epicStrictMode = exports2.commandBodyPredatesStrictMode = exports2.STRICT_MODE_KEY = exports2.STRICT_MODE_HEADING = exports2.setEpicWatched = exports2.setEpicListFlat = exports2.setEpicSort = exports2.setActiveEpic = exports2.recordEpicOpened = exports2.readEpicListFlat = exports2.readEpicSort = exports2.readEpicFocus = exports2.pushRecent = exports2.epicSortFrom = exports2.epicIdFromBranch = exports2.epicFocusFrom = exports2.WATCHED_EPICS_KEY = exports2.RECENT_EPICS_LIMIT = exports2.RECENT_EPICS_KEY = exports2.EPIC_LIST_FLAT_KEY = exports2.EPIC_SORT_KEY = exports2.ACTIVE_EPIC_KEY = exports2.writeUserEpicIdPrefix = exports2.userConfigPath = exports2.updateUserConfig = void 0;
35465
35608
  exports2.isRunComplete = exports2.deriveRunProgress = exports2.PipelineRunError = exports2.retryAutoReview = exports2.submitAutoReviewVerdict = exports2.dirtyUpstreamOf = exports2.rerunApprovedStep = exports2.canRerunApprovedStep = exports2.recordLaunchFeedback = exports2.chooseStepModel = exports2.chooseStepSkill = exports2.requestStepUpdate = exports2.rerunStep = exports2.rejectStep = exports2.approveStep = exports2.undoStepDone = exports2.canUndoStepDone = exports2.markStepDone = exports2.canStartStep = exports2.startRun = exports2.activateBackendFromWorkspace = exports2.activateRunStateBackend = exports2.resolveRunStateBackend = exports2.GitRunStateStore = exports2.RUN_ID_PATTERN = exports2.FileRunStateStore = exports2.RunStateStore = exports2.harnessCapabilities = exports2.NO_HARNESS_CAPABILITIES = exports2.RunnerValidationError = exports2.validateRunnerExport = exports2.CustomRunnerLoader = exports2.buildClaudeSpawnEnv = exports2.hasClaudeLogin = exports2.isInsideClaudeCodeSession = exports2.createJsonSink = exports2.createLineSink = exports2.isCodexMcpConfigured = exports2.codexConfigPath = exports2.readProjectMcpServer = exports2.mcpRegistrarFor = exports2.codexMcpRegistrar = exports2.claudeMcpRegistrar = exports2.copilotMcpConfig = exports2.copilotGraphServer = exports2.CopilotRunner = exports2.CodexRunner = exports2.AUTOPILOT_ENV = exports2.APPROVAL_GATE_SCRIPT = exports2.emptyCiChecksMessage = void 0;
35466
- exports2.FAST_MODEL = exports2.CODING_MODEL = exports2.PLANNING_MODEL = exports2.isBuiltinPreset = exports2.BUILTIN_PRESET_IDS = exports2.writeBuiltinAutoReviewValidators = exports2.resolvePrimaryStack = exports2.getSdlcArtifactTemplates = exports2.getBuiltinArtifactTemplates = exports2.phaseArtifactFileName = exports2.sdlcClaudeCommand = exports2.builtinClaudeCommand = exports2.loadAllBuiltinPresets = exports2.loadBuiltinPreset = exports2.planRecipeMigration = exports2.getBuiltinRecipeSummaries = exports2.getAllBuiltinPipelineSummaries = exports2.getSdlcBuiltinPipelineSummary = exports2.getBuiltinPipelineSummary = exports2.getBuiltinWorkflowByPipelineId = exports2.getBuiltinWorkflow = exports2.workflowSlug = exports2.builtinTemplatesRoot = exports2.pipelineCommandId = exports2.PHASES = exports2.BUILTIN_WORKFLOWS = exports2.withBackfilledStepNames = exports2.describeDrift = exports2.reconcileRunSteps = exports2.RUN_STATE_SCHEMA_VERSION = exports2.migrateRunState = exports2.stepIdentity = exports2.resolvePath = exports2.AutoReviewerError = exports2.runAutoReview = exports2.renderRunReport = exports2.verifyRun = exports2.stepLabel = exports2.runExecLoop = exports2.estimateCostUsd = exports2.providerAliases = exports2.ratesFromConfig = exports2.mergeRates = exports2.BUILTIN_RATES = exports2.unchangedProduces = exports2.snapshotProduces = exports2.checkBudget = exports2.weighStepProgress = exports2.isActiveStatus = exports2.isStepOptional = void 0;
35467
- exports2.setClaudeConfigDir = exports2.resolveDeclaredPath = exports2.expandHome = exports2.ProfileLoadError = exports2.UnknownStandardError = exports2.builtinProfiles = exports2.loadActiveProfile = exports2.loadProfile = exports2.listProfileManifests = exports2.resolveStandard = exports2.workspaceStandard = exports2.isBuiltinProfileId = exports2.ProfileSchema = exports2.TRACE_RULES = exports2.PROFILES_DIR = exports2.DEFAULT_PROFILE_ID = exports2.BUILTIN_PROFILE_IDS = exports2.setEpicMemoryHook = exports2.isEpicMemoryHookEnabled = exports2.installAnnotationTools = exports2.relativeEpicRoot = exports2.provisionDeclaredWorkflows = exports2.provisionWorkflowFiles = exports2.writeWorkflowArtifactTemplates = exports2.writeWorkflowCommands = exports2.provisionShortcutDocs = exports2.writeTwoLayerCommands = exports2.shortcutCommandDoc = exports2.backboneCommandDoc = exports2.unprovisionedPhases = exports2.nextEligiblePhase = exports2.resolveComposition = exports2.shortcutCommandId = exports2.getCanonicalPhase = exports2.isCanonicalPhase = exports2.BACKBONE_COMMAND_ID = exports2.CANONICAL_PHASE_IDS = exports2.CANONICAL_PHASES = exports2.renderTemplate = exports2.DEFAULT_GLOBAL_WORKFLOW_IDS = exports2.detectGlobalBuiltinSource = exports2.uninstallWorkflowGlobalsByIds = exports2.isWorkflowGloballyInstalled = exports2.installWorkflowGlobalsByIds = exports2.installGlobalDefaults = exports2.stepModelOptions = exports2.pickAgentModel = exports2.resolveProviderModel = exports2.isClaudeTierAlias = exports2.CLAUDE_TIER_ALIASES = void 0;
35468
- exports2.AIDLC_CORE_VERSION = exports2.AIDLC_CLI_GUIDE_TEXT = exports2.AIDLC_KNOWLEDGE = exports2.clearResolveCommandCache = exports2.resolveCommand = exports2.remapClaudePath = exports2.claudeConfigEnv = exports2.claudeJsonPath = exports2.isDefaultClaudeConfigDir = exports2.claudeConfigDir = exports2.resolveClaudeConfigDir = exports2.defaultClaudeConfigDir = exports2.getClaudeConfigDirOverride = void 0;
35609
+ exports2.CODING_MODEL = exports2.PLANNING_MODEL = exports2.isBuiltinPreset = exports2.BUILTIN_PRESET_IDS = exports2.writeBuiltinAutoReviewValidators = exports2.resolvePrimaryStack = exports2.getSdlcArtifactTemplates = exports2.getBuiltinArtifactTemplates = exports2.phaseArtifactFileName = exports2.sdlcClaudeCommand = exports2.builtinClaudeCommand = exports2.loadAllBuiltinPresets = exports2.loadBuiltinPreset = exports2.planRecipeMigration = exports2.getBuiltinRecipeSummaries = exports2.getAllBuiltinPipelineSummaries = exports2.getSdlcBuiltinPipelineSummary = exports2.getBuiltinPipelineSummary = exports2.getBuiltinWorkflowByPipelineId = exports2.getBuiltinWorkflow = exports2.workflowSlug = exports2.builtinTemplatesRoot = exports2.pipelineCommandId = exports2.PHASES = exports2.BUILTIN_WORKFLOWS = exports2.withBackfilledStepNames = exports2.describeDrift = exports2.reconcileRunSteps = exports2.RUN_STATE_SCHEMA_VERSION = exports2.migrateRunState = exports2.stepIdentity = exports2.resolvePath = exports2.AutoReviewerError = exports2.runAutoReview = exports2.renderRunReport = exports2.verifyRun = exports2.stepLabel = exports2.runExecLoop = exports2.estimateCostUsd = exports2.providerAliases = exports2.ratesFromConfig = exports2.mergeRates = exports2.BUILTIN_RATES = exports2.unchangedProduces = exports2.snapshotProduces = exports2.checkBudget = exports2.weighStepProgress = exports2.nextRunnableStep = exports2.isActiveStatus = exports2.isStepOptional = void 0;
35610
+ exports2.resolveDeclaredPath = exports2.expandHome = exports2.ProfileLoadError = exports2.UnknownStandardError = exports2.builtinProfiles = exports2.loadActiveProfile = exports2.loadProfile = exports2.listProfileManifests = exports2.resolveStandard = exports2.workspaceStandard = exports2.isBuiltinProfileId = exports2.ProfileSchema = exports2.TRACE_RULES = exports2.PROFILES_DIR = exports2.DEFAULT_PROFILE_ID = exports2.BUILTIN_PROFILE_IDS = exports2.setEpicMemoryHook = exports2.isEpicMemoryHookEnabled = exports2.installAnnotationTools = exports2.relativeEpicRoot = exports2.provisionDeclaredWorkflows = exports2.provisionWorkflowFiles = exports2.writeWorkflowArtifactTemplates = exports2.writeWorkflowCommands = exports2.provisionShortcutDocs = exports2.writeTwoLayerCommands = exports2.shortcutCommandDoc = exports2.backboneCommandDoc = exports2.unprovisionedPhases = exports2.nextEligiblePhase = exports2.resolveComposition = exports2.shortcutCommandId = exports2.getCanonicalPhase = exports2.isCanonicalPhase = exports2.BACKBONE_COMMAND_ID = exports2.CANONICAL_PHASE_IDS = exports2.CANONICAL_PHASES = exports2.renderTemplate = exports2.DEFAULT_GLOBAL_WORKFLOW_IDS = exports2.detectGlobalBuiltinSource = exports2.uninstallWorkflowGlobalsByIds = exports2.isWorkflowGloballyInstalled = exports2.installWorkflowGlobalsByIds = exports2.installGlobalDefaults = exports2.stepModelOptions = exports2.pickAgentModel = exports2.resolveProviderModel = exports2.isClaudeTierAlias = exports2.CLAUDE_TIER_ALIASES = exports2.FAST_MODEL = void 0;
35611
+ exports2.AIDLC_CORE_VERSION = exports2.AIDLC_CLI_GUIDE_TEXT = exports2.AIDLC_KNOWLEDGE = exports2.clearResolveCommandCache = exports2.resolveCommand = exports2.remapClaudePath = exports2.claudeConfigEnv = exports2.claudeJsonPath = exports2.isDefaultClaudeConfigDir = exports2.claudeConfigDir = exports2.resolveClaudeConfigDir = exports2.defaultClaudeConfigDir = exports2.getClaudeConfigDirOverride = exports2.setClaudeConfigDir = void 0;
35469
35612
  var WorkspaceSchema_1 = require_WorkspaceSchema();
35470
35613
  Object.defineProperty(exports2, "WorkspaceSchema", { enumerable: true, get: function() {
35471
35614
  return WorkspaceSchema_1.WorkspaceSchema;
@@ -36272,6 +36415,9 @@ var require_dist = __commonJS({
36272
36415
  Object.defineProperty(exports2, "isActiveStatus", { enumerable: true, get: function() {
36273
36416
  return runProgress_1.isActiveStatus;
36274
36417
  } });
36418
+ Object.defineProperty(exports2, "nextRunnableStep", { enumerable: true, get: function() {
36419
+ return runProgress_1.nextRunnableStep;
36420
+ } });
36275
36421
  Object.defineProperty(exports2, "weighStepProgress", { enumerable: true, get: function() {
36276
36422
  return runProgress_1.weighStepProgress;
36277
36423
  } });
@@ -45293,7 +45439,7 @@ var require_package = __commonJS({
45293
45439
  "package.json"(exports2, module2) {
45294
45440
  module2.exports = {
45295
45441
  name: "@delete101020/aidlc",
45296
- version: "4.0.45",
45442
+ version: "4.0.47",
45297
45443
  description: "AIDLC Native CLI, a fork of AIDLC \u2014 drive Claude through the six-stage AI-Native SDLC Playbook: Plan \u2192 Design \u2192 Build \u2192 Test \u2192 Deploy \u2192 Maintain, with artifact gates, requirements traceability, an incident loop back to Plan, and Spec Kit support.",
45298
45444
  license: "MIT",
45299
45445
  repository: {
@@ -50328,7 +50474,7 @@ function registerRun(program3) {
50328
50474
  });
50329
50475
  cmd.command("exec <runId>").description(
50330
50476
  "Execute the current step by spawning the claude CLI, then auto-advance.\n Streams output live. Stops at human_review steps unless --auto-approve.\n Exit codes: 0 completed (or stopped at --until), 2 paused on a gate\n (awaiting review / rejected / sent back max_send_backs times / no code\n change after a send-back or a batch / max_batches / pause_between_batches /\n budget / stopped), 1 error (a step that ran\n past its timeout_minutes included). --require-complete maps any\n non-completed outcome to 1 for CI gating.\n Ctrl+C once: stop after the running step. Twice: stop it now."
50331
- ).option("--until <step>", "Stop after this step completes (index or agent id)").option("--auto-approve", "Also auto-approve human_review steps without pausing").option("--require-complete", "Exit 1 unless the run reaches completed (for CI gating)").option("--json", "Suppress decorative output; print a final JSON summary to stdout (claude stream goes to stderr)").option("--message <text>", "Override the user message sent to claude (default: context pairs)").option("--dry-run", "Print the assembled prompt without spawning claude").option("--skill <id>", "On steps that offer alternative skills (default_skill), run this one").action(async (runId, opts, actionCmd) => {
50477
+ ).option("--until <step>", "Stop after this step completes (index or agent id)").option("--auto-approve", "Also auto-approve human_review steps without pausing").option("--require-complete", "Exit 1 unless the run reaches completed (for CI gating)").option("--json", "Suppress decorative output; print a final JSON summary to stdout (claude stream goes to stderr)").option("--message <text>", "Override the user message sent to claude (default: context pairs)").option("--dry-run", "Print the assembled prompt without spawning claude").option("--skill <id>", "On steps that offer alternative skills (default_skill), run this one").option("--allow-dirty", "Autopilot: start on top of uncommitted changes (e.g. a step killed mid-run)").action(async (runId, opts, actionCmd) => {
50332
50478
  const root = resolveWorkspaceRoot(actionCmd);
50333
50479
  if (opts.json) {
50334
50480
  setQuiet(true);
@@ -50458,6 +50604,7 @@ async function execLoop(root, runId, opts) {
50458
50604
  message: opts.message,
50459
50605
  dryRun: opts.dryRun,
50460
50606
  skill: opts.skill,
50607
+ allowDirty: opts.allowDirty,
50461
50608
  shouldCancel: () => cancelRequested,
50462
50609
  signal: stopNow.signal
50463
50610
  },
@@ -50511,6 +50658,7 @@ function cliExecHooks(runId, claudeOut) {
50511
50658
  onRunCompleted: () => info(import_chalk10.default.green("\n\u{1F389} Run completed \u2014 all steps approved.")),
50512
50659
  onRunFailed: (reason) => console.error(import_chalk10.default.red(`
50513
50660
  ${reason}`)),
50661
+ onPreflightNote: (message) => info(import_chalk10.default.yellow(`\u26A0 ${message}`)),
50514
50662
  onStepStart: (e) => {
50515
50663
  info(import_chalk10.default.bold(`
50516
50664
  \u25B6 Step ${e.stepIdx}: ${e.label}`) + import_chalk10.default.dim(` (rev ${e.revision})`));
@@ -50599,6 +50747,10 @@ ${reason}`)),
50599
50747
  \u2933 Step "${e.label}" was rejected \u2014 carrying on.`) + import_chalk10.default.dim(` ${e.reason}`));
50600
50748
  info(import_chalk10.default.dim(` Want it back? aidlc run rerun ${e.runId} --step ${e.stepIdx}`));
50601
50749
  },
50750
+ onStepBypassed: (e) => {
50751
+ info(import_chalk10.default.dim(`
50752
+ \u2933 Not running "${e.label}" \u2014 the run does not need it here. Running "${e.nextLabel}" instead.`));
50753
+ },
50602
50754
  onAutoReviewStart: (e) => info(import_chalk10.default.bold(`
50603
50755
  \u{1F50D} Auto-review: "${e.label}"`)),
50604
50756
  onAutoReviewResult: (e) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@delete101020/aidlc",
3
- "version": "4.0.45",
3
+ "version": "4.0.47",
4
4
  "description": "AIDLC Native CLI, a fork of AIDLC — drive Claude through the six-stage AI-Native SDLC Playbook: Plan → Design → Build → Test → Deploy → Maintain, with artifact gates, requirements traceability, an incident loop back to Plan, and Spec Kit support.",
5
5
  "license": "MIT",
6
6
  "repository": {