@piecemaker-legal/piecemaker 2.0.14 → 2.0.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/dist/assets/{FindReplaceDialog-KU5TEIBJ-DwLQyvTV.js → FindReplaceDialog-KU5TEIBJ-BS2IquHh.js} +1 -1
  2. package/dist/assets/{FootnotePropertiesDialog-W3YHM4BV-B-Lq3Wxh.js → FootnotePropertiesDialog-W3YHM4BV-BaIL33wg.js} +1 -1
  3. package/dist/assets/{HyperlinkDialog-ZYH7ZHRF-lLf2tPu5.js → HyperlinkDialog-ZYH7ZHRF-BjI9sWR4.js} +4 -4
  4. package/dist/assets/{ImagePositionDialog-HEWYR6Q3-DnzhuAuM.js → ImagePositionDialog-HEWYR6Q3-C6BO_ttK.js} +1 -1
  5. package/dist/assets/{ImagePropertiesDialog-RAB47C6M-DGut41Ic.js → ImagePropertiesDialog-RAB47C6M-CGjpLtTI.js} +1 -1
  6. package/dist/assets/{PageSetupDialog-AIGIXO3E-DoTOiKsJ.js → PageSetupDialog-AIGIXO3E-C5OGjPCn.js} +1 -1
  7. package/dist/assets/{SplitCellDialog-IFBKYCD6-DNV_hFKw.js → SplitCellDialog-IFBKYCD6-DTUKFpZo.js} +1 -1
  8. package/dist/assets/{TablePropertiesDialog-TMLKGOOW-Ba57AtqO.js → TablePropertiesDialog-TMLKGOOW-2c-bDH8r.js} +1 -1
  9. package/dist/assets/{WatermarkDialog-KRL7WMIS-DpO_30sj.js → WatermarkDialog-KRL7WMIS-BeAZ0XuJ.js} +1 -1
  10. package/dist/assets/{abnfDiagram-VCTEODGH-D0mpNf2t.js → abnfDiagram-VCTEODGH-Cafje0km.js} +1 -1
  11. package/dist/assets/{arc-Bv8e2GDC.js → arc-B1nvw-hX.js} +1 -1
  12. package/dist/assets/{architectureDiagram-5GKGNRK7-MQBi2I4-.js → architectureDiagram-5GKGNRK7-DenAnPvr.js} +1 -1
  13. package/dist/assets/{blockDiagram-I7D4REHJ-DstJr0pC.js → blockDiagram-I7D4REHJ-C9TX8a8H.js} +1 -1
  14. package/dist/assets/{c4Diagram-7LVT6UL2-DotOtTxX.js → c4Diagram-7LVT6UL2-Dm7WYR8n.js} +1 -1
  15. package/dist/assets/channel-DTNnyhVz.js +1 -0
  16. package/dist/assets/{chunk-2Q5K7J3B-B9gc2v9X.js → chunk-2Q5K7J3B-BzOJKJZR.js} +1 -1
  17. package/dist/assets/{chunk-5VM5RSS4-CqpHPwaS.js → chunk-5VM5RSS4-BRUszDMV.js} +1 -1
  18. package/dist/assets/{chunk-F27PBJKO-CWQVjEgx.js → chunk-F27PBJKO-DXmbip6-.js} +1 -1
  19. package/dist/assets/{chunk-IMKFNOWR-BQcQ4Jwa.js → chunk-IMKFNOWR-CLo5fiT7.js} +1 -1
  20. package/dist/assets/{chunk-JWPE2WC7-CekOmdH0.js → chunk-JWPE2WC7-BXctXDNM.js} +1 -1
  21. package/dist/assets/{chunk-POPQ4Y6H-pZoPNHJO.js → chunk-POPQ4Y6H-TKaN1BJU.js} +1 -1
  22. package/dist/assets/{chunk-SVP7TREG-CVT-NRlT.js → chunk-SVP7TREG-2Y_i2api.js} +1 -1
  23. package/dist/assets/{chunk-TICWLB2K-Z3lcU-HD.js → chunk-TICWLB2K-D67Oeu-d.js} +1 -1
  24. package/dist/assets/{chunk-XXDRQBXY-gMwZV5S8.js → chunk-XXDRQBXY-C8btsXvp.js} +1 -1
  25. package/dist/assets/classDiagram-ZZMXUADV-DEpZ2Aie.js +1 -0
  26. package/dist/assets/classDiagram-v2-VYDZK3BY-DEpZ2Aie.js +1 -0
  27. package/dist/assets/{cose-bilkent-JH36ORCC-BOB0fNzU.js → cose-bilkent-JH36ORCC-CDjmznJD.js} +1 -1
  28. package/dist/assets/{cynefin-OW5HDTMX-LjWmlV2d.js → cynefin-OW5HDTMX-Cz2Zila7.js} +1 -1
  29. package/dist/assets/{cynefinDiagram-5FMLGOSQ-BeHh6fRm.js → cynefinDiagram-5FMLGOSQ-CCDUntcs.js} +1 -1
  30. package/dist/assets/{dagre-GXQ25YYZ-PDH35d23.js → dagre-GXQ25YYZ-uf93EB4q.js} +1 -1
  31. package/dist/assets/{diagram-S7CK7UJ4-Dp43fqwJ.js → diagram-S7CK7UJ4-CWD5w1S0.js} +1 -1
  32. package/dist/assets/{diagram-UQ7AKVKN-C1uaZ7Ig.js → diagram-UQ7AKVKN-BupQSG7M.js} +1 -1
  33. package/dist/assets/{diagram-VSXAHHWV-b8UrSsgG.js → diagram-VSXAHHWV-CBQKW_yS.js} +1 -1
  34. package/dist/assets/{diagram-VX7I27RA-C47mA-f5.js → diagram-VX7I27RA-eWkYnL2g.js} +1 -1
  35. package/dist/assets/{diagram-Z3DM3KII-Ou-0Eovi.js → diagram-Z3DM3KII-eTIwrxxP.js} +1 -1
  36. package/dist/assets/{ebnfDiagram-PWID7BFC-aDi11OMO.js → ebnfDiagram-PWID7BFC-DJZxQQmA.js} +1 -1
  37. package/dist/assets/{erDiagram-RLTQ6QDP-BlytbfKL.js → erDiagram-RLTQ6QDP-BT8C_kdQ.js} +1 -1
  38. package/dist/assets/{flowDiagram-HODETNUW-DwhhloRz.js → flowDiagram-HODETNUW-CraoY0mi.js} +1 -1
  39. package/dist/assets/{ganttDiagram-EL5Y4UJY-D_F7V6ja.js → ganttDiagram-EL5Y4UJY-ZaXfhnzT.js} +1 -1
  40. package/dist/assets/{gitGraphDiagram-WWUBYQGX-CzbrEY2k.js → gitGraphDiagram-WWUBYQGX-BSuHCYPJ.js} +1 -1
  41. package/dist/assets/index-C1854KB7.css +1 -0
  42. package/dist/assets/{index-CIz0Nvp7.js → index-DIIIoNKx.js} +140 -140
  43. package/dist/assets/{infoDiagram-27XIBGKW-C94uRMDo.js → infoDiagram-27XIBGKW-D6JUTMr9.js} +1 -1
  44. package/dist/assets/{ishikawaDiagram-5VMMS53U-ChnIieKx.js → ishikawaDiagram-5VMMS53U-2SNX3Hct.js} +1 -1
  45. package/dist/assets/{journeyDiagram-3NMN7TZE-oA_qMCz8.js → journeyDiagram-3NMN7TZE-BfLxikQz.js} +1 -1
  46. package/dist/assets/{kanban-definition-UXKFOSKX-Fz6-FHOs.js → kanban-definition-UXKFOSKX-D-0rPWC6.js} +1 -1
  47. package/dist/assets/{layout-CJCUH450.js → layout-UbVHo6lA.js} +1 -1
  48. package/dist/assets/{linear-C9nZWhdo.js → linear-Cznk7QbI.js} +1 -1
  49. package/dist/assets/{mermaid.core-BeRDJU42.js → mermaid.core-BoSxdsJv.js} +6 -6
  50. package/dist/assets/{mindmap-definition-YA3MSWOX-CaJbUiMZ.js → mindmap-definition-YA3MSWOX-CGRFQBXc.js} +1 -1
  51. package/dist/assets/{pegDiagram-XKGWAZYB-DJjbKz1y.js → pegDiagram-XKGWAZYB-3iXA_L6R.js} +1 -1
  52. package/dist/assets/{pieDiagram-E7YTZNPT-CW-BLG1L.js → pieDiagram-E7YTZNPT-CarSnOYt.js} +1 -1
  53. package/dist/assets/{quadrantDiagram-AXDQQJYC-CiSMX_OO.js → quadrantDiagram-AXDQQJYC-BQ-GK9LK.js} +1 -1
  54. package/dist/assets/{railroadDiagram-O6MQD6OU-CTIuvunz.js → railroadDiagram-O6MQD6OU-BdFRm0Mb.js} +1 -1
  55. package/dist/assets/{requirementDiagram-BXWQKSXE-B-HUu134.js → requirementDiagram-BXWQKSXE-8MgrmWC2.js} +1 -1
  56. package/dist/assets/{sankeyDiagram-P5KCCOFB-B1p2E7hR.js → sankeyDiagram-P5KCCOFB-C9sw-tkq.js} +1 -1
  57. package/dist/assets/{sequenceDiagram-WJ2MYXX4-CZ3c10t3.js → sequenceDiagram-WJ2MYXX4-D0PC5AQ3.js} +1 -1
  58. package/dist/assets/{sizeCapture-INFHLROL-BgmoRqos.js → sizeCapture-INFHLROL-DbL8fCKK.js} +1 -1
  59. package/dist/assets/{stateDiagram-D77RDMKH-DPqnJMDr.js → stateDiagram-D77RDMKH-D1hcL0yu.js} +1 -1
  60. package/dist/assets/{stateDiagram-v2-MP3YSRHH-BJOyC96W.js → stateDiagram-v2-MP3YSRHH-Zer7OO4Q.js} +1 -1
  61. package/dist/assets/{swimlanes-42K2YHIH-77lt2sGV.js → swimlanes-42K2YHIH-CaFxs4HW.js} +1 -1
  62. package/dist/assets/swimlanesDiagram-VR7AAH4N-D6dVAhUV.js +8 -0
  63. package/dist/assets/{timeline-definition-24CTP7MA-CxYTGgqp.js → timeline-definition-24CTP7MA-CicB5MP7.js} +1 -1
  64. package/dist/assets/{vennDiagram-4TSXK5OY-CEJXvAap.js → vennDiagram-4TSXK5OY-DC1WE4bR.js} +1 -1
  65. package/dist/assets/{wardleyDiagram-VM6X3IG4-DIQwX6bQ.js → wardleyDiagram-VM6X3IG4-C0XiXv2M.js} +1 -1
  66. package/dist/assets/{xychartDiagram-S5SC5T6Z-n9jd-Xax.js → xychartDiagram-S5SC5T6Z-CSZ90TfD.js} +1 -1
  67. package/dist/index.html +2 -2
  68. package/dist/sw.js +1 -1
  69. package/dist-server/server/piecemaker/desktop-update/index.js +3 -2
  70. package/dist-server/server/piecemaker/desktop-update/index.js.map +1 -1
  71. package/dist-server/server/piecemaker/harness/citation-instructions.js +2 -2
  72. package/dist-server/server/piecemaker/harness/citation-store.js +1 -1
  73. package/dist-server/server/piecemaker/harness/citation-store.js.map +1 -1
  74. package/dist-server/server/piecemaker/knowledge/local-routes.js +1 -1
  75. package/dist-server/server/piecemaker/knowledge/local-routes.js.map +1 -1
  76. package/dist-server/server/piecemaker/knowledge/pipeline.js +12 -1
  77. package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
  78. package/dist-server/server/piecemaker/knowledge/routes.js +1 -1
  79. package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
  80. package/dist-server/server/piecemaker/knowledge/scan-jobs.js +13 -0
  81. package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -1
  82. package/dist-server/server/piecemaker/knowledge/service.js +3 -2
  83. package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
  84. package/package.json +1 -1
  85. package/server/piecemaker/desktop-update/index.ts +3 -2
  86. package/server/piecemaker/harness/citation-instructions.ts +2 -2
  87. package/server/piecemaker/harness/citation-store.ts +1 -1
  88. package/server/piecemaker/knowledge/local-routes.ts +1 -1
  89. package/server/piecemaker/knowledge/pipeline.ts +20 -2
  90. package/server/piecemaker/knowledge/routes.ts +1 -1
  91. package/server/piecemaker/knowledge/scan-jobs.ts +19 -1
  92. package/server/piecemaker/knowledge/service.ts +3 -2
  93. package/server/piecemaker/vendor/installer/steps/04-conversion-md.mjs +46 -9
  94. package/server/piecemaker/vendor/installer/steps/07-legifrance.mjs +3 -3
  95. package/server/piecemaker/vendor/piecemaker-plugin/README.md +8 -17
  96. package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -1
  97. package/server/piecemaker/vendor/piecemaker-plugin/skills/recherche-juridique/SKILL.md +19 -34
  98. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +6 -1
  99. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +10 -2
  100. package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +67 -13
  101. package/server/piecemaker/vendor/websocket-server/scripts/mineru_improved_1.py +17 -5
  102. package/server/piecemaker/vendor/websocket-server/scripts/smart_converter.py +20 -3
  103. package/dist/assets/channel-UVnVNzmE.js +0 -1
  104. package/dist/assets/classDiagram-ZZMXUADV-B5s2HyRp.js +0 -1
  105. package/dist/assets/classDiagram-v2-VYDZK3BY-B5s2HyRp.js +0 -1
  106. package/dist/assets/index-C5slQNvE.css +0 -1
  107. package/dist/assets/swimlanesDiagram-VR7AAH4N-D2sHCxQu.js +0 -8
