deadbyte-mcp 0.11.3 → 0.13.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.
Files changed (127) hide show
  1. package/MANIFEST.SHA256 +126 -54
  2. package/R41-PARENT.json +15 -0
  3. package/README.txt +5 -4
  4. package/acceptance/r40/desktop-live-drift.mjs +106 -0
  5. package/acceptance/r40/desktop-live-ground.mjs +110 -0
  6. package/acceptance/r40/desktop-live-input.mjs +128 -0
  7. package/acceptance/r40/desktop-live-observe.mjs +100 -0
  8. package/acceptance/r40/desktop-live-uia.mjs +121 -0
  9. package/bin/appcontainer-stage.obj +0 -0
  10. package/bin/bootstrap-advapi32.obj +0 -0
  11. package/bin/bootstrap-exitcode.obj +0 -0
  12. package/bin/bootstrap-kernel32.obj +0 -0
  13. package/bin/child-control-probe.obj +0 -0
  14. package/bin/child-control-stage.obj +0 -0
  15. package/bin/contained-reverse-worker.obj +0 -0
  16. package/bin/contained-transform-worker.obj +0 -0
  17. package/bin/containment-probe.obj +0 -0
  18. package/bin/deadbyte-contain.obj +0 -0
  19. package/bin/deadbyte-desktop-input-r40.exe +0 -0
  20. package/bin/deadbyte-desktop-input-r40.obj +0 -0
  21. package/bin/deadbyte-desktop-observer-r40.exe +0 -0
  22. package/bin/deadbyte-desktop-observer-r40.obj +0 -0
  23. package/bin/deadbyte-desktop-uia-r40.exe +0 -0
  24. package/bin/deadbyte-desktop-uia-r40.obj +0 -0
  25. package/bin/deadbyte-exec.obj +0 -0
  26. package/bin/deadbyte-process-host.obj +0 -0
  27. package/bin/deadbyte-tunnel-host.obj +0 -0
  28. package/controller/README.TXT +7 -5
  29. package/controller/deadbyte-controller.config.psd1.example +3 -0
  30. package/controller/deadbyte-controller.ps1 +149 -4
  31. package/controller/deadbyte-desktop-policy.json +41 -0
  32. package/controller/deadbyte-process-policy.json +4 -4
  33. package/docs/ARCHITECTURE.md +6 -1
  34. package/docs/superpowers/specs/2026-09-19-r40-desktop-computer-use-design.md +214 -0
  35. package/docs/superpowers/specs/2026-09-20-r41-deterministic-memory-design.md +132 -0
  36. package/native/deadbyte-desktop-input.cpp +455 -0
  37. package/native/deadbyte-desktop-observer.cpp +253 -0
  38. package/native/deadbyte-desktop-uia.cpp +307 -0
  39. package/package.json +12 -8
  40. package/proof/CONTAINMENT-BUILD.txt +6 -6
  41. package/scripts/build-containment.ps1 +24 -14
  42. package/scripts/build-desktop-r40.ps1 +112 -0
  43. package/scripts/deferred-slot-operation-r40.mjs +126 -0
  44. package/scripts/deferred-slot-operation-r41.mjs +127 -0
  45. package/scripts/final-closure-r40.mjs +114 -0
  46. package/scripts/final-closure-r41.mjs +116 -0
  47. package/scripts/final-closure-verify-r40.mjs +212 -0
  48. package/scripts/final-closure-verify-r41.mjs +215 -0
  49. package/scripts/gate-windows-r40.ps1 +43 -0
  50. package/scripts/gate-windows-r41.ps1 +48 -0
  51. package/scripts/init-desktop-policy-r40.ps1 +85 -0
  52. package/scripts/r40-compact-ledger-probe.mjs +4 -0
  53. package/scripts/release-parity-r40.mjs +212 -0
  54. package/scripts/release-parity-r41.mjs +221 -0
  55. package/scripts/release-parity-tests-r40.ps1 +9 -0
  56. package/scripts/release-parity-tests-r41.ps1 +9 -0
  57. package/scripts/verify-memory-r41.mjs +88 -0
  58. package/scripts/verify-r41-parent.mjs +61 -0
  59. package/scripts/windows-gate-evidence-r40.mjs +52 -0
  60. package/scripts/windows-gate-evidence-r41.mjs +53 -0
  61. package/src/autonomous-context-engine.mjs +3 -1
  62. package/src/autonomous-planner-contracts.mjs +19 -1
  63. package/src/autonomous-planner.mjs +24 -0
  64. package/src/autonomous-runtime.mjs +164 -25
  65. package/src/capability-ledger.mjs +6 -1
  66. package/src/compact-gateway-mcp-tools.mjs +14 -2
  67. package/src/deadbyte-cli.mjs +72 -44
  68. package/src/desktop-contract.mjs +263 -0
  69. package/src/desktop-input-r40.mjs +148 -0
  70. package/src/desktop-mcp-tools-r40.mjs +126 -0
  71. package/src/desktop-memory-r40.mjs +272 -0
  72. package/src/desktop-observer-r40.mjs +231 -0
  73. package/src/desktop-policy-r40.mjs +110 -0
  74. package/src/desktop-runtime-r40.mjs +318 -0
  75. package/src/desktop-uia-r40.mjs +123 -0
  76. package/src/mcp-server.mjs +87 -19
  77. package/src/memory-r41.mjs +692 -0
  78. package/src/r40-compact-disarmed-probe.mjs +71 -0
  79. package/src/r40-full-surface-probe.mjs +34 -0
  80. package/src/release-generation.mjs +38 -5
  81. package/src/remote-console.mjs +41 -0
  82. package/src/remote-live-log.mjs +208 -45
  83. package/src/remote-mcp-desktop-r40-smoke-client.mjs +70 -0
  84. package/src/remote-mcp-r40-parity-client.mjs +200 -0
  85. package/src/remote-mcp-smoke-client.mjs +20 -6
  86. package/src/remote-result-journal.mjs +10 -2
  87. package/src/runtime-update.mjs +55 -17
  88. package/src/tool-audit.mjs +29 -2
  89. package/src/version.mjs +1 -1
  90. package/test/autonomous-capability-r36.test.mjs +43 -1
  91. package/test/autonomous-desktop-r40.test.mjs +188 -0
  92. package/test/capability-ledger-r36.test.mjs +1 -0
  93. package/test/cli-entrypoint.test.mjs +1 -1
  94. package/test/compact-catalog-r36.test.mjs +2 -2
  95. package/test/compact-gateway-r36.test.mjs +56 -4
  96. package/test/compact-max-catalog-r40.test.mjs +95 -0
  97. package/test/controller-desktop-r40.test.mjs +86 -0
  98. package/test/core.test.mjs +1 -1
  99. package/test/desktop-adversarial-r40.test.mjs +62 -0
  100. package/test/desktop-contract-r40.test.mjs +200 -0
  101. package/test/desktop-input-r40.test.mjs +63 -0
  102. package/test/desktop-mcp-tools-r40.test.mjs +61 -0
  103. package/test/desktop-memory-r40.test.mjs +141 -0
  104. package/test/desktop-observer-r40.test.mjs +119 -0
  105. package/test/desktop-policy-r40.test.mjs +111 -0
  106. package/test/desktop-runtime-r40.test.mjs +278 -0
  107. package/test/desktop-uia-r40.test.mjs +42 -0
  108. package/test/full-max-catalog-r40.test.mjs +91 -0
  109. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  110. package/test/memory-autonomous-integration-r41.test.mjs +31 -0
  111. package/test/memory-history-r41.test.mjs +126 -0
  112. package/test/memory-projections-r41.test.mjs +92 -0
  113. package/test/memory-retrieval-r41.test.mjs +124 -0
  114. package/test/memory-snapshot-r41.test.mjs +106 -0
  115. package/test/r33-closeout-regression.test.mjs +7 -7
  116. package/test/r33-finalization.test.mjs +15 -15
  117. package/test/r37-remote-tool-call-timeline.test.mjs +6 -5
  118. package/test/r40-finalization.test.mjs +118 -0
  119. package/test/r41-finalization.test.mjs +38 -0
  120. package/test/release-generation.test.mjs +41 -9
  121. package/test/release-version.test.mjs +20 -61
  122. package/test/remote-console-r40.test.mjs +38 -0
  123. package/test/remote-live-log-r37.test.mjs +89 -32
  124. package/test/remote-r24-catalog.test.mjs +12 -3
  125. package/test/remote-result-journal.test.mjs +15 -0
  126. package/test/remote-session-cli.test.mjs +69 -46
  127. package/test/runtime-self-update.test.mjs +44 -0
