@agent-native/core 0.41.1 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/dist/action.d.ts +13 -1
  2. package/dist/action.d.ts.map +1 -1
  3. package/dist/action.js.map +1 -1
  4. package/dist/agent/production-agent.d.ts +8 -0
  5. package/dist/agent/production-agent.d.ts.map +1 -1
  6. package/dist/agent/production-agent.js +93 -0
  7. package/dist/agent/production-agent.js.map +1 -1
  8. package/dist/cli/app-skill.d.ts +16 -0
  9. package/dist/cli/app-skill.d.ts.map +1 -1
  10. package/dist/cli/app-skill.js +33 -3
  11. package/dist/cli/app-skill.js.map +1 -1
  12. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  13. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  14. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  15. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  16. package/dist/cli/recap.d.ts.map +1 -1
  17. package/dist/cli/recap.js +14 -3
  18. package/dist/cli/recap.js.map +1 -1
  19. package/dist/cli/skills.d.ts +34 -3
  20. package/dist/cli/skills.d.ts.map +1 -1
  21. package/dist/cli/skills.js +172 -48
  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 +2 -2
  25. package/dist/client/AssistantChat.js.map +1 -1
  26. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  27. package/dist/client/agent-chat-adapter.js +172 -5
  28. package/dist/client/agent-chat-adapter.js.map +1 -1
  29. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +19 -0
  30. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  31. package/dist/client/blocks/library/AnnotatedCodeBlock.js +5 -57
  32. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  33. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  34. package/dist/client/blocks/library/ApiEndpointBlock.js +116 -7
  35. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  36. package/dist/client/blocks/library/DataModelBlock.d.ts.map +1 -1
  37. package/dist/client/blocks/library/DataModelBlock.js +75 -9
  38. package/dist/client/blocks/library/DataModelBlock.js.map +1 -1
  39. package/dist/client/blocks/library/DiffBlock.d.ts +1 -1
  40. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  41. package/dist/client/blocks/library/DiffBlock.js +195 -34
  42. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  43. package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
  44. package/dist/client/blocks/library/HighlightedCode.js +1 -1
  45. package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
  46. package/dist/client/blocks/library/annotation-rail.d.ts +96 -0
  47. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -0
  48. package/dist/client/blocks/library/annotation-rail.js +120 -0
  49. package/dist/client/blocks/library/annotation-rail.js.map +1 -0
  50. package/dist/client/blocks/library/api-endpoint.config.d.ts +31 -6
  51. package/dist/client/blocks/library/api-endpoint.config.d.ts.map +1 -1
  52. package/dist/client/blocks/library/api-endpoint.config.js +30 -6
  53. package/dist/client/blocks/library/api-endpoint.config.js.map +1 -1
  54. package/dist/client/blocks/library/code.d.ts.map +1 -1
  55. package/dist/client/blocks/library/code.js +32 -15
  56. package/dist/client/blocks/library/code.js.map +1 -1
  57. package/dist/client/blocks/library/columns.d.ts.map +1 -1
  58. package/dist/client/blocks/library/columns.js +56 -35
  59. package/dist/client/blocks/library/columns.js.map +1 -1
  60. package/dist/client/blocks/library/data-model.config.d.ts +17 -0
  61. package/dist/client/blocks/library/data-model.config.d.ts.map +1 -1
  62. package/dist/client/blocks/library/data-model.config.js +15 -0
  63. package/dist/client/blocks/library/data-model.config.js.map +1 -1
  64. package/dist/client/blocks/library/diff.config.d.ts +28 -6
  65. package/dist/client/blocks/library/diff.config.d.ts.map +1 -1
  66. package/dist/client/blocks/library/diff.config.js +30 -6
  67. package/dist/client/blocks/library/diff.config.js.map +1 -1
  68. package/dist/client/blocks/types.d.ts +2 -2
  69. package/dist/client/blocks/types.d.ts.map +1 -1
  70. package/dist/client/blocks/types.js.map +1 -1
  71. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
  72. package/dist/client/rich-markdown-editor/DragHandle.js +75 -9
  73. package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
  74. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +25 -1
  75. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
  76. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +29 -6
  77. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  78. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
  79. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
  80. package/dist/client/rich-markdown-editor/SharedRichEditor.js +5 -1
  81. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
  82. package/dist/extensions/actions.d.ts.map +1 -1
  83. package/dist/extensions/actions.js +159 -12
  84. package/dist/extensions/actions.js.map +1 -1
  85. package/dist/extensions/store.d.ts +21 -0
  86. package/dist/extensions/store.d.ts.map +1 -1
  87. package/dist/extensions/store.js +33 -1
  88. package/dist/extensions/store.js.map +1 -1
  89. package/dist/server/recap-image-route.d.ts.map +1 -1
  90. package/dist/server/recap-image-route.js +12 -3
  91. package/dist/server/recap-image-route.js.map +1 -1
  92. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
  93. package/docs/content/plan-plugin.md +107 -0
  94. package/docs/content/skills-guide.md +8 -0
  95. package/docs/content/visual-plans.md +2 -0
  96. package/package.json +1 -1
  97. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
