@ai-matrx/content-ir-react 0.9.3 → 0.11.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.
Files changed (46) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/dist/db-component.d.cts +8 -8
  3. package/dist/db-component.d.ts +8 -8
  4. package/dist/directive-host-DAb7Keg8.d.cts +63 -0
  5. package/dist/directive-host-DAb7Keg8.d.ts +63 -0
  6. package/dist/directives.cjs +382 -0
  7. package/dist/directives.cjs.map +1 -0
  8. package/dist/directives.d.cts +70 -0
  9. package/dist/directives.d.ts +70 -0
  10. package/dist/directives.js +369 -0
  11. package/dist/directives.js.map +1 -0
  12. package/dist/{host-types-CDcLW0TD.d.cts → host-types-C8jR31Wk.d.cts} +9 -0
  13. package/dist/{host-types-CpItjcYh.d.ts → host-types-IUEDmso7.d.ts} +9 -0
  14. package/dist/host.cjs +14 -4
  15. package/dist/host.cjs.map +1 -1
  16. package/dist/host.d.cts +5 -4
  17. package/dist/host.d.ts +5 -4
  18. package/dist/host.js +14 -4
  19. package/dist/host.js.map +1 -1
  20. package/dist/index.cjs +456 -47
  21. package/dist/index.cjs.map +1 -1
  22. package/dist/index.d.cts +85 -21
  23. package/dist/index.d.ts +85 -21
  24. package/dist/index.js +454 -31
  25. package/dist/index.js.map +1 -1
  26. package/dist/react.cjs +401 -46
  27. package/dist/react.cjs.map +1 -1
  28. package/dist/react.d.cts +11 -10
  29. package/dist/react.d.ts +11 -10
  30. package/dist/react.js +398 -29
  31. package/dist/react.js.map +1 -1
  32. package/dist/resolver.cjs +19 -1
  33. package/dist/resolver.cjs.map +1 -1
  34. package/dist/resolver.d.cts +3 -0
  35. package/dist/resolver.d.ts +3 -0
  36. package/dist/resolver.js +19 -1
  37. package/dist/resolver.js.map +1 -1
  38. package/dist/{route-QL2Vqf2e.d.cts → route-Bu85A41G.d.cts} +83 -3
  39. package/dist/{route-PUuEuEug.d.ts → route-DoFoDKBn.d.ts} +83 -3
  40. package/dist/route.cjs +14 -0
  41. package/dist/route.cjs.map +1 -1
  42. package/dist/route.d.cts +1 -1
  43. package/dist/route.d.ts +1 -1
  44. package/dist/route.js +15 -0
  45. package/dist/route.js.map +1 -1
  46. package/package.json +15 -2
package/dist/index.js CHANGED
@@ -14,17 +14,31 @@ function routeEnvOf(host) {
14
14
  }
15
15
 
16
16
  // host/ContentIrProvider.tsx
17
- import { createContext, useContext, useMemo } from "react";
17
+ import { createContext as createContext2, useContext as useContext2, useMemo } from "react";
18
+
19
+ // directives/directive-host.tsx
20
+ import { createContext, useContext } from "react";
18
21
  import { jsx } from "react/jsx-runtime";
19
- var ContentIrHostContext = createContext(null);
22
+ var DirectiveHostContext = createContext(null);
23
+ function DirectiveHostProvider({ host, children }) {
24
+ return /* @__PURE__ */ jsx(DirectiveHostContext.Provider, { value: host, children });
25
+ }
26
+ var EMPTY_HOST = {};
27
+ function useDirectiveHost() {
28
+ return useContext(DirectiveHostContext) ?? EMPTY_HOST;
29
+ }
30
+
31
+ // host/ContentIrProvider.tsx
32
+ import { jsx as jsx2 } from "react/jsx-runtime";
33
+ var ContentIrHostContext = createContext2(null);
20
34
  function ContentIrRenderProvider({
21
35
  host,
22
36
  children
23
37
  }) {
24
- return /* @__PURE__ */ jsx(ContentIrHostContext.Provider, { value: host, children });
38
+ return /* @__PURE__ */ jsx2(ContentIrHostContext.Provider, { value: host, children: /* @__PURE__ */ jsx2(DirectiveHostProvider, { host: host.directives ?? {}, children }) });
25
39
  }
26
40
  function useContentIrHostOrNull() {
27
- return useContext(ContentIrHostContext);
41
+ return useContext2(ContentIrHostContext);
28
42
  }
29
43
  function useContentIrHost() {
30
44
  const host = useContentIrHostOrNull();
@@ -55,11 +69,15 @@ function errorFields(error) {
55
69
  ...error.stack === void 0 ? {} : { stack: error.stack }
56
70
  };
57
71
  }
