agentroam 0.2.0-preview.40 → 0.2.0-preview.41

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.
@@ -172,7 +172,7 @@ if ($AgentRoamVersionRequest -notmatch '\d$') {
172
172
  $AgentRoamVersion = $AgentRoamVersionRequest
173
173
  }
174
174
  $LauncherRoot = Join-Path $LauncherParent $AgentRoamVersion
175
- $LauncherLock = Join-Path $LauncherRoot ".lock"
175
+ $LauncherLock = "$LauncherRoot.lock"
176
176
  $PackageSpec = "agentroam@$AgentRoamVersion"
177
177
  $ExtraPackageSpecs = @()
178
178
  if ($env:AGENTROAM_BOOTSTRAP_TEST -eq "1" -and $env:AGENTROAM_PACKAGE_SPEC) {
@@ -181,14 +181,97 @@ if ($env:AGENTROAM_BOOTSTRAP_TEST -eq "1" -and $env:AGENTROAM_PACKAGE_SPEC) {
181
181
  }
182
182
  $Entry = Join-Path $LauncherRoot "node_modules\agentroam\bin\agentroam.mjs"
183
183
 
184
- function Test-Launcher {
185
- if (-not (Test-Path -LiteralPath $Entry -PathType Leaf)) { return $false }
184
+ $LauncherCheckSource = @'
185
+ const { readFileSync, statSync } = require("node:fs");
186
+ const { createHash } = require("node:crypto");
187
+ const { createRequire } = require("node:module");
188
+ const { dirname, resolve, sep } = require("node:path");
189
+ const [prefix, launcherVersion, minimumNodeVersion, target, mode] = process.argv.slice(process.argv[1] === "-" ? 2 : 1);
190
+ try {
191
+ const packageName = {
192
+ "darwin-arm64": "agentroam-runtime-darwin-arm64",
193
+ "windows-amd64": "agentroam-runtime-win32-x64",
194
+ }[target];
195
+ if (!packageName) throw new Error("Unsupported runtime target: " + target);
196
+ const launcherPath = resolve(prefix, "node_modules/agentroam/package.json");
197
+ const launcher = JSON.parse(readFileSync(launcherPath, "utf8"));
198
+ if (launcher.version !== launcherVersion) throw new Error("AgentRoam launcher version mismatch");
199
+ const version = launcher.optionalDependencies?.[packageName];
200
+ if (typeof version !== "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version)) {
201
+ throw new Error("Runtime dependency must use an exact version: " + packageName);
202
+ }
203
+ if (mode === "spec") {
204
+ console.log(packageName + "@" + version);
205
+ } else {
206
+ if (mode !== "verify") throw new Error("Unknown runtime validation mode: " + mode);
207
+ const launcherRequire = createRequire(launcherPath);
208
+ const manifestPath = launcherRequire.resolve(packageName + "/manifest.json");
209
+ const runtimeRoot = dirname(launcherRequire.resolve(packageName + "/runtime"));
210
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
211
+ const runtimePackage = JSON.parse(readFileSync(resolve(dirname(manifestPath), "package.json"), "utf8"));
212
+ if (runtimePackage.name !== packageName || runtimePackage.version !== version ||
213
+ manifest.packageVersion !== version || manifest.target !== target ||
214
+ manifest.schemaVersion !== 2 || manifest.minimumNodeVersion !== minimumNodeVersion ||
215
+ !manifest.nativeFiles || typeof manifest.nativeFiles !== "object" || Array.isArray(manifest.nativeFiles)) {
216
+ throw new Error("Invalid runtime manifest: " + manifestPath);
217
+ }
218
+ const nativeTarget = target === "darwin-arm64" ? "darwin-arm64" : "win32-x64";
219
+ for (const file of [
220
+ "node_modules/better-sqlite3/prebuilds/" + nativeTarget + ".node",
221
+ "node_modules/node-pty/prebuilds/" + nativeTarget + "/pty.node",
222
+ ...(target === "darwin-arm64"
223
+ ? ["node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper"]
224
+ : ["node_modules/node-pty/prebuilds/win32-x64/conpty.node",
225
+ "node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll",
226
+ "node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe"]),
227
+ ]) {
228
+ if (!manifest.nativeFiles[file]) throw new Error("Missing runtime native inventory: " + file);
229
+ }
230
+ for (const file of ["bin/agentroam.mjs"]) {
231
+ if (!statSync(resolve(dirname(launcherPath), file)).isFile()) throw new Error("Missing launcher file: " + file);
232
+ }
233
+ for (const file of ["ws-server.mjs", ".next/BUILD_ID"]) {
234
+ if (!statSync(resolve(runtimeRoot, file)).isFile()) throw new Error("Missing runtime file: " + file);
235
+ }
236
+ for (const [file, expectedHash] of Object.entries(manifest.nativeFiles)) {
237
+ const path = resolve(runtimeRoot, file);
238
+ if (!path.startsWith(runtimeRoot + sep) || !/^[a-f0-9]{64}$/.test(expectedHash)) {
239
+ throw new Error("Invalid runtime native inventory: " + file);
240
+ }
241
+ const actualHash = createHash("sha256").update(readFileSync(path)).digest("hex");
242
+ if (actualHash !== expectedHash) throw new Error("Runtime native file checksum mismatch: " + file);
243
+ }
244
+ const runtimeRequire = createRequire(resolve(runtimeRoot, "package.json"));
245
+ for (const name of ["better-sqlite3", "node-pty"]) {
246
+ if (!runtimeRequire.resolve(name).startsWith(runtimeRoot + sep)) throw new Error("Missing runtime module: " + name);
247
+ }
248
+ const Database = runtimeRequire("better-sqlite3");
249
+ const database = new Database(":memory:");
250
+ try {
251
+ if (database.prepare("SELECT 1 AS ok").get()?.ok !== 1) throw new Error("SQLite runtime query failed");
252
+ } finally {
253
+ database.close();
254
+ }
255
+ if (typeof runtimeRequire("node-pty").spawn !== "function") throw new Error("Invalid PTY runtime module");
256
+ }
257
+ } catch (error) {
258
+ console.error("AgentRoam runtime validation failed: " + error.message);
259
+ process.exitCode = 1;
260
+ }
261
+ '@
262
+
263
+ function Test-LauncherRuntime([string]$Prefix) {
186
264
  try {
187
- $Output = & $NodeBin $Entry version 2>$null
188
- return $LASTEXITCODE -eq 0 -and $Output -match [Regex]::Escape($AgentRoamVersion)
265
+ # Pipe JavaScript to Node so Windows PowerShell 5 does not strip its quotes.
266
+ $LauncherCheckSource | & $NodeBin - $Prefix $AgentRoamVersion $MinimumNodeVersion windows-amd64 verify 2>$null
267
+ return $LASTEXITCODE -eq 0
189
268
  } catch { return $false }
190
269
  }
191
270
 
271
+ function Test-Launcher {
272
+ return Test-LauncherRuntime $LauncherRoot
273
+ }
274
+
192
275
  if (-not (Test-Launcher)) {
193
276
  $LauncherLockHandle = Enter-InstallLock $LauncherLock
194
277
  try {
@@ -198,11 +281,30 @@ if (-not (Test-Launcher)) {
198
281
  $NpmArgs = @("install", "--no-audit", "--no-fund", "--registry", $NpmRegistry, "--prefix", $TempLauncher) + $ExtraPackageSpecs + @($PackageSpec)
199
282
  & $NodeBin $NpmCli @NpmArgs
200
283
  if ($LASTEXITCODE -ne 0) { throw "npm install failed with exit code $LASTEXITCODE" }
201
- $TempEntry = Join-Path $TempLauncher "node_modules\agentroam\bin\agentroam.mjs"
202
- $VersionOutput = & $NodeBin $TempEntry version
203
- if ($LASTEXITCODE -ne 0 -or $VersionOutput -notmatch [Regex]::Escape($AgentRoamVersion)) { throw "AgentRoam version validation failed" }
204
- Remove-Item -LiteralPath $LauncherRoot -Recurse -Force -ErrorAction SilentlyContinue
205
- Move-Item -LiteralPath $TempLauncher -Destination $LauncherRoot
284
+ $RuntimeSpec = [string]($LauncherCheckSource | & $NodeBin - $TempLauncher $AgentRoamVersion $MinimumNodeVersion windows-amd64 spec)
285
+ if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($RuntimeSpec)) { throw "AgentRoam runtime dependency validation failed" }
286
+ if (-not (Test-LauncherRuntime $TempLauncher)) {
287
+ Remove-Item -LiteralPath (Join-Path $TempLauncher "node_modules\agentroam-runtime-win32-x64") -Recurse -Force -ErrorAction SilentlyContinue
288
+ $RuntimeArgs = @("install", "--save-exact", "--include=optional", "--no-audit", "--no-fund", "--registry", $NpmRegistry, "--prefix", $TempLauncher, $RuntimeSpec.Trim())
289
+ & $NodeBin $NpmCli @RuntimeArgs
290
+ if ($LASTEXITCODE -ne 0) { throw "Required AgentRoam runtime install failed with exit code $LASTEXITCODE" }
291
+ }
292
+ $LauncherCheckSource | & $NodeBin - $TempLauncher $AgentRoamVersion $MinimumNodeVersion windows-amd64 verify
293
+ if ($LASTEXITCODE -ne 0) { throw "AgentRoam runtime validation failed; previous installation preserved" }
294
+ $PreviousLauncher = $null
295
+ if (Test-Path -LiteralPath $LauncherRoot) {
296
+ $PreviousLauncher = Join-Path $LauncherParent ".previous-$AgentRoamVersion-$([Guid]::NewGuid().ToString('N'))"
297
+ Move-Item -LiteralPath $LauncherRoot -Destination $PreviousLauncher
298
+ }
299
+ try {
300
+ Move-Item -LiteralPath $TempLauncher -Destination $LauncherRoot
301
+ } catch {
302
+ if ($PreviousLauncher -and -not (Test-Path -LiteralPath $LauncherRoot)) {
303
+ Move-Item -LiteralPath $PreviousLauncher -Destination $LauncherRoot
304
+ }
305
+ throw
306
+ }
307
+ if ($PreviousLauncher) { Remove-Item -LiteralPath $PreviousLauncher -Recurse -Force }
206
308
  } finally {
207
309
  Remove-Item -LiteralPath $TempLauncher -Recurse -Force -ErrorAction SilentlyContinue
208
310
  }
@@ -26,6 +26,7 @@ else
26
26
  SERVICE_ROOT="$PWD"
27
27
  fi
28
28
  TEMP_ROOT=""
29
+ PREVIOUS_LAUNCHER_ROOT=""
29
30
  OWN_NODE_LOCK=0
30
31
  OWN_LAUNCHER_LOCK=0
31
32
  PROGRESS_PID=""
@@ -77,6 +78,9 @@ fail() {
77
78
 
78
79
  cleanup() {
79
80
  stop_progress
81
+ if [ -n "$PREVIOUS_LAUNCHER_ROOT" ] && [ -d "$PREVIOUS_LAUNCHER_ROOT" ] && [ ! -e "$LAUNCHER_ROOT" ]; then
82
+ mv "$PREVIOUS_LAUNCHER_ROOT" "$LAUNCHER_ROOT" || printf 'Could not restore previous launcher: %s\n' "$PREVIOUS_LAUNCHER_ROOT" >&2
83
+ fi
80
84
  if [ -n "$TEMP_ROOT" ] && [ -d "$TEMP_ROOT" ]; then
81
85
  rm -rf "$TEMP_ROOT"
82
86
  fi
@@ -271,9 +275,91 @@ if [ "${AGENTROAM_BOOTSTRAP_TEST:-}" = "1" ] && [ -n "${AGENTROAM_PACKAGE_SPEC:-
271
275
  EXTRA_PACKAGE_SPECS="${AGENTROAM_BOOTSTRAP_EXTRA_SPECS:-}"
272
276
  fi
273
277
 
278
+ LAUNCHER_CHECK_JS='
279
+ const { readFileSync, statSync } = require("node:fs");
280
+ const { createHash } = require("node:crypto");
281
+ const { createRequire } = require("node:module");
282
+ const { dirname, resolve, sep } = require("node:path");
283
+ const [prefix, launcherVersion, minimumNodeVersion, target, mode] = process.argv.slice(process.argv[1] === "-" ? 2 : 1);
284
+ try {
285
+ const packageName = {
286
+ "darwin-arm64": "agentroam-runtime-darwin-arm64",
287
+ "windows-amd64": "agentroam-runtime-win32-x64",
288
+ }[target];
289
+ if (!packageName) throw new Error("Unsupported runtime target: " + target);
290
+ const launcherPath = resolve(prefix, "node_modules/agentroam/package.json");
291
+ const launcher = JSON.parse(readFileSync(launcherPath, "utf8"));
292
+ if (launcher.version !== launcherVersion) throw new Error("AgentRoam launcher version mismatch");
293
+ const version = launcher.optionalDependencies?.[packageName];
294
+ if (typeof version !== "string" || !/^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/.test(version)) {
295
+ throw new Error("Runtime dependency must use an exact version: " + packageName);
296
+ }
297
+ if (mode === "spec") {
298
+ console.log(packageName + "@" + version);
299
+ } else {
300
+ if (mode !== "verify") throw new Error("Unknown runtime validation mode: " + mode);
301
+ const launcherRequire = createRequire(launcherPath);
302
+ const manifestPath = launcherRequire.resolve(packageName + "/manifest.json");
303
+ const runtimeRoot = dirname(launcherRequire.resolve(packageName + "/runtime"));
304
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
305
+ const runtimePackage = JSON.parse(readFileSync(resolve(dirname(manifestPath), "package.json"), "utf8"));
306
+ if (runtimePackage.name !== packageName || runtimePackage.version !== version ||
307
+ manifest.packageVersion !== version || manifest.target !== target ||
308
+ manifest.schemaVersion !== 2 || manifest.minimumNodeVersion !== minimumNodeVersion ||
309
+ !manifest.nativeFiles || typeof manifest.nativeFiles !== "object" || Array.isArray(manifest.nativeFiles)) {
310
+ throw new Error("Invalid runtime manifest: " + manifestPath);
311
+ }
312
+ const nativeTarget = target === "darwin-arm64" ? "darwin-arm64" : "win32-x64";
313
+ for (const file of [
314
+ "node_modules/better-sqlite3/prebuilds/" + nativeTarget + ".node",
315
+ "node_modules/node-pty/prebuilds/" + nativeTarget + "/pty.node",
316
+ ...(target === "darwin-arm64"
317
+ ? ["node_modules/node-pty/prebuilds/darwin-arm64/spawn-helper"]
318
+ : ["node_modules/node-pty/prebuilds/win32-x64/conpty.node",
319
+ "node_modules/node-pty/prebuilds/win32-x64/conpty/conpty.dll",
320
+ "node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe"]),
321
+ ]) {
322
+ if (!manifest.nativeFiles[file]) throw new Error("Missing runtime native inventory: " + file);
323
+ }
324
+ for (const file of ["bin/agentroam.mjs"]) {
325
+ if (!statSync(resolve(dirname(launcherPath), file)).isFile()) throw new Error("Missing launcher file: " + file);
326
+ }
327
+ for (const file of ["ws-server.mjs", ".next/BUILD_ID"]) {
328
+ if (!statSync(resolve(runtimeRoot, file)).isFile()) throw new Error("Missing runtime file: " + file);
329
+ }
330
+ for (const [file, expectedHash] of Object.entries(manifest.nativeFiles)) {
331
+ const path = resolve(runtimeRoot, file);
332
+ if (!path.startsWith(runtimeRoot + sep) || !/^[a-f0-9]{64}$/.test(expectedHash)) {
333
+ throw new Error("Invalid runtime native inventory: " + file);
334
+ }
335
+ const actualHash = createHash("sha256").update(readFileSync(path)).digest("hex");
336
+ if (actualHash !== expectedHash) throw new Error("Runtime native file checksum mismatch: " + file);
337
+ }
338
+ const runtimeRequire = createRequire(resolve(runtimeRoot, "package.json"));
339
+ for (const name of ["better-sqlite3", "node-pty"]) {
340
+ if (!runtimeRequire.resolve(name).startsWith(runtimeRoot + sep)) throw new Error("Missing runtime module: " + name);
341
+ }
342
+ const Database = runtimeRequire("better-sqlite3");
343
+ const database = new Database(":memory:");
344
+ try {
345
+ if (database.prepare("SELECT 1 AS ok").get()?.ok !== 1) throw new Error("SQLite runtime query failed");
346
+ } finally {
347
+ database.close();
348
+ }
349
+ if (typeof runtimeRequire("node-pty").spawn !== "function") throw new Error("Invalid PTY runtime module");
350
+ }
351
+ } catch (error) {
352
+ console.error("AgentRoam runtime validation failed: " + error.message);
353
+ process.exitCode = 1;
354
+ }
355
+ '
356
+
357
+ launcher_check() {
358
+ "$NODE_BIN" -e "$LAUNCHER_CHECK_JS" "$1" "$AGENTROAM_VERSION" "$MINIMUM_NODE_VERSION" darwin-arm64 "$2"
359
+ }
360
+
274
361
  launcher_is_valid() {
275
- [ -f "$LAUNCHER_ROOT/node_modules/agentroam/bin/agentroam.mjs" ] \
276
- && [ "$("$NODE_BIN" "$LAUNCHER_ROOT/node_modules/agentroam/bin/agentroam.mjs" version 2>/dev/null | awk '{print $2}' || true)" = "$AGENTROAM_VERSION" ]
362
+ launcher_check "$LAUNCHER_ROOT" verify >/dev/null 2>&1
277
363
  }
278
364
 
279
365
  start_progress "正在检查已安装的 CLI"
@@ -287,13 +373,23 @@ if ! launcher_is_valid; then
287
373
  # Test-only extra specs are whitespace-delimited artifact paths in isolated CI directories.
288
374
  # shellcheck disable=SC2086
289
375
  run_with_progress "正在下载和安装 CLI 及平台组件" "$NODE_BIN" "$NPM_CLI" install --no-audit --no-fund --registry "$NPM_REGISTRY" --prefix "$TEMP_ROOT" $EXTRA_PACKAGE_SPECS "$PACKAGE_SPEC"
376
+ runtime_spec=$(launcher_check "$TEMP_ROOT" spec)
377
+ if ! launcher_check "$TEMP_ROOT" verify; then
378
+ # A matching runtime is required even though npm treats platform packages as optional.
379
+ rm -rf "$TEMP_ROOT/node_modules/agentroam-runtime-darwin-arm64"
380
+ run_with_progress "正在安装必需的运行组件" "$NODE_BIN" "$NPM_CLI" install --save-exact --include=optional --no-audit --no-fund --registry "$NPM_REGISTRY" --prefix "$TEMP_ROOT" "$runtime_spec"
381
+ fi
382
+ run_with_progress "正在验证运行组件" launcher_check "$TEMP_ROOT" verify
290
383
  start_progress "正在验证并启用 CLI"
291
- entry="$TEMP_ROOT/node_modules/agentroam/bin/agentroam.mjs"
292
- [ -f "$entry" ] || fail "AgentRoam launcher is missing after npm install"
293
- [ "$("$NODE_BIN" "$entry" version | awk '{print $2}')" = "$AGENTROAM_VERSION" ] || fail "AgentRoam version validation failed"
294
- rm -rf "$LAUNCHER_ROOT"
295
- mv "$TEMP_ROOT" "$LAUNCHER_ROOT"
384
+ if [ -e "$LAUNCHER_ROOT" ]; then
385
+ PREVIOUS_LAUNCHER_ROOT=$(mktemp -d "$LAUNCHER_PARENT/.previous-$AGENTROAM_VERSION.XXXXXX")
386
+ rmdir "$PREVIOUS_LAUNCHER_ROOT"
387
+ mv "$LAUNCHER_ROOT" "$PREVIOUS_LAUNCHER_ROOT"
388
+ fi
389
+ if ! mv "$TEMP_ROOT" "$LAUNCHER_ROOT"; then fail "could not activate AgentRoam launcher"; fi
296
390
  TEMP_ROOT=""
391
+ if [ -n "$PREVIOUS_LAUNCHER_ROOT" ]; then rm -rf "$PREVIOUS_LAUNCHER_ROOT"; fi
392
+ PREVIOUS_LAUNCHER_ROOT=""
297
393
  fi
298
394
  rmdir "$LAUNCHER_LOCK" 2>/dev/null || true
299
395
  OWN_LAUNCHER_LOCK=0
@@ -3,13 +3,13 @@
3
3
  "installers": {
4
4
  "darwin-arm64": {
5
5
  "fileName": "install-agentroam.sh",
6
- "sha256": "9fad4cb6528e0b71224c40c4eece94881a67191b165ccb673b980498b8646487",
7
- "size": 14575
6
+ "sha256": "c399354e39001b4717bad7aae81e5f53b1346188befdf308f73e3dcd99580cb0",
7
+ "size": 19873
8
8
  },
9
9
  "windows-amd64": {
10
10
  "fileName": "install-agentroam.ps1",
11
- "sha256": "5df75c9a139997cfee382ef824216b92bf4a68eba679fbc5be01102019ce1652",
12
- "size": 13309
11
+ "sha256": "f331d2269cc66b18e732dd06f7252da56e883b9a344595e5d5977108f9e337e2",
12
+ "size": 19121
13
13
  }
14
14
  }
15
15
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agentroam",
3
- "version": "0.2.0-preview.40",
3
+ "version": "0.2.0-preview.41",
4
4
  "description": "Zero-install mobile remote terminal and file console",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,8 +26,8 @@
26
26
  "undici": "^6.25.0"
27
27
  },
28
28
  "optionalDependencies": {
29
- "agentroam-runtime-darwin-arm64": "0.2.0-preview.39",
30
- "agentroam-runtime-win32-x64": "0.2.0-preview.39",
29
+ "agentroam-runtime-darwin-arm64": "0.2.0-preview.41",
30
+ "agentroam-runtime-win32-x64": "0.2.0-preview.41",
31
31
  "agentroam-cloudflared-darwin-arm64": "0.2.0-preview.39",
32
32
  "agentroam-cloudflared-win32-x64": "0.2.0-preview.39",
33
33
  "agentroam-tui-darwin-arm64": "0.2.0-preview.39",