@mutmutco/cli 4.3.56 → 4.3.58
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 +101 -269
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -6046,6 +6046,15 @@ var REGISTRY_FETCH_TIMEOUT_MS = 8e3;
|
|
|
6046
6046
|
init_fetch_retry();
|
|
6047
6047
|
init_client_version();
|
|
6048
6048
|
|
|
6049
|
+
// ../shared/schedule-inventory.ts
|
|
6050
|
+
function classifyLlmValue(raw) {
|
|
6051
|
+
const value = raw.trim().toLowerCase();
|
|
6052
|
+
if (/^no\b|^none\b/.test(value)) return "no";
|
|
6053
|
+
if (/^yes\b/.test(value)) return "yes";
|
|
6054
|
+
if (/^embeddings\b/.test(value)) return "embeddings";
|
|
6055
|
+
return "unknown";
|
|
6056
|
+
}
|
|
6057
|
+
|
|
6049
6058
|
// src/workflow-context.ts
|
|
6050
6059
|
function parseWorkflowJobs(yaml) {
|
|
6051
6060
|
const lines2 = yaml.split(/\r?\n/);
|
|
@@ -6324,25 +6333,10 @@ function resolvedLabel(entry, now) {
|
|
|
6324
6333
|
var ORG = "mutmutco";
|
|
6325
6334
|
var DOC_START_MARKER = "<!-- schedules:inventory:start -->";
|
|
6326
6335
|
var DOC_END_MARKER = "<!-- schedules:inventory:end -->";
|
|
6327
|
-
function isJervResource(name) {
|
|
6328
|
-
return /^jerv-memory(?:-|$)/i.test(name);
|
|
6329
|
-
}
|
|
6330
6336
|
function llmFromHeader(yamlText) {
|
|
6331
6337
|
const m = /^#\s*llm:\s*(.+)$/im.exec(yamlText);
|
|
6332
6338
|
return m ? classifyLlmValue(m[1]) : "unknown";
|
|
6333
6339
|
}
|
|
6334
|
-
function classifyLlmValue(raw) {
|
|
6335
|
-
const value = raw.trim().toLowerCase();
|
|
6336
|
-
if (/^no\b|^none\b/.test(value)) return "no";
|
|
6337
|
-
if (/^yes\b/.test(value)) return "yes";
|
|
6338
|
-
if (/^embeddings\b/.test(value)) return "embeddings";
|
|
6339
|
-
return "unknown";
|
|
6340
|
-
}
|
|
6341
|
-
function readLlmDeclaration(text) {
|
|
6342
|
-
if (!text) return "unknown";
|
|
6343
|
-
const m = /\bllm:\s*(.+)/i.exec(text);
|
|
6344
|
-
return m ? classifyLlmValue(m[1]) : "unknown";
|
|
6345
|
-
}
|
|
6346
6340
|
function extractWorkflowCrons(yamlText) {
|
|
6347
6341
|
const crons = [];
|
|
6348
6342
|
for (const rawLine of yamlText.split("\n")) {
|
|
@@ -6366,126 +6360,6 @@ function workflowEntry(repo, workflowPath, yamlText) {
|
|
|
6366
6360
|
harbourUnmanaged: isHarbourUnmanaged(yamlText)
|
|
6367
6361
|
};
|
|
6368
6362
|
}
|
|
6369
|
-
function awsRuleEntries(payload) {
|
|
6370
|
-
if (!payload || typeof payload !== "object") {
|
|
6371
|
-
throw new Error("aws events list-rules answered a non-object payload \u2014 refusing to read it as zero rules");
|
|
6372
|
-
}
|
|
6373
|
-
const { Rules: rules } = payload;
|
|
6374
|
-
if (!Array.isArray(rules)) {
|
|
6375
|
-
throw new Error("aws events list-rules answered no Rules array \u2014 refusing to read it as zero rules");
|
|
6376
|
-
}
|
|
6377
|
-
const entries = [];
|
|
6378
|
-
for (const node of rules) {
|
|
6379
|
-
if (!node || typeof node !== "object") {
|
|
6380
|
-
throw new Error("aws events list-rules returned a non-object rule \u2014 refusing to read it as no rule");
|
|
6381
|
-
}
|
|
6382
|
-
const { Name, ScheduleExpression, State, Description } = node;
|
|
6383
|
-
if (typeof Name !== "string") {
|
|
6384
|
-
throw new Error("aws events list-rules returned a rule with no Name string \u2014 refusing to read it as no rule");
|
|
6385
|
-
}
|
|
6386
|
-
if (typeof ScheduleExpression !== "string") continue;
|
|
6387
|
-
if (State !== "ENABLED" || isJervResource(Name)) continue;
|
|
6388
|
-
entries.push({
|
|
6389
|
-
name: Name,
|
|
6390
|
-
cadence: ScheduleExpression,
|
|
6391
|
-
executor: "aws-eventbridge-rule",
|
|
6392
|
-
// An AWS rule declares `llm:` in its own Description (the shared convention) — a rule with no
|
|
6393
|
-
// Description reads `unknown`, and stack-internal plumbing like the Lambda warmer should say
|
|
6394
|
-
// `llm: no` there to go green.
|
|
6395
|
-
llm: readLlmDeclaration(typeof Description === "string" ? Description : void 0),
|
|
6396
|
-
resolved: "live",
|
|
6397
|
-
source: `aws events rule ${Name} (eu-central-1)`
|
|
6398
|
-
});
|
|
6399
|
-
}
|
|
6400
|
-
return entries;
|
|
6401
|
-
}
|
|
6402
|
-
function lambdaTargetFromArn(arn) {
|
|
6403
|
-
const marker = ":function:";
|
|
6404
|
-
const i = arn.indexOf(marker);
|
|
6405
|
-
if (i < 0) return { functionName: arn.split(":").pop() ?? "" };
|
|
6406
|
-
const rest = arn.slice(i + marker.length);
|
|
6407
|
-
const q = rest.indexOf(":");
|
|
6408
|
-
if (q < 0) return { functionName: rest };
|
|
6409
|
-
return { functionName: rest.slice(0, q), qualifier: rest.slice(q + 1) };
|
|
6410
|
-
}
|
|
6411
|
-
function awsScheduleEntry(payload) {
|
|
6412
|
-
if (!payload || typeof payload !== "object") {
|
|
6413
|
-
throw new Error("aws scheduler get-schedule answered a non-object payload \u2014 refusing to read it as no schedule");
|
|
6414
|
-
}
|
|
6415
|
-
const { Name, ScheduleExpression, State, Target, Description, CreationDate } = payload;
|
|
6416
|
-
if (typeof Name !== "string" || typeof ScheduleExpression !== "string") {
|
|
6417
|
-
throw new Error("aws scheduler get-schedule answered no Name/ScheduleExpression strings \u2014 refusing to read it as no schedule");
|
|
6418
|
-
}
|
|
6419
|
-
if (State !== "ENABLED" || isJervResource(Name)) return null;
|
|
6420
|
-
let target = "";
|
|
6421
|
-
let qualifier;
|
|
6422
|
-
let scheduleId;
|
|
6423
|
-
if (Target && typeof Target === "object") {
|
|
6424
|
-
const { Arn, Input } = Target;
|
|
6425
|
-
if (typeof Arn === "string") {
|
|
6426
|
-
const parsed = lambdaTargetFromArn(Arn);
|
|
6427
|
-
target = parsed.functionName;
|
|
6428
|
-
qualifier = parsed.qualifier;
|
|
6429
|
-
}
|
|
6430
|
-
if (typeof Input === "string") {
|
|
6431
|
-
try {
|
|
6432
|
-
const parsed = JSON.parse(Input);
|
|
6433
|
-
if (typeof parsed?.scheduleId === "string" && parsed.scheduleId) scheduleId = parsed.scheduleId;
|
|
6434
|
-
} catch {
|
|
6435
|
-
}
|
|
6436
|
-
}
|
|
6437
|
-
}
|
|
6438
|
-
const sourceBase = `aws scheduler schedule ${Name} (eu-central-1)`;
|
|
6439
|
-
const source = qualifier && target ? `${sourceBase} \u2192 ${target}:${qualifier}` : sourceBase;
|
|
6440
|
-
const armedAt = armedAtFromCreationDate(CreationDate);
|
|
6441
|
-
return {
|
|
6442
|
-
name: Name,
|
|
6443
|
-
cadence: ScheduleExpression,
|
|
6444
|
-
executor: target ? `aws-scheduler \u2192 ${target}` : "aws-scheduler",
|
|
6445
|
-
llm: readLlmDeclaration(typeof Description === "string" ? Description : void 0),
|
|
6446
|
-
resolved: "live",
|
|
6447
|
-
source,
|
|
6448
|
-
...scheduleId ? { scheduleId } : {},
|
|
6449
|
-
...armedAt ? { armedAt } : {}
|
|
6450
|
-
};
|
|
6451
|
-
}
|
|
6452
|
-
function armedAtFromCreationDate(creationDate) {
|
|
6453
|
-
if (creationDate instanceof Date) {
|
|
6454
|
-
return Number.isNaN(creationDate.getTime()) ? void 0 : creationDate.toISOString().slice(0, 10);
|
|
6455
|
-
}
|
|
6456
|
-
if (typeof creationDate === "string" && creationDate.trim()) {
|
|
6457
|
-
const parsed = Date.parse(creationDate);
|
|
6458
|
-
return Number.isNaN(parsed) ? void 0 : new Date(parsed).toISOString().slice(0, 10);
|
|
6459
|
-
}
|
|
6460
|
-
if (typeof creationDate === "number" && Number.isFinite(creationDate)) {
|
|
6461
|
-
const ms = creationDate > 1e12 ? creationDate : creationDate * 1e3;
|
|
6462
|
-
const date = new Date(ms);
|
|
6463
|
-
return Number.isNaN(date.getTime()) ? void 0 : date.toISOString().slice(0, 10);
|
|
6464
|
-
}
|
|
6465
|
-
return void 0;
|
|
6466
|
-
}
|
|
6467
|
-
function awsScheduleRefs(payload) {
|
|
6468
|
-
if (!payload || typeof payload !== "object") {
|
|
6469
|
-
throw new Error("aws scheduler list-schedules answered a non-object payload \u2014 refusing to read it as zero schedules");
|
|
6470
|
-
}
|
|
6471
|
-
const { Schedules: schedules } = payload;
|
|
6472
|
-
if (!Array.isArray(schedules)) {
|
|
6473
|
-
throw new Error("aws scheduler list-schedules answered no Schedules array \u2014 refusing to read it as zero schedules");
|
|
6474
|
-
}
|
|
6475
|
-
const refs = [];
|
|
6476
|
-
for (const s of schedules) {
|
|
6477
|
-
if (!s || typeof s !== "object") {
|
|
6478
|
-
throw new Error("aws scheduler list-schedules returned a non-object schedule \u2014 refusing to read it as no schedule");
|
|
6479
|
-
}
|
|
6480
|
-
const { Name, GroupName } = s;
|
|
6481
|
-
if (typeof Name !== "string") {
|
|
6482
|
-
throw new Error("aws scheduler list-schedules returned a schedule with no Name string \u2014 refusing to read it as no schedule");
|
|
6483
|
-
}
|
|
6484
|
-
if (isJervResource(Name)) continue;
|
|
6485
|
-
refs.push(typeof GroupName === "string" && GroupName !== "default" && GroupName !== "" ? { name: Name, group: GroupName } : { name: Name });
|
|
6486
|
-
}
|
|
6487
|
-
return refs;
|
|
6488
|
-
}
|
|
6489
6363
|
function decorateAwsModel(entries, registry2, verdicts) {
|
|
6490
6364
|
if (!registry2 || registry2.length === 0) return [...entries];
|
|
6491
6365
|
const rowById = new Map(registry2.map((r) => [r.id, r]));
|
|
@@ -6960,6 +6834,24 @@ async function fetchDeployFactsBySlug(slug, deps) {
|
|
|
6960
6834
|
return null;
|
|
6961
6835
|
}
|
|
6962
6836
|
}
|
|
6837
|
+
async function fetchScheduleInventory(deps) {
|
|
6838
|
+
try {
|
|
6839
|
+
if (!deps.baseUrl) return null;
|
|
6840
|
+
const token = await deps.token();
|
|
6841
|
+
if (!token) return null;
|
|
6842
|
+
const res = await retriedFetch(deps, `${deps.baseUrl.replace(/\/$/, "")}/schedules/inventory`, {
|
|
6843
|
+
method: "GET",
|
|
6844
|
+
headers: { Authorization: `Bearer ${token}` }
|
|
6845
|
+
});
|
|
6846
|
+
if (!res.ok) return null;
|
|
6847
|
+
const body = await res.json();
|
|
6848
|
+
if (!body || !Array.isArray(body.entries) || !Array.isArray(body.incomplete) || !body.incomplete.every((v) => typeof v === "string") || typeof body.schedulerRead !== "boolean" || !body.schedulerRead && body.incomplete.length === 0) return null;
|
|
6849
|
+
if (!body.entries.every((e) => e && typeof e.name === "string" && typeof e.cadence === "string" && typeof e.executor === "string" && typeof e.source === "string" && e.resolved === "live" && ["yes", "no", "embeddings", "unknown"].includes(e.llm) && (e.scheduleId === void 0 || typeof e.scheduleId === "string") && (e.armedAt === void 0 || typeof e.armedAt === "string"))) return null;
|
|
6850
|
+
return body;
|
|
6851
|
+
} catch {
|
|
6852
|
+
return null;
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6963
6855
|
async function fetchSchedulesList(deps) {
|
|
6964
6856
|
if (!deps.baseUrl) return null;
|
|
6965
6857
|
const token = await deps.token();
|
|
@@ -7071,6 +6963,9 @@ async function tenantReconcile(payload, deps) {
|
|
|
7071
6963
|
async function tenantDeploy(payload, deps) {
|
|
7072
6964
|
return postJson("/tenant-deploy", payload, deps, "POST", { noRetry: true, timeoutMs: TENANT_DEPLOY_TIMEOUT_MS });
|
|
7073
6965
|
}
|
|
6966
|
+
async function releaseAnnouncement(payload, deps) {
|
|
6967
|
+
return postJson("/release-announcement", payload, deps, "POST", { noRetry: true, timeoutMs: 3e4 });
|
|
6968
|
+
}
|
|
7074
6969
|
async function actionsCanary(payload, deps) {
|
|
7075
6970
|
return postJson("/actions-canary", payload, deps, "POST", { noRetry: true });
|
|
7076
6971
|
}
|
|
@@ -15877,10 +15772,10 @@ var rollout_plan_default = {
|
|
|
15877
15772
|
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)."
|
|
15878
15773
|
},
|
|
15879
15774
|
baseline: {
|
|
15880
|
-
version: "4.3.
|
|
15881
|
-
tag: "v4.3.
|
|
15882
|
-
commit: "
|
|
15883
|
-
npm: "@mutmutco/cli@4.3.
|
|
15775
|
+
version: "4.3.58",
|
|
15776
|
+
tag: "v4.3.58",
|
|
15777
|
+
commit: "aa4958ac3926",
|
|
15778
|
+
npm: "@mutmutco/cli@4.3.58"
|
|
15884
15779
|
},
|
|
15885
15780
|
exitCriterion: "fleet-n-of-n",
|
|
15886
15781
|
hubOnlyShortcut: "forbidden",
|
|
@@ -15897,14 +15792,14 @@ var rollout_plan_default = {
|
|
|
15897
15792
|
repo: "mutmutco/mmi-hub",
|
|
15898
15793
|
role: "canary",
|
|
15899
15794
|
schedule: "train",
|
|
15900
|
-
v3Target: "v4.3.
|
|
15795
|
+
v3Target: "v4.3.58"
|
|
15901
15796
|
}
|
|
15902
15797
|
],
|
|
15903
15798
|
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.",
|
|
15904
15799
|
rollback: {
|
|
15905
15800
|
independent: true,
|
|
15906
|
-
mechanism: "npm dist-tag latest -> 4.3.
|
|
15907
|
-
v3Target: "v4.3.
|
|
15801
|
+
mechanism: "npm dist-tag latest -> 4.3.58 and redeploy the Hub Lambda from tag v4.3.58 (aa4958ac3926); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
15802
|
+
v3Target: "v4.3.58 (@mutmutco/cli@4.3.58, tag commit aa4958ac3926 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
15908
15803
|
}
|
|
15909
15804
|
},
|
|
15910
15805
|
{
|
|
@@ -26539,6 +26434,11 @@ function rcandVersionStep(targets) {
|
|
|
26539
26434
|
function trainPlan(command, options = {}) {
|
|
26540
26435
|
const isHub = options.repo?.toLowerCase() === "mutmutco/mmi-hub";
|
|
26541
26436
|
const isDirect = options.releaseTrack === "direct" || options.releaseTrack === void 0 && isHub;
|
|
26437
|
+
const authority = {
|
|
26438
|
+
label: isHub ? "verify Hub master-admin train authority" : "verify project-admin or master train authority on this repo",
|
|
26439
|
+
command: "mmi-cli oracle org access role <owner/repo> --json",
|
|
26440
|
+
gated: true
|
|
26441
|
+
};
|
|
26542
26442
|
if (command === "rcand") {
|
|
26543
26443
|
if (isDirect) {
|
|
26544
26444
|
return [
|
|
@@ -26546,7 +26446,7 @@ function trainPlan(command, options = {}) {
|
|
|
26546
26446
|
];
|
|
26547
26447
|
}
|
|
26548
26448
|
return [
|
|
26549
|
-
|
|
26449
|
+
authority,
|
|
26550
26450
|
{ label: "verify current branch is development", gated: true },
|
|
26551
26451
|
rcandVersionStep(options),
|
|
26552
26452
|
{ label: "verify registry META for this project", command: "mmi-cli oracle org project get <owner/repo>", gated: true },
|
|
@@ -26559,7 +26459,7 @@ function trainPlan(command, options = {}) {
|
|
|
26559
26459
|
if (command === "release") {
|
|
26560
26460
|
if (isDirect) {
|
|
26561
26461
|
return [
|
|
26562
|
-
|
|
26462
|
+
authority,
|
|
26563
26463
|
{ label: "verify current branch is development", gated: true },
|
|
26564
26464
|
{ label: "verify registry META for this project", command: "mmi-cli oracle org project get <owner/repo>", gated: true },
|
|
26565
26465
|
{ label: "preflight required main secret names", command: "mmi-cli vault secrets preflight --stage main --repo <owner/repo>", gated: true },
|
|
@@ -26574,7 +26474,7 @@ function trainPlan(command, options = {}) {
|
|
|
26574
26474
|
}
|
|
26575
26475
|
if (options.dev) {
|
|
26576
26476
|
return [
|
|
26577
|
-
|
|
26477
|
+
authority,
|
|
26578
26478
|
{ label: "verify current branch is development", gated: true },
|
|
26579
26479
|
{ label: "guard: refuse if origin/rc carries content not in development (a dev -> main release would drop it)", command: "git rev-list --count --right-only --cherry-pick --no-merges origin/development...origin/rc", gated: true },
|
|
26580
26480
|
{ label: "verify registry META for this project", command: "mmi-cli oracle org project get <owner/repo>", gated: true },
|
|
@@ -26590,7 +26490,7 @@ function trainPlan(command, options = {}) {
|
|
|
26590
26490
|
];
|
|
26591
26491
|
}
|
|
26592
26492
|
return [
|
|
26593
|
-
|
|
26493
|
+
authority,
|
|
26594
26494
|
{ label: "verify current branch is rc", gated: true },
|
|
26595
26495
|
{ label: "verify registry META for this project", command: "mmi-cli oracle org project get <owner/repo>", gated: true },
|
|
26596
26496
|
{ label: "preflight required main secret names", command: "mmi-cli vault secrets preflight --stage main --repo <owner/repo>", gated: true },
|
|
@@ -26605,6 +26505,7 @@ function trainPlan(command, options = {}) {
|
|
|
26605
26505
|
];
|
|
26606
26506
|
}
|
|
26607
26507
|
return [
|
|
26508
|
+
authority,
|
|
26608
26509
|
{ label: "verify the fix is merged on development (the only hotfix origin)", gated: true },
|
|
26609
26510
|
// #6068: hotfix start/release run the SAME shared preflight as release/rcand, before any git mutation.
|
|
26610
26511
|
{ label: "verify registry META for this project", command: "mmi-cli oracle org project get <owner/repo>", gated: true },
|
|
@@ -30114,7 +30015,7 @@ function buildSetDeployPatch(_slug, input) {
|
|
|
30114
30015
|
}
|
|
30115
30016
|
var DEPLOY_STAGE_BRANCH = { dev: "development", rc: "rc", main: "main" };
|
|
30116
30017
|
function filelessTransitionGuide(repo, stage) {
|
|
30117
|
-
const authority =
|
|
30018
|
+
const authority = "Authority: a project-admin may complete this for their own repo; master may also do it.";
|
|
30118
30019
|
return [
|
|
30119
30020
|
`Fileless transition for ${repo} (${stage}):`,
|
|
30120
30021
|
` ${authority}`,
|
|
@@ -35588,15 +35489,9 @@ function writeError(res) {
|
|
|
35588
35489
|
|
|
35589
35490
|
// src/schedules-commands.ts
|
|
35590
35491
|
var import_promises5 = require("node:fs/promises");
|
|
35591
|
-
var import_node_child_process11 = require("node:child_process");
|
|
35592
|
-
var import_node_util6 = require("node:util");
|
|
35593
35492
|
init_clean_exit();
|
|
35594
35493
|
init_github_client();
|
|
35595
35494
|
init_cli_shared();
|
|
35596
|
-
var execFileP4 = (0, import_node_util6.promisify)(import_node_child_process11.execFile);
|
|
35597
|
-
var AWS_REGION = "eu-central-1";
|
|
35598
|
-
var AWS_TIMEOUT_MS = 3e4;
|
|
35599
|
-
var AWS_RETRY_DELAY_MS = 1500;
|
|
35600
35495
|
async function listWorkflows(client, repo) {
|
|
35601
35496
|
const all = [];
|
|
35602
35497
|
for (let page = 1; ; page += 1) {
|
|
@@ -35693,44 +35588,11 @@ async function githubEntries(client) {
|
|
|
35693
35588
|
drift.push(...reconciliation.map(renderDrift));
|
|
35694
35589
|
return { entries, incomplete, drift, reconciliation, readRepos, workflowNames: [...workflows.map((w) => w.name), ...unreadableNames], disabledWorkflowNames };
|
|
35695
35590
|
}
|
|
35696
|
-
async function awsJson(args) {
|
|
35697
|
-
const run = async () => {
|
|
35698
|
-
const { stdout } = await execFileP4("aws", [...args, "--region", AWS_REGION, "--output", "json"], {
|
|
35699
|
-
encoding: "utf8",
|
|
35700
|
-
windowsHide: true,
|
|
35701
|
-
timeout: AWS_TIMEOUT_MS
|
|
35702
|
-
});
|
|
35703
|
-
return JSON.parse(stdout);
|
|
35704
|
-
};
|
|
35705
|
-
try {
|
|
35706
|
-
return await run();
|
|
35707
|
-
} catch {
|
|
35708
|
-
await new Promise((resolve7) => setTimeout(resolve7, AWS_RETRY_DELAY_MS));
|
|
35709
|
-
return run();
|
|
35710
|
-
}
|
|
35711
|
-
}
|
|
35712
35591
|
async function awsEntries() {
|
|
35713
|
-
const
|
|
35714
|
-
|
|
35715
|
-
|
|
35716
|
-
|
|
35717
|
-
} catch (e) {
|
|
35718
|
-
incomplete.push(`aws: events list-rules failed \u2014 ${e.message}`);
|
|
35719
|
-
}
|
|
35720
|
-
let schedulerRead = false;
|
|
35721
|
-
try {
|
|
35722
|
-
const refs = awsScheduleRefs(await awsJson(["scheduler", "list-schedules"]));
|
|
35723
|
-
for (const ref of refs) {
|
|
35724
|
-
const args = ["scheduler", "get-schedule", "--name", ref.name, ...ref.group ? ["--group-name", ref.group] : []];
|
|
35725
|
-
const entry = awsScheduleEntry(await awsJson(args));
|
|
35726
|
-
if (entry) entries.push(entry);
|
|
35727
|
-
}
|
|
35728
|
-
schedulerRead = true;
|
|
35729
|
-
} catch (e) {
|
|
35730
|
-
incomplete.push(`aws: scheduler listing failed \u2014 ${e.message}`);
|
|
35731
|
-
}
|
|
35732
|
-
const reconciliation = unlauncheredLlmDrifts(entries);
|
|
35733
|
-
return { entries, incomplete, drift: reconciliation.map(renderDrift), reconciliation, schedulerRead };
|
|
35592
|
+
const inventory = await fetchScheduleInventory(registryClientDeps(await loadConfig()));
|
|
35593
|
+
if (!inventory) return { entries: [], incomplete: ["aws: Hub schedule inventory unavailable or unauthenticated"], drift: [], reconciliation: [], schedulerRead: false };
|
|
35594
|
+
const reconciliation = unlauncheredLlmDrifts(inventory.entries);
|
|
35595
|
+
return { ...inventory, reconciliation, drift: reconciliation.map(renderDrift) };
|
|
35734
35596
|
}
|
|
35735
35597
|
async function readOrFail(read) {
|
|
35736
35598
|
try {
|
|
@@ -36587,8 +36449,13 @@ async function resolveStageBuildSecrets(input) {
|
|
|
36587
36449
|
out[envKey] = fromVault;
|
|
36588
36450
|
continue;
|
|
36589
36451
|
}
|
|
36452
|
+
const fromGitHub = await input.githubToken?.();
|
|
36453
|
+
if (fromGitHub) {
|
|
36454
|
+
out[envKey] = fromGitHub;
|
|
36455
|
+
continue;
|
|
36456
|
+
}
|
|
36590
36457
|
missing.push(
|
|
36591
|
-
`${envKey}=${GITHUB_PACKAGES_TOKEN_REF} (
|
|
36458
|
+
`${envKey}=${GITHUB_PACKAGES_TOKEN_REF} (sign in with gh auth login using a package-readable GitHub identity, or provide process env ${envKey} or stageless project vault secret ${envKey}; npm.pkg.github.com still requires package read permission)`
|
|
36592
36459
|
);
|
|
36593
36460
|
continue;
|
|
36594
36461
|
}
|
|
@@ -36622,6 +36489,7 @@ async function fetchVaultRef(fetchVault, ref) {
|
|
|
36622
36489
|
}
|
|
36623
36490
|
|
|
36624
36491
|
// src/stage-commands.ts
|
|
36492
|
+
init_github_client();
|
|
36625
36493
|
function registerStageCommands(program3) {
|
|
36626
36494
|
function stagePortFromArgv() {
|
|
36627
36495
|
const raw = rawValue("--port", "");
|
|
@@ -36681,7 +36549,8 @@ function registerStageCommands(program3) {
|
|
|
36681
36549
|
const d = makeSecretsDeps(cfg);
|
|
36682
36550
|
const merge = await resolveStageBuildSecrets({
|
|
36683
36551
|
requiredBuildSecrets: required,
|
|
36684
|
-
fetchVault: (key, opts) => fetchSecretValue(d, key, opts ?? {})
|
|
36552
|
+
fetchVault: (key, opts) => fetchSecretValue(d, key, opts ?? {}),
|
|
36553
|
+
githubToken
|
|
36685
36554
|
});
|
|
36686
36555
|
return Object.keys(merge).length ? merge : void 0;
|
|
36687
36556
|
}
|
|
@@ -37083,7 +36952,7 @@ function renderVerifySecrets(body) {
|
|
|
37083
36952
|
}
|
|
37084
36953
|
|
|
37085
36954
|
// src/command-register-collaboration.ts
|
|
37086
|
-
var
|
|
36955
|
+
var import_node_child_process15 = require("node:child_process");
|
|
37087
36956
|
var import_node_fs41 = require("node:fs");
|
|
37088
36957
|
var import_promises7 = require("node:fs/promises");
|
|
37089
36958
|
init_clean_exit();
|
|
@@ -37469,12 +37338,12 @@ function boardAdvanceFailureMessage(result) {
|
|
|
37469
37338
|
}
|
|
37470
37339
|
|
|
37471
37340
|
// src/test-policy-core.ts
|
|
37472
|
-
var
|
|
37341
|
+
var import_node_child_process12 = require("node:child_process");
|
|
37473
37342
|
var import_node_fs35 = require("node:fs");
|
|
37474
37343
|
var import_node_path33 = require("node:path");
|
|
37475
37344
|
|
|
37476
37345
|
// src/test-command-policy-shared.mjs
|
|
37477
|
-
var
|
|
37346
|
+
var import_node_child_process11 = require("node:child_process");
|
|
37478
37347
|
var TEST_COMMAND_CLASS = "test";
|
|
37479
37348
|
var TRAILER_KEY = "Test-Policy-Override";
|
|
37480
37349
|
var OVERRIDE_RE = /^Test-Policy-Override:\s*(.+)$/im;
|
|
@@ -37591,7 +37460,7 @@ function evaluateTestCommandPolicy({ paths, mandatory, regulated = true, overrid
|
|
|
37591
37460
|
};
|
|
37592
37461
|
}
|
|
37593
37462
|
function git(args, cwd) {
|
|
37594
|
-
return (0,
|
|
37463
|
+
return (0, import_node_child_process11.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
37595
37464
|
}
|
|
37596
37465
|
function parseScope(value) {
|
|
37597
37466
|
const scoped = /^\[([^\]]*)\]\s*([\s\S]*)$/.exec(value);
|
|
@@ -38090,14 +37959,14 @@ function evaluate(changed, policy, present = () => false) {
|
|
|
38090
37959
|
return findings;
|
|
38091
37960
|
}
|
|
38092
37961
|
function git2(args, cwd) {
|
|
38093
|
-
return (0,
|
|
37962
|
+
return (0, import_node_child_process12.execFileSync)("git", args, { windowsHide: true, cwd, encoding: "utf8", maxBuffer: 32 * 1024 * 1024 });
|
|
38094
37963
|
}
|
|
38095
37964
|
var COAUTHOR_KEY = "Co-authored-by";
|
|
38096
37965
|
var GH_MESSAGE_SEPARATOR = /^-{5,}$/;
|
|
38097
37966
|
var LIFTED_KEYS = new RegExp(`^(?:${TRAILER_KEY}|${COAUTHOR_KEY}):`, "i");
|
|
38098
37967
|
function parseTrailers(message2, cwd) {
|
|
38099
37968
|
try {
|
|
38100
|
-
return (0,
|
|
37969
|
+
return (0, import_node_child_process12.execFileSync)("git", ["interpret-trailers", "--parse", "--unfold"], {
|
|
38101
37970
|
windowsHide: true,
|
|
38102
37971
|
cwd,
|
|
38103
37972
|
input: message2,
|
|
@@ -38853,7 +38722,7 @@ function postMergeReconWarnings(input) {
|
|
|
38853
38722
|
}
|
|
38854
38723
|
|
|
38855
38724
|
// src/review-verdict.ts
|
|
38856
|
-
var
|
|
38725
|
+
var import_node_child_process13 = require("node:child_process");
|
|
38857
38726
|
var import_node_fs38 = require("node:fs");
|
|
38858
38727
|
var import_node_os19 = require("node:os");
|
|
38859
38728
|
var import_node_path36 = require("node:path");
|
|
@@ -38953,8 +38822,8 @@ async function checkPrReview(number, repo, head, deps = {
|
|
|
38953
38822
|
}
|
|
38954
38823
|
function computePrPatchId(number, repo) {
|
|
38955
38824
|
return new Promise((resolve7, reject) => {
|
|
38956
|
-
const gh = (0,
|
|
38957
|
-
const git3 = (0,
|
|
38825
|
+
const gh = (0, import_node_child_process13.spawn)("gh", ["pr", "diff", number, "--repo", repo], { windowsHide: true, stdio: ["ignore", "pipe", "pipe"] });
|
|
38826
|
+
const git3 = (0, import_node_child_process13.spawn)("git", ["patch-id", "--stable"], { windowsHide: true, stdio: ["pipe", "pipe", "pipe"] });
|
|
38958
38827
|
let out = "";
|
|
38959
38828
|
let ghErr = "";
|
|
38960
38829
|
let gitErr = "";
|
|
@@ -39036,7 +38905,7 @@ async function postPrCommentFromFile(number, repo, body) {
|
|
|
39036
38905
|
}
|
|
39037
38906
|
|
|
39038
38907
|
// src/pr-create-docs-check.ts
|
|
39039
|
-
var
|
|
38908
|
+
var import_node_child_process14 = require("node:child_process");
|
|
39040
38909
|
init_cli_shared();
|
|
39041
38910
|
var GIT_TIMEOUT_MS2 = 15e3;
|
|
39042
38911
|
function catFileBatch(root, ref, paths) {
|
|
@@ -39044,7 +38913,7 @@ function catFileBatch(root, ref, paths) {
|
|
|
39044
38913
|
return new Promise((resolve7) => {
|
|
39045
38914
|
const chunks = [];
|
|
39046
38915
|
let settled = false;
|
|
39047
|
-
const child2 = (0,
|
|
38916
|
+
const child2 = (0, import_node_child_process14.spawn)("git", ["-C", root, "cat-file", "--batch", "--buffer"], { windowsHide: true });
|
|
39048
38917
|
const finish = () => {
|
|
39049
38918
|
if (settled) return;
|
|
39050
38919
|
settled = true;
|
|
@@ -40191,7 +40060,7 @@ function scheduleRelatedDiscovery(o) {
|
|
|
40191
40060
|
try {
|
|
40192
40061
|
const args = ["issue", "discover-related", "--number", String(o.number), "--title", o.title, "--body", o.body, "--fail-soft"];
|
|
40193
40062
|
if (o.repo) args.push("--repo", o.repo);
|
|
40194
|
-
spawnDetachedSelf(args, { spawn:
|
|
40063
|
+
spawnDetachedSelf(args, { spawn: import_node_child_process15.spawn, execPath: process.execPath, scriptPath: process.argv[1] }, { cwd: process.cwd() });
|
|
40195
40064
|
} catch {
|
|
40196
40065
|
}
|
|
40197
40066
|
}
|
|
@@ -41887,7 +41756,7 @@ ${SSH_RECIPE_AGENT_NOTE}`);
|
|
|
41887
41756
|
}
|
|
41888
41757
|
|
|
41889
41758
|
// src/dist-drift.ts
|
|
41890
|
-
var
|
|
41759
|
+
var import_node_child_process16 = require("node:child_process");
|
|
41891
41760
|
var import_node_crypto13 = require("node:crypto");
|
|
41892
41761
|
var import_node_fs44 = require("node:fs");
|
|
41893
41762
|
var import_node_os20 = require("node:os");
|
|
@@ -42032,7 +41901,7 @@ function bomPathFor(root) {
|
|
|
42032
41901
|
}
|
|
42033
41902
|
}
|
|
42034
41903
|
function rebuildTo(packageRoot, outDir) {
|
|
42035
|
-
(0,
|
|
41904
|
+
(0, import_node_child_process16.execFileSync)(process.execPath, ["build.mjs"], {
|
|
42036
41905
|
cwd: packageRoot,
|
|
42037
41906
|
env: { ...process.env, MMI_DIST_OUTDIR: outDir },
|
|
42038
41907
|
windowsHide: true,
|
|
@@ -42259,7 +42128,7 @@ function registerSchedulesLiftCommand(program3, deps = {}) {
|
|
|
42259
42128
|
}
|
|
42260
42129
|
|
|
42261
42130
|
// src/spawn-policy-core.ts
|
|
42262
|
-
var
|
|
42131
|
+
var import_node_child_process17 = require("node:child_process");
|
|
42263
42132
|
var import_node_fs45 = require("node:fs");
|
|
42264
42133
|
var import_node_path43 = require("node:path");
|
|
42265
42134
|
var SPAWNERS = ["spawn", "spawnSync", "exec", "execSync", "execFile", "execFileSync"];
|
|
@@ -42330,7 +42199,7 @@ function findViolationsInSource(raw) {
|
|
|
42330
42199
|
return found;
|
|
42331
42200
|
}
|
|
42332
42201
|
function policedFiles(root) {
|
|
42333
|
-
const r = (0,
|
|
42202
|
+
const r = (0, import_node_child_process17.spawnSync)("git", ["ls-files", "-z", "--cached", "--others", "--exclude-standard"], {
|
|
42334
42203
|
cwd: root,
|
|
42335
42204
|
encoding: "utf8",
|
|
42336
42205
|
windowsHide: true,
|
|
@@ -42636,50 +42505,6 @@ init_house_map();
|
|
|
42636
42505
|
// src/hotfix-apply.ts
|
|
42637
42506
|
var import_promises9 = require("node:fs/promises");
|
|
42638
42507
|
|
|
42639
|
-
// src/slack-alert.ts
|
|
42640
|
-
var SSM_REGION = "eu-central-1";
|
|
42641
|
-
var SSM_TOKEN_PARAM = "/mmi-future/_org/slack/SLACK_BOT_TOKEN";
|
|
42642
|
-
var SSM_CHANNEL_PARAM = "/mmi-future/_org/slack/SLACK_ALERTS_CHANNEL";
|
|
42643
|
-
var SLACK_TIMEOUT_MS = 1e4;
|
|
42644
|
-
async function readSsmParameter(deps, name, decrypt) {
|
|
42645
|
-
const args = [
|
|
42646
|
-
"ssm",
|
|
42647
|
-
"get-parameter",
|
|
42648
|
-
"--region",
|
|
42649
|
-
SSM_REGION,
|
|
42650
|
-
"--name",
|
|
42651
|
-
name,
|
|
42652
|
-
"--query",
|
|
42653
|
-
"Parameter.Value",
|
|
42654
|
-
"--output",
|
|
42655
|
-
"text",
|
|
42656
|
-
...decrypt ? ["--with-decryption"] : []
|
|
42657
|
-
];
|
|
42658
|
-
const value = (await deps.run("aws", args)).trim();
|
|
42659
|
-
if (!value || value === "None") throw new Error(`SSM parameter ${name} is empty`);
|
|
42660
|
-
return value;
|
|
42661
|
-
}
|
|
42662
|
-
async function postToChannel(deps, channel, text) {
|
|
42663
|
-
const resolved = channel.trim();
|
|
42664
|
-
if (!resolved || resolved === "None") throw new Error("no Slack channel resolved");
|
|
42665
|
-
const token = await readSsmParameter(deps, SSM_TOKEN_PARAM, true);
|
|
42666
|
-
const fetchImpl = deps.fetchImpl ?? fetch;
|
|
42667
|
-
const res = await fetchImpl("https://slack.com/api/chat.postMessage", {
|
|
42668
|
-
method: "POST",
|
|
42669
|
-
headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json; charset=utf-8" },
|
|
42670
|
-
body: JSON.stringify({ channel: resolved, text, unfurl_links: false }),
|
|
42671
|
-
signal: AbortSignal.timeout(SLACK_TIMEOUT_MS)
|
|
42672
|
-
});
|
|
42673
|
-
const json = await res.json().catch(() => ({}));
|
|
42674
|
-
if (!json.ok) throw new Error(`slack postMessage failed: ${json.error ?? `http ${res.status}`}`);
|
|
42675
|
-
return { status: "posted", note: "posted" };
|
|
42676
|
-
}
|
|
42677
|
-
async function postToAlertsChannel(deps, text) {
|
|
42678
|
-
const channel = await readSsmParameter(deps, SSM_CHANNEL_PARAM, false);
|
|
42679
|
-
await postToChannel(deps, channel, text);
|
|
42680
|
-
return { status: "posted", note: "posted to the alerts channel" };
|
|
42681
|
-
}
|
|
42682
|
-
|
|
42683
42508
|
// src/release-announce.ts
|
|
42684
42509
|
var ANNOUNCE_REPO = "mutmutco/MMI-Hub";
|
|
42685
42510
|
var MAX_BULLETS = 6;
|
|
@@ -42786,12 +42611,6 @@ async function announceRelease(deps, args) {
|
|
|
42786
42611
|
if (args.summaryFile) {
|
|
42787
42612
|
if (!deps.readFile) throw new Error("summary file given but deps.readFile is missing");
|
|
42788
42613
|
lines2 = summaryFileLines(await deps.readFile(args.summaryFile), neutralize);
|
|
42789
|
-
if (deps.removeFile) {
|
|
42790
|
-
try {
|
|
42791
|
-
await deps.removeFile(args.summaryFile);
|
|
42792
|
-
} catch {
|
|
42793
|
-
}
|
|
42794
|
-
}
|
|
42795
42614
|
}
|
|
42796
42615
|
if (lines2.length === 0) {
|
|
42797
42616
|
if (target.kind !== "alerts") {
|
|
@@ -42807,12 +42626,16 @@ async function announceRelease(deps, args) {
|
|
|
42807
42626
|
releaseUrl,
|
|
42808
42627
|
...target.kind === "channel" ? { language: target.language } : {}
|
|
42809
42628
|
});
|
|
42810
|
-
|
|
42811
|
-
|
|
42812
|
-
|
|
42629
|
+
const delivery = await deps.postAnnouncement({ repo: args.repo, tag: args.tag, text });
|
|
42630
|
+
if (delivery === "skipped") return { status: "skipped", note: missingChannelNote(args.repo) };
|
|
42631
|
+
if (args.summaryFile && deps.removeFile) {
|
|
42632
|
+
try {
|
|
42633
|
+
await deps.removeFile(args.summaryFile);
|
|
42634
|
+
} catch {
|
|
42635
|
+
}
|
|
42813
42636
|
}
|
|
42814
|
-
|
|
42815
|
-
return { status: "announced", note:
|
|
42637
|
+
const destination = target.kind === "alerts" ? "alerts channel" : "project release channel";
|
|
42638
|
+
return { status: "announced", note: `${delivery === "already-posted" ? "already announced" : "announced"} ${args.tag} to the ${destination}` };
|
|
42816
42639
|
} catch (e) {
|
|
42817
42640
|
return { status: "failed", note: `announce failed (release unaffected): ${e.message}` };
|
|
42818
42641
|
}
|
|
@@ -43939,12 +43762,12 @@ async function findInFlightHotfixVersion(deps, ctx, latestMainTag, workflows = H
|
|
|
43939
43762
|
}
|
|
43940
43763
|
|
|
43941
43764
|
// src/hotfix-coverage.ts
|
|
43942
|
-
var
|
|
43765
|
+
var import_node_child_process18 = require("node:child_process");
|
|
43943
43766
|
var CHERRY_TRAILER = /\(cherry picked from commit ([0-9a-f]{7,40})\)/g;
|
|
43944
43767
|
function checkHotfixCoverage(options = {}) {
|
|
43945
43768
|
const { cwd = process.cwd(), mainRef = "origin/main", rcRef = "origin/rc", manifestPaths = [] } = options;
|
|
43946
43769
|
const ack = (options.ack ?? []).filter(Boolean);
|
|
43947
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
43770
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process18.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
43948
43771
|
const revList = (range) => {
|
|
43949
43772
|
const out = git3(["rev-list", "--no-merges", range]).trim();
|
|
43950
43773
|
return out ? out.split("\n") : [];
|
|
@@ -44012,7 +43835,7 @@ function checkHotfixCoverage(options = {}) {
|
|
|
44012
43835
|
}
|
|
44013
43836
|
function checkHotfixCarries(options) {
|
|
44014
43837
|
const { cwd = process.cwd(), branch, baseRef, targets } = options;
|
|
44015
|
-
const git3 = options.git ?? ((args, opts) => (0,
|
|
43838
|
+
const git3 = options.git ?? ((args, opts) => (0, import_node_child_process18.execFileSync)("git", args, { cwd, encoding: "utf8", input: opts?.input, stdio: ["pipe", "pipe", "pipe"] }));
|
|
44016
43839
|
const isAncestor = (sha, ref) => {
|
|
44017
43840
|
try {
|
|
44018
43841
|
git3(["merge-base", "--is-ancestor", sha, ref]);
|
|
@@ -44282,6 +44105,15 @@ function trainApplyDeps() {
|
|
|
44282
44105
|
// registry releaseChannel META for a product repo — best-effort inside announceRelease itself.
|
|
44283
44106
|
announce: (args) => announceRelease({
|
|
44284
44107
|
run: async (file, cmdArgs) => (await execFileP(file, cmdArgs, { timeout: GH_TRAIN_TIMEOUT_MS })).stdout,
|
|
44108
|
+
postAnnouncement: async (payload) => {
|
|
44109
|
+
const res = await releaseAnnouncement(payload, registryClientDeps(await loadConfig()));
|
|
44110
|
+
const body = res.body;
|
|
44111
|
+
if (!res.ok) throw new Error(body?.error ?? `Hub announcement failed (HTTP ${res.status}); verify delivery before retrying`);
|
|
44112
|
+
if (body?.ok !== true || body.status !== "posted" && body?.status !== "already-posted" && body?.status !== "skipped") {
|
|
44113
|
+
throw new Error("Hub announcement returned an unverified delivery result; do not resend");
|
|
44114
|
+
}
|
|
44115
|
+
return body.status;
|
|
44116
|
+
},
|
|
44285
44117
|
readFile: (path2) => (0, import_promises10.readFile)(path2, "utf8"),
|
|
44286
44118
|
removeFile: (path2) => (0, import_promises10.unlink)(path2),
|
|
44287
44119
|
// #6521/#6523: the project's own release channel AND releaseLanguage, read from registry META in ONE
|
|
@@ -44573,7 +44405,7 @@ function registerTrainCommandsAndInventory(program3) {
|
|
|
44573
44405
|
}
|
|
44574
44406
|
function registerTrainOperationsCommands(program3, runProjectInfoSyncCallback) {
|
|
44575
44407
|
for (const commandName of ["rcand", "release"]) {
|
|
44576
|
-
const trainCmd = program3.command(commandName).description(`plan ${commandName} train operations; mutations require explicit
|
|
44408
|
+
const trainCmd = program3.command(commandName).description(`plan ${commandName} train operations; mutations require explicit project-admin or master approval`).option("--json", "machine-readable output").option("--watch", "block on the deploy/publish workflow runs and report their outcomes").option("--apply", "execute the guarded repo-authorized train after explicit approval (Hub: master only)").option("--resume", commandName === "rcand" ? "finish a candidate whose immutable public rc tag passed policy but origin/rc was not pushed (#3881)" : "finish a partial release or its protected post-release alignment without re-cutting, republishing, or redeploying (#3851/#3885)").option("--out <path>", "write the terminal result (--apply, --resume, --abort, --retry-publish) to this file as UTF-8 (no BOM) instead of stdout \u2014 the shell-free receipt path (#5983/#6068)");
|
|
44577
44409
|
const RELEASE_ONLY_FLAGS = [
|
|
44578
44410
|
{ flags: "--announce-summary-file <path>", description: "agent-curated 3-6 line release Slack summary; required for a new MMI-Hub --apply (#883/#3901) and for a product repo whose registry META sets `releaseChannel` (#6523), in its `releaseLanguage`; nothing is posted to a project channel without it" },
|
|
44579
44411
|
{ flags: "--ack <shas>", description: "comma-separated dev shas a human verified are in the candidate, overriding the hotfix-coverage guard for a conflicted port whose -x trailer was lost (#958)" },
|
|
@@ -45914,8 +45746,8 @@ ${filelessTransitionGuide(target, o.stage)}`
|
|
|
45914
45746
|
}
|
|
45915
45747
|
return reportWrite("org project set-deploy", res);
|
|
45916
45748
|
});
|
|
45917
|
-
var projectTenantTasks = project.command("tenant-tasks").description("project-admin self-declare of tenant tasks for your own repo
|
|
45918
|
-
projectTenantTasks.command("declare <name>").description(
|
|
45749
|
+
var projectTenantTasks = project.command("tenant-tasks").description("project-admin self-declare of tenant tasks for every stage of your own repo \u2014 new-task-only; editing an existing task stays master-only (`org project set --var tenantTasks=...`)");
|
|
45750
|
+
projectTenantTasks.command("declare <name>").description("register a NEW tenant task \u2014 becomes runnable via `runtime tenant control \u2026 run-task` on its declared dev/rc/main stages. Body shape {service,command[],stages[],timeoutSeconds?,artifact?}; required artifact tasks must carry {artifact} in the command argv.").option("--service <name>", "service in the tenant runtime the task runs in (required unless --var carries it)").option("--command <argv...>", "task command as argv (repeatable; required unless --var carries it)").option("--stages <list>", "comma-separated dev,rc,main stages this task may run on (required unless --var carries it)").option("--timeout-seconds <n>", "optional wall-clock ceiling 1..3600").option("--artifact <none|required>", "artifact contract (default none; required tasks must contain {artifact} in argv)").option("--var <json>", "full task object {service,command[],stages[],timeoutSeconds?,artifact?} \u2014 use instead of the individual flags").option("--repo <owner/repo>", "target repo (defaults to the current repo)").option("--json", "machine-readable output").action(async (name, o) => {
|
|
45919
45751
|
const cfg = await loadConfig();
|
|
45920
45752
|
let target;
|
|
45921
45753
|
try {
|
package/package.json
CHANGED