@@ -0,0 +1,120 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useMemo } from "react";
3
+ import { cn } from "../../utils.js";
4
+ /**
5
+ * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.
6
+ *
7
+ * Both blocks render a numbered code surface plus a side "rail" of notes, where
8
+ * each note targets a 1-based `lines` ref (`"3"` or `"3-5"`) and hovering a code
9
+ * line ↔ its note cross-highlights. This module owns the pure pieces that were
10
+ * identical between them so neither block forks the behavior:
11
+ *
12
+ * - `parseLineRange` — the forgiving 1-based `lines` range parser.
13
+ * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list
14
+ * into stable, marker-numbered, range-resolved records and a line→markers map.
15
+ * - `rangeLabel` — the human "Line 8" / "Lines 3–6" label.
16
+ * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row
17
+ * (used by the diff grid; the annotated-code surface uses its own rail bar).
18
+ * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.
19
+ * `showMarker` opts the diff block into a leading numbered pip on each card so
20
+ * a note can be matched to its `①`/`②` row marker; annotated-code omits it to
21
+ * keep its original card chrome.
22
+ *
23
+ * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a
24
+ * before/after grid (each annotation also carries a `side`). The shared types
25
+ * here are intentionally minimal — callers pass their own `side` handling and
26
+ * decide which rows a marker lands on; this module only owns the parsing, the
27
+ * resolved-record shape, and the rendered marker + rail chrome.
28
+ */
29
+ /* ── Line-ref parsing ──────────────────────────────────────────────────────── */
30
+ /**
31
+ * Parse a 1-based `lines` ref (`"3"` or `"3-5"`) into an inclusive `[start,end]`
32
+ * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully
33
+ * out-of-range refs so callers can ignore them gracefully. A reversed range
34
+ * (`"5-3"`) is normalized; a partially out-of-range range is clamped.
35
+ */
36
+ export function parseLineRange(ref, lineCount) {
37
+ const match = /^\s*(\d+)\s*(?:-\s*(\d+)\s*)?$/.exec(ref);
38
+ if (!match)
39
+ return null;
40
+ let start = Number.parseInt(match[1], 10);
41
+ let end = match[2] != null ? Number.parseInt(match[2], 10) : start;
42
+ if (!Number.isFinite(start) || !Number.isFinite(end))
43
+ return null;
44
+ if (start > end)
45
+ [start, end] = [end, start];
46
+ // Fully outside the file → ignore.
47
+ if (end < 1 || start > lineCount)
48
+ return null;
49
+ return { start: Math.max(1, start), end: Math.min(lineCount, end) };
50
+ }
51
+ /**
52
+ * Resolve a raw annotation list into stable, marker-numbered records, parsing
53
+ * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a
54
+ * per-annotation line count (before-side vs after-side); annotated-code passes a
55
+ * single constant. Markers are authoring-order, 1-based, and assigned to ALL
56
+ * annotations (even unresolved ones) so numbering is stable regardless of which
57
+ * refs happen to match.
58
+ */
59
+ export function resolveAnnotations(annotations, lineCountFor) {
60
+ return (annotations ?? []).map((annotation, index) => ({
61
+ index,
62
+ marker: index + 1,
63
+ annotation,
64
+ range: parseLineRange(annotation.lines, lineCountFor(annotation)),
65
+ }));
66
+ }
67
+ /** Map a 1-based line number → the resolved annotations covering it. */
68
+ export function buildLineMarkerMap(resolved) {
69
+ const map = new Map();
70
+ for (const item of resolved) {
71
+ if (!item.range)
72
+ continue;
73
+ for (let n = item.range.start; n <= item.range.end; n += 1) {
74
+ const list = map.get(n) ?? [];
75
+ list.push(item);
76
+ map.set(n, list);
77
+ }
78
+ }
79
+ return map;
80
+ }
81
+ /** Human label for a resolved annotation's line span ("Line 8" / "Lines 3–6"). */
82
+ export function rangeLabel(item) {
83
+ if (!item.range)
84
+ return `Lines ${item.annotation.lines}`;
85
+ return item.range.start === item.range.end
86
+ ? `Line ${item.range.start}`
87
+ : `Lines ${item.range.start}–${item.range.end}`;
88
+ }
89
+ /* ── Marker ────────────────────────────────────────────────────────────────── */
90
+ /**
91
+ * The numbered amber pip rendered on an annotated code row's gutter. `active`
92
+ * brightens it when its note (or a co-located row) is hovered.
93
+ */
94
+ export function AnnotationGutterMarker({ marker, active, className, }) {
95
+ return (_jsx("span", { "aria-hidden": true, className: cn("inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors", active
96
+ ? "bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950"
97
+ : "bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300", className), children: marker }));
98
+ }
99
+ /* ── Note rail ─────────────────────────────────────────────────────────────── */
100
+ /**
101
+ * The responsive list of line-anchored note cards. Each card shows its marker
102
+ * pip, the resolved line span ("Line 8"), an optional label, and the markdown
103
+ * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;
104
+ * `activeIndex` driven from outside lets a hovered code row light its card and
105
+ * vice-versa. Only annotations whose `range` resolved are listed.
106
+ */
107
+ export function AnnotationNoteRail({ items, activeIndex, onActiveChange, ctx, className, showMarker = false, }) {
108
+ const sideAnnotations = useMemo(() => items.filter((item) => item.range), [items]);
109
+ return (_jsx("div", { className: cn("flex flex-col gap-2.5", className), children: sideAnnotations.map((item) => {
110
+ const isActive = activeIndex === item.index;
111
+ return (_jsxs("div", { onMouseEnter: () => onActiveChange(item.index), onMouseLeave: () => onActiveChange(null), className: cn("rounded-lg border px-3.5 py-2.5 transition-colors", isActive
112
+ ? "border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]"
113
+ : "border-plan-line bg-plan-block/40 hover:border-amber-400/50"), children: [_jsxs("div", { className: cn("flex flex-wrap gap-x-2 gap-y-0.5", showMarker ? "items-center" : "items-baseline"), children: [showMarker && (_jsx(AnnotationGutterMarker, { marker: item.marker, active: isActive })), _jsx("span", { className: "text-[11px] font-semibold uppercase tracking-wide text-plan-muted", children: rangeLabel(item) }), item.annotation.label && (_jsx("span", { className: "text-[13px] font-semibold text-plan-text", children: item.annotation.label }))] }), _jsx("div", { className: "plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85", children: ctx.renderMarkdown ? (ctx.renderMarkdown(item.annotation.note)) : (_jsx("p", { children: item.annotation.note })) })] }, item.index));
114
+ }) }));
115
+ }
116
+ /** Whether a resolved list has at least one note worth rendering a rail for. */
117
+ export function hasRailAnnotations(items) {
118
+ return items.some((item) => item.range);
119
+ }
120
+ //# sourceMappingURL=annotation-rail.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-rail.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useMemo, type ReactNode } from \"react\";\nimport { cn } from \"../../utils.js\";\nimport type { BlockRenderContext } from \"../types.js\";\n\n/**\n * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.\n *\n * Both blocks render a numbered code surface plus a side \"rail\" of notes, where\n * each note targets a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) and hovering a code\n * line ↔ its note cross-highlights. This module owns the pure pieces that were\n * identical between them so neither block forks the behavior:\n *\n * - `parseLineRange` — the forgiving 1-based `lines` range parser.\n * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list\n * into stable, marker-numbered, range-resolved records and a line→markers map.\n * - `rangeLabel` — the human \"Line 8\" / \"Lines 3–6\" label.\n * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row\n * (used by the diff grid; the annotated-code surface uses its own rail bar).\n * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.\n * `showMarker` opts the diff block into a leading numbered pip on each card so\n * a note can be matched to its `①`/`②` row marker; annotated-code omits it to\n * keep its original card chrome.\n *\n * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a\n * before/after grid (each annotation also carries a `side`). The shared types\n * here are intentionally minimal — callers pass their own `side` handling and\n * decide which rows a marker lands on; this module only owns the parsing, the\n * resolved-record shape, and the rendered marker + rail chrome.\n */\n\n/* ── Line-ref parsing ──────────────────────────────────────────────────────── */\n\n/**\n * Parse a 1-based `lines` ref (`\"3\"` or `\"3-5\"`) into an inclusive `[start,end]`\n * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully\n * out-of-range refs so callers can ignore them gracefully. A reversed range\n * (`\"5-3\"`) is normalized; a partially out-of-range range is clamped.\n */\nexport function parseLineRange(\n ref: string,\n lineCount: number,\n): { start: number; end: number } | null {\n const match = /^\\s*(\\d+)\\s*(?:-\\s*(\\d+)\\s*)?$/.exec(ref);\n if (!match) return null;\n let start = Number.parseInt(match[1], 10);\n let end = match[2] != null ? Number.parseInt(match[2], 10) : start;\n if (!Number.isFinite(start) || !Number.isFinite(end)) return null;\n if (start > end) [start, end] = [end, start];\n // Fully outside the file → ignore.\n if (end < 1 || start > lineCount) return null;\n return { start: Math.max(1, start), end: Math.min(lineCount, end) };\n}\n\n/** The minimal annotation shape the rail needs (a superset works too). */\nexport interface RailAnnotation {\n lines: string;\n label?: string;\n note: string;\n}\n\nexport interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {\n /** Index in the original `annotations` array (stable hover key). */\n index: number;\n /** 1-based marker number (authoring order). */\n marker: number;\n annotation: A;\n range: { start: number; end: number } | null;\n}\n\n/**\n * Resolve a raw annotation list into stable, marker-numbered records, parsing\n * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a\n * per-annotation line count (before-side vs after-side); annotated-code passes a\n * single constant. Markers are authoring-order, 1-based, and assigned to ALL\n * annotations (even unresolved ones) so numbering is stable regardless of which\n * refs happen to match.\n */\nexport function resolveAnnotations<A extends RailAnnotation>(\n annotations: A[] | undefined,\n lineCountFor: (annotation: A) => number,\n): ResolvedAnnotation<A>[] {\n return (annotations ?? []).map((annotation, index) => ({\n index,\n marker: index + 1,\n annotation,\n range: parseLineRange(annotation.lines, lineCountFor(annotation)),\n }));\n}\n\n/** Map a 1-based line number → the resolved annotations covering it. */\nexport function buildLineMarkerMap<A extends RailAnnotation>(\n resolved: ResolvedAnnotation<A>[],\n): Map<number, ResolvedAnnotation<A>[]> {\n const map = new Map<number, ResolvedAnnotation<A>[]>();\n for (const item of resolved) {\n if (!item.range) continue;\n for (let n = item.range.start; n <= item.range.end; n += 1) {\n const list = map.get(n) ?? [];\n list.push(item);\n map.set(n, list);\n }\n }\n return map;\n}\n\n/** Human label for a resolved annotation's line span (\"Line 8\" / \"Lines 3–6\"). */\nexport function rangeLabel(item: ResolvedAnnotation): string {\n if (!item.range) return `Lines ${item.annotation.lines}`;\n return item.range.start === item.range.end\n ? `Line ${item.range.start}`\n : `Lines ${item.range.start}–${item.range.end}`;\n}\n\n/* ── Marker ────────────────────────────────────────────────────────────────── */\n\n/**\n * The numbered amber pip rendered on an annotated code row's gutter. `active`\n * brightens it when its note (or a co-located row) is hovered.\n */\nexport function AnnotationGutterMarker({\n marker,\n active,\n className,\n}: {\n marker: number;\n active: boolean;\n className?: string;\n}) {\n return (\n <span\n aria-hidden\n className={cn(\n \"inline-flex size-[15px] shrink-0 items-center justify-center rounded-full text-[9px] font-semibold leading-none tabular-nums transition-colors\",\n active\n ? \"bg-amber-500 text-white dark:bg-amber-400 dark:text-amber-950\"\n : \"bg-amber-400/25 text-amber-700 dark:bg-amber-300/20 dark:text-amber-300\",\n className,\n )}\n >\n {marker}\n </span>\n );\n}\n\n/* ── Note rail ─────────────────────────────────────────────────────────────── */\n\n/**\n * The responsive list of line-anchored note cards. Each card shows its marker\n * pip, the resolved line span (\"Line 8\"), an optional label, and the markdown\n * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;\n * `activeIndex` driven from outside lets a hovered code row light its card and\n * vice-versa. Only annotations whose `range` resolved are listed.\n */\nexport function AnnotationNoteRail<A extends RailAnnotation>({\n items,\n activeIndex,\n onActiveChange,\n ctx,\n className,\n showMarker = false,\n}: {\n items: ResolvedAnnotation<A>[];\n activeIndex: number | null;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n className?: string;\n /** Show a leading numbered pip on each card (diff block). */\n showMarker?: boolean;\n}) {\n const sideAnnotations = useMemo(\n () => items.filter((item) => item.range),\n [items],\n );\n return (\n <div className={cn(\"flex flex-col gap-2.5\", className)}>\n {sideAnnotations.map((item) => {\n const isActive = activeIndex === item.index;\n return (\n <div\n key={item.index}\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n className={cn(\n \"rounded-lg border px-3.5 py-2.5 transition-colors\",\n isActive\n ? \"border-amber-400/70 bg-amber-50 dark:border-amber-300/40 dark:bg-amber-300/[0.08]\"\n : \"border-plan-line bg-plan-block/40 hover:border-amber-400/50\",\n )}\n >\n <div\n className={cn(\n \"flex flex-wrap gap-x-2 gap-y-0.5\",\n showMarker ? \"items-center\" : \"items-baseline\",\n )}\n >\n {showMarker && (\n <AnnotationGutterMarker\n marker={item.marker}\n active={isActive}\n />\n )}\n <span className=\"text-[11px] font-semibold uppercase tracking-wide text-plan-muted\">\n {rangeLabel(item)}\n </span>\n {item.annotation.label && (\n <span className=\"text-[13px] font-semibold text-plan-text\">\n {item.annotation.label}\n </span>\n )}\n </div>\n <div className=\"plan-annotation-note mt-1 text-[13px] leading-relaxed text-plan-text/85\">\n {ctx.renderMarkdown ? (\n ctx.renderMarkdown(item.annotation.note)\n ) : (\n <p>{item.annotation.note}</p>\n )}\n </div>\n </div>\n );\n })}\n </div>\n );\n}\n\n/** Whether a resolved list has at least one note worth rendering a rail for. */\nexport function hasRailAnnotations(items: ResolvedAnnotation[]): boolean {\n return items.some((item) => item.range);\n}\n\nexport type AnnotationRailChildren = ReactNode;\n"]}
@@ -21,12 +21,28 @@ export type ApiEndpointMethod = "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "H
21
21
  export declare const API_ENDPOINT_METHODS: ApiEndpointMethod[];
