@mutmutco/claude-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/.claude-plugin/plugin.json +11 -0
- package/.pi-plugin/package.json +23 -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/hooks.json +38 -0
- package/package.json +22 -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,208 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rcand
|
|
3
|
+
description: Promote development to a release-candidate branch.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
**Host-native invocation:** Claude `/mmi:rcand` · Codex `$mmi:rcand` · jervcode/Kimi `/skill:rcand` · Kilo `skill` tool. A backticked `/name` in this doc names the matching workflow (this skill or a sibling), not a literal command.
|
|
7
|
+
|
|
8
|
+
# /rcand — promote development to release-candidate
|
|
9
|
+
|
|
10
|
+
Merge `development → rc`, tag `vX.Y.0-rc.N`, push (the GitHub authority gate), then dispatch the rc deploy
|
|
11
|
+
path. **Train-authority gated (D14):** the repo's project-admin or the master. Direct-track repos
|
|
12
|
+
(product repos with `releaseTrack: direct`, plus MMI-Hub via the `isHubControlRepo` special-case) are the exception: they skip rc and `/rcand` refuses there;
|
|
13
|
+
run `/release` from `development` instead. The board needs no touch
|
|
14
|
+
here — items reach `Done` when their PR merges to `development` (native close → Done); `rc` is a deploy
|
|
15
|
+
stage, not a lane.
|
|
16
|
+
|
|
17
|
+
Authority is **structural + server-checked**: step 0 asks the Hub (`mmi-cli oracle org access role`), and step 4
|
|
18
|
+
pushes to the protected `rc` branch, whose per-repo allowlist carries the same people (master + that repo's
|
|
19
|
+
project-admins). No `.env` role marker. Gate ordering: the tag lands the rc SHA
|
|
20
|
+
for checks, and every deploy side-effect waits until the protected `rc` push accepts that checked SHA.
|
|
21
|
+
|
|
22
|
+
## Step 0 — train-authority probe (server-side, D14)
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
mmi-cli oracle org access role {owner}/{repo} --json # Hub-verified: { role, train }
|
|
26
|
+
```
|
|
27
|
+
`train: false` — or ANY error (fail closed) → stop: a product repo's train belongs to that repo's
|
|
28
|
+
**project-admin** (repo write + registry `projectAdmins`) or the master. When `project-admin` + `train`,
|
|
29
|
+
proceed — do not redirect to the master (`AGENTS.md` § Authority). Errors → fix `gh auth` first,
|
|
30
|
+
never proceed unverified.
|
|
31
|
+
|
|
32
|
+
**CLI freshness (#2562):** check the running CLI is current BEFORE step 1 — `mmi-cli devops rcand --apply` refuses
|
|
33
|
+
a stale CLI at its own step 0 (pre-mutation), but the manual steps below mutate local state earlier, so a
|
|
34
|
+
stale CLI discovered late reads as a mid-train abort. When another train just published a new CLI (e.g. a
|
|
35
|
+
Hub release), run `mmi-cli doctor --no-repo-writes` first. A stale-CLI refusal itself changes
|
|
36
|
+
nothing; after updating, the rerun resumes any partial train state safely.
|
|
37
|
+
|
|
38
|
+
**Run from the checkout that already has `development` — never a fresh isolated worktree (#2770).** This is
|
|
39
|
+
a shared-branch train operation (merge/tag/push against origin's protected `rc`), not an isolated
|
|
40
|
+
feature-branch edit. A background-job harness that isolates every task into a fresh worktree by default
|
|
41
|
+
breaks here: `git worktree`s cannot have the same branch checked out twice, so a fresh worktree can't check
|
|
42
|
+
out `development` while the primary checkout already has it. Exit any such worktree first and run from the
|
|
43
|
+
primary checkout.
|
|
44
|
+
|
|
45
|
+
## Step 1 — development ahead of rc?
|
|
46
|
+
|
|
47
|
+
Preconditions: on `development`, clean tree. The clean-tree check rejects UNTRACKED scratch too, not just
|
|
48
|
+
modified tracked files — if `--apply` stops with `working tree must be clean before …`, run `git status
|
|
49
|
+
--porcelain` on the paths it named and read both columns. Gitignore the `??` scratch (or move it to a
|
|
50
|
+
gitignored path like `tmp/`). Treat every tracked state except exactly ` M` as real work to commit or stash;
|
|
51
|
+
for ` M`, discard only when `git diff HEAD --numstat -- <paths>` is empty, and only with
|
|
52
|
+
`git checkout -- <paths>`. Plain `git diff --numstat` prints nothing for a merely staged change, so it
|
|
53
|
+
cannot tell real work from line-ending churn (#1472, #4004).
|
|
54
|
+
```bash
|
|
55
|
+
git fetch origin
|
|
56
|
+
git rev-list --count origin/rc..origin/development
|
|
57
|
+
```
|
|
58
|
+
Dirty → stop. Count `0` → stop ("nothing to promote"). `>0` → capture the commit list for the report.
|
|
59
|
+
|
|
60
|
+
> Verifying CLI/plugin-health before a train? Use `mmi-cli doctor --no-repo-writes`: it runs the
|
|
61
|
+
> env/plugin repairs but never mutates the working tree, so a pending org-managed `.gitignore` repair is
|
|
62
|
+
> reported with its follow-up command instead of dirtying the product checkout right before promotion.
|
|
63
|
+
> Apply that follow-up after the train.
|
|
64
|
+
|
|
65
|
+
## Step 1b — registry + rc secret-name preflight
|
|
66
|
+
|
|
67
|
+
Resolve the project META first; its `deployModel` decides the deploy path. `tenant-container` repos use the
|
|
68
|
+
central tenant deployer and therefore need DEPLOY# coords. Serverless, `registry-publish`, and
|
|
69
|
+
`solo-container` repos deploy from their own workflow, so do **not** dispatch `tenant-deploy.yml` for them.
|
|
70
|
+
Direct-track repos (`releaseTrack: direct`, e.g. MMI-Hub) have no rc candidate path; `mmi-cli devops rcand --apply`
|
|
71
|
+
refuses after this preflight.
|
|
72
|
+
Verify META + required SSM secret names before touching `rc`:
|
|
73
|
+
```bash
|
|
74
|
+
mmi-cli oracle org project get {owner}/{repo}
|
|
75
|
+
mmi-cli vault secrets preflight --stage rc --repo {owner}/{repo}
|
|
76
|
+
```
|
|
77
|
+
Missing META or secret names → stop and repair the registry/secrets first.
|
|
78
|
+
|
|
79
|
+
## Step 2 — merge development → rc (never force)
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git checkout rc
|
|
83
|
+
git pull --ff-only origin rc
|
|
84
|
+
git merge development --no-edit
|
|
85
|
+
```
|
|
86
|
+
Conflict → `git merge --abort`, report paths, resolve on `development`, re-run.
|
|
87
|
+
|
|
88
|
+
**Exception — version manifests only.** When every conflicted path is a version manifest
|
|
89
|
+
(`package.json` · `package-lock.json`), the incoming `development` side carries the org truth — the
|
|
90
|
+
`/release` version fold (#976) bumps manifests on `main` and the release back-merge brings them to
|
|
91
|
+
`development`, so `development` is always the newer side. Take it deterministically and continue (no
|
|
92
|
+
hand-resolution, no abort):
|
|
93
|
+
```bash
|
|
94
|
+
git checkout --theirs package.json package-lock.json && git add package.json package-lock.json
|
|
95
|
+
git commit --no-edit
|
|
96
|
+
```
|
|
97
|
+
Any other conflicted path in the same merge → abort as above. Tag (step 3) only AFTER the merge commit
|
|
98
|
+
exists — a tag minted before the conflict resolution points at the wrong SHA.
|
|
99
|
+
|
|
100
|
+
## Step 3 — tag the rc
|
|
101
|
+
|
|
102
|
+
The shared helper derives the next rc tag from existing tags (re-run-safe — `-rc.N` increments). `rc` mode
|
|
103
|
+
reads `MMI_BUMP_INTENT`; unset it resolves to `patch` (#4929) — declare `minor`/`major` explicitly for a
|
|
104
|
+
planned feature cycle:
|
|
105
|
+
```bash
|
|
106
|
+
TAG=$(MMI_BUMP_INTENT=minor node scripts/next-version.mjs rc) # -> vX.Y.0-rc.N
|
|
107
|
+
git tag "$TAG"
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## Step 4 — push tag, wait for the REQUIRED checks, then push rc (the gate)
|
|
111
|
+
|
|
112
|
+
Required status checks are **per-repo branch protection, not a fixed list** — MMI-Hub requires `cli` ·
|
|
113
|
+
`infra` · `docs`, but a product repo may require different contexts or none at all (#1045). A fresh merge
|
|
114
|
+
SHA has no check-runs yet, so when checks ARE required, pushing the branch *first* is structurally rejected
|
|
115
|
+
until CI catches up (it then succeeds on a retry — avoidable noise). Push the **tag first**: it lands the
|
|
116
|
+
SHA and triggers the repo's CI without touching the protected branch ref. Then probe what `rc` actually
|
|
117
|
+
requires and wait only for those contexts:
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
git push origin "vX.Y.0-rc.N" # lands the SHA + triggers the repo's CI
|
|
121
|
+
SHA=$(git rev-parse rc)
|
|
122
|
+
# discover the REQUIRED contexts on rc (classic protection + rulesets; 404 = none from that source):
|
|
123
|
+
gh api repos/{owner}/{repo}/branches/rc/protection/required_status_checks --jq '[.contexts[]]'
|
|
124
|
+
gh api repos/{owner}/{repo}/rules/branches/rc \
|
|
125
|
+
--jq '[.[]|select(.type=="required_status_checks")|.parameters.required_status_checks[].context]'
|
|
126
|
+
# ZERO required contexts -> push rc immediately (the GitHub push gate is the backstop).
|
|
127
|
+
# Otherwise poll until every required context is "success" on $SHA — never a hard-coded list, and bound
|
|
128
|
+
# the wait (~10 min): on timeout, stop with a clear failure naming the pending/failed contexts.
|
|
129
|
+
gh api repos/{owner}/{repo}/commits/$SHA/check-runs \
|
|
130
|
+
--jq '[.check_runs[]|{name:.name,conclusion:.conclusion}]'
|
|
131
|
+
git push origin rc
|
|
132
|
+
```
|
|
133
|
+
(`mmi-cli devops rcand --apply` performs this discovery + bounded wait itself.)
|
|
134
|
+
Rejected (protected / not a bypass actor) → stop, nothing deployed, no board writes; leave the local tag
|
|
135
|
+
for an authorized re-push, never force. Non-fast-forward → re-pull, re-run from step 1.
|
|
136
|
+
|
|
137
|
+
## Step 5 — rc deploy (model-specific, non-blocking)
|
|
138
|
+
|
|
139
|
+
For `tenant-container` repos, dispatch the Hub **tenant-deploy.yml** workflow for rc (OIDC, keyless). Don't
|
|
140
|
+
deploy by hand, and **don't block on it** — start the watch as a background task and move straight to
|
|
141
|
+
Step 6:
|
|
142
|
+
```bash
|
|
143
|
+
gh workflow run tenant-deploy.yml --repo mutmutco/MMI-Hub \
|
|
144
|
+
-f slug={slug} -f repo={owner}/{repo} -f ref=rc -f stage=rc
|
|
145
|
+
gh run watch "$(gh run list --workflow tenant-deploy.yml --limit 1 --json databaseId -q '.[0].databaseId')" \
|
|
146
|
+
--exit-status # run this in the BACKGROUND (Bash run_in_background) — capture its URL for the report
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
For serverless repos, do **not** dispatch `tenant-deploy.yml`: their own push-triggered workflow owns the
|
|
150
|
+
rc deploy.
|
|
151
|
+
|
|
152
|
+
`mmi-cli devops rcand --apply --json` returns the relevant run `runId` + `runUrl` (alongside `deployStatus`), so
|
|
153
|
+
you never hand-correlate Actions. For tenant-container repos, that is the dispatched `tenant-deploy.yml`
|
|
154
|
+
run. For Hub serverless, that is the auto-fired `deploy.yml` run from the protected `rc` push. Add
|
|
155
|
+
`--watch` to block on the run and have `deployStatus` resolve to `success`/`failure`; `promoted: true`
|
|
156
|
+
stays set either way — a failed **deploy** never undoes the **promotion**.
|
|
157
|
+
|
|
158
|
+
The deploy runs while you report. When the background watch returns, surface the outcome:
|
|
159
|
+
**green** → note the run + rc env URL; **red** → report plainly. The rc tag is already pushed, so the
|
|
160
|
+
correct next action is a **deploy retry of the existing rc ref** after the Hub runtime is repaired — never
|
|
161
|
+
a re-tag/re-merge:
|
|
162
|
+
```bash
|
|
163
|
+
mmi-cli devops runtime tenant redeploy {owner}/{repo} rc --watch # re-dispatch tenant-deploy.yml for the promoted rc
|
|
164
|
+
```
|
|
165
|
+
**Branch the recovery by failure class — a bare redeploy is NOT always the whole recovery.** For **exit 78**
|
|
166
|
+
(`compose is fileless but DEPLOY#<stage>.noEnvFile is not true`) a plain redeploy fails identically: the
|
|
167
|
+
box's baked `/opt/mmi-control/<slug>.sh` still carries the stale `noEnvFile`, so it writes no `.env` while
|
|
168
|
+
the fileless compose expects passthrough. Fix the registry AND re-render the box control script first, then
|
|
169
|
+
redeploy (`set-deploy` alone is not enough — the reconcile is the discoverable-but-non-obvious middle step):
|
|
170
|
+
```bash
|
|
171
|
+
mmi-cli oracle org project set-deploy {owner}/{repo} --stage rc --no-env-file true # register the DEPLOY#rc fileless flag
|
|
172
|
+
mmi-cli devops runtime tenant reconcile {owner}/{repo} rc --watch # Hub-authorized; project-admin needs no MMI-Hub Actions access
|
|
173
|
+
mmi-cli devops runtime tenant redeploy {owner}/{repo} rc --watch # NOW the redeploy reads the corrected control script
|
|
174
|
+
mmi-cli devops runtime tenant control {owner}/{repo} rc verify-broker --watch # value-free broker proof for runtime consumers
|
|
175
|
+
```
|
|
176
|
+
The reconcile must finish green before redeploy starts; `--watch` enforces that ordering. A failed rc
|
|
177
|
+
dispatch stays fail-loud — rc is ephemeral and re-runnable, so the redeploy (after the reconcile step above
|
|
178
|
+
for an exit-78 fileless mismatch) re-runs it.
|
|
179
|
+
|
|
180
|
+
## Step 6 — report
|
|
181
|
+
|
|
182
|
+
Version `vX.Y.0-rc.N` · merged commits · rc deploy run + env URL.
|
|
183
|
+
|
|
184
|
+
## Notes
|
|
185
|
+
|
|
186
|
+
- `rc` is NOT prod. Shipping `rc → main → prod` is `/release` (ships exactly what's on `rc`; never pulls
|
|
187
|
+
`development`). Never force-push `rc`; never commit to `rc` outside the step-2 merge.
|
|
188
|
+
- `rc` is **ephemeral**: `/rcand` creates the rc runtime, `/release` retires it after a confirmed prod
|
|
189
|
+
deploy. A full-track repo can skip rc entirely with `/release --dev` (`development → main`); `/hotfix`
|
|
190
|
+
always skips rc (it cherry-picks `development → main` directly).
|
|
191
|
+
- **MAJOR / exact-target cycle:** for a release the tag math can't derive (a MAJOR like `2.0.0`, or skipping
|
|
192
|
+
a version already on npm), export `MMI_RELEASE_VERSION=X.Y.Z` before `/rcand` — `next-version.mjs rc` then
|
|
193
|
+
opens that exact cycle (validated to move strictly forward). Keep it exported through `/release`.
|
|
194
|
+
- **`MMI_BUMP_INTENT=major|minor|patch` selects the increment for `next-version.mjs rc`** (Step 3); absent,
|
|
195
|
+
it defaults to `patch` (#4929). **Export it for the whole run:** `mmi-cli devops rcand --apply` resolves
|
|
196
|
+
the intent itself with the same default, so a one-off prefix on the `next-version.mjs` command leaves the
|
|
197
|
+
apply deriving a different increment than the tag you minted. This is
|
|
198
|
+
a different knob from `MMI_RELEASE_VERSION` above: `MMI_BUMP_INTENT` picks the increment,
|
|
199
|
+
`MMI_RELEASE_VERSION` overrides the computed version entirely and is for the exceptional case only.
|
|
200
|
+
|
|
201
|
+
## Retro — one check before you finish
|
|
202
|
+
Before your final report, answer one question honestly: did **this skill's own instructions** misfire
|
|
203
|
+
this run — ambiguous wording, a misleading message, or an environment failure it should have warned
|
|
204
|
+
about? (Process only — never the user's code or task; e.g. a misleading authority or gate message, or an
|
|
205
|
+
ambiguous tag or push-order step.) If yes, file **one** lesson and move on; a clean run is silent (hard
|
|
206
|
+
cap: one per run). It lands on the Hub board (deduped) and is fixed only via a reviewed PR — never edit
|
|
207
|
+
the skill live; the retro is advisory, so if the call fails, note it and continue:
|
|
208
|
+
`mmi-cli learning skill-lesson --skill rcand --title "<what misfired>" --body "<what; evidence; proposed amendment>"`
|