@launchsecure/launch-kit 0.0.26 → 0.0.28
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/beacon/beacon.mjs +1003 -440
- package/dist/beacon/beacon.mjs.map +1 -1
- package/dist/beacon/beacon.umd.js +45 -24
- package/dist/beacon/beacon.umd.js.map +1 -1
- package/dist/beacon/types/capture/events.d.ts +20 -0
- package/dist/beacon/types/capture/events.d.ts.map +1 -0
- package/dist/beacon/types/element.d.ts +1 -0
- package/dist/beacon/types/element.d.ts.map +1 -1
- package/dist/beacon/types/index.d.ts +2 -1
- package/dist/beacon/types/index.d.ts.map +1 -1
- package/dist/beacon/types/monitor/dom.d.ts +13 -0
- package/dist/beacon/types/monitor/dom.d.ts.map +1 -0
- package/dist/beacon/types/monitor/index.d.ts +19 -0
- package/dist/beacon/types/monitor/index.d.ts.map +1 -0
- package/dist/beacon/types/monitor/network.d.ts +12 -0
- package/dist/beacon/types/monitor/network.d.ts.map +1 -0
- package/dist/beacon/types/monitor/transport.d.ts +27 -0
- package/dist/beacon/types/monitor/transport.d.ts.map +1 -0
- package/dist/beacon/types/monitor/types.d.ts +117 -0
- package/dist/beacon/types/monitor/types.d.ts.map +1 -0
- package/dist/beacon/types/types.d.ts +10 -0
- package/dist/beacon/types/types.d.ts.map +1 -1
- package/dist/beacon/types/ui/drawer.d.ts +3 -1
- package/dist/beacon/types/ui/drawer.d.ts.map +1 -1
- package/dist/beacon/types/ui/monitor-panel.d.ts +19 -0
- package/dist/beacon/types/ui/monitor-panel.d.ts.map +1 -0
- package/dist/chart-client/assets/index-CJ4mgRRF.css +1 -0
- package/dist/chart-client/assets/{index-Bk1hawjD.js → index-Ccy-DpI-.js} +46 -42
- package/dist/chart-client/index.html +2 -2
- package/dist/client/assets/index-DI5qSR_w.css +32 -0
- package/dist/client/assets/index-Dp0_okva.js +294 -0
- package/dist/client/index.html +2 -2
- package/dist/council-client/assets/index-C_-vAM9L.css +1 -0
- package/dist/council-client/index.html +2 -2
- package/dist/deck-client/assets/{_baseUniq-C2xT_eYu.js → _baseUniq-W2JQDmje.js} +1 -1
- package/dist/deck-client/assets/{arc-CmVL9pGd.js → arc-DIBWAId9.js} +1 -1
- package/dist/deck-client/assets/{architectureDiagram-Q4EWVU46-BSFgdjve.js → architectureDiagram-Q4EWVU46-CAIRMvJK.js} +1 -1
- package/dist/deck-client/assets/{blockDiagram-DXYQGD6D-DuLzscvP.js → blockDiagram-DXYQGD6D-BeNaNiOi.js} +1 -1
- package/dist/deck-client/assets/{c4Diagram-AHTNJAMY-CfCJB8eY.js → c4Diagram-AHTNJAMY-B9Ozi62h.js} +1 -1
- package/dist/deck-client/assets/channel-CRdozqbp.js +1 -0
- package/dist/deck-client/assets/{chunk-4BX2VUAB-DxmLYTWZ.js → chunk-4BX2VUAB-D7AZ47dt.js} +1 -1
- package/dist/deck-client/assets/{chunk-4TB4RGXK-CCnf7GFE.js → chunk-4TB4RGXK-DnVnNPcI.js} +1 -1
- package/dist/deck-client/assets/{chunk-55IACEB6-Db9DApcj.js → chunk-55IACEB6-UKYs-YNd.js} +1 -1
- package/dist/deck-client/assets/{chunk-EDXVE4YY-DmYDq8ZI.js → chunk-EDXVE4YY-D43b-SKn.js} +1 -1
- package/dist/deck-client/assets/{chunk-FMBD7UC4-BGhUlF20.js → chunk-FMBD7UC4-QzBAoyyW.js} +1 -1
- package/dist/deck-client/assets/{chunk-OYMX7WX6-CpEnicQZ.js → chunk-OYMX7WX6-Cjif4r6W.js} +1 -1
- package/dist/deck-client/assets/{chunk-QZHKN3VN-Doa7LKwf.js → chunk-QZHKN3VN-CqLDirEI.js} +1 -1
- package/dist/deck-client/assets/{chunk-YZCP3GAM-CpkIlH6V.js → chunk-YZCP3GAM-_FQvmMs4.js} +1 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-lIZMp57W.js +1 -0
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-lIZMp57W.js +1 -0
- package/dist/deck-client/assets/clone-BtWeSTyJ.js +1 -0
- package/dist/deck-client/assets/{cose-bilkent-S5V4N54A-Bkh8Bfcb.js → cose-bilkent-S5V4N54A-rfrocesE.js} +1 -1
- package/dist/deck-client/assets/{dagre-KV5264BT-Bp0XpTgH.js → dagre-KV5264BT-Bv_7DJat.js} +1 -1
- package/dist/deck-client/assets/{diagram-5BDNPKRD-ZHiyGYPQ.js → diagram-5BDNPKRD-4F1414G5.js} +1 -1
- package/dist/deck-client/assets/{diagram-G4DWMVQ6-BW-Q8_H5.js → diagram-G4DWMVQ6-C4-Pszqm.js} +1 -1
- package/dist/deck-client/assets/{diagram-MMDJMWI5-6I3LTafu.js → diagram-MMDJMWI5-B647TIx9.js} +1 -1
- package/dist/deck-client/assets/{diagram-TYMM5635-CyM5YK28.js → diagram-TYMM5635-BFAqpezd.js} +1 -1
- package/dist/deck-client/assets/{erDiagram-SMLLAGMA-CjNxVJHk.js → erDiagram-SMLLAGMA-BfBfrJOC.js} +1 -1
- package/dist/deck-client/assets/{flowDiagram-DWJPFMVM-BDQHuAJR.js → flowDiagram-DWJPFMVM-DX9YAYes.js} +1 -1
- package/dist/deck-client/assets/{ganttDiagram-T4ZO3ILL-B7MnkpbP.js → ganttDiagram-T4ZO3ILL-DCuiy7wF.js} +1 -1
- package/dist/deck-client/assets/{gitGraphDiagram-UUTBAWPF-C9dZAcYD.js → gitGraphDiagram-UUTBAWPF-CGp1IXUh.js} +1 -1
- package/dist/deck-client/assets/{graph-CjdBnzUy.js → graph-B7g8aoxv.js} +1 -1
- package/dist/deck-client/assets/{index-DeIVPW63.js → index-Dg1r-WSN.js} +3 -3
- package/dist/deck-client/assets/index-DsIZ3LqL.css +1 -0
- package/dist/deck-client/assets/{infoDiagram-42DDH7IO-C7d3iRC3.js → infoDiagram-42DDH7IO-L3fahMkF.js} +1 -1
- package/dist/deck-client/assets/{ishikawaDiagram-UXIWVN3A-BcYGKj09.js → ishikawaDiagram-UXIWVN3A-aS_EjWBZ.js} +1 -1
- package/dist/deck-client/assets/{journeyDiagram-VCZTEJTY-DqFlRrOL.js → journeyDiagram-VCZTEJTY-djTSQZF9.js} +1 -1
- package/dist/deck-client/assets/{kanban-definition-6JOO6SKY-BJhPp1NR.js → kanban-definition-6JOO6SKY-CcTHo4CM.js} +1 -1
- package/dist/deck-client/assets/{layout-DIeS6GvK.js → layout-mEJiadb7.js} +1 -1
- package/dist/deck-client/assets/{linear-He_yJy5H.js → linear-XgTKqyRu.js} +1 -1
- package/dist/deck-client/assets/{min-DQ6Kx06t.js → min-Ct9jZdpd.js} +1 -1
- package/dist/deck-client/assets/{mindmap-definition-QFDTVHPH-sQ62L8T2.js → mindmap-definition-QFDTVHPH-BaFxCGNU.js} +1 -1
- package/dist/deck-client/assets/{pieDiagram-DEJITSTG-BqCWmU2K.js → pieDiagram-DEJITSTG-CIbYYjtw.js} +1 -1
- package/dist/deck-client/assets/{quadrantDiagram-34T5L4WZ-rQ1TJOoe.js → quadrantDiagram-34T5L4WZ-D9EtCOvh.js} +1 -1
- package/dist/deck-client/assets/{requirementDiagram-MS252O5E-BO2MPBOM.js → requirementDiagram-MS252O5E-xeni9eVG.js} +1 -1
- package/dist/deck-client/assets/{sankeyDiagram-XADWPNL6-BgsHEVex.js → sankeyDiagram-XADWPNL6-LYeknz9h.js} +1 -1
- package/dist/deck-client/assets/{sequenceDiagram-FGHM5R23-B3j1yMLU.js → sequenceDiagram-FGHM5R23-RDbsKFZf.js} +1 -1
- package/dist/deck-client/assets/{stateDiagram-FHFEXIEX-C8jFlZou.js → stateDiagram-FHFEXIEX-BH1Zjglk.js} +1 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BrV78NDR.js +1 -0
- package/dist/deck-client/assets/{timeline-definition-GMOUNBTQ-tM-qo4Zk.js → timeline-definition-GMOUNBTQ-IFXxKptt.js} +1 -1
- package/dist/deck-client/assets/{vennDiagram-DHZGUBPP-B0-6kOEu.js → vennDiagram-DHZGUBPP-D-sLkQs9.js} +1 -1
- package/dist/deck-client/assets/{wardley-RL74JXVD-HpBk07P-.js → wardley-RL74JXVD-C010F8l4.js} +1 -1
- package/dist/deck-client/assets/{wardleyDiagram-NUSXRM2D-BkA1NLDE.js → wardleyDiagram-NUSXRM2D-BTjjuDU3.js} +1 -1
- package/dist/deck-client/assets/{xychartDiagram-5P7HB3ND-CEKGSuI-.js → xychartDiagram-5P7HB3ND-AYbv92n-.js} +1 -1
- package/dist/deck-client/index.html +2 -2
- package/dist/server/beacon-monitor-entry.js +353 -0
- package/dist/server/chart-serve.js +3836 -3750
- package/dist/server/cli.js +8789 -8219
- package/dist/server/council-entry.js +17 -5
- package/dist/server/council-serve.js +8 -3
- package/dist/server/course-entry.js +246 -0
- package/dist/server/deck-mcp-entry.js +24 -12
- package/dist/server/deck-serve.js +11 -8
- package/dist/server/graph-mcp-entry.js +5005 -4865
- package/dist/server/init-entry.js +939 -0
- package/dist/server/orbit-entry.js +2435 -0
- package/dist/server/parse-worker-entry.js +4721 -0
- package/dist/server/recall-entry.js +356 -18
- package/package.json +11 -4
- package/scaffolds/ls-marketplace/.claude-plugin/marketplace.json +15 -0
- package/scaffolds/ls-marketplace/plugins/ls/.claude-plugin/plugin.json +28 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/activate-beacon.md +216 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-array.md +92 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-clear.md +68 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-pulse.md +80 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/beacon-scan.md +62 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/show-mcp-status.md +109 -0
- package/scaffolds/ls-marketplace/plugins/ls/commands/standup.md +177 -0
- package/scaffolds/migrate-safety/.github/workflows/backup-on-migration.yml +72 -0
- package/scaffolds/migrate-safety/docs/migrations-runbook.md +172 -0
- package/scaffolds/migrate-safety/scripts/migrate-with-backup.sh +294 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
- package/dist/chart-client/assets/index-DpaGa3bY.css +0 -1
- package/dist/client/assets/index-Bfel4OQ5.css +0 -32
- package/dist/client/assets/index-eC-WuUWB.js +0 -291
- package/dist/council-client/assets/index-P5kMsT5a.css +0 -1
- package/dist/deck-client/assets/channel-B4aNO8ZB.js +0 -1
- package/dist/deck-client/assets/classDiagram-6PBFFD2Q-BHTI0yWz.js +0 -1
- package/dist/deck-client/assets/classDiagram-v2-HSJHXN6E-BHTI0yWz.js +0 -1
- package/dist/deck-client/assets/clone-HduFm7qU.js +0 -1
- package/dist/deck-client/assets/index-LKZDAS9S.css +0 -1
- package/dist/deck-client/assets/stateDiagram-v2-QKLJ7IA2-BoqepHW0.js +0 -1
- /package/dist/council-client/assets/{index-Cs_MVXHf.js → index-Dt4zWKSj.js} +0 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Draft a daily standup from work done since the last push, group themes using launch-chart, show the draft, and post to LaunchSecure Comm Hub as a daily_update after explicit confirmation.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Standup
|
|
6
|
+
|
|
7
|
+
Generates a daily-update comment for the LaunchSecure Comm Hub. Pulls commits since the last push (with fallbacks), groups them by codebase layer/module using `launch-chart`, drafts a summary in the project's house style, shows it to the user, and posts only after the user confirms. Never posts without explicit "yes".
|
|
8
|
+
|
|
9
|
+
## Preflight
|
|
10
|
+
|
|
11
|
+
1. Verify `.launch-secure.cred.config` exists at the repo root. If missing, abort and tell the user to run `npx launch-kit init` first — without the cred file the `launch-secure` MCP cannot authenticate, so we cannot read prior standups or post the new one.
|
|
12
|
+
2. Verify we are inside a git repo (`git rev-parse --git-dir`). If not, abort with a clear message.
|
|
13
|
+
3. Record the current branch (`git rev-parse --abbrev-ref HEAD`).
|
|
14
|
+
4. Detect whether `launch-chart` is wired by calling `mcp__launch-chart__detect_project_stack`. If the call fails or returns nothing, fall back to git-only grouping (note this in the final summary).
|
|
15
|
+
|
|
16
|
+
## Gather
|
|
17
|
+
|
|
18
|
+
Pull data from layered sources, in this order:
|
|
19
|
+
|
|
20
|
+
### 1. Determine the window
|
|
21
|
+
|
|
22
|
+
- **Primary**: `git log --reverse --pretty=format:'%h%x09%an%x09%ae%x09%s%n%b%n%x00' @{push}..HEAD`. The `@{push}` revspec resolves to where this branch was last pushed; the diff is commits ahead of upstream.
|
|
23
|
+
- **Fallback 1**: if the primary returns empty OR `@{push}` errors with `unknown revision`, query the `launch-secure` MCP via `communication_read({ tag: "daily_update", limit: 1 })`. Take the most recent comment's `createdAt`; gather commits since then via `git log --since="<that timestamp>"`.
|
|
24
|
+
- **Fallback 2**: if no prior `daily_update` exists either, use `git log --since="24 hours ago"`.
|
|
25
|
+
|
|
26
|
+
Tell the user which window was used in one short line ("Using commits since last push (12 commits)" or "No commits since last push — falling back to commits since 2026-05-20 14:01 (last standup)").
|
|
27
|
+
|
|
28
|
+
### 2. Collect change context
|
|
29
|
+
|
|
30
|
+
- `git diff --stat @{push}..HEAD` (or whichever window was chosen) — file paths + line counts. Drives theme grouping in the next step.
|
|
31
|
+
- `git log --pretty=format:'%h %s' <window>` — short subject lines for quick scan.
|
|
32
|
+
- Branch names + PR references in commit messages (look for `#<digits>`, `LS-<id>`, branch slugs like `fix/foo-bar`). These are work-item handles.
|
|
33
|
+
|
|
34
|
+
### 3. Group by layer/module using launch-chart
|
|
35
|
+
|
|
36
|
+
This is the chart's job — do **not** group by file path string-matching. For each changed file (deduped from the diff stat):
|
|
37
|
+
|
|
38
|
+
- Call `mcp__launch-chart__read_graph({ search: "<file basename>", layer: "<best guess: ui|api|db|static>" })` to resolve the file to a graph node, OR
|
|
39
|
+
- Call `mcp__launch-chart__read_graph({ node_id: "<full path>" })` if the file path matches a known node id format
|
|
40
|
+
|
|
41
|
+
From the resolved nodes, pull each node's `module` and `layer` fields. Group commits/files into themes by `module` first, then by `layer` when `module` is missing. Common LS modules: `auth`, `pda`, `pda-guides`, `pda-shell`, `radar`, `chart`, `orbit`, `recall`, `comms`, `board`, `webhooks`, `feedback`, `briefs`, `mcp`, etc.
|
|
42
|
+
|
|
43
|
+
If a file doesn't resolve in the chart (new file, non-TS, config), bucket it under "Misc" or by directory (`scripts/`, `docs/`, `.github/`).
|
|
44
|
+
|
|
45
|
+
### 4. Audit pass (optional, skip if it slows things down)
|
|
46
|
+
|
|
47
|
+
Call `mcp__launch-chart__audit_layer({ layer: "all" })` to surface any drift introduced today (schema_drift, unprotected_routes, dead_screens, hardcoded_values). If the audit reports new issues that didn't exist before (best-effort — compare against the prior standup's audit if possible, otherwise just report current state), flag them in the closing `----` block.
|
|
48
|
+
|
|
49
|
+
### 5. Blast radius for the biggest changes (deploy-safety signal)
|
|
50
|
+
|
|
51
|
+
For the top-3 files by lines-changed in `git diff --stat`, call `mcp__launch-chart__blast_points({ node_id: "<file>", hops: 2 })`. If any of them has a blast radius of >10 dependent nodes, note it as a deploy-risk signal in the `----` block ("touched X which has 24 downstream consumers — review before deploy").
|
|
52
|
+
|
|
53
|
+
### 6. Work-item linkage
|
|
54
|
+
|
|
55
|
+
For each work-item handle found in commit messages, call `mcp__launch-secure__work_items_list` (or `work_item_get` if you have an ID) to pull title + status. If any work items were closed today (status changed to DONE/COMPLETED), call them out in the closing block.
|
|
56
|
+
|
|
57
|
+
### 7. Release detection
|
|
58
|
+
|
|
59
|
+
A commit qualifies the post for the `release` tag if ANY of the following are true:
|
|
60
|
+
- `package.json` `version` field changed in `git diff @{push}..HEAD -- package.json`
|
|
61
|
+
- A migration file under `prisma/migrations/` was added or `prisma/schema.prisma` changed
|
|
62
|
+
- A deploy/publish was mentioned in commit subjects (regex: `\b(publish|release|deploy|bump)\b`)
|
|
63
|
+
- A new bin or export was added to a package's `package.json`
|
|
64
|
+
|
|
65
|
+
If any are true, set `addReleaseTag = true`. Otherwise `false`.
|
|
66
|
+
|
|
67
|
+
## Draft
|
|
68
|
+
|
|
69
|
+
Produce the standup in the **exact** house format. This is the format Prajyot uses for human-written daily updates (verified against the May 18, 19, 20 posts in the Comm Hub):
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
Hey @everyone
|
|
73
|
+
|
|
74
|
+
Pushed <N> commits to <branch> today. Highlights:
|
|
75
|
+
|
|
76
|
+
→ <Theme 1>
|
|
77
|
+
- <outcome bullet, not a commit message>
|
|
78
|
+
- <outcome bullet>
|
|
79
|
+
|
|
80
|
+
→ <Theme 2>
|
|
81
|
+
- <outcome bullet>
|
|
82
|
+
|
|
83
|
+
→ <Theme N>
|
|
84
|
+
- <outcome bullet>
|
|
85
|
+
|
|
86
|
+
----
|
|
87
|
+
|
|
88
|
+
<one-line PSA or deploy-safety note. Examples: "TS clean, no schema/migration changes, safe to deploy." or "Includes prisma migration <name> — run migrate-with-backup.sh before deploy.">
|
|
89
|
+
|
|
90
|
+
Thanks
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**Strict format rules:**
|
|
94
|
+
|
|
95
|
+
- `Hey @everyone` — exactly this. Not "Hey team", not "Hi everyone". Single line, blank line after.
|
|
96
|
+
- `Pushed N commits to <branch> today. Highlights:` — replace `<branch>` with the actual branch from preflight. If the window was a fallback (not "since last push"), say "Drafted N commits' worth of work on <branch> today. Highlights:" instead — be honest about the window.
|
|
97
|
+
- `→ <Theme>` — right-arrow + space + theme name. Theme names come from chart's `module` grouping (e.g. "→ Radar", "→ Webhooks", "→ Chart / Freshness"). Capitalize the first letter.
|
|
98
|
+
- `- <bullet>` — plain hyphen + space. Bullets are **outcomes**, not commit messages. Translate "feat(radar): add transcript view" into "Structured transcript view with overlay reply drawer". Drop scope prefixes and verb tense.
|
|
99
|
+
- Blank line between themes.
|
|
100
|
+
- `----` — four hyphens, on its own line, blank line above and below.
|
|
101
|
+
- The closing block: one short line is fine. Don't pad.
|
|
102
|
+
- `Thanks` — exact word, no comma, no name signature (the post's author is attached automatically).
|
|
103
|
+
|
|
104
|
+
**Constraints:**
|
|
105
|
+
|
|
106
|
+
- Plain text only. No `**bold**`, no `*italic*`, no backticks, no `# headers`, no markdown link syntax. The Comm Hub renders as plain text.
|
|
107
|
+
- Aim for ≤ 350 words total. Standups are skim-able; trim aggressively.
|
|
108
|
+
- Top 3–6 themes is the sweet spot. If you have 20 commits in 12 different modules, collapse the small ones into a "→ Misc" theme.
|
|
109
|
+
- Bullets should be **outcome-shaped**: what landed in the product, not what the diff did. "Multi-select EventTypesPicker on subscription forms" beats "modified components/webhooks/EventTypesPicker.tsx".
|
|
110
|
+
- Mention work-item closures and any deploy-affecting changes (migrations, env var changes, breaking API changes) in the closing block.
|
|
111
|
+
|
|
112
|
+
## Confirm
|
|
113
|
+
|
|
114
|
+
Show the draft to the user verbatim in a code-fenced block (so they see plain-text formatting as-is), then ask **exactly**:
|
|
115
|
+
|
|
116
|
+
> "Post this as a daily_update to LS Comm Hub? Reply `yes` to post, `edit` to revise, or `cancel` to abort."
|
|
117
|
+
|
|
118
|
+
Responses:
|
|
119
|
+
|
|
120
|
+
- **`yes`, `y`, `ok`, `post it`** — proceed to duplicate check + post.
|
|
121
|
+
- **`edit`, `change <thing>`, free-form revisions** — apply the edits, regenerate the draft, re-show, re-ask.
|
|
122
|
+
- **`cancel`, `no`, `nope`** — abort. Don't post. Don't keep partial state.
|
|
123
|
+
|
|
124
|
+
Anything ambiguous → treat as "edit, what would you like changed?".
|
|
125
|
+
|
|
126
|
+
## Duplicate check
|
|
127
|
+
|
|
128
|
+
Before posting, call `mcp__launch-secure__communication_read({ tag: "daily_update", limit: 5 })`. If any returned comment has:
|
|
129
|
+
- `resourceType: "comment"` (not `"daily_update"` — that's bot-only, distinct stream)
|
|
130
|
+
- `author.email` matches the current user's email (from `git config user.email`)
|
|
131
|
+
- `createdAt` within the last 12 hours
|
|
132
|
+
|
|
133
|
+
…then a manual daily_update already exists from today. Offer:
|
|
134
|
+
|
|
135
|
+
> "A daily_update already exists from you today (posted at <time>, <preview-50-chars>). Choose: `replace` to update it (communication_update), `append` to post another, `cancel` to stop."
|
|
136
|
+
|
|
137
|
+
- **replace** → call `mcp__launch-secure__communication_update({ id: "<existing-id>", content: <new-draft> })`. Preserve tags.
|
|
138
|
+
- **append** → proceed to post.
|
|
139
|
+
- **cancel** → abort.
|
|
140
|
+
|
|
141
|
+
## Post
|
|
142
|
+
|
|
143
|
+
Call `mcp__launch-secure__communication_write`:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
{
|
|
147
|
+
resourceType: "comment",
|
|
148
|
+
content: "<the final draft, plain text>",
|
|
149
|
+
tags: addReleaseTag ? ["daily_update", "release"] : ["daily_update"]
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`org_slug` and `project_slug` are auto-supplied from the cred config via the MCP's headersHelper — do NOT pass them yourself.
|
|
154
|
+
|
|
155
|
+
On success: report the comment ID and a friendly "posted to LS Comm Hub" line. If the response includes a URL field, surface it.
|
|
156
|
+
|
|
157
|
+
On failure: surface the error verbatim. Don't retry automatically — auth or schema errors deserve human attention. The draft is preserved in chat so the user can retry manually.
|
|
158
|
+
|
|
159
|
+
## Tag handling
|
|
160
|
+
|
|
161
|
+
Before adding any tag, you may verify it exists via `mcp__launch-secure__tags_list`. The `daily_update` and `release` tags are standard in LS projects; if either is missing, the post will still succeed but the tag won't attach. Surface this as a warning, not a blocker.
|
|
162
|
+
|
|
163
|
+
## Idempotency
|
|
164
|
+
|
|
165
|
+
Re-running `/ls:standup`:
|
|
166
|
+
- Always re-pulls the window fresh. No cached state.
|
|
167
|
+
- Duplicate check handles same-day reposts.
|
|
168
|
+
- The draft is never written to disk — only shown in chat. User can copy it manually if they cancel.
|
|
169
|
+
|
|
170
|
+
## Notes for the assistant
|
|
171
|
+
|
|
172
|
+
- Use `launch-chart` for grouping, not grep/glob. The whole point is producing themes that match how the codebase is organized, not how files are named.
|
|
173
|
+
- The user's preference is short, terse standups (verified style across May 18→20 posts). Default to under-rather-than-over.
|
|
174
|
+
- "Outcome bullet, not commit message" is the single most important transform. A standup full of "feat(x): add y" reads like a changelog, not a status.
|
|
175
|
+
- Never assume `release` tag without evidence (see Release detection above). False positives confuse downstream consumers.
|
|
176
|
+
- Don't ask the user clarifying questions before drafting — produce a first cut, then iterate. The draft is cheap; the conversation isn't.
|
|
177
|
+
- If `launch-chart` is unavailable (no `.launchchart.json`, MCP not responding), fall back to grouping by top-level path segment (`src/app/api/` → "API", `src/client/components/board/` → "Board", etc.) and note "chart unavailable, grouped by path" in chat (not in the post).
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
name: Backup prod DB before migration deploys
|
|
2
|
+
|
|
3
|
+
# Triggers a logical pg_dump of prod whenever a migration file lands on master
|
|
4
|
+
# or implementation. Backup is uploaded as a workflow artifact (90-day retention)
|
|
5
|
+
# tied to the commit SHA — see docs/migrations-runbook.md for restore steps.
|
|
6
|
+
#
|
|
7
|
+
# Required secrets (configure under repo Settings → Secrets and variables → Actions):
|
|
8
|
+
# PROD_DATABASE_URL — full DATABASE_URL for the production DB.
|
|
9
|
+
# Treat this as production credential — anyone who can
|
|
10
|
+
# download the artifact effectively has prod data.
|
|
11
|
+
#
|
|
12
|
+
# Required permissions: this workflow only reads from the DB and writes an
|
|
13
|
+
# artifact; it does not push code, deploy, or modify anything.
|
|
14
|
+
|
|
15
|
+
on:
|
|
16
|
+
push:
|
|
17
|
+
branches: [master, implementation]
|
|
18
|
+
paths:
|
|
19
|
+
- 'prisma/migrations/**'
|
|
20
|
+
- 'prisma/schema.prisma'
|
|
21
|
+
workflow_dispatch: # allow manual runs for ad-hoc snapshots
|
|
22
|
+
|
|
23
|
+
permissions:
|
|
24
|
+
contents: read
|
|
25
|
+
|
|
26
|
+
jobs:
|
|
27
|
+
backup:
|
|
28
|
+
runs-on: ubuntu-latest
|
|
29
|
+
timeout-minutes: 15
|
|
30
|
+
steps:
|
|
31
|
+
- name: Checkout
|
|
32
|
+
uses: actions/checkout@v4
|
|
33
|
+
|
|
34
|
+
- name: Run wrapper in backup-only mode
|
|
35
|
+
env:
|
|
36
|
+
# The same env-var contract used for local — only the destination differs.
|
|
37
|
+
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
|
|
38
|
+
BACKUP_DIR: artifacts
|
|
39
|
+
# Force docker so the wrapper auto-detects the server's major version
|
|
40
|
+
# and pulls the matching postgres:<major> image. Avoids hardcoding a
|
|
41
|
+
# client version that drifts when prod Postgres is upgraded.
|
|
42
|
+
# ubuntu-latest runners ship with docker pre-installed.
|
|
43
|
+
PG_DUMP_VIA_DOCKER: '1'
|
|
44
|
+
run: |
|
|
45
|
+
if [[ -z "$DATABASE_URL" ]]; then
|
|
46
|
+
echo "::error::PROD_DATABASE_URL secret is not configured."
|
|
47
|
+
echo "Set it under repo Settings → Secrets and variables → Actions."
|
|
48
|
+
exit 1
|
|
49
|
+
fi
|
|
50
|
+
bash scripts/migrate-with-backup.sh backup-only
|
|
51
|
+
|
|
52
|
+
- name: Upload dump as artifact
|
|
53
|
+
uses: actions/upload-artifact@v4
|
|
54
|
+
with:
|
|
55
|
+
name: prod-db-backup-${{ github.sha }}
|
|
56
|
+
path: artifacts/*.sql.gz
|
|
57
|
+
retention-days: 90
|
|
58
|
+
if-no-files-found: error
|
|
59
|
+
|
|
60
|
+
- name: Summary
|
|
61
|
+
run: |
|
|
62
|
+
echo "### Backup complete" >> $GITHUB_STEP_SUMMARY
|
|
63
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
64
|
+
echo "Triggered by: \`${{ github.event_name }}\` on \`${{ github.ref_name }}\`" >> $GITHUB_STEP_SUMMARY
|
|
65
|
+
echo "Commit: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY
|
|
66
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
67
|
+
echo "Download via:" >> $GITHUB_STEP_SUMMARY
|
|
68
|
+
echo '```bash' >> $GITHUB_STEP_SUMMARY
|
|
69
|
+
echo "gh run download ${{ github.run_id }} -n prod-db-backup-${{ github.sha }}" >> $GITHUB_STEP_SUMMARY
|
|
70
|
+
echo '```' >> $GITHUB_STEP_SUMMARY
|
|
71
|
+
echo "" >> $GITHUB_STEP_SUMMARY
|
|
72
|
+
echo "Restore steps: see [docs/migrations-runbook.md](../blob/${{ github.sha }}/docs/migrations-runbook.md)." >> $GITHUB_STEP_SUMMARY
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
# Migrations runbook
|
|
2
|
+
|
|
3
|
+
Operational reference for the three-layer migration safety system. Read this before running a migration in prod, and again when something has gone wrong.
|
|
4
|
+
|
|
5
|
+
## The three layers (recap)
|
|
6
|
+
|
|
7
|
+
| Layer | What | Where defined |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| 1 — Process | Expand-and-contract: never combine "add + backfill + drop" in one migration. Two PRs, two deploys. | `CLAUDE.md` |
|
|
10
|
+
| 2 — Tooling | `scripts/migrate-with-backup.sh` — pg_dump before every `prisma migrate`, abort if dump fails. | `scripts/migrate-with-backup.sh` |
|
|
11
|
+
| 3 — In-migration SQL | Pre-flight count + abort-on-orphan + sidecar backup table before any column drop. | `CLAUDE.md` |
|
|
12
|
+
|
|
13
|
+
Recovery never depends on a single layer. PITR (if your provider has it) is a fourth, continuous layer underneath.
|
|
14
|
+
|
|
15
|
+
## Routine: running a migration
|
|
16
|
+
|
|
17
|
+
### Local (against `.env.testing` or `.env`)
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
# Always use these — they wrap pg_dump around prisma migrate.
|
|
21
|
+
npm run db:migrate # = prisma migrate dev (creates a new migration)
|
|
22
|
+
npm run db:migrate:deploy # = prisma migrate deploy (applies pending migrations)
|
|
23
|
+
npm run db:backup # dump only, no migration (manual snapshot)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Backups land in `.backups/pre-migrate-<mode>-<YYYYMMDD-HHMMSS>-<git-sha>.sql.gz`. The directory is gitignored. Prune old ones manually when convenient.
|
|
27
|
+
|
|
28
|
+
If your local `pg_dump` is older than the server, the wrapper auto-falls-back to a Docker container with `postgres:16`. Override the image if your server is on a different major:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
PG_DUMP_DOCKER_IMAGE=postgres:15 PG_DUMP_VIA_DOCKER=1 npm run db:backup
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
### Production (Vercel build)
|
|
35
|
+
|
|
36
|
+
The Vercel `build` script still runs `prisma migrate deploy` directly — the *prod backup* is decoupled from the Vercel build and runs on GitHub Actions instead (see `.github/workflows/backup-on-migration.yml`). Whenever a commit on `master` or `implementation` touches `prisma/migrations/**` or `prisma/schema.prisma`, the workflow runs the same wrapper in `backup-only` mode against `PROD_DATABASE_URL` and uploads the dump as a GHA artifact.
|
|
37
|
+
|
|
38
|
+
**One-time setup before the workflow can run**:
|
|
39
|
+
|
|
40
|
+
1. Repo → Settings → Secrets and variables → Actions → "New repository secret"
|
|
41
|
+
2. Name: `PROD_DATABASE_URL`. Value: full Postgres URL of prod (with credentials).
|
|
42
|
+
3. Confirm the workflow file is on `master`. The first migration commit afterward will trigger it.
|
|
43
|
+
|
|
44
|
+
## Recovery
|
|
45
|
+
|
|
46
|
+
### Find the right backup
|
|
47
|
+
|
|
48
|
+
**Local backups** — listed by timestamp + commit SHA:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
ls -lt .backups/
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Prod backups (GHA artifacts)**:
|
|
55
|
+
|
|
56
|
+
- Web UI: repo → **Actions** tab → "Backup prod DB before migration deploys" workflow → click the run for the relevant commit → scroll to "Artifacts" at the bottom → download the `.zip`.
|
|
57
|
+
- CLI:
|
|
58
|
+
```bash
|
|
59
|
+
gh run list --workflow=backup-on-migration.yml --limit 10
|
|
60
|
+
gh run download <run-id> -n prod-db-backup-<commit-sha>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
GHA artifacts are retained for 90 days by default (configurable in the workflow file).
|
|
64
|
+
|
|
65
|
+
### Restore commands
|
|
66
|
+
|
|
67
|
+
The dump format is identical regardless of where it came from (local or GHA), so the restore commands work for both. Decompress with `gunzip -c` (portable; macOS `zcat` does NOT decompress `.gz`).
|
|
68
|
+
|
|
69
|
+
**1. Inspect a dump without restoring:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
gunzip -c .backups/pre-migrate-deploy-<ts>-<sha>.sql.gz | head -50
|
|
73
|
+
gunzip -c .backups/pre-migrate-deploy-<ts>-<sha>.sql.gz | grep -E '^(CREATE TABLE|INSERT INTO "Project")' | head
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**2. Restore to a fresh scratch database (for forensics, dry-run, or recovering a specific row):**
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Create a scratch DB (psql must point at a server you control; do NOT do this against prod)
|
|
80
|
+
createdb scratch_restore
|
|
81
|
+
# Or via psql: psql -c 'CREATE DATABASE scratch_restore' "$ADMIN_DB_URL"
|
|
82
|
+
|
|
83
|
+
gunzip -c .backups/pre-migrate-deploy-<ts>-<sha>.sql.gz \
|
|
84
|
+
| psql "postgresql://USER:PASS@HOST:PORT/scratch_restore"
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Now you have an exact copy of the pre-migration state. Inspect, copy specific rows back to prod, or run the migration against the scratch DB to verify what *would* happen.
|
|
88
|
+
|
|
89
|
+
**3. Full prod rollback (last resort — see provider section below first):**
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# DESTRUCTIVE — drops the existing schema and replaces it with the dumped contents.
|
|
93
|
+
# Only do this if PITR is unavailable AND you've decided a full rollback is the right call.
|
|
94
|
+
# The dump uses --no-owner --no-privileges, so Postgres roles are NOT modified.
|
|
95
|
+
|
|
96
|
+
# 1. Take a current dump first (in case rollback itself goes wrong)
|
|
97
|
+
DATABASE_URL="$PROD_DATABASE_URL" npm run db:backup
|
|
98
|
+
|
|
99
|
+
# 2. Drop and recreate public schema
|
|
100
|
+
psql "$PROD_DATABASE_URL" -c 'DROP SCHEMA public CASCADE; CREATE SCHEMA public;'
|
|
101
|
+
|
|
102
|
+
# 3. Restore from the pre-migration dump
|
|
103
|
+
gunzip -c .backups/pre-migrate-deploy-<ts>-<sha>.sql.gz | psql "$PROD_DATABASE_URL"
|
|
104
|
+
|
|
105
|
+
# 4. Re-run prisma migrate so the migrations table reflects current state
|
|
106
|
+
DATABASE_URL="$PROD_DATABASE_URL" npx prisma migrate resolve --applied <last-good-migration>
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Provider-specific recovery (preferred over manual restore when available)
|
|
110
|
+
|
|
111
|
+
| Provider | Recovery feature | Notes |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| Neon | Branch from PITR | Console → Branches → "Create branch from a previous state" → pick a timestamp before the bad migration. Update `DATABASE_URL` to the new branch. Free tier: 7-day retention. |
|
|
114
|
+
| Vercel Postgres | Same as Neon (it's Neon) | Use the Vercel dashboard or Neon console. |
|
|
115
|
+
| Supabase | Daily snapshots (paid tiers) | Dashboard → Database → Backups. |
|
|
116
|
+
| RDS / Aurora | Automated snapshots + PITR | AWS console. PITR up to backup retention period. |
|
|
117
|
+
| Self-hosted | Whatever you set up | Hopefully `pg_basebackup` + WAL archiving. |
|
|
118
|
+
|
|
119
|
+
**Rule of thumb**: provider PITR > GHA artifact > local `.backups/`. Try them in that order — PITR is closest to "the exact moment before things broke," GHA artifacts are the moment before deploy, local backups are whoever ran the last migration on their laptop.
|
|
120
|
+
|
|
121
|
+
## Dry-running a migration before merging
|
|
122
|
+
|
|
123
|
+
Before merging a destructive migration PR, restore a fresh GHA artifact (or a `pg_dump` you took manually against prod) into a scratch DB and run the migration there. Check row counts before/after. If the wrapper aborts on orphan check, the migration is broken — fix the SQL.
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
# Pull most recent prod backup
|
|
127
|
+
gh run download $(gh run list --workflow=backup-on-migration.yml --limit 1 --json databaseId -q '.[0].databaseId') \
|
|
128
|
+
-n prod-db-backup-<sha> -D /tmp/prod-snapshot
|
|
129
|
+
|
|
130
|
+
# Spin up a scratch DB and restore
|
|
131
|
+
createdb migration_dryrun
|
|
132
|
+
gunzip -c /tmp/prod-snapshot/*.sql.gz | psql "postgresql://localhost/migration_dryrun"
|
|
133
|
+
|
|
134
|
+
# Apply the pending migration
|
|
135
|
+
DATABASE_URL="postgresql://localhost/migration_dryrun" \
|
|
136
|
+
bash scripts/migrate-with-backup.sh deploy
|
|
137
|
+
|
|
138
|
+
# Spot-check: did the rows you expected get backfilled?
|
|
139
|
+
psql "postgresql://localhost/migration_dryrun" -c 'SELECT count(*) FROM "Project" WHERE ...;'
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
If the dry-run looks right, merge. If it doesn't, fix the migration and try again.
|
|
143
|
+
|
|
144
|
+
## Security
|
|
145
|
+
|
|
146
|
+
**Treat dump files like prod credentials.** They contain:
|
|
147
|
+
|
|
148
|
+
- Hashed passwords (still attackable offline)
|
|
149
|
+
- OAuth tokens stored in `Integration.metadata` — these are live credentials for Vercel, GitHub, Neon, etc. Anyone with the dump can impersonate the integration.
|
|
150
|
+
- User PII (emails, names, anything stored in user-facing tables)
|
|
151
|
+
|
|
152
|
+
**Therefore:**
|
|
153
|
+
|
|
154
|
+
- `.backups/` is gitignored and must stay that way. Never commit a `.sql.gz` from this directory.
|
|
155
|
+
- GHA artifacts inherit the repo's access — only collaborators on the repo can download them. If you make the repo public or add an external collaborator, they get historical artifacts too. Audit before changing access.
|
|
156
|
+
- When sharing a dump for debugging, scrub the sensitive tables first (`Integration`, `Account`, `Session`, anything with tokens). A quick scrub:
|
|
157
|
+
```bash
|
|
158
|
+
gunzip -c backup.sql.gz | grep -v '^COPY public."Integration"' | gzip > backup-scrubbed.sql.gz
|
|
159
|
+
```
|
|
160
|
+
(This is a blunt instrument — it drops the entire `Integration` COPY block. Inspect before sharing.)
|
|
161
|
+
- Rotate any tokens that may have been exposed if a dump leaks. Vercel/GitHub/Neon integration tokens can all be revoked from their respective dashboards.
|
|
162
|
+
|
|
163
|
+
## Adding support for a new DB engine
|
|
164
|
+
|
|
165
|
+
Today the wrapper supports Postgres only. To add MySQL/MongoDB/etc.:
|
|
166
|
+
|
|
167
|
+
1. Add a case branch in `scripts/migrate-with-backup.sh` matching the URL scheme (`mysql://`, `mongodb://`, etc.).
|
|
168
|
+
2. Use the appropriate dump tool (`mysqldump`, `mongodump`).
|
|
169
|
+
3. Update the sanity check to recognize the new dump format.
|
|
170
|
+
4. Update this runbook with restore commands for the new engine.
|
|
171
|
+
|
|
172
|
+
The orchestration logic (dump → validate → migrate, abort on dump failure) stays identical.
|