@piecemaker-legal/piecemaker 2.0.9 → 2.0.10

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.
Files changed (165) hide show
  1. package/dist/assets/FindReplaceDialog-KU5TEIBJ-CQ76sPaJ.js +1 -0
  2. package/dist/assets/FootnotePropertiesDialog-W3YHM4BV-BpgYQvvd.js +1 -0
  3. package/dist/assets/HyperlinkDialog-ZYH7ZHRF-qIPBOssF.css +1 -0
  4. package/dist/assets/HyperlinkDialog-ZYH7ZHRF-z08UbYbL.js +144 -0
  5. package/dist/assets/ImagePositionDialog-HEWYR6Q3-CFzOnzAt.js +1 -0
  6. package/dist/assets/ImagePropertiesDialog-RAB47C6M-D-ThGU-b.js +1 -0
  7. package/dist/assets/PageSetupDialog-AIGIXO3E-_PYIO8eb.js +1 -0
  8. package/dist/assets/SplitCellDialog-IFBKYCD6-Cb9uQOB8.js +1 -0
  9. package/dist/assets/TablePropertiesDialog-TMLKGOOW-12vmjb6B.js +1 -0
  10. package/dist/assets/WatermarkDialog-KRL7WMIS-C-d8rzt2.js +1 -0
  11. package/dist/assets/{abnfDiagram-VCTEODGH-WrsSAHOe.js → abnfDiagram-VCTEODGH-B4OsX7eF.js} +1 -1
  12. package/dist/assets/arc-BK1oUIk7.js +1 -0
  13. package/dist/assets/architectureDiagram-5GKGNRK7-CfaFI6L7.js +36 -0
  14. package/dist/assets/{blockDiagram-I7D4REHJ-zGMnF7Ox.js → blockDiagram-I7D4REHJ-DQEI2azY.js} +1 -1
  15. package/dist/assets/{c4Diagram-7LVT6UL2-ClWw3bqt.js → c4Diagram-7LVT6UL2-DbravpVi.js} +1 -1
  16. package/dist/assets/channel-DVyNr2Yg.js +1 -0
  17. package/dist/assets/{chunk-2Q5K7J3B-C-9ICPHv.js → chunk-2Q5K7J3B-BLpZ9huC.js} +1 -1
  18. package/dist/assets/{chunk-5VM5RSS4-Bawy3teT.js → chunk-5VM5RSS4-BLlEdmX9.js} +1 -1
  19. package/dist/assets/{chunk-F27PBJKO-DQ375RQO.js → chunk-F27PBJKO-D-ZNhI6q.js} +1 -1
  20. package/dist/assets/{chunk-IMKFNOWR-CflNF2f6.js → chunk-IMKFNOWR-vzSiKnhh.js} +1 -1
  21. package/dist/assets/{chunk-JWPE2WC7-CIXQv0gc.js → chunk-JWPE2WC7-DfF0k4nb.js} +1 -1
  22. package/dist/assets/{chunk-POPQ4Y6H-Cza5j6Qw.js → chunk-POPQ4Y6H-BnwCYsPP.js} +1 -1
  23. package/dist/assets/{chunk-SVP7TREG-GQ_VvWZR.js → chunk-SVP7TREG-DRxc8fhq.js} +1 -1
  24. package/dist/assets/{chunk-TICWLB2K-BEmU16W5.js → chunk-TICWLB2K-Dd2Q-md-.js} +1 -1
  25. package/dist/assets/{chunk-XXDRQBXY-C1KpkLYH.js → chunk-XXDRQBXY-DBjkEUp_.js} +1 -1
  26. package/dist/assets/classDiagram-ZZMXUADV-2pGPHl5H.js +1 -0
  27. package/dist/assets/classDiagram-v2-VYDZK3BY-2pGPHl5H.js +1 -0
  28. package/dist/assets/{cose-bilkent-JH36ORCC-CZE48TRG.js → cose-bilkent-JH36ORCC-By6PS4oe.js} +1 -1
  29. package/dist/assets/{cynefin-OW5HDTMX-L-tx1eC-.js → cynefin-OW5HDTMX-YxWpjc5W.js} +1 -1
  30. package/dist/assets/{cynefinDiagram-5FMLGOSQ-Coa8oJwR.js → cynefinDiagram-5FMLGOSQ-DrtXzz3p.js} +1 -1
  31. package/dist/assets/{dagre-GXQ25YYZ-Bu_3Y75K.js → dagre-GXQ25YYZ-BDpTLKqZ.js} +1 -1
  32. package/dist/assets/{diagram-S7CK7UJ4-CFiiV4es.js → diagram-S7CK7UJ4-C4LvqeCs.js} +1 -1
  33. package/dist/assets/{diagram-UQ7AKVKN-CCXheGAA.js → diagram-UQ7AKVKN-BTpnMeHp.js} +1 -1
  34. package/dist/assets/{diagram-VSXAHHWV-B70m4lr_.js → diagram-VSXAHHWV-DucHHWev.js} +1 -1
  35. package/dist/assets/{diagram-VX7I27RA-CHkiMOVA.js → diagram-VX7I27RA-DYHZNmmH.js} +1 -1
  36. package/dist/assets/{diagram-Z3DM3KII-_awpc4Bs.js → diagram-Z3DM3KII-BHIH2BGN.js} +1 -1
  37. package/dist/assets/{ebnfDiagram-PWID7BFC-CZzjH86H.js → ebnfDiagram-PWID7BFC-CGiEkwj0.js} +1 -1
  38. package/dist/assets/{erDiagram-RLTQ6QDP-9DgiHZg9.js → erDiagram-RLTQ6QDP-AJMHi2Us.js} +1 -1
  39. package/dist/assets/{flowDiagram-HODETNUW-DHY_503b.js → flowDiagram-HODETNUW-BqzANBh2.js} +1 -1
  40. package/dist/assets/{ganttDiagram-EL5Y4UJY-DPiiYZ_l.js → ganttDiagram-EL5Y4UJY-B0xPDY2_.js} +1 -1
  41. package/dist/assets/{gitGraphDiagram-WWUBYQGX-Ddd_evm7.js → gitGraphDiagram-WWUBYQGX-CzPX5CNO.js} +1 -1
  42. package/dist/assets/{index-tibHq7Qp.js → index-Bk2iXKnJ.js} +140 -140
  43. package/dist/assets/index-Dc9wNuS4.css +1 -0
  44. package/dist/assets/{infoDiagram-27XIBGKW-BPRNhfwb.js → infoDiagram-27XIBGKW-Cjc44H0O.js} +1 -1
  45. package/dist/assets/{ishikawaDiagram-5VMMS53U-BXx6aqkq.js → ishikawaDiagram-5VMMS53U-BWhr2v7r.js} +1 -1
  46. package/dist/assets/{journeyDiagram-3NMN7TZE-BK8TZM29.js → journeyDiagram-3NMN7TZE-Bl4r6RrP.js} +1 -1
  47. package/dist/assets/{kanban-definition-UXKFOSKX-CHioRmxz.js → kanban-definition-UXKFOSKX-FV-T0Vy1.js} +6 -6
  48. package/dist/assets/layout-CTfb1sAF.js +1 -0
  49. package/dist/assets/{linear-CTEhUcKG.js → linear-Dfgi6vlo.js} +1 -1
  50. package/dist/assets/{mermaid.core-DYUb_UUB.js → mermaid.core-DOCGsdlo.js} +7 -7
  51. package/dist/assets/{mindmap-definition-YA3MSWOX-D7ODZ4oS.js → mindmap-definition-YA3MSWOX-CymQ86ir.js} +1 -1
  52. package/dist/assets/{pegDiagram-XKGWAZYB-8J-_2_kw.js → pegDiagram-XKGWAZYB-1VMq_vi0.js} +1 -1
  53. package/dist/assets/{pieDiagram-E7YTZNPT-ebg0yfMi.js → pieDiagram-E7YTZNPT-C5GgXtJU.js} +1 -1
  54. package/dist/assets/processTemplate-GPFDLQMX-B1sVV2O0.js +22 -0
  55. package/dist/assets/{quadrantDiagram-AXDQQJYC-BoWkDiFb.js → quadrantDiagram-AXDQQJYC-C6zpryYf.js} +1 -1
  56. package/dist/assets/{railroadDiagram-O6MQD6OU-BRJ77ldz.js → railroadDiagram-O6MQD6OU-D-sv4SWi.js} +1 -1
  57. package/dist/assets/{requirementDiagram-BXWQKSXE-Z0JJgktA.js → requirementDiagram-BXWQKSXE-CkjY-z4B.js} +1 -1
  58. package/dist/assets/sankeyDiagram-P5KCCOFB-De-d8Q6L.js +40 -0
  59. package/dist/assets/{sequenceDiagram-WJ2MYXX4-BPAjtXwp.js → sequenceDiagram-WJ2MYXX4-DCsGSJa9.js} +1 -1
  60. package/dist/assets/{server.browser-BzI1jrZw.js → server.browser-BY3bL-IX.js} +1 -1
  61. package/dist/assets/{sizeCapture-INFHLROL-BGZPCzM4.js → sizeCapture-INFHLROL-xINZhgER.js} +1 -1
  62. package/dist/assets/stateDiagram-D77RDMKH-CuLUTWSL.js +1 -0
  63. package/dist/assets/stateDiagram-v2-MP3YSRHH-Cnbs-M92.js +1 -0
  64. package/dist/assets/{swimlanes-42K2YHIH-DvuB15qF.js → swimlanes-42K2YHIH-BwxARD7N.js} +1 -1
  65. package/dist/assets/swimlanesDiagram-VR7AAH4N-D7p8qZI2.js +8 -0
  66. package/dist/assets/{timeline-definition-24CTP7MA-ZIziYCIF.js → timeline-definition-24CTP7MA-BIOvnn-l.js} +3 -3
  67. package/dist/assets/{vendor-codemirror-CjW0lHR5.js → vendor-codemirror-CN-sJePf.js} +2 -2
  68. package/dist/assets/{vendor-react-D809iwXR.js → vendor-react-B22wqN3J.js} +5 -5
  69. package/dist/assets/{vennDiagram-4TSXK5OY-C5_B9gWa.js → vennDiagram-4TSXK5OY-BSD6Pfmt.js} +4 -4
  70. package/dist/assets/{wardleyDiagram-VM6X3IG4-DMlH9Afw.js → wardleyDiagram-VM6X3IG4-7Zz2iRkF.js} +1 -1
  71. package/dist/assets/{xychartDiagram-S5SC5T6Z-BldhJt7i.js → xychartDiagram-S5SC5T6Z-Ctx17Y1D.js} +1 -1
  72. package/dist/index.html +4 -4
  73. package/dist/sw.js +1 -1
  74. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js +4 -53
  75. package/dist-server/server/modules/providers/list/mistral/mistral-models.provider.js.map +1 -1
  76. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js +2 -3
  77. package/dist-server/server/modules/providers/list/mistral/mistral-runtime.provider.js.map +1 -1
  78. package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js +30 -0
  79. package/dist-server/server/modules/providers/list/mistral/mistral-vibe-models.js.map +1 -0
  80. package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js +24 -0
  81. package/dist-server/server/modules/providers/tests/mistral-vibe-models.test.js.map +1 -0
  82. package/dist-server/server/piecemaker/anonymizer/lifecycle.js +2 -3
  83. package/dist-server/server/piecemaker/anonymizer/lifecycle.js.map +1 -1
  84. package/dist-server/server/piecemaker/docx-document.js +50 -0
  85. package/dist-server/server/piecemaker/docx-document.js.map +1 -0
  86. package/dist-server/server/piecemaker/index.js +9 -2
  87. package/dist-server/server/piecemaker/index.js.map +1 -1
  88. package/dist-server/server/piecemaker/model-discovery/codex-catalog.js +46 -0
  89. package/dist-server/server/piecemaker/model-discovery/codex-catalog.js.map +1 -0
  90. package/dist-server/server/piecemaker/model-discovery/index.js +42 -0
  91. package/dist-server/server/piecemaker/model-discovery/index.js.map +1 -0
  92. package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js +19 -0
  93. package/dist-server/server/piecemaker/model-discovery/mistral-catalog.js.map +1 -0
  94. package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js +61 -0
  95. package/dist-server/server/piecemaker/model-discovery/stdio-rpc.js.map +1 -0
  96. package/dist-server/server/piecemaker/project-registry.js +29 -0
  97. package/dist-server/server/piecemaker/project-registry.js.map +1 -0
  98. package/package.json +12 -1
  99. package/scripts/piecemaker/cli/disable-anonymizer.mjs +19 -0
  100. package/scripts/piecemaker/cli/lib/config.mjs +0 -1
  101. package/scripts/piecemaker/cli/lib/services.mjs +1 -10
  102. package/scripts/piecemaker/cli/piecemaker.mjs +0 -3
  103. package/server/modules/providers/list/mistral/mistral-models.provider.ts +4 -53
  104. package/server/modules/providers/list/mistral/mistral-runtime.provider.ts +2 -3
  105. package/server/modules/providers/list/mistral/mistral-vibe-models.ts +43 -0
  106. package/server/modules/providers/tests/mistral-vibe-models.test.ts +27 -0
  107. package/server/piecemaker/anonymizer/client-config.cjs +92 -92
  108. package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +9 -16
  109. package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.toml +1 -1
  110. package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +251 -268
  111. package/server/piecemaker/anonymizer/lifecycle.ts +2 -3
  112. package/server/piecemaker/anonymizer/rewriter-bridge.cjs +6 -0
  113. package/server/piecemaker/anonymizer/service.cjs +103 -174
  114. package/server/piecemaker/docx-document.ts +54 -0
  115. package/server/piecemaker/harness/decisions.cjs +1 -1
  116. package/server/piecemaker/harness/index.cjs +2 -3
  117. package/server/piecemaker/harness/verification.cjs +1 -1
  118. package/server/piecemaker/index.ts +11 -3
  119. package/server/piecemaker/model-discovery/codex-catalog.ts +67 -0
  120. package/server/piecemaker/model-discovery/index.ts +69 -0
  121. package/server/piecemaker/model-discovery/mistral-catalog.ts +36 -0
  122. package/server/piecemaker/model-discovery/stdio-rpc.ts +79 -0
  123. package/server/piecemaker/project-registry.ts +34 -0
  124. package/server/piecemaker/router.cjs +6 -7
  125. package/server/piecemaker/vendor/installer/bin/piecemaker.mjs +31 -77
  126. package/server/piecemaker/vendor/installer/lib/codex-skills.mjs +2 -84
  127. package/server/piecemaker/vendor/installer/lib/service.mjs +4 -24
  128. package/server/piecemaker/vendor/installer/steps/06-hooks.mjs +10 -21
  129. package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +0 -11
  130. package/server/piecemaker/vendor/installer/steps/09-codex-plugin.mjs +6 -36
  131. package/server/piecemaker/vendor/installer/steps/13-garde-secrets.mjs +30 -12
  132. package/server/piecemaker/vendor/piecemaker-plugin/README.md +2 -9
  133. package/server/piecemaker/vendor/piecemaker-plugin/scripts/billing-track.mjs +5 -5
  134. package/server/piecemaker/vendor/piecemaker-plugin/scripts/classify-ai-documents.mjs +8 -8
  135. package/server/piecemaker/vendor/piecemaker-plugin/scripts/commit-track.mjs +2 -2
  136. package/server/piecemaker/vendor/piecemaker-plugin/scripts/compile-recherche.mjs +4 -6
  137. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/case-folders.cjs +71 -38
  138. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/mapping.cjs +8 -38
  139. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/protection.cjs +82 -61
  140. package/server/piecemaker/vendor/piecemaker-plugin/scripts/protect-originals.mjs +4 -55
  141. package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +24 -117
  142. package/server/piecemaker/vendor/piecemaker-plugin/skills/tamponnage/SKILL.md +2 -2
  143. package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +15 -121
  144. package/server/piecemaker/vendor/websocket-server/case-registry.cjs +16 -32
  145. package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +0 -73
  146. package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +0 -7
  147. package/server/piecemaker/vendor/websocket-server/stamping-routes.cjs +3 -12
  148. package/server/piecemaker/vendor/websocket-server/workspace-paths.cjs +6 -6
  149. package/dist/assets/arc-DAA6wH-C.js +0 -1
  150. package/dist/assets/architectureDiagram-5GKGNRK7-BGNHr7ef.js +0 -36
  151. package/dist/assets/channel-BAQyfMll.js +0 -1
  152. package/dist/assets/classDiagram-ZZMXUADV-BNGCuvrR.js +0 -1
  153. package/dist/assets/classDiagram-v2-VYDZK3BY-BNGCuvrR.js +0 -1
  154. package/dist/assets/index-WwknP0l4.css +0 -1
  155. package/dist/assets/layout-DEnkyfTY.js +0 -1
  156. package/dist/assets/sankeyDiagram-P5KCCOFB-4PW5HTOP.js +0 -40
  157. package/dist/assets/stateDiagram-D77RDMKH-o-vEcKwz.js +0 -1
  158. package/dist/assets/stateDiagram-v2-MP3YSRHH-BsuDaKkN.js +0 -1
  159. package/dist/assets/swimlanesDiagram-VR7AAH4N-DcCAyKlT.js +0 -8
  160. package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +0 -78
  161. package/scripts/piecemaker/hooks/proxy-guard.mjs +0 -251
  162. package/server/piecemaker/anonymizer/providers.cjs +0 -120
  163. package/server/piecemaker/vendor/installer/steps/08-telegram.mjs +0 -482
  164. package/server/piecemaker/vendor/piecemaker-plugin/scripts/lib/central-mapping.cjs +0 -0
  165. package/server/piecemaker/vendor/websocket-server/telegram-admin.cjs +0 -602
