@agent-native/core 0.41.1 → 0.43.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 (181) hide show
  1. package/README.md +17 -56
  2. package/dist/action.d.ts +13 -1
  3. package/dist/action.d.ts.map +1 -1
  4. package/dist/action.js.map +1 -1
  5. package/dist/agent/production-agent.d.ts +8 -0
  6. package/dist/agent/production-agent.d.ts.map +1 -1
  7. package/dist/agent/production-agent.js +93 -0
  8. package/dist/agent/production-agent.js.map +1 -1
  9. package/dist/cli/app-skill.d.ts +16 -0
  10. package/dist/cli/app-skill.d.ts.map +1 -1
  11. package/dist/cli/app-skill.js +33 -3
  12. package/dist/cli/app-skill.js.map +1 -1
  13. package/dist/cli/pr-visual-recap-workflow.d.ts +1 -1
  14. package/dist/cli/pr-visual-recap-workflow.d.ts.map +1 -1
  15. package/dist/cli/pr-visual-recap-workflow.js +1 -1
  16. package/dist/cli/pr-visual-recap-workflow.js.map +1 -1
  17. package/dist/cli/recap.d.ts.map +1 -1
  18. package/dist/cli/recap.js +38 -16
  19. package/dist/cli/recap.js.map +1 -1
  20. package/dist/cli/skills.d.ts +30 -3
  21. package/dist/cli/skills.d.ts.map +1 -1
  22. package/dist/cli/skills.js +180 -114
  23. package/dist/cli/skills.js.map +1 -1
  24. package/dist/client/AssistantChat.d.ts.map +1 -1
  25. package/dist/client/AssistantChat.js +2 -2
  26. package/dist/client/AssistantChat.js.map +1 -1
  27. package/dist/client/agent-chat-adapter.d.ts.map +1 -1
  28. package/dist/client/agent-chat-adapter.js +172 -5
  29. package/dist/client/agent-chat-adapter.js.map +1 -1
  30. package/dist/client/blocks/index.d.ts +11 -0
  31. package/dist/client/blocks/index.d.ts.map +1 -1
  32. package/dist/client/blocks/index.js +11 -0
  33. package/dist/client/blocks/index.js.map +1 -1
  34. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts +19 -0
  35. package/dist/client/blocks/library/AnnotatedCodeBlock.d.ts.map +1 -1
  36. package/dist/client/blocks/library/AnnotatedCodeBlock.js +6 -58
  37. package/dist/client/blocks/library/AnnotatedCodeBlock.js.map +1 -1
  38. package/dist/client/blocks/library/ApiEndpointBlock.d.ts.map +1 -1
  39. package/dist/client/blocks/library/ApiEndpointBlock.js +116 -7
  40. package/dist/client/blocks/library/ApiEndpointBlock.js.map +1 -1
  41. package/dist/client/blocks/library/DataModelBlock.d.ts.map +1 -1
  42. package/dist/client/blocks/library/DataModelBlock.js +75 -9
  43. package/dist/client/blocks/library/DataModelBlock.js.map +1 -1
  44. package/dist/client/blocks/library/DiffBlock.d.ts +1 -1
  45. package/dist/client/blocks/library/DiffBlock.d.ts.map +1 -1
  46. package/dist/client/blocks/library/DiffBlock.js +265 -39
  47. package/dist/client/blocks/library/DiffBlock.js.map +1 -1
  48. package/dist/client/blocks/library/FileTreeBlock.d.ts.map +1 -1
  49. package/dist/client/blocks/library/FileTreeBlock.js +27 -4
  50. package/dist/client/blocks/library/FileTreeBlock.js.map +1 -1
  51. package/dist/client/blocks/library/HighlightedCode.d.ts +1 -1
  52. package/dist/client/blocks/library/HighlightedCode.js +1 -1
  53. package/dist/client/blocks/library/HighlightedCode.js.map +1 -1
  54. package/dist/client/blocks/library/JsonExplorerBlock.js +1 -1
  55. package/dist/client/blocks/library/JsonExplorerBlock.js.map +1 -1
  56. package/dist/client/blocks/library/MermaidBlock.js +1 -1
  57. package/dist/client/blocks/library/MermaidBlock.js.map +1 -1
  58. package/dist/client/blocks/library/annotation-rail.d.ts +115 -0
  59. package/dist/client/blocks/library/annotation-rail.d.ts.map +1 -0
  60. package/dist/client/blocks/library/annotation-rail.js +139 -0
  61. package/dist/client/blocks/library/annotation-rail.js.map +1 -0
  62. package/dist/client/blocks/library/api-endpoint.config.d.ts +31 -6
  63. package/dist/client/blocks/library/api-endpoint.config.d.ts.map +1 -1
  64. package/dist/client/blocks/library/api-endpoint.config.js +30 -6
  65. package/dist/client/blocks/library/api-endpoint.config.js.map +1 -1
  66. package/dist/client/blocks/library/callout.config.d.ts +29 -0
  67. package/dist/client/blocks/library/callout.config.d.ts.map +1 -0
  68. package/dist/client/blocks/library/callout.config.js +33 -0
  69. package/dist/client/blocks/library/callout.config.js.map +1 -0
  70. package/dist/client/blocks/library/callout.d.ts +20 -0
  71. package/dist/client/blocks/library/callout.d.ts.map +1 -0
  72. package/dist/client/blocks/library/callout.js +61 -0
  73. package/dist/client/blocks/library/callout.js.map +1 -0
  74. package/dist/client/blocks/library/checklist.d.ts.map +1 -1
  75. package/dist/client/blocks/library/checklist.js +3 -3
  76. package/dist/client/blocks/library/checklist.js.map +1 -1
  77. package/dist/client/blocks/library/code.d.ts.map +1 -1
  78. package/dist/client/blocks/library/code.js +32 -15
  79. package/dist/client/blocks/library/code.js.map +1 -1
  80. package/dist/client/blocks/library/columns.d.ts.map +1 -1
  81. package/dist/client/blocks/library/columns.js +56 -35
  82. package/dist/client/blocks/library/columns.js.map +1 -1
  83. package/dist/client/blocks/library/data-model.config.d.ts +17 -0
  84. package/dist/client/blocks/library/data-model.config.d.ts.map +1 -1
  85. package/dist/client/blocks/library/data-model.config.js +15 -0
  86. package/dist/client/blocks/library/data-model.config.js.map +1 -1
  87. package/dist/client/blocks/library/decision.config.d.ts +37 -0
  88. package/dist/client/blocks/library/decision.config.d.ts.map +1 -0
  89. package/dist/client/blocks/library/decision.config.js +32 -0
  90. package/dist/client/blocks/library/decision.config.js.map +1 -0
  91. package/dist/client/blocks/library/decision.d.ts +19 -0
  92. package/dist/client/blocks/library/decision.d.ts.map +1 -0
  93. package/dist/client/blocks/library/decision.js +119 -0
  94. package/dist/client/blocks/library/decision.js.map +1 -0
  95. package/dist/client/blocks/library/diagram.config.d.ts +64 -0
  96. package/dist/client/blocks/library/diagram.config.d.ts.map +1 -0
  97. package/dist/client/blocks/library/diagram.config.js +111 -0
  98. package/dist/client/blocks/library/diagram.config.js.map +1 -0
  99. package/dist/client/blocks/library/diagram.d.ts +16 -0
  100. package/dist/client/blocks/library/diagram.d.ts.map +1 -0
  101. package/dist/client/blocks/library/diagram.js +261 -0
  102. package/dist/client/blocks/library/diagram.js.map +1 -0
  103. package/dist/client/blocks/library/diff.config.d.ts +28 -6
  104. package/dist/client/blocks/library/diff.config.d.ts.map +1 -1
  105. package/dist/client/blocks/library/diff.config.js +30 -6
  106. package/dist/client/blocks/library/diff.config.js.map +1 -1
  107. package/dist/client/blocks/library/question-form.config.d.ts +69 -0
  108. package/dist/client/blocks/library/question-form.config.d.ts.map +1 -0
  109. package/dist/client/blocks/library/question-form.config.js +58 -0
  110. package/dist/client/blocks/library/question-form.config.js.map +1 -0
  111. package/dist/client/blocks/library/question-form.d.ts +20 -0
  112. package/dist/client/blocks/library/question-form.d.ts.map +1 -0
  113. package/dist/client/blocks/library/question-form.js +286 -0
  114. package/dist/client/blocks/library/question-form.js.map +1 -0
  115. package/dist/client/blocks/library/sanitize-html.d.ts +5 -0
  116. package/dist/client/blocks/library/sanitize-html.d.ts.map +1 -0
  117. package/dist/client/blocks/library/sanitize-html.js +240 -0
  118. package/dist/client/blocks/library/sanitize-html.js.map +1 -0
  119. package/dist/client/blocks/library/server-specs.d.ts.map +1 -1
  120. package/dist/client/blocks/library/server-specs.js +59 -0
  121. package/dist/client/blocks/library/server-specs.js.map +1 -1
  122. package/dist/client/blocks/library/specs.d.ts.map +1 -1
  123. package/dist/client/blocks/library/specs.js +11 -0
  124. package/dist/client/blocks/library/specs.js.map +1 -1
  125. package/dist/client/blocks/library/tabs.d.ts.map +1 -1
  126. package/dist/client/blocks/library/tabs.js +12 -12
  127. package/dist/client/blocks/library/tabs.js.map +1 -1
  128. package/dist/client/blocks/library/wireframe-kit.d.ts +260 -0
  129. package/dist/client/blocks/library/wireframe-kit.d.ts.map +1 -0
  130. package/dist/client/blocks/library/wireframe-kit.js +920 -0
  131. package/dist/client/blocks/library/wireframe-kit.js.map +1 -0
  132. package/dist/client/blocks/library/wireframe.config.d.ts +123 -0
  133. package/dist/client/blocks/library/wireframe.config.d.ts.map +1 -0
  134. package/dist/client/blocks/library/wireframe.config.js +294 -0
  135. package/dist/client/blocks/library/wireframe.config.js.map +1 -0
  136. package/dist/client/blocks/library/wireframe.d.ts +15 -0
  137. package/dist/client/blocks/library/wireframe.d.ts.map +1 -0
  138. package/dist/client/blocks/library/wireframe.js +206 -0
  139. package/dist/client/blocks/library/wireframe.js.map +1 -0
  140. package/dist/client/blocks/registry.d.ts +9 -0
  141. package/dist/client/blocks/registry.d.ts.map +1 -1
  142. package/dist/client/blocks/registry.js +12 -5
  143. package/dist/client/blocks/registry.js.map +1 -1
  144. package/dist/client/blocks/server.d.ts +1 -0
  145. package/dist/client/blocks/server.d.ts.map +1 -1
  146. package/dist/client/blocks/server.js +1 -0
  147. package/dist/client/blocks/server.js.map +1 -1
  148. package/dist/client/blocks/types.d.ts +10 -2
  149. package/dist/client/blocks/types.d.ts.map +1 -1
  150. package/dist/client/blocks/types.js.map +1 -1
  151. package/dist/client/rich-markdown-editor/DragHandle.d.ts.map +1 -1
  152. package/dist/client/rich-markdown-editor/DragHandle.js +152 -21
  153. package/dist/client/rich-markdown-editor/DragHandle.js.map +1 -1
  154. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts +25 -1
  155. package/dist/client/rich-markdown-editor/RegistryBlockNode.d.ts.map +1 -1
  156. package/dist/client/rich-markdown-editor/RegistryBlockNode.js +29 -6
  157. package/dist/client/rich-markdown-editor/RegistryBlockNode.js.map +1 -1
  158. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts +8 -1
  159. package/dist/client/rich-markdown-editor/SharedRichEditor.d.ts.map +1 -1
  160. package/dist/client/rich-markdown-editor/SharedRichEditor.js +5 -1
  161. package/dist/client/rich-markdown-editor/SharedRichEditor.js.map +1 -1
  162. package/dist/extensions/actions.d.ts.map +1 -1
  163. package/dist/extensions/actions.js +159 -12
  164. package/dist/extensions/actions.js.map +1 -1
  165. package/dist/extensions/store.d.ts +21 -0
  166. package/dist/extensions/store.d.ts.map +1 -1
  167. package/dist/extensions/store.js +33 -1
  168. package/dist/extensions/store.js.map +1 -1
  169. package/dist/server/recap-image-route.d.ts.map +1 -1
  170. package/dist/server/recap-image-route.js +12 -3
  171. package/dist/server/recap-image-route.js.map +1 -1
  172. package/dist/styles/agent-native.css +1 -0
  173. package/dist/styles/blocks.css +1380 -0
  174. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
  175. package/docs/content/plan-plugin.md +107 -0
  176. package/docs/content/pr-visual-recap.md +2 -2
  177. package/docs/content/skills-guide.md +8 -0
  178. package/docs/content/template-plan.md +94 -17
  179. package/package.json +2 -1
  180. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +30 -5
  181. package/docs/content/visual-plans.md +0 -80
