@piecemaker-legal/piecemaker 1.0.6 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (217) hide show
  1. package/dist/assets/{abnfDiagram-VCTEODGH-DF7LFtT-.js → abnfDiagram-VCTEODGH-K8VucbQ5.js} +1 -1
  2. package/dist/assets/{arc-xOmjWeVH.js → arc-DUmCdRoC.js} +1 -1
  3. package/dist/assets/{architectureDiagram-5GKGNRK7-CESzNPwa.js → architectureDiagram-5GKGNRK7-DYhs5vqD.js} +1 -1
  4. package/dist/assets/{blockDiagram-I7D4REHJ-BjdN78Ad.js → blockDiagram-I7D4REHJ-DaXJ9nve.js} +1 -1
  5. package/dist/assets/{c4Diagram-7LVT6UL2-BcK9EDWT.js → c4Diagram-7LVT6UL2-BLbi-zPT.js} +1 -1
  6. package/dist/assets/channel-CJIq1vqf.js +1 -0
  7. package/dist/assets/{chunk-2Q5K7J3B-DGUN1JFP.js → chunk-2Q5K7J3B-Bzs3gxaq.js} +1 -1
  8. package/dist/assets/{chunk-5VM5RSS4-BG3BBcFr.js → chunk-5VM5RSS4-CQNzml7k.js} +1 -1
  9. package/dist/assets/{chunk-F27PBJKO-CLIOfrF5.js → chunk-F27PBJKO-B8xedWWH.js} +1 -1
  10. package/dist/assets/{chunk-IMKFNOWR-D6lGkqij.js → chunk-IMKFNOWR-CjBGlNOu.js} +1 -1
  11. package/dist/assets/{chunk-JWPE2WC7-BmF9vLBT.js → chunk-JWPE2WC7-vfnYEpgA.js} +1 -1
  12. package/dist/assets/{chunk-POPQ4Y6H-C_0SR3ak.js → chunk-POPQ4Y6H-Btl98tE8.js} +1 -1
  13. package/dist/assets/{chunk-SVP7TREG-rT20Wfpp.js → chunk-SVP7TREG-Bp6-pLjR.js} +1 -1
  14. package/dist/assets/{chunk-TICWLB2K-Cn2hkmcf.js → chunk-TICWLB2K-DvmznW2q.js} +1 -1
  15. package/dist/assets/{chunk-XXDRQBXY-Dm_eP1_v.js → chunk-XXDRQBXY-QSHJTsI3.js} +1 -1
  16. package/dist/assets/classDiagram-ZZMXUADV-BYkEWggn.js +1 -0
  17. package/dist/assets/classDiagram-v2-VYDZK3BY-BYkEWggn.js +1 -0
  18. package/dist/assets/{cose-bilkent-JH36ORCC-cJeeJsep.js → cose-bilkent-JH36ORCC-DxpyZoe2.js} +1 -1
  19. package/dist/assets/{cynefin-OW5HDTMX-DX2ePIXe.js → cynefin-OW5HDTMX-B9GRp2Gn.js} +1 -1
  20. package/dist/assets/{cynefinDiagram-5FMLGOSQ-BvWXN-RR.js → cynefinDiagram-5FMLGOSQ-Q-2tz5GW.js} +1 -1
  21. package/dist/assets/{dagre-GXQ25YYZ-CkwPRhGR.js → dagre-GXQ25YYZ-3Rl3NqNe.js} +1 -1
  22. package/dist/assets/{diagram-S7CK7UJ4-CBGNzYyv.js → diagram-S7CK7UJ4-CreeWCO1.js} +1 -1
  23. package/dist/assets/{diagram-UQ7AKVKN-CiwCU0SJ.js → diagram-UQ7AKVKN-DNBoIyDJ.js} +1 -1
  24. package/dist/assets/{diagram-VSXAHHWV-Aekg4nTk.js → diagram-VSXAHHWV-ZkcE_cRk.js} +1 -1
  25. package/dist/assets/{diagram-VX7I27RA-DPFP5K7r.js → diagram-VX7I27RA-Dzdf7N2Q.js} +1 -1
  26. package/dist/assets/{diagram-Z3DM3KII-BHJkxoey.js → diagram-Z3DM3KII-M6b-nr1u.js} +1 -1
  27. package/dist/assets/{ebnfDiagram-PWID7BFC-2rV1P32T.js → ebnfDiagram-PWID7BFC-DunIw64n.js} +1 -1
  28. package/dist/assets/{erDiagram-RLTQ6QDP-C4BjyS_H.js → erDiagram-RLTQ6QDP-kN0Se5uc.js} +1 -1
  29. package/dist/assets/{flowDiagram-HODETNUW-DL1TBlAG.js → flowDiagram-HODETNUW-24YCovut.js} +1 -1
  30. package/dist/assets/{ganttDiagram-EL5Y4UJY-MKjvzCWz.js → ganttDiagram-EL5Y4UJY-DTUUEEy6.js} +1 -1
  31. package/dist/assets/{gitGraphDiagram-WWUBYQGX-CS_oTGK5.js → gitGraphDiagram-WWUBYQGX-BitrqhMr.js} +1 -1
  32. package/dist/assets/{index-XOGQDqU3.js → index-CG9hW1GU.js} +120 -120
  33. package/dist/assets/index-D_Dc_nQv.css +1 -0
  34. package/dist/assets/{infoDiagram-27XIBGKW-ihUr2GjN.js → infoDiagram-27XIBGKW-BNHN5Mby.js} +1 -1
  35. package/dist/assets/{ishikawaDiagram-5VMMS53U-D2YAnuir.js → ishikawaDiagram-5VMMS53U-De3IQKso.js} +1 -1
  36. package/dist/assets/{journeyDiagram-3NMN7TZE-Bc2hSZGD.js → journeyDiagram-3NMN7TZE-CWlkZ25T.js} +1 -1
  37. package/dist/assets/{kanban-definition-UXKFOSKX-LRMGNonX.js → kanban-definition-UXKFOSKX-2o_ax-Nk.js} +1 -1
  38. package/dist/assets/{layout-CcfWOlPV.js → layout-Btga9ZYP.js} +1 -1
  39. package/dist/assets/{linear-7JoS2gQO.js → linear-BoGGmqPG.js} +1 -1
  40. package/dist/assets/{mermaid.core-ijh_SsuN.js → mermaid.core-M308jnLQ.js} +6 -6
  41. package/dist/assets/{mindmap-definition-YA3MSWOX-DCE4nzfF.js → mindmap-definition-YA3MSWOX-BJ6C_grh.js} +1 -1
  42. package/dist/assets/{pegDiagram-XKGWAZYB-SjaGa7lE.js → pegDiagram-XKGWAZYB-qcdYX0Xe.js} +1 -1
  43. package/dist/assets/{pieDiagram-E7YTZNPT-1xcRidSZ.js → pieDiagram-E7YTZNPT-XPrSlt1M.js} +1 -1
  44. package/dist/assets/{quadrantDiagram-AXDQQJYC-obHAHnYV.js → quadrantDiagram-AXDQQJYC-COhHhra5.js} +1 -1
  45. package/dist/assets/{railroadDiagram-O6MQD6OU-BsCVcRZb.js → railroadDiagram-O6MQD6OU-Mw_KF6gb.js} +1 -1
  46. package/dist/assets/{requirementDiagram-BXWQKSXE-CUNkhvqb.js → requirementDiagram-BXWQKSXE-DPbt7jUM.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-P5KCCOFB-DhezXMKm.js → sankeyDiagram-P5KCCOFB-B6HzL6Gh.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-WJ2MYXX4-CL9VswXH.js → sequenceDiagram-WJ2MYXX4-B_dXXCC0.js} +1 -1
  49. package/dist/assets/{sizeCapture-INFHLROL-t0g9jiEz.js → sizeCapture-INFHLROL-DwODubWN.js} +1 -1
  50. package/dist/assets/{stateDiagram-D77RDMKH-BW-g-IOz.js → stateDiagram-D77RDMKH-5AUnOL3S.js} +1 -1
  51. package/dist/assets/stateDiagram-v2-MP3YSRHH-CFM_nDL9.js +1 -0
  52. package/dist/assets/{swimlanes-42K2YHIH-LsuyeBte.js → swimlanes-42K2YHIH-BLnIwbnd.js} +1 -1
  53. package/dist/assets/swimlanesDiagram-VR7AAH4N-BRQJYnDN.js +8 -0
  54. package/dist/assets/{timeline-definition-24CTP7MA-B0cFka1R.js → timeline-definition-24CTP7MA-B1Yc7-na.js} +1 -1
  55. package/dist/assets/{vendor-codemirror-C5qqu4R7.js → vendor-codemirror-CjW0lHR5.js} +5 -5
  56. package/dist/assets/{vennDiagram-4TSXK5OY-D3HNCDR3.js → vennDiagram-4TSXK5OY-BFRtl-NI.js} +1 -1
  57. package/dist/assets/{wardleyDiagram-VM6X3IG4-DJ3Co8nb.js → wardleyDiagram-VM6X3IG4-BsR8iaD_.js} +1 -1
  58. package/dist/assets/{xychartDiagram-S5SC5T6Z-Cz5E9New.js → xychartDiagram-S5SC5T6Z-Crh1SwrA.js} +1 -1
  59. package/dist/favicon.png +0 -0
  60. package/dist/favicon.svg +1 -9
  61. package/dist/generate-icons.js +47 -46
  62. package/dist/icons/icon-128x128.png +0 -0
  63. package/dist/icons/icon-128x128.svg +1 -12
  64. package/dist/icons/icon-144x144.png +0 -0
  65. package/dist/icons/icon-144x144.svg +1 -12
  66. package/dist/icons/icon-152x152.png +0 -0
  67. package/dist/icons/icon-152x152.svg +1 -12
  68. package/dist/icons/icon-192x192.png +0 -0
  69. package/dist/icons/icon-192x192.svg +1 -12
  70. package/dist/icons/icon-384x384.png +0 -0
  71. package/dist/icons/icon-384x384.svg +1 -12
  72. package/dist/icons/icon-512x512.png +0 -0
  73. package/dist/icons/icon-512x512.svg +1 -12
  74. package/dist/icons/icon-72x72.png +0 -0
  75. package/dist/icons/icon-72x72.svg +1 -12
  76. package/dist/icons/icon-96x96.png +0 -0
  77. package/dist/icons/icon-96x96.svg +1 -12
  78. package/dist/index.html +3 -3
  79. package/dist/logo-128.png +0 -0
  80. package/dist/logo-256.png +0 -0
  81. package/dist/logo-32.png +0 -0
  82. package/dist/logo-512.png +0 -0
  83. package/dist/logo-64.png +0 -0
  84. package/dist/logo-sources/logo-black.png +0 -0
  85. package/dist/logo-sources/logo-white.png +0 -0
  86. package/dist/logo.svg +1 -17
  87. package/dist/sw.js +1 -1
  88. package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js +91 -0
  89. package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js.map +1 -0
  90. package/dist-server/plugins/piecemaker-dossier/src/knowledge.js +112 -10
  91. package/dist-server/plugins/piecemaker-dossier/src/knowledge.js.map +1 -1
  92. package/dist-server/plugins/piecemaker-dossier/src/scan-result.js +5 -1
  93. package/dist-server/plugins/piecemaker-dossier/src/scan-result.js.map +1 -1
  94. package/dist-server/server/index.js +60 -26
  95. package/dist-server/server/index.js.map +1 -1
  96. package/dist-server/server/modules/cli/desktop-shortcut.js +80 -0
  97. package/dist-server/server/modules/cli/desktop-shortcut.js.map +1 -0
  98. package/dist-server/server/modules/cli/pwa-launcher.js +27 -4
  99. package/dist-server/server/modules/cli/pwa-launcher.js.map +1 -1
  100. package/dist-server/server/modules/database/repositories/projects.db.js +28 -6
  101. package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
  102. package/dist-server/server/modules/database/tests/projects.db.integration.test.js +58 -1
  103. package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
  104. package/dist-server/server/modules/plugins/plugins.routes.js +8 -1
  105. package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -1
  106. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +2 -0
  107. package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
  108. package/dist-server/server/piecemaker/bodacc-search.js +191 -0
  109. package/dist-server/server/piecemaker/bodacc-search.js.map +1 -0
  110. package/dist-server/server/piecemaker/company-search.js +145 -0
  111. package/dist-server/server/piecemaker/company-search.js.map +1 -0
  112. package/dist-server/server/piecemaker/company-search.test.js +18 -0
  113. package/dist-server/server/piecemaker/company-search.test.js.map +1 -0
  114. package/dist-server/server/piecemaker/index.js +6 -2
  115. package/dist-server/server/piecemaker/index.js.map +1 -1
  116. package/dist-server/server/piecemaker/knowledge/index.js +9 -4
  117. package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
  118. package/dist-server/server/piecemaker/knowledge/pipeline.js +68 -58
  119. package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
  120. package/dist-server/server/piecemaker/knowledge/routes.js +2 -4
  121. package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
  122. package/dist-server/server/piecemaker/knowledge/scan-jobs.js +91 -0
  123. package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -0
  124. package/dist-server/server/piecemaker/knowledge/service.js +18 -36
  125. package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
  126. package/dist-server/server/piecemaker/library/connector-installation.js +224 -0
  127. package/dist-server/server/piecemaker/library/connector-installation.js.map +1 -0
  128. package/dist-server/server/piecemaker/library/index.js +11 -1
  129. package/dist-server/server/piecemaker/library/index.js.map +1 -1
  130. package/dist-server/server/piecemaker/library/marketplace.js +102 -43
  131. package/dist-server/server/piecemaker/library/marketplace.js.map +1 -1
  132. package/dist-server/server/piecemaker/library/migrate.js +8 -1
  133. package/dist-server/server/piecemaker/library/migrate.js.map +1 -1
  134. package/dist-server/server/piecemaker/library/provider-agents.js +50 -0
  135. package/dist-server/server/piecemaker/library/provider-agents.js.map +1 -0
  136. package/dist-server/server/piecemaker/library/provider-connectors.js +80 -0
  137. package/dist-server/server/piecemaker/library/provider-connectors.js.map +1 -0
  138. package/dist-server/server/piecemaker/library/provider-skills.js +11 -2
  139. package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -1
  140. package/dist-server/server/piecemaker/library/store.js +125 -35
  141. package/dist-server/server/piecemaker/library/store.js.map +1 -1
  142. package/dist-server/server/piecemaker/library/workspace-installation.js +53 -29
  143. package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
  144. package/dist-server/server/piecemaker/timesheet/service.js +4 -21
  145. package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
  146. package/package.json +3 -2
  147. package/product.config.json +1 -0
  148. package/scripts/piecemaker/cli/install-command.mjs +35 -9
  149. package/scripts/piecemaker/cli/lib/app-window.mjs +47 -0
  150. package/scripts/piecemaker/cli/lib/config.mjs +1 -0
  151. package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +78 -0
  152. package/scripts/piecemaker/cli/lib/plugins.mjs +2 -0
  153. package/scripts/piecemaker/cli/lib/pwa.mjs +49 -13
  154. package/scripts/piecemaker/cli/lib/services.mjs +65 -4
  155. package/scripts/piecemaker/cli/piecemaker-command.test.mjs +25 -0
  156. package/scripts/piecemaker/cli/piecemaker.mjs +60 -45
  157. package/scripts/piecemaker/cli/piecemaker.ps1 +8 -0
  158. package/scripts/piecemaker/cli/piecemaker.sh +6 -1
  159. package/server/index.ts +52 -23
  160. package/server/modules/cli/desktop-shortcut.ts +89 -0
  161. package/server/modules/cli/pwa-launcher.ts +29 -4
  162. package/server/modules/database/repositories/projects.db.ts +28 -6
  163. package/server/modules/database/tests/projects.db.integration.test.ts +63 -1
  164. package/server/modules/plugins/plugins.routes.ts +8 -1
  165. package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +5 -0
  166. package/server/piecemaker/anonymizer/client-config.cjs +10 -2
  167. package/server/piecemaker/anonymizer/dictionary.cjs +6 -72
  168. package/server/piecemaker/bodacc-search.ts +205 -0
  169. package/server/piecemaker/company-search.test.ts +26 -0
  170. package/server/piecemaker/company-search.ts +183 -0
  171. package/server/piecemaker/index.ts +8 -2
  172. package/server/piecemaker/knowledge/index.ts +9 -4
  173. package/server/piecemaker/knowledge/pipeline.ts +89 -57
  174. package/server/piecemaker/knowledge/routes.ts +2 -4
  175. package/server/piecemaker/knowledge/scan-jobs.ts +111 -0
  176. package/server/piecemaker/knowledge/service.ts +18 -33
  177. package/server/piecemaker/library/connector-installation.ts +248 -0
  178. package/server/piecemaker/library/index.ts +5 -1
  179. package/server/piecemaker/library/marketplace.ts +104 -39
  180. package/server/piecemaker/library/migrate.ts +8 -1
  181. package/server/piecemaker/library/provider-agents.ts +49 -0
  182. package/server/piecemaker/library/provider-connectors.ts +89 -0
  183. package/server/piecemaker/library/provider-skills.ts +10 -1
  184. package/server/piecemaker/library/store.ts +129 -36
  185. package/server/piecemaker/library/workspace-installation.ts +54 -29
  186. package/server/piecemaker/router.cjs +2 -1
  187. package/server/piecemaker/timesheet/service.ts +4 -16
  188. package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +0 -27
  189. package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +1 -1
  190. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +2 -3
  191. package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -3
  192. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3 -10
  193. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +135 -4
  194. package/server/piecemaker/vendor/websocket-server/process-group.cjs +95 -0
  195. package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
  196. package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +280 -149
  197. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
  198. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/scanner_worker.cpython-312.pyc +0 -0
  199. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +35 -29
  200. package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +0 -5
  201. package/server/shared/types.ts +1 -0
  202. package/dist/assets/channel-Dz3eE5vU.js +0 -1
  203. package/dist/assets/classDiagram-ZZMXUADV-BC1eKV2j.js +0 -1
  204. package/dist/assets/classDiagram-v2-VYDZK3BY-BC1eKV2j.js +0 -1
  205. package/dist/assets/index-DhwJpHCq.css +0 -1
  206. package/dist/assets/stateDiagram-v2-MP3YSRHH-BXuT4zDG.js +0 -1
  207. package/dist/assets/swimlanesDiagram-VR7AAH4N-B0eYrB4U.js +0 -8
  208. package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +0 -111
  209. package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +0 -216
  210. package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +0 -134
  211. package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +0 -138
  212. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +0 -246
  213. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +0 -62
  214. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
  215. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +0 -118
  216. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +0 -164
  217. package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +0 -479
