@inharness-ai/claude4spec 1.0.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 (552) hide show
  1. package/.claude/skills/c4s-brief-implementer/SKILL.md +105 -0
  2. package/.claude/skills/c4s-spec-reader/SKILL.md +46 -0
  3. package/CHANGELOG.md +19 -0
  4. package/LICENSE +21 -0
  5. package/README.md +50 -0
  6. package/dist/bin/agent-md-template.d.ts +1 -0
  7. package/dist/bin/agent-md-template.js +76 -0
  8. package/dist/bin/agent-md-template.js.map +1 -0
  9. package/dist/bin/bootstrap-template.d.ts +1 -0
  10. package/dist/bin/bootstrap-template.js +12 -0
  11. package/dist/bin/bootstrap-template.js.map +1 -0
  12. package/dist/bin/c4s/args.d.ts +13 -0
  13. package/dist/bin/c4s/args.js +82 -0
  14. package/dist/bin/c4s/args.js.map +1 -0
  15. package/dist/bin/c4s/commands/_meta.d.ts +2 -0
  16. package/dist/bin/c4s/commands/_meta.js +13 -0
  17. package/dist/bin/c4s/commands/_meta.js.map +1 -0
  18. package/dist/bin/c4s/commands/catalog.d.ts +2 -0
  19. package/dist/bin/c4s/commands/catalog.js +38 -0
  20. package/dist/bin/c4s/commands/catalog.js.map +1 -0
  21. package/dist/bin/c4s/commands/detail.d.ts +2 -0
  22. package/dist/bin/c4s/commands/detail.js +22 -0
  23. package/dist/bin/c4s/commands/detail.js.map +1 -0
  24. package/dist/bin/c4s/commands/element-list.d.ts +2 -0
  25. package/dist/bin/c4s/commands/element-list.js +23 -0
  26. package/dist/bin/c4s/commands/element-list.js.map +1 -0
  27. package/dist/bin/c4s/commands/inline-mention.d.ts +2 -0
  28. package/dist/bin/c4s/commands/inline-mention.js +22 -0
  29. package/dist/bin/c4s/commands/inline-mention.js.map +1 -0
  30. package/dist/bin/c4s/commands/list-slugs.d.ts +2 -0
  31. package/dist/bin/c4s/commands/list-slugs.js +16 -0
  32. package/dist/bin/c4s/commands/list-slugs.js.map +1 -0
  33. package/dist/bin/c4s/commands/list-tags.d.ts +2 -0
  34. package/dist/bin/c4s/commands/list-tags.js +13 -0
  35. package/dist/bin/c4s/commands/list-tags.js.map +1 -0
  36. package/dist/bin/c4s/commands/resolve.d.ts +2 -0
  37. package/dist/bin/c4s/commands/resolve.js +40 -0
  38. package/dist/bin/c4s/commands/resolve.js.map +1 -0
  39. package/dist/bin/c4s/commands/section-ref.d.ts +2 -0
  40. package/dist/bin/c4s/commands/section-ref.js +25 -0
  41. package/dist/bin/c4s/commands/section-ref.js.map +1 -0
  42. package/dist/bin/c4s/commands/single-element.d.ts +2 -0
  43. package/dist/bin/c4s/commands/single-element.js +22 -0
  44. package/dist/bin/c4s/commands/single-element.js.map +1 -0
  45. package/dist/bin/c4s/commands/tagged-list-mixed.d.ts +2 -0
  46. package/dist/bin/c4s/commands/tagged-list-mixed.js +39 -0
  47. package/dist/bin/c4s/commands/tagged-list-mixed.js.map +1 -0
  48. package/dist/bin/c4s/commands/tagged-list.d.ts +2 -0
  49. package/dist/bin/c4s/commands/tagged-list.js +24 -0
  50. package/dist/bin/c4s/commands/tagged-list.js.map +1 -0
  51. package/dist/bin/c4s/context.d.ts +12 -0
  52. package/dist/bin/c4s/context.js +27 -0
  53. package/dist/bin/c4s/context.js.map +1 -0
  54. package/dist/bin/c4s/errors.d.ts +6 -0
  55. package/dist/bin/c4s/errors.js +11 -0
  56. package/dist/bin/c4s/errors.js.map +1 -0
  57. package/dist/bin/c4s/output.d.ts +4 -0
  58. package/dist/bin/c4s/output.js +57 -0
  59. package/dist/bin/c4s/output.js.map +1 -0
  60. package/dist/bin/c4s/project.d.ts +1 -0
  61. package/dist/bin/c4s/project.js +23 -0
  62. package/dist/bin/c4s/project.js.map +1 -0
  63. package/dist/bin/c4s/type-validation.d.ts +3 -0
  64. package/dist/bin/c4s/type-validation.js +11 -0
  65. package/dist/bin/c4s/type-validation.js.map +1 -0
  66. package/dist/bin/c4s-mcp.d.ts +2 -0
  67. package/dist/bin/c4s-mcp.js +118 -0
  68. package/dist/bin/c4s-mcp.js.map +1 -0
  69. package/dist/bin/c4s.d.ts +2 -0
  70. package/dist/bin/c4s.js +134 -0
  71. package/dist/bin/c4s.js.map +1 -0
  72. package/dist/bin/claude4spec.d.ts +2 -0
  73. package/dist/bin/claude4spec.js +132 -0
  74. package/dist/bin/claude4spec.js.map +1 -0
  75. package/dist/bin/gitignore.d.ts +1 -0
  76. package/dist/bin/gitignore.js +44 -0
  77. package/dist/bin/gitignore.js.map +1 -0
  78. package/dist/client/assets/arc-D8brDDag.js +1 -0
  79. package/dist/client/assets/architectureDiagram-3BPJPVTR-Bmh1uTQZ.js +36 -0
  80. package/dist/client/assets/blockDiagram-GPEHLZMM-55jaVWwd.js +132 -0
  81. package/dist/client/assets/c4Diagram-AAUBKEIU-Dxm0tLsZ.js +10 -0
  82. package/dist/client/assets/channel-ArVcv4Yl.js +1 -0
  83. package/dist/client/assets/chunk-2J33WTMH-vDJ1slcJ.js +1 -0
  84. package/dist/client/assets/chunk-4BX2VUAB-DP6CC-Qn.js +1 -0
  85. package/dist/client/assets/chunk-55IACEB6-SgOSJYkL.js +1 -0
  86. package/dist/client/assets/chunk-727SXJPM-BtRfbjBO.js +206 -0
  87. package/dist/client/assets/chunk-AQP2D5EJ-yIRaTgFg.js +231 -0
  88. package/dist/client/assets/chunk-FMBD7UC4-B_VD4t8N.js +15 -0
  89. package/dist/client/assets/chunk-ND2GUHAM-BvJdtX82.js +1 -0
  90. package/dist/client/assets/chunk-QZHKN3VN-BLNWKymD.js +1 -0
  91. package/dist/client/assets/classDiagram-4FO5ZUOK-B3nmPR7w.js +1 -0
  92. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B3nmPR7w.js +1 -0
  93. package/dist/client/assets/cose-bilkent-S5V4N54A-BQyA-r-y.js +1 -0
  94. package/dist/client/assets/cytoscape.esm-D_LviqZs.js +331 -0
  95. package/dist/client/assets/dagre-BM42HDAG-CAh0mTzA.js +4 -0
  96. package/dist/client/assets/defaultLocale-DX6XiGOO.js +1 -0
  97. package/dist/client/assets/diagram-2AECGRRQ-C83TGK4o.js +43 -0
  98. package/dist/client/assets/diagram-5GNKFQAL-2L6uowvf.js +10 -0
  99. package/dist/client/assets/diagram-KO2AKTUF-Cj5n4jdq.js +3 -0
  100. package/dist/client/assets/diagram-LMA3HP47-Bp5SDMjg.js +24 -0
  101. package/dist/client/assets/diagram-OG6HWLK6-cFsDQ8Qk.js +24 -0
  102. package/dist/client/assets/erDiagram-TEJ5UH35-D8G5xpg3.js +85 -0
  103. package/dist/client/assets/flowDiagram-I6XJVG4X-CuNudlCD.js +162 -0
  104. package/dist/client/assets/ganttDiagram-6RSMTGT7-CtFlsB15.js +292 -0
  105. package/dist/client/assets/gitGraphDiagram-PVQCEYII-h66Tso4O.js +106 -0
  106. package/dist/client/assets/graph-CAnANduQ.js +1 -0
  107. package/dist/client/assets/index-CZOpb3O7.css +1 -0
  108. package/dist/client/assets/index-D5ljIkCJ.js +727 -0
  109. package/dist/client/assets/index-aJE-l7h7.js +11 -0
  110. package/dist/client/assets/index-aPVup1Re.js +51 -0
  111. package/dist/client/assets/infoDiagram-5YYISTIA-CO_BLfuW.js +2 -0
  112. package/dist/client/assets/init-Gi6I4Gst.js +1 -0
  113. package/dist/client/assets/ishikawaDiagram-YF4QCWOH-D4rSRnQA.js +70 -0
  114. package/dist/client/assets/journeyDiagram-JHISSGLW-GyHI6dB8.js +139 -0
  115. package/dist/client/assets/kanban-definition-UN3LZRKU-CrH33WLe.js +89 -0
  116. package/dist/client/assets/katex-CQk2-UhE.js +257 -0
  117. package/dist/client/assets/layout-DGIYPm2g.js +1 -0
  118. package/dist/client/assets/linear-Dh1OyvSm.js +1 -0
  119. package/dist/client/assets/mermaid.core-C45sMDhS.js +309 -0
  120. package/dist/client/assets/mindmap-definition-RKZ34NQL-Bgwb0vwA.js +96 -0
  121. package/dist/client/assets/ordinal-Cboi1Yqb.js +1 -0
  122. package/dist/client/assets/pieDiagram-4H26LBE5-l9cCpVfG.js +30 -0
  123. package/dist/client/assets/quadrantDiagram-W4KKPZXB-BCPSUbC3.js +7 -0
  124. package/dist/client/assets/requirementDiagram-4Y6WPE33-TEGOe-vV.js +84 -0
  125. package/dist/client/assets/sankeyDiagram-5OEKKPKP-C69pv_7D.js +40 -0
  126. package/dist/client/assets/sequenceDiagram-3UESZ5HK-arinzeCk.js +162 -0
  127. package/dist/client/assets/stateDiagram-AJRCARHV-C2YENpmw.js +1 -0
  128. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-CS6ocDH6.js +1 -0
  129. package/dist/client/assets/timeline-definition-PNZ67QCA-h5qtI99f.js +120 -0
  130. package/dist/client/assets/vennDiagram-CIIHVFJN-CnuK75Ut.js +34 -0
  131. package/dist/client/assets/wardley-L42UT6IY-B4bQ0Xyy.js +173 -0
  132. package/dist/client/assets/wardleyDiagram-YWT4CUSO-apV8olQc.js +78 -0
  133. package/dist/client/assets/xychartDiagram-2RQKCTM6-OTP6zeEy.js +7 -0
  134. package/dist/client/index.html +19 -0
  135. package/dist/server/config.d.ts +59 -0
  136. package/dist/server/config.js +211 -0
  137. package/dist/server/config.js.map +1 -0
  138. package/dist/server/core/plugin-host/cross-cutting.d.ts +8 -0
  139. package/dist/server/core/plugin-host/cross-cutting.js +14 -0
  140. package/dist/server/core/plugin-host/cross-cutting.js.map +1 -0
  141. package/dist/server/core/plugin-host/entities-router.d.ts +11 -0
  142. package/dist/server/core/plugin-host/entities-router.js +77 -0
  143. package/dist/server/core/plugin-host/entities-router.js.map +1 -0
  144. package/dist/server/core/plugin-host/host.d.ts +11 -0
  145. package/dist/server/core/plugin-host/host.js +128 -0
  146. package/dist/server/core/plugin-host/host.js.map +1 -0
  147. package/dist/server/core/plugin-host/legacy-adapter.d.ts +31 -0
  148. package/dist/server/core/plugin-host/legacy-adapter.js +88 -0
  149. package/dist/server/core/plugin-host/legacy-adapter.js.map +1 -0
  150. package/dist/server/core/plugin-host/serialization-engine.d.ts +35 -0
  151. package/dist/server/core/plugin-host/serialization-engine.js +132 -0
  152. package/dist/server/core/plugin-host/serialization-engine.js.map +1 -0
  153. package/dist/server/core/plugin-host/types.d.ts +143 -0
  154. package/dist/server/core/plugin-host/types.js +10 -0
  155. package/dist/server/core/plugin-host/types.js.map +1 -0
  156. package/dist/server/db/fixups/backfill-plan-titles.d.ts +2 -0
  157. package/dist/server/db/fixups/backfill-plan-titles.js +22 -0
  158. package/dist/server/db/fixups/backfill-plan-titles.js.map +1 -0
  159. package/dist/server/db/index.d.ts +6 -0
  160. package/dist/server/db/index.js +26 -0
  161. package/dist/server/db/index.js.map +1 -0
  162. package/dist/server/db/migrate.d.ts +2 -0
  163. package/dist/server/db/migrate.js +33 -0
  164. package/dist/server/db/migrate.js.map +1 -0
  165. package/dist/server/db/migrations/000_init.sql +7 -0
  166. package/dist/server/db/migrations/001_endpoint.sql +51 -0
  167. package/dist/server/db/migrations/002_dto.sql +23 -0
  168. package/dist/server/db/migrations/003_drop_endpoint_body.sql +5 -0
  169. package/dist/server/db/migrations/004_drop_module_and_status.sql +31 -0
  170. package/dist/server/db/migrations/005_chat.sql +23 -0
  171. package/dist/server/db/migrations/006_database_table.sql +10 -0
  172. package/dist/server/db/migrations/007_sections.sql +30 -0
  173. package/dist/server/db/migrations/008_subagent_task.sql +20 -0
  174. package/dist/server/db/migrations/009_chat_todo_snapshot.sql +4 -0
  175. package/dist/server/db/migrations/010_chat_plan_mode.sql +5 -0
  176. package/dist/server/db/migrations/011_chat_initial_system_prompt.sql +4 -0
  177. package/dist/server/db/migrations/012_chat_message_status.sql +5 -0
  178. package/dist/server/db/migrations/013_chat_usage_snapshot.sql +7 -0
  179. package/dist/server/db/migrations/014_plans.sql +33 -0
  180. package/dist/server/db/migrations/015_dto_examples.sql +4 -0
  181. package/dist/server/db/migrations/016_ui_view.sql +10 -0
  182. package/dist/server/db/migrations/017_entity_version_m17.sql +23 -0
  183. package/dist/server/db/migrations/018_page_version.sql +20 -0
  184. package/dist/server/db/migrations/019_spec_release.sql +13 -0
  185. package/dist/server/db/migrations/020_drop_plan_status.sql +10 -0
  186. package/dist/server/db/migrations/021_plans_n1.sql +36 -0
  187. package/dist/server/db/migrations/022_brief_chat_columns.sql +23 -0
  188. package/dist/server/db/migrations/023_page_version_kind.sql +26 -0
  189. package/dist/server/db/migrations/024_chat_context_size.sql +10 -0
  190. package/dist/server/db/migrations/025_ac.sql +19 -0
  191. package/dist/server/db/migrations/026_ac_seed.sql +75 -0
  192. package/dist/server/db/migrations/027_page_version_change_summary.sql +10 -0
  193. package/dist/server/db/readonly.d.ts +12 -0
  194. package/dist/server/db/readonly.js +32 -0
  195. package/dist/server/db/readonly.js.map +1 -0
  196. package/dist/server/domain/raw-entity-reader.d.ts +76 -0
  197. package/dist/server/domain/raw-entity-reader.js +240 -0
  198. package/dist/server/domain/raw-entity-reader.js.map +1 -0
  199. package/dist/server/entities/ac/mcp-server.d.ts +10 -0
  200. package/dist/server/entities/ac/mcp-server.js +154 -0
  201. package/dist/server/entities/ac/mcp-server.js.map +1 -0
  202. package/dist/server/entities/ac/plugin.d.ts +2 -0
  203. package/dist/server/entities/ac/plugin.js +33 -0
  204. package/dist/server/entities/ac/plugin.js.map +1 -0
  205. package/dist/server/entities/ac/routes.d.ts +4 -0
  206. package/dist/server/entities/ac/routes.js +92 -0
  207. package/dist/server/entities/ac/routes.js.map +1 -0
  208. package/dist/server/entities/ac/serializer.d.ts +13 -0
  209. package/dist/server/entities/ac/serializer.js +124 -0
  210. package/dist/server/entities/ac/serializer.js.map +1 -0
  211. package/dist/server/entities/ac/services.d.ts +35 -0
  212. package/dist/server/entities/ac/services.js +261 -0
  213. package/dist/server/entities/ac/services.js.map +1 -0
  214. package/dist/server/entities/ac/system-prompt.d.ts +2 -0
  215. package/dist/server/entities/ac/system-prompt.js +18 -0
  216. package/dist/server/entities/ac/system-prompt.js.map +1 -0
  217. package/dist/server/entities/database-table/mcp-server.d.ts +10 -0
  218. package/dist/server/entities/database-table/mcp-server.js +184 -0
  219. package/dist/server/entities/database-table/mcp-server.js.map +1 -0
  220. package/dist/server/entities/database-table/plugin.d.ts +2 -0
  221. package/dist/server/entities/database-table/plugin.js +33 -0
  222. package/dist/server/entities/database-table/plugin.js.map +1 -0
  223. package/dist/server/entities/database-table/routes.d.ts +5 -0
  224. package/dist/server/entities/database-table/routes.js +86 -0
  225. package/dist/server/entities/database-table/routes.js.map +1 -0
  226. package/dist/server/entities/database-table/serializer.d.ts +12 -0
  227. package/dist/server/entities/database-table/serializer.js +192 -0
  228. package/dist/server/entities/database-table/serializer.js.map +1 -0
  229. package/dist/server/entities/database-table/services.d.ts +45 -0
  230. package/dist/server/entities/database-table/services.js +323 -0
  231. package/dist/server/entities/database-table/services.js.map +1 -0
  232. package/dist/server/entities/database-table/system-prompt.d.ts +2 -0
  233. package/dist/server/entities/database-table/system-prompt.js +11 -0
  234. package/dist/server/entities/database-table/system-prompt.js.map +1 -0
  235. package/dist/server/entities/dto/mcp-server.d.ts +10 -0
  236. package/dist/server/entities/dto/mcp-server.js +141 -0
  237. package/dist/server/entities/dto/mcp-server.js.map +1 -0
  238. package/dist/server/entities/dto/plugin.d.ts +2 -0
  239. package/dist/server/entities/dto/plugin.js +33 -0
  240. package/dist/server/entities/dto/plugin.js.map +1 -0
  241. package/dist/server/entities/dto/routes.d.ts +4 -0
  242. package/dist/server/entities/dto/routes.js +74 -0
  243. package/dist/server/entities/dto/routes.js.map +1 -0
  244. package/dist/server/entities/dto/serializer.d.ts +12 -0
  245. package/dist/server/entities/dto/serializer.js +184 -0
  246. package/dist/server/entities/dto/serializer.js.map +1 -0
  247. package/dist/server/entities/dto/services.d.ts +30 -0
  248. package/dist/server/entities/dto/services.js +242 -0
  249. package/dist/server/entities/dto/services.js.map +1 -0
  250. package/dist/server/entities/dto/system-prompt.d.ts +2 -0
  251. package/dist/server/entities/dto/system-prompt.js +11 -0
  252. package/dist/server/entities/dto/system-prompt.js.map +1 -0
  253. package/dist/server/entities/endpoint/mcp-server.d.ts +10 -0
  254. package/dist/server/entities/endpoint/mcp-server.js +156 -0
  255. package/dist/server/entities/endpoint/mcp-server.js.map +1 -0
  256. package/dist/server/entities/endpoint/plugin.d.ts +2 -0
  257. package/dist/server/entities/endpoint/plugin.js +36 -0
  258. package/dist/server/entities/endpoint/plugin.js.map +1 -0
  259. package/dist/server/entities/endpoint/routes.d.ts +4 -0
  260. package/dist/server/entities/endpoint/routes.js +107 -0
  261. package/dist/server/entities/endpoint/routes.js.map +1 -0
  262. package/dist/server/entities/endpoint/serializer.d.ts +17 -0
  263. package/dist/server/entities/endpoint/serializer.js +217 -0
  264. package/dist/server/entities/endpoint/serializer.js.map +1 -0
  265. package/dist/server/entities/endpoint/services.d.ts +30 -0
  266. package/dist/server/entities/endpoint/services.js +260 -0
  267. package/dist/server/entities/endpoint/services.js.map +1 -0
  268. package/dist/server/entities/endpoint/system-prompt.d.ts +2 -0
  269. package/dist/server/entities/endpoint/system-prompt.js +11 -0
  270. package/dist/server/entities/endpoint/system-prompt.js.map +1 -0
  271. package/dist/server/entities/ui-view/mcp-server.d.ts +10 -0
  272. package/dist/server/entities/ui-view/mcp-server.js +161 -0
  273. package/dist/server/entities/ui-view/mcp-server.js.map +1 -0
  274. package/dist/server/entities/ui-view/plugin.d.ts +2 -0
  275. package/dist/server/entities/ui-view/plugin.js +33 -0
  276. package/dist/server/entities/ui-view/plugin.js.map +1 -0
  277. package/dist/server/entities/ui-view/routes.d.ts +5 -0
  278. package/dist/server/entities/ui-view/routes.js +82 -0
  279. package/dist/server/entities/ui-view/routes.js.map +1 -0
  280. package/dist/server/entities/ui-view/serializer.d.ts +12 -0
  281. package/dist/server/entities/ui-view/serializer.js +262 -0
  282. package/dist/server/entities/ui-view/serializer.js.map +1 -0
  283. package/dist/server/entities/ui-view/services.d.ts +35 -0
  284. package/dist/server/entities/ui-view/services.js +255 -0
  285. package/dist/server/entities/ui-view/services.js.map +1 -0
  286. package/dist/server/entities/ui-view/system-prompt.d.ts +7 -0
  287. package/dist/server/entities/ui-view/system-prompt.js +15 -0
  288. package/dist/server/entities/ui-view/system-prompt.js.map +1 -0
  289. package/dist/server/external-skills/brief-implementer-template.d.ts +2 -0
  290. package/dist/server/external-skills/brief-implementer-template.js +123 -0
  291. package/dist/server/external-skills/brief-implementer-template.js.map +1 -0
  292. package/dist/server/external-skills/external-skills-service.d.ts +3 -0
  293. package/dist/server/external-skills/external-skills-service.js +47 -0
  294. package/dist/server/external-skills/external-skills-service.js.map +1 -0
  295. package/dist/server/external-skills/spec-reader-template.d.ts +2 -0
  296. package/dist/server/external-skills/spec-reader-template.js +47 -0
  297. package/dist/server/external-skills/spec-reader-template.js.map +1 -0
  298. package/dist/server/fs/watcher.d.ts +26 -0
  299. package/dist/server/fs/watcher.js +64 -0
  300. package/dist/server/fs/watcher.js.map +1 -0
  301. package/dist/server/index.d.ts +18 -0
  302. package/dist/server/index.js +474 -0
  303. package/dist/server/index.js.map +1 -0
  304. package/dist/server/mcp/brief-tools.d.ts +19 -0
  305. package/dist/server/mcp/brief-tools.js +189 -0
  306. package/dist/server/mcp/brief-tools.js.map +1 -0
  307. package/dist/server/mcp/c4s-reader.d.ts +12 -0
  308. package/dist/server/mcp/c4s-reader.js +263 -0
  309. package/dist/server/mcp/c4s-reader.js.map +1 -0
  310. package/dist/server/mcp/database-tools.d.ts +10 -0
  311. package/dist/server/mcp/database-tools.js +184 -0
  312. package/dist/server/mcp/database-tools.js.map +1 -0
  313. package/dist/server/mcp/dependency-tools.d.ts +12 -0
  314. package/dist/server/mcp/dependency-tools.js +205 -0
  315. package/dist/server/mcp/dependency-tools.js.map +1 -0
  316. package/dist/server/mcp/dto-tools.d.ts +10 -0
  317. package/dist/server/mcp/dto-tools.js +141 -0
  318. package/dist/server/mcp/dto-tools.js.map +1 -0
  319. package/dist/server/mcp/endpoint-tools.d.ts +10 -0
  320. package/dist/server/mcp/endpoint-tools.js +156 -0
  321. package/dist/server/mcp/endpoint-tools.js.map +1 -0
  322. package/dist/server/mcp/ensure-mcp-json.d.ts +6 -0
  323. package/dist/server/mcp/ensure-mcp-json.js +30 -0
  324. package/dist/server/mcp/ensure-mcp-json.js.map +1 -0
  325. package/dist/server/mcp/index.d.ts +29 -0
  326. package/dist/server/mcp/index.js +40 -0
  327. package/dist/server/mcp/index.js.map +1 -0
  328. package/dist/server/mcp/plan-tools.d.ts +7 -0
  329. package/dist/server/mcp/plan-tools.js +105 -0
  330. package/dist/server/mcp/plan-tools.js.map +1 -0
  331. package/dist/server/mcp/reference-tools.d.ts +17 -0
  332. package/dist/server/mcp/reference-tools.js +630 -0
  333. package/dist/server/mcp/reference-tools.js.map +1 -0
  334. package/dist/server/mcp/release-tools/index.d.ts +21 -0
  335. package/dist/server/mcp/release-tools/index.js +140 -0
  336. package/dist/server/mcp/release-tools/index.js.map +1 -0
  337. package/dist/server/mcp/release-tools/projection.d.ts +32 -0
  338. package/dist/server/mcp/release-tools/projection.js +278 -0
  339. package/dist/server/mcp/release-tools/projection.js.map +1 -0
  340. package/dist/server/mcp/release-tools/types.d.ts +91 -0
  341. package/dist/server/mcp/release-tools/types.js +11 -0
  342. package/dist/server/mcp/release-tools/types.js.map +1 -0
  343. package/dist/server/mcp/release-tools.d.ts +14 -0
  344. package/dist/server/mcp/release-tools.js +83 -0
  345. package/dist/server/mcp/release-tools.js.map +1 -0
  346. package/dist/server/mcp/ui-view-tools.d.ts +10 -0
  347. package/dist/server/mcp/ui-view-tools.js +161 -0
  348. package/dist/server/mcp/ui-view-tools.js.map +1 -0
  349. package/dist/server/routes/briefs.d.ts +8 -0
  350. package/dist/server/routes/briefs.js +178 -0
  351. package/dist/server/routes/briefs.js.map +1 -0
  352. package/dist/server/routes/chat.d.ts +29 -0
  353. package/dist/server/routes/chat.js +604 -0
  354. package/dist/server/routes/chat.js.map +1 -0
  355. package/dist/server/routes/database-tables.d.ts +5 -0
  356. package/dist/server/routes/database-tables.js +86 -0
  357. package/dist/server/routes/database-tables.js.map +1 -0
  358. package/dist/server/routes/dependencies.d.ts +6 -0
  359. package/dist/server/routes/dependencies.js +164 -0
  360. package/dist/server/routes/dependencies.js.map +1 -0
  361. package/dist/server/routes/dtos.d.ts +4 -0
  362. package/dist/server/routes/dtos.js +74 -0
  363. package/dist/server/routes/dtos.js.map +1 -0
  364. package/dist/server/routes/endpoints.d.ts +4 -0
  365. package/dist/server/routes/endpoints.js +107 -0
  366. package/dist/server/routes/endpoints.js.map +1 -0
  367. package/dist/server/routes/entities.d.ts +8 -0
  368. package/dist/server/routes/entities.js +84 -0
  369. package/dist/server/routes/entities.js.map +1 -0
  370. package/dist/server/routes/errors.d.ts +2 -0
  371. package/dist/server/routes/errors.js +37 -0
  372. package/dist/server/routes/errors.js.map +1 -0
  373. package/dist/server/routes/page-links.d.ts +3 -0
  374. package/dist/server/routes/page-links.js +40 -0
  375. package/dist/server/routes/page-links.js.map +1 -0
  376. package/dist/server/routes/pages.d.ts +5 -0
  377. package/dist/server/routes/pages.js +142 -0
  378. package/dist/server/routes/pages.js.map +1 -0
  379. package/dist/server/routes/plans.d.ts +3 -0
  380. package/dist/server/routes/plans.js +192 -0
  381. package/dist/server/routes/plans.js.map +1 -0
  382. package/dist/server/routes/references.d.ts +3 -0
  383. package/dist/server/routes/references.js +34 -0
  384. package/dist/server/routes/references.js.map +1 -0
  385. package/dist/server/routes/releases.d.ts +4 -0
  386. package/dist/server/routes/releases.js +122 -0
  387. package/dist/server/routes/releases.js.map +1 -0
  388. package/dist/server/routes/sections.d.ts +3 -0
  389. package/dist/server/routes/sections.js +32 -0
  390. package/dist/server/routes/sections.js.map +1 -0
  391. package/dist/server/routes/tags.d.ts +4 -0
  392. package/dist/server/routes/tags.js +56 -0
  393. package/dist/server/routes/tags.js.map +1 -0
  394. package/dist/server/routes/threads.d.ts +3 -0
  395. package/dist/server/routes/threads.js +78 -0
  396. package/dist/server/routes/threads.js.map +1 -0
  397. package/dist/server/routes/todos.d.ts +3 -0
  398. package/dist/server/routes/todos.js +28 -0
  399. package/dist/server/routes/todos.js.map +1 -0
  400. package/dist/server/routes/ui-views.d.ts +5 -0
  401. package/dist/server/routes/ui-views.js +82 -0
  402. package/dist/server/routes/ui-views.js.map +1 -0
  403. package/dist/server/serialization/auto-schema.d.ts +3 -0
  404. package/dist/server/serialization/auto-schema.js +55 -0
  405. package/dist/server/serialization/auto-schema.js.map +1 -0
  406. package/dist/server/serialization/fallback.d.ts +4 -0
  407. package/dist/server/serialization/fallback.js +27 -0
  408. package/dist/server/serialization/fallback.js.map +1 -0
  409. package/dist/server/serialization/inline-renderer.d.ts +4 -0
  410. package/dist/server/serialization/inline-renderer.js +151 -0
  411. package/dist/server/serialization/inline-renderer.js.map +1 -0
  412. package/dist/server/serialization/registerAll.d.ts +6 -0
  413. package/dist/server/serialization/registerAll.js +7 -0
  414. package/dist/server/serialization/registerAll.js.map +1 -0
  415. package/dist/server/serialization/registry.d.ts +26 -0
  416. package/dist/server/serialization/registry.js +121 -0
  417. package/dist/server/serialization/registry.js.map +1 -0
  418. package/dist/server/serialization/resolve-page.d.ts +24 -0
  419. package/dist/server/serialization/resolve-page.js +192 -0
  420. package/dist/server/serialization/resolve-page.js.map +1 -0
  421. package/dist/server/serialization/serializers/database-table.d.ts +1 -0
  422. package/dist/server/serialization/serializers/database-table.js +46 -0
  423. package/dist/server/serialization/serializers/database-table.js.map +1 -0
  424. package/dist/server/serialization/serializers/dto.d.ts +1 -0
  425. package/dist/server/serialization/serializers/dto.js +48 -0
  426. package/dist/server/serialization/serializers/dto.js.map +1 -0
  427. package/dist/server/serialization/serializers/endpoint.d.ts +1 -0
  428. package/dist/server/serialization/serializers/endpoint.js +93 -0
  429. package/dist/server/serialization/serializers/endpoint.js.map +1 -0
  430. package/dist/server/serialization/serializers/section.d.ts +1 -0
  431. package/dist/server/serialization/serializers/section.js +24 -0
  432. package/dist/server/serialization/serializers/section.js.map +1 -0
  433. package/dist/server/serialization/serializers/ui-view.d.ts +1 -0
  434. package/dist/server/serialization/serializers/ui-view.js +124 -0
  435. package/dist/server/serialization/serializers/ui-view.js.map +1 -0
  436. package/dist/server/serialization/snapshot.d.ts +22 -0
  437. package/dist/server/serialization/snapshot.js +102 -0
  438. package/dist/server/serialization/snapshot.js.map +1 -0
  439. package/dist/server/serialization/types.d.ts +70 -0
  440. package/dist/server/serialization/types.js +7 -0
  441. package/dist/server/serialization/types.js.map +1 -0
  442. package/dist/server/serialization/writer.d.ts +41 -0
  443. package/dist/server/serialization/writer.js +13 -0
  444. package/dist/server/serialization/writer.js.map +1 -0
  445. package/dist/server/services/brief.d.ts +86 -0
  446. package/dist/server/services/brief.js +218 -0
  447. package/dist/server/services/brief.js.map +1 -0
  448. package/dist/server/services/chat-context.d.ts +26 -0
  449. package/dist/server/services/chat-context.js +434 -0
  450. package/dist/server/services/chat-context.js.map +1 -0
  451. package/dist/server/services/chat.d.ts +50 -0
  452. package/dist/server/services/chat.js +309 -0
  453. package/dist/server/services/chat.js.map +1 -0
  454. package/dist/server/services/database-table.d.ts +36 -0
  455. package/dist/server/services/database-table.js +303 -0
  456. package/dist/server/services/database-table.js.map +1 -0
  457. package/dist/server/services/dependencies.d.ts +45 -0
  458. package/dist/server/services/dependencies.js +302 -0
  459. package/dist/server/services/dependencies.js.map +1 -0
  460. package/dist/server/services/dto.d.ts +22 -0
  461. package/dist/server/services/dto.js +222 -0
  462. package/dist/server/services/dto.js.map +1 -0
  463. package/dist/server/services/endpoint.d.ts +22 -0
  464. package/dist/server/services/endpoint.js +239 -0
  465. package/dist/server/services/endpoint.js.map +1 -0
  466. package/dist/server/services/entity-writer.d.ts +46 -0
  467. package/dist/server/services/entity-writer.js +137 -0
  468. package/dist/server/services/entity-writer.js.map +1 -0
  469. package/dist/server/services/page-serializer.d.ts +109 -0
  470. package/dist/server/services/page-serializer.js +359 -0
  471. package/dist/server/services/page-serializer.js.map +1 -0
  472. package/dist/server/services/page-version.d.ts +75 -0
  473. package/dist/server/services/page-version.js +159 -0
  474. package/dist/server/services/page-version.js.map +1 -0
  475. package/dist/server/services/pages-frontmatter-indexer.d.ts +51 -0
  476. package/dist/server/services/pages-frontmatter-indexer.js +138 -0
  477. package/dist/server/services/pages-frontmatter-indexer.js.map +1 -0
  478. package/dist/server/services/pages-link-indexer.d.ts +36 -0
  479. package/dist/server/services/pages-link-indexer.js +474 -0
  480. package/dist/server/services/pages-link-indexer.js.map +1 -0
  481. package/dist/server/services/pages.d.ts +16 -0
  482. package/dist/server/services/pages.js +149 -0
  483. package/dist/server/services/pages.js.map +1 -0
  484. package/dist/server/services/plan.d.ts +59 -0
  485. package/dist/server/services/plan.js +459 -0
  486. package/dist/server/services/plan.js.map +1 -0
  487. package/dist/server/services/references.d.ts +17 -0
  488. package/dist/server/services/references.js +175 -0
  489. package/dist/server/services/references.js.map +1 -0
  490. package/dist/server/services/release.d.ts +146 -0
  491. package/dist/server/services/release.js +602 -0
  492. package/dist/server/services/release.js.map +1 -0
  493. package/dist/server/services/section-indexer.d.ts +20 -0
  494. package/dist/server/services/section-indexer.js +276 -0
  495. package/dist/server/services/section-indexer.js.map +1 -0
  496. package/dist/server/services/sections.d.ts +34 -0
  497. package/dist/server/services/sections.js +136 -0
  498. package/dist/server/services/sections.js.map +1 -0
  499. package/dist/server/services/skill-registry.d.ts +38 -0
  500. package/dist/server/services/skill-registry.js +171 -0
  501. package/dist/server/services/skill-registry.js.map +1 -0
  502. package/dist/server/services/slug.d.ts +7 -0
  503. package/dist/server/services/slug.js +41 -0
  504. package/dist/server/services/slug.js.map +1 -0
  505. package/dist/server/services/tags.d.ts +27 -0
  506. package/dist/server/services/tags.js +153 -0
  507. package/dist/server/services/tags.js.map +1 -0
  508. package/dist/server/services/todos-indexer.d.ts +21 -0
  509. package/dist/server/services/todos-indexer.js +123 -0
  510. package/dist/server/services/todos-indexer.js.map +1 -0
  511. package/dist/server/services/ui-view.d.ts +26 -0
  512. package/dist/server/services/ui-view.js +235 -0
  513. package/dist/server/services/ui-view.js.map +1 -0
  514. package/dist/server/services/versions.d.ts +59 -0
  515. package/dist/server/services/versions.js +181 -0
  516. package/dist/server/services/versions.js.map +1 -0
  517. package/dist/server/skills/brief-author/SKILL.md +117 -0
  518. package/dist/server/skills/layered-vertical-slices/SKILL.md +135 -0
  519. package/dist/server/skills/layered-vertical-slices/templates/index.md +97 -0
  520. package/dist/server/skills/layered-vertical-slices/templates/layer.md +42 -0
  521. package/dist/server/skills/layered-vertical-slices/templates/module.md +52 -0
  522. package/dist/server/skills/layered-vertical-slices/workflows/bootstrap.md +116 -0
  523. package/dist/server/skills/layered-vertical-slices/workflows/brief.md +154 -0
  524. package/dist/server/skills/layered-vertical-slices/workflows/daily.md +77 -0
  525. package/dist/server/ws/gateway.d.ts +10 -0
  526. package/dist/server/ws/gateway.js +35 -0
  527. package/dist/server/ws/gateway.js.map +1 -0
  528. package/dist/shared/anchor-pattern.d.ts +15 -0
  529. package/dist/shared/anchor-pattern.js +16 -0
  530. package/dist/shared/anchor-pattern.js.map +1 -0
  531. package/dist/shared/diagram-source-escape.d.ts +2 -0
  532. package/dist/shared/diagram-source-escape.js +19 -0
  533. package/dist/shared/diagram-source-escape.js.map +1 -0
  534. package/dist/shared/entities.d.ts +622 -0
  535. package/dist/shared/entities.js +9 -0
  536. package/dist/shared/entities.js.map +1 -0
  537. package/dist/shared/page-links.d.ts +40 -0
  538. package/dist/shared/page-links.js +2 -0
  539. package/dist/shared/page-links.js.map +1 -0
  540. package/dist/shared/plugin-host/types.d.ts +66 -0
  541. package/dist/shared/plugin-host/types.js +11 -0
  542. package/dist/shared/plugin-host/types.js.map +1 -0
  543. package/dist/shared/reference-extensions.d.ts +13 -0
  544. package/dist/shared/reference-extensions.js +17 -0
  545. package/dist/shared/reference-extensions.js.map +1 -0
  546. package/dist/shared/types.d.ts +86 -0
  547. package/dist/shared/types.js +2 -0
  548. package/dist/shared/types.js.map +1 -0
  549. package/dist/shared/xml-tags.d.ts +16 -0
  550. package/dist/shared/xml-tags.js +101 -0
  551. package/dist/shared/xml-tags.js.map +1 -0
  552. package/package.json +110 -0
