@natjswenson/shipflow 0.2.5 → 0.2.6

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/SKILL.md CHANGED
@@ -7,8 +7,17 @@ user_invocable: true
7
7
  # /shipflow — branching + release-automation setup
8
8
 
9
9
  All deterministic work is delegated to the CLI. Invoke it as
10
- `npx -y @natjswenson/shipflow <command>`. Every command prints JSON to
11
- stdout — parse it, don't try to re-derive what it computed.
10
+ `npx -y @natjswenson/shipflow@latest <command>` **always with the explicit
11
+ `@latest` tag, never bare `@natjswenson/shipflow`.** Without a version/tag,
12
+ `npx` prefers an already-resolvable install on `PATH` (e.g. a stale global
13
+ `npm install -g @natjswenson/shipflow` from a prior manual test) over
14
+ fetching the current version from the registry, and does so silently with
15
+ no warning. This isn't hypothetical: it happened in this exact repo — the
16
+ same command with the `@latest` tag omitted silently ran a stale global
17
+ 0.2.0 install (missing every fix through 0.2.5, including the Critical
18
+ template-injection fix), while `npx -y @natjswenson/shipflow@latest -v`
19
+ correctly resolved 0.2.5. Every command prints JSON to stdout — parse it,
20
+ don't try to re-derive what it computed.
12
21
 
13
22
  **This skill never mutates repo state directly.** Every mutating action goes
14
23
  through `shipflow apply`, and the computed plan is always shown to the user
@@ -30,7 +39,7 @@ user; the CLI is the only thing that *does*.
30
39
 
31
40
  1. **Detect.** Run:
32
41
  ```
33
- npx -y @natjswenson/shipflow detect --repo <path> --main main --dev dev
42
+ npx -y @natjswenson/shipflow@latest detect --repo <path> --main main --dev dev
34
43
  ```
