@delete101020/aidlc 4.0.9 → 4.0.11

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 (2) hide show
  1. package/dist/bundle.js +1115 -39
  2. package/package.json +1 -1
package/dist/bundle.js CHANGED
@@ -19837,6 +19837,17 @@ var require_WorkspaceSchema = __commonJS({
19837
19837
  name: zod_1.z.string().optional(),
19838
19838
  /** Step is part of the pipeline but skipped at run time when false. Defaults to true. */
19839
19839
  enabled: zod_1.z.boolean().default(true),
19840
+ /**
19841
+ * A step the run may fail and carry on past. Its rejection never marks the
19842
+ * epic failed, never parks the run cursor, and never keeps the run from
19843
+ * completing; the autopilot loop steps over it to whatever else is open.
19844
+ *
19845
+ * For the side branch whose findings are welcome but not required — a
19846
+ * second reviewer's lens, an optional QC pass. Without the flag the only
19847
+ * thing making such a step skippable is that nothing happens to
19848
+ * `depends_on` it, which the runner cannot tell from an oversight.
19849
+ */
19850
+ optional: zod_1.z.boolean().default(false),
19840
19851
  /** Artifact paths the step is expected to produce. Checked after work. */
19841
19852
  produces: zod_1.z.array(zod_1.z.string().min(1)).default([]),
19842
19853
  /**
@@ -19969,6 +19980,7 @@ var require_WorkspaceSchema = __commonJS({
19969
19980
  return {
19970
19981
  agent: step,
19971
19982
  enabled: true,
19983
+ optional: false,
19972
19984
  produces: [],
19973
19985
  produces_contains: [],
19974
19986
  requires: [],
@@ -19994,6 +20006,7 @@ var require_WorkspaceSchema = __commonJS({
19994
20006
  name: typeof obj.name === "string" ? obj.name : void 0,
19995
20007
  skills,
19996
20008
  enabled: typeof obj.enabled === "boolean" ? obj.enabled : true,
20009
+ optional: obj.optional === true,
19997
20010
  produces,
19998
20011
  produces_contains,
19999
20012
  requires,
@@ -20055,6 +20068,24 @@ var require_WorkspaceSchema = __commonJS({
20055
20068
  }
20056
20069
  }
20057
20070
  }
20071
+ const pipelineIds = new Set(config.pipelines.map((p) => p.id));
20072
+ for (const cmd of config.slash_commands ?? []) {
20073
+ const target = cmd;
20074
+ if (typeof target.agent === "string" && !agentIds.has(target.agent)) {
20075
+ issues.push({
20076
+ code: "unknown-command-agent",
20077
+ message: `Slash command "${target.name}" targets agent "${target.agent}" which is not defined in agents:`,
20078
+ path: `slash_commands.${target.name}.agent`
20079
+ });
20080
+ }
20081
+ if (typeof target.pipeline === "string" && !pipelineIds.has(target.pipeline)) {
20082
+ issues.push({
20083
+ code: "unknown-command-pipeline",
20084
+ message: `Slash command "${target.name}" targets pipeline "${target.pipeline}" which is not defined in pipelines:`,
20085
+ path: `slash_commands.${target.name}.pipeline`
20086
+ });
20087
+ }
20088
+ }
20058
20089
  const pipelinesById = new Map(config.pipelines.map((p) => [p.id, p]));
20059
20090
  for (const recipe of config.recipes) {
20060
20091
  const source = recipe.from ? pipelinesById.get(recipe.from) : config.pipelines[0];
@@ -20752,6 +20783,83 @@ var require_RunState = __commonJS({
20752
20783
  }
20753
20784
  });
20754
20785
 
20786
+ // ../core/dist/runs/runProgress.js
20787
+ var require_runProgress = __commonJS({
20788
+ "../core/dist/runs/runProgress.js"(exports2) {
20789
+ "use strict";
20790
+ Object.defineProperty(exports2, "__esModule", { value: true });
20791
+ exports2.isActiveStatus = isActiveStatus;
20792
+ exports2.isStepOptional = isStepOptional;
20793
+ exports2.deriveRunProgress = deriveRunProgress;
20794
+ exports2.isRunComplete = isRunComplete;
20795
+ var WorkspaceSchema_1 = require_WorkspaceSchema();
20796
+ var ACTIVE = /* @__PURE__ */ new Set([
20797
+ "awaiting_work",
20798
+ "awaiting_auto_review",
20799
+ "awaiting_review"
20800
+ ]);
20801
+ function isActiveStatus(status) {
20802
+ return ACTIVE.has(status);
20803
+ }
20804
+ function isStepOptional(pipeline, idx) {
20805
+ const cfg = pipeline?.steps?.[idx];
20806
+ return cfg === void 0 ? false : (0, WorkspaceSchema_1.normalizeStep)(cfg).optional;
20807
+ }
20808
+ function usesDag(pipeline) {
20809
+ return pipeline.steps.some((s) => (0, WorkspaceSchema_1.normalizeStep)(s).depends_on.length > 0);
20810
+ }
20811
+ function deriveRunProgress(state, pipeline) {
20812
+ const dag = pipeline ? usesDag(pipeline) : false;
20813
+ const approvedDagIds = /* @__PURE__ */ new Set();
20814
+ if (pipeline && dag) {
20815
+ state.steps.forEach((s, i) => {
20816
+ if (s.status !== "approved") {
20817
+ return;
20818
+ }
20819
+ const norm = (0, WorkspaceSchema_1.normalizeStep)(pipeline.steps[i] ?? { agent: s.agent });
20820
+ approvedDagIds.add(norm.name ?? norm.agent);
20821
+ });
20822
+ }
20823
+ const actionable = [];
20824
+ const rejected = [];
20825
+ const blocking = [];
20826
+ state.steps.forEach((s, i) => {
20827
+ if (isActiveStatus(s.status)) {
20828
+ actionable.push(i);
20829
+ return;
20830
+ }
20831
+ if (s.status === "rejected") {
20832
+ rejected.push(i);
20833
+ if (!isStepOptional(pipeline, i)) {
20834
+ blocking.push(i);
20835
+ }
20836
+ return;
20837
+ }
20838
+ if (s.status === "pending" && pipeline && dag) {
20839
+ const deps = (0, WorkspaceSchema_1.normalizeStep)(pipeline.steps[i] ?? { agent: s.agent }).depends_on;
20840
+ if (deps.length > 0 && deps.every((d) => approvedDagIds.has(d))) {
20841
+ actionable.push(i);
20842
+ }
20843
+ }
20844
+ });
20845
+ const stuck = blocking.length > 0 && actionable.length === 0;
20846
+ const status = state.status === "completed" ? "done" : stuck ? "failed" : "in_progress";
20847
+ return { actionable, rejected, blocking, stuck, status };
20848
+ }
20849
+ function isRunComplete(state, pipeline) {
20850
+ return state.steps.every((s, i) => {
20851
+ if (s.status === "approved") {
20852
+ return true;
20853
+ }
20854
+ if (!isStepOptional(pipeline, i)) {
20855
+ return false;
20856
+ }
20857
+ return s.status === "rejected" || s.status === "pending";
20858
+ });
20859
+ }
20860
+ }
20861
+ });
20862
+
20755
20863
  // ../core/dist/runs/reconcileRun.js
