@guiho/runx 0.2.6 → 0.4.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/CHANGELOG.md +44 -0
- package/DOCS.md +128 -109
- package/README.md +58 -58
- package/devops/build-binaries.ts +44 -62
- package/devops/devops.xdocs.md +8 -5
- package/devops/install.ps1 +182 -152
- package/devops/install.sh +197 -262
- package/devops/installers.spec.ts +31 -0
- package/devops/verify-release-assets.ts +17 -0
- package/docs/decisions/decisions.xdocs.md +4 -0
- package/docs/decisions/interactive-init-manifest.md +187 -0
- package/docs/docs.xdocs.md +3 -1
- package/docs/plans/interactive-init-manifest.md +177 -0
- package/docs/plans/plans.xdocs.md +11 -0
- package/docs/plans/rfc-0034-cli-compliance-migration.md +586 -0
- package/docs/plans/upgrade-reliability-implementation.md +95 -0
- package/docs/reviews/implementation/implementation.xdocs.md +6 -0
- package/docs/reviews/implementation/interactive-init-manifest-review.md +69 -0
- package/docs/reviews/implementation/rfc-0034-cli-compliance-migration-review.md +59 -0
- package/docs/reviews/plans/interactive-init-manifest-review.md +82 -0
- package/docs/reviews/plans/plans.xdocs.md +10 -0
- package/docs/reviews/plans/rfc-0034-cli-compliance-migration-review.md +80 -0
- package/docs/reviews/plans/upgrade-reliability-implementation-review.md +65 -0
- package/docs/superpowers/specs/2026-07-15-upgrade-reliability-design.md +662 -0
- package/docs/superpowers/specs/specs.xdocs.md +24 -0
- package/docs/superpowers/superpowers.xdocs.md +21 -0
- package/docs/todo/rfc-0034-cli-compliance-migration-implementation.md +58 -0
- package/docs/todo/rfc-0034-cli-compliance-migration.md +151 -0
- package/docs/todo/todo.xdocs.md +6 -2
- package/docs/validation/interactive-init-manifest.md +79 -0
- package/docs/validation/rfc-0034-cli-compliance-migration.md +67 -0
- package/docs/validation/upgrade-reliability.md +124 -0
- package/docs/validation/validation.xdocs.md +9 -0
- package/library/agents.d.ts +28 -4
- package/library/agents.d.ts.map +1 -1
- package/library/agents.js +143 -41
- package/library/cli.d.ts.map +1 -1
- package/library/cli.js +297 -317
- package/library/configuration.d.ts +57 -0
- package/library/configuration.d.ts.map +1 -0
- package/library/configuration.js +111 -0
- package/library/embedded-resources.d.ts +6 -1
- package/library/embedded-resources.d.ts.map +1 -1
- package/library/embedded-resources.js +10 -4
- package/library/executor.d.ts +5 -1
- package/library/executor.d.ts.map +1 -1
- package/library/executor.js +10 -10
- package/library/help.d.ts +8 -4
- package/library/help.d.ts.map +1 -1
- package/library/help.js +70 -42
- package/library/init.d.ts +18 -0
- package/library/init.d.ts.map +1 -0
- package/library/init.js +43 -0
- package/library/manifest.d.ts +4 -40
- package/library/manifest.d.ts.map +1 -1
- package/library/manifest.js +4 -112
- package/library/path-utils.d.ts +13 -0
- package/library/path-utils.d.ts.map +1 -0
- package/library/path-utils.js +82 -0
- package/library/recovery.d.ts +7 -0
- package/library/recovery.d.ts.map +1 -0
- package/library/recovery.js +23 -0
- package/library/release-catalog.d.ts +32 -0
- package/library/release-catalog.d.ts.map +1 -0
- package/library/release-catalog.js +124 -0
- package/library/self-management.d.ts +24 -4
- package/library/self-management.d.ts.map +1 -1
- package/library/self-management.js +279 -99
- package/library/storage.d.ts +13 -0
- package/library/storage.d.ts.map +1 -0
- package/library/storage.js +38 -0
- package/library/types.d.ts +11 -16
- package/library/types.d.ts.map +1 -1
- package/library/types.js +3 -0
- package/library/update-cache.d.ts +21 -0
- package/library/update-cache.d.ts.map +1 -0
- package/library/update-cache.js +68 -0
- package/library/upgrade-reporting.d.ts +11 -0
- package/library/upgrade-reporting.d.ts.map +1 -0
- package/library/upgrade-reporting.js +67 -0
- package/library/upgrade-types.d.ts +72 -0
- package/library/upgrade-types.d.ts.map +1 -0
- package/library/upgrade-types.js +3 -0
- package/package.json +6 -3
- package/scripts/runx-bin.mjs +49 -0
- package/scripts/runx-bin.spec.ts +62 -0
- package/scripts/scripts.xdocs.md +3 -3
- package/skills/guiho-s-runx/SKILL.md +64 -59
- package/skills/guiho-s-runx/guiho-s-runx.xdocs.md +7 -4
- package/skills/skills.xdocs.md +1 -1
- package/docs/todo/implement-runx-alpha.md +0 -36
- package/scripts/runx-bin.ts +0 -24
package/library/manifest.js
CHANGED
|
@@ -1,112 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const identifier = '^[a-z][a-z0-9-]*$';
|
|
6
|
-
export const CommandSchema = Type.Object({
|
|
7
|
-
uid: Type.String({ pattern: identifier }),
|
|
8
|
-
id: Type.String({ pattern: identifier }),
|
|
9
|
-
group: Type.String({ pattern: identifier }),
|
|
10
|
-
summary: Type.String({ minLength: 1 }),
|
|
11
|
-
description: Type.String({ minLength: 1 }),
|
|
12
|
-
command: Type.String({ minLength: 1 }),
|
|
13
|
-
cwd: Type.Optional(Type.String({ minLength: 1 })),
|
|
14
|
-
shell: Type.Optional(Type.Union([
|
|
15
|
-
Type.Literal('auto'),
|
|
16
|
-
Type.Literal('bash'),
|
|
17
|
-
Type.Literal('sh'),
|
|
18
|
-
Type.Literal('powershell'),
|
|
19
|
-
Type.Literal('cmd'),
|
|
20
|
-
])),
|
|
21
|
-
tags: Type.Optional(Type.Array(Type.String({ minLength: 1 }))),
|
|
22
|
-
confirm: Type.Optional(Type.Union([Type.Literal('never'), Type.Literal('always')])),
|
|
23
|
-
}, { additionalProperties: false });
|
|
24
|
-
export const ManifestSchema = Type.Object({
|
|
25
|
-
version: Type.Literal(1),
|
|
26
|
-
project: Type.Optional(Type.Object({ name: Type.String({ minLength: 1 }) }, { additionalProperties: false })),
|
|
27
|
-
groups: Type.Record(Type.String({ pattern: identifier }), Type.Object({ summary: Type.String({ minLength: 1 }) }, { additionalProperties: false })),
|
|
28
|
-
commands: Type.Array(CommandSchema, { minItems: 1 }),
|
|
29
|
-
}, { additionalProperties: false });
|
|
30
|
-
const manifestCheck = TypeCompiler.Compile(ManifestSchema);
|
|
31
|
-
export const findManifest = async (cwd, explicitFile) => {
|
|
32
|
-
if (explicitFile) {
|
|
33
|
-
const candidate = resolve(cwd, explicitFile);
|
|
34
|
-
if (await Bun.file(candidate).exists())
|
|
35
|
-
return candidate;
|
|
36
|
-
throw new RunXError(`Manifest not found: ${candidate}`);
|
|
37
|
-
}
|
|
38
|
-
let current = resolve(cwd);
|
|
39
|
-
while (true) {
|
|
40
|
-
const candidate = resolve(current, 'runx.yaml');
|
|
41
|
-
if (await Bun.file(candidate).exists())
|
|
42
|
-
return candidate;
|
|
43
|
-
const parent = dirname(current);
|
|
44
|
-
if (parent === current)
|
|
45
|
-
break;
|
|
46
|
-
current = parent;
|
|
47
|
-
}
|
|
48
|
-
throw new RunXError('No runx.yaml found. Run this command inside a configured project or pass --file <path>.');
|
|
49
|
-
};
|
|
50
|
-
export const readManifest = async (cwd, explicitFile) => {
|
|
51
|
-
const path = await findManifest(cwd, explicitFile);
|
|
52
|
-
let parsed;
|
|
53
|
-
try {
|
|
54
|
-
parsed = Bun.YAML.parse(await Bun.file(path).text());
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
const message = error instanceof Error ? error.message : 'Unknown YAML parsing error.';
|
|
58
|
-
throw new RunXError(`Invalid YAML in ${path}: ${message}`);
|
|
59
|
-
}
|
|
60
|
-
if (!manifestCheck.Check(parsed)) {
|
|
61
|
-
const errors = [...manifestCheck.Errors(parsed)].map((error) => `${error.path || '/'}: ${error.message}`);
|
|
62
|
-
throw new RunXError(`Invalid RunX manifest ${path}:\n${errors.join('\n')}`);
|
|
63
|
-
}
|
|
64
|
-
const manifest = parsed;
|
|
65
|
-
validateManifestSemantics(manifest, path);
|
|
66
|
-
return { manifest, path };
|
|
67
|
-
};
|
|
68
|
-
export const resolveCommand = (manifest, manifestPath, selector) => {
|
|
69
|
-
const commands = manifest.commands;
|
|
70
|
-
let command = commands.find((entry) => entry.uid === selector);
|
|
71
|
-
if (!command && selector.includes('/')) {
|
|
72
|
-
command = commands.find((entry) => `${entry.group}/${entry.id}` === selector);
|
|
73
|
-
}
|
|
74
|
-
if (!command && /^\d+$/.test(selector)) {
|
|
75
|
-
command = commands[Number.parseInt(selector, 10) - 1];
|
|
76
|
-
}
|
|
77
|
-
if (!command) {
|
|
78
|
-
const matches = commands.filter((entry) => entry.id === selector);
|
|
79
|
-
if (matches.length > 1) {
|
|
80
|
-
throw new RunXError(`Ambiguous command ID "${selector}". Use one of: ${matches.map((entry) => `${entry.group}/${entry.id} (${entry.uid})`).join(', ')}`);
|
|
81
|
-
}
|
|
82
|
-
command = matches[0];
|
|
83
|
-
}
|
|
84
|
-
if (!command)
|
|
85
|
-
throw new RunXError(`Unknown command selector: ${selector}`);
|
|
86
|
-
const manifestDirectory = dirname(manifestPath);
|
|
87
|
-
const commandCwd = resolve(manifestDirectory, command.cwd ?? '.');
|
|
88
|
-
const relativeCwd = relative(manifestDirectory, commandCwd);
|
|
89
|
-
invariant(!isAbsolute(relativeCwd) && !relativeCwd.startsWith('..'), `Command ${command.uid} has a cwd outside the manifest directory.`);
|
|
90
|
-
return {
|
|
91
|
-
...command,
|
|
92
|
-
index: commands.indexOf(command) + 1,
|
|
93
|
-
selector: `${command.group}/${command.id}`,
|
|
94
|
-
manifestPath,
|
|
95
|
-
cwd: commandCwd,
|
|
96
|
-
};
|
|
97
|
-
};
|
|
98
|
-
const validateManifestSemantics = (manifest, path) => {
|
|
99
|
-
const uids = new Set();
|
|
100
|
-
const selectors = new Set();
|
|
101
|
-
for (const command of manifest.commands) {
|
|
102
|
-
if (!manifest.groups[command.group])
|
|
103
|
-
throw new RunXError(`Command ${command.uid} references unknown group "${command.group}" in ${path}.`);
|
|
104
|
-
if (uids.has(command.uid))
|
|
105
|
-
throw new RunXError(`Duplicate command UID "${command.uid}" in ${path}.`);
|
|
106
|
-
const selector = `${command.group}/${command.id}`;
|
|
107
|
-
if (selectors.has(selector))
|
|
108
|
-
throw new RunXError(`Duplicate command selector "${selector}" in ${path}.`);
|
|
109
|
-
uids.add(command.uid);
|
|
110
|
-
selectors.add(selector);
|
|
111
|
-
}
|
|
112
|
-
};
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
export { commandSchema as CommandSchema, findConfiguration as findManifest, manifestSchema as ManifestSchema, readManifest, resolveCommand, } from './configuration.js';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
export { baseName, directoryName, homeDirectory, isAbsolutePath, joinPath, normalizePath, relativePath, resolvePath, };
|
|
5
|
+
declare function normalizePath(value: string): string;
|
|
6
|
+
declare function isAbsolutePath(value: string): boolean;
|
|
7
|
+
declare function resolvePath(...values: string[]): string;
|
|
8
|
+
declare function joinPath(...values: string[]): string;
|
|
9
|
+
declare function directoryName(value: string): string;
|
|
10
|
+
declare function baseName(value: string): string;
|
|
11
|
+
declare function relativePath(from: string, to: string): string;
|
|
12
|
+
declare function homeDirectory(): string;
|
|
13
|
+
//# sourceMappingURL=path-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"path-utils.d.ts","sourceRoot":"","sources":["../source/path-utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,QAAQ,EACR,aAAa,EACb,aAAa,EACb,cAAc,EACd,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,CAAA;AAQD,iBAAS,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAoB5C;AAED,iBAAS,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE9C;AAED,iBAAS,WAAW,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAQhD;AAED,iBAAS,QAAQ,CAAC,GAAG,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAE7C;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAQ5C;AAED,iBAAS,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvC;AAED,iBAAS,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAYtD;AAED,iBAAS,aAAa,IAAI,MAAM,CAI/B"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
export { baseName, directoryName, homeDirectory, isAbsolutePath, joinPath, normalizePath, relativePath, resolvePath, };
|
|
5
|
+
const windowsDrivePattern = /^[A-Za-z]:[\\/]/;
|
|
6
|
+
function pathSeparator(value = process.platform) {
|
|
7
|
+
return value === 'win32' ? '\\' : '/';
|
|
8
|
+
}
|
|
9
|
+
function normalizePath(value) {
|
|
10
|
+
const separator = pathSeparator();
|
|
11
|
+
const normalized = value.replace(/[\\/]+/g, separator);
|
|
12
|
+
const drive = windowsDrivePattern.test(normalized) ? normalized.slice(0, 2) : '';
|
|
13
|
+
const rooted = drive !== '' || normalized.startsWith(separator);
|
|
14
|
+
const parts = normalized.slice(drive.length).split(separator);
|
|
15
|
+
const output = [];
|
|
16
|
+
for (const part of parts) {
|
|
17
|
+
if (!part || part === '.')
|
|
18
|
+
continue;
|
|
19
|
+
if (part === '..') {
|
|
20
|
+
if (output.length > 0 && output.at(-1) !== '..')
|
|
21
|
+
output.pop();
|
|
22
|
+
else if (!rooted)
|
|
23
|
+
output.push(part);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
output.push(part);
|
|
27
|
+
}
|
|
28
|
+
const prefix = drive ? `${drive}${separator}` : rooted ? separator : '';
|
|
29
|
+
return `${prefix}${output.join(separator)}` || (rooted ? prefix : '.');
|
|
30
|
+
}
|
|
31
|
+
function isAbsolutePath(value) {
|
|
32
|
+
return windowsDrivePattern.test(value) || value.startsWith('/') || value.startsWith('\\');
|
|
33
|
+
}
|
|
34
|
+
function resolvePath(...values) {
|
|
35
|
+
let current = '';
|
|
36
|
+
for (const value of values) {
|
|
37
|
+
if (!value)
|
|
38
|
+
continue;
|
|
39
|
+
current = isAbsolutePath(value) ? value : current ? joinPath(current, value) : value;
|
|
40
|
+
}
|
|
41
|
+
if (!isAbsolutePath(current))
|
|
42
|
+
current = joinPath(process.cwd(), current);
|
|
43
|
+
return normalizePath(current);
|
|
44
|
+
}
|
|
45
|
+
function joinPath(...values) {
|
|
46
|
+
return normalizePath(values.filter(Boolean).join(pathSeparator()));
|
|
47
|
+
}
|
|
48
|
+
function directoryName(value) {
|
|
49
|
+
const normalized = normalizePath(value);
|
|
50
|
+
const separator = pathSeparator();
|
|
51
|
+
const index = normalized.lastIndexOf(separator);
|
|
52
|
+
if (index < 0)
|
|
53
|
+
return '.';
|
|
54
|
+
if (index === 0)
|
|
55
|
+
return separator;
|
|
56
|
+
if (index === 2 && windowsDrivePattern.test(normalized))
|
|
57
|
+
return normalized.slice(0, 3);
|
|
58
|
+
return normalized.slice(0, index);
|
|
59
|
+
}
|
|
60
|
+
function baseName(value) {
|
|
61
|
+
const normalized = normalizePath(value);
|
|
62
|
+
const index = normalized.lastIndexOf(pathSeparator());
|
|
63
|
+
return index < 0 ? normalized : normalized.slice(index + 1);
|
|
64
|
+
}
|
|
65
|
+
function relativePath(from, to) {
|
|
66
|
+
const separator = pathSeparator();
|
|
67
|
+
const fromParts = normalizePath(from).split(separator);
|
|
68
|
+
const toParts = normalizePath(to).split(separator);
|
|
69
|
+
const insensitive = process.platform === 'win32';
|
|
70
|
+
let index = 0;
|
|
71
|
+
while (index < fromParts.length
|
|
72
|
+
&& index < toParts.length
|
|
73
|
+
&& (insensitive ? fromParts[index].toLowerCase() === toParts[index].toLowerCase() : fromParts[index] === toParts[index]))
|
|
74
|
+
index += 1;
|
|
75
|
+
return [...Array(fromParts.length - index).fill('..'), ...toParts.slice(index)].join(separator) || '.';
|
|
76
|
+
}
|
|
77
|
+
function homeDirectory() {
|
|
78
|
+
const home = Bun.env.HOME ?? Bun.env.USERPROFILE;
|
|
79
|
+
if (!home)
|
|
80
|
+
throw new Error('RunX requires HOME or USERPROFILE to resolve global storage.');
|
|
81
|
+
return resolvePath(home);
|
|
82
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import type { RecoveryInstructions, UpgradeOs } from './upgrade-types.js';
|
|
5
|
+
export { createRecoveryInstructions };
|
|
6
|
+
declare const createRecoveryInstructions: (targetVersion: string, os: UpgradeOs, targetSource?: RecoveryInstructions['targetSource'], installerBaseUrl?: string) => RecoveryInstructions;
|
|
7
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../source/recovery.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,oBAAoB,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAEzE,OAAO,EAAE,0BAA0B,EAAE,CAAA;AAIrC,QAAA,MAAM,0BAA0B,kBAAmB,MAAM,MAAM,SAAS,iBAAgB,oBAAoB,CAAC,cAAc,CAAC,gCAA4C,oBAevK,CAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
export { createRecoveryInstructions };
|
|
5
|
+
const rawBase = 'https://raw.githubusercontent.com/CGuiho/runx/main/devops';
|
|
6
|
+
const createRecoveryInstructions = (targetVersion, os, targetSource = 'resolved', installerBaseUrl = rawBase) => {
|
|
7
|
+
if (os === 'windows') {
|
|
8
|
+
return {
|
|
9
|
+
targetVersion,
|
|
10
|
+
targetSource,
|
|
11
|
+
installCommand: `powershell.exe -NoProfile -ExecutionPolicy Bypass -Command '& ([scriptblock]::Create((Invoke-RestMethod "${installerBaseUrl}/install.ps1"))) -Version "${escapePowerShell(targetVersion)}"'`,
|
|
12
|
+
stopProcessCommand: 'powershell.exe -NoProfile -Command "Get-Process runx -ErrorAction SilentlyContinue | Stop-Process -Force"',
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
return {
|
|
16
|
+
targetVersion,
|
|
17
|
+
targetSource,
|
|
18
|
+
installCommand: `curl -fsSL ${installerBaseUrl}/install.sh | sh -s -- --version '${escapeShell(targetVersion)}'`,
|
|
19
|
+
stopProcessCommand: 'pkill -x runx',
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const escapePowerShell = (value) => value.replace(/`/g, '``').replace(/"/g, '`"');
|
|
23
|
+
const escapeShell = (value) => value.replace(/'/g, `'"'"'`);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import type { ReleaseAsset, ReleaseCatalog, UpgradeArch, UpgradeOs, UpgradeVariant } from './upgrade-types.js';
|
|
5
|
+
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, resolveUpgradePlatform, };
|
|
6
|
+
declare const githubReleaseSchema: import("@sinclair/typebox").TObject<{
|
|
7
|
+
tag_name: import("@sinclair/typebox").TString;
|
|
8
|
+
draft: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
9
|
+
prerelease: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TBoolean>;
|
|
10
|
+
published_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
11
|
+
created_at: import("@sinclair/typebox").TOptional<import("@sinclair/typebox").TUnion<[import("@sinclair/typebox").TString, import("@sinclair/typebox").TNull]>>;
|
|
12
|
+
assets: import("@sinclair/typebox").TArray<import("@sinclair/typebox").TObject<{
|
|
13
|
+
name: import("@sinclair/typebox").TString;
|
|
14
|
+
browser_download_url: import("@sinclair/typebox").TString;
|
|
15
|
+
}>>;
|
|
16
|
+
}>;
|
|
17
|
+
export type GitHubRelease = import('@sinclair/typebox').Static<typeof githubReleaseSchema>;
|
|
18
|
+
export type ReleasePlatform = {
|
|
19
|
+
os: UpgradeOs;
|
|
20
|
+
arch: UpgradeArch;
|
|
21
|
+
variant: UpgradeVariant;
|
|
22
|
+
};
|
|
23
|
+
type FetchCatalogOptions = ReleasePlatform & {
|
|
24
|
+
currentVersion: string;
|
|
25
|
+
fetchImpl?: typeof fetch;
|
|
26
|
+
};
|
|
27
|
+
declare const fetchReleaseCatalog: (options: FetchCatalogOptions) => Promise<ReleaseCatalog>;
|
|
28
|
+
declare const findCompatibleAsset: (release: GitHubRelease, platform: ReleasePlatform) => ReleaseAsset | null;
|
|
29
|
+
declare const assetCandidates: ({ os, arch, variant }: ReleasePlatform) => string[];
|
|
30
|
+
declare const resolveUpgradePlatform: (platform?: NodeJS.Platform, architecture?: NodeJS.Architecture) => ReleasePlatform;
|
|
31
|
+
declare const normalizeReleaseVersion: (tag: string) => string;
|
|
32
|
+
//# sourceMappingURL=release-catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"release-catalog.d.ts","sourceRoot":"","sources":["../source/release-catalog.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAuB,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAEnI,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,GACvB,CAAA;AAED,QAAA,MAAM,mBAAmB;;;;;;;;;;EAUS,CAAA;AAIlC,MAAM,MAAM,aAAa,GAAG,OAAO,mBAAmB,EAAE,MAAM,CAAC,OAAO,mBAAmB,CAAC,CAAA;AAE1F,MAAM,MAAM,eAAe,GAAG;IAC5B,EAAE,EAAE,SAAS,CAAA;IACb,IAAI,EAAE,WAAW,CAAA;IACjB,OAAO,EAAE,cAAc,CAAA;CACxB,CAAA;AAED,KAAK,mBAAmB,GAAG,eAAe,GAAG;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,SAAS,CAAC,EAAE,OAAO,KAAK,CAAA;CACzB,CAAA;AAID,QAAA,MAAM,mBAAmB,YAAmB,mBAAmB,KAAG,OAAO,CAAC,cAAc,CAoCvF,CAAA;AAkBD,QAAA,MAAM,mBAAmB,YAAa,aAAa,YAAY,eAAe,KAAG,YAAY,GAAG,IAM/F,CAAA;AAED,QAAA,MAAM,eAAe,0BAA2B,eAAe,KAAG,MAAM,EAUvE,CAAA;AAED,QAAA,MAAM,sBAAsB,sEAA+D,eAM1F,CAAA;AAED,QAAA,MAAM,uBAAuB,QAAS,MAAM,KAAG,MAA6D,CAAA"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import { Type } from '@sinclair/typebox';
|
|
5
|
+
import { Value } from '@sinclair/typebox/value';
|
|
6
|
+
import { compare, parse, valid } from 'semver';
|
|
7
|
+
import { RunXError } from './errors.js';
|
|
8
|
+
export { assetCandidates, fetchReleaseCatalog, findCompatibleAsset, normalizeReleaseVersion, resolveUpgradePlatform, };
|
|
9
|
+
const githubReleaseSchema = Type.Object({
|
|
10
|
+
tag_name: Type.String(),
|
|
11
|
+
draft: Type.Optional(Type.Boolean()),
|
|
12
|
+
prerelease: Type.Optional(Type.Boolean()),
|
|
13
|
+
published_at: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
14
|
+
created_at: Type.Optional(Type.Union([Type.String(), Type.Null()])),
|
|
15
|
+
assets: Type.Array(Type.Object({
|
|
16
|
+
name: Type.String(),
|
|
17
|
+
browser_download_url: Type.String(),
|
|
18
|
+
}, { additionalProperties: true })),
|
|
19
|
+
}, { additionalProperties: true });
|
|
20
|
+
const githubReleasesSchema = Type.Array(githubReleaseSchema);
|
|
21
|
+
const repositoryApi = 'https://api.github.com/repos/CGuiho/runx/releases';
|
|
22
|
+
const fetchReleaseCatalog = async (options) => {
|
|
23
|
+
const fetchImpl = options.fetchImpl ?? fetch;
|
|
24
|
+
const releases = [];
|
|
25
|
+
let page = 1;
|
|
26
|
+
let next = true;
|
|
27
|
+
while (next) {
|
|
28
|
+
const response = await fetchImpl(`${repositoryApi}?per_page=100&page=${page}`, {
|
|
29
|
+
headers: { accept: 'application/vnd.github+json' },
|
|
30
|
+
});
|
|
31
|
+
if (!response.ok)
|
|
32
|
+
throw new RunXError(`Could not retrieve RunX releases page ${page}: HTTP ${response.status}`, 4);
|
|
33
|
+
const payload = await response.json();
|
|
34
|
+
let pageReleases;
|
|
35
|
+
try {
|
|
36
|
+
pageReleases = Value.Decode(githubReleasesSchema, payload);
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
throw new RunXError(`Could not retrieve RunX releases page ${page}: malformed release`, 4);
|
|
40
|
+
}
|
|
41
|
+
releases.push(...pageReleases.filter((release) => !release.draft));
|
|
42
|
+
next = hasNextPage(response.headers.get('link'));
|
|
43
|
+
page += 1;
|
|
44
|
+
}
|
|
45
|
+
const normalized = releases.map((release) => normalizeRelease(release, options));
|
|
46
|
+
normalized.sort(compareCatalogEntries);
|
|
47
|
+
const latestStableVersion = normalized.find((entry) => valid(entry.version) && !entry.prerelease)?.version ?? null;
|
|
48
|
+
for (const entry of normalized)
|
|
49
|
+
entry.latestStable = entry.version === latestStableVersion;
|
|
50
|
+
return {
|
|
51
|
+
schemaVersion: 1,
|
|
52
|
+
command: 'runx upgrade list',
|
|
53
|
+
currentVersion: options.currentVersion,
|
|
54
|
+
latestStableVersion,
|
|
55
|
+
releases: normalized,
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
const normalizeRelease = (release, platform) => {
|
|
59
|
+
const version = normalizeReleaseVersion(release.tag_name);
|
|
60
|
+
const parsed = parse(version);
|
|
61
|
+
const prerelease = parsed ? parsed.prerelease.length > 0 : Boolean(release.prerelease);
|
|
62
|
+
return {
|
|
63
|
+
tag: release.tag_name,
|
|
64
|
+
version,
|
|
65
|
+
channel: releaseChannel(version, prerelease),
|
|
66
|
+
prerelease,
|
|
67
|
+
publishedAt: release.published_at ?? release.created_at ?? null,
|
|
68
|
+
current: version === platform.currentVersion,
|
|
69
|
+
latestStable: false,
|
|
70
|
+
compatibleAsset: findCompatibleAsset(release, platform),
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
const findCompatibleAsset = (release, platform) => {
|
|
74
|
+
for (const candidate of assetCandidates(platform)) {
|
|
75
|
+
const asset = release.assets.find((item) => item.name === candidate);
|
|
76
|
+
if (asset)
|
|
77
|
+
return { name: asset.name, url: asset.browser_download_url };
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
};
|
|
81
|
+
const assetCandidates = ({ os, arch, variant }) => {
|
|
82
|
+
const suffix = os === 'windows' ? '.exe' : '';
|
|
83
|
+
if (arch === 'arm64')
|
|
84
|
+
return [`runx-${os}-arm64${suffix}`];
|
|
85
|
+
const prefix = `runx-${os}-x64`;
|
|
86
|
+
const names = {
|
|
87
|
+
baseline: [`${prefix}-baseline${suffix}`, `${prefix}${suffix}`, `${prefix}-modern${suffix}`],
|
|
88
|
+
default: [`${prefix}${suffix}`, `${prefix}-baseline${suffix}`, `${prefix}-modern${suffix}`],
|
|
89
|
+
modern: [`${prefix}-modern${suffix}`, `${prefix}${suffix}`, `${prefix}-baseline${suffix}`],
|
|
90
|
+
};
|
|
91
|
+
return names[variant];
|
|
92
|
+
};
|
|
93
|
+
const resolveUpgradePlatform = (platform = process.platform, architecture = process.arch) => {
|
|
94
|
+
const os = platform === 'win32' ? 'windows' : platform === 'darwin' ? 'darwin' : platform === 'linux' ? 'linux' : null;
|
|
95
|
+
const arch = architecture === 'x64' ? 'x64' : architecture === 'arm64' ? 'arm64' : null;
|
|
96
|
+
if (!os)
|
|
97
|
+
throw new RunXError(`Self-upgrade is not supported on ${platform}.`);
|
|
98
|
+
if (!arch)
|
|
99
|
+
throw new RunXError(`Self-upgrade is not supported on architecture ${architecture}.`);
|
|
100
|
+
return { os, arch, variant: 'baseline' };
|
|
101
|
+
};
|
|
102
|
+
const normalizeReleaseVersion = (tag) => tag.replace(/^@guiho\/runx@/, '').replace(/^v/, '');
|
|
103
|
+
const releaseChannel = (version, prerelease) => {
|
|
104
|
+
const parsed = parse(version);
|
|
105
|
+
if (!parsed)
|
|
106
|
+
return 'other';
|
|
107
|
+
if (!prerelease)
|
|
108
|
+
return 'stable';
|
|
109
|
+
const identifier = parsed.prerelease[0];
|
|
110
|
+
return typeof identifier === 'string' ? identifier : 'prerelease';
|
|
111
|
+
};
|
|
112
|
+
const compareCatalogEntries = (left, right) => {
|
|
113
|
+
const leftValid = valid(left.version);
|
|
114
|
+
const rightValid = valid(right.version);
|
|
115
|
+
if (leftValid && rightValid)
|
|
116
|
+
return compare(rightValid, leftValid);
|
|
117
|
+
if (leftValid)
|
|
118
|
+
return -1;
|
|
119
|
+
if (rightValid)
|
|
120
|
+
return 1;
|
|
121
|
+
return timestamp(right.publishedAt) - timestamp(left.publishedAt);
|
|
122
|
+
};
|
|
123
|
+
const timestamp = (value) => value ? Date.parse(value) || 0 : 0;
|
|
124
|
+
const hasNextPage = (link) => Boolean(link?.split(',').some((part) => /rel="next"/.test(part)));
|
|
@@ -1,11 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @copyright Copyright © 2026 GUIHO Technologies as represented by Cristóvão GUIHO. All Rights Reserved.
|
|
3
|
+
*/
|
|
4
|
+
import type { ReleaseCatalog, UpgradeEnvelope, UpgradeEvent, UpgradePlan } from './upgrade-types.js';
|
|
5
|
+
import type { UpdateResult } from './types.js';
|
|
6
|
+
export { checkForLatestVersion, listAvailableVersions, uninstallSelf, upgradeSelf, validateNativeBinary };
|
|
7
|
+
export type UpgradeFileOperations = {
|
|
8
|
+
rename: (from: string, to: string) => Promise<void>;
|
|
9
|
+
remove: (path: string) => Promise<void>;
|
|
10
|
+
makeExecutable: (path: string) => Promise<void>;
|
|
11
|
+
};
|
|
12
|
+
export type UpgradeSelfOptions = {
|
|
13
|
+
dryRun: boolean;
|
|
14
|
+
currentVersion?: string;
|
|
15
|
+
requestedVersion?: string;
|
|
16
|
+
arch?: UpgradePlan['arch'];
|
|
17
|
+
variant?: import('./upgrade-types.js').UpgradeVariant;
|
|
18
|
+
onPlan?: (plan: UpgradePlan) => void;
|
|
19
|
+
onEvent?: (event: UpgradeEvent) => void;
|
|
20
|
+
fileOperations?: UpgradeFileOperations;
|
|
21
|
+
};
|
|
3
22
|
declare const checkForLatestVersion: () => Promise<UpdateResult>;
|
|
4
|
-
declare const listAvailableVersions: () => Promise<
|
|
5
|
-
declare const upgradeSelf: (
|
|
23
|
+
declare const listAvailableVersions: () => Promise<ReleaseCatalog>;
|
|
24
|
+
declare const upgradeSelf: (input: boolean | UpgradeSelfOptions) => Promise<UpgradeEnvelope>;
|
|
6
25
|
declare const uninstallSelf: (dryRun: boolean) => Promise<{
|
|
7
26
|
executablePath: string;
|
|
8
27
|
scheduled: boolean;
|
|
9
28
|
dryRun: boolean;
|
|
10
29
|
}>;
|
|
30
|
+
declare const validateNativeBinary: (bytes: Uint8Array, os: UpgradePlan['os']) => void;
|
|
11
31
|
//# sourceMappingURL=self-management.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"self-management.d.ts","sourceRoot":"","sources":["../source/self-management.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"self-management.d.ts","sourceRoot":"","sources":["../source/self-management.ts"],"names":[],"mappings":"AAAA;;GAEG;AAUH,OAAO,KAAK,EAAE,cAAc,EAA6C,eAAe,EAAkC,YAAY,EAAgB,WAAW,EAAiB,MAAM,oBAAoB,CAAA;AAC5M,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAE9C,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,aAAa,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAA;AAEzG,MAAM,MAAM,qBAAqB,GAAG;IAClC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACvC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAChD,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,MAAM,EAAE,OAAO,CAAA;IACf,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;IAC1B,OAAO,CAAC,EAAE,OAAO,oBAAoB,EAAE,cAAc,CAAA;IACrD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,IAAI,CAAA;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAA;IACvC,cAAc,CAAC,EAAE,qBAAqB,CAAA;CACvC,CAAA;AAuCD,QAAA,MAAM,qBAAqB,QAAa,OAAO,CAAC,YAAY,CAS3D,CAAA;AAED,QAAA,MAAM,qBAAqB,QAAa,OAAO,CAAC,cAAc,CAG7D,CAAA;AAED,QAAA,MAAM,WAAW,UAAiB,OAAO,GAAG,kBAAkB,KAAG,OAAO,CAAC,eAAe,CA4IvF,CAAA;AAED,QAAA,MAAM,aAAa,WAAkB,OAAO,KAAG,OAAO,CAAC;IAAE,cAAc,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,OAAO,CAAA;CAAE,CAWrH,CAAA;AAkFD,QAAA,MAAM,oBAAoB,UAAW,UAAU,MAAM,WAAW,CAAC,IAAI,CAAC,KAAG,IAOxE,CAAA"}
|