@agent-native/core 0.44.0 → 0.44.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  2. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  3. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  4. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  5. package/dist/cli/recap.d.ts +23 -0
  6. package/dist/cli/recap.d.ts.map +1 -1
  7. package/dist/cli/recap.js +175 -0
  8. package/dist/cli/recap.js.map +1 -1
  9. package/dist/cli/skills.d.ts +3 -3
  10. package/dist/cli/skills.d.ts.map +1 -1
  11. package/dist/cli/skills.js +54 -7
  12. package/dist/cli/skills.js.map +1 -1
  13. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  14. package/dist/client/blocks/library/AnnotatedCodeBlock.js +21 -8
  15. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  16. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  17. package/dist/client/blocks/library/ApiEndpointBlock.js +112 -12
  18. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  19. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  20. package/dist/client/blocks/library/DiffBlock.js +59 -75
  21. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  22. package/dist/client/blocks/library/JsonExplorerBlock.d.ts.map +1 -1
  23. package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
  24. package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
  25. package/dist/client/blocks/library/MermaidBlock.d.ts.map +1 -1
  26. package/dist/client/blocks/library/MermaidBlock.js +22 -3
  27. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  28. package/dist/client/blocks/library/annotation-rail.d.ts +85 -0
  29. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -1
  30. package/dist/client/blocks/library/annotation-rail.js +149 -8
  31. package/dist/client/blocks/library/annotation-rail.js.map +1 -1
  32. package/dist/client/blocks/library/diagram.d.ts +17 -0
  33. package/dist/client/blocks/library/diagram.d.ts.map +1 -1
  34. package/dist/client/blocks/library/diagram.js +47 -2
  35. package/dist/client/blocks/library/diagram.js.map +1 -1
  36. package/dist/client/composer/TiptapComposer.d.ts.map +1 -1
  37. package/dist/client/composer/TiptapComposer.js +13 -8
  38. package/dist/client/composer/TiptapComposer.js.map +1 -1
  39. package/dist/client/composer/pasted-text.d.ts +25 -0
  40. package/dist/client/composer/pasted-text.d.ts.map +1 -1
  41. package/dist/client/composer/pasted-text.js +86 -4
  42. package/dist/client/composer/pasted-text.js.map +1 -1
  43. package/dist/db/migrations.d.ts +10 -0
  44. package/dist/db/migrations.d.ts.map +1 -1
  45. package/dist/db/migrations.js +32 -0
  46. package/dist/db/migrations.js.map +1 -1
  47. package/dist/server/og-fonts-data.d.ts +3 -0
  48. package/dist/server/og-fonts-data.d.ts.map +1 -0
  49. package/dist/server/og-fonts-data.js +9 -0
  50. package/dist/server/og-fonts-data.js.map +1 -0
  51. package/dist/server/og-fonts.d.ts +10 -0
  52. package/dist/server/og-fonts.d.ts.map +1 -0
  53. package/dist/server/og-fonts.js +58 -0
  54. package/dist/server/og-fonts.js.map +1 -0
  55. package/dist/server/social-og-image.d.ts.map +1 -1
  56. package/dist/server/social-og-image.js +16 -5
  57. package/dist/server/social-og-image.js.map +1 -1
  58. package/dist/styles/blocks.css +111 -0
  59. package/dist/usage/store.d.ts +12 -0
  60. package/dist/usage/store.d.ts.map +1 -1
  61. package/dist/usage/store.js +35 -5
  62. package/dist/usage/store.js.map +1 -1
  63. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AnnotatedCodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/AnnotatedCodeBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAcpC;;;;;;;;;;;;;;;;;;GAkBG;AAIH,iBAAS,iBAAiB,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,iBAAiB,CAAC,2CAiInC;AAOD,iBAAS,iBAAiB,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,iBAAiB,CAAC,2CAiJnC;AAED,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC"}
1
+ {"version":3,"file":"AnnotatedCodeBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/AnnotatedCodeBlock.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAEV,iBAAiB,EAClB,MAAM,4BAA4B,CAAC;AAkBpC;;;;;;;;;;;;;;;;;;GAkBG;AAIH,iBAAS,iBAAiB,CAAC,EACzB,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,iBAAiB,CAAC,2CAqJnC;AAOD,iBAAS,iBAAiB,CAAC,EACzB,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,iBAAiB,CAAC,2CAiJnC;AAED,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,CAAC"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useMemo, useState } from "react";
2
+ import { useMemo, useRef } from "react";
3
3
  import { IconCode, IconPlus, IconTrash } from "@tabler/icons-react";
4
4
  import { cn } from "../../utils.js";
5
5
  import { highlightCode, inferLanguageFromFilename, normalizeCodeLanguage, } from "./code-highlight.js";
6
- import { AnnotationNoteRail, buildLineMarkerMap, hasRailAnnotations, resolveAnnotations, } from "./annotation-rail.js";
6
+ import { AnnotationHiddenStack, AnnotationHoverCard, anchorFromElements, buildLineMarkerMap, hasRailAnnotations, resolveAnnotations, useAnnotationHover, } from "./annotation-rail.js";
7
7
  import { DevInput, DevLabel, DevTextarea } from "./dev-doc-ui.js";
8
8
  /**
9
9
  * "Explain this code" walkthrough block: a standard syntax-highlighted code
@@ -26,7 +26,12 @@ import { DevInput, DevLabel, DevTextarea } from "./dev-doc-ui.js";
26
26
  */
27
27
  /* ── Read ──────────────────────────────────────────────────────────────────── */
