@mcmcjs/julia 0.1.0 → 0.2.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/dist/index.cjs +79 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +47 -1
- package/dist/index.d.ts +47 -1
- package/dist/index.js +75 -5
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,7 +22,10 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
detectJulia: () => detectJulia,
|
|
24
24
|
detectJuliaup: () => detectJuliaup,
|
|
25
|
-
|
|
25
|
+
juliaupInstallCommand: () => juliaupInstallCommand,
|
|
26
|
+
planSetup: () => planSetup,
|
|
27
|
+
runDoctor: () => runDoctor,
|
|
28
|
+
runSetup: () => runSetup
|
|
26
29
|
});
|
|
27
30
|
module.exports = __toCommonJS(index_exports);
|
|
28
31
|
|
|
@@ -32,10 +35,16 @@ var import_node_os = require("os");
|
|
|
32
35
|
var import_node_path = require("path");
|
|
33
36
|
var import_node_util = require("util");
|
|
34
37
|
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
function createRunner(timeoutMs = 1e4) {
|
|
39
|
+
return async (command, args) => {
|
|
40
|
+
const { stdout } = await execFileAsync(command, args, {
|
|
41
|
+
timeout: timeoutMs,
|
|
42
|
+
maxBuffer: 16 * 1024 * 1024
|
|
43
|
+
});
|
|
44
|
+
return stdout;
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var defaultRunner = createRunner();
|
|
39
48
|
function candidates(binary) {
|
|
40
49
|
return [(0, import_node_path.join)((0, import_node_os.homedir)(), ".juliaup", "bin", binary), binary];
|
|
41
50
|
}
|
|
@@ -62,10 +71,74 @@ async function runDoctor(runner) {
|
|
|
62
71
|
const [juliaup, julia] = await Promise.all([detectJuliaup(runner), detectJulia(runner)]);
|
|
63
72
|
return { juliaup, julia, ready: julia.found };
|
|
64
73
|
}
|
|
74
|
+
|
|
75
|
+
// src/setup.ts
|
|
76
|
+
var JULIAUP_INSTALL_URL = "https://install.julialang.org";
|
|
77
|
+
function juliaupInstallCommand(platform) {
|
|
78
|
+
if (platform === "win32") {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return { command: "sh", args: ["-c", `curl -fsSL ${JULIAUP_INSTALL_URL} | sh -s -- --yes`] };
|
|
82
|
+
}
|
|
83
|
+
function planSetup(report, platform) {
|
|
84
|
+
if (report.julia.found) return [];
|
|
85
|
+
if (report.juliaup.found) {
|
|
86
|
+
return [
|
|
87
|
+
{
|
|
88
|
+
tool: "julia",
|
|
89
|
+
label: "install the latest stable Julia via juliaup",
|
|
90
|
+
command: { command: report.juliaup.path ?? "juliaup", args: ["add", "release"] }
|
|
91
|
+
}
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
return [
|
|
95
|
+
{
|
|
96
|
+
tool: "juliaup",
|
|
97
|
+
label: "install juliaup (this also installs Julia)",
|
|
98
|
+
command: juliaupInstallCommand(platform)
|
|
99
|
+
}
|
|
100
|
+
];
|
|
101
|
+
}
|
|
102
|
+
async function runSetup(options = {}) {
|
|
103
|
+
const {
|
|
104
|
+
runner,
|
|
105
|
+
installer = createRunner(15 * 6e4),
|
|
106
|
+
platform = process.platform,
|
|
107
|
+
dryRun = false
|
|
108
|
+
} = options;
|
|
109
|
+
const before = await runDoctor(runner);
|
|
110
|
+
if (before.ready) return { ...before, steps: [] };
|
|
111
|
+
const plan = planSetup(before, platform);
|
|
112
|
+
if (dryRun) {
|
|
113
|
+
return {
|
|
114
|
+
...before,
|
|
115
|
+
steps: plan.map((step) => ({ ...step, status: step.command ? "skipped" : "unsupported" }))
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
const steps = [];
|
|
119
|
+
for (const step of plan) {
|
|
120
|
+
if (!step.command) {
|
|
121
|
+
steps.push({ ...step, status: "unsupported" });
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
try {
|
|
125
|
+
await installer(step.command.command, step.command.args);
|
|
126
|
+
steps.push({ ...step, status: "ran" });
|
|
127
|
+
} catch (error) {
|
|
128
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
129
|
+
steps.push({ ...step, status: "failed", detail });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
const after = await runDoctor(runner);
|
|
133
|
+
return { juliaup: after.juliaup, julia: after.julia, ready: after.ready, steps };
|
|
134
|
+
}
|
|
65
135
|
// Annotate the CommonJS export names for ESM import in node:
|
|
66
136
|
0 && (module.exports = {
|
|
67
137
|
detectJulia,
|
|
68
138
|
detectJuliaup,
|
|
69
|
-
|
|
139
|
+
juliaupInstallCommand,
|
|
140
|
+
planSetup,
|
|
141
|
+
runDoctor,
|
|
142
|
+
runSetup
|
|
70
143
|
});
|
|
71
144
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/doctor.ts"],"sourcesContent":["export type { DoctorReport } from \"./doctor\";\nexport { runDoctor } from \"./doctor\";\nexport type { CommandRunner, ToolInfo } from \"./environment\";\nexport { detectJulia, detectJuliaup } from \"./environment\";\n","import { execFile } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Information about a detected command-line tool. */\nexport interface ToolInfo {\n found: boolean;\n version?: string;\n path?: string;\n}\n\n/** Runs a command and resolves its stdout. Injectable so detection is testable. */\nexport type CommandRunner = (command: string, args: string[]) => Promise<string>;\n\
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/environment.ts","../src/doctor.ts","../src/setup.ts"],"sourcesContent":["export type { DoctorReport } from \"./doctor\";\nexport { runDoctor } from \"./doctor\";\nexport type { CommandRunner, ToolInfo } from \"./environment\";\nexport { detectJulia, detectJuliaup } from \"./environment\";\nexport type {\n InstallCommand,\n SetupOptions,\n SetupResult,\n SetupStep,\n SetupStepResult,\n StepStatus,\n} from \"./setup\";\nexport { juliaupInstallCommand, planSetup, runSetup } from \"./setup\";\n","import { execFile } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Information about a detected command-line tool. */\nexport interface ToolInfo {\n found: boolean;\n version?: string;\n path?: string;\n}\n\n/** Runs a command and resolves its stdout. Injectable so detection is testable. */\nexport type CommandRunner = (command: string, args: string[]) => Promise<string>;\n\n/** Creates a runner backed by execFile with the given timeout in milliseconds. */\nexport function createRunner(timeoutMs = 10_000): CommandRunner {\n return async (command, args) => {\n const { stdout } = await execFileAsync(command, args, {\n timeout: timeoutMs,\n maxBuffer: 16 * 1024 * 1024,\n });\n return stdout;\n };\n}\n\nconst defaultRunner = createRunner();\n\n// juliaup installs its shims here; we also fall back to whatever is on PATH.\nfunction candidates(binary: string): string[] {\n return [join(homedir(), \".juliaup\", \"bin\", binary), binary];\n}\n\nasync function detect(\n binary: string,\n parseVersion: (stdout: string) => string | undefined,\n runner: CommandRunner,\n): Promise<ToolInfo> {\n for (const path of candidates(binary)) {\n try {\n const version = parseVersion(await runner(path, [\"--version\"]));\n if (version) return { found: true, version, path };\n } catch {\n // not available at this path; try the next candidate\n }\n }\n return { found: false };\n}\n\nconst versionNumber = (stdout: string): string | undefined => stdout.match(/(\\d+\\.\\d+\\.\\d+)/)?.[1];\n\n/** Detects the Julia runtime via `julia --version`. */\nexport function detectJulia(runner: CommandRunner = defaultRunner): Promise<ToolInfo> {\n return detect(\"julia\", versionNumber, runner);\n}\n\n/** Detects the juliaup version manager via `juliaup --version`. */\nexport function detectJuliaup(runner: CommandRunner = defaultRunner): Promise<ToolInfo> {\n return detect(\"juliaup\", versionNumber, runner);\n}\n","import { type CommandRunner, detectJulia, detectJuliaup, type ToolInfo } from \"./environment\";\n\n/** A summary of the Julia toolchain available for inference. */\nexport interface DoctorReport {\n juliaup: ToolInfo;\n julia: ToolInfo;\n /** True when Julia itself is available (the minimum needed to run inference). */\n ready: boolean;\n}\n\n/** Detects the installed Julia toolchain and reports whether inference can run. */\nexport async function runDoctor(runner?: CommandRunner): Promise<DoctorReport> {\n const [juliaup, julia] = await Promise.all([detectJuliaup(runner), detectJulia(runner)]);\n return { juliaup, julia, ready: julia.found };\n}\n","import { type DoctorReport, runDoctor } from \"./doctor\";\nimport { type CommandRunner, createRunner, type ToolInfo } from \"./environment\";\n\n/** The official juliaup install script, piped to a shell by the install step. */\nconst JULIAUP_INSTALL_URL = \"https://install.julialang.org\";\n\n/** An executable and its arguments, run directly (no shell word-splitting). */\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\n/**\n * The command that installs juliaup on the given platform, or null when\n * automatic install is not yet supported there.\n */\nexport function juliaupInstallCommand(platform: NodeJS.Platform): InstallCommand | null {\n if (platform === \"win32\") {\n // TODO: install juliaup on Windows via winget or the Microsoft Store.\n return null;\n }\n return { command: \"sh\", args: [\"-c\", `curl -fsSL ${JULIAUP_INSTALL_URL} | sh -s -- --yes`] };\n}\n\n/** A single provisioning step needed to make the toolchain ready. */\nexport interface SetupStep {\n tool: \"juliaup\" | \"julia\";\n /** A short description of what the step does. */\n label: string;\n /** The command to run, or null when the step cannot be performed automatically. */\n command: InstallCommand | null;\n}\n\n/** The ordered steps needed to reach a ready toolchain, given the current state. */\nexport function planSetup(report: DoctorReport, platform: NodeJS.Platform): SetupStep[] {\n if (report.julia.found) return [];\n if (report.juliaup.found) {\n return [\n {\n tool: \"julia\",\n label: \"install the latest stable Julia via juliaup\",\n command: { command: report.juliaup.path ?? \"juliaup\", args: [\"add\", \"release\"] },\n },\n ];\n }\n return [\n {\n tool: \"juliaup\",\n label: \"install juliaup (this also installs Julia)\",\n command: juliaupInstallCommand(platform),\n },\n ];\n}\n\nexport type StepStatus = \"ran\" | \"skipped\" | \"failed\" | \"unsupported\";\n\nexport interface SetupStepResult extends SetupStep {\n status: StepStatus;\n /** Error detail when the step failed. */\n detail?: string;\n}\n\nexport interface SetupResult {\n juliaup: ToolInfo;\n julia: ToolInfo;\n /** True when Julia is available after setup. */\n ready: boolean;\n steps: SetupStepResult[];\n}\n\nexport interface SetupOptions {\n /** Runs detection commands. Injectable for tests. */\n runner?: CommandRunner;\n /** Runs install steps, which may take several minutes. Injectable for tests. */\n installer?: CommandRunner;\n /** Target platform; defaults to the current process platform. */\n platform?: NodeJS.Platform;\n /** Plan the steps but do not run them. */\n dryRun?: boolean;\n}\n\n/** Installs the Julia toolchain (juliaup and Julia) needed for inference. */\nexport async function runSetup(options: SetupOptions = {}): Promise<SetupResult> {\n const {\n runner,\n installer = createRunner(15 * 60_000),\n platform = process.platform,\n dryRun = false,\n } = options;\n\n const before = await runDoctor(runner);\n if (before.ready) return { ...before, steps: [] };\n\n const plan = planSetup(before, platform);\n\n if (dryRun) {\n return {\n ...before,\n steps: plan.map((step) => ({ ...step, status: step.command ? \"skipped\" : \"unsupported\" })),\n };\n }\n\n const steps: SetupStepResult[] = [];\n for (const step of plan) {\n if (!step.command) {\n steps.push({ ...step, status: \"unsupported\" });\n continue;\n }\n try {\n await installer(step.command.command, step.command.args);\n steps.push({ ...step, status: \"ran\" });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n steps.push({ ...step, status: \"failed\", detail });\n }\n }\n\n const after = await runDoctor(runner);\n return { juliaup: after.juliaup, julia: after.julia, ready: after.ready, steps };\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -21,4 +21,50 @@ interface DoctorReport {
|
|
|
21
21
|
/** Detects the installed Julia toolchain and reports whether inference can run. */
|
|
22
22
|
declare function runDoctor(runner?: CommandRunner): Promise<DoctorReport>;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
/** An executable and its arguments, run directly (no shell word-splitting). */
|
|
25
|
+
interface InstallCommand {
|
|
26
|
+
command: string;
|
|
27
|
+
args: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The command that installs juliaup on the given platform, or null when
|
|
31
|
+
* automatic install is not yet supported there.
|
|
32
|
+
*/
|
|
33
|
+
declare function juliaupInstallCommand(platform: NodeJS.Platform): InstallCommand | null;
|
|
34
|
+
/** A single provisioning step needed to make the toolchain ready. */
|
|
35
|
+
interface SetupStep {
|
|
36
|
+
tool: "juliaup" | "julia";
|
|
37
|
+
/** A short description of what the step does. */
|
|
38
|
+
label: string;
|
|
39
|
+
/** The command to run, or null when the step cannot be performed automatically. */
|
|
40
|
+
command: InstallCommand | null;
|
|
41
|
+
}
|
|
42
|
+
/** The ordered steps needed to reach a ready toolchain, given the current state. */
|
|
43
|
+
declare function planSetup(report: DoctorReport, platform: NodeJS.Platform): SetupStep[];
|
|
44
|
+
type StepStatus = "ran" | "skipped" | "failed" | "unsupported";
|
|
45
|
+
interface SetupStepResult extends SetupStep {
|
|
46
|
+
status: StepStatus;
|
|
47
|
+
/** Error detail when the step failed. */
|
|
48
|
+
detail?: string;
|
|
49
|
+
}
|
|
50
|
+
interface SetupResult {
|
|
51
|
+
juliaup: ToolInfo;
|
|
52
|
+
julia: ToolInfo;
|
|
53
|
+
/** True when Julia is available after setup. */
|
|
54
|
+
ready: boolean;
|
|
55
|
+
steps: SetupStepResult[];
|
|
56
|
+
}
|
|
57
|
+
interface SetupOptions {
|
|
58
|
+
/** Runs detection commands. Injectable for tests. */
|
|
59
|
+
runner?: CommandRunner;
|
|
60
|
+
/** Runs install steps, which may take several minutes. Injectable for tests. */
|
|
61
|
+
installer?: CommandRunner;
|
|
62
|
+
/** Target platform; defaults to the current process platform. */
|
|
63
|
+
platform?: NodeJS.Platform;
|
|
64
|
+
/** Plan the steps but do not run them. */
|
|
65
|
+
dryRun?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** Installs the Julia toolchain (juliaup and Julia) needed for inference. */
|
|
68
|
+
declare function runSetup(options?: SetupOptions): Promise<SetupResult>;
|
|
69
|
+
|
|
70
|
+
export { type CommandRunner, type DoctorReport, type InstallCommand, type SetupOptions, type SetupResult, type SetupStep, type SetupStepResult, type StepStatus, type ToolInfo, detectJulia, detectJuliaup, juliaupInstallCommand, planSetup, runDoctor, runSetup };
|
package/dist/index.d.ts
CHANGED
|
@@ -21,4 +21,50 @@ interface DoctorReport {
|
|
|
21
21
|
/** Detects the installed Julia toolchain and reports whether inference can run. */
|
|
22
22
|
declare function runDoctor(runner?: CommandRunner): Promise<DoctorReport>;
|
|
23
23
|
|
|
24
|
-
|
|
24
|
+
/** An executable and its arguments, run directly (no shell word-splitting). */
|
|
25
|
+
interface InstallCommand {
|
|
26
|
+
command: string;
|
|
27
|
+
args: string[];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The command that installs juliaup on the given platform, or null when
|
|
31
|
+
* automatic install is not yet supported there.
|
|
32
|
+
*/
|
|
33
|
+
declare function juliaupInstallCommand(platform: NodeJS.Platform): InstallCommand | null;
|
|
34
|
+
/** A single provisioning step needed to make the toolchain ready. */
|
|
35
|
+
interface SetupStep {
|
|
36
|
+
tool: "juliaup" | "julia";
|
|
37
|
+
/** A short description of what the step does. */
|
|
38
|
+
label: string;
|
|
39
|
+
/** The command to run, or null when the step cannot be performed automatically. */
|
|
40
|
+
command: InstallCommand | null;
|
|
41
|
+
}
|
|
42
|
+
/** The ordered steps needed to reach a ready toolchain, given the current state. */
|
|
43
|
+
declare function planSetup(report: DoctorReport, platform: NodeJS.Platform): SetupStep[];
|
|
44
|
+
type StepStatus = "ran" | "skipped" | "failed" | "unsupported";
|
|
45
|
+
interface SetupStepResult extends SetupStep {
|
|
46
|
+
status: StepStatus;
|
|
47
|
+
/** Error detail when the step failed. */
|
|
48
|
+
detail?: string;
|
|
49
|
+
}
|
|
50
|
+
interface SetupResult {
|
|
51
|
+
juliaup: ToolInfo;
|
|
52
|
+
julia: ToolInfo;
|
|
53
|
+
/** True when Julia is available after setup. */
|
|
54
|
+
ready: boolean;
|
|
55
|
+
steps: SetupStepResult[];
|
|
56
|
+
}
|
|
57
|
+
interface SetupOptions {
|
|
58
|
+
/** Runs detection commands. Injectable for tests. */
|
|
59
|
+
runner?: CommandRunner;
|
|
60
|
+
/** Runs install steps, which may take several minutes. Injectable for tests. */
|
|
61
|
+
installer?: CommandRunner;
|
|
62
|
+
/** Target platform; defaults to the current process platform. */
|
|
63
|
+
platform?: NodeJS.Platform;
|
|
64
|
+
/** Plan the steps but do not run them. */
|
|
65
|
+
dryRun?: boolean;
|
|
66
|
+
}
|
|
67
|
+
/** Installs the Julia toolchain (juliaup and Julia) needed for inference. */
|
|
68
|
+
declare function runSetup(options?: SetupOptions): Promise<SetupResult>;
|
|
69
|
+
|
|
70
|
+
export { type CommandRunner, type DoctorReport, type InstallCommand, type SetupOptions, type SetupResult, type SetupStep, type SetupStepResult, type StepStatus, type ToolInfo, detectJulia, detectJuliaup, juliaupInstallCommand, planSetup, runDoctor, runSetup };
|
package/dist/index.js
CHANGED
|
@@ -4,10 +4,16 @@ import { homedir } from "os";
|
|
|
4
4
|
import { join } from "path";
|
|
5
5
|
import { promisify } from "util";
|
|
6
6
|
var execFileAsync = promisify(execFile);
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
function createRunner(timeoutMs = 1e4) {
|
|
8
|
+
return async (command, args) => {
|
|
9
|
+
const { stdout } = await execFileAsync(command, args, {
|
|
10
|
+
timeout: timeoutMs,
|
|
11
|
+
maxBuffer: 16 * 1024 * 1024
|
|
12
|
+
});
|
|
13
|
+
return stdout;
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
var defaultRunner = createRunner();
|
|
11
17
|
function candidates(binary) {
|
|
12
18
|
return [join(homedir(), ".juliaup", "bin", binary), binary];
|
|
13
19
|
}
|
|
@@ -34,9 +40,73 @@ async function runDoctor(runner) {
|
|
|
34
40
|
const [juliaup, julia] = await Promise.all([detectJuliaup(runner), detectJulia(runner)]);
|
|
35
41
|
return { juliaup, julia, ready: julia.found };
|
|
36
42
|
}
|
|
43
|
+
|
|
44
|
+
// src/setup.ts
|
|
45
|
+
var JULIAUP_INSTALL_URL = "https://install.julialang.org";
|
|
46
|
+
function juliaupInstallCommand(platform) {
|
|
47
|
+
if (platform === "win32") {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
return { command: "sh", args: ["-c", `curl -fsSL ${JULIAUP_INSTALL_URL} | sh -s -- --yes`] };
|
|
51
|
+
}
|
|
52
|
+
function planSetup(report, platform) {
|
|
53
|
+
if (report.julia.found) return [];
|
|
54
|
+
if (report.juliaup.found) {
|
|
55
|
+
return [
|
|
56
|
+
{
|
|
57
|
+
tool: "julia",
|
|
58
|
+
label: "install the latest stable Julia via juliaup",
|
|
59
|
+
command: { command: report.juliaup.path ?? "juliaup", args: ["add", "release"] }
|
|
60
|
+
}
|
|
61
|
+
];
|
|
62
|
+
}
|
|
63
|
+
return [
|
|
64
|
+
{
|
|
65
|
+
tool: "juliaup",
|
|
66
|
+
label: "install juliaup (this also installs Julia)",
|
|
67
|
+
command: juliaupInstallCommand(platform)
|
|
68
|
+
}
|
|
69
|
+
];
|
|
70
|
+
}
|
|
71
|
+
async function runSetup(options = {}) {
|
|
72
|
+
const {
|
|
73
|
+
runner,
|
|
74
|
+
installer = createRunner(15 * 6e4),
|
|
75
|
+
platform = process.platform,
|
|
76
|
+
dryRun = false
|
|
77
|
+
} = options;
|
|
78
|
+
const before = await runDoctor(runner);
|
|
79
|
+
if (before.ready) return { ...before, steps: [] };
|
|
80
|
+
const plan = planSetup(before, platform);
|
|
81
|
+
if (dryRun) {
|
|
82
|
+
return {
|
|
83
|
+
...before,
|
|
84
|
+
steps: plan.map((step) => ({ ...step, status: step.command ? "skipped" : "unsupported" }))
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const steps = [];
|
|
88
|
+
for (const step of plan) {
|
|
89
|
+
if (!step.command) {
|
|
90
|
+
steps.push({ ...step, status: "unsupported" });
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
try {
|
|
94
|
+
await installer(step.command.command, step.command.args);
|
|
95
|
+
steps.push({ ...step, status: "ran" });
|
|
96
|
+
} catch (error) {
|
|
97
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
98
|
+
steps.push({ ...step, status: "failed", detail });
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const after = await runDoctor(runner);
|
|
102
|
+
return { juliaup: after.juliaup, julia: after.julia, ready: after.ready, steps };
|
|
103
|
+
}
|
|
37
104
|
export {
|
|
38
105
|
detectJulia,
|
|
39
106
|
detectJuliaup,
|
|
40
|
-
|
|
107
|
+
juliaupInstallCommand,
|
|
108
|
+
planSetup,
|
|
109
|
+
runDoctor,
|
|
110
|
+
runSetup
|
|
41
111
|
};
|
|
42
112
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/environment.ts","../src/doctor.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Information about a detected command-line tool. */\nexport interface ToolInfo {\n found: boolean;\n version?: string;\n path?: string;\n}\n\n/** Runs a command and resolves its stdout. Injectable so detection is testable. */\nexport type CommandRunner = (command: string, args: string[]) => Promise<string>;\n\
|
|
1
|
+
{"version":3,"sources":["../src/environment.ts","../src/doctor.ts","../src/setup.ts"],"sourcesContent":["import { execFile } from \"node:child_process\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport { promisify } from \"node:util\";\n\nconst execFileAsync = promisify(execFile);\n\n/** Information about a detected command-line tool. */\nexport interface ToolInfo {\n found: boolean;\n version?: string;\n path?: string;\n}\n\n/** Runs a command and resolves its stdout. Injectable so detection is testable. */\nexport type CommandRunner = (command: string, args: string[]) => Promise<string>;\n\n/** Creates a runner backed by execFile with the given timeout in milliseconds. */\nexport function createRunner(timeoutMs = 10_000): CommandRunner {\n return async (command, args) => {\n const { stdout } = await execFileAsync(command, args, {\n timeout: timeoutMs,\n maxBuffer: 16 * 1024 * 1024,\n });\n return stdout;\n };\n}\n\nconst defaultRunner = createRunner();\n\n// juliaup installs its shims here; we also fall back to whatever is on PATH.\nfunction candidates(binary: string): string[] {\n return [join(homedir(), \".juliaup\", \"bin\", binary), binary];\n}\n\nasync function detect(\n binary: string,\n parseVersion: (stdout: string) => string | undefined,\n runner: CommandRunner,\n): Promise<ToolInfo> {\n for (const path of candidates(binary)) {\n try {\n const version = parseVersion(await runner(path, [\"--version\"]));\n if (version) return { found: true, version, path };\n } catch {\n // not available at this path; try the next candidate\n }\n }\n return { found: false };\n}\n\nconst versionNumber = (stdout: string): string | undefined => stdout.match(/(\\d+\\.\\d+\\.\\d+)/)?.[1];\n\n/** Detects the Julia runtime via `julia --version`. */\nexport function detectJulia(runner: CommandRunner = defaultRunner): Promise<ToolInfo> {\n return detect(\"julia\", versionNumber, runner);\n}\n\n/** Detects the juliaup version manager via `juliaup --version`. */\nexport function detectJuliaup(runner: CommandRunner = defaultRunner): Promise<ToolInfo> {\n return detect(\"juliaup\", versionNumber, runner);\n}\n","import { type CommandRunner, detectJulia, detectJuliaup, type ToolInfo } from \"./environment\";\n\n/** A summary of the Julia toolchain available for inference. */\nexport interface DoctorReport {\n juliaup: ToolInfo;\n julia: ToolInfo;\n /** True when Julia itself is available (the minimum needed to run inference). */\n ready: boolean;\n}\n\n/** Detects the installed Julia toolchain and reports whether inference can run. */\nexport async function runDoctor(runner?: CommandRunner): Promise<DoctorReport> {\n const [juliaup, julia] = await Promise.all([detectJuliaup(runner), detectJulia(runner)]);\n return { juliaup, julia, ready: julia.found };\n}\n","import { type DoctorReport, runDoctor } from \"./doctor\";\nimport { type CommandRunner, createRunner, type ToolInfo } from \"./environment\";\n\n/** The official juliaup install script, piped to a shell by the install step. */\nconst JULIAUP_INSTALL_URL = \"https://install.julialang.org\";\n\n/** An executable and its arguments, run directly (no shell word-splitting). */\nexport interface InstallCommand {\n command: string;\n args: string[];\n}\n\n/**\n * The command that installs juliaup on the given platform, or null when\n * automatic install is not yet supported there.\n */\nexport function juliaupInstallCommand(platform: NodeJS.Platform): InstallCommand | null {\n if (platform === \"win32\") {\n // TODO: install juliaup on Windows via winget or the Microsoft Store.\n return null;\n }\n return { command: \"sh\", args: [\"-c\", `curl -fsSL ${JULIAUP_INSTALL_URL} | sh -s -- --yes`] };\n}\n\n/** A single provisioning step needed to make the toolchain ready. */\nexport interface SetupStep {\n tool: \"juliaup\" | \"julia\";\n /** A short description of what the step does. */\n label: string;\n /** The command to run, or null when the step cannot be performed automatically. */\n command: InstallCommand | null;\n}\n\n/** The ordered steps needed to reach a ready toolchain, given the current state. */\nexport function planSetup(report: DoctorReport, platform: NodeJS.Platform): SetupStep[] {\n if (report.julia.found) return [];\n if (report.juliaup.found) {\n return [\n {\n tool: \"julia\",\n label: \"install the latest stable Julia via juliaup\",\n command: { command: report.juliaup.path ?? \"juliaup\", args: [\"add\", \"release\"] },\n },\n ];\n }\n return [\n {\n tool: \"juliaup\",\n label: \"install juliaup (this also installs Julia)\",\n command: juliaupInstallCommand(platform),\n },\n ];\n}\n\nexport type StepStatus = \"ran\" | \"skipped\" | \"failed\" | \"unsupported\";\n\nexport interface SetupStepResult extends SetupStep {\n status: StepStatus;\n /** Error detail when the step failed. */\n detail?: string;\n}\n\nexport interface SetupResult {\n juliaup: ToolInfo;\n julia: ToolInfo;\n /** True when Julia is available after setup. */\n ready: boolean;\n steps: SetupStepResult[];\n}\n\nexport interface SetupOptions {\n /** Runs detection commands. Injectable for tests. */\n runner?: CommandRunner;\n /** Runs install steps, which may take several minutes. Injectable for tests. */\n installer?: CommandRunner;\n /** Target platform; defaults to the current process platform. */\n platform?: NodeJS.Platform;\n /** Plan the steps but do not run them. */\n dryRun?: boolean;\n}\n\n/** Installs the Julia toolchain (juliaup and Julia) needed for inference. */\nexport async function runSetup(options: SetupOptions = {}): Promise<SetupResult> {\n const {\n runner,\n installer = createRunner(15 * 60_000),\n platform = process.platform,\n dryRun = false,\n } = options;\n\n const before = await runDoctor(runner);\n if (before.ready) return { ...before, steps: [] };\n\n const plan = planSetup(before, platform);\n\n if (dryRun) {\n return {\n ...before,\n steps: plan.map((step) => ({ ...step, status: step.command ? \"skipped\" : \"unsupported\" })),\n };\n }\n\n const steps: SetupStepResult[] = [];\n for (const step of plan) {\n if (!step.command) {\n steps.push({ ...step, status: \"unsupported\" });\n continue;\n }\n try {\n await installer(step.command.command, step.command.args);\n steps.push({ ...step, status: \"ran\" });\n } catch (error) {\n const detail = error instanceof Error ? error.message : String(error);\n steps.push({ ...step, status: \"failed\", detail });\n }\n }\n\n const after = await runDoctor(runner);\n return { juliaup: after.juliaup, julia: after.julia, ready: after.ready, steps };\n}\n"],"mappings":"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","names":[]}
|