@piecemaker-legal/piecemaker 2.0.8 → 2.0.10

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 (169) hide show
  1. package/dist/assets/FindReplaceDialog-KU5TEIBJ-CQ76sPaJ.js +1 -0
  2. package/dist/assets/FootnotePropertiesDialog-W3YHM4BV-BpgYQvvd.js +1 -0
  3. package/dist/assets/HyperlinkDialog-ZYH7ZHRF-qIPBOssF.css +1 -0
  4. package/dist/assets/HyperlinkDialog-ZYH7ZHRF-z08UbYbL.js +144 -0
  5. package/dist/assets/ImagePositionDialog-HEWYR6Q3-CFzOnzAt.js +1 -0
  6. package/dist/assets/ImagePropertiesDialog-RAB47C6M-D-ThGU-b.js +1 -0
  7. package/dist/assets/PageSetupDialog-AIGIXO3E-_PYIO8eb.js +1 -0
  8. package/dist/assets/SplitCellDialog-IFBKYCD6-Cb9uQOB8.js +1 -0
  9. package/dist/assets/TablePropertiesDialog-TMLKGOOW-12vmjb6B.js +1 -0
  10. package/dist/assets/WatermarkDialog-KRL7WMIS-C-d8rzt2.js +1 -0
  11. package/dist/assets/{abnfDiagram-VCTEODGH-XuFdW3jA.js → abnfDiagram-VCTEODGH-B4OsX7eF.js} +1 -1
  12. package/dist/assets/arc-BK1oUIk7.js +1 -0
  13. package/dist/assets/architectureDiagram-5GKGNRK7-CfaFI6L7.js +36 -0
  14. package/dist/assets/{blockDiagram-I7D4REHJ-CsgOSDLB.js → blockDiagram-I7D4REHJ-DQEI2azY.js} +1 -1
  15. package/dist/assets/{c4Diagram-7LVT6UL2-awKtsGCB.js → c4Diagram-7LVT6UL2-DbravpVi.js} +1 -1
  16. package/dist/assets/channel-DVyNr2Yg.js +1 -0
  17. package/dist/assets/{chunk-2Q5K7J3B-DA5F8ig-.js → chunk-2Q5K7J3B-BLpZ9huC.js} +1 -1
  18. package/dist/assets/{chunk-5VM5RSS4-DawRFEGW.js → chunk-5VM5RSS4-BLlEdmX9.js} +1 -1
  19. package/dist/assets/{chunk-F27PBJKO-BO6B_U1p.js → chunk-F27PBJKO-D-ZNhI6q.js} +1 -1
  20. package/dist/assets/{chunk-IMKFNOWR-Dhrf_k6W.js → chunk-IMKFNOWR-vzSiKnhh.js} +1 -1
  21. package/dist/assets/{chunk-JWPE2WC7-BTGX4CJ7.js → chunk-JWPE2WC7-DfF0k4nb.js} +1 -1
  22. package/dist/assets/{chunk-POPQ4Y6H-ByKLZ0wa.js → chunk-POPQ4Y6H-BnwCYsPP.js} +1 -1
  23. package/dist/assets/{chunk-SVP7TREG-DNCtUeow.js → chunk-SVP7TREG-DRxc8fhq.js} +1 -1
  24. package/dist/assets/{chunk-TICWLB2K-bgcAtBKw.js → chunk-TICWLB2K-Dd2Q-md-.js} +1 -1
  25. package/dist/assets/{chunk-XXDRQBXY-AD-pwqOj.js → chunk-XXDRQBXY-DBjkEUp_.js} +1 -1
  26. package/dist/assets/classDiagram-ZZMXUADV-2pGPHl5H.js +1 -0
  27. package/dist/assets/classDiagram-v2-VYDZK3BY-2pGPHl5H.js +1 -0
  28. package/dist/assets/{cose-bilkent-JH36ORCC-D23VMTjy.js → cose-bilkent-JH36ORCC-By6PS4oe.js} +1 -1
  29. package/dist/assets/{cynefin-OW5HDTMX-thDLtHBg.js → cynefin-OW5HDTMX-YxWpjc5W.js} +1 -1
  30. package/dist/assets/{cynefinDiagram-5FMLGOSQ-BTG5qDGi.js → cynefinDiagram-5FMLGOSQ-DrtXzz3p.js} +1 -1
  31. package/dist/assets/{dagre-GXQ25YYZ-yXAeLV32.js → dagre-GXQ25YYZ-BDpTLKqZ.js} +1 -1
  32. package/dist/assets/{diagram-S7CK7UJ4-v1-YDY3c.js → diagram-S7CK7UJ4-C4LvqeCs.js} +1 -1
  33. package/dist/assets/{diagram-UQ7AKVKN-DlO9hQ63.js → diagram-UQ7AKVKN-BTpnMeHp.js} +1 -1
  34. package/dist/assets/{diagram-VSXAHHWV-B3Bz2C6Y.js → diagram-VSXAHHWV-DucHHWev.js} +1 -1
  35. package/dist/assets/{diagram-VX7I27RA-BosIgZRa.js → diagram-VX7I27RA-DYHZNmmH.js} +1 -1
  36. package/dist/assets/{diagram-Z3DM3KII-C1MFbIji.js → diagram-Z3DM3KII-BHIH2BGN.js} +1 -1
  37. package/dist/assets/{ebnfDiagram-PWID7BFC-B6g9aRAb.js → ebnfDiagram-PWID7BFC-CGiEkwj0.js} +1 -1
  38. package/dist/assets/{erDiagram-RLTQ6QDP-BuV5RUQ-.js → erDiagram-RLTQ6QDP-AJMHi2Us.js} +1 -1
  39. package/dist/assets/{flowDiagram-HODETNUW-OFcS8Psg.js → flowDiagram-HODETNUW-BqzANBh2.js} +1 -1
  40. package/dist/assets/{ganttDiagram-EL5Y4UJY-CxCIs-y4.js → ganttDiagram-EL5Y4UJY-B0xPDY2_.js} +1 -1
  41. package/dist/assets/{gitGraphDiagram-WWUBYQGX-DQHfgTRq.js → gitGraphDiagram-WWUBYQGX-CzPX5CNO.js} +1 -1
  42. package/dist/assets/{index-BPmxqMd5.js → index-Bk2iXKnJ.js} +140 -140
  43. package/dist/assets/index-Dc9wNuS4.css +1 -0
  44. package/dist/assets/{infoDiagram-27XIBGKW-UvDaFHGE.js → infoDiagram-27XIBGKW-Cjc44H0O.js} +1 -1
  45. package/dist/assets/{ishikawaDiagram-5VMMS53U-B04u_588.js → ishikawaDiagram-5VMMS53U-BWhr2v7r.js} +1 -1
  46. package/dist/assets/{journeyDiagram-3NMN7TZE-BYvBbjXl.js → journeyDiagram-3NMN7TZE-Bl4r6RrP.js} +1 -1
  47. package/dist/assets/{kanban-definition-UXKFOSKX-DxAJd2LW.js → kanban-definition-UXKFOSKX-FV-T0Vy1.js} +6 -6
  48. package/dist/assets/layout-CTfb1sAF.js +1 -0
  49. package/dist/assets/{linear-CmWY0F-m.js → linear-Dfgi6vlo.js} +1 -1
  50. package/dist/assets/{mermaid.core-ClUcKNvb.js → mermaid.core-DOCGsdlo.js} +7 -7
  51. package/dist/assets/{mindmap-definition-YA3MSWOX-DZ2GO-J-.js → mindmap-definition-YA3MSWOX-CymQ86ir.js} +1 -1
  52. package/dist/assets/{pegDiagram-XKGWAZYB-DF4i_o7r.js → pegDiagram-XKGWAZYB-1VMq_vi0.js} +1 -1
  53. package/dist/assets/{pieDiagram-E7YTZNPT-G20Z0KTO.js → pieDiagram-E7YTZNPT-C5GgXtJU.js} +1 -1
  54. package/dist/assets/processTemplate-GPFDLQMX-B1sVV2O0.js +22 -0
  55. package/dist/assets/{quadrantDiagram-AXDQQJYC-5MRlN0BO.js → quadrantDiagram-AXDQQJYC-C6zpryYf.js} +1 -1
  56. package/dist/assets/{railroadDiagram-O6MQD6OU-B4Fp-guo.js → railroadDiagram-O6MQD6OU-D-sv4SWi.js} +1 -1
  57. package/dist/assets/{requirementDiagram-BXWQKSXE-DFL0eww_.js → requirementDiagram-BXWQKSXE-CkjY-z4B.js} +1 -1
  58. package/dist/assets/sankeyDiagram-P5KCCOFB-De-d8Q6L.js +40 -0
  59. package/dist/assets/{sequenceDiagram-WJ2MYXX4-iP9OUxwi.js → sequenceDiagram-WJ2MYXX4-DCsGSJa9.js} +1 -1
  60. package/dist/assets/{server.browser-BzI1jrZw.js → server.browser-BY3bL-IX.js} +1 -1
  61. package/dist/assets/{sizeCapture-INFHLROL-C95kgcA-.js → sizeCapture-INFHLROL-xINZhgER.js} +1 -1
  62. package/dist/assets/stateDiagram-D77RDMKH-CuLUTWSL.js +1 -0
  63. package/dist/assets/stateDiagram-v2-MP3YSRHH-Cnbs-M92.js +1 -0
  64. package/dist/assets/{swimlanes-42K2YHIH-BbMY7ECY.js → swimlanes-42K2YHIH-BwxARD7N.js} +1 -1
  65. package/dist/assets/swimlanesDiagram-VR7AAH4N-D7p8qZI2.js +8 -0
  66. package/dist/assets/{timeline-definition-24CTP7MA-BQs8wPer.js → timeline-definition-24CTP7MA-BIOvnn-l.js} +3 -3
  67. package/dist/assets/{vendor-codemirror-CjW0lHR5.js → vendor-codemirror-CN-sJePf.js} +2 -2
  68. package/dist/assets/{vendor-react-D809iwXR.js → vendor-react-B22wqN3J.js} +5 -5
  69. package/dist/assets/{vennDiagram-4TSXK5OY-Imm0EPbt.js → vennDiagram-4TSXK5OY-BSD6Pfmt.js} +4 -4
  70. package/dist/assets/{wardleyDiagram-VM6X3IG4-DpMMDayn.js → wardleyDiagram-VM6X3IG4-7Zz2iRkF.js} +1 -1
  71. package/dist/assets/{xychartDiagram-S5SC5T6Z-DdLp1sYL.js → xychartDiagram-S5SC5T6Z-Ctx17Y1D.js} +1 -1
  72. package/dist/index.html +4 -4
  73. package/dist/sw.js +1 -1
  74. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +4 -53
  75. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -1
  76. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +2 -3
  77. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -1
  78. package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js +30 -0
  79. package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js.map +1 -0
  80. package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js +24 -0
  81. package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js.map +1 -0
  82. package/dist-server/server/piecemaker/anonymizer/lifecycle.js +2 -3
  83. package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -1
  84. package/dist-server/server/piecemaker/desktop-update/index.js +4 -3
  85. package/dist-server/server/piecemaker/desktop-update/index.js.map +1 -1
  86. package/dist-server/server/piecemaker/docx-document.js +50 -0
  87. package/dist-server/server/piecemaker/docx-document.js.map +1 -0
  88. package/dist-server/server/piecemaker/index.js +9 -2
  89. package/dist-server/server/piecemaker/index.js.map +1 -1
  90. package/dist-server/server/piecemaker/model-discovery/codex-catalog.js +46 -0
  91. package/dist-server/server/piecemaker/model-discovery/codex-catalog.js.map +1 -0
  92. package/dist-server/server/piecemaker/model-discovery/index.js +42 -0
  93. package/dist-server/server/piecemaker/model-discovery/index.js.map +1 -0
  94. package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js +19 -0
  95. package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js.map +1 -0
  96. package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js +61 -0
  97. package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js.map +1 -0
  98. package/dist-server/server/piecemaker/project-registry.js +29 -0
  99. package/dist-server/server/piecemaker/project-registry.js.map +1 -0
  100. package/package.json +12 -1
  101. package/scripts/piecemaker/cli/disable-anonymizer.mjs +19 -0
  102. package/scripts/piecemaker/cli/lib/config.mjs +0 -1
  103. package/scripts/piecemaker/cli/lib/services.mjs +1 -10
  104. package/scripts/piecemaker/cli/piecemaker.mjs +0 -3
  105. package/server/modules/providers/list/mistral/mistral-models.provider.ts +4 -53
  106. package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +2 -3
  107. package/server/modules/providers/list/mistral/mistral-vibe-models.ts +43 -0
  108. package/server/modules/providers/tests/mistral-vibe-models.test.ts +27 -0
  109. package/server/piecemaker/anonymizer/client-config.cjs +92 -92
  110. package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +9 -16
  111. package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.toml +1 -1
  112. package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +251 -268
  113. package/server/piecemaker/anonymizer/lifecycle.ts +2 -3
  114. package/server/piecemaker/anonymizer/rewriter-bridge.cjs +6 -0
  115. package/server/piecemaker/anonymizer/service.cjs +117 -175
  116. package/server/piecemaker/desktop-update/index.ts +4 -3
  117. package/server/piecemaker/docx-document.ts +54 -0
  118. package/server/piecemaker/harness/decisions.cjs +1 -1
  119. package/server/piecemaker/harness/index.cjs +2 -3
  120. package/server/piecemaker/harness/verification.cjs +1 -1
  121. package/server/piecemaker/index.ts +11 -3
  122. package/server/piecemaker/model-discovery/codex-catalog.ts +67 -0
  123. package/server/piecemaker/model-discovery/index.ts +69 -0
  124. package/server/piecemaker/model-discovery/mistral-catalog.ts +36 -0
  125. package/server/piecemaker/model-discovery/stdio-rpc.ts +79 -0
  126. package/server/piecemaker/project-registry.ts +34 -0
  127. package/server/piecemaker/router.cjs +6 -7
  128. package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +31 -77
  129. package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +2 -84
  130. package/server/piecemaker/vendor/installer/lib/service.mjs +4 -24
  131. package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +10 -21
  132. package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +0 -11
  133. package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +6 -36
  134. package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +30 -12
  135. package/server/piecemaker/vendor/piecemaker-plugin/README.md +2 -9
  136. package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +5 -5
  137. package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +8 -8
  138. package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +2 -2
  139. package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +4 -6
  140. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +71 -38
  141. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +8 -38
  142. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +82 -61
  143. package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +4 -55
  144. package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +24 -117
  145. package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +2 -2
  146. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +15 -121
  147. package/server/piecemaker/vendor/websocket-server/case-registry.cjs +16 -32
  148. package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +0 -73
  149. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +0 -7
  150. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +2 -0
  151. package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +3 -12
  152. package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +6 -6
  153. package/dist/assets/arc-CsCtfL20.js +0 -1
  154. package/dist/assets/architectureDiagram-5GKGNRK7-DGxozBGS.js +0 -36
  155. package/dist/assets/channel-DnynWwYa.js +0 -1
  156. package/dist/assets/classDiagram-ZZMXUADV-CHIsGj2B.js +0 -1
  157. package/dist/assets/classDiagram-v2-VYDZK3BY-CHIsGj2B.js +0 -1
  158. package/dist/assets/index-WwknP0l4.css +0 -1
  159. package/dist/assets/layout-R7w2kLxO.js +0 -1
  160. package/dist/assets/sankeyDiagram-P5KCCOFB-CpOdmqdy.js +0 -40
  161. package/dist/assets/stateDiagram-D77RDMKH-D9WHRvlY.js +0 -1
  162. package/dist/assets/stateDiagram-v2-MP3YSRHH-D9Qlflkb.js +0 -1
  163. package/dist/assets/swimlanesDiagram-VR7AAH4N-CA64dwpM.js +0 -8
  164. package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +0 -78
  165. package/scripts/piecemaker/hooks/proxy-guard.mjs +0 -251
  166. package/server/piecemaker/anonymizer/providers.cjs +0 -120
  167. package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +0 -482
  168. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
  169. package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +0 -602
