deadbyte-mcp 0.15.28 → 0.15.30
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/MANIFEST.SHA256 +76 -54
- package/PROVENANCE.json +21 -10
- package/README.txt +16 -14
- package/RELEASE.json +29 -10
- package/SBOM.cdx.json +3 -3
- package/STABILIZATION-PROGRESS.md +60 -0
- package/TEST-MATRIX.json +51 -93
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-hardware-observer-r45.obj +0 -0
- package/bin/deadbyte-process-host.exe +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/controller/deadbyte-controller.ps1 +4 -1
- package/controller/deadbyte-desktop-policy.json +5 -5
- package/controller/deadbyte-host-policy.json +170 -0
- package/controller/deadbyte-process-policy.json +5 -5
- package/docs/R51-PROVENANCE.json +18 -0
- package/docs/R51-RELEASE.json +115 -0
- package/docs/R51-TEST-MATRIX.json +166 -0
- package/docs/R52-ACTIVATION-FORENSICS.md +85 -0
- package/native/deadbyte-process-host.cpp +5 -3
- package/package.json +96 -94
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/gate-windows-r52.ps1 +58 -0
- package/scripts/gate-windows-r53.ps1 +58 -0
- package/scripts/verify-r42-parent.mjs +1 -1
- package/scripts/verify-r43-parent.mjs +1 -1
- package/scripts/verify-r44-parent.mjs +1 -1
- package/scripts/verify-r45-parent.mjs +1 -1
- package/scripts/windows-gate-evidence-r52.mjs +94 -0
- package/scripts/windows-gate-evidence-r53.mjs +102 -0
- package/src/authority-smoke.mjs +1 -0
- package/src/coding-plane.mjs +43 -12
- package/src/coding-task-runtime.mjs +10 -4
- package/src/deadbyte-cli.mjs +4 -2
- package/src/doctor-r45.mjs +2 -1
- package/src/machine-fs-smoke-client.mjs +1 -0
- package/src/mcp-contained-smoke-client.mjs +1 -0
- package/src/mcp-host-smoke-client.mjs +1 -0
- package/src/mcp-smoke-client.mjs +1 -0
- package/src/process-smoke-client.mjs +1 -0
- package/src/release-slot.mjs +5 -2
- package/src/remote-session-guardian.mjs +12 -4
- package/src/runtime-coherence.mjs +13 -4
- package/src/runtime-update.mjs +28 -7
- package/src/state-root.mjs +8 -0
- package/src/trust.mjs +2 -1
- package/src/tunnel-stdio-compat-smoke.mjs +1 -0
- package/src/version.mjs +1 -1
- package/test/coding-runtime.test.mjs +70 -1
- package/test/commander-biff-reference-r48.test.mjs +1 -1
- package/test/helpers/coding-disconnect-server.mjs +11 -0
- package/test/r44-finalizer.test.mjs +4 -3
- package/test/r49-windows-gate.test.mjs +19 -9
- package/test/r51-release-contract.test.mjs +22 -20
- package/test/r52-host-revocation.test.mjs +65 -0
- package/test/r52-offline-predecessor-recovery.test.mjs +77 -0
- package/test/r52-release-contract.test.mjs +64 -0
- package/test/r53-release-contract.test.mjs +66 -0
- package/test/release-slot.test.mjs +2 -1
- package/test/skill-mcp-r44.test.mjs +3 -0
- package/test/stabilization-guardian.test.mjs +25 -0
- package/test/stabilization-parent-context.test.mjs +18 -0
- package/test/stabilization-powershell.test.mjs +26 -0
- package/test/stabilization-semver.test.mjs +23 -0
- package/test/stabilization-smoke-root.test.mjs +23 -0
- package/test/stabilization-state-root.test.mjs +60 -0
- package/test/stabilization-update-child-root.test.mjs +20 -0
|
@@ -39,7 +39,7 @@ deadbyte-process-host.cpp
|
|
|
39
39
|
exit_code=0
|
|
40
40
|
==== probe-dependencies ====
|
|
41
41
|
|
|
42
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
42
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\containment-probe.exe
|
|
43
43
|
|
|
44
44
|
File Type: EXECUTABLE IMAGE
|
|
45
45
|
|
|
@@ -59,7 +59,7 @@ File Type: EXECUTABLE IMAGE
|
|
|
59
59
|
exit_code=0
|
|
60
60
|
==== contained-launcher-dependencies ====
|
|
61
61
|
|
|
62
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
62
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\deadbyte-exec.exe
|
|
63
63
|
|
|
64
64
|
File Type: EXECUTABLE IMAGE
|
|
65
65
|
|
|
@@ -83,7 +83,7 @@ File Type: EXECUTABLE IMAGE
|
|
|
83
83
|
exit_code=0
|
|
84
84
|
==== contained-worker-dependencies ====
|
|
85
85
|
|
|
86
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
86
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\contained-transform-worker.exe
|
|
87
87
|
|
|
88
88
|
File Type: EXECUTABLE IMAGE
|
|
89
89
|
|
|
@@ -104,7 +104,7 @@ File Type: EXECUTABLE IMAGE
|
|
|
104
104
|
exit_code=0
|
|
105
105
|
==== contained-reverse-worker-dependencies ====
|
|
106
106
|
|
|
107
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
107
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\contained-reverse-worker.exe
|
|
108
108
|
|
|
109
109
|
File Type: EXECUTABLE IMAGE
|
|
110
110
|
|
|
@@ -125,7 +125,7 @@ File Type: EXECUTABLE IMAGE
|
|
|
125
125
|
exit_code=0
|
|
126
126
|
==== named-tunnel-host-dependencies ====
|
|
127
127
|
|
|
128
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
128
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\deadbyte-tunnel-host.exe
|
|
129
129
|
|
|
130
130
|
File Type: EXECUTABLE IMAGE
|
|
131
131
|
|
|
@@ -144,7 +144,7 @@ File Type: EXECUTABLE IMAGE
|
|
|
144
144
|
exit_code=0
|
|
145
145
|
==== process-host-dependencies ====
|
|
146
146
|
|
|
147
|
-
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-
|
|
147
|
+
Dump of file D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.30-stabilization\bin\deadbyte-process-host.exe
|
|
148
148
|
|
|
149
149
|
File Type: EXECUTABLE IMAGE
|
|
150
150
|
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
Set-StrictMode -Version 3.0
|
|
3
|
+
|
|
4
|
+
function Invoke-GateStep {
|
|
5
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$NpmArgs)
|
|
6
|
+
Write-Host "==== $Name ===="
|
|
7
|
+
& npm.cmd @NpmArgs
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.29 / R52 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function Invoke-NodeTest {
|
|
12
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$TestFiles)
|
|
13
|
+
Write-Host "==== $Name ===="
|
|
14
|
+
& node.exe --test --test-concurrency=1 @TestFiles
|
|
15
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.29 / R52 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Invoke-NodeTest 'r52-package-boundary' @('test/package-boundary.test.mjs')
|
|
19
|
+
Invoke-NodeTest 'r52-release-smoke-isolation' @('test/release-smoke-isolation.test.mjs')
|
|
20
|
+
Invoke-GateStep 'r52-focused-contracts' @('run','r52:focused:test')
|
|
21
|
+
Invoke-GateStep 'containment-build' @('run','containment:build')
|
|
22
|
+
Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
|
|
23
|
+
Write-Host "==== desktop-policy-refresh ===="
|
|
24
|
+
& (Join-Path $PSScriptRoot 'init-desktop-policy-r40.ps1')
|
|
25
|
+
Invoke-GateStep 'hardware-build' @('run','hardware:build')
|
|
26
|
+
|
|
27
|
+
$hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
|
|
28
|
+
Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
|
|
29
|
+
if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
|
|
30
|
+
|
|
31
|
+
Invoke-GateStep 'r52-release-focused' @('run','r48:release:test')
|
|
32
|
+
Invoke-NodeTest 'r49-donor-proof' @('test/r49-remote-control-donors.test.mjs')
|
|
33
|
+
Invoke-NodeTest 'r49-desktop-wait' @('test/desktop-runtime-r40.test.mjs','test/desktop-mcp-tools-r40.test.mjs','test/autonomous-desktop-r40.test.mjs')
|
|
34
|
+
Invoke-GateStep 'r49-catalog' @('run','r48:catalog:test')
|
|
35
|
+
Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
|
|
36
|
+
Invoke-GateStep 'full-regression' @('run','r48:full:test')
|
|
37
|
+
Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
|
|
38
|
+
Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
|
|
39
|
+
Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
|
|
40
|
+
Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
|
|
41
|
+
Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
|
|
42
|
+
Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
|
|
43
|
+
Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
|
|
44
|
+
Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
|
|
45
|
+
Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
|
|
46
|
+
Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
|
|
47
|
+
Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
|
|
48
|
+
Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
|
|
49
|
+
Invoke-GateStep 'manifest-write' @('run','manifest:write')
|
|
50
|
+
Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
|
|
51
|
+
Invoke-GateStep 'doctor' @('run','doctor')
|
|
52
|
+
Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
|
|
53
|
+
Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
|
|
54
|
+
Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
|
|
55
|
+
|
|
56
|
+
& node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r52.mjs')
|
|
57
|
+
if ($LASTEXITCODE -ne 0) { throw "R52 evidence writer failed with exit code $LASTEXITCODE" }
|
|
58
|
+
Write-Host '==== DEADBYTE 0.15.29 / R52 WINDOWS GATE: PASS ===='
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
$ErrorActionPreference = 'Stop'
|
|
2
|
+
Set-StrictMode -Version 3.0
|
|
3
|
+
|
|
4
|
+
function Invoke-GateStep {
|
|
5
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$NpmArgs)
|
|
6
|
+
Write-Host "==== $Name ===="
|
|
7
|
+
& npm.cmd @NpmArgs
|
|
8
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.30 / R53 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function Invoke-NodeTest {
|
|
12
|
+
param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$TestFiles)
|
|
13
|
+
Write-Host "==== $Name ===="
|
|
14
|
+
& node.exe --test --test-concurrency=1 @TestFiles
|
|
15
|
+
if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.30 / R53 gate failed at $Name with exit code $LASTEXITCODE" }
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Invoke-NodeTest 'r53-package-boundary' @('test/package-boundary.test.mjs')
|
|
19
|
+
Invoke-NodeTest 'r53-release-smoke-isolation' @('test/release-smoke-isolation.test.mjs')
|
|
20
|
+
Invoke-GateStep 'r53-focused-contracts' @('run','r53:focused:test')
|
|
21
|
+
Invoke-GateStep 'containment-build' @('run','containment:build')
|
|
22
|
+
Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
|
|
23
|
+
Write-Host "==== desktop-policy-refresh ===="
|
|
24
|
+
& (Join-Path $PSScriptRoot 'init-desktop-policy-r40.ps1')
|
|
25
|
+
Invoke-GateStep 'hardware-build' @('run','hardware:build')
|
|
26
|
+
|
|
27
|
+
$hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
|
|
28
|
+
Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
|
|
29
|
+
if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
|
|
30
|
+
|
|
31
|
+
Invoke-GateStep 'r53-release-focused' @('run','r48:release:test')
|
|
32
|
+
Invoke-NodeTest 'r49-donor-proof' @('test/r49-remote-control-donors.test.mjs')
|
|
33
|
+
Invoke-NodeTest 'r49-desktop-wait' @('test/desktop-runtime-r40.test.mjs','test/desktop-mcp-tools-r40.test.mjs','test/autonomous-desktop-r40.test.mjs')
|
|
34
|
+
Invoke-GateStep 'r49-catalog' @('run','r48:catalog:test')
|
|
35
|
+
Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
|
|
36
|
+
Invoke-GateStep 'full-regression' @('run','r48:full:test')
|
|
37
|
+
Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
|
|
38
|
+
Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
|
|
39
|
+
Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
|
|
40
|
+
Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
|
|
41
|
+
Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
|
|
42
|
+
Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
|
|
43
|
+
Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
|
|
44
|
+
Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
|
|
45
|
+
Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
|
|
46
|
+
Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
|
|
47
|
+
Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
|
|
48
|
+
Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
|
|
49
|
+
Invoke-GateStep 'manifest-write' @('run','manifest:write')
|
|
50
|
+
Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
|
|
51
|
+
Invoke-GateStep 'doctor' @('run','doctor')
|
|
52
|
+
Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
|
|
53
|
+
Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
|
|
54
|
+
Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
|
|
55
|
+
|
|
56
|
+
& node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r53.mjs')
|
|
57
|
+
if ($LASTEXITCODE -ne 0) { throw "R53 evidence writer failed with exit code $LASTEXITCODE" }
|
|
58
|
+
Write-Host '==== DEADBYTE 0.15.30 / R53 WINDOWS GATE: PASS ===='
|
|
@@ -82,7 +82,7 @@ export async function verifyR42Parent(file=path.join(root,'R42-PARENT.json')){
|
|
|
82
82
|
const closureBytes=await readFile(path.resolve(record.parent_final_closure_path));
|
|
83
83
|
insist(sha256(closureBytes)===record.parent_final_closure_sha256,'R41 parent final closure raw hash mismatch');
|
|
84
84
|
const closure=JSON.parse(closureBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
85
|
-
const pointer=verifySignedClosure(closure,record,await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
|
|
85
|
+
const pointer=verifySignedClosure(closure,record,await readFile(path.resolve(process.env.DEADBYTE_PARENT_VERIFY_KEY||path.join(stateRoot,'trust','ed25519-public.pem'))));
|
|
86
86
|
const generationFiles=await verifyTree(path.resolve(pointer.generation_root),'GENERATION.SHA256',record.parent_generation_manifest_sha256,{exact:true});
|
|
87
87
|
|
|
88
88
|
const tarball=await readFile(path.resolve(record.parent_public_tarball_path));
|
|
@@ -107,7 +107,7 @@ export async function verifyR43Parent(file=path.join(root,'R43-PARENT.json')){
|
|
|
107
107
|
const activationBytes=await readFile(path.resolve(record.parent_activation_receipt_path));
|
|
108
108
|
insist(sha256(activationBytes)===record.parent_activation_receipt_file_sha256,'R42 activation raw file hash mismatch');
|
|
109
109
|
const activation=JSON.parse(activationBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
110
|
-
const keyInfo=publicKeyInfo(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
|
|
110
|
+
const keyInfo=publicKeyInfo(await readFile(path.resolve(process.env.DEADBYTE_PARENT_VERIFY_KEY||path.join(stateRoot,'trust','ed25519-public.pem'))));
|
|
111
111
|
verifyActivationEnvelope(activation,keyInfo,record);
|
|
112
112
|
|
|
113
113
|
return {
|
|
@@ -76,7 +76,7 @@ export async function verifyR44Parent(parentFile,{stateRoot=path.join(os.homedir
|
|
|
76
76
|
insist(envelope.body.version===parent.parent_version,'R44 parent closure version mismatch');
|
|
77
77
|
insist(envelope.body.release_label==='R43 AUTHORITY HARDENING PATCH','R44 parent closure label mismatch');
|
|
78
78
|
|
|
79
|
-
const publicKey=createPublicKey(await readFile(path.join(path.resolve(stateRoot),'trust','ed25519-public.pem')));
|
|
79
|
+
const publicKey=createPublicKey(await readFile(path.resolve(process.env.DEADBYTE_PARENT_VERIFY_KEY||path.join(path.resolve(stateRoot),'trust','ed25519-public.pem'))));
|
|
80
80
|
insist(publicKey.asymmetricKeyType==='ed25519','R44 parent trust key must be Ed25519');
|
|
81
81
|
const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
|
|
82
82
|
insist(keyId===parent.parent_final_closure_signer_key_id,'R44 parent trust key id mismatch');
|
|
@@ -76,7 +76,7 @@ export async function verifyR45Parent(parentFile,{stateRoot=path.join(os.homedir
|
|
|
76
76
|
insist(envelope.body.version===parent.parent_version,'R45 parent closure version mismatch');
|
|
77
77
|
insist(envelope.body.release_label==='R44 REMOTE AGENT SKILL BASELINE','R45 parent closure label mismatch');
|
|
78
78
|
|
|
79
|
-
const publicKey=createPublicKey(await readFile(path.join(path.resolve(stateRoot),'trust','ed25519-public.pem')));
|
|
79
|
+
const publicKey=createPublicKey(await readFile(path.resolve(process.env.DEADBYTE_PARENT_VERIFY_KEY||path.join(path.resolve(stateRoot),'trust','ed25519-public.pem'))));
|
|
80
80
|
insist(publicKey.asymmetricKeyType==='ed25519','R45 parent trust key must be Ed25519');
|
|
81
81
|
const keyId=sha256(Buffer.from(publicKey.export({type:'spki',format:'der'})));
|
|
82
82
|
insist(keyId===parent.parent_final_closure_signer_key_id,'R45 parent trust key id mismatch');
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { doctor } from '../src/doctor-r45.mjs';
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const stateRoot = path.resolve(process.env.DEADBYTE_STATE_ROOT || path.join(os.homedir(), '.deadbyte-mcp'));
|
|
10
|
+
const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const insist = (ok, message) => { if (!ok) throw new Error(message); };
|
|
12
|
+
const pkg = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8'));
|
|
13
|
+
const release = JSON.parse(await readFile(path.join(root, 'RELEASE.json'), 'utf8'));
|
|
14
|
+
const provenance = JSON.parse(await readFile(path.join(root, 'PROVENANCE.json'), 'utf8'));
|
|
15
|
+
const active = JSON.parse(await readFile(path.join(stateRoot, 'active-release.json'), 'utf8'));
|
|
16
|
+
const manifestSha256 = sha256(await readFile(path.join(root, 'MANIFEST.SHA256')));
|
|
17
|
+
|
|
18
|
+
insist(pkg.version === '0.15.29' && release.version === pkg.version && release.train === 'R52', 'R52 candidate identity mismatch');
|
|
19
|
+
insist(
|
|
20
|
+
active.release_id === release.runtime_predecessor.release_id &&
|
|
21
|
+
active.manifest_sha256 === release.runtime_predecessor.manifest_sha256 &&
|
|
22
|
+
active.generation_manifest_sha256 === release.runtime_predecessor.generation_manifest_sha256,
|
|
23
|
+
'active runtime is not the exact sealed R52 runtime rollback target'
|
|
24
|
+
);
|
|
25
|
+
insist(release.parent.version === '0.15.28' && release.parent.manifest_sha256 === release.source_predecessor.manifest_file_sha256 && release.parent.tarball_sha256 === release.source_predecessor.tarball_sha256, 'R52 published parent binding mismatch');
|
|
26
|
+
insist(release.source_predecessor.version === '0.15.28', 'R52 source predecessor version mismatch');
|
|
27
|
+
insist(release.source_predecessor.tarball_sha256 === '0a74332ba715d80a532dc871ece4826bdb917b8c7a442e71388a06d44698c411', 'R52 source predecessor tarball mismatch');
|
|
28
|
+
insist(provenance.source_predecessor_activation_failure_receipt_sha256 === '090f165c96da0d5a8e9c0815fd389fe94e8fe36c23a6878ee825b8f46bfb0bc2', 'R52 failure receipt binding mismatch');
|
|
29
|
+
|
|
30
|
+
const health = await doctor();
|
|
31
|
+
insist(health.status === 'ok' && health.package_version === pkg.version && health.manifest?.verified === true, 'R52 doctor evidence invalid');
|
|
32
|
+
insist(health.policy?.host_v2_ready === true, 'R52 Host policy v2 is not ready');
|
|
33
|
+
|
|
34
|
+
const evidence = {
|
|
35
|
+
schema: 'deadbyte.r52-windows-gate.v1',
|
|
36
|
+
status: 'passed',
|
|
37
|
+
exit_code: 0,
|
|
38
|
+
version: pkg.version,
|
|
39
|
+
train: 'R52',
|
|
40
|
+
completed_at_utc: new Date().toISOString(),
|
|
41
|
+
manifest_sha256: manifestSha256,
|
|
42
|
+
parent: release.parent,
|
|
43
|
+
runtime_predecessor: release.runtime_predecessor,
|
|
44
|
+
source_predecessor: release.source_predecessor,
|
|
45
|
+
activation_failure_receipt_sha256: provenance.source_predecessor_activation_failure_receipt_sha256,
|
|
46
|
+
active_predecessor: {
|
|
47
|
+
release_id: active.release_id,
|
|
48
|
+
version: active.version,
|
|
49
|
+
manifest_sha256: active.manifest_sha256,
|
|
50
|
+
generation_manifest_sha256: active.generation_manifest_sha256
|
|
51
|
+
},
|
|
52
|
+
doctor: { verified_entries: health.manifest.verified_entries, host_v2_ready: true },
|
|
53
|
+
gates: {
|
|
54
|
+
offline_predecessor_host_revoke_before_capture: true,
|
|
55
|
+
package_boundary: true,
|
|
56
|
+
release_smoke_isolation: true,
|
|
57
|
+
runtime_coherence: true,
|
|
58
|
+
coding_command_singleflight: true,
|
|
59
|
+
foreground_desktop_host_fail_closed: true,
|
|
60
|
+
livelog_optimizer: true,
|
|
61
|
+
full_regression: true,
|
|
62
|
+
commander_hardening: true,
|
|
63
|
+
donor_proof: true,
|
|
64
|
+
desktop_wait: true,
|
|
65
|
+
exact_catalog: true,
|
|
66
|
+
stdio_smokes: true,
|
|
67
|
+
manifest_final_verify: true
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const bytes = Buffer.from(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
72
|
+
const dir = path.join(stateRoot, 'evidence', 'release');
|
|
73
|
+
await mkdir(dir, { recursive: true });
|
|
74
|
+
const target = path.join(dir, `r52-windows-gate-${manifestSha256.slice(0, 16)}.json`);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const handle = await open(target, 'wx', 0o600);
|
|
78
|
+
try { await handle.writeFile(bytes); await handle.sync(); }
|
|
79
|
+
finally { await handle.close(); }
|
|
80
|
+
} catch (error) {
|
|
81
|
+
if (error?.code !== 'EEXIST') throw error;
|
|
82
|
+
const prior = JSON.parse(await readFile(target, 'utf8'));
|
|
83
|
+
insist(
|
|
84
|
+
prior.schema === evidence.schema &&
|
|
85
|
+
prior.status === 'passed' &&
|
|
86
|
+
prior.version === evidence.version &&
|
|
87
|
+
prior.manifest_sha256 === manifestSha256 &&
|
|
88
|
+
prior.parent?.release_id === release.parent.release_id &&
|
|
89
|
+
prior.activation_failure_receipt_sha256 === evidence.activation_failure_receipt_sha256,
|
|
90
|
+
'conflicting R52 gate evidence identity'
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(JSON.stringify({ status: 'passed', path: target, sha256: sha256(bytes), manifest_sha256: manifestSha256 }));
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile } from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
import { doctor } from '../src/doctor-r45.mjs';
|
|
7
|
+
|
|
8
|
+
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
|
|
9
|
+
const stateRoot = path.resolve(process.env.DEADBYTE_STATE_ROOT || path.join(os.homedir(), '.deadbyte-mcp'));
|
|
10
|
+
const sha256 = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
11
|
+
const insist = (ok, message) => { if (!ok) throw new Error(message); };
|
|
12
|
+
const pkg = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8'));
|
|
13
|
+
const release = JSON.parse(await readFile(path.join(root, 'RELEASE.json'), 'utf8'));
|
|
14
|
+
const provenance = JSON.parse(await readFile(path.join(root, 'PROVENANCE.json'), 'utf8'));
|
|
15
|
+
const matrix = JSON.parse(await readFile(path.join(root, 'TEST-MATRIX.json'), 'utf8'));
|
|
16
|
+
const active = JSON.parse(await readFile(path.join(stateRoot, 'active-release.json'), 'utf8'));
|
|
17
|
+
const manifestSha256 = sha256(await readFile(path.join(root, 'MANIFEST.SHA256')));
|
|
18
|
+
|
|
19
|
+
insist(pkg.version === '0.15.30' && release.version === pkg.version && release.train === 'R53', 'R53 candidate identity mismatch');
|
|
20
|
+
insist(
|
|
21
|
+
active.release_id === release.runtime_predecessor.release_id &&
|
|
22
|
+
active.manifest_sha256 === release.runtime_predecessor.manifest_sha256 &&
|
|
23
|
+
active.generation_manifest_sha256 === release.runtime_predecessor.generation_manifest_sha256,
|
|
24
|
+
'active runtime is not exact sealed 0.15.29 predecessor'
|
|
25
|
+
);
|
|
26
|
+
insist(release.parent.version === '0.15.29', 'R53 parent version mismatch');
|
|
27
|
+
insist(release.parent.release_id === 'v0.15.29-f74eaa1b3d00e6fb', 'R53 parent release id mismatch');
|
|
28
|
+
insist(release.parent.manifest_sha256 === 'f74eaa1b3d00e6fb5a36b2358efb815e3686c9fe9dbd3b84d25a713ef957748c', 'R53 parent manifest mismatch');
|
|
29
|
+
insist(release.parent.generation_manifest_sha256 === '289b4fc065de0681da6864cc1bbe09aab198ca804945ffc27c786438dad13f5a', 'R53 parent generation mismatch');
|
|
30
|
+
insist(release.parent.tarball_sha256 === 'f535d7121a384bed106d34bc7525afa9d4048c7e290f270699e25136d1e82eeb', 'R53 parent tarball mismatch');
|
|
31
|
+
insist(provenance.parent_release_id === release.parent.release_id, 'R53 provenance parent release mismatch');
|
|
32
|
+
insist(provenance.parent_manifest_sha256 === release.parent.manifest_sha256, 'R53 provenance parent manifest mismatch');
|
|
33
|
+
insist(provenance.parent_generation_manifest_sha256 === release.parent.generation_manifest_sha256, 'R53 provenance parent generation mismatch');
|
|
34
|
+
insist(provenance.operator_override?.four_hour_soak === 'NOT_COMPLETED', 'R53 soak bypass missing');
|
|
35
|
+
insist(provenance.operator_override?.stable_final_claim === false, 'R53 must not claim stable/final');
|
|
36
|
+
insist(matrix.operator_override?.four_hour_soak === 'NOT_COMPLETED', 'R53 matrix soak bypass missing');
|
|
37
|
+
|
|
38
|
+
const health = await doctor();
|
|
39
|
+
insist(health.status === 'ok' && health.package_version === pkg.version && health.manifest?.verified === true, 'R53 doctor evidence invalid');
|
|
40
|
+
insist(health.policy?.host_v2_ready === true, 'R53 Host policy v2 is not ready');
|
|
41
|
+
|
|
42
|
+
const evidence = {
|
|
43
|
+
schema: 'deadbyte.r53-windows-gate.v1',
|
|
44
|
+
status: 'passed',
|
|
45
|
+
exit_code: 0,
|
|
46
|
+
version: pkg.version,
|
|
47
|
+
train: 'R53',
|
|
48
|
+
completed_at_utc: new Date().toISOString(),
|
|
49
|
+
manifest_sha256: manifestSha256,
|
|
50
|
+
parent: release.parent,
|
|
51
|
+
runtime_predecessor: release.runtime_predecessor,
|
|
52
|
+
stabilization: release.stabilization,
|
|
53
|
+
operator_override: provenance.operator_override,
|
|
54
|
+
active_predecessor: {
|
|
55
|
+
release_id: active.release_id,
|
|
56
|
+
version: active.version,
|
|
57
|
+
manifest_sha256: active.manifest_sha256,
|
|
58
|
+
generation_manifest_sha256: active.generation_manifest_sha256
|
|
59
|
+
},
|
|
60
|
+
doctor: { verified_entries: health.manifest.verified_entries, host_v2_ready: true },
|
|
61
|
+
gates: {
|
|
62
|
+
r53_focused: true,
|
|
63
|
+
package_boundary: true,
|
|
64
|
+
release_smoke_isolation: true,
|
|
65
|
+
runtime_coherence: true,
|
|
66
|
+
coding_command_singleflight: true,
|
|
67
|
+
foreground_desktop_host_fail_closed: true,
|
|
68
|
+
full_regression: true,
|
|
69
|
+
commander_hardening: true,
|
|
70
|
+
donor_proof: true,
|
|
71
|
+
desktop_wait: true,
|
|
72
|
+
exact_catalog: true,
|
|
73
|
+
stdio_smokes: true,
|
|
74
|
+
manifest_final_verify: true,
|
|
75
|
+
four_hour_soak_completed: false
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const bytes = Buffer.from(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
80
|
+
const dir = path.join(stateRoot, 'evidence', 'release');
|
|
81
|
+
await mkdir(dir, { recursive: true });
|
|
82
|
+
const target = path.join(dir, `r53-windows-gate-${manifestSha256.slice(0, 16)}.json`);
|
|
83
|
+
|
|
84
|
+
try {
|
|
85
|
+
const handle = await open(target, 'wx', 0o600);
|
|
86
|
+
try { await handle.writeFile(bytes); await handle.sync(); }
|
|
87
|
+
finally { await handle.close(); }
|
|
88
|
+
} catch (error) {
|
|
89
|
+
if (error?.code !== 'EEXIST') throw error;
|
|
90
|
+
const prior = JSON.parse(await readFile(target, 'utf8'));
|
|
91
|
+
insist(
|
|
92
|
+
prior.schema === evidence.schema &&
|
|
93
|
+
prior.status === 'passed' &&
|
|
94
|
+
prior.version === evidence.version &&
|
|
95
|
+
prior.manifest_sha256 === manifestSha256 &&
|
|
96
|
+
prior.parent?.release_id === release.parent.release_id &&
|
|
97
|
+
prior.operator_override?.four_hour_soak === 'NOT_COMPLETED',
|
|
98
|
+
'conflicting R53 gate evidence identity'
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
console.log(JSON.stringify({ status: 'passed', path: target, sha256: sha256(bytes), manifest_sha256: manifestSha256 }));
|
package/src/authority-smoke.mjs
CHANGED
|
@@ -60,6 +60,7 @@ const transport = new StdioClientTransport({
|
|
|
60
60
|
cwd: repoRoot,
|
|
61
61
|
env: {
|
|
62
62
|
...getDefaultEnvironment(),
|
|
63
|
+
DEADBYTE_STATE_ROOT: path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(trust,'state')),
|
|
63
64
|
DEADBYTE_WORKSPACE_ROOT: workspaceRoot,
|
|
64
65
|
DEADBYTE_SIGNING_KEY: keys.privateKeyPath,
|
|
65
66
|
DEADBYTE_VERIFY_KEY: keys.publicKeyPath
|
package/src/coding-plane.mjs
CHANGED
|
@@ -11,6 +11,7 @@ import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
|
|
|
11
11
|
import { createCodingSearch } from './coding-search.mjs';
|
|
12
12
|
import { createSearchCursorCodec } from './search-cursor.mjs';
|
|
13
13
|
import { atomicMutation } from './atomic-mutation.mjs';
|
|
14
|
+
import { fileURLToPath } from 'node:url';
|
|
14
15
|
|
|
15
16
|
export const CODING_POLICY_SCHEMA = 'deadbyte.coding-policy.v1';
|
|
16
17
|
export const CODING_LEASE_SCHEMA = 'deadbyte.coding-lease.v1';
|
|
@@ -591,7 +592,7 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
591
592
|
receipt_sha256: signed.receipt.receipt_sha256, request_sha256: request };
|
|
592
593
|
}
|
|
593
594
|
async function runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args = [], cwd = '.', timeoutMs = null,
|
|
594
|
-
executionDeadlineUtc = null, preExecutionCheck = null }) {
|
|
595
|
+
executionDeadlineUtc = null, preExecutionCheck = null, cancellationCheck = null }) {
|
|
595
596
|
const lease = await assertCodingArmed(policy, rootId);
|
|
596
597
|
if (!ID_RE.test(commandId ?? '')) throw new Error('invalid coding command id');
|
|
597
598
|
const command = policy.commands[commandId];
|
|
@@ -633,28 +634,58 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
633
634
|
if (deadlineBound < 100) throw new Error('coding execution deadline expires too soon to execute command');
|
|
634
635
|
const effectiveTimeout = Math.min(requestedTimeout, command.timeout_ms, grantBound, deadlineBound);
|
|
635
636
|
const argv = [...command.prefix_args, script.resolved, ...args];
|
|
637
|
+
// The internal Windows host owns a kill-on-close Job Object. Its identity
|
|
638
|
+
// is package-pinned, never selected by a caller or granted public PID input.
|
|
639
|
+
let executable=command.executable, launchArgs=argv;
|
|
640
|
+
if(process.platform==='win32'){
|
|
641
|
+
const host=fileURLToPath(new URL('../bin/deadbyte-process-host.exe',import.meta.url));
|
|
642
|
+
const hostPolicy=JSON.parse(await readFile(new URL('../controller/deadbyte-process-policy.json',import.meta.url),'utf8'));
|
|
643
|
+
if(await sha256File(host)!==hostPolicy.native_host?.sha256) throw new Error('coding process host hash changed');
|
|
644
|
+
executable=host;
|
|
645
|
+
launchArgs=[command.executable,cwdResolved,randomBytes(32).toString('hex'),'--deadbyte-transport=pipe-quiet',...argv];
|
|
646
|
+
}
|
|
647
|
+
if(cancellationCheck!==null&&typeof cancellationCheck!=='function') throw new Error('cancellation check must be internal function');
|
|
648
|
+
if(cancellationCheck&&await cancellationCheck()) throw new Error('coding command cancelled before dispatch');
|
|
649
|
+
await recheckCodingAuthority(policy,activeLease,rootId);
|
|
636
650
|
const startMs = performance.now();
|
|
637
|
-
const child = spawn(
|
|
651
|
+
const child = spawn(executable, launchArgs, {
|
|
638
652
|
cwd: cwdResolved, env: codingEnvironment(), shell: false, windowsHide: true,
|
|
639
|
-
detached:
|
|
653
|
+
detached: process.platform!=='win32', stdio: ['ignore', 'pipe', 'pipe']
|
|
640
654
|
});
|
|
655
|
+
const killOwned=()=>{
|
|
656
|
+
if(child.exitCode!==null||child.signalCode!==null)return;
|
|
657
|
+
if(process.platform==='win32') child.kill('SIGKILL');
|
|
658
|
+
else {try{process.kill(-child.pid,'SIGKILL');}catch(error){if(error.code!=='ESRCH')throw error;}}
|
|
659
|
+
};
|
|
641
660
|
const stdoutState = { chunks: [], bytes: 0, exceeded: null };
|
|
642
661
|
const stderrState = { chunks: [], bytes: 0, exceeded: null };
|
|
643
|
-
collectBounded(child.stdout, command.max_output_bytes, stdoutState, 'stdout',
|
|
644
|
-
collectBounded(child.stderr, command.max_output_bytes, stderrState, 'stderr',
|
|
662
|
+
collectBounded(child.stdout, command.max_output_bytes, stdoutState, 'stdout', killOwned);
|
|
663
|
+
collectBounded(child.stderr, command.max_output_bytes, stderrState, 'stderr', killOwned);
|
|
645
664
|
let timedOut = false;
|
|
646
665
|
let timer;
|
|
666
|
+
let cancelTimer,checking=false,cancellationError=null,finished=false;
|
|
667
|
+
if(cancellationCheck){
|
|
668
|
+
cancelTimer=setInterval(async()=>{
|
|
669
|
+
if(checking||finished)return;
|
|
670
|
+
checking=true;
|
|
671
|
+
try{if(await cancellationCheck())killOwned();}
|
|
672
|
+
catch(error){cancellationError=error;killOwned();}
|
|
673
|
+
finally{checking=false;}
|
|
674
|
+
},50);
|
|
675
|
+
cancelTimer.unref?.();
|
|
676
|
+
}
|
|
647
677
|
const timerDelay = deadlineAtMs === null
|
|
648
678
|
? effectiveTimeout
|
|
649
679
|
: Math.max(1, Math.min(effectiveTimeout, Math.floor(deadlineAtMs - Date.now())));
|
|
650
680
|
const completion = new Promise((resolve, reject) => {
|
|
651
681
|
child.once('error', reject);
|
|
652
682
|
child.once('close', (code, signal) => resolve({ code, signal }));
|
|
653
|
-
timer = setTimeout(() => { timedOut = true;
|
|
683
|
+
timer = setTimeout(() => { timedOut = true; killOwned(); }, timerDelay);
|
|
654
684
|
timer.unref?.();
|
|
655
685
|
});
|
|
656
686
|
let result;
|
|
657
|
-
try { result = await completion; } finally { if (timer) clearTimeout(timer); }
|
|
687
|
+
try { result = await completion; } finally { finished=true;if (timer) clearTimeout(timer);if(cancelTimer)clearInterval(cancelTimer); }
|
|
688
|
+
if(cancellationError)throw cancellationError;
|
|
658
689
|
if (stdoutState.exceeded || stderrState.exceeded) throw new Error(stdoutState.exceeded ?? stderrState.exceeded);
|
|
659
690
|
const stdoutBytes = Buffer.concat(stdoutState.chunks);
|
|
660
691
|
const stderrBytes = Buffer.concat(stderrState.chunks);
|
|
@@ -669,7 +700,7 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
669
700
|
}
|
|
670
701
|
|
|
671
702
|
async function commandRun({ rootId, commandId, scriptPath, scriptSha256, args = [], cwd = '.', timeoutMs = null,
|
|
672
|
-
executionDeadlineUtc = null, preExecutionCheck = null, receiptId = null, requestSha256 = null }) {
|
|
703
|
+
executionDeadlineUtc = null, preExecutionCheck = null, cancellationCheck = null, receiptId = null, requestSha256 = null }) {
|
|
673
704
|
const request = requestSha256 ?? requestSha('coding_command_run', {
|
|
674
705
|
root_id: rootId, command_id: commandId, script_path: scriptPath, script_sha256: scriptSha256,
|
|
675
706
|
args, cwd, timeout_ms: timeoutMs
|
|
@@ -704,7 +735,7 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
704
735
|
}
|
|
705
736
|
const execution = (async () => {
|
|
706
737
|
const started = new Date().toISOString();
|
|
707
|
-
const result = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck });
|
|
738
|
+
const result = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck, cancellationCheck });
|
|
708
739
|
const signed = await signCodingReceipt(policy, signingKeyPath, result.lease, {
|
|
709
740
|
operation: 'coding_command_run', request_sha256: request, root_id: rootId, command_id: commandId,
|
|
710
741
|
script_path: scriptPath, executable_sha256: result.executable_sha256, script_sha256: result.script_sha256,
|
|
@@ -751,7 +782,7 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
751
782
|
|
|
752
783
|
async function benchmarkRun({ rootId, commandId, scriptPath, scriptSha256, args = [], cwd = '.', timeoutMs = null,
|
|
753
784
|
executionDeadlineUtc = null, preExecutionCheck = null, warmups = 1, iterations = 5, baselineMedianMs = null, maxRegressionPct = 5,
|
|
754
|
-
receiptId = null, requestSha256 = null }) {
|
|
785
|
+
receiptId = null, requestSha256 = null, cancellationCheck = null }) {
|
|
755
786
|
if (!Number.isInteger(warmups) || warmups < 0 || warmups > 3) throw new Error('warmups must be in [0, 3]');
|
|
756
787
|
if (!Number.isInteger(iterations) || iterations < 1 || iterations > 20) throw new Error('iterations must be in [1, 20]');
|
|
757
788
|
if (baselineMedianMs !== null && (!Number.isFinite(baselineMedianMs) || baselineMedianMs <= 0)) throw new Error('baseline_median_ms must be positive or null');
|
|
@@ -762,13 +793,13 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
|
|
|
762
793
|
max_regression_pct: maxRegressionPct
|
|
763
794
|
});
|
|
764
795
|
for (let i = 0; i < warmups; i += 1) {
|
|
765
|
-
const warm = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck });
|
|
796
|
+
const warm = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck, cancellationCheck });
|
|
766
797
|
if (warm.timed_out || warm.exit_code !== 0) throw new Error(`benchmark warmup failed exit=${String(warm.exit_code)} timed_out=${warm.timed_out}`);
|
|
767
798
|
}
|
|
768
799
|
const samples = [];
|
|
769
800
|
let last = null;
|
|
770
801
|
for (let i = 0; i < iterations; i += 1) {
|
|
771
|
-
last = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck });
|
|
802
|
+
last = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck, cancellationCheck });
|
|
772
803
|
if (last.timed_out || last.exit_code !== 0) throw new Error(`benchmark iteration ${i + 1} failed exit=${String(last.exit_code)} timed_out=${last.timed_out}`);
|
|
773
804
|
samples.push(last.elapsed_ms);
|
|
774
805
|
}
|
|
@@ -474,7 +474,7 @@ async function reconcileInterrupted(ctx, plan, events, derived, codingRuntime, s
|
|
|
474
474
|
return deriveState(plan, events);
|
|
475
475
|
}
|
|
476
476
|
|
|
477
|
-
async function executeStep(codingRuntime, plan, step, attempt) {
|
|
477
|
+
async function executeStep(codingRuntime, plan, step, attempt, cancellationCheck = null) {
|
|
478
478
|
const receiptId = receiptIdFor(plan.task_id, step.step_id, attempt, plan.plan_sha256);
|
|
479
479
|
const requestSha256 = expectedRequest(codingRuntime, step);
|
|
480
480
|
if (step.kind === 'write') {
|
|
@@ -486,12 +486,12 @@ async function executeStep(codingRuntime, plan, step, attempt) {
|
|
|
486
486
|
} else if (step.kind === 'command') {
|
|
487
487
|
await codingRuntime.commandRun({ rootId: step.root_id, commandId: step.command_id, scriptPath: step.script_path,
|
|
488
488
|
scriptSha256: step.script_sha256, args: step.args, cwd: step.cwd, timeoutMs: step.timeout_ms,
|
|
489
|
-
receiptId, requestSha256 });
|
|
489
|
+
receiptId, requestSha256, cancellationCheck });
|
|
490
490
|
} else if (step.kind === 'benchmark') {
|
|
491
491
|
await codingRuntime.benchmarkRun({ rootId: step.root_id, commandId: step.command_id, scriptPath: step.script_path,
|
|
492
492
|
scriptSha256: step.script_sha256, args: step.args, cwd: step.cwd, timeoutMs: step.timeout_ms,
|
|
493
493
|
warmups: step.warmups, iterations: step.iterations, baselineMedianMs: step.baseline_median_ms,
|
|
494
|
-
maxRegressionPct: step.max_regression_pct, receiptId, requestSha256 });
|
|
494
|
+
maxRegressionPct: step.max_regression_pct, receiptId, requestSha256, cancellationCheck });
|
|
495
495
|
} else {
|
|
496
496
|
throw new Error(`coding step '${step.step_id}' is not executable`);
|
|
497
497
|
}
|
|
@@ -670,7 +670,10 @@ export function createCodingTaskRuntime({ codingRuntime, signingKeyPath, verifyK
|
|
|
670
670
|
try {
|
|
671
671
|
const remainingMs = timeoutMs === null ? null : Math.max(100, Math.floor(deadlineState(deadline).remaining_ms));
|
|
672
672
|
const boundedStep = remainingMs === null ? next : { ...next, timeout_ms: next.timeout_ms === null || next.timeout_ms === undefined ? remainingMs : Math.min(next.timeout_ms, remainingMs) };
|
|
673
|
-
const executed = await executeStep(codingRuntime, plan, boundedStep, attempt);
|
|
673
|
+
const executed = await executeStep(codingRuntime, plan, boundedStep, attempt,()=>readCancel(ctx,verifyKeyPath));
|
|
674
|
+
if(await consumeCancel(ctx,journal,signingKeyPath,verifyKeyPath)){
|
|
675
|
+
derived=deriveState(plan,journal);return {status:'cancelled',task_id:taskId,...derived};
|
|
676
|
+
}
|
|
674
677
|
if (!executed.outcome.valid) {
|
|
675
678
|
await appendEvent(ctx, journal, signingKeyPath, 'task_paused', {
|
|
676
679
|
stepId: next.step_id, payload: { reason: 'post_execute_receipt_mismatch', detail: executed.outcome.reason }
|
|
@@ -700,6 +703,9 @@ export function createCodingTaskRuntime({ codingRuntime, signingKeyPath, verifyK
|
|
|
700
703
|
}
|
|
701
704
|
derived = deriveState(plan, journal);
|
|
702
705
|
} catch (error) {
|
|
706
|
+
if(await consumeCancel(ctx,journal,signingKeyPath,verifyKeyPath)){
|
|
707
|
+
derived=deriveState(plan,journal);return {status:'cancelled',task_id:taskId,...derived};
|
|
708
|
+
}
|
|
703
709
|
if (deadlineExpired()) {
|
|
704
710
|
derived = await failDeadline(ctx, journal, plan, next.step_id);
|
|
705
711
|
return { status: 'failed', task_id: taskId, ...derived, deadline };
|
package/src/deadbyte-cli.mjs
CHANGED
|
@@ -16,6 +16,8 @@ import { printDoctor } from './doctor-r45.mjs';
|
|
|
16
16
|
import { createLiveTimelineFilter, createLiveTimelineTracker, createLiveTimelineWriter, formatCompactAuditEvent, formatRemoteLifecycle, formatRemoteToolCall, formatRuntimeDiagnosticLine, selectLiveLogNames } from './remote-live-log.mjs';
|
|
17
17
|
import { prepareRemoteConsole, remoteDisplayText } from './remote-console.mjs';
|
|
18
18
|
import { ensureRuntimeCoherence } from './runtime-coherence.mjs';
|
|
19
|
+
import { windowsPowerShellEnvironment } from './runtime-update.mjs';
|
|
20
|
+
import { resolveStateRoot } from './state-root.mjs';
|
|
19
21
|
|
|
20
22
|
const REMOTE_COMMANDS=new Set([
|
|
21
23
|
'menu','start','resume','park','stop','restart','status','url','test','fulltest','toggle','clean','machinetest',
|
|
@@ -42,7 +44,7 @@ const CURRENT_DEPLOY_SCRIPT=path.join(CURRENT_PACKAGE_ROOT,'scripts','deploy-r48
|
|
|
42
44
|
const REMOTE_UPDATE_TIMEOUT_MS=900000;
|
|
43
45
|
const LIVE_LOG_DISCOVERY_INTERVAL_MS=1000;
|
|
44
46
|
|
|
45
|
-
function stateRoot(){return
|
|
47
|
+
function stateRoot(){return resolveStateRoot();}
|
|
46
48
|
async function requireRegular(file,label){const info=await lstat(file);if(!info.isFile()||info.isSymbolicLink()) throw new Error(`${label} must be a regular non-symlink file`);return file;}
|
|
47
49
|
function printHelp(){
|
|
48
50
|
const exact=`deadbyte-mcp@${DEADBYTE_VERSION}`;
|
|
@@ -171,7 +173,7 @@ function invokeController(ctx,command,{capture=false,allowFailure=false,echoCapt
|
|
|
171
173
|
stderrFd=openSync(redirectOutput.stderr_path,'w');
|
|
172
174
|
stdio=['ignore',stdoutFd,stderrFd];
|
|
173
175
|
}else stdio=capture?['ignore','pipe','pipe']:'inherit';
|
|
174
|
-
const options={stdio,encoding:capture?'utf8':undefined,windowsHide:false,shell:false};
|
|
176
|
+
const options={stdio,encoding:capture?'utf8':undefined,windowsHide:false,shell:false,env:windowsPowerShellEnvironment()};
|
|
175
177
|
if(Number.isInteger(timeoutMs)&&timeoutMs>0) options.timeout=timeoutMs;
|
|
176
178
|
result=spawnSync(ctx.powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',ctx.launcher,command],options);
|
|
177
179
|
}finally{
|
package/src/doctor-r45.mjs
CHANGED
|
@@ -4,9 +4,10 @@ import os from 'node:os';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { DEADBYTE_VERSION, MCP_PROTOCOL_VERSION } from './version.mjs';
|
|
7
|
+
import { resolveStateRoot } from './state-root.mjs';
|
|
7
8
|
|
|
8
9
|
const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
|
|
9
|
-
const stateRoot=()=>
|
|
10
|
+
const stateRoot=()=>resolveStateRoot();
|
|
10
11
|
const sha256=b=>createHash('sha256').update(b).digest('hex');
|
|
11
12
|
async function jsonOrNull(file){try{return JSON.parse((await readFile(file,'utf8')).replace(/^\uFEFF/,''));}catch(e){if(e?.code==='ENOENT')return null;throw e;}}
|
|
12
13
|
async function fileHash(file){return sha256(await readFile(file));}
|