20756
20864
  var require_reconcileRun = __commonJS({
20757
20865
  "../core/dist/runs/reconcileRun.js"(exports2) {
@@ -20920,6 +21028,7 @@ var require_PipelineRunner = __commonJS({
20920
21028
  var path17 = __importStar(require("path"));
20921
21029
  var WorkspaceSchema_1 = require_WorkspaceSchema();
20922
21030
  var RunState_1 = require_RunState();
21031
+ var runProgress_1 = require_runProgress();
20923
21032
  var reconcileRun_1 = require_reconcileRun();
20924
21033
  var PipelineRunError3 = class extends Error {
20925
21034
  missing;
@@ -21099,6 +21208,7 @@ var require_PipelineRunner = __commonJS({
21099
21208
  sentBackToIdx: idx
21100
21209
  });
21101
21210
  next.status = "running";
21211
+ settleOptionalRejection(next, idx, pipeline);
21102
21212
  return next;
21103
21213
  }
21104
21214
  if (norm.human_review) {
@@ -21239,6 +21349,9 @@ var require_PipelineRunner = __commonJS({
21239
21349
  })
21240
21350
  };
21241
21351
  next.status = "running";
21352
+ if (pipeline) {
21353
+ settleOptionalRejection(next, idx, pipeline);
21354
+ }
21242
21355
  return next;
21243
21356
  }
21244
21357
  function rerunStep3(args) {
@@ -21357,7 +21470,7 @@ var require_PipelineRunner = __commonJS({
21357
21470
  }
21358
21471
  const dagId = (i) => normalized[i].name ?? normalized[i].agent;
21359
21472
  const approvedDagIds = new Set(next.steps.filter((s) => s.status === "approved").map((s) => dagId(s.stepIdx)));
21360
- let openedAny = false;
21473
+ const opened = [];
21361
21474
  for (let i = 0; i < normalized.length; i++) {
21362
21475
  const sStep = next.steps[i];
21363
21476
  if (sStep.status !== "pending") {
@@ -21376,25 +21489,47 @@ var require_PipelineRunner = __commonJS({
21376
21489
  status: "awaiting_work",
21377
21490
  startedAt: finishedAt
21378
21491
  };
21379
- openedAny = true;
21380
- if (next.currentStepIdx === idx) {
21381
- next.currentStepIdx = i;
21382
- }
21492
+ opened.push(i);
21383
21493
  }
21384
- const allApproved = next.steps.every((s) => s.status === "approved");
21385
- if (allApproved) {
21494
+ if ((0, runProgress_1.isRunComplete)(next, pipeline)) {
21386
21495
  next.status = "completed";
21387
21496
  return next;
21388
21497
  }
21389
- if (!openedAny) {
21390
- const stillActive = next.steps.findIndex((s) => s.status === "awaiting_work" || s.status === "awaiting_auto_review" || s.status === "awaiting_review");
21391
- if (stillActive >= 0) {
21392
- next.currentStepIdx = stillActive;
21393
- }
21394
- }
21498
+ refocusCursor(next, opened);
21395
21499
  next.status = "running";
21396
21500
  return next;
21397
21501
  }
21502
+ function refocusCursor(next, opened) {
21503
+ const cur = next.steps[next.currentStepIdx];
21504
+ if (cur && cur.status !== "approved" && cur.status !== "rejected") {
21505
+ return;
21506
+ }
21507
+ const target = opened.length > 0 ? Math.min(...opened) : next.steps.findIndex((s) => (0, runProgress_1.isActiveStatus)(s.status));
21508
+ if (target >= 0) {
21509
+ next.currentStepIdx = target;
21510
+ }
21511
+ }
21512
+ function settleOptionalRejection(next, idx, pipeline) {
21513
+ if (!(0, runProgress_1.isStepOptional)(pipeline, idx)) {
21514
+ return;
21515
+ }
21516
+ const normalized = pipeline.steps.map(WorkspaceSchema_1.normalizeStep);
21517
+ const usesDag = normalized.some((s) => s.depends_on.length > 0);
21518
+ if (!usesDag) {
21519
+ const follower = next.steps[idx + 1];
21520
+ if (follower && follower.status === "pending") {
21521
+ next.steps[idx + 1] = {
21522
+ ...follower,
21523
+ status: "awaiting_work",
21524
+ startedAt: (/* @__PURE__ */ new Date()).toISOString()
21525
+ };
21526
+ }
21527
+ }
21528
+ refocusCursor(next, []);
21529
+ if ((0, runProgress_1.isRunComplete)(next, pipeline)) {
21530
+ next.status = "completed";
21531
+ }
21532
+ }
21398
21533
  function clone(value) {
21399
21534
  return JSON.parse(JSON.stringify(value));
21400
21535
  }
@@ -25081,10 +25216,12 @@ var require_EpicScaffold = __commonJS({
25081
25216
  exports2.epicsRoot = epicsRoot3;
25082
25217
  exports2.mapStepStatusToEpic = mapStepStatusToEpic;
25083
25218
  exports2.mirrorRunStateToEpic = mirrorRunStateToEpic2;
25219
+ exports2.lockedEpicDirError = lockedEpicDirError;
25084
25220
  exports2.scaffoldEpic = scaffoldEpic2;
25085
25221
  var fs14 = __importStar(require("fs"));
25086
25222
  var path17 = __importStar(require("path"));
25087
25223
  var PipelineRunner_1 = require_PipelineRunner();
25224
+ var runProgress_1 = require_runProgress();
25088
25225
  var RunStateStore_1 = require_RunStateStore();
25089
25226
  var EpicPipelineStore_1 = require_EpicPipelineStore();
25090
25227
  var epicTags_1 = require_epicTags();
@@ -25132,7 +25269,9 @@ var require_EpicScaffold = __commonJS({
25132
25269
  } catch {
25133
25270
  return;
25134
25271
  }
25135
- const epicStatus = runState.status === "completed" ? "done" : runState.steps.some((s) => s.status === "rejected") ? "failed" : "in_progress";
25272
+ const pipelines = Array.isArray(doc?.pipelines) ? doc.pipelines : [];
25273
+ const pipeline = pipelines.find((p) => p.id === runState.pipelineId);
25274
+ const epicStatus = (0, runProgress_1.deriveRunProgress)(runState, pipeline).status;
25136
25275
  const stepStates = runState.steps.map((s) => ({
25137
25276
  agent: s.agent,
25138
25277
  // The step's identity, mirrored alongside its agent so state.json says
@@ -25161,6 +25300,15 @@ var require_EpicScaffold = __commonJS({
25161
25300
  };
25162
25301
  fs14.writeFileSync(stateFile, JSON.stringify(next, null, 2) + "\n", "utf8");
25163
25302
  }
25303
+ function lockedEpicDirError(workspaceRoot, epicDir, err, action) {
25304
+ const rel = path17.relative(workspaceRoot, epicDir) || epicDir;
25305
+ const code = err?.code;
25306
+ const detail = err instanceof Error ? err.message : String(err);
25307
+ if (code === "EPERM" || code === "EACCES" || code === "EBUSY") {
25308
+ return new EpicScaffoldError3(`Epic dir ${rel} exists but cannot be ${action === "read" ? "read" : "created"} (${code}). It was most likely deleted while another process still held it open \u2014 on Windows the name survives until the last handle closes. Close whatever points at it (editor window, a terminal sitting in that folder, file explorer) or reboot, then start the epic again. Deleting it again will not help. Underlying error: ${detail}`);
25309
+ }
25310
+ return new EpicScaffoldError3(`Cannot ${action} epic dir ${rel}: ${detail}`);
25311
+ }
25164
25312
  function scaffoldEpic2(args) {
25165
25313
  const { workspaceRoot, doc, epicId, title, description, target, agents, inputs, extraProjects, pipeline, seedArtifacts, enableAutopilot = false, strictMode = true, tags } = args;
25166
25314
  if (!epicId.trim()) {
@@ -25171,12 +25319,21 @@ var require_EpicScaffold = __commonJS({
25171
25319
  }
25172
25320
  const epicDir = path17.join(epicsRoot3(workspaceRoot, doc), epicId);
25173
25321
  if (fs14.existsSync(epicDir)) {
25174
- const entries = fs14.readdirSync(epicDir);
25322
+ let entries;
25323
+ try {
25324
+ entries = fs14.readdirSync(epicDir);
25325
+ } catch (err) {
25326
+ throw lockedEpicDirError(workspaceRoot, epicDir, err, "read");
25327
+ }
25175
25328
  if (entries.length !== 1 || entries[0] !== EpicPipelineStore_1.EPIC_PIPELINE_FILENAME) {
25176
25329
  throw new EpicScaffoldError3(`Epic dir already exists at ${path17.relative(workspaceRoot, epicDir) || epicDir}. Delete it first.`);
25177
25330
  }
25178
25331
  }
25179
- fs14.mkdirSync(epicDir, { recursive: true });
25332
+ try {
25333
+ fs14.mkdirSync(epicDir, { recursive: true });
25334
+ } catch (err) {
25335
+ throw lockedEpicDirError(workspaceRoot, epicDir, err, "create");
25336
+ }
25180
25337
  const artifactsDir = path17.join(epicDir, "artifacts");
25181
25338
  fs14.mkdirSync(artifactsDir, { recursive: true });
25182
25339
  for (const [fileName, content] of Object.entries(seedArtifacts ?? {})) {
@@ -25427,6 +25584,400 @@ var require_EpicArtifactCommit = __commonJS({
25427
25584
  }
25428
25585
  });
25429
25586
 
25587
+ // ../core/dist/runs/EpicDescription.js
25588
+ var require_EpicDescription = __commonJS({
25589
+ "../core/dist/runs/EpicDescription.js"(exports2) {
25590
+ "use strict";
25591
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
25592
+ if (k2 === void 0) k2 = k;
25593
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25594
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
25595
+ desc = { enumerable: true, get: function() {
25596
+ return m[k];
25597
+ } };
25598
+ }
25599
+ Object.defineProperty(o, k2, desc);
25600
+ } : function(o, m, k, k2) {
25601
+ if (k2 === void 0) k2 = k;
25602
+ o[k2] = m[k];
25603
+ });
25604
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
25605
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25606
+ } : function(o, v) {
25607
+ o["default"] = v;
25608
+ });
25609
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
25610
+ var ownKeys = function(o) {
25611
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
25612
+ var ar = [];
25613
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
25614
+ return ar;
25615
+ };
25616
+ return ownKeys(o);
25617
+ };
25618
+ return function(mod) {
25619
+ if (mod && mod.__esModule) return mod;
25620
+ var result = {};
25621
+ if (mod != null) {
25622
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
25623
+ }
25624
+ __setModuleDefault(result, mod);
25625
+ return result;
25626
+ };
25627
+ }();
25628
+ Object.defineProperty(exports2, "__esModule", { value: true });
25629
+ exports2.EpicDescriptionError = void 0;
25630
+ exports2.setEpicDescription = setEpicDescription2;
25631
+ var fs14 = __importStar(require("fs"));
25632
+ var path17 = __importStar(require("path"));
25633
+ var EpicDescriptionError2 = class extends Error {
25634
+ constructor(message) {
25635
+ super(message);
25636
+ this.name = "EpicDescriptionError";
25637
+ }
25638
+ };
25639
+ exports2.EpicDescriptionError = EpicDescriptionError2;
25640
+ function readState(stateFile, epicId) {
25641
+ let raw;
25642
+ try {
25643
+ raw = fs14.readFileSync(stateFile, "utf8");
25644
+ } catch (err) {
25645
+ throw new EpicDescriptionError2(`Cannot read ${path17.basename(stateFile)} for ${epicId}: ${err.message}`);
25646
+ }
25647
+ let parsed;
25648
+ try {
25649
+ parsed = JSON.parse(raw);
25650
+ } catch (err) {
25651
+ throw new EpicDescriptionError2(`${stateFile} is not valid JSON \u2014 fix it by hand before editing the description. ${err.message}`);
25652
+ }
25653
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
25654
+ throw new EpicDescriptionError2(`${stateFile} does not hold an epic state object.`);
25655
+ }
25656
+ return parsed;
25657
+ }
25658
+ function splitDoc(text) {
25659
+ const lines = text.split(/\r?\n/);
25660
+ const h1 = lines.findIndex((l) => /^#\s/.test(l));
25661
+ if (h1 === -1) {
25662
+ return null;
25663
+ }
25664
+ let end = lines.length;
25665
+ for (let i = h1 + 1; i < lines.length; i++) {
25666
+ if (/^#{1,6}\s/.test(lines[i])) {
25667
+ end = i;
25668
+ break;
25669
+ }
25670
+ }
25671
+ return {
25672
+ head: lines.slice(0, h1 + 1).join("\n"),
25673
+ lead: lines.slice(h1 + 1, end).join("\n"),
25674
+ rest: lines.slice(end).join("\n")
25675
+ };
25676
+ }
25677
+ function setEpicDescription2(epicDir, epicId, description) {
25678
+ const next = description.trim();
25679
+ const stateFile = path17.join(epicDir, "state.json");
25680
+ const docFile = path17.join(epicDir, `${epicId}.md`);
25681
+ const state = readState(stateFile, epicId);
25682
+ const previous = typeof state.description === "string" ? state.description : "";
25683
+ state.description = next;
25684
+ try {
25685
+ fs14.writeFileSync(stateFile, JSON.stringify(state, null, 2) + "\n", "utf8");
25686
+ } catch (err) {
25687
+ throw new EpicDescriptionError2(`Cannot write ${stateFile}: ${err.message}`);
25688
+ }
25689
+ const title = typeof state.title === "string" ? state.title.trim() : "";
25690
+ const doc = writeDoc(docFile, epicId, title, previous, next);
25691
+ return { epicId, description: next, previous, doc, docFile };
25692
+ }
25693
+ function writeDoc(docFile, epicId, title, previous, next) {
25694
+ let text = null;
25695
+ try {
25696
+ text = fs14.readFileSync(docFile, "utf8");
25697
+ } catch {
25698
+ text = null;
25699
+ }
25700
+ if (text === null) {
25701
+ const body = `# ${epicId}${title ? ` \u2014 ${title}` : ""}
25702
+ ` + (next ? `
25703
+ ${next}
25704
+ ` : "");
25705
+ try {
25706
+ fs14.mkdirSync(path17.dirname(docFile), { recursive: true });
25707
+ fs14.writeFileSync(docFile, body, "utf8");
25708
+ } catch (err) {
25709
+ throw new EpicDescriptionError2(`Cannot write ${docFile}: ${err.message}`);
25710
+ }
25711
+ return "created";
25712
+ }
25713
+ const parts = splitDoc(text);
25714
+ if (!parts) {
25715
+ return "kept";
25716
+ }
25717
+ const leadText = parts.lead.trim();
25718
+ if (leadText !== previous.trim()) {
25719
+ return "kept";
25720
+ }
25721
+ if (leadText === next) {
25722
+ return "unchanged";
25723
+ }
25724
+ const rebuilt = parts.head + "\n" + (next ? `
25725
+ ${next}
25726
+ ` : "") + (parts.rest ? `
25727
+ ${parts.rest}` : "");
25728
+ try {
25729
+ fs14.writeFileSync(docFile, rebuilt, "utf8");
25730
+ } catch (err) {
25731
+ throw new EpicDescriptionError2(`Cannot write ${docFile}: ${err.message}`);
25732
+ }
25733
+ return "updated";
25734
+ }
25735
+ }
25736
+ });
25737
+
25738
+ // ../core/dist/runs/EpicWorkflowSwitch.js
25739
+ var require_EpicWorkflowSwitch = __commonJS({
25740
+ "../core/dist/runs/EpicWorkflowSwitch.js"(exports2) {
25741
+ "use strict";
25742
+ var __createBinding = exports2 && exports2.__createBinding || (Object.create ? function(o, m, k, k2) {
25743
+ if (k2 === void 0) k2 = k;
25744
+ var desc = Object.getOwnPropertyDescriptor(m, k);
25745
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
25746
+ desc = { enumerable: true, get: function() {
25747
+ return m[k];
25748
+ } };
25749
+ }
25750
+ Object.defineProperty(o, k2, desc);
25751
+ } : function(o, m, k, k2) {
25752
+ if (k2 === void 0) k2 = k;
25753
+ o[k2] = m[k];
25754
+ });
25755
+ var __setModuleDefault = exports2 && exports2.__setModuleDefault || (Object.create ? function(o, v) {
25756
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25757
+ } : function(o, v) {
25758
+ o["default"] = v;
25759
+ });
25760
+ var __importStar = exports2 && exports2.__importStar || /* @__PURE__ */ function() {
25761
+ var ownKeys = function(o) {
25762
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
25763
+ var ar = [];
25764
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
25765
+ return ar;
25766
+ };
25767
+ return ownKeys(o);
25768
+ };
25769
+ return function(mod) {
25770
+ if (mod && mod.__esModule) return mod;
25771
+ var result = {};
25772
+ if (mod != null) {
25773
+ for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
25774
+ }
25775
+ __setModuleDefault(result, mod);
25776
+ return result;
25777
+ };
25778
+ }();
25779
+ Object.defineProperty(exports2, "__esModule", { value: true });
25780
+ exports2.EpicWorkflowSwitchError = void 0;
25781
+ exports2.epicWorkflowLock = epicWorkflowLock2;
25782
+ exports2.canSwitchEpicWorkflow = canSwitchEpicWorkflow;
25783
+ exports2.planEpicWorkflowSwitch = planEpicWorkflowSwitch2;
25784
+ exports2.stageEpicWorkflowSwitch = stageEpicWorkflowSwitch2;
25785
+ exports2.applyEpicWorkflowSwitch = applyEpicWorkflowSwitch2;
25786
+ var fs14 = __importStar(require("fs"));
25787
+ var path17 = __importStar(require("path"));
25788
+ var WorkspaceSchema_1 = require_WorkspaceSchema();
25789
+ var PipelineRunner_1 = require_PipelineRunner();
25790
+ var RunStateStore_1 = require_RunStateStore();
25791
+ var PipelineAssembler_1 = require_PipelineAssembler();
25792
+ var EpicScaffold_1 = require_EpicScaffold();
25793
+ var EpicPipelineStore_1 = require_EpicPipelineStore();
25794
+ var EpicWorkflowSwitchError2 = class extends Error {
25795
+ constructor(message) {
25796
+ super(message);
25797
+ this.name = "EpicWorkflowSwitchError";
25798
+ }
25799
+ };
25800
+ exports2.EpicWorkflowSwitchError = EpicWorkflowSwitchError2;
25801
+ function epicWorkflowLock2(run) {
25802
+ if (!run) {
25803
+ return null;
25804
+ }
25805
+ if (run.status !== "running") {
25806
+ return `the run is already ${run.status}`;
25807
+ }
25808
+ for (const step of run.steps) {
25809
+ const id = step.name ?? step.agent;
25810
+ if (step.status !== "pending" && step.status !== "awaiting_work") {
25811
+ return `step "${id}" is ${step.status}`;
25812
+ }
25813
+ if (step.revision > 1) {
25814
+ return `step "${id}" has already been rerun`;
25815
+ }
25816
+ if ((step.history?.length ?? 0) > 0) {
25817
+ return `step "${id}" already has history`;
25818
+ }
25819
+ if (step.artifactsProduced.length > 0) {
25820
+ return `step "${id}" has produced artifacts`;
25821
+ }
25822
+ }
25823
+ return null;
25824
+ }
25825
+ function canSwitchEpicWorkflow(workspaceRoot, epicId) {
25826
+ return epicWorkflowLock2(RunStateStore_1.RunStateStore.load(workspaceRoot, epicId)) === null;
25827
+ }
25828
+ function readEpicState(epicDir, epicId) {
25829
+ const file = path17.join(epicDir, "state.json");
25830
+ let raw;
25831
+ try {
25832
+ raw = fs14.readFileSync(file, "utf8");
25833
+ } catch {
25834
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" has no state.json at ${file}.`);
25835
+ }
25836
+ let parsed;
25837
+ try {
25838
+ parsed = JSON.parse(raw);
25839
+ } catch (err) {
25840
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" has a state.json that is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
25841
+ }
25842
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
25843
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" has a state.json that is not an object.`);
25844
+ }
25845
+ return parsed;
25846
+ }
25847
+ function stepAgents(pipeline) {
25848
+ return pipeline.steps.map((s) => (0, WorkspaceSchema_1.normalizeStep)(s).agent);
25849
+ }
25850
+ function planEpicWorkflowSwitch2(args) {
25851
+ const { workspaceRoot, doc, config, epicId, target } = args;
25852
+ const epicDir = path17.join((0, EpicScaffold_1.epicsRoot)(workspaceRoot, doc), epicId);
25853
+ const state = readEpicState(epicDir, epicId);
25854
+ const lock = epicWorkflowLock2(RunStateStore_1.RunStateStore.load(workspaceRoot, epicId));
25855
+ if (lock) {
25856
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" has already started, so its workflow can't be changed: ${lock}. Add or remove individual steps instead (\`aidlc epic step add\` / \`remove\`), or start a new epic.`);
25857
+ }
25858
+ const currentPipelineId = typeof state.pipeline === "string" && state.pipeline ? state.pipeline : null;
25859
+ const currentAgentId = typeof state.agent === "string" && state.agent ? state.agent : null;
25860
+ const from = currentPipelineId ? { kind: "pipeline", id: currentPipelineId } : currentAgentId ? { kind: "agent", id: currentAgentId } : { kind: "none", id: null };
25861
+ const ownFile = (0, EpicPipelineStore_1.epicPipelinePath)(workspaceRoot, doc, epicId);
25862
+ const previousOwnedPipelineId = fs14.existsSync(ownFile) && currentPipelineId ? currentPipelineId : null;
25863
+ let pipeline;
25864
+ let owned;
25865
+ if (target.kind === "pipeline") {
25866
+ const found = config.pipelines.find((p) => p.id === target.id);
25867
+ if (!found) {
25868
+ const available = config.pipelines.map((p) => p.id).join(", ") || "(none defined)";
25869
+ throw new EpicWorkflowSwitchError2(`Pipeline "${target.id}" is not defined. Available: ${available}`);
25870
+ }
25871
+ const otherOwner = (0, EpicPipelineStore_1.epicOwningPipeline)(doc, target.id);
25872
+ if (otherOwner && otherOwner !== epicId) {
25873
+ throw new EpicWorkflowSwitchError2(`Pipeline "${target.id}" belongs to epic "${otherOwner}" \u2014 it lives in that epic's folder and editing it there would reshape that epic too. Pick a recipe instead, and this epic gets its own copy.`);
25874
+ }
25875
+ if (target.id === currentPipelineId) {
25876
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" already runs pipeline "${target.id}".`);
25877
+ }
25878
+ if (found.steps.length === 0) {
25879
+ throw new EpicWorkflowSwitchError2(`Pipeline "${target.id}" has no steps to run.`);
25880
+ }
25881
+ pipeline = found;
25882
+ owned = otherOwner === epicId;
25883
+ } else {
25884
+ const taken = new Set(config.pipelines.map((p) => p.id).filter((id) => id !== previousOwnedPipelineId));
25885
+ const pipelineId = (0, PipelineAssembler_1.recipePipelineId)({ recipeId: target.id, epicId, taken });
25886
+ pipeline = (0, PipelineAssembler_1.assemblePipeline)(config, { recipeId: target.id, pipelineId });
25887
+ owned = true;
25888
+ }
25889
+ return {
25890
+ epicId,
25891
+ from,
25892
+ to: target,
25893
+ pipeline,
25894
+ owned,
25895
+ previousOwnedPipelineId,
25896
+ agents: stepAgents(pipeline)
25897
+ };
25898
+ }
25899
+ function stageEpicWorkflowSwitch2(doc, plan) {
25900
+ const { previousOwnedPipelineId, pipeline, owned, epicId } = plan;
25901
+ const next = pipeline;
25902
+ const at = previousOwnedPipelineId ? doc.pipelines.findIndex((p) => p.id === previousOwnedPipelineId) : -1;
25903
+ if (previousOwnedPipelineId) {
25904
+ (0, EpicPipelineStore_1.unstageEpicPipeline)(doc, previousOwnedPipelineId);
25905
+ }
25906
+ if (owned) {
25907
+ const existing = doc.pipelines.findIndex((p) => p.id === pipeline.id);
25908
+ if (existing >= 0) {
25909
+ doc.pipelines.splice(existing, 1, next);
25910
+ } else if (at >= 0) {
25911
+ doc.pipelines.splice(at, 1, next);
25912
+ } else {
25913
+ doc.pipelines.push(next);
25914
+ }
25915
+ if (previousOwnedPipelineId && previousOwnedPipelineId !== pipeline.id) {
25916
+ doc.pipelines = doc.pipelines.filter((p) => p.id !== previousOwnedPipelineId);
25917
+ }
25918
+ (0, EpicPipelineStore_1.stageEpicPipeline)(doc, pipeline.id, epicId);
25919
+ } else if (at >= 0) {
25920
+ doc.pipelines.splice(at, 1);
25921
+ }
25922
+ }
25923
+ function applyEpicWorkflowSwitch2(workspaceRoot, doc, plan) {
25924
+ const { epicId } = plan;
25925
+ const epicDir = path17.join((0, EpicScaffold_1.epicsRoot)(workspaceRoot, doc), epicId);
25926
+ const stateFile = path17.join(epicDir, "state.json");
25927
+ const state = readEpicState(epicDir, epicId);
25928
+ const previous = RunStateStore_1.RunStateStore.load(workspaceRoot, epicId);
25929
+ const lock = epicWorkflowLock2(previous);
25930
+ if (lock) {
25931
+ throw new EpicWorkflowSwitchError2(`Epic "${epicId}" has already started, so its workflow can't be changed: ${lock}.`);
25932
+ }
25933
+ let removedPipelineFile = null;
25934
+ if (!plan.owned && plan.previousOwnedPipelineId) {
25935
+ const file = (0, EpicPipelineStore_1.epicPipelinePath)(workspaceRoot, doc, epicId);
25936
+ if (fs14.existsSync(file)) {
25937
+ fs14.rmSync(file);
25938
+ removedPipelineFile = file;
25939
+ }
25940
+ }
25941
+ state.pipeline = plan.pipeline.id;
25942
+ state.agent = null;
25943
+ fs14.writeFileSync(stateFile, JSON.stringify(state, null, 2) + "\n", "utf8");
25944
+ const context = previous?.context ?? readInputs2(epicDir);
25945
+ const runState = (0, PipelineRunner_1.startRun)({
25946
+ runId: epicId,
25947
+ pipeline: plan.pipeline,
25948
+ context: { ...context, epic: epicId }
25949
+ });
25950
+ RunStateStore_1.RunStateStore.save(workspaceRoot, runState);
25951
+ (0, EpicScaffold_1.mirrorRunStateToEpic)(workspaceRoot, runState, doc);
25952
+ return {
25953
+ epicId,
25954
+ pipelineId: plan.pipeline.id,
25955
+ agents: plan.agents,
25956
+ previousPipelineId: plan.from.kind === "pipeline" ? plan.from.id : null,
25957
+ removedPipelineFile,
25958
+ runState
25959
+ };
25960
+ }
25961
+ function readInputs2(epicDir) {
25962
+ try {
25963
+ const parsed = JSON.parse(fs14.readFileSync(path17.join(epicDir, "inputs.json"), "utf8"));
25964
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
25965
+ return {};
25966
+ }
25967
+ const out2 = {};
25968
+ for (const [k, v] of Object.entries(parsed)) {
25969
+ if (typeof v === "string") {
25970
+ out2[k] = v;
25971
+ }
25972
+ }
25973
+ return out2;
25974
+ } catch {
25975
+ return {};
25976
+ }
25977
+ }
25978
+ }
25979
+ });
25980
+
25430
25981
  // ../core/dist/runs/EpicStepEdit.js
25431
25982
  var require_EpicStepEdit = __commonJS({
25432
25983
  "../core/dist/runs/EpicStepEdit.js"(exports2) {
@@ -28412,6 +28963,304 @@ var require_WorkspaceLoader = __commonJS({
28412
28963
  }
28413
28964
  });
28414
28965
 
28966
+ // ../core/dist/loader/recipeRefs.js
28967
+ var require_recipeRefs = __commonJS({
28968
+ "../core/dist/loader/recipeRefs.js"(exports2) {
28969
+ "use strict";
28970
+ Object.defineProperty(exports2, "__esModule", { value: true });
28971
+ exports2.recipesDrawingFrom = recipesDrawingFrom;
28972
+ exports2.dropRecipeStep = dropRecipeStep;
28973
+ exports2.dropRecipesForPipeline = dropRecipesForPipeline;
28974
+ function recipeList(doc) {
28975
+ return Array.isArray(doc.recipes) ? doc.recipes : [];
28976
+ }
28977
+ function stepIds(recipe) {
28978
+ return Array.isArray(recipe.steps) ? recipe.steps.map(String) : [];
28979
+ }
28980
+ function recipesDrawingFrom(doc, pipelineId) {
28981
+ const firstPipelineId = doc.pipelines.length > 0 ? String(doc.pipelines[0].id ?? "") : "";
28982
+ return recipeList(doc).filter((r) => {
28983
+ const from = typeof r.from === "string" && r.from ? r.from : "";
28984
+ return from ? from === pipelineId : firstPipelineId === pipelineId;
28985
+ });
28986
+ }
28987
+ function emptyEdit(recipe) {
28988
+ return { recipeId: String(recipe.id ?? ""), steps: [], gates: [], removed: false };
28989
+ }
28990
+ function dropGate(recipe, stepId) {
28991
+ const gates = recipe.gates;
28992
+ if (!gates || typeof gates !== "object" || Array.isArray(gates)) {
28993
+ return false;
28994
+ }
28995
+ const map2 = gates;
28996
+ if (!(stepId in map2)) {
28997
+ return false;
28998
+ }
28999
+ delete map2[stepId];
29000
+ if (Object.keys(map2).length === 0) {
29001
+ delete recipe.gates;
29002
+ }
29003
+ return true;
29004
+ }
29005
+ function dropRecipeStep(doc, pipelineId, stepId) {
29006
+ const edits = [];
29007
+ const emptied = [];
29008
+ for (const recipe of recipesDrawingFrom(doc, pipelineId)) {
29009
+ const edit = emptyEdit(recipe);
29010
+ const steps = stepIds(recipe);
29011
+ if (steps.includes(stepId)) {
29012
+ const kept = steps.filter((s) => s !== stepId);
29013
+ edit.steps.push(stepId);
29014
+ if (kept.length === 0) {
29015
+ edit.removed = true;
29016
+ emptied.push(recipe);
29017
+ } else {
29018
+ recipe.steps = kept;
29019
+ }
29020
+ }
29021
+ if (dropGate(recipe, stepId)) {
29022
+ edit.gates.push(stepId);
29023
+ }
29024
+ if (edit.steps.length > 0 || edit.gates.length > 0) {
29025
+ edits.push(edit);
29026
+ }
29027
+ }
29028
+ if (emptied.length > 0) {
29029
+ doc.recipes = recipeList(doc).filter((r) => !emptied.includes(r));
29030
+ }
29031
+ return edits;
29032
+ }
29033
+ function dropRecipesForPipeline(doc, pipelineId) {
29034
+ const doomed = recipeList(doc).filter((r) => r.from === pipelineId);
29035
+ if (doomed.length === 0) {
29036
+ return [];
29037
+ }
29038
+ doc.recipes = recipeList(doc).filter((r) => !doomed.includes(r));
29039
+ return doomed.map((r) => String(r.id ?? ""));
29040
+ }
29041
+ }
29042
+ });
29043
+
29044
+ // ../core/dist/loader/renameRefs.js
29045
+ var require_renameRefs = __commonJS({
29046
+ "../core/dist/loader/renameRefs.js"(exports2) {
29047
+ "use strict";
29048
+ Object.defineProperty(exports2, "__esModule", { value: true });
29049
+ exports2.renameAgentRefs = renameAgentRefs;
29050
+ exports2.renameSkillRefs = renameSkillRefs;
29051
+ exports2.agentReferences = agentReferences;
29052
+ exports2.skillReferences = skillReferences;
29053
+ exports2.unusedAfterStepRemoval = unusedAfterStepRemoval;
29054
+ var recipeRefs_1 = require_recipeRefs();
29055
+ function list(value) {
29056
+ return Array.isArray(value) ? value : [];
29057
+ }
29058
+ function strings(value) {
29059
+ return Array.isArray(value) ? value.map(String) : null;
29060
+ }
29061
+ function dagIdOf(step) {
29062
+ return typeof step.name === "string" && step.name.trim() ? step.name : String(step.agent ?? "");
29063
+ }
29064
+ function renameSkillOn(obj, oldId, newId) {
29065
+ let moved = false;
29066
+ const arr = strings(obj.skills);
29067
+ if (arr && arr.includes(oldId)) {
29068
+ obj.skills = arr.map((s) => s === oldId ? newId : s);
29069
+ moved = true;
29070
+ }
29071
+ if (typeof obj.skill === "string" && obj.skill === oldId) {
29072
+ obj.skill = newId;
29073
+ moved = true;
29074
+ }
29075
+ return moved;
29076
+ }
29077
+ function declaredSkills(obj) {
29078
+ return strings(obj.skills) ?? (typeof obj.skill === "string" ? [obj.skill] : []);
29079
+ }
29080
+ function renameAgentRefs(doc, oldId, newId) {
29081
+ const edit = { paths: [], renamedStepIds: [] };
29082
+ if (!oldId || !newId || oldId === newId) {
29083
+ return edit;
29084
+ }
29085
+ for (const pipeline of list(doc.pipelines)) {
29086
+ const pipelineId = String(pipeline.id ?? "");
29087
+ const steps = pipeline.steps;
29088
+ if (!Array.isArray(steps)) {
29089
+ continue;
29090
+ }
29091
+ let dagIdMoved = false;
29092
+ for (let i = 0; i < steps.length; i++) {
29093
+ const step = steps[i];
29094
+ if (typeof step === "string") {
29095
+ if (step === oldId) {
29096
+ steps[i] = newId;
29097
+ dagIdMoved = true;
29098
+ edit.paths.push(`pipelines.${pipelineId}.steps.${oldId}`);
29099
+ }
29100
+ continue;
29101
+ }
29102
+ if (!step || typeof step !== "object") {
29103
+ continue;
29104
+ }
29105
+ const obj = step;
29106
+ if (obj.agent !== oldId) {
29107
+ continue;
29108
+ }
29109
+ obj.agent = newId;
29110
+ const named = typeof obj.name === "string" && obj.name.trim() !== "";
29111
+ edit.paths.push(`pipelines.${pipelineId}.steps.${named ? String(obj.name) : oldId}.agent`);
29112
+ if (!named) {
29113
+ dagIdMoved = true;
29114
+ }
29115
+ }
29116
+ if (!dagIdMoved) {
29117
+ continue;
29118
+ }
29119
+ edit.renamedStepIds.push(oldId);
29120
+ for (const step of steps) {
29121
+ if (!step || typeof step !== "object") {
29122
+ continue;
29123
+ }
29124
+ const obj = step;
29125
+ const deps = strings(obj.depends_on);
29126
+ if (!deps || !deps.includes(oldId)) {
29127
+ continue;
29128
+ }
29129
+ obj.depends_on = deps.map((d) => d === oldId ? newId : d);
29130
+ edit.paths.push(`pipelines.${pipelineId}.steps.${dagIdOf(obj)}.depends_on`);
29131
+ }
29132
+ for (const recipe of (0, recipeRefs_1.recipesDrawingFrom)(doc, pipelineId)) {
29133
+ const recipeId = String(recipe.id ?? "");
29134
+ const recipeSteps = strings(recipe.steps);
29135
+ if (recipeSteps && recipeSteps.includes(oldId)) {
29136
+ recipe.steps = recipeSteps.map((s) => s === oldId ? newId : s);
29137
+ edit.paths.push(`recipes.${recipeId}.steps`);
29138
+ }
29139
+ const gates = recipe.gates;
29140
+ if (gates && typeof gates === "object" && !Array.isArray(gates)) {
29141
+ const map2 = gates;
29142
+ if (oldId in map2) {
29143
+ map2[newId] = map2[oldId];
29144
+ delete map2[oldId];
29145
+ edit.paths.push(`recipes.${recipeId}.gates.${oldId}`);
29146
+ }
29147
+ }
29148
+ }
29149
+ }
29150
+ for (const cmd of list(doc.slash_commands)) {
29151
+ if (cmd.agent === oldId) {
29152
+ cmd.agent = newId;
29153
+ edit.paths.push(`slash_commands.${String(cmd.name ?? "")}.agent`);
29154
+ }
29155
+ }
29156
+ return edit;
29157
+ }
29158
+ function renameSkillRefs(doc, oldId, newId) {
29159
+ const edit = { paths: [], renamedStepIds: [] };
29160
+ if (!oldId || !newId || oldId === newId) {
29161
+ return edit;
29162
+ }
29163
+ for (const agent of list(doc.agents)) {
29164
+ if (renameSkillOn(agent, oldId, newId)) {
29165
+ edit.paths.push(`agents.${String(agent.id ?? "")}.skills`);
29166
+ }
29167
+ }
29168
+ for (const pipeline of list(doc.pipelines)) {
29169
+ const pipelineId = String(pipeline.id ?? "");
29170
+ for (const step of Array.isArray(pipeline.steps) ? pipeline.steps : []) {
29171
+ if (!step || typeof step !== "object") {
29172
+ continue;
29173
+ }
29174
+ const obj = step;
29175
+ if (!renameSkillOn(obj, oldId, newId)) {
29176
+ continue;
29177
+ }
29178
+ edit.paths.push(`pipelines.${pipelineId}.steps.${dagIdOf(obj)}.skills`);
29179
+ }
29180
+ }
29181
+ return edit;
29182
+ }
29183
+ function agentReferences(doc, id) {
29184
+ const out2 = { paths: [], messages: [] };
29185
+ if (!id) {
29186
+ return out2;
29187
+ }
29188
+ for (const pipeline of list(doc.pipelines)) {
29189
+ const pipelineId = String(pipeline.id ?? "");
29190
+ for (const step of Array.isArray(pipeline.steps) ? pipeline.steps : []) {
29191
+ const isObj = Boolean(step) && typeof step === "object";
29192
+ const agent = typeof step === "string" ? step : step?.agent;
29193
+ if (agent !== id) {
29194
+ continue;
29195
+ }
29196
+ const name = isObj ? dagIdOf(step) : id;
29197
+ out2.paths.push(`pipelines.${pipelineId}.steps.${name}`);
29198
+ out2.messages.push(`Pipeline "${pipelineId}" step "${name}" still runs agent "${id}".`);
29199
+ }
29200
+ }
29201
+ for (const cmd of list(doc.slash_commands)) {
29202
+ if (cmd.agent !== id) {
29203
+ continue;
29204
+ }
29205
+ const name = String(cmd.name ?? "");
29206
+ out2.paths.push(`slash_commands.${name}.agent`);
29207
+ out2.messages.push(`Slash command "${name}" still targets agent "${id}".`);
29208
+ }
29209
+ return out2;
29210
+ }
29211
+ function skillReferences(doc, id) {
29212
+ const out2 = { paths: [], messages: [] };
29213
+ if (!id) {
29214
+ return out2;
29215
+ }
29216
+ for (const agent of list(doc.agents)) {
29217
+ const declared = declaredSkills(agent);
29218
+ if (!declared.includes(id)) {
29219
+ continue;
29220
+ }
29221
+ const agentId = String(agent.id ?? "");
29222
+ out2.paths.push(`agents.${agentId}.skills`);
29223
+ out2.messages.push(declared.length === 1 ? `Agent "${agentId}" declares "${id}" as its only skill \u2014 it needs another before this one goes.` : `Agent "${agentId}" declares skill "${id}".`);
29224
+ }
29225
+ for (const pipeline of list(doc.pipelines)) {
29226
+ const pipelineId = String(pipeline.id ?? "");
29227
+ for (const step of Array.isArray(pipeline.steps) ? pipeline.steps : []) {
29228
+ if (!step || typeof step !== "object") {
29229
+ continue;
29230
+ }
29231
+ const obj = step;
29232
+ if (!declaredSkills(obj).includes(id)) {
29233
+ continue;
29234
+ }
29235
+ out2.paths.push(`pipelines.${pipelineId}.steps.${dagIdOf(obj)}.skills`);
29236
+ out2.messages.push(`Pipeline "${pipelineId}" step "${dagIdOf(obj)}" narrows to skill "${id}".`);
29237
+ }
29238
+ }
29239
+ return out2;
29240
+ }
29241
+ function unusedAfterStepRemoval(doc, agentId) {
29242
+ const none = { agent: null, slashCommands: [], skills: [] };
29243
+ if (!agentId) {
29244
+ return none;
29245
+ }
29246
+ for (const pipeline of list(doc.pipelines)) {
29247
+ for (const step of Array.isArray(pipeline.steps) ? pipeline.steps : []) {
29248
+ const agent2 = typeof step === "string" ? step : step?.agent;
29249
+ if (agent2 === agentId) {
29250
+ return none;
29251
+ }
29252
+ }
29253
+ }
29254
+ const agent = list(doc.agents).find((a) => a.id === agentId);
29255
+ return {
29256
+ agent: agentId,
29257
+ slashCommands: list(doc.slash_commands).filter((c) => c.agent === agentId).map((c) => String(c.name ?? "")),
29258
+ skills: agent ? declaredSkills(agent) : []
29259
+ };
29260
+ }
29261
+ }
29262
+ });
29263
+
28415
29264
  // ../core/dist/loader/projectInstructions.js
28416
29265
  var require_projectInstructions = __commonJS({
28417
29266
  "../core/dist/loader/projectInstructions.js"(exports2) {
@@ -29441,6 +30290,7 @@ var require_execEngine = __commonJS({
29441
30290
  var AutoReviewer_1 = require_AutoReviewer();
29442
30291
  var EpicArtifactCommit_1 = require_EpicArtifactCommit();
29443
30292
  var EpicScaffold_1 = require_EpicScaffold();
30293
+ var runProgress_1 = require_runProgress();
29444
30294
  var budget_1 = require_budget();
29445
30295
  var pricing_1 = require_pricing();
29446
30296
  var models_1 = require_models();
@@ -29505,9 +30355,34 @@ var require_execEngine = __commonJS({
29505
30355
  return { kind: "awaiting_review" };
29506
30356
  }
29507
30357
  if (step.status === "rejected") {
30358
+ const skippable = (0, runProgress_1.isStepOptional)(initialPipeline, state.currentStepIdx) || initialPipeline.on_failure === "continue";
30359
+ const openElsewhere = state.steps.findIndex((s, i) => i !== state.currentStepIdx && (0, runProgress_1.isActiveStatus)(s.status));
30360
+ if (skippable && openElsewhere >= 0) {
30361
+ hooks.onStepSkipped?.({
30362
+ stepIdx: state.currentStepIdx,
30363
+ agent: step.agent,
30364
+ reason: step.rejectReason ?? step.autoReviewVerdict?.reason ?? "rejected",
30365
+ nextStepIdx: openElsewhere,
30366
+ runId
30367
+ });
30368
+ RunStateStore_1.RunStateStore.save(root, { ...state, currentStepIdx: openElsewhere });
30369
+ continue;
30370
+ }
29508
30371
  hooks.onRejected?.({ agent: step.agent, runId });
29509
30372
  return { kind: "rejected" };
29510
30373
  }
30374
+ if (step.status === "approved") {
30375
+ const openElsewhere = state.steps.findIndex((s) => (0, runProgress_1.isActiveStatus)(s.status));
30376
+ if (openElsewhere >= 0) {
30377
+ RunStateStore_1.RunStateStore.save(root, { ...state, currentStepIdx: openElsewhere });
30378
+ continue;
30379
+ }
30380
+ const parked = state.steps.find((s) => s.status === "rejected");
30381
+ if (parked) {
30382
+ hooks.onRejected?.({ agent: parked.agent, runId });
30383
+ return { kind: "rejected" };
30384
+ }
30385
+ }
29511
30386
  if (step.status !== "awaiting_work") {
29512
30387
  hooks.onRunFailed?.(`Unexpected step status "${step.status}" \u2014 cannot exec.`);
29513
30388
  return { kind: "error" };
@@ -31352,6 +32227,7 @@ var require_commandModel = __commonJS({
31352
32227
  var strictMode_1 = require_strictMode();
31353
32228
  var commandBodyFreshness_1 = require_commandBodyFreshness();
31354
32229
  var WorkspaceSchema_1 = require_WorkspaceSchema();
32230
+ var runProgress_1 = require_runProgress();
31355
32231
  exports2.CANONICAL_PHASES = [
31356
32232
  { id: "plan", name: "Plan", description: "Scaffold the epic and write the PRD.", artifact: "PRD.md" },
31357
32233
  { id: "prototype", name: "Prototype", description: "Propose the UI visually with multiple design options.", artifact: "PROTOTYPE.md" },
@@ -31418,14 +32294,14 @@ var require_commandModel = __commonJS({
31418
32294
  };
31419
32295
  const statusByDagId = /* @__PURE__ */ new Map();
31420
32296
  state.steps.forEach((s, idx) => statusByDagId.set(dagId(idx), s.status));
31421
- for (let i = 0; i < state.steps.length; i++) {
31422
- const st = state.steps[i].status;
31423
- if (st === "awaiting_work") {
31424
- return { index: i, phaseId: dagId(i), reason: "awaiting_work" };
31425
- }
31426
- if (st === "rejected") {
31427
- return { index: i, phaseId: dagId(i), reason: "rejected" };
31428
- }
32297
+ const open = state.steps.findIndex((s) => s.status === "awaiting_work");
32298
+ if (open >= 0) {
32299
+ return { index: open, phaseId: dagId(open), reason: "awaiting_work" };
32300
+ }
32301
+ const optional = (i) => (0, runProgress_1.isStepOptional)(pipeline, i);
32302
+ const blocked = state.steps.findIndex((s, i) => s.status === "rejected" && !optional(i));
32303
+ if (blocked >= 0) {
32304
+ return { index: blocked, phaseId: dagId(blocked), reason: "rejected" };
31429
32305
  }
31430
32306
  for (let i = 0; i < state.steps.length; i++) {
31431
32307
  if (state.steps[i].status !== "pending") {
@@ -31438,6 +32314,10 @@ var require_commandModel = __commonJS({
31438
32314
  return { index: i, phaseId: dagId(i), reason: "unblocked" };
31439
32315
  }
31440
32316
  }
32317
+ const skipped = state.steps.findIndex((s, i) => s.status === "rejected" && optional(i));
32318
+ if (skipped >= 0) {
32319
+ return { index: skipped, phaseId: dagId(skipped), reason: "rejected" };
32320
+ }
31441
32321
  return null;
31442
32322
  }
31443
32323
  function unprovisionedPhases(config, canonical = exports2.CANONICAL_PHASE_IDS) {
@@ -31477,10 +32357,12 @@ The first token is the **epic id**; an optional second token is the **phase**.
31477
32357
  - **If a phase was given**, use it. Validate it is a step in the epic's
31478
32358
  pipeline (see step 3). If it isn't, tell the user which phases the pipeline
31479
32359
  *does* have and stop.
31480
- - **If no phase was given**, pick the **next eligible phase**: the first step
31481
- that is \`awaiting_work\`, else the first \`rejected\` step, else the first
31482
- \`pending\` step whose every \`depends_on\` is \`approved\`. If none is
31483
- actionable (all approved or paused for review), say so and stop.
32360
+ - **If no phase was given**, pick the **next eligible phase**, checking each
32361
+ rule against every step before moving to the next rule: any step that is
32362
+ \`awaiting_work\`, else any \`rejected\` step *not* marked \`optional: true\`,
32363
+ else the first \`pending\` step whose every \`depends_on\` is \`approved\`, else
32364
+ a \`rejected\` \`optional\` step. If none is actionable (all approved or
32365
+ paused for review), say so and stop.
31484
32366
 
31485
32367
  ## 3. Resolve composition from the pipeline (never from the command name)
31486
32368
 
@@ -32066,12 +32948,12 @@ var require_dist = __commonJS({
32066
32948
  "../core/dist/index.js"(exports2) {
32067
32949
  "use strict";
32068
32950
  Object.defineProperty(exports2, "__esModule", { value: true });
32069
- exports2.parseFollowUps = exports2.FollowUpsParseError = exports2.FollowUpManifestSchema = exports2.FollowUpItemSchema = exports2.SIGNAL_FILE = exports2.FOLLOW_UP_ARTIFACT = exports2.readEpicSignal = exports2.existingEpicIds = exports2.followUpIdFor = exports2.followUpEpicId = exports2.renderIntentMarkdown = exports2.openFollowUpEpic = exports2.openIncidentEpic = exports2.SignalParseError = exports2.isSignal = exports2.parseSignal = exports2.SignalSchema = exports2.EpicStepEditError = exports2.resolveStepRef = exports2.describeGateEffect = exports2.commitEpicStepEdit = exports2.planSetEpicStepGates = exports2.planRemoveEpicStep = exports2.planAddEpicStep = exports2.EpicScaffoldError = exports2.epicsRoot = exports2.mapStepStatusToEpic = exports2.mirrorRunStateToEpic = exports2.scaffoldEpic = exports2.resolveArtifactCommitConfig = exports2.commitApprovedArtifacts = exports2.PipelineAdaptError = exports2.applyAdaptation = exports2.parseAdaptationVerdict = exports2.buildAdaptationPrompt = exports2.buildPhaseCatalog = exports2.slugEpicId = exports2.parseClassificationVerdict = exports2.buildClassificationPrompt = exports2.heuristicClassify = exports2.PipelineAssembleError = exports2.recipePipelineId = exports2.assemblePipeline = exports2.collectWorkspaceRefIssues = exports2.stepDagId = exports2.stepAgentId = exports2.normalizeStep = exports2.WorkspaceValidationError = exports2.validateWorkspace = exports2.WorkspaceSchema = void 0;
32070
- 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.WORKSPACE_DIR = exports2.WORKSPACE_FILENAME = exports2.WorkspaceParseError = exports2.WorkspaceNotFoundError = exports2.WorkspaceLoader = exports2.renderPlanMarkdown = exports2.generatePlan = exports2.collectContext = exports2.followUpHookFailures = exports2.pendingFollowUpDone = exports2.applyFollowUpHookRun = exports2.trackFollowUpChildren = exports2.writeFollowUpHookLedger = exports2.readFollowUpHookLedger = exports2.followUpHookLedgerPath = exports2.runFollowUpHook = exports2.fillFollowUpHookCommand = exports2.resolveFollowUpHooks = exports2.epicPipelineId = exports2.FOLLOW_UP_HOOK_TIMEOUT_MS = exports2.FOLLOW_UP_HOOKS_LEDGER = exports2.stepProducesFollowUps = exports2.collectFollowUpHookIssues = exports2.FOLLOW_UP_HOOK_PLACEHOLDERS = exports2.FOLLOW_UP_HOOK_KEYS = exports2.FOLLOW_UP_INTENT = exports2.FOLLOW_UPS_FILE = exports2.openManifestFollowUp = exports2.followUpChildId = exports2.followUpsOf = exports2.readEpicFollowUps = void 0;
32071
- exports2.buildClaudeSpawnEnv = exports2.hasClaudeLogin = exports2.isInsideClaudeCodeSession = exports2.createJsonSink = exports2.createLineSink = exports2.isCodexMcpConfigured = exports2.codexConfigPath = exports2.readProjectMcpServer = exports2.mcpRegistrarFor = exports2.codexMcpRegistrar = exports2.claudeMcpRegistrar = exports2.CodexRunner = 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.strictModeSection = exports2.resolveEpicStrictMode = exports2.epicStrictMode = exports2.commandBodyPredatesStrictMode = exports2.STRICT_MODE_KEY = exports2.STRICT_MODE_HEADING = exports2.writeUserEpicIdPrefix = exports2.userConfigPath = 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 = void 0;
32072
- 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.runExecLoop = exports2.estimateCostUsd = exports2.providerAliases = exports2.ratesFromConfig = exports2.mergeRates = exports2.BUILTIN_RATES = exports2.checkBudget = exports2.PipelineRunError = exports2.retryAutoReview = exports2.submitAutoReviewVerdict = exports2.requestStepUpdate = exports2.rerunStep = exports2.rejectStep = exports2.approveStep = 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 = void 0;
32073
- 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.resolveProviderModel = exports2.isClaudeTierAlias = exports2.CLAUDE_TIER_ALIASES = 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 = void 0;
32074
- 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 = 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 = void 0;
32951
+ exports2.followUpEpicId = exports2.renderIntentMarkdown = exports2.openFollowUpEpic = exports2.openIncidentEpic = exports2.SignalParseError = exports2.isSignal = exports2.parseSignal = exports2.SignalSchema = exports2.EpicStepEditError = exports2.resolveStepRef = exports2.describeGateEffect = exports2.commitEpicStepEdit = exports2.planSetEpicStepGates = exports2.planRemoveEpicStep = exports2.planAddEpicStep = exports2.EpicWorkflowSwitchError = exports2.canSwitchEpicWorkflow = exports2.epicWorkflowLock = exports2.applyEpicWorkflowSwitch = exports2.stageEpicWorkflowSwitch = exports2.planEpicWorkflowSwitch = exports2.EpicDescriptionError = exports2.setEpicDescription = exports2.lockedEpicDirError = exports2.EpicScaffoldError = exports2.epicsRoot = exports2.mapStepStatusToEpic = exports2.mirrorRunStateToEpic = exports2.scaffoldEpic = exports2.resolveArtifactCommitConfig = exports2.commitApprovedArtifacts = exports2.PipelineAdaptError = exports2.applyAdaptation = exports2.parseAdaptationVerdict = exports2.buildAdaptationPrompt = exports2.buildPhaseCatalog = exports2.slugEpicId = exports2.parseClassificationVerdict = exports2.buildClassificationPrompt = exports2.heuristicClassify = exports2.PipelineAssembleError = exports2.recipePipelineId = exports2.assemblePipeline = exports2.collectWorkspaceRefIssues = exports2.stepDagId = exports2.stepAgentId = exports2.normalizeStep = exports2.WorkspaceValidationError = exports2.validateWorkspace = exports2.WorkspaceSchema = void 0;
32952
+ 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 = exports2.generatePlan = exports2.collectContext = exports2.followUpHookFailures = exports2.pendingFollowUpDone = exports2.applyFollowUpHookRun = exports2.trackFollowUpChildren = exports2.writeFollowUpHookLedger = exports2.readFollowUpHookLedger = exports2.followUpHookLedgerPath = exports2.runFollowUpHook = exports2.fillFollowUpHookCommand = exports2.resolveFollowUpHooks = exports2.epicPipelineId = exports2.FOLLOW_UP_HOOK_TIMEOUT_MS = exports2.FOLLOW_UP_HOOKS_LEDGER = exports2.stepProducesFollowUps = exports2.collectFollowUpHookIssues = exports2.FOLLOW_UP_HOOK_PLACEHOLDERS = exports2.FOLLOW_UP_HOOK_KEYS = exports2.FOLLOW_UP_INTENT = exports2.FOLLOW_UPS_FILE = exports2.openManifestFollowUp = exports2.followUpChildId = exports2.followUpsOf = exports2.readEpicFollowUps = exports2.parseFollowUps = exports2.FollowUpsParseError = exports2.FollowUpManifestSchema = exports2.FollowUpItemSchema = exports2.SIGNAL_FILE = exports2.FOLLOW_UP_ARTIFACT = exports2.readEpicSignal = exports2.existingEpicIds = exports2.followUpIdFor = void 0;
32953
+ exports2.commandBodyIsStale = exports2.readEpicTags = exports2.normalizeTags = exports2.normalizeTag = exports2.epicMatchesTags = exports2.applyTagEdit = exports2.MAX_TAG_LENGTH = exports2.EPIC_TAGS_KEY = exports2.strictModeSection = exports2.resolveEpicStrictMode = exports2.epicStrictMode = exports2.commandBodyPredatesStrictMode = exports2.STRICT_MODE_KEY = exports2.STRICT_MODE_HEADING = exports2.writeUserEpicIdPrefix = exports2.userConfigPath = 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 = void 0;
32954
+ exports2.runExecLoop = exports2.estimateCostUsd = exports2.providerAliases = exports2.ratesFromConfig = exports2.mergeRates = exports2.BUILTIN_RATES = exports2.checkBudget = exports2.isActiveStatus = exports2.isStepOptional = exports2.isRunComplete = exports2.deriveRunProgress = exports2.PipelineRunError = exports2.retryAutoReview = exports2.submitAutoReviewVerdict = exports2.requestStepUpdate = exports2.rerunStep = exports2.rejectStep = exports2.approveStep = 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.CodexRunner = exports2.DefaultRunner = exports2.RunnerRegistry = exports2.targetPath = exports2.scopePaths = exports2.discoverAssets = void 0;
32955
+ 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.resolveProviderModel = exports2.isClaudeTierAlias = exports2.CLAUDE_TIER_ALIASES = 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 = void 0;
32956
+ 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 = 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 = void 0;
32075
32957
  var WorkspaceSchema_1 = require_WorkspaceSchema();
32076
32958
  Object.defineProperty(exports2, "WorkspaceSchema", { enumerable: true, get: function() {
32077
32959
  return WorkspaceSchema_1.WorkspaceSchema;
@@ -32156,6 +33038,35 @@ var require_dist = __commonJS({
32156
33038
  Object.defineProperty(exports2, "EpicScaffoldError", { enumerable: true, get: function() {
32157
33039
  return EpicScaffold_1.EpicScaffoldError;
32158
33040
  } });
33041
+ Object.defineProperty(exports2, "lockedEpicDirError", { enumerable: true, get: function() {
33042
+ return EpicScaffold_1.lockedEpicDirError;
33043
+ } });
33044
+ var EpicDescription_1 = require_EpicDescription();
33045
+ Object.defineProperty(exports2, "setEpicDescription", { enumerable: true, get: function() {
33046
+ return EpicDescription_1.setEpicDescription;
33047
+ } });
33048
+ Object.defineProperty(exports2, "EpicDescriptionError", { enumerable: true, get: function() {
33049
+ return EpicDescription_1.EpicDescriptionError;
33050
+ } });
33051
+ var EpicWorkflowSwitch_1 = require_EpicWorkflowSwitch();
33052
+ Object.defineProperty(exports2, "planEpicWorkflowSwitch", { enumerable: true, get: function() {
33053
+ return EpicWorkflowSwitch_1.planEpicWorkflowSwitch;
33054
+ } });
33055
+ Object.defineProperty(exports2, "stageEpicWorkflowSwitch", { enumerable: true, get: function() {
33056
+ return EpicWorkflowSwitch_1.stageEpicWorkflowSwitch;
33057
+ } });
33058
+ Object.defineProperty(exports2, "applyEpicWorkflowSwitch", { enumerable: true, get: function() {
33059
+ return EpicWorkflowSwitch_1.applyEpicWorkflowSwitch;
33060
+ } });
33061
+ Object.defineProperty(exports2, "epicWorkflowLock", { enumerable: true, get: function() {
33062
+ return EpicWorkflowSwitch_1.epicWorkflowLock;
33063
+ } });
33064
+ Object.defineProperty(exports2, "canSwitchEpicWorkflow", { enumerable: true, get: function() {
33065
+ return EpicWorkflowSwitch_1.canSwitchEpicWorkflow;
33066
+ } });
33067
+ Object.defineProperty(exports2, "EpicWorkflowSwitchError", { enumerable: true, get: function() {
33068
+ return EpicWorkflowSwitch_1.EpicWorkflowSwitchError;
33069
+ } });
32159
33070
  var EpicStepEdit_1 = require_EpicStepEdit();
32160
33071
  Object.defineProperty(exports2, "planAddEpicStep", { enumerable: true, get: function() {
32161
33072
  return EpicStepEdit_1.planAddEpicStep;
@@ -32330,6 +33241,32 @@ var require_dist = __commonJS({
32330
33241
  Object.defineProperty(exports2, "WORKSPACE_DIR", { enumerable: true, get: function() {
32331
33242
  return WorkspaceLoader_1.WORKSPACE_DIR;
32332
33243
  } });
33244
+ var recipeRefs_1 = require_recipeRefs();
33245
+ Object.defineProperty(exports2, "recipesDrawingFrom", { enumerable: true, get: function() {
33246
+ return recipeRefs_1.recipesDrawingFrom;
33247
+ } });
33248
+ Object.defineProperty(exports2, "dropRecipeStep", { enumerable: true, get: function() {
33249
+ return recipeRefs_1.dropRecipeStep;
33250
+ } });
33251
+ Object.defineProperty(exports2, "dropRecipesForPipeline", { enumerable: true, get: function() {
33252
+ return recipeRefs_1.dropRecipesForPipeline;
33253
+ } });
33254
+ var renameRefs_1 = require_renameRefs();
33255
+ Object.defineProperty(exports2, "renameAgentRefs", { enumerable: true, get: function() {
33256
+ return renameRefs_1.renameAgentRefs;
33257
+ } });
33258
+ Object.defineProperty(exports2, "renameSkillRefs", { enumerable: true, get: function() {
33259
+ return renameRefs_1.renameSkillRefs;
33260
+ } });
33261
+ Object.defineProperty(exports2, "agentReferences", { enumerable: true, get: function() {
33262
+ return renameRefs_1.agentReferences;
33263
+ } });
33264
+ Object.defineProperty(exports2, "skillReferences", { enumerable: true, get: function() {
33265
+ return renameRefs_1.skillReferences;
33266
+ } });
33267
+ Object.defineProperty(exports2, "unusedAfterStepRemoval", { enumerable: true, get: function() {
33268
+ return renameRefs_1.unusedAfterStepRemoval;
33269
+ } });
32333
33270
  var EpicPipelineStore_1 = require_EpicPipelineStore();
32334
33271
  Object.defineProperty(exports2, "EPIC_PIPELINE_FILENAME", { enumerable: true, get: function() {
32335
33272
  return EpicPipelineStore_1.EPIC_PIPELINE_FILENAME;
@@ -32628,6 +33565,19 @@ var require_dist = __commonJS({
32628
33565
  Object.defineProperty(exports2, "PipelineRunError", { enumerable: true, get: function() {
32629
33566
  return PipelineRunner_1.PipelineRunError;
32630
33567
  } });
33568
+ var runProgress_1 = require_runProgress();
33569
+ Object.defineProperty(exports2, "deriveRunProgress", { enumerable: true, get: function() {
33570
+ return runProgress_1.deriveRunProgress;
33571
+ } });
33572
+ Object.defineProperty(exports2, "isRunComplete", { enumerable: true, get: function() {
33573
+ return runProgress_1.isRunComplete;
33574
+ } });
33575
+ Object.defineProperty(exports2, "isStepOptional", { enumerable: true, get: function() {
33576
+ return runProgress_1.isStepOptional;
33577
+ } });
33578
+ Object.defineProperty(exports2, "isActiveStatus", { enumerable: true, get: function() {
33579
+ return runProgress_1.isActiveStatus;
33580
+ } });
32631
33581
  var budget_1 = require_budget();
32632
33582
  Object.defineProperty(exports2, "checkBudget", { enumerable: true, get: function() {
32633
33583
  return budget_1.checkBudget;
@@ -41630,7 +42580,7 @@ var require_package = __commonJS({
41630
42580
  "package.json"(exports2, module2) {
41631
42581
  module2.exports = {
41632
42582
  name: "@delete101020/aidlc",
41633
- version: "4.0.9",
42583
+ version: "4.0.11",
41634
42584
  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.",
41635
42585
  license: "MIT",
41636
42586
  repository: {
@@ -46447,9 +47397,10 @@ function registerRun(program3) {
46447
47397
  cmd.command("reject <runId>").description("Reject the current awaiting_review step").requiredOption("--reason <text>", "Why the step was rejected").action((runId, opts, actionCmd) => {
46448
47398
  const root = resolveWorkspaceRoot(actionCmd);
46449
47399
  const state = requireRun(root, runId);
47400
+ const pipeline = requirePipelineForRun(root, state);
46450
47401
  let next;
46451
47402
  try {
46452
- next = (0, import_core13.rejectStep)({ state, reason: opts.reason });
47403
+ next = (0, import_core13.rejectStep)({ state, reason: opts.reason, pipeline });
46453
47404
  } catch (err) {
46454
47405
  console.error(import_chalk10.default.red(err instanceof Error ? err.message : String(err)));
46455
47406
  process.exit(1);
@@ -46460,18 +47411,23 @@ function registerRun(program3) {
46460
47411
  console.log(import_chalk10.default.dim(` Reason: ${opts.reason}`));
46461
47412
  console.log(import_chalk10.default.dim(` Rerun: aidlc run rerun ${runId} [--feedback "..."]`));
46462
47413
  });
46463
- cmd.command("rerun <runId>").description("Retry the current rejected step (bumps revision, resets to awaiting_work)").option("--feedback <text>", "Notes for the next attempt (stored on the step)").action((runId, opts, actionCmd) => {
47414
+ cmd.command("rerun <runId>").description("Retry a rejected step (bumps revision, resets to awaiting_work)").option("--feedback <text>", "Notes for the next attempt (stored on the step)").option("--step <idx>", "0-based step index (default: the run's current step)").action((runId, opts, actionCmd) => {
46464
47415
  const root = resolveWorkspaceRoot(actionCmd);
46465
47416
  const state = requireRun(root, runId);
47417
+ const stepIdx = opts.step === void 0 ? void 0 : Number(opts.step);
47418
+ if (stepIdx !== void 0 && !Number.isInteger(stepIdx)) {
47419
+ console.error(import_chalk10.default.red(`--step must be an integer, got "${opts.step}"`));
47420
+ process.exit(1);
47421
+ }
46466
47422
  let next;
46467
47423
  try {
46468
- next = (0, import_core13.rerunStep)({ state, feedback: opts.feedback });
47424
+ next = (0, import_core13.rerunStep)({ state, feedback: opts.feedback, stepIdx });
46469
47425
  } catch (err) {
46470
47426
  console.error(import_chalk10.default.red(err instanceof Error ? err.message : String(err)));
46471
47427
  process.exit(1);
46472
47428
  }
46473
47429
  saveRunState(root, next, state);
46474
- const step = next.steps[next.currentStepIdx];
47430
+ const step = next.steps[stepIdx ?? next.currentStepIdx];
46475
47431
  console.log(import_chalk10.default.yellow("\u21BA") + ` Rerunning "${step.agent}" (rev ${step.revision})`);
46476
47432
  if (opts.feedback) {
46477
47433
  console.log(import_chalk10.default.dim(` Feedback: ${opts.feedback}`));
@@ -46729,6 +47685,11 @@ ${reason}`)),
46729
47685
  \u2718 Step "${e.agent}" was rejected.`));
46730
47686
  info(import_chalk10.default.dim(` Rerun: aidlc run rerun ${e.runId} [--feedback "..."]`));
46731
47687
  },
47688
+ onStepSkipped: (e) => {
47689
+ info(import_chalk10.default.yellow(`
47690
+ \u2933 Step "${e.agent}" was rejected \u2014 carrying on.`) + import_chalk10.default.dim(` ${e.reason}`));
47691
+ info(import_chalk10.default.dim(` Want it back? aidlc run rerun ${e.runId} --step ${e.stepIdx}`));
47692
+ },
46732
47693
  onAutoReviewStart: (e) => info(import_chalk10.default.bold(`
46733
47694
  \u{1F50D} Auto-review: "${e.agent}"`)),
46734
47695
  onAutoReviewResult: (e) => {
@@ -48337,6 +49298,121 @@ Run ${import_chalk15.default.cyan(`${runCmd} ${epicId}`)} in Claude to begin.`);
48337
49298
  console.log(import_chalk15.default.dim(` was: ${before.join(" ")}`));
48338
49299
  }
48339
49300
  });
49301
+ cmd.command("describe <id> [text...]").description("Show or set an epic's description. Bare `describe <id>` prints it.").option("--clear", "empty the description").option("--json", "Output the result as JSON").action((id, text, opts, actionCmd) => {
49302
+ const root = resolveWorkspaceRoot(actionCmd);
49303
+ const doc = readYaml(root);
49304
+ const dir = path12.join((0, import_core19.epicsRoot)(root, doc), id);
49305
+ const file = path12.join(dir, "state.json");
49306
+ if (!fs10.existsSync(file)) {
49307
+ const all = listEpics(root, doc).map((e) => e.id);
49308
+ console.error(import_chalk15.default.red(`Epic "${id}" not found.`));
49309
+ if (all.length > 0) {
49310
+ console.error(import_chalk15.default.dim(`Available: ${all.join(", ")}`));
49311
+ }
49312
+ process.exit(1);
49313
+ }
49314
+ const words = text.join(" ").trim();
49315
+ if (!opts.clear && words === "") {
49316
+ let current = "";
49317
+ try {
49318
+ const state = JSON.parse(fs10.readFileSync(file, "utf8"));
49319
+ current = typeof state.description === "string" ? state.description : "";
49320
+ } catch (err) {
49321
+ console.error(import_chalk15.default.red(`Could not read ${file}: ${err instanceof Error ? err.message : String(err)}`));
49322
+ process.exit(1);
49323
+ }
49324
+ if (opts.json) {
49325
+ console.log(JSON.stringify({ id, description: current }, null, 2));
49326
+ return;
49327
+ }
49328
+ console.log(current ? current : import_chalk15.default.dim("(no description)"));
49329
+ return;
49330
+ }
49331
+ try {
49332
+ const edit = (0, import_core19.setEpicDescription)(dir, id, opts.clear ? "" : words);
49333
+ if (opts.json) {
49334
+ console.log(JSON.stringify(edit, null, 2));
49335
+ return;
49336
+ }
49337
+ console.log(import_chalk15.default.green("\u2714") + ` ${import_chalk15.default.bold(id)}: ` + (edit.description ? edit.description : import_chalk15.default.dim("(no description)")));
49338
+ if (edit.previous) {
49339
+ console.log(import_chalk15.default.dim(` was: ${edit.previous}`));
49340
+ }
49341
+ console.log(import_chalk15.default.dim(` ${id}.md: ${edit.doc === "kept" ? "left as it is \u2014 written by hand since, and agents read it" : edit.doc === "created" ? "created" : edit.doc}`));
49342
+ } catch (err) {
49343
+ console.error(import_chalk15.default.red(err instanceof import_core19.EpicDescriptionError ? err.message : String(err)));
49344
+ process.exit(1);
49345
+ }
49346
+ });
49347
+ cmd.command("workflow <id>").description("Show or change the workflow an epic runs. Only before its first step moves.").option("--recipe <recipeId>", "rebuild the epic's own pipeline from this recipe").option("--pipeline <pipelineId>", "point the epic at a pipeline that already exists").option("--json", "Output the result as JSON").action((id, opts, actionCmd) => {
49348
+ const root = resolveWorkspaceRoot(actionCmd);
49349
+ const doc = requireYaml(root);
49350
+ const stateFile = path12.join((0, import_core19.epicsRoot)(root, doc), id, "state.json");
49351
+ if (!fs10.existsSync(stateFile)) {
49352
+ const all = listEpics(root, doc).map((e) => e.id);
49353
+ console.error(import_chalk15.default.red(`Epic "${id}" not found.`));
49354
+ if (all.length > 0) {
49355
+ console.error(import_chalk15.default.dim(`Available: ${all.join(", ")}`));
49356
+ }
49357
+ process.exit(1);
49358
+ }
49359
+ if (opts.recipe && opts.pipeline) {
49360
+ console.error(import_chalk15.default.red("Pass --recipe or --pipeline, not both."));
49361
+ process.exit(1);
49362
+ }
49363
+ const lock = (0, import_core19.epicWorkflowLock)(import_core19.RunStateStore.load(root, id));
49364
+ if (!opts.recipe && !opts.pipeline) {
49365
+ const state = JSON.parse(fs10.readFileSync(stateFile, "utf8"));
49366
+ const current = typeof state.pipeline === "string" && state.pipeline ? { kind: "pipeline", id: state.pipeline } : typeof state.agent === "string" && state.agent ? { kind: "agent", id: state.agent } : { kind: "none", id: null };
49367
+ const recipes = Array.isArray(doc.recipes) ? doc.recipes.map((r) => String(r.id ?? "")) : [];
49368
+ if (opts.json) {
49369
+ console.log(JSON.stringify({ id, current, canChange: lock === null, lock, recipes }, null, 2));
49370
+ return;
49371
+ }
49372
+ console.log(`${import_chalk15.default.bold(id)} runs ${current.id ? import_chalk15.default.cyan(`${current.kind} ${current.id}`) : import_chalk15.default.dim("(nothing)")}`);
49373
+ if (lock) {
49374
+ console.log(import_chalk15.default.dim(` locked: ${lock} \u2014 use \`aidlc epic step add/remove\` instead`));
49375
+ } else {
49376
+ console.log(import_chalk15.default.dim(" not started yet, so the workflow can still be changed:"));
49377
+ console.log(import_chalk15.default.dim(` aidlc epic workflow ${id} --recipe <${recipes.join("|") || "recipe"}>`));
49378
+ }
49379
+ return;
49380
+ }
49381
+ let config;
49382
+ try {
49383
+ config = (0, import_core19.validateWorkspace)(doc, ".aidlc/workspace.yaml");
49384
+ } catch (err) {
49385
+ console.error(import_chalk15.default.red("workspace.yaml is invalid \u2014 not changing anything:"));
49386
+ console.error(import_chalk15.default.dim(err instanceof Error ? err.message : String(err)));
49387
+ process.exit(1);
49388
+ }
49389
+ const target = opts.recipe ? { kind: "recipe", id: opts.recipe } : { kind: "pipeline", id: opts.pipeline };
49390
+ try {
49391
+ const plan = (0, import_core19.planEpicWorkflowSwitch)({ workspaceRoot: root, doc, config, epicId: id, target });
49392
+ (0, import_core19.stageEpicWorkflowSwitch)(doc, plan);
49393
+ (0, import_core19.validateWorkspace)(doc, ".aidlc/workspace.yaml");
49394
+ writeYaml(root, doc);
49395
+ const result = (0, import_core19.applyEpicWorkflowSwitch)(root, doc, plan);
49396
+ if (opts.json) {
49397
+ console.log(JSON.stringify(result, null, 2));
49398
+ return;
49399
+ }
49400
+ console.log(import_chalk15.default.green("\u2714") + ` ${import_chalk15.default.bold(id)} now runs ${import_chalk15.default.cyan(result.pipelineId)}` + (target.kind === "recipe" ? import_chalk15.default.dim(` (from recipe ${target.id})`) : ""));
49401
+ console.log(import_chalk15.default.dim(` steps: ${result.agents.join(" \u2192 ")}`));
49402
+ if (result.previousPipelineId && result.previousPipelineId !== result.pipelineId) {
49403
+ console.log(import_chalk15.default.dim(` was: ${result.previousPipelineId}`));
49404
+ }
49405
+ if (result.removedPipelineFile) {
49406
+ console.log(import_chalk15.default.dim(` removed ${path12.relative(root, result.removedPipelineFile)} \u2014 the shared pipeline takes over`));
49407
+ }
49408
+ } catch (err) {
49409
+ if (err instanceof import_core19.EpicWorkflowSwitchError || err instanceof import_core19.PipelineAssembleError) {
49410
+ console.error(import_chalk15.default.red(err.message));
49411
+ process.exit(1);
49412
+ }
49413
+ throw err;
49414
+ }
49415
+ });
48340
49416
  const pipelineCmd = cmd.command("pipeline").description("Move epic-owned pipelines out of the shared workspace.yaml");
48341
49417
  pipelineCmd.command("extract").description(
48342
49418
  "Move each epic's pipeline out of .aidlc/workspace.yaml into\n <state.root>/<epic>/pipeline.yaml. Only pipelines an epic names in its\n own state.json move; shared and hand-authored ones stay put."