@mutmutco/cli 4.1.5 → 4.1.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 +127 -35
- package/package.json +1 -1
package/dist/main.cjs
CHANGED
|
@@ -13152,10 +13152,10 @@ var rollout_plan_default = {
|
|
|
13152
13152
|
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)."
|
|
13153
13153
|
},
|
|
13154
13154
|
baseline: {
|
|
13155
|
-
version: "4.1.
|
|
13156
|
-
tag: "v4.1.
|
|
13157
|
-
commit: "
|
|
13158
|
-
npm: "@mutmutco/cli@4.1.
|
|
13155
|
+
version: "4.1.7",
|
|
13156
|
+
tag: "v4.1.7",
|
|
13157
|
+
commit: "3811b46c48ba",
|
|
13158
|
+
npm: "@mutmutco/cli@4.1.7"
|
|
13159
13159
|
},
|
|
13160
13160
|
exitCriterion: "fleet-n-of-n",
|
|
13161
13161
|
hubOnlyShortcut: "forbidden",
|
|
@@ -13172,14 +13172,14 @@ var rollout_plan_default = {
|
|
|
13172
13172
|
repo: "mutmutco/mmi-hub",
|
|
13173
13173
|
role: "canary",
|
|
13174
13174
|
schedule: "train",
|
|
13175
|
-
v3Target: "v4.1.
|
|
13175
|
+
v3Target: "v4.1.7"
|
|
13176
13176
|
}
|
|
13177
13177
|
],
|
|
13178
13178
|
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.",
|
|
13179
13179
|
rollback: {
|
|
13180
13180
|
independent: true,
|
|
13181
|
-
mechanism: "npm dist-tag latest -> 4.1.
|
|
13182
|
-
v3Target: "v4.1.
|
|
13181
|
+
mechanism: "npm dist-tag latest -> 4.1.7 and redeploy the Hub Lambda from tag v4.1.7 (3811b46c48ba); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
13182
|
+
v3Target: "v4.1.7 (@mutmutco/cli@4.1.7, tag commit 3811b46c48ba \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
13183
13183
|
}
|
|
13184
13184
|
},
|
|
13185
13185
|
{
|
|
@@ -15941,6 +15941,40 @@ var HUB_REPO3 = "mutmutco/MMI-Hub";
|
|
|
15941
15941
|
function isHubControlRepo(repo) {
|
|
15942
15942
|
return repo.toLowerCase() === HUB_REPO3.toLowerCase();
|
|
15943
15943
|
}
|
|
15944
|
+
function supportsReleaseAbort(repo, meta, branchHints) {
|
|
15945
|
+
if (isHubControlRepo(repo)) return true;
|
|
15946
|
+
if (meta.deployModel !== "registry-publish") return false;
|
|
15947
|
+
return resolveReleaseTrack(meta, branchHints, repo) === "direct";
|
|
15948
|
+
}
|
|
15949
|
+
function resolveReleaseAbortNpmPackage(meta, repo) {
|
|
15950
|
+
if (isHubControlRepo(repo)) return "@mutmutco/cli";
|
|
15951
|
+
const publishDir = typeof meta.publishDir === "string" && meta.publishDir.trim() ? meta.publishDir.trim() : ".";
|
|
15952
|
+
try {
|
|
15953
|
+
const pkg = JSON.parse((0, import_node_fs15.readFileSync)((0, import_node_path14.join)(publishDir, "package.json"), "utf8"));
|
|
15954
|
+
const name = pkg.name?.trim();
|
|
15955
|
+
if (!name) throw new Error("missing name field");
|
|
15956
|
+
return name;
|
|
15957
|
+
} catch (e) {
|
|
15958
|
+
throw new Error(
|
|
15959
|
+
`release --abort: cannot read npm publish name from ${publishDir}/package.json (${e instanceof Error ? e.message : String(e)}); nothing was written`
|
|
15960
|
+
);
|
|
15961
|
+
}
|
|
15962
|
+
}
|
|
15963
|
+
async function proveNpmVersionUnpublished(deps, packageName, version, tag) {
|
|
15964
|
+
try {
|
|
15965
|
+
const published = clean2(await deps.run("npm", ["view", `${packageName}@${version}`, "version", "--json"]));
|
|
15966
|
+
if (published) {
|
|
15967
|
+
throw new Error(`release --abort: ${packageName}@${version} is already published; ${tag} cannot be reused`);
|
|
15968
|
+
}
|
|
15969
|
+
throw new Error("npm registry returned an empty successful response");
|
|
15970
|
+
} catch (error) {
|
|
15971
|
+
const detail = `${error instanceof Error ? error.message : String(error)} ${String(error.stderr ?? "")}`;
|
|
15972
|
+
if (!/E404|not found|No match found/i.test(detail)) {
|
|
15973
|
+
if (/already published/.test(detail)) throw error;
|
|
15974
|
+
throw new Error(`release --abort: npm publish absence could not be proven (${detail.trim()}); nothing was written`);
|
|
15975
|
+
}
|
|
15976
|
+
}
|
|
15977
|
+
}
|
|
15944
15978
|
function projectGetFailureText(e) {
|
|
15945
15979
|
const err = e;
|
|
15946
15980
|
return [err.message, err.stderr, err.stdout].filter(Boolean).join(" ");
|
|
@@ -16387,8 +16421,9 @@ function partialTrainRecoveryError(cause, input) {
|
|
|
16387
16421
|
- origin/${branch}: NOT pushed
|
|
16388
16422
|
- ${releaseState}
|
|
16389
16423
|
` + deployLine;
|
|
16390
|
-
const
|
|
16391
|
-
|
|
16424
|
+
const releaseAbortEligible = input.meta ? supportsReleaseAbort(input.repo, input.meta, input.branchHints) : isHubControlRepo(input.repo);
|
|
16425
|
+
const failedAbortEligibleMainGate = input.stage === "main" && releaseAbortEligible && /^required train check failed:/i.test(causeMessage);
|
|
16426
|
+
if (failedAbortEligibleMainGate) {
|
|
16392
16427
|
return new Error(
|
|
16393
16428
|
`${causeMessage}
|
|
16394
16429
|
|
|
@@ -17229,7 +17264,7 @@ async function gateTrueMergeCommit(deps, ctx, tag, releaseSha, requiredChecks) {
|
|
|
17229
17264
|
}
|
|
17230
17265
|
}
|
|
17231
17266
|
}
|
|
17232
|
-
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe) {
|
|
17267
|
+
async function completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, startBranch, preFold, tagProbe, branchHints) {
|
|
17233
17268
|
const resumeCommand = options.dev ? "mmi-cli devops release --dev --apply" : "mmi-cli devops release --apply";
|
|
17234
17269
|
try {
|
|
17235
17270
|
await verifyPublishDryRun(deps, ctx, meta, deployModel);
|
|
@@ -17265,16 +17300,17 @@ async function completeMainRelease(deps, ctx, meta, deployModel, watch, options,
|
|
|
17265
17300
|
}
|
|
17266
17301
|
const tagPushSince = (deps.now ?? Date.now)();
|
|
17267
17302
|
let checks;
|
|
17303
|
+
const recoveryInput = { repo: ctx.repo, tag, stage: "main", deployModel, meta, branchHints };
|
|
17268
17304
|
try {
|
|
17269
17305
|
checks = await waitForRequiredTrainChecks(deps, ctx, releaseSha, requiredChecks, tagPush.pushed ? tagPushSince : void 0);
|
|
17270
17306
|
} catch (e) {
|
|
17271
|
-
throw partialTrainRecoveryError(e,
|
|
17307
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17272
17308
|
}
|
|
17273
17309
|
if (trueMergeGateNote) checks = `${trueMergeGateNote}; ${checks}`;
|
|
17274
17310
|
try {
|
|
17275
17311
|
await runGitPush(deps, ["push", "origin", "main"]);
|
|
17276
17312
|
} catch (e) {
|
|
17277
|
-
throw partialTrainRecoveryError(e,
|
|
17313
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17278
17314
|
}
|
|
17279
17315
|
const releaseUrl = clean2(await deps.run("gh", ["release", "create", tag, "--target", "main", "--generate-notes", "--latest", "--repo", ctx.repo])) || void 0;
|
|
17280
17316
|
await verifyPublishedRelease(deps, ctx.repo, tag, "main", releaseSha);
|
|
@@ -17446,16 +17482,17 @@ async function runReleaseResume(deps, options = {}) {
|
|
|
17446
17482
|
}
|
|
17447
17483
|
const steps = [];
|
|
17448
17484
|
let requiredChecks;
|
|
17485
|
+
const recoveryInput = { repo: ctx.repo, tag, stage: "main", deployModel, meta, branchHints };
|
|
17449
17486
|
try {
|
|
17450
17487
|
requiredChecks = await discoverRequiredCheckContexts(deps, ctx, "main");
|
|
17451
17488
|
} catch (e) {
|
|
17452
|
-
throw partialTrainRecoveryError(e,
|
|
17489
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17453
17490
|
}
|
|
17454
17491
|
assertTagAddressableRequiredContexts(deps, requiredChecks, ctx.repo);
|
|
17455
17492
|
try {
|
|
17456
17493
|
steps.push(await waitForRequiredTrainChecks(deps, ctx, tagSha, requiredChecks, void 0));
|
|
17457
17494
|
} catch (e) {
|
|
17458
|
-
throw partialTrainRecoveryError(e,
|
|
17495
|
+
throw partialTrainRecoveryError(e, recoveryInput);
|
|
17459
17496
|
}
|
|
17460
17497
|
await runGitPush(deps, ["push", "origin", `${tagSha}:refs/heads/main`]);
|
|
17461
17498
|
steps.push(`pushed ${tagSha.slice(0, 12)} to origin/main`);
|
|
@@ -17500,8 +17537,12 @@ async function runReleaseAbort(deps, options = {}) {
|
|
|
17500
17537
|
throw new Error("release --abort requires --apply after explicit approval; nothing was written");
|
|
17501
17538
|
}
|
|
17502
17539
|
const ctx = await buildTrainApplyContext(deps);
|
|
17503
|
-
|
|
17504
|
-
|
|
17540
|
+
const meta = requireProjectMetaForTrain(await loadProjectMeta(deps, ctx), ctx.repo);
|
|
17541
|
+
const branchHints = await loadReleaseTrackBranchHints(deps);
|
|
17542
|
+
if (!supportsReleaseAbort(ctx.repo, meta, branchHints)) {
|
|
17543
|
+
throw new Error(
|
|
17544
|
+
"release --abort is limited to mutmutco/MMI-Hub and eligible direct-track registry-publish repos until other release tracks define equivalent publish-absence proof"
|
|
17545
|
+
);
|
|
17505
17546
|
}
|
|
17506
17547
|
await requireCleanTree(deps);
|
|
17507
17548
|
if (await currentBranch(deps) !== "main") {
|
|
@@ -17536,19 +17577,8 @@ async function runReleaseAbort(deps, options = {}) {
|
|
|
17536
17577
|
throw new Error(`release --abort: ${tag} is released or its unpublished state could not be proven; nothing was written`);
|
|
17537
17578
|
}
|
|
17538
17579
|
const version = tag.slice(1);
|
|
17539
|
-
|
|
17540
|
-
|
|
17541
|
-
if (published) {
|
|
17542
|
-
throw new Error(`release --abort: @mutmutco/cli@${version} is already published; ${tag} cannot be reused`);
|
|
17543
|
-
}
|
|
17544
|
-
throw new Error("npm registry returned an empty successful response");
|
|
17545
|
-
} catch (error) {
|
|
17546
|
-
const detail = `${error instanceof Error ? error.message : String(error)} ${String(error.stderr ?? "")}`;
|
|
17547
|
-
if (!/E404|not found|No match found/i.test(detail)) {
|
|
17548
|
-
if (/already published/.test(detail)) throw error;
|
|
17549
|
-
throw new Error(`release --abort: npm publish absence could not be proven (${detail.trim()}); nothing was written`);
|
|
17550
|
-
}
|
|
17551
|
-
}
|
|
17580
|
+
const npmPackage = resolveReleaseAbortNpmPackage(meta, ctx.repo);
|
|
17581
|
+
await proveNpmVersionUnpublished(deps, npmPackage, version, tag);
|
|
17552
17582
|
await runGitPush(deps, ["push", "origin", "--delete", tag]);
|
|
17553
17583
|
if (await probeRemoteTag(deps, tag)) {
|
|
17554
17584
|
throw new Error(`release --abort: origin still reports ${tag} after deletion; local state was preserved`);
|
|
@@ -17710,7 +17740,7 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
17710
17740
|
const releaseSha3 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
17711
17741
|
return { versionFold: versionFold3, releaseSha: releaseSha3 };
|
|
17712
17742
|
});
|
|
17713
|
-
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2 } = await completeMainRelease(deps, ctx, meta, deployModel2, watch, options, tag2, releaseSha2, "development", preFold2, tagProbe2);
|
|
17743
|
+
const { checks: checks2, releaseUrl: releaseUrl2, announceNote: announceNote2, dispatch: d2 } = await completeMainRelease(deps, ctx, meta, deployModel2, watch, options, tag2, releaseSha2, "development", preFold2, tagProbe2, branchHints);
|
|
17714
17744
|
const devRollForward2 = await rollDevelopmentForward(deps, ctx, tag2);
|
|
17715
17745
|
if (directTrack) {
|
|
17716
17746
|
return {
|
|
@@ -17797,7 +17827,7 @@ async function runTrainApplyPipeline(mode, input) {
|
|
|
17797
17827
|
const releaseSha2 = requireValue(clean2(await deps.run("git", ["rev-parse", "main"])), "release sha");
|
|
17798
17828
|
return { versionFold: versionFold2, releaseSha: releaseSha2 };
|
|
17799
17829
|
});
|
|
17800
|
-
const { checks, releaseUrl, announceNote, dispatch: d } = await completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, "rc", preFold, tagProbe);
|
|
17830
|
+
const { checks, releaseUrl, announceNote, dispatch: d } = await completeMainRelease(deps, ctx, meta, deployModel, watch, options, tag, releaseSha, "rc", preFold, tagProbe, branchHints);
|
|
17801
17831
|
const retirement = await retireRcRuntime(deps, ctx, deployModel, d.deployStatus, releasedRcSha);
|
|
17802
17832
|
const devRollForward = await rollDevelopmentForward(deps, ctx, tag);
|
|
17803
17833
|
const rcAlignment = await alignRcForward(deps, ctx, tag);
|
|
@@ -26381,17 +26411,28 @@ async function gcRepoIndexCloud(deps) {
|
|
|
26381
26411
|
{ attempts: 1, timeoutMs, sleep: deps.retrySleep }
|
|
26382
26412
|
);
|
|
26383
26413
|
const body = await res.json().catch(() => ({}));
|
|
26384
|
-
if (!res.ok)
|
|
26414
|
+
if (!res.ok) {
|
|
26415
|
+
const detail = typeof body.error === "string" ? body.error : `gc HTTP ${res.status}`;
|
|
26416
|
+
return { ok: false, error: detail };
|
|
26417
|
+
}
|
|
26418
|
+
if (body.ok === false) {
|
|
26419
|
+
return { ok: false, error: typeof body.error === "string" ? body.error : "repo-index gc failed" };
|
|
26420
|
+
}
|
|
26385
26421
|
const removed = Array.isArray(body.removed) ? body.removed.filter((repo) => typeof repo === "string") : [];
|
|
26386
26422
|
const kept = Number(body.kept);
|
|
26423
|
+
const pendingRepos = Array.isArray(body.pendingRepos) ? body.pendingRepos.filter((repo) => typeof repo === "string") : void 0;
|
|
26424
|
+
const repoErrors = body.repoErrors && typeof body.repoErrors === "object" && !Array.isArray(body.repoErrors) ? Object.fromEntries(Object.entries(body.repoErrors).filter((entry) => typeof entry[1] === "string")) : void 0;
|
|
26387
26425
|
return {
|
|
26388
26426
|
ok: true,
|
|
26427
|
+
...body.partial === true ? { partial: true } : {},
|
|
26389
26428
|
removed,
|
|
26390
26429
|
kept: Number.isFinite(kept) ? kept : 0,
|
|
26391
26430
|
v4: {
|
|
26392
26431
|
dryRun: body.v4?.dryRun === true,
|
|
26393
26432
|
repos: normalizeGcV4Repos(body.v4?.repos)
|
|
26394
|
-
}
|
|
26433
|
+
},
|
|
26434
|
+
...pendingRepos?.length ? { pendingRepos } : {},
|
|
26435
|
+
...repoErrors && Object.keys(repoErrors).length ? { repoErrors } : {}
|
|
26395
26436
|
};
|
|
26396
26437
|
} catch (e) {
|
|
26397
26438
|
const msg = e.message || String(e);
|
|
@@ -35423,6 +35464,7 @@ Next command: ${report.nextCommand}`);
|
|
|
35423
35464
|
// src/explain-command.ts
|
|
35424
35465
|
init_cli_shared();
|
|
35425
35466
|
init_error_codes();
|
|
35467
|
+
init_house_map();
|
|
35426
35468
|
var LOOP_PLAYBOOKS = {
|
|
35427
35469
|
agent: {
|
|
35428
35470
|
title: "Agent",
|
|
@@ -35613,7 +35655,50 @@ function explainCommandManifest(manifest, command, opts = {}) {
|
|
|
35613
35655
|
}
|
|
35614
35656
|
};
|
|
35615
35657
|
}
|
|
35658
|
+
function houseEntryAsChild(entry, house) {
|
|
35659
|
+
return {
|
|
35660
|
+
name: entry.path.split(" ").pop() ?? entry.path,
|
|
35661
|
+
path: entry.canonical,
|
|
35662
|
+
flat_path: entry.path,
|
|
35663
|
+
house,
|
|
35664
|
+
canonical: entry.canonical,
|
|
35665
|
+
...entry.description ? { description: entry.description } : {},
|
|
35666
|
+
arguments: [],
|
|
35667
|
+
options: [],
|
|
35668
|
+
subcommands: [],
|
|
35669
|
+
category: "core",
|
|
35670
|
+
discovery: "primary",
|
|
35671
|
+
help_group: "Plan and work",
|
|
35672
|
+
module_owner: "unclassified",
|
|
35673
|
+
consumer: "unclassified"
|
|
35674
|
+
};
|
|
35675
|
+
}
|
|
35676
|
+
function houseRootAsParent(manifest, house) {
|
|
35677
|
+
const subcommands = house.commands.map(
|
|
35678
|
+
(entry) => findCommandInManifest(manifest, entry.canonical) ?? houseEntryAsChild(entry, house.root)
|
|
35679
|
+
);
|
|
35680
|
+
return {
|
|
35681
|
+
name: house.root,
|
|
35682
|
+
path: house.root,
|
|
35683
|
+
flat_path: house.root,
|
|
35684
|
+
house: house.root,
|
|
35685
|
+
canonical: house.root,
|
|
35686
|
+
description: HOUSE_QUESTIONS[house.root],
|
|
35687
|
+
arguments: [],
|
|
35688
|
+
options: [],
|
|
35689
|
+
subcommands,
|
|
35690
|
+
category: "core",
|
|
35691
|
+
discovery: "primary",
|
|
35692
|
+
help_group: "Plan and work",
|
|
35693
|
+
module_owner: "unclassified",
|
|
35694
|
+
consumer: "unclassified"
|
|
35695
|
+
};
|
|
35696
|
+
}
|
|
35616
35697
|
function findCommandInManifest(manifest, commandPath3) {
|
|
35698
|
+
if (isHouseRoot(commandPath3)) {
|
|
35699
|
+
const house = manifest.houses.find((entry) => entry.root === commandPath3);
|
|
35700
|
+
return house ? houseRootAsParent(manifest, house) : void 0;
|
|
35701
|
+
}
|
|
35617
35702
|
const visit = (command) => {
|
|
35618
35703
|
if (command.path === commandPath3 || command.flat_path === commandPath3) return command;
|
|
35619
35704
|
for (const child2 of command.subcommands) {
|
|
@@ -40687,6 +40772,13 @@ repoIndex.command("gc").description("remove v4 cloud authority material for repo
|
|
|
40687
40772
|
console.log(
|
|
40688
40773
|
`repo-index: gc tombstoned ${res.removed.length} orphan authorit${res.removed.length === 1 ? "y" : "ies"}, removed ${artifactsRemoved} artifact(s); kept ${res.kept} authorit${res.kept === 1 ? "y" : "ies"}, ${artifactsKept} artifact(s)`
|
|
40689
40774
|
);
|
|
40775
|
+
if (res.partial) {
|
|
40776
|
+
const pending = res.pendingRepos?.length ?? 0;
|
|
40777
|
+
const errors = res.repoErrors ? Object.keys(res.repoErrors).length : 0;
|
|
40778
|
+
console.warn(
|
|
40779
|
+
`repo-index: gc partial \u2014 ${pending} repo(s) pending${errors ? `, ${errors} repo error(s)` : ""}; retry gc until pendingRepos is empty`
|
|
40780
|
+
);
|
|
40781
|
+
}
|
|
40690
40782
|
} catch (e) {
|
|
40691
40783
|
return await failGraceful(e.message);
|
|
40692
40784
|
}
|
|
@@ -42714,7 +42806,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42714
42806
|
{ flags: "--announce-summary-file <path>", description: "agent-curated 3-6 line Hub Slack summary; required for a new MMI-Hub --apply (#883/#3901)" },
|
|
42715
42807
|
{ 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)" },
|
|
42716
42808
|
{ flags: "--dev", description: "full-track repos release development -> main directly, skipping rc (refuses if rc carries content not in development; no-op on direct-track repos) (#1062)" },
|
|
42717
|
-
{ flags: "--abort", description: "with --apply, delete only a proven unpublished failed
|
|
42809
|
+
{ flags: "--abort", description: "with --apply, delete only a proven unpublished failed release tag on MMI-Hub or an eligible direct-track registry-publish repo and restore local main for a clean recut (#3944/#5650)" },
|
|
42718
42810
|
{ flags: "--retry-publish <run-id>", description: "with --apply, retry failed jobs of one proven Hub publish release run (#3949)" }
|
|
42719
42811
|
];
|
|
42720
42812
|
for (const f of RELEASE_ONLY_FLAGS) {
|
|
@@ -42740,7 +42832,7 @@ for (const commandName of ["rcand", "release"]) {
|
|
|
42740
42832
|
return fail(`${commandName}: --announce-summary-file applies only to release \u2014 rcand posts no Hub Slack announcement. Run: mmi-cli devops release --announce-summary-file <path>`);
|
|
42741
42833
|
}
|
|
42742
42834
|
if (o.abort && commandName !== "release") {
|
|
42743
|
-
return fail(`${commandName}: --abort applies only to release \u2014 it rolls back a proven unpublished
|
|
42835
|
+
return fail(`${commandName}: --abort applies only to release \u2014 it rolls back a proven unpublished release tag. Run: mmi-cli devops release --abort --apply`);
|
|
42744
42836
|
}
|
|
42745
42837
|
if (o.retryPublish && commandName !== "release") {
|
|
42746
42838
|
return fail(`${commandName}: --retry-publish applies only to release. Run: mmi-cli devops release --retry-publish <run-id> --apply --watch`);
|
package/package.json
CHANGED