@mutmutco/cli 4.4.5 → 4.4.7
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 +303 -71
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -1112,6 +1112,7 @@ var init_cli_shared = __esm({
|
|
|
1112
1112
|
// src/board-write.ts
|
|
1113
1113
|
var board_write_exports = {};
|
|
1114
1114
|
__export(board_write_exports, {
|
|
1115
|
+
addIssueToProjectViaHub: () => addIssueToProjectViaHub,
|
|
1115
1116
|
writeHubBoardField: () => writeHubBoardField
|
|
1116
1117
|
});
|
|
1117
1118
|
async function writeHubBoardField(request) {
|
|
@@ -1125,6 +1126,18 @@ async function writeHubBoardField(request) {
|
|
|
1125
1126
|
const body = await res.json().catch(() => null);
|
|
1126
1127
|
if (!res.ok || body?.updated !== true) throw new Error(`board field write HTTP ${res.status}: ${body?.error ?? "unconfirmed result"}`);
|
|
1127
1128
|
}
|
|
1129
|
+
async function addIssueToProjectViaHub(cfg, contentNodeId) {
|
|
1130
|
+
const config = await loadConfig();
|
|
1131
|
+
const res = await fetch(`${config.sagaApiUrl?.replace(/\/$/, "")}/board/attach`, {
|
|
1132
|
+
method: "POST",
|
|
1133
|
+
headers: await hubHeaders({ "content-type": "application/json" }),
|
|
1134
|
+
body: JSON.stringify({ projectId: cfg.projectId, contentNodeId }),
|
|
1135
|
+
signal: AbortSignal.timeout(25e3)
|
|
1136
|
+
});
|
|
1137
|
+
const body = await res.json().catch(() => null);
|
|
1138
|
+
if (!res.ok || !body?.itemId) throw new Error(`board attach HTTP ${res.status}: ${body?.error ?? "unconfirmed result"}`);
|
|
1139
|
+
return body.itemId;
|
|
1140
|
+
}
|
|
1128
1141
|
var init_board_write = __esm({
|
|
1129
1142
|
"src/board-write.ts"() {
|
|
1130
1143
|
"use strict";
|
|
@@ -7288,37 +7301,71 @@ function pathWords(text) {
|
|
|
7288
7301
|
function proseWords(text) {
|
|
7289
7302
|
return text.toLowerCase().split(/[^a-z0-9]+/).filter(Boolean);
|
|
7290
7303
|
}
|
|
7304
|
+
function countWords(words) {
|
|
7305
|
+
const counts = /* @__PURE__ */ new Map();
|
|
7306
|
+
for (const w of words) counts.set(w, (counts.get(w) ?? 0) + 1);
|
|
7307
|
+
return counts;
|
|
7308
|
+
}
|
|
7309
|
+
var TITLE_WEIGHT = 3;
|
|
7310
|
+
var PATH_WEIGHT = 4;
|
|
7311
|
+
var BODY_WEIGHT = 1;
|
|
7291
7312
|
function inferSurface(candidates, context = {}) {
|
|
7292
7313
|
const sorted = [...candidates].sort();
|
|
7293
7314
|
if (sorted.length === 0) throw new Error("inferSurface: no surface:* candidates to choose from");
|
|
7294
|
-
const
|
|
7295
|
-
const
|
|
7315
|
+
const titleCounts = countWords(proseWords([context.title ?? "", context.type ?? ""].join(" ")));
|
|
7316
|
+
const pathCounts = countWords(pathWords(context.body ?? ""));
|
|
7317
|
+
const bodyCounts = countWords(proseWords(context.body ?? ""));
|
|
7318
|
+
const scoreOf = (label) => {
|
|
7319
|
+
let score = 0;
|
|
7320
|
+
let fromPath = false;
|
|
7321
|
+
let fromTitle = false;
|
|
7322
|
+
for (const word of surfaceWords(label)) {
|
|
7323
|
+
const title = titleCounts.get(word) ?? 0;
|
|
7324
|
+
const path2 = pathCounts.get(word) ?? 0;
|
|
7325
|
+
const body = bodyCounts.get(word) ?? 0;
|
|
7326
|
+
if (title > 0) fromTitle = true;
|
|
7327
|
+
if (path2 > 0) fromPath = true;
|
|
7328
|
+
score += title * TITLE_WEIGHT + path2 * PATH_WEIGHT + body * BODY_WEIGHT;
|
|
7329
|
+
}
|
|
7330
|
+
return { score, fromPath, fromTitle };
|
|
7331
|
+
};
|
|
7296
7332
|
let best = sorted[0];
|
|
7297
7333
|
let bestScore = 0;
|
|
7298
7334
|
let bestFromPath = false;
|
|
7335
|
+
let bestFromTitle = false;
|
|
7336
|
+
const scores = /* @__PURE__ */ new Map();
|
|
7299
7337
|
for (const label of sorted) {
|
|
7300
|
-
const
|
|
7301
|
-
|
|
7302
|
-
const pathHits = words.filter((w) => pWords.has(w)).length;
|
|
7303
|
-
const proseHits = words.filter((w) => tWords.has(w)).length;
|
|
7304
|
-
const score = pathHits * 2 + proseHits;
|
|
7338
|
+
const { score, fromPath, fromTitle } = scoreOf(label);
|
|
7339
|
+
scores.set(label, score);
|
|
7305
7340
|
if (score > bestScore) {
|
|
7306
7341
|
bestScore = score;
|
|
7307
7342
|
best = label;
|
|
7308
|
-
bestFromPath =
|
|
7343
|
+
bestFromPath = fromPath;
|
|
7344
|
+
bestFromTitle = fromTitle;
|
|
7309
7345
|
}
|
|
7310
7346
|
}
|
|
7311
|
-
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
};
|
|
7316
|
-
}
|
|
7347
|
+
const tied = sorted.filter((label) => (scores.get(label) ?? 0) === bestScore);
|
|
7348
|
+
const uncertain = bestScore === 0 || bestScore < TITLE_WEIGHT || tied.length > 1;
|
|
7349
|
+
const alternatives = uncertain ? sorted.filter((label) => label !== best && (scores.get(label) ?? 0) > 0).sort((a, b) => (scores.get(b) ?? 0) - (scores.get(a) ?? 0) || (a < b ? -1 : a > b ? 1 : 0)).slice(0, 3) : [];
|
|
7350
|
+
const reason = bestScore === 0 ? `no path or title/body word matched any of ${sorted.length} surface label(s) \u2014 defaulted to the alphabetically-first` : bestFromPath ? "matched a path mentioned in the issue body" : bestFromTitle ? "matched a word in the issue title/body" : "matched a word in the issue body";
|
|
7317
7351
|
return {
|
|
7318
7352
|
label: best,
|
|
7319
|
-
reason
|
|
7353
|
+
reason,
|
|
7354
|
+
...uncertain ? { uncertain: true } : {},
|
|
7355
|
+
...alternatives.length ? { alternatives } : {}
|
|
7320
7356
|
};
|
|
7321
7357
|
}
|
|
7358
|
+
function surfaceInferenceSuffix(inferred) {
|
|
7359
|
+
if (!inferred.uncertain) return "";
|
|
7360
|
+
const alts = inferred.alternatives?.length ? ` Other candidates: ${inferred.alternatives.join(", ")}.` : "";
|
|
7361
|
+
return ` This pick is low-confidence \u2014 pass --surface <value> to choose explicitly.${alts}`;
|
|
7362
|
+
}
|
|
7363
|
+
function surfaceInferenceNote(inferred) {
|
|
7364
|
+
const base = `mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}).`;
|
|
7365
|
+
return inferred.uncertain ? `${base}${surfaceInferenceSuffix(inferred)}
|
|
7366
|
+
` : `${base} Pass --surface to choose.
|
|
7367
|
+
`;
|
|
7368
|
+
}
|
|
7322
7369
|
async function checkSurfaceRequirement(input, deps = {}) {
|
|
7323
7370
|
if (input.waiver) {
|
|
7324
7371
|
const reason = input.waiver.reason.trim();
|
|
@@ -7350,7 +7397,7 @@ async function checkSurfaceRequirement(input, deps = {}) {
|
|
|
7350
7397
|
}
|
|
7351
7398
|
if (known.length === 0) return { enforcing: false, taxonomyAbsent: true };
|
|
7352
7399
|
if (labelsCarrySurface(input.labels)) return { enforcing: true };
|
|
7353
|
-
return { enforcing: true, inferred: inferSurface(known, { title: input.title, body: input.body }) };
|
|
7400
|
+
return { enforcing: true, inferred: inferSurface(known, { title: input.title, type: input.type, body: input.body }) };
|
|
7354
7401
|
}
|
|
7355
7402
|
function conflictingSurfaceInputs(surfaceFlag, labels) {
|
|
7356
7403
|
if (!surfaceFlag) return void 0;
|
|
@@ -11114,11 +11161,24 @@ mutation($projectId: ID!, $itemId: ID!) {
|
|
|
11114
11161
|
async function updateItemSingleSelect(client, projectId, itemId, fieldId, optionId) {
|
|
11115
11162
|
try {
|
|
11116
11163
|
await client.graphql(UPDATE_ITEM_FIELD_MUTATION, { projectId, itemId, fieldId, optionId });
|
|
11164
|
+
return { credential: "user" };
|
|
11117
11165
|
} catch (error) {
|
|
11118
11166
|
const errors = error.graphqlErrors;
|
|
11119
|
-
if (
|
|
11120
|
-
|
|
11121
|
-
|
|
11167
|
+
if (errors?.length && errors.every((entry) => entry.type === "INSUFFICIENT_SCOPES")) {
|
|
11168
|
+
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
11169
|
+
await writeHubBoardField2({ projectId, itemId, fieldId, optionId });
|
|
11170
|
+
return { credential: "app_installation" };
|
|
11171
|
+
}
|
|
11172
|
+
if (isGitHubRateLimitError(error)) {
|
|
11173
|
+
const { writeHubBoardField: writeHubBoardField2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
11174
|
+
try {
|
|
11175
|
+
await writeHubBoardField2({ projectId, itemId, fieldId, optionId });
|
|
11176
|
+
return { credential: "app_installation" };
|
|
11177
|
+
} catch {
|
|
11178
|
+
throw error;
|
|
11179
|
+
}
|
|
11180
|
+
}
|
|
11181
|
+
throw error;
|
|
11122
11182
|
}
|
|
11123
11183
|
}
|
|
11124
11184
|
function parseIssueSelector(selector, defaultRepo, expectedRepo) {
|
|
@@ -12361,8 +12421,9 @@ async function moveBoardItem(options, deps = {}) {
|
|
|
12361
12421
|
throw boardNotFoundError(`${selector.repo}#${selector.number}`, { owner: cfg.projectOwner, number: cfg.projectNumber });
|
|
12362
12422
|
}
|
|
12363
12423
|
const optionId = cfg.statusOptions[options.status];
|
|
12424
|
+
let credential = "user";
|
|
12364
12425
|
try {
|
|
12365
|
-
await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId);
|
|
12426
|
+
({ credential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId));
|
|
12366
12427
|
} catch (e) {
|
|
12367
12428
|
if (options.status === "Done" && isArchivedItemRefusal(ghError(e))) {
|
|
12368
12429
|
return {
|
|
@@ -12384,7 +12445,9 @@ async function moveBoardItem(options, deps = {}) {
|
|
|
12384
12445
|
viewer: lookup.viewer,
|
|
12385
12446
|
repo: currentRepo,
|
|
12386
12447
|
status: options.status,
|
|
12387
|
-
partial: false
|
|
12448
|
+
partial: false,
|
|
12449
|
+
credential
|
|
12450
|
+
// #6834: which credential served the write — the user token or the Hub App leg.
|
|
12388
12451
|
};
|
|
12389
12452
|
}
|
|
12390
12453
|
async function resolveClaimWritable(collected, client, snapshot, unscanned) {
|
|
@@ -12550,8 +12613,9 @@ async function claimOneBoardItem(ctx, selector, options) {
|
|
|
12550
12613
|
throw new Error(`claim failed before board status changed: ${ghError(e)}`);
|
|
12551
12614
|
}
|
|
12552
12615
|
await postClaimMarkerComment(client, item, ctx.session);
|
|
12616
|
+
let credential = "user";
|
|
12553
12617
|
try {
|
|
12554
|
-
await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, cfg.statusOptions["In Progress"]);
|
|
12618
|
+
({ credential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, cfg.statusOptions["In Progress"]));
|
|
12555
12619
|
} catch (e) {
|
|
12556
12620
|
const warning = `partial claim: ${item.ref} was assigned to @${assignedLogin}, but Status was not moved to In Progress (${ghError(e)})`;
|
|
12557
12621
|
if (!options.allowPartial) throw new Error(warning);
|
|
@@ -12568,6 +12632,7 @@ async function claimOneBoardItem(ctx, selector, options) {
|
|
|
12568
12632
|
repo: report.repo,
|
|
12569
12633
|
status: "In Progress",
|
|
12570
12634
|
partial: false,
|
|
12635
|
+
credential,
|
|
12571
12636
|
...claimedReceipt()
|
|
12572
12637
|
};
|
|
12573
12638
|
}
|
|
@@ -12601,7 +12666,7 @@ async function claimBoardIssues(options, deps = {}) {
|
|
|
12601
12666
|
const ref = `${selector.repo}#${selector.number}`;
|
|
12602
12667
|
try {
|
|
12603
12668
|
const result = await claimOneBoardItem(ctx, selector, { ...options, bulk: true });
|
|
12604
|
-
results[index] = { ref: result.item.ref, claimed: true, item: result.item, status: result.status, partial: result.partial, warning: result.warning, outcome: result.outcome, holder: result.holder, previousHolder: result.previousHolder, resumeEvidence: result.resumeEvidence, reclaimedFrom: result.reclaimedFrom, alreadyClaimed: result.alreadyClaimed, renewed: result.renewed, checked: result.checked };
|
|
12669
|
+
results[index] = { ref: result.item.ref, claimed: true, item: result.item, status: result.status, partial: result.partial, warning: result.warning, outcome: result.outcome, holder: result.holder, previousHolder: result.previousHolder, resumeEvidence: result.resumeEvidence, reclaimedFrom: result.reclaimedFrom, alreadyClaimed: result.alreadyClaimed, renewed: result.renewed, checked: result.checked, credential: result.credential };
|
|
12605
12670
|
} catch (e) {
|
|
12606
12671
|
results[index] = { ref, claimed: false, reason: e.message };
|
|
12607
12672
|
}
|
|
@@ -12661,13 +12726,14 @@ async function moveBoardIssues(options, deps = {}) {
|
|
|
12661
12726
|
const idx = next++;
|
|
12662
12727
|
const { item, ref, index: resultIdx } = resolvedList[idx];
|
|
12663
12728
|
try {
|
|
12664
|
-
await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, statusOptionId);
|
|
12729
|
+
const { credential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, statusOptionId);
|
|
12665
12730
|
results[resultIdx] = {
|
|
12666
12731
|
ref,
|
|
12667
12732
|
moved: true,
|
|
12668
12733
|
item: { ...item, status: options.status, statusOptionId },
|
|
12669
12734
|
status: options.status,
|
|
12670
|
-
partial: false
|
|
12735
|
+
partial: false,
|
|
12736
|
+
credential
|
|
12671
12737
|
};
|
|
12672
12738
|
} catch (e) {
|
|
12673
12739
|
const warning = `partial move: ${ref} status was not changed to ${options.status} (${ghError(e)})`;
|
|
@@ -12734,8 +12800,9 @@ async function unclaimBoardIssue(options, deps = {}) {
|
|
|
12734
12800
|
return { item, viewer, repo: currentRepo, status: item.status, partial: true, warning };
|
|
12735
12801
|
}
|
|
12736
12802
|
const optionId = cfg.statusOptions[toStatus];
|
|
12803
|
+
let unclaimCredential = "user";
|
|
12737
12804
|
try {
|
|
12738
|
-
await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId);
|
|
12805
|
+
({ credential: unclaimCredential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId));
|
|
12739
12806
|
} catch (e) {
|
|
12740
12807
|
const warning = `partial unclaim: ${item.ref} status was not changed to ${toStatus} (${ghError(e)})`;
|
|
12741
12808
|
if (!options.allowPartial) throw new Error(warning);
|
|
@@ -12746,7 +12813,8 @@ async function unclaimBoardIssue(options, deps = {}) {
|
|
|
12746
12813
|
viewer,
|
|
12747
12814
|
repo: currentRepo,
|
|
12748
12815
|
status: toStatus,
|
|
12749
|
-
partial: false
|
|
12816
|
+
partial: false,
|
|
12817
|
+
credential: unclaimCredential
|
|
12750
12818
|
};
|
|
12751
12819
|
}
|
|
12752
12820
|
async function setBoardItemPriority(client, cfg, itemId, priority) {
|
|
@@ -15870,10 +15938,10 @@ var rollout_plan_default = {
|
|
|
15870
15938
|
note: "The v4.0.0 stamp happens at cut time (D6e #4463); until then the candidate is the origin/development head artifacts (built cli/dist + npm pack), identity proven by dist content hash (D6a)."
|
|
15871
15939
|
},
|
|
15872
15940
|
baseline: {
|
|
15873
|
-
version: "4.4.
|
|
15874
|
-
tag: "v4.4.
|
|
15875
|
-
commit: "
|
|
15876
|
-
npm: "@mutmutco/cli@4.4.
|
|
15941
|
+
version: "4.4.7",
|
|
15942
|
+
tag: "v4.4.7",
|
|
15943
|
+
commit: "f0781ed0cbda",
|
|
15944
|
+
npm: "@mutmutco/cli@4.4.7"
|
|
15877
15945
|
},
|
|
15878
15946
|
exitCriterion: "fleet-n-of-n",
|
|
15879
15947
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15890,14 +15958,14 @@ var rollout_plan_default = {
|
|
|
15890
15958
|
repo: "mutmutco/mmi-hub",
|
|
15891
15959
|
role: "canary",
|
|
15892
15960
|
schedule: "train",
|
|
15893
|
-
v3Target: "v4.4.
|
|
15961
|
+
v3Target: "v4.4.7"
|
|
15894
15962
|
}
|
|
15895
15963
|
],
|
|
15896
15964
|
rollbackTrigger: "Any red inside the post-contract soak window: `devops train gate` FAIL attributable to the v4 doors, Hub endpoint health probe failure, a pre-v4 client admitted instead of receiving actionable HTTP 426, or npm consumer install/doctor failure on the v4-only dist.",
|
|
15897
15965
|
rollback: {
|
|
15898
15966
|
independent: true,
|
|
15899
|
-
mechanism: "npm dist-tag latest -> 4.4.
|
|
15900
|
-
v3Target: "v4.4.
|
|
15967
|
+
mechanism: "npm dist-tag latest -> 4.4.7 and redeploy the Hub Lambda from tag v4.4.7 (f0781ed0cbda); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15968
|
+
v3Target: "v4.4.7 (@mutmutco/cli@4.4.7, tag commit f0781ed0cbda \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15901
15969
|
}
|
|
15902
15970
|
},
|
|
15903
15971
|
{
|
|
@@ -22814,6 +22882,62 @@ async function waitForFoldIndexLock(deps, startBranch, resumeCommand) {
|
|
|
22814
22882
|
await sleep2(Math.min(GIT_INDEX_LOCK_POLL_MS, Math.max(1, deadline - now())));
|
|
22815
22883
|
}
|
|
22816
22884
|
}
|
|
22885
|
+
function isIndexLockFailure(message2) {
|
|
22886
|
+
return /index\.lock/i.test(message2) && /File exists/i.test(message2);
|
|
22887
|
+
}
|
|
22888
|
+
async function clearFoldChildIndexLock(deps) {
|
|
22889
|
+
const lockPath = requireValue(
|
|
22890
|
+
clean2(await deps.run("git", ["rev-parse", "--git-path", "index.lock"])),
|
|
22891
|
+
"git index lock path"
|
|
22892
|
+
);
|
|
22893
|
+
try {
|
|
22894
|
+
await (0, import_promises3.unlink)(lockPath);
|
|
22895
|
+
} catch (e) {
|
|
22896
|
+
if (e.code === "ENOENT") return void 0;
|
|
22897
|
+
throw e;
|
|
22898
|
+
}
|
|
22899
|
+
return lockPath;
|
|
22900
|
+
}
|
|
22901
|
+
async function resetFoldMainWithStaleLockRetry(deps, preFoldMainSha, killedCause) {
|
|
22902
|
+
try {
|
|
22903
|
+
await deps.run("git", ["reset", "--hard", preFoldMainSha]);
|
|
22904
|
+
return { ok: true, lockNote: "" };
|
|
22905
|
+
} catch (firstError) {
|
|
22906
|
+
const firstMessage = firstError instanceof Error ? firstError.message : String(firstError);
|
|
22907
|
+
if (!isIndexLockFailure(firstMessage)) return { ok: false, error: firstError, lockNote: "" };
|
|
22908
|
+
if (!foldChildWasKilled(killedCause)) {
|
|
22909
|
+
return {
|
|
22910
|
+
ok: false,
|
|
22911
|
+
error: firstError,
|
|
22912
|
+
lockNote: "the git index lock was NOT removed \u2014 no killed fold child is attributable, so its holder may still be alive (resolve or wait it out, then retry)"
|
|
22913
|
+
};
|
|
22914
|
+
}
|
|
22915
|
+
let clearedLockPath;
|
|
22916
|
+
try {
|
|
22917
|
+
clearedLockPath = await clearFoldChildIndexLock(deps);
|
|
22918
|
+
} catch (e) {
|
|
22919
|
+
return {
|
|
22920
|
+
ok: false,
|
|
22921
|
+
error: firstError,
|
|
22922
|
+
lockNote: `the fold child's stale git index lock could not be removed: ${e instanceof Error ? e.message : String(e)}`
|
|
22923
|
+
};
|
|
22924
|
+
}
|
|
22925
|
+
if (!clearedLockPath) return { ok: false, error: firstError, lockNote: "" };
|
|
22926
|
+
try {
|
|
22927
|
+
await deps.run("git", ["reset", "--hard", preFoldMainSha]);
|
|
22928
|
+
return {
|
|
22929
|
+
ok: true,
|
|
22930
|
+
lockNote: `removed the stale git index lock ${clearedLockPath} left by the fold child the train killed (signal), then retried the reset`
|
|
22931
|
+
};
|
|
22932
|
+
} catch (retryError) {
|
|
22933
|
+
return {
|
|
22934
|
+
ok: false,
|
|
22935
|
+
error: retryError,
|
|
22936
|
+
lockNote: `removed the stale git index lock ${clearedLockPath} left by the fold child the train killed (signal) and retried the reset once, which failed again`
|
|
22937
|
+
};
|
|
22938
|
+
}
|
|
22939
|
+
}
|
|
22940
|
+
}
|
|
22817
22941
|
async function recoverFailedRcand(deps, cause, preRcSha) {
|
|
22818
22942
|
const causeMessage = cause instanceof Error ? cause.message : String(cause);
|
|
22819
22943
|
const branch = await currentBranch(deps).catch(() => "");
|
|
@@ -22857,10 +22981,13 @@ Recovery sequence:
|
|
|
22857
22981
|
3. mmi-cli devops rcand --apply`
|
|
22858
22982
|
);
|
|
22859
22983
|
}
|
|
22984
|
+
function foldChildWasKilled(causeMessage) {
|
|
22985
|
+
return /\bSIGTERM\b|was killed \(signal/.test(causeMessage);
|
|
22986
|
+
}
|
|
22860
22987
|
function foldFailureAnchor(causeMessage) {
|
|
22861
|
-
if (
|
|
22862
|
-
if (/\bEPERM\b|\bEBUSY\b/.test(causeMessage)) return "
|
|
22863
|
-
if (/^(?:npm|node) .* failed\b/.test(causeMessage)) return "
|
|
22988
|
+
if (foldChildWasKilled(causeMessage)) return troubleshootingAnchor("fold-npm-ci-sigterm");
|
|
22989
|
+
if (/\bEPERM\b|\bEBUSY\b/.test(causeMessage)) return troubleshootingAnchor("fold-eperm-ebusy");
|
|
22990
|
+
if (/^(?:npm|node) .* failed\b/.test(causeMessage)) return troubleshootingAnchor("fold-lifecycle-script");
|
|
22864
22991
|
return void 0;
|
|
22865
22992
|
}
|
|
22866
22993
|
async function recoverFailedFold(deps, cause, startBranch, preFoldMainSha, resumeCommand) {
|
|
@@ -22889,13 +23016,12 @@ fold failed with an in-progress merge; automatic \`git merge --abort\` failed: $
|
|
|
22889
23016
|
if (probe.branch === "main" && preFoldMainSha) {
|
|
22890
23017
|
const mainDescendsFromPreFold = await deps.run("git", ["merge-base", "--is-ancestor", preFoldMainSha, "main"]).then(() => true).catch(() => false);
|
|
22891
23018
|
if (mainDescendsFromPreFold) {
|
|
22892
|
-
|
|
22893
|
-
|
|
22894
|
-
} catch (e) {
|
|
23019
|
+
const attempt = await resetFoldMainWithStaleLockRetry(deps, preFoldMainSha, rawCause);
|
|
23020
|
+
if (!attempt.ok) {
|
|
22895
23021
|
return foldFailureGuidance(
|
|
22896
23022
|
`${causeMessage}
|
|
22897
23023
|
|
|
22898
|
-
fold failed after this run's merge/fold committed locally on main; automatic \`git reset --hard ${shaLabel(preFoldMainSha)}\` failed: ${
|
|
23024
|
+
fold failed after this run's merge/fold committed locally on main; automatic \`git reset --hard ${shaLabel(preFoldMainSha)}\` failed: ${attempt.error instanceof Error ? attempt.error.message : String(attempt.error)}${attempt.lockNote ? `; ${attempt.lockNote}` : ""}.`,
|
|
22899
23025
|
await probeFoldFailureState(deps),
|
|
22900
23026
|
startBranch,
|
|
22901
23027
|
preFoldMainSha,
|
|
@@ -22910,7 +23036,7 @@ fold failed after this run's merge/fold committed locally on main; automatic \`g
|
|
|
22910
23036
|
startBranch,
|
|
22911
23037
|
preFoldMainSha,
|
|
22912
23038
|
resumeCommand,
|
|
22913
|
-
`local main was reset to its pre-fold state ${shaLabel(preFoldMainSha)} (discarding only this run's merge/fold commit(s) at ${shaLabel(probe.mainSha)})${aheadNote}`
|
|
23039
|
+
`local main was reset to its pre-fold state ${shaLabel(preFoldMainSha)} (discarding only this run's merge/fold commit(s) at ${shaLabel(probe.mainSha)})${attempt.lockNote ? `; ${attempt.lockNote}` : ""}${aheadNote}`
|
|
22914
23040
|
);
|
|
22915
23041
|
}
|
|
22916
23042
|
}
|
|
@@ -33529,10 +33655,10 @@ function formatOwnDetail(cmd) {
|
|
|
33529
33655
|
}
|
|
33530
33656
|
lines2.push("");
|
|
33531
33657
|
}
|
|
33532
|
-
const
|
|
33533
|
-
if (
|
|
33658
|
+
const ownOptions2 = cmd.options.filter((opt) => opt.flags !== "--help" && opt.flags !== "-V, --version");
|
|
33659
|
+
if (ownOptions2.length) {
|
|
33534
33660
|
lines2.push("Options:");
|
|
33535
|
-
for (const opt of
|
|
33661
|
+
for (const opt of ownOptions2) {
|
|
33536
33662
|
const tags = [];
|
|
33537
33663
|
if (opt.mandatory) tags.push("required");
|
|
33538
33664
|
if (opt.default !== void 0) tags.push(`default: ${JSON.stringify(opt.default)}`);
|
|
@@ -33594,6 +33720,56 @@ function formatExplainLoop(playbook) {
|
|
|
33594
33720
|
}
|
|
33595
33721
|
return lines2.join("\n");
|
|
33596
33722
|
}
|
|
33723
|
+
function ownOptions(cmd) {
|
|
33724
|
+
return cmd.options.filter((opt) => opt.flags !== "--help" && opt.flags !== "-V, --version");
|
|
33725
|
+
}
|
|
33726
|
+
function briefCommand(cmd) {
|
|
33727
|
+
return {
|
|
33728
|
+
path: cmd.path,
|
|
33729
|
+
...cmd.description ? { description: cmd.description } : {},
|
|
33730
|
+
arguments: cmd.arguments.map((arg) => ({
|
|
33731
|
+
name: arg.name,
|
|
33732
|
+
required: arg.required,
|
|
33733
|
+
...arg.variadic ? { variadic: true } : {},
|
|
33734
|
+
...arg.description ? { description: arg.description } : {}
|
|
33735
|
+
})),
|
|
33736
|
+
options: ownOptions(cmd).map((opt) => ({
|
|
33737
|
+
flags: opt.flags,
|
|
33738
|
+
takesValue: opt.takesValue,
|
|
33739
|
+
...opt.mandatory ? { required: true } : {},
|
|
33740
|
+
...opt.description ? { description: opt.description } : {}
|
|
33741
|
+
}))
|
|
33742
|
+
};
|
|
33743
|
+
}
|
|
33744
|
+
function explainBriefManifest(manifest, command) {
|
|
33745
|
+
return {
|
|
33746
|
+
schema_version: 1,
|
|
33747
|
+
scope: "command",
|
|
33748
|
+
brief: true,
|
|
33749
|
+
name: manifest.name,
|
|
33750
|
+
...manifest.version ? { version: manifest.version } : {},
|
|
33751
|
+
command: briefCommand(command),
|
|
33752
|
+
...command.subcommands.length ? { children: command.subcommands.map(briefCommand) } : {}
|
|
33753
|
+
};
|
|
33754
|
+
}
|
|
33755
|
+
function formatExplainBrief(cmd, rootName) {
|
|
33756
|
+
const lines2 = [`${rootName} ${cmd.path}${cmd.description ? ` \u2014 ${cmd.description}` : ""}`];
|
|
33757
|
+
for (const arg of cmd.arguments) {
|
|
33758
|
+
const flag = arg.required ? `<${arg.name}>` : `[${arg.name}]`;
|
|
33759
|
+
lines2.push(` ${flag} ${arg.required ? "required" : "optional"}${arg.description ? ` ${arg.description}` : ""}`);
|
|
33760
|
+
}
|
|
33761
|
+
for (const opt of ownOptions(cmd)) {
|
|
33762
|
+
lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
|
|
33763
|
+
}
|
|
33764
|
+
for (const child2 of cmd.subcommands) {
|
|
33765
|
+
const args = child2.arguments.map((arg) => arg.required ? `<${arg.name}>` : `[${arg.name}]`).join(" ");
|
|
33766
|
+
lines2.push(`${child2.path}${args ? ` ${args}` : ""}${child2.description ? ` \u2014 ${child2.description}` : ""}`);
|
|
33767
|
+
for (const opt of ownOptions(child2)) {
|
|
33768
|
+
lines2.push(` ${opt.flags} ${opt.takesValue ? "takes-value" : "flag"}${opt.mandatory ? " required" : ""}${opt.description ? ` ${opt.description}` : ""}`);
|
|
33769
|
+
}
|
|
33770
|
+
}
|
|
33771
|
+
return lines2.join("\n");
|
|
33772
|
+
}
|
|
33597
33773
|
function catalogCommandPaths(manifest) {
|
|
33598
33774
|
const acc = [];
|
|
33599
33775
|
const walk2 = (command) => {
|
|
@@ -33728,7 +33904,7 @@ function findCommandInManifest(manifest, commandPath3) {
|
|
|
33728
33904
|
return visit(manifest.tree);
|
|
33729
33905
|
}
|
|
33730
33906
|
function registerExplainCommand(program3) {
|
|
33731
|
-
program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").option("--out <path>", "write the output to a UTF-8 file instead of stdout (#5802 byte contract)").option("--recursive", "include full schemas for immediate children (default: compact child index)").option("--full", "alias for --recursive").action((commandArgs, opts) => {
|
|
33907
|
+
program3.command("explain").description("print a command's purpose, flags, and examples from the live schema \u2014 one grounding call replaces trial-and-error").argument("[command...]", 'the command path to explain (e.g. "issue create")').addOption(new Option("--loop <name>", "print the canonical command sequence: agent | start-work | ship-pr | hotfix").choices(Object.keys(LOOP_PLAYBOOKS))).option("--json", "machine-readable focused command, route, or loop detail").option("--brief", "compact per-verb flags, value requirements, and one-line descriptions (no schemas or prose)").option("--out <path>", "write the output to a UTF-8 file instead of stdout (#5802 byte contract)").option("--recursive", "include full schemas for immediate children (default: compact child index)").option("--full", "alias for --recursive").action((commandArgs, opts) => {
|
|
33732
33908
|
const emit = (output) => {
|
|
33733
33909
|
if (!opts.out) console.log(output);
|
|
33734
33910
|
else console.log(`Wrote explain output to ${opts.out} (UTF-8, ${writeUtf8Receipt(opts.out, output)} bytes)`);
|
|
@@ -33767,6 +33943,10 @@ function registerExplainCommand(program3) {
|
|
|
33767
33943
|
return;
|
|
33768
33944
|
}
|
|
33769
33945
|
const recursive = Boolean(opts.recursive || opts.full);
|
|
33946
|
+
if (opts.brief) {
|
|
33947
|
+
emit(opts.json ? JSON.stringify(explainBriefManifest(manifest, command), null, 2) : formatExplainBrief(command, manifest.name));
|
|
33948
|
+
return;
|
|
33949
|
+
}
|
|
33770
33950
|
emit(opts.json ? JSON.stringify(explainCommandManifest(manifest, command, { recursive }), null, 2) : command.subcommands.length ? formatExplainGroup(command, manifest.name) : formatExplainCommand(command, manifest.name));
|
|
33771
33951
|
});
|
|
33772
33952
|
}
|
|
@@ -34438,10 +34618,10 @@ async function preflightBatchSurfaces(validated, rowRepo, options) {
|
|
|
34438
34618
|
continue;
|
|
34439
34619
|
}
|
|
34440
34620
|
if (known.length === 0) continue;
|
|
34441
|
-
const inferred = inferSurface(known, { title: spec.title, body: spec.body });
|
|
34621
|
+
const inferred = inferSurface(known, { title: spec.title, type: spec.type, body: spec.body });
|
|
34442
34622
|
spec.labels = [...spec.labels ?? [], inferred.label];
|
|
34443
34623
|
process.stderr.write(
|
|
34444
|
-
`mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose
|
|
34624
|
+
`mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.${surfaceInferenceSuffix(inferred)}
|
|
34445
34625
|
`
|
|
34446
34626
|
);
|
|
34447
34627
|
}
|
|
@@ -37583,6 +37763,10 @@ function spawnDetachedSelf(args, deps, opts = {}) {
|
|
|
37583
37763
|
var import_node_path39 = require("node:path");
|
|
37584
37764
|
|
|
37585
37765
|
// src/attach-to-project.ts
|
|
37766
|
+
async function attachViaHubApp(cfg, contentNodeId) {
|
|
37767
|
+
const { addIssueToProjectViaHub: addIssueToProjectViaHub2 } = await Promise.resolve().then(() => (init_board_write(), board_write_exports));
|
|
37768
|
+
return addIssueToProjectViaHub2(cfg, contentNodeId);
|
|
37769
|
+
}
|
|
37586
37770
|
function boardAttachRateLimitedReceipt(resetEpochSeconds) {
|
|
37587
37771
|
return {
|
|
37588
37772
|
onBoard: false,
|
|
@@ -40625,7 +40809,7 @@ async function attachToProject(issueNumber, repo, priority) {
|
|
|
40625
40809
|
}
|
|
40626
40810
|
}
|
|
40627
40811
|
}
|
|
40628
|
-
return { projectItemId, onBoard: true };
|
|
40812
|
+
return { projectItemId, onBoard: true, credential: "user" };
|
|
40629
40813
|
} catch (e) {
|
|
40630
40814
|
const err = e;
|
|
40631
40815
|
const detail = (err.stderr || err.message || String(e)).trim();
|
|
@@ -40637,11 +40821,33 @@ async function attachToProject(issueNumber, repo, priority) {
|
|
|
40637
40821
|
{ repo: targetRepo2, number: issueNumber },
|
|
40638
40822
|
priority
|
|
40639
40823
|
);
|
|
40640
|
-
return { projectItemId, onBoard: true };
|
|
40824
|
+
return { projectItemId, onBoard: true, credential: "user" };
|
|
40641
40825
|
}
|
|
40642
40826
|
return { onBoard: true };
|
|
40643
40827
|
}
|
|
40644
40828
|
if (isRateLimitText(detail)) {
|
|
40829
|
+
if (targetRepo2) {
|
|
40830
|
+
try {
|
|
40831
|
+
const boardCfg = await loadConfigForRepo(targetRepo2);
|
|
40832
|
+
const viewArgs2 = ["issue", "view", String(issueNumber), "--json", "id", "--jq", ".id"];
|
|
40833
|
+
if (targetRepo2) viewArgs2.push("--repo", targetRepo2);
|
|
40834
|
+
const contentId2 = (await execFileP("gh", viewArgs2, { timeout: 1e4 })).stdout.trim();
|
|
40835
|
+
if (contentId2 && boardCfg.projectId) {
|
|
40836
|
+
const projectItemId = await attachViaHubApp(boardCfg, contentId2);
|
|
40837
|
+
if (priority) {
|
|
40838
|
+
try {
|
|
40839
|
+
await setBoardItemPriority(defaultGitHubClient(), boardCfg, projectItemId, priority);
|
|
40840
|
+
} catch (e2) {
|
|
40841
|
+
const err2 = e2;
|
|
40842
|
+
process.stderr.write(`warning: issue #${issueNumber} board Priority not set: ${(err2.stderr || err2.message || String(e2)).trim()}
|
|
40843
|
+
`);
|
|
40844
|
+
}
|
|
40845
|
+
}
|
|
40846
|
+
return { projectItemId, onBoard: true, credential: "app_installation" };
|
|
40847
|
+
}
|
|
40848
|
+
} catch {
|
|
40849
|
+
}
|
|
40850
|
+
}
|
|
40645
40851
|
process.stderr.write(`warning: issue #${issueNumber} created but board attach rate-limited: ${detail}
|
|
40646
40852
|
`);
|
|
40647
40853
|
let resetEpochSeconds;
|
|
@@ -40750,6 +40956,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40750
40956
|
repo: planRepo,
|
|
40751
40957
|
labels: [...planLabels, ...surface ? [surface] : []],
|
|
40752
40958
|
title,
|
|
40959
|
+
type,
|
|
40753
40960
|
body: opts.body
|
|
40754
40961
|
});
|
|
40755
40962
|
if (warn) process.stderr.write(`${warn}
|
|
@@ -40757,10 +40964,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40757
40964
|
if (refusal) fail(refusal.message, refusal.payload);
|
|
40758
40965
|
if (inferred && !surface) {
|
|
40759
40966
|
planInferred = inferred;
|
|
40760
|
-
process.stderr.write(
|
|
40761
|
-
`mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
|
|
40762
|
-
`
|
|
40763
|
-
);
|
|
40967
|
+
process.stderr.write(surfaceInferenceNote(inferred));
|
|
40764
40968
|
}
|
|
40765
40969
|
}
|
|
40766
40970
|
return {
|
|
@@ -40770,7 +40974,9 @@ function registerCollaborationCommands(program3) {
|
|
|
40770
40974
|
priority,
|
|
40771
40975
|
repo: opts.repo,
|
|
40772
40976
|
...surface ? { surface } : {},
|
|
40773
|
-
...planInferred ? { surface_inferred: true, surface: planInferred.label, surface_reason: planInferred.reason } : {}
|
|
40977
|
+
...planInferred ? { surface_inferred: true, surface: planInferred.label, surface_reason: planInferred.reason } : {},
|
|
40978
|
+
...planInferred?.uncertain ? { surface_uncertain: true } : {},
|
|
40979
|
+
...planInferred?.alternatives?.length ? { surface_alternatives: planInferred.alternatives } : {}
|
|
40774
40980
|
};
|
|
40775
40981
|
}
|
|
40776
40982
|
).action(async (o) => {
|
|
@@ -40814,7 +41020,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40814
41020
|
return fail(`issue create: ${e.message}`, e instanceof TextArgError ? { code: e.code, offending_flag: e.offendingFlag } : void 0);
|
|
40815
41021
|
}
|
|
40816
41022
|
{
|
|
40817
|
-
const surfaceCheck = await checkSurfaceRequirement({ repo: targetRepo2, labels: extraLabels, title, body });
|
|
41023
|
+
const surfaceCheck = await checkSurfaceRequirement({ repo: targetRepo2, labels: extraLabels, title, type: issueType, body });
|
|
40818
41024
|
const { refusal, warn, inferred } = surfaceCheck;
|
|
40819
41025
|
if (warn) process.stderr.write(`${warn}
|
|
40820
41026
|
`);
|
|
@@ -40844,10 +41050,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40844
41050
|
labels: extraLabels.length ? extraLabels : void 0
|
|
40845
41051
|
});
|
|
40846
41052
|
surfaceInferred = inferred;
|
|
40847
|
-
process.stderr.write(
|
|
40848
|
-
`mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
|
|
40849
|
-
`
|
|
40850
|
-
);
|
|
41053
|
+
process.stderr.write(surfaceInferenceNote(inferred));
|
|
40851
41054
|
}
|
|
40852
41055
|
if (refusal && !surfaceWaived()) return fail(refusal.message, refusal.payload);
|
|
40853
41056
|
}
|
|
@@ -40859,7 +41062,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40859
41062
|
return;
|
|
40860
41063
|
}
|
|
40861
41064
|
const attached = await attachToProject(created.number, targetRepo2, priority);
|
|
40862
|
-
const { projectItemId, onBoard } = attached;
|
|
41065
|
+
const { projectItemId, onBoard, credential: attachCredential } = attached;
|
|
40863
41066
|
let parent;
|
|
40864
41067
|
let parentLinkError;
|
|
40865
41068
|
if (o.parent !== void 0) {
|
|
@@ -40879,6 +41082,7 @@ function registerCollaborationCommands(program3) {
|
|
|
40879
41082
|
priority,
|
|
40880
41083
|
projectItemId,
|
|
40881
41084
|
onBoard,
|
|
41085
|
+
...attachCredential ? { credential: attachCredential } : {},
|
|
40882
41086
|
// #5489: partial receipt when the GitHub issue landed but Project v2 attach hit GraphQL quota.
|
|
40883
41087
|
...attached.boardAttach ? {
|
|
40884
41088
|
boardAttach: attached.boardAttach,
|
|
@@ -40887,7 +41091,10 @@ function registerCollaborationCommands(program3) {
|
|
|
40887
41091
|
} : {},
|
|
40888
41092
|
...parentLinkFields(parent, parentLinkError),
|
|
40889
41093
|
// #1164: surfaced so a caller can see (and override with --surface) a pick it never asked for.
|
|
40890
|
-
...surfaceInferred ? { surface_inferred: true, surface: surfaceInferred.label, surface_reason: surfaceInferred.reason } : {}
|
|
41094
|
+
...surfaceInferred ? { surface_inferred: true, surface: surfaceInferred.label, surface_reason: surfaceInferred.reason } : {},
|
|
41095
|
+
// #6818: a weak/ambiguous pick says so, with its runner-ups, so the caller can pass --surface.
|
|
41096
|
+
...surfaceInferred?.uncertain ? { surface_uncertain: true } : {},
|
|
41097
|
+
...surfaceInferred?.alternatives?.length ? { surface_alternatives: surfaceInferred.alternatives } : {}
|
|
40891
41098
|
}));
|
|
40892
41099
|
}), [
|
|
40893
41100
|
'mmi-cli oracle issue create --type task --title "Wire the schema"',
|
|
@@ -41511,10 +41718,21 @@ ${list}`);
|
|
|
41511
41718
|
return cwdRepo?.toLowerCase() === repo.split("/").slice(-2).join("/").toLowerCase();
|
|
41512
41719
|
}
|
|
41513
41720
|
async function prLandUpdateBranch(prNumber, repo, explicitRepo) {
|
|
41514
|
-
|
|
41515
|
-
|
|
41516
|
-
|
|
41517
|
-
|
|
41721
|
+
let head = "";
|
|
41722
|
+
let base = "";
|
|
41723
|
+
const rested = await fetchRestPrSnapshot(prNumber, repo).catch(() => void 0);
|
|
41724
|
+
if (rested && rested.headRef && rested.baseRef) {
|
|
41725
|
+
console.warn("pr land: PR head/base read via REST (App-capable poll identity) instead of gh GraphQL (#6834).");
|
|
41726
|
+
head = rested.headRef;
|
|
41727
|
+
base = rested.baseRef;
|
|
41728
|
+
} else {
|
|
41729
|
+
const viewed = JSON.parse((await execFileP("gh", ["pr", "view", prNumber, "--repo", repo, "--json", "headRefName,baseRefName"], { timeout: GC_GH_TIMEOUT_MS4 })).stdout);
|
|
41730
|
+
head = viewed.headRefName;
|
|
41731
|
+
base = viewed.baseRefName;
|
|
41732
|
+
}
|
|
41733
|
+
const localCheckedOut = await prHeadCheckedOutHere(head, repo, explicitRepo);
|
|
41734
|
+
console.warn(`pr land: PR #${prNumber} is BEHIND ${base} \u2014 updating ${head} from the base (${localCheckedOut ? "local merge commit + push" : "GitHub update-branch"}) and re-waiting the checks once (#6263).`);
|
|
41735
|
+
return updatePrHeadForMerge({ prNumber, repo, head, base, localCheckedOut });
|
|
41518
41736
|
}
|
|
41519
41737
|
class PrHeadBehindBaseError extends Error {
|
|
41520
41738
|
}
|
|
@@ -41555,9 +41773,22 @@ ${list}`);
|
|
|
41555
41773
|
if (landClosingGuardVerdict.message) console.warn(landClosingGuardVerdict.message);
|
|
41556
41774
|
const result = await runPrLand(number, { repo: o.repo, requireTrain: o.requireTrain !== false }, {
|
|
41557
41775
|
resolveRepo: async (prNumber, repoOpt) => {
|
|
41558
|
-
const
|
|
41559
|
-
|
|
41560
|
-
|
|
41776
|
+
const knownRepo = repoOpt ?? await resolveRepo(o.repo).catch(() => void 0) ?? o.repo;
|
|
41777
|
+
let repoFromGh = "";
|
|
41778
|
+
let base = "";
|
|
41779
|
+
if (knownRepo) {
|
|
41780
|
+
const rested = await fetchRestPrSnapshot(prNumber, knownRepo).catch(() => void 0);
|
|
41781
|
+
if (rested) {
|
|
41782
|
+
console.warn("pr land: PR repo/base read via REST (App-capable poll identity) instead of gh GraphQL (#6834).");
|
|
41783
|
+
repoFromGh = knownRepo;
|
|
41784
|
+
base = rested.baseRef;
|
|
41785
|
+
}
|
|
41786
|
+
}
|
|
41787
|
+
if (!repoFromGh || !base) {
|
|
41788
|
+
const args = repoOpt ? ["--repo", repoOpt] : repoArgs;
|
|
41789
|
+
const viewed = (await execFileP("gh", ["pr", "view", prNumber, ...args, "--json", "headRepository,baseRefName", "--jq", '.headRepository.nameWithOwner + " " + .baseRefName'], { timeout: GC_GH_TIMEOUT_MS4 })).stdout.trim();
|
|
41790
|
+
[repoFromGh, base] = viewed.split(/\s+/);
|
|
41791
|
+
}
|
|
41561
41792
|
const repo = repoOpt ?? repoFromGh;
|
|
41562
41793
|
if (!repo) throw new Error("pr land: could not resolve PR repo");
|
|
41563
41794
|
let track;
|
|
@@ -41683,8 +41914,9 @@ ${list}`);
|
|
|
41683
41914
|
console.error(line);
|
|
41684
41915
|
}
|
|
41685
41916
|
}
|
|
41686
|
-
|
|
41687
|
-
|
|
41917
|
+
const credential = await pollToken().catch(() => void 0) ? "app_installation" : "user";
|
|
41918
|
+
if (o.json) printLine(JSON.stringify({ ...result, credential }));
|
|
41919
|
+
else printLine(`pr land: ${result.status}${result.error ? ` \u2014 ${result.error}` : ""} (credential: ${credential})`);
|
|
41688
41920
|
if (result.status === "failed") process.exitCode = 1;
|
|
41689
41921
|
});
|
|
41690
41922
|
jsonParity(pr.command("merge <number>").description("merge a PR (squash by default); archives gitignored tmp/** before worktree teardown; on no-ci repos run pr ci-policy / checks-wait first (#1432, #5679)").option("--squash", "squash merge (default)").option("--merge", "create a merge commit").option("--rebase", "rebase merge").option("--repo <owner/repo>", "target repo (defaults to the current repo); from a foreign checkout the remote probe/delete address this repo and local cleanup runs only in the verified sibling checkout ../<repo>, else localBranch reports skipped-foreign-cwd and the receipt carries foreignCwd: true (#6148)").option("--auto", "enable auto-merge \u2014 merge once the base-branch policy is satisfied (use for policy-gated repos)").addOption(new Option("--disable-auto", "disable a queued auto-merge without merging").conflicts(["auto", "wait", "squash", "merge", "rebase", "preserveWorktree", "gc", "squashBodyFile", "force"])).option("--wait", `wait for checks to reach a terminal passing verdict before merging (default budget ${PR_CHECKS_TIMEOUT_MS / 6e4}m) \u2014 run as a background/monitor task or under a shell timeout above that budget; a short foreground timeout (e.g. 120s) kills it after checks pass and leaves the PR open (#6027)`).option("--preserve-worktree", "after merge, keep the local PR worktree/branch for an active batch (#1888); also the merge settings-proof bypass when delete_branch_on_merge cannot be proven (#6210)").option("--gc", "acknowledge deleting unarchived gitignored tmp/** evidence newer than the branch base (#5679)").option("--squash-body-file <path>", "squash commit body (overrides GitHub COMMIT_MESSAGES); use when a pushed commit mentions close/fix/resolve + #N that must not close (#5723)").option("--force", "acknowledge and merge past a remaining prunable/severe scratch housekeeping block (advisory kept plans/ never blocks, #3012) or a negated-closing-keyword (#3718) or ambiguous-cross-repo-closing (#4279) refusal").option("--without-review <reason>", "compatibility option; shared merge helpers do not require a review verdict")).action(async (number, o) => {
|
package/package.json
CHANGED