@launchsecure/launch-kit 0.0.27 → 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/server/beacon-monitor-entry.js +353 -0
- package/dist/server/cli.js +50 -2
- package/dist/server/council-entry.js +0 -0
- package/dist/server/course-entry.js +246 -0
- package/dist/server/fb-wizard.js +0 -0
- package/dist/server/init-entry.js +394 -64
- package/dist/server/orbit-entry.js +187 -24
- package/package.json +24 -23
- 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/scripts/migrate-with-backup.sh +0 -0
- package/scaffolds/recall-hook/scripts/ensure-recall.sh +69 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Wire @launchsecure/launch-kit/beacon into this app — mounts the <launch-kit-beacon> Web Component in the root layout and scaffolds /api/feedback forwarding to LaunchSecure. Detects the framework, asks scope/endpoint/trigger decisions, then writes a real PR-shaped change.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Activate launch-kit-beacon
|
|
6
|
+
|
|
7
|
+
Integrate the in-app feedback widget into the current project. Beacon is a vanilla Web Component shipped via the `@launchsecure/launch-kit/beacon` subpath export. It captures a written description, severity (bug/idea/UX/a11y), a viewport screenshot with auto-numbered element pins, and runtime errors (`window.error` + `unhandledrejection`). Reports POST to a feedback endpoint that forwards into LaunchSecure as feedback comments in the Comm Hub.
|
|
8
|
+
|
|
9
|
+
This command does the integration as a normal dev cycle — read the layout, propose the diff, install deps, verify in the browser. It is NOT a one-shot script.
|
|
10
|
+
|
|
11
|
+
## Preflight
|
|
12
|
+
|
|
13
|
+
1. Confirm `.launch-secure.cred.config` exists at the repo root. If missing, stop and tell the user to run `npx launch-kit init` first — without the cred file the scaffolded `/api/feedback` route has no upstream credentials.
|
|
14
|
+
2. Read `package.json` to detect framework:
|
|
15
|
+
- **Next.js App Router** — `next` in deps AND `app/` or `src/app/` directory present.
|
|
16
|
+
- **Next.js Pages Router** — `next` in deps AND `pages/` directory (no `app/`).
|
|
17
|
+
- **Vite + React** — `vite` + `react` in deps; no server route available (Vite is client-only — feedback POSTs will need a user-supplied endpoint).
|
|
18
|
+
- **Other** — Astro, SvelteKit, Nuxt, plain HTML, Express, etc. Print the integration snippet and stop; the user wires it themselves.
|
|
19
|
+
3. Grep the source for `launch-kit-beacon` to check if beacon is already mounted. If found, ask the user whether to update the existing mount or abort.
|
|
20
|
+
4. Use the `launch-chart` MCP (`detect_project_stack`, `read_graph` with `type: "page"`) to confirm the root layout file path before editing.
|
|
21
|
+
|
|
22
|
+
## Decisions
|
|
23
|
+
|
|
24
|
+
Ask the user three questions before touching files:
|
|
25
|
+
|
|
26
|
+
1. **Mount scope**
|
|
27
|
+
- (a) Whole app — mount in the root layout, shown on every route
|
|
28
|
+
- (b) Auth-gated only — mount in an authenticated layout group (e.g. `(authenticated)/layout.tsx`)
|
|
29
|
+
- (c) Specific route group — user picks the layout file
|
|
30
|
+
|
|
31
|
+
2. **Feedback endpoint**
|
|
32
|
+
- (a) Scaffold `/api/feedback` forwarding to LaunchSecure (recommended). Reads `.launch-secure.cred.config` server-side, POSTs to `<serverUrl>/api/feedback` with the PAT in the `Authorization` header. Secrets stay server-side.
|
|
33
|
+
- (b) Skip — user will wire their own endpoint and set `endpoint=` attribute manually.
|
|
34
|
+
|
|
35
|
+
3. **Trigger**
|
|
36
|
+
- (a) Default floating button, position `bottom-right`
|
|
37
|
+
- (b) User provides a custom trigger via `slot="trigger"`; widget renders no default button
|
|
38
|
+
|
|
39
|
+
Echo the chosen answers back before writing.
|
|
40
|
+
|
|
41
|
+
## Implementation — Next.js App Router (v1 target)
|
|
42
|
+
|
|
43
|
+
### 1. Add dependency
|
|
44
|
+
|
|
45
|
+
Check if `@launchsecure/launch-kit` is already in `dependencies` in `package.json`. If not, add it (pinned to a caret range of the current major). Then run install with the detected package manager (`pnpm install` / `npm install` / `yarn install` / `bun install`). Detect the PM from `packageManager` field first, then lockfile presence (pnpm-lock.yaml > yarn.lock > bun.lock > package-lock.json).
|
|
46
|
+
|
|
47
|
+
### 2. Mount the widget
|
|
48
|
+
|
|
49
|
+
Web Components cannot SSR. The beacon module calls `customElements.define` at import time, which throws in a Node SSR environment. Mount via a small Client Component, not directly in the Server Component layout.
|
|
50
|
+
|
|
51
|
+
Create `src/app/_components/BeaconMount.tsx` (or `app/_components/BeaconMount.tsx` if the project uses `app/` at the repo root):
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
'use client';
|
|
55
|
+
|
|
56
|
+
import { useEffect } from 'react';
|
|
57
|
+
|
|
58
|
+
export function BeaconMount() {
|
|
59
|
+
useEffect(() => {
|
|
60
|
+
void import('@launchsecure/launch-kit/beacon');
|
|
61
|
+
}, []);
|
|
62
|
+
return (
|
|
63
|
+
<launch-kit-beacon
|
|
64
|
+
endpoint="/api/feedback"
|
|
65
|
+
position="bottom-right"
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Then read the target layout file (root layout for scope (a), authenticated layout for (b), or user-specified layout for (c)) and add the mount near the end of `<body>`:
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import { BeaconMount } from '@/app/_components/BeaconMount';
|
|
75
|
+
// ... inside the layout's return, just before </body>:
|
|
76
|
+
<BeaconMount />
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
If the user picked trigger option (b) (custom trigger via slot), set `position="hidden"` on the element and pass children through:
|
|
80
|
+
|
|
81
|
+
```tsx
|
|
82
|
+
<launch-kit-beacon endpoint="/api/feedback" position="hidden">
|
|
83
|
+
<button slot="trigger">Send feedback</button>
|
|
84
|
+
</launch-kit-beacon>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### 3. Add TypeScript declaration
|
|
88
|
+
|
|
89
|
+
Create `src/types/launch-kit-beacon.d.ts` (or `types/launch-kit-beacon.d.ts` at repo root if the project has no `src/`):
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
93
|
+
|
|
94
|
+
declare global {
|
|
95
|
+
namespace JSX {
|
|
96
|
+
interface IntrinsicElements {
|
|
97
|
+
'launch-kit-beacon': DetailedHTMLProps<
|
|
98
|
+
HTMLAttributes<HTMLElement> & {
|
|
99
|
+
endpoint?: string;
|
|
100
|
+
position?: 'bottom-right' | 'bottom-left' | 'hidden';
|
|
101
|
+
theme?: 'auto' | 'light' | 'dark';
|
|
102
|
+
severities?: string;
|
|
103
|
+
},
|
|
104
|
+
HTMLElement
|
|
105
|
+
>;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export {};
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Confirm `tsconfig.json` includes the types directory (most Next.js setups already cover `src/**/*.d.ts` via the default `"include": ["**/*.ts", "**/*.tsx"]`). If not, add the file's path to `include`.
|
|
114
|
+
|
|
115
|
+
### 4. Scaffold /api/feedback (if user chose endpoint option (a))
|
|
116
|
+
|
|
117
|
+
Create `src/app/api/feedback/route.ts` (or `app/api/feedback/route.ts`):
|
|
118
|
+
|
|
119
|
+
```ts
|
|
120
|
+
import { readFileSync } from 'node:fs';
|
|
121
|
+
import { join } from 'node:path';
|
|
122
|
+
|
|
123
|
+
import type { NextRequest } from 'next/server';
|
|
124
|
+
|
|
125
|
+
interface Profile {
|
|
126
|
+
pat: string;
|
|
127
|
+
orgSlug: string;
|
|
128
|
+
projectSlug: string;
|
|
129
|
+
serverUrl: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface CredConfig extends Partial<Profile> {
|
|
133
|
+
active?: string;
|
|
134
|
+
profiles?: Record<string, Profile>;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function readCred(): Profile {
|
|
138
|
+
// Resolved relative to the working directory of the Next.js server, which
|
|
139
|
+
// is the repo root in both `next dev` and `next start`. For production
|
|
140
|
+
// deploys (Vercel, Docker, etc.) where the cred file is not present,
|
|
141
|
+
// switch to env vars: LS_PAT, LS_ORG_SLUG, LS_PROJECT_SLUG, LS_SERVER_URL.
|
|
142
|
+
//
|
|
143
|
+
// Handles both shapes: nested multi-profile (written by `launch-course`)
|
|
144
|
+
// and legacy flat (written by older `launch-kit init` runs).
|
|
145
|
+
const p = join(process.cwd(), '.launch-secure.cred.config');
|
|
146
|
+
const raw = JSON.parse(readFileSync(p, 'utf-8')) as CredConfig;
|
|
147
|
+
const block = raw.profiles && raw.active ? raw.profiles[raw.active] : raw;
|
|
148
|
+
if (!block?.pat || !block.orgSlug || !block.projectSlug || !block.serverUrl) {
|
|
149
|
+
throw new Error('.launch-secure.cred.config is missing required fields');
|
|
150
|
+
}
|
|
151
|
+
return { pat: block.pat, orgSlug: block.orgSlug, projectSlug: block.projectSlug, serverUrl: block.serverUrl };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export async function POST(req: NextRequest) {
|
|
155
|
+
const cred = readCred();
|
|
156
|
+
const body = await req.text();
|
|
157
|
+
const upstream = await fetch(`${cred.serverUrl}/api/feedback`, {
|
|
158
|
+
method: 'POST',
|
|
159
|
+
headers: {
|
|
160
|
+
'Content-Type': 'application/json',
|
|
161
|
+
Authorization: `Bearer ${cred.pat}`,
|
|
162
|
+
'X-Org-Slug': cred.orgSlug,
|
|
163
|
+
'X-Project-Slug': cred.projectSlug,
|
|
164
|
+
},
|
|
165
|
+
body,
|
|
166
|
+
});
|
|
167
|
+
return new Response(upstream.body, {
|
|
168
|
+
status: upstream.status,
|
|
169
|
+
headers: { 'Content-Type': upstream.headers.get('Content-Type') ?? 'application/json' },
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Tell the user explicitly: this works for local dev. For production, replace `readCred()` with `process.env.LS_PAT` / `LS_ORG_SLUG` / `LS_PROJECT_SLUG` / `LS_SERVER_URL` and set those env vars in their deployment platform.
|
|
175
|
+
|
|
176
|
+
### 5. Verify
|
|
177
|
+
|
|
178
|
+
After all edits:
|
|
179
|
+
1. Run install with the detected PM.
|
|
180
|
+
2. Run `pnpm dev` (or detected dev command from `package.json` scripts).
|
|
181
|
+
3. Open the app in the browser. Confirm the floating beacon button is visible bottom-right (or that the custom slot trigger renders, for option (b)).
|
|
182
|
+
4. Click it, fill in a description, pick severity, capture a screenshot, submit.
|
|
183
|
+
5. Confirm via the `launch-secure` MCP: call `communication_read` and look for a new feedback comment landing in the project's Comm Hub.
|
|
184
|
+
6. Report the verification result to the user (which steps passed, anything that didn't).
|
|
185
|
+
|
|
186
|
+
## Implementation — Next.js Pages Router
|
|
187
|
+
|
|
188
|
+
Same as App Router but adjust paths:
|
|
189
|
+
- Mount in `pages/_app.tsx` instead of `app/layout.tsx`. `_app.tsx` is already a Client Component, so the dynamic `import` workaround in step 2 is unnecessary — import `@launchsecure/launch-kit/beacon` at the top of the file directly.
|
|
190
|
+
- Feedback endpoint becomes `pages/api/feedback.ts` with a default-exported handler matching the Pages API signature (`req: NextApiRequest, res: NextApiResponse`).
|
|
191
|
+
- TypeScript declaration is identical.
|
|
192
|
+
|
|
193
|
+
## Implementation — Vite + React
|
|
194
|
+
|
|
195
|
+
- Mount: add `import '@launchsecure/launch-kit/beacon';` to `src/main.tsx` (or whatever entry the Vite config points at), and add `<launch-kit-beacon endpoint="...">` inside the root `<App>` render. No SSR concerns — Vite is client-only.
|
|
196
|
+
- No server route — Vite does not provide one. Print the beacon snippet and tell the user they need either (a) to stand up their own backend with a forwarding handler matching the Next.js scaffold, or (b) to wait until LS exposes a public per-project ingest URL.
|
|
197
|
+
- TypeScript declaration is identical.
|
|
198
|
+
|
|
199
|
+
## Implementation — other frameworks
|
|
200
|
+
|
|
201
|
+
For Astro, SvelteKit, Nuxt, Express, plain HTML, etc.: do NOT attempt to edit application source automatically. Print the integration snippet and the API forwarding handler skeleton (translated to Node `http`/Express), and tell the user the two changes they need to make in their stack. Frameworks vary too much to mechanize this correctly.
|
|
202
|
+
|
|
203
|
+
## Idempotency
|
|
204
|
+
|
|
205
|
+
Re-running `/ls:activate-beacon`:
|
|
206
|
+
- If `BeaconMount.tsx` exists, leave it alone unless the user explicitly asks to regenerate.
|
|
207
|
+
- If `<launch-kit-beacon>` is already mounted in the layout, do NOT add a duplicate. Offer to update attributes (endpoint, position) or migrate trigger mode.
|
|
208
|
+
- If `app/api/feedback/route.ts` exists, do NOT overwrite. Diff against the scaffold template and ask whether to merge.
|
|
209
|
+
- If `@launchsecure/launch-kit` is already a dependency, skip the install step (but still run install if other files changed).
|
|
210
|
+
|
|
211
|
+
## Notes for the assistant
|
|
212
|
+
|
|
213
|
+
- Use the `launch-chart` MCP for file discovery instead of grep/glob (per project CLAUDE.md). `read_graph` with `type: "page"` finds layout files; `grep_nodes` with a `launch-kit-beacon` pattern finds existing mounts.
|
|
214
|
+
- Use the `launch-secure` MCP `communication_read` to verify a test feedback landed in the Comm Hub after the user submits.
|
|
215
|
+
- Show the diff before applying edits. The user reviews and approves like any PR.
|
|
216
|
+
- This is the user's application code. Default to the smallest possible edit — do not "improve" surrounding code, restyle the layout, or refactor unrelated files.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show the array of launch-beacon monitor sessions in `.launchsecure/` — which is most recent, how many events each has, last event time, suspected liveness. Use to confirm a session is being recorded, find an old session to inspect, or audit disk usage. Read-only.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /ls:beacon-array
|
|
6
|
+
|
|
7
|
+
Liveness + inventory across every `launch-beacon monitor` session this repo has recorded — one row per beacon in the array.
|
|
8
|
+
|
|
9
|
+
`$ARGUMENTS` may be `full` for an expanded report. Empty → terse one-line-per-session summary.
|
|
10
|
+
|
|
11
|
+
## Preflight
|
|
12
|
+
|
|
13
|
+
List the NDJSON files. If none, say so plainly:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
ls -t .launchsecure/beacon-*.ndjson 2>/dev/null || { echo "No beacon sessions found in .launchsecure/. Start one with: npx launch-beacon monitor"; exit 0; }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
If the listing is empty (the command above succeeded but produced no output because `2>/dev/null` swallowed the error and no files matched), check explicitly:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
SESSIONS=$(ls -t .launchsecure/beacon-*.ndjson 2>/dev/null)
|
|
23
|
+
test -n "$SESSIONS" || { echo "No beacon sessions found in .launchsecure/. Start one with: npx launch-beacon monitor"; exit 0; }
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Per-session facts to collect
|
|
27
|
+
|
|
28
|
+
For each session file (newest first), gather:
|
|
29
|
+
- **token** — slice between `beacon-` and `.ndjson` in the filename
|
|
30
|
+
- **events** — `wc -l < <file>`
|
|
31
|
+
- **last_ts** — parse the last JSON line's `.ts` field (epoch ms). Use a one-liner like:
|
|
32
|
+
```bash
|
|
33
|
+
tail -n 1 "$F" | sed -n 's/.*"ts":\([0-9]*\).*/\1/p'
|
|
34
|
+
```
|
|
35
|
+
- **last_kind** — same trick on `.kind` from the last line
|
|
36
|
+
- **mtime** — `stat -f "%m" "$F"` on macOS or `stat -c "%Y" "$F"` on Linux. Use whichever your shell supports; fall back to `ls -lt` parse if neither.
|
|
37
|
+
- **size** — file size in bytes (`stat` again; or `wc -c < "$F"`)
|
|
38
|
+
|
|
39
|
+
Use the mtime to compute **age** ("just now", "2m ago", "1h ago"). Do the arithmetic yourself (current epoch minus mtime); don't shell out for time formatting.
|
|
40
|
+
|
|
41
|
+
## Liveness heuristic
|
|
42
|
+
|
|
43
|
+
Mark a session as **active** if its mtime is within the last 5 seconds — that's the maximum interval the receiver flushes batches. Otherwise **idle**. Sessions older than 30 minutes are **stale** (the receiver enforces a 30-min cap, so anything older is from a previous monitor run).
|
|
44
|
+
|
|
45
|
+
## Default output (no arguments)
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
.launchsecure/
|
|
49
|
+
● 8f3c2a91 247 events click (just now) ACTIVE
|
|
50
|
+
a1b2c3d4 89 events error (12m ago) idle
|
|
51
|
+
2557799f 1,247 events route (2h ago) stale
|
|
52
|
+
|
|
53
|
+
3 sessions, 1 active.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Rules:
|
|
57
|
+
- Glyph: `●` (filled) for active, blank for idle/stale.
|
|
58
|
+
- Columns: token (8 chars) — events (right-aligned) — last event "kind (age)" — status word.
|
|
59
|
+
- Summary line: total count + how many active.
|
|
60
|
+
- Plain text, monospace alignment.
|
|
61
|
+
|
|
62
|
+
## Full output (`/ls:beacon-array full`)
|
|
63
|
+
|
|
64
|
+
Same per-session block as default, but expand each into a block with extra fields:
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
● 8f3c2a91 — ACTIVE
|
|
68
|
+
file: .launchsecure/beacon-8f3c2a91.ndjson
|
|
69
|
+
size: 42.1 KB
|
|
70
|
+
events: 247
|
|
71
|
+
started: 2026-05-21T07:12:33Z (8m ago)
|
|
72
|
+
last event: 2026-05-21T07:20:51Z (just now)
|
|
73
|
+
last kind: click
|
|
74
|
+
kinds: click 142, fetch 71, route 12, error 3, dialog 9, probe 10
|
|
75
|
+
|
|
76
|
+
a1b2c3d4 — idle
|
|
77
|
+
file: .launchsecure/beacon-a1b2c3d4.ndjson
|
|
78
|
+
...
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
`kinds:` is a histogram from `grep -oE '"kind":"[a-z]+"' <file> | sort | uniq -c | sort -rn`. Format as `kind1 N1, kind2 N2, …` newest-first by count.
|
|
82
|
+
|
|
83
|
+
`started:` = first line's `.ts`; `last event:` = last line's `.ts`.
|
|
84
|
+
|
|
85
|
+
End with the same summary line as default.
|
|
86
|
+
|
|
87
|
+
## Constraints
|
|
88
|
+
|
|
89
|
+
- **Read-only.** No deletion, no rotation, no auto-cleanup.
|
|
90
|
+
- **Fast.** Default view should be sub-second even with many session files. Don't full-parse JSON — line counts + first/last line sed is enough.
|
|
91
|
+
- **Plain text.** No markdown tables, no fenced blocks in the actual output.
|
|
92
|
+
- **Don't suggest cleanup.** That's `/ls:beacon-clear`'s job. Stale sessions are informational, not an error.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Wipe launch-beacon monitor session NDJSON files. Default clears only the latest session (so you can start a clean repro); pass `all` to remove every `.launchsecure/beacon-*.ndjson`. Always shows what will be deleted and asks for confirmation. Destructive.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /ls:beacon-clear
|
|
6
|
+
|
|
7
|
+
Clean slate before a fresh repro. The receiver appends to the same NDJSON file across reconnects of the same session, so an existing file accumulates noise from earlier attempts — clearing first makes the new stream easier to reason about.
|
|
8
|
+
|
|
9
|
+
Parse `$ARGUMENTS`:
|
|
10
|
+
- empty → clear the most recent session file only
|
|
11
|
+
- `all` → clear every `.launchsecure/beacon-*.ndjson`
|
|
12
|
+
- a specific token or filename → clear that one file (must match a real path)
|
|
13
|
+
|
|
14
|
+
## Preflight
|
|
15
|
+
|
|
16
|
+
List candidate files. If none, say so and stop:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
SESSIONS=$(ls -t .launchsecure/beacon-*.ndjson 2>/dev/null)
|
|
20
|
+
test -n "$SESSIONS" || { echo "No beacon sessions found in .launchsecure/. Nothing to clear."; exit 0; }
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Decide the **target set** based on `$ARGUMENTS`:
|
|
24
|
+
- empty → first line of `$SESSIONS` (the newest)
|
|
25
|
+
- `all` → all lines of `$SESSIONS`
|
|
26
|
+
- otherwise → resolve to a single path (try `.launchsecure/beacon-<arg>.ndjson` first, then the literal arg). If it doesn't exist or isn't inside `.launchsecure/`, refuse with a clear message.
|
|
27
|
+
|
|
28
|
+
## Refusal rule
|
|
29
|
+
|
|
30
|
+
Refuse with a clear message if:
|
|
31
|
+
- the target set is empty
|
|
32
|
+
- any target path resolves outside `.launchsecure/` (defence against `..` injection from `$ARGUMENTS`)
|
|
33
|
+
- the active monitor session is being written *right now* (mtime within the last 5 seconds) — print a one-line warning and ask the user to stop the monitor first, e.g.:
|
|
34
|
+
```
|
|
35
|
+
⚠ .launchsecure/beacon-8f3c2a91.ndjson was written 2s ago — looks active.
|
|
36
|
+
Stop the receiver (Ctrl+C in the launch-beacon monitor terminal) and re-run /ls:beacon-clear.
|
|
37
|
+
```
|
|
38
|
+
The user can still force by passing the token explicitly as the argument — but never silently nuke an actively-written file.
|
|
39
|
+
|
|
40
|
+
## Confirmation
|
|
41
|
+
|
|
42
|
+
Print what's about to be deleted and ask before doing it.
|
|
43
|
+
|
|
44
|
+
```
|
|
45
|
+
About to delete 1 file:
|
|
46
|
+
.launchsecure/beacon-a1b2c3d4.ndjson 89 events, 12m ago
|
|
47
|
+
|
|
48
|
+
Confirm? (y/N)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
For `all`, list every file with its size + age. Don't truncate the list — the user should see all of it.
|
|
52
|
+
|
|
53
|
+
Wait for explicit `y`/`yes`. Anything else → abort with `Cancelled. No files were deleted.`
|
|
54
|
+
|
|
55
|
+
## Delete
|
|
56
|
+
|
|
57
|
+
`rm` each target. After deletion, print a one-line summary:
|
|
58
|
+
|
|
59
|
+
```
|
|
60
|
+
✓ deleted 1 file (89 events freed).
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Constraints
|
|
64
|
+
|
|
65
|
+
- **Destructive — always confirm.** Even if `$ARGUMENTS` is `all`, ask first.
|
|
66
|
+
- **Scope-locked to `.launchsecure/`.** Reject anything outside that directory, even if the user passes an absolute path. We never delete files we didn't write.
|
|
67
|
+
- **No undo.** NDJSON is local-only; we don't ship recall integration for it (recall is for source files). Be explicit in the confirmation message.
|
|
68
|
+
- **Don't stop the monitor server.** This command only clears files. The receiver keeps running and will reopen the same file on its next write — which is fine, the file just starts empty again.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show the most recent error from the active launch-beacon monitor session, plus the N events that preceded it (default 10). Answers "what was happening when it broke" without scrolling through the full stream. Read-only.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /ls:beacon-pulse
|
|
6
|
+
|
|
7
|
+
The "what happened just before this error" command — a single pulse, freezing the moment the beacon caught a failure. When a bug fires, the actual story is usually the chain of events leading up to it: the click that triggered a state change, the failed fetch that left auth in a bad state, the route change that mounted the wrong component.
|
|
8
|
+
|
|
9
|
+
Parse `$ARGUMENTS` as one optional integer — the count of preceding events to include. Default 10. Cap at 100.
|
|
10
|
+
|
|
11
|
+
## Preflight
|
|
12
|
+
|
|
13
|
+
Same as `/ls:beacon-scan` — find the latest NDJSON; if none, stop:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
LATEST=$(ls -t .launchsecure/beacon-*.ndjson 2>/dev/null | head -1)
|
|
17
|
+
test -n "$LATEST" || { echo "No beacon sessions found. Start one with: npx launch-beacon monitor"; exit 0; }
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Locate the most recent error
|
|
21
|
+
|
|
22
|
+
Errors are events with `"kind":"error"` or `"kind":"unhandledrejection"`. Find the line number of the LAST such line in the file:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
ERR_LINE=$(grep -nE '"kind":"(error|unhandledrejection)"' "$LATEST" | tail -1 | cut -d: -f1)
|
|
26
|
+
test -n "$ERR_LINE" || { echo "No errors in the current session. Use /ls:beacon-scan to browse all events."; exit 0; }
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Pull the window
|
|
30
|
+
|
|
31
|
+
`N` is the user-supplied count (default 10). Read the file lines from `max(1, ERR_LINE-N)` through `ERR_LINE`:
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
N="${1:-10}"
|
|
35
|
+
START=$(( ERR_LINE - N ))
|
|
36
|
+
[ "$START" -lt 1 ] && START=1
|
|
37
|
+
sed -n "${START},${ERR_LINE}p" "$LATEST"
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
That's your input. The error itself is the last line; everything before is context.
|
|
41
|
+
|
|
42
|
+
## Output
|
|
43
|
+
|
|
44
|
+
Render a **timeline** with the error visually separated at the bottom:
|
|
45
|
+
|
|
46
|
+
```
|
|
47
|
+
session: .launchsecure/beacon-<token>.ndjson
|
|
48
|
+
window: 10 events before error at line 247
|
|
49
|
+
|
|
50
|
+
12:34:51 click button.submit-btn
|
|
51
|
+
12:34:51 fetch POST 401 /api/sessions (120ms) FAILED
|
|
52
|
+
12:34:51 fetch GET 401 /api/me (45ms) FAILED
|
|
53
|
+
12:34:52 route /login → /dashboard (pushState)
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
╴╴╴╴ ERROR ╴╴╴╴
|
|
57
|
+
12:34:53 error Cannot read properties of undefined (reading 'orgSlug')
|
|
58
|
+
at apps/Console.tsx:42:18
|
|
59
|
+
stack: Console.render
|
|
60
|
+
React.renderWithHooks
|
|
61
|
+
React.beginWork
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Format rules:
|
|
65
|
+
- One line per event, same SUMMARY format as `/ls:beacon-scan`.
|
|
66
|
+
- The error block at the end gets the message + (truncated) stack frames if present.
|
|
67
|
+
- Separator above the error is the visual cue.
|
|
68
|
+
|
|
69
|
+
After the timeline, write **one short paragraph** of analysis: what does the chain *look* like? Common patterns:
|
|
70
|
+
- 401s → error referencing user/org → "auth expired or org context missing"
|
|
71
|
+
- click → no observable effect → click again → error → "first click handler crashed silently; second click landed on something else"
|
|
72
|
+
- route change → error → "component on the new route blew up during initial render"
|
|
73
|
+
|
|
74
|
+
Don't dive into a fix — name the suspected proximate cause, suggest one concrete next step (which file to read, which probe to add, which `/ls:beacon-scan <kind>` to drill into).
|
|
75
|
+
|
|
76
|
+
## Constraints
|
|
77
|
+
|
|
78
|
+
- **Read-only.**
|
|
79
|
+
- **Most recent error only.** If the user wants an earlier one, they can clear the session (`/ls:beacon-clear`) and reproduce, or grep manually.
|
|
80
|
+
- **Plain text.** Same monospace conventions as `/ls:beacon-scan`.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Scan recent events from the active launch-beacon monitor session. Defaults to last 50 events across all kinds; pass a kind (`error`, `click`, `fetch`, `route`, `dialog`, `probe`, etc.) to filter, and/or a numeric limit. Reads `.launchsecure/beacon-*.ndjson` — the file written by `launch-beacon monitor`. Read-only.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /ls:beacon-scan
|
|
6
|
+
|
|
7
|
+
Recent runtime events captured by a `launch-beacon monitor` session. Use this as the first step when investigating something that just happened in the browser — clicks, failed network calls, errors, route changes, probe() calls, dialog mount/unmount.
|
|
8
|
+
|
|
9
|
+
Parse `$ARGUMENTS` as up to two tokens (space-separated):
|
|
10
|
+
- A **kind filter**: one of `error`, `unhandledrejection`, `fetch`, `xhr`, `click`, `mousedown`, `route`, `dialog`, `probe`. Anything else is treated as a limit.
|
|
11
|
+
- A **limit**: integer. Default 50.
|
|
12
|
+
|
|
13
|
+
Examples:
|
|
14
|
+
- `/ls:beacon-scan` → last 50 events of any kind
|
|
15
|
+
- `/ls:beacon-scan error` → last 50 errors only
|
|
16
|
+
- `/ls:beacon-scan click 20` → last 20 click events
|
|
17
|
+
- `/ls:beacon-scan 100` → last 100 events of any kind
|
|
18
|
+
|
|
19
|
+
## Preflight
|
|
20
|
+
|
|
21
|
+
Find the most recent NDJSON file via Bash. If none exist, say so plainly and stop — there's nothing to scan.
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
LATEST=$(ls -t .launchsecure/beacon-*.ndjson 2>/dev/null | head -1)
|
|
25
|
+
test -n "$LATEST" || { echo "No beacon sessions found in .launchsecure/. Start one with: npx launch-beacon monitor"; exit 0; }
|
|
26
|
+
echo "session: $LATEST"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Scan
|
|
30
|
+
|
|
31
|
+
If no kind filter, `tail -n <limit> "$LATEST"`.
|
|
32
|
+
|
|
33
|
+
If a kind filter is set, `grep '"kind":"<kind>"' "$LATEST" | tail -n <limit>`. The events are NDJSON, one per line — `grep` over the literal `"kind":"X"` substring is safe because the `kind` field is always the first or near-first key serialised by the beacon client.
|
|
34
|
+
|
|
35
|
+
Capture the raw JSON lines as the input to your analysis.
|
|
36
|
+
|
|
37
|
+
## Output
|
|
38
|
+
|
|
39
|
+
Group events visually by **time** (most recent last — chronological order matches the user's intuition for "what happened"). For each event, render one line:
|
|
40
|
+
|
|
41
|
+
```
|
|
42
|
+
HH:MM:SS KIND SUMMARY
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Where SUMMARY is a one-liner pulled from the event body:
|
|
46
|
+
- **error / unhandledrejection** → `message` (truncate ≤ 80 chars)
|
|
47
|
+
- **fetch / xhr** → `METHOD status url (durationMs)` — flag `FAILED` if `failed:true`
|
|
48
|
+
- **click / mousedown** → `target.selector` and, when `hitMatchesTarget === false`, also append `(occluded by <hitTarget.selector>)` — that's exactly the diagnostic the user is here for
|
|
49
|
+
- **route** → `from → to (via)`
|
|
50
|
+
- **dialog** → `<action> <selector>` (e.g. `mount dialog#xyz` or `unmount section[role=dialog]`)
|
|
51
|
+
- **probe** → `<label>: <truncated JSON>`
|
|
52
|
+
|
|
53
|
+
After the timeline, if anything looks suspicious (clusters of failed network calls, a click followed by no observable effect, a `hitMatchesTarget:false` event, an unhandled rejection), call it out in **one short paragraph** at the end. Don't analyze every event — only surface the standouts.
|
|
54
|
+
|
|
55
|
+
If the buffer is empty after filtering, say so: `No events match that filter in <session>.`
|
|
56
|
+
|
|
57
|
+
## Constraints
|
|
58
|
+
|
|
59
|
+
- **Read-only.** Never delete, modify, or write to the NDJSON file. Wiping is `/ls:beacon-clear`.
|
|
60
|
+
- **Always use the latest session by default.** If the user wants a specific session, they'll pass it as a third token — accept any of `<token>`, `<filename>`, or absolute path, and resolve to a valid `.launchsecure/beacon-*.ndjson` path before scanning. Reject with a clear error if it doesn't exist.
|
|
61
|
+
- **Plain text output.** Monospace alignment beats markdown tables here. The user is reading this fast during a debug loop.
|
|
62
|
+
- **Don't speculate on root cause.** Surface anomalies; let the user direct the next query (often: `/ls:beacon-pulse` for context around the latest error).
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Show the health of launch-kit's daemon-style MCPs (today just launch-recall). Default output is a terse one-line summary per daemon; pass `full` for expanded details — PID, pidfile, last snapshot, debounce, shadow repo size, recent activity. Read-only; never mutates state.
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# /ls:show-mcp-status
|
|
6
|
+
|
|
7
|
+
Reports the liveness and recent activity of launch-kit's long-running MCP daemons. The recall watcher is the only daemon today; this command is structured so additional daemons can be added without changing its interface.
|
|
8
|
+
|
|
9
|
+
Read $ARGUMENTS to decide output verbosity:
|
|
10
|
+
- empty (`/ls:show-mcp-status`) → terse one-liner per daemon. Goal: fits in one or two visual lines.
|
|
11
|
+
- `full` (`/ls:show-mcp-status full`) → expanded report per daemon. Goal: enough detail to diagnose health problems.
|
|
12
|
+
|
|
13
|
+
## Preflight
|
|
14
|
+
|
|
15
|
+
1. Verify the launch-recall MCP is wired by checking whether `mcp__launch-recall__recall_status` (or `mcp__local-launch-recall__recall_status` for dev repos) is callable. If neither is available, say so plainly: "launch-recall MCP not wired in this project — nothing to report" and stop.
|
|
16
|
+
2. Pick whichever recall MCP is available. Prefer the project-level published one (`mcp__launch-recall__*`) unless only the local dev one is wired.
|
|
17
|
+
|
|
18
|
+
## Daemons
|
|
19
|
+
|
|
20
|
+
Today: **launch-recall** (the shadow-git file watcher).
|
|
21
|
+
|
|
22
|
+
Structure your output so adding more daemons later is a copy-paste — one section per daemon, same shape.
|
|
23
|
+
|
|
24
|
+
## Default output (no arguments)
|
|
25
|
+
|
|
26
|
+
Call `mcp__launch-recall__recall_status`. Format as ONE LINE per daemon, then a single summary line. Example:
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
recall ✓ alive pid 12456 last snap 2m ago
|
|
30
|
+
|
|
31
|
+
All daemons healthy.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Or if dead:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
recall ✗ dead pidfile missing/stale
|
|
38
|
+
|
|
39
|
+
1 daemon down. Run /ls:show-mcp-status full for details, or restart the watcher (kill any stale pid, then either start a new Claude Code session — the SessionStart hook respawns it — or run `node packages/cli/dist/server/recall-entry.js watch` from this repo).
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Rules for the default view:
|
|
43
|
+
- One line per daemon — name, glyph, status word, key metric.
|
|
44
|
+
- `✓` (green) for alive, `✗` (red) for dead.
|
|
45
|
+
- "X ago" for timestamps — relative time, easier to scan than ISO.
|
|
46
|
+
- Summary line on a fresh line at the end. If anything is wrong, include a one-sentence recovery hint.
|
|
47
|
+
- No JSON, no PID files paths, no debug info — that's for `full`.
|
|
48
|
+
|
|
49
|
+
## Full output (`/ls:show-mcp-status full`)
|
|
50
|
+
|
|
51
|
+
For each daemon, call BOTH `recall_status` AND `recall_report`. Combine into a per-daemon block:
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
recall — launch-recall watcher (shadow-git backup)
|
|
55
|
+
|
|
56
|
+
Status: ✓ alive
|
|
57
|
+
PID: 12456
|
|
58
|
+
Watch tree: /Users/prajyot/Documents/Work/AutomateWithUs/launchsecure-v2
|
|
59
|
+
Shadow repo: /Users/prajyot/Documents/Work/AutomateWithUs/launchsecure-v2/.recall/repo.git
|
|
60
|
+
|
|
61
|
+
Last snapshot: 2026-05-21T12:05:45+05:30 (2m ago)
|
|
62
|
+
Total snaps: 1,247
|
|
63
|
+
Shadow size: 1.4 MB
|
|
64
|
+
Debounce: 3000ms
|
|
65
|
+
Retention: keepLast 5000, maxAgeDays 30
|
|
66
|
+
|
|
67
|
+
Recent activity (last 5 snaps):
|
|
68
|
+
a1b2c3d 2m ago snap 2026-05-21T06:35:45Z
|
|
69
|
+
9f8e7d6 14m ago snap 2026-05-21T06:21:42Z
|
|
70
|
+
2557799 53m ago snap 2026-05-21T05:52:35Z
|
|
71
|
+
8349edb 17h ago snap 2026-05-20T13:36:39Z
|
|
72
|
+
e5a05cf 17h ago snap 2026-05-20T13:32:05Z
|
|
73
|
+
|
|
74
|
+
All daemons healthy.
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
If a daemon is dead, the block should still appear but with status `✗ dead` and as many fields as can be derived from the on-disk shadow repo + pidfile. Include a concrete recovery command at the end of the block (the same SessionStart restart path from the default view, plus the manual command for impatient users).
|
|
78
|
+
|
|
79
|
+
Rules for the full view:
|
|
80
|
+
- Two-column field labels — visually aligned, easier to skim.
|
|
81
|
+
- Times: ISO timestamp + relative ("2m ago") in parens.
|
|
82
|
+
- Sizes: human-readable (KB/MB), not bytes.
|
|
83
|
+
- Last 5 snapshots only — newer first.
|
|
84
|
+
- One blank line between daemon blocks (for when there are more than one).
|
|
85
|
+
- Summary line at the end, same as the default view.
|
|
86
|
+
|
|
87
|
+
## Health classification
|
|
88
|
+
|
|
89
|
+
Use these rules to decide alive vs dead vs degraded:
|
|
90
|
+
|
|
91
|
+
- **alive**: `recall_status.running === true` AND `lastSnapshotAt` is within the last 6 hours (heuristic — for an active repo, snaps happen every few minutes; 6h of silence suggests the watcher is wedged or no files have changed, both worth surfacing).
|
|
92
|
+
- **dead**: `recall_status.running === false` OR `recall_status` errors out.
|
|
93
|
+
- **degraded** (still print as alive but note it): `running === true` BUT `lastSnapshotAt` is older than 6h. Add a single inline note `(no activity in 6h — possibly idle or wedged)`.
|
|
94
|
+
|
|
95
|
+
Don't over-warn — if a repo has genuinely been idle (e.g. you opened it for the first time today after a week), a 6h+ gap is normal. The note is informational, not an error.
|
|
96
|
+
|
|
97
|
+
## Constraints
|
|
98
|
+
|
|
99
|
+
- **Read-only.** This command never mutates state, never restarts watchers, never modifies config. Recovery is a recommendation in the output, not an automatic action.
|
|
100
|
+
- **Fast.** Default view should be sub-second. The MCP tools are cheap; don't add scrubbing or heavy formatting.
|
|
101
|
+
- **Plain text.** No markdown headers, no fenced blocks in the actual output — Claude Code renders them but the human eye scans monospace plain text fastest.
|
|
102
|
+
- **Output what the user asked for.** If they ran the default, don't dump the full report "just in case." If they ran `full`, don't abbreviate.
|
|
103
|
+
|
|
104
|
+
## Notes for the assistant
|
|
105
|
+
|
|
106
|
+
- Use the wired `launch-recall` MCP tools — do not shell out to `node packages/cli/dist/server/recall-entry.js status` even though it works. Going through MCP makes this command portable across projects that have launch-kit init'd via npx vs dev-build.
|
|
107
|
+
- When listing recent snaps, use the `recentSnapshots` array from `recall_report`. It's already sorted newest-first; just truncate.
|
|
108
|
+
- For "X ago" formatting, do the math yourself. Don't fetch any time service.
|
|
109
|
+
- If you find yourself wanting to add features beyond status display (restart the watcher, prune snaps, etc.) — stop. Those belong in separate `/ls:*` commands. This one is a status pane.
|