@agent-native/core 0.37.0 → 0.37.2

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 (62) hide show
  1. package/dist/agent/production-agent.d.ts.map +1 -1
  2. package/dist/agent/production-agent.js +72 -10
  3. package/dist/agent/production-agent.js.map +1 -1
  4. package/dist/brand-kit/fig/decode.d.ts +33 -0
  5. package/dist/brand-kit/fig/decode.d.ts.map +1 -0
  6. package/dist/brand-kit/fig/decode.js +358 -0
  7. package/dist/brand-kit/fig/decode.js.map +1 -0
  8. package/dist/brand-kit/fig/extract-design-system.d.ts +44 -0
  9. package/dist/brand-kit/fig/extract-design-system.d.ts.map +1 -0
  10. package/dist/brand-kit/fig/extract-design-system.js +752 -0
  11. package/dist/brand-kit/fig/extract-design-system.js.map +1 -0
  12. package/dist/brand-kit/fig/fig-to-html.d.ts +246 -0
  13. package/dist/brand-kit/fig/fig-to-html.d.ts.map +1 -0
  14. package/dist/brand-kit/fig/fig-to-html.js +1506 -0
  15. package/dist/brand-kit/fig/fig-to-html.js.map +1 -0
  16. package/dist/brand-kit/fig/index.d.ts +30 -0
  17. package/dist/brand-kit/fig/index.d.ts.map +1 -0
  18. package/dist/brand-kit/fig/index.js +43 -0
  19. package/dist/brand-kit/fig/index.js.map +1 -0
  20. package/dist/cli/skills.d.ts.map +1 -1
  21. package/dist/cli/skills.js +303 -69
  22. package/dist/cli/skills.js.map +1 -1
  23. package/dist/client/AssistantChat.d.ts.map +1 -1
  24. package/dist/client/AssistantChat.js +6 -104
  25. package/dist/client/AssistantChat.js.map +1 -1
  26. package/dist/client/composer/TiptapComposer.js +1 -1
  27. package/dist/client/composer/TiptapComposer.js.map +1 -1
  28. package/dist/client/composer/extensions/SkillReference.js +1 -1
  29. package/dist/client/composer/extensions/SkillReference.js.map +1 -1
  30. package/dist/client/context-xray/ContextMeter.js +1 -1
  31. package/dist/client/context-xray/ContextMeter.js.map +1 -1
  32. package/dist/client/context-xray/ContextSegmentRow.d.ts.map +1 -1
  33. package/dist/client/context-xray/ContextSegmentRow.js +4 -4
  34. package/dist/client/context-xray/ContextSegmentRow.js.map +1 -1
  35. package/dist/client/context-xray/ContextTreemap.d.ts.map +1 -1
  36. package/dist/client/context-xray/ContextTreemap.js +2 -2
  37. package/dist/client/context-xray/ContextTreemap.js.map +1 -1
  38. package/dist/client/context-xray/ContextXRayPanel.d.ts.map +1 -1
  39. package/dist/client/context-xray/ContextXRayPanel.js +19 -18
  40. package/dist/client/context-xray/ContextXRayPanel.js.map +1 -1
  41. package/dist/client/resources/ResourcesPanel.js +2 -2
  42. package/dist/client/resources/ResourcesPanel.js.map +1 -1
  43. package/dist/client/sharing/ShareButton.d.ts +4 -0
  44. package/dist/client/sharing/ShareButton.d.ts.map +1 -1
  45. package/dist/client/sharing/ShareButton.js +6 -4
  46. package/dist/client/sharing/ShareButton.js.map +1 -1
  47. package/dist/resources/store.js +4 -4
  48. package/dist/resources/store.js.map +1 -1
  49. package/dist/server/agent-chat-plugin.d.ts.map +1 -1
  50. package/dist/server/agent-chat-plugin.js +92 -56
  51. package/dist/server/agent-chat-plugin.js.map +1 -1
  52. package/dist/server/agents-bundle.d.ts +6 -4
  53. package/dist/server/agents-bundle.d.ts.map +1 -1
  54. package/dist/server/agents-bundle.js +20 -12
  55. package/dist/server/agents-bundle.js.map +1 -1
  56. package/dist/templates/default/AGENTS.md +10 -8
  57. package/dist/vite/agents-bundle-plugin.d.ts.map +1 -1
  58. package/dist/vite/agents-bundle-plugin.js +16 -6
  59. package/dist/vite/agents-bundle-plugin.js.map +1 -1
  60. package/docs/content/workspace.md +3 -3
  61. package/package.json +6 -1
  62. package/src/templates/default/AGENTS.md +10 -8
@@ -4,7 +4,7 @@ import { NodeViewWrapper, ReactNodeViewRenderer } from "@tiptap/react";
4
4
  import { IconStack2 } from "@tabler/icons-react";
