@ai-matrx/content-ir-react 0.11.10 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.cjs CHANGED
@@ -115,16 +115,73 @@ function useContentIrKindVersion(kind, sources) {
115
115
 
116
116
  // react/KindInstanceRender.tsx
117
117
  var import_react6 = require("react");
118
- var import_content_ir6 = require("@ai-matrx/content-ir");
118
+ var import_content_ir8 = require("@ai-matrx/content-ir");
119
119
 
120
120
  // directives/DirectiveRender.tsx
121
- var import_content_ir4 = require("@ai-matrx/content-ir");
121
+ var import_content_ir6 = require("@ai-matrx/content-ir");
122
122
 
123
123
  // directives/DirectiveFallbackCard.tsx
124
- var import_content_ir = require("@ai-matrx/content-ir");
124
+ var import_content_ir2 = require("@ai-matrx/content-ir");
125
125
 
126
126
  // directives/ApplyDirectiveButton.tsx
127
127
  var import_react4 = require("react");
128
+ var import_content_ir = require("@ai-matrx/content-ir");
129
+
130
+ // directives/item-changes.ts
131
+ var TARGETING_CLASSES = /* @__PURE__ */ new Set(["update", "delete"]);
132
+ var NOT_A_CHANGE = /* @__PURE__ */ new Set(["__kind", "id"]);
133
+ var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
134
+ var CHANGE_VALUE_MAX = 60;
135
+ function itemRecordId(item) {
136
+ const id = item.id;
137
+ if (typeof id === "string" && id.trim()) return id.trim();
138
+ if (typeof id === "number") return String(id);
139
+ return null;
140
+ }
141
+ function fieldLabel(key) {
142
+ const spaced = key.replace(/_/g, " ").trim();
143
+ return spaced.charAt(0).toUpperCase() + spaced.slice(1);
144
+ }
145
+ function recordFallbackName(nounLabel3, id) {
146
+ const short = UUID_RE.test(id) ? id.slice(0, 8) : id.length > 12 ? `${id.slice(0, 12)}\u2026` : id;
147
+ return `${nounLabel3} ${short}`;
148
+ }
149
+ function describeValue(value) {
150
+ if (value === null || value === void 0) return { value: "cleared", full: "cleared", clears: true };
151
+ if (typeof value === "string") {
152
+ const trimmed = value.trim();
153
+ if (!trimmed) return { value: "cleared", full: "cleared", clears: true };
154
+ const oneLine = trimmed.replace(/\s+/g, " ");
155
+ const shown = oneLine.length > CHANGE_VALUE_MAX ? `${oneLine.slice(0, CHANGE_VALUE_MAX - 1)}\u2026` : oneLine;
156
+ return { value: shown, full: trimmed, clears: false };
157
+ }
158
+ if (typeof value === "number" || typeof value === "boolean") {
159
+ return { value: String(value), full: String(value), clears: false };
160
+ }
161
+ if (Array.isArray(value)) {
162
+ const n2 = value.length;
163
+ const text2 = n2 === 0 ? "cleared" : `${n2} ${n2 === 1 ? "entry" : "entries"}`;
164
+ return { value: text2, full: safeJson(value), clears: n2 === 0 };
165
+ }
166
+ const n = Object.keys(value).length;
167
+ const text = n === 0 ? "cleared" : `${n} ${n === 1 ? "field" : "fields"}`;
168
+ return { value: text, full: safeJson(value), clears: n === 0 };
169
+ }
170
+ function safeJson(value) {
171
+ try {
172
+ return JSON.stringify(value, null, 2);
173
+ } catch {
174
+ return String(value);
175
+ }
176
+ }
177
+ function itemChanges(item) {
178
+ const out = [];
179
+ for (const [key, raw] of Object.entries(item)) {
180
+ if (NOT_A_CHANGE.has(key)) continue;
181
+ out.push({ key, label: fieldLabel(key), ...describeValue(raw) });
182
+ }
183
+ return out;
184
+ }
128
185
 
129
186
  // directives/icons.tsx
130
187
  var import_jsx_runtime3 = require("react/jsx-runtime");
@@ -242,10 +299,38 @@ function ApplyDirectiveButton({
242
299
  const items = directive.items;
243
300
  async function handleApply() {
244
301
  if (!confirm) return;
302
+ if (host.ask) {
303
+ setState({ status: "asking" });
304
+ let ok = false;
305
+ try {
306
+ ok = await host.ask({
307
+ directive,
308
+ items,
309
+ nounLabel: (0, import_content_ir.nounLabel)(directive.noun, host.nouns)
310
+ });
311
+ } catch (error) {
312
+ setState({
313
+ status: "error",
314
+ message: error instanceof Error && error.message ? error.message : "We could not ask you to confirm this, so nothing was done."
315
+ });
316
+ return;
317
+ }
318
+ if (!ok) {
319
+ setState({ status: "idle" });
320
+ return;
321
+ }
322
+ }
323
+ setElapsed(0);
245
324
  setState({ status: "applying" });
246
325
  try {
247
326
  const result = await confirm({ __kind: directive.slug, items });
248
- setState({ status: "applied", applied: result.applied, failed: result.failed });
327
+ setState({
328
+ status: "applied",
329
+ applied: result.applied,
330
+ failed: result.failed,
331
+ message: result.message?.trim() ? result.message.trim() : null,
332
+ records: result.records ?? []
333
+ });
249
334
  onApplied?.();
250
335
  } catch (error) {
251
336
  setState({
@@ -256,15 +341,26 @@ function ApplyDirectiveButton({
256
341
  }
257
342
  if (state.status === "applied") {
258
343
  const bad = state.failed > 0;
344
+ const trashed = directive.directiveClass === "delete";
345
+ const label2 = (0, import_content_ir.nounLabel)(directive.noun, host.nouns);
346
+ const records = host.renderRecord ? state.records : [];
259
347
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
260
348
  "span",
261
349
  {
262
- className: `inline-flex items-center gap-1 text-xs ${bad ? "text-destructive" : "text-primary"}`,
350
+ className: `inline-flex min-w-0 flex-wrap items-center gap-1 text-xs ${bad ? "text-destructive" : "text-primary"}`,
351
+ "data-apply-state": "applied",
263
352
  children: [
264
- bad ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AlertIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckCircleIcon, { className: "h-3.5 w-3.5" }),
265
- "Applied ",
266
- state.applied,
267
- bad ? ` \xB7 ${state.failed} failed` : ""
353
+ bad ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AlertIcon, { className: "h-3.5 w-3.5 shrink-0" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(CheckCircleIcon, { className: "h-3.5 w-3.5 shrink-0" }),
354
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { children: [
355
+ state.message ?? `Applied ${state.applied}`,
356
+ bad && !state.message ? ` \xB7 ${state.failed} failed` : ""
357
+ ] }),
358
+ records.map((record) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "inline-flex min-w-0 items-center", children: host.renderRecord?.({
359
+ ...record,
360
+ fallback: recordFallbackName(label2, record.id),
361
+ context: "applied",
362
+ trashed
363
+ }) }, `${record.noun}:${record.id}`))
268
364
  ]
269
365
  }
270
366
  );
@@ -275,7 +371,7 @@ function ApplyDirectiveButton({
275
371
  {
276
372
  type: "button",
277
373
  onClick: () => void handleApply(),
278
- disabled: state.status === "applying" || items.length === 0,
374
+ disabled: state.status === "applying" || state.status === "asking" || items.length === 0,
279
375
  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",
280
376
  children: [
281
377
  state.status === "applying" ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PlayIcon, { className: "h-3.5 w-3.5" }),
@@ -295,7 +391,7 @@ var import_jsx_runtime5 = require("react/jsx-runtime");
295
391
  function DirectiveFallbackCard({ directive, reason }) {
296
392
  const host = useDirectiveHost();
297
393
  const count = directive.items.length;
298
- const display = (0, import_content_ir.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
394
+ const display = (0, import_content_ir2.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
299
395
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("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", children: [
300
396
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(BoxesIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
301
397
  /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "text-foreground", children: display.title }),
@@ -317,8 +413,48 @@ function DirectiveFallbackCard({ directive, reason }) {
317
413
  ] });
318
414
  }
319
415
 
416
+ // directives/DirectiveProvisionalCard.tsx
417
+ var import_content_ir3 = require("@ai-matrx/content-ir");
418
+ var import_jsx_runtime6 = require("react/jsx-runtime");
419
+ var COMPLETE_SLUG_RE = /^\{\s*"__kind"\s*:\s*"([^"]+)"/;
420
+ function provisionalDirectiveSlug(content) {
421
+ const match = content.trimStart().match(COMPLETE_SLUG_RE);
422
+ return match?.[1] ?? null;
423
+ }
424
+ function DirectiveProvisionalCard({ content, streaming, className }) {
425
+ const host = useDirectiveHost();
426
+ const slug = provisionalDirectiveSlug(content);
427
+ const known = slug ? (0, import_content_ir3.parseDirectiveSlug)(slug) : null;
428
+ const display = known ? (0, import_content_ir3.directiveDisplay)(known.directiveClass, known.noun, host.nouns) : null;
429
+ const Icon = known ? classIcon(known.directiveClass, known.noun) : BoxesIcon;
430
+ const title = display?.title ?? "Structured action";
431
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
432
+ "div",
433
+ {
434
+ className: `my-3 rounded-md border border-border bg-card px-2.5 py-1.5${className ? ` ${className}` : ""}`,
435
+ "data-directive": slug ?? void 0,
436
+ "data-directive-state": streaming ? "streaming" : "incomplete",
437
+ children: [
438
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
439
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
440
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-foreground", children: title }),
441
+ display?.family ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs text-muted-foreground", children: display.family }) : null,
442
+ streaming ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "inline-flex items-center gap-1.5 text-xs text-muted-foreground", role: "status", children: [
443
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "h-1.5 w-1.5 animate-pulse rounded-full bg-primary", "aria-hidden": true }),
444
+ "Writing\u2026"
445
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs text-destructive", role: "status", children: "Cut off before it finished \u2014 nothing can be applied." })
446
+ ] }),
447
+ streaming ? null : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("details", { className: "mt-1 text-xs text-muted-foreground", children: [
448
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("summary", { className: "cursor-pointer select-none hover:text-foreground", children: "Show what arrived" }),
449
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("pre", { className: "mt-1 max-h-64 overflow-auto whitespace-pre-wrap break-all rounded bg-muted px-2 py-1 text-[11px]", children: content })
450
+ ] })
451
+ ]
452
+ }
453
+ );
454
+ }
455
+
320
456
  // directives/registry.ts
321
- var import_content_ir2 = require("@ai-matrx/content-ir");
457
+ var import_content_ir4 = require("@ai-matrx/content-ir");
322
458
  var REGISTRY_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.content-ir-react.directive-renderers");
323
459
  var registry = globalThis[REGISTRY_SLOT] ??= {
324
460
  bySlug: /* @__PURE__ */ new Map(),
@@ -330,8 +466,8 @@ function getDirectiveRenderer(directive) {
330
466
 
331
467
  // directives/SideEffectDirectiveCard.tsx
332
468
  var import_react5 = require("react");
333
- var import_content_ir3 = require("@ai-matrx/content-ir");
334
- var import_jsx_runtime6 = require("react/jsx-runtime");
469
+ var import_content_ir5 = require("@ai-matrx/content-ir");
470
+ var import_jsx_runtime7 = require("react/jsx-runtime");
335
471
  var ROWS_BEFORE_FOLD = 3;
336
472
  function ItemRow({
337
473
  directive,
@@ -340,31 +476,35 @@ function ItemRow({
340
476
  total
341
477
  }) {
342
478
  const host = useDirectiveHost();
343
- const titleColumn = (0, import_content_ir3.nounTitleColumn)(directive.noun, host.nouns);
344
- const title = (0, import_content_ir3.itemTitle)(item, titleColumn, index, total);
345
- const subtitle = (0, import_content_ir3.itemSubtitle)(item);
346
- const facts = (0, import_content_ir3.itemFacts)(item);
479
+ const recordId = TARGETING_CLASSES.has(directive.directiveClass) ? itemRecordId(item) : null;
480
+ if (recordId) {
481
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(TargetRow, { directive, item, recordId });
482
+ }
483
+ const titleColumn = (0, import_content_ir5.nounTitleColumn)(directive.noun, host.nouns);
484
+ const title = (0, import_content_ir5.itemTitle)(item, titleColumn, index, total);
485
+ const subtitle = (0, import_content_ir5.itemSubtitle)(item);
486
+ const facts = (0, import_content_ir5.itemFacts)(item);
347
487
  const kind = host.itemKind?.(directive.slug) ?? null;
348
- const display = (0, import_content_ir3.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
488
+ const display = (0, import_content_ir5.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
349
489
  const openItem = host.openItem;
350
- const body = /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
351
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "min-w-0 shrink-0 truncate font-medium text-foreground", children: title }),
352
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex", children: facts.map((fact) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "truncate text-[11px] text-muted-foreground", children: [
490
+ const body = /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
491
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "min-w-0 shrink-0 truncate font-medium text-foreground", children: title }),
492
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex", children: facts.map((fact) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "truncate text-[11px] text-muted-foreground", children: [
353
493
  fact.value,
354
494
  " ",
355
495
  fact.label
356
496
  ] }, fact.key)) }),
