@ai-matrx/content-ir-react 0.10.0 → 0.11.1

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 +67 -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 +474 -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 +479 -36
  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 +404 -33
  31. package/dist/react.js.map +1 -1
  32. package/dist/{route-QL2Vqf2e.d.cts → route-B9U-9QCw.d.cts} +117 -3
  33. package/dist/{route-PUuEuEug.d.ts → route-gNpJ8zzW.d.ts} +117 -3
  34. package/dist/route.cjs +52 -2
  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 +55 -2
  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;
@@ -510,11 +538,13 @@ function kindServerDataFromStoredValue(value, env) {
510
538
 
511
539
  // route/partial-kind-route.ts
512
540
  import {
541
+ envelopeFromCompleteValue as envelopeFromCompleteValue2,
513
542
  IR_ENVELOPE_KEY,
514
543
  IR_PARTIAL_KEY,
515
544
  IR_VERSION,
516
545
  isProvisionalKind,
517
546
  readEnvelope as readEnvelope2,
547
+ readObjectKind as readObjectKind2,
518
548
  readPartialKindEvent
519
549
  } from "@ai-matrx/content-ir";
520
550
  var IR_PROVISIONAL_KEY = "__ir_provisional";
@@ -556,6 +586,36 @@ function resolveAnnouncedKindLoading(block, options) {
556
586
  if (verified && verified.root.status === "complete") return null;
557
587
  return { kind, envelope: envelopeFromPartialKind(event) };
558
588
  }
589
+ function parseCompletedJsonObject(content) {
590
+ let source = content.trim();
591
+ const fenced = source.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?```$/i);
592
+ if (fenced?.[1]) source = fenced[1].trim();
593
+ try {
594
+ const value = JSON.parse(source);
595
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
596
+ } catch {
597
+ return null;
598
+ }
599
+ }
600
+ function resolveSupersededKindRender(block, env, options) {
601
+ const event = readPartialKindEvent(block.metadata);
602
+ if (event?.state !== "superseded") return null;
603
+ if (readEnvelope2(block.metadata)?.root.status === "complete") return null;
604
+ const value = parseCompletedJsonObject(block.content);
605
+ if (!value || readObjectKind2(value) !== event.kind) return null;
606
+ const { [IR_PARTIAL_KEY]: _partial, ...rest } = block.metadata ?? {};
607
+ void _partial;
608
+ const envelope = envelopeFromCompleteValue2(value, event.kind);
609
+ const terminalBlock = {
610
+ ...block,
611
+ // A code/json block's serverData is an annotation, not kind data.
612
+ serverData: void 0,
613
+ metadata: { ...rest, [IR_ENVELOPE_KEY]: envelope }
614
+ };
615
+ const routed = applyIrKindRoute(terminalBlock, env, options);
616
+ if (routed === terminalBlock) return null;
617
+ return { block: routed, kind: event.kind, seq: event.seq, envelope };
618
+ }
559
619
  function resolveProvisionalKindRender(block, env, options) {
560
620
  if (options?.streamActive === false) return null;
561
621
  const event = readPartialKindEvent(block.metadata);
@@ -596,7 +656,12 @@ function createKindRouteBinding(env, options) {
596
656
  resolveProvisionalKindRender: (block, streamOptions) => resolveProvisionalKindRender(block, env, {
597
657
  ...streamOptions,
598
658
  ...ownedTypes ? { ownedTypes } : null
599
- })
659
+ }),
660
+ resolveSupersededKindRender: (block) => resolveSupersededKindRender(
661
+ block,
662
+ env,
663
+ ownedTypes ? { ownedTypes } : void 0
664
+ )
600
665
  };
601
666
  }
602
667
 
@@ -640,19 +705,386 @@ function useContentIrKindVersion(kind, sources) {
640
705
  }
641
706
 
642
707
  // 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";
708
+ import { useEffect as useEffect2, useState as useState3 } from "react";
709
+ import {
710
+ envelopeFromCompleteValue as envelopeFromCompleteValue3,
711
+ IR_ENVELOPE_KEY as IR_ENVELOPE_KEY2,
712
+ isReservedDirectiveSlug as isReservedDirectiveSlug2
713
+ } from "@ai-matrx/content-ir";
714
+
715
+ // directives/DirectiveRender.tsx
716
+ import { tryDecodeDirectiveContent } from "@ai-matrx/content-ir";
717
+
718
+ // directives/DirectiveFallbackCard.tsx
719
+ import { directiveDisplay } from "@ai-matrx/content-ir";
720
+
721
+ // directives/ApplyDirectiveButton.tsx
722
+ import { useEffect, useRef, useState } from "react";
723
+
724
+ // directives/icons.tsx
725
+ import { jsx as jsx3, jsxs } from "react/jsx-runtime";
726
+ function Svg({ children, ...props }) {
727
+ return /* @__PURE__ */ jsx3(
728
+ "svg",
729
+ {
730
+ xmlns: "http://www.w3.org/2000/svg",
731
+ viewBox: "0 0 24 24",
732
+ fill: "none",
733
+ stroke: "currentColor",
734
+ strokeWidth: 2,
735
+ strokeLinecap: "round",
736
+ strokeLinejoin: "round",
737
+ "aria-hidden": "true",
738
+ ...props,
739
+ children
740
+ }
741
+ );
742
+ }
743
+ var FilePlusIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
744
+ /* @__PURE__ */ jsx3("path", { d: "M4 22h14a2 2 0 0 0 2-2V7l-5-5H6a2 2 0 0 0-2 2v4" }),
745
+ /* @__PURE__ */ jsx3("path", { d: "M14 2v4a2 2 0 0 0 2 2h4" }),
746
+ /* @__PURE__ */ jsx3("path", { d: "M3 15h6" }),
747
+ /* @__PURE__ */ jsx3("path", { d: "M6 12v6" })
748
+ ] });
749
+ var PencilIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
750
+ /* @__PURE__ */ jsx3("path", { d: "M12 20h9" }),
751
+ /* @__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" })
752
+ ] });
753
+ var TrashIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
754
+ /* @__PURE__ */ jsx3("path", { d: "M3 6h18" }),
755
+ /* @__PURE__ */ jsx3("path", { d: "M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6" }),
756
+ /* @__PURE__ */ jsx3("path", { d: "M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2" }),
757
+ /* @__PURE__ */ jsx3("line", { x1: "10", x2: "10", y1: "11", y2: "17" }),
758
+ /* @__PURE__ */ jsx3("line", { x1: "14", x2: "14", y1: "11", y2: "17" })
759
+ ] });
760
+ var PlayIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("polygon", { points: "6 3 20 12 6 21 6 3" }) });
761
+ var WebhookIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
762
+ /* @__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" }),
763
+ /* @__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" }),
764
+ /* @__PURE__ */ jsx3("path", { d: "m12 6 3.13 5.73C15.66 12.7 16.9 13 18 13a4 4 0 0 1 0 8" })
765
+ ] });
766
+ var BoxesIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
767
+ /* @__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" }),
768
+ /* @__PURE__ */ jsx3("path", { d: "m7 16.5-4.74-2.85" }),
769
+ /* @__PURE__ */ jsx3("path", { d: "m7 16.5 5-3" }),
770
+ /* @__PURE__ */ jsx3("path", { d: "M7 16.5v5.17" }),
771
+ /* @__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" }),
772
+ /* @__PURE__ */ jsx3("path", { d: "m17 16.5-5-3" }),
773
+ /* @__PURE__ */ jsx3("path", { d: "m17 16.5 4.74-2.85" }),
774
+ /* @__PURE__ */ jsx3("path", { d: "M17 16.5v5.17" }),
775
+ /* @__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" }),
776
+ /* @__PURE__ */ jsx3("path", { d: "M12 8 7.26 5.15" }),
777
+ /* @__PURE__ */ jsx3("path", { d: "m12 8 4.74-2.85" }),
778
+ /* @__PURE__ */ jsx3("path", { d: "M12 13.5V8" })
779
+ ] });
780
+ var ChevronDownIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "m6 9 6 6 6-6" }) });
781
+ var ChevronRightIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "m9 18 6-6-6-6" }) });
782
+ var MaximizeIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
783
+ /* @__PURE__ */ jsx3("polyline", { points: "15 3 21 3 21 9" }),
784
+ /* @__PURE__ */ jsx3("polyline", { points: "9 21 3 21 3 15" }),
785
+ /* @__PURE__ */ jsx3("line", { x1: "21", x2: "14", y1: "3", y2: "10" }),
786
+ /* @__PURE__ */ jsx3("line", { x1: "3", x2: "10", y1: "21", y2: "14" })
787
+ ] });
788
+ var LoaderIcon = (p) => /* @__PURE__ */ jsx3(Svg, { ...p, children: /* @__PURE__ */ jsx3("path", { d: "M21 12a9 9 0 1 1-6.219-8.56" }) });
789
+ var CheckCircleIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
790
+ /* @__PURE__ */ jsx3("circle", { cx: "12", cy: "12", r: "10" }),
791
+ /* @__PURE__ */ jsx3("path", { d: "m9 12 2 2 4-4" })
792
+ ] });
793
+ var AlertIcon = (p) => /* @__PURE__ */ jsxs(Svg, { ...p, children: [
794
+ /* @__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" }),
795
+ /* @__PURE__ */ jsx3("path", { d: "M12 9v4" }),
796
+ /* @__PURE__ */ jsx3("path", { d: "M12 17h.01" })
797
+ ] });
798
+ var AGENT_NOUNS = /* @__PURE__ */ new Set(["create_agent", "create_agent_definition", "agent"]);
799
+ function classIcon(directiveClass, noun) {
800
+ if (directiveClass === "action" && AGENT_NOUNS.has(noun)) return WebhookIcon;
801
+ switch (directiveClass) {
802
+ case "create":
803
+ return FilePlusIcon;
804
+ case "update":
805
+ return PencilIcon;
806
+ case "delete":
807
+ return TrashIcon;
808
+ default:
809
+ return PlayIcon;
810
+ }
811
+ }
812
+
813
+ // directives/ApplyDirectiveButton.tsx
814
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
815
+ function ApplyDirectiveButton({
816
+ directive,
817
+ label = "Apply",
818
+ itemCount,
819
+ onApplied
820
+ }) {
821
+ const host = useDirectiveHost();
822
+ const [state, setState] = useState({ status: "idle" });
823
+ const [elapsed, setElapsed] = useState(0);
824
+ const startedAt = useRef(null);
825
+ useEffect(() => {
826
+ if (state.status !== "applying") return;
827
+ startedAt.current = Date.now();
828
+ const id = setInterval(
829
+ () => setElapsed(Math.round((Date.now() - (startedAt.current ?? 0)) / 1e3)),
830
+ 1e3
831
+ );
832
+ return () => clearInterval(id);
833
+ }, [state.status]);
834
+ if (!directive.parsed.executes) return null;
835
+ const confirm = host.confirm;
836
+ if (!confirm) return null;
837
+ const items = directive.items;
838
+ async function handleApply() {
839
+ if (!confirm) return;
840
+ setState({ status: "applying" });
841
+ try {
842
+ const result = await confirm({ __kind: directive.slug, items });
843
+ setState({ status: "applied", applied: result.applied, failed: result.failed });
844
+ onApplied?.();
845
+ } catch (error) {
846
+ setState({
847
+ status: "error",
848
+ message: error instanceof Error && error.message ? error.message : "That couldn't be applied just now. Please try again."
849
+ });
850
+ }
851
+ }
852
+ if (state.status === "applied") {
853
+ const bad = state.failed > 0;
854
+ return /* @__PURE__ */ jsxs2(
855
+ "span",
856
+ {
857
+ className: `inline-flex items-center gap-1 text-xs ${bad ? "text-destructive" : "text-primary"}`,
858
+ children: [
859
+ bad ? /* @__PURE__ */ jsx4(AlertIcon, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ jsx4(CheckCircleIcon, { className: "h-3.5 w-3.5" }),
860
+ "Applied ",
861
+ state.applied,
862
+ bad ? ` \xB7 ${state.failed} failed` : ""
863
+ ]
864
+ }
865
+ );
866
+ }
867
+ return /* @__PURE__ */ jsxs2("span", { className: "inline-flex items-center gap-2", children: [
868
+ /* @__PURE__ */ jsxs2(
869
+ "button",
870
+ {
871
+ type: "button",
872
+ onClick: () => void handleApply(),
873
+ disabled: state.status === "applying" || items.length === 0,
874
+ 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",
875
+ children: [
876
+ 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" }),
877
+ state.status === "applying" ? `Applying${itemCount ? ` ${itemCount} ${itemCount === 1 ? "item" : "items"}` : ""}\u2026${elapsed ? ` ${elapsed}s` : ""}` : label
878
+ ]
879
+ }
880
+ ),
881
+ state.status === "error" ? /* @__PURE__ */ jsxs2("span", { className: "inline-flex max-w-sm items-start gap-1 text-xs text-destructive", children: [
882
+ /* @__PURE__ */ jsx4(AlertIcon, { className: "mt-0.5 h-3.5 w-3.5 shrink-0" }),
883
+ /* @__PURE__ */ jsx4("span", { children: state.message })
884
+ ] }) : null
885
+ ] });
886
+ }
887
+
888
+ // directives/DirectiveFallbackCard.tsx
889
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
890
+ function DirectiveFallbackCard({ directive, reason }) {
891
+ const host = useDirectiveHost();
892
+ const count = directive.items.length;
893
+ const display = directiveDisplay(directive.directiveClass, directive.noun, host.nouns);
894
+ 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: [
895
+ /* @__PURE__ */ jsx5(BoxesIcon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
896
+ /* @__PURE__ */ jsx5("span", { className: "text-foreground", children: display.title }),
897
+ display.family ? /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
898
+ "\xB7 ",
899
+ display.family
900
+ ] }) : null,
901
+ /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
902
+ "\xB7 ",
903
+ count,
904
+ " ",
905
+ count === 1 ? "item" : "items"
906
+ ] }),
907
+ reason ? /* @__PURE__ */ jsxs3("span", { className: "text-muted-foreground", children: [
908
+ "\xB7 ",
909
+ reason
910
+ ] }) : null,
911
+ /* @__PURE__ */ jsx5(ApplyDirectiveButton, { directive })
912
+ ] });
913
+ }
914
+
915
+ // directives/registry.ts
916
+ import {
917
+ buildDirectiveSlug
918
+ } from "@ai-matrx/content-ir";
919
+ var REGISTRY_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.content-ir-react.directive-renderers");
920
+ var registry = globalThis[REGISTRY_SLOT] ??= {
921
+ bySlug: /* @__PURE__ */ new Map(),
922
+ byClass: /* @__PURE__ */ new Map()
923
+ };
924
+ function registerDirectiveRenderer(directiveClass, renderer, noun) {
925
+ if (noun) registry.bySlug.set(buildDirectiveSlug(directiveClass, noun), renderer);
926
+ else registry.byClass.set(directiveClass, renderer);
927
+ }
928
+ function getDirectiveRenderer(directive) {
929
+ return registry.bySlug.get(directive.slug) ?? registry.byClass.get(directive.directiveClass) ?? null;
930
+ }
931
+ function resetDirectiveRenderers() {
932
+ registry.bySlug.clear();
933
+ registry.byClass.clear();
934
+ }
935
+
936
+ // directives/SideEffectDirectiveCard.tsx
937
+ import { useState as useState2 } from "react";
938
+ import {
939
+ asKindInstance,
940
+ directiveDisplay as directiveDisplay2,
941
+ itemFacts,
942
+ itemSubtitle,
943
+ itemTitle,
944
+ nounTitleColumn
945
+ } from "@ai-matrx/content-ir";
946
+ import { Fragment, jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
947
+ var ROWS_BEFORE_FOLD = 3;
948
+ function ItemRow({
949
+ directive,
950
+ item,
951
+ index,
952
+ total
953
+ }) {
954
+ const host = useDirectiveHost();
955
+ const titleColumn = nounTitleColumn(directive.noun, host.nouns);
956
+ const title = itemTitle(item, titleColumn, index, total);
957
+ const subtitle = itemSubtitle(item);
958
+ const facts = itemFacts(item);
959
+ const kind = host.itemKind?.(directive.slug) ?? null;
960
+ const display = directiveDisplay2(directive.directiveClass, directive.noun, host.nouns);
961
+ const openItem = host.openItem;
962
+ const body = /* @__PURE__ */ jsxs4(Fragment, { children: [
963
+ /* @__PURE__ */ jsx6("span", { className: "min-w-0 shrink-0 truncate font-medium text-foreground", children: title }),
964
+ /* @__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: [
965
+ fact.value,
966
+ " ",
967
+ fact.label
968
+ ] }, fact.key)) }),
969
+ subtitle && facts.length === 0 ? /* @__PURE__ */ jsx6("span", { className: "hidden truncate text-[11px] text-muted-foreground sm:inline", children: subtitle }) : null,
970
+ openItem ? /* @__PURE__ */ jsx6(MaximizeIcon, { className: "ml-auto h-3 w-3 shrink-0 text-muted-foreground" }) : null
971
+ ] });
972
+ return /* @__PURE__ */ jsxs4("div", { className: "flex items-center gap-2 py-1 text-xs", children: [
973
+ openItem ? /* @__PURE__ */ jsx6(
974
+ "button",
975
+ {
976
+ type: "button",
977
+ onClick: () => openItem({
978
+ // Stamped so the panel's kind pipeline types it from its own first key.
979
+ item: asKindInstance(item, kind) ?? item,
980
+ itemKind: kind,
981
+ title,
982
+ subtitle: `${display.title} \xB7 item ${index + 1} of ${total}`,
983
+ directive,
984
+ index,
985
+ total
986
+ }),
987
+ 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",
988
+ title: "Open to read it",
989
+ children: body
990
+ }
991
+ ) : /* @__PURE__ */ jsx6("span", { className: "flex min-w-0 flex-1 items-center gap-2 px-1 py-0.5", children: body }),
992
+ host.renderCopy?.({ label: title, value: item, kind, size: "xs" })
993
+ ] });
994
+ }
995
+ function SideEffectDirectiveCard({ directive }) {
996
+ const host = useDirectiveHost();
997
+ const [expanded, setExpanded] = useState2(false);
998
+ const items = directive.items;
999
+ const total = items.length;
1000
+ const display = directiveDisplay2(directive.directiveClass, directive.noun, host.nouns);
1001
+ const Icon = classIcon(directive.directiveClass, directive.noun);
1002
+ const shown = expanded ? items : items.slice(0, ROWS_BEFORE_FOLD);
1003
+ const hidden = total - shown.length;
1004
+ 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: [
1005
+ /* @__PURE__ */ jsxs4("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
1006
+ /* @__PURE__ */ jsx6(Icon, { className: "h-3.5 w-3.5 shrink-0 text-muted-foreground" }),
1007
+ /* @__PURE__ */ jsx6("span", { className: "text-sm font-medium text-foreground", children: display.title }),
1008
+ display.family ? /* @__PURE__ */ jsx6("span", { className: "text-xs text-muted-foreground", children: display.family }) : null,
1009
+ /* @__PURE__ */ jsxs4("span", { className: "text-xs tabular-nums text-muted-foreground", children: [
1010
+ total,
1011
+ " ",
1012
+ total === 1 ? "item" : "items"
1013
+ ] }),
1014
+ /* @__PURE__ */ jsxs4("div", { className: "ml-auto flex items-center gap-1", children: [
1015
+ host.renderCopy?.({ label: display.title, value: directive.shell, size: "icon" }),
1016
+ /* @__PURE__ */ jsx6(ApplyDirectiveButton, { directive, itemCount: total })
1017
+ ] })
1018
+ ] }),
1019
+ total === 0 ? (
1020
+ // Stated, never silent: an empty batch is a real (and suspicious) state.
1021
+ /* @__PURE__ */ jsx6("p", { className: "mt-1 text-xs text-muted-foreground", children: "No items \u2014 nothing would be written." })
1022
+ ) : /* @__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)) }),
1023
+ hidden > 0 || expanded ? /* @__PURE__ */ jsxs4(
1024
+ "button",
1025
+ {
1026
+ type: "button",
1027
+ onClick: () => setExpanded((v) => !v),
1028
+ className: "mt-0.5 inline-flex items-center gap-1 rounded px-1 py-0.5 text-[11px] text-muted-foreground hover:text-foreground",
1029
+ children: [
1030
+ expanded ? /* @__PURE__ */ jsx6(ChevronDownIcon, { className: "h-3 w-3" }) : /* @__PURE__ */ jsx6(ChevronRightIcon, { className: "h-3 w-3" }),
1031
+ expanded ? "Show less" : `Show ${hidden} more`
1032
+ ]
1033
+ }
1034
+ ) : null
1035
+ ] });
1036
+ }
1037
+
1038
+ // directives/DirectiveRender.tsx
1039
+ import { jsx as jsx7 } from "react/jsx-runtime";
1040
+ function DirectiveRender({ content, className }) {
1041
+ const host = useDirectiveHost();
1042
+ const directive = tryDecodeDirectiveContent(content, (message) => {
1043
+ const line = `[kind-directives] ${message}`;
1044
+ if (host.reportError) host.reportError(line);
1045
+ else console.error(line);
1046
+ });
1047
+ if (!directive) {
1048
+ const raw = typeof content === "string" ? content : JSON.stringify(content, null, 2);
1049
+ return /* @__PURE__ */ jsx7(
1050
+ "pre",
1051
+ {
1052
+ className: `my-3 overflow-x-auto rounded-md border border-border bg-muted px-3 py-2 text-xs text-muted-foreground${className ? ` ${className}` : ""}`,
1053
+ children: raw
1054
+ }
1055
+ );
1056
+ }
1057
+ const Renderer = getDirectiveRenderer(directive);
1058
+ if (Renderer) return /* @__PURE__ */ jsx7(Renderer, { directive });
1059
+ if (directive.parsed.executes) return /* @__PURE__ */ jsx7(SideEffectDirectiveCard, { directive });
1060
+ return /* @__PURE__ */ jsx7(DirectiveFallbackCard, { directive });
1061
+ }
1062
+
1063
+ // react/KindInstanceRender.tsx
1064
+ import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
646
1065
  function isRecordValue(value) {
647
1066
  return typeof value === "object" && value !== null && !Array.isArray(value);
648
1067
  }
649
1068
  function kindIsRoutable(kind, host) {
1069
+ if (isReservedDirectiveSlug2(kind)) return true;
650
1070
  if (host.kinds.getDefinition(kind)?.legacyBlockType) return true;
651
1071
  const resolution = host.components.resolve(kind, host.platform, "output");
652
1072
  if (!resolution?.isActive) return false;
653
1073
  return resolution.componentKey !== GENERIC_STRUCTURED_COMPONENT_KEY;
654
1074
  }
655
- function KindInstanceRender({
1075
+ function KindInstanceRender(props) {
1076
+ if (isReservedDirectiveSlug2(props.kind)) {
1077
+ return /* @__PURE__ */ jsx8(
1078
+ DirectiveRender,
1079
+ {
1080
+ content: props.value,
1081
+ ...props.className === void 0 ? {} : { className: props.className }
1082
+ }
1083
+ );
1084
+ }
1085
+ return /* @__PURE__ */ jsx8(KindInstanceRenderInner, { ...props });
1086
+ }
1087
+ function KindInstanceRenderInner({
656
1088
  kind,
657
1089
  value,
658
1090
  showRoutingNote = true,
@@ -661,10 +1093,10 @@ function KindInstanceRender({
661
1093
  className
662
1094
  }) {
663
1095
  const host = useContentIrHost();
664
- const [routingStatus, setRoutingStatus] = useState(
1096
+ const [routingStatus, setRoutingStatus] = useState3(
665
1097
  () => kindIsRoutable(kind, host) ? "routable" : "checking"
666
1098
  );
667
- useEffect(() => {
1099
+ useEffect2(() => {
668
1100
  let cancelled = false;
669
1101
  let warmed = false;
670
1102
  const syncRoutingStatus = () => {
@@ -696,24 +1128,24 @@ function KindInstanceRender({
696
1128
  content: JSON.stringify(value, null, 2),
697
1129
  language: "json",
698
1130
  metadata: {
699
- [IR_ENVELOPE_KEY2]: envelopeFromCompleteValue2(value, kind)
1131
+ [IR_ENVELOPE_KEY2]: envelopeFromCompleteValue3(value, kind)
700
1132
  }
701
1133
  } : null;
702
1134
  const frameClass = variant === "bare" ? void 0 : "rounded-md border border-border bg-card p-3";
703
1135
  if (routingStatus === "unroutable" && unroutableFallback !== void 0) {
704
- return /* @__PURE__ */ jsx2(Fragment, { children: unroutableFallback });
1136
+ return /* @__PURE__ */ jsx8(Fragment2, { children: unroutableFallback });
705
1137
  }
706
1138
  const onTheFloor = block === null || routingStatus === "unroutable";
707
1139
  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) })
1140
+ return /* @__PURE__ */ jsxs5("div", { className: className ? `space-y-3 ${className}` : "space-y-3", children: [
1141
+ 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,
1142
+ /* @__PURE__ */ jsx8("div", { className: frameClass, children: onTheFloor ? host.renderValue({ value, kind }) : host.renderBlock(block) })
711
1143
  ] });
712
1144
  }
713
1145
 
714
1146
  // react/ProvisionalKindBoundary.tsx
715
1147
  import React from "react";
716
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1148
+ import { jsx as jsx9, jsxs as jsxs6 } from "react/jsx-runtime";
717
1149
  var ProvisionalKindBoundaryInner = class extends React.Component {
718
1150
  state = { failed: false };
719
1151
  static getDerivedStateFromError() {
@@ -738,14 +1170,14 @@ var ProvisionalKindBoundaryInner = class extends React.Component {
738
1170
  };
739
1171
  function ProvisionalKindBoundary(props) {
740
1172
  const host = useContentIrHost();
741
- return /* @__PURE__ */ jsx3(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
1173
+ return /* @__PURE__ */ jsx9(ProvisionalKindBoundaryInner, { ...props, reportError: host.reportError });
742
1174
  }
743
1175
  function ProvisionalKindFrame({ children }) {
744
1176
  const host = useContentIrHost();
745
1177
  const label = "Still arriving";
746
- return /* @__PURE__ */ jsxs2("div", { className: "relative", "aria-busy": "true", children: [
1178
+ return /* @__PURE__ */ jsxs6("div", { className: "relative", "aria-busy": "true", children: [
747
1179
  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 }) })
1180
+ /* @__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
1181
  ] });
750
1182
  }
751
1183
 
@@ -753,10 +1185,10 @@ function ProvisionalKindFrame({ children }) {
753
1185
  import "react";
754
1186
  import {
755
1187
  readEnvelope as readEnvelope3,
756
- readObjectKind as readObjectKind2,
1188
+ readObjectKind as readObjectKind3,
757
1189
  reconstructRegionValue
758
1190
  } from "@ai-matrx/content-ir";
759
- import { jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1191
+ import { jsx as jsx10, jsxs as jsxs7 } from "react/jsx-runtime";
760
1192
  function readStructuredValue(content, metadata) {
761
1193
  const envelope = readEnvelope3(metadata);
762
1194
  if (envelope) {
@@ -778,22 +1210,22 @@ function GenericStructuredView({
778
1210
  const envelope = readEnvelope3(metadata);
779
1211
  const status = envelope?.root.status ?? "complete";
780
1212
  const { value, recovered } = readStructuredValue(content, metadata);
781
- const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? readObjectKind2(value) : null) ?? "";
1213
+ const kind = envelope?.root.kind ?? (typeof value === "object" && value !== null && !Array.isArray(value) ? readObjectKind3(value) : null) ?? "";
782
1214
  const marker = readIrRouteMarker(metadata);
783
1215
  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,
1216
+ return /* @__PURE__ */ jsxs7("div", { className: className ? `my-2 min-w-0 ${className}` : "my-2 min-w-0", children: [
1217
+ status === "streaming" ? streamingIndicator ?? /* @__PURE__ */ jsx10("div", { className: "mb-2 text-xs text-muted-foreground", children: "Still arriving\u2026" }) : null,
786
1218
  recovered ? host.renderValue({ value, ...kind ? { kind } : {}, note }) : (
787
1219
  // Zero-data-loss backstop: the region never parsed, so show the source
788
1220
  // 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 })
1221
+ /* @__PURE__ */ jsx10("pre", { className: "max-h-96 overflow-auto font-mono text-xs leading-relaxed text-muted-foreground", children: content })
790
1222
  )
791
1223
  ] });
792
1224
  }
793
1225
 
794
1226
  // react/RuntimeWrapperViews.tsx
795
- import { readNodeOutcomeValue, readObjectKind as readObjectKind3, readRunResultValue } from "@ai-matrx/content-ir";
796
- import { Fragment as Fragment2, jsx as jsx5 } from "react/jsx-runtime";
1227
+ import { readNodeOutcomeValue, readObjectKind as readObjectKind4, readRunResultValue } from "@ai-matrx/content-ir";
1228
+ import { Fragment as Fragment3, jsx as jsx11 } from "react/jsx-runtime";
797
1229
  function isRecord2(value) {
798
1230
  return typeof value === "object" && value !== null && !Array.isArray(value);
799
1231
  }
@@ -809,16 +1241,16 @@ function DelegatedOutput({
809
1241
  }) {
810
1242
  const host = useContentIrHost();
811
1243
  if (output === null || output === void 0) {
812
- return /* @__PURE__ */ jsx5("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
1244
+ return /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground", children: emptyLabel });
813
1245
  }
814
1246
  if (!isRecord2(output)) {
815
- return /* @__PURE__ */ jsx5(Fragment2, { children: host.renderValue({ value: output }) });
1247
+ return /* @__PURE__ */ jsx11(Fragment3, { children: host.renderValue({ value: output }) });
816
1248
  }
817
- const kind = readObjectKind3(output) ?? declaredKind;
1249
+ const kind = readObjectKind4(output) ?? declaredKind;
818
1250
  if (!kind) {
819
- return /* @__PURE__ */ jsx5(Fragment2, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
1251
+ return /* @__PURE__ */ jsx11(Fragment3, { children: fallback?.(output) ?? host.renderValue({ value: output }) });
820
1252
  }
821
- return /* @__PURE__ */ jsx5(
1253
+ return /* @__PURE__ */ jsx11(
822
1254
  KindInstanceRender,
823
1255
  {
824
1256
  kind,
@@ -835,7 +1267,7 @@ function NodeOutcomeView({ serverData, fallback }) {
835
1267
  readNodeOutcomeValue
836
1268
  );
837
1269
  if (!wrapper) return null;
838
- return /* @__PURE__ */ jsx5(
1270
+ return /* @__PURE__ */ jsx11(
839
1271
  DelegatedOutput,
840
1272
  {
841
1273
  output: wrapper.output,
@@ -850,14 +1282,14 @@ function RunResultView({ serverData, fallback }) {
850
1282
  readRunResultValue
851
1283
  );
852
1284
  if (!wrapper) return null;
853
- return /* @__PURE__ */ jsx5("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ jsx5(
1285
+ return /* @__PURE__ */ jsx11("div", { className: "space-y-2", children: wrapper.outputs.length > 0 ? wrapper.outputs.map((outcome) => /* @__PURE__ */ jsx11(
854
1286
  NodeOutcomeView,
855
1287
  {
856
1288
  serverData: { wrapper: outcome },
857
1289
  ...fallback === void 0 ? {} : { fallback }
858
1290
  },
859
1291
  `${outcome.node_id}:${outcome.attempt}`
860
- )) : /* @__PURE__ */ jsx5(
1292
+ )) : /* @__PURE__ */ jsx11(
861
1293
  DelegatedOutput,
862
1294
  {
863
1295
  output: wrapper.output,
@@ -1054,11 +1486,16 @@ var DbKindComponentErrorBoundary = class extends React2.Component {
1054
1486
  }
1055
1487
  };
1056
1488
  export {
1489
+ ApplyDirectiveButton,
1057
1490
  ComponentResolver,
1058
1491
  ContentIrRenderProvider,
1059
1492
  DB_KIND_COMPONENT_KEY,
1493
+ DIRECTIVE_BLOCK_TYPE,
1060
1494
  DbKindComponentErrorBoundary,
1061
1495
  DelegatedOutput,
1496
+ DirectiveFallbackCard,
1497
+ DirectiveHostProvider,
1498
+ DirectiveRender,
1062
1499
  GENERIC_STRUCTURED_COMPONENT_KEY,
1063
1500
  GenericStructuredView,
1064
1501
  IR_PROVISIONAL_KEY,
@@ -1068,11 +1505,13 @@ export {
1068
1505
  ProvisionalKindBoundary,
1069
1506
  ProvisionalKindFrame,
1070
1507
  RunResultView,
1508
+ SideEffectDirectiveCard,
1071
1509
  applyIrKindRoute,
1072
1510
  consoleErrorReporter,
1073
1511
  createDbKindComponentCache,
1074
1512
  createKindRouteBinding,
1075
1513
  envelopeFromPartialKind,
1514
+ getDirectiveRenderer,
1076
1515
  isDbKindComponentBodyPending,
1077
1516
  isPartialReadyKind,
1078
1517
  isProvisionalBlock,
@@ -1081,14 +1520,18 @@ export {
1081
1520
  kindServerDataFromStoredValue,
1082
1521
  markKindPartialUnsafe,
1083
1522
  readIrRouteMarker,
1523
+ registerDirectiveRenderer,
1524
+ resetDirectiveRenderers,
1084
1525
  resetPartialUnsafeKinds,
1085
1526
  resetSourcelessDbRowReports,
1086
1527
  resolveAnnouncedKindLoading,
1087
1528
  resolveProvisionalKindRender,
1529
+ resolveSupersededKindRender,
1088
1530
  routeEnvOf,
1089
1531
  useContentIrHost,
1090
1532
  useContentIrHostOrNull,
1091
1533
  useContentIrKindVersion,
1534
+ useDirectiveHost,
1092
1535
  useKindRouteEnv
1093
1536
  };
1094
1537
  //# sourceMappingURL=index.js.map