@mutmutco/pi-plugin 4.2.1 → 4.2.2

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mutmutco/pi-plugin",
3
- "version": "4.2.1",
3
+ "version": "4.2.2",
4
4
  "description": "MMI workflow skills and org gates delivery.",
5
5
  "author": {
6
6
  "name": "MMI Future",
@@ -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);
@@ -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.