@piecemaker-legal/piecemaker 1.0.6 → 1.0.7

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 (209) hide show
  1. package/dist/assets/{abnfDiagram-VCTEODGH-DF7LFtT-.js → abnfDiagram-VCTEODGH-CR3_ADBu.js} +1 -1
  2. package/dist/assets/{arc-xOmjWeVH.js → arc-b92imMmc.js} +1 -1
  3. package/dist/assets/{architectureDiagram-5GKGNRK7-CESzNPwa.js → architectureDiagram-5GKGNRK7-Dfm5Epud.js} +1 -1
  4. package/dist/assets/{blockDiagram-I7D4REHJ-BjdN78Ad.js → blockDiagram-I7D4REHJ-B8kLLyAv.js} +1 -1
  5. package/dist/assets/{c4Diagram-7LVT6UL2-BcK9EDWT.js → c4Diagram-7LVT6UL2-BWSyAAWX.js} +1 -1
  6. package/dist/assets/channel-BbcW_Tkh.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-DGUN1JFP.js → chunk-2Q5K7J3B-Ci743mcC.js} +1 -1
  8. package/dist/assets/{chunk-5VM5RSS4-BG3BBcFr.js → chunk-5VM5RSS4-SdXpal6h.js} +1 -1
  9. package/dist/assets/{chunk-F27PBJKO-CLIOfrF5.js → chunk-F27PBJKO-Rof94ueX.js} +1 -1
  10. package/dist/assets/{chunk-IMKFNOWR-D6lGkqij.js → chunk-IMKFNOWR-B3st6ECc.js} +1 -1
  11. package/dist/assets/{chunk-JWPE2WC7-BmF9vLBT.js → chunk-JWPE2WC7-alXmu5xU.js} +1 -1
  12. package/dist/assets/{chunk-POPQ4Y6H-C_0SR3ak.js → chunk-POPQ4Y6H-dMs1OCce.js} +1 -1
  13. package/dist/assets/{chunk-SVP7TREG-rT20Wfpp.js → chunk-SVP7TREG-BmM8FsmF.js} +1 -1
  14. package/dist/assets/{chunk-TICWLB2K-Cn2hkmcf.js → chunk-TICWLB2K-CL1LytYG.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-Dm_eP1_v.js → chunk-XXDRQBXY-7U9iRPT1.js} +1 -1
  16. package/dist/assets/classDiagram-ZZMXUADV-D9_YRZ7i.js +1 -0
  17. package/dist/assets/classDiagram-v2-VYDZK3BY-D9_YRZ7i.js +1 -0
  18. package/dist/assets/{cose-bilkent-JH36ORCC-cJeeJsep.js → cose-bilkent-JH36ORCC-DFOMlhj2.js} +1 -1
  19. package/dist/assets/{cynefin-OW5HDTMX-DX2ePIXe.js → cynefin-OW5HDTMX-CDdJFd9d.js} +1 -1
  20. package/dist/assets/{cynefinDiagram-5FMLGOSQ-BvWXN-RR.js → cynefinDiagram-5FMLGOSQ-DPyVNrMW.js} +1 -1
  21. package/dist/assets/{dagre-GXQ25YYZ-CkwPRhGR.js → dagre-GXQ25YYZ-B3bpHa9D.js} +1 -1
  22. package/dist/assets/{diagram-S7CK7UJ4-CBGNzYyv.js → diagram-S7CK7UJ4-DeFO2rXB.js} +1 -1
  23. package/dist/assets/{diagram-UQ7AKVKN-CiwCU0SJ.js → diagram-UQ7AKVKN-CbdGTOVf.js} +1 -1
  24. package/dist/assets/{diagram-VSXAHHWV-Aekg4nTk.js → diagram-VSXAHHWV-DFfNQyMd.js} +1 -1
  25. package/dist/assets/{diagram-VX7I27RA-DPFP5K7r.js → diagram-VX7I27RA-DbNZ6_X3.js} +1 -1
  26. package/dist/assets/{diagram-Z3DM3KII-BHJkxoey.js → diagram-Z3DM3KII-B8F-ZkNJ.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-PWID7BFC-2rV1P32T.js → ebnfDiagram-PWID7BFC-BfCCPPAP.js} +1 -1
  28. package/dist/assets/{erDiagram-RLTQ6QDP-C4BjyS_H.js → erDiagram-RLTQ6QDP-DcV-3Kzv.js} +1 -1
  29. package/dist/assets/{flowDiagram-HODETNUW-DL1TBlAG.js → flowDiagram-HODETNUW-BwSkJXCo.js} +1 -1
  30. package/dist/assets/{ganttDiagram-EL5Y4UJY-MKjvzCWz.js → ganttDiagram-EL5Y4UJY-BffHk77T.js} +1 -1
  31. package/dist/assets/{gitGraphDiagram-WWUBYQGX-CS_oTGK5.js → gitGraphDiagram-WWUBYQGX-CQ1EWa74.js} +1 -1
  32. package/dist/assets/{index-XOGQDqU3.js → index-BqK33gaZ.js} +120 -120
  33. package/dist/assets/index-D_Dc_nQv.css +1 -0
  34. package/dist/assets/{infoDiagram-27XIBGKW-ihUr2GjN.js → infoDiagram-27XIBGKW-DqIaBXQn.js} +1 -1
  35. package/dist/assets/{ishikawaDiagram-5VMMS53U-D2YAnuir.js → ishikawaDiagram-5VMMS53U-HlhsaZgv.js} +1 -1
  36. package/dist/assets/{journeyDiagram-3NMN7TZE-Bc2hSZGD.js → journeyDiagram-3NMN7TZE-BYO8-7rN.js} +1 -1
  37. package/dist/assets/{kanban-definition-UXKFOSKX-LRMGNonX.js → kanban-definition-UXKFOSKX-DXb8zHGT.js} +1 -1
  38. package/dist/assets/{layout-CcfWOlPV.js → layout-CREOVuEZ.js} +1 -1
  39. package/dist/assets/{linear-7JoS2gQO.js → linear-CVCrIRIY.js} +1 -1
  40. package/dist/assets/{mermaid.core-ijh_SsuN.js → mermaid.core-DFqeWtQR.js} +6 -6
  41. package/dist/assets/{mindmap-definition-YA3MSWOX-DCE4nzfF.js → mindmap-definition-YA3MSWOX-SUpXz333.js} +1 -1
  42. package/dist/assets/{pegDiagram-XKGWAZYB-SjaGa7lE.js → pegDiagram-XKGWAZYB-D-yWpve3.js} +1 -1
  43. package/dist/assets/{pieDiagram-E7YTZNPT-1xcRidSZ.js → pieDiagram-E7YTZNPT-BJX4Zp4Z.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-AXDQQJYC-obHAHnYV.js → quadrantDiagram-AXDQQJYC-CHajheTu.js} +1 -1
  45. package/dist/assets/{railroadDiagram-O6MQD6OU-BsCVcRZb.js → railroadDiagram-O6MQD6OU-DHJWzW5A.js} +1 -1
  46. package/dist/assets/{requirementDiagram-BXWQKSXE-CUNkhvqb.js → requirementDiagram-BXWQKSXE-DigUIdso.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-P5KCCOFB-DhezXMKm.js → sankeyDiagram-P5KCCOFB-CFUDDbA5.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-WJ2MYXX4-CL9VswXH.js → sequenceDiagram-WJ2MYXX4-6tSaXfYD.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-t0g9jiEz.js → sizeCapture-INFHLROL-CXASEDKe.js} +1 -1
  50. package/dist/assets/{stateDiagram-D77RDMKH-BW-g-IOz.js → stateDiagram-D77RDMKH-DWTCAQfZ.js} +1 -1
  51. package/dist/assets/stateDiagram-v2-MP3YSRHH-HDQF4MGA.js +1 -0
  52. package/dist/assets/{swimlanes-42K2YHIH-LsuyeBte.js → swimlanes-42K2YHIH-7-oz5r-e.js} +1 -1
  53. package/dist/assets/swimlanesDiagram-VR7AAH4N-CJbgQFt8.js +8 -0
  54. package/dist/assets/{timeline-definition-24CTP7MA-B0cFka1R.js → timeline-definition-24CTP7MA-DVH5g4ty.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-CQvY_ALZ.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-VM6X3IG4-DJ3Co8nb.js → wardleyDiagram-VM6X3IG4-BdlTJgEc.js} +1 -1
  58. package/dist/assets/{xychartDiagram-S5SC5T6Z-Cz5E9New.js → xychartDiagram-S5SC5T6Z-CYn2sV77.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/database/repositories/projects.db.js +28 -6
  97. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
  98. package/dist-server/server/modules/database/tests/projects.db.integration.test.js +58 -1
  99. package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
  100. package/dist-server/server/modules/plugins/plugins.routes.js +8 -1
  101. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -1
  102. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +2 -0
  103. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  104. package/dist-server/server/piecemaker/bodacc-search.js +191 -0
  105. package/dist-server/server/piecemaker/bodacc-search.js.map +1 -0
  106. package/dist-server/server/piecemaker/company-search.js +145 -0
  107. package/dist-server/server/piecemaker/company-search.js.map +1 -0
  108. package/dist-server/server/piecemaker/company-search.test.js +18 -0
  109. package/dist-server/server/piecemaker/company-search.test.js.map +1 -0
  110. package/dist-server/server/piecemaker/index.js +6 -2
  111. package/dist-server/server/piecemaker/index.js.map +1 -1
  112. package/dist-server/server/piecemaker/knowledge/index.js +9 -4
  113. package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
  114. package/dist-server/server/piecemaker/knowledge/pipeline.js +68 -58
  115. package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
  116. package/dist-server/server/piecemaker/knowledge/routes.js +2 -4
  117. package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
  118. package/dist-server/server/piecemaker/knowledge/scan-jobs.js +91 -0
  119. package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -0
  120. package/dist-server/server/piecemaker/knowledge/service.js +18 -36
  121. package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
  122. package/dist-server/server/piecemaker/library/connector-installation.js +224 -0
  123. package/dist-server/server/piecemaker/library/connector-installation.js.map +1 -0
  124. package/dist-server/server/piecemaker/library/index.js +11 -1
  125. package/dist-server/server/piecemaker/library/index.js.map +1 -1
  126. package/dist-server/server/piecemaker/library/marketplace.js +102 -43
  127. package/dist-server/server/piecemaker/library/marketplace.js.map +1 -1
  128. package/dist-server/server/piecemaker/library/migrate.js +8 -1
  129. package/dist-server/server/piecemaker/library/migrate.js.map +1 -1
  130. package/dist-server/server/piecemaker/library/provider-agents.js +50 -0
  131. package/dist-server/server/piecemaker/library/provider-agents.js.map +1 -0
  132. package/dist-server/server/piecemaker/library/provider-connectors.js +80 -0
  133. package/dist-server/server/piecemaker/library/provider-connectors.js.map +1 -0
  134. package/dist-server/server/piecemaker/library/provider-skills.js +11 -2
  135. package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -1
  136. package/dist-server/server/piecemaker/library/store.js +125 -35
  137. package/dist-server/server/piecemaker/library/store.js.map +1 -1
  138. package/dist-server/server/piecemaker/library/workspace-installation.js +53 -29
  139. package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
  140. package/dist-server/server/piecemaker/timesheet/service.js +4 -21
  141. package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
  142. package/package.json +3 -2
  143. package/scripts/piecemaker/cli/install-command.mjs +35 -9
  144. package/scripts/piecemaker/cli/lib/config.mjs +1 -0
  145. package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +78 -0
  146. package/scripts/piecemaker/cli/lib/plugins.mjs +2 -0
  147. package/scripts/piecemaker/cli/lib/pwa.mjs +46 -7
  148. package/scripts/piecemaker/cli/lib/services.mjs +65 -4
  149. package/scripts/piecemaker/cli/piecemaker-command.test.mjs +25 -0
  150. package/scripts/piecemaker/cli/piecemaker.mjs +45 -44
  151. package/scripts/piecemaker/cli/piecemaker.ps1 +8 -0
  152. package/scripts/piecemaker/cli/piecemaker.sh +6 -1
  153. package/server/index.ts +52 -23
  154. package/server/modules/database/repositories/projects.db.ts +28 -6
  155. package/server/modules/database/tests/projects.db.integration.test.ts +63 -1
  156. package/server/modules/plugins/plugins.routes.ts +8 -1
  157. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +5 -0
  158. package/server/piecemaker/anonymizer/client-config.cjs +10 -2
  159. package/server/piecemaker/anonymizer/dictionary.cjs +6 -72
  160. package/server/piecemaker/bodacc-search.ts +205 -0
  161. package/server/piecemaker/company-search.test.ts +26 -0
  162. package/server/piecemaker/company-search.ts +183 -0
  163. package/server/piecemaker/index.ts +8 -2
  164. package/server/piecemaker/knowledge/index.ts +9 -4
  165. package/server/piecemaker/knowledge/pipeline.ts +89 -57
  166. package/server/piecemaker/knowledge/routes.ts +2 -4
  167. package/server/piecemaker/knowledge/scan-jobs.ts +111 -0
  168. package/server/piecemaker/knowledge/service.ts +18 -33
  169. package/server/piecemaker/library/connector-installation.ts +248 -0
  170. package/server/piecemaker/library/index.ts +5 -1
  171. package/server/piecemaker/library/marketplace.ts +104 -39
  172. package/server/piecemaker/library/migrate.ts +8 -1
  173. package/server/piecemaker/library/provider-agents.ts +49 -0
  174. package/server/piecemaker/library/provider-connectors.ts +89 -0
  175. package/server/piecemaker/library/provider-skills.ts +10 -1
  176. package/server/piecemaker/library/store.ts +129 -36
  177. package/server/piecemaker/library/workspace-installation.ts +54 -29
  178. package/server/piecemaker/router.cjs +2 -1
  179. package/server/piecemaker/timesheet/service.ts +4 -16
  180. package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +0 -27
  181. package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +1 -1
  182. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +2 -3
  183. package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -3
  184. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3 -10
  185. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +135 -4
  186. package/server/piecemaker/vendor/websocket-server/process-group.cjs +95 -0
  187. package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
  188. package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +280 -149
  189. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
  190. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/scanner_worker.cpython-312.pyc +0 -0
  191. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +35 -29
  192. package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +0 -5
  193. package/server/shared/types.ts +1 -0
  194. package/dist/assets/channel-Dz3eE5vU.js +0 -1
  195. package/dist/assets/classDiagram-ZZMXUADV-BC1eKV2j.js +0 -1
  196. package/dist/assets/classDiagram-v2-VYDZK3BY-BC1eKV2j.js +0 -1
  197. package/dist/assets/index-DhwJpHCq.css +0 -1
  198. package/dist/assets/stateDiagram-v2-MP3YSRHH-BXuT4zDG.js +0 -1
  199. package/dist/assets/swimlanesDiagram-VR7AAH4N-B0eYrB4U.js +0 -8
  200. package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +0 -111
  201. package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +0 -216
  202. package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +0 -134
  203. package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +0 -138
  204. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +0 -246
  205. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +0 -62
  206. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
  207. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +0 -118
  208. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +0 -164
  209. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +0 -479
@@ -1,111 +0,0 @@
1
- /** Instructions PieceMaker générées dans chaque dossier juridique enregistré. */
2
- const fs = require('node:fs');
3
- const os = require('node:os');
4
- const path = require('node:path');
5
-
6
- const { registeredCaseFolders } = require('../piecemaker-plugin/scripts/lib/case-folders.cjs');
7
- const {
8
- historyRepo,
9
- resolveCase,
10
- } = require('../piecemaker-plugin/scripts/lib/commits.cjs');
11
-
12
- const IMPORT_START = '<!-- piecemaker-instructions-start -->';
13
- const IMPORT_END = '<!-- piecemaker-instructions-end -->';
14
-
15
- function caseHistoryRepoLabel(folder) {
16
- try {
17
- const legalCase = resolveCase(path.dirname(folder), path.basename(folder));
18
- const absolute = historyRepo(path.join(os.homedir(), '.piecemaker'), legalCase);
19
- const home = os.homedir();
20
- return absolute.startsWith(`${home}${path.sep}`) ? `~${absolute.slice(home.length)}` : absolute;
21
- } catch {
22
- return '';
23
- }
24
- }
25
-
26
- function caseRuleContent(repoRoot, folder = '') {
27
- const template = path.join(repoRoot, 'installer', 'templates', 'workspace-CLAUDE.md');
28
- if (!fs.existsSync(template)) throw new Error('Le modèle d’instructions PieceMaker est introuvable.');
29
- let content = fs.readFileSync(template, 'utf8')
30
- .replace(
31
- '| Racine des dossiers | ce répertoire (`workspacePath` de `~/.piecemaker/config.json`) |',
32
- '| Dossier juridique actif | ce répertoire (`caseFolders` de `~/.piecemaker/config.json`) |',
33
- );
34
-
35
- const repoLabel = folder ? caseHistoryRepoLabel(folder) : '';
36
- if (repoLabel) {
37
- content = content.replace(
38
- '| Historique des dossiers | `~/.piecemaker/case-history/` |',
39
- `| Historique de ce dossier | \`${repoLabel}\` |`,
40
- );
41
- }
42
- return content;
43
- }
44
-
45
- function managedImportBlock(rule) {
46
- return `${IMPORT_START}
47
- ## PieceMaker — instructions gérées
48
-
49
- Pour une chronologie factuelle, appeler d'abord l'outil \`chronologie\` du
50
- serveur MCP \`piecemaker\`. Consulter aussi la règle complète suivante :
51
-
52
- @${rule}
53
- ${IMPORT_END}`;
54
- }
55
-
56
- /**
57
- * Ajoute uniquement un bloc PieceMaker géré. Le reste de CLAUDE.md/AGENTS.md
58
- * appartient à l'utilisateur et reste byte-for-byte intact.
59
- */
60
- function ensureInstructionImport(file, rule) {
61
- const block = managedImportBlock(rule);
62
- let current = '';
63
- try {
64
- current = fs.readFileSync(file, 'utf8');
65
- } catch {}
66
-
67
- const pattern = new RegExp(`${IMPORT_START}[\\s\\S]*?${IMPORT_END}\\n?`, 'm');
68
- const next = pattern.test(current)
69
- ? current.replace(pattern, `${block}\n`)
70
- : `${block}\n\n${current || '# Ce dossier\n\n<!-- Instructions propres à ce dossier. -->\n'}`;
71
- if (next !== current) fs.writeFileSync(file, next, 'utf8');
72
- }
73
-
74
- function ensureCaseRule(repoRoot, folder) {
75
- const target = path.join(folder, '.claude', 'rules', 'piecemaker.md');
76
- fs.mkdirSync(path.dirname(target), { recursive: true });
77
- const content = caseRuleContent(repoRoot, folder);
78
- let previous = null;
79
- try { previous = fs.readFileSync(target, 'utf8'); } catch {}
80
- if (previous !== content) fs.writeFileSync(target, content, 'utf8');
81
-
82
- // Claude Code charge nativement .claude/rules ; les imports explicites
83
- // garantissent aussi la disponibilité depuis Codex/AGENTS.md et rendent la
84
- // règle visible à la racine sans écraser les consignes propres au dossier.
85
- for (const name of ['CLAUDE.md', 'AGENTS.md']) {
86
- ensureInstructionImport(path.join(folder, name), target);
87
- }
88
- return target;
89
- }
90
-
91
- function refreshRegisteredCaseRules(repoRoot, config) {
92
- const result = { refreshed: 0, failed: [] };
93
- for (const folder of registeredCaseFolders(config)) {
94
- try {
95
- ensureCaseRule(repoRoot, folder);
96
- result.refreshed += 1;
97
- } catch (error) {
98
- result.failed.push({ folder, error: error.message });
99
- }
100
- }
101
- return result;
102
- }
103
-
104
- module.exports = {
105
- IMPORT_END,
106
- IMPORT_START,
107
- caseRuleContent,
108
- ensureCaseRule,
109
- ensureInstructionImport,
110
- refreshRegisteredCaseRules,
111
- };
@@ -1,216 +0,0 @@
1
- # Partial Address Anonymization Feature
2
-
3
- ## Overview
4
-
5
- This feature implements smart address parsing to preserve city, postal code, and country information in anonymized documents while only anonymizing street addresses. This maintains legal context while protecting private information.
6
-
7
- ## How It Works
8
-
9
- ### Address Parsing
10
-
11
- When GLiNER extracts a `LOCATION` entity, the system now:
12
-
13
- 1. **Parses the address** into components:
14
- - Street part (number + type + name)
15
- - Postal code
16
- - City
17
- - Country
18
-
19
- 2. **Determines anonymization strategy**:
20
- - **None (no anonymization)**: City or country name only (e.g., "Paris", "France")
21
- - **Partial**: Street address with city/postal/country (e.g., "123 Rue de Rivoli, 75001 Paris, France")
22
- - **Full**: Unparseable addresses (fallback for safety)
23
-
24
- 3. **Applies strategy**:
25
- - **Partial**: Only street part → code, preserve city/postal/country
26
- - **Full**: Entire address → code
27
-
28
- ### Supported Formats
29
-
30
- #### French Addresses
31
- - Format: `[Number] [Type] [Name], [Postal] [City], [Country]`
32
- - Examples:
33
- - `123 Rue de Rivoli, 75001 Paris, France`
34
- - `20 Bis rue de la Princesse, Lyon`
35
- - `42 boulevard Saint-Germain, 75005 Paris`
36
-
37
- #### Belgian Addresses
38
- - Format: `[Type] [Name] [Number], [Postal] [City], [Country]`
39
- - Examples:
40
- - `Rue de la Loi 123, 1000 Bruxelles, Belgique`
41
- - `Avenue Louise 54, 1050 Bruxelles`
42
-
43
- #### Swiss Addresses
44
- - Format: `[Type] [Name] [Number], [Postal] [City], [Country]`
45
- - Examples:
46
- - `Rue du Rhône 50, 1204 Genève, Suisse`
47
- - `Chemin des Fleurs 8, 1006 Lausanne`
48
-
49
- #### Luxembourg Addresses
50
- - Format: `[Type] [Name] [Number], L-[Postal] [City]`
51
- - Examples:
52
- - `Avenue de la Liberté 10, L-1931 Luxembourg`
53
-
54
- #### City/Country Only
55
- - Format: Just the name
56
- - Examples: `Paris`, `Lyon`, `Bruxelles`, `France`
57
- - **Not anonymized** - preserved in plaintext
58
-
59
- ## Examples
60
-
61
- ### Before Implementation
62
-
63
- **Input document:**
64
- ```
65
- The company is located at 123 Rue de Rivoli, 75001 Paris, France.
66
- The court in Paris ruled...
67
- ```
68
-
69
- **Anonymized output:**
70
- ```
71
- The company is located at ADRESSE_01.
72
- The court in ADRESSE_02 ruled...
73
- ```
74
- ❌ Lost all geographic context, even city names
75
-
76
- ### After Implementation
77
-
78
- **Input document:**
79
- ```
80
- The company is located at 123 Rue de Rivoli, 75001 Paris, France.
81
- The court in Paris ruled...
82
- ```
83
-
84
- **Anonymized output:**
85
- ```
86
- The company is located at ADRESSE_01, 75001 Paris, France.
87
- The court in Paris ruled...
88
- ```
89
- ✅ Street anonymized, city/postal preserved, city-only name untouched
90
-
91
- ## Data Structure
92
-
93
- ### Mapping File Format
94
-
95
- ```json
96
- {
97
- "mapping": {
98
- "123 Rue de Rivoli": "ADRESSE_01"
99
- },
100
- "reverse_mapping": {
101
- "ADRESSE_01": ["123 Rue de Rivoli"]
102
- },
103
- "extracted_data": {
104
- "adresses": {
105
- "ADRESSE_01": {
106
- "original": "123 Rue de Rivoli, 75001 Paris, France",
107
- "code": "ADRESSE_01",
108
- "variants": ["123 Rue de Rivoli"],
109
- "score": 0.92,
110
- "recognizer": "GLiNER2Recognizer",
111
- "parsed": {
112
- "success": true,
113
- "is_city_only": false,
114
- "street_part": "123 Rue de Rivoli",
115
- "postal_code": "75001",
116
- "city": "Paris",
117
- "country": "France",
118
- "anonymization_strategy": "partial"
119
- }
120
- }
121
- }
122
- }
123
- }
124
- ```
125
-
126
- ### Anonymization Strategies
127
-
128
- | Strategy | Description | Example Input | Example Output |
129
- |----------|-------------|---------------|----------------|
130
- | `none` | City/country only, no anonymization | "Paris" | "Paris" |
131
- | `partial` | Street anonymized, city/postal/country preserved | "123 Rue de Rivoli, 75001 Paris, France" | "ADRESSE_01, 75001 Paris, France" |
132
- | `full` | Entire address anonymized (parse failure) | "Complex Format Address" | "ADRESSE_02" |
133
-
134
- ## Fallback Behavior
135
-
136
- | Scenario | Parsing Result | Strategy | Behavior |
137
- |----------|----------------|----------|----------|
138
- | Full address with street | `success: true`, `is_city_only: false` | `partial` | Anonymize street only |
139
- | City or country only | `success: true`, `is_city_only: true` | `none` | Keep visible (not in mapping) |
140
- | Unparseable address | `success: false` | `full` | Anonymize everything (safe fallback) |
141
- | Empty/invalid | `success: false` | `full` | Anonymize everything |
142
-
143
- ## Files Modified
144
-
145
- ### 1. `websocket-server/scripts/convert_and_scan_pipeline.py`
146
- - Added `parse_address()` function with regex patterns for French/Belgian/Swiss/Luxembourg addresses
147
- - Added `is_city_or_country_only()` and `is_known_city_or_country()` helper functions
148
- - Updated `convert_to_anonymization_format()` to parse addresses and apply strategies
149
- - Updated `merge_with_existing_mapping()` with same logic
150
-
151
- ### 2. `websocket-server/lib/anonymization-server.cjs`
152
- - Updated POST `/api/anonymize/text` route to handle partial address anonymization
153
- - Added special handling for addresses in both hierarchical and flat mapping formats
154
- - Updated de-anonymization logic to reconstruct full addresses from partial anonymization
155
-
156
- ### 3. `websocket-server/scripts/test_address_parsing.py` (new)
157
- - Comprehensive test suite with 16 test cases
158
- - Tests French, Belgian, Swiss, Luxembourg, city-only, and unparseable addresses
159
- - 100% test coverage
160
-
161
- ## Testing
162
-
163
- Run the test suite:
164
- ```bash
165
- python3 websocket-server/scripts/test_address_parsing.py
166
- ```
167
-
168
- Expected output:
169
- ```
170
- 🎉 All tests passed!
171
- Total tests: 16
172
- Passed: 16 (100%)
173
- Failed: 0
174
- ```
175
-
176
- ## Integration Testing
177
-
178
- To test with real documents:
179
-
180
- ```bash
181
- # Process a document with addresses
182
- python3 websocket-server/scripts/convert_and_scan_pipeline.py \
183
- test_document.pdf \
184
- -o output \
185
- --document-id test_partial
186
-
187
- # Check the mapping file
188
- cat output/mapping_test_partial.json | jq '.extracted_data.adresses | .[].parsed'
189
-
190
- # Verify:
191
- # 1. City-only addresses are NOT in the mapping
192
- # 2. Full addresses have parsed data with partial strategy
193
- # 3. Unparseable addresses have full strategy
194
- ```
195
-
196
- ## Safety Features
197
-
198
- 1. **City-only detection**: Cities and countries are never accidentally anonymized
199
- 2. **Parse failure fallback**: Unparseable addresses default to full anonymization (safest)
200
- 3. **No false negatives**: Street addresses are never left visible by mistake
201
- 4. **Validation**: 100% test coverage ensures reliability
202
-
203
- ## Performance
204
-
205
- - **Parsing success rate**: >90% for French addresses
206
- - **City-only detection**: 100% accuracy for known cities
207
- - **Fallback coverage**: 100% (all unparseable addresses handled safely)
208
- - **Zero false negatives**: No street addresses leaked
209
-
210
- ## Future Enhancements
211
-
212
- Potential improvements:
213
- - Add more European address formats (Spain, Italy, Germany)
214
- - Support US/UK address formats
215
- - ML-based address component recognition for complex formats
216
- - User-configurable city/country whitelist
@@ -1,134 +0,0 @@
1
- # Entity Deduplication Implementation Summary
2
-
3
- ## Changes Made to `convert_and_scan_pipeline.py`
4
-
5
- ### 1. Added Imports (Lines 34-42)
6
- ```python
7
- import unicodedata
8
- import re
9
- from typing import List, Optional, Tuple, Dict, Set
10
- ```
11
-
12
- ### 2. Added Helper Functions (Before `convert_to_anonymization_format()`)
13
-
14
- #### `normalize_name(text: str) -> str`
15
- - Removes diacritics (é → e, à → a, etc.)
16
- - Converts to lowercase
17
- - Removes honorifics/titles (Mr., Mrs., Ms., Dr., M., Mme., Maître, etc.)
18
- - Normalizes whitespace (multiple spaces → single space)
19
- - Returns normalized form for comparison only
20
-
21
- #### `are_names_similar(name1, norm1, name2, norm2) -> bool`
22
- - Checks if two names refer to the same person using multiple strategies:
23
- - Exact match after normalization
24
- - Substring match (one contains the other, min 3 chars)
25
- - Token-based match (all tokens of shorter name appear in longer)
26
-
27
- #### `consolidate_duplicate_entities(entities: List[Dict]) -> List[Dict]`
28
- - Groups entities by similarity
29
- - Handles both exact duplicates and variations (e.g., "Mr. Dupont" vs "Jean Dupont")
30
- - For each group:
31
- - Chooses longest variant as canonical text
32
- - Keeps highest score among all variants
33
- - Stores all unique variants (removes duplicates while preserving order)
34
- - Returns deduplicated entity list
35
-
36
- ### 3. Updated `convert_to_anonymization_format()`
37
-
38
- **Added pre-processing:**
39
- ```python
40
- # Consolidate PERSON entities to remove duplicates
41
- for entity_type in consolidated_entities.get("entities", {}).keys():
42
- if entity_type == "PERSON":
43
- consolidated_entities["entities"][entity_type] = consolidate_duplicate_entities(
44
- consolidated_entities["entities"][entity_type]
45
- )
46
- ```
47
-
48
- **Modified main loop:**
49
- - Removed: `mapping[text_lower] = code` (no lowercase in mapping)
50
- - Changed: `"variants": [text, text_lower]` → `"variants": variants`
51
- - Added: Loop through pre-consolidated variants and add each to mapping
52
- - Get variants from: `entity.get("variants", [text])`
53
-
54
- ### 4. Updated `merge_with_existing_mapping()`
55
-
56
- **Applied same changes:**
57
- - Removed: `merged_mapping[text_lower] = new_code`
58
- - Changed: `"variants": [text, text_lower]` → `"variants": variants`
59
- - Get variants from: `old_entry.get("variants", [text])`
60
- - Add all variants to merged mapping
61
-
62
- ## Expected Behavior
63
-
64
- ### Before (Current Output)
65
- ```json
66
- {
67
- "mapping": {
68
- "Mr. Dupont": "PERSONNE_PHYSIQUE_03",
69
- "mr. gilly": "PERSONNE_PHYSIQUE_03",
70
- "Mr. Dupont": "PERSONNE_PHYSIQUE_04", // duplicate gets different code
71
- "mr. gilly": "PERSONNE_PHYSIQUE_04",
72
- "Mr. Dupont": "PERSONNE_PHYSIQUE_05",
73
- "mr. gilly": "PERSONNE_PHYSIQUE_05",
74
- "Jean Dupont": "PERSONNE_PHYSIQUE_08"
75
- }
76
- }
77
- ```
78
-
79
- ### After (Fixed Output)
80
- ```json
81
- {
82
- "mapping": {
83
- "Jean Dupont": "PERSONNE_PHYSIQUE_03",
84
- "Mr. Dupont": "PERSONNE_PHYSIQUE_03",
85
- "Mr. Dupont": "PERSONNE_PHYSIQUE_03",
86
- "Mr.Dupont": "PERSONNE_PHYSIQUE_03"
87
- },
88
- "extracted_data": {
89
- "personnes_physiques": {
90
- "PERSONNE_PHYSIQUE_03": {
91
- "original": "Jean Dupont",
92
- "code": "PERSONNE_PHYSIQUE_03",
93
- "variants": ["Jean Dupont", "Mr. Dupont", "Mr. Dupont", "Mr.Dupont"],
94
- "score": 0.95,
95
- "recognizer": "GLiNER2Recognizer"
96
- }
97
- }
98
- }
99
- }
100
- ```
101
-
102
- ## Key Improvements
103
-
104
- 1. **No lowercase duplicates**: Removed redundant lowercase variants from mapping and variants array
105
- 2. **Exact duplicates consolidated**: Same person appearing multiple times gets single code
106
- 3. **Spacing variations handled**: "Mr. Dupont" vs "Mr. Dupont" vs "Mr.Dupont" → same code
107
- 4. **Name variations consolidated**: "Mr. Dupont" vs "Jean Dupont" → same code
108
- 5. **Longest variant as canonical**: "Jean Dupont" (longest) chosen over "Mr. Dupont"
109
- 6. **No duplicate variants**: Variants array contains only unique strings
110
- 7. **Non-PERSON entities unaffected**: Organizations and locations not consolidated
111
-
112
- ## Test Results
113
-
114
- All unit tests pass:
115
- - ✅ normalize_name() - 7/7 tests
116
- - ✅ are_names_similar() - 8/8 tests
117
- - ✅ consolidate_duplicate_entities() - 5/5 tests
118
-
119
- Test demonstrates:
120
- - 7 input entities → 3 unique persons
121
- - "Mr. Dupont" (appears twice) + "Mr. Dupont" + "Jean Dupont" + "Mr.Dupont" → single entity
122
- - Canonical form: "Jean Dupont" (longest)
123
- - Score: 0.95 (highest)
124
- - Variants: 4 unique strings (no duplicates)
125
-
126
- ## Next Steps for Verification
127
-
128
- 1. **Test with real document**: Process a document containing duplicate person names
129
- 2. **Compare entity counts**:
130
- - Before: ~185 PERSONNE_PHYSIQUE entries
131
- - After: ~90-100 entries (expected ~50% reduction)
132
- 3. **Verify consolidation**: Check that variations of same person get same code
133
- 4. **Verify non-PERSON entities**: Organizations and locations unaffected
134
- 5. **Regression test**: Different people still get different codes
@@ -1,138 +0,0 @@
1
- # GLiNER2.5 Entity Extractor
2
-
3
- ## Description
4
-
5
- PieceMaker utilise GLiNER2.5, un extracteur d'entités nommé multilingue basé sur
6
- la nouvelle architecture boundary de Fastino (287 M paramètres). Il détecte
7
- localement les entités sensibles dans les documents Markdown.
8
-
9
- ## Installation
10
-
11
- ```bash
12
- pip install 'gliner2[local]>=2.0.0'
13
- ```
14
-
15
- Le modèle `fastino/gliner2.5-multi-v1` est téléchargé par l’installateur
16
- (environ 1,1 Go). La migration depuis `fastino/gliner2-multi-v1` est obligatoire.
17
-
18
- ## Utilisation via l'interface
19
-
20
- 1. Cliquer sur le bouton 🏷️ dans la barre de contrôle
21
- 2. Sélectionner un ou plusieurs fichiers Markdown (.md)
22
- 3. Cliquer sur "▶ Extraire"
23
- 4. Les résultats sont sauvegardés dans le dossier de sortie configuré
24
-
25
- ## Utilisation en ligne de commande
26
-
27
- ```bash
28
- python presidio-gliner/presidio-gliner.py <fichier.md> -o <dossier_sortie>
29
- ```
30
-
31
- ### Exemple
32
-
33
- ```bash
34
- python presidio-gliner/presidio-gliner.py document.md -o ./presidio_gliner_output
35
- ```
36
-
37
- ## Entités détectées
38
-
39
- Le pipeline GLiNER2.5 + Presidio détecte notamment les types suivants :
40
-
41
- - **person**: Noms de personnes
42
- - **email**: Adresses email
43
- - **phone**: Numéros de téléphone (mobile et fixe)
44
- - **address**: Adresses physiques et localisations
45
- - **organization**: Noms d'entreprises et organisations
46
- - **date**: Dates (incluant dates de naissance)
47
- - **ssn**: Numéros de sécurité sociale
48
- - **credit_card**: Numéros de carte de crédit
49
- - **bank_account**: Numéros de compte bancaire
50
- - **passport**: Numéros de passeport
51
- - **ip_address**: Adresses IP
52
- - **url**: URLs et adresses web
53
-
54
- ## Format de sortie
55
-
56
- Le script génère un fichier JSON avec la structure suivante:
57
-
58
- ```json
59
- {
60
- "source_file": "/chemin/vers/fichier.md",
61
- "scanned_at": "2025-01-15T10:30:00Z",
62
- "entities": {
63
- "PERSON": [
64
- {
65
- "text": "John Doe",
66
- "start": 123,
67
- "end": 131,
68
- "score": 0.95,
69
- "recognizer": "gliner2"
70
- }
71
- ],
72
- "EMAIL": [
73
- {
74
- "text": "john.doe@example.com",
75
- "start": 145,
76
- "end": 165,
77
- "score": 0.98,
78
- "recognizer": "gliner2"
79
- }
80
- ]
81
- },
82
- "summary": {
83
- "total_entities_found": 15,
84
- "entity_types": ["PERSON", "EMAIL", "PHONE", "ADDRESS"],
85
- "model": "fastino/gliner2.5-multi-v1"
86
- }
87
- }
88
- ```
89
-
90
- ## Configuration
91
-
92
- ### Seuil de confiance
93
-
94
- Le scanner utilise le seuil de confiance 0,5 recommandé par défaut pour la
95
- nouvelle tête boundary. Les entités moins certaines ne sont pas retournées.
96
-
97
- ### Variables d'environnement
98
-
99
- - `GLINER2_SCAN_PATH`: Chemin personnalisé vers le script Python
100
- - `PYTHON_PATH`: Chemin vers l'interpréteur Python (défaut: `python3`)
101
-
102
- ## Comparaison avec Presidio
103
-
104
- | Caractéristique | GLiNER2 | Presidio |
105
- |----------------|---------|----------|
106
- | API | Simple, 1 modèle | Multiple composants |
107
- | Performance CPU | Optimisée | Plus lente |
108
- | Confidence scores | Natif | Natif |
109
- | Spans de texte | Natif | Natif |
110
- | Format de sortie | JSON natif | JSON natif |
111
- | Taille du modèle | 287M params | Variable |
112
- | Personnalisation | Labels flexibles | Patterns regex |
113
-
114
- ## Avantages de GLiNER2
115
-
116
- 1. **API simplifiée**: Un seul modèle, une seule méthode d'extraction
117
- 2. **Performance**: Optimisé pour CPU, inférence rapide
118
- 3. **Flexibilité**: Support de labels personnalisés sans réentraînement
119
- 4. **Extraction native**: Confidence scores et spans inclus sans post-processing
120
- 5. **Format JSON**: Output structuré directement utilisable
121
-
122
- ## Dépendances
123
-
124
- - Python 3.10+
125
- - `gliner2[local]>=2.0.0`
126
- - torch et transformers (installés par l’extra `local`)
127
-
128
- ## Limitations
129
-
130
- - Nécessite un téléchargement initial du modèle (~1,1 Go)
131
- - Performance optimale sur CPU moderne (multi-core recommandé)
132
- - Précision variable selon la qualité du texte source
133
-
134
- ## Support
135
-
136
- Pour plus d'informations sur GLiNER2.5 :
137
- - Documentation : https://github.com/fastino-ai/GLiNER2
138
- - Modèle : https://huggingface.co/fastino/gliner2.5-multi-v1