@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.
Files changed (45) hide show
  1. package/.codex-plugin/plugin.json +30 -0
  2. package/bin/mmi-cli +6 -0
  3. package/bin/mmi-cli.cmd +3 -0
  4. package/bin/mmi-hook +2 -0
  5. package/bin/mmi-hook-console.cmd +10 -0
  6. package/bin/mmi-hook.exe +0 -0
  7. package/hooks/codex-hooks.json +41 -0
  8. package/package.json +21 -0
  9. package/scripts/command-ladder-core.mjs +334 -0
  10. package/scripts/command-ladder-gate.mjs +126 -0
  11. package/scripts/deny-gate-crash.mjs +179 -0
  12. package/scripts/edit-tool-paths.mjs +113 -0
  13. package/scripts/env-write-lint.mjs +137 -0
  14. package/scripts/hook-io.mjs +22 -0
  15. package/scripts/hook-policy.mjs +73 -0
  16. package/scripts/hook-run.mjs +437 -0
  17. package/scripts/hook-trace.mjs +151 -0
  18. package/scripts/pretooluse-shell-gates.mjs +424 -0
  19. package/scripts/secret-echo-lint.mjs +177 -0
  20. package/scripts/secret-redact.mjs +552 -0
  21. package/scripts/throttle-core.mjs +324 -0
  22. package/scripts/validate-hook.mjs +156 -0
  23. package/scripts/vault-edit-gate.mjs +94 -0
  24. package/skills/bootstrap/SKILL.md +550 -0
  25. package/skills/bootstrap/seeds/Dockerfile.template +30 -0
  26. package/skills/bootstrap/seeds/README.template.md +37 -0
  27. package/skills/bootstrap/seeds/architecture.template.md +34 -0
  28. package/skills/bootstrap/seeds/decisions-readme.template.md +45 -0
  29. package/skills/bootstrap/seeds/docker-compose.template.yml +26 -0
  30. package/skills/bootstrap/seeds/gate.template.yml +85 -0
  31. package/skills/bootstrap/seeds/google-login.template.md +33 -0
  32. package/skills/bootstrap/seeds/manifest.json +26 -0
  33. package/skills/bootstrap/seeds/mmi-product-required-checks.template.json +23 -0
  34. package/skills/browser-automation/SKILL.md +95 -0
  35. package/skills/epic/SKILL.md +104 -0
  36. package/skills/hotfix/SKILL.md +165 -0
  37. package/skills/mmi/SKILL.md +404 -0
  38. package/skills/mmi-doctor/SKILL.md +63 -0
  39. package/skills/onboard/SKILL.md +85 -0
  40. package/skills/rcand/SKILL.md +208 -0
  41. package/skills/release/SKILL.md +599 -0
  42. package/skills/resume/SKILL.md +90 -0
  43. package/skills/secrets/SKILL.md +159 -0
  44. package/skills/stage/SKILL.md +153 -0
  45. 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>"`