@rightkit/release 0.2.118 → 0.2.120
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/development.mjs +8 -2
- package/direct-bootstrap.mjs +12 -0
- package/package.json +1 -1
- package/portable-development.mjs +56 -0
- package/rightkit-versions.json +16 -11
package/development.mjs
CHANGED
|
@@ -34,6 +34,10 @@ export function developmentEnvironment(env = process.env) {
|
|
|
34
34
|
const pathKey = Object.keys(result).find((key) => key.toLowerCase() === "path") ?? "PATH";
|
|
35
35
|
result[pathKey] = [agentBin, result[pathKey]].filter(Boolean).join(path.delimiter);
|
|
36
36
|
}
|
|
37
|
+
// Same default as the agent-bin `rightkit` shim: children that run the managed client directly
|
|
38
|
+
// (resolveCommand("rightkit"), build scripts) must not lose the broker endpoint.
|
|
39
|
+
const socket = managedRoot && path.join(managedRoot, "broker.sock");
|
|
40
|
+
if (!result.RIGHTKIT_BUILD_BROKER_SOCKET && socket && existsSync(socket)) result.RIGHTKIT_BUILD_BROKER_SOCKET = socket;
|
|
37
41
|
}
|
|
38
42
|
return result;
|
|
39
43
|
}
|
|
@@ -196,7 +200,7 @@ function execute(command, { root, env, dryRun, run, label }) {
|
|
|
196
200
|
const args = (command.args ?? []).map(String);
|
|
197
201
|
if (dryRun) return { cmd: command.cmd, args, cwd };
|
|
198
202
|
const launch = resolveCommand(command.cmd, args, { root, env });
|
|
199
|
-
const result = run(launch.command, launch.args, { cwd, env, stdio: "inherit", windowsHide: true, shell: false, timeout: command.timeoutMs });
|
|
203
|
+
const result = run(launch.command, launch.args, { cwd, env: launch.env ?? env, stdio: "inherit", windowsHide: true, shell: false, timeout: command.timeoutMs });
|
|
200
204
|
if (result.status !== 0) throw new Error(`development ${label} command failed (${result.status}): ${command.name ?? command.cmd}`);
|
|
201
205
|
}
|
|
202
206
|
export function resolveCommand(command, args, { root, env = process.env } = {}) {
|
|
@@ -205,7 +209,9 @@ export function resolveCommand(command, args, { root, env = process.env } = {})
|
|
|
205
209
|
if (command === "rightkit") {
|
|
206
210
|
const client = managedRuntimeClient(env);
|
|
207
211
|
if (!client) throw new Error("installed RightKit runtime client is unavailable for development command");
|
|
208
|
-
|
|
212
|
+
const socket = path.join(path.dirname(path.dirname(path.dirname(path.dirname(client)))), "broker.sock");
|
|
213
|
+
const childEnv = !env.RIGHTKIT_BUILD_BROKER_SOCKET && existsSync(socket) ? { ...env, RIGHTKIT_BUILD_BROKER_SOCKET: socket } : undefined;
|
|
214
|
+
return { command: process.execPath, args: [client, ...args], ...(childEnv ? { env: childEnv } : {}) };
|
|
209
215
|
}
|
|
210
216
|
return { command, args };
|
|
211
217
|
}
|
package/direct-bootstrap.mjs
CHANGED
|
@@ -353,6 +353,10 @@ function Invoke-BoundedExe($Path, [string[]]$Arguments, [int]$TimeoutSeconds) {
|
|
|
353
353
|
"$ReleaseBase = if ($Version) { " + psQuote("https://github.com/" + repository + "/releases/download/v") + " + $Version } else { $null }",
|
|
354
354
|
"$Work = Join-Path ([IO.Path]::GetTempPath()) (" + psQuote(product + "-install-") + " + [guid]::NewGuid())",
|
|
355
355
|
"New-Item -ItemType Directory -Force -Path $Work | Out-Null",
|
|
356
|
+
// Early failures (download, catalog, checksum, preflight) throw before the activation
|
|
357
|
+
// try/finally; the trap removes $Work for them, and stale dirs from older bootstraps are swept.
|
|
358
|
+
"trap { try { if ($Work -and (Test-Path -LiteralPath $Work)) { Remove-Item -LiteralPath $Work -Recurse -Force -ErrorAction SilentlyContinue } } catch {}; break }",
|
|
359
|
+
"Get-ChildItem ([IO.Path]::GetTempPath()) -Directory -Filter " + psQuote(product + "-install-*") + " -ErrorAction SilentlyContinue | Where-Object { $_.FullName -ne $Work -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } | ForEach-Object { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction SilentlyContinue }",
|
|
356
360
|
"$ManifestPath = Join-Path $Work 'release-manifest.json'; $SignaturePath = Join-Path $Work 'release-manifest.cat'; $ChecksumsPath = Join-Path $Work 'checksums.json'",
|
|
357
361
|
"function Receive-ReleaseFile([string]$Name, [string]$Destination) { if ($LocalReleaseRoot) { $RootPrefix = $LocalReleaseRoot.TrimEnd([IO.Path]::DirectorySeparatorChar, [IO.Path]::AltDirectorySeparatorChar) + [IO.Path]::DirectorySeparatorChar; $Source = [IO.Path]::GetFullPath((Join-Path $LocalReleaseRoot $Name)); if (-not $Source.StartsWith($RootPrefix, [StringComparison]::OrdinalIgnoreCase) -or -not (Test-Path -LiteralPath $Source -PathType Leaf)) { throw ('Local release asset is missing or escapes root: ' + $Name) }; Copy-Item -LiteralPath $Source -Destination $Destination } else { Invoke-WebRequest ($ReleaseBase + '/' + $Name) -OutFile $Destination } }",
|
|
358
362
|
"Receive-ReleaseFile 'release-manifest.json' $ManifestPath",
|
|
@@ -367,6 +371,10 @@ function Invoke-BoundedExe($Path, [string[]]$Arguments, [int]$TimeoutSeconds) {
|
|
|
367
371
|
"$ReleaseBase = " + psQuote("https://github.com/" + repository + "/releases/download/v") + " + $Version",
|
|
368
372
|
"$Work = Join-Path ([IO.Path]::GetTempPath()) (" + psQuote(product + "-install-") + " + [guid]::NewGuid())",
|
|
369
373
|
"New-Item -ItemType Directory -Force -Path $Work | Out-Null",
|
|
374
|
+
// Early failures (download, catalog, checksum, preflight) throw before the activation
|
|
375
|
+
// try/finally; the trap removes $Work for them, and stale dirs from older bootstraps are swept.
|
|
376
|
+
"trap { try { if ($Work -and (Test-Path -LiteralPath $Work)) { Remove-Item -LiteralPath $Work -Recurse -Force -ErrorAction SilentlyContinue } } catch {}; break }",
|
|
377
|
+
"Get-ChildItem ([IO.Path]::GetTempPath()) -Directory -Filter " + psQuote(product + "-install-*") + " -ErrorAction SilentlyContinue | Where-Object { $_.FullName -ne $Work -and $_.LastWriteTime -lt (Get-Date).AddDays(-1) } | ForEach-Object { Remove-Item -LiteralPath $_.FullName -Recurse -Force -ErrorAction SilentlyContinue }",
|
|
370
378
|
"$ManifestPath = Join-Path $Work 'release-manifest.json'; $SignaturePath = Join-Path $Work 'release-manifest.cat'; $ChecksumsPath = Join-Path $Work 'checksums.json'",
|
|
371
379
|
"Invoke-WebRequest ($ReleaseBase + '/release-manifest.json') -OutFile $ManifestPath",
|
|
372
380
|
"Invoke-WebRequest ($ReleaseBase + '/release-manifest.cat') -OutFile $SignaturePath",
|
|
@@ -440,6 +448,10 @@ function Invoke-BoundedExe($Path, [string[]]$Arguments, [int]$TimeoutSeconds) {
|
|
|
440
448
|
" $StableBin = Split-Path $StableExe -Parent; $InstallRootResolved = [IO.Path]::GetFullPath($InstallRoot).TrimEnd([IO.Path]::DirectorySeparatorChar); $UserPath = [Environment]::GetEnvironmentVariable('Path','User'); $Kept = @($UserPath -split ';' | Where-Object { $Entry = $_.Trim(); $Entry -ne '' -and -not ($Entry.TrimEnd([IO.Path]::DirectorySeparatorChar).StartsWith(($InstallRootResolved + [IO.Path]::DirectorySeparatorChar), [StringComparison]::OrdinalIgnoreCase) -and -not $Entry.TrimEnd([IO.Path]::DirectorySeparatorChar).Equals($StableBin.TrimEnd([IO.Path]::DirectorySeparatorChar), [StringComparison]::OrdinalIgnoreCase)) }); $NewPath = ((@($StableBin) + $Kept) -join ';'); if ($NewPath -ne $UserPath) { [Environment]::SetEnvironmentVariable('Path', $NewPath, 'User') }",
|
|
441
449
|
// Journal cleanup must succeed before discarding the prior pointer. If
|
|
442
450
|
// cleanup fails, catch still has a rollback anchor to restore.
|
|
451
|
+
// Retention: after a healthy activation keep only the new version and the prior target (the
|
|
452
|
+
// app's first-start probation may still roll back to it, then deletes it). Every other version
|
|
453
|
+
// is removed; one a running process still holds fails the rename and is retried next install.
|
|
454
|
+
" $KeepVersions = @([IO.Path]::GetFullPath($VersionRoot).TrimEnd([IO.Path]::DirectorySeparatorChar)); if ($PriorTarget) { $KeepVersions += [IO.Path]::GetFullPath([string]$PriorTarget).TrimEnd([IO.Path]::DirectorySeparatorChar) }; Get-ChildItem -LiteralPath $VersionsRoot -Directory -Force -ErrorAction SilentlyContinue | Where-Object { $Candidate = $_.FullName.TrimEnd([IO.Path]::DirectorySeparatorChar); -not ($KeepVersions | Where-Object { $_.Equals($Candidate, [StringComparison]::OrdinalIgnoreCase) }) } | ForEach-Object { try { $Doomed = Join-Path $VersionsRoot ('.prune-' + [guid]::NewGuid()); Rename-Item -LiteralPath $_.FullName -NewName (Split-Path -Leaf $Doomed) -ErrorAction Stop; Remove-Item -LiteralPath $Doomed -Recurse -Force -ErrorAction SilentlyContinue } catch { } }",
|
|
443
455
|
" Remove-Item -Force $Journal; Remove-StableJunction $PreviousLink; Write-Output (" + psQuote(product + " ") + " + $Version + ' installed')",
|
|
444
456
|
"} catch {",
|
|
445
457
|
" $InstallError = $_; $RollbackErrors = New-Object 'System.Collections.Generic.List[string]'",
|
package/package.json
CHANGED
package/portable-development.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
|
+
import { spawnSync } from "./background-process.mjs";
|
|
4
5
|
|
|
5
6
|
const CHUNK_BYTES = 1024 * 1024;
|
|
6
7
|
|
|
@@ -62,6 +63,7 @@ export function installPortableDevelopment(descriptor, { root, platform = proces
|
|
|
62
63
|
const entryDigest = hashFile(entrypoint);
|
|
63
64
|
if (entryDigest !== hashFile(path.join(source, descriptor.entrypoint))) throw new Error("development entrypoint readback did not match source");
|
|
64
65
|
if (backup) removeIfExists(backup);
|
|
66
|
+
emit("PRUNE", pruneDevelopmentVersions(installRoot, versionRoot, { platform }));
|
|
65
67
|
emit("SUCCEEDED", { installRoot, current, versionRoot, digest, entrypoint: descriptor.entrypoint, entrypointDigest: entryDigest });
|
|
66
68
|
return { installRoot, current, versionRoot, digest, entrypoint: path.join(current, descriptor.entrypoint), entrypointDigest: entryDigest };
|
|
67
69
|
} catch (error) {
|
|
@@ -75,6 +77,60 @@ export function installPortableDevelopment(descriptor, { root, platform = proces
|
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Development installs keep only the active version: dev builds are rebuilt from source, so there is
|
|
82
|
+
* no rollback copy. A version a running process still uses is skipped and removed by the next
|
|
83
|
+
* install. Never throws: a prune problem must not fail an install that already activated.
|
|
84
|
+
*/
|
|
85
|
+
export function pruneDevelopmentVersions(installRoot, keepRoot, { platform = process.platform, runningExecutables = null } = {}) {
|
|
86
|
+
const versionsRoot = path.join(installRoot, "versions");
|
|
87
|
+
const removed = []; const skipped = []; let reclaimedBytes = 0;
|
|
88
|
+
let running = null;
|
|
89
|
+
const inUse = (dir) => {
|
|
90
|
+
if (platform === "win32") return false; // Windows: a loaded image or DLL makes the rename below fail.
|
|
91
|
+
running ??= runningExecutables ?? listRunningExecutables();
|
|
92
|
+
return running.some((exe) => isWithin(dir, exe, platform));
|
|
93
|
+
};
|
|
94
|
+
const candidates = [];
|
|
95
|
+
for (const [dir, pattern] of [[versionsRoot, /^(dev-[0-9a-f]+|\.stage-.+|\.prune-.+)$/], [installRoot, /^\.(current-backup|prune)-.+$/]]) {
|
|
96
|
+
let names = [];
|
|
97
|
+
try { names = fs.readdirSync(dir); } catch { continue; }
|
|
98
|
+
for (const name of names) if (pattern.test(name)) candidates.push(path.join(dir, name));
|
|
99
|
+
}
|
|
100
|
+
for (const candidate of candidates) {
|
|
101
|
+
if (samePath(candidate, keepRoot, platform)) continue;
|
|
102
|
+
if (path.basename(candidate).includes(`-${process.pid}-`)) continue; // this process's own stage/backup
|
|
103
|
+
try {
|
|
104
|
+
if (inUse(candidate)) { skipped.push({ path: candidate, reason: "in-use" }); continue; }
|
|
105
|
+
const bytes = treeBytes(candidate);
|
|
106
|
+
// Rename first: on Windows this fails while any file inside is loaded, so a running version is skipped whole.
|
|
107
|
+
const doomed = path.basename(candidate).startsWith(".prune-") ? candidate : path.join(path.dirname(candidate), `.prune-${randomSuffix()}`);
|
|
108
|
+
if (doomed !== candidate) fs.renameSync(candidate, doomed);
|
|
109
|
+
fs.rmSync(doomed, { recursive: true, force: true });
|
|
110
|
+
removed.push(candidate); reclaimedBytes += bytes;
|
|
111
|
+
} catch (error) {
|
|
112
|
+
skipped.push({ path: candidate, reason: error?.code ?? error?.message ?? String(error) });
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
return { kept: keepRoot, removed: removed.length, skipped, reclaimedBytes };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function listRunningExecutables() {
|
|
119
|
+
const result = spawnSync("ps", ["-axo", "comm="], { encoding: "utf8" });
|
|
120
|
+
return result.status === 0 ? result.stdout.split(/\r?\n/).map((line) => line.trim()).filter((line) => path.isAbsolute(line)) : [];
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function treeBytes(target) {
|
|
124
|
+
let total = 0;
|
|
125
|
+
const stat = fs.lstatSync(target);
|
|
126
|
+
if (!stat.isDirectory()) return stat.size;
|
|
127
|
+
for (const entry of fs.readdirSync(target, { withFileTypes: true })) {
|
|
128
|
+
const child = path.join(target, entry.name);
|
|
129
|
+
total += entry.isDirectory() && !entry.isSymbolicLink() ? treeBytes(child) : fs.lstatSync(child).size;
|
|
130
|
+
}
|
|
131
|
+
return total;
|
|
132
|
+
}
|
|
133
|
+
|
|
78
134
|
function validateDescriptor(descriptor, root, platform) {
|
|
79
135
|
if (!descriptor || descriptor.kind !== "portable" || descriptor.activation?.kind !== "current") throw new Error("unsupported portable development descriptor");
|
|
80
136
|
if (typeof root !== "string" || !path.isAbsolute(root)) throw new Error("repository root must be absolute");
|
package/rightkit-versions.json
CHANGED
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
"@rightkit/license": "0.1.8",
|
|
25
25
|
"@rightkit/logs": "0.1.4",
|
|
26
26
|
"@rightkit/media-ui": "0.2.5",
|
|
27
|
-
"@rightkit/onboarding": "0.2.
|
|
27
|
+
"@rightkit/onboarding": "0.2.2",
|
|
28
28
|
"@rightkit/pdf-ui": "0.1.1",
|
|
29
29
|
"@rightkit/platform-ui": "0.1.2",
|
|
30
30
|
"@rightkit/qa": "0.2.1",
|
|
31
|
-
"@rightkit/release": "0.2.
|
|
32
|
-
"@rightkit/settings-ui": "0.2.
|
|
31
|
+
"@rightkit/release": "0.2.120",
|
|
32
|
+
"@rightkit/settings-ui": "0.2.4",
|
|
33
33
|
"@rightkit/shell": "0.1.0",
|
|
34
34
|
"@rightkit/tauri": "0.1.1",
|
|
35
35
|
"@rightkit/theme": "0.2.0",
|
|
@@ -139,7 +139,9 @@
|
|
|
139
139
|
"0.2.114",
|
|
140
140
|
"0.2.115",
|
|
141
141
|
"0.2.116",
|
|
142
|
-
"0.2.117"
|
|
142
|
+
"0.2.117",
|
|
143
|
+
"0.2.118",
|
|
144
|
+
"0.2.119"
|
|
143
145
|
],
|
|
144
146
|
"@rightkit/qa": [
|
|
145
147
|
"0.1.0",
|
|
@@ -161,11 +163,14 @@
|
|
|
161
163
|
],
|
|
162
164
|
"@rightkit/settings-ui": [
|
|
163
165
|
"0.1.0",
|
|
164
|
-
"0.2.0"
|
|
166
|
+
"0.2.0",
|
|
167
|
+
"0.2.2",
|
|
168
|
+
"0.2.3"
|
|
165
169
|
],
|
|
166
170
|
"@rightkit/onboarding": [
|
|
167
171
|
"0.1.0",
|
|
168
|
-
"0.2.0"
|
|
172
|
+
"0.2.0",
|
|
173
|
+
"0.2.1"
|
|
169
174
|
],
|
|
170
175
|
"@rightkit/doc-render": [
|
|
171
176
|
"0.1.0",
|
|
@@ -200,19 +205,19 @@
|
|
|
200
205
|
"rightkit-audio": "0.1.0",
|
|
201
206
|
"rightkit-browser": "0.1.1",
|
|
202
207
|
"rightkit-cache": "0.1.0",
|
|
203
|
-
"rightkit-control": "0.1.
|
|
208
|
+
"rightkit-control": "0.1.2",
|
|
204
209
|
"rightkit-crash": "0.1.0",
|
|
205
|
-
"rightkit-db": "0.2.
|
|
210
|
+
"rightkit-db": "0.2.1",
|
|
206
211
|
"rightkit-framed-sidecar": "0.1.0",
|
|
207
212
|
"rightkit-fs": "0.1.0",
|
|
208
|
-
"rightkit-jobs": "0.1
|
|
213
|
+
"rightkit-jobs": "0.2.1",
|
|
209
214
|
"rightkit-logs": "0.2.0",
|
|
210
|
-
"rightkit-media": "0.
|
|
215
|
+
"rightkit-media": "0.2.2",
|
|
211
216
|
"rightkit-models": "0.1.0",
|
|
212
217
|
"rightkit-pdf": "0.1.0",
|
|
213
218
|
"rightkit-playback": "0.1.0",
|
|
214
219
|
"rightkit-process": "0.2.1",
|
|
215
|
-
"rightkit-qa": "0.
|
|
220
|
+
"rightkit-qa": "0.2.0",
|
|
216
221
|
"rightkit-sandbox": "0.1.0",
|
|
217
222
|
"rightkit-search": "0.1.0",
|
|
218
223
|
"rightkit-service": "0.1.0",
|