357
- subtitle && facts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "hidden truncate text-[11px] text-muted-foreground sm:inline", children: subtitle }) : null,
358
- openItem ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(MaximizeIcon, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground" }) : null
497
+ subtitle && facts.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "hidden truncate text-[11px] text-muted-foreground sm:inline", children: subtitle }) : null,
498
+ openItem ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(MaximizeIcon, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground" }) : null
359
499
  ] });
360
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
361
- openItem ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
500
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
501
+ openItem ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
362
502
  "button",
363
503
  {
364
504
  type: "button",
365
505
  onClick: () => openItem({
366
506
  // Stamped so the panel's kind pipeline types it from its own first key.
367
- item: (0, import_content_ir3.asKindInstance)(item, kind) ?? item,
507
+ item: (0, import_content_ir5.asKindInstance)(item, kind) ?? item,
368
508
  itemKind: kind,
369
509
  title,
370
510
  subtitle: `${display.title} \xB7 item ${index + 1} of ${total}`,
@@ -376,46 +516,81 @@ function ItemRow({
376
516
  title: "Open to read it",
377
517
  children: body
378
518
  }
379
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5", children: body }),
519
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5", children: body }),
380
520
  host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
381
521
  ] });
382
522
  }
523
+ function TargetRow({
524
+ directive,
525
+ item,
526
+ recordId
527
+ }) {
528
+ const host = useDirectiveHost();
529
+ const fallback = recordFallbackName((0, import_content_ir5.nounLabel)(directive.noun, host.nouns), recordId);
530
+ const changes = directive.directiveClass === "update" ? itemChanges(item) : [];
531
+ const name = host.renderRecord ? host.renderRecord({ noun: directive.noun, id: recordId, fallback, context: "row" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "truncate font-medium text-foreground", children: fallback });
532
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "py-1 text-xs", "data-directive-target": recordId, children: [
533
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex min-w-0 items-center gap-2", children: [
534
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "flex min-w-0 flex-1 items-center gap-1 px-1", children: name }),
535
+ host.renderCopy?.({ label: fallback, value: item, size: "xs" })
536
+ ] }),
537
+ directive.directiveClass === "update" ? changes.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "px-1 text-[11px] text-muted-foreground", children: "Sets no fields \u2014 nothing would change." }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("ul", { className: "mt-0.5 space-y-0.5 px-1", children: changes.map((change) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
538
+ "li",
539
+ {
540
+ className: "flex min-w-0 items-baseline gap-1.5 text-[11px]",
541
+ title: `${change.label} \u2192 ${change.full}`,
542
+ children: [
543
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "shrink-0 text-muted-foreground", children: change.label }),
544
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": true, className: "shrink-0 text-muted-foreground", children: "\u2192" }),
545
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
546
+ "span",
547
+ {
548
+ className: `min-w-0 truncate ${change.clears ? "italic text-muted-foreground" : "text-foreground"}`,
549
+ children: change.value
550
+ }
551
+ )
552
+ ]
553
+ },
554
+ change.key
555
+ )) }) : null
556
+ ] });
557
+ }
383
558
  function SideEffectDirectiveCard({ directive }) {
384
559
  const host = useDirectiveHost();
385
560
  const [expanded, setExpanded] = (0, import_react5.useState)(false);
386
561
  const items = directive.items;
387
562
  const total = items.length;
388
- const display = (0, import_content_ir3.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
563
+ const display = (0, import_content_ir5.directiveDisplay)(directive.directiveClass, directive.noun, host.nouns);
389
564
  const Icon = classIcon(directive.directiveClass, directive.noun);
390
565
  const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);
391
566
  const hidden = total - shown.length;
392
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "my-3 rounded-md border border-border bg-card px-2.5 py-1.5", "data-directive": directive.slug, children: [
393
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
394
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
395
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm font-medium text-foreground", children: display.title }),
396
- display.family ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-xs text-muted-foreground", children: display.family }) : null,
397
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs tabular-nums text-muted-foreground", children: [
567
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "my-3 rounded-md border border-border bg-card px-2.5 py-1.5", "data-directive": directive.slug, children: [
568
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
569
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
570
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-sm font-medium text-foreground", children: display.title }),
571
+ display.family ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-xs text-muted-foreground", children: display.family }) : null,
572
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { className: "text-xs tabular-nums text-muted-foreground", children: [
398
573
  total,
399
574
  " ",
400
575
  total === 1 ? "item" : "items"
401
576
  ] }),
402
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "ml-auto flex items-center gap-1", children: [
577
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "ml-auto flex items-center gap-1", children: [
403
578
  host.renderCopy?.({ label: display.title, value: directive.shell, size: "icon" }),
404
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ApplyDirectiveButton, { directive, itemCount: total })
579
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ApplyDirectiveButton, { directive, itemCount: total })
405
580
  ] })