28
28
  function AnnotatedCodeRead({ data, blockId, title, summary, ctx, }) {
29
- const [activeIndex, setActiveIndex] = useState(null);
29
+ // On-hover popover (anchored to the right of the code) replaces the old
30
+ // persistent rail: nothing is visible when idle. `codeRef` measures the code
31
+ // block's right edge; `hover` carries the active index + captured geometry.
32
+ const hover = useAnnotationHover();
33
+ const { activeIndex } = hover;
34
+ const codeRef = useRef(null);
30
35
  const lines = useMemo(() => data.code.replace(/\n$/, "").split("\n"), [data.code]);
31
36
  const lineCount = lines.length;
32
37
  const language = useMemo(() => normalizeCodeLanguage(data.language) ??
@@ -38,25 +43,33 @@ function AnnotatedCodeRead({ data, blockId, title, summary, ctx, }) {
38
43
  const lineMarkers = useMemo(() => buildLineMarkerMap(resolved), [resolved]);
39
44
  const hasAnnotations = hasRailAnnotations(resolved);
40
45
  const langChip = data.language?.trim();
41
- const codeSurface = (_jsxs("div", { className: "overflow-hidden rounded-xl border border-plan-line bg-plan-code", children: [(data.filename || langChip) && (_jsxs("div", { className: "flex items-center gap-2 border-b border-plan-line bg-plan-block/50 px-3.5 py-2", children: [_jsx(IconCode, { className: "size-3.5 shrink-0 text-plan-muted" }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-[13px] font-medium text-plan-code-text", children: data.filename || "snippet" }), langChip && (_jsx("span", { className: "shrink-0 rounded border border-plan-line px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wide text-plan-muted", children: langChip }))] })), _jsx("div", { className: "overflow-x-auto py-1.5", children: _jsx("div", { className: "min-w-full font-mono [font-size:var(--plan-code-size)] leading-[22px]", children: lines.map((_text, idx) => {
46
+ // The resolved annotation whose card is currently shown on hover.
47
+ const activeItem = useMemo(() => activeIndex == null
48
+ ? null
49
+ : (resolved.find((item) => item.index === activeIndex) ?? null), [activeIndex, resolved]);
50
+ const codeSurface = (_jsxs("div", { ref: codeRef, className: "overflow-hidden rounded-xl border border-plan-line bg-plan-code", children: [(data.filename || langChip) && (_jsxs("div", { className: "flex items-center gap-2 border-b border-plan-line bg-plan-block/50 px-3.5 py-2", children: [_jsx(IconCode, { className: "size-3.5 shrink-0 text-plan-muted" }), _jsx("span", { className: "min-w-0 flex-1 truncate font-mono text-[13px] font-medium text-plan-code-text", children: data.filename || "snippet" }), langChip && (_jsx("span", { className: "shrink-0 rounded border border-plan-line px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wide text-plan-muted", children: langChip }))] })), _jsx("div", { className: "overflow-x-auto py-1.5", "data-code-surface": true, children: _jsx("div", { className: "min-w-full font-mono [font-size:var(--plan-doc-code-size)] leading-[22px]", children: lines.map((_text, idx) => {
42
51
  const lineNo = idx + 1;
43
52
  const markers = lineMarkers.get(lineNo);
44
53
  const isAnnotated = !!markers?.length;
45
54
  const isActive = activeIndex != null &&
46
55
  !!markers?.some((m) => m.index === activeIndex);
47
- return (_jsxs("div", { className: cn("flex w-full", isActive
56
+ return (_jsxs("div", { "data-annot-row": isAnnotated ? markers?.[0].index : undefined, className: cn("flex w-full", isActive
48
57
  ? "bg-amber-400/20 dark:bg-amber-300/15"
49
58
  : isAnnotated
50
59
  ? "bg-amber-400/[0.07] dark:bg-amber-300/[0.07]"
51
60
  : null), onMouseEnter: isAnnotated && markers
52
- ? () => setActiveIndex(markers[0].index)
53
- : undefined, onMouseLeave: isAnnotated ? () => setActiveIndex(null) : undefined, children: [_jsx("span", { "aria-hidden": true, className: cn("w-[3px] shrink-0 self-stretch", isAnnotated
61
+ ? (event) => {
62
+ const anchor = anchorFromElements(codeRef.current, event.currentTarget);
63
+ if (anchor)
64
+ hover.open(markers[0].index, anchor);
65
+ }
66
+ : undefined, onMouseLeave: isAnnotated ? () => hover.scheduleClose() : undefined, children: [_jsx("span", { "aria-hidden": true, className: cn("w-[3px] shrink-0 self-stretch", isAnnotated
54
67
  ? isActive
55
68
  ? "bg-amber-500 dark:bg-amber-400"
56
69
  : "bg-amber-400/45 dark:bg-amber-300/35"
57
70
  : null) }), _jsx("span", { className: "w-11 shrink-0 select-none px-3 text-right text-[11px] tabular-nums text-plan-muted/60", children: lineNo }), _jsx("span", { className: "flex-1 whitespace-pre pr-4 text-plan-code-text", children: highlightedLines[idx] })] }, lineNo));
58
71
  }) }) })] }));
59
- return (_jsxs("section", { className: "plan-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), hasAnnotations ? (_jsx("div", { className: "@container/code", children: _jsxs("div", { className: "grid items-start gap-3 @xl/code:grid-cols-[minmax(0,1fr)_minmax(190px,250px)]", children: [codeSurface, _jsx(AnnotationNoteRail, { items: resolved, activeIndex: activeIndex, onActiveChange: setActiveIndex, ctx: ctx })] }) })) : (codeSurface), summary && _jsx("p", { className: "mt-5 text-plan-muted", children: summary })] }));
72
+ return (_jsxs("section", { className: "plan-block relative", "data-block-id": blockId, children: [title && _jsx("div", { className: "plan-block-label", children: title }), codeSurface, hasAnnotations && _jsx(AnnotationHiddenStack, { items: resolved, ctx: ctx }), hasAnnotations && activeItem && hover.anchor && (_jsx(AnnotationHoverCard, { item: activeItem, anchor: hover.anchor, ctx: ctx, onMouseEnter: hover.cancelClose, onMouseLeave: hover.scheduleClose })), summary && _jsx("p", { className: "mt-5 text-plan-muted", children: summary })] }));
60
73
  }
61
74
  /* ── Edit (panel) ──────────────────────────────────────────────────────────── */
62
75
  const codeAreaClass = "min-h-[160px] font-mono [font-size:var(--plan-code-size)] leading-5";
@@ -1 +1 @@
1
- {"version":3,"file":"AnnotatedCodeBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/AnnotatedCodeBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useState } from \"react\";\nimport { IconCode, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type {\n AnnotatedCodeAnnotation,\n AnnotatedCodeData,\n} from \"./annotated-code.config.js\";\nimport {\n highlightCode,\n inferLanguageFromFilename,\n normalizeCodeLanguage,\n} from \"./code-highlight.js\";\nimport {\n AnnotationNoteRail,\n buildLineMarkerMap,\n hasRailAnnotations,\n resolveAnnotations,\n} from \"./annotation-rail.js\";\nimport { DevInput, DevLabel, DevTextarea } from \"./dev-doc-ui.js\";\n\n/**\n * \"Explain this code\" walkthrough block: a standard syntax-highlighted code\n * surface on the left with line-anchored annotation cards on the right (the\n * Stripe-docs / Sourcegraph layout). Each annotated line range gets a subtle\n * highlight band + an accent rail down the gutter; its card shows the `lines`\n * range, optional `label`, and the always-visible markdown `note` (via\n * `ctx.renderMarkdown`). Hovering a card highlights its lines and vice-versa.\n *\n * Syntax highlighting reuses the shared `highlightCode` lowlight helper (the same\n * colorful palette as the `code-tabs` block) per line, so it matches the app's\n * standard code styling and supports per-line bands without an async loader. The\n * surface uses the plan `--plan-code*`/`--plan-*` tokens and Tailwind `dark:`\n * pairs, so it reads correctly in BOTH light and dark mode. Code lines render as\n * `<span>`s (never one `<pre>` per line) so they don't pick up document\n * code/pre chrome. Lives in core so any app can register the dev-doc block.\n *\n * Editing is panel-driven (config-style, like the diff/HTML blocks): a monospace\n * code Textarea, filename/language Inputs, and add/remove-able annotation rows.\n */\n\n/* ── Read ──────────────────────────────────────────────────────────────────── */\n\nfunction AnnotatedCodeRead({\n data,\n blockId,\n title,\n summary,\n ctx,\n}: BlockReadProps<AnnotatedCodeData>) {\n const [activeIndex, setActiveIndex] = useState<number | null>(null);\n\n const lines = useMemo(\n () => data.code.replace(/\\n$/, \"\").split(\"\\n\"),\n [data.code],\n );\n const lineCount = lines.length;\n\n const language = useMemo(\n () =>\n normalizeCodeLanguage(data.language) ??\n inferLanguageFromFilename(data.filename),\n [data.language, data.filename],\n );\n\n // Highlight each line once; empty lines keep their height with a NBSP.\n const highlightedLines = useMemo(\n () =>\n lines.map((text) => (text.length ? highlightCode(text, language) : \" \")),\n [lines, language],\n );\n\n const resolved = useMemo(\n () => resolveAnnotations(data.annotations, () => lineCount),\n [data.annotations, lineCount],\n );\n\n // line number (1-based) → resolved annotations covering it.\n const lineMarkers = useMemo(() => buildLineMarkerMap(resolved), [resolved]);\n\n const hasAnnotations = hasRailAnnotations(resolved);\n const langChip = data.language?.trim();\n\n const codeSurface = (\n <div className=\"overflow-hidden rounded-xl border border-plan-line bg-plan-code\">\n {(data.filename || langChip) && (\n <div className=\"flex items-center gap-2 border-b border-plan-line bg-plan-block/50 px-3.5 py-2\">\n <IconCode className=\"size-3.5 shrink-0 text-plan-muted\" />\n <span className=\"min-w-0 flex-1 truncate font-mono text-[13px] font-medium text-plan-code-text\">\n {data.filename || \"snippet\"}\n </span>\n {langChip && (\n <span className=\"shrink-0 rounded border border-plan-line px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wide text-plan-muted\">\n {langChip}\n </span>\n )}\n </div>\n )}\n <div className=\"overflow-x-auto py-1.5\">\n <div className=\"min-w-full font-mono [font-size:var(--plan-code-size)] leading-[22px]\">\n {lines.map((_text, idx) => {\n const lineNo = idx + 1;\n const markers = lineMarkers.get(lineNo);\n const isAnnotated = !!markers?.length;\n const isActive =\n activeIndex != null &&\n !!markers?.some((m) => m.index === activeIndex);\n return (\n <div\n key={lineNo}\n className={cn(\n \"flex w-full\",\n isActive\n ? \"bg-amber-400/20 dark:bg-amber-300/15\"\n : isAnnotated\n ? \"bg-amber-400/[0.07] dark:bg-amber-300/[0.07]\"\n : null,\n )}\n onMouseEnter={\n isAnnotated && markers\n ? () => setActiveIndex(markers[0].index)\n : undefined\n }\n onMouseLeave={\n isAnnotated ? () => setActiveIndex(null) : undefined\n }\n >\n {/* Accent rail: amber on annotated lines, brighter when active. */}\n <span\n aria-hidden\n className={cn(\n \"w-[3px] shrink-0 self-stretch\",\n isAnnotated\n ? isActive\n ? \"bg-amber-500 dark:bg-amber-400\"\n : \"bg-amber-400/45 dark:bg-amber-300/35\"\n : null,\n )}\n />\n <span className=\"w-11 shrink-0 select-none px-3 text-right text-[11px] tabular-nums text-plan-muted/60\">\n {lineNo}\n </span>\n <span className=\"flex-1 whitespace-pre pr-4 text-plan-code-text\">\n {highlightedLines[idx]}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n {hasAnnotations ? (\n // The side rail stays for annotated-code, but responds to the block's\n // OWN width via a container query: side-by-side when there's room,\n // stacked below the code (single-column grid) when the container is\n // narrow — e.g. nested inside a vertical-tabs content column.\n <div className=\"@container/code\">\n <div className=\"grid items-start gap-3 @xl/code:grid-cols-[minmax(0,1fr)_minmax(190px,250px)]\">\n {codeSurface}\n <AnnotationNoteRail\n items={resolved}\n activeIndex={activeIndex}\n onActiveChange={setActiveIndex}\n ctx={ctx}\n />\n </div>\n </div>\n ) : (\n codeSurface\n )}\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/* ── Edit (panel) ──────────────────────────────────────────────────────────── */\n\nconst codeAreaClass =\n \"min-h-[160px] font-mono [font-size:var(--plan-code-size)] leading-5\";\n\nfunction AnnotatedCodeEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<AnnotatedCodeData>) {\n const annotations = data.annotations ?? [];\n const patch = (next: Partial<AnnotatedCodeData>) =>\n onChange({ ...data, ...next });\n\n const updateAnnotation = (\n index: number,\n next: Partial<AnnotatedCodeAnnotation>,\n ) =>\n patch({\n annotations: annotations.map((annotation, i) =>\n i === index ? { ...annotation, ...next } : annotation,\n ),\n });\n\n const removeAnnotation = (index: number) =>\n patch({ annotations: annotations.filter((_, i) => i !== index) });\n\n const addAnnotation = () => {\n if (annotations.length >= 80) return; // schema max\n patch({\n annotations: [...annotations, { lines: \"1\", label: \"\", note: \"\" }],\n });\n };\n\n return (\n <div className=\"flex flex-col gap-3\" data-plan-interactive>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-filename\" className=\"text-xs\">\n Filename\n </DevLabel>\n <DevInput\n id=\"annotated-code-filename\"\n value={data.filename ?? \"\"}\n placeholder=\"src/server/auth.ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ filename: event.target.value || undefined })\n }\n />\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-language\" className=\"text-xs\">\n Language\n </DevLabel>\n <DevInput\n id=\"annotated-code-language\"\n value={data.language ?? \"\"}\n placeholder=\"ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ language: event.target.value || undefined })\n }\n />\n </div>\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-code\" className=\"text-xs\">\n Code\n </DevLabel>\n <DevTextarea\n id=\"annotated-code-code\"\n spellCheck={false}\n className={codeAreaClass}\n value={data.code}\n disabled={!editable}\n onChange={(event) => patch({ code: event.target.value })}\n />\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center justify-between\">\n <DevLabel className=\"text-xs\">Annotations</DevLabel>\n {editable && annotations.length < 80 && (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={addAnnotation}\n className=\"flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-plan-muted transition-colors hover:bg-plan-block/60 hover:text-plan-text\"\n >\n <IconPlus className=\"size-3.5\" />\n Add annotation\n </button>\n )}\n </div>\n {annotations.length === 0 && (\n <p className=\"text-xs text-plan-muted\">\n No annotations yet. Add one to anchor a note to a line range.\n </p>\n )}\n {annotations.map((annotation, index) => (\n <div\n key={index}\n className=\"flex flex-col gap-2 rounded-md border border-plan-line bg-plan-block/30 p-2\"\n >\n <div className=\"grid gap-2 sm:grid-cols-[120px_minmax(0,1fr)_auto]\">\n <DevInput\n aria-label={`Annotation ${index + 1} lines`}\n value={annotation.lines}\n placeholder=\"3-5\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, { lines: event.target.value })\n }\n />\n <DevInput\n aria-label={`Annotation ${index + 1} label`}\n value={annotation.label ?? \"\"}\n placeholder=\"Label (optional)\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, {\n label: event.target.value || undefined,\n })\n }\n />\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove annotation ${index + 1}`}\n onClick={() => removeAnnotation(index)}\n className=\"flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-md text-plan-muted transition-colors hover:bg-muted hover:text-foreground\"\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <DevTextarea\n aria-label={`Annotation ${index + 1} note`}\n className=\"min-h-[60px] text-sm\"\n value={annotation.note}\n placeholder=\"Explain what these lines do…\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, { note: event.target.value })\n }\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport { AnnotatedCodeRead, AnnotatedCodeEdit };\n"]}
1
+ {"version":3,"file":"AnnotatedCodeBlock.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/AnnotatedCodeBlock.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, useRef } from \"react\";\nimport { IconCode, IconPlus, IconTrash } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockEditProps, BlockReadProps } from \"../types.js\";\nimport type {\n AnnotatedCodeAnnotation,\n AnnotatedCodeData,\n} from \"./annotated-code.config.js\";\nimport {\n highlightCode,\n inferLanguageFromFilename,\n normalizeCodeLanguage,\n} from \"./code-highlight.js\";\nimport {\n AnnotationHiddenStack,\n AnnotationHoverCard,\n anchorFromElements,\n buildLineMarkerMap,\n hasRailAnnotations,\n resolveAnnotations,\n useAnnotationHover,\n type ResolvedAnnotation,\n} from \"./annotation-rail.js\";\nimport { DevInput, DevLabel, DevTextarea } from \"./dev-doc-ui.js\";\n\n/**\n * \"Explain this code\" walkthrough block: a standard syntax-highlighted code\n * surface on the left with line-anchored annotation cards on the right (the\n * Stripe-docs / Sourcegraph layout). Each annotated line range gets a subtle\n * highlight band + an accent rail down the gutter; its card shows the `lines`\n * range, optional `label`, and the always-visible markdown `note` (via\n * `ctx.renderMarkdown`). Hovering a card highlights its lines and vice-versa.\n *\n * Syntax highlighting reuses the shared `highlightCode` lowlight helper (the same\n * colorful palette as the `code-tabs` block) per line, so it matches the app's\n * standard code styling and supports per-line bands without an async loader. The\n * surface uses the plan `--plan-code*`/`--plan-*` tokens and Tailwind `dark:`\n * pairs, so it reads correctly in BOTH light and dark mode. Code lines render as\n * `<span>`s (never one `<pre>` per line) so they don't pick up document\n * code/pre chrome. Lives in core so any app can register the dev-doc block.\n *\n * Editing is panel-driven (config-style, like the diff/HTML blocks): a monospace\n * code Textarea, filename/language Inputs, and add/remove-able annotation rows.\n */\n\n/* ── Read ──────────────────────────────────────────────────────────────────── */\n\nfunction AnnotatedCodeRead({\n data,\n blockId,\n title,\n summary,\n ctx,\n}: BlockReadProps<AnnotatedCodeData>) {\n // On-hover popover (anchored to the right of the code) replaces the old\n // persistent rail: nothing is visible when idle. `codeRef` measures the code\n // block's right edge; `hover` carries the active index + captured geometry.\n const hover = useAnnotationHover();\n const { activeIndex } = hover;\n const codeRef = useRef<HTMLDivElement | null>(null);\n\n const lines = useMemo(\n () => data.code.replace(/\\n$/, \"\").split(\"\\n\"),\n [data.code],\n );\n const lineCount = lines.length;\n\n const language = useMemo(\n () =>\n normalizeCodeLanguage(data.language) ??\n inferLanguageFromFilename(data.filename),\n [data.language, data.filename],\n );\n\n // Highlight each line once; empty lines keep their height with a NBSP.\n const highlightedLines = useMemo(\n () =>\n lines.map((text) => (text.length ? highlightCode(text, language) : \" \")),\n [lines, language],\n );\n\n const resolved = useMemo(\n () => resolveAnnotations(data.annotations, () => lineCount),\n [data.annotations, lineCount],\n );\n\n // line number (1-based) → resolved annotations covering it.\n const lineMarkers = useMemo(() => buildLineMarkerMap(resolved), [resolved]);\n\n const hasAnnotations = hasRailAnnotations(resolved);\n const langChip = data.language?.trim();\n\n // The resolved annotation whose card is currently shown on hover.\n const activeItem =\n useMemo<ResolvedAnnotation<AnnotatedCodeAnnotation> | null>(\n () =>\n activeIndex == null\n ? null\n : (resolved.find((item) => item.index === activeIndex) ?? null),\n [activeIndex, resolved],\n );\n\n const codeSurface = (\n <div\n ref={codeRef}\n className=\"overflow-hidden rounded-xl border border-plan-line bg-plan-code\"\n >\n {(data.filename || langChip) && (\n <div className=\"flex items-center gap-2 border-b border-plan-line bg-plan-block/50 px-3.5 py-2\">\n <IconCode className=\"size-3.5 shrink-0 text-plan-muted\" />\n <span className=\"min-w-0 flex-1 truncate font-mono text-[13px] font-medium text-plan-code-text\">\n {data.filename || \"snippet\"}\n </span>\n {langChip && (\n <span className=\"shrink-0 rounded border border-plan-line px-1.5 py-0.5 font-mono text-[10px] uppercase tracking-wide text-plan-muted\">\n {langChip}\n </span>\n )}\n </div>\n )}\n <div className=\"overflow-x-auto py-1.5\" data-code-surface>\n <div className=\"min-w-full font-mono [font-size:var(--plan-doc-code-size)] leading-[22px]\">\n {lines.map((_text, idx) => {\n const lineNo = idx + 1;\n const markers = lineMarkers.get(lineNo);\n const isAnnotated = !!markers?.length;\n const isActive =\n activeIndex != null &&\n !!markers?.some((m) => m.index === activeIndex);\n return (\n <div\n key={lineNo}\n data-annot-row={isAnnotated ? markers?.[0].index : undefined}\n className={cn(\n \"flex w-full\",\n isActive\n ? \"bg-amber-400/20 dark:bg-amber-300/15\"\n : isAnnotated\n ? \"bg-amber-400/[0.07] dark:bg-amber-300/[0.07]\"\n : null,\n )}\n onMouseEnter={\n isAnnotated && markers\n ? (event) => {\n const anchor = anchorFromElements(\n codeRef.current,\n event.currentTarget,\n );\n if (anchor) hover.open(markers[0].index, anchor);\n }\n : undefined\n }\n onMouseLeave={\n isAnnotated ? () => hover.scheduleClose() : undefined\n }\n >\n {/* Accent rail: amber on annotated lines, brighter when active. */}\n <span\n aria-hidden\n className={cn(\n \"w-[3px] shrink-0 self-stretch\",\n isAnnotated\n ? isActive\n ? \"bg-amber-500 dark:bg-amber-400\"\n : \"bg-amber-400/45 dark:bg-amber-300/35\"\n : null,\n )}\n />\n <span className=\"w-11 shrink-0 select-none px-3 text-right text-[11px] tabular-nums text-plan-muted/60\">\n {lineNo}\n </span>\n <span className=\"flex-1 whitespace-pre pr-4 text-plan-code-text\">\n {highlightedLines[idx]}\n </span>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n );\n\n return (\n <section className=\"plan-block relative\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n {/* The code keeps its full width — no persistent annotation column. Notes\n live in a visually-hidden stack (a11y + tests) and surface ONE at a\n time as an on-hover popover anchored to the right of the code. */}\n {codeSurface}\n {hasAnnotations && <AnnotationHiddenStack items={resolved} ctx={ctx} />}\n {hasAnnotations && activeItem && hover.anchor && (\n <AnnotationHoverCard\n item={activeItem}\n anchor={hover.anchor}\n ctx={ctx}\n onMouseEnter={hover.cancelClose}\n onMouseLeave={hover.scheduleClose}\n />\n )}\n {summary && <p className=\"mt-5 text-plan-muted\">{summary}</p>}\n </section>\n );\n}\n\n/* ── Edit (panel) ──────────────────────────────────────────────────────────── */\n\nconst codeAreaClass =\n \"min-h-[160px] font-mono [font-size:var(--plan-code-size)] leading-5\";\n\nfunction AnnotatedCodeEdit({\n data,\n onChange,\n editable,\n}: BlockEditProps<AnnotatedCodeData>) {\n const annotations = data.annotations ?? [];\n const patch = (next: Partial<AnnotatedCodeData>) =>\n onChange({ ...data, ...next });\n\n const updateAnnotation = (\n index: number,\n next: Partial<AnnotatedCodeAnnotation>,\n ) =>\n patch({\n annotations: annotations.map((annotation, i) =>\n i === index ? { ...annotation, ...next } : annotation,\n ),\n });\n\n const removeAnnotation = (index: number) =>\n patch({ annotations: annotations.filter((_, i) => i !== index) });\n\n const addAnnotation = () => {\n if (annotations.length >= 80) return; // schema max\n patch({\n annotations: [...annotations, { lines: \"1\", label: \"\", note: \"\" }],\n });\n };\n\n return (\n <div className=\"flex flex-col gap-3\" data-plan-interactive>\n <div className=\"grid gap-3 sm:grid-cols-2\">\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-filename\" className=\"text-xs\">\n Filename\n </DevLabel>\n <DevInput\n id=\"annotated-code-filename\"\n value={data.filename ?? \"\"}\n placeholder=\"src/server/auth.ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ filename: event.target.value || undefined })\n }\n />\n </div>\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-language\" className=\"text-xs\">\n Language\n </DevLabel>\n <DevInput\n id=\"annotated-code-language\"\n value={data.language ?? \"\"}\n placeholder=\"ts\"\n disabled={!editable}\n onChange={(event) =>\n patch({ language: event.target.value || undefined })\n }\n />\n </div>\n </div>\n\n <div className=\"flex flex-col gap-1.5\">\n <DevLabel htmlFor=\"annotated-code-code\" className=\"text-xs\">\n Code\n </DevLabel>\n <DevTextarea\n id=\"annotated-code-code\"\n spellCheck={false}\n className={codeAreaClass}\n value={data.code}\n disabled={!editable}\n onChange={(event) => patch({ code: event.target.value })}\n />\n </div>\n\n <div className=\"flex flex-col gap-2\">\n <div className=\"flex items-center justify-between\">\n <DevLabel className=\"text-xs\">Annotations</DevLabel>\n {editable && annotations.length < 80 && (\n <button\n type=\"button\"\n data-plan-interactive\n onClick={addAnnotation}\n className=\"flex cursor-pointer items-center gap-1 rounded-md px-2 py-1 text-xs font-medium text-plan-muted transition-colors hover:bg-plan-block/60 hover:text-plan-text\"\n >\n <IconPlus className=\"size-3.5\" />\n Add annotation\n </button>\n )}\n </div>\n {annotations.length === 0 && (\n <p className=\"text-xs text-plan-muted\">\n No annotations yet. Add one to anchor a note to a line range.\n </p>\n )}\n {annotations.map((annotation, index) => (\n <div\n key={index}\n className=\"flex flex-col gap-2 rounded-md border border-plan-line bg-plan-block/30 p-2\"\n >\n <div className=\"grid gap-2 sm:grid-cols-[120px_minmax(0,1fr)_auto]\">\n <DevInput\n aria-label={`Annotation ${index + 1} lines`}\n value={annotation.lines}\n placeholder=\"3-5\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, { lines: event.target.value })\n }\n />\n <DevInput\n aria-label={`Annotation ${index + 1} label`}\n value={annotation.label ?? \"\"}\n placeholder=\"Label (optional)\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, {\n label: event.target.value || undefined,\n })\n }\n />\n {editable && (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Remove annotation ${index + 1}`}\n onClick={() => removeAnnotation(index)}\n className=\"flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-md text-plan-muted transition-colors hover:bg-muted hover:text-foreground\"\n >\n <IconTrash className=\"size-4\" />\n </button>\n )}\n </div>\n <DevTextarea\n aria-label={`Annotation ${index + 1} note`}\n className=\"min-h-[60px] text-sm\"\n value={annotation.note}\n placeholder=\"Explain what these lines do…\"\n disabled={!editable}\n onChange={(event) =>\n updateAnnotation(index, { note: event.target.value })\n }\n />\n </div>\n ))}\n </div>\n </div>\n );\n}\n\nexport { AnnotatedCodeRead, AnnotatedCodeEdit };\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"ApiEndpointBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/ApiEndpointBlock.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAEV,eAAe,EAKhB,MAAM,0BAA0B,CAAC;AAsOlC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,eAAe,CAAC,2CAgSjC;AAkBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,eAAe,CAAC,2CAiXjC"}
1
+ {"version":3,"file":"ApiEndpointBlock.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/ApiEndpointBlock.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,KAAK,EAEV,eAAe,EAKhB,MAAM,0BAA0B,CAAC;AAgXlC;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,eAAe,CAAC,2CAkSjC;AAkBD;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,EAC9B,IAAI,EACJ,QAAQ,EACR,QAAQ,GACT,EAAE,cAAc,CAAC,eAAe,CAAC,2CAiXjC"}
@@ -5,7 +5,6 @@ import { cn } from "../../utils.js";
5
5
  import { API_ENDPOINT_CHANGES, API_ENDPOINT_METHODS, API_PARAM_LOCATIONS, } from "./api-endpoint.config.js";
6
6
  import { JsonExplorerSurface } from "./JsonExplorerBlock.js";
7
7
  import { DevBadge, DevInput, DevSwitch, DevTextarea, DevSelect, } from "./dev-doc-ui.js";
8
- import { CodeSurface } from "./HighlightedCode.js";
9
8
  /**
10
9
  * Read + Edit renderers for an `api-endpoint` block — a Swagger / Stripe-style
11
10
  * API reference. Lives in core so any app can register the dev-doc block (no
@@ -114,31 +113,132 @@ function wasIsRequiredFlag(was) {
114
113
  /** Guess a fence language from a content type so examples highlight nicely. */
115
114
  function fenceLangForContentType(contentType) {
116
115
  const ct = (contentType ?? "").toLowerCase();
117
- if (ct.includes("json"))
118
- return "json";
119
116
  if (ct.includes("xml") || ct.includes("html"))
120
117
  return "html";
121
118
  if (ct.includes("yaml") || ct.includes("yml"))
122
119
  return "yaml";
123
120
  return "json";
124
121
  }
125
- function shouldUseJsonExplorer(example, contentType) {
122
+ /**
123
+ * Strip JSONC niceties so an otherwise-valid-but-commented example still parses
124
+ * as JSON and earns the collapsible JsonExplorer (instead of falling back to a
125
+ * plain code block). Removes `//` line comments and `/* … *​/` block comments,
126
+ * then trailing commas before `}`/`]`. String contents are preserved: `//`
127
+ * inside a quoted string (e.g. a URL) is NOT treated as a comment.
128
+ */
129
+ function stripJsonComments(source) {
130
+ let out = "";
131
+ let inString = false;
132
+ let stringQuote = "";
133
+ let inLineComment = false;
134
+ let inBlockComment = false;
135
+ for (let i = 0; i < source.length; i += 1) {
136
+ const char = source[i];
137
+ const next = source[i + 1];
138
+ if (inLineComment) {
139
+ if (char === "\n") {
140
+ inLineComment = false;
141
+ out += char;
142
+ }
143
+ continue;
144
+ }
145
+ if (inBlockComment) {
146
+ if (char === "*" && next === "/") {
147
+ inBlockComment = false;
148
+ i += 1;
149
+ }
150
+ continue;
151
+ }
152
+ if (inString) {
153
+ out += char;
154
+ if (char === "\\") {
155
+ // Copy the escaped char verbatim so an escaped quote can't end the
156
+ // string early.
157
+ if (next !== undefined) {
158
+ out += next;
159
+ i += 1;
160
+ }
161
+ }
162
+ else if (char === stringQuote) {
163
+ inString = false;
164
+ }
165
+ continue;
166
+ }
167
+ if (char === '"' || char === "'") {
168
+ inString = true;
169
+ stringQuote = char;
170
+ out += char;
171
+ continue;
172
+ }
173
+ if (char === "/" && next === "/") {
174
+ inLineComment = true;
175
+ i += 1;
176
+ continue;
177
+ }
178
+ if (char === "/" && next === "*") {
179
+ inBlockComment = true;
180
+ i += 1;
181
+ continue;
182
+ }
183
+ // Drop a trailing comma before a closing bracket so the result is strict
184
+ // JSON. Done here (not via a post-pass regex) so it stays string-aware: we
185
+ // only reach this branch outside strings/comments, and the structural comma
186
+ // is the last non-whitespace char already emitted. A comma inside a string
187
+ // value like `"hello,}"` is followed by its closing quote, not the bracket,
188
+ // so it is never stripped.
189
+ if (char === "}" || char === "]") {
190
+ out = out.replace(/,\s*$/, "");
191
+ }
192
+ out += char;
193
+ }
194
+ return out;
195
+ }
196
+ /**
197
+ * Decide whether an example should render with the collapsible JsonExplorer.
198
+ * Returns the strict-JSON text to feed the explorer (comment-stripped when the
199
+ * raw example was JSONC), or `null` when the example is not parseable as JSON
200
+ * (e.g. an explicitly non-JSON content type, or free-form/XML/YAML text) and
201
+ * should fall back to the styled code surface.
202
+ */
203
+ function jsonExplorerSource(example, contentType) {
126
204
  const ct = (contentType ?? "").toLowerCase();
127
205
  if (contentType && !ct.includes("json"))
128
- return false;
206
+ return null;
129
207
  try {
130
208
  JSON.parse(example);
131
- return true;
209
+ return example;
132
210
  }
133
211
  catch {
134
- return false;
212
+ // Tolerate JSONC: a commented-but-otherwise-valid body still gets the nice
213
+ // explorer. Feed the explorer the stripped (strict-JSON) text so it parses.
214
+ const stripped = stripJsonComments(example);
215
+ try {
216
+ JSON.parse(stripped);
217
+ return stripped;
218
+ }
219
+ catch {
220
+ return null;
221
+ }
135
222
  }
136
223
  }
224
+ /**
225
+ * Plain (non-JSON) example fallback. Renders inside the SAME surface chrome as
226
+ * {@link JsonExplorerSurface} — one `rounded-xl border bg-plan-code` box with a
227
+ * label bar and an `overflow-auto` scroll body — so a JSONC / free-form example
228
+ * reads consistently with the JSON-explorer examples instead of as a separate,
229
+ * differently-styled code box (no extra background tint, no clipped overflow).
230
+ * Font-size is inherited from `--plan-code-size` (the same token the global code
231
+ * rule manages); we never hardcode it here.
232
+ */
233
+ function ApiCodeExample({ code, label = "JSON", className, }) {
234
+ return (_jsxs("div", { "data-code-surface": true, className: cn("overflow-hidden rounded-xl border border-plan-line bg-plan-code", className), children: [_jsx("div", { className: "flex items-center gap-2 border-b border-plan-line px-3 py-1.5", children: _jsx("span", { className: "font-mono text-xs uppercase tracking-wide text-plan-muted", children: label }) }), _jsx("pre", { className: "overflow-x-auto px-3 py-2.5 font-mono [font-size:var(--plan-doc-code-size)] leading-relaxed text-plan-code-text", children: code })] }));
235
+ }
137
236
  function ApiExample({ example, contentType, className, }) {
138
- if (shouldUseJsonExplorer(example, contentType)) {
139
- return (_jsx(JsonExplorerSurface, { data: { json: example, collapsedDepth: 2 }, className: className }));
237
+ const jsonSource = jsonExplorerSource(example, contentType);
238
+ if (jsonSource !== null) {
239
+ return (_jsx(JsonExplorerSurface, { data: { json: jsonSource, collapsedDepth: 2 }, className: className }));
140
240
  }
141
- return (_jsx(CodeSurface, { code: example, language: fenceLangForContentType(contentType), className: className }));
241
+ return (_jsx(ApiCodeExample, { code: example, label: fenceLangForContentType(contentType).toUpperCase(), className: className }));
142
242
  }
143
243
  /* ── Read (collapsed-by-default swagger row) ───────────────────────────────── */
144
244
  /**
@@ -163,7 +263,7 @@ export function ApiEndpointRead({ data, blockId, title, summary, ctx, }) {
163
263
  // `change` ink composes with `deprecated`: a deprecated route
164
264
  // still mutes/strikes its path; a changed route tints it (a
165
265
  // removed route also strikes via CHANGE_INK).
166
- data.change ? CHANGE_INK[data.change] : "text-plan-text", data.deprecated && "text-plan-muted line-through"), children: data.path }), data.change && _jsx(ChangeChip, { change: data.change, variant: "label" }), data.deprecated && (_jsx(DevBadge, { className: "shrink-0 border-amber-500/40 text-amber-600 dark:text-amber-300", children: "Deprecated" })), (data.summary || summary) && (_jsx("span", { className: "ml-1 min-w-0 flex-1 truncate text-sm text-plan-muted", children: data.summary || summary })), data.auth && (_jsx(IconLock, { className: "size-3.5 shrink-0 text-plan-muted", "aria-label": "Requires authentication" }))] }), open && hasBody && (_jsxs("div", { className: "border-t border-plan-line px-4 py-4", children: [data.auth && (_jsxs("div", { className: "mb-4 flex items-center gap-2 text-xs text-plan-muted", children: [_jsx(IconLock, { className: "size-3.5 shrink-0" }), _jsxs("span", { children: [_jsx("span", { className: "font-medium text-plan-text", children: "Auth:" }), " ", data.auth] })] })), data.description?.trim() && (_jsx("div", { className: "an-api-endpoint-desc", children: ctx.renderMarkdown?.(data.description) })), params.length > 0 && (_jsxs("div", { className: "mt-5", children: [_jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-plan-muted", children: "Parameters" }), _jsx("div", { className: "mt-2 overflow-hidden rounded-lg border border-plan-line", children: _jsxs("table", { className: "w-full border-collapse text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-accent/30 text-left text-xs uppercase tracking-wide text-plan-muted", children: [_jsx("th", { className: "px-3 py-2 font-medium", children: "Name" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "In" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Type" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Required" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Description" })] }) }), _jsx("tbody", { children: params.map((param, index) => {
266
+ data.change ? CHANGE_INK[data.change] : "text-plan-text", data.deprecated && "text-plan-muted line-through"), children: data.path }), data.change && _jsx(ChangeChip, { change: data.change, variant: "label" }), data.deprecated && (_jsx(DevBadge, { className: "shrink-0 border-amber-500/40 text-amber-600 dark:text-amber-300", children: "Deprecated" })), (data.summary || summary) && (_jsx("span", { className: "ml-1 min-w-0 flex-1 truncate text-sm text-plan-muted", children: data.summary || summary })), data.auth && (_jsx(IconLock, { className: "size-3.5 shrink-0 text-plan-muted", "aria-label": "Requires authentication" }))] }), open && hasBody && (_jsxs("div", { className: "px-4 pb-4 pt-1", children: [data.auth && (_jsxs("div", { className: "mb-4 flex items-center gap-2 text-xs text-plan-muted", children: [_jsx(IconLock, { className: "size-3.5 shrink-0" }), _jsxs("span", { children: [_jsx("span", { className: "font-medium text-plan-text", children: "Auth:" }), " ", data.auth] })] })), data.description?.trim() && (_jsx("div", { className: "an-api-endpoint-desc", children: ctx.renderMarkdown?.(data.description) })), params.length > 0 && (_jsxs("div", { className: "mt-5", children: [_jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-plan-muted", children: "Parameters" }), _jsx("div", { className: "mt-2 overflow-hidden rounded-lg border border-plan-line", children: _jsxs("table", { className: "w-full border-collapse text-sm", children: [_jsx("thead", { children: _jsxs("tr", { className: "bg-accent/30 text-left text-xs uppercase tracking-wide text-plan-muted", children: [_jsx("th", { className: "px-3 py-2 font-medium", children: "Name" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "In" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Type" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Required" }), _jsx("th", { className: "px-3 py-2 font-medium", children: "Description" })] }) }), _jsx("tbody", { children: params.map((param, index) => {
167
267
  const change = param.change;
168
268
  // A `modified` `was` describes either the required flag
169
269
  // or the prior type; route it to the right column.
@@ -182,7 +282,7 @@ export function ApiEndpointRead({ data, blockId, title, summary, ctx, }) {
182
282
  : "text-plan-text"), children: param.name }), change && _jsx(ChangeChip, { change: change })] }) }), _jsx("td", { className: "px-3 py-2", children: _jsx("span", { className: cn("rounded px-1.5 py-0.5 font-mono text-[11px] font-semibold", PARAM_IN_BADGE[param.in]), children: param.in }) }), _jsx("td", { className: "px-3 py-2 font-mono text-xs text-plan-muted", children: _jsx(WasArrowCurrent, { was: wasForType, current: _jsx("span", { className: cn(wasForType && "text-plan-text"), children: param.type || "—" }) }) }), _jsx("td", { className: "px-3 py-2 text-xs", children: _jsx(WasArrowCurrent, { was: wasForRequired, current: param.required ? (_jsx("span", { className: "font-medium text-red-600 dark:text-red-300", children: "required" })) : (_jsx("span", { className: "text-plan-muted", children: "optional" })) }) }), _jsx("td", { className: "px-3 py-2 text-xs text-plan-muted", children: param.description || "—" })] }, `${param.name}-${index}`));
183
283
  }) })] }) })] })), hasRequest && (_jsxs("div", { className: "mt-5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-semibold uppercase tracking-wide text-plan-muted", children: "Request body" }), data.request?.contentType && (_jsx("span", { className: "rounded bg-accent/40 px-1.5 py-0.5 font-mono text-[11px] text-plan-muted", children: data.request.contentType }))] }), data.request?.example && (_jsx(ApiExample, { example: data.request.example, contentType: data.request.contentType, className: "mt-2 an-api-endpoint-example" }))] })), responses.length > 0 && (_jsxs("div", { className: "mt-5", children: [_jsx("div", { className: "text-xs font-semibold uppercase tracking-wide text-plan-muted", children: "Responses" }), _jsx("div", { className: "mt-2 flex flex-col gap-3", children: responses.map((response, index) => (_jsxs("div", { className: "rounded-lg border border-plan-line", children: [_jsxs("div", { className: "flex items-center gap-2 px-3 py-2", children: [_jsx("span", { className: cn("rounded px-2 py-0.5 font-mono text-xs font-bold", statusPillClass(response.status)), children: response.status }), response.description && (_jsx("span", { className: cn("text-sm", response.change
184
284
  ? CHANGE_INK[response.change]
185
- : "text-plan-muted"), children: response.description })), response.change && (_jsx(ChangeChip, { change: response.change, variant: "label", className: "ml-auto" }))] }), response.example && (_jsx("div", { className: "border-t border-plan-line px-3 pb-3 pt-3 an-api-endpoint-example", children: _jsx(ApiExample, { example: response.example, className: "mt-0" }) }))] }, `${response.status}-${index}`))) })] }))] }))] })] }));
285
+ : "text-plan-muted"), children: response.description })), response.change && (_jsx(ChangeChip, { change: response.change, variant: "label", className: "ml-auto" }))] }), response.example && (_jsx("div", { className: "px-3 pb-3 pt-0 an-api-endpoint-example", children: _jsx(ApiExample, { example: response.example, className: "mt-0" }) }))] }, `${response.status}-${index}`))) })] }))] }))] })] }));
186
286
  }
187
287
  /* ── Edit (panel form) ─────────────────────────────────────────────────────── */
188
288
  const fieldLabelClass = "text-xs font-medium text-muted-foreground";