@mutmutco/pi-plugin 4.2.1 → 4.2.3
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/package.json +1 -1
- package/scripts/env-write-lint.mjs +12 -3
- package/skills/release/SKILL.md +28 -0
package/package.json
CHANGED
|
@@ -46,6 +46,15 @@ const PS_WRITE_RE = new RegExp(
|
|
|
46
46
|
// `copy`/`move` are the cmd.exe spellings AND the default PowerShell aliases for Copy-Item/Move-Item, so
|
|
47
47
|
// `copy .env.example .env` reached disk past every analyzer (pre-existing since #2663; found by the #3563
|
|
48
48
|
// cross-vendor check, openai-sol). `xcopy`/`robocopy` are the other two Windows spellings.
|
|
49
|
+
|
|
50
|
+
// #5820: segment separators include NEWLINES. Without them a multi-line script — a heredoc body, an
|
|
51
|
+
// SSH `bash -s` payload — collapses into ONE segment, and the copy/git/touch scans below then pair a
|
|
52
|
+
// verb on one line with "the last path token in the segment" from an unrelated line further down:
|
|
53
|
+
// `cp a b` on line 1 plus a later line ending in an env-shaped token was denied as env_write_copy,
|
|
54
|
+
// neither line a write (found applying the documented jerv-central procedure, runbooks/box-ops.md).
|
|
55
|
+
// Adding \r\n strictly TIGHTENS the scans — every real create form still matches on its own line.
|
|
56
|
+
const SEGMENT_RE = /(?:\|\||&&|[;&|\r\n])/;
|
|
57
|
+
|
|
49
58
|
const COPY_VERBS = /^(?:cp|mv|install|ln|rsync|copy|move|xcopy|robocopy|Copy-Item|Move-Item)$/i;
|
|
50
59
|
|
|
51
60
|
/** Inspect one command for a real-.env CREATE. Returns { block, reason, reasonId } or null (clean). */
|
|
@@ -87,7 +96,7 @@ export function analyze({ toolName, command } = {}) {
|
|
|
87
96
|
// `bash -lc "cp …"` all put a wrapper first. And the destination is not always last — PowerShell takes
|
|
88
97
|
// `-Destination`, and `cp <file> <dir>/` names the directory while the basename comes from the source
|
|
89
98
|
// (all four ALLOWED before this; cross-vendor check, openai-sol).
|
|
90
|
-
for (const raw of command.split(
|
|
99
|
+
for (const raw of command.split(SEGMENT_RE)) {
|
|
91
100
|
const seg = raw.trim();
|
|
92
101
|
if (!seg) continue;
|
|
93
102
|
const tokens = seg.split(/\s+/).filter(Boolean);
|
|
@@ -107,7 +116,7 @@ export function analyze({ toolName, command } = {}) {
|
|
|
107
116
|
}
|
|
108
117
|
|
|
109
118
|
// `git checkout <ref> -- <path>` / `git restore --source <ref> <path>` materialise a file from history.
|
|
110
|
-
for (const raw of command.split(
|
|
119
|
+
for (const raw of command.split(SEGMENT_RE)) {
|
|
111
120
|
const tokens = raw.trim().split(/\s+/).filter(Boolean);
|
|
112
121
|
const gitAt = tokens.findIndex((t) => (t.replace(/\\/g, '/').split('/').pop() ?? '') === 'git');
|
|
113
122
|
if (gitAt === -1 || !/^(?:checkout|restore)$/i.test(tokens[gitAt + 1] ?? '')) continue;
|
|
@@ -115,7 +124,7 @@ export function analyze({ toolName, command } = {}) {
|
|
|
115
124
|
}
|
|
116
125
|
|
|
117
126
|
// touch: any non-flag arg that is a real .env token creates the file.
|
|
118
|
-
for (const raw of command.split(
|
|
127
|
+
for (const raw of command.split(SEGMENT_RE)) {
|
|
119
128
|
const seg = raw.trim();
|
|
120
129
|
if (!seg) continue;
|
|
121
130
|
const tokens = seg.split(/\s+/).filter(Boolean);
|
package/skills/release/SKILL.md
CHANGED
|
@@ -469,6 +469,17 @@ stray tag locally and on origin, confirm `next-version` would re-derive the *sam
|
|
|
469
469
|
then re-run a **single** `mmi-cli devops release --apply`. If the newer skip-version already published
|
|
470
470
|
cleanly, keep it and only remove the broken older Release/tag.
|
|
471
471
|
|
|
472
|
+
**Resuming a resumable partial state? The recovery form is `--resume --watch --json`, and nothing
|
|
473
|
+
else (#5815).** `--resume` and `--apply` are **mutually exclusive** and the CLI refuses the pair:
|
|
474
|
+
`--apply cuts the NEXT version, --resume finishes the immutable tag already on origin`
|
|
475
|
+
(`cli/src/index.ts`, the #3851 guard). A continuation that reaches for
|
|
476
|
+
`--resume --apply --watch` is asking the train to mint a new version while finishing an old one —
|
|
477
|
+
it refuses before any mutation, so nothing is lost, but the operator has spent a turn on a form that
|
|
478
|
+
can never run. `--apply` belongs to a **new** release cut, never to recovery.
|
|
479
|
+
```bash
|
|
480
|
+
mmi-cli devops release --resume --watch --json --repo <owner/repo>
|
|
481
|
+
```
|
|
482
|
+
|
|
472
483
|
## Step 4 — GitHub Release + start prod deploy (non-blocking)
|
|
473
484
|
|
|
474
485
|
For `tenant-container` repos, publish the GitHub Release and dispatch the central tenant deploy.
|
|
@@ -662,6 +673,23 @@ without a leading `v`.
|
|
|
662
673
|
Run that verify from a checkout **at the tag** (`main` right after the release merge, `git checkout
|
|
663
674
|
"vX.Y.0"`, or a worktree at the tag) — verify checks the working tree and refuses any other commit once
|
|
664
675
|
the tag exists, so a stale `development`/`rc` checkout can't masquerade as a broken release.
|
|
676
|
+
|
|
677
|
+
**Build the tag checkout before verifying, or it refuses deterministically (#5814).** `verify` (without
|
|
678
|
+
`--skip-npm-view`) runs a live `npm pack` per public surface, and `npm pack` refuses a package whose
|
|
679
|
+
declared `bin` target is absent — e.g. `updater publishes bin jerv-hub -> dist/index.cjs, which npm pack
|
|
680
|
+
does not ship — run npm run build`. Whether that bites depends on the repo: a build output that is
|
|
681
|
+
**tracked** (MMI-Hub commits `updater/dist/index.cjs`) is present in a clean tag checkout, one that is
|
|
682
|
+
**gitignored** is not, and a fresh clone has no `node_modules` either way. So provision the tag worktree
|
|
683
|
+
first, and check the declared bin targets rather than assuming:
|
|
684
|
+
```bash
|
|
685
|
+
git worktree add "$PROOF" "vX.Y.0" # $PROOF outside the repo — see the scratch note below
|
|
686
|
+
cd "$PROOF" && npm ci && npm run build # build only if a declared bin target is missing from the checkout
|
|
687
|
+
node scripts/release-distribution.mjs verify "X.Y.0"
|
|
688
|
+
```
|
|
689
|
+
Removing that proof tree afterwards: `npm ci` writes `node_modules`, which `git status --porcelain`
|
|
690
|
+
never shows and which makes `git worktree remove` refuse with `Directory not empty`. Delete
|
|
691
|
+
`node_modules` first, then remove the worktree. On Windows a global install made from a worktree leaves
|
|
692
|
+
a junction there, so delete the directory rather than following it.
|
|
665
693
|
Release-blocking for Hub tooling changes: every public artifact must match the registry version and BOM
|
|
666
694
|
identity. Manual fallback if CI can't publish: `node scripts/release-distribution.mjs publish "X.Y.0"`
|
|
667
695
|
from a machine with npm auth.
|