@mutmutco/cli 4.5.16 → 4.5.18
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 +204 -31
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -7401,6 +7401,18 @@ function surfaceInferenceSuffix(inferred) {
|
|
|
7401
7401
|
const alts = inferred.alternatives?.length ? ` Other candidates: ${inferred.alternatives.join(", ")}.` : "";
|
|
7402
7402
|
return ` This pick is low-confidence \u2014 pass --surface <value> to choose explicitly.${alts}`;
|
|
7403
7403
|
}
|
|
7404
|
+
function uncertainSurfaceRefusal(inferred, command = "issue create") {
|
|
7405
|
+
if (!inferred.uncertain) return void 0;
|
|
7406
|
+
const alternatives = inferred.alternatives?.length ? ` Other candidates: ${inferred.alternatives.join(", ")}.` : "";
|
|
7407
|
+
return {
|
|
7408
|
+
message: `${command}: surface inference is uncertain (${inferred.reason}) \u2014 pass --surface <value> to choose explicitly or --no-surface only when the filing is genuinely exempt.${alternatives}`,
|
|
7409
|
+
payload: {
|
|
7410
|
+
code: ERROR_CODES.ERR_MISSING_FLAG,
|
|
7411
|
+
offending_flag: "--surface",
|
|
7412
|
+
expected: ["--surface <value>", "--no-surface for a genuinely exempt filing"]
|
|
7413
|
+
}
|
|
7414
|
+
};
|
|
7415
|
+
}
|
|
7404
7416
|
function surfaceInferenceNote(inferred) {
|
|
7405
7417
|
const base = `mmi-cli: no --surface given \u2014 filed under ${inferred.label} (${inferred.reason}).`;
|
|
7406
7418
|
return inferred.uncertain ? `${base}${surfaceInferenceSuffix(inferred)}
|
|
@@ -7438,7 +7450,9 @@ async function checkSurfaceRequirement(input, deps = {}) {
|
|
|
7438
7450
|
}
|
|
7439
7451
|
if (known.length === 0) return { enforcing: false, taxonomyAbsent: true };
|
|
7440
7452
|
if (labelsCarrySurface(input.labels)) return { enforcing: true };
|
|
7441
|
-
|
|
7453
|
+
const inferred = inferSurface(known, { title: input.title, type: input.type, body: input.body });
|
|
7454
|
+
const refusal = uncertainSurfaceRefusal(inferred, input.command ?? "issue create");
|
|
7455
|
+
return refusal ? { enforcing: true, refusal } : { enforcing: true, inferred };
|
|
7442
7456
|
}
|
|
7443
7457
|
function conflictingSurfaceInputs(surfaceFlag, labels) {
|
|
7444
7458
|
if (!surfaceFlag) return void 0;
|
|
@@ -9530,11 +9544,16 @@ function resolveUseEnvNames(keys, name) {
|
|
|
9530
9544
|
function referencesDollarEnv(arg, name) {
|
|
9531
9545
|
return arg.includes(`\${${name}}`) || new RegExp(`\\$${name}(?![A-Za-z0-9_])`).test(arg);
|
|
9532
9546
|
}
|
|
9547
|
+
function isShellScriptCommand(command) {
|
|
9548
|
+
const exe = (command[0] ?? "").split(/[/\\]/).pop()?.toLowerCase().replace(/\.exe$/, "") ?? "";
|
|
9549
|
+
return /^(?:ba|z|da|k)?sh$/.test(exe) && command.slice(1).some((a) => /^-[a-z]*c[a-z]*$/i.test(a));
|
|
9550
|
+
}
|
|
9533
9551
|
function secretsUseDollarHint(command, envNames) {
|
|
9552
|
+
if (isShellScriptCommand(command)) return null;
|
|
9534
9553
|
for (const arg of command) {
|
|
9535
9554
|
for (const name of envNames) {
|
|
9536
9555
|
if (!referencesDollarEnv(arg, name)) continue;
|
|
9537
|
-
return `secrets use: $${name} is injected into the CHILD's env,
|
|
9556
|
+
return `secrets use: ${command[0]} receives the literal text $${name} \u2014 the value is injected into the CHILD's env, and ${command[0]} does not expand variables in its arguments. Wrap the consumer in a shell so expansion happens inside: bash -c 'your-command "$${name}"'`;
|
|
9538
9557
|
}
|
|
9539
9558
|
}
|
|
9540
9559
|
return null;
|
|
@@ -10851,6 +10870,9 @@ function readSessionId(env) {
|
|
|
10851
10870
|
}
|
|
10852
10871
|
return void 0;
|
|
10853
10872
|
}
|
|
10873
|
+
function readSessionIdSource(env) {
|
|
10874
|
+
return SESSION_ID_ENV_VARS.find((key) => Boolean(env[key]?.trim()));
|
|
10875
|
+
}
|
|
10854
10876
|
var synthesizedSessionId;
|
|
10855
10877
|
function fallbackSessionId(surface) {
|
|
10856
10878
|
if (!synthesizedSessionId) {
|
|
@@ -11076,6 +11098,7 @@ var ITEM_FIELD_VALUES_PAGE = 25;
|
|
|
11076
11098
|
var ITEM_LABELS_PAGE = 25;
|
|
11077
11099
|
var ITEM_ASSIGNEES_PAGE = 10;
|
|
11078
11100
|
var ITEM_PROJECT_ITEMS_PAGE = 50;
|
|
11101
|
+
var LINKED_REPOS_PAGE = 20;
|
|
11079
11102
|
var CONTENT_LABELS_AND_ASSIGNEES = `
|
|
11080
11103
|
labels(first: ${ITEM_LABELS_PAGE}) { pageInfo { hasNextPage } nodes { name } }
|
|
11081
11104
|
assignees(first: ${ITEM_ASSIGNEES_PAGE}) { pageInfo { hasNextPage } nodes { login } }`;
|
|
@@ -11086,6 +11109,7 @@ query($owner: String!, $number: Int!, $after: String, $query: String) {
|
|
|
11086
11109
|
projectV2(number: $number) {
|
|
11087
11110
|
id
|
|
11088
11111
|
title
|
|
11112
|
+
repositories(first: ${LINKED_REPOS_PAGE}) { pageInfo { hasNextPage } nodes { nameWithOwner } }
|
|
11089
11113
|
items(first: 100, after: $after, query: $query) {
|
|
11090
11114
|
pageInfo { hasNextPage endCursor }
|
|
11091
11115
|
nodes {
|
|
@@ -11126,6 +11150,44 @@ query($owner: String!, $number: Int!, $after: String, $query: String) {
|
|
|
11126
11150
|
}
|
|
11127
11151
|
}
|
|
11128
11152
|
}`;
|
|
11153
|
+
var INDEX_LAG_RECOVERY_PAGE = 50;
|
|
11154
|
+
var INDEX_LAG_RECOVERY_ITEMS_PAGE = 10;
|
|
11155
|
+
var INDEX_LAG_RECOVERY_MAX_PAGES = 10;
|
|
11156
|
+
var indexLagRecoveryQuery = (connection) => `
|
|
11157
|
+
query($repoOwner: String!, $repoName: String!, $after: String) {
|
|
11158
|
+
repository(owner: $repoOwner, name: $repoName) {
|
|
11159
|
+
${connection}(first: ${INDEX_LAG_RECOVERY_PAGE}, after: $after, states: OPEN) {
|
|
11160
|
+
pageInfo { hasNextPage endCursor }
|
|
11161
|
+
nodes {
|
|
11162
|
+
__typename
|
|
11163
|
+
id
|
|
11164
|
+
number
|
|
11165
|
+
title
|
|
11166
|
+
url
|
|
11167
|
+
state
|
|
11168
|
+
updatedAt
|
|
11169
|
+
repository { nameWithOwner }${CONTENT_LABELS_AND_ASSIGNEES}
|
|
11170
|
+
projectItems(first: ${INDEX_LAG_RECOVERY_ITEMS_PAGE}) {
|
|
11171
|
+
pageInfo { hasNextPage }
|
|
11172
|
+
nodes {
|
|
11173
|
+
id
|
|
11174
|
+
project { id }
|
|
11175
|
+
fieldValues(first: ${ITEM_FIELD_VALUES_PAGE}) {
|
|
11176
|
+
pageInfo { hasNextPage }
|
|
11177
|
+
nodes {
|
|
11178
|
+
... on ProjectV2ItemFieldSingleSelectValue {
|
|
11179
|
+
name
|
|
11180
|
+
optionId
|
|
11181
|
+
field { ... on ProjectV2SingleSelectField { id name } }
|
|
11182
|
+
}
|
|
11183
|
+
}
|
|
11184
|
+
}
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
}
|
|
11188
|
+
}
|
|
11189
|
+
}
|
|
11190
|
+
}`;
|
|
11129
11191
|
var ACTIVE_BOARD_ITEMS_FILTER = "-status:Done -is:closed";
|
|
11130
11192
|
var DOCTOR_BOARD_ITEMS_FILTER = "-status:Done";
|
|
11131
11193
|
var ARCHIVE_BOARD_ITEMS_FILTER = "status:Done is:closed";
|
|
@@ -11349,6 +11411,52 @@ function shouldSkipInactiveBoardNode(node, cfg) {
|
|
|
11349
11411
|
const status = parseSingleSelectFields(node.fieldValues?.nodes, cfg).status?.name;
|
|
11350
11412
|
return status === "Done";
|
|
11351
11413
|
}
|
|
11414
|
+
async function recoverIndexLaggedItems(graphql, projectId, linkedRepos, listed, isInactive, warnings) {
|
|
11415
|
+
const known = new Set(listed.map((node) => node.id));
|
|
11416
|
+
const nodes = [];
|
|
11417
|
+
let partial = false;
|
|
11418
|
+
if (linkedRepos?.pageInfo?.hasNextPage) {
|
|
11419
|
+
warnings.push(`partial board read: index-lag recovery covers only the first ${LINKED_REPOS_PAGE} linked repos`);
|
|
11420
|
+
partial = true;
|
|
11421
|
+
}
|
|
11422
|
+
for (const repo of (linkedRepos?.nodes ?? []).map((node) => node.nameWithOwner).filter((name) => Boolean(name))) {
|
|
11423
|
+
const [repoOwner, repoName2] = repo.split("/");
|
|
11424
|
+
let recoveredHere = 0;
|
|
11425
|
+
for (const connection of ["issues", "pullRequests"]) {
|
|
11426
|
+
let after;
|
|
11427
|
+
let pages = 0;
|
|
11428
|
+
try {
|
|
11429
|
+
do {
|
|
11430
|
+
const page = (await graphql(indexLagRecoveryQuery(connection), { repoOwner, repoName: repoName2, ...after ? { after } : {} })).repository?.[connection];
|
|
11431
|
+
for (const content of page?.nodes ?? []) {
|
|
11432
|
+
const { projectItems, ...contentFields } = content;
|
|
11433
|
+
const item = (projectItems?.nodes ?? []).find((entry) => entry.project?.id === projectId);
|
|
11434
|
+
if (!item?.id || known.has(item.id)) continue;
|
|
11435
|
+
const node = { id: item.id, fieldValues: item.fieldValues, content: contentFields };
|
|
11436
|
+
if (isInactive(node)) continue;
|
|
11437
|
+
known.add(item.id);
|
|
11438
|
+
nodes.push(node);
|
|
11439
|
+
recoveredHere += 1;
|
|
11440
|
+
}
|
|
11441
|
+
after = page?.pageInfo?.hasNextPage ? page.pageInfo.endCursor ?? void 0 : void 0;
|
|
11442
|
+
pages += 1;
|
|
11443
|
+
if (after && pages >= INDEX_LAG_RECOVERY_MAX_PAGES) {
|
|
11444
|
+
warnings.push(`partial board read: index-lag recovery for ${repo} ${connection} capped at ${pages * INDEX_LAG_RECOVERY_PAGE} open items`);
|
|
11445
|
+
partial = true;
|
|
11446
|
+
after = void 0;
|
|
11447
|
+
}
|
|
11448
|
+
} while (after);
|
|
11449
|
+
} catch (e) {
|
|
11450
|
+
warnings.push(`partial board read: index-lag recovery for ${repo} ${connection} failed (${e.message})`);
|
|
11451
|
+
partial = true;
|
|
11452
|
+
}
|
|
11453
|
+
}
|
|
11454
|
+
if (recoveredHere) {
|
|
11455
|
+
warnings.push(`board read: ${recoveredHere} active item(s) from ${repo} were missing from GitHub's project items listing (Projects index lag) \u2014 recovered from their own project membership`);
|
|
11456
|
+
}
|
|
11457
|
+
}
|
|
11458
|
+
return { nodes, partial };
|
|
11459
|
+
}
|
|
11352
11460
|
async function collectBoardItems(cfg, options, deps) {
|
|
11353
11461
|
const client = deps.client ?? defaultGitHubClient();
|
|
11354
11462
|
const currentRepo = await resolveCurrentRepo(options, deps);
|
|
@@ -11361,6 +11469,7 @@ async function collectBoardItems(cfg, options, deps) {
|
|
|
11361
11469
|
let projectId = cfg.projectId;
|
|
11362
11470
|
let partial = false;
|
|
11363
11471
|
let pageCount = 0;
|
|
11472
|
+
let linkedRepos;
|
|
11364
11473
|
do {
|
|
11365
11474
|
try {
|
|
11366
11475
|
const page = await fetchProjectPage(client, cfg, after, itemsQuery);
|
|
@@ -11369,6 +11478,7 @@ async function collectBoardItems(cfg, options, deps) {
|
|
|
11369
11478
|
if (!project2) throw new Error(`project ${cfg.projectOwner}#${cfg.projectNumber} not found`);
|
|
11370
11479
|
projectId = project2.id;
|
|
11371
11480
|
projectTitle ||= project2.title;
|
|
11481
|
+
linkedRepos ??= project2.repositories;
|
|
11372
11482
|
pageCount += 1;
|
|
11373
11483
|
const pageNodes = project2.items.nodes ?? [];
|
|
11374
11484
|
if (options.activeOnly) {
|
|
@@ -11410,6 +11520,18 @@ async function collectBoardItems(cfg, options, deps) {
|
|
|
11410
11520
|
partial = true;
|
|
11411
11521
|
}
|
|
11412
11522
|
}
|
|
11523
|
+
if (options.activeOnly) {
|
|
11524
|
+
const recovered = await recoverIndexLaggedItems(
|
|
11525
|
+
(query, variables) => client.graphql(query, variables),
|
|
11526
|
+
projectId,
|
|
11527
|
+
linkedRepos,
|
|
11528
|
+
nodes,
|
|
11529
|
+
(node) => shouldSkipInactiveBoardNode(node, cfg),
|
|
11530
|
+
warnings
|
|
11531
|
+
);
|
|
11532
|
+
nodes.push(...recovered.nodes);
|
|
11533
|
+
partial ||= recovered.partial;
|
|
11534
|
+
}
|
|
11413
11535
|
const read = nodesToItems(nodes, warnings, cfg);
|
|
11414
11536
|
if (read.failures.length) {
|
|
11415
11537
|
const message2 = `partial board read: ${read.failures.length} item(s) came back truncated and were not read \u2014 ${read.failures.join(" | ")}`;
|
|
@@ -12467,15 +12589,36 @@ async function moveBoardItem(options, deps = {}) {
|
|
|
12467
12589
|
({ credential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId));
|
|
12468
12590
|
} catch (e) {
|
|
12469
12591
|
if (options.status === "Done" && isArchivedItemRefusal(ghError(e))) {
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12592
|
+
if (item.status === "Done") {
|
|
12593
|
+
return {
|
|
12594
|
+
item,
|
|
12595
|
+
viewer: lookup.viewer,
|
|
12596
|
+
repo: currentRepo,
|
|
12597
|
+
status: "Done",
|
|
12598
|
+
partial: false,
|
|
12599
|
+
archived: true,
|
|
12600
|
+
warning: `${item.ref} is archived and already Done; no status write was needed`
|
|
12601
|
+
};
|
|
12602
|
+
}
|
|
12603
|
+
try {
|
|
12604
|
+
await client.graphql(
|
|
12605
|
+
`mutation($projectId: ID!, $itemId: ID!) { unarchiveProjectV2Item(input: { projectId: $projectId, itemId: $itemId }) { item { id } } }`,
|
|
12606
|
+
{ projectId: cfg.projectId, itemId: item.itemId }
|
|
12607
|
+
);
|
|
12608
|
+
({ credential } = await updateItemSingleSelect(client, cfg.projectId, item.itemId, cfg.statusFieldId, optionId));
|
|
12609
|
+
return {
|
|
12610
|
+
item: { ...item, status: "Done", statusOptionId: optionId },
|
|
12611
|
+
viewer: lookup.viewer,
|
|
12612
|
+
repo: currentRepo,
|
|
12613
|
+
status: "Done",
|
|
12614
|
+
partial: false,
|
|
12615
|
+
credential
|
|
12616
|
+
};
|
|
12617
|
+
} catch (recoveryError) {
|
|
12618
|
+
const warning2 = `partial move: ${item.ref} was archived at '${item.status}' and could not be unarchived and moved to Done (${ghError(recoveryError)})`;
|
|
12619
|
+
if (!options.allowPartial) throw new Error(warning2);
|
|
12620
|
+
return { item, viewer: lookup.viewer, repo: currentRepo, status: item.status, partial: true, warning: warning2 };
|
|
12621
|
+
}
|
|
12479
12622
|
}
|
|
12480
12623
|
const warning = `partial move: ${item.ref} status was not changed to ${options.status} (${ghError(e)})`;
|
|
12481
12624
|
if (!options.allowPartial) throw new Error(warning);
|
|
@@ -12549,9 +12692,26 @@ async function prepareClaimContext(options, selectors, deps, collected, snapshot
|
|
|
12549
12692
|
items: collected.items,
|
|
12550
12693
|
writable: writableOrUnknown(writable),
|
|
12551
12694
|
report,
|
|
12552
|
-
session: deps.session ?? describeSessionIdentity()
|
|
12695
|
+
session: deps.session ?? describeSessionIdentity(),
|
|
12696
|
+
...deps.snapshot ? {
|
|
12697
|
+
freshAppItem: async (selector) => {
|
|
12698
|
+
const fresh = await collectBoardPreferringSnapshot(cfg, { repo: options.repo }, deps);
|
|
12699
|
+
if (!fresh.snapshot || fresh.collected.partial) return void 0;
|
|
12700
|
+
return fresh.collected.items.find((candidate) => candidate.repository.toLowerCase() === selector.repo.toLowerCase() && candidate.number === selector.number);
|
|
12701
|
+
}
|
|
12702
|
+
} : {}
|
|
12553
12703
|
};
|
|
12554
12704
|
}
|
|
12705
|
+
async function freshClaimItem(ctx, selector) {
|
|
12706
|
+
try {
|
|
12707
|
+
return (await fetchIssueProjectItem(ctx.client, ctx.cfg, selector)).item;
|
|
12708
|
+
} catch (e) {
|
|
12709
|
+
if (!isRateLimitRefusal(e) || !ctx.freshAppItem) throw e;
|
|
12710
|
+
const item = await ctx.freshAppItem(selector).catch(() => void 0);
|
|
12711
|
+
if (!item) throw e;
|
|
12712
|
+
return item;
|
|
12713
|
+
}
|
|
12714
|
+
}
|
|
12555
12715
|
async function claimOneBoardItem(ctx, selector, options) {
|
|
12556
12716
|
const { cfg, client, report } = ctx;
|
|
12557
12717
|
const flatItem = findBoardItem(ctx.items, selector, { owner: cfg.projectOwner, number: cfg.projectNumber });
|
|
@@ -12607,7 +12767,7 @@ async function claimOneBoardItem(ctx, selector, options) {
|
|
|
12607
12767
|
const pre = evaluateClaim(flatItem, assignedLogin);
|
|
12608
12768
|
if (!pre.ok) throw new NotClaimableError(pre.reason, { ref: flatItem.ref, status: flatItem.status });
|
|
12609
12769
|
let item = flatItem;
|
|
12610
|
-
const fresh =
|
|
12770
|
+
const fresh = await freshClaimItem(ctx, { repo: item.repository, number: item.number });
|
|
12611
12771
|
if (!fresh) throw new Error(`${item.ref} is not on this project board`);
|
|
12612
12772
|
const verdict = evaluateClaim(fresh, assignedLogin);
|
|
12613
12773
|
if (!verdict.ok) throw new NotClaimableError(verdict.reason, { ref: fresh.ref, status: fresh.status });
|
|
@@ -14724,9 +14884,10 @@ function buildRegisterPayload(repo, cls, vars, options = {}) {
|
|
|
14724
14884
|
deployModel,
|
|
14725
14885
|
// Persist the canonical stage hosts at the same write-time boundary as deployModel. Read paths never
|
|
14726
14886
|
// infer from an absent edgeDomains field.
|
|
14727
|
-
edgeDomains: inferEdgeDomainsForWrite(slug),
|
|
14887
|
+
edgeDomains: options.existing?.edgeDomains ?? inferEdgeDomainsForWrite(slug),
|
|
14728
14888
|
// #1359: always persist an explicit track so release tooling never guesses from absence alone.
|
|
14729
|
-
|
|
14889
|
+
// #7134: an explicit flag wins, then the registered track, then the class default (first bootstrap).
|
|
14890
|
+
releaseTrack: options.releaseTrack ?? (isReleaseTrack(options.existing?.releaseTrack) ? options.existing.releaseTrack : void 0) ?? resolveBootstrapReleaseTrack(cls, void 0),
|
|
14730
14891
|
// Board coords (from GraphQL at bootstrap, passed as --var by the skill).
|
|
14731
14892
|
projectOwner: vars.PROJECT_OWNER || void 0,
|
|
14732
14893
|
projectNumber: num(vars.PROJECT_NUMBER),
|
|
@@ -16001,10 +16162,10 @@ var rollout_plan_default = {
|
|
|
16001
16162
|
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)."
|
|
16002
16163
|
},
|
|
16003
16164
|
baseline: {
|
|
16004
|
-
version: "4.5.
|
|
16005
|
-
tag: "v4.5.
|
|
16006
|
-
commit: "
|
|
16007
|
-
npm: "@mutmutco/cli@4.5.
|
|
16165
|
+
version: "4.5.18",
|
|
16166
|
+
tag: "v4.5.18",
|
|
16167
|
+
commit: "afc70753c56b",
|
|
16168
|
+
npm: "@mutmutco/cli@4.5.18"
|
|
16008
16169
|
},
|
|
16009
16170
|
exitCriterion: "fleet-n-of-n",
|
|
16010
16171
|
hubOnlyShortcut: "forbidden",
|
|
@@ -16021,14 +16182,14 @@ var rollout_plan_default = {
|
|
|
16021
16182
|
repo: "mutmutco/mmi-hub",
|
|
16022
16183
|
role: "canary",
|
|
16023
16184
|
schedule: "train",
|
|
16024
|
-
v3Target: "v4.5.
|
|
16185
|
+
v3Target: "v4.5.18"
|
|
16025
16186
|
}
|
|
16026
16187
|
],
|
|
16027
16188
|
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.",
|
|
16028
16189
|
rollback: {
|
|
16029
16190
|
independent: true,
|
|
16030
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
16031
|
-
v3Target: "v4.5.
|
|
16191
|
+
mechanism: "npm dist-tag latest -> 4.5.18 and redeploy the Hub Lambda from tag v4.5.18 (afc70753c56b); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
16192
|
+
v3Target: "v4.5.18 (@mutmutco/cli@4.5.18, tag commit afc70753c56b \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
16032
16193
|
}
|
|
16033
16194
|
},
|
|
16034
16195
|
{
|
|
@@ -30111,7 +30272,7 @@ function registerBootstrapCommands(program3) {
|
|
|
30111
30272
|
for (const [k, v] of Object.entries(gateConfigToVars(meta?.gate))) if (rawVars[k] == null) rawVars[k] = v;
|
|
30112
30273
|
} catch {
|
|
30113
30274
|
}
|
|
30114
|
-
const vars = withDerivedRepoVars(rawVars, parsedRepo, o.class,
|
|
30275
|
+
const vars = withDerivedRepoVars(rawVars, parsedRepo, o.class, effectiveTrack, registryRequiredCheckBranches, registryMeta?.requiredChecks);
|
|
30115
30276
|
if (!vars.PROJECT_ID) {
|
|
30116
30277
|
try {
|
|
30117
30278
|
const r = await gh(linkedProjectsQueryArgs(parsedRepo.owner, parsedRepo.name));
|
|
@@ -30477,7 +30638,9 @@ ${onlyManagedBlock ? `Only the marker-bounded Hub-managed block inside repo-owne
|
|
|
30477
30638
|
projectType: o.projectType || registryMeta?.projectType || void 0,
|
|
30478
30639
|
// #6090: META is authoritative on a rerun
|
|
30479
30640
|
deployModel: o.deployModel || registryMeta?.deployModel || void 0,
|
|
30480
|
-
|
|
30641
|
+
// #7134: explicit flag only; the registered track and edge domains win on a re-run.
|
|
30642
|
+
releaseTrack: o.releaseTrack || void 0,
|
|
30643
|
+
existing: registryMeta
|
|
30481
30644
|
});
|
|
30482
30645
|
} catch (e) {
|
|
30483
30646
|
return fail(`bootstrap apply: ${e.message}`);
|
|
@@ -33001,7 +33164,8 @@ async function collectOnboardStatus(opts = {}) {
|
|
|
33001
33164
|
let board = { ok: false, detail: "no config" };
|
|
33002
33165
|
try {
|
|
33003
33166
|
if (cfg.sagaApiUrl) {
|
|
33004
|
-
const
|
|
33167
|
+
const boardCfg = await loadConfigOrDiscover();
|
|
33168
|
+
const report = await readBoard({ config: boardCfg }, { snapshot: registryClientDeps(boardCfg) });
|
|
33005
33169
|
const total = report.primary.claimable.length + report.primary.userOwned.length + report.primary.taken.length;
|
|
33006
33170
|
board = { ok: true, detail: `board has ${total} active items (${report.primary.claimable.length} claimable, ${report.primary.userOwned.length} yours)` };
|
|
33007
33171
|
} else {
|
|
@@ -35691,10 +35855,12 @@ function validateBatchSpecs(specs) {
|
|
|
35691
35855
|
}
|
|
35692
35856
|
return { ok: errors.length === 0, errors, validated };
|
|
35693
35857
|
}
|
|
35694
|
-
async function preflightBatchSurfaces(validated, rowRepo, options) {
|
|
35858
|
+
async function preflightBatchSurfaces(validated, rowRepo, options, deps = {}) {
|
|
35859
|
+
const surfaceApplies = deps.surfaceLabelApplies ?? surfaceLabelApplies;
|
|
35860
|
+
const readLabels = deps.readRepoSurfaceLabels ?? readRepoSurfaceLabels;
|
|
35695
35861
|
const applies = /* @__PURE__ */ new Map();
|
|
35696
35862
|
const appliesTo = async (repo) => {
|
|
35697
|
-
if (!applies.has(repo)) applies.set(repo, await
|
|
35863
|
+
if (!applies.has(repo)) applies.set(repo, await surfaceApplies(repo));
|
|
35698
35864
|
return applies.get(repo);
|
|
35699
35865
|
};
|
|
35700
35866
|
if (options.surface) {
|
|
@@ -35709,7 +35875,7 @@ async function preflightBatchSurfaces(validated, rowRepo, options) {
|
|
|
35709
35875
|
const censusFor = (repo) => {
|
|
35710
35876
|
let pending = censusCache.get(repo);
|
|
35711
35877
|
if (!pending) {
|
|
35712
|
-
pending =
|
|
35878
|
+
pending = readLabels(repo);
|
|
35713
35879
|
censusCache.set(repo, pending);
|
|
35714
35880
|
}
|
|
35715
35881
|
return pending;
|
|
@@ -35727,9 +35893,14 @@ async function preflightBatchSurfaces(validated, rowRepo, options) {
|
|
|
35727
35893
|
}
|
|
35728
35894
|
if (known.length === 0) continue;
|
|
35729
35895
|
const inferred = inferSurface(known, { title: spec.title, type: spec.type, body: spec.body });
|
|
35896
|
+
const refusal = uncertainSurfaceRefusal(inferred, `issue create --batch row ${row}`);
|
|
35897
|
+
if (refusal) {
|
|
35898
|
+
errors.push({ row, error: refusal.message });
|
|
35899
|
+
continue;
|
|
35900
|
+
}
|
|
35730
35901
|
spec.labels = [...spec.labels ?? [], inferred.label];
|
|
35731
35902
|
process.stderr.write(
|
|
35732
|
-
`mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose
|
|
35903
|
+
`mmi-cli: no --surface given \u2014 row ${row} filed under ${inferred.label} (${inferred.reason}). Pass --surface to choose.
|
|
35733
35904
|
`
|
|
35734
35905
|
);
|
|
35735
35906
|
}
|
|
@@ -41028,6 +41199,8 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
41028
41199
|
const repo = await requireRepo(repoOption);
|
|
41029
41200
|
const { client, throttledPaths } = withRateLimitRetry(deps.client ?? defaultGitHubClient(), deps);
|
|
41030
41201
|
const actor = deps.actor ?? describeSessionIdentity();
|
|
41202
|
+
const source = deps.actorSource ?? (deps.actor ? "the caller-supplied identity" : readSessionIdSource(process.env) ?? "a synthesized fallback");
|
|
41203
|
+
const requester = `requesting lane: ${actor.surface}/${actor.session}@${actor.host} (session id from ${source})`;
|
|
41031
41204
|
const checkContest = deps.checkContest ?? checkLaneContest;
|
|
41032
41205
|
for (const number of issues) {
|
|
41033
41206
|
const state = await client.rest("GET", `repos/${repo}/issues/${number}`).then((issue) => issue?.state, () => void 0);
|
|
@@ -41045,10 +41218,10 @@ async function prCreateClaimRefusal(body, repoOption, deps = {}) {
|
|
|
41045
41218
|
contest.unverifiable.length ? `liveness could not be fully verified (failed to read: ${contest.unverifiable.join(", ")})` : ""
|
|
41046
41219
|
].filter(Boolean).join("; ");
|
|
41047
41220
|
if (!contest.marker && !contest.unverifiable.includes("comments")) {
|
|
41048
|
-
return `pr create: REFUSED \u2014 ${ref} carries no claim marker (its claim-marker comments were read from ${commentsPath} and name no holder) and shows ${kinds} work evidence (${why}); if this work is yours, \`mmi-cli oracle board claim ${ref} --force\` re-stamps your lane's marker and clears the refusal (move it to In Progress first if it sits In Review), or drop the closing line before creating this PR`;
|
|
41221
|
+
return `pr create: REFUSED \u2014 ${ref} carries no claim marker (its claim-marker comments were read from ${commentsPath} and name no holder) and shows ${kinds} work evidence (${why}); if this work is yours, \`mmi-cli oracle board claim ${ref} --force\` re-stamps your lane's marker and clears the refusal (move it to In Progress first if it sits In Review), or drop the closing line before creating this PR; ${requester}`;
|
|
41049
41222
|
}
|
|
41050
41223
|
const holder = contest.marker ? `lane ${describeClaimMarker(contest.marker)} (claim marker read from ${commentsPath}${posted})` : `an unreadable lane (its claim-marker comments could not be read${throttledPaths.has(commentsPath) ? " \u2014 GitHub rate-limited the read (HTTP 403) and the bounded reset-aware retry could not clear it" : ""}; the holder may be this very lane)`;
|
|
41051
|
-
return `pr create: REFUSED \u2014 ${ref} is held by ${holder} with ${kinds} work evidence (${why}); run \`mmi-cli oracle board claim ${ref} --force\` (move it to In Progress first if it sits In Review) or drop the closing line before creating this PR`;
|
|
41224
|
+
return `pr create: REFUSED \u2014 ${ref} is held by ${holder} with ${kinds} work evidence (${why}); run \`mmi-cli oracle board claim ${ref} --force\` (move it to In Progress first if it sits In Review) or drop the closing line before creating this PR; ${requester}`;
|
|
41052
41225
|
}
|
|
41053
41226
|
return void 0;
|
|
41054
41227
|
}
|
package/package.json
CHANGED