22
22
  export type ApiParamLocation = "path" | "query" | "header" | "body";
23
23
  export declare const API_PARAM_LOCATIONS: ApiParamLocation[];
24
+ /**
25
+ * Diff state for a route / param / response, shared with the `file-tree` and
26
+ * `data-model` blocks so a recap reads consistently across all three. Drives the
27
+ * same change chips (Added / Modified / Removed / Renamed). Absent ⇒ no chip,
28
+ * rendered exactly as before diff support existed.
29
+ */
30
+ export type ApiEndpointChange = "added" | "modified" | "removed" | "renamed";
31
+ export declare const API_ENDPOINT_CHANGES: ApiEndpointChange[];
24
32
  export interface ApiEndpointParam {
25
33
  name: string;
26
34
  in: ApiParamLocation;
27
35
  type?: string;
28
36
  required?: boolean;
29
37
  description?: string;
38
+ /** Diff state for this parameter (drives the change chip). */
39
+ change?: ApiEndpointChange;
40
+ /**
41
+ * Prior value when `change === "modified"` — e.g. the old type (`string`) or
42
+ * the old required flag (`optional`). Shown struck-through before the current
43
+ * value so a reviewer can see the before/after at a glance.
44
+ */
45
+ was?: string;
30
46
  }
31
47
  export interface ApiEndpointRequest {
32
48
  contentType?: string;
@@ -36,6 +52,8 @@ export interface ApiEndpointResponse {
36
52
  status: string;
37
53
  description?: string;
38
54
  example?: string;
55
+ /** Diff state for this response (e.g. a new `409` is "added"). */
56
+ change?: ApiEndpointChange;
39
57
  }
40
58
  export interface ApiEndpointData {
41
59
  method: ApiEndpointMethod;
@@ -45,6 +63,8 @@ export interface ApiEndpointData {
45
63
  description?: string;
46
64
  auth?: string;
47
65
  deprecated?: boolean;
66
+ /** Diff state for the whole route (added/removed/renamed endpoint). */
67
+ change?: ApiEndpointChange;
48
68
  params?: ApiEndpointParam[];
49
69
  request?: ApiEndpointRequest;
50
70
  responses?: ApiEndpointResponse[];
@@ -57,12 +77,17 @@ export interface ApiEndpointData {
57
77
  */
58
78
  export declare const apiEndpointSchema: z.ZodType<ApiEndpointData>;
59
79
  /**
60
- * MDX config: `<Endpoint method path summary auth deprecated params request
61
- * responses>\n\n{description}\n\n</Endpoint>`. `description` is the prose body
62
- * (`childrenField`), so it is excluded from the attribute bag and survives as
63
- * real inline-editable MDX prose. The remaining keys are emitted in a STABLE
64
- * order (method, path, summary, auth, deprecated, params, request, responses);
65
- * `undefined` values are dropped by the shared `prop()` encoder.
80
+ * MDX config: `<Endpoint method path summary auth deprecated change params
81
+ * request responses>\n\n{description}\n\n</Endpoint>`. `description` is the prose
82
+ * body (`childrenField`), so it is excluded from the attribute bag and survives
83
+ * as real inline-editable MDX prose. The remaining keys are emitted in a STABLE
84
+ * order (method, path, summary, auth, deprecated, change, params, request,
85
+ * responses); `undefined` values are dropped by the shared `prop()` encoder.
86
+ *
87
+ * The root `change` is a flat string attribute; the per-param `change` + `was`
88
+ * and per-response `change` ride along inside the `params` / `responses` JSON
89
+ * props (the whole arrays are serialized verbatim), so all three diff levels
90
+ * round-trip without extra encoding.
66
91
  *
67
92
  * `fromAttrs` tolerates missing/partial attributes for backward-compat, mirrors
68
93
  * the schema defaults, and reads the prose `children` into `description`.
@@ -1 +1 @@
1
- {"version":3,"file":"api-endpoint.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/api-endpoint.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,CAAC;AAEd,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,EAQnD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpE,eAAO,MAAM,mBAAmB,EAAE,gBAAgB,EAKjD,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACnC;AAqBD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAUb,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,eAAe,CA6B1D,CAAC"}
1
+ {"version":3,"file":"api-endpoint.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/api-endpoint.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,iBAAiB,GACzB,KAAK,GACL,MAAM,GACN,KAAK,GACL,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,CAAC;AAEd,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,EAQnD,CAAC;AAEF,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEpE,eAAO,MAAM,mBAAmB,EAAE,gBAAgB,EAKjD,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE7E,eAAO,MAAM,oBAAoB,EAAE,iBAAiB,EAKnD,CAAC;AAEF,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,gBAAgB,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,kBAAkB;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,iBAAiB,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uEAAuE;IACvE,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B,SAAS,CAAC,EAAE,mBAAmB,EAAE,CAAC;CACnC;AA0BD;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAWb,CAAC,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;AAS5C;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,cAAc,EAAE,cAAc,CAAC,eAAe,CA+B1D,CAAC"}
@@ -14,12 +14,21 @@ export const API_PARAM_LOCATIONS = [
14
14
  "header",
15
15
  "body",
16
16
  ];
17
+ export const API_ENDPOINT_CHANGES = [
18
+ "added",
19
+ "modified",
20
+ "removed",
21
+ "renamed",
22
+ ];
23
+ const apiChangeSchema = z.enum(["added", "modified", "removed", "renamed"]);
17
24
  const apiParamSchema = z.object({
18
25
  name: z.string().trim().min(1).max(160),
19
26
  in: z.enum(["path", "query", "header", "body"]),
20
27
  type: z.string().trim().max(120).optional(),
21
28
  required: z.boolean().optional(),
22
29
  description: z.string().trim().max(1_000).optional(),
30
+ change: apiChangeSchema.optional(),
31
+ was: z.string().trim().max(400).optional(),
23
32
  });
24
33
  const apiRequestSchema = z.object({
25
34
  contentType: z.string().trim().max(160).optional(),
@@ -29,6 +38,7 @@ const apiResponseSchema = z.object({
29
38
  status: z.string().trim().min(1).max(40),
30
39
  description: z.string().trim().max(1_000).optional(),
31
40
  example: z.string().max(20_000).optional(),
41
+ change: apiChangeSchema.optional(),
32
42
  });
33
43
  /**
34
44
  * Data-compatible with the inline `api-endpoint` member of `planBlockSchema`
@@ -43,17 +53,29 @@ export const apiEndpointSchema = z.object({
43
53
  description: z.string().max(20_000).optional(),
44
54
  auth: z.string().trim().max(200).optional(),
45
55
  deprecated: z.boolean().optional(),
56
+ change: apiChangeSchema.optional(),
46
57
  params: z.array(apiParamSchema).max(60).optional(),
47
58
  request: apiRequestSchema.optional(),
48
59
  responses: z.array(apiResponseSchema).max(40).optional(),
49
60
  });
61
+ /** Coerce a serialized `change` attribute back to the enum (drops garbage). */
62
+ function readChange(value) {
63
+ return value && API_ENDPOINT_CHANGES.includes(value)
64
+ ? value
65
+ : undefined;
66
+ }
50
67
  /**
51
- * MDX config: `<Endpoint method path summary auth deprecated params request
52
- * responses>\n\n{description}\n\n</Endpoint>`. `description` is the prose body
53
- * (`childrenField`), so it is excluded from the attribute bag and survives as
54
- * real inline-editable MDX prose. The remaining keys are emitted in a STABLE
55
- * order (method, path, summary, auth, deprecated, params, request, responses);
56
- * `undefined` values are dropped by the shared `prop()` encoder.
68
+ * MDX config: `<Endpoint method path summary auth deprecated change params
69
+ * request responses>\n\n{description}\n\n</Endpoint>`. `description` is the prose
70
+ * body (`childrenField`), so it is excluded from the attribute bag and survives
71
+ * as real inline-editable MDX prose. The remaining keys are emitted in a STABLE
72
+ * order (method, path, summary, auth, deprecated, change, params, request,
73
+ * responses); `undefined` values are dropped by the shared `prop()` encoder.
74
+ *
75
+ * The root `change` is a flat string attribute; the per-param `change` + `was`
76
+ * and per-response `change` ride along inside the `params` / `responses` JSON
77
+ * props (the whole arrays are serialized verbatim), so all three diff levels
78
+ * round-trip without extra encoding.
57
79
  *
58
80
  * `fromAttrs` tolerates missing/partial attributes for backward-compat, mirrors
59
81
  * the schema defaults, and reads the prose `children` into `description`.
@@ -67,6 +89,7 @@ export const apiEndpointMdx = {
67
89
  summary: data.summary,
68
90
  auth: data.auth,
69
91
  deprecated: data.deprecated,
92
+ change: data.change,
70
93
  params: data.params,
71
94
  request: data.request,
72
95
  responses: data.responses,
@@ -82,6 +105,7 @@ export const apiEndpointMdx = {
82
105
  description: description.length > 0 ? description : undefined,
83
106
  auth: attrs.string("auth"),
84
107
  deprecated: attrs.bool("deprecated"),
108
+ change: readChange(attrs.string("change")),
85
109
  params: attrs.array("params"),
86
110
  request: request ?? undefined,
87
111
  responses: attrs.array("responses"),
@@ -1 +1 @@
1
- {"version":3,"file":"api-endpoint.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/api-endpoint.config.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from \"zod\";\nimport type { BlockMdxConfig } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the PLAN-SPECIFIC `api-endpoint` block: its data\n * schema and MDX round-trip config. Shared by the server MDX adapter\n * (`plan-mdx.ts` via `plan-block-registry.ts`) and the client spec\n * (`planBlocks.tsx`). Keeping this React-free means importing it into a server\n * module never pulls React into the Nitro/SSR bundle.\n *\n * The block renders a Swagger / Stripe-style API reference row: a colored method\n * pill + monospace path + summary, collapsed by default, expanding to a params\n * table, a request body example, and per-status response examples.\n *\n * The schema MUST stay data-compatible with the `api-endpoint` branch of\n * `planBlockSchema` (`plan-content.ts`), and the MDX `tag` (`Endpoint`) +\n * attribute/children shape MUST match the inline planBlockSchema member so\n * stored `.mdx` round-trips. `description` is MDX *children* (prose body);\n * every other field is an attribute.\n */\n\nexport type ApiEndpointMethod =\n | \"GET\"\n | \"POST\"\n | \"PUT\"\n | \"PATCH\"\n | \"DELETE\"\n | \"HEAD\"\n | \"OPTIONS\";\n\nexport const API_ENDPOINT_METHODS: ApiEndpointMethod[] = [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\",\n \"HEAD\",\n \"OPTIONS\",\n];\n\nexport type ApiParamLocation = \"path\" | \"query\" | \"header\" | \"body\";\n\nexport const API_PARAM_LOCATIONS: ApiParamLocation[] = [\n \"path\",\n \"query\",\n \"header\",\n \"body\",\n];\n\nexport interface ApiEndpointParam {\n name: string;\n in: ApiParamLocation;\n type?: string;\n required?: boolean;\n description?: string;\n}\n\nexport interface ApiEndpointRequest {\n contentType?: string;\n example?: string;\n}\n\nexport interface ApiEndpointResponse {\n status: string;\n description?: string;\n example?: string;\n}\n\nexport interface ApiEndpointData {\n method: ApiEndpointMethod;\n path: string;\n summary?: string;\n /** Markdown prose body. Serialized as MDX children, not an attribute. */\n description?: string;\n auth?: string;\n deprecated?: boolean;\n params?: ApiEndpointParam[];\n request?: ApiEndpointRequest;\n responses?: ApiEndpointResponse[];\n}\n\nconst apiParamSchema = z.object({\n name: z.string().trim().min(1).max(160),\n in: z.enum([\"path\", \"query\", \"header\", \"body\"]),\n type: z.string().trim().max(120).optional(),\n required: z.boolean().optional(),\n description: z.string().trim().max(1_000).optional(),\n}) as z.ZodType<ApiEndpointParam>;\n\nconst apiRequestSchema = z.object({\n contentType: z.string().trim().max(160).optional(),\n example: z.string().max(20_000).optional(),\n}) as z.ZodType<ApiEndpointRequest>;\n\nconst apiResponseSchema = z.object({\n status: z.string().trim().min(1).max(40),\n description: z.string().trim().max(1_000).optional(),\n example: z.string().max(20_000).optional(),\n}) as z.ZodType<ApiEndpointResponse>;\n\n/**\n * Data-compatible with the inline `api-endpoint` member of `planBlockSchema`\n * (`plan-content.ts`). `method` + `path` are required; everything else is\n * optional and defaults to omitted so a fresh endpoint validates from\n * `{ method: \"GET\", path: \"/api/resource\" }`.\n */\nexport const apiEndpointSchema = z.object({\n method: z.enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\"]),\n path: z.string().trim().min(1).max(500),\n summary: z.string().trim().max(400).optional(),\n description: z.string().max(20_000).optional(),\n auth: z.string().trim().max(200).optional(),\n deprecated: z.boolean().optional(),\n params: z.array(apiParamSchema).max(60).optional(),\n request: apiRequestSchema.optional(),\n responses: z.array(apiResponseSchema).max(40).optional(),\n}) as unknown as z.ZodType<ApiEndpointData>;\n\n/**\n * MDX config: `<Endpoint method path summary auth deprecated params request\n * responses>\\n\\n{description}\\n\\n</Endpoint>`. `description` is the prose body\n * (`childrenField`), so it is excluded from the attribute bag and survives as\n * real inline-editable MDX prose. The remaining keys are emitted in a STABLE\n * order (method, path, summary, auth, deprecated, params, request, responses);\n * `undefined` values are dropped by the shared `prop()` encoder.\n *\n * `fromAttrs` tolerates missing/partial attributes for backward-compat, mirrors\n * the schema defaults, and reads the prose `children` into `description`.\n */\nexport const apiEndpointMdx: BlockMdxConfig<ApiEndpointData> = {\n tag: \"Endpoint\",\n childrenField: \"description\",\n toAttrs: (data) => ({\n method: data.method,\n path: data.path,\n summary: data.summary,\n auth: data.auth,\n deprecated: data.deprecated,\n params: data.params,\n request: data.request as Record<string, unknown> | undefined,\n responses: data.responses,\n }),\n fromAttrs: (attrs, children) => {\n const method = (attrs.string(\"method\") ?? \"GET\") as ApiEndpointMethod;\n const request = attrs.object<ApiEndpointRequest>(\"request\");\n const description = children.trim();\n return {\n method: API_ENDPOINT_METHODS.includes(method) ? method : \"GET\",\n path: attrs.string(\"path\") ?? \"\",\n summary: attrs.string(\"summary\"),\n description: description.length > 0 ? description : undefined,\n auth: attrs.string(\"auth\"),\n deprecated: attrs.bool(\"deprecated\"),\n params: attrs.array<ApiEndpointParam>(\"params\"),\n request: request ?? undefined,\n responses: attrs.array<ApiEndpointResponse>(\"responses\"),\n };\n },\n};\n"]}
1
+ {"version":3,"file":"api-endpoint.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/api-endpoint.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AA8BxB,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,KAAK;IACL,MAAM;IACN,KAAK;IACL,OAAO;IACP,QAAQ;IACR,MAAM;IACN,SAAS;CACV,CAAC;AAIF,MAAM,CAAC,MAAM,mBAAmB,GAAuB;IACrD,MAAM;IACN,OAAO;IACP,QAAQ;IACR,MAAM;CACP,CAAC;AAUF,MAAM,CAAC,MAAM,oBAAoB,GAAwB;IACvD,OAAO;IACP,UAAU;IACV,SAAS;IACT,SAAS;CACV,CAAC;AA8CF,MAAM,eAAe,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC,CAAC;AAE5E,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACvC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC;IAC/C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAChC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACpD,MAAM,EAAE,eAAe,CAAC,QAAQ,EAAE;IAClC,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;CAC3C,CAAgC,CAAC;AAElC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAClD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;CAC3C,CAAkC,CAAC;AAEpC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;IACxC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;IACpD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;IAC1C,MAAM,EAAE,eAAe,CAAC,QAAQ,EAAE;CACnC,CAAmC,CAAC;AAErC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACxC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;IAC5E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC9C,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE;IAC9C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;IAC3C,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,eAAe,CAAC,QAAQ,EAAE;IAClC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAClD,OAAO,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACpC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;CACzD,CAA0C,CAAC;AAE5C,+EAA+E;AAC/E,SAAS,UAAU,CAAC,KAAyB;IAC3C,OAAO,KAAK,IAAI,oBAAoB,CAAC,QAAQ,CAAC,KAA0B,CAAC;QACvE,CAAC,CAAE,KAA2B;QAC9B,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,cAAc,GAAoC;IAC7D,GAAG,EAAE,UAAU;IACf,aAAa,EAAE,aAAa;IAC5B,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU,EAAE,IAAI,CAAC,UAAU;QAC3B,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,MAAM,EAAE,IAAI,CAAC,MAAM;QACnB,OAAO,EAAE,IAAI,CAAC,OAA8C;QAC5D,SAAS,EAAE,IAAI,CAAC,SAAS;KAC1B,CAAC;IACF,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;QAC7B,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAsB,CAAC;QACtE,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAqB,SAAS,CAAC,CAAC;QAC5D,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,oBAAoB,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK;YAC9D,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YAChC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC;YAChC,WAAW,EAAE,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;YAC7D,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;YAC1B,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC;YACpC,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,EAAE,KAAK,CAAC,KAAK,CAAmB,QAAQ,CAAC;YAC/C,OAAO,EAAE,OAAO,IAAI,SAAS;YAC7B,SAAS,EAAE,KAAK,CAAC,KAAK,CAAsB,WAAW,CAAC;SACzD,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { z } from \"zod\";\nimport type { BlockMdxConfig } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the PLAN-SPECIFIC `api-endpoint` block: its data\n * schema and MDX round-trip config. Shared by the server MDX adapter\n * (`plan-mdx.ts` via `plan-block-registry.ts`) and the client spec\n * (`planBlocks.tsx`). Keeping this React-free means importing it into a server\n * module never pulls React into the Nitro/SSR bundle.\n *\n * The block renders a Swagger / Stripe-style API reference row: a colored method\n * pill + monospace path + summary, collapsed by default, expanding to a params\n * table, a request body example, and per-status response examples.\n *\n * The schema MUST stay data-compatible with the `api-endpoint` branch of\n * `planBlockSchema` (`plan-content.ts`), and the MDX `tag` (`Endpoint`) +\n * attribute/children shape MUST match the inline planBlockSchema member so\n * stored `.mdx` round-trips. `description` is MDX *children* (prose body);\n * every other field is an attribute.\n */\n\nexport type ApiEndpointMethod =\n | \"GET\"\n | \"POST\"\n | \"PUT\"\n | \"PATCH\"\n | \"DELETE\"\n | \"HEAD\"\n | \"OPTIONS\";\n\nexport const API_ENDPOINT_METHODS: ApiEndpointMethod[] = [\n \"GET\",\n \"POST\",\n \"PUT\",\n \"PATCH\",\n \"DELETE\",\n \"HEAD\",\n \"OPTIONS\",\n];\n\nexport type ApiParamLocation = \"path\" | \"query\" | \"header\" | \"body\";\n\nexport const API_PARAM_LOCATIONS: ApiParamLocation[] = [\n \"path\",\n \"query\",\n \"header\",\n \"body\",\n];\n\n/**\n * Diff state for a route / param / response, shared with the `file-tree` and\n * `data-model` blocks so a recap reads consistently across all three. Drives the\n * same change chips (Added / Modified / Removed / Renamed). Absent ⇒ no chip,\n * rendered exactly as before diff support existed.\n */\nexport type ApiEndpointChange = \"added\" | \"modified\" | \"removed\" | \"renamed\";\n\nexport const API_ENDPOINT_CHANGES: ApiEndpointChange[] = [\n \"added\",\n \"modified\",\n \"removed\",\n \"renamed\",\n];\n\nexport interface ApiEndpointParam {\n name: string;\n in: ApiParamLocation;\n type?: string;\n required?: boolean;\n description?: string;\n /** Diff state for this parameter (drives the change chip). */\n change?: ApiEndpointChange;\n /**\n * Prior value when `change === \"modified\"` — e.g. the old type (`string`) or\n * the old required flag (`optional`). Shown struck-through before the current\n * value so a reviewer can see the before/after at a glance.\n */\n was?: string;\n}\n\nexport interface ApiEndpointRequest {\n contentType?: string;\n example?: string;\n}\n\nexport interface ApiEndpointResponse {\n status: string;\n description?: string;\n example?: string;\n /** Diff state for this response (e.g. a new `409` is \"added\"). */\n change?: ApiEndpointChange;\n}\n\nexport interface ApiEndpointData {\n method: ApiEndpointMethod;\n path: string;\n summary?: string;\n /** Markdown prose body. Serialized as MDX children, not an attribute. */\n description?: string;\n auth?: string;\n deprecated?: boolean;\n /** Diff state for the whole route (added/removed/renamed endpoint). */\n change?: ApiEndpointChange;\n params?: ApiEndpointParam[];\n request?: ApiEndpointRequest;\n responses?: ApiEndpointResponse[];\n}\n\nconst apiChangeSchema = z.enum([\"added\", \"modified\", \"removed\", \"renamed\"]);\n\nconst apiParamSchema = z.object({\n name: z.string().trim().min(1).max(160),\n in: z.enum([\"path\", \"query\", \"header\", \"body\"]),\n type: z.string().trim().max(120).optional(),\n required: z.boolean().optional(),\n description: z.string().trim().max(1_000).optional(),\n change: apiChangeSchema.optional(),\n was: z.string().trim().max(400).optional(),\n}) as z.ZodType<ApiEndpointParam>;\n\nconst apiRequestSchema = z.object({\n contentType: z.string().trim().max(160).optional(),\n example: z.string().max(20_000).optional(),\n}) as z.ZodType<ApiEndpointRequest>;\n\nconst apiResponseSchema = z.object({\n status: z.string().trim().min(1).max(40),\n description: z.string().trim().max(1_000).optional(),\n example: z.string().max(20_000).optional(),\n change: apiChangeSchema.optional(),\n}) as z.ZodType<ApiEndpointResponse>;\n\n/**\n * Data-compatible with the inline `api-endpoint` member of `planBlockSchema`\n * (`plan-content.ts`). `method` + `path` are required; everything else is\n * optional and defaults to omitted so a fresh endpoint validates from\n * `{ method: \"GET\", path: \"/api/resource\" }`.\n */\nexport const apiEndpointSchema = z.object({\n method: z.enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\", \"HEAD\", \"OPTIONS\"]),\n path: z.string().trim().min(1).max(500),\n summary: z.string().trim().max(400).optional(),\n description: z.string().max(20_000).optional(),\n auth: z.string().trim().max(200).optional(),\n deprecated: z.boolean().optional(),\n change: apiChangeSchema.optional(),\n params: z.array(apiParamSchema).max(60).optional(),\n request: apiRequestSchema.optional(),\n responses: z.array(apiResponseSchema).max(40).optional(),\n}) as unknown as z.ZodType<ApiEndpointData>;\n\n/** Coerce a serialized `change` attribute back to the enum (drops garbage). */\nfunction readChange(value: string | undefined): ApiEndpointChange | undefined {\n return value && API_ENDPOINT_CHANGES.includes(value as ApiEndpointChange)\n ? (value as ApiEndpointChange)\n : undefined;\n}\n\n/**\n * MDX config: `<Endpoint method path summary auth deprecated change params\n * request responses>\\n\\n{description}\\n\\n</Endpoint>`. `description` is the prose\n * body (`childrenField`), so it is excluded from the attribute bag and survives\n * as real inline-editable MDX prose. The remaining keys are emitted in a STABLE\n * order (method, path, summary, auth, deprecated, change, params, request,\n * responses); `undefined` values are dropped by the shared `prop()` encoder.\n *\n * The root `change` is a flat string attribute; the per-param `change` + `was`\n * and per-response `change` ride along inside the `params` / `responses` JSON\n * props (the whole arrays are serialized verbatim), so all three diff levels\n * round-trip without extra encoding.\n *\n * `fromAttrs` tolerates missing/partial attributes for backward-compat, mirrors\n * the schema defaults, and reads the prose `children` into `description`.\n */\nexport const apiEndpointMdx: BlockMdxConfig<ApiEndpointData> = {\n tag: \"Endpoint\",\n childrenField: \"description\",\n toAttrs: (data) => ({\n method: data.method,\n path: data.path,\n summary: data.summary,\n auth: data.auth,\n deprecated: data.deprecated,\n change: data.change,\n params: data.params,\n request: data.request as Record<string, unknown> | undefined,\n responses: data.responses,\n }),\n fromAttrs: (attrs, children) => {\n const method = (attrs.string(\"method\") ?? \"GET\") as ApiEndpointMethod;\n const request = attrs.object<ApiEndpointRequest>(\"request\");\n const description = children.trim();\n return {\n method: API_ENDPOINT_METHODS.includes(method) ? method : \"GET\",\n path: attrs.string(\"path\") ?? \"\",\n summary: attrs.string(\"summary\"),\n description: description.length > 0 ? description : undefined,\n auth: attrs.string(\"auth\"),\n deprecated: attrs.bool(\"deprecated\"),\n change: readChange(attrs.string(\"change\")),\n params: attrs.array<ApiEndpointParam>(\"params\"),\n request: request ?? undefined,\n responses: attrs.array<ApiEndpointResponse>(\"responses\"),\n };\n },\n};\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/code.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AA2OtE,eAAO,MAAM,SAAS,2CAYpB,CAAC"}
1
+ {"version":3,"file":"code.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/code.tsx"],"names":[],"mappings":"AAuBA,OAAO,EAAuB,KAAK,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAiWtE,eAAO,MAAM,SAAS,2CAYpB,CAAC"}
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useId, useLayoutEffect, useMemo, useRef, useState, } from "react";
3
- import { IconCheck, IconCode, IconCopy } from "@tabler/icons-react";
2
+ import { useId, useMemo, useRef, useState, } from "react";
3
+ import { IconCheck, IconCode, IconCopy, IconPencil } from "@tabler/icons-react";
4
4
  import { cn } from "../../utils.js";
