pigo-excel-python-bridge 0.1.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 +21 -0
- package/README.md +53 -0
- package/cli.mjs +372 -0
- package/package.json +22 -0
- package/scripts/python-bridge-server.mjs +1023 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Thomas Mustier
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# pigo-excel-python-bridge
|
|
2
|
+
|
|
3
|
+
Local HTTPS Python / LibreOffice bridge helper for Pi for Excel.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx pigo-excel-python-bridge
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
This command:
|
|
12
|
+
|
|
13
|
+
1. Ensures `mkcert` exists (installs via Homebrew on macOS if missing)
|
|
14
|
+
2. Creates certificates in `~/.pi-for-excel/certs/` when needed
|
|
15
|
+
3. Starts the bridge at `https://localhost:3340`
|
|
16
|
+
4. Runs in real local execution mode by default
|
|
17
|
+
|
|
18
|
+
Real mode requires `python3` on `PATH`. LibreOffice (`soffice` / `libreoffice`) is optional for Python execution but required for `libreoffice_convert`.
|
|
19
|
+
|
|
20
|
+
Optional assisted install (macOS/Homebrew):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx pigo-excel-python-bridge --install-missing
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
This installs missing `python3` and/or LibreOffice before starting the bridge.
|
|
27
|
+
|
|
28
|
+
To force safe simulated mode:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
PYTHON_BRIDGE_MODE=stub npx pigo-excel-python-bridge
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Then in Pi for Excel:
|
|
35
|
+
|
|
36
|
+
1. The default Python bridge URL is already `https://localhost:3340`
|
|
37
|
+
2. (Optional) set `/experimental python-bridge-url <url>` to use a non-default URL
|
|
38
|
+
3. (Optional) run `/experimental python-bridge-token <token>` if you set `PYTHON_BRIDGE_TOKEN`
|
|
39
|
+
|
|
40
|
+
## Publishing (maintainers)
|
|
41
|
+
|
|
42
|
+
Package source lives in `pkg/python-bridge/`.
|
|
43
|
+
|
|
44
|
+
Before packing/publishing, `prepack` copies runtime files from repo root:
|
|
45
|
+
|
|
46
|
+
- `scripts/python-bridge-server.mjs`
|
|
47
|
+
|
|
48
|
+
Publish from this directory:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
cd pkg/python-bridge
|
|
52
|
+
npm publish
|
|
53
|
+
```
|
package/cli.mjs
ADDED
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { spawn, spawnSync } from "node:child_process";
|
|
4
|
+
import fs from "node:fs";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import process from "node:process";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
|
|
10
|
+
const PACKAGE_TAG = "pigo-excel-python-bridge";
|
|
11
|
+
const DEFAULT_PORT = "3340";
|
|
12
|
+
const INSTALL_MISSING_FLAG = "--install-missing";
|
|
13
|
+
|
|
14
|
+
const cliDir = path.dirname(fileURLToPath(import.meta.url));
|
|
15
|
+
const bridgeScriptPath = path.join(cliDir, "scripts", "python-bridge-server.mjs");
|
|
16
|
+
|
|
17
|
+
const homeDir = os.homedir();
|
|
18
|
+
const appDir = path.join(homeDir, ".pi-for-excel");
|
|
19
|
+
const certDir = path.join(appDir, "certs");
|
|
20
|
+
const keyPath = path.join(certDir, "key.pem");
|
|
21
|
+
const certPath = path.join(certDir, "cert.pem");
|
|
22
|
+
|
|
23
|
+
function commandExists(command) {
|
|
24
|
+
const whichCommand = process.platform === "win32" ? "where" : "which";
|
|
25
|
+
const result = spawnSync(whichCommand, [command], { stdio: "ignore" });
|
|
26
|
+
return result.status === 0;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function canRunBinary(command, args = ["--version"]) {
|
|
30
|
+
const result = spawnSync(command, args, {
|
|
31
|
+
stdio: "ignore",
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (result.error || result.signal) {
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return result.status === 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function run(command, args, options = {}) {
|
|
42
|
+
const result = spawnSync(command, args, {
|
|
43
|
+
stdio: "inherit",
|
|
44
|
+
...options,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.error) {
|
|
48
|
+
console.error(`[${PACKAGE_TAG}] Failed to run: ${command}`);
|
|
49
|
+
console.error(result.error.message);
|
|
50
|
+
process.exit(1);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
54
|
+
process.exit(result.status);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (result.signal) {
|
|
58
|
+
console.error(`[${PACKAGE_TAG}] ${command} terminated by signal ${result.signal}`);
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function supportsMkcertCli(command) {
|
|
64
|
+
const result = spawnSync(command, ["-CAROOT"], {
|
|
65
|
+
stdio: "ignore",
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
if (result.error) {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return result.status === 0 && !result.signal;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function resolveMkcertCommand() {
|
|
76
|
+
const candidates = [];
|
|
77
|
+
|
|
78
|
+
if (process.platform === "darwin") {
|
|
79
|
+
const brewCandidates = ["/opt/homebrew/bin/mkcert", "/usr/local/bin/mkcert"];
|
|
80
|
+
for (const candidate of brewCandidates) {
|
|
81
|
+
if (fs.existsSync(candidate)) {
|
|
82
|
+
candidates.push(candidate);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (commandExists("mkcert")) {
|
|
88
|
+
candidates.push("mkcert");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
for (const candidate of candidates) {
|
|
92
|
+
if (supportsMkcertCli(candidate)) {
|
|
93
|
+
return candidate;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (process.platform === "darwin") {
|
|
98
|
+
if (!commandExists("brew")) {
|
|
99
|
+
console.error(`[${PACKAGE_TAG}] Homebrew is not installed.`);
|
|
100
|
+
console.error(`[${PACKAGE_TAG}] Install Homebrew first: https://brew.sh`);
|
|
101
|
+
process.exit(1);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
console.log(`[${PACKAGE_TAG}] Installing mkcert via Homebrew...`);
|
|
105
|
+
run("brew", ["install", "mkcert"]);
|
|
106
|
+
|
|
107
|
+
const brewCandidates = ["/opt/homebrew/bin/mkcert", "/usr/local/bin/mkcert", "mkcert"];
|
|
108
|
+
for (const candidate of brewCandidates) {
|
|
109
|
+
if (candidate !== "mkcert" && !fs.existsSync(candidate)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (supportsMkcertCli(candidate)) {
|
|
114
|
+
return candidate;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
console.error(`[${PACKAGE_TAG}] mkcert is installed but not compatible with required CLI flags.`);
|
|
119
|
+
console.error(`[${PACKAGE_TAG}] Ensure FiloSottile mkcert is used (not the npm mkcert package).`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
console.error(`[${PACKAGE_TAG}] Please install mkcert, then run this command again.`);
|
|
124
|
+
console.error(`[${PACKAGE_TAG}] Install instructions: https://github.com/FiloSottile/mkcert#installation`);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function installMkcertCa(mkcertCommand) {
|
|
129
|
+
const result = spawnSync(mkcertCommand, ["-install"], {
|
|
130
|
+
stdio: "inherit",
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
if (!result.error && result.status === 0 && !result.signal) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
console.error(`[${PACKAGE_TAG}] Failed to install mkcert local CA.`);
|
|
138
|
+
console.error(`[${PACKAGE_TAG}] Run manually: mkcert -install`);
|
|
139
|
+
console.error(`[${PACKAGE_TAG}] If it fails, fix trust-store permissions and retry.`);
|
|
140
|
+
|
|
141
|
+
if (typeof result.status === "number" && result.status !== 0) {
|
|
142
|
+
process.exit(result.status);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
function ensureCertificates() {
|
|
149
|
+
fs.mkdirSync(certDir, { recursive: true });
|
|
150
|
+
|
|
151
|
+
if (fs.existsSync(keyPath) && fs.existsSync(certPath)) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const mkcertCommand = resolveMkcertCommand();
|
|
156
|
+
|
|
157
|
+
console.log(`[${PACKAGE_TAG}] Generating local HTTPS certificates...`);
|
|
158
|
+
installMkcertCa(mkcertCommand);
|
|
159
|
+
|
|
160
|
+
run(mkcertCommand, ["-key-file", keyPath, "-cert-file", certPath, "localhost"], {
|
|
161
|
+
cwd: certDir,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
if (!fs.existsSync(keyPath) || !fs.existsSync(certPath)) {
|
|
165
|
+
console.error(`[${PACKAGE_TAG}] Failed to generate TLS certificates.`);
|
|
166
|
+
process.exit(1);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function resolveConfiguredLibreOfficeBinary(env = process.env) {
|
|
171
|
+
const raw = typeof env.PYTHON_BRIDGE_LIBREOFFICE_BIN === "string"
|
|
172
|
+
? env.PYTHON_BRIDGE_LIBREOFFICE_BIN
|
|
173
|
+
: "";
|
|
174
|
+
const trimmed = raw.trim();
|
|
175
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function resolveBundledLibreOfficeBinary() {
|
|
179
|
+
const candidates = [
|
|
180
|
+
"/Applications/LibreOffice.app/Contents/MacOS/soffice",
|
|
181
|
+
path.join(homeDir, "Applications", "LibreOffice.app", "Contents", "MacOS", "soffice"),
|
|
182
|
+
];
|
|
183
|
+
|
|
184
|
+
for (const candidate of candidates) {
|
|
185
|
+
if (!fs.existsSync(candidate)) {
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
if (canRunBinary(candidate, ["--version"])) {
|
|
190
|
+
return candidate;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function resolveAvailableLibreOfficeBinary(env = process.env) {
|
|
198
|
+
const configured = resolveConfiguredLibreOfficeBinary(env);
|
|
199
|
+
if (configured && canRunBinary(configured, ["--version"])) {
|
|
200
|
+
return configured;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (canRunBinary("soffice", ["--version"])) {
|
|
204
|
+
return "soffice";
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (canRunBinary("libreoffice", ["--version"])) {
|
|
208
|
+
return "libreoffice";
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
return resolveBundledLibreOfficeBinary();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function applyLibreOfficeBinaryOverride(env) {
|
|
215
|
+
if (resolveConfiguredLibreOfficeBinary(env)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const availableBinary = resolveAvailableLibreOfficeBinary(env);
|
|
220
|
+
if (!availableBinary) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (availableBinary === "soffice" || availableBinary === "libreoffice") {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
env.PYTHON_BRIDGE_LIBREOFFICE_BIN = availableBinary;
|
|
229
|
+
console.log(`[${PACKAGE_TAG}] Using LibreOffice binary: ${availableBinary}`);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function installMissingDependencies() {
|
|
233
|
+
const pythonMissing = !canRunBinary("python3", ["--version"]);
|
|
234
|
+
const libreOfficeMissing = !resolveAvailableLibreOfficeBinary();
|
|
235
|
+
|
|
236
|
+
if (!pythonMissing && !libreOfficeMissing) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (process.platform !== "darwin") {
|
|
241
|
+
console.warn(`[${PACKAGE_TAG}] ${INSTALL_MISSING_FLAG} currently supports macOS/Homebrew only.`);
|
|
242
|
+
if (pythonMissing) {
|
|
243
|
+
console.warn(`[${PACKAGE_TAG}] Please install python3 manually and retry.`);
|
|
244
|
+
}
|
|
245
|
+
if (libreOfficeMissing) {
|
|
246
|
+
console.warn(`[${PACKAGE_TAG}] Please install LibreOffice manually and retry.`);
|
|
247
|
+
}
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (!commandExists("brew")) {
|
|
252
|
+
console.error(`[${PACKAGE_TAG}] Homebrew is required for ${INSTALL_MISSING_FLAG}.`);
|
|
253
|
+
console.error(`[${PACKAGE_TAG}] Install Homebrew first: https://brew.sh`);
|
|
254
|
+
process.exit(1);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (pythonMissing) {
|
|
258
|
+
console.log(`[${PACKAGE_TAG}] Installing missing dependency: python3`);
|
|
259
|
+
run("brew", ["install", "python"]);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
if (libreOfficeMissing) {
|
|
263
|
+
console.log(`[${PACKAGE_TAG}] Installing missing dependency: LibreOffice`);
|
|
264
|
+
run("brew", ["install", "--cask", "libreoffice"]);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!canRunBinary("python3", ["--version"])) {
|
|
268
|
+
console.warn(`[${PACKAGE_TAG}] python3 is still unavailable after install attempt.`);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
if (!resolveAvailableLibreOfficeBinary()) {
|
|
272
|
+
console.warn(`[${PACKAGE_TAG}] LibreOffice is still unavailable after install attempt.`);
|
|
273
|
+
console.warn(`[${PACKAGE_TAG}] You can set PYTHON_BRIDGE_LIBREOFFICE_BIN to an absolute soffice path.`);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function resolveBridgeConfig() {
|
|
278
|
+
const userArgs = process.argv.slice(2);
|
|
279
|
+
const installMissing = userArgs.includes(INSTALL_MISSING_FLAG);
|
|
280
|
+
const bridgeUserArgs = userArgs.filter((arg) => arg !== INSTALL_MISSING_FLAG);
|
|
281
|
+
|
|
282
|
+
const hasExplicitScheme = bridgeUserArgs.includes("--https") || bridgeUserArgs.includes("--http");
|
|
283
|
+
const bridgeArgs = hasExplicitScheme ? bridgeUserArgs : ["--https", ...bridgeUserArgs];
|
|
284
|
+
|
|
285
|
+
const usesHttpOnly = bridgeArgs.includes("--http") && !bridgeArgs.includes("--https");
|
|
286
|
+
|
|
287
|
+
return {
|
|
288
|
+
bridgeArgs,
|
|
289
|
+
usesHttps: !usesHttpOnly,
|
|
290
|
+
installMissing,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function applyDefaultPort(env) {
|
|
295
|
+
const configuredPort = typeof env.PORT === "string" ? env.PORT.trim() : "";
|
|
296
|
+
if (configuredPort.length === 0) {
|
|
297
|
+
env.PORT = DEFAULT_PORT;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function applyDefaultMode(env) {
|
|
302
|
+
const configuredMode = typeof env.PYTHON_BRIDGE_MODE === "string"
|
|
303
|
+
? env.PYTHON_BRIDGE_MODE.trim()
|
|
304
|
+
: "";
|
|
305
|
+
|
|
306
|
+
if (configuredMode.length === 0) {
|
|
307
|
+
env.PYTHON_BRIDGE_MODE = "real";
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function startBridge(bridgeArgs) {
|
|
312
|
+
fs.mkdirSync(certDir, { recursive: true });
|
|
313
|
+
console.log(`[${PACKAGE_TAG}] Using certificate directory: ${certDir}`);
|
|
314
|
+
|
|
315
|
+
const childEnv = { ...process.env };
|
|
316
|
+
applyDefaultPort(childEnv);
|
|
317
|
+
applyDefaultMode(childEnv);
|
|
318
|
+
applyLibreOfficeBinaryOverride(childEnv);
|
|
319
|
+
|
|
320
|
+
if (typeof childEnv.PI_FOR_EXCEL_CERT_DIR !== "string" || childEnv.PI_FOR_EXCEL_CERT_DIR.trim().length === 0) {
|
|
321
|
+
childEnv.PI_FOR_EXCEL_CERT_DIR = certDir;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const child = spawn(process.execPath, [bridgeScriptPath, ...bridgeArgs], {
|
|
325
|
+
env: childEnv,
|
|
326
|
+
stdio: "inherit",
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
let shuttingDown = false;
|
|
330
|
+
|
|
331
|
+
const forwardSignal = (signal) => {
|
|
332
|
+
if (shuttingDown) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
shuttingDown = true;
|
|
336
|
+
if (!child.killed) {
|
|
337
|
+
child.kill(signal);
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
|
|
341
|
+
process.on("SIGINT", () => forwardSignal("SIGINT"));
|
|
342
|
+
process.on("SIGTERM", () => forwardSignal("SIGTERM"));
|
|
343
|
+
|
|
344
|
+
child.on("exit", (code, signal) => {
|
|
345
|
+
if (signal) {
|
|
346
|
+
process.kill(process.pid, signal);
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
349
|
+
process.exit(code ?? 1);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
child.on("error", (error) => {
|
|
353
|
+
console.error(`[${PACKAGE_TAG}] Failed to start bridge process.`);
|
|
354
|
+
console.error(error.message);
|
|
355
|
+
process.exit(1);
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (!fs.existsSync(bridgeScriptPath)) {
|
|
360
|
+
console.error(`[${PACKAGE_TAG}] Missing bridge runtime files.`);
|
|
361
|
+
console.error(`[${PACKAGE_TAG}] Reinstall the package or run npm pack again.`);
|
|
362
|
+
process.exit(1);
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
const bridgeConfig = resolveBridgeConfig();
|
|
366
|
+
if (bridgeConfig.installMissing) {
|
|
367
|
+
installMissingDependencies();
|
|
368
|
+
}
|
|
369
|
+
if (bridgeConfig.usesHttps) {
|
|
370
|
+
ensureCertificates();
|
|
371
|
+
}
|
|
372
|
+
startBridge(bridgeConfig.bridgeArgs);
|
package/package.json
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pigo-excel-python-bridge",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "One-command local HTTPS Python / LibreOffice bridge helper for PiGo (Excel add-in).",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pigo-excel-python-bridge": "cli.mjs"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"cli.mjs",
|
|
11
|
+
"scripts/*.mjs",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"prepack": "node ../../scripts/sync-python-bridge-package.mjs"
|
|
17
|
+
},
|
|
18
|
+
"engines": {
|
|
19
|
+
"node": ">=20"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT"
|
|
22
|
+
}
|