@cellarnode/ui 0.201.0 → 0.202.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 (158) hide show
  1. package/dist/agent/composer.d.ts +6 -1
  2. package/dist/agent/composer.d.ts.map +1 -1
  3. package/dist/agent/composer.js +43 -9
  4. package/dist/agent/composer.js.map +1 -1
  5. package/dist/agent/conversation.d.ts +20 -2
  6. package/dist/agent/conversation.d.ts.map +1 -1
  7. package/dist/agent/conversation.js +37 -5
  8. package/dist/agent/conversation.js.map +1 -1
  9. package/dist/agent/copy.d.ts +7 -0
  10. package/dist/agent/copy.d.ts.map +1 -1
  11. package/dist/agent/copy.js +9 -0
  12. package/dist/agent/copy.js.map +1 -1
  13. package/dist/agent/fixtures.d.ts +34 -0
  14. package/dist/agent/fixtures.d.ts.map +1 -1
  15. package/dist/agent/fixtures.js +77 -0
  16. package/dist/agent/fixtures.js.map +1 -1
  17. package/dist/agent/index.d.ts +18 -1
  18. package/dist/agent/index.d.ts.map +1 -1
  19. package/dist/agent/index.js +18 -1
  20. package/dist/agent/index.js.map +1 -1
  21. package/dist/agent/markdown.d.ts +64 -0
  22. package/dist/agent/markdown.d.ts.map +1 -0
  23. package/dist/agent/markdown.js +220 -0
  24. package/dist/agent/markdown.js.map +1 -0
  25. package/dist/agent/masked-value.d.ts +1 -0
  26. package/dist/agent/masked-value.d.ts.map +1 -1
  27. package/dist/agent/masked-value.js +4 -1
  28. package/dist/agent/masked-value.js.map +1 -1
  29. package/dist/agent/message.d.ts +26 -6
  30. package/dist/agent/message.d.ts.map +1 -1
  31. package/dist/agent/message.js +47 -11
  32. package/dist/agent/message.js.map +1 -1
  33. package/dist/agent/panel-frame.js +1 -1
  34. package/dist/agent/panel-frame.js.map +1 -1
  35. package/dist/agent/role-cards/card-kit.d.ts +111 -0
  36. package/dist/agent/role-cards/card-kit.d.ts.map +1 -0
  37. package/dist/agent/role-cards/card-kit.js +68 -0
  38. package/dist/agent/role-cards/card-kit.js.map +1 -0
  39. package/dist/agent/role-cards/data-table-card.d.ts +80 -0
  40. package/dist/agent/role-cards/data-table-card.d.ts.map +1 -0
  41. package/dist/agent/role-cards/data-table-card.js +214 -0
  42. package/dist/agent/role-cards/data-table-card.js.map +1 -0
  43. package/dist/agent/role-cards/fixtures.d.ts +124 -0
  44. package/dist/agent/role-cards/fixtures.d.ts.map +1 -0
  45. package/dist/agent/role-cards/fixtures.js +401 -0
  46. package/dist/agent/role-cards/fixtures.js.map +1 -0
  47. package/dist/agent/role-cards/host-contract.d.ts +214 -0
  48. package/dist/agent/role-cards/host-contract.d.ts.map +1 -0
  49. package/dist/agent/role-cards/host-contract.js +348 -0
  50. package/dist/agent/role-cards/host-contract.js.map +1 -0
  51. package/dist/agent/role-cards/inspector-drawer.d.ts +42 -0
  52. package/dist/agent/role-cards/inspector-drawer.d.ts.map +1 -0
  53. package/dist/agent/role-cards/inspector-drawer.js +68 -0
  54. package/dist/agent/role-cards/inspector-drawer.js.map +1 -0
  55. package/dist/agent/role-cards/inspector-fixtures.d.ts +84 -0
  56. package/dist/agent/role-cards/inspector-fixtures.d.ts.map +1 -0
  57. package/dist/agent/role-cards/inspector-fixtures.js +162 -0
  58. package/dist/agent/role-cards/inspector-fixtures.js.map +1 -0
  59. package/dist/agent/role-cards/inspector-record.d.ts +109 -0
  60. package/dist/agent/role-cards/inspector-record.d.ts.map +1 -0
  61. package/dist/agent/role-cards/inspector-record.js +346 -0
  62. package/dist/agent/role-cards/inspector-record.js.map +1 -0
  63. package/dist/agent/role-cards/inspector-view.d.ts +137 -0
  64. package/dist/agent/role-cards/inspector-view.d.ts.map +1 -0
  65. package/dist/agent/role-cards/inspector-view.js +261 -0
  66. package/dist/agent/role-cards/inspector-view.js.map +1 -0
  67. package/dist/agent/role-cards/match-card.d.ts +21 -0
  68. package/dist/agent/role-cards/match-card.d.ts.map +1 -0
  69. package/dist/agent/role-cards/match-card.js +30 -0
  70. package/dist/agent/role-cards/match-card.js.map +1 -0
  71. package/dist/agent/role-cards/offer-card.d.ts +27 -0
  72. package/dist/agent/role-cards/offer-card.d.ts.map +1 -0
  73. package/dist/agent/role-cards/offer-card.js +68 -0
  74. package/dist/agent/role-cards/offer-card.js.map +1 -0
  75. package/dist/agent/role-cards/opportunity-card.d.ts +26 -0
  76. package/dist/agent/role-cards/opportunity-card.d.ts.map +1 -0
  77. package/dist/agent/role-cards/opportunity-card.js +50 -0
  78. package/dist/agent/role-cards/opportunity-card.js.map +1 -0
  79. package/dist/agent/role-cards/product-card.d.ts +32 -0
  80. package/dist/agent/role-cards/product-card.d.ts.map +1 -0
  81. package/dist/agent/role-cards/product-card.js +50 -0
  82. package/dist/agent/role-cards/product-card.js.map +1 -0
  83. package/dist/agent/role-cards/proposal-diff.d.ts +38 -0
  84. package/dist/agent/role-cards/proposal-diff.d.ts.map +1 -0
  85. package/dist/agent/role-cards/proposal-diff.js +74 -0
  86. package/dist/agent/role-cards/proposal-diff.js.map +1 -0
  87. package/dist/agent/role-cards/registry.d.ts +43 -0
  88. package/dist/agent/role-cards/registry.d.ts.map +1 -0
  89. package/dist/agent/role-cards/registry.js +46 -0
  90. package/dist/agent/role-cards/registry.js.map +1 -0
  91. package/dist/agent/role-cards/score-meter.d.ts +12 -0
  92. package/dist/agent/role-cards/score-meter.d.ts.map +1 -0
  93. package/dist/agent/role-cards/score-meter.js +17 -0
  94. package/dist/agent/role-cards/score-meter.js.map +1 -0
  95. package/dist/agent/role-cards/surface-links.d.ts +54 -0
  96. package/dist/agent/role-cards/surface-links.d.ts.map +1 -0
  97. package/dist/agent/role-cards/surface-links.js +149 -0
  98. package/dist/agent/role-cards/surface-links.js.map +1 -0
  99. package/dist/agent/role-cards/text-safety.d.ts +24 -0
  100. package/dist/agent/role-cards/text-safety.d.ts.map +1 -0
  101. package/dist/agent/role-cards/text-safety.js +61 -0
  102. package/dist/agent/role-cards/text-safety.js.map +1 -0
  103. package/dist/agent/schema.d.ts +7 -0
  104. package/dist/agent/schema.d.ts.map +1 -1
  105. package/dist/agent/schema.js +25 -2
  106. package/dist/agent/schema.js.map +1 -1
  107. package/dist/agent/states.d.ts +1 -0
  108. package/dist/agent/states.d.ts.map +1 -1
  109. package/dist/agent/states.js +1 -1
  110. package/dist/agent/states.js.map +1 -1
  111. package/dist/agent/thinking.d.ts +13 -4
  112. package/dist/agent/thinking.d.ts.map +1 -1
  113. package/dist/agent/thinking.js +15 -6
  114. package/dist/agent/thinking.js.map +1 -1
  115. package/dist/agent/thread-list.d.ts +33 -2
  116. package/dist/agent/thread-list.d.ts.map +1 -1
  117. package/dist/agent/thread-list.js +158 -8
  118. package/dist/agent/thread-list.js.map +1 -1
  119. package/dist/agent/tool-activity-model.d.ts +136 -0
  120. package/dist/agent/tool-activity-model.d.ts.map +1 -0
  121. package/dist/agent/tool-activity-model.js +288 -0
  122. package/dist/agent/tool-activity-model.js.map +1 -0
  123. package/dist/agent/tool-activity.d.ts +55 -0
  124. package/dist/agent/tool-activity.d.ts.map +1 -0
  125. package/dist/agent/tool-activity.js +159 -0
  126. package/dist/agent/tool-activity.js.map +1 -0
  127. package/dist/agent/tool-call-card.d.ts +9 -1
  128. package/dist/agent/tool-call-card.d.ts.map +1 -1
  129. package/dist/agent/tool-call-card.js +7 -1
  130. package/dist/agent/tool-call-card.js.map +1 -1
  131. package/dist/agent/ui.js +1 -1
  132. package/dist/agent/ui.js.map +1 -1
  133. package/dist/agent/use-motion.d.ts +15 -0
  134. package/dist/agent/use-motion.d.ts.map +1 -0
  135. package/dist/agent/use-motion.js +52 -0
  136. package/dist/agent/use-motion.js.map +1 -0
  137. package/dist/chat/chat-composer.d.ts.map +1 -1
  138. package/dist/chat/chat-composer.js +1 -1
  139. package/dist/chat/chat-composer.js.map +1 -1
  140. package/dist/chat/use-stick-to-bottom.d.ts +5 -0
  141. package/dist/chat/use-stick-to-bottom.d.ts.map +1 -1
  142. package/dist/chat/use-stick-to-bottom.js +11 -1
  143. package/dist/chat/use-stick-to-bottom.js.map +1 -1
  144. package/dist/components/sheet.d.ts +3 -1
  145. package/dist/components/sheet.d.ts.map +1 -1
  146. package/dist/components/sheet.js +2 -2
  147. package/dist/components/sheet.js.map +1 -1
  148. package/dist/portfolio-import/import-job-panels.d.ts +6 -0
  149. package/dist/portfolio-import/import-job-panels.d.ts.map +1 -1
  150. package/dist/portfolio-import/import-job-panels.js +11 -4
  151. package/dist/portfolio-import/import-job-panels.js.map +1 -1
  152. package/dist/portfolio-import/job-error-copy.d.ts +62 -0
  153. package/dist/portfolio-import/job-error-copy.d.ts.map +1 -0
  154. package/dist/portfolio-import/job-error-copy.js +78 -0
  155. package/dist/portfolio-import/job-error-copy.js.map +1 -0
  156. package/dist/realtime/organisation-events/schemas.d.ts +2 -2
  157. package/package.json +4 -1
  158. package/src/theme/tokens.css +66 -0
