@mutmutco/cli 4.4.7 → 4.4.9

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/main.cjs +605 -393
  2. package/package.json +1 -1
package/dist/main.cjs CHANGED
@@ -4534,7 +4534,7 @@ function useColor() {
4534
4534
  var program = new Command();
4535
4535
 
4536
4536
  // src/command-composition.ts
4537
- var import_node_fs48 = require("node:fs");
4537
+ var import_node_fs49 = require("node:fs");
4538
4538
  init_clean_exit();
4539
4539
  init_cli_shared();
4540
4540
 
@@ -5437,7 +5437,7 @@ function resolveVerbAliasShim(argv) {
5437
5437
 
5438
5438
  // src/command-composition.ts
5439
5439
  var import_node_os21 = require("node:os");
5440
- var import_node_path46 = require("node:path");
5440
+ var import_node_path47 = require("node:path");
5441
5441
 
5442
5442
  // src/board-read.ts
5443
5443
  var import_node_fs13 = require("node:fs");
@@ -15938,10 +15938,10 @@ var rollout_plan_default = {
15938
15938
  note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
15939
15939
  },
15940
15940
  baseline: {
15941
- version: "4.4.7",
15942
- tag: "v4.4.7",
15943
- commit: "f0781ed0cbda",
15944
- npm: "@mutmutco/cli@4.4.7"
15941
+ version: "4.4.9",
15942
+ tag: "v4.4.9",
15943
+ commit: "da79ce082e9b",
15944
+ npm: "@mutmutco/cli@4.4.9"
15945
15945
  },
15946
15946
  exitCriterion: "fleet-n-of-n",
15947
15947
  hubOnlyShortcut: "forbidden",
@@ -15958,14 +15958,14 @@ var rollout_plan_default = {
15958
15958
  repo: "mutmutco/mmi-hub",
15959
15959
  role: "canary",
15960
15960
  schedule: "train",
15961
- v3Target: "v4.4.7"
15961
+ v3Target: "v4.4.9"
15962
15962
  }
15963
15963
  ],
15964
15964
  rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
15965
15965
  rollback: {
15966
15966
  independent: true,
15967
- mechanism: "npm dist-tag latest -> 4.4.7 and redeploy the Hub Lambda from tag v4.4.7 (f0781ed0cbda); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15968
- v3Target: "v4.4.7 (@mutmutco/cli@4.4.7, tag commit f0781ed0cbda \u2014 last known-good release carrying the repo-index v4-only contract)"
15967
+ mechanism: "npm dist-tag latest -> 4.4.9 and redeploy the Hub Lambda from tag v4.4.9 (da79ce082e9b); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
15968
+ v3Target: "v4.4.9 (@mutmutco/cli@4.4.9, tag commit da79ce082e9b \u2014 last known-good release carrying the repo-index v4-only contract)"
15969
15969
  }
15970
15970
  },
15971
15971
  {
@@ -18259,6 +18259,9 @@ function correlateTenantRun(deps, since, titleIncludes) {
18259
18259
  function correlatePublishRun(deps, since, titleIncludes) {
18260
18260
  return correlateRun(deps, { workflow: "tenant-publish.yml", since, mode: "dispatch", titleIncludes });
18261
18261
  }
18262
+ function correlateGetPublishRun(deps, since, product) {
18263
+ return correlateRun(deps, { workflow: "get-publish.yml", since, mode: "dispatch", titleIncludes: [product] });
18264
+ }
18262
18265
  function correlateControlRun(deps, since, titleIncludes) {
18263
18266
  return correlateRun(deps, { workflow: "tenant-control.yml", since, mode: "dispatch", titleIncludes });
18264
18267
  }
@@ -18801,6 +18804,10 @@ function isReleaseShaDeployEnumerationCandidate(row, nonDeployEvents) {
18801
18804
  return true;
18802
18805
  }
18803
18806
 
18807
+ // src/train-apply-deploy.ts
18808
+ var import_node_fs19 = require("node:fs");
18809
+ var import_node_path17 = require("node:path");
18810
+
18804
18811
  // src/vercel-deployments.ts
18805
18812
  var TERMINAL = /* @__PURE__ */ new Set(["success", "failure", "error", "inactive"]);
18806
18813
  function isTerminalVercelState(state) {
@@ -19009,6 +19016,114 @@ function appendPublishDispatch(deploy, publish) {
19009
19016
  deployStatus: deploy.deployStatus === "failure" || publish.deployStatus === "failure" ? "failure" : deploy.deployStatus === "pending" || publish.deployStatus === "pending" ? "pending" : "success"
19010
19017
  };
19011
19018
  }
19019
+ var HUB_SERVED_PRODUCT = "mmi";
19020
+ function getPublishDispatchCommand(repo, product = HUB_SERVED_PRODUCT) {
19021
+ return `gh workflow run get-publish.yml --repo ${repo} --ref main -f product=${product}`;
19022
+ }
19023
+ function readLocalLauncherVersion(root = process.cwd()) {
19024
+ try {
19025
+ const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "installer", "launcher", "package.json"), "utf8");
19026
+ const version = JSON.parse(raw).version;
19027
+ return typeof version === "string" && version.trim() ? version.trim() : null;
19028
+ } catch {
19029
+ return null;
19030
+ }
19031
+ }
19032
+ function readServedChannelUrl(product = HUB_SERVED_PRODUCT, root = process.cwd()) {
19033
+ try {
19034
+ const raw = (0, import_node_fs19.readFileSync)((0, import_node_path17.join)(root, "config", `product.${product}.json`), "utf8");
19035
+ const host = JSON.parse(raw).host;
19036
+ if (typeof host !== "string" || !host.trim()) return null;
19037
+ return `${host.trim().replace(/\/+$/, "")}/release/version`;
19038
+ } catch {
19039
+ return null;
19040
+ }
19041
+ }
19042
+ async function fetchServedChannelVersion(url, fetchImpl = fetch) {
19043
+ try {
19044
+ const res = await fetchImpl(url, { method: "GET", redirect: "follow", signal: AbortSignal.timeout(15e3) });
19045
+ if (res.status !== 200) return { ok: false, status: res.status };
19046
+ const body = (await res.text()).slice(0, 4096);
19047
+ const version = JSON.parse(body).version;
19048
+ if (typeof version !== "string" || !version.trim()) return { ok: false, status: res.status, error: "pointer carried no version" };
19049
+ return { ok: true, version: version.trim(), status: res.status };
19050
+ } catch (e) {
19051
+ return { ok: false, error: e instanceof Error ? e.message : String(e) };
19052
+ }
19053
+ }
19054
+ async function appendServedChannelPublish(deps, input, dispatch) {
19055
+ if (!isHubControlRepo(input.repo)) return dispatch;
19056
+ const channelUrl = input.channelUrl ?? readServedChannelUrl();
19057
+ const remedy = getPublishDispatchCommand(input.repo);
19058
+ const withNote = (note, deployStatus) => ({
19059
+ ...dispatch,
19060
+ note: `${dispatch.note}; ${note}`,
19061
+ ...deployStatus ? { deployStatus } : {}
19062
+ });
19063
+ if (input.publishStatus !== "success") {
19064
+ return withNote(`served channel NOT moved (publish did not succeed) \u2014 after the publish is green, run \`${remedy}\``);
19065
+ }
19066
+ const since = (deps.now ?? Date.now)();
19067
+ try {
19068
+ await deps.run("gh", ["workflow", "run", "get-publish.yml", "--repo", input.repo, "--ref", "main", "-f", `product=${HUB_SERVED_PRODUCT}`]);
19069
+ } catch (e) {
19070
+ const msg = e instanceof Error ? e.message : String(e);
19071
+ return withNote(`get-publish dispatch FAILED: ${msg}. The release itself landed, but the SERVED CHANNEL IS UNCHANGED \u2014 recover with \`${remedy}\``, "failure");
19072
+ }
19073
+ const correlated = await correlateGetPublishRun(deps, since, HUB_SERVED_PRODUCT);
19074
+ if (correlated.read === "failed") {
19075
+ return withNote(`get-publish dispatched but its run could not be READ: ${correlated.error}. Check the Actions tab; if it never ran, recover with \`${remedy}\``, "failure");
19076
+ }
19077
+ const { runId, runUrl } = correlated;
19078
+ const runRow = { workflow: "get-publish.yml", ...runId ? { runId } : {}, ...runUrl ? { runUrl } : {} };
19079
+ if (!input.watch) {
19080
+ return {
19081
+ ...dispatch,
19082
+ note: `${dispatch.note}; dispatched get-publish.yml (product=${HUB_SERVED_PRODUCT}) \u2014 NOT watched, so the served channel is not yet proven moved`,
19083
+ workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "pending" }]
19084
+ };
19085
+ }
19086
+ const runStatus = await watchTenantRun(deps, runId, input.repo);
19087
+ if (runStatus !== "success") {
19088
+ return {
19089
+ ...dispatch,
19090
+ note: `${dispatch.note}; get-publish.yml ${runStatus} \u2014 the SERVED CHANNEL IS UNCHANGED; recover with \`${remedy}\``,
19091
+ workflowRuns: [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: runStatus }],
19092
+ deployStatus: "failure"
19093
+ };
19094
+ }
19095
+ const expected = (deps.readLauncherVersion ?? readLocalLauncherVersion)();
19096
+ const runs = [...dispatch.workflowRuns ?? [], { ...runRow, conclusion: "success" }];
19097
+ if (!channelUrl) {
19098
+ return {
19099
+ ...dispatch,
19100
+ note: `${dispatch.note}; get-publish.yml succeeded but the channel URL could not be read from the product config \u2014 the move is unverified`,
19101
+ workflowRuns: runs
19102
+ };
19103
+ }
19104
+ const probe = await (deps.readServedChannelVersion ?? fetchServedChannelVersion)(channelUrl);
19105
+ if (!probe.ok) {
19106
+ const why = probe.error ?? `HTTP ${probe.status ?? "unknown"}`;
19107
+ return {
19108
+ ...dispatch,
19109
+ note: `${dispatch.note}; get-publish.yml succeeded but the served channel version could NOT be read at ${channelUrl} (${why}) \u2014 the move is unverified`,
19110
+ workflowRuns: runs
19111
+ };
19112
+ }
19113
+ if (expected && probe.version !== expected) {
19114
+ return {
19115
+ ...dispatch,
19116
+ note: `${dispatch.note}; get-publish.yml succeeded but the served channel still reports ${probe.version} (expected launcher ${expected}) \u2014 THE CHANNEL DID NOT MOVE; recover with \`${remedy}\``,
19117
+ workflowRuns: runs,
19118
+ deployStatus: "failure"
19119
+ };
19120
+ }
19121
+ return {
19122
+ ...dispatch,
19123
+ note: `${dispatch.note}; served channel moved \u2014 ${channelUrl} now reports ${probe.version}${expected ? "" : " (no local launcher version to compare against)"}`,
19124
+ workflowRuns: runs
19125
+ };
19126
+ }
19012
19127
  var JERV_GATEWAY_RUN_URL_NOTE = "no run URL emitted \u2014 host health leg runs outside GitHub Actions";