406
581
  ] }),
407
582
  total === 0 ? (
408
583
  // Stated, never silent: an empty batch is a real (and suspicious) state.
409
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
410
- ) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ItemRow, { directive, item, index: i, total }, i)) }),
411
- hidden > 0 || expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
584
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
585
+ ) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ItemRow, { directive, item, index: i, total }, i)) }),
586
+ hidden > 0 || expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
412
587
  "button",
413
588
  {
414
589
  type: "button",
415
590
  onClick: () => setExpanded((v) => !v),
416
591
  className: "mt-0.5 inline-flex items-center gap-1 rounded px-1 py-0.5 text-[11px] text-muted-foreground hover:text-foreground",
417
592
  children: [
418
- expanded ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronDownIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(ChevronRightIcon, { className: "h-3 w-3" }),
593
+ expanded ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronDownIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ChevronRightIcon, { className: "h-3 w-3" }),
419
594
  expanded ? "Show less" : `Show ${hidden} more`
420
595
  ]
421
596
  }
@@ -424,17 +599,28 @@ function SideEffectDirectiveCard({ directive }) {
424
599
  }
425
600
 
426
601
  // directives/DirectiveRender.tsx
427
- var import_jsx_runtime7 = require("react/jsx-runtime");
428
- function DirectiveRender({ content, className }) {
602
+ var import_jsx_runtime8 = require("react/jsx-runtime");
603
+ function isWholeJson(content) {
604
+ try {
605
+ JSON.parse(content);
606
+ return true;
607
+ } catch {
608
+ return false;
609
+ }
610
+ }
611
+ function DirectiveRender({ content, className, streaming }) {
429
612
  const host = useDirectiveHost();
430
- const directive = (0, import_content_ir4.tryDecodeDirectiveContent)(content, (message) => {
613
+ const directive = (0, import_content_ir6.tryDecodeDirectiveContent)(content, (message) => {
431
614
  const line = `[kind-directives] ${message}`;
432
615
  if (host.reportError) host.reportError(line);
433
616
  else console.error(line);
434
617
  });
435
618
  if (!directive) {
619
+ if (typeof content === "string" && (0, import_content_ir6.looksLikeDirectiveHead)(content) && !isWholeJson(content)) {
620
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DirectiveProvisionalCard, { content, streaming: streaming !== false, className });
621
+ }
436
622
  const raw = typeof content === "string" ? content : JSON.stringify(content, null, 2);
437
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
623
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
438
624
  "pre",
439
625
  {
440
626
  className: `my-3 overflow-x-auto rounded-md border border-border bg-muted px-3 py-2 text-xs text-muted-foreground${className ? ` ${className}` : ""}`,
@@ -443,13 +629,13 @@ function DirectiveRender({ content, className }) {
443
629
  );
444
630
  }
445
631
  const Renderer = getDirectiveRenderer(directive);
446
- if (Renderer) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Renderer, { directive });
447
- if (directive.parsed.executes) return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SideEffectDirectiveCard, { directive });
448
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(DirectiveFallbackCard, { directive });
632
+ if (Renderer) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(Renderer, { directive });
633
+ if (directive.parsed.executes) return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(SideEffectDirectiveCard, { directive });
634
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(DirectiveFallbackCard, { directive });
449
635
  }
450
636
 
451
637
  // route/kind-route.ts
452
- var import_content_ir5 = require("@ai-matrx/content-ir");
638
+ var import_content_ir7 = require("@ai-matrx/content-ir");
453
639
  var IR_ROUTE_KEY = "__ir_route";
454
640
  var GENERIC_STRUCTURED_COMPONENT_KEY = "generic_structured";
455
641
  var SOURCELESS_DB_ROW_SLOT = /* @__PURE__ */ Symbol.for(
@@ -468,20 +654,20 @@ function readIrRouteMarker(metadata) {
468
654
  }
469
655
 
470
656
  // react/KindInstanceRender.tsx
471
- var import_jsx_runtime8 = require("react/jsx-runtime");
657
+ var import_jsx_runtime9 = require("react/jsx-runtime");
472
658
  function isRecordValue(value) {
473
659
  return typeof value === "object" && value !== null && !Array.isArray(value);
474
660
  }
475
661
  function kindIsRoutable(kind, host) {
476
- if ((0, import_content_ir6.isReservedDirectiveSlug)(kind)) return true;
662
+ if ((0, import_content_ir8.isReservedDirectiveSlug)(kind)) return true;
477
663
  if (host.kinds.getDefinition(kind)?.legacyBlockType) return true;
478
664
  const resolution = host.components.resolve(kind, host.platform, "output");
479
665
  if (!resolution?.isActive) return false;
480
666
  return resolution.componentKey !== GENERIC_STRUCTURED_COMPONENT_KEY;
481
667
  }
482
668
  function KindInstanceRender(props) {
483
- if ((0, import_content_ir6.isReservedDirectiveSlug)(props.kind)) {
484
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
669
+ if ((0, import_content_ir8.isReservedDirectiveSlug)(props.kind)) {
670
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
485
671
  DirectiveRender,
486
672
  {
487
673
  content: props.value,
@@ -489,7 +675,7 @@ function KindInstanceRender(props) {
489
675
  }
490
676
  );
491
677
  }
492
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(KindInstanceRenderInner, { ...props });
678
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(KindInstanceRenderInner, { ...props });
493
679
  }
494
680
  function KindInstanceRenderInner({
495
681
  kind,
@@ -535,18 +721,18 @@ function KindInstanceRenderInner({
535
721
  content: JSON.stringify(value, null, 2),
536
722
  language: "json",
537
723
  metadata: {
538
- [import_content_ir6.IR_ENVELOPE_KEY]: (0, import_content_ir6.envelopeFromCompleteValue)(value, kind)
724
+ [import_content_ir8.IR_ENVELOPE_KEY]: (0, import_content_ir8.envelopeFromCompleteValue)(value, kind)
539
725
  }
540
726
  } : null;
541
727
  const frameClass = variant === "bare" ? void 0 : "rounded-md border border-border bg-card p-3";
542
728
  if (routingStatus === "unroutable" && unroutableFallback !== void 0) {
543
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(import_jsx_runtime8.Fragment, { children: unroutableFallback });
729
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(import_jsx_runtime9.Fragment, { children: unroutableFallback });
544
730
  }
545
731
  const onTheFloor = block === null || routingStatus === "unroutable";
546
732
  const notice = "This shape has no custom component yet, so it renders through the universal viewer \u2014 exactly what production shows today.";
547
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
548
- showRoutingNote && routingStatus === "unroutable" ? host.renderNotice?.(notice) ?? /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: "rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-xs text-amber-800 dark:text-amber-200", children: notice }) : null,
549
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { className: frameClass, children: onTheFloor ? host.renderValue({ value, kind }) : host.renderBlock(block) })
733
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
734
+ showRoutingNote && routingStatus === "unroutable" ? host.renderNotice?.(notice) ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "rounded-md border border-amber-500/30 bg-amber-500/5 px-3 py-2 text-xs text-amber-800 dark:text-amber-200", children: notice }) : null,
735
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: frameClass, children: onTheFloor ? host.renderValue({ value, kind }) : host.renderBlock(block) })
550
736
  ] });
