@mutmutco/codex-plugin 3.131.0
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/.codex-plugin/plugin.json +30 -0
- package/bin/mmi-cli +6 -0
- package/bin/mmi-cli.cmd +3 -0
- package/bin/mmi-hook +2 -0
- package/bin/mmi-hook-console.cmd +10 -0
- package/bin/mmi-hook.exe +0 -0
- package/hooks/codex-hooks.json +41 -0
- package/package.json +21 -0
- package/scripts/command-ladder-core.mjs +334 -0
- package/scripts/command-ladder-gate.mjs +126 -0
- package/scripts/deny-gate-crash.mjs +179 -0
- package/scripts/edit-tool-paths.mjs +113 -0
- package/scripts/env-write-lint.mjs +137 -0
- package/scripts/hook-io.mjs +22 -0
- package/scripts/hook-policy.mjs +73 -0
- package/scripts/hook-run.mjs +437 -0
- package/scripts/hook-trace.mjs +151 -0
- package/scripts/pretooluse-shell-gates.mjs +424 -0
- package/scripts/secret-echo-lint.mjs +177 -0
- package/scripts/secret-redact.mjs +552 -0
- package/scripts/throttle-core.mjs +324 -0
- package/scripts/validate-hook.mjs +156 -0
- package/scripts/vault-edit-gate.mjs +94 -0
- package/skills/bootstrap/SKILL.md +550 -0
- package/skills/bootstrap/seeds/Dockerfile.template +30 -0
- package/skills/bootstrap/seeds/README.template.md +37 -0
- package/skills/bootstrap/seeds/architecture.template.md +34 -0
- package/skills/bootstrap/seeds/decisions-readme.template.md +45 -0
- package/skills/bootstrap/seeds/docker-compose.template.yml +26 -0
- package/skills/bootstrap/seeds/gate.template.yml +85 -0
- package/skills/bootstrap/seeds/google-login.template.md +33 -0
- package/skills/bootstrap/seeds/manifest.json +26 -0
- package/skills/bootstrap/seeds/mmi-product-required-checks.template.json +23 -0
- package/skills/browser-automation/SKILL.md +95 -0
- package/skills/epic/SKILL.md +104 -0
- package/skills/hotfix/SKILL.md +165 -0
- package/skills/mmi/SKILL.md +404 -0
- package/skills/mmi-doctor/SKILL.md +63 -0
- package/skills/onboard/SKILL.md +85 -0
- package/skills/rcand/SKILL.md +208 -0
- package/skills/release/SKILL.md +599 -0
- package/skills/resume/SKILL.md +90 -0
- package/skills/secrets/SKILL.md +159 -0
- package/skills/stage/SKILL.md +153 -0
- package/skills/worktree/SKILL.md +151 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# {{REPO_NAME}} — Architecture
|
|
2
|
+
|
|
3
|
+
> How this repo is **built** — a short, stable entry, not a runtime inventory. Pair with `README.md`
|
|
4
|
+
> (what it *is*). State current truth, inspect don't narrate: no change-comments or version-era labels
|
|
5
|
+
> (history is in git). (Write fresh — D35.)
|
|
6
|
+
|
|
7
|
+
## What this repo produces
|
|
8
|
+
|
|
9
|
+
(What ships from this repo — the product/service/library, in one or two bullets.)
|
|
10
|
+
|
|
11
|
+
## Layout
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
(top-level dir) (what it is, one line)
|
|
15
|
+
(top-level dir) (what it is, one line)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Stack
|
|
19
|
+
|
|
20
|
+
(Languages, frameworks, datastores, major services — inspect the lockfile/manifest, don't assume.)
|
|
21
|
+
|
|
22
|
+
## Build & deploy
|
|
23
|
+
|
|
24
|
+
- **Class + release track + stages:** `mmi-cli oracle org project get` (registry SSOT — full = development/rc/main,
|
|
25
|
+
direct = development/main, trunk = main; never copied here, so it cannot go stale).
|
|
26
|
+
- **Deploys run centrally** via the Hub (`tenant-deploy.yml`); this repo carries no deploy files, unless
|
|
27
|
+
noted otherwise below.
|
|
28
|
+
- (Build/test commands, CI gate, deploy target.)
|
|
29
|
+
|
|
30
|
+
## Conventions
|
|
31
|
+
|
|
32
|
+
Follows the org spine (carried by the MMI plugin per machine). Repo-specific agent guidance:
|
|
33
|
+
`README.md` § Agent context — no agent guide is committed to the repo (the org `mmi-no-agent-files-org`
|
|
34
|
+
ruleset blocks every agent-guide path).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Decision records
|
|
2
|
+
|
|
3
|
+
Prose in this tree is only for **why** — why we chose a shape, what we rejected, what constraint
|
|
4
|
+
bound us. It never describes current implementation and never claims to be current. Code (and
|
|
5
|
+
generated refs) are the only truth about *what is*.
|
|
6
|
+
|
|
7
|
+
## One file per decision
|
|
8
|
+
|
|
9
|
+
`docs/decisions/YYYY-MM-DD-<slug>.md`
|
|
10
|
+
|
|
11
|
+
- **Date** in the filename is the day the decision was recorded (UTC calendar date).
|
|
12
|
+
- **Slug** is a short kebab-case label for the subject (`single-aws-account`, `cowork-plugin-boundary`).
|
|
13
|
+
|
|
14
|
+
## Frontmatter
|
|
15
|
+
|
|
16
|
+
```yaml
|
|
17
|
+
---
|
|
18
|
+
date: YYYY-MM-DD
|
|
19
|
+
sha: <git commit sha at which this was true>
|
|
20
|
+
status: decided | superseded
|
|
21
|
+
subjects:
|
|
22
|
+
- <topic or path this decision binds>
|
|
23
|
+
---
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
| Field | Meaning |
|
|
27
|
+
| --- | --- |
|
|
28
|
+
| `date` | Same calendar day as the filename prefix. |
|
|
29
|
+
| `sha` | The commit that embodies or records the decision — a pin in history, not a claim that the tree still looks like that. |
|
|
30
|
+
| `status` | `decided` (in force) or `superseded` (replaced by a later record; leave the old file in place). |
|
|
31
|
+
| `subjects` | Short list of topics, paths, or surfaces the decision constrains. |
|
|
32
|
+
|
|
33
|
+
## Body
|
|
34
|
+
|
|
35
|
+
1. `# <Title>` — the decision in one line (what was chosen, not how it works today).
|
|
36
|
+
2. `## Why` — the rationale and the binding constraints.
|
|
37
|
+
3. `## Rejected alternatives` — each alternative as a bullet: what it was, why it lost.
|
|
38
|
+
|
|
39
|
+
Do not narrate live topology, versions, box coordinates, or "how to run it." If a reader needs
|
|
40
|
+
current state, they read the code or a generated ref — not this file.
|
|
41
|
+
|
|
42
|
+
## Ownership
|
|
43
|
+
|
|
44
|
+
Bootstrap seeds this README once (`ownership: repo`) and never clobbers it. Individual decision
|
|
45
|
+
files are authored in the same PR as the change and merged by a human. There is no scheduled docs-janitor backstop (Hub#4119/#4164).
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
services:
|
|
2
|
+
app:
|
|
3
|
+
build:
|
|
4
|
+
context: .
|
|
5
|
+
dockerfile: Dockerfile
|
|
6
|
+
# Build-time secret opt-in:
|
|
7
|
+
# secrets:
|
|
8
|
+
# - NODE_AUTH_TOKEN
|
|
9
|
+
restart: unless-stopped
|
|
10
|
+
# The box control document writes registry coords + stage-scoped SSM secret values into the
|
|
11
|
+
# release ./.env before `docker compose up`; env_file is what delivers them into the container.
|
|
12
|
+
env_file: .env
|
|
13
|
+
environment:
|
|
14
|
+
NODE_ENV: production
|
|
15
|
+
MMI_STAGE: ${MMI_STAGE:-dev}
|
|
16
|
+
MMI_PORT: ${MMI_PORT:-3000}
|
|
17
|
+
PORT: ${PORT:-3000}
|
|
18
|
+
MMI_EDGE_DOMAIN: ${MMI_EDGE_DOMAIN:-}
|
|
19
|
+
ports:
|
|
20
|
+
- "${MMI_PORT:-3000}:${PORT:-3000}"
|
|
21
|
+
|
|
22
|
+
# Build-time secret opt-in. Requires registry META:
|
|
23
|
+
# requiredBuildSecrets: ["NODE_AUTH_TOKEN=@github-packages-token"]
|
|
24
|
+
# secrets:
|
|
25
|
+
# NODE_AUTH_TOKEN:
|
|
26
|
+
# environment: NODE_AUTH_TOKEN
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
name: gate
|
|
2
|
+
# Org-standard green-before-merge gate for product repos (#1333). Runs on PRs, train-branch pushes,
|
|
3
|
+
# and v* tags so /release and /hotfix can discover required contexts on the tagged SHA.
|
|
4
|
+
#
|
|
5
|
+
# Runner: self-hosted mmi-runner (mmi-live) — see docs/Guides/gh-runner-runbook.md in MMI-Hub.
|
|
6
|
+
# #4118: if GATE_CMD runs tsgo or other memory-heavy typecheck / browser work, pin this job to
|
|
7
|
+
# runs-on: [self-hosted, linux, x64, mmi-heavy]
|
|
8
|
+
# instead — standard lanes are MemoryMax=1200M and will cgroup-OOM those workloads.
|
|
9
|
+
# Stack-aware (#1550): the runtime is rendered into the setup-step `if:` — both the Node and Python
|
|
10
|
+
# setup steps live in the file but only the one matching GATE_RUNTIME runs. Knobs (override at
|
|
11
|
+
# bootstrap with --var):
|
|
12
|
+
# GATE_RUNTIME — node | python (selects which setup step fires)
|
|
13
|
+
# GATE_CMD — the check command ({{GATE_CMD}})
|
|
14
|
+
# GATE_INSTALL_CMD — the dependency-install command ({{GATE_INSTALL_CMD}})
|
|
15
|
+
# GATE_WORKDIR — app working directory when not the repo root ({{GATE_WORKDIR}})
|
|
16
|
+
# GATE_CACHE_DEP_PATH— npm lockfile path for the setup-node cache ({{GATE_CACHE_DEP_PATH}})
|
|
17
|
+
# GATE_PY_VERSION — Python version for setup-python ({{GATE_PY_VERSION}})
|
|
18
|
+
# GATE_MAX_SECONDS — run-with-budget wall-clock ceiling in seconds ({{GATE_MAX_SECONDS}}); 300 default,
|
|
19
|
+
# tighten per repo (org project set --var gate={"maxSeconds":N}) once measured (#3178)
|
|
20
|
+
# GATE_PUSH_BRANCHES_YAML — YAML list of push branches that trigger the workflow file (rendered by
|
|
21
|
+
# bootstrap from the release track; not usually hand-passed)
|
|
22
|
+
# GATE_FULL_RUN_BRANCH — train branch whose PUSHES run the full gate job (development on full/direct;
|
|
23
|
+
# main on trunk). `main` is ALWAYS included in the job `if:` below so a required-
|
|
24
|
+
# checks ruleset on main cannot be silently skipped by a future bootstrap (#4113).
|
|
25
|
+
# GATE_BUDGET_SHA is rendered by the CLI from its blessed run-with-budget pin — not an operator knob.
|
|
26
|
+
# (seed touch: keep kilo mirror + BOM digests in lockstep after classifier land.)
|
|
27
|
+
on:
|
|
28
|
+
pull_request:
|
|
29
|
+
push:
|
|
30
|
+
branches: {{GATE_PUSH_BRANCHES_YAML}}
|
|
31
|
+
tags: ['v*']
|
|
32
|
+
|
|
33
|
+
env:
|
|
34
|
+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
|
|
35
|
+
|
|
36
|
+
# #3001: cancel superseded runs — agent push-bursts queue a full fresh run per push.
|
|
37
|
+
# Per-PR group only (a repo-wide group hits GitHub's one-pending-slot limit and cancels
|
|
38
|
+
# innocent queued runs — MMC-ZuberShade#880). Pushes group by ref: each tag and the train
|
|
39
|
+
# branch supersede only themselves.
|
|
40
|
+
concurrency:
|
|
41
|
+
group: gate-${{ github.event.pull_request.number || github.ref }}
|
|
42
|
+
cancel-in-progress: true
|
|
43
|
+
|
|
44
|
+
permissions:
|
|
45
|
+
contents: read
|
|
46
|
+
|
|
47
|
+
jobs:
|
|
48
|
+
gate:
|
|
49
|
+
# #4113: bake `main` into the template permanently. GATE_FULL_RUN_BRANCH selects the train push
|
|
50
|
+
# that runs the full job; main must never become skippable via bootstrap vars alone while the
|
|
51
|
+
# org ruleset still requires `gate` on main.
|
|
52
|
+
if: ${{ github.event_name != 'push' || github.ref_name == '{{GATE_FULL_RUN_BRANCH}}' || github.ref_name == 'main' || github.ref_type == 'tag' }}
|
|
53
|
+
runs-on: [self-hosted, linux, x64, mmi-live]
|
|
54
|
+
defaults:
|
|
55
|
+
run: { working-directory: {{GATE_WORKDIR}} }
|
|
56
|
+
steps:
|
|
57
|
+
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
|
|
58
|
+
- if: ${{ '{{GATE_RUNTIME}}' == 'node' }}
|
|
59
|
+
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
60
|
+
with: { node-version: 24, cache: npm, cache-dependency-path: {{GATE_CACHE_DEP_PATH}} }
|
|
61
|
+
- if: ${{ '{{GATE_RUNTIME}}' == 'python' }}
|
|
62
|
+
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
|
|
63
|
+
with: { python-version: '{{GATE_PY_VERSION}}' }
|
|
64
|
+
# MMI-Hub#3446: assert the runtime toolchain is on PATH BEFORE the install step. A runner whose
|
|
65
|
+
# node/npm (or python) is missing, or whose setup step raced, fails `{{GATE_INSTALL_CMD}}` with a
|
|
66
|
+
# bare `command not found` (exit 127) that reads like a broken diff and abandons a correct PR in an
|
|
67
|
+
# autonomous merge loop. This names the RUNNER instead — a distinguishable infra failure that
|
|
68
|
+
# `mmi-cli devops pr checks-wait` classifies as rerunnable (title `CI runner toolchain`), mirroring the
|
|
69
|
+
# disk (#3366) and browser (#808) preflights. No test ran; the diff is not implicated.
|
|
70
|
+
- name: Toolchain preflight
|
|
71
|
+
if: ${{ '{{GATE_RUNTIME}}' == 'node' }}
|
|
72
|
+
run: |
|
|
73
|
+
node -v && npm -v || { echo "::error title=CI runner toolchain::RUNNER NOT PROVISIONED — node/npm not on PATH after setup-node. This is the runner, not your diff; no install or test ran. Re-run the job (a fresh lane usually clears it); if it persists the mmi-runner node toolchain needs attention (docs/Guides/gh-runner-runbook.md in MMI-Hub)."; exit 1; }
|
|
74
|
+
- name: Toolchain preflight
|
|
75
|
+
if: ${{ '{{GATE_RUNTIME}}' == 'python' }}
|
|
76
|
+
run: |
|
|
77
|
+
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; }
|
|
78
|
+
- run: {{GATE_INSTALL_CMD}}
|
|
79
|
+
# #3178: the check runs under the org wall-clock budget — a hung suite dies at the ceiling instead
|
|
80
|
+
# of squatting a runner lane for GitHub's 6h default. ci-audit + the release train enforce this step.
|
|
81
|
+
- uses: mutmutco/MMI-Hub/.github/actions/run-with-budget@{{GATE_BUDGET_SHA}}
|
|
82
|
+
with:
|
|
83
|
+
command: {{GATE_CMD}}
|
|
84
|
+
max-seconds: {{GATE_MAX_SECONDS}}
|
|
85
|
+
working-directory: {{GATE_WORKDIR}}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Google login — {{REPO_NAME}}
|
|
2
|
+
|
|
3
|
+
This repo has a Google OAuth client provisioned by the org — one client spanning local/`/stage`, dev, rc, and
|
|
4
|
+
prod. Adding Google login here is **self-serve**: you do not need master-admin help.
|
|
5
|
+
|
|
6
|
+
## Reach the creds (from SSM — never in git, never printed)
|
|
7
|
+
```bash
|
|
8
|
+
# Confirm they resolve for your repo (names only, no value):
|
|
9
|
+
mmi-cli vault secrets list
|
|
10
|
+
# Consume them keyless in a command — injected into its env, never printed (raw `secrets get` was removed, #2844):
|
|
11
|
+
mmi-cli vault secrets use GOOGLE_CLIENT_ID -- <cmd>
|
|
12
|
+
mmi-cli vault secrets use GOOGLE_CLIENT_SECRET -- <cmd>
|
|
13
|
+
```
|
|
14
|
+
The canonical keys are the stageless `GOOGLE_CLIENT_ID` + `GOOGLE_CLIENT_SECRET` pair at the project vault
|
|
15
|
+
root. The project-admin can manage them for their own repo; runtime and CI read them keylessly. Never bake a secret into an
|
|
16
|
+
image or commit it. The remote fileless deploy writes no release `.env`; **do not commit or hand-edit a `.env`**.
|
|
17
|
+
The only `.env` you may create is the gitignored one `/stage` makes from `.env.example` for local dev.
|
|
18
|
+
|
|
19
|
+
## The one rule that makes every environment work
|
|
20
|
+
Build the OAuth `redirect_uri` from the **incoming request** — never a hardcoded base URL:
|
|
21
|
+
- callback path: `/api/auth/callback`
|
|
22
|
+
- derive scheme + host from `X-Forwarded-Proto` / `X-Forwarded-Host` (set by the Caddy proxy), falling back
|
|
23
|
+
to the `Host` header.
|
|
24
|
+
|
|
25
|
+
The client's loopback redirect URIs are registered **port-agnostic**, so any local port works; dev/rc/prod
|
|
26
|
+
URIs are registered for both `mutatismutandis.co` and `mutmut.co`, so the deploy train works unchanged.
|
|
27
|
+
|
|
28
|
+
## Reference implementation + full guide
|
|
29
|
+
Inspect this repo's expected URIs and confirm the client is port-agnostic:
|
|
30
|
+
```bash
|
|
31
|
+
mmi-cli vault org oauth plan # the canonical JS origins + redirect URIs + SSM cred params
|
|
32
|
+
mmi-cli vault org oauth verify # probes an arbitrary :9123 loopback — no redirect_uri_mismatch = good
|
|
33
|
+
```
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Bootstrap seed manifest (#201) — the machine-readable contract of what /bootstrap and `mmi-cli devops bootstrap --apply` (#202) stamp into a target repo. Consumed by the CLI (loadBootstrapSeeds). ownership: 'org' = org-delivered, OVERWRITTEN on upgrade (the org owns it); 'repo' = created ONCE on a fresh bootstrap, never clobbered on upgrade (the repo owns its content). source: 'self' = copy MMI-Hub's own current file verbatim; 'seed:<file>' = render the named template in this dir with {{PLACEHOLDERS}}; 'managed-block' = merge the org-managed .gitignore block in place (preserves the repo's own ignore lines) — this is how the org-managed .gitignore block reaches every repo now that the fanout pipeline is retired (Hub#3010); the doctor SessionStart heal keeps it current thereafter. NOTE: this manifest seeds org-managed PRODUCT assets only — it never seeds AGENTS.md / CLAUDE.md / .claude/settings.json (personal agent guides) or a legacy repo-local control-plane marker. classes: which repo classes receive this seed.",
|
|
3
|
+
"placeholders": ["OWNER", "REPO", "REPO_SLUG", "REPO_NAME", "CLASS", "GATE_CMD", "GATE_PUSH_BRANCHES_YAML", "GATE_FULL_RUN_BRANCH", "GATE_RULESET_BRANCH_REFS_JSON", "PROJECT_OWNER", "PROJECT_NUMBER", "PROJECT_ID", "STATUS_FIELD_ID", "STATUS_TODO", "STATUS_IN_PROGRESS", "STATUS_IN_REVIEW", "STATUS_DONE", "STACK", "REGION"],
|
|
4
|
+
"seeds": [
|
|
5
|
+
{ "target": ".github/ISSUE_TEMPLATE/bug.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
6
|
+
{ "target": ".github/ISSUE_TEMPLATE/feature.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
7
|
+
{ "target": ".github/ISSUE_TEMPLATE/task.yml", "source": "self", "ownership": "org", "classes": ["deployable", "content"] },
|
|
8
|
+
{ "target": ".github/ISSUE_TEMPLATE/config.yml", "source": "self", "ownership": "repo", "classes": ["deployable", "content"] },
|
|
9
|
+
{ "target": "scripts/next-version.mjs", "source": "self", "ownership": "org", "classes": ["deployable"] },
|
|
10
|
+
{ "target": ".github/workflows/gate.yml", "source": "seed:gate.template.yml", "ownership": "repo", "classes": ["deployable"] },
|
|
11
|
+
{ "target": ".github/workflows/agent-pr.yml", "source": "self", "ownership": "org", "classes": ["deployable"], "waivers": { "jerv-jervcode": "pins this workflow's EXACT step shapes in its own scripts/workflow-boundary-core.mjs — a literal repositories: Jerv-JervCode token scope, and whole-step equality for the surface and verdict legs. #4040 widened the org seed to the same hardened boundary (pull_request_target off the trusted base, an immutable BASE..HEAD compare with a file-count equality wall, a per-repo App token scope, and a certified-head merge), so the two now agree on substance. They cannot agree on bytes: a seed serving 16 repos resolves its token scope and its required contexts at run time, which exact-step equality rejects by construction. The waiver is permanent by design, not a deferral — lifting it would mean weakening the strictest repo to match a fleet file." } },
|
|
12
|
+
{ "target": ".github/rulesets/mmi-product-required-checks.json", "source": "seed:mmi-product-required-checks.template.json", "ownership": "org", "classes": ["deployable"] },
|
|
13
|
+
{ "target": ".gitignore", "source": "managed-block", "ownership": "org", "classes": ["deployable", "content"] },
|
|
14
|
+
{ "target": "README.md", "source": "seed:README.template.md", "ownership": "repo", "classes": ["deployable", "content"] },
|
|
15
|
+
{ "target": "architecture.md", "source": "seed:architecture.template.md", "ownership": "repo", "classes": ["deployable", "content"] },
|
|
16
|
+
{ "target": "docs/decisions/README.md", "source": "seed:decisions-readme.template.md", "ownership": "repo", "classes": ["deployable", "content"] },
|
|
17
|
+
{ "target": "docs/Guides/google-login.md", "source": "seed:google-login.template.md", "ownership": "repo", "classes": ["deployable"], "projectTypes": ["web-app"] },
|
|
18
|
+
{ "target": "docker-compose.yml", "source": "seed:docker-compose.template.yml", "ownership": "repo", "classes": ["deployable"], "deployModels": ["tenant-container"] },
|
|
19
|
+
{ "target": "Dockerfile", "source": "seed:Dockerfile.template", "ownership": "repo", "classes": ["deployable"], "deployModels": ["tenant-container"] }
|
|
20
|
+
],
|
|
21
|
+
"labels": [
|
|
22
|
+
{ "name": "bug", "color": "d73a4a", "description": "Something is broken or behaving wrong" },
|
|
23
|
+
{ "name": "feature", "color": "a2eeef", "description": "New capability or enhancement" },
|
|
24
|
+
{ "name": "task", "color": "0052cc", "description": "Task, chore, or improvement" }
|
|
25
|
+
]
|
|
26
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "Repository-level ruleset requiring the product gate job (#1333). Apply via GitHub repo rulesets (master-admin) after bootstrap seeds gate.yml — the job name gate must match this context.",
|
|
3
|
+
"name": "mmi-product-required-checks",
|
|
4
|
+
"target": "branch",
|
|
5
|
+
"enforcement": "active",
|
|
6
|
+
"conditions": {
|
|
7
|
+
"ref_name": {
|
|
8
|
+
"include": {{GATE_RULESET_BRANCH_REFS_JSON}},
|
|
9
|
+
"exclude": []
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"rules": [
|
|
13
|
+
{
|
|
14
|
+
"type": "required_status_checks",
|
|
15
|
+
"parameters": {
|
|
16
|
+
"strict_required_status_checks_policy": false,
|
|
17
|
+
"required_status_checks": [
|
|
18
|
+
{ "context": "gate" }
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: browser-automation
|
|
3
|
+
description: Use DOM-first Playwright MCP for browser work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
**Host-native invocation:** Claude `/mmi:browser-automation` · Codex `$mmi:browser-automation` · jervcode/Kimi `/skill:browser-automation` · Kilo `skill` tool. A backticked `/name` in this doc names the matching workflow (this skill or a sibling), not a literal command.
|
|
7
|
+
|
|
8
|
+
# Browser automation — DOM-first Playwright MCP
|
|
9
|
+
|
|
10
|
+
Org standard for agent browser work on Claude Code. **Playwright** is the engine; agents interact through **structure-first** MCP tools, not pixels-first defaults.
|
|
11
|
+
|
|
12
|
+
## Doctrine (non-negotiable)
|
|
13
|
+
|
|
14
|
+
1. **Accessibility tree first** — semantic structure the agent can reason about (`browser_snapshot`, a11y refs).
|
|
15
|
+
2. **DOM second** — selectors, snapshots, network when the tree is not enough.
|
|
16
|
+
3. **Vision last** — screenshots only when tree + DOM cannot answer the question.
|
|
17
|
+
4. **Prefer HTTP/OpenAPI** — call APIs directly when discovery or the task allows; do not drive UI for data you can fetch.
|
|
18
|
+
|
|
19
|
+
**Never** pass `--caps=vision` (or equivalent vision-first defaults) on Playwright MCP org-wide. Vision caps burn tokens, hide structure, and break on theme/layout drift.
|
|
20
|
+
|
|
21
|
+
## When to use what
|
|
22
|
+
|
|
23
|
+
| Need | Use |
|
|
24
|
+
|------|-----|
|
|
25
|
+
| Local dev server + smoke on current branch | **`/stage`** — gitignored stack under `tmp/stage/`; see `skills/stage/SKILL.md` |
|
|
26
|
+
| Personal cloud dev preview of your branch | **`/stage --live`** — IP-gated dev stage; not rc/prod |
|
|
27
|
+
| Interactive UI debug, one-off flow, agent-driven clicks | **Playwright MCP** (this skill) — DOM-first, artifacts under `tmp/` |
|
|
28
|
+
| Durable hosted automation outside dev machines | **Stagehand + Browserbase** (production path) — explicit choice, not the default for every local task |
|
|
29
|
+
|
|
30
|
+
`/stage` and Playwright MCP **complement** each other. `/stage` spins the app; MCP drives the browser against a URL (often the stage URL).
|
|
31
|
+
|
|
32
|
+
## MCP configuration (no vision)
|
|
33
|
+
|
|
34
|
+
### Claude Code
|
|
35
|
+
|
|
36
|
+
Enable the official Playwright plugin (`playwright@claude-plugins-official`) via `/plugin`. Follow its DOM-first tools; do not enable vision-first modes for routine agent work. Point MCP output at `tmp/playwright-mcp` when the server accepts `--output-dir`.
|
|
37
|
+
|
|
38
|
+
Editor-host MCP configs (Cursor `.cursor/mcp.json`, Codex `config.toml`) are retired org surfaces (#2741/#2808) — bootstrap no longer seeds them; do not reintroduce them.
|
|
39
|
+
|
|
40
|
+
## Playwright availability
|
|
41
|
+
|
|
42
|
+
Check the configured/global CLI before adding a temporary local dependency. On Windows PowerShell:
|
|
43
|
+
|
|
44
|
+
```powershell
|
|
45
|
+
Get-Command playwright
|
|
46
|
+
playwright --version
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`node -e "require.resolve('playwright')"` only proves a Node module is installed in the current package; it
|
|
50
|
+
can fail while the global or editor-configured Playwright CLI works. Use the available CLI for smoke checks
|
|
51
|
+
and MCP setup. Temporary per-worktree installs are fallback-only, and should stay untracked.
|
|
52
|
+
|
|
53
|
+
## Agent workflow (MCP)
|
|
54
|
+
|
|
55
|
+
1. **Goal** — what observable outcome proves success?
|
|
56
|
+
2. **Navigate** — open the target URL (often from `/stage` JSON: `mmi-cli stage --json`).
|
|
57
|
+
3. **Snapshot** — a11y tree / DOM snapshot before interacting.
|
|
58
|
+
4. **Act** — click, type, select using refs from the latest snapshot.
|
|
59
|
+
5. **Re-snapshot** after navigation or major DOM changes (refs go stale).
|
|
60
|
+
6. **Vision only if stuck** — one screenshot to disambiguate; then return to tree/DOM.
|
|
61
|
+
|
|
62
|
+
Core MCP loop:
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
browser_navigate → browser_snapshot → browser_click / browser_type → browser_snapshot
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Artifacts and hygiene
|
|
69
|
+
|
|
70
|
+
- **All Playwright MCP output → `tmp/playwright-mcp/`** (pass `--output-dir tmp/playwright-mcp` when the MCP server supports it).
|
|
71
|
+
- **Never** leave traces, screenshots, or reports at the repo root.
|
|
72
|
+
- `.playwright-mcp/` at repo root is gitignored as a **safety net only** — not the canonical path.
|
|
73
|
+
- The housekeeping gate refuses tracked browser artifacts (`.playwright-mcp/`, `playwright-report/`, `test-results/`).
|
|
74
|
+
|
|
75
|
+
## Anti-patterns (org-wide avoid)
|
|
76
|
+
|
|
77
|
+
- `--caps=vision` or screenshot-first wrappers for routine tasks
|
|
78
|
+
- Skyvern, Magnitude, LaVague, or other vision-first agent browsers as org defaults
|
|
79
|
+
- Committing `.playwright-mcp/`, `playwright-report/`, or `test-results/` from agent runs
|
|
80
|
+
- Replacing `/stage` with ad-hoc MCP servers for branch smoke (use `/stage` for the stack, MCP for the browser)
|
|
81
|
+
|
|
82
|
+
## Related
|
|
83
|
+
|
|
84
|
+
- **`/stage`** — `skills/stage/SKILL.md`
|
|
85
|
+
- **`/grind`** (optional external tool) — use DOM-first browser checks in verification when criteria need UI proof
|
|
86
|
+
|
|
87
|
+
## Retro — one check before you finish
|
|
88
|
+
|
|
89
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
90
|
+
this run — ambiguous wording, a misleading MCP snippet, or an artifact path it should have warned
|
|
91
|
+
about? (Process only — never the user's code or task.) If yes, file **one** lesson and move on; a clean run is
|
|
92
|
+
silent (hard cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR —
|
|
93
|
+
never edit the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
94
|
+
|
|
95
|
+
`mmi-cli learning skill-lesson --skill browser-automation --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: epic
|
|
3
|
+
description: Decompose a vision or umbrella issue into linked child issues via one batch create.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# /epic — decompose an umbrella into children
|
|
7
|
+
|
|
8
|
+
Turn one large item — a vision issue, an epic, an umbrella issue — into a set of native sub-issues in a
|
|
9
|
+
single pre-validated batch, each already linked to its parent. This is the slice-and-fan-out act done by
|
|
10
|
+
hand today: draft the children, validate them all, create them, confirm the tree.
|
|
11
|
+
|
|
12
|
+
## Opening branch — create a new umbrella when none exists
|
|
13
|
+
|
|
14
|
+
When the request is a product intent rather than an existing issue, gather the intent first, read the
|
|
15
|
+
repo's live issue templates, draft the umbrella from the matching feature/task template, and show that
|
|
16
|
+
draft for the user's go. Only then create one issue with the `epic` label and an explicit Priority field;
|
|
17
|
+
re-read it from the board to prove the body, label, and priority landed. Stop there unless the user also
|
|
18
|
+
asked for and approved child decomposition.
|
|
19
|
+
|
|
20
|
+
## Step 0 — load the umbrella whole
|
|
21
|
+
|
|
22
|
+
Read the parent end-to-end before slicing — body **and every comment**, treating later comments as
|
|
23
|
+
superseding:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
mmi-cli oracle board show <owner/repo#N> # status, body, and every comment for the umbrella
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Slice by deliverable, not by phase: each child must be independently claimable and land in its own PR.
|
|
30
|
+
Keep the parent as the umbrella — do not close it until the last child merges.
|
|
31
|
+
|
|
32
|
+
## Step 1 — draft the batch file
|
|
33
|
+
|
|
34
|
+
Write a JSON array (one object per child) to a scratch path under `tmp/`. Each row:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
[
|
|
38
|
+
{ "type": "task", "title": "C1: extract the shared frame", "body": "…", "priority": "high",
|
|
39
|
+
"surface": "cli", "parent": "owner/repo#42" },
|
|
40
|
+
{ "type": "feature", "title": "C2: wire the new command", "body": "…", "priority": "medium",
|
|
41
|
+
"parent": "owner/repo#42" }
|
|
42
|
+
]
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
- `type` — `bug` · `feature` · `task` (required; maps to the repo's issue-template label).
|
|
46
|
+
- `title` — required, non-empty; keep it a short, greppable deliverable.
|
|
47
|
+
- `parent` — the umbrella ref (`#N`, `owner/repo#N`, or URL); links each child as a native sub-issue on
|
|
48
|
+
create, so you do not need a separate `link-child` pass. Cross-repo is fine (a Hub umbrella can parent
|
|
49
|
+
product-repo children).
|
|
50
|
+
- `priority` — `urgent|high|medium|low` (defaults to `medium`); sets the board Priority **field**.
|
|
51
|
+
- `repo` — optional per-row target repo (`owner/repo`); defaults to `--repo`, then the current repo.
|
|
52
|
+
This is how one batch fans children out across repos under a single umbrella.
|
|
53
|
+
- `surface` — required when the target repo uses `surface:*` taxonomy; accepts the value with or without
|
|
54
|
+
the prefix. A top-level `--surface <value>` may supply the default for every applicable row.
|
|
55
|
+
|
|
56
|
+
The batch **pre-validates every row before creating any** — one bad row fails the whole set with an
|
|
57
|
+
aggregate error, so you fix all of them once. Get the user's go on the drafted set before writing.
|
|
58
|
+
|
|
59
|
+
## Step 2 — create the children
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
mmi-cli oracle issue create --type task --batch tmp/epic-children.json --surface cli
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
`--type` is required by the create command but each row's own `type` governs; pass any valid type as the
|
|
66
|
+
placeholder. It prints per-row `{number,url}` results and fails loud on any misfire. Add
|
|
67
|
+
`--idempotency-key <key>` when a retried loop must not duplicate.
|
|
68
|
+
|
|
69
|
+
The idempotency lookup is find-before-create, not an atomic reservation. Run one batch writer at a time:
|
|
70
|
+
never submit concurrent creates with the same key. Size the calling command's wall-clock budget for the
|
|
71
|
+
whole sequential batch. If the command times out, its outcome is unknown — confirm the process has ended,
|
|
72
|
+
wait for writes to quiesce, inspect the children, then retry the missing rows with the same key.
|
|
73
|
+
|
|
74
|
+
## Step 3 — confirm the tree
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
mmi-cli oracle issue children <owner/repo#N> # each child: number/title/state/repo/boardStatus/linkedPrs
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Verify every intended child is linked and on the board as Todo. To link a child that already existed (not
|
|
81
|
+
part of the batch), use the inverse-friendly single link:
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
mmi-cli oracle issue link-child <parent> <child>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Each child is now a parallel item — fan them out one worktree + PR each. **When the last child merges,
|
|
88
|
+
close the umbrella** (its board `Done` follows automatically).
|
|
89
|
+
|
|
90
|
+
## Notes
|
|
91
|
+
|
|
92
|
+
- Native sub-issues, not a body task-list: the parent renders a sub-issue checklist and each child renders
|
|
93
|
+
its parent — nothing to hand-maintain.
|
|
94
|
+
- Never free-type children with raw `gh issue create` — the batch path carries validation, board attach,
|
|
95
|
+
and structured output.
|
|
96
|
+
|
|
97
|
+
## Retro — one check before you finish
|
|
98
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
99
|
+
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
100
|
+
about? (Process only — never the user's code or task; e.g. a batch schema that rejected a valid row, or a
|
|
101
|
+
link that attached to the wrong parent.) If yes, file **one** lesson and move on; a clean run is silent
|
|
102
|
+
(hard cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR — never
|
|
103
|
+
edit the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
104
|
+
`mmi-cli learning skill-lesson --skill epic --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hotfix
|
|
3
|
+
description: Promote an already-merged development fix to main and production through the gated Hub train.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
**Host-native invocation:** Claude `/mmi:hotfix` · Codex `$mmi:hotfix` · jervcode/Kimi `/skill:hotfix` · Kilo `skill` tool. A backticked `/name` in this doc names the matching workflow (this skill or a sibling), not a literal command.
|
|
7
|
+
|
|
8
|
+
# /hotfix — promote a development fix to main + prod
|
|
9
|
+
|
|
10
|
+
A hotfix is promotion, not authoring. The fix must land on `development` through a normal issue,
|
|
11
|
+
worktree, PR, review, and CI gate first. Hub then ports that merged PR or SHA to a main-base hotfix PR,
|
|
12
|
+
preserves the cherry-pick audit trail, and performs the PATCH release. Never author directly from `main`.
|
|
13
|
+
Never author the fix on a branch off `main`. The main-base branch is only the orchestrated port of a fix
|
|
14
|
+
that is already merged to `development`.
|
|
15
|
+
|
|
16
|
+
The FIX is never back-merged: `development` already contains it, and `rc` absorbs it at the next
|
|
17
|
+
`/rcand`. The release hotfix-coverage guard blocks a later candidate that omits the production fix.
|
|
18
|
+
|
|
19
|
+
The VERSION FOLD is different, and `hotfix release` ports it for you (#4410). `hotfix start` commits the
|
|
20
|
+
fold onto the main-base branch, so after the tag `main` declares the new version while `development`
|
|
21
|
+
still declares the old one. The Hub's catalogs now pin exact npm packages (#4948), so there is no
|
|
22
|
+
branch/content lockstep red; the fold still must land so the next release starts from production's real
|
|
23
|
+
version, BOM, and package pins. Step 3 opens that development-base fold PR automatically; land it.
|
|
24
|
+
|
|
25
|
+
## Merge floor (#3167 — non-negotiable)
|
|
26
|
+
|
|
27
|
+
- **Never squash-merge a tagged commit.** The hotfix PR itself may squash (step 2 — the tag lands *after*,
|
|
28
|
+
on the merged `main` HEAD, and the `-x` trailer must survive the squash message). But any merge that
|
|
29
|
+
carries an already-tagged commit — an alignment PR, a later `main → development` roll-forward — lands as a
|
|
30
|
+
true merge, never squash: a squash re-mints the SHA and orphans the tag from the branch lineage.
|
|
31
|
+
- **A refused release train is a stop, never a license to finish by hand.** A conflict on the port, a red
|
|
32
|
+
authority probe, a failed required check, a refused `hotfix release` — each ends the run. Fix the cause on
|
|
33
|
+
`development` through a normal PR and re-run the orchestrator; never hand-cherry-pick, bare-push, or
|
|
34
|
+
bypass the gate to finish.
|
|
35
|
+
- **Version probes anchor on the latest Release tag, not a branch.** `hotfix status` derives the PATCH from
|
|
36
|
+
the latest Release tag; branch manifests and stale local tags are not version sources.
|
|
37
|
+
|
|
38
|
+
## Authority and preflight
|
|
39
|
+
|
|
40
|
+
Production changes require the authorized human's explicit approval in the current turn. Verify authority
|
|
41
|
+
and CLI health before starting:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
mmi-cli oracle org access role <owner/repo> --json
|
|
45
|
+
mmi-cli doctor --no-repo-writes
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Stop on a red authority or CLI-version result. The worktree must be clean; move scratch into `tmp/` or
|
|
49
|
+
gitignore it rather than widening the hotfix diff. A TRACKED path named in a `working tree must be clean
|
|
50
|
+
before …` refusal is not scratch: read both `git status --porcelain` columns, treat every state except
|
|
51
|
+
exactly ` M` as real work to commit or stash, and for ` M` discard only when
|
|
52
|
+
`git diff HEAD --numstat -- <paths>` is empty, and only with `git checkout -- <paths>`. Plain
|
|
53
|
+
`git diff --numstat` prints nothing for a merely staged change, so it cannot make that call (#4004).
|
|
54
|
+
|
|
55
|
+
## 1. Start from the merged development fix
|
|
56
|
+
|
|
57
|
+
Use the orchestrator with an explicit source every time:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
mmi-cli devops hotfix start --from <development-pr-or-sha>[,<development-pr-or-sha>...] --json
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**One hotfix cycle carries as many merged fixes as you name.** `--from` takes a comma-separated list in
|
|
64
|
+
pick order, and every sha it picks goes into the PR's carries marker, so the release proves each one
|
|
65
|
+
present before tagging. Do not open one hotfix per fix: batch everything ready for production into the
|
|
66
|
+
single PATCH. A fix that only becomes ready mid-cycle rides the same tag — cherry-pick it with `-x` onto
|
|
67
|
+
a `hotfix/<tag>-<n>` continuation branch, merge that PR, and rerun `hotfix release` with the full
|
|
68
|
+
`--carries` list; the release pins the newest merged SHA (#1025).
|
|
69
|
+
|
|
70
|
+
`hotfix start` resolves the PATCH version, branches from `origin/main`, performs the cherry-pick with `-x`,
|
|
71
|
+
prepares Hub distribution artifacts when applicable (stamping BOM `sourceCommit` at the durable
|
|
72
|
+
`origin/main` merge-base so a squash merge cannot orphan it — #4361; and for `registry-publish`
|
|
73
|
+
consumers, folds the package version so upgrade probes observe the PATCH), pushes the branch, and opens
|
|
74
|
+
the main-base PR. Do not duplicate those steps with raw branch commands, manual cherry-picks, or raw
|
|
75
|
+
GitHub PR creation.
|
|
76
|
+
|
|
77
|
+
Conflicts confined to regenerable distribution / version-fold paths (e.g. Hub `distribution-bom.json`,
|
|
78
|
+
locked plugin manifests, consumer `package.json`) — and, for hub-serverless + registry-publish, shipped
|
|
79
|
+
skill roots `skills/` and `.kilo-plugin/skills/` (#4363 / #4471) — are auto-resolved (take the picked
|
|
80
|
+
side) and regenerated by the bump/fold step. Source TS under `src/` / `cli/src/` is never auto-resolved.
|
|
81
|
+
|
|
82
|
+
Before cutting the hotfix branch, `hotfix start` preflights every `--from` pick on an accumulating
|
|
83
|
+
`origin/main` tree (#4472). If any pick would hard-stop, it refuses with every failing pick and path and
|
|
84
|
+
prescribes **one** development-based cite-only synthesis PR for the whole batch (#4643; the old
|
|
85
|
+
"cut from origin/main" pattern #4467 wording is retired — a main-parented branch must never merge
|
|
86
|
+
into development, #4365/#4371): cut from `origin/development`, regenerate the conflicting content so
|
|
87
|
+
it cherry-picks cleanly onto `origin/main`, land it with the cite-only marker (the #5096 flow) — not N
|
|
88
|
+
serial ports. Behavior changes still land on `development` first through a normal PR, then rerun hotfix
|
|
89
|
+
start from the port merge SHA(s) — never hand-resolve onto main.
|
|
90
|
+
|
|
91
|
+
## 2. Verify the hotfix PR
|
|
92
|
+
|
|
93
|
+
Run the repo's local gate against the hotfix branch, then obtain the independent reviewer required by the
|
|
94
|
+
active agent doctrine. Review the actual main-base diff and the original issue acceptance criteria.
|
|
95
|
+
|
|
96
|
+
Wait for required CI through Hub:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
mmi-cli devops pr checks-wait <hotfix-pr-number>
|
|
100
|
+
mmi-cli devops pr merge <number> --squash
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The main-base PR is the production gate. Do not bypass checks or protected-branch authority. After the
|
|
104
|
+
authorized merge, verify the merged main commit still carries the cherry-pick provenance; if the PR was
|
|
105
|
+
squashed, the source trailer must survive in the squash message so future coverage checks remain exact.
|
|
106
|
+
Because Hub's default branch is `development`, the main-base hotfix PR does not close a separate tracking
|
|
107
|
+
issue. The development PR should already have closed the work item; do not add raw GitHub issue operations.
|
|
108
|
+
|
|
109
|
+
## 3. Run the gated release
|
|
110
|
+
|
|
111
|
+
Derive the tag from `mmi-cli devops hotfix status`, then release with the same declared source:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
mmi-cli devops hotfix status
|
|
115
|
+
mmi-cli devops hotfix release <vX.Y.Z> --carries <development-pr-or-sha>[,<development-pr-or-sha>...]
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
Name **every** fix the cycle carries. Each is proven an ancestor of the tagged SHA before tagging; a
|
|
119
|
+
missing one refuses the release and names the continuation path.
|
|
120
|
+
|
|
121
|
+
For MMI-Hub, pass a fresh 2-4 line neutral summary file with `--announce-summary-file`; never reuse a
|
|
122
|
+
stale file and never put a product or brand name in the summary. Hub release scope never includes another
|
|
123
|
+
repo's board or `ds-propagate.yml`. The orchestrator creates the tag and GitHub Release, selects the
|
|
124
|
+
registry-declared deploy path, watches the release-triggered or central deployment, verifies distribution,
|
|
125
|
+
and announces best-effort. Do not hand-dispatch a second publish/deploy path: duplicate release events can
|
|
126
|
+
race or double-publish.
|
|
127
|
+
|
|
128
|
+
For a private package, trust the authenticated publish job and its logged package/version result; a bare
|
|
129
|
+
unauthenticated `npm view` cannot distinguish private from missing.
|
|
130
|
+
|
|
131
|
+
## 4. Verify and report
|
|
132
|
+
|
|
133
|
+
Report the tag and Release URL, production run and URL, source development PR/SHA, hotfix PR, and these
|
|
134
|
+
branch facts:
|
|
135
|
+
|
|
136
|
+
- `main`: the tag commit is on `origin/main`.
|
|
137
|
+
- `development`: the source fix was already merged before the hotfix began.
|
|
138
|
+
- `rc`: intentionally untouched; the next release coverage gate prevents regression.
|
|
139
|
+
- the development fold PR the release opened (`hotfix-fold/<tag>`), and whether it landed.
|
|
140
|
+
|
|
141
|
+
Do not hand-open a manifest-alignment PR: the version fold is already ported by `hotfix release` — land
|
|
142
|
+
its PR instead of authoring one. That port is explicitly NOT a back-merge — nothing from `main` is
|
|
143
|
+
merged into `development`; the fold is regenerated on a branch cut from `development` itself. If the run
|
|
144
|
+
reported `development fold port FAILED`, follow the manual remedy it named; never improvise a merge from
|
|
145
|
+
`main`.
|
|
146
|
+
|
|
147
|
+
### Development fold after a hotfix (#4517 / #4948)
|
|
148
|
+
|
|
149
|
+
The Hub's thin catalogs now pin exact npm packages, so the old main-anchored catalog-lockstep gate is
|
|
150
|
+
retired: an unreleased branch cannot deliver a package version the release train has not published.
|
|
151
|
+
Hotfix versioning still belongs on the main-base train, never in an improvised development prepare PR:
|
|
152
|
+
|
|
153
|
+
1. `mmi-cli devops hotfix start --from <merged-dev-pr-or-sha>` (prepare + distribution bump on `hotfix/vX.Y.Z` from `main`)
|
|
154
|
+
2. merge the hotfix PR → `mmi-cli devops hotfix release vX.Y.Z` (publish)
|
|
155
|
+
3. land the automatic `hotfix-fold/<tag>` development fold PR (or follow its printed remedy)
|
|
156
|
+
|
|
157
|
+
The fold is now required for version/BOM/package-pin continuity, not to clear a branch-content gate.
|
|
158
|
+
|
|
159
|
+
## Retro
|
|
160
|
+
|
|
161
|
+
If this skill's instructions themselves misfired, file one deduplicated lesson and continue:
|
|
162
|
+
|
|
163
|
+
```bash
|
|
164
|
+
mmi-cli learning skill-lesson --skill hotfix --title "<what misfired>" --body "<what; evidence; proposed amendment>"
|
|
165
|
+
```
|