@mutmutco/cli 4.6.35 → 4.6.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/main.cjs +640 -326
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -1229,8 +1229,6 @@ var init_house_map = __esm({
|
|
|
1229
1229
|
// --- harbour — declared lanes -------------------------------------------------------------------
|
|
1230
1230
|
"org schedules": "harbour",
|
|
1231
1231
|
// register/run/park schedule rows under the one lane contract
|
|
1232
|
-
intercom: "harbour",
|
|
1233
|
-
// #9184: the guest coordination lane to the MM Coordinator — a bounded lane, not a claim on org truth
|
|
1234
1232
|
// --- devops — shipping --------------------------------------------------------------------------
|
|
1235
1233
|
pr: "devops",
|
|
1236
1234
|
read: "devops",
|
|
@@ -1279,6 +1277,11 @@ var init_house_map = __esm({
|
|
|
1279
1277
|
pickup: "learning",
|
|
1280
1278
|
// cloud-agent adoption gate (#5708)
|
|
1281
1279
|
// --- core — the front door itself ---------------------------------------------------------------
|
|
1280
|
+
// #9993: `intercom` is the guest's own coordination door, not a declared org lane — it reads and
|
|
1281
|
+
// writes nothing of this org's truth (no schedules, no registry, no board), it talks to the Jerv
|
|
1282
|
+
// Gateway as this caller's own GitHub identity. So it is core: `mmi-cli intercom guest …`, unprefixed.
|
|
1283
|
+
// The old `harbour intercom guest …` spelling still runs through HOUSE_ALIASES below.
|
|
1284
|
+
intercom: "core",
|
|
1282
1285
|
commands: "core",
|
|
1283
1286
|
whoami: "core",
|
|
1284
1287
|
spawn: "core",
|
|
@@ -1303,7 +1306,9 @@ var init_house_map = __esm({
|
|
|
1303
1306
|
HOUSE_ALIASES = {
|
|
1304
1307
|
issue: ["devops"],
|
|
1305
1308
|
// filing/managing issues is oracle, but reads as shipping work
|
|
1306
|
-
"issue create": ["devops"]
|
|
1309
|
+
"issue create": ["devops"],
|
|
1310
|
+
intercom: ["harbour"]
|
|
1311
|
+
// #9993: `intercom` moved out of harbour to core; the old spelling still routes
|
|
1307
1312
|
};
|
|
1308
1313
|
}
|
|
1309
1314
|
});
|
|
@@ -13690,7 +13695,7 @@ function isAgentScratchPath(path2) {
|
|
|
13690
13695
|
return /^tmp_[^/]+$/.test(normalized);
|
|
13691
13696
|
}
|
|
13692
13697
|
var PUSH_WALL_AGENT_CONFIG_DIRS = [".cursor/rules/", ".codex/", ".agents/"];
|
|
13693
|
-
var LIVE_SESSION_DIRS = [".jerv/", ".pi/"];
|
|
13698
|
+
var LIVE_SESSION_DIRS = [".jerv/", ".pi/", "review-state/"];
|
|
13694
13699
|
function pathUnderDirPrefix(path2, dir) {
|
|
13695
13700
|
return path2 === dir || path2 === dir.slice(0, -1) || path2.startsWith(dir) || path2.includes(`/${dir}`);
|
|
13696
13701
|
}
|
|
@@ -14549,7 +14554,7 @@ function scanWorktreeTmpEvidence(worktreePath, newerThanMs, deps = {}) {
|
|
|
14549
14554
|
function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
14550
14555
|
const copyFile = deps.copyFile ?? import_node_fs12.copyFileSync;
|
|
14551
14556
|
const fileSize = deps.fileSize ?? ((path2) => (0, import_node_fs12.statSync)(path2).size);
|
|
14552
|
-
const
|
|
14557
|
+
const writeFile5 = deps.writeFile ?? ((path2, text) => (0, import_node_fs12.writeFileSync)(path2, text));
|
|
14553
14558
|
const mkdirp = deps.mkdirp ?? ((path2) => {
|
|
14554
14559
|
(0, import_node_fs12.mkdirSync)(path2, { recursive: true });
|
|
14555
14560
|
});
|
|
@@ -14576,7 +14581,7 @@ function archiveWorktreeTmpArtifacts(args, deps = {}) {
|
|
|
14576
14581
|
bytes += copied;
|
|
14577
14582
|
}
|
|
14578
14583
|
const manifest = (0, import_node_path9.join)((0, import_node_path9.dirname)(dest), "tmp-manifest.json");
|
|
14579
|
-
|
|
14584
|
+
writeFile5(manifest, `${JSON.stringify({ files: scan.entries.map(({ relPath, bytes: b }) => ({ relPath, bytes: b })), bytes, excluded: scan.excluded, skippedLinks: scan.links }, null, 2)}
|
|
14580
14585
|
`);
|
|
14581
14586
|
return { status: "archived", path: dest, runScope, entries: scan.entries.length, bytes, manifest, excluded: scan.excluded, skippedLinks: scan.links };
|
|
14582
14587
|
} catch (e) {
|
|
@@ -15261,8 +15266,8 @@ function resolveVerbAliasShim(argv) {
|
|
|
15261
15266
|
}
|
|
15262
15267
|
|
|
15263
15268
|
// src/command-composition.ts
|
|
15264
|
-
var
|
|
15265
|
-
var
|
|
15269
|
+
var import_node_os29 = require("node:os");
|
|
15270
|
+
var import_node_path65 = require("node:path");
|
|
15266
15271
|
|
|
15267
15272
|
// src/board-read.ts
|
|
15268
15273
|
var import_node_fs18 = require("node:fs");
|
|
@@ -15366,13 +15371,6 @@ async function fetchHubBoardSnapshot(request, deps) {
|
|
|
15366
15371
|
// src/board-read.ts
|
|
15367
15372
|
init_github_quota();
|
|
15368
15373
|
|
|
15369
|
-
// src/claim-marker-client.ts
|
|
15370
|
-
init_github_client();
|
|
15371
|
-
init_github_quota();
|
|
15372
|
-
|
|
15373
|
-
// src/pr-checks-rest.ts
|
|
15374
|
-
init_cli_shared();
|
|
15375
|
-
|
|
15376
15374
|
// ../shared/github-quota-scope.ts
|
|
15377
15375
|
var import_node_crypto4 = require("node:crypto");
|
|
15378
15376
|
function appQuotaScope(appId, installationId, origin = "https://api.github.com", resource = "graphql") {
|
|
@@ -15737,6 +15735,13 @@ async function activateAppActor(commandPath4, env, mint, note = (line) => proces
|
|
|
15737
15735
|
return "app";
|
|
15738
15736
|
}
|
|
15739
15737
|
|
|
15738
|
+
// src/claim-marker-client.ts
|
|
15739
|
+
init_github_client();
|
|
15740
|
+
init_github_quota();
|
|
15741
|
+
|
|
15742
|
+
// src/pr-checks-rest.ts
|
|
15743
|
+
init_cli_shared();
|
|
15744
|
+
|
|
15740
15745
|
// src/merge-ci-policy.ts
|
|
15741
15746
|
function resolveMergeCiPolicy(input) {
|
|
15742
15747
|
if (input.registryCi === "none") {
|
|
@@ -17174,9 +17179,11 @@ async function fetchRestCorePool(gh2 = defaultGhApi, nowMs = Date.now()) {
|
|
|
17174
17179
|
// src/claim-marker-client.ts
|
|
17175
17180
|
var claimWriteTokenProvider;
|
|
17176
17181
|
var claimWriteTokenOnce;
|
|
17182
|
+
var notedPersonalClaimWrite = false;
|
|
17177
17183
|
function setClaimWriteTokenProvider(provider) {
|
|
17178
17184
|
claimWriteTokenProvider = provider;
|
|
17179
17185
|
claimWriteTokenOnce = void 0;
|
|
17186
|
+
notedPersonalClaimWrite = false;
|
|
17180
17187
|
}
|
|
17181
17188
|
async function selectClaimWriteClient(client, appClient) {
|
|
17182
17189
|
if (appClient) return appClient;
|
|
@@ -17187,15 +17194,26 @@ async function selectClaimWriteClient(client, appClient) {
|
|
|
17187
17194
|
token = await claimWriteTokenOnce;
|
|
17188
17195
|
} catch (e) {
|
|
17189
17196
|
claimWriteTokenOnce = void 0;
|
|
17197
|
+
if (e instanceof AppActorError && e.code === "vault-denied" && process.env.MMI_ACTOR?.trim() !== "app") return personalClaimWrite(client);
|
|
17190
17198
|
const detail = e instanceof Error ? e.message : String(e);
|
|
17191
17199
|
throw new Error(`${detail} \u2014 refusing personal-token fallback for claim write (#9511)`);
|
|
17192
17200
|
}
|
|
17193
17201
|
if (!token) {
|
|
17194
17202
|
claimWriteTokenOnce = void 0;
|
|
17195
|
-
|
|
17203
|
+
if (process.env.MMI_ACTOR?.trim() === "app") {
|
|
17204
|
+
throw new Error("app actor: claim write token unavailable \u2014 refusing personal-token fallback for claim write (#9511)");
|
|
17205
|
+
}
|
|
17206
|
+
return personalClaimWrite(client);
|
|
17196
17207
|
}
|
|
17197
17208
|
return createGitHubClient({ token: async () => token });
|
|
17198
17209
|
}
|
|
17210
|
+
function personalClaimWrite(client) {
|
|
17211
|
+
if (!notedPersonalClaimWrite) {
|
|
17212
|
+
notedPersonalClaimWrite = true;
|
|
17213
|
+
process.stderr.write("note: no App route on this host (no MMI-Hub vault access) \u2014 claim writes go as your own GitHub login\n");
|
|
17214
|
+
}
|
|
17215
|
+
return client;
|
|
17216
|
+
}
|
|
17199
17217
|
async function selectLivenessClient(client, appClient) {
|
|
17200
17218
|
if (appClient) return appClient;
|
|
17201
17219
|
let token;
|
|
@@ -22745,6 +22763,7 @@ mutation($projectId: ID!, $itemId: ID!) {
|
|
|
22745
22763
|
item { id }
|
|
22746
22764
|
}
|
|
22747
22765
|
}`;
|
|
22766
|
+
var BOARD_WRITE_REFUSAL_TYPES = /* @__PURE__ */ new Set(["INSUFFICIENT_SCOPES", "FORBIDDEN", "NOT_FOUND"]);
|
|
22748
22767
|
async function updateItemSingleSelect(client, projectId, itemId, fieldId, optionId) {
|
|
22749
22768
|
if (process.env.MMI_ACTOR?.trim() === "app") {
|
|
22750
22769
|
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
@@ -22771,10 +22790,14 @@ async function updateItemSingleSelect(client, projectId, itemId, fieldId, option
|
|
|
22771
22790
|
return { credential: "user" };
|
|
22772
22791
|
} catch (error) {
|
|
22773
22792
|
const errors = error.graphqlErrors;
|
|
22774
|
-
if (errors?.length && errors.every((entry) => entry.type
|
|
22793
|
+
if (errors?.length && errors.every((entry) => entry.type !== void 0 && BOARD_WRITE_REFUSAL_TYPES.has(entry.type))) {
|
|
22775
22794
|
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
22776
|
-
|
|
22777
|
-
|
|
22795
|
+
try {
|
|
22796
|
+
await writeHubBoardField2({ projectId, itemId, fieldId, optionId });
|
|
22797
|
+
return { credential: "app_installation" };
|
|
22798
|
+
} catch {
|
|
22799
|
+
throw error;
|
|
22800
|
+
}
|
|
22778
22801
|
}
|
|
22779
22802
|
if (isGitHubRateLimitError(error)) {
|
|
22780
22803
|
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
@@ -25284,6 +25307,8 @@ var MANAGED_GITIGNORE_LINES = [
|
|
|
25284
25307
|
// (measured on the v3.120.0 Hub train), with no legal resolution: committing another host's runtime
|
|
25285
25308
|
// state is not an option, so the operator's only move was to park the directory outside the repo.
|
|
25286
25309
|
".pi/",
|
|
25310
|
+
// #10003: reviewer worktrees — never committable, regenerate during review (same runtime class as `.pi/`).
|
|
25311
|
+
"/review-state/",
|
|
25287
25312
|
".aws-sam/",
|
|
25288
25313
|
// jerv-cli lease markers are ephemeral runtime state and never tracked. Hub#2586.
|
|
25289
25314
|
".jerv-lease.json",
|
|
@@ -25409,7 +25434,7 @@ function extractForwardRefs(markdown) {
|
|
|
25409
25434
|
});
|
|
25410
25435
|
return refs;
|
|
25411
25436
|
}
|
|
25412
|
-
function checkPins(root,
|
|
25437
|
+
function checkPins(root, readFile11, docs) {
|
|
25413
25438
|
const findings = [];
|
|
25414
25439
|
for (const [doc, markdown] of Object.entries(docs)) {
|
|
25415
25440
|
for (const pin of extractPins(markdown)) {
|
|
@@ -25417,7 +25442,7 @@ function checkPins(root, readFile10, docs) {
|
|
|
25417
25442
|
findings.push({ kind: "malformed-pin", doc, line: pin.line, detail: pin.text });
|
|
25418
25443
|
continue;
|
|
25419
25444
|
}
|
|
25420
|
-
const source =
|
|
25445
|
+
const source = readFile11((0, import_node_path16.join)(root, pin.file));
|
|
25421
25446
|
if (source == null) {
|
|
25422
25447
|
findings.push({ kind: "missing-test", doc, line: pin.line, detail: pin.file });
|
|
25423
25448
|
continue;
|
|
@@ -25713,15 +25738,15 @@ function checkRunbookCoverage(docs, base, git3) {
|
|
|
25713
25738
|
}
|
|
25714
25739
|
return findings;
|
|
25715
25740
|
}
|
|
25716
|
-
function checkSeedRunbookReview(root, base,
|
|
25717
|
-
const manifestJson =
|
|
25741
|
+
function checkSeedRunbookReview(root, base, readFile11, git3) {
|
|
25742
|
+
const manifestJson = readFile11((0, import_node_path16.join)(root, "skills/bootstrap/seeds/manifest.json"));
|
|
25718
25743
|
if (!manifestJson) return [];
|
|
25719
25744
|
const changed = new Set(git3(["diff", "--name-only", `${base}...HEAD`]).split(/\r?\n/).filter(Boolean));
|
|
25720
25745
|
const touched = loadBootstrapSeeds(manifestJson).seeds.filter((seed) => isPropagatableSeed(seed) && changed.has(seedSourcePath(seed)));
|
|
25721
25746
|
if (!touched.length) return [];
|
|
25722
25747
|
let declarations = null;
|
|
25723
25748
|
try {
|
|
25724
|
-
declarations = JSON.parse(
|
|
25749
|
+
declarations = JSON.parse(readFile11((0, import_node_path16.join)(root, RUNBOOK_UNAFFECTED_PATH)) ?? "null");
|
|
25725
25750
|
} catch {
|
|
25726
25751
|
declarations = null;
|
|
25727
25752
|
}
|
|
@@ -25808,12 +25833,12 @@ function defaultTrackedFiles(root, firstSegments, exec3 = import_node_child_proc
|
|
|
25808
25833
|
throw error;
|
|
25809
25834
|
}
|
|
25810
25835
|
}
|
|
25811
|
-
function mergeGroupRunbookMessages(root, deps,
|
|
25836
|
+
function mergeGroupRunbookMessages(root, deps, readFile11, warnings) {
|
|
25812
25837
|
const env = deps.env ?? process.env;
|
|
25813
25838
|
if (env.GITHUB_EVENT_NAME !== "merge_group") return "";
|
|
25814
25839
|
let source = "merge_group event payload";
|
|
25815
25840
|
try {
|
|
25816
|
-
const event = JSON.parse(
|
|
25841
|
+
const event = JSON.parse(readFile11(env.GITHUB_EVENT_PATH ?? "") ?? "");
|
|
25817
25842
|
const match = /^refs\/heads\/gh-readonly-queue\/.+\/pr-([1-9]\d*)-[a-f0-9]+$/.exec(event.merge_group?.head_ref ?? "");
|
|
25818
25843
|
const repo = env.GITHUB_REPOSITORY;
|
|
25819
25844
|
if (!match || !repo || !/^[\w.-]+\/[\w.-]+$/.test(repo)) throw new Error("invalid queue source");
|
|
@@ -25836,7 +25861,7 @@ function mergeGroupRunbookMessages(root, deps, readFile10, warnings) {
|
|
|
25836
25861
|
}
|
|
25837
25862
|
}
|
|
25838
25863
|
function runDocRefs(root, deps = {}) {
|
|
25839
|
-
const
|
|
25864
|
+
const readFile11 = deps.readFile ?? readFileOrNull;
|
|
25840
25865
|
const exists = deps.exists ?? import_node_fs19.existsSync;
|
|
25841
25866
|
const listDocs = deps.listDocs ?? defaultListDocs;
|
|
25842
25867
|
const isIgnored = deps.isIgnored ?? ((paths) => defaultIsIgnored(root, paths));
|
|
@@ -25850,11 +25875,11 @@ function runDocRefs(root, deps = {}) {
|
|
|
25850
25875
|
const walked = listDocs(root);
|
|
25851
25876
|
const ignoredDocs = walked.length ? isIgnored(walked) : /* @__PURE__ */ new Set();
|
|
25852
25877
|
const docs = Object.fromEntries(
|
|
25853
|
-
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel,
|
|
25878
|
+
walked.filter((rel) => !ignoredDocs.has(rel)).map((rel) => [rel, readFile11((0, import_node_path16.join)(root, rel))]).filter(([rel, body]) => body != null && (!deps.runbooksOnly || isRunbook(rel, body)))
|
|
25854
25879
|
);
|
|
25855
25880
|
const refResult = checkRefs(root, { exists, isIgnored, trackedFirstSegments }, docs);
|
|
25856
25881
|
const findings = [
|
|
25857
|
-
...checkPins(root,
|
|
25882
|
+
...checkPins(root, readFile11, docs).findings,
|
|
25858
25883
|
...refResult.findings
|
|
25859
25884
|
];
|
|
25860
25885
|
if (commandPaths == null) {
|
|
@@ -25868,7 +25893,7 @@ function runDocRefs(root, deps = {}) {
|
|
|
25868
25893
|
findings.push(...checkCommands(docs, commandPaths).findings);
|
|
25869
25894
|
}
|
|
25870
25895
|
const runbooks = Object.fromEntries(Object.entries(docs).filter(([doc, body]) => isRunbook(doc, body)));
|
|
25871
|
-
findings.push(...checkRunbookClaims(root, runbooks, { readFile:
|
|
25896
|
+
findings.push(...checkRunbookClaims(root, runbooks, { readFile: readFile11, exists, isIgnored, trackedFirstSegments, commandPaths, commandOptions: deps.commandOptions, commandSource: deps.commandSource }));
|
|
25872
25897
|
const warnings = [...refResult.warnings];
|
|
25873
25898
|
if (deps.runbooksOnly && !Object.keys(runbooks).length) {
|
|
25874
25899
|
warnings.push({ kind: "runbook-missing", doc: "docs/Guides/operator.md", line: 0, detail: "no operator runbook or <!-- runbook --> document exists" });
|
|
@@ -25876,9 +25901,9 @@ function runDocRefs(root, deps = {}) {
|
|
|
25876
25901
|
if (deps.base) {
|
|
25877
25902
|
const git3 = deps.git ?? ((args) => (0, import_node_child_process6.execFileSync)("git", args, { cwd: root, encoding: "utf8", maxBuffer: CHECK_IGNORE_MAX_BUFFER, windowsHide: true }));
|
|
25878
25903
|
const stale = checkRunbookCoverage(runbooks, deps.base, git3);
|
|
25879
|
-
const seedStale = checkSeedRunbookReview(root, deps.base,
|
|
25904
|
+
const seedStale = checkSeedRunbookReview(root, deps.base, readFile11, git3);
|
|
25880
25905
|
const messages = git3(["log", "--format=%B", `${deps.base}..HEAD`]);
|
|
25881
|
-
const sourceMessages = stale.length || seedStale.length ? mergeGroupRunbookMessages(root, deps,
|
|
25906
|
+
const sourceMessages = stale.length || seedStale.length ? mergeGroupRunbookMessages(root, deps, readFile11, warnings) : "";
|
|
25882
25907
|
const allMessages = `${messages}
|
|
25883
25908
|
${sourceMessages}`;
|
|
25884
25909
|
const override = /^Runbook-Unaffected:[ \t]*\S.*$/m.test(allMessages);
|
|
@@ -26837,22 +26862,22 @@ function renderBootstrapAncillaryPlan(labels, environments, exceptions = []) {
|
|
|
26837
26862
|
...exceptions.map(({ name, detail }) => ` OK environment ${name} (${detail})`)
|
|
26838
26863
|
].join("\n");
|
|
26839
26864
|
}
|
|
26840
|
-
function resolveSeedContent(seed, vars,
|
|
26841
|
-
if (seed.source === "self") return
|
|
26865
|
+
function resolveSeedContent(seed, vars, readFile11) {
|
|
26866
|
+
if (seed.source === "self") return readFile11(seed.target);
|
|
26842
26867
|
if (seed.source.startsWith("seed:")) {
|
|
26843
|
-
const tmpl =
|
|
26868
|
+
const tmpl = readFile11(`skills/bootstrap/seeds/${seed.source.slice("seed:".length)}`);
|
|
26844
26869
|
return tmpl == null ? null : renderSeed(tmpl, vars);
|
|
26845
26870
|
}
|
|
26846
26871
|
return null;
|
|
26847
26872
|
}
|
|
26848
|
-
function resolveSeedWriteContent(seed, vars,
|
|
26873
|
+
function resolveSeedWriteContent(seed, vars, readFile11, remoteContent) {
|
|
26849
26874
|
if (!seed.managedBlock) {
|
|
26850
|
-
return { ok: true, content: resolveSeedContent(seed, vars,
|
|
26875
|
+
return { ok: true, content: resolveSeedContent(seed, vars, readFile11), managed: seed.source === "managed-block" };
|
|
26851
26876
|
}
|
|
26852
|
-
const base = remoteContent ?? resolveSeedContent(seed, vars,
|
|
26877
|
+
const base = remoteContent ?? resolveSeedContent(seed, vars, readFile11);
|
|
26853
26878
|
if (base == null) return { ok: true, content: null, managed: true };
|
|
26854
26879
|
const blockSeed = { ...seed, source: seed.managedBlock.source, managedBlock: void 0 };
|
|
26855
|
-
const desired = resolveSeedContent(blockSeed, vars,
|
|
26880
|
+
const desired = resolveSeedContent(blockSeed, vars, readFile11);
|
|
26856
26881
|
if (desired == null) return { ok: true, content: null, managed: true };
|
|
26857
26882
|
const result = upsertManagedSeedBlock(base, desired, seed.managedBlock.begin, seed.managedBlock.end);
|
|
26858
26883
|
return result.ok ? { ok: true, content: result.content, managed: true } : { ok: false, reason: result.reason, managed: true };
|
|
@@ -28367,10 +28392,10 @@ var rollout_plan_default = {
|
|
|
28367
28392
|
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)."
|
|
28368
28393
|
},
|
|
28369
28394
|
baseline: {
|
|
28370
|
-
version: "4.6.
|
|
28371
|
-
tag: "v4.6.
|
|
28372
|
-
commit: "
|
|
28373
|
-
npm: "@mutmutco/cli@4.6.
|
|
28395
|
+
version: "4.6.37",
|
|
28396
|
+
tag: "v4.6.37",
|
|
28397
|
+
commit: "94211a24e48a",
|
|
28398
|
+
npm: "@mutmutco/cli@4.6.37"
|
|
28374
28399
|
},
|
|
28375
28400
|
exitCriterion: "fleet-n-of-n",
|
|
28376
28401
|
hubOnlyShortcut: "forbidden",
|
|
@@ -28387,14 +28412,14 @@ var rollout_plan_default = {
|
|
|
28387
28412
|
repo: "mutmutco/mmi-hub",
|
|
28388
28413
|
role: "canary",
|
|
28389
28414
|
schedule: "train",
|
|
28390
|
-
v3Target: "v4.6.
|
|
28415
|
+
v3Target: "v4.6.37"
|
|
28391
28416
|
}
|
|
28392
28417
|
],
|
|
28393
28418
|
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.",
|
|
28394
28419
|
rollback: {
|
|
28395
28420
|
independent: true,
|
|
28396
|
-
mechanism: "npm dist-tag latest -> 4.6.
|
|
28397
|
-
v3Target: "v4.6.
|
|
28421
|
+
mechanism: "npm dist-tag latest -> 4.6.37 and redeploy the Hub Lambda from tag v4.6.37 (94211a24e48a); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
28422
|
+
v3Target: "v4.6.37 (@mutmutco/cli@4.6.37, tag commit 94211a24e48a \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
28398
28423
|
}
|
|
28399
28424
|
},
|
|
28400
28425
|
{
|
|
@@ -43417,8 +43442,8 @@ function annotateChangeMeaning(changed, policy, read) {
|
|
|
43417
43442
|
function isMeaningfulRow(file) {
|
|
43418
43443
|
return file.meaningful !== false;
|
|
43419
43444
|
}
|
|
43420
|
-
function loadPolicy(root,
|
|
43421
|
-
const raw =
|
|
43445
|
+
function loadPolicy(root, readFile11 = readFileOrNull2) {
|
|
43446
|
+
const raw = readFile11((0, import_node_path30.join)(root, POLICY_FILE));
|
|
43422
43447
|
if (raw == null) return { mandatory: [], declared: false };
|
|
43423
43448
|
return parsePolicy(raw, POLICY_FILE);
|
|
43424
43449
|
}
|
|
@@ -44155,12 +44180,16 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
44155
44180
|
receipt = { ...receipt, state: "pending", uuid: details.uuid };
|
|
44156
44181
|
}
|
|
44157
44182
|
const sleep2 = options.sleep ?? ((ms) => new Promise((resolve8) => setTimeout(resolve8, ms)));
|
|
44158
|
-
|
|
44159
|
-
|
|
44183
|
+
const confirmDelays = [0, 1e3, 2e3, 4e3, 8e3, 15e3, 15e3, 15e3];
|
|
44184
|
+
let readFailure;
|
|
44185
|
+
for (const delay of confirmDelays) {
|
|
44186
|
+
if (delay) await sleep2(delay);
|
|
44187
|
+
readFailure = void 0;
|
|
44160
44188
|
try {
|
|
44161
44189
|
response = admissionResponse(await read([`repos/${repo}/pulls/${pr}/merge-async/${receipt.uuid}`, "--include", ...ASYNC_HEADERS]));
|
|
44162
44190
|
} catch {
|
|
44163
|
-
|
|
44191
|
+
readFailure = "the saved operation cannot be read (including expired results)";
|
|
44192
|
+
continue;
|
|
44164
44193
|
}
|
|
44165
44194
|
if (response.code !== 200) return reconcile(`the saved operation returned HTTP ${response.code}`);
|
|
44166
44195
|
const { status, details } = response.body;
|
|
@@ -44202,6 +44231,7 @@ async function submitQueueAdmission(pr, repo, head, read, write, options, resume
|
|
|
44202
44231
|
if (receipt.head !== head) return reconcile("the previous head completed admission; inspect current head and membership before continuing");
|
|
44203
44232
|
return reconcile(`operation ${receipt.uuid} reported ${status}, but matching-head membership or merged state is unconfirmed`, status === "enqueued");
|
|
44204
44233
|
}
|
|
44234
|
+
if (readFailure) return reconcile(readFailure);
|
|
44205
44235
|
return markReenqueued({
|
|
44206
44236
|
mergeStatus: "queue-admission-pending",
|
|
44207
44237
|
retryable: false,
|
|
@@ -44424,8 +44454,8 @@ async function abandonQueueAdmission(pr, repo, options = {}) {
|
|
|
44424
44454
|
}
|
|
44425
44455
|
const receipt = journal.receipt;
|
|
44426
44456
|
if (!receipt) return refuse("no queue-admission receipt exists for this PR; nothing to abandon");
|
|
44427
|
-
if (!["pending", "enqueued"].includes(receipt.state)) {
|
|
44428
|
-
return refuse(`the saved admission is '${receipt.state}', not a stuck non-terminal 'pending'/'enqueued' receipt; nothing to abandon`);
|
|
44457
|
+
if (!["pending", "enqueued"].includes(receipt.state) && !(receipt.state === "dispatching" && !receipt.uuid)) {
|
|
44458
|
+
return refuse(`the saved admission is '${receipt.state}'${receipt.uuid ? ` with operation ${receipt.uuid}` : ""}, not a stuck non-terminal 'pending'/'enqueued' receipt; nothing to abandon`);
|
|
44429
44459
|
}
|
|
44430
44460
|
let snapshot;
|
|
44431
44461
|
try {
|
|
@@ -45759,20 +45789,20 @@ function buildPrLifecycle(state, manifest, joins) {
|
|
|
45759
45789
|
if (member.pr !== state.number) continue;
|
|
45760
45790
|
if (!member.admission_event_id) continue;
|
|
45761
45791
|
const ep = episodes.find((x) => x.episode_id === member.admission_event_id);
|
|
45762
|
-
const
|
|
45763
|
-
if (!
|
|
45792
|
+
const join55 = joins.find((j) => j.run_id === run.run_id && j.run_attempt === run.run_attempt && j.pr === member.pr && j.admission_event_id === member.admission_event_id);
|
|
45793
|
+
if (!join55) continue;
|
|
45764
45794
|
if (!ep) {
|
|
45765
45795
|
if (state.status === "complete") {
|
|
45766
|
-
|
|
45767
|
-
|
|
45796
|
+
join55.status = "unresolved";
|
|
45797
|
+
join55.reason = "admission-event-not-in-history";
|
|
45768
45798
|
} else {
|
|
45769
|
-
|
|
45770
|
-
|
|
45799
|
+
join55.status = "unresolved";
|
|
45800
|
+
join55.reason = "history-incomplete";
|
|
45771
45801
|
}
|
|
45772
45802
|
continue;
|
|
45773
45803
|
}
|
|
45774
|
-
|
|
45775
|
-
delete
|
|
45804
|
+
join55.status = "joined";
|
|
45805
|
+
delete join55.reason;
|
|
45776
45806
|
ep.runs.push({ run_id: run.run_id, run_attempt: run.run_attempt, head_sha: run.head_sha });
|
|
45777
45807
|
}
|
|
45778
45808
|
}
|
|
@@ -46149,6 +46179,15 @@ async function attachOnIntegrationRefusal(detail, cfg, contentNodeId, attach = a
|
|
|
46149
46179
|
return { warning: `board attach refused: the gh login is an App installation token without Projects access (${detail}) and the Hub App leg failed (${e.message}). If the Hub reports the same refusal, ${PROJECTS_PERMISSION_HINT}` };
|
|
46150
46180
|
}
|
|
46151
46181
|
}
|
|
46182
|
+
var ATTACH_AUTHORITY_REFUSAL = /FORBIDDEN|NOT_FOUND|Resource not accessible|missing required scopes|insufficient (?:permissions?|scope)|Could not resolve to a node|does not have (?:access|permission)/i;
|
|
46183
|
+
async function attachOnAuthorityRefusal(detail, cfg, contentNodeId, attach = attachViaHubApp) {
|
|
46184
|
+
if (!ATTACH_AUTHORITY_REFUSAL.test(detail)) return void 0;
|
|
46185
|
+
try {
|
|
46186
|
+
return { projectItemId: await attach(cfg, contentNodeId) };
|
|
46187
|
+
} catch (e) {
|
|
46188
|
+
return { warning: `${detail}; the Hub attach also refused (${e.message}) \u2014 attach needs org-owner, repo-admin or repository write authority on the board's repository` };
|
|
46189
|
+
}
|
|
46190
|
+
}
|
|
46152
46191
|
async function issueNodeIdForAttach(repo, number, ghView, client) {
|
|
46153
46192
|
try {
|
|
46154
46193
|
return (await ghView()).trim();
|
|
@@ -51627,7 +51666,7 @@ function registerBootstrapCommands(program3) {
|
|
|
51627
51666
|
const slug = parsedRepo.slug;
|
|
51628
51667
|
const onlyTarget = o.fromConfig && o.only.trim() === "gate.yml" ? ".github/workflows/gate.yml" : o.only.trim();
|
|
51629
51668
|
const gh2 = async (args) => execFileP("gh", args, { timeout: 2e4 });
|
|
51630
|
-
const
|
|
51669
|
+
const readFile11 = (p) => (0, import_node_fs40.existsSync)(p) ? (0, import_node_fs40.readFileSync)(p, "utf8") : null;
|
|
51631
51670
|
const enc = (p) => p.split("/").map(encodeURIComponent).join("/");
|
|
51632
51671
|
const putSeed = async (target, content, ref, sha) => {
|
|
51633
51672
|
const tmp = (0, import_node_path37.join)((0, import_node_os21.tmpdir)(), `mmi-seed-${process.pid}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}.json`);
|
|
@@ -51799,7 +51838,7 @@ function registerBootstrapCommands(program3) {
|
|
|
51799
51838
|
registryMeta?.requiredCheckBranches,
|
|
51800
51839
|
registryMeta?.requiredChecks
|
|
51801
51840
|
);
|
|
51802
|
-
const rendered = resolveSeedContent(gateSeed, gateVars,
|
|
51841
|
+
const rendered = resolveSeedContent(gateSeed, gateVars, readFile11);
|
|
51803
51842
|
if (rendered === null || missingPlaceholders(rendered).length) return failGraceful("bootstrap apply: registry gate template is unreadable or has unfilled placeholders");
|
|
51804
51843
|
const base = (await readTargetedSeedFiles(repo, scopedPlan, onlyTarget, scopedPlan.baseSha, controlClient)).base?.content ?? null;
|
|
51805
51844
|
configGateAction = planGateFromConfig(base, rendered);
|
|
@@ -51903,7 +51942,7 @@ function registerBootstrapCommands(program3) {
|
|
|
51903
51942
|
...vars,
|
|
51904
51943
|
...registryMeta?.requiredChecks?.length ? { GATE_RULESET_CONTEXTS_JSON: rulesetVars.GATE_RULESET_CONTEXTS_JSON } : {},
|
|
51905
51944
|
...registryMeta?.requiredCheckBranches?.length ? { GATE_RULESET_BRANCH_REFS_JSON: rulesetVars.GATE_RULESET_BRANCH_REFS_JSON } : {}
|
|
51906
|
-
} : vars,
|
|
51945
|
+
} : vars, readFile11, preservedContent);
|
|
51907
51946
|
if (!writeContent.ok) {
|
|
51908
51947
|
return fail(`bootstrap apply: ${resolved.target}: ${writeContent.reason} \u2014 refusing to overwrite repo-owned content`);
|
|
51909
51948
|
}
|
|
@@ -52049,7 +52088,7 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
|
|
|
52049
52088
|
}
|
|
52050
52089
|
const rulesetSeed = repo.toLowerCase() === "mutmutco/mmi-hub" ? void 0 : manifest.seeds.find((s) => s.target === ".github/rulesets/mmi-product-required-checks.json");
|
|
52051
52090
|
if (rulesetSeed) {
|
|
52052
|
-
const rulesetContent = resolveSeedContent({ ...rulesetSeed, target: rulesetSeed.target.replace("{{REPO_SLUG}}", slug) }, vars,
|
|
52091
|
+
const rulesetContent = resolveSeedContent({ ...rulesetSeed, target: rulesetSeed.target.replace("{{REPO_SLUG}}", slug) }, vars, readFile11);
|
|
52053
52092
|
if (rulesetContent) {
|
|
52054
52093
|
try {
|
|
52055
52094
|
const client = controlClient;
|
|
@@ -52841,32 +52880,183 @@ function registerDeployCommands(program3) {
|
|
|
52841
52880
|
}
|
|
52842
52881
|
|
|
52843
52882
|
// src/intercom-guest.ts
|
|
52883
|
+
var import_node_crypto19 = require("node:crypto");
|
|
52884
|
+
var import_promises5 = require("node:fs/promises");
|
|
52885
|
+
var import_node_os22 = require("node:os");
|
|
52886
|
+
var import_node_path38 = require("node:path");
|
|
52887
|
+
init_cli_shared();
|
|
52844
52888
|
init_github_client();
|
|
52845
|
-
var CANONICAL_COMMAND = "mmi-cli
|
|
52889
|
+
var CANONICAL_COMMAND = "mmi-cli intercom guest";
|
|
52846
52890
|
var INTERCOM_GUEST_VERBS = ["register", "read", "send", "join", "leave"];
|
|
52891
|
+
var DELIVERIES_LIMIT_MAX = 100;
|
|
52892
|
+
var DELIVERIES_LIMIT_DEFAULT = 20;
|
|
52893
|
+
function deliveriesLimit(limit) {
|
|
52894
|
+
if (limit === void 0 || !Number.isFinite(limit) || limit < 1) return DELIVERIES_LIMIT_DEFAULT;
|
|
52895
|
+
return Math.min(Math.floor(limit), DELIVERIES_LIMIT_MAX);
|
|
52896
|
+
}
|
|
52847
52897
|
var INTERCOM_GUEST_CONTRACT = {
|
|
52848
|
-
source: "mutmutco/Jerv-Hub#
|
|
52898
|
+
source: "mutmutco/Jerv-Hub#2727 published guest wire contract (gateway/v1: contract/operations.js, contract/authorization.json, src/http/handler.js)",
|
|
52899
|
+
contractVersion: "gateway/v1",
|
|
52900
|
+
baseUrl: "https://jerv-central.tail4ce549.ts.net",
|
|
52849
52901
|
baseUrlEnv: "MMI_INTERCOM_GATEWAY_URL",
|
|
52850
|
-
|
|
52902
|
+
discovery: {
|
|
52903
|
+
operation: "intercom.directory",
|
|
52904
|
+
method: "POST",
|
|
52905
|
+
path: "/v1/intercom/directory",
|
|
52906
|
+
mutation: false,
|
|
52907
|
+
credential: "required",
|
|
52908
|
+
// Idle endpoints are included on purpose: the Coordinator is reachable while it is idle, and the
|
|
52909
|
+
// contract says to match its display name and take the id from the row, never to remember one.
|
|
52910
|
+
body: () => ({ limit: 200, includeIdle: true })
|
|
52911
|
+
},
|
|
52912
|
+
operations: {
|
|
52913
|
+
// #9993 — the guest's first contact. `displayName` is the gh login; the Gateway appends 8 hex of the
|
|
52914
|
+
// endpoint id only when the name collides. HostKind/project are optional and omitted (the Gateway
|
|
52915
|
+
// stores `remote`). With a stored credential this same call rotates and resumes the endpoint.
|
|
52916
|
+
register: {
|
|
52917
|
+
operation: "intercom.register",
|
|
52918
|
+
method: "POST",
|
|
52919
|
+
path: "/v1/intercom/register",
|
|
52920
|
+
mutation: true,
|
|
52921
|
+
credential: "optional",
|
|
52922
|
+
needsLogin: true,
|
|
52923
|
+
body: (_request, context) => ({ displayName: context.login ?? "" })
|
|
52924
|
+
},
|
|
52925
|
+
// #9993 — `read` is the inbox: pending deliveries. Accepting them (intercom.accept) or acking them
|
|
52926
|
+
// (intercom.ack) is a separate, explicit call the contract documents under `cliVerbs.read.then`.
|
|
52927
|
+
read: {
|
|
52928
|
+
operation: "intercom.deliveries",
|
|
52929
|
+
method: "POST",
|
|
52930
|
+
path: "/v1/intercom/deliveries",
|
|
52931
|
+
mutation: false,
|
|
52932
|
+
credential: "required",
|
|
52933
|
+
body: (request) => ({ state: "pending", limit: deliveriesLimit(request.limit) })
|
|
52934
|
+
},
|
|
52935
|
+
// #9993 — the wire field is `text`. A body field named `message` is `unknown_field` at the Gateway.
|
|
52936
|
+
send: {
|
|
52937
|
+
operation: "intercom.send",
|
|
52938
|
+
method: "POST",
|
|
52939
|
+
path: "/v1/intercom/send",
|
|
52940
|
+
mutation: true,
|
|
52941
|
+
credential: "required",
|
|
52942
|
+
body: (request) => ({ to: request.to, text: request.message })
|
|
52943
|
+
},
|
|
52944
|
+
// #9993 — no Gateway operation admits a guest to a suite (Jerv-Hub#2524): a join is an ordinary
|
|
52945
|
+
// `send` to the Coordinator carrying the suite message convention. The suite name travels inside the
|
|
52946
|
+
// text because the convention carries no suite field.
|
|
52947
|
+
join: {
|
|
52948
|
+
operation: "intercom.send",
|
|
52949
|
+
method: "POST",
|
|
52950
|
+
path: "/v1/intercom/send",
|
|
52951
|
+
mutation: true,
|
|
52952
|
+
credential: "required",
|
|
52953
|
+
needsCoordinator: true,
|
|
52954
|
+
body: (request, context) => ({
|
|
52955
|
+
to: context.coordinator,
|
|
52956
|
+
text: `Suite join: ${context.endpointId ?? ""}, ${context.displayName ?? context.login ?? ""} guest, repo ${context.repo}, host ${context.host}, suite ${request.suite ?? ""}`
|
|
52957
|
+
})
|
|
52958
|
+
},
|
|
52959
|
+
// #9993 — leaving is the same shape, and the Coordinator marks the seat left.
|
|
52960
|
+
leave: {
|
|
52961
|
+
operation: "intercom.send",
|
|
52962
|
+
method: "POST",
|
|
52963
|
+
path: "/v1/intercom/send",
|
|
52964
|
+
mutation: true,
|
|
52965
|
+
credential: "required",
|
|
52966
|
+
needsCoordinator: true,
|
|
52967
|
+
body: (_request, context) => ({
|
|
52968
|
+
to: context.coordinator,
|
|
52969
|
+
text: `Suite leave: ${context.endpointId ?? ""}`
|
|
52970
|
+
})
|
|
52971
|
+
}
|
|
52972
|
+
}
|
|
52851
52973
|
};
|
|
52852
52974
|
var INTERCOM_GUEST_CONTRACT_MISSING = "intercom-guest-contract-missing";
|
|
52853
52975
|
var INTERCOM_GUEST_BASE_URL_MISSING = "intercom-guest-base-url-missing";
|
|
52854
52976
|
var INTERCOM_GUEST_NO_IDENTITY = "intercom-guest-no-identity";
|
|
52977
|
+
var INTERCOM_GUEST_INPUT_MISSING = "intercom-guest-input-missing";
|
|
52978
|
+
var INTERCOM_GUEST_NO_CREDENTIAL = "intercom-guest-no-credential";
|
|
52979
|
+
var INTERCOM_GUEST_COORDINATOR_MISSING = "intercom-guest-coordinator-missing";
|
|
52980
|
+
function intercomGuestStorePath(env = process.env) {
|
|
52981
|
+
const home = env.MMI_INTERCOM_HOME?.trim();
|
|
52982
|
+
return (0, import_node_path38.join)(home && home.length > 0 ? home : (0, import_node_path38.join)((0, import_node_os22.homedir)(), ".mmi", "intercom"), "guest.json");
|
|
52983
|
+
}
|
|
52855
52984
|
function scrubToken(text, token) {
|
|
52856
52985
|
if (!token) return text;
|
|
52857
52986
|
return text.split(token).join("***");
|
|
52858
52987
|
}
|
|
52988
|
+
function scrubSecrets(text, secrets) {
|
|
52989
|
+
return secrets.reduce((acc, secret) => scrubToken(acc, secret), text);
|
|
52990
|
+
}
|
|
52859
52991
|
function missingContractRefusal(verb) {
|
|
52860
52992
|
return [
|
|
52861
|
-
`${CANONICAL_COMMAND} ${verb}: not sent \u2014
|
|
52862
|
-
|
|
52863
|
-
"
|
|
52864
|
-
"
|
|
52865
|
-
|
|
52866
|
-
"`INTERCOM_GUEST_CONTRACT.operations` in cli/src/intercom-guest.ts
|
|
52993
|
+
`${CANONICAL_COMMAND} ${verb}: not sent \u2014 this CLI build carries no Jerv Gateway operation for the '${verb}' verb (${INTERCOM_GUEST_CONTRACT.source}).`,
|
|
52994
|
+
"The published guest contract publishes the method, path and field shape for every verb this client knows",
|
|
52995
|
+
`(${INTERCOM_GUEST_VERBS.join(", ")}), so an empty entry means the contract moved and this build did not follow it \u2014`,
|
|
52996
|
+
"this client refuses instead of guessing an endpoint: a guessed call would come back 404/403 and read as a permission",
|
|
52997
|
+
"or allowlist answer when the real answer is that the operation is unknown here.",
|
|
52998
|
+
"To fix it: check the published contract against `INTERCOM_GUEST_CONTRACT.operations` in cli/src/intercom-guest.ts",
|
|
52999
|
+
"\u2014 that object is the one place the wire shape lives.",
|
|
52867
53000
|
"Nothing was read and nothing was sent: no token was touched and no request was made."
|
|
52868
53001
|
].join(" ");
|
|
52869
53002
|
}
|
|
53003
|
+
function missingInput(request) {
|
|
53004
|
+
if (request.verb === "send") {
|
|
53005
|
+
if (!request.to?.trim()) return "`--to <address>` is required";
|
|
53006
|
+
if (!request.message?.trim()) return "`--message <text>` is required";
|
|
53007
|
+
}
|
|
53008
|
+
if (request.verb === "join" && !request.suite?.trim()) return "`--suite <name>` is required";
|
|
53009
|
+
return void 0;
|
|
53010
|
+
}
|
|
53011
|
+
function coordinatorEndpointId(directoryBody) {
|
|
53012
|
+
let parsed;
|
|
53013
|
+
try {
|
|
53014
|
+
parsed = JSON.parse(directoryBody);
|
|
53015
|
+
} catch {
|
|
53016
|
+
return void 0;
|
|
53017
|
+
}
|
|
53018
|
+
const data = parsed?.data ?? parsed;
|
|
53019
|
+
const items = data?.items;
|
|
53020
|
+
if (!Array.isArray(items)) return void 0;
|
|
53021
|
+
const candidates = items.filter((item) => Boolean(item) && typeof item === "object");
|
|
53022
|
+
const named = candidates.filter((item) => typeof item.displayName === "string" && /^Coordinator(\s|$)/.test(item.displayName) && item.self !== true);
|
|
53023
|
+
const exact = named.find((item) => item.displayName === "Coordinator") ?? named[0];
|
|
53024
|
+
return typeof exact?.endpointId === "string" && exact.endpointId.length > 0 ? exact.endpointId : void 0;
|
|
53025
|
+
}
|
|
53026
|
+
async function readStore(path2) {
|
|
53027
|
+
try {
|
|
53028
|
+
const parsed = JSON.parse(await (0, import_promises5.readFile)(path2, "utf8"));
|
|
53029
|
+
return parsed && typeof parsed === "object" ? parsed : void 0;
|
|
53030
|
+
} catch {
|
|
53031
|
+
return void 0;
|
|
53032
|
+
}
|
|
53033
|
+
}
|
|
53034
|
+
async function writeStore(path2, entry) {
|
|
53035
|
+
await (0, import_promises5.mkdir)((0, import_node_path38.dirname)(path2), { recursive: true, mode: 448 });
|
|
53036
|
+
await (0, import_promises5.writeFile)(path2, `${JSON.stringify(entry, null, 2)}
|
|
53037
|
+
`, { encoding: "utf8", mode: 384 });
|
|
53038
|
+
await (0, import_promises5.chmod)(path2, 384).catch(() => {
|
|
53039
|
+
});
|
|
53040
|
+
}
|
|
53041
|
+
function registrationEntry(gateway, body, previous) {
|
|
53042
|
+
let parsed;
|
|
53043
|
+
try {
|
|
53044
|
+
parsed = JSON.parse(body);
|
|
53045
|
+
} catch {
|
|
53046
|
+
return void 0;
|
|
53047
|
+
}
|
|
53048
|
+
const data = parsed?.data ?? parsed;
|
|
53049
|
+
const credential = typeof data?.credential === "string" ? data.credential : previous?.credential;
|
|
53050
|
+
if (!credential) return void 0;
|
|
53051
|
+
return {
|
|
53052
|
+
gateway,
|
|
53053
|
+
endpointId: typeof data?.endpointId === "string" ? data.endpointId : previous?.endpointId,
|
|
53054
|
+
deviceId: typeof data?.deviceId === "string" ? data.deviceId : previous?.deviceId,
|
|
53055
|
+
credential,
|
|
53056
|
+
displayName: typeof data?.displayName === "string" ? data.displayName : previous?.displayName,
|
|
53057
|
+
epoch: typeof data?.epoch === "number" ? data.epoch : previous?.epoch
|
|
53058
|
+
};
|
|
53059
|
+
}
|
|
52870
53060
|
async function runIntercomGuest(request, deps = {}) {
|
|
52871
53061
|
const verb = request.verb;
|
|
52872
53062
|
const contract = deps.contract ?? INTERCOM_GUEST_CONTRACT;
|
|
@@ -52874,61 +53064,156 @@ async function runIntercomGuest(request, deps = {}) {
|
|
|
52874
53064
|
if (!operation) {
|
|
52875
53065
|
return { ok: false, verb, code: INTERCOM_GUEST_CONTRACT_MISSING, message: missingContractRefusal(verb), tokenRead: false };
|
|
52876
53066
|
}
|
|
53067
|
+
const inputProblem = missingInput(request);
|
|
53068
|
+
if (inputProblem) {
|
|
53069
|
+
return {
|
|
53070
|
+
ok: false,
|
|
53071
|
+
verb,
|
|
53072
|
+
code: INTERCOM_GUEST_INPUT_MISSING,
|
|
53073
|
+
message: `${CANONICAL_COMMAND} ${verb}: not sent \u2014 ${inputProblem}. Nothing was read and no request was made.`,
|
|
53074
|
+
tokenRead: false
|
|
53075
|
+
};
|
|
53076
|
+
}
|
|
52877
53077
|
const env = deps.env ?? process.env;
|
|
52878
|
-
const baseUrl = env[contract.baseUrlEnv]?.trim();
|
|
53078
|
+
const baseUrl = (env[contract.baseUrlEnv]?.trim() || contract.baseUrl).replace(/\/+$/, "");
|
|
52879
53079
|
if (!baseUrl) {
|
|
52880
53080
|
return {
|
|
52881
53081
|
ok: false,
|
|
52882
53082
|
verb,
|
|
52883
53083
|
code: INTERCOM_GUEST_BASE_URL_MISSING,
|
|
52884
|
-
message: `${CANONICAL_COMMAND} ${verb}: not sent \u2014 ${contract.baseUrlEnv} is
|
|
53084
|
+
message: `${CANONICAL_COMMAND} ${verb}: not sent \u2014 ${contract.baseUrlEnv} is empty and the published contract names no base URL either (${contract.source}). Nothing was read and no request was made.`,
|
|
52885
53085
|
tokenRead: false
|
|
52886
53086
|
};
|
|
52887
53087
|
}
|
|
53088
|
+
const storePath = deps.storePath ?? intercomGuestStorePath(env);
|
|
53089
|
+
const store = await readStore(storePath);
|
|
52888
53090
|
const identity = await (deps.readToken ?? githubKeyringTokenRead)();
|
|
52889
53091
|
if (identity.state !== "ok") {
|
|
52890
53092
|
return {
|
|
52891
53093
|
ok: false,
|
|
52892
53094
|
verb,
|
|
52893
53095
|
code: INTERCOM_GUEST_NO_IDENTITY,
|
|
52894
|
-
message:
|
|
52895
|
-
`${CANONICAL_COMMAND} ${verb}: not sent \u2014 the guest identity is the caller's own \`gh\` login and it could not be read (${identity.detail}). Run \`gh auth login\`, then retry. No request was made
|
|
53096
|
+
message: scrubSecrets(
|
|
53097
|
+
`${CANONICAL_COMMAND} ${verb}: not sent \u2014 the guest identity is the caller's own \`gh\` login and it could not be read (${identity.detail}). Run \`gh auth login\`, then retry. No request was made.`,
|
|
53098
|
+
[]
|
|
52896
53099
|
),
|
|
52897
53100
|
tokenRead: false
|
|
52898
53101
|
};
|
|
52899
53102
|
}
|
|
52900
53103
|
const token = identity.token;
|
|
52901
|
-
|
|
52902
|
-
|
|
52903
|
-
|
|
52904
|
-
|
|
52905
|
-
|
|
52906
|
-
|
|
53104
|
+
let login;
|
|
53105
|
+
if (operation.needsLogin) {
|
|
53106
|
+
login = await (deps.readLogin ?? githubLogin)();
|
|
53107
|
+
if (!login) {
|
|
53108
|
+
return {
|
|
53109
|
+
ok: false,
|
|
53110
|
+
verb,
|
|
53111
|
+
code: INTERCOM_GUEST_NO_IDENTITY,
|
|
53112
|
+
message: scrubSecrets(
|
|
53113
|
+
`${CANONICAL_COMMAND} ${verb}: not sent \u2014 ${operation.operation} needs your GitHub login as \`displayName\` and \`gh api user\` returned none. Run \`gh auth login\`, then retry. No request was made.`,
|
|
53114
|
+
[token]
|
|
53115
|
+
),
|
|
53116
|
+
tokenRead: true
|
|
53117
|
+
};
|
|
53118
|
+
}
|
|
52907
53119
|
}
|
|
52908
|
-
|
|
52909
|
-
|
|
52910
|
-
|
|
52911
|
-
|
|
52912
|
-
|
|
52913
|
-
|
|
53120
|
+
const credential = store?.credential;
|
|
53121
|
+
if (operation.credential === "required" && !credential) {
|
|
53122
|
+
return {
|
|
53123
|
+
ok: false,
|
|
53124
|
+
verb,
|
|
53125
|
+
code: INTERCOM_GUEST_NO_CREDENTIAL,
|
|
53126
|
+
message: scrubSecrets(
|
|
53127
|
+
`${CANONICAL_COMMAND} ${verb}: not sent \u2014 no intercom credential is stored for this machine (${storePath}). ${operation.operation} requires the \`Jerv-Intercom-Credential\` the Gateway returns exactly once, so run \`${CANONICAL_COMMAND} register\` first. Nothing was read and no request was made.`,
|
|
53128
|
+
[token]
|
|
53129
|
+
),
|
|
53130
|
+
tokenRead: true
|
|
53131
|
+
};
|
|
52914
53132
|
}
|
|
52915
|
-
const
|
|
52916
|
-
|
|
53133
|
+
const fetchImpl = deps.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
53134
|
+
const newKey = deps.newIdempotencyKey ?? (() => (0, import_node_crypto19.randomUUID)());
|
|
53135
|
+
const secrets = [token, credential].filter((secret) => Boolean(secret));
|
|
53136
|
+
const callOne = async (op, body2) => {
|
|
53137
|
+
const headers = {
|
|
53138
|
+
accept: "application/json",
|
|
53139
|
+
"content-type": "application/json",
|
|
53140
|
+
"jerv-contract-version": contract.contractVersion,
|
|
53141
|
+
"jerv-guest-github-token": token
|
|
53142
|
+
};
|
|
53143
|
+
if (credential && op.credential !== "never") headers["jerv-intercom-credential"] = credential;
|
|
53144
|
+
if (op.mutation) headers["idempotency-key"] = newKey();
|
|
53145
|
+
let response;
|
|
53146
|
+
try {
|
|
53147
|
+
response = await fetchImpl(new URL(op.path, baseUrl).toString(), { method: op.method, headers, body: JSON.stringify(body2) });
|
|
53148
|
+
} catch (error) {
|
|
53149
|
+
return { transport: error instanceof Error ? error.message : String(error) };
|
|
53150
|
+
}
|
|
53151
|
+
const text = await response.text().catch(() => "");
|
|
53152
|
+
return { status: response.status, ok: response.ok, text };
|
|
53153
|
+
};
|
|
53154
|
+
let context = {
|
|
53155
|
+
login,
|
|
53156
|
+
credential,
|
|
53157
|
+
endpointId: store?.endpointId,
|
|
53158
|
+
displayName: store?.displayName,
|
|
53159
|
+
repo: env.GITHUB_REPOSITORY?.trim() || "unknown",
|
|
53160
|
+
host: (0, import_node_os22.hostname)()
|
|
53161
|
+
};
|
|
53162
|
+
if (operation.needsCoordinator) {
|
|
53163
|
+
const directory = await callOne(contract.discovery, contract.discovery.body?.(request, context) ?? {});
|
|
53164
|
+
if ("transport" in directory) {
|
|
53165
|
+
return { ok: false, verb, code: "intercom-guest-transport-failed", message: scrubSecrets(`${CANONICAL_COMMAND} ${verb}: the Gateway call failed in transport (${directory.transport}).`, secrets), tokenRead: true };
|
|
53166
|
+
}
|
|
53167
|
+
if (!directory.ok) {
|
|
53168
|
+
return {
|
|
53169
|
+
ok: false,
|
|
53170
|
+
verb,
|
|
53171
|
+
code: `intercom-guest-http-${directory.status}`,
|
|
53172
|
+
message: scrubSecrets(`${CANONICAL_COMMAND} ${verb}: ${contract.discovery.operation} answered HTTP ${directory.status}${directory.text ? ` \u2014 ${directory.text.slice(0, 600)}` : ""}`, secrets),
|
|
53173
|
+
tokenRead: true
|
|
53174
|
+
};
|
|
53175
|
+
}
|
|
53176
|
+
const coordinator = coordinatorEndpointId(directory.text);
|
|
53177
|
+
if (!coordinator) {
|
|
53178
|
+
return {
|
|
53179
|
+
ok: false,
|
|
53180
|
+
verb,
|
|
53181
|
+
code: INTERCOM_GUEST_COORDINATOR_MISSING,
|
|
53182
|
+
message: scrubSecrets(
|
|
53183
|
+
`${CANONICAL_COMMAND} ${verb}: ${contract.discovery.operation} listed no live endpoint named \`Coordinator\`, so there is nobody to send to and nothing was sent. The Coordinator's endpoint id comes from that directory, never from this client.`,
|
|
53184
|
+
secrets
|
|
53185
|
+
),
|
|
53186
|
+
tokenRead: true
|
|
53187
|
+
};
|
|
53188
|
+
}
|
|
53189
|
+
context = { ...context, coordinator };
|
|
53190
|
+
}
|
|
53191
|
+
const body = operation.body ? operation.body(request, context) : {};
|
|
53192
|
+
const result = await callOne(operation, body);
|
|
53193
|
+
if ("transport" in result) {
|
|
53194
|
+
return { ok: false, verb, code: "intercom-guest-transport-failed", message: scrubSecrets(`${CANONICAL_COMMAND} ${verb}: the Gateway call failed in transport (${result.transport}).`, secrets), tokenRead: true };
|
|
53195
|
+
}
|
|
53196
|
+
if (!result.ok) {
|
|
52917
53197
|
return {
|
|
52918
53198
|
ok: false,
|
|
52919
53199
|
verb,
|
|
52920
|
-
code: `intercom-guest-http-${
|
|
52921
|
-
message:
|
|
53200
|
+
code: `intercom-guest-http-${result.status}`,
|
|
53201
|
+
message: scrubSecrets(`${CANONICAL_COMMAND} ${verb}: the Gateway answered HTTP ${result.status}${result.text ? ` \u2014 ${result.text.slice(0, 600)}` : ""}`, secrets),
|
|
52922
53202
|
tokenRead: true
|
|
52923
53203
|
};
|
|
52924
53204
|
}
|
|
52925
|
-
|
|
53205
|
+
if (operation.operation === "intercom.register") {
|
|
53206
|
+
const entry = registrationEntry(baseUrl, result.text, store);
|
|
53207
|
+
if (entry) await writeStore(storePath, entry).catch(() => {
|
|
53208
|
+
});
|
|
53209
|
+
}
|
|
53210
|
+
return { ok: true, verb, status: result.status, body: scrubSecrets(result.text, secrets) };
|
|
52926
53211
|
}
|
|
52927
53212
|
function renderIntercomGuestResult(result) {
|
|
52928
53213
|
return result.ok ? result.body : result.message;
|
|
52929
53214
|
}
|
|
52930
53215
|
function registerIntercomGuestCommands(program3, io = {}) {
|
|
52931
|
-
const guest = program3.command("intercom").description("Coordinate with the MM Coordinator through the Jerv Gateway intercom (guest identity; Jerv-Hub#
|
|
53216
|
+
const guest = program3.command("intercom").description("Coordinate with the MM Coordinator through the Jerv Gateway intercom (guest identity; Jerv-Hub#2727)").command("guest").description("Guest coordination verbs: register, read, send, join, leave \u2014 coordination only, never orders");
|
|
52932
53217
|
const out = io.out ?? ((line) => process.stdout.write(`${line}
|
|
52933
53218
|
`));
|
|
52934
53219
|
const err = io.err ?? ((line) => process.stderr.write(`${line}
|
|
@@ -52943,19 +53228,21 @@ function registerIntercomGuestCommands(program3, io = {}) {
|
|
|
52943
53228
|
return;
|
|
52944
53229
|
}
|
|
52945
53230
|
err(renderIntercomGuestResult(result));
|
|
52946
|
-
setExitCode(
|
|
53231
|
+
setExitCode(
|
|
53232
|
+
result.code === INTERCOM_GUEST_CONTRACT_MISSING || result.code === INTERCOM_GUEST_BASE_URL_MISSING || result.code === INTERCOM_GUEST_NO_CREDENTIAL ? 2 : 1
|
|
53233
|
+
);
|
|
52947
53234
|
};
|
|
52948
|
-
guest.command("register").description("Register this guest endpoint with the Gateway using your `gh
|
|
53235
|
+
guest.command("register").description("Register this guest endpoint with the Gateway, using your `gh` login as the display name").action(async () => {
|
|
52949
53236
|
await run({ verb: "register" });
|
|
52950
53237
|
});
|
|
52951
|
-
guest.command("read").description(
|
|
52952
|
-
const limit = Number(options.limit ??
|
|
52953
|
-
await run({ verb: "read", limit:
|
|
53238
|
+
guest.command("read").description(`Read the deliveries waiting for this guest endpoint (default ${DELIVERIES_LIMIT_DEFAULT}, at most ${DELIVERIES_LIMIT_MAX})`).option("--limit <n>", `how many deliveries to look at (1-${DELIVERIES_LIMIT_MAX})`, String(DELIVERIES_LIMIT_DEFAULT)).action(async (options) => {
|
|
53239
|
+
const limit = Number(options.limit ?? DELIVERIES_LIMIT_DEFAULT);
|
|
53240
|
+
await run({ verb: "read", limit: deliveriesLimit(limit) });
|
|
52954
53241
|
});
|
|
52955
|
-
guest.command("send").description("Send a coordination message to
|
|
53242
|
+
guest.command("send").description("Send a coordination message to the MM Coordinator").requiredOption("--to <address>", "peer endpoint id or display name (the MM Coordinator)").requiredOption("--message <text>", "the coordination message").action(async (options) => {
|
|
52956
53243
|
await run({ verb: "send", to: options.to, message: options.message });
|
|
52957
53244
|
});
|
|
52958
|
-
guest.command("join").description("Request to join a suite").requiredOption("--suite <name>", "suite name").action(async (options) => {
|
|
53245
|
+
guest.command("join").description("Request to join a suite (a message to the MM Coordinator, who grants it)").requiredOption("--suite <name>", "suite name").action(async (options) => {
|
|
52959
53246
|
await run({ verb: "join", suite: options.suite });
|
|
52960
53247
|
});
|
|
52961
53248
|
guest.command("leave").description("Leave the suite and withdraw this guest endpoint").action(async () => {
|
|
@@ -52970,7 +53257,7 @@ init_github_client();
|
|
|
52970
53257
|
init_cli_shared();
|
|
52971
53258
|
|
|
52972
53259
|
// src/suite-status.ts
|
|
52973
|
-
var
|
|
53260
|
+
var import_node_crypto20 = require("node:crypto");
|
|
52974
53261
|
var SUITE_REPO = "mutmutco/MM-Work";
|
|
52975
53262
|
var REPOS = {
|
|
52976
53263
|
"mmi-scout": "mutmutco/MMI-Scout",
|
|
@@ -52998,7 +53285,7 @@ function parseSuiteMapping(body) {
|
|
|
52998
53285
|
return void 0;
|
|
52999
53286
|
}
|
|
53000
53287
|
}
|
|
53001
|
-
var sha2562 = (b) => (0,
|
|
53288
|
+
var sha2562 = (b) => (0, import_node_crypto20.createHash)("sha256").update(b).digest("hex");
|
|
53002
53289
|
async function proveBundle(url, tag, fetchUrl) {
|
|
53003
53290
|
const get = async (u) => {
|
|
53004
53291
|
try {
|
|
@@ -53254,8 +53541,8 @@ async function waitSuiteDev(deps, opts) {
|
|
|
53254
53541
|
|
|
53255
53542
|
// src/suite-train.ts
|
|
53256
53543
|
var import_node_fs41 = require("node:fs");
|
|
53257
|
-
var
|
|
53258
|
-
var
|
|
53544
|
+
var import_node_path39 = require("node:path");
|
|
53545
|
+
var import_node_crypto21 = require("node:crypto");
|
|
53259
53546
|
|
|
53260
53547
|
// src/kit-version.ts
|
|
53261
53548
|
var parse = (v) => /^(\d+)\.(\d+)\.(\d+)(-.+)?$/.exec(typeof v === "string" ? v.trim() : "");
|
|
@@ -53356,8 +53643,8 @@ function readSuiteCut(path2) {
|
|
|
53356
53643
|
return record2;
|
|
53357
53644
|
}
|
|
53358
53645
|
function writeSuiteCut(path2, record2) {
|
|
53359
|
-
(0, import_node_fs41.mkdirSync)((0,
|
|
53360
|
-
const temp = `${path2}.${(0,
|
|
53646
|
+
(0, import_node_fs41.mkdirSync)((0, import_node_path39.dirname)(path2), { recursive: true });
|
|
53647
|
+
const temp = `${path2}.${(0, import_node_crypto21.randomBytes)(8).toString("hex")}.tmp`;
|
|
53361
53648
|
try {
|
|
53362
53649
|
(0, import_node_fs41.writeFileSync)(temp, JSON.stringify(record2, null, 2), { flag: "wx" });
|
|
53363
53650
|
(0, import_node_fs41.renameSync)(temp, path2);
|
|
@@ -53416,7 +53703,7 @@ async function retireFailedLeadRcLedger(deps, ownerGo) {
|
|
|
53416
53703
|
if (ledger.repo !== SUITE_REPO || ledger.lane !== "rcand" || ledger.phases.promotion.state === "complete" || !states.includes("failed")) return void 0;
|
|
53417
53704
|
if (!ownerGo) throw new Error(`the lead's failed rcand ledger for ${ledger.tag} blocks every train; retire it with suite abandon --owner-go`);
|
|
53418
53705
|
if ((await deps.rcHead())?.toLowerCase() === ledger.tagSha.toLowerCase()) throw new Error(`origin rc already points at ${ledger.tag}; it was promoted, so its ledger is not retired`);
|
|
53419
|
-
const archive = (0,
|
|
53706
|
+
const archive = (0, import_node_path39.join)((0, import_node_path39.dirname)(deps.ledgerPath), `phases.archive-${ledger.tag}.json`);
|
|
53420
53707
|
if ((0, import_node_fs41.existsSync)(archive)) throw new Error(`ledger archive already exists at ${archive}; inspect before retiring again`);
|
|
53421
53708
|
await deps.markAbandoned(SUITE_REPO, ledger.tag, ledger.tagSha);
|
|
53422
53709
|
await fence(() => (0, import_node_fs41.renameSync)(deps.ledgerPath, archive));
|
|
@@ -53783,7 +54070,7 @@ Each member's live release must serve <data>/main/module.js at its main pin path
|
|
|
53783
54070
|
}
|
|
53784
54071
|
return record2;
|
|
53785
54072
|
}
|
|
53786
|
-
var hotfixRecordPath = (deps) => (0,
|
|
54073
|
+
var hotfixRecordPath = (deps) => (0, import_node_path39.join)((0, import_node_path39.dirname)(deps.recordPath), "hotfix.json");
|
|
53787
54074
|
function readSuiteHotfix(path2) {
|
|
53788
54075
|
let raw;
|
|
53789
54076
|
try {
|
|
@@ -54098,20 +54385,20 @@ async function runRcDataSwitch(deps, opts) {
|
|
|
54098
54385
|
|
|
54099
54386
|
// src/suite-train-io.ts
|
|
54100
54387
|
var import_node_child_process19 = require("node:child_process");
|
|
54101
|
-
var import_node_path51 = require("node:path");
|
|
54102
|
-
var import_node_fs55 = require("node:fs");
|
|
54103
54388
|
var import_node_path52 = require("node:path");
|
|
54389
|
+
var import_node_fs55 = require("node:fs");
|
|
54390
|
+
var import_node_path53 = require("node:path");
|
|
54104
54391
|
init_cli_shared();
|
|
54105
54392
|
|
|
54106
54393
|
// src/command-register-train-operations.ts
|
|
54107
|
-
var
|
|
54394
|
+
var import_promises10 = require("node:fs/promises");
|
|
54108
54395
|
init_clean_exit();
|
|
54109
54396
|
init_cli_shared();
|
|
54110
54397
|
init_client_version();
|
|
54111
54398
|
init_house_map();
|
|
54112
54399
|
|
|
54113
54400
|
// src/hotfix-apply.ts
|
|
54114
|
-
var
|
|
54401
|
+
var import_promises6 = require("node:fs/promises");
|
|
54115
54402
|
|
|
54116
54403
|
// src/release-announce.ts
|
|
54117
54404
|
var ANNOUNCE_REPO = "mutmutco/MMI-Hub";
|
|
@@ -54454,8 +54741,8 @@ async function preflightHotfixBatchPicks(deps, sources, pickTolerated) {
|
|
|
54454
54741
|
if (sources.length === 0) return { failures: [], skipped: [] };
|
|
54455
54742
|
const { mkdtemp: mkdtemp2, rm: rm2 } = await import("node:fs/promises");
|
|
54456
54743
|
const { tmpdir: tmpdir13 } = await import("node:os");
|
|
54457
|
-
const { join:
|
|
54458
|
-
const dir = await mkdtemp2(
|
|
54744
|
+
const { join: join55 } = await import("node:path");
|
|
54745
|
+
const dir = await mkdtemp2(join55(tmpdir13(), "mmi-hotfix-preflight-"));
|
|
54459
54746
|
const wt = { run: (file, args) => deps.run(file, file === "git" ? ["-C", dir, ...args] : args) };
|
|
54460
54747
|
const failures = [];
|
|
54461
54748
|
const skipped = [];
|
|
@@ -55167,7 +55454,7 @@ async function runHotfixReleaseLocked(deps, versionInput, options, doctor) {
|
|
|
55167
55454
|
}
|
|
55168
55455
|
let lines2;
|
|
55169
55456
|
try {
|
|
55170
|
-
lines2 = summaryFileLines(await (deps.readFile ?? ((p) => (0,
|
|
55457
|
+
lines2 = summaryFileLines(await (deps.readFile ?? ((p) => (0, import_promises6.readFile)(p, "utf8")))(options.announceSummaryFile));
|
|
55171
55458
|
} catch (e) {
|
|
55172
55459
|
throw new Error(`could not read --announce-summary-file ${options.announceSummaryFile}: ${e.message} \u2014 see https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#announce-summary-missing`);
|
|
55173
55460
|
}
|
|
@@ -55793,8 +56080,8 @@ function checkHotfixCarries(options) {
|
|
|
55793
56080
|
|
|
55794
56081
|
// src/merge-cleanup.ts
|
|
55795
56082
|
var import_node_fs42 = require("node:fs");
|
|
55796
|
-
var
|
|
55797
|
-
var
|
|
56083
|
+
var import_node_path40 = require("node:path");
|
|
56084
|
+
var import_node_os23 = require("node:os");
|
|
55798
56085
|
init_cli_shared();
|
|
55799
56086
|
init_github_client();
|
|
55800
56087
|
|
|
@@ -56201,8 +56488,8 @@ function resolveSquashMergeBodyText(commits, allowedClosing, cwd) {
|
|
|
56201
56488
|
return rewritten === base ? null : rewritten;
|
|
56202
56489
|
}
|
|
56203
56490
|
function writeSquashBodyFile(body) {
|
|
56204
|
-
const dir = (0, import_node_fs42.mkdtempSync)((0,
|
|
56205
|
-
const path2 = (0,
|
|
56491
|
+
const dir = (0, import_node_fs42.mkdtempSync)((0, import_node_path40.join)((0, import_node_os23.tmpdir)(), "mmi-squash-body-"));
|
|
56492
|
+
const path2 = (0, import_node_path40.join)(dir, "body.txt");
|
|
56206
56493
|
(0, import_node_fs42.writeFileSync)(path2, body.endsWith("\n") ? body : `${body}
|
|
56207
56494
|
`, "utf8");
|
|
56208
56495
|
return { path: path2, cleanup: () => {
|
|
@@ -56458,9 +56745,9 @@ async function deleteMergedRemoteBranch(options) {
|
|
|
56458
56745
|
init_github_client();
|
|
56459
56746
|
|
|
56460
56747
|
// src/release-custody.ts
|
|
56461
|
-
var
|
|
56748
|
+
var import_node_crypto22 = require("node:crypto");
|
|
56462
56749
|
var import_node_fs43 = require("node:fs");
|
|
56463
|
-
var
|
|
56750
|
+
var import_node_path41 = require("node:path");
|
|
56464
56751
|
init_github_client();
|
|
56465
56752
|
|
|
56466
56753
|
// src/release-custody-bootstrap.ts
|
|
@@ -56682,7 +56969,7 @@ var ReleaseCustodyError = class extends Error {
|
|
|
56682
56969
|
this.name = "ReleaseCustodyError";
|
|
56683
56970
|
}
|
|
56684
56971
|
};
|
|
56685
|
-
var custodyDigest = (value) => (0,
|
|
56972
|
+
var custodyDigest = (value) => (0, import_node_crypto22.createHash)("sha256").update(value).digest("hex");
|
|
56686
56973
|
function parseCustody(raw, repo) {
|
|
56687
56974
|
const s = JSON.parse(raw);
|
|
56688
56975
|
if (s.schema !== "mmi-release-custody/v1" || s.repo !== repo || !s.precutId || !Number.isSafeInteger(s.revision) || s.revision < 1 || !s.controller || !Number.isSafeInteger(s.controller.runId) || s.controller.runId <= 0 || !Number.isSafeInteger(s.controller.runAttempt) || s.controller.runAttempt <= 0 || !s.controller.token || !(s.ledger === null || typeof s.ledger === "string") || !s.archives || !s.effects) {
|
|
@@ -56783,7 +57070,7 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
56783
57070
|
}
|
|
56784
57071
|
}
|
|
56785
57072
|
let state = {
|
|
56786
|
-
...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0,
|
|
57073
|
+
...found.state ?? { schema: "mmi-release-custody/v1", repo, precutId: (0, import_node_crypto22.randomUUID)(), effects: {}, ...await initialize() },
|
|
56787
57074
|
revision: (found.state?.revision ?? 0) + 1,
|
|
56788
57075
|
controller
|
|
56789
57076
|
};
|
|
@@ -56844,7 +57131,7 @@ var ReleaseCustodySession = class _ReleaseCustodySession {
|
|
|
56844
57131
|
proof: { kind: "ledger-lifecycle", controller: state.controller }
|
|
56845
57132
|
};
|
|
56846
57133
|
}
|
|
56847
|
-
return { ...state, ledger: raw, archives, precutId: state.ledger && !raw ? (0,
|
|
57134
|
+
return { ...state, ledger: raw, archives, precutId: state.ledger && !raw ? (0, import_node_crypto22.randomUUID)() : state.precutId };
|
|
56848
57135
|
});
|
|
56849
57136
|
}
|
|
56850
57137
|
async preserveLocal(raw) {
|
|
@@ -56960,10 +57247,10 @@ function localRaw(path2) {
|
|
|
56960
57247
|
function hydrateLocal(path2, raw) {
|
|
56961
57248
|
const previous = localRaw(path2);
|
|
56962
57249
|
if (previous === raw) return;
|
|
56963
|
-
(0, import_node_fs43.mkdirSync)((0,
|
|
57250
|
+
(0, import_node_fs43.mkdirSync)((0, import_node_path41.dirname)(path2), { recursive: true });
|
|
56964
57251
|
if (previous !== null) {
|
|
56965
57252
|
const ledger = parseReleaseLedger(previous);
|
|
56966
|
-
const archive = (0,
|
|
57253
|
+
const archive = (0, import_node_path41.join)((0, import_node_path41.dirname)(path2), `phases.local-${ledger.tagSha}-${custodyDigest(previous)}.json`);
|
|
56967
57254
|
if (!(0, import_node_fs43.existsSync)(archive)) (0, import_node_fs43.writeFileSync)(archive, previous, { flag: "wx" });
|
|
56968
57255
|
if (raw === null) (0, import_node_fs43.renameSync)(path2, `${path2}.retired-${custodyDigest(previous)}`);
|
|
56969
57256
|
}
|
|
@@ -57078,7 +57365,7 @@ function withHubReleaseCustody(deps) {
|
|
|
57078
57365
|
if (!authority.ok || !authority.train || authority.authenticatedDelegation !== true) {
|
|
57079
57366
|
throw new ReleaseCustodyError("repository custody requires the server-verified owner-triggered train session");
|
|
57080
57367
|
}
|
|
57081
|
-
const controller = { ...runIdentity, token: (0,
|
|
57368
|
+
const controller = { ...runIdentity, token: (0, import_node_crypto22.randomUUID)(), ...process.env.GITHUB_JOB ? { job: process.env.GITHUB_JOB } : {} };
|
|
57082
57369
|
const raw = localRaw(path2);
|
|
57083
57370
|
const requiredContexts = () => discoverRequiredCheckContexts(
|
|
57084
57371
|
deps,
|
|
@@ -57159,7 +57446,7 @@ function withHubReleaseCustody(deps) {
|
|
|
57159
57446
|
|
|
57160
57447
|
// src/project-info-sync.ts
|
|
57161
57448
|
var import_node_fs44 = require("node:fs");
|
|
57162
|
-
var
|
|
57449
|
+
var import_node_path42 = require("node:path");
|
|
57163
57450
|
var UPDATE_PROJECT_INFO = `mutation($projectId: ID!, $shortDescription: String!, $readme: String!) {
|
|
57164
57451
|
updateProjectV2(input: { projectId: $projectId, shortDescription: $shortDescription, readme: $readme }) {
|
|
57165
57452
|
projectV2 { id }
|
|
@@ -57206,7 +57493,7 @@ function sharedName(entries, fallback) {
|
|
|
57206
57493
|
}
|
|
57207
57494
|
function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
57208
57495
|
if (!project2.projectId) throw new Error(`org project sync-info: ${targetRepo2} registry META has no projectId`);
|
|
57209
|
-
const readmePath = (0,
|
|
57496
|
+
const readmePath = (0, import_node_path42.join)(repoRoot2, "README.md");
|
|
57210
57497
|
if (!(0, import_node_fs44.existsSync)(readmePath)) throw new Error(`org project sync-info: ${targetRepo2} has no README.md`);
|
|
57211
57498
|
const entries = entriesFor(project2, projects);
|
|
57212
57499
|
const memberRepos = [...new Set(entries.flatMap((entry) => entry.repos ?? []))].filter((repo) => /^[^/]+\/[^/]+$/.test(repo)).sort((a, b) => a.localeCompare(b));
|
|
@@ -57232,8 +57519,8 @@ function buildProjectInfoSyncPlan(targetRepo2, project2, projects, repoRoot2) {
|
|
|
57232
57519
|
const targetBase = `https://github.com/${targetRepo2}`;
|
|
57233
57520
|
const targetBranch = branchFor(targetRepo2, projects);
|
|
57234
57521
|
const orgDocs = [
|
|
57235
|
-
(0, import_node_fs44.existsSync)((0,
|
|
57236
|
-
(0, import_node_fs44.existsSync)((0,
|
|
57522
|
+
(0, import_node_fs44.existsSync)((0, import_node_path42.join)(repoRoot2, "architecture.md")) ? `- [Hub architecture](${targetBase}/blob/${targetBranch}/architecture.md)` : "",
|
|
57523
|
+
(0, import_node_fs44.existsSync)((0, import_node_path42.join)(repoRoot2, "docs", "Architecture", "agentic-dev-environment.md")) ? `- [Agentic development environment](${targetBase}/blob/${targetBranch}/docs/Architecture/agentic-dev-environment.md)` : ""
|
|
57237
57524
|
].filter(Boolean);
|
|
57238
57525
|
if (orgDocs.length) lines2.push("", "## Organisation docs", "", ...orgDocs);
|
|
57239
57526
|
return { projectId: project2.projectId, projectName, targetRepo: targetRepo2, memberRepos, shortDescription, readme: `${lines2.join("\n")}
|
|
@@ -57256,7 +57543,7 @@ async function syncProjectInfo(plan, client, apply) {
|
|
|
57256
57543
|
|
|
57257
57544
|
// src/train-commands.ts
|
|
57258
57545
|
var import_node_fs45 = require("node:fs");
|
|
57259
|
-
var
|
|
57546
|
+
var import_node_path43 = require("node:path");
|
|
57260
57547
|
init_cli_shared();
|
|
57261
57548
|
init_clean_exit();
|
|
57262
57549
|
init_client_version();
|
|
@@ -57271,7 +57558,7 @@ function resolveReleaseBumpIntent(raw) {
|
|
|
57271
57558
|
}
|
|
57272
57559
|
function readRepoVersion() {
|
|
57273
57560
|
try {
|
|
57274
|
-
return JSON.parse((0, import_node_fs45.readFileSync)((0,
|
|
57561
|
+
return JSON.parse((0, import_node_fs45.readFileSync)((0, import_node_path43.join)(process.cwd(), ".claude-plugin", "plugin.json"), "utf8")).version || void 0;
|
|
57275
57562
|
} catch {
|
|
57276
57563
|
return void 0;
|
|
57277
57564
|
}
|
|
@@ -57381,8 +57668,8 @@ function releaseProgressVerdict(status, subject = "Release") {
|
|
|
57381
57668
|
}
|
|
57382
57669
|
|
|
57383
57670
|
// src/suite-pin.ts
|
|
57384
|
-
var
|
|
57385
|
-
var
|
|
57671
|
+
var import_promises7 = require("node:fs/promises");
|
|
57672
|
+
var import_node_path44 = require("node:path");
|
|
57386
57673
|
var SuitePinError = class _SuitePinError extends Error {
|
|
57387
57674
|
diagnostic;
|
|
57388
57675
|
constructor(repo, tag, error) {
|
|
@@ -57450,8 +57737,8 @@ async function openSuiteCutPinPr(deps, input) {
|
|
|
57450
57737
|
if (input.carriedOnly) return { status: "unchanged" };
|
|
57451
57738
|
throw new Error("pins already match without a merged cut PR \u2014 provenance unverified");
|
|
57452
57739
|
}
|
|
57453
|
-
await (0,
|
|
57454
|
-
scratch = await (0,
|
|
57740
|
+
await (0, import_promises7.mkdir)((0, import_node_path44.join)(deps.root, "tmp"), { recursive: true });
|
|
57741
|
+
scratch = await (0, import_promises7.mkdtemp)((0, import_node_path44.join)(deps.root, "tmp", "suite-pin-"));
|
|
57455
57742
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
57456
57743
|
await run("git", ["clone", "--quiet", "--branch", prs.length ? branch : "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
57457
57744
|
if (prs.length) {
|
|
@@ -57463,8 +57750,8 @@ async function openSuiteCutPinPr(deps, input) {
|
|
|
57463
57750
|
await run("git", ["switch", "-c", branch]);
|
|
57464
57751
|
}
|
|
57465
57752
|
for (const stage of ["rc", "main"]) {
|
|
57466
|
-
const path2 = (0,
|
|
57467
|
-
await (0,
|
|
57753
|
+
const path2 = (0, import_node_path44.join)(scratch, `${stage}-pins.json`);
|
|
57754
|
+
await (0, import_promises7.writeFile)(path2, JSON.stringify(input.pins.map((p) => ({ module: p.module, url: p[stage] }))));
|
|
57468
57755
|
await run("node", ["scripts/pin-modules.mjs", "--stage", stage, "--pins", path2]);
|
|
57469
57756
|
}
|
|
57470
57757
|
await run("git", ["add", "seed/modules.json"]);
|
|
@@ -57494,7 +57781,7 @@ async function openSuiteCutPinPr(deps, input) {
|
|
|
57494
57781
|
} catch (e) {
|
|
57495
57782
|
throw new Error(`suite cut pin PR FAILED: ${e.message}; merge/verify the single ${SUITE_REPO} development pin PR, then rerun the cut (never recut member tags)`);
|
|
57496
57783
|
} finally {
|
|
57497
|
-
if (scratch) await (0,
|
|
57784
|
+
if (scratch) await (0, import_promises7.rm)(scratch, { recursive: true, force: true });
|
|
57498
57785
|
}
|
|
57499
57786
|
}
|
|
57500
57787
|
async function openSuiteRestorePinPr(deps, input) {
|
|
@@ -57516,13 +57803,13 @@ async function openSuiteRestorePinPr(deps, input) {
|
|
|
57516
57803
|
}
|
|
57517
57804
|
});
|
|
57518
57805
|
if (!todo.length) return void 0;
|
|
57519
|
-
await (0,
|
|
57520
|
-
scratch = await (0,
|
|
57806
|
+
await (0, import_promises7.mkdir)((0, import_node_path44.join)(deps.root, "tmp"), { recursive: true });
|
|
57807
|
+
scratch = await (0, import_promises7.mkdtemp)((0, import_node_path44.join)(deps.root, "tmp", "suite-pin-"));
|
|
57521
57808
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
57522
57809
|
await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
57523
57810
|
await run("git", ["switch", "-c", branch]);
|
|
57524
|
-
const path2 = (0,
|
|
57525
|
-
await (0,
|
|
57811
|
+
const path2 = (0, import_node_path44.join)(scratch, "main-pins.json");
|
|
57812
|
+
await (0, import_promises7.writeFile)(path2, JSON.stringify(todo.map((p) => ({ module: p.module, url: p.prior }))));
|
|
57526
57813
|
await run("node", ["scripts/pin-modules.mjs", "--stage", "main", "--pins", path2]);
|
|
57527
57814
|
await run("git", ["add", "seed/modules.json"]);
|
|
57528
57815
|
await run("git", ["commit", "-m", `Restore main pins of abandoned suite cut ${input.cut.slice(0, 12)} (#7758)`]);
|
|
@@ -57547,7 +57834,7 @@ async function openSuiteRestorePinPr(deps, input) {
|
|
|
57547
57834
|
} catch (e) {
|
|
57548
57835
|
throw new Error(`suite restore pin PR FAILED: ${e.message}; rerun suite abandon --owner-go (the record is kept until the restore PR exists)`);
|
|
57549
57836
|
} finally {
|
|
57550
|
-
if (scratch) await (0,
|
|
57837
|
+
if (scratch) await (0, import_promises7.rm)(scratch, { recursive: true, force: true });
|
|
57551
57838
|
}
|
|
57552
57839
|
}
|
|
57553
57840
|
async function openSuitePinPr(deps, input) {
|
|
@@ -57595,8 +57882,8 @@ async function openSuitePinPr(deps, input) {
|
|
|
57595
57882
|
if (newer.length) return { status: "superseded", pr: newer[0].url, url: pin };
|
|
57596
57883
|
const open2 = onBranch.find((p) => p.state === "OPEN");
|
|
57597
57884
|
if (open2 && tagOf(open2.title ?? "") === tag) return { status: "pending", pr: open2.url, url: pin };
|
|
57598
|
-
await (0,
|
|
57599
|
-
scratch = await (0,
|
|
57885
|
+
await (0, import_promises7.mkdir)((0, import_node_path44.join)(deps.root, "tmp"), { recursive: true });
|
|
57886
|
+
scratch = await (0, import_promises7.mkdtemp)((0, import_node_path44.join)(deps.root, "tmp", "suite-pin-"));
|
|
57600
57887
|
const run = (file, args) => deps.run(file, args, scratch);
|
|
57601
57888
|
await run("git", ["clone", "--quiet", "--branch", "development", "--single-branch", `https://github.com/${SUITE_REPO}.git`, "."]);
|
|
57602
57889
|
await run("git", ["switch", "-c", branch]);
|
|
@@ -57623,7 +57910,7 @@ async function openSuitePinPr(deps, input) {
|
|
|
57623
57910
|
} finally {
|
|
57624
57911
|
if (scratch) {
|
|
57625
57912
|
try {
|
|
57626
|
-
await (0,
|
|
57913
|
+
await (0, import_promises7.rm)(scratch, { recursive: true, force: true });
|
|
57627
57914
|
} catch (e) {
|
|
57628
57915
|
const cleanupFailure = failure ?? new SuitePinError(repo, tag, e);
|
|
57629
57916
|
cleanupFailure.diagnostic.cleanupFailed = true;
|
|
@@ -57649,7 +57936,7 @@ function prTitleRefusal(title) {
|
|
|
57649
57936
|
// src/command-register-collaboration.ts
|
|
57650
57937
|
var import_node_child_process18 = require("node:child_process");
|
|
57651
57938
|
var import_node_fs54 = require("node:fs");
|
|
57652
|
-
var
|
|
57939
|
+
var import_promises9 = require("node:fs/promises");
|
|
57653
57940
|
init_clean_exit();
|
|
57654
57941
|
init_cli_shared();
|
|
57655
57942
|
init_error_codes();
|
|
@@ -57672,11 +57959,11 @@ function spawnDetachedSelf(args, deps, opts = {}) {
|
|
|
57672
57959
|
}
|
|
57673
57960
|
|
|
57674
57961
|
// src/command-register-collaboration.ts
|
|
57675
|
-
var
|
|
57962
|
+
var import_node_path51 = require("node:path");
|
|
57676
57963
|
init_house_map();
|
|
57677
57964
|
|
|
57678
57965
|
// src/issue-body.ts
|
|
57679
|
-
var
|
|
57966
|
+
var import_node_os24 = require("node:os");
|
|
57680
57967
|
init_error_codes();
|
|
57681
57968
|
var TextArgError = class extends Error {
|
|
57682
57969
|
constructor(message2, code, offendingFlag) {
|
|
@@ -57689,7 +57976,7 @@ var TextArgError = class extends Error {
|
|
|
57689
57976
|
offendingFlag;
|
|
57690
57977
|
};
|
|
57691
57978
|
function emptyStdinMessage(fileFlag) {
|
|
57692
|
-
if ((0,
|
|
57979
|
+
if ((0, import_node_os24.platform)() === "win32") {
|
|
57693
57980
|
return `${fileFlag} - read empty stdin (on Windows, ${fileFlag} - is unreliable through the npm .cmd shim \u2014 use ${fileFlag} <path>, or pipe to \`node cli/dist/index.cjs\` directly)`;
|
|
57694
57981
|
}
|
|
57695
57982
|
return `${fileFlag} - read empty stdin (nothing piped \u2014 pass a heredoc/pipe, or ${fileFlag} <path>)`;
|
|
@@ -57790,7 +58077,7 @@ init_github_quota();
|
|
|
57790
58077
|
|
|
57791
58078
|
// src/issue-commands.ts
|
|
57792
58079
|
var import_node_fs46 = require("node:fs");
|
|
57793
|
-
var
|
|
58080
|
+
var import_node_crypto23 = require("node:crypto");
|
|
57794
58081
|
init_cli_shared();
|
|
57795
58082
|
init_clean_exit();
|
|
57796
58083
|
init_error_codes();
|
|
@@ -58267,7 +58554,7 @@ function rowIdempotencyKey(batchKey, spec) {
|
|
|
58267
58554
|
const identity = `${spec.type}
|
|
58268
58555
|
${spec.title.trim()}
|
|
58269
58556
|
${spec.body ?? ""}`;
|
|
58270
|
-
const hash = (0,
|
|
58557
|
+
const hash = (0, import_node_crypto23.createHash)("sha256").update(identity).digest("hex").slice(0, 16);
|
|
58271
58558
|
return `${batchKey}:${hash}`;
|
|
58272
58559
|
}
|
|
58273
58560
|
var BATCH_SPEC_KEYS = /* @__PURE__ */ new Set(["type", "title", "body", "priority", "labels", "label", "parent", "repo", "surface"]);
|
|
@@ -58727,7 +59014,7 @@ ${lines2}`, {
|
|
|
58727
59014
|
|
|
58728
59015
|
// src/post-merge-recon.ts
|
|
58729
59016
|
var import_node_fs47 = require("node:fs");
|
|
58730
|
-
var
|
|
59017
|
+
var import_node_path45 = require("node:path");
|
|
58731
59018
|
|
|
58732
59019
|
// src/cross-repo-filing-issue.ts
|
|
58733
59020
|
init_github_client();
|
|
@@ -58897,7 +59184,7 @@ function buildPostMergeReconRecovery(input) {
|
|
|
58897
59184
|
}
|
|
58898
59185
|
function writePostMergeReconRecovery(cwd, recovery) {
|
|
58899
59186
|
const path2 = postMergeReconStatePath(cwd, recovery.repo, recovery.pr);
|
|
58900
|
-
(0, import_node_fs47.mkdirSync)((0,
|
|
59187
|
+
(0, import_node_fs47.mkdirSync)((0, import_node_path45.dirname)(path2), { recursive: true });
|
|
58901
59188
|
(0, import_node_fs47.writeFileSync)(path2, `${JSON.stringify(recovery, null, 2)}
|
|
58902
59189
|
`, "utf8");
|
|
58903
59190
|
return path2;
|
|
@@ -58937,7 +59224,7 @@ function postMergeReconWarnings(input) {
|
|
|
58937
59224
|
}
|
|
58938
59225
|
|
|
58939
59226
|
// src/pr-commands.ts
|
|
58940
|
-
var
|
|
59227
|
+
var import_promises8 = require("node:fs/promises");
|
|
58941
59228
|
init_cli_shared();
|
|
58942
59229
|
|
|
58943
59230
|
// src/api-read.ts
|
|
@@ -60430,10 +60717,10 @@ function registerPrLifecycleCommands(program3) {
|
|
|
60430
60717
|
let body;
|
|
60431
60718
|
try {
|
|
60432
60719
|
if (o.title || o.titleFile) {
|
|
60433
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
60720
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises8.readFile, readStdin });
|
|
60434
60721
|
}
|
|
60435
60722
|
if (o.body || o.bodyFile) {
|
|
60436
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
60723
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises8.readFile, readStdin });
|
|
60437
60724
|
}
|
|
60438
60725
|
} catch (e) {
|
|
60439
60726
|
return fail(`pr edit: ${e.message}`);
|
|
@@ -60464,7 +60751,7 @@ function registerPrLifecycleCommands(program3) {
|
|
|
60464
60751
|
}
|
|
60465
60752
|
let body;
|
|
60466
60753
|
try {
|
|
60467
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
60754
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises8.readFile, readStdin });
|
|
60468
60755
|
} catch (e) {
|
|
60469
60756
|
return fail(`pr comment: ${e.message}`);
|
|
60470
60757
|
}
|
|
@@ -60749,8 +61036,8 @@ function registerPrLifecycleCommands(program3) {
|
|
|
60749
61036
|
// src/review-verdict.ts
|
|
60750
61037
|
var import_node_child_process15 = require("node:child_process");
|
|
60751
61038
|
var import_node_fs49 = require("node:fs");
|
|
60752
|
-
var
|
|
60753
|
-
var
|
|
61039
|
+
var import_node_os25 = require("node:os");
|
|
61040
|
+
var import_node_path46 = require("node:path");
|
|
60754
61041
|
init_cli_shared();
|
|
60755
61042
|
var REVIEW_VERDICT_MARKER = "<!-- zeroci-review v1 -->";
|
|
60756
61043
|
var REVIEW_VERDICTS = ["PROCEED", "CORRECT", "ESCALATE"];
|
|
@@ -60915,8 +61202,8 @@ async function readPrIssueComments(number, repo) {
|
|
|
60915
61202
|
return comments;
|
|
60916
61203
|
}
|
|
60917
61204
|
async function postPrCommentFromFile(number, repo, body) {
|
|
60918
|
-
const dir = (0, import_node_fs49.mkdtempSync)((0,
|
|
60919
|
-
const path2 = (0,
|
|
61205
|
+
const dir = (0, import_node_fs49.mkdtempSync)((0, import_node_path46.join)((0, import_node_os25.tmpdir)(), "mmi-review-verdict-"));
|
|
61206
|
+
const path2 = (0, import_node_path46.join)(dir, "body.md");
|
|
60920
61207
|
try {
|
|
60921
61208
|
(0, import_node_fs49.writeFileSync)(path2, body, "utf8");
|
|
60922
61209
|
const { stdout } = await execFileP("gh", ["pr", "comment", number, "--repo", repo, "--body-file", path2], { timeout: GH_MUTATION_TIMEOUT_MS });
|
|
@@ -61412,17 +61699,17 @@ function createPreparationDeps(input, io = {}) {
|
|
|
61412
61699
|
|
|
61413
61700
|
// src/worktree-residue-sweep.ts
|
|
61414
61701
|
var import_node_fs53 = require("node:fs");
|
|
61415
|
-
var
|
|
61702
|
+
var import_node_path50 = require("node:path");
|
|
61416
61703
|
|
|
61417
61704
|
// src/worktree-merge-cleanup.ts
|
|
61418
61705
|
var import_node_fs52 = require("node:fs");
|
|
61419
|
-
var
|
|
61706
|
+
var import_node_path49 = require("node:path");
|
|
61420
61707
|
init_cli_shared();
|
|
61421
61708
|
|
|
61422
61709
|
// src/stage-runner.ts
|
|
61423
61710
|
var import_node_child_process17 = require("node:child_process");
|
|
61424
61711
|
var import_node_fs51 = require("node:fs");
|
|
61425
|
-
var
|
|
61712
|
+
var import_node_path48 = require("node:path");
|
|
61426
61713
|
var import_node_net = require("node:net");
|
|
61427
61714
|
var import_node_util5 = require("node:util");
|
|
61428
61715
|
|
|
@@ -61433,7 +61720,7 @@ function normalizeEol2(s) {
|
|
|
61433
61720
|
|
|
61434
61721
|
// src/env-detection.ts
|
|
61435
61722
|
var import_node_fs50 = require("node:fs");
|
|
61436
|
-
var
|
|
61723
|
+
var import_node_path47 = require("node:path");
|
|
61437
61724
|
var SKIPPED_DIRS = /* @__PURE__ */ new Set([".git", "node_modules", "dist", ".jerv", ".pi", ".venv", "venv"]);
|
|
61438
61725
|
function isEnvBaseName(name) {
|
|
61439
61726
|
return name.toLowerCase() === ".env";
|
|
@@ -61451,13 +61738,13 @@ function findEnvFiles(root) {
|
|
|
61451
61738
|
const relPath = rel ? `${rel}/${entry.name}` : entry.name;
|
|
61452
61739
|
if (entry.isDirectory()) {
|
|
61453
61740
|
if (SKIPPED_DIRS.has(entry.name)) continue;
|
|
61454
|
-
walk2((0,
|
|
61741
|
+
walk2((0, import_node_path47.join)(dir, entry.name), relPath);
|
|
61455
61742
|
continue;
|
|
61456
61743
|
}
|
|
61457
61744
|
if (isEnvBaseName(entry.name)) {
|
|
61458
61745
|
let isDir = false;
|
|
61459
61746
|
try {
|
|
61460
|
-
isDir = (0, import_node_fs50.lstatSync)((0,
|
|
61747
|
+
isDir = (0, import_node_fs50.lstatSync)((0, import_node_path47.join)(dir, entry.name)).isDirectory();
|
|
61461
61748
|
} catch {
|
|
61462
61749
|
}
|
|
61463
61750
|
if (!isDir) found.push(relPath);
|
|
@@ -61596,10 +61883,10 @@ var DOCKER_TIMEOUT_MS = 15e3;
|
|
|
61596
61883
|
function stageBash() {
|
|
61597
61884
|
if (process.platform !== "win32") return "bash";
|
|
61598
61885
|
const configured = process.env.SHELL;
|
|
61599
|
-
if (configured && (0,
|
|
61886
|
+
if (configured && (0, import_node_path48.isAbsolute)(configured) && /[/\\]bash(?:\.exe)?$/i.test(configured) && !/[/\\](?:System32|Sysnative)[/\\]bash(?:\.exe)?$/i.test(configured) && (0, import_node_fs51.existsSync)(configured)) return configured;
|
|
61600
61887
|
const candidates = [
|
|
61601
|
-
(0,
|
|
61602
|
-
...process.env.LOCALAPPDATA ? [(0,
|
|
61888
|
+
(0, import_node_path48.join)(process.env.ProgramFiles || "C:\\Program Files", "Git", "bin", "bash.exe"),
|
|
61889
|
+
...process.env.LOCALAPPDATA ? [(0, import_node_path48.join)(process.env.LOCALAPPDATA, "Programs", "Git", "bin", "bash.exe")] : []
|
|
61603
61890
|
];
|
|
61604
61891
|
const bash = candidates.find((path2) => (0, import_node_fs51.existsSync)(path2));
|
|
61605
61892
|
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.");
|
|
@@ -61739,7 +62026,7 @@ function appendForceRecreate(up) {
|
|
|
61739
62026
|
return `${up.trimEnd()} --force-recreate`;
|
|
61740
62027
|
}
|
|
61741
62028
|
function stageStatePath(cwd = process.cwd()) {
|
|
61742
|
-
return (0,
|
|
62029
|
+
return (0, import_node_path48.join)(cwd, "tmp", "stage", "state.json");
|
|
61743
62030
|
}
|
|
61744
62031
|
function normPath(path2) {
|
|
61745
62032
|
return path2.replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
@@ -61956,7 +62243,7 @@ function stageProcessEnv(stagePort, extraEnv) {
|
|
|
61956
62243
|
}
|
|
61957
62244
|
function composeResolvesPort(cwd) {
|
|
61958
62245
|
if (process.env.PORT) return true;
|
|
61959
|
-
const envFile = (0,
|
|
62246
|
+
const envFile = (0, import_node_path48.join)(cwd, ".env");
|
|
61960
62247
|
return (0, import_node_fs51.existsSync)(envFile) && envFileKeys((0, import_node_fs51.readFileSync)(envFile, "utf8")).has("PORT");
|
|
61961
62248
|
}
|
|
61962
62249
|
function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
@@ -61972,13 +62259,13 @@ function stageComposeEnv(config, stagePort, vaultEnvMerge, cwd) {
|
|
|
61972
62259
|
function stageComposeFiles(cwd) {
|
|
61973
62260
|
const files = ["docker-compose.yml"];
|
|
61974
62261
|
for (const conventional of ["docker-compose.override.yml", "docker-compose.override.yaml"]) {
|
|
61975
|
-
if ((0, import_node_fs51.existsSync)((0,
|
|
62262
|
+
if ((0, import_node_fs51.existsSync)((0, import_node_path48.join)(cwd, conventional))) files.push(conventional);
|
|
61976
62263
|
}
|
|
61977
62264
|
return [...files, RUNTIME_ENV_OVERRIDE_RELPATH];
|
|
61978
62265
|
}
|
|
61979
62266
|
async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
61980
62267
|
const keys = Object.keys(vaultEnvMerge ?? {});
|
|
61981
|
-
if (!keys.length || !(0, import_node_fs51.existsSync)((0,
|
|
62268
|
+
if (!keys.length || !(0, import_node_fs51.existsSync)((0, import_node_path48.join)(cwd, "docker-compose.yml"))) return {};
|
|
61982
62269
|
let configJson;
|
|
61983
62270
|
try {
|
|
61984
62271
|
const { stdout } = await execFileP3("docker", ["compose", "config", "--format", "json"], {
|
|
@@ -61994,15 +62281,15 @@ async function prepareRuntimeEnvPassthrough(cwd, composeEnv, vaultEnvMerge) {
|
|
|
61994
62281
|
}
|
|
61995
62282
|
const body = renderRuntimeEnvOverride(runtimeEnvMarkedServices(configJson), keys, runtimeEnvExcludes(configJson), runtimeEnvSelects(configJson));
|
|
61996
62283
|
if (!body) return {};
|
|
61997
|
-
const overridePath = (0,
|
|
61998
|
-
(0, import_node_fs51.mkdirSync)((0,
|
|
62284
|
+
const overridePath = (0, import_node_path48.join)(cwd, RUNTIME_ENV_OVERRIDE_RELPATH);
|
|
62285
|
+
(0, import_node_fs51.mkdirSync)((0, import_node_path48.join)(cwd, "tmp", "stage"), { recursive: true });
|
|
61999
62286
|
(0, import_node_fs51.writeFileSync)(overridePath, body, "utf8");
|
|
62000
62287
|
return stageComposeFileEnv(stageComposeFiles(cwd));
|
|
62001
62288
|
}
|
|
62002
62289
|
async function ensureStageRuntimeEnv(config, opts, cwd) {
|
|
62003
62290
|
if (!config.ensureEnv) return;
|
|
62004
|
-
const target = (0,
|
|
62005
|
-
const example = (0,
|
|
62291
|
+
const target = (0, import_node_path48.join)(cwd, config.ensureEnv.target);
|
|
62292
|
+
const example = (0, import_node_path48.join)(cwd, config.ensureEnv.example);
|
|
62006
62293
|
if (!(0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
|
|
62007
62294
|
(0, import_node_fs51.copyFileSync)(example, target);
|
|
62008
62295
|
} else if ((0, import_node_fs51.existsSync)(target) && (0, import_node_fs51.existsSync)(example)) {
|
|
@@ -62356,7 +62643,7 @@ function normPath2(p) {
|
|
|
62356
62643
|
return p.replace(/\\/g, "/").replace(/\/+$/, "");
|
|
62357
62644
|
}
|
|
62358
62645
|
function unlinkNodeModulesJunction(wtPath) {
|
|
62359
|
-
const nm = (0,
|
|
62646
|
+
const nm = (0, import_node_path49.join)(wtPath, "node_modules");
|
|
62360
62647
|
try {
|
|
62361
62648
|
if ((0, import_node_fs52.lstatSync)(nm).isSymbolicLink()) (0, import_node_fs52.rmdirSync)(nm);
|
|
62362
62649
|
return { ok: true };
|
|
@@ -62493,7 +62780,7 @@ async function preCleanWorktreeForRemoval(wtPath, execGit) {
|
|
|
62493
62780
|
}
|
|
62494
62781
|
async function listNestedIgnoredNodeModules(wtPath, execGit) {
|
|
62495
62782
|
const out = await execGit(["-C", wtPath, "ls-files", "--others", "--ignored", "--exclude-standard", "--directory"]).catch(() => "");
|
|
62496
|
-
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0,
|
|
62783
|
+
return out.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.endsWith("node_modules/") && line !== "node_modules/").map((line) => (0, import_node_path49.join)(wtPath, line.slice(0, -1)));
|
|
62497
62784
|
}
|
|
62498
62785
|
function safeRemoveTree(path2) {
|
|
62499
62786
|
const stat4 = (0, import_node_fs52.lstatSync)(path2);
|
|
@@ -62506,7 +62793,7 @@ function safeRemoveTree(path2) {
|
|
|
62506
62793
|
return;
|
|
62507
62794
|
}
|
|
62508
62795
|
if (stat4.isDirectory()) {
|
|
62509
|
-
for (const entry of (0, import_node_fs52.readdirSync)(path2)) safeRemoveTree((0,
|
|
62796
|
+
for (const entry of (0, import_node_fs52.readdirSync)(path2)) safeRemoveTree((0, import_node_path49.join)(path2, entry));
|
|
62510
62797
|
(0, import_node_fs52.rmdirSync)(path2);
|
|
62511
62798
|
return;
|
|
62512
62799
|
}
|
|
@@ -62514,7 +62801,7 @@ function safeRemoveTree(path2) {
|
|
|
62514
62801
|
}
|
|
62515
62802
|
async function removeWorktreeNodeModules(wtPath) {
|
|
62516
62803
|
try {
|
|
62517
|
-
safeRemoveTree((0,
|
|
62804
|
+
safeRemoveTree((0, import_node_path49.join)(wtPath, "node_modules"));
|
|
62518
62805
|
return { ok: true };
|
|
62519
62806
|
} catch (e) {
|
|
62520
62807
|
if (e.code === "ENOENT") return { ok: true };
|
|
@@ -62559,7 +62846,7 @@ function unlinkEscapingReparsePoints(root, primaryRoot) {
|
|
|
62559
62846
|
return { ok: false, error: `cannot scan ${normPath2(dir)} for reparse points: ${errorMessage(e)}` };
|
|
62560
62847
|
}
|
|
62561
62848
|
for (const entry of entries) {
|
|
62562
|
-
const child2 = (0,
|
|
62849
|
+
const child2 = (0, import_node_path49.join)(dir, entry.name);
|
|
62563
62850
|
if (entry.isSymbolicLink()) {
|
|
62564
62851
|
let target = "";
|
|
62565
62852
|
try {
|
|
@@ -62886,7 +63173,7 @@ async function cleanupPrMergeLocalBranch(branch, options) {
|
|
|
62886
63173
|
const preHelperGuard = unlinkEscapingReparsePoints(wtPath, options.primaryRoot);
|
|
62887
63174
|
if (!preHelperGuard.ok) return refuseReparseEscape(preHelperGuard.error);
|
|
62888
63175
|
unlinkedReparsePoints.push(...preHelperGuard.unlinked);
|
|
62889
|
-
if (pathExists((0,
|
|
63176
|
+
if (pathExists((0, import_node_path49.join)(wtPath, "node_modules"))) {
|
|
62890
63177
|
const nmRemoved = await (options.removeRealNodeModules ?? removeWorktreeNodeModules)(wtPath);
|
|
62891
63178
|
if (!nmRemoved.ok) {
|
|
62892
63179
|
report.worktree = {
|
|
@@ -63022,35 +63309,35 @@ function renderPrMergeCleanupLines(cleanup) {
|
|
|
63022
63309
|
// src/worktree-residue-sweep.ts
|
|
63023
63310
|
var RESIDUE_LEDGER_FILE = "mmi-worktree-residue.json";
|
|
63024
63311
|
function canonicalWorktreeRoot(primary) {
|
|
63025
|
-
return (0,
|
|
63312
|
+
return (0, import_node_path50.join)((0, import_node_path50.dirname)(primary), "mmi-worktrees", (0, import_node_path50.basename)(primary));
|
|
63026
63313
|
}
|
|
63027
63314
|
function lastSegment(p) {
|
|
63028
|
-
return (0,
|
|
63315
|
+
return (0, import_node_path50.basename)(p.split(/[\\/]+/).filter(Boolean).pop() ?? p);
|
|
63029
63316
|
}
|
|
63030
63317
|
function readProvenance(folder, gitCommonDir, exists) {
|
|
63031
63318
|
const found = {
|
|
63032
63319
|
path: folder,
|
|
63033
63320
|
gitdirPresent: false,
|
|
63034
|
-
registrationId: (0,
|
|
63321
|
+
registrationId: (0, import_node_path50.basename)(folder),
|
|
63035
63322
|
registrationPresent: false
|
|
63036
63323
|
};
|
|
63037
63324
|
try {
|
|
63038
|
-
const pointer = /^\s*gitdir:\s*(.+?)\s*$/m.exec((0, import_node_fs53.readFileSync)((0,
|
|
63325
|
+
const pointer = /^\s*gitdir:\s*(.+?)\s*$/m.exec((0, import_node_fs53.readFileSync)((0, import_node_path50.join)(folder, ".git"), "utf8"));
|
|
63039
63326
|
if (pointer) {
|
|
63040
63327
|
const target = pointer[1];
|
|
63041
|
-
found.gitdir = (0,
|
|
63328
|
+
found.gitdir = (0, import_node_path50.isAbsolute)(target) ? target : (0, import_node_path50.join)(folder, target);
|
|
63042
63329
|
found.gitdirPresent = exists(found.gitdir);
|
|
63043
63330
|
found.registrationId = lastSegment(found.gitdir);
|
|
63044
63331
|
}
|
|
63045
63332
|
} catch {
|
|
63046
63333
|
}
|
|
63047
63334
|
try {
|
|
63048
|
-
found.registrationPresent = exists((0,
|
|
63335
|
+
found.registrationPresent = exists((0, import_node_path50.join)(gitCommonDir, "worktrees", found.registrationId));
|
|
63049
63336
|
} catch {
|
|
63050
63337
|
}
|
|
63051
63338
|
if (found.gitdir && found.gitdirPresent) {
|
|
63052
63339
|
try {
|
|
63053
|
-
const head = (0, import_node_fs53.readFileSync)((0,
|
|
63340
|
+
const head = (0, import_node_fs53.readFileSync)((0, import_node_path50.join)(found.gitdir, "HEAD"), "utf8").trim();
|
|
63054
63341
|
const branch = /^ref:\s*(.+?)\s*$/.exec(head);
|
|
63055
63342
|
if (branch) found.head = branch[1].startsWith("refs/heads/") ? branch[1].slice("refs/heads/".length) : `ref ${branch[1]}`;
|
|
63056
63343
|
else if (/^[0-9a-f]{7,64}$/i.test(head)) found.head = `detached ${head.slice(0, 12)}`;
|
|
@@ -63069,7 +63356,7 @@ function norm2(p) {
|
|
|
63069
63356
|
return process.platform === "win32" ? s.toLowerCase() : s;
|
|
63070
63357
|
}
|
|
63071
63358
|
function residueLedgerPath(gitCommonDir) {
|
|
63072
|
-
return (0,
|
|
63359
|
+
return (0, import_node_path50.join)(gitCommonDir, RESIDUE_LEDGER_FILE);
|
|
63073
63360
|
}
|
|
63074
63361
|
function readPaths(file, deps) {
|
|
63075
63362
|
try {
|
|
@@ -63082,7 +63369,7 @@ function readPaths(file, deps) {
|
|
|
63082
63369
|
function writePaths(file, paths, deps) {
|
|
63083
63370
|
try {
|
|
63084
63371
|
const write = deps.writeLedger ?? ((f, t) => {
|
|
63085
|
-
(0, import_node_fs53.mkdirSync)((0,
|
|
63372
|
+
(0, import_node_fs53.mkdirSync)((0, import_node_path50.dirname)(f), { recursive: true });
|
|
63086
63373
|
(0, import_node_fs53.writeFileSync)(f, t, "utf8");
|
|
63087
63374
|
});
|
|
63088
63375
|
write(file, `${JSON.stringify([...new Set(paths)], null, 1)}
|
|
@@ -63142,7 +63429,7 @@ async function sweepWorktreeResidue(gitCommonDir, registered, deps = {}) {
|
|
|
63142
63429
|
} catch {
|
|
63143
63430
|
}
|
|
63144
63431
|
for (const name of children) {
|
|
63145
|
-
const child2 = (0,
|
|
63432
|
+
const child2 = (0, import_node_path50.join)(root, name);
|
|
63146
63433
|
const key = norm2(child2);
|
|
63147
63434
|
if (live.has(key) || key === primary || keptKeys.has(key) || !isDir(child2)) continue;
|
|
63148
63435
|
let entries;
|
|
@@ -63194,10 +63481,10 @@ function argvWantsJson2() {
|
|
|
63194
63481
|
return process.argv.some((a) => a === "--json" || a.startsWith("--json="));
|
|
63195
63482
|
}
|
|
63196
63483
|
function hubRoot() {
|
|
63197
|
-
const fromPkg = (0,
|
|
63484
|
+
const fromPkg = (0, import_node_path51.join)(__dirname, "..", "..");
|
|
63198
63485
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
63199
|
-
if ((0, import_node_fs54.existsSync)((0,
|
|
63200
|
-
if ((0, import_node_fs54.existsSync)((0,
|
|
63486
|
+
if ((0, import_node_fs54.existsSync)((0, import_node_path51.join)(fromPkg, marker))) return fromPkg;
|
|
63487
|
+
if ((0, import_node_fs54.existsSync)((0, import_node_path51.join)(process.cwd(), marker))) return process.cwd();
|
|
63201
63488
|
return null;
|
|
63202
63489
|
}
|
|
63203
63490
|
function ciAuditDeps() {
|
|
@@ -63209,7 +63496,7 @@ function ciAuditDeps() {
|
|
|
63209
63496
|
getProjectMeta: async (slug) => fetchProjectBySlug(slug, registryClientDeps(await cfgPromise)),
|
|
63210
63497
|
readSeedFile: (path2) => {
|
|
63211
63498
|
if (!root) return null;
|
|
63212
|
-
const fullPath = (0,
|
|
63499
|
+
const fullPath = (0, import_node_path51.join)(root, path2);
|
|
63213
63500
|
return (0, import_node_fs54.existsSync)(fullPath) ? (0, import_node_fs54.readFileSync)(fullPath, "utf8") : null;
|
|
63214
63501
|
}
|
|
63215
63502
|
};
|
|
@@ -63338,6 +63625,24 @@ async function attachToProject(issueNumber, repo, priority) {
|
|
|
63338
63625
|
}
|
|
63339
63626
|
return boardAttachRateLimitedReceipt(resetEpochSeconds);
|
|
63340
63627
|
}
|
|
63628
|
+
const authority = contentId ? await attachOnAuthorityRefusal(detail, cfg, contentId) : void 0;
|
|
63629
|
+
if (authority && "projectItemId" in authority) {
|
|
63630
|
+
if (priority) {
|
|
63631
|
+
try {
|
|
63632
|
+
await setBoardItemPriority(defaultGitHubClient(), cfg, authority.projectItemId, priority);
|
|
63633
|
+
} catch (pe) {
|
|
63634
|
+
const perr = pe;
|
|
63635
|
+
process.stderr.write(`warning: issue #${issueNumber} board Priority not set: ${(perr.stderr || perr.message || String(pe)).trim()}
|
|
63636
|
+
`);
|
|
63637
|
+
}
|
|
63638
|
+
}
|
|
63639
|
+
return { projectItemId: authority.projectItemId, onBoard: true, credential: "app_installation" };
|
|
63640
|
+
}
|
|
63641
|
+
if (authority) {
|
|
63642
|
+
process.stderr.write(`warning: issue #${issueNumber} created but NOT added to the project board: ${authority.warning}
|
|
63643
|
+
`);
|
|
63644
|
+
return { onBoard: false };
|
|
63645
|
+
}
|
|
63341
63646
|
process.stderr.write(`warning: issue #${issueNumber} created but NOT added to the project board: ${detail}
|
|
63342
63647
|
`);
|
|
63343
63648
|
return { onBoard: false };
|
|
@@ -63416,7 +63721,7 @@ function registerCollaborationCommands(program3) {
|
|
|
63416
63721
|
try {
|
|
63417
63722
|
title = await resolveIssueTitle(
|
|
63418
63723
|
{ title: opts.title, titleFile: opts.titleFile },
|
|
63419
|
-
{ readFile:
|
|
63724
|
+
{ readFile: import_promises9.readFile, readStdin }
|
|
63420
63725
|
);
|
|
63421
63726
|
} catch (e) {
|
|
63422
63727
|
return fail(
|
|
@@ -63470,8 +63775,8 @@ function registerCollaborationCommands(program3) {
|
|
|
63470
63775
|
let surfaceInferred;
|
|
63471
63776
|
try {
|
|
63472
63777
|
issueType = resolveCreateType(o.type, "issue create", o.label);
|
|
63473
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
63474
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
63778
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63779
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63475
63780
|
if (o.idempotencyKey) body = appendIdempotencyMarker(body, o.idempotencyKey);
|
|
63476
63781
|
priority = resolveCreatePriority(o.priority, "issue create");
|
|
63477
63782
|
extraLabels = [...o.label ?? []];
|
|
@@ -63786,7 +64091,7 @@ function registerCollaborationCommands(program3) {
|
|
|
63786
64091
|
}
|
|
63787
64092
|
let body;
|
|
63788
64093
|
try {
|
|
63789
|
-
body = o.edit !== void 0 ? "" : await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
64094
|
+
body = o.edit !== void 0 ? "" : await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63790
64095
|
} catch (e) {
|
|
63791
64096
|
return fail(`issue comment: ${e.message}`);
|
|
63792
64097
|
}
|
|
@@ -63865,8 +64170,8 @@ ${list}`);
|
|
|
63865
64170
|
let title;
|
|
63866
64171
|
const sourceRepo = o.repo ?? await resolveRepo(void 0);
|
|
63867
64172
|
try {
|
|
63868
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
63869
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
64173
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises9.readFile, readStdin });
|
|
64174
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63870
64175
|
priority = resolveCreatePriority(o.priority, "report");
|
|
63871
64176
|
if (!ISSUE_TYPES.includes(o.type)) {
|
|
63872
64177
|
throw new Error(`unknown issue type "${o.type}" \u2014 expected one of: ${ISSUE_TYPES.join(", ")}`);
|
|
@@ -63920,8 +64225,8 @@ ${list}`);
|
|
|
63920
64225
|
let args;
|
|
63921
64226
|
try {
|
|
63922
64227
|
skill = assertSkillName(o.skill);
|
|
63923
|
-
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
63924
|
-
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
64228
|
+
rawBody = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises9.readFile, readStdin });
|
|
64229
|
+
const rawTitle = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63925
64230
|
title = buildSkillLessonTitle(skill, rawTitle);
|
|
63926
64231
|
priority = resolveCreatePriority(o.priority, "skill-lesson");
|
|
63927
64232
|
body = buildSkillLessonBody(rawBody, sourceRepo, pluginSha);
|
|
@@ -63982,8 +64287,8 @@ ${list}`);
|
|
|
63982
64287
|
let body;
|
|
63983
64288
|
let title;
|
|
63984
64289
|
try {
|
|
63985
|
-
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile:
|
|
63986
|
-
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile:
|
|
64290
|
+
title = await resolveIssueTitle({ title: o.title, titleFile: o.titleFile }, { readFile: import_promises9.readFile, readStdin });
|
|
64291
|
+
body = await resolveIssueBody({ body: o.body, bodyFile: o.bodyFile }, { readFile: import_promises9.readFile, readStdin });
|
|
63987
64292
|
} catch (e) {
|
|
63988
64293
|
return fail(`pr create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
|
|
63989
64294
|
}
|
|
@@ -64077,11 +64382,11 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
|
|
|
64077
64382
|
}
|
|
64078
64383
|
});
|
|
64079
64384
|
async function listCiWorkflowPaths(cwd = process.cwd()) {
|
|
64080
|
-
const wfDir = (0,
|
|
64385
|
+
const wfDir = (0, import_node_path51.join)(cwd, ".github", "workflows");
|
|
64081
64386
|
if (!(0, import_node_fs54.existsSync)(wfDir)) return [];
|
|
64082
64387
|
return (0, import_node_fs54.readdirSync)(wfDir).filter((name) => /\.(ya?ml)$/i.test(name)).filter((name) => {
|
|
64083
64388
|
try {
|
|
64084
|
-
return workflowReportsPrChecks((0, import_node_fs54.readFileSync)((0,
|
|
64389
|
+
return workflowReportsPrChecks((0, import_node_fs54.readFileSync)((0, import_node_path51.join)(wfDir, name), "utf8"));
|
|
64085
64390
|
} catch {
|
|
64086
64391
|
return true;
|
|
64087
64392
|
}
|
|
@@ -64336,7 +64641,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
|
|
|
64336
64641
|
}
|
|
64337
64642
|
class PrHeadBehindBaseError extends Error {
|
|
64338
64643
|
}
|
|
64339
|
-
pr.command("land <numbers...>").description("agent merge path (#1440): train probe \u2014 checks-wait \u2014 merge --auto \u2014 poll enqueued \u2014 development PRs only. Several PR numbers land together (#8322): all are enqueued, waited on together, a queue-ejected PR is updated and re-enqueued once, a queue merge is followed by worktree/branch cleanup and board Done, and one table (or --json) reports each outcome").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the PR repo)").option("--enqueue-only", "return once queue membership is confirmed; without a merge queue, land normally").option("--abandon-admission", "one stuck-receipt recovery, one PR per call: journal the saved non-terminal (pending/enqueued) queue-admission receipt terminal ONLY after positively observing the PR OPEN at the receipt head and absent from the queue; any unprovable observation refuses and changes nothing (#9951). The next pr land then submits a new intent with no new head").option("--no-require-train", "skip train-authority preflight (not recommended for autonomous agents)").option("--force", "silence the leftover-scratch warning (scratch never blocks, #8785) and acknowledge 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").option("--timeout <minutes>", `merge-queue wait per PR (default ${PR_LAND_QUEUE_TIMEOUT_MS / 6e4} minutes, one window per ${PR_LAND_QUEUE_BATCH_SIZE} PRs \u2014 per-repo ruleset check_response_timeout_minutes is 15 default with 30/45/60 overrides in .github/rulesets/mmi-development-merge-queue.json; agents never edit the ruleset to shorten a queue wait)`).option("--preserve-worktree", "after a queue merge keep the local worktree and branch (skips the post-merge cleanup)").option("--expect-head <sha>", "pin the PR head to this full 40-hex SHA (#8456): checked before landing, after checks and by GitHub at enqueue (--match-head-commit); never updates a BEHIND head and never retries an ejection \u2014 it stops with pinnedHead.refused instead. One PR only").action(async (numbers, opts) => {
|
|
64644
|
+
pr.command("land <numbers...>").description("agent merge path (#1440): train probe \u2014 checks-wait \u2014 merge --auto \u2014 poll enqueued \u2014 development PRs only. Several PR numbers land together (#8322): all are enqueued, waited on together, a queue-ejected PR is updated and re-enqueued once, a queue merge is followed by worktree/branch cleanup and board Done, and one table (or --json) reports each outcome").option("--json", "machine-readable output").option("--repo <owner/repo>", "target repo (defaults to the PR repo)").option("--enqueue-only", "return once queue membership is confirmed; without a merge queue, land normally").option("--abandon-admission", "one stuck-receipt recovery, one PR per call: journal the saved non-terminal (pending/enqueued, or a dispatching send that saved no operation UUID after its sender died \u2014 #9995) queue-admission receipt terminal ONLY after positively observing the PR OPEN at the receipt head and absent from the queue; any unprovable observation refuses and changes nothing (#9951). The next pr land then submits a new intent with no new head").option("--no-require-train", "skip train-authority preflight (not recommended for autonomous agents)").option("--force", "silence the leftover-scratch warning (scratch never blocks, #8785) and acknowledge 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").option("--timeout <minutes>", `merge-queue wait per PR (default ${PR_LAND_QUEUE_TIMEOUT_MS / 6e4} minutes, one window per ${PR_LAND_QUEUE_BATCH_SIZE} PRs \u2014 per-repo ruleset check_response_timeout_minutes is 15 default with 30/45/60 overrides in .github/rulesets/mmi-development-merge-queue.json; agents never edit the ruleset to shorten a queue wait)`).option("--preserve-worktree", "after a queue merge keep the local worktree and branch (skips the post-merge cleanup)").option("--expect-head <sha>", "pin the PR head to this full 40-hex SHA (#8456): checked before landing, after checks and by GitHub at enqueue (--match-head-commit); never updates a BEHIND head and never retries an ejection \u2014 it stops with pinnedHead.refused instead. One PR only").action(async (numbers, opts) => {
|
|
64340
64645
|
const timeoutMinutes = opts.timeout === void 0 ? void 0 : Number(opts.timeout);
|
|
64341
64646
|
if (timeoutMinutes !== void 0 && !(timeoutMinutes > 0)) return fail("pr land: --timeout must be a positive number of minutes");
|
|
64342
64647
|
if (opts.abandonAdmission) {
|
|
@@ -64677,7 +64982,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
|
|
|
64677
64982
|
const remote = foreignCwd ? `https://github.com/${targetRepo2}.git` : "origin";
|
|
64678
64983
|
let foreignCheckout;
|
|
64679
64984
|
if (foreignCwd) {
|
|
64680
|
-
const sibling = (0,
|
|
64985
|
+
const sibling = (0, import_node_path51.join)((0, import_node_path51.dirname)(beforeWorktrees[0]?.path || startingPath || process.cwd()), targetRepo2.split("/")[1]);
|
|
64681
64986
|
const siblingRepo = repoFromRemoteUrl(await gitOut(["-C", sibling, "remote", "get-url", "origin"]).catch(() => ""));
|
|
64682
64987
|
if (siblingRepo?.toLowerCase() === targetRepo2.toLowerCase()) {
|
|
64683
64988
|
const siblingWorktrees = await execFileP("git", ["-C", sibling, "worktree", "list", "--porcelain"], { timeout: GIT_TIMEOUT_MS }).then((r) => parseGitWorktreePorcelain(r.stdout)).catch(() => void 0);
|
|
@@ -64911,7 +65216,7 @@ ${preparation.findings.map((finding) => `[${finding.check}/${finding.state}] ${f
|
|
|
64911
65216
|
let residueSweep;
|
|
64912
65217
|
if (!(foreignCwd && !foreignCheckout)) {
|
|
64913
65218
|
try {
|
|
64914
|
-
gitCommonDir = (0,
|
|
65219
|
+
gitCommonDir = (0, import_node_path51.resolve)(primaryRoot, (await execFileP("git", ["-C", primaryRoot, "rev-parse", "--git-common-dir"], { timeout: GIT_TIMEOUT_MS })).stdout.trim());
|
|
64915
65220
|
residueSweep = await sweepWorktreeResidue(gitCommonDir, beforeWorktrees.map((w) => w.path));
|
|
64916
65221
|
} catch {
|
|
64917
65222
|
}
|
|
@@ -65131,7 +65436,7 @@ function trainGitArgs(args) {
|
|
|
65131
65436
|
async function announceSummaryLineCountRefusal(path2) {
|
|
65132
65437
|
let content;
|
|
65133
65438
|
try {
|
|
65134
|
-
content = await (0,
|
|
65439
|
+
content = await (0, import_promises10.readFile)(path2, "utf8");
|
|
65135
65440
|
} catch (e) {
|
|
65136
65441
|
return `release: could not read --announce-summary-file ${path2}: ${e.message} \u2014 see https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#announce-summary-missing`;
|
|
65137
65442
|
}
|
|
@@ -65143,7 +65448,7 @@ async function announceSummaryLineCountRefusal(path2) {
|
|
|
65143
65448
|
async function announceSummaryRefusal(path2, isHub = false, isWorkSuite = false) {
|
|
65144
65449
|
let lines2;
|
|
65145
65450
|
try {
|
|
65146
|
-
lines2 = summaryFileLines(await (0,
|
|
65451
|
+
lines2 = summaryFileLines(await (0, import_promises10.readFile)(path2, "utf8"));
|
|
65147
65452
|
} catch (e) {
|
|
65148
65453
|
return `release: could not read --announce-summary-file ${path2}: ${e.message} \u2014 see https://github.com/mutmutco/MMI-Hub/blob/development/docs/Guides/train-troubleshooting.md#announce-summary-missing`;
|
|
65149
65454
|
}
|
|
@@ -65281,8 +65586,8 @@ function trainApplyDeps() {
|
|
|
65281
65586
|
}
|
|
65282
65587
|
return body.status;
|
|
65283
65588
|
},
|
|
65284
|
-
readFile: (path2) => (0,
|
|
65285
|
-
removeFile: (path2) => (0,
|
|
65589
|
+
readFile: (path2) => (0, import_promises10.readFile)(path2, "utf8"),
|
|
65590
|
+
removeFile: (path2) => (0, import_promises10.unlink)(path2),
|
|
65286
65591
|
// #6521/#6523: the project's own release channel AND releaseLanguage, read from registry META in ONE
|
|
65287
65592
|
// checked read. Same shape as fetchEdgeDomains below: a FAILED read refuses by name so the announce
|
|
65288
65593
|
// note reports a failed read, never a project that configured nothing.
|
|
@@ -66210,7 +66515,7 @@ function rcRunCauseFromLog(log) {
|
|
|
66210
66515
|
function memberAnnounceSummaryFile(repo, summaryFile, memberSummaryFiles) {
|
|
66211
66516
|
return repo === SUITE_REPO ? summaryFile : memberSummaryFiles[repo];
|
|
66212
66517
|
}
|
|
66213
|
-
var suiteStateDir = (root) => (0,
|
|
66518
|
+
var suiteStateDir = (root) => (0, import_node_path53.join)(resolvePrimaryGitDir(root), "mmi-runtime", "suite");
|
|
66214
66519
|
async function runSuiteMemberRcand(repo, previousRc, rcWasAbsent) {
|
|
66215
66520
|
const deps = trainApplyDeps();
|
|
66216
66521
|
deps.suiteCut = suiteCutContext(repo, SUITE_REPO);
|
|
@@ -66257,16 +66562,16 @@ async function rcandInCheckout(repo, deps, previousRc, rcWasAbsent) {
|
|
|
66257
66562
|
}
|
|
66258
66563
|
}
|
|
66259
66564
|
function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr, memberSummaryFilesTr = {}) {
|
|
66260
|
-
const recordPath = (0,
|
|
66261
|
-
const base = (0,
|
|
66565
|
+
const recordPath = (0, import_node_path53.join)(suiteStateDir(root), "cut.json");
|
|
66566
|
+
const base = (0, import_node_path53.join)(suiteStateDir(root), "checkouts");
|
|
66262
66567
|
const checkout = async (repo) => {
|
|
66263
66568
|
if (repo === SUITE_REPO) return root;
|
|
66264
|
-
const target = (0,
|
|
66569
|
+
const target = (0, import_node_path53.join)(base, repo.split("/")[1]);
|
|
66265
66570
|
if (!(0, import_node_fs55.existsSync)(target)) {
|
|
66266
66571
|
(0, import_node_fs55.mkdirSync)(base, { recursive: true });
|
|
66267
66572
|
await exec("git", ["clone", "--quiet", "--branch", "development", `https://github.com/${repo}.git`, target], root, WATCH_TIMEOUT);
|
|
66268
66573
|
}
|
|
66269
|
-
if (!(0, import_node_fs55.existsSync)((0,
|
|
66574
|
+
if (!(0, import_node_fs55.existsSync)((0, import_node_path53.join)(target, ".git"))) throw new Error(`${repo}: suite checkout has no .git at ${target}; stop`);
|
|
66270
66575
|
const origin = await exec("git", ["remote", "get-url", "origin"], target);
|
|
66271
66576
|
if (!origin.toLowerCase().endsWith(`/${repo.toLowerCase()}.git`) && !origin.toLowerCase().endsWith(`/${repo.toLowerCase()}`))
|
|
66272
66577
|
throw new Error(`${repo}: suite checkout origin mismatch at ${target}; stop`);
|
|
@@ -66330,7 +66635,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
66330
66635
|
if (repo === SUITE_REPO) return inTrain(repo, (deps) => rcandInCheckout(repo, deps, previousRc, rcWasAbsent));
|
|
66331
66636
|
const target = await checkout(repo);
|
|
66332
66637
|
return new Promise((resolveResult, reject2) => {
|
|
66333
|
-
const child2 = (0, import_node_child_process19.fork)((0,
|
|
66638
|
+
const child2 = (0, import_node_child_process19.fork)((0, import_node_path52.resolve)(process.argv[1]), ["devops", "suite", "member-rcand-internal", repo, previousRc ?? "", ...rcWasAbsent ? ["--rc-was-absent"] : []], {
|
|
66334
66639
|
cwd: target,
|
|
66335
66640
|
stdio: ["ignore", "inherit", "inherit", "ipc"],
|
|
66336
66641
|
execArgv: []
|
|
@@ -66574,7 +66879,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
66574
66879
|
if (parseSuiteMapping(body)) return;
|
|
66575
66880
|
const dir = suiteStateDir(root);
|
|
66576
66881
|
(0, import_node_fs55.mkdirSync)(dir, { recursive: true });
|
|
66577
|
-
const file = (0,
|
|
66882
|
+
const file = (0, import_node_path53.join)(dir, `notes-${leadTag}.md`);
|
|
66578
66883
|
(0, import_node_fs55.writeFileSync)(file, `${body}
|
|
66579
66884
|
|
|
66580
66885
|
${suiteMappingBlock(leadTag, mapping)}`);
|
|
@@ -66951,8 +67256,8 @@ function registerJevCommands(program3) {
|
|
|
66951
67256
|
// src/packages-adopt-export.ts
|
|
66952
67257
|
var import_node_child_process20 = require("node:child_process");
|
|
66953
67258
|
var import_node_fs57 = require("node:fs");
|
|
66954
|
-
var
|
|
66955
|
-
var
|
|
67259
|
+
var import_node_os26 = require("node:os");
|
|
67260
|
+
var import_node_path54 = require("node:path");
|
|
66956
67261
|
var import_node_util6 = require("node:util");
|
|
66957
67262
|
init_cli_shared();
|
|
66958
67263
|
|
|
@@ -67572,25 +67877,25 @@ function expectedFromRun(run, opts) {
|
|
|
67572
67877
|
}
|
|
67573
67878
|
async function adoptExport(opts, deps) {
|
|
67574
67879
|
if (!/^sha256:[0-9a-f]{64}$/.test(opts.digest)) throw new Error("--digest must be sha256:<64 hex>, from the export run summary");
|
|
67575
|
-
const packagePath = (0,
|
|
67576
|
-
const lockPath = (0,
|
|
67880
|
+
const packagePath = (0, import_node_path54.join)(opts.dir, "package.json");
|
|
67881
|
+
const lockPath = (0, import_node_path54.join)(opts.dir, "package-lock.json");
|
|
67577
67882
|
const packageText = (0, import_node_fs57.readFileSync)(packagePath, "utf8");
|
|
67578
67883
|
const lockText = (0, import_node_fs57.readFileSync)(lockPath, "utf8");
|
|
67579
|
-
const work = (0, import_node_fs57.mkdtempSync)((0,
|
|
67884
|
+
const work = (0, import_node_fs57.mkdtempSync)((0, import_node_path54.join)((0, import_node_os26.tmpdir)(), "mmi-adopt-export-"));
|
|
67580
67885
|
try {
|
|
67581
67886
|
const run = JSON.parse((await deps.ghApi(`repos/${EXPORT_REPO}/actions/runs/${opts.run}`)).toString("utf8"));
|
|
67582
|
-
(0, import_node_fs57.writeFileSync)((0,
|
|
67583
|
-
(0, import_node_fs57.writeFileSync)((0,
|
|
67584
|
-
(0, import_node_fs57.writeFileSync)((0,
|
|
67585
|
-
const script = (0,
|
|
67887
|
+
(0, import_node_fs57.writeFileSync)((0, import_node_path54.join)(work, "expected.json"), JSON.stringify(expectedFromRun(run, opts)));
|
|
67888
|
+
(0, import_node_fs57.writeFileSync)((0, import_node_path54.join)(work, "provider.json"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}`));
|
|
67889
|
+
(0, import_node_fs57.writeFileSync)((0, import_node_path54.join)(work, "artifact.zip"), await deps.ghApi(`repos/${EXPORT_REPO}/actions/artifacts/${opts.artifact}/zip`));
|
|
67890
|
+
const script = (0, import_node_path54.join)(work, "package_export.py");
|
|
67586
67891
|
(0, import_node_fs57.writeFileSync)(script, package_export_default);
|
|
67587
67892
|
await deps.python(script, ["verify", work, opts.ds, opts.screens]);
|
|
67588
|
-
const verified = (0,
|
|
67589
|
-
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs57.readFileSync)((0,
|
|
67893
|
+
const verified = (0, import_node_path54.join)(work, "verified");
|
|
67894
|
+
const metadata = Object.fromEntries(PACKAGES.map(({ name, short: short3 }) => [name, JSON.parse((0, import_node_fs57.readFileSync)((0, import_node_path54.join)(verified, `${short3}.metadata.json`), "utf8"))]));
|
|
67590
67895
|
const plan = planAdoption(packageText, lockText, metadata);
|
|
67591
67896
|
for (const { name } of plan.result.adopted) {
|
|
67592
67897
|
const short3 = PACKAGES.find((p) => p.name === name).short;
|
|
67593
|
-
await deps.npm(["cache", "add", (0,
|
|
67898
|
+
await deps.npm(["cache", "add", (0, import_node_path54.join)(verified, `${short3}.tgz`)], opts.dir);
|
|
67594
67899
|
}
|
|
67595
67900
|
(0, import_node_fs57.writeFileSync)(packagePath, plan.packageText);
|
|
67596
67901
|
(0, import_node_fs57.writeFileSync)(lockPath, plan.lockText);
|
|
@@ -67780,8 +68085,8 @@ async function collectWaveStatus(deps) {
|
|
|
67780
68085
|
init_github_client();
|
|
67781
68086
|
init_cli_shared();
|
|
67782
68087
|
var import_node_fs59 = require("node:fs");
|
|
67783
|
-
var
|
|
67784
|
-
var
|
|
68088
|
+
var import_node_os27 = require("node:os");
|
|
68089
|
+
var import_node_path55 = require("node:path");
|
|
67785
68090
|
var GC_GH_TIMEOUT_MS3 = 2e4;
|
|
67786
68091
|
var defaultStatusDeps = {
|
|
67787
68092
|
repo: resolveRepo,
|
|
@@ -68000,10 +68305,10 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
68000
68305
|
else if (top) nextCommand = `mmi-cli oracle board claim ${top.number} # ${top.title}`;
|
|
68001
68306
|
else nextCommand = "mmi-cli oracle board read \u2014 no claimable items found";
|
|
68002
68307
|
}
|
|
68003
|
-
const home = (0,
|
|
68308
|
+
const home = (0, import_node_os27.homedir)();
|
|
68004
68309
|
const plugin = onboardPluginGate({
|
|
68005
|
-
readKnown: () => readFileSyncSafe((0,
|
|
68006
|
-
readSettings: () => readFileSyncSafe((0,
|
|
68310
|
+
readKnown: () => readFileSyncSafe((0, import_node_path55.join)(home, ...KNOWN_MARKETPLACES_RELATIVE), import_node_fs59.readFileSync),
|
|
68311
|
+
readSettings: () => readFileSyncSafe((0, import_node_path55.join)(home, ".claude", "settings.json"), import_node_fs59.readFileSync)
|
|
68007
68312
|
});
|
|
68008
68313
|
return {
|
|
68009
68314
|
guide: "Read the MMI org-guide skill before project work; load only the relevant topic. Use mmi-help for a short introduction.",
|
|
@@ -70640,7 +70945,7 @@ function registerConnectionsOauth(program3, deps) {
|
|
|
70640
70945
|
}
|
|
70641
70946
|
|
|
70642
70947
|
// src/schedules-commands.ts
|
|
70643
|
-
var
|
|
70948
|
+
var import_promises11 = require("node:fs/promises");
|
|
70644
70949
|
init_clean_exit();
|
|
70645
70950
|
init_github_client();
|
|
70646
70951
|
init_cli_shared();
|
|
@@ -70820,9 +71125,9 @@ function registerSchedulesCommands(program3) {
|
|
|
70820
71125
|
await failGraceful("org schedules --doc: refusing to regenerate the doc from an incomplete read (see warnings above).");
|
|
70821
71126
|
return;
|
|
70822
71127
|
}
|
|
70823
|
-
const docText = await (0,
|
|
71128
|
+
const docText = await (0, import_promises11.readFile)(o.doc, "utf8");
|
|
70824
71129
|
const spliced = spliceDoc(docText, renderDocSection(entries, now.toISOString()));
|
|
70825
|
-
await (0,
|
|
71130
|
+
await (0, import_promises11.writeFile)(o.doc, spliced, "utf8");
|
|
70826
71131
|
reportParked(parkedLines);
|
|
70827
71132
|
reportDrift(drift);
|
|
70828
71133
|
console.log(`org schedules: wrote ${entries.length} entries into ${o.doc}`);
|
|
@@ -71135,7 +71440,7 @@ function registerSessionReport(program3) {
|
|
|
71135
71440
|
|
|
71136
71441
|
// src/stage-commands.ts
|
|
71137
71442
|
var import_node_fs60 = require("node:fs");
|
|
71138
|
-
var
|
|
71443
|
+
var import_node_path56 = require("node:path");
|
|
71139
71444
|
init_cli_shared();
|
|
71140
71445
|
init_clean_exit();
|
|
71141
71446
|
|
|
@@ -71383,8 +71688,8 @@ function registerStageCommands(program3) {
|
|
|
71383
71688
|
const repo = Array.isArray(project2?.repos) && typeof project2.repos[0] === "string" ? project2.repos[0] : slug;
|
|
71384
71689
|
const resolution = decideStage({
|
|
71385
71690
|
registry: { deployModel: project2?.deployModel, portRange, error: read.ok ? void 0 : read.error },
|
|
71386
|
-
hasCompose: (0, import_node_fs60.existsSync)((0,
|
|
71387
|
-
hasEnvExample: (0, import_node_fs60.existsSync)((0,
|
|
71691
|
+
hasCompose: (0, import_node_fs60.existsSync)((0, import_node_path56.join)(process.cwd(), "docker-compose.yml")),
|
|
71692
|
+
hasEnvExample: (0, import_node_fs60.existsSync)((0, import_node_path56.join)(process.cwd(), ".env.example")),
|
|
71388
71693
|
repo
|
|
71389
71694
|
});
|
|
71390
71695
|
if (resolution.source === "derived" && resolution.derived) {
|
|
@@ -71676,21 +71981,21 @@ vercel preview (${preview.branch}): ${d.state}${d.url ? ` \u2014 ${d.url}` : ""}
|
|
|
71676
71981
|
}
|
|
71677
71982
|
|
|
71678
71983
|
// src/tenant-artifact.ts
|
|
71679
|
-
var
|
|
71984
|
+
var import_node_crypto24 = require("node:crypto");
|
|
71680
71985
|
var import_node_fs61 = require("node:fs");
|
|
71681
|
-
var
|
|
71682
|
-
var
|
|
71986
|
+
var import_promises12 = require("node:fs/promises");
|
|
71987
|
+
var import_node_path57 = require("node:path");
|
|
71683
71988
|
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}$/;
|
|
71684
71989
|
var MAX_BYTES2 = 5 * 1024 * 1024 * 1024;
|
|
71685
71990
|
async function sha256File(path2) {
|
|
71686
|
-
const hash = (0,
|
|
71991
|
+
const hash = (0, import_node_crypto24.createHash)("sha256");
|
|
71687
71992
|
for await (const chunk of (0, import_node_fs61.createReadStream)(path2)) hash.update(chunk);
|
|
71688
71993
|
return hash.digest("hex");
|
|
71689
71994
|
}
|
|
71690
71995
|
async function putTenantArtifact(repo, stage, inputPath, deps) {
|
|
71691
71996
|
if (!["dev", "rc", "main"].includes(stage)) throw new Error("tenant artifact put: <stage> must be dev, rc, or main");
|
|
71692
|
-
const path2 = (0,
|
|
71693
|
-
const info = await (0,
|
|
71997
|
+
const path2 = (0, import_node_path57.resolve)(inputPath);
|
|
71998
|
+
const info = await (0, import_promises12.stat)(path2);
|
|
71694
71999
|
if (!info.isFile()) throw new Error("tenant artifact put: input path must be a file");
|
|
71695
72000
|
if (!Number.isSafeInteger(info.size) || info.size < 1 || info.size > MAX_BYTES2) throw new Error(`tenant artifact put: file must be 1..${MAX_BYTES2} bytes`);
|
|
71696
72001
|
const sha2564 = await sha256File(path2);
|
|
@@ -72169,12 +72474,12 @@ async function resolveWhoami(deps) {
|
|
|
72169
72474
|
}
|
|
72170
72475
|
|
|
72171
72476
|
// src/command-register-developer.ts
|
|
72172
|
-
var
|
|
72477
|
+
var import_node_path64 = require("node:path");
|
|
72173
72478
|
|
|
72174
72479
|
// src/doc-refs-command-source.ts
|
|
72175
72480
|
var import_node_child_process21 = require("node:child_process");
|
|
72176
72481
|
var import_node_fs62 = require("node:fs");
|
|
72177
|
-
var
|
|
72482
|
+
var import_node_path58 = require("node:path");
|
|
72178
72483
|
var IN_PROCESS_SOURCE = "in-process";
|
|
72179
72484
|
var BUNDLE_MANIFEST_TIMEOUT_MS = 12e4;
|
|
72180
72485
|
var BUNDLE_MANIFEST_MAX_BUFFER = 64 * 1024 * 1024;
|
|
@@ -72196,7 +72501,7 @@ function inventoryFromManifest(manifest, source) {
|
|
|
72196
72501
|
function readBundleManifest(bundle, exec3 = import_node_child_process21.execFileSync) {
|
|
72197
72502
|
try {
|
|
72198
72503
|
const text = exec3(process.execPath, [bundle, "commands", "--all", "--json"], {
|
|
72199
|
-
cwd: (0,
|
|
72504
|
+
cwd: (0, import_node_path58.dirname)(bundle),
|
|
72200
72505
|
encoding: "utf8",
|
|
72201
72506
|
windowsHide: true,
|
|
72202
72507
|
timeout: BUNDLE_MANIFEST_TIMEOUT_MS,
|
|
@@ -72212,16 +72517,16 @@ function readBundleManifest(bundle, exec3 = import_node_child_process21.execFile
|
|
|
72212
72517
|
function isRunningBundle(bundle, argv1 = process.argv[1], platform2 = process.platform) {
|
|
72213
72518
|
if (!argv1) return false;
|
|
72214
72519
|
const norm3 = (path2) => {
|
|
72215
|
-
const absolute = (0,
|
|
72520
|
+
const absolute = (0, import_node_path58.resolve)(path2);
|
|
72216
72521
|
return platform2 === "win32" ? absolute.toLowerCase() : absolute;
|
|
72217
72522
|
};
|
|
72218
72523
|
const running = norm3(argv1);
|
|
72219
|
-
if (!["main.cjs", "index.cjs"].includes((0,
|
|
72220
|
-
return (0,
|
|
72524
|
+
if (!["main.cjs", "index.cjs"].includes((0, import_node_path58.basename)(running))) return false;
|
|
72525
|
+
return (0, import_node_path58.dirname)(running) === (0, import_node_path58.dirname)(norm3(bundle));
|
|
72221
72526
|
}
|
|
72222
72527
|
function nameUnknownCommandSources(findings, source, root) {
|
|
72223
|
-
const checkoutBundle = (0,
|
|
72224
|
-
const recovery = source !== IN_PROCESS_SOURCE && (0,
|
|
72528
|
+
const checkoutBundle = (0, import_node_path58.resolve)(root, "cli", "dist", "main.cjs");
|
|
72529
|
+
const recovery = source !== IN_PROCESS_SOURCE && (0, import_node_path58.resolve)(source) === checkoutBundle ? "; rebuild with `npm --prefix cli run build` and retry, or pass `--commands-from <bundle>`" : "";
|
|
72225
72530
|
for (const finding of findings) {
|
|
72226
72531
|
if (finding.kind !== "unknown-command") continue;
|
|
72227
72532
|
finding.commandSource = source;
|
|
@@ -72233,7 +72538,7 @@ function resolveCommandInventory(deps) {
|
|
|
72233
72538
|
const read = deps.read ?? ((bundle) => readBundleManifest(bundle));
|
|
72234
72539
|
const warnings = [];
|
|
72235
72540
|
if (deps.from) {
|
|
72236
|
-
const bundle = (0,
|
|
72541
|
+
const bundle = (0, import_node_path58.isAbsolute)(deps.from) ? deps.from : (0, import_node_path58.resolve)(deps.root, deps.from);
|
|
72237
72542
|
if (!exists(bundle)) {
|
|
72238
72543
|
throw new Error(`docs refs --commands-from: ${bundle} does not exist \u2014 name the CLI bundle to read commands from (usually cli/dist/main.cjs)`);
|
|
72239
72544
|
}
|
|
@@ -72243,7 +72548,7 @@ function resolveCommandInventory(deps) {
|
|
|
72243
72548
|
}
|
|
72244
72549
|
return { inventory: inventory2, warnings };
|
|
72245
72550
|
}
|
|
72246
|
-
const treeBundle = (0,
|
|
72551
|
+
const treeBundle = (0, import_node_path58.join)(deps.root, "cli", "dist", "main.cjs");
|
|
72247
72552
|
if (!exists(treeBundle)) {
|
|
72248
72553
|
return { inventory: deps.inProcess(), warnings };
|
|
72249
72554
|
}
|
|
@@ -72363,26 +72668,26 @@ async function executeWaveLand(plan, deps) {
|
|
|
72363
72668
|
|
|
72364
72669
|
// src/dist-drift.ts
|
|
72365
72670
|
var import_node_child_process22 = require("node:child_process");
|
|
72366
|
-
var
|
|
72671
|
+
var import_node_crypto26 = require("node:crypto");
|
|
72367
72672
|
var import_node_fs64 = require("node:fs");
|
|
72368
|
-
var
|
|
72369
|
-
var
|
|
72673
|
+
var import_node_os28 = require("node:os");
|
|
72674
|
+
var import_node_path60 = require("node:path");
|
|
72370
72675
|
|
|
72371
72676
|
// ../scripts/distribution-digest.mjs
|
|
72372
|
-
var
|
|
72677
|
+
var import_node_crypto25 = require("node:crypto");
|
|
72373
72678
|
var import_node_fs63 = require("node:fs");
|
|
72374
|
-
var
|
|
72679
|
+
var import_node_path59 = require("node:path");
|
|
72375
72680
|
var slash = (value) => value.replaceAll("\\", "/");
|
|
72376
72681
|
function repoPath(root, declaredPath, label) {
|
|
72377
|
-
const absoluteRoot = (0,
|
|
72378
|
-
const target = (0,
|
|
72379
|
-
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${
|
|
72682
|
+
const absoluteRoot = (0, import_node_path59.resolve)(root);
|
|
72683
|
+
const target = (0, import_node_path59.resolve)(root, declaredPath);
|
|
72684
|
+
if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${import_node_path59.sep}`)) {
|
|
72380
72685
|
throw new Error(`${label} ${declaredPath} escapes the repository root`);
|
|
72381
72686
|
}
|
|
72382
72687
|
return target;
|
|
72383
72688
|
}
|
|
72384
72689
|
function digestFiles(files) {
|
|
72385
|
-
const hash = (0,
|
|
72690
|
+
const hash = (0, import_node_crypto25.createHash)("sha256");
|
|
72386
72691
|
for (const file of [...files].sort((a, b) => a.relative.localeCompare(b.relative))) {
|
|
72387
72692
|
const content = file.stat.isSymbolicLink() ? Buffer.from((0, import_node_fs63.readlinkSync)(file.absolute), "utf8") : (0, import_node_fs63.readFileSync)(file.absolute);
|
|
72388
72693
|
hash.update(file.relative, "utf8");
|
|
@@ -72413,7 +72718,7 @@ var DIST_ARTIFACTS = [
|
|
|
72413
72718
|
];
|
|
72414
72719
|
var BOM_DIST_TREE_ID = "mmi-cli-dist";
|
|
72415
72720
|
var ABSENT = "absent";
|
|
72416
|
-
var sha2563 = (bytes) => `sha256:${(0,
|
|
72721
|
+
var sha2563 = (bytes) => `sha256:${(0, import_node_crypto26.createHash)("sha256").update(bytes).digest("hex")}`;
|
|
72417
72722
|
function artifactDrift(path2, committedBytes, rebuiltBytes) {
|
|
72418
72723
|
const committed = committedBytes ? sha2563(committedBytes) : ABSENT;
|
|
72419
72724
|
const rebuiltExpected = rebuiltBytes ? sha2563(rebuiltBytes) : ABSENT;
|
|
@@ -72491,7 +72796,7 @@ function walkFiles(root) {
|
|
|
72491
72796
|
const files = [];
|
|
72492
72797
|
const walk2 = (directory) => {
|
|
72493
72798
|
for (const entry of (0, import_node_fs64.readdirSync)(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
72494
|
-
const child2 = (0,
|
|
72799
|
+
const child2 = (0, import_node_path60.join)(directory, entry.name);
|
|
72495
72800
|
if (entry.isDirectory()) walk2(child2);
|
|
72496
72801
|
else files.push(child2);
|
|
72497
72802
|
}
|
|
@@ -72501,10 +72806,10 @@ function walkFiles(root) {
|
|
|
72501
72806
|
}
|
|
72502
72807
|
function bomPathFor(root) {
|
|
72503
72808
|
try {
|
|
72504
|
-
const registry2 = JSON.parse((0, import_node_fs64.readFileSync)((0,
|
|
72505
|
-
return (0,
|
|
72809
|
+
const registry2 = JSON.parse((0, import_node_fs64.readFileSync)((0, import_node_path60.join)(root, "surfaces.json"), "utf8"));
|
|
72810
|
+
return (0, import_node_path60.join)(root, registry2?.sharedAgentCore?.releaseMetadata?.bomPath ?? "distribution-bom.json");
|
|
72506
72811
|
} catch {
|
|
72507
|
-
return (0,
|
|
72812
|
+
return (0, import_node_path60.join)(root, "distribution-bom.json");
|
|
72508
72813
|
}
|
|
72509
72814
|
}
|
|
72510
72815
|
function rebuildTo(packageRoot, outDir) {
|
|
@@ -72517,28 +72822,28 @@ function rebuildTo(packageRoot, outDir) {
|
|
|
72517
72822
|
});
|
|
72518
72823
|
}
|
|
72519
72824
|
function runDistStatus(root) {
|
|
72520
|
-
const stage = (0, import_node_fs64.mkdtempSync)((0,
|
|
72825
|
+
const stage = (0, import_node_fs64.mkdtempSync)((0, import_node_path60.join)((0, import_node_os28.tmpdir)(), "mmi-dist-drift-"));
|
|
72521
72826
|
let overlayCount = 0;
|
|
72522
72827
|
try {
|
|
72523
|
-
const cliOut = (0,
|
|
72524
|
-
const hubOut = (0,
|
|
72525
|
-
rebuildTo((0,
|
|
72526
|
-
rebuildTo((0,
|
|
72828
|
+
const cliOut = (0, import_node_path60.join)(stage, "cli-dist");
|
|
72829
|
+
const hubOut = (0, import_node_path60.join)(stage, "hub-dist");
|
|
72830
|
+
rebuildTo((0, import_node_path60.join)(root, "cli"), cliOut);
|
|
72831
|
+
rebuildTo((0, import_node_path60.join)(root, "updater"), hubOut);
|
|
72527
72832
|
const outDirFor = (packageDir) => packageDir === "cli" ? cliOut : hubOut;
|
|
72528
72833
|
const rebuilt = (path2) => {
|
|
72529
72834
|
const spec = DIST_ARTIFACTS.find((entry) => entry.path === path2);
|
|
72530
|
-
return spec ? readOrNull((0,
|
|
72835
|
+
return spec ? readOrNull((0, import_node_path60.join)(outDirFor(spec.packageDir), spec.output)) : null;
|
|
72531
72836
|
};
|
|
72532
|
-
const committed = (path2) => readOrNull((0,
|
|
72533
|
-
const tree = (path2) => readOrNull((0,
|
|
72534
|
-
const distRoot = (0,
|
|
72535
|
-
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0,
|
|
72837
|
+
const committed = (path2) => readOrNull((0, import_node_path60.join)(root, path2));
|
|
72838
|
+
const tree = (path2) => readOrNull((0, import_node_path60.join)(root, path2));
|
|
72839
|
+
const distRoot = (0, import_node_path60.join)(root, "cli", "dist");
|
|
72840
|
+
const distTree = () => walkFiles(distRoot).map((absolute) => `cli/dist/${(0, import_node_path60.relative)(distRoot, absolute).replaceAll("\\", "/")}`);
|
|
72536
72841
|
const bom = JSON.parse((0, import_node_fs64.readFileSync)(bomPathFor(root), "utf8"));
|
|
72537
72842
|
const digest = (entries) => {
|
|
72538
|
-
const overlay = (0,
|
|
72843
|
+
const overlay = (0, import_node_path60.join)(stage, `overlay-${overlayCount++}`);
|
|
72539
72844
|
for (const entry of entries) {
|
|
72540
|
-
const target = (0,
|
|
72541
|
-
(0, import_node_fs64.mkdirSync)((0,
|
|
72845
|
+
const target = (0, import_node_path60.join)(overlay, entry.path);
|
|
72846
|
+
(0, import_node_fs64.mkdirSync)((0, import_node_path60.dirname)(target), { recursive: true });
|
|
72542
72847
|
(0, import_node_fs64.writeFileSync)(target, entry.bytes);
|
|
72543
72848
|
}
|
|
72544
72849
|
return digestPackedFiles(overlay, entries.map((entry) => entry.path));
|
|
@@ -72550,7 +72855,7 @@ function runDistStatus(root) {
|
|
|
72550
72855
|
}
|
|
72551
72856
|
|
|
72552
72857
|
// src/doc-refs-live.ts
|
|
72553
|
-
var
|
|
72858
|
+
var import_node_path61 = require("node:path");
|
|
72554
72859
|
var concrete = (value) => !!value && !/[<>{}$]/.test(value);
|
|
72555
72860
|
var liveOption = (tokens2, flag) => {
|
|
72556
72861
|
const index = tokens2.indexOf(flag);
|
|
@@ -72623,7 +72928,7 @@ async function runLiveDocRefs(root, deps, live) {
|
|
|
72623
72928
|
const offline = runDocRefs(root, { ...deps, runbooksOnly: true });
|
|
72624
72929
|
const read = deps.readFile ?? readFileOrNull;
|
|
72625
72930
|
const docs = Object.fromEntries((deps.listDocs ?? defaultListDocs)(root).flatMap((doc) => {
|
|
72626
|
-
const body = read((0,
|
|
72931
|
+
const body = read((0, import_node_path61.join)(root, doc));
|
|
72627
72932
|
return body !== null && isRunbook(doc, body) && !deps.isIgnored?.([doc]).has(doc) ? [[doc, body]] : [];
|
|
72628
72933
|
}));
|
|
72629
72934
|
const remote = await checkRunbookLive(docs, live);
|
|
@@ -72672,13 +72977,13 @@ init_cli_shared();
|
|
|
72672
72977
|
// src/edge-tunnel.ts
|
|
72673
72978
|
var HOSTNAME_RE = /^(?=.{1,253}$)([a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)(\.[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)+$/;
|
|
72674
72979
|
var UPSTREAM_RE = /^https?:\/\/[^/\s]+(?::\d+)?(?:\/.*)?$/;
|
|
72675
|
-
function tunnelNameFromHostname(
|
|
72676
|
-
return
|
|
72980
|
+
function tunnelNameFromHostname(hostname5) {
|
|
72981
|
+
return hostname5.replace(/\./g, "-").slice(0, 63);
|
|
72677
72982
|
}
|
|
72678
|
-
function planInfraTunnel(
|
|
72679
|
-
const host =
|
|
72983
|
+
function planInfraTunnel(hostname5, upstream) {
|
|
72984
|
+
const host = hostname5.trim().toLowerCase();
|
|
72680
72985
|
const origin = upstream.trim();
|
|
72681
|
-
if (!HOSTNAME_RE.test(host)) throw new Error(`invalid hostname ${JSON.stringify(
|
|
72986
|
+
if (!HOSTNAME_RE.test(host)) throw new Error(`invalid hostname ${JSON.stringify(hostname5)}`);
|
|
72682
72987
|
if (!UPSTREAM_RE.test(origin)) throw new Error(`invalid upstream ${JSON.stringify(upstream)} \u2014 expected http(s)://host:port`);
|
|
72683
72988
|
const tunnelName = tunnelNameFromHostname(host);
|
|
72684
72989
|
const configYaml = [
|
|
@@ -72833,8 +73138,8 @@ async function diagnoseHub(deps) {
|
|
|
72833
73138
|
}
|
|
72834
73139
|
|
|
72835
73140
|
// src/schedules-lift-command.ts
|
|
72836
|
-
var
|
|
72837
|
-
var
|
|
73141
|
+
var import_promises13 = require("node:fs/promises");
|
|
73142
|
+
var import_node_path62 = require("node:path");
|
|
72838
73143
|
init_clean_exit();
|
|
72839
73144
|
init_cli_shared();
|
|
72840
73145
|
var DEFAULT_WORKFLOWS_DIR = ".github/workflows";
|
|
@@ -72856,14 +73161,14 @@ var RegistryUnreachableError = class extends Error {
|
|
|
72856
73161
|
async function readWorkflowFiles(dir) {
|
|
72857
73162
|
let names;
|
|
72858
73163
|
try {
|
|
72859
|
-
names = await (0,
|
|
73164
|
+
names = await (0, import_promises13.readdir)(dir);
|
|
72860
73165
|
} catch {
|
|
72861
73166
|
return [];
|
|
72862
73167
|
}
|
|
72863
73168
|
const files = [];
|
|
72864
73169
|
for (const name of names.sort()) {
|
|
72865
73170
|
if (!/\.ya?ml$/.test(name)) continue;
|
|
72866
|
-
files.push({ path: `.github/workflows/${name}`, text: await (0,
|
|
73171
|
+
files.push({ path: `.github/workflows/${name}`, text: await (0, import_promises13.readFile)((0, import_node_path62.join)(dir, name), "utf8") });
|
|
72867
73172
|
}
|
|
72868
73173
|
return files;
|
|
72869
73174
|
}
|
|
@@ -72947,7 +73252,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
72947
73252
|
// src/spawn-policy-core.ts
|
|
72948
73253
|
var import_node_child_process24 = require("node:child_process");
|
|
72949
73254
|
var import_node_fs65 = require("node:fs");
|
|
72950
|
-
var
|
|
73255
|
+
var import_node_path63 = require("node:path");
|
|
72951
73256
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
72952
73257
|
var CALL_SOURCE = String.raw`(^|[^.\w$])(${SPAWNERS.join("|")})\s*\(`;
|
|
72953
73258
|
var SOURCE_EXT = /\.(ts|mts|cts|js|mjs|cjs)$/;
|
|
@@ -73033,7 +73338,7 @@ function runSpawnPolicy(root) {
|
|
|
73033
73338
|
for (const file of files) {
|
|
73034
73339
|
let raw;
|
|
73035
73340
|
try {
|
|
73036
|
-
raw = (0, import_node_fs65.readFileSync)((0,
|
|
73341
|
+
raw = (0, import_node_fs65.readFileSync)((0, import_node_path63.join)(root, file), "utf8");
|
|
73037
73342
|
} catch {
|
|
73038
73343
|
continue;
|
|
73039
73344
|
}
|
|
@@ -73053,7 +73358,7 @@ function runSpawnPolicy(root) {
|
|
|
73053
73358
|
function registerDeveloperCommands(program3) {
|
|
73054
73359
|
const rules = program3.command("rules").description("org-managed .gitignore delivery");
|
|
73055
73360
|
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) => {
|
|
73056
|
-
const path2 = (0,
|
|
73361
|
+
const path2 = (0, import_node_path64.join)(process.cwd(), ".gitignore");
|
|
73057
73362
|
const current = (0, import_node_fs66.existsSync)(path2) ? (0, import_node_fs66.readFileSync)(path2, "utf8") : null;
|
|
73058
73363
|
const plan = planManagedGitignore(current);
|
|
73059
73364
|
const drift = [...plan.added.map((l) => `+${l}`), ...plan.removed.map((l) => `-${l}`)].join(", ") || "block normalize";
|
|
@@ -73383,12 +73688,12 @@ ${r.stderr ?? ""}`).catch(() => "");
|
|
|
73383
73688
|
var ENV_HEAL_LOCK_STALE_MS = 10 * 6e4;
|
|
73384
73689
|
var ENV_HEAL_LOCK_MAX_WAIT_MS = 2 * 6e4;
|
|
73385
73690
|
function envHealLockPath(home) {
|
|
73386
|
-
return (0,
|
|
73691
|
+
return (0, import_node_path65.join)(home, ".claude", "plugins", ".mmi-env-heal.lock");
|
|
73387
73692
|
}
|
|
73388
73693
|
async function withEnvHealLock(what, run) {
|
|
73389
73694
|
try {
|
|
73390
73695
|
return await withFileLock(
|
|
73391
|
-
envHealLockPath((0,
|
|
73696
|
+
envHealLockPath((0, import_node_os29.homedir)()),
|
|
73392
73697
|
{ staleMs: ENV_HEAL_LOCK_STALE_MS, maxWaitMs: ENV_HEAL_LOCK_MAX_WAIT_MS, label: "mmi env-heal lock" },
|
|
73393
73698
|
run
|
|
73394
73699
|
);
|
|
@@ -73486,7 +73791,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
73486
73791
|
const configRoot = surfaceConfigRoot(surface);
|
|
73487
73792
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
73488
73793
|
const plan = buildPluginCachePlan(
|
|
73489
|
-
(0,
|
|
73794
|
+
(0, import_node_os29.homedir)(),
|
|
73490
73795
|
running,
|
|
73491
73796
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
73492
73797
|
{ configRoot, includeStaging: surface !== "codex" }
|
|
@@ -73514,7 +73819,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
73514
73819
|
const running = surface === "codex" ? installedActivePluginVersion(surface) : runningPluginVersion(process.env, resolveClientVersion());
|
|
73515
73820
|
const installed = installedActivePluginVersion(surface);
|
|
73516
73821
|
const plan = buildPluginCachePlan(
|
|
73517
|
-
(0,
|
|
73822
|
+
(0, import_node_os29.homedir)(),
|
|
73518
73823
|
running,
|
|
73519
73824
|
pluginCacheFsDeps(configRoot, () => 0),
|
|
73520
73825
|
{ configRoot, includeStaging: surface !== "codex", installedVersion: installed }
|
|
@@ -73556,7 +73861,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
73556
73861
|
// has no generated routing index would
|
|
73557
73862
|
// get a permanent — demanding an artifact it never asked for.
|
|
73558
73863
|
docsIndexState: (root) => {
|
|
73559
|
-
if (!(0, import_node_fs67.existsSync)((0,
|
|
73864
|
+
if (!(0, import_node_fs67.existsSync)((0, import_node_path65.join)(root, DOCS_INDEX_PATH))) return void 0;
|
|
73560
73865
|
const real = createDocsIndexDeps(root);
|
|
73561
73866
|
let docs;
|
|
73562
73867
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -73565,7 +73870,7 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
73565
73870
|
},
|
|
73566
73871
|
// #4168: working-tree heal — write if drifted, then re-check. Commit remains the operator's step.
|
|
73567
73872
|
healDocsIndex: (root) => {
|
|
73568
|
-
if (!(0, import_node_fs67.existsSync)((0,
|
|
73873
|
+
if (!(0, import_node_fs67.existsSync)((0, import_node_path65.join)(root, DOCS_INDEX_PATH))) return { drift: false, docCount: 0 };
|
|
73569
73874
|
const real = createDocsIndexDeps(root);
|
|
73570
73875
|
let docs;
|
|
73571
73876
|
const listDocs = () => docs ??= real.listDocs();
|
|
@@ -73948,7 +74253,16 @@ setGhWriteTokenProvider(() => {
|
|
|
73948
74253
|
throw e;
|
|
73949
74254
|
});
|
|
73950
74255
|
});
|
|
73951
|
-
|
|
74256
|
+
var claimWriteToken;
|
|
74257
|
+
setClaimWriteTokenProvider(() => {
|
|
74258
|
+
if (process.env.MMI_ACTOR?.trim() === "app") {
|
|
74259
|
+
return mintFilingWriteToken(appActorDeps()).then((t) => t.token);
|
|
74260
|
+
}
|
|
74261
|
+
return claimWriteToken ??= mintFilingWriteToken(appActorDeps()).then((t) => t.token, (e) => {
|
|
74262
|
+
if (e instanceof AppActorError && e.code === "vault-denied") return void 0;
|
|
74263
|
+
throw e;
|
|
74264
|
+
});
|
|
74265
|
+
});
|
|
73952
74266
|
setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
|
|
73953
74267
|
var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
|
|
73954
74268
|
registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -74787,16 +75101,16 @@ function ciAuditDeps2() {
|
|
|
74787
75101
|
// gate re-seed step is skipped gracefully rather than failing mid-run.
|
|
74788
75102
|
readSeedFile: (path2) => {
|
|
74789
75103
|
if (!root) return null;
|
|
74790
|
-
const fullPath = (0,
|
|
75104
|
+
const fullPath = (0, import_node_path65.join)(root, path2);
|
|
74791
75105
|
return (0, import_node_fs67.existsSync)(fullPath) ? (0, import_node_fs67.readFileSync)(fullPath, "utf8") : null;
|
|
74792
75106
|
}
|
|
74793
75107
|
};
|
|
74794
75108
|
}
|
|
74795
75109
|
function hubRoot2() {
|
|
74796
|
-
const fromPkg = (0,
|
|
75110
|
+
const fromPkg = (0, import_node_path65.join)(__dirname, "..", "..");
|
|
74797
75111
|
const marker = "skills/bootstrap/seeds/manifest.json";
|
|
74798
|
-
if ((0, import_node_fs67.existsSync)((0,
|
|
74799
|
-
if ((0, import_node_fs67.existsSync)((0,
|
|
75112
|
+
if ((0, import_node_fs67.existsSync)((0, import_node_path65.join)(fromPkg, marker))) return fromPkg;
|
|
75113
|
+
if ((0, import_node_fs67.existsSync)((0, import_node_path65.join)(process.cwd(), marker))) return process.cwd();
|
|
74800
75114
|
return null;
|
|
74801
75115
|
}
|
|
74802
75116
|
registerQueryCommands(program2);
|
|
@@ -75010,7 +75324,7 @@ function directoryBytes(path2) {
|
|
|
75010
75324
|
return 0;
|
|
75011
75325
|
}
|
|
75012
75326
|
for (const entry of entries) {
|
|
75013
|
-
const child2 = (0,
|
|
75327
|
+
const child2 = (0, import_node_path65.join)(path2, entry.name);
|
|
75014
75328
|
if (entry.isDirectory()) total += directoryBytes(child2);
|
|
75015
75329
|
else {
|
|
75016
75330
|
try {
|
|
@@ -75040,7 +75354,7 @@ function pluginCacheFsDeps(configRoot, dirBytes) {
|
|
|
75040
75354
|
dirBytes,
|
|
75041
75355
|
listStagingDirs: (root) => (0, import_node_fs67.readdirSync)(root, { withFileTypes: true }).filter((d) => d.isDirectory()).map((d) => {
|
|
75042
75356
|
try {
|
|
75043
|
-
return { name: d.name, mtimeMs: newestMtimeMs((0,
|
|
75357
|
+
return { name: d.name, mtimeMs: newestMtimeMs((0, import_node_path65.join)(root, d.name), listDirEntries, (p) => (0, import_node_fs67.statSync)(p).mtimeMs) };
|
|
75044
75358
|
} catch {
|
|
75045
75359
|
return { name: d.name, mtimeMs: Date.now() };
|
|
75046
75360
|
}
|
|
@@ -75054,7 +75368,7 @@ function stagingApplyFsGuard(configRoot) {
|
|
|
75054
75368
|
return {
|
|
75055
75369
|
referencedPaths: () => readInstalledPluginRefs(configRoot),
|
|
75056
75370
|
mtimeMs: (name) => {
|
|
75057
|
-
const p = (0,
|
|
75371
|
+
const p = (0, import_node_path65.join)(stagingRoot, name);
|
|
75058
75372
|
if (!(0, import_node_fs67.existsSync)(p)) return null;
|
|
75059
75373
|
try {
|
|
75060
75374
|
return newestMtimeMs(p, listDirEntries, (q) => (0, import_node_fs67.statSync)(q).mtimeMs);
|
|
@@ -75077,7 +75391,7 @@ program2.command("plugin-prune").description(`prune stale cached MMI plugin vers
|
|
|
75077
75391
|
return;
|
|
75078
75392
|
}
|
|
75079
75393
|
const plan = buildPluginCachePlan(
|
|
75080
|
-
(0,
|
|
75394
|
+
(0, import_node_os29.homedir)(),
|
|
75081
75395
|
running,
|
|
75082
75396
|
pluginCacheFsDeps(configRoot, directoryBytes),
|
|
75083
75397
|
{ withBytes: true, configRoot, includeStaging: surface !== "codex" }
|
|
@@ -75093,7 +75407,7 @@ program2.command("archive-prune").description("inventory worktree evidence archi
|
|
|
75093
75407
|
let primary = o.repoRoot;
|
|
75094
75408
|
if (!primary) {
|
|
75095
75409
|
const common = await gitOut(["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
75096
|
-
primary = common ? (0,
|
|
75410
|
+
primary = common ? (0, import_node_path65.dirname)(common) : "";
|
|
75097
75411
|
}
|
|
75098
75412
|
if (!primary) {
|
|
75099
75413
|
const detail = "archive-prune: not inside a git checkout (pass --repo-root <primary checkout>)";
|