35
44
  (Use whatever branch names the user has, or `main`/`dev` as a starting guess — you'll confirm them next.) This prints a `RepoState` plus a `protectionOwnerClassification` of `"external"`, `"shipflow"`, or `"ambiguous"`.
36
45
 
@@ -38,7 +47,7 @@ user; the CLI is the only thing that *does*.
38
47
  - **Map onto the existing default branch** — set the config's `branches.main` to the detected default branch name and continue with the rest of setup treating that as "main." No mutating calls needed; `branches.main` is fully configurable.
39
48
  - **Switch the repo's default branch to `main`** — flag this as a bigger, more disruptive action than the rest of setup (it affects every collaborator and every open PR), get a distinct explicit confirmation for it specifically, separate from the general setup go-ahead, then run:
40
49
  ```
41
- npx -y @natjswenson/shipflow rename-default-branch --repo <path> --branch <old-default> --to main
50
+ npx -y @natjswenson/shipflow@latest rename-default-branch --repo <path> --branch <old-default> --to main
42
51
  ```
43
52
  GitHub natively retargets the default-branch pointer and open PRs' base ref. On success, tell the user their own local checkout still points at the old name and needs `git fetch origin && git checkout main` to follow, then re-run step 1's `detect` (repo state changed) before continuing.
44
53
 
@@ -57,18 +66,18 @@ user; the CLI is the only thing that *does*.
57
66
 
58
67
  7. **Show the plan.** Run:
59
68
  ```
60
- npx -y @natjswenson/shipflow plan --repo <path>
69
+ npx -y @natjswenson/shipflow@latest plan --repo <path>
61
70
  ```
62
71
  This prints `{ plan, stateHash }`. Present `plan.creates`/`plan.updates`/`plan.noops` to the user in plain language — what will be created, what will change, what's already correct. **Wait for explicit confirmation before proceeding.** If any entry has `handEditDetected: true`, call it out specifically and ask whether to override (see step 9).
63
72
 
64
73
  8. **Dry-run apply** (optional sanity check, same output shape as the real apply but nothing is mutated):
65
74
  ```
66
- npx -y @natjswenson/shipflow apply --repo <path> --dry-run
75
+ npx -y @natjswenson/shipflow@latest apply --repo <path> --dry-run
67
76
  ```
68
77
 
69
78
  9. **Apply for real**, passing the `stateHash` from step 7's plan output as `--expect-state-hash` — this is the TOCTOU guard: if repo state drifted between the plan you showed the user and this call, `apply` refuses to mutate anything and tells you to re-plan. **`--expect-state-hash` is mandatory for a real (non-dry-run) apply** — omitting it is a hard CLI refusal, not a silent skip of the check; the only way around it is the explicitly-named `--skip-hash-check` escape hatch, which you should never reach for as a matter of course.
70
79
  ```
71
- npx -y @natjswenson/shipflow apply --repo <path> --expect-state-hash <hash-from-step-7>
80
+ npx -y @natjswenson/shipflow@latest apply --repo <path> --expect-state-hash <hash-from-step-7>
72
81
  ```
73
82
  If a `handEditDetected` entry was confirmed for override in step 7, pass `--force <entry-id>` (repeatable — one flag per confirmed entry id, never a blanket override) **and** `--force-reason "<short justification>"` — the CLI refuses any `--force` without an accompanying reason, and that reason is echoed back in the apply result for auditability. Write a real justification tied to the user's actual confirmation (e.g. `--force-reason "user confirmed hand-edit override for the branch-rename migration on 2026-07-15"`), never a placeholder string.
74
83
 
@@ -84,7 +93,7 @@ This is a **separate, later invocation** from the one that ran the promotion's `
84
93
 
85
94
  1. Run:
86
95
  ```
87
- npx -y @natjswenson/shipflow releases --repo <path>
96
+ npx -y @natjswenson/shipflow@latest releases --repo <path>
88
97
  ```
89
98
  This returns every `dev → main` PR still labeled `release-pending`, each with a `merged` flag (confirmed independently, not just inferred from the label).
90
99
 
@@ -92,7 +101,7 @@ This is a **separate, later invocation** from the one that ran the promotion's `
92
101
 
93
102
  3. If yes, dispatch each changed skill's release workflow and clear the label **only after every dispatch is confirmed successful**:
94
103
  ```
95
- npx -y @natjswenson/shipflow release-dispatch --repo <path> --pr <number> --workflow-file <skill1>.yml --workflow-file <skill2>.yml --ref main
104
+ npx -y @natjswenson/shipflow@latest release-dispatch --repo <path> --pr <number> --workflow-file <skill1>.yml --workflow-file <skill2>.yml --ref main
96
105
  ```
97
106
  If `dispatched` shows a partial failure, the label is deliberately left in place — report this to the user and note the promotion will resurface next time `releases` is checked; a later re-dispatch is safe (each skill's release workflow is idempotent).
98
107
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@natjswenson/shipflow",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Scaffold a configurable dev/main branching, auto-merge, branch-cleanup, and release-tagging workflow into any repo",
5
5
  "license": "MIT",
6
6
  "author": "Nate Swenson",
@@ -75,6 +75,11 @@
75
75
  "id": "force-requires-reason",
76
76
  "pattern": "refuses any `--force` without an accompanying reason",
77
77
  "rationale": "Found by a Siege security audit (2026-07-15, SIEGE-2026-07-15-002): --force had zero code-level friction beyond the flag itself, so a confused or prompt-injected agent could force through an unprotected merge or a tampered template with no audit trail. --force now requires --force-reason, echoed back in the apply result."
78
+ },
79
+ {
80
+ "id": "npx-must-pin-latest",
81
+ "pattern": "always with the explicit\\s+`@latest` tag, never bare",
82
+ "rationale": "Self-discovered 2026-07-15 during PAT-wiring dogfood on claude-skills itself: a bare `npx -y @natjswenson/shipflow <command>` silently resolved a stale global install (0.2.0) instead of fetching the current version from the registry, with no warning — meaning every fix through 0.2.5 (including the Critical template-injection fix) was silently skipped. Every CLI invocation in this file must pin @latest."
78
83
  }
79
84
  ],
80
85
  "cli_commands_referenced": ["detect", "plan", "apply", "releases", "release-dispatch", "rename-default-branch"]