@piecemaker-legal/piecemaker 2.0.11 → 2.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{FindReplaceDialog-KU5TEIBJ-BucOHLdm.js → FindReplaceDialog-KU5TEIBJ-DiS1F6O4.js} +1 -1
- package/dist/assets/{FootnotePropertiesDialog-W3YHM4BV-D5UqbelV.js → FootnotePropertiesDialog-W3YHM4BV-BMRWztwh.js} +1 -1
- package/dist/assets/{HyperlinkDialog-ZYH7ZHRF-8yEhLigd.js → HyperlinkDialog-ZYH7ZHRF-D5r9CZf2.js} +4 -4
- package/dist/assets/{ImagePositionDialog-HEWYR6Q3-wGIBYxCm.js → ImagePositionDialog-HEWYR6Q3-EeK_GFbX.js} +1 -1
- package/dist/assets/{ImagePropertiesDialog-RAB47C6M-D86PckZ2.js → ImagePropertiesDialog-RAB47C6M-BgrZEZLp.js} +1 -1
- package/dist/assets/{PageSetupDialog-AIGIXO3E-DLETP-7v.js → PageSetupDialog-AIGIXO3E-DdFpkcLH.js} +1 -1
- package/dist/assets/{SplitCellDialog-IFBKYCD6-CwdQBXeb.js → SplitCellDialog-IFBKYCD6-B2J0yPH6.js} +1 -1
- package/dist/assets/{TablePropertiesDialog-TMLKGOOW-j2nA7KJs.js → TablePropertiesDialog-TMLKGOOW-iTyD5Vwt.js} +1 -1
- package/dist/assets/{WatermarkDialog-KRL7WMIS-XFJ9gTkC.js → WatermarkDialog-KRL7WMIS-CdwIWeEi.js} +1 -1
- package/dist/assets/{abnfDiagram-VCTEODGH-DiCrND_Y.js → abnfDiagram-VCTEODGH-CCQgv7yc.js} +1 -1
- package/dist/assets/{arc-DOjgbMYz.js → arc-B-Y10mRQ.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-brzIFVhl.js → architectureDiagram-5GKGNRK7-C-mYZ4DW.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-C8JhTjQQ.js → blockDiagram-I7D4REHJ-Bby14xNO.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-jfYxccyk.js → c4Diagram-7LVT6UL2-CoqTzQi7.js} +1 -1
- package/dist/assets/channel-BxbXkYrr.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-CrlEShp9.js → chunk-2Q5K7J3B-CYlmti0k.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DzPlUHGq.js → chunk-5VM5RSS4-W35KZUQj.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-Cp9cpeWU.js → chunk-F27PBJKO-BVIu5FJA.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-BifUldEN.js → chunk-IMKFNOWR-DRf1mnVb.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-ggPEIkWu.js → chunk-JWPE2WC7-CUJ1N2G9.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-3h_nayRX.js → chunk-POPQ4Y6H-p6IVobio.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-CH29aG6J.js → chunk-SVP7TREG-DOM_pdOM.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-PluJUM5k.js → chunk-TICWLB2K-VqAu84r8.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-DXU39Vwg.js → chunk-XXDRQBXY-vaUsyH7g.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-COu_XNpX.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-COu_XNpX.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-Dz6roYrN.js → cose-bilkent-JH36ORCC-B_sTVfyq.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-BLzrpSit.js → cynefin-OW5HDTMX-DvnWaxw0.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-kfxnERDZ.js → cynefinDiagram-5FMLGOSQ-DriBDRYQ.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-DP57bp-N.js → dagre-GXQ25YYZ-BAwYXMGG.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-DAlsrQVW.js → diagram-S7CK7UJ4-DX03OYpD.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-By5yrMer.js → diagram-UQ7AKVKN-rdUs_hF8.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-Dx89kryN.js → diagram-VSXAHHWV-CobmLXkM.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-B9fARitZ.js → diagram-VX7I27RA-B18D7USE.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-DC15CEH1.js → diagram-Z3DM3KII-CRrNHL6r.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-BKQzghGF.js → ebnfDiagram-PWID7BFC-HXzGHTn6.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-CPY6RM7G.js → erDiagram-RLTQ6QDP-lbfD5sxC.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-4dL4GJcf.js → flowDiagram-HODETNUW-Dd0lb1Fm.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-D4-cVcfb.js → ganttDiagram-EL5Y4UJY-CKBO9TRh.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-BMeVIEiX.js → gitGraphDiagram-WWUBYQGX-Ds_AlKrJ.js} +1 -1
- package/dist/assets/index-C5slQNvE.css +1 -0
- package/dist/assets/{index-DNtFDOni.js → index-C9XXF765.js} +146 -146
- package/dist/assets/{infoDiagram-27XIBGKW-D5qMSUEU.js → infoDiagram-27XIBGKW-BbNgbn6W.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-BDnyKRHm.js → ishikawaDiagram-5VMMS53U-B9FZGWPM.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-dGz5ZGzq.js → journeyDiagram-3NMN7TZE-9z26Mgkz.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-D7UAz7o_.js → kanban-definition-UXKFOSKX-dQoIQkFu.js} +1 -1
- package/dist/assets/{layout-DKrmEGrz.js → layout-C03dZv1L.js} +1 -1
- package/dist/assets/{linear-CrTdMY-p.js → linear-BAgwn459.js} +1 -1
- package/dist/assets/{mermaid.core-CXQOT5G6.js → mermaid.core-Bb-zdGYl.js} +6 -6
- package/dist/assets/{mindmap-definition-YA3MSWOX-VgEiYfay.js → mindmap-definition-YA3MSWOX-BZ77-g1t.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-9IqT8gGx.js → pegDiagram-XKGWAZYB-vlBCwMpy.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-D98pRE-t.js → pieDiagram-E7YTZNPT-DGaLzhN2.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-b9PwkYzL.js → quadrantDiagram-AXDQQJYC-J517wJ3s.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-Dz87hsPE.js → railroadDiagram-O6MQD6OU-MiMqTB2q.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-CkcV73dK.js → requirementDiagram-BXWQKSXE-ClFWrfsX.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-UBN31Yrs.js → sankeyDiagram-P5KCCOFB-BQjzvuzZ.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-CpQxd5Za.js → sequenceDiagram-WJ2MYXX4-BVI9Mtfy.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-mCsFmyzw.js → sizeCapture-INFHLROL-npWe2anw.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-B0MTBN-3.js → stateDiagram-D77RDMKH-BE4pwhgm.js} +1 -1
- package/dist/assets/{stateDiagram-v2-MP3YSRHH-DzBPN39W.js → stateDiagram-v2-MP3YSRHH-PdR5r-x_.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-Dzydjm0e.js → swimlanes-42K2YHIH-DJMuv4Fv.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-Cxv8b9_h.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-Dz0toOLu.js → timeline-definition-24CTP7MA-BLHKdXUW.js} +1 -1
- package/dist/assets/{vennDiagram-4TSXK5OY-DOWp7dkf.js → vennDiagram-4TSXK5OY-vpWJbaKf.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-CUxsztUB.js → wardleyDiagram-VM6X3IG4-BC1q3_Z5.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-DS96vNED.js → xychartDiagram-S5SC5T6Z--yDqjI6l.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js +61 -1
- package/dist-server/plugins/piecemaker-dossier/src/knowledge.js.map +1 -1
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js +0 -48
- package/dist-server/plugins/piecemaker-dossier/src/scan-result.js.map +1 -1
- package/dist-server/server/piecemaker/desktop-update/service.js +2 -1
- package/dist-server/server/piecemaker/desktop-update/service.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/pipeline.js +25 -29
- package/dist-server/server/piecemaker/knowledge/pipeline.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/service.js +1 -16
- package/dist-server/server/piecemaker/knowledge/service.js.map +1 -1
- package/dist-server/server/piecemaker/project-registry.js +5 -5
- package/dist-server/server/piecemaker/project-registry.js.map +1 -1
- package/package.json +1 -1
- package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +1 -1
- package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +2 -1
- package/server/piecemaker/anonymizer/rewrite.cjs +2 -2
- package/server/piecemaker/anonymizer/service.cjs +3 -2
- package/server/piecemaker/anonymizer/sqlite-dictionary.cjs +3 -31
- package/server/piecemaker/desktop-update/service.ts +2 -1
- package/server/piecemaker/index.ts +1 -1
- package/server/piecemaker/knowledge/pipeline.ts +24 -31
- package/server/piecemaker/knowledge/service.ts +1 -14
- package/server/piecemaker/project-registry.ts +6 -6
- package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +9 -162
- package/server/piecemaker/vendor/installer/lib/commandes.mjs +1 -2
- package/server/piecemaker/vendor/installer/lib/conversion-client.mjs +62 -3
- package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +23 -69
- package/server/piecemaker/vendor/installer/steps/12-mcp-piecemaker.mjs +3 -3
- package/server/piecemaker/vendor/mcp/README.md +1 -1
- package/server/piecemaker/vendor/mcp/piecemaker/server.mjs +12 -75
- package/server/piecemaker/vendor/piecemaker-plugin/hooks/hooks.json +0 -40
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +2 -2
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +26 -7
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs +0 -28
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/hook-io.mjs +0 -13
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs +3 -3
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +10 -143
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +1 -1
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs +0 -65
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +11 -2
- package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +9 -5
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +2 -150
- package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +3 -0
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +23 -372
- package/server/piecemaker/vendor/websocket-server/renamed-originals.cjs +136 -0
- package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +115 -96
- package/dist/assets/channel-Dajzu2W1.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-dDEP_giv.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-dDEP_giv.js +0 -1
- package/dist/assets/index-Dc9wNuS4.css +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-BXQpbUMD.js +0 -8
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +0 -194
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +0 -71
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit-worker.mjs +0 -260
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit.mjs +0 -83
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* Serveur MCP « piecemaker » —
|
|
3
|
+
* Serveur MCP « piecemaker » — outil de conversion exposé
|
|
4
4
|
* à Claude Code (et à tout client MCP) sans passer
|
|
5
5
|
* par du texte injecté dans un CLAUDE.md.
|
|
6
6
|
*
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* d'arguments, même localisation de dossier, une seule implémentation
|
|
11
11
|
* (voir `installer/bin/piecemaker.mjs`).
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* La commande lancée ici (`conversion --json`) court-circuite le bandeau, la
|
|
14
|
+
* vérification de mise à jour et le menu interactif. Elle confie le travail au
|
|
15
|
+
* serveur applicatif déjà lancé (application de bureau ou `piecemaker`) et ne
|
|
16
|
+
* démarre un serveur que si aucun ne répond.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
19
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
@@ -95,28 +95,6 @@ export function conversionArgs({ dossier, pieces, force }) {
|
|
|
95
95
|
return args;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
export function chronologyArgs({ dossier }) {
|
|
99
|
-
return ['chronology', '--json', '--case', dossier];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
export function chronologyCorrectionArgs(action, { dossier, path: piecePath, nature, dateIso, localisation, fields, entityAdditions, entityExclusions, reason }) {
|
|
103
|
-
const correction = {};
|
|
104
|
-
if (nature !== undefined) correction.nature = nature;
|
|
105
|
-
if (dateIso !== undefined) correction.dateIso = dateIso;
|
|
106
|
-
if (localisation !== undefined) correction.localisation = localisation;
|
|
107
|
-
if (fields !== undefined) correction.fields = fields;
|
|
108
|
-
if (reason !== undefined) correction.reason = reason;
|
|
109
|
-
if (entityAdditions !== undefined || entityExclusions !== undefined) {
|
|
110
|
-
correction.entityDecisions = {
|
|
111
|
-
additions: entityAdditions || [],
|
|
112
|
-
exclusions: entityExclusions || [],
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
const args = ['chronology', '--action', action, '--path', piecePath, '--correction-json', JSON.stringify(correction), '--json'];
|
|
116
|
-
if (dossier) args.push('--case', dossier);
|
|
117
|
-
return args;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
98
|
/** Dossier ciblé par un appel d'outil : celui demandé, sinon la session en cours. */
|
|
121
99
|
export function resolveDossier(dossier) {
|
|
122
100
|
return dossier && String(dossier).trim() ? dossier : process.cwd();
|
|
@@ -126,21 +104,6 @@ const DOSSIER_SCHEMA = z.string()
|
|
|
126
104
|
.optional()
|
|
127
105
|
.describe('Chemin absolu du dossier juridique ciblé. Par défaut, le répertoire de la session Claude Code en cours.');
|
|
128
106
|
|
|
129
|
-
const CHRONOLOGY_CORRECTION_SCHEMA = {
|
|
130
|
-
dossier: DOSSIER_SCHEMA,
|
|
131
|
-
path: z.string().min(1).describe('Chemin relatif de la pièce, tel qu\'indexé par la chronologie.'),
|
|
132
|
-
nature: z.string().optional().describe('Nature de l\'acte (ex. « Assignation », « Conclusions »).'),
|
|
133
|
-
dateIso: z.string().optional().describe('Date de la pièce au format ISO 8601 (AAAA-MM-JJ).'),
|
|
134
|
-
localisation: z.string().optional().describe('Juridiction ou localisation associée à la pièce.'),
|
|
135
|
-
fields: z.array(z.object({ label: z.string(), value: z.string() })).optional()
|
|
136
|
-
.describe('Champs personnalisés additionnels de la pièce.'),
|
|
137
|
-
entityAdditions: z.array(z.string()).optional()
|
|
138
|
-
.describe('Codes d\'entités (personnes/sociétés pseudonymisées) à rattacher manuellement à la pièce.'),
|
|
139
|
-
entityExclusions: z.array(z.string()).optional()
|
|
140
|
-
.describe('Codes d\'entités détectés automatiquement à exclure manuellement de la pièce.'),
|
|
141
|
-
reason: z.string().optional().describe('Motif de la correction, consigné dans l\'historique du dossier.'),
|
|
142
|
-
};
|
|
143
|
-
|
|
144
107
|
/**
|
|
145
108
|
* Construit le serveur MCP et y enregistre les outils. Séparé de
|
|
146
109
|
* `main()` pour rester testable sans jamais brancher de transport stdio.
|
|
@@ -160,45 +123,19 @@ export function createServer({ execFn } = {}) {
|
|
|
160
123
|
.describe('Noms ou chemins relatifs des pièces à convertir. Par défaut, toutes les pièces pas encore prêtes.'),
|
|
161
124
|
force: z.boolean().optional().describe('Reconvertit et rescanne même les pièces déjà prêtes.'),
|
|
162
125
|
},
|
|
126
|
+
annotations: {
|
|
127
|
+
title: 'Conversion et pseudonymisation des pièces',
|
|
128
|
+
readOnlyHint: false,
|
|
129
|
+
destructiveHint: false,
|
|
130
|
+
idempotentHint: true,
|
|
131
|
+
openWorldHint: false,
|
|
132
|
+
},
|
|
163
133
|
}, async ({ dossier, pieces, force }) => {
|
|
164
134
|
const resolved = resolveDossier(dossier);
|
|
165
135
|
const result = await run(conversionArgs({ dossier: resolved, pieces, force }), resolved);
|
|
166
136
|
return toToolResult(result);
|
|
167
137
|
});
|
|
168
138
|
|
|
169
|
-
server.registerTool('chronologie', {
|
|
170
|
-
description: 'Affiche la chronologie pseudonymisée du dossier juridique (dates, pièces, événements), en JSON.',
|
|
171
|
-
inputSchema: {
|
|
172
|
-
dossier: DOSSIER_SCHEMA,
|
|
173
|
-
},
|
|
174
|
-
}, async ({ dossier }) => {
|
|
175
|
-
const resolved = resolveDossier(dossier);
|
|
176
|
-
const result = await run(chronologyArgs({ dossier: resolved }), resolved);
|
|
177
|
-
return toToolResult(result);
|
|
178
|
-
});
|
|
179
|
-
|
|
180
|
-
server.registerTool('write_chronology', {
|
|
181
|
-
description: 'Crée une correction manuelle de chronologie pour une pièce (date, nature d\'acte, '
|
|
182
|
-
+ 'localisation, personnes citées, champs custom). Échoue si une correction existe déjà pour cette '
|
|
183
|
-
+ 'pièce — utiliser edit_chronology pour la modifier.',
|
|
184
|
-
inputSchema: CHRONOLOGY_CORRECTION_SCHEMA,
|
|
185
|
-
}, async ({ dossier, ...params }) => {
|
|
186
|
-
const resolved = resolveDossier(dossier);
|
|
187
|
-
const result = await run(chronologyCorrectionArgs('write', { dossier: resolved, ...params }), resolved);
|
|
188
|
-
return toToolResult(result);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
server.registerTool('edit_chronology', {
|
|
192
|
-
description: 'Modifie la correction manuelle de chronologie déjà enregistrée pour une pièce (date, '
|
|
193
|
-
+ 'nature d\'acte, localisation, personnes citées, champs custom). Échoue si aucune correction '
|
|
194
|
-
+ 'n\'existe pour cette pièce — utiliser write_chronology pour en créer une.',
|
|
195
|
-
inputSchema: CHRONOLOGY_CORRECTION_SCHEMA,
|
|
196
|
-
}, async ({ dossier, ...params }) => {
|
|
197
|
-
const resolved = resolveDossier(dossier);
|
|
198
|
-
const result = await run(chronologyCorrectionArgs('edit', { dossier: resolved, ...params }), resolved);
|
|
199
|
-
return toToolResult(result);
|
|
200
|
-
});
|
|
201
|
-
|
|
202
139
|
return server;
|
|
203
140
|
}
|
|
204
141
|
|
|
@@ -21,15 +21,6 @@
|
|
|
21
21
|
}
|
|
22
22
|
]
|
|
23
23
|
},
|
|
24
|
-
{
|
|
25
|
-
"matcher": "Write|Edit",
|
|
26
|
-
"hooks": [
|
|
27
|
-
{
|
|
28
|
-
"type": "command",
|
|
29
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/commit-track.mjs\""
|
|
30
|
-
}
|
|
31
|
-
]
|
|
32
|
-
},
|
|
33
24
|
{
|
|
34
25
|
"matcher": "Write",
|
|
35
26
|
"hooks": [
|
|
@@ -48,37 +39,6 @@
|
|
|
48
39
|
}
|
|
49
40
|
]
|
|
50
41
|
}
|
|
51
|
-
],
|
|
52
|
-
"Stop": [
|
|
53
|
-
{
|
|
54
|
-
"matcher": "*",
|
|
55
|
-
"hooks": [
|
|
56
|
-
{
|
|
57
|
-
"type": "command",
|
|
58
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/billing-track.mjs\""
|
|
59
|
-
}
|
|
60
|
-
]
|
|
61
|
-
},
|
|
62
|
-
{
|
|
63
|
-
"matcher": "*",
|
|
64
|
-
"hooks": [
|
|
65
|
-
{
|
|
66
|
-
"type": "command",
|
|
67
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/session-commit.mjs\""
|
|
68
|
-
}
|
|
69
|
-
]
|
|
70
|
-
}
|
|
71
|
-
],
|
|
72
|
-
"TaskCompleted": [
|
|
73
|
-
{
|
|
74
|
-
"matcher": "*",
|
|
75
|
-
"hooks": [
|
|
76
|
-
{
|
|
77
|
-
"type": "command",
|
|
78
|
-
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/billing-track.mjs\""
|
|
79
|
-
}
|
|
80
|
-
]
|
|
81
|
-
}
|
|
82
42
|
]
|
|
83
43
|
}
|
|
84
44
|
}
|
|
@@ -72,8 +72,8 @@ async function main() {
|
|
|
72
72
|
const pdfPath = path.join(rechercheDir, `${slug}.pdf`);
|
|
73
73
|
|
|
74
74
|
// Le modèle n'a vu que des codes ; l'historique du cabinet doit rester
|
|
75
|
-
// lisible → on ré-identifie le Markdown final avant écriture disque
|
|
76
|
-
//
|
|
75
|
+
// lisible → on ré-identifie le Markdown final avant écriture disque.
|
|
76
|
+
// Idempotent.
|
|
77
77
|
let markdown = renderMarkdown(data, { caseName: located.caseName });
|
|
78
78
|
const legalCase = resolveProjectCaseMapping(located.caseRoot);
|
|
79
79
|
if (legalCase?.reverse_mapping) markdown = revertMapping(markdown, legalCase.reverse_mapping);
|
|
@@ -4,6 +4,7 @@ const os = require('node:os');
|
|
|
4
4
|
const path = require('node:path');
|
|
5
5
|
|
|
6
6
|
const PROJECTS_FILE = 'projects.json';
|
|
7
|
+
const ANONYMIZED_PROJECTS_FILE = 'anonymized-projects.json';
|
|
7
8
|
|
|
8
9
|
function piecemakerHome() {
|
|
9
10
|
return process.env.PIECEMAKER_HOME || path.join(os.homedir(), '.piecemaker');
|
|
@@ -13,6 +14,10 @@ function projectsFile() {
|
|
|
13
14
|
return path.join(piecemakerHome(), PROJECTS_FILE);
|
|
14
15
|
}
|
|
15
16
|
|
|
17
|
+
function anonymizedProjectsFile() {
|
|
18
|
+
return path.join(piecemakerHome(), ANONYMIZED_PROJECTS_FILE);
|
|
19
|
+
}
|
|
20
|
+
|
|
16
21
|
function realDirectory(value) {
|
|
17
22
|
const requested = String(value || '').trim();
|
|
18
23
|
if (!requested || !path.isAbsolute(requested)) return null;
|
|
@@ -41,24 +46,31 @@ function isEligibleProjectFolder(folder) {
|
|
|
41
46
|
return !excludedRoots().some((root) => isInsideOrEqualPath(root, folder));
|
|
42
47
|
}
|
|
43
48
|
|
|
44
|
-
function
|
|
49
|
+
function readSources(file) {
|
|
45
50
|
try {
|
|
46
|
-
const parsed = JSON.parse(fs.readFileSync(
|
|
51
|
+
const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
47
52
|
return parsed?.sources && typeof parsed.sources === 'object' && !Array.isArray(parsed.sources) ? parsed.sources : {};
|
|
48
53
|
} catch {
|
|
49
54
|
return {};
|
|
50
55
|
}
|
|
51
56
|
}
|
|
52
57
|
|
|
58
|
+
function publishedFolders(file) {
|
|
59
|
+
const folders = Object.values(readSources(file)).flatMap((list) => (Array.isArray(list) ? list : []));
|
|
60
|
+
return [...new Set(folders.map(realDirectory).filter(Boolean))].filter(isEligibleProjectFolder);
|
|
61
|
+
}
|
|
62
|
+
|
|
53
63
|
/** Absolute, existing and de-duplicated project folders, across every publishing server. */
|
|
54
64
|
function registeredProjectFolders() {
|
|
55
|
-
|
|
56
|
-
|
|
65
|
+
return publishedFolders(projectsFile());
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function anonymizedProjectFolders() {
|
|
69
|
+
return publishedFolders(anonymizedProjectsFile());
|
|
57
70
|
}
|
|
58
71
|
|
|
59
|
-
function
|
|
60
|
-
const
|
|
61
|
-
const sources = readProjectSources();
|
|
72
|
+
function writeSource(file, sourceId, folders) {
|
|
73
|
+
const sources = readSources(file);
|
|
62
74
|
if (folders === null) delete sources[sourceId];
|
|
63
75
|
else sources[sourceId] = [...new Set(folders.map((folder) => path.resolve(String(folder))))].sort();
|
|
64
76
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
@@ -72,6 +84,11 @@ function publishProjectSource(sourceId, folders) {
|
|
|
72
84
|
}
|
|
73
85
|
}
|
|
74
86
|
|
|
87
|
+
function publishProjectSource(sourceId, folders, anonymizedFolders = []) {
|
|
88
|
+
writeSource(projectsFile(), sourceId, folders);
|
|
89
|
+
writeSource(anonymizedProjectsFile(), sourceId, folders === null ? null : anonymizedFolders);
|
|
90
|
+
}
|
|
91
|
+
|
|
75
92
|
function resolveTarget(target) {
|
|
76
93
|
try {
|
|
77
94
|
return fs.realpathSync(path.resolve(String(target)));
|
|
@@ -101,6 +118,7 @@ function locateProjectCase(target) {
|
|
|
101
118
|
for (const caseRoot of roots) {
|
|
102
119
|
if (!isInsideOrEqualPath(caseRoot, absolute)) continue;
|
|
103
120
|
return {
|
|
121
|
+
anonymized: anonymizedProjectFolders().includes(caseRoot),
|
|
104
122
|
casesRoot: path.dirname(caseRoot),
|
|
105
123
|
caseName: path.basename(caseRoot),
|
|
106
124
|
caseRoot,
|
|
@@ -113,6 +131,7 @@ function locateProjectCase(target) {
|
|
|
113
131
|
}
|
|
114
132
|
|
|
115
133
|
module.exports = {
|
|
134
|
+
anonymizedProjectFolders,
|
|
116
135
|
locateProjectCase,
|
|
117
136
|
publishProjectSource,
|
|
118
137
|
registeredProjectFolders,
|
|
@@ -564,33 +564,6 @@ function resolveCase(casesRoot, caseName) {
|
|
|
564
564
|
return { casesRoot: root, name, root: caseRoot };
|
|
565
565
|
}
|
|
566
566
|
|
|
567
|
-
function locateCaseFile(casesRoot, filePath) {
|
|
568
|
-
const root = resolveCasesRoot(casesRoot);
|
|
569
|
-
const requested = path.resolve(String(filePath || ''));
|
|
570
|
-
let absolute = requested;
|
|
571
|
-
try {
|
|
572
|
-
absolute = fs.realpathSync(requested);
|
|
573
|
-
} catch {
|
|
574
|
-
try {
|
|
575
|
-
absolute = path.join(fs.realpathSync(path.dirname(requested)), path.basename(requested));
|
|
576
|
-
} catch {}
|
|
577
|
-
}
|
|
578
|
-
if (absolute === root || !absolute.startsWith(`${root}${path.sep}`)) return null;
|
|
579
|
-
const relativeToRoot = path.relative(root, absolute);
|
|
580
|
-
const [caseName, ...parts] = relativeToRoot.split(path.sep);
|
|
581
|
-
if (!caseName || parts.length === 0) return null;
|
|
582
|
-
const legalCase = resolveCase(root, caseName);
|
|
583
|
-
if (isProtectedFile(absolute, legalCase.root)) {
|
|
584
|
-
return { ...legalCase, absolute, protected: true, relative: parts.join('/') };
|
|
585
|
-
}
|
|
586
|
-
if (path.extname(absolute).toLowerCase() && !SAFE_EXTENSIONS.has(path.extname(absolute).toLowerCase())) {
|
|
587
|
-
return { ...legalCase, absolute, protected: false, safe: false, relative: parts.join('/') };
|
|
588
|
-
}
|
|
589
|
-
const relative = path.relative(legalCase.root, absolute).split(path.sep).join('/');
|
|
590
|
-
if (!relative || relative.startsWith('../')) return null;
|
|
591
|
-
return { ...legalCase, absolute, protected: false, safe: SAFE_EXTENSIONS.has(path.extname(relative).toLowerCase()), relative };
|
|
592
|
-
}
|
|
593
|
-
|
|
594
567
|
async function safeCaseFiles(caseRoot) {
|
|
595
568
|
const startedAt = performance.now();
|
|
596
569
|
const root = await fsp.realpath(caseRoot);
|
|
@@ -1668,7 +1641,6 @@ module.exports = {
|
|
|
1668
1641
|
logPerformance,
|
|
1669
1642
|
listHistory,
|
|
1670
1643
|
listHistoryPeriod,
|
|
1671
|
-
locateCaseFile,
|
|
1672
1644
|
parseCommitTrailers,
|
|
1673
1645
|
originalFilesOverview,
|
|
1674
1646
|
repositoryOverview,
|
|
@@ -25,8 +25,6 @@ import path from 'node:path';
|
|
|
25
25
|
|
|
26
26
|
export const HOME_DIR = path.join(os.homedir(), '.piecemaker');
|
|
27
27
|
export const CONFIG_FILE = path.join(HOME_DIR, 'config.json');
|
|
28
|
-
export const BILLING_DIR = path.join(HOME_DIR, 'billing');
|
|
29
|
-
export const SYNTHESIS_DIR = path.join(BILLING_DIR, 'synthese');
|
|
30
28
|
|
|
31
29
|
/** Upper bound on waiting for stdout to drain before exiting anyway. */
|
|
32
30
|
const FLUSH_TIMEOUT_MS = 2000;
|
|
@@ -236,14 +234,3 @@ export function ensureDirSafe(dir) {
|
|
|
236
234
|
return false;
|
|
237
235
|
}
|
|
238
236
|
}
|
|
239
|
-
|
|
240
|
-
/** Append one line to a JSONL file. Single appendFileSync call, never throws. */
|
|
241
|
-
export function appendJsonl(filePath, obj) {
|
|
242
|
-
try {
|
|
243
|
-
ensureDirSafe(path.dirname(filePath));
|
|
244
|
-
fs.appendFileSync(filePath, `${JSON.stringify(obj)}\n`, 'utf8');
|
|
245
|
-
return true;
|
|
246
|
-
} catch {
|
|
247
|
-
return false;
|
|
248
|
-
}
|
|
249
|
-
}
|
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
*
|
|
10
10
|
* On ne débranche pas la détection : GLiNER continue de les trouver. C'est au
|
|
11
11
|
* moment de bâtir le mapping qu'elles sont écartées — `normalizeMappingDocument`
|
|
12
|
-
* (mapping.cjs) appelle `isInstitutionalEntity` sur chaque
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* (mapping.cjs) appelle `isInstitutionalEntity` sur chaque entité lue, et le
|
|
13
|
+
* magasin du dossier les retire de la base. Une entité bannie n'est donc jamais
|
|
14
|
+
* substituée par les hooks.
|
|
15
15
|
*
|
|
16
16
|
* La liste est globale (tous dossiers confondus), éditable depuis les paramètres
|
|
17
17
|
* de l'administration, et la comparaison est insensible à la casse et aux
|
|
@@ -47,8 +47,7 @@ function readJsonFile(file, fallback = null) {
|
|
|
47
47
|
* Tous les mappings présents, sous-dossier `WORKSPACE_SUBDIR` **et** racine
|
|
48
48
|
* (lecture tolérante pendant la migration). Le fichier canonique du sous-dossier
|
|
49
49
|
* passe en dernier : c'est lui qui gagne quand `readCaseMapping` fusionne, tandis
|
|
50
|
-
* que les copies legacy (racine ou `mapping_<id>.json`)
|
|
51
|
-
* perdre avant le prochain enregistrement.
|
|
50
|
+
* que les copies legacy (racine ou `mapping_<id>.json`) complètent la lecture.
|
|
52
51
|
*/
|
|
53
52
|
function existingMappingFiles(caseRoot) {
|
|
54
53
|
const dirs = [
|
|
@@ -80,113 +79,27 @@ function existingMappingFiles(caseRoot) {
|
|
|
80
79
|
}
|
|
81
80
|
|
|
82
81
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
* `mapping_dossier.json` / `mapping_<id>.json` et un `mapping_default.json` resté
|
|
86
|
-
* à la racine sont lus pour migration (voir `existingMappingFiles`), mais toute
|
|
87
|
-
* écriture converge vers `<dossier>/<WORKSPACE_SUBDIR>/mapping_default.json`.
|
|
82
|
+
* Emplacement historique du mapping JSON d'un dossier, lu seulement : plus
|
|
83
|
+
* aucun code ne l'écrit, le mapping vit en base.
|
|
88
84
|
*/
|
|
89
85
|
function caseMappingFile(caseRoot) {
|
|
90
86
|
return path.join(caseRoot, WORKSPACE_SUBDIR, CANONICAL_MAPPING_FILE);
|
|
91
87
|
}
|
|
92
88
|
|
|
93
|
-
function cleanMappingString(value) {
|
|
94
|
-
return String(value || '').trim();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
function normalizePartyAssignments(value) {
|
|
98
|
-
if (!Array.isArray(value)) return [];
|
|
99
|
-
return value.map((raw) => {
|
|
100
|
-
const assignment = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
101
|
-
const variants = [...new Set((Array.isArray(assignment.variants) ? assignment.variants : [])
|
|
102
|
-
.map(cleanMappingString).filter(Boolean))];
|
|
103
|
-
return {
|
|
104
|
-
field: cleanMappingString(assignment.field),
|
|
105
|
-
code: cleanMappingString(assignment.code),
|
|
106
|
-
original_code: cleanMappingString(assignment.original_code),
|
|
107
|
-
category: cleanMappingString(assignment.category),
|
|
108
|
-
principal: cleanMappingString(assignment.principal),
|
|
109
|
-
variants,
|
|
110
|
-
};
|
|
111
|
-
}).filter((assignment) => assignment.code && assignment.variants.length);
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function normalizeProcedureParty(raw, side) {
|
|
115
|
-
const party = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
116
|
-
const type = party.type === 'societe' ? 'societe' : 'personne_physique';
|
|
117
|
-
const allowedPositions = new Set(['demandeur', 'defendeur', 'appelant', 'intime', 'requerant', 'mis_en_cause', 'intervenant', 'autre']);
|
|
118
|
-
const position = allowedPositions.has(party.position) ? party.position : side === 'client' ? 'demandeur' : 'defendeur';
|
|
119
|
-
return {
|
|
120
|
-
type,
|
|
121
|
-
position,
|
|
122
|
-
position_libelle: position === 'autre' ? cleanMappingString(party.position_libelle) : '',
|
|
123
|
-
civilite: type === 'personne_physique' ? cleanMappingString(party.civilite) : '',
|
|
124
|
-
nom: type === 'personne_physique' ? cleanMappingString(party.nom) : '',
|
|
125
|
-
date_naissance: type === 'personne_physique' ? cleanMappingString(party.date_naissance) : '',
|
|
126
|
-
lieu_naissance: type === 'personne_physique' ? cleanMappingString(party.lieu_naissance) : '',
|
|
127
|
-
adresse: type === 'personne_physique' ? cleanMappingString(party.adresse) : '',
|
|
128
|
-
societe_nom: type === 'societe' ? cleanMappingString(party.societe_nom) : '',
|
|
129
|
-
forme_sociale: type === 'societe' ? cleanMappingString(party.forme_sociale) : '',
|
|
130
|
-
pays: type === 'societe' ? cleanMappingString(party.pays) || 'France' : '',
|
|
131
|
-
siren: type === 'societe' ? cleanMappingString(party.siren) : '',
|
|
132
|
-
siege_social: type === 'societe' ? cleanMappingString(party.siege_social) : '',
|
|
133
|
-
representant: type === 'societe' ? cleanMappingString(party.representant) : '',
|
|
134
|
-
mapping_assignments: normalizePartyAssignments(party.mapping_assignments),
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
function relationshipId(source, target, role) {
|
|
139
|
-
return `relation:${source}\u0000${target}\u0000${role}`;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
function normalizeProfileRelationships(value) {
|
|
143
|
-
if (!Array.isArray(value)) return [];
|
|
144
|
-
const ids = new Set();
|
|
145
|
-
const relationships = new Set();
|
|
146
|
-
return value.flatMap((raw) => {
|
|
147
|
-
const relationship = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
148
|
-
const source = cleanMappingString(relationship.source);
|
|
149
|
-
const original_source = cleanMappingString(relationship.original_source);
|
|
150
|
-
const target = cleanMappingString(relationship.target);
|
|
151
|
-
const role = cleanMappingString(relationship.role);
|
|
152
|
-
const id = cleanMappingString(relationship.id) || relationshipId(source, target, role);
|
|
153
|
-
const key = `${source}\u0000${target}\u0000${role}`;
|
|
154
|
-
if (!source || !target || !role || source === target || ids.has(id) || relationships.has(key)) return [];
|
|
155
|
-
ids.add(id);
|
|
156
|
-
relationships.add(key);
|
|
157
|
-
return [{ id, source, original_source, target, role }];
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
function normalizeProcedureInfo(raw) {
|
|
162
|
-
const info = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
163
|
-
return {
|
|
164
|
-
parties_clientes: (Array.isArray(info.parties_clientes) ? info.parties_clientes : [])
|
|
165
|
-
.map((party) => normalizeProcedureParty(party, 'client')),
|
|
166
|
-
parties_adverses: (Array.isArray(info.parties_adverses) ? info.parties_adverses : [])
|
|
167
|
-
.map((party) => normalizeProcedureParty(party, 'adversaire')),
|
|
168
|
-
relations: normalizeProfileRelationships(info.relations),
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
89
|
function normalizeMappingDocument(raw) {
|
|
173
90
|
const document = raw && typeof raw === 'object' && !Array.isArray(raw) ? raw : {};
|
|
174
91
|
const mapping = {};
|
|
175
92
|
const reverse = {};
|
|
176
93
|
const source = document.mapping && typeof document.mapping === 'object' ? document.mapping : {};
|
|
177
94
|
// Les entités institutionnelles (juridictions, registres, publications
|
|
178
|
-
// officielles…) sont écartées ici même
|
|
179
|
-
//
|
|
180
|
-
//
|
|
181
|
-
// continue de les détecter — on ne débranche que le codage.
|
|
95
|
+
// officielles…) sont écartées ici même, à la lecture : une entité bannie n'est
|
|
96
|
+
// jamais substituée par les hooks. GLiNER continue de les détecter — on ne
|
|
97
|
+
// débranche que le codage.
|
|
182
98
|
for (const [entity, code] of Object.entries(source)) {
|
|
183
99
|
const from = String(entity || '').trim();
|
|
184
100
|
const to = String(code || '').trim();
|
|
185
101
|
if (from && to && !isInstitutionalEntity(from)) mapping[from] = to;
|
|
186
102
|
}
|
|
187
|
-
const ignored = [...new Set((Array.isArray(document.ignored) ? document.ignored : [])
|
|
188
|
-
.map((entity) => String(entity || '').trim())
|
|
189
|
-
.filter(Boolean))];
|
|
190
103
|
const reverseSource = document.reverse_mapping && typeof document.reverse_mapping === 'object' ? document.reverse_mapping : {};
|
|
191
104
|
for (const [code, value] of Object.entries(reverseSource)) {
|
|
192
105
|
const key = String(code || '').trim();
|
|
@@ -202,36 +115,10 @@ function normalizeMappingDocument(raw) {
|
|
|
202
115
|
if (!reverse[code]) reverse[code] = [entity];
|
|
203
116
|
else if (!reverse[code].includes(entity)) reverse[code].push(entity);
|
|
204
117
|
}
|
|
205
|
-
|
|
206
|
-
// qui porte les variants d'une entité et l'analyse des adresses, dont la
|
|
207
|
-
// dé-anonymisation partielle a besoin (anonymization-server.cjs).
|
|
208
|
-
// L'administration ne l'édite pas, mais elle ne doit surtout pas le détruire —
|
|
209
|
-
// seules les entrées dont le code a disparu du mapping sont retirées.
|
|
210
|
-
const extracted = {};
|
|
211
|
-
const extractedSource = document.extracted_data && typeof document.extracted_data === 'object'
|
|
212
|
-
&& !Array.isArray(document.extracted_data) ? document.extracted_data : {};
|
|
213
|
-
for (const [category, codes] of Object.entries(extractedSource)) {
|
|
214
|
-
if (!codes || typeof codes !== 'object' || Array.isArray(codes)) continue;
|
|
215
|
-
extracted[category] = Object.fromEntries(
|
|
216
|
-
Object.entries(codes).filter(([code]) => reverse[code])
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
return {
|
|
220
|
-
mapping,
|
|
221
|
-
reverse_mapping: reverse,
|
|
222
|
-
extracted_data: extracted,
|
|
223
|
-
ignored: ignored.filter((entity) => !mapping[entity]),
|
|
224
|
-
informations_dossier: normalizeProcedureInfo(document.informations_dossier),
|
|
225
|
-
};
|
|
118
|
+
return { mapping, reverse_mapping: reverse };
|
|
226
119
|
}
|
|
227
120
|
|
|
228
121
|
/** L'ordre d'écriture suit `byDescendingEntityLength`. */
|
|
229
|
-
function sortedMapping(mapping) {
|
|
230
|
-
return Object.fromEntries(
|
|
231
|
-
Object.entries(mapping).sort((a, b) => b[0].length - a[0].length || a[0].localeCompare(b[0], 'fr'))
|
|
232
|
-
);
|
|
233
|
-
}
|
|
234
|
-
|
|
235
122
|
function readCaseMapping(caseRoot) {
|
|
236
123
|
const file = caseMappingFile(caseRoot);
|
|
237
124
|
const sourceFiles = existingMappingFiles(caseRoot);
|
|
@@ -239,15 +126,10 @@ function readCaseMapping(caseRoot) {
|
|
|
239
126
|
return { file, sourceFiles: [], exists: false, ...normalizeMappingDocument(null) };
|
|
240
127
|
}
|
|
241
128
|
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
// entité a été recodée. Le prochain enregistrement écrira l'ensemble dans le
|
|
245
|
-
// seul `mapping_default.json`.
|
|
129
|
+
// Tous les anciens mappings sont réunis en mémoire. Le canonique passe en
|
|
130
|
+
// dernier et gagne donc si une même entité a été recodée.
|
|
246
131
|
const mapping = {};
|
|
247
132
|
const preferredVariants = {};
|
|
248
|
-
const extracted_data = {};
|
|
249
|
-
const ignored = [];
|
|
250
|
-
let informations_dossier = normalizeProcedureInfo();
|
|
251
133
|
const readableFiles = [];
|
|
252
134
|
for (const sourceFile of sourceFiles) {
|
|
253
135
|
const raw = readJsonFile(sourceFile, null);
|
|
@@ -255,18 +137,9 @@ function readCaseMapping(caseRoot) {
|
|
|
255
137
|
readableFiles.push(sourceFile);
|
|
256
138
|
const document = normalizeMappingDocument(raw);
|
|
257
139
|
Object.assign(mapping, document.mapping);
|
|
258
|
-
ignored.push(...document.ignored);
|
|
259
140
|
for (const [code, variants] of Object.entries(document.reverse_mapping)) {
|
|
260
141
|
preferredVariants[code] = [...new Set([...(preferredVariants[code] || []), ...variants])];
|
|
261
142
|
}
|
|
262
|
-
for (const [category, codes] of Object.entries(document.extracted_data)) {
|
|
263
|
-
extracted_data[category] = { ...(extracted_data[category] || {}), ...codes };
|
|
264
|
-
}
|
|
265
|
-
if (path.basename(sourceFile) === CANONICAL_MAPPING_FILE
|
|
266
|
-
|| document.informations_dossier.parties_clientes.length
|
|
267
|
-
|| document.informations_dossier.parties_adverses.length) {
|
|
268
|
-
informations_dossier = document.informations_dossier;
|
|
269
|
-
}
|
|
270
143
|
}
|
|
271
144
|
|
|
272
145
|
const reverse_mapping = {};
|
|
@@ -281,7 +154,7 @@ function readCaseMapping(caseRoot) {
|
|
|
281
154
|
file,
|
|
282
155
|
sourceFiles: readableFiles,
|
|
283
156
|
exists: readableFiles.length > 0,
|
|
284
|
-
...normalizeMappingDocument({ mapping, reverse_mapping
|
|
157
|
+
...normalizeMappingDocument({ mapping, reverse_mapping }),
|
|
285
158
|
};
|
|
286
159
|
}
|
|
287
160
|
|
|
@@ -302,15 +175,9 @@ module.exports = {
|
|
|
302
175
|
applyMapping,
|
|
303
176
|
buildEntityRegex,
|
|
304
177
|
byDescendingEntityLength,
|
|
305
|
-
caseMappingFile,
|
|
306
178
|
escapeWithVariants,
|
|
307
|
-
normalizeMappingDocument,
|
|
308
|
-
normalizeProcedureInfo,
|
|
309
179
|
readCaseMapping,
|
|
310
|
-
readJsonFile,
|
|
311
180
|
resolveProjectCaseMapping,
|
|
312
181
|
resolveMappedPath,
|
|
313
182
|
revertMapping,
|
|
314
|
-
sortedMapping,
|
|
315
|
-
CANONICAL_MAPPING_FILE,
|
|
316
183
|
};
|
|
@@ -30,7 +30,7 @@ const PROTECTION_FILE = 'protection.json';
|
|
|
30
30
|
const PROTECTION_BYPASS_FILE = 'protection-bypass.json';
|
|
31
31
|
|
|
32
32
|
/**
|
|
33
|
-
* Sous-dossier technique historique
|
|
33
|
+
* Sous-dossier technique historique (ancien emplacement du mapping JSON).
|
|
34
34
|
* Le Markdown courant vit dans les sous-dossiers de conversion de
|
|
35
35
|
* Correspondance et Data Room ; ce repli reste nécessaire aux anciens dossiers
|
|
36
36
|
* et aux espaces de travail OOXML. `mapping.cjs` et `commits.cjs` l'importent.
|
|
@@ -1,66 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session timing helpers shared by the commit and billing hooks.
|
|
3
|
-
*
|
|
4
|
-
* A hook runs once per event with no memory of the session's start. The
|
|
5
|
-
* transcript is the only durable clock: its first entry's `timestamp` is the
|
|
6
|
-
* session start. `commit-track.mjs` needs that start on every Write/Edit to
|
|
7
|
-
* stamp the elapsed session time into the commit, so reading the whole
|
|
8
|
-
* transcript on each tool call would be wasteful — we only need the first
|
|
9
|
-
* timestamp, so we scan a bounded head of the file.
|
|
10
|
-
*
|
|
11
|
-
* Everything here fails soft: an unreadable/empty/malformed transcript yields
|
|
12
|
-
* `null`, and the caller simply omits the time trailer.
|
|
13
|
-
*/
|
|
14
|
-
const fs = require('node:fs');
|
|
15
|
-
|
|
16
|
-
// Enough to comfortably contain the first JSONL record even with a large
|
|
17
|
-
// system prompt echoed into it; we stop at the first line that parses.
|
|
18
|
-
const HEAD_BYTES = 256 * 1024;
|
|
19
|
-
|
|
20
|
-
/** First ISO timestamp in the transcript (session start), or null. */
|
|
21
|
-
function readSessionStartTimestamp(transcriptPath) {
|
|
22
|
-
if (!transcriptPath) return null;
|
|
23
|
-
let fd;
|
|
24
|
-
try {
|
|
25
|
-
fd = fs.openSync(transcriptPath, 'r');
|
|
26
|
-
const stat = fs.fstatSync(fd);
|
|
27
|
-
const length = Math.min(stat.size, HEAD_BYTES);
|
|
28
|
-
if (length === 0) return null;
|
|
29
|
-
const buffer = Buffer.allocUnsafe(length);
|
|
30
|
-
const bytesRead = fs.readSync(fd, buffer, 0, length, 0);
|
|
31
|
-
const text = buffer.subarray(0, bytesRead).toString('utf8');
|
|
32
|
-
for (const line of text.split('\n')) {
|
|
33
|
-
const trimmed = line.trim();
|
|
34
|
-
if (!trimmed) continue;
|
|
35
|
-
// The last line of a partial head read may be truncated; ignore parse
|
|
36
|
-
// failures and keep looking for the first fully-formed record.
|
|
37
|
-
let entry;
|
|
38
|
-
try {
|
|
39
|
-
entry = JSON.parse(trimmed);
|
|
40
|
-
} catch {
|
|
41
|
-
continue;
|
|
42
|
-
}
|
|
43
|
-
const ts = entry?.timestamp || entry?.message?.timestamp;
|
|
44
|
-
if (ts && Number.isFinite(Date.parse(ts))) return ts;
|
|
45
|
-
}
|
|
46
|
-
return null;
|
|
47
|
-
} catch {
|
|
48
|
-
return null;
|
|
49
|
-
} finally {
|
|
50
|
-
if (fd !== undefined) {
|
|
51
|
-
try { fs.closeSync(fd); } catch {}
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Milliseconds elapsed between the session's first entry and `now`. */
|
|
57
|
-
function sessionElapsedMs(transcriptPath, now = Date.now()) {
|
|
58
|
-
const start = readSessionStartTimestamp(transcriptPath);
|
|
59
|
-
if (!start) return null;
|
|
60
|
-
const ms = now - Date.parse(start);
|
|
61
|
-
return Number.isFinite(ms) && ms >= 0 ? ms : null;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
1
|
/** Compact French duration, e.g. "12 min 30 s", "1 h 05 min", "8 s". */
|
|
65
2
|
function formatDurationFr(ms) {
|
|
66
3
|
if (!Number.isFinite(ms) || ms < 0) return null;
|
|
@@ -75,6 +12,4 @@ function formatDurationFr(ms) {
|
|
|
75
12
|
|
|
76
13
|
module.exports = {
|
|
77
14
|
formatDurationFr,
|
|
78
|
-
readSessionStartTimestamp,
|
|
79
|
-
sessionElapsedMs,
|
|
80
15
|
};
|