@mutmutco/claude-plugin 4.5.130 → 4.5.132
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/cli/dist/main.cjs
CHANGED
|
@@ -8162,6 +8162,11 @@ var DECLARED_ENTRIES = [
|
|
|
8162
8162
|
// archived stage (including a stage whose containers are down) into scratch Postgres and compare
|
|
8163
8163
|
// row counts, and read-verify every storage archive against its listing; per-stage PASS/FAIL.
|
|
8164
8164
|
{ name: "mmi-backup-restore-check (mm-central, mm-work)", cadence: "0 3 1 * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-backup-restore-check \u2192 /opt/mmi-control/nightly-backup-restore-check.sh; monthly restore proof for every archived stage (#7148; source scripts/nightly-backup-restore-check.sh); owner-approved mmi-oguz rebuild as CI-only mmi-runner2 with full erasure and no backups (#7859); zuber (46.225.58.31) is gone: deleted 2026-09-18 by the owner-approved ZuberShade decommission (MMC-ZuberShade#1838, snapshot kept); Hetzner has since reassigned that IP to another machine (#7351)" },
|
|
8165
|
+
// #8176: continuous WAL archiving of the mm-work dev Postgres (owner targets RPO <= 5 min, RTO <= 1 h). Postgres copies each
|
|
8166
|
+
// finished WAL file into a host spool (MM-Work#4170); this timer ships it encrypted to the Storage Box with WAL-G.
|
|
8167
|
+
{ name: "mmi-walg-ship@mm-work-dev (mm-work)", cadence: "every 30s (systemd OnUnitInactiveSec=30s)", executor: "box systemd", llm: "no", resolved: "declared", source: "/etc/systemd/system/mmi-walg-ship@.timer \u2192 /opt/mmi-control/walg-ship.sh mm-work-dev; spool /srv/mm-work/walspool/mm-work-dev \u2192 Storage Box backups/walg/mmi-tools/mm-work-dev, libsodium-encrypted (#8176; source scripts/walg/; status /var/lib/mmi-backup-status/mm-work-dev.ship.json)" },
|
|
8168
|
+
{ name: "mmi-walg-base (mm-work)", cadence: "30 3 * * 0", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-walg-base \u2192 /opt/mmi-control/walg-base.sh mm-work-dev; weekly WAL-G base backup + age-based retention (keep the base at or before now-7d and everything after, #8193) (#8176; source scripts/walg/; log /var/log/mmi-walg.log; status /var/lib/mmi-backup-status/mm-work-dev.base.json)" },
|
|
8169
|
+
{ name: "mmi-walg-drill (mm-work)", cadence: "0 4 2 * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mmi-walg-drill \u2192 /opt/mmi-control/walg-drill.sh mm-work-dev; monthly restore drill measuring RPO/RTO against the owner targets (300s/3600s) into a throwaway --network none container (#8177; source scripts/walg/; status /var/lib/mmi-backup-status/mm-work-dev.drill.json; alarm: backup-health.yml)" },
|
|
8165
8170
|
// #7662 (MM-Work#1520): Vercel Cron's 15-minute central mail call, moved to the box with MM-Work. The app
|
|
8166
8171
|
// calls its own endpoint with its own CRON_SECRET via docker exec, so the secret stays in the container.
|
|
8167
8172
|
{ name: "mm-work-mail-tick (mm-work)", cadence: "*/15 * * * *", executor: "box cron.d", llm: "no", resolved: "declared", source: "/etc/cron.d/mm-work-mail-tick \u2192 /opt/mmi-control/mm-work-mail-tick.sh; GET /api/internal/mail per stage listed in MM_WORK_MAIL_STAGES (source scripts/mm-work-mail-tick.sh; log /var/log/mm-work-mail-tick.log)" },
|
|
@@ -16681,6 +16686,7 @@ function gateExtraStepsYaml(steps) {
|
|
|
16681
16686
|
return steps.map((step) => [
|
|
16682
16687
|
`
|
|
16683
16688
|
- name: ${yamlScalar(step.name)}`,
|
|
16689
|
+
"\n if: ${{ steps.development-gate.outputs.reuse != 'true' }}",
|
|
16684
16690
|
step.env && Object.keys(step.env).length ? `
|
|
16685
16691
|
env:${envYaml(step.env, " ")}` : "",
|
|
16686
16692
|
"\n uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}",
|
|
@@ -17240,23 +17246,33 @@ async function installAppFoldDeps(deps) {
|
|
|
17240
17246
|
}
|
|
17241
17247
|
var SHARED_INSTALLER_PACKAGES = ["@mutmutco/installer-face", "@mutmutco/installer-launcher", "@mutmutco/installer-gate"];
|
|
17242
17248
|
async function refreshSharedInstallerDeps(deps) {
|
|
17243
|
-
let
|
|
17249
|
+
let lockPaths;
|
|
17244
17250
|
try {
|
|
17245
|
-
|
|
17246
|
-
const present = Object.keys(lock.packages ?? {});
|
|
17247
|
-
declared = SHARED_INSTALLER_PACKAGES.filter((name) => present.some((key) => key === `node_modules/${name}` || key.endsWith(`/node_modules/${name}`)));
|
|
17248
|
-
} catch {
|
|
17249
|
-
return null;
|
|
17250
|
-
}
|
|
17251
|
-
if (declared.length === 0) return null;
|
|
17252
|
-
try {
|
|
17253
|
-
await deps.run("npm", ["update", ...declared, "--package-lock-only", "--no-audit", "--no-fund"]);
|
|
17251
|
+
lockPaths = (await deps.run("git", ["ls-tree", "-r", "--name-only", "HEAD"])).split("\n").filter((path2) => path2 === "package-lock.json" || path2.endsWith("/package-lock.json"));
|
|
17254
17252
|
} catch (e) {
|
|
17255
|
-
|
|
17256
|
-
|
|
17257
|
-
|
|
17253
|
+
throw trainReadFailure(
|
|
17254
|
+
"shared installer refresh: `git ls-tree -r --name-only HEAD`",
|
|
17255
|
+
e,
|
|
17256
|
+
"rerun in a readable checkout \u2014 lockfile roots must be discovered, never guessed"
|
|
17257
|
+
);
|
|
17258
|
+
}
|
|
17259
|
+
const notes = [];
|
|
17260
|
+
for (const lockPath of lockPaths) {
|
|
17261
|
+
const lock = JSON.parse(await deps.run("git", ["show", `HEAD:${lockPath}`]));
|
|
17262
|
+
const present = Object.keys(lock.packages ?? {});
|
|
17263
|
+
const declared = SHARED_INSTALLER_PACKAGES.filter((name) => present.some((key) => key === `node_modules/${name}` || key.endsWith(`/node_modules/${name}`)));
|
|
17264
|
+
if (declared.length === 0) continue;
|
|
17265
|
+
const prefix = lockPath.includes("/") ? lockPath.slice(0, lockPath.lastIndexOf("/")) : null;
|
|
17266
|
+
try {
|
|
17267
|
+
await deps.run("npm", [...prefix ? ["--prefix", prefix] : [], "update", ...declared, "--package-lock-only", "--no-audit", "--no-fund"]);
|
|
17268
|
+
notes.push(`shared installer deps refreshed in ${prefix ?? "."} (${declared.join(", ")})`);
|
|
17269
|
+
} catch (e) {
|
|
17270
|
+
const why = e instanceof Error ? e.message.split("\n")[0] : String(e);
|
|
17271
|
+
deps.warn?.(`shared installer refresh skipped for ${prefix ?? "."} (${why}) \u2014 shipping the locked versions`);
|
|
17272
|
+
notes.push(`shared installer refresh skipped for ${prefix ?? "."} (${why}); the locked ${declared.join(", ")} still satisfy their ranges`);
|
|
17273
|
+
}
|
|
17258
17274
|
}
|
|
17259
|
-
return
|
|
17275
|
+
return notes.length > 0 ? notes.join("; ") : null;
|
|
17260
17276
|
}
|
|
17261
17277
|
async function restoreMainNpmPackIdentities(deps, version) {
|
|
17262
17278
|
const bomPath = "distribution-bom.json";
|
|
@@ -18258,10 +18274,10 @@ var rollout_plan_default = {
|
|
|
18258
18274
|
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)."
|
|
18259
18275
|
},
|
|
18260
18276
|
baseline: {
|
|
18261
|
-
version: "4.5.
|
|
18262
|
-
tag: "v4.5.
|
|
18263
|
-
commit: "
|
|
18264
|
-
npm: "@mutmutco/cli@4.5.
|
|
18277
|
+
version: "4.5.132",
|
|
18278
|
+
tag: "v4.5.132",
|
|
18279
|
+
commit: "80a4c6f78d39",
|
|
18280
|
+
npm: "@mutmutco/cli@4.5.132"
|
|
18265
18281
|
},
|
|
18266
18282
|
exitCriterion: "fleet-n-of-n",
|
|
18267
18283
|
hubOnlyShortcut: "forbidden",
|
|
@@ -18278,14 +18294,14 @@ var rollout_plan_default = {
|
|
|
18278
18294
|
repo: "mutmutco/mmi-hub",
|
|
18279
18295
|
role: "canary",
|
|
18280
18296
|
schedule: "train",
|
|
18281
|
-
v3Target: "v4.5.
|
|
18297
|
+
v3Target: "v4.5.132"
|
|
18282
18298
|
}
|
|
18283
18299
|
],
|
|
18284
18300
|
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.",
|
|
18285
18301
|
rollback: {
|
|
18286
18302
|
independent: true,
|
|
18287
|
-
mechanism: "npm dist-tag latest -> 4.5.
|
|
18288
|
-
v3Target: "v4.5.
|
|
18303
|
+
mechanism: "npm dist-tag latest -> 4.5.132 and redeploy the Hub Lambda from tag v4.5.132 (80a4c6f78d39); installed clients repair via `mmi-cli doctor`. No other cohort is touched.",
|
|
18304
|
+
v3Target: "v4.5.132 (@mutmutco/cli@4.5.132, tag commit 80a4c6f78d39 \u2014 last known-good release carrying the repo-index v4-only contract)"
|
|
18289
18305
|
}
|
|
18290
18306
|
},
|
|
18291
18307
|
{
|
|
@@ -29517,10 +29533,17 @@ ${r.repo} (${r.class}, policy=${r.mergePolicy}) ${verdict}`);
|
|
|
29517
29533
|
}
|
|
29518
29534
|
return lines2.join("\n");
|
|
29519
29535
|
}
|
|
29536
|
+
function unauditedReconcileError(reason) {
|
|
29537
|
+
return `cannot audit \u2014 ${reason}; no reconcile change made (unaudited, not canonical)`;
|
|
29538
|
+
}
|
|
29520
29539
|
async function applyCiReconcileMergeSettingsFromReport(repo, deps, report) {
|
|
29521
29540
|
const applied = [];
|
|
29522
29541
|
const skipped = [];
|
|
29523
29542
|
const errors = [];
|
|
29543
|
+
if (report.unauditedReason) {
|
|
29544
|
+
errors.push(unauditedReconcileError(report.unauditedReason));
|
|
29545
|
+
return { repo, applied, skipped, errors };
|
|
29546
|
+
}
|
|
29524
29547
|
const mergeChecks = report.checks.filter((c) => c.label.startsWith("allow_") || c.label.startsWith("delete_branch") || c.label.startsWith("has_wiki"));
|
|
29525
29548
|
const needsPatch = mergeChecks.some((c) => !c.ok);
|
|
29526
29549
|
if (!needsPatch) {
|
|
@@ -29824,6 +29847,9 @@ async function applyCiReconcileRepo(repo, deps, options = {}) {
|
|
|
29824
29847
|
return { repo, applied: [], skipped: [], errors: ["product-ruleset requires registry META requiredChecks"] };
|
|
29825
29848
|
}
|
|
29826
29849
|
const report = await auditRepoCi(repo, deps);
|
|
29850
|
+
if (report.unauditedReason) {
|
|
29851
|
+
return { repo, applied: [], skipped: [], errors: [unauditedReconcileError(report.unauditedReason)] };
|
|
29852
|
+
}
|
|
29827
29853
|
const finish = (result2, pendingReason) => options.productRulesetOnly ? Promise.resolve(result2) : finalizeCiReconcile(repo, deps, result2, report, pendingReason);
|
|
29828
29854
|
const baseBranch = "development";
|
|
29829
29855
|
let raw = report.class === "deployable" && !report.explicitNoCi ? await fetchRulesetSeedBody(deps, repo) : null;
|
package/cli/package.json
CHANGED
package/package.json
CHANGED
|
@@ -50,6 +50,7 @@ concurrency:
|
|
|
50
50
|
cancel-in-progress: true
|
|
51
51
|
|
|
52
52
|
permissions:
|
|
53
|
+
actions: read # #8206: exact-SHA development workflow verdict
|
|
53
54
|
contents: read
|
|
54
55
|
# MMI-Hub#7542: the product image build below reads org private packages with the workflow's
|
|
55
56
|
# own ephemeral token (NODE_AUTH_TOKEN) — the same reader the central deploy uses.
|
|
@@ -65,12 +66,40 @@ jobs:
|
|
|
65
66
|
defaults:
|
|
66
67
|
run: { working-directory: {{GATE_WORKDIR}} }{{GATE_SERVICES_YAML}}
|
|
67
68
|
steps:
|
|
68
|
-
|
|
69
|
+
# #8206: keep a fresh successful tag gate; promote the exact development verdict, not a ref.
|
|
70
|
+
- name: Reuse development gate for rc tag
|
|
71
|
+
id: development-gate
|
|
72
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
|
73
|
+
with:
|
|
74
|
+
script: |
|
|
75
|
+
core.setOutput('reuse', 'false');
|
|
76
|
+
if (context.eventName !== 'push' || !/^refs\/tags\/v.+-rc\.\d+$/.test(context.ref) || !/^[0-9a-f]{40}$/.test(context.sha)) return;
|
|
77
|
+
try {
|
|
78
|
+
const { data: current } = await github.rest.actions.getWorkflowRun({ ...context.repo, run_id: context.runId });
|
|
79
|
+
const { data } = await github.rest.actions.listWorkflowRuns({
|
|
80
|
+
...context.repo, workflow_id: current.workflow_id, branch: 'development',
|
|
81
|
+
event: 'push', head_sha: context.sha, per_page: 100
|
|
82
|
+
});
|
|
83
|
+
// API returns newest first: a newer red/pending rerun must not reuse an older green.
|
|
84
|
+
const run = data.workflow_runs[0];
|
|
85
|
+
if (!run || run.head_sha !== context.sha || run.head_branch !== 'development' ||
|
|
86
|
+
run.event !== 'push' || run.status !== 'completed' || run.conclusion !== 'success') return;
|
|
87
|
+
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, {
|
|
88
|
+
...context.repo, run_id: run.id, filter: 'latest', per_page: 100
|
|
89
|
+
});
|
|
90
|
+
if (!jobs.some(job => job.name === 'gate' && job.status === 'completed' && job.conclusion === 'success')) return;
|
|
91
|
+
core.setOutput('reuse', 'true');
|
|
92
|
+
core.info('Reusing successful development gate run ' + run.id + ' for exact SHA ' + context.sha);
|
|
93
|
+
} catch (error) {
|
|
94
|
+
core.warning('Development gate proof unavailable; running normal gate: ' + error.message);
|
|
95
|
+
}
|
|
96
|
+
- if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
97
|
+
uses: mutmutco/MMI-Hub/.github/actions/runner-checkout@{{GATE_RUNNER_SHA}}
|
|
69
98
|
with:
|
|
70
99
|
lockfile-path: {{GATE_CACHE_DEP_PATH}}
|
|
71
100
|
fetch-depth: 0 # #8129: runbook freshness needs the PR merge-base history.
|
|
72
101
|
- name: Runbook guard
|
|
73
|
-
if: ${{ github.event_name == 'pull_request' }}
|
|
102
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' && (github.event_name == 'pull_request') }}
|
|
74
103
|
uses: mutmutco/MMI-Hub/.github/actions/runbook-guard@{{GATE_RUNBOOK_SHA}}
|
|
75
104
|
with:
|
|
76
105
|
base-ref: origin/${{ github.base_ref }}
|
|
@@ -81,11 +110,13 @@ jobs:
|
|
|
81
110
|
# `npm config get cache` for any explicit cache restore). Job-level `env:` cannot use the
|
|
82
111
|
# `runner` context — write via GITHUB_ENV from the shell `$RUNNER_TEMP` instead.
|
|
83
112
|
- name: Isolate npm cache (per-job)
|
|
113
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
84
114
|
shell: bash
|
|
85
115
|
run: echo "NPM_CONFIG_CACHE=$RUNNER_TEMP/npm-cache" >> "$GITHUB_ENV"
|
|
86
116
|
# MMI-Hub#5111: Windows CRLF in tracked shell scripts breaks Linux runners before the real
|
|
87
117
|
# check can explain it. Inspect only tracked files before install; .gitattributes is the fix.
|
|
88
118
|
- name: Line-ending guard
|
|
119
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
89
120
|
shell: bash
|
|
90
121
|
run: |
|
|
91
122
|
offenders=$(mktemp)
|
|
@@ -116,6 +147,7 @@ jobs:
|
|
|
116
147
|
# files (Dockerfile + docker-compose.yml) skip in a second — no new job, no new required
|
|
117
148
|
# context, no ruleset or registry change (#7012 needs nothing to cover).
|
|
118
149
|
- name: Product image build (tenant-container only)
|
|
150
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
119
151
|
env:
|
|
120
152
|
# The documented build-secret opt-in (compose `build.secrets` + registry
|
|
121
153
|
# requiredBuildSecrets `NODE_AUTH_TOKEN=@github-packages-token`): the workflow's own
|
|
@@ -146,25 +178,27 @@ jobs:
|
|
|
146
178
|
# MMI-Hub#5871: declare the npm MAJOR rather than inheriting whatever the runner's node bundles.
|
|
147
179
|
# A bare major, never an exact patch (it goes stale and then prescribes downgrading operator
|
|
148
180
|
# hosts toward it, #5862) and never `latest` (it takes the next major silently, #4782).
|
|
149
|
-
- if: ${{ '{{GATE_RUNTIME}}' == 'node' }}
|
|
181
|
+
- if: ${{ steps.development-gate.outputs.reuse != 'true' && ('{{GATE_RUNTIME}}' == 'node') }}
|
|
150
182
|
uses: mutmutco/MMI-Hub/.github/actions/runner-node-toolchain@{{GATE_RUNNER_SHA}}
|
|
151
183
|
with:
|
|
152
184
|
node-version: 24
|
|
153
185
|
npm-version: '12'
|
|
154
|
-
- if: ${{ '{{GATE_RUNTIME}}' == 'python' }}
|
|
186
|
+
- if: ${{ steps.development-gate.outputs.reuse != 'true' && ('{{GATE_RUNTIME}}' == 'python') }}
|
|
155
187
|
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
156
188
|
with: { python-version: '{{GATE_PY_VERSION}}' }
|
|
157
189
|
# MMI-Hub#3446: assert the runtime toolchain is on PATH BEFORE the install step. Node uses the
|
|
158
190
|
# runner-node-toolchain composite above (setup-node + preflight in one action, #5610). Python
|
|
159
191
|
# keeps the inline preflight below.
|
|
160
192
|
- name: Toolchain preflight
|
|
161
|
-
if: ${{ '{{GATE_RUNTIME}}' == 'python' }}
|
|
193
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' && ('{{GATE_RUNTIME}}' == 'python') }}
|
|
162
194
|
run: |
|
|
163
195
|
python3 --version || { echo "::error title=CI runner toolchain::RUNNER NOT PROVISIONED — python3 not on PATH after setup-python. This is the runner, not your diff; no install or test ran. Re-run the job; if it persists the mmi-runner python toolchain needs attention (docs/Guides/gh-runner-runbook.md in MMI-Hub)."; exit 1; }
|
|
164
196
|
- run: {{GATE_INSTALL_CMD}}
|
|
197
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
165
198
|
# #3178: the check runs under the org wall-clock budget — a hung suite dies at the ceiling instead
|
|
166
199
|
# of squatting a runner lane for GitHub's 6h default. ci-audit + the release train enforce this step.
|
|
167
200
|
- uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}
|
|
201
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
168
202
|
with:
|
|
169
203
|
command: {{GATE_CMD}}
|
|
170
204
|
max-seconds: {{GATE_MAX_SECONDS}}
|
|
@@ -8,6 +8,7 @@ concurrency:
|
|
|
8
8
|
group: gate-${{ github.event.pull_request.number || github.ref }}
|
|
9
9
|
cancel-in-progress: true
|
|
10
10
|
permissions:
|
|
11
|
+
actions: read # #8206: exact-SHA development workflow verdict
|
|
11
12
|
contents: read
|
|
12
13
|
packages: read
|
|
13
14
|
jobs:
|
|
@@ -15,26 +16,59 @@ jobs:
|
|
|
15
16
|
runs-on: [self-hosted, linux, x64, mmi-live]
|
|
16
17
|
timeout-minutes: 10
|
|
17
18
|
steps:
|
|
18
|
-
|
|
19
|
+
# #8206: keep a fresh successful tag gate; promote the exact development verdict, not a ref.
|
|
20
|
+
- name: Reuse development gate for rc tag
|
|
21
|
+
id: development-gate
|
|
22
|
+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
|
|
23
|
+
with:
|
|
24
|
+
script: |
|
|
25
|
+
core.setOutput('reuse', 'false');
|
|
26
|
+
if (context.eventName !== 'push' || !/^refs\/tags\/v.+-rc\.\d+$/.test(context.ref) || !/^[0-9a-f]{40}$/.test(context.sha)) return;
|
|
27
|
+
try {
|
|
28
|
+
const { data: current } = await github.rest.actions.getWorkflowRun({ ...context.repo, run_id: context.runId });
|
|
29
|
+
const { data } = await github.rest.actions.listWorkflowRuns({
|
|
30
|
+
...context.repo, workflow_id: current.workflow_id, branch: 'development',
|
|
31
|
+
event: 'push', head_sha: context.sha, per_page: 100
|
|
32
|
+
});
|
|
33
|
+
// API returns newest first: a newer red/pending rerun must not reuse an older green.
|
|
34
|
+
const run = data.workflow_runs[0];
|
|
35
|
+
if (!run || run.head_sha !== context.sha || run.head_branch !== 'development' ||
|
|
36
|
+
run.event !== 'push' || run.status !== 'completed' || run.conclusion !== 'success') return;
|
|
37
|
+
const jobs = await github.paginate(github.rest.actions.listJobsForWorkflowRun, {
|
|
38
|
+
...context.repo, run_id: run.id, filter: 'latest', per_page: 100
|
|
39
|
+
});
|
|
40
|
+
if (!jobs.some(job => job.name === 'gate' && job.status === 'completed' && job.conclusion === 'success')) return;
|
|
41
|
+
core.setOutput('reuse', 'true');
|
|
42
|
+
core.info('Reusing successful development gate run ' + run.id + ' for exact SHA ' + context.sha);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
core.warning('Development gate proof unavailable; running normal gate: ' + error.message);
|
|
45
|
+
}
|
|
46
|
+
- if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
47
|
+
uses: mutmutco/MMI-Hub/.github/actions/runner-checkout@{{GATE_RUNNER_SHA}}
|
|
19
48
|
with:
|
|
20
49
|
lockfile-path: package-lock.json
|
|
21
50
|
fetch-depth: 0 # #8129: runbook freshness needs the PR merge-base history.
|
|
22
51
|
- name: Runbook guard
|
|
23
|
-
if: ${{ github.event_name == 'pull_request' }}
|
|
52
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' && (github.event_name == 'pull_request') }}
|
|
24
53
|
uses: mutmutco/MMI-Hub/.github/actions/runbook-guard@{{GATE_RUNBOOK_SHA}}
|
|
25
54
|
with:
|
|
26
55
|
base-ref: origin/${{ github.base_ref }}
|
|
27
56
|
- name: Isolate npm cache
|
|
57
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
28
58
|
run: echo "NPM_CONFIG_CACHE=$RUNNER_TEMP/npm-cache" >> "$GITHUB_ENV"
|
|
29
59
|
- uses: mutmutco/MMI-Hub/.github/actions/runner-node-toolchain@{{GATE_RUNNER_SHA}}
|
|
60
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
30
61
|
with:
|
|
31
62
|
node-version: 24
|
|
32
63
|
npm-version: '12'
|
|
33
64
|
- run: npm ci --no-audit --no-fund
|
|
65
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
34
66
|
- run: npm ci --prefix module --no-audit --no-fund
|
|
67
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
35
68
|
env:
|
|
36
69
|
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
37
70
|
- uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}
|
|
71
|
+
if: ${{ steps.development-gate.outputs.reuse != 'true' }}
|
|
38
72
|
with:
|
|
39
73
|
command: npm run typecheck && npm run build && npm --prefix module run check
|
|
40
74
|
max-seconds: {{GATE_MAX_SECONDS}}
|