@launchsecure/launch-kit 0.0.32 → 0.0.34
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/chart-serve.js +167 -2
- package/dist/server/cli.js +328 -42
- package/dist/server/course-entry.js +1 -1
- package/dist/server/graph-mcp-entry.js +180 -4
- package/dist/server/init-entry.js +1133 -219
- package/dist/server/launch-radar-entry.js +45 -0
- package/dist/server/parse-worker-entry.js +167 -2
- package/dist/server/radar-docker-init-entry.js +644 -0
- package/dist/server/radar-entrypoint-entry.js +99 -0
- package/dist/server/radar-teardown-entry.js +478 -0
- package/dist/server/recall-entry.js +4 -1
- package/dist/server/rover-entry.js +20122 -0
- package/package.json +7 -5
- package/scaffolds/ls-marketplace/plugins/kit/commands/activate-statusline.md +5 -5
- package/scaffolds/ls-marketplace/plugins/kit/commands/standup.md +6 -6
- package/scaffolds/ls-marketplace/plugins/kit/skills/analyse/SKILL.md +6 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/brief/SKILL.md +40 -48
- package/scaffolds/ls-marketplace/plugins/kit/skills/debug/SKILL.md +45 -20
- package/scaffolds/ls-marketplace/plugins/kit/skills/deploy-check/SKILL.md +76 -67
- package/scaffolds/ls-marketplace/plugins/kit/skills/handoff/SKILL.md +132 -0
- package/scaffolds/ls-marketplace/plugins/kit/skills/ship/SKILL.md +290 -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,290 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: End-to-end ship flow — runs /kit:deploy-check, prints the exact commit list, authors a shipping-log Brief (doc/shipping-logs/*.md) that joins the push payload, then pushes the named branch only after explicit confirmation. The Brief publishes itself to the LS Comm Hub via file-content-sync when the push lands — no separate post, no local log file. Stack-agnostic: detects the project's migrations tooling and deploy platform at runtime rather than assuming any one stack. Never calls a host's deploy CLI directly — pushing to a deploy-tracked branch lets the host's git integration deploy.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /kit:ship
|
|
6
|
+
|
|
7
|
+
Compose `/kit:deploy-check` + shipping-log Brief + `git push` 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
|
+
This skill ships with `launch-kit init` into **any** project — Node, Python, Ruby, Go, Rust, a static site, a library — so it makes **no stack assumptions**. It detects the migrations tooling and deploy platform at runtime (Preflight step 7) and adapts; anything it can't detect, it degrades to a safe, platform-neutral path rather than referencing a tool the repo doesn't have.
|
|
10
|
+
|
|
11
|
+
The shipping log is a **Brief**: a markdown doc at `doc/shipping-logs/<date>-<target>-<sha>.md`, committed as part of the ship itself. If the project syncs its docs to LaunchSecure (the `shipping-logs` doc category mapped to the discussion handler — the same file-content-sync mechanism the LS server uses for any `doc/**` category), the moment the push lands the doc materializes as a Comm Hub comment under the "Shipping Logs" header — team-visible, branch-aware, no separate publish step. If the project is not wired to LaunchSecure, the Brief is still a durable in-repo record of every ship. The repo records what shipped; the Comm Hub renders it when present. One artifact, one or two surfaces.
|
|
12
|
+
|
|
13
|
+
Hard rule from project memory: **never push commits the user didn't explicitly name**, and **pushing to a deploy-tracked branch may auto-deploy** — so this skill always asks per-action before pushing, even when invoked with arguments. There is no `--yes-i-mean-it` flag.
|
|
14
|
+
|
|
15
|
+
Parse `$ARGUMENTS`:
|
|
16
|
+
|
|
17
|
+
- (empty) — full flow on the current branch → its upstream (resolved via `git rev-parse --abbrev-ref @{u}` or, missing that, `origin/<current-branch>`).
|
|
18
|
+
- **--to=<branch>** — push to a different remote branch (e.g. `--to=staging`). The skill never creates a new remote branch silently — if the target doesn't exist on origin, surface that and ask.
|
|
19
|
+
- **--dry-run** — run deploy-check + build the shipping-log Brief preview, but do NOT write the doc, do NOT commit, do NOT push. Useful for "what would shipping look like right now?".
|
|
20
|
+
- **--note=<text>** — free-form human note rendered as the Brief's `**Note**:` line. Useful for hotfix context, rollout caveats, or named reviewer.
|
|
21
|
+
- **--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.
|
|
22
|
+
- **--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.
|
|
23
|
+
|
|
24
|
+
Examples:
|
|
25
|
+
|
|
26
|
+
- `/kit:ship` → check, author Brief, confirm, push current branch (including the Brief) to its upstream.
|
|
27
|
+
- `/kit:ship --dry-run` → check + preview the Brief only; no writes, no push.
|
|
28
|
+
- `/kit:ship --to=master` from `implementation` → cross-branch merge-and-deploy flow (see "Cross-branch ship" below).
|
|
29
|
+
- `/kit:ship --note="hotfix for feedback widget 500s"` → Brief carries the note.
|
|
30
|
+
|
|
31
|
+
## Preflight
|
|
32
|
+
|
|
33
|
+
1. `git rev-parse --is-inside-work-tree` — abort if not a git repo.
|
|
34
|
+
2. Resolve current branch and the **deploy-target branch**:
|
|
35
|
+
- If `--to=` given, use it.
|
|
36
|
+
- Else `git rev-parse --abbrev-ref @{u}` (the branch's tracked upstream).
|
|
37
|
+
- Else fall back to `origin/<current>` and warn that no upstream is set.
|
|
38
|
+
3. Resolve the **deploy-tracked branch list** for "is this a prod push?" gating:
|
|
39
|
+
- Read `git symbolic-ref refs/remotes/origin/HEAD --short` (strip `origin/`) → that's the repo's default; treat as deploy-tracked.
|
|
40
|
+
- Always treat `master` and `main` as deploy-tracked if they exist on origin.
|
|
41
|
+
- If the resolved target is in this list, set `IS_PROD_PUSH=true`. Used to escalate confirmations and refuse `--quick` / `--skip-check=build`.
|
|
42
|
+
4. Print the scope upfront — the user should never wonder what's about to happen:
|
|
43
|
+
```
|
|
44
|
+
ship: <current-branch> → <target-branch> (prod: yes|no)
|
|
45
|
+
```
|
|
46
|
+
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.
|
|
47
|
+
6. Confirm the shipping-logs category exists — `doc/shipping-logs/` directory present OR `shipping-logs` listed in the project's docCategories config (e.g. a `.launch-secure.config` / launch-kit config). If neither, warn: `⚠ shipping-logs doc category not registered — the Brief is still written to the repo, but won't sync to the Comm Hub` and continue.
|
|
48
|
+
7. **Detect the project stack** (this is what makes the skill portable — do it once here, reuse in steps 3 and 5). Probe the working tree; do not assume:
|
|
49
|
+
- **`MIGRATIONS_DIR`** — the first of these that exists, else `none`:
|
|
50
|
+
`prisma/migrations/` (Prisma) · `supabase/migrations/` (Supabase) · `drizzle/` or a dir containing `drizzle/meta/` (Drizzle) · `db/migrate/` (Rails/ActiveRecord) · `migrations/` with `alembic.ini` nearby or `alembic/versions/` (Alembic) · `*/migrations/` under a Django app · `src/main/resources/db/migration/` (Flyway) · a knex/TypeORM/Sequelize migrations dir named in the repo's ORM config. If a launch-kit/project config declares an explicit `migrationsPath`, that wins over detection. If none match, `MIGRATIONS_DIR=none` → the migration gate (step 3) is skipped entirely. Non-DB projects (libraries, CLIs, static sites) legitimately have no migrations.
|
|
51
|
+
- **`BACKUP_STORY`** — detect what protects a migration: a backup script (`scripts/*backup*`, `scripts/migrate-with-backup.*`) and/or a CI workflow (`.github/workflows/*backup*`, `*migrat*`, or the equivalent under `.gitlab-ci.yml` / other CI). Record whatever exists, or `none`.
|
|
52
|
+
- **`DEPLOY_PLATFORM`** — the first marker that matches, else `unknown`:
|
|
53
|
+
`vercel.json` / `.vercel/` → `vercel` · `netlify.toml` → `netlify` · `fly.toml` → `fly` · `render.yaml` → `render` · `railway.json`/`railway.toml` → `railway` · an app-deploying workflow under `.github/workflows/` → `github-actions` · a `Dockerfile` with no platform marker → `container` · none → `unknown`. Drives the post-push guidance in step 5; never hardcode a single host.
|
|
54
|
+
|
|
55
|
+
## Step 1 — Gate (run /kit:deploy-check)
|
|
56
|
+
|
|
57
|
+
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`, which does its own stack detection (typecheck/build/migration-drift adapt to the detected toolchain).
|
|
58
|
+
|
|
59
|
+
Verdict handling:
|
|
60
|
+
|
|
61
|
+
- **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".
|
|
62
|
+
- **GO WITH CAVEATS** → surface the warnings, then ask:
|
|
63
|
+
> "deploy-check returned GO WITH CAVEATS (<N> warnings listed above). Continue with ship? Reply `yes` to continue, `cancel` to abort."
|
|
64
|
+
- **GO** → continue silently to step 2.
|
|
65
|
+
|
|
66
|
+
Hard rules:
|
|
67
|
+
|
|
68
|
+
- 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.`
|
|
69
|
+
- If deploy-check reports a `migration_safety` row (it only does when the project has migrations) and it is anything other than ✓, treat as NO-GO regardless of overall verdict. Migration corruption is why the project carries a migration-safety discipline — this skill enforces it when migrations exist, and is silent about it when they don't.
|
|
70
|
+
|
|
71
|
+
## Step 2 — Show the exact push payload
|
|
72
|
+
|
|
73
|
+
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).
|
|
74
|
+
|
|
75
|
+
```
|
|
76
|
+
About to push <current-branch> → origin/<target-branch>:
|
|
77
|
+
|
|
78
|
+
<sha> <subject> <author-relative-time>
|
|
79
|
+
<sha> <subject> <author-relative-time>
|
|
80
|
+
…
|
|
81
|
+
|
|
82
|
+
<N> commits, <M> files changed (<+adds>/<-dels>)
|
|
83
|
+
(+ 1 shipping-log Brief commit, authored in step 4)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Generated from:
|
|
87
|
+
|
|
88
|
+
- `git log --pretty=format:' %h %s (%ar, %an)' origin/<target>..HEAD`
|
|
89
|
+
- `git diff --shortstat origin/<target>...HEAD`
|
|
90
|
+
|
|
91
|
+
If the list is empty → abort: `nothing to push — local branch is at or behind origin/<target>`.
|
|
92
|
+
|
|
93
|
+
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.
|
|
94
|
+
|
|
95
|
+
## Step 3 — Migration backup gate (only when MIGRATIONS_DIR ≠ none)
|
|
96
|
+
|
|
97
|
+
If `MIGRATIONS_DIR=none` (detected in Preflight step 7), **skip this step entirely** — there's nothing to gate.
|
|
98
|
+
|
|
99
|
+
Otherwise, if `git diff origin/<target>...HEAD --name-only -- <MIGRATIONS_DIR>` returns any files, surface:
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
⚠ This push includes <N> new migration(s):
|
|
103
|
+
- <MIGRATIONS_DIR>/<file>
|
|
104
|
+
…
|
|
105
|
+
|
|
106
|
+
Backup story:
|
|
107
|
+
<BACKUP_STORY, described concretely — e.g.:>
|
|
108
|
+
- CI: <detected workflow> runs a DB dump server-side once the migration lands on <target-branch>.
|
|
109
|
+
- Local: if you applied locally, you used <detected backup script> per the repo's migration docs.
|
|
110
|
+
<or, if BACKUP_STORY=none:>
|
|
111
|
+
- ⚠ No automated pre-migration backup detected in this repo. Take a manual dump before this lands,
|
|
112
|
+
or add a backup step to CI. Recovery is impossible without one.
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Then ask:
|
|
116
|
+
|
|
117
|
+
> "Migration push detected. Type `understood` to continue, or `cancel` to abort."
|
|
118
|
+
|
|
119
|
+
This is a deliberate friction point — typing a word is more honest than `y`. Do not accept `yes` here; require `understood`.
|
|
120
|
+
|
|
121
|
+
## Step 4 — Author the shipping-log Brief
|
|
122
|
+
|
|
123
|
+
Build the Brief BEFORE pushing so it ships inside the same payload — the record and the code land atomically, and (when synced) file-content-sync publishes both on the same webhook delivery.
|
|
124
|
+
|
|
125
|
+
If `--dry-run`, build and show the Brief in a fenced block but do NOT write the file and do NOT commit.
|
|
126
|
+
|
|
127
|
+
### Path & naming
|
|
128
|
+
|
|
129
|
+
```
|
|
130
|
+
doc/shipping-logs/<YYYY-MM-DD>-<target-branch>-<shortsha>.md
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
- `<YYYY-MM-DD>` — ship date (local date).
|
|
134
|
+
- `<target-branch>` — slugified target (e.g. `master`, `implementation`).
|
|
135
|
+
- `<shortsha>` — short sha of the current HEAD (pre-Brief-commit). Keeps same-day ships to the same target from colliding, and makes the filename greppable back to the commit range.
|
|
136
|
+
|
|
137
|
+
One ship = one new file. Never append to or rewrite a previous ship's Brief — corrections happen in a new `## Update <ISO-date>` section added to the SAME ship's Brief.
|
|
138
|
+
|
|
139
|
+
### Brief format
|
|
140
|
+
|
|
141
|
+
Plain markdown, no HTML, no emojis (project comms convention). Frontmatter carries only the title — the discussion handler manages its own sync fields.
|
|
142
|
+
|
|
143
|
+
```markdown
|
|
144
|
+
---
|
|
145
|
+
title: Ship <YYYY-MM-DD> — <branch> → <target>: <one-line summary>
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
**Shipped**: <ISO timestamp>
|
|
149
|
+
**Branch**: <branch> → <target>
|
|
150
|
+
**Prod push**: yes | no
|
|
151
|
+
**Commits**: <N> (<oldest-sha>..<newest-sha>)
|
|
152
|
+
**Deploy check**: <verdict>
|
|
153
|
+
**Note**: <--note value — omit this line entirely when absent>
|
|
154
|
+
|
|
155
|
+
## Summary
|
|
156
|
+
|
|
157
|
+
<One paragraph: what this ship is, why it went out, what a teammate needs to know.>
|
|
158
|
+
|
|
159
|
+
## What shipped
|
|
160
|
+
|
|
161
|
+
### <theme scope, e.g. db-providers>
|
|
162
|
+
- <outcome bullet — short product-facing sentence, NOT a raw commit subject>
|
|
163
|
+
- <outcome bullet>
|
|
164
|
+
|
|
165
|
+
### <next theme>
|
|
166
|
+
- …
|
|
167
|
+
|
|
168
|
+
## Migrations
|
|
169
|
+
|
|
170
|
+
<List each migration path + its backup story, or "None.">
|
|
171
|
+
|
|
172
|
+
## Deploy check
|
|
173
|
+
|
|
174
|
+
<verdict>
|
|
175
|
+
- <warning lines from the deploy-check report, verbatim>
|
|
176
|
+
|
|
177
|
+
## Commits
|
|
178
|
+
|
|
179
|
+
- `<shortsha>` <subject>
|
|
180
|
+
- `<shortsha>` <subject>
|
|
181
|
+
- …
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Field sources:
|
|
185
|
+
|
|
186
|
+
- **Theme grouping** — group commits by conventional-commit scope (same default rule as `/kit:standup` step 3). Outcomes are short product-facing sentences. If commits lack scopes and there are ≥20 changed files across ≥5 dirs, escalate to launch-chart module grouping; otherwise bucket into a `misc` theme.
|
|
187
|
+
- **Commits / stats** — `git log --pretty=format:'%h%x09%s' origin/<target>..HEAD` + `git diff --shortstat origin/<target>...HEAD`.
|
|
188
|
+
- **Migrations** — if `MIGRATIONS_DIR ≠ none`: `git diff --name-only origin/<target>...HEAD -- <MIGRATIONS_DIR>` (exactly what step 3 saw); else `None.`
|
|
189
|
+
- **Deploy check** — verdict + warnings from step 1's report.
|
|
190
|
+
|
|
191
|
+
### Preview + confirm
|
|
192
|
+
|
|
193
|
+
Show the full Brief in a fenced block, then ask:
|
|
194
|
+
|
|
195
|
+
> "Write this Brief to `doc/shipping-logs/<filename>` and commit it? Reply `yes` to write + commit, `edit` to tweak (summary, themes, note), `skip` to ship without a log, or `cancel` to abort the ship."
|
|
196
|
+
|
|
197
|
+
- `yes` / `y` → write the file, then `git add doc/shipping-logs/<filename> && git commit -m "docs(shipping-logs): ship <YYYY-MM-DD> — <target> (<one-line summary>)"`. The Brief commit is now the payload's tip.
|
|
198
|
+
- `edit` → ask what to change, redraft, re-show, re-ask.
|
|
199
|
+
- `skip` → no file, no commit. The ship proceeds unlogged — say so plainly: `shipping without a log entry; there will be no record of this ship.`
|
|
200
|
+
- `cancel` → abort the entire ship. Nothing was written, nothing was pushed.
|
|
201
|
+
|
|
202
|
+
## Step 5 — Push confirmation
|
|
203
|
+
|
|
204
|
+
Ask **exactly**:
|
|
205
|
+
|
|
206
|
+
- If `IS_PROD_PUSH=false`:
|
|
207
|
+
> "Push <N> commits to origin/<target-branch>? Reply `yes` to push, `cancel` to abort."
|
|
208
|
+
- If `IS_PROD_PUSH=true`:
|
|
209
|
+
> "Push <N> commits to origin/<target-branch>. This is a deploy-tracked branch — <if DEPLOY_PLATFORM≠unknown: '<platform> will deploy automatically'; else: 'whatever deploy pipeline is wired to this branch will pick it up'>. Reply `ship it` to push, `cancel` to abort."
|
|
210
|
+
|
|
211
|
+
`<N>` includes the Brief commit from step 4 (when not skipped). 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.
|
|
212
|
+
|
|
213
|
+
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`.
|
|
214
|
+
|
|
215
|
+
If the push fails AND a Brief commit was created in step 4, leave it in place — it's a normal local commit; the user resolves the push problem and re-runs `/kit:ship` (step 2 will show it as part of the payload).
|
|
216
|
+
|
|
217
|
+
After a successful push:
|
|
218
|
+
|
|
219
|
+
- The Brief is now live in the repo. If the project is wired to LaunchSecure, file-content-sync picks it up from the webhook delivery and materializes the Comm Hub comment under the "Shipping Logs" category (branch-aware: a ship to a non-default branch shows with a branch pill until it reaches the default branch).
|
|
220
|
+
- If `IS_PROD_PUSH=true`, surface deploy guidance **for the detected platform** (`DEPLOY_PLATFORM`), never a hardcoded host:
|
|
221
|
+
|
|
222
|
+
| DEPLOY_PLATFORM | Post-push line |
|
|
223
|
+
|---|---|
|
|
224
|
+
| `vercel` | `Vercel's git integration will deploy the latest commit on <target>. Check: vercel ls --prod. Do NOT run vercel deploy from here — it bypasses the git→Vercel flow and double-deploys.` |
|
|
225
|
+
| `netlify` | `Netlify's git integration will build the latest commit on <target>. Check the Netlify dashboard / netlify status. Do NOT run netlify deploy --prod from here.` |
|
|
226
|
+
| `fly` | `If a deploy GitHub Action is wired, it will run flyctl deploy on push. Otherwise a maintainer runs it. Check: fly status.` |
|
|
227
|
+
| `render` / `railway` | `<platform>'s git integration will deploy the latest commit on <target>. Check the <platform> dashboard.` |
|
|
228
|
+
| `github-actions` | `The deploy workflow under .github/workflows/ will run on push to <target>. Check: gh run list --branch <target>.` |
|
|
229
|
+
| `container` / `unknown` | `Push complete. This repo has no detected managed-deploy integration — whatever CI/CD or manual process is wired to <target> takes over from here. This skill does not deploy.` |
|
|
230
|
+
|
|
231
|
+
```
|
|
232
|
+
Pushed.
|
|
233
|
+
<platform-specific line from the table above>
|
|
234
|
+
|
|
235
|
+
Shipping log written: doc/shipping-logs/<filename><if synced: → Comm Hub "Shipping Logs">
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
## Cross-branch ship (--to=master from a feature branch)
|
|
239
|
+
|
|
240
|
+
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:
|
|
241
|
+
|
|
242
|
+
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`.
|
|
243
|
+
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.
|
|
244
|
+
3. On non-fast-forward reject from origin, do NOT suggest `--force`. Surface and stop.
|
|
245
|
+
4. The Brief's `**Branch**:` line shows the asymmetric flow (`<current> → master`) and its filename uses `master` as the target slug.
|
|
246
|
+
|
|
247
|
+
## Constraints
|
|
248
|
+
|
|
249
|
+
- **Never auto-commit and auto-push in one breath.** Always two explicit confirmations (step 4 Brief commit, step 5 push). The `--dry-run` flag exists instead of bundling.
|
|
250
|
+
- **Never call a host's deploy CLI** (`vercel deploy`, `netlify deploy`, `flyctl deploy`, etc.). Managed deploys come from the host's git integration on push to a deploy-tracked branch. Calling the CLI double-deploys and bypasses the gate. The one exception is a project whose `DEPLOY_PLATFORM` is genuinely CLI-only with no git integration — and even then, this skill stops at the push and leaves the deploy to the user.
|
|
251
|
+
- **Never `git push --force` / `--force-with-lease`.** If a push fails, the user investigates.
|
|
252
|
+
- **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).
|
|
253
|
+
- **Never bypass migration_safety when migrations exist.** A ✓ on the deploy-check migration_safety row is the gate; anything else is NO-GO. When the project has no migrations, there is no such row and nothing to bypass.
|
|
254
|
+
- **No stack assumptions.** Everything stack-specific (migrations tooling, deploy host, backup story) is resolved by detection in Preflight step 7. If detection comes up empty, degrade to the neutral path — never reference a tool, path, or command the repo doesn't have.
|
|
255
|
+
- **Single source of truth for checks.** Do not duplicate `/kit:deploy-check` logic inline; invoke it.
|
|
256
|
+
- **One ship, one Brief.** Never edit, delete, or rewrite a previous ship's Brief. Corrections go in an `## Update <ISO-date>` section appended to that ship's own Brief in a follow-up commit.
|
|
257
|
+
- **Log only what actually ships.** The Brief is committed before the push, but it only publishes when the push lands — if the user cancels at step 5, tell them the Brief commit is still local and will ride along with the next ship (or can be dropped by them; never drop it yourself).
|
|
258
|
+
- **Honest about deploy state.** This skill ends when the push completes. It does NOT wait for a build to finish, does NOT verify the prod URL is up, does NOT roll back. Point the user at the detected platform's status command for deploy-monitoring.
|
|
259
|
+
- **Dry-run is truly dry.** `--dry-run` must NOT write any file, must NOT commit, must NOT push. The preview is shown in chat only.
|
|
260
|
+
- **Respect doc/ ownership rules.** Only ever write under `doc/shipping-logs/`. Never touch `doc/ideas/` (personal scratch) or other categories from this skill.
|
|
261
|
+
|
|
262
|
+
## Idempotency
|
|
263
|
+
|
|
264
|
+
Re-running `/kit:ship` after a successful run:
|
|
265
|
+
|
|
266
|
+
- Step 2 will show "nothing to push" if the previous push landed cleanly — the natural no-op. No new Brief results.
|
|
267
|
+
- Each successful ship is a separate file in `doc/shipping-logs/`. There is no per-day or per-branch coalescing — the Comm Hub renders them as separate entries. If a hotfix ships 10 minutes after a feature, both Briefs exist independently.
|
|
268
|
+
- A Brief committed but not pushed (cancelled at step 5) is picked up by the next run: step 2 shows it in the payload, step 4 detects an existing un-pushed Brief for this range and offers to reuse or rewrite it instead of authoring a duplicate.
|
|
269
|
+
|
|
270
|
+
## Reading the log
|
|
271
|
+
|
|
272
|
+
The shipping history lives in the repo, and (when synced) in the Comm Hub:
|
|
273
|
+
|
|
274
|
+
```
|
|
275
|
+
# repo side — every ship, newest first
|
|
276
|
+
ls -t doc/shipping-logs/
|
|
277
|
+
|
|
278
|
+
# one ship's full record
|
|
279
|
+
cat doc/shipping-logs/<file>.md
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Comm Hub side (when the project is LaunchSecure-wired): the "Shipping Logs" category header in the LS sidebar lists every published ship Brief with the BookOpen icon. Filter chips (Published / In Development) follow the branch-aware brief tiers.
|
|
283
|
+
|
|
284
|
+
## Notes for the assistant
|
|
285
|
+
|
|
286
|
+
- 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.
|
|
287
|
+
- "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 5 phrasing changes).
|
|
288
|
+
- The shipping-log Brief is the durable artifact and (when synced) the published record at once — there is no separate "publish" step and no local NDJSON file. If you find `.launchsecure/ship-log.ndjson` in a repo, it's from a pre-Brief version of this skill; leave it alone (don't migrate, don't delete) and mention it once.
|
|
289
|
+
- **Portability is the contract.** This skill is installed by `launch-kit init` into projects on stacks you can't predict. Anything you hardcode that isn't in *this* repo is a bug for the next repo. When in doubt, detect or degrade — never assume.
|
|
290
|
+
- 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`.
|
|
@@ -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
|