@@ -1,6 +1,9 @@
1
+ import path from 'node:path';
2
+
1
3
  import { providerSkillsService } from '@/modules/providers/index.js';
2
4
  import type { LLMProvider, ProviderSkillListOptions } from '@/shared/types.js';
3
5
 
6
+ import { importLibraryDirectory } from './migrate.js';
4
7
  import type { createLibraryStore } from './store.js';
5
8
 
6
9
  const LIBRARY_SKILL_PROVIDERS: LLMProvider[] = ['claude', 'codex', 'cursor', 'mistral', 'opencode'];
@@ -35,14 +38,20 @@ export async function scanAndPersistLibraryProviderSkills(
35
38
  store: ReturnType<typeof createLibraryStore>,
36
39
  workspacePath: string | undefined,
37
40
  reader: ProviderSkillsReader = providerSkillsService,
41
+ userHome?: string,
38
42
  ) {
39
43
  const result = await listLibraryProviderSkills(workspacePath, reader);
40
44
  for (const provider of result.providers) {
41
45
  for (const skill of provider.skills) {
42
- if (!skill.sourcePath) continue;
46
+ if (!skill.sourcePath || skill.scope !== 'user' || skill.pluginId || skill.pluginName) continue;
43
47
  try { store.importFile(skill.sourcePath, 'skill'); }
44
48
  catch { try { store.importFile(skill.sourcePath, 'skill', false); } catch {} }
45
49
  }
46
50
  }
51
+ if (userHome) {
52
+ try { importLibraryDirectory(store, path.join(userHome, '.grok', 'skills'), 'skill', false); } catch {}
53
+ }
47
54
  return result;
48
55
  }
