@piecemaker-legal/piecemaker 1.0.0
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/LICENSE +718 -0
- package/README.md +80 -0
- package/dist/Mistral-Icon-Gradient-RGB.svg +12 -0
- package/dist/api-docs.html +901 -0
- package/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/abnfDiagram-N423BO3Z-DjEx6DRO.js +1 -0
- package/dist/assets/arc-DYt0oU_6.js +1 -0
- package/dist/assets/architectureDiagram-T3A2C74G-Dn6DhYDe.js +36 -0
- package/dist/assets/blockDiagram-VBNYF7ZC-CsvhTLZi.js +132 -0
- package/dist/assets/c4Diagram-5PPSVZJV-BuPnjHm6.js +10 -0
- package/dist/assets/channel-Czt0N91A.js +1 -0
- package/dist/assets/chunk-2GRJ4B5K-BZJJc1-J.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-6stdrDbe.js +1 -0
- package/dist/assets/chunk-5RXB4S5H-D5UwN5cg.js +231 -0
- package/dist/assets/chunk-5VM5RSS4-BDB8AQ_I.js +15 -0
- package/dist/assets/chunk-6Q2QTUOP-RhjQ-NDz.js +88 -0
- package/dist/assets/chunk-GF5L2VYU-CJuiA7R4.js +206 -0
- package/dist/assets/chunk-JWPE2WC7-DjFkIZqh.js +1 -0
- package/dist/assets/chunk-KBJHAD2P-BeSQsoqv.js +1 -0
- package/dist/assets/chunk-RYQCIY6F-CPgwsb0o.js +1 -0
- package/dist/assets/chunk-XXDRQBXY-CMMVEsX3.js +1 -0
- package/dist/assets/classDiagram-JCYQIIEL-BrnQyrwR.js +1 -0
- package/dist/assets/classDiagram-v2-OCEON4UE-BrnQyrwR.js +1 -0
- package/dist/assets/cose-bilkent-JH36ORCC-XAdYMfi5.js +1 -0
- package/dist/assets/cynefin-VYW2F7L2-d2GpDBn-.js +178 -0
- package/dist/assets/cynefinDiagram-MW4NZA55-CGtqUrU1.js +62 -0
- package/dist/assets/cytoscape.esm-C10L9Icf.js +331 -0
- package/dist/assets/dagre-VZM6K2ZE-BxujKIsf.js +4 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/diagram-7IWD3JNH-CJn9hobL.js +30 -0
- package/dist/assets/diagram-B4RE2ZJO-DF0Cnjzz.js +3 -0
- package/dist/assets/diagram-LBJQPF4R-Bq4d3NfR.js +24 -0
- package/dist/assets/diagram-Q27KOJAE-DDdfoXt-.js +24 -0
- package/dist/assets/diagram-UB23O5K3-TSFk7FuJ.js +41 -0
- package/dist/assets/ebnfDiagram-BXEA7PRR-DRvm2Wy9.js +1 -0
- package/dist/assets/erDiagram-JOGREHBK-BmdN66-A.js +85 -0
- package/dist/assets/flowDiagram-UKHOOZJN-Dsp5LwJz.js +156 -0
- package/dist/assets/ganttDiagram-PKOTCBZU-CYfCQ4Yi.js +292 -0
- package/dist/assets/gitGraphDiagram-DS77QQ5N-DEzmuv8v.js +106 -0
- package/dist/assets/graph-Cx-EqisW.js +1 -0
- package/dist/assets/index-CqFxV_pT.css +32 -0
- package/dist/assets/index-dWwHeqcq.js +4989 -0
- package/dist/assets/infoDiagram-6WML65LV-B1EfV5Bm.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-WSZJBQD7-OuQJfUii.js +70 -0
- package/dist/assets/journeyDiagram-NVQOT4AX-DHIilb_4.js +139 -0
- package/dist/assets/kanban-definition-27J2QSJJ-D4CvKWBP.js +89 -0
- package/dist/assets/layout-D6BstSzF.js +1 -0
- package/dist/assets/linear-i_Nzyzap.js +1 -0
- package/dist/assets/map-CV9uif0g.js +1 -0
- package/dist/assets/mermaid.core-DbSHejzG.js +312 -0
- package/dist/assets/mindmap-definition-FAOFIHXS-DqhC-BPZ.js +96 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pegDiagram-VL7TDLO6-pBqvOEvm.js +1 -0
- package/dist/assets/pieDiagram-7S7Q4E2Y-BH53iuaz.js +39 -0
- package/dist/assets/quadrantDiagram-CIZ2JOQS-CvW9ldJo.js +7 -0
- package/dist/assets/railroadDiagram-AXF67PYL-CERi66oR.js +1 -0
- package/dist/assets/requirementDiagram-LRYGKXZP-DbcP4MGI.js +84 -0
- package/dist/assets/sankeyDiagram-W5VNT64P-DO9bPHWO.js +40 -0
- package/dist/assets/sequenceDiagram-SI44F4Z6-D3zd2eJS.js +162 -0
- package/dist/assets/server.browser-CtX3Hdl5.js +27 -0
- package/dist/assets/sizeCapture-X5ZJPWSS-mcEXJiem.js +1 -0
- package/dist/assets/stateDiagram-OKZ733FA-DMqQgpiD.js +1 -0
- package/dist/assets/stateDiagram-v2-UEYNNEHI-DprF_P9y.js +1 -0
- package/dist/assets/swimlanes-SLNWSIFB-Cb8rIhB1.js +2 -0
- package/dist/assets/swimlanesDiagram-ULZ7WXOC-C6NVYMho.js +8 -0
- package/dist/assets/timeline-definition-Z64GVDOM-BQ4r_QsK.js +120 -0
- package/dist/assets/vendor-codemirror-CYrSt7-U.js +41 -0
- package/dist/assets/vendor-react-BGZc9oRE.js +59 -0
- package/dist/assets/vendor-xterm-CS4rQ5Mr.js +66 -0
- package/dist/assets/vennDiagram-T6HMQDX7-BEkKGTum.js +34 -0
- package/dist/assets/wardleyDiagram-T6FBY63Y-kJwmgH-h.js +78 -0
- package/dist/assets/xychartDiagram-ELKLHX3M-CSJRTKCr.js +7 -0
- package/dist/clear-cache.html +85 -0
- package/dist/convert-icons.md +53 -0
- package/dist/favicon.png +0 -0
- package/dist/favicon.svg +9 -0
- package/dist/generate-icons.js +49 -0
- package/dist/icons/claude-ai-icon.svg +1 -0
- package/dist/icons/codex-white.svg +3 -0
- package/dist/icons/codex.svg +3 -0
- package/dist/icons/cursor-white.svg +12 -0
- package/dist/icons/cursor.svg +1 -0
- package/dist/icons/icon-128x128.png +0 -0
- package/dist/icons/icon-128x128.svg +12 -0
- package/dist/icons/icon-144x144.png +0 -0
- package/dist/icons/icon-144x144.svg +12 -0
- package/dist/icons/icon-152x152.png +0 -0
- package/dist/icons/icon-152x152.svg +12 -0
- package/dist/icons/icon-192x192.png +0 -0
- package/dist/icons/icon-192x192.svg +12 -0
- package/dist/icons/icon-384x384.png +0 -0
- package/dist/icons/icon-384x384.svg +12 -0
- package/dist/icons/icon-512x512.png +0 -0
- package/dist/icons/icon-512x512.svg +12 -0
- package/dist/icons/icon-72x72.png +0 -0
- package/dist/icons/icon-72x72.svg +12 -0
- package/dist/icons/icon-96x96.png +0 -0
- package/dist/icons/icon-96x96.svg +12 -0
- package/dist/icons/icon-template.svg +12 -0
- package/dist/index.html +60 -0
- 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.svg +17 -0
- package/dist/manifest.json +61 -0
- package/dist/screenshots/cli-selection.png +0 -0
- package/dist/screenshots/desktop-main.png +0 -0
- package/dist/screenshots/mobile-chat.png +0 -0
- package/dist/screenshots/tools-modal.png +0 -0
- package/dist/sw.js +125 -0
- package/dist-server/server/index.js +345 -0
- package/dist-server/server/index.js.map +1 -0
- package/dist-server/server/load-env.js +46 -0
- package/dist-server/server/load-env.js.map +1 -0
- package/dist-server/server/modules/agent/agent.module.js +38 -0
- package/dist-server/server/modules/agent/agent.module.js.map +1 -0
- package/dist-server/server/modules/agent/agent.routes.js +1161 -0
- package/dist-server/server/modules/agent/agent.routes.js.map +1 -0
- package/dist-server/server/modules/agent/index.js +3 -0
- package/dist-server/server/modules/agent/index.js.map +1 -0
- package/dist-server/server/modules/agent/tests/agent.routes.test.js +176 -0
- package/dist-server/server/modules/agent/tests/agent.routes.test.js.map +1 -0
- package/dist-server/server/modules/assets/assets.routes.js +130 -0
- package/dist-server/server/modules/assets/assets.routes.js.map +1 -0
- package/dist-server/server/modules/assets/index.js +4 -0
- package/dist-server/server/modules/assets/index.js.map +1 -0
- package/dist-server/server/modules/assets/services/image-assets.service.js +95 -0
- package/dist-server/server/modules/assets/services/image-assets.service.js.map +1 -0
- package/dist-server/server/modules/assets/tests/image-assets.service.test.js +56 -0
- package/dist-server/server/modules/assets/tests/image-assets.service.test.js.map +1 -0
- package/dist-server/server/modules/auth/auth.middleware.js +133 -0
- package/dist-server/server/modules/auth/auth.middleware.js.map +1 -0
- package/dist-server/server/modules/auth/auth.module.js +29 -0
- package/dist-server/server/modules/auth/auth.module.js.map +1 -0
- package/dist-server/server/modules/auth/auth.routes.js +45 -0
- package/dist-server/server/modules/auth/auth.routes.js.map +1 -0
- package/dist-server/server/modules/auth/auth.service.js +113 -0
- package/dist-server/server/modules/auth/auth.service.js.map +1 -0
- package/dist-server/server/modules/auth/index.js +9 -0
- package/dist-server/server/modules/auth/index.js.map +1 -0
- package/dist-server/server/modules/auth/tests/auth.service.test.js +80 -0
- package/dist-server/server/modules/auth/tests/auth.service.test.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use-mcp.js +352 -0
- package/dist-server/server/modules/browser-use/browser-use-mcp.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js +107 -0
- package/dist-server/server/modules/browser-use/browser-use-mcp.routes.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use-runtime.js +10 -0
- package/dist-server/server/modules/browser-use/browser-use-runtime.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use.routes.js +93 -0
- package/dist-server/server/modules/browser-use/browser-use.routes.js.map +1 -0
- package/dist-server/server/modules/browser-use/browser-use.service.js +686 -0
- package/dist-server/server/modules/browser-use/browser-use.service.js.map +1 -0
- package/dist-server/server/modules/browser-use/index.js +11 -0
- package/dist-server/server/modules/browser-use/index.js.map +1 -0
- package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js +8 -0
- package/dist-server/server/modules/browser-use/tests/browser-use.service.test.js.map +1 -0
- package/dist-server/server/modules/cli/cli.js +17 -0
- package/dist-server/server/modules/cli/cli.js.map +1 -0
- package/dist-server/server/modules/cli/cli.module.js +93 -0
- package/dist-server/server/modules/cli/cli.module.js.map +1 -0
- package/dist-server/server/modules/cli/cli.service.js +230 -0
- package/dist-server/server/modules/cli/cli.service.js.map +1 -0
- package/dist-server/server/modules/cli/index.js +3 -0
- package/dist-server/server/modules/cli/index.js.map +1 -0
- package/dist-server/server/modules/cli/pwa-launcher.js +116 -0
- package/dist-server/server/modules/cli/pwa-launcher.js.map +1 -0
- package/dist-server/server/modules/cli/sandbox.service.js +332 -0
- package/dist-server/server/modules/cli/sandbox.service.js.map +1 -0
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js +154 -0
- package/dist-server/server/modules/cli/tests/cli-environment-bootstrap.test.js.map +1 -0
- package/dist-server/server/modules/cli/tests/cli.service.test.js +91 -0
- package/dist-server/server/modules/cli/tests/cli.service.test.js.map +1 -0
- package/dist-server/server/modules/cli/tests/sandbox.service.test.js +55 -0
- package/dist-server/server/modules/cli/tests/sandbox.service.test.js.map +1 -0
- package/dist-server/server/modules/commands/commands.module.js +20 -0
- package/dist-server/server/modules/commands/commands.module.js.map +1 -0
- package/dist-server/server/modules/commands/commands.routes.js +498 -0
- package/dist-server/server/modules/commands/commands.routes.js.map +1 -0
- package/dist-server/server/modules/commands/index.js +3 -0
- package/dist-server/server/modules/commands/index.js.map +1 -0
- package/dist-server/server/modules/commands/tests/commands.test.js +91 -0
- package/dist-server/server/modules/commands/tests/commands.test.js.map +1 -0
- package/dist-server/server/modules/database/connection.js +125 -0
- package/dist-server/server/modules/database/connection.js.map +1 -0
- package/dist-server/server/modules/database/index.js +23 -0
- package/dist-server/server/modules/database/index.js.map +1 -0
- package/dist-server/server/modules/database/init-db.js +18 -0
- package/dist-server/server/modules/database/init-db.js.map +1 -0
- package/dist-server/server/modules/database/migrations.js +465 -0
- package/dist-server/server/modules/database/migrations.js.map +1 -0
- package/dist-server/server/modules/database/repositories/api-keys.js +72 -0
- package/dist-server/server/modules/database/repositories/api-keys.js.map +1 -0
- package/dist-server/server/modules/database/repositories/app-config.js +47 -0
- package/dist-server/server/modules/database/repositories/app-config.js.map +1 -0
- package/dist-server/server/modules/database/repositories/credentials.js +68 -0
- package/dist-server/server/modules/database/repositories/credentials.js.map +1 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js +54 -0
- package/dist-server/server/modules/database/repositories/github-tokens.js.map +1 -0
- package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js +100 -0
- package/dist-server/server/modules/database/repositories/notification-channel-endpoints.js.map +1 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js +82 -0
- package/dist-server/server/modules/database/repositories/notification-preferences.js.map +1 -0
- package/dist-server/server/modules/database/repositories/projects.db.js +172 -0
- package/dist-server/server/modules/database/repositories/projects.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/provider-models.js +112 -0
- package/dist-server/server/modules/database/repositories/provider-models.js.map +1 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js +49 -0
- package/dist-server/server/modules/database/repositories/push-subscriptions.js.map +1 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js +31 -0
- package/dist-server/server/modules/database/repositories/scan-state.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js +71 -0
- package/dist-server/server/modules/database/repositories/scheduled-messages.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js +105 -0
- package/dist-server/server/modules/database/repositories/session-drafts.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js +507 -0
- package/dist-server/server/modules/database/repositories/sessions.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/user-preferences.db.js +65 -0
- package/dist-server/server/modules/database/repositories/user-preferences.db.js.map +1 -0
- package/dist-server/server/modules/database/repositories/users.js +88 -0
- package/dist-server/server/modules/database/repositories/users.js.map +1 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js +38 -0
- package/dist-server/server/modules/database/repositories/vapid-keys.js.map +1 -0
- package/dist-server/server/modules/database/schema.js +291 -0
- package/dist-server/server/modules/database/schema.js.map +1 -0
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js +64 -0
- package/dist-server/server/modules/database/tests/projects.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js +102 -0
- package/dist-server/server/modules/database/tests/provider-models.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js +79 -0
- package/dist-server/server/modules/database/tests/sessions-provider-mapping.test.js.map +1 -0
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js +93 -0
- package/dist-server/server/modules/database/tests/sessions.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js +105 -0
- package/dist-server/server/modules/database/tests/user-preferences.db.integration.test.js.map +1 -0
- package/dist-server/server/modules/file-tree/file-tree.module.js +95 -0
- package/dist-server/server/modules/file-tree/file-tree.module.js.map +1 -0
- package/dist-server/server/modules/file-tree/file-tree.routes.js +208 -0
- package/dist-server/server/modules/file-tree/file-tree.routes.js.map +1 -0
- package/dist-server/server/modules/file-tree/file-tree.service.js +584 -0
- package/dist-server/server/modules/file-tree/file-tree.service.js.map +1 -0
- package/dist-server/server/modules/file-tree/index.js +3 -0
- package/dist-server/server/modules/file-tree/index.js.map +1 -0
- package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js +123 -0
- package/dist-server/server/modules/file-tree/tests/file-tree.routes.test.js.map +1 -0
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js +311 -0
- package/dist-server/server/modules/file-tree/tests/file-tree.service.test.js.map +1 -0
- package/dist-server/server/modules/git/git-branch.service.js +15 -0
- package/dist-server/server/modules/git/git-branch.service.js.map +1 -0
- package/dist-server/server/modules/git/git-parsing.service.js +61 -0
- package/dist-server/server/modules/git/git-parsing.service.js.map +1 -0
- package/dist-server/server/modules/git/git.module.js +14 -0
- package/dist-server/server/modules/git/git.module.js.map +1 -0
- package/dist-server/server/modules/git/git.routes.js +1347 -0
- package/dist-server/server/modules/git/git.routes.js.map +1 -0
- package/dist-server/server/modules/git/index.js +3 -0
- package/dist-server/server/modules/git/index.js.map +1 -0
- package/dist-server/server/modules/git/tests/git-branch.service.test.js +52 -0
- package/dist-server/server/modules/git/tests/git-branch.service.test.js.map +1 -0
- package/dist-server/server/modules/git/tests/git-init.routes.test.js +132 -0
- package/dist-server/server/modules/git/tests/git-init.routes.test.js.map +1 -0
- package/dist-server/server/modules/git/tests/git.test.js +80 -0
- package/dist-server/server/modules/git/tests/git.test.js.map +1 -0
- package/dist-server/server/modules/notifications/index.js +20 -0
- package/dist-server/server/modules/notifications/index.js.map +1 -0
- package/dist-server/server/modules/notifications/notifications.routes.js +115 -0
- package/dist-server/server/modules/notifications/notifications.routes.js.map +1 -0
- package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js +97 -0
- package/dist-server/server/modules/notifications/services/desktop-notification-clients.service.js.map +1 -0
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js +249 -0
- package/dist-server/server/modules/notifications/services/notification-orchestrator.service.js.map +1 -0
- package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js +44 -0
- package/dist-server/server/modules/notifications/tests/notification-orchestrator.integration.test.js.map +1 -0
- package/dist-server/server/modules/notifications/vapid-keys.service.js +28 -0
- package/dist-server/server/modules/notifications/vapid-keys.service.js.map +1 -0
- package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js +79 -0
- package/dist-server/server/modules/notifications/websocket/desktop-notifications-websocket.service.js.map +1 -0
- package/dist-server/server/modules/plugins/index.js +9 -0
- package/dist-server/server/modules/plugins/index.js.map +1 -0
- package/dist-server/server/modules/plugins/plugin-process.service.js +191 -0
- package/dist-server/server/modules/plugins/plugin-process.service.js.map +1 -0
- package/dist-server/server/modules/plugins/plugin-registry.service.js +415 -0
- package/dist-server/server/modules/plugins/plugin-registry.service.js.map +1 -0
- package/dist-server/server/modules/plugins/plugins.module.js +30 -0
- package/dist-server/server/modules/plugins/plugins.module.js.map +1 -0
- package/dist-server/server/modules/plugins/plugins.routes.js +70 -0
- package/dist-server/server/modules/plugins/plugins.routes.js.map +1 -0
- package/dist-server/server/modules/plugins/plugins.service.js +123 -0
- package/dist-server/server/modules/plugins/plugins.service.js.map +1 -0
- package/dist-server/server/modules/plugins/tests/plugins.service.test.js +28 -0
- package/dist-server/server/modules/plugins/tests/plugins.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/index.js +9 -0
- package/dist-server/server/modules/projects/index.js.map +1 -0
- package/dist-server/server/modules/projects/projects.routes.js +205 -0
- package/dist-server/server/modules/projects/projects.routes.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js +220 -0
- package/dist-server/server/modules/projects/services/project-clone.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js +89 -0
- package/dist-server/server/modules/projects/services/project-delete.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-management.service.js +90 -0
- package/dist-server/server/modules/projects/services/project-management.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/project-star.service.js +60 -0
- package/dist-server/server/modules/projects/services/project-star.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js +167 -0
- package/dist-server/server/modules/projects/services/projects-has-taskmaster.service.js.map +1 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js +188 -0
- package/dist-server/server/modules/projects/services/projects-with-sessions-fetch.service.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js +126 -0
- package/dist-server/server/modules/projects/tests/project-clone.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js +85 -0
- package/dist-server/server/modules/projects/tests/project-management.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js +95 -0
- package/dist-server/server/modules/projects/tests/project-star.service.test.js.map +1 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js +87 -0
- package/dist-server/server/modules/projects/tests/projects-has-taskmaster.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/index.js +12 -0
- package/dist-server/server/modules/providers/index.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js +151 -0
- package/dist-server/server/modules/providers/list/claude/claude-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js +46 -0
- package/dist-server/server/modules/providers/list/claude/claude-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js +103 -0
- package/dist-server/server/modules/providers/list/claude/claude-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js +267 -0
- package/dist-server/server/modules/providers/list/claude/claude-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js +1058 -0
- package/dist-server/server/modules/providers/list/claude/claude-runtime.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js +141 -0
- package/dist-server/server/modules/providers/list/claude/claude-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js +924 -0
- package/dist-server/server/modules/providers/list/claude/claude-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js +205 -0
- package/dist-server/server/modules/providers/list/claude/claude-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js +23 -0
- package/dist-server/server/modules/providers/list/claude/claude.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js +204 -0
- package/dist-server/server/modules/providers/list/codex/codex-app-server.client.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +84 -0
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js +32 -0
- package/dist-server/server/modules/providers/list/codex/codex-fork.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js +107 -0
- package/dist-server/server/modules/providers/list/codex/codex-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js +109 -0
- package/dist-server/server/modules/providers/list/codex/codex-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js +498 -0
- package/dist-server/server/modules/providers/list/codex/codex-runtime.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js +153 -0
- package/dist-server/server/modules/providers/list/codex/codex-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js +1955 -0
- package/dist-server/server/modules/providers/list/codex/codex-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js +62 -0
- package/dist-server/server/modules/providers/list/codex/codex-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js +23 -0
- package/dist-server/server/modules/providers/list/codex/codex.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +118 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js +80 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js +100 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js +305 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-runtime.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js +111 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js +566 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js +35 -0
- package/dist-server/server/modules/providers/list/cursor/cursor-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js +21 -0
- package/dist-server/server/modules/providers/list/cursor/cursor.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-auth.provider.js +147 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-mcp.provider.js +15 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +69 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +326 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.js +12 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-sessions.provider.js +180 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-skills.provider.js +15 -0
- package/dist-server/server/modules/providers/list/mistral/mistral-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/mistral/mistral.provider.js +25 -0
- package/dist-server/server/modules/providers/list/mistral/mistral.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js +91 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-auth.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js +181 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js +257 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-models.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js +368 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +225 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-runtime.provider.test.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js +136 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js +404 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-sessions.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js +62 -0
- package/dist-server/server/modules/providers/list/opencode/opencode-skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/list/opencode/opencode.provider.js +21 -0
- package/dist-server/server/modules/providers/list/opencode/opencode.provider.js.map +1 -0
- package/dist-server/server/modules/providers/provider.registry.js +33 -0
- package/dist-server/server/modules/providers/provider.registry.js.map +1 -0
- package/dist-server/server/modules/providers/provider.routes.js +676 -0
- package/dist-server/server/modules/providers/provider.routes.js.map +1 -0
- package/dist-server/server/modules/providers/services/mcp.service.js +84 -0
- package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js +25 -0
- package/dist-server/server/modules/providers/services/provider-auth.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js +94 -0
- package/dist-server/server/modules/providers/services/provider-capabilities.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-models.service.js +289 -0
- package/dist-server/server/modules/providers/services/provider-models.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-runtime.service.js +66 -0
- package/dist-server/server/modules/providers/services/provider-runtime.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js +372 -0
- package/dist-server/server/modules/providers/services/provider-token-usage.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js +974 -0
- package/dist-server/server/modules/providers/services/session-conversations-search.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-history-cache.service.js +87 -0
- package/dist-server/server/modules/providers/services/session-history-cache.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js +130 -0
- package/dist-server/server/modules/providers/services/session-synchronizer.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js +214 -0
- package/dist-server/server/modules/providers/services/sessions-watcher.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/sessions.service.js +519 -0
- package/dist-server/server/modules/providers/services/sessions.service.js.map +1 -0
- package/dist-server/server/modules/providers/services/skills.service.js +22 -0
- package/dist-server/server/modules/providers/services/skills.service.js.map +1 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js +13 -0
- package/dist-server/server/modules/providers/shared/base/abstract.provider.js.map +1 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js +102 -0
- package/dist-server/server/modules/providers/shared/mcp/mcp.provider.js.map +1 -0
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js +207 -0
- package/dist-server/server/modules/providers/shared/skills/skills.provider.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-auth.test.js +174 -0
- package/dist-server/server/modules/providers/tests/claude-auth.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js +470 -0
- package/dist-server/server/modules/providers/tests/claude-sessions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js +16 -0
- package/dist-server/server/modules/providers/tests/claude-subagent-echo.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js +85 -0
- package/dist-server/server/modules/providers/tests/claude-token-budget.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js +338 -0
- package/dist-server/server/modules/providers/tests/codex-message-editing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js +54 -0
- package/dist-server/server/modules/providers/tests/codex-session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js +491 -0
- package/dist-server/server/modules/providers/tests/codex-sessions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js +291 -0
- package/dist-server/server/modules/providers/tests/mcp.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/opencode-models.test.js +103 -0
- package/dist-server/server/modules/providers/tests/opencode-models.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js +424 -0
- package/dist-server/server/modules/providers/tests/opencode-sessions.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js +205 -0
- package/dist-server/server/modules/providers/tests/provider-attachment-history.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js +268 -0
- package/dist-server/server/modules/providers/tests/provider-models.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js +126 -0
- package/dist-server/server/modules/providers/tests/provider-runtime.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js +329 -0
- package/dist-server/server/modules/providers/tests/provider-token-usage.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/provider.routes.test.js +161 -0
- package/dist-server/server/modules/providers/tests/provider.routes.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-fork.test.js +113 -0
- package/dist-server/server/modules/providers/tests/session-fork.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js +120 -0
- package/dist-server/server/modules/providers/tests/session-history-cache.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js +90 -0
- package/dist-server/server/modules/providers/tests/session-orphan-prune.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js +122 -0
- package/dist-server/server/modules/providers/tests/session-synchronizer-coalescing.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/sessions-details.test.js +62 -0
- package/dist-server/server/modules/providers/tests/sessions-details.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/sessions.service.test.js +131 -0
- package/dist-server/server/modules/providers/tests/sessions.service.test.js.map +1 -0
- package/dist-server/server/modules/providers/tests/skills.test.js +398 -0
- package/dist-server/server/modules/providers/tests/skills.test.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/index.js +5 -0
- package/dist-server/server/modules/scheduled-messages/index.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js +47 -0
- package/dist-server/server/modules/scheduled-messages/scheduled-messages.routes.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js +163 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js +95 -0
- package/dist-server/server/modules/scheduled-messages/services/scheduled-messages.service.js.map +1 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js +255 -0
- package/dist-server/server/modules/scheduled-messages/tests/scheduled-messages.test.js.map +1 -0
- package/dist-server/server/modules/settings/index.js +3 -0
- package/dist-server/server/modules/settings/index.js.map +1 -0
- package/dist-server/server/modules/settings/settings.module.js +35 -0
- package/dist-server/server/modules/settings/settings.module.js.map +1 -0
- package/dist-server/server/modules/settings/settings.routes.js +34 -0
- package/dist-server/server/modules/settings/settings.routes.js.map +1 -0
- package/dist-server/server/modules/settings/settings.service.js +116 -0
- package/dist-server/server/modules/settings/settings.service.js.map +1 -0
- package/dist-server/server/modules/settings/tests/settings.service.test.js +48 -0
- package/dist-server/server/modules/settings/tests/settings.service.test.js.map +1 -0
- package/dist-server/server/modules/system/index.js +3 -0
- package/dist-server/server/modules/system/index.js.map +1 -0
- package/dist-server/server/modules/system/system.module.js +44 -0
- package/dist-server/server/modules/system/system.module.js.map +1 -0
- package/dist-server/server/modules/system/system.routes.js +16 -0
- package/dist-server/server/modules/system/system.routes.js.map +1 -0
- package/dist-server/server/modules/system/system.service.js +45 -0
- package/dist-server/server/modules/system/system.service.js.map +1 -0
- package/dist-server/server/modules/system/tests/system.service.test.js +100 -0
- package/dist-server/server/modules/system/tests/system.service.test.js.map +1 -0
- package/dist-server/server/modules/taskmaster/index.js +3 -0
- package/dist-server/server/modules/taskmaster/index.js.map +1 -0
- package/dist-server/server/modules/taskmaster/taskmaster.module.js +20 -0
- package/dist-server/server/modules/taskmaster/taskmaster.module.js.map +1 -0
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js +1372 -0
- package/dist-server/server/modules/taskmaster/taskmaster.routes.js.map +1 -0
- package/dist-server/server/modules/taskmaster/taskmaster.service.js +107 -0
- package/dist-server/server/modules/taskmaster/taskmaster.service.js.map +1 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js +180 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.routes.test.js.map +1 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js +85 -0
- package/dist-server/server/modules/taskmaster/tests/taskmaster.service.test.js.map +1 -0
- package/dist-server/server/modules/user/index.js +3 -0
- package/dist-server/server/modules/user/index.js.map +1 -0
- package/dist-server/server/modules/user/tests/user.service.test.js +123 -0
- package/dist-server/server/modules/user/tests/user.service.test.js.map +1 -0
- package/dist-server/server/modules/user/user.module.js +56 -0
- package/dist-server/server/modules/user/user.module.js.map +1 -0
- package/dist-server/server/modules/user/user.routes.js +88 -0
- package/dist-server/server/modules/user/user.routes.js.map +1 -0
- package/dist-server/server/modules/user/user.service.js +134 -0
- package/dist-server/server/modules/user/user.service.js.map +1 -0
- package/dist-server/server/modules/voice/index.js +3 -0
- package/dist-server/server/modules/voice/index.js.map +1 -0
- package/dist-server/server/modules/voice/tests/voice.service.test.js +87 -0
- package/dist-server/server/modules/voice/tests/voice.service.test.js.map +1 -0
- package/dist-server/server/modules/voice/voice.module.js +44 -0
- package/dist-server/server/modules/voice/voice.module.js.map +1 -0
- package/dist-server/server/modules/voice/voice.routes.js +87 -0
- package/dist-server/server/modules/voice/voice.routes.js.map +1 -0
- package/dist-server/server/modules/voice/voice.service.js +148 -0
- package/dist-server/server/modules/voice/voice.service.js.map +1 -0
- package/dist-server/server/modules/websocket/index.js +11 -0
- package/dist-server/server/modules/websocket/index.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js +232 -0
- package/dist-server/server/modules/websocket/services/chat-run-registry.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js +135 -0
- package/dist-server/server/modules/websocket/services/chat-session-writer.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js +467 -0
- package/dist-server/server/modules/websocket/services/chat-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js +52 -0
- package/dist-server/server/modules/websocket/services/plugin-websocket-proxy.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js +94 -0
- package/dist-server/server/modules/websocket/services/session-upsert-broadcast.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js +472 -0
- package/dist-server/server/modules/websocket/services/shell-websocket.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js +36 -0
- package/dist-server/server/modules/websocket/services/websocket-auth.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js +90 -0
- package/dist-server/server/modules/websocket/services/websocket-server.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js +14 -0
- package/dist-server/server/modules/websocket/services/websocket-state.service.js.map +1 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js +32 -0
- package/dist-server/server/modules/websocket/services/websocket-writer.service.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js +40 -0
- package/dist-server/server/modules/websocket/tests/chat-attachment-filter.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js +263 -0
- package/dist-server/server/modules/websocket/tests/chat-edit-send.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js +275 -0
- package/dist-server/server/modules/websocket/tests/chat-run-registry.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js +106 -0
- package/dist-server/server/modules/websocket/tests/session-upsert-broadcast.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js +177 -0
- package/dist-server/server/modules/websocket/tests/shell-websocket.service.test.js.map +1 -0
- package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js +61 -0
- package/dist-server/server/modules/websocket/tests/websocket-heartbeat.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/index.js +3 -0
- package/dist-server/server/modules/worktrees/index.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js +37 -0
- package/dist-server/server/modules/worktrees/services/worktree-create-and-open.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-create.service.js +67 -0
- package/dist-server/server/modules/worktrees/services/worktree-create.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-git.service.js +172 -0
- package/dist-server/server/modules/worktrees/services/worktree-git.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-list.service.js +91 -0
- package/dist-server/server/modules/worktrees/services/worktree-list.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-merge.service.js +118 -0
- package/dist-server/server/modules/worktrees/services/worktree-merge.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-open.service.js +58 -0
- package/dist-server/server/modules/worktrees/services/worktree-open.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/services/worktree-remove.service.js +65 -0
- package/dist-server/server/modules/worktrees/services/worktree-remove.service.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js +58 -0
- package/dist-server/server/modules/worktrees/tests/worktree-create-and-open.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js +85 -0
- package/dist-server/server/modules/worktrees/tests/worktree-create.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js +58 -0
- package/dist-server/server/modules/worktrees/tests/worktree-git.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js +34 -0
- package/dist-server/server/modules/worktrees/tests/worktree-list.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js +137 -0
- package/dist-server/server/modules/worktrees/tests/worktree-merge.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js +99 -0
- package/dist-server/server/modules/worktrees/tests/worktree-open.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js +157 -0
- package/dist-server/server/modules/worktrees/tests/worktree-remove.service.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js +167 -0
- package/dist-server/server/modules/worktrees/tests/worktrees.routes.test.js.map +1 -0
- package/dist-server/server/modules/worktrees/worktrees.module.js +97 -0
- package/dist-server/server/modules/worktrees/worktrees.module.js.map +1 -0
- package/dist-server/server/modules/worktrees/worktrees.routes.js +84 -0
- package/dist-server/server/modules/worktrees/worktrees.routes.js.map +1 -0
- package/dist-server/server/piecemaker/activation/claude-mcp.cjs +109 -0
- package/dist-server/server/piecemaker/activation/claude-mcp.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/claude-plugins.cjs +60 -0
- package/dist-server/server/piecemaker/activation/claude-plugins.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/codex-mcp.cjs +93 -0
- package/dist-server/server/piecemaker/activation/codex-mcp.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/errors.cjs +14 -0
- package/dist-server/server/piecemaker/activation/errors.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/library.cjs +281 -0
- package/dist-server/server/piecemaker/activation/library.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/library.test.js +281 -0
- package/dist-server/server/piecemaker/activation/library.test.js.map +1 -0
- package/dist-server/server/piecemaker/activation/markdown.cjs +103 -0
- package/dist-server/server/piecemaker/activation/markdown.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/paths.cjs +103 -0
- package/dist-server/server/piecemaker/activation/paths.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/paths.test.js +91 -0
- package/dist-server/server/piecemaker/activation/paths.test.js.map +1 -0
- package/dist-server/server/piecemaker/activation/routes.cjs +100 -0
- package/dist-server/server/piecemaker/activation/routes.cjs.map +1 -0
- package/dist-server/server/piecemaker/activation/routes.test.js +307 -0
- package/dist-server/server/piecemaker/activation/routes.test.js.map +1 -0
- package/dist-server/server/piecemaker/activation/snapshot.cjs +28 -0
- package/dist-server/server/piecemaker/activation/snapshot.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/anonymizer.test.js +282 -0
- package/dist-server/server/piecemaker/anonymizer/anonymizer.test.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/client-config.cjs +224 -0
- package/dist-server/server/piecemaker/anonymizer/client-config.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/codex-http.test.js +19 -0
- package/dist-server/server/piecemaker/anonymizer/codex-http.test.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/dictionary.cjs +163 -0
- package/dist-server/server/piecemaker/anonymizer/dictionary.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js +20 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.test.js +35 -0
- package/dist-server/server/piecemaker/anonymizer/lifecycle.test.js.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/providers.cjs +236 -0
- package/dist-server/server/piecemaker/anonymizer/providers.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/proxy.cjs +338 -0
- package/dist-server/server/piecemaker/anonymizer/proxy.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/rewrite.cjs +249 -0
- package/dist-server/server/piecemaker/anonymizer/rewrite.cjs.map +1 -0
- package/dist-server/server/piecemaker/anonymizer/service.cjs +217 -0
- package/dist-server/server/piecemaker/anonymizer/service.cjs.map +1 -0
- package/dist-server/server/piecemaker/harness/chat-harness.js +157 -0
- package/dist-server/server/piecemaker/harness/chat-harness.js.map +1 -0
- package/dist-server/server/piecemaker/harness/chat-harness.test.js +120 -0
- package/dist-server/server/piecemaker/harness/chat-harness.test.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citation-instructions.js +17 -0
- package/dist-server/server/piecemaker/harness/citation-instructions.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citation-store.js +72 -0
- package/dist-server/server/piecemaker/harness/citation-store.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citation-turn.js +211 -0
- package/dist-server/server/piecemaker/harness/citation-turn.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citation-turn.test.js +144 -0
- package/dist-server/server/piecemaker/harness/citation-turn.test.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citations.routes.js +16 -0
- package/dist-server/server/piecemaker/harness/citations.routes.js.map +1 -0
- package/dist-server/server/piecemaker/harness/citations.routes.test.js +68 -0
- package/dist-server/server/piecemaker/harness/citations.routes.test.js.map +1 -0
- package/dist-server/server/piecemaker/harness/decisions.cjs +298 -0
- package/dist-server/server/piecemaker/harness/decisions.cjs.map +1 -0
- package/dist-server/server/piecemaker/harness/flux-sse.cjs +108 -0
- package/dist-server/server/piecemaker/harness/flux-sse.cjs.map +1 -0
- package/dist-server/server/piecemaker/harness/harness.test.js +259 -0
- package/dist-server/server/piecemaker/harness/harness.test.js.map +1 -0
- package/dist-server/server/piecemaker/harness/index.cjs +100 -0
- package/dist-server/server/piecemaker/harness/index.cjs.map +1 -0
- package/dist-server/server/piecemaker/harness/proxy-harness.test.js +199 -0
- package/dist-server/server/piecemaker/harness/proxy-harness.test.js.map +1 -0
- package/dist-server/server/piecemaker/harness/source-passages.js +19 -0
- package/dist-server/server/piecemaker/harness/source-passages.js.map +1 -0
- package/dist-server/server/piecemaker/harness/verification.cjs +152 -0
- package/dist-server/server/piecemaker/harness/verification.cjs.map +1 -0
- package/dist-server/server/piecemaker/index.js +46 -0
- package/dist-server/server/piecemaker/index.js.map +1 -0
- package/dist-server/server/piecemaker/library/index.js +66 -0
- package/dist-server/server/piecemaker/library/index.js.map +1 -0
- package/dist-server/server/piecemaker/library/marketplace.js +204 -0
- package/dist-server/server/piecemaker/library/marketplace.js.map +1 -0
- package/dist-server/server/piecemaker/library/migrate-cli.js +13 -0
- package/dist-server/server/piecemaker/library/migrate-cli.js.map +1 -0
- package/dist-server/server/piecemaker/library/migrate.js +53 -0
- package/dist-server/server/piecemaker/library/migrate.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-skills.js +40 -0
- package/dist-server/server/piecemaker/library/provider-skills.js.map +1 -0
- package/dist-server/server/piecemaker/library/provider-skills.test.js +55 -0
- package/dist-server/server/piecemaker/library/provider-skills.test.js.map +1 -0
- package/dist-server/server/piecemaker/library/routes.js +56 -0
- package/dist-server/server/piecemaker/library/routes.js.map +1 -0
- package/dist-server/server/piecemaker/library/runtime.js +34 -0
- package/dist-server/server/piecemaker/library/runtime.js.map +1 -0
- package/dist-server/server/piecemaker/library/store.js +440 -0
- package/dist-server/server/piecemaker/library/store.js.map +1 -0
- package/dist-server/server/piecemaker/library/store.test.js +265 -0
- package/dist-server/server/piecemaker/library/store.test.js.map +1 -0
- package/dist-server/server/piecemaker/library/workspace-installation.js +70 -0
- package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -0
- package/dist-server/server/piecemaker/originals-cache.cjs +45 -0
- package/dist-server/server/piecemaker/originals-cache.cjs.map +1 -0
- package/dist-server/server/piecemaker/originals-cache.test.js +68 -0
- package/dist-server/server/piecemaker/originals-cache.test.js.map +1 -0
- package/dist-server/server/piecemaker/protection/bypass.cjs +66 -0
- package/dist-server/server/piecemaker/protection/bypass.cjs.map +1 -0
- package/dist-server/server/piecemaker/protection/bypass.test.js +117 -0
- package/dist-server/server/piecemaker/protection/bypass.test.js.map +1 -0
- package/dist-server/server/piecemaker/protection/routes.cjs +38 -0
- package/dist-server/server/piecemaker/protection/routes.cjs.map +1 -0
- package/dist-server/server/piecemaker/timesheet/index.js +9 -0
- package/dist-server/server/piecemaker/timesheet/index.js.map +1 -0
- package/dist-server/server/piecemaker/timesheet/routes.js +42 -0
- package/dist-server/server/piecemaker/timesheet/routes.js.map +1 -0
- package/dist-server/server/piecemaker/timesheet/service.js +241 -0
- package/dist-server/server/piecemaker/timesheet/service.js.map +1 -0
- package/dist-server/server/piecemaker/timesheet/service.test.js +124 -0
- package/dist-server/server/piecemaker/timesheet/service.test.js.map +1 -0
- package/dist-server/server/piecemaker/timesheet/store.js +126 -0
- package/dist-server/server/piecemaker/timesheet/store.js.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs +147 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +285 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +87 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs +526 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs +304 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs +1660 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs +152 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs +84 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +332 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js +64 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +420 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs +91 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +304 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs +293 -0
- package/dist-server/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs +5 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.cjs +91 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.cjs.map +1 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.test.js +11 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/legal-forms.test.js.map +1 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +955 -0
- package/dist-server/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs.map +1 -0
- package/dist-server/server/shared/claude-cli-path.js +120 -0
- package/dist-server/server/shared/claude-cli-path.js.map +1 -0
- package/dist-server/server/shared/frontmatter.js +16 -0
- package/dist-server/server/shared/frontmatter.js.map +1 -0
- package/dist-server/server/shared/image-attachments.js +344 -0
- package/dist-server/server/shared/image-attachments.js.map +1 -0
- package/dist-server/server/shared/interfaces.js +2 -0
- package/dist-server/server/shared/interfaces.js.map +1 -0
- package/dist-server/server/shared/message-unification.js +376 -0
- package/dist-server/server/shared/message-unification.js.map +1 -0
- package/dist-server/server/shared/tests/application-data-root.test.js +33 -0
- package/dist-server/server/shared/tests/application-data-root.test.js.map +1 -0
- package/dist-server/server/shared/tests/claude-cli-path.test.js +89 -0
- package/dist-server/server/shared/tests/claude-cli-path.test.js.map +1 -0
- package/dist-server/server/shared/tests/image-attachments.test.js +262 -0
- package/dist-server/server/shared/tests/image-attachments.test.js.map +1 -0
- package/dist-server/server/shared/tests/message-unification.test.js +174 -0
- package/dist-server/server/shared/tests/message-unification.test.js.map +1 -0
- package/dist-server/server/shared/tests/slice-tail-page.test.js +35 -0
- package/dist-server/server/shared/tests/slice-tail-page.test.js.map +1 -0
- package/dist-server/server/shared/types.js +2 -0
- package/dist-server/server/shared/types.js.map +1 -0
- package/dist-server/server/shared/utils.js +1010 -0
- package/dist-server/server/shared/utils.js.map +1 -0
- package/dist-server/shared/networkHosts.js +20 -0
- package/dist-server/shared/networkHosts.js.map +1 -0
- package/dist-server/shared/product-config.mjs +79 -0
- package/dist-server/shared/product-config.mjs.map +1 -0
- package/package.json +271 -0
- package/product.config.json +17 -0
- package/public/api-docs.html +901 -0
- package/scripts/fix-node-pty.js +67 -0
- package/scripts/piecemaker/cli/install-command.mjs +130 -0
- package/scripts/piecemaker/cli/lib/composants.mjs +68 -0
- package/scripts/piecemaker/cli/lib/config.mjs +32 -0
- package/scripts/piecemaker/cli/lib/exec.mjs +79 -0
- package/scripts/piecemaker/cli/lib/node-runtime.mjs +76 -0
- package/scripts/piecemaker/cli/lib/ports.mjs +96 -0
- package/scripts/piecemaker/cli/lib/pwa.mjs +323 -0
- package/scripts/piecemaker/cli/lib/repos.mjs +140 -0
- package/scripts/piecemaker/cli/lib/services.mjs +71 -0
- package/scripts/piecemaker/cli/lib/ui.mjs +41 -0
- package/scripts/piecemaker/cli/piecemaker.mjs +159 -0
- package/scripts/piecemaker/cli/piecemaker.ps1 +63 -0
- package/scripts/piecemaker/cli/piecemaker.sh +60 -0
- package/scripts/piecemaker/generate-i18n-overrides.mjs +219 -0
- package/scripts/piecemaker/hooks/proxy-guard.mjs +286 -0
- package/scripts/promote-dist-server.mjs +50 -0
- package/scripts/release/build-server-bundle.js +178 -0
- package/scripts/release/package-piecemaker.sh +73 -0
- package/scripts/release/prepare-desktop-app.js +168 -0
- package/server/index.ts +410 -0
- package/server/load-env.ts +48 -0
- package/server/modules/agent/agent.module.ts +52 -0
- package/server/modules/agent/agent.routes.ts +1287 -0
- package/server/modules/agent/index.ts +2 -0
- package/server/modules/agent/tests/agent.routes.test.ts +205 -0
- package/server/modules/assets/assets.routes.ts +150 -0
- package/server/modules/assets/index.ts +3 -0
- package/server/modules/assets/services/image-assets.service.ts +127 -0
- package/server/modules/assets/tests/image-assets.service.test.ts +74 -0
- package/server/modules/auth/auth.middleware.ts +163 -0
- package/server/modules/auth/auth.module.ts +38 -0
- package/server/modules/auth/auth.routes.ts +57 -0
- package/server/modules/auth/auth.service.ts +155 -0
- package/server/modules/auth/index.ts +9 -0
- package/server/modules/auth/tests/auth.service.test.ts +95 -0
- package/server/modules/browser-use/browser-use-mcp.routes.ts +120 -0
- package/server/modules/browser-use/browser-use-mcp.ts +386 -0
- package/server/modules/browser-use/browser-use-runtime.ts +10 -0
- package/server/modules/browser-use/browser-use.routes.ts +96 -0
- package/server/modules/browser-use/browser-use.service.ts +835 -0
- package/server/modules/browser-use/index.ts +11 -0
- package/server/modules/browser-use/tests/browser-use.service.test.ts +10 -0
- package/server/modules/cli/cli.module.ts +110 -0
- package/server/modules/cli/cli.service.ts +266 -0
- package/server/modules/cli/cli.ts +19 -0
- package/server/modules/cli/index.ts +2 -0
- package/server/modules/cli/pwa-launcher.ts +131 -0
- package/server/modules/cli/sandbox.service.ts +413 -0
- package/server/modules/cli/tests/cli-environment-bootstrap.test.ts +186 -0
- package/server/modules/cli/tests/cli.service.test.ts +107 -0
- package/server/modules/cli/tests/sandbox.service.test.ts +61 -0
- package/server/modules/commands/commands.module.ts +22 -0
- package/server/modules/commands/commands.routes.ts +605 -0
- package/server/modules/commands/index.ts +2 -0
- package/server/modules/commands/tests/commands.test.ts +114 -0
- package/server/modules/database/connection.ts +144 -0
- package/server/modules/database/index.ts +27 -0
- package/server/modules/database/init-db.ts +17 -0
- package/server/modules/database/migrations.ts +552 -0
- package/server/modules/database/repositories/api-keys.ts +119 -0
- package/server/modules/database/repositories/app-config.ts +53 -0
- package/server/modules/database/repositories/credentials.ts +106 -0
- package/server/modules/database/repositories/github-tokens.ts +100 -0
- package/server/modules/database/repositories/notification-channel-endpoints.ts +153 -0
- package/server/modules/database/repositories/notification-preferences.ts +117 -0
- package/server/modules/database/repositories/projects.db.ts +196 -0
- package/server/modules/database/repositories/provider-models.ts +168 -0
- package/server/modules/database/repositories/push-subscriptions.ts +80 -0
- package/server/modules/database/repositories/scan-state.db.ts +42 -0
- package/server/modules/database/repositories/scheduled-messages.db.ts +127 -0
- package/server/modules/database/repositories/session-drafts.db.ts +171 -0
- package/server/modules/database/repositories/sessions.db.ts +714 -0
- package/server/modules/database/repositories/user-preferences.db.ts +80 -0
- package/server/modules/database/repositories/users.ts +140 -0
- package/server/modules/database/repositories/vapid-keys.ts +57 -0
- package/server/modules/database/schema.ts +306 -0
- package/server/modules/database/tests/projects.db.integration.test.ts +72 -0
- package/server/modules/database/tests/provider-models.db.integration.test.ts +125 -0
- package/server/modules/database/tests/sessions-provider-mapping.test.ts +109 -0
- package/server/modules/database/tests/sessions.db.integration.test.ts +116 -0
- package/server/modules/database/tests/user-preferences.db.integration.test.ts +135 -0
- package/server/modules/file-tree/file-tree.module.ts +116 -0
- package/server/modules/file-tree/file-tree.routes.ts +258 -0
- package/server/modules/file-tree/file-tree.service.ts +675 -0
- package/server/modules/file-tree/index.ts +2 -0
- package/server/modules/file-tree/tests/file-tree.routes.test.ts +157 -0
- package/server/modules/file-tree/tests/file-tree.service.test.ts +371 -0
- package/server/modules/git/git-branch.service.ts +43 -0
- package/server/modules/git/git-parsing.service.ts +66 -0
- package/server/modules/git/git.module.ts +22 -0
- package/server/modules/git/git.routes.ts +1600 -0
- package/server/modules/git/index.ts +2 -0
- package/server/modules/git/tests/git-branch.service.test.ts +60 -0
- package/server/modules/git/tests/git-init.routes.test.ts +135 -0
- package/server/modules/git/tests/git.test.ts +106 -0
- package/server/modules/notifications/index.ts +24 -0
- package/server/modules/notifications/notifications.routes.ts +127 -0
- package/server/modules/notifications/services/desktop-notification-clients.service.ts +124 -0
- package/server/modules/notifications/services/notification-orchestrator.service.js +310 -0
- package/server/modules/notifications/tests/notification-orchestrator.integration.test.ts +55 -0
- package/server/modules/notifications/vapid-keys.service.ts +38 -0
- package/server/modules/notifications/websocket/desktop-notifications-websocket.service.ts +109 -0
- package/server/modules/plugins/index.ts +9 -0
- package/server/modules/plugins/plugin-process.service.ts +217 -0
- package/server/modules/plugins/plugin-registry.service.ts +461 -0
- package/server/modules/plugins/plugins.module.ts +33 -0
- package/server/modules/plugins/plugins.routes.ts +66 -0
- package/server/modules/plugins/plugins.service.ts +147 -0
- package/server/modules/plugins/tests/plugins.service.test.ts +32 -0
- package/server/modules/projects/index.ts +11 -0
- package/server/modules/projects/projects.routes.ts +273 -0
- package/server/modules/projects/services/project-clone.service.ts +323 -0
- package/server/modules/projects/services/project-delete.service.ts +102 -0
- package/server/modules/projects/services/project-management.service.ts +144 -0
- package/server/modules/projects/services/project-star.service.ts +78 -0
- package/server/modules/projects/services/projects-has-taskmaster.service.ts +248 -0
- package/server/modules/projects/services/projects-with-sessions-fetch.service.ts +314 -0
- package/server/modules/projects/tests/project-clone.service.test.ts +183 -0
- package/server/modules/projects/tests/project-management.service.test.ts +117 -0
- package/server/modules/projects/tests/project-star.service.test.ts +123 -0
- package/server/modules/projects/tests/projects-has-taskmaster.service.test.ts +105 -0
- package/server/modules/providers/README.md +380 -0
- package/server/modules/providers/index.ts +14 -0
- package/server/modules/providers/list/claude/claude-auth.provider.ts +180 -0
- package/server/modules/providers/list/claude/claude-fork.provider.ts +57 -0
- package/server/modules/providers/list/claude/claude-mcp.provider.ts +135 -0
- package/server/modules/providers/list/claude/claude-models.provider.ts +314 -0
- package/server/modules/providers/list/claude/claude-runtime.provider.js +1217 -0
- package/server/modules/providers/list/claude/claude-session-synchronizer.provider.ts +203 -0
- package/server/modules/providers/list/claude/claude-sessions.provider.ts +1108 -0
- package/server/modules/providers/list/claude/claude-skills.provider.ts +265 -0
- package/server/modules/providers/list/claude/claude.provider.ts +33 -0
- package/server/modules/providers/list/codex/codex-app-server.client.ts +243 -0
- package/server/modules/providers/list/codex/codex-auth.provider.ts +100 -0
- package/server/modules/providers/list/codex/codex-fork.provider.ts +40 -0
- package/server/modules/providers/list/codex/codex-mcp.provider.ts +135 -0
- package/server/modules/providers/list/codex/codex-models.provider.ts +123 -0
- package/server/modules/providers/list/codex/codex-runtime.provider.js +572 -0
- package/server/modules/providers/list/codex/codex-session-synchronizer.provider.ts +212 -0
- package/server/modules/providers/list/codex/codex-sessions.provider.ts +2267 -0
- package/server/modules/providers/list/codex/codex-skills.provider.ts +73 -0
- package/server/modules/providers/list/codex/codex.provider.ts +33 -0
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +143 -0
- package/server/modules/providers/list/cursor/cursor-mcp.provider.ts +108 -0
- package/server/modules/providers/list/cursor/cursor-models.provider.ts +119 -0
- package/server/modules/providers/list/cursor/cursor-runtime.provider.js +387 -0
- package/server/modules/providers/list/cursor/cursor-session-synchronizer.provider.ts +158 -0
- package/server/modules/providers/list/cursor/cursor-sessions.provider.ts +654 -0
- package/server/modules/providers/list/cursor/cursor-skills.provider.ts +39 -0
- package/server/modules/providers/list/cursor/cursor.provider.ts +30 -0
- package/server/modules/providers/list/mistral/mistral-auth.provider.ts +181 -0
- package/server/modules/providers/list/mistral/mistral-mcp.provider.ts +20 -0
- package/server/modules/providers/list/mistral/mistral-models.provider.ts +76 -0
- package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +417 -0
- package/server/modules/providers/list/mistral/mistral-session-synchronizer.provider.ts +15 -0
- package/server/modules/providers/list/mistral/mistral-sessions.provider.ts +210 -0
- package/server/modules/providers/list/mistral/mistral-skills.provider.ts +20 -0
- package/server/modules/providers/list/mistral/mistral.provider.ts +35 -0
- package/server/modules/providers/list/opencode/opencode-auth.provider.ts +110 -0
- package/server/modules/providers/list/opencode/opencode-mcp.provider.ts +228 -0
- package/server/modules/providers/list/opencode/opencode-models.provider.ts +304 -0
- package/server/modules/providers/list/opencode/opencode-runtime.provider.js +434 -0
- package/server/modules/providers/list/opencode/opencode-runtime.provider.test.js +261 -0
- package/server/modules/providers/list/opencode/opencode-session-synchronizer.provider.ts +179 -0
- package/server/modules/providers/list/opencode/opencode-sessions.provider.ts +500 -0
- package/server/modules/providers/list/opencode/opencode-skills.provider.ts +78 -0
- package/server/modules/providers/list/opencode/opencode.provider.ts +30 -0
- package/server/modules/providers/provider.registry.ts +38 -0
- package/server/modules/providers/provider.routes.ts +909 -0
- package/server/modules/providers/services/mcp.service.ts +109 -0
- package/server/modules/providers/services/provider-auth.service.ts +26 -0
- package/server/modules/providers/services/provider-capabilities.service.ts +133 -0
- package/server/modules/providers/services/provider-models.service.ts +401 -0
- package/server/modules/providers/services/provider-runtime.service.ts +108 -0
- package/server/modules/providers/services/provider-token-usage.service.ts +484 -0
- package/server/modules/providers/services/session-conversations-search.service.ts +1321 -0
- package/server/modules/providers/services/session-history-cache.service.ts +139 -0
- package/server/modules/providers/services/session-synchronizer.service.ts +162 -0
- package/server/modules/providers/services/sessions-watcher.service.ts +266 -0
- package/server/modules/providers/services/sessions.service.ts +663 -0
- package/server/modules/providers/services/skills.service.ts +39 -0
- package/server/modules/providers/shared/base/abstract.provider.ts +32 -0
- package/server/modules/providers/shared/mcp/mcp.provider.ts +151 -0
- package/server/modules/providers/shared/skills/skills.provider.ts +287 -0
- package/server/modules/providers/tests/claude-auth.test.ts +208 -0
- package/server/modules/providers/tests/claude-sessions.test.ts +573 -0
- package/server/modules/providers/tests/claude-subagent-echo.test.ts +25 -0
- package/server/modules/providers/tests/claude-token-budget.test.ts +104 -0
- package/server/modules/providers/tests/codex-message-editing.test.ts +419 -0
- package/server/modules/providers/tests/codex-session-fork.test.ts +59 -0
- package/server/modules/providers/tests/codex-sessions.test.ts +553 -0
- package/server/modules/providers/tests/mcp.test.ts +349 -0
- package/server/modules/providers/tests/opencode-models.test.ts +154 -0
- package/server/modules/providers/tests/opencode-sessions.test.ts +522 -0
- package/server/modules/providers/tests/provider-attachment-history.test.ts +247 -0
- package/server/modules/providers/tests/provider-models.service.test.ts +353 -0
- package/server/modules/providers/tests/provider-runtime.service.test.ts +138 -0
- package/server/modules/providers/tests/provider-token-usage.service.test.ts +373 -0
- package/server/modules/providers/tests/provider.routes.test.ts +244 -0
- package/server/modules/providers/tests/session-fork.test.ts +173 -0
- package/server/modules/providers/tests/session-history-cache.service.test.ts +143 -0
- package/server/modules/providers/tests/session-orphan-prune.test.ts +107 -0
- package/server/modules/providers/tests/session-synchronizer-coalescing.test.ts +136 -0
- package/server/modules/providers/tests/sessions-details.test.ts +73 -0
- package/server/modules/providers/tests/sessions.service.test.ts +193 -0
- package/server/modules/providers/tests/skills.test.ts +692 -0
- package/server/modules/scheduled-messages/index.ts +8 -0
- package/server/modules/scheduled-messages/scheduled-messages.routes.ts +68 -0
- package/server/modules/scheduled-messages/services/scheduled-message-dispatcher.service.ts +203 -0
- package/server/modules/scheduled-messages/services/scheduled-messages.service.ts +121 -0
- package/server/modules/scheduled-messages/tests/scheduled-messages.test.ts +310 -0
- package/server/modules/settings/index.ts +2 -0
- package/server/modules/settings/settings.module.ts +50 -0
- package/server/modules/settings/settings.routes.ts +51 -0
- package/server/modules/settings/settings.service.ts +186 -0
- package/server/modules/settings/tests/settings.service.test.ts +54 -0
- package/server/modules/system/index.ts +2 -0
- package/server/modules/system/system.module.ts +62 -0
- package/server/modules/system/system.routes.ts +21 -0
- package/server/modules/system/system.service.ts +76 -0
- package/server/modules/system/tests/system.service.test.ts +118 -0
- package/server/modules/taskmaster/index.ts +2 -0
- package/server/modules/taskmaster/taskmaster.module.ts +24 -0
- package/server/modules/taskmaster/taskmaster.routes.ts +1472 -0
- package/server/modules/taskmaster/taskmaster.service.ts +132 -0
- package/server/modules/taskmaster/tests/taskmaster.routes.test.ts +201 -0
- package/server/modules/taskmaster/tests/taskmaster.service.test.ts +97 -0
- package/server/modules/user/index.ts +2 -0
- package/server/modules/user/tests/user.service.test.ts +151 -0
- package/server/modules/user/user.module.ts +67 -0
- package/server/modules/user/user.routes.ts +94 -0
- package/server/modules/user/user.service.ts +190 -0
- package/server/modules/voice/index.ts +2 -0
- package/server/modules/voice/tests/voice.service.test.ts +99 -0
- package/server/modules/voice/voice.module.ts +47 -0
- package/server/modules/voice/voice.routes.ts +113 -0
- package/server/modules/voice/voice.service.ts +192 -0
- package/server/modules/websocket/README.md +273 -0
- package/server/modules/websocket/index.ts +11 -0
- package/server/modules/websocket/services/chat-run-registry.service.ts +310 -0
- package/server/modules/websocket/services/chat-session-writer.service.ts +175 -0
- package/server/modules/websocket/services/chat-websocket.service.ts +654 -0
- package/server/modules/websocket/services/plugin-websocket-proxy.service.ts +65 -0
- package/server/modules/websocket/services/session-upsert-broadcast.service.ts +108 -0
- package/server/modules/websocket/services/shell-websocket.service.ts +628 -0
- package/server/modules/websocket/services/websocket-auth.service.ts +59 -0
- package/server/modules/websocket/services/websocket-server.service.ts +126 -0
- package/server/modules/websocket/services/websocket-state.service.ts +16 -0
- package/server/modules/websocket/services/websocket-writer.service.ts +38 -0
- package/server/modules/websocket/tests/chat-attachment-filter.test.ts +59 -0
- package/server/modules/websocket/tests/chat-edit-send.test.ts +309 -0
- package/server/modules/websocket/tests/chat-run-registry.test.ts +313 -0
- package/server/modules/websocket/tests/session-upsert-broadcast.test.ts +138 -0
- package/server/modules/websocket/tests/shell-websocket.service.test.ts +227 -0
- package/server/modules/websocket/tests/websocket-heartbeat.service.test.ts +78 -0
- package/server/modules/worktrees/index.ts +2 -0
- package/server/modules/worktrees/services/worktree-create-and-open.service.ts +53 -0
- package/server/modules/worktrees/services/worktree-create.service.ts +104 -0
- package/server/modules/worktrees/services/worktree-git.service.ts +207 -0
- package/server/modules/worktrees/services/worktree-list.service.ts +143 -0
- package/server/modules/worktrees/services/worktree-merge.service.ts +157 -0
- package/server/modules/worktrees/services/worktree-open.service.ts +85 -0
- package/server/modules/worktrees/services/worktree-remove.service.ts +88 -0
- package/server/modules/worktrees/tests/worktree-create-and-open.service.test.ts +68 -0
- package/server/modules/worktrees/tests/worktree-create.service.test.ts +142 -0
- package/server/modules/worktrees/tests/worktree-git.service.test.ts +84 -0
- package/server/modules/worktrees/tests/worktree-list.service.test.ts +45 -0
- package/server/modules/worktrees/tests/worktree-merge.service.test.ts +213 -0
- package/server/modules/worktrees/tests/worktree-open.service.test.ts +122 -0
- package/server/modules/worktrees/tests/worktree-remove.service.test.ts +227 -0
- package/server/modules/worktrees/tests/worktrees.routes.test.ts +199 -0
- package/server/modules/worktrees/worktrees.module.ts +113 -0
- package/server/modules/worktrees/worktrees.routes.ts +116 -0
- package/server/piecemaker/activation/claude-mcp.cjs +115 -0
- package/server/piecemaker/activation/claude-plugins.cjs +65 -0
- package/server/piecemaker/activation/codex-mcp.cjs +102 -0
- package/server/piecemaker/activation/errors.cjs +15 -0
- package/server/piecemaker/activation/index.cjs +5 -0
- package/server/piecemaker/activation/library.cjs +284 -0
- package/server/piecemaker/activation/library.cjs.bak +223 -0
- package/server/piecemaker/activation/library.test.js +365 -0
- package/server/piecemaker/activation/markdown.cjs +108 -0
- package/server/piecemaker/activation/markdown.cjs.bak +78 -0
- package/server/piecemaker/activation/paths.cjs +104 -0
- package/server/piecemaker/activation/paths.test.js +158 -0
- package/server/piecemaker/activation/routes.cjs +101 -0
- package/server/piecemaker/activation/routes.test.js +344 -0
- package/server/piecemaker/activation/snapshot.cjs +30 -0
- package/server/piecemaker/anonymizer/anonymizer.test.js +320 -0
- package/server/piecemaker/anonymizer/client-config.cjs +228 -0
- package/server/piecemaker/anonymizer/codex-http.test.js +20 -0
- package/server/piecemaker/anonymizer/dictionary.cjs +174 -0
- package/server/piecemaker/anonymizer/lifecycle.test.ts +37 -0
- package/server/piecemaker/anonymizer/lifecycle.ts +22 -0
- package/server/piecemaker/anonymizer/providers.cjs +241 -0
- package/server/piecemaker/anonymizer/proxy.cjs +365 -0
- package/server/piecemaker/anonymizer/rewrite.cjs +251 -0
- package/server/piecemaker/anonymizer/routes.cjs +43 -0
- package/server/piecemaker/anonymizer/service.cjs +218 -0
- package/server/piecemaker/harness/chat-harness.test.ts +131 -0
- package/server/piecemaker/harness/chat-harness.ts +151 -0
- package/server/piecemaker/harness/citation-instructions.ts +18 -0
- package/server/piecemaker/harness/citation-store.ts +80 -0
- package/server/piecemaker/harness/citation-turn.test.ts +155 -0
- package/server/piecemaker/harness/citation-turn.ts +197 -0
- package/server/piecemaker/harness/citations.routes.test.ts +68 -0
- package/server/piecemaker/harness/citations.routes.ts +18 -0
- package/server/piecemaker/harness/decisions.cjs +302 -0
- package/server/piecemaker/harness/flux-sse.cjs +111 -0
- package/server/piecemaker/harness/harness.test.js +296 -0
- package/server/piecemaker/harness/index.cjs +103 -0
- package/server/piecemaker/harness/proxy-harness.test.js +226 -0
- package/server/piecemaker/harness/source-passages.ts +21 -0
- package/server/piecemaker/harness/verification.cjs +159 -0
- package/server/piecemaker/index.ts +59 -0
- package/server/piecemaker/library/index.ts +54 -0
- package/server/piecemaker/library/marketplace.ts +152 -0
- package/server/piecemaker/library/migrate-cli.ts +11 -0
- package/server/piecemaker/library/migrate.ts +49 -0
- package/server/piecemaker/library/policy.cjs +9 -0
- package/server/piecemaker/library/provider-skills.test.ts +61 -0
- package/server/piecemaker/library/provider-skills.ts +48 -0
- package/server/piecemaker/library/routes.ts +38 -0
- package/server/piecemaker/library/runtime.ts +39 -0
- package/server/piecemaker/library/store.test.ts +280 -0
- package/server/piecemaker/library/store.ts +429 -0
- package/server/piecemaker/library/workspace-installation.ts +61 -0
- package/server/piecemaker/originals-cache.cjs +54 -0
- package/server/piecemaker/originals-cache.test.js +77 -0
- package/server/piecemaker/protection/bypass.cjs +73 -0
- package/server/piecemaker/protection/bypass.test.js +140 -0
- package/server/piecemaker/protection/routes.cjs +39 -0
- package/server/piecemaker/router.cjs +109 -0
- package/server/piecemaker/timesheet/index.ts +9 -0
- package/server/piecemaker/timesheet/routes.ts +48 -0
- package/server/piecemaker/timesheet/service.test.ts +142 -0
- package/server/piecemaker/timesheet/service.ts +298 -0
- package/server/piecemaker/timesheet/store.ts +167 -0
- package/server/piecemaker/vendor/.env +2 -0
- package/server/piecemaker/vendor/installer/assets/PieceMakerApp.swift +189 -0
- package/server/piecemaker/vendor/installer/assets/claude-hooks/piecemaker-guard-secrets.mjs +230 -0
- package/server/piecemaker/vendor/installer/assets/claude-hooks/piecemaker-secret-paths.default.json +1 -0
- package/server/piecemaker/vendor/installer/assets/piecemaker.icns +0 -0
- package/server/piecemaker/vendor/installer/assets/piecemaker.ico +0 -0
- package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +1018 -0
- package/server/piecemaker/vendor/installer/lib/banner.mjs +35 -0
- package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +343 -0
- package/server/piecemaker/vendor/installer/lib/commandes.mjs +13 -0
- package/server/piecemaker/vendor/installer/lib/desktop-launcher.mjs +305 -0
- package/server/piecemaker/vendor/installer/lib/legacy-legifrance.mjs +72 -0
- package/server/piecemaker/vendor/installer/lib/platform.mjs +163 -0
- package/server/piecemaker/vendor/installer/lib/prompt.mjs +138 -0
- package/server/piecemaker/vendor/installer/lib/resume-steps.mjs +174 -0
- package/server/piecemaker/vendor/installer/lib/secrets-guard.mjs +193 -0
- package/server/piecemaker/vendor/installer/lib/service.mjs +467 -0
- package/server/piecemaker/vendor/installer/lib/state.mjs +114 -0
- package/server/piecemaker/vendor/installer/lib/ui.mjs +159 -0
- package/server/piecemaker/vendor/installer/steps/00-identite.mjs +71 -0
- package/server/piecemaker/vendor/installer/steps/01-prerequis.mjs +119 -0
- package/server/piecemaker/vendor/installer/steps/02-dependances-node.mjs +127 -0
- package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +249 -0
- package/server/piecemaker/vendor/installer/steps/03b-python-graphify.mjs +161 -0
- package/server/piecemaker/vendor/installer/steps/04-conversion-md.mjs +147 -0
- package/server/piecemaker/vendor/installer/steps/05-certificats.mjs +171 -0
- package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +266 -0
- package/server/piecemaker/vendor/installer/steps/07-legifrance.mjs +279 -0
- package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +482 -0
- package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +151 -0
- package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +142 -0
- package/server/piecemaker/vendor/installer/steps/10-libreoffice.mjs +130 -0
- package/server/piecemaker/vendor/installer/steps/10-pandoc.mjs +212 -0
- package/server/piecemaker/vendor/installer/steps/11-docx-cli.mjs +144 -0
- package/server/piecemaker/vendor/installer/steps/12-mcp-piecemaker.mjs +124 -0
- package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +136 -0
- package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +271 -0
- package/server/piecemaker/vendor/installer/steps/15-pwa-desktop.mjs +64 -0
- package/server/piecemaker/vendor/installer/templates/root-CLAUDE.md +79 -0
- package/server/piecemaker/vendor/installer/templates/workspace-CLAUDE.md +111 -0
- package/server/piecemaker/vendor/mcp/README.md +13 -0
- package/server/piecemaker/vendor/mcp/piecemaker/server.mjs +222 -0
- package/server/piecemaker/vendor/mike-defaults-fr/PROVENANCE.md +10 -0
- package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/compare-documents/SKILL.md +51 -0
- package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/draft-from-template/SKILL.md +27 -0
- package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/extract-key-terms/SKILL.md +43 -0
- package/server/piecemaker/vendor/mike-defaults-fr/assistant-workflows/proofread/SKILL.md +98 -0
- package/server/piecemaker/vendor/mike-defaults-fr/catalog.json +22 -0
- package/server/piecemaker/vendor/mike-defaults-fr/tabular-review-workflows/commercial-agreement-tabular-review/SKILL.md +31 -0
- package/server/piecemaker/vendor/mike-defaults-fr/tabular-review-workflows/commercial-agreement-tabular-review/table-columns.yaml +92 -0
- package/server/piecemaker/vendor/package.json +7 -0
- package/server/piecemaker/vendor/piecemaker-plugin/README.md +115 -0
- package/server/piecemaker/vendor/piecemaker-plugin/agents/analyste-piece.md +38 -0
- package/server/piecemaker/vendor/piecemaker-plugin/agents/jurisprudence-scanner.md +50 -0
- package/server/piecemaker/vendor/piecemaker-plugin/hooks/hooks.json +84 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +194 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/build-recherche-pdf.mjs +91 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +123 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +71 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +107 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/anonymization-state.cjs +146 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folder-structure.cjs +303 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +86 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citation-sources.cjs +519 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/citations.cjs +292 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/commits.cjs +1683 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/docx-text-worker.cjs +43 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/hook-io.mjs +249 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/institutional-terms.cjs +160 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/legifrance-reads.cjs +85 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +346 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.test.js +68 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +419 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/recherche-report.cjs +177 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/session-timing.cjs +80 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/substitution.cjs +318 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/verify-citations.cjs +318 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +256 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit-worker.mjs +260 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/session-commit.mjs +83 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +179 -0
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/track-legifrance-reads.mjs +46 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/ajout-de-fonctionnalites/SKILL.md +66 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/conversion-md/SKILL.md +60 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/graphe-juridique/SKILL.md +105 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/recherche-juridique/SKILL.md +234 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/redaction-juridique/SKILL.md +96 -0
- package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +148 -0
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +3195 -0
- package/server/piecemaker/vendor/websocket-server/case-folder-structure.cjs +3 -0
- package/server/piecemaker/vendor/websocket-server/case-instructions.cjs +114 -0
- package/server/piecemaker/vendor/websocket-server/case-registry.cjs +93 -0
- package/server/piecemaker/vendor/websocket-server/claude-assets.cjs +338 -0
- package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +380 -0
- package/server/piecemaker/vendor/websocket-server/document-index.cjs +682 -0
- package/server/piecemaker/vendor/websocket-server/graphify-document-graph.cjs +456 -0
- package/server/piecemaker/vendor/websocket-server/legal-chronology.cjs +502 -0
- package/server/piecemaker/vendor/websocket-server/legal-forms.cjs +89 -0
- package/server/piecemaker/vendor/websocket-server/legal-forms.test.js +10 -0
- package/server/piecemaker/vendor/websocket-server/legal-graph-materializer.cjs +234 -0
- package/server/piecemaker/vendor/websocket-server/legal-graph-prompt.txt +155 -0
- package/server/piecemaker/vendor/websocket-server/legal-graph.cjs +2021 -0
- package/server/piecemaker/vendor/websocket-server/legal-identity-boundary.cjs +247 -0
- package/server/piecemaker/vendor/websocket-server/legal-party-registry.cjs +261 -0
- package/server/piecemaker/vendor/websocket-server/lib/doc-generate.cjs +229 -0
- package/server/piecemaker/vendor/websocket-server/lib/export-render.cjs +442 -0
- package/server/piecemaker/vendor/websocket-server/lib/office-to-pdf.cjs +306 -0
- package/server/piecemaker/vendor/websocket-server/lib/stamping.cjs +39 -0
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +965 -0
- package/server/piecemaker/vendor/websocket-server/scripts/ADDRESS_ANONYMIZATION.md +216 -0
- package/server/piecemaker/vendor/websocket-server/scripts/DEDUPLICATION_CHANGES.md +134 -0
- package/server/piecemaker/vendor/websocket-server/scripts/GLINER2_README.md +138 -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 +1984 -0
- package/server/piecemaker/vendor/websocket-server/scripts/graphify-legal-sitecustomize.py +50 -0
- package/server/piecemaker/vendor/websocket-server/scripts/mineru_improved_1.py +208 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/AUDIT_PERF_QUALITE.md +246 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/MODELE_COREML.md +62 -0
- 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/__pycache__/model_config.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/build_coreml.py +118 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/coreml_runtime.py +164 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/BACKENDS_MESURES.md +384 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/CRITERES_QUALITE.md +81 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/__pycache__/coreml_encoder.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_backend.py +151 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_batchsize.py +47 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_coreml_pipeline.py +138 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/bench_gensight.py +124 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/check_gold.py +66 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/coreml_encoder.py +182 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/encoder_backends.py +179 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/evaluate.py +130 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/gold.py +59 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/profile_split.py +65 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_A.md +67 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_B.md +57 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/slice_C.md +907 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/sweep.py +115 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_substitution.cjs +116 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_whitespace.py +67 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/eval/verify_worker.py +106 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/model_config.py +28 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/presidio-gliner.py +471 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +668 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__init__.py +10 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/__init__.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/analysis_explanation.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/entity_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/local_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/pattern.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/pattern_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/__pycache__/recognizer_result.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/analysis_explanation.py +65 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/entity_recognizer.py +213 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/__init__.py +21 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/language_validation.py +18 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/schemas.py +132 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/input_validation/yaml_recognizer_models.py +422 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/local_recognizer.py +7 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__init__.py +15 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/__init__.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/device_detector.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/ner_model_configuration.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/nlp_artifacts.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/nlp_engine.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/__pycache__/spacy_nlp_engine.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/device_detector.py +65 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/ner_model_configuration.py +128 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_artifacts.py +88 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_engine.py +65 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/nlp_engine_provider.py +114 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/nlp_engine/spacy_nlp_engine.py +290 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/pattern.py +66 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/pattern_recognizer.py +297 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__init__.py +4 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__pycache__/__init__.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/__pycache__/gliner_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__init__.py +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/__init__.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/credit_card_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/crypto_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/email_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/iban_patterns.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/iban_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/ip_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/mac_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/__pycache__/url_recognizer.cpython-312.pyc +0 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/credit_card_recognizer.py +82 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/crypto_recognizer.py +141 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/date_recognizer.py +102 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/email_recognizer.py +48 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/iban_patterns.py +173 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/iban_recognizer.py +221 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/ip_recognizer.py +65 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/mac_recognizer.py +73 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/generic/url_recognizer.py +50 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/gliner_recognizer.py +218 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/predefined_recognizers/spacy_recognizer.py +139 -0
- package/server/piecemaker/vendor/websocket-server/scripts/presidio_analyzer/recognizer_result.py +188 -0
- package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +29 -0
- package/server/piecemaker/vendor/websocket-server/scripts/scan_utils.py +469 -0
- package/server/piecemaker/vendor/websocket-server/scripts/smart_converter.py +356 -0
- package/server/piecemaker/vendor/websocket-server/scripts/warmup.py +454 -0
- package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +334 -0
- package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +602 -0
- package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +22 -0
- package/server/shared/claude-cli-path.ts +157 -0
- package/server/shared/frontmatter.ts +18 -0
- package/server/shared/image-attachments.ts +437 -0
- package/server/shared/interfaces.ts +241 -0
- package/server/shared/message-unification.ts +449 -0
- package/server/shared/tests/application-data-root.test.ts +29 -0
- package/server/shared/tests/claude-cli-path.test.ts +118 -0
- package/server/shared/tests/image-attachments.test.ts +353 -0
- package/server/shared/tests/message-unification.test.ts +218 -0
- package/server/shared/tests/slice-tail-page.test.ts +42 -0
- package/server/shared/types.ts +1354 -0
- package/server/shared/utils.ts +1212 -0
- package/server/tsconfig.json +40 -0
- package/shared/networkHosts.js +22 -0
- package/shared/product-config.mjs +86 -0
|
@@ -0,0 +1,1660 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/** Git commit history for independent PieceMaker legal matters. */
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const zlib = require('node:zlib');
|
|
8
|
+
const { spawn } = require('node:child_process');
|
|
9
|
+
const { performance } = require('node:perf_hooks');
|
|
10
|
+
const { promisify } = require('node:util');
|
|
11
|
+
const { Worker } = require('node:worker_threads');
|
|
12
|
+
const { documentKey, isProtectedFile, isResourceFile, readProtection, WORKSPACE_SUBDIR, } = require('./protection.cjs');
|
|
13
|
+
const { isAnonymizedEntry, isConvertedEntry, readAnonymizationState, stateKey, } = require('./anonymization-state.cjs');
|
|
14
|
+
const { formatDurationFr } = require('./session-timing.cjs');
|
|
15
|
+
const fsp = fs.promises;
|
|
16
|
+
// Root commits (first commit of a case, diffed against the empty tree) can
|
|
17
|
+
// produce patches well into the tens of MB even though only MAX_PATCH_BYTES
|
|
18
|
+
// of it is ever kept (see revisionDetails/worktreeDetails). This ceiling only
|
|
19
|
+
// exists to bound memory on a runaway/corrupt diff, so it must stay well
|
|
20
|
+
// above realistic patch sizes — a 16MB cap was killing legitimate large
|
|
21
|
+
// root-commit diffs (e.g. ~33MB) and turning them into a 400 error.
|
|
22
|
+
const MAX_GIT_BUFFER = 128 * 1024 * 1024;
|
|
23
|
+
const MAX_PATCH_BYTES = 768 * 1024;
|
|
24
|
+
const MAX_SAFE_FILES = 10_000;
|
|
25
|
+
const MAX_SAFE_BYTES = 250 * 1024 * 1024;
|
|
26
|
+
const HISTORY_REF = 'refs/heads/main';
|
|
27
|
+
const LEGACY_HISTORY_REF = 'refs/heads/checkpoints';
|
|
28
|
+
// Le hook PostToolUse commite à chaque Write/Edit : un mois d'activité peut
|
|
29
|
+
// donc contenir des milliers de commits. `listHistory` plafonne à 250 pour un
|
|
30
|
+
// affichage récent ; l'export mensuel a besoin de tout, mais reste borné pour
|
|
31
|
+
// ne jamais renvoyer un volume qui exploserait MAX_GIT_BUFFER.
|
|
32
|
+
const MAX_HISTORY_PERIOD_COMMITS = 5000;
|
|
33
|
+
const SAFE_EXTENSIONS = new Set(['.md', '.json']);
|
|
34
|
+
const DOCX_MANIFEST_PATH = '.piecemaker/history-docx-ooxml.json';
|
|
35
|
+
const DOCX_MANIFEST_VERSION = 1;
|
|
36
|
+
const DOCX_FINGERPRINT_ALGORITHM = 'ooxml-central-directory-crc32-v1';
|
|
37
|
+
const MAX_DOCX_CENTRAL_BYTES = 16 * 1024 * 1024;
|
|
38
|
+
const MAX_DOCX_PARTS = 20_000;
|
|
39
|
+
const MAX_DOCX_TEXT_XML_BYTES = 32 * 1024 * 1024;
|
|
40
|
+
const TECHNICAL_CASE_NAMES = new Set(['piecemaker_output']);
|
|
41
|
+
/**
|
|
42
|
+
* Arborescences techniques jamais parcourues. Un dossier juridique finit par
|
|
43
|
+
* héberger autre chose que des pièces : le dossier de test embarque une copie
|
|
44
|
+
* complète d'un projet Node, dont les 53 000 fichiers noyaient la liste de
|
|
45
|
+
* l'administration (47 000 entrées) et faisaient entrer les `package.json` de
|
|
46
|
+
* `node_modules` dans l'historique du dossier.
|
|
47
|
+
*/
|
|
48
|
+
const IGNORED_DIRECTORY_NAMES = new Set([
|
|
49
|
+
'node_modules', 'dist', 'build', 'out', 'coverage', 'vendor', 'target', '__pycache__', 'venv',
|
|
50
|
+
]);
|
|
51
|
+
/** Plafond de la liste de l'administration ; au-delà, `truncated` le signale. */
|
|
52
|
+
const MAX_ORIGINALS = 2000;
|
|
53
|
+
const PERF_SLOW_MS = 250;
|
|
54
|
+
const PERF_LOG_ALL = process.env.PIECEMAKER_PERF_LOG === '1';
|
|
55
|
+
const COMMIT_USER_NAME_KEY = 'PIECEMAKER_USER_NAME';
|
|
56
|
+
const TECHNICAL_COMMIT_EMAIL = 'commits@piecemaker.local';
|
|
57
|
+
// Repli d'auteur Git quand aucune identité n'a été renseignée : un commit
|
|
58
|
+
// automatique (ex. enregistrement du mapping) ne doit jamais être bloqué par
|
|
59
|
+
// une identité manquante.
|
|
60
|
+
const DEFAULT_COMMIT_USER_NAME = 'PieceMaker';
|
|
61
|
+
const GLOBAL_ENV_FILE = path.resolve(__dirname, '..', '..', '..', '.env');
|
|
62
|
+
// Identité de commit partagée par tous les clones. `GLOBAL_ENV_FILE` est résolu
|
|
63
|
+
// relativement à ce module : lancé depuis le cache du plugin (hook d'édition),
|
|
64
|
+
// il pointe à côté du clone runtime et n'existe pas — le `.env` de l'identité
|
|
65
|
+
// vit dans le clone runtime, hors de portée. `config.json` sous ~/.piecemaker
|
|
66
|
+
// est le seul emplacement stable que le hook lit à coup sûr, quel que soit le
|
|
67
|
+
// clone d'où il tourne.
|
|
68
|
+
const IDENTITY_CONFIG_FILE = path.join(os.homedir(), '.piecemaker', 'config.json');
|
|
69
|
+
const inflateRaw = promisify(zlib.inflateRaw);
|
|
70
|
+
const deflateRaw = promisify(zlib.deflateRaw);
|
|
71
|
+
function validateCommitUserName(value) {
|
|
72
|
+
const cleaned = String(value || '').trim();
|
|
73
|
+
if (!cleaned) {
|
|
74
|
+
throw new Error('Identité utilisateur absente : renseignez votre nom dans les paramètres administrateur.');
|
|
75
|
+
}
|
|
76
|
+
if (cleaned.length > 160 || /[\x00-\x1f\x7f<>]/.test(cleaned)) {
|
|
77
|
+
throw new Error('Nom utilisateur invalide pour la signature des commits.');
|
|
78
|
+
}
|
|
79
|
+
return cleaned;
|
|
80
|
+
}
|
|
81
|
+
function unquoteEnvValue(value) {
|
|
82
|
+
const raw = String(value || '').trim();
|
|
83
|
+
if (raw.length >= 2 && ((raw.startsWith('"') && raw.endsWith('"')) || (raw.startsWith("'") && raw.endsWith("'")))) {
|
|
84
|
+
return raw.slice(1, -1);
|
|
85
|
+
}
|
|
86
|
+
return raw;
|
|
87
|
+
}
|
|
88
|
+
function readCommitIdentityEnv(file = GLOBAL_ENV_FILE) {
|
|
89
|
+
let value = '';
|
|
90
|
+
try {
|
|
91
|
+
if (file && fs.existsSync(file)) {
|
|
92
|
+
for (const line of fs.readFileSync(file, 'utf8').split(/\r?\n/)) {
|
|
93
|
+
const match = line.match(/^\s*PIECEMAKER_USER_NAME\s*=(.*)$/);
|
|
94
|
+
if (match)
|
|
95
|
+
value = unquoteEnvValue(match[1]);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
// Le processus peut encore avoir reçu l'identité depuis son environnement.
|
|
101
|
+
}
|
|
102
|
+
return value || process.env[COMMIT_USER_NAME_KEY] || '';
|
|
103
|
+
}
|
|
104
|
+
/** Nom de l'utilisateur mémorisé dans ~/.piecemaker/config.json (tous clones). */
|
|
105
|
+
function readCommitIdentityConfig(file = IDENTITY_CONFIG_FILE) {
|
|
106
|
+
try {
|
|
107
|
+
if (file && fs.existsSync(file)) {
|
|
108
|
+
const config = JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
109
|
+
const name = config?.commits?.userName ?? config?.userName;
|
|
110
|
+
if (typeof name === 'string' && name.trim())
|
|
111
|
+
return name.trim();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// Config illisible : on retombe sur les autres sources d'identité.
|
|
116
|
+
}
|
|
117
|
+
return '';
|
|
118
|
+
}
|
|
119
|
+
/** Identité personnelle appliquée à l'auteur et au validateur Git. */
|
|
120
|
+
function resolveCommitIdentity({ identity = null, envFile = GLOBAL_ENV_FILE, configFile = IDENTITY_CONFIG_FILE } = {}) {
|
|
121
|
+
const requestedName = typeof identity === 'string' ? identity : identity?.name;
|
|
122
|
+
// Sans identité explicite (hook d'édition), on tente le `.env` du clone
|
|
123
|
+
// courant puis, à défaut, config.json — le hook tourne depuis le cache du
|
|
124
|
+
// plugin où `envFile` par défaut n'existe pas. À défaut de tout ça, un nom
|
|
125
|
+
// technique par défaut : l'absence d'identité ne doit jamais empêcher un
|
|
126
|
+
// commit automatique.
|
|
127
|
+
const name = validateCommitUserName((identity ? requestedName : readCommitIdentityEnv(envFile) || readCommitIdentityConfig(configFile)) || DEFAULT_COMMIT_USER_NAME);
|
|
128
|
+
return {
|
|
129
|
+
name,
|
|
130
|
+
// Git exige une adresse dans son format d'identité, mais PieceMaker ne
|
|
131
|
+
// collecte aucune adresse personnelle pour signer les tâches.
|
|
132
|
+
email: TECHNICAL_COMMIT_EMAIL,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Journal de performance volontairement compact : aucun contenu de dossier ni
|
|
137
|
+
* argument Git n'est journalisé. Les opérations lentes sont visibles par
|
|
138
|
+
* défaut ; PIECEMAKER_PERF_LOG=1 affiche aussi les étapes rapides pendant un
|
|
139
|
+
* diagnostic ponctuel.
|
|
140
|
+
*/
|
|
141
|
+
function logPerformance(operation, startedAt, details = {}, slowMs = PERF_SLOW_MS) {
|
|
142
|
+
const durationMs = Number((performance.now() - startedAt).toFixed(1));
|
|
143
|
+
if (PERF_LOG_ALL || durationMs >= slowMs) {
|
|
144
|
+
const write = durationMs >= slowMs ? console.warn : console.log;
|
|
145
|
+
write(`[PM-PERF] ${operation}`, { durationMs, ...details });
|
|
146
|
+
}
|
|
147
|
+
return durationMs;
|
|
148
|
+
}
|
|
149
|
+
async function runGit(cwd, args, { gitDir, workTree, env = {}, input, allowFailure = false, encoding = 'utf8', maxOutputBytes = MAX_GIT_BUFFER, truncateOutput = false, } = {}) {
|
|
150
|
+
const startedAt = performance.now();
|
|
151
|
+
const command = [
|
|
152
|
+
...(gitDir ? [`--git-dir=${gitDir}`] : []),
|
|
153
|
+
...(workTree ? [`--work-tree=${workTree}`] : []),
|
|
154
|
+
'-c',
|
|
155
|
+
'core.quotePath=false',
|
|
156
|
+
...args,
|
|
157
|
+
];
|
|
158
|
+
// `spawn` plutôt que `spawnSync` : le serveur d'administration sert aussi le
|
|
159
|
+
// task pane et le WebSocket depuis la même boucle d'événements, qu'un git
|
|
160
|
+
// synchrone bloquerait le temps du parcours complet du dossier.
|
|
161
|
+
return new Promise((resolve, reject) => {
|
|
162
|
+
const child = spawn('git', command, {
|
|
163
|
+
cwd,
|
|
164
|
+
windowsHide: true,
|
|
165
|
+
env: { ...process.env, ...env },
|
|
166
|
+
});
|
|
167
|
+
const outChunks = [];
|
|
168
|
+
const errChunks = [];
|
|
169
|
+
let outBytes = 0;
|
|
170
|
+
let failure = null;
|
|
171
|
+
let truncated = false;
|
|
172
|
+
child.stdout.on('data', (chunk) => {
|
|
173
|
+
if (truncated)
|
|
174
|
+
return;
|
|
175
|
+
const nextBytes = outBytes + chunk.length;
|
|
176
|
+
if (nextBytes > maxOutputBytes) {
|
|
177
|
+
if (truncateOutput) {
|
|
178
|
+
const remaining = Math.max(maxOutputBytes - outBytes, 0);
|
|
179
|
+
if (remaining)
|
|
180
|
+
outChunks.push(chunk.subarray(0, remaining));
|
|
181
|
+
outBytes += remaining;
|
|
182
|
+
truncated = true;
|
|
183
|
+
child.kill();
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
if (!failure) {
|
|
187
|
+
failure = new Error(`git ${args[0]} a produit une sortie trop volumineuse`);
|
|
188
|
+
child.kill();
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
outBytes = nextBytes;
|
|
193
|
+
outChunks.push(chunk);
|
|
194
|
+
});
|
|
195
|
+
child.stderr.on('data', (chunk) => errChunks.push(chunk));
|
|
196
|
+
child.on('error', (error) => { failure = failure || error; });
|
|
197
|
+
child.on('close', (code) => {
|
|
198
|
+
const rawStdout = Buffer.concat(outChunks);
|
|
199
|
+
const rawStderr = Buffer.concat(errChunks).toString('utf8');
|
|
200
|
+
const stdout = encoding === null ? rawStdout : rawStdout.toString('utf8').trimEnd();
|
|
201
|
+
const stderr = encoding === null ? rawStderr : rawStderr.trim();
|
|
202
|
+
const status = failure ? null : truncated && truncateOutput ? 0 : code;
|
|
203
|
+
logPerformance('git', startedAt, {
|
|
204
|
+
command: args[0] || 'unknown',
|
|
205
|
+
status: status ?? 1,
|
|
206
|
+
stdoutBytes: rawStdout.length,
|
|
207
|
+
truncated,
|
|
208
|
+
});
|
|
209
|
+
if (!allowFailure && ((status ?? 1) !== 0 || failure)) {
|
|
210
|
+
reject(new Error(stderr.trim() || rawStdout.toString('utf8') || failure?.message || `git ${args[0]} a échoué`));
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
resolve({ code: status ?? 1, stdout, stderr, error: failure, truncated });
|
|
214
|
+
});
|
|
215
|
+
child.stdin.on('error', () => { });
|
|
216
|
+
child.stdin.end(input === undefined ? undefined : input);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
/** `PieceMaker_Output` et consorts ne sont pas des dossiers juridiques. */
|
|
220
|
+
function isTechnicalCaseDirectoryName(value) {
|
|
221
|
+
return TECHNICAL_CASE_NAMES.has(String(value || '').trim().toLowerCase());
|
|
222
|
+
}
|
|
223
|
+
function isIgnoredDirectoryName(value) {
|
|
224
|
+
const name = String(value || '').trim().toLowerCase();
|
|
225
|
+
return IGNORED_DIRECTORY_NAMES.has(name) || TECHNICAL_CASE_NAMES.has(name);
|
|
226
|
+
}
|
|
227
|
+
function isDocxPath(value) {
|
|
228
|
+
return path.extname(String(value || '')).toLowerCase() === '.docx';
|
|
229
|
+
}
|
|
230
|
+
function emptyDocxManifest() {
|
|
231
|
+
return { version: DOCX_MANIFEST_VERSION, algorithm: DOCX_FINGERPRINT_ALGORITHM, files: {} };
|
|
232
|
+
}
|
|
233
|
+
function findZipEnd(buffer) {
|
|
234
|
+
const first = Math.max(0, buffer.length - 65_557);
|
|
235
|
+
for (let offset = buffer.length - 22; offset >= first; offset -= 1) {
|
|
236
|
+
if (buffer.readUInt32LE(offset) === 0x06054b50)
|
|
237
|
+
return offset;
|
|
238
|
+
}
|
|
239
|
+
return -1;
|
|
240
|
+
}
|
|
241
|
+
async function parseCentralDirectory(buffer, entries) {
|
|
242
|
+
if (entries > MAX_DOCX_PARTS)
|
|
243
|
+
return null;
|
|
244
|
+
const parts = [];
|
|
245
|
+
let offset = 0;
|
|
246
|
+
for (let index = 0; index < entries; index += 1) {
|
|
247
|
+
if (offset + 46 > buffer.length || buffer.readUInt32LE(offset) !== 0x02014b50)
|
|
248
|
+
return null;
|
|
249
|
+
const flags = buffer.readUInt16LE(offset + 8);
|
|
250
|
+
const compression = buffer.readUInt16LE(offset + 10);
|
|
251
|
+
const crc32 = buffer.readUInt32LE(offset + 16).toString(16).padStart(8, '0');
|
|
252
|
+
const compressedSize = buffer.readUInt32LE(offset + 20);
|
|
253
|
+
const size = buffer.readUInt32LE(offset + 24);
|
|
254
|
+
const nameLength = buffer.readUInt16LE(offset + 28);
|
|
255
|
+
const next = offset + 46 + nameLength + buffer.readUInt16LE(offset + 30) + buffer.readUInt16LE(offset + 32);
|
|
256
|
+
if (next > buffer.length)
|
|
257
|
+
return null;
|
|
258
|
+
const name = buffer.subarray(offset + 46, offset + 46 + nameLength)
|
|
259
|
+
.toString((flags & 0x0800) !== 0 ? 'utf8' : 'latin1')
|
|
260
|
+
.replaceAll('\\', '/');
|
|
261
|
+
if (name && !name.endsWith('/')) {
|
|
262
|
+
parts.push({
|
|
263
|
+
name,
|
|
264
|
+
crc32,
|
|
265
|
+
size,
|
|
266
|
+
compressedSize,
|
|
267
|
+
compression,
|
|
268
|
+
localOffset: buffer.readUInt32LE(offset + 42),
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
offset = next;
|
|
272
|
+
if (index > 0 && index % 1000 === 0)
|
|
273
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
274
|
+
}
|
|
275
|
+
parts.sort((left, right) => left.name.localeCompare(right.name));
|
|
276
|
+
return parts;
|
|
277
|
+
}
|
|
278
|
+
/** Empreinte canonique des entrées OOXML, indépendante du conteneur ZIP. */
|
|
279
|
+
async function fingerprintCentralDirectory(buffer, entries) {
|
|
280
|
+
const parts = await parseCentralDirectory(buffer, entries);
|
|
281
|
+
if (!parts)
|
|
282
|
+
return null;
|
|
283
|
+
const hash = crypto.createHash('sha256');
|
|
284
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
285
|
+
const part = parts[index];
|
|
286
|
+
hash.update(`${part.name}\0${part.crc32}\0${part.size}\n`);
|
|
287
|
+
if (index > 0 && index % 1000 === 0)
|
|
288
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
289
|
+
}
|
|
290
|
+
return { fingerprint: hash.digest('hex'), format: 'ooxml', partCount: parts.length };
|
|
291
|
+
}
|
|
292
|
+
const docxFingerprintCache = new Map();
|
|
293
|
+
const docxTreeCache = new Map();
|
|
294
|
+
const docxTextCache = new Map();
|
|
295
|
+
function boundedCacheSet(cache, key, value, max) {
|
|
296
|
+
if (cache.has(key))
|
|
297
|
+
cache.delete(key);
|
|
298
|
+
cache.set(key, value);
|
|
299
|
+
if (cache.size > max)
|
|
300
|
+
cache.delete(cache.keys().next().value);
|
|
301
|
+
}
|
|
302
|
+
function docxStat(stat) {
|
|
303
|
+
return {
|
|
304
|
+
size: stat.size,
|
|
305
|
+
mtimeMs: Number(stat.mtimeMs.toFixed(3)),
|
|
306
|
+
ctimeMs: Number(stat.ctimeMs.toFixed(3)),
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
function sameDocxStat(entry, stat) {
|
|
310
|
+
return entry?.size === stat.size && entry?.mtimeMs === stat.mtimeMs && entry?.ctimeMs === stat.ctimeMs;
|
|
311
|
+
}
|
|
312
|
+
async function readRange(handle, length, position) {
|
|
313
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
314
|
+
const { bytesRead } = await handle.read(buffer, 0, length, position);
|
|
315
|
+
return bytesRead === length ? buffer : buffer.subarray(0, bytesRead);
|
|
316
|
+
}
|
|
317
|
+
function normalizeWordSections(sections) {
|
|
318
|
+
return new Promise((resolve, reject) => {
|
|
319
|
+
const worker = new Worker(path.join(__dirname, 'docx-text-worker.cjs'), { workerData: sections });
|
|
320
|
+
worker.once('message', resolve);
|
|
321
|
+
worker.once('error', reject);
|
|
322
|
+
worker.once('exit', (code) => {
|
|
323
|
+
if (code !== 0)
|
|
324
|
+
reject(new Error(`Extraction DOCX interrompue (${code}).`));
|
|
325
|
+
});
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
async function readZipPart(handle, part) {
|
|
329
|
+
if (![0, 8].includes(part.compression)
|
|
330
|
+
|| part.compressedSize > MAX_DOCX_TEXT_XML_BYTES
|
|
331
|
+
|| part.size > MAX_DOCX_TEXT_XML_BYTES)
|
|
332
|
+
return null;
|
|
333
|
+
const header = await readRange(handle, 30, part.localOffset);
|
|
334
|
+
if (header.length !== 30 || header.readUInt32LE(0) !== 0x04034b50)
|
|
335
|
+
return null;
|
|
336
|
+
const dataOffset = part.localOffset + 30 + header.readUInt16LE(26) + header.readUInt16LE(28);
|
|
337
|
+
const compressed = await readRange(handle, part.compressedSize, dataOffset);
|
|
338
|
+
if (compressed.length !== part.compressedSize)
|
|
339
|
+
return null;
|
|
340
|
+
if (part.compression === 0)
|
|
341
|
+
return compressed;
|
|
342
|
+
try {
|
|
343
|
+
return await inflateRaw(compressed, { maxOutputLength: MAX_DOCX_TEXT_XML_BYTES });
|
|
344
|
+
}
|
|
345
|
+
catch {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
function docxPartTitle(name) {
|
|
350
|
+
if (name === 'word/document.xml')
|
|
351
|
+
return 'Corps du document';
|
|
352
|
+
if (/^word\/header\d*\.xml$/i.test(name))
|
|
353
|
+
return 'En-tête';
|
|
354
|
+
if (/^word\/footer\d*\.xml$/i.test(name))
|
|
355
|
+
return 'Pied de page';
|
|
356
|
+
if (name === 'word/footnotes.xml')
|
|
357
|
+
return 'Notes de bas de page';
|
|
358
|
+
if (name === 'word/endnotes.xml')
|
|
359
|
+
return 'Notes de fin';
|
|
360
|
+
if (name === 'word/comments.xml')
|
|
361
|
+
return 'Commentaires';
|
|
362
|
+
return name;
|
|
363
|
+
}
|
|
364
|
+
async function extractDocxText(file, stat) {
|
|
365
|
+
const key = `${file}\0${stat.size}\0${stat.mtimeMs}\0${stat.ctimeMs}`;
|
|
366
|
+
if (docxTextCache.has(key))
|
|
367
|
+
return docxTextCache.get(key);
|
|
368
|
+
let handle;
|
|
369
|
+
let text = '';
|
|
370
|
+
try {
|
|
371
|
+
handle = await fsp.open(file, 'r');
|
|
372
|
+
const tailLength = Math.min(stat.size, 65_557);
|
|
373
|
+
const tail = await readRange(handle, tailLength, stat.size - tailLength);
|
|
374
|
+
const end = findZipEnd(tail);
|
|
375
|
+
if (end < 0)
|
|
376
|
+
return '';
|
|
377
|
+
const entries = tail.readUInt16LE(end + 10);
|
|
378
|
+
const centralSize = tail.readUInt32LE(end + 12);
|
|
379
|
+
const centralOffset = tail.readUInt32LE(end + 16);
|
|
380
|
+
if (entries === 0xffff || centralSize > MAX_DOCX_CENTRAL_BYTES || centralOffset + centralSize > stat.size)
|
|
381
|
+
return '';
|
|
382
|
+
const parts = await parseCentralDirectory(await readRange(handle, centralSize, centralOffset), entries);
|
|
383
|
+
if (!parts)
|
|
384
|
+
return '';
|
|
385
|
+
const readable = parts.filter((part) => part.name === 'word/document.xml'
|
|
386
|
+
|| /^word\/(?:header\d*|footer\d*|footnotes|endnotes|comments)\.xml$/i.test(part.name));
|
|
387
|
+
const sections = [];
|
|
388
|
+
let totalBytes = 0;
|
|
389
|
+
for (const part of readable) {
|
|
390
|
+
totalBytes += part.size;
|
|
391
|
+
if (totalBytes > MAX_DOCX_TEXT_XML_BYTES)
|
|
392
|
+
break;
|
|
393
|
+
const xml = await readZipPart(handle, part);
|
|
394
|
+
if (!xml)
|
|
395
|
+
continue;
|
|
396
|
+
sections.push({ title: docxPartTitle(part.name), xml: xml.toString('utf8') });
|
|
397
|
+
}
|
|
398
|
+
text = await normalizeWordSections(sections);
|
|
399
|
+
}
|
|
400
|
+
finally {
|
|
401
|
+
await handle?.close().catch(() => { });
|
|
402
|
+
}
|
|
403
|
+
boundedCacheSet(docxTextCache, key, text, 2_000);
|
|
404
|
+
return text;
|
|
405
|
+
}
|
|
406
|
+
async function encodeTextSnapshot(text) {
|
|
407
|
+
const compressed = await deflateRaw(Buffer.from(String(text || ''), 'utf8'), { level: 6 });
|
|
408
|
+
return compressed.toString('base64');
|
|
409
|
+
}
|
|
410
|
+
async function decodeTextSnapshot(entry) {
|
|
411
|
+
if (!entry?.textDeflate)
|
|
412
|
+
return null;
|
|
413
|
+
try {
|
|
414
|
+
return (await inflateRaw(Buffer.from(entry.textDeflate, 'base64'), { maxOutputLength: MAX_DOCX_TEXT_XML_BYTES })).toString('utf8');
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
return null;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
async function addDocxTextSnapshot(caseRoot, relative, entry) {
|
|
421
|
+
const absolute = path.join(caseRoot, ...relative.split('/'));
|
|
422
|
+
const stat = docxStat(await fsp.stat(absolute));
|
|
423
|
+
const text = await extractDocxText(absolute, stat);
|
|
424
|
+
return {
|
|
425
|
+
...entry,
|
|
426
|
+
textDeflate: await encodeTextSnapshot(text),
|
|
427
|
+
textHash: crypto.createHash('sha256').update(text).digest('hex'),
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
async function fingerprintDocx(file, stat) {
|
|
431
|
+
const key = `${file}\0${stat.size}\0${stat.mtimeMs}\0${stat.ctimeMs}`;
|
|
432
|
+
if (docxFingerprintCache.has(key))
|
|
433
|
+
return docxFingerprintCache.get(key);
|
|
434
|
+
let fingerprint = null;
|
|
435
|
+
let handle;
|
|
436
|
+
try {
|
|
437
|
+
handle = await fsp.open(file, 'r');
|
|
438
|
+
const tailLength = Math.min(stat.size, 65_557);
|
|
439
|
+
const tail = await readRange(handle, tailLength, stat.size - tailLength);
|
|
440
|
+
const end = findZipEnd(tail);
|
|
441
|
+
if (end >= 0) {
|
|
442
|
+
const entries = tail.readUInt16LE(end + 10);
|
|
443
|
+
const centralSize = tail.readUInt32LE(end + 12);
|
|
444
|
+
const centralOffset = tail.readUInt32LE(end + 16);
|
|
445
|
+
if (entries !== 0xffff && centralSize <= MAX_DOCX_CENTRAL_BYTES && centralOffset + centralSize <= stat.size) {
|
|
446
|
+
fingerprint = await fingerprintCentralDirectory(await readRange(handle, centralSize, centralOffset), entries);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
catch {
|
|
451
|
+
fingerprint = null;
|
|
452
|
+
}
|
|
453
|
+
finally {
|
|
454
|
+
await handle?.close().catch(() => { });
|
|
455
|
+
}
|
|
456
|
+
// Repli pour un faux/ZIP64 DOCX : métadonnées seulement, jamais le binaire.
|
|
457
|
+
fingerprint ||= {
|
|
458
|
+
fingerprint: crypto.createHash('sha256').update(`metadata\0${stat.size}\0${stat.mtimeMs}\0${stat.ctimeMs}`).digest('hex'),
|
|
459
|
+
format: 'metadata-fallback',
|
|
460
|
+
partCount: 0,
|
|
461
|
+
};
|
|
462
|
+
boundedCacheSet(docxFingerprintCache, key, fingerprint, 20_000);
|
|
463
|
+
return fingerprint;
|
|
464
|
+
}
|
|
465
|
+
async function currentDocxManifest(caseRoot, baseline = emptyDocxManifest(), { includeText = false } = {}) {
|
|
466
|
+
const root = await fsp.realpath(caseRoot);
|
|
467
|
+
const protection = includeText ? readProtection(root) : null;
|
|
468
|
+
const files = {};
|
|
469
|
+
let count = 0;
|
|
470
|
+
async function visit(directory, prefix = '') {
|
|
471
|
+
for (const entry of await fsp.readdir(directory, { withFileTypes: true })) {
|
|
472
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('~$') || entry.isSymbolicLink())
|
|
473
|
+
continue;
|
|
474
|
+
const absolute = path.join(directory, entry.name);
|
|
475
|
+
const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
476
|
+
if (entry.isDirectory()) {
|
|
477
|
+
if (!isIgnoredDirectoryName(entry.name))
|
|
478
|
+
await visit(absolute, relative);
|
|
479
|
+
continue;
|
|
480
|
+
}
|
|
481
|
+
if (!entry.isFile() || !isDocxPath(entry.name))
|
|
482
|
+
continue;
|
|
483
|
+
if (count >= MAX_SAFE_FILES)
|
|
484
|
+
throw new Error('Ce dossier contient trop de documents Word pour calculer leur historique.');
|
|
485
|
+
const stat = docxStat(await fsp.stat(absolute));
|
|
486
|
+
const previous = baseline.files[relative];
|
|
487
|
+
let current;
|
|
488
|
+
if (sameDocxStat(previous, stat)) {
|
|
489
|
+
current = previous;
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
const fingerprint = await fingerprintDocx(absolute, stat);
|
|
493
|
+
current = previous?.fingerprint === fingerprint.fingerprint ? previous : { ...stat, ...fingerprint };
|
|
494
|
+
}
|
|
495
|
+
if (includeText) {
|
|
496
|
+
if (isProtectedFile(absolute, root, protection)) {
|
|
497
|
+
const { textDeflate: _textDeflate, textHash: _textHash, ...withoutText } = current;
|
|
498
|
+
current = withoutText;
|
|
499
|
+
}
|
|
500
|
+
else if (!current.textDeflate) {
|
|
501
|
+
current = await addDocxTextSnapshot(root, relative, current);
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
files[relative] = current;
|
|
505
|
+
count += 1;
|
|
506
|
+
if (count % 100 === 0)
|
|
507
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
await visit(root);
|
|
511
|
+
return {
|
|
512
|
+
version: DOCX_MANIFEST_VERSION,
|
|
513
|
+
algorithm: DOCX_FINGERPRINT_ALGORITHM,
|
|
514
|
+
files: Object.fromEntries(Object.entries(files).sort(([left], [right]) => left.localeCompare(right, 'fr'))),
|
|
515
|
+
};
|
|
516
|
+
}
|
|
517
|
+
function serializeDocxManifest(manifest) {
|
|
518
|
+
return `${JSON.stringify(manifest)}\n`;
|
|
519
|
+
}
|
|
520
|
+
function parseDocxManifest(value) {
|
|
521
|
+
try {
|
|
522
|
+
const manifest = JSON.parse(String(value || ''));
|
|
523
|
+
return manifest?.version === DOCX_MANIFEST_VERSION && manifest.files && typeof manifest.files === 'object'
|
|
524
|
+
? manifest
|
|
525
|
+
: emptyDocxManifest();
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
return emptyDocxManifest();
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
function resolveCasesRoot(casesRoot) {
|
|
532
|
+
if (!casesRoot)
|
|
533
|
+
throw new Error('Le dossier racine PieceMaker n’est pas configuré.');
|
|
534
|
+
const root = path.resolve(String(casesRoot));
|
|
535
|
+
if (!fs.existsSync(root) || !fs.statSync(root).isDirectory()) {
|
|
536
|
+
throw new Error(`Le dossier racine PieceMaker est introuvable : ${root}`);
|
|
537
|
+
}
|
|
538
|
+
return fs.realpathSync(root);
|
|
539
|
+
}
|
|
540
|
+
function resolveCase(casesRoot, caseName) {
|
|
541
|
+
const root = resolveCasesRoot(casesRoot);
|
|
542
|
+
const name = String(caseName || '').trim();
|
|
543
|
+
if (!name || name === '.' || name === '..' || path.basename(name) !== name || name.startsWith('.')) {
|
|
544
|
+
throw new Error('Dossier juridique invalide.');
|
|
545
|
+
}
|
|
546
|
+
const candidate = path.join(root, name);
|
|
547
|
+
if (!fs.existsSync(candidate) || !fs.statSync(candidate).isDirectory()) {
|
|
548
|
+
throw new Error(`Le dossier juridique « ${name} » est introuvable.`);
|
|
549
|
+
}
|
|
550
|
+
const caseRoot = fs.realpathSync(candidate);
|
|
551
|
+
if (path.dirname(caseRoot) !== root) {
|
|
552
|
+
throw new Error('Le dossier juridique résout hors de la racine PieceMaker.');
|
|
553
|
+
}
|
|
554
|
+
return { casesRoot: root, name, root: caseRoot };
|
|
555
|
+
}
|
|
556
|
+
function locateCaseFile(casesRoot, filePath) {
|
|
557
|
+
const root = resolveCasesRoot(casesRoot);
|
|
558
|
+
const requested = path.resolve(String(filePath || ''));
|
|
559
|
+
let absolute = requested;
|
|
560
|
+
try {
|
|
561
|
+
absolute = fs.realpathSync(requested);
|
|
562
|
+
}
|
|
563
|
+
catch {
|
|
564
|
+
try {
|
|
565
|
+
absolute = path.join(fs.realpathSync(path.dirname(requested)), path.basename(requested));
|
|
566
|
+
}
|
|
567
|
+
catch { }
|
|
568
|
+
}
|
|
569
|
+
if (absolute === root || !absolute.startsWith(`${root}${path.sep}`))
|
|
570
|
+
return null;
|
|
571
|
+
const relativeToRoot = path.relative(root, absolute);
|
|
572
|
+
const [caseName, ...parts] = relativeToRoot.split(path.sep);
|
|
573
|
+
if (!caseName || parts.length === 0)
|
|
574
|
+
return null;
|
|
575
|
+
const legalCase = resolveCase(root, caseName);
|
|
576
|
+
if (isProtectedFile(absolute, legalCase.root)) {
|
|
577
|
+
return { ...legalCase, absolute, protected: true, relative: parts.join('/') };
|
|
578
|
+
}
|
|
579
|
+
if (path.extname(absolute).toLowerCase() && !SAFE_EXTENSIONS.has(path.extname(absolute).toLowerCase())) {
|
|
580
|
+
return { ...legalCase, absolute, protected: false, safe: false, relative: parts.join('/') };
|
|
581
|
+
}
|
|
582
|
+
const relative = path.relative(legalCase.root, absolute).split(path.sep).join('/');
|
|
583
|
+
if (!relative || relative.startsWith('../'))
|
|
584
|
+
return null;
|
|
585
|
+
return { ...legalCase, absolute, protected: false, safe: SAFE_EXTENSIONS.has(path.extname(relative).toLowerCase()), relative };
|
|
586
|
+
}
|
|
587
|
+
async function safeCaseFiles(caseRoot) {
|
|
588
|
+
const startedAt = performance.now();
|
|
589
|
+
const root = await fsp.realpath(caseRoot);
|
|
590
|
+
const files = [];
|
|
591
|
+
let bytes = 0;
|
|
592
|
+
async function visit(directory, prefix = '') {
|
|
593
|
+
for (const entry of await fsp.readdir(directory, { withFileTypes: true })) {
|
|
594
|
+
if (entry.name.startsWith('.') || entry.isSymbolicLink())
|
|
595
|
+
continue;
|
|
596
|
+
const absolute = path.join(directory, entry.name);
|
|
597
|
+
const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
598
|
+
if (entry.isDirectory()) {
|
|
599
|
+
if (!isIgnoredDirectoryName(entry.name))
|
|
600
|
+
await visit(absolute, relative);
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
if (!entry.isFile() || !SAFE_EXTENSIONS.has(path.extname(entry.name).toLowerCase()))
|
|
604
|
+
continue;
|
|
605
|
+
const size = (await fsp.stat(absolute)).size;
|
|
606
|
+
bytes += size;
|
|
607
|
+
files.push(relative);
|
|
608
|
+
if (files.length > MAX_SAFE_FILES)
|
|
609
|
+
throw new Error('Ce dossier contient trop de fichiers Markdown/JSON pour un commit sûr.');
|
|
610
|
+
if (bytes > MAX_SAFE_BYTES)
|
|
611
|
+
throw new Error('Les fichiers accessibles à l’IA dépassent 250 Mo ; commit annulé.');
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
await visit(root);
|
|
615
|
+
const sorted = files.sort((a, b) => a.localeCompare(b, 'fr'));
|
|
616
|
+
logPerformance('safeCaseFiles', startedAt, { files: sorted.length, bytes });
|
|
617
|
+
return sorted;
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Les pièces d'un dossier juridique, sous-dossiers compris.
|
|
621
|
+
*
|
|
622
|
+
* Le recensement ne dépend plus d'un sous-dossier « Pièces originales » : un
|
|
623
|
+
* cabinet range ses pièces à plat, à côté du Markdown qu'il en tire, et cette
|
|
624
|
+
* organisation-là ne protégeait donc rien. Est une pièce tout fichier qui n'est
|
|
625
|
+
* ni Markdown ni JSON — le reste, ce sont les dérivés que l'IA a le droit de
|
|
626
|
+
* lire (sous mapping) et le mapping lui-même.
|
|
627
|
+
*
|
|
628
|
+
* `converted` / `scanned` restent l'état du pipeline ; `protected` est la
|
|
629
|
+
* décision prise dans l'administration et appliquée par les hooks. Le scan
|
|
630
|
+
* n'est plus déduit de la présence d'un mapping sensible par pièce : le
|
|
631
|
+
* manifeste technique `.piecemaker/anonymization-state.json`, dépourvu de PII,
|
|
632
|
+
* mémorise les empreintes de conversion et de scan. Les anciens sensitive maps
|
|
633
|
+
* ne servent que de compatibilité pendant leur migration.
|
|
634
|
+
*/
|
|
635
|
+
async function originalFilesOverview(caseRoot, { safeFiles: knownSafeFiles = null } = {}) {
|
|
636
|
+
const startedAt = performance.now();
|
|
637
|
+
const root = await fsp.realpath(caseRoot);
|
|
638
|
+
const safeFiles = knownSafeFiles || await safeCaseFiles(root);
|
|
639
|
+
const markdownKeys = new Set(safeFiles.filter((file) => path.extname(file).toLowerCase() === '.md').map(documentKey));
|
|
640
|
+
const scanKeys = new Set(safeFiles
|
|
641
|
+
.filter((file) => file.toLowerCase().endsWith('_sensitive_map.json'))
|
|
642
|
+
.map((file) => documentKey(file).replace(/-sensitive-map$/, '')));
|
|
643
|
+
const anonymizationState = readAnonymizationState(root);
|
|
644
|
+
const protection = readProtection(root);
|
|
645
|
+
const originals = [];
|
|
646
|
+
let truncated = false;
|
|
647
|
+
async function visit(directory, prefix = '') {
|
|
648
|
+
const entries = await fsp.readdir(directory, { withFileTypes: true });
|
|
649
|
+
// MinerU écrit sa sortie dans `<nom de la pièce>/auto/` à côté de la pièce.
|
|
650
|
+
// Ces dérivés portent le même contenu que l'original — ils restent donc
|
|
651
|
+
// protégés par défaut — mais les lister doublerait chaque pièce dans
|
|
652
|
+
// l'administration.
|
|
653
|
+
const conversionOutputs = new Set(entries.filter((entry) => entry.isFile()).map((entry) => documentKey(entry.name)));
|
|
654
|
+
for (const entry of entries) {
|
|
655
|
+
if (entry.name.startsWith('.') || entry.name.startsWith('~$') || entry.isSymbolicLink())
|
|
656
|
+
continue;
|
|
657
|
+
const absolute = path.join(directory, entry.name);
|
|
658
|
+
const relative = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
659
|
+
if (entry.isDirectory()) {
|
|
660
|
+
// Le sous-dossier des fichiers produits (Markdown, mapping) n'est jamais
|
|
661
|
+
// une source de pièces : ses `.md`/`.json` sont déjà écartés par
|
|
662
|
+
// `SAFE_EXTENSIONS`, mais d'éventuels dérivés non-Markdown (images
|
|
663
|
+
// MinerU) qui y vivent ne doivent pas non plus être listés comme pièces.
|
|
664
|
+
// `safeCaseFiles`, lui, continue de le parcourir pour repérer les `.md`.
|
|
665
|
+
if (entry.name === WORKSPACE_SUBDIR)
|
|
666
|
+
continue;
|
|
667
|
+
if (isIgnoredDirectoryName(entry.name) || conversionOutputs.has(documentKey(entry.name)))
|
|
668
|
+
continue;
|
|
669
|
+
await visit(absolute, relative);
|
|
670
|
+
continue;
|
|
671
|
+
}
|
|
672
|
+
if (originals.length >= MAX_ORIGINALS) {
|
|
673
|
+
truncated = true;
|
|
674
|
+
return;
|
|
675
|
+
}
|
|
676
|
+
if (!entry.isFile())
|
|
677
|
+
continue;
|
|
678
|
+
if (SAFE_EXTENSIONS.has(path.extname(entry.name).toLowerCase()))
|
|
679
|
+
continue;
|
|
680
|
+
const stat = await fsp.stat(absolute);
|
|
681
|
+
const key = documentKey(entry.name);
|
|
682
|
+
const stateEntry = anonymizationState.files[stateKey(relative)];
|
|
683
|
+
// Un dossier ancien sans manifeste conserve le comportement historique
|
|
684
|
+
// (Markdown présent = converti). Dès qu'une empreinte existe, elle rend un
|
|
685
|
+
// Markdown périmé visible au lieu de le réutiliser silencieusement.
|
|
686
|
+
const converted = markdownKeys.has(key) && (!stateEntry || isConvertedEntry(stateEntry, stat));
|
|
687
|
+
const scanned = converted && (isAnonymizedEntry(stateEntry, stat)
|
|
688
|
+
|| scanKeys.has(key));
|
|
689
|
+
originals.push({
|
|
690
|
+
name: entry.name,
|
|
691
|
+
path: relative,
|
|
692
|
+
extension: path.extname(entry.name).toLowerCase(),
|
|
693
|
+
size: stat.size,
|
|
694
|
+
modifiedAt: stat.mtime.toISOString(),
|
|
695
|
+
converted,
|
|
696
|
+
scanned,
|
|
697
|
+
protected: isProtectedFile(absolute, root, protection),
|
|
698
|
+
resource: isResourceFile(absolute, root, protection),
|
|
699
|
+
status: converted ? (scanned ? 'ready' : 'awaiting-scan') : 'not-converted',
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
await visit(root);
|
|
704
|
+
const sorted = originals.sort((a, b) => a.path.localeCompare(b.path, 'fr'));
|
|
705
|
+
if (truncated)
|
|
706
|
+
sorted.truncated = true;
|
|
707
|
+
logPerformance('originalFilesOverview', startedAt, {
|
|
708
|
+
safeFiles: safeFiles.length,
|
|
709
|
+
originals: sorted.length,
|
|
710
|
+
truncated,
|
|
711
|
+
});
|
|
712
|
+
return sorted;
|
|
713
|
+
}
|
|
714
|
+
function historyId(legalCase) {
|
|
715
|
+
const slug = legalCase.name
|
|
716
|
+
.normalize('NFKD')
|
|
717
|
+
.replace(/[\u0300-\u036f]/g, '')
|
|
718
|
+
.replace(/[^A-Za-z0-9._-]+/g, '-')
|
|
719
|
+
.replace(/^[.-]+|[.-]+$/g, '')
|
|
720
|
+
.slice(0, 60) || 'dossier';
|
|
721
|
+
const digest = crypto.createHash('sha256').update(legalCase.root).digest('hex').slice(0, 12);
|
|
722
|
+
return `${slug}-${digest}`;
|
|
723
|
+
}
|
|
724
|
+
const caseStateCache = new Map();
|
|
725
|
+
function caseStateCacheKey(homeDir, legalCase) {
|
|
726
|
+
return `${path.resolve(homeDir)}:${historyId(legalCase)}`;
|
|
727
|
+
}
|
|
728
|
+
function historyDirectory(homeDir = path.join(os.homedir(), '.piecemaker')) {
|
|
729
|
+
return path.join(homeDir, 'case-history');
|
|
730
|
+
}
|
|
731
|
+
function historyRepo(homeDir, legalCase) {
|
|
732
|
+
return path.join(historyDirectory(homeDir), `${historyId(legalCase)}.git`);
|
|
733
|
+
}
|
|
734
|
+
async function ensureHistoryRepo(homeDir, legalCase) {
|
|
735
|
+
const gitDir = historyRepo(homeDir, legalCase);
|
|
736
|
+
if (!fs.existsSync(gitDir)) {
|
|
737
|
+
fs.mkdirSync(path.dirname(gitDir), { recursive: true });
|
|
738
|
+
await runGit(legalCase.root, ['init', '--bare', gitDir]);
|
|
739
|
+
await runGit(legalCase.root, ['symbolic-ref', 'HEAD', HISTORY_REF], { gitDir });
|
|
740
|
+
}
|
|
741
|
+
const main = await runGit(legalCase.root, ['rev-parse', '--verify', HISTORY_REF], { gitDir, allowFailure: true });
|
|
742
|
+
if (main.code !== 0) {
|
|
743
|
+
const legacy = await runGit(legalCase.root, ['rev-parse', '--verify', LEGACY_HISTORY_REF], { gitDir, allowFailure: true });
|
|
744
|
+
if (legacy.code === 0)
|
|
745
|
+
await runGit(legalCase.root, ['update-ref', HISTORY_REF, legacy.stdout], { gitDir });
|
|
746
|
+
}
|
|
747
|
+
const head = await runGit(legalCase.root, ['symbolic-ref', '-q', 'HEAD'], { gitDir, allowFailure: true });
|
|
748
|
+
const headCommit = head.code === 0
|
|
749
|
+
? await runGit(legalCase.root, ['rev-parse', '--verify', head.stdout], { gitDir, allowFailure: true })
|
|
750
|
+
: { code: 1 };
|
|
751
|
+
const migratedMain = await runGit(legalCase.root, ['rev-parse', '--verify', HISTORY_REF], { gitDir, allowFailure: true });
|
|
752
|
+
if (head.code !== 0 || !head.stdout.startsWith('refs/heads/') || (headCommit.code !== 0 && migratedMain.code === 0)) {
|
|
753
|
+
await runGit(legalCase.root, ['symbolic-ref', 'HEAD', HISTORY_REF], { gitDir });
|
|
754
|
+
}
|
|
755
|
+
return gitDir;
|
|
756
|
+
}
|
|
757
|
+
async function activeHistoryRef(legalCase, gitDir) {
|
|
758
|
+
const result = await runGit(legalCase.root, ['symbolic-ref', '-q', 'HEAD'], { gitDir, allowFailure: true });
|
|
759
|
+
return result.code === 0 && result.stdout.startsWith('refs/heads/') ? result.stdout : HISTORY_REF;
|
|
760
|
+
}
|
|
761
|
+
async function latestCommit(legalCase, gitDir) {
|
|
762
|
+
const result = await runGit(legalCase.root, ['rev-parse', '--verify', await activeHistoryRef(legalCase, gitDir)], { gitDir, allowFailure: true });
|
|
763
|
+
return result.code === 0 ? result.stdout : '';
|
|
764
|
+
}
|
|
765
|
+
async function historyBranches(casesRoot, homeDir, caseName) {
|
|
766
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
767
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
768
|
+
const activeRef = await activeHistoryRef(legalCase, gitDir);
|
|
769
|
+
const active = activeRef.slice('refs/heads/'.length);
|
|
770
|
+
const result = await runGit(legalCase.root, ['for-each-ref', '--format=%(refname:short)', 'refs/heads'], { gitDir });
|
|
771
|
+
const branches = [...new Set([active, ...result.stdout.split('\n').map((name) => name.trim()).filter(Boolean)])]
|
|
772
|
+
.sort((a, b) => a.localeCompare(b, 'fr'));
|
|
773
|
+
return { active, branches };
|
|
774
|
+
}
|
|
775
|
+
async function validatedBranchName(legalCase, gitDir, value) {
|
|
776
|
+
const name = String(value || '').trim();
|
|
777
|
+
if (!name || name.length > 120)
|
|
778
|
+
throw new Error('Le nom de branche est requis.');
|
|
779
|
+
const valid = await runGit(legalCase.root, ['check-ref-format', '--branch', name], { gitDir, allowFailure: true });
|
|
780
|
+
if (valid.code !== 0)
|
|
781
|
+
throw new Error('Nom de branche Git invalide.');
|
|
782
|
+
return name;
|
|
783
|
+
}
|
|
784
|
+
async function createHistoryBranch({ casesRoot, caseName, homeDir = path.join(os.homedir(), '.piecemaker'), name } = {}) {
|
|
785
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
786
|
+
return withCaseLock(homeDir, legalCase, async () => {
|
|
787
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
788
|
+
const branch = await validatedBranchName(legalCase, gitDir, name);
|
|
789
|
+
const ref = `refs/heads/${branch}`;
|
|
790
|
+
const exists = await runGit(legalCase.root, ['show-ref', '--verify', '--quiet', ref], { gitDir, allowFailure: true });
|
|
791
|
+
if (exists.code === 0)
|
|
792
|
+
throw new Error(`La branche « ${branch} » existe déjà.`);
|
|
793
|
+
const parent = await latestCommit(legalCase, gitDir);
|
|
794
|
+
if (parent)
|
|
795
|
+
await runGit(legalCase.root, ['update-ref', ref, parent], { gitDir });
|
|
796
|
+
await runGit(legalCase.root, ['symbolic-ref', 'HEAD', ref], { gitDir });
|
|
797
|
+
caseStateCache.delete(caseStateCacheKey(homeDir, legalCase));
|
|
798
|
+
return historyBranches(casesRoot, homeDir, legalCase.name);
|
|
799
|
+
}, { waitMs: 10_000 });
|
|
800
|
+
}
|
|
801
|
+
async function checkoutHistoryBranch({ casesRoot, caseName, homeDir = path.join(os.homedir(), '.piecemaker'), name } = {}) {
|
|
802
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
803
|
+
return withCaseLock(homeDir, legalCase, async () => {
|
|
804
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
805
|
+
const branch = await validatedBranchName(legalCase, gitDir, name);
|
|
806
|
+
const ref = `refs/heads/${branch}`;
|
|
807
|
+
const exists = await runGit(legalCase.root, ['show-ref', '--verify', '--quiet', ref], { gitDir, allowFailure: true });
|
|
808
|
+
const current = await activeHistoryRef(legalCase, gitDir);
|
|
809
|
+
if (exists.code !== 0 && current !== ref)
|
|
810
|
+
throw new Error(`La branche « ${branch} » n’existe pas.`);
|
|
811
|
+
await runGit(legalCase.root, ['symbolic-ref', 'HEAD', ref], { gitDir });
|
|
812
|
+
caseStateCache.delete(caseStateCacheKey(homeDir, legalCase));
|
|
813
|
+
return historyBranches(casesRoot, homeDir, legalCase.name);
|
|
814
|
+
}, { waitMs: 10_000 });
|
|
815
|
+
}
|
|
816
|
+
async function withCaseLock(homeDir, legalCase, callback, { waitMs = 0 } = {}) {
|
|
817
|
+
const directory = historyDirectory(homeDir);
|
|
818
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
819
|
+
const lock = path.join(directory, `${historyId(legalCase)}.lock`);
|
|
820
|
+
const deadline = Date.now() + Math.max(Number(waitMs) || 0, 0);
|
|
821
|
+
let fd;
|
|
822
|
+
try {
|
|
823
|
+
while (fd === undefined) {
|
|
824
|
+
try {
|
|
825
|
+
fd = fs.openSync(lock, 'wx');
|
|
826
|
+
}
|
|
827
|
+
catch (error) {
|
|
828
|
+
if (error.code !== 'EEXIST')
|
|
829
|
+
throw error;
|
|
830
|
+
let age = 0;
|
|
831
|
+
try {
|
|
832
|
+
age = Date.now() - fs.statSync(lock).mtimeMs;
|
|
833
|
+
}
|
|
834
|
+
catch {
|
|
835
|
+
continue;
|
|
836
|
+
}
|
|
837
|
+
if (age >= 60_000) {
|
|
838
|
+
try {
|
|
839
|
+
fs.unlinkSync(lock);
|
|
840
|
+
}
|
|
841
|
+
catch { }
|
|
842
|
+
continue;
|
|
843
|
+
}
|
|
844
|
+
if (Date.now() >= deadline)
|
|
845
|
+
return { created: false, skipped: 'busy' };
|
|
846
|
+
await new Promise((resolve) => setTimeout(resolve, Math.min(50, Math.max(deadline - Date.now(), 1))));
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
fs.writeFileSync(fd, `${process.pid}\n`, 'utf8');
|
|
850
|
+
return await callback();
|
|
851
|
+
}
|
|
852
|
+
finally {
|
|
853
|
+
if (fd !== undefined) {
|
|
854
|
+
try {
|
|
855
|
+
fs.closeSync(fd);
|
|
856
|
+
}
|
|
857
|
+
catch { }
|
|
858
|
+
try {
|
|
859
|
+
fs.unlinkSync(lock);
|
|
860
|
+
}
|
|
861
|
+
catch { }
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
}
|
|
865
|
+
async function putDocxManifestInIndex(legalCase, gitDir, env, manifest) {
|
|
866
|
+
if (!Object.keys(manifest.files).length)
|
|
867
|
+
return;
|
|
868
|
+
const blob = (await runGit(legalCase.root, ['hash-object', '-w', '--stdin'], {
|
|
869
|
+
gitDir,
|
|
870
|
+
input: serializeDocxManifest(manifest),
|
|
871
|
+
})).stdout;
|
|
872
|
+
await runGit(legalCase.root, ['update-index', '--add', '--cacheinfo', `100644,${blob},${DOCX_MANIFEST_PATH}`], {
|
|
873
|
+
gitDir,
|
|
874
|
+
workTree: legalCase.root,
|
|
875
|
+
env,
|
|
876
|
+
});
|
|
877
|
+
}
|
|
878
|
+
async function treeDocxManifest(legalCase, gitDir, treeish) {
|
|
879
|
+
if (!treeish)
|
|
880
|
+
return emptyDocxManifest();
|
|
881
|
+
const key = `${gitDir}\0${treeish}`;
|
|
882
|
+
if (docxTreeCache.has(key))
|
|
883
|
+
return docxTreeCache.get(key);
|
|
884
|
+
const result = await runGit(legalCase.root, ['show', `${treeish}:${DOCX_MANIFEST_PATH}`], { gitDir, allowFailure: true });
|
|
885
|
+
const manifest = result.code === 0 ? parseDocxManifest(result.stdout) : emptyDocxManifest();
|
|
886
|
+
boundedCacheSet(docxTreeCache, key, manifest, 2_000);
|
|
887
|
+
return manifest;
|
|
888
|
+
}
|
|
889
|
+
function docxChanges(beforeManifest, afterManifest) {
|
|
890
|
+
const before = beforeManifest.files;
|
|
891
|
+
const after = afterManifest.files;
|
|
892
|
+
return [...new Set([...Object.keys(before), ...Object.keys(after)])]
|
|
893
|
+
.sort((left, right) => left.localeCompare(right, 'fr'))
|
|
894
|
+
.flatMap((filePath) => {
|
|
895
|
+
if (!before[filePath])
|
|
896
|
+
return [{ status: 'A', path: filePath, previousPath: null, kind: 'added' }];
|
|
897
|
+
if (!after[filePath])
|
|
898
|
+
return [{ status: 'D', path: filePath, previousPath: null, kind: 'deleted' }];
|
|
899
|
+
return before[filePath].fingerprint === after[filePath].fingerprint
|
|
900
|
+
? []
|
|
901
|
+
: [{ status: 'M', path: filePath, previousPath: null, kind: 'modified' }];
|
|
902
|
+
});
|
|
903
|
+
}
|
|
904
|
+
async function liveDocxText(legalCase, filePath, entry) {
|
|
905
|
+
if (!entry)
|
|
906
|
+
return '';
|
|
907
|
+
const absolute = path.join(legalCase.root, ...filePath.split('/'));
|
|
908
|
+
try {
|
|
909
|
+
const stat = docxStat(await fsp.stat(absolute));
|
|
910
|
+
const fingerprint = await fingerprintDocx(absolute, stat);
|
|
911
|
+
if (fingerprint.fingerprint !== entry.fingerprint)
|
|
912
|
+
return null;
|
|
913
|
+
return extractDocxText(absolute, stat);
|
|
914
|
+
}
|
|
915
|
+
catch {
|
|
916
|
+
return null;
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
async function entryDocxText(legalCase, filePath, entry) {
|
|
920
|
+
if (!entry)
|
|
921
|
+
return '';
|
|
922
|
+
return await decodeTextSnapshot(entry) ?? liveDocxText(legalCase, filePath, entry);
|
|
923
|
+
}
|
|
924
|
+
function limitPatch(value) {
|
|
925
|
+
const buffer = Buffer.from(String(value || ''), 'utf8');
|
|
926
|
+
if (buffer.length <= MAX_PATCH_BYTES)
|
|
927
|
+
return { stdout: buffer.toString('utf8'), truncated: false };
|
|
928
|
+
return { stdout: `${buffer.subarray(0, MAX_PATCH_BYTES).toString('utf8')}…`, truncated: true };
|
|
929
|
+
}
|
|
930
|
+
async function docxTextDiff(legalCase, beforeManifest, afterManifest, filePath) {
|
|
931
|
+
const before = beforeManifest.files[filePath];
|
|
932
|
+
const after = afterManifest.files[filePath];
|
|
933
|
+
const absolute = path.join(legalCase.root, ...filePath.split('/'));
|
|
934
|
+
if (isProtectedFile(absolute, legalCase.root)) {
|
|
935
|
+
return {
|
|
936
|
+
stdout: `diff --text a/${filePath} b/${filePath}\n@@ Document protégé @@\n Le texte n’est pas extrait des pièces protégées.\n`,
|
|
937
|
+
truncated: false,
|
|
938
|
+
stats: { files: 1, added: 0, deleted: 0 },
|
|
939
|
+
};
|
|
940
|
+
}
|
|
941
|
+
const [beforeText, afterText] = await Promise.all([
|
|
942
|
+
entryDocxText(legalCase, filePath, before),
|
|
943
|
+
entryDocxText(legalCase, filePath, after),
|
|
944
|
+
]);
|
|
945
|
+
if (beforeText === null || afterText === null) {
|
|
946
|
+
const available = afterText ?? beforeText ?? '';
|
|
947
|
+
const prefix = afterText !== null ? '+' : '-';
|
|
948
|
+
const lines = available.split('\n').map((line) => `${prefix}${line}`);
|
|
949
|
+
const patch = limitPatch([
|
|
950
|
+
`diff --text a/${filePath} b/${filePath}`,
|
|
951
|
+
`--- ${before ? `a/${filePath}` : '/dev/null'}`,
|
|
952
|
+
`+++ ${after ? `b/${filePath}` : '/dev/null'}`,
|
|
953
|
+
'@@ Texte partiellement disponible @@',
|
|
954
|
+
' Le prochain commit servira de référence textuelle complète.',
|
|
955
|
+
...lines,
|
|
956
|
+
'',
|
|
957
|
+
].join('\n'));
|
|
958
|
+
return {
|
|
959
|
+
...patch,
|
|
960
|
+
stats: {
|
|
961
|
+
files: 1,
|
|
962
|
+
added: prefix === '+' ? lines.length : 0,
|
|
963
|
+
deleted: prefix === '-' ? lines.length : 0,
|
|
964
|
+
},
|
|
965
|
+
};
|
|
966
|
+
}
|
|
967
|
+
const temporary = await fsp.mkdtemp(path.join(os.tmpdir(), 'piecemaker-docx-diff-'));
|
|
968
|
+
const beforeFile = path.join(temporary, 'avant.txt');
|
|
969
|
+
const afterFile = path.join(temporary, 'apres.txt');
|
|
970
|
+
try {
|
|
971
|
+
await Promise.all([
|
|
972
|
+
fsp.writeFile(beforeFile, `${beforeText}\n`, { encoding: 'utf8', mode: 0o600 }),
|
|
973
|
+
fsp.writeFile(afterFile, `${afterText}\n`, { encoding: 'utf8', mode: 0o600 }),
|
|
974
|
+
]);
|
|
975
|
+
const result = await runGit(legalCase.root, [
|
|
976
|
+
'diff', '--no-index', '--text', '--unified=3', '--', beforeFile, afterFile,
|
|
977
|
+
], { allowFailure: true, maxOutputBytes: MAX_PATCH_BYTES, truncateOutput: true });
|
|
978
|
+
const hunk = String(result.stdout || '').match(/^@@[\s\S]*$/m)?.[0] || '';
|
|
979
|
+
const patch = [
|
|
980
|
+
`diff --text a/${filePath} b/${filePath}`,
|
|
981
|
+
`--- ${before ? `a/${filePath}` : '/dev/null'}`,
|
|
982
|
+
`+++ ${after ? `b/${filePath}` : '/dev/null'}`,
|
|
983
|
+
hunk,
|
|
984
|
+
].filter(Boolean).join('\n');
|
|
985
|
+
const body = hunk.split('\n');
|
|
986
|
+
return {
|
|
987
|
+
stdout: patch,
|
|
988
|
+
truncated: result.truncated,
|
|
989
|
+
stats: {
|
|
990
|
+
files: 1,
|
|
991
|
+
added: body.filter((line) => line.startsWith('+') && !line.startsWith('+++')).length,
|
|
992
|
+
deleted: body.filter((line) => line.startsWith('-') && !line.startsWith('---')).length,
|
|
993
|
+
},
|
|
994
|
+
};
|
|
995
|
+
}
|
|
996
|
+
finally {
|
|
997
|
+
await fsp.rm(temporary, { recursive: true, force: true });
|
|
998
|
+
}
|
|
999
|
+
}
|
|
1000
|
+
async function buildCurrentTree(legalCase, gitDir, homeDir, baselineDocx = emptyDocxManifest(), { includeDocx = true } = {}) {
|
|
1001
|
+
const startedAt = performance.now();
|
|
1002
|
+
const temporaryIndex = path.join(historyDirectory(homeDir), `index-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
1003
|
+
const env = { GIT_INDEX_FILE: temporaryIndex };
|
|
1004
|
+
const [files, docxManifest] = await Promise.all([
|
|
1005
|
+
safeCaseFiles(legalCase.root),
|
|
1006
|
+
currentDocxManifest(legalCase.root, baselineDocx, { includeText: includeDocx }),
|
|
1007
|
+
]);
|
|
1008
|
+
try {
|
|
1009
|
+
await runGit(legalCase.root, ['read-tree', '--empty'], { gitDir, workTree: legalCase.root, env });
|
|
1010
|
+
if (files.length) {
|
|
1011
|
+
// Un seul processus Git reçoit les chemins en NUL sur stdin. L'ancien
|
|
1012
|
+
// découpage par groupes de 100 relançait Git 38 fois sur un gros dossier.
|
|
1013
|
+
await runGit(legalCase.root, [
|
|
1014
|
+
'add', '-f', '--pathspec-from-file=-', '--pathspec-file-nul',
|
|
1015
|
+
], {
|
|
1016
|
+
gitDir,
|
|
1017
|
+
workTree: legalCase.root,
|
|
1018
|
+
env,
|
|
1019
|
+
// Apple Git stocke les chemins précomposés dans l'index alors qu'APFS
|
|
1020
|
+
// les renvoie souvent décomposés. Les arguments argv étaient convertis
|
|
1021
|
+
// implicitement ; les pathspec lus sur stdin doivent l'être ici.
|
|
1022
|
+
input: Buffer.from(`${files.map((file) => process.platform === 'darwin' ? file.normalize('NFC') : file).join('\0')}\0`, 'utf8'),
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
if (includeDocx)
|
|
1026
|
+
await putDocxManifestInIndex(legalCase, gitDir, env, docxManifest);
|
|
1027
|
+
const tree = (await runGit(legalCase.root, ['write-tree'], { gitDir, workTree: legalCase.root, env })).stdout;
|
|
1028
|
+
if (includeDocx)
|
|
1029
|
+
boundedCacheSet(docxTreeCache, `${gitDir}\0${tree}`, docxManifest, 2_000);
|
|
1030
|
+
const snapshot = includeDocx
|
|
1031
|
+
? tree
|
|
1032
|
+
: crypto.createHash('sha1').update(`${tree}\0${serializeDocxManifest(docxManifest)}`).digest('hex');
|
|
1033
|
+
logPerformance('buildCurrentTree', startedAt, {
|
|
1034
|
+
files: files.length,
|
|
1035
|
+
gitAddBatches: files.length ? 1 : 0,
|
|
1036
|
+
});
|
|
1037
|
+
return { tree, snapshot, files, docxManifest };
|
|
1038
|
+
}
|
|
1039
|
+
finally {
|
|
1040
|
+
try {
|
|
1041
|
+
fs.unlinkSync(temporaryIndex);
|
|
1042
|
+
}
|
|
1043
|
+
catch { }
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
/**
|
|
1047
|
+
* Construit un arbre à partir du parent en n'y appliquant que les chemins de
|
|
1048
|
+
* l'opération courante. Les autres modifications présentes dans le work-tree
|
|
1049
|
+
* restent donc locales et ne peuvent pas fuiter dans un commit automatique.
|
|
1050
|
+
*/
|
|
1051
|
+
async function buildSelectedTree(legalCase, gitDir, homeDir, parent, selectedPaths) {
|
|
1052
|
+
const startedAt = performance.now();
|
|
1053
|
+
const temporaryIndex = path.join(historyDirectory(homeDir), `index-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`);
|
|
1054
|
+
const env = { GIT_INDEX_FILE: temporaryIndex };
|
|
1055
|
+
try {
|
|
1056
|
+
await runGit(legalCase.root, ['read-tree', ...(parent ? [parent] : ['--empty'])], {
|
|
1057
|
+
gitDir,
|
|
1058
|
+
workTree: legalCase.root,
|
|
1059
|
+
env,
|
|
1060
|
+
});
|
|
1061
|
+
if (selectedPaths.length) {
|
|
1062
|
+
await runGit(legalCase.root, [
|
|
1063
|
+
'add', '-f', '-A', '--pathspec-from-file=-', '--pathspec-file-nul',
|
|
1064
|
+
], {
|
|
1065
|
+
gitDir,
|
|
1066
|
+
workTree: legalCase.root,
|
|
1067
|
+
env,
|
|
1068
|
+
input: Buffer.from(`${selectedPaths.map((file) => process.platform === 'darwin' ? file.normalize('NFC') : file).join('\0')}\0`, 'utf8'),
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
const tree = (await runGit(legalCase.root, ['write-tree'], { gitDir, workTree: legalCase.root, env })).stdout;
|
|
1072
|
+
logPerformance('buildSelectedTree', startedAt, { files: selectedPaths.length });
|
|
1073
|
+
return { tree, files: selectedPaths };
|
|
1074
|
+
}
|
|
1075
|
+
finally {
|
|
1076
|
+
try {
|
|
1077
|
+
fs.unlinkSync(temporaryIndex);
|
|
1078
|
+
}
|
|
1079
|
+
catch { }
|
|
1080
|
+
}
|
|
1081
|
+
}
|
|
1082
|
+
async function emptyTree(legalCase, gitDir) {
|
|
1083
|
+
return (await runGit(legalCase.root, ['mktree'], { gitDir, input: '' })).stdout;
|
|
1084
|
+
}
|
|
1085
|
+
function parseNameStatus(raw) {
|
|
1086
|
+
return String(raw || '').split(/\r?\n/).filter(Boolean).map((line) => {
|
|
1087
|
+
const columns = line.split('\t');
|
|
1088
|
+
return { status: columns[0] || 'M', path: columns.at(-1) || '', previousPath: columns.length > 2 ? columns[1] : null };
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
function statusKind(code) {
|
|
1092
|
+
const value = String(code || '').trim();
|
|
1093
|
+
if (value.includes('A') || value === '??')
|
|
1094
|
+
return 'added';
|
|
1095
|
+
if (value.includes('D'))
|
|
1096
|
+
return 'deleted';
|
|
1097
|
+
if (value.includes('R'))
|
|
1098
|
+
return 'renamed';
|
|
1099
|
+
return 'modified';
|
|
1100
|
+
}
|
|
1101
|
+
async function diffTrees(legalCase, gitDir, from, to, manifests = null) {
|
|
1102
|
+
const raw = (await runGit(legalCase.root, ['diff-tree', '--no-commit-id', '--name-status', '-r', from, to], { gitDir })).stdout;
|
|
1103
|
+
const parsed = parseNameStatus(raw);
|
|
1104
|
+
const regular = parsed
|
|
1105
|
+
.filter((file) => file.path !== DOCX_MANIFEST_PATH)
|
|
1106
|
+
.map((file) => ({ ...file, kind: statusKind(file.status) }));
|
|
1107
|
+
let wordChanges = [];
|
|
1108
|
+
if (manifests) {
|
|
1109
|
+
wordChanges = docxChanges(manifests.before, manifests.after);
|
|
1110
|
+
}
|
|
1111
|
+
else if (parsed.some((file) => file.path === DOCX_MANIFEST_PATH)) {
|
|
1112
|
+
wordChanges = docxChanges(await treeDocxManifest(legalCase, gitDir, from), await treeDocxManifest(legalCase, gitDir, to));
|
|
1113
|
+
}
|
|
1114
|
+
return [...regular, ...wordChanges].sort((left, right) => left.path.localeCompare(right.path, 'fr'));
|
|
1115
|
+
}
|
|
1116
|
+
async function workingState(casesRoot, homeDir, caseName) {
|
|
1117
|
+
const startedAt = performance.now();
|
|
1118
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1119
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1120
|
+
const latest = await latestCommit(legalCase, gitDir);
|
|
1121
|
+
const base = latest || await emptyTree(legalCase, gitDir);
|
|
1122
|
+
const baselineDocx = latest ? await treeDocxManifest(legalCase, gitDir, base) : emptyDocxManifest();
|
|
1123
|
+
// L'admin compare le manifeste en mémoire. Il n'est écrit dans l'index Git
|
|
1124
|
+
// qu'au commit : aucun processus Git supplémentaire sur le chemin chaud.
|
|
1125
|
+
const current = await buildCurrentTree(legalCase, gitDir, homeDir, baselineDocx, { includeDocx: false });
|
|
1126
|
+
const changes = await diffTrees(legalCase, gitDir, base, current.tree, { before: baselineDocx, after: current.docxManifest });
|
|
1127
|
+
logPerformance('workingState', startedAt, { files: current.files.length, changes: changes.length });
|
|
1128
|
+
const state = { legalCase, gitDir, latest, current, base, baselineDocx, changes };
|
|
1129
|
+
caseStateCache.set(caseStateCacheKey(homeDir, legalCase), state);
|
|
1130
|
+
return state;
|
|
1131
|
+
}
|
|
1132
|
+
/**
|
|
1133
|
+
* Structured git trailers appended at the end of a commit message.
|
|
1134
|
+
*
|
|
1135
|
+
* `PieceMaker-Session` is the durable join key between a case's commits and the
|
|
1136
|
+
* billing ledger (which records the authoritative final duration at session
|
|
1137
|
+
* Stop). `PieceMaker-Temps-Session` is the session time elapsed at the instant
|
|
1138
|
+
* of the commit — so the last commit of a session carries ~its full duration,
|
|
1139
|
+
* and every commit is self-documenting without needing the ledger. Both stay
|
|
1140
|
+
* parseable (`Clé: valeur`) and are read back by `listHistory` via `%b`.
|
|
1141
|
+
*/
|
|
1142
|
+
function buildCommitTrailers({ sessionId, durationMs }) {
|
|
1143
|
+
const trailers = [];
|
|
1144
|
+
const session = String(sessionId || '').replace(/[\x00-\x1f\x7f]/g, '').trim().slice(0, 120);
|
|
1145
|
+
if (session)
|
|
1146
|
+
trailers.push(`PieceMaker-Session: ${session}`);
|
|
1147
|
+
if (Number.isFinite(durationMs) && durationMs >= 0) {
|
|
1148
|
+
const human = formatDurationFr(durationMs);
|
|
1149
|
+
if (human)
|
|
1150
|
+
trailers.push(`PieceMaker-Temps-Session: ${human} (${Math.round(durationMs)} ms)`);
|
|
1151
|
+
}
|
|
1152
|
+
return trailers;
|
|
1153
|
+
}
|
|
1154
|
+
async function createCommit({ casesRoot, caseName, homeDir = path.join(os.homedir(), '.piecemaker'), label = 'Commit PieceMaker', description = '', sessionId = null, durationMs = null, event = 'manual', paths = null, waitForLockMs = 0, identity = null, envFile = GLOBAL_ENV_FILE, } = {}) {
|
|
1155
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1156
|
+
caseStateCache.delete(caseStateCacheKey(homeDir, legalCase));
|
|
1157
|
+
const safeLabel = String(label || 'Commit PieceMaker').replace(/[\r\n]+/g, ' ').trim().slice(0, 140);
|
|
1158
|
+
const safeDescription = String(description || '').replaceAll('\0', '').replaceAll('\r\n', '\n').trim().slice(0, 4000);
|
|
1159
|
+
const selectedPaths = paths == null
|
|
1160
|
+
? null
|
|
1161
|
+
: [...new Set((Array.isArray(paths) ? paths : [paths]).map((file) => validateRelativeSafePath(legalCase, file)))];
|
|
1162
|
+
return withCaseLock(homeDir, legalCase, async () => {
|
|
1163
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1164
|
+
const parent = await latestCommit(legalCase, gitDir);
|
|
1165
|
+
const parentTree = parent
|
|
1166
|
+
? (await runGit(legalCase.root, ['rev-parse', `${parent}^{tree}`], { gitDir })).stdout
|
|
1167
|
+
: await emptyTree(legalCase, gitDir);
|
|
1168
|
+
const baselineDocx = selectedPaths === null && parent
|
|
1169
|
+
? await treeDocxManifest(legalCase, gitDir, parentTree)
|
|
1170
|
+
: emptyDocxManifest();
|
|
1171
|
+
const current = selectedPaths === null
|
|
1172
|
+
? await buildCurrentTree(legalCase, gitDir, homeDir, baselineDocx)
|
|
1173
|
+
: await buildSelectedTree(legalCase, gitDir, homeDir, parent, selectedPaths);
|
|
1174
|
+
if (current.tree === parentTree) {
|
|
1175
|
+
return { created: false, commit: parent || null, caseName: legalCase.name, files: [] };
|
|
1176
|
+
}
|
|
1177
|
+
const timestamp = new Date().toISOString();
|
|
1178
|
+
const trailers = buildCommitTrailers({ sessionId, durationMs });
|
|
1179
|
+
const message = `${safeLabel || 'Commit PieceMaker'}\n${safeDescription ? `\n${safeDescription}\n` : ''}${trailers.length ? `\n${trailers.join('\n')}\n` : ''}`;
|
|
1180
|
+
const commitIdentity = resolveCommitIdentity({ identity, envFile });
|
|
1181
|
+
const gitIdentity = {
|
|
1182
|
+
GIT_AUTHOR_NAME: commitIdentity.name,
|
|
1183
|
+
GIT_AUTHOR_EMAIL: commitIdentity.email,
|
|
1184
|
+
GIT_COMMITTER_NAME: commitIdentity.name,
|
|
1185
|
+
GIT_COMMITTER_EMAIL: commitIdentity.email,
|
|
1186
|
+
GIT_AUTHOR_DATE: timestamp,
|
|
1187
|
+
GIT_COMMITTER_DATE: timestamp,
|
|
1188
|
+
};
|
|
1189
|
+
const args = ['commit-tree', current.tree, ...(parent ? ['-p', parent] : [])];
|
|
1190
|
+
const commit = (await runGit(legalCase.root, args, { gitDir, env: gitIdentity, input: message })).stdout;
|
|
1191
|
+
await runGit(legalCase.root, ['update-ref', await activeHistoryRef(legalCase, gitDir), commit, ...(parent ? [parent] : [])], { gitDir });
|
|
1192
|
+
const files = await diffTrees(legalCase, gitDir, parentTree, current.tree, selectedPaths === null ? { before: baselineDocx, after: current.docxManifest } : null);
|
|
1193
|
+
return {
|
|
1194
|
+
created: true,
|
|
1195
|
+
commit,
|
|
1196
|
+
parent: parent || null,
|
|
1197
|
+
timestamp,
|
|
1198
|
+
label: safeLabel || 'Commit PieceMaker',
|
|
1199
|
+
sessionId,
|
|
1200
|
+
durationMs: Number.isFinite(durationMs) && durationMs >= 0 ? durationMs : null,
|
|
1201
|
+
event,
|
|
1202
|
+
author: commitIdentity.name,
|
|
1203
|
+
caseName: legalCase.name,
|
|
1204
|
+
files,
|
|
1205
|
+
};
|
|
1206
|
+
}, { waitMs: waitForLockMs });
|
|
1207
|
+
}
|
|
1208
|
+
function parseLog(raw) {
|
|
1209
|
+
return String(raw || '').split('\x1e').map((record) => record.trim()).filter(Boolean).map((record) => {
|
|
1210
|
+
const [hash, shortHash, author, timestamp, subject, ...body] = record.split('\x1f');
|
|
1211
|
+
return {
|
|
1212
|
+
hash,
|
|
1213
|
+
shortHash,
|
|
1214
|
+
author,
|
|
1215
|
+
timestamp,
|
|
1216
|
+
subject,
|
|
1217
|
+
body: body.join('\x1f').trim(),
|
|
1218
|
+
kind: 'commit',
|
|
1219
|
+
};
|
|
1220
|
+
}).filter((entry) => entry.hash);
|
|
1221
|
+
}
|
|
1222
|
+
async function listHistory(casesRoot, homeDir, { caseName, limit = 120 } = {}) {
|
|
1223
|
+
const startedAt = performance.now();
|
|
1224
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1225
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1226
|
+
if (!await latestCommit(legalCase, gitDir)) {
|
|
1227
|
+
logPerformance('listHistory', startedAt, { commits: 0 });
|
|
1228
|
+
return [];
|
|
1229
|
+
}
|
|
1230
|
+
const safeLimit = Math.min(Math.max(Number(limit) || 120, 1), 250);
|
|
1231
|
+
const historyRef = await activeHistoryRef(legalCase, gitDir);
|
|
1232
|
+
const raw = (await runGit(legalCase.root, [
|
|
1233
|
+
'log', `--max-count=${safeLimit}`, '--date=iso-strict',
|
|
1234
|
+
'--pretty=format:%x1e%H%x1f%h%x1f%an%x1f%aI%x1f%s%x1f%b', historyRef,
|
|
1235
|
+
], { gitDir })).stdout;
|
|
1236
|
+
const history = parseLog(raw);
|
|
1237
|
+
logPerformance('listHistory', startedAt, { commits: history.length, limit: safeLimit });
|
|
1238
|
+
return history;
|
|
1239
|
+
}
|
|
1240
|
+
/**
|
|
1241
|
+
* Les mois `YYYY-MM` où le dossier a des commits, du plus récent au plus
|
|
1242
|
+
* ancien — alimente le menu déroulant de l'export mensuel. Une seule colonne
|
|
1243
|
+
* (`%aI`) suffit : dériver le mois ne demande que les 7 premiers caractères
|
|
1244
|
+
* d'une date ISO stricte, pas un `git log` structuré comme `listHistory`.
|
|
1245
|
+
*/
|
|
1246
|
+
async function historyMonths(casesRoot, homeDir, { caseName } = {}) {
|
|
1247
|
+
const startedAt = performance.now();
|
|
1248
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1249
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1250
|
+
if (!await latestCommit(legalCase, gitDir)) {
|
|
1251
|
+
logPerformance('historyMonths', startedAt, { months: 0 });
|
|
1252
|
+
return [];
|
|
1253
|
+
}
|
|
1254
|
+
const historyRef = await activeHistoryRef(legalCase, gitDir);
|
|
1255
|
+
const raw = (await runGit(legalCase.root, ['log', '--date=iso-strict', '--pretty=format:%aI', historyRef], { gitDir })).stdout;
|
|
1256
|
+
const months = [...new Set(raw.split('\n').map((line) => line.trim().slice(0, 7)).filter(Boolean))].sort((left, right) => right.localeCompare(left));
|
|
1257
|
+
logPerformance('historyMonths', startedAt, { months: months.length });
|
|
1258
|
+
return months;
|
|
1259
|
+
}
|
|
1260
|
+
/**
|
|
1261
|
+
* Variante de `parseLog` avec la liste des fichiers touchés par chaque
|
|
1262
|
+
* commit. Le format ajoute un `%x1f` terminal après le corps (`%b`) : ce
|
|
1263
|
+
* séparateur referme le champ « corps », multi-ligne, sans ambiguïté avec la
|
|
1264
|
+
* liste de fichiers de `--name-only` qui le suit jusqu'au `\x1e` du commit
|
|
1265
|
+
* suivant. `parseLog` reste inchangé pour `listHistory` (son format n'a pas
|
|
1266
|
+
* ce dernier séparateur).
|
|
1267
|
+
*/
|
|
1268
|
+
function parseLogWithFiles(raw) {
|
|
1269
|
+
return String(raw || '').split('\x1e').map((record) => record.trim()).filter(Boolean).map((record) => {
|
|
1270
|
+
const fields = record.split('\x1f');
|
|
1271
|
+
const [hash, shortHash, author, timestamp, subject] = fields;
|
|
1272
|
+
// Entre le 5e séparateur et le dernier se trouve le corps (`%b`), qui ne
|
|
1273
|
+
// devrait jamais contenir de \x1f mais est rejoint par défense, comme le
|
|
1274
|
+
// fait déjà `parseLog` ; le tout dernier segment est la liste des
|
|
1275
|
+
// fichiers, un par ligne.
|
|
1276
|
+
const body = fields.slice(5, -1).join('\x1f').trim();
|
|
1277
|
+
const files = String(fields.at(-1) || '').split('\n').map((line) => line.trim()).filter(Boolean);
|
|
1278
|
+
return {
|
|
1279
|
+
hash,
|
|
1280
|
+
shortHash,
|
|
1281
|
+
author,
|
|
1282
|
+
timestamp,
|
|
1283
|
+
subject,
|
|
1284
|
+
body,
|
|
1285
|
+
kind: 'commit',
|
|
1286
|
+
files,
|
|
1287
|
+
filesCount: files.length,
|
|
1288
|
+
};
|
|
1289
|
+
}).filter((entry) => entry.hash);
|
|
1290
|
+
}
|
|
1291
|
+
/**
|
|
1292
|
+
* Sépare les trailers techniques `PieceMaker-*` du corps d'un commit (voir
|
|
1293
|
+
* `buildCommitTrailers`). Miroir du parsing côté client
|
|
1294
|
+
* (`admin/app.js` → `parsePieceMakerTrailers`), avec en plus la durée brute
|
|
1295
|
+
* en millisecondes que l'affichage seul n'a pas besoin de connaître mais
|
|
1296
|
+
* qu'un export chiffré (temps facturable par mois) exploite directement.
|
|
1297
|
+
*/
|
|
1298
|
+
function parseCommitTrailers(body) {
|
|
1299
|
+
const lines = String(body || '').split('\n');
|
|
1300
|
+
const kept = [];
|
|
1301
|
+
let sessionId = null;
|
|
1302
|
+
let durationMs = null;
|
|
1303
|
+
for (const line of lines) {
|
|
1304
|
+
const session = line.match(/^PieceMaker-Session:\s*(.+)$/);
|
|
1305
|
+
if (session) {
|
|
1306
|
+
sessionId = session[1].trim();
|
|
1307
|
+
continue;
|
|
1308
|
+
}
|
|
1309
|
+
const time = line.match(/^PieceMaker-Temps-Session:\s*.+?\((\d+)\s*ms\)\s*$/);
|
|
1310
|
+
if (time) {
|
|
1311
|
+
durationMs = Number(time[1]);
|
|
1312
|
+
continue;
|
|
1313
|
+
}
|
|
1314
|
+
kept.push(line);
|
|
1315
|
+
}
|
|
1316
|
+
return { comment: kept.join('\n').trim(), sessionId, durationMs };
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Commits d'une période `[since, until)`, fichiers touchés compris. `until`
|
|
1320
|
+
* est exclusif côté appelant (premier jour du mois suivant, typiquement) :
|
|
1321
|
+
* cette fonction ne fait aucune arithmétique de date, elle transmet telles
|
|
1322
|
+
* quelles à `--since`/`--until`. Pas de plafond façon `listHistory` — le hook
|
|
1323
|
+
* `PostToolUse` commite à chaque Write/Edit, un mois peut en compter des
|
|
1324
|
+
* milliers — seulement un plafond de sécurité large pour ne pas exploser
|
|
1325
|
+
* `MAX_GIT_BUFFER` sur un dossier anormalement actif.
|
|
1326
|
+
*/
|
|
1327
|
+
async function listHistoryPeriod(casesRoot, homeDir, { caseName, since, until } = {}) {
|
|
1328
|
+
const startedAt = performance.now();
|
|
1329
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1330
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1331
|
+
if (!await latestCommit(legalCase, gitDir)) {
|
|
1332
|
+
logPerformance('listHistoryPeriod', startedAt, { commits: 0 });
|
|
1333
|
+
return [];
|
|
1334
|
+
}
|
|
1335
|
+
const historyRef = await activeHistoryRef(legalCase, gitDir);
|
|
1336
|
+
const raw = (await runGit(legalCase.root, [
|
|
1337
|
+
'log', `--max-count=${MAX_HISTORY_PERIOD_COMMITS}`, '--date=iso-strict', '--name-only',
|
|
1338
|
+
...(since ? [`--since=${since}`] : []),
|
|
1339
|
+
...(until ? [`--until=${until}`] : []),
|
|
1340
|
+
'--pretty=format:%x1e%H%x1f%h%x1f%an%x1f%aI%x1f%s%x1f%b%x1f', historyRef,
|
|
1341
|
+
], { gitDir })).stdout;
|
|
1342
|
+
const history = parseLogWithFiles(raw).map((entry) => {
|
|
1343
|
+
const { comment, sessionId, durationMs } = parseCommitTrailers(entry.body);
|
|
1344
|
+
return { ...entry, comment, sessionId, durationMs };
|
|
1345
|
+
});
|
|
1346
|
+
logPerformance('listHistoryPeriod', startedAt, { commits: history.length, since, until });
|
|
1347
|
+
return history;
|
|
1348
|
+
}
|
|
1349
|
+
function normalizeRelativeHistoryPath(relativePath) {
|
|
1350
|
+
const normalized = String(relativePath || '').replaceAll('\\', '/').replace(/^\.\//, '');
|
|
1351
|
+
if (!normalized || path.posix.isAbsolute(normalized) || normalized.split('/').includes('..')) {
|
|
1352
|
+
throw new Error('Chemin de fichier invalide.');
|
|
1353
|
+
}
|
|
1354
|
+
return normalized;
|
|
1355
|
+
}
|
|
1356
|
+
function validateRelativeSafePath(legalCase, relativePath) {
|
|
1357
|
+
const normalized = normalizeRelativeHistoryPath(relativePath);
|
|
1358
|
+
const absolute = path.join(legalCase.root, ...normalized.split('/'));
|
|
1359
|
+
if (isProtectedFile(absolute, legalCase.root) || !SAFE_EXTENSIONS.has(path.extname(normalized).toLowerCase())) {
|
|
1360
|
+
throw new Error('Ce fichier n’est pas accessible à l’IA.');
|
|
1361
|
+
}
|
|
1362
|
+
return normalized;
|
|
1363
|
+
}
|
|
1364
|
+
function validateRelativeHistoryPath(legalCase, relativePath) {
|
|
1365
|
+
const normalized = normalizeRelativeHistoryPath(relativePath);
|
|
1366
|
+
return isDocxPath(normalized) ? normalized : validateRelativeSafePath(legalCase, normalized);
|
|
1367
|
+
}
|
|
1368
|
+
async function revisionMetadata(legalCase, gitDir, hash) {
|
|
1369
|
+
if (!/^[0-9a-f]{7,64}$/i.test(String(hash || '')))
|
|
1370
|
+
throw new Error('Identifiant de révision invalide.');
|
|
1371
|
+
const commit = (await runGit(legalCase.root, ['rev-parse', '--verify', `${hash}^{commit}`], { gitDir })).stdout;
|
|
1372
|
+
if ((await runGit(legalCase.root, ['merge-base', '--is-ancestor', commit, await activeHistoryRef(legalCase, gitDir)], { gitDir, allowFailure: true })).code !== 0) {
|
|
1373
|
+
throw new Error('Cette révision ne fait pas partie de ce dossier juridique.');
|
|
1374
|
+
}
|
|
1375
|
+
const raw = (await runGit(legalCase.root, ['show', '-s', '--date=iso-strict', '--format=%H%x1f%h%x1f%an%x1f%aI%x1f%s%x1f%b', commit], { gitDir })).stdout;
|
|
1376
|
+
const [fullHash, shortHash, author, timestamp, subject, ...body] = raw.split('\x1f');
|
|
1377
|
+
return { commit, hash: fullHash, shortHash, author, timestamp, subject, body: body.join('\x1f').trim() };
|
|
1378
|
+
}
|
|
1379
|
+
function parseShortStat(raw) {
|
|
1380
|
+
const value = String(raw || '');
|
|
1381
|
+
return {
|
|
1382
|
+
files: Number(value.match(/(\d+) files? changed/)?.[1] || 0),
|
|
1383
|
+
added: Number(value.match(/(\d+) insertions?\(\+\)/)?.[1] || 0),
|
|
1384
|
+
deleted: Number(value.match(/(\d+) deletions?\(-\)/)?.[1] || 0),
|
|
1385
|
+
};
|
|
1386
|
+
}
|
|
1387
|
+
async function revisionDetails(casesRoot, homeDir, caseName, hash, filePath = '') {
|
|
1388
|
+
const startedAt = performance.now();
|
|
1389
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1390
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1391
|
+
const meta = await revisionMetadata(legalCase, gitDir, hash);
|
|
1392
|
+
const commitTree = (await runGit(legalCase.root, ['rev-parse', `${meta.commit}^{tree}`], { gitDir })).stdout;
|
|
1393
|
+
const parent = await runGit(legalCase.root, ['rev-parse', '--verify', `${meta.commit}^`], { gitDir, allowFailure: true });
|
|
1394
|
+
const parentTree = parent.code === 0
|
|
1395
|
+
? (await runGit(legalCase.root, ['rev-parse', `${parent.stdout}^{tree}`], { gitDir })).stdout
|
|
1396
|
+
: await emptyTree(legalCase, gitDir);
|
|
1397
|
+
const files = await diffTrees(legalCase, gitDir, parentTree, commitTree);
|
|
1398
|
+
const selectedPath = filePath ? validateRelativeHistoryPath(legalCase, filePath) : '';
|
|
1399
|
+
const selectedFile = selectedPath ? files.find((file) => file.path === selectedPath) : null;
|
|
1400
|
+
if (selectedPath && !selectedFile)
|
|
1401
|
+
throw new Error('Ce fichier ne fait pas partie de cette révision.');
|
|
1402
|
+
// Sur un commit complet, Git doit parcourir tous les blobs une deuxième fois
|
|
1403
|
+
// pour produire le shortstat. Le patch contient déjà l'information utile et
|
|
1404
|
+
// est borné ci-dessous : ne calculer les statistiques que pour un fichier
|
|
1405
|
+
// explicitement sélectionné évite ce parcours redondant.
|
|
1406
|
+
const wordDiff = isDocxPath(selectedPath)
|
|
1407
|
+
? await docxTextDiff(legalCase, await treeDocxManifest(legalCase, gitDir, parentTree), await treeDocxManifest(legalCase, gitDir, commitTree), selectedPath)
|
|
1408
|
+
: null;
|
|
1409
|
+
const stats = wordDiff?.stats || (selectedPath
|
|
1410
|
+
? parseShortStat((await runGit(legalCase.root, [
|
|
1411
|
+
'diff-tree', '--root', '--no-commit-id', '--shortstat', '-r', meta.commit, '--', selectedPath,
|
|
1412
|
+
], { gitDir })).stdout)
|
|
1413
|
+
: { files: 0, added: 0, deleted: 0 });
|
|
1414
|
+
// Le premier clic sur un commit ne calcule que sa liste de fichiers. Le
|
|
1415
|
+
// patch, potentiellement volumineux, n'est demandé qu'après sélection d'un
|
|
1416
|
+
// fichier dans la colonne dédiée.
|
|
1417
|
+
const patchResult = wordDiff || (selectedPath
|
|
1418
|
+
? await runGit(legalCase.root, [
|
|
1419
|
+
'show', '--format=', '--no-ext-diff', '--unified=3', meta.commit, '--', selectedPath,
|
|
1420
|
+
], {
|
|
1421
|
+
gitDir,
|
|
1422
|
+
maxOutputBytes: MAX_PATCH_BYTES,
|
|
1423
|
+
truncateOutput: true,
|
|
1424
|
+
})
|
|
1425
|
+
: { stdout: '', truncated: false });
|
|
1426
|
+
const result = {
|
|
1427
|
+
...meta,
|
|
1428
|
+
kind: 'commit',
|
|
1429
|
+
files,
|
|
1430
|
+
filesCount: files.length,
|
|
1431
|
+
stats,
|
|
1432
|
+
selectedFile,
|
|
1433
|
+
selectedPath,
|
|
1434
|
+
patch: patchResult.stdout,
|
|
1435
|
+
truncated: patchResult.truncated,
|
|
1436
|
+
};
|
|
1437
|
+
logPerformance('revisionDetails', startedAt, {
|
|
1438
|
+
files: result.filesCount,
|
|
1439
|
+
selectedFile: Boolean(selectedPath),
|
|
1440
|
+
patchBytes: Buffer.byteLength(result.patch, 'utf8'),
|
|
1441
|
+
truncated: result.truncated,
|
|
1442
|
+
});
|
|
1443
|
+
return result;
|
|
1444
|
+
}
|
|
1445
|
+
async function worktreeDetails(casesRoot, homeDir, caseName, filePath = '', snapshot = '') {
|
|
1446
|
+
const startedAt = performance.now();
|
|
1447
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1448
|
+
const cached = caseStateCache.get(caseStateCacheKey(homeDir, legalCase));
|
|
1449
|
+
const state = snapshot && cached?.current.snapshot === snapshot
|
|
1450
|
+
? cached
|
|
1451
|
+
: await workingState(casesRoot, homeDir, caseName);
|
|
1452
|
+
const selectedPath = filePath ? validateRelativeHistoryPath(state.legalCase, filePath) : '';
|
|
1453
|
+
if (selectedPath && !state.changes.some((file) => file.path === selectedPath)) {
|
|
1454
|
+
throw new Error('Ce fichier ne fait pas partie des modifications actuelles.');
|
|
1455
|
+
}
|
|
1456
|
+
const selectedFile = selectedPath ? state.changes.find((file) => file.path === selectedPath) : null;
|
|
1457
|
+
const wordDiff = isDocxPath(selectedPath)
|
|
1458
|
+
? await docxTextDiff(state.legalCase, state.baselineDocx, state.current.docxManifest, selectedPath)
|
|
1459
|
+
: null;
|
|
1460
|
+
const statsRaw = wordDiff || !selectedPath ? '' : (await runGit(state.legalCase.root, [
|
|
1461
|
+
'diff', '--shortstat', state.base, state.current.tree, '--', selectedPath,
|
|
1462
|
+
], { gitDir: state.gitDir })).stdout;
|
|
1463
|
+
const stats = wordDiff?.stats || parseShortStat(statsRaw);
|
|
1464
|
+
const patchResult = wordDiff || (!selectedPath
|
|
1465
|
+
? { stdout: '', truncated: false }
|
|
1466
|
+
: await runGit(state.legalCase.root, [
|
|
1467
|
+
'diff', '--no-ext-diff', '--unified=3', state.base, state.current.tree, '--', selectedPath,
|
|
1468
|
+
], {
|
|
1469
|
+
gitDir: state.gitDir,
|
|
1470
|
+
maxOutputBytes: MAX_PATCH_BYTES,
|
|
1471
|
+
truncateOutput: true,
|
|
1472
|
+
}));
|
|
1473
|
+
const result = {
|
|
1474
|
+
hash: 'WORKTREE',
|
|
1475
|
+
shortHash: '',
|
|
1476
|
+
author: 'Modifications locales',
|
|
1477
|
+
timestamp: new Date().toISOString(),
|
|
1478
|
+
subject: 'Modifications depuis le dernier commit',
|
|
1479
|
+
kind: 'worktree',
|
|
1480
|
+
files: state.changes,
|
|
1481
|
+
filesCount: state.changes.length,
|
|
1482
|
+
stats,
|
|
1483
|
+
selectedFile,
|
|
1484
|
+
selectedPath,
|
|
1485
|
+
patch: patchResult.stdout,
|
|
1486
|
+
truncated: patchResult.truncated,
|
|
1487
|
+
};
|
|
1488
|
+
logPerformance('worktreeDetails', startedAt, {
|
|
1489
|
+
files: state.changes.length,
|
|
1490
|
+
selectedFile: Boolean(selectedPath),
|
|
1491
|
+
patchBytes: Buffer.byteLength(result.patch, 'utf8'),
|
|
1492
|
+
truncated: result.truncated,
|
|
1493
|
+
});
|
|
1494
|
+
return result;
|
|
1495
|
+
}
|
|
1496
|
+
function listCases(casesRoot) {
|
|
1497
|
+
const requestedRoot = path.resolve(String(casesRoot || ''));
|
|
1498
|
+
if (!fs.existsSync(requestedRoot)) {
|
|
1499
|
+
return { name: 'PieceMaker', root: requestedRoot, branch: 'Dossiers indépendants', head: '', shortHead: '', folders: [], changes: [] };
|
|
1500
|
+
}
|
|
1501
|
+
const root = resolveCasesRoot(requestedRoot);
|
|
1502
|
+
const entries = fs.readdirSync(root, { withFileTypes: true })
|
|
1503
|
+
.filter((entry) => entry.isDirectory()
|
|
1504
|
+
&& !entry.isSymbolicLink()
|
|
1505
|
+
&& !entry.name.startsWith('.')
|
|
1506
|
+
&& !isTechnicalCaseDirectoryName(entry.name))
|
|
1507
|
+
.sort((a, b) => a.name.localeCompare(b.name, 'fr'));
|
|
1508
|
+
return {
|
|
1509
|
+
name: path.basename(root),
|
|
1510
|
+
root,
|
|
1511
|
+
branch: 'Dossiers indépendants',
|
|
1512
|
+
head: '',
|
|
1513
|
+
shortHead: '',
|
|
1514
|
+
folders: entries.map((entry) => ({ name: entry.name, path: entry.name })),
|
|
1515
|
+
changes: [],
|
|
1516
|
+
};
|
|
1517
|
+
}
|
|
1518
|
+
async function caseOverview(casesRoot, homeDir, caseName) {
|
|
1519
|
+
const startedAt = performance.now();
|
|
1520
|
+
const state = await workingState(casesRoot, homeDir, caseName);
|
|
1521
|
+
const originals = await originalFilesOverview(state.legalCase.root, { safeFiles: state.current.files });
|
|
1522
|
+
const enrichedChanges = await Promise.all(state.changes.map(async (change) => {
|
|
1523
|
+
if (change.kind === 'deleted')
|
|
1524
|
+
return change;
|
|
1525
|
+
try {
|
|
1526
|
+
const stat = await fsp.stat(path.join(state.legalCase.root, ...change.path.split('/')));
|
|
1527
|
+
return { ...change, modifiedAt: stat.mtime.toISOString() };
|
|
1528
|
+
}
|
|
1529
|
+
catch {
|
|
1530
|
+
return change;
|
|
1531
|
+
}
|
|
1532
|
+
}));
|
|
1533
|
+
const folder = {
|
|
1534
|
+
name: state.legalCase.name,
|
|
1535
|
+
path: state.legalCase.name,
|
|
1536
|
+
changes: enrichedChanges.length,
|
|
1537
|
+
workingChanges: enrichedChanges,
|
|
1538
|
+
head: state.latest,
|
|
1539
|
+
shortHead: state.latest.slice(0, 7),
|
|
1540
|
+
snapshot: state.current.snapshot,
|
|
1541
|
+
originals,
|
|
1542
|
+
protectedOriginals: originals.filter((file) => file.protected).length,
|
|
1543
|
+
};
|
|
1544
|
+
logPerformance('caseOverview', startedAt, {
|
|
1545
|
+
files: state.current.files.length,
|
|
1546
|
+
changes: state.changes.length,
|
|
1547
|
+
originals: originals.length,
|
|
1548
|
+
});
|
|
1549
|
+
return folder;
|
|
1550
|
+
}
|
|
1551
|
+
async function repositoryOverview(casesRoot, homeDir = path.join(os.homedir(), '.piecemaker')) {
|
|
1552
|
+
const startedAt = performance.now();
|
|
1553
|
+
const repository = listCases(casesRoot);
|
|
1554
|
+
if (!repository.folders.length) {
|
|
1555
|
+
logPerformance('repositoryOverview', startedAt, { folders: 0 });
|
|
1556
|
+
return repository;
|
|
1557
|
+
}
|
|
1558
|
+
// Séquentiel : chaque dossier lance déjà une série de processus git, les
|
|
1559
|
+
// paralléliser en ferait exploser le nombre sur un poste de travail.
|
|
1560
|
+
const folders = [];
|
|
1561
|
+
for (const entry of repository.folders) {
|
|
1562
|
+
folders.push(await caseOverview(repository.root, homeDir, entry.name));
|
|
1563
|
+
}
|
|
1564
|
+
const result = { ...repository, folders };
|
|
1565
|
+
logPerformance('repositoryOverview', startedAt, {
|
|
1566
|
+
folders: folders.length,
|
|
1567
|
+
workingChanges: folders.reduce((count, folder) => count + folder.workingChanges.length, 0),
|
|
1568
|
+
originals: folders.reduce((count, folder) => count + folder.originals.length, 0),
|
|
1569
|
+
});
|
|
1570
|
+
return result;
|
|
1571
|
+
}
|
|
1572
|
+
function safeDestination(legalCase, relativePath) {
|
|
1573
|
+
const normalized = validateRelativeSafePath(legalCase, relativePath);
|
|
1574
|
+
let current = legalCase.root;
|
|
1575
|
+
const parts = normalized.split('/');
|
|
1576
|
+
for (const part of parts.slice(0, -1)) {
|
|
1577
|
+
current = path.join(current, part);
|
|
1578
|
+
if (fs.existsSync(current) && fs.lstatSync(current).isSymbolicLink())
|
|
1579
|
+
throw new Error('Restauration refusée à travers un lien symbolique.');
|
|
1580
|
+
}
|
|
1581
|
+
return { normalized, absolute: path.join(legalCase.root, ...parts) };
|
|
1582
|
+
}
|
|
1583
|
+
async function restoreRevision({ casesRoot, caseName, homeDir = path.join(os.homedir(), '.piecemaker'), hash } = {}) {
|
|
1584
|
+
const legalCase = resolveCase(casesRoot, caseName);
|
|
1585
|
+
const gitDir = await ensureHistoryRepo(homeDir, legalCase);
|
|
1586
|
+
const meta = await revisionMetadata(legalCase, gitDir, hash);
|
|
1587
|
+
const safety = await createCommit({
|
|
1588
|
+
casesRoot: legalCase.casesRoot,
|
|
1589
|
+
caseName: legalCase.name,
|
|
1590
|
+
homeDir,
|
|
1591
|
+
label: `Sauvegarde avant restauration de ${meta.shortHash}`,
|
|
1592
|
+
event: 'before-restore',
|
|
1593
|
+
});
|
|
1594
|
+
if (safety.skipped === 'busy')
|
|
1595
|
+
throw new Error('Un commit est déjà en cours. Réessayez dans quelques secondes.');
|
|
1596
|
+
const targetFiles = (await runGit(legalCase.root, ['ls-tree', '-r', '--name-only', meta.commit], { gitDir })).stdout
|
|
1597
|
+
.split(/\r?\n/)
|
|
1598
|
+
.filter((relative) => relative && relative !== DOCX_MANIFEST_PATH);
|
|
1599
|
+
const targetSet = new Set(targetFiles);
|
|
1600
|
+
for (const relative of await safeCaseFiles(legalCase.root)) {
|
|
1601
|
+
if (!targetSet.has(relative))
|
|
1602
|
+
fs.unlinkSync(safeDestination(legalCase, relative).absolute);
|
|
1603
|
+
}
|
|
1604
|
+
for (const relative of targetFiles) {
|
|
1605
|
+
const destination = safeDestination(legalCase, relative);
|
|
1606
|
+
fs.mkdirSync(path.dirname(destination.absolute), { recursive: true });
|
|
1607
|
+
const content = (await runGit(legalCase.root, ['show', `${meta.commit}:${destination.normalized}`], { gitDir, encoding: null })).stdout;
|
|
1608
|
+
const temporary = `${destination.absolute}.piecemaker-${process.pid}.tmp`;
|
|
1609
|
+
fs.writeFileSync(temporary, content);
|
|
1610
|
+
fs.renameSync(temporary, destination.absolute);
|
|
1611
|
+
}
|
|
1612
|
+
const restoredState = await createCommit({
|
|
1613
|
+
casesRoot: legalCase.casesRoot,
|
|
1614
|
+
caseName: legalCase.name,
|
|
1615
|
+
homeDir,
|
|
1616
|
+
label: `Restauration de ${meta.shortHash} · ${meta.subject}`,
|
|
1617
|
+
event: 'restore',
|
|
1618
|
+
});
|
|
1619
|
+
return {
|
|
1620
|
+
restored: true,
|
|
1621
|
+
revision: meta.commit,
|
|
1622
|
+
safetyCommit: safety.commit || null,
|
|
1623
|
+
restorationCommit: restoredState.commit || null,
|
|
1624
|
+
changes: (await workingState(legalCase.casesRoot, homeDir, legalCase.name)).changes,
|
|
1625
|
+
originalsPreserved: true,
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
module.exports = {
|
|
1629
|
+
COMMIT_USER_NAME_KEY,
|
|
1630
|
+
GLOBAL_ENV_FILE,
|
|
1631
|
+
IDENTITY_CONFIG_FILE,
|
|
1632
|
+
SAFE_EXTENSIONS,
|
|
1633
|
+
readCommitIdentityConfig,
|
|
1634
|
+
caseOverview,
|
|
1635
|
+
checkoutHistoryBranch,
|
|
1636
|
+
createCommit,
|
|
1637
|
+
createHistoryBranch,
|
|
1638
|
+
historyBranches,
|
|
1639
|
+
historyMonths,
|
|
1640
|
+
historyRepo,
|
|
1641
|
+
isProtectedFile,
|
|
1642
|
+
isTechnicalCaseDirectoryName,
|
|
1643
|
+
listCases,
|
|
1644
|
+
logPerformance,
|
|
1645
|
+
listHistory,
|
|
1646
|
+
listHistoryPeriod,
|
|
1647
|
+
locateCaseFile,
|
|
1648
|
+
parseCommitTrailers,
|
|
1649
|
+
originalFilesOverview,
|
|
1650
|
+
repositoryOverview,
|
|
1651
|
+
resolveCommitIdentity,
|
|
1652
|
+
resolveCase,
|
|
1653
|
+
resolveCasesRoot,
|
|
1654
|
+
restoreRevision,
|
|
1655
|
+
revisionDetails,
|
|
1656
|
+
runGit,
|
|
1657
|
+
safeCaseFiles,
|
|
1658
|
+
worktreeDetails,
|
|
1659
|
+
};
|
|
1660
|
+
//# sourceMappingURL=commits.cjs.map
|