@@ -0,0 +1,50 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { fmt, useCopy } from "../copy.js";
3
+ import { MaskedValue } from "../masked-value.js";
4
+ import { detailAgrees } from "./host-contract.js";
5
+ import { AgentCardExtras, subjectOf, AgentCardFrame, AgentCardLink, AgentChip, AgentField, AgentFieldGrid, } from "./card-kit.js";
6
+ const DEFAULT_COPY = {
7
+ producer: "Producer",
8
+ category: "Category",
9
+ vintage: "Vintage",
10
+ abv: "ABV",
11
+ volume: "Volume",
12
+ packaging: "Packaging",
13
+ variants: "Versions",
14
+ matches: "Matches",
15
+ organic: "Organic",
16
+ fairtrade: "Fairtrade",
17
+ sustainable: "Sustainable",
18
+ pendingReview: "Pending review",
19
+ approved: "Approved",
20
+ readiness: "{percent}% ready to match",
21
+ readyToApprove: "Ready to approve",
22
+ blockers: "{n} required",
23
+ recommendations: "{n} recommended",
24
+ acknowledgements: "{n} to confirm",
25
+ };
26
+ /**
27
+ * @internal Read card for one product (CEL-2445). Pairs with `AgentReadinessChecklist`: this card only summarises the
28
+ * readiness counts; the checklist is where gaps are fixed.
29
+ */
30
+ export function AgentProductCard({ data, copy, ...host }) {
31
+ const { allowLink, renderLink, maskedCopy } = host;
32
+ const c = useCopy(DEFAULT_COPY, copy);
33
+ // A `detail` that names neither a product nor a variant is a steered or broken card: refuse it, do not render it.
34
+ if (!detailAgrees("ProductCard", data))
35
+ return null;
36
+ const category = [data.category, data.subtype].filter(Boolean).join(" / ") || undefined;
37
+ const r = data.readiness;
38
+ const gaps = r
39
+ ? [
40
+ r.blockers ? fmt(c.blockers, { n: r.blockers }) : null,
41
+ r.acknowledgements ? fmt(c.acknowledgements, { n: r.acknowledgements }) : null,
42
+ r.recommendations ? fmt(c.recommendations, { n: r.recommendations }) : null,
43
+ ].filter(Boolean)
44
+ : [];
45
+ const certs = (data.certifications ?? []).map((k) => c[k]);
46
+ return (_jsxs(AgentCardFrame, { title: _jsx(AgentCardLink, { path: data.link, allowLink: allowLink, renderLink: renderLink, children: _jsx(MaskedValue, { value: data.name, copy: maskedCopy }) }), badge: data.validation ? (_jsx(AgentChip, { tone: data.validation === "approved" ? "success" : "warning", children: data.validation === "approved" ? c.approved : c.pendingReview })) : undefined, children: [_jsxs(AgentFieldGrid, { children: [_jsx(AgentField, { label: c.producer, value: data.producer, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.category, value: category, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.vintage, value: data.vintage ?? undefined, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.abv, value: data.abv, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.volume, value: data.volume, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.packaging, value: data.packaging, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.variants, value: data.variantCount, maskedCopy: maskedCopy }), _jsx(AgentField, { label: c.matches, value: data.matchCount, maskedCopy: maskedCopy })] }), certs.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2", children: certs.map((label) => (_jsx(AgentChip, { tone: "success", children: label }, label))) })), r && (_jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("div", { className: "flex flex-wrap items-baseline justify-between gap-x-3 gap-y-0.5 text-xs/4", children: [_jsx("span", { className: "font-medium", children: r.canApprove
47
+ ? c.readyToApprove
48
+ : fmt(c.readiness, { percent: Math.round(r.percent) }) }), gaps.length > 0 && _jsx("span", { className: "text-muted-foreground", children: gaps.join(" / ") })] }), _jsx("div", { role: "progressbar", "aria-valuemin": 0, "aria-valuemax": 100, "aria-valuenow": Math.round(r.percent), "aria-label": fmt(c.readiness, { percent: Math.round(r.percent) }), className: "h-1.5 overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-primary", style: { width: `${Math.min(Math.max(r.percent, 0), 100)}%` } }) })] })), _jsx(AgentCardExtras, { data: data, subject: subjectOf(data.detail), host: host })] }));
49
+ }
50
+ //# sourceMappingURL=product-card.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"product-card.js","sourceRoot":"","sources":["../../../src/agent/role-cards/product-card.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { CardDetail, CardProposal } from "@cellarnode/agent-cards/zod4";
2
+ import { type AgentToolCatalog, type ApplyProposalFailure, type DetailKind, type ProposalApplyPlan } from "./host-contract.js";
3
+ export interface AgentProposalDiffCopy {
4
+ title: string;
5
+ field: string;
6
+ /** The model's claimed current value. The server's value is only shown after Apply fetched it. */
7
+ before: string;
8
+ after: string;
9
+ empty: string;
10
+ apply: string;
11
+ applying: string;
12
+ edit: string;
13
+ reject: string;
14
+ tierNote: string;
15
+ refused: Record<ApplyProposalFailure, string>;
16
+ }
17
+ export declare const DEFAULT_COPY: AgentProposalDiffCopy;
18
+ export interface AgentProposalDiffProps {
19
+ proposal: CardProposal;
20
+ /** Apply is offered only with a catalog, a record fetch AND the subject of the card (`expected`). Otherwise the diff is read-only. */
21
+ catalog?: AgentToolCatalog;
22
+ fetchRecord?: (kind: DetailKind, id: string) => Promise<unknown>;
23
+ expected?: Pick<CardDetail, "kind" | "id">;
24
+ /** Called ONLY with the `planProposalApply` result (server truth against `after`, a catalog-built confirm plan); never with the raw proposal. */
25
+ onApply?: (result: ProposalApplyPlan) => void;
26
+ /** Called when Apply was refused (stale record, other subject, bad args...). The reason is also shown inline. */
27
+ onApplyRefused?: (reason: ApplyProposalFailure) => void;
28
+ onEdit?: (proposal: CardProposal) => void;
29
+ onReject?: (proposal: CardProposal) => void;
30
+ copy?: Partial<AgentProposalDiffCopy>;
31
+ }
32
+ /**
33
+ * @internal An agent-proposed edit as before/after rows with Apply, Edit before applying and Reject. Text only: values are never
34
+ * interpreted as markup. The "before" column is what the MODEL claims; Apply re-fetches the record and refuses a proposal the
35
+ * server no longer agrees with.
36
+ */
37
+ export declare function AgentProposalDiff({ proposal, catalog, fetchRecord, expected, onApply, onApplyRefused, onEdit, onReject, copy, }: AgentProposalDiffProps): import("react/jsx-runtime").JSX.Element;
38
+ //# sourceMappingURL=proposal-diff.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-diff.d.ts","sourceRoot":"","sources":["../../../src/agent/role-cards/proposal-diff.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAG7E,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,oBAAoB,EACzB,KAAK,UAAU,EACf,KAAK,iBAAiB,EACvB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;CAC/C;AACD,eAAO,MAAM,YAAY,EAAE,qBAyB1B,CAAC;AAEF,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,YAAY,CAAC;IACvB,sIAAsI;IACtI,OAAO,CAAC,EAAE,gBAAgB,CAAC;IAC3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACjE,QAAQ,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,iJAAiJ;IACjJ,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC9C,iHAAiH;IACjH,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,oBAAoB,KAAK,IAAI,CAAC;IACxD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,IAAI,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACvC;AAKD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,QAAQ,EACR,OAAO,EACP,WAAW,EACX,QAAQ,EACR,OAAO,EACP,cAAc,EACd,MAAM,EACN,QAAQ,EACR,IAAI,GACL,EAAE,sBAAsB,2CA+GxB"}
@@ -0,0 +1,74 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from "react";
3
+ import { fmt, useCopy } from "../copy.js";
4
+ import { agentButton } from "../ui.js";
5
+ import { planProposalApply, } from "./host-contract.js";
6
+ export const DEFAULT_COPY = {
7
+ title: "Proposed change",
8
+ field: "Field",
9
+ before: "Proposed from",
10
+ after: "Proposed",
11
+ empty: "(empty)",
12
+ apply: "Apply",
13
+ applying: "Checking the current record",
14
+ edit: "Edit before applying",
15
+ reject: "Reject",
16
+ tierNote: "Applying asks you to confirm ({tier}).",
17
+ refused: {
18
+ unknown_tool: "This change cannot be applied from here.",
19
+ tier_mismatch: "This change cannot be applied from here.",
20
+ no_target_arg: "This change cannot be applied from here.",
21
+ no_target_kind: "This change cannot be applied from here.",
22
+ kind_mismatch: "This change is for a different kind of record.",
23
+ subject_mismatch: "This change is for a different record than this card.",
24
+ target_override: "This change cannot be applied from here.",
25
+ record_unavailable: "Could not load the current record. Try again.",
26
+ unknown_path: "This change names a field the record does not have.",
27
+ stale: "The record changed since the agent looked. Ask it to propose again.",
28
+ nothing_to_apply: "The record already has these values.",
29
+ invalid_args: "These values are not accepted. Edit them and try again.",
30
+ },
31
+ };
32
+ const show = (v, empty) => v === null || v === "" ? empty : String(v);
33
+ /**
34
+ * @internal An agent-proposed edit as before/after rows with Apply, Edit before applying and Reject. Text only: values are never
35
+ * interpreted as markup. The "before" column is what the MODEL claims; Apply re-fetches the record and refuses a proposal the
36
+ * server no longer agrees with.
37
+ */
38
+ export function AgentProposalDiff({ proposal, catalog, fetchRecord, expected, onApply, onApplyRefused, onEdit, onReject, copy, }) {
39
+ const c = useCopy(DEFAULT_COPY, {
40
+ ...copy,
41
+ refused: { ...DEFAULT_COPY.refused, ...copy?.refused },
42
+ });
43
+ const [busy, setBusy] = useState(false);
44
+ const [refusal, setRefusal] = useState(null);
45
+ const mountedRef = useRef(true);
46
+ useEffect(() => {
47
+ mountedRef.current = true;
48
+ return () => {
49
+ mountedRef.current = false;
50
+ };
51
+ }, []);
52
+ const canApply = !!(onApply && catalog && fetchRecord && expected);
53
+ const interactive = canApply || onEdit || onReject;
54
+ async function apply() {
55
+ if (!catalog || !fetchRecord || !expected || !onApply || busy)
56
+ return;
57
+ setBusy(true);
58
+ setRefusal(null);
59
+ const result = await planProposalApply(proposal, catalog, fetchRecord, expected);
60
+ if (!mountedRef.current)
61
+ return;
62
+ setBusy(false);
63
+ if (result.ok)
64
+ onApply(result);
65
+ else {
66
+ setRefusal(result.reason);
67
+ onApplyRefused?.(result.reason);
68
+ }
69
+ }
70
+ return (_jsxs("div", { className: "flex flex-col gap-2 rounded-xl bg-muted/50 p-3", "aria-busy": busy, children: [_jsx("p", { className: "text-xs/4 font-medium text-muted-foreground", children: c.title }), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full min-w-64 text-left text-sm/5", children: [_jsx("thead", { className: "text-xs/4 text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { scope: "col", className: "py-1 pr-3 font-medium", children: c.field }), _jsx("th", { scope: "col", className: "py-1 pr-3 font-medium", children: c.before }), _jsx("th", { scope: "col", className: "py-1 font-medium", children: c.after })] }) }), _jsx("tbody", { children: proposal.changes.map((ch) => (_jsxs("tr", { className: "border-t border-border/60 align-top", children: [_jsx("th", { scope: "row", className: "py-1.5 pr-3 font-mono text-xs/5 font-normal break-all", children: ch.path }), _jsx("td", { className: ch.before === null || ch.before === ""
71
+ ? "py-1.5 pr-3 text-muted-foreground"
72
+ : "py-1.5 pr-3 text-muted-foreground line-through decoration-muted-foreground/60", children: show(ch.before, c.empty) }), _jsx("td", { className: "py-1.5 font-medium", children: show(ch.after, c.empty) })] }, ch.path))) })] }) }), proposal.tier !== "reversible" && (_jsx("p", { className: "text-xs/4 text-muted-foreground", children: fmt(c.tierNote, { tier: proposal.tier }) })), refusal && (_jsx("p", { role: "alert", className: "text-xs/4 font-medium text-[var(--tone-danger-fg)]", children: c.refused[refusal] })), busy && (_jsx("p", { role: "status", className: "text-xs/4 text-muted-foreground", children: c.applying })), interactive && (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [canApply && (_jsx("button", { type: "button", disabled: busy, className: proposal.tier === "reversible" ? agentButton.primary : agentButton.danger, onClick: apply, children: c.apply })), onEdit && (_jsx("button", { type: "button", className: agentButton.quiet, onClick: () => onEdit(proposal), children: c.edit })), onReject && (_jsx("button", { type: "button", className: agentButton.ghost, onClick: () => onReject(proposal), children: c.reject }))] }))] }));
73
+ }
74
+ //# sourceMappingURL=proposal-diff.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"proposal-diff.js","sourceRoot":"","sources":["../../../src/agent/role-cards/proposal-diff.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import { type ReactNode } from "react";
2
+ import { type AgentDataTableCardCopy, type AgentDataTableCardProps } from "./data-table-card.js";
3
+ import { type AgentMatchCardCopy } from "./match-card.js";
4
+ import { type AgentOfferCardCopy } from "./offer-card.js";
5
+ import { type AgentOpportunityCardCopy } from "./opportunity-card.js";
6
+ import { type AgentProductCardCopy } from "./product-card.js";
7
+ import type { AgentRoleCardHostProps } from "./card-kit.js";
8
+ import { ROLE_AGENT_CARD_TYPES, type RoleAgentCardType } from "./host-contract.js";
9
+ export { ROLE_AGENT_CARD_TYPES, type RoleAgentCardType };
10
+ /** The host's own words for every string of each card, by card. Anything left out keeps the English default. */
11
+ export interface RoleAgentCardCopy {
12
+ offer?: Partial<AgentOfferCardCopy>;
13
+ product?: Partial<AgentProductCardCopy>;
14
+ opportunity?: Partial<AgentOpportunityCardCopy>;
15
+ match?: Partial<AgentMatchCardCopy>;
16
+ dataTable?: Partial<AgentDataTableCardCopy>;
17
+ }
18
+ /**
19
+ * The host's link rules, tool catalog, record fetch and callbacks. Without a catalog every tool action and every proposal is dropped; with one, an unknown tool or a tier that differs from the catalog's is dropped too.
20
+ * `allowLink` decides every link a card carries, a table's included (`createSurfaceAllowLink` builds the one for a role host).
21
+ * `maskedCopy` (from the host props) is the mask pill's strings on every card.
22
+ */
23
+ export interface RenderRoleAgentCardOptions extends AgentRoleCardHostProps {
24
+ /** The card's strings in the host's language, per card type. */
25
+ copy?: RoleAgentCardCopy;
26
+ /** `DataTable` only: more column keys whose text someone else wrote, quoted like third-party text. */
27
+ thirdPartyColumns?: AgentDataTableCardProps["thirdPartyColumns"];
28
+ /** `DataTable` only: the host's own label for a column, by key. */
29
+ columnLabels?: AgentDataTableCardProps["columnLabels"];
30
+ /** `DataTable` only: the host's display text for a cell (a date, a currency), or `undefined` for the default. */
31
+ formatCell?: AgentDataTableCardProps["formatCell"];
32
+ /** `DataTable` only: a BCP 47 tag for the numbers in cells. */
33
+ locale?: AgentDataTableCardProps["locale"];
34
+ }
35
+ /**
36
+ * @internal `cardType` (chosen by the agent) → renderer. The agent selects a card and fills it; it never authors layout.
37
+ * Data is read through `readRoleCard` first: an unknown type, data that fails the `@cellarnode/agent-cards` schema (bad link,
38
+ * out-of-range score, unknown status) or a card whose `detail` disagrees with it renders NOTHING. A card is an enhancement; the
39
+ * text answer stands alone. The data a card draws is always what `readRoleCard` made safe: it is set last, so nothing in
40
+ * `options` can replace it.
41
+ */
42
+ export declare function renderRoleAgentCard(cardType: string, data: unknown, options?: RenderRoleAgentCardOptions): ReactNode;
43
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/agent/role-cards/registry.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,EAEL,KAAK,sBAAsB,EAC3B,KAAK,uBAAuB,EAC7B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAkB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AACvE,OAAO,EAAwB,KAAK,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAoB,KAAK,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAC7E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACzD,OAAO,EAAgB,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAE9F,OAAO,EAAE,qBAAqB,EAAE,KAAK,iBAAiB,EAAE,CAAC;AAEzD,gHAAgH;AAChH,MAAM,WAAW,iBAAiB;IAChC,KAAK,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,CAAC;IACxC,WAAW,CAAC,EAAE,OAAO,CAAC,wBAAwB,CAAC,CAAC;IAChD,KAAK,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,CAAC;IACpC,SAAS,CAAC,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAC;CAC7C;AAED;;;;GAIG;AACH,MAAM,WAAW,0BAA2B,SAAQ,sBAAsB;IACxE,gEAAgE;IAChE,IAAI,CAAC,EAAE,iBAAiB,CAAC;IACzB,sGAAsG;IACtG,iBAAiB,CAAC,EAAE,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;IACjE,mEAAmE;IACnE,YAAY,CAAC,EAAE,uBAAuB,CAAC,cAAc,CAAC,CAAC;IACvD,iHAAiH;IACjH,UAAU,CAAC,EAAE,uBAAuB,CAAC,YAAY,CAAC,CAAC;IACnD,+DAA+D;IAC/D,MAAM,CAAC,EAAE,uBAAuB,CAAC,QAAQ,CAAC,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,OAAO,EACb,OAAO,GAAE,0BAA+B,GACvC,SAAS,CA4BX"}
@@ -0,0 +1,46 @@
1
+ import { createElement } from "react";
2
+ import { AgentDataTableCard, } from "./data-table-card.js";
3
+ import { AgentMatchCard } from "./match-card.js";
4
+ import { AgentOfferCard } from "./offer-card.js";
5
+ import { AgentOpportunityCard } from "./opportunity-card.js";
6
+ import { AgentProductCard } from "./product-card.js";
7
+ import { readRoleCard, ROLE_AGENT_CARD_TYPES } from "./host-contract.js";
8
+ export { ROLE_AGENT_CARD_TYPES };
9
+ /**
10
+ * @internal `cardType` (chosen by the agent) → renderer. The agent selects a card and fills it; it never authors layout.
11
+ * Data is read through `readRoleCard` first: an unknown type, data that fails the `@cellarnode/agent-cards` schema (bad link,
12
+ * out-of-range score, unknown status) or a card whose `detail` disagrees with it renders NOTHING. A card is an enhancement; the
13
+ * text answer stands alone. The data a card draws is always what `readRoleCard` made safe: it is set last, so nothing in
14
+ * `options` can replace it.
15
+ */
16
+ export function renderRoleAgentCard(cardType, data, options = {}) {
17
+ const card = readRoleCard(cardType, data, options.catalog);
18
+ if (!card)
19
+ return null;
20
+ const { copy, thirdPartyColumns, columnLabels, formatCell, locale, ...host } = options;
21
+ switch (card.cardType) {
22
+ case "OfferCard":
23
+ return createElement(AgentOfferCard, { ...host, copy: copy?.offer, data: card.data });
24
+ case "ProductCard":
25
+ return createElement(AgentProductCard, { ...host, copy: copy?.product, data: card.data });
26
+ case "OpportunityCard":
27
+ return createElement(AgentOpportunityCard, {
28
+ ...host,
29
+ copy: copy?.opportunity,
30
+ data: card.data,
31
+ });
32
+ case "MatchCard":
33
+ return createElement(AgentMatchCard, { ...host, copy: copy?.match, data: card.data });
34
+ case "DataTable":
35
+ return createElement(AgentDataTableCard, {
36
+ ...host,
37
+ copy: copy?.dataTable,
38
+ thirdPartyColumns,
39
+ columnLabels,
40
+ formatCell,
41
+ locale,
42
+ data: card.data,
43
+ });
44
+ }
45
+ }
46
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/agent/role-cards/registry.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,OAAO,CAAC;AACtD,OAAO,EACL,kBAAkB,GAGnB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAA2B,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,cAAc,EAA2B,MAAM,cAAc,CAAC;AACvE,OAAO,EAAE,oBAAoB,EAAiC,MAAM,oBAAoB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAA6B,MAAM,gBAAgB,CAAC;AAE7E,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAA0B,MAAM,iBAAiB,CAAC;AAE9F,OAAO,EAAE,qBAAqB,EAA0B,CAAC;AA6BzD;;;;;;GAMG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,IAAa,EACb,UAAsC,EAAE;IAExC,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3D,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,MAAM,EAAE,IAAI,EAAE,iBAAiB,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACvF,QAAQ,IAAI,CAAC,QAAQ,EAAE,CAAC;QACtB,KAAK,WAAW;YACd,OAAO,aAAa,CAAC,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxF,KAAK,aAAa;YAChB,OAAO,aAAa,CAAC,gBAAgB,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5F,KAAK,iBAAiB;YACpB,OAAO,aAAa,CAAC,oBAAoB,EAAE;gBACzC,GAAG,IAAI;gBACP,IAAI,EAAE,IAAI,EAAE,WAAW;gBACvB,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB,CAAC,CAAC;QACL,KAAK,WAAW;YACd,OAAO,aAAa,CAAC,cAAc,EAAE,EAAE,GAAG,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACxF,KAAK,WAAW;YACd,OAAO,aAAa,CAAC,kBAAkB,EAAE;gBACvC,GAAG,IAAI;gBACP,IAAI,EAAE,IAAI,EAAE,SAAS;gBACrB,iBAAiB;gBACjB,YAAY;gBACZ,UAAU;gBACV,MAAM;gBACN,IAAI,EAAE,IAAI,CAAC,IAAI;aAChB,CAAC,CAAC;IACP,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @internal A 0 to 5 fit score as a ring. The number is always shown as text (colour is never the only signal) and the
3
+ * ring has no animation, so there is nothing to reduce for `prefers-reduced-motion`.
4
+ */
5
+ export declare function AgentScoreMeter({ score, max, label, className, }: {
6
+ score: number;
7
+ max?: number;
8
+ /** Accessible name, e.g. "Match score". */
9
+ label: string;
10
+ className?: string;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ //# sourceMappingURL=score-meter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score-meter.d.ts","sourceRoot":"","sources":["../../../src/agent/role-cards/score-meter.tsx"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,GAAO,EACP,KAAK,EACL,SAAS,GACV,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,2CAqCA"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cn } from "../../lib/utils.js";
3
+ /**
4
+ * @internal A 0 to 5 fit score as a ring. The number is always shown as text (colour is never the only signal) and the
5
+ * ring has no animation, so there is nothing to reduce for `prefers-reduced-motion`.
6
+ */
7
+ export function AgentScoreMeter({ score, max = 5, label, className, }) {
8
+ const clamped = Math.min(Math.max(score, 0), max);
9
+ const r = 15.9155; // circumference 100
10
+ const tone = clamped >= 4
11
+ ? "text-[var(--tone-success-fg)]"
12
+ : clamped >= 2.5
13
+ ? "text-[var(--tone-warning-fg)]"
14
+ : "text-[var(--tone-danger-fg)]";
15
+ return (_jsxs("div", { role: "img", "aria-label": `${label}: ${clamped.toFixed(1)} / ${max}`, className: cn("relative inline-flex size-14 shrink-0 items-center justify-center", tone, className), children: [_jsxs("svg", { viewBox: "0 0 36 36", className: "absolute inset-0 size-full -rotate-90", "aria-hidden": true, children: [_jsx("circle", { cx: "18", cy: "18", r: r, fill: "none", strokeWidth: "3", className: "stroke-muted" }), _jsx("circle", { cx: "18", cy: "18", r: r, fill: "none", strokeWidth: "3", strokeLinecap: "round", stroke: "currentColor", strokeDasharray: `${(clamped / max) * 100} 100` })] }), _jsx("span", { "aria-hidden": true, className: "text-sm/5 font-semibold tabular-nums text-foreground", children: clamped.toFixed(1) })] }));
16
+ }
17
+ //# sourceMappingURL=score-meter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"score-meter.js","sourceRoot":"","sources":["../../../src/agent/role-cards/score-meter.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAErC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,EAC9B,KAAK,EACL,GAAG,GAAG,CAAC,EACP,KAAK,EACL,SAAS,GAOV;IACC,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAClD,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,oBAAoB;IACvC,MAAM,IAAI,GACR,OAAO,IAAI,CAAC;QACV,CAAC,CAAC,+BAA+B;QACjC,CAAC,CAAC,OAAO,IAAI,GAAG;YACd,CAAC,CAAC,+BAA+B;YACjC,CAAC,CAAC,8BAA8B,CAAC;IACvC,OAAO,CACL,eACE,IAAI,EAAC,KAAK,gBACE,GAAG,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,EACtD,SAAS,EAAE,EAAE,CACX,mEAAmE,EACnE,IAAI,EACJ,SAAS,CACV,aAED,eAAK,OAAO,EAAC,WAAW,EAAC,SAAS,EAAC,uCAAuC,kCACxE,iBAAQ,EAAE,EAAC,IAAI,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAC,MAAM,EAAC,WAAW,EAAC,GAAG,EAAC,SAAS,EAAC,cAAc,GAAG,EACrF,iBACE,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,CAAC,EACJ,IAAI,EAAC,MAAM,EACX,WAAW,EAAC,GAAG,EACf,aAAa,EAAC,OAAO,EACrB,MAAM,EAAC,cAAc,EACrB,eAAe,EAAE,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC,GAAG,GAAG,MAAM,GAC/C,IACE,EACN,oCAAkB,SAAS,EAAC,sDAAsD,YAC/E,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,GACd,IACH,CACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * @internal The link rule of each role host (CEL-2488): which INTERNAL paths a card may link to on that app.
3
+ *
4
+ * A card's `link`, a table's `link` and an action's `href` are paths the agent chose. The schema only proves they are internal
5
+ * (one leading slash, no scheme); whether a path is a route of THIS app is the host's call, made through `allowLink`
6
+ * (`AgentCardLinkProps`). A path means nothing without its app: `/portfolio/...` is a producer route, whereas the e-label app keeps
7
+ * its producer area under `/app/*`, so a card that links across apps must render as plain text, not as a dead or wrong link.
8
+ * The routes listed here are the ones the cellarnode-mcp link tools put on a card (`get_offer_file_link`, `get_org_document_link`,
9
+ * `get_attachment_link`, `list_producer_documents`, `get_producer_showcase`: `agents/src/role-result-cards.ts`), per surface.
10
+ * `src/core/app-links.ts` in that repo knows more routes (`/messenger`, `/imports/<id>`, `/labels/<id>`, `/lab-reports`) that no
11
+ * card carries yet. A host passes the result as its `allowLink`, and `extraPrefixes` adds the routes it owns beyond these
12
+ * (`/opportunities`, `/matches`, `/messenger`).
13
+ *
14
+ * Every path is checked the same way BEFORE it is matched against a route, and fails closed:
15
+ * - it satisfies the card contract's own link rule (`LINK_PATTERN`, at most `LINK_MAX_LENGTH`);
16
+ * - it has no query (`?`): no agent link carries one, and a query is where an open redirect (`?next=...`) hides;
17
+ * - it has no empty segment (`//`, a trailing slash) and no `.` or `..` segment, raw or percent-encoded, which a browser would
18
+ * resolve out of the route that was matched (`/offers/../admin`);
19
+ * - no segment decodes to anything but printable ASCII (so no control character, no space, no bidi or zero-width character that
20
+ * arrived as `%E2%80%AE`), nothing holding `/`, `\`, `#` or `?`, and no segment is still encoded after one round of decoding
21
+ * (`%252e%252e`).
22
+ */
23
+ /** The three apps that draw role-agent cards. */
24
+ export type AgentHostSurface = "producer" | "importer" | "elabel";
25
+ /**
26
+ * `allowLink` for a host surface: true only for a clean internal path that is one of the routes the agents emit for that app, or
27
+ * sits at or below one of `extraPrefixes` (the host's own routes, e.g. `["/opportunities", "/matches"]`). A prefix matches on a
28
+ * whole segment: `/app` accepts `/app/portfolio` and not `/application`.
29
+ *
30
+ * Throws on an extra prefix that is not a clean path with at least one segment: that is a host bug, and a prefix like `/` would
31
+ * quietly allow every link.
32
+ */
33
+ export declare function createSurfaceAllowLink(surface: AgentHostSurface, extraPrefixes?: readonly string[]): (path: string) => boolean;
34
+ /**
35
+ * What a card's deep link points at: the name of the link, in the host's language, comes from this. `product` and `productGallery`
36
+ * are one product (version) of a portfolio and its gallery; `labels` and `imports` are e-label pages; `elabelHome` is the e-label
37
+ * app's own start page and `elabel` any other page of it.
38
+ */
39
+ export type AgentLinkKind = "offer" | "producer" | "organisation" | "portfolio" | "product" | "productGallery" | "labels" | "imports" | "elabelHome" | "elabel";
40
+ /**
41
+ * The kind of page a clean internal path opens, or `undefined` for a path that is not clean or not one of the routes the agents
42
+ * emit (a route the host added through `extraPrefixes`). Reads only the path, so it names a link the same way on every surface.
43
+ * Under `/app` (the e-label app) the page is named by the segment after it: `/app/portfolio/...` is a portfolio page, `/app/labels/...`
44
+ * a label, `/app/imports/...` an import, `/app` itself the app's home, and anything else just "a page of the e-label app".
45
+ */
46
+ export declare function agentLinkKind(path: string): AgentLinkKind | undefined;
47
+ /**
48
+ * Per surface, the `DataTable` column keys whose text someone else wrote, as the cellarnode-mcp agents name them: the key says who
49
+ * wrote the column. `counterpartyFile` is the other side's offer file, `producerFile` and `producerBeverage` are a producer's public
50
+ * documents and beverages as an importer sees them; `file` is the caller's own document or attachment and is not listed. Pass the
51
+ * result as `thirdPartyColumns` (`DEFAULT_THIRD_PARTY_COLUMNS` already quotes these keys on every surface). An unknown surface gets none.
52
+ */
53
+ export declare function surfaceThirdPartyColumns(surface: AgentHostSurface): readonly string[];
54
+ //# sourceMappingURL=surface-links.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-links.d.ts","sourceRoot":"","sources":["../../../src/agent/role-cards/surface-links.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,iDAAiD;AACjD,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,CAAC;AA0ElE;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,gBAAgB,EACzB,aAAa,GAAE,SAAS,MAAM,EAAO,GACpC,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAY3B;AAED;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,OAAO,GACP,UAAU,GACV,cAAc,GACd,WAAW,GACX,SAAS,GACT,gBAAgB,GAChB,QAAQ,GACR,SAAS,GACT,YAAY,GACZ,QAAQ,CAAC;AAQb;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CA8BrE;AAQD;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,MAAM,EAAE,CAIrF"}
@@ -0,0 +1,149 @@
1
+ import { LINK_MAX_LENGTH, LINK_PATTERN } from "@cellarnode/agent-cards/zod4";
2
+ /**
3
+ * Per surface, the routes the agents emit.
4
+ * - producer: an offer and what hangs off it, the organisation profile (where a registration or compliance document opens), the
5
+ * portfolio list and a product's pages;
6
+ * - importer: a producer's page, an offer, and the organisation profile (where the importer's own registration or compliance
7
+ * document opens: `get_org_document_link` emits it for an importer too);
8
+ * - e-label: everything under `/app` (its producer area), the app's own root included.
9
+ */
10
+ const SURFACE_RULES = {
11
+ producer: [
12
+ { prefix: "/offers", below: true },
13
+ { prefix: "/organisation/profile", self: true },
14
+ { prefix: "/portfolio", self: true, below: true },
15
+ ],
16
+ importer: [
17
+ { prefix: "/producers", below: true },
18
+ { prefix: "/offers", below: true },
19
+ { prefix: "/organisation/profile", self: true },
20
+ ],
21
+ elabel: [{ prefix: "/app", self: true, below: true }],
22
+ };
23
+ /** Printable ASCII only (U+0021 to U+007E): no control character, no space, nothing beyond ASCII. */
24
+ function isPrintableAscii(text) {
25
+ for (let i = 0; i < text.length; i++) {
26
+ const code = text.charCodeAt(i);
27
+ if (code < 0x21 || code > 0x7e)
28
+ return false;
29
+ }
30
+ return true;
31
+ }
32
+ /** One path segment: not a dot segment, and nothing an encoding could use to climb out or to smuggle a separator. */
33
+ function safeSegment(segment) {
34
+ if (segment === "")
35
+ return false;
36
+ let decoded;
37
+ try {
38
+ decoded = decodeURIComponent(segment);
39
+ }
40
+ catch {
41
+ return false; // a malformed escape
42
+ }
43
+ // A dot segment, raw or percent-encoded (`%2e%2e` decodes to `..`).
44
+ if (decoded === "." || decoded === "..")
45
+ return false;
46
+ if (/[/\\#?]/.test(decoded) || !isPrintableAscii(decoded))
47
+ return false;
48
+ // Still encoded after one round: a double encoding is never a plain id.
49
+ return !decoded.includes("%");
50
+ }
51
+ /** The segments of a clean internal path, or `null` when the path is not one (see the rules at the top of the file). */
52
+ function cleanSegments(path) {
53
+ if (typeof path !== "string" || path.length > LINK_MAX_LENGTH)
54
+ return null;
55
+ if (!LINK_PATTERN.test(path) || path.includes("?"))
56
+ return null;
57
+ const segments = path.slice(1).split("/");
58
+ return segments.every(safeSegment) ? segments : null;
59
+ }
60
+ const splitPrefix = (prefix) => prefix.slice(1).split("/");
61
+ function matches(segments, rule) {
62
+ const base = splitPrefix(rule.prefix);
63
+ if (segments.length < base.length || !base.every((seg, i) => segments[i] === seg))
64
+ return false;
65
+ return segments.length === base.length ? rule.self === true : rule.below === true;
66
+ }
67
+ /**
68
+ * `allowLink` for a host surface: true only for a clean internal path that is one of the routes the agents emit for that app, or
69
+ * sits at or below one of `extraPrefixes` (the host's own routes, e.g. `["/opportunities", "/matches"]`). A prefix matches on a
70
+ * whole segment: `/app` accepts `/app/portfolio` and not `/application`.
71
+ *
72
+ * Throws on an extra prefix that is not a clean path with at least one segment: that is a host bug, and a prefix like `/` would
73
+ * quietly allow every link.
74
+ */
75
+ export function createSurfaceAllowLink(surface, extraPrefixes = []) {
76
+ const own = Object.hasOwn(SURFACE_RULES, surface) ? SURFACE_RULES[surface] : undefined;
77
+ const extra = extraPrefixes.map((prefix) => {
78
+ if (cleanSegments(prefix) === null)
79
+ throw new Error(`Not a clean route prefix: ${prefix}`);
80
+ return { prefix, self: true, below: true };
81
+ });
82
+ // An unknown surface (a cast, a surface added later) has no routes of its own: it links to nothing but what the host adds.
83
+ const rules = [...(own ?? []), ...extra];
84
+ return (path) => {
85
+ const segments = cleanSegments(path);
86
+ return segments !== null && rules.some((rule) => matches(segments, rule));
87
+ };
88
+ }
89
+ /** The portfolio routes (`portfolio`, `portfolio/<id>`, `portfolio/<id>/products/<id>[/gallery]`), the same in the producer and the e-label app. */
90
+ function portfolioKind(segments) {
91
+ if (segments[2] !== "products" || segments.length < 4)
92
+ return "portfolio";
93
+ return segments[4] === "gallery" ? "productGallery" : "product";
94
+ }
95
+ /**
96
+ * The kind of page a clean internal path opens, or `undefined` for a path that is not clean or not one of the routes the agents
97
+ * emit (a route the host added through `extraPrefixes`). Reads only the path, so it names a link the same way on every surface.
98
+ * Under `/app` (the e-label app) the page is named by the segment after it: `/app/portfolio/...` is a portfolio page, `/app/labels/...`
99
+ * a label, `/app/imports/...` an import, `/app` itself the app's home, and anything else just "a page of the e-label app".
100
+ */
101
+ export function agentLinkKind(path) {
102
+ const segments = cleanSegments(path);
103
+ if (segments === null)
104
+ return undefined;
105
+ switch (segments[0]) {
106
+ case "app": {
107
+ const inner = segments.slice(1);
108
+ switch (inner[0]) {
109
+ case undefined:
110
+ return "elabelHome";
111
+ case "portfolio":
112
+ return portfolioKind(inner);
113
+ case "labels":
114
+ return "labels";
115
+ case "imports":
116
+ return "imports";
117
+ default:
118
+ return "elabel";
119
+ }
120
+ }
121
+ case "offers":
122
+ return "offer";
123
+ case "producers":
124
+ return "producer";
125
+ case "portfolio":
126
+ return portfolioKind(segments);
127
+ case "organisation":
128
+ return segments.length === 2 && segments[1] === "profile" ? "organisation" : undefined;
129
+ default:
130
+ return undefined;
131
+ }
132
+ }
133
+ const SURFACE_THIRD_PARTY_COLUMNS = {
134
+ producer: ["counterpartyFile"],
135
+ importer: ["counterpartyFile", "producerFile", "producerBeverage"],
136
+ elabel: [],
137
+ };
138
+ /**
139
+ * Per surface, the `DataTable` column keys whose text someone else wrote, as the cellarnode-mcp agents name them: the key says who
140
+ * wrote the column. `counterpartyFile` is the other side's offer file, `producerFile` and `producerBeverage` are a producer's public
141
+ * documents and beverages as an importer sees them; `file` is the caller's own document or attachment and is not listed. Pass the
142
+ * result as `thirdPartyColumns` (`DEFAULT_THIRD_PARTY_COLUMNS` already quotes these keys on every surface). An unknown surface gets none.
143
+ */
144
+ export function surfaceThirdPartyColumns(surface) {
145
+ return Object.hasOwn(SURFACE_THIRD_PARTY_COLUMNS, surface)
146
+ ? SURFACE_THIRD_PARTY_COLUMNS[surface]
147
+ : [];
148
+ }
149
+ //# sourceMappingURL=surface-links.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"surface-links.js","sourceRoot":"","sources":["../../../src/agent/role-cards/surface-links.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @internal Text from a record or a card is untrusted: it may carry bidi overrides, zero-width characters or control characters
3
+ * that reorder, hide or split what a person reads, and it may be arbitrarily long. These are the one place that cleans and
4
+ * bounds it (CEL-2445 host contract, CEL-2487).
5
+ */
6
+ /**
7
+ * Code points that may reorder, hide or split what a person reads: C0/DEL controls, line/paragraph separators, the Arabic letter
8
+ * mark (U+061C), zero-width and direction marks (U+200B-200F), bidi embeddings and overrides (U+202A-202E), word joiner,
9
+ * invisible operators, bidi isolates and the deprecated format characters (U+2060-206F), interlinear annotation marks
10
+ * (U+FFF9-FFFB), the BOM, and the invisible "tag" characters (U+E0000-E007F) that can carry a hidden message through a copy and paste.
11
+ */
12
+ export declare const isUnsafeChar: (code: number) => boolean;
13
+ /** Every unsafe character becomes a space (so nothing is silently joined into a different word). Walks by code point. */
14
+ export declare function replaceUnsafe(raw: string): string;
15
+ /** The first `max` code points of `text`, never splitting a surrogate pair; `ellipsis` marks a cut. Linear in `max`, not in the text. */
16
+ export declare function clipCodePoints(text: string, max: number, ellipsis?: boolean): string;
17
+ /**
18
+ * Short, single-line text (a label, a title): unsafe characters out, whitespace collapsed, clipped to `max` code points.
19
+ * `undefined` when nothing readable is left.
20
+ */
21
+ export declare function cleanInline(raw: unknown, max: number, ellipsis?: boolean): string | undefined;
22
+ /** A value shown as body text: unsafe characters out, clipped to `max` code points with an ellipsis. */
23
+ export declare function cleanValue(raw: string, max: number): string;
24
+ //# sourceMappingURL=text-safety.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text-safety.d.ts","sourceRoot":"","sources":["../../../src/agent/role-cards/text-safety.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,KAAG,OAWN,CAAC;AAEvC,yHAAyH;AACzH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEjD;AAED,yIAAyI;AACzI,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,MAAM,CAWlF;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,UAAQ,GAAG,MAAM,GAAG,SAAS,CAO3F;AAED,wGAAwG;AACxG,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG3D"}