72
+ var WARM_RETRY_DELAYS_MS = [1e3, 5e3, 15e3];
58
73
  var ComponentResolver = class {
59
74
  compiled = null;
60
75
  db = /* @__PURE__ */ new Map();
61
76
  warmPromise = null;
62
77
  warmFailureLogged = false;
78
+ /** Consecutive warm-load failures — indexes WARM_RETRY_DELAYS_MS. */
79
+ warmFailures = 0;
80
+ warmRetryTimer = null;
63
81
  /**
64
82
  * True once a list load has RUN TO COMPLETION (success or failure), or once
65
83
  * any rows have been ingested by any tier. Until then `resolve()` answering
@@ -326,6 +344,11 @@ var ComponentResolver = class {
326
344
  this.warmPromise = loadAll().then((rows) => {
327
345
  this.ingestDbRows(rows);
328
346
  this.settled = true;
347
+ this.warmFailures = 0;
348
+ if (this.warmRetryTimer) {
349
+ clearTimeout(this.warmRetryTimer);
350
+ this.warmRetryTimer = null;
351
+ }
329
352
  }).catch((error) => {
330
353
  const message = `component-resolver warm load failed (compiled bootstrap still serving): ${describe(error)}`;
331
354
  if (!this.warmFailureLogged) {
@@ -338,8 +361,17 @@ var ComponentResolver = class {
338
361
  ...errorFields(error),
339
362
  raw: error
340
363
  });
341
- this.settled = true;
342
364
  this.warmPromise = null;
365
+ this.warmFailures += 1;
366
+ const delay = WARM_RETRY_DELAYS_MS[this.warmFailures - 1] ?? null;
367
+ if (delay === null) {
368
+ this.settled = true;
369
+ } else if (!this.warmRetryTimer) {
370
+ this.warmRetryTimer = setTimeout(() => {
371
+ this.warmRetryTimer = null;
372
+ void this.ensureWarm();
373
+ }, delay);
374
+ }
343
375
  });
344
376
  }
345
377
  return this.warmPromise;
@@ -354,12 +386,14 @@ var ComponentResolver = class {
354
386
  // route/kind-route.ts
355
387
  import {
356
388
  envelopeFromCompleteValue,
389
+ isReservedDirectiveSlug,
357
390
  readEnvelope,
358
391
  readObjectKind
359
392
  } from "@ai-matrx/content-ir";
360
393
  var IR_ROUTE_KEY = "__ir_route";
361
394
  var GENERIC_STRUCTURED_COMPONENT_KEY = "generic_structured";
362
395
  var DB_KIND_COMPONENT_KEY = "db_kind_component";
396
+ var DIRECTIVE_BLOCK_TYPE = "matrx";
363
397
  function isDbSourceResolution(resolution) {
364
398
  return resolution !== null && resolution.resolvedBy === "db" && resolution.source === "db" && resolution.isActive;
365
399
  }
@@ -437,6 +471,18 @@ function applyIrKindRoute(block, env, options) {
437
471
  const kind = envelope.root.kind;
438
472
  if (!kind) return block;
439
473
  if (envelope.root.kindState === "pending_schema") return block;
474
+ if (isReservedDirectiveSlug(kind)) {
475
+ if (block.type === DIRECTIVE_BLOCK_TYPE) return block;
476
+ return {
477
+ ...block,
478
+ type: DIRECTIVE_BLOCK_TYPE,
479
+ serverData: void 0,
480
+ metadata: {
481
+ ...block.metadata ?? {},
482
+ [IR_ROUTE_KEY]: { by: "directive", key: DIRECTIVE_BLOCK_TYPE }
483
+ }
484
+ };
485
+ }
440
486
  const def = env.kinds.getDefinition(kind);
441
487
  const resolution = env.components.resolve(kind, env.platform, "output");
442
488
  const componentsSettled = env.components.hasSettled?.() ?? true;
@@ -622,19 +668,386 @@ function useContentIrKindVersion(kind, sources) {
622
668
  }
623
669
 
624
670
  // react/KindInstanceRender.tsx
625
- import { useEffect, useState } from "react";
626
- import { envelopeFromCompleteValue as envelopeFromCompleteValue2, IR_ENVELOPE_KEY as IR_ENVELOPE_KEY2 } from "@ai-matrx/content-ir";
627
- import { Fragment, jsx as jsx2, jsxs } from "react/jsx-runtime";
671
+ import { useEffect as useEffect2, useState as useState3 } from "react";
672
+ import {
673
+ envelopeFromCompleteValue as envelopeFromCompleteValue2,
674
+ IR_ENVELOPE_KEY as IR_ENVELOPE_KEY2,
675
+ isReservedDirectiveSlug as isReservedDirectiveSlug2
676
+ } from "@ai-matrx/content-ir";
677
+
678
+ // directives/DirectiveRender.tsx
679
+ import { tryDecodeDirectiveContent } from "@ai-matrx/content-ir";
680
+
681
+ // directives/DirectiveFallbackCard.tsx
682
+ import { directiveDisplay } from "@ai-matrx/content-ir";
683
+
684
+ // directives/ApplyDirectiveButton.tsx
685
+ import { useEffect, useRef, useState } from "react";
686
+
687
+ // directives/icons.tsx
688
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
689
+ function Svg({ children, ...props }) {
690
+ return /* @__PURE__ */ jsx3(
691
+ "svg",
692
+ {
693
+ xmlns: "http://www.w3.org/2000/svg",
694
+ viewBox: "0 0 24 24",
695
+ fill: "none",
696
+ stroke: "currentColor",
697
+ strokeWidth: 2,
698
+ strokeLinecap: "round",
699
+ strokeLinejoin: "round",
700
+ "aria-hidden": "true",
701
+ ...props,
702
+ children
703
+ }
704
+ );
705
+ }
706
+ var FilePlusIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
707
+ /* @__PURE__ */ jsx3("path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4" }),
708
+ /* @__PURE__ */ jsx3("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
709
+ /* @__PURE__ */ jsx3("path", { d: "M3 15h6" }),
710
+ /* @__PURE__ */ jsx3("path", { d: "M6 12v6" })
711
+ ] });
712
+ var PencilIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
713
+ /* @__PURE__ */ jsx3("path", { d: "M12 20h9" }),
714
+ /* @__PURE__ */ jsx3("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" })
715
+ ] });
716
+ var TrashIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
717
+ /* @__PURE__ */ jsx3("path", { d: "M3 6h18" }),
718
+ /* @__PURE__ */ jsx3("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
719
+ /* @__PURE__ */ jsx3("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
720
+ /* @__PURE__ */ jsx3("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
721
+ /* @__PURE__ */ jsx3("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
722
+ ] });
723
+ var PlayIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("polygon", { points: "6 3 20 12 6 21 6 3" }) });
724
+ var WebhookIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
725
+ /* @__PURE__ */ jsx3("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" }),
726
+ /* @__PURE__ */ jsx3("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" }),
727
+ /* @__PURE__ */ jsx3("path", { d: "m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8" })
728
+ ] });
729
+ var BoxesIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
730
+ /* @__PURE__ */ jsx3("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" }),
731
+ /* @__PURE__ */ jsx3("path", { d: "m7 16.5-4.74-2.85" }),
732
+ /* @__PURE__ */ jsx3("path", { d: "m7 16.5 5-3" }),
733
+ /* @__PURE__ */ jsx3("path", { d: "M7 16.5v5.17" }),
734
+ /* @__PURE__ */ jsx3("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" }),
735
+ /* @__PURE__ */ jsx3("path", { d: "m17 16.5-5-3" }),
736
+ /* @__PURE__ */ jsx3("path", { d: "m17 16.5 4.74-2.85" }),
737
+ /* @__PURE__ */ jsx3("path", { d: "M17 16.5v5.17" }),
738
+ /* @__PURE__ */ jsx3("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" }),
739
+ /* @__PURE__ */ jsx3("path", { d: "M12 8 7.26 5.15" }),
740
+ /* @__PURE__ */ jsx3("path", { d: "m12 8 4.74-2.85" }),
741
+ /* @__PURE__ */ jsx3("path", { d: "M12 13.5V8" })
742
+ ] });
743
+ var ChevronDownIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }) });
744
+ var ChevronRightIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "m9 18 6-6-6-6" }) });
745
+ var MaximizeIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
746
+ /* @__PURE__ */ jsx3("polyline", { points: "15 3 21 3 21 9" }),
747
+ /* @__PURE__ */ jsx3("polyline", { points: "9 21 3 21 3 15" }),
748
+ /* @__PURE__ */ jsx3("line", { x1: "21", x2: "14", y1: "3", y2: "10" }),
749
+ /* @__PURE__ */ jsx3("line", { x1: "3", x2: "10", y1: "21", y2: "14" })
750
+ ] });
751
+ var LoaderIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
752
+ var CheckCircleIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
753
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
754
+ /* @__PURE__ */ jsx3("path", { d: "m9 12 2 2 4-4" })
755
+ ] });
756
+ var AlertIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
757
+ /* @__PURE__ */ jsx3("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" }),
758
+ /* @__PURE__ */ jsx3("path", { d: "M12 9v4" }),
759
+ /* @__PURE__ */ jsx3("path", { d: "M12 17h.01" })
760
+ ] });
761
+ var AGENT_NOUNS = /* @__PURE__ */ new Set(["create_agent", "create_agent_definition", "agent"]);
762
+ function classIcon(directiveClass, noun) {
763
+ if (directiveClass === "action" && AGENT_NOUNS.has(noun)) return WebhookIcon;
764
+ switch (directiveClass) {
765
+ case "create":
766
+ return FilePlusIcon;
767
+ case "update":
768
+ return PencilIcon;
769
+ case "delete":
770
+ return TrashIcon;
771
+ default:
772
+ return PlayIcon;
773
+ }
774
+ }
775
+
776
+ // directives/ApplyDirectiveButton.tsx
777
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
778
+ function ApplyDirectiveButton({
779
+ directive,
780
+ label = "Apply",
781
+ itemCount,
782
+ onApplied
783
+ }) {
784
+ const host = useDirectiveHost();
785
+ const [state, setState] = useState({ status: "idle" });
786
+ const [elapsed, setElapsed] = useState(0);
787
+ const startedAt = useRef(null);
788
+ useEffect(() => {
789
+ if (state.status !== "applying") return;
790
+ startedAt.current = Date.now();
791
+ const id = setInterval(
792
+ () => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
793
+ 1e3
794
+ );
795
+ return () => clearInterval(id);
796
+ }, [state.status]);
797
+ if (!directive.parsed.executes) return null;
798
+ const confirm = host.confirm;
799
+ if (!confirm) return null;
800
+ const items = directive.items;
801
+ async function handleApply() {
802
+ if (!confirm) return;
803
+ setState({ status: "applying" });
804
+ try {
805
+ const result = await confirm({ __kind: directive.slug, items });
806
+ setState({ status: "applied", applied: result.applied, failed: result.failed });
807
+ onApplied?.();
808
+ } catch (error) {
809
+ setState({
810
+ status: "error",
811
+ message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
812
+ });
813
+ }
814
+ }
815
+ if (state.status === "applied") {
816
+ const bad = state.failed > 0;
817
+ return /* @__PURE__ */ jsxs2(
818
+ "span",
819
+ {
820
+ className: `inline-flex items-center gap-1 text-xs ${bad ? "text-destructive" : "text-primary"}`,
821
+ children: [
822
+ bad ? /* @__PURE__ */ jsx4(AlertIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx4(CheckCircleIcon, { className: "h-3.5 w-3.5" }),
823
+ "Applied ",
824
+ state.applied,
825
+ bad ? ` \xB7 ${state.failed} failed` : ""
826
+ ]
827
+ }
828
+ );
829
+ }
830
+ return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
831
+ /* @__PURE__ */ jsxs2(
832
+ "button",
833
+ {
834
+ type: "button",
835
+ onClick: () => void handleApply(),
836
+ disabled: state.status === "applying" || items.length === 0,
837
+ 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",
838
+ children: [
839
+ state.status === "applying" ? /* @__PURE__ */ jsx4(LoaderIcon, { className: "h-3.5 w-3.5 animate-spin" }) : /* @__PURE__ */ jsx4(PlayIcon, { className: "h-3.5 w-3.5" }),
840
+ state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
841
+ ]
842
+ }
843
+ ),
844
+ state.status === "error" ? /* @__PURE__ */ jsxs2("span", { className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive", children: [
845
+ /* @__PURE__ */ jsx4(AlertIcon, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
846
+ /* @__PURE__ */ jsx4("span", { children: state.message })
847
+ ] }) : null
848
+ ] });
849
+ }
850
+
851
+ // directives/DirectiveFallbackCard.tsx
852
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
853
+ function DirectiveFallbackCard({ directive, reason }) {
854
+ const host = useDirectiveHost();
855
+ const count = directive.items.length;
856
+ const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);
857
+ return /* @__PURE__ */ jsxs3("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: [
858
+ /* @__PURE__ */ jsx5(BoxesIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
859
+ /* @__PURE__ */ jsx5("span", { className: "text-foreground", children: display.title }),
860
+ display.family ? /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
861
+ "\xB7 ",
862
+ display.family
863
+ ] }) : null,
864
+ /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
865
+ "\xB7 ",
866
+ count,
867
+ " ",
868
+ count === 1 ? "item" : "items"
869
+ ] }),
870
+ reason ? /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
871
+ "\xB7 ",
872
+ reason
873
+ ] }) : null,
874
+ /* @__PURE__ */ jsx5(ApplyDirectiveButton, { directive })
875
+ ] });
876
+ }
877
+
878
+ // directives/registry.ts
879
+ import {
880
+ buildDirectiveSlug
881
+ } from "@ai-matrx/content-ir";
882
+ var REGISTRY_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.content-ir-react.directive-renderers");
883
+ var registry = globalThis[REGISTRY_SLOT] ??= {
884
+ bySlug: /* @__PURE__ */ new Map(),
885
+ byClass: /* @__PURE__ */ new Map()
886
+ };
887
+ function registerDirectiveRenderer(directiveClass, renderer, noun) {
888
+ if (noun) registry.bySlug.set(buildDirectiveSlug(directiveClass, noun), renderer);
889
+ else registry.byClass.set(directiveClass, renderer);
890
+ }
891
+ function getDirectiveRenderer(directive) {
892
+ return registry.bySlug.get(directive.slug) ?? registry.byClass.get(directive.directiveClass) ?? null;
893
+ }
894
+ function resetDirectiveRenderers() {
895
+ registry.bySlug.clear();
896
+ registry.byClass.clear();
897
+ }
898
+
899
+ // directives/SideEffectDirectiveCard.tsx
900
+ import { useState as useState2 } from "react";
901
+ import {
902
+ asKindInstance,
903
+ directiveDisplay as directiveDisplay2,
904
+ itemFacts,
905
+ itemSubtitle,
906
+ itemTitle,
907
+ nounTitleColumn
908
+ } from "@ai-matrx/content-ir";
909
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
910
+ var ROWS_BEFORE_FOLD = 3;
911
+ function ItemRow({
912
+ directive,
913
+ item,
914
+ index,
915
+ total
916
+ }) {
917
+ const host = useDirectiveHost();
918
+ const titleColumn = nounTitleColumn(directive.noun, host.nouns);
919
+ const title = itemTitle(item, titleColumn, index, total);
920
+ const subtitle = itemSubtitle(item);
921
+ const facts = itemFacts(item);
922
+ const kind = host.itemKind?.(directive.slug) ?? null;
923
+ const display = directiveDisplay2(directive.directiveClass, directive.noun, host.nouns);
924
+ const openItem = host.openItem;
925
+ const body = /* @__PURE__ */ jsxs4(Fragment, { children: [
926
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 shrink-0 truncate font-medium text-foreground", children: title }),
927
+ /* @__PURE__ */ jsx6("span", { className: "hidden min-w-0 flex-1 items-baseline gap-2 overflow-hidden sm:flex", children: facts.map((fact) => /* @__PURE__ */ jsxs4("span", { className: "truncate text-[11px] text-muted-foreground", children: [
928
+ fact.value,
929
+ " ",
930
+ fact.label
931
+ ] }, fact.key)) }),
932
+ subtitle && facts.length === 0 ? /* @__PURE__ */ jsx6("span", { className: "hidden truncate text-[11px] text-muted-foreground sm:inline", children: subtitle }) : null,
933
+ openItem ? /* @__PURE__ */ jsx6(MaximizeIcon, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground" }) : null
934
+ ] });
935
+ return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
936
+ openItem ? /* @__PURE__ */ jsx6(
937
+ "button",
938
+ {
939
+ type: "button",
940
+ onClick: () => openItem({
941
+ // Stamped so the panel's kind pipeline types it from its own first key.
942
+ item: asKindInstance(item, kind) ?? item,
943
+ itemKind: kind,
944
+ title,
945
+ subtitle: `${display.title} \xB7 item ${index + 1} of ${total}`,
946
+ directive,
947
+ index,
948
+ total
949
+ }),
950
+ 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",
951
+ title: "Open to read it",
952
+ children: body
953
+ }
954
+ ) : /* @__PURE__ */ jsx6("span", { className: "flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5", children: body }),
955
+ host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
956
+ ] });
957
+ }
958
+ function SideEffectDirectiveCard({ directive }) {
959
+ const host = useDirectiveHost();
960
+ const [expanded, setExpanded] = useState2(false);
961
+ const items = directive.items;
962
+ const total = items.length;
963
+ const display = directiveDisplay2(directive.directiveClass, directive.noun, host.nouns);
964
+ const Icon = classIcon(directive.directiveClass, directive.noun);
965
+ const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);
966
+ const hidden = total - shown.length;
967
+ return /* @__PURE__ */ jsxs4("div", { className: "my-3 rounded-md border border-border bg-card px-2.5 py-1.5", "data-directive": directive.slug, children: [
968
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
969
+ /* @__PURE__ */ jsx6(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
970
+ /* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-foreground", children: display.title }),
971
+ display.family ? /* @__PURE__ */ jsx6("span", { className: "text-xs text-muted-foreground", children: display.family }) : null,
972
+ /* @__PURE__ */ jsxs4("span", { className: "text-xs tabular-nums text-muted-foreground", children: [
973
+ total,
974
+ " ",
975
+ total === 1 ? "item" : "items"
976
+ ] }),
977
+ /* @__PURE__ */ jsxs4("div", { className: "ml-auto flex items-center gap-1", children: [
978
+ host.renderCopy?.({ label: display.title, value: directive.shell, size: "icon" }),
979
+ /* @__PURE__ */ jsx6(ApplyDirectiveButton, { directive, itemCount: total })
980
+ ] })
981
+ ] }),
982
+ total === 0 ? (
983
+ // Stated, never silent: an empty batch is a real (and suspicious) state.
984
+ /* @__PURE__ */ jsx6("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
985
+ ) : /* @__PURE__ */ jsx6("div", { className: "mt-0.5 divide-y divide-border/60", children: shown.map((item, i) => /* @__PURE__ */ jsx6(ItemRow, { directive, item, index: i, total }, i)) }),
986
+ hidden > 0 || expanded ? /* @__PURE__ */ jsxs4(
987
+ "button",
988
+ {
989
+ type: "button",
990
+ onClick: () => setExpanded((v) => !v),
991
+ className: "mt-0.5 inline-flex items-center gap-1 rounded px-1 py-0.5 text-[11px] text-muted-foreground hover:text-foreground",
992
+ children: [
993
+ expanded ? /* @__PURE__ */ jsx6(ChevronDownIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx6(ChevronRightIcon, { className: "h-3 w-3" }),
994
+ expanded ? "Show less" : `Show ${hidden} more`
995
+ ]
996
+ }
997
+ ) : null
998
+ ] });
999
+ }
1000
+
1001
+ // directives/DirectiveRender.tsx
1002
+ import { jsx as jsx7 } from "react/jsx-runtime";
1003
+ function DirectiveRender({ content, className }) {
1004
+ const host = useDirectiveHost();
1005
+ const directive = tryDecodeDirectiveContent(content, (message) => {
1006
+ const line = `[kind-directives] ${message}`;
1007
+ if (host.reportError) host.reportError(line);
1008
+ else console.error(line);
1009
+ });
1010
+ if (!directive) {
1011
+ const raw = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1012
+ return /* @__PURE__ */ jsx7(
1013
+ "pre",
1014
+ {
1015
+ className: `my-3 overflow-x-auto rounded-md border border-border bg-muted px-3 py-2 text-xs text-muted-foreground${className ? ` ${className}` : ""}`,
1016
+ children: raw
1017
+ }
1018
+ );
1019
+ }
1020
+ const Renderer = getDirectiveRenderer(directive);
1021
+ if (Renderer) return /* @__PURE__ */ jsx7(Renderer, { directive });
1022
+ if (directive.parsed.executes) return /* @__PURE__ */ jsx7(SideEffectDirectiveCard, { directive });
1023
+ return /* @__PURE__ */ jsx7(DirectiveFallbackCard, { directive });
1024
+ }
1025
+
1026
+ // react/KindInstanceRender.tsx
1027
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
628
1028
  function isRecordValue(value) {
629
1029
  return typeof value === "object" && value !== null && !Array.isArray(value);
630
1030
  }