551
737
  }
552
738
 
@@ -554,7 +740,7 @@ function KindInstanceRenderInner({
554
740
  var import_react7 = __toESM(require("react"), 1);
555
741
 
556
742
  // route/partial-kind-route.ts
557
- var import_content_ir7 = require("@ai-matrx/content-ir");
743
+ var import_content_ir9 = require("@ai-matrx/content-ir");
558
744
  var PARTIAL_UNSAFE_SLOT = /* @__PURE__ */ Symbol.for(
559
745
  "ai-matrx.content-ir-react.partial-unsafe-kinds"
560
746
  );
@@ -564,7 +750,7 @@ function markKindPartialUnsafe(kind) {
564
750
  }
565
751
 
566
752
  // react/ProvisionalKindBoundary.tsx
567
- var import_jsx_runtime9 = require("react/jsx-runtime");
753
+ var import_jsx_runtime10 = require("react/jsx-runtime");
568
754
  var ProvisionalKindBoundaryInner = class extends import_react7.default.Component {
569
755
  state = { failed: false };
570
756
  static getDerivedStateFromError() {
@@ -589,25 +775,25 @@ var ProvisionalKindBoundaryInner = class extends import_react7.default.Component
589
775
  };
590
776
  function ProvisionalKindBoundary(props) {
591
777
  const host = useContentIrHost();
592
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
778
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
593
779
  }
594
780
  function ProvisionalKindFrame({ children }) {
595
781
  const host = useContentIrHost();
596
782
  const label = "Still arriving";
597
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "relative", "aria-busy": "true", children: [
783
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "relative", "aria-busy": "true", children: [
598
784
  children,
599
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "pointer-events-none absolute -top-2 right-4 z-10 select-none rounded-full bg-background px-1.5 leading-4", children: host.renderShimmer?.(label) ?? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { className: "text-[10px] text-muted-foreground", children: label }) })
785
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "pointer-events-none absolute -top-2 right-4 z-10 select-none rounded-full bg-background px-1.5 leading-4", children: host.renderShimmer?.(label) ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-[10px] text-muted-foreground", children: label }) })
600
786
  ] });
