@piecemaker-legal/piecemaker 1.0.6 → 1.0.8

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 (217) hide show
  1. package/dist/assets/{abnfDiagram-VCTEODGH-DF7LFtT-.js → abnfDiagram-VCTEODGH-K8VucbQ5.js} +1 -1
  2. package/dist/assets/{arc-xOmjWeVH.js → arc-DUmCdRoC.js} +1 -1
  3. package/dist/assets/{architectureDiagram-5GKGNRK7-CESzNPwa.js → architectureDiagram-5GKGNRK7-DYhs5vqD.js} +1 -1
  4. package/dist/assets/{blockDiagram-I7D4REHJ-BjdN78Ad.js → blockDiagram-I7D4REHJ-DaXJ9nve.js} +1 -1
  5. package/dist/assets/{c4Diagram-7LVT6UL2-BcK9EDWT.js → c4Diagram-7LVT6UL2-BLbi-zPT.js} +1 -1
  6. package/dist/assets/channel-CJIq1vqf.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-DGUN1JFP.js → chunk-2Q5K7J3B-Bzs3gxaq.js} +1 -1
  8. package/dist/assets/{chunk-5VM5RSS4-BG3BBcFr.js → chunk-5VM5RSS4-CQNzml7k.js} +1 -1
  9. package/dist/assets/{chunk-F27PBJKO-CLIOfrF5.js → chunk-F27PBJKO-B8xedWWH.js} +1 -1
  10. package/dist/assets/{chunk-IMKFNOWR-D6lGkqij.js → chunk-IMKFNOWR-CjBGlNOu.js} +1 -1
  11. package/dist/assets/{chunk-JWPE2WC7-BmF9vLBT.js → chunk-JWPE2WC7-vfnYEpgA.js} +1 -1
  12. package/dist/assets/{chunk-POPQ4Y6H-C_0SR3ak.js → chunk-POPQ4Y6H-Btl98tE8.js} +1 -1
  13. package/dist/assets/{chunk-SVP7TREG-rT20Wfpp.js → chunk-SVP7TREG-Bp6-pLjR.js} +1 -1
  14. package/dist/assets/{chunk-TICWLB2K-Cn2hkmcf.js → chunk-TICWLB2K-DvmznW2q.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-Dm_eP1_v.js → chunk-XXDRQBXY-QSHJTsI3.js} +1 -1
  16. package/dist/assets/classDiagram-ZZMXUADV-BYkEWggn.js +1 -0
  17. package/dist/assets/classDiagram-v2-VYDZK3BY-BYkEWggn.js +1 -0
  18. package/dist/assets/{cose-bilkent-JH36ORCC-cJeeJsep.js → cose-bilkent-JH36ORCC-DxpyZoe2.js} +1 -1
  19. package/dist/assets/{cynefin-OW5HDTMX-DX2ePIXe.js → cynefin-OW5HDTMX-B9GRp2Gn.js} +1 -1
  20. package/dist/assets/{cynefinDiagram-5FMLGOSQ-BvWXN-RR.js → cynefinDiagram-5FMLGOSQ-Q-2tz5GW.js} +1 -1
  21. package/dist/assets/{dagre-GXQ25YYZ-CkwPRhGR.js → dagre-GXQ25YYZ-3Rl3NqNe.js} +1 -1
  22. package/dist/assets/{diagram-S7CK7UJ4-CBGNzYyv.js → diagram-S7CK7UJ4-CreeWCO1.js} +1 -1
  23. package/dist/assets/{diagram-UQ7AKVKN-CiwCU0SJ.js → diagram-UQ7AKVKN-DNBoIyDJ.js} +1 -1
  24. package/dist/assets/{diagram-VSXAHHWV-Aekg4nTk.js → diagram-VSXAHHWV-ZkcE_cRk.js} +1 -1
  25. package/dist/assets/{diagram-VX7I27RA-DPFP5K7r.js → diagram-VX7I27RA-Dzdf7N2Q.js} +1 -1
  26. package/dist/assets/{diagram-Z3DM3KII-BHJkxoey.js → diagram-Z3DM3KII-M6b-nr1u.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-PWID7BFC-2rV1P32T.js → ebnfDiagram-PWID7BFC-DunIw64n.js} +1 -1
  28. package/dist/assets/{erDiagram-RLTQ6QDP-C4BjyS_H.js → erDiagram-RLTQ6QDP-kN0Se5uc.js} +1 -1
  29. package/dist/assets/{flowDiagram-HODETNUW-DL1TBlAG.js → flowDiagram-HODETNUW-24YCovut.js} +1 -1
  30. package/dist/assets/{ganttDiagram-EL5Y4UJY-MKjvzCWz.js → ganttDiagram-EL5Y4UJY-DTUUEEy6.js} +1 -1
  31. package/dist/assets/{gitGraphDiagram-WWUBYQGX-CS_oTGK5.js → gitGraphDiagram-WWUBYQGX-BitrqhMr.js} +1 -1
  32. package/dist/assets/{index-XOGQDqU3.js → index-CG9hW1GU.js} +120 -120
  33. package/dist/assets/index-D_Dc_nQv.css +1 -0
  34. package/dist/assets/{infoDiagram-27XIBGKW-ihUr2GjN.js → infoDiagram-27XIBGKW-BNHN5Mby.js} +1 -1
  35. package/dist/assets/{ishikawaDiagram-5VMMS53U-D2YAnuir.js → ishikawaDiagram-5VMMS53U-De3IQKso.js} +1 -1
  36. package/dist/assets/{journeyDiagram-3NMN7TZE-Bc2hSZGD.js → journeyDiagram-3NMN7TZE-CWlkZ25T.js} +1 -1
  37. package/dist/assets/{kanban-definition-UXKFOSKX-LRMGNonX.js → kanban-definition-UXKFOSKX-2o_ax-Nk.js} +1 -1
  38. package/dist/assets/{layout-CcfWOlPV.js → layout-Btga9ZYP.js} +1 -1
  39. package/dist/assets/{linear-7JoS2gQO.js → linear-BoGGmqPG.js} +1 -1
  40. package/dist/assets/{mermaid.core-ijh_SsuN.js → mermaid.core-M308jnLQ.js} +6 -6
  41. package/dist/assets/{mindmap-definition-YA3MSWOX-DCE4nzfF.js → mindmap-definition-YA3MSWOX-BJ6C_grh.js} +1 -1
  42. package/dist/assets/{pegDiagram-XKGWAZYB-SjaGa7lE.js → pegDiagram-XKGWAZYB-qcdYX0Xe.js} +1 -1
  43. package/dist/assets/{pieDiagram-E7YTZNPT-1xcRidSZ.js → pieDiagram-E7YTZNPT-XPrSlt1M.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-AXDQQJYC-obHAHnYV.js → quadrantDiagram-AXDQQJYC-COhHhra5.js} +1 -1
  45. package/dist/assets/{railroadDiagram-O6MQD6OU-BsCVcRZb.js → railroadDiagram-O6MQD6OU-Mw_KF6gb.js} +1 -1
  46. package/dist/assets/{requirementDiagram-BXWQKSXE-CUNkhvqb.js → requirementDiagram-BXWQKSXE-DPbt7jUM.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-P5KCCOFB-DhezXMKm.js → sankeyDiagram-P5KCCOFB-B6HzL6Gh.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-WJ2MYXX4-CL9VswXH.js → sequenceDiagram-WJ2MYXX4-B_dXXCC0.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-t0g9jiEz.js → sizeCapture-INFHLROL-DwODubWN.js} +1 -1
  50. package/dist/assets/{stateDiagram-D77RDMKH-BW-g-IOz.js → stateDiagram-D77RDMKH-5AUnOL3S.js} +1 -1
  51. package/dist/assets/stateDiagram-v2-MP3YSRHH-CFM_nDL9.js +1 -0
  52. package/dist/assets/{swimlanes-42K2YHIH-LsuyeBte.js → swimlanes-42K2YHIH-BLnIwbnd.js} +1 -1
  53. package/dist/assets/swimlanesDiagram-VR7AAH4N-BRQJYnDN.js +8 -0
  54. package/dist/assets/{timeline-definition-24CTP7MA-B0cFka1R.js → timeline-definition-24CTP7MA-B1Yc7-na.js} +1 -1
  55. package/dist/assets/{vendor-codemirror-C5qqu4R7.js → vendor-codemirror-CjW0lHR5.js} +5 -5
  56. package/dist/assets/{vennDiagram-4TSXK5OY-D3HNCDR3.js → vennDiagram-4TSXK5OY-BFRtl-NI.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-VM6X3IG4-DJ3Co8nb.js → wardleyDiagram-VM6X3IG4-BsR8iaD_.js} +1 -1
  58. package/dist/assets/{xychartDiagram-S5SC5T6Z-Cz5E9New.js → xychartDiagram-S5SC5T6Z-Crh1SwrA.js} +1 -1
  59. package/dist/favicon.png +0 -0
  60. package/dist/favicon.svg +1 -9
  61. package/dist/generate-icons.js +47 -46
  62. package/dist/icons/icon-128x128.png +0 -0
  63. package/dist/icons/icon-128x128.svg +1 -12
  64. package/dist/icons/icon-144x144.png +0 -0
  65. package/dist/icons/icon-144x144.svg +1 -12
  66. package/dist/icons/icon-152x152.png +0 -0
  67. package/dist/icons/icon-152x152.svg +1 -12
  68. package/dist/icons/icon-192x192.png +0 -0
  69. package/dist/icons/icon-192x192.svg +1 -12
  70. package/dist/icons/icon-384x384.png +0 -0
  71. package/dist/icons/icon-384x384.svg +1 -12
  72. package/dist/icons/icon-512x512.png +0 -0
  73. package/dist/icons/icon-512x512.svg +1 -12
  74. package/dist/icons/icon-72x72.png +0 -0
  75. package/dist/icons/icon-72x72.svg +1 -12
  76. package/dist/icons/icon-96x96.png +0 -0
  77. package/dist/icons/icon-96x96.svg +1 -12
  78. package/dist/index.html +3 -3
  79. package/dist/logo-128.png +0 -0
  80. package/dist/logo-256.png +0 -0
  81. package/dist/logo-32.png +0 -0
  82. package/dist/logo-512.png +0 -0
  83. package/dist/logo-64.png +0 -0
  84. package/dist/logo-sources/logo-black.png +0 -0
  85. package/dist/logo-sources/logo-white.png +0 -0
  86. package/dist/logo.svg +1 -17
  87. package/dist/sw.js +1 -1
  88. package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js +91 -0
  89. package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js.map +1 -0
  90. package/dist-server/plugins/piecemaker-dossier/src/knowledge.js +112 -10
  91. package/dist-server/plugins/piecemaker-dossier/src/knowledge.js.map +1 -1
  92. package/dist-server/plugins/piecemaker-dossier/src/scan-result.js +5 -1
  93. package/dist-server/plugins/piecemaker-dossier/src/scan-result.js.map +1 -1
  94. package/dist-server/server/index.js +60 -26
  95. package/dist-server/server/index.js.map +1 -1
  96. package/dist-server/server/modules/cli/desktop-shortcut.js +80 -0
  97. package/dist-server/server/modules/cli/desktop-shortcut.js.map +1 -0
  98. package/dist-server/server/modules/cli/pwa-launcher.js +27 -4
  99. package/dist-server/server/modules/cli/pwa-launcher.js.map +1 -1
  100. package/dist-server/server/modules/database/repositories/projects.db.js +28 -6
  101. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
  102. package/dist-server/server/modules/database/tests/projects.db.integration.test.js +58 -1
  103. package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
  104. package/dist-server/server/modules/plugins/plugins.routes.js +8 -1
  105. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -1
  106. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +2 -0
  107. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  108. package/dist-server/server/piecemaker/bodacc-search.js +191 -0
  109. package/dist-server/server/piecemaker/bodacc-search.js.map +1 -0
  110. package/dist-server/server/piecemaker/company-search.js +145 -0
  111. package/dist-server/server/piecemaker/company-search.js.map +1 -0
  112. package/dist-server/server/piecemaker/company-search.test.js +18 -0
  113. package/dist-server/server/piecemaker/company-search.test.js.map +1 -0
  114. package/dist-server/server/piecemaker/index.js +6 -2
  115. package/dist-server/server/piecemaker/index.js.map +1 -1
  116. package/dist-server/server/piecemaker/knowledge/index.js +9 -4
  117. package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
  118. package/dist-server/server/piecemaker/knowledge/pipeline.js +68 -58
  119. package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
  120. package/dist-server/server/piecemaker/knowledge/routes.js +2 -4
  121. package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
  122. package/dist-server/server/piecemaker/knowledge/scan-jobs.js +91 -0
  123. package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -0
  124. package/dist-server/server/piecemaker/knowledge/service.js +18 -36
  125. package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
  126. package/dist-server/server/piecemaker/library/connector-installation.js +224 -0
  127. package/dist-server/server/piecemaker/library/connector-installation.js.map +1 -0
  128. package/dist-server/server/piecemaker/library/index.js +11 -1
  129. package/dist-server/server/piecemaker/library/index.js.map +1 -1
  130. package/dist-server/server/piecemaker/library/marketplace.js +102 -43
  131. package/dist-server/server/piecemaker/library/marketplace.js.map +1 -1
  132. package/dist-server/server/piecemaker/library/migrate.js +8 -1
  133. package/dist-server/server/piecemaker/library/migrate.js.map +1 -1
  134. package/dist-server/server/piecemaker/library/provider-agents.js +50 -0
  135. package/dist-server/server/piecemaker/library/provider-agents.js.map +1 -0
  136. package/dist-server/server/piecemaker/library/provider-connectors.js +80 -0
  137. package/dist-server/server/piecemaker/library/provider-connectors.js.map +1 -0
  138. package/dist-server/server/piecemaker/library/provider-skills.js +11 -2
  139. package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -1
  140. package/dist-server/server/piecemaker/library/store.js +125 -35
  141. package/dist-server/server/piecemaker/library/store.js.map +1 -1
  142. package/dist-server/server/piecemaker/library/workspace-installation.js +53 -29
  143. package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
  144. package/dist-server/server/piecemaker/timesheet/service.js +4 -21
  145. package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
  146. package/package.json +3 -2
  147. package/product.config.json +1 -0
  148. package/scripts/piecemaker/cli/install-command.mjs +35 -9
  149. package/scripts/piecemaker/cli/lib/app-window.mjs +47 -0
  150. package/scripts/piecemaker/cli/lib/config.mjs +1 -0
  151. package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +78 -0
  152. package/scripts/piecemaker/cli/lib/plugins.mjs +2 -0
  153. package/scripts/piecemaker/cli/lib/pwa.mjs +49 -13
  154. package/scripts/piecemaker/cli/lib/services.mjs +65 -4
  155. package/scripts/piecemaker/cli/piecemaker-command.test.mjs +25 -0
  156. package/scripts/piecemaker/cli/piecemaker.mjs +60 -45
  157. package/scripts/piecemaker/cli/piecemaker.ps1 +8 -0
  158. package/scripts/piecemaker/cli/piecemaker.sh +6 -1
  159. package/server/index.ts +52 -23
  160. package/server/modules/cli/desktop-shortcut.ts +89 -0
  161. package/server/modules/cli/pwa-launcher.ts +29 -4
  162. package/server/modules/database/repositories/projects.db.ts +28 -6
  163. package/server/modules/database/tests/projects.db.integration.test.ts +63 -1
  164. package/server/modules/plugins/plugins.routes.ts +8 -1
  165. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +5 -0
  166. package/server/piecemaker/anonymizer/client-config.cjs +10 -2
  167. package/server/piecemaker/anonymizer/dictionary.cjs +6 -72
  168. package/server/piecemaker/bodacc-search.ts +205 -0
  169. package/server/piecemaker/company-search.test.ts +26 -0
  170. package/server/piecemaker/company-search.ts +183 -0
  171. package/server/piecemaker/index.ts +8 -2
  172. package/server/piecemaker/knowledge/index.ts +9 -4
  173. package/server/piecemaker/knowledge/pipeline.ts +89 -57
  174. package/server/piecemaker/knowledge/routes.ts +2 -4
  175. package/server/piecemaker/knowledge/scan-jobs.ts +111 -0
  176. package/server/piecemaker/knowledge/service.ts +18 -33
  177. package/server/piecemaker/library/connector-installation.ts +248 -0
  178. package/server/piecemaker/library/index.ts +5 -1
  179. package/server/piecemaker/library/marketplace.ts +104 -39
  180. package/server/piecemaker/library/migrate.ts +8 -1
  181. package/server/piecemaker/library/provider-agents.ts +49 -0
  182. package/server/piecemaker/library/provider-connectors.ts +89 -0
  183. package/server/piecemaker/library/provider-skills.ts +10 -1
  184. package/server/piecemaker/library/store.ts +129 -36
  185. package/server/piecemaker/library/workspace-installation.ts +54 -29
  186. package/server/piecemaker/router.cjs +2 -1
  187. package/server/piecemaker/timesheet/service.ts +4 -16
  188. package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +0 -27
  189. package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +1 -1
  190. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +2 -3
  191. package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -3
  192. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3 -10
  193. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +135 -4
  194. package/server/piecemaker/vendor/websocket-server/process-group.cjs +95 -0
  195. package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
  196. package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +280 -149
  197. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
  198. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/scanner_worker.cpython-312.pyc +0 -0
  199. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +35 -29
  200. package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +0 -5
  201. package/server/shared/types.ts +1 -0
  202. package/dist/assets/channel-Dz3eE5vU.js +0 -1
  203. package/dist/assets/classDiagram-ZZMXUADV-BC1eKV2j.js +0 -1
  204. package/dist/assets/classDiagram-v2-VYDZK3BY-BC1eKV2j.js +0 -1
  205. package/dist/assets/index-DhwJpHCq.css +0 -1
  206. package/dist/assets/stateDiagram-v2-MP3YSRHH-BXuT4zDG.js +0 -1
  207. package/dist/assets/swimlanesDiagram-VR7AAH4N-B0eYrB4U.js +0 -8
  208. package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +0 -111
  209. package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +0 -216
  210. package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +0 -134
  211. package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +0 -138
  212. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +0 -246
  213. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +0 -62
  214. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
  215. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +0 -118
  216. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +0 -164
  217. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +0 -479
