feat(dashboard): scripts grouped by trigger family + lexicon targeting panel master
Frontend for the trigger-keyed scripts subsystem (commit a086830). The dashboard now exposes: - `/dashboard/settings/scripts` — grouped list of all scripts by trigger family (Record events, XRPC handlers, Label arrivals). The script's `id` IS its trigger string; the table makes that visible in monospace and links to the detail page. - `/dashboard/settings/scripts/new` — create form. The trigger id is composed via a `(kind, suffix)` picker (kind dropdown for the prefix family + free-text suffix for the NSID). The Lua body prefills with a `handle()` skeleton. The form accepts a `?id=<trigger>` URL param so the lexicon detail page can deep-link with a candidate id pre-filled. - `/dashboard/settings/scripts/[id]` — detail/edit. The id is the PK so it's locked here; rename = delete + recreate. The header shows the cascade hint for record events ("`record.create:<id>` fires only on this action; cascades to `record.index:<id>` if absent."). The lexicon detail page gets a new "Scripts targeting this lexicon" panel that lists the trigger ids relevant to the lexicon's type: - Record-type lexicons show the four `record.*` slots (`record.index` / `record.create` / `record.update` / `record.delete`) with Edit/Create links. - XRPC lexicons show the matching `xrpc.{query,procedure}` slot. Existing scripts link straight to the detail page; missing rows link to the New Script page pre-filled with the trigger id. Operators get a one-click path from a lexicon to the scripts that affect it. The legacy `index_hook` editor on the lexicon page is left in place for now — operators with existing data can still see and edit the column, even though the runtime no longer reads it. A follow-up commit can drop the editor once we're confident no one relies on it. New: `web/src/types/scripts.ts` (Script, UpsertScriptBody, PatchScriptBody, TriggerKind / TriggerFamily helpers, parseTriggerId, DEFAULT_SCRIPT_BODY). Sidebar gets a Scripts nav item under Integrations (`scripts:read`-gated). Signed-off-by: Chris Pardy <chris.pardy@gmail.com> Signed-off-by: Trezy <tre@trezy.com>