@@ -0,0 +1,43 @@
1
+ import type { ProviderModelOption } from '@/shared/types.js';
2
+
3
+ type VibeModelPreset = {
4
+ name: string;
5
+ provider: string;
6
+ alias: string;
7
+ display_name: string;
8
+ adjustableReasoning: boolean;
9
+ };
10
+
11
+ export const VIBE_MODEL_PRESETS: readonly VibeModelPreset[] = [
12
+ { name: 'mistral-vibe-cli-latest', provider: 'mistral', alias: 'mistral-medium-3.5', display_name: 'Mistral Medium 3.5', adjustableReasoning: true },
13
+ { name: 'zai-glm-5-3', provider: 'mistral', alias: 'glm-5.3', display_name: 'Z.ai GLM 5.3', adjustableReasoning: false },
14
+ { name: 'zai-glm-5-2', provider: 'mistral', alias: 'glm-5.2', display_name: 'Z.ai GLM 5.2', adjustableReasoning: false },
15
+ ];
16
+
17
+ export const VIBE_REASONING_EFFORT: NonNullable<ProviderModelOption['effort']> = {
18
+ default: 'high',
19
+ values: [
20
+ { value: 'none', description: 'Minimal thinking, no reasoning trace.' },
21
+ { value: 'high', description: 'Full reasoning before answering.' },
22
+ ],
23
+ };
24
+
25
+ const VIBE_THINKING_BY_EFFORT: Record<string, string> = { none: 'low', high: 'high' };
26
+
27
+ export function vibeModelOption(alias: string, label: string, description?: string): ProviderModelOption {
28
+ const preset = VIBE_MODEL_PRESETS.find((candidate) => candidate.alias === alias);
29
+ return {
30
+ value: alias,
31
+ label,
32
+ ...(description ? { description } : {}),
33
+ ...(preset?.adjustableReasoning ? { effort: VIBE_REASONING_EFFORT } : {}),
34
+ };
35
+ }
36
+
37
+ export function buildVibeModelsEnvironment(selectedAlias?: string, effort?: string): string {
38
+ const thinking = effort ? VIBE_THINKING_BY_EFFORT[effort] : undefined;
39
+ return JSON.stringify(Object.fromEntries(VIBE_MODEL_PRESETS.map(({ adjustableReasoning, ...model }) => [
40
+ model.alias,
41
+ adjustableReasoning && thinking && model.alias === selectedAlias ? { ...model, thinking } : model,
42
+ ])));
43
+ }
@@ -0,0 +1,27 @@
1
+ import assert from 'node:assert/strict';
2
+ import test from 'node:test';
3
+
4
+ import { MISTRAL_PREDEFINED_MODELS } from '@/modules/providers/list/mistral/mistral-models.provider.js';
5
+ import { buildVibeModelsEnvironment } from '@/modules/providers/list/mistral/mistral-vibe-models.js';
6
+
7
+ test('Vibe receives the GLM models alongside Mistral Medium without overriding thinking by default', () => {
8
+ const models = JSON.parse(buildVibeModelsEnvironment());
9
+ assert.deepEqual(Object.keys(models), ['mistral-medium-3.5', 'glm-5.3', 'glm-5.2']);
10
+ assert.deepEqual(models['glm-5.3'], { name: 'zai-glm-5-3', provider: 'mistral', alias: 'glm-5.3', display_name: 'Z.ai GLM 5.3' });
11
+ assert.equal(models['mistral-medium-3.5'].thinking, undefined);
12
+ });
13
+
14
+ test('the selected effort becomes Vibe thinking only on models with adjustable reasoning', () => {
15
+ assert.equal(JSON.parse(buildVibeModelsEnvironment('mistral-medium-3.5', 'none'))['mistral-medium-3.5'].thinking, 'low');
16
+ assert.equal(JSON.parse(buildVibeModelsEnvironment('mistral-medium-3.5', 'high'))['mistral-medium-3.5'].thinking, 'high');
17
+ assert.equal(JSON.parse(buildVibeModelsEnvironment('glm-5.3', 'high'))['glm-5.3'].thinking, undefined);
18
+ assert.equal(JSON.parse(buildVibeModelsEnvironment('mistral-medium-3.5', 'bogus'))['mistral-medium-3.5'].thinking, undefined);
19
+ });
20
+
21
+ test('the curated Mistral catalog lists GLM 5.3 and 5.2 and offers effort on Medium 3.5 only', () => {
22
+ const byValue = Object.fromEntries(MISTRAL_PREDEFINED_MODELS.OPTIONS.map((option) => [option.value, option]));
23
+ assert.deepEqual(Object.keys(byValue), ['mistral-medium-3.5', 'glm-5.3', 'glm-5.2', 'local']);
24
+ assert.deepEqual(byValue['mistral-medium-3.5'].effort?.values.map((value) => value.value), ['none', 'high']);
25
+ assert.equal(byValue['glm-5.3'].effort, undefined);
26
+ assert.equal(MISTRAL_PREDEFINED_MODELS.DEFAULT, 'mistral-medium-3.5');
27
+ });
@@ -1,119 +1,119 @@
1
1
  const fs = require('node:fs');