@@ -559,10 +559,21 @@ const waiting = [];
559
559
  let reservedBytes = 0;
560
560
  let acceptingJobs = true;
561
561
 
562
+ /**
563
+ * Jobs admis via `runManagedPythonJob` (pas de `legalCase`, donc absents de
564
+ * `jobs`) : `runningAnonymize` doit les voir pour que l'exclusivité GLiNER
565
+ * reste vraie dans les deux sens, quel que soit le consommateur qui a lancé
566
+ * le traitement en cours.
567
+ */
568
+ const runningManaged = new Set();
569
+
562
570
  function runningAnonymize() {
563
571
  for (const job of jobs.values()) {
564
572
  if (job.state === 'running' && job.action === 'anonymize') return true;
565
573
  }
574
+ for (const job of runningManaged) {
575
+ if (job.action === 'anonymize') return true;
576
+ }
566
577
  return false;
567
578
  }
568
579
 
@@ -577,7 +588,12 @@ function canAdmit(job) {
577
588
  return true;
578
589
  }
579
590
 
580
- /** Admet les traitements en file qui rentrent désormais, du plus ancien au plus récent. */
591
+ /**
592
+ * Admet les traitements en file qui rentrent désormais, du plus ancien au plus
593
+ * récent. Un descripteur `runManagedPythonJob` (identifié par la présence de
594
+ * `run`, sans `legalCase`) suit son propre lancement : même file, même
595
+ * contrôle d'admission, exécution différente.
596
+ */
581
597
  function pumpQueue() {
582
598
  if (!acceptingJobs) return;
583
599
  for (let index = 0; index < waiting.length; index += 1) {
@@ -585,7 +601,8 @@ function pumpQueue() {
585
601
  if (!canAdmit(descriptor.job)) continue;
586
602
  waiting.splice(index, 1);
587
603
  index -= 1;
588
- launchJob(descriptor);
604
+ if (descriptor.run) launchManagedJob(descriptor);
605
+ else launchJob(descriptor);
589
606
  }
590
607
  }
591
608
 
@@ -749,6 +766,108 @@ function spawnTracked(job, script, args, progressScale = {}) {
749
766
  });
