@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
@@ -1 +1 @@
1
- {"version":3,"file":"columns.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconColumns } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockContainerRegion,\n BlockEditProps,\n BlockReadProps,\n NestedBlock,\n} from \"../types.js\";\nimport {\n columnsSchema,\n columnsMdx,\n type ColumnsData,\n type ColumnsColumn,\n} from \"./columns.config.js\";\n\n/**\n * Standard `columns` block: a multi-column side-by-side container whose columns\n * each hold a list of child blocks. Labels may still exist in stored data for\n * source round-tripping, but the document UI intentionally renders bare regions.\n *\n * Like `tabs`, child rendering flows through `ctx.renderBlock` — the app's own\n * block dispatcher — so registered children render via their spec and\n * unconverted children fall through the app's legacy switch. This is the\n * coexistence seam: the core columns block never has to know app-specific child\n * block types. The plan CSS classes (`plan-block`, `text-plan-*`) resolve\n * against the plan app's stylesheet at render time.\n */\n\n/** Mint a reasonably-unique column id without pulling a dep into core. */\nfunction newColId(): string {\n return `col-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Tailwind grid-column classes keyed by the column count. The grid collapses to\n * a single column on small screens and fans out to the column count at `md`+, so\n * narrow viewports stack the panels instead of crushing them.\n */\nconst COLS_CLASS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-1 md:grid-cols-2\",\n 3: \"grid-cols-1 md:grid-cols-3\",\n 4: \"grid-cols-1 md:grid-cols-4\",\n};\n\n/** Resolve the responsive grid class for a column count (clamped to 1–4). */\nfunction gridColsClass(count: number): string {\n return COLS_CLASS[Math.min(4, Math.max(1, count))] ?? COLS_CLASS[1];\n}\n\nconst API_REFERENCE_BLOCK_TYPES = new Set([\"api-endpoint\", \"openapi-spec\"]);\nconst BEFORE_LABELS = new Set([\"before\", \"old\", \"previous\", \"current\"]);\nconst AFTER_LABELS = new Set([\"after\", \"new\", \"next\", \"target\"]);\n\nfunction normalizedLabel(column: ColumnsColumn): string {\n return column.label?.trim().toLowerCase() ?? \"\";\n}\n\nfunction isComparisonGroup(columns: ColumnsColumn[]): boolean {\n const labels = columns.map(normalizedLabel);\n return (\n labels.some((label) => BEFORE_LABELS.has(label)) &&\n labels.some((label) => AFTER_LABELS.has(label))\n );\n}\n\nfunction isApiReferenceGroup(columns: ColumnsColumn[]): boolean {\n return (\n columns.length > 1 &&\n !isComparisonGroup(columns) &&\n columns.every(\n (column) =>\n column.blocks.length > 0 &&\n column.blocks.every((block) =>\n API_REFERENCE_BLOCK_TYPES.has(block.type),\n ),\n )\n );\n}\n\nfunction columnsLayoutClass(columns: ColumnsColumn[]): string {\n return isApiReferenceGroup(columns)\n ? COLS_CLASS[1]\n : gridColsClass(columns.length);\n}\n\nfunction isBlankRichTextBlock(block: NestedBlock): boolean {\n if (block.type !== \"rich-text\") return false;\n const data = block.data;\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return false;\n const markdown = (data as { markdown?: unknown }).markdown;\n return typeof markdown === \"string\" && markdown.trim().length === 0;\n}\n\nfunction isEffectivelyEmptyRegion(blocks: NestedBlock[]): boolean {\n return (\n blocks.length === 0 ||\n (blocks.length === 1 && isBlankRichTextBlock(blocks[0]!))\n );\n}\n\nfunction areSameBlocks(a: NestedBlock[], b: NestedBlock[]): boolean {\n if (a === b) return true;\n try {\n return JSON.stringify(a) === JSON.stringify(b);\n } catch {\n return false;\n }\n}\n\n/** Read renderer: a responsive grid of columns, each child rendered read-only. */\nexport function ColumnsBlockReader({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<ColumnsData>) {\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className={cn(\"grid gap-6\", columnsLayoutClass(data.columns))}>\n {data.columns.map((column) => (\n <div key={column.id} className=\"min-w-0\">\n <div>\n {column.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({ block: child, editing: false })}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </section>\n );\n}\n\n/**\n * Editor: the same responsive grid, with child blocks rendered editable in\n * place through the app dispatcher. A child change updates that child within\n * its column and commits the whole\n * columns block — mirroring the legacy `tabs` onChange bubbling so the plan's\n * recursive `updateBlocks`/`findBlock` (`PlanContentRenderer`) keeps working.\n *\n * Renders BARE (no `plan-block` section / title): in edit mode the app's block\n * dispatcher already wraps registered editors in a titled `plan-block` section,\n * so wrapping again here would double-nest. The read renderer owns its own\n * section because read mode renders the spec directly.\n */\nexport function ColumnsBlockEditor({\n data,\n onChange,\n editable,\n blockId,\n ctx,\n}: BlockEditProps<ColumnsData>) {\n const commit = (columns: ColumnsColumn[]) => onChange({ columns });\n\n const updateChild = (columnId: string, child: NestedBlock) =>\n commit(\n data.columns.map((column) =>\n column.id === columnId\n ? {\n ...column,\n blocks: column.blocks.map((existing) =>\n existing.id === child.id ? child : existing,\n ),\n }\n : column,\n ),\n );\n\n return (\n <div data-columns-edit-block={blockId} className=\"grid gap-3\">\n <div className={cn(\"grid gap-6\", columnsLayoutClass(data.columns))}>\n {data.columns.map((column) => (\n <div key={column.id} className=\"min-w-0\">\n <div>\n {ctx.renderBlocksEditor\n ? ctx.renderBlocksEditor({\n blocks: column.blocks,\n onChange: (nextBlocks) => {\n if (areSameBlocks(nextBlocks, column.blocks)) return;\n onChange(\n {\n columns: data.columns.map((existing) =>\n existing.id === column.id\n ? {\n ...existing,\n blocks: nextBlocks,\n }\n : existing,\n ),\n },\n {\n containerRegion: {\n regionId: column.id,\n blocks: nextBlocks,\n },\n },\n );\n },\n editable,\n containerBlockId: blockId,\n regionId: column.id,\n regionLabel: column.label,\n })\n : column.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: true,\n onChange: (next) => updateChild(column.id, next),\n })}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * The standard columns block spec (with React `Read`/`Edit`). Apps register this\n * in their browser registry. The schema + MDX config come from\n * `./columns.config.ts`, the exact same object server / agent code registers, so\n * rendering and source round-trip never drift.\n */\nexport const columnsBlock = defineBlock<ColumnsData>({\n type: \"columns\",\n schema: columnsSchema,\n mdx: columnsMdx,\n Read: ColumnsBlockReader,\n Edit: ColumnsBlockEditor,\n placement: [\"block\"],\n editSurface: \"container\",\n container: {\n regions: (data): BlockContainerRegion[] => data.columns,\n updateRegion: (data, regionId, blocks) => {\n const shouldRemoveRegion =\n data.columns.length > 1 && isEffectivelyEmptyRegion(blocks);\n\n return {\n columns: data.columns\n .map((column) =>\n column.id === regionId ? { ...column, blocks } : column,\n )\n .filter((column) => column.id !== regionId || !shouldRemoveRegion),\n };\n },\n addRegion: (data, afterRegionId) => {\n if (data.columns.length >= 4) return data;\n const nextColumn: ColumnsColumn = {\n id: newColId(),\n blocks: [],\n };\n if (!afterRegionId) return { columns: [...data.columns, nextColumn] };\n const afterIndex = data.columns.findIndex(\n (column) => column.id === afterRegionId,\n );\n if (afterIndex < 0) return { columns: [...data.columns, nextColumn] };\n return {\n columns: [\n ...data.columns.slice(0, afterIndex + 1),\n nextColumn,\n ...data.columns.slice(afterIndex + 1),\n ],\n };\n },\n removeRegion: (data, regionId) => {\n if (data.columns.length <= 1) return data;\n return {\n columns: data.columns.filter((column) => column.id !== regionId),\n };\n },\n },\n label: \"Columns\",\n icon: IconColumns,\n description:\n \"A multi-column side-by-side layout container; each column holds its own list of blocks. Ideal for before/after or current/target comparisons.\",\n empty: () => ({\n columns: [\n { id: newColId(), blocks: [] },\n { id: newColId(), blocks: [] },\n ],\n }),\n});\n"]}
1
+ {"version":3,"file":"columns.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/columns.tsx"],"names":[],"mappings":"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","sourcesContent":["import { IconColumns } from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type {\n BlockContainerRegion,\n BlockEditProps,\n BlockReadProps,\n NestedBlock,\n} from \"../types.js\";\nimport {\n columnsSchema,\n columnsMdx,\n type ColumnsData,\n type ColumnsColumn,\n} from \"./columns.config.js\";\n\n/**\n * Standard `columns` block: a multi-column side-by-side container whose columns\n * each hold a list of child blocks. A column's optional `label` renders as a\n * small heading above that column (e.g. `Before` / `After`), so a comparison\n * names its states outside the content — never baked into a child wireframe.\n *\n * Like `tabs`, child rendering flows through `ctx.renderBlock` — the app's own\n * block dispatcher — so registered children render via their spec and\n * unconverted children fall through the app's legacy switch. This is the\n * coexistence seam: the core columns block never has to know app-specific child\n * block types. The plan CSS classes (`plan-block`, `text-plan-*`) resolve\n * against the plan app's stylesheet at render time.\n */\n\n/** Mint a reasonably-unique column id without pulling a dep into core. */\nfunction newColId(): string {\n return `col-${Math.random().toString(36).slice(2, 10)}`;\n}\n\n/**\n * Tailwind grid-column classes keyed by the column count. The grid collapses to\n * a single column on small screens and fans out to the column count at `md`+, so\n * narrow viewports stack the panels instead of crushing them.\n */\nconst COLS_CLASS: Record<number, string> = {\n 1: \"grid-cols-1\",\n 2: \"grid-cols-1 md:grid-cols-2\",\n 3: \"grid-cols-1 md:grid-cols-3\",\n 4: \"grid-cols-1 md:grid-cols-4\",\n};\n\n/** Resolve the responsive grid class for a column count (clamped to 1–4). */\nfunction gridColsClass(count: number): string {\n return COLS_CLASS[Math.min(4, Math.max(1, count))] ?? COLS_CLASS[1];\n}\n\nconst API_REFERENCE_BLOCK_TYPES = new Set([\"api-endpoint\", \"openapi-spec\"]);\nconst BEFORE_LABELS = new Set([\"before\", \"old\", \"previous\", \"current\"]);\nconst AFTER_LABELS = new Set([\"after\", \"new\", \"next\", \"target\"]);\n\n// Wireframe surfaces that render too wide to survive a half-width comparison\n// column: a full desktop page or browser frame shrinks and crops when squeezed\n// side by side, so a comparison that holds one of these stacks vertically.\nconst WIDE_WIREFRAME_SURFACES = new Set([\"desktop\", \"browser\"]);\n\nfunction normalizedLabel(column: ColumnsColumn): string {\n return column.label?.trim().toLowerCase() ?? \"\";\n}\n\nfunction isComparisonGroup(columns: ColumnsColumn[]): boolean {\n const labels = columns.map(normalizedLabel);\n return (\n labels.some((label) => BEFORE_LABELS.has(label)) &&\n labels.some((label) => AFTER_LABELS.has(label))\n );\n}\n\n/** A wireframe child whose `surface` is wide enough to need full document width. */\nfunction isWideWireframeBlock(block: NestedBlock): boolean {\n if (block.type !== \"wireframe\") return false;\n const surface = (block.data as { surface?: unknown } | undefined)?.surface;\n return typeof surface === \"string\" && WIDE_WIREFRAME_SURFACES.has(surface);\n}\n\nfunction hasWideWireframe(columns: ColumnsColumn[]): boolean {\n return columns.some((column) => column.blocks.some(isWideWireframeBlock));\n}\n\nfunction isApiReferenceGroup(columns: ColumnsColumn[]): boolean {\n return (\n columns.length > 1 &&\n !isComparisonGroup(columns) &&\n columns.every(\n (column) =>\n column.blocks.length > 0 &&\n column.blocks.every((block) =>\n API_REFERENCE_BLOCK_TYPES.has(block.type),\n ),\n )\n );\n}\n\nfunction columnsLayoutClass(columns: ColumnsColumn[]): string {\n // API reference groups always read as a single stacked column.\n if (isApiReferenceGroup(columns)) return COLS_CLASS[1];\n // Wide wireframes (full desktop / browser surfaces) crop when squeezed into a\n // half-width comparison cell, so stack the states vertically and let each\n // frame use the full document width. Narrow surfaces stay side by side.\n if (hasWideWireframe(columns)) return COLS_CLASS[1];\n return gridColsClass(columns.length);\n}\n\nfunction isBlankRichTextBlock(block: NestedBlock): boolean {\n if (block.type !== \"rich-text\") return false;\n const data = block.data;\n if (!data || typeof data !== \"object\" || Array.isArray(data)) return false;\n const markdown = (data as { markdown?: unknown }).markdown;\n return typeof markdown === \"string\" && markdown.trim().length === 0;\n}\n\nfunction isEffectivelyEmptyRegion(blocks: NestedBlock[]): boolean {\n return (\n blocks.length === 0 ||\n (blocks.length === 1 && isBlankRichTextBlock(blocks[0]!))\n );\n}\n\nfunction areSameBlocks(a: NestedBlock[], b: NestedBlock[]): boolean {\n if (a === b) return true;\n try {\n return JSON.stringify(a) === JSON.stringify(b);\n } catch {\n return false;\n }\n}\n\n/** Read renderer: a responsive grid of columns, each child rendered read-only. */\nexport function ColumnsBlockReader({\n data,\n blockId,\n title,\n ctx,\n}: BlockReadProps<ColumnsData>) {\n return (\n <section className=\"plan-block\" data-block-id={blockId}>\n {title && <div className=\"plan-block-label\">{title}</div>}\n <div className={cn(\"grid gap-6\", columnsLayoutClass(data.columns))}>\n {data.columns.map((column) => (\n <div key={column.id} className=\"min-w-0\">\n {column.label && (\n <h4 className=\"plan-columns-label\">{column.label}</h4>\n )}\n <div>\n {column.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({ block: child, editing: false })}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </section>\n );\n}\n\n/**\n * Editor: the same responsive grid, with child blocks rendered editable in\n * place through the app dispatcher. A child change updates that child within\n * its column and commits the whole\n * columns block — mirroring the legacy `tabs` onChange bubbling so the plan's\n * recursive `updateBlocks`/`findBlock` (`PlanContentRenderer`) keeps working.\n *\n * Renders BARE (no `plan-block` section / title): in edit mode the app's block\n * dispatcher already wraps registered editors in a titled `plan-block` section,\n * so wrapping again here would double-nest. The read renderer owns its own\n * section because read mode renders the spec directly.\n */\nexport function ColumnsBlockEditor({\n data,\n onChange,\n editable,\n blockId,\n ctx,\n}: BlockEditProps<ColumnsData>) {\n const commit = (columns: ColumnsColumn[]) => onChange({ columns });\n\n const updateChild = (columnId: string, child: NestedBlock) =>\n commit(\n data.columns.map((column) =>\n column.id === columnId\n ? {\n ...column,\n blocks: column.blocks.map((existing) =>\n existing.id === child.id ? child : existing,\n ),\n }\n : column,\n ),\n );\n\n return (\n <div data-columns-edit-block={blockId} className=\"grid gap-3\">\n <div className={cn(\"grid gap-6\", columnsLayoutClass(data.columns))}>\n {data.columns.map((column) => (\n <div key={column.id} className=\"min-w-0\">\n {column.label && (\n <h4 className=\"plan-columns-label\">{column.label}</h4>\n )}\n <div>\n {ctx.renderBlocksEditor\n ? ctx.renderBlocksEditor({\n blocks: column.blocks,\n onChange: (nextBlocks) => {\n if (areSameBlocks(nextBlocks, column.blocks)) return;\n onChange(\n {\n columns: data.columns.map((existing) =>\n existing.id === column.id\n ? {\n ...existing,\n blocks: nextBlocks,\n }\n : existing,\n ),\n },\n {\n containerRegion: {\n regionId: column.id,\n blocks: nextBlocks,\n },\n },\n );\n },\n editable,\n containerBlockId: blockId,\n regionId: column.id,\n regionLabel: column.label,\n })\n : column.blocks.map((child) => (\n <div key={child.id}>\n {ctx.renderBlock?.({\n block: child,\n editing: true,\n onChange: (next) => updateChild(column.id, next),\n })}\n </div>\n ))}\n </div>\n </div>\n ))}\n </div>\n </div>\n );\n}\n\n/**\n * The standard columns block spec (with React `Read`/`Edit`). Apps register this\n * in their browser registry. The schema + MDX config come from\n * `./columns.config.ts`, the exact same object server / agent code registers, so\n * rendering and source round-trip never drift.\n */\nexport const columnsBlock = defineBlock<ColumnsData>({\n type: \"columns\",\n schema: columnsSchema,\n mdx: columnsMdx,\n Read: ColumnsBlockReader,\n Edit: ColumnsBlockEditor,\n placement: [\"block\"],\n editSurface: \"container\",\n container: {\n regions: (data): BlockContainerRegion[] => data.columns,\n updateRegion: (data, regionId, blocks) => {\n const shouldRemoveRegion =\n data.columns.length > 1 && isEffectivelyEmptyRegion(blocks);\n\n return {\n columns: data.columns\n .map((column) =>\n column.id === regionId ? { ...column, blocks } : column,\n )\n .filter((column) => column.id !== regionId || !shouldRemoveRegion),\n };\n },\n addRegion: (data, afterRegionId) => {\n if (data.columns.length >= 4) return data;\n const nextColumn: ColumnsColumn = {\n id: newColId(),\n blocks: [],\n };\n if (!afterRegionId) return { columns: [...data.columns, nextColumn] };\n const afterIndex = data.columns.findIndex(\n (column) => column.id === afterRegionId,\n );\n if (afterIndex < 0) return { columns: [...data.columns, nextColumn] };\n return {\n columns: [\n ...data.columns.slice(0, afterIndex + 1),\n nextColumn,\n ...data.columns.slice(afterIndex + 1),\n ],\n };\n },\n removeRegion: (data, regionId) => {\n if (data.columns.length <= 1) return data;\n return {\n columns: data.columns.filter((column) => column.id !== regionId),\n };\n },\n },\n label: \"Columns\",\n icon: IconColumns,\n description:\n \"A multi-column side-by-side layout container; each column holds its own list of blocks. Ideal for before/after or current/target comparisons.\",\n empty: () => ({\n columns: [\n { id: newColId(), blocks: [] },\n { id: newColId(), blocks: [] },\n ],\n }),\n});\n"]}
@@ -22,6 +22,13 @@ import type { BlockMdxConfig } from "../types.js";
22
22
  /** Cardinality of a relation between two entities. */