@@ -1 +1 @@
1
- {"version":3,"file":"scan-jobs.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/scan-jobs.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"scan-jobs.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/scan-jobs.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;AAajC,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,KAAK,CAAW;IAEzB,YAAY,KAAe;QACzB,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC5D,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF;AAmBD,MAAM,sBAAsB,GAAG,CAAC,GAAG,MAAM,CAAC;AAE1C,SAAS,SAAS,CAAC,GAAqB;IACtC,OAAO,GAAG,CAAC,KAAK,KAAK,SAAS,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,uBAAuB;IACrC,MAAM,IAAI,GAAG,IAAI,GAAG,EAA4B,CAAC;IACjD,MAAM,WAAW,GAAG,IAAI,GAAG,EAA2B,CAAC;IAEvD,MAAM,KAAK,GAAG,GAAG,EAAE;QACjB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,sBAAsB,CAAC;QACrD,KAAK,MAAM,CAAC,EAAE,EAAE,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7B,IAAI,SAAS,CAAC,GAAG,CAAC;gBAAE,SAAS;YAC7B,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,UAAU,IAAI,GAAG,CAAC,SAAS,CAAC,GAAG,QAAQ;gBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;IACH,CAAC,CAAC;IAEF,MAAM,iBAAiB,GAAG,CAAC,SAAiB,EAA2B,EAAE;QACvE,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;YAAE,IAAI,GAAG,CAAC,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC;gBAAE,OAAO,GAAG,CAAC;QAC/F,OAAO,IAAI,CAAC;IACd,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,SAAiB,EAAE,GAAiG;YACxH,KAAK,EAAE,CAAC;YACR,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAC7C,IAAI,OAAO;gBAAE,OAAO,OAAO,CAAC;YAC5B,MAAM,GAAG,GAAqB;gBAC5B,EAAE,EAAE,MAAM,CAAC,UAAU,EAAE;gBACvB,SAAS;gBACT,MAAM,EAAE,WAAW;gBACnB,MAAM,EAAE,WAAW;gBACnB,KAAK,EAAE,SAAS;gBAChB,KAAK,EAAE,SAAS;gBAChB,OAAO,EAAE,CAAC;gBACV,SAAS,EAAE,CAAC;gBACZ,KAAK,EAAE,CAAC;gBACR,KAAK,EAAE,IAAI;gBACX,WAAW,EAAE,IAAI;gBACjB,MAAM,EAAE,IAAI;gBACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;gBACnC,UAAU,EAAE,IAAI;aACjB,CAAC;YACF,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;YACtB,MAAM,MAAM,GAAG,CAAC,QAA+B,EAAE,EAAE;gBACjD,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;oBAAE,OAAO;gBACpC,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;gBAC3B,GAAG,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;gBACrE,GAAG,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,CAAC;gBACnC,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,GAAG,CAAC,KAAK,CAAC;YAC1C,CAAC,CAAC;YACF,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;YACzC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;YACpC,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,MAAe,EAAE,EAAE;gBACtD,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;oBAAE,OAAO;gBACpC,GAAG,CAAC,KAAK,GAAG,MAAM,CAAC;gBACnB,GAAG,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACrB,GAAG,CAAC,OAAO,GAAG,GAAG,CAAC;gBAClB,GAAG,CAAC,MAAM,GAAG,MAAM,IAAI,IAAI,CAAC;YAC9B,CAAC,EAAE,CAAC,KAAc,EAAE,EAAE;gBACpB,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;oBAAE,OAAO;gBACpC,IAAI,KAAK,YAAY,gBAAgB,EAAE,CAAC;oBACtC,GAAG,CAAC,KAAK,GAAG,cAAc,CAAC;oBAC3B,GAAG,CAAC,WAAW,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;oBACzC,OAAO;gBACT,CAAC;gBACD,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC;gBACpB,GAAG,CAAC,KAAK,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACrE,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;gBACd,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC3B,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC9D,CAAC,CAAC,CAAC;YACH,OAAO,GAAG,CAAC;QACb,CAAC;QACD,GAAG,CAAC,EAAW;YACb,KAAK,EAAE,CAAC;YACR,OAAO,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QAC9D,CAAC;QACD,iBAAiB,CAAC,SAAiB;YACjC,KAAK,EAAE,CAAC;YACR,OAAO,iBAAiB,CAAC,SAAS,CAAC,CAAC;QACtC,CAAC;QACD,MAAM,CAAC,GAA4B;YACjC,IAAI,CAAC,GAAG,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS;gBAAE,OAAO,GAAG,CAAC;YAChD,GAAG,CAAC,KAAK,GAAG,WAAW,CAAC;YACxB,GAAG,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;YAC1C,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC;YACjC,WAAW,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC3B,OAAO,GAAG,CAAC;QACb,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -22,11 +22,12 @@ export function createKnowledgeService(store, projects, pipeline) {
22
22
  graph(value) {
23
23
  return store.snapshot(ensureProject(value));
24
24
  },
25
- scan(value, files) {
25
+ scan(value, files, ocrMissing) {
26
26
  const id = ensureProject(value);
27
+ const ocrChoice = ocrMissing === 'ask' ? 'ask' : 'continue';
27
28
  return {
28
29
  job: scanJobs.start(id, async (report, signal) => {
29
- const result = await pipeline.scan(id, files, report, signal);
30
+ const result = await pipeline.scan(id, files, report, signal, ocrChoice);
30
31
  store.markAnonymizationComplete(id);
31
32
  return result;
32
33
  }),
@@ -1 +1 @@
1
- {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAMzD,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9F,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAqB,EAAE,QAAuB,EAAE,QAAoD;IACzI,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAG,CAAC,KAAc,EAAU,EAAE;QAC/C,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,KAA0B;YAC9B,OAAO,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACtG,CAAC;QACD,MAAM,CAAC,KAA2B;YAChC,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,KAAK,CAAC,KAAc;YAClB,OAAO,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,KAAc,EAAE,KAAe;YAClC,MAAM,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YAChC,OAAO;gBACL,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;oBAC/C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;oBAC9D,KAAK,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;oBACpC,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC;aACH,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,KAAc,EAAE,KAAe;YACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrG,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC;QACD,UAAU,CAAC,KAAc,EAAE,KAAe;YACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrG,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"service.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/service.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAMzD,SAAS,SAAS,CAAC,KAAc;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,SAAS,CAAC,wBAAwB,CAAC,CAAC;IAC9F,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,KAAqB,EAAE,QAAuB,EAAE,QAAoD;IACzI,MAAM,QAAQ,GAAG,uBAAuB,EAAE,CAAC;IAC3C,MAAM,aAAa,GAAG,CAAC,KAAc,EAAU,EAAE;QAC/C,MAAM,EAAE,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;QACxE,OAAO,EAAE,CAAC;IACZ,CAAC,CAAC;IACF,OAAO;QACL,KAAK,CAAC,KAA0B;YAC9B,OAAO,KAAK,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,SAAS,EAAE,CAAC,CAAC;QACtG,CAAC;QACD,MAAM,CAAC,KAA2B;YAChC,OAAO,KAAK,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,EAAE,SAAS,EAAE,aAAa,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,KAAK,CAAC,KAAc;YAClB,OAAO,KAAK,CAAC,QAAQ,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QAC9C,CAAC;QACD,IAAI,CAAC,KAAc,EAAE,KAAe,EAAE,UAAoB;YACxD,MAAM,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,CAAC;YAChC,MAAM,SAAS,GAAG,UAAU,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC;YAC5D,OAAO;gBACL,GAAG,EAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;oBAC/C,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;oBACzE,KAAK,CAAC,yBAAyB,CAAC,EAAE,CAAC,CAAC;oBACpC,OAAO,MAAM,CAAC;gBAChB,CAAC,CAAC;aACH,CAAC;QACJ,CAAC;QACD,OAAO,CAAC,KAAc,EAAE,KAAe;YACrC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrG,OAAO,EAAE,GAAG,EAAE,CAAC;QACjB,CAAC;QACD,UAAU,CAAC,KAAc,EAAE,KAAe;YACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAiB,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YACrG,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACvC,CAAC;KACF,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@piecemaker-legal/piecemaker",
3
- "version": "2.0.14",
3
+ "version": "2.0.16",
4
4
  "productName": "PieceMaker",
5
5
  "description": "Plateforme IA pour juristes français",
6
6
  "type": "module",
@@ -1,4 +1,5 @@
1
1
  import { spawn } from 'node:child_process';
2
+ import os from 'node:os';
2
3
  import path from 'node:path';
3
4
 
4
5
  import { loadProductConfig } from '../../../shared/product-config.mjs';
@@ -8,7 +9,7 @@ import { createDesktopUpdateService } from './service.js';
8
9
 
9
10
  function runInstaller(command: string, environment: NodeJS.ProcessEnv) {
10
11
  return new Promise<{ exitCode: number | null; output: string; errorOutput: string }>((resolve, reject) => {
11
- const child = spawn('sh', ['-c', command], { env: environment, detached: true, stdio: ['ignore', 'pipe', 'pipe'] });
12
+ const child = spawn('sh', ['-c', command], { cwd: os.homedir(), env: environment, detached: true, stdio: ['ignore', 'pipe', 'pipe'] });
12
13
  let output = '';
13
14
  let errorOutput = '';
14
15
  child.stdout.on('data', (chunk: Buffer) => {
@@ -33,7 +34,7 @@ function productRepository(appRoot: string): string | null {
33
34
  }
34
35
 
35
36
  function launchDetached(command: string) {
36
- spawn('sh', ['-c', command], { detached: true, stdio: 'ignore' }).unref();
37
+ spawn('sh', ['-c', command], { cwd: os.homedir(), detached: true, stdio: 'ignore' }).unref();
37
38
  }
38
39
 
39
40
  export function createPieceMakerDesktopUpdateRouter(appRoot: string) {
@@ -1,10 +1,10 @@
1
1
  const OPEN = '<PIECEMAKER_CITATION_INSTRUCTIONS>';
2
2
  const CLOSE = '</PIECEMAKER_CITATION_INSTRUCTIONS>';
3
3
  const INSTRUCTIONS = `${OPEN}
4
- Pour les citations de pièces et de jurisprudence : ne citer que des sources lues dans ce tour. Chercher, trier, puis lire les sources retenues avant de citer. Lire les décisions Légifrance avec consulter_decision : un titre, un sommaire ou Download_Query_Results ne vaut pas lecture du texte intégral.
4
+ Pour les citations de pièces et de jurisprudence : ne citer que des sources lues dans ce tour. Chercher, trier, puis lire les sources retenues avant de citer. Lire les décisions Légifrance ou Judilibre avec consulter_decision : un titre ou un sommaire ne vaut pas lecture du texte intégral.
5
5
  Copier les extraits littéralement. Au plus 3 extraits par citation, chacun de 25 mots maximum. Utiliser les marqueurs [1], [2], etc., contigus et dans l'ordre de première apparition. Une entrée par référence ; réutiliser la référence pour la même citation.
6
6
  Terminer toute réponse comportant ces citations par un bloc <CITATIONS> contenant un tableau JSON strict, puis </CITATIONS>. Sans citation, ne pas ajouter de bloc.
7
- Décision : {"ref":1,"kind":"case","decision_id":"identifiant Legifrance lu","quotes":[{"quote":"extrait exact"}]}.
7
+ Décision : {"ref":1,"kind":"case","decision_id":"identifiant Légifrance ou Judilibre lu","quotes":[{"quote":"extrait exact"}]}.
8
8
  Pièce : {"ref":2,"kind":"document","doc_id":"chemin relatif au dossier du Markdown converti","quotes":[{"page":1,"quote":"extrait exact"}]}.
9
9
  Une plage de pages prend la forme "1-2" ; [[PAGE_BREAK]] sépare les segments des deux pages. Les champs sheet et cell peuvent localiser une citation de tableur. Ne pas inventer une source indisponible ; expliquer qu'elle n'a pas pu être lue.
10
10
  ${CLOSE}`;
@@ -60,7 +60,7 @@ export function createCitationStore(homeDir: string) {
60
60
  try {
61
61
  const snapshot = JSON.parse(await readFile(path.join(directory, `${token}.json`), 'utf8')) as CitationSnapshot;
62
62
  const id = snapshot.citation.decision_id;
63
- if (forViewing && !snapshot.source && typeof id === 'string' && /^(JURITEXT|CETATEXT)\d{12}$/.test(id)) {
63
+ if (forViewing && !snapshot.source && typeof id === 'string' && /^(?:(?:JURITEXT|CETATEXT)\d{12}|[0-9a-f]{24})$/.test(id)) {
64
64
  try {
65
65
  const file = path.join(homeDir, 'decisions', `${id}.json`);
66
66
  const info = await lstat(file);
@@ -53,7 +53,7 @@ export function createKnowledgeLocalRouter(
53
53
 
54
54
  router.post('/scan', (request, response) => respond(() => {
55
55
  const id = resolveProjectId(request.body);
56
- return { projectId: id, ...getService().scan(id, request.body?.files) };
56
+ return { projectId: id, ...getService().scan(id, request.body?.files, request.body?.ocrMissing) };
57
57
  }, response));
58
58
 
59
59
  router.get('/scan/job', (request, response) => respond(() => {
@@ -10,7 +10,8 @@ import type { KnowledgeStore } from '../../../plugins/piecemaker-dossier/src/kno
10
10
  import { persistScanResult, scanResultOperations } from '../../../plugins/piecemaker-dossier/src/scan-result.js';
11
11
  import type { GlinerDocument, GlinerMappingDocument, JsonData } from '../../../plugins/piecemaker-dossier/src/types.js';
12
12
 
13
- import type { KnowledgeScanProgress } from './scan-jobs.js';
13
+ import { OcrRequiredError } from './scan-jobs.js';
14
+ import type { KnowledgeScanProgress, OcrMissingChoice } from './scan-jobs.js';
14
15
 
15
16
  type ProjectLookup = {
16
17
  getProjectById(projectId: string): { project_id: string; project_path: string } | null;
@@ -35,6 +36,7 @@ type OriginalsPipeline = {
35
36
  signal?: AbortSignal;
36
37
  input?: string;
37
38
  onMapping?: (mapping: unknown) => void;
39
+ onOcrRequired?: (payload: unknown) => void;
38
40
  }): Promise<unknown>;
39
41
  };
40
42
 
@@ -141,6 +143,11 @@ function textValue(value: unknown): string {
141
143
  return typeof value === 'string' ? value.trim() : '';
142
144
  }
143
145
 
146
+ function ocrRequiredFiles(payload: unknown): string[] {
147
+ const files = payload && typeof payload === 'object' ? (payload as { files?: unknown }).files : null;
148
+ return Array.isArray(files) ? files.filter((file): file is string => typeof file === 'string') : [];
149
+ }
150
+
144
151
  async function withPythonPath<T>(pythonPath: string, run: () => Promise<T>): Promise<T> {
145
152
  const previous = process.env.PYTHON_PATH;
146
153
  process.env.PYTHON_PATH = pythonPath;
@@ -155,7 +162,13 @@ async function withPythonPath<T>(pythonPath: string, run: () => Promise<T>): Pro
155
162
  export function createKnowledgePipeline(options: PipelineOptions) {
156
163
  const script = path.join(options.applicationRoot, 'server', 'piecemaker', 'vendor', 'websocket-server', 'scripts', 'convert_and_scan_pipeline.py');
157
164
  return {
158
- async scan(projectId: string, requestedFiles?: unknown, onProgress?: (progress: KnowledgeScanProgress) => void, signal?: AbortSignal) {
165
+ async scan(
166
+ projectId: string,
167
+ requestedFiles?: unknown,
168
+ onProgress?: (progress: KnowledgeScanProgress) => void,
169
+ signal?: AbortSignal,
170
+ ocrMissing: OcrMissingChoice = 'continue',
171
+ ) {
159
172
  const project = options.projects.getProjectById(projectId);
160
173
  if (!project) throw new Error('Project not found.');
161
174
  const projectPath = fs.realpathSync(project.project_path);
@@ -177,9 +190,12 @@ export function createKnowledgePipeline(options: PipelineOptions) {
177
190
  projectPath,
178
191
  '--state-file',
179
192
  stateFile,
193
+ '--ocr-missing',
194
+ ocrMissing,
180
195
  ];
181
196
  if (!explicitFiles) args.push('--skip-existing');
182
197
  let received: GlinerMappingDocument | null = null;
198
+ let ocrRequired: string[] | null = null;
183
199
  try {
184
200
  await withPythonPath(pythonExecutable(options.pythonPath), () => runManagedPythonJob({
185
201
  action: 'anonymize',
@@ -189,8 +205,10 @@ export function createKnowledgePipeline(options: PipelineOptions) {
189
205
  signal,
190
206
  input: JSON.stringify(seed),
191
207
  onMapping: (value) => { received = value as GlinerMappingDocument; },
208
+ onOcrRequired: (value) => { ocrRequired = ocrRequiredFiles(value); },
192
209
  }));
193
210
  } catch (error) {
211
+ if (ocrRequired) throw new OcrRequiredError(ocrRequired);
194
212
  if (received) options.store.update({ projectId, operations: scanResultOperations({ projectId, mapping: received, documents: [] }) });
195
213
  throw error;
196
214
  }
@@ -20,7 +20,7 @@ export function createKnowledgeRouter(service: KnowledgeService) {
20
20
  router.get('/knowledge/graph', (request, response) => respond(() => service.graph(request.query.projectId), response));
21
21
  router.post('/knowledge/query', (request, response) => respond(() => service.query(request.body), response));
22
22
  router.post('/knowledge/update', (request, response) => respond(() => service.update(request.body), response));
23
- router.post('/knowledge/scan', (request, response) => respond(() => service.scan(request.body?.projectId, request.body?.files), response));
23
+ router.post('/knowledge/scan', (request, response) => respond(() => service.scan(request.body?.projectId, request.body?.files, request.body?.ocrMissing), response));
24
24
  router.get('/knowledge/scan/job', (request, response) => respond(() => service.scanJob(request.query.id, request.query.projectId), response));
25
25
  router.post('/knowledge/scan/cancel', (request, response) => respond(() => service.cancelScan(request.body?.id, request.body?.projectId), response));
26
26
  return router;
@@ -9,17 +9,29 @@ export type KnowledgeScanProgress = {
9
9
  total: number;
10
10
  };
11
11
 
12
+ export type OcrMissingChoice = 'ask' | 'continue';
13
+
14
+ export class OcrRequiredError extends Error {
15
+ readonly files: string[];
16
+
17
+ constructor(files: string[]) {
18
+ super('Pièces scannées : MinerU (OCR) n’est pas installé.');
19
+ this.files = files;
20
+ }
21
+ }
22
+
12
23
  export type KnowledgeScanJob = {
13
24
  id: string;
14
25
  projectId: string;
15
26
  source: 'knowledge';
16
27
  action: 'anonymize';
17
- state: 'running' | 'done' | 'error' | 'cancelled';
28
+ state: 'running' | 'done' | 'error' | 'cancelled' | 'ocr-required';
18
29
  phase: KnowledgeScanPhase;
19
30
  percent: number;
20
31
  processed: number;
21
32
  total: number;
22
33
  error: string | null;
34
+ ocrRequired: { files: string[] } | null;
23
35
  result: unknown;
24
36
  startedAt: string;
25
37
  finishedAt: string | null;
@@ -64,6 +76,7 @@ export function createKnowledgeScanJobs() {
64
76
  processed: 0,
65
77
  total: 0,
66
78
  error: null,
79
+ ocrRequired: null,
67
80
  result: null,
68
81
  startedAt: new Date().toISOString(),
69
82
  finishedAt: null,
@@ -86,6 +99,11 @@ export function createKnowledgeScanJobs() {
86
99
  job.result = result ?? null;
87
100
  }, (error: unknown) => {
88
101
  if (job.state !== 'running') return;
102
+ if (error instanceof OcrRequiredError) {
103
+ job.state = 'ocr-required';
104
+ job.ocrRequired = { files: error.files };
105
+ return;
106
+ }
89
107
  job.state = 'error';
90
108
  job.error = error instanceof Error ? error.message : String(error);
91
109
  }).finally(() => {
@@ -30,11 +30,12 @@ export function createKnowledgeService(store: KnowledgeStore, projects: ProjectL
30
30
  graph(value: unknown) {
31
31
  return store.snapshot(ensureProject(value));
32
32
  },
33
- scan(value: unknown, files?: unknown) {
33
+ scan(value: unknown, files?: unknown, ocrMissing?: unknown) {
34
34
  const id = ensureProject(value);
35
+ const ocrChoice = ocrMissing === 'ask' ? 'ask' : 'continue';
35
36
  return {
36
37
  job: scanJobs.start(id, async (report, signal) => {
37
- const result = await pipeline.scan(id, files, report, signal);
38
+ const result = await pipeline.scan(id, files, report, signal, ocrChoice);
38
39
  store.markAnonymizationComplete(id);
39
40
  return result;
40
41
  }),
@@ -23,6 +23,47 @@ export const meta = {
23
23
 
24
24
  const SCRIPTS_DIR = path.join(REPO_ROOT, 'websocket-server', 'scripts');
25
25
  const SMART_CONVERTER = path.join(SCRIPTS_DIR, 'smart_converter.py');
26
+ const MINERU_SPEC = 'mineru[pipeline,vlm]==2.7.6';
27
+
28
+ function venvScript(vp, name) {
29
+ return path.join(vp.binDir, process.platform === 'win32' ? `${name}.exe` : name);
30
+ }
31
+
32
+ function pipelineModelsReady() {
33
+ try {
34
+ const config = JSON.parse(fs.readFileSync(path.join(os.homedir(), 'mineru.json'), 'utf8'));
35
+ const modelDir = config?.['models-dir']?.pipeline;
36
+ return Boolean(modelDir) && fs.existsSync(modelDir);
37
+ } catch {
38
+ return false;
39
+ }
40
+ }
41
+
42
+ async function installMineru(vp) {
43
+ const spin = spinner('Installation de MinerU...');
44
+ const installed = await run(vp.python, ['-m', 'pip', 'install', MINERU_SPEC], {
45
+ cwd: os.homedir(),
46
+ onLine: (line) => spin.update(line.slice(0, 100)),
47
+ });
48
+ if (installed !== 0) {
49
+ spin.fail('Échec de l\'installation de MinerU');
50
+ return false;
51
+ }
52
+ spin.succeed('MinerU installé');
53
+ if (pipelineModelsReady()) return true;
54
+ const models = spinner('Téléchargement des modèles MinerU...');
55
+ const downloaded = await run(venvScript(vp, 'mineru-models-download'), ['-s', 'huggingface', '-m', 'pipeline'], {
56
+ cwd: os.homedir(),
57
+ env: { ...process.env, MINERU_MODEL_SOURCE: 'huggingface' },
58
+ onLine: (line) => models.update(line.slice(0, 100)),
59
+ });
60
+ if (downloaded !== 0) {
61
+ models.fail('Échec du téléchargement des modèles MinerU');
62
+ return false;
63
+ }
64
+ models.succeed('Modèles MinerU téléchargés');
65
+ return true;
66
+ }
26
67
 
27
68
  function checkImports(pythonBin) {
28
69
  return runCapture(pythonBin, ['-c', 'import markitdown, pypdf']);
@@ -89,19 +130,15 @@ export async function install(ctx) {
89
130
 
90
131
  // 2. Optional MinerU install — heavy (PyTorch-class deps), only needed for
91
132
  // scanned PDFs / images that have no extractable text layer.
92
- const wantMineru = await confirm(
133
+ const mineruRequested = process.env.PIECEMAKER_INSTALL_MINERU === '1';
134
+ const wantMineru = mineruRequested || await confirm(
93
135
  'Installer MinerU (OCR pour PDF scannés et images) ? Optionnel, volumineux (plusieurs centaines de Mo à quelques Go de dépendances).',
94
136
  false
95
137
  );
96
138
  let mineruNote = '';
97
139
  if (wantMineru) {
98
- const spin = spinner('Installation de MinerU...');
99
- const code = await run(vp.python, ['-m', 'pip', 'install', '-U', 'mineru'], {
100
- onLine: (line) => spin.update(line.slice(0, 100)),
101
- });
102
- if (code === 0) spin.succeed('MinerU installé');
103
- else {
104
- spin.fail('Échec de l\'installation de MinerU');
140
+ if (!(await installMineru(vp))) {
141
+ if (mineruRequested) return { status: 'failed', note: 'MinerU n\'a pas pu être installé.' };
105
142
  mineruNote = ' MinerU n\'a pas pu être installé automatiquement — consultez sa documentation pour l\'installer manuellement.';
106
143
  }
107
144
  } else {
@@ -139,7 +176,7 @@ export async function check(ctx) {
139
176
  return { status: 'failed', note: 'markitdown ou pypdf non installés.' };
140
177
  }
141
178
  // MinerU is optional (OCR only) — its absence does not degrade the status.
142
- const mineruAvailable = runCapture('mineru', ['--version']).code === 0;
179
+ const mineruAvailable = runCapture(venvScript(vp, 'mineru'), ['--version']).code === 0;
143
180
  return {
144
181
  status: 'done',
145
182
  note: mineruAvailable ? '' : 'MinerU non installé (optionnel — nécessaire seulement pour l\'OCR des PDF scannés).',
@@ -25,9 +25,9 @@ export const meta = {
25
25
 
26
26
  const MARKETPLACE_NAME = 'mcp-legifrance';
27
27
  const MARKETPLACE_REPO = 'PieceMaker-Legal/mcp-legifrance';
28
- const PLUGIN_NAME = 'legifrance';
28
+ const PLUGIN_NAME = 'piecemaker';
29
29
  const PLUGIN_SPEC = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
30
- const MINIMUM_PLUGIN_VERSION = '1.0.0';
30
+ const MINIMUM_PLUGIN_VERSION = '1.1.0';
31
31
  const REGISTRATION_URL = 'https://piste.gouv.fr/registration';
32
32
  const CATALOG_URL = 'https://piste.gouv.fr/api-catalog-all';
33
33
  const PISTE_ENV = 'production';
@@ -53,7 +53,7 @@ function pluginState(capture = runCapture) {
53
53
  if (result.code !== 0) return { known: false, installed: false, enabled: false, installPath: null, version: null };
54
54
  const plugins = parseJson(result.stdout, []);
55
55
  const plugin = Array.isArray(plugins)
56
- ? plugins.find((item) => item.id === PLUGIN_SPEC || item.name === PLUGIN_NAME)
56
+ ? plugins.find((item) => item.id === PLUGIN_SPEC)
57
57
  : null;
58
58
  return {
59
59
  known: true,
@@ -84,25 +84,16 @@ serveur et l'étape 06 réconcilient cet enregistrement.
84
84
  L'étape `07-legifrance` installe le plugin autonome depuis
85
85
  `PieceMaker-Legal/mcp-legifrance`. Son runtime, ses tests, son venv et sa
86
86
  configuration MCP ne vivent plus dans ce dépôt. Le plugin est identifié dans
87
- Claude par `legifrance`, avec le namespace `mcp__plugin_legifrance_legifrance`.
87
+ Claude par `piecemaker@mcp-legifrance`, avec le namespace
88
+ `mcp__plugin_piecemaker_legifrance`.
88
89
 
89
90
  Les identifiants PISTE sont copiés avec des permissions 0600 dans
90
91
  `~/.config/mcp-legifrance/.env`. Le `.env` PieceMaker reste alimenté pour
91
92
  l'administration et la migration des installations antérieures.
92
93
 
93
- Deux outils complètent les recherches ponctuelles :
94
-
95
- - `Build_Research_Corpus` fige plusieurs requêtes, déduplique, télécharge et
96
- scanne chaque texte intégral ; un filtre booléen auditable ferme les
97
- incompatibilités certaines, puis prépare toutes les candidates en lots de
98
- 30 décisions au plus par défaut ;
99
- - `Validate_Research_Cards` exige une fiche par décision, confirme chaque
100
- citation dans le texte source et produit la matrice ainsi que les métriques
101
- de couverture et de consommation.
102
-
103
- Ce flux n'utilise ni embeddings, ni base vectorielle, ni top-k. Le filtre
104
- statique exige la présence conjointe d'un contexte SA et d'une révocation située
105
- à 300 caractères au plus d'une fonction dirigeante ; chaque cooccurrence d'une
106
- candidate est conservée. Les tokens sont annoncés comme estimés tant qu'un usage
107
- exact du fournisseur n'a pas été passé au validateur. L'implémentation et ses
108
- tests appartiennent désormais au dépôt MCP autonome.
94
+ `Search_Jurisprudence` est le seul outil de recherche jurisprudentielle : il
95
+ interroge Légifrance et Judilibre en un appel, avec les mêmes filtres et la même
96
+ requête booléenne, et fusionne les doublons. `Build_Research_Corpus` utilise le
97
+ même moteur pour figer une formulation, télécharger et scanner chaque texte
98
+ intégral, puis préparer les lots de revue, sans embeddings, base vectorielle ni
99
+ top-k. L'implémentation et ses tests appartiennent au dépôt MCP autonome.
@@ -42,7 +42,9 @@ Bridge (`taskpane/modules/python-bridge.js` →
42
42
  - **`auto`** (par défaut) — inspecte le fichier et choisit automatiquement
43
43
  entre les deux ; c'est le choix par défaut à laisser tel quel sauf besoin
44
44
  spécifique (ex. forcer `mineru` sur un PDF qui a une couche de texte
45
- corrompue ou illisible).
45
+ corrompue ou illisible). Si MinerU n'est pas installé, un scan passe par
46
+ markitdown : le Markdown obtenu est vide ou presque. Le signaler à
47
+ l'utilisateur plutôt que d'en conclure que la pièce est vide.
46
48
 
47
49
  ## Enchaînement avec le scan PII
48
50
 
@@ -22,51 +22,37 @@ effectivement disponibles, puis le format exact que le vérificateur accepte.
22
22
 
23
23
  | Outil | Rôle |
24
24
  | --- | --- |
25
- | `Search_Cour_Cassation` | Recherche ciblée dans la jurisprudence de la Cour de cassation (mots-clés, opérateurs ET/OU, expression exacte, référence d'article), filtrable par matière et publication au bulletin. |
26
- | `Search_Conseil_Etat` | Même recherche ciblée dans la jurisprudence du Conseil d'État, filtrable par publication au recueil Lebon. |
27
- | `Search_Cour_Appel` | Même recherche dans les cours d'appel, filtrable par ville — bien cibler (ville + dates), le volume est important. |
28
- | `Search_CAA` | Même recherche dans les cours administratives d'appel, filtrable par ville. |
29
- | `Search_Premiere_Instance` | Recherche dans les juridictions de première instance — volume très limité (~50 décisions), opérateur OU par défaut. |
25
+ | `Search_Jurisprudence` | Seul outil de recherche jurisprudentielle : interroge en un appel Légifrance et Judilibre pour la Cour de cassation, les cours d'appel, la première instance, le Conseil d'État et les CAA, avec les mêmes filtres (`matiere` obligatoire en cassation, publication, villes, `types_premiere_instance` obligatoire en première instance, recueil Lebon, dates) et la même requête (guillemets, `ET`, `OU`, parenthèses, articles). Les doublons Légifrance/Judilibre sont fusionnés ; au-delà de 500 résultats cumulés, la recherche est refusée. |
30
26
  | `Search_Code` | Recherche dans les codes juridiques français (Code civil, Code du travail…) — référence d'article exacte (`L. 1235-3`), mots-clés ou expression exacte. Renvoie les identifiants `LEGIARTI…` des articles trouvés. |
31
27
  | `consulter_article` | Texte intégral et vigueur d'une version précise d'article, à partir de son identifiant `LEGIARTI…` rendu par `Search_Code`. |
32
- | `consulter_decision` | Rapatrie le texte intégral d'une décision à partir de son identifiant (`JURITEXT…`, `CETATEXT…`). **Rapatrie le texte intégral et le met en cache** (voir plus bas) — c'est le moyen normal de lire une décision avant de la citer. |
33
- | `Download_Query_Results` | Télécharge en masse tous les résultats d'une requête dans un dossier local, pour trier sans paginer. **Ne rapatrie pas le texte intégral** (voir l'avertissement ci-dessous) — sert au tri, jamais directement à la citation. |
34
- | `Build_Research_Corpus` | Construit un corpus exhaustif et reproductible sur une question de droit : plusieurs requêtes, déduplication, téléchargement et scan du texte intégral de chaque décision. **Rapatrie le texte intégral.** À utiliser pour une recherche large et systématique plutôt qu'un enchaînement manuel de `Search_*`. |
35
- | `Validate_Research_Cards` | Valide mécaniquement (sans LLM) le résultat de `Build_Research_Corpus` : une fiche par décision, citations confirmées dans le texte intégral, rapport de couverture. |
28
+ | `consulter_decision` | Rapatrie le texte intégral d'une décision à partir de son identifiant Légifrance (`JURITEXT…`, `CETATEXT…`) ou Judilibre (24 caractères hexadécimaux). **Rapatrie le texte intégral et le met en cache** (voir plus bas) — c'est le moyen normal de lire une décision avant de la citer. |
29
+ | `Build_Research_Corpus` | Construit un corpus exhaustif et reproductible sur une question de droit : une formulation, recherchée par le même moteur et avec les mêmes filtres que `Search_Jurisprudence`, déduplication, téléchargement et scan du texte intégral de chaque décision. **Rapatrie le texte intégral.** À utiliser pour une recherche large et systématique plutôt qu'une suite de pages de `Search_Jurisprudence`. |
36
30
  | `Tracking_BODACC` | Situation d'une entreprise (procédures collectives) via son SIREN — hors jurisprudence, utile pour qualifier une partie. |
37
31
 
38
32
  ### Le fait décisif : seuls deux chemins rendent une citation vérifiable
39
33
 
40
34
  Le vérificateur ne peut confirmer une citation que si le texte intégral de sa
41
- source est quelque part sur disque. Sur les trois façons dont le MCP restitue
42
- une décision, **une seule ne rapatrie pas ce texte** :
35
+ source est quelque part sur disque :
43
36
 
44
37
  - **`Build_Research_Corpus`** écrit `decisions.jsonl` (une décision par ligne,
45
38
  champ `texte` = texte intégral réel) — vérifiable.
46
39
  - **`consulter_decision`** renvoie le texte intégral dans sa réponse d'outil ;
47
40
  le hook `decision-cache.mjs` le capte au passage et l'écrit dans
48
41
  `~/.piecemaker/decisions/<id>.json` — vérifiable.
49
- - **`Download_Query_Results`** écrit `results.json`, mais chaque entrée ne
50
- contient que `id`, `titre`, `lien`, `date`, `analyse` (un sommaire) et,
51
- optionnellement, `solution.dispositif` (le dispositif seul — jamais les
52
- motifs). **Pas de texte intégral.** Citer une décision connue uniquement par
53
- ce canal produira une citation non vérifiée et bloquera le tour.
54
-
55
- **Conséquence pratique** : `Download_Query_Results` sert à trier une liste de
56
- résultats (lire les titres/sommaires, écarter le hors-sujet). Dès qu'une
57
- décision de cette liste doit être citée, il faut d'abord la lire avec
58
- `consulter_decision` (ou l'avoir dans un corpus `Build_Research_Corpus`) —
59
- jamais citer directement depuis `results.json`.
42
+
43
+ **Conséquence pratique** : les résultats de `Search_Jurisprudence` (titre,
44
+ analyse, extraits) servent à trier. Dès qu'une décision doit être citée, il
45
+ faut d'abord la lire avec `consulter_decision` (ou l'avoir dans un corpus
46
+ `Build_Research_Corpus`).
60
47
 
61
48
  ## Déroulé de recherche
62
49
 
63
- 1. **Recherche large** avec l'outil `Search_*` adapté à la juridiction visée
50
+ 1. **Recherche large** avec `Search_Jurisprudence` sur les juridictions visées
64
51
  (ou `Build_Research_Corpus` pour une question de droit qui mérite un
65
52
  balayage systématique plutôt qu'une requête isolée). Pour un texte de loi,
66
53
  `Search_Code`.
67
- 2. **Tri** des résultats sur les seuls éléments déjà renvoyés (titre, sommaire,
68
- date, `analyse`) — sans lire chaque décision en entier. `Download_Query_Results`
69
- aide à trier un grand volume hors ligne.
54
+ 2. **Tri** des résultats sur les seuls éléments déjà renvoyés (titre, analyse,
55
+ date, extraits) — sans lire chaque décision en entier.
70
56
  3. **Lecture** des seules décisions/articles retenus comme potentiellement
71
57
  cite-worthy : `consulter_decision` (jurisprudence) ou `consulter_article`
72
58
  (texte de loi), ou relecture du `decisions.jsonl` d'un corpus déjà construit.
@@ -114,9 +100,9 @@ prend l'une des deux formes suivantes.
114
100
  ### Forme « jurisprudence » (`kind: "case"`)
115
101
 
116
102
  Identifie la décision par `decision_id` — l'identifiant Légifrance
117
- (`JURITEXT…`, `CETATEXT…`) tel que rendu par `Search_*`/`Download_Query_Results`/
118
- `Build_Research_Corpus`, et lu avec `consulter_decision` (ou présent dans un
119
- `decisions.jsonl`).
103
+ (`JURITEXT…`, `CETATEXT…`) ou Judilibre (24 caractères hexadécimaux) tel que
104
+ rendu par `Search_Jurisprudence`/`Build_Research_Corpus`, et lu avec
105
+ `consulter_decision` (ou présent dans un `decisions.jsonl`).
120
106
 
121
107
  ```json
122
108
  {
@@ -208,9 +194,8 @@ retombe sur un tableau `quotes` d'un seul élément :
208
194
 
209
195
  1. Parse le bloc `<CITATIONS>` du dernier message.
210
196
  2. Pour chaque citation, résout sa source réelle — texte intégral de la
211
- décision (corpus `Build_Research_Corpus`, cache `consulter_decision`, ou en
212
- dernier recours le sommaire de `Download_Query_Results`) ou pièce
213
- Markdown du dossier.
197
+ décision (corpus `Build_Research_Corpus` ou cache `consulter_decision`) ou
198
+ pièce Markdown du dossier.
214
199
  3. Localise mécaniquement chaque extrait dans ce texte. Un extrait qui a
215
200
  légèrement dérivé (espace, casse, ponctuation) est **corrigé
216
201
  automatiquement** avec l'extrait source exact — ce n'est pas une faute.
@@ -224,8 +209,8 @@ citation si elle ne peut pas être justifiée par une source effectivement lue.
224
209
 
225
210
  ## Ce qu'il ne faut pas faire
226
211
 
227
- - Ne jamais citer une décision connue uniquement par un résultat
228
- `Download_Query_Results` sans l'avoir d'abord lue avec `consulter_decision`.
212
+ - Ne jamais citer une décision connue uniquement par un résultat de
213
+ `Search_Jurisprudence` sans l'avoir d'abord lue avec `consulter_decision`.
229
214
  - Ne jamais paraphraser un extrait pour qu'il « sonne » comme la source — le
230
215
  vérificateur tolère l'espace/la casse/la ponctuation, pas le sens.
231
216
  - Ne jamais laisser un `ref` sauter un numéro ou repartir en désordre.
@@ -1638,7 +1638,12 @@ function startInstallJob(repoRoot, component) {
1638
1638
  windowsHide: true,
1639
1639
  stdio: ['ignore', 'pipe', 'pipe'],
1640
1640
  // PIECEMAKER_YES=1 : accepte les valeurs par défaut (MinerU inclus) sans TTY.
1641
- env: { ...process.env, PIECEMAKER_YES: '1', NO_COLOR: '1' },
1641
+ env: {
1642
+ ...process.env,
1643
+ PIECEMAKER_YES: '1',
1644
+ NO_COLOR: '1',
1645
+ ...(component === 'mineru' ? { PIECEMAKER_INSTALL_MINERU: '1' } : {}),
1646
+ },
1642
1647
  });
1643
1648
  const tailStderr = [];
1644
1649
  const onLine = (chunk) => {
@@ -255,6 +255,14 @@ function spawnTracked(job, script, args, progressScale = {}, io = {}) {
255
255
  }
256
256
  continue;
257
257
  }
258
+ if (line.startsWith('OCR_REQUIRED:')) {
259
+ try {
260
+ io.onOcrRequired?.(JSON.parse(line.slice('OCR_REQUIRED:'.length)));
261
+ } catch (error) {
262
+ errorLines.push(`pièces à OCR illisibles : ${error.message}`);
263
+ }
264
+ continue;
265
+ }
258
266
  const progress = /^PROGRESS:([A-Z]+):(\d+):(\d+):(\d+)/.exec(line.trim());
259
267
  if (!progress) continue;
260
268
  const [, marker, pct, current, total] = progress;
@@ -341,7 +349,7 @@ function spawnTracked(job, script, args, progressScale = {}, io = {}) {
341
349
  * `onProgress`, si fourni, est appelé à chaque mise à jour de la progression
342
350
  * avec `{ phase, percent, processed, total }`.
343
351
  */
344
- function runManagedPythonJob({ action, script, args, onProgress, signal, input, onMapping } = {}) {
352
+ function runManagedPythonJob({ action, script, args, onProgress, signal, input, onMapping, onOcrRequired } = {}) {
345
353
  if (!['convert', 'anonymize'].includes(action)) throw new Error('Action inconnue.');
346
354
  if (!acceptingJobs) throw new Error('Le serveur est en cours d’arrêt : aucun nouveau traitement ne peut démarrer.');
347
355
  const job = {
@@ -375,7 +383,7 @@ function runManagedPythonJob({ action, script, args, onProgress, signal, input,
375
383
  if (signal.aborted) abort();
376
384
  else signal.addEventListener('abort', abort, { once: true });
377
385
  }
378
- const run = () => spawnTracked(job, script, args, {}, { input, onMapping });
386
+ const run = () => spawnTracked(job, script, args, {}, { input, onMapping, onOcrRequired });
379
387
  const descriptor = { job, run };
380
388
  const completion = new Promise((resolve, reject) => {
381
389
  descriptor.resolve = resolve;