631
1031
  function kindIsRoutable(kind, host) {
1032
+ if (isReservedDirectiveSlug2(kind)) return true;
632
1033
  if (host.kinds.getDefinition(kind)?.legacyBlockType) return true;
633
1034
  const resolution = host.components.resolve(kind, host.platform, "output");
634
1035
  if (!resolution?.isActive) return false;
635
1036
  return resolution.componentKey !== GENERIC_STRUCTURED_COMPONENT_KEY;
636
1037
  }
637
- function KindInstanceRender({
1038
+ function KindInstanceRender(props) {
1039
+ if (isReservedDirectiveSlug2(props.kind)) {
1040
+ return /* @__PURE__ */ jsx8(
1041
+ DirectiveRender,
1042
+ {
1043
+ content: props.value,
1044
+ ...props.className === void 0 ? {} : { className: props.className }
1045
+ }
1046
+ );
1047
+ }
1048
+ return /* @__PURE__ */ jsx8(KindInstanceRenderInner, { ...props });
1049
+ }
1050
+ function KindInstanceRenderInner({
638
1051
  kind,
639
1052
  value,
640
1053
  showRoutingNote = true,
@@ -643,10 +1056,10 @@ function KindInstanceRender({
643
1056
  className
644
1057
  }) {
645
1058
  const host = useContentIrHost();
646
- const [routingStatus, setRoutingStatus] = useState(
1059
+ const [routingStatus, setRoutingStatus] = useState3(
647
1060
  () => kindIsRoutable(kind, host) ? "routable" : "checking"
648
1061
  );
649
- useEffect(() => {
1062
+ useEffect2(() => {
650
1063
  let cancelled = false;
651
1064
  let warmed = false;
652
1065
  const syncRoutingStatus = () => {
@@ -683,19 +1096,19 @@ function KindInstanceRender({
683
1096
  } : null;
684
1097
  const frameClass = variant === "bare" ? void 0 : "rounded-md border border-border bg-card p-3";
685
1098
  if (routingStatus === "unroutable" && unroutableFallback !== void 0) {
686
- return /* @__PURE__ */ jsx2(Fragment, { children: unroutableFallback });
1099
+ return /* @__PURE__ */ jsx8(Fragment2, { children: unroutableFallback });
687
1100
  }
688
1101
  const onTheFloor = block === null || routingStatus === "unroutable";
689
1102
  const notice = "This shape has no custom component yet, so it renders through the universal viewer \u2014 exactly what production shows today.";
690
- return /* @__PURE__ */ jsxs("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
691
- showRoutingNote && routingStatus === "unroutable" ? host.renderNotice?.(notice) ?? /* @__PURE__ */ jsx2("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,
692
- /* @__PURE__ */ jsx2("div", { className: frameClass, children: onTheFloor ? host.renderValue({ value, kind }) : host.renderBlock(block) })
1103
+ return /* @__PURE__ */ jsxs5("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
1104
+ showRoutingNote && routingStatus === "unroutable" ? host.renderNotice?.(notice) ?? /* @__PURE__ */ jsx8("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,
1105
+ /* @__PURE__ */ jsx8("div", { className: frameClass, children: onTheFloor ? host.renderValue({ value, kind }) : host.renderBlock(block) })
693
1106
  ] });
694
1107
  }
695
1108
 
696
1109
  // react/ProvisionalKindBoundary.tsx
697
1110
  import React from "react";
698
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1111
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
699
1112
  var ProvisionalKindBoundaryInner = class extends React.Component {
700
1113
  state = { failed: false };
701
1114
  static getDerivedStateFromError() {
@@ -720,14 +1133,14 @@ var ProvisionalKindBoundaryInner = class extends React.Component {
720
1133
  };
721
1134
  function ProvisionalKindBoundary(props) {
722
1135
  const host = useContentIrHost();
723
- return /* @__PURE__ */ jsx3(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
1136
+ return /* @__PURE__ */ jsx9(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
724
1137
  }
725
1138
  function ProvisionalKindFrame({ children }) {
726
1139
  const host = useContentIrHost();
727
1140
  const label = "Still arriving";
728
- return /* @__PURE__ */ jsxs2("div", { className: "relative", "aria-busy": "true", children: [
1141
+ return /* @__PURE__ */ jsxs6("div", { className: "relative", "aria-busy": "true", children: [
729
1142
  children,
730
- /* @__PURE__ */ jsx3("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__ */ jsx3("span", { className: "text-[10px] text-muted-foreground", children: label }) })
1143
+ /* @__PURE__ */ jsx9("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__ */ jsx9("span", { className: "text-[10px] text-muted-foreground", children: label }) })
731
1144
  ] });
732
1145
  }
733
1146
 
@@ -738,7 +1151,7 @@ import {
738
1151
  readObjectKind as readObjectKind2,
739
1152
  reconstructRegionValue
740
1153
  } from "@ai-matrx/content-ir";
741
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1154
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
742
1155
  function readStructuredValue(content, metadata) {
743
1156
  const envelope = readEnvelope3(metadata);
744
1157
  if (envelope) {
@@ -763,19 +1176,19 @@ function GenericStructuredView({
763
1176
  const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? readObjectKind2(value) : null) ?? "";
764
1177
  const marker = readIrRouteMarker(metadata);
765
1178
  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";
766
- return /* @__PURE__ */ jsxs3("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
767
- status === "streaming" ? streamingIndicator ?? /* @__PURE__ */ jsx4("div", { className: "mb-2 text-xs text-muted-foreground", children: "Still arriving\u2026" }) : null,
1179
+ return /* @__PURE__ */ jsxs7("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
1180
+ status === "streaming" ? streamingIndicator ?? /* @__PURE__ */ jsx10("div", { className: "mb-2 text-xs text-muted-foreground", children: "Still arriving\u2026" }) : null,
768
1181
  recovered ? host.renderValue({ value, ...kind ? { kind } : {}, note }) : (
769
1182
  // Zero-data-loss backstop: the region never parsed, so show the source
770
1183
  // verbatim rather than swallowing it.
771
- /* @__PURE__ */ jsx4("pre", { className: "max-h-96 overflow-auto font-mono text-xs leading-relaxed text-muted-foreground", children: content })
1184
+ /* @__PURE__ */ jsx10("pre", { className: "max-h-96 overflow-auto font-mono text-xs leading-relaxed text-muted-foreground", children: content })
772
1185
  )
773
1186
  ] });
774
1187
  }
775
1188
 
776
1189
  // react/RuntimeWrapperViews.tsx
777
1190
  import { readNodeOutcomeValue, readObjectKind as readObjectKind3, readRunResultValue } from "@ai-matrx/content-ir";
778
- import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
1191
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
779
1192
  function isRecord2(value) {
780
1193
  return typeof value === "object" && value !== null && !Array.isArray(value);
781
1194
  }
@@ -791,16 +1204,16 @@ function DelegatedOutput({
791
1204
  }) {
792
1205
  const host = useContentIrHost();
793
1206
  if (output === null || output === void 0) {
794
- return /* @__PURE__ */ jsx5("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
1207
+ return /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
795
1208
  }
796
1209
  if (!isRecord2(output)) {
797
- return /* @__PURE__ */ jsx5(Fragment2, { children: host.renderValue({ value: output }) });
1210
+ return /* @__PURE__ */ jsx11(Fragment3, { children: host.renderValue({ value: output }) });
798
1211
  }
799
1212
  const kind = readObjectKind3(output) ?? declaredKind;
800
1213
  if (!kind) {
801
- return /* @__PURE__ */ jsx5(Fragment2, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
1214
+ return /* @__PURE__ */ jsx11(Fragment3, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
802
1215
  }
803
- return /* @__PURE__ */ jsx5(
1216
+ return /* @__PURE__ */ jsx11(
804
1217
  KindInstanceRender,
805
1218
  {
806
1219
  kind,
@@ -817,7 +1230,7 @@ function NodeOutcomeView({ serverData, fallback }) {
817
1230
  readNodeOutcomeValue
818
1231
  );
819
1232
  if (!wrapper) return null;
820
- return /* @__PURE__ */ jsx5(
1233
+ return /* @__PURE__ */ jsx11(
821
1234
  DelegatedOutput,
822
1235
  {
823
1236
  output: wrapper.output,
@@ -832,14 +1245,14 @@ function RunResultView({ serverData, fallback }) {
832
1245
  readRunResultValue
833
1246
  );
834
1247
  if (!wrapper) return null;
835
- return /* @__PURE__ */ jsx5("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ jsx5(
1248
+ return /* @__PURE__ */ jsx11("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ jsx11(
836
1249
  NodeOutcomeView,
837
1250
  {
838
1251
  serverData: { wrapper: outcome },
839
1252
  ...fallback === void 0 ? {} : { fallback }
840
1253
  },
841
1254
  `${outcome.node_id}:${outcome.attempt}`
842
- )) : /* @__PURE__ */ jsx5(
1255
+ )) : /* @__PURE__ */ jsx11(
843
1256
  DelegatedOutput,
844
1257
  {
845
1258
  output: wrapper.output,
@@ -1036,11 +1449,16 @@ var DbKindComponentErrorBoundary = class extends React2.Component {
1036
1449
  }
1037
1450
  };
1038
1451
  export {
1452
+ ApplyDirectiveButton,
1039
1453
  ComponentResolver,
1040
1454
  ContentIrRenderProvider,
1041
1455
  DB_KIND_COMPONENT_KEY,
1456
+ DIRECTIVE_BLOCK_TYPE,
1042
1457
  DbKindComponentErrorBoundary,
1043
1458
  DelegatedOutput,
1459
+ DirectiveFallbackCard,
1460
+ DirectiveHostProvider,
1461
+ DirectiveRender,
1044
1462
  GENERIC_STRUCTURED_COMPONENT_KEY,
1045
1463
  GenericStructuredView,
1046
1464
  IR_PROVISIONAL_KEY,
@@ -1050,11 +1468,13 @@ export {
1050
1468
  ProvisionalKindBoundary,
1051
1469
  ProvisionalKindFrame,
1052
1470
  RunResultView,
1471
+ SideEffectDirectiveCard,
1053
1472
  applyIrKindRoute,
1054
1473
  consoleErrorReporter,
1055
1474
  createDbKindComponentCache,
1056
1475
  createKindRouteBinding,
1057
1476
  envelopeFromPartialKind,
1477
+ getDirectiveRenderer,
1058
1478
  isDbKindComponentBodyPending,
1059
1479
  isPartialReadyKind,
1060
1480
  isProvisionalBlock,
@@ -1063,6 +1483,8 @@ export {
1063
1483
  kindServerDataFromStoredValue,
1064
1484
  markKindPartialUnsafe,
1065
1485
  readIrRouteMarker,
1486
+ registerDirectiveRenderer,
1487
+ resetDirectiveRenderers,
1066
1488
  resetPartialUnsafeKinds,
1067
1489
  resetSourcelessDbRowReports,
1068
1490
  resolveAnnouncedKindLoading,
@@ -1071,6 +1493,7 @@ export {
1071
1493
  useContentIrHost,
1072
1494
  useContentIrHostOrNull,
1073
1495
  useContentIrKindVersion,
1496
+ useDirectiveHost,
1074
1497
  useKindRouteEnv
1075
1498
  };
1076
1499
  //# sourceMappingURL=index.js.map