---
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.
---

# Activate launch-kit-beacon

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.

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.

## Preflight

1. Confirm `.launch-secure.cred.config` exists at the repo root. If missing, stop and tell the user to run `npx @launchsecure/launch-kit init` first — without the cred file the scaffolded `/api/feedback` route has no upstream credentials.
2. Read `package.json` to detect framework:
   - **Next.js App Router** — `next` in deps AND `app/` or `src/app/` directory present.
   - **Next.js Pages Router** — `next` in deps AND `pages/` directory (no `app/`).
   - **Vite + React** — `vite` + `react` in deps; no server route available (Vite is client-only — feedback POSTs will need a user-supplied endpoint).
   - **Other** — Astro, SvelteKit, Nuxt, plain HTML, Express, etc. Print the integration snippet and stop; the user wires it themselves.
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.
4. Use the `launch-chart` MCP (`detect_project_stack`, `read_graph` with `type: "page"`) to confirm the root layout file path before editing.

## Decisions

Ask the user three questions before touching files:

1. **Mount scope**
   - (a) Whole app — mount in the root layout, shown on every route
   - (b) Auth-gated only — mount in an authenticated layout group (e.g. `(authenticated)/layout.tsx`)
   - (c) Specific route group — user picks the layout file

2. **Feedback endpoint**
   - (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.
   - (b) Skip — user will wire their own endpoint and set `endpoint=` attribute manually.

3. **Trigger**
   - (a) Default floating button, position `bottom-right`
   - (b) User provides a custom trigger via `slot="trigger"`; widget renders no default button

Echo the chosen answers back before writing.

## Implementation — Next.js App Router (v1 target)

### 1. Add dependency

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).

### 2. Mount the widget

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.

Create `src/app/_components/BeaconMount.tsx` (or `app/_components/BeaconMount.tsx` if the project uses `app/` at the repo root):

```tsx
'use client';

import { useEffect } from 'react';

export function BeaconMount() {
  useEffect(() => {
    void import('@launchsecure/launch-kit/beacon');
  }, []);
  return (
    <launch-kit-beacon
      endpoint="/api/feedback"
      position="bottom-right"
    />
  );
}
```

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>`:

```tsx
import { BeaconMount } from '@/app/_components/BeaconMount';
// ... inside the layout's return, just before </body>:
<BeaconMount />
```

If the user picked trigger option (b) (custom trigger via slot), set `position="hidden"` on the element and pass children through:

```tsx
<launch-kit-beacon endpoint="/api/feedback" position="hidden">
  <button slot="trigger">Send feedback</button>
</launch-kit-beacon>
```

### 3. Add TypeScript declaration

Create `src/types/launch-kit-beacon.d.ts` (or `types/launch-kit-beacon.d.ts` at repo root if the project has no `src/`):

```ts
import type { DetailedHTMLProps, HTMLAttributes } from 'react';

declare global {
  namespace JSX {
    interface IntrinsicElements {
      'launch-kit-beacon': DetailedHTMLProps<
        HTMLAttributes<HTMLElement> & {
          endpoint?: string;
          position?: 'bottom-right' | 'bottom-left' | 'hidden';
          theme?: 'auto' | 'light' | 'dark';
          severities?: string;
        },
        HTMLElement
      >;
    }
  }
}

export {};
```

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`.

### 4. Scaffold /api/feedback (if user chose endpoint option (a))

Create `src/app/api/feedback/route.ts` (or `app/api/feedback/route.ts`):

```ts
import { readFileSync } from 'node:fs';
import { join } from 'node:path';

import type { NextRequest } from 'next/server';

interface Profile {
  pat: string;
  orgSlug: string;
  projectSlug: string;
  serverUrl: string;
}

interface CredConfig extends Partial<Profile> {
  active?: string;
  profiles?: Record<string, Profile>;
}

function readCred(): Profile {
  // Resolved relative to the working directory of the Next.js server, which
  // is the repo root in both `next dev` and `next start`. For production
  // deploys (Vercel, Docker, etc.) where the cred file is not present,
  // switch to env vars: LS_PAT, LS_ORG_SLUG, LS_PROJECT_SLUG, LS_SERVER_URL.
  //
  // Handles both shapes: nested multi-profile (written by `launch-course`)
  // and legacy flat (written by older `launch-kit init` runs).
  const p = join(process.cwd(), '.launch-secure.cred.config');
  const raw = JSON.parse(readFileSync(p, 'utf-8')) as CredConfig;
  const block = raw.profiles && raw.active ? raw.profiles[raw.active] : raw;
  if (!block?.pat || !block.orgSlug || !block.projectSlug || !block.serverUrl) {
    throw new Error('.launch-secure.cred.config is missing required fields');
  }
  return { pat: block.pat, orgSlug: block.orgSlug, projectSlug: block.projectSlug, serverUrl: block.serverUrl };
}

export async function POST(req: NextRequest) {
  const cred = readCred();
  const body = await req.text();
  const upstream = await fetch(`${cred.serverUrl}/api/feedback`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${cred.pat}`,
      'X-Org-Slug': cred.orgSlug,
      'X-Project-Slug': cred.projectSlug,
    },
    body,
  });
  return new Response(upstream.body, {
    status: upstream.status,
    headers: { 'Content-Type': upstream.headers.get('Content-Type') ?? 'application/json' },
  });
}
```

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.

### 5. Verify

After all edits:
1. Run install with the detected PM.
2. Run `pnpm dev` (or detected dev command from `package.json` scripts).
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)).
4. Click it, fill in a description, pick severity, capture a screenshot, submit.
5. Confirm via the `launch-secure` MCP: call `communication_read` and look for a new feedback comment landing in the project's Comm Hub.
6. Report the verification result to the user (which steps passed, anything that didn't).

## Implementation — Next.js Pages Router

Same as App Router but adjust paths:
- 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.
- Feedback endpoint becomes `pages/api/feedback.ts` with a default-exported handler matching the Pages API signature (`req: NextApiRequest, res: NextApiResponse`).
- TypeScript declaration is identical.

## Implementation — Vite + React

- 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.
- 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.
- TypeScript declaration is identical.

## Implementation — other frameworks

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.

## Idempotency

Re-running `/kit:activate-beacon`:
- If `BeaconMount.tsx` exists, leave it alone unless the user explicitly asks to regenerate.
- 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.
- If `app/api/feedback/route.ts` exists, do NOT overwrite. Diff against the scaffold template and ask whether to merge.
- If `@launchsecure/launch-kit` is already a dependency, skip the install step (but still run install if other files changed).

## Notes for the assistant

- 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.
- Use the `launch-secure` MCP `communication_read` to verify a test feedback landed in the Comm Hub after the user submits.
- Show the diff before applying edits. The user reviews and approves like any PR.
- 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.
