aigent-hive 0.13.2-test.2 → 0.14.0-test.2

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/install.cmd CHANGED
@@ -1,6 +1,6 @@
1
1
  @echo off
2
2
  setlocal EnableExtensions DisableDelayedExpansion
3
- set "HIVE_INSTALL_PACKAGE_VERSION=0.13.2-test.2"
3
+ set "HIVE_INSTALL_PACKAGE_VERSION=0.14.0-test.2"
4
4
  set "HIVE_INSTALL_URL=https://unpkg.com/aigent-hive@%HIVE_INSTALL_PACKAGE_VERSION%/install.ps1"
5
5
  set "HIVE_INSTALL_SCRIPT=%TEMP%\aigent-hive-install-%RANDOM%-%RANDOM%.ps1"
6
6
 
package/install.ps1 CHANGED
@@ -1,14 +1,15 @@
1
1
  param(
2
2
  [ValidatePattern('^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$')]
3
- [string]$Version = "0.13.2",
3
+ [string]$Version = "0.14.0",
4
4
  [ValidatePattern('^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(-test(\.[1-9][0-9]*)?)?$')]
5
- [string]$PackageVersion = "0.13.2-test.2",
6
- [string]$Prefix = "$env:LOCALAPPDATA\AigentHive"
5
+ [string]$PackageVersion = "0.14.0-test.2",
6
+ [string]$Prefix = "$env:LOCALAPPDATA\AigentHive",
7
+ [switch]$DeferLockedBackup
7
8
  )
8
9
 
9
10
  $ErrorActionPreference = "Stop"
10
11
  $AuthorizedSignerThumbprint = ""
11
- $ExpectedArchiveSha256 = "3094364940f6d85d6a63aaad349c9180a0d2bb17fab3807369f5db5a7c2b0198"
12
+ $ExpectedArchiveSha256 = "49a33aff75c1519e97edd847c18b7ac08419138b7ae2a04469abc6d03c951024"
12
13
  if ($AuthorizedSignerThumbprint -like "__AIGENT_HIVE_*") {
13
14
  $AuthorizedSignerThumbprint = ""
14
15
  }