5
+ import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover.js";
5
6
  import { defineBlock } from "../types.js";
6
- import { CodeSurface } from "./HighlightedCode.js";
7
+ import { CodeSurface, DEFAULT_CODE_MAX_LINES } from "./HighlightedCode.js";
7
8
  import { highlightCode, inferLanguageFromFilename, normalizeCodeLanguage, } from "./code-highlight.js";
8
9
  import { codeSchema, codeMdx } from "./code.config.js";
9
10
  /**
@@ -54,30 +55,46 @@ function CodeRead({ data, blockId }) {
54
55
  return (_jsx("section", { className: "plan-block", "data-block-id": blockId, children: _jsxs("div", { className: "plan-code group relative", children: [data.filename && (_jsxs("div", { className: "plan-code-head", children: [_jsxs("span", { className: "plan-code-filename", children: [_jsx(IconCode, { className: "size-4 shrink-0 opacity-70" }), data.filename] }), _jsx("span", { className: "plan-code-chrome", children: _jsx(CopyButton, { value: data.code }) })] })), _jsx(CodeSurface, { code: data.code, language: language, maxLines: data.maxLines, className: data.filename ? "mt-0" : "mt-0" }), !data.filename && (_jsx("span", { className: "plan-code-chrome plan-code-chrome-float", children: _jsx(CopyButton, { value: data.code }) })), data.caption && _jsx("p", { className: "plan-code-caption", children: data.caption })] }) }));
55
56
  }
56
57
  /* ── Edit (single border, no resize, auto-grow, hover chrome) ──────────────── */