601
787
  }
602
788
 
603
789
  // react/GenericStructuredView.tsx
604
790
  var import_react8 = require("react");
605
- var import_content_ir8 = require("@ai-matrx/content-ir");
606
- var import_jsx_runtime10 = require("react/jsx-runtime");
791
+ var import_content_ir10 = require("@ai-matrx/content-ir");
792
+ var import_jsx_runtime11 = require("react/jsx-runtime");
607
793
  function readStructuredValue(content, metadata) {
608
- const envelope = (0, import_content_ir8.readEnvelope)(metadata);
794
+ const envelope = (0, import_content_ir10.readEnvelope)(metadata);
609
795
  if (envelope) {
610
- return { value: (0, import_content_ir8.reconstructRegionValue)(envelope), recovered: true };
796
+ return { value: (0, import_content_ir10.reconstructRegionValue)(envelope), recovered: true };
611
797
  }
612
798
  try {
613
799
  return { value: JSON.parse(content), recovered: true };
@@ -622,25 +808,25 @@ function GenericStructuredView({
622
808
  className
623
809
  }) {
624
810
  const host = useContentIrHost();
625
- const envelope = (0, import_content_ir8.readEnvelope)(metadata);
811
+ const envelope = (0, import_content_ir10.readEnvelope)(metadata);
626
812
  const status = envelope?.root.status ?? "complete";
627
813
  const { value, recovered } = readStructuredValue(content, metadata);
628
- const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? (0, import_content_ir8.readObjectKind)(value) : null) ?? "";
814
+ const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? (0, import_content_ir10.readObjectKind)(value) : null) ?? "";
629
815
  const marker = readIrRouteMarker(metadata);
630
816
  const note = marker?.reason === "inactive" ? "a custom view is registered but held inactive" : marker?.reason === "broken-instance" ? "this instance did not match the shape's schema" : marker?.reason === "unregistered" ? "this shape isn't registered on this platform" : "no custom view yet";
631
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
632
- status === "streaming" ? streamingIndicator ?? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "mb-2 text-xs text-muted-foreground", children: "Still arriving\u2026" }) : null,
817
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
818
+ status === "streaming" ? streamingIndicator ?? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "mb-2 text-xs text-muted-foreground", children: "Still arriving\u2026" }) : null,
633
819
  recovered ? host.renderValue({ value, ...kind ? { kind } : {}, note }) : (
634
820
  // Zero-data-loss backstop: the region never parsed, so show the source
635
821
  // verbatim rather than swallowing it.
636
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("pre", { className: "max-h-96 overflow-auto font-mono text-xs leading-relaxed text-muted-foreground", children: content })
822
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("pre", { className: "max-h-96 overflow-auto font-mono text-xs leading-relaxed text-muted-foreground", children: content })
637
823
  )
