deadbyte-mcp 0.11.1 → 0.11.3
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 +36 -20
- package/README.txt +7 -7
- package/controller/README.TXT +1 -1
- package/controller/deadbyte-controller.ps1 +4 -4
- package/docs/ARCHITECTURE.md +1 -1
- package/package.json +6 -6
- package/scripts/deferred-slot-operation-r38.mjs +124 -0
- package/scripts/deferred-slot-operation-r39.mjs +124 -0
- package/scripts/final-closure-r38.mjs +113 -0
- package/scripts/final-closure-r39.mjs +113 -0
- package/scripts/final-closure-verify-r38.mjs +208 -0
- package/scripts/final-closure-verify-r39.mjs +208 -0
- package/scripts/gate-windows-r38.ps1 +42 -0
- package/scripts/gate-windows-r39.ps1 +42 -0
- package/scripts/release-parity-r38.mjs +200 -0
- package/scripts/release-parity-r39.mjs +200 -0
- package/scripts/release-parity-tests-r38.ps1 +9 -0
- package/scripts/release-parity-tests-r39.ps1 +9 -0
- package/scripts/windows-gate-evidence-r38.mjs +52 -0
- package/scripts/windows-gate-evidence-r39.mjs +52 -0
- package/src/deadbyte-cli.mjs +7 -3
- package/src/release-generation.mjs +18 -1
- package/src/remote-live-log.mjs +9 -2
- package/src/version.mjs +1 -1
- package/test/cli-entrypoint.test.mjs +1 -1
- package/test/controller.test.mjs +11 -0
- package/test/core.test.mjs +1 -1
- package/test/production-docs.test.mjs +3 -3
- package/test/r33-closeout-regression.test.mjs +8 -8
- package/test/r33-finalization.test.mjs +14 -14
- package/test/r37-remote-tool-call-timeline.test.mjs +2 -2
- package/test/r38-finalization.test.mjs +74 -0
- package/test/r39-finalization.test.mjs +74 -0
- package/test/release-generation.test.mjs +13 -3
- package/test/release-version.test.mjs +47 -25
- package/test/remote-live-log-r37.test.mjs +1 -1
- package/test/remote-session-cli.test.mjs +46 -12
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence, R38_PREDECESSOR_RELEASE_ID, R38_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r38.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r38.mjs';
|
|
6
|
+
|
|
7
|
+
const root=new URL('../',import.meta.url);
|
|
8
|
+
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
9
|
+
|
|
10
|
+
function parityFixture(){
|
|
11
|
+
const manifest='a'.repeat(64);
|
|
12
|
+
return {
|
|
13
|
+
schema:'deadbyte.r38-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
14
|
+
candidate:{release_id:`v0.11.2-${manifest.slice(0,16)}`,version:'0.11.2',manifest_sha256:manifest},
|
|
15
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r38',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
|
|
16
|
+
local_full:{status:'passed',tool_count:76,strict_output_schemas:true},
|
|
17
|
+
public_compact:{status:'passed',tool_count:41,capability_closure:true,gateway_count:5},
|
|
18
|
+
autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
|
|
19
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
|
|
20
|
+
rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
|
|
21
|
+
predecessor:{release_id:R38_PREDECESSOR_RELEASE_ID,version:'0.11.1',manifest_sha256:R38_PREDECESSOR_MANIFEST},
|
|
22
|
+
predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
|
|
23
|
+
successor:{release_id:`v0.11.2-${manifest.slice(0,16)}`,version:'0.11.2',manifest_sha256:manifest},
|
|
24
|
+
successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
|
|
25
|
+
requirements:Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface'].map(key=>[key,true]))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test('R38 parity validator requires full-76, compact closure, exact public 0.11.1 predecessor and immutable-slot separation',()=>{
|
|
30
|
+
const good=parityFixture();
|
|
31
|
+
assert.equal(validateParityEvidence(good),true);
|
|
32
|
+
assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:75}}),/full 76/i);
|
|
33
|
+
assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,capability_closure:false}}),/compact closure/i);
|
|
34
|
+
assert.throws(()=>validateParityEvidence({...good,predecessor:{...good.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
35
|
+
assert.throws(()=>validateParityEvidence({...good,immutable_slot:{...good.immutable_slot,development_root:good.immutable_slot.release_root}}),/immutable-slot/i);
|
|
36
|
+
assert.throws(()=>validateParityEvidence({...good,stage_restore:{status:'missing',manifest_sha256:good.candidate.manifest_sha256}}),/stage restore/i);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('R38 parity captures R38 bridge, exact public 0.11.1 predecessor, stage reseed and successor restore',async()=>{
|
|
40
|
+
const parity=await text('scripts/release-parity-r38.mjs');
|
|
41
|
+
assert.match(parity,/R38_PREDECESSOR_RELEASE_ID='v0\.11\.1-220fac89dd82cdcd'/);
|
|
42
|
+
assert.match(parity,/220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76/);
|
|
43
|
+
assert.match(parity,/const stageRestore=await restoreFrozenStage/);
|
|
44
|
+
assert.match(parity,/publicR38Disarmed/);
|
|
45
|
+
assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('R38 current final closure writer and independent verifier bind R38 domains and public 0.11.1 predecessor',async()=>{
|
|
49
|
+
const [writer,verifier]=await Promise.all([text('scripts/final-closure-r38.mjs'),text('scripts/final-closure-verify-r38.mjs')]);
|
|
50
|
+
assert.equal(typeof verifyFinalClosureObject,'function');
|
|
51
|
+
assert.match(writer,/DEADBYTE-R38-FINAL-CLOSURE-V1/);
|
|
52
|
+
assert.match(writer,/deadbyte\.r38-final-closure\.v1/);
|
|
53
|
+
assert.match(writer,/pointer\.version==='0\.11\.2'/);
|
|
54
|
+
assert.match(writer,/R38 FINAL MACHINE BASELINE/);
|
|
55
|
+
assert.match(writer,/deadbyte\.r38-parity\.v1/);
|
|
56
|
+
assert.match(writer,/deadbyte\.r38-windows-gate\.v1/);
|
|
57
|
+
assert.match(writer,/R38_PREDECESSOR_RELEASE_ID/);
|
|
58
|
+
assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
|
|
59
|
+
assert.match(verifier,/DEADBYTE-R38-FINAL-CLOSURE-V1/);
|
|
60
|
+
assert.match(verifier,/deadbyte\.r38-final-closure\.v1/);
|
|
61
|
+
assert.match(verifier,/envelope\.body\.version==='0\.11\.2'/);
|
|
62
|
+
assert.match(verifier,/R38 FINAL MACHINE BASELINE/);
|
|
63
|
+
assert.match(verifier,/deadbyte\.r38-parity\.v1/);
|
|
64
|
+
assert.match(verifier,/deadbyte\.r38-windows-gate\.v1/);
|
|
65
|
+
assert.match(verifier,/220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76/);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('R38 bounded public parity suite covers current release identity and agent fabric',async()=>{
|
|
69
|
+
const script=await text('scripts/release-parity-tests-r38.ps1');
|
|
70
|
+
assert.match(script,/r38-finalization\.test\.mjs/);
|
|
71
|
+
assert.match(script,/release-version\.test\.mjs/);
|
|
72
|
+
assert.match(script,/r37-agent-fabric\.test\.mjs/);
|
|
73
|
+
assert.match(script,/remote-live-log-r37\.test\.mjs/);
|
|
74
|
+
});
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence, R39_PREDECESSOR_RELEASE_ID, R39_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r39.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r39.mjs';
|
|
6
|
+
|
|
7
|
+
const root=new URL('../',import.meta.url);
|
|
8
|
+
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
9
|
+
|
|
10
|
+
function parityFixture(){
|
|
11
|
+
const manifest='a'.repeat(64);
|
|
12
|
+
return {
|
|
13
|
+
schema:'deadbyte.r39-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
14
|
+
candidate:{release_id:`v0.11.3-${manifest.slice(0,16)}`,version:'0.11.3',manifest_sha256:manifest},
|
|
15
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r39',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
|
|
16
|
+
local_full:{status:'passed',tool_count:76,strict_output_schemas:true},
|
|
17
|
+
public_compact:{status:'passed',tool_count:41,capability_closure:true,gateway_count:5},
|
|
18
|
+
autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
|
|
19
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
|
|
20
|
+
rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
|
|
21
|
+
predecessor:{release_id:R39_PREDECESSOR_RELEASE_ID,version:'0.11.2',manifest_sha256:R39_PREDECESSOR_MANIFEST},
|
|
22
|
+
predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
|
|
23
|
+
successor:{release_id:`v0.11.3-${manifest.slice(0,16)}`,version:'0.11.3',manifest_sha256:manifest},
|
|
24
|
+
successor_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false},
|
|
25
|
+
requirements:Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface'].map(key=>[key,true]))
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
test('R39 parity validator requires full-76, compact closure, exact public 0.11.2 predecessor and immutable-slot separation',()=>{
|
|
30
|
+
const good=parityFixture();
|
|
31
|
+
assert.equal(validateParityEvidence(good),true);
|
|
32
|
+
assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:75}}),/full 76/i);
|
|
33
|
+
assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,capability_closure:false}}),/compact closure/i);
|
|
34
|
+
assert.throws(()=>validateParityEvidence({...good,predecessor:{...good.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
35
|
+
assert.throws(()=>validateParityEvidence({...good,immutable_slot:{...good.immutable_slot,development_root:good.immutable_slot.release_root}}),/immutable-slot/i);
|
|
36
|
+
assert.throws(()=>validateParityEvidence({...good,stage_restore:{status:'missing',manifest_sha256:good.candidate.manifest_sha256}}),/stage restore/i);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test('R39 parity captures R39 bridge, exact public 0.11.2 predecessor, stage reseed and successor restore',async()=>{
|
|
40
|
+
const parity=await text('scripts/release-parity-r39.mjs');
|
|
41
|
+
assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);
|
|
42
|
+
assert.match(parity,/058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b/);
|
|
43
|
+
assert.match(parity,/const stageRestore=await restoreFrozenStage/);
|
|
44
|
+
assert.match(parity,/publicR39Disarmed/);
|
|
45
|
+
assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test('R39 current final closure writer and independent verifier bind R39 domains and public 0.11.2 predecessor',async()=>{
|
|
49
|
+
const [writer,verifier]=await Promise.all([text('scripts/final-closure-r39.mjs'),text('scripts/final-closure-verify-r39.mjs')]);
|
|
50
|
+
assert.equal(typeof verifyFinalClosureObject,'function');
|
|
51
|
+
assert.match(writer,/DEADBYTE-R39-FINAL-CLOSURE-V1/);
|
|
52
|
+
assert.match(writer,/deadbyte\.r39-final-closure\.v1/);
|
|
53
|
+
assert.match(writer,/pointer\.version==='0\.11\.3'/);
|
|
54
|
+
assert.match(writer,/R39 FINAL MACHINE BASELINE/);
|
|
55
|
+
assert.match(writer,/deadbyte\.r39-parity\.v1/);
|
|
56
|
+
assert.match(writer,/deadbyte\.r39-windows-gate\.v1/);
|
|
57
|
+
assert.match(writer,/R39_PREDECESSOR_RELEASE_ID/);
|
|
58
|
+
assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
|
|
59
|
+
assert.match(verifier,/DEADBYTE-R39-FINAL-CLOSURE-V1/);
|
|
60
|
+
assert.match(verifier,/deadbyte\.r39-final-closure\.v1/);
|
|
61
|
+
assert.match(verifier,/envelope\.body\.version==='0\.11\.3'/);
|
|
62
|
+
assert.match(verifier,/R39 FINAL MACHINE BASELINE/);
|
|
63
|
+
assert.match(verifier,/deadbyte\.r39-parity\.v1/);
|
|
64
|
+
assert.match(verifier,/deadbyte\.r39-windows-gate\.v1/);
|
|
65
|
+
assert.match(verifier,/058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b/);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test('R39 bounded public parity suite covers current release identity and agent fabric',async()=>{
|
|
69
|
+
const script=await text('scripts/release-parity-tests-r39.ps1');
|
|
70
|
+
assert.match(script,/r39-finalization\.test\.mjs/);
|
|
71
|
+
assert.match(script,/release-version\.test\.mjs/);
|
|
72
|
+
assert.match(script,/r37-agent-fabric\.test\.mjs/);
|
|
73
|
+
assert.match(script,/remote-live-log-r37\.test\.mjs/);
|
|
74
|
+
});
|
|
@@ -30,16 +30,23 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
30
30
|
]},
|
|
31
31
|
LocalReadyUri:'http://127.0.0.1:8787/healthz',UrlRegex:'https://x',McpUrlFile:'C:/mcp-url.txt',McpUrlFileSha256:EXE,McpPathFile:'C:/token.txt',StartTimeoutSeconds:30,ProbeTimeoutSeconds:3};
|
|
32
32
|
const coding={schema:'deadbyte.coding-policy.v1',enabled:true,lease_file:'C:/old/coding.json',evidence_dir:'C:/old/evidence',
|
|
33
|
-
roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']}},commands:{tests:command()},max_read_bytes:524288,max_write_bytes:2097152};
|
|
33
|
+
roots:{core:{path:'C:/old/core',read:true,write:true,exec:true,deny_paths:['node_modules']}},commands:{tests:command(),powershell_script:command()},max_read_bytes:524288,max_write_bytes:2097152};
|
|
34
34
|
const autonomous={schema:'deadbyte.autonomous-policy.v1',enabled:true,lease_file:'C:/old/auto.json',evidence_dir:'C:/old/auto-evidence',coding_policy_sha256:'0'.repeat(64),root_ids:['core'],planner:{backend:'client_sampling',max_tokens:4096},
|
|
35
|
-
profiles:{
|
|
35
|
+
profiles:{
|
|
36
|
+
gate:{kind:'command',root_id:'core',command_id:'tests',script_path:'scripts/gate.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:120000,expect_exit_code:0,required_for_release:true,run_after_mutation:true,description:'gate'},
|
|
37
|
+
'windows-release':{kind:'command',root_id:'core',command_id:'powershell_script',script_path:'scripts/gate-windows-old.ps1',script_sha256:'0'.repeat(64),args:[],cwd:'.',timeout_ms:300000,expect_exit_code:0,required_for_release:true,run_after_mutation:false,description:'historical Windows release gate'}
|
|
38
|
+
},
|
|
36
39
|
limits:{max_iterations:12,max_mutations:24,max_wall_ms:1800000,max_context_bytes:1048576,max_diff_bytes:1048576,max_files_per_diff:8}};
|
|
37
40
|
const host={schema:'deadbyte.host-policy.v1',enabled:true,arm_file:'C:/old/host.json',roots:{core:{path:'C:/old/core',read:true,write:true,exec:true}},commands:{tests:command()},max_read_bytes:262144,max_write_bytes:1048576};
|
|
38
41
|
const processPolicy={schema:'deadbyte.process-policy.v1',enabled:true,grant_file:'C:/old/process-grant.json',state_dir:'C:/old/process-state',
|
|
39
42
|
native_host:{path:'C:/old/deadbyte-process-host.exe',sha256:'0'.repeat(64)},
|
|
40
43
|
roots:{core:{path:'C:/old/core',deny_paths:['node_modules']}},
|
|
41
44
|
profiles:{probe:{executable:'C:/Windows/System32/ping.exe',executable_sha256:EXE,root_ids:['core'],prefix_args:['127.0.0.1','-n','2'],max_args:0,max_arg_bytes:256,max_sessions:1,max_input_bytes:4096,max_retained_output_bytes:65536,env_allow:['PATH','TEMP','TMP'],input_actions:{}}}};
|
|
42
|
-
const development=path.join(base,'development'); await mkdir(development,{recursive:true}); await mkdir(path.join(development,'scripts'),{recursive:true});
|
|
45
|
+
const development=path.join(base,'development'); await mkdir(development,{recursive:true}); await mkdir(path.join(development,'scripts'),{recursive:true});
|
|
46
|
+
await writeFile(path.join(development,'scripts','gate.ps1'),'Write-Output gate\n');
|
|
47
|
+
await writeFile(path.join(development,'scripts','gate-windows-old.ps1'),'Write-Output old-gate\n');
|
|
48
|
+
await writeFile(path.join(development,'scripts','gate-windows-current.ps1'),'Write-Output current-gate\n');
|
|
49
|
+
await writeFile(path.join(development,'package.json'),JSON.stringify({scripts:{'gate:windows':'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-current.ps1'}}));
|
|
43
50
|
const result=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
44
51
|
const verified=await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
|
|
45
52
|
assert.equal(verified.files,6);
|
|
@@ -62,6 +69,9 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
62
69
|
assert.equal(generatedAuto.coding_policy_sha256,sha(codingBytes));
|
|
63
70
|
assert.equal(generatedAuto.lease_file,path.join(path.resolve(state),'runtime','autonomous-grant.json'));
|
|
64
71
|
assert.equal(generatedAuto.profiles.gate.script_sha256,sha(Buffer.from('Write-Output gate\n')));
|
|
72
|
+
assert.equal(generatedAuto.profiles['windows-release'].script_path,'scripts/gate-windows-current.ps1');
|
|
73
|
+
assert.equal(generatedAuto.profiles['windows-release'].script_sha256,sha(Buffer.from('Write-Output current-gate\n')));
|
|
74
|
+
assert.equal(generatedAuto.profiles['windows-release'].description,'Full Windows target release gate; runs only when finish is requested.');
|
|
65
75
|
const generatedHost=JSON.parse(await readFile(result.host_policy_path,'utf8'));
|
|
66
76
|
assert.equal(generatedHost.roots.core.path,path.resolve(development));
|
|
67
77
|
assert.notEqual(generatedHost.roots.core.path,path.resolve(release));
|
|
@@ -5,40 +5,62 @@ import { createHash } from 'node:crypto';
|
|
|
5
5
|
|
|
6
6
|
const root=new URL('../',import.meta.url);
|
|
7
7
|
const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
8
|
-
const
|
|
9
|
-
const
|
|
8
|
+
const R39_PREDECESSOR_RELEASE_ID='v0.11.2-058605dfccaa3035';
|
|
9
|
+
const R39_PREDECESSOR_MANIFEST='058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b';
|
|
10
10
|
|
|
11
|
-
test('
|
|
11
|
+
test('R39 hotfix authority agrees on V0.11.3 and preserves exact public 0.11.2 predecessor',async()=>{
|
|
12
12
|
const pkg=JSON.parse(await text('package.json'));
|
|
13
13
|
const [version,controller,gate,readme,architecture,controllerReadme,deferred,parity,closure,closureVerify,windowsGate,semanticConfig]=await Promise.all([
|
|
14
|
-
text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows.ps1'),
|
|
14
|
+
text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows-r39.ps1'),
|
|
15
15
|
text('README.txt'),text('docs/ARCHITECTURE.md'),text('controller/README.TXT'),
|
|
16
|
-
text('scripts/deferred-slot-operation.mjs'),text('scripts/release-parity.mjs'),text('scripts/final-closure.mjs'),
|
|
17
|
-
text('scripts/final-closure-verify.mjs'),text('scripts/windows-gate-evidence.mjs'),
|
|
16
|
+
text('scripts/deferred-slot-operation-r39.mjs'),text('scripts/release-parity-r39.mjs'),text('scripts/final-closure-r39.mjs'),
|
|
17
|
+
text('scripts/final-closure-verify-r39.mjs'),text('scripts/windows-gate-evidence-r39.mjs'),
|
|
18
18
|
text('controller/deadbyte-semantic-lsp-config.json')
|
|
19
19
|
]);
|
|
20
|
-
assert.equal(pkg.version,'0.11.
|
|
21
|
-
assert.
|
|
22
|
-
assert.
|
|
23
|
-
assert.
|
|
24
|
-
assert.
|
|
25
|
-
assert.
|
|
26
|
-
assert.match(
|
|
27
|
-
assert.match(
|
|
28
|
-
assert.match(
|
|
29
|
-
assert.match(
|
|
30
|
-
assert.match(
|
|
31
|
-
assert.match(
|
|
32
|
-
assert.match(
|
|
33
|
-
assert.match(
|
|
20
|
+
assert.equal(pkg.version,'0.11.3');
|
|
21
|
+
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r39.ps1');
|
|
22
|
+
assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r39.mjs');
|
|
23
|
+
assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r39.mjs');
|
|
24
|
+
assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r39.mjs');
|
|
25
|
+
assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r39.mjs');
|
|
26
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.11\.3'/);
|
|
27
|
+
assert.match(controller,/CONTROLLER V0\.11\.3 \/ R39/);
|
|
28
|
+
assert.match(gate,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);
|
|
29
|
+
assert.match(readme,/^DEADBYTE MCP V0\.11\.3 \/ R39 HOTFIX BASELINE$/m);
|
|
30
|
+
assert.match(architecture,/^# DEADBYTE MCP V0\.11\.3 \/ R39 ARCHITECTURE$/m);
|
|
31
|
+
assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.3 \/ R39 CONTROLLER$/m);
|
|
32
|
+
assert.match(deferred,/--expected-version','0\.11\.3'/);
|
|
33
|
+
assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);
|
|
34
|
+
assert.match(parity,new RegExp(R39_PREDECESSOR_MANIFEST));
|
|
35
|
+
assert.match(parity,/version==='0\.11\.3'|version:'0\.11\.3'/);
|
|
36
|
+
assert.match(closure,/version:'0\.11\.3'/);
|
|
37
|
+
assert.match(closureVerify,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);
|
|
38
|
+
assert.match(windowsGate,/version:'0\.11\.3'/);
|
|
34
39
|
assert.equal(createHash('sha256').update(Buffer.from(semanticConfig,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
|
|
40
|
+
assert.equal(R39_PREDECESSOR_RELEASE_ID,'v0.11.2-058605dfccaa3035');
|
|
35
41
|
});
|
|
36
42
|
|
|
37
|
-
test('
|
|
38
|
-
const [
|
|
39
|
-
assert.match(parity,/R36_EXPECTED_TOOLS\.length !== 76/);
|
|
40
|
-
assert.match(parity,/R36_COMPACT_TOOL_LIMIT=42/);
|
|
43
|
+
test('R39 hotfix keeps ONLINE reuse and fixes PowerShell $Host recovery collision',async()=>{
|
|
44
|
+
const [cli,controller]=await Promise.all([text('src/deadbyte-cli.mjs'),text('controller/deadbyte-controller.ps1')]);
|
|
41
45
|
assert.match(cli,/controllerRuntimeReady/);
|
|
42
46
|
assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
43
|
-
assert.
|
|
47
|
+
assert.match(cli,/invokeController\(ctx,'start',\{discardOutput:true,timeoutMs:REMOTE_START_TIMEOUT_MS\}\)/);
|
|
48
|
+
assert.match(cli,/remote controller start returned without a verified ONLINE runtime/);
|
|
49
|
+
assert.match(cli,/discardOutput\?\['ignore','ignore','ignore'\]/);
|
|
50
|
+
const start=controller.indexOf('function Recover-AutonomousSupervisor');
|
|
51
|
+
const end=controller.indexOf('function Show-State',start);
|
|
52
|
+
assert.ok(start>=0&&end>start,'supervisor recovery block missing');
|
|
53
|
+
const block=controller.slice(start,end);
|
|
54
|
+
assert.doesNotMatch(block,/\$host\s*=/i);
|
|
55
|
+
assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{
|
|
59
|
+
const [parity,gate,closure]=await Promise.all([
|
|
60
|
+
text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')
|
|
61
|
+
]);
|
|
62
|
+
assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
|
|
63
|
+
assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);
|
|
64
|
+
assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
|
|
65
|
+
assert.match(closure,/version:'0\.11\.1'/);
|
|
44
66
|
});
|
|
@@ -7,7 +7,7 @@ test('R37 live timeline renders sanitized tool-call detail and correlates termin
|
|
|
7
7
|
const tracker=createLiveTimelineTracker({clock:()=>now});
|
|
8
8
|
const run=tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'abcdef1234567890',
|
|
9
9
|
args:{root_id:'projects',path:'src/a.mjs',content:'SECRET',token:'SECRET'}});
|
|
10
|
-
assert.match(run,/^1970-01-
|
|
10
|
+
assert.match(run,/^1970-01-01T07:00:01\.000\+07:00 \| coding_file_read\s+\| Arguments: \{/);
|
|
11
11
|
assert.match(run,/\"path\":\"src\/a\.mjs\"/);
|
|
12
12
|
assert.match(run,/\"reason\":\"payload\"/);
|
|
13
13
|
assert.match(run,/\"reason\":\"secret\"/);
|
|
@@ -16,11 +16,15 @@ async function fixture({failCommand='',statusOnline=false}={}){
|
|
|
16
16
|
const state=path.join(dir,'state');
|
|
17
17
|
const bin=path.join(state,'bin');
|
|
18
18
|
const trace=path.join(dir,'trace.txt');
|
|
19
|
+
const startedMarker=path.join(dir,'started.txt');
|
|
20
|
+
const spawnedStdout=path.join(dir,'spawned.stdout.log');
|
|
21
|
+
const spawnedStderr=path.join(dir,'spawned.stderr.log');
|
|
22
|
+
const spawnedPid=path.join(dir,'spawned.pid');
|
|
19
23
|
await mkdir(bin,{recursive:true});
|
|
20
24
|
const launcher=path.join(bin,'DEADBYTE-MCP.ps1');
|
|
21
|
-
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) { Write-Error \"forced $Command failure\"; exit 9 }\nswitch ($Command) {\n 'start' { Write-Host 'DEADBYTE MCP = ONLINE' }\n 'status' { if ($env:DEADBYTE_REMOTE_TEST_STATUS_ONLINE -eq '1') { 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' { Write-Host 'DEADBYTE MCP = PARKED' }\n default { Write-Host \"$Command OK\" }\n}\nexit 0\n`;
|
|
25
|
+
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) { 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`;
|
|
22
26
|
await writeFile(launcher,ps1,'utf8');
|
|
23
|
-
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'}};
|
|
27
|
+
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};
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
async function traceCommands(file,{read=readFile,retryDelayMs=10,maxAttempts=20}={}){
|
|
@@ -90,15 +94,45 @@ winTest('bare remote reuses a fully verified ONLINE runtime without invoking blo
|
|
|
90
94
|
}
|
|
91
95
|
});
|
|
92
96
|
|
|
97
|
+
winTest('bare remote PARKED startup does not wait for a long-lived child holding inherited pipe handles',async()=>{
|
|
98
|
+
const fx=await fixture();
|
|
99
|
+
fx.env.DEADBYTE_REMOTE_TEST_SPAWN_CHILD='1';
|
|
100
|
+
let child=null;
|
|
101
|
+
try{
|
|
102
|
+
const startedAt=Date.now();
|
|
103
|
+
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
104
|
+
const output=await collect(child);
|
|
105
|
+
const ready=await waitFor(fx.trace,commands=>commands.includes('hoststatus'),{timeoutMs:8000});
|
|
106
|
+
const elapsed=Date.now()-startedAt;
|
|
107
|
+
assert.deepEqual(ready.slice(0,10),[
|
|
108
|
+
'status','start','status','armprocess','armcoding','armautonomous',
|
|
109
|
+
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
110
|
+
]);
|
|
111
|
+
assert.ok(elapsed<7000,`PARKED startup waited on inherited child pipe handles: ${elapsed}ms`);
|
|
112
|
+
assert.equal(child.exitCode,null,'remote session must remain foreground after PARKED startup');
|
|
113
|
+
assert.match(output.stdout,/\[BOOT\] Starting bridge\/runtime\.\.\./);
|
|
114
|
+
assert.match(output.stdout,/\[OK\] ONLINE/);
|
|
115
|
+
child.stdin.end();
|
|
116
|
+
const ended=await Promise.race([output.closed,sleep(6000).then(()=>({timeout:true}))]);
|
|
117
|
+
assert.equal(ended.timeout,undefined,'remote session did not exit after PARKED startup proof');
|
|
118
|
+
assert.equal(ended.code,0,output.stderr);
|
|
119
|
+
}finally{
|
|
120
|
+
if(child?.exitCode===null) child.kill('SIGKILL');
|
|
121
|
+
try{const pid=Number((await readFile(fx.spawnedPid,'utf8')).trim());if(Number.isInteger(pid)&&pid>0) process.kill(pid,'SIGKILL');}catch{}
|
|
122
|
+
await sleep(100);
|
|
123
|
+
await rm(fx.dir,{recursive:true,force:true});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
93
127
|
winTest('bare remote uses one unified live timeline, keeps authority semantics, then disarms and parks when the foreground session ends',async()=>{
|
|
94
128
|
const fx=await fixture();
|
|
95
129
|
let child=null;
|
|
96
130
|
try{
|
|
97
131
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
98
132
|
const output=await collect(child);
|
|
99
|
-
const ready=await waitFor(fx.trace,commands=>commands.slice(0,
|
|
100
|
-
assert.deepEqual(ready.slice(0,
|
|
101
|
-
'status','start','armprocess','armcoding','armautonomous',
|
|
133
|
+
const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
|
|
134
|
+
assert.deepEqual(ready.slice(0,10),[
|
|
135
|
+
'status','start','status','armprocess','armcoding','armautonomous',
|
|
102
136
|
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
103
137
|
]);
|
|
104
138
|
assert.equal(child.exitCode,null,'remote session must remain foreground after becoming ready');
|
|
@@ -136,9 +170,9 @@ winTest('bare remote uses one unified live timeline, keeps authority semantics,
|
|
|
136
170
|
].join('\n')+'\n','utf8');
|
|
137
171
|
const logDeadline=Date.now()+3000;
|
|
138
172
|
while(Date.now()<logDeadline&&!/✗ \[fedcba98\] ERR coding_file_read 1\.73s/.test(output.stdout)) await sleep(50);
|
|
139
|
-
assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}
|
|
173
|
+
assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+07:00 \| coding_tree\s+\| Arguments: .*\"path\":\"src\".*\"root_id\":\"projects\".*\[cursor r1:[0-9a-f]{24}:1\]$/m);
|
|
140
174
|
assert.match(output.stdout,/✓ \[abcdef12\] OK coding_tree 42ms \[cursor r1:[0-9a-f]{24}:2\]/);
|
|
141
|
-
assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}
|
|
175
|
+
assert.match(output.stdout,/^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}\.[0-9]{3}\+07:00 \| coding_file_read\s+\| Arguments: \{\"path\":\"src\/deadbyte-cli\.mjs\",\"root_id\":\"projects\"\} \[cursor r1:[0-9a-f]{24}:3\]$/m);
|
|
142
176
|
assert.match(output.stdout,/✗ \[fedcba98\] ERR coding_file_read 1\.73s \[cursor r1:[0-9a-f]{24}:4\]/);
|
|
143
177
|
assert.equal((output.stdout.match(/✓ \[abcdef12\] OK coding_tree 42ms/g)||[]).length,1,'duplicate terminal result must print once');
|
|
144
178
|
const resultJournal=JSON.parse(await readFile(path.join(fx.state,'runtime','remote-results',`${marker.result_session_id}.json`),'utf8'));
|
|
@@ -209,7 +243,7 @@ winTest('remote --resume replays sanitized tool-call and terminal result events
|
|
|
209
243
|
while(Date.now()<deadline&&(!/coding_file_read\s+\| Arguments: .*REPLAY cursor r1:[0-9a-f]{24}:3/.test(secondOutput.stdout)||
|
|
210
244
|
!/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/.test(secondOutput.stdout)||
|
|
211
245
|
!/\[LOG\] Unified live timeline/.test(secondOutput.stdout))) await sleep(50);
|
|
212
|
-
assert.match(secondOutput.stdout,/^2026-09-
|
|
246
|
+
assert.match(secondOutput.stdout,/^2026-09-18T23:30:01\.000\+07:00 \| coding_file_read\s+\| Arguments: .*\"path\":\"src\/deadbyte-cli\.mjs\".*REPLAY cursor r1:[0-9a-f]{24}:3$/m);
|
|
213
247
|
assert.match(secondOutput.stdout,/\[REPLAY\] \[OK\] coding_file_read \[cursor r1:[0-9a-f]{24}:4\]/);
|
|
214
248
|
assert.match(secondOutput.stdout,/♻️ \[SESSION\] Previous result stream replayed/);
|
|
215
249
|
assert.doesNotMatch(secondOutput.stdout,/DO_NOT_REPLAY_SECRET/);
|
|
@@ -249,9 +283,9 @@ winTest('detached guardian revokes authority, parks, and removes the session mar
|
|
|
249
283
|
try{
|
|
250
284
|
child=spawn(process.execPath,[cliPath,'remote'],{env:fx.env,stdio:['pipe','pipe','pipe'],windowsHide:true});
|
|
251
285
|
const output=await collect(child);
|
|
252
|
-
const ready=await waitFor(fx.trace,commands=>commands.slice(0,
|
|
253
|
-
assert.deepEqual(ready.slice(0,
|
|
254
|
-
'status','start','armprocess','armcoding','armautonomous',
|
|
286
|
+
const ready=await waitFor(fx.trace,commands=>commands.slice(0,10).join(',')==='status,start,status,armprocess,armcoding,armautonomous,processstatus,codingstatus,autonomousstatus,hoststatus');
|
|
287
|
+
assert.deepEqual(ready.slice(0,10),[
|
|
288
|
+
'status','start','status','armprocess','armcoding','armautonomous',
|
|
255
289
|
'processstatus','codingstatus','autonomousstatus','hoststatus'
|
|
256
290
|
]);
|
|
257
291
|
const markerPath=path.join(fx.state,'runtime','remote-session.json');
|
|
@@ -294,7 +328,7 @@ winTest('bare remote rolls back authority and parks if one plane fails to arm',a
|
|
|
294
328
|
assert.equal(ended.timeout,undefined,'failed startup did not terminate');
|
|
295
329
|
assert.notEqual(ended.code,0);
|
|
296
330
|
const commands=await traceCommands(fx.trace);
|
|
297
|
-
assert.deepEqual(commands.slice(0,
|
|
331
|
+
assert.deepEqual(commands.slice(0,5),['status','start','status','armprocess','armcoding']);
|
|
298
332
|
assert.deepEqual(commands.slice(-5),['disarmautonomous','disarmcoding','disarmprocess','disarmhost','park']);
|
|
299
333
|
assert.doesNotMatch(output.stdout,/Live logs/i);
|
|
300
334
|
}finally{await rm(fx.dir,{recursive:true,force:true});}
|