@mutmutco/claude-plugin 4.5.161 → 4.5.162
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/.claude-plugin/plugin.json +1 -1
- package/cli/dist/main.cjs +198 -89
- package/cli/package.json +1 -1
- package/package.json +1 -1
- package/skills/board/SKILL.md +3 -20
- package/skills/board/examples.md +12 -0
- package/skills/board/reference.md +11 -0
- package/skills/bootstrap/SKILL.md +5 -418
- package/skills/bootstrap/reference.md +421 -0
- package/skills/hotfix/SKILL.md +2 -4
- package/skills/hotfix/recovery.md +4 -0
- package/skills/hotfix/suite.md +2 -0
- package/skills/org-guide/SKILL.md +1 -1
- package/skills/org-guide/references/work-and-releases.md +19 -1
- package/skills/rcand/SKILL.md +2 -2
- package/skills/rcand/recovery.md +2 -0
- package/skills/rcand/suite.md +2 -0
- package/skills/release/SKILL.md +6 -10
- package/skills/release/suite.md +5 -0
- package/skills/release/vercel.md +2 -0
- package/skills/release/verification.md +7 -0
- package/skills/secrets/SKILL.md +3 -64
- package/skills/secrets/reference.md +67 -0
- package/skills/stage/SKILL.md +4 -96
- package/skills/stage/live.md +34 -0
- package/skills/stage/reference.md +49 -0
- package/skills/stage/smoke.md +17 -0
package/cli/dist/main.cjs
CHANGED
|
@@ -76,19 +76,19 @@ function hardExit(code) {
|
|
|
76
76
|
process.exit(code);
|
|
77
77
|
}
|
|
78
78
|
function flushStream(stream) {
|
|
79
|
-
return new Promise((
|
|
79
|
+
return new Promise((resolve7) => {
|
|
80
80
|
try {
|
|
81
|
-
stream.write("", () =>
|
|
81
|
+
stream.write("", () => resolve7());
|
|
82
82
|
} catch {
|
|
83
|
-
|
|
83
|
+
resolve7();
|
|
84
84
|
}
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
87
|
async function flushStdio(timeoutMs = STDIO_FLUSH_TIMEOUT_MS) {
|
|
88
88
|
await Promise.race([
|
|
89
89
|
Promise.all([flushStream(process.stdout), flushStream(process.stderr)]),
|
|
90
|
-
new Promise((
|
|
91
|
-
setTimeout(
|
|
90
|
+
new Promise((resolve7) => {
|
|
91
|
+
setTimeout(resolve7, timeoutMs).unref?.();
|
|
92
92
|
})
|
|
93
93
|
]);
|
|
94
94
|
}
|
|
@@ -96,7 +96,7 @@ async function cleanExit(code) {
|
|
|
96
96
|
process.exitCode = code;
|
|
97
97
|
await closeHttpPool();
|
|
98
98
|
await flushStdio();
|
|
99
|
-
await new Promise((
|
|
99
|
+
await new Promise((resolve7) => setImmediate(resolve7));
|
|
100
100
|
return void 0;
|
|
101
101
|
}
|
|
102
102
|
async function finishCliRun(watchdogMs = CLI_EXIT_WATCHDOG_MS) {
|
|
@@ -590,6 +590,11 @@ var init_github_client = __esm({
|
|
|
590
590
|
});
|
|
591
591
|
|
|
592
592
|
// src/gh-read-route.ts
|
|
593
|
+
function isAppFilingWrite(args) {
|
|
594
|
+
if (args.some((a) => VIEWER.test(a))) return false;
|
|
595
|
+
const [group, verb] = args;
|
|
596
|
+
return (group === "issue" || group === "label") && verb === "create";
|
|
597
|
+
}
|
|
593
598
|
function isViewerFreeGhRead(args) {
|
|
594
599
|
if (args.some((a) => VIEWER.test(a))) return false;
|
|
595
600
|
const [group, verb] = args;
|
|
@@ -692,7 +697,7 @@ function rateLimitedReceipt(opts) {
|
|
|
692
697
|
};
|
|
693
698
|
}
|
|
694
699
|
async function runWithRateLimitBackoff(operation, opts) {
|
|
695
|
-
const sleep2 = opts.sleep ?? ((ms) => new Promise((
|
|
700
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
696
701
|
const now = opts.now ?? Date.now;
|
|
697
702
|
const log = opts.log ?? ((message2) => console.warn(message2));
|
|
698
703
|
const capMs = opts.capMs ?? RATE_LIMIT_WAIT_CAP_MS;
|
|
@@ -782,7 +787,7 @@ async function fetchWithRetry(fetchImpl, url, init, opts = {}) {
|
|
|
782
787
|
const attempts = opts.attempts ?? 3;
|
|
783
788
|
const baseDelayMs = opts.baseDelayMs ?? 250;
|
|
784
789
|
const retryOn = opts.retryOn ?? ((res) => res.status >= 500);
|
|
785
|
-
const sleep2 = opts.sleep ?? ((ms) => new Promise((
|
|
790
|
+
const sleep2 = opts.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
786
791
|
let lastErr;
|
|
787
792
|
for (let i = 0; i < attempts; i++) {
|
|
788
793
|
const isLast = i === attempts - 1;
|
|
@@ -1109,8 +1114,8 @@ async function readStdin(opts = {}) {
|
|
|
1109
1114
|
})().catch(() => {
|
|
1110
1115
|
});
|
|
1111
1116
|
let timer;
|
|
1112
|
-
const timeout = new Promise((
|
|
1113
|
-
timer = setTimeout(
|
|
1117
|
+
const timeout = new Promise((resolve7) => {
|
|
1118
|
+
timer = setTimeout(resolve7, timeoutMs);
|
|
1114
1119
|
});
|
|
1115
1120
|
try {
|
|
1116
1121
|
await Promise.race([drain, timeout]);
|
|
@@ -1161,11 +1166,21 @@ __export(cli_shared_exports, {
|
|
|
1161
1166
|
readStdin: () => readStdin,
|
|
1162
1167
|
repoProject: () => repoProject,
|
|
1163
1168
|
setGhReadTokenProvider: () => setGhReadTokenProvider,
|
|
1169
|
+
setGhWriteTokenProvider: () => setGhWriteTokenProvider,
|
|
1164
1170
|
setInjectedStdin: () => setInjectedStdin
|
|
1165
1171
|
});
|
|
1166
1172
|
function setGhReadTokenProvider(provider) {
|
|
1167
1173
|
ghReadTokenProvider = provider;
|
|
1168
1174
|
}
|
|
1175
|
+
function setGhWriteTokenProvider(provider) {
|
|
1176
|
+
ghWriteTokenProvider = provider;
|
|
1177
|
+
}
|
|
1178
|
+
async function ghFilingAppEnv(file, args) {
|
|
1179
|
+
if (!ghWriteTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1180
|
+
if (!isAppFilingWrite(args)) return void 0;
|
|
1181
|
+
const token = await ghWriteTokenProvider().catch(() => void 0);
|
|
1182
|
+
return token ? { ...process.env, GH_TOKEN: token } : void 0;
|
|
1183
|
+
}
|
|
1169
1184
|
async function ghReadAppEnv(file, args) {
|
|
1170
1185
|
if (!ghReadTokenProvider || !/(^|[\\/])gh(\.exe)?$/i.test(file) || process.env.MMI_ACTOR?.trim() === "personal") return void 0;
|
|
1171
1186
|
if (!isViewerFreeGhRead(args)) return void 0;
|
|
@@ -1187,12 +1202,12 @@ function killProcessTree(pid) {
|
|
|
1187
1202
|
function execFileHard(file, args, options) {
|
|
1188
1203
|
const { timeout, step, ...rest } = options;
|
|
1189
1204
|
const started = Date.now();
|
|
1190
|
-
return new Promise((
|
|
1205
|
+
return new Promise((resolve7, reject) => {
|
|
1191
1206
|
const child2 = (0, import_node_child_process2.execFile)(file, args, { encoding: "utf8", windowsHide: true, ...rest, timeout: 0 }, (error, stdout, stderr) => {
|
|
1192
1207
|
clearTimeout(timer);
|
|
1193
1208
|
if (expired) return;
|
|
1194
1209
|
if (error) reject(error);
|
|
1195
|
-
else
|
|
1210
|
+
else resolve7({ stdout: String(stdout), stderr: String(stderr) });
|
|
1196
1211
|
});
|
|
1197
1212
|
let expired = false;
|
|
1198
1213
|
const timer = setTimeout(() => {
|
|
@@ -1340,7 +1355,7 @@ function printLine(value) {
|
|
|
1340
1355
|
(0, import_node_fs5.writeSync)(1, `${value}
|
|
1341
1356
|
`);
|
|
1342
1357
|
}
|
|
1343
|
-
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, ghReadTokenProvider, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1358
|
+
var import_node_child_process2, import_node_fs5, import_node_util3, rawExecFileP, DEFAULT_EXEC_TIMEOUT_MS, execFileP, ghReadTokenProvider, ghWriteTokenProvider, GIT_TIMEOUT_MS, ExecDeadlineError, cachedGithubLogin, gitOut, consoleIo;
|
|
1344
1359
|
var init_cli_shared = __esm({
|
|
1345
1360
|
"src/cli-shared.ts"() {
|
|
1346
1361
|
"use strict";
|
|
@@ -1364,7 +1379,7 @@ var init_cli_shared = __esm({
|
|
|
1364
1379
|
// promisify(execFile)'s overloads widen to string|Buffer when options is spread in.
|
|
1365
1380
|
rawExecFileP(file, args, { encoding: "utf8", windowsHide: true, timeout: DEFAULT_EXEC_TIMEOUT_MS, killSignal: "SIGTERM", ...options, ...env ? { env } : {} })
|
|
1366
1381
|
);
|
|
1367
|
-
const appEnv = options.env ? void 0 : await ghReadAppEnv(file, args);
|
|
1382
|
+
const appEnv = options.env ? void 0 : await ghReadAppEnv(file, args) ?? await ghFilingAppEnv(file, args);
|
|
1368
1383
|
if (!appEnv) return run();
|
|
1369
1384
|
try {
|
|
1370
1385
|
return await run(appEnv);
|
|
@@ -6664,7 +6679,6 @@ var import_node_fs14 = require("node:fs");
|
|
|
6664
6679
|
var import_node_path11 = require("node:path");
|
|
6665
6680
|
var PLAN_ADVISORY_AGE_MS = 30 * 24 * 36e5;
|
|
6666
6681
|
var ROOT_SCRATCH_STALE_MS = 24 * 36e5;
|
|
6667
|
-
var SCRATCH_GC_THROTTLE_MS = 24 * 36e5;
|
|
6668
6682
|
function executeScratchGc(repoRoot2, opts, now = Date.now()) {
|
|
6669
6683
|
const snap = collectScratchSnapshot(repoRoot2);
|
|
6670
6684
|
const plan = planScratchGc(snap, now);
|
|
@@ -7239,7 +7253,9 @@ async function mintInstallationToken(deps) {
|
|
|
7239
7253
|
return mintScopedInstallationToken(deps, APP_POLL_PERMISSIONS);
|
|
7240
7254
|
}
|
|
7241
7255
|
var APP_WRITE_COMMANDS = /* @__PURE__ */ new Map([
|
|
7242
|
-
["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }]
|
|
7256
|
+
["issue comment", { metadata: "read", issues: "write", pull_requests: "write" }],
|
|
7257
|
+
// #8401: the detached related-issue lookup (issue list/view reads + one marker comment) — no identity contract.
|
|
7258
|
+
["issue discover-related", { metadata: "read", issues: "write" }]
|
|
7243
7259
|
]);
|
|
7244
7260
|
async function mintCommandWriteToken(deps, commandPath3) {
|
|
7245
7261
|
const permissions = APP_WRITE_COMMANDS.get(commandPath3);
|
|
@@ -7251,6 +7267,14 @@ async function mintCommandWriteToken(deps, commandPath3) {
|
|
|
7251
7267
|
throw new AppActorError(`app actor: write token mint failed (${e?.constructor?.name ?? "Error"})`);
|
|
7252
7268
|
}
|
|
7253
7269
|
}
|
|
7270
|
+
async function mintFilingWriteToken(deps) {
|
|
7271
|
+
try {
|
|
7272
|
+
return await mintFromMember(deps, { metadata: "read", issues: "write" }, APP_VAULT_KEYS);
|
|
7273
|
+
} catch (e) {
|
|
7274
|
+
if (e instanceof AppActorError) throw e;
|
|
7275
|
+
throw new AppActorError(`app actor: filing token mint failed (${e?.constructor?.name ?? "Error"})`);
|
|
7276
|
+
}
|
|
7277
|
+
}
|
|
7254
7278
|
async function mintStatusWriteToken(deps) {
|
|
7255
7279
|
return mintScopedInstallationToken(deps, { metadata: "read", statuses: "write" });
|
|
7256
7280
|
}
|
|
@@ -8201,7 +8225,7 @@ async function readRestPrSnapshotWithRetry(prNumber, repo, gh2 = defaultGhApi, o
|
|
|
8201
8225
|
const retries = options?.retries ?? PR_SNAPSHOT_READ_RETRIES;
|
|
8202
8226
|
const untilMs = options?.retryTransientUntilMs;
|
|
8203
8227
|
const delayMs = options?.delayMs ?? (untilMs !== void 0 ? PR_CHECKS_POLL_MS : PR_SNAPSHOT_READ_DELAY_MS);
|
|
8204
|
-
const sleep2 = options?.sleep ?? ((ms) => new Promise((
|
|
8228
|
+
const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
8205
8229
|
const now = options?.now ?? (() => Date.now());
|
|
8206
8230
|
let lastError = "no attempt completed";
|
|
8207
8231
|
let attempt = 0;
|
|
@@ -10181,15 +10205,15 @@ async function postJson(pathSuffix, payload, deps, method = "POST", opts = {}) {
|
|
|
10181
10205
|
return { ok: false, status: 0, body: null, error: e.message, unreachable: "transport" };
|
|
10182
10206
|
}
|
|
10183
10207
|
}
|
|
10184
|
-
async function edgeDnsForStage(slug, stage, deps, ensure = false) {
|
|
10208
|
+
async function edgeDnsForStage(slug, stage, deps, ensure = false, deletion) {
|
|
10185
10209
|
if (!deps.baseUrl) throw new Error("Hub API URL unavailable");
|
|
10186
10210
|
const token = await deps.token();
|
|
10187
10211
|
if (!token) throw new Error("Hub session token unavailable");
|
|
10188
10212
|
const path2 = `/projects/${encodeURIComponent(slug)}/edge-dns/${stage}`;
|
|
10189
10213
|
let body;
|
|
10190
|
-
if (ensure) {
|
|
10191
|
-
const write = await postJson(path2, {}, deps, "POST", { noRetry: true });
|
|
10192
|
-
if (!write.ok) throw new Error(`Hub edge dns ensure failed: ${write.error ?? `HTTP ${write.status}`}`);
|
|
10214
|
+
if (ensure || deletion) {
|
|
10215
|
+
const write = await postJson(path2, deletion ?? {}, deps, deletion ? "DELETE" : "POST", { noRetry: true });
|
|
10216
|
+
if (!write.ok) throw new Error(`Hub edge dns ${deletion ? "delete" : "ensure"} failed: ${write.error ?? `HTTP ${write.status}`}`);
|
|
10193
10217
|
body = write.body;
|
|
10194
10218
|
} else {
|
|
10195
10219
|
const res = await retriedFetch(
|
|
@@ -10203,6 +10227,20 @@ async function edgeDnsForStage(slug, stage, deps, ensure = false) {
|
|
|
10203
10227
|
if (typeof body?.required !== "boolean") throw new Error("Hub edge dns response invalid");
|
|
10204
10228
|
return body;
|
|
10205
10229
|
}
|
|
10230
|
+
async function boxPreviewsForHost(box, opts, deps) {
|
|
10231
|
+
const payload = {
|
|
10232
|
+
box,
|
|
10233
|
+
...opts.portStart !== void 0 ? { portStart: opts.portStart } : {},
|
|
10234
|
+
...opts.cap !== void 0 ? { cap: opts.cap } : {},
|
|
10235
|
+
apply: opts.apply === true
|
|
10236
|
+
};
|
|
10237
|
+
const write = await postJson("/projects/box-previews", payload, deps, "POST", { noRetry: opts.apply === true });
|
|
10238
|
+
if (!write.ok) {
|
|
10239
|
+
const detail = write.body?.error;
|
|
10240
|
+
throw new Error(`Hub box previews failed: ${detail ?? write.error ?? `HTTP ${write.status}`}`);
|
|
10241
|
+
}
|
|
10242
|
+
return write.body;
|
|
10243
|
+
}
|
|
10206
10244
|
async function edgeCertificateForStage(slug, stage, deps, ensure = false) {
|
|
10207
10245
|
if (!deps.baseUrl) throw new Error("Hub API URL unavailable");
|
|
10208
10246
|
const token = await deps.token();
|
|
@@ -12063,7 +12101,7 @@ async function createPrViaRestFallback(args, swappedArgs, deps, knownPools) {
|
|
|
12063
12101
|
}
|
|
12064
12102
|
async function ghCreate(args, deps = {}) {
|
|
12065
12103
|
const exec3 = deps.exec ?? execFileP;
|
|
12066
|
-
const sleep2 = deps.sleep ?? ((ms) => new Promise((
|
|
12104
|
+
const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
12067
12105
|
const now = deps.now ?? Date.now;
|
|
12068
12106
|
const read = deps.readFile ?? import_promises.readFile;
|
|
12069
12107
|
const restCreatePr = deps.restCreatePr ?? ((input) => defaultRestCreatePr(exec3, input));
|
|
@@ -12891,8 +12929,8 @@ var PRE_SPAWN_DRAIN_TIMEOUT_MS = 2e3;
|
|
|
12891
12929
|
async function drainHttpPoolBeforeSpawn() {
|
|
12892
12930
|
const drained = await Promise.race([
|
|
12893
12931
|
closeHttpPool().then(() => true),
|
|
12894
|
-
new Promise((
|
|
12895
|
-
setTimeout(() =>
|
|
12932
|
+
new Promise((resolve7) => {
|
|
12933
|
+
setTimeout(() => resolve7(false), PRE_SPAWN_DRAIN_TIMEOUT_MS).unref?.();
|
|
12896
12934
|
})
|
|
12897
12935
|
]);
|
|
12898
12936
|
if (!drained) destroyHttpPool();
|
|
@@ -15580,7 +15618,7 @@ async function setBoardItemPriority(client, cfg, itemId, priority) {
|
|
|
15580
15618
|
await updateItemSingleSelect(client, cfg.projectId, itemId, cfg.priorityFieldId, optionId);
|
|
15581
15619
|
return cliPriorityToFieldName(priority);
|
|
15582
15620
|
}
|
|
15583
|
-
var defaultRetrySleep = (ms) => new Promise((
|
|
15621
|
+
var defaultRetrySleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
15584
15622
|
async function resolveProjectItemIdWithRetry(client, cfg, selector, opts = {}) {
|
|
15585
15623
|
const attempts = Math.max(1, opts.attempts ?? 5);
|
|
15586
15624
|
const delayMs = opts.delayMs ?? 300;
|
|
@@ -16500,7 +16538,7 @@ function checkRunbookCoverage(docs, base, git3) {
|
|
|
16500
16538
|
const globs = lines2.slice(heading.start, markerEnd - 1).flatMap((text) => /<!--\s*runbook-covers:\s*(.*?)\s*-->/.exec(text)?.[1].split(",").map((s) => s.trim()) ?? []);
|
|
16501
16539
|
const affected = changed.filter((path2) => globs.some((glob) => matches(glob, path2)));
|
|
16502
16540
|
if (affected.length && !ranges.some((r) => r.count > 0 && r.start < end && r.start + r.count > heading.start)) {
|
|
16503
|
-
findings.push({ kind: "runbook-section-stale", doc, line: heading.start, detail: `${heading.title}: changed ${affected.join(", ")}; update this section or declare Runbook-Unaffected: <reason
|
|
16541
|
+
findings.push({ kind: "runbook-section-stale", doc, line: heading.start, detail: `${heading.title}: changed ${affected.join(", ")}; update this section or declare Runbook-Unaffected: <reason>`, section: { heading: heading.title, level: heading.level, startLine: heading.start, endLine: end - 1 }, sources: affected });
|
|
16504
16542
|
}
|
|
16505
16543
|
}
|
|
16506
16544
|
}
|
|
@@ -18919,10 +18957,10 @@ var rollout_plan_default = {
|
|
|
18919
18957
|
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)."
|
|
18920
18958
|
},
|
|
18921
18959
|
baseline: {
|
|
18922
|
-
version: "4.5.
|
|
18923
|
-
tag: "v4.5.
|
|
18924
|
-
commit: "
|
|
18925
|
-
npm: "@mutmutco/cli@4.5.
|
|
18960
|
+
version: "4.5.162",
|
|
18961
|
+
tag: "v4.5.162",
|
|
18962
|
+
commit: "5d12949c1714",
|
|
18963
|
+
npm: "@mutmutco/cli@4.5.162"
|
|
18926
18964
|
},
|
|
18927
18965
|
exitCriterion: "fleet-n-of-n",
|
|
18928
18966
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18939,14 +18977,14 @@ var rollout_plan_default = {
|
|
|
18939
18977
|
repo: "mutmutco/mmi-hub",
|
|
18940
18978
|
role: "canary",
|
|
18941
18979
|
schedule: "train",
|
|
18942
|
-
v3Target: "v4.5.
|
|
18980
|
+
v3Target: "v4.5.162"
|
|
18943
18981
|
}
|
|
18944
18982
|
],
|
|
18945
18983
|
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.",
|
|
18946
18984
|
rollback: {
|
|
18947
18985
|
independent: true,
|
|
18948
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18949
|
-
v3Target: "v4.5.
|
|
18986
|
+
mechanism: "npm dist-tag latest -> 4.5.162 and redeploy the Hub Lambda from tag v4.5.162 (5d12949c1714); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18987
|
+
v3Target: "v4.5.162 (@mutmutco/cli@4.5.162, tag commit 5d12949c1714 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18950
18988
|
}
|
|
18951
18989
|
},
|
|
18952
18990
|
{
|
|
@@ -21033,7 +21071,7 @@ async function runMergeTreePreflight(deps, ours, theirs) {
|
|
|
21033
21071
|
async function predictMergeConflicts(deps, ours, theirs) {
|
|
21034
21072
|
return runMergeTreePreflight(deps, ours, theirs);
|
|
21035
21073
|
}
|
|
21036
|
-
async function mergeWithToleratedResolution(deps, sourceRef, label,
|
|
21074
|
+
async function mergeWithToleratedResolution(deps, sourceRef, label, resolve7, extraTolerated = []) {
|
|
21037
21075
|
try {
|
|
21038
21076
|
await deps.run("git", ["merge", sourceRef, "--no-edit"]);
|
|
21039
21077
|
return;
|
|
@@ -21047,7 +21085,7 @@ async function mergeWithToleratedResolution(deps, sourceRef, label, resolve8, ex
|
|
|
21047
21085
|
unmerged.length === 0 ? `${label} merge failed without conflicted paths \u2014 merge aborted; inspect the repo state and rerun` : `${label} merge conflicts on untolerated path(s): ${blocking.join(", ")} \u2014 merge aborted (the train is misaligned; reconcile the branches via an approved alignment PR, then rerun)`
|
|
21048
21086
|
);
|
|
21049
21087
|
}
|
|
21050
|
-
await deps.run("git", ["checkout", `--${
|
|
21088
|
+
await deps.run("git", ["checkout", `--${resolve7}`, "--", ...unmerged]);
|
|
21051
21089
|
await deps.run("git", ["add", "--", ...unmerged]);
|
|
21052
21090
|
await deps.run("git", ["commit", "--no-edit"]);
|
|
21053
21091
|
}
|
|
@@ -21241,7 +21279,7 @@ var CORRELATE_SKEW_SLACK_MS = 1e4;
|
|
|
21241
21279
|
var CORRELATE_PAGE_LIMIT = 50;
|
|
21242
21280
|
var RUN_CONFIRM_ATTEMPTS = 3;
|
|
21243
21281
|
var RUN_CONFIRM_DELAY_MS = 1e3;
|
|
21244
|
-
var defaultSleep = (ms) => new Promise((
|
|
21282
|
+
var defaultSleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
21245
21283
|
function resolveSleep(deps) {
|
|
21246
21284
|
return deps.sleep ?? defaultSleep;
|
|
21247
21285
|
}
|
|
@@ -21545,7 +21583,7 @@ async function enqueueAlignmentAutoMerge(deps, ctx, prNumber, prUrl, openedNote)
|
|
|
21545
21583
|
}
|
|
21546
21584
|
return { ...base, note: manual };
|
|
21547
21585
|
}
|
|
21548
|
-
var ALIGNMENT_LAND_POLL_MS =
|
|
21586
|
+
var ALIGNMENT_LAND_POLL_MS = 6e4;
|
|
21549
21587
|
var ALIGNMENT_LAND_TIMEOUT_MS = 20 * 6e4;
|
|
21550
21588
|
async function awaitAlignmentLanded(deps, ctx, leg, base, opts = {}) {
|
|
21551
21589
|
if (leg.status !== "pr-pending" || !leg.autoMergeEnqueued || leg.prNumber === void 0) return leg;
|
|
@@ -23162,7 +23200,7 @@ async function runTenantReconcile(deps, options) {
|
|
|
23162
23200
|
};
|
|
23163
23201
|
}
|
|
23164
23202
|
function tenantControlWatches(action) {
|
|
23165
|
-
return action === "status" || action === "retire" || action === "verify-secrets" || action === "verify-broker" || action === "logs" || action === "run-task";
|
|
23203
|
+
return action === "status" || action === "retire" || action === "undo" || action === "verify-secrets" || action === "verify-broker" || action === "logs" || action === "run-task";
|
|
23166
23204
|
}
|
|
23167
23205
|
async function runTenantControl(deps, options) {
|
|
23168
23206
|
const { repo, stage, action } = options;
|
|
@@ -23809,8 +23847,6 @@ var import_node_path23 = require("node:path");
|
|
|
23809
23847
|
// src/jerv-cli-spawn.ts
|
|
23810
23848
|
var import_node_os13 = require("node:os");
|
|
23811
23849
|
var import_node_path22 = require("node:path");
|
|
23812
|
-
init_cli_shared();
|
|
23813
|
-
var JERV_CLI_ENTRY = (0, import_node_path22.join)("node_modules", "@jervaise", "jerv-cli", "dist", "index.cjs");
|
|
23814
23850
|
function pathEnvEntries(pathEnv, platform2 = process.platform) {
|
|
23815
23851
|
if (platform2 !== "win32") {
|
|
23816
23852
|
return pathEnv.split(import_node_path22.delimiter).map((e) => e.trim()).filter(Boolean);
|
|
@@ -24444,7 +24480,7 @@ function lockTokenPid(token) {
|
|
|
24444
24480
|
const m = /^(\d+)-/.exec(token);
|
|
24445
24481
|
return m ? Number(m[1]) : void 0;
|
|
24446
24482
|
}
|
|
24447
|
-
var sleep = (ms) => new Promise((
|
|
24483
|
+
var sleep = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
24448
24484
|
var IMMEDIATE_RETRY_BUDGET = 3;
|
|
24449
24485
|
var FileLockBusyError = class extends Error {
|
|
24450
24486
|
lockPath;
|
|
@@ -25320,7 +25356,7 @@ async function defaultWatchRun(deps, runId, repo) {
|
|
|
25320
25356
|
}
|
|
25321
25357
|
let confirmError;
|
|
25322
25358
|
for (let attempt = 0; attempt < RUN_CONFIRM_ATTEMPTS2; attempt++) {
|
|
25323
|
-
if (attempt > 0) await new Promise((
|
|
25359
|
+
if (attempt > 0) await new Promise((resolve7) => setTimeout(resolve7, RUN_CONFIRM_DELAY_MS2));
|
|
25324
25360
|
try {
|
|
25325
25361
|
const parsed = JSON.parse(await deps.run("gh", ["run", "view", String(runId), "--repo", repo, "--json", "status,conclusion"]));
|
|
25326
25362
|
if (parsed.status === "completed") return parsed.conclusion === "success" ? "success" : "failure";
|
|
@@ -26362,11 +26398,11 @@ var defaultDeps = {
|
|
|
26362
26398
|
// #5813: the caller supplies that command line. `process.argv` is NOT it — the house shim splices
|
|
26363
26399
|
// the house root out in place, so re-reading it here re-ran the removed flat alias (`release …`
|
|
26364
26400
|
// instead of `devops release …`) and the converged child refused with exit 2.
|
|
26365
|
-
reexec: (argv) => new Promise((
|
|
26401
|
+
reexec: (argv) => new Promise((resolve7) => {
|
|
26366
26402
|
const args = [...argv];
|
|
26367
26403
|
const child2 = isWin2 ? (0, import_node_child_process8.spawn)("cmd.exe", ["/c", "mmi-cli", ...args], { stdio: "inherit", windowsHide: true }) : (0, import_node_child_process8.spawn)("mmi-cli", args, { stdio: "inherit", windowsHide: true });
|
|
26368
|
-
child2.on("exit", (code) =>
|
|
26369
|
-
child2.on("error", () =>
|
|
26404
|
+
child2.on("exit", (code) => resolve7(code ?? 1));
|
|
26405
|
+
child2.on("error", () => resolve7(1));
|
|
26370
26406
|
}),
|
|
26371
26407
|
// stderr only — stdout may be carrying --json output.
|
|
26372
26408
|
warn: (line) => console.error(line)
|
|
@@ -26474,7 +26510,7 @@ var defaultDeps2 = {
|
|
|
26474
26510
|
}
|
|
26475
26511
|
},
|
|
26476
26512
|
registryWhoami: probeRegistryWhoami,
|
|
26477
|
-
sleep: (ms) => new Promise((
|
|
26513
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
26478
26514
|
env: process.env
|
|
26479
26515
|
};
|
|
26480
26516
|
function message(e) {
|
|
@@ -32728,6 +32764,7 @@ function applyRemoteScript(items, date) {
|
|
|
32728
32764
|
|
|
32729
32765
|
// src/box-commands.ts
|
|
32730
32766
|
init_clean_exit();
|
|
32767
|
+
init_cli_shared();
|
|
32731
32768
|
|
|
32732
32769
|
// src/secrets-commands.ts
|
|
32733
32770
|
var import_node_fs31 = require("node:fs");
|
|
@@ -33603,6 +33640,14 @@ function buildSetDeployPatch(_slug, input) {
|
|
|
33603
33640
|
if (!DEPLOY_DOMAIN_RE.test(a)) throw new Error(`org project set-deploy: --alias must be a DNS hostname, got ${JSON.stringify(a)}`);
|
|
33604
33641
|
}
|
|
33605
33642
|
const uniqueAliases = [...new Set(aliases)];
|
|
33643
|
+
const redirectFrom = [...new Set((input.redirectFrom ?? []).map((a) => clean4(a)).filter((a) => a !== void 0))];
|
|
33644
|
+
for (const entry of redirectFrom) {
|
|
33645
|
+
const [host, target, extra] = entry.split("=");
|
|
33646
|
+
if (!host || !DEPLOY_DOMAIN_RE.test(host) || extra !== void 0 || target !== void 0 && !DEPLOY_DOMAIN_RE.test(target)) throw new Error(`org project set-deploy: invalid --redirect-from ${JSON.stringify(entry)}`);
|
|
33647
|
+
const serving = [domain, ...uniqueAliases].map((a) => a?.toLowerCase());
|
|
33648
|
+
if (serving.includes(host.toLowerCase())) throw new Error("org project set-deploy: --redirect-from must not equal the primary domain or an alias");
|
|
33649
|
+
if (target !== void 0 && domain !== void 0 && (input.aliases !== void 0 || input.clearAliases) && !serving.includes(target.toLowerCase())) throw new Error("org project set-deploy: --redirect-from target must be the primary domain or an alias");
|
|
33650
|
+
}
|
|
33606
33651
|
if (input.clearAliases && uniqueAliases.length) {
|
|
33607
33652
|
throw new Error("org project set-deploy: --clear-aliases cannot be combined with --alias (they contradict)");
|
|
33608
33653
|
}
|
|
@@ -33642,6 +33687,7 @@ function buildSetDeployPatch(_slug, input) {
|
|
|
33642
33687
|
// #2986: an explicit `[]` is what the route reads as "clear them"; omitting the key is what it reads as
|
|
33643
33688
|
// "keep them". Those are different instructions and they now have different flags.
|
|
33644
33689
|
...input.clearAliases ? { aliases: [] } : uniqueAliases.length ? { aliases: uniqueAliases } : {},
|
|
33690
|
+
...input.redirectFrom !== void 0 ? { redirectFrom } : {},
|
|
33645
33691
|
...input.noEnvFile !== void 0 ? { noEnvFile: input.noEnvFile } : {},
|
|
33646
33692
|
// #7353: an explicit `[]` is what the route reads as "clear them"; omitting the key is what it reads as
|
|
33647
33693
|
// "keep them" — same patch contract as aliases (#2986/#2984).
|
|
@@ -34404,6 +34450,48 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
34404
34450
|
await failGraceful(e.message);
|
|
34405
34451
|
}
|
|
34406
34452
|
});
|
|
34453
|
+
box.command("previews <name>").description("inspect or configure a box preview port range in BOX#<sshHost>/META (#8444; master-only, dry-run unless --apply)").option("--port-start <port>", "first port in the dedicated preview interval (>= 1024)", (v) => Number(v)).option("--cap <n>", "maximum concurrent PR previews on this box (1..20, default 3)", (v) => Number(v)).option("--apply", "write the preview port range to BOX#<sshHost>/META (default: dry-run)").option("--json", "machine-readable output").action(async (name, o) => {
|
|
34454
|
+
try {
|
|
34455
|
+
const { boxes, incomplete } = await fetchInventory();
|
|
34456
|
+
const result = lookupBox(name, boxes, incomplete);
|
|
34457
|
+
if (result.kind === "unknown") {
|
|
34458
|
+
warnIncomplete(result.reasons);
|
|
34459
|
+
await failGraceful(
|
|
34460
|
+
`runtime box: cannot confirm whether '${name}' exists \u2014 part of the inventory could not be read (see above). Refusing to answer "no such box" from a list I know is incomplete.`
|
|
34461
|
+
);
|
|
34462
|
+
return;
|
|
34463
|
+
}
|
|
34464
|
+
if (result.kind === "absent") {
|
|
34465
|
+
await failGraceful(`runtime box: no box named '${name}'. Known boxes: ${result.known.join(", ") || "(none)"}`);
|
|
34466
|
+
return;
|
|
34467
|
+
}
|
|
34468
|
+
const found = result.box;
|
|
34469
|
+
if (!found.address) {
|
|
34470
|
+
await failGraceful(`runtime box previews: box '${found.name}' has no public IPv4 address`);
|
|
34471
|
+
return;
|
|
34472
|
+
}
|
|
34473
|
+
const status = await boxPreviewsForHost(
|
|
34474
|
+
found.address,
|
|
34475
|
+
{ portStart: o.portStart, cap: o.cap, apply: o.apply === true },
|
|
34476
|
+
registryClientDeps(await loadConfig())
|
|
34477
|
+
);
|
|
34478
|
+
const fmt = (r) => r ? `${r.ports.start}..${r.ports.end} (portStart=${r.previewPortStart}, cap=${r.previewCap})` : "(unconfigured)";
|
|
34479
|
+
if (o.json) {
|
|
34480
|
+
console.log(JSON.stringify({ ...status, box: found.name, address: found.address, incomplete }, null, 2));
|
|
34481
|
+
} else {
|
|
34482
|
+
console.log(
|
|
34483
|
+
`${found.name} (${found.address}) \u2014 ${status.apply ? "applied" : "dry-run"}
|
|
34484
|
+
current: ${fmt(status.current)}
|
|
34485
|
+
planned: ${fmt(status.planned)}
|
|
34486
|
+
live reservations: ${status.activeReservations}`
|
|
34487
|
+
);
|
|
34488
|
+
warnIncomplete(incomplete);
|
|
34489
|
+
}
|
|
34490
|
+
if (incomplete.length) process.exitCode = 1;
|
|
34491
|
+
} catch (e) {
|
|
34492
|
+
await failGraceful(e.message);
|
|
34493
|
+
}
|
|
34494
|
+
});
|
|
34407
34495
|
box.command("control <name>").description("box-side control files (#7402): --plan (default, read-only) reports drift from the repo; --apply --only <src> installs with backups").option("--plan", "read-only drift report (the default)").option("--apply", "install the files named by --only on this box, backing up each previous copy").option("--only <src>", "with --apply: a manifest src to install (repeatable; approval is file by file)", (v, acc) => [...acc, v], []).option("--dest <path>", "with --apply: a destination of a multi-target --only source to install (repeatable, #7409)", (v, acc) => [...acc, v], []).option("--all-targets", "with --apply: install a multi-target --only source to every one of its destinations on this box").option("--ref <ref>", "git ref the repo content is read from", "origin/development").option("--json", "machine-readable output").action(async (name, o) => {
|
|
34408
34496
|
try {
|
|
34409
34497
|
if (o.apply && o.plan) throw new UsageError("box control: --plan and --apply are exclusive");
|
|
@@ -38327,7 +38415,7 @@ Each module must ship a live release that bind-mounts <deployPath>/data read-onl
|
|
|
38327
38415
|
let running = 0;
|
|
38328
38416
|
const waiting = [];
|
|
38329
38417
|
const results = await Promise.allSettled(record.members.map(async (member) => {
|
|
38330
|
-
if (running >= 4) await new Promise((
|
|
38418
|
+
if (running >= 4) await new Promise((resolve7) => waiting.push(resolve7));
|
|
38331
38419
|
else running++;
|
|
38332
38420
|
try {
|
|
38333
38421
|
if ((await deps.head(member.repo, "development"))?.toLowerCase() !== member.development.toLowerCase())
|
|
@@ -38998,7 +39086,7 @@ function clean3(out) {
|
|
|
38998
39086
|
return out.trim();
|
|
38999
39087
|
}
|
|
39000
39088
|
function sleeper(deps) {
|
|
39001
|
-
return deps.sleep ?? ((ms) => new Promise((
|
|
39089
|
+
return deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
39002
39090
|
}
|
|
39003
39091
|
function normalizeHotfixVersion(input) {
|
|
39004
39092
|
const m = /^v?(\d+\.\d+\.\d+)$/.exec(input.trim());
|
|
@@ -40672,7 +40760,7 @@ async function updatePrHeadFromBase(input) {
|
|
|
40672
40760
|
} catch (e) {
|
|
40673
40761
|
throw new Error(`GitHub could not update ${input.head} from ${input.base} (${e.message.trim()}) \u2014 ${remedy}`);
|
|
40674
40762
|
}
|
|
40675
|
-
const sleep2 = input.sleep ?? ((ms) => new Promise((
|
|
40763
|
+
const sleep2 = input.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
40676
40764
|
for (let attempt = 0; attempt < PR_HEAD_UPDATE_API_READ_RETRIES; attempt++) {
|
|
40677
40765
|
const to = await readHead2();
|
|
40678
40766
|
if (to && to !== from) return { from, to, base: input.base, via: "update-branch-api" };
|
|
@@ -40697,7 +40785,7 @@ async function mergeAutoWithTransientRetry(prNumber, repo, deps) {
|
|
|
40697
40785
|
if (first.mergeStatus !== "failed") return first;
|
|
40698
40786
|
const ready = await deps.probeMergeReady(prNumber, repo).catch(() => ({ open: false, mergeable: false, checksPassing: false }));
|
|
40699
40787
|
if (!ready.open || !ready.mergeable || !ready.checksPassing) return first;
|
|
40700
|
-
const sleep2 = deps.sleep ?? ((ms) => new Promise((
|
|
40788
|
+
const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
40701
40789
|
await sleep2(PR_LAND_MERGE_RETRY_DELAY_MS);
|
|
40702
40790
|
const retried = await deps.mergeAuto(prNumber, repo);
|
|
40703
40791
|
if (retried.mergeStatus !== "failed") return retried;
|
|
@@ -40708,7 +40796,7 @@ var AUTO_MERGE_CONFIRM_DELAY_MS = 15e3;
|
|
|
40708
40796
|
async function confirmAutoMergeEnqueued(deps, options) {
|
|
40709
40797
|
const retries = options?.retries ?? AUTO_MERGE_CONFIRM_RETRIES;
|
|
40710
40798
|
const delayMs = options?.delayMs ?? AUTO_MERGE_CONFIRM_DELAY_MS;
|
|
40711
|
-
const sleep2 = deps.sleep ?? ((ms) => new Promise((
|
|
40799
|
+
const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
40712
40800
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
40713
40801
|
if (await deps.readMerged().catch(() => false)) return "merged";
|
|
40714
40802
|
const stuck = await deps.readAutoMergeRequest().then((s) => s.trim()).catch(() => "");
|
|
@@ -40725,7 +40813,7 @@ async function confirmAutoMergeEnqueued(deps, options) {
|
|
|
40725
40813
|
async function readGhPrStateWithRetry(fetchState, options) {
|
|
40726
40814
|
const retries = options?.retries ?? PR_LAND_STATE_READ_RETRIES;
|
|
40727
40815
|
const delayMs = options?.delayMs ?? PR_LAND_STATE_READ_DELAY_MS;
|
|
40728
|
-
const sleep2 = options?.sleep ?? ((ms) => new Promise((
|
|
40816
|
+
const sleep2 = options?.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
40729
40817
|
let lastError = "empty state";
|
|
40730
40818
|
for (let attempt = 0; attempt < retries; attempt++) {
|
|
40731
40819
|
try {
|
|
@@ -40809,7 +40897,7 @@ async function runPrLand(prNumber, options, deps) {
|
|
|
40809
40897
|
return queueMerged(base, deps);
|
|
40810
40898
|
}
|
|
40811
40899
|
const deadline = (deps.now ?? (() => Date.now()))() + (options.queueTimeoutMs ?? PR_LAND_QUEUE_TIMEOUT_MS);
|
|
40812
|
-
await (deps.sleep ?? ((ms) => new Promise((
|
|
40900
|
+
await (deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms))))(deps.pollDelayMs?.(0) ?? PR_LAND_POLL_MS);
|
|
40813
40901
|
return pollPrMergeQueue(prNumber, options, deps, base, void 0, deadline);
|
|
40814
40902
|
}
|
|
40815
40903
|
if (merge.mergeStatus === "merged") {
|
|
@@ -40847,7 +40935,7 @@ function queueMerged(base, deps) {
|
|
|
40847
40935
|
}
|
|
40848
40936
|
async function pollPrMergeQueue(pr, options, deps, base, snapshot, deadlineMs) {
|
|
40849
40937
|
const now = deps.now ?? (() => Date.now());
|
|
40850
|
-
const sleep2 = deps.sleep ?? ((ms) => new Promise((
|
|
40938
|
+
const sleep2 = deps.sleep ?? ((ms) => new Promise((resolve7) => setTimeout(resolve7, ms)));
|
|
40851
40939
|
const timeoutMs = options.queueTimeoutMs ?? PR_LAND_QUEUE_TIMEOUT_MS;
|
|
40852
40940
|
const deadline = deadlineMs ?? now() + timeoutMs;
|
|
40853
40941
|
let attempt = 0;
|
|
@@ -41990,7 +42078,7 @@ async function composeOverrideBodyFile(prNumber, repoArgs, gh2, opts) {
|
|
|
41990
42078
|
async function ghAdminTrueMergeWhenClean(prNumber, repo, opts = {}) {
|
|
41991
42079
|
const io = opts.io ?? defaultGhMergeAutoIo;
|
|
41992
42080
|
const sleep2 = opts.sleep ?? ((ms) => new Promise((r) => setTimeout(r, ms)));
|
|
41993
|
-
const pollMs = opts.pollMs ??
|
|
42081
|
+
const pollMs = opts.pollMs ?? 6e4;
|
|
41994
42082
|
const deadline = Date.now() + (opts.timeoutMs ?? 20 * 6e4);
|
|
41995
42083
|
for (; ; ) {
|
|
41996
42084
|
const raw = await io.gh(["pr", "view", prNumber, "--repo", repo, "--json", "state,mergeStateStatus"], GC_GH_TIMEOUT_MS).catch(() => "");
|
|
@@ -44017,7 +44105,7 @@ var import_promises7 = require("node:fs/promises");
|
|
|
44017
44105
|
init_cli_shared();
|
|
44018
44106
|
init_error_codes();
|
|
44019
44107
|
var GC_GH_TIMEOUT_MS2 = 2e4;
|
|
44020
|
-
var CHECKS_WATCH_POLL_MS =
|
|
44108
|
+
var CHECKS_WATCH_POLL_MS = 6e4;
|
|
44021
44109
|
var CHECKS_WATCH_TIMEOUT_MS = 10 * 6e4;
|
|
44022
44110
|
function prCommentMarker(markerId) {
|
|
44023
44111
|
return `<!-- mmi-pr-marker:${markerId} -->`;
|
|
@@ -44556,7 +44644,7 @@ async function checkPrReview(number, repo, head, deps = {
|
|
|
44556
44644
|
}
|
|
44557
44645
|
}
|
|
44558
44646
|
function computePrPatchId(number, repo) {
|
|
44559
|
-
return new Promise((
|
|
44647
|
+
return new Promise((resolve7, reject) => {
|
|
44560
44648
|
const gh2 = (0, import_node_child_process14.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
44561
44649
|
const git3 = (0, import_node_child_process14.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
|
|
44562
44650
|
let out = "";
|
|
@@ -44594,7 +44682,7 @@ function computePrPatchId(number, repo) {
|
|
|
44594
44682
|
if (gitCode !== 0) return reject(new Error(`git patch-id --stable exited ${gitCode}: ${gitErr.trim()}`));
|
|
44595
44683
|
const id = out.trim().split(/\s+/)[0];
|
|
44596
44684
|
if (!/^[0-9a-f]{40}$/.test(id ?? "")) return reject(new Error(`patch-id: PR #${number} diff is empty or unreadable (gh: ${ghErr.trim() || "no stderr"})`));
|
|
44597
|
-
|
|
44685
|
+
resolve7(id);
|
|
44598
44686
|
};
|
|
44599
44687
|
gh2.on("close", (code) => {
|
|
44600
44688
|
ghCode = code;
|
|
@@ -44645,7 +44733,7 @@ init_cli_shared();
|
|
|
44645
44733
|
var GIT_TIMEOUT_MS2 = 15e3;
|
|
44646
44734
|
function catFileBatch(root, ref, paths) {
|
|
44647
44735
|
if (paths.length === 0) return Promise.resolve([]);
|
|
44648
|
-
return new Promise((
|
|
44736
|
+
return new Promise((resolve7) => {
|
|
44649
44737
|
const chunks = [];
|
|
44650
44738
|
let settled = false;
|
|
44651
44739
|
const child2 = (0, import_node_child_process15.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
|
|
@@ -44653,7 +44741,7 @@ function catFileBatch(root, ref, paths) {
|
|
|
44653
44741
|
if (settled) return;
|
|
44654
44742
|
settled = true;
|
|
44655
44743
|
clearTimeout(timer);
|
|
44656
|
-
|
|
44744
|
+
resolve7(parseCatFileBatch(Buffer.concat(chunks), paths.length));
|
|
44657
44745
|
};
|
|
44658
44746
|
const timer = setTimeout(() => {
|
|
44659
44747
|
child2.kill("SIGKILL");
|
|
@@ -45078,7 +45166,7 @@ function healthPollIntervalMs() {
|
|
|
45078
45166
|
return HEALTH_POLL_INTERVAL_MS;
|
|
45079
45167
|
}
|
|
45080
45168
|
function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
|
|
45081
|
-
return new Promise((
|
|
45169
|
+
return new Promise((resolve7, reject) => {
|
|
45082
45170
|
let settled = false;
|
|
45083
45171
|
const finish = (fn) => {
|
|
45084
45172
|
if (settled) return;
|
|
@@ -45088,7 +45176,7 @@ function waitForProcessStability(child2, graceMs = earlyExitGraceMs()) {
|
|
|
45088
45176
|
child2.removeAllListeners("exit");
|
|
45089
45177
|
fn();
|
|
45090
45178
|
};
|
|
45091
|
-
const timer = setTimeout(() => finish(
|
|
45179
|
+
const timer = setTimeout(() => finish(resolve7), graceMs);
|
|
45092
45180
|
child2.on("error", (err) => finish(() => reject(new Error(`stage process failed to start: ${err.message}`))));
|
|
45093
45181
|
child2.on("exit", (code, signal) => {
|
|
45094
45182
|
const detail = code != null ? `code ${code}` : signal ? `signal ${signal}` : "unknown reason";
|
|
@@ -45281,10 +45369,10 @@ function pickStagePort(range, isFree) {
|
|
|
45281
45369
|
throw new Error(`no free stage port in range ${start}-${end} \u2014 every port is in use`);
|
|
45282
45370
|
}
|
|
45283
45371
|
function isPortFree(port) {
|
|
45284
|
-
return new Promise((
|
|
45372
|
+
return new Promise((resolve7) => {
|
|
45285
45373
|
const srv = (0, import_node_net.createServer)();
|
|
45286
|
-
srv.once("error", () =>
|
|
45287
|
-
srv.once("listening", () => srv.close(() =>
|
|
45374
|
+
srv.once("error", () => resolve7(false));
|
|
45375
|
+
srv.once("listening", () => srv.close(() => resolve7(true)));
|
|
45288
45376
|
srv.listen(port, "127.0.0.1");
|
|
45289
45377
|
});
|
|
45290
45378
|
}
|
|
@@ -45562,7 +45650,7 @@ async function killTree(pid) {
|
|
|
45562
45650
|
} catch {
|
|
45563
45651
|
}
|
|
45564
45652
|
}
|
|
45565
|
-
await new Promise((
|
|
45653
|
+
await new Promise((resolve7) => setTimeout(resolve7, 500));
|
|
45566
45654
|
try {
|
|
45567
45655
|
process.kill(-pid, "SIGKILL");
|
|
45568
45656
|
} catch {
|
|
@@ -45635,7 +45723,7 @@ async function waitForHealth(url, timeoutMs, anyStatus = false) {
|
|
|
45635
45723
|
} catch (e) {
|
|
45636
45724
|
last = e.message;
|
|
45637
45725
|
}
|
|
45638
|
-
await new Promise((
|
|
45726
|
+
await new Promise((resolve7) => setTimeout(resolve7, healthPollIntervalMs()));
|
|
45639
45727
|
}
|
|
45640
45728
|
throw new Error(`stage health check timed out for ${url}${last ? ` (${last})` : ""}`);
|
|
45641
45729
|
}
|
|
@@ -45822,7 +45910,7 @@ function unlinkNodeModulesJunction(wtPath) {
|
|
|
45822
45910
|
}
|
|
45823
45911
|
}
|
|
45824
45912
|
function defaultSleep2(ms) {
|
|
45825
|
-
return new Promise((
|
|
45913
|
+
return new Promise((resolve7) => setTimeout(resolve7, ms));
|
|
45826
45914
|
}
|
|
45827
45915
|
async function removeResidueDirectory(wtPath, options = {}) {
|
|
45828
45916
|
const { sleep: sleep2 = defaultSleep2, removeEmptyDir = import_node_fs44.rmdirSync, exists = import_node_fs44.existsSync } = options;
|
|
@@ -47572,7 +47660,7 @@ ${list}`);
|
|
|
47572
47660
|
// #5400: after grace, name "GitHub delivered zero runs" instead of burning the full budget as pending.
|
|
47573
47661
|
pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr checks-wait", number, repo),
|
|
47574
47662
|
baseBranch,
|
|
47575
|
-
sleep: (ms) => new Promise((
|
|
47663
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
47576
47664
|
log: (message2) => console.warn(message2),
|
|
47577
47665
|
timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
|
|
47578
47666
|
// Liveness on stderr, one line per poll. A silent bounded wait is indistinguishable from a hang, and
|
|
@@ -47742,7 +47830,7 @@ ${list}`);
|
|
|
47742
47830
|
// #5400: same zero-runs delivery probe as checks-wait — do not burn the land budget on silence.
|
|
47743
47831
|
pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr land", prNumber, repo),
|
|
47744
47832
|
baseBranch: "development",
|
|
47745
|
-
sleep: (ms) => new Promise((
|
|
47833
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
47746
47834
|
log: (message2) => console.warn(message2),
|
|
47747
47835
|
// `pr land` inherits the same (raised) checks budget, so it needs the same liveness — otherwise the
|
|
47748
47836
|
// 30m wait is SILENT and reads exactly like the hang #2940 was filed about, only three times longer.
|
|
@@ -47794,7 +47882,7 @@ ${list}`);
|
|
|
47794
47882
|
} else {
|
|
47795
47883
|
lastFailure = void 0;
|
|
47796
47884
|
}
|
|
47797
|
-
await new Promise((
|
|
47885
|
+
await new Promise((resolve7) => setTimeout(resolve7, PR_LAND_POLL_MS));
|
|
47798
47886
|
}
|
|
47799
47887
|
if (lastFailure) {
|
|
47800
47888
|
throw new Error(
|
|
@@ -47985,7 +48073,7 @@ ${list}`);
|
|
|
47985
48073
|
checksDiagnosticCommand: `gh pr checks ${number} --repo ${repo}`,
|
|
47986
48074
|
pollHeadWorkflowRunCount: () => waitLoopHeadWorkflowRunCount("pr merge --wait", number, repo),
|
|
47987
48075
|
baseBranch,
|
|
47988
|
-
sleep: (ms) => new Promise((
|
|
48076
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
47989
48077
|
log: (message2) => console.warn(message2),
|
|
47990
48078
|
timeoutMs: Math.max(1, budgetMs - (Date.now() - waitStarted)),
|
|
47991
48079
|
progress: ({ state, elapsedMs, remainingMs }) => console.warn(`pr merge: --wait checks \u2014 ${state}, ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
|
|
@@ -48075,7 +48163,7 @@ ${list}`);
|
|
|
48075
48163
|
}
|
|
48076
48164
|
if (!o.auto && mergeRejectedBaseBranchModified(message2)) {
|
|
48077
48165
|
console.warn(`pr merge: the base branch was modified by a concurrent merge \u2014 waiting ${PR_MERGE_BASE_RACE_RETRY_DELAY_MS / 1e3}s and retrying PR #${number}'s merge once (#6052).`);
|
|
48078
|
-
await new Promise((
|
|
48166
|
+
await new Promise((resolve7) => setTimeout(resolve7, PR_MERGE_BASE_RACE_RETRY_DELAY_MS));
|
|
48079
48167
|
await execFileP("gh", buildPrMergeArgs({ number, repoArgs, method, auto: false, deleteBranch: false, bodyFile }), { timeout: GH_MUTATION_TIMEOUT_MS }).catch((e2) => {
|
|
48080
48168
|
const m2 = String(e2.message || "");
|
|
48081
48169
|
if (/already been merged/i.test(m2)) {
|
|
@@ -48337,7 +48425,7 @@ ${list}`);
|
|
|
48337
48425
|
console.warn(`ci checks-wait: zero-runs probe FAILED (${read.error}) \u2014 not treating as delivery failure this cycle`);
|
|
48338
48426
|
return null;
|
|
48339
48427
|
},
|
|
48340
|
-
sleep: (ms) => new Promise((
|
|
48428
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms)),
|
|
48341
48429
|
log: (message2) => console.warn(message2),
|
|
48342
48430
|
timeoutMs: timeoutMs ?? PR_CHECKS_TIMEOUT_MS,
|
|
48343
48431
|
progress: ({ state, elapsedMs, remainingMs }) => console.warn(`ci checks-wait: ${state} \u2014 ${Math.round(elapsedMs / 1e3)}s elapsed, ${Math.round(remainingMs / 6e4)}m left`)
|
|
@@ -48714,7 +48802,7 @@ function hotfixFollowUpLegs(runs, foldPort, alignment, foldNote, deployNote) {
|
|
|
48714
48802
|
}
|
|
48715
48803
|
return legs;
|
|
48716
48804
|
}
|
|
48717
|
-
async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((
|
|
48805
|
+
async function runProjectInfoSyncLeg(cb, repo, sleep2 = (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))) {
|
|
48718
48806
|
for (let attempt = 0; ; attempt++) {
|
|
48719
48807
|
try {
|
|
48720
48808
|
return await cb(repo, true);
|
|
@@ -49639,7 +49727,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49639
49727
|
if (!reuse) await gh(["workflow", "run", "module-rc-publish.yml", "--repo", "mutmutco/MMI-Hub", ...fields.flatMap((f) => ["--field", f])]);
|
|
49640
49728
|
let candidate = reuse;
|
|
49641
49729
|
for (let i = 0; !candidate && i < 25; i++) {
|
|
49642
|
-
await new Promise((
|
|
49730
|
+
await new Promise((resolve7) => setTimeout(resolve7, 1e3));
|
|
49643
49731
|
candidate = (await rcRuns()).find((r) => r.displayTitle === title && Date.parse(r.createdAt) >= since);
|
|
49644
49732
|
}
|
|
49645
49733
|
if (!candidate) throw new Error(`workflow dispatch outcome ambiguous for "${title}"; inspect Actions before retrying`);
|
|
@@ -49795,7 +49883,7 @@ function suiteTrainIo(root, summaryFile, memberSummaryFiles = {}, summaryFileTr,
|
|
|
49795
49883
|
for (let i = 0; ; i++) {
|
|
49796
49884
|
const pin = await openSuitePinPr({ root, run: (file, args, cwd) => exec(file, args, cwd, GIT_TIMEOUT_MS) }, { repo, tag, stage: "main" });
|
|
49797
49885
|
if (pin.status !== "pending" || i >= 40) return pin;
|
|
49798
|
-
await new Promise((
|
|
49886
|
+
await new Promise((resolve7) => setTimeout(resolve7, 3e4));
|
|
49799
49887
|
}
|
|
49800
49888
|
},
|
|
49801
49889
|
suiteMapping: async (leadTag) => {
|
|
@@ -49877,7 +49965,7 @@ function suiteRcDataProdDeps() {
|
|
|
49877
49965
|
const rc = facts.stages.rc;
|
|
49878
49966
|
return rc?.present ? rc.substrate ?? "an unnamed substrate" : null;
|
|
49879
49967
|
},
|
|
49880
|
-
sleep: (ms) => new Promise((
|
|
49968
|
+
sleep: (ms) => new Promise((resolve7) => setTimeout(resolve7, ms))
|
|
49881
49969
|
};
|
|
49882
49970
|
}
|
|
49883
49971
|
function registerSuiteCommands(program3) {
|
|
@@ -52665,6 +52753,12 @@ async function runDoctorClean(opts, io, deps) {
|
|
|
52665
52753
|
init_cli_shared();
|
|
52666
52754
|
init_error_codes();
|
|
52667
52755
|
init_house_map();
|
|
52756
|
+
var PR_PREFLIGHT_STEPS = [
|
|
52757
|
+
{ label: "Review the docs and runbook sections affected by the code" },
|
|
52758
|
+
{ label: "Update affected instructions, or record a precise Runbook-Unaffected explanation when they genuinely remain unchanged" },
|
|
52759
|
+
{ label: "Commit code and documentation first (coverage compares committed base...HEAD)", command: "git commit" },
|
|
52760
|
+
{ label: "Run the repository's existing fast local preflight (check:local where declared, otherwise its documented equivalent)", command: "npm run check:local" }
|
|
52761
|
+
];
|
|
52668
52762
|
var LOOP_PLAYBOOKS = {
|
|
52669
52763
|
agent: {
|
|
52670
52764
|
title: "Agent",
|
|
@@ -52676,7 +52770,8 @@ var LOOP_PLAYBOOKS = {
|
|
|
52676
52770
|
{ label: "Claim board work (board mutation only \u2014 never `oracle issue claim` or the flat `board claim`; ground unknown write routes via `commands` / `explain` first)", command: "mmi-cli oracle board claim <ref>" },
|
|
52677
52771
|
{ label: "Prepare the local workspace through the host surface" },
|
|
52678
52772
|
{ label: "Before broad docs rewrites, follow docs/Guides/doc-ceremony-cut.md" },
|
|
52679
|
-
{ label: "Apply the repository test policy,
|
|
52773
|
+
{ label: "Apply the repository test policy and run only its permitted focused checks, without a broad local build or full suite", command: "mmi-cli tests policy --base origin/development" },
|
|
52774
|
+
...PR_PREFLIGHT_STEPS,
|
|
52680
52775
|
{ label: "Publish the branch", command: "git push origin <branch>:<branch>" },
|
|
52681
52776
|
{ label: "Open the development-base PR", command: 'mmi-cli devops pr create --title "<title>" --body-file .jerv/PR_BODY.md --base development' },
|
|
52682
52777
|
{ label: "Land to development (waits for checks itself)", command: "mmi-cli devops pr land <PR-number>" },
|
|
@@ -52698,6 +52793,7 @@ var LOOP_PLAYBOOKS = {
|
|
|
52698
52793
|
"ship-pr": {
|
|
52699
52794
|
title: "Ship PR",
|
|
52700
52795
|
steps: [
|
|
52796
|
+
...PR_PREFLIGHT_STEPS,
|
|
52701
52797
|
{ label: "Publish the branch", command: "git push origin <branch>:<branch>" },
|
|
52702
52798
|
{ label: "Open the development-base PR", command: 'mmi-cli devops pr create --title "<title>" --body-file .jerv/PR_BODY.md --base development' },
|
|
52703
52799
|
{ label: "Land the PR (merge to development \u2014 waits for checks itself)", command: "mmi-cli devops pr land <PR-number>" }
|
|
@@ -55856,7 +55952,7 @@ function createRunbookLiveDeps(cliBin) {
|
|
|
55856
55952
|
};
|
|
55857
55953
|
const first = await probe().catch(() => 599);
|
|
55858
55954
|
if (first < 500) return first;
|
|
55859
|
-
await new Promise((
|
|
55955
|
+
await new Promise((resolve7) => setTimeout(resolve7, 2e4));
|
|
55860
55956
|
return probe();
|
|
55861
55957
|
}
|
|
55862
55958
|
};
|
|
@@ -55929,11 +56025,13 @@ function registerEdgeCommands(program3) {
|
|
|
55929
56025
|
process.exitCode = 1;
|
|
55930
56026
|
}
|
|
55931
56027
|
});
|
|
55932
|
-
edge.command("dns <action> <owner/repo> <stage>").description("read (`status`)
|
|
55933
|
-
if (
|
|
56028
|
+
edge.command("dns <action> <owner/repo> <stage>").description("read (`status`), create missing (`ensure`) or guarded delete (`delete`, dry-run unless --apply) stage DNS; writes are master-only").option("--host <host>", "declared stage host to delete").option("--apply", "apply the guarded DNS deletion").action(async (action, repo, stage, options) => {
|
|
56029
|
+
if (!["status", "ensure", "delete"].includes(action)) return fail("runtime edge dns: <action> must be status, ensure or delete");
|
|
56030
|
+
if (action === "delete" && !options.host) return fail("runtime edge dns delete: --host is required");
|
|
56031
|
+
if (action !== "delete" && (options.host || options.apply)) return fail("runtime edge dns: --host and --apply are only for delete");
|
|
55934
56032
|
if (stage !== "dev" && stage !== "rc" && stage !== "main") return fail("runtime edge dns: <stage> must be dev, rc, or main");
|
|
55935
56033
|
try {
|
|
55936
|
-
const result = await edgeDnsForStage(slugOf(repo), stage, registryClientDeps(await loadConfig()), action === "ensure");
|
|
56034
|
+
const result = await edgeDnsForStage(slugOf(repo), stage, registryClientDeps(await loadConfig()), action === "ensure", action === "delete" ? { host: options.host, apply: options.apply === true } : void 0);
|
|
55937
56035
|
console.log(JSON.stringify(result, null, 2));
|
|
55938
56036
|
if (result.required && result.complete === false) process.exitCode = 1;
|
|
55939
56037
|
} catch (e) {
|
|
@@ -56673,8 +56771,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56673
56771
|
});
|
|
56674
56772
|
const raced = await Promise.race([
|
|
56675
56773
|
work.then((r) => ({ ...r, timedOut: false })),
|
|
56676
|
-
new Promise((
|
|
56677
|
-
ceiling = setTimeout(() =>
|
|
56774
|
+
new Promise((resolve7) => {
|
|
56775
|
+
ceiling = setTimeout(() => resolve7({ timedOut: true, scanned: 0, findings: 0, fixed: 0, failed: 0 }), BOARD_DOCTOR_TIMEOUT_MS);
|
|
56678
56776
|
})
|
|
56679
56777
|
]);
|
|
56680
56778
|
if (raced.timedOut) return { scanned: 0, findings: 0, fixed: 0, failed: 0, timedOut: true };
|
|
@@ -56707,8 +56805,8 @@ function mmiDoctorDeps(opts = {}) {
|
|
|
56707
56805
|
incomplete: nb.incomplete,
|
|
56708
56806
|
timedOut: false
|
|
56709
56807
|
})),
|
|
56710
|
-
new Promise((
|
|
56711
|
-
ceiling = setTimeout(() =>
|
|
56808
|
+
new Promise((resolve7) => {
|
|
56809
|
+
ceiling = setTimeout(() => resolve7({ driftLines: [], incomplete: [], timedOut: true }), SCHEDULES_DRIFT_TIMEOUT_MS);
|
|
56712
56810
|
})
|
|
56713
56811
|
]);
|
|
56714
56812
|
if (!raced.timedOut && raced.incomplete.length === 0) writeSchedulesDriftCache(cachePath, raced.driftLines);
|
|
@@ -56988,7 +57086,6 @@ function envelopeAwareWriteErr(str2) {
|
|
|
56988
57086
|
}
|
|
56989
57087
|
writeHumanParseError(str2);
|
|
56990
57088
|
}
|
|
56991
|
-
var INVOKED_ARGV3 = process.argv.slice(2);
|
|
56992
57089
|
var program2 = new Command();
|
|
56993
57090
|
program2.name("mmi-cli").description("MMI Future Hub CLI \u2014 the org control plane for agentic coding.").version(resolveClientVersion()).configureOutput({ writeErr: envelopeAwareWriteErr }).showHelpAfterError(PARSE_HINT_SENTINEL);
|
|
56994
57091
|
program2.addHelpText(
|
|
@@ -57013,6 +57110,8 @@ function appActorDeps() {
|
|
|
57013
57110
|
}
|
|
57014
57111
|
setPollTokenProvider(async () => activeAppToken() ?? pollTokenOrUndefined(appActorDeps()));
|
|
57015
57112
|
setGhReadTokenProvider(pollToken);
|
|
57113
|
+
var filingToken;
|
|
57114
|
+
setGhWriteTokenProvider(() => filingToken ??= mintFilingWriteToken(appActorDeps()).then((t) => t.token, () => void 0));
|
|
57016
57115
|
setStatusWriteTokenProvider(() => mintStatusWriteToken(appActorDeps()));
|
|
57017
57116
|
var registerPreAction = Reflect.get(program2, ["h", "ook"].join(""));
|
|
57018
57117
|
registerPreAction.call(program2, "preAction", async (_thisCommand, actionCommand) => {
|
|
@@ -57090,6 +57189,15 @@ Dry run: pass --confirm-data-loss ${repo}/${stage} to decommission.`);
|
|
|
57090
57189
|
return failGraceful(`runtime tenant control: ${e.message}`);
|
|
57091
57190
|
}
|
|
57092
57191
|
});
|
|
57192
|
+
tenant.command("undo <owner/repo> <stage>").description("switch a tenant stage back to its previous release (warm standby: seconds; else recreated from the retained release, no rebuild); watches by default").option("--json", "machine-readable output").action(async (repo, stage, o) => {
|
|
57193
|
+
try {
|
|
57194
|
+
const result = await runTenantControl(trainApplyDeps(), { repo, stage, action: "undo", watch: true });
|
|
57195
|
+
printLine(o.json ? JSON.stringify(result, null, 2) : renderTenantControl(result));
|
|
57196
|
+
if (result.conclusion === "failure") return failGraceful(`runtime tenant undo ${stage}: ${result.category ?? "failed"} \u2014 ${result.note}`);
|
|
57197
|
+
} catch (e) {
|
|
57198
|
+
return failGraceful(`runtime tenant undo: ${e.message}`);
|
|
57199
|
+
}
|
|
57200
|
+
});
|
|
57093
57201
|
var tenantArtifact = tenant.command("artifact").description("private stage-bound inputs for declared tenant tasks");
|
|
57094
57202
|
tenantArtifact.command("put <owner/repo> <stage> <path>").description("upload a private file through a short-lived Hub grant; prints only an opaque artifact id").option("--json", "machine-readable output").action(async (repo, stage, path2, o) => {
|
|
57095
57203
|
try {
|
|
@@ -57532,7 +57640,7 @@ fullTrack.command("readiness <owner/repo>").description("aggregate branch topolo
|
|
|
57532
57640
|
console.log(JSON.stringify(report, null, 2));
|
|
57533
57641
|
if (!report.rcand.canApply) process.exitCode = 1;
|
|
57534
57642
|
});
|
|
57535
|
-
project.command("set-deploy [owner/repo]").description("patch a tenant DEPLOY row \u2014 project-admin may set only --no-env-file/--compose-profiles on their own existing dev/rc row; master may seed/change all coords and main; defaults to the current repo").addOption(new Option("--stage <stage>", "dev | rc | main").makeOptionMandatory().choices(["dev", "rc", "main"])).option("--ssh-host <host>", "the box address the deploy ssh-es into; omit to keep the stored value (required only for a NEW hetzner-ssh row \u2014 `mmi-cli devops runtime box list` finds it)").option("--ssh-user <user>", "ssh user; omit to leave the row unchanged (default root on a new row)").option("--port <port>", "loopback port the container binds / Caddy upstream (1..65535); omit to leave the row unchanged").addOption(new Option("--substrate <substrate>", "hetzner-ssh | s3-cloudfront; omit to leave the row unchanged").choices([...DEPLOY_SUBSTRATES])).option("--deploy-role-arn <arn>", "s3-cloudfront: the scoped OIDC deployer role tenant-deploy.yml assumes for this stage").option("--app-bucket <bucket>", "s3-cloudfront: the S3 bucket the built dist/ is synced into").option("--distribution-id <id>", "s3-cloudfront: the CloudFront distribution invalidated after the sync").option("--distribution-domain <domain>", "s3-cloudfront: the host the post-deploy security-header proof is measured against").option("--deploy-path <path>", "on-box per-stage release root; omit to leave the row unchanged (default /opt/mmi/<slug>/<stage> on a new row)").option("--service <name>", "systemd/compose service name; omit to leave the row unchanged (default the slug on a new row)").option("--domain <domain>", "canonical serving host; omit to leave the row unchanged").option("--alias <domain...>", "extra serving hostname the box Caddy answers (repeatable); omit to leave the stored aliases unchanged").option("--clear-aliases", "remove EVERY serving alias from the row (#2986) \u2014 omitting --alias preserves them, so clearing needs saying out loud").option("--no-env-file <bool>", "set the DEPLOY# fileless flag (true|false) \u2014 own-repo project-admin dev/rc; master main; true = env passthrough with no .env symlink").option("--compose-profiles <profiles>", "comma-separated compose profiles to enable for this stage (e.g. huddles,slack-bridge); omit to leave unchanged").option("--clear-compose-profiles", "remove EVERY compose profile from the row \u2014 omitting --compose-profiles preserves them, so clearing needs saying out loud").option("--force", "explicit recovery override: skip fileless-compose verification only after independent proof").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
|
|
57643
|
+
project.command("set-deploy [owner/repo]").description("patch a tenant DEPLOY row \u2014 project-admin may set only --no-env-file/--compose-profiles on their own existing dev/rc row; master may seed/change all coords and main; defaults to the current repo").addOption(new Option("--stage <stage>", "dev | rc | main").makeOptionMandatory().choices(["dev", "rc", "main"])).option("--ssh-host <host>", "the box address the deploy ssh-es into; omit to keep the stored value (required only for a NEW hetzner-ssh row \u2014 `mmi-cli devops runtime box list` finds it)").option("--ssh-user <user>", "ssh user; omit to leave the row unchanged (default root on a new row)").option("--port <port>", "loopback port the container binds / Caddy upstream (1..65535); omit to leave the row unchanged").addOption(new Option("--substrate <substrate>", "hetzner-ssh | s3-cloudfront; omit to leave the row unchanged").choices([...DEPLOY_SUBSTRATES])).option("--deploy-role-arn <arn>", "s3-cloudfront: the scoped OIDC deployer role tenant-deploy.yml assumes for this stage").option("--app-bucket <bucket>", "s3-cloudfront: the S3 bucket the built dist/ is synced into").option("--distribution-id <id>", "s3-cloudfront: the CloudFront distribution invalidated after the sync").option("--distribution-domain <domain>", "s3-cloudfront: the host the post-deploy security-header proof is measured against").option("--deploy-path <path>", "on-box per-stage release root; omit to leave the row unchanged (default /opt/mmi/<slug>/<stage> on a new row)").option("--service <name>", "systemd/compose service name; omit to leave the row unchanged (default the slug on a new row)").option("--domain <domain>", "canonical serving host; omit to leave the row unchanged").option("--alias <domain...>", "extra serving hostname the box Caddy answers (repeatable); omit to leave the stored aliases unchanged").option("--redirect-from <host>", "permanent redirect host or host=target (primary or alias); repeatable", (host, hosts) => [...hosts, host], []).option("--clear-aliases", "remove EVERY serving alias from the row (#2986) \u2014 omitting --alias preserves them, so clearing needs saying out loud").option("--no-env-file <bool>", "set the DEPLOY# fileless flag (true|false) \u2014 own-repo project-admin dev/rc; master main; true = env passthrough with no .env symlink").option("--compose-profiles <profiles>", "comma-separated compose profiles to enable for this stage (e.g. huddles,slack-bridge); omit to leave unchanged").option("--clear-compose-profiles", "remove EVERY compose profile from the row \u2014 omitting --compose-profiles preserves them, so clearing needs saying out loud").option("--force", "explicit recovery override: skip fileless-compose verification only after independent proof").option("--json", "machine-readable output").action(async (repoOrSlug, o) => {
|
|
57536
57644
|
const cfg = await loadConfig();
|
|
57537
57645
|
let target;
|
|
57538
57646
|
try {
|
|
@@ -57587,6 +57695,7 @@ ${filelessTransitionGuide(target, o.stage)}`
|
|
|
57587
57695
|
distributionId: o.distributionId,
|
|
57588
57696
|
distributionDomain: o.distributionDomain,
|
|
57589
57697
|
aliases: o.alias,
|
|
57698
|
+
redirectFrom: o.redirectFrom?.length ? o.redirectFrom : void 0,
|
|
57590
57699
|
clearAliases: o.clearAliases,
|
|
57591
57700
|
noEnvFile,
|
|
57592
57701
|
composeProfiles,
|