opendraft 1.6.17 → 1.6.19
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/bin/opendraft.js +164 -5
- package/package.json +1 -1
package/bin/opendraft.js
CHANGED
|
@@ -101,6 +101,8 @@ function checkPython() {
|
|
|
101
101
|
'/usr/bin/python3',
|
|
102
102
|
];
|
|
103
103
|
|
|
104
|
+
let oldestFound = null; // Track if we find an old Python version
|
|
105
|
+
|
|
104
106
|
for (const cmd of pythonCommands) {
|
|
105
107
|
try {
|
|
106
108
|
const version = execSync(`${cmd} --version 2>&1`, { encoding: 'utf8' }).trim();
|
|
@@ -110,13 +112,25 @@ function checkPython() {
|
|
|
110
112
|
const minor = parseInt(match[2]);
|
|
111
113
|
// Require Python 3.10-3.13
|
|
112
114
|
if (major === 3 && minor >= 10 && minor <= 13) {
|
|
113
|
-
return { cmd, version: `${major}.${minor}
|
|
115
|
+
return { cmd, version: `${major}.${minor}`, status: 'ok' };
|
|
116
|
+
}
|
|
117
|
+
// Track old Python versions (3.7, 3.8, 3.9)
|
|
118
|
+
if (major === 3 && minor >= 7 && minor < 10) {
|
|
119
|
+
if (!oldestFound || minor > oldestFound.minor) {
|
|
120
|
+
oldestFound = { cmd, major, minor, version: `${major}.${minor}` };
|
|
121
|
+
}
|
|
114
122
|
}
|
|
115
123
|
}
|
|
116
124
|
} catch (e) {
|
|
117
125
|
// Command not found, try next
|
|
118
126
|
}
|
|
119
127
|
}
|
|
128
|
+
|
|
129
|
+
// Return info about old Python if found
|
|
130
|
+
if (oldestFound) {
|
|
131
|
+
return { cmd: oldestFound.cmd, version: oldestFound.version, status: 'too_old' };
|
|
132
|
+
}
|
|
133
|
+
|
|
120
134
|
return null;
|
|
121
135
|
}
|
|
122
136
|
|
|
@@ -177,6 +191,25 @@ function installOpendraft(pythonCmd) {
|
|
|
177
191
|
});
|
|
178
192
|
return { success: true };
|
|
179
193
|
} catch (e) {
|
|
194
|
+
const errorMsg = (e.stderr || e.message || '').toLowerCase();
|
|
195
|
+
|
|
196
|
+
// Detect specific error types for better messages
|
|
197
|
+
if (errorMsg.includes('permission denied') || errorMsg.includes('errno 13') || errorMsg.includes('access denied')) {
|
|
198
|
+
return { success: false, error: 'permission_denied' };
|
|
199
|
+
}
|
|
200
|
+
if (errorMsg.includes('network') || errorMsg.includes('connection') || errorMsg.includes('timeout') ||
|
|
201
|
+
errorMsg.includes('could not find') || errorMsg.includes('no matching distribution') ||
|
|
202
|
+
errorMsg.includes('retrying') || errorMsg.includes('ssl')) {
|
|
203
|
+
return { success: false, error: 'network_error' };
|
|
204
|
+
}
|
|
205
|
+
if (errorMsg.includes('no space') || errorMsg.includes('disk full') || errorMsg.includes('errno 28')) {
|
|
206
|
+
return { success: false, error: 'disk_full' };
|
|
207
|
+
}
|
|
208
|
+
if (errorMsg.includes('no module named pip') || errorMsg.includes('pip not found') ||
|
|
209
|
+
errorMsg.includes('no such file') && errorMsg.includes('pip')) {
|
|
210
|
+
return { success: false, error: 'no_pip' };
|
|
211
|
+
}
|
|
212
|
+
|
|
180
213
|
return {
|
|
181
214
|
success: false,
|
|
182
215
|
error: e.stderr || e.message || 'Unknown installation error'
|
|
@@ -250,6 +283,38 @@ function showFriendlyError(errorType, details = {}) {
|
|
|
250
283
|
}
|
|
251
284
|
break;
|
|
252
285
|
|
|
286
|
+
case 'python_too_old':
|
|
287
|
+
printBox([
|
|
288
|
+
`${RED}${BOLD}Python Version Too Old${RESET}`,
|
|
289
|
+
``,
|
|
290
|
+
`You have Python ${details.version}, but OpenDraft needs 3.10+`,
|
|
291
|
+
], RED);
|
|
292
|
+
|
|
293
|
+
const platOld = os.platform();
|
|
294
|
+
print(`${BOLD}You need to install a newer Python version:${RESET}`);
|
|
295
|
+
console.log();
|
|
296
|
+
|
|
297
|
+
if (platOld === 'darwin') {
|
|
298
|
+
print(`${BOLD}Option 1: Homebrew (recommended)${RESET}`);
|
|
299
|
+
print(` ${CYAN}brew install python@3.11${RESET}`);
|
|
300
|
+
console.log();
|
|
301
|
+
print(`${BOLD}Option 2: Download from python.org${RESET}`);
|
|
302
|
+
print(` ${CYAN}https://python.org/downloads${RESET}`);
|
|
303
|
+
} else if (platOld === 'win32') {
|
|
304
|
+
print(`1. Go to ${CYAN}https://python.org/downloads${RESET}`);
|
|
305
|
+
print(`2. Download Python 3.11 or newer`);
|
|
306
|
+
print(`3. ${YELLOW}Check "Add Python to PATH"${RESET} during install`);
|
|
307
|
+
print(`4. ${BOLD}Restart your terminal${RESET}`);
|
|
308
|
+
} else {
|
|
309
|
+
print(`${CYAN}sudo apt install python3.11${RESET} (Ubuntu/Debian)`);
|
|
310
|
+
print(`${CYAN}sudo dnf install python3.11${RESET} (Fedora)`);
|
|
311
|
+
}
|
|
312
|
+
console.log();
|
|
313
|
+
print(`Then try again: ${CYAN}npx opendraft${RESET}`);
|
|
314
|
+
console.log();
|
|
315
|
+
print(`${GRAY}Your current Python ${details.version} will not be affected.${RESET}`)
|
|
316
|
+
break;
|
|
317
|
+
|
|
253
318
|
case 'install_failed':
|
|
254
319
|
printBox([
|
|
255
320
|
`${RED}${BOLD}Installation Failed${RESET}`,
|
|
@@ -269,11 +334,93 @@ function showFriendlyError(errorType, details = {}) {
|
|
|
269
334
|
print(` ${CYAN}brew install pipx && pipx install opendraft${RESET}`);
|
|
270
335
|
console.log();
|
|
271
336
|
|
|
272
|
-
if (details.error) {
|
|
337
|
+
if (details.error && typeof details.error === 'string' && !['permission_denied', 'network_error', 'disk_full'].includes(details.error)) {
|
|
273
338
|
print(`${GRAY}Technical details: ${details.error.substring(0, 200)}${RESET}`);
|
|
274
339
|
}
|
|
275
340
|
break;
|
|
276
341
|
|
|
342
|
+
case 'permission_denied':
|
|
343
|
+
printBox([
|
|
344
|
+
`${RED}${BOLD}Permission Denied${RESET}`,
|
|
345
|
+
``,
|
|
346
|
+
`Can't install packages - you don't have permission.`,
|
|
347
|
+
], RED);
|
|
348
|
+
|
|
349
|
+
print(`${BOLD}Try one of these:${RESET}`);
|
|
350
|
+
console.log();
|
|
351
|
+
print(`${BOLD}Option 1: Install for your user only (recommended)${RESET}`);
|
|
352
|
+
print(` ${CYAN}pip install --user opendraft${RESET}`);
|
|
353
|
+
console.log();
|
|
354
|
+
print(`${BOLD}Option 2: Use sudo (if Option 1 doesn't work)${RESET}`);
|
|
355
|
+
print(` ${CYAN}sudo pip install opendraft${RESET}`);
|
|
356
|
+
console.log();
|
|
357
|
+
print(`${BOLD}Option 3: Use pipx (cleanest)${RESET}`);
|
|
358
|
+
print(` ${CYAN}pipx install opendraft${RESET}`);
|
|
359
|
+
break;
|
|
360
|
+
|
|
361
|
+
case 'network_error':
|
|
362
|
+
printBox([
|
|
363
|
+
`${RED}${BOLD}Network Error${RESET}`,
|
|
364
|
+
``,
|
|
365
|
+
`Can't download the package. Check your internet.`,
|
|
366
|
+
], RED);
|
|
367
|
+
|
|
368
|
+
print(`${BOLD}Things to try:${RESET}`);
|
|
369
|
+
console.log();
|
|
370
|
+
print(`1. Check your internet connection`);
|
|
371
|
+
print(`2. If on VPN, try disconnecting temporarily`);
|
|
372
|
+
print(`3. If on corporate network, you may need proxy settings`);
|
|
373
|
+
console.log();
|
|
374
|
+
print(`${BOLD}Then try again:${RESET}`);
|
|
375
|
+
print(` ${CYAN}npx opendraft${RESET}`);
|
|
376
|
+
console.log();
|
|
377
|
+
print(`${GRAY}Still not working? Try downloading manually:${RESET}`);
|
|
378
|
+
print(` ${CYAN}pip install opendraft --timeout 120${RESET}`);
|
|
379
|
+
break;
|
|
380
|
+
|
|
381
|
+
case 'disk_full':
|
|
382
|
+
printBox([
|
|
383
|
+
`${RED}${BOLD}Disk Full${RESET}`,
|
|
384
|
+
``,
|
|
385
|
+
`Not enough disk space to install the package.`,
|
|
386
|
+
], RED);
|
|
387
|
+
|
|
388
|
+
print(`${BOLD}Free up some space:${RESET}`);
|
|
389
|
+
console.log();
|
|
390
|
+
print(`1. Empty your Trash/Recycle Bin`);
|
|
391
|
+
print(`2. Delete old downloads or unused apps`);
|
|
392
|
+
print(`3. Clear pip cache: ${CYAN}pip cache purge${RESET}`);
|
|
393
|
+
console.log();
|
|
394
|
+
print(`Then try again: ${CYAN}npx opendraft${RESET}`);
|
|
395
|
+
break;
|
|
396
|
+
|
|
397
|
+
case 'no_pip':
|
|
398
|
+
printBox([
|
|
399
|
+
`${RED}${BOLD}pip Not Found${RESET}`,
|
|
400
|
+
``,
|
|
401
|
+
`Python is installed but pip (package manager) is missing.`,
|
|
402
|
+
], RED);
|
|
403
|
+
|
|
404
|
+
const platPip = os.platform();
|
|
405
|
+
print(`${BOLD}Install pip:${RESET}`);
|
|
406
|
+
console.log();
|
|
407
|
+
|
|
408
|
+
if (platPip === 'darwin') {
|
|
409
|
+
print(`${CYAN}python3 -m ensurepip --upgrade${RESET}`);
|
|
410
|
+
console.log();
|
|
411
|
+
print(`Or reinstall Python from ${CYAN}https://python.org${RESET}`);
|
|
412
|
+
} else if (platPip === 'win32') {
|
|
413
|
+
print(`${CYAN}python -m ensurepip --upgrade${RESET}`);
|
|
414
|
+
console.log();
|
|
415
|
+
print(`Or reinstall Python and check "pip" during install`);
|
|
416
|
+
} else {
|
|
417
|
+
print(`${CYAN}sudo apt install python3-pip${RESET} (Ubuntu/Debian)`);
|
|
418
|
+
print(`${CYAN}sudo dnf install python3-pip${RESET} (Fedora)`);
|
|
419
|
+
}
|
|
420
|
+
console.log();
|
|
421
|
+
print(`Then try again: ${CYAN}npx opendraft${RESET}`);
|
|
422
|
+
break;
|
|
423
|
+
|
|
277
424
|
case 'module_not_found':
|
|
278
425
|
printBox([
|
|
279
426
|
`${RED}${BOLD}OpenDraft Package Issue${RESET}`,
|
|
@@ -468,13 +615,19 @@ async function main() {
|
|
|
468
615
|
|
|
469
616
|
// Re-check Python after installation
|
|
470
617
|
const pythonAfter = checkPython();
|
|
471
|
-
if (!pythonAfter) {
|
|
618
|
+
if (!pythonAfter || pythonAfter.status === 'too_old') {
|
|
472
619
|
print(`${RED}Python still not found.${RESET} Please restart your terminal and try again.`);
|
|
473
620
|
process.exit(1);
|
|
474
621
|
}
|
|
475
622
|
return;
|
|
476
623
|
}
|
|
477
624
|
|
|
625
|
+
// Check if Python version is too old
|
|
626
|
+
if (python.status === 'too_old') {
|
|
627
|
+
showFriendlyError('python_too_old', { version: python.version });
|
|
628
|
+
process.exit(1);
|
|
629
|
+
}
|
|
630
|
+
|
|
478
631
|
print(`${GREEN}✓${RESET} Python ${python.version} found`);
|
|
479
632
|
|
|
480
633
|
// Handle --install
|
|
@@ -487,7 +640,10 @@ async function main() {
|
|
|
487
640
|
print(`Run: ${CYAN}npx opendraft${RESET}`);
|
|
488
641
|
console.log();
|
|
489
642
|
} else {
|
|
490
|
-
|
|
643
|
+
// Show specific error message based on error type
|
|
644
|
+
const errorType = ['permission_denied', 'network_error', 'disk_full', 'no_pip'].includes(result.error)
|
|
645
|
+
? result.error : 'install_failed';
|
|
646
|
+
showFriendlyError(errorType, { error: result.error });
|
|
491
647
|
process.exit(1);
|
|
492
648
|
}
|
|
493
649
|
return;
|
|
@@ -504,7 +660,10 @@ async function main() {
|
|
|
504
660
|
const result = installOpendraft(python.cmd);
|
|
505
661
|
|
|
506
662
|
if (!result.success) {
|
|
507
|
-
|
|
663
|
+
// Show specific error message based on error type
|
|
664
|
+
const errorType = ['permission_denied', 'network_error', 'disk_full', 'no_pip'].includes(result.error)
|
|
665
|
+
? result.error : 'install_failed';
|
|
666
|
+
showFriendlyError(errorType, { error: result.error });
|
|
508
667
|
process.exit(1);
|
|
509
668
|
}
|
|
510
669
|
|