@@ -1,6 +1,16 @@
1
1
  $ErrorActionPreference = 'Stop'
2
2
  Set-StrictMode -Version Latest
3
3
 
4
+ function Get-Sha256Hex {
5
+ param([Parameter(Mandatory=$true)][string]$Path)
6
+ $Stream = [System.IO.File]::OpenRead([System.IO.Path]::GetFullPath($Path))
7
+ try {
8
+ $Hasher = [System.Security.Cryptography.SHA256]::Create()
9
+ try { return ([System.BitConverter]::ToString($Hasher.ComputeHash($Stream))).Replace('-', '').ToLowerInvariant() }
10
+ finally { $Hasher.Dispose() }
11
+ } finally { $Stream.Dispose() }
12
+ }
13
+
4
14
  $Root = Split-Path -Parent $PSScriptRoot
5
15
  $Bin = Join-Path $Root 'bin'
6
16
  $Native = Join-Path $Root 'native'
@@ -209,19 +219,19 @@ if (-not (Test-Path -LiteralPath $ContainedReverseWorkerExe)) { throw "contained
209
219
  if (-not (Test-Path -LiteralPath $TunnelHostExe)) { throw "named tunnel host executable missing after successful compile: $TunnelHostExe" }
210
220
  if (-not (Test-Path -LiteralPath $ProcessHostExe)) { throw "process host executable missing after successful compile: $ProcessHostExe" }
211
221
 
212
- $LauncherHash = (Get-FileHash -LiteralPath $LauncherExe -Algorithm SHA256).Hash.ToLowerInvariant()
213
- $ProbeHash = (Get-FileHash -LiteralPath $ProbeExe -Algorithm SHA256).Hash.ToLowerInvariant()
214
- $BootstrapKernelHash = (Get-FileHash -LiteralPath $BootstrapKernelExe -Algorithm SHA256).Hash.ToLowerInvariant()
215
- $BootstrapAdvapiHash = (Get-FileHash -LiteralPath $BootstrapAdvapiExe -Algorithm SHA256).Hash.ToLowerInvariant()
216
- $StageLauncherHash = (Get-FileHash -LiteralPath $StageLauncherExe -Algorithm SHA256).Hash.ToLowerInvariant()
217
- $BootstrapExitHash = (Get-FileHash -LiteralPath $BootstrapExitExe -Algorithm SHA256).Hash.ToLowerInvariant()
218
- $ChildControlStageHash = (Get-FileHash -LiteralPath $ChildControlStageExe -Algorithm SHA256).Hash.ToLowerInvariant()
219
- $ChildControlProbeHash = (Get-FileHash -LiteralPath $ChildControlProbeExe -Algorithm SHA256).Hash.ToLowerInvariant()
220
- $ContainedLauncherHash = (Get-FileHash -LiteralPath $ContainedLauncherExe -Algorithm SHA256).Hash.ToLowerInvariant()
221
- $ContainedWorkerHash = (Get-FileHash -LiteralPath $ContainedWorkerExe -Algorithm SHA256).Hash.ToLowerInvariant()
222
- $ContainedReverseWorkerHash = (Get-FileHash -LiteralPath $ContainedReverseWorkerExe -Algorithm SHA256).Hash.ToLowerInvariant()
223
- $TunnelHostHash = (Get-FileHash -LiteralPath $TunnelHostExe -Algorithm SHA256).Hash.ToLowerInvariant()
224
- $ProcessHostHash = (Get-FileHash -LiteralPath $ProcessHostExe -Algorithm SHA256).Hash.ToLowerInvariant()
222
+ $LauncherHash = Get-Sha256Hex -Path $LauncherExe
223
+ $ProbeHash = Get-Sha256Hex -Path $ProbeExe
224
+ $BootstrapKernelHash = Get-Sha256Hex -Path $BootstrapKernelExe
225
+ $BootstrapAdvapiHash = Get-Sha256Hex -Path $BootstrapAdvapiExe
226
+ $StageLauncherHash = Get-Sha256Hex -Path $StageLauncherExe
227
+ $BootstrapExitHash = Get-Sha256Hex -Path $BootstrapExitExe
228
+ $ChildControlStageHash = Get-Sha256Hex -Path $ChildControlStageExe
229
+ $ChildControlProbeHash = Get-Sha256Hex -Path $ChildControlProbeExe
230
+ $ContainedLauncherHash = Get-Sha256Hex -Path $ContainedLauncherExe
231
+ $ContainedWorkerHash = Get-Sha256Hex -Path $ContainedWorkerExe
232
+ $ContainedReverseWorkerHash = Get-Sha256Hex -Path $ContainedReverseWorkerExe
233
+ $TunnelHostHash = Get-Sha256Hex -Path $TunnelHostExe
234
+ $ProcessHostHash = Get-Sha256Hex -Path $ProcessHostExe
225
235
 
226
236
  $WorkerRegistryLines = @(
227
237
  'schema=deadbyte.worker-registry.v1',
@@ -239,7 +249,7 @@ $WorkerRegistryLines = @(
239
249
  )
240
250
  $Utf8NoBom = New-Object System.Text.UTF8Encoding($false)
241
251
  [System.IO.File]::WriteAllText($WorkerRegistryManifest, (($WorkerRegistryLines -join "`n") + "`n"), $Utf8NoBom)
242
- $WorkerRegistryManifestHash = (Get-FileHash -LiteralPath $WorkerRegistryManifest -Algorithm SHA256).Hash.ToLowerInvariant()
252
+ $WorkerRegistryManifestHash = Get-Sha256Hex -Path $WorkerRegistryManifest
243
253
 
244
254
  [ordered]@{
245
255
  status = 'built'
@@ -0,0 +1,112 @@
1
+ $ErrorActionPreference='Stop'
2
+ Set-StrictMode -Version Latest
3
+ function Get-Sha256Hex {
4
+ param([Parameter(Mandatory=$true)][string]$Path)
5
+ $Stream=[System.IO.File]::OpenRead([System.IO.Path]::GetFullPath($Path))
6
+ try{$Hasher=[System.Security.Cryptography.SHA256]::Create();try{return ([System.BitConverter]::ToString($Hasher.ComputeHash($Stream))).Replace('-','').ToLowerInvariant()}finally{$Hasher.Dispose()}}
7
+ finally{$Stream.Dispose()}
8
+ }
9
+
10
+ $Root=Split-Path -Parent $PSScriptRoot
11
+ $Src=Join-Path $Root 'native\deadbyte-desktop-observer.cpp'
12
+ $InputSrc=Join-Path $Root 'native\deadbyte-desktop-input.cpp'
13
+ $UiaSrc=Join-Path $Root 'native\deadbyte-desktop-uia.cpp'
14
+ $Bin=Join-Path $Root 'bin'
15
+ $Exe=Join-Path $Bin 'deadbyte-desktop-observer-r40.exe'
16
+ $Obj=Join-Path $Bin 'deadbyte-desktop-observer-r40.obj'
17
+ $InputExe=Join-Path $Bin 'deadbyte-desktop-input-r40.exe'
18
+ $InputObj=Join-Path $Bin 'deadbyte-desktop-input-r40.obj'
19
+ $UiaExe=Join-Path $Bin 'deadbyte-desktop-uia-r40.exe'
20
+ $UiaObj=Join-Path $Bin 'deadbyte-desktop-uia-r40.obj'
21
+ New-Item -ItemType Directory -Force -Path $Bin | Out-Null
22
+
23
+ $vswhere='C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe'
24
+ if(-not (Test-Path -LiteralPath $vswhere)){throw 'vswhere.exe not found'}
25
+ $install=(& $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath | Select-Object -First 1)
26
+ if(-not $install){throw 'MSVC x64 C++ toolchain not found'}
27
+ $dev=Join-Path $install 'Common7\Tools\VsDevCmd.bat'
28
+ if(-not (Test-Path -LiteralPath $dev)){throw "VsDevCmd.bat missing: $dev"}
29
+ $cmd=if($env:ComSpec){$env:ComSpec}else{Join-Path $env:SystemRoot 'System32\cmd.exe'}
30
+
31
+ Remove-Item -Force -ErrorAction SilentlyContinue $Exe,$Obj,$InputExe,$InputObj,$UiaExe,$UiaObj
32
+ $common='/nologo /std:c++17 /permissive- /W4 /WX /O2 /MT /EHsc /guard:cf /diagnostics:caret /FC /utf-8 /Brepro /DUNICODE /D_UNICODE /D_WIN32_WINNT=0x0A00 /DWINVER=0x0A00'
33
+ $compile='cl {0} "{1}" /Fo:"{2}" /Fe:"{3}" user32.lib gdi32.lib /link /Brepro /INCREMENTAL:NO' -f $common,$Src,$Obj,$Exe
34
+ $line='call "{0}" -no_logo -arch=x64 -host_arch=x64 && {1}' -f $dev,$compile
35
+ $out=& $cmd /d /s /c $line 2>&1
36
+ $exit=$LASTEXITCODE
37
+ $out | ForEach-Object { Write-Host ([string]$_) }
38
+ if($exit -ne 0){throw "desktop observer compile failed exit=$exit"}
39
+ if(-not (Test-Path -LiteralPath $Exe -PathType Leaf)){throw 'desktop observer exe missing after compile'}
40
+
41
+ $inputCompile='cl {0} "{1}" /Fo:"{2}" /Fe:"{3}" user32.lib /link /Brepro /INCREMENTAL:NO' -f $common,$InputSrc,$InputObj,$InputExe
42
+ $inputLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && {1}' -f $dev,$inputCompile
43
+ $inputOut=& $cmd /d /s /c $inputLine 2>&1
44
+ $inputExit=$LASTEXITCODE
45
+ $inputOut | ForEach-Object { Write-Host ([string]$_) }
46
+ if($inputExit -ne 0){throw "desktop input compile failed exit=$inputExit"}
47
+ if(-not (Test-Path -LiteralPath $InputExe -PathType Leaf)){throw 'desktop input exe missing after compile'}
48
+
49
+ $uiaCompile='cl {0} "{1}" /Fo:"{2}" /Fe:"{3}" user32.lib ole32.lib oleaut32.lib uiautomationcore.lib /link /Brepro /INCREMENTAL:NO' -f $common,$UiaSrc,$UiaObj,$UiaExe
50
+ $uiaLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && {1}' -f $dev,$uiaCompile
51
+ $uiaOut=& $cmd /d /s /c $uiaLine 2>&1
52
+ $uiaExit=$LASTEXITCODE
53
+ $uiaOut | ForEach-Object { Write-Host ([string]$_) }
54
+ if($uiaExit -ne 0){throw "desktop UIA compile failed exit=$uiaExit"}
55
+ if(-not (Test-Path -LiteralPath $UiaExe -PathType Leaf)){throw 'desktop UIA exe missing after compile'}
56
+
57
+ $selfTest=& $InputExe --selftest 2>&1
58
+ $selfExit=$LASTEXITCODE
59
+ $selfTest | ForEach-Object { Write-Host ([string]$_) }
60
+ if($selfExit -ne 0){throw "desktop input selftest failed exit=$selfExit"}
61
+ if(-not (($selfTest -join [Environment]::NewLine) -match '"status":"passed"')){throw 'desktop input selftest did not report pass'}
62
+
63
+ $uiaSelfTest=& $UiaExe --selftest 2>&1
64
+ $uiaSelfExit=$LASTEXITCODE
65
+ $uiaSelfTest | ForEach-Object { Write-Host ([string]$_) }
66
+ if($uiaSelfExit -ne 0){throw "desktop UIA selftest failed exit=$uiaSelfExit"}
67
+ if(-not (($uiaSelfTest -join [Environment]::NewLine) -match '"status":"passed"')){throw 'desktop UIA selftest did not report pass'}
68
+
69
+ $depLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && dumpbin /nologo /dependents "{1}"' -f $dev,$Exe
70
+ $deps=& $cmd /d /s /c $depLine 2>&1
71
+ $depExit=$LASTEXITCODE
72
+ $deps | ForEach-Object { Write-Host ([string]$_) }
73
+ if($depExit -ne 0){throw "observer dumpbin failed exit=$depExit"}
74
+
75
+ $inputDepLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && dumpbin /nologo /dependents "{1}"' -f $dev,$InputExe
76
+ $inputDeps=& $cmd /d /s /c $inputDepLine 2>&1
77
+ $inputDepExit=$LASTEXITCODE
78
+ $inputDeps | ForEach-Object { Write-Host ([string]$_) }
79
+ if($inputDepExit -ne 0){throw "input dumpbin failed exit=$inputDepExit"}
80
+
81
+ $uiaDepLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && dumpbin /nologo /dependents "{1}"' -f $dev,$UiaExe
82
+ $uiaDeps=& $cmd /d /s /c $uiaDepLine 2>&1
83
+ $uiaDepExit=$LASTEXITCODE
84
+ $uiaDeps | ForEach-Object { Write-Host ([string]$_) }
85
+ if($uiaDepExit -ne 0){throw "UIA dumpbin failed exit=$uiaDepExit"}
86
+
87
+ [pscustomobject]@{
88
+ status='built'
89
+ observer=[ordered]@{
90
+ source_sha256=Get-Sha256Hex -Path $Src
91
+ exe=$Exe
92
+ exe_sha256=Get-Sha256Hex -Path $Exe
93
+ obj_sha256=Get-Sha256Hex -Path $Obj
94
+ dependencies=@($deps | ForEach-Object {[string]$_})
95
+ }
96
+ input=[ordered]@{
97
+ source_sha256=Get-Sha256Hex -Path $InputSrc
98
+ exe=$InputExe
99
+ exe_sha256=Get-Sha256Hex -Path $InputExe
100
+ obj_sha256=Get-Sha256Hex -Path $InputObj
101
+ dependencies=@($inputDeps | ForEach-Object {[string]$_})
102
+ selftest=@($selfTest | ForEach-Object {[string]$_})
103
+ }
104
+ uia=[ordered]@{
105
+ source_sha256=Get-Sha256Hex -Path $UiaSrc
106
+ exe=$UiaExe
107
+ exe_sha256=Get-Sha256Hex -Path $UiaExe
108
+ obj_sha256=Get-Sha256Hex -Path $UiaObj
109
+ dependencies=@($uiaDeps | ForEach-Object {[string]$_})
110
+ selftest=@($uiaSelfTest | ForEach-Object {[string]$_})
111
+ }
112
+ }|ConvertTo-Json -Depth 6
@@ -0,0 +1,126 @@
1
+ import { createHash, createPublicKey, randomBytes } from 'node:crypto';
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { parseActivePointer } from '../src/release-slot.mjs';
8
+ import { loadPowerShellDataFile, runSlotUpdateCli, verifySlotUpdateEnvelope } from '../src/runtime-update.mjs';
9
+
10
+ const HEX64=/^[0-9a-f]{64}$/;
11
+ const RECEIPT_ID=/^r27-[A-Za-z0-9-]+$/;
12
+ const here=path.dirname(fileURLToPath(import.meta.url));
13
+ const packageRoot=path.resolve(here,'..');
14
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
15
+ const evidenceRoot=path.join(stateRoot,'evidence','deferred-slot-operations');
16
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
17
+ const atomicJson=async(file,value)=>{
18
+ await mkdir(path.dirname(file),{recursive:true});
19
+ const temp=`${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
20
+ await writeFile(temp,`${JSON.stringify(value,null,2)}\n`,{flag:'wx'});
21
+ await import('node:fs/promises').then(fs=>fs.rename(temp,file));
22
+ };
23
+ function activationArgs(manifestSha){
24
+ if(!HEX64.test(manifestSha??'')) throw new Error('activate requires one lowercase manifest SHA-256');
25
+ return ['--stage',packageRoot,'--development-root',packageRoot,'--expected-version','0.12.0',
26
+ '--expected-manifest',manifestSha,'--process-policy',path.join(packageRoot,'controller','deadbyte-process-policy.json'),
27
+ '--process-policy-sha256',null,'--desktop-policy',path.join(packageRoot,'controller','deadbyte-desktop-policy.json'),
28
+ '--desktop-policy-sha256',null,'--semantic-lsp-config',path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json'),
29
+ '--semantic-lsp-config-sha256',null,'--enable-machine-fs','--enable-observation','--enable-desktop','--enable-autonomous-supervisor'];
30
+ }
31
+ async function bridgeBootstrapArgs(explicitBridgeRoot=null,explicitBridgeSha256=null){
32
+ const hasRoot=typeof explicitBridgeRoot==='string'&&explicitBridgeRoot.length>0;
33
+ const hasSha=typeof explicitBridgeSha256==='string'&&explicitBridgeSha256.length>0;
34
+ if(hasRoot!==hasSha) throw new Error('bridge override requires exact root + SHA pair');
35
+ let bridgeRootRaw,expectedSha256=null;
36
+ if(hasRoot){
37
+ if(!path.isAbsolute(explicitBridgeRoot)||!HEX64.test(explicitBridgeSha256)) throw new Error('bridge override requires exact root + SHA pair');
38
+ bridgeRootRaw=explicitBridgeRoot;expectedSha256=explicitBridgeSha256;
39
+ }else{
40
+ const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
41
+ const config=await loadPowerShellDataFile(pointer.config_path);
42
+ bridgeRootRaw=config?.Bridge?.WorkingDirectory;
43
+ if(typeof bridgeRootRaw!=='string'||!path.isAbsolute(bridgeRootRaw)) throw new Error('active controller Bridge.WorkingDirectory must be absolute');
44
+ }
45
+ const bridgeRoot=await realpath(path.resolve(bridgeRootRaw));
46
+ const packageFile=path.join(bridgeRoot,'package.json');
47
+ const bridgeScript=path.join(bridgeRoot,'src','bridge.mjs');
48
+ const pkg=JSON.parse(await readFile(packageFile,'utf8'));
49
+ if(pkg?.name!=='deadbyte-chatgpt-bridge') throw new Error('active Bridge package identity mismatch');
50
+ const scriptSha256=sha256(await readFile(bridgeScript));
51
+ if(expectedSha256&&scriptSha256!==expectedSha256) throw new Error('bridge override SHA-256 mismatch');
52
+ return ['--bridge-root',bridgeRoot,'--bridge-script-sha256',scriptSha256];
53
+ }
54
+ async function rollbackArgs(receiptPath){
55
+ const resolved=await realpath(path.resolve(receiptPath));
56
+ const allowed=path.join(stateRoot,'evidence','updates')+path.sep;
57
+ if(!resolved.startsWith(allowed)||path.basename(resolved).toLowerCase()!=='receipt.json'||!RECEIPT_ID.test(path.basename(path.dirname(resolved)))) {
58
+ throw new Error('rollback receipt must be one signed activation receipt under the update evidence store');
59
+ }
60
+ const envelope=JSON.parse(await readFile(resolved,'utf8'));
61
+ const publicKey=createPublicKey(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
62
+ if(!verifySlotUpdateEnvelope(envelope,publicKey)||envelope.body?.rollback_performed!==false) throw new Error('rollback activation receipt verification failed');
63
+ const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
64
+ if(pointer.release_id!==envelope.body?.active_pointer?.release_id||pointer.generation_root!==envelope.body?.active_pointer?.generation_root) {
65
+ throw new Error('rollback receipt does not identify the active release generation');
66
+ }
67
+ return ['--rollback-receipt',resolved];
68
+ }
69
+ async function normalizedArgs(mode,value,{explicitBridgeRoot=null,explicitBridgeSha256=null}={}){
70
+ if(mode==='activate'){
71
+ const args=activationArgs(value);
72
+ args[args.indexOf('--process-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-process-policy.json')));
73
+ args[args.indexOf('--desktop-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-desktop-policy.json')));
74
+ args[args.indexOf('--semantic-lsp-config-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json')));
75
+ args.push(...await bridgeBootstrapArgs(explicitBridgeRoot,explicitBridgeSha256));
76
+ return args;
77
+ }
78
+ if(mode==='rollback'){
79
+ if(explicitBridgeRoot||explicitBridgeSha256) throw new Error('rollback does not accept bridge override');
80
+ return rollbackArgs(value);
81
+ }
82
+ throw new Error("operation must be exactly 'activate' or 'rollback'");
83
+ }
84
+ const rawArgs=process.argv.slice(2);
85
+ const mode=rawArgs[0],value=rawArgs[1];
86
+ if(!value||!['activate','rollback'].includes(mode)) throw new Error('usage: deferred-slot-operation-r40.mjs <activate manifest_sha256|rollback activation_receipt> [--bridge-root ABS --bridge-script-sha256 HEX64]');
87
+ let cursor=2,explicitBridgeRoot=null,explicitBridgeSha256=null;
88
+ if(rawArgs[cursor]==='--bridge-root'){
89
+ explicitBridgeRoot=rawArgs[cursor+1]??null;
90
+ if(rawArgs[cursor+2]!=='--bridge-script-sha256') throw new Error('bridge override requires exact root + SHA pair');
91
+ explicitBridgeSha256=rawArgs[cursor+3]??null;cursor+=4;
92
+ }
93
+ let workerFlag=null,operationIdArg=null;
94
+ if(rawArgs[cursor]==='--worker'){workerFlag='--worker';operationIdArg=rawArgs[cursor+1]??null;cursor+=2;}
95
+ if(cursor!==rawArgs.length) throw new Error('deferred slot operation arguments invalid');
96
+ if((explicitBridgeRoot===null)!==(explicitBridgeSha256===null)) throw new Error('bridge override requires exact root + SHA pair');
97
+ if(mode==='rollback'&&(explicitBridgeRoot||explicitBridgeSha256)) throw new Error('rollback does not accept bridge override');
98
+ if(workerFlag==='--worker'){
99
+ if(!/^[0-9a-f]{32}$/.test(operationIdArg??'')) throw new Error('deferred worker operation id invalid');
100
+ const statePath=path.join(evidenceRoot,`${operationIdArg}.json`);
101
+ await new Promise(resolve=>setTimeout(resolve,4000));
102
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'running',started_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
103
+ try{
104
+ const args=await normalizedArgs(mode,value,{explicitBridgeRoot,explicitBridgeSha256});
105
+ const result=await runSlotUpdateCli(args,{stateRoot});
106
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'completed',
107
+ completed_at_utc:new Date().toISOString(),receipt_path:result.receipt_path,receipt_sha256:result.receipt_sha256,
108
+ active_release:result.pointer.release_id,generation_root:result.pointer.generation_root,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
109
+ }catch(error){
110
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'failed',
111
+ completed_at_utc:new Date().toISOString(),error:String(error?.message??error),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
112
+ process.exitCode=1;
113
+ }
114
+ }else{
115
+ const operationId=randomBytes(16).toString('hex');
116
+ const statePath=path.join(evidenceRoot,`${operationId}.json`);
117
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationId,mode,state:'scheduled',scheduled_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
118
+ const workerArgs=[fileURLToPath(import.meta.url),mode,value];
119
+ if(explicitBridgeRoot) workerArgs.push('--bridge-root',explicitBridgeRoot,'--bridge-script-sha256',explicitBridgeSha256);
120
+ workerArgs.push('--worker',operationId);
121
+ const child=spawn(process.execPath,workerArgs,{
122
+ cwd:packageRoot,detached:true,stdio:'ignore',windowsHide:true,env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}
123
+ });
124
+ child.unref();
125
+ console.log(JSON.stringify({status:'scheduled',operation_id:operationId,mode,state_path:statePath,execution_provider:'deadbyte_mcp',rdc_operation_count:0,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256}));
126
+ }
@@ -0,0 +1,127 @@
1
+ import { createHash, createPublicKey, randomBytes } from 'node:crypto';
2
+ import { spawn } from 'node:child_process';
3
+ import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { parseActivePointer } from '../src/release-slot.mjs';
8
+ import { loadPowerShellDataFile, runSlotUpdateCli, verifySlotUpdateEnvelope } from '../src/runtime-update.mjs';
9
+
10
+ const HEX64=/^[0-9a-f]{64}$/;
11
+ const RECEIPT_ID=/^r27-[A-Za-z0-9-]+$/;
12
+ const here=path.dirname(fileURLToPath(import.meta.url));
13
+ const packageRoot=path.resolve(here,'..');
14
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
15
+ const evidenceRoot=path.join(stateRoot,'evidence','deferred-slot-operations');
16
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
17
+ const atomicJson=async(file,value)=>{
18
+ await mkdir(path.dirname(file),{recursive:true});
19
+ const temp=`${file}.${process.pid}.${randomBytes(4).toString('hex')}.tmp`;
20
+ await writeFile(temp,`${JSON.stringify(value,null,2)}\n`,{flag:'wx'});
21
+ await import('node:fs/promises').then(fs=>fs.rename(temp,file));
22
+ };
23
+ function activationArgs(manifestSha){
24
+ if(!HEX64.test(manifestSha??'')) throw new Error('activate requires one lowercase manifest SHA-256');
25
+ return ['--stage',packageRoot,'--development-root',packageRoot,'--expected-version','0.13.0',
26
+ '--expected-manifest',manifestSha,'--process-policy',path.join(packageRoot,'controller','deadbyte-process-policy.json'),
27
+ '--process-policy-sha256',null,'--desktop-policy',path.join(packageRoot,'controller','deadbyte-desktop-policy.json'),
28
+ '--desktop-policy-sha256',null,'--semantic-lsp-config',path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json'),
29
+ '--semantic-lsp-config-sha256',null,'--enable-machine-fs','--enable-observation','--enable-desktop','--enable-autonomous-supervisor'];
30
+ }
31
+ async function bridgeBootstrapArgs(explicitBridgeRoot=null,explicitBridgeSha256=null){
32
+ const hasRoot=typeof explicitBridgeRoot==='string'&&explicitBridgeRoot.length>0;
33
+ const hasSha=typeof explicitBridgeSha256==='string'&&explicitBridgeSha256.length>0;
34
+ if(hasRoot!==hasSha) throw new Error('bridge override requires exact root + SHA pair');
35
+ let bridgeRootRaw,expectedSha256=null;
36
+ if(hasRoot){
37
+ if(!path.isAbsolute(explicitBridgeRoot)||!HEX64.test(explicitBridgeSha256)) throw new Error('bridge override requires exact root + SHA pair');
38
+ bridgeRootRaw=explicitBridgeRoot;expectedSha256=explicitBridgeSha256;
39
+ }else{
40
+ const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
41
+ const config=await loadPowerShellDataFile(pointer.config_path);
42
+ bridgeRootRaw=config?.Bridge?.WorkingDirectory;
43
+ if(typeof bridgeRootRaw!=='string'||!path.isAbsolute(bridgeRootRaw)) throw new Error('active controller Bridge.WorkingDirectory must be absolute');
44
+ }
45
+ const bridgeRoot=await realpath(path.resolve(bridgeRootRaw));
46
+ const packageFile=path.join(bridgeRoot,'package.json');
47
+ const bridgeScript=path.join(bridgeRoot,'src','bridge.mjs');
48
+ const pkg=JSON.parse(await readFile(packageFile,'utf8'));
49
+ if(pkg?.name!=='deadbyte-chatgpt-bridge') throw new Error('active Bridge package identity mismatch');
50
+ const scriptSha256=sha256(await readFile(bridgeScript));
51
+ if(expectedSha256&&scriptSha256!==expectedSha256) throw new Error('bridge override SHA-256 mismatch');
52
+ return ['--bridge-root',bridgeRoot,'--bridge-script-sha256',scriptSha256];
53
+ }
54
+ async function rollbackArgs(receiptPath){
55
+ const resolved=await realpath(path.resolve(receiptPath));
56
+ const allowed=path.join(stateRoot,'evidence','updates')+path.sep;
57
+ if(!resolved.startsWith(allowed)||path.basename(resolved).toLowerCase()!=='receipt.json'||!RECEIPT_ID.test(path.basename(path.dirname(resolved)))) {
58
+ throw new Error('rollback receipt must be one signed activation receipt under the update evidence store');
59
+ }
60
+ const envelope=JSON.parse(await readFile(resolved,'utf8'));
61
+ const publicKey=createPublicKey(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
62
+ if(!verifySlotUpdateEnvelope(envelope,publicKey)||envelope.body?.rollback_performed!==false) throw new Error('rollback activation receipt verification failed');
63
+ const pointer=parseActivePointer(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
64
+ if(pointer.release_id!==envelope.body?.active_pointer?.release_id||pointer.generation_root!==envelope.body?.active_pointer?.generation_root) {
65
+ throw new Error('rollback receipt does not identify the active release generation');
66
+ }
67
+ return ['--rollback-receipt',resolved];
68
+ }
69
+ async function normalizedArgs(mode,value,{explicitBridgeRoot=null,explicitBridgeSha256=null}={}){
70
+ if(mode==='activate'){
71
+ const args=activationArgs(value);
72
+ args[args.indexOf('--process-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-process-policy.json')));
73
+ args[args.indexOf('--desktop-policy-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-desktop-policy.json')));
74
+ args[args.indexOf('--semantic-lsp-config-sha256')+1]=sha256(await readFile(path.join(packageRoot,'controller','deadbyte-semantic-lsp-config.json')));
75
+ args.push(...await bridgeBootstrapArgs(explicitBridgeRoot,explicitBridgeSha256));
76
+ return args;
77
+ }
78
+ if(mode==='rollback'){
79
+ if(explicitBridgeRoot||explicitBridgeSha256) throw new Error('rollback does not accept bridge override');
80
+ return rollbackArgs(value);
81
+ }
82
+ throw new Error("operation must be exactly 'activate' or 'rollback'");
83
+ }
84
+ const rawArgs=process.argv.slice(2);
85
+ const mode=rawArgs[0],value=rawArgs[1];
86
+ if(!value||!['activate','rollback'].includes(mode)) throw new Error('usage: deferred-slot-operation-r41.mjs <activate manifest_sha256|rollback activation_receipt> [--bridge-root ABS --bridge-script-sha256 HEX64]');
87
+ let cursor=2,explicitBridgeRoot=null,explicitBridgeSha256=null;
88
+ if(rawArgs[cursor]==='--bridge-root'){
89
+ explicitBridgeRoot=rawArgs[cursor+1]??null;
90
+ if(rawArgs[cursor+2]!=='--bridge-script-sha256') throw new Error('bridge override requires exact root + SHA pair');
91
+ explicitBridgeSha256=rawArgs[cursor+3]??null;cursor+=4;
92
+ }
93
+ let workerFlag=null,operationIdArg=null;
94
+ if(rawArgs[cursor]==='--worker'){workerFlag='--worker';operationIdArg=rawArgs[cursor+1]??null;cursor+=2;}
95
+ if(cursor!==rawArgs.length) throw new Error('deferred slot operation arguments invalid');
96
+ if((explicitBridgeRoot===null)!==(explicitBridgeSha256===null)) throw new Error('bridge override requires exact root + SHA pair');
97
+ if(mode==='rollback'&&(explicitBridgeRoot||explicitBridgeSha256)) throw new Error('rollback does not accept bridge override');
98
+ if(workerFlag==='--worker'){
99
+ if(!/^[0-9a-f]{32}$/.test(operationIdArg??'')) throw new Error('deferred worker operation id invalid');
100
+ const statePath=path.join(evidenceRoot,`${operationIdArg}.json`);
101
+ await new Promise(resolve=>setTimeout(resolve,4000));
102
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'running',started_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
103
+ try{
104
+ const args=await normalizedArgs(mode,value,{explicitBridgeRoot,explicitBridgeSha256});
105
+ const result=await runSlotUpdateCli(args,{stateRoot});
106
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'completed',
107
+ completed_at_utc:new Date().toISOString(),receipt_path:result.receipt_path,receipt_sha256:result.receipt_sha256,
108
+ active_release:result.pointer.release_id,generation_root:result.pointer.generation_root,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
109
+ }catch(error){
110
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationIdArg,mode,state:'failed',
111
+ completed_at_utc:new Date().toISOString(),error:String(error?.message??error),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
112
+ process.exitCode=1;
113
+ }
114
+ }else{
115
+ const operationId=randomBytes(16).toString('hex');
116
+ const statePath=path.join(evidenceRoot,`${operationId}.json`);
117
+ await atomicJson(statePath,{schema:'deadbyte.deferred-slot-operation.v1',operation_id:operationId,mode,state:'scheduled',scheduled_at_utc:new Date().toISOString(),bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256});
118
+ const workerArgs=[fileURLToPath(import.meta.url),mode,value];
119
+ if(explicitBridgeRoot) workerArgs.push('--bridge-root',explicitBridgeRoot,'--bridge-script-sha256',explicitBridgeSha256);
120
+ workerArgs.push('--worker',operationId);
121
+ const child=spawn(process.execPath,workerArgs,{
122
+ cwd:packageRoot,detached:true,stdio:'ignore',windowsHide:true,env:{...process.env,DEADBYTE_STATE_ROOT:stateRoot}
123
+ });
124
+ child.unref();
125
+ console.log(JSON.stringify({status:'scheduled',operation_id:operationId,mode,state_path:statePath,execution_provider:'deadbyte_mcp',rdc_operation_count:0,bridge_root:explicitBridgeRoot,bridge_script_sha256:explicitBridgeSha256}));
126
+ }
127
+
@@ -0,0 +1,114 @@
1
+ import { createHash, createPrivateKey, createPublicKey, sign as cryptoSign } from 'node:crypto';
2
+ import { lstat, mkdir, open, readFile, rename, rm } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { probeR40FullSurface } from '../src/r40-full-surface-probe.mjs';
7
+ import { probeR40CompactDisarmed } from '../src/r40-compact-disarmed-probe.mjs';
8
+ import {
9
+ validateParityEvidence,
10
+ R40_PREDECESSOR_RELEASE_ID,
11
+ R40_PREDECESSOR_MANIFEST
12
+ } from './release-parity-r40.mjs';
13
+
14
+ const DOMAIN=Buffer.from('DEADBYTE-R40-FINAL-CLOSURE-V1\0','utf8');
15
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
16
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
17
+ const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
18
+ ?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
19
+ const canonicalJson=value=>JSON.stringify(canonical(value));
20
+ function insist(ok,msg){if(!ok) throw new Error(msg);}
21
+ function samePath(a,b){return path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();}
22
+ async function fileEvidence(file){const abs=path.resolve(file),bytes=await readFile(abs);return {path:abs,sha256:sha256(bytes)};}
23
+ async function publicUrl(){
24
+ const value=(await readFile(path.join(stateRoot,'bridge','mcp-url.txt'),'utf8')).trim();
25
+ const url=new URL(value);insist(url.protocol==='https:','final closure requires HTTPS public endpoint');return value;
26
+ }
27
+ async function grantAbsence(){
28
+ const out={};
29
+ for(const name of ['process-grant.json','coding-grant.json','autonomous-grant.json','desktop-grant.json','host-grant.json']){
30
+ let absent=false;try{await lstat(path.join(stateRoot,'runtime',name));}catch(error){if(error?.code==='ENOENT') absent=true;else throw error;}
31
+ insist(absent,`authority grant still present: ${name}`);out[name]=true;
32
+ }
33
+ return out;
34
+ }
35
+ async function atomicCreate(file,bytes){
36
+ await mkdir(path.dirname(file),{recursive:true});
37
+ const temp=`${file}.tmp-${process.pid}-${Math.random().toString(16).slice(2)}`;
38
+ const handle=await open(temp,'wx');
39
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
40
+ try{await rename(temp,file);}catch(error){await rm(temp,{force:true}).catch(()=>{});throw error;}
41
+ }
42
+
43
+ export async function writeFinalClosure({parityPath,activationPath,windowsGatePath}){
44
+ const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
45
+ insist(pointer.version==='0.12.0','final closure requires V0.12.0 active release');
46
+ insist(pointer.release_id===`v${pointer.version}-${pointer.manifest_sha256.slice(0,16)}`,'final closure release id/content address mismatch');
47
+
48
+ const parity=JSON.parse(await readFile(path.resolve(parityPath),'utf8'));
49
+ insist(parity.schema==='deadbyte.r40-parity.v1','R40 parity schema mismatch at final closure');
50
+ validateParityEvidence(parity);
51
+ insist(parity.candidate?.release_id===pointer.release_id&&parity.candidate?.manifest_sha256===pointer.manifest_sha256,'parity candidate/current release mismatch');
52
+ insist(parity.successor?.release_id===pointer.release_id&&parity.successor?.manifest_sha256===pointer.manifest_sha256,'parity successor/current release mismatch');
53
+ insist(parity.predecessor?.release_id===R40_PREDECESSOR_RELEASE_ID&&parity.predecessor?.manifest_sha256===R40_PREDECESSOR_MANIFEST,'parity predecessor identity mismatch');
54
+ insist(parity.rollback?.receipt_path&&parity.restore?.receipt_path,'parity rollback/restore receipt paths missing');
55
+ insist(parity.immutable_slot?.protected===true,'parity immutable-slot proof missing');
56
+ insist(samePath(parity.immutable_slot.release_root,pointer.release_root),'parity immutable release root mismatch');
57
+ insist(!samePath(parity.immutable_slot.development_root,pointer.release_root),'development_root must differ from immutable release_root');
58
+
59
+ const windowsGate=JSON.parse(await readFile(path.resolve(windowsGatePath),'utf8'));
60
+ insist(windowsGate.schema==='deadbyte.r40-windows-gate.v1'&&windowsGate.status==='passed'&&windowsGate.exit_code===0,'R40 Windows gate evidence invalid');
61
+ insist(windowsGate.version==='0.12.0'&&windowsGate.manifest_sha256===pointer.manifest_sha256,'R40 Windows gate/current release mismatch');
62
+ insist(windowsGate.marker==='DEADBYTE V0.12.0 / R40 WINDOWS BATCH GATE: PASS','R40 Windows gate marker mismatch');
63
+
64
+ const localFull=await probeR40FullSurface({packageRoot:pointer.release_root,generationRoot:pointer.generation_root,stateRoot});
65
+ insist(localFull.status==='passed'&&localFull.tool_count===80&&localFull.strict_output_schemas===true,'final local full 80-tool proof failed');
66
+ const compact=await probeR40CompactDisarmed(await publicUrl());
67
+ insist(compact.status==='passed'&&compact.tool_count===42&&compact.capability_closure===true,'final public compact capability closure failed');
68
+ insist(compact.coding_armed===false&&compact.autonomous_armed===false&&compact.desktop_armed===false,'final public compact authority is not DISARMED');
69
+ insist(compact.desktop_observation_receipt_verified===true&&compact.desktop_grounding_receipt_verified===true,'final public Desktop read-only proof missing');
70
+ insist(compact.release_id===pointer.release_id&&compact.release_manifest_sha256===pointer.manifest_sha256,'final public compact release binding mismatch');
71
+ insist(compact.machine_status?.release_id===pointer.release_id&&compact.machine_status?.release_manifest_sha256===pointer.manifest_sha256,'final machine status/current release mismatch');
72
+ insist(compact.machine_ping?.nonce===compact.nonce,'final machine ping nonce mismatch');
73
+
74
+ const evidence={
75
+ parity:await fileEvidence(parityPath),activation:await fileEvidence(activationPath),
76
+ rollback:await fileEvidence(parity.rollback.receipt_path),restore:await fileEvidence(parity.restore.receipt_path),
77
+ windows_gate:await fileEvidence(windowsGatePath)
78
+ };
79
+ const body={
80
+ schema:'deadbyte.r40-final-closure.v1',version:'0.12.0',release_label:'R40 FINAL MACHINE BASELINE',
81
+ completed_at_utc:new Date().toISOString(),active_pointer:pointer,
82
+ predecessor:{release_id:R40_PREDECESSOR_RELEASE_ID,version:'0.11.3',manifest_sha256:R40_PREDECESSOR_MANIFEST},
83
+ immutable_slot:{protected:true,release_root:path.resolve(pointer.release_root),development_root:path.resolve(parity.immutable_slot.development_root)},
84
+ surfaces:{
85
+ local_full:{status:localFull.status,profile:localFull.profile,tool_count:localFull.tool_count,catalog_sha256:localFull.catalog_sha256,strict_output_schemas:localFull.strict_output_schemas,protocol_revision:localFull.protocol_revision},
86
+ public_compact:{status:compact.status,profile:compact.profile,tool_count:compact.tool_count,catalog_sha256:compact.catalog_sha256,strict_output_schemas:compact.strict_output_schemas,ledger_sha256:compact.ledger_sha256,capability_count:compact.capability_count,production_non_host_capabilities:compact.production_non_host_capabilities,capability_closure:compact.capability_closure,coding_armed:compact.coding_armed,autonomous_armed:compact.autonomous_armed,desktop_armed:compact.desktop_armed,desktop_observation_receipt_verified:compact.desktop_observation_receipt_verified,desktop_grounding_receipt_verified:compact.desktop_grounding_receipt_verified,protocol_revision:compact.protocol_revision}
87
+ },
88
+ evidence,
89
+ machine:{status:compact.machine_status,ping:compact.machine_ping,nonce:compact.nonce},
90
+ authority:{all_disarmed:true,grants_absent:await grantAbsence()}
91
+ };
92
+ const privateKey=createPrivateKey(await readFile(path.join(stateRoot,'trust','ed25519-private.pem')));
93
+ const publicKey=createPublicKey(privateKey);
94
+ insist(privateKey.asymmetricKeyType==='ed25519'&&publicKey.asymmetricKeyType==='ed25519','closure signing key must be Ed25519');
95
+ const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
96
+ const bodyBytes=Buffer.from(canonicalJson(body),'utf8');
97
+ const signature=cryptoSign(null,Buffer.concat([DOMAIN,bodyBytes]),privateKey);
98
+ const envelope={body,body_sha256:sha256(bodyBytes),attestation:{algorithm:'ed25519',domain:'DEADBYTE-R40-FINAL-CLOSURE-V1',key_id:keyId,signature_base64:signature.toString('base64')}};
99
+ envelope.closure_sha256=sha256(Buffer.from(canonicalJson(envelope),'utf8'));
100
+ const dir=path.join(stateRoot,'evidence','release');
101
+ const file=path.join(dir,`r40-final-${pointer.manifest_sha256.slice(0,16)}.json`);
102
+ const bytes=Buffer.from(`${JSON.stringify(envelope,null,2)}\n`,'utf8');
103
+ await atomicCreate(file,bytes);
104
+ return {status:'written',path:file,sha256:sha256(bytes),closure_sha256:envelope.closure_sha256,release_id:pointer.release_id};
105
+ }
106
+
107
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
108
+ if(invoked){
109
+ const [parityPath,activationPath,windowsGatePath]=process.argv.slice(2);
110
+ if(!parityPath||!activationPath||!windowsGatePath) throw new Error('usage: node scripts/final-closure-r40.mjs <parity.json> <activation-receipt.json> <windows-gate.json>');
111
+ writeFinalClosure({parityPath,activationPath,windowsGatePath})
112
+ .then(result=>console.log(JSON.stringify(result,null,2)))
113
+ .catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
114
+ }