@ai-matrx/content-ir-react 0.15.1 → 0.15.2

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/CHANGELOG.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.2 — 2026-10-02
4
+
5
+ - While "Run again" asks, the tally stays on screen (only its own button goes
6
+ quiet) — it was swapped for a disabled Apply. No consumer action.
7
+
3
8
  ## 0.15.1 — 2026-10-02
4
9
 
5
10
  - The applied tally keeps its glyph beside its sentence: a long server
@@ -256,6 +256,7 @@ function ApplyDirectiveButton({
256
256
  readsLedger ? { status: "checking" } : { status: "idle" }
257
257
  );
258
258
  const [elapsed, setElapsed] = (0, import_react2.useState)(0);
259
+ const [askingAgain, setAskingAgain] = (0, import_react2.useState)(false);
259
260
  const startedAt = (0, import_react2.useRef)(null);
260
261
  const nounText = (0, import_content_ir2.nounLabel)(directive.noun, host.nouns);
261
262
  const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
@@ -320,7 +321,8 @@ function ApplyDirectiveButton({
320
321
  if (!confirm) return;
321
322
  const before = state;
322
323
  if (host.ask) {
323
- setState({ status: "asking" });
324
+ if (again) setAskingAgain(true);
325
+ else setState({ status: "asking" });
324
326
  let ok = false;
325
327
  try {
326
328
  ok = await host.ask({
@@ -330,12 +332,14 @@ function ApplyDirectiveButton({
330
332
  ...again ? { again: true } : {}
331
333
  });
332
334
  } catch (error) {
335
+ setAskingAgain(false);
333
336
  setState({
334
337
  status: "error",
335
338
  message: error instanceof Error && error.message ? error.message : "We could not ask you to confirm this, so nothing was done."
336
339
  });
337
340
  return;
338
341
  }
342
+ setAskingAgain(false);
339
343
  if (!ok) {
340
344
  setState(again ? before : { status: "idle" });
341
345
  return;
@@ -391,8 +395,9 @@ function ApplyDirectiveButton({
391
395
  "button",
392
396
  {
393
397
  type: "button",
398
+ disabled: askingAgain,
394
399
  onClick: () => void handleApply(!bad),
395
- className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
400
+ className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-50",
396
401
  "data-apply-action": bad ? "retry" : "run-again",
397
402
  children: [
398
403
  /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RotateCcwIcon, { className: "h-3 w-3" }),
@@ -1 +1 @@
1
- {"version":3,"sources":["../directives.ts","../directives/directive-host.tsx","../directives/registry.ts","../directives/ApplyDirectiveButton.tsx","../directives/item-changes.ts","../directives/icons.tsx","../directives/SideEffectDirectiveCard.tsx","../directives/DirectiveFallbackCard.tsx","../directives/DirectiveProvisionalCard.tsx","../directives/DirectiveRender.tsx"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/directives` — the Kind Directives render tier:\n * the host seams (`DirectiveHostProvider`), the renderer registry with THE\n * PREFIX TIER, the side-effect card, the fallback floor, the Apply control, and\n * `DirectiveRender` — THE renderer every UI draws a directive through. Client\n * entry (stamped \"use client\").\n */\nexport * from \"./directives/directive-host\";\nexport * from \"./directives/registry\";\nexport * from \"./directives/ApplyDirectiveButton\";\nexport * from \"./directives/SideEffectDirectiveCard\";\nexport * from \"./directives/DirectiveFallbackCard\";\nexport * from \"./directives/DirectiveProvisionalCard\";\nexport * from \"./directives/DirectiveRender\";\nexport * from \"./directives/item-changes\";\n","\"use client\";\n\n/**\n * THE DIRECTIVE HOST CONTRACT — what the directive tier refuses to decide.\n *\n * The package owns the DECISIONS (decode → renderer → card → floor, the\n * position law, never-null rendering) and the card itself. Four things stay\n * host property and enter through named seams:\n *\n * 1. APPLYING a side-effect directive — `POST /directives/confirm` as the\n * user, with the host's auth and base URL. Absent → the Apply control is\n * ABSENT (honest), never a dead button.\n * 2. OPENING an item to read it before approving — a window panel, a dialog,\n * a route. Absent → items are not clickable.\n * 3. COPY controls — host chrome (matrx-frontend's CopyButtons). Absent → none.\n * 4. The NOUN catalog + item-kind lookup — server-derived tables the host\n * mirrors (or reads from its kind catalog's `items` edges).\n * 5. ASKING (`ask`), NAMING a record (`renderRecord`), and READING the ledger\n * (`applyState`) — the consequence before the click, the doors, and the\n * state that survives a reload.\n *\n * A host that has adopted `ContentIrRenderProvider` passes `directives` on its\n * ContentIrHost; a host that has NOT (Workflow Studio, 2026-09-08) mounts\n * `DirectiveHostProvider` alone — the directive tier never requires the full\n * render host, because a chat bubble must be able to draw a directive card\n * identically everywhere, today.\n */\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type {\n DecodedDirective,\n DirectiveItemKindLookup,\n DirectiveNounCatalog,\n} from \"@ai-matrx/content-ir\";\n\nexport interface DirectiveApplyResult {\n applied: number;\n failed: number;\n /**\n * The server's own receipt sentence (\"Deleted task “Ship it”.\"), shown in\n * place of a bare count. Never composed client-side.\n */\n message?: string | null;\n /**\n * The records the apply created or changed, so the tally is a way IN to them\n * (no dead ends). Rendered through `renderRecord`; absent → the sentence alone.\n */\n records?: DirectiveRecordRef[];\n}\n\n/**\n * What the server's action ledger says about ONE block, read on mount so a\n * reloaded page never offers \"Apply\" for work that already ran (reviewer\n * defect 5, 2026-10-02).\n *\n * - `not_applied` — still to do (or partly done: the batch re-applies, and the\n * server replays the members it already holds). The card offers Apply.\n * - `in_flight` — another request is applying it right now. The card says it\n * is finishing and asks again shortly; it offers neither Apply nor a tally.\n * - `applied` — the ledger holds every item. The card shows the tally exactly\n * as a fresh apply would: the ledger's own sentence and the records, as doors.\n */\nexport interface DirectiveApplyState {\n state: \"not_applied\" | \"in_flight\" | \"applied\";\n /** The ledger row's sentence (\"Created task.\"), never composed client-side. */\n message?: string | null;\n /** The records the original apply wrote — the tally's doors. */\n records?: DirectiveRecordRef[];\n}\n\n/** One record a directive names: the noun it is, and its id. */\nexport interface DirectiveRecordRef {\n noun: string;\n id: string;\n}\n\nexport interface DirectiveRecordProps extends DirectiveRecordRef {\n /**\n * What to show until (or unless) the host resolves the live name —\n * \"Task 1a2b3c4d\". Never blank, never \"Item\".\n */\n fallback: string;\n /** Where it is drawn: an item row, the confirm dialog, or the applied tally. */\n context: \"row\" | \"dialog\" | \"applied\";\n /**\n * True when the record is (about to be) in the trash — the host may still\n * name it but should not promise it opens as a live record.\n */\n trashed?: boolean;\n}\n\n/** What the person is being asked to approve — everything the card knows. */\nexport interface DirectiveAskRequest {\n directive: DecodedDirective;\n /** The items, exactly as they will be sent. */\n items: Record<string, unknown>[];\n /** The noun's human label (\"Task\"), from the host's catalog when it has one. */\n nounLabel: string;\n /**\n * True for \"Run again\": the ledger already holds this block, and a yes runs\n * it a SECOND time (`force`) — another copy for a create, the same fields\n * written again for an update, another delete for a restored record. The\n * question must say so.\n */\n again?: boolean;\n}\n\n/**\n * The shell a card hands its host — the two keys, plus WHERE it sits.\n *\n * `conversationId` is the conversation the card renders in (a chat message),\n * absent in a person's own content (a note). It is the idempotency NAMESPACE:\n * a card in an agent's message must apply under the SAME key as that\n * proposal's Approve button, or the one action could run twice.\n */\nexport interface DirectiveShell {\n __kind: string;\n items: Record<string, unknown>[];\n conversationId?: string;\n /** \"Run again\": skip the ledger's dedup and apply a second time. */\n force?: boolean;\n}\n\nexport interface DirectiveOpenItemOptions {\n /** The item, `__kind`-stamped when the shape has an item kind. */\n item: Record<string, unknown>;\n /** The content-IR kind this item IS, or null when the shape has none. */\n itemKind: string | null;\n /** What the item is called — the same title the card shows. */\n title: string;\n /** \"Run Create agent definition · item 1 of 1\". */\n subtitle: string | null;\n directive: DecodedDirective;\n index: number;\n total: number;\n}\n\nexport interface DirectiveCopyProps {\n label: string;\n /** The value to copy — the whole shell or one item. */\n value: unknown;\n /** The item's kind, when copying an item. */\n kind?: string | null;\n size: \"icon\" | \"xs\";\n}\n\nexport interface DirectiveHost {\n /**\n * Apply a side-effect directive as the user (the server re-validates every\n * item against the registered model and runs the ONE handler; idempotent).\n * Reject with an Error whose message is safe to show.\n */\n confirm?: (shell: DirectiveShell) => Promise<DirectiveApplyResult>;\n /**\n * Ask the person BEFORE anything runs, naming the consequence (the records,\n * what changes). Resolve `true` to go ahead, `false` to leave the card as it\n * was. The Apply control stays idle while this is open — nothing reads as\n * \"applying\" until the person has said yes. Absent → `confirm` is called\n * directly (a host that asks inside `confirm` keeps working, but its card\n * will read \"Applying…\" while its dialog is up).\n */\n ask?: (request: DirectiveAskRequest) => Promise<boolean>;\n /**\n * Has this exact block already been applied? Read ONCE when the card mounts\n * (and again while the answer is `in_flight`), so the card survives a reload:\n * the server ledger, not component state, is what knows. The identity is the\n * server's (it hashes the validated items in the same namespace `confirm`\n * applies in), so a host asks — it never computes. Batch on the host side if\n * a page carries many cards. Reject with an Error when the ledger cannot be\n * read: the card reports it and offers Apply, which is safe because `confirm`\n * is idempotent. Absent → the card starts at Apply, as before.\n */\n applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;\n /**\n * Draw ONE existing record by its live name, as a way to open it. Used on\n * update/delete rows (the record that will change), in the host's own ask\n * dialog if it likes, and on the applied tally (what was written). Absent →\n * the fallback text, unlinked.\n */\n renderRecord?: (props: DirectiveRecordProps) => ReactNode;\n /** Open ONE item to read it properly before approving the write. */\n openItem?: (options: DirectiveOpenItemOptions) => void;\n /** Host copy controls. */\n renderCopy?: (props: DirectiveCopyProps) => ReactNode;\n /** The mirrored noun catalog (label / family / title column). */\n nouns?: DirectiveNounCatalog;\n /** slug → the kind ONE item is (THE DIRECTIVE⇄KIND SEAM), or null. */\n itemKind?: DirectiveItemKindLookup;\n /** Where a decode failure or an unhonourable shell is reported. Default: console.error. */\n reportError?: (message: string) => void;\n}\n\nconst DirectiveHostContext = createContext<DirectiveHost | null>(null);\n\n/** Where a directive renders — today, the conversation it sits in (if any). */\nexport interface DirectiveScope {\n conversationId?: string | null;\n}\n\nconst DirectiveScopeContext = createContext<DirectiveScope>({});\n\n/**\n * Tell every card below WHERE it renders. A host draws a chat message's\n * directives inside one of these (or passes `conversationId` to\n * `DirectiveRender`), so the card applies in that conversation's namespace —\n * the same key the agent's proposal approves under. A note mounts none.\n */\nexport function DirectiveScopeProvider({\n conversationId,\n children,\n}: DirectiveScope & { children: ReactNode }) {\n return (\n <DirectiveScopeContext.Provider value={{ conversationId: conversationId ?? null }}>\n {children}\n </DirectiveScopeContext.Provider>\n );\n}\n\nexport function useDirectiveScope(): DirectiveScope {\n return useContext(DirectiveScopeContext);\n}\n\nexport interface DirectiveHostProviderProps {\n host: DirectiveHost;\n children: ReactNode;\n}\n\nexport function DirectiveHostProvider({ host, children }: DirectiveHostProviderProps) {\n return <DirectiveHostContext.Provider value={host}>{children}</DirectiveHostContext.Provider>;\n}\n\nconst EMPTY_HOST: DirectiveHost = {};\n\n/**\n * The wired directive host. Unlike the render host this does NOT throw when\n * unwired: a directive still renders (named, itemised, copy-less, apply-less)\n * — degrading the chrome is honest, hiding the content is not.\n */\nexport function useDirectiveHost(): DirectiveHost {\n return useContext(DirectiveHostContext) ?? EMPTY_HOST;\n}\n","/**\n * Kind Directives — the renderer registry, and THE PREFIX TIER.\n *\n * A directive IS a kind instance, so the renderer for one is resolved from its\n * SLUG, in the same shape the kind component resolver uses:\n *\n * getDirectiveRenderer(directive)\n * → an exact-slug renderer (directive_v1_action_plan_tree)\n * → else the CLASS prefix rule (every directive_v1_reference_*)\n * → else null (DirectiveRender's own tier: the\n * side-effect card, then the floor)\n *\n * THE PREFIX RULE is Arman's routing-language ruling made real: registering\n * `reference` once gives EVERY enrolled noun a renderer for free; a custom\n * renderer for one slug overrides it; a brand-new server noun renders with\n * ZERO client edits. Hosts register their bespoke renderers (reference chips,\n * plan trees) here; the package supplies the side-effect card and the floor.\n */\n\nimport type { ComponentType } from \"react\";\nimport {\n type DecodedDirective,\n type DirectiveClass,\n buildDirectiveSlug,\n} from \"@ai-matrx/content-ir\";\n\nexport interface DirectiveRendererProps {\n /** The decoded two-key shell — slug, class, noun, items, position law. */\n directive: DecodedDirective;\n}\n\nexport type DirectiveRenderer = ComponentType<DirectiveRendererProps>;\n\n// REGISTRY ON A globalThis SLOT — never module-level Maps. With `splitting:\n// false` dual ESM/CJS output this module is duplicated into the root bundle and\n// the `./directives` bundle, and a host registering a renderer through one\n// graph must be visible to a card rendering through the other.\nconst REGISTRY_SLOT = Symbol.for(\"ai-matrx.content-ir-react.directive-renderers\");\ninterface Registry {\n bySlug: Map<string, DirectiveRenderer>;\n byClass: Map<DirectiveClass, DirectiveRenderer>;\n}\ntype RegistryHolder = typeof globalThis & { [REGISTRY_SLOT]?: Registry };\nconst registry: Registry = ((globalThis as RegistryHolder)[REGISTRY_SLOT] ??= {\n bySlug: new Map(),\n byClass: new Map(),\n});\n\n/**\n * Register a renderer for a whole CLASS (the prefix rule), or for one exact\n * `(class, noun)` pair, which wins. `noun` is passed as a noun, never a\n * hand-typed slug: the slug is BUILT by the grammar, so a registration whose\n * slug could not be parsed back is unconstructable rather than unreachable.\n */\nexport function registerDirectiveRenderer(\n directiveClass: DirectiveClass,\n renderer: DirectiveRenderer,\n noun?: string,\n): void {\n if (noun) registry.bySlug.set(buildDirectiveSlug(directiveClass, noun), renderer);\n else registry.byClass.set(directiveClass, renderer);\n}\n\n/** The renderer for a slug: exact → class prefix rule → null. */\nexport function getDirectiveRenderer(\n directive: Pick<DecodedDirective, \"slug\" | \"directiveClass\">,\n): DirectiveRenderer | null {\n return (\n registry.bySlug.get(directive.slug) ?? registry.byClass.get(directive.directiveClass) ?? null\n );\n}\n\n/** Tests only. */\nexport function resetDirectiveRenderers(): void {\n registry.bySlug.clear();\n registry.byClass.clear();\n}\n","\"use client\";\n\n/**\n * \"Apply\" for a side-effect Kind Directive that arrived as CONTENT.\n *\n * THE POSITION RULE, honoured exactly: a directive inside content NEVER\n * auto-executes — that is the guard against untrusted content mutating things.\n * But \"does not auto-execute\" was never \"is inert\": the user seeing it must be\n * able to say yes. This button IS that yes, through the host's `confirm` seam\n * (`POST /directives/confirm`, re-validated server-side, run as the user).\n *\n * No `confirm` seam → NO button. A control that cannot do its job is absent,\n * never dead. Only a side-effect class is applicable at all (`parsed.executes`).\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { nounLabel, type DecodedDirective } from \"@ai-matrx/content-ir\";\nimport {\n useDirectiveHost,\n useDirectiveScope,\n type DirectiveRecordRef,\n type DirectiveShell,\n} from \"./directive-host\";\nimport { recordFallbackName } from \"./item-changes\";\nimport { AlertIcon, CheckCircleIcon, LoaderIcon, PlayIcon, RotateCcwIcon } from \"./icons\";\n\ntype ApplyState =\n // Reading the server ledger on mount: has this block already run? Nothing\n // offers a write until it answers (reviewer defect 5, 2026-10-02).\n | { status: \"checking\" }\n // The ledger has a claim but no result: another request is applying it now.\n | { status: \"finishing\" }\n | { status: \"idle\" }\n // The host's `ask` dialog is up. NOTHING is applying yet, so nothing says so.\n | { status: \"asking\" }\n | { status: \"applying\" }\n | {\n status: \"applied\";\n applied: number;\n failed: number;\n message: string | null;\n records: DirectiveRecordRef[];\n }\n | { status: \"error\"; message: string };\n\n/** How often a card re-reads a block another request is mid-applying. */\nconst FINISH_POLL_MS = 2_000;\n/** ~1 minute (the server's own claim wait is 45 s), then Apply is offered — idempotent. */\nconst FINISH_POLLS_MAX = 30;\n\nexport interface ApplyDirectiveButtonProps {\n directive: DecodedDirective;\n label?: string;\n /** How many things this will write — shown during the wait so a long apply reads as work, not a frozen spinner. */\n itemCount?: number;\n onApplied?: () => void;\n}\n\nexport function ApplyDirectiveButton({\n directive,\n label = \"Apply\",\n itemCount,\n onApplied,\n}: ApplyDirectiveButtonProps) {\n const host = useDirectiveHost();\n const scope = useDirectiveScope();\n // WHERE the card sits is the namespace its apply keys in: a chat message's\n // conversation (the SAME key the agent proposal's Approve uses — never two\n // applies of one action), else the person's own content.\n const conversationId = scope.conversationId || undefined;\n const items = directive.items;\n // The ledger read runs only where an apply could: a side effect, a confirm\n // seam, something to write. Everything else starts (and stays) where it was.\n const readsLedger =\n !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;\n const [state, setState] = useState<ApplyState>(\n readsLedger ? { status: \"checking\" } : { status: \"idle\" },\n );\n const [elapsed, setElapsed] = useState(0);\n const startedAt = useRef<number | null>(null);\n const nounText = nounLabel(directive.noun, host.nouns);\n\n // THE CARD SURVIVES A RELOAD. Component state dies with the page; the\n // server's action ledger does not. Ask it once on mount — and every\n // FINISH_POLL_MS while another request is mid-apply — and render exactly\n // what a fresh apply would have left on screen.\n const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : \"\";\n const read = host.applyState;\n const report = host.reportError;\n useEffect(() => {\n if (!shellKey || !read) return;\n // Parsed back from the key so the effect depends on the shell's CONTENT,\n // never on the per-render identity of `directive.items`.\n const [slug, shellItems, inConversation] = JSON.parse(shellKey) as [\n string,\n Record<string, unknown>[],\n string | null,\n ];\n const shell: DirectiveShell = { __kind: slug, items: shellItems };\n if (inConversation) shell.conversationId = inConversation;\n let live = true;\n let polls = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const ask = () => {\n read(shell)\n .then((answer) => {\n if (!live) return;\n if (answer.state === \"applied\") {\n setState((prev) =>\n prev.status === \"checking\" || prev.status === \"finishing\"\n ? {\n status: \"applied\",\n applied: shellItems.length,\n failed: 0,\n message: answer.message?.trim() ? answer.message.trim() : null,\n records: answer.records ?? [],\n }\n : prev,\n );\n } else if (answer.state === \"in_flight\" && polls < FINISH_POLLS_MAX) {\n polls += 1;\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"finishing\" } : prev));\n timer = setTimeout(ask, FINISH_POLL_MS);\n } else {\n // Not applied — or still \"in flight\" after a minute, when Apply is\n // the honest offer: confirm is idempotent and replays the receipt.\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"idle\" } : prev));\n }\n })\n .catch((error: unknown) => {\n if (!live) return;\n const why = error instanceof Error && error.message ? error.message : String(error);\n (report ?? console.error)(\n `[kind-directives] Could not read whether ${slug} was already applied: ${why}`,\n );\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"idle\" } : prev));\n });\n };\n ask();\n return () => {\n live = false;\n if (timer) clearTimeout(timer);\n };\n }, [shellKey, read, report]);\n\n // An honest clock beats a fake progress bar.\n useEffect(() => {\n if (state.status !== \"applying\") return;\n startedAt.current = Date.now();\n const id = setInterval(\n () => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1000)),\n 1000,\n );\n return () => clearInterval(id);\n }, [state.status]);\n\n if (!directive.parsed.executes) return null;\n const confirm = host.confirm;\n if (!confirm) return null;\n\n /**\n * `again` = \"Run again\": the ledger already holds this block, so a plain\n * confirm would only replay its receipt. The person is asked in words that\n * say it runs a SECOND time, and a yes sends `force`.\n */\n async function handleApply(again = false) {\n if (!confirm) return;\n // A \"no\" to Run again leaves the tally exactly where it was.\n const before = state;\n // THE STATUS TELLS THE TRUTH (reviewer, 2026-09-30): the card used to read\n // \"Applying 1 item…\" while the confirm dialog was still asking. Ask first,\n // idle; only a yes moves the control to \"applying\".\n if (host.ask) {\n setState({ status: \"asking\" });\n let ok = false;\n try {\n ok = await host.ask({\n directive,\n items,\n nounLabel: nounText,\n ...(again ? { again: true } : {}),\n });\n } catch (error) {\n setState({\n status: \"error\",\n message:\n error instanceof Error && error.message\n ? error.message\n : \"We could not ask you to confirm this, so nothing was done.\",\n });\n return;\n }\n if (!ok) {\n // Declining is not an error: the card is exactly as it was.\n setState(again ? before : { status: \"idle\" });\n return;\n }\n }\n setElapsed(0);\n setState({ status: \"applying\" });\n try {\n const shell: DirectiveShell = { __kind: directive.slug, items };\n if (conversationId) shell.conversationId = conversationId;\n if (again) shell.force = true;\n const result = await confirm(shell);\n setState({\n status: \"applied\",\n applied: result.applied,\n failed: result.failed,\n message: result.message?.trim() ? result.message.trim() : null,\n records: result.records ?? [],\n });\n onApplied?.();\n } catch (error) {\n setState({\n status: \"error\",\n message:\n error instanceof Error && error.message\n ? error.message\n : \"That couldn't be applied just now. Please try again.\",\n });\n }\n }\n\n if (state.status === \"applied\") {\n const bad = state.failed > 0;\n const trashed = directive.directiveClass === \"delete\";\n const label = nounText;\n // THE TALLY IS A DOOR (no dead ends): the records the apply wrote, each by\n // name and each opening, beside the server's own sentence when it sent one.\n const records = host.renderRecord ? state.records : [];\n return (\n <span\n className={`flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 text-xs ${bad ? \"text-destructive\" : \"text-primary\"}`}\n data-apply-state=\"applied\"\n >\n {/* The glyph rides WITH the sentence: a long server sentence wraps\n beside it, never leaving the icon alone on a line (phone width). */}\n <span className=\"inline-flex min-w-0 items-start gap-1\">\n {bad ? (\n <AlertIcon className=\"mt-px h-3.5 w-3.5 shrink-0\" />\n ) : (\n <CheckCircleIcon className=\"mt-px h-3.5 w-3.5 shrink-0\" />\n )}\n <span className=\"min-w-0\">\n {state.message ?? `Applied ${state.applied}`}\n {bad && !state.message ? ` · ${state.failed} failed` : \"\"}\n </span>\n </span>\n {records.map((record) => (\n <span key={`${record.noun}:${record.id}`} className=\"inline-flex min-w-0 items-center\">\n {host.renderRecord?.({\n ...record,\n fallback: recordFallbackName(label, record.id),\n context: \"applied\",\n trashed,\n })}\n </span>\n ))}\n {/* A failed item was never ledgered, so a plain re-apply retries only\n it. A clean tally offers \"Run again\" — the one way past the\n ledger's dedup, asked in words that say it runs a second time. */}\n <button\n type=\"button\"\n onClick={() => void handleApply(!bad)}\n className=\"inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground\"\n data-apply-action={bad ? \"retry\" : \"run-again\"}\n >\n <RotateCcwIcon className=\"h-3 w-3\" />\n {bad ? \"Retry\" : \"Run again\"}\n </button>\n </span>\n );\n }\n\n if (state.status === \"checking\") {\n return (\n <span\n className=\"inline-flex h-6 w-6 items-center justify-center text-muted-foreground\"\n role=\"status\"\n aria-label=\"Checking whether this already ran\"\n data-apply-state=\"checking\"\n >\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n </span>\n );\n }\n\n if (state.status === \"finishing\") {\n return (\n <span\n className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"\n role=\"status\"\n data-apply-state=\"finishing\"\n >\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n Finishing…\n </span>\n );\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleApply()}\n disabled={state.status === \"applying\" || state.status === \"asking\" || items.length === 0}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-xs font-medium hover:bg-accent disabled:opacity-50\"\n >\n {state.status === \"applying\" ? (\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <PlayIcon className=\"h-3.5 w-3.5\" />\n )}\n {state.status === \"applying\"\n ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? \"item\" : \"items\"}` : \"\"}…${elapsed ? ` ${elapsed}s` : \"\"}`\n : label}\n </button>\n {state.status === \"error\" ? (\n <span className=\"inline-flex max-w-sm items-start gap-1 text-xs text-destructive\">\n <AlertIcon className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>{state.message}</span>\n </span>\n ) : null}\n </span>\n );\n}\n\nexport default ApplyDirectiveButton;\n","/**\n * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the\n * confirm dialog, and anything else that must say it before the click.\n *\n * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item\n * as \"Item\" — they never named the record they would change, and an Update card\n * never said what it would change. The item-summary helpers name a thing to be\n * CREATED from its own fields; an update or delete item carries the TARGET's id\n * and, for an update, the NEW values — so its \"title\" field is the new title,\n * not the name of the record being changed. Naming the target is the host's\n * live lookup (`DirectiveHost.renderRecord`); what changes is right here.\n *\n * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence\n * names what changes.\n */\n\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\n\n/** Classes whose items point at an EXISTING record by `id`. */\nexport const TARGETING_CLASSES: ReadonlySet<string> = new Set([\"update\", \"delete\"]);\n\n/** Never a change: identity and plumbing. */\nconst NOT_A_CHANGE = new Set<string>([\"__kind\", \"id\"]);\n\n/** How long a changed value may read before it is shortened (full value on hover). */\nexport const CHANGE_VALUE_MAX = 60;\n\n/** The id of the existing record an update/delete item targets, or null. */\nexport function itemRecordId(item: Record<string, unknown>): string | null {\n const id = item.id;\n if (typeof id === \"string\" && id.trim()) return id.trim();\n if (typeof id === \"number\") return String(id);\n return null;\n}\n\n/** \"due_date\" → \"Due date\". Underscores read as developer output. */\nexport function fieldLabel(key: string): string {\n const spaced = key.replace(/_/g, \" \").trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/** A short, honest name for a record we could not look up: \"Task 1a2b3c4d\". */\nexport function recordFallbackName(nounLabel: string, id: string): string {\n const short = isUuidShape(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}…` : id;\n return `${nounLabel} ${short}`;\n}\n\nexport interface ItemChange {\n key: string;\n /** \"Due date\". */\n label: string;\n /** What it becomes, shortened for a row; `full` carries the whole value. */\n value: string;\n full: string;\n /** True when the new value empties the field. */\n clears: boolean;\n}\n\nfunction describeValue(value: unknown): { value: string; full: string; clears: boolean } {\n if (value === null || value === undefined) return { value: \"cleared\", full: \"cleared\", clears: true };\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return { value: \"cleared\", full: \"cleared\", clears: true };\n const oneLine = trimmed.replace(/\\s+/g, \" \");\n const shown = oneLine.length > CHANGE_VALUE_MAX ? `${oneLine.slice(0, CHANGE_VALUE_MAX - 1)}…` : oneLine;\n return { value: shown, full: trimmed, clears: false };\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return { value: String(value), full: String(value), clears: false };\n }\n if (Array.isArray(value)) {\n const n = value.length;\n const text = n === 0 ? \"cleared\" : `${n} ${n === 1 ? \"entry\" : \"entries\"}`;\n return { value: text, full: safeJson(value), clears: n === 0 };\n }\n const n = Object.keys(value as object).length;\n const text = n === 0 ? \"cleared\" : `${n} ${n === 1 ? \"field\" : \"fields\"}`;\n return { value: text, full: safeJson(value), clears: n === 0 };\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Every field an UPDATE item sets, in the order the item carries them — ALL of\n * them, never a sample: a person approving an overwrite sees the whole of it.\n */\nexport function itemChanges(item: Record<string, unknown>): ItemChange[] {\n const out: ItemChange[] = [];\n for (const [key, raw] of Object.entries(item)) {\n if (NOT_A_CHANGE.has(key)) continue;\n out.push({ key, label: fieldLabel(key), ...describeValue(raw) });\n }\n return out;\n}\n","/**\n * The handful of glyphs the directive cards need, as inline SVG. This package\n * depends on no icon library (see the FEATURE boundary); the paths are the\n * Lucide set's (ISC), so the cards look identical to a Lucide-using host.\n */\n\nimport type { ReactElement, SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction Svg({ children, ...props }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport const FilePlusIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n <path d=\"M3 15h6\" />\n <path d=\"M6 12v6\" />\n </Svg>\n);\nexport const PencilIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M12 20h9\" />\n <path d=\"M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z\" />\n </Svg>\n);\nexport const TrashIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n <line x1=\"10\" x2=\"10\" y1=\"11\" y2=\"17\" />\n <line x1=\"14\" x2=\"14\" y1=\"11\" y2=\"17\" />\n </Svg>\n);\nexport const PlayIcon = (p: IconProps) => (\n <Svg {...p}>\n <polygon points=\"6 3 20 12 6 21 6 3\" />\n </Svg>\n);\nexport const WebhookIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2\" />\n <path d=\"m6 17 3.13-5.78c.53-.97.1-2.01-.4-2.96A4 4 0 0 1 14 5.5c.63.42 1.13 1 1.44 1.66\" />\n <path d=\"m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8\" />\n </Svg>\n);\nexport const BoxesIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z\" />\n <path d=\"m7 16.5-4.74-2.85\" />\n <path d=\"m7 16.5 5-3\" />\n <path d=\"M7 16.5v5.17\" />\n <path d=\"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z\" />\n <path d=\"m17 16.5-5-3\" />\n <path d=\"m17 16.5 4.74-2.85\" />\n <path d=\"M17 16.5v5.17\" />\n <path d=\"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z\" />\n <path d=\"M12 8 7.26 5.15\" />\n <path d=\"m12 8 4.74-2.85\" />\n <path d=\"M12 13.5V8\" />\n </Svg>\n);\nexport const ChevronDownIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m6 9 6 6 6-6\" />\n </Svg>\n);\nexport const ChevronRightIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m9 18 6-6-6-6\" />\n </Svg>\n);\nexport const MaximizeIcon = (p: IconProps) => (\n <Svg {...p}>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\" />\n <line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\" />\n </Svg>\n);\nexport const LoaderIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </Svg>\n);\n/** Lucide `rotate-ccw` — \"Run again\". */\nexport const RotateCcwIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </Svg>\n);\nexport const CheckCircleIcon = (p: IconProps) => (\n <Svg {...p}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m9 12 2 2 4-4\" />\n </Svg>\n);\nexport const AlertIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </Svg>\n);\n\n/**\n * The icon for a side-effect directive card. THE CLASS LEADS: on a card whose\n * job is \"authorize this write\", the first thing to see is whether this\n * CREATES, CHANGES, or DELETES. A noun override exists only where the platform\n * has a settled visual identity for the thing — agents are a Webhook.\n */\nconst AGENT_NOUNS = new Set([\"create_agent\", \"create_agent_definition\", \"agent\"]);\n\nexport function classIcon(directiveClass: string, noun: string): (p: IconProps) => ReactElement {\n if (directiveClass === \"action\" && AGENT_NOUNS.has(noun)) return WebhookIcon;\n switch (directiveClass) {\n case \"create\":\n return FilePlusIcon;\n case \"update\":\n return PencilIcon;\n case \"delete\":\n return TrashIcon;\n default:\n return PlayIcon;\n }\n}\n","\"use client\";\n\n/**\n * The card for a SIDE-EFFECT directive in content — create / update / delete /\n * action. One card for every shape the server can register, so a person is\n * never asked to approve a write they cannot identify.\n *\n * WHY IT EXISTS (Arman, 2026-08-26): the floor it replaced gave \"a name and\n * then an apply button, which essentially tells the user to click apply and\n * conduct a potentially destructive action without any clue as to what this\n * thing is.\"\n *\n * THE DESIGN:\n * - Say what it IS, from authority — the catalog's own words for the title,\n * the noun's title column for each item, never a guess.\n * - Facts, not prose — a few scalar chips; nesting goes to the panel.\n * - Read before you approve — `View` opens the item through the host's seam,\n * which wraps the item's OWN kind component (THE DIRECTIVE⇄KIND SEAM).\n * - Copy is table stakes, at the batch and at the item (host chrome).\n * - Apply stays exactly where it was — the host's confirm seam.\n *\n * NEVER RETURNS NULL — a shape with no items degrades to a stated line.\n */\n\nimport { useState } from \"react\";\nimport {\n asKindInstance,\n directiveDisplay,\n itemFacts,\n itemSubtitle,\n itemTitle,\n nounLabel,\n nounTitleColumn,\n type DecodedDirective,\n} from \"@ai-matrx/content-ir\";\nimport { ApplyDirectiveButton } from \"./ApplyDirectiveButton\";\nimport { TARGETING_CLASSES, itemChanges, itemRecordId, recordFallbackName } from \"./item-changes\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { ChevronDownIcon, ChevronRightIcon, MaximizeIcon, classIcon } from \"./icons\";\n\nexport interface SideEffectDirectiveCardProps {\n directive: DecodedDirective;\n}\n\n/** How many items render as rows before the rest collapse behind a toggle. */\nconst ROWS_BEFORE_FOLD = 3;\n\nfunction ItemRow({\n directive,\n item,\n index,\n total,\n}: {\n directive: DecodedDirective;\n item: Record<string, unknown>;\n index: number;\n total: number;\n}) {\n const host = useDirectiveHost();\n // An update/delete item points at a record that ALREADY EXISTS: name THAT\n // record (its live name, through the host), never the item's own fields —\n // an update's `title` is the NEW title — and never \"Item\".\n const recordId = TARGETING_CLASSES.has(directive.directiveClass) ? itemRecordId(item) : null;\n if (recordId) {\n return <TargetRow directive={directive} item={item} recordId={recordId} />;\n }\n const titleColumn = nounTitleColumn(directive.noun, host.nouns);\n const title = itemTitle(item, titleColumn, index, total);\n const subtitle = itemSubtitle(item);\n const facts = itemFacts(item);\n const kind = host.itemKind?.(directive.slug) ?? null;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n const openItem = host.openItem;\n\n const body = (\n <>\n {/* THE IDENTITY WINS THE SPACE: the title keeps its intrinsic width and the facts give way. */}\n <span className=\"min-w-0 shrink-0 truncate font-medium text-foreground\">{title}</span>\n <span className=\"hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex\">\n {facts.map((fact) => (\n <span key={fact.key} className=\"truncate text-[11px] text-muted-foreground\">\n {fact.value} {fact.label}\n </span>\n ))}\n </span>\n {subtitle && facts.length === 0 ? (\n <span className=\"hidden truncate text-[11px] text-muted-foreground sm:inline\">{subtitle}</span>\n ) : null}\n {openItem ? (\n <MaximizeIcon className=\"ml-auto h-3 w-3 shrink-0 text-muted-foreground\" />\n ) : null}\n </>\n );\n\n return (\n <div className=\"flex items-center gap-2 py-1 text-xs\">\n {openItem ? (\n <button\n type=\"button\"\n onClick={() =>\n openItem({\n // Stamped so the panel's kind pipeline types it from its own first key.\n item: asKindInstance(item, kind) ?? item,\n itemKind: kind,\n title,\n subtitle: `${display.title} · item ${index + 1} of ${total}`,\n directive,\n index,\n total,\n })\n }\n className=\"flex min-w-0 flex-1 items-center gap-2 rounded px-1 py-0.5 text-left hover:bg-accent hover:text-accent-foreground\"\n title=\"Open to read it\"\n >\n {body}\n </button>\n ) : (\n <span className=\"flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5\">{body}</span>\n )}\n {host.renderCopy?.({ label: title, value: item, kind, size: \"xs\" })}\n </div>\n );\n}\n\n/**\n * ONE row for an item that changes an EXISTING record: the record by its live\n * name (a way to open it, through `renderRecord`), then — for an update —\n * every field it sets, \"Due date → 2026-10-15\".\n */\nfunction TargetRow({\n directive,\n item,\n recordId,\n}: {\n directive: DecodedDirective;\n item: Record<string, unknown>;\n recordId: string;\n}) {\n const host = useDirectiveHost();\n const fallback = recordFallbackName(nounLabel(directive.noun, host.nouns), recordId);\n const changes = directive.directiveClass === \"update\" ? itemChanges(item) : [];\n const name = host.renderRecord ? (\n host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: \"row\" })\n ) : (\n <span className=\"truncate font-medium text-foreground\">{fallback}</span>\n );\n\n return (\n <div className=\"py-1 text-xs\" data-directive-target={recordId}>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"flex min-w-0 flex-1 items-center gap-1 px-1\">{name}</span>\n {host.renderCopy?.({ label: fallback, value: item, size: \"xs\" })}\n </div>\n {directive.directiveClass === \"update\" ? (\n changes.length === 0 ? (\n <p className=\"px-1 text-[11px] text-muted-foreground\">Sets no fields — nothing would change.</p>\n ) : (\n <ul className=\"mt-0.5 space-y-0.5 px-1\">\n {changes.map((change) => (\n <li\n key={change.key}\n className=\"flex min-w-0 items-baseline gap-1.5 text-[11px]\"\n title={`${change.label} → ${change.full}`}\n >\n <span className=\"shrink-0 text-muted-foreground\">{change.label}</span>\n <span aria-hidden className=\"shrink-0 text-muted-foreground\">→</span>\n <span\n className={`min-w-0 truncate ${change.clears ? \"italic text-muted-foreground\" : \"text-foreground\"}`}\n >\n {change.value}\n </span>\n </li>\n ))}\n </ul>\n )\n ) : null}\n </div>\n );\n}\n\nexport function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps) {\n const host = useDirectiveHost();\n const [expanded, setExpanded] = useState(false);\n const items = directive.items;\n const total = items.length;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n const Icon = classIcon(directive.directiveClass, directive.noun);\n\n const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);\n const hidden = total - shown.length;\n\n return (\n <div className=\"my-3 rounded-md border border-border bg-card px-2.5 py-1.5\" data-directive={directive.slug}>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <Icon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-sm font-medium text-foreground\">{display.title}</span>\n {display.family ? <span className=\"text-xs text-muted-foreground\">{display.family}</span> : null}\n <span className=\"text-xs tabular-nums text-muted-foreground\">\n {total} {total === 1 ? \"item\" : \"items\"}\n </span>\n <div className=\"ml-auto flex items-center gap-1\">\n {host.renderCopy?.({ label: display.title, value: directive.shell, size: \"icon\" })}\n <ApplyDirectiveButton directive={directive} itemCount={total} />\n </div>\n </div>\n\n {total === 0 ? (\n // Stated, never silent: an empty batch is a real (and suspicious) state.\n <p className=\"mt-1 text-xs text-muted-foreground\">No items — nothing would be written.</p>\n ) : (\n <div className=\"mt-0.5 divide-y divide-border/60\">\n {shown.map((item, i) => (\n <ItemRow key={i} directive={directive} item={item} index={i} total={total} />\n ))}\n </div>\n )}\n\n {hidden > 0 || expanded ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"mt-0.5 inline-flex items-center gap-1 rounded px-1 py-0.5 text-[11px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? <ChevronDownIcon className=\"h-3 w-3\" /> : <ChevronRightIcon className=\"h-3 w-3\" />}\n {expanded ? \"Show less\" : `Show ${hidden} more`}\n </button>\n ) : null}\n </div>\n );\n}\n\nexport default SideEffectDirectiveCard;\n","\"use client\";\n\n/**\n * The neutral \"we could not render this, but we will NEVER hide it\" card —\n * THE PREFIX FLOOR of the Kind Directives route.\n *\n * THE RULE THIS ENFORCES: a registered directive renderer must never return\n * `null`. `DirectiveRender` renders a renderer's output verbatim, so a `null`\n * deletes the assistant's whole message block (2026-07-26: a 70KB content plan\n * vanished exactly that way). When a renderer cannot draw its rich view, it\n * renders THIS instead: named by class and noun, itemised by count, with Apply\n * when the class is a side effect and the host can apply.\n */\n\nimport { directiveDisplay, type DecodedDirective } from \"@ai-matrx/content-ir\";\nimport { ApplyDirectiveButton } from \"./ApplyDirectiveButton\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { BoxesIcon } from \"./icons\";\n\nexport interface DirectiveFallbackCardProps {\n directive: DecodedDirective;\n /** Short, human explanation of why the rich renderer degraded. */\n reason?: string;\n}\n\nexport function DirectiveFallbackCard({ directive, reason }: DirectiveFallbackCardProps) {\n const host = useDirectiveHost();\n const count = directive.items.length;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n return (\n <div className=\"my-3 inline-flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted px-2.5 py-1 text-sm\">\n <BoxesIcon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-foreground\">{display.title}</span>\n {display.family ? <span className=\"text-muted-foreground\">· {display.family}</span> : null}\n <span className=\"text-muted-foreground\">\n · {count} {count === 1 ? \"item\" : \"items\"}\n </span>\n {reason ? <span className=\"text-muted-foreground\">· {reason}</span> : null}\n <ApplyDirectiveButton directive={directive} />\n </div>\n );\n}\n\nexport default DirectiveFallbackCard;\n","\"use client\";\n\n/**\n * The card for a directive whose JSON has NOT finished arriving — the\n * provisional tier of `DirectiveRender`.\n *\n * WHY IT EXISTS (found live 2026-09-25, the agent builder's\n * `directive_v1_action_create_agent_definition` in the agent run window): an\n * agent streams a directive as one JSON document, `__kind` first. Every splitter\n * already types the block as a directive from its first bytes\n * (`looksLikeDirectiveHead`), but the decoder can only honour a COMPLETE shell,\n * so for the whole stream `DirectiveRender` fell to its raw `<pre>` — the person\n * watched a wall of JSON grow and then snap into a card at the last byte.\n *\n * The head already says what this is (class + noun), so the card says it from\n * the first bytes, from the same catalog words the finished card uses:\n *\n * - STREAMING — \"Create agent definition · writing…\". No Apply: nothing is\n * applicable until the shell is whole.\n * - NOT STREAMING, still undecodable — the document was cut off (a model hit\n * its output limit, a stream died). Said plainly, never dressed as\n * \"writing…\" forever, with what did arrive one click away.\n *\n * NEVER RETURNS NULL.\n */\n\nimport { directiveDisplay, parseDirectiveSlug } from \"@ai-matrx/content-ir\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { BoxesIcon, classIcon } from \"./icons\";\n\n/** A head whose slug has fully arrived: `{\"__kind\":\"directive_v1_…\"` + closing quote. */\nconst COMPLETE_SLUG_RE = /^\\{\\s*\"__kind\"\\s*:\\s*\"([^\"]+)\"/;\n\n/** The directive slug of a partial document, once its closing quote has arrived. */\nexport function provisionalDirectiveSlug(content: string): string | null {\n const match = content.trimStart().match(COMPLETE_SLUG_RE);\n return match?.[1] ?? null;\n}\n\nexport interface DirectiveProvisionalCardProps {\n /** The partial fence body as received so far. */\n content: string;\n /**\n * Whether the document may still be arriving. `false` means the stream is\n * over and the document never completed — the card says it was cut off.\n */\n streaming: boolean;\n className?: string | undefined;\n}\n\nexport function DirectiveProvisionalCard({ content, streaming, className }: DirectiveProvisionalCardProps) {\n const host = useDirectiveHost();\n const slug = provisionalDirectiveSlug(content);\n const known = slug ? parseDirectiveSlug(slug) : null;\n const display = known ? directiveDisplay(known.directiveClass, known.noun, host.nouns) : null;\n const Icon = known ? classIcon(known.directiveClass, known.noun) : BoxesIcon;\n const title = display?.title ?? \"Structured action\";\n\n return (\n <div\n className={`my-3 rounded-md border border-border bg-card px-2.5 py-1.5${className ? ` ${className}` : \"\"}`}\n data-directive={slug ?? undefined}\n data-directive-state={streaming ? \"streaming\" : \"incomplete\"}\n >\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <Icon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-sm font-medium text-foreground\">{title}</span>\n {display?.family ? <span className=\"text-xs text-muted-foreground\">{display.family}</span> : null}\n {streaming ? (\n <span className=\"inline-flex items-center gap-1.5 text-xs text-muted-foreground\" role=\"status\">\n <span className=\"h-1.5 w-1.5 animate-pulse rounded-full bg-primary\" aria-hidden />\n Writing…\n </span>\n ) : (\n <span className=\"text-xs text-destructive\" role=\"status\">\n Cut off before it finished — nothing can be applied.\n </span>\n )}\n </div>\n {streaming ? null : (\n <details className=\"mt-1 text-xs text-muted-foreground\">\n <summary className=\"cursor-pointer select-none hover:text-foreground\">Show what arrived</summary>\n <pre className=\"mt-1 max-h-64 overflow-auto whitespace-pre-wrap break-all rounded bg-muted px-2 py-1 text-[11px]\">\n {content}\n </pre>\n </details>\n )}\n </div>\n );\n}\n\nexport default DirectiveProvisionalCard;\n","\"use client\";\n\n/**\n * DirectiveRender — THE renderer for anything whose `__kind` is a reserved\n * directive slug, on every AI Matrx UI.\n *\n * Pipeline (one pipeline, mirroring the backend):\n * 0. THE PROVISIONAL TIER — a head that names a directive but does not\n * decode yet renders `DirectiveProvisionalCard` (\"writing…\" while\n * streaming, \"cut off\" once the host says the stream ended).\n * 1. `tryDecodeDirectiveContent` → the two-key shell (a stored 4-key fence is\n * translated inside the decoder). Not a directive (bad JSON / no reserved\n * `__kind`) → raw <pre>, never throws. An unhonourable shell is REPORTED\n * through the host and falls to raw — a render seam must not take a whole\n * message block down over one fence, and must never go silent.\n * 2. `getDirectiveRenderer` → exact slug, else the CLASS prefix rule (the\n * host's registrations). Found → render it.\n * 3. THE SIDE-EFFECT TIER — every create / update / delete / action shape\n * renders the side-effect card, so a person is never asked to approve a\n * write they cannot identify.\n * 4. THE FLOOR — a class nothing registers still shows the fallback card.\n * Never null, never silent.\n *\n * Position decides capability: in content only `reference`/`secret` resolve;\n * a side-effect directive in prose is a card with an explicit Apply, never\n * executed on sight.\n */\n\nimport { looksLikeDirectiveHead, tryDecodeDirectiveContent } from \"@ai-matrx/content-ir\";\nimport { DirectiveScopeProvider, useDirectiveHost } from \"./directive-host\";\nimport { DirectiveFallbackCard } from \"./DirectiveFallbackCard\";\nimport { DirectiveProvisionalCard } from \"./DirectiveProvisionalCard\";\nimport { getDirectiveRenderer } from \"./registry\";\nimport { SideEffectDirectiveCard } from \"./SideEffectDirectiveCard\";\n\nexport interface DirectiveRenderProps {\n /** The fence body (JSON string) or an already-parsed shell / value. */\n content: unknown;\n className?: string;\n /**\n * Whether the document may still be arriving. A host that knows its stream\n * has ended passes `false`, so an undecodable directive head is shown as CUT\n * OFF rather than \"writing…\" forever. Omitted = it may still be arriving.\n */\n streaming?: boolean;\n /**\n * The conversation this directive renders in (a chat message). Applies and\n * ledger reads key on it — the same namespace an agent proposal's Approve\n * uses — so one action can never apply twice through two doors. Omit in a\n * person's own content. Overrides any enclosing `DirectiveScopeProvider`.\n */\n conversationId?: string | null;\n}\n\n/**\n * A document that parses is WHOLE: if it still does not decode, it is a\n * malformed directive (already reported by the decoder), never one \"still\n * arriving\" — only a genuinely unfinished document gets the provisional tier.\n */\nfunction isWholeJson(content: string): boolean {\n try {\n JSON.parse(content);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps) {\n if (conversationId === undefined) return <DirectiveRenderInner {...props} />;\n return (\n <DirectiveScopeProvider conversationId={conversationId}>\n <DirectiveRenderInner {...props} />\n </DirectiveScopeProvider>\n );\n}\n\nfunction DirectiveRenderInner({ content, className, streaming }: Omit<DirectiveRenderProps, \"conversationId\">) {\n const host = useDirectiveHost();\n const directive = tryDecodeDirectiveContent(content, (message) => {\n const line = `[kind-directives] ${message}`;\n if (host.reportError) host.reportError(line);\n else console.error(line);\n });\n\n if (!directive) {\n // THE PROVISIONAL TIER: the head already names a directive but the shell is\n // not whole yet (mid-stream) or never became whole (cut off). The class and\n // noun are known from the first bytes — say what it is, never show the\n // growing JSON as if it were the answer.\n if (typeof content === \"string\" && looksLikeDirectiveHead(content) && !isWholeJson(content)) {\n return (\n <DirectiveProvisionalCard content={content} streaming={streaming !== false} className={className} />\n );\n }\n const raw = typeof content === \"string\" ? content : JSON.stringify(content, null, 2);\n return (\n <pre\n className={`my-3 overflow-x-auto rounded-md border border-border bg-muted px-3 py-2 text-xs text-muted-foreground${className ? ` ${className}` : \"\"}`}\n >\n {raw}\n </pre>\n );\n }\n\n const Renderer = getDirectiveRenderer(directive);\n if (Renderer) return <Renderer directive={directive} />;\n if (directive.parsed.executes) return <SideEffectDirectiveCard directive={directive} />;\n return <DirectiveFallbackCard directive={directive} />;\n}\n\nexport default DirectiveRender;\n"],"mappings":"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","names":["import_react","import_content_ir","nounLabel","n","text","import_jsx_runtime","import_jsx_runtime","label","import_react","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime"]}
1
+ {"version":3,"sources":["../directives.ts","../directives/directive-host.tsx","../directives/registry.ts","../directives/ApplyDirectiveButton.tsx","../directives/item-changes.ts","../directives/icons.tsx","../directives/SideEffectDirectiveCard.tsx","../directives/DirectiveFallbackCard.tsx","../directives/DirectiveProvisionalCard.tsx","../directives/DirectiveRender.tsx"],"sourcesContent":["/**\n * `@ai-matrx/content-ir-react/directives` — the Kind Directives render tier:\n * the host seams (`DirectiveHostProvider`), the renderer registry with THE\n * PREFIX TIER, the side-effect card, the fallback floor, the Apply control, and\n * `DirectiveRender` — THE renderer every UI draws a directive through. Client\n * entry (stamped \"use client\").\n */\nexport * from \"./directives/directive-host\";\nexport * from \"./directives/registry\";\nexport * from \"./directives/ApplyDirectiveButton\";\nexport * from \"./directives/SideEffectDirectiveCard\";\nexport * from \"./directives/DirectiveFallbackCard\";\nexport * from \"./directives/DirectiveProvisionalCard\";\nexport * from \"./directives/DirectiveRender\";\nexport * from \"./directives/item-changes\";\n","\"use client\";\n\n/**\n * THE DIRECTIVE HOST CONTRACT — what the directive tier refuses to decide.\n *\n * The package owns the DECISIONS (decode → renderer → card → floor, the\n * position law, never-null rendering) and the card itself. Four things stay\n * host property and enter through named seams:\n *\n * 1. APPLYING a side-effect directive — `POST /directives/confirm` as the\n * user, with the host's auth and base URL. Absent → the Apply control is\n * ABSENT (honest), never a dead button.\n * 2. OPENING an item to read it before approving — a window panel, a dialog,\n * a route. Absent → items are not clickable.\n * 3. COPY controls — host chrome (matrx-frontend's CopyButtons). Absent → none.\n * 4. The NOUN catalog + item-kind lookup — server-derived tables the host\n * mirrors (or reads from its kind catalog's `items` edges).\n * 5. ASKING (`ask`), NAMING a record (`renderRecord`), and READING the ledger\n * (`applyState`) — the consequence before the click, the doors, and the\n * state that survives a reload.\n *\n * A host that has adopted `ContentIrRenderProvider` passes `directives` on its\n * ContentIrHost; a host that has NOT (Workflow Studio, 2026-09-08) mounts\n * `DirectiveHostProvider` alone — the directive tier never requires the full\n * render host, because a chat bubble must be able to draw a directive card\n * identically everywhere, today.\n */\n\nimport { createContext, useContext, type ReactNode } from \"react\";\nimport type {\n DecodedDirective,\n DirectiveItemKindLookup,\n DirectiveNounCatalog,\n} from \"@ai-matrx/content-ir\";\n\nexport interface DirectiveApplyResult {\n applied: number;\n failed: number;\n /**\n * The server's own receipt sentence (\"Deleted task “Ship it”.\"), shown in\n * place of a bare count. Never composed client-side.\n */\n message?: string | null;\n /**\n * The records the apply created or changed, so the tally is a way IN to them\n * (no dead ends). Rendered through `renderRecord`; absent → the sentence alone.\n */\n records?: DirectiveRecordRef[];\n}\n\n/**\n * What the server's action ledger says about ONE block, read on mount so a\n * reloaded page never offers \"Apply\" for work that already ran (reviewer\n * defect 5, 2026-10-02).\n *\n * - `not_applied` — still to do (or partly done: the batch re-applies, and the\n * server replays the members it already holds). The card offers Apply.\n * - `in_flight` — another request is applying it right now. The card says it\n * is finishing and asks again shortly; it offers neither Apply nor a tally.\n * - `applied` — the ledger holds every item. The card shows the tally exactly\n * as a fresh apply would: the ledger's own sentence and the records, as doors.\n */\nexport interface DirectiveApplyState {\n state: \"not_applied\" | \"in_flight\" | \"applied\";\n /** The ledger row's sentence (\"Created task.\"), never composed client-side. */\n message?: string | null;\n /** The records the original apply wrote — the tally's doors. */\n records?: DirectiveRecordRef[];\n}\n\n/** One record a directive names: the noun it is, and its id. */\nexport interface DirectiveRecordRef {\n noun: string;\n id: string;\n}\n\nexport interface DirectiveRecordProps extends DirectiveRecordRef {\n /**\n * What to show until (or unless) the host resolves the live name —\n * \"Task 1a2b3c4d\". Never blank, never \"Item\".\n */\n fallback: string;\n /** Where it is drawn: an item row, the confirm dialog, or the applied tally. */\n context: \"row\" | \"dialog\" | \"applied\";\n /**\n * True when the record is (about to be) in the trash — the host may still\n * name it but should not promise it opens as a live record.\n */\n trashed?: boolean;\n}\n\n/** What the person is being asked to approve — everything the card knows. */\nexport interface DirectiveAskRequest {\n directive: DecodedDirective;\n /** The items, exactly as they will be sent. */\n items: Record<string, unknown>[];\n /** The noun's human label (\"Task\"), from the host's catalog when it has one. */\n nounLabel: string;\n /**\n * True for \"Run again\": the ledger already holds this block, and a yes runs\n * it a SECOND time (`force`) — another copy for a create, the same fields\n * written again for an update, another delete for a restored record. The\n * question must say so.\n */\n again?: boolean;\n}\n\n/**\n * The shell a card hands its host — the two keys, plus WHERE it sits.\n *\n * `conversationId` is the conversation the card renders in (a chat message),\n * absent in a person's own content (a note). It is the idempotency NAMESPACE:\n * a card in an agent's message must apply under the SAME key as that\n * proposal's Approve button, or the one action could run twice.\n */\nexport interface DirectiveShell {\n __kind: string;\n items: Record<string, unknown>[];\n conversationId?: string;\n /** \"Run again\": skip the ledger's dedup and apply a second time. */\n force?: boolean;\n}\n\nexport interface DirectiveOpenItemOptions {\n /** The item, `__kind`-stamped when the shape has an item kind. */\n item: Record<string, unknown>;\n /** The content-IR kind this item IS, or null when the shape has none. */\n itemKind: string | null;\n /** What the item is called — the same title the card shows. */\n title: string;\n /** \"Run Create agent definition · item 1 of 1\". */\n subtitle: string | null;\n directive: DecodedDirective;\n index: number;\n total: number;\n}\n\nexport interface DirectiveCopyProps {\n label: string;\n /** The value to copy — the whole shell or one item. */\n value: unknown;\n /** The item's kind, when copying an item. */\n kind?: string | null;\n size: \"icon\" | \"xs\";\n}\n\nexport interface DirectiveHost {\n /**\n * Apply a side-effect directive as the user (the server re-validates every\n * item against the registered model and runs the ONE handler; idempotent).\n * Reject with an Error whose message is safe to show.\n */\n confirm?: (shell: DirectiveShell) => Promise<DirectiveApplyResult>;\n /**\n * Ask the person BEFORE anything runs, naming the consequence (the records,\n * what changes). Resolve `true` to go ahead, `false` to leave the card as it\n * was. The Apply control stays idle while this is open — nothing reads as\n * \"applying\" until the person has said yes. Absent → `confirm` is called\n * directly (a host that asks inside `confirm` keeps working, but its card\n * will read \"Applying…\" while its dialog is up).\n */\n ask?: (request: DirectiveAskRequest) => Promise<boolean>;\n /**\n * Has this exact block already been applied? Read ONCE when the card mounts\n * (and again while the answer is `in_flight`), so the card survives a reload:\n * the server ledger, not component state, is what knows. The identity is the\n * server's (it hashes the validated items in the same namespace `confirm`\n * applies in), so a host asks — it never computes. Batch on the host side if\n * a page carries many cards. Reject with an Error when the ledger cannot be\n * read: the card reports it and offers Apply, which is safe because `confirm`\n * is idempotent. Absent → the card starts at Apply, as before.\n */\n applyState?: (shell: DirectiveShell) => Promise<DirectiveApplyState>;\n /**\n * Draw ONE existing record by its live name, as a way to open it. Used on\n * update/delete rows (the record that will change), in the host's own ask\n * dialog if it likes, and on the applied tally (what was written). Absent →\n * the fallback text, unlinked.\n */\n renderRecord?: (props: DirectiveRecordProps) => ReactNode;\n /** Open ONE item to read it properly before approving the write. */\n openItem?: (options: DirectiveOpenItemOptions) => void;\n /** Host copy controls. */\n renderCopy?: (props: DirectiveCopyProps) => ReactNode;\n /** The mirrored noun catalog (label / family / title column). */\n nouns?: DirectiveNounCatalog;\n /** slug → the kind ONE item is (THE DIRECTIVE⇄KIND SEAM), or null. */\n itemKind?: DirectiveItemKindLookup;\n /** Where a decode failure or an unhonourable shell is reported. Default: console.error. */\n reportError?: (message: string) => void;\n}\n\nconst DirectiveHostContext = createContext<DirectiveHost | null>(null);\n\n/** Where a directive renders — today, the conversation it sits in (if any). */\nexport interface DirectiveScope {\n conversationId?: string | null;\n}\n\nconst DirectiveScopeContext = createContext<DirectiveScope>({});\n\n/**\n * Tell every card below WHERE it renders. A host draws a chat message's\n * directives inside one of these (or passes `conversationId` to\n * `DirectiveRender`), so the card applies in that conversation's namespace —\n * the same key the agent's proposal approves under. A note mounts none.\n */\nexport function DirectiveScopeProvider({\n conversationId,\n children,\n}: DirectiveScope & { children: ReactNode }) {\n return (\n <DirectiveScopeContext.Provider value={{ conversationId: conversationId ?? null }}>\n {children}\n </DirectiveScopeContext.Provider>\n );\n}\n\nexport function useDirectiveScope(): DirectiveScope {\n return useContext(DirectiveScopeContext);\n}\n\nexport interface DirectiveHostProviderProps {\n host: DirectiveHost;\n children: ReactNode;\n}\n\nexport function DirectiveHostProvider({ host, children }: DirectiveHostProviderProps) {\n return <DirectiveHostContext.Provider value={host}>{children}</DirectiveHostContext.Provider>;\n}\n\nconst EMPTY_HOST: DirectiveHost = {};\n\n/**\n * The wired directive host. Unlike the render host this does NOT throw when\n * unwired: a directive still renders (named, itemised, copy-less, apply-less)\n * — degrading the chrome is honest, hiding the content is not.\n */\nexport function useDirectiveHost(): DirectiveHost {\n return useContext(DirectiveHostContext) ?? EMPTY_HOST;\n}\n","/**\n * Kind Directives — the renderer registry, and THE PREFIX TIER.\n *\n * A directive IS a kind instance, so the renderer for one is resolved from its\n * SLUG, in the same shape the kind component resolver uses:\n *\n * getDirectiveRenderer(directive)\n * → an exact-slug renderer (directive_v1_action_plan_tree)\n * → else the CLASS prefix rule (every directive_v1_reference_*)\n * → else null (DirectiveRender's own tier: the\n * side-effect card, then the floor)\n *\n * THE PREFIX RULE is Arman's routing-language ruling made real: registering\n * `reference` once gives EVERY enrolled noun a renderer for free; a custom\n * renderer for one slug overrides it; a brand-new server noun renders with\n * ZERO client edits. Hosts register their bespoke renderers (reference chips,\n * plan trees) here; the package supplies the side-effect card and the floor.\n */\n\nimport type { ComponentType } from \"react\";\nimport {\n type DecodedDirective,\n type DirectiveClass,\n buildDirectiveSlug,\n} from \"@ai-matrx/content-ir\";\n\nexport interface DirectiveRendererProps {\n /** The decoded two-key shell — slug, class, noun, items, position law. */\n directive: DecodedDirective;\n}\n\nexport type DirectiveRenderer = ComponentType<DirectiveRendererProps>;\n\n// REGISTRY ON A globalThis SLOT — never module-level Maps. With `splitting:\n// false` dual ESM/CJS output this module is duplicated into the root bundle and\n// the `./directives` bundle, and a host registering a renderer through one\n// graph must be visible to a card rendering through the other.\nconst REGISTRY_SLOT = Symbol.for(\"ai-matrx.content-ir-react.directive-renderers\");\ninterface Registry {\n bySlug: Map<string, DirectiveRenderer>;\n byClass: Map<DirectiveClass, DirectiveRenderer>;\n}\ntype RegistryHolder = typeof globalThis & { [REGISTRY_SLOT]?: Registry };\nconst registry: Registry = ((globalThis as RegistryHolder)[REGISTRY_SLOT] ??= {\n bySlug: new Map(),\n byClass: new Map(),\n});\n\n/**\n * Register a renderer for a whole CLASS (the prefix rule), or for one exact\n * `(class, noun)` pair, which wins. `noun` is passed as a noun, never a\n * hand-typed slug: the slug is BUILT by the grammar, so a registration whose\n * slug could not be parsed back is unconstructable rather than unreachable.\n */\nexport function registerDirectiveRenderer(\n directiveClass: DirectiveClass,\n renderer: DirectiveRenderer,\n noun?: string,\n): void {\n if (noun) registry.bySlug.set(buildDirectiveSlug(directiveClass, noun), renderer);\n else registry.byClass.set(directiveClass, renderer);\n}\n\n/** The renderer for a slug: exact → class prefix rule → null. */\nexport function getDirectiveRenderer(\n directive: Pick<DecodedDirective, \"slug\" | \"directiveClass\">,\n): DirectiveRenderer | null {\n return (\n registry.bySlug.get(directive.slug) ?? registry.byClass.get(directive.directiveClass) ?? null\n );\n}\n\n/** Tests only. */\nexport function resetDirectiveRenderers(): void {\n registry.bySlug.clear();\n registry.byClass.clear();\n}\n","\"use client\";\n\n/**\n * \"Apply\" for a side-effect Kind Directive that arrived as CONTENT.\n *\n * THE POSITION RULE, honoured exactly: a directive inside content NEVER\n * auto-executes — that is the guard against untrusted content mutating things.\n * But \"does not auto-execute\" was never \"is inert\": the user seeing it must be\n * able to say yes. This button IS that yes, through the host's `confirm` seam\n * (`POST /directives/confirm`, re-validated server-side, run as the user).\n *\n * No `confirm` seam → NO button. A control that cannot do its job is absent,\n * never dead. Only a side-effect class is applicable at all (`parsed.executes`).\n */\n\nimport { useEffect, useRef, useState } from \"react\";\nimport { nounLabel, type DecodedDirective } from \"@ai-matrx/content-ir\";\nimport {\n useDirectiveHost,\n useDirectiveScope,\n type DirectiveRecordRef,\n type DirectiveShell,\n} from \"./directive-host\";\nimport { recordFallbackName } from \"./item-changes\";\nimport { AlertIcon, CheckCircleIcon, LoaderIcon, PlayIcon, RotateCcwIcon } from \"./icons\";\n\ntype ApplyState =\n // Reading the server ledger on mount: has this block already run? Nothing\n // offers a write until it answers (reviewer defect 5, 2026-10-02).\n | { status: \"checking\" }\n // The ledger has a claim but no result: another request is applying it now.\n | { status: \"finishing\" }\n | { status: \"idle\" }\n // The host's `ask` dialog is up. NOTHING is applying yet, so nothing says so.\n | { status: \"asking\" }\n | { status: \"applying\" }\n | {\n status: \"applied\";\n applied: number;\n failed: number;\n message: string | null;\n records: DirectiveRecordRef[];\n }\n | { status: \"error\"; message: string };\n\n/** How often a card re-reads a block another request is mid-applying. */\nconst FINISH_POLL_MS = 2_000;\n/** ~1 minute (the server's own claim wait is 45 s), then Apply is offered — idempotent. */\nconst FINISH_POLLS_MAX = 30;\n\nexport interface ApplyDirectiveButtonProps {\n directive: DecodedDirective;\n label?: string;\n /** How many things this will write — shown during the wait so a long apply reads as work, not a frozen spinner. */\n itemCount?: number;\n onApplied?: () => void;\n}\n\nexport function ApplyDirectiveButton({\n directive,\n label = \"Apply\",\n itemCount,\n onApplied,\n}: ApplyDirectiveButtonProps) {\n const host = useDirectiveHost();\n const scope = useDirectiveScope();\n // WHERE the card sits is the namespace its apply keys in: a chat message's\n // conversation (the SAME key the agent proposal's Approve uses — never two\n // applies of one action), else the person's own content.\n const conversationId = scope.conversationId || undefined;\n const items = directive.items;\n // The ledger read runs only where an apply could: a side effect, a confirm\n // seam, something to write. Everything else starts (and stays) where it was.\n const readsLedger =\n !!host.applyState && !!host.confirm && directive.parsed.executes && items.length > 0;\n const [state, setState] = useState<ApplyState>(\n readsLedger ? { status: \"checking\" } : { status: \"idle\" },\n );\n const [elapsed, setElapsed] = useState(0);\n // \"Run again\" asks from the tally; the tally stays on screen while it asks\n // (only its own button goes quiet), never swapped for a disabled Apply.\n const [askingAgain, setAskingAgain] = useState(false);\n const startedAt = useRef<number | null>(null);\n const nounText = nounLabel(directive.noun, host.nouns);\n\n // THE CARD SURVIVES A RELOAD. Component state dies with the page; the\n // server's action ledger does not. Ask it once on mount — and every\n // FINISH_POLL_MS while another request is mid-apply — and render exactly\n // what a fresh apply would have left on screen.\n const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : \"\";\n const read = host.applyState;\n const report = host.reportError;\n useEffect(() => {\n if (!shellKey || !read) return;\n // Parsed back from the key so the effect depends on the shell's CONTENT,\n // never on the per-render identity of `directive.items`.\n const [slug, shellItems, inConversation] = JSON.parse(shellKey) as [\n string,\n Record<string, unknown>[],\n string | null,\n ];\n const shell: DirectiveShell = { __kind: slug, items: shellItems };\n if (inConversation) shell.conversationId = inConversation;\n let live = true;\n let polls = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n const ask = () => {\n read(shell)\n .then((answer) => {\n if (!live) return;\n if (answer.state === \"applied\") {\n setState((prev) =>\n prev.status === \"checking\" || prev.status === \"finishing\"\n ? {\n status: \"applied\",\n applied: shellItems.length,\n failed: 0,\n message: answer.message?.trim() ? answer.message.trim() : null,\n records: answer.records ?? [],\n }\n : prev,\n );\n } else if (answer.state === \"in_flight\" && polls < FINISH_POLLS_MAX) {\n polls += 1;\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"finishing\" } : prev));\n timer = setTimeout(ask, FINISH_POLL_MS);\n } else {\n // Not applied — or still \"in flight\" after a minute, when Apply is\n // the honest offer: confirm is idempotent and replays the receipt.\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"idle\" } : prev));\n }\n })\n .catch((error: unknown) => {\n if (!live) return;\n const why = error instanceof Error && error.message ? error.message : String(error);\n (report ?? console.error)(\n `[kind-directives] Could not read whether ${slug} was already applied: ${why}`,\n );\n setState((prev) => (prev.status === \"checking\" || prev.status === \"finishing\" ? { status: \"idle\" } : prev));\n });\n };\n ask();\n return () => {\n live = false;\n if (timer) clearTimeout(timer);\n };\n }, [shellKey, read, report]);\n\n // An honest clock beats a fake progress bar.\n useEffect(() => {\n if (state.status !== \"applying\") return;\n startedAt.current = Date.now();\n const id = setInterval(\n () => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1000)),\n 1000,\n );\n return () => clearInterval(id);\n }, [state.status]);\n\n if (!directive.parsed.executes) return null;\n const confirm = host.confirm;\n if (!confirm) return null;\n\n /**\n * `again` = \"Run again\": the ledger already holds this block, so a plain\n * confirm would only replay its receipt. The person is asked in words that\n * say it runs a SECOND time, and a yes sends `force`.\n */\n async function handleApply(again = false) {\n if (!confirm) return;\n // A \"no\" to Run again leaves the tally exactly where it was.\n const before = state;\n // THE STATUS TELLS THE TRUTH (reviewer, 2026-09-30): the card used to read\n // \"Applying 1 item…\" while the confirm dialog was still asking. Ask first,\n // idle; only a yes moves the control to \"applying\".\n if (host.ask) {\n if (again) setAskingAgain(true);\n else setState({ status: \"asking\" });\n let ok = false;\n try {\n ok = await host.ask({\n directive,\n items,\n nounLabel: nounText,\n ...(again ? { again: true } : {}),\n });\n } catch (error) {\n setAskingAgain(false);\n setState({\n status: \"error\",\n message:\n error instanceof Error && error.message\n ? error.message\n : \"We could not ask you to confirm this, so nothing was done.\",\n });\n return;\n }\n setAskingAgain(false);\n if (!ok) {\n // Declining is not an error: the card is exactly as it was.\n setState(again ? before : { status: \"idle\" });\n return;\n }\n }\n setElapsed(0);\n setState({ status: \"applying\" });\n try {\n const shell: DirectiveShell = { __kind: directive.slug, items };\n if (conversationId) shell.conversationId = conversationId;\n if (again) shell.force = true;\n const result = await confirm(shell);\n setState({\n status: \"applied\",\n applied: result.applied,\n failed: result.failed,\n message: result.message?.trim() ? result.message.trim() : null,\n records: result.records ?? [],\n });\n onApplied?.();\n } catch (error) {\n setState({\n status: \"error\",\n message:\n error instanceof Error && error.message\n ? error.message\n : \"That couldn't be applied just now. Please try again.\",\n });\n }\n }\n\n if (state.status === \"applied\") {\n const bad = state.failed > 0;\n const trashed = directive.directiveClass === \"delete\";\n const label = nounText;\n // THE TALLY IS A DOOR (no dead ends): the records the apply wrote, each by\n // name and each opening, beside the server's own sentence when it sent one.\n const records = host.renderRecord ? state.records : [];\n return (\n <span\n className={`flex min-w-0 flex-wrap items-center gap-x-2 gap-y-0.5 text-xs ${bad ? \"text-destructive\" : \"text-primary\"}`}\n data-apply-state=\"applied\"\n >\n {/* The glyph rides WITH the sentence: a long server sentence wraps\n beside it, never leaving the icon alone on a line (phone width). */}\n <span className=\"inline-flex min-w-0 items-start gap-1\">\n {bad ? (\n <AlertIcon className=\"mt-px h-3.5 w-3.5 shrink-0\" />\n ) : (\n <CheckCircleIcon className=\"mt-px h-3.5 w-3.5 shrink-0\" />\n )}\n <span className=\"min-w-0\">\n {state.message ?? `Applied ${state.applied}`}\n {bad && !state.message ? ` · ${state.failed} failed` : \"\"}\n </span>\n </span>\n {records.map((record) => (\n <span key={`${record.noun}:${record.id}`} className=\"inline-flex min-w-0 items-center\">\n {host.renderRecord?.({\n ...record,\n fallback: recordFallbackName(label, record.id),\n context: \"applied\",\n trashed,\n })}\n </span>\n ))}\n {/* A failed item was never ledgered, so a plain re-apply retries only\n it. A clean tally offers \"Run again\" — the one way past the\n ledger's dedup, asked in words that say it runs a second time. */}\n <button\n type=\"button\"\n disabled={askingAgain}\n onClick={() => void handleApply(!bad)}\n className=\"inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-50\"\n data-apply-action={bad ? \"retry\" : \"run-again\"}\n >\n <RotateCcwIcon className=\"h-3 w-3\" />\n {bad ? \"Retry\" : \"Run again\"}\n </button>\n </span>\n );\n }\n\n if (state.status === \"checking\") {\n return (\n <span\n className=\"inline-flex h-6 w-6 items-center justify-center text-muted-foreground\"\n role=\"status\"\n aria-label=\"Checking whether this already ran\"\n data-apply-state=\"checking\"\n >\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n </span>\n );\n }\n\n if (state.status === \"finishing\") {\n return (\n <span\n className=\"inline-flex items-center gap-1 text-xs text-muted-foreground\"\n role=\"status\"\n data-apply-state=\"finishing\"\n >\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n Finishing…\n </span>\n );\n }\n\n return (\n <span className=\"inline-flex items-center gap-2\">\n <button\n type=\"button\"\n onClick={() => void handleApply()}\n disabled={state.status === \"applying\" || state.status === \"asking\" || items.length === 0}\n className=\"inline-flex items-center gap-1 rounded-md border border-border bg-background px-2 py-1 text-xs font-medium hover:bg-accent disabled:opacity-50\"\n >\n {state.status === \"applying\" ? (\n <LoaderIcon className=\"h-3.5 w-3.5 animate-spin\" />\n ) : (\n <PlayIcon className=\"h-3.5 w-3.5\" />\n )}\n {state.status === \"applying\"\n ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? \"item\" : \"items\"}` : \"\"}…${elapsed ? ` ${elapsed}s` : \"\"}`\n : label}\n </button>\n {state.status === \"error\" ? (\n <span className=\"inline-flex max-w-sm items-start gap-1 text-xs text-destructive\">\n <AlertIcon className=\"mt-0.5 h-3.5 w-3.5 shrink-0\" />\n <span>{state.message}</span>\n </span>\n ) : null}\n </span>\n );\n}\n\nexport default ApplyDirectiveButton;\n","/**\n * WHAT A DIRECTIVE ITEM WILL DO TO AN EXISTING RECORD — for the card, the\n * confirm dialog, and anything else that must say it before the click.\n *\n * WHY (reviewer, 2026-09-30): an Update card and a Delete card showed each item\n * as \"Item\" — they never named the record they would change, and an Update card\n * never said what it would change. The item-summary helpers name a thing to be\n * CREATED from its own fields; an update or delete item carries the TARGET's id\n * and, for an update, the NEW values — so its \"title\" field is the new title,\n * not the name of the record being changed. Naming the target is the host's\n * live lookup (`DirectiveHost.renderRecord`); what changes is right here.\n *\n * Law: common-docs/policies/destructive-and-expensive-actions.md — the sentence\n * names what changes.\n */\n\nimport { isUuidShape } from \"@ai-matrx/kit/uuid\";\n\n/** Classes whose items point at an EXISTING record by `id`. */\nexport const TARGETING_CLASSES: ReadonlySet<string> = new Set([\"update\", \"delete\"]);\n\n/** Never a change: identity and plumbing. */\nconst NOT_A_CHANGE = new Set<string>([\"__kind\", \"id\"]);\n\n/** How long a changed value may read before it is shortened (full value on hover). */\nexport const CHANGE_VALUE_MAX = 60;\n\n/** The id of the existing record an update/delete item targets, or null. */\nexport function itemRecordId(item: Record<string, unknown>): string | null {\n const id = item.id;\n if (typeof id === \"string\" && id.trim()) return id.trim();\n if (typeof id === \"number\") return String(id);\n return null;\n}\n\n/** \"due_date\" → \"Due date\". Underscores read as developer output. */\nexport function fieldLabel(key: string): string {\n const spaced = key.replace(/_/g, \" \").trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/** A short, honest name for a record we could not look up: \"Task 1a2b3c4d\". */\nexport function recordFallbackName(nounLabel: string, id: string): string {\n const short = isUuidShape(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}…` : id;\n return `${nounLabel} ${short}`;\n}\n\nexport interface ItemChange {\n key: string;\n /** \"Due date\". */\n label: string;\n /** What it becomes, shortened for a row; `full` carries the whole value. */\n value: string;\n full: string;\n /** True when the new value empties the field. */\n clears: boolean;\n}\n\nfunction describeValue(value: unknown): { value: string; full: string; clears: boolean } {\n if (value === null || value === undefined) return { value: \"cleared\", full: \"cleared\", clears: true };\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (!trimmed) return { value: \"cleared\", full: \"cleared\", clears: true };\n const oneLine = trimmed.replace(/\\s+/g, \" \");\n const shown = oneLine.length > CHANGE_VALUE_MAX ? `${oneLine.slice(0, CHANGE_VALUE_MAX - 1)}…` : oneLine;\n return { value: shown, full: trimmed, clears: false };\n }\n if (typeof value === \"number\" || typeof value === \"boolean\") {\n return { value: String(value), full: String(value), clears: false };\n }\n if (Array.isArray(value)) {\n const n = value.length;\n const text = n === 0 ? \"cleared\" : `${n} ${n === 1 ? \"entry\" : \"entries\"}`;\n return { value: text, full: safeJson(value), clears: n === 0 };\n }\n const n = Object.keys(value as object).length;\n const text = n === 0 ? \"cleared\" : `${n} ${n === 1 ? \"field\" : \"fields\"}`;\n return { value: text, full: safeJson(value), clears: n === 0 };\n}\n\nfunction safeJson(value: unknown): string {\n try {\n return JSON.stringify(value, null, 2);\n } catch {\n return String(value);\n }\n}\n\n/**\n * Every field an UPDATE item sets, in the order the item carries them — ALL of\n * them, never a sample: a person approving an overwrite sees the whole of it.\n */\nexport function itemChanges(item: Record<string, unknown>): ItemChange[] {\n const out: ItemChange[] = [];\n for (const [key, raw] of Object.entries(item)) {\n if (NOT_A_CHANGE.has(key)) continue;\n out.push({ key, label: fieldLabel(key), ...describeValue(raw) });\n }\n return out;\n}\n","/**\n * The handful of glyphs the directive cards need, as inline SVG. This package\n * depends on no icon library (see the FEATURE boundary); the paths are the\n * Lucide set's (ISC), so the cards look identical to a Lucide-using host.\n */\n\nimport type { ReactElement, SVGProps } from \"react\";\n\ntype IconProps = SVGProps<SVGSVGElement>;\n\nfunction Svg({ children, ...props }: IconProps) {\n return (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n {...props}\n >\n {children}\n </svg>\n );\n}\n\nexport const FilePlusIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4\" />\n <path d=\"M14 2v4a2 2 0 0 0 2 2h4\" />\n <path d=\"M3 15h6\" />\n <path d=\"M6 12v6\" />\n </Svg>\n);\nexport const PencilIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M12 20h9\" />\n <path d=\"M16.376 3.622a1 1 0 0 1 3.002 3.002L7.368 18.635a2 2 0 0 1-.855.506l-2.872.838a.5.5 0 0 1-.62-.62l.838-2.872a2 2 0 0 1 .506-.854z\" />\n </Svg>\n);\nexport const TrashIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 6h18\" />\n <path d=\"M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6\" />\n <path d=\"M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2\" />\n <line x1=\"10\" x2=\"10\" y1=\"11\" y2=\"17\" />\n <line x1=\"14\" x2=\"14\" y1=\"11\" y2=\"17\" />\n </Svg>\n);\nexport const PlayIcon = (p: IconProps) => (\n <Svg {...p}>\n <polygon points=\"6 3 20 12 6 21 6 3\" />\n </Svg>\n);\nexport const WebhookIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M18 16.98h-5.99c-1.1 0-1.95.94-2.48 1.9A4 4 0 0 1 2 17c.01-.7.2-1.4.57-2\" />\n <path d=\"m6 17 3.13-5.78c.53-.97.1-2.01-.4-2.96A4 4 0 0 1 14 5.5c.63.42 1.13 1 1.44 1.66\" />\n <path d=\"m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8\" />\n </Svg>\n);\nexport const BoxesIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M2.97 12.92A2 2 0 0 0 2 14.63v3.24a2 2 0 0 0 .97 1.71l3 1.8a2 2 0 0 0 2.06 0L12 19v-5.5l-5-3-4.03 2.42Z\" />\n <path d=\"m7 16.5-4.74-2.85\" />\n <path d=\"m7 16.5 5-3\" />\n <path d=\"M7 16.5v5.17\" />\n <path d=\"M12 13.5V19l3.97 2.38a2 2 0 0 0 2.06 0l3-1.8a2 2 0 0 0 .97-1.71v-3.24a2 2 0 0 0-.97-1.71L17 10.5l-5 3Z\" />\n <path d=\"m17 16.5-5-3\" />\n <path d=\"m17 16.5 4.74-2.85\" />\n <path d=\"M17 16.5v5.17\" />\n <path d=\"M7.97 4.42A2 2 0 0 0 7 6.13v4.37l5 3 5-3V6.13a2 2 0 0 0-.97-1.71l-3-1.8a2 2 0 0 0-2.06 0l-3 1.8Z\" />\n <path d=\"M12 8 7.26 5.15\" />\n <path d=\"m12 8 4.74-2.85\" />\n <path d=\"M12 13.5V8\" />\n </Svg>\n);\nexport const ChevronDownIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m6 9 6 6 6-6\" />\n </Svg>\n);\nexport const ChevronRightIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m9 18 6-6-6-6\" />\n </Svg>\n);\nexport const MaximizeIcon = (p: IconProps) => (\n <Svg {...p}>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" x2=\"14\" y1=\"3\" y2=\"10\" />\n <line x1=\"3\" x2=\"10\" y1=\"21\" y2=\"14\" />\n </Svg>\n);\nexport const LoaderIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M21 12a9 9 0 1 1-6.219-8.56\" />\n </Svg>\n);\n/** Lucide `rotate-ccw` — \"Run again\". */\nexport const RotateCcwIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8\" />\n <path d=\"M3 3v5h5\" />\n </Svg>\n);\nexport const CheckCircleIcon = (p: IconProps) => (\n <Svg {...p}>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <path d=\"m9 12 2 2 4-4\" />\n </Svg>\n);\nexport const AlertIcon = (p: IconProps) => (\n <Svg {...p}>\n <path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\" />\n <path d=\"M12 9v4\" />\n <path d=\"M12 17h.01\" />\n </Svg>\n);\n\n/**\n * The icon for a side-effect directive card. THE CLASS LEADS: on a card whose\n * job is \"authorize this write\", the first thing to see is whether this\n * CREATES, CHANGES, or DELETES. A noun override exists only where the platform\n * has a settled visual identity for the thing — agents are a Webhook.\n */\nconst AGENT_NOUNS = new Set([\"create_agent\", \"create_agent_definition\", \"agent\"]);\n\nexport function classIcon(directiveClass: string, noun: string): (p: IconProps) => ReactElement {\n if (directiveClass === \"action\" && AGENT_NOUNS.has(noun)) return WebhookIcon;\n switch (directiveClass) {\n case \"create\":\n return FilePlusIcon;\n case \"update\":\n return PencilIcon;\n case \"delete\":\n return TrashIcon;\n default:\n return PlayIcon;\n }\n}\n","\"use client\";\n\n/**\n * The card for a SIDE-EFFECT directive in content — create / update / delete /\n * action. One card for every shape the server can register, so a person is\n * never asked to approve a write they cannot identify.\n *\n * WHY IT EXISTS (Arman, 2026-08-26): the floor it replaced gave \"a name and\n * then an apply button, which essentially tells the user to click apply and\n * conduct a potentially destructive action without any clue as to what this\n * thing is.\"\n *\n * THE DESIGN:\n * - Say what it IS, from authority — the catalog's own words for the title,\n * the noun's title column for each item, never a guess.\n * - Facts, not prose — a few scalar chips; nesting goes to the panel.\n * - Read before you approve — `View` opens the item through the host's seam,\n * which wraps the item's OWN kind component (THE DIRECTIVE⇄KIND SEAM).\n * - Copy is table stakes, at the batch and at the item (host chrome).\n * - Apply stays exactly where it was — the host's confirm seam.\n *\n * NEVER RETURNS NULL — a shape with no items degrades to a stated line.\n */\n\nimport { useState } from \"react\";\nimport {\n asKindInstance,\n directiveDisplay,\n itemFacts,\n itemSubtitle,\n itemTitle,\n nounLabel,\n nounTitleColumn,\n type DecodedDirective,\n} from \"@ai-matrx/content-ir\";\nimport { ApplyDirectiveButton } from \"./ApplyDirectiveButton\";\nimport { TARGETING_CLASSES, itemChanges, itemRecordId, recordFallbackName } from \"./item-changes\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { ChevronDownIcon, ChevronRightIcon, MaximizeIcon, classIcon } from \"./icons\";\n\nexport interface SideEffectDirectiveCardProps {\n directive: DecodedDirective;\n}\n\n/** How many items render as rows before the rest collapse behind a toggle. */\nconst ROWS_BEFORE_FOLD = 3;\n\nfunction ItemRow({\n directive,\n item,\n index,\n total,\n}: {\n directive: DecodedDirective;\n item: Record<string, unknown>;\n index: number;\n total: number;\n}) {\n const host = useDirectiveHost();\n // An update/delete item points at a record that ALREADY EXISTS: name THAT\n // record (its live name, through the host), never the item's own fields —\n // an update's `title` is the NEW title — and never \"Item\".\n const recordId = TARGETING_CLASSES.has(directive.directiveClass) ? itemRecordId(item) : null;\n if (recordId) {\n return <TargetRow directive={directive} item={item} recordId={recordId} />;\n }\n const titleColumn = nounTitleColumn(directive.noun, host.nouns);\n const title = itemTitle(item, titleColumn, index, total);\n const subtitle = itemSubtitle(item);\n const facts = itemFacts(item);\n const kind = host.itemKind?.(directive.slug) ?? null;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n const openItem = host.openItem;\n\n const body = (\n <>\n {/* THE IDENTITY WINS THE SPACE: the title keeps its intrinsic width and the facts give way. */}\n <span className=\"min-w-0 shrink-0 truncate font-medium text-foreground\">{title}</span>\n <span className=\"hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex\">\n {facts.map((fact) => (\n <span key={fact.key} className=\"truncate text-[11px] text-muted-foreground\">\n {fact.value} {fact.label}\n </span>\n ))}\n </span>\n {subtitle && facts.length === 0 ? (\n <span className=\"hidden truncate text-[11px] text-muted-foreground sm:inline\">{subtitle}</span>\n ) : null}\n {openItem ? (\n <MaximizeIcon className=\"ml-auto h-3 w-3 shrink-0 text-muted-foreground\" />\n ) : null}\n </>\n );\n\n return (\n <div className=\"flex items-center gap-2 py-1 text-xs\">\n {openItem ? (\n <button\n type=\"button\"\n onClick={() =>\n openItem({\n // Stamped so the panel's kind pipeline types it from its own first key.\n item: asKindInstance(item, kind) ?? item,\n itemKind: kind,\n title,\n subtitle: `${display.title} · item ${index + 1} of ${total}`,\n directive,\n index,\n total,\n })\n }\n className=\"flex min-w-0 flex-1 items-center gap-2 rounded px-1 py-0.5 text-left hover:bg-accent hover:text-accent-foreground\"\n title=\"Open to read it\"\n >\n {body}\n </button>\n ) : (\n <span className=\"flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5\">{body}</span>\n )}\n {host.renderCopy?.({ label: title, value: item, kind, size: \"xs\" })}\n </div>\n );\n}\n\n/**\n * ONE row for an item that changes an EXISTING record: the record by its live\n * name (a way to open it, through `renderRecord`), then — for an update —\n * every field it sets, \"Due date → 2026-10-15\".\n */\nfunction TargetRow({\n directive,\n item,\n recordId,\n}: {\n directive: DecodedDirective;\n item: Record<string, unknown>;\n recordId: string;\n}) {\n const host = useDirectiveHost();\n const fallback = recordFallbackName(nounLabel(directive.noun, host.nouns), recordId);\n const changes = directive.directiveClass === \"update\" ? itemChanges(item) : [];\n const name = host.renderRecord ? (\n host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: \"row\" })\n ) : (\n <span className=\"truncate font-medium text-foreground\">{fallback}</span>\n );\n\n return (\n <div className=\"py-1 text-xs\" data-directive-target={recordId}>\n <div className=\"flex min-w-0 items-center gap-2\">\n <span className=\"flex min-w-0 flex-1 items-center gap-1 px-1\">{name}</span>\n {host.renderCopy?.({ label: fallback, value: item, size: \"xs\" })}\n </div>\n {directive.directiveClass === \"update\" ? (\n changes.length === 0 ? (\n <p className=\"px-1 text-[11px] text-muted-foreground\">Sets no fields — nothing would change.</p>\n ) : (\n <ul className=\"mt-0.5 space-y-0.5 px-1\">\n {changes.map((change) => (\n <li\n key={change.key}\n className=\"flex min-w-0 items-baseline gap-1.5 text-[11px]\"\n title={`${change.label} → ${change.full}`}\n >\n <span className=\"shrink-0 text-muted-foreground\">{change.label}</span>\n <span aria-hidden className=\"shrink-0 text-muted-foreground\">→</span>\n <span\n className={`min-w-0 truncate ${change.clears ? \"italic text-muted-foreground\" : \"text-foreground\"}`}\n >\n {change.value}\n </span>\n </li>\n ))}\n </ul>\n )\n ) : null}\n </div>\n );\n}\n\nexport function SideEffectDirectiveCard({ directive }: SideEffectDirectiveCardProps) {\n const host = useDirectiveHost();\n const [expanded, setExpanded] = useState(false);\n const items = directive.items;\n const total = items.length;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n const Icon = classIcon(directive.directiveClass, directive.noun);\n\n const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);\n const hidden = total - shown.length;\n\n return (\n <div className=\"my-3 rounded-md border border-border bg-card px-2.5 py-1.5\" data-directive={directive.slug}>\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <Icon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-sm font-medium text-foreground\">{display.title}</span>\n {display.family ? <span className=\"text-xs text-muted-foreground\">{display.family}</span> : null}\n <span className=\"text-xs tabular-nums text-muted-foreground\">\n {total} {total === 1 ? \"item\" : \"items\"}\n </span>\n <div className=\"ml-auto flex items-center gap-1\">\n {host.renderCopy?.({ label: display.title, value: directive.shell, size: \"icon\" })}\n <ApplyDirectiveButton directive={directive} itemCount={total} />\n </div>\n </div>\n\n {total === 0 ? (\n // Stated, never silent: an empty batch is a real (and suspicious) state.\n <p className=\"mt-1 text-xs text-muted-foreground\">No items — nothing would be written.</p>\n ) : (\n <div className=\"mt-0.5 divide-y divide-border/60\">\n {shown.map((item, i) => (\n <ItemRow key={i} directive={directive} item={item} index={i} total={total} />\n ))}\n </div>\n )}\n\n {hidden > 0 || expanded ? (\n <button\n type=\"button\"\n onClick={() => setExpanded((v) => !v)}\n className=\"mt-0.5 inline-flex items-center gap-1 rounded px-1 py-0.5 text-[11px] text-muted-foreground hover:text-foreground\"\n >\n {expanded ? <ChevronDownIcon className=\"h-3 w-3\" /> : <ChevronRightIcon className=\"h-3 w-3\" />}\n {expanded ? \"Show less\" : `Show ${hidden} more`}\n </button>\n ) : null}\n </div>\n );\n}\n\nexport default SideEffectDirectiveCard;\n","\"use client\";\n\n/**\n * The neutral \"we could not render this, but we will NEVER hide it\" card —\n * THE PREFIX FLOOR of the Kind Directives route.\n *\n * THE RULE THIS ENFORCES: a registered directive renderer must never return\n * `null`. `DirectiveRender` renders a renderer's output verbatim, so a `null`\n * deletes the assistant's whole message block (2026-07-26: a 70KB content plan\n * vanished exactly that way). When a renderer cannot draw its rich view, it\n * renders THIS instead: named by class and noun, itemised by count, with Apply\n * when the class is a side effect and the host can apply.\n */\n\nimport { directiveDisplay, type DecodedDirective } from \"@ai-matrx/content-ir\";\nimport { ApplyDirectiveButton } from \"./ApplyDirectiveButton\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { BoxesIcon } from \"./icons\";\n\nexport interface DirectiveFallbackCardProps {\n directive: DecodedDirective;\n /** Short, human explanation of why the rich renderer degraded. */\n reason?: string;\n}\n\nexport function DirectiveFallbackCard({ directive, reason }: DirectiveFallbackCardProps) {\n const host = useDirectiveHost();\n const count = directive.items.length;\n const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);\n return (\n <div className=\"my-3 inline-flex flex-wrap items-center gap-2 rounded-md border border-border bg-muted px-2.5 py-1 text-sm\">\n <BoxesIcon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-foreground\">{display.title}</span>\n {display.family ? <span className=\"text-muted-foreground\">· {display.family}</span> : null}\n <span className=\"text-muted-foreground\">\n · {count} {count === 1 ? \"item\" : \"items\"}\n </span>\n {reason ? <span className=\"text-muted-foreground\">· {reason}</span> : null}\n <ApplyDirectiveButton directive={directive} />\n </div>\n );\n}\n\nexport default DirectiveFallbackCard;\n","\"use client\";\n\n/**\n * The card for a directive whose JSON has NOT finished arriving — the\n * provisional tier of `DirectiveRender`.\n *\n * WHY IT EXISTS (found live 2026-09-25, the agent builder's\n * `directive_v1_action_create_agent_definition` in the agent run window): an\n * agent streams a directive as one JSON document, `__kind` first. Every splitter\n * already types the block as a directive from its first bytes\n * (`looksLikeDirectiveHead`), but the decoder can only honour a COMPLETE shell,\n * so for the whole stream `DirectiveRender` fell to its raw `<pre>` — the person\n * watched a wall of JSON grow and then snap into a card at the last byte.\n *\n * The head already says what this is (class + noun), so the card says it from\n * the first bytes, from the same catalog words the finished card uses:\n *\n * - STREAMING — \"Create agent definition · writing…\". No Apply: nothing is\n * applicable until the shell is whole.\n * - NOT STREAMING, still undecodable — the document was cut off (a model hit\n * its output limit, a stream died). Said plainly, never dressed as\n * \"writing…\" forever, with what did arrive one click away.\n *\n * NEVER RETURNS NULL.\n */\n\nimport { directiveDisplay, parseDirectiveSlug } from \"@ai-matrx/content-ir\";\nimport { useDirectiveHost } from \"./directive-host\";\nimport { BoxesIcon, classIcon } from \"./icons\";\n\n/** A head whose slug has fully arrived: `{\"__kind\":\"directive_v1_…\"` + closing quote. */\nconst COMPLETE_SLUG_RE = /^\\{\\s*\"__kind\"\\s*:\\s*\"([^\"]+)\"/;\n\n/** The directive slug of a partial document, once its closing quote has arrived. */\nexport function provisionalDirectiveSlug(content: string): string | null {\n const match = content.trimStart().match(COMPLETE_SLUG_RE);\n return match?.[1] ?? null;\n}\n\nexport interface DirectiveProvisionalCardProps {\n /** The partial fence body as received so far. */\n content: string;\n /**\n * Whether the document may still be arriving. `false` means the stream is\n * over and the document never completed — the card says it was cut off.\n */\n streaming: boolean;\n className?: string | undefined;\n}\n\nexport function DirectiveProvisionalCard({ content, streaming, className }: DirectiveProvisionalCardProps) {\n const host = useDirectiveHost();\n const slug = provisionalDirectiveSlug(content);\n const known = slug ? parseDirectiveSlug(slug) : null;\n const display = known ? directiveDisplay(known.directiveClass, known.noun, host.nouns) : null;\n const Icon = known ? classIcon(known.directiveClass, known.noun) : BoxesIcon;\n const title = display?.title ?? \"Structured action\";\n\n return (\n <div\n className={`my-3 rounded-md border border-border bg-card px-2.5 py-1.5${className ? ` ${className}` : \"\"}`}\n data-directive={slug ?? undefined}\n data-directive-state={streaming ? \"streaming\" : \"incomplete\"}\n >\n <div className=\"flex flex-wrap items-center gap-x-2 gap-y-1\">\n <Icon className=\"h-3.5 w-3.5 shrink-0 text-muted-foreground\" />\n <span className=\"text-sm font-medium text-foreground\">{title}</span>\n {display?.family ? <span className=\"text-xs text-muted-foreground\">{display.family}</span> : null}\n {streaming ? (\n <span className=\"inline-flex items-center gap-1.5 text-xs text-muted-foreground\" role=\"status\">\n <span className=\"h-1.5 w-1.5 animate-pulse rounded-full bg-primary\" aria-hidden />\n Writing…\n </span>\n ) : (\n <span className=\"text-xs text-destructive\" role=\"status\">\n Cut off before it finished — nothing can be applied.\n </span>\n )}\n </div>\n {streaming ? null : (\n <details className=\"mt-1 text-xs text-muted-foreground\">\n <summary className=\"cursor-pointer select-none hover:text-foreground\">Show what arrived</summary>\n <pre className=\"mt-1 max-h-64 overflow-auto whitespace-pre-wrap break-all rounded bg-muted px-2 py-1 text-[11px]\">\n {content}\n </pre>\n </details>\n )}\n </div>\n );\n}\n\nexport default DirectiveProvisionalCard;\n","\"use client\";\n\n/**\n * DirectiveRender — THE renderer for anything whose `__kind` is a reserved\n * directive slug, on every AI Matrx UI.\n *\n * Pipeline (one pipeline, mirroring the backend):\n * 0. THE PROVISIONAL TIER — a head that names a directive but does not\n * decode yet renders `DirectiveProvisionalCard` (\"writing…\" while\n * streaming, \"cut off\" once the host says the stream ended).\n * 1. `tryDecodeDirectiveContent` → the two-key shell (a stored 4-key fence is\n * translated inside the decoder). Not a directive (bad JSON / no reserved\n * `__kind`) → raw <pre>, never throws. An unhonourable shell is REPORTED\n * through the host and falls to raw — a render seam must not take a whole\n * message block down over one fence, and must never go silent.\n * 2. `getDirectiveRenderer` → exact slug, else the CLASS prefix rule (the\n * host's registrations). Found → render it.\n * 3. THE SIDE-EFFECT TIER — every create / update / delete / action shape\n * renders the side-effect card, so a person is never asked to approve a\n * write they cannot identify.\n * 4. THE FLOOR — a class nothing registers still shows the fallback card.\n * Never null, never silent.\n *\n * Position decides capability: in content only `reference`/`secret` resolve;\n * a side-effect directive in prose is a card with an explicit Apply, never\n * executed on sight.\n */\n\nimport { looksLikeDirectiveHead, tryDecodeDirectiveContent } from \"@ai-matrx/content-ir\";\nimport { DirectiveScopeProvider, useDirectiveHost } from \"./directive-host\";\nimport { DirectiveFallbackCard } from \"./DirectiveFallbackCard\";\nimport { DirectiveProvisionalCard } from \"./DirectiveProvisionalCard\";\nimport { getDirectiveRenderer } from \"./registry\";\nimport { SideEffectDirectiveCard } from \"./SideEffectDirectiveCard\";\n\nexport interface DirectiveRenderProps {\n /** The fence body (JSON string) or an already-parsed shell / value. */\n content: unknown;\n className?: string;\n /**\n * Whether the document may still be arriving. A host that knows its stream\n * has ended passes `false`, so an undecodable directive head is shown as CUT\n * OFF rather than \"writing…\" forever. Omitted = it may still be arriving.\n */\n streaming?: boolean;\n /**\n * The conversation this directive renders in (a chat message). Applies and\n * ledger reads key on it — the same namespace an agent proposal's Approve\n * uses — so one action can never apply twice through two doors. Omit in a\n * person's own content. Overrides any enclosing `DirectiveScopeProvider`.\n */\n conversationId?: string | null;\n}\n\n/**\n * A document that parses is WHOLE: if it still does not decode, it is a\n * malformed directive (already reported by the decoder), never one \"still\n * arriving\" — only a genuinely unfinished document gets the provisional tier.\n */\nfunction isWholeJson(content: string): boolean {\n try {\n JSON.parse(content);\n return true;\n } catch {\n return false;\n }\n}\n\nexport function DirectiveRender({ conversationId, ...props }: DirectiveRenderProps) {\n if (conversationId === undefined) return <DirectiveRenderInner {...props} />;\n return (\n <DirectiveScopeProvider conversationId={conversationId}>\n <DirectiveRenderInner {...props} />\n </DirectiveScopeProvider>\n );\n}\n\nfunction DirectiveRenderInner({ content, className, streaming }: Omit<DirectiveRenderProps, \"conversationId\">) {\n const host = useDirectiveHost();\n const directive = tryDecodeDirectiveContent(content, (message) => {\n const line = `[kind-directives] ${message}`;\n if (host.reportError) host.reportError(line);\n else console.error(line);\n });\n\n if (!directive) {\n // THE PROVISIONAL TIER: the head already names a directive but the shell is\n // not whole yet (mid-stream) or never became whole (cut off). The class and\n // noun are known from the first bytes — say what it is, never show the\n // growing JSON as if it were the answer.\n if (typeof content === \"string\" && looksLikeDirectiveHead(content) && !isWholeJson(content)) {\n return (\n <DirectiveProvisionalCard content={content} streaming={streaming !== false} className={className} />\n );\n }\n const raw = typeof content === \"string\" ? content : JSON.stringify(content, null, 2);\n return (\n <pre\n className={`my-3 overflow-x-auto rounded-md border border-border bg-muted px-3 py-2 text-xs text-muted-foreground${className ? ` ${className}` : \"\"}`}\n >\n {raw}\n </pre>\n );\n }\n\n const Renderer = getDirectiveRenderer(directive);\n if (Renderer) return <Renderer directive={directive} />;\n if (directive.parsed.executes) return <SideEffectDirectiveCard directive={directive} />;\n return <DirectiveFallbackCard directive={directive} />;\n}\n\nexport default DirectiveRender;\n"],"mappings":"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","names":["import_react","import_content_ir","nounLabel","n","text","import_jsx_runtime","import_jsx_runtime","label","import_react","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime","import_content_ir","import_jsx_runtime"]}
@@ -215,6 +215,7 @@ function ApplyDirectiveButton({
215
215
  readsLedger ? { status: "checking" } : { status: "idle" }
216
216
  );
217
217
  const [elapsed, setElapsed] = useState(0);
218
+ const [askingAgain, setAskingAgain] = useState(false);
218
219
  const startedAt = useRef(null);
219
220
  const nounText = nounLabel(directive.noun, host.nouns);
220
221
  const shellKey = readsLedger ? JSON.stringify([directive.slug, items, conversationId ?? null]) : "";
@@ -279,7 +280,8 @@ function ApplyDirectiveButton({
279
280
  if (!confirm) return;
280
281
  const before = state;
281
282
  if (host.ask) {
282
- setState({ status: "asking" });
283
+ if (again) setAskingAgain(true);
284
+ else setState({ status: "asking" });
283
285
  let ok = false;
284
286
  try {
285
287
  ok = await host.ask({
@@ -289,12 +291,14 @@ function ApplyDirectiveButton({
289
291
  ...again ? { again: true } : {}
290
292
  });
291
293
  } catch (error) {
294
+ setAskingAgain(false);
292
295
  setState({
293
296
  status: "error",
294
297
  message: error instanceof Error && error.message ? error.message : "We could not ask you to confirm this, so nothing was done."
295
298
  });
296
299
  return;
297
300
  }
301
+ setAskingAgain(false);
298
302
  if (!ok) {
299
303
  setState(again ? before : { status: "idle" });
300
304
  return;
@@ -350,8 +354,9 @@ function ApplyDirectiveButton({
350
354
  "button",
351
355
  {
352
356
  type: "button",
357
+ disabled: askingAgain,
353
358
  onClick: () => void handleApply(!bad),
354
- className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground",
359
+ className: "inline-flex items-center gap-1 rounded px-1 py-0.5 text-muted-foreground hover:bg-accent hover:text-accent-foreground disabled:opacity-50",
355
360
  "data-apply-action": bad ? "retry" : "run-again",
356
361
  children: [
357
362
  /* @__PURE__ */ jsx3(RotateCcwIcon, { className: "h-3 w-3" }),