57
- function CodeEditorSurface({ code, language, filename, editable, onCodeChange, onLanguageChange, }) {
58
- const textareaRef = useRef(null);
58
+ const SETTINGS_INPUT = "flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
59
+ /** Hover "settings" (pencil) → popover to edit the filename + max-lines cap. */
60
+ function CodeSettingsPopover({ filename, maxLines, onFilenameChange, onMaxLinesChange, }) {
61
+ return (_jsxs(Popover, { children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Code block settings", title: "Code block settings", className: "plan-code-chip", children: _jsx(IconPencil, { className: "size-3.5" }) }) }), _jsxs(PopoverContent, { align: "end", side: "bottom", className: "w-64 p-0", "data-plan-interactive": true, children: [_jsx("div", { className: "border-b border-border px-3 py-2 text-sm font-semibold text-foreground", children: "Code block" }), _jsxs("div", { className: "grid gap-3 p-3", children: [_jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Filename" }), _jsx("input", { type: "text", "data-plan-interactive": true, className: SETTINGS_INPUT, placeholder: "src/file.ts", value: filename ?? "", onChange: (event) => onFilenameChange(event.target.value || undefined) })] }), _jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: "text-xs font-medium text-muted-foreground", children: "Max lines before expand" }), _jsx("input", { type: "number", min: 0, step: 1, "data-plan-interactive": true, className: SETTINGS_INPUT, placeholder: `${DEFAULT_CODE_MAX_LINES} (default) · 0 = no limit`, value: maxLines ?? "", onChange: (event) => {
62
+ const raw = event.target.value.trim();
63
+ const parsed = raw === "" ? undefined : Number(raw);
64
+ onMaxLinesChange(parsed === undefined || Number.isNaN(parsed)
65
+ ? undefined
66
+ : Math.max(0, Math.min(2000, Math.floor(parsed))));
67
+ } })] })] })] })] }));
68
+ }
69
+ function CodeEditorSurface({ code, language, filename, maxLines, editable, onCodeChange, onLanguageChange, onFilenameChange, onMaxLinesChange, }) {
70
+ const [expanded, setExpanded] = useState(false);
59
71
  const highlightLayerRef = useRef(null);
60
72
  const selectId = useId();
61
73
  const resolvedLanguage = normalizeCodeLanguage(language) ?? inferLanguageFromFilename(filename);
62
74
  const highlighted = useMemo(() => highlightCode(code, resolvedLanguage), [resolvedLanguage, code]);
63
- // Auto-grow to content height — no drag-to-resize handle.
64
- useLayoutEffect(() => {
65
- const node = textareaRef.current;
66
- if (!node)
67
- return;
68
- node.style.height = "auto";
69
- node.style.height = `${node.scrollHeight}px`;
70
- }, [code]);
75
+ // Size the editor to its content by line count deterministic, no layout
76
+ // measurement. `wrap="off"` means one row per line. Long snippets collapse to
77
+ // `cap` lines behind a "Show N more lines" toggle, matching the read surface
78
+ // and the file-tree block. `maxLines` omitted ⇒ DEFAULT (40); `0` ⇒ never
79
+ // collapse (show everything).
80
+ const lineCount = code ? code.split("\n").length : 1;
81
+ const cap = maxLines == null ? DEFAULT_CODE_MAX_LINES : maxLines > 0 ? maxLines : null;
82
+ const collapsible = cap != null && lineCount > cap;
83
+ const collapsed = collapsible && !expanded;
84
+ const hiddenLines = collapsible ? lineCount - cap : 0;
85
+ const rows = collapsed ? cap : lineCount + 1;
71
86
  const syncScroll = (event) => {
72
87
  const layer = highlightLayerRef.current;
73
88
  if (!layer)
74
89
  return;
75
90
  layer.scrollLeft = event.currentTarget.scrollLeft;
76
91
  };
77
- return (_jsxs("div", { className: cn("plan-code plan-code-editing group relative", !editable && "opacity-60"), children: [_jsxs("div", { className: "plan-code-head", children: [_jsxs("span", { className: "plan-code-filename plan-code-muted", children: [_jsx(IconCode, { className: "size-4 shrink-0 opacity-70" }), filename || "Snippet"] }), _jsxs("span", { className: "plan-code-chrome", children: [_jsx("label", { htmlFor: selectId, className: "sr-only", children: "Code language" }), _jsx("select", { id: selectId, "data-plan-interactive": true, disabled: !editable, className: "plan-code-lang-select", value: normalizeCodeLanguage(language) ? (language ?? "") : "", onChange: (event) => onLanguageChange(event.target.value || undefined), children: CODE_LANGUAGES.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value || "auto"))) }), _jsx(CopyButton, { value: code })] })] }), _jsxs("div", { className: "plan-code-editor-body", children: [_jsx("pre", { ref: highlightLayerRef, "aria-hidden": "true", className: "plan-code-editor-layer", children: _jsxs("code", { children: [highlighted, code.endsWith("\n") ? " " : null] }) }), _jsx("textarea", { ref: textareaRef, "data-plan-interactive": true, spellCheck: false, wrap: "off", className: "plan-code-editor-input", value: code, disabled: !editable, onChange: (event) => onCodeChange(event.target.value), onScroll: syncScroll })] })] }));
92
+ return (_jsxs("div", { className: cn("plan-code plan-code-editing group relative", !editable && "opacity-60"), children: [_jsxs("div", { className: "plan-code-head", children: [_jsxs("span", { className: "plan-code-filename plan-code-muted", children: [_jsx(IconCode, { className: "size-4 shrink-0 opacity-70" }), filename || "Snippet"] }), _jsxs("span", { className: "plan-code-chrome", children: [_jsx("label", { htmlFor: selectId, className: "sr-only", children: "Code language" }), _jsx("select", { id: selectId, "data-plan-interactive": true, disabled: !editable, className: "plan-code-lang-select", value: normalizeCodeLanguage(language) ? (language ?? "") : "", onChange: (event) => onLanguageChange(event.target.value || undefined), children: CODE_LANGUAGES.map((option) => (_jsx("option", { value: option.value, children: option.label }, option.value || "auto"))) }), editable && (_jsx(CodeSettingsPopover, { filename: filename, maxLines: maxLines, onFilenameChange: onFilenameChange, onMaxLinesChange: onMaxLinesChange })), _jsx(CopyButton, { value: code })] })] }), _jsxs("div", { className: "plan-code-editor-body", children: [_jsx("pre", { ref: highlightLayerRef, "aria-hidden": "true", className: "plan-code-editor-layer", children: _jsxs("code", { children: [highlighted, code.endsWith("\n") ? " " : null] }) }), _jsx("textarea", { "data-plan-interactive": true, spellCheck: false, wrap: "off", rows: Math.max(3, rows), className: "plan-code-editor-input", value: code, disabled: !editable, onChange: (event) => onCodeChange(event.target.value), onScroll: syncScroll }), collapsed && (_jsx("div", { className: "plan-code-editor-fade", "aria-hidden": "true" }))] }), collapsible && (_jsx("button", { type: "button", "data-plan-interactive": true, className: "plan-code-surface-toggle", onClick: () => setExpanded((value) => !value), children: collapsed
93
+ ? `Show ${hiddenLines} more line${hiddenLines === 1 ? "" : "s"}`
94
+ : "Show less" }))] }));
78
95
  }