23
23
  export type DataModelRelationKind = "1-1" | "1-n" | "n-n";
24
24
  export declare const DATA_MODEL_RELATION_KINDS: DataModelRelationKind[];
25
+ /**
26
+ * Diff status of an entity or field, used to render before/after change chips
27
+ * on a data model. Shares the SAME vocabulary as the `file-tree` block's
28
+ * `FileTreeChange` so change chips look consistent across dev-doc blocks.
29
+ */
30
+ export type DataModelChange = "added" | "modified" | "removed" | "renamed";
31
+ export declare const DATA_MODEL_CHANGES: DataModelChange[];
25
32
  /** One column of an entity. `fk` is a string like `"User.id"`. */
26
33
  export interface DataModelField {
27
34
  name: string;
@@ -32,12 +39,18 @@ export interface DataModelField {
32
39
  nullable?: boolean;
33
40
  default?: string;
34
41
  note?: string;
42
+ /** Diff status of this field, driving its change chip. */
43
+ change?: DataModelChange;
44
+ /** Prior value when `change === "modified"` (e.g. the old column type). */
45
+ was?: string;
35
46
  }
36
47
  /** One table / model. `id` is referenced by relations (`from`/`to`). */
37
48
  export interface DataModelEntity {
38
49
  id: string;
39
50
  name: string;
40
51
  note?: string;
52
+ /** Diff status of the whole table (added / removed / renamed / modified). */
53
+ change?: DataModelChange;
41
54
  fields: DataModelField[];
42
55
  }
43
56
  /** An explicit relation between two entities, by `id` (or `name`). */
@@ -63,6 +76,10 @@ export declare const dataModelSchema: z.ZodType<DataModelData>;
63
76
  * props on a self-closing element — the `<DataModel id … entities={…}
64
77
  * relations={…} />` form. `toAttrs` emits `entities` then `relations` in a STABLE
65
78
  * order (the shared `prop()` encoder drops `relations` when it is undefined).
79
+ * Because `entities` is one JSON prop, each entity's `change` and each field's
80
+ * `change` / `was` diff attributes ride along inside it and round-trip verbatim
81
+ * (export → import) with no per-attribute handling, mirroring how `file-tree`
82
+ * encodes its per-entry `change` inside the `entries` JSON prop.
66
83
  *
67
84
  * `fromAttrs` tolerates missing/partial attributes for backward-compat: a missing
68
85
  * `entities` decodes to `[]` and a missing `relations` decodes to `undefined` so
@@ -1 +1 @@
1
- {"version":3,"file":"data-model.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/data-model.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,sDAAsD;AACtD,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1D,eAAO,MAAM,yBAAyB,EAAE,qBAAqB,EAI5D,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,8EAA8E;IAC9E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AA0BD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAGX,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;AAE1C;;;;;;;;;GASG;AACH,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,aAAa,CAUtD,CAAC"}
1
+ {"version":3,"file":"data-model.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/data-model.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,sDAAsD;AACtD,MAAM,MAAM,qBAAqB,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,CAAC;AAE1D,eAAO,MAAM,yBAAyB,EAAE,qBAAqB,EAI5D,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3E,eAAO,MAAM,kBAAkB,EAAE,eAAe,EAK/C,CAAC;AAEF,kEAAkE;AAClE,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,8EAA8E;IAC9E,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0DAA0D;IAC1D,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wEAAwE;AACxE,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6EAA6E;IAC7E,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,MAAM,EAAE,cAAc,EAAE,CAAC;CAC1B;AAED,sEAAsE;AACtE,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,eAAe,EAAE,CAAC;IAC5B,SAAS,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACjC;AAgCD;;;;;GAKG;AACH,eAAO,MAAM,eAAe,EAGX,CAAC,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC;AAE1C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,aAAa,CAUtD,CAAC"}
@@ -4,6 +4,14 @@ export const DATA_MODEL_RELATION_KINDS = [
4
4
  "1-n",
5
5
  "n-n",
6
6
  ];
7
+ export const DATA_MODEL_CHANGES = [
8
+ "added",
9
+ "modified",
10
+ "removed",
11
+ "renamed",
12
+ ];
13
+ /** Diff-status enum, shared with the inline `data-model` schema's `change`. */
14
+ const changeSchema = z.enum(["added", "modified", "removed", "renamed"]);
7
15
  const fieldSchema = z.object({
8
16
  name: z.string().trim().min(1).max(160),
9
17
  type: z.string().trim().max(120).optional(),
@@ -12,11 +20,14 @@ const fieldSchema = z.object({
12
20
  nullable: z.boolean().optional(),
13
21
  default: z.string().trim().max(400).optional(),
14
22
  note: z.string().trim().max(600).optional(),
23
+ change: changeSchema.optional(),
24
+ was: z.string().trim().max(400).optional(),
15
25
  });
16
26
  const entitySchema = z.object({
17
27
  id: z.string().trim().min(1).max(120),
18
28
  name: z.string().trim().min(1).max(160),
19
29
  note: z.string().trim().max(600).optional(),
30
+ change: changeSchema.optional(),
20
31
  fields: z.array(fieldSchema).max(80),
21
32
  });
22
33
  const relationSchema = z.object({
@@ -40,6 +51,10 @@ export const dataModelSchema = z.object({
40
51
  * props on a self-closing element — the `<DataModel id … entities={…}
41
52
  * relations={…} />` form. `toAttrs` emits `entities` then `relations` in a STABLE
42
53
  * order (the shared `prop()` encoder drops `relations` when it is undefined).
54
+ * Because `entities` is one JSON prop, each entity's `change` and each field's
55
+ * `change` / `was` diff attributes ride along inside it and round-trip verbatim
56
+ * (export → import) with no per-attribute handling, mirroring how `file-tree`
57
+ * encodes its per-entry `change` inside the `entries` JSON prop.
43
58
  *
44
59
  * `fromAttrs` tolerates missing/partial attributes for backward-compat: a missing
45
60
  * `entities` decodes to `[]` and a missing `relations` decodes to `undefined` so
@@ -1 +1 @@
1
- {"version":3,"file":"data-model.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/data-model.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 `data-model` block: its data schema\n * and MDX round-trip config. Shared by the server MDX adapter (`plan-mdx.ts` via\n * `plan-block-registry.ts`) and the client spec (`planBlocks.tsx`). Keeping this\n * React-free means importing it into a server module never pulls React into the\n * Nitro/SSR bundle.\n *\n * The block renders a dbdiagram / Prisma-style entity-relationship diagram: a set\n * of entity cards (each a small table of fields with PK / FK / nullable flags)\n * plus optional explicit relations. The Read renderer makes foreign keys\n * interactive — hovering / clicking an FK highlights and scrolls to the\n * referenced entity — which is why this is a custom block, not a plain table.\n *\n * The schema MUST stay data-compatible with the `data-model` branch of\n * `planBlockSchema` (`plan-content.ts`), and the MDX `tag` (`DataModel`) +\n * attribute shape MUST match the inline planBlockSchema member so stored `.mdx`\n * round-trips: the whole `entities` and `relations` arrays are JSON props\n * (`<DataModel id … entities={…} relations={…} />`).\n */\n\n/** Cardinality of a relation between two entities. */\nexport type DataModelRelationKind = \"1-1\" | \"1-n\" | \"n-n\";\n\nexport const DATA_MODEL_RELATION_KINDS: DataModelRelationKind[] = [\n \"1-1\",\n \"1-n\",\n \"n-n\",\n];\n\n/** One column of an entity. `fk` is a string like `\"User.id\"`. */\nexport interface DataModelField {\n name: string;\n type?: string;\n pk?: boolean;\n /** Foreign-key target, e.g. `\"User.id\"` (entity name/id + optional field). */\n fk?: string;\n nullable?: boolean;\n default?: string;\n note?: string;\n}\n\n/** One table / model. `id` is referenced by relations (`from`/`to`). */\nexport interface DataModelEntity {\n id: string;\n name: string;\n note?: string;\n fields: DataModelField[];\n}\n\n/** An explicit relation between two entities, by `id` (or `name`). */\nexport interface DataModelRelation {\n from: string;\n to: string;\n kind?: DataModelRelationKind;\n label?: string;\n}\n\nexport interface DataModelData {\n entities: DataModelEntity[];\n relations?: DataModelRelation[];\n}\n\nconst fieldSchema = z.object({\n name: z.string().trim().min(1).max(160),\n type: z.string().trim().max(120).optional(),\n pk: z.boolean().optional(),\n fk: z.string().trim().max(200).optional(),\n nullable: z.boolean().optional(),\n default: z.string().trim().max(400).optional(),\n note: z.string().trim().max(600).optional(),\n}) as z.ZodType<DataModelField>;\n\nconst entitySchema = z.object({\n id: z.string().trim().min(1).max(120),\n name: z.string().trim().min(1).max(160),\n note: z.string().trim().max(600).optional(),\n fields: z.array(fieldSchema).max(80),\n}) as z.ZodType<DataModelEntity>;\n\nconst relationSchema = z.object({\n from: z.string().trim().min(1).max(120),\n to: z.string().trim().min(1).max(120),\n kind: z.enum([\"1-1\", \"1-n\", \"n-n\"]).optional(),\n label: z.string().trim().max(160).optional(),\n}) as z.ZodType<DataModelRelation>;\n\n/**\n * Data-compatible with the inline `data-model` member of `planBlockSchema`\n * (`plan-content.ts`). At least one entity is required; `relations` is optional\n * (the Read renderer can infer simple `1-n` relations from `fk` fields when it is\n * omitted) so a fresh model validates from a single entity with a couple fields.\n */\nexport const dataModelSchema = z.object({\n entities: z.array(entitySchema).min(1).max(60),\n relations: z.array(relationSchema).max(200).optional(),\n}) as unknown as z.ZodType<DataModelData>;\n\n/**\n * MDX config: the whole `entities` and `relations` arrays are serialized as JSON\n * props on a self-closing element — the `<DataModel id … entities={…}\n * relations={…} />` form. `toAttrs` emits `entities` then `relations` in a STABLE\n * order (the shared `prop()` encoder drops `relations` when it is undefined).\n *\n * `fromAttrs` tolerates missing/partial attributes for backward-compat: a missing\n * `entities` decodes to `[]` and a missing `relations` decodes to `undefined` so\n * a plan written before this block existed still parses.\n */\nexport const dataModelMdx: BlockMdxConfig<DataModelData> = {\n tag: \"DataModel\",\n toAttrs: (data) => ({\n entities: data.entities,\n relations: data.relations,\n }),\n fromAttrs: (attrs) => ({\n entities: attrs.array<DataModelEntity>(\"entities\") ?? [],\n relations: attrs.array<DataModelRelation>(\"relations\"),\n }),\n};\n"]}
1
+ {"version":3,"file":"data-model.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/data-model.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 `data-model` block: its data schema\n * and MDX round-trip config. Shared by the server MDX adapter (`plan-mdx.ts` via\n * `plan-block-registry.ts`) and the client spec (`planBlocks.tsx`). Keeping this\n * React-free means importing it into a server module never pulls React into the\n * Nitro/SSR bundle.\n *\n * The block renders a dbdiagram / Prisma-style entity-relationship diagram: a set\n * of entity cards (each a small table of fields with PK / FK / nullable flags)\n * plus optional explicit relations. The Read renderer makes foreign keys\n * interactive — hovering / clicking an FK highlights and scrolls to the\n * referenced entity — which is why this is a custom block, not a plain table.\n *\n * The schema MUST stay data-compatible with the `data-model` branch of\n * `planBlockSchema` (`plan-content.ts`), and the MDX `tag` (`DataModel`) +\n * attribute shape MUST match the inline planBlockSchema member so stored `.mdx`\n * round-trips: the whole `entities` and `relations` arrays are JSON props\n * (`<DataModel id … entities={…} relations={…} />`).\n */\n\n/** Cardinality of a relation between two entities. */\nexport type DataModelRelationKind = \"1-1\" | \"1-n\" | \"n-n\";\n\nexport const DATA_MODEL_RELATION_KINDS: DataModelRelationKind[] = [\n \"1-1\",\n \"1-n\",\n \"n-n\",\n];\n\n/**\n * Diff status of an entity or field, used to render before/after change chips\n * on a data model. Shares the SAME vocabulary as the `file-tree` block's\n * `FileTreeChange` so change chips look consistent across dev-doc blocks.\n */\nexport type DataModelChange = \"added\" | \"modified\" | \"removed\" | \"renamed\";\n\nexport const DATA_MODEL_CHANGES: DataModelChange[] = [\n \"added\",\n \"modified\",\n \"removed\",\n \"renamed\",\n];\n\n/** One column of an entity. `fk` is a string like `\"User.id\"`. */\nexport interface DataModelField {\n name: string;\n type?: string;\n pk?: boolean;\n /** Foreign-key target, e.g. `\"User.id\"` (entity name/id + optional field). */\n fk?: string;\n nullable?: boolean;\n default?: string;\n note?: string;\n /** Diff status of this field, driving its change chip. */\n change?: DataModelChange;\n /** Prior value when `change === \"modified\"` (e.g. the old column type). */\n was?: string;\n}\n\n/** One table / model. `id` is referenced by relations (`from`/`to`). */\nexport interface DataModelEntity {\n id: string;\n name: string;\n note?: string;\n /** Diff status of the whole table (added / removed / renamed / modified). */\n change?: DataModelChange;\n fields: DataModelField[];\n}\n\n/** An explicit relation between two entities, by `id` (or `name`). */\nexport interface DataModelRelation {\n from: string;\n to: string;\n kind?: DataModelRelationKind;\n label?: string;\n}\n\nexport interface DataModelData {\n entities: DataModelEntity[];\n relations?: DataModelRelation[];\n}\n\n/** Diff-status enum, shared with the inline `data-model` schema's `change`. */\nconst changeSchema = z.enum([\"added\", \"modified\", \"removed\", \"renamed\"]);\n\nconst fieldSchema = z.object({\n name: z.string().trim().min(1).max(160),\n type: z.string().trim().max(120).optional(),\n pk: z.boolean().optional(),\n fk: z.string().trim().max(200).optional(),\n nullable: z.boolean().optional(),\n default: z.string().trim().max(400).optional(),\n note: z.string().trim().max(600).optional(),\n change: changeSchema.optional(),\n was: z.string().trim().max(400).optional(),\n}) as z.ZodType<DataModelField>;\n\nconst entitySchema = z.object({\n id: z.string().trim().min(1).max(120),\n name: z.string().trim().min(1).max(160),\n note: z.string().trim().max(600).optional(),\n change: changeSchema.optional(),\n fields: z.array(fieldSchema).max(80),\n}) as z.ZodType<DataModelEntity>;\n\nconst relationSchema = z.object({\n from: z.string().trim().min(1).max(120),\n to: z.string().trim().min(1).max(120),\n kind: z.enum([\"1-1\", \"1-n\", \"n-n\"]).optional(),\n label: z.string().trim().max(160).optional(),\n}) as z.ZodType<DataModelRelation>;\n\n/**\n * Data-compatible with the inline `data-model` member of `planBlockSchema`\n * (`plan-content.ts`). At least one entity is required; `relations` is optional\n * (the Read renderer can infer simple `1-n` relations from `fk` fields when it is\n * omitted) so a fresh model validates from a single entity with a couple fields.\n */\nexport const dataModelSchema = z.object({\n entities: z.array(entitySchema).min(1).max(60),\n relations: z.array(relationSchema).max(200).optional(),\n}) as unknown as z.ZodType<DataModelData>;\n\n/**\n * MDX config: the whole `entities` and `relations` arrays are serialized as JSON\n * props on a self-closing element — the `<DataModel id … entities={…}\n * relations={…} />` form. `toAttrs` emits `entities` then `relations` in a STABLE\n * order (the shared `prop()` encoder drops `relations` when it is undefined).\n * Because `entities` is one JSON prop, each entity's `change` and each field's\n * `change` / `was` diff attributes ride along inside it and round-trip verbatim\n * (export → import) with no per-attribute handling, mirroring how `file-tree`\n * encodes its per-entry `change` inside the `entries` JSON prop.\n *\n * `fromAttrs` tolerates missing/partial attributes for backward-compat: a missing\n * `entities` decodes to `[]` and a missing `relations` decodes to `undefined` so\n * a plan written before this block existed still parses.\n */\nexport const dataModelMdx: BlockMdxConfig<DataModelData> = {\n tag: \"DataModel\",\n toAttrs: (data) => ({\n entities: data.entities,\n relations: data.relations,\n }),\n fromAttrs: (attrs) => ({\n entities: attrs.array<DataModelEntity>(\"entities\") ?? [],\n relations: attrs.array<DataModelRelation>(\"relations\"),\n }),\n};\n"]}
@@ -0,0 +1,37 @@
1
+ import { z } from "zod";
2
+ import type { BlockMdxConfig } from "../types.js";
3
+ /**
4
+ * Pure (React-free) part of the shared `decision` block: its data schema and MDX
5
+ * round-trip config. Lives in core so BOTH apps' server/shared registries and
6
+ * the client spec (`decision.tsx`) consume one definition. Keeping it React-free
7
+ * means importing it into a server module never pulls React into the Nitro/SSR
8
+ * bundle.
9
+ *
10
+ * The MDX `tag` + `question`/`options` attribute shape MUST match the legacy
11
+ * `<Decision question options />` encoding so stored `.mdx` round-trips
12
+ * byte-compatibly (the block originated in the plan template before moving here).
13
+ */
14
+ export interface DecisionOption {
15
+ id: string;
16
+ label: string;
17
+ detail?: string;
18
+ /**
19
+ * Authored recommendation only. A reviewer's actual selection does NOT live
20
+ * here — responses belong in comments / events, never in the canonical
21
+ * document body.
22
+ */
23
+ recommended?: boolean;
24
+ }
25
+ export interface DecisionData {
26
+ question: string;
27
+ options: DecisionOption[];
28
+ }
29
+ export declare const decisionSchema: z.ZodType<DecisionData>;
30
+ /**
31
+ * MDX config: `question` and `options` are both attributes — exactly the legacy
32
+ * `<Decision question options />` form. `toAttrs` writes them in their historical
33
+ * order; `fromAttrs` tolerates missing attributes with the same `?? "Decision"` /
34
+ * `?? []` defaults the plan template used.
35
+ */
36
+ export declare const decisionMdx: BlockMdxConfig<DecisionData>;
37
+ //# sourceMappingURL=decision.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/decision.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;GAUG;AAEH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;CAC3B;AAID,eAAO,MAAM,cAAc,EAaV,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;AAEzC;;;;;GAKG;AACH,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,YAAY,CAUpD,CAAC"}
@@ -0,0 +1,32 @@
1
+ import { z } from "zod";
2
+ const decisionIdSchema = z.string().trim().min(1).max(120);
3
+ export const decisionSchema = z.object({
4
+ question: z.string().trim().min(1).max(500),
5
+ options: z
6
+ .array(z.object({
7
+ id: decisionIdSchema,
8
+ label: z.string().trim().min(1).max(200),
9
+ detail: z.string().trim().max(800).optional(),
10
+ recommended: z.boolean().optional(),
11
+ }))
12
+ .min(1)
13
+ .max(20),
14
+ });
15
+ /**
16
+ * MDX config: `question` and `options` are both attributes — exactly the legacy
17
+ * `<Decision question options />` form. `toAttrs` writes them in their historical
18
+ * order; `fromAttrs` tolerates missing attributes with the same `?? "Decision"` /
19
+ * `?? []` defaults the plan template used.
20
+ */
21
+ export const decisionMdx = {
22
+ tag: "Decision",
23
+ toAttrs: (data) => ({
24
+ question: data.question,
25
+ options: data.options,
26
+ }),
27
+ fromAttrs: (attrs) => ({
28
+ question: attrs.string("question") ?? "Decision",
29
+ options: attrs.array("options") ?? [],
30
+ }),
31
+ };
32
+ //# sourceMappingURL=decision.config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.config.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/decision.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAgCxB,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAC3C,OAAO,EAAE,CAAC;SACP,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,EAAE,EAAE,gBAAgB;QACpB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;QACxC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE;QAC7C,WAAW,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE;KACpC,CAAC,CACH;SACA,GAAG,CAAC,CAAC,CAAC;SACN,GAAG,CAAC,EAAE,CAAC;CACX,CAAuC,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,CAAC,MAAM,WAAW,GAAiC;IACvD,GAAG,EAAE,UAAU;IACf,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAClB,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,OAAO,EAAE,IAAI,CAAC,OAAO;KACtB,CAAC;IACF,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QACrB,QAAQ,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,UAAU;QAChD,OAAO,EAAE,KAAK,CAAC,KAAK,CAAiB,SAAS,CAAC,IAAI,EAAE;KACtD,CAAC;CACH,CAAC","sourcesContent":["import { z } from \"zod\";\nimport type { BlockMdxConfig } from \"../types.js\";\n\n/**\n * Pure (React-free) part of the shared `decision` block: its data schema and MDX\n * round-trip config. Lives in core so BOTH apps' server/shared registries and\n * the client spec (`decision.tsx`) consume one definition. Keeping it React-free\n * means importing it into a server module never pulls React into the Nitro/SSR\n * bundle.\n *\n * The MDX `tag` + `question`/`options` attribute shape MUST match the legacy\n * `<Decision question options />` encoding so stored `.mdx` round-trips\n * byte-compatibly (the block originated in the plan template before moving here).\n */\n\nexport interface DecisionOption {\n id: string;\n label: string;\n detail?: string;\n /**\n * Authored recommendation only. A reviewer's actual selection does NOT live\n * here — responses belong in comments / events, never in the canonical\n * document body.\n */\n recommended?: boolean;\n}\n\nexport interface DecisionData {\n question: string;\n options: DecisionOption[];\n}\n\nconst decisionIdSchema = z.string().trim().min(1).max(120);\n\nexport const decisionSchema = z.object({\n question: z.string().trim().min(1).max(500),\n options: z\n .array(\n z.object({\n id: decisionIdSchema,\n label: z.string().trim().min(1).max(200),\n detail: z.string().trim().max(800).optional(),\n recommended: z.boolean().optional(),\n }),\n )\n .min(1)\n .max(20),\n}) as unknown as z.ZodType<DecisionData>;\n\n/**\n * MDX config: `question` and `options` are both attributes — exactly the legacy\n * `<Decision question options />` form. `toAttrs` writes them in their historical\n * order; `fromAttrs` tolerates missing attributes with the same `?? \"Decision\"` /\n * `?? []` defaults the plan template used.\n */\nexport const decisionMdx: BlockMdxConfig<DecisionData> = {\n tag: \"Decision\",\n toAttrs: (data) => ({\n question: data.question,\n options: data.options,\n }),\n fromAttrs: (attrs) => ({\n question: attrs.string(\"question\") ?? \"Decision\",\n options: attrs.array<DecisionOption>(\"options\") ?? [],\n }),\n};\n"]}
@@ -0,0 +1,19 @@
1
+ import type { BlockReadProps, BlockEditProps } from "../types.js";
2
+ import { type DecisionData } from "./decision.config.js";
3
+ /**
4
+ * Standard `decision` block — a decision prompt with inline-editable option
5
+ * cards and one authored "recommended" choice. Lives in core so any app can
6
+ * register it (it originated in the plan template).
7
+ *
8
+ * The root `<section>` keeps the app-neutral `an-block` class (document-flow
9
+ * spacing hook) alongside the legacy `plan-block` class (styled by the plan
10
+ * template's own stylesheet), so plan renders as before and any other app gets
11
+ * theme-token styling. All inner color comes from shadcn theme tokens
12
+ * (`text-muted-foreground`, `text-foreground`, `bg-muted`, `bg-background`,
13
+ * `border-border`, `ring`), so it reads correctly in any template palette.
14
+ */
15
+ export declare function DecisionBlock({ data, blockId, title, }: BlockReadProps<DecisionData>): import("react/jsx-runtime").JSX.Element;
16
+ export declare function DecisionBlockEdit({ data, onChange, editable, blockId, title, summary, ctx, }: BlockEditProps<DecisionData>): import("react/jsx-runtime").JSX.Element;
17
+ /** Full client spec for the shared `decision` block (schema + MDX + Read/Edit). */
18
+ export declare const decisionBlock: import("../types.js").BlockSpec<DecisionData>;
19
+ //# sourceMappingURL=decision.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/decision.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAClE,OAAO,EAGL,KAAK,YAAY,EAElB,MAAM,sBAAsB,CAAC;AAE9B;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,OAAO,EACP,KAAK,GACN,EAAE,cAAc,CAAC,YAAY,CAAC,2CAsC9B;AAaD,wBAAgB,iBAAiB,CAAC,EAChC,IAAI,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,KAAK,EACL,OAAO,EACP,GAAG,GACJ,EAAE,cAAc,CAAC,YAAY,CAAC,2CAiI9B;AA+GD,mFAAmF;AACnF,eAAO,MAAM,aAAa,+CAgCxB,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
3
+ import { IconCheck, IconPencil, IconPlus, IconTrash, } from "@tabler/icons-react";
4
+ import { cn } from "../../utils.js";
5
+ import { defineBlock } from "../types.js";
6
+ import { decisionMdx, decisionSchema, } from "./decision.config.js";
7
+ /**
8
+ * Standard `decision` block — a decision prompt with inline-editable option
9
+ * cards and one authored "recommended" choice. Lives in core so any app can
10
+ * register it (it originated in the plan template).
11
+ *
12
+ * The root `<section>` keeps the app-neutral `an-block` class (document-flow
13
+ * spacing hook) alongside the legacy `plan-block` class (styled by the plan
14
+ * template's own stylesheet), so plan renders as before and any other app gets
15
+ * theme-token styling. All inner color comes from shadcn theme tokens
16
+ * (`text-muted-foreground`, `text-foreground`, `bg-muted`, `bg-background`,
17
+ * `border-border`, `ring`), so it reads correctly in any template palette.
18
+ */
19
+ export function DecisionBlock({ data, blockId, title, }) {
20
+ return (_jsxs("section", { className: "an-block plan-block", "data-block-id": blockId, children: [title && _jsx("div", { className: "an-block-label plan-block-label", children: title }), _jsx("p", { className: "mt-3 max-w-3xl text-lg leading-8 text-muted-foreground", children: data.question }), _jsx("div", { className: "mt-6 grid gap-3 md:grid-cols-2", children: data.options.map((option) => (_jsxs("article", { className: cn("rounded-xl border border-border bg-muted p-4", option.recommended
21
+ ? "shadow-[inset_3px_0_0_hsl(var(--ring))]"
22
+ : "opacity-85"), children: [_jsxs("div", { className: "flex items-start justify-between gap-3", children: [_jsx("h3", { className: "text-lg font-semibold tracking-tight text-foreground", children: option.label }), option.recommended && (_jsx("span", { className: "rounded-full border border-border px-2 py-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground", children: "Recommended" }))] }), option.detail && (_jsx("p", { className: "mt-3 text-sm leading-6 text-muted-foreground", children: option.detail }))] }, option.id))) })] }));
23
+ }
24
+ const inlineInputClass = "w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring";
25
+ const inlineTextareaClass = "w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm leading-6 text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring";
26
+ const inlineLabelClass = "text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground";
27
+ function newLocalId(prefix) {
28
+ return `${prefix}-${Math.random().toString(36).slice(2, 10)}`;
29
+ }
30
+ export function DecisionBlockEdit({ data, onChange, editable, blockId, title, summary, ctx, }) {
31
+ const updateOption = (optionId, patch) => onChange({
32
+ ...data,
33
+ options: data.options.map((option) => option.id === optionId ? { ...option, ...patch } : option),
34
+ });
35
+ const removeOption = (optionId) => {
36
+ if (data.options.length <= 1)
37
+ return;
38
+ onChange({
39
+ ...data,
40
+ options: data.options.filter((option) => option.id !== optionId),
41
+ });
42
+ };
43
+ const addOption = () => {
44
+ if (data.options.length >= 20)
45
+ return;
46
+ onChange({
47
+ ...data,
48
+ options: [
49
+ ...data.options,
50
+ { id: newLocalId("option"), label: "New option" },
51
+ ],
52
+ });
53
+ };
54
+ const settings = editable
55
+ ? (ctx.renderEditSurface?.({
56
+ title: "Decision",
57
+ blockId,
58
+ blockType: "decision",
59
+ blockTitle: title,
60
+ blockSummary: summary,
61
+ blockData: data,
62
+ trigger: (_jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Edit decision options", className: "flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground", children: _jsx(IconPencil, { className: "size-4" }) })),
63
+ children: (_jsx(DecisionSettings, { options: data.options, onToggleRecommended: (option) => updateOption(option.id, { recommended: !option.recommended }), onRemove: removeOption, onAdd: addOption })),
64
+ }) ?? (_jsx(DecisionInlineSettings, { options: data.options, onToggleRecommended: (option) => updateOption(option.id, { recommended: !option.recommended }), onRemove: removeOption, onAdd: addOption })))
65
+ : null;
66
+ return (_jsxs("div", { className: "grid gap-5", "data-plan-interactive": true, children: [_jsxs("div", { className: "flex items-start gap-3", children: [_jsxs("label", { className: "grid min-w-0 flex-1 gap-1.5", children: [_jsx("span", { className: inlineLabelClass, children: "Question" }), _jsx("textarea", { className: inlineTextareaClass, rows: 2, value: data.question, disabled: !editable, onChange: (event) => onChange({ ...data, question: event.target.value }) })] }), settings] }), _jsx("div", { className: "grid gap-3", children: data.options.map((option) => (_jsxs("article", { className: cn("rounded-lg border border-border bg-muted p-4", option.recommended &&
67
+ "border-ring/60 shadow-[inset_3px_0_0_hsl(var(--ring))]"), children: [_jsx("div", { className: "grid gap-3", children: _jsxs("label", { className: "grid gap-1.5", children: [_jsx("span", { className: inlineLabelClass, children: "Option" }), _jsx("input", { className: inlineInputClass, value: option.label, disabled: !editable, onChange: (event) => updateOption(option.id, { label: event.target.value }) })] }) }), _jsxs("label", { className: "mt-3 grid gap-1.5", children: [_jsx("span", { className: inlineLabelClass, children: "Detail" }), _jsx("textarea", { className: inlineTextareaClass, rows: 2, value: option.detail ?? "", disabled: !editable, onChange: (event) => updateOption(option.id, {
68
+ detail: event.target.value || undefined,
69
+ }) })] })] }, option.id))) })] }));
70
+ }
71
+ /** Option-management controls rendered inside the host's edit surface popover. */
72
+ function DecisionSettings({ options, onToggleRecommended, onRemove, onAdd, }) {
73
+ return (_jsxs("div", { className: "grid gap-3", children: [_jsx("div", { className: "text-sm font-semibold text-foreground", children: "Decision settings" }), _jsx("div", { className: "grid gap-2", children: options.map((option, index) => (_jsxs("div", { className: "grid gap-2 rounded-md border border-border bg-muted/20 p-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-2", children: [_jsx("span", { className: "min-w-0 truncate text-xs font-medium text-foreground", children: option.label.trim() || `Option ${index + 1}` }), option.recommended && (_jsx("span", { className: "shrink-0 rounded-full border border-border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground", children: "Recommended" }))] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("button", { type: "button", "data-plan-interactive": true, onClick: () => onToggleRecommended(option), className: cn("inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium transition-colors", option.recommended
74
+ ? "bg-background text-foreground shadow-sm"
75
+ : "text-muted-foreground hover:bg-background/70 hover:text-foreground"), children: [option.recommended && _jsx(IconCheck, { className: "size-3.5" }), option.recommended ? "Recommended" : "Mark recommended"] }), _jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": `Delete ${option.label || `option ${index + 1}`}`, disabled: options.length <= 1, onClick: () => onRemove(option.id), className: "inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-border text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50", children: _jsx(IconTrash, { className: "size-3.5" }) })] })] }, option.id))) }), _jsxs("button", { type: "button", "data-plan-interactive": true, disabled: options.length >= 20, onClick: onAdd, className: "inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50", children: [_jsx(IconPlus, { className: "size-3.5" }), "Add option"] })] }));
76
+ }
77
+ /**
78
+ * Fallback for hosts that do not provide `ctx.renderEditSurface`: a plain
79
+ * disclosure button that reveals the same settings inline (no overlay primitive,
80
+ * so core stays shadcn-free).
81
+ */
82
+ function DecisionInlineSettings(props) {
83
+ const [open, setOpen] = useState(false);
84
+ return (_jsxs("div", { className: "grid gap-2", children: [_jsx("button", { type: "button", "data-plan-interactive": true, "aria-label": "Edit decision options", "aria-expanded": open, onClick: () => setOpen((value) => !value), className: "flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground", children: _jsx(IconPencil, { className: "size-4" }) }), open && (_jsx("div", { className: "w-80 rounded-md border border-border bg-background p-3 shadow-sm", children: _jsx(DecisionSettings, { ...props }) }))] }));
85
+ }
86
+ /** Full client spec for the shared `decision` block (schema + MDX + Read/Edit). */
87
+ export const decisionBlock = defineBlock({
88
+ type: "decision",
89
+ schema: decisionSchema,
90
+ mdx: decisionMdx,
91
+ Read: DecisionBlock,
92
+ Edit: DecisionBlockEdit,
93
+ placement: ["block"],
94
+ // `panel`: the document shows the clean read view (question + option cards with
95
+ // the recommended pick highlighted), and the corner pencil opens the editor in
96
+ // a popover. NOT `inline` — an inline schema-editing form (question + per-option
97
+ // textareas) rendered straight into the doc reads as a confusing data-entry wall
98
+ // rather than a decision. Mirrors how `question-form` / `visual-questions` edit.
99
+ editSurface: "panel",
100
+ label: "Decision",
101
+ description: "A decision prompt with option cards and an authored recommended choice. Shows a clean read view in the document; edit the question and options from the corner pencil.",
102
+ empty: () => ({
103
+ question: "Which implementation direction should we take?",
104
+ options: [
105
+ {
106
+ id: "recommended",
107
+ label: "Recommended path",
108
+ detail: "Smallest useful slice with clear rollback.",
109
+ recommended: true,
110
+ },
111
+ {
112
+ id: "alternative",
113
+ label: "Alternative",
114
+ detail: "Broader pass that touches more surfaces.",
115
+ },
116
+ ],
117
+ }),
118
+ });
119
+ //# sourceMappingURL=decision.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision.js","sourceRoot":"","sources":["../../../../src/client/blocks/library/decision.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useState } from \"react\";\nimport {\n IconCheck,\n IconPencil,\n IconPlus,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { cn } from \"../../utils.js\";\nimport { defineBlock } from \"../types.js\";\nimport type { BlockReadProps, BlockEditProps } from \"../types.js\";\nimport {\n decisionMdx,\n decisionSchema,\n type DecisionData,\n type DecisionOption,\n} from \"./decision.config.js\";\n\n/**\n * Standard `decision` block — a decision prompt with inline-editable option\n * cards and one authored \"recommended\" choice. Lives in core so any app can\n * register it (it originated in the plan template).\n *\n * The root `<section>` keeps the app-neutral `an-block` class (document-flow\n * spacing hook) alongside the legacy `plan-block` class (styled by the plan\n * template's own stylesheet), so plan renders as before and any other app gets\n * theme-token styling. All inner color comes from shadcn theme tokens\n * (`text-muted-foreground`, `text-foreground`, `bg-muted`, `bg-background`,\n * `border-border`, `ring`), so it reads correctly in any template palette.\n */\nexport function DecisionBlock({\n data,\n blockId,\n title,\n}: BlockReadProps<DecisionData>) {\n return (\n <section className=\"an-block plan-block\" data-block-id={blockId}>\n {title && <div className=\"an-block-label plan-block-label\">{title}</div>}\n <p className=\"mt-3 max-w-3xl text-lg leading-8 text-muted-foreground\">\n {data.question}\n </p>\n <div className=\"mt-6 grid gap-3 md:grid-cols-2\">\n {data.options.map((option) => (\n <article\n key={option.id}\n className={cn(\n \"rounded-xl border border-border bg-muted p-4\",\n option.recommended\n ? \"shadow-[inset_3px_0_0_hsl(var(--ring))]\"\n : \"opacity-85\",\n )}\n >\n <div className=\"flex items-start justify-between gap-3\">\n <h3 className=\"text-lg font-semibold tracking-tight text-foreground\">\n {option.label}\n </h3>\n {option.recommended && (\n <span className=\"rounded-full border border-border px-2 py-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground\">\n Recommended\n </span>\n )}\n </div>\n {option.detail && (\n <p className=\"mt-3 text-sm leading-6 text-muted-foreground\">\n {option.detail}\n </p>\n )}\n </article>\n ))}\n </div>\n </section>\n );\n}\n\nconst inlineInputClass =\n \"w-full rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring\";\nconst inlineTextareaClass =\n \"w-full resize-y rounded-md border border-border bg-background px-3 py-2 text-sm leading-6 text-foreground shadow-sm outline-none transition-colors placeholder:text-muted-foreground focus:border-ring\";\nconst inlineLabelClass =\n \"text-[11px] font-semibold uppercase tracking-[0.08em] text-muted-foreground\";\n\nfunction newLocalId(prefix: string): string {\n return `${prefix}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function DecisionBlockEdit({\n data,\n onChange,\n editable,\n blockId,\n title,\n summary,\n ctx,\n}: BlockEditProps<DecisionData>) {\n const updateOption = (optionId: string, patch: Partial<DecisionOption>) =>\n onChange({\n ...data,\n options: data.options.map((option) =>\n option.id === optionId ? { ...option, ...patch } : option,\n ),\n });\n\n const removeOption = (optionId: string) => {\n if (data.options.length <= 1) return;\n onChange({\n ...data,\n options: data.options.filter((option) => option.id !== optionId),\n });\n };\n\n const addOption = () => {\n if (data.options.length >= 20) return;\n onChange({\n ...data,\n options: [\n ...data.options,\n { id: newLocalId(\"option\"), label: \"New option\" },\n ],\n });\n };\n\n const settings = editable\n ? (ctx.renderEditSurface?.({\n title: \"Decision\",\n blockId,\n blockType: \"decision\",\n blockTitle: title,\n blockSummary: summary,\n blockData: data,\n trigger: (\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit decision options\"\n className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground\"\n >\n <IconPencil className=\"size-4\" />\n </button>\n ),\n children: (\n <DecisionSettings\n options={data.options}\n onToggleRecommended={(option) =>\n updateOption(option.id, { recommended: !option.recommended })\n }\n onRemove={removeOption}\n onAdd={addOption}\n />\n ),\n }) ?? (\n // No panel surface provided by the host: fall back to a plain inline\n // settings card so option management still works.\n <DecisionInlineSettings\n options={data.options}\n onToggleRecommended={(option) =>\n updateOption(option.id, { recommended: !option.recommended })\n }\n onRemove={removeOption}\n onAdd={addOption}\n />\n ))\n : null;\n\n return (\n <div className=\"grid gap-5\" data-plan-interactive>\n <div className=\"flex items-start gap-3\">\n <label className=\"grid min-w-0 flex-1 gap-1.5\">\n <span className={inlineLabelClass}>Question</span>\n <textarea\n className={inlineTextareaClass}\n rows={2}\n value={data.question}\n disabled={!editable}\n onChange={(event) =>\n onChange({ ...data, question: event.target.value })\n }\n />\n </label>\n {settings}\n </div>\n <div className=\"grid gap-3\">\n {data.options.map((option) => (\n <article\n key={option.id}\n className={cn(\n \"rounded-lg border border-border bg-muted p-4\",\n option.recommended &&\n \"border-ring/60 shadow-[inset_3px_0_0_hsl(var(--ring))]\",\n )}\n >\n <div className=\"grid gap-3\">\n <label className=\"grid gap-1.5\">\n <span className={inlineLabelClass}>Option</span>\n <input\n className={inlineInputClass}\n value={option.label}\n disabled={!editable}\n onChange={(event) =>\n updateOption(option.id, { label: event.target.value })\n }\n />\n </label>\n </div>\n <label className=\"mt-3 grid gap-1.5\">\n <span className={inlineLabelClass}>Detail</span>\n <textarea\n className={inlineTextareaClass}\n rows={2}\n value={option.detail ?? \"\"}\n disabled={!editable}\n onChange={(event) =>\n updateOption(option.id, {\n detail: event.target.value || undefined,\n })\n }\n />\n </label>\n </article>\n ))}\n </div>\n </div>\n );\n}\n\n/** Option-management controls rendered inside the host's edit surface popover. */\nfunction DecisionSettings({\n options,\n onToggleRecommended,\n onRemove,\n onAdd,\n}: {\n options: DecisionOption[];\n onToggleRecommended: (option: DecisionOption) => void;\n onRemove: (optionId: string) => void;\n onAdd: () => void;\n}) {\n return (\n <div className=\"grid gap-3\">\n <div className=\"text-sm font-semibold text-foreground\">\n Decision settings\n </div>\n <div className=\"grid gap-2\">\n {options.map((option, index) => (\n <div\n key={option.id}\n className=\"grid gap-2 rounded-md border border-border bg-muted/20 p-2\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"min-w-0 truncate text-xs font-medium text-foreground\">\n {option.label.trim() || `Option ${index + 1}`}\n </span>\n {option.recommended && (\n <span className=\"shrink-0 rounded-full border border-border px-2 py-0.5 text-[10px] font-semibold uppercase tracking-[0.08em] text-muted-foreground\">\n Recommended\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n onClick={() => onToggleRecommended(option)}\n className={cn(\n \"inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium transition-colors\",\n option.recommended\n ? \"bg-background text-foreground shadow-sm\"\n : \"text-muted-foreground hover:bg-background/70 hover:text-foreground\",\n )}\n >\n {option.recommended && <IconCheck className=\"size-3.5\" />}\n {option.recommended ? \"Recommended\" : \"Mark recommended\"}\n </button>\n <button\n type=\"button\"\n data-plan-interactive\n aria-label={`Delete ${option.label || `option ${index + 1}`}`}\n disabled={options.length <= 1}\n onClick={() => onRemove(option.id)}\n className=\"inline-flex size-8 shrink-0 items-center justify-center rounded-md border border-border text-destructive transition-colors hover:bg-destructive/10 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconTrash className=\"size-3.5\" />\n </button>\n </div>\n </div>\n ))}\n </div>\n <button\n type=\"button\"\n data-plan-interactive\n disabled={options.length >= 20}\n onClick={onAdd}\n className=\"inline-flex h-8 items-center justify-center gap-1.5 rounded-md border border-border px-2.5 text-xs font-medium text-foreground transition-colors hover:bg-accent disabled:cursor-not-allowed disabled:opacity-50\"\n >\n <IconPlus className=\"size-3.5\" />\n Add option\n </button>\n </div>\n );\n}\n\n/**\n * Fallback for hosts that do not provide `ctx.renderEditSurface`: a plain\n * disclosure button that reveals the same settings inline (no overlay primitive,\n * so core stays shadcn-free).\n */\nfunction DecisionInlineSettings(props: {\n options: DecisionOption[];\n onToggleRecommended: (option: DecisionOption) => void;\n onRemove: (optionId: string) => void;\n onAdd: () => void;\n}) {\n const [open, setOpen] = useState(false);\n return (\n <div className=\"grid gap-2\">\n <button\n type=\"button\"\n data-plan-interactive\n aria-label=\"Edit decision options\"\n aria-expanded={open}\n onClick={() => setOpen((value) => !value)}\n className=\"flex size-9 shrink-0 items-center justify-center rounded-md border border-border bg-muted text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground\"\n >\n <IconPencil className=\"size-4\" />\n </button>\n {open && (\n <div className=\"w-80 rounded-md border border-border bg-background p-3 shadow-sm\">\n <DecisionSettings {...props} />\n </div>\n )}\n </div>\n );\n}\n\n/** Full client spec for the shared `decision` block (schema + MDX + Read/Edit). */\nexport const decisionBlock = defineBlock<DecisionData>({\n type: \"decision\",\n schema: decisionSchema,\n mdx: decisionMdx,\n Read: DecisionBlock,\n Edit: DecisionBlockEdit,\n placement: [\"block\"],\n // `panel`: the document shows the clean read view (question + option cards with\n // the recommended pick highlighted), and the corner pencil opens the editor in\n // a popover. NOT `inline` — an inline schema-editing form (question + per-option\n // textareas) rendered straight into the doc reads as a confusing data-entry wall\n // rather than a decision. Mirrors how `question-form` / `visual-questions` edit.\n editSurface: \"panel\",\n label: \"Decision\",\n description:\n \"A decision prompt with option cards and an authored recommended choice. Shows a clean read view in the document; edit the question and options from the corner pencil.\",\n empty: () => ({\n question: \"Which implementation direction should we take?\",\n options: [\n {\n id: \"recommended\",\n label: \"Recommended path\",\n detail: \"Smallest useful slice with clear rollback.\",\n recommended: true,\n },\n {\n id: \"alternative\",\n label: \"Alternative\",\n detail: \"Broader pass that touches more surfaces.\",\n },\n ],\n }),\n});\n"]}
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ import type { BlockMdxConfig } from "../types.js";
3
+ /**
4
+ * Pure (React-free) part of the shared `diagram` 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
+ * (`diagram.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 shape MUST match the legacy `<Diagram … data={…} />`
11
+ * encoding — the whole `data` object is serialized as one JSON `data` prop — so
12
+ * stored `.mdx` round-trips byte-compatibly (the block originated in the plan
13
+ * template before moving here).
14
+ */
15
+ export interface DiagramNode {
16
+ id: string;
17
+ label: string;
18
+ detail?: string;
19
+ x?: number;
20
+ y?: number;
21
+ }
22
+ export interface DiagramEdge {
23
+ from: string;
24
+ to: string;
25
+ label?: string;
26
+ }
27
+ export interface DiagramNote {
28
+ id: string;
29
+ text: string;
30
+ x?: number;
31
+ y?: number;
32
+ }
33
+ export interface DiagramData {
34
+ /**
35
+ * Preferred authoring path for architecture/code diagrams: a scoped, inert
36
+ * HTML/SVG fragment. Use .diagram-* primitives and --wf-* tokens; the
37
+ * renderer supplies theme-token-backed styling plus sketch/clean style hooks.
38
+ */
39
+ html?: string;
40
+ css?: string;
41
+ caption?: string;
42
+ /**
43
+ * Legacy compatibility path for older/simple node graphs. New plans should use
44
+ * `html`/`css` when layout quality matters.
45
+ */
46
+ nodes?: DiagramNode[];
47
+ edges?: DiagramEdge[];
48
+ notes?: DiagramNote[];
49
+ }
50
+ /**
51
+ * The block can be a flexible HTML/SVG fragment or a legacy positional
52
+ * node/edge/note graph, so it ships a custom `Edit` rather than relying on the
53
+ * schema auto-editor. Editing stays comment/patch-driven.
54
+ */
55
+ export declare const diagramSchema: z.ZodType<DiagramData>;
56
+ /**
57
+ * MDX config: the entire `data` object is serialized as one JSON `data` prop and
58
+ * the element is self-closing — exactly the legacy `<Diagram id … data={…} />`
59
+ * form. `toAttrs` returns `{ data }`; `fromAttrs` reads the `data` object,
60
+ * mirroring the legacy `dataAttr(node, "data") ?? { nodes: [], edges: [] }`
61
+ * default so plans missing the prop still parse.
62
+ */
63
+ export declare const diagramMdx: BlockMdxConfig<DiagramData>;
64
+ //# sourceMappingURL=diagram.config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagram.config.d.ts","sourceRoot":"","sources":["../../../../src/client/blocks/library/diagram.config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;CACvB;AAoED;;;;GAIG;AACH,eAAO,MAAM,aAAa,EA8BP,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAE1C;;;;;;GAMG;AACH,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,WAAW,CAWlD,CAAC"}