@piecemaker-legal/piecemaker 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 (1424) hide show
  1. package/LICENSE +718 -0
  2. package/README.md +80 -0
  3. package/dist/Mistral-Icon-Gradient-RGB.svg +12 -0
  4. package/dist/api-docs.html +901 -0
  5. package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
  6. package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
  7. package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
  8. package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
  9. package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
  10. package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
  11. package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
  12. package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
  13. package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
  14. package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
  15. package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
  16. package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
  17. package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
  18. package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
  19. package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
  20. package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
  21. package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
  22. package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
  23. package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
  24. package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
  25. package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
  26. package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
  27. package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
  28. package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
  29. package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
  30. package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
  31. package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
  32. package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
  33. package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
  34. package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
  35. package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
  36. package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
  37. package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
  38. package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
  39. package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
  40. package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
  41. package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
  42. package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
  43. package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
  44. package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
  45. package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
  46. package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
  47. package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
  48. package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
  49. package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
  50. package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
  51. package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
  52. package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
  53. package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
  54. package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
  55. package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
  56. package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
  57. package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
  58. package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
  59. package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
  60. package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
  61. package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
  62. package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
  63. package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
  64. package/dist/assets/abnfDiagram-N423BO3Z-DjEx6DRO.js +1 -0
  65. package/dist/assets/arc-DYt0oU_6.js +1 -0
  66. package/dist/assets/architectureDiagram-T3A2C74G-Dn6DhYDe.js +36 -0
  67. package/dist/assets/blockDiagram-VBNYF7ZC-CsvhTLZi.js +132 -0
  68. package/dist/assets/c4Diagram-5PPSVZJV-BuPnjHm6.js +10 -0
  69. package/dist/assets/channel-Czt0N91A.js +1 -0
  70. package/dist/assets/chunk-2GRJ4B5K-BZJJc1-J.js +1 -0
  71. package/dist/assets/chunk-2Q5K7J3B-6stdrDbe.js +1 -0
  72. package/dist/assets/chunk-5RXB4S5H-D5UwN5cg.js +231 -0
  73. package/dist/assets/chunk-5VM5RSS4-BDB8AQ_I.js +15 -0
  74. package/dist/assets/chunk-6Q2QTUOP-RhjQ-NDz.js +88 -0
  75. package/dist/assets/chunk-GF5L2VYU-CJuiA7R4.js +206 -0
  76. package/dist/assets/chunk-JWPE2WC7-DjFkIZqh.js +1 -0
  77. package/dist/assets/chunk-KBJHAD2P-BeSQsoqv.js +1 -0
  78. package/dist/assets/chunk-RYQCIY6F-CPgwsb0o.js +1 -0
  79. package/dist/assets/chunk-XXDRQBXY-CMMVEsX3.js +1 -0
  80. package/dist/assets/classDiagram-JCYQIIEL-BrnQyrwR.js +1 -0
  81. package/dist/assets/classDiagram-v2-OCEON4UE-BrnQyrwR.js +1 -0
  82. package/dist/assets/cose-bilkent-JH36ORCC-XAdYMfi5.js +1 -0
  83. package/dist/assets/cynefin-VYW2F7L2-d2GpDBn-.js +178 -0
  84. package/dist/assets/cynefinDiagram-MW4NZA55-CGtqUrU1.js +62 -0
  85. package/dist/assets/cytoscape.esm-C10L9Icf.js +331 -0
  86. package/dist/assets/dagre-VZM6K2ZE-BxujKIsf.js +4 -0
  87. package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
  88. package/dist/assets/diagram-7IWD3JNH-CJn9hobL.js +30 -0
  89. package/dist/assets/diagram-B4RE2ZJO-DF0Cnjzz.js +3 -0
  90. package/dist/assets/diagram-LBJQPF4R-Bq4d3NfR.js +24 -0
  91. package/dist/assets/diagram-Q27KOJAE-DDdfoXt-.js +24 -0
  92. package/dist/assets/diagram-UB23O5K3-TSFk7FuJ.js +41 -0
  93. package/dist/assets/ebnfDiagram-BXEA7PRR-DRvm2Wy9.js +1 -0
  94. package/dist/assets/erDiagram-JOGREHBK-BmdN66-A.js +85 -0
  95. package/dist/assets/flowDiagram-UKHOOZJN-Dsp5LwJz.js +156 -0
  96. package/dist/assets/ganttDiagram-PKOTCBZU-CYfCQ4Yi.js +292 -0
  97. package/dist/assets/gitGraphDiagram-DS77QQ5N-DEzmuv8v.js +106 -0
  98. package/dist/assets/graph-Cx-EqisW.js +1 -0
  99. package/dist/assets/index-CqFxV_pT.css +32 -0
  100. package/dist/assets/index-dWwHeqcq.js +4989 -0
  101. package/dist/assets/infoDiagram-6WML65LV-B1EfV5Bm.js +2 -0
  102. package/dist/assets/init-Gi6I4Gst.js +1 -0
  103. package/dist/assets/ishikawaDiagram-WSZJBQD7-OuQJfUii.js +70 -0
  104. package/dist/assets/journeyDiagram-NVQOT4AX-DHIilb_4.js +139 -0
  105. package/dist/assets/kanban-definition-27J2QSJJ-D4CvKWBP.js +89 -0
  106. package/dist/assets/layout-D6BstSzF.js +1 -0
  107. package/dist/assets/linear-i_Nzyzap.js +1 -0
  108. package/dist/assets/map-CV9uif0g.js +1 -0
  109. package/dist/assets/mermaid.core-DbSHejzG.js +312 -0
  110. package/dist/assets/mindmap-definition-FAOFIHXS-DqhC-BPZ.js +96 -0
  111. package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
  112. package/dist/assets/pegDiagram-VL7TDLO6-pBqvOEvm.js +1 -0
  113. package/dist/assets/pieDiagram-7S7Q4E2Y-BH53iuaz.js +39 -0
  114. package/dist/assets/quadrantDiagram-CIZ2JOQS-CvW9ldJo.js +7 -0
  115. package/dist/assets/railroadDiagram-AXF67PYL-CERi66oR.js +1 -0
  116. package/dist/assets/requirementDiagram-LRYGKXZP-DbcP4MGI.js +84 -0
  117. package/dist/assets/sankeyDiagram-W5VNT64P-DO9bPHWO.js +40 -0
  118. package/dist/assets/sequenceDiagram-SI44F4Z6-D3zd2eJS.js +162 -0
  119. package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
  120. package/dist/assets/sizeCapture-X5ZJPWSS-mcEXJiem.js +1 -0
  121. package/dist/assets/stateDiagram-OKZ733FA-DMqQgpiD.js +1 -0
  122. package/dist/assets/stateDiagram-v2-UEYNNEHI-DprF_P9y.js +1 -0
  123. package/dist/assets/swimlanes-SLNWSIFB-Cb8rIhB1.js +2 -0
  124. package/dist/assets/swimlanesDiagram-ULZ7WXOC-C6NVYMho.js +8 -0
  125. package/dist/assets/timeline-definition-Z64GVDOM-BQ4r_QsK.js +120 -0
  126. package/dist/assets/vendor-codemirror-CYrSt7-U.js +41 -0
  127. package/dist/assets/vendor-react-BGZc9oRE.js +59 -0
  128. package/dist/assets/vendor-xterm-CS4rQ5Mr.js +66 -0
  129. package/dist/assets/vennDiagram-T6HMQDX7-BEkKGTum.js +34 -0
  130. package/dist/assets/wardleyDiagram-T6FBY63Y-kJwmgH-h.js +78 -0
  131. package/dist/assets/xychartDiagram-ELKLHX3M-CSJRTKCr.js +7 -0
  132. package/dist/clear-cache.html +85 -0
  133. package/dist/convert-icons.md +53 -0
  134. package/dist/favicon.png +0 -0
  135. package/dist/favicon.svg +9 -0
  136. package/dist/generate-icons.js +49 -0
  137. package/dist/icons/claude-ai-icon.svg +1 -0
  138. package/dist/icons/codex-white.svg +3 -0
  139. package/dist/icons/codex.svg +3 -0
  140. package/dist/icons/cursor-white.svg +12 -0
  141. package/dist/icons/cursor.svg +1 -0
  142. package/dist/icons/icon-128x128.png +0 -0
  143. package/dist/icons/icon-128x128.svg +12 -0
  144. package/dist/icons/icon-144x144.png +0 -0
  145. package/dist/icons/icon-144x144.svg +12 -0
  146. package/dist/icons/icon-152x152.png +0 -0
  147. package/dist/icons/icon-152x152.svg +12 -0
  148. package/dist/icons/icon-192x192.png +0 -0
  149. package/dist/icons/icon-192x192.svg +12 -0
  150. package/dist/icons/icon-384x384.png +0 -0
  151. package/dist/icons/icon-384x384.svg +12 -0
  152. package/dist/icons/icon-512x512.png +0 -0
  153. package/dist/icons/icon-512x512.svg +12 -0
  154. package/dist/icons/icon-72x72.png +0 -0
  155. package/dist/icons/icon-72x72.svg +12 -0
  156. package/dist/icons/icon-96x96.png +0 -0
  157. package/dist/icons/icon-96x96.svg +12 -0
  158. package/dist/icons/icon-template.svg +12 -0
  159. package/dist/index.html +60 -0
  160. package/dist/logo-128.png +0 -0
  161. package/dist/logo-256.png +0 -0
  162. package/dist/logo-32.png +0 -0
  163. package/dist/logo-512.png +0 -0
  164. package/dist/logo-64.png +0 -0
  165. package/dist/logo.svg +17 -0
  166. package/dist/manifest.json +61 -0
  167. package/dist/screenshots/cli-selection.png +0 -0
  168. package/dist/screenshots/desktop-main.png +0 -0
  169. package/dist/screenshots/mobile-chat.png +0 -0
  170. package/dist/screenshots/tools-modal.png +0 -0
  171. package/dist/sw.js +125 -0
  172. package/dist-server/server/index.js +345 -0
  173. package/dist-server/server/index.js.map +1 -0
  174. package/dist-server/server/load-env.js +46 -0
  175. package/dist-server/server/load-env.js.map +1 -0
  176. package/dist-server/server/modules/agent/agent.module.js +38 -0
  177. package/dist-server/server/modules/agent/agent.module.js.map +1 -0
  178. package/dist-server/server/modules/agent/agent.routes.js +1161 -0
  179. package/dist-server/server/modules/agent/agent.routes.js.map +1 -0
  180. package/dist-server/server/modules/agent/index.js +3 -0
  181. package/dist-server/server/modules/agent/index.js.map +1 -0
  182. package/dist-server/server/modules/agent/tests/agent.routes.test.js +176 -0
  183. package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -0
  184. package/dist-server/server/modules/assets/assets.routes.js +130 -0
  185. package/dist-server/server/modules/assets/assets.routes.js.map +1 -0
  186. package/dist-server/server/modules/assets/index.js +4 -0
  187. package/dist-server/server/modules/assets/index.js.map +1 -0
  188. package/dist-server/server/modules/assets/services/image-assets.service.js +95 -0
  189. package/dist-server/server/modules/assets/services/image-assets.service.js.map +1 -0
  190. package/dist-server/server/modules/assets/tests/image-assets.service.test.js +56 -0
  191. package/dist-server/server/modules/assets/tests/image-assets.service.test.js.map +1 -0
  192. package/dist-server/server/modules/auth/auth.middleware.js +133 -0
  193. package/dist-server/server/modules/auth/auth.middleware.js.map +1 -0
  194. package/dist-server/server/modules/auth/auth.module.js +29 -0
  195. package/dist-server/server/modules/auth/auth.module.js.map +1 -0
  196. package/dist-server/server/modules/auth/auth.routes.js +45 -0
  197. package/dist-server/server/modules/auth/auth.routes.js.map +1 -0
  198. package/dist-server/server/modules/auth/auth.service.js +113 -0
  199. package/dist-server/server/modules/auth/auth.service.js.map +1 -0
  200. package/dist-server/server/modules/auth/index.js +9 -0
  201. package/dist-server/server/modules/auth/index.js.map +1 -0
  202. package/dist-server/server/modules/auth/tests/auth.service.test.js +80 -0
  203. package/dist-server/server/modules/auth/tests/auth.service.test.js.map +1 -0
  204. package/dist-server/server/modules/browser-use/browser-use-mcp.js +352 -0
  205. package/dist-server/server/modules/browser-use/browser-use-mcp.js.map +1 -0
  206. package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js +107 -0
  207. package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js.map +1 -0
  208. package/dist-server/server/modules/browser-use/browser-use-runtime.js +10 -0
  209. package/dist-server/server/modules/browser-use/browser-use-runtime.js.map +1 -0
  210. package/dist-server/server/modules/browser-use/browser-use.routes.js +93 -0
  211. package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -0
  212. package/dist-server/server/modules/browser-use/browser-use.service.js +686 -0
  213. package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -0
  214. package/dist-server/server/modules/browser-use/index.js +11 -0
  215. package/dist-server/server/modules/browser-use/index.js.map +1 -0
  216. package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js +8 -0
  217. package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js.map +1 -0
  218. package/dist-server/server/modules/cli/cli.js +17 -0
  219. package/dist-server/server/modules/cli/cli.js.map +1 -0
  220. package/dist-server/server/modules/cli/cli.module.js +93 -0
  221. package/dist-server/server/modules/cli/cli.module.js.map +1 -0
  222. package/dist-server/server/modules/cli/cli.service.js +230 -0
  223. package/dist-server/server/modules/cli/cli.service.js.map +1 -0
  224. package/dist-server/server/modules/cli/index.js +3 -0
  225. package/dist-server/server/modules/cli/index.js.map +1 -0
  226. package/dist-server/server/modules/cli/pwa-launcher.js +116 -0
  227. package/dist-server/server/modules/cli/pwa-launcher.js.map +1 -0
  228. package/dist-server/server/modules/cli/sandbox.service.js +332 -0
  229. package/dist-server/server/modules/cli/sandbox.service.js.map +1 -0
  230. package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +154 -0
  231. package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js.map +1 -0
  232. package/dist-server/server/modules/cli/tests/cli.service.test.js +91 -0
  233. package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -0
  234. package/dist-server/server/modules/cli/tests/sandbox.service.test.js +55 -0
  235. package/dist-server/server/modules/cli/tests/sandbox.service.test.js.map +1 -0
  236. package/dist-server/server/modules/commands/commands.module.js +20 -0
  237. package/dist-server/server/modules/commands/commands.module.js.map +1 -0
  238. package/dist-server/server/modules/commands/commands.routes.js +498 -0
  239. package/dist-server/server/modules/commands/commands.routes.js.map +1 -0
  240. package/dist-server/server/modules/commands/index.js +3 -0
  241. package/dist-server/server/modules/commands/index.js.map +1 -0
  242. package/dist-server/server/modules/commands/tests/commands.test.js +91 -0
  243. package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -0
  244. package/dist-server/server/modules/database/connection.js +125 -0
  245. package/dist-server/server/modules/database/connection.js.map +1 -0
  246. package/dist-server/server/modules/database/index.js +23 -0
  247. package/dist-server/server/modules/database/index.js.map +1 -0
  248. package/dist-server/server/modules/database/init-db.js +18 -0
  249. package/dist-server/server/modules/database/init-db.js.map +1 -0
  250. package/dist-server/server/modules/database/migrations.js +465 -0
  251. package/dist-server/server/modules/database/migrations.js.map +1 -0
  252. package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
  253. package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
  254. package/dist-server/server/modules/database/repositories/app-config.js +47 -0
  255. package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
  256. package/dist-server/server/modules/database/repositories/credentials.js +68 -0
  257. package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
  258. package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
  259. package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
  260. package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js +100 -0
  261. package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js.map +1 -0
  262. package/dist-server/server/modules/database/repositories/notification-preferences.js +82 -0
  263. package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
  264. package/dist-server/server/modules/database/repositories/projects.db.js +172 -0
  265. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
  266. package/dist-server/server/modules/database/repositories/provider-models.js +112 -0
  267. package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -0
  268. package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
  269. package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
  270. package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
  271. package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
  272. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
  273. package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
  274. package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
  275. package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
  276. package/dist-server/server/modules/database/repositories/sessions.db.js +507 -0
  277. package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
  278. package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
  279. package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
  280. package/dist-server/server/modules/database/repositories/users.js +88 -0
  281. package/dist-server/server/modules/database/repositories/users.js.map +1 -0
  282. package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
  283. package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
  284. package/dist-server/server/modules/database/schema.js +291 -0
  285. package/dist-server/server/modules/database/schema.js.map +1 -0
  286. package/dist-server/server/modules/database/tests/projects.db.integration.test.js +64 -0
  287. package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -0
  288. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +102 -0
  289. package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -0
  290. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +79 -0
  291. package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -0
  292. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +93 -0
  293. package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -0
  294. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
  295. package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
  296. package/dist-server/server/modules/file-tree/file-tree.module.js +95 -0
  297. package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -0
  298. package/dist-server/server/modules/file-tree/file-tree.routes.js +208 -0
  299. package/dist-server/server/modules/file-tree/file-tree.routes.js.map +1 -0
  300. package/dist-server/server/modules/file-tree/file-tree.service.js +584 -0
  301. package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -0
  302. package/dist-server/server/modules/file-tree/index.js +3 -0
  303. package/dist-server/server/modules/file-tree/index.js.map +1 -0
  304. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js +123 -0
  305. package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js.map +1 -0
  306. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +311 -0
  307. package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -0
  308. package/dist-server/server/modules/git/git-branch.service.js +15 -0
  309. package/dist-server/server/modules/git/git-branch.service.js.map +1 -0
  310. package/dist-server/server/modules/git/git-parsing.service.js +61 -0
  311. package/dist-server/server/modules/git/git-parsing.service.js.map +1 -0
  312. package/dist-server/server/modules/git/git.module.js +14 -0
  313. package/dist-server/server/modules/git/git.module.js.map +1 -0
  314. package/dist-server/server/modules/git/git.routes.js +1347 -0
  315. package/dist-server/server/modules/git/git.routes.js.map +1 -0
  316. package/dist-server/server/modules/git/index.js +3 -0
  317. package/dist-server/server/modules/git/index.js.map +1 -0
  318. package/dist-server/server/modules/git/tests/git-branch.service.test.js +52 -0
  319. package/dist-server/server/modules/git/tests/git-branch.service.test.js.map +1 -0
  320. package/dist-server/server/modules/git/tests/git-init.routes.test.js +132 -0
  321. package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -0
  322. package/dist-server/server/modules/git/tests/git.test.js +80 -0
  323. package/dist-server/server/modules/git/tests/git.test.js.map +1 -0
  324. package/dist-server/server/modules/notifications/index.js +20 -0
  325. package/dist-server/server/modules/notifications/index.js.map +1 -0
  326. package/dist-server/server/modules/notifications/notifications.routes.js +115 -0
  327. package/dist-server/server/modules/notifications/notifications.routes.js.map +1 -0
  328. package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js +97 -0
  329. package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js.map +1 -0
  330. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +249 -0
  331. package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -0
  332. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js +44 -0
  333. package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js.map +1 -0
  334. package/dist-server/server/modules/notifications/vapid-keys.service.js +28 -0
  335. package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -0
  336. package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js +79 -0
  337. package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js.map +1 -0
  338. package/dist-server/server/modules/plugins/index.js +9 -0
  339. package/dist-server/server/modules/plugins/index.js.map +1 -0
  340. package/dist-server/server/modules/plugins/plugin-process.service.js +191 -0
  341. package/dist-server/server/modules/plugins/plugin-process.service.js.map +1 -0
  342. package/dist-server/server/modules/plugins/plugin-registry.service.js +415 -0
  343. package/dist-server/server/modules/plugins/plugin-registry.service.js.map +1 -0
  344. package/dist-server/server/modules/plugins/plugins.module.js +30 -0
  345. package/dist-server/server/modules/plugins/plugins.module.js.map +1 -0
  346. package/dist-server/server/modules/plugins/plugins.routes.js +70 -0
  347. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -0
  348. package/dist-server/server/modules/plugins/plugins.service.js +123 -0
  349. package/dist-server/server/modules/plugins/plugins.service.js.map +1 -0
  350. package/dist-server/server/modules/plugins/tests/plugins.service.test.js +28 -0
  351. package/dist-server/server/modules/plugins/tests/plugins.service.test.js.map +1 -0
  352. package/dist-server/server/modules/projects/index.js +9 -0
  353. package/dist-server/server/modules/projects/index.js.map +1 -0
  354. package/dist-server/server/modules/projects/projects.routes.js +205 -0
  355. package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
  356. package/dist-server/server/modules/projects/services/project-clone.service.js +220 -0
  357. package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
  358. package/dist-server/server/modules/projects/services/project-delete.service.js +89 -0
  359. package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
  360. package/dist-server/server/modules/projects/services/project-management.service.js +90 -0
  361. package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
  362. package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
  363. package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
  364. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +167 -0
  365. package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
  366. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +188 -0
  367. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
  368. package/dist-server/server/modules/projects/tests/project-clone.service.test.js +126 -0
  369. package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
  370. package/dist-server/server/modules/projects/tests/project-management.service.test.js +85 -0
  371. package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
  372. package/dist-server/server/modules/projects/tests/project-star.service.test.js +95 -0
  373. package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
  374. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +87 -0
  375. package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
  376. package/dist-server/server/modules/providers/index.js +12 -0
  377. package/dist-server/server/modules/providers/index.js.map +1 -0
  378. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +151 -0
  379. package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
  380. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
  381. package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
  382. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
  383. package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
  384. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +267 -0
  385. package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -0
  386. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +1058 -0
  387. package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -0
  388. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +141 -0
  389. package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
  390. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +924 -0
  391. package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
  392. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +205 -0
  393. package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
  394. package/dist-server/server/modules/providers/list/claude/claude.provider.js +23 -0
  395. package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
  396. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
  397. package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
  398. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
  399. package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
  400. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
  401. package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
  402. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
  403. package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
  404. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +109 -0
  405. package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -0
  406. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +498 -0
  407. package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -0
  408. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +153 -0
  409. package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
  410. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1955 -0
  411. package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
  412. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +62 -0
  413. package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
  414. package/dist-server/server/modules/providers/list/codex/codex.provider.js +23 -0
  415. package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
  416. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
  417. package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
  418. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
  419. package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
  420. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +100 -0
  421. package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -0
  422. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +305 -0
  423. package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -0
  424. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +111 -0
  425. package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
  426. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +566 -0
  427. package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
  428. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +35 -0
  429. package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
  430. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +21 -0
  431. package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
  432. package/dist-server/server/modules/providers/list/mistral/mistral-auth.provider.js +147 -0
  433. package/dist-server/server/modules/providers/list/mistral/mistral-auth.provider.js.map +1 -0
  434. package/dist-server/server/modules/providers/list/mistral/mistral-mcp.provider.js +15 -0
  435. package/dist-server/server/modules/providers/list/mistral/mistral-mcp.provider.js.map +1 -0
  436. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +69 -0
  437. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -0
  438. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +326 -0
  439. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -0
  440. package/dist-server/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.js +12 -0
  441. package/dist-server/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.js.map +1 -0
  442. package/dist-server/server/modules/providers/list/mistral/mistral-sessions.provider.js +180 -0
  443. package/dist-server/server/modules/providers/list/mistral/mistral-sessions.provider.js.map +1 -0
  444. package/dist-server/server/modules/providers/list/mistral/mistral-skills.provider.js +15 -0
  445. package/dist-server/server/modules/providers/list/mistral/mistral-skills.provider.js.map +1 -0
  446. package/dist-server/server/modules/providers/list/mistral/mistral.provider.js +25 -0
  447. package/dist-server/server/modules/providers/list/mistral/mistral.provider.js.map +1 -0
  448. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +91 -0
  449. package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -0
  450. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js +181 -0
  451. package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js.map +1 -0
  452. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +257 -0
  453. package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -0
  454. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +368 -0
  455. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -0
  456. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +225 -0
  457. package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js.map +1 -0
  458. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +136 -0
  459. package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -0
  460. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +404 -0
  461. package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -0
  462. package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js +62 -0
  463. package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js.map +1 -0
  464. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +21 -0
  465. package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -0
  466. package/dist-server/server/modules/providers/provider.registry.js +33 -0
  467. package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
  468. package/dist-server/server/modules/providers/provider.routes.js +676 -0
  469. package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
  470. package/dist-server/server/modules/providers/services/mcp.service.js +84 -0
  471. package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
  472. package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
  473. package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
  474. package/dist-server/server/modules/providers/services/provider-capabilities.service.js +94 -0
  475. package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -0
  476. package/dist-server/server/modules/providers/services/provider-models.service.js +289 -0
  477. package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -0
  478. package/dist-server/server/modules/providers/services/provider-runtime.service.js +66 -0
  479. package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -0
  480. package/dist-server/server/modules/providers/services/provider-token-usage.service.js +372 -0
  481. package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -0
  482. package/dist-server/server/modules/providers/services/session-conversations-search.service.js +974 -0
  483. package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
  484. package/dist-server/server/modules/providers/services/session-history-cache.service.js +87 -0
  485. package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
  486. package/dist-server/server/modules/providers/services/session-synchronizer.service.js +130 -0
  487. package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
  488. package/dist-server/server/modules/providers/services/sessions-watcher.service.js +214 -0
  489. package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
  490. package/dist-server/server/modules/providers/services/sessions.service.js +519 -0
  491. package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
  492. package/dist-server/server/modules/providers/services/skills.service.js +22 -0
  493. package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
  494. package/dist-server/server/modules/providers/shared/base/abstract.provider.js +13 -0
  495. package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
  496. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
  497. package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
  498. package/dist-server/server/modules/providers/shared/skills/skills.provider.js +207 -0
  499. package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
  500. package/dist-server/server/modules/providers/tests/claude-auth.test.js +174 -0
  501. package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -0
  502. package/dist-server/server/modules/providers/tests/claude-sessions.test.js +470 -0
  503. package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -0
  504. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
  505. package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
  506. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
  507. package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
  508. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
  509. package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
  510. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
  511. package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
  512. package/dist-server/server/modules/providers/tests/codex-sessions.test.js +491 -0
  513. package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -0
  514. package/dist-server/server/modules/providers/tests/mcp.test.js +291 -0
  515. package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
  516. package/dist-server/server/modules/providers/tests/opencode-models.test.js +103 -0
  517. package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -0
  518. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +424 -0
  519. package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -0
  520. package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js +205 -0
  521. package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js.map +1 -0
  522. package/dist-server/server/modules/providers/tests/provider-models.service.test.js +268 -0
  523. package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -0
  524. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +126 -0
  525. package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -0
  526. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +329 -0
  527. package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -0
  528. package/dist-server/server/modules/providers/tests/provider.routes.test.js +161 -0
  529. package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -0
  530. package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
  531. package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
  532. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +120 -0
  533. package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
  534. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
  535. package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
  536. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
  537. package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
  538. package/dist-server/server/modules/providers/tests/sessions-details.test.js +62 -0
  539. package/dist-server/server/modules/providers/tests/sessions-details.test.js.map +1 -0
  540. package/dist-server/server/modules/providers/tests/sessions.service.test.js +131 -0
  541. package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -0
  542. package/dist-server/server/modules/providers/tests/skills.test.js +398 -0
  543. package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
  544. package/dist-server/server/modules/scheduled-messages/index.js +5 -0
  545. package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
  546. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
  547. package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
  548. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +163 -0
  549. package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
  550. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
  551. package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
  552. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +255 -0
  553. package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
  554. package/dist-server/server/modules/settings/index.js +3 -0
  555. package/dist-server/server/modules/settings/index.js.map +1 -0
  556. package/dist-server/server/modules/settings/settings.module.js +35 -0
  557. package/dist-server/server/modules/settings/settings.module.js.map +1 -0
  558. package/dist-server/server/modules/settings/settings.routes.js +34 -0
  559. package/dist-server/server/modules/settings/settings.routes.js.map +1 -0
  560. package/dist-server/server/modules/settings/settings.service.js +116 -0
  561. package/dist-server/server/modules/settings/settings.service.js.map +1 -0
  562. package/dist-server/server/modules/settings/tests/settings.service.test.js +48 -0
  563. package/dist-server/server/modules/settings/tests/settings.service.test.js.map +1 -0
  564. package/dist-server/server/modules/system/index.js +3 -0
  565. package/dist-server/server/modules/system/index.js.map +1 -0
  566. package/dist-server/server/modules/system/system.module.js +44 -0
  567. package/dist-server/server/modules/system/system.module.js.map +1 -0
  568. package/dist-server/server/modules/system/system.routes.js +16 -0
  569. package/dist-server/server/modules/system/system.routes.js.map +1 -0
  570. package/dist-server/server/modules/system/system.service.js +45 -0
  571. package/dist-server/server/modules/system/system.service.js.map +1 -0
  572. package/dist-server/server/modules/system/tests/system.service.test.js +100 -0
  573. package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -0
  574. package/dist-server/server/modules/taskmaster/index.js +3 -0
  575. package/dist-server/server/modules/taskmaster/index.js.map +1 -0
  576. package/dist-server/server/modules/taskmaster/taskmaster.module.js +20 -0
  577. package/dist-server/server/modules/taskmaster/taskmaster.module.js.map +1 -0
  578. package/dist-server/server/modules/taskmaster/taskmaster.routes.js +1372 -0
  579. package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -0
  580. package/dist-server/server/modules/taskmaster/taskmaster.service.js +107 -0
  581. package/dist-server/server/modules/taskmaster/taskmaster.service.js.map +1 -0
  582. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +180 -0
  583. package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -0
  584. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js +85 -0
  585. package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js.map +1 -0
  586. package/dist-server/server/modules/user/index.js +3 -0
  587. package/dist-server/server/modules/user/index.js.map +1 -0
  588. package/dist-server/server/modules/user/tests/user.service.test.js +123 -0
  589. package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -0
  590. package/dist-server/server/modules/user/user.module.js +56 -0
  591. package/dist-server/server/modules/user/user.module.js.map +1 -0
  592. package/dist-server/server/modules/user/user.routes.js +88 -0
  593. package/dist-server/server/modules/user/user.routes.js.map +1 -0
  594. package/dist-server/server/modules/user/user.service.js +134 -0
  595. package/dist-server/server/modules/user/user.service.js.map +1 -0
  596. package/dist-server/server/modules/voice/index.js +3 -0
  597. package/dist-server/server/modules/voice/index.js.map +1 -0
  598. package/dist-server/server/modules/voice/tests/voice.service.test.js +87 -0
  599. package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -0
  600. package/dist-server/server/modules/voice/voice.module.js +44 -0
  601. package/dist-server/server/modules/voice/voice.module.js.map +1 -0
  602. package/dist-server/server/modules/voice/voice.routes.js +87 -0
  603. package/dist-server/server/modules/voice/voice.routes.js.map +1 -0
  604. package/dist-server/server/modules/voice/voice.service.js +148 -0
  605. package/dist-server/server/modules/voice/voice.service.js.map +1 -0
  606. package/dist-server/server/modules/websocket/index.js +11 -0
  607. package/dist-server/server/modules/websocket/index.js.map +1 -0
  608. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +232 -0
  609. package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -0
  610. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +135 -0
  611. package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -0
  612. package/dist-server/server/modules/websocket/services/chat-websocket.service.js +467 -0
  613. package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
  614. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
  615. package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
  616. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
  617. package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
  618. package/dist-server/server/modules/websocket/services/shell-websocket.service.js +472 -0
  619. package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
  620. package/dist-server/server/modules/websocket/services/websocket-auth.service.js +36 -0
  621. package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
  622. package/dist-server/server/modules/websocket/services/websocket-server.service.js +90 -0
  623. package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
  624. package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
  625. package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
  626. package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
  627. package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
  628. package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js +40 -0
  629. package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js.map +1 -0
  630. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
  631. package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
  632. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +275 -0
  633. package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -0
  634. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
  635. package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
  636. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +177 -0
  637. package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -0
  638. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js +61 -0
  639. package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js.map +1 -0
  640. package/dist-server/server/modules/worktrees/index.js +3 -0
  641. package/dist-server/server/modules/worktrees/index.js.map +1 -0
  642. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js +37 -0
  643. package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js.map +1 -0
  644. package/dist-server/server/modules/worktrees/services/worktree-create.service.js +67 -0
  645. package/dist-server/server/modules/worktrees/services/worktree-create.service.js.map +1 -0
  646. package/dist-server/server/modules/worktrees/services/worktree-git.service.js +172 -0
  647. package/dist-server/server/modules/worktrees/services/worktree-git.service.js.map +1 -0
  648. package/dist-server/server/modules/worktrees/services/worktree-list.service.js +91 -0
  649. package/dist-server/server/modules/worktrees/services/worktree-list.service.js.map +1 -0
  650. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js +118 -0
  651. package/dist-server/server/modules/worktrees/services/worktree-merge.service.js.map +1 -0
  652. package/dist-server/server/modules/worktrees/services/worktree-open.service.js +58 -0
  653. package/dist-server/server/modules/worktrees/services/worktree-open.service.js.map +1 -0
  654. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +65 -0
  655. package/dist-server/server/modules/worktrees/services/worktree-remove.service.js.map +1 -0
  656. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js +58 -0
  657. package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js.map +1 -0
  658. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js +85 -0
  659. package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js.map +1 -0
  660. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js +58 -0
  661. package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js.map +1 -0
  662. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js +34 -0
  663. package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js.map +1 -0
  664. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js +137 -0
  665. package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js.map +1 -0
  666. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js +99 -0
  667. package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js.map +1 -0
  668. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js +157 -0
  669. package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js.map +1 -0
  670. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js +167 -0
  671. package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js.map +1 -0
  672. package/dist-server/server/modules/worktrees/worktrees.module.js +97 -0
  673. package/dist-server/server/modules/worktrees/worktrees.module.js.map +1 -0
  674. package/dist-server/server/modules/worktrees/worktrees.routes.js +84 -0
  675. package/dist-server/server/modules/worktrees/worktrees.routes.js.map +1 -0
  676. package/dist-server/server/piecemaker/activation/claude-mcp.cjs +109 -0
  677. package/dist-server/server/piecemaker/activation/claude-mcp.cjs.map +1 -0
  678. package/dist-server/server/piecemaker/activation/claude-plugins.cjs +60 -0
  679. package/dist-server/server/piecemaker/activation/claude-plugins.cjs.map +1 -0
  680. package/dist-server/server/piecemaker/activation/codex-mcp.cjs +93 -0
  681. package/dist-server/server/piecemaker/activation/codex-mcp.cjs.map +1 -0
  682. package/dist-server/server/piecemaker/activation/errors.cjs +14 -0
  683. package/dist-server/server/piecemaker/activation/errors.cjs.map +1 -0
  684. package/dist-server/server/piecemaker/activation/library.cjs +281 -0
  685. package/dist-server/server/piecemaker/activation/library.cjs.map +1 -0
  686. package/dist-server/server/piecemaker/activation/library.test.js +281 -0
  687. package/dist-server/server/piecemaker/activation/library.test.js.map +1 -0
  688. package/dist-server/server/piecemaker/activation/markdown.cjs +103 -0
  689. package/dist-server/server/piecemaker/activation/markdown.cjs.map +1 -0
  690. package/dist-server/server/piecemaker/activation/paths.cjs +103 -0
  691. package/dist-server/server/piecemaker/activation/paths.cjs.map +1 -0
  692. package/dist-server/server/piecemaker/activation/paths.test.js +91 -0
  693. package/dist-server/server/piecemaker/activation/paths.test.js.map +1 -0
  694. package/dist-server/server/piecemaker/activation/routes.cjs +100 -0
  695. package/dist-server/server/piecemaker/activation/routes.cjs.map +1 -0
  696. package/dist-server/server/piecemaker/activation/routes.test.js +307 -0
  697. package/dist-server/server/piecemaker/activation/routes.test.js.map +1 -0
  698. package/dist-server/server/piecemaker/activation/snapshot.cjs +28 -0
  699. package/dist-server/server/piecemaker/activation/snapshot.cjs.map +1 -0
  700. package/dist-server/server/piecemaker/anonymizer/anonymizer.test.js +282 -0
  701. package/dist-server/server/piecemaker/anonymizer/anonymizer.test.js.map +1 -0
  702. package/dist-server/server/piecemaker/anonymizer/client-config.cjs +224 -0
  703. package/dist-server/server/piecemaker/anonymizer/client-config.cjs.map +1 -0
  704. package/dist-server/server/piecemaker/anonymizer/codex-http.test.js +19 -0
  705. package/dist-server/server/piecemaker/anonymizer/codex-http.test.js.map +1 -0
  706. package/dist-server/server/piecemaker/anonymizer/dictionary.cjs +163 -0
  707. package/dist-server/server/piecemaker/anonymizer/dictionary.cjs.map +1 -0
  708. package/dist-server/server/piecemaker/anonymizer/lifecycle.js +20 -0
  709. package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -0
  710. package/dist-server/server/piecemaker/anonymizer/lifecycle.test.js +35 -0
  711. package/dist-server/server/piecemaker/anonymizer/lifecycle.test.js.map +1 -0
  712. package/dist-server/server/piecemaker/anonymizer/providers.cjs +236 -0
  713. package/dist-server/server/piecemaker/anonymizer/providers.cjs.map +1 -0
  714. package/dist-server/server/piecemaker/anonymizer/proxy.cjs +338 -0
  715. package/dist-server/server/piecemaker/anonymizer/proxy.cjs.map +1 -0
  716. package/dist-server/server/piecemaker/anonymizer/rewrite.cjs +249 -0
  717. package/dist-server/server/piecemaker/anonymizer/rewrite.cjs.map +1 -0
  718. package/dist-server/server/piecemaker/anonymizer/service.cjs +217 -0
  719. package/dist-server/server/piecemaker/anonymizer/service.cjs.map +1 -0
  720. package/dist-server/server/piecemaker/harness/chat-harness.js +157 -0
  721. package/dist-server/server/piecemaker/harness/chat-harness.js.map +1 -0
  722. package/dist-server/server/piecemaker/harness/chat-harness.test.js +120 -0
  723. package/dist-server/server/piecemaker/harness/chat-harness.test.js.map +1 -0
  724. package/dist-server/server/piecemaker/harness/citation-instructions.js +17 -0
  725. package/dist-server/server/piecemaker/harness/citation-instructions.js.map +1 -0
  726. package/dist-server/server/piecemaker/harness/citation-store.js +72 -0
  727. package/dist-server/server/piecemaker/harness/citation-store.js.map +1 -0
  728. package/dist-server/server/piecemaker/harness/citation-turn.js +211 -0
  729. package/dist-server/server/piecemaker/harness/citation-turn.js.map +1 -0
  730. package/dist-server/server/piecemaker/harness/citation-turn.test.js +144 -0
  731. package/dist-server/server/piecemaker/harness/citation-turn.test.js.map +1 -0
  732. package/dist-server/server/piecemaker/harness/citations.routes.js +16 -0
  733. package/dist-server/server/piecemaker/harness/citations.routes.js.map +1 -0
  734. package/dist-server/server/piecemaker/harness/citations.routes.test.js +68 -0
  735. package/dist-server/server/piecemaker/harness/citations.routes.test.js.map +1 -0
  736. package/dist-server/server/piecemaker/harness/decisions.cjs +298 -0
  737. package/dist-server/server/piecemaker/harness/decisions.cjs.map +1 -0
  738. package/dist-server/server/piecemaker/harness/flux-sse.cjs +108 -0
  739. package/dist-server/server/piecemaker/harness/flux-sse.cjs.map +1 -0
  740. package/dist-server/server/piecemaker/harness/harness.test.js +259 -0
  741. package/dist-server/server/piecemaker/harness/harness.test.js.map +1 -0
  742. package/dist-server/server/piecemaker/harness/index.cjs +100 -0
  743. package/dist-server/server/piecemaker/harness/index.cjs.map +1 -0
  744. package/dist-server/server/piecemaker/harness/proxy-harness.test.js +199 -0
  745. package/dist-server/server/piecemaker/harness/proxy-harness.test.js.map +1 -0
  746. package/dist-server/server/piecemaker/harness/source-passages.js +19 -0
  747. package/dist-server/server/piecemaker/harness/source-passages.js.map +1 -0
  748. package/dist-server/server/piecemaker/harness/verification.cjs +152 -0
  749. package/dist-server/server/piecemaker/harness/verification.cjs.map +1 -0
  750. package/dist-server/server/piecemaker/index.js +46 -0
  751. package/dist-server/server/piecemaker/index.js.map +1 -0
  752. package/dist-server/server/piecemaker/library/index.js +66 -0
  753. package/dist-server/server/piecemaker/library/index.js.map +1 -0
  754. package/dist-server/server/piecemaker/library/marketplace.js +204 -0
  755. package/dist-server/server/piecemaker/library/marketplace.js.map +1 -0
  756. package/dist-server/server/piecemaker/library/migrate-cli.js +13 -0
  757. package/dist-server/server/piecemaker/library/migrate-cli.js.map +1 -0
  758. package/dist-server/server/piecemaker/library/migrate.js +53 -0
  759. package/dist-server/server/piecemaker/library/migrate.js.map +1 -0
  760. package/dist-server/server/piecemaker/library/provider-skills.js +40 -0
  761. package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -0
  762. package/dist-server/server/piecemaker/library/provider-skills.test.js +55 -0
  763. package/dist-server/server/piecemaker/library/provider-skills.test.js.map +1 -0
  764. package/dist-server/server/piecemaker/library/routes.js +56 -0
  765. package/dist-server/server/piecemaker/library/routes.js.map +1 -0
  766. package/dist-server/server/piecemaker/library/runtime.js +34 -0
  767. package/dist-server/server/piecemaker/library/runtime.js.map +1 -0
  768. package/dist-server/server/piecemaker/library/store.js +440 -0
  769. package/dist-server/server/piecemaker/library/store.js.map +1 -0
  770. package/dist-server/server/piecemaker/library/store.test.js +265 -0
  771. package/dist-server/server/piecemaker/library/store.test.js.map +1 -0
  772. package/dist-server/server/piecemaker/library/workspace-installation.js +70 -0
  773. package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -0
  774. package/dist-server/server/piecemaker/originals-cache.cjs +45 -0
  775. package/dist-server/server/piecemaker/originals-cache.cjs.map +1 -0
  776. package/dist-server/server/piecemaker/originals-cache.test.js +68 -0
  777. package/dist-server/server/piecemaker/originals-cache.test.js.map +1 -0
  778. package/dist-server/server/piecemaker/protection/bypass.cjs +66 -0
  779. package/dist-server/server/piecemaker/protection/bypass.cjs.map +1 -0
  780. package/dist-server/server/piecemaker/protection/bypass.test.js +117 -0
  781. package/dist-server/server/piecemaker/protection/bypass.test.js.map +1 -0
  782. package/dist-server/server/piecemaker/protection/routes.cjs +38 -0
  783. package/dist-server/server/piecemaker/protection/routes.cjs.map +1 -0
  784. package/dist-server/server/piecemaker/timesheet/index.js +9 -0
  785. package/dist-server/server/piecemaker/timesheet/index.js.map +1 -0
  786. package/dist-server/server/piecemaker/timesheet/routes.js +42 -0
  787. package/dist-server/server/piecemaker/timesheet/routes.js.map +1 -0
  788. package/dist-server/server/piecemaker/timesheet/service.js +241 -0
  789. package/dist-server/server/piecemaker/timesheet/service.js.map +1 -0
  790. package/dist-server/server/piecemaker/timesheet/service.test.js +124 -0
  791. package/dist-server/server/piecemaker/timesheet/service.test.js.map +1 -0
  792. package/dist-server/server/piecemaker/timesheet/store.js +126 -0
  793. package/dist-server/server/piecemaker/timesheet/store.js.map +1 -0
  794. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs +147 -0
  795. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs.map +1 -0
  796. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +285 -0
  797. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs.map +1 -0
  798. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +87 -0
  799. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs.map +1 -0
  800. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
  801. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs.map +1 -0
  802. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs +526 -0
  803. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs.map +1 -0
  804. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs +304 -0
  805. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs.map +1 -0
  806. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs +1660 -0
  807. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs.map +1 -0
  808. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs +152 -0
  809. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs.map +1 -0
  810. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs +84 -0
  811. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs.map +1 -0
  812. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +332 -0
  813. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs.map +1 -0
  814. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js +64 -0
  815. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js.map +1 -0
  816. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +420 -0
  817. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs.map +1 -0
  818. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs +91 -0
  819. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs.map +1 -0
  820. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +304 -0
  821. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs.map +1 -0
  822. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs +293 -0
  823. package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs.map +1 -0
  824. package/dist-server/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs +5 -0
  825. package/dist-server/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs.map +1 -0
  826. package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.cjs +91 -0
  827. package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.cjs.map +1 -0
  828. package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.test.js +11 -0
  829. package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.test.js.map +1 -0
  830. package/dist-server/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +955 -0
  831. package/dist-server/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs.map +1 -0
  832. package/dist-server/server/shared/claude-cli-path.js +120 -0
  833. package/dist-server/server/shared/claude-cli-path.js.map +1 -0
  834. package/dist-server/server/shared/frontmatter.js +16 -0
  835. package/dist-server/server/shared/frontmatter.js.map +1 -0
  836. package/dist-server/server/shared/image-attachments.js +344 -0
  837. package/dist-server/server/shared/image-attachments.js.map +1 -0
  838. package/dist-server/server/shared/interfaces.js +2 -0
  839. package/dist-server/server/shared/interfaces.js.map +1 -0
  840. package/dist-server/server/shared/message-unification.js +376 -0
  841. package/dist-server/server/shared/message-unification.js.map +1 -0
  842. package/dist-server/server/shared/tests/application-data-root.test.js +33 -0
  843. package/dist-server/server/shared/tests/application-data-root.test.js.map +1 -0
  844. package/dist-server/server/shared/tests/claude-cli-path.test.js +89 -0
  845. package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -0
  846. package/dist-server/server/shared/tests/image-attachments.test.js +262 -0
  847. package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -0
  848. package/dist-server/server/shared/tests/message-unification.test.js +174 -0
  849. package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
  850. package/dist-server/server/shared/tests/slice-tail-page.test.js +35 -0
  851. package/dist-server/server/shared/tests/slice-tail-page.test.js.map +1 -0
  852. package/dist-server/server/shared/types.js +2 -0
  853. package/dist-server/server/shared/types.js.map +1 -0
  854. package/dist-server/server/shared/utils.js +1010 -0
  855. package/dist-server/server/shared/utils.js.map +1 -0
  856. package/dist-server/shared/networkHosts.js +20 -0
  857. package/dist-server/shared/networkHosts.js.map +1 -0
  858. package/dist-server/shared/product-config.mjs +79 -0
  859. package/dist-server/shared/product-config.mjs.map +1 -0
  860. package/package.json +271 -0
  861. package/product.config.json +17 -0
  862. package/public/api-docs.html +901 -0
  863. package/scripts/fix-node-pty.js +67 -0
  864. package/scripts/piecemaker/cli/install-command.mjs +130 -0
  865. package/scripts/piecemaker/cli/lib/composants.mjs +68 -0
  866. package/scripts/piecemaker/cli/lib/config.mjs +32 -0
  867. package/scripts/piecemaker/cli/lib/exec.mjs +79 -0
  868. package/scripts/piecemaker/cli/lib/node-runtime.mjs +76 -0
  869. package/scripts/piecemaker/cli/lib/ports.mjs +96 -0
  870. package/scripts/piecemaker/cli/lib/pwa.mjs +323 -0
  871. package/scripts/piecemaker/cli/lib/repos.mjs +140 -0
  872. package/scripts/piecemaker/cli/lib/services.mjs +71 -0
  873. package/scripts/piecemaker/cli/lib/ui.mjs +41 -0
  874. package/scripts/piecemaker/cli/piecemaker.mjs +159 -0
  875. package/scripts/piecemaker/cli/piecemaker.ps1 +63 -0
  876. package/scripts/piecemaker/cli/piecemaker.sh +60 -0
  877. package/scripts/piecemaker/generate-i18n-overrides.mjs +219 -0
  878. package/scripts/piecemaker/hooks/proxy-guard.mjs +286 -0
  879. package/scripts/promote-dist-server.mjs +50 -0
  880. package/scripts/release/build-server-bundle.js +178 -0
  881. package/scripts/release/package-piecemaker.sh +73 -0
  882. package/scripts/release/prepare-desktop-app.js +168 -0
  883. package/server/index.ts +410 -0
  884. package/server/load-env.ts +48 -0
  885. package/server/modules/agent/agent.module.ts +52 -0
  886. package/server/modules/agent/agent.routes.ts +1287 -0
  887. package/server/modules/agent/index.ts +2 -0
  888. package/server/modules/agent/tests/agent.routes.test.ts +205 -0
  889. package/server/modules/assets/assets.routes.ts +150 -0
  890. package/server/modules/assets/index.ts +3 -0
  891. package/server/modules/assets/services/image-assets.service.ts +127 -0
  892. package/server/modules/assets/tests/image-assets.service.test.ts +74 -0
  893. package/server/modules/auth/auth.middleware.ts +163 -0
  894. package/server/modules/auth/auth.module.ts +38 -0
  895. package/server/modules/auth/auth.routes.ts +57 -0
  896. package/server/modules/auth/auth.service.ts +155 -0
  897. package/server/modules/auth/index.ts +9 -0
  898. package/server/modules/auth/tests/auth.service.test.ts +95 -0
  899. package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -0
  900. package/server/modules/browser-use/browser-use-mcp.ts +386 -0
  901. package/server/modules/browser-use/browser-use-runtime.ts +10 -0
  902. package/server/modules/browser-use/browser-use.routes.ts +96 -0
  903. package/server/modules/browser-use/browser-use.service.ts +835 -0
  904. package/server/modules/browser-use/index.ts +11 -0
  905. package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -0
  906. package/server/modules/cli/cli.module.ts +110 -0
  907. package/server/modules/cli/cli.service.ts +266 -0
  908. package/server/modules/cli/cli.ts +19 -0
  909. package/server/modules/cli/index.ts +2 -0
  910. package/server/modules/cli/pwa-launcher.ts +131 -0
  911. package/server/modules/cli/sandbox.service.ts +413 -0
  912. package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -0
  913. package/server/modules/cli/tests/cli.service.test.ts +107 -0
  914. package/server/modules/cli/tests/sandbox.service.test.ts +61 -0
  915. package/server/modules/commands/commands.module.ts +22 -0
  916. package/server/modules/commands/commands.routes.ts +605 -0
  917. package/server/modules/commands/index.ts +2 -0
  918. package/server/modules/commands/tests/commands.test.ts +114 -0
  919. package/server/modules/database/connection.ts +144 -0
  920. package/server/modules/database/index.ts +27 -0
  921. package/server/modules/database/init-db.ts +17 -0
  922. package/server/modules/database/migrations.ts +552 -0
  923. package/server/modules/database/repositories/api-keys.ts +119 -0
  924. package/server/modules/database/repositories/app-config.ts +53 -0
  925. package/server/modules/database/repositories/credentials.ts +106 -0
  926. package/server/modules/database/repositories/github-tokens.ts +100 -0
  927. package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -0
  928. package/server/modules/database/repositories/notification-preferences.ts +117 -0
  929. package/server/modules/database/repositories/projects.db.ts +196 -0
  930. package/server/modules/database/repositories/provider-models.ts +168 -0
  931. package/server/modules/database/repositories/push-subscriptions.ts +80 -0
  932. package/server/modules/database/repositories/scan-state.db.ts +42 -0
  933. package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
  934. package/server/modules/database/repositories/session-drafts.db.ts +171 -0
  935. package/server/modules/database/repositories/sessions.db.ts +714 -0
  936. package/server/modules/database/repositories/user-preferences.db.ts +80 -0
  937. package/server/modules/database/repositories/users.ts +140 -0
  938. package/server/modules/database/repositories/vapid-keys.ts +57 -0
  939. package/server/modules/database/schema.ts +306 -0
  940. package/server/modules/database/tests/projects.db.integration.test.ts +72 -0
  941. package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -0
  942. package/server/modules/database/tests/sessions-provider-mapping.test.ts +109 -0
  943. package/server/modules/database/tests/sessions.db.integration.test.ts +116 -0
  944. package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
  945. package/server/modules/file-tree/file-tree.module.ts +116 -0
  946. package/server/modules/file-tree/file-tree.routes.ts +258 -0
  947. package/server/modules/file-tree/file-tree.service.ts +675 -0
  948. package/server/modules/file-tree/index.ts +2 -0
  949. package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -0
  950. package/server/modules/file-tree/tests/file-tree.service.test.ts +371 -0
  951. package/server/modules/git/git-branch.service.ts +43 -0
  952. package/server/modules/git/git-parsing.service.ts +66 -0
  953. package/server/modules/git/git.module.ts +22 -0
  954. package/server/modules/git/git.routes.ts +1600 -0
  955. package/server/modules/git/index.ts +2 -0
  956. package/server/modules/git/tests/git-branch.service.test.ts +60 -0
  957. package/server/modules/git/tests/git-init.routes.test.ts +135 -0
  958. package/server/modules/git/tests/git.test.ts +106 -0
  959. package/server/modules/notifications/index.ts +24 -0
  960. package/server/modules/notifications/notifications.routes.ts +127 -0
  961. package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -0
  962. package/server/modules/notifications/services/notification-orchestrator.service.js +310 -0
  963. package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -0
  964. package/server/modules/notifications/vapid-keys.service.ts +38 -0
  965. package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -0
  966. package/server/modules/plugins/index.ts +9 -0
  967. package/server/modules/plugins/plugin-process.service.ts +217 -0
  968. package/server/modules/plugins/plugin-registry.service.ts +461 -0
  969. package/server/modules/plugins/plugins.module.ts +33 -0
  970. package/server/modules/plugins/plugins.routes.ts +66 -0
  971. package/server/modules/plugins/plugins.service.ts +147 -0
  972. package/server/modules/plugins/tests/plugins.service.test.ts +32 -0
  973. package/server/modules/projects/index.ts +11 -0
  974. package/server/modules/projects/projects.routes.ts +273 -0
  975. package/server/modules/projects/services/project-clone.service.ts +323 -0
  976. package/server/modules/projects/services/project-delete.service.ts +102 -0
  977. package/server/modules/projects/services/project-management.service.ts +144 -0
  978. package/server/modules/projects/services/project-star.service.ts +78 -0
  979. package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -0
  980. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +314 -0
  981. package/server/modules/projects/tests/project-clone.service.test.ts +183 -0
  982. package/server/modules/projects/tests/project-management.service.test.ts +117 -0
  983. package/server/modules/projects/tests/project-star.service.test.ts +123 -0
  984. package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -0
  985. package/server/modules/providers/README.md +380 -0
  986. package/server/modules/providers/index.ts +14 -0
  987. package/server/modules/providers/list/claude/claude-auth.provider.ts +180 -0
  988. package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
  989. package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
  990. package/server/modules/providers/list/claude/claude-models.provider.ts +314 -0
  991. package/server/modules/providers/list/claude/claude-runtime.provider.js +1217 -0
  992. package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +203 -0
  993. package/server/modules/providers/list/claude/claude-sessions.provider.ts +1108 -0
  994. package/server/modules/providers/list/claude/claude-skills.provider.ts +265 -0
  995. package/server/modules/providers/list/claude/claude.provider.ts +33 -0
  996. package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
  997. package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
  998. package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
  999. package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
  1000. package/server/modules/providers/list/codex/codex-models.provider.ts +123 -0
  1001. package/server/modules/providers/list/codex/codex-runtime.provider.js +572 -0
  1002. package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +212 -0
  1003. package/server/modules/providers/list/codex/codex-sessions.provider.ts +2267 -0
  1004. package/server/modules/providers/list/codex/codex-skills.provider.ts +73 -0
  1005. package/server/modules/providers/list/codex/codex.provider.ts +33 -0
  1006. package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
  1007. package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
  1008. package/server/modules/providers/list/cursor/cursor-models.provider.ts +119 -0
  1009. package/server/modules/providers/list/cursor/cursor-runtime.provider.js +387 -0
  1010. package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +158 -0
  1011. package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +654 -0
  1012. package/server/modules/providers/list/cursor/cursor-skills.provider.ts +39 -0
  1013. package/server/modules/providers/list/cursor/cursor.provider.ts +30 -0
  1014. package/server/modules/providers/list/mistral/mistral-auth.provider.ts +181 -0
  1015. package/server/modules/providers/list/mistral/mistral-mcp.provider.ts +20 -0
  1016. package/server/modules/providers/list/mistral/mistral-models.provider.ts +76 -0
  1017. package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +417 -0
  1018. package/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.ts +15 -0
  1019. package/server/modules/providers/list/mistral/mistral-sessions.provider.ts +210 -0
  1020. package/server/modules/providers/list/mistral/mistral-skills.provider.ts +20 -0
  1021. package/server/modules/providers/list/mistral/mistral.provider.ts +35 -0
  1022. package/server/modules/providers/list/opencode/opencode-auth.provider.ts +110 -0
  1023. package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -0
  1024. package/server/modules/providers/list/opencode/opencode-models.provider.ts +304 -0
  1025. package/server/modules/providers/list/opencode/opencode-runtime.provider.js +434 -0
  1026. package/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +261 -0
  1027. package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +179 -0
  1028. package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +500 -0
  1029. package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -0
  1030. package/server/modules/providers/list/opencode/opencode.provider.ts +30 -0
  1031. package/server/modules/providers/provider.registry.ts +38 -0
  1032. package/server/modules/providers/provider.routes.ts +909 -0
  1033. package/server/modules/providers/services/mcp.service.ts +109 -0
  1034. package/server/modules/providers/services/provider-auth.service.ts +26 -0
  1035. package/server/modules/providers/services/provider-capabilities.service.ts +133 -0
  1036. package/server/modules/providers/services/provider-models.service.ts +401 -0
  1037. package/server/modules/providers/services/provider-runtime.service.ts +108 -0
  1038. package/server/modules/providers/services/provider-token-usage.service.ts +484 -0
  1039. package/server/modules/providers/services/session-conversations-search.service.ts +1321 -0
  1040. package/server/modules/providers/services/session-history-cache.service.ts +139 -0
  1041. package/server/modules/providers/services/session-synchronizer.service.ts +162 -0
  1042. package/server/modules/providers/services/sessions-watcher.service.ts +266 -0
  1043. package/server/modules/providers/services/sessions.service.ts +663 -0
  1044. package/server/modules/providers/services/skills.service.ts +39 -0
  1045. package/server/modules/providers/shared/base/abstract.provider.ts +32 -0
  1046. package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
  1047. package/server/modules/providers/shared/skills/skills.provider.ts +287 -0
  1048. package/server/modules/providers/tests/claude-auth.test.ts +208 -0
  1049. package/server/modules/providers/tests/claude-sessions.test.ts +573 -0
  1050. package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
  1051. package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
  1052. package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
  1053. package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
  1054. package/server/modules/providers/tests/codex-sessions.test.ts +553 -0
  1055. package/server/modules/providers/tests/mcp.test.ts +349 -0
  1056. package/server/modules/providers/tests/opencode-models.test.ts +154 -0
  1057. package/server/modules/providers/tests/opencode-sessions.test.ts +522 -0
  1058. package/server/modules/providers/tests/provider-attachment-history.test.ts +247 -0
  1059. package/server/modules/providers/tests/provider-models.service.test.ts +353 -0
  1060. package/server/modules/providers/tests/provider-runtime.service.test.ts +138 -0
  1061. package/server/modules/providers/tests/provider-token-usage.service.test.ts +373 -0
  1062. package/server/modules/providers/tests/provider.routes.test.ts +244 -0
  1063. package/server/modules/providers/tests/session-fork.test.ts +173 -0
  1064. package/server/modules/providers/tests/session-history-cache.service.test.ts +143 -0
  1065. package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
  1066. package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
  1067. package/server/modules/providers/tests/sessions-details.test.ts +73 -0
  1068. package/server/modules/providers/tests/sessions.service.test.ts +193 -0
  1069. package/server/modules/providers/tests/skills.test.ts +692 -0
  1070. package/server/modules/scheduled-messages/index.ts +8 -0
  1071. package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
  1072. package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +203 -0
  1073. package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
  1074. package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +310 -0
  1075. package/server/modules/settings/index.ts +2 -0
  1076. package/server/modules/settings/settings.module.ts +50 -0
  1077. package/server/modules/settings/settings.routes.ts +51 -0
  1078. package/server/modules/settings/settings.service.ts +186 -0
  1079. package/server/modules/settings/tests/settings.service.test.ts +54 -0
  1080. package/server/modules/system/index.ts +2 -0
  1081. package/server/modules/system/system.module.ts +62 -0
  1082. package/server/modules/system/system.routes.ts +21 -0
  1083. package/server/modules/system/system.service.ts +76 -0
  1084. package/server/modules/system/tests/system.service.test.ts +118 -0
  1085. package/server/modules/taskmaster/index.ts +2 -0
  1086. package/server/modules/taskmaster/taskmaster.module.ts +24 -0
  1087. package/server/modules/taskmaster/taskmaster.routes.ts +1472 -0
  1088. package/server/modules/taskmaster/taskmaster.service.ts +132 -0
  1089. package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +201 -0
  1090. package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -0
  1091. package/server/modules/user/index.ts +2 -0
  1092. package/server/modules/user/tests/user.service.test.ts +151 -0
  1093. package/server/modules/user/user.module.ts +67 -0
  1094. package/server/modules/user/user.routes.ts +94 -0
  1095. package/server/modules/user/user.service.ts +190 -0
  1096. package/server/modules/voice/index.ts +2 -0
  1097. package/server/modules/voice/tests/voice.service.test.ts +99 -0
  1098. package/server/modules/voice/voice.module.ts +47 -0
  1099. package/server/modules/voice/voice.routes.ts +113 -0
  1100. package/server/modules/voice/voice.service.ts +192 -0
  1101. package/server/modules/websocket/README.md +273 -0
  1102. package/server/modules/websocket/index.ts +11 -0
  1103. package/server/modules/websocket/services/chat-run-registry.service.ts +310 -0
  1104. package/server/modules/websocket/services/chat-session-writer.service.ts +175 -0
  1105. package/server/modules/websocket/services/chat-websocket.service.ts +654 -0
  1106. package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
  1107. package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
  1108. package/server/modules/websocket/services/shell-websocket.service.ts +628 -0
  1109. package/server/modules/websocket/services/websocket-auth.service.ts +59 -0
  1110. package/server/modules/websocket/services/websocket-server.service.ts +126 -0
  1111. package/server/modules/websocket/services/websocket-state.service.ts +16 -0
  1112. package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
  1113. package/server/modules/websocket/tests/chat-attachment-filter.test.ts +59 -0
  1114. package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
  1115. package/server/modules/websocket/tests/chat-run-registry.test.ts +313 -0
  1116. package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
  1117. package/server/modules/websocket/tests/shell-websocket.service.test.ts +227 -0
  1118. package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -0
  1119. package/server/modules/worktrees/index.ts +2 -0
  1120. package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -0
  1121. package/server/modules/worktrees/services/worktree-create.service.ts +104 -0
  1122. package/server/modules/worktrees/services/worktree-git.service.ts +207 -0
  1123. package/server/modules/worktrees/services/worktree-list.service.ts +143 -0
  1124. package/server/modules/worktrees/services/worktree-merge.service.ts +157 -0
  1125. package/server/modules/worktrees/services/worktree-open.service.ts +85 -0
  1126. package/server/modules/worktrees/services/worktree-remove.service.ts +88 -0
  1127. package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -0
  1128. package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -0
  1129. package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -0
  1130. package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -0
  1131. package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -0
  1132. package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -0
  1133. package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -0
  1134. package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -0
  1135. package/server/modules/worktrees/worktrees.module.ts +113 -0
  1136. package/server/modules/worktrees/worktrees.routes.ts +116 -0
  1137. package/server/piecemaker/activation/claude-mcp.cjs +115 -0
  1138. package/server/piecemaker/activation/claude-plugins.cjs +65 -0
  1139. package/server/piecemaker/activation/codex-mcp.cjs +102 -0
  1140. package/server/piecemaker/activation/errors.cjs +15 -0
  1141. package/server/piecemaker/activation/index.cjs +5 -0
  1142. package/server/piecemaker/activation/library.cjs +284 -0
  1143. package/server/piecemaker/activation/library.cjs.bak +223 -0
  1144. package/server/piecemaker/activation/library.test.js +365 -0
  1145. package/server/piecemaker/activation/markdown.cjs +108 -0
  1146. package/server/piecemaker/activation/markdown.cjs.bak +78 -0
  1147. package/server/piecemaker/activation/paths.cjs +104 -0
  1148. package/server/piecemaker/activation/paths.test.js +158 -0
  1149. package/server/piecemaker/activation/routes.cjs +101 -0
  1150. package/server/piecemaker/activation/routes.test.js +344 -0
  1151. package/server/piecemaker/activation/snapshot.cjs +30 -0
  1152. package/server/piecemaker/anonymizer/anonymizer.test.js +320 -0
  1153. package/server/piecemaker/anonymizer/client-config.cjs +228 -0
  1154. package/server/piecemaker/anonymizer/codex-http.test.js +20 -0
  1155. package/server/piecemaker/anonymizer/dictionary.cjs +174 -0
  1156. package/server/piecemaker/anonymizer/lifecycle.test.ts +37 -0
  1157. package/server/piecemaker/anonymizer/lifecycle.ts +22 -0
  1158. package/server/piecemaker/anonymizer/providers.cjs +241 -0
  1159. package/server/piecemaker/anonymizer/proxy.cjs +365 -0
  1160. package/server/piecemaker/anonymizer/rewrite.cjs +251 -0
  1161. package/server/piecemaker/anonymizer/routes.cjs +43 -0
  1162. package/server/piecemaker/anonymizer/service.cjs +218 -0
  1163. package/server/piecemaker/harness/chat-harness.test.ts +131 -0
  1164. package/server/piecemaker/harness/chat-harness.ts +151 -0
  1165. package/server/piecemaker/harness/citation-instructions.ts +18 -0
  1166. package/server/piecemaker/harness/citation-store.ts +80 -0
  1167. package/server/piecemaker/harness/citation-turn.test.ts +155 -0
  1168. package/server/piecemaker/harness/citation-turn.ts +197 -0
  1169. package/server/piecemaker/harness/citations.routes.test.ts +68 -0
  1170. package/server/piecemaker/harness/citations.routes.ts +18 -0
  1171. package/server/piecemaker/harness/decisions.cjs +302 -0
  1172. package/server/piecemaker/harness/flux-sse.cjs +111 -0
  1173. package/server/piecemaker/harness/harness.test.js +296 -0
  1174. package/server/piecemaker/harness/index.cjs +103 -0
  1175. package/server/piecemaker/harness/proxy-harness.test.js +226 -0
  1176. package/server/piecemaker/harness/source-passages.ts +21 -0
  1177. package/server/piecemaker/harness/verification.cjs +159 -0
  1178. package/server/piecemaker/index.ts +59 -0
  1179. package/server/piecemaker/library/index.ts +54 -0
  1180. package/server/piecemaker/library/marketplace.ts +152 -0
  1181. package/server/piecemaker/library/migrate-cli.ts +11 -0
  1182. package/server/piecemaker/library/migrate.ts +49 -0
  1183. package/server/piecemaker/library/policy.cjs +9 -0
  1184. package/server/piecemaker/library/provider-skills.test.ts +61 -0
  1185. package/server/piecemaker/library/provider-skills.ts +48 -0
  1186. package/server/piecemaker/library/routes.ts +38 -0
  1187. package/server/piecemaker/library/runtime.ts +39 -0
  1188. package/server/piecemaker/library/store.test.ts +280 -0
  1189. package/server/piecemaker/library/store.ts +429 -0
  1190. package/server/piecemaker/library/workspace-installation.ts +61 -0
  1191. package/server/piecemaker/originals-cache.cjs +54 -0
  1192. package/server/piecemaker/originals-cache.test.js +77 -0
  1193. package/server/piecemaker/protection/bypass.cjs +73 -0
  1194. package/server/piecemaker/protection/bypass.test.js +140 -0
  1195. package/server/piecemaker/protection/routes.cjs +39 -0
  1196. package/server/piecemaker/router.cjs +109 -0
  1197. package/server/piecemaker/timesheet/index.ts +9 -0
  1198. package/server/piecemaker/timesheet/routes.ts +48 -0
  1199. package/server/piecemaker/timesheet/service.test.ts +142 -0
  1200. package/server/piecemaker/timesheet/service.ts +298 -0
  1201. package/server/piecemaker/timesheet/store.ts +167 -0
  1202. package/server/piecemaker/vendor/.env +2 -0
  1203. package/server/piecemaker/vendor/installer/assets/PieceMakerApp.swift +189 -0
  1204. package/server/piecemaker/vendor/installer/assets/claude-hooks/piecemaker-guard-secrets.mjs +230 -0
  1205. package/server/piecemaker/vendor/installer/assets/claude-hooks/piecemaker-secret-paths.default.json +1 -0
  1206. package/server/piecemaker/vendor/installer/assets/piecemaker.icns +0 -0
  1207. package/server/piecemaker/vendor/installer/assets/piecemaker.ico +0 -0
  1208. package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +1018 -0
  1209. package/server/piecemaker/vendor/installer/lib/banner.mjs +35 -0
  1210. package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +343 -0
  1211. package/server/piecemaker/vendor/installer/lib/commandes.mjs +13 -0
  1212. package/server/piecemaker/vendor/installer/lib/desktop-launcher.mjs +305 -0
  1213. package/server/piecemaker/vendor/installer/lib/legacy-legifrance.mjs +72 -0
  1214. package/server/piecemaker/vendor/installer/lib/platform.mjs +163 -0
  1215. package/server/piecemaker/vendor/installer/lib/prompt.mjs +138 -0
  1216. package/server/piecemaker/vendor/installer/lib/resume-steps.mjs +174 -0
  1217. package/server/piecemaker/vendor/installer/lib/secrets-guard.mjs +193 -0
  1218. package/server/piecemaker/vendor/installer/lib/service.mjs +467 -0
  1219. package/server/piecemaker/vendor/installer/lib/state.mjs +114 -0
  1220. package/server/piecemaker/vendor/installer/lib/ui.mjs +159 -0
  1221. package/server/piecemaker/vendor/installer/steps/00-identite.mjs +71 -0
  1222. package/server/piecemaker/vendor/installer/steps/01-prerequis.mjs +119 -0
  1223. package/server/piecemaker/vendor/installer/steps/02-dependances-node.mjs +127 -0
  1224. package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +249 -0
  1225. package/server/piecemaker/vendor/installer/steps/03b-python-graphify.mjs +161 -0
  1226. package/server/piecemaker/vendor/installer/steps/04-conversion-md.mjs +147 -0
  1227. package/server/piecemaker/vendor/installer/steps/05-certificats.mjs +171 -0
  1228. package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +266 -0
  1229. package/server/piecemaker/vendor/installer/steps/07-legifrance.mjs +279 -0
  1230. package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +482 -0
  1231. package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +151 -0
  1232. package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +142 -0
  1233. package/server/piecemaker/vendor/installer/steps/10-libreoffice.mjs +130 -0
  1234. package/server/piecemaker/vendor/installer/steps/10-pandoc.mjs +212 -0
  1235. package/server/piecemaker/vendor/installer/steps/11-docx-cli.mjs +144 -0
  1236. package/server/piecemaker/vendor/installer/steps/12-mcp-piecemaker.mjs +124 -0
  1237. package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +136 -0
  1238. package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +271 -0
  1239. package/server/piecemaker/vendor/installer/steps/15-pwa-desktop.mjs +64 -0
  1240. package/server/piecemaker/vendor/installer/templates/root-CLAUDE.md +79 -0
  1241. package/server/piecemaker/vendor/installer/templates/workspace-CLAUDE.md +111 -0
  1242. package/server/piecemaker/vendor/mcp/README.md +13 -0
  1243. package/server/piecemaker/vendor/mcp/piecemaker/server.mjs +222 -0
  1244. package/server/piecemaker/vendor/mike-defaults-fr/PROVENANCE.md +10 -0
  1245. package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/compare-documents/SKILL.md +51 -0
  1246. package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/draft-from-template/SKILL.md +27 -0
  1247. package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/extract-key-terms/SKILL.md +43 -0
  1248. package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/proofread/SKILL.md +98 -0
  1249. package/server/piecemaker/vendor/mike-defaults-fr/catalog.json +22 -0
  1250. package/server/piecemaker/vendor/mike-defaults-fr/tabular-review-workflows/commercial-agreement-tabular-review/SKILL.md +31 -0
  1251. package/server/piecemaker/vendor/mike-defaults-fr/tabular-review-workflows/commercial-agreement-tabular-review/table-columns.yaml +92 -0
  1252. package/server/piecemaker/vendor/package.json +7 -0
  1253. package/server/piecemaker/vendor/piecemaker-plugin/README.md +115 -0
  1254. package/server/piecemaker/vendor/piecemaker-plugin/agents/analyste-piece.md +38 -0
  1255. package/server/piecemaker/vendor/piecemaker-plugin/agents/jurisprudence-scanner.md +50 -0
  1256. package/server/piecemaker/vendor/piecemaker-plugin/hooks/hooks.json +84 -0
  1257. package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +194 -0
  1258. package/server/piecemaker/vendor/piecemaker-plugin/scripts/build-recherche-pdf.mjs +91 -0
  1259. package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +123 -0
  1260. package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +71 -0
  1261. package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +107 -0
  1262. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs +146 -0
  1263. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +303 -0
  1264. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +86 -0
  1265. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
  1266. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs +519 -0
  1267. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs +292 -0
  1268. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs +1683 -0
  1269. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/docx-text-worker.cjs +43 -0
  1270. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/hook-io.mjs +249 -0
  1271. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs +160 -0
  1272. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs +85 -0
  1273. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +346 -0
  1274. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js +68 -0
  1275. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +419 -0
  1276. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/recherche-report.cjs +177 -0
  1277. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs +80 -0
  1278. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +318 -0
  1279. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs +318 -0
  1280. package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +256 -0
  1281. package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit-worker.mjs +260 -0
  1282. package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit.mjs +83 -0
  1283. package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +179 -0
  1284. package/server/piecemaker/vendor/piecemaker-plugin/scripts/track-legifrance-reads.mjs +46 -0
  1285. package/server/piecemaker/vendor/piecemaker-plugin/skills/ajout-de-fonctionnalites/SKILL.md +66 -0
  1286. package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +60 -0
  1287. package/server/piecemaker/vendor/piecemaker-plugin/skills/graphe-juridique/SKILL.md +105 -0
  1288. package/server/piecemaker/vendor/piecemaker-plugin/skills/recherche-juridique/SKILL.md +234 -0
  1289. package/server/piecemaker/vendor/piecemaker-plugin/skills/redaction-juridique/SKILL.md +96 -0
  1290. package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +148 -0
  1291. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3195 -0
  1292. package/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs +3 -0
  1293. package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +114 -0
  1294. package/server/piecemaker/vendor/websocket-server/case-registry.cjs +93 -0
  1295. package/server/piecemaker/vendor/websocket-server/claude-assets.cjs +338 -0
  1296. package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +380 -0
  1297. package/server/piecemaker/vendor/websocket-server/document-index.cjs +682 -0
  1298. package/server/piecemaker/vendor/websocket-server/graphify-document-graph.cjs +456 -0
  1299. package/server/piecemaker/vendor/websocket-server/legal-chronology.cjs +502 -0
  1300. package/server/piecemaker/vendor/websocket-server/legal-forms.cjs +89 -0
  1301. package/server/piecemaker/vendor/websocket-server/legal-forms.test.js +10 -0
  1302. package/server/piecemaker/vendor/websocket-server/legal-graph-materializer.cjs +234 -0
  1303. package/server/piecemaker/vendor/websocket-server/legal-graph-prompt.txt +155 -0
  1304. package/server/piecemaker/vendor/websocket-server/legal-graph.cjs +2021 -0
  1305. package/server/piecemaker/vendor/websocket-server/legal-identity-boundary.cjs +247 -0
  1306. package/server/piecemaker/vendor/websocket-server/legal-party-registry.cjs +261 -0
  1307. package/server/piecemaker/vendor/websocket-server/lib/doc-generate.cjs +229 -0
  1308. package/server/piecemaker/vendor/websocket-server/lib/export-render.cjs +442 -0
  1309. package/server/piecemaker/vendor/websocket-server/lib/office-to-pdf.cjs +306 -0
  1310. package/server/piecemaker/vendor/websocket-server/lib/stamping.cjs +39 -0
  1311. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +965 -0
  1312. package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +216 -0
  1313. package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +134 -0
  1314. package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +138 -0
  1315. package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
  1316. package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +1984 -0
  1317. package/server/piecemaker/vendor/websocket-server/scripts/graphify-legal-sitecustomize.py +50 -0
  1318. package/server/piecemaker/vendor/websocket-server/scripts/mineru_improved_1.py +208 -0
  1319. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +246 -0
  1320. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +62 -0
  1321. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
  1322. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
  1323. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +118 -0
  1324. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +164 -0
  1325. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/BACKENDS_MESURES.md +384 -0
  1326. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/CRITERES_QUALITE.md +81 -0
  1327. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/__pycache__/coreml_encoder.cpython-312.pyc +0 -0
  1328. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_backend.py +151 -0
  1329. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_batchsize.py +47 -0
  1330. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_coreml_pipeline.py +138 -0
  1331. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_gensight.py +124 -0
  1332. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/check_gold.py +66 -0
  1333. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/coreml_encoder.py +182 -0
  1334. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/encoder_backends.py +179 -0
  1335. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/evaluate.py +130 -0
  1336. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/gold.py +59 -0
  1337. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/profile_split.py +65 -0
  1338. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_A.md +67 -0
  1339. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_B.md +57 -0
  1340. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_C.md +907 -0
  1341. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/sweep.py +115 -0
  1342. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_substitution.cjs +116 -0
  1343. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_whitespace.py +67 -0
  1344. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_worker.py +106 -0
  1345. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/model_config.py +28 -0
  1346. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +471 -0
  1347. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +668 -0
  1348. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__init__.py +10 -0
  1349. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/__init__.cpython-312.pyc +0 -0
  1350. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/analysis_explanation.cpython-312.pyc +0 -0
  1351. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/entity_recognizer.cpython-312.pyc +0 -0
  1352. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/local_recognizer.cpython-312.pyc +0 -0
  1353. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/pattern.cpython-312.pyc +0 -0
  1354. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/pattern_recognizer.cpython-312.pyc +0 -0
  1355. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/recognizer_result.cpython-312.pyc +0 -0
  1356. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/analysis_explanation.py +65 -0
  1357. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/entity_recognizer.py +213 -0
  1358. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/__init__.py +21 -0
  1359. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/language_validation.py +18 -0
  1360. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/schemas.py +132 -0
  1361. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/yaml_recognizer_models.py +422 -0
  1362. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/local_recognizer.py +7 -0
  1363. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__init__.py +15 -0
  1364. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/__init__.cpython-312.pyc +0 -0
  1365. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/device_detector.cpython-312.pyc +0 -0
  1366. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/ner_model_configuration.cpython-312.pyc +0 -0
  1367. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/nlp_artifacts.cpython-312.pyc +0 -0
  1368. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/nlp_engine.cpython-312.pyc +0 -0
  1369. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/spacy_nlp_engine.cpython-312.pyc +0 -0
  1370. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/device_detector.py +65 -0
  1371. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/ner_model_configuration.py +128 -0
  1372. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_artifacts.py +88 -0
  1373. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_engine.py +65 -0
  1374. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_engine_provider.py +114 -0
  1375. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/spacy_nlp_engine.py +290 -0
  1376. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/pattern.py +66 -0
  1377. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/pattern_recognizer.py +297 -0
  1378. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__init__.py +4 -0
  1379. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__pycache__/__init__.cpython-312.pyc +0 -0
  1380. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__pycache__/gliner_recognizer.cpython-312.pyc +0 -0
  1381. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__init__.py +0 -0
  1382. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/__init__.cpython-312.pyc +0 -0
  1383. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/credit_card_recognizer.cpython-312.pyc +0 -0
  1384. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/crypto_recognizer.cpython-312.pyc +0 -0
  1385. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/email_recognizer.cpython-312.pyc +0 -0
  1386. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/iban_patterns.cpython-312.pyc +0 -0
  1387. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/iban_recognizer.cpython-312.pyc +0 -0
  1388. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/ip_recognizer.cpython-312.pyc +0 -0
  1389. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/mac_recognizer.cpython-312.pyc +0 -0
  1390. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/url_recognizer.cpython-312.pyc +0 -0
  1391. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/credit_card_recognizer.py +82 -0
  1392. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/crypto_recognizer.py +141 -0
  1393. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/date_recognizer.py +102 -0
  1394. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/email_recognizer.py +48 -0
  1395. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/iban_patterns.py +173 -0
  1396. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/iban_recognizer.py +221 -0
  1397. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/ip_recognizer.py +65 -0
  1398. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/mac_recognizer.py +73 -0
  1399. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/url_recognizer.py +50 -0
  1400. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/gliner_recognizer.py +218 -0
  1401. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/spacy_recognizer.py +139 -0
  1402. package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/recognizer_result.py +188 -0
  1403. package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +29 -0
  1404. package/server/piecemaker/vendor/websocket-server/scripts/scan_utils.py +469 -0
  1405. package/server/piecemaker/vendor/websocket-server/scripts/smart_converter.py +356 -0
  1406. package/server/piecemaker/vendor/websocket-server/scripts/warmup.py +454 -0
  1407. package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +334 -0
  1408. package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +602 -0
  1409. package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +22 -0
  1410. package/server/shared/claude-cli-path.ts +157 -0
  1411. package/server/shared/frontmatter.ts +18 -0
  1412. package/server/shared/image-attachments.ts +437 -0
  1413. package/server/shared/interfaces.ts +241 -0
  1414. package/server/shared/message-unification.ts +449 -0
  1415. package/server/shared/tests/application-data-root.test.ts +29 -0
  1416. package/server/shared/tests/claude-cli-path.test.ts +118 -0
  1417. package/server/shared/tests/image-attachments.test.ts +353 -0
  1418. package/server/shared/tests/message-unification.test.ts +218 -0
  1419. package/server/shared/tests/slice-tail-page.test.ts +42 -0
  1420. package/server/shared/types.ts +1354 -0
  1421. package/server/shared/utils.ts +1212 -0
  1422. package/server/tsconfig.json +40 -0
  1423. package/shared/networkHosts.js +22 -0
  1424. package/shared/product-config.mjs +86 -0
