@launchsecure/launch-kit 0.0.32 → 0.0.33
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/dist/chart-client/assets/{index-B__ARB8k.js → index-DFu2xIrM.js} +2 -2
- package/dist/chart-client/assets/index-DpKO9p0s.css +1 -0
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/{index-h8kMzVtG.js → index-Cbw6bVdx.js} +2 -2
- package/dist/client/assets/index-Dv6dD2zY.css +32 -0
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/index-AqQ9Sei6.css +1 -0
- package/dist/council-client/assets/{index-CWaDcsFR.js → index-CAsmGTzg.js} +2 -2
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/{_baseUniq-C7GsHvgg.js → _baseUniq-BiVx0WO_.js} +1 -1
- package/dist/deck-client/assets/{arc-CSrZRINY.js → arc-DGMkiEzS.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-zoB-G17J.js → architectureDiagram-Q4EWVU46-Y2WRmHtk.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-BRjjtYH6.js → blockDiagram-DXYQGD6D-_Lbfu5BQ.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-C3D3sd2U.js → c4Diagram-AHTNJAMY-CTqpYTBX.js} +1 -1
- package/dist/deck-client/assets/channel-DB6LxW_l.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-DhpDMOPO.js → chunk-4BX2VUAB-liEIbPHs.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-BIRgPXRl.js → chunk-4TB4RGXK-CCc6lYvL.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-BF24dwDZ.js → chunk-55IACEB6-D02jJUR2.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-CW75Y61B.js → chunk-EDXVE4YY-BFmGMbLD.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-B5-oyL79.js → chunk-FMBD7UC4-6wFLOVcJ.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-BB2bHe_Q.js → chunk-OYMX7WX6-Bnr8RiBf.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-D80eZO4B.js → chunk-QZHKN3VN-Ct82MksJ.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-Dz9787p_.js → chunk-YZCP3GAM-BXmN1diQ.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-g944ZyG8.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-g944ZyG8.js +1 -0
- package/dist/deck-client/assets/clone-DiIRH1pI.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-MQjiZLcL.js → cose-bilkent-S5V4N54A-CmQCT-mH.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-DG4EcLpJ.js → dagre-KV5264BT-DDdSa9EX.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-1n7hM3Gc.js → diagram-5BDNPKRD-Bccks2xJ.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-CYMarncV.js → diagram-G4DWMVQ6-CPPNgxmQ.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-DSisoipe.js → diagram-MMDJMWI5-KrD300pS.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-Btnq49OJ.js → diagram-TYMM5635-DefnLuQf.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-Cu2Hb_Tz.js → erDiagram-SMLLAGMA-DI9FfnFP.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-CGJzUzsO.js → flowDiagram-DWJPFMVM-twKyd3Fx.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-D9sqGUBT.js → ganttDiagram-T4ZO3ILL-Wau3jhBr.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-C0QwX2od.js → gitGraphDiagram-UUTBAWPF-D9GgYXwb.js} +1 -1
- package/dist/deck-client/assets/{graph-CcBjOQCl.js → graph-BhNLzyXS.js} +1 -1
- package/dist/deck-client/assets/index-B-YQq5b5.css +1 -0
- package/dist/deck-client/assets/{index-0arwoc0z.js → index-BtQBaQ7s.js} +3 -3
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-DTimhhhS.js → infoDiagram-42DDH7IO-TylGlSG-.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-DxOxg_B4.js → ishikawaDiagram-UXIWVN3A-DAT8icpg.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-Bpq0qa4j.js → journeyDiagram-VCZTEJTY-D3v_XL72.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-aTIrpcVO.js → kanban-definition-6JOO6SKY-DNUOBiNr.js} +1 -1
- package/dist/deck-client/assets/{layout-DqglLR2E.js → layout-COfodgwF.js} +1 -1
- package/dist/deck-client/assets/{linear-D5GxehPc.js → linear-DmTsuIvK.js} +1 -1
- package/dist/deck-client/assets/{min-DXLfSREq.js → min-BW1F7i1D.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-mO5Vys7I.js → mindmap-definition-QFDTVHPH-CErFzKWl.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-Dm0gzdAr.js → pieDiagram-DEJITSTG-DW5F757o.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-Daq7j3qD.js → quadrantDiagram-34T5L4WZ-B1S2-TfI.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-CmwV95um.js → requirementDiagram-MS252O5E-BY5BAR-5.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BOYl3Nkf.js → sankeyDiagram-XADWPNL6-CE1Cp9HS.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-BuUjhIcW.js → sequenceDiagram-FGHM5R23-IaHnbKye.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-LUZ_uwio.js → stateDiagram-FHFEXIEX-CwPJm9hU.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-DQYa2M1q.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-CDUxCCAW.js → timeline-definition-GMOUNBTQ-DVFGGSgN.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-BRb24Tf7.js → vennDiagram-DHZGUBPP-C1194MJi.js} +1 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-CHZiUbBa.js +162 -0
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BLGlYrQz.js → wardleyDiagram-NUSXRM2D-hpwdFfGj.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-De31MSnk.js → xychartDiagram-5P7HB3ND-DYkotwy8.js} +1 -1
- package/dist/deck-client/index.html +2 -2
- package/dist/server/cli.js +91 -13
- package/dist/server/council-entry.js +0 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/init-entry.js +740 -221
- package/dist/server/radar-docker-init-entry.js +239 -0
- package/dist/server/radar-entrypoint-entry.js +99 -0
- package/dist/server/radar-teardown-entry.js +477 -0
- package/dist/server/recall-entry.js +4 -1
- package/package.json +22 -23
- package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +5 -5
- package/scaffolds/ls-marketplace/plugins/kit/skills/ship/SKILL.md +274 -0
- package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +0 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +0 -0
- package/scaffolds/statusline/statusline-mcp.sh +82 -2
- package/scaffolds/statusline/statusline-wrapper.sh +8 -1
- package/dist/chart-client/assets/index-CDIhdgWg.css +0 -1
- package/dist/client/assets/index-CfW4n40I.css +0 -32
- package/dist/council-client/assets/index-CZim6x1u.css +0 -1
- package/dist/deck-client/assets/channel-8ReQnQfH.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-cRxTeGkK.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-cRxTeGkK.js +0 -1
- package/dist/deck-client/assets/clone-LSHZ3K6R.js +0 -1
- package/dist/deck-client/assets/index-BlTlhxFW.css +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-CnnRwE5D.js +0 -1
- package/dist/deck-client/assets/wardley-RL74JXVD-B0BYyVBY.js +0 -162
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: End-to-end ship flow — runs /kit:deploy-check, prints the exact commit list, pushes the named branch only after explicit confirmation, then appends a structured entry to .launchsecure/ship-log.ndjson describing what shipped. Pushing to a deploy-tracked branch (default master) triggers Vercel automatically; this skill never calls `vercel deploy` directly. No LS Comm Hub post — the local log is the source of truth and can be republished later by a separate skill.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /kit:ship
|
|
6
|
+
|
|
7
|
+
Compose `/kit:deploy-check` + `git push` + local ship-log append into one gated workflow. The skill is the human checklist for "I'm shipping now" — same checks a careful human would run, encoded so they cannot be skipped or reordered.
|
|
8
|
+
|
|
9
|
+
The ship log at `.launchsecure/ship-log.ndjson` is the durable record of what shipped, when, and by whom. Each successful ship appends one JSON object. A future skill (`/kit:ship-publish` or similar) can tail this log and emit an internal activity update / Comm Hub post / changelog page — but that's a separate concern. This skill writes the log; it does not publish.
|
|
10
|
+
|
|
11
|
+
Hard rule from project memory: **never push commits the user didn't explicitly name**, and **pushing to master = auto-deploy** — so this skill always asks per-action before pushing, even when invoked with arguments. There is no `--yes-i-mean-it` flag.
|
|
12
|
+
|
|
13
|
+
Parse `$ARGUMENTS`:
|
|
14
|
+
|
|
15
|
+
- (empty) — full flow on the current branch → its upstream (resolved via `git rev-parse --abbrev-ref @{u}` or, missing that, `origin/<current-branch>`).
|
|
16
|
+
- **--to=<branch>** — push to a different remote branch (e.g. `--to=staging-mirror`). The skill never creates a new remote branch silently — if the target doesn't exist on origin, surface that and ask.
|
|
17
|
+
- **--dry-run** — run deploy-check + build the ship-log entry preview, but do NOT push and do NOT append to the log. Useful for "what would shipping look like right now?".
|
|
18
|
+
- **--note=<text>** — free-form human note attached to the log entry's `note` field. Useful for hotfix context, rollout caveats, or named reviewer.
|
|
19
|
+
- **--skip-check=<list>** — forwarded verbatim to `/kit:deploy-check --skip=<list>`. Surface skipped checks in the final report; do not let `--skip-check=build` slip through silently.
|
|
20
|
+
- **--quick** — forwarded to deploy-check (skips the slow `build` step). Refuse if the target is a deploy-tracked branch (`master` or whatever the repo's default is) — for prod, build must run.
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
|
|
24
|
+
- `/kit:ship` → check, confirm, push current branch to its upstream, append ship-log entry.
|
|
25
|
+
- `/kit:ship --dry-run` → check + preview the log entry only; no push, no log write.
|
|
26
|
+
- `/kit:ship --to=master` from `implementation` → cross-branch merge-and-deploy flow (see "Cross-branch ship" below).
|
|
27
|
+
- `/kit:ship --note="hotfix for feedback widget 500s"` → push + log entry with the note attached.
|
|
28
|
+
|
|
29
|
+
## Preflight
|
|
30
|
+
|
|
31
|
+
1. `git rev-parse --is-inside-work-tree` — abort if not a git repo.
|
|
32
|
+
2. Resolve current branch and the **deploy-target branch**:
|
|
33
|
+
- If `--to=` given, use it.
|
|
34
|
+
- Else `git rev-parse --abbrev-ref @{u}` (the branch's tracked upstream).
|
|
35
|
+
- Else fall back to `origin/<current>` and warn that no upstream is set.
|
|
36
|
+
3. Resolve the **deploy-tracked branch list** for "is this a prod push?" gating:
|
|
37
|
+
- Read `git symbolic-ref refs/remotes/origin/HEAD --short` (strip `origin/`) → that's the repo's default; treat as deploy-tracked.
|
|
38
|
+
- Always treat `master` and `main` as deploy-tracked if they exist on origin.
|
|
39
|
+
- If the resolved target is in this list, set `IS_PROD_PUSH=true`. Used to escalate confirmations and refuse `--quick` / `--skip-check=build`.
|
|
40
|
+
4. Print the scope upfront — the user should never wonder what's about to happen:
|
|
41
|
+
```
|
|
42
|
+
ship: <current-branch> → <target-branch> (prod: yes|no)
|
|
43
|
+
```
|
|
44
|
+
5. Stash check — if `git status --porcelain` shows uncommitted changes, refuse with `✗ working tree not clean — commit, stash, or discard before shipping`. Shipping with dirty state is never the right move; the deploy-check skill is lenient about it because it's read-only, this skill is not.
|
|
45
|
+
|
|
46
|
+
## Step 1 — Gate (run /kit:deploy-check)
|
|
47
|
+
|
|
48
|
+
Invoke `/kit:deploy-check` against the resolved target. Forward `--quick` / `--skip-check=` / `--target=`. Do NOT re-implement any check here — single source of truth lives in `deploy-check/SKILL.md`.
|
|
49
|
+
|
|
50
|
+
Verdict handling:
|
|
51
|
+
|
|
52
|
+
- **NO-GO** → abort the ship. Print the failing checks verbatim from deploy-check. Tell the user what to fix. Do not offer to "force ship".
|
|
53
|
+
- **GO WITH CAVEATS** → surface the warnings, then ask:
|
|
54
|
+
> "deploy-check returned GO WITH CAVEATS (<N> warnings listed above). Continue with ship? Reply `yes` to continue, `cancel` to abort."
|
|
55
|
+
- **GO** → continue silently to step 2.
|
|
56
|
+
|
|
57
|
+
Hard rules:
|
|
58
|
+
|
|
59
|
+
- If `IS_PROD_PUSH=true` and the user passed `--quick` or `--skip-check=build`, refuse before running deploy-check: `✗ --quick / --skip-check=build are not allowed for prod pushes. Re-run without them.`
|
|
60
|
+
- If deploy-check's `migration_safety` row is anything other than ✓, treat as NO-GO regardless of overall verdict. Migration corruption incidents are why the project has the three-layer migration rule in CLAUDE.md — this skill enforces it.
|
|
61
|
+
|
|
62
|
+
## Step 2 — Show the exact push payload
|
|
63
|
+
|
|
64
|
+
Print, verbatim, what's about to be pushed. This is the user's last chance to recognise an unexpected commit (per project memory: `push X` never includes other local commits).
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
About to push <current-branch> → origin/<target-branch>:
|
|
68
|
+
|
|
69
|
+
<sha> <subject> <author-relative-time>
|
|
70
|
+
<sha> <subject> <author-relative-time>
|
|
71
|
+
…
|
|
72
|
+
|
|
73
|
+
<N> commits, <M> files changed (<+adds>/<-dels>)
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Generated from:
|
|
77
|
+
|
|
78
|
+
- `git log --pretty=format:' %h %s (%ar, %an)' origin/<target>..HEAD`
|
|
79
|
+
- `git diff --shortstat origin/<target>...HEAD`
|
|
80
|
+
|
|
81
|
+
If the list is empty → abort: `nothing to push — local branch is at or behind origin/<target>`.
|
|
82
|
+
|
|
83
|
+
If any commit author is not the current `git config user.email`, surface a `⚠ <N> commits authored by someone else (<emails>)` line — common in shared branches but worth flagging once.
|
|
84
|
+
|
|
85
|
+
## Step 3 — Migration backup gate
|
|
86
|
+
|
|
87
|
+
If `git diff origin/<target>...HEAD --name-only -- prisma/migrations/` returns any files, surface:
|
|
88
|
+
|
|
89
|
+
```
|
|
90
|
+
⚠ This push includes <N> new migration(s):
|
|
91
|
+
- prisma/migrations/<dir>/migration.sql
|
|
92
|
+
…
|
|
93
|
+
|
|
94
|
+
Backup story:
|
|
95
|
+
- CI: .github/workflows/backup-on-migration.yml runs pg_dump server-side once the migration lands on <target-branch>.
|
|
96
|
+
- Local: if you have already applied locally, you've used scripts/migrate-with-backup.sh (per CLAUDE.md). If not, the CI workflow is the safety net.
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then ask:
|
|
100
|
+
|
|
101
|
+
> "Migration push detected. Type `understood` to continue, or `cancel` to abort."
|
|
102
|
+
|
|
103
|
+
This is a deliberate friction point — typing a word is more honest than `y`. Do not accept `yes` here; require `understood`.
|
|
104
|
+
|
|
105
|
+
## Step 4 — Push confirmation
|
|
106
|
+
|
|
107
|
+
Ask **exactly**:
|
|
108
|
+
|
|
109
|
+
- If `IS_PROD_PUSH=false`:
|
|
110
|
+
> "Push <N> commits to origin/<target-branch>? Reply `yes` to push, `cancel` to abort."
|
|
111
|
+
- If `IS_PROD_PUSH=true`:
|
|
112
|
+
> "Push <N> commits to origin/<target-branch>. This is a prod-tracked branch — Vercel will deploy automatically. Reply `ship it` to push, `cancel` to abort."
|
|
113
|
+
|
|
114
|
+
Accept exactly `yes` / `ship it` (case-insensitive). Anything else → treat as cancel. **Never** accept silence, `ok`, `sure`, free-form approval. If `--dry-run`, skip this step entirely.
|
|
115
|
+
|
|
116
|
+
On confirm: `git push origin <current-branch>:<target-branch>`. Stream stdout. If the push fails (non-fast-forward, hook reject, auth) — surface the error verbatim, do not retry, do not `--force`.
|
|
117
|
+
|
|
118
|
+
After a successful push to a deploy-tracked branch, surface the Vercel deployment lookup hint:
|
|
119
|
+
|
|
120
|
+
```
|
|
121
|
+
Pushed. Vercel deploy will pick up the latest commit on <target-branch>.
|
|
122
|
+
→ check status: `vercel ls --prod` or watch the Vercel dashboard
|
|
123
|
+
(do NOT run `vercel deploy` from here — that bypasses the GitHub→Vercel flow and double-deploys)
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Step 5 — Append ship-log entry
|
|
127
|
+
|
|
128
|
+
After a successful push, append exactly one JSON line to `.launchsecure/ship-log.ndjson`. This is the durable record of the ship event — the source of truth a future `/kit:ship-publish` (or any reader) consumes to emit activity feeds, changelogs, or Comm Hub posts.
|
|
129
|
+
|
|
130
|
+
If `--dry-run`, build the entry and show it in a fenced block but do NOT write it. If the push failed in step 4, do NOT write the entry (the log only records successful ships).
|
|
131
|
+
|
|
132
|
+
### File location & format
|
|
133
|
+
|
|
134
|
+
- Path: `.launchsecure/ship-log.ndjson` (sibling of `.launchsecure/graphs/`, `.launchsecure/beacon-*.ndjson`).
|
|
135
|
+
- Format: NDJSON — one JSON object per line, append-only, never rewrite or compact.
|
|
136
|
+
- If the file does not exist, create it. Do NOT add a header line; readers should tolerate empty file = zero ship events.
|
|
137
|
+
- Ensure `.launchsecure/ship-log.ndjson` is gitignored — on first run, check `.gitignore` for `.launchsecure/ship-log.ndjson` or a covering pattern (`.launchsecure/*.ndjson`); if absent, surface a one-line warning suggesting the user add it. Do NOT silently edit `.gitignore` — that's a separate user decision per project memory on extending vs adding things.
|
|
138
|
+
|
|
139
|
+
### Entry schema
|
|
140
|
+
|
|
141
|
+
Every entry conforms to schema `v: 1`. Forward-compatible reader rule: ignore unknown fields, never break on missing optional fields.
|
|
142
|
+
|
|
143
|
+
```json
|
|
144
|
+
{
|
|
145
|
+
"v": 1,
|
|
146
|
+
"shipId": "<ulid or `${ts}-${shortSha}`>",
|
|
147
|
+
"ts": "2026-05-29T12:45:00.000Z",
|
|
148
|
+
"branch": "implementation",
|
|
149
|
+
"target": "master",
|
|
150
|
+
"isProdPush": true,
|
|
151
|
+
"author": { "name": "Prajyot", "email": "prajyot@automatewith.us" },
|
|
152
|
+
"commits": [
|
|
153
|
+
{ "sha": "abc1234", "subject": "feat(ship): add ship skill", "author": "Prajyot", "ts": "2026-05-29T12:30:00.000Z" }
|
|
154
|
+
],
|
|
155
|
+
"stats": { "files": 3, "insertions": 187, "deletions": 0 },
|
|
156
|
+
"migrations": ["prisma/migrations/2026_05_29_add_ship_log/migration.sql"],
|
|
157
|
+
"envVarsAdded": ["FEED_BACKEND_URL"],
|
|
158
|
+
"deployCheck": {
|
|
159
|
+
"verdict": "GO",
|
|
160
|
+
"warnings": ["lint: 12 warnings"],
|
|
161
|
+
"skipped": []
|
|
162
|
+
},
|
|
163
|
+
"themes": [
|
|
164
|
+
{ "scope": "ship", "outcomes": ["End-to-end ship skill with deploy-check gate and append-only ship log"] }
|
|
165
|
+
],
|
|
166
|
+
"summary": "Shipped 1 commit to master — ship skill scaffold",
|
|
167
|
+
"note": "<--note value, or null>",
|
|
168
|
+
"pushedAt": "2026-05-29T12:45:00.000Z",
|
|
169
|
+
"vercelDeployHint": "auto-triggered on push to master"
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Field sources:
|
|
174
|
+
|
|
175
|
+
- `shipId` — generate `${pushedAt-as-yyyymmdd-hhmmss}-${shortSha-of-HEAD}` for human-greppable IDs. ULID is fine if a generator is available.
|
|
176
|
+
- `ts` / `pushedAt` — current ISO timestamp at the moment the entry is written (just after `git push` succeeds).
|
|
177
|
+
- `branch` / `target` / `isProdPush` — from preflight (step 1).
|
|
178
|
+
- `author` — `git config user.name` + `git config user.email`.
|
|
179
|
+
- `commits` — `git log --pretty=format:'%H%x09%s%x09%an%x09%aI' origin/<target>..HEAD` (use the pre-push range — these are the commits that just landed).
|
|
180
|
+
- `stats` — `git diff --shortstat origin/<target>...<sha>` where `<sha>` is the new HEAD.
|
|
181
|
+
- `migrations` — `git diff --name-only origin/<target>...HEAD -- prisma/migrations/` (if step 3 fired, surface those exact paths; else empty array).
|
|
182
|
+
- `envVarsAdded` — pulled from deploy-check's `env_coverage` row, parsed from its `detail`. If deploy-check was skipped or didn't run that check, `[]`.
|
|
183
|
+
- `deployCheck.verdict` / `warnings` / `skipped` — from the deploy-check report in step 1.
|
|
184
|
+
- `themes` — group commits by conventional-commit scope (same default rule as `/kit:standup` step 3). Each theme: `{ scope, outcomes: [<outcome-bullets translated from commit subjects>] }`. Outcomes are short product-facing sentences, NOT raw subject lines. If commits lack scopes and there are ≥20 changed files across ≥5 dirs, escalate to launch-chart module grouping (same rule as standup step 3); otherwise bucket into `{scope: "misc", outcomes: […]}`.
|
|
185
|
+
- `summary` — one-line human-readable. Format: `Shipped <N> commit(s) to <target>${migrations ? " — includes migration" : ""}${themes ? " — " + topTheme : ""}`.
|
|
186
|
+
- `note` — verbatim `--note=` value, or `null` if absent.
|
|
187
|
+
- `vercelDeployHint` — `"auto-triggered on push to <target>"` if `isProdPush`, else `"no auto-deploy (target is not deploy-tracked)"`.
|
|
188
|
+
|
|
189
|
+
### Preview + confirm
|
|
190
|
+
|
|
191
|
+
After step 4's push succeeds, build the entry and show it pretty-printed in a fenced code block:
|
|
192
|
+
|
|
193
|
+
```
|
|
194
|
+
About to append to .launchsecure/ship-log.ndjson:
|
|
195
|
+
|
|
196
|
+
{
|
|
197
|
+
"v": 1,
|
|
198
|
+
"shipId": "20260529-124500-abc1234",
|
|
199
|
+
…
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
Append? Reply `yes` to write, `edit summary` to tweak the summary or themes, `skip` to ship without logging, or `cancel` to abort the append.
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
- `yes` / `y` → append the entry as a single minified line (`JSON.stringify(entry) + "\n"`) using `>> .launchsecure/ship-log.ndjson`. Confirm with `appended shipId=<id>`.
|
|
206
|
+
- `edit summary` → ask what to change (summary text, theme grouping, note), redraft the entry, re-show, re-ask.
|
|
207
|
+
- `skip` → do not write. Print the entry once more so the user can manually save it elsewhere if they want. Ship is still considered successful — the push landed.
|
|
208
|
+
- `cancel` → do not write. Same as `skip` but no echo. **Do not** attempt to revert the push — surface clearly: `Push already landed on origin/<target>; cancel only stops the log append.`
|
|
209
|
+
|
|
210
|
+
### Atomicity
|
|
211
|
+
|
|
212
|
+
Append must be atomic — partial writes corrupt the NDJSON file. Use:
|
|
213
|
+
|
|
214
|
+
```
|
|
215
|
+
echo "<minified-json>" >> .launchsecure/ship-log.ndjson
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
NOT `cat ... > tmp && mv tmp ...` (rewrite is wrong for an append-only log). NOT multi-line JSON. One line, one ship, one append.
|
|
219
|
+
|
|
220
|
+
If the write fails (disk full, permission), surface the entry verbatim in chat so the user can save it manually, and exit non-zero. Do NOT retry.
|
|
221
|
+
|
|
222
|
+
## Cross-branch ship (--to=master from a feature branch)
|
|
223
|
+
|
|
224
|
+
When the user runs `/kit:ship --to=master` from a non-master branch, the flow is **push the current branch's commits onto master**, which is a fast-forward / merge, not a normal push. Handle this carefully:
|
|
225
|
+
|
|
226
|
+
1. After deploy-check passes, before step 2, verify the current branch is ahead of `origin/master` (`git rev-list --left-right --count origin/master...HEAD` → left=behind, right=ahead). If behind, abort: `✗ <current> is behind origin/master by <N>; rebase or merge master first`.
|
|
227
|
+
2. The push command becomes `git push origin <current-branch>:master`. Make sure step 2's "About to push" preamble shows this asymmetric refspec so the user sees it.
|
|
228
|
+
3. On non-fast-forward reject from origin, do NOT suggest `--force`. Surface and stop.
|
|
229
|
+
|
|
230
|
+
## Constraints
|
|
231
|
+
|
|
232
|
+
- **Never auto-push and auto-log in one breath.** Always two explicit confirmations (step 4 push, step 5 append). The `--dry-run` flag exists instead of bundling.
|
|
233
|
+
- **Never call `vercel deploy` CLI.** Deploys come from Vercel's GitHub integration on push to deploy-tracked branches. Calling the CLI double-deploys and bypasses the gate.
|
|
234
|
+
- **Never `git push --force` / `--force-with-lease`.** If a push fails, the user investigates.
|
|
235
|
+
- **Never `git push <branch>` without an explicit refspec.** Always `<local-branch>:<remote-branch>` so the destination is unambiguous in the printed command (and in shell history).
|
|
236
|
+
- **Never bypass migration_safety.** A ✓ on the deploy-check migration_safety row is the gate; anything else is NO-GO even if the overall verdict isn't.
|
|
237
|
+
- **Single source of truth for checks.** Do not duplicate `/kit:deploy-check` logic inline; invoke it.
|
|
238
|
+
- **Append-only log.** Never edit, delete, or rewrite past entries in `ship-log.ndjson`. Corrections happen via a new entry referencing the previous `shipId` (e.g. `correctionOf: "<prev shipId>"` — readers handle the merge).
|
|
239
|
+
- **Log only successful ships.** If `git push` fails, do NOT write an entry. The log records what actually landed on the remote, not what was attempted.
|
|
240
|
+
- **No publishing from this skill.** This skill writes the log; it does NOT post to LS Comm Hub, does NOT update activity feeds, does NOT trigger webhooks. Those are downstream consumers (future `/kit:ship-publish` or a server-side tailer).
|
|
241
|
+
- **Honest about deploy state.** This skill ends when the push completes and the log entry lands. It does NOT wait for Vercel to finish building, does NOT verify the prod URL is up, does NOT roll back. If the user needs deploy-monitoring, point them at `vercel ls --prod` or the Vercel dashboard.
|
|
242
|
+
- **Dry-run is truly dry.** `--dry-run` must NOT call `git push`, must NOT write to `ship-log.ndjson`. The preview is shown in chat only.
|
|
243
|
+
|
|
244
|
+
## Idempotency
|
|
245
|
+
|
|
246
|
+
Re-running `/kit:ship` after a successful run:
|
|
247
|
+
|
|
248
|
+
- Step 2 will show "nothing to push" if the previous push landed cleanly — the natural no-op. No new log entry results.
|
|
249
|
+
- Each successful ship is a separate line in `ship-log.ndjson`. There is no per-day or per-branch coalescing — that's a reader's job. If a hotfix ships 10 minutes after a feature, both entries exist independently.
|
|
250
|
+
- The preview is never persisted before confirmation; cancelling at any step leaves no partial entry behind.
|
|
251
|
+
|
|
252
|
+
## Reading the log
|
|
253
|
+
|
|
254
|
+
For ad-hoc inspection while the publisher skill doesn't exist yet:
|
|
255
|
+
|
|
256
|
+
```
|
|
257
|
+
# last ship
|
|
258
|
+
tail -n 1 .launchsecure/ship-log.ndjson | jq
|
|
259
|
+
|
|
260
|
+
# ships to master in the last 7 days
|
|
261
|
+
jq -c 'select(.target == "master" and (.ts | fromdateiso8601) > (now - 7*86400))' .launchsecure/ship-log.ndjson
|
|
262
|
+
|
|
263
|
+
# count ships per day
|
|
264
|
+
jq -r '.ts[:10]' .launchsecure/ship-log.ndjson | sort | uniq -c
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
These are documented for the user, not for this skill — `/kit:ship` itself never reads back the log.
|
|
268
|
+
|
|
269
|
+
## Notes for the assistant
|
|
270
|
+
|
|
271
|
+
- The user has explicit project-memory rules against unauthorised pushes and dumb reverts. Treat every confirmation as load-bearing — don't paraphrase the prompt wording, don't accept ambiguous approval.
|
|
272
|
+
- "Ship" is the user's verb for "I want this in production." If the target isn't actually deploy-tracked, the skill should still work but should say so clearly in the scope line (step 4 phrasing changes).
|
|
273
|
+
- The ship log is the durable artifact. Future skills will read from it — keep the schema stable, additive only. Bump `v:` when you make a breaking schema change and update this file's schema block in the same commit.
|
|
274
|
+
- This skill assumes `/kit:deploy-check` exists. If missing (older launch-kit install), surface that as a preflight error pointing to `npx @launchsecure/launch-kit init`. No dependency on `/kit:standup` anymore — the log replaces the Comm Hub post.
|
|
File without changes
|
|
File without changes
|
|
@@ -4,11 +4,17 @@
|
|
|
4
4
|
# Composes into any existing statusline via the launch-kit wrapper.
|
|
5
5
|
#
|
|
6
6
|
# Usage:
|
|
7
|
-
# statusline-mcp.sh # all known chips (recall, chart, deck, council)
|
|
7
|
+
# statusline-mcp.sh # all known chips (recall, chart, deck, council, secure)
|
|
8
8
|
# statusline-mcp.sh --show=recall,chart # only the listed chips
|
|
9
9
|
# statusline-mcp.sh --compact # collapse to `mcp <up>/<total>`
|
|
10
10
|
# green when all up, red if any down
|
|
11
11
|
#
|
|
12
|
+
# `secure` differs from the others: recall/chart/deck/council are local
|
|
13
|
+
# daemons probed via a pidfile/lockfile/freshness file, but launch-secure is
|
|
14
|
+
# the hosted MCP. Its chip is a reachability probe (curl) against the active
|
|
15
|
+
# profile's serverUrl, cached for SECURE_CACHE_TTL seconds so the statusline
|
|
16
|
+
# never blocks on the network on every render.
|
|
17
|
+
#
|
|
12
18
|
# Project root is inferred from $LK_STATUSLINE_CWD (set by the wrapper) or
|
|
13
19
|
# $PWD by walking up until a `.launchsecure` dir is found. Silent exit when
|
|
14
20
|
# the cwd is not inside a launchsecure project.
|
|
@@ -22,7 +28,12 @@ for arg in "$@"; do
|
|
|
22
28
|
--compact) compact=1 ;;
|
|
23
29
|
esac
|
|
24
30
|
done
|
|
25
|
-
[ -z "$show" ] && show="recall,chart,deck,council"
|
|
31
|
+
[ -z "$show" ] && show="recall,chart,deck,council,secure"
|
|
32
|
+
|
|
33
|
+
# TTL for the cached launch-secure reachability probe (seconds). The statusline
|
|
34
|
+
# re-renders far too often to curl on every paint; one live probe per window is
|
|
35
|
+
# plenty for an "is the host up" signal.
|
|
36
|
+
SECURE_CACHE_TTL=30
|
|
26
37
|
|
|
27
38
|
GREEN=$'\033[32m'
|
|
28
39
|
ORANGE=$'\033[33m'
|
|
@@ -173,6 +184,74 @@ chip_council() {
|
|
|
173
184
|
_state="orange"; _display="${ORANGE}council${RESET}"
|
|
174
185
|
}
|
|
175
186
|
|
|
187
|
+
# Pull the active profile's serverUrl out of .launch-secure.cred.config without
|
|
188
|
+
# jq (the chip script stays coreutils-only). Handles both shapes the cred file
|
|
189
|
+
# can take — profiled ({active, profiles:{<name>:{serverUrl}}}) and flat
|
|
190
|
+
# ({serverUrl}) — mirroring the .mcp.json headersHelper's own fallback.
|
|
191
|
+
extract_secure_url() {
|
|
192
|
+
local cred="$1" active
|
|
193
|
+
active=$(grep -o '"active"[[:space:]]*:[[:space:]]*"[^"]*"' "$cred" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
|
|
194
|
+
awk -v prof="$active" '
|
|
195
|
+
function opens(s){ return gsub(/{/,"&",s) }
|
|
196
|
+
function closes(s){ return gsub(/}/,"&",s) }
|
|
197
|
+
BEGIN { inprof = (prof == "") ? 1 : 0; depth = 0 }
|
|
198
|
+
{
|
|
199
|
+
if (prof != "" && !inprof) {
|
|
200
|
+
if (index($0, "\"" prof "\"") > 0 && index($0, "{") > 0) { inprof = 1; depth = opens($0) - closes($0) }
|
|
201
|
+
next
|
|
202
|
+
}
|
|
203
|
+
if (match($0, /"serverUrl"[[:space:]]*:[[:space:]]*"[^"]*"/)) {
|
|
204
|
+
s = substr($0, RSTART, RLENGTH)
|
|
205
|
+
sub(/.*:[[:space:]]*"/, "", s); sub(/".*/, "", s)
|
|
206
|
+
print s; exit
|
|
207
|
+
}
|
|
208
|
+
if (prof != "") { depth += opens($0) - closes($0); if (depth <= 0) exit }
|
|
209
|
+
}
|
|
210
|
+
' "$cred" 2>/dev/null
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
_render_secure() {
|
|
214
|
+
# $1 = state (green|red|unknown), $2 = label (active profile name)
|
|
215
|
+
case "$1" in
|
|
216
|
+
green) _state="green"; _display="${GREEN}secure(${2})${RESET}" ;;
|
|
217
|
+
unknown) _state="orange"; _display="${ORANGE}secure(${2})${RESET}" ;;
|
|
218
|
+
*) _state="red"; _display="${RED}secure(${2})${RESET}" ;;
|
|
219
|
+
esac
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
chip_secure() {
|
|
223
|
+
local cred="$PROJECT_ROOT/.launch-secure.cred.config"
|
|
224
|
+
if [ ! -f "$cred" ]; then _state="orange"; _display="${ORANGE}secure(?)${RESET}"; return; fi
|
|
225
|
+
|
|
226
|
+
local active url label
|
|
227
|
+
active=$(grep -o '"active"[[:space:]]*:[[:space:]]*"[^"]*"' "$cred" 2>/dev/null | head -1 | sed 's/.*"\([^"]*\)".*/\1/')
|
|
228
|
+
url=$(extract_secure_url "$cred")
|
|
229
|
+
if [ -z "$url" ]; then _state="orange"; _display="${ORANGE}secure(?)${RESET}"; return; fi
|
|
230
|
+
label="${active:-secure}"
|
|
231
|
+
|
|
232
|
+
# Cache keyed on the URL so a course-switch (prod↔local) invalidates instantly.
|
|
233
|
+
local cache="$PROJECT_ROOT/.launchsecure/.statusline-secure.cache"
|
|
234
|
+
local now; now=$(date +%s)
|
|
235
|
+
if [ -f "$cache" ]; then
|
|
236
|
+
local c_ts c_url c_state
|
|
237
|
+
IFS='|' read -r c_ts c_url c_state < "$cache" 2>/dev/null || true
|
|
238
|
+
if [ -n "${c_ts:-}" ] && [ "${c_url:-}" = "$url" ] && [ $((now - c_ts)) -lt "$SECURE_CACHE_TTL" ]; then
|
|
239
|
+
_render_secure "$c_state" "$label"; return
|
|
240
|
+
fi
|
|
241
|
+
fi
|
|
242
|
+
|
|
243
|
+
# Live probe. Any HTTP status — including 401/403/404/405 — means the host is
|
|
244
|
+
# reachable; only a transport failure (curl writes 000) counts as down. No
|
|
245
|
+
# curl on PATH → unknown (orange), never a false red.
|
|
246
|
+
local state="unknown" code
|
|
247
|
+
if command -v curl >/dev/null 2>&1; then
|
|
248
|
+
code=$(curl -s -o /dev/null -m 2 -w '%{http_code}' "$url" 2>/dev/null || echo 000)
|
|
249
|
+
if [ -n "$code" ] && [ "$code" != "000" ]; then state="green"; else state="red"; fi
|
|
250
|
+
fi
|
|
251
|
+
printf '%s|%s|%s\n' "$now" "$url" "$state" > "$cache" 2>/dev/null || true
|
|
252
|
+
_render_secure "$state" "$label"
|
|
253
|
+
}
|
|
254
|
+
|
|
176
255
|
show_list=$(echo "$show" | tr ',' ' ')
|
|
177
256
|
total=0
|
|
178
257
|
up=0
|
|
@@ -183,6 +262,7 @@ for d in $show_list; do
|
|
|
183
262
|
chart) chip_chart ;;
|
|
184
263
|
deck) chip_deck ;;
|
|
185
264
|
council) chip_council ;;
|
|
265
|
+
secure) chip_secure ;;
|
|
186
266
|
*) continue ;;
|
|
187
267
|
esac
|
|
188
268
|
total=$((total + 1))
|
|
@@ -40,7 +40,14 @@ if [ -x "$HOME/.launchsecure/statusline-mcp.sh" ]; then
|
|
|
40
40
|
fi
|
|
41
41
|
fi
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
# Layout: by default the chips go on their OWN line below the user's original
|
|
44
|
+
# statusline (Claude Code renders each stdout newline as a new row). Set
|
|
45
|
+
# LK_STATUSLINE_INLINE=1 to keep the old single-line ` | `-joined layout.
|
|
46
|
+
if [ "${LK_STATUSLINE_INLINE:-0}" = "1" ]; then
|
|
47
|
+
sep=$'\033[2m | \033[0m'
|
|
48
|
+
else
|
|
49
|
+
sep=$'\n'
|
|
50
|
+
fi
|
|
44
51
|
if [ -n "$original_output" ] && [ -n "$chips" ]; then
|
|
45
52
|
printf '%s%s%s' "$original_output" "$sep" "$chips"
|
|
46
53
|
elif [ -n "$original_output" ]; then
|