@inharness-ai/claude4spec 1.0.14 → 1.0.16

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 (353) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/bin/c4s/args.d.ts +2 -0
  3. package/dist/bin/c4s/args.js +3 -0
  4. package/dist/bin/c4s/args.js.map +1 -1
  5. package/dist/bin/c4s/commands/ask.js +2 -0
  6. package/dist/bin/c4s/commands/ask.js.map +1 -1
  7. package/dist/bin/c4s/commands/catalog.js +1 -1
  8. package/dist/bin/c4s/commands/catalog.js.map +1 -1
  9. package/dist/bin/c4s/commands/describe.d.ts +2 -0
  10. package/dist/bin/c4s/commands/describe.js +22 -0
  11. package/dist/bin/c4s/commands/describe.js.map +1 -0
  12. package/dist/bin/c4s/commands/find-references.d.ts +13 -0
  13. package/dist/bin/c4s/commands/find-references.js +81 -0
  14. package/dist/bin/c4s/commands/find-references.js.map +1 -0
  15. package/dist/bin/c4s/context.d.ts +4 -3
  16. package/dist/bin/c4s/context.js +17 -6
  17. package/dist/bin/c4s/context.js.map +1 -1
  18. package/dist/bin/c4s/errors.d.ts +1 -1
  19. package/dist/bin/c4s/errors.js.map +1 -1
  20. package/dist/bin/c4s/type-validation.d.ts +3 -0
  21. package/dist/bin/c4s/type-validation.js +14 -0
  22. package/dist/bin/c4s/type-validation.js.map +1 -1
  23. package/dist/bin/c4s-mcp.d.ts +1 -1
  24. package/dist/bin/c4s-mcp.js +23 -12
  25. package/dist/bin/c4s-mcp.js.map +1 -1
  26. package/dist/bin/c4s.js +20 -3
  27. package/dist/bin/c4s.js.map +1 -1
  28. package/dist/bin/claude4spec.js +122 -74
  29. package/dist/bin/claude4spec.js.map +1 -1
  30. package/dist/client/assets/{arc-E0e7X_zn.js → arc-DrA6qHTw.js} +1 -1
  31. package/dist/client/assets/{architectureDiagram-3BPJPVTR-BzlqOVZv.js → architectureDiagram-3BPJPVTR-TEnwTtVX.js} +1 -1
  32. package/dist/client/assets/{blockDiagram-GPEHLZMM-BIQcApN7.js → blockDiagram-GPEHLZMM-txRnQm5w.js} +1 -1
  33. package/dist/client/assets/{c4Diagram-AAUBKEIU-CDU0V1yk.js → c4Diagram-AAUBKEIU-ad8X3Q8n.js} +1 -1
  34. package/dist/client/assets/channel-zmRfuI3H.js +1 -0
  35. package/dist/client/assets/{chunk-2J33WTMH-PtDSwC5f.js → chunk-2J33WTMH-Cp08Xa7f.js} +1 -1
  36. package/dist/client/assets/{chunk-4BX2VUAB-DTUPWrSO.js → chunk-4BX2VUAB-Dc_0On6j.js} +1 -1
  37. package/dist/client/assets/{chunk-55IACEB6-Cpd59xZT.js → chunk-55IACEB6-8d1qQ5z6.js} +1 -1
  38. package/dist/client/assets/{chunk-727SXJPM-C4DOvpJT.js → chunk-727SXJPM-TZenviWx.js} +1 -1
  39. package/dist/client/assets/{chunk-AQP2D5EJ-CtjeHPBB.js → chunk-AQP2D5EJ-DKRRWy-J.js} +1 -1
  40. package/dist/client/assets/{chunk-FMBD7UC4-CZA3OvVr.js → chunk-FMBD7UC4-DLEErJWK.js} +1 -1
  41. package/dist/client/assets/{chunk-ND2GUHAM-Cbx6nQHm.js → chunk-ND2GUHAM-pKGgwz_0.js} +1 -1
  42. package/dist/client/assets/{chunk-QZHKN3VN-3DunELI_.js → chunk-QZHKN3VN-DVcNz8ng.js} +1 -1
  43. package/dist/client/assets/classDiagram-4FO5ZUOK-B9RFgPu-.js +1 -0
  44. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B9RFgPu-.js +1 -0
  45. package/dist/client/assets/{cose-bilkent-S5V4N54A-CKYJnuL7.js → cose-bilkent-S5V4N54A-DZejbxEG.js} +1 -1
  46. package/dist/client/assets/{dagre-BM42HDAG-BrvRwrr_.js → dagre-BM42HDAG-DrPrkFcW.js} +1 -1
  47. package/dist/client/assets/{diagram-2AECGRRQ-BaVLuzcD.js → diagram-2AECGRRQ-Dpn8TJa2.js} +1 -1
  48. package/dist/client/assets/{diagram-5GNKFQAL-9Cu7Wa7J.js → diagram-5GNKFQAL-BxkzEc_t.js} +1 -1
  49. package/dist/client/assets/{diagram-KO2AKTUF-XKiCVdjO.js → diagram-KO2AKTUF-KG0o4LQ7.js} +1 -1
  50. package/dist/client/assets/{diagram-LMA3HP47-DerecU5v.js → diagram-LMA3HP47-CJ-AjQPt.js} +1 -1
  51. package/dist/client/assets/{diagram-OG6HWLK6-BWcREvZ9.js → diagram-OG6HWLK6-D_FG9cDJ.js} +1 -1
  52. package/dist/client/assets/{erDiagram-TEJ5UH35-DU3BBQJY.js → erDiagram-TEJ5UH35-DllhUlzY.js} +1 -1
  53. package/dist/client/assets/{flowDiagram-I6XJVG4X-DXO_IJeR.js → flowDiagram-I6XJVG4X-Bg3OotXu.js} +1 -1
  54. package/dist/client/assets/{ganttDiagram-6RSMTGT7-CXiFZEPx.js → ganttDiagram-6RSMTGT7-BUpUL2Cj.js} +1 -1
  55. package/dist/client/assets/{gitGraphDiagram-PVQCEYII-DHewdln-.js → gitGraphDiagram-PVQCEYII-DMRhyWth.js} +1 -1
  56. package/dist/client/assets/{index-DT5g2AtL.js → index-BB2RmhGR.js} +1 -1
  57. package/dist/client/assets/index-BXzOTCgN.css +1 -0
  58. package/dist/client/assets/index-DRFbyGvK.js +788 -0
  59. package/dist/client/assets/{index-DD0GkjkG.js → index-Daewu-VD.js} +1 -1
  60. package/dist/client/assets/{infoDiagram-5YYISTIA-CN40PAGW.js → infoDiagram-5YYISTIA-Bq9D64Ar.js} +1 -1
  61. package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-B8KsyuPk.js → ishikawaDiagram-YF4QCWOH-DIaKHHF-.js} +1 -1
  62. package/dist/client/assets/{journeyDiagram-JHISSGLW-BlEb3E_P.js → journeyDiagram-JHISSGLW-gQWGLTeZ.js} +1 -1
  63. package/dist/client/assets/{kanban-definition-UN3LZRKU-B080CGS9.js → kanban-definition-UN3LZRKU-vRgZ5RjE.js} +1 -1
  64. package/dist/client/assets/{linear-D6Tg-IET.js → linear-B4a11szP.js} +1 -1
  65. package/dist/client/assets/{mermaid.core-DP18nW3T.js → mermaid.core-JhUbsJFB.js} +4 -4
  66. package/dist/client/assets/{mindmap-definition-RKZ34NQL-bfo7Qm5I.js → mindmap-definition-RKZ34NQL-ZH-Oz_D-.js} +1 -1
  67. package/dist/client/assets/{pieDiagram-4H26LBE5-ZsPztPu6.js → pieDiagram-4H26LBE5-6rpNrJR6.js} +1 -1
  68. package/dist/client/assets/{quadrantDiagram-W4KKPZXB-DKrTleIL.js → quadrantDiagram-W4KKPZXB-DpTKtxEM.js} +1 -1
  69. package/dist/client/assets/{requirementDiagram-4Y6WPE33-D4YX8ZgG.js → requirementDiagram-4Y6WPE33-DpDvZkrK.js} +1 -1
  70. package/dist/client/assets/{sankeyDiagram-5OEKKPKP-Bo-xm6Mc.js → sankeyDiagram-5OEKKPKP-KKjWCTYP.js} +1 -1
  71. package/dist/client/assets/{sequenceDiagram-3UESZ5HK-CozgdKp6.js → sequenceDiagram-3UESZ5HK-BCmXos1U.js} +1 -1
  72. package/dist/client/assets/{stateDiagram-AJRCARHV-CiK61MwV.js → stateDiagram-AJRCARHV-Xq7jqpMj.js} +1 -1
  73. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C3mDHsxD.js +1 -0
  74. package/dist/client/assets/{timeline-definition-PNZ67QCA-CgHoguI7.js → timeline-definition-PNZ67QCA-CMmq8p5q.js} +1 -1
  75. package/dist/client/assets/{vennDiagram-CIIHVFJN-TY32dxQb.js → vennDiagram-CIIHVFJN-DgK-w2Jv.js} +1 -1
  76. package/dist/client/assets/{wardley-L42UT6IY-C6Q7VFwH.js → wardley-L42UT6IY-C5CwlFHh.js} +1 -1
  77. package/dist/client/assets/{wardleyDiagram-YWT4CUSO-nZLnVsQL.js → wardleyDiagram-YWT4CUSO-D47CtDSc.js} +1 -1
  78. package/dist/client/assets/{xychartDiagram-2RQKCTM6-DHdYRHEr.js → xychartDiagram-2RQKCTM6-C1M_xTVv.js} +1 -1
  79. package/dist/client/index.html +2 -2
  80. package/dist/core/ask/run-ask.d.ts +3 -1
  81. package/dist/core/ask/run-ask.js +75 -54
  82. package/dist/core/ask/run-ask.js.map +1 -1
  83. package/dist/core/references/find-references.d.ts +13 -0
  84. package/dist/core/references/find-references.js +41 -0
  85. package/dist/core/references/find-references.js.map +1 -0
  86. package/dist/core/references/index.d.ts +2 -0
  87. package/dist/core/references/index.js +2 -0
  88. package/dist/core/references/index.js.map +1 -0
  89. package/dist/core/references/types.d.ts +45 -0
  90. package/dist/core/references/types.js +9 -0
  91. package/dist/core/references/types.js.map +1 -0
  92. package/dist/core/workspace/resolve.d.ts +29 -0
  93. package/dist/core/workspace/resolve.js +80 -0
  94. package/dist/core/workspace/resolve.js.map +1 -0
  95. package/dist/server/config.d.ts +58 -6
  96. package/dist/server/config.js +94 -19
  97. package/dist/server/config.js.map +1 -1
  98. package/dist/server/core/plugin-host/cli-engine.d.ts +8 -0
  99. package/dist/server/core/plugin-host/cli-engine.js +16 -0
  100. package/dist/server/core/plugin-host/cli-engine.js.map +1 -0
  101. package/dist/server/core/plugin-host/cross-cutting.js +1 -1
  102. package/dist/server/core/plugin-host/cross-cutting.js.map +1 -1
  103. package/dist/server/core/plugin-host/entities-router.d.ts +3 -1
  104. package/dist/server/core/plugin-host/entities-router.js +24 -19
  105. package/dist/server/core/plugin-host/entities-router.js.map +1 -1
  106. package/dist/server/core/plugin-host/host.js +4 -9
  107. package/dist/server/core/plugin-host/host.js.map +1 -1
  108. package/dist/server/core/plugin-host/project-host.d.ts +38 -0
  109. package/dist/server/core/plugin-host/project-host.js +118 -0
  110. package/dist/server/core/plugin-host/project-host.js.map +1 -0
  111. package/dist/server/core/plugin-host/registry.d.ts +14 -0
  112. package/dist/server/core/plugin-host/registry.js +26 -0
  113. package/dist/server/core/plugin-host/registry.js.map +1 -0
  114. package/dist/server/core/plugin-host/serialization-engine.d.ts +38 -8
  115. package/dist/server/core/plugin-host/serialization-engine.js +63 -39
  116. package/dist/server/core/plugin-host/serialization-engine.js.map +1 -1
  117. package/dist/server/core/plugin-host/types.d.ts +49 -27
  118. package/dist/server/db/index.d.ts +8 -1
  119. package/dist/server/db/index.js +12 -3
  120. package/dist/server/db/index.js.map +1 -1
  121. package/dist/server/db/migrations/035_m29_slug_identity.sql +248 -0
  122. package/dist/server/db/readonly.d.ts +8 -3
  123. package/dist/server/db/readonly.js +7 -4
  124. package/dist/server/db/readonly.js.map +1 -1
  125. package/dist/server/domain/raw-entity-reader.d.ts +5 -5
  126. package/dist/server/domain/raw-entity-reader.js +34 -39
  127. package/dist/server/domain/raw-entity-reader.js.map +1 -1
  128. package/dist/server/entities/ac/ac-analysis.service.d.ts +54 -0
  129. package/dist/server/entities/ac/ac-analysis.service.js +162 -0
  130. package/dist/server/entities/ac/ac-analysis.service.js.map +1 -0
  131. package/dist/server/entities/ac/mcp-server.d.ts +10 -2
  132. package/dist/server/entities/ac/mcp-server.js +34 -3
  133. package/dist/server/entities/ac/mcp-server.js.map +1 -1
  134. package/dist/server/entities/ac/plugin.d.ts +3 -1
  135. package/dist/server/entities/ac/plugin.js +9 -5
  136. package/dist/server/entities/ac/plugin.js.map +1 -1
  137. package/dist/server/entities/ac/serializer.js +1 -1
  138. package/dist/server/entities/ac/serializer.js.map +1 -1
  139. package/dist/server/entities/ac/services.d.ts +19 -7
  140. package/dist/server/entities/ac/services.js +65 -42
  141. package/dist/server/entities/ac/services.js.map +1 -1
  142. package/dist/server/entities/ac/system-prompt.js +1 -8
  143. package/dist/server/entities/ac/system-prompt.js.map +1 -1
  144. package/dist/server/entities/database-table/mcp-server.d.ts +2 -2
  145. package/dist/server/entities/database-table/mcp-server.js +5 -2
  146. package/dist/server/entities/database-table/mcp-server.js.map +1 -1
  147. package/dist/server/entities/database-table/plugin.d.ts +3 -1
  148. package/dist/server/entities/database-table/plugin.js +6 -5
  149. package/dist/server/entities/database-table/plugin.js.map +1 -1
  150. package/dist/server/entities/database-table/routes.d.ts +2 -2
  151. package/dist/server/entities/database-table/serializer.js +1 -1
  152. package/dist/server/entities/database-table/serializer.js.map +1 -1
  153. package/dist/server/entities/database-table/services.d.ts +19 -7
  154. package/dist/server/entities/database-table/services.js +77 -49
  155. package/dist/server/entities/database-table/services.js.map +1 -1
  156. package/dist/server/entities/database-table/system-prompt.js +1 -1
  157. package/dist/server/entities/database-table/system-prompt.js.map +1 -1
  158. package/dist/server/entities/dto/mcp-server.d.ts +2 -2
  159. package/dist/server/entities/dto/mcp-server.js +5 -2
  160. package/dist/server/entities/dto/mcp-server.js.map +1 -1
  161. package/dist/server/entities/dto/plugin.d.ts +3 -1
  162. package/dist/server/entities/dto/plugin.js +6 -5
  163. package/dist/server/entities/dto/plugin.js.map +1 -1
  164. package/dist/server/entities/dto/serializer.js +2 -2
  165. package/dist/server/entities/dto/serializer.js.map +1 -1
  166. package/dist/server/entities/dto/services.d.ts +19 -7
  167. package/dist/server/entities/dto/services.js +73 -49
  168. package/dist/server/entities/dto/services.js.map +1 -1
  169. package/dist/server/entities/dto/system-prompt.js +1 -1
  170. package/dist/server/entities/dto/system-prompt.js.map +1 -1
  171. package/dist/server/entities/endpoint/mcp-server.d.ts +2 -2
  172. package/dist/server/entities/endpoint/mcp-server.js +5 -2
  173. package/dist/server/entities/endpoint/mcp-server.js.map +1 -1
  174. package/dist/server/entities/endpoint/plugin.d.ts +3 -1
  175. package/dist/server/entities/endpoint/plugin.js +6 -5
  176. package/dist/server/entities/endpoint/plugin.js.map +1 -1
  177. package/dist/server/entities/endpoint/serializer.js +4 -4
  178. package/dist/server/entities/endpoint/serializer.js.map +1 -1
  179. package/dist/server/entities/endpoint/services.d.ts +21 -9
  180. package/dist/server/entities/endpoint/services.js +94 -65
  181. package/dist/server/entities/endpoint/services.js.map +1 -1
  182. package/dist/server/entities/endpoint/system-prompt.js +1 -1
  183. package/dist/server/entities/endpoint/system-prompt.js.map +1 -1
  184. package/dist/server/entities/mutate-opts.d.ts +15 -0
  185. package/dist/server/entities/mutate-opts.js +2 -0
  186. package/dist/server/entities/mutate-opts.js.map +1 -0
  187. package/dist/server/entities/ui-view/mcp-server.d.ts +2 -2
  188. package/dist/server/entities/ui-view/mcp-server.js +5 -2
  189. package/dist/server/entities/ui-view/mcp-server.js.map +1 -1
  190. package/dist/server/entities/ui-view/plugin.d.ts +3 -1
  191. package/dist/server/entities/ui-view/plugin.js +6 -5
  192. package/dist/server/entities/ui-view/plugin.js.map +1 -1
  193. package/dist/server/entities/ui-view/routes.d.ts +2 -2
  194. package/dist/server/entities/ui-view/serializer.js +1 -1
  195. package/dist/server/entities/ui-view/serializer.js.map +1 -1
  196. package/dist/server/entities/ui-view/services.d.ts +19 -7
  197. package/dist/server/entities/ui-view/services.js +68 -44
  198. package/dist/server/entities/ui-view/services.js.map +1 -1
  199. package/dist/server/entities/ui-view/system-prompt.d.ts +0 -5
  200. package/dist/server/entities/ui-view/system-prompt.js +3 -7
  201. package/dist/server/entities/ui-view/system-prompt.js.map +1 -1
  202. package/dist/server/external-skills/brief-implementer-template.d.ts +1 -1
  203. package/dist/server/external-skills/brief-implementer-template.js +1 -1
  204. package/dist/server/external-skills/spec-reader-template.d.ts +1 -1
  205. package/dist/server/external-skills/spec-reader-template.js +3 -2
  206. package/dist/server/external-skills/spec-reader-template.js.map +1 -1
  207. package/dist/server/fs/entities-watcher.d.ts +31 -0
  208. package/dist/server/fs/entities-watcher.js +68 -0
  209. package/dist/server/fs/entities-watcher.js.map +1 -0
  210. package/dist/server/fs/watcher.d.ts +2 -2
  211. package/dist/server/fs/watcher.js +7 -1
  212. package/dist/server/fs/watcher.js.map +1 -1
  213. package/dist/server/index.d.ts +11 -1
  214. package/dist/server/index.js +134 -639
  215. package/dist/server/index.js.map +1 -1
  216. package/dist/server/mcp/c4s-reader.d.ts +2 -2
  217. package/dist/server/mcp/c4s-reader.js +41 -4
  218. package/dist/server/mcp/c4s-reader.js.map +1 -1
  219. package/dist/server/mcp/c4s-tools.js +2 -0
  220. package/dist/server/mcp/c4s-tools.js.map +1 -1
  221. package/dist/server/mcp/ensure-mcp-json.d.ts +9 -2
  222. package/dist/server/mcp/ensure-mcp-json.js +18 -4
  223. package/dist/server/mcp/ensure-mcp-json.js.map +1 -1
  224. package/dist/server/mcp/reference-tools.d.ts +8 -2
  225. package/dist/server/mcp/reference-tools.js +52 -179
  226. package/dist/server/mcp/reference-tools.js.map +1 -1
  227. package/dist/server/mcp/release-tools/index.d.ts +2 -2
  228. package/dist/server/routes/agent-turn.d.ts +41 -7
  229. package/dist/server/routes/agent-turn.js +84 -20
  230. package/dist/server/routes/agent-turn.js.map +1 -1
  231. package/dist/server/routes/chat.js +47 -15
  232. package/dist/server/routes/chat.js.map +1 -1
  233. package/dist/server/routes/config.d.ts +24 -0
  234. package/dist/server/routes/config.js +231 -0
  235. package/dist/server/routes/config.js.map +1 -0
  236. package/dist/server/routes/references.d.ts +2 -1
  237. package/dist/server/routes/references.js +4 -5
  238. package/dist/server/routes/references.js.map +1 -1
  239. package/dist/server/routes/releases.d.ts +2 -2
  240. package/dist/server/routes/static.d.ts +11 -0
  241. package/dist/server/routes/static.js +44 -0
  242. package/dist/server/routes/static.js.map +1 -0
  243. package/dist/server/routes/threads.js +14 -2
  244. package/dist/server/routes/threads.js.map +1 -1
  245. package/dist/server/serialization/auto-schema.d.ts +2 -1
  246. package/dist/server/serialization/auto-schema.js +5 -6
  247. package/dist/server/serialization/auto-schema.js.map +1 -1
  248. package/dist/server/serialization/registerAll.d.ts +7 -6
  249. package/dist/server/serialization/registerAll.js +17 -6
  250. package/dist/server/serialization/registerAll.js.map +1 -1
  251. package/dist/server/serialization/resolve-page.d.ts +2 -2
  252. package/dist/server/serialization/serializers/section.d.ts +6 -1
  253. package/dist/server/serialization/serializers/section.js +6 -3
  254. package/dist/server/serialization/serializers/section.js.map +1 -1
  255. package/dist/server/services/brief.d.ts +2 -2
  256. package/dist/server/services/chat-context.d.ts +24 -0
  257. package/dist/server/services/chat-context.js +70 -13
  258. package/dist/server/services/chat-context.js.map +1 -1
  259. package/dist/server/services/entity-indexer.d.ts +42 -0
  260. package/dist/server/services/entity-indexer.js +179 -0
  261. package/dist/server/services/entity-indexer.js.map +1 -0
  262. package/dist/server/services/entity-store.d.ts +68 -0
  263. package/dist/server/services/entity-store.js +162 -0
  264. package/dist/server/services/entity-store.js.map +1 -0
  265. package/dist/server/services/entity-writer.d.ts +12 -1
  266. package/dist/server/services/entity-writer.js +22 -11
  267. package/dist/server/services/entity-writer.js.map +1 -1
  268. package/dist/server/services/git.js +6 -1
  269. package/dist/server/services/git.js.map +1 -1
  270. package/dist/server/services/pages-frontmatter-indexer.d.ts +2 -2
  271. package/dist/server/services/pages-link-indexer.d.ts +2 -2
  272. package/dist/server/services/pages.d.ts +2 -0
  273. package/dist/server/services/pages.js +24 -9
  274. package/dist/server/services/pages.js.map +1 -1
  275. package/dist/server/services/plan.d.ts +2 -2
  276. package/dist/server/services/references.d.ts +25 -0
  277. package/dist/server/services/references.js +102 -21
  278. package/dist/server/services/references.js.map +1 -1
  279. package/dist/server/services/release-bundle.d.ts +0 -1
  280. package/dist/server/services/release-bundle.js +0 -1
  281. package/dist/server/services/release-bundle.js.map +1 -1
  282. package/dist/server/services/release-import.d.ts +2 -0
  283. package/dist/server/services/release-import.js +6 -4
  284. package/dist/server/services/release-import.js.map +1 -1
  285. package/dist/server/services/release.d.ts +10 -10
  286. package/dist/server/services/release.js +32 -63
  287. package/dist/server/services/release.js.map +1 -1
  288. package/dist/server/services/section-indexer.d.ts +4 -3
  289. package/dist/server/services/section-indexer.js +8 -9
  290. package/dist/server/services/section-indexer.js.map +1 -1
  291. package/dist/server/services/skill-registry.d.ts +28 -1
  292. package/dist/server/services/skill-registry.js +51 -10
  293. package/dist/server/services/skill-registry.js.map +1 -1
  294. package/dist/server/services/slug.js +6 -0
  295. package/dist/server/services/slug.js.map +1 -1
  296. package/dist/server/services/static-html.d.ts +24 -0
  297. package/dist/server/services/static-html.js +49 -0
  298. package/dist/server/services/static-html.js.map +1 -0
  299. package/dist/server/services/tags.d.ts +13 -3
  300. package/dist/server/services/tags.js +65 -26
  301. package/dist/server/services/tags.js.map +1 -1
  302. package/dist/server/services/todos-indexer.d.ts +2 -2
  303. package/dist/server/services/versions.d.ts +7 -7
  304. package/dist/server/services/versions.js +34 -37
  305. package/dist/server/services/versions.js.map +1 -1
  306. package/dist/server/workspace/bootstrap.d.ts +42 -0
  307. package/dist/server/workspace/bootstrap.js +73 -0
  308. package/dist/server/workspace/bootstrap.js.map +1 -0
  309. package/dist/server/workspace/context-cache.d.ts +48 -0
  310. package/dist/server/workspace/context-cache.js +147 -0
  311. package/dist/server/workspace/context-cache.js.map +1 -0
  312. package/dist/server/workspace/db-migration.d.ts +11 -0
  313. package/dist/server/workspace/db-migration.js +44 -0
  314. package/dist/server/workspace/db-migration.js.map +1 -0
  315. package/dist/server/workspace/middleware.d.ts +15 -0
  316. package/dist/server/workspace/middleware.js +36 -0
  317. package/dist/server/workspace/middleware.js.map +1 -0
  318. package/dist/server/workspace/project-context.d.ts +65 -0
  319. package/dist/server/workspace/project-context.js +655 -0
  320. package/dist/server/workspace/project-context.js.map +1 -0
  321. package/dist/server/workspace/project-id.d.ts +7 -0
  322. package/dist/server/workspace/project-id.js +11 -0
  323. package/dist/server/workspace/project-id.js.map +1 -0
  324. package/dist/server/workspace/registry.d.ts +58 -0
  325. package/dist/server/workspace/registry.js +264 -0
  326. package/dist/server/workspace/registry.js.map +1 -0
  327. package/dist/server/workspace/routes.d.ts +21 -0
  328. package/dist/server/workspace/routes.js +181 -0
  329. package/dist/server/workspace/routes.js.map +1 -0
  330. package/dist/server/workspace/types.d.ts +30 -0
  331. package/dist/server/workspace/types.js +6 -0
  332. package/dist/server/workspace/types.js.map +1 -0
  333. package/dist/server/ws/gateway.d.ts +12 -2
  334. package/dist/server/ws/gateway.js +51 -9
  335. package/dist/server/ws/gateway.js.map +1 -1
  336. package/dist/server/ws/project-emitter.d.ts +17 -0
  337. package/dist/server/ws/project-emitter.js +12 -0
  338. package/dist/server/ws/project-emitter.js.map +1 -0
  339. package/dist/shared/entities.d.ts +2 -2
  340. package/dist/shared/languages.d.ts +17 -0
  341. package/dist/shared/languages.js +31 -0
  342. package/dist/shared/languages.js.map +1 -0
  343. package/dist/shared/types.d.ts +11 -0
  344. package/dist/shared/xml-tags.d.ts +8 -0
  345. package/dist/shared/xml-tags.js +24 -0
  346. package/dist/shared/xml-tags.js.map +1 -1
  347. package/package.json +10 -3
  348. package/dist/client/assets/channel-BqjILLUr.js +0 -1
  349. package/dist/client/assets/classDiagram-4FO5ZUOK-LjT84-kK.js +0 -1
  350. package/dist/client/assets/classDiagram-v2-Q7XG4LA2-LjT84-kK.js +0 -1
  351. package/dist/client/assets/index-BTXWIk4x.css +0 -1
  352. package/dist/client/assets/index-DcIG_8JB.js +0 -760
  353. package/dist/client/assets/stateDiagram-v2-BHNVJYJU-C6-8M5Sb.js +0 -1