638
824
  ] });
639
825
  }
640
826
 
641
827
  // react/RuntimeWrapperViews.tsx
642
- var import_content_ir9 = require("@ai-matrx/content-ir");
643
- var import_jsx_runtime11 = require("react/jsx-runtime");
828
+ var import_content_ir11 = require("@ai-matrx/content-ir");
829
+ var import_jsx_runtime12 = require("react/jsx-runtime");
644
830
  function isRecord2(value) {
645
831
  return typeof value === "object" && value !== null && !Array.isArray(value);
646
832
  }
@@ -656,16 +842,16 @@ function DelegatedOutput({
656
842
  }) {
657
843
  const host = useContentIrHost();
658
844
  if (output === null || output === void 0) {
659
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
845
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
660
846
  }
661
847
  if (!isRecord2(output)) {
662
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: host.renderValue({ value: output }) });
848
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: host.renderValue({ value: output }) });
663
849
  }
664
- const kind = (0, import_content_ir9.readObjectKind)(output) ?? declaredKind;
850
+ const kind = (0, import_content_ir11.readObjectKind)(output) ?? declaredKind;
665
851
  if (!kind) {
666
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_jsx_runtime11.Fragment, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
852
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_jsx_runtime12.Fragment, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
667
853
  }
668
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
854
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
669
855
  KindInstanceRender,
