@piecemaker-legal/piecemaker 2.0.9 → 2.0.11
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 +1 -0
- package/dist/assets/FootnotePropertiesDialog-W3YHM4BV-D5UqbelV.js +1 -0
- package/dist/assets/HyperlinkDialog-ZYH7ZHRF-8yEhLigd.js +144 -0
- package/dist/assets/HyperlinkDialog-ZYH7ZHRF-qIPBOssF.css +1 -0
- package/dist/assets/ImagePositionDialog-HEWYR6Q3-wGIBYxCm.js +1 -0
- package/dist/assets/ImagePropertiesDialog-RAB47C6M-D86PckZ2.js +1 -0
- package/dist/assets/PageSetupDialog-AIGIXO3E-DLETP-7v.js +1 -0
- package/dist/assets/SplitCellDialog-IFBKYCD6-CwdQBXeb.js +1 -0
- package/dist/assets/TablePropertiesDialog-TMLKGOOW-j2nA7KJs.js +1 -0
- package/dist/assets/WatermarkDialog-KRL7WMIS-XFJ9gTkC.js +1 -0
- package/dist/assets/{abnfDiagram-VCTEODGH-WrsSAHOe.js → abnfDiagram-VCTEODGH-DiCrND_Y.js} +1 -1
- package/dist/assets/arc-DOjgbMYz.js +1 -0
- package/dist/assets/architectureDiagram-5GKGNRK7-brzIFVhl.js +36 -0
- package/dist/assets/{blockDiagram-I7D4REHJ-zGMnF7Ox.js → blockDiagram-I7D4REHJ-C8JhTjQQ.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-ClWw3bqt.js → c4Diagram-7LVT6UL2-jfYxccyk.js} +1 -1
- package/dist/assets/channel-Dajzu2W1.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-C-9ICPHv.js → chunk-2Q5K7J3B-CrlEShp9.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-Bawy3teT.js → chunk-5VM5RSS4-DzPlUHGq.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-DQ375RQO.js → chunk-F27PBJKO-Cp9cpeWU.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-CflNF2f6.js → chunk-IMKFNOWR-BifUldEN.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-CIXQv0gc.js → chunk-JWPE2WC7-ggPEIkWu.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-Cza5j6Qw.js → chunk-POPQ4Y6H-3h_nayRX.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-GQ_VvWZR.js → chunk-SVP7TREG-CH29aG6J.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-BEmU16W5.js → chunk-TICWLB2K-PluJUM5k.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-C1KpkLYH.js → chunk-XXDRQBXY-DXU39Vwg.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-dDEP_giv.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-dDEP_giv.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-CZE48TRG.js → cose-bilkent-JH36ORCC-Dz6roYrN.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-L-tx1eC-.js → cynefin-OW5HDTMX-BLzrpSit.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-Coa8oJwR.js → cynefinDiagram-5FMLGOSQ-kfxnERDZ.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-Bu_3Y75K.js → dagre-GXQ25YYZ-DP57bp-N.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-CFiiV4es.js → diagram-S7CK7UJ4-DAlsrQVW.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-CCXheGAA.js → diagram-UQ7AKVKN-By5yrMer.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-B70m4lr_.js → diagram-VSXAHHWV-Dx89kryN.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-CHkiMOVA.js → diagram-VX7I27RA-B9fARitZ.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-_awpc4Bs.js → diagram-Z3DM3KII-DC15CEH1.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-CZzjH86H.js → ebnfDiagram-PWID7BFC-BKQzghGF.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-9DgiHZg9.js → erDiagram-RLTQ6QDP-CPY6RM7G.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-DHY_503b.js → flowDiagram-HODETNUW-4dL4GJcf.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-DPiiYZ_l.js → ganttDiagram-EL5Y4UJY-D4-cVcfb.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-Ddd_evm7.js → gitGraphDiagram-WWUBYQGX-BMeVIEiX.js} +1 -1
- package/dist/assets/{index-tibHq7Qp.js → index-DNtFDOni.js} +140 -140
- package/dist/assets/index-Dc9wNuS4.css +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-BPRNhfwb.js → infoDiagram-27XIBGKW-D5qMSUEU.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-BXx6aqkq.js → ishikawaDiagram-5VMMS53U-BDnyKRHm.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-BK8TZM29.js → journeyDiagram-3NMN7TZE-dGz5ZGzq.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-CHioRmxz.js → kanban-definition-UXKFOSKX-D7UAz7o_.js} +6 -6
- package/dist/assets/layout-DKrmEGrz.js +1 -0
- package/dist/assets/{linear-CTEhUcKG.js → linear-CrTdMY-p.js} +1 -1
- package/dist/assets/{mermaid.core-DYUb_UUB.js → mermaid.core-CXQOT5G6.js} +7 -7
- package/dist/assets/{mindmap-definition-YA3MSWOX-D7ODZ4oS.js → mindmap-definition-YA3MSWOX-VgEiYfay.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-8J-_2_kw.js → pegDiagram-XKGWAZYB-9IqT8gGx.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-ebg0yfMi.js → pieDiagram-E7YTZNPT-D98pRE-t.js} +1 -1
- package/dist/assets/processTemplate-GPFDLQMX-B1sVV2O0.js +22 -0
- package/dist/assets/{quadrantDiagram-AXDQQJYC-BoWkDiFb.js → quadrantDiagram-AXDQQJYC-b9PwkYzL.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BRJ77ldz.js → railroadDiagram-O6MQD6OU-Dz87hsPE.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-Z0JJgktA.js → requirementDiagram-BXWQKSXE-CkcV73dK.js} +1 -1
- package/dist/assets/sankeyDiagram-P5KCCOFB-UBN31Yrs.js +40 -0
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-BPAjtXwp.js → sequenceDiagram-WJ2MYXX4-CpQxd5Za.js} +1 -1
- package/dist/assets/{server.browser-BzI1jrZw.js → server.browser-BY3bL-IX.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BGZPCzM4.js → sizeCapture-INFHLROL-mCsFmyzw.js} +1 -1
- package/dist/assets/stateDiagram-D77RDMKH-B0MTBN-3.js +1 -0
- package/dist/assets/stateDiagram-v2-MP3YSRHH-DzBPN39W.js +1 -0
- package/dist/assets/{swimlanes-42K2YHIH-DvuB15qF.js → swimlanes-42K2YHIH-Dzydjm0e.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-BXQpbUMD.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-ZIziYCIF.js → timeline-definition-24CTP7MA-Dz0toOLu.js} +3 -3
- package/dist/assets/{vendor-codemirror-CjW0lHR5.js → vendor-codemirror-CN-sJePf.js} +2 -2
- package/dist/assets/{vendor-react-D809iwXR.js → vendor-react-B22wqN3J.js} +5 -5
- package/dist/assets/{vennDiagram-4TSXK5OY-C5_B9gWa.js → vennDiagram-4TSXK5OY-DOWp7dkf.js} +4 -4
- package/dist/assets/{wardleyDiagram-VM6X3IG4-DMlH9Afw.js → wardleyDiagram-VM6X3IG4-CUxsztUB.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-BldhJt7i.js → xychartDiagram-S5SC5T6Z-DS96vNED.js} +1 -1
- package/dist/index.html +4 -4
- package/dist/sw.js +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +4 -53
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +2 -3
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js +30 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js +24 -0
- package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js.map +1 -0
- package/dist-server/server/piecemaker/agent-instructions.js +148 -0
- package/dist-server/server/piecemaker/agent-instructions.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js +2 -3
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -1
- package/dist-server/server/piecemaker/docx-document.js +50 -0
- package/dist-server/server/piecemaker/docx-document.js.map +1 -0
- package/dist-server/server/piecemaker/index.js +13 -2
- package/dist-server/server/piecemaker/index.js.map +1 -1
- package/dist-server/server/piecemaker/model-discovery/codex-catalog.js +46 -0
- package/dist-server/server/piecemaker/model-discovery/codex-catalog.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/index.js +42 -0
- package/dist-server/server/piecemaker/model-discovery/index.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js +19 -0
- package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js.map +1 -0
- package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js +61 -0
- package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js.map +1 -0
- package/dist-server/server/piecemaker/project-registry.js +29 -0
- package/dist-server/server/piecemaker/project-registry.js.map +1 -0
- package/package.json +12 -1
- package/scripts/piecemaker/cli/disable-anonymizer.mjs +19 -0
- package/scripts/piecemaker/cli/lib/config.mjs +0 -1
- package/scripts/piecemaker/cli/lib/plugins.mjs +1 -0
- package/scripts/piecemaker/cli/lib/services.mjs +1 -10
- package/scripts/piecemaker/cli/piecemaker.mjs +0 -3
- package/server/modules/providers/list/mistral/mistral-models.provider.ts +4 -53
- package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +2 -3
- package/server/modules/providers/list/mistral/mistral-vibe-models.ts +43 -0
- package/server/modules/providers/tests/mistral-vibe-models.test.ts +27 -0
- package/server/piecemaker/agent-instructions.ts +148 -0
- package/server/piecemaker/anonymizer/client-config.cjs +92 -92
- package/server/piecemaker/anonymizer/dictionary.cjs +34 -3
- package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +9 -16
- package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.toml +1 -1
- package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +251 -268
- package/server/piecemaker/anonymizer/hudsucker-smoke.cjs +343 -0
- package/server/piecemaker/anonymizer/lifecycle.ts +2 -3
- package/server/piecemaker/anonymizer/rewriter-bridge.cjs +13 -4
- package/server/piecemaker/anonymizer/rewriter-worker.cjs +85 -0
- package/server/piecemaker/anonymizer/service.cjs +109 -179
- package/server/piecemaker/anonymizer/sqlite-dictionary.cjs +12 -1
- package/server/piecemaker/docx-document.ts +54 -0
- package/server/piecemaker/harness/decisions.cjs +1 -1
- package/server/piecemaker/harness/index.cjs +2 -3
- package/server/piecemaker/harness/verification.cjs +1 -1
- package/server/piecemaker/index.ts +15 -3
- package/server/piecemaker/model-discovery/codex-catalog.ts +67 -0
- package/server/piecemaker/model-discovery/index.ts +69 -0
- package/server/piecemaker/model-discovery/mistral-catalog.ts +36 -0
- package/server/piecemaker/model-discovery/stdio-rpc.ts +79 -0
- package/server/piecemaker/project-registry.ts +34 -0
- package/server/piecemaker/router.cjs +6 -8
- package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +31 -77
- package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +2 -84
- package/server/piecemaker/vendor/installer/lib/service.mjs +4 -24
- package/server/piecemaker/vendor/installer/steps/02-dependances-node.mjs +5 -5
- package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +10 -21
- package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +0 -11
- package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +6 -36
- package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +30 -12
- package/server/piecemaker/vendor/piecemaker-plugin/README.md +2 -9
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +5 -5
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +8 -8
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +2 -2
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +4 -6
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +2 -90
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +71 -38
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +8 -38
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +82 -61
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +189 -41
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +4 -55
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +24 -117
- package/server/piecemaker/vendor/piecemaker-plugin/skills/ajout-de-fonctionnalites/SKILL.md +4 -18
- package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +2 -2
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +14 -148
- package/server/piecemaker/vendor/websocket-server/case-registry.cjs +16 -42
- package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +0 -73
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +0 -7
- package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +3 -12
- package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +6 -6
- package/dist/assets/arc-DAA6wH-C.js +0 -1
- package/dist/assets/architectureDiagram-5GKGNRK7-BGNHr7ef.js +0 -36
- package/dist/assets/channel-BAQyfMll.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-BNGCuvrR.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-BNGCuvrR.js +0 -1
- package/dist/assets/index-WwknP0l4.css +0 -1
- package/dist/assets/layout-DEnkyfTY.js +0 -1
- package/dist/assets/sankeyDiagram-P5KCCOFB-4PW5HTOP.js +0 -40
- package/dist/assets/stateDiagram-D77RDMKH-o-vEcKwz.js +0 -1
- package/dist/assets/stateDiagram-v2-MP3YSRHH-BsuDaKkN.js +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-DcCAyKlT.js +0 -8
- package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +0 -78
- package/scripts/piecemaker/hooks/proxy-guard.mjs +0 -251
- package/server/piecemaker/anonymizer/providers.cjs +0 -120
- package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +0 -482
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
- package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +0 -602
|
@@ -115,6 +115,157 @@ function byDescendingEntityLength(getEntity) {
|
|
|
115
115
|
};
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
+
function mappingSignature(entries) {
|
|
119
|
+
let signature = '';
|
|
120
|
+
for (const [key, value] of entries) signature += key + '\u0000' + value + '\u0001';
|
|
121
|
+
return signature;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function literalAnchor(value) {
|
|
125
|
+
const runs = String(value).match(/[A-Za-z0-9_]+/g) || [];
|
|
126
|
+
return runs.reduce((longest, run) => (run.length > longest.length ? run : longest), '');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const ANCHOR_WIDTH = 37;
|
|
130
|
+
const ANCHOR_SYMBOL = new Int8Array(128).fill(-1);
|
|
131
|
+
for (let letter = 0; letter < 26; letter += 1) {
|
|
132
|
+
ANCHOR_SYMBOL[65 + letter] = letter;
|
|
133
|
+
ANCHOR_SYMBOL[97 + letter] = letter;
|
|
134
|
+
}
|
|
135
|
+
for (let digit = 0; digit < 10; digit += 1) ANCHOR_SYMBOL[48 + digit] = 26 + digit;
|
|
136
|
+
ANCHOR_SYMBOL[95] = 36;
|
|
137
|
+
const KELVIN_SIGN = 0x212A;
|
|
138
|
+
const LONG_S = 0x017F;
|
|
139
|
+
|
|
140
|
+
function anchorSymbol(unit) {
|
|
141
|
+
if (unit < 128) return ANCHOR_SYMBOL[unit];
|
|
142
|
+
if (unit === KELVIN_SIGN) return ANCHOR_SYMBOL[107];
|
|
143
|
+
if (unit === LONG_S) return ANCHOR_SYMBOL[115];
|
|
144
|
+
return -1;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function buildAnchorScanner(anchors) {
|
|
148
|
+
let transitions = new Int32Array(ANCHOR_WIDTH * 16).fill(-1);
|
|
149
|
+
const outputs = [[]];
|
|
150
|
+
let size = 1;
|
|
151
|
+
anchors.forEach((anchor, index) => {
|
|
152
|
+
if (!anchor) return;
|
|
153
|
+
let node = 0;
|
|
154
|
+
for (let position = 0; position < anchor.length; position += 1) {
|
|
155
|
+
const slot = node * ANCHOR_WIDTH + ANCHOR_SYMBOL[anchor.charCodeAt(position)];
|
|
156
|
+
if (transitions[slot] === -1) {
|
|
157
|
+
if ((size + 1) * ANCHOR_WIDTH > transitions.length) {
|
|
158
|
+
const grown = new Int32Array(transitions.length * 2).fill(-1);
|
|
159
|
+
grown.set(transitions);
|
|
160
|
+
transitions = grown;
|
|
161
|
+
}
|
|
162
|
+
transitions[slot] = size;
|
|
163
|
+
outputs.push([]);
|
|
164
|
+
size += 1;
|
|
165
|
+
}
|
|
166
|
+
node = transitions[slot];
|
|
167
|
+
}
|
|
168
|
+
outputs[node].push(index);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const failure = new Int32Array(size);
|
|
172
|
+
const queue = [];
|
|
173
|
+
for (let symbol = 0; symbol < ANCHOR_WIDTH; symbol += 1) {
|
|
174
|
+
const child = transitions[symbol];
|
|
175
|
+
if (child === -1) transitions[symbol] = 0;
|
|
176
|
+
else queue.push(child);
|
|
177
|
+
}
|
|
178
|
+
for (let head = 0; head < queue.length; head += 1) {
|
|
179
|
+
const node = queue[head];
|
|
180
|
+
outputs[node] = outputs[node].concat(outputs[failure[node]]);
|
|
181
|
+
for (let symbol = 0; symbol < ANCHOR_WIDTH; symbol += 1) {
|
|
182
|
+
const slot = node * ANCHOR_WIDTH + symbol;
|
|
183
|
+
const child = transitions[slot];
|
|
184
|
+
if (child === -1) {
|
|
185
|
+
transitions[slot] = transitions[failure[node] * ANCHOR_WIDTH + symbol];
|
|
186
|
+
} else {
|
|
187
|
+
failure[child] = transitions[failure[node] * ANCHOR_WIDTH + symbol];
|
|
188
|
+
queue.push(child);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const next = new Int32Array(size * ANCHOR_WIDTH);
|
|
194
|
+
for (let slot = 0; slot < next.length; slot += 1) next[slot] = transitions[slot] * ANCHOR_WIDTH;
|
|
195
|
+
const emitted = new Array(size * ANCHOR_WIDTH).fill(null);
|
|
196
|
+
for (let node = 0; node < size; node += 1) if (outputs[node].length) emitted[node * ANCHOR_WIDTH] = outputs[node];
|
|
197
|
+
|
|
198
|
+
return (text) => {
|
|
199
|
+
const found = new Set();
|
|
200
|
+
let state = 0;
|
|
201
|
+
for (let position = 0; position < text.length; position += 1) {
|
|
202
|
+
const symbol = anchorSymbol(text.charCodeAt(position));
|
|
203
|
+
if (symbol === -1) {
|
|
204
|
+
state = 0;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
state = next[state + symbol];
|
|
208
|
+
const matched = emitted[state];
|
|
209
|
+
if (matched !== null) for (const index of matched) found.add(index);
|
|
210
|
+
}
|
|
211
|
+
return found;
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function compileReplacements(replacements) {
|
|
216
|
+
return { replacements, scan: buildAnchorScanner(replacements.map(({ anchor }) => anchor.toLowerCase())) };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
function isDeeplyFrozen(object) {
|
|
220
|
+
return Object.isFrozen(object) && Object.values(object).every((value) => !Array.isArray(value) || Object.isFrozen(value));
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const compiledMappings = new WeakMap();
|
|
224
|
+
|
|
225
|
+
function compileMapping(mapping) {
|
|
226
|
+
const cached = compiledMappings.get(mapping);
|
|
227
|
+
if (cached && cached.frozen) return cached;
|
|
228
|
+
const entries = Object.entries(mapping);
|
|
229
|
+
const signature = mappingSignature(entries);
|
|
230
|
+
if (cached && cached.signature === signature) return cached;
|
|
231
|
+
|
|
232
|
+
const codes = [...new Set(entries.map(([, code]) => String(code)).filter(Boolean))]
|
|
233
|
+
.sort((a, b) => b.length - a.length);
|
|
234
|
+
const replacements = [];
|
|
235
|
+
for (const [entity, code] of entries.sort(byDescendingEntityLength(([key]) => key))) {
|
|
236
|
+
const regex = buildEntityRegex(entity);
|
|
237
|
+
if (!regex) continue;
|
|
238
|
+
const trimmed = entity.trim();
|
|
239
|
+
replacements.push({ regex, code, anchor: literalAnchor(regex.flags.includes('i') ? trimmed : trimmed.toUpperCase()) });
|
|
240
|
+
}
|
|
241
|
+
const compiled = {
|
|
242
|
+
frozen: Object.isFrozen(mapping),
|
|
243
|
+
signature,
|
|
244
|
+
codes,
|
|
245
|
+
codeProbe: codes.length ? new RegExp(codes.map(escapeRegex).join('|')) : null,
|
|
246
|
+
replacements: compileReplacements(replacements),
|
|
247
|
+
};
|
|
248
|
+
compiledMappings.set(mapping, compiled);
|
|
249
|
+
return compiled;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function applyReplacements({ replacements, scan }, text) {
|
|
253
|
+
let output = text;
|
|
254
|
+
let present = null;
|
|
255
|
+
replacements.forEach(({ regex, code, anchor }, index) => {
|
|
256
|
+
if (anchor) {
|
|
257
|
+
if (present === null) present = scan(output);
|
|
258
|
+
if (!present.has(index)) return;
|
|
259
|
+
}
|
|
260
|
+
const next = output.replace(regex, code);
|
|
261
|
+
if (next !== output) {
|
|
262
|
+
output = next;
|
|
263
|
+
present = null;
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
return output;
|
|
267
|
+
}
|
|
268
|
+
|
|
118
269
|
/**
|
|
119
270
|
* Entité → code. Les entrées passent de la plus longue à la plus courte pour
|
|
120
271
|
* qu'un nom contenu dans un autre ne consomme jamais le plus long en premier
|
|
@@ -122,41 +273,49 @@ function byDescendingEntityLength(getEntity) {
|
|
|
122
273
|
*/
|
|
123
274
|
function applyMapping(text, mapping) {
|
|
124
275
|
if (typeof text !== 'string' || !text) return text;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
// sous-chaîne (≥ 3 car.) et l'underscore-séparateur (acronymes 2 car.)
|
|
130
|
-
// pourraient sinon réécrire l'intérieur d'un code — « SA » dans « URGOT SA »,
|
|
131
|
-
// « Moral » dans « PERSONNE_MORALE_01 » — et le corrompre. Chaque code distinct
|
|
132
|
-
// est remplacé par un caractère de zone privée (ni lettre ni chiffre, absent des
|
|
133
|
-
// documents, jamais matché par une regex d'entité), on anonymise, puis on
|
|
134
|
-
// restaure. C'est aussi ce qui garantit l'idempotence : réappliquer le mapping à
|
|
135
|
-
// un texte déjà codé masque ses codes et ne touche à rien. Codes triés du plus
|
|
136
|
-
// long au plus court pour qu'un code contenu dans un autre ne soit pas masqué
|
|
137
|
-
// en premier.
|
|
138
|
-
const codes = [...new Set(entries.map(([, code]) => String(code)).filter(Boolean))]
|
|
139
|
-
.sort((a, b) => b.length - a.length);
|
|
276
|
+
if (!mapping || typeof mapping !== 'object') return text;
|
|
277
|
+
const compiled = compileMapping(mapping);
|
|
278
|
+
if (!compiled.replacements.replacements.length) return text;
|
|
279
|
+
|
|
140
280
|
const restore = [];
|
|
141
281
|
let masked = text;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
let output = masked;
|
|
150
|
-
for (const [entity, code] of entries.sort(byDescendingEntityLength(([key]) => key))) {
|
|
151
|
-
const regex = buildEntityRegex(entity);
|
|
152
|
-
if (!regex) continue;
|
|
153
|
-
output = output.replace(regex, code);
|
|
282
|
+
if (compiled.codeProbe && compiled.codeProbe.test(text)) {
|
|
283
|
+
compiled.codes.forEach((code, idx) => {
|
|
284
|
+
if (!masked.includes(code)) return;
|
|
285
|
+
const token = String.fromCodePoint(0xE000 + idx);
|
|
286
|
+
restore.push([token, code]);
|
|
287
|
+
masked = masked.split(code).join(token);
|
|
288
|
+
});
|
|
154
289
|
}
|
|
155
290
|
|
|
291
|
+
let output = applyReplacements(compiled.replacements, masked);
|
|
292
|
+
if (output === masked) return text;
|
|
293
|
+
|
|
156
294
|
for (const [token, code] of restore) output = output.split(token).join(code);
|
|
157
295
|
return output;
|
|
158
296
|
}
|
|
159
297
|
|
|
298
|
+
const compiledReverseMappings = new WeakMap();
|
|
299
|
+
|
|
300
|
+
function compileReverseMapping(reverseMapping) {
|
|
301
|
+
const cached = compiledReverseMappings.get(reverseMapping);
|
|
302
|
+
if (cached && cached.frozen) return cached;
|
|
303
|
+
const entries = Object.entries(reverseMapping);
|
|
304
|
+
const signature = mappingSignature(entries.map(([code, variants]) => [code, Array.isArray(variants) ? variants[0] : variants]));
|
|
305
|
+
if (cached && cached.signature === signature) return cached;
|
|
306
|
+
|
|
307
|
+
const replacements = [];
|
|
308
|
+
for (const [code, variants] of entries.sort(byDescendingEntityLength(([key]) => key))) {
|
|
309
|
+
const canonical = Array.isArray(variants) ? variants[0] : variants;
|
|
310
|
+
if (!canonical) continue;
|
|
311
|
+
const regex = new RegExp(`${WORD_BOUNDARY_BEFORE}${escapeRegex(String(code))}${WORD_BOUNDARY_AFTER}`, 'giu');
|
|
312
|
+
replacements.push({ regex, code: String(canonical), anchor: literalAnchor(code) });
|
|
313
|
+
}
|
|
314
|
+
const compiled = { frozen: isDeeplyFrozen(reverseMapping), signature, replacements: compileReplacements(replacements) };
|
|
315
|
+
compiledReverseMappings.set(reverseMapping, compiled);
|
|
316
|
+
return compiled;
|
|
317
|
+
}
|
|
318
|
+
|
|
160
319
|
/**
|
|
161
320
|
* Code → entité. Le premier variant du tableau fait foi : c'est l'orthographe
|
|
162
321
|
* canonique retenue par `consolidate_duplicate_entities`, celle qu'un humain
|
|
@@ -175,20 +334,9 @@ function applyMapping(text, mapping) {
|
|
|
175
334
|
*/
|
|
176
335
|
function revertMapping(text, reverseMapping) {
|
|
177
336
|
if (typeof text !== 'string' || !text) return text;
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
let output = text;
|
|
182
|
-
for (const [code, variants] of entries.sort(byDescendingEntityLength(([key]) => key))) {
|
|
183
|
-
const canonical = Array.isArray(variants) ? variants[0] : variants;
|
|
184
|
-
if (!canonical) continue;
|
|
185
|
-
// Un code est un identifiant ASCII : pas de variantes Unicode à gérer, mais
|
|
186
|
-
// les mêmes frontières de mots, pour ne pas réécrire un code cité dans un
|
|
187
|
-
// mot plus long.
|
|
188
|
-
const regex = new RegExp(`${WORD_BOUNDARY_BEFORE}${escapeRegex(String(code))}${WORD_BOUNDARY_AFTER}`, 'giu');
|
|
189
|
-
output = output.replace(regex, String(canonical));
|
|
190
|
-
}
|
|
191
|
-
return output;
|
|
337
|
+
if (!reverseMapping || typeof reverseMapping !== 'object') return text;
|
|
338
|
+
const compiled = compileReverseMapping(reverseMapping);
|
|
339
|
+
return applyReplacements(compiled.replacements, text);
|
|
192
340
|
}
|
|
193
341
|
|
|
194
342
|
function normalizedPathName(value) {
|
|
@@ -21,19 +21,16 @@
|
|
|
21
21
|
import fs from 'node:fs';
|
|
22
22
|
import path from 'node:path';
|
|
23
23
|
import { createRequire } from 'node:module';
|
|
24
|
-
import {
|
|
24
|
+
import { readHookPayload, runHook, noop } from './lib/hook-io.mjs';
|
|
25
25
|
|
|
26
26
|
const require = createRequire(import.meta.url);
|
|
27
|
-
const {
|
|
28
|
-
const { caseHasMapping } = require('./lib/mapping.cjs');
|
|
27
|
+
const { locateProjectCase } = require('./lib/case-folders.cjs');
|
|
29
28
|
const {
|
|
30
29
|
isMappingFile,
|
|
31
30
|
isSecretFile,
|
|
32
31
|
isProtectedFile,
|
|
33
32
|
markdownCounterpart,
|
|
34
33
|
readProtection,
|
|
35
|
-
relativeKey,
|
|
36
|
-
READABLE_EXTENSIONS,
|
|
37
34
|
} = require('./lib/protection.cjs');
|
|
38
35
|
|
|
39
36
|
/** Au-delà, on ne cherche pas de chemin : une commande pareille n'en cite pas un. */
|
|
@@ -81,36 +78,6 @@ function secretReason(absolute) {
|
|
|
81
78
|
return `[PieceMaker] « ${path.basename(absolute)} » est un fichier de secrets d’environnement : il n’est jamais accessible à l’IA.`;
|
|
82
79
|
}
|
|
83
80
|
|
|
84
|
-
/**
|
|
85
|
-
* Refus « dossier non anonymisé ». Sans `mapping_default.json`, le proxy n'a
|
|
86
|
-
* rien à coder : lire une pièce livrerait des données personnelles en clair.
|
|
87
|
-
* On l'explique synthétiquement au modèle, avec l'action qui débloque la lecture.
|
|
88
|
-
*/
|
|
89
|
-
function missingMappingReason(caseName) {
|
|
90
|
-
return `[PieceMaker] « ${caseName} » est un dossier PieceMaker sans mapping d’anonymisation (mapping_default.json absent) : sa lecture est bloquée car son contenu n’est pas encore anonymisable et partirait en clair. Lancez l’anonymisation du dossier dans l’administration PieceMaker avant toute lecture.`;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Surface lisible dont le contenu serait normalement codé à la lecture (`.md`,
|
|
95
|
-
* `.json` de pièce) : c'est précisément ce que `missingMappingReason` doit
|
|
96
|
-
* protéger quand aucun mapping n'existe. On écarte les originaux (déjà refusés
|
|
97
|
-
* par `isProtectedFile`), le mapping et les scans (refusés à part), la
|
|
98
|
-
* configuration du dossier (`.piecemaker/…`, dotfiles) et les consignes
|
|
99
|
-
* structurelles `CLAUDE.md`/`AGENTS.md` — jamais des pièces, et l'assistant du
|
|
100
|
-
* dossier doit pouvoir charger sa consigne même avant anonymisation.
|
|
101
|
-
*/
|
|
102
|
-
function isReadableCaseSurface(absolute, caseRoot) {
|
|
103
|
-
const stat = statSafe(absolute);
|
|
104
|
-
if (!stat || stat.isDirectory()) return false;
|
|
105
|
-
const key = relativeKey(absolute, caseRoot);
|
|
106
|
-
if (!key) return false;
|
|
107
|
-
if (key.split('/').some((segment) => segment.startsWith('.'))) return false;
|
|
108
|
-
if (!READABLE_EXTENSIONS.has(path.extname(key).toLowerCase())) return false;
|
|
109
|
-
if (isMappingFile(absolute)) return false;
|
|
110
|
-
const base = path.basename(key);
|
|
111
|
-
return base !== 'CLAUDE.md' && base !== 'AGENTS.md';
|
|
112
|
-
}
|
|
113
|
-
|
|
114
81
|
function statSafe(target) {
|
|
115
82
|
try {
|
|
116
83
|
return fs.statSync(target);
|
|
@@ -189,23 +156,19 @@ function caseRootHasMapping(located) {
|
|
|
189
156
|
async function main() {
|
|
190
157
|
const payload = await readHookPayload(2000);
|
|
191
158
|
if (!payload) return null;
|
|
192
|
-
const config = loadPieceMakerConfig();
|
|
193
159
|
|
|
194
160
|
const toolName = payload.tool_name;
|
|
195
161
|
const cwd = payload.cwd || process.cwd();
|
|
196
162
|
|
|
197
163
|
if (toolName === 'Bash') {
|
|
198
164
|
for (const candidate of commandPaths(payload.tool_input?.command, cwd)) {
|
|
199
|
-
const located =
|
|
165
|
+
const located = locateProjectCase(candidate);
|
|
200
166
|
if (!located) continue;
|
|
201
167
|
if (isMappingFile(candidate)) return deny(mappingReason(candidate));
|
|
202
168
|
if (isSecretFile(candidate)) return deny(secretReason(candidate));
|
|
203
169
|
if (isProtectedFile(candidate, located.caseRoot)) {
|
|
204
170
|
return deny(protectionReason(candidate, located.caseRoot));
|
|
205
171
|
}
|
|
206
|
-
if (isReadableCaseSurface(candidate, located.caseRoot) && !caseHasMapping(located.caseRoot)) {
|
|
207
|
-
return deny(missingMappingReason(located.caseName));
|
|
208
|
-
}
|
|
209
172
|
}
|
|
210
173
|
return null;
|
|
211
174
|
}
|
|
@@ -214,7 +177,7 @@ async function main() {
|
|
|
214
177
|
|
|
215
178
|
const target = absolutePath(payload.tool_input?.file_path || payload.tool_input?.path, cwd);
|
|
216
179
|
if (!target) return null;
|
|
217
|
-
const located =
|
|
180
|
+
const located = locateProjectCase(target);
|
|
218
181
|
if (!located) return null;
|
|
219
182
|
|
|
220
183
|
// Un répertoire n'est pas une pièce : `Grep`/`Glob` en visent un couramment,
|
|
@@ -227,20 +190,6 @@ async function main() {
|
|
|
227
190
|
return deny(protectionReason(target, located.caseRoot));
|
|
228
191
|
}
|
|
229
192
|
|
|
230
|
-
// Dossier PieceMaker sans mapping : la garantie « anonymisé à la lecture »
|
|
231
|
-
// n'existe pas encore. Lire une surface lisible (`.md`/`.json` de pièce) la
|
|
232
|
-
// ferait sortir en clair, et un `Grep` récursif à la racine en ferait autant
|
|
233
|
-
// sur tout le dossier (un `Glob`, qui ne ramène que des noms, reste permis).
|
|
234
|
-
// On calcule l'absence de mapping au plus tard, une fois les refus francs
|
|
235
|
-
// (mapping, original) écartés — c'est le seul chemin qui paie la lecture du
|
|
236
|
-
// mapping.
|
|
237
|
-
if (isReadableCaseSurface(target, located.caseRoot) && !caseHasMapping(located.caseRoot)) {
|
|
238
|
-
return deny(missingMappingReason(located.caseName));
|
|
239
|
-
}
|
|
240
|
-
if (toolName === 'Grep' && located.absolute === located.caseRoot && !caseHasMapping(located.caseRoot)) {
|
|
241
|
-
return deny(missingMappingReason(located.caseName));
|
|
242
|
-
}
|
|
243
|
-
|
|
244
193
|
// Un `Grep` récursif ramène le *contenu* du mapping ; un `Glob` n'en ramène
|
|
245
194
|
// que le nom, qui ne trahit rien — d'où la restriction à Grep ici.
|
|
246
195
|
if (toolName === 'Grep' && caseRootHasMapping(located)) {
|
|
@@ -1,120 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
/**
|
|
3
|
-
* statusLine Claude Code — bandeau permanent d'état de l'anonymisation PieceMaker.
|
|
4
|
-
*
|
|
5
|
-
* Contrat statusLine (type "command") : JSON sur stdin décrivant la session
|
|
6
|
-
* (workspace, model...), une seule ligne sur stdout, exit 0. Appelé très
|
|
7
|
-
* souvent (à chaque rendu de l'interface) : ce script doit rester rapide et
|
|
8
|
-
* ne jamais bloquer ni jeter.
|
|
9
|
-
*
|
|
10
|
-
* Le badge reflète les deux mêmes conditions que `proxy-guard.mjs` (routage
|
|
11
|
-
* + proxy vivant), mais sans autostart ni journalisation : une statusLine
|
|
12
|
-
* n'est pas le bon endroit pour une action de fond, seulement pour un
|
|
13
|
-
* affichage. Le sondage réseau est borné à 400 ms et son résultat est mis en
|
|
14
|
-
* cache 5 s dans ~/.piecemaker/proxy-statusline.json pour éviter une requête
|
|
15
|
-
* à chaque frappe.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import fs from 'node:fs';
|
|
19
2
|
import http from 'node:http';
|
|
20
|
-
import os from 'node:os';
|
|
21
3
|
import path from 'node:path';
|
|
22
|
-
import {
|
|
4
|
+
import { loadPieceMakerConfig, readHookPayload } from './lib/hook-io.mjs';
|
|
23
5
|
|
|
24
|
-
const CACHE_FILE = path.join(HOME_DIR, 'proxy-statusline.json');
|
|
25
|
-
const CACHE_TTL_MS = 5000;
|
|
26
6
|
const PROBE_TIMEOUT_MS = 400;
|
|
27
7
|
const STDIN_TIMEOUT_MS = 1000;
|
|
28
|
-
const DEFAULT_PORT = 4000;
|
|
29
8
|
const FLUSH_TIMEOUT_MS = 1000;
|
|
9
|
+
const VERT = '\u001b[32m';
|
|
10
|
+
const ROUGE = '\u001b[31m';
|
|
11
|
+
const RESET = '\u001b[0m';
|
|
30
12
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
function validPort(value) {
|
|
34
|
-
const port = Number(value);
|
|
35
|
-
return Number.isInteger(port) && port >= 1024 && port <= 65535 ? port : DEFAULT_PORT;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Même définition du routage que proxy-guard.mjs — lecture directe, jamais de throw. */
|
|
39
|
-
function readRouting() {
|
|
40
|
-
try {
|
|
41
|
-
const settings = JSON.parse(fs.readFileSync(SETTINGS_FILE, 'utf8'));
|
|
42
|
-
const value = settings?.env?.HTTPS_PROXY;
|
|
43
|
-
if (typeof value !== 'string' || !value) return false;
|
|
44
|
-
const url = new URL(value);
|
|
45
|
-
return ['127.0.0.1', 'localhost'].includes(url.hostname);
|
|
46
|
-
} catch {
|
|
47
|
-
return false;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Cache court entre deux sondages. Un cache illisible/absent n'empêche pas de sonder. */
|
|
52
|
-
function readCache() {
|
|
13
|
+
function routedProxy() {
|
|
53
14
|
try {
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
if (Date.now() - parsed.ts > CACHE_TTL_MS) return null;
|
|
57
|
-
return parsed;
|
|
15
|
+
const url = new URL(process.env.HTTPS_PROXY || process.env.https_proxy || '');
|
|
16
|
+
return ['127.0.0.1', 'localhost'].includes(url.hostname) ? url : null;
|
|
58
17
|
} catch {
|
|
59
18
|
return null;
|
|
60
19
|
}
|
|
61
20
|
}
|
|
62
21
|
|
|
63
|
-
function
|
|
64
|
-
try {
|
|
65
|
-
fs.mkdirSync(HOME_DIR, { recursive: true });
|
|
66
|
-
fs.writeFileSync(CACHE_FILE, JSON.stringify({ ts: Date.now(), actif }), 'utf8');
|
|
67
|
-
} catch {
|
|
68
|
-
// Le cache est un confort de performance, pas une garantie.
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
function probe(port, timeoutMs) {
|
|
22
|
+
function proxyHealthy(proxy) {
|
|
73
23
|
return new Promise((resolve) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
const request = http.get({
|
|
82
|
-
hostname: '127.0.0.1',
|
|
83
|
-
port,
|
|
84
|
-
path: '/health/liveliness',
|
|
85
|
-
timeout: timeoutMs,
|
|
86
|
-
}, (response) => {
|
|
87
|
-
response.resume();
|
|
88
|
-
finish(response.statusCode === 200);
|
|
89
|
-
});
|
|
90
|
-
request.on('timeout', () => { request.destroy(); finish(false); });
|
|
91
|
-
request.on('error', () => finish(false));
|
|
92
|
-
} catch {
|
|
93
|
-
finish(false);
|
|
94
|
-
}
|
|
24
|
+
const request = http.get({ hostname: proxy.hostname, port: proxy.port, path: '/health', timeout: PROBE_TIMEOUT_MS }, (response) => {
|
|
25
|
+
response.resume();
|
|
26
|
+
resolve(response.statusCode === 200);
|
|
27
|
+
});
|
|
28
|
+
request.on('timeout', () => { request.destroy(); resolve(false); });
|
|
29
|
+
request.on('error', () => resolve(false));
|
|
95
30
|
});
|
|
96
31
|
}
|
|
97
32
|
|
|
98
|
-
/**
|
|
99
|
-
* Couleur ANSI du badge : vert quand l'anonymisation est effective, rouge
|
|
100
|
-
* sinon. Claude Code rend les séquences ANSI de la statusLine ; on n'en met
|
|
101
|
-
* que sur le badge, jamais sur le dossier ni le modèle.
|
|
102
|
-
*/
|
|
103
|
-
const VERT = '\u001b[32m';
|
|
104
|
-
const ROUGE = '\u001b[31m';
|
|
105
|
-
const RESET = '\u001b[0m';
|
|
106
|
-
|
|
107
33
|
function colore(texte, couleur) {
|
|
108
34
|
return process.env.NO_COLOR ? texte : `${couleur}${texte}${RESET}`;
|
|
109
35
|
}
|
|
110
36
|
|
|
111
|
-
function badge(
|
|
112
|
-
|
|
113
|
-
if (
|
|
114
|
-
return colore('
|
|
37
|
+
async function badge() {
|
|
38
|
+
const proxy = routedProxy();
|
|
39
|
+
if (!proxy) return colore('⚠️ Anonymisation PieceMaker inactive — accès direct', ROUGE);
|
|
40
|
+
if (await proxyHealthy(proxy)) return colore('🔒 Anonymisation PieceMaker active ✓', VERT);
|
|
41
|
+
return colore('⛔ Anonymisation PieceMaker indisponible — requêtes bloquées (relancer piecemaker)', ROUGE);
|
|
115
42
|
}
|
|
116
43
|
|
|
117
|
-
/** Écrit la ligne et quitte proprement, en attendant le flush comme hook-io.mjs::emit. */
|
|
118
44
|
function printAndExit(text) {
|
|
119
45
|
const guard = setTimeout(() => process.exit(0), FLUSH_TIMEOUT_MS);
|
|
120
46
|
guard.unref?.();
|
|
@@ -139,35 +65,16 @@ function safeCwdName(cwd) {
|
|
|
139
65
|
}
|
|
140
66
|
|
|
141
67
|
async function main() {
|
|
142
|
-
|
|
143
|
-
try {
|
|
144
|
-
payload = await readHookPayload(STDIN_TIMEOUT_MS);
|
|
145
|
-
} catch {
|
|
146
|
-
payload = null;
|
|
147
|
-
}
|
|
148
|
-
|
|
68
|
+
const payload = await readHookPayload(STDIN_TIMEOUT_MS).catch(() => null);
|
|
149
69
|
const dirName = safeCwdName(payload?.workspace?.current_dir || payload?.cwd);
|
|
150
70
|
const modelName = typeof payload?.model?.display_name === 'string' ? payload.model.display_name : '';
|
|
151
|
-
|
|
152
|
-
let config = {};
|
|
71
|
+
let disabled = false;
|
|
153
72
|
try {
|
|
154
|
-
|
|
73
|
+
disabled = loadPieceMakerConfig()?.anonymizer?.enabled === false;
|
|
155
74
|
} catch {
|
|
156
|
-
|
|
75
|
+
disabled = false;
|
|
157
76
|
}
|
|
158
|
-
const
|
|
159
|
-
const routed = readRouting();
|
|
160
|
-
|
|
161
|
-
const cached = readCache();
|
|
162
|
-
let actif;
|
|
163
|
-
if (cached) {
|
|
164
|
-
actif = cached.actif;
|
|
165
|
-
} else {
|
|
166
|
-
actif = await probe(port, PROBE_TIMEOUT_MS);
|
|
167
|
-
writeCache(actif);
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
const parts = [badge(routed, actif)];
|
|
77
|
+
const parts = [disabled ? 'Anonymisation PieceMaker désactivée' : await badge()];
|
|
171
78
|
if (dirName) parts.push(dirName);
|
|
172
79
|
if (modelName) parts.push(modelName);
|
|
173
80
|
printAndExit(parts.join(' · '));
|
|
@@ -14,9 +14,9 @@ skill sert de guide pour ranger un ajout personnel au bon endroit.
|
|
|
14
14
|
|
|
15
15
|
| Type d'ajout | Emplacement | Portée |
|
|
16
16
|
| --- | --- | --- |
|
|
17
|
-
| Instructions ou préférences globales (style, rappels, habitudes) |
|
|
18
|
-
| Skill personnelle réutilisable | Nouveau dossier
|
|
19
|
-
| Gabarit personnel (acte, courrier type…) |
|
|
17
|
+
| Instructions ou préférences globales (style, rappels, habitudes) | `~/.piecemaker/custom/perso.md` | Toutes les affaires — ce fichier est importé automatiquement dans chaque dossier via `~/.piecemaker/CLAUDE.md`. |
|
|
18
|
+
| Skill personnelle réutilisable | Nouveau dossier `~/.claude/skills/<nom>/SKILL.md` | Toutes les sessions Claude Code — découverte automatique, jamais écrasée par PieceMaker (un fichier créé à la main n'est jamais remplacé par l'application). |
|
|
19
|
+
| Gabarit personnel (acte, courrier type…) | `~/.piecemaker/templates/` | Disponible pour toute rédaction, indépendamment du dépôt de l'application. |
|
|
20
20
|
| Élément propre à une seule affaire (parties, juridiction, échéances) | Section « Ce dossier » du `CLAUDE.md` / `AGENTS.md` de ce dossier | Uniquement ce dossier-là. |
|
|
21
21
|
|
|
22
22
|
Ces emplacements sont hors du dépôt PieceMaker : une mise à jour de PieceMaker
|
|
@@ -26,7 +26,7 @@ PieceMaker — la garantie va dans les deux sens.
|
|
|
26
26
|
|
|
27
27
|
## Format minimal d'une skill personnelle
|
|
28
28
|
|
|
29
|
-
Un fichier
|
|
29
|
+
Un fichier `~/.claude/skills/<nom>/SKILL.md` avec un en-tête
|
|
30
30
|
puis du texte libre :
|
|
31
31
|
|
|
32
32
|
```markdown
|
|
@@ -50,17 +50,3 @@ Instructions pour l'assistant, en français, centrées sur la tâche.
|
|
|
50
50
|
3. **Créer ou éditer le fichier correspondant**, en respectant le format
|
|
51
51
|
attendu (front matter pour une skill, section « Ce dossier » pour un
|
|
52
52
|
élément local, etc.).
|
|
53
|
-
4. **Pour un nouveau dossier d'affaire** qui n'a pas encore de wrapper : sur
|
|
54
|
-
demande, proposer et créer `CLAUDE.md` et `AGENTS.md` à la racine du
|
|
55
|
-
dossier, avec exactement ce contenu (chemin absolu, jamais `~`) :
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
@/Users/tsardet/.piecemaker/CLAUDE.md
|
|
59
|
-
|
|
60
|
-
# Ce dossier
|
|
61
|
-
<!-- Éléments propres à ce dossier : parties, juridiction, échéances, particularités. À compléter. -->
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Si l'un de ces deux fichiers existe déjà dans le dossier, ne jamais
|
|
65
|
-
l'écraser : le lire, et s'il ne contient pas déjà cette ligne d'import,
|
|
66
|
-
l'ajouter en tête sans supprimer le contenu existant.
|
|
@@ -40,8 +40,8 @@ dossier ni par utilisateur.
|
|
|
40
40
|
haute définition : forme, contour, police, couleur et épaisseur, puis
|
|
41
41
|
« Enregistrer le tampon »).
|
|
42
42
|
2. **La liste des pièces vient des dossiers juridiques enregistrés** :
|
|
43
|
-
`GET /api/admin/dossiers` → `listDossiers` bâtit la liste sur
|
|
44
|
-
|
|
43
|
+
`GET /api/admin/dossiers` → `listDossiers` bâtit la liste sur les projets
|
|
44
|
+
publiés par le serveur (`~/.piecemaker/projects.json`), et chaque
|
|
45
45
|
pièce est un **fichier original** du dossier (tout fichier qui n'est ni
|
|
46
46
|
`.md` ni `.json`, via `listOriginals`), **identifié par son chemin relatif
|
|
47
47
|
au dossier** — aucun `compilation_dossier_*.json` n'est requis. L'ancien
|