@@ -0,0 +1,655 @@
1
+ import { Router } from 'express';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { readConfig } from '../config.js';
5
+ import { openDb } from '../db/index.js';
6
+ import { PagesService } from '../services/pages.js';
7
+ import { pagesRouter } from '../routes/pages.js';
8
+ import { StaticHtmlService } from '../services/static-html.js';
9
+ import { staticRouter } from '../routes/static.js';
10
+ import { tagsRouter } from '../routes/tags.js';
11
+ import { entitiesRouter } from '../core/plugin-host/entities-router.js';
12
+ import { referencesRouter } from '../routes/references.js';
13
+ import { TagsService, DomainError } from '../services/tags.js';
14
+ import { VersionService } from '../services/versions.js';
15
+ import { ReferencesService } from '../services/references.js';
16
+ import { ChatService } from '../services/chat.js';
17
+ import { SectionsService } from '../services/sections.js';
18
+ import { registerExtensionReferenceType } from '../../shared/reference-extensions.js';
19
+ import { SUPPORTED_LANGUAGES, isSupportedLanguage } from '../../shared/languages.js';
20
+ import { PlanService } from '../services/plan.js';
21
+ import { plansRouter } from '../routes/plans.js';
22
+ import { BriefService } from '../services/brief.js';
23
+ import { briefsRouter } from '../routes/briefs.js';
24
+ import { PatchService } from '../services/patch.js';
25
+ import { patchesRouter } from '../routes/patches.js';
26
+ import { RemoteAuthService } from '../services/remote-auth.js';
27
+ import { RemoteHttpClient, assertRemoteApiReachable } from '../services/remote-http-client.js';
28
+ import { remoteAccountRouter } from '../routes/remote-account.js';
29
+ import { remoteProjectRouter } from '../routes/remote-project.js';
30
+ import { PagesFrontmatterIndexer } from '../services/pages-frontmatter-indexer.js';
31
+ import { SectionIndexerService } from '../services/section-indexer.js';
32
+ import { TodosIndexerService } from '../services/todos-indexer.js';
33
+ import { PagesLinkIndexerService } from '../services/pages-link-indexer.js';
34
+ import { PageSerializer } from '../services/page-serializer.js';
35
+ import { PageVersionService } from '../services/page-version.js';
36
+ import { RawEntityReader } from '../domain/raw-entity-reader.js';
37
+ import { ReleaseService } from '../services/release.js';
38
+ import { releasesRouter } from '../routes/releases.js';
39
+ import { ReleasePushService } from '../services/release-push.js';
40
+ import { releasePushesRouter } from '../routes/release-pushes.js';
41
+ import { ReleaseImportService, rollbackClone } from '../services/release-import.js';
42
+ import { createReleaseToolsServer } from '../mcp/release-tools/index.js';
43
+ import { GitService } from '../services/git.js';
44
+ import { gitRouter } from '../routes/git.js';
45
+ import { PagesWatcher } from '../fs/watcher.js';
46
+ import { EntitiesWatcher } from '../fs/entities-watcher.js';
47
+ import { EntityStore } from '../services/entity-store.js';
48
+ import { EntityIndexerService } from '../services/entity-indexer.js';
49
+ import { createReferenceToolsServer } from '../mcp/reference-tools.js';
50
+ import { SkillRegistry, SkillResolver, findSkillsRoots } from '../services/skill-registry.js';
51
+ import { chatRouter } from '../routes/chat.js';
52
+ import { threadsRouter } from '../routes/threads.js';
53
+ import { sectionsRouter } from '../routes/sections.js';
54
+ import { todosRouter } from '../routes/todos.js';
55
+ import { pageLinksRouter } from '../routes/page-links.js';
56
+ import { errorHandler } from '../routes/errors.js';
57
+ import { configRouter } from '../routes/config.js';
58
+ import { SerializationEngine } from '../core/plugin-host/serialization-engine.js';
59
+ import { sectionSerializer } from '../serialization/serializers/section.js';
60
+ import { pluginHostRouter } from '../core/plugin-host/cross-cutting.js';
61
+ import { ProjectWsEmitter } from '../ws/project-emitter.js';
62
+ import { projectIdForCwd } from './project-id.js';
63
+ import { ensureWelcomePage } from './bootstrap.js';
64
+ // M06 registers <section_ref/> as the 6th XML reference type via the M19
65
+ // extension reference types slot. Registration is PROCESS-level (tag shape is
66
+ // static); the per-project anchor validation lives in reference-tools, which
67
+ // owns a per-context SectionsService — a validate closure here would leak one
68
+ // project's sections into every other context (M31).
69
+ registerExtensionReferenceType({
70
+ tag: 'section_ref',
71
+ attrOrder: ['anchor'],
72
+ });
73
+ /**
74
+ * M29: one-time best-effort backup of the derived SQLite before a DB→text
75
+ * export / divergent-rebuild, so the prior index is recoverable. Idempotent —
76
+ * skips if the `.pre-migration.bak` already exists. M31: follows the workspace
77
+ * slot path (the DB no longer lives in the project dir).
78
+ */
79
+ function backupDbBeforeMigration(slotDir) {
80
+ const src = path.join(slotDir, 'db.sqlite');
81
+ const bak = path.join(slotDir, 'db.sqlite.pre-migration.bak');
82
+ try {
83
+ if (fs.existsSync(src) && !fs.existsSync(bak))
84
+ fs.copyFileSync(src, bak);
85
+ }
86
+ catch (err) {
87
+ console.warn('[m29] db backup failed:', err.message);
88
+ }
89
+ }
90
+ /**
91
+ * M31: builds one fully-wired project — DB, services, watchers, indexers and
92
+ * the per-context router. Mechanical carve of the former startServer body;
93
+ * handlers are byte-identical, only the mount prefixes lost their `/api`.
94
+ * Await cost ≈ entityIndexer.indexAll() (<1s budget); section/todos/link
95
+ * indexers stay fire-and-forget.
96
+ */
97
+ export async function buildProjectContext(deps) {
98
+ // Partial-build cleanup: resources acquired before a build failure (db
99
+ // handle, watcher fds) are released in reverse order — a failed build is
100
+ // cached as a 500 for THIS project only and must leak nothing.
101
+ const cleanup = [];
102
+ try {
103
+ return await buildInner(deps, cleanup);
104
+ }
105
+ catch (err) {
106
+ for (const fn of cleanup.reverse()) {
107
+ try {
108
+ await fn();
109
+ }
110
+ catch {
111
+ /* best-effort */
112
+ }
113
+ }
114
+ throw err;
115
+ }
116
+ }
117
+ async function buildInner(deps, cleanup) {
118
+ const { registry, workspace, cwd, gateway, mode } = deps;
119
+ const projectId = projectIdForCwd(cwd);
120
+ const router = Router();
121
+ // M31: every former WsGateway consumer now broadcasts into this project's
122
+ // room only — the emitter is signature-compatible (`broadcast(event)`).
123
+ const ws = new ProjectWsEmitter(gateway, projectId);
124
+ // M31: per-project agent-turn registries (was module-global in agent-turn.ts).
125
+ const activeAdapters = new Map();
126
+ const pendingInputs = new Map();
127
+ const skillRegistry = SkillRegistry.load(findSkillsRoots(cwd));
128
+ const bootConfig = readConfig(cwd);
129
+ // Effective pagesDir precedence: CLI flag > config.json > hardcoded 'pages'.
130
+ const pagesDir = deps.pagesDirOverride ?? bootConfig.pagesDir ?? 'pages';
131
+ // M21: briefsDir, default '.claude4spec/briefs'. Walidacja: musi byc relative,
132
+ // nie moze uciekac z cwd. Kolizja z pagesDir → tylko warn (user moze mocno
133
+ // celowo umieszczac brief'y w katalogu pages — frontmatter.type='brief'
134
+ // pelni hidden-tree filter).
135
+ const briefsDir = bootConfig.briefsDir ?? '.claude4spec/briefs';
136
+ if (path.isAbsolute(briefsDir)) {
137
+ throw new Error(`config.json: briefsDir must be relative to cwd, got: ${briefsDir}`);
138
+ }
139
+ const briefsAbs = path.resolve(cwd, briefsDir);
140
+ const briefsRel = path.relative(cwd, briefsAbs);
141
+ if (briefsRel.startsWith('..') || path.isAbsolute(briefsRel)) {
142
+ throw new Error(`config.json: briefsDir must not escape project root, got: ${briefsDir}`);
143
+ }
144
+ if (briefsDir === pagesDir) {
145
+ console.warn(`[config] briefsDir === pagesDir ("${pagesDir}") — brief files will be visible in both indexers`);
146
+ }
147
+ // M23: patchesDir, default '.claude4spec/patches'. Same validation as briefsDir.
148
+ const patchesDir = bootConfig.patchesDir ?? '.claude4spec/patches';
149
+ if (path.isAbsolute(patchesDir)) {
150
+ throw new Error(`config.json: patchesDir must be relative to cwd, got: ${patchesDir}`);
151
+ }
152
+ const patchesAbs = path.resolve(cwd, patchesDir);
153
+ const patchesRel = path.relative(cwd, patchesAbs);
154
+ if (patchesRel.startsWith('..') || path.isAbsolute(patchesRel)) {
155
+ throw new Error(`config.json: patchesDir must not escape project root, got: ${patchesDir}`);
156
+ }
157
+ if (patchesDir === pagesDir || patchesDir === briefsDir) {
158
+ console.warn(`[config] patchesDir collides with pagesDir/briefsDir ("${patchesDir}") — patch files will be visible in multiple indexers`);
159
+ }
160
+ // M29: entitiesDir, default '.claude4spec/entities'. Same path-safety as
161
+ // briefsDir/patchesDir — but this directory is COMMITTED to git (source of
162
+ // truth for entities; SQLite is a derived index rebuilt from it at boot).
163
+ const entitiesDir = bootConfig.entitiesDir ?? '.claude4spec/entities';
164
+ if (path.isAbsolute(entitiesDir)) {
165
+ throw new Error(`config.json: entitiesDir must be relative to cwd, got: ${entitiesDir}`);
166
+ }
167
+ const entitiesAbs = path.resolve(cwd, entitiesDir);
168
+ const entitiesRel = path.relative(cwd, entitiesAbs);
169
+ if (entitiesRel.startsWith('..') || path.isAbsolute(entitiesRel)) {
170
+ throw new Error(`config.json: entitiesDir must not escape project root, got: ${entitiesDir}`);
171
+ }
172
+ // M01 (0.1.36): resolve the remote base URL with precedence
173
+ // `--remote-url` flag (deps) > config.json > prod constant. The prod-constant
174
+ // fallback lives in RemoteHttpClient; here `null` means "use prod".
175
+ const remoteApiUrl = deps.remoteApiUrl ?? bootConfig.remoteApiUrl;
176
+ // M24: an explicit remoteApiUrl override (flag or config.json) must be a valid,
177
+ // reachable host — hard error at build, no fallback to the production constant.
178
+ // M31: failure is a per-project build failure (500), not a boot failure.
179
+ if (remoteApiUrl != null && remoteApiUrl.trim() !== '') {
180
+ await assertRemoteApiReachable(remoteApiUrl);
181
+ }
182
+ const pluginHost = deps.pluginRegistry.consolidate(bootConfig.entities);
183
+ const hostState = pluginHost.partition();
184
+ console.log(`[plugin-host] active: [${hostState.active.join(', ') || '∅'}]` +
185
+ (hostState.inactive.length ? `, inactive: [${hostState.inactive.join(', ')}]` : '') +
186
+ (hostState.unknown.length ? `, unknown: [${hostState.unknown.join(', ')}]` : ''));
187
+ const initialWritingStyle = bootConfig.writingStyle;
188
+ if (initialWritingStyle !== null && !skillRegistry.isSelectable(initialWritingStyle)) {
189
+ const available = skillRegistry.listSelectable().map((s) => s.slug).join(', ') || '(none)';
190
+ throw new Error(`config.json: writingStyle "${initialWritingStyle}" not a selectable writing-style skill. Available: ${available}`);
191
+ }
192
+ // 0.1.51: fail fast on a hand-edited language value outside SUPPORTED_LANGUAGES so
193
+ // a bogus display name never reaches the system prompt. PATCH /config enforces
194
+ // the same membership at runtime.
195
+ if (bootConfig.language !== null && !isSupportedLanguage(bootConfig.language)) {
196
+ throw new Error(`config.json: language "${bootConfig.language}" not supported. Available: ${SUPPORTED_LANGUAGES.join(', ')}`);
197
+ }
198
+ const initialConvLang = bootConfig.agent?.conversationalLanguage ?? null;
199
+ if (initialConvLang !== null && !isSupportedLanguage(initialConvLang)) {
200
+ throw new Error(`config.json: agent.conversationalLanguage "${initialConvLang}" not supported. Available: ${SUPPORTED_LANGUAGES.join(', ')}`);
201
+ }
202
+ const skillResolver = new SkillResolver(skillRegistry, cwd);
203
+ const db = openDb(workspace, cwd);
204
+ cleanup.push(() => db.close());
205
+ const dbSlotDir = registry.slotDir(workspace, projectId);
206
+ const pages = new PagesService(cwd, pagesDir);
207
+ await pages.ensureRoot();
208
+ // M30: static file server rooted at the same pagesDir, backing the HTML preview iframe.
209
+ const staticHtml = new StaticHtmlService(cwd, pagesDir);
210
+ // M21 m02multidir: drugi PagesService dla briefsDir. Wspoldziel z pierwszym
211
+ // zarowno PageVersionService jak i WsGateway, ale ma osobny watcher (debounce
212
+ // independent per katalog) i osobny PageSerializer (constructor-bound do
213
+ // odpowiedniego rootDir).
214
+ const briefsPages = new PagesService(cwd, briefsDir);
215
+ await briefsPages.ensureRoot();
216
+ // M23 m02multidir: trzeci PagesService dla patchesDir (analogicznie do briefsDir).
217
+ const patchesPages = new PagesService(cwd, patchesDir);
218
+ await patchesPages.ensureRoot();
219
+ const tagsService = new TagsService(db.handle);
220
+ const versionService = new VersionService(db.handle);
221
+ const rawReader = new RawEntityReader(db.handle);
222
+ // M17: wire snapshot capture deps. After this, every entity service
223
+ // mutation captures a deterministic snapshot via host.snapshot(...).
224
+ versionService.configureSnapshot(rawReader, pluginHost);
225
+ // M24: remote-account identity (device flow + local session). Single HTTP
226
+ // client per project context; base URL from config.remoteApiUrl (or the prod constant).
227
+ const remoteHttpClient = new RemoteHttpClient(remoteApiUrl);
228
+ const remoteAuthService = new RemoteAuthService(db.handle, remoteHttpClient);
229
+ const chatService = new ChatService(db.handle);
230
+ // Orphan cleanup: rowsy chat_message.status='streaming' pozostale po crashu poprzedniego
231
+ // procesu (SIGKILL/OOM) — brak aktywnego adaptera po starcie, flipujemy wszystkie na 'complete'.
232
+ chatService.finalizeAllStreamingRows();
233
+ const watcher = new PagesWatcher(pages.root, ws);
234
+ cleanup.push(() => watcher.close());
235
+ // M21 m02multidir: drugi PagesWatcher na briefsDir. Wspoldzieli ten sam
236
+ // gateway (broadcast `page:changed` z drugiego katalogu — UI może slot-detect
237
+ // przez prefix sciezki, jezeli kiedys bedzie potrzebne).
238
+ const briefsWatcher = new PagesWatcher(briefsPages.root, ws);
239
+ cleanup.push(() => briefsWatcher.close());
240
+ // M23 m02multidir: trzeci PagesWatcher na patchesDir.
241
+ const patchesWatcher = new PagesWatcher(patchesPages.root, ws);
242
+ cleanup.push(() => patchesWatcher.close());
243
+ // M29: dedicated watcher + file store + indexer for the committed entity store.
244
+ // The page-family watchers above are rooted outside `.claude4spec/`, so this
245
+ // watcher owns `<entitiesDir>` exclusively.
246
+ const entitiesWatcher = new EntitiesWatcher(entitiesAbs);
247
+ cleanup.push(() => entitiesWatcher.close());
248
+ const entityStore = new EntityStore(cwd, entitiesDir, entitiesWatcher, rawReader, pluginHost);
249
+ entityStore.ensureRoot();
250
+ const entityIndexer = new EntityIndexerService(db.handle, entityStore, entitiesWatcher, ws, pluginHost, tagsService, rawReader);
251
+ const referencesService = new ReferencesService(pages, watcher);
252
+ const sectionsService = new SectionsService(db.handle);
253
+ sectionsService.setWriteDeps({ pages, watcher });
254
+ const planService = new PlanService(db.handle, ws, chatService);
255
+ const sectionIndexer = new SectionIndexerService(db.handle, pages, watcher, ws, pluginHost);
256
+ const todosIndexer = new TodosIndexerService(pages, ws);
257
+ const pagesLinkIndexer = new PagesLinkIndexerService(pages, ws);
258
+ // M17: page versioning (out of L9 plugin host — decyzja 1)
259
+ const pageSerializer = new PageSerializer(pages);
260
+ // M21 m02multidir: osobny serializer dla briefsDir (PageSerializer trzyma
261
+ // referencje do PagesService w konstruktorze — czyta z dysku przez nia).
262
+ // PageVersionService akceptuje override serializera w recordVersion(),
263
+ // wiec dwa serializery dziela jedna instancje wersjonowania.
264
+ const briefsSerializer = new PageSerializer(briefsPages);
265
+ // M23: serializer dla patchesDir (analogicznie do briefsSerializer).
266
+ const patchesSerializer = new PageSerializer(patchesPages);
267
+ const pageVersions = new PageVersionService(db.handle, pageSerializer);
268
+ // M21 m02fmidx / M23: in-memory frontmatter indexer feeded przez trzy watchery.
269
+ const pagesFrontmatterIndexer = new PagesFrontmatterIndexer(pages, briefsPages, patchesPages, ws);
270
+ // Mount all active backend modules — each plugin constructs its own service,
271
+ // mounts its router, registers its MCP server, and registers its entity
272
+ // service via the supplied MountContext. Inactive plugins are skipped
273
+ // (config.entities).
274
+ pluginHost.mountBackend({
275
+ app: router,
276
+ db: db.handle,
277
+ host: pluginHost,
278
+ cwd,
279
+ ws,
280
+ tagsService,
281
+ versionService,
282
+ referencesService,
283
+ entityStore,
284
+ registerMcpServer: (name, server) => pluginHost.registerMcpServer(name, server),
285
+ registerEntityService: (type, service) => pluginHost.registerEntityService(type, service),
286
+ });
287
+ // Cross-cutting MCP server — owned by the host, not a plugin (M13).
288
+ // Registered as a factory: a fresh instance is built per agent turn so
289
+ // concurrent turns never share one MCP transport.
290
+ pluginHost.registerMcpServer('reference-tools', () => createReferenceToolsServer({
291
+ pluginHost,
292
+ tagsService,
293
+ referencesService,
294
+ pagesService: pages,
295
+ sectionsService,
296
+ ws,
297
+ db: db.handle,
298
+ cwd,
299
+ entityStore,
300
+ }));
301
+ // M17: ReleaseService + cross-cutting `release-tools` MCP. Like
302
+ // reference-tools, owned by the host (not a plugin) — release semantics
303
+ // are dual-track (entities + pages), neither side is a plugin owner.
304
+ const releaseService = new ReleaseService(db.handle, pluginHost, versionService, pageVersions, pageSerializer, rawReader, tagsService, pages, watcher, cwd);
305
+ // M29: release restore must persist restored entities' files.
306
+ releaseService.setEntityStore(entityStore);
307
+ // M28 Git Sync — best-effort mirroring of release create/push into the user's
308
+ // git repo. Probes `pages.root` for the worktree; reads config per-action.
309
+ const gitService = new GitService(cwd, pages.root);
310
+ // M25 Release Push — coordinates M17 bundle build + M24 transport; owns release_push.
311
+ const releasePushService = new ReleasePushService(db.handle, releaseService, remoteAuthService, gitService, cwd);
312
+ pluginHost.registerMcpServer('release-tools', () => createReleaseToolsServer({ releaseService, gitService, ws }));
313
+ // M27 Project Clone — bootstrap-time only. Runs after services exist (DB
314
+ // migrated, plugin host mounted, pages root ensured) but BEFORE watchers start
315
+ // and before listen, so restore writes land without watcher double-capture.
316
+ if (deps.clone) {
317
+ const importService = new ReleaseImportService(db.handle, releaseService, remoteHttpClient, cwd);
318
+ try {
319
+ const result = await importService.clone(deps.clone.slug, { nameOverride: deps.clone.nameOverride });
320
+ console.log(` cloned remote project '${deps.clone.slug}' → local release #${result.localReleaseId ?? '?'}`);
321
+ }
322
+ catch (err) {
323
+ const code = err instanceof DomainError ? err.code : 'CLONE_FAILED';
324
+ console.error(`\x1b[31mclone failed\x1b[0m: ${code} — ${err instanceof Error ? err.message : String(err)}`);
325
+ // Full all-or-nothing rollback: cwd returns to its pre-`--clone` state. Close
326
+ // the DB handle first so db.sqlite can be unlinked (required on Windows).
327
+ db.close();
328
+ rollbackClone(cwd, {
329
+ pagesDir,
330
+ configCreated: deps.clone.configCreated,
331
+ claudeDirCreated: deps.clone.claudeDirCreated,
332
+ gitignoreCreated: deps.clone.gitignoreCreated,
333
+ dbSlotDir,
334
+ });
335
+ process.exit(1);
336
+ }
337
+ }
338
+ // M21: BriefService — top-level (nie plugin), wzorzec analogiczny do
339
+ // PlanService. Mountowany router /briefs poniżej.
340
+ const briefService = new BriefService({
341
+ briefsPages,
342
+ briefsWatcher,
343
+ briefsSerializer,
344
+ pageVersions,
345
+ chatService,
346
+ releaseService,
347
+ frontmatterIndexer: pagesFrontmatterIndexer,
348
+ ws,
349
+ });
350
+ // M23: PatchService — top-level (nie plugin), wzorzec analogiczny do
351
+ // BriefService. Mountowany router /patches poniżej.
352
+ const patchService = new PatchService({
353
+ patchesPages,
354
+ patchesWatcher,
355
+ patchesSerializer,
356
+ pageVersions,
357
+ chatService,
358
+ frontmatterIndexer: pagesFrontmatterIndexer,
359
+ });
360
+ // Per-context config/meta/writing-styles (carved out of startServer inline
361
+ // handlers — single response builder in routes/config.ts).
362
+ router.use(configRouter({
363
+ cwd,
364
+ skillRegistry,
365
+ onContextConfigChanged: deps.onContextConfigChanged,
366
+ onOnboardingCompleted: (effectivePagesDir) => ensureWelcomePage(cwd, effectivePagesDir),
367
+ }));
368
+ router.use(pluginHostRouter(pluginHost));
369
+ router.use('/pages', pagesRouter(pages, watcher, pageVersions));
370
+ router.use('/static', staticRouter(staticHtml));
371
+ router.use('/tags', tagsRouter(tagsService, referencesService));
372
+ router.use('/references', referencesRouter(pluginHost, referencesService));
373
+ router.use('/entities', entitiesRouter(pluginHost, tagsService, versionService, entityStore));
374
+ // 0.1.58: peer-discovery for the `<workspace_projects>` prompt block. For each
375
+ // workspace project except this one, build a PeerProject whose `path` is the
376
+ // registry `cwd` (passed 1:1 as the `project` param to `c4s-tools.ask`); name/
377
+ // description are lazily read from the peer's config.json (source of truth,
378
+ // no denormalization). Unreadable config → entry with `path` only. Re-read per
379
+ // turn so peer-config edits surface on the next thread's first turn.
380
+ const listWorkspacePeers = () => {
381
+ const ws = registry.getWorkspace(workspace.name);
382
+ if (!ws)
383
+ return [];
384
+ return ws.projects
385
+ .filter((p) => p.cwd !== cwd)
386
+ .map((p) => {
387
+ const peer = { path: p.cwd };
388
+ try {
389
+ const peerCfg = readConfig(p.cwd);
390
+ if (peerCfg.name)
391
+ peer.name = peerCfg.name;
392
+ if (peerCfg.description)
393
+ peer.description = peerCfg.description;
394
+ }
395
+ catch {
396
+ /* unreadable/missing config → path-only entry, not an error */
397
+ }
398
+ return peer;
399
+ });
400
+ };
401
+ // Wspolne deps tury agenta — `threadsRouter` (POST /:id/ask) i `chatRouter`
402
+ // (POST /chat, SSE) dziela ten sam runtime i rejestr `activeAdapters`.
403
+ const agentDeps = {
404
+ pluginHost,
405
+ activeAdapters,
406
+ pendingInputs,
407
+ onTurnFinished: deps.onTurnFinished,
408
+ chatService,
409
+ pagesService: pages,
410
+ tagsService,
411
+ sectionsService,
412
+ planService,
413
+ briefService,
414
+ patchService,
415
+ pageVersions,
416
+ skillResolver,
417
+ skillRegistry,
418
+ ws,
419
+ cwd,
420
+ pagesDir,
421
+ mode,
422
+ db,
423
+ workspaceName: workspace.name,
424
+ listWorkspacePeers,
425
+ };
426
+ router.use('/threads', threadsRouter(agentDeps));
427
+ router.use('/sections', sectionsRouter(sectionsService));
428
+ router.use('/todos', todosRouter(todosIndexer));
429
+ router.use('/page-links', pageLinksRouter(pagesLinkIndexer));
430
+ router.use('/plans', plansRouter(planService));
431
+ router.use('/releases', releasesRouter(releaseService, ws, gitService));
432
+ router.use('/release-pushes', releasePushesRouter(releasePushService));
433
+ router.use('/git', gitRouter(gitService));
434
+ router.use('/briefs', briefsRouter(briefService, pageVersions));
435
+ router.use('/patches', patchesRouter(patchService));
436
+ router.use('/remote-account', remoteAccountRouter(remoteAuthService));
437
+ router.use('/remote-project', remoteProjectRouter(remoteAuthService, cwd));
438
+ router.use('/chat', chatRouter(agentDeps));
439
+ router.use(errorHandler);
440
+ watcher.onChange((relPath, kind) => {
441
+ if (kind === 'unlink') {
442
+ sectionIndexer.handleUnlink(relPath).catch((err) => {
443
+ console.error('[section-indexer] unlink error:', err);
444
+ });
445
+ todosIndexer.handleUnlink(relPath);
446
+ pagesLinkIndexer.handleUnlink(relPath);
447
+ pagesFrontmatterIndexer.handleUnlink('pages', relPath);
448
+ // M17: capture filesystem-origin delete (chokidar saw external rm)
449
+ pageVersions.recordVersion(relPath, 'delete', 'filesystem').catch((err) => {
450
+ console.warn(`[page-version] watcher delete capture for ${relPath}:`, err.message);
451
+ });
452
+ }
453
+ else {
454
+ sectionIndexer.schedulePage(relPath);
455
+ todosIndexer.schedulePage(relPath);
456
+ pagesLinkIndexer.schedulePage(relPath);
457
+ pagesFrontmatterIndexer.schedulePage('pages', relPath);
458
+ // M17: capture filesystem-origin add/change. `kind === 'add'` may be a
459
+ // real new file (op=create) or a re-detection — pageVersions.hasAny
460
+ // distinguishes.
461
+ const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
462
+ pageVersions.recordVersion(relPath, op, 'filesystem').catch((err) => {
463
+ console.warn(`[page-version] watcher capture for ${relPath}:`, err.message);
464
+ });
465
+ }
466
+ });
467
+ // M21 m02multidir: drugi watcher dla briefsDir. Tylko frontmatter indexer
468
+ // + page_version (z dedykowanym briefsSerializer). Section/todos/pages-link
469
+ // indexery NIE pracuja na briefsDir (briefs to nie pages w sensie M02 →
470
+ // nie czesc nawigowalnego drzewa, nie agreguja section_ref/todo'ow do tabel).
471
+ briefsWatcher.onChange((relPath, kind) => {
472
+ if (kind === 'unlink') {
473
+ pagesFrontmatterIndexer.handleUnlink('briefs', relPath);
474
+ pageVersions.recordVersion(relPath, 'delete', 'filesystem', undefined, briefsSerializer, 'brief').catch((err) => {
475
+ console.warn(`[page-version] brief delete capture for ${relPath}:`, err.message);
476
+ });
477
+ }
478
+ else {
479
+ pagesFrontmatterIndexer.schedulePage('briefs', relPath);
480
+ const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
481
+ pageVersions.recordVersion(relPath, op, 'filesystem', undefined, briefsSerializer, 'brief').catch((err) => {
482
+ console.warn(`[page-version] brief capture for ${relPath}:`, err.message);
483
+ });
484
+ // Direct disk edit (not suppressed): refresh open BriefEditors. The indexer
485
+ // only fires `briefs:changed` on frontmatter changes, so body-only edits
486
+ // need this explicit broadcast. `external` → reload-or-confirm like Pages.
487
+ ws.broadcast({ kind: 'briefs:changed', path: relPath, origin: 'external' });
488
+ }
489
+ });
490
+ // M23: trzeci watcher dla patchesDir — analogicznie do briefsWatcher.
491
+ patchesWatcher.onChange((relPath, kind) => {
492
+ if (kind === 'unlink') {
493
+ pagesFrontmatterIndexer.handleUnlink('patches', relPath);
494
+ pageVersions.recordVersion(relPath, 'delete', 'filesystem', undefined, patchesSerializer, 'patch').catch((err) => {
495
+ console.warn(`[page-version] patch delete capture for ${relPath}:`, err.message);
496
+ });
497
+ }
498
+ else {
499
+ pagesFrontmatterIndexer.schedulePage('patches', relPath);
500
+ const op = kind === 'add' && !pageVersions.hasAny(relPath) ? 'create' : 'update';
501
+ pageVersions.recordVersion(relPath, op, 'filesystem', undefined, patchesSerializer, 'patch').catch((err) => {
502
+ console.warn(`[page-version] patch capture for ${relPath}:`, err.message);
503
+ });
504
+ }
505
+ });
506
+ // M29: external edits / git pull of entity files → incremental reindex.
507
+ entitiesWatcher.onChange((relPath, kind) => {
508
+ if (kind === 'unlink') {
509
+ entityIndexer.handleUnlink(relPath).catch((err) => {
510
+ console.error(`[entity-indexer] unlink ${relPath}:`, err);
511
+ });
512
+ }
513
+ else {
514
+ entityIndexer.schedulePage(relPath);
515
+ }
516
+ });
517
+ watcher.start();
518
+ briefsWatcher.start();
519
+ patchesWatcher.start();
520
+ sectionIndexer.indexAll().catch((err) => {
521
+ console.error('[section-indexer] initial indexAll failed:', err);
522
+ });
523
+ todosIndexer.indexAll().catch((err) => {
524
+ console.error('[todos-indexer] initial indexAll failed:', err);
525
+ });
526
+ pagesLinkIndexer.indexAll().catch((err) => {
527
+ console.error('[pages-link-indexer] initial indexAll failed:', err);
528
+ });
529
+ // M17: initial sync of page_version. For each markdown file with no captured
530
+ // version — or whose latest captured version is a `delete` tombstone while the
531
+ // file is back on disk — write an `op = 'create'` baseline. The latter case
532
+ // covers delete+recreate that happened while the server wasn't watching
533
+ // (server down, `git checkout` between restarts): without this, the phantom
534
+ // `delete` stays the latest row and release diffs show the page as removed.
535
+ (async () => {
536
+ try {
537
+ const files = await pages.listMarkdownFiles();
538
+ for (const relPath of files) {
539
+ const latest = pageVersions.getLatestForPath(relPath);
540
+ if (latest && latest.op !== 'delete')
541
+ continue;
542
+ await pageVersions.recordVersion(relPath, 'create', 'filesystem');
543
+ }
544
+ }
545
+ catch (err) {
546
+ console.warn('[page-version] initial sync failed:', err.message);
547
+ }
548
+ })();
549
+ // M21: initial sync — page_version baseline dla briefów + frontmatter indexer.
550
+ (async () => {
551
+ try {
552
+ const files = await briefsPages.listMarkdownFiles();
553
+ for (const relPath of files) {
554
+ if (pageVersions.hasAny(relPath))
555
+ continue;
556
+ await pageVersions.recordVersion(relPath, 'create', 'filesystem', undefined, briefsSerializer, 'brief');
557
+ }
558
+ }
559
+ catch (err) {
560
+ console.warn('[page-version] briefs initial sync failed:', err.message);
561
+ }
562
+ // M23: initial sync — page_version baseline dla patchy.
563
+ try {
564
+ const files = await patchesPages.listMarkdownFiles();
565
+ for (const relPath of files) {
566
+ if (pageVersions.hasAny(relPath))
567
+ continue;
568
+ await pageVersions.recordVersion(relPath, 'create', 'filesystem', undefined, patchesSerializer, 'patch');
569
+ }
570
+ }
571
+ catch (err) {
572
+ console.warn('[page-version] patches initial sync failed:', err.message);
573
+ }
574
+ try {
575
+ await pagesFrontmatterIndexer.indexAll();
576
+ }
577
+ catch (err) {
578
+ console.warn('[pages-frontmatter-indexer] initial sync failed:', err.message);
579
+ }
580
+ })();
581
+ // M29: entity store boot. (1) one-time DB→text export for pre-M29 projects
582
+ // whose entities live only in SQLite; (2) rebuild the derived index from the
583
+ // committed files. Awaited BEFORE the context serves — the app is
584
+ // entity-centric, so serving REST/MCP before the index is ready would 404 /
585
+ // return empty.
586
+ try {
587
+ const fileEntityCount = entityStore.listAll().length;
588
+ const hasTagsFile = entityStore.readTags().length > 0;
589
+ const dbEntityCount = rawReader
590
+ .listTypes()
591
+ .filter((t) => pluginHost.getEntity(t))
592
+ .reduce((n, t) => n + rawReader.listSlugs(t).length, 0);
593
+ const filesPresent = fileEntityCount > 0 || hasTagsFile;
594
+ if (!filesPresent && dbEntityCount > 0) {
595
+ // Pre-M29 project: entities live only in SQLite → export to text once.
596
+ console.log(`[m29] exporting ${dbEntityCount} entities DB→text into ${entitiesDir} ...`);
597
+ backupDbBeforeMigration(dbSlotDir);
598
+ for (const type of rawReader.listTypes()) {
599
+ if (!pluginHost.getEntity(type))
600
+ continue;
601
+ for (const slug of rawReader.listSlugs(type))
602
+ entityStore.persist(type, slug);
603
+ }
604
+ entityStore.persistTags();
605
+ }
606
+ else if (filesPresent && dbEntityCount > 0 && fileEntityCount !== dbEntityCount) {
607
+ // Edge (brief migrt001 §3): committed files differ from a non-empty DB
608
+ // (e.g. a git pull dropped/added entities). Files win on rebuild — back up
609
+ // the derived DB first so the prior index is recoverable.
610
+ console.warn(`[m29] entity file count (${fileEntityCount}) != DB count (${dbEntityCount}); rebuilding from files (db backed up)`);
611
+ backupDbBeforeMigration(dbSlotDir);
612
+ }
613
+ await entityIndexer.indexAll();
614
+ }
615
+ catch (err) {
616
+ console.error('[entity-indexer] boot indexAll failed:', err);
617
+ }
618
+ // M29: enable tags.json persistence only AFTER the boot rebuild, so any
619
+ // auto-created tag during indexAll does not write files mid-rebuild.
620
+ tagsService.setEntityStore(entityStore);
621
+ // M29: enable slug-rename propagation into entity files (dto→endpoint
622
+ // linked_dtos, *→ac verifies). After indexAll so the index is consistent.
623
+ referencesService.setEntityDeps(db.handle, entityStore);
624
+ // Start the entities watcher only after the boot export/rebuild, so bulk
625
+ // self-writes during export never race a live reindex.
626
+ entitiesWatcher.start();
627
+ const writingStyle = initialWritingStyle
628
+ ? { slug: initialWritingStyle, title: skillRegistry.resolve(initialWritingStyle).metadata.title }
629
+ : null;
630
+ return {
631
+ projectId,
632
+ cwd,
633
+ workspace,
634
+ router,
635
+ db,
636
+ pluginHost,
637
+ serialization: new SerializationEngine(pluginHost, sectionSerializer),
638
+ ws,
639
+ activeAdapters,
640
+ pendingInputs,
641
+ writingStyle,
642
+ hasInFlightTurn: () => activeAdapters.size > 0,
643
+ // M31 dispose sequence: watchers → MCP factories → room → db handle.
644
+ dispose: async () => {
645
+ await watcher.close();
646
+ await briefsWatcher.close();
647
+ await patchesWatcher.close();
648
+ await entitiesWatcher.close();
649
+ pluginHost.clearMcpFactories();
650
+ gateway.closeRoom(projectId);
651
+ db.close();
652
+ },
653
+ };
654
+ }
655
+ //# sourceMappingURL=project-context.js.map