@@ -0,0 +1,235 @@
1
+ import { uiViewSlug } from './slug.js';
2
+ import { DomainError } from './tags.js';
3
+ const VALID_LOCATIONS = ['path', 'query', 'hash'];
4
+ export class UiViewService {
5
+ db;
6
+ tags;
7
+ versions;
8
+ constructor(db, tags, versions) {
9
+ this.db = db;
10
+ this.tags = tags;
11
+ this.versions = versions;
12
+ }
13
+ create(input, actor) {
14
+ if (!input.name)
15
+ throw new DomainError('VALIDATION', 'name is required');
16
+ const slug = input.slug?.trim() || uiViewSlug(input.name);
17
+ if (!slug)
18
+ throw new DomainError('VALIDATION', 'slug resolves to empty');
19
+ const params = input.params ?? [];
20
+ const url = normaliseUrl(input.url);
21
+ const tx = this.db.transaction(() => {
22
+ const conflict = this.db.prepare(`SELECT 1 FROM ui_view WHERE slug = ?`).get(slug);
23
+ if (conflict)
24
+ throw new DomainError('SLUG_CONFLICT', `ui view slug '${slug}' already exists`);
25
+ const info = this.db
26
+ .prepare(`INSERT INTO ui_view (slug, name, url, description, params)
27
+ VALUES (?, ?, ?, ?, ?)`)
28
+ .run(slug, input.name, url, input.description ?? null, JSON.stringify(params));
29
+ const id = Number(info.lastInsertRowid);
30
+ if (input.tags?.length)
31
+ this.tags.assignTags('ui-view', id, input.tags);
32
+ const created = this.getByIdInternal(id);
33
+ this.versions.createVersion('ui-view', id, created, actor, 'Created');
34
+ const warnings = computeWarnings(url, params);
35
+ return { uiView: created, warnings };
36
+ });
37
+ return tx();
38
+ }
39
+ list(query = {}) {
40
+ const where = [];
41
+ const params = [];
42
+ if (query.search) {
43
+ where.push(`(name LIKE ? OR description LIKE ? OR slug LIKE ? OR url LIKE ?)`);
44
+ const like = `%${query.search}%`;
45
+ params.push(like, like, like, like);
46
+ }
47
+ const tagSlugs = query.tags?.filter(Boolean) ?? [];
48
+ if (tagSlugs.length) {
49
+ const placeholders = tagSlugs.map(() => '?').join(',');
50
+ if (query.tagFilter === 'or') {
51
+ where.push(`
52
+ id IN (
53
+ SELECT et.entity_id FROM entity_tag et
54
+ JOIN tag t ON t.id = et.tag_id
55
+ WHERE et.entity_type = 'ui-view' AND t.slug IN (${placeholders})
56
+ )
57
+ `);
58
+ params.push(...tagSlugs);
59
+ }
60
+ else {
61
+ where.push(`
62
+ id IN (
63
+ SELECT et.entity_id
64
+ FROM entity_tag et
65
+ JOIN tag t ON t.id = et.tag_id
66
+ WHERE et.entity_type = 'ui-view' AND t.slug IN (${placeholders})
67
+ GROUP BY et.entity_id
68
+ HAVING COUNT(DISTINCT t.slug) = ?
69
+ )
70
+ `);
71
+ params.push(...tagSlugs, tagSlugs.length);
72
+ }
73
+ }
74
+ const whereSql = where.length ? `WHERE ${where.join(' AND ')}` : '';
75
+ const limit = Math.min(Math.max(query.limit ?? 200, 1), 500);
76
+ const offset = Math.max(query.offset ?? 0, 0);
77
+ const rows = this.db
78
+ .prepare(`SELECT * FROM ui_view ${whereSql}
79
+ ORDER BY name
80
+ LIMIT ? OFFSET ?`)
81
+ .all(...params, limit, offset);
82
+ return rows.map((r) => this.hydrate(r));
83
+ }
84
+ getBySlug(slug) {
85
+ const row = this.db.prepare(`SELECT * FROM ui_view WHERE slug = ?`).get(slug);
86
+ return row ? this.hydrate(row) : null;
87
+ }
88
+ getIdBySlug(slug) {
89
+ const row = this.db.prepare(`SELECT id FROM ui_view WHERE slug = ?`).get(slug);
90
+ return row?.id ?? null;
91
+ }
92
+ update(slug, input, actor) {
93
+ const tx = this.db.transaction(() => {
94
+ const current = this.db.prepare(`SELECT * FROM ui_view WHERE slug = ?`).get(slug);
95
+ if (!current)
96
+ throw new DomainError('NOT_FOUND', `ui view '${slug}' not found`);
97
+ const nextName = input.name ?? current.name;
98
+ const autoSlug = uiViewSlug(nextName);
99
+ const nextSlug = input.newSlug?.trim() || autoSlug;
100
+ if (nextSlug !== slug) {
101
+ const conflict = this.db.prepare(`SELECT 1 FROM ui_view WHERE slug = ?`).get(nextSlug);
102
+ if (conflict)
103
+ throw new DomainError('SLUG_CONFLICT', `ui view slug '${nextSlug}' already exists`);
104
+ }
105
+ const nextParams = input.params !== undefined ? JSON.stringify(input.params) : current.params;
106
+ const nextUrl = input.url !== undefined ? normaliseUrl(input.url) : current.url;
107
+ this.db
108
+ .prepare(`UPDATE ui_view
109
+ SET slug = ?, name = ?, url = ?, description = ?, params = ?,
110
+ updated_at = datetime('now')
111
+ WHERE id = ?`)
112
+ .run(nextSlug, nextName, nextUrl, input.description !== undefined ? input.description : current.description, nextParams, current.id);
113
+ if (input.tags)
114
+ this.tags.assignTags('ui-view', current.id, input.tags);
115
+ const updated = this.getByIdInternal(current.id);
116
+ const summary = nextSlug !== slug ? `Renamed from '${slug}' to '${nextSlug}'` : 'Updated';
117
+ this.versions.createVersion('ui-view', current.id, updated, actor, summary);
118
+ const warnings = computeWarnings(updated.url, updated.params);
119
+ return { uiView: updated, previousSlug: slug, warnings };
120
+ });
121
+ return tx();
122
+ }
123
+ remove(slug, actor, brokenReferences = []) {
124
+ const tx = this.db.transaction(() => {
125
+ const row = this.db.prepare(`SELECT * FROM ui_view WHERE slug = ?`).get(slug);
126
+ if (!row)
127
+ throw new DomainError('NOT_FOUND', `ui view '${slug}' not found`);
128
+ this.versions.createVersion('ui-view', row.id, null, actor, 'Deleted');
129
+ this.db
130
+ .prepare(`DELETE FROM entity_tag WHERE entity_type = 'ui-view' AND entity_id = ?`)
131
+ .run(row.id);
132
+ this.db.prepare(`DELETE FROM ui_view WHERE id = ?`).run(row.id);
133
+ return { deleted: true, brokenReferences };
134
+ });
135
+ return tx();
136
+ }
137
+ getByIdInternal(id) {
138
+ const row = this.db.prepare(`SELECT * FROM ui_view WHERE id = ?`).get(id);
139
+ if (!row)
140
+ throw new Error(`ui_view id ${id} disappeared mid-tx`);
141
+ return this.hydrate(row);
142
+ }
143
+ hydrate(row) {
144
+ return {
145
+ slug: row.slug,
146
+ name: row.name,
147
+ url: row.url,
148
+ description: row.description,
149
+ params: parseParams(row.params),
150
+ tags: this.tags.getEntityTagSlugs('ui-view', row.id),
151
+ createdAt: row.created_at,
152
+ updatedAt: row.updated_at,
153
+ };
154
+ }
155
+ }
156
+ function normaliseUrl(value) {
157
+ if (value === undefined || value === null)
158
+ return null;
159
+ const trimmed = value.trim();
160
+ return trimmed === '' ? null : trimmed;
161
+ }
162
+ function parseParams(raw) {
163
+ try {
164
+ const parsed = JSON.parse(raw);
165
+ if (!Array.isArray(parsed))
166
+ return [];
167
+ return parsed
168
+ .filter((p) => p && typeof p === 'object' && typeof p.name === 'string')
169
+ .map((p) => {
170
+ const inValue = String(p.in ?? '');
171
+ const location = VALID_LOCATIONS.includes(inValue)
172
+ ? inValue
173
+ : 'query';
174
+ const out = {
175
+ name: String(p.name),
176
+ in: location,
177
+ };
178
+ if (typeof p.type === 'string')
179
+ out.type = p.type;
180
+ if (typeof p.required === 'boolean')
181
+ out.required = p.required;
182
+ if (typeof p.default === 'string')
183
+ out.default = p.default;
184
+ if (typeof p.description === 'string')
185
+ out.description = p.description;
186
+ return out;
187
+ });
188
+ }
189
+ catch {
190
+ return [];
191
+ }
192
+ }
193
+ const PATH_PARAM_RE = /:([a-zA-Z_][a-zA-Z0-9_]*)/g;
194
+ export function computeWarnings(url, params) {
195
+ const warnings = [];
196
+ for (let i = 0; i < params.length; i++) {
197
+ const p = params[i];
198
+ if (!p.name) {
199
+ warnings.push(`params[${i}]: missing 'name'`);
200
+ }
201
+ if (!VALID_LOCATIONS.includes(p.in)) {
202
+ warnings.push(`params[${i}] '${p.name ?? '?'}': invalid 'in' value '${p.in}' (expected path|query|hash)`);
203
+ }
204
+ }
205
+ const seen = new Set();
206
+ for (const p of params) {
207
+ const key = `${p.in}::${p.name}`;
208
+ if (seen.has(key)) {
209
+ warnings.push(`Duplicate param (name='${p.name}', in='${p.in}')`);
210
+ }
211
+ seen.add(key);
212
+ }
213
+ const urlPathParams = new Set();
214
+ if (url) {
215
+ const matches = url.matchAll(PATH_PARAM_RE);
216
+ for (const m of matches)
217
+ urlPathParams.add(m[1]);
218
+ }
219
+ const declaredPathParams = new Set(params.filter((p) => p.in === 'path' && p.name).map((p) => p.name));
220
+ for (const name of urlPathParams) {
221
+ if (!declaredPathParams.has(name)) {
222
+ warnings.push(`path param ":${name}" in URL not declared in params[]`);
223
+ }
224
+ }
225
+ for (const name of declaredPathParams) {
226
+ if (url && !urlPathParams.has(name)) {
227
+ warnings.push(`path param '${name}' declared but not present in URL`);
228
+ }
229
+ }
230
+ if (url === null && declaredPathParams.size > 0) {
231
+ warnings.push(`path params declared but URL is null (modal/drawer should not have path params)`);
232
+ }
233
+ return warnings;
234
+ }
235
+ //# sourceMappingURL=ui-view.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ui-view.js","sourceRoot":"","sources":["../../../src/server/services/ui-view.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type Database from 'better-sqlite3';
2
+ import type { ChangedBy, EntityType, VersionDetail, VersionListItem } from '../../shared/entities.js';
3
+ import type { PluginHost } from '../core/plugin-host/types.js';
4
+ import type { RawEntityReader, RawEntityType } from '../domain/raw-entity-reader.js';
5
+ export type VersionOp = 'create' | 'update' | 'delete';
6
+ export interface CreateVersionInput {
7
+ entityType: EntityType;
8
+ entityId: number;
9
+ data: unknown;
10
+ changedBy: ChangedBy;
11
+ changeSummary?: string | null;
12
+ /** M17: which kind of mutation. Required for new code; legacy callers omit. */
13
+ op?: VersionOp;
14
+ /** M17: serializer.version at time of capture. Null for legacy rows. */
15
+ serializerVersion?: string | null;
16
+ }
17
+ export declare class VersionService {
18
+ private db;
19
+ private snapshotDeps;
20
+ constructor(db: Database.Database);
21
+ /** M17: wire snapshot dependencies. Called once during server bootstrap. */
22
+ configureSnapshot(reader: RawEntityReader, host: PluginHost): void;
23
+ /**
24
+ * M17: capture a deterministic snapshot of an entity into entity_version.
25
+ * Falls back to `createVersion(..., entity, ...)` if snapshot deps not wired
26
+ * yet (very early in bootstrap or for tests). For `op = 'delete'`, calls
27
+ * host.snapshot BEFORE the caller deletes the row — pass `previousSnapshot`
28
+ * explicitly to capture a tombstone with last-known data.
29
+ */
30
+ captureEntitySnapshot(type: RawEntityType, entityId: number, op: VersionOp, actor: ChangedBy, summary: string | null, serializerVersion: string): VersionListItem;
31
+ /**
32
+ * Capture a new version. M17 augments the row with `op` and
33
+ * `serializer_version`; `release_id` always starts NULL and is assigned by
34
+ * `releaseService.createRelease()`.
35
+ */
36
+ createVersion(entityType: EntityType, entityId: number, data: unknown, changedBy: ChangedBy, changeSummary?: string | null, op?: VersionOp, serializerVersion?: string | null): VersionListItem;
37
+ listVersions(entityType: EntityType, entityId: number): VersionListItem[];
38
+ getVersion(entityType: EntityType, entityId: number, version: number): VersionDetail | null;
39
+ /**
40
+ * M17: latest captured version of an entity at-or-before a given release.
41
+ * `releaseId === null` returns the latest unreleased capture (release_id IS NULL).
42
+ * `releaseId === undefined` returns the latest overall (no release filter).
43
+ */
44
+ getLatestVersionForEntity(entityType: EntityType, entityId: number, releaseId?: number | null): VersionDetail | null;
45
+ diff(entityType: EntityType, entityId: number, fromVersion: number, toVersion: number): {
46
+ from: VersionDetail;
47
+ to: VersionDetail;
48
+ changes: DiffEntry[];
49
+ };
50
+ private nextVersionNumber;
51
+ private toListItem;
52
+ private toDetail;
53
+ }
54
+ export interface DiffEntry {
55
+ path: string;
56
+ from: unknown;
57
+ to: unknown;
58
+ }
59
+ export declare function computeDiff(from: unknown, to: unknown, prefix?: string): DiffEntry[];
@@ -0,0 +1,181 @@
1
+ import { DomainError } from './tags.js';
2
+ export class VersionService {
3
+ db;
4
+ // M17: lazily wired by index.ts after pluginHost.consolidate. When present,
5
+ // entity services prefer captureSnapshot(...) over createVersion(...) so
6
+ // entity_version.data carries the full snapshot (decyzja 4 — portable identity).
7
+ snapshotDeps = null;
8
+ constructor(db) {
9
+ this.db = db;
10
+ }
11
+ /** M17: wire snapshot dependencies. Called once during server bootstrap. */
12
+ configureSnapshot(reader, host) {
13
+ this.snapshotDeps = { reader, host };
14
+ }
15
+ /**
16
+ * M17: capture a deterministic snapshot of an entity into entity_version.
17
+ * Falls back to `createVersion(..., entity, ...)` if snapshot deps not wired
18
+ * yet (very early in bootstrap or for tests). For `op = 'delete'`, calls
19
+ * host.snapshot BEFORE the caller deletes the row — pass `previousSnapshot`
20
+ * explicitly to capture a tombstone with last-known data.
21
+ */
22
+ captureEntitySnapshot(type, entityId, op, actor, summary, serializerVersion) {
23
+ if (!this.snapshotDeps) {
24
+ // Fallback: deps not yet wired. Store legacy domain object via createVersion.
25
+ return this.createVersion(type, entityId, null, actor, summary, op, serializerVersion);
26
+ }
27
+ // For all ops (including delete), snapshot the entity *as it currently is*
28
+ // (callers must call this BEFORE the row is deleted from its table).
29
+ const rawEntity = this.snapshotDeps.reader.getEntityById(type, entityId);
30
+ if (!rawEntity) {
31
+ // Entity not found — fall back to last-known snapshot so tombstone has
32
+ // restorable data. This path is only hit if a caller calls capture
33
+ // post-delete (anti-pattern but defensive).
34
+ const last = this.getLatestVersionForEntity(type, entityId);
35
+ return this.createVersion(type, entityId, last?.data ?? null, actor, summary, op, serializerVersion);
36
+ }
37
+ const ctx = { reader: this.snapshotDeps.reader, depth: 0, maxDepth: 1 };
38
+ const snapshot = this.snapshotDeps.host.snapshot(type, rawEntity, ctx);
39
+ return this.createVersion(type, entityId, snapshot, actor, summary, op, serializerVersion);
40
+ }
41
+ /**
42
+ * Capture a new version. M17 augments the row with `op` and
43
+ * `serializer_version`; `release_id` always starts NULL and is assigned by
44
+ * `releaseService.createRelease()`.
45
+ */
46
+ createVersion(entityType, entityId, data, changedBy, changeSummary, op, serializerVersion) {
47
+ const next = this.nextVersionNumber(entityType, entityId);
48
+ const inferredOp = op ?? (data === null ? 'delete' : (next === 1 ? 'create' : 'update'));
49
+ const info = this.db
50
+ .prepare(`INSERT INTO entity_version
51
+ (entity_type, entity_id, version, data, changed_by, change_summary, op, serializer_version)
52
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)`)
53
+ .run(entityType, entityId, next, JSON.stringify(data), changedBy, changeSummary ?? null, inferredOp, serializerVersion ?? null);
54
+ const row = this.db
55
+ .prepare(`SELECT * FROM entity_version WHERE id = ?`)
56
+ .get(info.lastInsertRowid);
57
+ return this.toListItem(row);
58
+ }
59
+ listVersions(entityType, entityId) {
60
+ const rows = this.db
61
+ .prepare(`SELECT id, version, changed_by, change_summary, created_at, release_id, op
62
+ FROM entity_version
63
+ WHERE entity_type = ? AND entity_id = ?
64
+ ORDER BY version DESC`)
65
+ .all(entityType, entityId);
66
+ return rows.map((r) => ({
67
+ id: r.id,
68
+ version: r.version,
69
+ changedBy: r.changed_by,
70
+ changeSummary: r.change_summary,
71
+ createdAt: r.created_at,
72
+ ...(r.release_id !== null ? { releaseId: r.release_id } : {}),
73
+ ...(r.op ? { op: r.op } : {}),
74
+ }));
75
+ }
76
+ getVersion(entityType, entityId, version) {
77
+ const row = this.db
78
+ .prepare(`SELECT * FROM entity_version
79
+ WHERE entity_type = ? AND entity_id = ? AND version = ?`)
80
+ .get(entityType, entityId, version);
81
+ if (!row)
82
+ return null;
83
+ return this.toDetail(row);
84
+ }
85
+ /**
86
+ * M17: latest captured version of an entity at-or-before a given release.
87
+ * `releaseId === null` returns the latest unreleased capture (release_id IS NULL).
88
+ * `releaseId === undefined` returns the latest overall (no release filter).
89
+ */
90
+ getLatestVersionForEntity(entityType, entityId, releaseId) {
91
+ let row;
92
+ if (releaseId === undefined) {
93
+ row = this.db
94
+ .prepare(`SELECT * FROM entity_version
95
+ WHERE entity_type = ? AND entity_id = ?
96
+ ORDER BY version DESC LIMIT 1`)
97
+ .get(entityType, entityId);
98
+ }
99
+ else if (releaseId === null) {
100
+ row = this.db
101
+ .prepare(`SELECT * FROM entity_version
102
+ WHERE entity_type = ? AND entity_id = ? AND release_id IS NULL
103
+ ORDER BY version DESC LIMIT 1`)
104
+ .get(entityType, entityId);
105
+ }
106
+ else {
107
+ row = this.db
108
+ .prepare(`SELECT * FROM entity_version
109
+ WHERE entity_type = ? AND entity_id = ? AND release_id IS NOT NULL AND release_id <= ?
110
+ ORDER BY version DESC LIMIT 1`)
111
+ .get(entityType, entityId, releaseId);
112
+ }
113
+ return row ? this.toDetail(row) : null;
114
+ }
115
+ diff(entityType, entityId, fromVersion, toVersion) {
116
+ const from = this.getVersion(entityType, entityId, fromVersion);
117
+ const to = this.getVersion(entityType, entityId, toVersion);
118
+ if (!from || !to)
119
+ throw new DomainError('NOT_FOUND', 'version not found');
120
+ return { from, to, changes: computeDiff(from.data, to.data) };
121
+ }
122
+ nextVersionNumber(entityType, entityId) {
123
+ const row = this.db
124
+ .prepare(`SELECT MAX(version) AS v FROM entity_version WHERE entity_type = ? AND entity_id = ?`)
125
+ .get(entityType, entityId);
126
+ return (row.v ?? 0) + 1;
127
+ }
128
+ toListItem(row) {
129
+ return {
130
+ id: row.id,
131
+ version: row.version,
132
+ changedBy: row.changed_by,
133
+ changeSummary: row.change_summary,
134
+ createdAt: row.created_at,
135
+ ...(row.release_id !== null ? { releaseId: row.release_id } : {}),
136
+ ...(row.op ? { op: row.op } : {}),
137
+ };
138
+ }
139
+ toDetail(row) {
140
+ return {
141
+ id: row.id,
142
+ entityType: row.entity_type,
143
+ entityId: row.entity_id,
144
+ version: row.version,
145
+ data: safeParse(row.data),
146
+ changedBy: row.changed_by,
147
+ changeSummary: row.change_summary,
148
+ createdAt: row.created_at,
149
+ ...(row.release_id !== null ? { releaseId: row.release_id } : {}),
150
+ ...(row.op ? { op: row.op } : {}),
151
+ };
152
+ }
153
+ }
154
+ function safeParse(raw) {
155
+ try {
156
+ return JSON.parse(raw);
157
+ }
158
+ catch {
159
+ return raw;
160
+ }
161
+ }
162
+ export function computeDiff(from, to, prefix = '') {
163
+ if (deepEqual(from, to))
164
+ return [];
165
+ if (!isObj(from) || !isObj(to))
166
+ return [{ path: prefix || '/', from, to }];
167
+ const keys = new Set([...Object.keys(from), ...Object.keys(to)]);
168
+ const changes = [];
169
+ for (const key of keys) {
170
+ const sub = prefix ? `${prefix}.${key}` : key;
171
+ changes.push(...computeDiff(from[key], to[key], sub));
172
+ }
173
+ return changes;
174
+ }
175
+ function isObj(v) {
176
+ return v !== null && typeof v === 'object' && !Array.isArray(v);
177
+ }
178
+ function deepEqual(a, b) {
179
+ return JSON.stringify(a) === JSON.stringify(b);
180
+ }
181
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../../../src/server/services/versions.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,117 @@
1
+ ---
2
+ title: Brief Author
3
+ description: "Generates and edits release briefs — self-contained narrative artifacts that summarise what changed between two releases (M17). TRIGGER automatically loaded for chat threads with context_type='brief'. The agent has access to ONLY brief-tools (4) and release-tools (read-only) — no filesystem access. Defines the brief genre (audience, format, tooling, branches, error handling); the active writing-style skill supplies methodology-specific guidance via its `workflows/brief.md`."
4
+ version: 2
5
+ language: en
6
+ scope: contextual
7
+ ---
8
+
9
+ # Brief Author
10
+
11
+ You are the **Brief Author**, a specialised editorial agent collaborating with a human user on a single brief artifact. A brief is a **self-contained markdown narrative** that summarises what changed between two releases of a specification.
12
+
13
+ The system prompt already binds you to the **self-contained invariant**: the brief is consumed both inside claude4spec (rendered Tiptap, clickable references) AND in some other terminal where the reader has only the raw file bytes — no database, no MCP, no claude4spec UI, no CLI. The second audience is load-bearing — it is what justifies storing the brief on disk instead of in a DB. Everything below is the brief *genre*: rules that hold regardless of which writing style the underlying spec uses.
14
+
15
+ > **Methodology-specific guidance — read second.** This skill defines the genre. **How to interpret an `MCPReleaseDiff` for the active writing style** — what counts as feature substance vs. spec-format convention, how to inline its entity types, what to put in "For implementers" — lives in the active writing-style skill at `workflows/brief.md`. The system prompt names which writing style is active. After loading this skill, load that one and read its `workflows/brief.md` before composing the brief.
16
+
17
+ ---
18
+
19
+ ## What you can and cannot do
20
+
21
+ **Available tools:**
22
+ - `get_brief` — read the current brief state. Returns `{ frontmatter, body, content, hash }`. Use `hash` as `expectedHash` for the next `update_brief` to detect concurrent edits.
23
+ - `update_brief` — edit the body via `replace`, `append`, or `insert_after_section`. You CANNOT modify frontmatter (immutable: `type`, `from_release`, `to_release`, `generated_at`, `generator_version`).
24
+ - `list_brief_versions` / `get_brief_version` — inspect history, diff against earlier versions.
25
+ - `release-tools` (read-only) — `release_list`, `release_show`, and `release_diff(fromIdOrName, toIdOrName, include?, entityTypes?)` returning a self-contained `MCPReleaseDiff`. Use `release_diff(brief.frontmatter.from_release, brief.frontmatter.to_release)` to obtain the `MCPReleaseDiff` that grounds your narrative — one round-trip is all you need.
26
+
27
+ **`release-tools` is the ONLY plugin MCP available in this thread.** There is no `get_endpoint` / `get_dto` / `get_database-table` / `get_ui-view` / `get_ac`, no `Read pages/...`, no `Grep`, no filesystem. The `MCPReleaseDiff` payload is your entire ground truth — every snapshot you need is carried inside it.
28
+
29
+ **You cannot:**
30
+ - Read or write any file on disk (no `Read`, `Write`, `Edit`, `Glob`, `Grep`, `Bash`).
31
+ - Mutate any entity, page, plan, or release. Briefs are write-side only.
32
+ - Modify brief frontmatter (immutable to agents — only the user can toggle `archived` via the UI Settings popover).
33
+ - Drill down into entities or pages on demand. The diff is self-contained by design (see "Self-containment" below).
34
+
35
+ ---
36
+
37
+ ## Two operating branches
38
+
39
+ ### Branch A — Initial generation (body is empty)
40
+
41
+ Triggered when `get_brief` returns a brief whose body contains only the H1 heading (or is otherwise empty).
42
+
43
+ **Initial brief detection:** if `frontmatter.from_release === null`, this is an *initial brief* — there is no previous release. Skip the two-release diff; instead call `release-tools.release_diff({ fromIdOrName: null, toIdOrName: <to_release> })` to obtain an `MCPReleaseDiff` where every entry is `op: 'create'` with `before` omitted (synthetic empty `from` snapshot). Frame the narrative as *"the project starts here — this is the initial state of `<to_release>`"*, not as a delta. The H1 should be `# Initial brief: <to_release>` (already pre-filled by the system).
44
+
45
+ 1. Call `get_brief` to confirm `frontmatter.from_release` and `frontmatter.to_release` and capture `hash`.
46
+ 2. Call `release-tools.release_diff({ fromIdOrName, toIdOrName })` to obtain the `MCPReleaseDiff`. This is your single source of truth — full `before`/`after` snapshots per entity and full `before`/`after` raw markdown per modified section travel in the payload. Default filters (`include: ['pages','entities']`, all entity types) cover everything; pass narrower filters only if you have a clear context-budget reason.
47
+ 3. **Filter the diff using the active writing style's `workflows/brief.md`.** It defines what counts as feature substance (keep, translate, inline) vs. spec-format convention (drop) vs. editorial noise (drop) for this methodology.
48
+ 4. **Mine the kept entries** for inlinable content — entity shapes, code/SQL fragments, file paths — per the writing style's inlining patterns.
49
+ 5. **For each entity with `op: 'update'`**: compare `MCPEntityDelta.before` vs `MCPEntityDelta.after` directly — both are full snapshots produced by the plugin's serializer. Describe the diff in prose. **Do NOT call any drill-down tool — there is none available in this thread.** Slugs, field shapes, every value you need is in the snapshot.
50
+ 6. **For each entity with `op: 'create'`**: read `MCPEntityDelta.after` for any inline content needed in prose. You MAY insert `<inline_mention type="<type>" slug="<slug>"/>` in the narrative for the claude4spec UI audience — it renders as a live entity view. The second-audience terminal sees the literal tag; treat such mentions as supplements, never as substitutes for inlined content.
51
+ 7. **For each entity with `op: 'delete'`**: only `before` is present. Frame the deletion in prose; the second-audience reader needs to know what disappeared, not what replaced it (often nothing).
52
+ 8. **For each `MCPPageDelta.sections[i]`**: use `before` / `after` raw markdown directly. NEVER consume `line_diff` — there is none in this payload. For `op: 'move'`, both fields are absent (content unchanged, only position shifted) — usually drop from the brief unless ordering itself is the user-visible change.
53
+ 9. **`MCPPageDelta.frontmatter` / `MCPPageDelta.xmlRefs`**: present iff changed. Read `before`/`after` only when relevant to narrative (e.g. `pageType: module → layer`). Default: ignore — metadata, not content.
54
+ 10. Compose a narrative that:
55
+ - Opens with a short summary (2–4 sentences) describing the *intent* of the release. The reader should learn *why* in the first paragraph.
56
+ - Groups changes by user-visible theme (new capabilities, breaking changes, internal refactors), not by entity type or by spec page.
57
+ - For each theme: state what the system now does in plain prose and **inline the change content** per the writing style's patterns.
58
+ - Closes with a **For implementers** section — concrete edit targets per the writing style's structure.
59
+ 11. **Język/styl/audytorium** wynika z pierwszej user-message w threadzie — klient dokleja `additionalPrompt` z modala „Generate brief from this release" (np. *„po polsku, dla juniora, ton formalny"*). Jeśli pierwsza wiadomość zawiera takie wytyczne, uszanuj je. Domyślnie pisz w angielskim, krótkimi deklaratywnymi zdaniami.
60
+ 12. Submit via `update_brief({ action: 'replace', content: <full markdown body>, expectedHash: <hash from step 1>, changeSummary: 'initial generation' })`.
61
+
62
+ ### Branch B — Editorial (body already exists)
63
+
64
+ Triggered when `get_brief` returns a brief with non-trivial body content.
65
+
66
+ 1. Always start with `get_brief` to refresh `expectedHash` (another thread or the user may have edited since).
67
+ 2. Read the user's request carefully. Common patterns:
68
+ - **"Make it shorter"** → favour `replace` with a tightened version, but **never** drop inlined diff fragments / file paths / signatures (those are what makes the brief usable to the second audience). Tighten prose, not facts.
69
+ - **"Add a section about X"** → use `insert_after_section({ anchor: '<8char>', content })` — extract the anchor from the body (the `<!-- anchor: ... -->` comment immediately preceding the target heading). Prefer `anchor` over `heading` (anchors are stable across renames).
70
+ - **"Append an FAQ"** → `update_brief({ action: 'append', content })`.
71
+ 3. Never wholesale-replace if a smaller surgical edit would do. `replace` discards section anchors; `insert_after_section` preserves them.
72
+ 4. If you receive `BRIEF_CONFLICT`, the brief was edited by another writer. Call `get_brief` again, reconcile your intended change against the new content, then retry.
73
+ 5. If a target anchor is missing, the tool falls back to append-at-end with a warning — re-evaluate whether that is what the user wanted before continuing.
74
+
75
+ ---
76
+
77
+ ## Self-containment — the genre invariant
78
+
79
+ Two rules sit above any methodology-specific guidance:
80
+
81
+ 1. **The `MCPReleaseDiff` payload is your only source.** There is no fetch-on-demand path in this thread — no `get_<type>`, no `Read pages/...`. Every snapshot you need is already in the payload (`MCPEntityDelta.before/after`, `MCPSectionDelta.before/after`). Whenever a change involves a concrete artefact — DTO field, endpoint signature, SQL, view URL, code snippet — paste it into the brief. The reader cannot fetch it on demand. Phrases like *"see the release diff"*, *"per the spec page"*, or *"as defined elsewhere"* are failures.
82
+ 2. **Describe the SYSTEM, not the spec edits.** The brief is about how the specified system behaves now vs. before — not about which markdown files gained/lost sections. Editorial mechanics (anchor injection, section reorder without content change, typo, prose smoothing, comment edit, heading rename without semantic shift) belong in version history, not in the brief. *Drop them.*
83
+
84
+ - GOOD: *"Brief threads whitelist their toolset — only `brief-tools` and `release-tools` are mounted; plan/entity MCPs are silently omitted to keep the editorial agent on its lane."*
85
+ - BAD: *"Section 'Tool whitelist' was added to `m05-chat-agent.md` between 'Context registry' and 'System prompt builder'."*
86
+
87
+ When this invariant conflicts with brevity, choose self-containment. A longer brief that stands alone beats a terse brief that requires claude4spec to interpret. The writing-style workflow refines *which* parts of an `MCPReleaseDiff` count as substance vs. format vs. editorial — but the invariant above governs all of them.
88
+
89
+ If after filtering nothing substantive remains in a release, say so explicitly: *"This release contains only editorial cleanup of the specification — no system behaviour changes."* Do not pad.
90
+
91
+ ---
92
+
93
+ ## Style & quality bar
94
+
95
+ - **Concrete over abstract.** Write *"the `endpoint.dto` link became polymorphic (`{ kind: 'request' | 'response' | 'error' }`)"* rather than *"we improved entity flexibility."*
96
+ - **One concept per paragraph.** Both audiences benefit from short paragraphs (skimming humans, pattern-matching agents).
97
+ - **No marketing tone.** Engineering documentation, not a release announcement.
98
+ - **Inline the diff, don't paraphrase it.** When a section change matters, paste the relevant fragment with a short framing sentence.
99
+ - **Two delimited sections** at minimum: `## What changed` (human-context narrative) and `## For implementers` (second-audience payload). The brief may have other sections in between — these two are the floor.
100
+
101
+ ---
102
+
103
+ ## Tool error handling
104
+
105
+ | Error code | Action |
106
+ |------------|--------|
107
+ | `BRIEF_CONFLICT` | Re-`get_brief`, reconcile, retry once. If conflict persists, ask the user to reconcile manually. |
108
+ | `BRIEF_FRONTMATTER_IMMUTABLE` | Your `content` accidentally altered frontmatter. Strip the YAML header — `update_brief` always preserves the existing frontmatter. |
109
+ | `BRIEF_ARCHIVED` | The user archived this brief. Inform the user and stop editing until they unarchive. |
110
+ | `MISSING_TARGET` | `insert_after_section` requires `anchor` or `heading`. Re-issue with one of them. |
111
+ | `AMBIGUOUS_HEADING` | Two sections share the same heading text — switch to `anchor`. |
112
+ | `VERSION_NOT_FOUND` | The version number you passed does not exist. List versions first. |
113
+ | `INVALID_INCLUDE_FILTER` | `release_diff` / `release_show` rejected an empty `include` array. Drop the arg to fall back to defaults (`['pages','entities']`). |
114
+ | `INVALID_ENTITY_TYPES_FILTER` | Empty `entityTypes` array. Drop the arg to fall back to defaults (all 5 types). |
115
+ | `CONFLICTING_FILTERS` | You passed `entityTypes` without `'entities'` in `include`. Either add `'entities'` to `include` or drop `entityTypes`. |
116
+
117
+ If `release-tools.release_diff` returns an empty diff (both `entities` and `pages` empty — e.g. `from === to`), report that to the user — do not fabricate changes.