@@ -0,0 +1,115 @@
1
+ import { type ReactNode } from "react";
2
+ import type { BlockRenderContext } from "../types.js";
3
+ /**
4
+ * Shared line-anchored annotation UI for the `annotated-code` and `diff` blocks.
5
+ *
6
+ * Both blocks render a numbered code surface plus a side "rail" of notes, where
7
+ * each note targets a 1-based `lines` ref (`"3"` or `"3-5"`) and hovering a code
8
+ * line ↔ its note cross-highlights. This module owns the pure pieces that were
9
+ * identical between them so neither block forks the behavior:
10
+ *
11
+ * - `parseLineRange` — the forgiving 1-based `lines` range parser.
12
+ * - `resolveAnnotations` / `buildLineMarkerMap` — turn a raw annotation list
13
+ * into stable, marker-numbered, range-resolved records and a line→markers map.
14
+ * - `rangeLabel` — the human "Line 8" / "Lines 3–6" label.
15
+ * - `AnnotationGutterMarker` — the numbered amber pip placed on an annotated row
16
+ * (used by the diff grid; the annotated-code surface uses its own rail bar).
17
+ * - `AnnotationNoteRail` — the responsive list of note cards with two-way hover.
18
+ * `showMarker` opts the diff block into a leading numbered pip on each card so
19
+ * a note can be matched to its `①`/`②` row marker; annotated-code omits it to
20
+ * keep its original card chrome.
21
+ *
22
+ * `AnnotatedCodeBlock` annotates a single code surface; `DiffBlock` annotates a
23
+ * before/after grid (each annotation also carries a `side`). The shared types
24
+ * here are intentionally minimal — callers pass their own `side` handling and
25
+ * decide which rows a marker lands on; this module only owns the parsing, the
26
+ * resolved-record shape, and the rendered marker + rail chrome.
27
+ */
28
+ /**
29
+ * Parse a 1-based `lines` ref (`"3"` or `"3-5"`) into an inclusive `[start,end]`
30
+ * pair, clamped to `[1, lineCount]`. Returns `null` for malformed or fully
31
+ * out-of-range refs so callers can ignore them gracefully. A reversed range
32
+ * (`"5-3"`) is normalized; a partially out-of-range range is clamped.
33
+ */
34
+ export declare function parseLineRange(ref: string, lineCount: number): {
35
+ start: number;
36
+ end: number;
37
+ } | null;
38
+ /** The minimal annotation shape the rail needs (a superset works too). */
39
+ export interface RailAnnotation {
40
+ lines: string;
41
+ label?: string;
42
+ note: string;
43
+ }
44
+ export interface ResolvedAnnotation<A extends RailAnnotation = RailAnnotation> {
45
+ /** Index in the original `annotations` array (stable hover key). */
46
+ index: number;
47
+ /** 1-based marker number (authoring order). */
48
+ marker: number;
49
+ annotation: A;
50
+ range: {
51
+ start: number;
52
+ end: number;
53
+ } | null;
54
+ }
55
+ /**
56
+ * Resolve a raw annotation list into stable, marker-numbered records, parsing
57
+ * each `lines` ref against `lineCount`. `lineCountFor` lets the diff block pick a
58
+ * per-annotation line count (before-side vs after-side); annotated-code passes a
59
+ * single constant. Markers are authoring-order, 1-based, and assigned to ALL
60
+ * annotations (even unresolved ones) so numbering is stable regardless of which
61
+ * refs happen to match.
62
+ */
63
+ export declare function resolveAnnotations<A extends RailAnnotation>(annotations: A[] | undefined, lineCountFor: (annotation: A) => number): ResolvedAnnotation<A>[];
64
+ /** Map a 1-based line number → the resolved annotations covering it. */
65
+ export declare function buildLineMarkerMap<A extends RailAnnotation>(resolved: ResolvedAnnotation<A>[]): Map<number, ResolvedAnnotation<A>[]>;
66
+ /** Human label for a resolved annotation's line span ("Line 8" / "Lines 3–6"). */
67
+ export declare function rangeLabel(item: ResolvedAnnotation): string;
68
+ /**
69
+ * The numbered amber pip rendered on an annotated code row's gutter. `active`
70
+ * brightens it when its note (or a co-located row) is hovered.
71
+ */
72
+ export declare function AnnotationGutterMarker({ marker, active, className, }: {
73
+ marker: number;
74
+ active: boolean;
75
+ className?: string;
76
+ }): import("react/jsx-runtime").JSX.Element;
77
+ /**
78
+ * The responsive list of line-anchored note cards. Each card shows its marker
79
+ * pip, the resolved line span ("Line 8"), an optional label, and the markdown
80
+ * `note` (via `ctx.renderMarkdown`). Hovering a card sets the active index;
81
+ * `activeIndex` driven from outside lets a hovered code row light its card and
82
+ * vice-versa. Only annotations whose `range` resolved are listed.
83
+ */
84
+ export declare function AnnotationNoteRail<A extends RailAnnotation>({ items, activeIndex, onActiveChange, ctx, className, showMarker, }: {
85
+ items: ResolvedAnnotation<A>[];
86
+ activeIndex: number | null;
87
+ onActiveChange: (index: number | null) => void;
88
+ ctx: BlockRenderContext;
89
+ className?: string;
90
+ /** Show a leading numbered pip on each card (diff block). */
91
+ showMarker?: boolean;
92
+ }): import("react/jsx-runtime").JSX.Element;
93
+ /**
94
+ * A single line-anchored note rendered INLINE in the diff flow — full-width,
95
+ * directly under the line it annotates — instead of in a side rail (the
96
+ * GitHub-review affordance). The diff block places one of these after the first
97
+ * row of each annotation's range, so the numbered `①`/`②` row marker and the note
98
+ * read together in one column. It carries the same marker pip, line range,
99
+ * optional label, and markdown `note` as a rail card, and the same two-way hover
100
+ * wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.
101
+ *
102
+ * The outer band is `min-w-full` so the amber wash spans the diff's full scroll
103
+ * width; the content is `sticky left-0` with a readable `max-w` so the note stays
104
+ * pinned and legible while long code lines scroll horizontally beneath it.
105
+ */
106
+ export declare function InlineAnnotationNote<A extends RailAnnotation>({ item, active, onActiveChange, ctx, }: {
107
+ item: ResolvedAnnotation<A>;
108
+ active: boolean;
109
+ onActiveChange: (index: number | null) => void;
110
+ ctx: BlockRenderContext;
111
+ }): import("react/jsx-runtime").JSX.Element;
112
+ /** Whether a resolved list has at least one note worth rendering a rail for. */
113
+ export declare function hasRailAnnotations(items: ResolvedAnnotation[]): boolean;
114
+ export type AnnotationRailChildren = ReactNode;
115
+ //# sourceMappingURL=annotation-rail.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"annotation-rail.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/annotation-rail.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
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
+ /* ── Inline note (GitHub-style) ─────────────────────────────────────────────── */
117
+ /**
118
+ * A single line-anchored note rendered INLINE in the diff flow — full-width,
119
+ * directly under the line it annotates — instead of in a side rail (the
120
+ * GitHub-review affordance). The diff block places one of these after the first
121
+ * row of each annotation's range, so the numbered `①`/`②` row marker and the note
122
+ * read together in one column. It carries the same marker pip, line range,
123
+ * optional label, and markdown `note` as a rail card, and the same two-way hover
124
+ * wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.
125
+ *
126
+ * The outer band is `min-w-full` so the amber wash spans the diff's full scroll
127
+ * width; the content is `sticky left-0` with a readable `max-w` so the note stays
128
+ * pinned and legible while long code lines scroll horizontally beneath it.
129
+ */
130
+ export function InlineAnnotationNote({ item, active, onActiveChange, ctx, }) {
131
+ return (_jsx("div", { onMouseEnter: () => onActiveChange(item.index), onMouseLeave: () => onActiveChange(null), className: cn("min-w-full border-y transition-colors", active
132
+ ? "border-amber-400/60 bg-amber-100/70 dark:border-amber-300/40 dark:bg-amber-300/[0.12]"
133
+ : "border-amber-400/30 bg-amber-50/70 dark:border-amber-300/20 dark:bg-amber-300/[0.06]"), children: _jsxs("div", { className: "sticky left-0 flex max-w-[44rem] gap-2.5 whitespace-normal px-3 py-2.5 font-sans", children: [_jsx(AnnotationGutterMarker, { marker: item.marker, active: active }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2 gap-y-0.5", children: [_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 })) })] })] }) }));
134
+ }
135
+ /** Whether a resolved list has at least one note worth rendering a rail for. */
136
+ export function hasRailAnnotations(items) {
137
+ return items.some((item) => item.range);
138
+ }
139
+ //# 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/* ── Inline note (GitHub-style) ─────────────────────────────────────────────── */\n\n/**\n * A single line-anchored note rendered INLINE in the diff flow — full-width,\n * directly under the line it annotates — instead of in a side rail (the\n * GitHub-review affordance). The diff block places one of these after the first\n * row of each annotation's range, so the numbered `①`/`②` row marker and the note\n * read together in one column. It carries the same marker pip, line range,\n * optional label, and markdown `note` as a rail card, and the same two-way hover\n * wiring (`active` / `onActiveChange`) so the row and its note cross-highlight.\n *\n * The outer band is `min-w-full` so the amber wash spans the diff's full scroll\n * width; the content is `sticky left-0` with a readable `max-w` so the note stays\n * pinned and legible while long code lines scroll horizontally beneath it.\n */\nexport function InlineAnnotationNote<A extends RailAnnotation>({\n item,\n active,\n onActiveChange,\n ctx,\n}: {\n item: ResolvedAnnotation<A>;\n active: boolean;\n onActiveChange: (index: number | null) => void;\n ctx: BlockRenderContext;\n}) {\n return (\n <div\n onMouseEnter={() => onActiveChange(item.index)}\n onMouseLeave={() => onActiveChange(null)}\n className={cn(\n \"min-w-full border-y transition-colors\",\n active\n ? \"border-amber-400/60 bg-amber-100/70 dark:border-amber-300/40 dark:bg-amber-300/[0.12]\"\n : \"border-amber-400/30 bg-amber-50/70 dark:border-amber-300/20 dark:bg-amber-300/[0.06]\",\n )}\n >\n <div className=\"sticky left-0 flex max-w-[44rem] gap-2.5 whitespace-normal px-3 py-2.5 font-sans\">\n <AnnotationGutterMarker marker={item.marker} active={active} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex flex-wrap items-baseline gap-x-2 gap-y-0.5\">\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 </div>\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":"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;AAkCF,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;CACrD,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;CAC3C,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,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;;;;;;;;;;GAUG;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,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,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\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":"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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\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"]}
@@ -0,0 +1,29 @@
1
+ import { z } from "zod";
2
+ import type { BlockMdxConfig } from "../types.js";
3
+ /**
4
+ * Pure (React-free) part of the shared `callout` block: its data schema and MDX
5
+ * round-trip config. Lives in core so BOTH apps' server/shared registries
6
+ * (`plan-block-registry.ts`, `nfm-registry.ts`) and the client spec
7
+ * (`callout.tsx`) consume one definition. Keeping it React-free means importing
8
+ * it into a server module never pulls React into the Nitro/SSR bundle.
9
+ *
10
+ * The MDX `tag` + attribute/children shape MUST match the legacy
11
+ * `<Callout tone>…body…</Callout>` encoding so stored `.mdx` round-trips
12
+ * byte-compatibly (the block originated in the plan template before moving here).
13
+ */
14
+ export type CalloutTone = "info" | "decision" | "risk" | "warning" | "success";
15
+ export interface CalloutData {
16
+ tone?: CalloutTone;
17
+ /** Markdown body. Tagged `markdown()` so the auto-editor edits it inline. */
18
+ body: string;
19
+ }
20
+ export declare const CALLOUT_TONES: CalloutTone[];
21
+ export declare const calloutSchema: z.ZodType<CalloutData>;
22
+ /**
23
+ * MDX config: `tone` is an attribute, `body` is MDX children — exactly the
24
+ * legacy `<Callout id … tone>\n\n{body}\n\n</Callout>` form. `toAttrs` returns
25
+ * only `tone` (body is `childrenField`, excluded from attributes); `fromAttrs`
26
+ * reads `tone` and uses the stringified prose children as `body`.
27
+ */
28
+ export declare const calloutMdx: BlockMdxConfig<CalloutData>;
29
+ //# sourceMappingURL=callout.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callout.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/callout.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;AAE/E,MAAM,WAAW,WAAW;IAC1B,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,eAAO,MAAM,aAAa,EAAE,WAAW,EAMtC,CAAC;AAEF,eAAO,MAAM,aAAa,EAOT,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAExC;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,WAAW,CAQlD,CAAC"}
@@ -0,0 +1,33 @@
1
+ import { z } from "zod";
2
+ import { markdown } from "../schema-form/introspect.js";
3
+ export const CALLOUT_TONES = [
4
+ "info",
5
+ "decision",
6
+ "risk",
7
+ "warning",
8
+ "success",
9
+ ];
10
+ export const calloutSchema = z.object({
11
+ tone: z
12
+ .enum(["info", "decision", "risk", "warning", "success"])
13
+ .optional(),
14
+ // `markdown()` tags the field so `SchemaBlockEditor` renders it with the
15
+ // shared rich-markdown editor (inline, Notion-style) instead of a textarea.
16
+ body: markdown(z.string().trim().min(1).max(10_000)),
17
+ });
18
+ /**
19
+ * MDX config: `tone` is an attribute, `body` is MDX children — exactly the
20
+ * legacy `<Callout id … tone>\n\n{body}\n\n</Callout>` form. `toAttrs` returns
21
+ * only `tone` (body is `childrenField`, excluded from attributes); `fromAttrs`
22
+ * reads `tone` and uses the stringified prose children as `body`.
23
+ */
24
+ export const calloutMdx = {
25
+ tag: "Callout",
26
+ childrenField: "body",
27
+ toAttrs: (data) => ({ tone: data.tone }),
28
+ fromAttrs: (attrs, children) => ({
29
+ tone: attrs.string("tone"),
30
+ body: children,
31
+ }),
32
+ };
33
+ //# sourceMappingURL=callout.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callout.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/callout.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AAuBxD,MAAM,CAAC,MAAM,aAAa,GAAkB;IAC1C,MAAM;IACN,UAAU;IACV,MAAM;IACN,SAAS;IACT,SAAS;CACV,CAAC;AAEF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,CAAC,CAAC;SACxD,QAAQ,EAAwC;IACnD,yEAAyE;IACzE,4EAA4E;IAC5E,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAsB;CAC1E,CAAsC,CAAC;AAExC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAgC;IACrD,GAAG,EAAE,SAAS;IACd,aAAa,EAAE,MAAM;IACrB,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;IACxC,SAAS,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC/B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,CAA4B;QACrD,IAAI,EAAE,QAAQ;KACf,CAAC;CACH,CAAC","sourcesContent":["import { z } from \"zod\";\nimport { markdown } from \"../schema-form/introspect.js\";\nimport type { BlockMdxConfig } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the shared `callout` block: its data schema and MDX\n * round-trip config. Lives in core so BOTH apps' server/shared registries\n * (`plan-block-registry.ts`, `nfm-registry.ts`) and the client spec\n * (`callout.tsx`) consume one definition. Keeping it React-free means importing\n * it into a server module never pulls React into the Nitro/SSR bundle.\n *\n * The MDX `tag` + attribute/children shape MUST match the legacy\n * `<Callout tone>…body…</Callout>` encoding so stored `.mdx` round-trips\n * byte-compatibly (the block originated in the plan template before moving here).\n */\n\nexport type CalloutTone = \"info\" | \"decision\" | \"risk\" | \"warning\" | \"success\";\n\nexport interface CalloutData {\n tone?: CalloutTone;\n /** Markdown body. Tagged `markdown()` so the auto-editor edits it inline. */\n body: string;\n}\n\nexport const CALLOUT_TONES: CalloutTone[] = [\n \"info\",\n \"decision\",\n \"risk\",\n \"warning\",\n \"success\",\n];\n\nexport const calloutSchema = z.object({\n tone: z\n .enum([\"info\", \"decision\", \"risk\", \"warning\", \"success\"])\n .optional() as z.ZodType<CalloutTone | undefined>,\n // `markdown()` tags the field so `SchemaBlockEditor` renders it with the\n // shared rich-markdown editor (inline, Notion-style) instead of a textarea.\n body: markdown(z.string().trim().min(1).max(10_000)) as z.ZodType<string>,\n}) as unknown as z.ZodType<CalloutData>;\n\n/**\n * MDX config: `tone` is an attribute, `body` is MDX children — exactly the\n * legacy `<Callout id … tone>\\n\\n{body}\\n\\n</Callout>` form. `toAttrs` returns\n * only `tone` (body is `childrenField`, excluded from attributes); `fromAttrs`\n * reads `tone` and uses the stringified prose children as `body`.\n */\nexport const calloutMdx: BlockMdxConfig<CalloutData> = {\n tag: \"Callout\",\n childrenField: \"body\",\n toAttrs: (data) => ({ tone: data.tone }),\n fromAttrs: (attrs, children) => ({\n tone: attrs.string(\"tone\") as CalloutTone | undefined,\n body: children,\n }),\n};\n"]}
@@ -0,0 +1,20 @@
1
+ import type { BlockReadProps, BlockEditProps } from "../types.js";
2
+ import { type CalloutData } from "./callout.config.js";
3
+ /**
4
+ * Standard `callout` block — an emphasized note with a tone (info / decision /
5
+ * risk / warning / success) and a markdown body. Lives in core so any app can
6
+ * register it (it originated in the plan template).
7
+ *
8
+ * The section carries BOTH the app-neutral `an-callout` classes (styled by
9
+ * core's `blocks.css` with shadcn theme tokens, so it looks right in any app)
10
+ * and the legacy `plan-callout` classes (styled by the plan template's own
11
+ * stylesheet). Plan therefore renders byte-identically to before; content (and
12
+ * any other app) gets the theme-token treatment. `data-tone` drives the accent
13
+ * in both. The body renders through `ctx.renderMarkdown` so each app supplies
14
+ * its own GFM renderer (plan's react-markdown reader, content's, etc.).
15
+ */
16
+ export declare function CalloutBlock({ data, blockId, title, ctx, }: BlockReadProps<CalloutData>): import("react/jsx-runtime").JSX.Element;
17
+ export declare function CalloutBlockEdit({ data, onChange, editable, blockId, title, summary, ctx, }: BlockEditProps<CalloutData>): import("react/jsx-runtime").JSX.Element;
18
+ /** Full client spec for the shared `callout` block (schema + MDX + Read/Edit). */
19
+ export declare const calloutBlock: import("../types.js").BlockSpec<CalloutData>;
20
+ //# sourceMappingURL=callout.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callout.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/callout.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAIL,KAAK,WAAW,EAEjB,MAAM,qBAAqB,CAAC;AAE7B;;;;;;;;;;;;GAYG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAI,EACJ,OAAO,EACP,KAAK,EACL,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CAa7B;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,WAAW,CAAC,2CA6E7B;AAED,kFAAkF;AAClF,eAAO,MAAM,YAAY,8CAcvB,CAAC"}