19013
19128
  async function appendJervGatewayReleaseDeploy(deps, repo, tag, tagSha, dispatch) {
19014
19129
  if (!isJervHubRepo(repo)) return dispatch;
@@ -19523,9 +19638,9 @@ function renderTenantControl(r) {
19523
19638
  }
19524
19639
 
19525
19640
  // src/train-apply-phases.ts
19526
- var import_node_fs23 = require("node:fs");
19641
+ var import_node_fs24 = require("node:fs");
19527
19642
  var import_promises3 = require("node:fs/promises");
19528
- var import_node_path23 = require("node:path");
19643
+ var import_node_path24 = require("node:path");
19529
19644
 
19530
19645
  // src/actions-billing-preflight.ts
19531
19646
  var CANARY_WORKFLOW = "actions-job-start-canary.yml";
@@ -19778,14 +19893,14 @@ Resume it: ${resumeCommand}
19778
19893
 
19779
19894
  // src/train-doctor.ts
19780
19895
  var import_node_child_process9 = require("node:child_process");
19781
- var import_node_fs22 = require("node:fs");
19896
+ var import_node_fs23 = require("node:fs");
19782
19897
  var import_node_os13 = require("node:os");
19783
- var import_node_path22 = require("node:path");
19898
+ var import_node_path23 = require("node:path");
19784
19899
 
19785
19900
  // src/doctor-io.ts
19786
- var import_node_fs19 = require("node:fs");
19901
+ var import_node_fs20 = require("node:fs");
19787
19902
  var import_node_os10 = require("node:os");
19788
- var import_node_path17 = require("node:path");
19903
+ var import_node_path18 = require("node:path");
19789
19904
  var import_node_child_process7 = require("node:child_process");
19790
19905
  var import_node_util4 = require("node:util");
19791
19906
 
@@ -19798,8 +19913,8 @@ function nodeDiscardSinkPath(platform2 = process.platform) {
19798
19913
  var execFileP2 = (0, import_node_util4.promisify)(import_node_child_process7.execFile);
19799
19914
  function execFileCapture(file, args, opts = {}) {
19800
19915
  const sink = nodeDiscardSinkPath();
19801
- const inFd = (0, import_node_fs19.openSync)(sink, "r");
19802
- const errFd = (0, import_node_fs19.openSync)(sink, "w");
19916
+ const inFd = (0, import_node_fs20.openSync)(sink, "r");
19917
+ const errFd = (0, import_node_fs20.openSync)(sink, "w");
19803
19918
  try {
19804
19919
  return (0, import_node_child_process7.execFileSync)(file, args, {
19805
19920
  ...opts,
@@ -19807,17 +19922,17 @@ function execFileCapture(file, args, opts = {}) {
19807
19922
  stdio: [inFd, "pipe", errFd]
19808
19923
  });
19809
19924
  } finally {
19810
- (0, import_node_fs19.closeSync)(inFd);
19811
- (0, import_node_fs19.closeSync)(errFd);
19925
+ (0, import_node_fs20.closeSync)(inFd);
19926
+ (0, import_node_fs20.closeSync)(errFd);
19812
19927
  }
19813
19928
  }
19814
19929
  var MMI_PLUGIN_ID2 = "mmi@mutmutco";
19815
19930
  function stagedClaudePluginVersion() {
19816
19931
  try {
19817
- const stagingRoot = (0, import_node_path17.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "staging");
19818
- const record = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(stagingRoot, "launch-target.json"), "utf8"));
19932
+ const stagingRoot = (0, import_node_path18.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "staging");
19933
+ const record = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(stagingRoot, "launch-target.json"), "utf8"));
19819
19934
  if (typeof record.target !== "string" || typeof record.incoming !== "string") return void 0;
19820
- const manifest = JSON.parse((0, import_node_fs19.readFileSync)((0, import_node_path17.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
19935
+ const manifest = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path18.join)(record.incoming, ".claude-plugin", "plugin.json"), "utf8"));
19821
19936
  if (typeof manifest.version !== "string") return void 0;
19822
19937
  return manifest.version === record.target ? record.target : void 0;
19823
19938
  } catch {
@@ -19827,7 +19942,7 @@ function stagedClaudePluginVersion() {
19827
19942
  function installedClaudePluginVersion() {
19828
19943
  try {
19829
19944
  const file = JSON.parse(
19830
- (0, import_node_fs19.readFileSync)((0, import_node_path17.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
19945
+ (0, import_node_fs20.readFileSync)((0, import_node_path18.join)((0, import_node_os10.homedir)(), ".claude", "plugins", "installed_plugins.json"), "utf8")
19831
19946
  );
19832
19947
  const versions = (file.plugins?.[MMI_PLUGIN_ID2] ?? []).map((r) => r.version).filter((v) => Boolean(v));
19833
19948
  if (versions.length === 0) return void 0;
@@ -19838,7 +19953,7 @@ function installedClaudePluginVersion() {
19838
19953
  }
19839
19954
  function manifestVersion(path2) {
19840
19955
  try {
19841
- const manifest = JSON.parse((0, import_node_fs19.readFileSync)(path2, "utf8"));
19956
+ const manifest = JSON.parse((0, import_node_fs20.readFileSync)(path2, "utf8"));
19842
19957
  return typeof manifest.version === "string" && manifest.version.trim() ? manifest.version.trim() : void 0;
19843
19958
  } catch {
19844
19959
  return void 0;
@@ -19847,12 +19962,12 @@ function manifestVersion(path2) {
19847
19962
  function readHermesPluginEvidence(env = process.env) {
19848
19963
  const host = hermesConfigRoot(env);
19849
19964
  const root = hermesPluginRoot(env);
19850
- const installRecordPresent = (0, import_node_fs19.existsSync)(root);
19851
- const manifestPath = (0, import_node_path17.join)(root, "plugin.yaml");
19965
+ const installRecordPresent = (0, import_node_fs20.existsSync)(root);
19966
+ const manifestPath = (0, import_node_path18.join)(root, "plugin.yaml");
19852
19967
  let installedVersion;
19853
19968
  let manifest = "missing";
19854
19969
  try {
19855
- const text = (0, import_node_fs19.readFileSync)(manifestPath, "utf8");
19970
+ const text = (0, import_node_fs20.readFileSync)(manifestPath, "utf8");
19856
19971
  let version;
19857
19972
  try {
19858
19973
  const parsed = JSON.parse(text).version;
@@ -19866,25 +19981,25 @@ function readHermesPluginEvidence(env = process.env) {
19866
19981
  if (version) {
19867
19982
  installedVersion = version;
19868
19983
  manifest = "valid";
19869
- } else if ((0, import_node_fs19.existsSync)(manifestPath)) manifest = "invalid";
19984
+ } else if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
19870
19985
  } catch {
19871
- if ((0, import_node_fs19.existsSync)(manifestPath)) manifest = "invalid";
19986
+ if ((0, import_node_fs20.existsSync)(manifestPath)) manifest = "invalid";
19872
19987
  }
19873
19988
  let skills = false;
19874
19989
  try {
19875
- skills = (0, import_node_fs19.existsSync)((0, import_node_path17.join)(root, "skills")) && (0, import_node_fs19.statSync)((0, import_node_path17.join)(root, "skills")).isDirectory();
19990
+ skills = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "skills")) && (0, import_node_fs20.statSync)((0, import_node_path18.join)(root, "skills")).isDirectory();
19876
19991
  } catch {
19877
19992
  }
19878
19993
  let provisioned = false;
19879
- const provisionedRoot = (0, import_node_path17.join)(host, "skills", "mmi");
19994
+ const provisionedRoot = (0, import_node_path18.join)(host, "skills", "mmi");
19880
19995
  try {
19881
- provisioned = (0, import_node_fs19.existsSync)(provisionedRoot) && (0, import_node_fs19.statSync)(provisionedRoot).isDirectory();
19996
+ provisioned = (0, import_node_fs20.existsSync)(provisionedRoot) && (0, import_node_fs20.statSync)(provisionedRoot).isDirectory();
19882
19997
  } catch {
19883
19998
  }
19884
- const treeOk = (0, import_node_fs19.existsSync)((0, import_node_path17.join)(root, "__init__.py")) && skills && manifest === "valid";
19999
+ const treeOk = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, "__init__.py")) && skills && manifest === "valid";
19885
20000
  const receipt = treeOk && !provisioned ? `hermes-skills-unprovisioned:${provisionedRoot}` : void 0;
19886
20001
  return {
19887
- hostPresent: (0, import_node_fs19.existsSync)(host),
20002
+ hostPresent: (0, import_node_fs20.existsSync)(host),
19888
20003
  installRecordPresent,
19889
20004
  manifest,
19890
20005
  payloadPresent: treeOk && provisioned,
@@ -19896,7 +20011,7 @@ function installedSurfacePluginVersion(surface) {
19896
20011
  const token = surfaceToken(surface);
19897
20012
  if (token === "hermes") return readHermesPluginEvidence().installedVersion;
19898
20013
  if (token === "cursor") {
19899
- return manifestVersion((0, import_node_path17.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
20014
+ return manifestVersion((0, import_node_path18.join)(cursorLocalPluginRoot(), ".cursor-plugin", "plugin.json"));
19900
20015
  }
19901
20016
  if (token === "jervcode") {
19902
20017
  return installedJervCodePackageVersion();
@@ -19933,13 +20048,13 @@ function worktreeRootSync() {
19933
20048
  }
19934
20049
  var gitignorePath = () => {
19935
20050
  const root = worktreeRootSync();
19936
- return root === null ? null : (0, import_node_path17.join)(root, ".gitignore");
20051
+ return root === null ? null : (0, import_node_path18.join)(root, ".gitignore");
19937
20052
  };
19938
20053
  function readGitignore() {
19939
20054
  const path2 = gitignorePath();
19940
20055
  if (path2 === null) return null;
19941
20056
  try {
19942
- return (0, import_node_fs19.readFileSync)(path2, "utf8");
20057
+ return (0, import_node_fs20.readFileSync)(path2, "utf8");
19943
20058
  } catch {
19944
20059
  return null;
19945
20060
  }
@@ -19948,14 +20063,14 @@ function writeGitignore(content) {
19948
20063
  const path2 = gitignorePath();
19949
20064
  if (path2 === null) return false;
19950
20065
  try {
19951
- (0, import_node_fs19.writeFileSync)(path2, content, "utf8");
20066
+ (0, import_node_fs20.writeFileSync)(path2, content, "utf8");
19952
20067
  return true;
19953
20068
  } catch {
19954
20069
  return false;
19955
20070
  }
19956
20071
  }
19957
20072
  function lineEndingState(root) {
19958
- const attributesPresent = (0, import_node_fs19.existsSync)((0, import_node_path17.join)(root, ".gitattributes"));
20073
+ const attributesPresent = (0, import_node_fs20.existsSync)((0, import_node_path18.join)(root, ".gitattributes"));
19959
20074
  try {
19960
20075
  const output = execFileCapture("git", ["-C", root, "ls-files", "--eol", "--", ":(glob)**/*.sh"], {
19961
20076
  windowsHide: true
@@ -19998,18 +20113,18 @@ function compatHolds(range, version) {
19998
20113
  }
19999
20114
 
20000
20115
  // src/claude-binary-doctor.ts
20001
- var import_node_fs20 = require("node:fs");
20116
+ var import_node_fs21 = require("node:fs");
20002
20117
  var import_node_os12 = require("node:os");
20003
- var import_node_path19 = require("node:path");
20118
+ var import_node_path20 = require("node:path");
20004
20119
 
20005
20120
  // src/jerv-cli-spawn.ts
20006
20121
  var import_node_os11 = require("node:os");
20007
- var import_node_path18 = require("node:path");
20122
+ var import_node_path19 = require("node:path");
20008
20123
  init_cli_shared();
20009
- var JERV_CLI_ENTRY = (0, import_node_path18.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
20124
+ var JERV_CLI_ENTRY = (0, import_node_path19.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
20010
20125
  function pathEnvEntries(pathEnv, platform2 = process.platform) {
20011
20126
  if (platform2 !== "win32") {
20012
- return pathEnv.split(import_node_path18.delimiter).map((e) => e.trim()).filter(Boolean);
20127
+ return pathEnv.split(import_node_path19.delimiter).map((e) => e.trim()).filter(Boolean);
20013
20128
  }
20014
20129
  if (pathEnv.includes(";")) {
20015
20130
  return pathEnv.split(";").map((e) => e.trim()).filter(Boolean);
@@ -20042,10 +20157,10 @@ function jervCliCandidateDirs(env = process.env, home = (0, import_node_os11.hom
20042
20157
  push(normalizeSpawnPathEntry(entry, platform2));
20043
20158
  }
20044
20159
  if (platform2 === "win32") {
20045
- if (env.APPDATA) push((0, import_node_path18.join)(env.APPDATA, "npm"));
20046
- if (env.LOCALAPPDATA) push((0, import_node_path18.join)(env.LOCALAPPDATA, "npm"));
20160
+ if (env.APPDATA) push((0, import_node_path19.join)(env.APPDATA, "npm"));
20161
+ if (env.LOCALAPPDATA) push((0, import_node_path19.join)(env.LOCALAPPDATA, "npm"));
20047
20162
  } else {
20048
- push((0, import_node_path18.join)(home, ".local", "bin"));
20163
+ push((0, import_node_path19.join)(home, ".local", "bin"));
20049
20164
  }
20050
20165
  return out;
20051
20166
  }
@@ -20098,26 +20213,26 @@ function globalNodeModulesRoots(host) {
20098
20213
  out.push(dir);
20099
20214
  };
20100
20215
  const prefix = env.npm_config_prefix?.trim();
20101
- if (prefix) push(platform2 === "win32" ? (0, import_node_path19.join)(prefix, "node_modules") : (0, import_node_path19.join)(prefix, "lib", "node_modules"));
20216
+ if (prefix) push(platform2 === "win32" ? (0, import_node_path20.join)(prefix, "node_modules") : (0, import_node_path20.join)(prefix, "lib", "node_modules"));
20102
20217
  for (const dir of jervCliCandidateDirs(env, host.home ?? (0, import_node_os12.homedir)(), platform2)) {
20103
- push((0, import_node_path19.join)(dir, "node_modules"));
20104
- push((0, import_node_path19.join)((0, import_node_path19.dirname)(dir), "lib", "node_modules"));
20218
+ push((0, import_node_path20.join)(dir, "node_modules"));
20219
+ push((0, import_node_path20.join)((0, import_node_path20.dirname)(dir), "lib", "node_modules"));
20105
20220
  }
20106
20221
  return out;
20107
20222
  }
20108
20223
  function readHead(path2) {
20109
20224
  let fd;
20110
20225
  try {
20111
- fd = (0, import_node_fs20.openSync)(path2, "r");
20226
+ fd = (0, import_node_fs21.openSync)(path2, "r");
20112
20227
  const buffer = new Uint8Array(MAGIC_HEAD_BYTES);
20113
- const read = (0, import_node_fs20.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
20228
+ const read = (0, import_node_fs21.readSync)(fd, buffer, 0, MAGIC_HEAD_BYTES, 0);
20114
20229
  return buffer.subarray(0, read);
20115
20230
  } catch {
20116
20231
  return void 0;
20117
20232
  } finally {
20118
20233
  if (fd !== void 0) {
20119
20234
  try {
20120
- (0, import_node_fs20.closeSync)(fd);
20235
+ (0, import_node_fs21.closeSync)(fd);
20121
20236
  } catch {
20122
20237
  }
20123
20238
  }
@@ -20125,7 +20240,7 @@ function readHead(path2) {
20125
20240
  }
20126
20241
  function fileBytes(path2) {
20127
20242
  try {
20128
- return (0, import_node_fs20.statSync)(path2).size;
20243
+ return (0, import_node_fs21.statSync)(path2).size;
20129
20244
  } catch {
20130
20245
  return void 0;
20131
20246
  }
@@ -20139,17 +20254,17 @@ function readClaudeBinaryState(host = {}) {
20139
20254
  const arch = host.arch ?? process.arch;
20140
20255
  const magic = EXECUTABLE_MAGIC[platform2];
20141
20256
  if (!magic) return void 0;
20142
- const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path19.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs20.existsSync)((0, import_node_path19.join)(dir, "package.json")));
20257
+ const packageRoot = globalNodeModulesRoots(host).map((root) => (0, import_node_path20.join)(root, ...PACKAGE.split("/"))).find((dir) => (0, import_node_fs21.existsSync)((0, import_node_path20.join)(dir, "package.json")));
20143
20258
  if (!packageRoot) return void 0;
20144
20259
  const keys = platformPackageKeys(platform2, arch);
20145
20260
  const fallbackPackage = `${PACKAGE}-${keys[0]}`;
20146
20261
  let manifest;
20147
20262
  try {
20148
- manifest = JSON.parse((0, import_node_fs20.readFileSync)((0, import_node_path19.join)(packageRoot, "package.json"), "utf8"));
20263
+ manifest = JSON.parse((0, import_node_fs21.readFileSync)((0, import_node_path20.join)(packageRoot, "package.json"), "utf8"));
20149
20264
  } catch (e) {
20150
20265
  return {
20151
20266
  state: "unreadable",
20152
- binPath: (0, import_node_path19.join)(packageRoot, "package.json"),
20267
+ binPath: (0, import_node_path20.join)(packageRoot, "package.json"),
20153
20268
  expectedMagic: magic.name,
20154
20269
  platformPackage: fallbackPackage,
20155
20270
  error: `package.json could not be read \u2014 ${e.message}`
@@ -20166,17 +20281,17 @@ function readClaudeBinaryState(host = {}) {
20166
20281
  error: "package.json declares no `bin` entry \u2014 the executed file cannot be resolved"
20167
20282
  };
20168
20283
  }
20169
- const binPath = (0, import_node_path19.join)(packageRoot, binRelative);
20170
- const binName = (0, import_node_path19.basename)(binRelative);
20284
+ const binPath = (0, import_node_path20.join)(packageRoot, binRelative);
20285
+ const binName = (0, import_node_path20.basename)(binRelative);
20171
20286
  const optional = manifest.optionalDependencies;
20172
20287
  const publishes = (name) => typeof optional === "object" && optional !== null && Object.prototype.hasOwnProperty.call(optional, name);
20173
20288
  const published = keys.map((key) => `${PACKAGE}-${key}`).filter(publishes);
20174
20289
  if (published.length === 0) return void 0;
20175
20290
  const binIn = (name) => [
20176
- (0, import_node_path19.join)(packageRoot, "node_modules", ...name.split("/"), binName),
20177
- (0, import_node_path19.join)((0, import_node_path19.dirname)((0, import_node_path19.dirname)(packageRoot)), ...name.split("/"), binName)
20291
+ (0, import_node_path20.join)(packageRoot, "node_modules", ...name.split("/"), binName),
20292
+ (0, import_node_path20.join)((0, import_node_path20.dirname)((0, import_node_path20.dirname)(packageRoot)), ...name.split("/"), binName)
20178
20293
  ];
20179
- const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs20.existsSync)(file)) })).find((c) => c.path);
20294
+ const found = published.map((name) => ({ name, path: binIn(name).find((file) => (0, import_node_fs21.existsSync)(file)) })).find((c) => c.path);
20180
20295
  const platformPackage = found?.name ?? published[0];
20181
20296
  let source;
20182
20297
  let sourceProblem;
@@ -20187,7 +20302,7 @@ function readClaudeBinaryState(host = {}) {
20187
20302
  } else {
20188
20303
  source = { path: found.path, bytes: fileBytes(found.path) ?? 0 };
20189
20304
  }
20190
- if (!(0, import_node_fs20.existsSync)(binPath)) {
20305
+ if (!(0, import_node_fs21.existsSync)(binPath)) {
20191
20306
  return { state: "missing", binPath, expectedMagic: magic.name, platformPackage, ...source ? { source } : {}, ...sourceProblem ? { sourceProblem } : {} };
20192
20307
  }
20193
20308
  const head = readHead(binPath);
@@ -20230,9 +20345,9 @@ function healClaudeBinary(host = {}, onStep) {
20230
20345
  const platform2 = host.platform ?? process.platform;
20231
20346
  const aside = `${probe.binPath}.stub-${Date.now()}`;
20232
20347
  let renamed = false;
20233
- if ((0, import_node_fs20.existsSync)(probe.binPath)) {
20348
+ if ((0, import_node_fs21.existsSync)(probe.binPath)) {
20234
20349
  try {
20235
- (0, import_node_fs20.renameSync)(probe.binPath, aside);
20350
+ (0, import_node_fs21.renameSync)(probe.binPath, aside);
20236
20351
  renamed = true;
20237
20352
  onStep?.(`renamed the stub aside: ${aside}`);
20238
20353
  } catch (e) {
@@ -20241,12 +20356,12 @@ function healClaudeBinary(host = {}, onStep) {
20241
20356
  }
20242
20357
  try {
20243
20358
  onStep?.(`copying ${probe.source.path} \u2192 ${probe.binPath} (${(probe.source.bytes / 1e6).toFixed(0)} MB)`);
20244
- (0, import_node_fs20.copyFileSync)(probe.source.path, probe.binPath);
20245
- if (platform2 !== "win32") (0, import_node_fs20.chmodSync)(probe.binPath, 493);
20359
+ (0, import_node_fs21.copyFileSync)(probe.source.path, probe.binPath);
20360
+ if (platform2 !== "win32") (0, import_node_fs21.chmodSync)(probe.binPath, 493);
20246
20361
  } catch (e) {
20247
20362
  if (renamed) {
20248
20363
  try {
20249
- (0, import_node_fs20.renameSync)(aside, probe.binPath);
20364
+ (0, import_node_fs21.renameSync)(aside, probe.binPath);
20250
20365
  } catch {
20251
20366
  return { ok: false, detail: `copy failed (${e.message}) and the stub could not be restored \u2014 the original is at ${aside}` };
20252
20367
  }
@@ -20260,7 +20375,7 @@ function healClaudeBinary(host = {}, onStep) {
20260
20375
  let kept = false;
20261
20376
  if (renamed) {
20262
20377
  try {
20263
- (0, import_node_fs20.rmSync)(aside);
20378
+ (0, import_node_fs21.rmSync)(aside);
20264
20379
  } catch {
20265
20380
  kept = true;
20266
20381
  }
@@ -20619,13 +20734,13 @@ function checkLineEndings(probe) {
20619
20734
  }
20620
20735
 
20621
20736
  // src/release-ledger.ts
20622
- var import_node_fs21 = require("node:fs");
20623
- var import_node_path21 = require("node:path");
20737
+ var import_node_fs22 = require("node:fs");
20738
+ var import_node_path22 = require("node:path");
20624
20739
  var import_node_crypto5 = require("node:crypto");
20625
20740
 
20626
20741
  // src/file-lock.ts
20627
20742
  var import_promises2 = require("node:fs/promises");
20628
- var import_node_path20 = require("node:path");
20743
+ var import_node_path21 = require("node:path");
20629
20744
  var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
20630
20745
  var IMMEDIATE_RETRY_BUDGET = 3;
20631
20746
  var FileLockBusyError = class extends Error {
@@ -20710,7 +20825,7 @@ async function releaseFileLock(lockPath, guard) {
20710
20825
  }
20711
20826
  async function withFileLock(lockPath, opts, fn) {
20712
20827
  const resolved = resolveFileLockOpts(opts);
20713
- await (0, import_promises2.mkdir)((0, import_node_path20.dirname)(lockPath), { recursive: true }).catch(() => void 0);
20828
+ await (0, import_promises2.mkdir)((0, import_node_path21.dirname)(lockPath), { recursive: true }).catch(() => void 0);
20714
20829
  const guard = await acquireFileLock(lockPath, resolved, Date.now() + resolved.maxWaitMs);
20715
20830
  try {
20716
20831
  return await fn();
@@ -20879,37 +20994,37 @@ function resolvePrimaryGitDir(cwd) {
20879
20994
  }
20880
20995
  let common;
20881
20996
  try {
20882
- common = (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(gitDir, "commondir"), "utf8").trim();
20997
+ common = (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(gitDir, "commondir"), "utf8").trim();
20883
20998
  } catch (e) {
20884
20999
  if (e.code !== "ENOENT") {
20885
21000
  throw new ReleaseLedgerError("unreadable", `release ledger: the worktree gitdir's commondir pointer could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not primary (#5987/#4713)`);
20886
21001
  }
20887
21002
  }
20888
21003
  if (!common) return gitDir;
20889
- const commonDir = (0, import_node_path21.isAbsolute)(common) ? common : (0, import_node_path21.resolve)(gitDir, common);
21004
+ const commonDir = (0, import_node_path22.isAbsolute)(common) ? common : (0, import_node_path22.resolve)(gitDir, common);
20890
21005
  try {
20891
- (0, import_node_fs21.readFileSync)((0, import_node_path21.join)(commonDir, "HEAD"), "utf8");
21006
+ (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(commonDir, "HEAD"), "utf8");
20892
21007
  } catch (e) {
20893
21008
  throw new ReleaseLedgerError("no-checkout", `release ledger: the worktree's commondir pointer names ${commonDir}, which has no readable HEAD (${e instanceof Error ? e.message : String(e)}) \u2014 the primary checkout may have been removed; refusing to write the ledger into a doomed location`);
20894
21009
  }
20895
21010
  return commonDir;
20896
21011
  }
20897
21012
  function releaseLedgerPath(cwd) {
20898
- return (0, import_node_path21.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
21013
+ return (0, import_node_path22.join)(resolvePrimaryGitDir(cwd), "mmi-runtime", "release", "phases.json");
20899
21014
  }
20900
21015
  function atomicWriteJson(path2, ledger) {
20901
- (0, import_node_fs21.mkdirSync)((0, import_node_path21.dirname)(path2), { recursive: true });
21016
+ (0, import_node_fs22.mkdirSync)((0, import_node_path22.dirname)(path2), { recursive: true });
20902
21017
  const tmp = `${path2}.tmp-${process.pid}-${(0, import_node_crypto5.randomBytes)(4).toString("hex")}`;
20903
- (0, import_node_fs21.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
21018
+ (0, import_node_fs22.writeFileSync)(tmp, `${JSON.stringify(ledger, null, 2)}
20904
21019
  `, "utf8");
20905
- (0, import_node_fs21.renameSync)(tmp, path2);
21020
+ (0, import_node_fs22.renameSync)(tmp, path2);
20906
21021
  }
20907
21022
  async function withReleaseLedger(path2, expected, fn, opts = {}) {
20908
21023
  return withFileLock(`${path2}.lock`, { label: "release ledger", maxWaitMs: opts.maxWaitMs ?? 5e3 }, async () => {
20909
21024
  let current;
20910
21025
  let raw;
20911
21026
  try {
20912
- raw = (0, import_node_fs21.readFileSync)(path2, "utf8");
21027
+ raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
20913
21028
  } catch (e) {
20914
21029
  if (e.code !== "ENOENT") {
20915
21030
  throw new ReleaseLedgerError("unreadable", `release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987)`);
@@ -21543,7 +21658,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
21543
21658
  return withFileLock(`${path2}.lock`, { label: "release ledger", maxWaitMs }, async () => {
21544
21659
  let raw;
21545
21660
  try {
21546
- raw = (0, import_node_fs21.readFileSync)(path2, "utf8");
21661
+ raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
21547
21662
  } catch (e) {
21548
21663
  if (e.code === "ENOENT") return { cleared: false };
21549
21664
  return { cleared: false, note: `release ledger at ${path2} could not be read for clearing (${e instanceof Error ? e.message : String(e)}) \u2014 left in place` };
@@ -21559,7 +21674,7 @@ async function clearLedgerFile(path2, anchors, maxWaitMs) {
21559
21674
  } catch (e) {
21560
21675
  return { cleared: false, note: `release ledger at ${path2} belongs to ${ledger.tag} @ ${ledger.tagSha.slice(0, 12)} \u2014 not this release; left in place (${e instanceof Error ? e.message : String(e)})` };
21561
21676
  }
21562
- (0, import_node_fs21.unlinkSync)(path2);
21677
+ (0, import_node_fs22.unlinkSync)(path2);
21563
21678
  return { cleared: true, note: `cleared the release ledger at ${path2} for the live-proven aborted ${anchors.tag}` };
21564
21679
  });
21565
21680
  }
@@ -21662,7 +21777,7 @@ async function healStaleAlignmentLeg(deps, cwd, expected) {
21662
21777
  return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
21663
21778
  let prior;
21664
21779
  try {
21665
- prior = parseReleaseLedger((0, import_node_fs21.readFileSync)(path2, "utf8"));
21780
+ prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
21666
21781
  } catch {
21667
21782
  return void 0;
21668
21783
  }
@@ -21687,7 +21802,7 @@ async function supersedeContentCausedDeployLeg(deps, cwd) {
21687
21802
  return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
21688
21803
  let prior;
21689
21804
  try {
21690
- prior = parseReleaseLedger((0, import_node_fs21.readFileSync)(path2, "utf8"));
21805
+ prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
21691
21806
  } catch (e) {
21692
21807
  throw new ReleaseLedgerError(
21693
21808
  "unreadable",
@@ -21783,11 +21898,11 @@ async function proveOriginPromotionOrArchived(deps, prior, path2, label, ref) {
21783
21898
  if (!releaseAbsent) {
21784
21899
  throw new Error(`${label}: origin no longer has ${prior.tag} but its GitHub Release still exists \u2014 resolve the mixed external state before closing the ledger; nothing was written (${ref})`);
21785
21900
  }
21786
- const archivePath = (0, import_node_path21.join)((0, import_node_path21.dirname)(path2), `phases.archive-${prior.tag}.json`);
21787
- if ((0, import_node_fs21.existsSync)(archivePath)) {
21901
+ const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
21902
+ if ((0, import_node_fs22.existsSync)(archivePath)) {
21788
21903
  throw new Error(`${label}: archive already exists at ${archivePath} \u2014 preserving both ledger records; resolve the collision by hand; nothing was written (${ref})`);
21789
21904
  }
21790
- (0, import_node_fs21.renameSync)(path2, archivePath);
21905
+ (0, import_node_fs22.renameSync)(path2, archivePath);
21791
21906
  return "deleted";
21792
21907
  }
21793
21908
  async function supersedeContentCausedPublishLeg(deps, cwd) {
@@ -21795,7 +21910,7 @@ async function supersedeContentCausedPublishLeg(deps, cwd) {
21795
21910
  return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
21796
21911
  let prior;
21797
21912
  try {
21798
- prior = parseReleaseLedger((0, import_node_fs21.readFileSync)(path2, "utf8"));
21913
+ prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
21799
21914
  } catch (e) {
21800
21915
  throw new ReleaseLedgerError(
21801
21916
  "unreadable",
@@ -21877,7 +21992,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
21877
21992
  return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
21878
21993
  let prior;
21879
21994
  try {
21880
- prior = parseReleaseLedger((0, import_node_fs21.readFileSync)(path2, "utf8"));
21995
+ prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
21881
21996
  } catch (e) {
21882
21997
  throw new ReleaseLedgerError(
21883
21998
  "unreadable",
@@ -21982,7 +22097,7 @@ async function supersedeContentCausedDeployAndPublishLegs(deps, cwd) {
21982
22097
  async function reverifyPriorRunLegs(deps, path2, targetTag) {
21983
22098
  let prior;
21984
22099
  try {
21985
- prior = parseReleaseLedger((0, import_node_fs21.readFileSync)(path2, "utf8"));
22100
+ prior = parseReleaseLedger((0, import_node_fs22.readFileSync)(path2, "utf8"));
21986
22101
  } catch {
21987
22102
  return;
21988
22103
  }
@@ -22002,7 +22117,7 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
22002
22117
  return withFileLock(`${path2}.lock`, { label: "release ledger" }, async () => {
22003
22118
  let raw;
22004
22119
  try {
22005
- raw = (0, import_node_fs21.readFileSync)(path2, "utf8");
22120
+ raw = (0, import_node_fs22.readFileSync)(path2, "utf8");
22006
22121
  } catch (e) {
22007
22122
  if (e.code === "ENOENT") return { ok: true };
22008
22123
  return { ok: false, error: `the release ledger at ${path2} could not be READ (${e instanceof Error ? e.message : String(e)}) \u2014 a failed read is unverified, not absent (#5987/#4713)` };
@@ -22039,15 +22154,15 @@ async function beginReleaseLedger(deps, cwd, targetTag) {
22039
22154
  if (liveSha.toLowerCase() !== prior.tagSha.toLowerCase()) {
22040
22155
  return { ok: false, error: `the completed ${prior.tag} ledger says phases-green but origin reports ${liveSha.slice(0, 12) || "no tag"} \u2260 ${prior.tagSha.slice(0, 12)} \u2014 refusing to archive on unproven state; resolve by hand (#5987)` };
22041
22156
  }
22042
- const archivePath = (0, import_node_path21.join)((0, import_node_path21.dirname)(path2), `phases.archive-${prior.tag}.json`);
22157
+ const archivePath = (0, import_node_path22.join)((0, import_node_path22.dirname)(path2), `phases.archive-${prior.tag}.json`);
22043
22158
  try {
22044
- (0, import_node_fs21.unlinkSync)(archivePath);
22159
+ (0, import_node_fs22.unlinkSync)(archivePath);
22045
22160
  } catch (e) {
22046
22161
  if (e.code !== "ENOENT") {
22047
22162
  return { ok: false, error: `could not clear the stale archive at ${archivePath} (${e instanceof Error ? e.message : String(e)}) \u2014 the ledger for ${prior.tag} stays active (#5987)` };
22048
22163
  }
22049
22164
  }
22050
- (0, import_node_fs21.renameSync)(path2, archivePath);
22165
+ (0, import_node_fs22.renameSync)(path2, archivePath);
22051
22166
  return { ok: true, note: `archived the completed release ledger ${prior.tag} to ${archivePath} (live-proven at ${prior.tagSha.slice(0, 12)})` };
22052
22167
  });
22053
22168
  }
@@ -22148,10 +22263,10 @@ function readOriginWorkflowsDefault(root, ref) {
22148
22263
  }
22149
22264
  var NPM_REGISTRY = "https://registry.npmjs.org";
22150
22265
  async function probeRegistryWhoami(train) {
22151
- const dir = (0, import_node_fs22.mkdtempSync)((0, import_node_path22.join)((0, import_node_os13.tmpdir)(), "mmi-npmrc-"));
22152
- const rc = (0, import_node_path22.join)(dir, "npmrc");
22266
+ const dir = (0, import_node_fs23.mkdtempSync)((0, import_node_path23.join)((0, import_node_os13.tmpdir)(), "mmi-npmrc-"));
22267
+ const rc = (0, import_node_path23.join)(dir, "npmrc");
22153
22268
  try {
22154
- (0, import_node_fs22.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
22269
+ (0, import_node_fs23.writeFileSync)(rc, "//registry.npmjs.org/:_authToken=${NPM_TOKEN}\n");
22155
22270
  await train.runSelf(["secrets", "use", "npm/NPM_TOKEN", "--slug", "_org", "--", "npm", "whoami", "--registry", NPM_REGISTRY, "--userconfig", rc]);
22156
22271
  return { kind: "ok", detail: "the registry answered a login" };
22157
22272
  } catch (e) {
@@ -22162,7 +22277,7 @@ async function probeRegistryWhoami(train) {
22162
22277
  if (/\bE401\b|401 Unauthorized/.test(stderr)) return { kind: "rejected", detail: "npm whoami answered 401 Unauthorized" };
22163
22278
  return { kind: "unverified", detail: first };
22164
22279
  } finally {
22165
- (0, import_node_fs22.rmSync)(dir, { recursive: true, force: true });
22280
+ (0, import_node_fs23.rmSync)(dir, { recursive: true, force: true });
22166
22281
  }
22167
22282
  }
22168
22283
  var REGISTRY_TOKEN_ENV = /\b(NODE_AUTH_TOKEN|NPM_TOKEN)\b/;
@@ -22180,7 +22295,7 @@ var defaultDeps2 = {
22180
22295
  ledgerPath: releaseLedgerPath,
22181
22296
  readLedgerRaw: (path2) => {
22182
22297
  try {
22183
- return (0, import_node_fs22.readFileSync)(path2, "utf8");
22298
+ return (0, import_node_fs23.readFileSync)(path2, "utf8");
22184
22299
  } catch (e) {
22185
22300
  if (e.code === "ENOENT") return void 0;
22186
22301
  throw e;
@@ -22189,7 +22304,7 @@ var defaultDeps2 = {
22189
22304
  healAlignmentLeg: healStaleAlignmentLeg,
22190
22305
  readSurfacesRaw: (cwd) => {
22191
22306
  try {
22192
- return (0, import_node_fs22.readFileSync)((0, import_node_path22.join)(cwd, "surfaces.json"), "utf8");
22307
+ return (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(cwd, "surfaces.json"), "utf8");
22193
22308
  } catch {
22194
22309
  return void 0;
22195
22310
  }
@@ -22594,6 +22709,53 @@ async function runTrainDoctor(input) {
22594
22709
  regenerate the projections (\`node scripts/check-skill-payload.mjs\`) and commit the canonical fix; never hand-edit a projection` });
22595
22710
  }
22596
22711
  }
22712
+ if (isHubControlRepo(repo)) {
22713
+ const verifyDeps = async () => {
22714
+ try {
22715
+ await train.run("node", [`${cwd}/scripts/release-distribution.mjs`, "verify-deps"]);
22716
+ return null;
22717
+ } catch (e) {
22718
+ return message(e);
22719
+ }
22720
+ };
22721
+ const failure = await verifyDeps();
22722
+ if (failure) {
22723
+ const firstDir = /in (cli|updater)\/node_modules/u.exec(failure)?.[1] ?? null;
22724
+ if (!heal || !firstDir) {
22725
+ add({
22726
+ code: "hub-build-deps",
22727
+ severity: "blocker",
22728
+ source: "local",
22729
+ title: `the Hub distribution build dependencies do not resolve${firstDir ? ` in ${firstDir}/node_modules` : ""} \u2014 the release refuses at preflight`,
22730
+ remedy: firstDir ? `run \`mmi-cli devops train doctor --heal\` (installs ${firstDir} from its lockfile), or \`npm --prefix ${firstDir} ci\`` : "run `npm --prefix cli ci` and `npm --prefix updater ci`, then rerun"
22731
+ });
22732
+ } else {
22733
+ const installed = [];
22734
+ let pending = firstDir;
22735
+ let outstanding = failure;
22736
+ let failed = null;
22737
+ while (pending && !installed.includes(pending)) {
22738
+ const dir = pending;
22739
+ try {
22740
+ await train.run("npm", ["--prefix", dir, "ci"]);
22741
+ } catch (e) {
22742
+ failed = { dir, detail: `\`npm --prefix ${dir} ci\` failed: ${message(e)}` };
22743
+ break;
22744
+ }
22745
+ installed.push(dir);
22746
+ outstanding = await verifyDeps();
22747
+ pending = outstanding ? /in (cli|updater)\/node_modules/u.exec(outstanding)?.[1] ?? null : null;
22748
+ }
22749
+ if (failed) {
22750
+ add({ code: "hub-build-deps", severity: "blocker", source: "local", title: failed.detail, remedy: `repair ${failed.dir}/node_modules by hand, then rerun` });
22751
+ } else if (outstanding) {
22752
+ add({ code: "hub-build-deps", severity: "blocker", source: "local", title: `installing ${installed.join(", ")} from ${installed.length === 1 ? "its lockfile" : "their lockfiles"} did not resolve the build dependencies`, remedy: outstanding });
22753
+ } else {
22754
+ add({ code: "hub-build-deps", severity: "healed", source: "local", title: `installed ${installed.join(", ")} from ${installed.length === 1 ? "its lockfile" : "their lockfiles"} \u2014 the Hub distribution build dependencies resolve`, remedy: "nothing \u2014 the release preflight passes" });
22755
+ }
22756
+ }
22757
+ }
22758
+ }
22597
22759
  const branches = TRAIN_BRANCHES.filter((b) => b !== "rc" || track === "full");
22598
22760
  if (heal) {
22599
22761
  const sync = await syncLocalTrainBranches(train.run, { branches, fetch: false });
@@ -22689,34 +22851,34 @@ function formatTrainDoctor(v) {
22689
22851
  // src/train-apply-phases.ts
22690
22852
  var TRAIN_BUMP_INTENTS = ["major", "minor", "patch"];
22691
22853
  function readLocalGateWorkflows() {
22692
- const dir = (0, import_node_path23.join)(".github", "workflows");
22854
+ const dir = (0, import_node_path24.join)(".github", "workflows");
22693
22855
  let names;
22694
22856
  try {
22695
- names = (0, import_node_fs23.readdirSync)(dir);
22857
+ names = (0, import_node_fs24.readdirSync)(dir);
22696
22858
  } catch {
22697
22859
  return null;
22698
22860
  }
22699
22861
  const files = [];
22700
22862
  for (const name of names.filter(isGateWorkflowPath)) {
22701
22863
  try {
22702
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(dir, name), "utf8") });
22864
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
22703
22865
  } catch {
22704
22866
  }
22705
22867
  }
22706
22868
  return files;
22707
22869
  }
22708
22870
  function readLocalWorkflows() {
22709
- const dir = (0, import_node_path23.join)(".github", "workflows");
22871
+ const dir = (0, import_node_path24.join)(".github", "workflows");
22710
22872
  let names;
22711
22873
  try {
22712
- names = (0, import_node_fs23.readdirSync)(dir);
22874
+ names = (0, import_node_fs24.readdirSync)(dir);
22713
22875
  } catch {
22714
22876
  return null;
22715
22877
  }
22716
22878
  const files = [];
22717
22879
  for (const name of names.filter((n) => /\.ya?ml$/i.test(n))) {
22718
22880
  try {
22719
- files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs23.readFileSync)((0, import_node_path23.join)(dir, name), "utf8") });
22881
+ files.push({ path: `${dir}/${name}`.replace(/\\/g, "/"), body: (0, import_node_fs24.readFileSync)((0, import_node_path24.join)(dir, name), "utf8") });
22720
22882
  } catch {
22721
22883
  }
22722
22884
  }
@@ -23506,6 +23668,11 @@ ${recovery.note}`), recoveryInput);
23506
23668
  });
23507
23669
  let dispatch = appendPublishDispatch(deployDispatch, publishDispatch);
23508
23670
  if (publishSkipNote) dispatch = { ...dispatch, note: `${dispatch.note}; tenant-publish.yml skipped (${publishSkipNote})` };
23671
+ dispatch = await appendServedChannelPublish(
23672
+ deps,
23673
+ { repo: ctx.repo, publishStatus: publishLeg.state === "complete" ? "success" : "failure", watch },
23674
+ dispatch
23675
+ );
23509
23676
  const announcing = announceShippedRelease(
23510
23677
  deps,
23511
23678
  { repo: ctx.repo, tag, summaryFile: options.announceSummaryFile },
@@ -23562,7 +23729,7 @@ async function activeRcandLedgerCandidate(deps, cwd) {
23562
23729
  }
23563
23730
  let prior;
23564
23731
  try {
23565
- prior = parseReleaseLedger((0, import_node_fs23.readFileSync)(path2, "utf8"));
23732
+ prior = parseReleaseLedger((0, import_node_fs24.readFileSync)(path2, "utf8"));
23566
23733
  } catch {
23567
23734
  return void 0;
23568
23735
  }
@@ -26988,9 +27155,9 @@ function registerBoardCommands(program3) {
26988
27155
  }
26989
27156
 
26990
27157
  // src/bootstrap-commands.ts
26991
- var import_node_fs25 = require("node:fs");
27158
+ var import_node_fs26 = require("node:fs");
26992
27159
  var import_node_os14 = require("node:os");
26993
- var import_node_path25 = require("node:path");
27160
+ var import_node_path26 = require("node:path");
26994
27161
  init_cli_shared();
26995
27162
  init_clean_exit();
26996
27163
 
@@ -27170,8 +27337,8 @@ init_github_client();
27170
27337
  init_cli_shared();
27171
27338
 
27172
27339
  // src/port-registry.ts
27173
- var import_node_fs24 = require("node:fs");
27174
- var import_node_path24 = require("node:path");
27340
+ var import_node_fs25 = require("node:fs");
27341
+ var import_node_path25 = require("node:path");
27175
27342
 
27176
27343
  // ../infra/port-geometry.mjs
27177
27344
  var PORT_BLOCK = 100;
@@ -27185,8 +27352,8 @@ function nextPortBlock(registry2) {
27185
27352
  return [base, base + PORT_SPAN];
27186
27353
  }
27187
27354
  function loadPortRegistry(path2) {
27188
- if (!(0, import_node_fs24.existsSync)(path2)) return {};
27189
- const raw = JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8"));
27355
+ if (!(0, import_node_fs25.existsSync)(path2)) return {};
27356
+ const raw = JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8"));
27190
27357
  const out = {};
27191
27358
  for (const [key, value] of Object.entries(raw)) {
27192
27359
  if (Array.isArray(value) && value.length === 2 && value.every((n) => typeof n === "number")) {
@@ -27200,9 +27367,9 @@ function ensurePortRange(repo, path2) {
27200
27367
  const existing = registry2[repo];
27201
27368
  if (existing) return existing;
27202
27369
  const range = nextPortBlock(registry2);
27203
- const raw = (0, import_node_fs24.existsSync)(path2) ? JSON.parse((0, import_node_fs24.readFileSync)(path2, "utf8")) : {};
27370
+ const raw = (0, import_node_fs25.existsSync)(path2) ? JSON.parse((0, import_node_fs25.readFileSync)(path2, "utf8")) : {};
27204
27371
  raw[repo] = range;
27205
- (0, import_node_fs24.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
27372
+ (0, import_node_fs25.writeFileSync)(path2, JSON.stringify(raw, null, 2) + "\n", "utf8");
27206
27373
  return range;
27207
27374
  }
27208
27375
  function portCursorSeed(registry2) {
@@ -27224,22 +27391,22 @@ function existingPortRange(repo, registry2) {
27224
27391
  return registry2[repo] ?? null;
27225
27392
  }
27226
27393
  function portRangeInfraAt(root, source) {
27227
- const registryPath = (0, import_node_path24.join)(root, "infra", "port-ranges.json");
27228
- const ddbScriptPath = (0, import_node_path24.join)(root, "infra", "port-ddb.mjs");
27229
- if (!(0, import_node_fs24.existsSync)(registryPath) || !(0, import_node_fs24.existsSync)(ddbScriptPath)) return null;
27394
+ const registryPath = (0, import_node_path25.join)(root, "infra", "port-ranges.json");
27395
+ const ddbScriptPath = (0, import_node_path25.join)(root, "infra", "port-ddb.mjs");
27396
+ if (!(0, import_node_fs25.existsSync)(registryPath) || !(0, import_node_fs25.existsSync)(ddbScriptPath)) return null;
27230
27397
  return { root, source, registryPath, ddbScriptPath };
27231
27398
  }
27232
27399
  function resolvePortRangeInfra(cwd, packageDir) {
27233
27400
  const direct = portRangeInfraAt(cwd, "cwd");
27234
27401
  if (direct) return direct;
27235
- for (let dir = cwd; ; dir = (0, import_node_path24.dirname)(dir)) {
27236
- const sibling = portRangeInfraAt((0, import_node_path24.join)(dir, "MMI-Hub"), "sibling-hub");
27402
+ for (let dir = cwd; ; dir = (0, import_node_path25.dirname)(dir)) {
27403
+ const sibling = portRangeInfraAt((0, import_node_path25.join)(dir, "MMI-Hub"), "sibling-hub");
27237
27404
  if (sibling) return sibling;
27238
- const parent = (0, import_node_path24.dirname)(dir);
27405
+ const parent = (0, import_node_path25.dirname)(dir);
27239
27406
  if (parent === dir) break;
27240
27407
  }
27241
27408
  if (packageDir) {
27242
- const pkgRoot = (0, import_node_path24.join)(packageDir, "..", "..");
27409
+ const pkgRoot = (0, import_node_path25.join)(packageDir, "..", "..");
27243
27410
  const pkgFrom = portRangeInfraAt(pkgRoot, "pkg-root");
27244
27411
  if (pkgFrom) return pkgFrom;
27245
27412
  }
@@ -28725,13 +28892,13 @@ function registerBootstrapCommands(program3) {
28725
28892
  deployFactsRead: deployFacts !== null,
28726
28893
  pushAllowlistOwners: verifyOwners,
28727
28894
  pushAllowlistOwnersRead: verifyOwnersRead,
28728
- readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs25.existsSync)(path2) ? (0, import_node_fs25.readFileSync)(path2, "utf8") : null,
28895
+ readLocalFile: (path2) => path2 === "projects.json" && apiProjects != null ? apiProjects : (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : null,
28729
28896
  // requiredGcpApis is stored as an array by a JSON write, but `org project set --var KEY=VALUE` stores a raw
28730
28897
  // comma-string — accept either so the seeded value verifies regardless of how it was written.
28731
28898
  // #3689: the same committed map the org access audit reads (#3664), so a sanctioned admin is not a
28732
28899
  // permanent bootstrap failure on one surface and an intended state on the other. Absent file → no
28733
28900
  // sanction, which is the pre-#3664 behaviour.
28734
- sanctionedAdmins: (0, import_node_fs25.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs25.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
28901
+ sanctionedAdmins: (0, import_node_fs26.existsSync)("access-matrix.json") ? entriesValueByCanonicalRepo(loadSanctionedAdmins((0, import_node_fs26.readFileSync)("access-matrix.json", "utf8")), repo) : void 0,
28735
28902
  requiredGcpApis: (() => {
28736
28903
  const v = meta?.requiredGcpApis;
28737
28904
  if (Array.isArray(v)) return v;
@@ -28809,14 +28976,14 @@ function registerBootstrapCommands(program3) {
28809
28976
  bootstrap.command("drift").description("#3818: compare every org-owned whole-file seed against MMI-Hub's copy across the registry roster; read-only").option("--repo <owner/repo>", "audit one repo instead of the roster (never a fleet verdict)").option("--json", "machine-readable output").action(async () => {
28810
28977
  const o = { repo: rawValue("--repo", ""), json: rawFlag("--json") };
28811
28978
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
28812
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
28979
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap drift: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the reference this compares against`);
28813
28980
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
28814
28981
  if (!seedSource.ok) return fail(`bootstrap drift: ${seedSource.reason}`);
28815
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
28982
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
28816
28983
  const hubContents = /* @__PURE__ */ new Map();
28817
28984
  for (const s of manifest.seeds) {
28818
28985
  if (s.ownership !== "org" || s.source !== "self") continue;
28819
- hubContents.set(s.target, (0, import_node_fs25.existsSync)(s.target) ? (0, import_node_fs25.readFileSync)(s.target, "utf8") : null);
28986
+ hubContents.set(s.target, (0, import_node_fs26.existsSync)(s.target) ? (0, import_node_fs26.readFileSync)(s.target, "utf8") : null);
28820
28987
  }
28821
28988
  let targets;
28822
28989
  let classOf = (_repo) => "deployable";
@@ -28979,10 +29146,10 @@ function registerBootstrapCommands(program3) {
28979
29146
  return;
28980
29147
  }
28981
29148
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
28982
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
29149
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap apply: ${manifestPath} not found; bootstrap runs from the MMI-Hub repo root by design \u2014 it stamps org-level resources (Project, Ruleset, secrets, access) through the GitHub App, which is only authorized from the Hub checkout`);
28983
29150
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
28984
29151
  if (!seedSource.ok) return fail(`bootstrap apply: ${seedSource.reason}`);
28985
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
29152
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
28986
29153
  const baseBranch = o.class === "content" ? "main" : "development";
28987
29154
  const slug = parsedRepo.slug;
28988
29155
  const onlyTarget = o.only.trim();
@@ -28994,16 +29161,16 @@ function registerBootstrapCommands(program3) {
28994
29161
  }
28995
29162
  const onlyManagedBlock = onlyTarget ? seedsToApply[0]?.managedBlock != null : false;
28996
29163
  const gh = async (args) => execFileP("gh", args, { timeout: 2e4 });
28997
- const readFile9 = (p) => (0, import_node_fs25.existsSync)(p) ? (0, import_node_fs25.readFileSync)(p, "utf8") : null;
29164
+ const readFile9 = (p) => (0, import_node_fs26.existsSync)(p) ? (0, import_node_fs26.readFileSync)(p, "utf8") : null;
28998
29165
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
28999
29166
  const putSeed = async (target, content, ref, sha) => {
29000
- const tmp = (0, import_node_path25.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29001
- (0, import_node_fs25.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
29167
+ const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29168
+ (0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(target, content, ref, sha)), "utf8");
29002
29169
  try {
29003
29170
  await gh(contentPutInputArgs(repo, target, tmp));
29004
29171
  } finally {
29005
29172
  try {
29006
- (0, import_node_fs25.unlinkSync)(tmp);
29173
+ (0, import_node_fs26.unlinkSync)(tmp);
29007
29174
  } catch {
29008
29175
  }
29009
29176
  }
@@ -29452,10 +29619,10 @@ LIVE apply to ${repo}:
29452
29619
  bootstrap.command("propagate").description("#4238: re-entrant canary\u2192wave tick \u2014 plan (or, with --execute, open) per-repo PRs fanning an org-owned seed out to the fleet").option("--target <path>", "the manifest target to propagate (an org-owned whole file or declared Hub-managed block)").option("--execute", "LIVE tick via gh (master-gated) \u2014 opens/reuses per-repo seed-propagate PRs; dry-run prints the plan only").option("--json", "machine-readable output").action(async () => {
29453
29620
  const o = { target: rawValue("--target", ""), execute: rawFlag("--execute"), json: rawFlag("--json") };
29454
29621
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29455
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
29622
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap propagate: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the Hub's copies ARE the desired state this tick propagates`);
29456
29623
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29457
29624
  if (!seedSource.ok) return fail(`bootstrap propagate: ${seedSource.reason}`);
29458
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
29625
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
29459
29626
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
29460
29627
  if (!o.target) {
29461
29628
  return fail(`bootstrap propagate: --target <path> is required \u2014 one of:
@@ -29464,9 +29631,9 @@ LIVE apply to ${repo}:
29464
29631
  const seed = propagatable.find((s) => s.target === o.target);
29465
29632
  if (!seed) return fail(`bootstrap propagate: --target '${o.target}' names no centrally propagatable seed in ${manifestPath}. Propagatable targets:
29466
29633
  ${propagatable.map((s) => s.target).join("\n ")}`);
29467
- if (!seed.managedBlock && !(0, import_node_fs25.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
29468
- const hubContent = seed.managedBlock ? null : (0, import_node_fs25.readFileSync)(seed.target, "utf8");
29469
- const readSeedFile2 = (path2) => (0, import_node_fs25.existsSync)(path2) ? (0, import_node_fs25.readFileSync)(path2, "utf8") : null;
29634
+ if (!seed.managedBlock && !(0, import_node_fs26.existsSync)(seed.target)) return fail(`bootstrap propagate: the Hub's own copy of '${seed.target}' is missing \u2014 nothing to propagate`);
29635
+ const hubContent = seed.managedBlock ? null : (0, import_node_fs26.readFileSync)(seed.target, "utf8");
29636
+ const readSeedFile2 = (path2) => (0, import_node_fs26.existsSync)(path2) ? (0, import_node_fs26.readFileSync)(path2, "utf8") : null;
29470
29637
  const isWorkflowSeed = seed.target.startsWith(".github/workflows/");
29471
29638
  const cfg = await loadConfig();
29472
29639
  const projects = await fetchProjectsList(registryClientDeps(cfg));
@@ -29475,9 +29642,9 @@ LIVE apply to ${repo}:
29475
29642
  }
29476
29643
  const rosterRepos = collectRegistryRepos(projects).filter((r) => r.toLowerCase() !== "mutmutco/mmi-hub");
29477
29644
  let independentCount = rosterRepos.length;
29478
- if ((0, import_node_fs25.existsSync)("projects.json")) {
29645
+ if ((0, import_node_fs26.existsSync)("projects.json")) {
29479
29646
  try {
29480
- const local = JSON.parse((0, import_node_fs25.readFileSync)("projects.json", "utf8"));
29647
+ const local = JSON.parse((0, import_node_fs26.readFileSync)("projects.json", "utf8"));
29481
29648
  const localRepos = /* @__PURE__ */ new Set();
29482
29649
  for (const p of local.projects ?? []) for (const r of p.repos ?? []) {
29483
29650
  const full = (r.includes("/") ? r : `mutmutco/${r}`).toLowerCase();
@@ -29638,15 +29805,15 @@ LIVE apply to ${repo}:
29638
29805
  } catch {
29639
29806
  existingSha = void 0;
29640
29807
  }
29641
- const tmp = (0, import_node_path25.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29808
+ const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-propagate-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29642
29809
  const desiredContent = desiredByRepo.get(rec.repo);
29643
29810
  if (desiredContent == null) return fail(`bootstrap propagate: no resolved content for ${rec.repo} ${seed.target} \u2014 refusing to write`);
29644
- (0, import_node_fs25.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
29811
+ (0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, desiredContent, branch, existingSha)), "utf8");
29645
29812
  try {
29646
29813
  await gh(contentPutInputArgs(rec.repo, seed.target, tmp));
29647
29814
  } finally {
29648
29815
  try {
29649
- (0, import_node_fs25.unlinkSync)(tmp);
29816
+ (0, import_node_fs26.unlinkSync)(tmp);
29650
29817
  } catch {
29651
29818
  }
29652
29819
  }
@@ -29713,10 +29880,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29713
29880
  return fail(`bootstrap rollback: ${e.message}`);
29714
29881
  }
29715
29882
  const manifestPath = "skills/bootstrap/seeds/manifest.json";
29716
- if (!(0, import_node_fs25.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
29883
+ if (!(0, import_node_fs26.existsSync)(manifestPath)) return fail(`bootstrap rollback: ${manifestPath} not found; run from the MMI-Hub repo root \u2014 the manifest names which targets are org-owned and therefore propagated (and rollback-able)`);
29717
29884
  const seedSource = await resolveHubSeedSource(execGitForSeedSource);
29718
29885
  if (!seedSource.ok) return fail(`bootstrap rollback: ${seedSource.reason}`);
29719
- const manifest = loadBootstrapSeeds((0, import_node_fs25.readFileSync)(manifestPath, "utf8"));
29886
+ const manifest = loadBootstrapSeeds((0, import_node_fs26.readFileSync)(manifestPath, "utf8"));
29720
29887
  const propagatable = manifest.seeds.filter(isPropagatableSeed);
29721
29888
  if (!o.target) {
29722
29889
  return fail(`bootstrap rollback: --target <path> is required \u2014 one of:
@@ -29733,10 +29900,10 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29733
29900
  const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
29734
29901
  let candidates;
29735
29902
  if (o.record) {
29736
- if (!(0, import_node_fs25.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
29903
+ if (!(0, import_node_fs26.existsSync)(o.record)) return fail(`bootstrap rollback: --record '${o.record}' not found`);
29737
29904
  let parsed;
29738
29905
  try {
29739
- parsed = JSON.parse((0, import_node_fs25.readFileSync)(o.record, "utf8"));
29906
+ parsed = JSON.parse((0, import_node_fs26.readFileSync)(o.record, "utf8"));
29740
29907
  } catch (e) {
29741
29908
  return fail(`bootstrap rollback: --record '${o.record}' is not valid JSON: ${e.message}`);
29742
29909
  }
@@ -29813,13 +29980,13 @@ Rollback: \`mmi-cli devops bootstrap rollback ${rec.repo} --target ${seed.target
29813
29980
  } catch {
29814
29981
  existingSha = void 0;
29815
29982
  }
29816
- const tmp = (0, import_node_path25.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29817
- (0, import_node_fs25.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
29983
+ const tmp = (0, import_node_path26.join)((0, import_node_os14.tmpdir)(), `mmi-rollback-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
29984
+ (0, import_node_fs26.writeFileSync)(tmp, JSON.stringify(contentPutBody(seed.target, preSeedContent, plan.branch, existingSha)), "utf8");
29818
29985
  try {
29819
29986
  await gh(contentPutInputArgs(repo, seed.target, tmp));
29820
29987
  } finally {
29821
29988
  try {
29822
- (0, import_node_fs25.unlinkSync)(tmp);
29989
+ (0, import_node_fs26.unlinkSync)(tmp);
29823
29990
  } catch {
29824
29991
  }
29825
29992
  }
@@ -30886,7 +31053,7 @@ function renderDeployPortDoctor(report) {
30886
31053
  init_cli_shared();
30887
31054
 
30888
31055
  // src/wave-status.ts
30889
- var import_node_fs28 = require("node:fs");
31056
+ var import_node_fs29 = require("node:fs");
30890
31057
 
30891
31058
  // src/git-worktree-observation.ts
30892
31059
  function parseGitWorktreePorcelain(text) {
@@ -30917,8 +31084,8 @@ function deriveComposeProjectName(worktreePath) {
30917
31084
 
30918
31085
  // src/stage-runner.ts
30919
31086
  var import_node_child_process10 = require("node:child_process");
30920
- var import_node_fs27 = require("node:fs");
30921
- var import_node_path27 = require("node:path");
31087
+ var import_node_fs28 = require("node:fs");
31088
+ var import_node_path28 = require("node:path");
30922
31089
  var import_node_net = require("node:net");
30923
31090
  var import_node_util5 = require("node:util");
30924
31091
 
@@ -30928,8 +31095,8 @@ function normalizeEol2(s) {
30928
31095
  }
30929
31096
 
30930
31097
  // src/env-detection.ts
30931
- var import_node_fs26 = require("node:fs");
30932
- var import_node_path26 = require("node:path");
31098
+ var import_node_fs27 = require("node:fs");
31099
+ var import_node_path27 = require("node:path");
30933
31100
  var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
30934
31101
  function isEnvBaseName(name) {
30935
31102
  return name.toLowerCase() === ".env";
@@ -30939,7 +31106,7 @@ function findEnvFiles(root) {
30939
31106
  const walk2 = (dir, rel) => {
30940
31107
  let entries;
30941
31108
  try {
30942
- entries = (0, import_node_fs26.readdirSync)(dir, { withFileTypes: true });
31109
+ entries = (0, import_node_fs27.readdirSync)(dir, { withFileTypes: true });
30943
31110
  } catch {
30944
31111
  return;
30945
31112
  }
@@ -30947,13 +31114,13 @@ function findEnvFiles(root) {
30947
31114
  const relPath = rel ? `${rel}/${entry.name}` : entry.name;
30948
31115
  if (entry.isDirectory()) {
30949
31116
  if (SKIPPED_DIRS.has(entry.name)) continue;
30950
- walk2((0, import_node_path26.join)(dir, entry.name), relPath);
31117
+ walk2((0, import_node_path27.join)(dir, entry.name), relPath);
30951
31118
  continue;
30952
31119
  }
30953
31120
  if (isEnvBaseName(entry.name)) {
30954
31121
  let isDir = false;
30955
31122
  try {
30956
- isDir = (0, import_node_fs26.lstatSync)((0, import_node_path26.join)(dir, entry.name)).isDirectory();
31123
+ isDir = (0, import_node_fs27.lstatSync)((0, import_node_path27.join)(dir, entry.name)).isDirectory();
30957
31124
  } catch {
30958
31125
  }
30959
31126
  if (!isDir) found.push(relPath);
@@ -31015,12 +31182,12 @@ var DOCKER_TIMEOUT_MS = 15e3;
31015
31182
  function stageBash() {
31016
31183
  if (process.platform !== "win32") return "bash";
31017
31184
  const configured = process.env.SHELL;
31018
- if (configured && (0, import_node_path27.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs27.existsSync)(configured)) return configured;
31185
+ if (configured && (0, import_node_path28.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs28.existsSync)(configured)) return configured;
31019
31186
  const candidates = [
31020
- (0, import_node_path27.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
31021
- ...process.env.LOCALAPPDATA ? [(0, import_node_path27.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
31187
+ (0, import_node_path28.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
31188
+ ...process.env.LOCALAPPDATA ? [(0, import_node_path28.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
31022
31189
  ];
31023
- const bash = candidates.find((path2) => (0, import_node_fs27.existsSync)(path2));
31190
+ const bash = candidates.find((path2) => (0, import_node_fs28.existsSync)(path2));
31024
31191
  if (!bash) throw new Error("Local stages require Git Bash on Windows. Install Git for Windows or set SHELL to its absolute bash.exe path.");
31025
31192
  return bash;
31026
31193
  }
@@ -31151,7 +31318,7 @@ function appendForceRecreate(up) {
31151
31318
  return `${up.trimEnd()} --force-recreate`;
31152
31319
  }
31153
31320
  function stageStatePath(cwd = process.cwd()) {
31154
- return (0, import_node_path27.join)(cwd, "tmp", "stage", "state.json");
31321
+ return (0, import_node_path28.join)(cwd, "tmp", "stage", "state.json");
31155
31322
  }
31156
31323
  function normPath(path2) {
31157
31324
  return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
@@ -31368,8 +31535,8 @@ function stageProcessEnv(stagePort, extraEnv) {
31368
31535
  }
31369
31536
  function composeResolvesPort(cwd) {
31370
31537
  if (process.env.PORT) return true;
31371
- const envFile = (0, import_node_path27.join)(cwd, ".env");
31372
- return (0, import_node_fs27.existsSync)(envFile) && envFileKeys((0, import_node_fs27.readFileSync)(envFile, "utf8")).has("PORT");
31538
+ const envFile = (0, import_node_path28.join)(cwd, ".env");
31539
+ return (0, import_node_fs28.existsSync)(envFile) && envFileKeys((0, import_node_fs28.readFileSync)(envFile, "utf8")).has("PORT");
31373
31540
  }
31374
31541
  function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
31375
31542
  return {
@@ -31382,13 +31549,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
31382
31549
  function stageComposeFiles(cwd) {
31383
31550
  const files = ["docker-compose.yml"];
31384
31551
  for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
31385
- if ((0, import_node_fs27.existsSync)((0, import_node_path27.join)(cwd, conventional))) files.push(conventional);
31552
+ if ((0, import_node_fs28.existsSync)((0, import_node_path28.join)(cwd, conventional))) files.push(conventional);
31386
31553
  }
31387
31554
  return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
31388
31555
  }
31389
31556
  async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
31390
31557
  const keys = Object.keys(vaultEnvMerge ?? {});
31391
- if (!keys.length || !(0, import_node_fs27.existsSync)((0, import_node_path27.join)(cwd, "docker-compose.yml"))) return {};
31558
+ if (!keys.length || !(0, import_node_fs28.existsSync)((0, import_node_path28.join)(cwd, "docker-compose.yml"))) return {};
31392
31559
  let configJson;
31393
31560
  try {
31394
31561
  const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
@@ -31404,21 +31571,21 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
31404
31571
  }
31405
31572
  const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys);
31406
31573
  if (!body) return {};
31407
- const overridePath = (0, import_node_path27.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
31408
- (0, import_node_fs27.mkdirSync)((0, import_node_path27.join)(cwd, "tmp", "stage"), { recursive: true });
31409
- (0, import_node_fs27.writeFileSync)(overridePath, body, "utf8");
31574
+ const overridePath = (0, import_node_path28.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
31575
+ (0, import_node_fs28.mkdirSync)((0, import_node_path28.join)(cwd, "tmp", "stage"), { recursive: true });
31576
+ (0, import_node_fs28.writeFileSync)(overridePath, body, "utf8");
31410
31577
  return stageComposeFileEnv(stageComposeFiles(cwd));
31411
31578
  }
31412
31579
  async function ensureStageRuntimeEnv(config, opts, cwd) {
31413
31580
  if (!config.ensureEnv) return;
31414
- const target = (0, import_node_path27.join)(cwd, config.ensureEnv.target);
31415
- const example = (0, import_node_path27.join)(cwd, config.ensureEnv.example);
31416
- if (!(0, import_node_fs27.existsSync)(target) && (0, import_node_fs27.existsSync)(example)) {
31417
- (0, import_node_fs27.copyFileSync)(example, target);
31418
- } else if ((0, import_node_fs27.existsSync)(target) && (0, import_node_fs27.existsSync)(example)) {
31419
- const stale = detectStaleEnvFile((0, import_node_fs27.readFileSync)(example, "utf8"), (0, import_node_fs27.readFileSync)(target, "utf8"), {
31420
- exampleMtimeMs: (0, import_node_fs27.statSync)(example).mtimeMs,
31421
- targetMtimeMs: (0, import_node_fs27.statSync)(target).mtimeMs
31581
+ const target = (0, import_node_path28.join)(cwd, config.ensureEnv.target);
31582
+ const example = (0, import_node_path28.join)(cwd, config.ensureEnv.example);
31583
+ if (!(0, import_node_fs28.existsSync)(target) && (0, import_node_fs28.existsSync)(example)) {
31584
+ (0, import_node_fs28.copyFileSync)(example, target);
31585
+ } else if ((0, import_node_fs28.existsSync)(target) && (0, import_node_fs28.existsSync)(example)) {
31586
+ const stale = detectStaleEnvFile((0, import_node_fs28.readFileSync)(example, "utf8"), (0, import_node_fs28.readFileSync)(target, "utf8"), {
31587
+ exampleMtimeMs: (0, import_node_fs28.statSync)(example).mtimeMs,
31588
+ targetMtimeMs: (0, import_node_fs28.statSync)(target).mtimeMs
31422
31589
  });
31423
31590
  if (stale) {
31424
31591
  const msg = `stale ${config.ensureEnv.target} (${stale}) \u2014 delete it or refresh from ${config.ensureEnv.example} before re-running /stage`;
@@ -31426,8 +31593,8 @@ async function ensureStageRuntimeEnv(config, opts, cwd) {
31426
31593
  console.error(`mmi-cli stage: ${msg} (allowed via --allow-stale-env)`);
31427
31594
  }
31428
31595
  }
31429
- if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs27.existsSync)(target)) {
31430
- (0, import_node_fs27.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs27.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
31596
+ if (opts.vaultEnvMerge && Object.keys(opts.vaultEnvMerge).length && (0, import_node_fs28.existsSync)(target)) {
31597
+ (0, import_node_fs28.writeFileSync)(target, mergeEnvSecretsIntoFile((0, import_node_fs28.readFileSync)(target, "utf8"), opts.vaultEnvMerge), "utf8");
31431
31598
  }
31432
31599
  }
31433
31600
  async function gitText(cwd, args) {
@@ -31457,20 +31624,20 @@ async function resolveGlobalStatePath(cwd, explicit) {
31457
31624
  return void 0;
31458
31625
  }
31459
31626
  function readState(path2) {
31460
- if (!(0, import_node_fs27.existsSync)(path2)) return null;
31627
+ if (!(0, import_node_fs28.existsSync)(path2)) return null;
31461
31628
  try {
31462
- return JSON.parse((0, import_node_fs27.readFileSync)(path2, "utf8"));
31629
+ return JSON.parse((0, import_node_fs28.readFileSync)(path2, "utf8"));
31463
31630
  } catch {
31464
31631
  return null;
31465
31632
  }
31466
31633
  }
31467
31634
  function mkdirFor(path2) {
31468
31635
  const dir = path2.slice(0, Math.max(path2.lastIndexOf("/"), path2.lastIndexOf("\\")));
31469
- (0, import_node_fs27.mkdirSync)(dir, { recursive: true });
31636
+ (0, import_node_fs28.mkdirSync)(dir, { recursive: true });
31470
31637
  }
31471
31638
  function writeState(path2, state) {
31472
31639
  mkdirFor(path2);
31473
- (0, import_node_fs27.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
31640
+ (0, import_node_fs28.writeFileSync)(path2, JSON.stringify(state, null, 2), "utf8");
31474
31641
  }
31475
31642
  function writeStagePortReservation(port, cwd, statePath, globalStatePath, now) {
31476
31643
  const reservation = {
@@ -31499,7 +31666,7 @@ async function cleanupStageState(state, paths, timeoutMs, fallbackCwd, currentEn
31499
31666
  );
31500
31667
  }
31501
31668
  for (const path2 of [...new Set(paths.filter((p) => Boolean(p)))]) {
31502
- (0, import_node_fs27.rmSync)(path2, { force: true });
31669
+ (0, import_node_fs28.rmSync)(path2, { force: true });
31503
31670
  }
31504
31671
  }
31505
31672
  async function killTree(pid) {
@@ -31686,8 +31853,8 @@ async function runStage(config = {}, opts = {}) {
31686
31853
  });
31687
31854
  }
31688
31855
  } catch (e) {
31689
- (0, import_node_fs27.rmSync)(statePath, { force: true });
31690
- if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs27.rmSync)(globalStatePath, { force: true });
31856
+ (0, import_node_fs28.rmSync)(statePath, { force: true });
31857
+ if (globalStatePath && globalStatePath !== statePath) (0, import_node_fs28.rmSync)(globalStatePath, { force: true });
31691
31858
  throw e;
31692
31859
  }
31693
31860
  const started = await startStage(config, {
@@ -31704,9 +31871,9 @@ async function runStage(config = {}, opts = {}) {
31704
31871
  // src/wave-status.ts
31705
31872
  function readStageSummary(worktreePath) {
31706
31873
  const statePath = stageStatePath(worktreePath);
31707
- if (!(0, import_node_fs28.existsSync)(statePath)) return void 0;
31874
+ if (!(0, import_node_fs29.existsSync)(statePath)) return void 0;
31708
31875
  try {
31709
- const state = JSON.parse((0, import_node_fs28.readFileSync)(statePath, "utf8"));
31876
+ const state = JSON.parse((0, import_node_fs29.readFileSync)(statePath, "utf8"));
31710
31877
  const port = typeof state.port === "number" ? state.port : void 0;
31711
31878
  if (port == null || !Number.isInteger(port) || port <= 0) return void 0;
31712
31879
  return { port, url: typeof state.url === "string" ? state.url : void 0 };
@@ -31763,9 +31930,9 @@ async function collectWaveStatus(deps) {
31763
31930
  // src/discovery-commands.ts
31764
31931
  init_github_client();
31765
31932
  init_cli_shared();
31766
- var import_node_fs29 = require("node:fs");
31933
+ var import_node_fs30 = require("node:fs");
31767
31934
  var import_node_os15 = require("node:os");
31768
- var import_node_path28 = require("node:path");
31935
+ var import_node_path29 = require("node:path");
31769
31936
  var GC_GH_TIMEOUT_MS = 2e4;
31770
31937
  async function collectStatus() {
31771
31938
  const repo = await resolveRepo();
@@ -31955,8 +32122,8 @@ async function collectOnboardStatus(opts = {}) {
31955
32122
  }
31956
32123
  const home = (0, import_node_os15.homedir)();
31957
32124
  const plugin = onboardPluginGate({
31958
- readKnown: () => readFileSyncSafe((0, import_node_path28.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs29.readFileSync),
31959
- readSettings: () => readFileSyncSafe((0, import_node_path28.join)(home, ".claude", "settings.json"), import_node_fs29.readFileSync)
32125
+ readKnown: () => readFileSyncSafe((0, import_node_path29.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs30.readFileSync),
32126
+ readSettings: () => readFileSyncSafe((0, import_node_path29.join)(home, ".claude", "settings.json"), import_node_fs30.readFileSync)
31960
32127
  });
31961
32128
  return {
31962
32129
  guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
@@ -33973,7 +34140,7 @@ function parseOriginRepo(remoteUrl) {
33973
34140
  init_github_client();
33974
34141
 
33975
34142
  // src/issue-commands.ts
33976
- var import_node_fs30 = require("node:fs");
34143
+ var import_node_fs31 = require("node:fs");
33977
34144
  var import_node_crypto10 = require("node:crypto");
33978
34145
  init_cli_shared();
33979
34146
  init_clean_exit();
@@ -34230,7 +34397,7 @@ async function editIssue(client, options, deps = {}) {
34230
34397
  const url = `https://github.com/${repo}/issues/${parsed.number}`;
34231
34398
  const patch = {};
34232
34399
  let bodyChanged = false;
34233
- const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs30.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
34400
+ const textDeps = () => deps.textDeps ?? { readFile: (p, e) => Promise.resolve((0, import_node_fs31.readFileSync)(p, e)), readStdin: () => Promise.resolve("") };
34234
34401
  if (options.titleFile !== void 0) {
34235
34402
  patch.title = await resolveIssueTitle({ title: options.title, titleFile: options.titleFile }, textDeps());
34236
34403
  } else if (options.title !== void 0) {
@@ -34886,7 +35053,7 @@ function extendCreateCommand(issue, batchAttach) {
34886
35053
  if (opts.batch) {
34887
35054
  let specs;
34888
35055
  try {
34889
- const raw = (0, import_node_fs30.readFileSync)(opts.batch, "utf8");
35056
+ const raw = (0, import_node_fs31.readFileSync)(opts.batch, "utf8");
34890
35057
  specs = JSON.parse(raw);
34891
35058
  if (!Array.isArray(specs)) {
34892
35059
  const top = specs === null ? "null" : typeof specs === "object" ? `an object with keys: ${Object.keys(specs).join(", ") || "(none)"}` : `a ${typeof specs}`;
@@ -36050,8 +36217,8 @@ function registerPrLifecycleCommands(program3) {
36050
36217
  }
36051
36218
 
36052
36219
  // src/project-info-sync.ts
36053
- var import_node_fs31 = require("node:fs");
36054
- var import_node_path29 = require("node:path");
36220
+ var import_node_fs32 = require("node:fs");
36221
+ var import_node_path30 = require("node:path");
36055
36222
  var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
36056
36223
  updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
36057
36224
  projectV2 { id }
@@ -36098,14 +36265,14 @@ function sharedName(entries, fallback) {
36098
36265
  }
36099
36266
  function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
36100
36267
  if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
36101
- const readmePath = (0, import_node_path29.join)(repoRoot2, "README.md");
36102
- if (!(0, import_node_fs31.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
36268
+ const readmePath = (0, import_node_path30.join)(repoRoot2, "README.md");
36269
+ if (!(0, import_node_fs32.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
36103
36270
  const entries = entriesFor(project2, projects);
36104
36271
  const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
36105
36272
  const projectName = sharedName(entries, project2.name?.trim() || targetRepo2.split("/").pop() || targetRepo2);
36106
36273
  if (!memberRepos.length) throw new Error(`org project sync-info: project ${projectName} has no registered member repos`);
36107
36274
  const entryNames = entries.map((entry) => entry.name?.trim()).filter((name) => Boolean(name));
36108
- const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs31.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
36275
+ const shortDescription = memberRepos.length === 1 ? shortDescriptionFromReadme((0, import_node_fs32.readFileSync)(readmePath, "utf8")) : `Shared work across ${new Intl.ListFormat("en", { type: "conjunction" }).format(entryNames)}.`;
36109
36276
  const lines2 = [
36110
36277
  `# ${projectName}`,
36111
36278
  "",
@@ -36124,8 +36291,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
36124
36291
  const targetBase = `https://github.com/${targetRepo2}`;
36125
36292
  const targetBranch = branchFor(targetRepo2, projects);
36126
36293
  const orgDocs = [
36127
- (0, import_node_fs31.existsSync)((0, import_node_path29.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
36128
- (0, import_node_fs31.existsSync)((0, import_node_path29.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
36294
+ (0, import_node_fs32.existsSync)((0, import_node_path30.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
36295
+ (0, import_node_fs32.existsSync)((0, import_node_path30.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
36129
36296
  ].filter(Boolean);
36130
36297
  if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
36131
36298
  return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
@@ -36507,8 +36674,8 @@ function registerSchedulesCommands(program3) {
36507
36674
  }
36508
36675
 
36509
36676
  // src/secrets-commands.ts
36510
- var import_node_fs32 = require("node:fs");
36511
- var import_node_path30 = require("node:path");
36677
+ var import_node_fs33 = require("node:fs");
36678
+ var import_node_path31 = require("node:path");
36512
36679
  var import_node_os17 = require("node:os");
36513
36680
  init_cli_shared();
36514
36681
  init_hub_auth();
@@ -36614,18 +36781,18 @@ function collectMap(value, previous = []) {
36614
36781
  return [...previous, value];
36615
36782
  }
36616
36783
  async function decryptRailsCredentials(input) {
36617
- const appDir = (0, import_node_path30.resolve)(input.appDir ?? process.cwd());
36784
+ const appDir = (0, import_node_path31.resolve)(input.appDir ?? process.cwd());
36618
36785
  const credentialsFile = input.credentialsFile ?? DEFAULT_RAILS_CREDENTIALS_FILE;
36619
36786
  const masterKeyFile = input.masterKeyFile ?? DEFAULT_RAILS_MASTER_KEY_FILE;
36620
- const credentialsPath = (0, import_node_path30.resolve)(appDir, credentialsFile);
36621
- const masterKeyPath = (0, import_node_path30.resolve)(appDir, masterKeyFile);
36787
+ const credentialsPath = (0, import_node_path31.resolve)(appDir, credentialsFile);
36788
+ const masterKeyPath = (0, import_node_path31.resolve)(appDir, masterKeyFile);
36622
36789
  const env = {
36623
36790
  ...process.env,
36624
36791
  MMI_RAILS_CREDENTIALS_FILE: credentialsPath,
36625
36792
  MMI_RAILS_MASTER_KEY_FILE: masterKeyPath
36626
36793
  };
36627
- if ((0, import_node_fs32.existsSync)(masterKeyPath)) {
36628
- env.RAILS_MASTER_KEY = (0, import_node_fs32.readFileSync)(masterKeyPath, "utf8").trim();
36794
+ if ((0, import_node_fs33.existsSync)(masterKeyPath)) {
36795
+ env.RAILS_MASTER_KEY = (0, import_node_fs33.readFileSync)(masterKeyPath, "utf8").trim();
36629
36796
  }
36630
36797
  const script = [
36631
36798
  'require "json"',
@@ -36635,9 +36802,9 @@ async function decryptRailsCredentials(input) {
36635
36802
  'config = ActiveSupport::EncryptedConfiguration.new(config_path: config_path, key_path: key_path, env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true)',
36636
36803
  "puts JSON.generate(config.config)"
36637
36804
  ].join("\n");
36638
- const scriptDir = (0, import_node_fs32.mkdtempSync)((0, import_node_path30.join)((0, import_node_os17.tmpdir)(), "mmi-rails-decrypt-"));
36639
- const scriptPath = (0, import_node_path30.join)(scriptDir, "decrypt.rb");
36640
- (0, import_node_fs32.writeFileSync)(scriptPath, script, "utf8");
36805
+ const scriptDir = (0, import_node_fs33.mkdtempSync)((0, import_node_path31.join)((0, import_node_os17.tmpdir)(), "mmi-rails-decrypt-"));
36806
+ const scriptPath = (0, import_node_path31.join)(scriptDir, "decrypt.rb");
36807
+ (0, import_node_fs33.writeFileSync)(scriptPath, script, "utf8");
36641
36808
  try {
36642
36809
  const args = ["exec", "ruby", scriptPath];
36643
36810
  const cmd = process.platform === "win32" ? "cmd.exe" : "bundle";
@@ -36649,7 +36816,7 @@ async function decryptRailsCredentials(input) {
36649
36816
  });
36650
36817
  return JSON.parse(stdout);
36651
36818
  } finally {
36652
- (0, import_node_fs32.rmSync)(scriptDir, { recursive: true, force: true });
36819
+ (0, import_node_fs33.rmSync)(scriptDir, { recursive: true, force: true });
36653
36820
  }
36654
36821
  }
36655
36822
  async function readSecretStdin() {
@@ -36739,7 +36906,7 @@ function registerSecretsCommands(program3) {
36739
36906
  let body;
36740
36907
  if (o.file) {
36741
36908
  try {
36742
- body = (0, import_node_fs32.readFileSync)((0, import_node_path30.resolve)(o.file), "utf8");
36909
+ body = (0, import_node_fs33.readFileSync)((0, import_node_path31.resolve)(o.file), "utf8");
36743
36910
  } catch (e) {
36744
36911
  return fail(`secrets org-catalog: cannot read --file ${o.file}: ${e.message}`);
36745
36912
  }
@@ -36871,7 +37038,7 @@ function registerSecretsCommands(program3) {
36871
37038
  {
36872
37039
  ...d,
36873
37040
  decryptRailsCredentials,
36874
- removeFile: (path2) => (0, import_node_fs32.unlinkSync)((0, import_node_path30.resolve)(o.appDir ?? process.cwd(), path2))
37041
+ removeFile: (path2) => (0, import_node_fs33.unlinkSync)((0, import_node_path31.resolve)(o.appDir ?? process.cwd(), path2))
36875
37042
  },
36876
37043
  {
36877
37044
  repo: o.repo,
@@ -37034,8 +37201,8 @@ function registerSessionReport(program3) {
37034
37201
  }
37035
37202
 
37036
37203
  // src/stage-commands.ts
37037
- var import_node_fs33 = require("node:fs");
37038
- var import_node_path31 = require("node:path");
37204
+ var import_node_fs34 = require("node:fs");
37205
+ var import_node_path32 = require("node:path");
37039
37206
  init_cli_shared();
37040
37207
  init_clean_exit();
37041
37208
 
@@ -37281,8 +37448,8 @@ function registerStageCommands(program3) {
37281
37448
  return {
37282
37449
  resolution: decideStage({
37283
37450
  registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
37284
- hasCompose: (0, import_node_fs33.existsSync)((0, import_node_path31.join)(process.cwd(), "docker-compose.yml")),
37285
- hasEnvExample: (0, import_node_fs33.existsSync)((0, import_node_path31.join)(process.cwd(), ".env.example")),
37451
+ hasCompose: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), "docker-compose.yml")),
37452
+ hasEnvExample: (0, import_node_fs34.existsSync)((0, import_node_path32.join)(process.cwd(), ".env.example")),
37286
37453
  repo
37287
37454
  }),
37288
37455
  project: project2,
@@ -37566,19 +37733,19 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
37566
37733
 
37567
37734
  // src/tenant-artifact.ts
37568
37735
  var import_node_crypto11 = require("node:crypto");
37569
- var import_node_fs34 = require("node:fs");
37736
+ var import_node_fs35 = require("node:fs");
37570
37737
  var import_promises6 = require("node:fs/promises");
37571
- var import_node_path32 = require("node:path");
37738
+ var import_node_path33 = require("node:path");
37572
37739
  var ARTIFACT_ID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
37573
37740
  var MAX_BYTES = 5 * 1024 * 1024 * 1024;
37574
37741
  async function sha256File(path2) {
37575
37742
  const hash = (0, import_node_crypto11.createHash)("sha256");
37576
- for await (const chunk of (0, import_node_fs34.createReadStream)(path2)) hash.update(chunk);
37743
+ for await (const chunk of (0, import_node_fs35.createReadStream)(path2)) hash.update(chunk);
37577
37744
  return hash.digest("hex");
37578
37745
  }
37579
37746
  async function putTenantArtifact(repo, stage, inputPath, deps) {
37580
37747
  if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
37581
- const path2 = (0, import_node_path32.resolve)(inputPath);
37748
+ const path2 = (0, import_node_path33.resolve)(inputPath);
37582
37749
  const info = await (0, import_promises6.stat)(path2);
37583
37750
  if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
37584
37751
  if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES} bytes`);
@@ -37596,7 +37763,7 @@ async function putTenantArtifact(repo, stage, inputPath, deps) {
37596
37763
  return [key, value];
37597
37764
  }));
37598
37765
  headers["content-length"] = String(info.size);
37599
- const stream = (0, import_node_fs34.createReadStream)(path2);
37766
+ const stream = (0, import_node_fs35.createReadStream)(path2);
37600
37767
  let uploaded;
37601
37768
  try {
37602
37769
  uploaded = await fetch(body.uploadUrl, {
@@ -37736,7 +37903,7 @@ function renderVerifySecrets(body) {
37736
37903
 
37737
37904
  // src/command-register-collaboration.ts
37738
37905
  var import_node_child_process15 = require("node:child_process");
37739
- var import_node_fs41 = require("node:fs");
37906
+ var import_node_fs42 = require("node:fs");
37740
37907
  var import_promises7 = require("node:fs/promises");
37741
37908
  init_clean_exit();
37742
37909
  init_cli_shared();
@@ -37760,7 +37927,7 @@ function spawnDetachedSelf(args, deps, opts = {}) {
37760
37927
  }
37761
37928
 
37762
37929
  // src/command-register-collaboration.ts
37763
- var import_node_path39 = require("node:path");
37930
+ var import_node_path40 = require("node:path");
37764
37931
 
37765
37932
  // src/attach-to-project.ts
37766
37933
  async function attachViaHubApp(cfg, contentNodeId) {
@@ -37851,6 +38018,9 @@ function prHeadBehindBase(input) {
37851
38018
  function prHeadUpdateRemedy(head, base) {
37852
38019
  return `git fetch origin ${base} && git merge origin/${base} (on ${head}), resolve the conflicts, push, then rerun \u2014 docs/Guides/train-troubleshooting.md#head-behind-base`;
37853
38020
  }
38021
+ function prLandedBranchFinality(prNumber, base) {
38022
+ return `PR #${prNumber} is merged, and that is final \u2014 stopping a local waiter or monitor does not unmerge it. The head branch is now landed; further commits pushed to it reach nothing. If more work is needed, run \`git fetch origin ${base} && git switch -c <new-branch> origin/${base}\`, then cherry-pick anything already committed \u2014 docs/Guides/train-troubleshooting.md#merged-pr-head-reuse`;
38023
+ }
37854
38024
  var PROTECTED_PR_HEAD_BRANCHES = ["main", "master", "development", "rc"];
37855
38025
  function isProtectedPrHead(head) {
37856
38026
  return PROTECTED_PR_HEAD_BRANCHES.includes(head);
@@ -37946,8 +38116,9 @@ async function readGhPrStateWithRetry(fetchState, options) {
37946
38116
  return { ok: false, error: lastError };
37947
38117
  }
37948
38118
  async function runPrLand(prNumber, options, deps) {
37949
- const repo = await deps.resolveRepo(prNumber, options.repo);
37950
- const base = { status: "failed", repo, pr: prNumber };
38119
+ const resolved = await deps.resolveRepo(prNumber, options.repo);
38120
+ const { repo } = resolved;
38121
+ const base = { status: "failed", repo, pr: prNumber, base: resolved.base };
37951
38122
  if (options.requireTrain !== false) {
37952
38123
  const verdict = await deps.fetchTrainAuthority(repo);
37953
38124
  if (!verdict.ok) {
@@ -37999,12 +38170,21 @@ async function runPrLand(prNumber, options, deps) {
37999
38170
  return { ...base, error: merge.error ?? "merge failed" };
38000
38171
  }
38001
38172
  if (merge.mergeStatus === "merged") {
38002
- return { ...base, status: "merged" };
38173
+ return {
38174
+ ...base,
38175
+ status: "merged",
38176
+ branchFinality: prLandedBranchFinality(prNumber, resolved.base)
38177
+ };
38003
38178
  }
38004
38179
  const now = deps.now ?? (() => Date.now());
38005
38180
  const merged = await deps.pollMerged(prNumber, repo, now() + PR_LAND_ENQUEUE_TIMEOUT_MS);
38006
38181
  if (merged) {
38007
- return { ...base, status: "auto-merge-enqueued-then-merged", mergeStatus: "merged" };
38182
+ return {
38183
+ ...base,
38184
+ status: "auto-merge-enqueued-then-merged",
38185
+ mergeStatus: "merged",
38186
+ branchFinality: prLandedBranchFinality(prNumber, resolved.base)
38187
+ };
38008
38188
  }
38009
38189
  return {
38010
38190
  ...base,
@@ -38016,8 +38196,8 @@ async function runPrLand(prNumber, options, deps) {
38016
38196
  init_github_client();
38017
38197
 
38018
38198
  // src/merge-cleanup.ts
38019
- var import_node_fs36 = require("node:fs");
38020
- var import_node_path34 = require("node:path");
38199
+ var import_node_fs37 = require("node:fs");
38200
+ var import_node_path35 = require("node:path");
38021
38201
  var import_node_os18 = require("node:os");
38022
38202
  init_cli_shared();
38023
38203
  init_github_client();
@@ -38126,8 +38306,8 @@ function boardAdvanceFailureMessage(result) {
38126
38306
 
38127
38307
  // src/test-policy-core.ts
38128
38308
  var import_node_child_process12 = require("node:child_process");
38129
- var import_node_fs35 = require("node:fs");
38130
- var import_node_path33 = require("node:path");
38309
+ var import_node_fs36 = require("node:fs");
38310
+ var import_node_path34 = require("node:path");
38131
38311
 
38132
38312
  // src/test-command-policy-shared.mjs
38133
38313
  var import_node_child_process11 = require("node:child_process");
@@ -38603,7 +38783,7 @@ function isMeaningfulRow(file) {
38603
38783
  return file.meaningful !== false;
38604
38784
  }
38605
38785
  function loadPolicy(root, readFile9 = readFileOrNull2) {
38606
- const raw = readFile9((0, import_node_path33.join)(root, POLICY_FILE));
38786
+ const raw = readFile9((0, import_node_path34.join)(root, POLICY_FILE));
38607
38787
  if (raw == null) return { mandatory: [], declared: false };
38608
38788
  return parsePolicy(raw, POLICY_FILE);
38609
38789
  }
@@ -38680,7 +38860,7 @@ function loadPolicySource(root, explicitRef, diffBase) {
38680
38860
  }
38681
38861
  function readFileOrNull2(path2) {
38682
38862
  try {
38683
- return (0, import_node_fs35.readFileSync)(path2, "utf8");
38863
+ return (0, import_node_fs36.readFileSync)(path2, "utf8");
38684
38864
  } catch {
38685
38865
  return null;
38686
38866
  }
@@ -38708,12 +38888,12 @@ function classify(changed, policy, present = () => false) {
38708
38888
  const removedProtected = [...removed].filter((p) => protectedBy.has(p)).map((p) => ({ path: p, why: protectedBy.get(p) ?? "" }));
38709
38889
  return { mandatoryHits, untestedHits, testChanges, meaningfulTestChanges, addedTests, removedProtected };
38710
38890
  }
38711
- function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
38712
- return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path33.join)(root, p)));
38891
+ function unresolvedProtectedEntries(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
38892
+ return (policy.protected ?? []).map((p) => p.path).filter((p) => !exists((0, import_node_path34.join)(root, p)));
38713
38893
  }
38714
- function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs35.existsSync)(path2)) {
38894
+ function unresolvedSatisfiers(policy, root, exists = (path2) => (0, import_node_fs36.existsSync)(path2)) {
38715
38895
  const declared = (policy.mandatory ?? []).flatMap((m) => m.satisfiedBy ?? []);
38716
- return [...new Set(declared)].filter((p) => !exists((0, import_node_path33.join)(root, p)));
38896
+ return [...new Set(declared)].filter((p) => !exists((0, import_node_path34.join)(root, p)));
38717
38897
  }
38718
38898
  function evaluate(changed, policy, present = () => false) {
38719
38899
  const { mandatoryHits, untestedHits, meaningfulTestChanges, addedTests, removedProtected } = classify(changed, policy, present);
@@ -38852,14 +39032,14 @@ function runTestPolicy(root, deps = {}) {
38852
39032
  }
38853
39033
  const loaded = deps.policy ? { policy: deps.policy, source: { ref: null, sha: null, path: POLICY_FILE } } : loadPolicySource(root, deps.policyRef, deps.base);
38854
39034
  const { policy, source: policySource } = loaded;
38855
- const exists = deps.exists ?? ((path2) => (0, import_node_fs35.existsSync)(path2));
39035
+ const exists = deps.exists ?? ((path2) => (0, import_node_fs36.existsSync)(path2));
38856
39036
  const counts = { mandatoryCount: (policy.mandatory ?? []).length, protectedCount: (policy.protected ?? []).length };
38857
39037
  const base = deps.changed ? "(injected)" : deps.policyRef ? resolveHotfixBase(root) : resolveBase(root, deps.base);
38858
39038
  const refusal = deps.changed ? null : untrustworthyRange(root, base);
38859
39039
  const raw = deps.changed ?? (refusal ? [] : changedFilesSince(base, root));
38860
39040
  const changed = deps.changed ? raw : annotateChangeMeaning(raw, policy, (path2) => ({
38861
39041
  before: blobAt(base, path2, root),
38862
- after: readFileOrNull2((0, import_node_path33.join)(root, path2))
39042
+ after: readFileOrNull2((0, import_node_path34.join)(root, path2))
38863
39043
  }));
38864
39044
  const lookup = deps.override !== void 0 ? { override: deps.override, refusals: [] } : !deps.changed && !refusal ? readOverride2(base, root) : { override: null, refusals: [] };
38865
39045
  const policyRefusals = policy.declared === false ? [{
@@ -38869,8 +39049,8 @@ function runTestPolicy(root, deps = {}) {
38869
39049
  A gate with no policy cannot decide which test commands are required or permitted.
38870
39050
  ` + (deps.base === HOTFIX_DIFF_BASE ? ` Hotfix lane (--base ${HOTFIX_DIFF_BASE}): pass --policy-ref <exact-${HOTFIX_POLICY_REF}-commit> so the current policy is read from ${HOTFIX_POLICY_REF}.` : ` Restore ${POLICY_FILE} on this branch; the policy file belongs on every non-hotfix lane.`)
38871
39051
  }] : [];
38872
- const present = (path2) => exists((0, import_node_path33.join)(root, path2));
38873
- const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path33.join)(root, p))) : null;
39052
+ const present = (path2) => exists((0, import_node_path34.join)(root, path2));
39053
+ const policyTree = policySource.sha ? new Set(git2(["ls-tree", "-r", "-z", "--name-only", policySource.sha], root).split("\0").filter(Boolean).map((p) => (0, import_node_path34.join)(root, p))) : null;
38874
39054
  const policyTreeExists = policyTree ? (abs) => policyTree.has(abs) : exists;
38875
39055
  const where = policySource.sha ? `${policySource.ref}@${policySource.sha}` : "this worktree";
38876
39056
  const removedByThisDiff = removedPaths(changed);
@@ -39088,13 +39268,13 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
39088
39268
  return rewritten === base ? null : rewritten;
39089
39269
  }
39090
39270
  function writeSquashBodyFile(body) {
39091
- const dir = (0, import_node_fs36.mkdtempSync)((0, import_node_path34.join)((0, import_node_os18.tmpdir)(), "mmi-squash-body-"));
39092
- const path2 = (0, import_node_path34.join)(dir, "body.txt");
39093
- (0, import_node_fs36.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
39271
+ const dir = (0, import_node_fs37.mkdtempSync)((0, import_node_path35.join)((0, import_node_os18.tmpdir)(), "mmi-squash-body-"));
39272
+ const path2 = (0, import_node_path35.join)(dir, "body.txt");
39273
+ (0, import_node_fs37.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
39094
39274
  `, "utf8");
39095
39275
  return { path: path2, cleanup: () => {
39096
39276
  try {
39097
- (0, import_node_fs36.rmSync)(dir, { recursive: true, force: true });
39277
+ (0, import_node_fs37.rmSync)(dir, { recursive: true, force: true });
39098
39278
  } catch {
39099
39279
  }
39100
39280
  } };
@@ -39301,8 +39481,8 @@ async function deleteMergedRemoteBranch(options) {
39301
39481
  }
39302
39482
 
39303
39483
  // src/post-merge-recon.ts
39304
- var import_node_fs37 = require("node:fs");
39305
- var import_node_path35 = require("node:path");
39484
+ var import_node_fs38 = require("node:fs");
39485
+ var import_node_path36 = require("node:path");
39306
39486
 
39307
39487
  // src/cross-repo-filing-issue.ts
39308
39488
  init_github_client();
@@ -39469,16 +39649,16 @@ function buildPostMergeReconRecovery(input) {
39469
39649
  }
39470
39650
  function writePostMergeReconRecovery(cwd, recovery) {
39471
39651
  const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
39472
- (0, import_node_fs37.mkdirSync)((0, import_node_path35.dirname)(path2), { recursive: true });
39473
- (0, import_node_fs37.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
39652
+ (0, import_node_fs38.mkdirSync)((0, import_node_path36.dirname)(path2), { recursive: true });
39653
+ (0, import_node_fs38.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
39474
39654
  `, "utf8");
39475
39655
  return path2;
39476
39656
  }
39477
39657
  function clearPostMergeReconRecovery(cwd, repo, pr) {
39478
39658
  const path2 = postMergeReconStatePath(cwd, repo, pr);
39479
- if (!(0, import_node_fs37.existsSync)(path2)) return;
39659
+ if (!(0, import_node_fs38.existsSync)(path2)) return;
39480
39660
  try {
39481
- (0, import_node_fs37.unlinkSync)(path2);
39661
+ (0, import_node_fs38.unlinkSync)(path2);
39482
39662
  } catch {
39483
39663
  }
39484
39664
  }
@@ -39510,9 +39690,9 @@ function postMergeReconWarnings(input) {
39510
39690
 
39511
39691
  // src/review-verdict.ts
39512
39692
  var import_node_child_process13 = require("node:child_process");
39513
- var import_node_fs38 = require("node:fs");
39693
+ var import_node_fs39 = require("node:fs");
39514
39694
  var import_node_os19 = require("node:os");
39515
- var import_node_path36 = require("node:path");
39695
+ var import_node_path37 = require("node:path");
39516
39696
  init_cli_shared();
39517
39697
  var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
39518
39698
  var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
@@ -39677,15 +39857,15 @@ async function readPrIssueComments(number, repo) {
39677
39857
  return comments;
39678
39858
  }
39679
39859
  async function postPrCommentFromFile(number, repo, body) {
39680
- const dir = (0, import_node_fs38.mkdtempSync)((0, import_node_path36.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
39681
- const path2 = (0, import_node_path36.join)(dir, "body.md");
39860
+ const dir = (0, import_node_fs39.mkdtempSync)((0, import_node_path37.join)((0, import_node_os19.tmpdir)(), "mmi-review-verdict-"));
39861
+ const path2 = (0, import_node_path37.join)(dir, "body.md");
39682
39862
  try {
39683
- (0, import_node_fs38.writeFileSync)(path2, body, "utf8");
39863
+ (0, import_node_fs39.writeFileSync)(path2, body, "utf8");
39684
39864
  const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
39685
39865
  return stdout.trim();
39686
39866
  } finally {
39687
39867
  try {
39688
- (0, import_node_fs38.rmSync)(dir, { recursive: true, force: true });
39868
+ (0, import_node_fs39.rmSync)(dir, { recursive: true, force: true });
39689
39869
  } catch {
39690
39870
  }
39691
39871
  }
@@ -39839,6 +40019,32 @@ function withRateLimitRetry(client, seams = {}) {
39839
40019
  throttledPaths
39840
40020
  };
39841
40021
  }
40022
+ async function prCreateMergedHeadWarning(input, deps = {}) {
40023
+ const guide = "docs/Guides/train-troubleshooting.md#merged-pr-head-reuse";
40024
+ if (!input.head) {
40025
+ return `pr create: WARNING \u2014 could not check whether the current head branch already landed (the current branch could not be resolved); continuing with PR creation \u2014 ${guide}`;
40026
+ }
40027
+ try {
40028
+ const repo = await requireRepo(input.repo);
40029
+ const owner = repo.split("/")[0];
40030
+ if (!owner) throw new Error(`invalid repository '${repo}'`);
40031
+ const qualifiedHead = input.head.includes(":") ? input.head : `${owner}:${input.head}`;
40032
+ const query = new URLSearchParams({ state: "closed", head: qualifiedHead, sort: "updated", direction: "desc" });
40033
+ const pulls = await (deps.client ?? defaultGitHubClient()).restPaginate(
40034
+ `repos/${repo}/pulls?${query.toString()}`
40035
+ );
40036
+ const merged = pulls.find((pull) => typeof pull.merged_at === "string" && pull.merged_at.length > 0);
40037
+ if (!merged) return void 0;
40038
+ if (typeof merged.number !== "number" || typeof merged.base?.ref !== "string" || !merged.base.ref) {
40039
+ throw new Error("GitHub returned a merged PR without its number or base branch");
40040
+ }
40041
+ const base = merged.base.ref;
40042
+ return `pr create: WARNING \u2014 head branch '${input.head}' already landed in merged PR #${merged.number}. If you meant to continue that landed work, cut a fresh branch from origin/${base}: \`git fetch origin ${base} && git switch -c <new-branch> origin/${base}\`, then cherry-pick anything already committed. Creating another PR from a deliberately reused branch name remains allowed \u2014 ${guide}`;
40043
+ } catch (e) {
40044
+ const detail = String(e.message || e).replace(/\s+/g, " ").slice(0, 240);
40045
+ return `pr create: WARNING \u2014 could not check whether head branch '${input.head}' already landed (${detail}); continuing with PR creation \u2014 ${guide}`;
40046
+ }
40047
+ }
39842
40048
  async function prCreateClaimRefusal(body, repoOption, deps = {}) {
39843
40049
  const issues = [...new Set(findClosingMentions(body).map((mention) => mention.issue))];
39844
40050
  if (!issues.length) return void 0;
@@ -39871,13 +40077,13 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
39871
40077
  }
39872
40078
 
39873
40079
  // src/worktree-merge-cleanup.ts
39874
- var import_node_fs40 = require("node:fs");
39875
- var import_node_path38 = require("node:path");
40080
+ var import_node_fs41 = require("node:fs");
40081
+ var import_node_path39 = require("node:path");
39876
40082
  init_cli_shared();
39877
40083
 
39878
40084
  // src/worktree-evidence-archive.ts
39879
- var import_node_fs39 = require("node:fs");
39880
- var import_node_path37 = require("node:path");
40085
+ var import_node_fs40 = require("node:fs");
40086
+ var import_node_path38 = require("node:path");
39881
40087
  var JERV_ARTIFACT_RUN_SCOPE_ENV_VARS = ["JERV_RUN_ID", ...SESSION_ID_ENV_VARS];
39882
40088
  function sanitizeArchiveSegment(value, max = 80) {
39883
40089
  const scrubbed = value.replace(/[^A-Za-z0-9._@+-]+/g, "-").replace(/^-+|-+$/g, "");
@@ -39892,24 +40098,24 @@ function resolveArtifactRunScope(env = process.env) {
39892
40098
  }
39893
40099
  function defaultIsDirectory(path2) {
39894
40100
  try {
39895
- return (0, import_node_fs39.lstatSync)(path2).isDirectory();
40101
+ return (0, import_node_fs40.lstatSync)(path2).isDirectory();
39896
40102
  } catch {
39897
40103
  return false;
39898
40104
  }
39899
40105
  }
39900
40106
  function archiveWorktreeJervArtifacts(args, deps = {}) {
39901
- const exists = deps.exists ?? import_node_fs39.existsSync;
40107
+ const exists = deps.exists ?? import_node_fs40.existsSync;
39902
40108
  const isDirectory = deps.isDirectory ?? defaultIsDirectory;
39903
- const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs39.cpSync)(from, to, { recursive: true, force: true }));
40109
+ const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
39904
40110
  const mkdirp = deps.mkdirp ?? ((path2) => {
39905
- (0, import_node_fs39.mkdirSync)(path2, { recursive: true });
40111
+ (0, import_node_fs40.mkdirSync)(path2, { recursive: true });
39906
40112
  });
39907
40113
  const env = deps.env ?? process.env;
39908
40114
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
39909
40115
  const resolveRoot = deps.resolveArchiveRoot ?? repoRuntimeStatePath;
39910
40116
  if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
39911
40117
  if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
39912
- const source = (0, import_node_path37.join)(args.worktreePath, ".jerv");
40118
+ const source = (0, import_node_path38.join)(args.worktreePath, ".jerv");
39913
40119
  if (!exists(source)) return { status: "absent" };
39914
40120
  if (!isDirectory(source)) return { status: "skipped", reason: "jerv-not-a-directory" };
39915
40121
  const runScope = resolveArtifactRunScope(env);
@@ -39917,7 +40123,7 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
39917
40123
  const stamp = now().toISOString().replace(/[:.]/g, "-");
39918
40124
  const dest = resolveRoot(args.primaryRoot, "jerv-artifacts", runScope, branchSlug, stamp, ".jerv");
39919
40125
  try {
39920
- mkdirp((0, import_node_path37.dirname)(dest));
40126
+ mkdirp((0, import_node_path38.dirname)(dest));
39921
40127
  copyDir(source, dest);
39922
40128
  if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
39923
40129
  return { status: "archived", path: dest, runScope };
@@ -39926,14 +40132,14 @@ function archiveWorktreeJervArtifacts(args, deps = {}) {
39926
40132
  }
39927
40133
  }
39928
40134
  function defaultStat(path2) {
39929
- const st = (0, import_node_fs39.statSync)(path2);
40135
+ const st = (0, import_node_fs40.statSync)(path2);
39930
40136
  return { mtimeMs: st.mtimeMs, size: st.size, isDirectory: () => st.isDirectory() };
39931
40137
  }
39932
40138
  function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
39933
- const exists = deps.exists ?? import_node_fs39.existsSync;
40139
+ const exists = deps.exists ?? import_node_fs40.existsSync;
39934
40140
  const stat4 = deps.stat ?? defaultStat;
39935
- const readdir2 = deps.readdir ?? import_node_fs39.readdirSync;
39936
- const tmpRoot = (0, import_node_path37.join)(worktreePath, "tmp");
40141
+ const readdir2 = deps.readdir ?? import_node_fs40.readdirSync;
40142
+ const tmpRoot = (0, import_node_path38.join)(worktreePath, "tmp");
39937
40143
  if (!exists(tmpRoot)) return [];
39938
40144
  const entries = [];
39939
40145
  const walk2 = (dir) => {
@@ -39944,14 +40150,14 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
39944
40150
  return;
39945
40151
  }
39946
40152
  for (const name of names) {
39947
- const full = (0, import_node_path37.join)(dir, name);
40153
+ const full = (0, import_node_path38.join)(dir, name);
39948
40154
  let st;
39949
40155
  try {
39950
40156
  st = stat4(full);
39951
40157
  } catch {
39952
40158
  continue;
39953
40159
  }
39954
- const relPath = (0, import_node_path37.relative)(worktreePath, full).replace(/\\/g, "/");
40160
+ const relPath = (0, import_node_path38.relative)(worktreePath, full).replace(/\\/g, "/");
39955
40161
  if (st.isDirectory()) {
39956
40162
  if (st.mtimeMs > newerThanMs) entries.push({ relPath, bytes: 0, mtimeMs: st.mtimeMs });
39957
40163
  walk2(full);
@@ -39965,10 +40171,10 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
39965
40171
  return entries;
39966
40172
  }
39967
40173
  function archiveWorktreeTmpArtifacts(args, deps = {}) {
39968
- const exists = deps.exists ?? import_node_fs39.existsSync;
39969
- const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs39.cpSync)(from, to, { recursive: true, force: true }));
40174
+ const exists = deps.exists ?? import_node_fs40.existsSync;
40175
+ const copyDir = deps.copyDir ?? ((from, to) => (0, import_node_fs40.cpSync)(from, to, { recursive: true, force: true }));
39970
40176
  const mkdirp = deps.mkdirp ?? ((path2) => {
39971
- (0, import_node_fs39.mkdirSync)(path2, { recursive: true });
40177
+ (0, import_node_fs40.mkdirSync)(path2, { recursive: true });
39972
40178
  });
39973
40179
  const env = deps.env ?? process.env;
39974
40180
  const now = deps.now ?? (() => /* @__PURE__ */ new Date());
@@ -39976,7 +40182,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
39976
40182
  if (!args.primaryRoot?.trim()) return { status: "skipped", reason: "missing-primary-root" };
39977
40183
  if (!args.worktreePath?.trim()) return { status: "skipped", reason: "missing-worktree-path" };
39978
40184
  const scanned = scanWorktreeTmpEvidence(args.worktreePath, args.newerThanMs, deps);
39979
- const source = (0, import_node_path37.join)(args.worktreePath, "tmp");
40185
+ const source = (0, import_node_path38.join)(args.worktreePath, "tmp");
39980
40186
  if (!scanned.length) return { status: "absent" };
39981
40187
  if (!exists(source)) return { status: "absent" };
39982
40188
  const runScope = resolveArtifactRunScope(env);
@@ -39984,7 +40190,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
39984
40190
  const stamp = now().toISOString().replace(/[:.]/g, "-");
39985
40191
  const dest = resolveRoot(args.primaryRoot, "worktree-artifacts", runScope, branchSlug, stamp, "tmp");
39986
40192
  try {
39987
- mkdirp((0, import_node_path37.dirname)(dest));
40193
+ mkdirp((0, import_node_path38.dirname)(dest));
39988
40194
  copyDir(source, dest);
39989
40195
  if (!exists(dest)) return { status: "failed", error: `archive write left no directory at ${dest}` };
39990
40196
  const bytes = scanned.reduce((sum, e) => sum + e.bytes, 0);
@@ -40053,9 +40259,9 @@ function normPath2(p) {
40053
40259
  return p.replace(/\\/g, "/").replace(/\/+$/, "");
40054
40260
  }
40055
40261
  function unlinkNodeModulesJunction(wtPath) {
40056
- const nm = (0, import_node_path38.join)(wtPath, "node_modules");
40262
+ const nm = (0, import_node_path39.join)(wtPath, "node_modules");
40057
40263
  try {
40058
- if ((0, import_node_fs40.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs40.rmdirSync)(nm);
40264
+ if ((0, import_node_fs41.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs41.rmdirSync)(nm);
40059
40265
  return { ok: true };
40060
40266
  } catch (e) {
40061
40267
  if (e.code === "ENOENT") return { ok: true };
@@ -40066,8 +40272,8 @@ function defaultSleep2(ms) {
40066
40272
  return new Promise((resolve7) => setTimeout(resolve7, ms));
40067
40273
  }
40068
40274
  async function removeResidueDirectory(wtPath, options = {}) {
40069
- const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs40.rmdirSync, exists = import_node_fs40.existsSync } = options;
40070
- const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs40.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
40275
+ const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs41.rmdirSync, exists = import_node_fs41.existsSync } = options;
40276
+ const removeRecursive = options.removeRecursive ?? ((path2) => (0, import_node_fs41.rmSync)(path2, { recursive: true, force: true, maxRetries: 10, retryDelay: 100 }));
40071
40277
  const junction = unlinkNodeModulesJunction(wtPath);
40072
40278
  if (!junction.ok) return junction;
40073
40279
  try {
@@ -40190,28 +40396,28 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
40190
40396
  }
40191
40397
  async function listNestedIgnoredNodeModules(wtPath, execGit) {
40192
40398
  const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
40193
- return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path38.join)(wtPath, line.slice(0, -1)));
40399
+ return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path39.join)(wtPath, line.slice(0, -1)));
40194
40400
  }
40195
40401
  function safeRemoveTree(path2) {
40196
- const stat4 = (0, import_node_fs40.lstatSync)(path2);
40402
+ const stat4 = (0, import_node_fs41.lstatSync)(path2);
40197
40403
  if (stat4.isSymbolicLink()) {
40198
40404
  try {
40199
- (0, import_node_fs40.rmdirSync)(path2);
40405
+ (0, import_node_fs41.rmdirSync)(path2);
40200
40406
  } catch {
40201
- (0, import_node_fs40.unlinkSync)(path2);
40407
+ (0, import_node_fs41.unlinkSync)(path2);
40202
40408
  }
40203
40409
  return;
40204
40410
  }
40205
40411
  if (stat4.isDirectory()) {
40206
- for (const entry of (0, import_node_fs40.readdirSync)(path2)) safeRemoveTree((0, import_node_path38.join)(path2, entry));
40207
- (0, import_node_fs40.rmdirSync)(path2);
40412
+ for (const entry of (0, import_node_fs41.readdirSync)(path2)) safeRemoveTree((0, import_node_path39.join)(path2, entry));
40413
+ (0, import_node_fs41.rmdirSync)(path2);
40208
40414
  return;
40209
40415
  }
40210
- (0, import_node_fs40.unlinkSync)(path2);
40416
+ (0, import_node_fs41.unlinkSync)(path2);
40211
40417
  }
40212
40418
  async function removeWorktreeNodeModules(wtPath) {
40213
40419
  try {
40214
- safeRemoveTree((0, import_node_path38.join)(wtPath, "node_modules"));
40420
+ safeRemoveTree((0, import_node_path39.join)(wtPath, "node_modules"));
40215
40421
  return { ok: true };
40216
40422
  } catch (e) {
40217
40423
  if (e.code === "ENOENT") return { ok: true };
@@ -40223,7 +40429,7 @@ function errorMessage(e) {
40223
40429
  }
40224
40430
  function resolvedOrRaw(path2) {
40225
40431
  try {
40226
- return normPath2((0, import_node_fs40.realpathSync)(path2));
40432
+ return normPath2((0, import_node_fs41.realpathSync)(path2));
40227
40433
  } catch {
40228
40434
  return normPath2(path2);
40229
40435
  }
@@ -40231,10 +40437,10 @@ function resolvedOrRaw(path2) {
40231
40437
  function unlinkEscapingReparsePoints(root, primaryRoot) {
40232
40438
  let realRoot;
40233
40439
  try {
40234
- if ((0, import_node_fs40.lstatSync)(root).isSymbolicLink()) {
40440
+ if ((0, import_node_fs41.lstatSync)(root).isSymbolicLink()) {
40235
40441
  return { ok: false, error: `delete root ${normPath2(root)} is a reparse point resolving to ${resolvedOrRaw(root)}` };
40236
40442
  }
40237
- realRoot = normPath2((0, import_node_fs40.realpathSync)(root));
40443
+ realRoot = normPath2((0, import_node_fs41.realpathSync)(root));
40238
40444
  } catch (e) {
40239
40445
  if (e.code === "ENOENT") return { ok: true, unlinked: [] };
40240
40446
  return { ok: false, error: `cannot resolve delete root ${normPath2(root)}: ${errorMessage(e)}` };
@@ -40250,16 +40456,16 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
40250
40456
  const dir = stack.pop();
40251
40457
  let entries;
40252
40458
  try {
40253
- entries = (0, import_node_fs40.readdirSync)(dir, { withFileTypes: true });
40459
+ entries = (0, import_node_fs41.readdirSync)(dir, { withFileTypes: true });
40254
40460
  } catch (e) {
40255
40461
  return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
40256
40462
  }
40257
40463
  for (const entry of entries) {
40258
- const child2 = (0, import_node_path38.join)(dir, entry.name);
40464
+ const child2 = (0, import_node_path39.join)(dir, entry.name);
40259
40465
  if (entry.isSymbolicLink()) {
40260
40466
  let target = "";
40261
40467
  try {
40262
- target = normPath2((0, import_node_fs40.realpathSync)(child2));
40468
+ target = normPath2((0, import_node_fs41.realpathSync)(child2));
40263
40469
  } catch {
40264
40470
  target = "";
40265
40471
  }
@@ -40442,7 +40648,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
40442
40648
  return report;
40443
40649
  }
40444
40650
  const execGit = options.execGit ?? (async (args) => (await execFileP("git", args, { timeout: GIT_TIMEOUT_MS })).stdout);
40445
- const pathExists = options.pathExists ?? import_node_fs40.existsSync;
40651
+ const pathExists = options.pathExists ?? import_node_fs41.existsSync;
40446
40652
  let afterWorktrees = [];
40447
40653
  try {
40448
40654
  afterWorktrees = parseGitWorktreePorcelain(await execGit(["worktree", "list", "--porcelain"]));
@@ -40582,7 +40788,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
40582
40788
  const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
40583
40789
  if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
40584
40790
  unlinkedReparsePoints.push(...preHelperGuard.unlinked);
40585
- if (pathExists((0, import_node_path38.join)(wtPath, "node_modules"))) {
40791
+ if (pathExists((0, import_node_path39.join)(wtPath, "node_modules"))) {
40586
40792
  const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
40587
40793
  if (!nmRemoved.ok) {
40588
40794
  report.worktree = {
@@ -40749,10 +40955,10 @@ function argvWantsJson2() {
40749
40955
  return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
40750
40956
  }
40751
40957
  function hubRoot() {
40752
- const fromPkg = (0, import_node_path39.join)(__dirname, "..", "..");
40958
+ const fromPkg = (0, import_node_path40.join)(__dirname, "..", "..");
40753
40959
  const marker = "skills/bootstrap/seeds/manifest.json";
40754
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(fromPkg, marker))) return fromPkg;
40755
- if ((0, import_node_fs41.existsSync)((0, import_node_path39.join)(process.cwd(), marker))) return process.cwd();
40960
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(fromPkg, marker))) return fromPkg;
40961
+ if ((0, import_node_fs42.existsSync)((0, import_node_path40.join)(process.cwd(), marker))) return process.cwd();
40756
40962
  return null;
40757
40963
  }
40758
40964
  function ciAuditDeps() {
@@ -40764,8 +40970,8 @@ function ciAuditDeps() {
40764
40970
  getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
40765
40971
  readSeedFile: (path2) => {
40766
40972
  if (!root) return null;
40767
- const fullPath = (0, import_node_path39.join)(root, path2);
40768
- return (0, import_node_fs41.existsSync)(fullPath) ? (0, import_node_fs41.readFileSync)(fullPath, "utf8") : null;
40973
+ const fullPath = (0, import_node_path40.join)(root, path2);
40974
+ return (0, import_node_fs42.existsSync)(fullPath) ? (0, import_node_fs42.readFileSync)(fullPath, "utf8") : null;
40769
40975
  }
40770
40976
  };
40771
40977
  }
@@ -41443,6 +41649,10 @@ ${list}`);
41443
41649
  }
41444
41650
  const claimRefusal = await prCreateClaimRefusal(body, o.repo);
41445
41651
  if (claimRefusal) return fail(claimRefusal);
41652
+ const createHead = o.head ?? await gitOut(["symbolic-ref", "--quiet", "--short", "HEAD"]).catch(() => "");
41653
+ const mergedHeadWarning = await prCreateMergedHeadWarning({ head: createHead || void 0, repo: o.repo });
41654
+ if (mergedHeadWarning) process.stderr.write(`${mergedHeadWarning}
41655
+ `);
41446
41656
  const created = await ghCreate(buildPrArgs({ title, body, base: o.base, head: o.head, repo: o.repo, draft: o.draft }));
41447
41657
  if (isGhCreateRateLimited(created)) {
41448
41658
  console.log(JSON.stringify(created));
@@ -41486,11 +41696,11 @@ ${list}`);
41486
41696
  }
41487
41697
  });
41488
41698
  async function listCiWorkflowPaths(cwd = process.cwd()) {
41489
- const wfDir = (0, import_node_path39.join)(cwd, ".github", "workflows");
41490
- if (!(0, import_node_fs41.existsSync)(wfDir)) return [];
41491
- return (0, import_node_fs41.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
41699
+ const wfDir = (0, import_node_path40.join)(cwd, ".github", "workflows");
41700
+ if (!(0, import_node_fs42.existsSync)(wfDir)) return [];
41701
+ return (0, import_node_fs42.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
41492
41702
  try {
41493
- return workflowReportsPrChecks((0, import_node_fs41.readFileSync)((0, import_node_path39.join)(wfDir, name), "utf8"));
41703
+ return workflowReportsPrChecks((0, import_node_fs42.readFileSync)((0, import_node_path40.join)(wfDir, name), "utf8"));
41494
41704
  } catch {
41495
41705
  return true;
41496
41706
  }
@@ -41686,7 +41896,7 @@ ${list}`);
41686
41896
  jsonParity(pr.command("review-verdict <number>").description("post an explicit review verdict comment: computes the PR diff patch-id and head sha, renders the v1 contract body, and posts it as a PR comment").requiredOption("--repo <owner/repo>", "target repo").requiredOption("--verdict <verdict>", `one of ${REVIEW_VERDICTS.join("|")}`).requiredOption("--scope <text>", "one line: what was reviewed").requiredOption("--risk <text>", "one line: the residual risk").option("--unverified <text>", "a claim the reviewer could not verify (repeatable)", (v, acc) => [...acc, v], []).requiredOption("--reviewer <id>", "reviewer seat or model id").option("--findings-file <path>", "Markdown findings appended after the JSON block")).action(async (number, o) => {
41687
41897
  if (!isReviewVerdict(o.verdict)) return fail(`pr review-verdict: --verdict must be one of ${REVIEW_VERDICTS.join("|")} (got ${o.verdict})`);
41688
41898
  const verdict = o.verdict;
41689
- const findings = o.findingsFile ? (0, import_node_fs41.readFileSync)(o.findingsFile, "utf8") : void 0;
41899
+ const findings = o.findingsFile ? (0, import_node_fs42.readFileSync)(o.findingsFile, "utf8") : void 0;
41690
41900
  let patch;
41691
41901
  let head;
41692
41902
  try {
@@ -41801,7 +42011,7 @@ ${list}`);
41801
42011
  const shape = track ? `${track} track` : "unresolved track \u2014 strict reading";
41802
42012
  throw new Error(`pr land: base branch ${base} is a promotion target (${shape}) \u2014 promotion merges stay human-only`);
41803
42013
  }
41804
- return repo;
42014
+ return { repo, base };
41805
42015
  },
41806
42016
  fetchTrainAuthority: async (repo) => fetchTrainAuthority(repo, registryClientDeps(await loadConfig())),
41807
42017
  resolveCiPolicy: (repo) => resolveRepoMergeCiPolicy(repo, ciAuditDeps()),
@@ -41916,7 +42126,9 @@ ${list}`);
41916
42126
  }
41917
42127
  const credential = await pollToken().catch(() => void 0) ? "app_installation" : "user";
41918
42128
  if (o.json) printLine(JSON.stringify({ ...result, credential }));
41919
- else printLine(`pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""} (credential: ${credential})`);
42129
+ else printLine(
42130
+ `pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""} (credential: ${credential})` + (result.branchFinality ? ` \u2014 ${result.branchFinality}` : "")
42131
+ );
41920
42132
  if (result.status === "failed") process.exitCode = 1;
41921
42133
  });
41922
42134
  jsonParity(pr.command("merge <number>").description("merge a PR (squash by default); archives gitignored tmp/** before worktree teardown; on no-ci repos run pr ci-policy / checks-wait first (#1432, #5679)").option("--squash", "squash merge (default)").option("--merge", "create a merge commit").option("--rebase", "rebase merge").option("--repo <owner/repo>", "target repo (defaults to the current repo); from a foreign checkout the remote probe/delete address this repo and local cleanup runs only in the verified sibling checkout ../<repo>, else localBranch reports skipped-foreign-cwd and the receipt carries foreignCwd: true (#6148)").option("--auto", "enable auto-merge \u2014 merge once the base-branch policy is satisfied (use for policy-gated repos)").addOption(new Option("--disable-auto", "disable a queued auto-merge without merging").conflicts(["auto", "wait", "squash", "merge", "rebase", "preserveWorktree", "gc", "squashBodyFile", "force"])).option("--wait", `wait for checks to reach a terminal passing verdict before merging (default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m) \u2014 run as a background/monitor task or under a shell timeout above that budget; a short foreground timeout (e.g. 120s) kills it after checks pass and leaves the PR open (#6027)`).option("--preserve-worktree", "after merge, keep the local PR worktree/branch for an active batch (#1888); also the merge settings-proof bypass when delete_branch_on_merge cannot be proven (#6210)").option("--gc", "acknowledge deleting unarchived gitignored tmp/** evidence newer than the branch base (#5679)").option("--squash-body-file <path>", "squash commit body (overrides GitHub COMMIT_MESSAGES); use when a pushed commit mentions close/fix/resolve + #N that must not close (#5723)").option("--force", "acknowledge and merge past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal").option("--without-review <reason>", "compatibility option; shared merge helpers do not require a review verdict")).action(async (number, o) => {
@@ -41958,7 +42170,7 @@ ${list}`);
41958
42170
  const mergeSquashBody = squashBodyTextForMerge(
41959
42171
  closingGuardInput,
41960
42172
  method === "--squash",
41961
- o.squashBodyFile ? (0, import_node_fs41.readFileSync)(o.squashBodyFile, "utf8") : void 0
42173
+ o.squashBodyFile ? (0, import_node_fs42.readFileSync)(o.squashBodyFile, "utf8") : void 0
41962
42174
  );
41963
42175
  if (!o.squashBodyFile) warnSquashBodyClosingStrip("pr merge", closingGuardInput, mergeSquashBody);
41964
42176
  const closingGuardVerdict = evaluateClosingGuard(closingGuardInput, {
@@ -41990,7 +42202,7 @@ ${list}`);
41990
42202
  const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
41991
42203
  let foreignCheckout;
41992
42204
  if (foreignCwd) {
41993
- const sibling = (0, import_node_path39.join)((0, import_node_path39.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
42205
+ const sibling = (0, import_node_path40.join)((0, import_node_path40.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
41994
42206
  const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
41995
42207
  if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
41996
42208
  const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
@@ -42088,7 +42300,7 @@ ${list}`);
42088
42300
  }
42089
42301
  if (!repoForPostCleanup) throw e;
42090
42302
  console.warn(`pr merge: gh GraphQL rate-limited \u2014 merging PR #${number} via REST PUT instead (#4588).`);
42091
- const commitMessage = bodyFile ? (0, import_node_fs41.readFileSync)(bodyFile, "utf8") : void 0;
42303
+ const commitMessage = bodyFile ? (0, import_node_fs42.readFileSync)(bodyFile, "utf8") : void 0;
42092
42304
  await defaultGitHubClient().rest("PUT", `repos/${repoForPostCleanup}/pulls/${number}/merge`, {
42093
42305
  body: { merge_method: method.slice(2), ...commitMessage ? { commit_message: commitMessage } : {} },
42094
42306
  timeoutMs: GH_MUTATION_TIMEOUT_MS
@@ -42208,7 +42420,7 @@ ${list}`);
42208
42420
  preserveWorktree: o.preserveWorktree,
42209
42421
  gcAcknowledged: o.gc,
42210
42422
  expectedHeadOid: headRefOid,
42211
- pathExists: (p) => (0, import_node_fs41.existsSync)(p),
42423
+ pathExists: (p) => (0, import_node_fs42.existsSync)(p),
42212
42424
  // #5899: pin cleanup git calls to the main checkout — the task worktree this process may be
42213
42425
  // standing in is removed mid-cleanup, so a cwd-relative invocation fails with
42214
42426
  // 'fatal: not a git repository' and leaves a spurious partial-cleanup exit.
@@ -42329,7 +42541,7 @@ ${list}`);
42329
42541
  }
42330
42542
 
42331
42543
  // src/command-register-developer.ts
42332
- var import_node_fs46 = require("node:fs");
42544
+ var import_node_fs47 = require("node:fs");
42333
42545
  init_clean_exit();
42334
42546
  init_cli_shared();
42335
42547
  init_error_codes();
@@ -42362,7 +42574,7 @@ async function resolveWhoami(deps) {
42362
42574
  }
42363
42575
 
42364
42576
  // src/command-register-developer.ts
42365
- var import_node_path44 = require("node:path");
42577
+ var import_node_path45 = require("node:path");
42366
42578
  init_house_map();
42367
42579
  init_hub_url();
42368
42580
 
@@ -42395,7 +42607,7 @@ async function executeWaveLand(plan, deps) {
42395
42607
  }
42396
42608
 
42397
42609
  // src/box-commands.ts
42398
- var import_node_fs42 = require("node:fs");
42610
+ var import_node_fs43 = require("node:fs");
42399
42611
  init_clean_exit();
42400
42612
 
42401
42613
  // src/box.ts
@@ -42607,7 +42819,7 @@ function registerBoxCommands(program3) {
42607
42819
  }
42608
42820
  const remote = command && command.length ? command.join(" ") : void 0;
42609
42821
  const wroteScript = o.ssh && o.script ? o.script : null;
42610
- if (wroteScript) (0, import_node_fs42.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
42822
+ if (wroteScript) (0, import_node_fs43.writeFileSync)(wroteScript, sshRecipeScript(found, remote), "utf8");
42611
42823
  if (o.json) {
42612
42824
  console.log(JSON.stringify({
42613
42825
  box: found,
@@ -42629,19 +42841,19 @@ ${SSH_RECIPE_AGENT_NOTE}`);
42629
42841
  // src/dist-drift.ts
42630
42842
  var import_node_child_process16 = require("node:child_process");
42631
42843
  var import_node_crypto13 = require("node:crypto");
42632
- var import_node_fs44 = require("node:fs");
42844
+ var import_node_fs45 = require("node:fs");
42633
42845
  var import_node_os20 = require("node:os");
42634
- var import_node_path41 = require("node:path");
42846
+ var import_node_path42 = require("node:path");
42635
42847
 
42636
42848
  // ../scripts/distribution-digest.mjs
42637
42849
  var import_node_crypto12 = require("node:crypto");
42638
- var import_node_fs43 = require("node:fs");
42639
- var import_node_path40 = require("node:path");
42850
+ var import_node_fs44 = require("node:fs");
42851
+ var import_node_path41 = require("node:path");
42640
42852
  var slash = (value) => value.replaceAll("\\", "/");
42641
42853
  function repoPath(root, declaredPath, label) {
42642
- const absoluteRoot = (0, import_node_path40.resolve)(root);
42643
- const target = (0, import_node_path40.resolve)(root, declaredPath);
42644
- if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path40.sep}`)) {
42854
+ const absoluteRoot = (0, import_node_path41.resolve)(root);
42855
+ const target = (0, import_node_path41.resolve)(root, declaredPath);
42856
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path41.sep}`)) {
42645
42857
  throw new Error(`${label} ${declaredPath} escapes the repository root`);
42646
42858
  }
42647
42859
  return target;
@@ -42649,7 +42861,7 @@ function repoPath(root, declaredPath, label) {
42649
42861
  function digestFiles(files) {
42650
42862
  const hash = (0, import_node_crypto12.createHash)("sha256");
42651
42863
  for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
42652
- const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs43.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs43.readFileSync)(file.absolute);
42864
+ const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs44.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs44.readFileSync)(file.absolute);
42653
42865
  hash.update(file.relative, "utf8");
42654
42866
  hash.update("\0");
42655
42867
  hash.update(file.stat.isSymbolicLink() ? "symlink" : "file", "utf8");
@@ -42664,8 +42876,8 @@ function digestFiles(files) {
42664
42876
  function digestPackedFiles(packageRoot, packedFiles) {
42665
42877
  return digestFiles(packedFiles.map((path2) => {
42666
42878
  const absolute = repoPath(packageRoot, path2, "packed artifact identity path");
42667
- if (!(0, import_node_fs43.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
42668
- return { absolute, relative: slash(path2), stat: (0, import_node_fs43.lstatSync)(absolute) };
42879
+ if (!(0, import_node_fs44.existsSync)(absolute)) throw new Error(`packed artifact identity path ${path2} does not exist`);
42880
+ return { absolute, relative: slash(path2), stat: (0, import_node_fs44.lstatSync)(absolute) };
42669
42881
  }));
42670
42882
  }
42671
42883
 
@@ -42749,13 +42961,13 @@ function renderDistDriftReceipt(receipt) {
42749
42961
  return lines2;
42750
42962
  }
42751
42963
  function readOrNull(path2) {
42752
- return (0, import_node_fs44.existsSync)(path2) ? (0, import_node_fs44.readFileSync)(path2) : null;
42964
+ return (0, import_node_fs45.existsSync)(path2) ? (0, import_node_fs45.readFileSync)(path2) : null;
42753
42965
  }
42754
42966
  function walkFiles(root) {
42755
42967
  const files = [];
42756
42968
  const walk2 = (directory) => {
42757
- for (const entry of (0, import_node_fs44.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
42758
- const child2 = (0, import_node_path41.join)(directory, entry.name);
42969
+ for (const entry of (0, import_node_fs45.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
42970
+ const child2 = (0, import_node_path42.join)(directory, entry.name);
42759
42971
  if (entry.isDirectory()) walk2(child2);
42760
42972
  else files.push(child2);
42761
42973
  }
@@ -42765,10 +42977,10 @@ function walkFiles(root) {
42765
42977
  }
42766
42978
  function bomPathFor(root) {
42767
42979
  try {
42768
- const registry2 = JSON.parse((0, import_node_fs44.readFileSync)((0, import_node_path41.join)(root, "surfaces.json"), "utf8"));
42769
- return (0, import_node_path41.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
42980
+ const registry2 = JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path42.join)(root, "surfaces.json"), "utf8"));
42981
+ return (0, import_node_path42.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
42770
42982
  } catch {
42771
- return (0, import_node_path41.join)(root, "distribution-bom.json");
42983
+ return (0, import_node_path42.join)(root, "distribution-bom.json");
42772
42984
  }
42773
42985
  }
42774
42986
  function rebuildTo(packageRoot, outDir) {
@@ -42781,35 +42993,35 @@ function rebuildTo(packageRoot, outDir) {
42781
42993
  });
42782
42994
  }
42783
42995
  function runDistStatus(root) {
42784
- const stage = (0, import_node_fs44.mkdtempSync)((0, import_node_path41.join)((0, import_node_os20.tmpdir)(), "mmi-dist-drift-"));
42996
+ const stage = (0, import_node_fs45.mkdtempSync)((0, import_node_path42.join)((0, import_node_os20.tmpdir)(), "mmi-dist-drift-"));
42785
42997
  let overlayCount = 0;
42786
42998
  try {
42787
- const cliOut = (0, import_node_path41.join)(stage, "cli-dist");
42788
- const hubOut = (0, import_node_path41.join)(stage, "hub-dist");
42789
- rebuildTo((0, import_node_path41.join)(root, "cli"), cliOut);
42790
- rebuildTo((0, import_node_path41.join)(root, "updater"), hubOut);
42999
+ const cliOut = (0, import_node_path42.join)(stage, "cli-dist");
43000
+ const hubOut = (0, import_node_path42.join)(stage, "hub-dist");
43001
+ rebuildTo((0, import_node_path42.join)(root, "cli"), cliOut);
43002
+ rebuildTo((0, import_node_path42.join)(root, "updater"), hubOut);
42791
43003
  const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
42792
43004
  const rebuilt = (path2) => {
42793
43005
  const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
42794
- return spec ? readOrNull((0, import_node_path41.join)(outDirFor(spec.packageDir), spec.output)) : null;
43006
+ return spec ? readOrNull((0, import_node_path42.join)(outDirFor(spec.packageDir), spec.output)) : null;
42795
43007
  };
42796
- const committed = (path2) => readOrNull((0, import_node_path41.join)(root, path2));
42797
- const tree = (path2) => readOrNull((0, import_node_path41.join)(root, path2));
42798
- const distRoot = (0, import_node_path41.join)(root, "cli", "dist");
42799
- const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path41.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
42800
- const bom = JSON.parse((0, import_node_fs44.readFileSync)(bomPathFor(root), "utf8"));
43008
+ const committed = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
43009
+ const tree = (path2) => readOrNull((0, import_node_path42.join)(root, path2));
43010
+ const distRoot = (0, import_node_path42.join)(root, "cli", "dist");
43011
+ const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path42.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
43012
+ const bom = JSON.parse((0, import_node_fs45.readFileSync)(bomPathFor(root), "utf8"));
42801
43013
  const digest = (entries) => {
42802
- const overlay = (0, import_node_path41.join)(stage, `overlay-${overlayCount++}`);
43014
+ const overlay = (0, import_node_path42.join)(stage, `overlay-${overlayCount++}`);
42803
43015
  for (const entry of entries) {
42804
- const target = (0, import_node_path41.join)(overlay, entry.path);
42805
- (0, import_node_fs44.mkdirSync)((0, import_node_path41.dirname)(target), { recursive: true });
42806
- (0, import_node_fs44.writeFileSync)(target, entry.bytes);
43016
+ const target = (0, import_node_path42.join)(overlay, entry.path);
43017
+ (0, import_node_fs45.mkdirSync)((0, import_node_path42.dirname)(target), { recursive: true });
43018
+ (0, import_node_fs45.writeFileSync)(target, entry.bytes);
42807
43019
  }
42808
43020
  return digestPackedFiles(overlay, entries.map((entry) => entry.path));
42809
43021
  };
42810
43022
  return computeDistDriftReceipt({ committed, tree, rebuilt, distTree, bom, digest });
42811
43023
  } finally {
42812
- (0, import_node_fs44.rmSync)(stage, { recursive: true, force: true });
43024
+ (0, import_node_fs45.rmSync)(stage, { recursive: true, force: true });
42813
43025
  }
42814
43026
  }
42815
43027
 
@@ -42888,7 +43100,7 @@ init_hub_auth();
42888
43100
 
42889
43101
  // src/schedules-lift-command.ts
42890
43102
  var import_promises8 = require("node:fs/promises");
42891
- var import_node_path42 = require("node:path");
43103
+ var import_node_path43 = require("node:path");
42892
43104
  init_clean_exit();
42893
43105
  init_cli_shared();
42894
43106
  var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
@@ -42917,7 +43129,7 @@ async function readWorkflowFiles(dir) {
42917
43129
  const files = [];
42918
43130
  for (const name of names.sort()) {
42919
43131
  if (!/\.ya?ml$/.test(name)) continue;
42920
- files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0, import_node_path42.join)(dir, name), "utf8") });
43132
+ files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises8.readFile)((0, import_node_path43.join)(dir, name), "utf8") });
42921
43133
  }
42922
43134
  return files;
42923
43135
  }
@@ -43000,8 +43212,8 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
43000
43212
 
43001
43213
  // src/spawn-policy-core.ts
43002
43214
  var import_node_child_process17 = require("node:child_process");
43003
- var import_node_fs45 = require("node:fs");
43004
- var import_node_path43 = require("node:path");
43215
+ var import_node_fs46 = require("node:fs");
43216
+ var import_node_path44 = require("node:path");
43005
43217
  var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
43006
43218
  var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
43007
43219
  var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
@@ -43087,7 +43299,7 @@ function runSpawnPolicy(root) {
43087
43299
  for (const file of files) {
43088
43300
  let raw;
43089
43301
  try {
43090
- raw = (0, import_node_fs45.readFileSync)((0, import_node_path43.join)(root, file), "utf8");
43302
+ raw = (0, import_node_fs46.readFileSync)((0, import_node_path44.join)(root, file), "utf8");
43091
43303
  } catch {
43092
43304
  continue;
43093
43305
  }
@@ -43107,19 +43319,19 @@ function runSpawnPolicy(root) {
43107
43319
  function registerDeveloperCommands(program3) {
43108
43320
  const rules = program3.command("rules").description("org-managed .gitignore delivery");
43109
43321
  rules.command("gitignore").option("--write", "upsert the managed block into .gitignore (default: check only, non-zero exit on drift)").option("--json", "machine-readable output").description("verify (or --write) this repo's org-managed .gitignore block matches the SSOT").action((opts) => {
43110
- const path2 = (0, import_node_path44.join)(process.cwd(), ".gitignore");
43111
- const current = (0, import_node_fs46.existsSync)(path2) ? (0, import_node_fs46.readFileSync)(path2, "utf8") : null;
43322
+ const path2 = (0, import_node_path45.join)(process.cwd(), ".gitignore");
43323
+ const current = (0, import_node_fs47.existsSync)(path2) ? (0, import_node_fs47.readFileSync)(path2, "utf8") : null;
43112
43324
  const plan = planManagedGitignore(current);
43113
43325
  const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
43114
43326
  if (opts.json) {
43115
- if (opts.write && plan.changed) (0, import_node_fs46.writeFileSync)(path2, plan.content, "utf8");
43327
+ if (opts.write && plan.changed) (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
43116
43328
  console.log(JSON.stringify(plan, null, 2));
43117
43329
  if (!opts.write && plan.changed) process.exitCode = 1;
43118
43330
  return;
43119
43331
  }
43120
43332
  if (opts.write) {
43121
43333
  if (plan.changed) {
43122
- (0, import_node_fs46.writeFileSync)(path2, plan.content, "utf8");
43334
+ (0, import_node_fs47.writeFileSync)(path2, plan.content, "utf8");
43123
43335
  console.log(`mmi-cli devops org rules gitignore: updated .gitignore (${drift})`);
43124
43336
  } else {
43125
43337
  console.log("mmi-cli devops org rules gitignore: up to date");
@@ -44753,8 +44965,8 @@ function checkHotfixCarries(options) {
44753
44965
  }
44754
44966
 
44755
44967
  // src/train-commands.ts
44756
- var import_node_fs47 = require("node:fs");
44757
- var import_node_path45 = require("node:path");
44968
+ var import_node_fs48 = require("node:fs");
44969
+ var import_node_path46 = require("node:path");
44758
44970
  init_cli_shared();
44759
44971
  init_clean_exit();
44760
44972
  init_client_version();
@@ -44769,7 +44981,7 @@ function resolveReleaseBumpIntent(raw) {
44769
44981
  }
44770
44982
  function readRepoVersion() {
44771
44983
  try {
44772
- return JSON.parse((0, import_node_fs47.readFileSync)((0, import_node_path45.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
44984
+ return JSON.parse((0, import_node_fs48.readFileSync)((0, import_node_path46.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
44773
44985
  } catch {
44774
44986
  return void 0;
44775
44987
  }
@@ -45735,7 +45947,7 @@ ${r.stderr ?? ""}`).catch(() => "");
45735
45947
  var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
45736
45948
  var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
45737
45949
  function envHealLockPath(home) {
45738
- return (0, import_node_path46.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
45950
+ return (0, import_node_path47.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
45739
45951
  }
45740
45952
  async function withEnvHealLock(what, run) {
45741
45953
  try {
@@ -45872,7 +46084,7 @@ function mmiDoctorDeps(opts = {}) {
45872
46084
  );
45873
46085
  const result = applyPluginCachePlan(
45874
46086
  plan,
45875
- (p) => (0, import_node_fs48.rmSync)(p, { recursive: true }),
46087
+ (p) => (0, import_node_fs49.rmSync)(p, { recursive: true }),
45876
46088
  stagingApplyFsGuard(configRoot)
45877
46089
  );
45878
46090
  return {
@@ -45907,7 +46119,7 @@ function mmiDoctorDeps(opts = {}) {
45907
46119
  // has no generated routing index would
45908
46120
  // get a permanent — demanding an artifact it never asked for.
45909
46121
  docsIndexState: (root) => {
45910
- if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return void 0;
46122
+ if (!(0, import_node_fs49.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return void 0;
45911
46123
  const real = createDocsIndexDeps(root);
45912
46124
  let docs;
45913
46125
  const listDocs = () => docs ??= real.listDocs();
@@ -45916,7 +46128,7 @@ function mmiDoctorDeps(opts = {}) {
45916
46128
  },
45917
46129
  // #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
45918
46130
  healDocsIndex: (root) => {
45919
- if (!(0, import_node_fs48.existsSync)((0, import_node_path46.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
46131
+ if (!(0, import_node_fs49.existsSync)((0, import_node_path47.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
45920
46132
  const real = createDocsIndexDeps(root);
45921
46133
  let docs;
45922
46134
  const listDocs = () => docs ??= real.listDocs();
@@ -46542,7 +46754,7 @@ project.command("set [owner/repo]").description("upsert project META (idempotent
46542
46754
  if (dupe) return fail(`org project set: KEY "${dupe}" was passed to both --var and --set; --set is an alias of --var, so pass each KEY once`);
46543
46755
  if (o.secretsFile) {
46544
46756
  try {
46545
- vars.push(`secrets=${(0, import_node_fs48.readFileSync)(o.secretsFile, "utf8")}`);
46757
+ vars.push(`secrets=${(0, import_node_fs49.readFileSync)(o.secretsFile, "utf8")}`);
46546
46758
  } catch (e) {
46547
46759
  return fail(`org project set: cannot read --secrets-file ${o.secretsFile}: ${e.message}`);
46548
46760
  }
@@ -46875,16 +47087,16 @@ function ciAuditDeps2() {
46875
47087
  // gate re-seed step is skipped gracefully rather than failing mid-run.
46876
47088
  readSeedFile: (path2) => {
46877
47089
  if (!root) return null;
46878
- const fullPath = (0, import_node_path46.join)(root, path2);
46879
- return (0, import_node_fs48.existsSync)(fullPath) ? (0, import_node_fs48.readFileSync)(fullPath, "utf8") : null;
47090
+ const fullPath = (0, import_node_path47.join)(root, path2);
47091
+ return (0, import_node_fs49.existsSync)(fullPath) ? (0, import_node_fs49.readFileSync)(fullPath, "utf8") : null;
46880
47092
  }
46881
47093
  };
46882
47094
  }
46883
47095
  function hubRoot2() {
46884
- const fromPkg = (0, import_node_path46.join)(__dirname, "..", "..");
47096
+ const fromPkg = (0, import_node_path47.join)(__dirname, "..", "..");
46885
47097
  const marker = "skills/bootstrap/seeds/manifest.json";
46886
- if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(fromPkg, marker))) return fromPkg;
46887
- if ((0, import_node_fs48.existsSync)((0, import_node_path46.join)(process.cwd(), marker))) return process.cwd();
47098
+ if ((0, import_node_fs49.existsSync)((0, import_node_path47.join)(fromPkg, marker))) return fromPkg;
47099
+ if ((0, import_node_fs49.existsSync)((0, import_node_path47.join)(process.cwd(), marker))) return process.cwd();
46888
47100
  return null;
46889
47101
  }
46890
47102
  registerQueryCommands(program2);
@@ -46984,10 +47196,10 @@ access.command("audit").description("audit collaborator roles + train-branch pus
46984
47196
  targets = resolution.targets;
46985
47197
  }
46986
47198
  const derivedMatrix = registryProjects ? accessMatrixFromProjects(registryProjects) : {};
46987
- const fileMatrix = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
47199
+ const fileMatrix = (0, import_node_fs49.existsSync)("access-matrix.json") ? loadAccessMatrix((0, import_node_fs49.readFileSync)("access-matrix.json", "utf8")) : {};
46988
47200
  const matrix = mergeAccessMatrix(fileMatrix, derivedMatrix);
46989
47201
  const dataAccess = registryProjects ? dataAccessContractsFromProjects(registryProjects) : { consumers: {} };
46990
- const sanctioned = (0, import_node_fs48.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs48.readFileSync)("access-matrix.json", "utf8")) : {};
47202
+ const sanctioned = (0, import_node_fs49.existsSync)("access-matrix.json") ? loadSanctionedAdmins((0, import_node_fs49.readFileSync)("access-matrix.json", "utf8")) : {};
46991
47203
  const report = await auditOrgAccess(targets, deps, matrix, dataAccess, sanctioned);
46992
47204
  console.log(o.json ? JSON.stringify(report, null, 2) : renderAccessReport(report));
46993
47205
  if (!report.ok) process.exitCode = 1;
@@ -47018,16 +47230,16 @@ function directoryBytes(path2) {
47018
47230
  let total = 0;
47019
47231
  let entries;
47020
47232
  try {
47021
- entries = (0, import_node_fs48.readdirSync)(path2, { withFileTypes: true });
47233
+ entries = (0, import_node_fs49.readdirSync)(path2, { withFileTypes: true });
47022
47234
  } catch {
47023
47235
  return 0;
47024
47236
  }
47025
47237
  for (const entry of entries) {
47026
- const child2 = (0, import_node_path46.join)(path2, entry.name);
47238
+ const child2 = (0, import_node_path47.join)(path2, entry.name);
47027
47239
  if (entry.isDirectory()) total += directoryBytes(child2);
47028
47240
  else {
47029
47241
  try {
47030
- total += (0, import_node_fs48.statSync)(child2).size;
47242
+ total += (0, import_node_fs49.statSync)(child2).size;
47031
47243
  } catch {
47032
47244
  }
47033
47245
  }
@@ -47035,25 +47247,25 @@ function directoryBytes(path2) {
47035
47247
  return total;
47036
47248
  }
47037
47249
  function listDirEntries(dir) {
47038
- return (0, import_node_fs48.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
47250
+ return (0, import_node_fs49.readdirSync)(dir, { withFileTypes: true }).map((d) => ({ name: d.name, isDirectory: d.isDirectory() }));
47039
47251
  }
47040
47252
  function readInstalledPluginRefs(configRoot) {
47041
47253
  const p = installedPluginsPathForConfig(configRoot);
47042
- if (!(0, import_node_fs48.existsSync)(p)) return [];
47254
+ if (!(0, import_node_fs49.existsSync)(p)) return [];
47043
47255
  try {
47044
- return installedPluginPaths((0, import_node_fs48.readFileSync)(p, "utf8"));
47256
+ return installedPluginPaths((0, import_node_fs49.readFileSync)(p, "utf8"));
47045
47257
  } catch {
47046
47258
  return null;
47047
47259
  }
47048
47260
  }
47049
47261
  function pluginCacheFsDeps(configRoot, dirBytes) {
47050
47262
  return {
47051
- exists: (p) => (0, import_node_fs48.existsSync)(p),
47052
- listVersionDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
47263
+ exists: (p) => (0, import_node_fs49.existsSync)(p),
47264
+ listVersionDirs: (root) => (0, import_node_fs49.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => d.name),
47053
47265
  dirBytes,
47054
- listStagingDirs: (root) => (0, import_node_fs48.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
47266
+ listStagingDirs: (root) => (0, import_node_fs49.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
47055
47267
  try {
47056
- return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path46.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs48.statSync)(p).mtimeMs) };
47268
+ return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path47.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs49.statSync)(p).mtimeMs) };
47057
47269
  } catch {
47058
47270
  return { name: d.name, mtimeMs: Date.now() };
47059
47271
  }
@@ -47067,10 +47279,10 @@ function stagingApplyFsGuard(configRoot) {
47067
47279
  return {
47068
47280
  referencedPaths: () => readInstalledPluginRefs(configRoot),
47069
47281
  mtimeMs: (name) => {
47070
- const p = (0, import_node_path46.join)(stagingRoot, name);
47071
- if (!(0, import_node_fs48.existsSync)(p)) return null;
47282
+ const p = (0, import_node_path47.join)(stagingRoot, name);
47283
+ if (!(0, import_node_fs49.existsSync)(p)) return null;
47072
47284
  try {
47073
- return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs48.statSync)(q).mtimeMs);
47285
+ return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs49.statSync)(q).mtimeMs);
47074
47286
  } catch {
47075
47287
  return null;
47076
47288
  }
@@ -47096,7 +47308,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
47096
47308
  { withBytes: true, configRoot, includeStaging: surface !== "codex" }
47097
47309
  );
47098
47310
  const anythingToDelete = plan.prune.length > 0 || plan.staging.length > 0;
47099
- const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs48.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
47311
+ const result = o.apply && anythingToDelete ? applyPluginCachePlan(plan, (p) => (0, import_node_fs49.rmSync)(p, { recursive: true, force: true }), stagingApplyFsGuard(configRoot)) : void 0;
47100
47312
  const warnings = plan.prune.length > 0 ? [CONCURRENT_SESSION_WARNING] : [];
47101
47313
  if (o.json) console.log(JSON.stringify({ ...plan, warnings, applied: result ?? null }));
47102
47314
  else console.log(renderPluginCachePlan(plan, result));