79
96
  function CodeEdit({ data, onChange, editable }) {
80
- return (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsx(CodeEditorSurface, { code: data.code, language: data.language, filename: data.filename, editable: editable, onCodeChange: (code) => onChange({ ...data, code }), onLanguageChange: (language) => onChange({ ...data, language }) }), editable && (_jsx("input", { type: "text", "data-plan-interactive": true, className: "plan-code-caption-input", placeholder: "Caption (optional)", value: data.caption ?? "", onChange: (event) => onChange({ ...data, caption: event.target.value || undefined }) }))] }));
97
+ return (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsx(CodeEditorSurface, { code: data.code, language: data.language, filename: data.filename, maxLines: data.maxLines, editable: editable, onCodeChange: (code) => onChange({ ...data, code }), onLanguageChange: (language) => onChange({ ...data, language }), onFilenameChange: (filename) => onChange({ ...data, filename }), onMaxLinesChange: (maxLines) => onChange({ ...data, maxLines }) }), editable && (_jsx("input", { type: "text", "data-plan-interactive": true, className: "plan-code-caption-input", placeholder: "Caption (optional)", value: data.caption ?? "", onChange: (event) => onChange({ ...data, caption: event.target.value || undefined }) }))] }));
81
98
  }
82
99
  /* ── Spec ──────────────────────────────────────────────────────────────────── */
