@timurproko/a1-install 0.2.6-dev.736 → 0.2.7-dev.1221
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/a1-install.js +119 -25
- package/bin/progress-palette.js +137 -3
- package/package.json +6 -2
package/bin/a1-install.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import { spawn } from "node:child_process";
|
|
4
4
|
import { access, lstat, readFile, realpath } from "node:fs/promises";
|
|
5
|
-
import { lstatSync, realpathSync } from "node:fs";
|
|
5
|
+
import { lstatSync, realpathSync, readFileSync, statSync } from "node:fs";
|
|
6
|
+
import { homedir } from "node:os";
|
|
6
7
|
import { delimiter, dirname, isAbsolute, join, resolve } from "node:path";
|
|
7
8
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
8
|
-
import { SHARED_PROGRESS_ACCENT_ANSI } from "./progress-palette.js";
|
|
9
|
+
import { SHARED_PROGRESS_ACCENT_ANSI, SHARED_PROGRESS_PALETTE } from "./progress-palette.js";
|
|
9
10
|
|
|
10
11
|
export { SHARED_PROGRESS_ACCENT_ANSI };
|
|
11
12
|
|
|
@@ -26,6 +27,9 @@ const STABLE_VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)$
|
|
|
26
27
|
const DEVELOPMENT_VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)-dev\.[1-9]\d*$/u;
|
|
27
28
|
const PREVIEW_NUMBER_PATTERN = /^[1-9]\d*$/u;
|
|
28
29
|
const VERSION_PATTERN = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-dev\.[1-9]\d*)?$/u;
|
|
30
|
+
const DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
31
|
+
const PACKAGE_DOCUMENT_TIMEOUT_MS = 30_000;
|
|
32
|
+
const MAX_PACKAGE_DOCUMENT_BYTES = 32 * 1024 * 1024;
|
|
29
33
|
|
|
30
34
|
class InstallationFailure extends Error {
|
|
31
35
|
constructor(reason, details = "", exitCode = 1) {
|
|
@@ -93,12 +97,34 @@ export function installerHelp() {
|
|
|
93
97
|
].join("\n");
|
|
94
98
|
}
|
|
95
99
|
|
|
96
|
-
|
|
100
|
+
// Invariant: the bootstrap cannot import the main package's settings manager or its dependencies.
|
|
101
|
+
// Mirror only its bounded, read-only global A1 accent resolution before acquisition.
|
|
102
|
+
export function resolveInstallerAccentColor(environment = process.env, home = homedir) {
|
|
103
|
+
try {
|
|
104
|
+
const selectedHome = environment.A1_PROFILE_HOME ?? home();
|
|
105
|
+
if (!isAbsolute(selectedHome) || selectedHome.includes("\0")) return "blue";
|
|
106
|
+
const file = join(selectedHome, ".a1", "agent", "settings.json");
|
|
107
|
+
if (statSync(file).size > 256 * 1024) return "blue";
|
|
108
|
+
const raw = readFileSync(file, "utf8");
|
|
109
|
+
if (Buffer.byteLength(raw, "utf8") > 256 * 1024) return "blue";
|
|
110
|
+
const root = JSON.parse(raw.replace(/^\uFEFF/u, ""));
|
|
111
|
+
const settings = root && typeof root === "object" && !Array.isArray(root)
|
|
112
|
+
? Object.getOwnPropertyDescriptor(root, "a1")?.value : undefined;
|
|
113
|
+
const value = settings && typeof settings === "object" && !Array.isArray(settings)
|
|
114
|
+
? settings.accentColor : undefined;
|
|
115
|
+
if (value === "default") return "purple";
|
|
116
|
+
return typeof value === "string" && Object.hasOwn(SHARED_PROGRESS_PALETTE, value) ? value : "blue";
|
|
117
|
+
} catch {
|
|
118
|
+
return "blue";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function renderProgressBar(percent, accent = SHARED_PROGRESS_ACCENT_ANSI) {
|
|
97
123
|
const bounded = Math.min(100, Math.max(0, Math.round(percent)));
|
|
98
124
|
const filled = Math.round((bounded / 100) * PROGRESS_WIDTH);
|
|
99
125
|
const gray = "\u001b[38;2;128;128;128m";
|
|
100
126
|
const track = "\u001b[38;2;102;102;102m";
|
|
101
|
-
return `${
|
|
127
|
+
return `${accent}${"━".repeat(filled)}${track}${"─".repeat(PROGRESS_WIDTH - filled)}${gray} ${bounded}%\u001b[39m`;
|
|
102
128
|
}
|
|
103
129
|
|
|
104
130
|
export function classifyProgressLine(line, fallback = "Installing") {
|
|
@@ -150,6 +176,7 @@ class ProgressDisplay {
|
|
|
150
176
|
this.timer = null;
|
|
151
177
|
this.visible = false;
|
|
152
178
|
this.maxWidth = PROGRESS_WIDTH + 6;
|
|
179
|
+
this.accent = options.accent ?? SHARED_PROGRESS_ACCENT_ANSI;
|
|
153
180
|
}
|
|
154
181
|
|
|
155
182
|
set(percent, _label, creepTo = percent) {
|
|
@@ -172,7 +199,7 @@ class ProgressDisplay {
|
|
|
172
199
|
this.shown = rounded;
|
|
173
200
|
if (!this.visible) this.output.write("\u001b[?25l");
|
|
174
201
|
this.visible = true;
|
|
175
|
-
this.output.write(`\r${renderProgressBar(rounded)}\u001b[K`);
|
|
202
|
+
this.output.write(`\r${renderProgressBar(rounded, this.accent)}\u001b[K`);
|
|
176
203
|
}
|
|
177
204
|
|
|
178
205
|
finish() {
|
|
@@ -279,16 +306,49 @@ async function runChild(command, args, options) {
|
|
|
279
306
|
|
|
280
307
|
function targetSpec(target) {
|
|
281
308
|
if (target.kind === "develop") return `${APPLICATION_PACKAGE}@next`;
|
|
309
|
+
if (target.kind === "preview") return `${APPLICATION_PACKAGE}@${target.requested}`;
|
|
282
310
|
return `${APPLICATION_PACKAGE}@latest`;
|
|
283
311
|
}
|
|
284
312
|
|
|
313
|
+
/** A numbered preview needs the registry's manifests; a full version resolves through npm directly. */
|
|
314
|
+
function previewNeedsPackageDocument(target) {
|
|
315
|
+
return target.kind === "preview" && PREVIEW_NUMBER_PATTERN.test(target.requested);
|
|
316
|
+
}
|
|
317
|
+
|
|
285
318
|
function resolutionArguments(target) {
|
|
286
|
-
if (target.kind === "preview") {
|
|
287
|
-
return ["view", APPLICATION_PACKAGE, "versions", "--json", "--loglevel=verbose", "--no-fund", "--no-audit"];
|
|
288
|
-
}
|
|
289
319
|
return ["view", targetSpec(target), "version", "--json", "--loglevel=verbose", "--no-fund", "--no-audit"];
|
|
290
320
|
}
|
|
291
321
|
|
|
322
|
+
function packageDocumentUrl(environment) {
|
|
323
|
+
const registry = (environment.npm_config_registry ?? "").trim() || DEFAULT_REGISTRY;
|
|
324
|
+
return `${registry.replace(/\/+$/u, "")}/${encodeURIComponent(APPLICATION_PACKAGE)}`;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* The registry's full package document, whose per-version manifests record the pull request a
|
|
329
|
+
* preview was published from; the version list and the abbreviated install document do not.
|
|
330
|
+
*/
|
|
331
|
+
async function fetchPackageDocument(fetchImpl, environment) {
|
|
332
|
+
let response;
|
|
333
|
+
try {
|
|
334
|
+
response = await fetchImpl(packageDocumentUrl(environment), {
|
|
335
|
+
headers: { accept: "application/json" },
|
|
336
|
+
signal: AbortSignal.timeout(PACKAGE_DOCUMENT_TIMEOUT_MS),
|
|
337
|
+
});
|
|
338
|
+
} catch (error) {
|
|
339
|
+
throw new InstallationFailure("could not resolve the selected release", String(error));
|
|
340
|
+
}
|
|
341
|
+
if (!response.ok) throw new InstallationFailure("could not resolve the selected release", `registry responded with status ${response.status}`);
|
|
342
|
+
const text = await response.text();
|
|
343
|
+
if (text.length > MAX_PACKAGE_DOCUMENT_BYTES) throw new InstallationFailure("could not resolve the selected release", "registry package document is oversized");
|
|
344
|
+
return text;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function recordedPullRequest(manifest) {
|
|
348
|
+
const value = manifest?.publication?.pullRequest;
|
|
349
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : null;
|
|
350
|
+
}
|
|
351
|
+
|
|
292
352
|
function updateArguments(target, targetVersion) {
|
|
293
353
|
if (target.kind === "develop") return ["update", "--develop"];
|
|
294
354
|
if (target.kind === "preview") return ["update", "--develop", targetVersion];
|
|
@@ -313,17 +373,32 @@ function parseResolvedVersion(stdout, target) {
|
|
|
313
373
|
return value;
|
|
314
374
|
}
|
|
315
375
|
|
|
316
|
-
|
|
376
|
+
/**
|
|
377
|
+
* The preview a `--develop` value names among the published versions: an exact full version, or a
|
|
378
|
+
* number that a manifest records as its pull request or that trails a `-dev.<number>` version
|
|
379
|
+
* published before pull requests were recorded. `source` is the registry's package document; a
|
|
380
|
+
* bare JSON list of versions is accepted as a document without records.
|
|
381
|
+
*/
|
|
382
|
+
export function resolvePublishedPreview(source, requested) {
|
|
317
383
|
let published;
|
|
318
|
-
try { published = JSON.parse(String(
|
|
319
|
-
catch { throw new InstallationFailure("could not resolve the selected release", String(
|
|
320
|
-
const
|
|
321
|
-
.filter(value => typeof value === "string"
|
|
384
|
+
try { published = JSON.parse(String(source).trim() || "[]"); }
|
|
385
|
+
catch { throw new InstallationFailure("could not resolve the selected release", String(source)); }
|
|
386
|
+
const manifests = Array.isArray(published)
|
|
387
|
+
? Object.fromEntries(published.filter(value => typeof value === "string").map(version => [version, {}]))
|
|
388
|
+
: published?.versions;
|
|
389
|
+
if (typeof manifests !== "object" || manifests === null) throw new InstallationFailure("could not resolve the selected release", String(source));
|
|
390
|
+
const previews = Object.entries(manifests)
|
|
391
|
+
.filter(([version]) => DEVELOPMENT_VERSION_PATTERN.test(version))
|
|
392
|
+
.map(([version, manifest]) => ({ version, pullRequest: recordedPullRequest(manifest) }));
|
|
393
|
+
const versions = previews.map(preview => preview.version);
|
|
322
394
|
if (DEVELOPMENT_VERSION_PATTERN.test(requested)) {
|
|
323
395
|
if (versions.includes(requested)) return requested;
|
|
324
396
|
throw new InstallationFailure("the selected release was not found", `published no preview ${requested}`);
|
|
325
397
|
}
|
|
326
|
-
const
|
|
398
|
+
const number = Number(requested);
|
|
399
|
+
const matches = previews
|
|
400
|
+
.filter(preview => preview.pullRequest === number || preview.version.endsWith(`-dev.${requested}`))
|
|
401
|
+
.map(preview => preview.version);
|
|
327
402
|
if (matches.length === 1) return matches[0];
|
|
328
403
|
const detail = matches.length === 0
|
|
329
404
|
? `published no preview for ${requested}`
|
|
@@ -500,7 +575,19 @@ export async function runInstaller(argv, options = {}) {
|
|
|
500
575
|
throw new InstallationFailure("Node.js 22.19.0 or newer is required");
|
|
501
576
|
}
|
|
502
577
|
|
|
503
|
-
const
|
|
578
|
+
const accentColor = resolveInstallerAccentColor(environment);
|
|
579
|
+
const background = Number.parseInt(String(environment.COLORFGBG ?? "").split(";").at(-1) ?? "", 10);
|
|
580
|
+
const appearance = Number.isInteger(background) && (background === 7 || background === 15 || background >= 231) ? "light" : "dark";
|
|
581
|
+
const program = (environment.TERM_PROGRAM ?? "").toLowerCase();
|
|
582
|
+
const known = ["kitty", "ghostty", "wezterm", "rex", "warpterminal", "iterm.app", "alacritty", "vscode", "zed"];
|
|
583
|
+
const trueColor = environment.PI_TRUE_COLOR === "1" || (environment.PI_TRUE_COLOR !== "0" && (
|
|
584
|
+
/^(truecolor|24bit)$/iu.test(environment.COLORTERM ?? "")
|
|
585
|
+
|| (environment.TERM ?? "").endsWith("-direct") || process.platform === "win32"
|
|
586
|
+
|| environment.WT_SESSION !== undefined || known.includes(program)
|
|
587
|
+
));
|
|
588
|
+
const mode = trueColor ? "truecolor" : "256color";
|
|
589
|
+
const accent = SHARED_PROGRESS_PALETTE[accentColor][appearance][mode].accent;
|
|
590
|
+
const progress = options.progress ?? new ProgressDisplay(stdout, options.tty ?? stdout.isTTY === true, { ...options.progressOptions, accent });
|
|
504
591
|
const runner = options.runner ?? createDefaultProcessRunner(environment);
|
|
505
592
|
let activeChild = null;
|
|
506
593
|
let killTimer = null;
|
|
@@ -532,16 +619,23 @@ export async function runInstaller(argv, options = {}) {
|
|
|
532
619
|
try {
|
|
533
620
|
progress.set(3, "Preparing", 10);
|
|
534
621
|
let phase = "Resolving version";
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
622
|
+
let targetVersion;
|
|
623
|
+
if (previewNeedsPackageDocument(parsed.target)) {
|
|
624
|
+
// Rationale: a numbered preview is found by the pull request its published manifest records,
|
|
625
|
+
// which only the registry's full package document carries.
|
|
626
|
+
const document = await fetchPackageDocument(options.fetch ?? globalThis.fetch, environment);
|
|
627
|
+
if (cancelled) throw new InstallationCancelled();
|
|
628
|
+
targetVersion = resolvePublishedPreview(document, parsed.target.requested);
|
|
629
|
+
} else {
|
|
630
|
+
const resolveResult = await runner.npm(resolutionArguments(parsed.target), {
|
|
631
|
+
onChild: setActiveChild,
|
|
632
|
+
onStderrLine: line => { phase = classifyProgressLine(line, phase); progress.set(10, phase, 18); },
|
|
633
|
+
});
|
|
634
|
+
setActiveChild(null);
|
|
635
|
+
if (cancelled) throw new InstallationCancelled();
|
|
636
|
+
if (resolveResult.code !== 0) throw new InstallationFailure(conciseFailure("resolve", resolveResult.stderr), resolveResult.stderr);
|
|
637
|
+
targetVersion = parseResolvedVersion(resolveResult.stdout, parsed.target);
|
|
638
|
+
}
|
|
545
639
|
progress.set(18, "Resolving packages", 24);
|
|
546
640
|
|
|
547
641
|
const rootResult = await runner.npm(["root", "--global", "--loglevel=error", "--no-fund", "--no-audit"], { onChild: setActiveChild });
|
package/bin/progress-palette.js
CHANGED
|
@@ -1,5 +1,139 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Generated by scripts/pi/sync-progress-palette.ts from
|
|
3
|
-
* (MIT), commit
|
|
2
|
+
* Generated by scripts/pi/sync-progress-palette.ts from A1's named accent projection
|
|
3
|
+
* over pinned Pi 1.4.0 (MIT), commit 4a080252f06caf63a525d7873c5d94d3c23887e0. Do not edit directly.
|
|
4
4
|
*/
|
|
5
|
-
export const
|
|
5
|
+
export const SHARED_PROGRESS_PALETTE = Object.freeze({
|
|
6
|
+
"blue": {
|
|
7
|
+
"dark": {
|
|
8
|
+
"truecolor": {
|
|
9
|
+
"accent": "\u001b[38;2;130;160;241m",
|
|
10
|
+
"border": "\u001b[38;2;116;102;197m"
|
|
11
|
+
},
|
|
12
|
+
"256color": {
|
|
13
|
+
"accent": "\u001b[38;5;111m",
|
|
14
|
+
"border": "\u001b[38;5;98m"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"light": {
|
|
18
|
+
"truecolor": {
|
|
19
|
+
"accent": "\u001b[38;2;63;96;226m",
|
|
20
|
+
"border": "\u001b[38;2;83;67;154m"
|
|
21
|
+
},
|
|
22
|
+
"256color": {
|
|
23
|
+
"accent": "\u001b[38;5;62m",
|
|
24
|
+
"border": "\u001b[38;5;60m"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
"purple": {
|
|
29
|
+
"dark": {
|
|
30
|
+
"truecolor": {
|
|
31
|
+
"accent": "\u001b[38;2;167;152;215m",
|
|
32
|
+
"border": "\u001b[38;2;105;115;167m"
|
|
33
|
+
},
|
|
34
|
+
"256color": {
|
|
35
|
+
"accent": "\u001b[38;5;140m",
|
|
36
|
+
"border": "\u001b[38;5;61m"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"light": {
|
|
40
|
+
"truecolor": {
|
|
41
|
+
"accent": "\u001b[38;2;116;89;180m",
|
|
42
|
+
"border": "\u001b[38;2;68;77;130m"
|
|
43
|
+
},
|
|
44
|
+
"256color": {
|
|
45
|
+
"accent": "\u001b[38;5;97m",
|
|
46
|
+
"border": "\u001b[38;5;60m"
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"cyan": {
|
|
51
|
+
"dark": {
|
|
52
|
+
"truecolor": {
|
|
53
|
+
"accent": "\u001b[38;2;93;179;186m",
|
|
54
|
+
"border": "\u001b[38;2;74;128;146m"
|
|
55
|
+
},
|
|
56
|
+
"256color": {
|
|
57
|
+
"accent": "\u001b[38;5;73m",
|
|
58
|
+
"border": "\u001b[38;5;66m"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"light": {
|
|
62
|
+
"truecolor": {
|
|
63
|
+
"accent": "\u001b[38;2;40;122;129m",
|
|
64
|
+
"border": "\u001b[38;2;40;89;106m"
|
|
65
|
+
},
|
|
66
|
+
"256color": {
|
|
67
|
+
"accent": "\u001b[38;5;30m",
|
|
68
|
+
"border": "\u001b[38;5;23m"
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"green": {
|
|
73
|
+
"dark": {
|
|
74
|
+
"truecolor": {
|
|
75
|
+
"accent": "\u001b[38;2;104;183;141m",
|
|
76
|
+
"border": "\u001b[38;2;75;132;120m"
|
|
77
|
+
},
|
|
78
|
+
"256color": {
|
|
79
|
+
"accent": "\u001b[38;5;72m",
|
|
80
|
+
"border": "\u001b[38;5;66m"
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
"light": {
|
|
84
|
+
"truecolor": {
|
|
85
|
+
"accent": "\u001b[38;2;51;126;88m",
|
|
86
|
+
"border": "\u001b[38;2;41;93;82m"
|
|
87
|
+
},
|
|
88
|
+
"256color": {
|
|
89
|
+
"accent": "\u001b[38;5;65m",
|
|
90
|
+
"border": "\u001b[38;5;23m"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
"orange": {
|
|
95
|
+
"dark": {
|
|
96
|
+
"truecolor": {
|
|
97
|
+
"accent": "\u001b[38;2;231;135;83m",
|
|
98
|
+
"border": "\u001b[38;2;178;89;79m"
|
|
99
|
+
},
|
|
100
|
+
"256color": {
|
|
101
|
+
"accent": "\u001b[38;5;173m",
|
|
102
|
+
"border": "\u001b[38;5;131m"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"light": {
|
|
106
|
+
"truecolor": {
|
|
107
|
+
"accent": "\u001b[38;2;174;80;16m",
|
|
108
|
+
"border": "\u001b[38;2;133;57;49m"
|
|
109
|
+
},
|
|
110
|
+
"256color": {
|
|
111
|
+
"accent": "\u001b[38;5;130m",
|
|
112
|
+
"border": "\u001b[38;5;95m"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"pink": {
|
|
117
|
+
"dark": {
|
|
118
|
+
"truecolor": {
|
|
119
|
+
"accent": "\u001b[38;2;223;122;199m",
|
|
120
|
+
"border": "\u001b[38;2;150;91;171m"
|
|
121
|
+
},
|
|
122
|
+
"256color": {
|
|
123
|
+
"accent": "\u001b[38;5;176m",
|
|
124
|
+
"border": "\u001b[38;5;97m"
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
"light": {
|
|
128
|
+
"truecolor": {
|
|
129
|
+
"accent": "\u001b[38;2;178;56;153m",
|
|
130
|
+
"border": "\u001b[38;2;114;61;131m"
|
|
131
|
+
},
|
|
132
|
+
"256color": {
|
|
133
|
+
"accent": "\u001b[38;5;132m",
|
|
134
|
+
"border": "\u001b[38;5;60m"
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
export const SHARED_PROGRESS_ACCENT_ANSI = SHARED_PROGRESS_PALETTE.blue.dark.truecolor.accent;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timurproko/a1-install",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.7-dev.1221",
|
|
4
4
|
"description": "Dependency-free installer for a1",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -23,5 +23,9 @@
|
|
|
23
23
|
"url": "https://github.com/timurproko/a1"
|
|
24
24
|
},
|
|
25
25
|
"author": "Timur Prokopiev",
|
|
26
|
-
"license": "MIT"
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"publication": {
|
|
28
|
+
"source": "81d81ade9416f501305300eafaafd2972b0efafb",
|
|
29
|
+
"pullRequest": 846
|
|
30
|
+
}
|
|
27
31
|
}
|