56
+
57
+ export { scanAndPersistLibraryClaudeAgents, scanAndPersistLibraryProviderAgents } from './provider-agents.js';
@@ -6,17 +6,26 @@ import Database from 'better-sqlite3';
6
6
 
7
7
  import { parseFrontMatter } from '@/shared/frontmatter.js';
8
8
 
9
+ import { parseConnectorConfig, prepareConnectorInstallation, type LibraryConnectorConfig } from './connector-installation.js';
9
10
  import { prepareWorkspaceInstallation } from './workspace-installation.js';
10
11
 
11
12
  type StoredLibraryEntry = {
12
13
  id: string;
13
- kind: 'skill' | 'agent';
14
+ kind: 'skill' | 'agent' | 'connector';
14
15
  name: string;
15
16
  description: string;
16
17
  content: string;
17
18
  assets: string;
18
19
  };
19
20
 
21
+ type LibraryConnectorInput = {
22
+ name: string;
23
+ description: string;
24
+ config: LibraryConnectorConfig;
25
+ source: string;
26
+ namespace?: string;
27
+ };
28
+
20
29
  type LibraryEntry = Omit<StoredLibraryEntry, 'assets'> & { assets: Record<string, string> };
21
30
 
22
31
  type LibraryCollectionEntry = {
@@ -112,14 +121,39 @@ export function createLibraryStore(home: string) {
112
121
  function list(workspacePath?: string) {
113
122
  const selected = workspacePath ? workspace(workspacePath) : '';
114
123
  return db.prepare(`SELECT e.id, e.kind, e.name, e.description,
115
- EXISTS(SELECT 1 FROM activation a WHERE a.entry_id = e.id AND a.workspace = ?) AS enabled
124
+ EXISTS(SELECT 1 FROM activation a WHERE a.entry_id = e.id AND a.workspace = ?) AS enabled,
125
+ (SELECT ce.collection_id FROM collection_entries ce WHERE ce.entry_id = e.id LIMIT 1) AS collectionId
116
126
  FROM entries e ORDER BY e.name COLLATE NOCASE`).all(selected).map((row) => {
117
- const entry = row as Omit<StoredLibraryEntry, 'content' | 'assets'> & { enabled: number };
118
- return { ...entry, enabled: Boolean(entry.enabled) };
127
+ const entry = row as Omit<StoredLibraryEntry, 'content' | 'assets'> & { enabled: number; collectionId: string | null };
128
+ return { ...entry, enabled: Boolean(entry.enabled), collectionId: entry.collectionId || null };
119
129
  });
120
130
  }
121
131
 
122
- function importFile(source: string, kind: StoredLibraryEntry['kind'], includeAssets = true) {
132
+ function persistImportedEntry(source: string, kind: StoredLibraryEntry['kind'], name: string, description: string, content: string, assets: Record<string, string>, id: string) {
133
+ const serialized = JSON.stringify(Object.fromEntries(Object.entries(assets).sort(([left], [right]) => left.localeCompare(right))));
134
+ const sourceHash = createHash('sha256').update(`${kind}\0${content}\0${serialized}`).digest('hex');
135
+ const originSource = !path.isAbsolute(source) || source.includes('#') ? source : path.resolve(source);
136
+ const existingOrigin = db.prepare('SELECT entry_id AS entryId, source_hash AS sourceHash FROM origins WHERE source = ?').get(originSource) as { entryId: string; sourceHash: string | null } | undefined;
137
+ if (existingOrigin) {
138
+ if (existingOrigin.sourceHash === null || existingOrigin.sourceHash === sourceHash) return existingOrigin.entryId;
139
+ const existingEntry = document(existingOrigin.entryId);
140
+ const existingAssets = JSON.stringify(Object.fromEntries(Object.entries(existingEntry.assets).sort(([left], [right]) => left.localeCompare(right))));
141
+ const existingHash = createHash('sha256').update(`${existingEntry.kind}\0${existingEntry.content}\0${existingAssets}`).digest('hex');
142
+ if (existingHash !== existingOrigin.sourceHash) return existingOrigin.entryId;
143
+ db.transaction(() => {
144
+ db.prepare('UPDATE entries SET name = ?, description = ?, content = ?, assets = ? WHERE id = ?').run(name, description, content, serialized, existingOrigin.entryId);
145
+ db.prepare('UPDATE origins SET source_hash = ? WHERE source = ?').run(sourceHash, originSource);
146
+ })();
147
+ return existingOrigin.entryId;
148
+ }
149
+ db.transaction(() => {
150
+ db.prepare('INSERT OR IGNORE INTO entries VALUES (?, ?, ?, ?, ?, ?)').run(id, kind, name, description, content, serialized);
151
+ db.prepare('INSERT INTO origins (source, entry_id, source_hash) VALUES (?, ?, ?)').run(originSource, id, sourceHash);
152
+ })();
153
+ return id;
154
+ }
155
+
156
+ function importFile(source: string, kind: 'skill' | 'agent', includeAssets = true) {
123
157
  const resolved = fs.realpathSync(source);
124
158
  const content = decodeUtf8File(fs.readFileSync(resolved));
125
159
  const parsed = parseFrontMatter(content);
@@ -147,30 +181,30 @@ export function createLibraryStore(home: string) {
147
181
  }
148
182
  }
149
183
  if (kind === 'skill' && includeAssets) collect(path.dirname(resolved));
150
- const serialized = JSON.stringify(Object.fromEntries(Object.entries(assets).sort(([a], [b]) => a.localeCompare(b))));
151
- const id = createHash('sha256').update(`${kind}\0${content}\0${serialized}`).digest('hex');
152
- const sourceHash = id;
153
- const existingOrigin = db.prepare('SELECT entry_id AS entryId, source_hash AS sourceHash FROM origins WHERE source = ?').get(path.resolve(source)) as { entryId: string; sourceHash: string | null } | undefined;
154
- if (existingOrigin) {
155
- if (existingOrigin.sourceHash === null || existingOrigin.sourceHash === sourceHash) return existingOrigin.entryId;
156
- const existingEntry = document(existingOrigin.entryId);
157
- const existingAssets = JSON.stringify(Object.fromEntries(Object.entries(existingEntry.assets).sort(([a], [b]) => a.localeCompare(b))));
158
- const existingHash = createHash('sha256').update(`${existingEntry.kind}\0${existingEntry.content}\0${existingAssets}`).digest('hex');
159
- if (existingHash !== existingOrigin.sourceHash) return existingOrigin.entryId;
160
- db.transaction(() => {
161
- db.prepare('UPDATE entries SET name = ?, description = ?, content = ?, assets = ? WHERE id = ?').run(name, description, content, serialized, existingOrigin.entryId);
162
- db.prepare('UPDATE origins SET source_hash = ? WHERE source = ?').run(sourceHash, path.resolve(source));
163
- })();
164
- return existingOrigin.entryId;
165
- }
166
- db.transaction(() => {
167
- db.prepare('INSERT OR IGNORE INTO entries VALUES (?, ?, ?, ?, ?, ?)').run(id, kind, name, description, content, serialized);
168
- db.prepare('INSERT INTO origins (source, entry_id, source_hash) VALUES (?, ?, ?)').run(path.resolve(source), id, sourceHash);
169
- })();
170
- return id;
184
+ const id = createHash('sha256').update(`${kind}\0${content}\0${JSON.stringify(Object.fromEntries(Object.entries(assets).sort(([left], [right]) => left.localeCompare(right))))}`).digest('hex');
185
+ return persistImportedEntry(resolved, kind, name, description, content, assets, id);
186
+ }
187
+
188
+ function importContent(source: string, kind: 'skill' | 'agent', content: string) {
189
+ const parsed = parseFrontMatter(content);
190
+ const data = parsed.data;
191
+ const sourceName = path.basename(source, path.extname(source));
192
+ const name = String(data.metadata?.title || data.name || sourceName);
193
+ const description = typeof data.description === 'string' ? data.description : '';
194
+ const id = createHash('sha256').update(`${kind}\0${content}\0{}`).digest('hex');
195
+ return persistImportedEntry(source, kind, name, description, content, {}, id);
196
+ }
197
+
198
+ function importConnector(input: LibraryConnectorInput) {
199
+ const name = input.name.trim();
200
+ if (!name) throw new Error('Nom requis.');
201
+ const content = `${JSON.stringify(input.config, null, 2)}\n`;
202
+ const description = input.description.trim() || (input.config.url || input.config.command || name);
203
+ const id = createHash('sha256').update(`connector\0${input.namespace || ''}\0${name}`).digest('hex');
204
+ return persistImportedEntry(input.source, 'connector', name, description, content, {}, id);
171
205
  }
172
206
 
173
- function createEntry(kind: StoredLibraryEntry['kind'], name: string, description: string) {
207
+ function createEntry(kind: 'skill' | 'agent', name: string, description: string) {
174
208
  const trimmedName = name.trim();
175
209
  if (!trimmedName) throw new Error('Nom requis.');
176
210
  const trimmedDescription = description.trim();
@@ -185,10 +219,16 @@ export function createLibraryStore(home: string) {
185
219
  return db.transaction(() => {
186
220
  const entry = document(id);
187
221
  if (entry.content !== previousContent) throw new Error('Le document a été modifié ailleurs. Rouvrez-le avant d’enregistrer.');
188
- const { data } = parseFrontMatter(content);
189
- const name = String(data.metadata?.title || data.name || entry.name);
190
- const description = typeof data.description === 'string' ? data.description : '';
191
- db.prepare('UPDATE entries SET name = ?, description = ?, content = ? WHERE id = ?').run(name, description, content, id);
222
+ if (entry.kind === 'connector') {
223
+ const config = parseConnectorConfig(content);
224
+ const description = config.url || config.command || entry.name;
225
+ db.prepare('UPDATE entries SET description = ?, content = ? WHERE id = ?').run(description, `${JSON.stringify(config, null, 2)}\n`, id);
226
+ } else {
227
+ const { data } = parseFrontMatter(content);
228
+ const name = String(data.metadata?.title || data.name || entry.name);
229
+ const description = typeof data.description === 'string' ? data.description : '';
230
+ db.prepare('UPDATE entries SET name = ?, description = ?, content = ? WHERE id = ?').run(name, description, content, id);
231
+ }
192
232
  const active = db.prepare('SELECT workspace FROM activation WHERE entry_id = ?').all(id) as Array<{ workspace: string }>;
193
233
  for (const { workspace: selected } of active) setEnabled(selected, id, true);
194
234
  return document(id);
@@ -228,7 +268,7 @@ export function createLibraryStore(home: string) {
228
268
  }
229
269
 
230
270
  function upsertCollection(input: LibraryCollectionInput) {
231
- if (!input.id || (!input.entries.length && !input.files.length)) return null;
271
+ if (!input.id || (!input.entries.length && !input.files.length && !input.source)) return null;
232
272
  return db.transaction(() => {
233
273
  db.prepare(`INSERT INTO collections (id, name, description, source) VALUES (?, ?, ?, ?)
234
274
  ON CONFLICT(id) DO UPDATE SET name = excluded.name, description = excluded.description, source = excluded.source`)
@@ -236,9 +276,11 @@ export function createLibraryStore(home: string) {
236
276
  db.prepare('DELETE FROM collection_entries WHERE collection_id = ?').run(input.id);
237
277
  const insert = db.prepare('INSERT INTO collection_entries (collection_id, entry_id, root_path) VALUES (?, ?, ?)');
238
278
  for (const entry of input.entries) insert.run(input.id, entry.entryId, normalizedCollectionPath(entry.rootPath));
239
- db.prepare('DELETE FROM collection_files WHERE collection_id = ?').run(input.id);
240
- const insertFile = db.prepare('INSERT INTO collection_files (collection_id, path, content) VALUES (?, ?, ?)');
241
- for (const file of input.files) insertFile.run(input.id, normalizedCollectionPath(file.path), file.content);
279
+ if (input.files.length) {
280
+ db.prepare('DELETE FROM collection_files WHERE collection_id = ?').run(input.id);
281
+ const insertFile = db.prepare('INSERT INTO collection_files (collection_id, path, content) VALUES (?, ?, ?)');
282
+ for (const file of input.files) insertFile.run(input.id, normalizedCollectionPath(file.path), file.content);
283
+ }
242
284
  return input.id;
243
285
  })();
244
286
  }
@@ -275,7 +317,48 @@ export function createLibraryStore(home: string) {
275
317
  });
276
318
  }
277
319
 
320
+ function collectionSource(id: string): string | null {
321
+ const row = db.prepare('SELECT source FROM collections WHERE id = ?').get(id) as { source: string } | undefined;
322
+ return row?.source || null;
323
+ }
324
+
325
+ function collectSourceFiles(source: string): Array<{ path: string; content: Buffer }> {
326
+ const root = fs.realpathSync(source);
327
+ const files: Array<{ path: string; content: Buffer }> = [];
328
+ let totalSize = 0;
329
+ const walk = (directory: string, relative = '') => {
330
+ for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
331
+ if (entry.name === '.git' || entry.name === 'node_modules' || entry.name === '__pycache__' || entry.isSymbolicLink()) continue;
332
+ const relativePath = path.posix.join(relative.split(path.sep).join('/'), entry.name);
333
+ const absolutePath = path.join(directory, entry.name);
334
+ if (entry.isDirectory()) walk(absolutePath, relativePath);
335
+ else if (entry.isFile()) {
336
+ const content = fs.readFileSync(absolutePath);
337
+ totalSize += content.length;
338
+ if (totalSize > 30 * 1024 * 1024 || files.length >= 5000) throw new Error(`Plugin trop volumineux : ${path.basename(root)}`);
339
+ files.push({ path: relativePath, content });
340
+ }
341
+ }
342
+ };
343
+ walk(root);
344
+ return files;
345
+ }
346
+
347
+ function ensureCollectionFiles(id: string) {
348
+ const stored = db.prepare('SELECT 1 FROM collection_files WHERE collection_id = ? LIMIT 1').get(id);
349
+ if (stored) return;
350
+ const source = collectionSource(id);
351
+ if (!source || !fs.existsSync(source) || fs.lstatSync(source).isSymbolicLink()) return;
352
+ const files = collectSourceFiles(source);
353
+ if (!files.length) return;
354
+ const insertFile = db.prepare('INSERT INTO collection_files (collection_id, path, content) VALUES (?, ?, ?)');
355
+ db.transaction(() => {
356
+ for (const file of files) insertFile.run(id, normalizedCollectionPath(file.path), file.content);
357
+ })();
358
+ }
359
+
278
360
  function collectionFiles(id: string) {
361
+ ensureCollectionFiles(id);
279
362
  const files = new Map<string, { path: string; size: number; editable: boolean }>();
280
363
  const storedFiles = db.prepare('SELECT path, content FROM collection_files WHERE collection_id = ?').all(id) as Array<{ path: string; content: Buffer }>;
281
364
  for (const file of storedFiles) {
@@ -304,6 +387,7 @@ export function createLibraryStore(home: string) {
304
387
  }
305
388
 
306
389
  function collectionFile(id: string, filePath: string) {
390
+ ensureCollectionFiles(id);
307
391
  const normalized = normalizedCollectionPath(filePath);
308
392
  for (const mapping of collectionEntries(id)) {
309
393
  const entry = document(mapping.entryId);
@@ -323,6 +407,7 @@ export function createLibraryStore(home: string) {
323
407
 
324
408
  function updateCollectionFile(id: string, filePath: string, content: string, previousContent: string) {
325
409
  if (typeof content !== 'string' || typeof previousContent !== 'string') throw new Error('Contenu et version précédente requis.');
410
+ ensureCollectionFiles(id);
326
411
  const normalized = normalizedCollectionPath(filePath);
327
412
  for (const mapping of collectionEntries(id)) {
328
413
  const entry = document(mapping.entryId);
@@ -373,6 +458,12 @@ export function createLibraryStore(home: string) {
373
458
  if (typeof enabled !== 'boolean') throw new Error('Activation booléenne requise.');
374
459
  const selected = workspace(workspacePath);
375
460
  const entry = document(id);
461
+ if (entry.kind === 'connector') {
462
+ prepareConnectorInstallation(selected, entry.name, parseConnectorConfig(entry.content), enabled)();
463
+ if (enabled) db.prepare('INSERT OR IGNORE INTO activation VALUES (?, ?)').run(selected, id);
464
+ else db.prepare('DELETE FROM activation WHERE workspace = ? AND entry_id = ?').run(selected, id);
465
+ return { ok: true, enabled };
466
+ }
376
467
  const packageRoot = path.join(directory, 'active', createHash('sha256').update(selected).digest('hex'), id);
377
468
  const install = prepareWorkspaceInstallation(selected, id, packageRoot, entry.kind, enabled);
378
469
  if (enabled) {
@@ -424,7 +515,7 @@ export function createLibraryStore(home: string) {
424
515
  function instructions(workspacePath: string) {
425
516
  const selected = workspace(workspacePath);
426
517
  const entries = db.prepare(`SELECT e.* FROM entries e JOIN activation a ON a.entry_id = e.id
427
- WHERE a.workspace = ? ORDER BY e.name`).all(selected) as StoredLibraryEntry[];
518
+ WHERE a.workspace = ? AND e.kind IN ('skill', 'agent') ORDER BY e.name`).all(selected) as StoredLibraryEntry[];
428
519
  return entries.map((entry) => {
429
520
  const assets = JSON.parse(entry.assets) as Record<string, string>;
430
521
  const references = Object.entries(assets).filter(([name]) => name === 'table-columns.yaml')
@@ -442,6 +533,8 @@ export function createLibraryStore(home: string) {
442
533
  deleteEntry,
443
534
  updateDocument,
444
535
  importFile,
536
+ importContent,
537
+ importConnector,
445
538
  setEnabled,
446
539
  instructions,
447
540
  upsertCollection,
@@ -1,44 +1,69 @@
1
1
  import fs from 'node:fs';
2
2
  import path from 'node:path';
3
3
 
4
+ const SKILL_PROVIDERS = ['.claude', '.agents', '.cursor', '.opencode', '.grok'];
5
+
6
+ const AGENT_TARGETS = [
7
+ { provider: '.claude', folder: 'agents', extension: '.md', sourceFile: 'agent.md' },
8
+ { provider: '.codex', folder: 'agents', extension: '.toml', sourceFile: 'agent.toml' },
9
+ { provider: '.opencode', folder: 'agent', extension: '.md', sourceFile: 'agent.md' },
10
+ { provider: '.grok', folder: 'agents', extension: '.md', sourceFile: 'agent.md' },
11
+ ] as const;
12
+
13
+ function assertWorkspaceDirectory(workspace: string, directory: string, enabled: boolean) {
14
+ if (!fs.existsSync(directory)) {
15
+ if (enabled) fs.mkdirSync(directory);
16
+ return;
17
+ }
18
+ if (!fs.statSync(directory).isDirectory() || !fs.realpathSync(directory).startsWith(workspace + path.sep)) {
19
+ throw new Error(`Répertoire de composants hors du dossier : ${directory}`);
20
+ }
21
+ }
22
+
4
23
  export function prepareWorkspaceInstallation(workspace: string, id: string, packageRoot: string, kind: 'skill' | 'agent', enabled: boolean) {
5
- const providers = kind === 'skill' ? ['.claude', '.agents'] : ['.claude', '.codex'];
6
- const targets = providers.map((provider) => {
7
- const parent = path.join(workspace, provider, kind === 'skill' ? 'skills' : 'agents');
8
- const extension = kind === 'skill' ? '' : provider === '.claude' ? '.md' : '.toml';
9
- const source = kind === 'skill' ? packageRoot : path.join(packageRoot, `agent${extension}`);
10
- for (const directory of [path.dirname(parent), parent]) {
11
- if (!fs.existsSync(directory)) {
12
- if (enabled) fs.mkdirSync(directory);
13
- continue;
14
- }
15
- if (!fs.statSync(directory).isDirectory() || !fs.realpathSync(directory).startsWith(workspace + path.sep)) {
16
- throw new Error(`Répertoire de composants hors du dossier : ${directory}`);
17
- }
18
- }
19
- const target = path.join(parent, `piecemaker-${id}${extension}`);
24
+ const targets = kind === 'skill'
25
+ ? SKILL_PROVIDERS.map((provider) => {
26
+ const parent = path.join(workspace, provider, 'skills');
27
+ for (const directory of [path.dirname(parent), parent]) assertWorkspaceDirectory(workspace, directory, enabled);
28
+ return {
29
+ parent,
30
+ target: path.join(parent, `piecemaker-${id}`),
31
+ source: packageRoot,
32
+ kind: 'skill' as const,
33
+ };
34
+ })
35
+ : AGENT_TARGETS.map((entry) => {
36
+ const parent = path.join(workspace, entry.provider, entry.folder);
37
+ for (const directory of [path.dirname(parent), parent]) assertWorkspaceDirectory(workspace, directory, enabled);
38
+ return {
39
+ parent,
40
+ target: path.join(parent, `piecemaker-${id}${entry.extension}`),
41
+ source: path.join(packageRoot, entry.sourceFile),
42
+ kind: 'agent' as const,
43
+ };
44
+ });
45
+
46
+ const prepared = targets.map((entry) => {
20
47
  let existing: fs.Stats;
21
- try { existing = fs.lstatSync(target); }
48
+ try { existing = fs.lstatSync(entry.target); }
22
49
  catch (error) {
23
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { target, source, installed: false, content: null };
50
+ if ((error as NodeJS.ErrnoException).code === 'ENOENT') return { ...entry, installed: false, content: null };
24
51
  throw error;
25
52
  }
26
- const content = kind === 'agent' && existing.isFile() ? fs.readFileSync(target) : null;
27
- const owned = kind === 'skill'
28
- ? existing.isSymbolicLink() && path.resolve(parent, fs.readlinkSync(target)) === source
29
- : content && fs.existsSync(source) && content.equals(fs.readFileSync(source));
30
- if (!owned) {
31
- throw new Error(`Composant personnel préservé : ${target}`);
32
- }
33
- return { target, source, installed: true, content };
53
+ const content = entry.kind === 'agent' && existing.isFile() ? fs.readFileSync(entry.target) : null;
54
+ const owned = entry.kind === 'skill'
55
+ ? existing.isSymbolicLink() && path.resolve(entry.parent, fs.readlinkSync(entry.target)) === entry.source
56
+ : content && fs.existsSync(entry.source) && content.equals(fs.readFileSync(entry.source));
57
+ if (!owned) throw new Error(`Composant personnel préservé : ${entry.target}`);
58
+ return { ...entry, installed: true, content };
34
59
  });
35
60
 
36
61
  return () => {
37
- const changed: typeof targets = [];
62
+ const changed: typeof prepared = [];
38
63
  try {
39
- for (const entry of targets) {
40
- const { target, source, installed } = entry;
41
- if (enabled && kind === 'agent') {
64
+ for (const entry of prepared) {
65
+ const { target, source, installed, kind: targetKind } = entry;
66
+ if (enabled && targetKind === 'agent') {
42
67
  fs.copyFileSync(source, target);
43
68
  changed.push(entry);
44
69
  } else if (enabled && !installed) {
@@ -15,6 +15,7 @@ const VENDOR_ROOT = path.join(__dirname, 'vendor');
15
15
  const { createAnonymizerRouter } = require('./anonymizer/routes.cjs');
16
16
  const { createAnonymizerService } = require('./anonymizer/service.cjs');
17
17
  const { createAdminRouter, registerLegalCase } = require('./vendor/websocket-server/admin-routes.cjs');
18
+ const { stopOriginalsJobs } = require('./vendor/websocket-server/originals-pipeline.cjs');
18
19
  const { readRegistryConfig, resolveCaseReference } = require('./vendor/websocket-server/case-registry.cjs');
19
20
  const protectionLibrary = require('./vendor/piecemaker-plugin/scripts/lib/protection.cjs');
20
21
  const { createProtectionBypassRouter } = require('./protection/routes.cjs');
@@ -104,4 +105,4 @@ function createPieceMakerRouter({ getRuntimeStatus = defaultRuntimeStatus, anony
104
105
  return router;
105
106
  }
106
107
 
107
- module.exports = { createPieceMakerRouter, piecemakerHome, VENDOR_ROOT };
108
+ module.exports = { createPieceMakerRouter, piecemakerHome, stopOriginalsJobs, VENDOR_ROOT };
@@ -71,24 +71,12 @@ function validTimestamp(value: string | null | undefined): string | null {
71
71
  return Number.isNaN(date.getTime()) ? null : date.toISOString();
72
72
  }
73
73
 
74
- function hashFile(filePath: string): string {
75
- const hash = createHash('sha256');
76
- let descriptor: number | undefined;
74
+ function fingerprintFile(filePath: string): string {
77
75
  try {
78
- descriptor = fs.openSync(filePath, 'r');
79
- const buffer = Buffer.allocUnsafe(64 * 1024);
80
- let bytesRead = 0;
81
- do {
82
- bytesRead = fs.readSync(descriptor, buffer, 0, buffer.length, null);
83
- if (bytesRead > 0) hash.update(buffer.subarray(0, bytesRead));
84
- } while (bytesRead > 0);
85
- return hash.digest('hex');
76
+ const stats = fs.statSync(filePath);
77
+ return `${stats.size}:${stats.mtimeMs}`;
86
78
  } catch {
87
79
  return 'missing';
88
- } finally {
89
- if (descriptor !== undefined) {
90
- try { fs.closeSync(descriptor); } catch { }
91
- }
92
80
  }
93
81
  }
94
82
 
@@ -115,7 +103,7 @@ function fingerprint(
115
103
  createdAt: session.created_at,
116
104
  updatedAt: session.updated_at,
117
105
  transcript: session.jsonl_path
118
- ? { path: session.jsonl_path, content: hashFile(session.jsonl_path) }
106
+ ? { path: session.jsonl_path, content: fingerprintFile(session.jsonl_path) }
119
107
  : { history: messages ? hashHistory(messages) : 'pending' },
120
108
  })).digest('hex');
121
109
  }
@@ -25,7 +25,6 @@ export const meta = {
25
25
  const SCRIPTS_DIR = path.join(REPO_ROOT, 'websocket-server', 'scripts');
26
26
  const REQUIREMENTS = path.join(SCRIPTS_DIR, 'requirements.txt');
27
27
  const WARMUP = path.join(SCRIPTS_DIR, 'warmup.py');
28
- const BUILD_COREML = path.join(SCRIPTS_DIR, 'presidio-gliner', 'build_coreml.py');
29
28
 
30
29
  function truncate(text) {
31
30
  const width = Math.max(20, columns() - 6);
@@ -184,32 +183,6 @@ export async function install(ctx) {
184
183
  }
185
184
  spin.succeed('GLiNER2.5 multilingue et modèles spaCy prêts');
186
185
 
187
- // Encodeur GPU CoreML (macOS) — optionnel. Il fait tourner l'encodeur mdeberta
188
- // sur le GPU et libère les cœurs CPU pendant un scan. Best-effort :
189
- // le runtime retombe sur torch si le modèle n'est pas généré, donc un échec ne
190
- // fait jamais échouer l'étape.
191
- if (process.platform === 'darwin' && fs.existsSync(BUILD_COREML)) {
192
- const buildIt = await confirm(
193
- 'Générer le nouvel encodeur GPU CoreML pour GLiNER2.5 maintenant ? (~4 min une fois, ~620 Mo — rend les scans plus rapides et libère le CPU)',
194
- true
195
- );
196
- if (buildIt) {
197
- const coremlSpin = spinner('Génération de l\'encodeur GPU CoreML (peut prendre plusieurs minutes)...');
198
- const coremlCode = await run(vp.python, [BUILD_COREML], {
199
- cwd: path.dirname(BUILD_COREML),
200
- onLine: (line) => coremlSpin.update(truncate(line)),
201
- });
202
- // build_coreml.py sort toujours 0 (best-effort) ; un code non nul signale un
203
- // problème d'exécution, mais l'anonymisation reste fonctionnelle sur torch.
204
- if (coremlCode === 0) {
205
- coremlSpin.succeed('Encodeur GPU CoreML prêt (repli torch automatique si absent)');
206
- } else {
207
- coremlSpin.fail('Encodeur GPU CoreML non généré — les scans tourneront sur CPU torch');
208
- return { status: 'done', note: 'Modèles prêts. Encodeur GPU non généré (scans sur CPU) — relancez l\'étape pour réessayer.' };
209
- }
210
- }
211
- }
212
-
213
186
  return { status: 'done', note: '' };
214
187
  }
215
188
 
@@ -8,7 +8,7 @@
8
8
  * PreToolUse hooks, which parse command text and are bypassable (see
9
9
  * docs/mxc-sandbox.md).
10
10
  *
11
- * Deliberately best-effort, like the CoreML encoder in step 03: mxc needs the
11
+ * Deliberately best-effort: mxc needs the
12
12
  * Rust toolchain, self-declares "not a security boundary currently", and its
13
13
  * value is defence-in-depth. Any failure falls back cleanly to the hooks and
14
14
  * never fails the install — the step is `required: false`. The runtime side
@@ -6,9 +6,8 @@
6
6
  * frontières de mots, des variantes Unicode et du tri longest-entity-first,
7
7
  * sinon deux moteurs de substitution divergent silencieusement.
8
8
  *
9
- * Ce moteur CommonJS est partagé par le serveur Word, l'historique et les
10
- * autres surfaces locales. Le proxy PII possède son
11
- * implémentation Python équivalente.
9
+ * Ce moteur CommonJS est partagé par le proxy PII (`anonymizer/dictionary.cjs`),
10
+ * l'historique et les autres surfaces locales.
12
11
  *
13
12
  * Deux sens, jamais symétriques dans leur usage :
14
13
  * - `applyMapping` entité → code, sur tout ce que l'IA s'apprête à lire ;
@@ -48,9 +48,9 @@ Bridge (`taskpane/modules/python-bridge.js` →
48
48
 
49
49
  Pour convertir puis scanner en un seul appel, utiliser
50
50
  `websocket-server/scripts/convert_and_scan_pipeline.py <file1> [file2 ...] -o <output_dir> [--engine ...] [--mode ...] [--lang ...]`,
51
- qui appelle `smart_converter.py` puis
52
- `websocket-server/scripts/presidio-gliner/presidio-gliner.py` pour chaque
53
- fichier. Sortie persistante : un Markdown par
51
+ qui appelle `smart_converter.py` puis le worker
52
+ `websocket-server/scripts/presidio-gliner/scanner_worker.py` (GLiNER chargé
53
+ une fois pour tout le lot). Sortie persistante : un Markdown par
54
54
  fichier et un unique `{output_dir}/mapping_default.json` cumulatif. Dans le
55
55
  pipeline d'administration d'un dossier, `-o` vise le sous-dossier
56
56
  `Fichiers convertis PieceMaker/` du dossier (racine réservée aux originaux) ;
@@ -775,15 +775,9 @@ async function configurationOverview({ repoRoot, homeDir, userHome, getRuntimeSt
775
775
  .every((name) => fs.existsSync(path.join(glinerModelCache, revision, name))));
776
776
  } catch { return false; }
777
777
  })();
778
- const glinerReady = fs.existsSync(path.join(glinerDir, 'presidio-gliner.py'))
778
+ const glinerReady = fs.existsSync(path.join(glinerDir, 'scanner_worker.py'))
779
779
  && hasPackage('gliner2')
780
780
  && glinerModelReady;
781
- const coremlDefault = path.join(
782
- glinerDir, 'models', 'gliner2.5-multi-v1-encoder_b1_832.mlmodelc',
783
- );
784
- const coreml = [process.env.PIECEMAKER_COREML_MODEL, coremlDefault]
785
- .filter(Boolean)
786
- .some((candidate) => fs.existsSync(candidate));
787
781
  const mineruReady = hasPackage('mineru') || hasPackage('magic_pdf')
788
782
  || fs.existsSync(path.join(venvDir, 'bin', 'mineru'));
789
783
  const folders = listConfiguredCases(readRegistryConfig(path.join(homeDir, 'config.json'))).map((entry) => {
@@ -841,11 +835,10 @@ async function configurationOverview({ repoRoot, homeDir, userHome, getRuntimeSt
841
835
  name: 'GLiNER2.5 · PII',
842
836
  installed: glinerReady,
843
837
  summary: glinerReady
844
- ? coreml ? 'Détection locale · GPU CoreML' : 'Détection locale · CPU'
838
+ ? 'Détection locale · PyTorch'
845
839
  : 'Modèle d’anonymisation absent',
846
- coreml,
847
840
  model: glinerModelId,
848
- engine: coreml ? 'CoreML (GPU)' : 'torch (CPU)',
841
+ engine: 'torch',
849
842
  },
850
843
  mineru: {
851
844
  name: 'MinerU · OCR',