670
856
  {
671
857
  kind,
@@ -679,10 +865,10 @@ function DelegatedOutput({
679
865
  function NodeOutcomeView({ serverData, fallback }) {
680
866
  const wrapper = readWrapperFrom(
681
867
  serverData,
682
- import_content_ir9.readNodeOutcomeValue
868
+ import_content_ir11.readNodeOutcomeValue
683
869
  );
684
870
  if (!wrapper) return null;
685
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
871
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
686
872
  DelegatedOutput,
687
873
  {
688
874
  output: wrapper.output,
@@ -694,17 +880,17 @@ function NodeOutcomeView({ serverData, fallback }) {
694
880
  function RunResultView({ serverData, fallback }) {
695
881
  const wrapper = readWrapperFrom(
696
882
  serverData,
697
- import_content_ir9.readRunResultValue
883
+ import_content_ir11.readRunResultValue
698
884
  );
699
885
  if (!wrapper) return null;
700
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
886
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
701
887
  NodeOutcomeView,
702
888
  {
703
889
  serverData: { wrapper: outcome },
704
890
  ...fallback === void 0 ? {} : { fallback }
705
891
  },
706
892
  `${outcome.node_id}:${outcome.attempt}`
707
- )) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
893
+ )) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
708
894
  DelegatedOutput,
709
895
  {
710
896
  output: wrapper.output,