@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.
- package/dist/assets/{abnfDiagram-VCTEODGH-DF7LFtT-.js → abnfDiagram-VCTEODGH-K8VucbQ5.js} +1 -1
- package/dist/assets/{arc-xOmjWeVH.js → arc-DUmCdRoC.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-CESzNPwa.js → architectureDiagram-5GKGNRK7-DYhs5vqD.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-BjdN78Ad.js → blockDiagram-I7D4REHJ-DaXJ9nve.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-BcK9EDWT.js → c4Diagram-7LVT6UL2-BLbi-zPT.js} +1 -1
- package/dist/assets/channel-CJIq1vqf.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-DGUN1JFP.js → chunk-2Q5K7J3B-Bzs3gxaq.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-BG3BBcFr.js → chunk-5VM5RSS4-CQNzml7k.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-CLIOfrF5.js → chunk-F27PBJKO-B8xedWWH.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-D6lGkqij.js → chunk-IMKFNOWR-CjBGlNOu.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BmF9vLBT.js → chunk-JWPE2WC7-vfnYEpgA.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-C_0SR3ak.js → chunk-POPQ4Y6H-Btl98tE8.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-rT20Wfpp.js → chunk-SVP7TREG-Bp6-pLjR.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-Cn2hkmcf.js → chunk-TICWLB2K-DvmznW2q.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-Dm_eP1_v.js → chunk-XXDRQBXY-QSHJTsI3.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-BYkEWggn.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-BYkEWggn.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-cJeeJsep.js → cose-bilkent-JH36ORCC-DxpyZoe2.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-DX2ePIXe.js → cynefin-OW5HDTMX-B9GRp2Gn.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-BvWXN-RR.js → cynefinDiagram-5FMLGOSQ-Q-2tz5GW.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-CkwPRhGR.js → dagre-GXQ25YYZ-3Rl3NqNe.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-CBGNzYyv.js → diagram-S7CK7UJ4-CreeWCO1.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-CiwCU0SJ.js → diagram-UQ7AKVKN-DNBoIyDJ.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-Aekg4nTk.js → diagram-VSXAHHWV-ZkcE_cRk.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-DPFP5K7r.js → diagram-VX7I27RA-Dzdf7N2Q.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-BHJkxoey.js → diagram-Z3DM3KII-M6b-nr1u.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-2rV1P32T.js → ebnfDiagram-PWID7BFC-DunIw64n.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-C4BjyS_H.js → erDiagram-RLTQ6QDP-kN0Se5uc.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-DL1TBlAG.js → flowDiagram-HODETNUW-24YCovut.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-MKjvzCWz.js → ganttDiagram-EL5Y4UJY-DTUUEEy6.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-CS_oTGK5.js → gitGraphDiagram-WWUBYQGX-BitrqhMr.js} +1 -1
- package/dist/assets/{index-XOGQDqU3.js → index-CG9hW1GU.js} +120 -120
- package/dist/assets/index-D_Dc_nQv.css +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-ihUr2GjN.js → infoDiagram-27XIBGKW-BNHN5Mby.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-D2YAnuir.js → ishikawaDiagram-5VMMS53U-De3IQKso.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-Bc2hSZGD.js → journeyDiagram-3NMN7TZE-CWlkZ25T.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-LRMGNonX.js → kanban-definition-UXKFOSKX-2o_ax-Nk.js} +1 -1
- package/dist/assets/{layout-CcfWOlPV.js → layout-Btga9ZYP.js} +1 -1
- package/dist/assets/{linear-7JoS2gQO.js → linear-BoGGmqPG.js} +1 -1
- package/dist/assets/{mermaid.core-ijh_SsuN.js → mermaid.core-M308jnLQ.js} +6 -6
- package/dist/assets/{mindmap-definition-YA3MSWOX-DCE4nzfF.js → mindmap-definition-YA3MSWOX-BJ6C_grh.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-SjaGa7lE.js → pegDiagram-XKGWAZYB-qcdYX0Xe.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-1xcRidSZ.js → pieDiagram-E7YTZNPT-XPrSlt1M.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-obHAHnYV.js → quadrantDiagram-AXDQQJYC-COhHhra5.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BsCVcRZb.js → railroadDiagram-O6MQD6OU-Mw_KF6gb.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-CUNkhvqb.js → requirementDiagram-BXWQKSXE-DPbt7jUM.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-DhezXMKm.js → sankeyDiagram-P5KCCOFB-B6HzL6Gh.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-CL9VswXH.js → sequenceDiagram-WJ2MYXX4-B_dXXCC0.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-t0g9jiEz.js → sizeCapture-INFHLROL-DwODubWN.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-BW-g-IOz.js → stateDiagram-D77RDMKH-5AUnOL3S.js} +1 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-CFM_nDL9.js +1 -0
- package/dist/assets/{swimlanes-42K2YHIH-LsuyeBte.js → swimlanes-42K2YHIH-BLnIwbnd.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-BRQJYnDN.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-B0cFka1R.js → timeline-definition-24CTP7MA-B1Yc7-na.js} +1 -1
- package/dist/assets/{vendor-codemirror-C5qqu4R7.js → vendor-codemirror-CjW0lHR5.js} +5 -5
- package/dist/assets/{vennDiagram-4TSXK5OY-D3HNCDR3.js → vennDiagram-4TSXK5OY-BFRtl-NI.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-DJ3Co8nb.js → wardleyDiagram-VM6X3IG4-BsR8iaD_.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-Cz5E9New.js → xychartDiagram-S5SC5T6Z-Crh1SwrA.js} +1 -1
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +1 -9
- package/dist/generate-icons.js +47 -46
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +1 -12
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +1 -12
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +1 -12
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +1 -12
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +1 -12
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +1 -12
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +1 -12
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +1 -12
- package/dist/index.html +3 -3
- package/dist/logo-128.png +0 -0
- package/dist/logo-256.png +0 -0
- package/dist/logo-32.png +0 -0
- package/dist/logo-512.png +0 -0
- package/dist/logo-64.png +0 -0
- package/dist/logo-sources/logo-black.png +0 -0
- package/dist/logo-sources/logo-white.png +0 -0
- package/dist/logo.svg +1 -17
- package/dist/sw.js +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js +91 -0
- package/dist-server/plugins/piecemaker-dossier/src/institutional-terms.js.map +1 -0
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js +112 -10
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js.map +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js +5 -1
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js.map +1 -1
- package/dist-server/server/index.js +60 -26
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/cli/desktop-shortcut.js +80 -0
- package/dist-server/server/modules/cli/desktop-shortcut.js.map +1 -0
- package/dist-server/server/modules/cli/pwa-launcher.js +27 -4
- package/dist-server/server/modules/cli/pwa-launcher.js.map +1 -1
- package/dist-server/server/modules/database/repositories/projects.db.js +28 -6
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -1
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js +58 -1
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -1
- package/dist-server/server/modules/plugins/plugins.routes.js +8 -1
- package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -1
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +2 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -1
- package/dist-server/server/piecemaker/bodacc-search.js +191 -0
- package/dist-server/server/piecemaker/bodacc-search.js.map +1 -0
- package/dist-server/server/piecemaker/company-search.js +145 -0
- package/dist-server/server/piecemaker/company-search.js.map +1 -0
- package/dist-server/server/piecemaker/company-search.test.js +18 -0
- package/dist-server/server/piecemaker/company-search.test.js.map +1 -0
- package/dist-server/server/piecemaker/index.js +6 -2
- package/dist-server/server/piecemaker/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/index.js +9 -4
- package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/pipeline.js +68 -58
- package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/routes.js +2 -4
- package/dist-server/server/piecemaker/knowledge/routes.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js +91 -0
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -0
- package/dist-server/server/piecemaker/knowledge/service.js +18 -36
- package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
- package/dist-server/server/piecemaker/library/connector-installation.js +224 -0
- package/dist-server/server/piecemaker/library/connector-installation.js.map +1 -0
- package/dist-server/server/piecemaker/library/index.js +11 -1
- package/dist-server/server/piecemaker/library/index.js.map +1 -1
- package/dist-server/server/piecemaker/library/marketplace.js +102 -43
- package/dist-server/server/piecemaker/library/marketplace.js.map +1 -1
- package/dist-server/server/piecemaker/library/migrate.js +8 -1
- package/dist-server/server/piecemaker/library/migrate.js.map +1 -1
- package/dist-server/server/piecemaker/library/provider-agents.js +50 -0
- package/dist-server/server/piecemaker/library/provider-agents.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-connectors.js +80 -0
- package/dist-server/server/piecemaker/library/provider-connectors.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-skills.js +11 -2
- package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -1
- package/dist-server/server/piecemaker/library/store.js +125 -35
- package/dist-server/server/piecemaker/library/store.js.map +1 -1
- package/dist-server/server/piecemaker/library/workspace-installation.js +53 -29
- package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
- package/dist-server/server/piecemaker/timesheet/service.js +4 -21
- package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
- package/package.json +3 -2
- package/product.config.json +1 -0
- package/scripts/piecemaker/cli/install-command.mjs +35 -9
- package/scripts/piecemaker/cli/lib/app-window.mjs +47 -0
- package/scripts/piecemaker/cli/lib/config.mjs +1 -0
- package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +78 -0
- package/scripts/piecemaker/cli/lib/plugins.mjs +2 -0
- package/scripts/piecemaker/cli/lib/pwa.mjs +49 -13
- package/scripts/piecemaker/cli/lib/services.mjs +65 -4
- package/scripts/piecemaker/cli/piecemaker-command.test.mjs +25 -0
- package/scripts/piecemaker/cli/piecemaker.mjs +60 -45
- package/scripts/piecemaker/cli/piecemaker.ps1 +8 -0
- package/scripts/piecemaker/cli/piecemaker.sh +6 -1
- package/server/index.ts +52 -23
- package/server/modules/cli/desktop-shortcut.ts +89 -0
- package/server/modules/cli/pwa-launcher.ts +29 -4
- package/server/modules/database/repositories/projects.db.ts +28 -6
- package/server/modules/database/tests/projects.db.integration.test.ts +63 -1
- package/server/modules/plugins/plugins.routes.ts +8 -1
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +5 -0
- package/server/piecemaker/anonymizer/client-config.cjs +10 -2
- package/server/piecemaker/anonymizer/dictionary.cjs +6 -72
- package/server/piecemaker/bodacc-search.ts +205 -0
- package/server/piecemaker/company-search.test.ts +26 -0
- package/server/piecemaker/company-search.ts +183 -0
- package/server/piecemaker/index.ts +8 -2
- package/server/piecemaker/knowledge/index.ts +9 -4
- package/server/piecemaker/knowledge/pipeline.ts +89 -57
- package/server/piecemaker/knowledge/routes.ts +2 -4
- package/server/piecemaker/knowledge/scan-jobs.ts +111 -0
- package/server/piecemaker/knowledge/service.ts +18 -33
- package/server/piecemaker/library/connector-installation.ts +248 -0
- package/server/piecemaker/library/index.ts +5 -1
- package/server/piecemaker/library/marketplace.ts +104 -39
- package/server/piecemaker/library/migrate.ts +8 -1
- package/server/piecemaker/library/provider-agents.ts +49 -0
- package/server/piecemaker/library/provider-connectors.ts +89 -0
- package/server/piecemaker/library/provider-skills.ts +10 -1
- package/server/piecemaker/library/store.ts +129 -36
- package/server/piecemaker/library/workspace-installation.ts +54 -29
- package/server/piecemaker/router.cjs +2 -1
- package/server/piecemaker/timesheet/service.ts +4 -16
- package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +0 -27
- package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +1 -1
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +2 -3
- package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +3 -3
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3 -10
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +135 -4
- package/server/piecemaker/vendor/websocket-server/process-group.cjs +95 -0
- package/server/piecemaker/vendor/websocket-server/scripts/__pycache__/scan_utils.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +280 -149
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/model_config.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/scanner_worker.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +35 -29
- package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +0 -5
- package/server/shared/types.ts +1 -0
- package/dist/assets/channel-Dz3eE5vU.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BC1eKV2j.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-BC1eKV2j.js +0 -1
- package/dist/assets/index-DhwJpHCq.css +0 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-BXuT4zDG.js +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-B0eYrB4U.js +0 -8
- package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +0 -111
- package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +0 -216
- package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +0 -134
- package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +0 -138
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +0 -246
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +0 -62
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/__pycache__/coreml_runtime.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +0 -118
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +0 -164
- 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
|
|
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
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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:
|
|
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
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
|
62
|
+
const changed: typeof prepared = [];
|
|
38
63
|
try {
|
|
39
|
-
for (const entry of
|
|
40
|
-
const { target, source, installed } = entry;
|
|
41
|
-
if (enabled &&
|
|
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
|
|
75
|
-
const hash = createHash('sha256');
|
|
76
|
-
let descriptor: number | undefined;
|
|
74
|
+
function fingerprintFile(filePath: string): string {
|
|
77
75
|
try {
|
|
78
|
-
|
|
79
|
-
|
|
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:
|
|
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
|
|
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
|
|
10
|
-
* autres surfaces locales.
|
|
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/
|
|
53
|
-
|
|
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, '
|
|
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
|
-
?
|
|
838
|
+
? 'Détection locale · PyTorch'
|
|
845
839
|
: 'Modèle d’anonymisation absent',
|
|
846
|
-
coreml,
|
|
847
840
|
model: glinerModelId,
|
|
848
|
-
engine:
|
|
841
|
+
engine: 'torch',
|
|
849
842
|
},
|
|
850
843
|
mineru: {
|
|
851
844
|
name: 'MinerU · OCR',
|