deadbyte-mcp 0.15.26 → 0.15.28
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/DEADBYTE-MCP.cmd +4 -0
- package/MANIFEST.SHA256 +28 -19
- package/PROVENANCE.json +10 -10
- package/README.txt +38 -14
- package/RELEASE.json +48 -15
- package/SBOM.cdx.json +3 -3
- package/TEST-MATRIX.json +135 -24
- package/package.json +4 -3
- package/scripts/deploy-r48.mjs +1 -1
- package/scripts/gate-windows-r50.ps1 +56 -0
- package/scripts/gate-windows-r51.ps1 +58 -0
- package/scripts/windows-gate-evidence-r50.mjs +80 -0
- package/scripts/windows-gate-evidence-r51.mjs +84 -0
- package/src/coding-plane.mjs +148 -17
- package/src/deadbyte-cli.mjs +88 -28
- package/src/remote-live-log.mjs +17 -5
- package/src/remote-session-guardian.mjs +1 -1
- package/src/runtime-coherence.mjs +50 -0
- package/src/version.mjs +1 -1
- package/test/coding-runtime.test.mjs +35 -1
- package/test/package-boundary.test.mjs +6 -0
- package/test/production-docs.test.mjs +5 -3
- package/test/r48-release-contract.test.mjs +26 -34
- package/test/r49-windows-gate.test.mjs +15 -11
- package/test/r51-live-log-polling.test.mjs +28 -0
- package/test/r51-release-contract.test.mjs +56 -0
- package/test/r51-runtime-coherence.test.mjs +59 -0
- package/test/remote-live-log-r37.test.mjs +14 -0
- package/test/remote-session-cli.test.mjs +24 -24
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
|
|
5
|
+
const root=new URL('../',import.meta.url);
|
|
6
|
+
const read=rel=>readFile(new URL(rel,root),'utf8');
|
|
7
|
+
const json=rel=>read(rel).then(JSON.parse);
|
|
8
|
+
|
|
9
|
+
test('R51 release identity is coherent across package lock source metadata SBOM and gate',async()=>{
|
|
10
|
+
const [pkg,lock,release,provenance,matrix,sbom,versionSource]=await Promise.all([
|
|
11
|
+
json('package.json'),json('package-lock.json'),json('RELEASE.json'),json('PROVENANCE.json'),json('TEST-MATRIX.json'),json('SBOM.cdx.json'),read('src/version.mjs')
|
|
12
|
+
]);
|
|
13
|
+
assert.equal(pkg.version,'0.15.28');
|
|
14
|
+
assert.equal(lock.version,pkg.version);
|
|
15
|
+
assert.equal(lock.packages[''].version,pkg.version);
|
|
16
|
+
assert.match(versionSource,/DEADBYTE_VERSION = '0\.15\.28'/);
|
|
17
|
+
assert.equal(release.version,pkg.version);
|
|
18
|
+
assert.equal(release.train,'R51');
|
|
19
|
+
assert.equal(provenance.version,pkg.version);
|
|
20
|
+
assert.equal(matrix.version,pkg.version);
|
|
21
|
+
assert.equal(matrix.train,'R51');
|
|
22
|
+
assert.equal(sbom.metadata.component.version,pkg.version);
|
|
23
|
+
assert.equal(sbom.serialNumber,'urn:cdx:deadbyte-mcp:r51:0.15.28');
|
|
24
|
+
assert.match(pkg.scripts['gate:windows'],/gate-windows-r51\.ps1/);
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
test('R51 lineage binds exact immutable published 0.15.27 parent',async()=>{
|
|
28
|
+
const [release,provenance]=await Promise.all([json('RELEASE.json'),json('PROVENANCE.json')]);
|
|
29
|
+
const expected={
|
|
30
|
+
release_id:'v0.15.27-1b1dbe24b45ad06a',
|
|
31
|
+
manifest_sha256:'1b1dbe24b45ad06a62771d15f510662952f3d7c3e5aa08053c6c61511c523e47',
|
|
32
|
+
generation_manifest_sha256:'f87a1637b3c55ba050d079d8a5e0862a2244b306be7e985880708e0d8ded3db0'
|
|
33
|
+
};
|
|
34
|
+
assert.deepEqual(release.parent,expected);
|
|
35
|
+
assert.equal(release.source_predecessor.version,'0.15.27');
|
|
36
|
+
assert.equal(release.source_predecessor.tarball_sha256,'e728031d097d8678dfef80f8648cce65e72a96611052c31969c80f884506d1d7');
|
|
37
|
+
assert.equal(release.source_predecessor.manifest_file_sha256,expected.manifest_sha256);
|
|
38
|
+
assert.equal(provenance.parent_release_id,expected.release_id);
|
|
39
|
+
assert.equal(provenance.parent_manifest_sha256,expected.manifest_sha256);
|
|
40
|
+
assert.equal(provenance.parent_generation_manifest_sha256,expected.generation_manifest_sha256);
|
|
41
|
+
assert.equal(provenance.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('R51 release advertises only implemented coherence single-flight authority and livelog hardening',async()=>{
|
|
45
|
+
const release=await json('RELEASE.json');
|
|
46
|
+
for(const key of [
|
|
47
|
+
'runtime_package_auto_coherence',
|
|
48
|
+
'coding_command_singleflight',
|
|
49
|
+
'coding_command_result_dedup_cache',
|
|
50
|
+
'foreground_desktop_host_fail_closed',
|
|
51
|
+
'human_livelog_slow_call_marker',
|
|
52
|
+
'human_livelog_peak_inflight',
|
|
53
|
+
'human_livelog_bounded_discovery',
|
|
54
|
+
'human_livelog_single_parse'
|
|
55
|
+
]) assert.equal(release.capabilities[key],true,key);
|
|
56
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { ensureRuntimeCoherence } from '../src/runtime-coherence.mjs';
|
|
4
|
+
|
|
5
|
+
const hex=value=>value.repeat(64).slice(0,64);
|
|
6
|
+
|
|
7
|
+
test('R51 runtime coherence upgrades older active slot exactly once and verifies final identity',async()=>{
|
|
8
|
+
let active={version:'0.15.27',manifest_sha256:hex('1'),release_id:'old'};
|
|
9
|
+
let disarms=0,activations=0;
|
|
10
|
+
const events=[];
|
|
11
|
+
const result=await ensureRuntimeCoherence({
|
|
12
|
+
cliVersion:'0.15.28',packageManifestSha256:hex('2'),
|
|
13
|
+
readActive:async()=>active,
|
|
14
|
+
disarmPrivileged:async()=>{disarms++;},
|
|
15
|
+
activateCurrentPackage:async()=>{activations++;active={version:'0.15.28',manifest_sha256:hex('2'),release_id:'new'};},
|
|
16
|
+
onEvent:event=>events.push(event)
|
|
17
|
+
});
|
|
18
|
+
assert.equal(result.status,'upgraded');
|
|
19
|
+
assert.equal(result.active.version,'0.15.28');
|
|
20
|
+
assert.equal(disarms,1);assert.equal(activations,1);
|
|
21
|
+
assert.deepEqual(events.map(event=>event.phase),['upgrade_start','upgrade_complete']);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
test('R51 runtime coherence is non-mutating when version and manifest already match',async()=>{
|
|
25
|
+
let mutations=0;
|
|
26
|
+
const active={version:'0.15.28',manifest_sha256:hex('a'),release_id:'same'};
|
|
27
|
+
const result=await ensureRuntimeCoherence({cliVersion:'0.15.28',packageManifestSha256:hex('a'),readActive:async()=>active,
|
|
28
|
+
disarmPrivileged:async()=>{mutations++;},activateCurrentPackage:async()=>{mutations++;}});
|
|
29
|
+
assert.equal(result.status,'coherent');assert.equal(mutations,0);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
test('R51 runtime coherence refuses downgrade and same-version manifest drift',async()=>{
|
|
33
|
+
await assert.rejects(()=>ensureRuntimeCoherence({cliVersion:'0.15.28',packageManifestSha256:hex('a'),
|
|
34
|
+
readActive:async()=>({version:'0.15.29',manifest_sha256:hex('b')}),disarmPrivileged:async()=>{},activateCurrentPackage:async()=>{}}),/newer than CLI/i);
|
|
35
|
+
await assert.rejects(()=>ensureRuntimeCoherence({cliVersion:'0.15.28',packageManifestSha256:hex('a'),
|
|
36
|
+
readActive:async()=>({version:'0.15.28',manifest_sha256:hex('b')}),disarmPrivileged:async()=>{},activateCurrentPackage:async()=>{}}),/manifest skew/i);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
test('R51 bare remote wires coherence before live generation binding and deploy honors state root override',async()=>{
|
|
41
|
+
const {readFile}=await import('node:fs/promises');
|
|
42
|
+
const cli=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
43
|
+
const deploy=await readFile(new URL('../scripts/deploy-r48.mjs',import.meta.url),'utf8');
|
|
44
|
+
assert.match(cli,/ensureRuntimeCoherence/);
|
|
45
|
+
assert.match(cli,/synchronizeForegroundRuntime/);
|
|
46
|
+
const syncAt=cli.indexOf('await synchronizeForegroundRuntime');
|
|
47
|
+
const rootsAt=cli.indexOf('await readLiveRootPaths');
|
|
48
|
+
assert.ok(syncAt>=0&&rootsAt>syncAt,'runtime coherence must complete before binding generation root paths');
|
|
49
|
+
assert.match(deploy,/process\.env\.DEADBYTE_STATE_ROOT/);
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
test('R51 foreground authority contract explicitly verifies and cleans desktop plus host',async()=>{
|
|
54
|
+
const {readFile}=await import('node:fs/promises');
|
|
55
|
+
const cli=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
56
|
+
assert.match(cli,/\['desktopstatus',\/\^Desktop plane/);
|
|
57
|
+
assert.match(cli,/SESSION_CLEANUP=.*disarmdesktop.*disarmhost/s);
|
|
58
|
+
assert.match(cli,/desktop, host DISARMED/);
|
|
59
|
+
});
|
|
@@ -204,3 +204,17 @@ test('expanded session summary reports outcome classes latency and slowest tool'
|
|
|
204
204
|
assert.match(summary,/p50 75ms \| p95 200ms/);
|
|
205
205
|
assert.match(summary,/slowest host_exec 200ms/);
|
|
206
206
|
});
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
test('R51 live timeline marks slow calls and reports peak in-flight concurrency',()=>{
|
|
210
|
+
let now=1000;
|
|
211
|
+
const tracker=createLiveTimelineTracker({clock:()=>now,slowCallMs:1000});
|
|
212
|
+
tracker.observe({event_type:'tool.request',tool:'coding_command_run',request_id:'slow-a-12345678',args:{root_id:'core',command_id:'node_script',script_path:'a.mjs'}});
|
|
213
|
+
tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'slow-b-12345678',args:{root_id:'core',path:'b.txt'}});
|
|
214
|
+
now=2500;
|
|
215
|
+
const line=tracker.observe({event_type:'tool.result',tool:'coding_command_run',request_id:'slow-a-12345678',outcome:{is_error:false,duration_ms:1500}});
|
|
216
|
+
assert.match(line,/1500ms|1\.50s/);
|
|
217
|
+
assert.match(line,/\[SLOW\]/);
|
|
218
|
+
tracker.observe({event_type:'tool.result',tool:'coding_file_read',request_id:'slow-b-12345678',outcome:{is_error:false,duration_ms:5}});
|
|
219
|
+
assert.match(tracker.summary(),/peak in-flight 2/);
|
|
220
|
+
});
|
|
@@ -23,7 +23,7 @@ async function fixture({failCommand='',statusOnline=false}={}){
|
|
|
23
23
|
const spawnedPid=path.join(dir,'spawned.pid');
|
|
24
24
|
await mkdir(bin,{recursive:true});
|
|
25
25
|
const launcher=path.join(bin,'DEADBYTE-MCP.ps1');
|
|
26
|
-
const ps1=`param([string]$Command)\n$ErrorActionPreference='Stop'\nfor($i=0;$i -lt 20;$i++){ try { [IO.File]::AppendAllText($env:DEADBYTE_REMOTE_TEST_TRACE,(\"$Command\" + [Environment]::NewLine),[Text.Encoding]::UTF8); break } catch { if($i -eq 19){ throw }; Start-Sleep -Milliseconds 10 } }\nif ($env:DEADBYTE_REMOTE_TEST_FAIL -and $Command -eq $env:DEADBYTE_REMOTE_TEST_FAIL) { $runtime=Join-Path $env:DEADBYTE_STATE_ROOT 'runtime'; New-Item -ItemType Directory -Path $runtime -Force | Out-Null; $failure=@{ schema='deadbyte.controller-start-failure.v1'; command=$Command; failed_at_utc='2026-09-26T00:00:00.000Z'; message='fixture controller evidence detail' } | ConvertTo-Json -Compress; [IO.File]::WriteAllText((Join-Path $runtime 'controller-start-failure.json'),$failure,[Text.Encoding]::UTF8); Write-Error \"forced $Command failure\"; exit 9 }\nswitch ($Command) {\n 'start' { if ($env:DEADBYTE_REMOTE_TEST_SPAWN_CHILD -eq '1') { $node=(Get-Command node.exe).Source; $spawned=Start-Process -FilePath $node -ArgumentList @('-e','setTimeout(()=>process.exit(0),10000)') -PassThru -WindowStyle Hidden -RedirectStandardOutput $env:DEADBYTE_REMOTE_TEST_SPAWN_STDOUT -RedirectStandardError $env:DEADBYTE_REMOTE_TEST_SPAWN_STDERR; if ($env:DEADBYTE_REMOTE_TEST_SPAWN_PID) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_SPAWN_PID,[string]$spawned.Id,[Text.Encoding]::UTF8) } }; if ($env:DEADBYTE_REMOTE_TEST_STARTED) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_STARTED,'1',[Text.Encoding]::UTF8) }; Write-Host 'DEADBYTE MCP = ONLINE' }\n 'status' { if ($env:DEADBYTE_REMOTE_TEST_STATUS_ONLINE -eq '1' -or ($env:DEADBYTE_REMOTE_TEST_STARTED -and (Test-Path -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED))) { Write-Host 'DEADBYTE MCP = ONLINE'; Write-Host 'Bridge PID : 1001 [verified]'; Write-Host 'Cloud PID : 1002 [verified]'; Write-Host 'Local ready : True'; Write-Host 'Loop supervisor: RUNNING [verified]' } else { Write-Host 'DEADBYTE MCP = OFFLINE' } }\n 'processstatus' { Write-Host 'Process plane : ARMED [standing-grant]' }\n 'codingstatus' { Write-Host 'Coding plane : ARMED [standing-grant]' }\n 'autonomousstatus' { Write-Host 'Autonomous : ARMED [standing-grant]' }\n 'hoststatus' { Write-Host 'Host plane : DISARMED [disarmed]' }\n 'park' { if ($env:DEADBYTE_REMOTE_TEST_STARTED) { Remove-Item -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED -Force -ErrorAction SilentlyContinue }; Write-Host 'DEADBYTE MCP = PARKED' }\n default { Write-Host \"$Command OK\" }\n}\nexit 0\n`;
|
|
26
|
+
const ps1=`param([string]$Command)\n$ErrorActionPreference='Stop'\nfor($i=0;$i -lt 20;$i++){ try { [IO.File]::AppendAllText($env:DEADBYTE_REMOTE_TEST_TRACE,(\"$Command\" + [Environment]::NewLine),[Text.Encoding]::UTF8); break } catch { if($i -eq 19){ throw }; Start-Sleep -Milliseconds 10 } }\nif ($env:DEADBYTE_REMOTE_TEST_FAIL -and $Command -eq $env:DEADBYTE_REMOTE_TEST_FAIL) { $runtime=Join-Path $env:DEADBYTE_STATE_ROOT 'runtime'; New-Item -ItemType Directory -Path $runtime -Force | Out-Null; $failure=@{ schema='deadbyte.controller-start-failure.v1'; command=$Command; failed_at_utc='2026-09-26T00:00:00.000Z'; message='fixture controller evidence detail' } | ConvertTo-Json -Compress; [IO.File]::WriteAllText((Join-Path $runtime 'controller-start-failure.json'),$failure,[Text.Encoding]::UTF8); Write-Error \"forced $Command failure\"; exit 9 }\nswitch ($Command) {\n 'start' { if ($env:DEADBYTE_REMOTE_TEST_SPAWN_CHILD -eq '1') { $node=(Get-Command node.exe).Source; $spawned=Start-Process -FilePath $node -ArgumentList @('-e','setTimeout(()=>process.exit(0),10000)') -PassThru -WindowStyle Hidden -RedirectStandardOutput $env:DEADBYTE_REMOTE_TEST_SPAWN_STDOUT -RedirectStandardError $env:DEADBYTE_REMOTE_TEST_SPAWN_STDERR; if ($env:DEADBYTE_REMOTE_TEST_SPAWN_PID) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_SPAWN_PID,[string]$spawned.Id,[Text.Encoding]::UTF8) } }; if ($env:DEADBYTE_REMOTE_TEST_STARTED) { [IO.File]::WriteAllText($env:DEADBYTE_REMOTE_TEST_STARTED,'1',[Text.Encoding]::UTF8) }; Write-Host 'DEADBYTE MCP = ONLINE' }\n 'status' { if ($env:DEADBYTE_REMOTE_TEST_STATUS_ONLINE -eq '1' -or ($env:DEADBYTE_REMOTE_TEST_STARTED -and (Test-Path -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED))) { Write-Host 'DEADBYTE MCP = ONLINE'; Write-Host 'Bridge PID : 1001 [verified]'; Write-Host 'Cloud PID : 1002 [verified]'; Write-Host 'Local ready : True'; Write-Host 'Loop supervisor: RUNNING [verified]' } else { Write-Host 'DEADBYTE MCP = OFFLINE' } }\n 'processstatus' { Write-Host 'Process plane : ARMED [standing-grant]' }\n 'codingstatus' { Write-Host 'Coding plane : ARMED [standing-grant]' }\n 'autonomousstatus' { Write-Host 'Autonomous : ARMED [standing-grant]' }\n 'desktopstatus' { Write-Host 'Desktop plane : DISARMED [disarmed]' }\n 'hoststatus' { Write-Host 'Host plane : DISARMED [disarmed]' }\n 'park' { if ($env:DEADBYTE_REMOTE_TEST_STARTED) { Remove-Item -LiteralPath $env:DEADBYTE_REMOTE_TEST_STARTED -Force -ErrorAction SilentlyContinue }; Write-Host 'DEADBYTE MCP = PARKED' }\n default { Write-Host \"$Command OK\" }\n}\nexit 0\n`;
|
|
27
27
|
await writeFile(launcher,ps1,'utf8');
|
|
28
28
|
return {dir,state,trace,env:{...process.env,DEADBYTE_STATE_ROOT:state,DEADBYTE_REMOTE_TEST_TRACE:trace,DEADBYTE_REMOTE_TEST_FAIL:failCommand,DEADBYTE_REMOTE_TEST_STATUS_ONLINE:statusOnline?'1':'0',DEADBYTE_REMOTE_TEST_STARTED:startedMarker,DEADBYTE_REMOTE_TEST_SPAWN_STDOUT:spawnedStdout,DEADBYTE_REMOTE_TEST_SPAWN_STDERR:spawnedStderr,DEADBYTE_REMOTE_TEST_SPAWN_PID:spawnedPid},spawnedPid};
|
|
29
29
|
}
|
|
@@ -77,17 +77,17 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
|
|
|
77
77
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
78
78
|
const output=await collect(child);
|
|
79
79
|
const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'),{timeoutMs:8000});
|
|
80
|
-
assert.deepEqual(ready.slice(0,
|
|
80
|
+
assert.deepEqual(ready.slice(0,9),[
|
|
81
81
|
'status','armprocess','armcoding','armautonomous',
|
|
82
|
-
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
82
|
+
'processstatus','codingstatus','autonomousstatus','desktopstatus','hoststatus'
|
|
83
83
|
]);
|
|
84
84
|
assert.doesNotMatch(ready.join(','),/(^|,)start(,|$)/);
|
|
85
85
|
assert.equal(child.exitCode,null,'remote session must remain foreground after reusing ONLINE runtime');
|
|
86
86
|
assert.match(output.stdout,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
87
87
|
const authDeadline=Date.now()+3000;
|
|
88
|
-
while(Date.now()<authDeadline&&!/\[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/.test(output.stdout)) await sleep(50);
|
|
88
|
+
while(Date.now()<authDeadline&&!/\[AUTH\] ARMED: process, coding, autonomous \| desktop, host DISARMED/.test(output.stdout)) await sleep(50);
|
|
89
89
|
assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
|
|
90
|
-
assert.match(output.stdout,/\[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/);
|
|
90
|
+
assert.match(output.stdout,/\[AUTH\] ARMED: process, coding, autonomous \| desktop, host DISARMED/);
|
|
91
91
|
child.kill('SIGINT');
|
|
92
92
|
await output.closed;
|
|
93
93
|
}finally{
|
|
@@ -106,9 +106,9 @@ winTest('bare remote PARKED startup does not wait for a long-lived child holding
|
|
|
106
106
|
const output=await collect(child);
|
|
107
107
|
const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'),{timeoutMs:8000});
|
|
108
108
|
const elapsed=Date.now()-startedAt;
|
|
109
|
-
assert.deepEqual(ready.slice(0,
|
|
109
|
+
assert.deepEqual(ready.slice(0,11),[
|
|
110
110
|
'status','start','status','armprocess','armcoding','armautonomous',
|
|
111
|
-
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
111
|
+
'processstatus','codingstatus','autonomousstatus','desktopstatus','hoststatus'
|
|
112
112
|
]);
|
|
113
113
|
assert.ok(elapsed<7000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
|
|
114
114
|
assert.equal(child.exitCode,null,'remote session must remain foreground after PARKED startup');
|
|
@@ -133,13 +133,13 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
133
133
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
134
134
|
const output=await collect(child);
|
|
135
135
|
const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
|
|
136
|
-
assert.deepEqual(ready.slice(0,
|
|
136
|
+
assert.deepEqual(ready.slice(0,11),[
|
|
137
137
|
'status','start','status','armprocess','armcoding','armautonomous',
|
|
138
|
-
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
138
|
+
'processstatus','codingstatus','autonomousstatus','desktopstatus','hoststatus'
|
|
139
139
|
]);
|
|
140
140
|
assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
|
|
141
141
|
const tailDeadline=Date.now()+3000;
|
|
142
|
-
while(Date.now()<tailDeadline&&!/\[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/.test(output.stdout)) await sleep(50);
|
|
142
|
+
while(Date.now()<tailDeadline&&!/\[AUTH\] ARMED: process, coding, autonomous \| desktop, host DISARMED/.test(output.stdout)) await sleep(50);
|
|
143
143
|
assert.match(output.stdout,/\[DISPLAY\] ASCII fallback: stdout_not_tty/);
|
|
144
144
|
assert.match(output.stdout,/\[DEVICE\] Starting DEADBYTE MCP/);
|
|
145
145
|
assert.match(output.stdout,/\[BRIDGE\] Local bridge connected/);
|
|
@@ -148,7 +148,7 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
148
148
|
assert.match(output.stdout,/\[BOOT\] Starting local \+ remote runtime/);
|
|
149
149
|
assert.match(output.stdout,/\[OK\] ONLINE/);
|
|
150
150
|
assert.match(output.stdout,/\[READY\] DEADBYTE MCP online/);
|
|
151
|
-
assert.match(output.stdout,/\[AUTH\] ARMED: process, coding, autonomous \| host DISARMED/);
|
|
151
|
+
assert.match(output.stdout,/\[AUTH\] ARMED: process, coding, autonomous \| desktop, host DISARMED/);
|
|
152
152
|
assert.match(output.stdout,/\[LOG\] Human live timeline\. Transport IN\/OUT hidden; full replay\/audit detail remains on disk\./);
|
|
153
153
|
assert.doesNotMatch(output.stdout,/Process plane\s*:/);
|
|
154
154
|
assert.doesNotMatch(output.stdout,/Coding plane\s*:/);
|
|
@@ -172,10 +172,10 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
172
172
|
'[TOOL OUT] 2026-09-16T00:00:00.002Z #000002 coding_file_read {"is_error":true}'
|
|
173
173
|
].join('\n')+'\n','utf8');
|
|
174
174
|
const logDeadline=Date.now()+3000;
|
|
175
|
-
while(Date.now()<logDeadline&&!/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s ERR$/m.test(output.stdout)) await sleep(50);
|
|
175
|
+
while(Date.now()<logDeadline&&!/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m.test(output.stdout)) await sleep(50);
|
|
176
176
|
assert.doesNotMatch(output.stdout,/\| Arguments:/,'default human view must not print request JSON');
|
|
177
177
|
assert.match(output.stdout,/^S .*#2 \[abcdef12\] coding_tree projects:src 42ms OK$/m);
|
|
178
|
-
assert.match(output.stdout,/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s ERR$/m);
|
|
178
|
+
assert.match(output.stdout,/^R .*#4 \[fedcba98\] coding_file_read projects:src\/deadbyte-cli\.mjs 1\.73s \[SLOW\] ERR$/m);
|
|
179
179
|
assert.equal((output.stdout.match(/\[abcdef12\].*coding_tree.*42ms.*OK/g)||[]).length,1,'duplicate terminal result must print once');
|
|
180
180
|
assert.doesNotMatch(output.stdout,/\[cursor r1:/,'full replay cursor belongs in the journal, not every human line');
|
|
181
181
|
const resultJournal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',`${marker.result_session_id}.json`),'utf8'));
|
|
@@ -194,11 +194,11 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
194
194
|
const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
|
|
195
195
|
assert.equal(ended.timeout,undefined,'remote session did not exit after foreground input closed');
|
|
196
196
|
const commands=await traceCommands(fx.trace);
|
|
197
|
-
assert.deepEqual(commands.slice(-
|
|
197
|
+
assert.deepEqual(commands.slice(-6),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','park']);
|
|
198
198
|
assert.match(output.stdout,/^DEADBYTE MCP$/m);
|
|
199
199
|
assert.match(output.stdout,/Human live timeline/i);
|
|
200
200
|
assert.match(output.stdout,/\[AUTH\] Revoking session authority/);
|
|
201
|
-
assert.doesNotMatch(output.stdout,/disarmautonomous OK|disarmcoding OK|disarmprocess OK|disarmhost OK|DEADBYTE MCP = PARKED/);
|
|
201
|
+
assert.doesNotMatch(output.stdout,/disarmautonomous OK|disarmcoding OK|disarmprocess OK|disarmdesktop OK|disarmhost OK|DEADBYTE MCP = PARKED/);
|
|
202
202
|
assert.doesNotMatch(output.stdout,/\p{Extended_Pictographic}/u,'piped Windows fallback must remain ASCII-safe');
|
|
203
203
|
}finally{
|
|
204
204
|
if(child?.exitCode===null) child.kill();
|
|
@@ -293,7 +293,7 @@ winTest('remote --verbose enables sanitized request detail while preserving fore
|
|
|
293
293
|
assert.equal(ended.timeout,undefined);
|
|
294
294
|
assert.equal(ended.code,0,output.stderr);
|
|
295
295
|
const commands=await traceCommands(fx.trace);
|
|
296
|
-
assert.deepEqual(commands.slice(-
|
|
296
|
+
assert.deepEqual(commands.slice(-6),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','park']);
|
|
297
297
|
}finally{
|
|
298
298
|
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
299
299
|
await rm(fx.dir,{recursive:true,force:true});
|
|
@@ -307,9 +307,9 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
|
|
|
307
307
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
308
308
|
const output=await collect(child);
|
|
309
309
|
const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
|
|
310
|
-
assert.deepEqual(ready.slice(0,
|
|
310
|
+
assert.deepEqual(ready.slice(0,11),[
|
|
311
311
|
'status','start','status','armprocess','armcoding','armautonomous',
|
|
312
|
-
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
312
|
+
'processstatus','codingstatus','autonomousstatus','desktopstatus','hoststatus'
|
|
313
313
|
]);
|
|
314
314
|
const markerPath=path.join(fx.state,'runtime','remote-session.json');
|
|
315
315
|
const markerDeadline=Date.now()+3000;
|
|
@@ -327,8 +327,8 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
|
|
|
327
327
|
assert.equal(killed,true,'failed to hard-kill remote owner');
|
|
328
328
|
await Promise.race([output.closed,sleep(3000)]);
|
|
329
329
|
|
|
330
|
-
const cleaned=await waitFor(fx.trace,commands=>commands.slice(-
|
|
331
|
-
assert.deepEqual(cleaned.slice(-
|
|
330
|
+
const cleaned=await waitFor(fx.trace,commands=>commands.slice(-6).join(',')==='disarmautonomous,disarmcoding,disarmprocess,disarmhost,park',{timeoutMs:10000});
|
|
331
|
+
assert.deepEqual(cleaned.slice(-6),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','park']);
|
|
332
332
|
const markerGoneDeadline=Date.now()+3000;
|
|
333
333
|
let markerGone=false;
|
|
334
334
|
while(Date.now()<markerGoneDeadline){
|
|
@@ -352,7 +352,7 @@ winTest('bare remote rolls back authority and parks if one plane fails to arm',a
|
|
|
352
352
|
assert.notEqual(ended.code,0);
|
|
353
353
|
const commands=await traceCommands(fx.trace);
|
|
354
354
|
assert.deepEqual(commands.slice(0,5),['status','start','status','armprocess','armcoding']);
|
|
355
|
-
assert.deepEqual(commands.slice(-
|
|
355
|
+
assert.deepEqual(commands.slice(-6),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','park']);
|
|
356
356
|
assert.doesNotMatch(output.stdout,/Live logs/i);
|
|
357
357
|
}finally{await rm(fx.dir,{recursive:true,force:true});}
|
|
358
358
|
});
|
|
@@ -367,9 +367,9 @@ winTest('bare remote recovers a stale crashed session before arming a new one',a
|
|
|
367
367
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
368
368
|
const output=await collect(child);
|
|
369
369
|
const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'));
|
|
370
|
-
assert.deepEqual(ready.slice(0,
|
|
371
|
-
assert.equal(ready[
|
|
372
|
-
assert.equal(ready[
|
|
370
|
+
assert.deepEqual(ready.slice(0,6),['disarmautonomous','disarmcoding','disarmprocess','disarmdesktop','disarmhost','park']);
|
|
371
|
+
assert.equal(ready[6],'status');
|
|
372
|
+
assert.equal(ready[7],'start');
|
|
373
373
|
assert.match(output.stdout,/\[RECOVERY\] Stale remote session pid=2147483000; revoking authority before restart\./);
|
|
374
374
|
child.stdin.end();
|
|
375
375
|
const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
|