@vascend/talos 0.1.0 → 0.1.1
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 +7 -3
- package/dist/backend/asset-events.js +9 -9
- package/dist/core/agent.js +3 -3
- package/dist/core/cli-args.js +50 -50
- package/dist/core/cli-installation.d.ts +4 -0
- package/dist/core/cli-installation.js +55 -0
- package/dist/core/compaction.js +26 -26
- package/dist/core/config.js +101 -101
- package/dist/core/execution-guidance.js +21 -21
- package/dist/core/package-update.d.ts +3 -1
- package/dist/core/package-update.js +19 -6
- package/dist/core/self-update.d.ts +1 -1
- package/dist/core/signed-release.d.ts +33 -0
- package/dist/core/signed-release.js +121 -0
- package/dist/core/update-check.d.ts +1 -1
- package/dist/core/update-check.js +15 -14
- package/dist/core/vibe-modes.js +13 -13
- package/dist/distribution/install.d.ts +1 -0
- package/dist/distribution/install.js +31 -0
- package/dist/install.mjs +271 -0
- package/dist/node-runtime.json +13 -0
- package/dist/providers/oauth-callback-server.js +32 -32
- package/dist/tools/capabilities.js +30 -30
- package/dist/tools/computer-capture.js +50 -50
- package/dist/tools/program.js +82 -82
- package/dist/tui/i18n-catalog.js +16 -0
- package/dist/tui/quick-help.js +31 -31
- package/dist/tui/repl.js +5 -5
- package/dist/tui/update-prompt.js +1 -0
- package/dist/vascend/code-events.js +9 -9
- package/dist/vascend/completeness.js +31 -31
- package/dist/vascend/context-fabric.js +16 -16
- package/dist/vascend/contract-memory.js +30 -30
- package/dist/vascend/council.js +82 -82
- package/dist/vascend/decision-promotion.js +23 -23
- package/dist/vascend/granular-kingdom.js +17 -17
- package/dist/vascend/granular-launcher.js +2 -2
- package/dist/vascend/kingdom-kpi.js +19 -19
- package/dist/vascend/kingdom-run.js +6 -6
- package/dist/vascend/kingdom.js +56 -56
- package/dist/vascend/mandate.js +21 -21
- package/dist/vascend/objective-revision.js +34 -34
- package/dist/vascend/patch-plan.js +22 -22
- package/dist/vascend/requirements.js +29 -29
- package/dist/vascend/reviewer.js +26 -26
- package/dist/vascend/room-memory.js +25 -25
- package/dist/vascend/runtime.js +44 -44
- package/dist/vascend/self-improve.js +39 -39
- package/dist/vascend/test-failure-memory.js +9 -9
- package/dist/vascend/vision.js +18 -18
- package/dist/vendor/computer-use/README.md +7 -7
- package/dist/vendor/computer-use/computer-desktop.js +211 -211
- package/dist/vendor/computer-use/computer-observe.js +315 -315
- package/dist/vendor/computer-use/computer-scripts.js +1230 -1230
- package/dist/vendor/computer-use/computer-tools.js +2136 -2136
- package/dist/vendor/computer-use/package.json +1 -1
- package/dist/vendor/computer-use/rac/atomic-input.js +91 -91
- package/dist/vendor/computer-use/rac/grammatica.js +101 -101
- package/dist/vendor/computer-use/rac/parser.js +185 -185
- package/dist/vendor/computer-use/rac/protocol.js +136 -136
- package/install.ps1 +374 -30
- package/install.sh +356 -43
- package/package.json +2 -2
- package/dist/core/kingdoms-mode-state.d.ts +0 -24
- package/dist/core/kingdoms-mode-state.js +0 -139
- package/dist/text-sanitize.js +0 -28
package/install.ps1
CHANGED
|
@@ -1,30 +1,374 @@
|
|
|
1
|
-
# Public entry
|
|
2
|
-
& {
|
|
3
|
-
$ErrorActionPreference = 'Stop'
|
|
4
|
-
$
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
15
|
-
$
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
if ($
|
|
22
|
-
if ($
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
# Generated by scripts/build-installers.mjs. Public entry: https://vascend.it/install.ps1
|
|
2
|
+
& {
|
|
3
|
+
$ErrorActionPreference = 'Stop'
|
|
4
|
+
$script:talosRuntimeBin = $null
|
|
5
|
+
function Initialize-TalosNode {
|
|
6
|
+
$existing = Get-Command node.exe -ErrorAction SilentlyContinue
|
|
7
|
+
$npm = Get-Command npm.cmd -ErrorAction SilentlyContinue
|
|
8
|
+
if ($env:TALOS_FORCE_BUNDLED_NODE -ne '1' -and $existing -and $npm) {
|
|
9
|
+
& $existing.Source -e 'process.exit(Number(process.versions.node.split(String.fromCharCode(46))[0]) >= 22 ? 0 : 1)' 2>$null
|
|
10
|
+
if ($LASTEXITCODE -eq 0) {
|
|
11
|
+
& $npm.Source --version *> $null
|
|
12
|
+
if ($LASTEXITCODE -eq 0) { return $existing.Source }
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
$architecture = if ($env:PROCESSOR_ARCHITEW6432) { $env:PROCESSOR_ARCHITEW6432 } else { $env:PROCESSOR_ARCHITECTURE }
|
|
16
|
+
switch ($architecture) {
|
|
17
|
+
'ARM64' { $platform = 'win-arm64'; $digest = '8779b1bde1d39f8d420e3b57aa657b39891af434d3de44a919044cec06785921' }
|
|
18
|
+
'AMD64' { $platform = 'win-x64'; $digest = '158f7685b44de51f6c0df1d153526cbcd3e1bc739a8dfc607721cef75de9e541' }
|
|
19
|
+
default { throw 'Talos requires 64-bit Windows (x64 or ARM64).' }
|
|
20
|
+
}
|
|
21
|
+
$runtimeBase = if ($env:TALOS_RUNTIME_DIR) { $env:TALOS_RUNTIME_DIR } else { Join-Path $env:LOCALAPPDATA 'Vascend\runtime' }
|
|
22
|
+
if ($runtimeBase -match '[;\x00-\x1f\x7f]') { throw 'Invalid Node runtime directory.' }
|
|
23
|
+
if (-not [IO.Path]::IsPathRooted($runtimeBase)) { $runtimeBase = Join-Path (Get-Location).Path $runtimeBase }
|
|
24
|
+
$runtimeBase = [IO.Path]::GetFullPath($runtimeBase)
|
|
25
|
+
$runtime = Join-Path $runtimeBase "node-v24.21.0-$platform"
|
|
26
|
+
if (-not (Test-Path -LiteralPath $runtime)) {
|
|
27
|
+
New-Item -ItemType Directory -Force -Path $runtimeBase | Out-Null
|
|
28
|
+
$stage = Join-Path $runtimeBase ('.node-download-' + [Guid]::NewGuid().ToString('N'))
|
|
29
|
+
New-Item -ItemType Directory -Path $stage | Out-Null
|
|
30
|
+
try {
|
|
31
|
+
Write-Host 'Installing Node.js 24.21.0 with npm for Talos...'
|
|
32
|
+
$archive = Join-Path $stage 'node.zip'
|
|
33
|
+
[Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
|
|
34
|
+
Invoke-WebRequest -UseBasicParsing -MaximumRedirection 0 -TimeoutSec 300 -Uri "https://nodejs.org/dist/v24.21.0/node-v24.21.0-$platform.zip" -OutFile $archive
|
|
35
|
+
if ((Get-FileHash -LiteralPath $archive -Algorithm SHA256).Hash.ToLowerInvariant() -ne $digest) { throw 'Node checksum mismatch. Installation refused.' }
|
|
36
|
+
Expand-Archive -LiteralPath $archive -DestinationPath $stage
|
|
37
|
+
if (Test-Path -LiteralPath $runtime) { throw 'The Node runtime already exists. Run the installer again.' }
|
|
38
|
+
$expanded = Join-Path $stage "node-v24.21.0-$platform"
|
|
39
|
+
if (-not ([IO.Path]::GetFullPath($expanded)).StartsWith($stage + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Invalid runtime source.' }
|
|
40
|
+
if (-not $runtime.StartsWith($runtimeBase + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Invalid runtime destination.' }
|
|
41
|
+
Move-Item -LiteralPath $expanded -Destination $runtime
|
|
42
|
+
} finally {
|
|
43
|
+
$resolvedStage = [IO.Path]::GetFullPath($stage)
|
|
44
|
+
if (-not $resolvedStage.StartsWith($runtimeBase + [IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Invalid temporary runtime directory.' }
|
|
45
|
+
Remove-Item -LiteralPath $resolvedStage -Recurse -Force
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
$script:talosRuntimeBin = $runtime
|
|
49
|
+
$env:Path = "$runtime;$env:Path"
|
|
50
|
+
$executable = Join-Path $runtime 'node.exe'
|
|
51
|
+
$reported = & $executable --version
|
|
52
|
+
if ($LASTEXITCODE -ne 0 -or $reported -ne 'v24.21.0' -or -not (Test-Path -LiteralPath (Join-Path $runtime 'node_modules\npm\bin\npm-cli.js'))) { throw 'The managed Node runtime is incomplete.' }
|
|
53
|
+
return $executable
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function Merge-TalosPath([string]$ExistingPath, [string[]]$Directories) {
|
|
57
|
+
$paths = [Collections.Generic.List[string]]::new()
|
|
58
|
+
$seen = [Collections.Generic.HashSet[string]]::new([StringComparer]::OrdinalIgnoreCase)
|
|
59
|
+
foreach ($directory in @($Directories) + @($ExistingPath -split ';')) {
|
|
60
|
+
if ($directory -and $seen.Add($directory.TrimEnd('\', '/'))) { $paths.Add($directory) }
|
|
61
|
+
}
|
|
62
|
+
return $paths -join ';'
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function Update-TalosPath([string]$Prefix, [string]$RuntimeBin) {
|
|
66
|
+
$directories = @($Prefix, $RuntimeBin) | Where-Object { $_ }
|
|
67
|
+
$env:Path = Merge-TalosPath $env:Path $directories
|
|
68
|
+
if ($env:TALOS_NO_MODIFY_PATH -eq '1') { return }
|
|
69
|
+
$before = [Environment]::GetEnvironmentVariable('Path', 'User')
|
|
70
|
+
$after = Merge-TalosPath $before $directories
|
|
71
|
+
if ($after -eq $before) { return }
|
|
72
|
+
[Environment]::SetEnvironmentVariable('Path', $after, 'User')
|
|
73
|
+
# Inform Explorer so newly opened terminals can inherit the updated PATH.
|
|
74
|
+
try {
|
|
75
|
+
if (-not ('TalosInstaller.EnvironmentNotification' -as [type])) {
|
|
76
|
+
Add-Type -TypeDefinition @'
|
|
77
|
+
using System;
|
|
78
|
+
using System.Runtime.InteropServices;
|
|
79
|
+
namespace TalosInstaller {
|
|
80
|
+
public static class EnvironmentNotification {
|
|
81
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
|
82
|
+
public static extern IntPtr SendMessageTimeout(IntPtr window, uint message, IntPtr wParam,
|
|
83
|
+
string lParam, uint flags, uint timeout, out IntPtr result);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
'@
|
|
87
|
+
}
|
|
88
|
+
$result = [IntPtr]::Zero
|
|
89
|
+
[void][TalosInstaller.EnvironmentNotification]::SendMessageTimeout([IntPtr]0xffff, 0x1a, [IntPtr]::Zero, 'Environment', 2, 1000, [ref]$result)
|
|
90
|
+
} catch { Write-Host 'PATH saved. Restart your terminal application if it still has the old environment.' }
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
$talosNode = Initialize-TalosNode
|
|
94
|
+
$env:TALOS_INSTALL_DIR = & $talosNode -p "require('node:path').resolve(process.env.TALOS_INSTALL_DIR || require('node:path').join(process.env.LOCALAPPDATA, 'Programs', 'Talos'))"
|
|
95
|
+
if ($LASTEXITCODE -ne 0) { throw 'Unable to resolve the Talos installation directory.' }
|
|
96
|
+
$talosInstaller = @'
|
|
97
|
+
// src/distribution/install.ts
|
|
98
|
+
import { join as join4 } from "node:path";
|
|
99
|
+
import { homedir } from "node:os";
|
|
100
|
+
|
|
101
|
+
// src/core/signed-release.ts
|
|
102
|
+
import { createHash, createPublicKey, verify } from "node:crypto";
|
|
103
|
+
import { mkdtemp, rm, writeFile } from "node:fs/promises";
|
|
104
|
+
import { tmpdir } from "node:os";
|
|
105
|
+
import { join } from "node:path";
|
|
106
|
+
var TALOS_DOWNLOAD_ORIGIN = "https://vascend.it";
|
|
107
|
+
var STABLE_VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
108
|
+
function stableVersion(value) {
|
|
109
|
+
return typeof value === "string" && value.length <= 40 && STABLE_VERSION.exec(value)?.[0] === value;
|
|
110
|
+
}
|
|
111
|
+
function verifyRelease(bytes, registryKeys, options = {}) {
|
|
112
|
+
if (bytes.length > 64 * 1024)
|
|
113
|
+
throw new Error("Release metadata is too large.");
|
|
114
|
+
const data = JSON.parse(Buffer.from(bytes).toString("utf8"));
|
|
115
|
+
if (!data || data.name !== "@vascend/talos" || !stableVersion(data.version) || options.version !== undefined && data.version !== options.version)
|
|
116
|
+
throw new Error("Unexpected release version.");
|
|
117
|
+
if (typeof data.dist?.integrity !== "string" || !/^sha512-[A-Za-z0-9+/]{86}==$/.test(data.dist.integrity) || data.dist.integrity.length !== 95 || !Array.isArray(data.dist.signatures) || data.dist.signatures.length > 10)
|
|
118
|
+
throw new Error("Invalid npm release signature.");
|
|
119
|
+
const keys = registryKeys?.keys;
|
|
120
|
+
if (!Array.isArray(keys) || keys.length > 30)
|
|
121
|
+
throw new Error("Invalid npm signing keys.");
|
|
122
|
+
const payload = Buffer.from(`${data.name}@${data.version}:${data.dist.integrity}`);
|
|
123
|
+
for (const signature of data.dist.signatures) {
|
|
124
|
+
if (typeof signature?.sig !== "string" || signature.sig.length > 256 || typeof signature.keyid !== "string")
|
|
125
|
+
continue;
|
|
126
|
+
for (const trusted of keys) {
|
|
127
|
+
if (!trusted || trusted.keyid !== signature.keyid || trusted.keytype !== "ecdsa-sha2-nistp256" || trusted.scheme !== "ecdsa-sha2-nistp256" || typeof trusted.key !== "string" || trusted.key.length > 512 || trusted.expires !== null && !(Date.parse(trusted.expires) > (options.now ?? Date.now())))
|
|
128
|
+
continue;
|
|
129
|
+
try {
|
|
130
|
+
const key = createPublicKey({ key: Buffer.from(trusted.key, "base64"), format: "der", type: "spki" });
|
|
131
|
+
if (key.asymmetricKeyType === "ec" && key.asymmetricKeyDetails?.namedCurve === "prime256v1" && verify("sha256", payload, key, Buffer.from(signature.sig, "base64")))
|
|
132
|
+
return data;
|
|
133
|
+
} catch {}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw new Error("The npm registry signature is invalid.");
|
|
137
|
+
}
|
|
138
|
+
function verifyPackage(bytes, release) {
|
|
139
|
+
if (`sha512-${createHash("sha512").update(bytes).digest("base64")}` !== release.dist.integrity) {
|
|
140
|
+
throw new Error("Release checksum does not match. Installation refused.");
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function fetchReleaseBytes(url, limit, options = {}) {
|
|
144
|
+
const controller = new AbortController;
|
|
145
|
+
const timer = setTimeout(() => controller.abort(), options.timeoutMs ?? 20000);
|
|
146
|
+
try {
|
|
147
|
+
const response = await (options.fetch ?? fetch)(url, { redirect: "error", signal: controller.signal, headers: { Accept: "application/octet-stream" } });
|
|
148
|
+
if (!response.ok || !response.body) {
|
|
149
|
+
await response.body?.cancel();
|
|
150
|
+
throw new Error("Release download is unavailable.");
|
|
151
|
+
}
|
|
152
|
+
if (Number(response.headers.get("content-length")) > limit) {
|
|
153
|
+
await response.body.cancel();
|
|
154
|
+
throw new Error("Release download is too large.");
|
|
155
|
+
}
|
|
156
|
+
const reader = response.body.getReader();
|
|
157
|
+
const chunks = [];
|
|
158
|
+
let length = 0;
|
|
159
|
+
try {
|
|
160
|
+
for (;; ) {
|
|
161
|
+
const { done, value } = await reader.read();
|
|
162
|
+
if (done)
|
|
163
|
+
break;
|
|
164
|
+
length += value.length;
|
|
165
|
+
if (length > limit)
|
|
166
|
+
throw new Error("Release download is too large.");
|
|
167
|
+
chunks.push(value);
|
|
168
|
+
}
|
|
169
|
+
} finally {
|
|
170
|
+
await reader.cancel();
|
|
171
|
+
}
|
|
172
|
+
return Buffer.concat(chunks);
|
|
173
|
+
} finally {
|
|
174
|
+
clearTimeout(timer);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
async function fetchSignedRelease(version = "latest", options = {}) {
|
|
178
|
+
if (version !== "latest" && !stableVersion(version))
|
|
179
|
+
throw new Error("Invalid Talos version.");
|
|
180
|
+
const [metadata, keys] = await Promise.all([
|
|
181
|
+
fetchReleaseBytes(`https://registry.npmjs.org/@vascend%2ftalos/${version}`, 64 * 1024, options),
|
|
182
|
+
fetchReleaseBytes("https://registry.npmjs.org/-/npm/v1/keys", 64 * 1024, options)
|
|
183
|
+
]);
|
|
184
|
+
return verifyRelease(metadata, JSON.parse(keys.toString("utf8")), version === "latest" ? {} : { version });
|
|
185
|
+
}
|
|
186
|
+
async function downloadVerifiedPackage(version, options = {}) {
|
|
187
|
+
const release = await fetchSignedRelease(version, options);
|
|
188
|
+
const filename = `vascend-talos-${release.version}.tgz`;
|
|
189
|
+
let bytes;
|
|
190
|
+
try {
|
|
191
|
+
bytes = await fetchReleaseBytes(`${TALOS_DOWNLOAD_ORIGIN}/talos/releases/${release.version}/${filename}`, 32 * 1024 * 1024, options);
|
|
192
|
+
verifyPackage(bytes, release);
|
|
193
|
+
} catch {
|
|
194
|
+
bytes = await fetchReleaseBytes(`https://registry.npmjs.org/@vascend/talos/-/talos-${release.version}.tgz`, 32 * 1024 * 1024, options);
|
|
195
|
+
verifyPackage(bytes, release);
|
|
196
|
+
}
|
|
197
|
+
const directory = await mkdtemp(join(tmpdir(), "talos-verified-"));
|
|
198
|
+
const dispose = () => rm(directory, { recursive: true, force: true });
|
|
199
|
+
try {
|
|
200
|
+
const path = join(directory, filename);
|
|
201
|
+
await writeFile(path, bytes, { flag: "wx", mode: 384 });
|
|
202
|
+
return { path, dispose };
|
|
203
|
+
} catch (error) {
|
|
204
|
+
await dispose();
|
|
205
|
+
throw error;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// src/core/package-update.ts
|
|
210
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2, realpathSync as realpathSync2 } from "node:fs";
|
|
211
|
+
import { delimiter, dirname as dirname2, join as join3 } from "node:path";
|
|
212
|
+
|
|
213
|
+
// src/core/update-process.ts
|
|
214
|
+
import { spawn } from "node:child_process";
|
|
215
|
+
var runUpdateCommand = (command) => new Promise((resolve, reject) => {
|
|
216
|
+
const child = spawn(command.command, [...command.args], {
|
|
217
|
+
cwd: command.cwd,
|
|
218
|
+
env: command.env,
|
|
219
|
+
shell: false,
|
|
220
|
+
windowsHide: true,
|
|
221
|
+
stdio: command.inherit ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
222
|
+
timeout: command.timeoutMs
|
|
223
|
+
});
|
|
224
|
+
let output = "";
|
|
225
|
+
let failed = false;
|
|
226
|
+
const collect = (data) => {
|
|
227
|
+
output += data.toString();
|
|
228
|
+
if (output.length > 2000000) {
|
|
229
|
+
failed = true;
|
|
230
|
+
child.kill();
|
|
231
|
+
reject(new Error("Command output exceeded limit"));
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
child.stdout?.on("data", collect);
|
|
235
|
+
child.stderr?.resume();
|
|
236
|
+
child.on("error", reject);
|
|
237
|
+
child.on("close", (code, signal) => {
|
|
238
|
+
if (failed)
|
|
239
|
+
return;
|
|
240
|
+
if (code === 0 && !signal)
|
|
241
|
+
resolve(output.trim());
|
|
242
|
+
else
|
|
243
|
+
reject(new Error(`${command.command} exited with ${signal ?? code}`));
|
|
244
|
+
});
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
// src/core/cli-installation.ts
|
|
248
|
+
import { existsSync, lstatSync, readFileSync, realpathSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
|
|
249
|
+
import { dirname, join as join2, resolve } from "node:path";
|
|
250
|
+
function installationPrefix(value) {
|
|
251
|
+
const prefix = resolve(value);
|
|
252
|
+
if (/[\x00-\x1f\x7f]/.test(prefix) || prefix.includes(process.platform === "win32" ? ";" : ":")) {
|
|
253
|
+
throw new Error("The installation directory cannot be represented safely in PATH.");
|
|
254
|
+
}
|
|
255
|
+
return prefix;
|
|
256
|
+
}
|
|
257
|
+
function windowsCliShim() {
|
|
258
|
+
return `@echo off\r
|
|
259
|
+
"%~dp0.talos-runtime\\node.exe" "%~dp0node_modules\\@vascend\\talos\\dist\\index.js" %*\r
|
|
260
|
+
`;
|
|
261
|
+
}
|
|
262
|
+
function finalizeCliInstallation(root, version) {
|
|
263
|
+
const pkg = JSON.parse(readFileSync(join2(root, "package.json"), "utf8"));
|
|
264
|
+
if (pkg.name !== "@vascend/talos" || pkg.version !== version)
|
|
265
|
+
throw new Error("Installed Talos version differs from the requested release.");
|
|
266
|
+
if (process.platform !== "win32")
|
|
267
|
+
return;
|
|
268
|
+
const modules = dirname(dirname(root));
|
|
269
|
+
if (dirname(root).split(/[\\/]/).pop() !== "@vascend" || modules.split(/[\\/]/).pop() !== "node_modules")
|
|
270
|
+
return;
|
|
271
|
+
const prefix = dirname(modules);
|
|
272
|
+
const belongsToTalos = (file) => {
|
|
273
|
+
if (!existsSync(file))
|
|
274
|
+
return false;
|
|
275
|
+
const info = lstatSync(file);
|
|
276
|
+
return info.isFile() && !info.isSymbolicLink() && info.size < 16384 && /node_modules[\\/]@vascend[\\/]talos[\\/]dist[\\/]index\.js/i.test(readFileSync(file, "utf8"));
|
|
277
|
+
};
|
|
278
|
+
for (const alias of ["talos", "horizon"]) {
|
|
279
|
+
const cmd = join2(prefix, `${alias}.cmd`);
|
|
280
|
+
if (!belongsToTalos(cmd))
|
|
281
|
+
continue;
|
|
282
|
+
if (!process.versions.bun) {
|
|
283
|
+
const runtime = join2(prefix, ".talos-runtime");
|
|
284
|
+
if (existsSync(runtime)) {
|
|
285
|
+
if (!lstatSync(runtime).isSymbolicLink())
|
|
286
|
+
throw new Error("The Talos runtime link is occupied by a regular directory.");
|
|
287
|
+
if (realpathSync(runtime).toLowerCase() !== realpathSync(dirname(process.execPath)).toLowerCase())
|
|
288
|
+
unlinkSync(runtime);
|
|
289
|
+
}
|
|
290
|
+
if (!existsSync(runtime))
|
|
291
|
+
symlinkSync(dirname(process.execPath), runtime, "junction");
|
|
292
|
+
writeFileSync(cmd, windowsCliShim());
|
|
293
|
+
}
|
|
294
|
+
const ps1 = join2(prefix, `${alias}.ps1`);
|
|
295
|
+
if (belongsToTalos(ps1))
|
|
296
|
+
unlinkSync(ps1);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// src/core/package-update.ts
|
|
301
|
+
var REGISTRY = "https://registry.npmjs.org";
|
|
302
|
+
function managerCommand(manager, env) {
|
|
303
|
+
if (process.platform !== "win32")
|
|
304
|
+
return { command: manager, args: [] };
|
|
305
|
+
const path = Object.entries(env).find(([key]) => key.toLowerCase() === "path")?.[1] ?? "";
|
|
306
|
+
const directories = path.split(delimiter).filter(Boolean).map((directory) => directory.replace(/^"|"$/g, ""));
|
|
307
|
+
const node = process.versions.bun ? directories.map((directory) => join3(directory, "node.exe")).find((file) => existsSync2(file)) : process.execPath;
|
|
308
|
+
for (const directory of directories) {
|
|
309
|
+
const exe = join3(directory, `${manager}.exe`);
|
|
310
|
+
if (existsSync2(exe))
|
|
311
|
+
return { command: exe, args: [] };
|
|
312
|
+
const scripts = {
|
|
313
|
+
npm: ["npm/bin/npm-cli.js"],
|
|
314
|
+
pnpm: ["pnpm/bin/pnpm.cjs", "corepack/dist/pnpm.js"],
|
|
315
|
+
yarn: ["yarn/bin/yarn.js", "corepack/dist/yarn.js"]
|
|
316
|
+
};
|
|
317
|
+
if (manager !== "bun")
|
|
318
|
+
for (const script of scripts[manager]) {
|
|
319
|
+
const file = join3(directory, "node_modules", script);
|
|
320
|
+
if (node && existsSync2(file))
|
|
321
|
+
return { command: node, args: [file] };
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
return null;
|
|
325
|
+
}
|
|
326
|
+
function packageUpdateArgs(manager, target, prefix) {
|
|
327
|
+
const security = ["--ignore-scripts", `--registry=${REGISTRY}`];
|
|
328
|
+
if (manager === "npm")
|
|
329
|
+
return ["install", "--global", target, ...security, "--no-audit", "--no-fund", ...prefix ? ["--prefix", prefix] : []];
|
|
330
|
+
if (manager === "yarn")
|
|
331
|
+
return ["global", "add", target, ...security];
|
|
332
|
+
return ["add", "--global", target, ...security];
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// src/distribution/install.ts
|
|
336
|
+
async function install() {
|
|
337
|
+
if (Number(process.versions.node.split(".")[0]) < 20)
|
|
338
|
+
throw new Error("Talos requires Node.js 20 or newer, including npm: https://nodejs.org");
|
|
339
|
+
const npm = managerCommand("npm", process.env);
|
|
340
|
+
if (!npm)
|
|
341
|
+
throw new Error("npm is missing. Install Node.js with npm from https://nodejs.org");
|
|
342
|
+
const version = process.env.TALOS_VERSION || "latest";
|
|
343
|
+
const release = await fetchSignedRelease(version);
|
|
344
|
+
const prefix = installationPrefix(process.env.TALOS_INSTALL_DIR || (process.platform === "win32" ? join4(process.env.LOCALAPPDATA || join4(homedir(), "AppData", "Local"), "Programs", "Talos") : join4(homedir(), ".local")));
|
|
345
|
+
console.log(`Installing Talos ${release.version} in ${prefix}`);
|
|
346
|
+
const artifact = await downloadVerifiedPackage(release.version);
|
|
347
|
+
try {
|
|
348
|
+
await runUpdateCommand({
|
|
349
|
+
...npm,
|
|
350
|
+
args: [...npm.args, ...packageUpdateArgs("npm", artifact.path, prefix)],
|
|
351
|
+
cwd: homedir(),
|
|
352
|
+
env: process.env,
|
|
353
|
+
inherit: true,
|
|
354
|
+
timeoutMs: 300000
|
|
355
|
+
});
|
|
356
|
+
const entry = join4(prefix, ...process.platform === "win32" ? [] : ["lib"], "node_modules", "@vascend", "talos", "dist", "index.js");
|
|
357
|
+
finalizeCliInstallation(join4(prefix, ...process.platform === "win32" ? [] : ["lib"], "node_modules", "@vascend", "talos"), release.version);
|
|
358
|
+
await runUpdateCommand({ command: process.execPath, args: [entry, "--version"], cwd: homedir(), env: process.env, inherit: true, timeoutMs: 1e4 });
|
|
359
|
+
console.log("Talos installed. npm registry signature and SHA-512 verified.");
|
|
360
|
+
} finally {
|
|
361
|
+
await artifact.dispose();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
install().catch((error) => {
|
|
365
|
+
console.error(error instanceof Error ? error.message : "Installation failed.");
|
|
366
|
+
process.exitCode = 1;
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
'@
|
|
370
|
+
$talosInstaller | & $talosNode --input-type=module -
|
|
371
|
+
if ($LASTEXITCODE -ne 0) { throw 'Talos installation failed. See the error above.' }
|
|
372
|
+
Update-TalosPath $env:TALOS_INSTALL_DIR $script:talosRuntimeBin
|
|
373
|
+
Write-Host 'Talos is ready. Run talos to sign in.'
|
|
374
|
+
}
|