2
- const os = require('node:os');
3
2
  const path = require('node:path');
4
3
 
5
- function atomicWrite(file, content, mode = 0o600) {
6
- fs.mkdirSync(path.dirname(file), { recursive: true });
4
+ const LEGACY_PROXY_KEYS = [
5
+ 'HTTPS_PROXY', 'HTTP_PROXY', 'ALL_PROXY', 'NO_PROXY', 'NODE_USE_ENV_PROXY',
6
+ 'NODE_EXTRA_CA_CERTS', 'SSL_CERT_FILE', 'CODEX_CA_CERTIFICATE', 'REQUESTS_CA_BUNDLE',
7
+ ];
8
+
9
+ function readObject(file) {
10
+ try {
11
+ const parsed = JSON.parse(fs.readFileSync(file, 'utf8'));
12
+ return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : null;
13
+ } catch {
14
+ return null;
15
+ }
16
+ }
17
+
18
+ function writeObject(file, value) {
7
19
  const temporary = `${file}.piecemaker-${process.pid}-${Date.now()}`;
8
- fs.writeFileSync(temporary, content, { encoding: 'utf8', mode });
20
+ fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { encoding: 'utf8', mode: 0o600 });
9
21
  fs.renameSync(temporary, file);
10
22
  }
11
23
 