@@ -0,0 +1,1984 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Convert & Scan Pipeline โ€” orchestrates document conversion and PII scanning.
4
+
5
+ This script chains smart_converter.py (conversion to Markdown) and
6
+ presidio-gliner.py (PII scanning) for batch processing of multiple documents.
7
+
8
+ Usage:
9
+ python3 convert_and_scan_pipeline.py <file1> [file2 ...] -o <output_dir> [options]
10
+
11
+ Options:
12
+ -o, --output DIR Output directory for all generated files
13
+ --engine ENGINE Conversion engine: auto|markitdown|mineru (default: auto)
14
+ --mode MODE MinerU mode: pipeline|hybrid|vlm (default: pipeline)
15
+ --lang CODE OCR language code for MinerU (default: auto)
16
+
17
+ Progress Format:
18
+ PROGRESS:CONVERT:percentage:current:total (Phase 1: Converting documents)
19
+ PROGRESS:SCAN:percentage:current:total (Phase 2: Scanning for PII)
20
+
21
+ Persistent Output Structure:
22
+ {output_dir}/
23
+ โ”œโ”€โ”€ document1.md
24
+ โ”œโ”€โ”€ document2.md
25
+ โ”œโ”€โ”€ mapping_default.json
26
+ โ””โ”€โ”€ .piecemaker/anonymization-state.json
27
+
28
+ The per-document sensitive maps are transient scanner payloads. They are
29
+ created in a private temporary directory, merged into mapping_default.json,
30
+ then removed automatically.
31
+
32
+ Exit Codes:
33
+ 0: Success (at least one file fully processed)
34
+ 1: No file could be fully converted and scanned
35
+ """
36
+
37
+ import sys
38
+ import os
39
+ import time
40
+ import argparse
41
+ import subprocess
42
+ import json
43
+ import hashlib
44
+ import tempfile
45
+ import unicodedata
46
+ import re
47
+ from pathlib import Path
48
+ from typing import List, Optional, Tuple, Dict, Set
49
+
50
+
51
+ def print_progress(phase: str, current: int, total: int) -> None:
52
+ """Print standardized progress message.
53
+
54
+ Args:
55
+ phase: 'CONVERT' or 'SCAN'
56
+ current: Current file index (1-based)
57
+ total: Total number of files
58
+ """
59
+ percentage = int((current / total) * 100)
60
+ print(f"PROGRESS:{phase}:{percentage}:{current}:{total}", flush=True)
61
+
62
+
63
+ def start_scanner_worker() -> Optional[subprocess.Popen]:
64
+ """Start the long-lived scanner worker subprocess.
65
+
66
+ The worker loads GLiNER2 + spaCy models once and stays alive to process
67
+ multiple files via a JSON-line stdin/stdout protocol. Launch this at the
68
+ start of the pipeline so model loading overlaps with Phase 1 (conversion).
69
+
70
+ Returns:
71
+ Worker subprocess handle, or None if the launch failed.
72
+ """
73
+ script_dir = Path(__file__).parent
74
+ worker_script = script_dir / "presidio-gliner" / "scanner_worker.py"
75
+
76
+ if not worker_script.exists():
77
+ print(f"โš ๏ธ scanner_worker.py not found at {worker_script}", file=sys.stderr)
78
+ return None
79
+
80
+ try:
81
+ proc = subprocess.Popen(
82
+ [sys.executable, str(worker_script)],
83
+ stdin=subprocess.PIPE,
84
+ stdout=subprocess.PIPE,
85
+ stderr=subprocess.PIPE,
86
+ text=True,
87
+ bufsize=1, # Line buffered
88
+ )
89
+ print(f"๐Ÿ”„ Scanner worker starting in background (PID {proc.pid})...")
90
+ return proc
91
+ except Exception as e:
92
+ print(f"โš ๏ธ Failed to start scanner worker: {e}", file=sys.stderr)
93
+ return None
94
+
95
+
96
+ def wait_for_worker_ready(proc: Optional[subprocess.Popen], timeout: int = 300) -> bool:
97
+ """Wait for the scanner worker to print READY on stdout.
98
+
99
+ While waiting, streams stderr output (model loading progress) in real-time.
100
+
101
+ Args:
102
+ proc: Worker subprocess
103
+ timeout: Max seconds to wait
104
+
105
+ Returns:
106
+ True if worker is ready, False on failure/timeout.
107
+ """
108
+ if proc is None:
109
+ return False
110
+
111
+ import re
112
+ import select
113
+ import threading
114
+
115
+ _chunk_re = re.compile(r"^PROGRESS:CHUNKS:\d+:\d+:\d+")
116
+
117
+ # Stream stderr in a background thread so we see model loading progress. The
118
+ # thread lives for the whole process, so it also carries the worker's per-chunk
119
+ # progress during a scan. A CHUNKS line is re-emitted CLEAN on stdout: the Node
120
+ # parent only reads stdout and requires a leading "PROGRESS:", so the "[worker]"
121
+ # prefix otherwise hid it and the admin bar stayed frozen on a long file. Only
122
+ # lines matching the strict pattern reach stdout โ€” never arbitrary worker stderr,
123
+ # which can carry document text under PIECEMAKER_DEBUG_ENTITIES.
124
+ def _stream_stderr():
125
+ try:
126
+ for line in proc.stderr:
127
+ stripped = line.strip()
128
+ if _chunk_re.match(stripped):
129
+ print(stripped, flush=True)
130
+ else:
131
+ print(f" [worker] {line}", end="", flush=True)
132
+ except (ValueError, OSError):
133
+ pass # Pipe closed
134
+
135
+ stderr_thread = threading.Thread(target=_stream_stderr, daemon=True)
136
+ stderr_thread.start()
137
+
138
+ start = time.time()
139
+ while time.time() - start < timeout:
140
+ if proc.poll() is not None:
141
+ print(f"โš ๏ธ Scanner worker exited prematurely (exit {proc.returncode})", file=sys.stderr)
142
+ return False
143
+
144
+ # Non-blocking read from stdout
145
+ try:
146
+ os.set_blocking(proc.stdout.fileno(), False)
147
+ line = proc.stdout.readline()
148
+ os.set_blocking(proc.stdout.fileno(), True)
149
+ except (IOError, OSError):
150
+ line = ""
151
+
152
+ if line.strip() == "READY":
153
+ print("โœ… Scanner worker ready (models loaded)")
154
+ return True
155
+
156
+ if not line:
157
+ time.sleep(0.1)
158
+
159
+ # Timeout
160
+ print("โš ๏ธ Scanner worker timed out waiting for READY", file=sys.stderr)
161
+ proc.kill()
162
+ return False
163
+
164
+
165
+ def scan_file_via_worker(proc: subprocess.Popen, md_file: str, output_dir: str) -> bool:
166
+ """Send a scan command to the worker and wait for the result.
167
+
168
+ Args:
169
+ proc: Worker subprocess
170
+ md_file: Path to markdown file
171
+ output_dir: Directory for output JSON
172
+
173
+ Returns:
174
+ True if scan succeeded, False otherwise.
175
+ """
176
+ cmd = json.dumps({"cmd": "scan", "md_file": md_file, "output_dir": output_dir})
177
+ try:
178
+ proc.stdin.write(cmd + "\n")
179
+ proc.stdin.flush()
180
+ except (BrokenPipeError, OSError) as e:
181
+ print(f"โš ๏ธ Failed to send command to worker: {e}", file=sys.stderr)
182
+ return False
183
+
184
+ # Read the JSON-line response (blocking)
185
+ try:
186
+ response_line = proc.stdout.readline()
187
+ except (IOError, OSError) as e:
188
+ print(f"โš ๏ธ Failed to read response from worker: {e}", file=sys.stderr)
189
+ return False
190
+
191
+ if not response_line:
192
+ print("โš ๏ธ Worker closed stdout unexpectedly", file=sys.stderr)
193
+ return False
194
+
195
+ try:
196
+ response = json.loads(response_line.strip())
197
+ except json.JSONDecodeError as e:
198
+ print(f"โš ๏ธ Invalid JSON from worker: {response_line.strip()}", file=sys.stderr)
199
+ return False
200
+
201
+ if response.get("status") == "ok":
202
+ return True
203
+ else:
204
+ print(f"โš ๏ธ Worker scan error: {response.get('message', 'unknown')}", file=sys.stderr)
205
+ return False
206
+
207
+
208
+ def stop_scanner_worker(proc: Optional[subprocess.Popen]) -> None:
209
+ """Gracefully stop the scanner worker."""
210
+ if proc is None or proc.poll() is not None:
211
+ return
212
+
213
+ try:
214
+ proc.stdin.write(json.dumps({"cmd": "quit"}) + "\n")
215
+ proc.stdin.flush()
216
+ proc.wait(timeout=10)
217
+ except Exception:
218
+ proc.kill()
219
+
220
+
221
+ def convert_file(
222
+ input_file: str,
223
+ output_dir: str,
224
+ engine: Optional[str] = None,
225
+ mode: Optional[str] = None,
226
+ lang: Optional[str] = None,
227
+ ) -> Tuple[bool, Optional[str]]:
228
+ """Run smart_converter.py subprocess to convert a file to Markdown with real-time output streaming.
229
+
230
+ Args:
231
+ input_file: Path to input document
232
+ output_dir: Directory for output markdown
233
+ engine: Conversion engine (auto/markitdown/mineru)
234
+ mode: MinerU mode (pipeline/hybrid/vlm)
235
+ lang: OCR language code
236
+
237
+ Returns:
238
+ (success, md_path): Tuple of success flag and path to generated .md file
239
+ """
240
+ script_dir = Path(__file__).parent
241
+ converter_script = script_dir / "smart_converter.py"
242
+
243
+ if not converter_script.exists():
244
+ print(f"โŒ smart_converter.py not found at {converter_script}", file=sys.stderr)
245
+ return False, None
246
+
247
+ # Build command
248
+ cmd = [sys.executable, str(converter_script), input_file, "-o", output_dir]
249
+
250
+ if engine:
251
+ cmd.extend(["--engine", engine])
252
+ if mode:
253
+ cmd.extend(["--mode", mode])
254
+ if lang:
255
+ cmd.extend(["--lang", lang])
256
+
257
+ try:
258
+ # Run converter with real-time output streaming
259
+ process = subprocess.Popen(
260
+ cmd,
261
+ stdout=subprocess.PIPE,
262
+ stderr=subprocess.PIPE,
263
+ text=True,
264
+ bufsize=1, # Line buffered
265
+ )
266
+
267
+ # Stream output in real-time
268
+ os.set_blocking(process.stdout.fileno(), False)
269
+ os.set_blocking(process.stderr.fileno(), False)
270
+
271
+ return_code = None
272
+ while return_code is None:
273
+ # Check if process has finished
274
+ return_code = process.poll()
275
+
276
+ # Read available output without blocking
277
+ try:
278
+ # Read stdout
279
+ while True:
280
+ line = process.stdout.readline()
281
+ if not line:
282
+ break
283
+ print(line, end="", flush=True)
284
+
285
+ # Read stderr
286
+ while True:
287
+ line = process.stderr.readline()
288
+ if not line:
289
+ break
290
+ print(line, end="", file=sys.stderr, flush=True)
291
+
292
+ except (IOError, OSError):
293
+ pass
294
+
295
+ # Small delay to prevent CPU spinning
296
+ if return_code is None:
297
+ time.sleep(0.01)
298
+
299
+ # Ensure we read any remaining output
300
+ try:
301
+ remaining_stdout, remaining_stderr = process.communicate(timeout=1)
302
+ if remaining_stdout:
303
+ print(remaining_stdout, end="", flush=True)
304
+ if remaining_stderr:
305
+ print(remaining_stderr, end="", file=sys.stderr, flush=True)
306
+ except subprocess.TimeoutExpired:
307
+ pass
308
+
309
+ if return_code != 0:
310
+ print(f"โš ๏ธ Conversion failed with exit code {return_code}", file=sys.stderr)
311
+ return False, None
312
+
313
+ # Determine generated .md file path
314
+ input_stem = Path(input_file).stem
315
+ md_path = Path(output_dir) / f"{input_stem}.md"
316
+
317
+ if not md_path.exists():
318
+ print(f"โš ๏ธ Expected output file not found: {md_path}", file=sys.stderr)
319
+ return False, None
320
+
321
+ return True, str(md_path)
322
+
323
+ except subprocess.TimeoutExpired:
324
+ print(f"โŒ Conversion timeout (>10 minutes): {input_file}", file=sys.stderr)
325
+ return False, None
326
+ except Exception as e:
327
+ print(f"โŒ Conversion error: {e}", file=sys.stderr)
328
+ return False, None
329
+
330
+
331
+ def scan_file(md_file: str, output_dir: str) -> bool:
332
+ """Run presidio-gliner.py subprocess to scan Markdown for PII with real-time output streaming.
333
+
334
+ Args:
335
+ md_file: Path to markdown file
336
+ output_dir: Directory for output JSON
337
+
338
+ Returns:
339
+ success: True if scan succeeded
340
+ """
341
+ script_dir = Path(__file__).parent
342
+ scanner_script = script_dir / "presidio-gliner" / "presidio-gliner.py"
343
+
344
+ if not scanner_script.exists():
345
+ print(f"โŒ presidio-gliner.py not found at {scanner_script}", file=sys.stderr)
346
+ return False
347
+
348
+ # Build command
349
+ cmd = [sys.executable, str(scanner_script), md_file, "-o", output_dir]
350
+
351
+ try:
352
+ # Run scanner with real-time output streaming
353
+ process = subprocess.Popen(
354
+ cmd,
355
+ stdout=subprocess.PIPE,
356
+ stderr=subprocess.PIPE,
357
+ text=True,
358
+ bufsize=1, # Line buffered
359
+ )
360
+
361
+ # Stream output in real-time
362
+ os.set_blocking(process.stdout.fileno(), False)
363
+ os.set_blocking(process.stderr.fileno(), False)
364
+
365
+ return_code = None
366
+ while return_code is None:
367
+ # Check if process has finished
368
+ return_code = process.poll()
369
+
370
+ # Read available output without blocking
371
+ try:
372
+ # Read stdout
373
+ while True:
374
+ line = process.stdout.readline()
375
+ if not line:
376
+ break
377
+ print(line, end="", flush=True)
378
+
379
+ # Read stderr
380
+ while True:
381
+ line = process.stderr.readline()
382
+ if not line:
383
+ break
384
+ print(line, end="", file=sys.stderr, flush=True)
385
+
386
+ except (IOError, OSError):
387
+ pass
388
+
389
+ # Small delay to prevent CPU spinning
390
+ if return_code is None:
391
+ time.sleep(0.01)
392
+
393
+ # Ensure we read any remaining output
394
+ try:
395
+ remaining_stdout, remaining_stderr = process.communicate(timeout=1)
396
+ if remaining_stdout:
397
+ print(remaining_stdout, end="", flush=True)
398
+ if remaining_stderr:
399
+ print(remaining_stderr, end="", file=sys.stderr, flush=True)
400
+ except subprocess.TimeoutExpired:
401
+ pass
402
+
403
+ if return_code != 0:
404
+ print(f"โš ๏ธ Scan failed with exit code {return_code}", file=sys.stderr)
405
+ return False
406
+
407
+ # Verify JSON output was created
408
+ md_stem = Path(md_file).stem
409
+ json_path = Path(output_dir) / f"{md_stem}_sensitive_map.json"
410
+
411
+ if not json_path.exists():
412
+ print(f"โš ๏ธ Expected JSON output not found: {json_path}", file=sys.stderr)
413
+ return False
414
+
415
+ return True
416
+
417
+ except subprocess.TimeoutExpired:
418
+ print(f"โŒ Scan timeout (>10 minutes): {md_file}", file=sys.stderr)
419
+ return False
420
+ except Exception as e:
421
+ print(f"โŒ Scan error: {e}", file=sys.stderr)
422
+ return False
423
+
424
+
425
+ def load_existing_mapping(mapping_path: Path) -> Optional[Dict]:
426
+ """Load the case/document mapping file if it exists.
427
+
428
+ This is the SAME file that the server uses (server.cjs line 2146),
429
+ ensuring single source of truth for mappings.
430
+
431
+ Args:
432
+ mapping_path: Full path to mapping_default.json (or an explicit target)
433
+
434
+ Returns:
435
+ Existing mapping data or None if file doesn't exist
436
+ """
437
+ if not mapping_path.exists():
438
+ print("โ„น๏ธ No existing mapping found, will create new one")
439
+ return None
440
+
441
+ try:
442
+ with open(mapping_path, 'r', encoding='utf-8') as f:
443
+ data = json.load(f)
444
+ print(f"โœ… Loaded existing mapping: {len(data.get('mapping', {}))} entries")
445
+ return data
446
+ except Exception as e:
447
+ print(f"โš ๏ธ Error loading existing mapping: {e}", file=sys.stderr)
448
+ return None
449
+
450
+
451
+ def read_individual_mappings(json_files: List[str]) -> Dict:
452
+ """Read and consolidate multiple individual _sensitive_map.json files.
453
+
454
+ Args:
455
+ json_files: List of paths to individual sensitive map files
456
+
457
+ Returns:
458
+ Consolidated entities dictionary
459
+ """
460
+ consolidated = {
461
+ "entities": {},
462
+ "summary": {
463
+ "total_entities_found": 0,
464
+ "entity_types": set(),
465
+ "source_files": []
466
+ }
467
+ }
468
+
469
+ for json_file in json_files:
470
+ if not os.path.exists(json_file):
471
+ print(f"โš ๏ธ Sensitive map not found: {json_file}", file=sys.stderr)
472
+ continue
473
+
474
+ with open(json_file, 'r', encoding='utf-8') as f:
475
+ data = json.load(f)
476
+
477
+ # Merge entities by type
478
+ for entity_type, entities in data.get("entities", {}).items():
479
+ if entity_type not in consolidated["entities"]:
480
+ consolidated["entities"][entity_type] = []
481
+ consolidated["entities"][entity_type].extend(entities)
482
+
483
+ # Update summary
484
+ consolidated["summary"]["source_files"].append(data.get("source_file", json_file))
485
+ consolidated["summary"]["entity_types"].update(data.get("summary", {}).get("entity_types", []))
486
+
487
+ # Convert set to list for JSON serialization
488
+ consolidated["summary"]["entity_types"] = sorted(list(consolidated["summary"]["entity_types"]))
489
+ consolidated["summary"]["total_entities_found"] = sum(
490
+ len(entities) for entities in consolidated["entities"].values()
491
+ )
492
+
493
+ return consolidated
494
+
495
+
496
+ def normalize_name(text: str) -> str:
497
+ """Normalize a name for comparison purposes.
498
+
499
+ Removes diacritics, converts to lowercase, removes honorifics/titles,
500
+ and normalizes whitespace.
501
+
502
+ Args:
503
+ text: Name to normalize
504
+
505
+ Returns:
506
+ Normalized name string (for comparison only)
507
+ """
508
+ # Remove diacritics (รฉ โ†’ e, ร  โ†’ a, etc.)
509
+ nfkd_form = unicodedata.normalize('NFKD', text)
510
+ text_no_accents = ''.join([c for c in nfkd_form if not unicodedata.combining(c)])
511
+
512
+ # Convert to lowercase
513
+ text_lower = text_no_accents.lower()
514
+
515
+ # Remove honorifics/titles (French and English)
516
+ # Matches: Mr., Mrs., Ms., Dr., M., Mme., Maรฎtre, etc.
517
+ # Important: "m." and "me." must have the dot to avoid matching "martin" or "marie"
518
+ honorifics_pattern = r'\b(mr\.?|mrs\.?|ms\.?|dr\.?|prof\.?|m\.|mme\.?|mlle\.?|maitre)\s*'
519
+ text_no_titles = re.sub(honorifics_pattern, '', text_lower, flags=re.IGNORECASE)
520
+
521
+ # Normalize whitespace (multiple spaces/newlines โ†’ single space)
522
+ text_normalized = ' '.join(text_no_titles.split())
523
+
524
+ return text_normalized.strip()
525
+
526
+
527
+ def are_names_similar(name1: str, norm1: str, name2: str, norm2: str) -> bool:
528
+ """Check if two names refer to the same person.
529
+
530
+ Uses multiple matching strategies:
531
+ - Exact match after normalization
532
+ - Substring match (one contains the other, min 3 chars)
533
+ - Token-based match (all tokens of shorter name appear in longer)
534
+
535
+ Args:
536
+ name1: First name (original)
537
+ norm1: First name (normalized)
538
+ name2: Second name (original)
539
+ norm2: Second name (normalized)
540
+
541
+ Returns:
542
+ True if names are similar enough to be considered the same person
543
+ """
544
+ # Exact match after normalization
545
+ if norm1 == norm2:
546
+ return True
547
+
548
+ # Substring match (one contains the other, min 3 chars)
549
+ min_length = min(len(norm1), len(norm2))
550
+ if min_length >= 3:
551
+ if norm1 in norm2 or norm2 in norm1:
552
+ return True
553
+
554
+ # Token-based match: all tokens of shorter name appear in longer
555
+ tokens1 = set(norm1.split())
556
+ tokens2 = set(norm2.split())
557
+
558
+ if not tokens1 or not tokens2:
559
+ return False
560
+
561
+ # Check if all tokens of shorter set appear in longer set
562
+ shorter_tokens = tokens1 if len(tokens1) <= len(tokens2) else tokens2
563
+ longer_tokens = tokens2 if len(tokens1) <= len(tokens2) else tokens1
564
+
565
+ if shorter_tokens and shorter_tokens.issubset(longer_tokens):
566
+ return True
567
+
568
+ return False
569
+
570
+
571
+ def consolidate_duplicate_entities(entities: List[Dict]) -> List[Dict]:
572
+ """Consolidate duplicate entities into single entries with variants.
573
+
574
+ Groups entities by similarity (exact duplicates and variations like
575
+ "Mr. Gilly" vs "Bernard Gilly"), choosing the longest variant as
576
+ canonical and storing all unique variants.
577
+
578
+ Args:
579
+ entities: List of entity dictionaries with 'text', 'score', etc.
580
+
581
+ Returns:
582
+ Deduplicated entity list with consolidated variants
583
+ """
584
+ if not entities:
585
+ return []
586
+
587
+ # Pre-compute normalized forms
588
+ entities_with_norm = [
589
+ {**entity, '_normalized': normalize_name(entity['text'])}
590
+ for entity in entities
591
+ ]
592
+
593
+ # Group similar entities
594
+ groups = []
595
+ used_indices = set()
596
+
597
+ for i, entity1 in enumerate(entities_with_norm):
598
+ if i in used_indices:
599
+ continue
600
+
601
+ # Start a new group with this entity
602
+ group = [entity1]
603
+ used_indices.add(i)
604
+
605
+ # Find all similar entities
606
+ for j, entity2 in enumerate(entities_with_norm):
607
+ if j in used_indices:
608
+ continue
609
+
610
+ if are_names_similar(
611
+ entity1['text'], entity1['_normalized'],
612
+ entity2['text'], entity2['_normalized']
613
+ ):
614
+ group.append(entity2)
615
+ used_indices.add(j)
616
+
617
+ groups.append(group)
618
+
619
+ # Consolidate each group
620
+ consolidated = []
621
+
622
+ for group in groups:
623
+ # Choose longest variant as canonical text
624
+ canonical = max(group, key=lambda e: len(e['text']))
625
+
626
+ # Get highest score
627
+ best_score = max(e.get('score', 0.0) for e in group)
628
+
629
+ # Collect all unique variants (remove duplicates while preserving order)
630
+ all_variants = [e['text'] for e in group]
631
+ unique_variants = list(dict.fromkeys(all_variants)) # Preserves order, removes duplicates
632
+
633
+ # Create consolidated entry
634
+ consolidated_entity = {
635
+ 'text': canonical['text'],
636
+ 'score': best_score,
637
+ 'recognizer': canonical.get('recognizer', 'unknown'),
638
+ 'variants': unique_variants
639
+ }
640
+
641
+ consolidated.append(consolidated_entity)
642
+
643
+ return consolidated
644
+
645
+
646
+ def is_known_city_or_country(text: str) -> bool:
647
+ """Check if text matches known city or country names.
648
+
649
+ Args:
650
+ text: Text to check
651
+
652
+ Returns:
653
+ True if text is a known city or country name
654
+ """
655
+ known_locations = {
656
+ 'paris', 'lyon', 'marseille', 'toulouse', 'nice', 'nantes',
657
+ 'bordeaux', 'lille', 'rennes', 'strasbourg', 'montpellier',
658
+ 'reims', 'le havre', 'saint-รฉtienne', 'toulon', 'grenoble',
659
+ 'dijon', 'angers', 'nรฎmes', 'villeurbanne', 'clermont-ferrand',
660
+ 'aix-en-provence', 'brest', 'limoges', 'tours', 'amiens',
661
+ 'perpignan', 'metz', 'besanรงon', 'orlรฉans', 'rouen',
662
+ 'bruxelles', 'genรจve', 'lausanne', 'luxembourg',
663
+ 'france', 'belgique', 'suisse', 'luxembourg'
664
+ }
665
+ return text.strip().lower() in known_locations
666
+
667
+
668
+ def is_city_or_country_only(text: str) -> bool:
669
+ """Check if text is only a city or country name (no street number).
670
+
671
+ Args:
672
+ text: Address text to check
673
+
674
+ Returns:
675
+ True if text appears to be only a city/country (no street address)
676
+ """
677
+ # No digits = likely just city/country
678
+ if not re.search(r'\d', text):
679
+ # Check against known cities/countries
680
+ return is_known_city_or_country(text)
681
+ return False
682
+
683
+
684
+ def parse_address(address_text: str) -> Dict:
685
+ """Parse address into street, city, postal, country components.
686
+
687
+ Supports French and basic international patterns (Belgium, Switzerland, Luxembourg).
688
+
689
+ Args:
690
+ address_text: Full address string
691
+
692
+ Returns:
693
+ Dictionary with parsing results:
694
+ {
695
+ "success": bool, # True if parsing succeeded
696
+ "is_city_only": bool, # True if only city/country (no street)
697
+ "street_part": Optional[str], # Street to anonymize
698
+ "postal_code": Optional[str],
699
+ "city": Optional[str],
700
+ "country": Optional[str],
701
+ "anonymization_strategy": "none" | "partial" | "full"
702
+ }
703
+ """
704
+ # Check if it's ONLY a city/country name (no street number)
705
+ if is_city_or_country_only(address_text):
706
+ # Extract city name (simple approach for known cities)
707
+ city_name = address_text.strip()
708
+ return {
709
+ "success": True,
710
+ "is_city_only": True,
711
+ "street_part": None,
712
+ "postal_code": None,
713
+ "city": city_name,
714
+ "country": None,
715
+ "anonymization_strategy": "none" # Keep visible
716
+ }
717
+
718
+ # French address pattern
719
+ # Pattern: [Number] [Type] [Name], [Postal] [City], [Country]
720
+ # Examples:
721
+ # "123 Rue de Rivoli, 75001 Paris, France"
722
+ # "11 rue Heinrich, Lyon"
723
+ # "20 Bis rue de la Princesse"
724
+ french_pattern = re.compile(
725
+ r'''
726
+ # Street number (required): 123, 20 Bis, 11 ter
727
+ (?P<street_number>\d+(?:\s*(?:[Bb]is|[Tt]er|[Qq]uater|[AaBb]))?)
728
+ \s+
729
+
730
+ # Street type: rue, avenue, boulevard, etc.
731
+ (?P<street_type>
732
+ (?:[Rr]ue|[Aa]venue|[Aa]v|[Bb]oulevard|[Bb]d|[Pp]lace|[Pp]l|
733
+ [Cc]hemin|[Aa]llรฉe|[Ii]mpasse|[Pp]assage|[Qq]uai|[Cc]ours|
734
+ [Rr]oute|[Vv]oie|[Ss]quare)
735
+ )
736
+ \s+
737
+
738
+ # Street name: everything until postal/city marker (greedy until comma or end)
739
+ (?P<street_name>
740
+ (?:[Dd]e\s+|[Ll]a\s+|[Ll]'\s*|[Dd]u\s+|[Dd]es\s+)? # Articles
741
+ [A-Zร€-ลธa-zร -รฟ0-9\s'-]+ # Name (greedy - captures until comma or end)
742
+ )
743
+ (?=,|\s*$|\s+\d{5}) # Lookahead: stop at comma, end of string, or postal code
744
+
745
+ # Optional: Postal code + City OR just City
746
+ (?:
747
+ ,?\s*
748
+ (?:
749
+ # Option 1: Postal code + City
750
+ (?P<postal_code>\d{5})
751
+ \s+
752
+ (?P<city>[A-Zร€-ลธ][A-Zร€-ลธa-zร -รฟ-]+(?:\s+[A-Zร€-ลธa-zร -รฟ-]+)*)
753
+ |
754
+ # Option 2: Just City (no postal code)
755
+ (?P<city_only>[A-Zร€-ลธ][A-Zร€-ลธa-zร -รฟ-]+(?:\s+[A-Zร€-ลธa-zร -รฟ-]+)*)
756
+ )
757
+ )?
758
+
759
+ # Optional: Country
760
+ (?:
761
+ ,?\s*
762
+ (?P<country>France|Belgique|Suisse|Luxembourg)
763
+ )?
764
+ ''',
765
+ re.VERBOSE
766
+ )
767
+
768
+ # Belgian pattern: "Rue de la Loi 123, 1000 Bruxelles, Belgique"
769
+ belgian_pattern = re.compile(
770
+ r'''
771
+ ^ # Must start at beginning (prevents matching after French number)
772
+ # Street type + name first (Belgian style)
773
+ (?P<street_type>
774
+ (?:[Rr]ue|[Aa]venue|[Bb]oulevard|[Pp]lace|[Cc]haussรฉe)
775
+ )
776
+ \s+
777
+ (?P<street_name>
778
+ (?:[Dd]e\s+|[Ll]a\s+|[Dd]u\s+|[Dd]es\s+)?
779
+ [A-Zร€-ลธa-zร -รฟ0-9\s'-]+ # Greedy
780
+ )
781
+ \s+
782
+ # Street number at the end
783
+ (?P<street_number>\d+(?:\s*(?:[Bb]is|[A-Za-z])?)?)
784
+ (?=,|\s*$) # Lookahead: stop at comma or end
785
+
786
+ # Optional: Postal code + City
787
+ (?:
788
+ ,?\s*
789
+ (?P<postal_code>\d{4})
790
+ \s+
791
+ (?P<city>[A-Zร€-ลธ][A-Zร€-ลธa-zร -รฟ-]+(?:\s+[A-Zร€-ลธa-zร -รฟ-]+)*)
792
+ )?
793
+
794
+ # Optional: Country
795
+ (?:
796
+ ,?\s*
797
+ (?P<country>Belgique|Belgium)
798
+ )?
799
+ ''',
800
+ re.VERBOSE
801
+ )
802
+
803
+ # Swiss pattern: "Rue du Rhรดne 50, 1204 Genรจve, Suisse"
804
+ swiss_pattern = re.compile(
805
+ r'''
806
+ ^ # Must start at beginning
807
+ # Street type + name first
808
+ (?P<street_type>
809
+ (?:[Rr]ue|[Aa]venue|[Cc]hemin|[Pp]lace)
810
+ )
811
+ \s+
812
+ (?P<street_name>
813
+ (?:[Dd]e\s+|[Ll]a\s+|[Dd]u\s+|[Dd]es\s+)?
814
+ [A-Zร€-ลธa-zร -รฟ0-9\s'-]+ # Greedy
815
+ )
816
+ \s+
817
+ # Street number
818
+ (?P<street_number>\d+(?:\s*[A-Za-z])?)
819
+ (?=,|\s*$) # Lookahead: stop at comma or end
820
+
821
+ # Optional: Postal code + City
822
+ (?:
823
+ ,?\s*
824
+ (?P<postal_code>\d{4})
825
+ \s+
826
+ (?P<city>[A-Zร€-ลธ][A-Zร€-ลธa-zร -รฟ-]+(?:\s+[A-Zร€-ลธa-zร -รฟ-]+)*)
827
+ )?
828
+
829
+ # Optional: Country
830
+ (?:
831
+ ,?\s*
832
+ (?P<country>Suisse|Switzerland)
833
+ )?
834
+ ''',
835
+ re.VERBOSE
836
+ )
837
+
838
+ # Luxembourg pattern: "Avenue de la Libertรฉ 10, L-1931 Luxembourg"
839
+ luxembourg_pattern = re.compile(
840
+ r'''
841
+ ^ # Must start at beginning
842
+ # Street type + name first
843
+ (?P<street_type>
844
+ (?:[Aa]venue|[Rr]ue|[Bb]oulevard|[Pp]lace)
845
+ )
846
+ \s+
847
+ (?P<street_name>
848
+ (?:[Dd]e\s+|[Ll]a\s+|[Dd]u\s+|[Dd]es\s+)?
849
+ [A-Zร€-ลธa-zร -รฟ0-9\s'-]+ # Greedy
850
+ )
851
+ \s+
852
+ # Street number
853
+ (?P<street_number>\d+(?:\s*[A-Za-z])?)
854
+ (?=,|\s*$) # Lookahead: stop at comma or end
855
+
856
+ # Optional: Postal code + City
857
+ (?:
858
+ ,?\s*
859
+ (?P<postal_code>L-\d{4})
860
+ \s+
861
+ (?P<city>[A-Zร€-ลธ][A-Zร€-ลธa-zร -รฟ-]+(?:\s+[A-Zร€-ลธa-zร -รฟ-]+)*)
862
+ )?
863
+
864
+ # Optional: Country
865
+ (?:
866
+ ,?\s*
867
+ (?P<country>Luxembourg)
868
+ )?
869
+ ''',
870
+ re.VERBOSE
871
+ )
872
+
873
+ # Smart pattern ordering based on distinguishing features
874
+ # This prevents Belgian pattern from matching Swiss/Luxembourg addresses
875
+ pattern_configs = []
876
+
877
+ # Check for distinguishing features to prioritize patterns
878
+ if 'L-' in address_text and re.search(r'L-\d{4}', address_text):
879
+ # Luxembourg postal code detected
880
+ pattern_configs = [
881
+ (luxembourg_pattern, 'luxembourg'),
882
+ (belgian_pattern, 'belgian'),
883
+ (swiss_pattern, 'swiss'),
884
+ (french_pattern, 'french')
885
+ ]
886
+ elif 'Suisse' in address_text or 'Switzerland' in address_text:
887
+ # Swiss country detected
888
+ pattern_configs = [
889
+ (swiss_pattern, 'swiss'),
890
+ (belgian_pattern, 'belgian'),
891
+ (luxembourg_pattern, 'luxembourg'),
892
+ (french_pattern, 'french')
893
+ ]
894
+ elif 'Belgique' in address_text or 'Belgium' in address_text:
895
+ # Belgian country detected
896
+ pattern_configs = [
897
+ (belgian_pattern, 'belgian'),
898
+ (swiss_pattern, 'swiss'),
899
+ (luxembourg_pattern, 'luxembourg'),
900
+ (french_pattern, 'french')
901
+ ]
902
+ else:
903
+ # Default order: Belgian/Swiss/Luxembourg first (number at end), then French (number first)
904
+ pattern_configs = [
905
+ (belgian_pattern, 'belgian'),
906
+ (swiss_pattern, 'swiss'),
907
+ (luxembourg_pattern, 'luxembourg'),
908
+ (french_pattern, 'french')
909
+ ]
910
+
911
+ for pattern, pattern_type in pattern_configs:
912
+ match = pattern.search(address_text)
913
+ if match and match.group('street_number'):
914
+ # SUCCESS: Partial anonymization
915
+ groups = match.groupdict()
916
+
917
+ # Build street part (what gets anonymized)
918
+ # Belgian/Swiss/Luxembourg: street_type + street_name + number
919
+ # French: number + street_type + street_name
920
+ if pattern_type in ('belgian', 'swiss', 'luxembourg'):
921
+ # Number at the end
922
+ street_components = []
923
+ if groups.get('street_type'):
924
+ street_components.append(groups['street_type'])
925
+ if groups.get('street_name'):
926
+ street_components.append(groups['street_name'].strip())
927
+ if groups.get('street_number'):
928
+ street_components.append(groups['street_number'])
929
+ else:
930
+ # French: Number at the beginning
931
+ street_components = []
932
+ if groups.get('street_number'):
933
+ street_components.append(groups['street_number'])
934
+ if groups.get('street_type'):
935
+ street_components.append(groups['street_type'])
936
+ if groups.get('street_name'):
937
+ street_components.append(groups['street_name'].strip())
938
+
939
+ street_part = ' '.join(street_components)
940
+
941
+ # Handle French pattern's city_only capture group
942
+ city = groups.get('city') or groups.get('city_only')
943
+
944
+ return {
945
+ "success": True,
946
+ "is_city_only": False,
947
+ "street_part": street_part,
948
+ "postal_code": groups.get('postal_code'),
949
+ "city": city,
950
+ "country": groups.get('country'),
951
+ "anonymization_strategy": "partial"
952
+ }
953
+
954
+ # FAILURE: Full anonymization (safest - prevents accidental exposure)
955
+ return {
956
+ "success": False,
957
+ "is_city_only": False,
958
+ "street_part": address_text,
959
+ "postal_code": None,
960
+ "city": None,
961
+ "country": None,
962
+ "anonymization_strategy": "full"
963
+ }
964
+
965
+
966
+ # ---------------------------------------------------------------------------
967
+ # Sociรฉtรฉ codes : le sigle sert de prรฉfixe (SA_1, SARL_1, SCI_1, GMBH_1, LLC_1โ€ฆ)
968
+ # ---------------------------------------------------------------------------
969
+ # Une organisation dont le nom (ou son contexte immรฉdiat) porte une forme juridique
970
+ # โ€” dรฉtectรฉe littรฉralement par scan_utils.extract_legal_form, qui a typรฉ l'entitรฉ
971
+ # ORGANIZATION_<sigle> โ€” est codรฉe <sigle>_<n>. Sans sigle, elle tombe sur
972
+ # PERS_MORALE_<n>. Chaque sigle a son propre compteur (SA_1, SA_2, puis SARL_1โ€ฆ),
973
+ # non paddรฉ, conformรฉment au choix du cabinet. Les personnes/adresses gardent leur
974
+ # padding _01. Ce vocabulaire est reflรฉtรฉ ร  l'identique cรดtรฉ administration
975
+ # (`originals-pipeline.cjs`) : les deux chemins รฉcrivent le mรชme mapping.
976
+
977
+ def _societe_form_key(entity_type: str) -> str:
978
+ """Clรฉ de compteur / prรฉfixe de code d'une organisation.
979
+
980
+ ORGANIZATION_SA โ†’ 'SA' (code SA_1) ; ORGANIZATION nu โ†’ 'PERS_MORALE'.
981
+ """
982
+ if entity_type.startswith("ORGANIZATION_"):
983
+ return entity_type.split("_", 1)[1] or "PERS_MORALE"
984
+ return "PERS_MORALE"
985
+
986
+
987
+ def _societe_counter_key_of_code(code: str) -> str:
988
+ """Clรฉ de compteur d'un code sociรฉtรฉ dรฉjร  attribuรฉ (legacy compris).
989
+
990
+ SA_3 โ†’ 'SA' ; URGOT SA โ†’ 'SA' ; role-prรฉfixรฉ CLIENT_DEMANDEUR_SA_1 โ†’ 'SA' ;
991
+ PERS_MORALE_2 / PERSONNE_MORALE_01 โ†’ 'PERS_MORALE'. On lit le dernier segment
992
+ avant le numรฉro, sauf prรฉsence de MORALE (repli sans sigle).
993
+ """
994
+ body = re.sub(r"_\d+$", "", str(code)).upper()
995
+ tokens = [t for t in body.split("_") if t]
996
+ if "MORALE" in tokens:
997
+ return "PERS_MORALE"
998
+ return tokens[-1] if tokens else "PERS_MORALE"
999
+
1000
+
1001
+ def _next_societe_code(entity_type: str, societe_counters: Dict[str, int]) -> str:
1002
+ """Prochain code sociรฉtรฉ pour *entity_type*, en incrรฉmentant son compteur propre."""
1003
+ key = _societe_form_key(entity_type)
1004
+ n = societe_counters.get(key, 0) + 1
1005
+ societe_counters[key] = n
1006
+ return f"{key}_{n}"
1007
+
1008
+
1009
+ def convert_to_anonymization_format(consolidated_entities: Dict) -> Dict:
1010
+ """Convert consolidated entities to anonymization mapping format.
1011
+
1012
+ Expected output format matches what showMappingValidation() expects:
1013
+ {
1014
+ mapping: { "original_text": "CODE_01", ... },
1015
+ reverse_mapping: { "CODE_01": ["original_text"], ... },
1016
+ extracted_data: {
1017
+ personnes_physiques: { "CODE_01": {...}, ... },
1018
+ societes: { "CODE_02": {...}, ... },
1019
+ adresses: { "CODE_03": {...}, ... },
1020
+ siren: { "CODE_04": {...}, ... }
1021
+ }
1022
+ }
1023
+ """
1024
+ mapping = {}
1025
+ reverse_mapping = {}
1026
+ # Texts deliberately left readable (city-only locations, the non-street part
1027
+ # of a partially anonymised address). They go to `ignored` so that the admin
1028
+ # rebuild (originals-pipeline.cjs) does not code them back from the raw scan.
1029
+ left_visible: List[str] = []
1030
+ extracted_data = {
1031
+ "personnes_physiques": {},
1032
+ "societes": {},
1033
+ "adresses": {},
1034
+ "siren": {},
1035
+ "autres": {} # For emails, phones, etc.
1036
+ }
1037
+
1038
+ # Entity type to category mapping
1039
+ # ORGANIZATION_* variants (e.g. ORGANIZATION_SA, ORGANIZATION_GMBH) are handled
1040
+ # by the startswith fallback below โ€” no need to enumerate every legal form here.
1041
+ category_map = {
1042
+ "PERSON": "personnes_physiques",
1043
+ "ORGANIZATION": "societes",
1044
+ "LOCATION": "adresses",
1045
+ "EMAIL": "autres",
1046
+ "PHONE": "autres",
1047
+ "CREDIT_CARD": "autres",
1048
+ "IBAN": "autres",
1049
+ "IP_ADDRESS": "autres",
1050
+ "URL": "autres",
1051
+ }
1052
+
1053
+ # Code counters per category
1054
+ counters = {
1055
+ "personnes_physiques": 1,
1056
+ "societes": 1,
1057
+ "adresses": 1,
1058
+ "siren": 1,
1059
+ "autres": 1
1060
+ }
1061
+ # Sociรฉtรฉs : un compteur par sigle (SA, SARL, GMBHโ€ฆ) et un pour PERS_MORALE,
1062
+ # sรฉparรฉ de `counters["societes"]` qui n'est plus utilisรฉ pour les coder.
1063
+ societe_counters: Dict[str, int] = {}
1064
+
1065
+ # Track seen entities to avoid duplicates across files
1066
+ seen_entities = {} # text -> code
1067
+
1068
+ # Consolidate PERSON entities to remove duplicates
1069
+ for entity_type in consolidated_entities.get("entities", {}).keys():
1070
+ if entity_type == "PERSON":
1071
+ consolidated_entities["entities"][entity_type] = consolidate_duplicate_entities(
1072
+ consolidated_entities["entities"][entity_type]
1073
+ )
1074
+
1075
+ for entity_type, entities in consolidated_entities.get("entities", {}).items():
1076
+ # Scalable fallback: ORGANIZATION_SA, ORGANIZATION_GMBH, etc. โ†’ societes
1077
+ category = category_map.get(entity_type) or (
1078
+ "societes" if entity_type.startswith("ORGANIZATION_") else "autres"
1079
+ )
1080
+
1081
+ for entity in entities:
1082
+ text = entity["text"]
1083
+ text_lower = text.lower()
1084
+
1085
+ # Skip if already processed
1086
+ if text_lower in seen_entities:
1087
+ mapping[text] = seen_entities[text_lower]
1088
+ continue
1089
+
1090
+ # Generate code based on category
1091
+ if category == "personnes_physiques":
1092
+ code = f"PERSONNE_PHYSIQUE_{counters[category]:02d}"
1093
+ counters[category] += 1
1094
+ elif category == "societes":
1095
+ # Sigle en prรฉfixe (SA_1, SARL_1โ€ฆ) ou PERS_MORALE_1, compteur par sigle.
1096
+ code = _next_societe_code(entity_type, societe_counters)
1097
+ elif category == "adresses":
1098
+ code = f"ADRESSE_{counters[category]:02d}"
1099
+ counters[category] += 1
1100
+ elif category == "siren":
1101
+ code = f"SIREN_{counters[category]:02d}"
1102
+ counters[category] += 1
1103
+ else:
1104
+ code = f"{entity_type}_{counters[category]:02d}"
1105
+ counters[category] += 1
1106
+
1107
+ # Get variants from entity (pre-consolidated for PERSON entities)
1108
+ variants = entity.get("variants", [text])
1109
+
1110
+ # Store mappings for all variants (no lowercase duplicates)
1111
+ for variant in variants:
1112
+ mapping[variant] = code
1113
+
1114
+ reverse_mapping[code] = [text] # Principal value (array for consistency)
1115
+ seen_entities[text_lower] = code
1116
+
1117
+ # Store in extracted_data
1118
+ extracted_data[category][code] = {
1119
+ "original": text,
1120
+ "code": code,
1121
+ "variants": variants,
1122
+ "score": entity.get("score", 1.0),
1123
+ "recognizer": entity.get("recognizer", "unknown")
1124
+ }
1125
+
1126
+ # Parse addresses for partial anonymization
1127
+ if category == "adresses":
1128
+ parsed_result = parse_address(text)
1129
+ extracted_data[category][code]["parsed"] = parsed_result
1130
+
1131
+ # If city-only, don't add to mapping (no anonymization needed)
1132
+ if parsed_result.get("is_city_only"):
1133
+ # Remove from mapping - city names stay visible
1134
+ for variant in variants:
1135
+ mapping.pop(variant, None)
1136
+ left_visible.extend(variants)
1137
+ reverse_mapping.pop(code, None)
1138
+ del extracted_data[category][code]
1139
+ counters[category] -= 1 # Revert counter
1140
+ elif parsed_result.get("anonymization_strategy") == "partial":
1141
+ # Update mapping to only anonymize street part
1142
+ # Remove full address from mapping
1143
+ for variant in variants:
1144
+ mapping.pop(variant, None)
1145
+ # Add only street part to mapping
1146
+ street_part = parsed_result.get("street_part")
1147
+ if street_part:
1148
+ mapping[street_part] = code
1149
+ # Update variants to only include street part
1150
+ extracted_data[category][code]["variants"] = [street_part]
1151
+ reverse_mapping[code] = [street_part]
1152
+ left_visible.extend(v for v in variants if v != street_part)
1153
+
1154
+ return {
1155
+ "mapping": mapping,
1156
+ "reverse_mapping": reverse_mapping,
1157
+ "extracted_data": extracted_data,
1158
+ **({"ignored": list(dict.fromkeys(left_visible))} if left_visible else {}),
1159
+ }
1160
+
1161
+
1162
+ def merge_with_existing_mapping(new_mapping: Dict, existing_mapping: Optional[Dict]) -> Dict:
1163
+ """Merge new mapping with existing mapping, avoiding duplicates.
1164
+
1165
+ Args:
1166
+ new_mapping: Newly generated mapping from current batch
1167
+ existing_mapping: Existing mapping data (or None)
1168
+
1169
+ Returns:
1170
+ Merged mapping data
1171
+ """
1172
+ if not existing_mapping:
1173
+ return new_mapping
1174
+
1175
+ # `ignored` is written by the admin editor (originals-pipeline.cjs): entities
1176
+ # the lawyer removed by hand are false positives and must not come back.
1177
+ ignored = [str(text).strip() for text in existing_mapping.get('ignored', []) if str(text).strip()]
1178
+ ignored_lower = {text.lower() for text in ignored}
1179
+ left_visible: List[str] = []
1180
+
1181
+ merged_mapping = {**existing_mapping.get('mapping', {})}
1182
+ merged_reverse = {**existing_mapping.get('reverse_mapping', {})}
1183
+ merged_extracted = {
1184
+ "personnes_physiques": {**existing_mapping.get('extracted_data', {}).get('personnes_physiques', {})},
1185
+ "societes": {**existing_mapping.get('extracted_data', {}).get('societes', {})},
1186
+ "adresses": {**existing_mapping.get('extracted_data', {}).get('adresses', {})},
1187
+ "siren": {**existing_mapping.get('extracted_data', {}).get('siren', {})},
1188
+ "autres": {**existing_mapping.get('extracted_data', {}).get('autres', {})}
1189
+ }
1190
+
1191
+ # Track seen entities to avoid duplicates
1192
+ seen_entities_lower = {k.lower(): v for k, v in merged_mapping.items()}
1193
+
1194
+ # Find highest existing code numbers per category
1195
+ code_counters = {
1196
+ "personnes_physiques": 1,
1197
+ "adresses": 1,
1198
+ "siren": 1,
1199
+ "autres": 1
1200
+ }
1201
+ # Sociรฉtรฉs : un compteur par sigle (SA, SARL, GMBHโ€ฆ) + PERS_MORALE, amorcรฉ
1202
+ # depuis les codes dรฉjร  prรฉsents. Le bucket `societes` d'extracted_data donne
1203
+ # les codes sociรฉtรฉ quelle que soit leur forme (bare SA_3 comme legacy
1204
+ # URGOT SA), lร  oรน un test par sous-chaรฎne ne reconnaรฎtrait pas SA_3.
1205
+ societe_counters: Dict[str, int] = {}
1206
+
1207
+ for code in merged_reverse.keys():
1208
+ if "PERSONNE_PHYSIQUE_" in code or code.startswith("DIRIGEANT_"):
1209
+ num = int(code.split("_")[-1])
1210
+ code_counters["personnes_physiques"] = max(code_counters["personnes_physiques"], num + 1)
1211
+ elif code.startswith("ADRESSE_"):
1212
+ num = int(code.split("_")[-1])
1213
+ code_counters["adresses"] = max(code_counters["adresses"], num + 1)
1214
+ elif code.startswith("SIREN_"):
1215
+ num = int(code.split("_")[-1])
1216
+ code_counters["siren"] = max(code_counters["siren"], num + 1)
1217
+
1218
+ for code in merged_extracted.get("societes", {}).keys():
1219
+ match = re.search(r"_(\d+)$", code)
1220
+ if not match:
1221
+ continue
1222
+ key = _societe_counter_key_of_code(code)
1223
+ societe_counters[key] = max(societe_counters.get(key, 0), int(match.group(1)) + 1)
1224
+
1225
+ # Merge new entries
1226
+ for text, code in new_mapping.get('mapping', {}).items():
1227
+ text_lower = text.lower()
1228
+
1229
+ # Skip if already exists (use existing code)
1230
+ if text_lower in seen_entities_lower:
1231
+ continue
1232
+
1233
+ # Skip entities the lawyer discarded from the mapping
1234
+ if text_lower in ignored_lower:
1235
+ continue
1236
+
1237
+ # Determine category
1238
+ category = None
1239
+ for cat_key in merged_extracted.keys():
1240
+ if code in new_mapping.get('extracted_data', {}).get(cat_key, {}):
1241
+ category = cat_key
1242
+ break
1243
+
1244
+ if not category:
1245
+ category = "autres"
1246
+
1247
+ # Generate new code with incremented counter
1248
+ if category == "personnes_physiques":
1249
+ new_code = f"PERSONNE_PHYSIQUE_{code_counters[category]:02d}"
1250
+ code_counters[category] += 1
1251
+ elif category == "societes":
1252
+ # Le sigle du code d'origine est prรฉservรฉ : SA_3 โ†’ SA_<n>, legacy
1253
+ # URGOT SA โ†’ SA_<n>, sinon PERS_MORALE_<n>. Compteur par sigle.
1254
+ key = _societe_counter_key_of_code(code)
1255
+ n = societe_counters.get(key, 0) + 1
1256
+ societe_counters[key] = n
1257
+ new_code = f"{key}_{n}"
1258
+ elif category == "adresses":
1259
+ new_code = f"ADRESSE_{code_counters[category]:02d}"
1260
+ code_counters[category] += 1
1261
+ elif category == "siren":
1262
+ new_code = f"SIREN_{code_counters[category]:02d}"
1263
+ code_counters[category] += 1
1264
+ else:
1265
+ # Extract entity type from new code
1266
+ entity_type = code.split("_")[0] if "_" in code else "AUTRE"
1267
+ new_code = f"{entity_type}_{code_counters[category]:02d}"
1268
+ code_counters[category] += 1
1269
+
1270
+ # Get variants from existing entry
1271
+ old_entry = new_mapping.get('extracted_data', {}).get(category, {}).get(code, {})
1272
+ variants = old_entry.get("variants", [text])
1273
+
1274
+ # Add all variants to merged structures (no lowercase duplicates)
1275
+ for variant in variants:
1276
+ merged_mapping[variant] = new_code
1277
+
1278
+ seen_entities_lower[text_lower] = new_code
1279
+
1280
+ # Update reverse mapping
1281
+ original = new_mapping.get('reverse_mapping', {}).get(code, [text])[0]
1282
+ merged_reverse[new_code] = [original]
1283
+
1284
+ # Update extracted_data
1285
+ merged_extracted[category][new_code] = {
1286
+ "original": original,
1287
+ "code": new_code,
1288
+ "variants": variants,
1289
+ "score": old_entry.get("score", 1.0),
1290
+ "recognizer": old_entry.get("recognizer", "unknown")
1291
+ }
1292
+
1293
+ # Parse addresses for partial anonymization (same logic as convert_to_anonymization_format)
1294
+ if category == "adresses":
1295
+ parsed_result = parse_address(original)
1296
+ merged_extracted[category][new_code]["parsed"] = parsed_result
1297
+
1298
+ # If city-only, don't add to mapping (no anonymization needed)
1299
+ if parsed_result.get("is_city_only"):
1300
+ # Remove from merged structures
1301
+ for variant in variants:
1302
+ merged_mapping.pop(variant, None)
1303
+ left_visible.extend(variants)
1304
+ merged_reverse.pop(new_code, None)
1305
+ del merged_extracted[category][new_code]
1306
+ # Don't increment counter since we're removing this entry
1307
+ elif parsed_result.get("anonymization_strategy") == "partial":
1308
+ # Update mapping to only anonymize street part
1309
+ # Remove full address from mapping
1310
+ for variant in variants:
1311
+ merged_mapping.pop(variant, None)
1312
+ # Add only street part to mapping
1313
+ street_part = parsed_result.get("street_part")
1314
+ if street_part:
1315
+ merged_mapping[street_part] = new_code
1316
+ # Update variants to only include street part
1317
+ merged_extracted[category][new_code]["variants"] = [street_part]
1318
+ merged_reverse[new_code] = [street_part]
1319
+ left_visible.extend(v for v in variants if v != street_part)
1320
+
1321
+ merged_ignored = list(dict.fromkeys(
1322
+ ignored + [str(text).strip() for text in new_mapping.get('ignored', []) if str(text).strip()] + left_visible
1323
+ ))
1324
+ return {
1325
+ "mapping": merged_mapping,
1326
+ "reverse_mapping": merged_reverse,
1327
+ "extracted_data": merged_extracted,
1328
+ "informations_dossier": existing_mapping.get("informations_dossier", {}),
1329
+ **({"ignored": merged_ignored} if merged_ignored else {}),
1330
+ }
1331
+
1332
+
1333
+ def save_mapping(mapping_path: Path, mapping_data: Dict) -> Path:
1334
+ """Save the merged mapping to the case/document mapping file.
1335
+
1336
+ Uses the SAME file as server.cjs (line 2146), ensuring the validated
1337
+ mapping can be read by GET /api/anonymize/mapping/:documentId.
1338
+
1339
+ Args:
1340
+ mapping_path: Full path to the mapping file to write
1341
+ mapping_data: Complete mapping data structure
1342
+
1343
+ Returns:
1344
+ Path to saved file
1345
+ """
1346
+ payload = {
1347
+ **mapping_data,
1348
+ "mapping": dict(sorted(
1349
+ mapping_data.get("mapping", {}).items(),
1350
+ key=lambda item: (-len(item[0]), item[0].casefold()),
1351
+ )),
1352
+ }
1353
+ mapping_path.parent.mkdir(parents=True, exist_ok=True)
1354
+ temporary = mapping_path.with_name(f"{mapping_path.name}.piecemaker-{os.getpid()}.tmp")
1355
+ with open(temporary, 'w', encoding='utf-8') as f:
1356
+ json.dump(payload, f, indent=2, ensure_ascii=False)
1357
+ f.write("\n")
1358
+ os.chmod(temporary, 0o600)
1359
+ os.replace(temporary, mapping_path)
1360
+
1361
+ return mapping_path
1362
+
1363
+
1364
+ def load_anonymization_state(state_path: Path) -> Dict:
1365
+ """Load the non-sensitive per-file processing manifest."""
1366
+ try:
1367
+ with open(state_path, "r", encoding="utf-8") as state_file:
1368
+ raw = json.load(state_file)
1369
+ except (FileNotFoundError, json.JSONDecodeError, OSError):
1370
+ raw = {}
1371
+ source_files = raw.get("files", {}) if isinstance(raw, dict) else {}
1372
+ files = {}
1373
+ if isinstance(source_files, dict):
1374
+ for key, entry in source_files.items():
1375
+ if not isinstance(entry, dict):
1376
+ continue
1377
+ if "size" in entry and "mtimeMs" in entry:
1378
+ legacy = {
1379
+ "size": entry["size"],
1380
+ "mtimeMs": entry["mtimeMs"],
1381
+ **({"updatedAt": entry["scannedAt"]} if entry.get("scannedAt") else {}),
1382
+ }
1383
+ files[key] = {"converted": legacy, "scanned": legacy}
1384
+ else:
1385
+ files[key] = {
1386
+ phase: value for phase, value in entry.items()
1387
+ if phase in ("converted", "scanned") and isinstance(value, dict)
1388
+ }
1389
+ return {"version": 1, "files": files}
1390
+
1391
+
1392
+ def anonymization_state_key(source_file: str, case_root: str) -> Optional[str]:
1393
+ """Hash source identity so the manifest itself contains no filename."""
1394
+ source = Path(source_file).resolve()
1395
+ try:
1396
+ identity = source.relative_to(Path(case_root).resolve()).as_posix()
1397
+ except ValueError:
1398
+ # Standalone CLI use can place outputs outside the input tree. Hashing
1399
+ # the absolute identity preserves --skip-existing without persisting it.
1400
+ identity = f"absolute:{source.as_posix()}"
1401
+ # Match the Node side (anonymization-state.cjs): an accented filename must
1402
+ # hash identically whether it reaches us as NFC or NFD, or the document-index
1403
+ # join drops it. Normalise to NFC on both sides, independent of the OS.
1404
+ identity = unicodedata.normalize("NFC", identity)
1405
+ return hashlib.sha256(identity.encode("utf-8")).hexdigest()
1406
+
1407
+
1408
+ def source_fingerprint(source_file: str) -> Dict:
1409
+ stat = os.stat(source_file)
1410
+ return {"size": stat.st_size, "mtimeMs": stat.st_mtime_ns // 1_000_000}
1411
+
1412
+
1413
+ def source_state_entry(state: Dict, source_file: str, case_root: str) -> Optional[Dict]:
1414
+ key = anonymization_state_key(source_file, case_root)
1415
+ return state.get("files", {}).get(key) if key else None
1416
+
1417
+
1418
+ def source_is_processed(state: Dict, source_file: str, case_root: str, phase: str) -> bool:
1419
+ entry = source_state_entry(state, source_file, case_root)
1420
+ if not isinstance(entry, dict):
1421
+ return False
1422
+ phase_entry = entry.get(phase)
1423
+ # Backward compatibility with the first, flat state format.
1424
+ if not isinstance(phase_entry, dict):
1425
+ phase_entry = entry if "size" in entry and "mtimeMs" in entry else None
1426
+ if not phase_entry:
1427
+ return False
1428
+ fingerprint = source_fingerprint(source_file)
1429
+ return phase_entry.get("size") == fingerprint["size"] and phase_entry.get("mtimeMs") == fingerprint["mtimeMs"]
1430
+
1431
+
1432
+ def source_is_converted(state: Dict, source_file: str, case_root: str) -> bool:
1433
+ return source_is_processed(state, source_file, case_root, "converted")
1434
+
1435
+
1436
+ def source_is_anonymized(state: Dict, source_file: str, case_root: str) -> bool:
1437
+ return source_is_processed(state, source_file, case_root, "scanned")
1438
+
1439
+
1440
+ def update_processing_state(state_path: Path, case_root: str, source_files: List[str], phase: str) -> None:
1441
+ """Atomically add successful conversions/scans without paths or entities."""
1442
+ if not source_files:
1443
+ return
1444
+ state = load_anonymization_state(state_path)
1445
+ updated_at = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
1446
+ for source_file in source_files:
1447
+ key = anonymization_state_key(source_file, case_root)
1448
+ if not key:
1449
+ continue
1450
+ fingerprint = {**source_fingerprint(source_file), "updatedAt": updated_at}
1451
+ entry = state["files"].get(key, {})
1452
+ entry[phase] = fingerprint
1453
+ if phase == "scanned":
1454
+ entry["converted"] = fingerprint
1455
+ state["files"][key] = entry
1456
+ state_path.parent.mkdir(parents=True, exist_ok=True)
1457
+ temporary = state_path.with_name(f"{state_path.name}.piecemaker-{os.getpid()}.tmp")
1458
+ with open(temporary, "w", encoding="utf-8") as state_file:
1459
+ json.dump(state, state_file, indent=2, ensure_ascii=False)
1460
+ state_file.write("\n")
1461
+ os.chmod(temporary, 0o600)
1462
+ os.replace(temporary, state_path)
1463
+
1464
+
1465
+ def update_anonymization_state(state_path: Path, case_root: str, source_files: List[str]) -> None:
1466
+ update_processing_state(state_path, case_root, source_files, "scanned")
1467
+
1468
+
1469
+ # ---------------------------------------------------------------------------
1470
+ # Per-document index โ€” chronology / nature / entity attribution
1471
+ # ---------------------------------------------------------------------------
1472
+ # The individual sensitive maps are the only place that knows which entities and
1473
+ # which document_meta belong to a given file; they are deleted right after the
1474
+ # merge, so the attribution has to be captured here. The persistent index keys
1475
+ # each document by the SAME hash the scan-state manifest uses (a filename can
1476
+ # carry a client's name), and stores only entity CODES plus the non-PII
1477
+ # nature/date/juridiction. It is never a source of clear PII on disk.
1478
+
1479
+ def load_document_index(index_path: Path) -> Dict:
1480
+ try:
1481
+ with open(index_path, "r", encoding="utf-8") as handle:
1482
+ raw = json.load(handle)
1483
+ except (FileNotFoundError, json.JSONDecodeError, OSError):
1484
+ raw = {}
1485
+ documents = raw.get("documents", {}) if isinstance(raw, dict) else {}
1486
+ overrides = raw.get("overrides", {}) if isinstance(raw, dict) else {}
1487
+ entity_decisions = raw.get("entityDecisions", {}) if isinstance(raw, dict) else {}
1488
+ revisions = raw.get("revisions", []) if isinstance(raw, dict) else []
1489
+ return {
1490
+ "version": 2,
1491
+ "documents": documents if isinstance(documents, dict) else {},
1492
+ # Corrections manuelles รฉcrites par le serveur Node : un re-scan met ร 
1493
+ # jour `documents`, mais ne doit jamais les effacer.
1494
+ "overrides": overrides if isinstance(overrides, dict) else {},
1495
+ # Les dรฉcisions locales d'entitรฉs et leur journal sont รฉgalement
1496
+ # append-only du point de vue du pipeline : seul le serveur admin les
1497
+ # modifie, un nouveau scan rafraรฎchit uniquement la dรฉtection brute.
1498
+ "entityDecisions": entity_decisions if isinstance(entity_decisions, dict) else {},
1499
+ "revisions": revisions if isinstance(revisions, list) else [],
1500
+ }
1501
+
1502
+
1503
+ def _mapping_code_lookup(final_mapping_data: Dict) -> Dict[str, str]:
1504
+ """Case-insensitive {variant -> code}, longest variant first so a short name
1505
+ that is a substring of a stored variant does not shadow the longer code."""
1506
+ lookup: Dict[str, str] = {}
1507
+ items = sorted(
1508
+ final_mapping_data.get("mapping", {}).items(),
1509
+ key=lambda kv: len(kv[0]),
1510
+ reverse=True,
1511
+ )
1512
+ for variant, code in items:
1513
+ key = str(variant).strip().lower()
1514
+ if key:
1515
+ lookup.setdefault(key, code)
1516
+ return lookup
1517
+
1518
+
1519
+ # Legal-form / generic tokens shared by company names and court names alike โ€”
1520
+ # excluded from the sensitive set so a real "Tribunal de commerce" is not scrubbed
1521
+ # because some mapped company is a "... SA".
1522
+ _FREE_TEXT_STOPWORDS = frozenset({
1523
+ "sarl", "sasu", "sociรฉtรฉ", "societe", "compagnie", "groupe", "group",
1524
+ "holding", "association", "syndicat", "france",
1525
+ })
1526
+
1527
+
1528
+ def _sensitive_tokens(final_mapping_data: Dict) -> Set[str]:
1529
+ """Distinctive tokens (>=4 chars) of every mapped entity.
1530
+
1531
+ Used to scrub free-text metadata (the juridiction): GLiNER's extract_json
1532
+ "juridiction" head routinely mis-captures a litigant's name as the court, and
1533
+ that name must never reach the non-PII index. Any free-text field sharing a
1534
+ token with a mapped entity is dropped rather than stored in clear.
1535
+ """
1536
+ tokens: Set[str] = set()
1537
+ for variant in final_mapping_data.get("mapping", {}):
1538
+ for token in re.findall(r"[a-zร -รฟ0-9]{4,}", str(variant).lower()):
1539
+ if token not in _FREE_TEXT_STOPWORDS:
1540
+ tokens.add(token)
1541
+ return tokens
1542
+
1543
+
1544
+ def _scrub_free_text(value, sensitive_tokens: Set[str]) -> Optional[str]:
1545
+ """Return the text, or None if it carries any mapped-entity token (PII)."""
1546
+ if not value:
1547
+ return None
1548
+ text = str(value).strip()
1549
+ if not text:
1550
+ return None
1551
+ found = set(re.findall(r"[a-zร -รฟ0-9]{4,}", text.lower()))
1552
+ # Noise-only extraction ("SA", "n/a", "RCS") carries no court name โ€” drop it.
1553
+ if not found:
1554
+ return None
1555
+ if found & sensitive_tokens:
1556
+ return None
1557
+ return text
1558
+
1559
+
1560
+ def _codes_for_entities(entities: Dict, code_lookup: Dict[str, str]) -> List[str]:
1561
+ codes: Set[str] = set()
1562
+ for entity_list in (entities or {}).values():
1563
+ if not isinstance(entity_list, list):
1564
+ continue
1565
+ for entity in entity_list:
1566
+ text = entity.get("text") if isinstance(entity, dict) else None
1567
+ if not text:
1568
+ continue
1569
+ code = code_lookup.get(str(text).strip().lower())
1570
+ if code:
1571
+ codes.add(code)
1572
+ return sorted(codes)
1573
+
1574
+
1575
+ def write_document_index(
1576
+ index_path: Path,
1577
+ case_root: str,
1578
+ scan_records: List[Dict],
1579
+ final_mapping_data: Dict,
1580
+ ) -> int:
1581
+ """Merge this run's scanned documents into <case>/.piecemaker/document-index.json.
1582
+
1583
+ Returns the number of document entries written/updated.
1584
+ """
1585
+ if not scan_records:
1586
+ return 0
1587
+ code_lookup = _mapping_code_lookup(final_mapping_data)
1588
+ sensitive_tokens = _sensitive_tokens(final_mapping_data)
1589
+ index = load_document_index(index_path)
1590
+ updated_at = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
1591
+ written = 0
1592
+ for record in scan_records:
1593
+ source = record.get("source")
1594
+ if not source:
1595
+ continue
1596
+ # The payload fields are captured in-memory before the transient scan
1597
+ # workspace is cleaned; fall back to re-reading json_path for standalone
1598
+ # callers (and tests) that pass the file directly.
1599
+ if "entities" in record or "document_meta" in record:
1600
+ entities = record.get("entities") or {}
1601
+ meta = record.get("document_meta") or {}
1602
+ else:
1603
+ try:
1604
+ with open(record.get("json_path"), "r", encoding="utf-8") as handle:
1605
+ data = json.load(handle)
1606
+ except (FileNotFoundError, json.JSONDecodeError, OSError, TypeError):
1607
+ continue
1608
+ entities = data.get("entities") or {}
1609
+ meta = data.get("document_meta") or {}
1610
+ key = anonymization_state_key(source, case_root)
1611
+ if not key:
1612
+ continue
1613
+ index["documents"][key] = {
1614
+ "nature": meta.get("nature"),
1615
+ "nature_confidence": meta.get("nature_confidence"),
1616
+ "doc_date": meta.get("doc_date"),
1617
+ "doc_date_iso": meta.get("doc_date_iso"),
1618
+ "localisation": _scrub_free_text(meta.get("juridiction"), sensitive_tokens),
1619
+ "personnes_visees": _codes_for_entities(entities, code_lookup),
1620
+ "updatedAt": updated_at,
1621
+ }
1622
+ written += 1
1623
+ if not written:
1624
+ return 0
1625
+ index_path.parent.mkdir(parents=True, exist_ok=True)
1626
+ temporary = index_path.with_name(f"{index_path.name}.piecemaker-{os.getpid()}.tmp")
1627
+ with open(temporary, "w", encoding="utf-8") as handle:
1628
+ # Index interne compact : moins de volume et de tokens ร  la lecture.
1629
+ json.dump(index, handle, ensure_ascii=False, separators=(",", ":"))
1630
+ handle.write("\n")
1631
+ os.chmod(temporary, 0o600)
1632
+ os.replace(temporary, index_path)
1633
+ return written
1634
+
1635
+
1636
+ def main():
1637
+ """Main pipeline orchestration."""
1638
+ parser = argparse.ArgumentParser(
1639
+ description="Convert documents to Markdown and scan for sensitive data",
1640
+ formatter_class=argparse.RawDescriptionHelpFormatter,
1641
+ epilog=__doc__,
1642
+ )
1643
+
1644
+ parser.add_argument(
1645
+ "files", nargs="+", help="Input files to process (PDF, DOCX, images, etc.)"
1646
+ )
1647
+ parser.add_argument(
1648
+ "-o",
1649
+ "--output",
1650
+ required=True,
1651
+ help="Output directory for Markdown files and mapping_default.json",
1652
+ )
1653
+ parser.add_argument(
1654
+ "--engine",
1655
+ choices=["auto", "markitdown", "mineru"],
1656
+ default="auto",
1657
+ help="Conversion engine (default: auto)",
1658
+ )
1659
+ parser.add_argument(
1660
+ "--mode",
1661
+ choices=["pipeline", "hybrid", "vlm"],
1662
+ help="MinerU processing mode (only used if engine=mineru)",
1663
+ )
1664
+ parser.add_argument("--lang", help="OCR language code (only used if engine=mineru)")
1665
+ parser.add_argument(
1666
+ "--document-id",
1667
+ default="default",
1668
+ help=argparse.SUPPRESS,
1669
+ )
1670
+ parser.add_argument(
1671
+ "--mapping-dir",
1672
+ default=None,
1673
+ help="Directory for mapping_default.json (default: same as --output)",
1674
+ )
1675
+ parser.add_argument(
1676
+ "--mapping-file",
1677
+ default=None,
1678
+ help="Exact mapping file to read and rewrite (overrides --mapping-dir)",
1679
+ )
1680
+ parser.add_argument(
1681
+ "--state-file",
1682
+ default=None,
1683
+ help="Technical scan-state manifest (default: <output>/.piecemaker/anonymization-state.json)",
1684
+ )
1685
+ parser.add_argument(
1686
+ "--case-root",
1687
+ default=None,
1688
+ help=(
1689
+ "Legal-case root used to key the scan-state manifest. Defaults to "
1690
+ "--output for standalone CLI use; the admin pipeline passes the case "
1691
+ "directory so state keys match even when --output is a subfolder."
1692
+ ),
1693
+ )
1694
+ parser.add_argument(
1695
+ "--skip-existing",
1696
+ action="store_true",
1697
+ help="Reuse existing Markdown and scans whose source fingerprint is unchanged",
1698
+ )
1699
+ args = parser.parse_args()
1700
+
1701
+ # Validate input files
1702
+ input_files = []
1703
+ for f in args.files:
1704
+ if not os.path.exists(f):
1705
+ print(f"โš ๏ธ File not found: {f}", file=sys.stderr)
1706
+ else:
1707
+ input_files.append(f)
1708
+
1709
+ if not input_files:
1710
+ print("โŒ No valid input files provided", file=sys.stderr)
1711
+ return 1
1712
+
1713
+ # Ensure output directory exists
1714
+ os.makedirs(args.output, exist_ok=True)
1715
+ mapping_target = (
1716
+ Path(args.mapping_file)
1717
+ if args.mapping_file
1718
+ else Path(args.mapping_dir or args.output) / "mapping_default.json"
1719
+ )
1720
+ state_target = Path(args.state_file) if args.state_file else Path(args.output) / ".piecemaker" / "anonymization-state.json"
1721
+ # Base pour les clรฉs du manifeste : le dossier juridique, dรฉcouplรฉ de --output
1722
+ # (dรฉsormais un sous-dossier). Les sources vivent sous le dossier, pas sous la
1723
+ # sortie ; sans ce dรฉcouplage leur clรฉ ne correspondrait plus ร  celle du Node.
1724
+ state_case_root = args.case_root or args.output
1725
+ anonymization_state = load_anonymization_state(state_target)
1726
+
1727
+ print(f"๐Ÿš€ Starting Convert & Scan Pipeline")
1728
+ print(f" Files: {len(input_files)}")
1729
+ print(f" Output: {args.output}")
1730
+ print(f" Engine: {args.engine}")
1731
+ if args.mode:
1732
+ print(f" Mode: {args.mode}")
1733
+ if args.lang:
1734
+ print(f" Language: {args.lang}")
1735
+ print()
1736
+
1737
+ # What is left to do, decided before anything runs: the scanner worker loads
1738
+ # ~1.1GB of GLiNER2.5 + spaCy weights, so it must only start when at least one
1739
+ # file actually needs a PII scan.
1740
+ def markdown_path(input_file: str) -> Path:
1741
+ return Path(args.output) / f"{Path(input_file).stem}.md"
1742
+
1743
+ scan_needed = any(
1744
+ not (args.skip_existing and source_is_anonymized(anonymization_state, f, state_case_root))
1745
+ for f in input_files
1746
+ )
1747
+
1748
+ # Start scanner worker immediately so model loading overlaps with Phase 1.
1749
+ if scan_needed:
1750
+ scanner_worker = start_scanner_worker()
1751
+ else:
1752
+ scanner_worker = None
1753
+ print("โœ… Every PII scan is already up to date โ€” GLiNER not started")
1754
+ print()
1755
+
1756
+ # Phase 1: Convert all files to Markdown
1757
+ print("=" * 70)
1758
+ print("PHASE 1: CONVERTING DOCUMENTS TO MARKDOWN")
1759
+ print("=" * 70)
1760
+ print()
1761
+
1762
+ md_files = []
1763
+ md_sources = {}
1764
+ converted_sources = []
1765
+ convert_success_count = 0
1766
+
1767
+ for i, input_file in enumerate(input_files, start=1):
1768
+ print_progress("CONVERT", i, len(input_files))
1769
+ existing_md = markdown_path(input_file)
1770
+
1771
+ state_entry = source_state_entry(anonymization_state, input_file, state_case_root)
1772
+ reusable_markdown = existing_md.exists() and (
1773
+ state_entry is None
1774
+ or source_is_converted(anonymization_state, input_file, state_case_root)
1775
+ )
1776
+ if args.skip_existing and reusable_markdown:
1777
+ print(f"๐Ÿ“„ [{i}/{len(input_files)}] Already converted, reusing: {existing_md.name}")
1778
+ md_files.append(str(existing_md))
1779
+ md_sources[str(existing_md)] = input_file
1780
+ converted_sources.append(input_file)
1781
+ convert_success_count += 1
1782
+ print()
1783
+ continue
1784
+
1785
+ print(f"๐Ÿ“„ [{i}/{len(input_files)}] Converting: {Path(input_file).name}")
1786
+
1787
+ success, md_path = convert_file(
1788
+ input_file, args.output, engine=args.engine, mode=args.mode, lang=args.lang
1789
+ )
1790
+
1791
+ if success and md_path:
1792
+ print(f" โœ… Markdown generated: {Path(md_path).name}")
1793
+ md_files.append(md_path)
1794
+ md_sources[md_path] = input_file
1795
+ converted_sources.append(input_file)
1796
+ convert_success_count += 1
1797
+ else:
1798
+ print(f" โŒ Conversion failed, skipping...")
1799
+
1800
+ print()
1801
+
1802
+ if not md_files:
1803
+ print("โŒ All conversions failed โ€” pipeline aborted", file=sys.stderr)
1804
+ return 1
1805
+
1806
+ print(
1807
+ f"โœ… Phase 1 complete: {convert_success_count}/{len(input_files)} files converted"
1808
+ )
1809
+ update_processing_state(state_target, state_case_root, converted_sources, "converted")
1810
+ print()
1811
+
1812
+ # Phase 2: Scan all Markdown files for PII
1813
+ print("=" * 70)
1814
+ print("PHASE 2: SCANNING FOR SENSITIVE DATA")
1815
+ print("=" * 70)
1816
+ print()
1817
+
1818
+ pending_scans = [
1819
+ md_file
1820
+ for md_file in md_files
1821
+ if not (
1822
+ args.skip_existing
1823
+ and source_is_anonymized(anonymization_state, md_sources[md_file], state_case_root)
1824
+ )
1825
+ ]
1826
+ skipped_scans = len(md_files) - len(pending_scans)
1827
+ if skipped_scans:
1828
+ print(f"โญ๏ธ {skipped_scans} file(s) already scanned, left untouched")
1829
+
1830
+ # Wait for the scanner worker to finish loading models.
1831
+ worker_ready = wait_for_worker_ready(scanner_worker) if pending_scans else False
1832
+
1833
+ if pending_scans and not worker_ready:
1834
+ print("โš ๏ธ Scanner worker not available, falling back to subprocess-per-file", file=sys.stderr)
1835
+ print()
1836
+
1837
+ scan_success_count = 0
1838
+ successful_scan_sources = []
1839
+ json_files = []
1840
+ # Keeps each scanned document's payload tied to its source so the per-document
1841
+ # index can attribute entity codes and metadata after the merge (the payloads
1842
+ # are deleted with the workspace below).
1843
+ scan_records: List[Dict] = []
1844
+ # Raw detections contain PII. They live only in a private OS temporary
1845
+ # directory and disappear after consolidation, including on exceptions.
1846
+ scan_workspace = tempfile.TemporaryDirectory(prefix="piecemaker-scans-")
1847
+ scan_output_dir = scan_workspace.name
1848
+
1849
+ for i, md_file in enumerate(pending_scans, start=1):
1850
+ print_progress("SCAN", i, len(pending_scans))
1851
+ print(f"๐Ÿ” [{i}/{len(pending_scans)}] Scanning: {Path(md_file).name}")
1852
+
1853
+ if worker_ready:
1854
+ success = scan_file_via_worker(scanner_worker, md_file, scan_output_dir)
1855
+ else:
1856
+ # Fallback: subprocess per file (old behavior)
1857
+ success = scan_file(md_file, scan_output_dir)
1858
+
1859
+ if success:
1860
+ json_path = Path(scan_output_dir) / f"{Path(md_file).stem}_sensitive_map.json"
1861
+ if not json_path.exists():
1862
+ print(f" โš ๏ธ Scanner reported success without a payload", file=sys.stderr)
1863
+ continue
1864
+ print(f" โœ… Sensitive entities collected")
1865
+ scan_success_count += 1
1866
+ successful_scan_sources.append(md_sources[md_file])
1867
+ json_files.append(str(json_path))
1868
+ scan_records.append({"source": md_sources[md_file], "json_path": str(json_path)})
1869
+ else:
1870
+ print(f" โš ๏ธ Scan failed, markdown preserved")
1871
+
1872
+ print()
1873
+
1874
+ # Shut down worker
1875
+ stop_scanner_worker(scanner_worker)
1876
+
1877
+ print(f"โœ… Phase 2 complete: {scan_success_count}/{len(pending_scans)} files scanned")
1878
+ print()
1879
+
1880
+ # Phase 3: Merge the transient detections into the one persistent mapping.
1881
+ print("=" * 70)
1882
+ print("PHASE 3: UPDATING THE CASE MAPPING")
1883
+ print("=" * 70)
1884
+ print()
1885
+
1886
+ if not json_files:
1887
+ scan_workspace.cleanup()
1888
+ if not pending_scans:
1889
+ print("โœ… No new scan to merge; mapping and processing state are already up to date")
1890
+ return 0
1891
+ print("โš ๏ธ No successful PII scan to merge", file=sys.stderr)
1892
+ print(f"โœ… Pipeline complete: {convert_success_count}/{len(input_files)} files converted")
1893
+ print()
1894
+ return 1
1895
+
1896
+ print(f"๐Ÿ“Š Step 1: Reading {len(json_files)} individual mapping(s)...")
1897
+
1898
+ # Read individual mappings
1899
+ consolidated = read_individual_mappings(json_files)
1900
+ # Capture each document's entities + metadata in memory before the transient
1901
+ # scan workspace is deleted, so the per-document index can be built once the
1902
+ # final mapping (and therefore the codes) is known further down.
1903
+ for record in scan_records:
1904
+ try:
1905
+ with open(record["json_path"], "r", encoding="utf-8") as handle:
1906
+ payload = json.load(handle)
1907
+ record["entities"] = payload.get("entities") or {}
1908
+ record["document_meta"] = payload.get("document_meta") or {}
1909
+ except (FileNotFoundError, json.JSONDecodeError, OSError, KeyError):
1910
+ record["entities"] = {}
1911
+ record["document_meta"] = {}
1912
+ scan_workspace.cleanup()
1913
+
1914
+ # Convert to anonymization format
1915
+ print("๐Ÿ”„ Step 2: Converting to anonymization format...")
1916
+ new_mapping_data = convert_to_anonymization_format(consolidated)
1917
+
1918
+ # Load existing mapping (if exists)
1919
+ print("๐Ÿ“‚ Step 3: Loading existing mapping...")
1920
+ existing_mapping = load_existing_mapping(mapping_target)
1921
+
1922
+ # Merge with existing mapping
1923
+ print("๐Ÿ”— Step 4: Merging with existing mapping...")
1924
+ final_mapping_data = merge_with_existing_mapping(new_mapping_data, existing_mapping)
1925
+
1926
+ # Save mapping (same file server uses)
1927
+ print("๐Ÿ’พ Step 5: Saving mapping...")
1928
+ mapping_path = save_mapping(mapping_target, final_mapping_data)
1929
+ update_anonymization_state(state_target, state_case_root, successful_scan_sources)
1930
+
1931
+ # Per-document index (chronology / nature / entity codes) lives next to the
1932
+ # scan-state manifest, keyed by the same hash so a filename is never stored.
1933
+ index_path = state_target.parent / "document-index.json"
1934
+ try:
1935
+ indexed = write_document_index(index_path, state_case_root, scan_records, final_mapping_data)
1936
+ if indexed:
1937
+ print(f"๐Ÿ—‚๏ธ Document index updated: {indexed} document(s)")
1938
+ except Exception as exc: # noqa: BLE001
1939
+ print(f"โš ๏ธ Document index update skipped: {exc}", file=sys.stderr)
1940
+
1941
+ print(f"โœ… Mapping saved to: {mapping_path}")
1942
+ print(f" โ€ข Total entities: {len(final_mapping_data['mapping'])} variants")
1943
+ print(f" โ€ข Unique codes: {len(final_mapping_data['reverse_mapping'])}")
1944
+ print(f"๐Ÿงน Step 6: Removed {len(json_files)} transient sensitive payload(s)")
1945
+ print()
1946
+
1947
+ # Summary
1948
+ print("=" * 70)
1949
+ print("PIPELINE COMPLETE")
1950
+ print("=" * 70)
1951
+ print(f"๐Ÿ“Š Results:")
1952
+ print(f" โ€ข Converted: {convert_success_count}/{len(input_files)} files")
1953
+ print(f" โ€ข Scanned: {scan_success_count}/{len(pending_scans)} files")
1954
+ print(f" โ€ข Entities mapped: {len(final_mapping_data['mapping'])} variants")
1955
+ print(f" โ€ข Unique entities: {len(final_mapping_data['reverse_mapping'])} codes")
1956
+ print(f"๐Ÿ“‚ Output directory: {args.output}")
1957
+ print(f"๐Ÿ“‹ Mapping file: {mapping_path}")
1958
+ print()
1959
+
1960
+ # Exit with success if at least one file was fully processed
1961
+ if scan_success_count > 0 or not pending_scans:
1962
+ return 0
1963
+ elif convert_success_count > 0:
1964
+ print(
1965
+ "โš ๏ธ Warning: All scans failed, but markdown files are available",
1966
+ file=sys.stderr,
1967
+ )
1968
+ return 0
1969
+ else:
1970
+ return 1
1971
+
1972
+
1973
+ if __name__ == "__main__":
1974
+ try:
1975
+ sys.exit(main())
1976
+ except KeyboardInterrupt:
1977
+ print("\n๐Ÿ›‘ Pipeline cancelled by user", file=sys.stderr)
1978
+ sys.exit(130)
1979
+ except Exception as e:
1980
+ print(f"\nโŒ Unexpected error: {e}", file=sys.stderr)
1981
+ import traceback
1982
+
1983
+ traceback.print_exc()
1984
+ sys.exit(1)