@piecemaker-legal/piecemaker 2.0.15 → 2.0.17
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.
- package/dist/assets/{FindReplaceDialog-KU5TEIBJ-Cp2ZFN7K.js → FindReplaceDialog-KU5TEIBJ-B4N6W1_z.js} +1 -1
- package/dist/assets/{FootnotePropertiesDialog-W3YHM4BV-pWCpugJN.js → FootnotePropertiesDialog-W3YHM4BV-D_X_JkAZ.js} +1 -1
- package/dist/assets/{HyperlinkDialog-ZYH7ZHRF-CbCWgVs6.js → HyperlinkDialog-ZYH7ZHRF-EbyukgDx.js} +4 -4
- package/dist/assets/{ImagePositionDialog-HEWYR6Q3-Du2r0Wko.js → ImagePositionDialog-HEWYR6Q3-D9jEaxlE.js} +1 -1
- package/dist/assets/{ImagePropertiesDialog-RAB47C6M-DLpeqGpW.js → ImagePropertiesDialog-RAB47C6M-DvA1kZnM.js} +1 -1
- package/dist/assets/{PageSetupDialog-AIGIXO3E-B_CipGFt.js → PageSetupDialog-AIGIXO3E-ChfsKF43.js} +1 -1
- package/dist/assets/{SplitCellDialog-IFBKYCD6-xMFwbIsB.js → SplitCellDialog-IFBKYCD6-uM26FNXt.js} +1 -1
- package/dist/assets/{TablePropertiesDialog-TMLKGOOW-Fz1cRdQ9.js → TablePropertiesDialog-TMLKGOOW-By6EQI5w.js} +1 -1
- package/dist/assets/{WatermarkDialog-KRL7WMIS-7suU5cvL.js → WatermarkDialog-KRL7WMIS-Bss9F6Ej.js} +1 -1
- package/dist/assets/{abnfDiagram-VCTEODGH-BKCg5tMI.js → abnfDiagram-VCTEODGH-yLjNPHY7.js} +1 -1
- package/dist/assets/{arc-BxB5WTHo.js → arc-CMQiMSh4.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-CM1c0ORG.js → architectureDiagram-5GKGNRK7-Cyna8IJZ.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-BH0vcN7C.js → blockDiagram-I7D4REHJ-DHAdjRYY.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-Z9_RzazA.js → c4Diagram-7LVT6UL2-qqZ0w4LC.js} +1 -1
- package/dist/assets/channel-B3AYuE-l.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-OQRYTAt1.js → chunk-2Q5K7J3B-NS0halN6.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DBpdDz0k.js → chunk-5VM5RSS4-BF6-6Cah.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-npTlDSfn.js → chunk-F27PBJKO-Dnj2jFRB.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-Cxrz4ZaK.js → chunk-IMKFNOWR-CmRgl1EE.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DK86pmtC.js → chunk-JWPE2WC7-BwC19UFc.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-uVCWOMNU.js → chunk-POPQ4Y6H-C1YWVD4-.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-hdcvsO4Z.js → chunk-SVP7TREG-D7XQTPRq.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-DQ2F5I7F.js → chunk-TICWLB2K-BkmTGk1O.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-oLFixl7-.js → chunk-XXDRQBXY-CYW7YgXL.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-CE2Zkr7h.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-CE2Zkr7h.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-b32g5AYD.js → cose-bilkent-JH36ORCC-BSktt6pW.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-CvzWSkfP.js → cynefin-OW5HDTMX-BNMRWXNG.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-eNSRssDp.js → cynefinDiagram-5FMLGOSQ-Dk59YHuO.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-ByshmYfw.js → dagre-GXQ25YYZ-DFhWeh0x.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-DM734w6p.js → diagram-S7CK7UJ4-BH_8x-q5.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-CeIgNHVI.js → diagram-UQ7AKVKN-DmxmlXg5.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-BCET7ibB.js → diagram-VSXAHHWV-DpG29cD4.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-BWH0JZL-.js → diagram-VX7I27RA-CvvYXTie.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-C6BrIsgm.js → diagram-Z3DM3KII-xOXaaZqs.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-B_n61ePe.js → ebnfDiagram-PWID7BFC-CtfFGqJB.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-BZJ1h673.js → erDiagram-RLTQ6QDP-AoCjoHUY.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-cymoZryb.js → flowDiagram-HODETNUW-Bl9_mq95.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-CPr5f3_S.js → ganttDiagram-EL5Y4UJY-DREJQ2BY.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-S3PeYZkU.js → gitGraphDiagram-WWUBYQGX-C1q5-iep.js} +1 -1
- package/dist/assets/index-C1854KB7.css +1 -0
- package/dist/assets/{index-KoMJ5vMA.js → index-RKNvOXcq.js} +140 -140
- package/dist/assets/{infoDiagram-27XIBGKW-CHua8hTk.js → infoDiagram-27XIBGKW-Cz2KUKWU.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-BMPmgP2f.js → ishikawaDiagram-5VMMS53U-BU6SdWsw.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-Dx8ezs5g.js → journeyDiagram-3NMN7TZE-CMMoiPf0.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-CnGlA00D.js → kanban-definition-UXKFOSKX-KpKnC3dd.js} +1 -1
- package/dist/assets/{layout-DdxskZT3.js → layout-6C8d-KNC.js} +1 -1
- package/dist/assets/{linear-CfdU6qlL.js → linear-CUINCO59.js} +1 -1
- package/dist/assets/{mermaid.core-D2KvaDg4.js → mermaid.core-ClgFTKfs.js} +6 -6
- package/dist/assets/{mindmap-definition-YA3MSWOX-CMoIPKDH.js → mindmap-definition-YA3MSWOX-oywqmpy6.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-DcemvKop.js → pegDiagram-XKGWAZYB-Uk65qoVL.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-BZEYiM_X.js → pieDiagram-E7YTZNPT-XxQhMRKu.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-CiAFc6a4.js → quadrantDiagram-AXDQQJYC-Djngo9IG.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-DLmf01wa.js → railroadDiagram-O6MQD6OU-C4I8SNPI.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-BMFvgV-y.js → requirementDiagram-BXWQKSXE-D62oiVFl.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-B4fcaIgK.js → sankeyDiagram-P5KCCOFB-HZuSub58.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-BHpaOBPQ.js → sequenceDiagram-WJ2MYXX4-B8_t7SDx.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BsOv244V.js → sizeCapture-INFHLROL-D2Lk0zlm.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-DM2-SXRt.js → stateDiagram-D77RDMKH-DC3NnV2S.js} +1 -1
- package/dist/assets/{stateDiagram-v2-MP3YSRHH-DIJgYrCw.js → stateDiagram-v2-MP3YSRHH-DSsQOGCi.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-CZmZpYra.js → swimlanes-42K2YHIH-6RzklsF9.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-ZU4NRSFy.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-D1ckb3Ke.js → timeline-definition-24CTP7MA-Beuacf_x.js} +1 -1
- package/dist/assets/{vennDiagram-4TSXK5OY-CgU7Doxj.js → vennDiagram-4TSXK5OY-CMqthbQr.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-BACRuQOS.js → wardleyDiagram-VM6X3IG4-DKrdN08q.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-D8sG0Qsi.js → xychartDiagram-S5SC5T6Z-BtMW2Qlh.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-server/server/piecemaker/desktop-update/index.js +3 -2
- package/dist-server/server/piecemaker/desktop-update/index.js.map +1 -1
- package/dist-server/server/piecemaker/harness/citation-instructions.js +2 -2
- package/dist-server/server/piecemaker/harness/citation-store.js +1 -1
- package/dist-server/server/piecemaker/harness/citation-store.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/local-routes.js +1 -1
- package/dist-server/server/piecemaker/knowledge/local-routes.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/pipeline.js +12 -1
- package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/routes.js +1 -1
- package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js +13 -0
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/service.js +3 -2
- package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
- package/package.json +2 -1
- package/scripts/piecemaker/cli/lib/plugins.mjs +28 -30
- package/scripts/piecemaker/cli/piecemaker-command.test.mjs +7 -0
- package/scripts/piecemaker/cli/piecemaker.mjs +9 -3
- package/server/piecemaker/desktop-update/index.ts +3 -2
- package/server/piecemaker/harness/citation-instructions.ts +2 -2
- package/server/piecemaker/harness/citation-store.ts +1 -1
- package/server/piecemaker/knowledge/local-routes.ts +1 -1
- package/server/piecemaker/knowledge/pipeline.ts +20 -2
- package/server/piecemaker/knowledge/routes.ts +1 -1
- package/server/piecemaker/knowledge/scan-jobs.ts +19 -1
- package/server/piecemaker/knowledge/service.ts +3 -2
- package/server/piecemaker/vendor/installer/steps/04-conversion-md.mjs +46 -9
- package/server/piecemaker/vendor/installer/steps/07-legifrance.mjs +3 -3
- package/server/piecemaker/vendor/piecemaker-plugin/README.md +8 -17
- package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -1
- package/server/piecemaker/vendor/piecemaker-plugin/skills/recherche-juridique/SKILL.md +19 -34
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +6 -1
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +10 -2
- package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +67 -13
- package/server/piecemaker/vendor/websocket-server/scripts/mineru_improved_1.py +17 -5
- package/server/piecemaker/vendor/websocket-server/scripts/smart_converter.py +20 -3
- package/dist/assets/channel-LQJzz1dz.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BaS6lPLe.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-BaS6lPLe.js +0 -1
- package/dist/assets/index-C5slQNvE.css +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-kkl3-vaA.js +0 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scan-jobs.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/scan-jobs.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"scan-jobs.js","sourceRoot":"","sources":["../../../../server/piecemaker/knowledge/scan-jobs.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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.
|
|
3
|
+
"version": "2.0.17",
|
|
4
4
|
"productName": "PieceMaker",
|
|
5
5
|
"description": "Plateforme IA pour juristes français",
|
|
6
6
|
"type": "module",
|
|
@@ -44,6 +44,7 @@
|
|
|
44
44
|
"desktop": "electron electron/main.js",
|
|
45
45
|
"desktop:dev": "cross-env ELECTRON_DEV_URL=http://127.0.0.1:5173 electron electron/main.js",
|
|
46
46
|
"desktop:stage": "node scripts/release/prepare-desktop-app.js",
|
|
47
|
+
"plugins": "node plugins/toolchain/cli.mjs",
|
|
47
48
|
"desktop:pack": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --dir",
|
|
48
49
|
"desktop:dist:mac": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --mac dmg",
|
|
49
50
|
"desktop:dist:win": "npm run build && npm run desktop:stage && electron-builder --projectDir .desktop-build/desktop-app --win nsis",
|
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { pathToFileURL } from 'node:url';
|
|
3
4
|
|
|
4
5
|
import { APP } from './config.mjs';
|
|
5
|
-
import { runInherited } from './exec.mjs';
|
|
6
|
-
import { runtimeEnv } from './node-runtime.mjs';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
{ id: 'piecemaker-telegram', label: 'Plugin Telegram' },
|
|
16
|
-
{ id: 'piecemaker-tabular-review', label: 'Plugin Tabular Review' },
|
|
17
|
-
];
|
|
18
|
-
|
|
19
|
-
export async function installPlugins(runtime, report) {
|
|
20
|
-
for (const plugin of PLUGINS) {
|
|
21
|
-
const installer = path.join(APP.directory, 'plugins', plugin.id, 'install.mjs');
|
|
22
|
-
if (!fs.existsSync(installer)) {
|
|
23
|
-
report.warn(`${plugin.label} — source introuvable`);
|
|
24
|
-
continue;
|
|
25
|
-
}
|
|
7
|
+
// Délègue à la chaîne commune du dépôt cible (plugins/toolchain, voir
|
|
8
|
+
// plugins.md) — la même que celle de l'application Electron.
|
|
9
|
+
async function toolchain() {
|
|
10
|
+
const entry = path.join(APP.directory, 'plugins', 'toolchain', 'index.mjs');
|
|
11
|
+
if (!fs.existsSync(entry)) throw new Error(`chaîne des plugins absente (${entry})`);
|
|
12
|
+
return import(pathToFileURL(entry).href);
|
|
13
|
+
}
|
|
26
14
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
15
|
+
/**
|
|
16
|
+
* `rebuild` : recompile depuis les sources (installation complète). Sinon,
|
|
17
|
+
* réinstalle seulement depuis le dernier bundle (réparation au lancement).
|
|
18
|
+
* Renvoie vrai si un plugin a été posé ou retiré.
|
|
19
|
+
*/
|
|
20
|
+
export async function installPlugins(report, { rebuild }) {
|
|
21
|
+
try {
|
|
22
|
+
const { installPlugins: install } = await toolchain();
|
|
23
|
+
const result = await install({
|
|
24
|
+
appRoot: APP.directory,
|
|
25
|
+
rebuild,
|
|
26
|
+
log: (plugin) => report.detail(`${plugin.label} compilé`),
|
|
27
|
+
logger: { log() {}, error: (message) => report.warn(message) },
|
|
32
28
|
});
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
29
|
+
for (const id of result.installed) report.ok(`Plugin ${id} — installé`);
|
|
30
|
+
for (const id of result.removed) report.ok(`Plugin ${id} — retiré`);
|
|
31
|
+
if (!result.installed.length && !result.removed.length && !result.failed.length) report.ok('Plugins PieceMaker — à jour');
|
|
32
|
+
return result.installed.length > 0 || result.removed.length > 0;
|
|
33
|
+
} catch (error) {
|
|
34
|
+
report.warn(`Plugins PieceMaker — ${error.message}`);
|
|
35
|
+
return false;
|
|
38
36
|
}
|
|
39
37
|
}
|
|
@@ -23,3 +23,10 @@ test('the desktop launcher binds to the installed piecemaker binary', () => {
|
|
|
23
23
|
assert.equal(executable.startsWith(BIN_DIR) || executable.includes(`${path.sep}node${path.sep}` ) || executable.includes('versions/node'), true);
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
|
+
|
|
27
|
+
test('plugins are installed through the shared toolchain, before the application starts', () => {
|
|
28
|
+
const plugins = fs.readFileSync(path.join(here, 'lib', 'plugins.mjs'), 'utf8');
|
|
29
|
+
assert.match(plugins, /'plugins', 'toolchain', 'index\.mjs'/);
|
|
30
|
+
const main = fs.readFileSync(path.join(here, 'piecemaker.mjs'), 'utf8');
|
|
31
|
+
assert.ok(main.indexOf('await installPlugins(') < main.indexOf('await resetAndLaunch('));
|
|
32
|
+
});
|
|
@@ -129,7 +129,15 @@ async function main() {
|
|
|
129
129
|
if (command.shims.length) ok(`installée : ${command.executable}`);
|
|
130
130
|
else warn('commande absente du PATH — relancez node scripts/piecemaker/cli/install-command.mjs');
|
|
131
131
|
|
|
132
|
-
|
|
132
|
+
// Les plugins sont posés AVANT le démarrage : l'hôte ne lance les serveurs de
|
|
133
|
+
// plugins (Telegram, Tabular Review) qu'à son boot, et l'interface ne lit la
|
|
134
|
+
// liste des plugins qu'au chargement. Installés après coup, ils restaient
|
|
135
|
+
// invisibles ou inertes jusqu'au lancement suivant.
|
|
136
|
+
if (!options.launchOnly) await synchroniseRepositories(runtime);
|
|
137
|
+
step('Plugins PieceMaker');
|
|
138
|
+
const pluginsChanged = await installPlugins(report, { rebuild: !options.launchOnly });
|
|
139
|
+
|
|
140
|
+
if (!options.launchOnly || pluginsChanged || !(await applicationIsRunning())) {
|
|
133
141
|
const running = await resetAndLaunch(runtime);
|
|
134
142
|
if (!running) return 1;
|
|
135
143
|
} else {
|
|
@@ -137,9 +145,7 @@ async function main() {
|
|
|
137
145
|
}
|
|
138
146
|
|
|
139
147
|
if (!options.launchOnly) {
|
|
140
|
-
await synchroniseRepositories(runtime);
|
|
141
148
|
await installComponents(runtime, report);
|
|
142
|
-
await installPlugins(runtime, report);
|
|
143
149
|
}
|
|
144
150
|
|
|
145
151
|
await installPwa();
|
|
@@ -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
|
|
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
|
|
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
|
|
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(
|
|
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
|
|
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
|
-
|
|
99
|
-
|
|
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 = '
|
|
28
|
+
const PLUGIN_NAME = 'piecemaker';
|
|
29
29
|
const PLUGIN_SPEC = `${PLUGIN_NAME}@${MARKETPLACE_NAME}`;
|
|
30
|
-
const MINIMUM_PLUGIN_VERSION = '1.
|
|
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
|
|
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
|
|
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
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
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
|
|