12
- const PROXY_ENV = {
13
- HTTPS_PROXY: (proxyUrl) => proxyUrl,
14
- HTTP_PROXY: (proxyUrl) => proxyUrl,
15
- ALL_PROXY: (proxyUrl) => proxyUrl,
16
- NO_PROXY: () => 'localhost,127.0.0.1,::1',
17
- NODE_USE_ENV_PROXY: () => '1',
18
- NODE_EXTRA_CA_CERTS: (_proxyUrl, caFile) => caFile,
19
- SSL_CERT_FILE: (_proxyUrl, caFile, trustBundle) => trustBundle || caFile,
20
- CODEX_CA_CERTIFICATE: (_proxyUrl, caFile) => caFile,
21
- REQUESTS_CA_BUNDLE: (_proxyUrl, caFile, trustBundle) => trustBundle || caFile,
22
- };
23
-
24
- function isLoopbackProxy(value) {
24
+ function isLoopback(value) {
25
25
  try {
26
- const url = new URL(String(value || ''));
27
- return ['127.0.0.1', 'localhost'].includes(url.hostname);
26
+ return ['127.0.0.1', 'localhost'].includes(new URL(String(value || '')).hostname);
28
27
  } catch {
29
28
  return false;
30
29
  }
31
30
  }
32
31
 
33
- function configureClaudeCodeProxy({ proxyUrl, caFile, trustBundle, userHome = os.homedir() } = {}) {
34
- const settingsFile = path.join(userHome, '.claude', 'settings.json');
35
- let settings = {};
36
- try {
37
- if (fs.existsSync(settingsFile)) {
38
- const parsed = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
39
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error('objet JSON attendu');
40
- settings = parsed;
41
- }
42
- } catch {
43
- return { configured: false, changed: false, conflict: true, file: settingsFile, reason: 'settings-invalid' };
44
- }
32
+ function isProxyGuard(hook) {
33
+ return [hook?.command, hook?.commandWindows].some((command) => typeof command === 'string' && command.includes('proxy-guard.mjs'));
34
+ }
45
35
 
46
- if (settings.env !== undefined
47
- && (!settings.env || typeof settings.env !== 'object' || Array.isArray(settings.env))) {
48
- return { configured: false, changed: false, conflict: true, file: settingsFile, reason: 'env-invalid' };
49
- }
50
- if (!settings.env) settings.env = {};
51
- const existingProxy = settings.env.HTTPS_PROXY;
52
- if (existingProxy && existingProxy !== proxyUrl && !isLoopbackProxy(existingProxy)) {
53
- return { configured: false, changed: false, conflict: true, file: settingsFile, reason: 'proxy-conflict' };
54
- }
36
+ function withoutProxyGuard(groups) {
37
+ if (!Array.isArray(groups)) return groups;
38
+ return groups
39
+ .map((group) => (Array.isArray(group?.hooks) ? { ...group, hooks: group.hooks.filter((hook) => !isProxyGuard(hook)) } : group))
40
+ .filter((group) => !Array.isArray(group?.hooks) || group.hooks.length);
41
+ }
55
42
 
43
+ function cleanClaudeSettings(file) {
44
+ const settings = readObject(file);
45
+ if (!settings) return false;
56
46
  let changed = false;
57
- for (const [key, produce] of Object.entries(PROXY_ENV)) {
58
- const value = produce(proxyUrl, caFile, trustBundle);
59
- if (!value) continue;
60
- if (settings.env[key] !== value) {
61
- settings.env[key] = value;
62
- changed = true;
63
- }
47
+ if (settings.env && isLoopback(settings.env.HTTPS_PROXY)) {
48
+ for (const key of LEGACY_PROXY_KEYS) delete settings.env[key];
49
+ if (!Object.keys(settings.env).length) delete settings.env;
50
+ changed = true;
64
51
  }
65
- if (!changed) return { configured: true, changed: false, conflict: false, file: settingsFile };
66
- atomicWrite(settingsFile, `${JSON.stringify(settings, null, 2)}\n`);
67
- return { configured: true, changed: true, conflict: false, file: settingsFile };
68
- }
69
-
70
- function bypassClaudeCodeProxy({ userHome = os.homedir() } = {}) {
71
- const settingsFile = path.join(userHome, '.claude', 'settings.json');
72
- if (!fs.existsSync(settingsFile)) {
73
- return { bypassed: true, changed: false, conflict: false, file: settingsFile };
52
+ const current = settings.hooks?.SessionStart;
53
+ const sessionStart = withoutProxyGuard(current);
54
+ if (Array.isArray(current) && JSON.stringify(sessionStart) !== JSON.stringify(current)) {
55
+ if (sessionStart.length) settings.hooks.SessionStart = sessionStart;
56
+ else delete settings.hooks.SessionStart;
57
+ changed = true;
74
58
  }
59
+ if (changed) writeObject(file, settings);
60
+ return changed;
61
+ }
75
62
 
76
- let settings;
77
- try {
78
- settings = JSON.parse(fs.readFileSync(settingsFile, 'utf8'));
79
- if (!settings || typeof settings !== 'object' || Array.isArray(settings)) throw new Error('objet JSON attendu');
80
- } catch {
81
- return { bypassed: false, changed: false, conflict: true, file: settingsFile, reason: 'settings-invalid' };
82
- }
63
+ function cleanCodexHooks(file) {
64
+ const document = readObject(file);
65
+ const current = document?.hooks?.SessionStart;
66
+ const sessionStart = withoutProxyGuard(current);
67
+ if (!Array.isArray(current) || JSON.stringify(sessionStart) === JSON.stringify(current)) return false;
68
+ if (sessionStart.length) document.hooks.SessionStart = sessionStart;
69
+ else delete document.hooks.SessionStart;
70
+ writeObject(file, document);
71
+ return true;
72
+ }
83
73
 
84
- const env = settings.env;
85
- if (!env || typeof env !== 'object' || Array.isArray(env)) {
86
- if (env === undefined) return { bypassed: true, changed: false, conflict: false, file: settingsFile };
87
- return { bypassed: false, changed: false, conflict: true, file: settingsFile, reason: 'env-invalid' };
88
- }
89
- if (!isLoopbackProxy(env.HTTPS_PROXY)) return { bypassed: true, changed: false, conflict: false, file: settingsFile };
74
+ const LEGACY_CONFIG_KEYS = [
75
+ 'mikePiiPort',
76
+ 'caseFolders',
77
+ 'anonymization',
78
+ 'litellmPort',
79
+ 'litellmVenvPath',
80
+ 'mxcPath',
81
+ 'mxcEnabled',
82
+ 'adminTheme',
83
+ 'port',
84
+ ];
90
85
 
86
+ function cleanPieceMakerConfig(homeDir) {
87
+ const file = path.join(homeDir, 'config.json');
88
+ const config = readObject(file);
91
89
  let changed = false;
92
- if (isLoopbackProxy(env.HTTPS_PROXY)) {
93
- for (const key of Object.keys(PROXY_ENV)) {
94
- if (env[key] !== undefined) {
95
- delete env[key];
96
- changed = true;
97
- }
98
- }
90
+ const legacyKeys = config ? LEGACY_CONFIG_KEYS.filter((key) => key in config) : [];
91
+ if (legacyKeys.length) {
92
+ for (const key of legacyKeys) delete config[key];
93
+ writeObject(file, config);
94
+ changed = true;
99
95
  }
100
- if (!changed) return { bypassed: true, changed: false, conflict: false, file: settingsFile };
101
- if (Object.keys(env).length === 0) delete settings.env;
102
- atomicWrite(settingsFile, `${JSON.stringify(settings, null, 2)}\n`);
103
- return { bypassed: true, changed: true, conflict: false, file: settingsFile };
104
- }
105
-
106
- function configureCodexProxy() {
107
- return { configured: true, changed: false, conflict: false, file: null };
96
+ const statuslineCache = path.join(homeDir, 'proxy-statusline.json');
97
+ if (fs.existsSync(statuslineCache)) {
98
+ fs.rmSync(statuslineCache, { force: true });
99
+ changed = true;
100
+ }
101
+ return changed;
108
102
  }
109
103
 
110
- function bypassCodexProxy() {
111
- return { bypassed: true, changed: false, conflict: false, file: null };
104
+ function removeLegacyProxyConfig({ userHome, homeDir = path.join(userHome, '.piecemaker') }) {
105
+ const cleaned = [];
106
+ const attempt = (name, run) => {
107
+ try {
108
+ if (run()) cleaned.push(name);
109
+ } catch {
110
+ return;
111
+ }
112
+ };
113
+ attempt('claude', () => cleanClaudeSettings(path.join(userHome, '.claude', 'settings.json')));
114
+ attempt('codex', () => cleanCodexHooks(path.join(process.env.CODEX_HOME || path.join(userHome, '.codex'), 'hooks.json')));
115
+ attempt('piecemaker', () => cleanPieceMakerConfig(homeDir));
116
+ return cleaned;
112
117
  }
113
118
 
114
- module.exports = {
115
- configureClaudeCodeProxy,
116
- bypassClaudeCodeProxy,
117
- configureCodexProxy,
118
- bypassCodexProxy,
119
- };
119
+ module.exports = { removeLegacyProxyConfig };
@@ -1,6 +1,5 @@
1
1
  const { execFileSync, spawn } = require('node:child_process');
2
2
  const fs = require('node:fs');
3
- const net = require('node:net');
4
3
  const os = require('node:os');
5
4
  const path = require('node:path');
6
5
 
@@ -25,17 +24,6 @@ function makeCertificateAuthority(directory) {
25
24
  return { cert, key };
26
25
  }
27
26
 
28
- function freePort() {
29
- return new Promise((resolve, reject) => {
30
- const server = net.createServer();
31
- server.once('error', reject);
32
- server.listen(0, '127.0.0.1', () => {
33
- const { port } = server.address();
34
- server.close((error) => (error ? reject(error) : resolve(port)));
35
- });
36
- });
37
- }
38
-
39
27
  function waitForOutput(child, needle, timeoutMs) {
40
28
  return new Promise((resolve, reject) => {
41
29
  let buffer = '';
@@ -71,21 +59,23 @@ async function startHudsuckerSession({
71
59
  const ca = makeCertificateAuthority(directory);
72
60
  const dictionary = createSqliteDictionaryLoader({ databasePath });
73
61
  const bridge = await startRewriterBridge({ dictionary, harness });
74
- const port = await freePort();
75
62
  const upstreamMap = hosts.map((host) => `${host}=127.0.0.1:${upstreamPort}`).join(',');
76
63
  const child = spawn(binary, [
77
- '--listen', `127.0.0.1:${port}`,
64
+ '--listen', '127.0.0.1:0',
78
65
  '--rewriter', `http://127.0.0.1:${bridge.port}`,
79
66
  '--ca-cert', ca.cert,
80
67
  '--ca-key', ca.key,
81
68
  '--hosts', hosts.join(','),
82
69
  '--upstream-map', upstreamMap,
83
70
  ], {
84
- stdio: ['ignore', 'pipe', 'pipe'],
71
+ stdio: ['pipe', 'pipe', 'pipe'],
85
72
  env: { ...process.env, HTTPS_PROXY: '', HTTP_PROXY: '', ALL_PROXY: '', http_proxy: '', https_proxy: '' },
86
73
  });
74
+ let logs = '';
75
+ child.stderr.on('data', (chunk) => { logs += chunk; });
76
+ let port;
87
77
  try {
88
- await waitForOutput(child, `listening 127.0.0.1:${port}`, 15000);
78
+ port = (await waitForOutput(child, 'listening 127.0.0.1:', 15000)).match(/listening 127\.0\.0\.1:(\d+)/)[1];
89
79
  } catch (error) {
90
80
  child.kill('SIGKILL');
91
81
  await bridge.close();
@@ -96,6 +86,9 @@ async function startHudsuckerSession({
96
86
  origin: `http://127.0.0.1:${port}`,
97
87
  caFile: ca.cert,
98
88
  stats: bridge.stats,
89
+ child,
90
+ bridge,
91
+ logs: () => logs,
99
92
  async close() {
100
93
  child.kill('SIGTERM');
101
94
  await new Promise((resolve) => child.once('exit', resolve));
@@ -10,5 +10,5 @@ http-body-util = "0.1"
10
10
  hudsucker = { version = "0.25", default-features = false, features = ["decoder", "http2", "rcgen-ca", "rustls-client"] }
11
11
  reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "stream"] }
12
12
  serde_json = "1"
13
- tokio = { version = "1", features = ["macros", "rt-multi-thread", "sync"] }
13
+ tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "sync"] }
14
14
  tokio-stream = "0.1"