83
100
  export const codeBlock = defineBlock({
@@ -1 +1 @@
1
- {"version":3,"file":"code.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useId,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type UIEvent,\n} from \"react\";\nimport { IconCheck, IconCode, IconCopy } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport { CodeSurface } from \"./HighlightedCode.js\";\nimport {\n highlightCode,\n inferLanguageFromFilename,\n normalizeCodeLanguage,\n} from \"./code-highlight.js\";\nimport { codeSchema, codeMdx, type CodeData } from \"./code.config.js\";\n\n/**\n * Standard `code` block (STANDARD core library): THE primitive single code\n * snippet, used everywhere in plan + content. Notion-style — one border, a\n * hover-revealed language switcher + copy, and the shared collapse-to-N-lines\n * read surface. A \"file rail\" of several files is just the `tabs` primitive\n * holding `code` blocks; there is no bespoke \"code-tabs\" container.\n *\n * Read = the shared {@link CodeSurface} (Shiki, single border, language label,\n * \"Show N more lines\"). Edit = a clean, single-border editable surface (no\n * drag-to-resize; it auto-grows to its content) with the same hover chrome.\n */\n\n/** Language options for the hover switcher; \"\" is the Auto-detect sentinel. */\nconst CODE_LANGUAGES: ReadonlyArray<{ value: string; label: string }> = [\n { value: \"\", label: \"Auto\" },\n { value: \"typescript\", label: \"TypeScript\" },\n { value: \"javascript\", label: \"JavaScript\" },\n { value: \"tsx\", label: \"TSX\" },\n { value: \"jsx\", label: \"JSX\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"bash\", label: \"Bash\" },\n { value: \"python\", label: \"Python\" },\n { value: \"sql\", label: \"SQL\" },\n { value: \"yaml\", label: \"YAML\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"graphql\", label: \"GraphQL\" },\n { value: \"go\", label: \"Go\" },\n { value: \"rust\", label: \"Rust\" },\n { value: \"diff\", label: \"Diff\" },\n];\n\nfunction CopyButton({ value }: { value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n title={copied ? \"Copied\" : \"Copy code\"}\n className=\"plan-code-chip\"\n onClick={() => {\n void navigator.clipboard?.writeText(value).then(\n () => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n },\n () => {},\n );\n }}\n >\n {copied ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n </button>\n );\n}\n\n/* ── Read ──────────────────────────────────────────────────────────────────── */\n\nfunction CodeRead({ data, blockId }: BlockReadProps<CodeData>) {\n const language =\n normalizeCodeLanguage(data.language) ??\n inferLanguageFromFilename(data.filename) ??\n undefined;\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n <div className=\"plan-code group relative\">\n {data.filename && (\n <div className=\"plan-code-head\">\n <span className=\"plan-code-filename\">\n <IconCode className=\"size-4 shrink-0 opacity-70\" />\n {data.filename}\n </span>\n <span className=\"plan-code-chrome\">\n <CopyButton value={data.code} />\n </span>\n </div>\n )}\n <CodeSurface\n code={data.code}\n language={language}\n maxLines={data.maxLines}\n className={data.filename ? \"mt-0\" : \"mt-0\"}\n />\n {!data.filename && (\n <span className=\"plan-code-chrome plan-code-chrome-float\">\n <CopyButton value={data.code} />\n </span>\n )}\n {data.caption && <p className=\"plan-code-caption\">{data.caption}</p>}\n </div>\n </section>\n );\n}\n\n/* ── Edit (single border, no resize, auto-grow, hover chrome) ──────────────── */\n\nfunction CodeEditorSurface({\n code,\n language,\n filename,\n editable,\n onCodeChange,\n onLanguageChange,\n}: {\n code: string;\n language?: string;\n filename?: string;\n editable: boolean;\n onCodeChange: (code: string) => void;\n onLanguageChange: (language: string | undefined) => void;\n}) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const highlightLayerRef = useRef<HTMLPreElement>(null);\n const selectId = useId();\n const resolvedLanguage =\n normalizeCodeLanguage(language) ?? inferLanguageFromFilename(filename);\n const highlighted = useMemo(\n () => highlightCode(code, resolvedLanguage),\n [resolvedLanguage, code],\n );\n\n // Auto-grow to content height — no drag-to-resize handle.\n useLayoutEffect(() => {\n const node = textareaRef.current;\n if (!node) return;\n node.style.height = \"auto\";\n node.style.height = `${node.scrollHeight}px`;\n }, [code]);\n\n const syncScroll = (event: UIEvent<HTMLTextAreaElement>) => {\n const layer = highlightLayerRef.current;\n if (!layer) return;\n layer.scrollLeft = event.currentTarget.scrollLeft;\n };\n\n return (\n <div\n className={cn(\n \"plan-code plan-code-editing group relative\",\n !editable && \"opacity-60\",\n )}\n >\n <div className=\"plan-code-head\">\n <span className=\"plan-code-filename plan-code-muted\">\n <IconCode className=\"size-4 shrink-0 opacity-70\" />\n {filename || \"Snippet\"}\n </span>\n <span className=\"plan-code-chrome\">\n <label htmlFor={selectId} className=\"sr-only\">\n Code language\n </label>\n <select\n id={selectId}\n data-plan-interactive\n disabled={!editable}\n className=\"plan-code-lang-select\"\n value={normalizeCodeLanguage(language) ? (language ?? \"\") : \"\"}\n onChange={(event) =>\n onLanguageChange(event.target.value || undefined)\n }\n >\n {CODE_LANGUAGES.map((option) => (\n <option key={option.value || \"auto\"} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n <CopyButton value={code} />\n </span>\n </div>\n <div className=\"plan-code-editor-body\">\n <pre\n ref={highlightLayerRef}\n aria-hidden=\"true\"\n className=\"plan-code-editor-layer\"\n >\n <code>\n {highlighted}\n {code.endsWith(\"\\n\") ? \" \" : null}\n </code>\n </pre>\n <textarea\n ref={textareaRef}\n data-plan-interactive\n spellCheck={false}\n wrap=\"off\"\n className=\"plan-code-editor-input\"\n value={code}\n disabled={!editable}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>) =>\n onCodeChange(event.target.value)\n }\n onScroll={syncScroll}\n />\n </div>\n </div>\n );\n}\n\nfunction CodeEdit({ data, onChange, editable }: BlockEditProps<CodeData>) {\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <CodeEditorSurface\n code={data.code}\n language={data.language}\n filename={data.filename}\n editable={editable}\n onCodeChange={(code) => onChange({ ...data, code })}\n onLanguageChange={(language) => onChange({ ...data, language })}\n />\n {editable && (\n <input\n type=\"text\"\n data-plan-interactive\n className=\"plan-code-caption-input\"\n placeholder=\"Caption (optional)\"\n value={data.caption ?? \"\"}\n onChange={(event) =>\n onChange({ ...data, caption: event.target.value || undefined })\n }\n />\n )}\n </div>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeBlock = defineBlock<CodeData>({\n type: \"code\",\n schema: codeSchema,\n mdx: codeMdx,\n Read: CodeRead,\n Edit: CodeEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n label: \"Code\",\n icon: IconCode,\n description:\n \"A single syntax-highlighted code snippet, Notion-style: one border, a hover language switcher + copy, and collapse-to-N lines. Put several in a `tabs` block for a file rail.\",\n});\n"]}
1
+ {"version":3,"file":"code.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/code.tsx"],"names":[],"mappings":"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","sourcesContent":["import {\n useId,\n useMemo,\n useRef,\n useState,\n type ChangeEvent,\n type UIEvent,\n} from \"react\";\nimport { IconCheck, IconCode, IconCopy, IconPencil } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport {\n Popover,\n PopoverContent,\n PopoverTrigger,\n} from \"../../components/ui/popover.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport { CodeSurface, DEFAULT_CODE_MAX_LINES } from \"./HighlightedCode.js\";\nimport {\n highlightCode,\n inferLanguageFromFilename,\n normalizeCodeLanguage,\n} from \"./code-highlight.js\";\nimport { codeSchema, codeMdx, type CodeData } from \"./code.config.js\";\n\n/**\n * Standard `code` block (STANDARD core library): THE primitive single code\n * snippet, used everywhere in plan + content. Notion-style — one border, a\n * hover-revealed language switcher + copy, and the shared collapse-to-N-lines\n * read surface. A \"file rail\" of several files is just the `tabs` primitive\n * holding `code` blocks; there is no bespoke \"code-tabs\" container.\n *\n * Read = the shared {@link CodeSurface} (Shiki, single border, language label,\n * \"Show N more lines\"). Edit = a clean, single-border editable surface (no\n * drag-to-resize; it auto-grows to its content) with the same hover chrome.\n */\n\n/** Language options for the hover switcher; \"\" is the Auto-detect sentinel. */\nconst CODE_LANGUAGES: ReadonlyArray<{ value: string; label: string }> = [\n { value: \"\", label: \"Auto\" },\n { value: \"typescript\", label: \"TypeScript\" },\n { value: \"javascript\", label: \"JavaScript\" },\n { value: \"tsx\", label: \"TSX\" },\n { value: \"jsx\", label: \"JSX\" },\n { value: \"json\", label: \"JSON\" },\n { value: \"html\", label: \"HTML\" },\n { value: \"css\", label: \"CSS\" },\n { value: \"bash\", label: \"Bash\" },\n { value: \"python\", label: \"Python\" },\n { value: \"sql\", label: \"SQL\" },\n { value: \"yaml\", label: \"YAML\" },\n { value: \"markdown\", label: \"Markdown\" },\n { value: \"graphql\", label: \"GraphQL\" },\n { value: \"go\", label: \"Go\" },\n { value: \"rust\", label: \"Rust\" },\n { value: \"diff\", label: \"Diff\" },\n];\n\nfunction CopyButton({ value }: { value: string }) {\n const [copied, setCopied] = useState(false);\n return (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={copied ? \"Copied\" : \"Copy code\"}\n title={copied ? \"Copied\" : \"Copy code\"}\n className=\"plan-code-chip\"\n onClick={() => {\n void navigator.clipboard?.writeText(value).then(\n () => {\n setCopied(true);\n setTimeout(() => setCopied(false), 1200);\n },\n () => {},\n );\n }}\n >\n {copied ? (\n <IconCheck className=\"size-3.5\" />\n ) : (\n <IconCopy className=\"size-3.5\" />\n )}\n </button>\n );\n}\n\n/* ── Read ──────────────────────────────────────────────────────────────────── */\n\nfunction CodeRead({ data, blockId }: BlockReadProps<CodeData>) {\n const language =\n normalizeCodeLanguage(data.language) ??\n inferLanguageFromFilename(data.filename) ??\n undefined;\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n <div className=\"plan-code group relative\">\n {data.filename && (\n <div className=\"plan-code-head\">\n <span className=\"plan-code-filename\">\n <IconCode className=\"size-4 shrink-0 opacity-70\" />\n {data.filename}\n </span>\n <span className=\"plan-code-chrome\">\n <CopyButton value={data.code} />\n </span>\n </div>\n )}\n <CodeSurface\n code={data.code}\n language={language}\n maxLines={data.maxLines}\n className={data.filename ? \"mt-0\" : \"mt-0\"}\n />\n {!data.filename && (\n <span className=\"plan-code-chrome plan-code-chrome-float\">\n <CopyButton value={data.code} />\n </span>\n )}\n {data.caption && <p className=\"plan-code-caption\">{data.caption}</p>}\n </div>\n </section>\n );\n}\n\n/* ── Edit (single border, no resize, auto-grow, hover chrome) ──────────────── */\n\nconst SETTINGS_INPUT =\n \"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50\";\n\n/** Hover \"settings\" (pencil) → popover to edit the filename + max-lines cap. */\nfunction CodeSettingsPopover({\n filename,\n maxLines,\n onFilenameChange,\n onMaxLinesChange,\n}: {\n filename?: string;\n maxLines?: number;\n onFilenameChange: (filename: string | undefined) => void;\n onMaxLinesChange: (maxLines: number | undefined) => void;\n}) {\n return (\n <Popover>\n <PopoverTrigger asChild>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Code block settings\"\n title=\"Code block settings\"\n className=\"plan-code-chip\"\n >\n <IconPencil className=\"size-3.5\" />\n </button>\n </PopoverTrigger>\n <PopoverContent\n align=\"end\"\n side=\"bottom\"\n className=\"w-64 p-0\"\n data-plan-interactive\n >\n <div className=\"border-b border-border px-3 py-2 text-sm font-semibold text-foreground\">\n Code block\n </div>\n <div className=\"grid gap-3 p-3\">\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Filename\n </span>\n <input\n type=\"text\"\n data-plan-interactive\n className={SETTINGS_INPUT}\n placeholder=\"src/file.ts\"\n value={filename ?? \"\"}\n onChange={(event) =>\n onFilenameChange(event.target.value || undefined)\n }\n />\n </label>\n <label className=\"grid gap-1.5\">\n <span className=\"text-xs font-medium text-muted-foreground\">\n Max lines before expand\n </span>\n <input\n type=\"number\"\n min={0}\n step={1}\n data-plan-interactive\n className={SETTINGS_INPUT}\n placeholder={`${DEFAULT_CODE_MAX_LINES} (default) · 0 = no limit`}\n value={maxLines ?? \"\"}\n onChange={(event) => {\n const raw = event.target.value.trim();\n const parsed = raw === \"\" ? undefined : Number(raw);\n onMaxLinesChange(\n parsed === undefined || Number.isNaN(parsed)\n ? undefined\n : Math.max(0, Math.min(2000, Math.floor(parsed))),\n );\n }}\n />\n </label>\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\nfunction CodeEditorSurface({\n code,\n language,\n filename,\n maxLines,\n editable,\n onCodeChange,\n onLanguageChange,\n onFilenameChange,\n onMaxLinesChange,\n}: {\n code: string;\n language?: string;\n filename?: string;\n maxLines?: number;\n editable: boolean;\n onCodeChange: (code: string) => void;\n onLanguageChange: (language: string | undefined) => void;\n onFilenameChange: (filename: string | undefined) => void;\n onMaxLinesChange: (maxLines: number | undefined) => void;\n}) {\n const [expanded, setExpanded] = useState(false);\n const highlightLayerRef = useRef<HTMLPreElement>(null);\n const selectId = useId();\n const resolvedLanguage =\n normalizeCodeLanguage(language) ?? inferLanguageFromFilename(filename);\n const highlighted = useMemo(\n () => highlightCode(code, resolvedLanguage),\n [resolvedLanguage, code],\n );\n // Size the editor to its content by line count — deterministic, no layout\n // measurement. `wrap=\"off\"` means one row per line. Long snippets collapse to\n // `cap` lines behind a \"Show N more lines\" toggle, matching the read surface\n // and the file-tree block. `maxLines` omitted ⇒ DEFAULT (40); `0` ⇒ never\n // collapse (show everything).\n const lineCount = code ? code.split(\"\\n\").length : 1;\n const cap =\n maxLines == null ? DEFAULT_CODE_MAX_LINES : maxLines > 0 ? maxLines : null;\n const collapsible = cap != null && lineCount > cap;\n const collapsed = collapsible && !expanded;\n const hiddenLines = collapsible ? lineCount - (cap as number) : 0;\n const rows = collapsed ? (cap as number) : lineCount + 1;\n\n const syncScroll = (event: UIEvent<HTMLTextAreaElement>) => {\n const layer = highlightLayerRef.current;\n if (!layer) return;\n layer.scrollLeft = event.currentTarget.scrollLeft;\n };\n\n return (\n <div\n className={cn(\n \"plan-code plan-code-editing group relative\",\n !editable && \"opacity-60\",\n )}\n >\n <div className=\"plan-code-head\">\n <span className=\"plan-code-filename plan-code-muted\">\n <IconCode className=\"size-4 shrink-0 opacity-70\" />\n {filename || \"Snippet\"}\n </span>\n <span className=\"plan-code-chrome\">\n <label htmlFor={selectId} className=\"sr-only\">\n Code language\n </label>\n <select\n id={selectId}\n data-plan-interactive\n disabled={!editable}\n className=\"plan-code-lang-select\"\n value={normalizeCodeLanguage(language) ? (language ?? \"\") : \"\"}\n onChange={(event) =>\n onLanguageChange(event.target.value || undefined)\n }\n >\n {CODE_LANGUAGES.map((option) => (\n <option key={option.value || \"auto\"} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n {editable && (\n <CodeSettingsPopover\n filename={filename}\n maxLines={maxLines}\n onFilenameChange={onFilenameChange}\n onMaxLinesChange={onMaxLinesChange}\n />\n )}\n <CopyButton value={code} />\n </span>\n </div>\n <div className=\"plan-code-editor-body\">\n <pre\n ref={highlightLayerRef}\n aria-hidden=\"true\"\n className=\"plan-code-editor-layer\"\n >\n <code>\n {highlighted}\n {code.endsWith(\"\\n\") ? \" \" : null}\n </code>\n </pre>\n <textarea\n data-plan-interactive\n spellCheck={false}\n wrap=\"off\"\n rows={Math.max(3, rows)}\n className=\"plan-code-editor-input\"\n value={code}\n disabled={!editable}\n onChange={(event: ChangeEvent<HTMLTextAreaElement>) =>\n onCodeChange(event.target.value)\n }\n onScroll={syncScroll}\n />\n {collapsed && (\n <div className=\"plan-code-editor-fade\" aria-hidden=\"true\" />\n )}\n </div>\n {collapsible && (\n <button\n type=\"button\"\n data-plan-interactive\n className=\"plan-code-surface-toggle\"\n onClick={() => setExpanded((value) => !value)}\n >\n {collapsed\n ? `Show ${hiddenLines} more line${hiddenLines === 1 ? \"\" : \"s\"}`\n : \"Show less\"}\n </button>\n )}\n </div>\n );\n}\n\nfunction CodeEdit({ data, onChange, editable }: BlockEditProps<CodeData>) {\n return (\n <div className=\"flex min-w-0 flex-col gap-2\">\n <CodeEditorSurface\n code={data.code}\n language={data.language}\n filename={data.filename}\n maxLines={data.maxLines}\n editable={editable}\n onCodeChange={(code) => onChange({ ...data, code })}\n onLanguageChange={(language) => onChange({ ...data, language })}\n onFilenameChange={(filename) => onChange({ ...data, filename })}\n onMaxLinesChange={(maxLines) => onChange({ ...data, maxLines })}\n />\n {editable && (\n <input\n type=\"text\"\n data-plan-interactive\n className=\"plan-code-caption-input\"\n placeholder=\"Caption (optional)\"\n value={data.caption ?? \"\"}\n onChange={(event) =>\n onChange({ ...data, caption: event.target.value || undefined })\n }\n />\n )}\n </div>\n );\n}\n\n/* ── Spec ──────────────────────────────────────────────────────────────────── */\n\nexport const codeBlock = defineBlock<CodeData>({\n type: \"code\",\n schema: codeSchema,\n mdx: codeMdx,\n Read: CodeRead,\n Edit: CodeEdit,\n placement: [\"block\"],\n editSurface: \"inline\",\n label: \"Code\",\n icon: IconCode,\n description:\n \"A single syntax-highlighted code snippet, Notion-style: one border, a hover language switcher + copy, and collapse-to-N lines. Put several in a `tabs` block for a file rail.\",\n});\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"columns.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,qBAAqB,CAAC;AAiG7B,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CAmB7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CAmE7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,8CA0DvB,CAAC"}
1
+ {"version":3,"file":"columns.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,cAAc,EACd,cAAc,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAGL,KAAK,WAAW,EAEjB,MAAM,qBAAqB,CAAC;AAsH7B,kFAAkF;AAClF,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CAsB7B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CAsE7B;AAED;;;;;GAKG;AACH,eAAO,MAAM,YAAY,8CA0DvB,CAAC"}