regen.mde 0.2.2 → 0.7.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/README.md +409 -295
- package/bin/build-corpus-editor.js +5 -3
- package/bin/postinstall.js +259 -187
- package/bin/regen-mdeditor-install.js +1 -1
- package/bin/regen-mdeditor-uninstall.js +1 -1
- package/desktop/BuildCorpusEditor/BuildCorpusBridge.cs +493 -270
- package/desktop/BuildCorpusEditor/EditorForm.cs +853 -540
- package/desktop/BuildCorpusEditor/Program.cs +85 -81
- package/dist/release/regen-mde-0.3.0-win-x64-setup.exe +0 -0
- package/dist/release/{regen.mde-0.2.2-win-x64.zip → regen-mde-0.3.0-win-x64.zip} +0 -0
- package/dist/release/regen-mde-0.7.0-win-x64-setup.exe +0 -0
- package/dist/release/regen-mde-0.7.0-win-x64.zip +0 -0
- package/dist/windows-editor/BuildCorpusEditor.dll +0 -0
- package/dist/windows-editor/BuildCorpusEditor.exe +0 -0
- package/dist/windows-editor/BuildCorpusEditor.pdb +0 -0
- package/dist/windows-editor/wwwroot/assets/index-C_VxJk4k.js +375 -0
- package/dist/windows-editor/wwwroot/assets/index-Wt9zSjIw.css +1 -0
- package/dist/windows-editor/wwwroot/index.html +3 -3
- package/editor-web/index.html +1 -1
- package/editor-web/src/main.jsx +1044 -399
- package/editor-web/src/styles.css +846 -602
- package/installer/install-regen-mde.ps1 +49 -10
- package/installer/regen-mde.nsi +16 -16
- package/package.json +90 -86
- package/pyproject.toml +35 -33
- package/requirements.txt +6 -4
- package/scripts/package-windows-editor.ps1 +8 -8
- package/scripts/release-dual.mjs +105 -0
- package/scripts/run-editor-implementation-plane.ps1 +29 -6
- package/src/build_corpus/docx_exporter.py +1055 -798
- package/src/build_corpus/equations.py +80 -0
- package/src/build_corpus/exporter.py +1488 -1195
- package/src/build_corpus/frontmatter.py +302 -0
- package/src/build_corpus/ppt_exporter.py +543 -532
- package/dist/release/regen.mde-0.2.2-win-x64-setup.exe +0 -0
- package/dist/windows-editor/wwwroot/assets/index-DjJ6xmhy.js +0 -326
- package/dist/windows-editor/wwwroot/assets/index-_dwMNNsm.css +0 -1
|
@@ -6,6 +6,7 @@ const fs = require("node:fs");
|
|
|
6
6
|
const root = path.resolve(__dirname, "..");
|
|
7
7
|
const callerCwd = process.cwd();
|
|
8
8
|
const candidates = [
|
|
9
|
+
path.join(root, "BuildCorpusEditor.exe"),
|
|
9
10
|
path.join(root, "dist", "windows-editor", "BuildCorpusEditor.exe"),
|
|
10
11
|
path.join(root, "desktop", "BuildCorpusEditor", "bin", "Release", "net8.0-windows", "win-x64", "BuildCorpusEditor.exe"),
|
|
11
12
|
];
|
|
@@ -13,11 +14,12 @@ const exe = candidates.find((candidate) => fs.existsSync(candidate)) || candidat
|
|
|
13
14
|
const args = process.argv.slice(2);
|
|
14
15
|
|
|
15
16
|
if (args.includes("--help") || args.includes("-h")) {
|
|
16
|
-
console.log(`regen
|
|
17
|
+
console.log(`regen-mde
|
|
17
18
|
|
|
18
19
|
Usage:
|
|
19
|
-
regen
|
|
20
|
-
|
|
20
|
+
regen-mde [document.md|document.docx] [options]
|
|
21
|
+
mdeditor [document.md|document.docx] [options]
|
|
22
|
+
regen-mdeditor [document.md|document.docx] [options]
|
|
21
23
|
regen-mdeditor [document.md|document.docx] [options]
|
|
22
24
|
build-corpus-editor [document.md|document.docx] [options]
|
|
23
25
|
|
package/bin/postinstall.js
CHANGED
|
@@ -1,187 +1,259 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
const { spawnSync } = require("node:child_process");
|
|
3
|
-
const path = require("node:path");
|
|
4
|
-
|
|
5
|
-
const UNINSTALL_MODE = process.argv.includes("--uninstall");
|
|
6
|
-
const SKIP_PIP_INSTALL = process.env.BUILD_CORPUS_SKIP_PIP_INSTALL === "1";
|
|
7
|
-
|
|
8
|
-
const packageRoot = path.resolve(__dirname, "..");
|
|
9
|
-
const candidates = process.platform === "win32" ? ["py", "python"] : ["python3", "python"];
|
|
10
|
-
const requirements = path.join(packageRoot, "requirements.txt");
|
|
11
|
-
|
|
12
|
-
function isGlobalInstall() {
|
|
13
|
-
return process.env.npm_config_global === "true";
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function printUsage() {
|
|
17
|
-
const isGlobal = isGlobalInstall();
|
|
18
|
-
if (isGlobal) {
|
|
19
|
-
console.log("Build Corpus installed globally. Run: build-corpus --help");
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
console.log("Build Corpus installed locally.");
|
|
24
|
-
console.log("Run with: npx build-corpus --help");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function warnOnShadowedWindowsCommand() {
|
|
28
|
-
if (process.platform !== "win32") return;
|
|
29
|
-
|
|
30
|
-
const whereResult = spawnSync("where.exe", ["build-corpus"], { encoding: "utf8" });
|
|
31
|
-
if (whereResult.error || whereResult.status !== 0) return;
|
|
32
|
-
|
|
33
|
-
const matches = whereResult.stdout
|
|
34
|
-
.split(/\r?\n/)
|
|
35
|
-
.map((line) => line.trim())
|
|
36
|
-
.filter(Boolean);
|
|
37
|
-
if (matches.length === 0) return;
|
|
38
|
-
|
|
39
|
-
const firstMatch = matches[0].toLowerCase();
|
|
40
|
-
if (!firstMatch.includes("python") || !firstMatch.endsWith("build-corpus.exe")) return;
|
|
41
|
-
|
|
42
|
-
console.warn("");
|
|
43
|
-
console.warn("WARNING: 'build-corpus' currently resolves to a Python executable:");
|
|
44
|
-
console.warn(` ${matches[0]}`);
|
|
45
|
-
console.warn("That usually means a stale pip install is shadowing the npm command.");
|
|
46
|
-
console.warn("Fix it with: py -3 -m pip uninstall build-corpus");
|
|
47
|
-
console.warn("Then rerun your npm install or use: npx build-corpus --help");
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
function installWindowsContextMenu() {
|
|
51
|
-
if (process.platform !== "win32") return;
|
|
52
|
-
if (!isGlobalInstall()) return;
|
|
53
|
-
if (process.env.BUILD_CORPUS_SKIP_WINDOWS_MENU === "1") return;
|
|
54
|
-
|
|
55
|
-
const prefix = process.env.npm_config_prefix || path.join(process.env.APPDATA || "", "npm");
|
|
56
|
-
const commandPath = path.join(prefix, "build-corpus.cmd");
|
|
57
|
-
const editorPath = path.join(prefix, "build-corpus-editor.cmd");
|
|
58
|
-
const nativeEditorPath = path.join(packageRoot, "dist", "windows-editor", "BuildCorpusEditor.exe");
|
|
59
|
-
const editorCommandPath = fileExists(nativeEditorPath) ? nativeEditorPath : editorPath;
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
...
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
for (const
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
const { spawnSync } = require("node:child_process");
|
|
3
|
+
const path = require("node:path");
|
|
4
|
+
|
|
5
|
+
const UNINSTALL_MODE = process.argv.includes("--uninstall");
|
|
6
|
+
const SKIP_PIP_INSTALL = process.env.BUILD_CORPUS_SKIP_PIP_INSTALL === "1";
|
|
7
|
+
|
|
8
|
+
const packageRoot = path.resolve(__dirname, "..");
|
|
9
|
+
const candidates = process.platform === "win32" ? ["py", "python"] : ["python3", "python"];
|
|
10
|
+
const requirements = path.join(packageRoot, "requirements.txt");
|
|
11
|
+
|
|
12
|
+
function isGlobalInstall() {
|
|
13
|
+
return process.env.npm_config_global === "true";
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function printUsage() {
|
|
17
|
+
const isGlobal = isGlobalInstall();
|
|
18
|
+
if (isGlobal) {
|
|
19
|
+
console.log("Build Corpus installed globally. Run: build-corpus --help");
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
console.log("Build Corpus installed locally.");
|
|
24
|
+
console.log("Run with: npx build-corpus --help");
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function warnOnShadowedWindowsCommand() {
|
|
28
|
+
if (process.platform !== "win32") return;
|
|
29
|
+
|
|
30
|
+
const whereResult = spawnSync("where.exe", ["build-corpus"], { encoding: "utf8" });
|
|
31
|
+
if (whereResult.error || whereResult.status !== 0) return;
|
|
32
|
+
|
|
33
|
+
const matches = whereResult.stdout
|
|
34
|
+
.split(/\r?\n/)
|
|
35
|
+
.map((line) => line.trim())
|
|
36
|
+
.filter(Boolean);
|
|
37
|
+
if (matches.length === 0) return;
|
|
38
|
+
|
|
39
|
+
const firstMatch = matches[0].toLowerCase();
|
|
40
|
+
if (!firstMatch.includes("python") || !firstMatch.endsWith("build-corpus.exe")) return;
|
|
41
|
+
|
|
42
|
+
console.warn("");
|
|
43
|
+
console.warn("WARNING: 'build-corpus' currently resolves to a Python executable:");
|
|
44
|
+
console.warn(` ${matches[0]}`);
|
|
45
|
+
console.warn("That usually means a stale pip install is shadowing the npm command.");
|
|
46
|
+
console.warn("Fix it with: py -3 -m pip uninstall build-corpus");
|
|
47
|
+
console.warn("Then rerun your npm install or use: npx build-corpus --help");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function installWindowsContextMenu() {
|
|
51
|
+
if (process.platform !== "win32") return;
|
|
52
|
+
if (!isGlobalInstall()) return;
|
|
53
|
+
if (process.env.BUILD_CORPUS_SKIP_WINDOWS_MENU === "1") return;
|
|
54
|
+
|
|
55
|
+
const prefix = process.env.npm_config_prefix || path.join(process.env.APPDATA || "", "npm");
|
|
56
|
+
const commandPath = path.join(prefix, "build-corpus.cmd");
|
|
57
|
+
const editorPath = path.join(prefix, "build-corpus-editor.cmd");
|
|
58
|
+
const nativeEditorPath = path.join(packageRoot, "dist", "windows-editor", "BuildCorpusEditor.exe");
|
|
59
|
+
const editorCommandPath = fileExists(nativeEditorPath) ? nativeEditorPath : editorPath;
|
|
60
|
+
const markdownInputMenus = [".docx", ".pptx", ".ppt"].map((extension) => ({
|
|
61
|
+
keyName: "BuildCorpusToMarkdown",
|
|
62
|
+
label: "Convert to Markdown",
|
|
63
|
+
commandValue: `"${commandPath}" "%1" --out-same-dir`,
|
|
64
|
+
extension,
|
|
65
|
+
}));
|
|
66
|
+
const menus = [
|
|
67
|
+
...markdownInputMenus,
|
|
68
|
+
{
|
|
69
|
+
keyName: "BuildCorpusFolderToMarkdown",
|
|
70
|
+
label: "Convert Documents to Markdown",
|
|
71
|
+
commandValue: `"${commandPath}" "%V" --out-same-dir`,
|
|
72
|
+
extension: "Directory",
|
|
73
|
+
},
|
|
74
|
+
...(process.env.BUILD_CORPUS_SKIP_EDITOR === "1" ? [] : [
|
|
75
|
+
{
|
|
76
|
+
keyName: "BuildCorpusOpenEditor",
|
|
77
|
+
label: "Open in regen-mde",
|
|
78
|
+
commandValue: `"${editorCommandPath}" "%1"`,
|
|
79
|
+
extension: ".docx",
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
keyName: "BuildCorpusOpenEditor",
|
|
83
|
+
label: "Open in regen-mde",
|
|
84
|
+
commandValue: `"${editorCommandPath}" "%1"`,
|
|
85
|
+
extension: ".md",
|
|
86
|
+
},
|
|
87
|
+
]),
|
|
88
|
+
{
|
|
89
|
+
keyName: "BuildCorpusToWord",
|
|
90
|
+
label: "Convert to Word",
|
|
91
|
+
commandValue: `"${commandPath}" "%1" --to word --out-same-dir`,
|
|
92
|
+
extension: ".md",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
keyName: "BuildCorpusInlineImages",
|
|
96
|
+
label: "Inline Markdown Images",
|
|
97
|
+
commandValue: `"${commandPath}" "%1" --inline-images`,
|
|
98
|
+
extension: ".md",
|
|
99
|
+
},
|
|
100
|
+
];
|
|
101
|
+
|
|
102
|
+
for (const menu of menus) {
|
|
103
|
+
const shellBase = menu.extension === "Directory"
|
|
104
|
+
? "HKCU\\Software\\Classes\\Directory\\shell"
|
|
105
|
+
: `HKCU\\Software\\Classes\\SystemFileAssociations\\${menu.extension}\\shell`;
|
|
106
|
+
const commands = [
|
|
107
|
+
["delete", `${shellBase}\\Life AI`, "/f"],
|
|
108
|
+
["delete", `HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\LifeAI.${menu.keyName}`, "/f"],
|
|
109
|
+
["delete", `HKCU\\Software\\LifeAI\\ShellCommands\\${menu.keyName}`, "/f"],
|
|
110
|
+
["add", `${shellBase}\\${menu.keyName}`, "/v", "MUIVerb", "/d", menu.label, "/f"],
|
|
111
|
+
["add", `${shellBase}\\${menu.keyName}`, "/v", "Icon", "/t", "REG_EXPAND_SZ", "/d", menu.keyName === "BuildCorpusOpenEditor" ? editorCommandPath : commandPath, "/f"],
|
|
112
|
+
["add", `${shellBase}\\${menu.keyName}\\command`, "/ve", "/d", menu.commandValue, "/f"],
|
|
113
|
+
];
|
|
114
|
+
|
|
115
|
+
for (const args of commands) {
|
|
116
|
+
const result = spawnSync("reg.exe", args, { stdio: "inherit" });
|
|
117
|
+
const status = result.status ?? 1;
|
|
118
|
+
if (args[0] === "delete" && status === 1 && !result.error) {
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
if (result.error || status !== 0) {
|
|
122
|
+
console.warn(`Build Corpus could not add the Windows ${menu.extension} context menu.`);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
spawnSync("reg.exe", ["add", "HKCU\\Software\\Classes\\.md", "/v", "Content Type", "/d", "text/markdown", "/f"], { stdio: "inherit" });
|
|
128
|
+
spawnSync("reg.exe", ["add", "HKCU\\Software\\Classes\\.md\\ShellNew", "/v", "NullFile", "/t", "REG_SZ", "/d", "", "/f"], { stdio: "inherit" });
|
|
129
|
+
|
|
130
|
+
console.log("Windows Explorer menus added for .docx, .pptx, .ppt, .md, folders, and New Markdown Document");
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function fileExists(candidate) {
|
|
134
|
+
try {
|
|
135
|
+
return require("node:fs").existsSync(candidate);
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function uninstallWindowsContextMenu() {
|
|
142
|
+
if (process.platform !== "win32") return 0;
|
|
143
|
+
|
|
144
|
+
const menus = [
|
|
145
|
+
{ extension: ".docx", keyName: "BuildCorpusToMarkdown" },
|
|
146
|
+
{ extension: ".pptx", keyName: "BuildCorpusToMarkdown" },
|
|
147
|
+
{ extension: ".ppt", keyName: "BuildCorpusToMarkdown" },
|
|
148
|
+
{ extension: ".docx", keyName: "BuildCorpusOpenEditor" },
|
|
149
|
+
{ extension: ".md", keyName: "BuildCorpusOpenEditor" },
|
|
150
|
+
{ extension: ".md", keyName: "BuildCorpusToWord" },
|
|
151
|
+
{ extension: ".md", keyName: "BuildCorpusInlineImages" },
|
|
152
|
+
{ extension: "Directory", keyName: "BuildCorpusFolderToMarkdown" },
|
|
153
|
+
];
|
|
154
|
+
|
|
155
|
+
let exitCode = 0;
|
|
156
|
+
for (const menu of menus) {
|
|
157
|
+
const shellBase = menu.extension === "Directory"
|
|
158
|
+
? `HKCU\\Software\\Classes\\Directory\\shell`
|
|
159
|
+
: `HKCU\\Software\\Classes\\SystemFileAssociations\\${menu.extension}\\shell`;
|
|
160
|
+
const removals = [
|
|
161
|
+
`${shellBase}\\BuildCorpus`,
|
|
162
|
+
`${shellBase}\\${menu.keyName}`,
|
|
163
|
+
`${shellBase}\\Life AI`,
|
|
164
|
+
`HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\CommandStore\\shell\\LifeAI.${menu.keyName}`,
|
|
165
|
+
`HKCU\\Software\\LifeAI\\ShellCommands\\${menu.keyName}`,
|
|
166
|
+
];
|
|
167
|
+
|
|
168
|
+
for (const key of removals) {
|
|
169
|
+
const result = spawnSync("reg.exe", ["delete", key, "/f"], { stdio: "inherit" });
|
|
170
|
+
const status = result.status ?? 1;
|
|
171
|
+
if (result.error || (status !== 0 && status !== 1)) {
|
|
172
|
+
console.warn(`Build Corpus could not remove the Windows ${menu.extension} context menu.`);
|
|
173
|
+
exitCode = 1;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
spawnSync("reg.exe", ["delete", "HKCU\\Software\\Classes\\.md\\ShellNew", "/f"], { stdio: "inherit" });
|
|
178
|
+
|
|
179
|
+
console.log("Windows Explorer menus removed for .docx, .pptx, .ppt, .md, and folders");
|
|
180
|
+
return exitCode;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
if (UNINSTALL_MODE) {
|
|
184
|
+
process.exit(uninstallWindowsContextMenu());
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (SKIP_PIP_INSTALL) {
|
|
188
|
+
printUsage();
|
|
189
|
+
installWindowsContextMenu();
|
|
190
|
+
warnOnShadowedWindowsCommand();
|
|
191
|
+
process.exit(0);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function pipInstallArgs(candidate, extraFlags) {
|
|
195
|
+
const base = candidate === "py"
|
|
196
|
+
? ["-3", "-m", "pip", "install", "-r", requirements]
|
|
197
|
+
: ["-m", "pip", "install", "-r", requirements];
|
|
198
|
+
return [...base, ...extraFlags];
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Install the Python dependencies for one interpreter candidate.
|
|
202
|
+
// On Windows we make a single attempt (PEP 668 does not apply). On Linux/macOS
|
|
203
|
+
// modern distros mark the system Python "externally managed" (PEP 668), so a
|
|
204
|
+
// bare `pip install` aborts; fall back to user-site, then --break-system-packages.
|
|
205
|
+
// Returns { found } so the caller can try the next interpreter on ENOENT, and
|
|
206
|
+
// { status } for the best attempt.
|
|
207
|
+
function installPythonDeps(candidate) {
|
|
208
|
+
const attempts = process.platform === "win32"
|
|
209
|
+
? [[]]
|
|
210
|
+
: [[], ["--user"], ["--break-system-packages"]];
|
|
211
|
+
|
|
212
|
+
let lastStatus = 1;
|
|
213
|
+
for (const extraFlags of attempts) {
|
|
214
|
+
const result = spawnSync(candidate, pipInstallArgs(candidate, extraFlags), { stdio: "inherit" });
|
|
215
|
+
if (result.error && result.error.code === "ENOENT") return { found: false, status: 1 };
|
|
216
|
+
lastStatus = result.status ?? 1;
|
|
217
|
+
if (lastStatus === 0) return { found: true, status: 0 };
|
|
218
|
+
}
|
|
219
|
+
return { found: true, status: lastStatus };
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function warnLinuxDependencyFallback() {
|
|
223
|
+
console.warn("");
|
|
224
|
+
console.warn("Build Corpus could not install its Python dependencies automatically.");
|
|
225
|
+
console.warn("On Debian/Ubuntu the system Python is externally managed (PEP 668).");
|
|
226
|
+
console.warn("Recommended: install the Python-native package in an isolated environment:");
|
|
227
|
+
console.warn(" pipx install build-corpus");
|
|
228
|
+
console.warn("Or install the dependencies into your user site manually:");
|
|
229
|
+
console.warn(" python3 -m pip install --user -r requirements.txt");
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
for (const candidate of candidates) {
|
|
233
|
+
const { found, status } = installPythonDeps(candidate);
|
|
234
|
+
if (!found) continue;
|
|
235
|
+
|
|
236
|
+
if (status !== 0) {
|
|
237
|
+
// Windows treats a pip failure as fatal; on Linux/macOS we never fail the
|
|
238
|
+
// npm install over PEP 668 — the CLI still works once deps are present.
|
|
239
|
+
if (process.platform === "win32") {
|
|
240
|
+
process.exit(status);
|
|
241
|
+
}
|
|
242
|
+
warnLinuxDependencyFallback();
|
|
243
|
+
printUsage();
|
|
244
|
+
process.exit(0);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
printUsage();
|
|
248
|
+
installWindowsContextMenu();
|
|
249
|
+
warnOnShadowedWindowsCommand();
|
|
250
|
+
process.exit(0);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
console.warn("Build Corpus could not find Python to install Python dependencies.");
|
|
254
|
+
if (process.platform !== "win32") {
|
|
255
|
+
console.warn("Install Python 3.10+ (e.g. `sudo apt install python3 python3-pip`), then re-run the install.");
|
|
256
|
+
}
|
|
257
|
+
printUsage();
|
|
258
|
+
installWindowsContextMenu();
|
|
259
|
+
process.exit(0);
|
|
@@ -3,7 +3,7 @@ const { spawnSync } = require("node:child_process");
|
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
|
|
5
5
|
if (process.platform !== "win32") {
|
|
6
|
-
console.error("regen
|
|
6
|
+
console.error("regen-mde installer is only available on Windows.");
|
|
7
7
|
process.exit(1);
|
|
8
8
|
}
|
|
9
9
|
|
|
@@ -3,7 +3,7 @@ const { spawnSync } = require("node:child_process");
|
|
|
3
3
|
const path = require("node:path");
|
|
4
4
|
|
|
5
5
|
if (process.platform !== "win32") {
|
|
6
|
-
console.error("regen
|
|
6
|
+
console.error("regen-mde uninstaller is only available on Windows.");
|
|
7
7
|
process.exit(1);
|
|
8
8
|
}
|
|
9
9
|
|