@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
|
@@ -4,7 +4,7 @@ import { tmpdir } from 'node:os';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import test from 'node:test';
|
|
6
6
|
|
|
7
|
-
import { closeConnection } from '@/modules/database/connection.js';
|
|
7
|
+
import { closeConnection, getConnection } from '@/modules/database/connection.js';
|
|
8
8
|
import { initializeDatabase } from '@/modules/database/init-db.js';
|
|
9
9
|
import { projectsDb } from '@/modules/database/repositories/projects.db.js';
|
|
10
10
|
|
|
@@ -70,3 +70,65 @@ test('projectsDb.createProjectPath returns active_conflict for active duplicates
|
|
|
70
70
|
assert.equal(conflict.project?.isArchived, 0);
|
|
71
71
|
});
|
|
72
72
|
});
|
|
73
|
+
|
|
74
|
+
test('projectsDb.getProjectPaths reads anonymization completion directly from SQLite', async () => {
|
|
75
|
+
await withIsolatedDatabase(() => {
|
|
76
|
+
const created = projectsDb.createProjectPath('/workspace/anonymized-project');
|
|
77
|
+
assert.ok(created.project);
|
|
78
|
+
|
|
79
|
+
projectsDb.getProjectPaths();
|
|
80
|
+
getConnection().prepare(`
|
|
81
|
+
INSERT INTO piecemaker_anonymization_status (project_id, completed_at)
|
|
82
|
+
VALUES (?, ?)
|
|
83
|
+
`).run(created.project.project_id, new Date().toISOString());
|
|
84
|
+
|
|
85
|
+
const project = projectsDb.getProjectPaths()[0];
|
|
86
|
+
assert.equal(project.anonymization_complete, 1);
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('projectsDb.getProjectPaths backfills anonymization completion from existing mappings', async () => {
|
|
91
|
+
await withIsolatedDatabase(() => {
|
|
92
|
+
const created = projectsDb.createProjectPath('/workspace/legacy-scanned-project');
|
|
93
|
+
assert.ok(created.project);
|
|
94
|
+
const db = getConnection();
|
|
95
|
+
db.exec(`
|
|
96
|
+
CREATE TABLE IF NOT EXISTS piecemaker_nodes (
|
|
97
|
+
project_id TEXT NOT NULL,
|
|
98
|
+
id TEXT NOT NULL,
|
|
99
|
+
kind TEXT NOT NULL,
|
|
100
|
+
label TEXT NOT NULL,
|
|
101
|
+
search_text TEXT NOT NULL DEFAULT '',
|
|
102
|
+
aliases_json TEXT NOT NULL DEFAULT '[]',
|
|
103
|
+
data_json TEXT NOT NULL DEFAULT '{}',
|
|
104
|
+
origin TEXT NOT NULL DEFAULT 'gliner',
|
|
105
|
+
created_at TEXT NOT NULL,
|
|
106
|
+
updated_at TEXT NOT NULL,
|
|
107
|
+
PRIMARY KEY (project_id, id)
|
|
108
|
+
);
|
|
109
|
+
CREATE TABLE IF NOT EXISTS piecemaker_mappings (
|
|
110
|
+
project_id TEXT NOT NULL,
|
|
111
|
+
node_id TEXT NOT NULL,
|
|
112
|
+
real_value TEXT NOT NULL,
|
|
113
|
+
masked_value TEXT NOT NULL,
|
|
114
|
+
search_text TEXT NOT NULL DEFAULT '',
|
|
115
|
+
data_json TEXT NOT NULL DEFAULT '{}',
|
|
116
|
+
origin TEXT NOT NULL DEFAULT 'gliner',
|
|
117
|
+
created_at TEXT NOT NULL,
|
|
118
|
+
updated_at TEXT NOT NULL,
|
|
119
|
+
PRIMARY KEY (project_id, node_id, real_value)
|
|
120
|
+
);
|
|
121
|
+
`);
|
|
122
|
+
db.prepare(`
|
|
123
|
+
INSERT INTO piecemaker_nodes(project_id,id,kind,label,search_text,aliases_json,data_json,origin,created_at,updated_at)
|
|
124
|
+
VALUES (?, 'person-1', 'person', 'Alice', 'alice', '[]', '{}', 'gliner', ?, ?)
|
|
125
|
+
`).run(created.project.project_id, new Date().toISOString(), new Date().toISOString());
|
|
126
|
+
db.prepare(`
|
|
127
|
+
INSERT INTO piecemaker_mappings(project_id,node_id,real_value,masked_value,search_text,data_json,origin,created_at,updated_at)
|
|
128
|
+
VALUES (?, 'person-1', 'Alice', 'PERSONNE_PHYSIQUE_01', 'alice', '{}', 'gliner', ?, ?)
|
|
129
|
+
`).run(created.project.project_id, new Date().toISOString(), new Date().toISOString());
|
|
130
|
+
|
|
131
|
+
const project = projectsDb.getProjectPaths()[0];
|
|
132
|
+
assert.equal(project.anonymization_complete, 1);
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -26,8 +26,15 @@ export function createPluginsRouter(service: ReturnType<typeof createPluginsServ
|
|
|
26
26
|
router.get('/:name/assets/*', async (req, res, next) => {
|
|
27
27
|
try {
|
|
28
28
|
const asset = service.resolveAsset(routeParameter(req.params.name), wildcardPath(req));
|
|
29
|
+
const stats = fs.statSync(asset.path);
|
|
30
|
+
const etag = `"${stats.mtimeMs.toString(16)}-${stats.size.toString(16)}"`;
|
|
29
31
|
res.setHeader('Content-Type', asset.contentType);
|
|
30
|
-
res.setHeader('
|
|
32
|
+
res.setHeader('ETag', etag);
|
|
33
|
+
res.setHeader('Cache-Control', 'private, max-age=0, must-revalidate');
|
|
34
|
+
if (req.headers['if-none-match'] === etag) {
|
|
35
|
+
res.status(304).end();
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
31
38
|
const stream = fs.createReadStream(asset.path);
|
|
32
39
|
stream.on('error', next);
|
|
33
40
|
stream.pipe(res);
|
|
@@ -29,6 +29,7 @@ export type ProjectListItem = {
|
|
|
29
29
|
displayName: string;
|
|
30
30
|
fullPath: string;
|
|
31
31
|
isStarred: boolean;
|
|
32
|
+
anonymizationComplete: boolean;
|
|
32
33
|
sessions: SessionSummary[];
|
|
33
34
|
sessionMeta: {
|
|
34
35
|
hasMore: boolean;
|
|
@@ -189,6 +190,7 @@ export async function getProjectsWithSessions(
|
|
|
189
190
|
project_path: string;
|
|
190
191
|
custom_project_name?: string | null;
|
|
191
192
|
isStarred?: number;
|
|
193
|
+
anonymization_complete?: number;
|
|
192
194
|
}>;
|
|
193
195
|
const totalProjects = projectRows.length;
|
|
194
196
|
const projects: ProjectListItem[] = [];
|
|
@@ -223,6 +225,7 @@ export async function getProjectsWithSessions(
|
|
|
223
225
|
displayName,
|
|
224
226
|
fullPath: projectPath,
|
|
225
227
|
isStarred: Boolean(row.isStarred),
|
|
228
|
+
anonymizationComplete: Boolean(row.anonymization_complete),
|
|
226
229
|
sessions: sessionsPage.sessions,
|
|
227
230
|
sessionMeta: {
|
|
228
231
|
hasMore: sessionsPage.hasMore,
|
|
@@ -257,6 +260,7 @@ export async function getArchivedProjectsWithSessions(
|
|
|
257
260
|
project_path: string;
|
|
258
261
|
custom_project_name?: string | null;
|
|
259
262
|
isStarred?: number;
|
|
263
|
+
anonymization_complete?: number;
|
|
260
264
|
}>;
|
|
261
265
|
|
|
262
266
|
const archivedProjects: ArchivedProjectListItem[] = [];
|
|
@@ -275,6 +279,7 @@ export async function getArchivedProjectsWithSessions(
|
|
|
275
279
|
displayName,
|
|
276
280
|
fullPath: row.project_path,
|
|
277
281
|
isStarred: Boolean(row.isStarred),
|
|
282
|
+
anonymizationComplete: Boolean(row.anonymization_complete),
|
|
278
283
|
isArchived: true,
|
|
279
284
|
sessions: sessionsPage.sessions,
|
|
280
285
|
sessionMeta: {
|
|
@@ -138,10 +138,18 @@ function configureCodexProxy({
|
|
|
138
138
|
|
|
139
139
|
const managedTable = lines.findIndex((line) => line.trim() === `[model_providers.${CODEX_PROVIDER_ID}]`);
|
|
140
140
|
const managedStart = lines.findIndex((line) => line.trim() === CODEX_BLOCK_START);
|
|
141
|
-
|
|
142
|
-
if (managedTable >= 0 &&
|
|
141
|
+
let managedEnd = lines.findIndex((line) => line.trim() === CODEX_BLOCK_END);
|
|
142
|
+
if (managedTable >= 0 && managedStart < 0) {
|
|
143
143
|
return { configured: false, changed: false, conflict: true, file: configFile, reason: 'provider-table-conflict' };
|
|
144
144
|
}
|
|
145
|
+
if (managedStart >= 0 && managedEnd < managedStart) {
|
|
146
|
+
let end = managedTable >= managedStart ? managedTable : managedStart;
|
|
147
|
+
for (let index = end + 1; index < lines.length; index += 1) {
|
|
148
|
+
if (/^\s*\[/.test(lines[index])) break;
|
|
149
|
+
end = index;
|
|
150
|
+
}
|
|
151
|
+
managedEnd = end;
|
|
152
|
+
}
|
|
145
153
|
|
|
146
154
|
if (provider) {
|
|
147
155
|
lines[provider.index] = `model_provider = ${tomlString(CODEX_PROVIDER_ID)} # géré par PieceMaker`;
|
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Dictionnaire d'anonymisation du proxy PII.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* chokepoint réseau demande : un nom appartenant au dossier B doit rester
|
|
8
|
-
* protégé même s'il est tapé dans une conversation ouverte sur le dossier A.
|
|
9
|
-
* Un proxy par dossier ne saurait pas le faire.
|
|
4
|
+
* Le proxy charge le dictionnaire depuis SQLite (`sqlite-dictionary.cjs`,
|
|
5
|
+
* tables `piecemaker_mappings` / `piecemaker_nodes`). Ce module construit la
|
|
6
|
+
* forme exploitable (`buildDictionary`) et applique la substitution.
|
|
10
7
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* Rechargement à chaud sur `mtime` : une conversion qui ré-écrit le mapping est
|
|
16
|
-
* prise en compte sans redémarrer CloudCLI.
|
|
8
|
+
* Un nom appartenant au dossier B doit rester protégé même s'il est tapé dans
|
|
9
|
+
* une conversation ouverte sur le dossier A. Un proxy par dossier ne saurait
|
|
10
|
+
* pas le faire.
|
|
17
11
|
*/
|
|
18
|
-
const fs = require('node:fs');
|
|
19
|
-
const path = require('node:path');
|
|
20
|
-
|
|
21
12
|
const {
|
|
22
13
|
applyMapping,
|
|
23
14
|
buildEntityRegex,
|
|
@@ -25,8 +16,6 @@ const {
|
|
|
25
16
|
MIN_ENTITY_LENGTH,
|
|
26
17
|
} = require('../vendor/piecemaker-plugin/scripts/lib/substitution.cjs');
|
|
27
18
|
|
|
28
|
-
const CENTRAL_FILENAME = 'central-mapping.json';
|
|
29
|
-
|
|
30
19
|
/** Un dictionnaire vide se comporte comme un proxy transparent. */
|
|
31
20
|
const EMPTY = Object.freeze({
|
|
32
21
|
version: 0,
|
|
@@ -41,14 +30,6 @@ const EMPTY = Object.freeze({
|
|
|
41
30
|
empty: true,
|
|
42
31
|
});
|
|
43
32
|
|
|
44
|
-
function readJson(file) {
|
|
45
|
-
try {
|
|
46
|
-
return JSON.parse(fs.readFileSync(file, 'utf8').replace(/^/, ''));
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
33
|
function plainObject(value) {
|
|
53
34
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
54
35
|
}
|
|
@@ -66,7 +47,6 @@ function plainObject(value) {
|
|
|
66
47
|
* moteur refuse de substituer (`buildEntityRegex` nul : ponctuation pure, deux
|
|
67
48
|
* caractères non acronymiques) est écartée des deux listes : surligner ce qui
|
|
68
49
|
* ne part pas codé serait un mensonge à l'écran.
|
|
69
|
-
*
|
|
70
50
|
*/
|
|
71
51
|
function buildDictionary(document, stamp) {
|
|
72
52
|
const mapping = plainObject(document?.mapping);
|
|
@@ -107,50 +87,6 @@ function buildDictionary(document, stamp) {
|
|
|
107
87
|
};
|
|
108
88
|
}
|
|
109
89
|
|
|
110
|
-
/**
|
|
111
|
-
* Chargeur à cache : relit le fichier uniquement quand sa signature
|
|
112
|
-
* (mtime + taille) change. `version` s'incrémente à chaque rechargement effectif,
|
|
113
|
-
* ce qui sert de clé de cache aux consommateurs (client compris).
|
|
114
|
-
*/
|
|
115
|
-
function createDictionaryLoader({ homeDir }) {
|
|
116
|
-
const file = path.join(homeDir, CENTRAL_FILENAME);
|
|
117
|
-
let signature = null;
|
|
118
|
-
let current = EMPTY;
|
|
119
|
-
let generation = 0;
|
|
120
|
-
|
|
121
|
-
function statSignature() {
|
|
122
|
-
try {
|
|
123
|
-
const stats = fs.statSync(file);
|
|
124
|
-
return `${stats.mtimeMs}:${stats.size}`;
|
|
125
|
-
} catch {
|
|
126
|
-
return null;
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function load(force = false) {
|
|
131
|
-
const next = statSignature();
|
|
132
|
-
if (!force && next === signature) return current;
|
|
133
|
-
signature = next;
|
|
134
|
-
if (next === null) {
|
|
135
|
-
current = EMPTY;
|
|
136
|
-
return current;
|
|
137
|
-
}
|
|
138
|
-
const document = readJson(file);
|
|
139
|
-
generation += 1;
|
|
140
|
-
current = document ? buildDictionary(document, generation) : EMPTY;
|
|
141
|
-
return current;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return {
|
|
145
|
-
file,
|
|
146
|
-
/** Le dictionnaire à jour, relu si le fichier a bougé. */
|
|
147
|
-
get: () => load(false),
|
|
148
|
-
/** Relecture inconditionnelle, pour le bouton « rafraîchir ». */
|
|
149
|
-
refresh: () => load(true),
|
|
150
|
-
exists: () => statSignature() !== null,
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
|
|
154
90
|
/** Nom réel → code, sur tout ce qui part vers l'API. */
|
|
155
91
|
function anonymize(text, dictionary) {
|
|
156
92
|
return dictionary.empty ? text : applyMapping(text, dictionary.mapping);
|
|
@@ -162,10 +98,8 @@ function deanonymize(text, dictionary) {
|
|
|
162
98
|
}
|
|
163
99
|
|
|
164
100
|
module.exports = {
|
|
165
|
-
CENTRAL_FILENAME,
|
|
166
101
|
EMPTY_DICTIONARY: EMPTY,
|
|
167
102
|
anonymize,
|
|
168
103
|
buildDictionary,
|
|
169
|
-
createDictionaryLoader,
|
|
170
104
|
deanonymize,
|
|
171
105
|
};
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
import express, { type Request, type Response } from 'express';
|
|
7
|
+
|
|
8
|
+
type McpContent = {
|
|
9
|
+
type?: string;
|
|
10
|
+
text?: string;
|
|
11
|
+
resource?: { text?: string };
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
type McpMessage = {
|
|
15
|
+
id?: number;
|
|
16
|
+
error?: { message?: string };
|
|
17
|
+
result?: { content?: McpContent[]; isError?: boolean };
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export type BodaccAnnouncement = {
|
|
21
|
+
id: string;
|
|
22
|
+
datePublication: string;
|
|
23
|
+
typeAvis: string;
|
|
24
|
+
familleAvis: string;
|
|
25
|
+
commercant: string;
|
|
26
|
+
ville: string;
|
|
27
|
+
tribunal: string;
|
|
28
|
+
jugement: string;
|
|
29
|
+
acte: string;
|
|
30
|
+
url: string;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type BodaccSearchResult = {
|
|
34
|
+
siren: string;
|
|
35
|
+
total: number;
|
|
36
|
+
alertes: string[];
|
|
37
|
+
annonces: BodaccAnnouncement[];
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const BODACC_FAMILY_CODES = new Set([
|
|
41
|
+
'dpc',
|
|
42
|
+
'modification',
|
|
43
|
+
'creation',
|
|
44
|
+
'radiation',
|
|
45
|
+
'collective',
|
|
46
|
+
'vente',
|
|
47
|
+
'immatriculation',
|
|
48
|
+
'divers',
|
|
49
|
+
'conciliation',
|
|
50
|
+
'retablissement_professionnel',
|
|
51
|
+
'inconnue',
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const MCP_TIMEOUT_MS = 45_000;
|
|
55
|
+
|
|
56
|
+
function collectLauncherCandidates(): string[] {
|
|
57
|
+
const candidates: string[] = [];
|
|
58
|
+
const addRoot = (root: string | undefined) => {
|
|
59
|
+
if (root) candidates.push(path.join(root, 'scripts', 'launcher.py'));
|
|
60
|
+
};
|
|
61
|
+
addRoot(process.env.LEGIFRANCE_MCP_ROOT);
|
|
62
|
+
if (process.env.LEGIFRANCE_MCP_LAUNCHER) candidates.push(process.env.LEGIFRANCE_MCP_LAUNCHER);
|
|
63
|
+
const pluginConfigPath = path.join(os.homedir(), '.claude', 'plugins', 'installed_plugins.json');
|
|
64
|
+
if (existsSync(pluginConfigPath)) {
|
|
65
|
+
try {
|
|
66
|
+
const configuration = JSON.parse(readFileSync(pluginConfigPath, 'utf8')) as { plugins?: Record<string, Array<{ installPath?: string }>> };
|
|
67
|
+
for (const [plugin, installations] of Object.entries(configuration.plugins || {})) {
|
|
68
|
+
if (!plugin.includes('mcp-legifrance')) continue;
|
|
69
|
+
for (const installation of installations) addRoot(installation.installPath);
|
|
70
|
+
}
|
|
71
|
+
} catch {
|
|
72
|
+
return candidates;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const versionsRoot = path.join(os.homedir(), '.claude', 'plugins', 'cache', 'mcp-legifrance', 'piecemaker');
|
|
76
|
+
if (existsSync(versionsRoot)) {
|
|
77
|
+
for (const version of readdirSync(versionsRoot).sort().reverse()) addRoot(path.join(versionsRoot, version));
|
|
78
|
+
}
|
|
79
|
+
return [...new Set(candidates)];
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function resolveLauncher(): string {
|
|
83
|
+
const launcher = collectLauncherCandidates().find((candidate) => existsSync(candidate));
|
|
84
|
+
if (!launcher) throw new Error('Le lanceur du PERS_MORALE_1 Légifrance est introuvable.');
|
|
85
|
+
return launcher;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function mcpCall(tool: string, argumentsValue: Record<string, string>): Promise<McpMessage> {
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
const processHandle = spawn(process.env.PYTHON_PATH || 'python3', [resolveLauncher()], {
|
|
91
|
+
env: { ...process.env, PYTHONDONTWRITEBYTECODE: '1' },
|
|
92
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
93
|
+
});
|
|
94
|
+
let stdout = '';
|
|
95
|
+
let settled = false;
|
|
96
|
+
const timeout = setTimeout(() => {
|
|
97
|
+
processHandle.kill('SIGTERM');
|
|
98
|
+
reject(new Error('Le PERS_MORALE_1 Légifrance n’a pas répondu à temps.'));
|
|
99
|
+
}, MCP_TIMEOUT_MS);
|
|
100
|
+
const finish = (callback: () => void) => {
|
|
101
|
+
if (settled) return;
|
|
102
|
+
settled = true;
|
|
103
|
+
clearTimeout(timeout);
|
|
104
|
+
callback();
|
|
105
|
+
};
|
|
106
|
+
processHandle.stdout.on('data', (chunk: Buffer) => {
|
|
107
|
+
stdout += chunk.toString();
|
|
108
|
+
for (const line of stdout.split(/\r?\n/).slice(0, -1)) {
|
|
109
|
+
try {
|
|
110
|
+
const message = JSON.parse(line) as McpMessage;
|
|
111
|
+
if (message.id === 3) finish(() => resolve(message));
|
|
112
|
+
} catch {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
stdout = stdout.split(/\r?\n/).at(-1) || '';
|
|
117
|
+
});
|
|
118
|
+
processHandle.once('error', (error) => finish(() => reject(error)));
|
|
119
|
+
processHandle.once('close', (code) => {
|
|
120
|
+
if (!settled) finish(() => reject(new Error(code === null ? 'Le processus Légifrance a été interrompu.' : `Le processus Légifrance s’est arrêté (${code}).`)));
|
|
121
|
+
});
|
|
122
|
+
processHandle.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: { protocolVersion: '2025-06-18', capabilities: {}, clientInfo: { name: 'piecemaker-dossier', version: '0.1.0' } } })}\n`);
|
|
123
|
+
processHandle.stdin.write('{"jsonrpc":"2.0","method":"notifications/initialized","params":{}}\n');
|
|
124
|
+
processHandle.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id: 3, method: 'tools/call', params: { name: tool, arguments: argumentsValue } })}\n`);
|
|
125
|
+
processHandle.stdin.end();
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function normalizedSiren(siren: string, siret: string): string {
|
|
130
|
+
const sirenDigits = siren.replace(/\D/g, '');
|
|
131
|
+
if (sirenDigits.length === 9) return sirenDigits;
|
|
132
|
+
const siretDigits = siret.replace(/\D/g, '');
|
|
133
|
+
if (siretDigits.length === 14) return siretDigits.slice(0, 9);
|
|
134
|
+
if (sirenDigits.length === 14) return sirenDigits.slice(0, 9);
|
|
135
|
+
throw new Error('Un SIREN à 9 chiffres ou un SIRET à 14 chiffres est requis.');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function resultContent(message: McpMessage): McpContent[] {
|
|
139
|
+
if (message.error?.message) throw new Error(message.error.message);
|
|
140
|
+
if (message.result?.isError) throw new Error(message.result.content?.find((entry) => entry.type === 'text')?.text || 'Recherche BODACC impossible.');
|
|
141
|
+
return message.result?.content || [];
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
function readHistory(content: McpContent[], siren: string): BodaccSearchResult {
|
|
145
|
+
const resourceText = content.find((entry) => entry.type === 'resource')?.resource?.text;
|
|
146
|
+
if (!resourceText) throw new Error('La réponse BODACC ne contient pas de données exploitables.');
|
|
147
|
+
const history = JSON.parse(resourceText) as { siren?: string; total_annonces?: number; alertes?: string[]; categories?: Record<string, Array<Record<string, unknown>>> };
|
|
148
|
+
const annonces = Object.values(history.categories || {}).flat().map((annonce) => ({
|
|
149
|
+
id: String(annonce.id || ''),
|
|
150
|
+
datePublication: String(annonce.date_parution || annonce.date || ''),
|
|
151
|
+
typeAvis: String(annonce.type_avis || annonce.type || ''),
|
|
152
|
+
familleAvis: String(annonce.famille_avis || ''),
|
|
153
|
+
commercant: String(annonce.commercant || ''),
|
|
154
|
+
ville: String(annonce.ville || ''),
|
|
155
|
+
tribunal: String(annonce.tribunal || ''),
|
|
156
|
+
jugement: String(annonce.jugement || ''),
|
|
157
|
+
acte: String(annonce.acte || ''),
|
|
158
|
+
url: String(annonce.url || ''),
|
|
159
|
+
}));
|
|
160
|
+
return { siren: history.siren || siren, total: Number(history.total_annonces || annonces.length), alertes: history.alertes || [], annonces };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function familyCode(announcement: BodaccAnnouncement): string {
|
|
164
|
+
const family = announcement.familleAvis.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLocaleLowerCase();
|
|
165
|
+
if (family.includes('depot') && family.includes('compte')) return 'dpc';
|
|
166
|
+
if (family.includes('modification')) return 'modification';
|
|
167
|
+
if (family.includes('creation')) return 'creation';
|
|
168
|
+
if (family.includes('radiation')) return 'radiation';
|
|
169
|
+
if (family.includes('conciliation')) return 'conciliation';
|
|
170
|
+
if (family.includes('retablissement professionnel')) return 'retablissement_professionnel';
|
|
171
|
+
if (family.includes('procedure') && family.includes('collective')) return 'collective';
|
|
172
|
+
if (family.includes('vente') || family.includes('cession')) return 'vente';
|
|
173
|
+
if (family.includes('immatriculation')) return 'immatriculation';
|
|
174
|
+
if (family.includes('divers')) return 'divers';
|
|
175
|
+
return 'inconnue';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function filterFamilies(result: BodaccSearchResult, requestedFamilies: string[] | null): BodaccSearchResult {
|
|
179
|
+
if (requestedFamilies === null) return result;
|
|
180
|
+
const families = [...new Set(requestedFamilies.filter((family) => BODACC_FAMILY_CODES.has(family)))];
|
|
181
|
+
if (families.length === BODACC_FAMILY_CODES.size) return result;
|
|
182
|
+
const annonces = result.annonces.filter((announcement) => families.includes(familyCode(announcement)));
|
|
183
|
+
return { ...result, total: annonces.length, annonces, alertes: result.alertes.filter((alert) => (alert.toLocaleLowerCase().includes('procedure') && families.includes('collective')) || (alert.toLocaleLowerCase().includes('radiation') && families.includes('radiation'))) };
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
async function searchBodacc(siren: string, siret: string, requestedFamilies: string[] | null): Promise<BodaccSearchResult> {
|
|
187
|
+
const normalized = normalizedSiren(siren, siret);
|
|
188
|
+
const response = await mcpCall('Tracking_BODACC', { siren: normalized, type_recherche: 'historique' });
|
|
189
|
+
return filterFamilies(readHistory(resultContent(response), normalized), requestedFamilies);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export function createBodaccSearchRouter() {
|
|
193
|
+
const router = express.Router();
|
|
194
|
+
router.post('/bodacc-search', async (request: Request, response: Response) => {
|
|
195
|
+
const siren = typeof request.body?.siren === 'string' ? request.body.siren : '';
|
|
196
|
+
const siret = typeof request.body?.siret === 'string' ? request.body.siret : '';
|
|
197
|
+
const families = Array.isArray(request.body?.families) ? request.body.families.filter((family: unknown): family is string => typeof family === 'string') : null;
|
|
198
|
+
try {
|
|
199
|
+
response.json(await searchBodacc(siren, siret, families));
|
|
200
|
+
} catch (error) {
|
|
201
|
+
response.status(502).json({ error: error instanceof Error ? error.message : 'Recherche BODACC impossible.' });
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
return router;
|
|
205
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { parseSearchLine } from './company-search.js';
|
|
5
|
+
|
|
6
|
+
test('company search accepts registry results without a legal form', () => {
|
|
7
|
+
assert.deepEqual(
|
|
8
|
+
parseSearchLine('- GENSIGHT BIOLOGICS | SIREN 751164757 | en activité | NAF 72.19Z | 74 RUE DU FBG ST ANTOINE 75012 PARIS 12'),
|
|
9
|
+
{
|
|
10
|
+
name: 'GENSIGHT BIOLOGICS',
|
|
11
|
+
siren: '751164757',
|
|
12
|
+
summary: 'en activité · NAF 72.19Z · 74 RUE DU FBG ST ANTOINE 75012 PARIS 12',
|
|
13
|
+
},
|
|
14
|
+
);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('company search preserves a legal form in registry results', () => {
|
|
18
|
+
assert.deepEqual(
|
|
19
|
+
parseSearchLine('- GENSIGHT BIOLOGICS (SA) | SIREN 751164757 | en activité | NAF 72.19Z | 74 RUE DU FBG ST ANTOINE 75012 PARIS 12'),
|
|
20
|
+
{
|
|
21
|
+
name: 'GENSIGHT BIOLOGICS',
|
|
22
|
+
siren: '751164757',
|
|
23
|
+
summary: 'SA · en activité · NAF 72.19Z · 74 RUE DU FBG ST ANTOINE 75012 PARIS 12',
|
|
24
|
+
},
|
|
25
|
+
);
|
|
26
|
+
});
|