750
767
  }
751
768
 
769
+ /**
770
+ * Point d'entrée générique pour tout traitement devant passer par le même
771
+ * contrôle d'admission que les pièces originales (exclusivité GLiNER, budget
772
+ * RAM, file d'attente, nice, timeout, arrêt propre du groupe de process).
773
+ *
774
+ * Contrairement à `startOriginalsJob`, cette fonction ne connaît aucune
775
+ * notion de dossier juridique enregistré (`legalCase`, mapping, commit) :
776
+ * elle sert les consommateurs qui ont leur propre gestion du résultat (le
777
+ * pipeline `knowledge`, dont le `projectId` n'est pas un dossier juridique du
778
+ * registre) mais qui doivent néanmoins partager le même verrou GLiNER et le
779
+ * même budget RAM que l'administration — sinon rien n'empêche deux scans
780
+ * simultanés de charger chacun leur propre modèle et de figer la machine.
781
+ *
782
+ * Lance directement `script` avec `args` via `spawnTracked` (même parseur de
783
+ * lignes `PROGRESS:`, même gestion du groupe de process, même priorité nice).
784
+ * `onProgress`, si fourni, est appelé à chaque mise à jour de la progression
785
+ * avec `{ phase, percent, processed, total }`.
786
+ */
787
+ function runManagedPythonJob({ action, script, args, onProgress, signal } = {}) {
788
+ if (!['convert', 'anonymize'].includes(action)) throw new Error('Action inconnue.');
789
+ if (!acceptingJobs) throw new Error('Le serveur est en cours d’arrêt : aucun nouveau traitement ne peut démarrer.');
790
+ const job = {
791
+ action,
792
+ cancelled: false,
793
+ cancelReason: null,
794
+ child: null,
795
+ processGroupId: null,
796
+ stopPromise: null,
797
+ phase: 'convert',
798
+ percent: 0,
799
+ processed: 0,
800
+ total: 0,
801
+ log: [],
802
+ reserveBytes: JOB_RESERVE_BYTES(action),
803
+ };
804
+ if (onProgress) {
805
+ for (const key of ['phase', 'percent', 'processed', 'total']) {
806
+ let value = job[key];
807
+ Object.defineProperty(job, key, {
808
+ get: () => value,
809
+ set: (next) => {
810
+ value = next;
811
+ onProgress({ phase: job.phase, percent: job.percent, processed: job.processed, total: job.total });
812
+ },
813
+ });
814
+ }
815
+ }
816
+ const abort = () => { void stopRunningJob(job, 'user-cancellation'); };
817
+ if (signal) {
818
+ if (signal.aborted) abort();
819
+ else signal.addEventListener('abort', abort, { once: true });
820
+ }
821
+ const run = () => spawnTracked(job, script, args);
822
+ const descriptor = { job, run };
823
+ const completion = new Promise((resolve, reject) => {
824
+ descriptor.resolve = resolve;
825
+ descriptor.reject = reject;
826
+ });
827
+ runningManaged.add(job);
828
+ if (canAdmit(job)) {
829
+ launchManagedJob(descriptor);
830
+ } else {
831
+ waiting.push(descriptor);
832
+ }
833
+ return completion.finally(() => {
834
+ signal?.removeEventListener('abort', abort);
835
+ });
836
+ }
837
+
838
+ /** Variante de `launchJob` pour un descripteur `runManagedPythonJob` (pas de `legalCase`/commit à gérer ici). */
839
+ function launchManagedJob(descriptor) {
840
+ const { job, run, resolve, reject } = descriptor;
841
+ reservedBytes += job.reserveBytes;
842
+ const timeoutId = setTimeout(() => {
843
+ void stopRunningJob(job, 'timeout');
844
+ }, JOB_TIMEOUT_MS());
845
+ (async () => {
846
+ try {
847
+ if (job.cancelled) throw cancellationError(job);
848
+ const result = await run(job);
849
+ if (job.cancelled) throw cancellationError(job);
850
+ resolve(result);
851
+ } catch (error) {
852
+ reject(error);
853
+ } finally {
854
+ clearTimeout(timeoutId);
855
+ const processGroupId = job.processGroupId;
856
+ try {
857
+ await verifyJobProcessTreeStopped(job, processGroupId);
858
+ } catch {
859
+ // Best-effort : une erreur de nettoyage ne doit pas masquer le résultat déjà tranché ci-dessus.
860
+ }
861
+ job.child = null;
862
+ job.processGroupId = null;
863
+ job.stopPromise = null;
864
+ runningManaged.delete(job);
865
+ reservedBytes -= job.reserveBytes;
866
+ pumpQueue();
867
+ }
868
+ })();
869
+ }
870
+
752
871
  /**
753
872
  * Migration « au prochain traitement », rattachée aux pièces du lot : range dans
754
873
  * le dossier de conversion métier le Markdown que d'anciennes versions ont laissé à la racine
@@ -1092,14 +1211,22 @@ function stopOriginalsJobs() {
1092
1211
  const { job } = descriptor;
1093
1212
  job.cancelled = true;
1094
1213
  job.cancelReason = 'server-shutdown';
1214
+ if (descriptor.run) {
1215
+ // Descripteur `runManagedPythonJob` : rejeter sa promesse est le seul
1216
+ // moyen de le débloquer, il n'a pas d'état `job.state`/`jobs` propre.
1217
+ descriptor.reject(cancellationError(job));
1218
+ continue;
1219
+ }
1095
1220
  job.state = 'error';
1096
1221
  job.error = 'Traitement interrompu par l’arrêt du serveur.';
1097
1222
  job.finishedAt = new Date().toISOString();
1098
1223
  }
1099
1224
 
1100
1225
  const running = [...jobs.values()].filter((job) => job.state === 'running');
1101
- const groups = [...new Set(running.map((job) => job.processGroupId).filter(Boolean))];
1102
- await Promise.allSettled(running.map((job) => stopRunningJob(job, 'server-shutdown')));
1226
+ const managedRunning = [...runningManaged];
1227
+ const allRunning = [...running, ...managedRunning];
1228
+ const groups = [...new Set(allRunning.map((job) => job.processGroupId).filter(Boolean))];
1229
+ await Promise.allSettled(allRunning.map((job) => stopRunningJob(job, 'server-shutdown')));
1103
1230
  await Promise.allSettled(running.map((job) => job.completion).filter(Boolean));
1104
1231
 
1105
1232
  // Contrôle défensif final, y compris si un enfant a fermé ses pipes avant
@@ -1135,6 +1262,10 @@ function cancelOriginalsJob(jobId) {
1135
1262
  module.exports = {
1136
1263
  cancelOriginalsJob,
1137
1264
  groupEntityHits,
1265
+ // Point d'entrée partagé : tout consommateur d'un pipeline GLiNER/markitdown
1266
+ // (même hors dossier juridique enregistré, ex. `knowledge/pipeline.ts`) doit
1267
+ // passer par ici pour rester sous l'exclusivité GLiNER et le budget RAM.
1268
+ runManagedPythonJob,
1138
1269
  stopOriginalsJobs,
1139
1270
  // Ré-exportés pour les routes de l'administration : l'implémentation vit
1140
1271
  // désormais dans `piecemaker-plugin/scripts/lib/mapping.cjs`.
@@ -0,0 +1,95 @@
1
+ const { spawn } = require('node:child_process');
2
+
3
+ const wait = (milliseconds) => new Promise((resolve) => setTimeout(resolve, milliseconds));
4
+
5
+ function posixProcessGroupExists(processGroupId) {
6
+ if (!Number.isInteger(processGroupId) || processGroupId <= 0) return false;
7
+ try {
8
+ process.kill(-processGroupId, 0);
9
+ return true;
10
+ } catch (error) {
11
+ if (error?.code === 'EPERM') return true;
12
+ if (error?.code === 'ESRCH') return false;
13
+ throw error;
14
+ }
15
+ }
16
+
17
+ function signalPosixProcessGroup(processGroupId, signal) {
18
+ try {
19
+ process.kill(-processGroupId, signal);
20
+ return true;
21
+ } catch (error) {
22
+ if (error?.code === 'ESRCH') return false;
23
+ throw error;
24
+ }
25
+ }
26
+
27
+ async function waitForPosixProcessGroupExit(processGroupId, timeoutMs, pollIntervalMs = 25) {
28
+ const deadline = Date.now() + timeoutMs;
29
+ while (posixProcessGroupExists(processGroupId)) {
30
+ if (Date.now() >= deadline) return false;
31
+ await wait(Math.min(pollIntervalMs, Math.max(1, deadline - Date.now())));
32
+ }
33
+ return true;
34
+ }
35
+
36
+ function taskkillProcessTree(processId) {
37
+ return new Promise((resolve, reject) => {
38
+ const killer = spawn('taskkill.exe', ['/PID', String(processId), '/T', '/F'], {
39
+ stdio: 'ignore',
40
+ windowsHide: true,
41
+ });
42
+ killer.once('error', reject);
43
+ killer.once('close', (code) => {
44
+ if (code === 0 || code === 128) resolve();
45
+ else reject(new Error(`taskkill a échoué avec le code ${code}.`));
46
+ });
47
+ });
48
+ }
49
+
50
+ /**
51
+ * Terminates a complete processing tree and confirms that it disappeared.
52
+ * On POSIX, the pipeline is its process-group leader. On Windows, taskkill /T
53
+ * performs the recursive termination while the root process still exists.
54
+ */
55
+ async function terminateProcessTree(processGroupId, {
56
+ graceMs = 2_000,
57
+ platform = process.platform,
58
+ } = {}) {
59
+ if (!Number.isInteger(processGroupId) || processGroupId <= 0) return;
60
+
61
+ if (platform === 'win32') {
62
+ await taskkillProcessTree(processGroupId);
63
+ return;
64
+ }
65
+
66
+ if (!posixProcessGroupExists(processGroupId)) return;
67
+ signalPosixProcessGroup(processGroupId, 'SIGTERM');
68
+ if (await waitForPosixProcessGroupExit(processGroupId, graceMs)) return;
69
+
70
+ signalPosixProcessGroup(processGroupId, 'SIGKILL');
71
+ if (!(await waitForPosixProcessGroupExit(processGroupId, graceMs))) {
72
+ throw new Error(`Le groupe de processus ${processGroupId} est toujours actif après SIGKILL.`);
73
+ }
74
+ }
75
+
76
+ /**
77
+ * Post-job guard: a successful direct child exit is insufficient because one
78
+ * of its descendants may still own CPU, memory, or inherited pipes.
79
+ */
80
+ async function ensureProcessTreeStopped(processGroupId, options) {
81
+ if (process.platform === 'win32') return;
82
+ if (posixProcessGroupExists(processGroupId)) {
83
+ await terminateProcessTree(processGroupId, options);
84
+ }
85
+ if (posixProcessGroupExists(processGroupId)) {
86
+ throw new Error(`Nettoyage incomplet du groupe de processus ${processGroupId}.`);
87
+ }
88
+ }
89
+
90
+ module.exports = {
91
+ ensureProcessTreeStopped,
92
+ posixProcessGroupExists,
93
+ terminateProcessTree,
94
+ waitForPosixProcessGroupExit,
95
+ };