@@ -110,7 +111,7 @@ function Assert-SafeDirectoryChain {
110
111
  if ($component -eq "." -or $component -eq "..") {
111
112
  throw "install path contains a reparse point or non-directory"
112
113
  }
113
- $currentPath = Join-Path $currentPath $component
114
+ $currentPath = [IO.Path]::Combine($currentPath, $component)
114
115
  $item = Get-Item -LiteralPath $currentPath -Force -ErrorAction SilentlyContinue
115
116
  if ($null -eq $item) {
116
117
  New-Item -ItemType Directory -Path $currentPath -ErrorAction Stop | Out-Null
@@ -209,6 +210,33 @@ function Assert-ExistingDirectInstall {
209
210
  }
210
211
  }
211
212
 
213
+ function New-DirectReplacementRecord {
214
+ param([string]$Destination,[string]$Backup,[string]$BeforeDigest,[string]$AfterDigest,[string]$Package,[string]$Identity)
215
+ if ($Identity -notmatch '^sha256:[0-9a-f]{64}$') { throw 'direct replacement prefix identity is missing' }
216
+ $prefixPath = Split-Path -Parent (Split-Path -Parent $Destination)
217
+ $sharePath = [IO.Path]::Combine($prefixPath, 'share\aigent-hive')
218
+ Assert-SafeDirectoryChain -Path $sharePath
219
+ $previous = Get-ValidatedDirectReceipt -ReceiptPath ([IO.Path]::Combine($sharePath, 'install-receipt.json'))
220
+ if ((Split-Path -Leaf $Destination) -ne 'hive.exe' -or $previous.artifact_sha256 -ne "sha256:$BeforeDigest") {
221
+ throw 'retired image does not match the owned direct installation'
222
+ }
223
+ $recordPath = [IO.Path]::Combine($sharePath, 'replacement-pending.json')
224
+ if (Test-Path -LiteralPath $recordPath) { throw 'finish the previous replacement with hive update first' }
225
+ $temporary = [IO.Path]::Combine($sharePath, ('.replacement-record-' + [Guid]::NewGuid().ToString('N')))
226
+ $bytes = [Text.UTF8Encoding]::new($false).GetBytes((@{
227
+ schema_version=1; prefix_identity=$Identity; backup_name=(Split-Path -Leaf $Backup)
228
+ before_sha256="sha256:$BeforeDigest"; after_sha256="sha256:$AfterDigest"
229
+ before_package_version=$previous.package_version; after_package_version=$Package
230
+ } | ConvertTo-Json -Compress))
231
+ try {
232
+ $stream=[IO.File]::Open($temporary,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
233
+ try { $stream.Write($bytes,0,$bytes.Length); $stream.Flush($true) } finally { $stream.Dispose() }
234
+ Move-InstallFile -Source $temporary -Destination $recordPath -Replace $false
235
+ } finally {
236
+ if(Test-Path -LiteralPath $temporary){Remove-Item -LiteralPath $temporary -Force}
237
+ }
238
+ }
239
+
212
240
  function Move-InstallFile {
213
241
  param(
214
242
  [Parameter(Mandatory = $true)]
@@ -216,7 +244,9 @@ function Move-InstallFile {
216
244
  [Parameter(Mandatory = $true)]
217
245
  [string]$Destination,
218
246
  [Parameter(Mandatory = $true)]
219
- [bool]$Replace
247
+ [bool]$Replace,
248
+ [string]$DeferredPackageVersion = '',
249
+ [string]$DeferredPrefixIdentity = ''
220
250
  )
221
251
 
222
252
  $sourceItem = Get-Item -LiteralPath $Source -Force -ErrorAction Stop
@@ -237,10 +267,26 @@ function Move-InstallFile {
237
267
  throw "install file target is not a regular leaf"
238
268
  }
239
269
  if ($Replace -and $null -ne $destinationItem) {
270
+ $deferred = $DeferredPackageVersion -ne ''
271
+ if ($deferred) {
272
+ if ((Split-Path -Leaf $Destination) -ne 'hive.exe' -or
273
+ (Split-Path -Leaf (Split-Path -Parent $Destination)) -ne 'bin') {
274
+ throw 'deferred replacement must target the owned bin/hive.exe'
275
+ }
276
+ $beforeDigest=Get-FileSha256 -Path $Destination
277
+ $afterDigest=Get-FileSha256 -Path $Source
278
+ if ($beforeDigest -eq $afterDigest) {
279
+ throw 'deferred replacement requires different verified program bytes'
280
+ }
281
+ }
240
282
  $destinationDirectory = Split-Path -Parent $Destination
241
- $backup = Join-Path $destinationDirectory (
283
+ $backup = [IO.Path]::Combine($destinationDirectory, (
242
284
  ".hive-replace-backup-" + [Guid]::NewGuid().ToString("N")
243
- )
285
+ ))
286
+ if ($deferred) {
287
+ New-DirectReplacementRecord -Destination $Destination -Backup $backup `
288
+ -BeforeDigest $beforeDigest -AfterDigest $afterDigest -Package $DeferredPackageVersion -Identity $DeferredPrefixIdentity
289
+ }
244
290
  [IO.File]::Replace($Source, $Destination, $backup)
245
291
  $backupItem = Get-Item -LiteralPath $backup -Force -ErrorAction Stop
246
292
  if (
@@ -249,7 +295,12 @@ function Move-InstallFile {
249
295
  ) {
250
296
  throw "install replacement backup is not a regular leaf"
251
297
  }
252
- Remove-Item -LiteralPath $backup -Force
298
+ try { Remove-Item -LiteralPath $backup -Force }
299
+ catch [UnauthorizedAccessException] {
300
+ if (-not $deferred) { throw }
301
+ # The exact recorded image is removed after its caller exits.
302
+ # Do not turn any other filesystem failure into success.
303
+ }
253
304
  } else {
254
305
  [IO.File]::Move($Source, $Destination)
255
306
  }
@@ -338,15 +389,90 @@ function Assert-AuthorizedAuthenticodeSignature {
338
389
  }
339
390
  }
340
391
 
392
+ function Publish-DirectInstall {
393
+ param([string]$Binary,[string]$Prefix,[string]$Version,[string]$PackageVersion,[switch]$DeferLockedBackup)
394
+ $stagedBinary=$null; $stagedReceipt=$null; $receiptStream=$null
395
+ try {
396
+ $binDirectory = [IO.Path]::Combine($Prefix, 'bin')
397
+ $shareDirectory = [IO.Path]::Combine($Prefix, 'share\aigent-hive')
398
+ Assert-SafeDirectoryChain -Path $Prefix
399
+ Assert-SafeDirectoryChain -Path $binDirectory
400
+ Assert-SafeDirectoryChain -Path $shareDirectory
401
+ $destination = [IO.Path]::Combine($binDirectory, 'hive.exe')
402
+ $receiptPath = [IO.Path]::Combine($shareDirectory, 'install-receipt.json')
403
+ $pendingReceiptPath = [IO.Path]::Combine($shareDirectory, 'install-receipt.pending.json')
404
+ if (Test-Path -LiteralPath ([IO.Path]::Combine($shareDirectory, 'replacement-pending.json'))) {
405
+ throw 'finish the previous replacement with hive update first'
406
+ }
407
+ Repair-PendingDirectInstall -Destination $destination -ReceiptPath $receiptPath -PendingReceiptPath $pendingReceiptPath
408
+ Assert-ExistingDirectInstall -Destination $destination -ReceiptPath $receiptPath
409
+ $stagedBinary = [IO.Path]::Combine($binDirectory, ('.hive-install-' + [Guid]::NewGuid()))
410
+ $stagedReceipt = [IO.Path]::Combine($shareDirectory, ('.install-receipt-' + [Guid]::NewGuid()))
411
+ Assert-SafeDirectoryChain -Path $binDirectory
412
+ Assert-SafeDirectoryChain -Path $shareDirectory
413
+ [IO.File]::Copy($Binary, $stagedBinary, $false)
414
+ $binaryDigest = Get-FileSha256 -Path $Binary
415
+ $receiptJson = @{
416
+ schema_version = 1
417
+ owner = "direct"
418
+ product = "aigent-hive"
419
+ version = $Version
420
+ package_version = $PackageVersion
421
+ artifact_sha256 = "sha256:$binaryDigest"
422
+ } | ConvertTo-Json -Compress
423
+ $receiptBytes = [Text.UTF8Encoding]::new($false).GetBytes($receiptJson)
424
+ $receiptStream = [IO.File]::Open($stagedReceipt,[IO.FileMode]::CreateNew,[IO.FileAccess]::ReadWrite,
425
+ ([IO.FileShare]::ReadWrite -bor [IO.FileShare]::Delete))
426
+ $receiptStream.Lock(0, 1)
427
+ $receiptStream.Write($receiptBytes, 0, $receiptBytes.Length)
428
+ $receiptStream.Flush($true)
429
+ Assert-SafeDirectoryChain -Path $binDirectory
430
+ Assert-SafeDirectoryChain -Path $shareDirectory
431
+ if ($null -ne (Get-Item -LiteralPath $pendingReceiptPath -Force -ErrorAction SilentlyContinue)) {
432
+ throw 'existing hive install transaction is not recoverable'
433
+ }
434
+ Move-InstallFile -Source $stagedReceipt -Destination $pendingReceiptPath -Replace $false
435
+ $stagedReceipt = $null
436
+ Assert-SafeDirectoryChain -Path $binDirectory
437
+ Assert-SafeDirectoryChain -Path $shareDirectory
438
+ $deferredPackage = if ($DeferLockedBackup) { $PackageVersion } else { '' }
439
+ $deferredIdentity = ''
440
+ if ($DeferLockedBackup) {
441
+ $scopeOutput = & $Binary __direct-install-scope --prefix $Prefix
442
+ if ($LASTEXITCODE -ne 0) { throw 'cannot bind the direct replacement prefix' }
443
+ $deferredIdentity = ($scopeOutput | ConvertFrom-Json).prefix_identity
444
+ }
445
+ Move-InstallFile -Source $stagedBinary -Destination $destination -Replace $true `
446
+ -DeferredPackageVersion $deferredPackage -DeferredPrefixIdentity $deferredIdentity
447
+ $stagedBinary = $null
448
+ Assert-SafeDirectoryChain -Path $binDirectory
449
+ Assert-SafeDirectoryChain -Path $shareDirectory
450
+ # Keep the pending receipt locked until publication and removal finish.
451
+ # ReplaceFile cannot consume that locked stream, so publish the same bytes from a closed copy.
452
+ $stagedReceipt = [IO.Path]::Combine($shareDirectory, ('.install-receipt-final-' + [Guid]::NewGuid()))
453
+ $finalStream=[IO.File]::Open($stagedReceipt,[IO.FileMode]::CreateNew,[IO.FileAccess]::Write,[IO.FileShare]::None)
454
+ try { $finalStream.Write($receiptBytes,0,$receiptBytes.Length);$finalStream.Flush($true) } finally { $finalStream.Dispose() }
455
+ Move-InstallFile -Source $stagedReceipt -Destination $receiptPath -Replace $true
456
+ $stagedReceipt = $null
457
+ [IO.File]::Delete($pendingReceiptPath)
458
+ Write-Output "installed hive $Version to $binDirectory\hive.exe"
459
+ } finally {
460
+ if ($null -ne $receiptStream) { $receiptStream.Dispose() }
461
+ foreach ($stagedPath in @($stagedBinary, $stagedReceipt)) {
462
+ if ($null -ne $stagedPath -and (Test-Path -LiteralPath $stagedPath)) {
463
+ Remove-Item -LiteralPath $stagedPath -Force
464
+ }
465
+ }
466
+ }
467
+ }
468
+
341
469
  $npmPackage = "win32-x64"
342
470
  $archive = "$npmPackage-$PackageVersion.tgz"
343
471
  $base = "https://registry.npmjs.org/@aigent-hive/$npmPackage/-"
344
- $work = Join-Path ([IO.Path]::GetTempPath()) ("aigent-hive-install-" + [Guid]::NewGuid())
472
+ $work = [IO.Path]::Combine([IO.Path]::GetTempPath(), ("aigent-hive-install-" + [Guid]::NewGuid()))
345
473
  New-Item -ItemType Directory -Path $work | Out-Null
346
- $stagedBinary = $null
347
- $stagedReceipt = $null
348
474
  try {
349
- $archivePath = Join-Path $work $archive
475
+ $archivePath = [IO.Path]::Combine($work, $archive)
350
476
  Invoke-WebRequest -UseBasicParsing -Uri "$base/$archive" -OutFile $archivePath
351
477
  $actual = Get-FileSha256 -Path $archivePath
352
478
  if ($ExpectedArchiveSha256 -ne $actual) {
@@ -386,7 +512,7 @@ try {
386
512
  if ($LASTEXITCODE -ne 0) {
387
513
  throw "release archive could not be extracted"
388
514
  }
389
- $binary = Join-Path $work "package\bin\hive.exe"
515
+ $binary = [IO.Path]::Combine($work, "package\bin\hive.exe")
390
516
  if ($AuthorizedSignerThumbprint -ne "") {
391
517
  $signature = Get-AuthenticodeSignature -LiteralPath $binary
392
518
  Assert-AuthorizedAuthenticodeSignature `
@@ -401,79 +527,10 @@ try {
401
527
  throw "signed binary version differs from requested release"
402
528
  }
403
529
 
404
- $binDirectory = Join-Path $Prefix "bin"
405
- $shareDirectory = Join-Path $Prefix "share\aigent-hive"
406
- Assert-SafeDirectoryChain -Path $Prefix
407
- Assert-SafeDirectoryChain -Path $binDirectory
408
- Assert-SafeDirectoryChain -Path $shareDirectory
409
- $destination = Join-Path $binDirectory "hive.exe"
410
- $receiptPath = Join-Path $shareDirectory "install-receipt.json"
411
- $pendingReceiptPath = Join-Path $shareDirectory "install-receipt.pending.json"
412
- Repair-PendingDirectInstall `
413
- -Destination $destination `
414
- -ReceiptPath $receiptPath `
415
- -PendingReceiptPath $pendingReceiptPath
416
- Assert-ExistingDirectInstall -Destination $destination -ReceiptPath $receiptPath
417
- $stagedBinary = Join-Path $binDirectory (".hive-install-" + [Guid]::NewGuid())
418
- $stagedReceipt = Join-Path $shareDirectory (".install-receipt-" + [Guid]::NewGuid())
419
- Assert-SafeDirectoryChain -Path $binDirectory
420
- Assert-SafeDirectoryChain -Path $shareDirectory
421
- [IO.File]::Copy($binary, $stagedBinary, $false)
422
- $binaryDigest = Get-FileSha256 -Path $binary
423
- $receiptJson = @{
424
- schema_version = 1
425
- owner = "direct"
426
- product = "aigent-hive"
427
- version = $Version
428
- package_version = $PackageVersion
429
- artifact_sha256 = "sha256:$binaryDigest"
430
- } | ConvertTo-Json -Compress
431
- $receiptBytes = [Text.UTF8Encoding]::new($false).GetBytes($receiptJson)
432
- $receiptStream = [IO.File]::Open(
433
- $stagedReceipt,
434
- [IO.FileMode]::CreateNew,
435
- [IO.FileAccess]::Write,
436
- [IO.FileShare]::None
437
- )
438
- try {
439
- $receiptStream.Write($receiptBytes, 0, $receiptBytes.Length)
440
- }
441
- finally {
442
- $receiptStream.Dispose()
443
- }
444
- Assert-SafeDirectoryChain -Path $binDirectory
445
- Assert-SafeDirectoryChain -Path $shareDirectory
446
- if ($null -ne (
447
- Get-Item -LiteralPath $pendingReceiptPath -Force -ErrorAction SilentlyContinue
448
- )) {
449
- throw "existing hive install transaction is not recoverable"
450
- }
451
- Move-InstallFile `
452
- -Source $stagedReceipt `
453
- -Destination $pendingReceiptPath `
454
- -Replace $false
455
- $stagedReceipt = $null
456
- Assert-SafeDirectoryChain -Path $binDirectory
457
- Assert-SafeDirectoryChain -Path $shareDirectory
458
- Move-InstallFile `
459
- -Source $stagedBinary `
460
- -Destination $destination `
461
- -Replace $true
462
- $stagedBinary = $null
463
- Assert-SafeDirectoryChain -Path $binDirectory
464
- Assert-SafeDirectoryChain -Path $shareDirectory
465
- Move-InstallFile `
466
- -Source $pendingReceiptPath `
467
- -Destination $receiptPath `
468
- -Replace $true
469
- Write-Output "installed hive $Version to $binDirectory\hive.exe"
530
+ Publish-DirectInstall -Binary $binary -Prefix $Prefix -Version $Version `
531
+ -PackageVersion $PackageVersion -DeferLockedBackup:$DeferLockedBackup
470
532
  }
471
533
  finally {
472
- foreach ($stagedPath in @($stagedBinary, $stagedReceipt)) {
473
- if ($null -ne $stagedPath -and (Test-Path -LiteralPath $stagedPath)) {
474
- Remove-Item -LiteralPath $stagedPath -Force
475
- }
476
- }
477
534
  if (Test-Path -LiteralPath $work) {
478
535
  Remove-Item -LiteralPath $work -Recurse -Force
479
536
  }
package/install.sh CHANGED
@@ -1,16 +1,16 @@
1
1
  #!/bin/sh
2
2
  set -eu
3
3
 
4
- embedded_product_version='0.13.2'
5
- embedded_package_version='0.13.2-test.2'
4
+ embedded_product_version='0.14.0'
5
+ embedded_package_version='0.14.0-test.2'
6
6
  version=${AIGENT_HIVE_VERSION:-$embedded_product_version}
7
7
  package_version=${AIGENT_HIVE_PACKAGE_VERSION:-$embedded_package_version}
8
8
  prefix=${AIGENT_HIVE_PREFIX:-"${HOME:?HOME is required}/.local"}
9
9
  authorized_team_id=''
10
- sha_aarch64_apple_darwin='574c667885808a849fefe6e27fd67f202424dad55f1b7b809112f785c1b02112'
11
- sha_x86_64_apple_darwin='a9eae4f2a1f1758378d03eff5fb5517e4d6c2175b1a5515854a49aad18d7631a'
12
- sha_aarch64_linux_musl='27f451fc7361e90ce566ac592a3d625874332e20a56f29c8c476f1543d782349'
13
- sha_x86_64_linux_musl='13ced41f3f49747a7c7b60fb9eea319a6577dc9fb2eaca3ee1cdfe3ed9b223fd'
10
+ sha_aarch64_apple_darwin='bd92c58338f57a029ae380b141ea7f0c5e7bf8ac9fd8473a84b5ca3590eaef93'
11
+ sha_x86_64_apple_darwin='b31896cf246dca2e20f1489a686580c0e0f417b5d53f10b4daf19f1f6db69ada'
12
+ sha_aarch64_linux_musl='95ca8d2012aefd88008266f45725c8c7a13f14789e390d39d7ea07c32dd1c2eb'
13
+ sha_x86_64_linux_musl='511d40d44f4757a0dbf3d255236ad89a3ee18f593dd8f2b4d458810ed06af09b'
14
14
 
15
15
  if ! printf '%s\n' "$version" | awk -F. '
16
16
  NF != 3 { exit 1 }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "aigent-hive",
3
- "version": "0.13.2-test.2",
3
+ "version": "0.14.0-test.2",
4
4
  "aigentHive": {
5
- "productVersion": "0.13.2"
5
+ "productVersion": "0.14.0"
6
6
  },
7
7
  "description": "Provider-neutral local agent harness for subscription-authenticated hosts",
8
8
  "license": "Apache-2.0",
@@ -31,10 +31,10 @@
31
31
  "node": ">=18"
32
32
  },
33
33
  "optionalDependencies": {
34
- "@aigent-hive/darwin-arm64": "0.13.2-test.2",
35
- "@aigent-hive/darwin-x64": "0.13.2-test.2",
36
- "@aigent-hive/linux-arm64": "0.13.2-test.2",
37
- "@aigent-hive/linux-x64": "0.13.2-test.2",
38
- "@aigent-hive/win32-x64": "0.13.2-test.2"
34
+ "@aigent-hive/darwin-arm64": "0.14.0-test.2",
35
+ "@aigent-hive/darwin-x64": "0.14.0-test.2",
36
+ "@aigent-hive/linux-arm64": "0.14.0-test.2",
37
+ "@aigent-hive/linux-x64": "0.14.0-test.2",
38
+ "@aigent-hive/win32-x64": "0.14.0-test.2"
39
39
  }
40
40
  }