5
5
  const SkillReferenceComponent = ({ node }) => {
6
6
  const displayName = (node.attrs.name || node.attrs.path || "")
7
- .replace(/^(\.agents\/)?skills\//, "")
7
+ .replace(/^(\.agents?\/)?skills\//, "")
8
8
  .replace(/\/SKILL\.md$/i, "")
9
9
  .replace(/\.md$/i, "")
10
10
  .split("/")
@@ -1 +1 @@
1
- {"version":3,"file":"SkillReference.js","sourceRoot":"","sources":["../../../../src/client/composer/extensions/SkillReference.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,uBAAuB,GAAG,CAAC,EAAE,IAAI,EAAiB,EAAE,EAAE;IAC1D,MAAM,WAAW,GACf,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;SACvC,OAAO,CAAC,wBAAwB,EAAE,EAAE,CAAC;SACrC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,EAAE,IAAI,OAAO,CAAC;IAEtB,OAAO,CACL,KAAC,eAAe,IAAC,EAAE,EAAC,MAAM,EAAC,SAAS,EAAC,QAAQ,YAC3C,gBACE,SAAS,EAAC,2KAA2K,EACrL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,aAEtB,KAAC,UAAU,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,gCAAgC,GAAG,EACnE,eAAM,SAAS,EAAC,UAAU,YAAE,WAAW,GAAQ,IAC1C,GACS,CACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,IAAI;IAChB,IAAI,EAAE,IAAI;IAEV,aAAa;QACX,OAAO;YACL,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACvB,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACvB,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,SAAS;QACP,OAAO,CAAC,EAAE,GAAG,EAAE,mCAAmC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,UAAU,CAAC,EAAE,cAAc,EAAE;QAC3B,OAAO;YACL,MAAM;YACN,eAAe,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,EAAE,cAAc,CAAC;SACpE,CAAC;IACJ,CAAC;IAED,WAAW;QACT,OAAO,qBAAqB,CAAC,uBAAuB,CAAC,CAAC;IACxD,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewWrapper, ReactNodeViewRenderer } from \"@tiptap/react\";\nimport { IconStack2 } from \"@tabler/icons-react\";\n\nconst SkillReferenceComponent = ({ node }: { node: any }) => {\n const displayName =\n (node.attrs.name || node.attrs.path || \"\")\n .replace(/^(\\.agents\\/)?skills\\//, \"\")\n .replace(/\\/SKILL\\.md$/i, \"\")\n .replace(/\\.md$/i, \"\")\n .split(\"/\")\n .pop() || \"skill\";\n\n return (\n <NodeViewWrapper as=\"span\" className=\"inline\">\n <span\n className=\"inline-flex items-center gap-1 rounded-md border border-input bg-muted/50 px-1.5 py-0.5 text-xs font-medium text-foreground align-middle mx-0.5 max-w-[160px] select-none\"\n title={node.attrs.path}\n >\n <IconStack2 size={14} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{displayName}</span>\n </span>\n </NodeViewWrapper>\n );\n};\n\nexport const SkillReference = Node.create({\n name: \"skillReference\",\n group: \"inline\",\n inline: true,\n selectable: true,\n atom: true,\n\n addAttributes() {\n return {\n name: { default: null },\n path: { default: null },\n source: { default: \"codebase\" },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-type=\"skill-reference\"]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n \"span\",\n mergeAttributes({ \"data-type\": \"skill-reference\" }, HTMLAttributes),\n ];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(SkillReferenceComponent);\n },\n});\n"]}
1
+ {"version":3,"file":"SkillReference.js","sourceRoot":"","sources":["../../../../src/client/composer/extensions/SkillReference.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACvE,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjD,MAAM,uBAAuB,GAAG,CAAC,EAAE,IAAI,EAAiB,EAAE,EAAE;IAC1D,MAAM,WAAW,GACf,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,IAAI,EAAE,CAAC;SACvC,OAAO,CAAC,yBAAyB,EAAE,EAAE,CAAC;SACtC,OAAO,CAAC,eAAe,EAAE,EAAE,CAAC;SAC5B,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,EAAE,IAAI,OAAO,CAAC;IAEtB,OAAO,CACL,KAAC,eAAe,IAAC,EAAE,EAAC,MAAM,EAAC,SAAS,EAAC,QAAQ,YAC3C,gBACE,SAAS,EAAC,2KAA2K,EACrL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,aAEtB,KAAC,UAAU,IAAC,IAAI,EAAE,EAAE,EAAE,SAAS,EAAC,gCAAgC,GAAG,EACnE,eAAM,SAAS,EAAC,UAAU,YAAE,WAAW,GAAQ,IAC1C,GACS,CACnB,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC,MAAM,CAAC;IACxC,IAAI,EAAE,gBAAgB;IACtB,KAAK,EAAE,QAAQ;IACf,MAAM,EAAE,IAAI;IACZ,UAAU,EAAE,IAAI;IAChB,IAAI,EAAE,IAAI;IAEV,aAAa;QACX,OAAO;YACL,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACvB,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE;YACvB,MAAM,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE;SAChC,CAAC;IACJ,CAAC;IAED,SAAS;QACP,OAAO,CAAC,EAAE,GAAG,EAAE,mCAAmC,EAAE,CAAC,CAAC;IACxD,CAAC;IAED,UAAU,CAAC,EAAE,cAAc,EAAE;QAC3B,OAAO;YACL,MAAM;YACN,eAAe,CAAC,EAAE,WAAW,EAAE,iBAAiB,EAAE,EAAE,cAAc,CAAC;SACpE,CAAC;IACJ,CAAC;IAED,WAAW;QACT,OAAO,qBAAqB,CAAC,uBAAuB,CAAC,CAAC;IACxD,CAAC;CACF,CAAC,CAAC","sourcesContent":["import { mergeAttributes, Node } from \"@tiptap/core\";\nimport { NodeViewWrapper, ReactNodeViewRenderer } from \"@tiptap/react\";\nimport { IconStack2 } from \"@tabler/icons-react\";\n\nconst SkillReferenceComponent = ({ node }: { node: any }) => {\n const displayName =\n (node.attrs.name || node.attrs.path || \"\")\n .replace(/^(\\.agents?\\/)?skills\\//, \"\")\n .replace(/\\/SKILL\\.md$/i, \"\")\n .replace(/\\.md$/i, \"\")\n .split(\"/\")\n .pop() || \"skill\";\n\n return (\n <NodeViewWrapper as=\"span\" className=\"inline\">\n <span\n className=\"inline-flex items-center gap-1 rounded-md border border-input bg-muted/50 px-1.5 py-0.5 text-xs font-medium text-foreground align-middle mx-0.5 max-w-[160px] select-none\"\n title={node.attrs.path}\n >\n <IconStack2 size={14} className=\"shrink-0 text-muted-foreground\" />\n <span className=\"truncate\">{displayName}</span>\n </span>\n </NodeViewWrapper>\n );\n};\n\nexport const SkillReference = Node.create({\n name: \"skillReference\",\n group: \"inline\",\n inline: true,\n selectable: true,\n atom: true,\n\n addAttributes() {\n return {\n name: { default: null },\n path: { default: null },\n source: { default: \"codebase\" },\n };\n },\n\n parseHTML() {\n return [{ tag: 'span[data-type=\"skill-reference\"]' }];\n },\n\n renderHTML({ HTMLAttributes }) {\n return [\n \"span\",\n mergeAttributes({ \"data-type\": \"skill-reference\" }, HTMLAttributes),\n ];\n },\n\n addNodeView() {\n return ReactNodeViewRenderer(SkillReferenceComponent);\n },\n});\n"]}
@@ -65,6 +65,6 @@ export function ContextMeter({ threadId, enabled = true, }) {
65
65
  if (action === "restore")
66
66
  restore.mutate(params, options);
67
67
  };
68
- return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Context ${pct}%, ${formatTokens(manifest.totalTokens)}. Open Context X-Ray.`, className: cn("flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", open && "bg-accent/60 text-foreground"), children: _jsx(ContextDonut, { pct: pct, advisory: !manifest.enforceable }) }) }) }), _jsxs(TooltipContent, { children: ["Context ", pct, "% \u00B7 ", formatTokens(manifest.totalTokens)] })] }), _jsx(PopoverContent, { align: "end", side: "top", sideOffset: 8, className: "w-[min(92vw,420px)] overflow-hidden p-0", children: _jsx(ContextXRayPanel, { manifest: manifest, optimistic: optimistic, onPin: (segmentId) => mutateStatus(segmentId, "pinned", "pin"), onEvict: (segmentId) => mutateStatus(segmentId, "evicted", "evict"), onRestore: (segmentId) => mutateStatus(segmentId, "active", "restore") }) })] }) }));
68
+ return (_jsx(TooltipProvider, { delayDuration: 200, children: _jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", "aria-label": `Context ${pct}%, ${formatTokens(manifest.totalTokens)}. Open Context X-Ray.`, className: cn("flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", open && "bg-accent/60 text-foreground"), children: _jsx(ContextDonut, { pct: pct, advisory: !manifest.enforceable }) }) }) }), _jsxs(TooltipContent, { children: ["Context ", pct, "% \u00B7 ", formatTokens(manifest.totalTokens)] })] }), _jsx(PopoverContent, { align: "end", side: "top", sideOffset: 8, className: "w-[min(92vw,380px)] overflow-hidden border-border/70 p-0", children: _jsx(ContextXRayPanel, { manifest: manifest, optimistic: optimistic, onPin: (segmentId) => mutateStatus(segmentId, "pinned", "pin"), onEvict: (segmentId) => mutateStatus(segmentId, "evicted", "evict"), onRestore: (segmentId) => mutateStatus(segmentId, "active", "restore") }) })] }) }));
69
69
  }
70
70
  //# sourceMappingURL=ContextMeter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextMeter.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextMeter.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAKpD,OAAO,EACL,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EACL,OAAO,EACP,cAAc,EACd,eAAe,EACf,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACrE,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,wBAAwB,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAErE,SAAS,YAAY,CAAC,EAAE,GAAG,EAAE,QAAQ,EAAsC;IACzE,MAAM,MAAM,GAAG,GAAG,CAAC;IACnB,MAAM,aAAa,GAAG,CAAC,GAAG,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;IACnD,MAAM,UAAU,GAAG,aAAa,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,aAAa,CAAC;IAEtE,OAAO,CACL,gBAAM,SAAS,EAAC,kDAAkD,aAChE,8BAAiB,MAAM,EAAC,OAAO,EAAC,WAAW,EAAC,SAAS,EAAC,mBAAmB,aACvE,iBACE,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,MAAM,EACT,SAAS,EAAC,cAAc,EACxB,IAAI,EAAC,MAAM,EACX,WAAW,EAAC,GAAG,GACf,EACF,iBACE,EAAE,EAAC,IAAI,EACP,EAAE,EAAC,IAAI,EACP,CAAC,EAAE,MAAM,EACT,SAAS,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,kBAAkB,CAAC,EACjE,IAAI,EAAC,MAAM,EACX,aAAa,EAAC,OAAO,EACrB,WAAW,EAAC,GAAG,EACf,eAAe,EAAE,aAAa,EAC9B,gBAAgB,EAAE,UAAU,GAC5B,IACE,EACN,eAAM,SAAS,EAAC,4CAA4C,GAAG,IAC1D,CACR,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,OAAO,GAAG,IAAI,GAIf;IACC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAE1C,IAAI,GAAG,EAAE,CAAC,CAAC;IACb,MAAM,eAAe,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,WAAW,GAAG,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,cAAc,CAC1B,sBAAsB,EACtB,WAAW,IAAI,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,EAClD;QACE,OAAO,EAAE,WAAW;QACpB,SAAS,EAAE,IAAI;KAChB,CAC4B,CAAC;IAChC,MAAM,GAAG,GAAG,iBAAiB,CAAC,aAAa,CAAC,CAAC;IAC7C,MAAM,KAAK,GAAG,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAErD,SAAS,CAAC,GAAG,EAAE;QACb,eAAe,CAAC,OAAO,GAAG,QAAQ,CAAC;QACnC,aAAa,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IAC3B,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEf,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,CAAC,OAAO,IAAI,OAAO,MAAM,KAAK,WAAW;YAAE,OAAO;QACnE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;QAC3D,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,KAAK,GAAG,CAAC;QACpD,MAAM,YAAY,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5C,IAAI,SAAS,IAAI,CAAC,CAAC,YAAY,IAAI,YAAY,KAAK,QAAQ,CAAC,EAAE,CAAC;YAC9D,OAAO,CAAC,IAAI,CAAC,CAAC;QAChB,CAAC;IACH,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExB,MAAM,QAAQ,GAAG,KAAK,CAAC,IAAI,CAAC;IAC5B,MAAM,QAAQ,GAAG,QAAQ,EAAE,QAAQ,IAAI,EAAE,CAAC;IAC1C,MAAM,GAAG,GAAG,QAAQ;QAClB,CAAC,CAAC,IAAI,CAAC,GAAG,CACN,GAAG,EACH,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,WAAW,GAAG,wBAAwB,CAAC,GAAG,GAAG,CAAC,CACpE;QACH,CAAC,CAAC,CAAC,CAAC;IAEN,IAAI,CAAC,WAAW,IAAI,CAAC,QAAQ,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,SAAS,IAAI,CAAC,EAAE,CAAC;QACtE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,YAAY,GAAG,CACnB,SAAiB,EACjB,MAA4B,EAC5B,MAAmC,EACnC,EAAE;QACF,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;QACrC,aAAa,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;QAC9D,MAAM,MAAM,GAAG,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG;YACd,OAAO,EAAE,GAAG,EAAE;gBACZ,IAAI,eAAe,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;oBACzC,aAAa,CAAC,QAAQ,CAAC,CAAC;gBAC1B,CAAC;YACH,CAAC;SACF,CAAC;QACF,IAAI,MAAM,KAAK,KAAK;YAAE,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAClD,IAAI,MAAM,KAAK,OAAO;YAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACtD,IAAI,MAAM,KAAK,SAAS;YAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC5D,CAAC,CAAC;IAEF,OAAO,CACL,KAAC,eAAe,IAAC,aAAa,EAAE,GAAG,YACjC,MAAC,OAAO,IAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,aACxC,MAAC,OAAO,eACN,KAAC,cAAc,IAAC,OAAO,kBACrB,KAAC,cAAc,IAAC,OAAO,kBACrB,iBACE,IAAI,EAAC,QAAQ,gBACD,WAAW,GAAG,MAAM,YAAY,CAC1C,QAAQ,CAAC,WAAW,CACrB,uBAAuB,EACxB,SAAS,EAAE,EAAE,CACX,sNAAsN,EACtN,IAAI,IAAI,8BAA8B,CACvC,YAED,KAAC,YAAY,IAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,GAAI,GACpD,GACM,GACF,EACjB,MAAC,cAAc,2BACJ,GAAG,eAAM,YAAY,CAAC,QAAQ,CAAC,WAAW,CAAC,IACrC,IACT,EACV,KAAC,cAAc,IACb,KAAK,EAAC,KAAK,EACX,IAAI,EAAC,KAAK,EACV,UAAU,EAAE,CAAC,EACb,SAAS,EAAC,yCAAyC,YAEnD,KAAC,gBAAgB,IACf,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,CAAC,EAC9D,OAAO,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,EACnE,SAAS,EAAE,CAAC,SAAS,EAAE,EAAE,CACvB,YAAY,CAAC,SAAS,EAAE,QAAQ,EAAE,SAAS,CAAC,GAE9C,GACa,IACT,GACM,CACnB,CAAC;AACJ,CAAC","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type {\n ContextManifest,\n ContextSegmentStatus,\n} from \"../../shared/context-xray.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../components/ui/popover.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { useActionMutation, useActionQuery } from \"../use-action.js\";\nimport { cn } from \"../utils.js\";\nimport { ContextXRayPanel } from \"./ContextXRayPanel.js\";\nimport { CONTEXT_XRAY_MODEL_LIMIT, formatTokens } from \"./format.js\";\n\nfunction ContextDonut({ pct, advisory }: { pct: number; advisory: boolean }) {\n const radius = 7.5;\n const circumference = 2 * Math.PI * radius;\n const displayPct = Math.max(3, Math.min(100, pct));\n const dashOffset = circumference - (displayPct / 100) * circumference;\n\n return (\n <span className=\"relative flex size-5 items-center justify-center\">\n <svg aria-hidden=\"true\" viewBox=\"0 0 20 20\" className=\"-rotate-90 size-5\">\n <circle\n cx=\"10\"\n cy=\"10\"\n r={radius}\n className=\"stroke-muted\"\n fill=\"none\"\n strokeWidth=\"3\"\n />\n <circle\n cx=\"10\"\n cy=\"10\"\n r={radius}\n className={cn(advisory ? \"stroke-amber-500\" : \"stroke-[#00B5FF]\")}\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeWidth=\"3\"\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n />\n </svg>\n <span className=\"absolute size-2 rounded-full bg-background\" />\n </span>\n );\n}\n\nexport function ContextMeter({\n threadId,\n enabled = true,\n}: {\n threadId?: string | null;\n enabled?: boolean;\n}) {\n const [open, setOpen] = useState(false);\n const [optimistic, setOptimistic] = useState<\n Map<string, ContextSegmentStatus>\n >(new Map());\n const currentThreadId = useRef(threadId);\n const shouldQuery = Boolean(threadId && enabled);\n const query = useActionQuery(\n \"context-manifest-get\",\n shouldQuery && threadId ? { threadId } : undefined,\n {\n enabled: shouldQuery,\n staleTime: 1000,\n },\n ) as { data?: ContextManifest };\n const pin = useActionMutation(\"context-pin\");\n const evict = useActionMutation(\"context-evict\");\n const restore = useActionMutation(\"context-restore\");\n\n useEffect(() => {\n currentThreadId.current = threadId;\n setOptimistic(new Map());\n }, [threadId]);\n\n useEffect(() => {\n if (!threadId || !enabled || typeof window === \"undefined\") return;\n const params = new URLSearchParams(window.location.search);\n const wantsXray = params.get(\"contextXray\") === \"1\";\n const targetThread = params.get(\"threadId\");\n if (wantsXray && (!targetThread || targetThread === threadId)) {\n setOpen(true);\n }\n }, [enabled, threadId]);\n\n const manifest = query.data;\n const segments = manifest?.segments ?? [];\n const pct = manifest\n ? Math.min(\n 100,\n Math.round((manifest.totalTokens / CONTEXT_XRAY_MODEL_LIMIT) * 100),\n )\n : 0;\n\n if (!shouldQuery || !threadId || !manifest || manifest.rawTokens <= 0) {\n return null;\n }\n\n const mutateStatus = (\n segmentId: string,\n status: ContextSegmentStatus,\n action: \"pin\" | \"evict\" | \"restore\",\n ) => {\n const previous = new Map(optimistic);\n setOptimistic((prev) => new Map(prev).set(segmentId, status));\n const params = { threadId, segmentId };\n const options = {\n onError: () => {\n if (currentThreadId.current === threadId) {\n setOptimistic(previous);\n }\n },\n };\n if (action === \"pin\") pin.mutate(params, options);\n if (action === \"evict\") evict.mutate(params, options);\n if (action === \"restore\") restore.mutate(params, options);\n };\n\n return (\n <TooltipProvider delayDuration={200}>\n <Popover open={open} onOpenChange={setOpen}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Context ${pct}%, ${formatTokens(\n manifest.totalTokens,\n )}. Open Context X-Ray.`}\n className={cn(\n \"flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n open && \"bg-accent/60 text-foreground\",\n )}\n >\n <ContextDonut pct={pct} advisory={!manifest.enforceable} />\n </button>\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent>\n Context {pct}% · {formatTokens(manifest.totalTokens)}\n </TooltipContent>\n </Tooltip>\n <PopoverContent\n align=\"end\"\n side=\"top\"\n sideOffset={8}\n className=\"w-[min(92vw,420px)] overflow-hidden p-0\"\n >\n <ContextXRayPanel\n manifest={manifest}\n optimistic={optimistic}\n onPin={(segmentId) => mutateStatus(segmentId, \"pinned\", \"pin\")}\n onEvict={(segmentId) => mutateStatus(segmentId, \"evicted\", \"evict\")}\n onRestore={(segmentId) =>\n mutateStatus(segmentId, \"active\", \"restore\")\n }\n />\n </PopoverContent>\n </Popover>\n </TooltipProvider>\n );\n}\n"]}
1
+ {"version":3,"file":"ContextMeter.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextMeter.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport type {\n ContextManifest,\n ContextSegmentStatus,\n} from \"../../shared/context-xray.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../components/ui/popover.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipProvider,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { useActionMutation, useActionQuery } from \"../use-action.js\";\nimport { cn } from \"../utils.js\";\nimport { ContextXRayPanel } from \"./ContextXRayPanel.js\";\nimport { CONTEXT_XRAY_MODEL_LIMIT, formatTokens } from \"./format.js\";\n\nfunction ContextDonut({ pct, advisory }: { pct: number; advisory: boolean }) {\n const radius = 7.5;\n const circumference = 2 * Math.PI * radius;\n const displayPct = Math.max(3, Math.min(100, pct));\n const dashOffset = circumference - (displayPct / 100) * circumference;\n\n return (\n <span className=\"relative flex size-5 items-center justify-center\">\n <svg aria-hidden=\"true\" viewBox=\"0 0 20 20\" className=\"-rotate-90 size-5\">\n <circle\n cx=\"10\"\n cy=\"10\"\n r={radius}\n className=\"stroke-muted\"\n fill=\"none\"\n strokeWidth=\"3\"\n />\n <circle\n cx=\"10\"\n cy=\"10\"\n r={radius}\n className={cn(advisory ? \"stroke-amber-500\" : \"stroke-[#00B5FF]\")}\n fill=\"none\"\n strokeLinecap=\"round\"\n strokeWidth=\"3\"\n strokeDasharray={circumference}\n strokeDashoffset={dashOffset}\n />\n </svg>\n <span className=\"absolute size-2 rounded-full bg-background\" />\n </span>\n );\n}\n\nexport function ContextMeter({\n threadId,\n enabled = true,\n}: {\n threadId?: string | null;\n enabled?: boolean;\n}) {\n const [open, setOpen] = useState(false);\n const [optimistic, setOptimistic] = useState<\n Map<string, ContextSegmentStatus>\n >(new Map());\n const currentThreadId = useRef(threadId);\n const shouldQuery = Boolean(threadId && enabled);\n const query = useActionQuery(\n \"context-manifest-get\",\n shouldQuery && threadId ? { threadId } : undefined,\n {\n enabled: shouldQuery,\n staleTime: 1000,\n },\n ) as { data?: ContextManifest };\n const pin = useActionMutation(\"context-pin\");\n const evict = useActionMutation(\"context-evict\");\n const restore = useActionMutation(\"context-restore\");\n\n useEffect(() => {\n currentThreadId.current = threadId;\n setOptimistic(new Map());\n }, [threadId]);\n\n useEffect(() => {\n if (!threadId || !enabled || typeof window === \"undefined\") return;\n const params = new URLSearchParams(window.location.search);\n const wantsXray = params.get(\"contextXray\") === \"1\";\n const targetThread = params.get(\"threadId\");\n if (wantsXray && (!targetThread || targetThread === threadId)) {\n setOpen(true);\n }\n }, [enabled, threadId]);\n\n const manifest = query.data;\n const segments = manifest?.segments ?? [];\n const pct = manifest\n ? Math.min(\n 100,\n Math.round((manifest.totalTokens / CONTEXT_XRAY_MODEL_LIMIT) * 100),\n )\n : 0;\n\n if (!shouldQuery || !threadId || !manifest || manifest.rawTokens <= 0) {\n return null;\n }\n\n const mutateStatus = (\n segmentId: string,\n status: ContextSegmentStatus,\n action: \"pin\" | \"evict\" | \"restore\",\n ) => {\n const previous = new Map(optimistic);\n setOptimistic((prev) => new Map(prev).set(segmentId, status));\n const params = { threadId, segmentId };\n const options = {\n onError: () => {\n if (currentThreadId.current === threadId) {\n setOptimistic(previous);\n }\n },\n };\n if (action === \"pin\") pin.mutate(params, options);\n if (action === \"evict\") evict.mutate(params, options);\n if (action === \"restore\") restore.mutate(params, options);\n };\n\n return (\n <TooltipProvider delayDuration={200}>\n <Popover open={open} onOpenChange={setOpen}>\n <Tooltip>\n <TooltipTrigger asChild>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n aria-label={`Context ${pct}%, ${formatTokens(\n manifest.totalTokens,\n )}. Open Context X-Ray.`}\n className={cn(\n \"flex size-7 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/50 hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring\",\n open && \"bg-accent/60 text-foreground\",\n )}\n >\n <ContextDonut pct={pct} advisory={!manifest.enforceable} />\n </button>\n </PopoverTrigger>\n </TooltipTrigger>\n <TooltipContent>\n Context {pct}% · {formatTokens(manifest.totalTokens)}\n </TooltipContent>\n </Tooltip>\n <PopoverContent\n align=\"end\"\n side=\"top\"\n sideOffset={8}\n className=\"w-[min(92vw,380px)] overflow-hidden border-border/70 p-0\"\n >\n <ContextXRayPanel\n manifest={manifest}\n optimistic={optimistic}\n onPin={(segmentId) => mutateStatus(segmentId, \"pinned\", \"pin\")}\n onEvict={(segmentId) => mutateStatus(segmentId, \"evicted\", \"evict\")}\n onRestore={(segmentId) =>\n mutateStatus(segmentId, \"active\", \"restore\")\n }\n />\n </PopoverContent>\n </Popover>\n </TooltipProvider>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextSegmentRow.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextSegmentRow.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAU3E,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,sBAAsB,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,2CAsHA"}
1
+ {"version":3,"file":"ContextSegmentRow.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextSegmentRow.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AAU3E,wBAAgB,iBAAiB,CAAC,EAChC,OAAO,EACP,QAAQ,EACR,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE;IACD,OAAO,EAAE,sBAAsB,CAAC;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,SAAS,EAAE,MAAM,IAAI,CAAC;CACvB,2CAyGA"}
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { IconArrowsMinimize, IconLock, IconPin, IconRotate2, IconX, } from "@tabler/icons-react";
2
+ import { IconLock, IconPin, IconRotate2, IconX } from "@tabler/icons-react";
3
3
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
4
4
  import { cn } from "../utils.js";
5
5
  import { formatTokens, statusLabel } from "./format.js";
@@ -13,10 +13,10 @@ export function ContextSegmentRow({ segment, advisory, onPin, onEvict, onRestore
13
13
  onEvict();
14
14
  if (event.key === "u" && segment.status !== "active")
15
15
  onRestore();
16
- }, className: cn("group flex min-h-12 items-center gap-2 rounded-md border border-transparent px-2 py-1.5 outline-none hover:border-border hover:bg-accent/35 focus-visible:border-ring", segment.status === "evicted" && "opacity-60"), children: [_jsx(SegmentProvenancePopover, { segment: segment, children: _jsxs("button", { type: "button", className: "min-w-0 flex-1 text-left", "aria-label": `Inspect ${segment.label}`, children: [_jsx("div", { className: cn("truncate text-xs font-medium text-foreground", segment.status === "evicted" && "line-through"), children: segment.label }), _jsxs("div", { className: "mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [_jsx("span", { children: formatTokens(segment.tokenCount) }), segment.tokenMethod === "estimate" && _jsx("span", { children: "~" }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: statusLabel(segment) }), advisory && _jsx("span", { children: "\u00B7 advisory" })] })] }) }), _jsx("div", { className: "flex shrink-0 items-center gap-1 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100", children: segment.protected ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground", children: _jsx(IconLock, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Protected during active turn" })] })) : segment.status === "evicted" ||
16
+ }, className: cn("group flex min-h-11 items-center gap-2 rounded-sm px-2 py-1.5 outline-none transition-colors hover:bg-accent/35 focus-visible:bg-accent/35 focus-visible:ring-1 focus-visible:ring-ring", segment.status === "evicted" && "opacity-60"), children: [_jsx(SegmentProvenancePopover, { segment: segment, children: _jsxs("button", { type: "button", className: "min-w-0 flex-1 text-left", "aria-label": `Inspect ${segment.label}`, children: [_jsx("div", { className: cn("truncate text-[13px] font-medium leading-5 text-foreground", segment.status === "evicted" && "line-through"), children: segment.label }), _jsxs("div", { className: "flex items-center gap-1.5 text-[11px] text-muted-foreground", children: [_jsx("span", { children: formatTokens(segment.tokenCount) }), segment.tokenMethod === "estimate" && _jsx("span", { children: "~" }), _jsx("span", { children: "\u00B7" }), _jsx("span", { children: statusLabel(segment) }), advisory && _jsx("span", { children: "\u00B7 advisory" })] })] }) }), _jsx("div", { className: "flex shrink-0 items-center gap-1 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100", children: segment.protected ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { className: "flex size-6 items-center justify-center rounded-md text-muted-foreground", children: _jsx(IconLock, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Protected during active turn" })] })) : segment.status === "evicted" ||
17
17
  segment.status === "summarized" ||
18
- segment.status === "pinned" ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onRestore, className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": segment.status === "pinned"
18
+ segment.status === "pinned" ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onRestore, className: "flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": segment.status === "pinned"
19
19
  ? "Unpin segment"
20
- : "Restore segment", children: _jsx(IconRotate2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: segment.status === "pinned" ? "Unpin" : "Restore" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onPin, className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": "Pin segment", children: _jsx(IconPin, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Pin" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", disabled: true, className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground/50", "aria-label": "Compress segment", children: _jsx(IconArrowsMinimize, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Compress is coming soon" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onEvict, className: "flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-destructive", "aria-label": "Evict segment", children: _jsx(IconX, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: advisory ? "Record eviction intent" : "Evict" })] })] })) })] }));
20
+ : "Restore segment", children: _jsx(IconRotate2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: segment.status === "pinned" ? "Unpin" : "Restore" })] })) : (_jsxs(_Fragment, { children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onPin, className: "flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground", "aria-label": "Pin segment", children: _jsx(IconPin, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Pin" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: onEvict, className: "flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-destructive", "aria-label": "Evict segment", children: _jsx(IconX, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: advisory ? "Record eviction intent" : "Evict" })] })] })) })] }));
21
21
  }
22
22
  //# sourceMappingURL=ContextSegmentRow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ContextSegmentRow.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextSegmentRow.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n IconArrowsMinimize,\n IconLock,\n IconPin,\n IconRotate2,\n IconX,\n} from \"@tabler/icons-react\";\nimport type { ContextManifestSegment } from \"../../shared/context-xray.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { cn } from \"../utils.js\";\nimport { formatTokens, statusLabel } from \"./format.js\";\nimport { SegmentProvenancePopover } from \"./SegmentProvenancePopover.js\";\n\nexport function ContextSegmentRow({\n segment,\n advisory,\n onPin,\n onEvict,\n onRestore,\n}: {\n segment: ContextManifestSegment;\n advisory: boolean;\n onPin: () => void;\n onEvict: () => void;\n onRestore: () => void;\n}) {\n const disabled = segment.protected || segment.status === \"evicted\";\n return (\n <div\n tabIndex={0}\n onKeyDown={(event) => {\n if (event.key === \"p\") onPin();\n if (event.key === \"e\" && !disabled) onEvict();\n if (event.key === \"u\" && segment.status !== \"active\") onRestore();\n }}\n className={cn(\n \"group flex min-h-12 items-center gap-2 rounded-md border border-transparent px-2 py-1.5 outline-none hover:border-border hover:bg-accent/35 focus-visible:border-ring\",\n segment.status === \"evicted\" && \"opacity-60\",\n )}\n >\n <SegmentProvenancePopover segment={segment}>\n <button\n type=\"button\"\n className=\"min-w-0 flex-1 text-left\"\n aria-label={`Inspect ${segment.label}`}\n >\n <div\n className={cn(\n \"truncate text-xs font-medium text-foreground\",\n segment.status === \"evicted\" && \"line-through\",\n )}\n >\n {segment.label}\n </div>\n <div className=\"mt-0.5 flex items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span>{formatTokens(segment.tokenCount)}</span>\n {segment.tokenMethod === \"estimate\" && <span>~</span>}\n <span>·</span>\n <span>{statusLabel(segment)}</span>\n {advisory && <span>· advisory</span>}\n </div>\n </button>\n </SegmentProvenancePopover>\n <div className=\"flex shrink-0 items-center gap-1 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100\">\n {segment.protected ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground\">\n <IconLock className=\"h-3.5 w-3.5\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>Protected during active turn</TooltipContent>\n </Tooltip>\n ) : segment.status === \"evicted\" ||\n segment.status === \"summarized\" ||\n segment.status === \"pinned\" ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onRestore}\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground\"\n aria-label={\n segment.status === \"pinned\"\n ? \"Unpin segment\"\n : \"Restore segment\"\n }\n >\n <IconRotate2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {segment.status === \"pinned\" ? \"Unpin\" : \"Restore\"}\n </TooltipContent>\n </Tooltip>\n ) : (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onPin}\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground\"\n aria-label=\"Pin segment\"\n >\n <IconPin className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Pin</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n disabled\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground/50\"\n aria-label=\"Compress segment\"\n >\n <IconArrowsMinimize className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Compress is coming soon</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onEvict}\n className=\"flex h-7 w-7 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-destructive\"\n aria-label=\"Evict segment\"\n >\n <IconX className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {advisory ? \"Record eviction intent\" : \"Evict\"}\n </TooltipContent>\n </Tooltip>\n </>\n )}\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"ContextSegmentRow.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextSegmentRow.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconLock, IconPin, IconRotate2, IconX } from \"@tabler/icons-react\";\nimport type { ContextManifestSegment } from \"../../shared/context-xray.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { cn } from \"../utils.js\";\nimport { formatTokens, statusLabel } from \"./format.js\";\nimport { SegmentProvenancePopover } from \"./SegmentProvenancePopover.js\";\n\nexport function ContextSegmentRow({\n segment,\n advisory,\n onPin,\n onEvict,\n onRestore,\n}: {\n segment: ContextManifestSegment;\n advisory: boolean;\n onPin: () => void;\n onEvict: () => void;\n onRestore: () => void;\n}) {\n const disabled = segment.protected || segment.status === \"evicted\";\n return (\n <div\n tabIndex={0}\n onKeyDown={(event) => {\n if (event.key === \"p\") onPin();\n if (event.key === \"e\" && !disabled) onEvict();\n if (event.key === \"u\" && segment.status !== \"active\") onRestore();\n }}\n className={cn(\n \"group flex min-h-11 items-center gap-2 rounded-sm px-2 py-1.5 outline-none transition-colors hover:bg-accent/35 focus-visible:bg-accent/35 focus-visible:ring-1 focus-visible:ring-ring\",\n segment.status === \"evicted\" && \"opacity-60\",\n )}\n >\n <SegmentProvenancePopover segment={segment}>\n <button\n type=\"button\"\n className=\"min-w-0 flex-1 text-left\"\n aria-label={`Inspect ${segment.label}`}\n >\n <div\n className={cn(\n \"truncate text-[13px] font-medium leading-5 text-foreground\",\n segment.status === \"evicted\" && \"line-through\",\n )}\n >\n {segment.label}\n </div>\n <div className=\"flex items-center gap-1.5 text-[11px] text-muted-foreground\">\n <span>{formatTokens(segment.tokenCount)}</span>\n {segment.tokenMethod === \"estimate\" && <span>~</span>}\n <span>·</span>\n <span>{statusLabel(segment)}</span>\n {advisory && <span>· advisory</span>}\n </div>\n </button>\n </SegmentProvenancePopover>\n <div className=\"flex shrink-0 items-center gap-1 opacity-100 sm:opacity-0 sm:group-hover:opacity-100 sm:group-focus-within:opacity-100\">\n {segment.protected ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <span className=\"flex size-6 items-center justify-center rounded-md text-muted-foreground\">\n <IconLock className=\"h-3.5 w-3.5\" />\n </span>\n </TooltipTrigger>\n <TooltipContent>Protected during active turn</TooltipContent>\n </Tooltip>\n ) : segment.status === \"evicted\" ||\n segment.status === \"summarized\" ||\n segment.status === \"pinned\" ? (\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onRestore}\n className=\"flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground\"\n aria-label={\n segment.status === \"pinned\"\n ? \"Unpin segment\"\n : \"Restore segment\"\n }\n >\n <IconRotate2 className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {segment.status === \"pinned\" ? \"Unpin\" : \"Restore\"}\n </TooltipContent>\n </Tooltip>\n ) : (\n <>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onPin}\n className=\"flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-foreground\"\n aria-label=\"Pin segment\"\n >\n <IconPin className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Pin</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={onEvict}\n className=\"flex size-6 items-center justify-center rounded-md text-muted-foreground hover:bg-background hover:text-destructive\"\n aria-label=\"Evict segment\"\n >\n <IconX className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>\n {advisory ? \"Record eviction intent\" : \"Evict\"}\n </TooltipContent>\n </Tooltip>\n </>\n )}\n </div>\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextTreemap.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextTreemap.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AA4C3E,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,2CA+DA"}
1
+ {"version":3,"file":"ContextTreemap.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextTreemap.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,8BAA8B,CAAC;AA4C3E,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,sBAAsB,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,2CA4DA"}
@@ -39,9 +39,9 @@ export function ContextTreemap({ segments, onSelect, }) {
39
39
  };
40
40
  }, []);
41
41
  if (data.length === 0) {
42
- return (_jsx("div", { className: "flex h-56 items-center justify-center rounded-md border border-dashed border-border text-xs text-muted-foreground", children: "No active segments" }));
42
+ return (_jsx("div", { className: "flex h-52 items-center justify-center rounded-md bg-muted/30 text-xs text-muted-foreground", children: "No active segments" }));
43
43
  }
44
- return (_jsx("div", { ref: containerRef, className: "h-64 min-w-0 rounded-md border border-border bg-muted/20 p-1", children: chartWidth > 0 && (_jsx(Treemap, { width: chartWidth, height: 248, data: data, dataKey: "size", nameKey: "name", aspectRatio: 4 / 3, isAnimationActive: false, content: _jsx(TreemapContent, {}), onClick: (datum) => {
44
+ return (_jsx("div", { ref: containerRef, className: "h-56 min-w-0 rounded-md bg-muted/25 p-1", children: chartWidth > 0 && (_jsx(Treemap, { width: chartWidth, height: 216, data: data, dataKey: "size", nameKey: "name", aspectRatio: 4 / 3, isAnimationActive: false, content: _jsx(TreemapContent, {}), onClick: (datum) => {
45
45
  if (datum?.segmentId)
46
46
  onSelect?.(datum.segmentId);
47
47
  } })) }));
@@ -1 +1 @@
1
- {"version":3,"file":"ContextTreemap.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextTreemap.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Treemap } from \"recharts\";\nimport type { ContextManifestSegment } from \"../../shared/context-xray.js\";\nimport { formatTokens, groupFill } from \"./format.js\";\n\ninterface TreemapDatum {\n name: string;\n size: number;\n group: string;\n segmentId: string;\n}\n\nfunction TreemapContent(props: any) {\n const { x, y, width, height, name, group, size } = props;\n if (width < 8 || height < 8) return null;\n const showLabel = width > 90 && height > 42;\n return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n rx={3}\n ry={3}\n fill={groupFill(group)}\n stroke=\"var(--background)\"\n strokeWidth={2}\n />\n {showLabel && (\n <foreignObject\n x={x + 6}\n y={y + 6}\n width={width - 12}\n height={height - 12}\n >\n <div className=\"flex h-full flex-col justify-between overflow-hidden text-[11px] leading-tight text-white\">\n <div className=\"truncate font-medium\">{name}</div>\n <div className=\"text-white/85\">{formatTokens(size)}</div>\n </div>\n </foreignObject>\n )}\n </g>\n );\n}\n\nexport function ContextTreemap({\n segments,\n onSelect,\n}: {\n segments: ContextManifestSegment[];\n onSelect?: (segmentId: string) => void;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [chartWidth, setChartWidth] = useState(0);\n const data: TreemapDatum[] = segments\n .filter((segment) => segment.status !== \"evicted\" && segment.tokenCount > 0)\n .map((segment) => ({\n name: segment.label,\n size: segment.tokenCount,\n group: segment.group,\n segmentId: segment.segmentId,\n }));\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n\n const updateWidth = () => {\n setChartWidth(Math.max(0, Math.floor(element.clientWidth - 8)));\n };\n updateWidth();\n\n const observer =\n typeof ResizeObserver !== \"undefined\"\n ? new ResizeObserver(updateWidth)\n : null;\n observer?.observe(element);\n window.addEventListener(\"resize\", updateWidth);\n return () => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", updateWidth);\n };\n }, []);\n\n if (data.length === 0) {\n return (\n <div className=\"flex h-56 items-center justify-center rounded-md border border-dashed border-border text-xs text-muted-foreground\">\n No active segments\n </div>\n );\n }\n\n return (\n <div\n ref={containerRef}\n className=\"h-64 min-w-0 rounded-md border border-border bg-muted/20 p-1\"\n >\n {chartWidth > 0 && (\n <Treemap\n width={chartWidth}\n height={248}\n data={data as any}\n dataKey=\"size\"\n nameKey=\"name\"\n aspectRatio={4 / 3}\n isAnimationActive={false}\n content={<TreemapContent />}\n onClick={(datum: any) => {\n if (datum?.segmentId) onSelect?.(datum.segmentId);\n }}\n />\n )}\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"ContextTreemap.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextTreemap.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { Treemap } from \"recharts\";\nimport type { ContextManifestSegment } from \"../../shared/context-xray.js\";\nimport { formatTokens, groupFill } from \"./format.js\";\n\ninterface TreemapDatum {\n name: string;\n size: number;\n group: string;\n segmentId: string;\n}\n\nfunction TreemapContent(props: any) {\n const { x, y, width, height, name, group, size } = props;\n if (width < 8 || height < 8) return null;\n const showLabel = width > 90 && height > 42;\n return (\n <g>\n <rect\n x={x}\n y={y}\n width={width}\n height={height}\n rx={3}\n ry={3}\n fill={groupFill(group)}\n stroke=\"var(--background)\"\n strokeWidth={2}\n />\n {showLabel && (\n <foreignObject\n x={x + 6}\n y={y + 6}\n width={width - 12}\n height={height - 12}\n >\n <div className=\"flex h-full flex-col justify-between overflow-hidden text-[11px] leading-tight text-white\">\n <div className=\"truncate font-medium\">{name}</div>\n <div className=\"text-white/85\">{formatTokens(size)}</div>\n </div>\n </foreignObject>\n )}\n </g>\n );\n}\n\nexport function ContextTreemap({\n segments,\n onSelect,\n}: {\n segments: ContextManifestSegment[];\n onSelect?: (segmentId: string) => void;\n}) {\n const containerRef = useRef<HTMLDivElement>(null);\n const [chartWidth, setChartWidth] = useState(0);\n const data: TreemapDatum[] = segments\n .filter((segment) => segment.status !== \"evicted\" && segment.tokenCount > 0)\n .map((segment) => ({\n name: segment.label,\n size: segment.tokenCount,\n group: segment.group,\n segmentId: segment.segmentId,\n }));\n\n useEffect(() => {\n const element = containerRef.current;\n if (!element) return;\n\n const updateWidth = () => {\n setChartWidth(Math.max(0, Math.floor(element.clientWidth - 8)));\n };\n updateWidth();\n\n const observer =\n typeof ResizeObserver !== \"undefined\"\n ? new ResizeObserver(updateWidth)\n : null;\n observer?.observe(element);\n window.addEventListener(\"resize\", updateWidth);\n return () => {\n observer?.disconnect();\n window.removeEventListener(\"resize\", updateWidth);\n };\n }, []);\n\n if (data.length === 0) {\n return (\n <div className=\"flex h-52 items-center justify-center rounded-md bg-muted/30 text-xs text-muted-foreground\">\n No active segments\n </div>\n );\n }\n\n return (\n <div ref={containerRef} className=\"h-56 min-w-0 rounded-md bg-muted/25 p-1\">\n {chartWidth > 0 && (\n <Treemap\n width={chartWidth}\n height={216}\n data={data as any}\n dataKey=\"size\"\n nameKey=\"name\"\n aspectRatio={4 / 3}\n isAnimationActive={false}\n content={<TreemapContent />}\n onClick={(datum: any) => {\n if (datum?.segmentId) onSelect?.(datum.segmentId);\n }}\n />\n )}\n </div>\n );\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ContextXRayPanel.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextXRayPanel.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EACV,eAAe,EAEf,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AA+FtC,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,UAAU,EACV,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,2CAsLA"}
1
+ {"version":3,"file":"ContextXRayPanel.d.ts","sourceRoot":"","sources":["../../../src/client/context-xray/ContextXRayPanel.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,eAAe,EAEf,oBAAoB,EACrB,MAAM,8BAA8B,CAAC;AAkEtC,wBAAgB,gBAAgB,CAAC,EAC/B,QAAQ,EACR,UAAU,EACV,KAAK,EACL,OAAO,EACP,SAAS,GACV,EAAE;IACD,QAAQ,EAAE,eAAe,CAAC;IAC1B,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;CACxC,2CAmKA"}
@@ -1,5 +1,5 @@
1
- import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { IconAdjustmentsHorizontal, IconChartTreemap, IconChevronDown, IconChevronRight, IconListDetails, IconPin, } from "@tabler/icons-react";
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconChartTreemap, IconChevronDown, IconChevronRight, IconListDetails, } from "@tabler/icons-react";
3
3
  import { useMemo, useState } from "react";
4
4
  import { Tooltip, TooltipContent, TooltipTrigger, } from "../components/ui/tooltip.js";
5
5
  import { cn } from "../utils.js";
@@ -47,12 +47,6 @@ function groupedSegments(segments) {
47
47
  return b.tokens - a.tokens;
48
48
  });
49
49
  }
50
- function StatusLine({ manifest }) {
51
- const pinned = manifest.segments.filter((s) => s.status === "pinned").length;
52
- const evicted = manifest.segments.filter((s) => s.status === "evicted").length;
53
- const estimate = manifest.tokenCountMethod === "estimate";
54
- return (_jsxs("div", { className: "flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground", children: [_jsxs("span", { children: ["Pinned ", pinned] }), _jsx("span", { children: "\u00B7" }), _jsxs("span", { children: ["Evicted ", evicted] }), estimate && (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsx("span", { children: "token counts estimated" })] })), !manifest.enforceable && (_jsxs(_Fragment, { children: [_jsx("span", { children: "\u00B7" }), _jsx("span", { className: "rounded-sm border border-amber-500/30 bg-amber-500/10 px-1.5 py-0.5 text-amber-700 dark:text-amber-300", children: "Advisory" })] }))] }));
55
- }
56
50
  export function ContextXRayPanel({ manifest, optimistic, onPin, onEvict, onRestore, }) {
57
51
  const [mode, setMode] = useState("list");
58
52
  const [collapsed, setCollapsed] = useState(new Set());
@@ -60,19 +54,26 @@ export function ContextXRayPanel({ manifest, optimistic, onPin, onEvict, onResto
60
54
  const groups = useMemo(() => groupedSegments(segments), [segments]);
61
55
  const pct = Math.min(100, Math.round((manifest.totalTokens / CONTEXT_XRAY_MODEL_LIMIT) * 100));
62
56
  const headroom = Math.max(0, CONTEXT_XRAY_MODEL_LIMIT - manifest.totalTokens);
63
- return (_jsxs("div", { className: "flex max-h-[min(72vh,560px)] flex-col", children: [_jsx("div", { className: "border-b border-border px-4 py-3", children: _jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsxs("div", { className: "min-w-0", children: [_jsxs("div", { className: "flex items-center gap-2 text-sm font-medium text-foreground", children: [_jsx(IconAdjustmentsHorizontal, { className: "h-4 w-4 shrink-0 text-muted-foreground" }), _jsx("span", { children: "Context X-Ray" })] }), _jsx("div", { className: "mt-1 text-xs text-muted-foreground", children: manifest.enforceable
64
- ? "Pin or evict what reaches future turns."
65
- : "Advisory for external host context." })] }), manifest.reclaimedTokens > 0 && (_jsxs("div", { className: "shrink-0 rounded-md border border-emerald-500/30 bg-emerald-500/10 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300", children: ["-", formatTokens(manifest.reclaimedTokens)] }))] }) }), _jsxs("div", { className: "space-y-3 overflow-y-auto px-4 py-3", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-end justify-between gap-3", children: [_jsxs("div", { children: [_jsx("div", { className: "text-xl font-semibold text-foreground", children: formatTokens(manifest.totalTokens) }), _jsxs("div", { className: "text-xs text-muted-foreground", children: [pct, "% used \u00B7 ", formatTokens(headroom), " free"] })] }), _jsx(StatusLine, { manifest: manifest })] }), _jsx("div", { className: "h-1.5 overflow-hidden rounded-full bg-muted", children: _jsx("div", { className: "h-full rounded-full bg-foreground transition-[width] duration-300", style: { width: `${pct}%` } }) })] }), _jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsxs("div", { className: "inline-flex rounded-md border border-border bg-muted/30 p-0.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setMode("list"), "aria-label": "Show context list", className: cn("flex size-7 items-center justify-center rounded text-muted-foreground", mode === "list"
66
- ? "bg-background text-foreground shadow-sm"
67
- : "hover:text-foreground"), children: _jsx(IconListDetails, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "List" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setMode("map"), "aria-label": "Show context map", className: cn("flex size-7 items-center justify-center rounded text-muted-foreground", mode === "map"
68
- ? "bg-background text-foreground shadow-sm"
69
- : "hover:text-foreground"), children: _jsx(IconChartTreemap, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Map" })] })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "flex items-center gap-1 text-[11px] text-muted-foreground", children: [_jsx(IconPin, { className: "h-3.5 w-3.5" }), _jsx("span", { children: segments.filter((s) => s.status === "pinned").length })] }) }), _jsx(TooltipContent, { children: "Pinned segments survive compaction" })] })] }), mode === "map" ? (_jsx(ContextTreemap, { segments: segments, onSelect: (segmentId) => {
57
+ const pinned = segments.filter((s) => s.status === "pinned").length;
58
+ const evicted = segments.filter((s) => s.status === "evicted").length;
59
+ const details = [
60
+ `${formatTokens(headroom)} free`,
61
+ pinned > 0 ? `${pinned} pinned` : null,
62
+ evicted > 0 ? `${evicted} evicted` : null,
63
+ manifest.tokenCountMethod === "estimate" ? "estimated" : null,
64
+ !manifest.enforceable ? "advisory" : null,
65
+ ].filter((item) => Boolean(item));
66
+ return (_jsxs("div", { className: "flex max-h-[min(72vh,520px)] flex-col", children: [_jsxs("div", { className: "border-b border-border/60 px-3 py-2.5", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("h2", { className: "min-w-0 truncate text-sm font-medium text-foreground", children: "Context X-Ray" }), _jsxs("div", { className: "shrink-0 text-xs tabular-nums text-muted-foreground", children: [formatTokens(manifest.totalTokens), " \u00B7 ", pct, "%"] })] }), _jsx("div", { className: "mt-2 h-1 overflow-hidden rounded-full bg-muted/70", children: _jsx("div", { className: "h-full rounded-full bg-foreground transition-[width] duration-200", style: { width: `${pct}%` } }) }), _jsxs("div", { className: "mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-muted-foreground", children: [details.map((detail) => (_jsx("span", { children: detail }, detail))), manifest.reclaimedTokens > 0 && (_jsxs("span", { className: "font-medium text-emerald-600 dark:text-emerald-400", children: ["-", formatTokens(manifest.reclaimedTokens)] }))] })] }), _jsxs("div", { className: "overflow-y-auto px-2 py-2", children: [_jsx("div", { className: "mb-1 flex items-center justify-end", children: _jsxs("div", { className: "inline-flex rounded-md bg-muted/40 p-0.5", children: [_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setMode("list"), "aria-label": "Show context list", className: cn("flex size-7 items-center justify-center rounded text-muted-foreground", mode === "list"
67
+ ? "bg-background text-foreground shadow-sm"
68
+ : "hover:text-foreground"), children: _jsx(IconListDetails, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "List" })] }), _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { type: "button", onClick: () => setMode("map"), "aria-label": "Show context map", className: cn("flex size-7 items-center justify-center rounded text-muted-foreground", mode === "map"
69
+ ? "bg-background text-foreground shadow-sm"
70
+ : "hover:text-foreground"), children: _jsx(IconChartTreemap, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Map" })] })] }) }), mode === "map" ? (_jsx(ContextTreemap, { segments: segments, onSelect: (segmentId) => {
70
71
  const segment = segments.find((s) => s.segmentId === segmentId);
71
72
  if (segment)
72
73
  setCollapsed(new Set());
73
- } })) : (_jsx("div", { className: "space-y-2", children: groups.map((group) => {
74
+ } })) : (_jsx("div", { className: "divide-y divide-border/60", children: groups.map((group) => {
74
75
  const isCollapsed = collapsed.has(group.name);
75
- return (_jsxs("div", { className: "rounded-md border border-border", children: [_jsxs("button", { type: "button", onClick: () => {
76
+ return (_jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => {
76
77
  setCollapsed((prev) => {
77
78
  const next = new Set(prev);
78
79
  if (next.has(group.name))
@@ -81,7 +82,7 @@ export function ContextXRayPanel({ manifest, optimistic, onPin, onEvict, onResto
81
82
  next.add(group.name);
82
83
  return next;
83
84
  });
84
- }, className: "flex w-full items-center gap-2 px-2.5 py-2 text-left", children: [isCollapsed ? (_jsx(IconChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground" })) : (_jsx(IconChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })), _jsx("span", { className: cn("h-2 w-2 rounded-full", groupColor(group.name)) }), _jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium", children: group.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: formatTokens(group.tokens) })] }), !isCollapsed && (_jsx("div", { className: "border-t border-border py-1", children: group.segments
85
+ }, className: "flex w-full items-center gap-2 rounded-sm px-1.5 py-2 text-left hover:bg-accent/35", children: [isCollapsed ? (_jsx(IconChevronRight, { className: "h-3.5 w-3.5 text-muted-foreground" })) : (_jsx(IconChevronDown, { className: "h-3.5 w-3.5 text-muted-foreground" })), _jsx("span", { className: cn("h-2 w-2 rounded-full", groupColor(group.name)) }), _jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium", children: group.name }), _jsx("span", { className: "text-[11px] text-muted-foreground", children: formatTokens(group.tokens) })] }), !isCollapsed && (_jsx("div", { className: "pb-1", children: group.segments
85
86
  .slice()
86
87
  .sort((a, b) => b.tokenCount - a.tokenCount)
87
88
  .map((segment) => (_jsx(ContextSegmentRow, { segment: segment, advisory: !manifest.enforceable, onPin: () => onPin(segment.segmentId), onEvict: () => onEvict(segment.segmentId), onRestore: () => onRestore(segment.segmentId) }, segment.segmentId))) }))] }, group.name));
@@ -1 +1 @@
1
- {"version":3,"file":"ContextXRayPanel.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextXRayPanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n IconAdjustmentsHorizontal,\n IconChartTreemap,\n IconChevronDown,\n IconChevronRight,\n IconListDetails,\n IconPin,\n} from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport type {\n ContextManifest,\n ContextManifestSegment,\n ContextSegmentStatus,\n} from \"../../shared/context-xray.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { cn } from \"../utils.js\";\nimport { ContextSegmentRow } from \"./ContextSegmentRow.js\";\nimport { ContextTreemap } from \"./ContextTreemap.js\";\nimport {\n CONTEXT_XRAY_MODEL_LIMIT,\n formatTokens,\n groupColor,\n} from \"./format.js\";\n\ninterface Group {\n name: string;\n tokens: number;\n segments: ContextManifestSegment[];\n}\n\nfunction applyOptimisticStatus(\n segments: ContextManifestSegment[],\n optimistic: Map<string, ContextSegmentStatus>,\n): ContextManifestSegment[] {\n if (optimistic.size === 0) return segments;\n return segments.map((segment) => {\n const status = optimistic.get(segment.segmentId);\n return status ? { ...segment, status } : segment;\n });\n}\n\nfunction groupedSegments(segments: ContextManifestSegment[]): Group[] {\n const map = new Map<string, Group>();\n for (const segment of segments) {\n const groupName =\n segment.status === \"pinned\"\n ? \"Pinned\"\n : segment.status === \"evicted\"\n ? \"Evicted\"\n : segment.group;\n const group = map.get(groupName) ?? {\n name: groupName,\n tokens: 0,\n segments: [],\n };\n group.tokens += segment.tokenCount;\n group.segments.push(segment);\n map.set(groupName, group);\n }\n const order = [\n \"Pinned\",\n \"Tool results\",\n \"Files read\",\n \"Conversation\",\n \"Thinking\",\n \"Evicted\",\n ];\n return [...map.values()].sort((a, b) => {\n const ai = order.indexOf(a.name);\n const bi = order.indexOf(b.name);\n if (ai >= 0 || bi >= 0) return (ai < 0 ? 99 : ai) - (bi < 0 ? 99 : bi);\n return b.tokens - a.tokens;\n });\n}\n\nfunction StatusLine({ manifest }: { manifest: ContextManifest }) {\n const pinned = manifest.segments.filter((s) => s.status === \"pinned\").length;\n const evicted = manifest.segments.filter(\n (s) => s.status === \"evicted\",\n ).length;\n const estimate = manifest.tokenCountMethod === \"estimate\";\n return (\n <div className=\"flex flex-wrap items-center gap-2 text-[11px] text-muted-foreground\">\n <span>Pinned {pinned}</span>\n <span>·</span>\n <span>Evicted {evicted}</span>\n {estimate && (\n <>\n <span>·</span>\n <span>token counts estimated</span>\n </>\n )}\n {!manifest.enforceable && (\n <>\n <span>·</span>\n <span className=\"rounded-sm border border-amber-500/30 bg-amber-500/10 px-1.5 py-0.5 text-amber-700 dark:text-amber-300\">\n Advisory\n </span>\n </>\n )}\n </div>\n );\n}\n\nexport function ContextXRayPanel({\n manifest,\n optimistic,\n onPin,\n onEvict,\n onRestore,\n}: {\n manifest: ContextManifest;\n optimistic: Map<string, ContextSegmentStatus>;\n onPin: (segmentId: string) => void;\n onEvict: (segmentId: string) => void;\n onRestore: (segmentId: string) => void;\n}) {\n const [mode, setMode] = useState<\"list\" | \"map\">(\"list\");\n const [collapsed, setCollapsed] = useState<Set<string>>(new Set());\n const segments = useMemo(\n () => applyOptimisticStatus(manifest.segments, optimistic),\n [manifest.segments, optimistic],\n );\n const groups = useMemo(() => groupedSegments(segments), [segments]);\n const pct = Math.min(\n 100,\n Math.round((manifest.totalTokens / CONTEXT_XRAY_MODEL_LIMIT) * 100),\n );\n const headroom = Math.max(0, CONTEXT_XRAY_MODEL_LIMIT - manifest.totalTokens);\n\n return (\n <div className=\"flex max-h-[min(72vh,560px)] flex-col\">\n <div className=\"border-b border-border px-4 py-3\">\n <div className=\"flex items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"flex items-center gap-2 text-sm font-medium text-foreground\">\n <IconAdjustmentsHorizontal className=\"h-4 w-4 shrink-0 text-muted-foreground\" />\n <span>Context X-Ray</span>\n </div>\n <div className=\"mt-1 text-xs text-muted-foreground\">\n {manifest.enforceable\n ? \"Pin or evict what reaches future turns.\"\n : \"Advisory for external host context.\"}\n </div>\n </div>\n {manifest.reclaimedTokens > 0 && (\n <div className=\"shrink-0 rounded-md border border-emerald-500/30 bg-emerald-500/10 px-2 py-1 text-xs font-medium text-emerald-700 dark:text-emerald-300\">\n -{formatTokens(manifest.reclaimedTokens)}\n </div>\n )}\n </div>\n </div>\n\n <div className=\"space-y-3 overflow-y-auto px-4 py-3\">\n <div className=\"space-y-2\">\n <div className=\"flex items-end justify-between gap-3\">\n <div>\n <div className=\"text-xl font-semibold text-foreground\">\n {formatTokens(manifest.totalTokens)}\n </div>\n <div className=\"text-xs text-muted-foreground\">\n {pct}% used · {formatTokens(headroom)} free\n </div>\n </div>\n <StatusLine manifest={manifest} />\n </div>\n <div className=\"h-1.5 overflow-hidden rounded-full bg-muted\">\n <div\n className=\"h-full rounded-full bg-foreground transition-[width] duration-300\"\n style={{ width: `${pct}%` }}\n />\n </div>\n </div>\n\n <div className=\"flex items-center justify-between gap-2\">\n <div className=\"inline-flex rounded-md border border-border bg-muted/30 p-0.5\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setMode(\"list\")}\n aria-label=\"Show context list\"\n className={cn(\n \"flex size-7 items-center justify-center rounded text-muted-foreground\",\n mode === \"list\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"hover:text-foreground\",\n )}\n >\n <IconListDetails className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>List</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setMode(\"map\")}\n aria-label=\"Show context map\"\n className={cn(\n \"flex size-7 items-center justify-center rounded text-muted-foreground\",\n mode === \"map\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"hover:text-foreground\",\n )}\n >\n <IconChartTreemap className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Map</TooltipContent>\n </Tooltip>\n </div>\n <Tooltip>\n <TooltipTrigger asChild>\n <div className=\"flex items-center gap-1 text-[11px] text-muted-foreground\">\n <IconPin className=\"h-3.5 w-3.5\" />\n <span>\n {segments.filter((s) => s.status === \"pinned\").length}\n </span>\n </div>\n </TooltipTrigger>\n <TooltipContent>Pinned segments survive compaction</TooltipContent>\n </Tooltip>\n </div>\n\n {mode === \"map\" ? (\n <ContextTreemap\n segments={segments}\n onSelect={(segmentId) => {\n const segment = segments.find((s) => s.segmentId === segmentId);\n if (segment) setCollapsed(new Set());\n }}\n />\n ) : (\n <div className=\"space-y-2\">\n {groups.map((group) => {\n const isCollapsed = collapsed.has(group.name);\n return (\n <div\n key={group.name}\n className=\"rounded-md border border-border\"\n >\n <button\n type=\"button\"\n onClick={() => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(group.name)) next.delete(group.name);\n else next.add(group.name);\n return next;\n });\n }}\n className=\"flex w-full items-center gap-2 px-2.5 py-2 text-left\"\n >\n {isCollapsed ? (\n <IconChevronRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n ) : (\n <IconChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n )}\n <span\n className={cn(\n \"h-2 w-2 rounded-full\",\n groupColor(group.name),\n )}\n />\n <span className=\"min-w-0 flex-1 truncate text-xs font-medium\">\n {group.name}\n </span>\n <span className=\"text-[11px] text-muted-foreground\">\n {formatTokens(group.tokens)}\n </span>\n </button>\n {!isCollapsed && (\n <div className=\"border-t border-border py-1\">\n {group.segments\n .slice()\n .sort((a, b) => b.tokenCount - a.tokenCount)\n .map((segment) => (\n <ContextSegmentRow\n key={segment.segmentId}\n segment={segment}\n advisory={!manifest.enforceable}\n onPin={() => onPin(segment.segmentId)}\n onEvict={() => onEvict(segment.segmentId)}\n onRestore={() => onRestore(segment.segmentId)}\n />\n ))}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"file":"ContextXRayPanel.js","sourceRoot":"","sources":["../../../src/client/context-xray/ContextXRayPanel.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n IconChartTreemap,\n IconChevronDown,\n IconChevronRight,\n IconListDetails,\n} from \"@tabler/icons-react\";\nimport { useMemo, useState } from \"react\";\nimport type {\n ContextManifest,\n ContextManifestSegment,\n ContextSegmentStatus,\n} from \"../../shared/context-xray.js\";\nimport {\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from \"../components/ui/tooltip.js\";\nimport { cn } from \"../utils.js\";\nimport { ContextSegmentRow } from \"./ContextSegmentRow.js\";\nimport { ContextTreemap } from \"./ContextTreemap.js\";\nimport {\n CONTEXT_XRAY_MODEL_LIMIT,\n formatTokens,\n groupColor,\n} from \"./format.js\";\n\ninterface Group {\n name: string;\n tokens: number;\n segments: ContextManifestSegment[];\n}\n\nfunction applyOptimisticStatus(\n segments: ContextManifestSegment[],\n optimistic: Map<string, ContextSegmentStatus>,\n): ContextManifestSegment[] {\n if (optimistic.size === 0) return segments;\n return segments.map((segment) => {\n const status = optimistic.get(segment.segmentId);\n return status ? { ...segment, status } : segment;\n });\n}\n\nfunction groupedSegments(segments: ContextManifestSegment[]): Group[] {\n const map = new Map<string, Group>();\n for (const segment of segments) {\n const groupName =\n segment.status === \"pinned\"\n ? \"Pinned\"\n : segment.status === \"evicted\"\n ? \"Evicted\"\n : segment.group;\n const group = map.get(groupName) ?? {\n name: groupName,\n tokens: 0,\n segments: [],\n };\n group.tokens += segment.tokenCount;\n group.segments.push(segment);\n map.set(groupName, group);\n }\n const order = [\n \"Pinned\",\n \"Tool results\",\n \"Files read\",\n \"Conversation\",\n \"Thinking\",\n \"Evicted\",\n ];\n return [...map.values()].sort((a, b) => {\n const ai = order.indexOf(a.name);\n const bi = order.indexOf(b.name);\n if (ai >= 0 || bi >= 0) return (ai < 0 ? 99 : ai) - (bi < 0 ? 99 : bi);\n return b.tokens - a.tokens;\n });\n}\n\nexport function ContextXRayPanel({\n manifest,\n optimistic,\n onPin,\n onEvict,\n onRestore,\n}: {\n manifest: ContextManifest;\n optimistic: Map<string, ContextSegmentStatus>;\n onPin: (segmentId: string) => void;\n onEvict: (segmentId: string) => void;\n onRestore: (segmentId: string) => void;\n}) {\n const [mode, setMode] = useState<\"list\" | \"map\">(\"list\");\n const [collapsed, setCollapsed] = useState<Set<string>>(new Set());\n const segments = useMemo(\n () => applyOptimisticStatus(manifest.segments, optimistic),\n [manifest.segments, optimistic],\n );\n const groups = useMemo(() => groupedSegments(segments), [segments]);\n const pct = Math.min(\n 100,\n Math.round((manifest.totalTokens / CONTEXT_XRAY_MODEL_LIMIT) * 100),\n );\n const headroom = Math.max(0, CONTEXT_XRAY_MODEL_LIMIT - manifest.totalTokens);\n const pinned = segments.filter((s) => s.status === \"pinned\").length;\n const evicted = segments.filter((s) => s.status === \"evicted\").length;\n const details = [\n `${formatTokens(headroom)} free`,\n pinned > 0 ? `${pinned} pinned` : null,\n evicted > 0 ? `${evicted} evicted` : null,\n manifest.tokenCountMethod === \"estimate\" ? \"estimated\" : null,\n !manifest.enforceable ? \"advisory\" : null,\n ].filter((item): item is string => Boolean(item));\n\n return (\n <div className=\"flex max-h-[min(72vh,520px)] flex-col\">\n <div className=\"border-b border-border/60 px-3 py-2.5\">\n <div className=\"flex items-center justify-between gap-3\">\n <h2 className=\"min-w-0 truncate text-sm font-medium text-foreground\">\n Context X-Ray\n </h2>\n <div className=\"shrink-0 text-xs tabular-nums text-muted-foreground\">\n {formatTokens(manifest.totalTokens)} · {pct}%\n </div>\n </div>\n <div className=\"mt-2 h-1 overflow-hidden rounded-full bg-muted/70\">\n <div\n className=\"h-full rounded-full bg-foreground transition-[width] duration-200\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <div className=\"mt-1.5 flex flex-wrap items-center gap-x-2 gap-y-1 text-[11px] text-muted-foreground\">\n {details.map((detail) => (\n <span key={detail}>{detail}</span>\n ))}\n {manifest.reclaimedTokens > 0 && (\n <span className=\"font-medium text-emerald-600 dark:text-emerald-400\">\n -{formatTokens(manifest.reclaimedTokens)}\n </span>\n )}\n </div>\n </div>\n\n <div className=\"overflow-y-auto px-2 py-2\">\n <div className=\"mb-1 flex items-center justify-end\">\n <div className=\"inline-flex rounded-md bg-muted/40 p-0.5\">\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setMode(\"list\")}\n aria-label=\"Show context list\"\n className={cn(\n \"flex size-7 items-center justify-center rounded text-muted-foreground\",\n mode === \"list\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"hover:text-foreground\",\n )}\n >\n <IconListDetails className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>List</TooltipContent>\n </Tooltip>\n <Tooltip>\n <TooltipTrigger asChild>\n <button\n type=\"button\"\n onClick={() => setMode(\"map\")}\n aria-label=\"Show context map\"\n className={cn(\n \"flex size-7 items-center justify-center rounded text-muted-foreground\",\n mode === \"map\"\n ? \"bg-background text-foreground shadow-sm\"\n : \"hover:text-foreground\",\n )}\n >\n <IconChartTreemap className=\"h-3.5 w-3.5\" />\n </button>\n </TooltipTrigger>\n <TooltipContent>Map</TooltipContent>\n </Tooltip>\n </div>\n </div>\n\n {mode === \"map\" ? (\n <ContextTreemap\n segments={segments}\n onSelect={(segmentId) => {\n const segment = segments.find((s) => s.segmentId === segmentId);\n if (segment) setCollapsed(new Set());\n }}\n />\n ) : (\n <div className=\"divide-y divide-border/60\">\n {groups.map((group) => {\n const isCollapsed = collapsed.has(group.name);\n return (\n <div key={group.name}>\n <button\n type=\"button\"\n onClick={() => {\n setCollapsed((prev) => {\n const next = new Set(prev);\n if (next.has(group.name)) next.delete(group.name);\n else next.add(group.name);\n return next;\n });\n }}\n className=\"flex w-full items-center gap-2 rounded-sm px-1.5 py-2 text-left hover:bg-accent/35\"\n >\n {isCollapsed ? (\n <IconChevronRight className=\"h-3.5 w-3.5 text-muted-foreground\" />\n ) : (\n <IconChevronDown className=\"h-3.5 w-3.5 text-muted-foreground\" />\n )}\n <span\n className={cn(\n \"h-2 w-2 rounded-full\",\n groupColor(group.name),\n )}\n />\n <span className=\"min-w-0 flex-1 truncate text-xs font-medium\">\n {group.name}\n </span>\n <span className=\"text-[11px] text-muted-foreground\">\n {formatTokens(group.tokens)}\n </span>\n </button>\n {!isCollapsed && (\n <div className=\"pb-1\">\n {group.segments\n .slice()\n .sort((a, b) => b.tokenCount - a.tokenCount)\n .map((segment) => (\n <ContextSegmentRow\n key={segment.segmentId}\n segment={segment}\n advisory={!manifest.enforceable}\n onPin={() => onPin(segment.segmentId)}\n onEvict={() => onEvict(segment.segmentId)}\n onRestore={() => onRestore(segment.segmentId)}\n />\n ))}\n </div>\n )}\n </div>\n );\n })}\n </div>\n )}\n </div>\n </div>\n );\n}\n"]}
@@ -140,7 +140,7 @@ Follow the create-skill pattern to build this. Before writing:
140
140
 
141
141
  1. **Determine the skill name** — derive a hyphen-case name from the description (e.g. "code review" → "code-review")
142
142
  2. **Determine the skill type** — Pattern (architectural rule), Workflow (step-by-step), or Generator (scaffolding)
143
- 3. **Write the skill** as a ${scope} resource at path "skills/<name>/SKILL.md" using resource-write
143
+ 3. **Write the skill** as a ${scope} resource at path "skills/<name>/SKILL.md" using the \`resources\` tool with \`action: "write"\`
144
144
 
145
145
  The skill file MUST have YAML frontmatter with name and description (under 40 words), then markdown with:
146
146
  - Clear rule/purpose statement
@@ -261,7 +261,7 @@ The job will run automatically on the schedule. Make the instructions specific
261
261
  newTab: true,
262
262
  context: `The user wants a reusable custom sub-agent profile for the workspace. Their description: "${trimmed}"
263
263
 
264
- Create it as a ${scope} resource under "agents/<name>.md" using resource-write.
264
+ Create it as a ${scope} resource under "agents/<name>.md" using the \`resources\` tool with \`action: "write"\`.
265
265
 
266
266
  Requirements:
267
267
  1. Derive a hyphen-case file name from the intent