@@ -1,120 +1,46 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * statusLine Claude Code — bandeau permanent d'état de l'anonymisation PieceMaker.
4
- *
5
- * Contrat statusLine (type "command") : JSON sur stdin décrivant la session
6
- * (workspace, model...), une seule ligne sur stdout, exit 0. Appelé très
7
- * souvent (à chaque rendu de l'interface) : ce script doit rester rapide et
8
- * ne jamais bloquer ni jeter.
9
- *
10
- * Le badge reflète les deux mêmes conditions que `proxy-guard.mjs` (routage
11
- * + proxy vivant), mais sans autostart ni journalisation : une statusLine
12
- * n'est pas le bon endroit pour une action de fond, seulement pour un
13
- * affichage. Le sondage réseau est borné à 400 ms et son résultat est mis en
14
- * cache 5 s dans ~/.piecemaker/proxy-statusline.json pour éviter une requête
15
- * à chaque frappe.
16
- */
17
-
18
- import fs from 'node:fs';
19
2
  import http from 'node:http';
20
- import os from 'node:os';
21
3
  import path from 'node:path';
22
- import { HOME_DIR, loadPieceMakerConfig, readHookPayload } from './lib/hook-io.mjs';
4
+ import { loadPieceMakerConfig, readHookPayload } from './lib/hook-io.mjs';
23
5
 
24
- const CACHE_FILE = path.join(HOME_DIR, 'proxy-statusline.json');
25
- const CACHE_TTL_MS = 5000;
26
6
  const PROBE_TIMEOUT_MS = 400;
27
7
  const STDIN_TIMEOUT_MS = 1000;
28
- const DEFAULT_PORT = 4000;
29
8
  const FLUSH_TIMEOUT_MS = 1000;
9
+ const VERT = '\u001b[32m';
10
+ const ROUGE = '\u001b[31m';
11
+ const RESET = '\u001b[0m';
30
12
 
31
- const SETTINGS_FILE = path.join(os.homedir(), '.claude', 'settings.json');
32
-
33
- function validPort(value) {
34
- const port = Number(value);
35
- return Number.isInteger(port) && port >= 1024 && port <= 65535 ? port : DEFAULT_PORT;
36
- }
37
-
38
- /** Même définition du routage que proxy-guard.mjs — lecture directe, jamais de throw. */
39
- function readRouting() {
40
- try {
41
- const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
42
- const value = settings?.env?.HTTPS_PROXY;
43
- if (typeof value !== 'string' || !value) return false;
44
- const url = new URL(value);
45
- return ['127.0.0.1', 'localhost'].includes(url.hostname);
46
- } catch {
47
- return false;
48
- }
49
- }
50
-
51
- /** Cache court entre deux sondages. Un cache illisible/absent n'empêche pas de sonder. */
52
- function readCache() {
13
+ function routedProxy() {
53
14
  try {
54
- const parsed = JSON.parse(fs.readFileSync(CACHE_FILE, 'utf8'));
55
- if (typeof parsed?.ts !== 'number' || typeof parsed?.actif !== 'boolean') return null;
56
- if (Date.now() - parsed.ts > CACHE_TTL_MS) return null;
57
- return parsed;
15
+ const url = new URL(process.env.HTTPS_PROXY || process.env.https_proxy || '');
16
+ return ['127.0.0.1', 'localhost'].includes(url.hostname) ? url : null;
58
17
  } catch {
59
18
  return null;
60
19
  }
61
20
  }
62
21
 
63
- function writeCache(actif) {
64
- try {
65
- fs.mkdirSync(HOME_DIR, { recursive: true });
66
- fs.writeFileSync(CACHE_FILE, JSON.stringify({ ts: Date.now(), actif }), 'utf8');
67
- } catch {
68
- // Le cache est un confort de performance, pas une garantie.
69
- }
70
- }
71
-
72
- function probe(port, timeoutMs) {
22
+ function proxyHealthy(proxy) {
73
23
  return new Promise((resolve) => {
74
- let settled = false;
75
- const finish = (ok) => {
76
- if (settled) return;
77
- settled = true;
78
- resolve(ok);
79
- };
80
- try {
81
- const request = http.get({
82
- hostname: '127.0.0.1',
83
- port,
84
- path: '/health/liveliness',
85
- timeout: timeoutMs,
86
- }, (response) => {
87
- response.resume();
88
- finish(response.statusCode === 200);
89
- });
90
- request.on('timeout', () => { request.destroy(); finish(false); });
91
- request.on('error', () => finish(false));
92
- } catch {
93
- finish(false);
94
- }
24
+ const request = http.get({ hostname: proxy.hostname, port: proxy.port, path: '/health', timeout: PROBE_TIMEOUT_MS }, (response) => {
25
+ response.resume();
26
+ resolve(response.statusCode === 200);
27
+ });
28
+ request.on('timeout', () => { request.destroy(); resolve(false); });
29
+ request.on('error', () => resolve(false));
95
30
  });
96
31
  }
97
32
 
98
- /**
99
- * Couleur ANSI du badge : vert quand l'anonymisation est effective, rouge
100
- * sinon. Claude Code rend les séquences ANSI de la statusLine ; on n'en met
101
- * que sur le badge, jamais sur le dossier ni le modèle.
102
- */
103
- const VERT = '\u001b[32m';
104
- const ROUGE = '\u001b[31m';
105
- const RESET = '\u001b[0m';
106
-
107
33
  function colore(texte, couleur) {
108
34
  return process.env.NO_COLOR ? texte : `${couleur}${texte}${RESET}`;
109
35
  }
110
36
 
111
- function badge(routed, actif) {
112
- if (routed && actif) return colore('🔒 Anonymisation PieceMaker active ✓', VERT);
113
- if (routed) return colore('⚠️ Anonymisation PieceMaker inactive — proxy arrêté (piecemaker)', ROUGE);
114
- return colore('⚠️ Anonymisation PieceMaker inactive — accès direct', ROUGE);
37
+ async function badge() {
38
+ const proxy = routedProxy();
39
+ if (!proxy) return colore('⚠️ Anonymisation PieceMaker inactive — accès direct', ROUGE);
40
+ if (await proxyHealthy(proxy)) return colore('🔒 Anonymisation PieceMaker active ✓', VERT);
41
+ return colore('⛔ Anonymisation PieceMaker indisponible — requêtes bloquées (relancer piecemaker)', ROUGE);
115
42
  }
116
43
 
117
- /** Écrit la ligne et quitte proprement, en attendant le flush comme hook-io.mjs::emit. */
118
44
  function printAndExit(text) {
119
45
  const guard = setTimeout(() => process.exit(0), FLUSH_TIMEOUT_MS);
120
46
  guard.unref?.();
@@ -139,35 +65,16 @@ function safeCwdName(cwd) {
139
65
  }
140
66
 
141
67
  async function main() {
142
- let payload = null;
143
- try {
144
- payload = await readHookPayload(STDIN_TIMEOUT_MS);
145
- } catch {
146
- payload = null;
147
- }
148
-
68
+ const payload = await readHookPayload(STDIN_TIMEOUT_MS).catch(() => null);
149
69
  const dirName = safeCwdName(payload?.workspace?.current_dir || payload?.cwd);
150
70
  const modelName = typeof payload?.model?.display_name === 'string' ? payload.model.display_name : '';
151
-
152
- let config = {};
71
+ let disabled = false;
153
72
  try {
154
- config = loadPieceMakerConfig();
73
+ disabled = loadPieceMakerConfig()?.anonymizer?.enabled === false;
155
74
  } catch {
156
- config = {};
75
+ disabled = false;
157
76
  }
158
- const port = validPort(config.litellmPort);
159
- const routed = readRouting();
160
-
161
- const cached = readCache();
162
- let actif;
163
- if (cached) {
164
- actif = cached.actif;
165
- } else {
166
- actif = await probe(port, PROBE_TIMEOUT_MS);
167
- writeCache(actif);
168
- }
169
-
170
- const parts = [badge(routed, actif)];
77
+ const parts = [disabled ? 'Anonymisation PieceMaker désactivée' : await badge()];
171
78
  if (dirName) parts.push(dirName);
172
79
  if (modelName) parts.push(modelName);
173
80
  printAndExit(parts.join(' · '));
@@ -40,8 +40,8 @@ dossier ni par utilisateur.
40
40
  haute définition : forme, contour, police, couleur et épaisseur, puis
41
41
  « Enregistrer le tampon »).
42
42
  2. **La liste des pièces vient des dossiers juridiques enregistrés** :
43
- `GET /api/admin/dossiers` → `listDossiers` bâtit la liste sur le registre
44
- `caseFolders` (quelle que soit sa place dans l'arborescence), et chaque
43
+ `GET /api/admin/dossiers` → `listDossiers` bâtit la liste sur les projets
44
+ publiés par le serveur (`~/.piecemaker/projects.json`), et chaque
45
45
  pièce est un **fichier original** du dossier (tout fichier qui n'est ni
46
46
  `.md` ni `.json`, via `listOriginals`), **identifié par son chemin relatif
47
47
  au dossier** — aucun `compilation_dossier_*.json` n'est requis. L'ancien
@@ -5,9 +5,9 @@ const crypto = require('node:crypto');
5
5
  const { spawn, spawnSync } = require('child_process');
6
6
  const { performance } = require('node:perf_hooks');
7
7
  const {
8
- listConfiguredCases,
8
+ listProjectCases,
9
+ projectCaseEntry,
9
10
  readRegistryConfig,
10
- registerCaseFolder,
11
11
  resolveCaseReference,
12
12
  validateSelectedCaseFolder,
13
13
  } = require('./case-registry.cjs');
@@ -67,13 +67,6 @@ const {
67
67
  unregisterClaudeAsset,
68
68
  } = require('./claude-assets.cjs');
69
69
  const { claudeHooksStatus } = require('./claude-hooks.cjs');
70
- const {
71
- controlDossierBot,
72
- controlTelegram,
73
- getTelegramState,
74
- saveDossierBot,
75
- saveTelegramConfig,
76
- } = require('./telegram-admin.cjs');
77
70
  const {
78
71
  DEFAULT_CASE_FOLDER_STRUCTURE,
79
72
  configuredCaseFolderStructure,
@@ -208,8 +201,9 @@ async function registerLegalCase({
208
201
  homeDir,
209
202
  } = {}) {
210
203
  const root = validateSelectedCaseFolder(folder);
211
- const previous = readRegistryConfig(configFile);
212
- const structure = ensureCaseFolderStructure(root, previous);
204
+ const entry = projectCaseEntry(root);
205
+ if (!entry) throw new Error('Ce dossier n’est pas un projet enregistré.');
206
+ const structure = ensureCaseFolderStructure(root, readRegistryConfig(configFile));
213
207
  const protection = readProtection(root);
214
208
  if (!protection.exists) writeProtection(root, { unprotected: [] });
215
209
  const currentMapping = readCaseMapping(root);
@@ -217,11 +211,8 @@ async function registerLegalCase({
217
211
  ? currentMapping
218
212
  : writeCaseMapping(root, { mapping: {}, reverse_mapping: {} });
219
213
 
220
- const registered = registerCaseFolder(previous, root);
221
- atomicWrite(configFile, `${JSON.stringify(registered.config, null, 2)}\n`);
222
-
223
214
  const folderOverview = await caseOverview(path.dirname(root), homeDir, path.basename(root));
224
- folderOverview.path = registered.entry.id;
215
+ folderOverview.path = entry.id;
225
216
  folderOverview.location = root;
226
217
  folderOverview.registered = true;
227
218
  folderOverview.branches = await historyBranches(path.dirname(root), homeDir, path.basename(root));
@@ -237,20 +228,12 @@ async function registerLegalCase({
237
228
 
238
229
  function defaultConfig(repoRoot, homeDir = path.join(os.homedir(), '.piecemaker')) {
239
230
  return {
240
- port: 43098,
241
231
  pythonPath: null,
242
232
  venvPath: path.join(homeDir, 'venv'),
243
- adminTheme: 'light',
244
233
  caseFolderStructure: { ...DEFAULT_CASE_FOLDER_STRUCTURE },
245
234
  };
246
235
  }
247
236
 
248
- function validateAdminTheme(value) {
249
- const theme = String(value || '');
250
- if (theme !== 'light' && theme !== 'dark') throw new Error('Le thème doit être « light » ou « dark ».');
251
- return theme;
252
- }
253
-
254
237
  function readJson(file, fallback) {
255
238
  try {
256
239
  return fs.existsSync(file) ? JSON.parse(fs.readFileSync(file, 'utf8')) : fallback;
@@ -741,7 +724,6 @@ async function configurationOverview({ repoRoot, homeDir, userHome, getRuntimeSt
741
724
  },
742
725
  ];
743
726
  const models = await ollamaState(fetchImpl);
744
- const telegram = getTelegramState({ repoRoot, homeDir, userHome });
745
727
 
746
728
  // Moteurs Python locaux du venv — détection par présence de paquet, sans import
747
729
  // (importer gliner2/mineru chargerait des centaines de Mo à chaque appel).
@@ -777,22 +759,11 @@ async function configurationOverview({ repoRoot, homeDir, userHome, getRuntimeSt
777
759
  && glinerModelReady;
778
760
  const mineruReady = hasPackage('mineru') || hasPackage('magic_pdf')
779
761
  || fs.existsSync(path.join(venvDir, 'bin', 'mineru'));
780
- const folders = listConfiguredCases(readRegistryConfig(path.join(homeDir, 'config.json'))).map((entry) => {
781
- const bot = telegram.dossiers.find((candidate) => {
782
- try { return path.resolve(candidate.workdir) === path.resolve(entry.root); } catch { return false; }
783
- });
784
- return {
785
- id: entry.id,
786
- name: entry.name,
787
- path: entry.root,
788
- bot: bot ? {
789
- id: bot.id,
790
- name: bot.name,
791
- configured: Boolean(bot.linked),
792
- running: Boolean(bot.running),
793
- } : null,
794
- };
795
- });
762
+ const folders = listProjectCases().map((entry) => ({
763
+ id: entry.id,
764
+ name: entry.name,
765
+ path: entry.root,
766
+ }));
796
767
 
797
768
  return {
798
769
  components: {
@@ -845,22 +816,6 @@ async function configurationOverview({ repoRoot, homeDir, userHome, getRuntimeSt
845
816
  ? 'OCR local · PDF scannés et images'
846
817
  : 'Optionnel · non installé',
847
818
  },
848
- telegram: {
849
- name: 'Telegram',
850
- installed: true,
851
- optional: true,
852
- configured: Boolean(telegram.assistant.token.configured || telegram.monitor.token.configured),
853
- summary: (() => {
854
- const running = [telegram.assistant.running && 'Assistant', telegram.monitor.running && 'Surveillance'].filter(Boolean);
855
- if (running.length) return `${running.join(' + ')} en ligne`;
856
- if (telegram.assistant.token.configured || telegram.monitor.token.configured) return 'Configuré · arrêté';
857
- return 'Aucun bot configuré';
858
- })(),
859
- bots: [
860
- { name: telegram.assistant.name, role: 'Assistant', configured: Boolean(telegram.assistant.token.configured), running: Boolean(telegram.assistant.running) },
861
- { name: telegram.monitor.name, role: 'Surveillance', configured: Boolean(telegram.monitor.token.configured), running: Boolean(telegram.monitor.running) },
862
- ],
863
- },
864
819
  },
865
820
  models: {
866
821
  provider: 'Ollama',
@@ -1584,9 +1539,8 @@ function finishAdminTiming(res, metric, startedAt, details = {}) {
1584
1539
  // dans l'arborescence. Chaque dossier expose ses pièces originales — tout fichier
1585
1540
  // qui n'est ni `.md` ni `.json` —, identifiées par leur chemin relatif au dossier.
1586
1541
  async function listDossiers(repoRoot, homeDir) {
1587
- const config = readRegistryConfig(path.join(homeDir, 'config.json'));
1588
1542
  const dossiers = [];
1589
- for (const entry of listConfiguredCases(config)) {
1543
+ for (const entry of listProjectCases()) {
1590
1544
  let originals;
1591
1545
  try {
1592
1546
  originals = await listOriginals(entry.root);
@@ -2045,11 +1999,10 @@ function createAdminRouter({
2045
1999
  const envFile = path.join(repoRoot, '.env');
2046
2000
  const registryConfig = () => readRegistryConfig(configFile);
2047
2001
  const selectedCase = (reference) => {
2048
- const config = registryConfig();
2049
- const legalCase = resolveCaseReference(config, reference);
2002
+ const legalCase = resolveCaseReference(reference);
2050
2003
  // Migration idempotente des dossiers enregistrés avant l'introduction de
2051
2004
  // l'arborescence métier. Le manifeste fige les noms utilisés par ce dossier.
2052
- ensureCaseFolderStructure(legalCase.root, config);
2005
+ ensureCaseFolderStructure(legalCase.root, registryConfig());
2053
2006
  return legalCase;
2054
2007
  };
2055
2008
 
@@ -2166,13 +2119,7 @@ function createAdminRouter({
2166
2119
  const patch = req.body?.config || {};
2167
2120
  const next = { ...current };
2168
2121
 
2169
- if (patch.port !== undefined) {
2170
- const port = Number(patch.port);
2171
- if (!Number.isInteger(port) || port < 1024 || port > 65535) throw new Error('Le port doit être compris entre 1024 et 65535.');
2172
- next.port = port;
2173
- }
2174
2122
  if (patch.pythonPath !== undefined) next.pythonPath = String(patch.pythonPath || '').trim() || null;
2175
- if (patch.adminTheme !== undefined) next.adminTheme = validateAdminTheme(patch.adminTheme);
2176
2123
  if (patch.caseFolderStructure !== undefined) {
2177
2124
  next.caseFolderStructure = normalizeCaseFolderStructure({
2178
2125
  ...current.caseFolderStructure,
@@ -2421,8 +2368,7 @@ function createAdminRouter({
2421
2368
  router.get('/repository', async (req, res) => {
2422
2369
  const startedAt = performance.now();
2423
2370
  try {
2424
- const config = registryConfig();
2425
- const entries = listConfiguredCases(config);
2371
+ const entries = listProjectCases();
2426
2372
  const overview = {
2427
2373
  name: 'PieceMaker',
2428
2374
  root: '',
@@ -2444,21 +2390,6 @@ function createAdminRouter({
2444
2390
  }
2445
2391
  });
2446
2392
 
2447
- router.post('/repository/cases', async (req, res) => {
2448
- try {
2449
- const selected = await pickFolder(process.platform, userHome);
2450
- if (!selected) return res.json({ ok: true, cancelled: true });
2451
- const result = await registerLegalCase({
2452
- folder: selected,
2453
- configFile,
2454
- homeDir,
2455
- });
2456
- res.status(201).json({ ok: true, ...result });
2457
- } catch (error) {
2458
- res.status(400).json({ error: error.message });
2459
- }
2460
- });
2461
-
2462
2393
  router.get('/repository/case', async (req, res) => {
2463
2394
  const startedAt = performance.now();
2464
2395
  try {
@@ -2980,42 +2911,6 @@ function createAdminRouter({
2980
2911
  }
2981
2912
  });
2982
2913
 
2983
- router.get('/telegram', (req, res) => {
2984
- res.json(getTelegramState({ repoRoot, homeDir, userHome }));
2985
- });
2986
-
2987
- router.put('/telegram', (req, res) => {
2988
- try {
2989
- res.json({ ok: true, ...saveTelegramConfig({ repoRoot, homeDir, userHome }, req.body) });
2990
- } catch (error) {
2991
- res.status(400).json({ error: error.message });
2992
- }
2993
- });
2994
-
2995
- router.post('/telegram/:role/:action', (req, res) => {
2996
- try {
2997
- res.json(controlTelegram({ repoRoot, homeDir, userHome }, req.params.role, req.params.action));
2998
- } catch (error) {
2999
- res.status(400).json({ error: error.message });
3000
- }
3001
- });
3002
-
3003
- router.put('/telegram/dossiers/:id', (req, res) => {
3004
- try {
3005
- res.json({ ok: true, dossier: saveDossierBot({ repoRoot, homeDir, userHome }, req.params.id, req.body) });
3006
- } catch (error) {
3007
- res.status(400).json({ error: error.message });
3008
- }
3009
- });
3010
-
3011
- router.post('/telegram/dossiers/:id/:action', (req, res) => {
3012
- try {
3013
- res.json(controlDossierBot({ repoRoot, homeDir, userHome }, req.params.id, req.params.action));
3014
- } catch (error) {
3015
- res.status(400).json({ error: error.message });
3016
- }
3017
- });
3018
-
3019
2914
  return router;
3020
2915
  }
3021
2916
 
@@ -3057,5 +2952,4 @@ module.exports = {
3057
2952
  saveManagedFile,
3058
2953
  selectLocalFolder,
3059
2954
  updateEnvFile,
3060
- validateAdminTheme,
3061
2955
  };
@@ -1,4 +1,4 @@
1
- /** Explicit legal-case folder registry used by the local admin and hooks. */
1
+ /** Legal-case registry: every CloudCLI project published by the server is a case. */
2
2
  const crypto = require('node:crypto');
3
3
  const fs = require('node:fs');
4
4
  const path = require('node:path');
@@ -6,10 +6,7 @@ const path = require('node:path');
6
6
  const {
7
7
  isTechnicalCaseDirectoryName,
8
8
  } = require('../piecemaker-plugin/scripts/lib/commits.cjs');
9
- const {
10
- configuredWatchPaths,
11
- registeredCaseFolders,
12
- } = require('../piecemaker-plugin/scripts/lib/case-folders.cjs');
9
+ const { registeredProjectFolders } = require('../piecemaker-plugin/scripts/lib/case-folders.cjs');
13
10
 
14
11
  function readRegistryConfig(configFile) {
15
12
  try {
@@ -25,8 +22,8 @@ function caseFolderId(folder) {
25
22
  return `folder-${digest}`;
26
23
  }
27
24
 
28
- function explicitEntries(config) {
29
- return registeredCaseFolders(config).map((root) => ({
25
+ function projectEntries() {
26
+ return registeredProjectFolders().map((root) => ({
30
27
  id: caseFolderId(root),
31
28
  name: path.basename(root),
32
29
  root,
@@ -36,22 +33,21 @@ function explicitEntries(config) {
36
33
  }));
37
34
  }
38
35
 
39
- /**
40
- * Admin index: only the explicitly registered legal-case folders. There is no
41
- * longer a workspace root whose immediate children are listed automatically —
42
- * a matter appears once it has been registered from the admin panel.
43
- */
44
- function listConfiguredCases(config) {
45
- return explicitEntries(config).sort((a, b) =>
36
+ function listProjectCases() {
37
+ return projectEntries().sort((a, b) =>
46
38
  a.name.localeCompare(b.name, 'fr') || a.root.localeCompare(b.root, 'fr'));
47
39
  }
48
40
 
49
- function resolveCaseReference(config, reference) {
41
+ function resolveCaseReference(reference) {
50
42
  const token = String(reference || '').trim();
51
43
  if (!token) throw new Error('Dossier juridique invalide.');
52
- const explicit = explicitEntries(config).find((entry) => entry.id === token);
53
- if (!explicit) throw new Error('Ce dossier juridique n’est pas enregistré.');
54
- return explicit;
44
+ const entry = projectEntries().find((candidate) => candidate.id === token);
45
+ if (!entry) throw new Error('Ce dossier juridique n’est pas un projet enregistré.');
46
+ return entry;
47
+ }
48
+
49
+ function projectCaseEntry(root) {
50
+ return projectEntries().find((entry) => entry.root === root) || null;
55
51
  }
56
52
 
57
53
  function validateSelectedCaseFolder(folder) {
@@ -71,23 +67,11 @@ function validateSelectedCaseFolder(folder) {
71
67
  return root;
72
68
  }
73
69
 
74
- function registerCaseFolder(config, folder) {
75
- const root = validateSelectedCaseFolder(folder);
76
- const existing = registeredCaseFolders(config);
77
- const caseFolders = [...new Set([...existing, root])];
78
- const next = { ...config, caseFolders };
79
- next.anonymization = {
80
- ...(config?.anonymization || {}),
81
- watchPaths: configuredWatchPaths(next),
82
- };
83
- return { config: next, entry: explicitEntries(next).find((item) => item.root === root) };
84
- }
85
-
86
70
  module.exports = {
87
71
  caseFolderId,
88
- listConfiguredCases,
72
+ listProjectCases,
73
+ projectCaseEntry,
89
74
  readRegistryConfig,
90
- registerCaseFolder,
91
75
  resolveCaseReference,
92
76
  validateSelectedCaseFolder,
93
77
  };
@@ -10,9 +10,6 @@
10
10
  const fs = require('fs');
11
11
  const path = require('path');
12
12
 
13
- /** Racine du dépôt git, quatre niveaux au-dessus de ce fichier vendorisé. */
14
- const GIT_REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..');
15
-
16
13
  const DEPRECATED_HOOKS = new Set([
17
14
  'anonymize-read.mjs',
18
15
  'deanonymize-write.mjs',
@@ -231,74 +228,6 @@ function installClaudeHooks(repoRoot, userHome) {
231
228
  return { ok: true, changed: changed || cleanup.changed, registered, settings: target, cleanup };
232
229
  }
233
230
 
234
- /**
235
- * Sentinelle SessionStart (proxy PII) — script unique, partagé avec Codex,
236
- * hors de piecemaker-plugin/ (voir scripts/piecemaker/hooks/proxy-guard.mjs).
237
- * Non sourcée depuis hooks.json : son placeholder ${CLAUDE_PLUGIN_ROOT} ne
238
- * peut pas désigner un script qui n'est délibérément pas vendorisé.
239
- */
240
- function sessionHookScriptPath() {
241
- return path.join(GIT_REPO_ROOT, 'scripts', 'piecemaker', 'hooks', 'proxy-guard.mjs');
242
- }
243
-
244
- function sessionHookCommand() {
245
- return `node "${sessionHookScriptPath().replaceAll('"', '\\"')}"`;
246
- }
247
-
248
- function isOwnSessionHook(hook) {
249
- const command = typeof hook?.command === 'string' ? hook.command : '';
250
- return command.includes('proxy-guard.mjs');
251
- }
252
-
253
- function claudeSessionHookStatus(userHome) {
254
- const target = settingsPath(userHome);
255
- const command = sessionHookCommand();
256
- if (!fs.existsSync(target)) return { ok: false, reason: 'settings-absent', command };
257
- const settings = readJson(target);
258
- if (!settings) return { ok: false, reason: 'settings-invalide', command };
259
- const groups = Array.isArray(settings.hooks?.SessionStart) ? settings.hooks.SessionStart : [];
260
- const managed = groups.flatMap((group) => Array.isArray(group?.hooks) ? group.hooks : []).filter(isOwnSessionHook);
261
- const exact = groups.some((group) => group?.matcher === 'startup|resume|clear'
262
- && Array.isArray(group.hooks)
263
- && group.hooks.some((hook) => hook?.type === 'command' && hook.command === command));
264
- return { ok: exact && managed.length === 1, reason: exact && managed.length === 1 ? '' : 'hook-absent-ou-perime', command };
265
- }
266
-
267
- /** Fusionne uniquement la sentinelle SessionStart ; tous les hooks personnels sont conservés. */
268
- function installClaudeSessionHook(userHome) {
269
- const target = settingsPath(userHome);
270
- const command = sessionHookCommand();
271
-
272
- let settings = {};
273
- if (fs.existsSync(target)) {
274
- settings = readJson(target);
275
- if (!settings) return { ok: false, changed: false, reason: 'settings-invalide', command, settings: target };
276
- }
277
- if (!settings.hooks || typeof settings.hooks !== 'object' || Array.isArray(settings.hooks)) settings.hooks = {};
278
-
279
- const groups = Array.isArray(settings.hooks.SessionStart) ? settings.hooks.SessionStart : [];
280
- const preserved = [];
281
- for (const group of groups) {
282
- if (!group || typeof group !== 'object' || Array.isArray(group)) {
283
- preserved.push(group);
284
- continue;
285
- }
286
- const hooks = Array.isArray(group.hooks) ? group.hooks.filter((hook) => !isOwnSessionHook(hook)) : [];
287
- if (hooks.length || !Array.isArray(group.hooks)) preserved.push({ ...group, hooks });
288
- }
289
-
290
- const status = claudeSessionHookStatus(userHome);
291
- if (status.ok) return { ok: true, changed: false, command, settings: target };
292
-
293
- settings.hooks.SessionStart = [...preserved, {
294
- matcher: 'startup|resume|clear',
295
- hooks: [{ type: 'command', command, timeout: 45 }],
296
- }];
297
- fs.mkdirSync(path.dirname(target), { recursive: true });
298
- fs.writeFileSync(target, `${JSON.stringify(settings, null, 2)}\n`, 'utf8');
299
- return { ok: true, changed: true, command, settings: target };
300
- }
301
-
302
231
  /**
303
232
  * statusLine Claude Code — même logique de matérialisation que les hooks,
304
233
  * mais pour une clé unique de settings.json (`statusLine`) plutôt qu'un
@@ -371,11 +300,9 @@ function installClaudeStatusLine(repoRoot, userHome) {
371
300
 
372
301
  module.exports = {
373
302
  claudeHooksStatus,
374
- claudeSessionHookStatus,
375
303
  claudeStatusLineStatus,
376
304
  directHookGroups,
377
305
  installClaudeHooks,
378
- installClaudeSessionHook,
379
306
  installClaudeStatusLine,
380
307
  removeDeprecatedHooks,
381
308
  settingsPath,
@@ -45,11 +45,6 @@ const {
45
45
  // Vocabulaire des sigles de sociétés (SA_1, SARL_1, PERS_MORALE_1…), miroir de
46
46
  // `_LEGAL_FORMS` (scan_utils.py) — sert à classer un code déjà attribué.
47
47
  const { isSocieteCode, societeCounterKey, detectCompanySigle, LEGAL_FORM_TOKENS } = require('./legal-forms.cjs');
48
- // À chaque enregistrement d'un mapping de dossier, le mapping central global est
49
- // reconstruit et dé-conflicté : c'est lui que le hook central applique à toute
50
- // lecture, dossier ou non. `syncCentralMapping` ne jette jamais — un central qui
51
- // échoue ne doit pas faire échouer la sauvegarde du dossier.
52
- const { syncCentralMapping } = require('../piecemaker-plugin/scripts/lib/central-mapping.cjs');
53
48
 
54
49
  const SCRIPTS_DIR = path.join(__dirname, 'scripts');
55
50
  const PIECEMAKER_HOME = path.join(os.homedir(), '.piecemaker');
@@ -154,8 +149,6 @@ function writeCaseMapping(caseRoot, document) {
154
149
  fs.unlinkSync(full);
155
150
  }
156
151
  }
157
- // Le mapping central reflète désormais ce dossier. Best-effort et jamais bloquant.
158
- try { syncCentralMapping(); } catch { /* le central ne doit pas bloquer une sauvegarde */ }
159
152
  return { file, exists: true, ignored: payload.ignored || [], ...payload };
160
153
  }
161
154
 
@@ -26,6 +26,8 @@ from collections import defaultdict
26
26
  from importlib.metadata import PackageNotFoundError, version as package_version
27
27
  from typing import Dict, List, Optional
28
28
 
29
+ os.environ["HF_HUB_OFFLINE"] = "1"
30
+
29
31
  # ---------------------------------------------------------------------------
30
32
  # Heavy imports — these are the expensive ones (~30-60s)
31
33
  # ---------------------------------------------------------------------------