@piecemaker-legal/piecemaker 1.1.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{abnfDiagram-VCTEODGH-DEXWh3LH.js → abnfDiagram-VCTEODGH-BeQS_HnO.js} +1 -1
- package/dist/assets/{arc-CoTRLXKW.js → arc-ClYjD3aM.js} +1 -1
- package/dist/assets/{architectureDiagram-5GKGNRK7-Cg-jO9oR.js → architectureDiagram-5GKGNRK7-Csdihb1L.js} +1 -1
- package/dist/assets/{blockDiagram-I7D4REHJ-ChXwQSIq.js → blockDiagram-I7D4REHJ-BuXey9ht.js} +1 -1
- package/dist/assets/{c4Diagram-7LVT6UL2-Bw2VGggd.js → c4Diagram-7LVT6UL2-DdO-ovOy.js} +1 -1
- package/dist/assets/channel-DhuuSCHK.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-C1WdqrLP.js → chunk-2Q5K7J3B-D3hzWzSc.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-BerUZBa1.js → chunk-5VM5RSS4-DeT3cR6k.js} +1 -1
- package/dist/assets/{chunk-F27PBJKO-5W7ax2gB.js → chunk-F27PBJKO-bazGi1ru.js} +1 -1
- package/dist/assets/{chunk-IMKFNOWR-JgDN1h4T.js → chunk-IMKFNOWR-BE3ZXrPd.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-ulNHnEdQ.js → chunk-JWPE2WC7-dTAsgByE.js} +1 -1
- package/dist/assets/{chunk-POPQ4Y6H-D4aTDC2T.js → chunk-POPQ4Y6H-DKYrzMSd.js} +1 -1
- package/dist/assets/{chunk-SVP7TREG-BA5zX4XF.js → chunk-SVP7TREG-BTtrMvhE.js} +1 -1
- package/dist/assets/{chunk-TICWLB2K-DhOULVhX.js → chunk-TICWLB2K-CZPHShPS.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-CkpCgrVg.js → chunk-XXDRQBXY-B0byFHaU.js} +1 -1
- package/dist/assets/classDiagram-ZZMXUADV-CO0E82Dl.js +1 -0
- package/dist/assets/classDiagram-v2-VYDZK3BY-CO0E82Dl.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-0xUSfjfV.js → cose-bilkent-JH36ORCC-BbLCzlaU.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-BE6fNu2_.js → cynefin-OW5HDTMX-CQ8ui4YD.js} +1 -1
- package/dist/assets/{cynefinDiagram-5FMLGOSQ-rFMnZ9b3.js → cynefinDiagram-5FMLGOSQ-T-GL1aIf.js} +1 -1
- package/dist/assets/{dagre-GXQ25YYZ-C1p4ffd7.js → dagre-GXQ25YYZ-CXxVKznH.js} +1 -1
- package/dist/assets/{diagram-S7CK7UJ4-BV_3Xj4O.js → diagram-S7CK7UJ4-B_-1Mf_7.js} +1 -1
- package/dist/assets/{diagram-UQ7AKVKN-Bb_Evkrm.js → diagram-UQ7AKVKN-Bs-OB8xI.js} +1 -1
- package/dist/assets/{diagram-VSXAHHWV-BzgupjxD.js → diagram-VSXAHHWV-BpUqq93o.js} +1 -1
- package/dist/assets/{diagram-VX7I27RA-D1c67z76.js → diagram-VX7I27RA-CZ6hSUo6.js} +1 -1
- package/dist/assets/{diagram-Z3DM3KII-DsJAJGKE.js → diagram-Z3DM3KII-DVZiDO6S.js} +1 -1
- package/dist/assets/{ebnfDiagram-PWID7BFC-B1ge_obq.js → ebnfDiagram-PWID7BFC-D_1izoKK.js} +1 -1
- package/dist/assets/{erDiagram-RLTQ6QDP-DrV-tggw.js → erDiagram-RLTQ6QDP-_jSi4sg-.js} +1 -1
- package/dist/assets/{flowDiagram-HODETNUW-CVzDiSQ3.js → flowDiagram-HODETNUW-BtBM7ez3.js} +1 -1
- package/dist/assets/{ganttDiagram-EL5Y4UJY-CGRdSN9D.js → ganttDiagram-EL5Y4UJY-Bz2nxw7c.js} +1 -1
- package/dist/assets/{gitGraphDiagram-WWUBYQGX-CAfvFXzL.js → gitGraphDiagram-WWUBYQGX-8Q3I3hoE.js} +1 -1
- package/dist/assets/{index-DaxH81ZJ.js → index-CZUj0Tlu.js} +152 -152
- package/dist/assets/index-DcfdIMj-.css +1 -0
- package/dist/assets/{infoDiagram-27XIBGKW-DTshEkGK.js → infoDiagram-27XIBGKW-Cc6eKjfU.js} +1 -1
- package/dist/assets/{ishikawaDiagram-5VMMS53U-DkbshVxp.js → ishikawaDiagram-5VMMS53U-Bd3w97qM.js} +1 -1
- package/dist/assets/{journeyDiagram-3NMN7TZE-v5qE8xpn.js → journeyDiagram-3NMN7TZE-Cy6XbK5X.js} +1 -1
- package/dist/assets/{kanban-definition-UXKFOSKX-a9CNMFLt.js → kanban-definition-UXKFOSKX-kyLqWDpr.js} +1 -1
- package/dist/assets/{layout-DrW4R1TH.js → layout-DXpPSEft.js} +1 -1
- package/dist/assets/{linear-Cs3qpXT_.js → linear-DH_h9cDZ.js} +1 -1
- package/dist/assets/{mermaid.core-C7Ti-Fty.js → mermaid.core-BghXiB7p.js} +6 -6
- package/dist/assets/{mindmap-definition-YA3MSWOX-B0VDdIcG.js → mindmap-definition-YA3MSWOX-C2xxEXsP.js} +1 -1
- package/dist/assets/{pegDiagram-XKGWAZYB-CV1L7MjP.js → pegDiagram-XKGWAZYB-DuppHX4-.js} +1 -1
- package/dist/assets/{pieDiagram-E7YTZNPT-DSCuzVTV.js → pieDiagram-E7YTZNPT-BCukPZ2a.js} +1 -1
- package/dist/assets/{quadrantDiagram-AXDQQJYC-hzX-9AKo.js → quadrantDiagram-AXDQQJYC-Dm_ojY_7.js} +1 -1
- package/dist/assets/{railroadDiagram-O6MQD6OU-BbmzIqcp.js → railroadDiagram-O6MQD6OU-BzdOv7BJ.js} +1 -1
- package/dist/assets/{requirementDiagram-BXWQKSXE-CQCRRBSL.js → requirementDiagram-BXWQKSXE-DgewPP_g.js} +1 -1
- package/dist/assets/{sankeyDiagram-P5KCCOFB-kiaLcW6X.js → sankeyDiagram-P5KCCOFB-vEIMvCSt.js} +1 -1
- package/dist/assets/{sequenceDiagram-WJ2MYXX4-Bgx8ST7Q.js → sequenceDiagram-WJ2MYXX4-BL_31NoY.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-BTjJ-ygN.js → sizeCapture-INFHLROL-Ch6u4xo6.js} +1 -1
- package/dist/assets/{stateDiagram-D77RDMKH-D48RR1FL.js → stateDiagram-D77RDMKH-ByquMuJv.js} +1 -1
- package/dist/assets/{stateDiagram-v2-MP3YSRHH-B-XwSR-z.js → stateDiagram-v2-MP3YSRHH-_QRJP_vn.js} +1 -1
- package/dist/assets/{swimlanes-42K2YHIH-BhE-QuEZ.js → swimlanes-42K2YHIH-BZyXEHOb.js} +1 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-sqZwZwbP.js +8 -0
- package/dist/assets/{timeline-definition-24CTP7MA-Cm7EUWWt.js → timeline-definition-24CTP7MA-CLBivayK.js} +1 -1
- package/dist/assets/{vennDiagram-4TSXK5OY-X-nC9wZ0.js → vennDiagram-4TSXK5OY-3dJ2PRqR.js} +1 -1
- package/dist/assets/{wardleyDiagram-VM6X3IG4-D33YvEQZ.js → wardleyDiagram-VM6X3IG4-C279LT36.js} +1 -1
- package/dist/assets/{xychartDiagram-S5SC5T6Z-lziwBKsM.js → xychartDiagram-S5SC5T6Z-FoqPDrei.js} +1 -1
- package/dist/index.html +2 -2
- package/dist/sw.js +1 -1
- package/dist-server/server/index.js +3 -1
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/piecemaker/harness/citations.routes.js +18 -1
- package/dist-server/server/piecemaker/harness/citations.routes.js.map +1 -1
- package/dist-server/server/piecemaker/harness/legifrance-html.js +112 -0
- package/dist-server/server/piecemaker/harness/legifrance-html.js.map +1 -0
- package/dist-server/server/piecemaker/index.js +7 -3
- package/dist-server/server/piecemaker/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/index.js +13 -6
- package/dist-server/server/piecemaker/knowledge/index.js.map +1 -1
- package/dist-server/server/piecemaker/knowledge/local-routes.js +55 -0
- package/dist-server/server/piecemaker/knowledge/local-routes.js.map +1 -0
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js +3 -1
- package/dist-server/server/piecemaker/knowledge/scan-jobs.js.map +1 -1
- package/dist-server/server/piecemaker/library/index.js +14 -41
- package/dist-server/server/piecemaker/library/index.js.map +1 -1
- package/dist-server/server/piecemaker/library/store.js +11 -3
- package/dist-server/server/piecemaker/library/store.js.map +1 -1
- package/dist-server/server/piecemaker/library/workspace-installation.js +26 -3
- package/dist-server/server/piecemaker/library/workspace-installation.js.map +1 -1
- package/dist-server/server/piecemaker/timesheet/service.js +8 -7
- package/dist-server/server/piecemaker/timesheet/service.js.map +1 -1
- package/dist-server/server/piecemaker/timesheet/store.js +5 -3
- package/dist-server/server/piecemaker/timesheet/store.js.map +1 -1
- package/package.json +1 -1
- package/product.config.json +2 -0
- package/scripts/piecemaker/build-app-icon.py +88 -0
- package/scripts/piecemaker/cli/lib/piecemaker-anonymizer.mjs +2 -2
- package/scripts/piecemaker/hooks/proxy-guard.mjs +19 -54
- package/scripts/release/assert-piecemaker-version.mjs +25 -0
- package/server/index.ts +4 -1
- package/server/piecemaker/anonymizer/client-config.cjs +45 -162
- package/server/piecemaker/anonymizer/hudsucker-fixture.cjs +127 -0
- package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.lock +2396 -0
- package/server/piecemaker/anonymizer/hudsucker-proxy/Cargo.toml +14 -0
- package/server/piecemaker/anonymizer/hudsucker-proxy/src/main.rs +501 -0
- package/server/piecemaker/anonymizer/providers.cjs +14 -135
- package/server/piecemaker/anonymizer/rewriter-bridge.cjs +221 -0
- package/server/piecemaker/anonymizer/service.cjs +144 -28
- package/server/piecemaker/harness/citations.routes.ts +23 -1
- package/server/piecemaker/harness/legifrance-html.ts +107 -0
- package/server/piecemaker/index.ts +8 -3
- package/server/piecemaker/knowledge/index.ts +14 -6
- package/server/piecemaker/knowledge/local-routes.ts +72 -0
- package/server/piecemaker/knowledge/scan-jobs.ts +4 -1
- package/server/piecemaker/library/index.ts +14 -34
- package/server/piecemaker/library/store.ts +11 -3
- package/server/piecemaker/library/workspace-installation.ts +20 -3
- package/server/piecemaker/timesheet/service.ts +9 -7
- package/server/piecemaker/timesheet/store.ts +5 -3
- package/server/piecemaker/vendor/installer/assets/claude-hooks/piecemaker-guard-secrets.mjs +0 -1
- 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 +56 -206
- package/server/piecemaker/vendor/installer/lib/commandes.mjs +2 -4
- package/server/piecemaker/vendor/installer/lib/conversion-client.mjs +74 -0
- package/server/piecemaker/vendor/installer/lib/service.mjs +4 -358
- package/server/piecemaker/vendor/installer/lib/state.mjs +0 -6
- package/server/piecemaker/vendor/installer/steps/03-python-gliner.mjs +4 -4
- package/server/piecemaker/vendor/installer/steps/09-claude-assets.mjs +0 -31
- package/server/piecemaker/vendor/piecemaker-plugin/scripts/statusline.mjs +3 -4
- package/server/piecemaker/vendor/websocket-server/admin-routes.cjs +1 -49
- package/server/piecemaker/vendor/websocket-server/claude-hooks.cjs +14 -12
- package/server/piecemaker/vendor/websocket-server/originals-pipeline.cjs +17 -476
- package/server/piecemaker/vendor/websocket-server/scripts/convert_and_scan_pipeline.py +2 -2
- package/server/piecemaker/vendor/websocket-server/scripts/mineru_improved_1.py +11 -2
- package/server/piecemaker/vendor/websocket-server/scripts/presidio-gliner/scanner_worker.py +13 -37
- package/server/piecemaker/vendor/websocket-server/scripts/requirements.txt +1 -7
- package/server/piecemaker/vendor/websocket-server/scripts/warmup.py +14 -85
- package/dist/assets/channel-DdzrPZ6Y.js +0 -1
- package/dist/assets/classDiagram-ZZMXUADV-Dim2o8E5.js +0 -1
- package/dist/assets/classDiagram-v2-VYDZK3BY-Dim2o8E5.js +0 -1
- package/dist/assets/index-D_Dc_nQv.css +0 -1
- package/dist/assets/swimlanesDiagram-VR7AAH4N-DR525d5V.js +0 -8
- package/server/piecemaker/anonymizer/proxy.cjs +0 -365
- package/server/piecemaker/vendor/installer/assets/PieceMakerApp.swift +0 -189
- package/server/piecemaker/vendor/installer/lib/desktop-launcher.mjs +0 -305
- package/server/piecemaker/vendor/installer/steps/05-certificats.mjs +0 -171
- package/server/piecemaker/vendor/installer/steps/14-mxc-sandbox.mjs +0 -271
- package/server/piecemaker/vendor/installer/steps/15-pwa-desktop.mjs +0 -64
- package/server/piecemaker/vendor/installer/templates/root-CLAUDE.md +0 -56
- package/server/piecemaker/vendor/installer/templates/workspace-CLAUDE.md +0 -52
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Raccourci Bureau et gestionnaire du protocole local `piecemaker:`.
|
|
3
|
-
*
|
|
4
|
-
* Le raccourci lance `piecemaker open` : le serveur est donc démarré avant
|
|
5
|
-
* l'ouverture de l'administration. Le gestionnaire de protocole, lui, lance
|
|
6
|
-
* seulement `piecemaker start`; la page PWA hors ligne peut ainsi redémarrer
|
|
7
|
-
* le serveur sans ouvrir une seconde fenêtre.
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import fs from 'node:fs';
|
|
11
|
-
import os from 'node:os';
|
|
12
|
-
import path from 'node:path';
|
|
13
|
-
|
|
14
|
-
import { HOME_DIR, REPO_ROOT, runCapture } from './platform.mjs';
|
|
15
|
-
|
|
16
|
-
const MAC_REGISTER = '/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister';
|
|
17
|
-
const DEFAULT_ICNS = path.join(REPO_ROOT, 'installer', 'assets', 'piecemaker.icns');
|
|
18
|
-
const DEFAULT_ICO = path.join(REPO_ROOT, 'installer', 'assets', 'piecemaker.ico');
|
|
19
|
-
const DEFAULT_PNG = path.join(REPO_ROOT, 'admin', 'icons', 'icon-512.png');
|
|
20
|
-
const SWIFT_SOURCE = path.join(REPO_ROOT, 'installer', 'assets', 'PieceMakerApp.swift');
|
|
21
|
-
|
|
22
|
-
function shellQuote(value) {
|
|
23
|
-
return `'${String(value).replaceAll("'", `'"'"'`)}'`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function powershellQuote(value) {
|
|
27
|
-
return `'${String(value).replaceAll("'", "''")}'`;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function desktopEntryQuote(value) {
|
|
31
|
-
return `"${String(value).replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('$', '\\$').replaceAll('`', '\\`')}"`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function commandSucceeded(result) {
|
|
35
|
-
return !result?.error && result?.code === 0;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function writeFile(file, content, mode = 0o644) {
|
|
39
|
-
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
40
|
-
fs.writeFileSync(file, content, { encoding: 'utf8', mode });
|
|
41
|
-
fs.chmodSync(file, mode);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function desktopDirectoryForLinux(homeDir) {
|
|
45
|
-
const config = path.join(homeDir, '.config', 'user-dirs.dirs');
|
|
46
|
-
try {
|
|
47
|
-
const match = fs.readFileSync(config, 'utf8').match(/^XDG_DESKTOP_DIR="([^"]+)"/m);
|
|
48
|
-
if (match) return match[1].replace('$HOME', homeDir);
|
|
49
|
-
} catch {}
|
|
50
|
-
return path.join(homeDir, 'Desktop');
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function resolveDesktopDirectory({ platform, homeDir, desktopDir, commandRunner }) {
|
|
54
|
-
if (desktopDir) return desktopDir;
|
|
55
|
-
if (platform === 'win32') {
|
|
56
|
-
const result = commandRunner('powershell.exe', [
|
|
57
|
-
'-NoProfile',
|
|
58
|
-
'-NonInteractive',
|
|
59
|
-
'-Command',
|
|
60
|
-
'[Environment]::GetFolderPath("Desktop")',
|
|
61
|
-
]);
|
|
62
|
-
if (commandSucceeded(result) && result.stdout) return result.stdout.trim();
|
|
63
|
-
}
|
|
64
|
-
if (platform === 'linux') return desktopDirectoryForLinux(homeDir);
|
|
65
|
-
return path.join(homeDir, 'Desktop');
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function desktopLauncherPaths({
|
|
69
|
-
platform = process.platform,
|
|
70
|
-
homeDir = os.homedir(),
|
|
71
|
-
runtimeDir = HOME_DIR,
|
|
72
|
-
desktopDir,
|
|
73
|
-
commandRunner = runCapture,
|
|
74
|
-
} = {}) {
|
|
75
|
-
const desktop = resolveDesktopDirectory({ platform, homeDir, desktopDir, commandRunner });
|
|
76
|
-
if (platform === 'darwin') {
|
|
77
|
-
return {
|
|
78
|
-
shortcut: path.join(desktop, 'PieceMaker.app'),
|
|
79
|
-
protocol: path.join(runtimeDir, 'launcher', 'PieceMaker Protocol.app'),
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
if (platform === 'win32') {
|
|
83
|
-
return {
|
|
84
|
-
shortcut: path.join(desktop, 'PieceMaker.lnk'),
|
|
85
|
-
protocol: 'HKCU\\Software\\Classes\\piecemaker',
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
shortcut: path.join(desktop, 'PieceMaker.desktop'),
|
|
90
|
-
protocol: path.join(homeDir, '.local', 'share', 'applications', 'piecemaker-protocol.desktop'),
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function macPlist({ executable, identifier, protocol = false, nativeApp = false }) {
|
|
95
|
-
const protocolBlock = protocol ? `
|
|
96
|
-
<key>CFBundleURLTypes</key>
|
|
97
|
-
<array>
|
|
98
|
-
<dict>
|
|
99
|
-
<key>CFBundleURLName</key><string>PieceMaker</string>
|
|
100
|
-
<key>CFBundleURLSchemes</key><array><string>piecemaker</string></array>
|
|
101
|
-
</dict>
|
|
102
|
-
</array>` : '';
|
|
103
|
-
const uiElement = nativeApp ? '' : '\n <key>LSUIElement</key><true/>';
|
|
104
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
105
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
106
|
-
<plist version="1.0">
|
|
107
|
-
<dict>
|
|
108
|
-
<key>CFBundleDisplayName</key><string>PieceMaker</string>
|
|
109
|
-
<key>CFBundleExecutable</key><string>${executable}</string>
|
|
110
|
-
<key>CFBundleIconFile</key><string>piecemaker.icns</string>
|
|
111
|
-
<key>CFBundleIdentifier</key><string>${identifier}</string>
|
|
112
|
-
<key>CFBundleInfoDictionaryVersion</key><string>6.0</string>
|
|
113
|
-
<key>CFBundlePackageType</key><string>APPL</string>
|
|
114
|
-
<key>CFBundleShortVersionString</key><string>1.0</string>
|
|
115
|
-
<key>CFBundleVersion</key><string>1</string>${uiElement}${protocolBlock}
|
|
116
|
-
</dict>
|
|
117
|
-
</plist>
|
|
118
|
-
`;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function createMacShellApplication(target, {
|
|
122
|
-
verb,
|
|
123
|
-
identifier,
|
|
124
|
-
protocol = false,
|
|
125
|
-
nodePath,
|
|
126
|
-
cliPath,
|
|
127
|
-
runtimeDir,
|
|
128
|
-
iconPath,
|
|
129
|
-
}) {
|
|
130
|
-
const executable = 'PieceMaker';
|
|
131
|
-
const contents = path.join(target, 'Contents');
|
|
132
|
-
const executablePath = path.join(contents, 'MacOS', executable);
|
|
133
|
-
const logPath = path.join(runtimeDir, 'desktop-launcher.log');
|
|
134
|
-
const script = `#!/bin/sh\n${shellQuote(nodePath)} ${shellQuote(cliPath)} ${verb} >>${shellQuote(logPath)} 2>&1 &\nexit 0\n`;
|
|
135
|
-
writeFile(executablePath, script, 0o755);
|
|
136
|
-
writeFile(path.join(contents, 'Info.plist'), macPlist({ executable, identifier, protocol }));
|
|
137
|
-
fs.mkdirSync(path.join(contents, 'Resources'), { recursive: true });
|
|
138
|
-
fs.copyFileSync(iconPath, path.join(contents, 'Resources', 'piecemaker.icns'));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
function createMacNativeApplication(target, { identifier, nodePath, cliPath, iconPath, commandRunner }) {
|
|
142
|
-
const executable = 'PieceMaker';
|
|
143
|
-
const contents = path.join(target, 'Contents');
|
|
144
|
-
const executablePath = path.join(contents, 'MacOS', executable);
|
|
145
|
-
fs.mkdirSync(path.dirname(executablePath), { recursive: true });
|
|
146
|
-
const compile = commandRunner('swiftc', [
|
|
147
|
-
'-o', executablePath,
|
|
148
|
-
'-framework', 'Cocoa',
|
|
149
|
-
'-framework', 'WebKit',
|
|
150
|
-
'-suppress-warnings',
|
|
151
|
-
SWIFT_SOURCE,
|
|
152
|
-
]);
|
|
153
|
-
if (!commandSucceeded(compile)) {
|
|
154
|
-
throw new Error(`Compilation Swift impossible : ${compile.stderr || compile.error?.message || `code ${compile.code}`}`);
|
|
155
|
-
}
|
|
156
|
-
fs.chmodSync(executablePath, 0o755);
|
|
157
|
-
const plist = macPlist({ executable, identifier, nativeApp: true });
|
|
158
|
-
writeFile(path.join(contents, 'Info.plist'), plist);
|
|
159
|
-
fs.mkdirSync(path.join(contents, 'Resources'), { recursive: true });
|
|
160
|
-
fs.copyFileSync(iconPath, path.join(contents, 'Resources', 'piecemaker.icns'));
|
|
161
|
-
const envPlist = `<?xml version="1.0" encoding="UTF-8"?>
|
|
162
|
-
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
163
|
-
<plist version="1.0">
|
|
164
|
-
<dict>
|
|
165
|
-
<key>PIECEMAKER_NODE</key><string>${nodePath}</string>
|
|
166
|
-
<key>PIECEMAKER_CLI</key><string>${cliPath}</string>
|
|
167
|
-
</dict>
|
|
168
|
-
</plist>
|
|
169
|
-
`;
|
|
170
|
-
writeFile(path.join(contents, 'Resources', 'environment.plist'), envPlist);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
function installMac({ paths, nodePath, cliPath, runtimeDir, iconPath, commandRunner }) {
|
|
174
|
-
const swiftAvailable = commandSucceeded(commandRunner('which', ['swiftc']));
|
|
175
|
-
if (swiftAvailable) {
|
|
176
|
-
createMacNativeApplication(paths.shortcut, {
|
|
177
|
-
identifier: 'com.piecemaker.desktop',
|
|
178
|
-
nodePath,
|
|
179
|
-
cliPath,
|
|
180
|
-
iconPath,
|
|
181
|
-
commandRunner,
|
|
182
|
-
});
|
|
183
|
-
} else {
|
|
184
|
-
createMacShellApplication(paths.shortcut, {
|
|
185
|
-
verb: 'open',
|
|
186
|
-
identifier: 'com.piecemaker.desktop',
|
|
187
|
-
nodePath,
|
|
188
|
-
cliPath,
|
|
189
|
-
runtimeDir,
|
|
190
|
-
iconPath,
|
|
191
|
-
});
|
|
192
|
-
}
|
|
193
|
-
createMacShellApplication(paths.protocol, {
|
|
194
|
-
verb: 'start',
|
|
195
|
-
identifier: 'com.piecemaker.protocol',
|
|
196
|
-
protocol: true,
|
|
197
|
-
nodePath,
|
|
198
|
-
cliPath,
|
|
199
|
-
runtimeDir,
|
|
200
|
-
iconPath,
|
|
201
|
-
});
|
|
202
|
-
const registration = commandRunner(MAC_REGISTER, ['-f', paths.protocol]);
|
|
203
|
-
return {
|
|
204
|
-
native: swiftAvailable,
|
|
205
|
-
protocolReady: commandSucceeded(registration),
|
|
206
|
-
protocolError: registration.stderr || registration.error?.message || '',
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
function installWindows({ paths, nodePath, cliPath, repoRoot, iconPath, commandRunner }) {
|
|
211
|
-
fs.mkdirSync(path.dirname(paths.shortcut), { recursive: true });
|
|
212
|
-
const script = [
|
|
213
|
-
'$shell = New-Object -ComObject WScript.Shell',
|
|
214
|
-
`$shortcut = $shell.CreateShortcut(${powershellQuote(paths.shortcut)})`,
|
|
215
|
-
`$shortcut.TargetPath = ${powershellQuote(nodePath)}`,
|
|
216
|
-
`$shortcut.Arguments = ${powershellQuote(`"${cliPath}" open`)}`,
|
|
217
|
-
`$shortcut.WorkingDirectory = ${powershellQuote(repoRoot)}`,
|
|
218
|
-
`$shortcut.IconLocation = ${powershellQuote(`${iconPath},0`)}`,
|
|
219
|
-
"$shortcut.Description = 'Démarrer et ouvrir PieceMaker'",
|
|
220
|
-
'$shortcut.Save()',
|
|
221
|
-
].join('; ');
|
|
222
|
-
const shortcut = commandRunner('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', script]);
|
|
223
|
-
if (!commandSucceeded(shortcut)) {
|
|
224
|
-
throw new Error(shortcut.stderr || shortcut.error?.message || 'Création du raccourci Windows impossible.');
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
const key = 'HKCU\\Software\\Classes\\piecemaker';
|
|
228
|
-
const protocolCommand = `"${nodePath}" "${cliPath}" start`;
|
|
229
|
-
const commands = [
|
|
230
|
-
[key, '/ve', '/d', 'URL:PieceMaker'],
|
|
231
|
-
[key, '/v', 'URL Protocol', '/d', ''],
|
|
232
|
-
[`${key}\\DefaultIcon`, '/ve', '/d', `"${iconPath}",0`],
|
|
233
|
-
[`${key}\\shell\\open\\command`, '/ve', '/d', protocolCommand],
|
|
234
|
-
];
|
|
235
|
-
const results = commands.map((args) => commandRunner('reg.exe', ['add', ...args, '/f']));
|
|
236
|
-
const failure = results.find((result) => !commandSucceeded(result));
|
|
237
|
-
return { protocolReady: !failure, protocolError: failure?.stderr || failure?.error?.message || '' };
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
function linuxDesktopEntry({ name, comment, nodePath, cliPath, verb, iconPath, protocol = false }) {
|
|
241
|
-
return `[Desktop Entry]
|
|
242
|
-
Type=Application
|
|
243
|
-
Name=${name}
|
|
244
|
-
Comment=${comment}
|
|
245
|
-
Exec=${desktopEntryQuote(nodePath)} ${desktopEntryQuote(cliPath)} ${verb}
|
|
246
|
-
Icon=${iconPath}
|
|
247
|
-
Terminal=false
|
|
248
|
-
Categories=Office;Utility;
|
|
249
|
-
${protocol ? 'NoDisplay=true\nMimeType=x-scheme-handler/piecemaker;\n' : ''}`;
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
function installLinux({ paths, nodePath, cliPath, iconPath, commandRunner }) {
|
|
253
|
-
writeFile(paths.shortcut, linuxDesktopEntry({
|
|
254
|
-
name: 'PieceMaker',
|
|
255
|
-
comment: 'Démarrer et ouvrir PieceMaker',
|
|
256
|
-
nodePath,
|
|
257
|
-
cliPath,
|
|
258
|
-
verb: 'open',
|
|
259
|
-
iconPath,
|
|
260
|
-
}), 0o755);
|
|
261
|
-
writeFile(paths.protocol, linuxDesktopEntry({
|
|
262
|
-
name: 'PieceMaker Protocol',
|
|
263
|
-
comment: 'Démarrer le serveur local PieceMaker',
|
|
264
|
-
nodePath,
|
|
265
|
-
cliPath,
|
|
266
|
-
verb: 'start',
|
|
267
|
-
iconPath,
|
|
268
|
-
protocol: true,
|
|
269
|
-
}), 0o755);
|
|
270
|
-
const registration = commandRunner('xdg-mime', ['default', path.basename(paths.protocol), 'x-scheme-handler/piecemaker']);
|
|
271
|
-
return { protocolReady: commandSucceeded(registration), protocolError: registration.stderr || registration.error?.message || '' };
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
export function installDesktopLauncher({
|
|
275
|
-
platform = process.platform,
|
|
276
|
-
homeDir = os.homedir(),
|
|
277
|
-
runtimeDir = HOME_DIR,
|
|
278
|
-
repoRoot = REPO_ROOT,
|
|
279
|
-
desktopDir,
|
|
280
|
-
nodePath = process.execPath,
|
|
281
|
-
commandRunner = runCapture,
|
|
282
|
-
iconPath,
|
|
283
|
-
} = {}) {
|
|
284
|
-
const paths = desktopLauncherPaths({ platform, homeDir, runtimeDir, desktopDir, commandRunner });
|
|
285
|
-
const cliPath = path.join(repoRoot, 'installer', 'bin', 'piecemaker.mjs');
|
|
286
|
-
let result;
|
|
287
|
-
if (platform === 'darwin') {
|
|
288
|
-
result = installMac({ paths, nodePath, cliPath, runtimeDir, iconPath: iconPath || DEFAULT_ICNS, commandRunner });
|
|
289
|
-
} else if (platform === 'win32') {
|
|
290
|
-
result = installWindows({ paths, nodePath, cliPath, repoRoot, iconPath: iconPath || DEFAULT_ICO, commandRunner });
|
|
291
|
-
} else {
|
|
292
|
-
result = installLinux({ paths, nodePath, cliPath, iconPath: iconPath || DEFAULT_PNG, commandRunner });
|
|
293
|
-
}
|
|
294
|
-
return { ...paths, ...result };
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
export function desktopLauncherStatus(options = {}) {
|
|
298
|
-
const paths = desktopLauncherPaths(options);
|
|
299
|
-
const shortcutReady = fs.existsSync(paths.shortcut);
|
|
300
|
-
const platform = options.platform || process.platform;
|
|
301
|
-
const protocolReady = platform === 'win32'
|
|
302
|
-
? commandSucceeded((options.commandRunner || runCapture)('reg.exe', ['query', paths.protocol, '/v', 'URL Protocol']))
|
|
303
|
-
: fs.existsSync(paths.protocol);
|
|
304
|
-
return { ...paths, shortcutReady, protocolReady };
|
|
305
|
-
}
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Step 05 — HTTPS certificates for the local server.
|
|
3
|
-
*
|
|
4
|
-
* The certificate the local server needs — a CA + a localhost server cert,
|
|
5
|
-
* read directly by server.cjs at
|
|
6
|
-
* websocket-server/localhost.{crt,key} — is produced by
|
|
7
|
-
* websocket-server/generate-ca-certificates.cjs. That is what this step
|
|
8
|
-
* drives; verify-certificates.cjs's checks are reproduced inline via openssl
|
|
9
|
-
* so we get a structured result instead of parsing console output.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { createRequire } from 'node:module';
|
|
13
|
-
import { spawnSync } from 'node:child_process';
|
|
14
|
-
import fs from 'node:fs';
|
|
15
|
-
import path from 'node:path';
|
|
16
|
-
import { log, spinner } from '../lib/ui.mjs';
|
|
17
|
-
import { confirm, nonInteractive } from '../lib/prompt.mjs';
|
|
18
|
-
import { commandExists, runCapture, IS_WINDOWS, IS_MAC, REPO_ROOT } from '../lib/platform.mjs';
|
|
19
|
-
|
|
20
|
-
export const meta = {
|
|
21
|
-
id: '05-certificats',
|
|
22
|
-
label: 'Certificats HTTPS',
|
|
23
|
-
description: 'Génère le certificat local requis pour servir l\'administration et l\'API en HTTPS',
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
const CERT_DIR = path.join(REPO_ROOT, 'websocket-server');
|
|
27
|
-
const CERT_PATH = path.join(CERT_DIR, 'localhost.crt');
|
|
28
|
-
const KEY_PATH = path.join(CERT_DIR, 'localhost.key');
|
|
29
|
-
const GEN_SCRIPT = path.join(CERT_DIR, 'generate-ca-certificates.cjs');
|
|
30
|
-
|
|
31
|
-
// Certs valid for less than this many seconds are treated as "needs renewal".
|
|
32
|
-
const EXPIRY_MARGIN_SECONDS = 30 * 24 * 60 * 60; // 30 days
|
|
33
|
-
|
|
34
|
-
const require = createRequire(import.meta.url);
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Read-only validity probe. Returns 'missing', 'expiring' (or unreadable), or 'valid'.
|
|
38
|
-
* When openssl is unavailable the expiry check is skipped gracefully — presence
|
|
39
|
-
* of both files is then treated as good enough.
|
|
40
|
-
*/
|
|
41
|
-
function probeCert() {
|
|
42
|
-
const filesExist = fs.existsSync(CERT_PATH) && fs.existsSync(KEY_PATH);
|
|
43
|
-
if (!filesExist) return { state: 'missing' };
|
|
44
|
-
|
|
45
|
-
if (!commandExists('openssl', ['version'])) {
|
|
46
|
-
return { state: 'valid', opensslMissing: true };
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const checkend = runCapture('openssl', ['x509', '-checkend', String(EXPIRY_MARGIN_SECONDS), '-noout', '-in', CERT_PATH]);
|
|
50
|
-
if (checkend.code === 0) return { state: 'valid' };
|
|
51
|
-
|
|
52
|
-
const enddate = runCapture('openssl', ['x509', '-enddate', '-noout', '-in', CERT_PATH]);
|
|
53
|
-
return { state: 'expiring', enddate: enddate.stdout.replace(/^notAfter=/, '') };
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function installCATrust(caCertPath) {
|
|
57
|
-
if (IS_MAC) {
|
|
58
|
-
// Requires an admin password entered interactively — stdio must be
|
|
59
|
-
// inherited so the user can type it in the real terminal.
|
|
60
|
-
const result = spawnSync(
|
|
61
|
-
'sudo',
|
|
62
|
-
['security', 'add-trusted-cert', '-d', '-r', 'trustRoot', '-k', '/Library/Keychains/System.keychain', caCertPath],
|
|
63
|
-
{ stdio: 'inherit' }
|
|
64
|
-
);
|
|
65
|
-
return result.status === 0;
|
|
66
|
-
}
|
|
67
|
-
if (IS_WINDOWS) {
|
|
68
|
-
const result = spawnSync('certutil', ['-addstore', '-user', 'Root', caCertPath], { stdio: 'inherit' });
|
|
69
|
-
return result.status === 0;
|
|
70
|
-
}
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export async function install(ctx) {
|
|
75
|
-
const probe = probeCert();
|
|
76
|
-
|
|
77
|
-
if (probe.state === 'valid') {
|
|
78
|
-
log.ok(`Certificat déjà valide : ${CERT_PATH}`);
|
|
79
|
-
if (probe.opensslMissing) log.detail('openssl absent — expiration non vérifiée, présence des fichiers seulement.');
|
|
80
|
-
return { status: 'done', note: '' };
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
if (ctx.dryRun) {
|
|
84
|
-
log.info(`[simulation] Génération du certificat CA + serveur dans ${CERT_DIR}`);
|
|
85
|
-
return { status: 'skipped', note: 'Mode simulation — aucune modification effectuée.' };
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
if (!commandExists('openssl', ['version'])) {
|
|
89
|
-
return {
|
|
90
|
-
status: 'failed',
|
|
91
|
-
note: 'OpenSSL introuvable — installez-le (brew install openssl / choco install openssl) puis relancez cette étape.',
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const filesExist = fs.existsSync(CERT_PATH) && fs.existsSync(KEY_PATH);
|
|
96
|
-
if (filesExist && probe.state === 'expiring') {
|
|
97
|
-
const regenerate = await confirm(
|
|
98
|
-
`Le certificat existant expire bientôt (${probe.enddate || 'date inconnue'}). Le régénérer ?`,
|
|
99
|
-
true
|
|
100
|
-
);
|
|
101
|
-
if (!regenerate) {
|
|
102
|
-
return { status: 'partial', note: 'Certificat existant conservé malgré son expiration prochaine.' };
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!fs.existsSync(GEN_SCRIPT)) {
|
|
107
|
-
return { status: 'failed', note: `Script de génération introuvable : ${GEN_SCRIPT}` };
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
const { generateCACertificates, verifyCertificate } = require(GEN_SCRIPT);
|
|
111
|
-
|
|
112
|
-
const spin = spinner('Génération du certificat CA et du certificat serveur (localhost)...');
|
|
113
|
-
let result;
|
|
114
|
-
try {
|
|
115
|
-
result = await generateCACertificates(CERT_DIR);
|
|
116
|
-
} catch (error) {
|
|
117
|
-
spin.fail('Échec de la génération des certificats');
|
|
118
|
-
return { status: 'failed', note: `${error.message} — vérifiez qu'openssl fonctionne (openssl version).` };
|
|
119
|
-
}
|
|
120
|
-
spin.succeed(`Certificats générés : ${path.basename(CERT_PATH)} / ${path.basename(KEY_PATH)}`);
|
|
121
|
-
|
|
122
|
-
try {
|
|
123
|
-
await verifyCertificate(result.serverCert, result.caCert);
|
|
124
|
-
} catch {
|
|
125
|
-
log.warn('La vérification du certificat serveur a échoué — les fichiers sont générés mais non validés.');
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// Trust the CA at the OS level so browsers accept the connection without
|
|
129
|
-
// a security warning. Requires admin rights — ask first.
|
|
130
|
-
if (nonInteractive || !process.stdout.isTTY) {
|
|
131
|
-
return {
|
|
132
|
-
status: 'partial',
|
|
133
|
-
note: `Certificats générés mais CA non ajoutée au magasin de confiance (mode non interactif). Exécutez manuellement : node "${GEN_SCRIPT}"`,
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
const wantTrust = await confirm(
|
|
138
|
-
'Ajouter ce certificat aux autorités de confiance du système ? Nécessaire pour que les navigateurs se connectent sans avertissement (mot de passe administrateur requis).',
|
|
139
|
-
true
|
|
140
|
-
);
|
|
141
|
-
|
|
142
|
-
if (!wantTrust) {
|
|
143
|
-
return {
|
|
144
|
-
status: 'partial',
|
|
145
|
-
note: 'CA non ajoutée au magasin de confiance — les navigateurs peuvent afficher un avertissement de sécurité.',
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
log.step('Ajout du certificat CA au magasin de confiance du système...');
|
|
150
|
-
const trusted = installCATrust(result.caCert);
|
|
151
|
-
if (!trusted) {
|
|
152
|
-
return {
|
|
153
|
-
status: 'partial',
|
|
154
|
-
note: 'Échec de l\'ajout au magasin de confiance (droits administrateur ?). Certificats générés mais non approuvés.',
|
|
155
|
-
};
|
|
156
|
-
}
|
|
157
|
-
log.ok('Certificat CA approuvé par le système');
|
|
158
|
-
|
|
159
|
-
return { status: 'done', note: '' };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export async function check(ctx) {
|
|
163
|
-
const probe = probeCert();
|
|
164
|
-
if (probe.state === 'valid') {
|
|
165
|
-
return { status: 'done', note: probe.opensslMissing ? 'Présence vérifiée (openssl absent, expiration non testée).' : '' };
|
|
166
|
-
}
|
|
167
|
-
if (probe.state === 'expiring') {
|
|
168
|
-
return { status: 'partial', note: `Certificat expire bientôt (${probe.enddate || 'date inconnue'}).` };
|
|
169
|
-
}
|
|
170
|
-
return { status: 'failed', note: `Certificat manquant : ${CERT_PATH}` };
|
|
171
|
-
}
|