@ai-matrx/content-ir-react 0.10.0 → 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 (40) hide show
  1. package/CHANGELOG.md +50 -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 +437 -46
  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 +435 -30
  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/{route-QL2Vqf2e.d.cts → route-Bu85A41G.d.cts} +83 -3
  33. package/dist/{route-PUuEuEug.d.ts → route-DoFoDKBn.d.ts} +83 -3
  34. package/dist/route.cjs +14 -0
  35. package/dist/route.cjs.map +1 -1
  36. package/dist/route.d.cts +1 -1
  37. package/dist/route.d.ts +1 -1
  38. package/dist/route.js +15 -0
  39. package/dist/route.js.map +1 -1
  40. 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();
@@ -372,12 +386,14 @@ var ComponentResolver = class {
372
386
  // route/kind-route.ts
373
387
  import {
374
388
  envelopeFromCompleteValue,
389
+ isReservedDirectiveSlug,
375
390
  readEnvelope,
376
391
  readObjectKind
377
392
  } from "@ai-matrx/content-ir";
378
393
  var IR_ROUTE_KEY = "__ir_route";
379
394
  var GENERIC_STRUCTURED_COMPONENT_KEY = "generic_structured";
380
395
  var DB_KIND_COMPONENT_KEY = "db_kind_component";
396
+ var DIRECTIVE_BLOCK_TYPE = "matrx";
381
397
  function isDbSourceResolution(resolution) {
382
398
  return resolution !== null && resolution.resolvedBy === "db" && resolution.source === "db" && resolution.isActive;
383
399
  }
@@ -455,6 +471,18 @@ function applyIrKindRoute(block, env, options) {
455
471
  const kind = envelope.root.kind;
456
472
  if (!kind) return block;
457
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
+ }
458
486
  const def = env.kinds.getDefinition(kind);
459
487
  const resolution = env.components.resolve(kind, env.platform, "output");
460
488
  const componentsSettled = env.components.hasSettled?.() ?? true;
@@ -640,19 +668,386 @@ function useContentIrKindVersion(kind, sources) {
640
668
  }
641
669
 
642
670
  // react/KindInstanceRender.tsx
643
- import { useEffect, useState } from "react";
644
- import { envelopeFromCompleteValue as envelopeFromCompleteValue2, IR_ENVELOPE_KEY as IR_ENVELOPE_KEY2 } from "@ai-matrx/content-ir";
645
- 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";
646
1028
  function isRecordValue(value) {
647
1029
  return typeof value === "object" && value !== null && !Array.isArray(value);
648
1030
  }
649
1031
  function kindIsRoutable(kind, host) {
1032
+ if (isReservedDirectiveSlug2(kind)) return true;
650
1033
  if (host.kinds.getDefinition(kind)?.legacyBlockType) return true;
651
1034
  const resolution = host.components.resolve(kind, host.platform, "output");
652
1035
  if (!resolution?.isActive) return false;
653
1036
  return resolution.componentKey !== GENERIC_STRUCTURED_COMPONENT_KEY;
654
1037
  }
655
- 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({
656
1051
  kind,
657
1052
  value,
658
1053
  showRoutingNote = true,
@@ -661,10 +1056,10 @@ function KindInstanceRender({
661
1056
  className
662
1057
  }) {
663
1058
  const host = useContentIrHost();
664
- const [routingStatus, setRoutingStatus] = useState(
1059
+ const [routingStatus, setRoutingStatus] = useState3(
665
1060
  () => kindIsRoutable(kind, host) ? "routable" : "checking"
666
1061
  );
667
- useEffect(() => {
1062
+ useEffect2(() => {
668
1063
  let cancelled = false;
669
1064
  let warmed = false;
670
1065
  const syncRoutingStatus = () => {
@@ -701,19 +1096,19 @@ function KindInstanceRender({
701
1096
  } : null;
702
1097
  const frameClass = variant === "bare" ? void 0 : "rounded-md border border-border bg-card p-3";
703
1098
  if (routingStatus === "unroutable" && unroutableFallback !== void 0) {
704
- return /* @__PURE__ */ jsx2(Fragment, { children: unroutableFallback });
1099
+ return /* @__PURE__ */ jsx8(Fragment2, { children: unroutableFallback });
705
1100
  }
706
1101
  const onTheFloor = block === null || routingStatus === "unroutable";
707
1102
  const notice = "This shape has no custom component yet, so it renders through the universal viewer \u2014 exactly what production shows today.";
708
- return /* @__PURE__ */ jsxs("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
709
- 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,
710
- /* @__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) })
711
1106
  ] });
712
1107
  }
713
1108
 
714
1109
  // react/ProvisionalKindBoundary.tsx
715
1110
  import React from "react";
716
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1111
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
717
1112
  var ProvisionalKindBoundaryInner = class extends React.Component {
718
1113
  state = { failed: false };
719
1114
  static getDerivedStateFromError() {
@@ -738,14 +1133,14 @@ var ProvisionalKindBoundaryInner = class extends React.Component {
738
1133
  };
739
1134
  function ProvisionalKindBoundary(props) {
740
1135
  const host = useContentIrHost();
741
- return /* @__PURE__ */ jsx3(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
1136
+ return /* @__PURE__ */ jsx9(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
742
1137
  }
743
1138
  function ProvisionalKindFrame({ children }) {
744
1139
  const host = useContentIrHost();
745
1140
  const label = "Still arriving";
746
- return /* @__PURE__ */ jsxs2("div", { className: "relative", "aria-busy": "true", children: [
1141
+ return /* @__PURE__ */ jsxs6("div", { className: "relative", "aria-busy": "true", children: [
747
1142
  children,
748
- /* @__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 }) })
749
1144
  ] });
750
1145
  }
751
1146
 
@@ -756,7 +1151,7 @@ import {
756
1151
  readObjectKind as readObjectKind2,
757
1152
  reconstructRegionValue
758
1153
  } from "@ai-matrx/content-ir";
759
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1154
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
760
1155
  function readStructuredValue(content, metadata) {
761
1156
  const envelope = readEnvelope3(metadata);
762
1157
  if (envelope) {
@@ -781,19 +1176,19 @@ function GenericStructuredView({
781
1176
  const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? readObjectKind2(value) : null) ?? "";
782
1177
  const marker = readIrRouteMarker(metadata);
783
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";
784
- return /* @__PURE__ */ jsxs3("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
785
- 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,
786
1181
  recovered ? host.renderValue({ value, ...kind ? { kind } : {}, note }) : (
787
1182
  // Zero-data-loss backstop: the region never parsed, so show the source
788
1183
  // verbatim rather than swallowing it.
789
- /* @__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 })
790
1185
  )
791
1186
  ] });
792
1187
  }
793
1188
 
794
1189
  // react/RuntimeWrapperViews.tsx
795
1190
  import { readNodeOutcomeValue, readObjectKind as readObjectKind3, readRunResultValue } from "@ai-matrx/content-ir";
796
- import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
1191
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
797
1192
  function isRecord2(value) {
798
1193
  return typeof value === "object" && value !== null && !Array.isArray(value);
799
1194
  }
@@ -809,16 +1204,16 @@ function DelegatedOutput({
809
1204
  }) {
810
1205
  const host = useContentIrHost();
811
1206
  if (output === null || output === void 0) {
812
- 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 });
813
1208
  }
814
1209
  if (!isRecord2(output)) {
815
- return /* @__PURE__ */ jsx5(Fragment2, { children: host.renderValue({ value: output }) });
1210
+ return /* @__PURE__ */ jsx11(Fragment3, { children: host.renderValue({ value: output }) });
816
1211
  }
817
1212
  const kind = readObjectKind3(output) ?? declaredKind;
818
1213
  if (!kind) {
819
- return /* @__PURE__ */ jsx5(Fragment2, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
1214
+ return /* @__PURE__ */ jsx11(Fragment3, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
820
1215
  }
821
- return /* @__PURE__ */ jsx5(
1216
+ return /* @__PURE__ */ jsx11(
822
1217
  KindInstanceRender,
823
1218
  {
824
1219
  kind,
@@ -835,7 +1230,7 @@ function NodeOutcomeView({ serverData, fallback }) {
835
1230
  readNodeOutcomeValue
836
1231
  );
837
1232
  if (!wrapper) return null;
838
- return /* @__PURE__ */ jsx5(
1233
+ return /* @__PURE__ */ jsx11(
839
1234
  DelegatedOutput,
840
1235
  {
841
1236
  output: wrapper.output,
@@ -850,14 +1245,14 @@ function RunResultView({ serverData, fallback }) {
850
1245
  readRunResultValue
851
1246
  );
852
1247
  if (!wrapper) return null;
853
- 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(
854
1249
  NodeOutcomeView,
855
1250
  {
856
1251
  serverData: { wrapper: outcome },
857
1252
  ...fallback === void 0 ? {} : { fallback }
858
1253
  },
859
1254
  `${outcome.node_id}:${outcome.attempt}`
860
- )) : /* @__PURE__ */ jsx5(
1255
+ )) : /* @__PURE__ */ jsx11(
861
1256
  DelegatedOutput,
862
1257
  {
863
1258
  output: wrapper.output,
@@ -1054,11 +1449,16 @@ var DbKindComponentErrorBoundary = class extends React2.Component {
1054
1449
  }
1055
1450
  };
1056
1451
  export {
1452
+ ApplyDirectiveButton,
1057
1453
  ComponentResolver,
1058
1454
  ContentIrRenderProvider,
1059
1455
  DB_KIND_COMPONENT_KEY,
1456
+ DIRECTIVE_BLOCK_TYPE,
1060
1457
  DbKindComponentErrorBoundary,
1061
1458
  DelegatedOutput,
1459
+ DirectiveFallbackCard,
1460
+ DirectiveHostProvider,
1461
+ DirectiveRender,
1062
1462
  GENERIC_STRUCTURED_COMPONENT_KEY,
1063
1463
  GenericStructuredView,
1064
1464
  IR_PROVISIONAL_KEY,
@@ -1068,11 +1468,13 @@ export {
1068
1468
  ProvisionalKindBoundary,
1069
1469
  ProvisionalKindFrame,
1070
1470
  RunResultView,
1471
+ SideEffectDirectiveCard,
1071
1472
  applyIrKindRoute,
1072
1473
  consoleErrorReporter,
1073
1474
  createDbKindComponentCache,
1074
1475
  createKindRouteBinding,
1075
1476
  envelopeFromPartialKind,
1477
+ getDirectiveRenderer,
1076
1478
  isDbKindComponentBodyPending,
1077
1479
  isPartialReadyKind,
1078
1480
  isProvisionalBlock,
@@ -1081,6 +1483,8 @@ export {
1081
1483
  kindServerDataFromStoredValue,
1082
1484
  markKindPartialUnsafe,
1083
1485
  readIrRouteMarker,
1486
+ registerDirectiveRenderer,
1487
+ resetDirectiveRenderers,
1084
1488
  resetPartialUnsafeKinds,
1085
1489
  resetSourcelessDbRowReports,
1086
1490
  resolveAnnouncedKindLoading,
@@ -1089,6 +1493,7 @@ export {
1089
1493
  useContentIrHost,
1090
1494
  useContentIrHostOrNull,
1091
1495
  useContentIrKindVersion,
1496
+ useDirectiveHost,
1092
1497
  useKindRouteEnv
1093
1498
  };
1094
1499
  //# sourceMappingURL=index.js.map