deadbyte-mcp 0.11.2 β 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MANIFEST.SHA256 +101 -39
- package/README.txt +10 -9
- package/acceptance/r40/desktop-live-drift.mjs +106 -0
- package/acceptance/r40/desktop-live-ground.mjs +110 -0
- package/acceptance/r40/desktop-live-input.mjs +128 -0
- package/acceptance/r40/desktop-live-observe.mjs +100 -0
- package/acceptance/r40/desktop-live-uia.mjs +121 -0
- package/bin/deadbyte-desktop-input-r40.exe +0 -0
- package/bin/deadbyte-desktop-input-r40.obj +0 -0
- package/bin/deadbyte-desktop-observer-r40.exe +0 -0
- package/bin/deadbyte-desktop-observer-r40.obj +0 -0
- package/bin/deadbyte-desktop-uia-r40.exe +0 -0
- package/bin/deadbyte-desktop-uia-r40.obj +0 -0
- package/controller/README.TXT +7 -5
- package/controller/deadbyte-controller.config.psd1.example +3 -0
- package/controller/deadbyte-controller.ps1 +149 -4
- package/controller/deadbyte-desktop-policy.json +41 -0
- package/docs/ARCHITECTURE.md +6 -1
- package/docs/superpowers/specs/2026-09-19-r40-desktop-computer-use-design.md +214 -0
- package/native/deadbyte-desktop-input.cpp +455 -0
- package/native/deadbyte-desktop-observer.cpp +253 -0
- package/native/deadbyte-desktop-uia.cpp +307 -0
- package/package.json +10 -8
- package/scripts/build-desktop-r40.ps1 +106 -0
- package/scripts/deferred-slot-operation-r39.mjs +124 -0
- package/scripts/deferred-slot-operation-r40.mjs +126 -0
- package/scripts/final-closure-r39.mjs +113 -0
- package/scripts/final-closure-r40.mjs +114 -0
- package/scripts/final-closure-verify-r39.mjs +208 -0
- package/scripts/final-closure-verify-r40.mjs +212 -0
- package/scripts/gate-windows-r39.ps1 +42 -0
- package/scripts/gate-windows-r40.ps1 +43 -0
- package/scripts/init-desktop-policy-r40.ps1 +79 -0
- package/scripts/r40-compact-ledger-probe.mjs +4 -0
- package/scripts/release-parity-r39.mjs +200 -0
- package/scripts/release-parity-r40.mjs +212 -0
- package/scripts/release-parity-tests-r39.ps1 +9 -0
- package/scripts/release-parity-tests-r40.ps1 +9 -0
- package/scripts/windows-gate-evidence-r39.mjs +52 -0
- package/scripts/windows-gate-evidence-r40.mjs +52 -0
- package/src/autonomous-context-engine.mjs +2 -1
- package/src/autonomous-planner-contracts.mjs +19 -1
- package/src/autonomous-planner.mjs +22 -0
- package/src/autonomous-runtime.mjs +144 -24
- package/src/capability-ledger.mjs +6 -1
- package/src/compact-gateway-mcp-tools.mjs +14 -2
- package/src/deadbyte-cli.mjs +79 -47
- package/src/desktop-contract.mjs +263 -0
- package/src/desktop-input-r40.mjs +148 -0
- package/src/desktop-mcp-tools-r40.mjs +126 -0
- package/src/desktop-memory-r40.mjs +272 -0
- package/src/desktop-observer-r40.mjs +231 -0
- package/src/desktop-policy-r40.mjs +110 -0
- package/src/desktop-runtime-r40.mjs +318 -0
- package/src/desktop-uia-r40.mjs +123 -0
- package/src/mcp-server.mjs +74 -19
- package/src/r40-compact-disarmed-probe.mjs +71 -0
- package/src/r40-full-surface-probe.mjs +34 -0
- package/src/release-generation.mjs +38 -5
- package/src/remote-console.mjs +41 -0
- package/src/remote-live-log.mjs +215 -45
- package/src/remote-mcp-desktop-r40-smoke-client.mjs +70 -0
- package/src/remote-mcp-r40-parity-client.mjs +200 -0
- package/src/remote-mcp-smoke-client.mjs +20 -6
- package/src/remote-result-journal.mjs +10 -2
- package/src/runtime-update.mjs +55 -17
- package/src/tool-audit.mjs +29 -2
- package/src/version.mjs +1 -1
- package/test/autonomous-capability-r36.test.mjs +43 -1
- package/test/autonomous-desktop-r40.test.mjs +188 -0
- package/test/capability-ledger-r36.test.mjs +1 -0
- package/test/cli-entrypoint.test.mjs +1 -1
- package/test/compact-catalog-r36.test.mjs +2 -2
- package/test/compact-gateway-r36.test.mjs +56 -4
- package/test/compact-max-catalog-r40.test.mjs +95 -0
- package/test/controller-desktop-r40.test.mjs +85 -0
- package/test/core.test.mjs +1 -1
- package/test/desktop-adversarial-r40.test.mjs +62 -0
- package/test/desktop-contract-r40.test.mjs +200 -0
- package/test/desktop-input-r40.test.mjs +63 -0
- package/test/desktop-mcp-tools-r40.test.mjs +61 -0
- package/test/desktop-memory-r40.test.mjs +141 -0
- package/test/desktop-observer-r40.test.mjs +119 -0
- package/test/desktop-policy-r40.test.mjs +111 -0
- package/test/desktop-runtime-r40.test.mjs +278 -0
- package/test/desktop-uia-r40.test.mjs +42 -0
- package/test/full-max-catalog-r40.test.mjs +91 -0
- package/test/helpers/autonomous-r34-fixture.mjs +3 -3
- 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 +7 -6
- package/test/r39-finalization.test.mjs +74 -0
- package/test/r40-finalization.test.mjs +118 -0
- package/test/release-generation.test.mjs +41 -9
- package/test/release-version.test.mjs +19 -58
- package/test/remote-console-r40.test.mjs +38 -0
- package/test/remote-live-log-r37.test.mjs +89 -32
- package/test/remote-r24-catalog.test.mjs +12 -3
- package/test/remote-result-journal.test.mjs +15 -0
- package/test/remote-session-cli.test.mjs +112 -55
- package/test/runtime-self-update.test.mjs +44 -0
|
@@ -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
|
+
});
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { validateParityEvidence,R40_PREDECESSOR_RELEASE_ID,R40_PREDECESSOR_MANIFEST } from '../scripts/release-parity-r40.mjs';
|
|
5
|
+
import { verifyFinalClosureObject } from '../scripts/final-closure-verify-r40.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.r40-parity.v1',status:'passed',execution_provider:'deadbyte_mcp',rdc_operation_count:0,
|
|
14
|
+
candidate:{release_id:'v0.12.0-'+manifest.slice(0,16),version:'0.12.0',manifest_sha256:manifest},
|
|
15
|
+
immutable_slot:{protected:true,release_root:'C:/immutable/r40',development_root:'D:/Projects/deadbyte-mcp-r36-dev'},
|
|
16
|
+
local_full:{status:'passed',tool_count:80,strict_output_schemas:true},
|
|
17
|
+
public_compact:{status:'passed',tool_count:42,capability_closure:true,gateway_count:6,desktop_armed:false,
|
|
18
|
+
desktop_observation_receipt_verified:true,desktop_grounding_receipt_verified:true},
|
|
19
|
+
autonomous:{status:'passed',signed_release_verified:true,observed_failure_before_replan:true},
|
|
20
|
+
desktop_guarded:{status:'passed',native_injected:true,replay_performed:false,predispatch_retry_count:0,observation_receipts_verified:1,action_receipts_verified:3},
|
|
21
|
+
before_rollback_disarmed:{status:'passed',capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
22
|
+
rollback:{state:'completed'},stage_restore:{status:'restored',manifest_sha256:manifest},restore:{state:'completed'},
|
|
23
|
+
predecessor:{release_id:R40_PREDECESSOR_RELEASE_ID,version:'0.11.3',manifest_sha256:R40_PREDECESSOR_MANIFEST},
|
|
24
|
+
predecessor_disarmed:{status:'passed',tool_count:41,capability_closure:true},
|
|
25
|
+
successor:{release_id:'v0.12.0-'+manifest.slice(0,16),version:'0.12.0',manifest_sha256:manifest},
|
|
26
|
+
successor_disarmed:{status:'passed',tool_count:42,capability_closure:true,coding_armed:false,autonomous_armed:false,desktop_armed:false},
|
|
27
|
+
requirements:Object.fromEntries(['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy',
|
|
28
|
+
'interrupted_recovery','evidence_verification','compact_closure','full_surface','desktop_readonly','desktop_guarded_input'].map(key=>[key,true]))
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
test('R40 parity validator requires full-80 compact-42 six gateways Desktop proof exact 0.11.3 predecessor and immutable separation',()=>{
|
|
33
|
+
const good=parityFixture();
|
|
34
|
+
assert.equal(validateParityEvidence(good),true);
|
|
35
|
+
assert.throws(()=>validateParityEvidence({...good,local_full:{...good.local_full,tool_count:79}}),/full 80/i);
|
|
36
|
+
assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,gateway_count:5}}),/compact/i);
|
|
37
|
+
assert.throws(()=>validateParityEvidence({...good,public_compact:{...good.public_compact,desktop_armed:true}}),/Desktop/i);
|
|
38
|
+
assert.throws(()=>validateParityEvidence({...good,desktop_guarded:{...good.desktop_guarded,replay_performed:true}}),/guarded Desktop/i);
|
|
39
|
+
assert.throws(()=>validateParityEvidence({...good,predecessor:{...good.predecessor,manifest_sha256:'b'.repeat(64)}}),/predecessor/i);
|
|
40
|
+
assert.throws(()=>validateParityEvidence({...good,immutable_slot:{...good.immutable_slot,development_root:good.immutable_slot.release_root}}),/immutable-slot/i);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
test('R40 parity binds exact sealed 0.11.3 predecessor and separate Desktop authority smoke',async()=>{
|
|
44
|
+
const parity=await text('scripts/release-parity-r40.mjs');
|
|
45
|
+
assert.equal(R40_PREDECESSOR_RELEASE_ID,'v0.11.3-ce761dd6e014d42e');
|
|
46
|
+
assert.equal(R40_PREDECESSOR_MANIFEST,'ce761dd6e014d42eddb635855038e0ce049c63c6e3af7e63c3005bbe198bcf7b');
|
|
47
|
+
assert.match(parity,/probeR40FullSurface/);
|
|
48
|
+
assert.match(parity,/runR40CompactParity/);
|
|
49
|
+
assert.match(parity,/probeR36CompactDisarmed/);
|
|
50
|
+
assert.match(parity,/armdesktop/);
|
|
51
|
+
assert.match(parity,/disarmdesktop/);
|
|
52
|
+
assert.match(parity,/runR40DesktopGuardedSmoke/);
|
|
53
|
+
assert.match(parity,/desktop_guarded_input/);
|
|
54
|
+
assert.match(parity,/scheduleDeferred\('activate',candidateManifest,\{bridgeRoot:successorBridge\.root,bridgeScriptSha256:successorBridge\.sha256\}\)/);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test('R40 deferred activation binds pinned Desktop policy and enables runtime without an arm command',async()=>{
|
|
58
|
+
const source=await text('scripts/deferred-slot-operation-r40.mjs');
|
|
59
|
+
assert.match(source,/--expected-version','0\.12\.0'/);
|
|
60
|
+
assert.match(source,/--desktop-policy'/);
|
|
61
|
+
assert.match(source,/--desktop-policy-sha256'/);
|
|
62
|
+
assert.match(source,/--enable-desktop'/);
|
|
63
|
+
assert.doesNotMatch(source,/armdesktop/);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test('R40 final closure writer and independent verifier bind R40 domains Desktop disarm and exact predecessor',async()=>{
|
|
67
|
+
const [writer,verifier]=await Promise.all([text('scripts/final-closure-r40.mjs'),text('scripts/final-closure-verify-r40.mjs')]);
|
|
68
|
+
assert.equal(typeof verifyFinalClosureObject,'function');
|
|
69
|
+
for(const source of [writer,verifier]){
|
|
70
|
+
assert.match(source,/DEADBYTE-R40-FINAL-CLOSURE-V1/);
|
|
71
|
+
assert.match(source,/deadbyte\.r40-final-closure\.v1/);
|
|
72
|
+
assert.match(source,/0\.12\.0/);
|
|
73
|
+
assert.match(source,/R40 FINAL MACHINE BASELINE/);
|
|
74
|
+
assert.match(source,/desktop-grant\.json/);
|
|
75
|
+
}
|
|
76
|
+
assert.match(writer,/probeR40FullSurface/);
|
|
77
|
+
assert.match(writer,/probeR40CompactDisarmed/);
|
|
78
|
+
assert.match(writer,/tool_count===80/);
|
|
79
|
+
assert.match(writer,/compact\.tool_count===42/);
|
|
80
|
+
assert.match(verifier,/R40_FULL_TOOL_COUNT=80/);
|
|
81
|
+
assert.match(verifier,/R40_COMPACT_TOOL_COUNT=42/);
|
|
82
|
+
assert.match(verifier,/v0\.11\.3-ce761dd6e014d42e/);
|
|
83
|
+
assert.match(verifier,/ce761dd6e014d42eddb635855038e0ce049c63c6e3af7e63c3005bbe198bcf7b/);
|
|
84
|
+
assert.match(verifier,/desktop_armed===false/);
|
|
85
|
+
assert.doesNotMatch(verifier,/from ['"]\.\.\/src\//);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
test('R40 Windows gate refreshes Desktop policy before manifest freeze and emits R40 evidence',async()=>{
|
|
89
|
+
const [gate,evidence]=await Promise.all([text('scripts/gate-windows-r40.ps1'),text('scripts/windows-gate-evidence-r40.mjs')]);
|
|
90
|
+
const desktop=gate.indexOf("'desktop-policy-refresh'");
|
|
91
|
+
const manifest=gate.indexOf("'release-manifest-write'");
|
|
92
|
+
assert.ok(desktop>=0&&manifest>desktop);
|
|
93
|
+
assert.match(gate,/desktop:policy:refresh/);
|
|
94
|
+
assert.match(gate,/DEADBYTE V0\.12\.0 \/ R40 WINDOWS BATCH GATE: PASS/);
|
|
95
|
+
assert.match(evidence,/deadbyte\.r40-windows-gate\.v1/);
|
|
96
|
+
assert.match(evidence,/version:'0\.12\.0'/);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('R40 bounded release parity suite includes Desktop updater generation and autonomous integration proofs',async()=>{
|
|
100
|
+
const script=await text('scripts/release-parity-tests-r40.ps1');
|
|
101
|
+
for(const required of ['r40-finalization.test.mjs','controller-desktop-r40.test.mjs','desktop-adversarial-r40.test.mjs',
|
|
102
|
+
'autonomous-desktop-r40.test.mjs','release-generation.test.mjs','runtime-self-update.test.mjs']) assert.match(script,new RegExp(required.replaceAll('.','\\.')));
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
test('R40 guarded Desktop smoke retries only bounded pre-dispatch foreground drift and never replays an unknown effect',async()=>{
|
|
107
|
+
const source=await text('src/remote-mcp-desktop-r40-smoke-client.mjs');
|
|
108
|
+
assert.match(source,/const maxPredispatchAttempts=3/);
|
|
109
|
+
assert.match(source,/desktop foreground window changed before action/);
|
|
110
|
+
assert.match(source,/if\(predispatchForegroundChanged\(actionResult\)\)/);
|
|
111
|
+
assert.match(source,/if\(attempt===maxPredispatchAttempts\)throw new Error\('Desktop guarded smoke foreground remained unstable before dispatch'\)/);
|
|
112
|
+
assert.match(source,/predispatchRetryCount\+=1/);
|
|
113
|
+
assert.match(source,/action=gateway\(actionResult,'desktop key_chord'\)/);
|
|
114
|
+
assert.match(source,/replay_performed:false/);
|
|
115
|
+
assert.match(source,/predispatch_retry_count:predispatchRetryCount/);
|
|
116
|
+
assert.doesNotMatch(source,/side_effect_state.*unknown.*continue/is);
|
|
117
|
+
assert.doesNotMatch(source,/desktop_action_started.*continue/is);
|
|
118
|
+
});
|
|
@@ -19,10 +19,16 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
19
19
|
await mkdir(path.join(release,'scripts'),{recursive:true}); await mkdir(path.join(release,'bin'),{recursive:true}); await mkdir(workspace,{recursive:true});
|
|
20
20
|
await writeFile(path.join(release,'scripts','gate.ps1'),'Write-Output gate\n');
|
|
21
21
|
await writeFile(path.join(release,'bin','deadbyte-process-host.exe'),'process-host-bytes\n');
|
|
22
|
+
const desktopObserver=Buffer.from('desktop-observer-bytes\n');
|
|
23
|
+
const desktopInput=Buffer.from('desktop-input-bytes\n');
|
|
24
|
+
const desktopUia=Buffer.from('desktop-uia-bytes\n');
|
|
25
|
+
await writeFile(path.join(release,'bin','deadbyte-desktop-observer-r40.exe'),desktopObserver);
|
|
26
|
+
await writeFile(path.join(release,'bin','deadbyte-desktop-input-r40.exe'),desktopInput);
|
|
27
|
+
await writeFile(path.join(release,'bin','deadbyte-desktop-uia-r40.exe'),desktopUia);
|
|
22
28
|
const semanticConfigPath=path.join(base,'semantic-lsp.json');
|
|
23
29
|
const semanticConfigBytes=Buffer.from(JSON.stringify({schema:'deadbyte.semantic-lsp-config.v1',servers:[]})+'\n','utf8');
|
|
24
30
|
await writeFile(semanticConfigPath,semanticConfigBytes);
|
|
25
|
-
const currentConfig={AgentRuntimeEnabled:true,ProcessRuntimeEnabled:true,CodingRuntimeEnabled:true,MachineFsRuntimeEnabled:true,ObservationRuntimeEnabled:true,AutonomousRuntimeEnabled:true,AutonomousSupervisorEnabled:true,SemanticLspConfigFile:semanticConfigPath,SemanticLspConfigSha256:sha(semanticConfigBytes),
|
|
31
|
+
const currentConfig={AgentRuntimeEnabled:true,ProcessRuntimeEnabled:true,CodingRuntimeEnabled:true,MachineFsRuntimeEnabled:true,ObservationRuntimeEnabled:true,DesktopRuntimeEnabled:true,AutonomousRuntimeEnabled:true,AutonomousSupervisorEnabled:true,SemanticLspConfigFile:semanticConfigPath,SemanticLspConfigSha256:sha(semanticConfigBytes),
|
|
26
32
|
Supervisor:{FilePath:'C:/node.exe',FileSha256:EXE,Arguments:'src\\autonomous-supervisor-host.mjs',WorkingDirectory:'C:/release',ScriptPath:'C:/release/src/autonomous-supervisor-host.mjs',ScriptSha256:'2'.repeat(64)},
|
|
27
33
|
Bridge:{FilePath:'C:/node.exe',FileSha256:EXE,Arguments:'bridge.mjs',WorkingDirectory:'C:/bridge',ScriptPath:'C:/bridge/bridge.mjs',ScriptSha256:EXE},
|
|
28
34
|
Cloud:{FilePath:'C:/deadbyte-tunnel-host.exe',FileSha256:EXE,Arguments:'"C:/cloudflared.exe" "C:/secret/tunnel-token.txt" "C:/bridge"',WorkingDirectory:'C:/release',Transport:'deadbyte.named-tunnel.v2',Dependencies:[
|
|
@@ -42,20 +48,35 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
42
48
|
native_host:{path:'C:/old/deadbyte-process-host.exe',sha256:'0'.repeat(64)},
|
|
43
49
|
roots:{core:{path:'C:/old/core',deny_paths:['node_modules']}},
|
|
44
50
|
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:{}}}};
|
|
51
|
+
const desktopPolicy={schema:'deadbyte.desktop-policy.v1',enabled:true,grant_file:'C:/old/desktop-grant.json',evidence_dir:'C:/old/desktop-evidence',
|
|
52
|
+
allowed_input_desktops:['Default'],allowed_actions:['click_primary','key_chord'],
|
|
53
|
+
limits:{max_frame_age_ms:2000,max_frame_bytes:8388608,capture_timeout_ms:5000,input_timeout_ms:2000,ground_timeout_ms:5000,post_observe_timeout_ms:5000,max_preview_bytes:1048576,max_text_bytes:4096},
|
|
54
|
+
observer:{executable:'C:/old/observer.exe',sha256:sha(desktopObserver),backend:'gdi-bitblt-fallback'},
|
|
55
|
+
input:{executable:'C:/old/input.exe',sha256:sha(desktopInput)},
|
|
56
|
+
grounder:{executable:'C:/old/uia.exe',sha256:sha(desktopUia)}};
|
|
45
57
|
const development=path.join(base,'development'); await mkdir(development,{recursive:true}); await mkdir(path.join(development,'scripts'),{recursive:true});
|
|
46
58
|
await writeFile(path.join(development,'scripts','gate.ps1'),'Write-Output gate\n');
|
|
47
59
|
await writeFile(path.join(development,'scripts','gate-windows-old.ps1'),'Write-Output old-gate\n');
|
|
48
60
|
await writeFile(path.join(development,'scripts','gate-windows-current.ps1'),'Write-Output current-gate\n');
|
|
49
61
|
await writeFile(path.join(development,'package.json'),JSON.stringify({scripts:{'gate:windows':'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-current.ps1'}}));
|
|
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});
|
|
62
|
+
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,desktopPolicy});
|
|
51
63
|
const verified=await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
|
|
52
|
-
assert.equal(verified.files,
|
|
64
|
+
assert.equal(verified.files,7);
|
|
53
65
|
const generatedProcess=JSON.parse(await readFile(result.process_policy_path,'utf8'));
|
|
54
66
|
assert.equal(generatedProcess.grant_file,path.join(path.resolve(state),'runtime','process-grant.json'));
|
|
55
67
|
assert.equal(generatedProcess.state_dir,path.join(path.resolve(state),'evidence','process'));
|
|
56
68
|
assert.equal(generatedProcess.roots.core.path,path.resolve(development));
|
|
57
69
|
assert.equal(generatedProcess.native_host.path,path.join(path.resolve(release),'bin','deadbyte-process-host.exe'));
|
|
58
70
|
assert.equal(generatedProcess.native_host.sha256,sha(Buffer.from('process-host-bytes\n')));
|
|
71
|
+
const generatedDesktop=JSON.parse(await readFile(result.desktop_policy_path,'utf8'));
|
|
72
|
+
assert.equal(generatedDesktop.grant_file,path.join(path.resolve(state),'runtime','desktop-grant.json'));
|
|
73
|
+
assert.equal(generatedDesktop.evidence_dir,path.join(path.resolve(state),'runtime','desktop-evidence'));
|
|
74
|
+
assert.equal(generatedDesktop.observer.executable,path.join(path.resolve(release),'bin','deadbyte-desktop-observer-r40.exe'));
|
|
75
|
+
assert.equal(generatedDesktop.input.executable,path.join(path.resolve(release),'bin','deadbyte-desktop-input-r40.exe'));
|
|
76
|
+
assert.equal(generatedDesktop.grounder.executable,path.join(path.resolve(release),'bin','deadbyte-desktop-uia-r40.exe'));
|
|
77
|
+
assert.equal(generatedDesktop.observer.sha256,sha(desktopObserver));
|
|
78
|
+
assert.equal(generatedDesktop.input.sha256,sha(desktopInput));
|
|
79
|
+
assert.equal(generatedDesktop.grounder.sha256,sha(desktopUia));
|
|
59
80
|
const generatedCoding=JSON.parse(await readFile(result.coding_policy_path,'utf8'));
|
|
60
81
|
assert.equal(generatedCoding.roots.core.path,path.resolve(development));
|
|
61
82
|
assert.notEqual(generatedCoding.roots.core.path,path.resolve(release));
|
|
@@ -89,6 +110,8 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
89
110
|
assert.match(config,/CodingRuntimeEnabled = \$true/);
|
|
90
111
|
assert.match(config,/MachineFsRuntimeEnabled = \$true/);
|
|
91
112
|
assert.match(config,/ObservationRuntimeEnabled = \$true/);
|
|
113
|
+
assert.match(config,/DesktopRuntimeEnabled = \$true/);
|
|
114
|
+
assert.match(config,/DesktopPolicyFile = '/);
|
|
92
115
|
assert.match(config,/CodingPolicyFile = '/);
|
|
93
116
|
assert.match(config,/AutonomousPolicyFile = '/);
|
|
94
117
|
assert.match(config,/AutonomousSupervisorEnabled = \$true/);
|
|
@@ -105,36 +128,44 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
105
128
|
assert.match(path.basename(result.generation_root),/^v0\.8\.3-aaaaaaaaaaaaaaaa-g[0-9a-f]{16}$/);
|
|
106
129
|
const changedConfig=structuredClone(currentConfig);
|
|
107
130
|
changedConfig.Bridge.Arguments='bridge-v2.mjs';
|
|
108
|
-
const second=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:changedConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
131
|
+
const second=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:changedConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
109
132
|
assert.notEqual(second.generation_root,result.generation_root);
|
|
110
133
|
assert.notEqual(second.generation_seed_sha256,result.generation_seed_sha256);
|
|
111
134
|
const endpointChanged=structuredClone(currentConfig);
|
|
112
135
|
endpointChanged.McpUrlFileSha256='2'.repeat(64);
|
|
113
|
-
const third=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:endpointChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
136
|
+
const third=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:endpointChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
114
137
|
assert.notEqual(third.generation_root,result.generation_root);
|
|
115
138
|
assert.notEqual(third.generation_seed_sha256,result.generation_seed_sha256);
|
|
116
139
|
const machineDisabled=structuredClone(currentConfig);
|
|
117
140
|
machineDisabled.MachineRuntimeEnabled=false;
|
|
118
|
-
const fourth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
141
|
+
const fourth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
119
142
|
assert.notEqual(fourth.generation_root,result.generation_root);
|
|
120
143
|
assert.notEqual(fourth.generation_seed_sha256,result.generation_seed_sha256);
|
|
121
144
|
const machineFsDisabled=structuredClone(currentConfig);
|
|
122
145
|
machineFsDisabled.MachineFsRuntimeEnabled=false;
|
|
123
|
-
const fifth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineFsDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
146
|
+
const fifth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:machineFsDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
124
147
|
assert.notEqual(fifth.generation_root,result.generation_root);
|
|
125
148
|
assert.notEqual(fifth.generation_seed_sha256,result.generation_seed_sha256);
|
|
126
149
|
const observationDisabled=structuredClone(currentConfig);
|
|
127
150
|
observationDisabled.ObservationRuntimeEnabled=false;
|
|
128
|
-
const sixth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:observationDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
151
|
+
const sixth=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:observationDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
129
152
|
assert.notEqual(sixth.generation_root,result.generation_root);
|
|
130
153
|
assert.notEqual(sixth.generation_seed_sha256,result.generation_seed_sha256);
|
|
154
|
+
const desktopDisabled=structuredClone(currentConfig);
|
|
155
|
+
desktopDisabled.DesktopRuntimeEnabled=false;
|
|
156
|
+
const desktopVariant=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:desktopDisabled,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
157
|
+
assert.notEqual(desktopVariant.generation_root,result.generation_root);
|
|
158
|
+
assert.notEqual(desktopVariant.generation_seed_sha256,result.generation_seed_sha256);
|
|
159
|
+
const desktopTampered=structuredClone(desktopPolicy);
|
|
160
|
+
desktopTampered.input.sha256='f'.repeat(64);
|
|
161
|
+
await assert.rejects(createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy:desktopTampered}),/desktop input helper SHA-256 mismatch/);
|
|
131
162
|
const semanticConfig2Path=path.join(base,'semantic-lsp-v2.json');
|
|
132
163
|
const semanticConfig2Bytes=Buffer.from(JSON.stringify({schema:'deadbyte.semantic-lsp-config.v1',servers:[{id:'changed'}]})+'\n','utf8');
|
|
133
164
|
await writeFile(semanticConfig2Path,semanticConfig2Bytes);
|
|
134
165
|
const semanticChanged=structuredClone(currentConfig);
|
|
135
166
|
semanticChanged.SemanticLspConfigFile=semanticConfig2Path;
|
|
136
167
|
semanticChanged.SemanticLspConfigSha256=sha(semanticConfig2Bytes);
|
|
137
|
-
const seventh=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:semanticChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy});
|
|
168
|
+
const seventh=await createGenerationBundle({stateRoot:state,releaseRoot:release,developmentRoot:development,workspaceRoot:workspace,releaseId:'v0.8.3-aaaaaaaaaaaaaaaa',currentConfig:semanticChanged,codingPolicy:coding,autonomousPolicy:autonomous,hostPolicy:host,processPolicy,desktopPolicy});
|
|
138
169
|
assert.notEqual(seventh.generation_root,result.generation_root);
|
|
139
170
|
assert.notEqual(seventh.generation_seed_sha256,result.generation_seed_sha256);
|
|
140
171
|
await verifyGenerationBundle(result.generation_root,result.generation_manifest_sha256);
|
|
@@ -143,5 +174,6 @@ test('R27 generation bundle rebinds authority and mutable state outside the rele
|
|
|
143
174
|
await verifyGenerationBundle(fourth.generation_root,fourth.generation_manifest_sha256);
|
|
144
175
|
await verifyGenerationBundle(fifth.generation_root,fifth.generation_manifest_sha256);
|
|
145
176
|
await verifyGenerationBundle(sixth.generation_root,sixth.generation_manifest_sha256);
|
|
177
|
+
await verifyGenerationBundle(desktopVariant.generation_root,desktopVariant.generation_manifest_sha256);
|
|
146
178
|
await verifyGenerationBundle(seventh.generation_root,seventh.generation_manifest_sha256);
|
|
147
179
|
});
|
|
@@ -2,62 +2,23 @@ import test from 'node:test';
|
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
3
|
import { readFile } from 'node:fs/promises';
|
|
4
4
|
import { createHash } from 'node:crypto';
|
|
5
|
-
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r38.ps1');
|
|
22
|
-
assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r38.mjs');
|
|
23
|
-
assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r38.mjs');
|
|
24
|
-
assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r38.mjs');
|
|
25
|
-
assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r38.mjs');
|
|
26
|
-
assert.match(version,/DEADBYTE_VERSION = '0\.11\.2'/);
|
|
27
|
-
assert.match(controller,/CONTROLLER V0\.11\.2 \/ R38/);
|
|
28
|
-
assert.match(gate,/DEADBYTE V0\.11\.2 \/ R38 WINDOWS BATCH GATE: PASS/);
|
|
29
|
-
assert.match(readme,/^DEADBYTE MCP V0\.11\.2 \/ R38 HOTFIX BASELINE$/m);
|
|
30
|
-
assert.match(architecture,/^# DEADBYTE MCP V0\.11\.2 \/ R38 ARCHITECTURE$/m);
|
|
31
|
-
assert.match(controllerReadme,/^DEADBYTE MCP V0\.11\.2 \/ R38 CONTROLLER$/m);
|
|
32
|
-
assert.match(deferred,/--expected-version','0\.11\.2'/);
|
|
33
|
-
assert.match(parity,/R38_PREDECESSOR_RELEASE_ID='v0\.11\.1-220fac89dd82cdcd'/);
|
|
34
|
-
assert.match(parity,new RegExp(R38_PREDECESSOR_MANIFEST));
|
|
35
|
-
assert.match(parity,/version==='0\.11\.2'|version:'0\.11\.2'/);
|
|
36
|
-
assert.match(closure,/version:'0\.11\.2'/);
|
|
37
|
-
assert.match(closureVerify,/DEADBYTE V0\.11\.2 \/ R38 WINDOWS BATCH GATE: PASS/);
|
|
38
|
-
assert.match(windowsGate,/version:'0\.11\.2'/);
|
|
39
|
-
assert.equal(createHash('sha256').update(Buffer.from(semanticConfig,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');
|
|
40
|
-
assert.equal(R38_PREDECESSOR_RELEASE_ID,'v0.11.1-220fac89dd82cdcd');
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('R38 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')]);
|
|
45
|
-
assert.match(cli,/controllerRuntimeReady/);
|
|
46
|
-
assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);
|
|
47
|
-
const start=controller.indexOf('function Recover-AutonomousSupervisor');
|
|
48
|
-
const end=controller.indexOf('function Show-State',start);
|
|
49
|
-
assert.ok(start>=0&&end>start,'supervisor recovery block missing');
|
|
50
|
-
const block=controller.slice(start,end);
|
|
51
|
-
assert.doesNotMatch(block,/\$host\s*=/i);
|
|
52
|
-
assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{
|
|
56
|
-
const [parity,gate,closure]=await Promise.all([
|
|
57
|
-
text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')
|
|
58
|
-
]);
|
|
59
|
-
assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);
|
|
60
|
-
assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);
|
|
61
|
-
assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);
|
|
62
|
-
assert.match(closure,/version:'0\.11\.1'/);
|
|
5
|
+
const root=new URL('../',import.meta.url);const text=rel=>readFile(new URL(rel,root),'utf8');
|
|
6
|
+
const R40_PREDECESSOR_RELEASE_ID='v0.11.3-ce761dd6e014d42e';
|
|
7
|
+
const R40_PREDECESSOR_MANIFEST='ce761dd6e014d42eddb635855038e0ce049c63c6e3af7e63c3005bbe198bcf7b';
|
|
8
|
+
test('R40 authority agrees on V0.12.0 and preserves exact sealed public 0.11.3 predecessor',async()=>{
|
|
9
|
+
const pkg=JSON.parse(await text('package.json'));
|
|
10
|
+
const [version,controller,gate,readme,architecture,controllerReadme,deferred,parity,closure,closureVerify,windowsGate,semanticConfig]=await Promise.all([
|
|
11
|
+
text('src/version.mjs'),text('controller/deadbyte-controller.ps1'),text('scripts/gate-windows-r40.ps1'),text('README.txt'),text('docs/ARCHITECTURE.md'),text('controller/README.TXT'),text('scripts/deferred-slot-operation-r40.mjs'),text('scripts/release-parity-r40.mjs'),text('scripts/final-closure-r40.mjs'),text('scripts/final-closure-verify-r40.mjs'),text('scripts/windows-gate-evidence-r40.mjs'),text('controller/deadbyte-semantic-lsp-config.json')]);
|
|
12
|
+
assert.equal(pkg.version,'0.12.0');assert.equal(pkg.scripts['gate:windows'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r40.ps1');
|
|
13
|
+
assert.equal(pkg.scripts['self-update:deferred'],'node scripts/deferred-slot-operation-r40.mjs');assert.equal(pkg.scripts['release:parity'],'node scripts/release-parity-r40.mjs');
|
|
14
|
+
assert.equal(pkg.scripts['release:final:write'],'node scripts/final-closure-r40.mjs');assert.equal(pkg.scripts['release:final:verify'],'node scripts/final-closure-verify-r40.mjs');
|
|
15
|
+
assert.equal(pkg.scripts['desktop:policy:refresh'],'powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-desktop-policy-r40.ps1');
|
|
16
|
+
assert.match(version,/DEADBYTE_VERSION = '0\.12\.0'/);assert.match(controller,/CONTROLLER V0\.12\.0 \/ R40/);assert.match(gate,/DEADBYTE V0\.12\.0 \/ R40 WINDOWS BATCH GATE: PASS/);
|
|
17
|
+
assert.match(readme,/^DEADBYTE MCP V0\.12\.0 \/ R40 DESKTOP COMPUTER-USE BASELINE$/m);assert.match(architecture,/^# DEADBYTE MCP V0\.12\.0 \/ R40 ARCHITECTURE$/m);assert.match(controllerReadme,/^DEADBYTE MCP V0\.12\.0 \/ R40 CONTROLLER$/m);
|
|
18
|
+
assert.match(deferred,/--expected-version','0\.12\.0'/);assert.match(deferred,/--enable-desktop/);assert.match(parity,/R40_PREDECESSOR_RELEASE_ID='v0\.11\.3-ce761dd6e014d42e'/);assert.match(parity,new RegExp(R40_PREDECESSOR_MANIFEST));
|
|
19
|
+
assert.match(parity,/version==='0\.12\.0'|version:'0\.12\.0'/);assert.match(closure,/version:'0\.12\.0'/);assert.match(closureVerify,/DEADBYTE V0\.12\.0 \/ R40 WINDOWS BATCH GATE: PASS/);assert.match(windowsGate,/version:'0\.12\.0'/);
|
|
20
|
+
assert.equal(createHash('sha256').update(Buffer.from(semanticConfig,'utf8')).digest('hex'),'d274b099a298c1033fea8f1e8849751693bbc0448778d619400acb82d4f53a3b');assert.equal(R40_PREDECESSOR_RELEASE_ID,'v0.11.3-ce761dd6e014d42e');
|
|
63
21
|
});
|
|
22
|
+
test('R40 keeps ONLINE reuse and PowerShell Host collision fix while Desktop stays explicit',async()=>{const [cli,controller]=await Promise.all([text('src/deadbyte-cli.mjs'),text('controller/deadbyte-controller.ps1')]);assert.match(cli,/controllerRuntimeReady/);assert.match(cli,/Runtime already ONLINE; reusing verified bridge\/cloud\/supervisor/);const start=controller.indexOf('function Recover-AutonomousSupervisor'),end=controller.indexOf('function Show-State',start);assert.ok(start>=0&&end>start);const block=controller.slice(start,end);assert.doesNotMatch(block,/\$host\s*=/i);assert.match(block,/\$hostStatus\s*=\s*Get-HostArmStatus/);assert.match(controller,/armdesktop/);assert.match(controller,/disarmdesktop/);});
|
|
23
|
+
test('sealed R39 tooling remains historical 0.11.3 authority with exact 0.11.2 predecessor',async()=>{const [parity,gate,closure]=await Promise.all([text('scripts/release-parity-r39.mjs'),text('scripts/gate-windows-r39.ps1'),text('scripts/final-closure-r39.mjs')]);assert.match(parity,/R39_PREDECESSOR_RELEASE_ID='v0\.11\.2-058605dfccaa3035'/);assert.match(parity,/version==='0\.11\.3'|version:'0\.11\.3'/);assert.match(gate,/DEADBYTE V0\.11\.3 \/ R39 WINDOWS BATCH GATE: PASS/);assert.match(closure,/version:'0\.11\.3'/);});
|
|
24
|
+
test('sealed R37 tooling remains historical 0.11.1 authority',async()=>{const [parity,gate,closure]=await Promise.all([text('scripts/release-parity.mjs'),text('scripts/gate-windows.ps1'),text('scripts/final-closure.mjs')]);assert.match(parity,/R37_PREDECESSOR_RELEASE_ID='v0\.11\.0-08c2a0008b1f84c9'/);assert.match(parity,/version==='0\.11\.1'|version:'0\.11\.1'/);assert.match(gate,/DEADBYTE V0\.11\.1 \/ R37 WINDOWS BATCH GATE: PASS/);assert.match(closure,/version:'0\.11\.1'/);});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { prepareRemoteConsole, remoteDisplayText } from '../src/remote-console.mjs';
|
|
4
|
+
|
|
5
|
+
test('R40 remote console keeps Unicode off Windows and forces deterministic ASCII when requested',()=>{
|
|
6
|
+
assert.equal(prepareRemoteConsole({platform:'linux',isTTY:false,env:{},spawnSyncFn:()=>{throw new Error('must not spawn');}}).mode,'unicode');
|
|
7
|
+
const forced=prepareRemoteConsole({platform:'win32',isTTY:true,env:{DEADBYTE_REMOTE_ASCII:'1'},spawnSyncFn:()=>{throw new Error('must not spawn');}});
|
|
8
|
+
assert.deepEqual(forced,{mode:'ascii',code_page:null,reason:'forced_ascii'});
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
test('R40 Windows pipe uses ASCII fallback instead of emitting mojibake',()=>{
|
|
12
|
+
let spawned=false;
|
|
13
|
+
const state=prepareRemoteConsole({platform:'win32',isTTY:false,env:{SystemRoot:'C:\\Windows'},spawnSyncFn:()=>{spawned=true;return {status:0};}});
|
|
14
|
+
assert.deepEqual(state,{mode:'ascii',code_page:null,reason:'stdout_not_tty'});
|
|
15
|
+
assert.equal(spawned,false);
|
|
16
|
+
const rendered=remoteDisplayText('π [DEVICE] ΰΉΰΈΰΈ’ π','ascii');
|
|
17
|
+
assert.doesNotMatch(rendered,/[^\x20-\x7E]/);
|
|
18
|
+
assert.match(rendered,/\\u\{/);
|
|
19
|
+
assert.equal(rendered.includes('\uFFFD'),false);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('R40 Windows TTY switches shared console code page to 65001 before enabling Unicode',()=>{
|
|
23
|
+
let call=null;
|
|
24
|
+
const state=prepareRemoteConsole({platform:'win32',isTTY:true,env:{SystemRoot:'C:\\Windows'},spawnSyncFn:(exe,args,options)=>{call={exe,args,options};return {status:0};}});
|
|
25
|
+
assert.equal(state.mode,'unicode');
|
|
26
|
+
assert.equal(state.code_page,65001);
|
|
27
|
+
assert.equal(call.exe,'C:\\Windows\\System32\\chcp.com');
|
|
28
|
+
assert.deepEqual(call.args,['65001']);
|
|
29
|
+
assert.equal(call.options.shell,false);
|
|
30
|
+
assert.equal(call.options.stdio,'ignore');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('R40 Windows TTY falls back to ASCII when code-page setup fails',()=>{
|
|
34
|
+
const failed=prepareRemoteConsole({platform:'win32',isTTY:true,env:{SystemRoot:'C:\\Windows'},spawnSyncFn:()=>({status:1})});
|
|
35
|
+
assert.deepEqual(failed,{mode:'ascii',code_page:null,reason:'codepage_65001_unavailable'});
|
|
36
|
+
const thrown=prepareRemoteConsole({platform:'win32',isTTY:true,env:{SystemRoot:'C:\\Windows'},spawnSyncFn:()=>{throw new Error('blocked');}});
|
|
37
|
+
assert.deepEqual(thrown,{mode:'ascii',code_page:null,reason:'codepage_probe_threw'});
|
|
38
|
+
});
|
|
@@ -1,50 +1,107 @@
|
|
|
1
1
|
import test from 'node:test';
|
|
2
2
|
import assert from 'node:assert/strict';
|
|
3
|
-
import { createLiveTimelineTracker } from '../src/remote-live-log.mjs';
|
|
3
|
+
import { createLiveTimelineTracker, formatRemoteLifecycle, formatRuntimeDiagnosticLine, summarizeLiveToolArgs, truncateUtf8 } from '../src/remote-live-log.mjs';
|
|
4
4
|
|
|
5
|
-
test('
|
|
5
|
+
test('R40 human live timeline suppresses noisy read request and emits one categorized terminal line',()=>{
|
|
6
6
|
let now=1000;
|
|
7
7
|
const tracker=createLiveTimelineTracker({clock:()=>now});
|
|
8
|
-
const
|
|
9
|
-
args:{root_id:'projects',path:'src/a.mjs',content:'SECRET',token:'SECRET'}});
|
|
10
|
-
assert.
|
|
11
|
-
assert.match(run,/\"path\":\"src\/a\.mjs\"/);
|
|
12
|
-
assert.match(run,/\"reason\":\"payload\"/);
|
|
13
|
-
assert.match(run,/\"reason\":\"secret\"/);
|
|
8
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'abcdef1234567890',
|
|
9
|
+
ts:'1970-01-01T00:00:01.000Z',args:{root_id:'projects',path:'src/a.mjs',content:'SECRET',token:'SECRET'}},{sequence:10});
|
|
10
|
+
assert.equal(start,null);
|
|
14
11
|
now=1250;
|
|
15
12
|
const done=tracker.observe({event_type:'tool.result',tool:'coding_file_read',request_id:'abcdef1234567890',
|
|
16
|
-
outcome:{is_error:false,duration_ms:250}});
|
|
17
|
-
assert.
|
|
13
|
+
ts:'1970-01-01T00:00:01.250Z',outcome:{is_error:false,duration_ms:250}},{sequence:11});
|
|
14
|
+
assert.match(done,/^π 07:00:01\.250 #11 \[abcdef12\] coding_file_read projects:src\/a\.mjs 250ms β$/);
|
|
18
15
|
assert.deepEqual(tracker.pending(),[]);
|
|
19
|
-
assert.doesNotMatch(
|
|
16
|
+
assert.doesNotMatch(String(done),/SECRET|Arguments:/);
|
|
20
17
|
});
|
|
21
18
|
|
|
22
|
-
test('
|
|
23
|
-
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
19
|
+
test('R40 long or mutating call gets start line and terminal error carries sanitized reason',()=>{
|
|
20
|
+
let now=1000;
|
|
21
|
+
const tracker=createLiveTimelineTracker({clock:()=>now});
|
|
22
|
+
const start=tracker.observe({event_type:'tool.request',tool:'coding_command_run',request_id:'request-23456789',
|
|
23
|
+
ts:'1970-01-01T00:00:01.000Z',args:{root_id:'core',command_id:'node_script',script_path:'scripts/check.mjs'}},{sequence:20});
|
|
24
|
+
assert.match(start,/^π 07:00:01\.000 #20 \[request-\] coding_command_run core node_script scripts\/check\.mjs β¦$/);
|
|
25
|
+
now=1900;
|
|
26
|
+
const done=tracker.observe({event_type:'tool.result',tool:'coding_command_run',request_id:'request-23456789',
|
|
27
|
+
ts:'1970-01-01T00:00:01.900Z',outcome:{is_error:true,duration_ms:900,reason:'script exited 1: ENOENT scripts/missing.mjs'}},{sequence:21});
|
|
28
|
+
assert.match(done,/π 07:00:01\.900 #21 \[request-\] coding_command_run .* 900ms β β script exited 1: ENOENT scripts\/missing\.mjs$/);
|
|
29
|
+
assert.equal(tracker.observe({event_type:'tool.result',tool:'coding_command_run',request_id:'request-23456789',
|
|
30
|
+
outcome:{is_error:true,duration_ms:900}},{sequence:22}),null);
|
|
27
31
|
});
|
|
28
32
|
|
|
29
|
-
test('
|
|
30
|
-
|
|
31
|
-
tracker
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
test('R40 heartbeat burst folds repeated status calls instead of printing every round-trip',()=>{
|
|
34
|
+
let now=1000;
|
|
35
|
+
const tracker=createLiveTimelineTracker({clock:()=>now,heartbeatBurstLimit:5,heartbeatWindowMs:3000});
|
|
36
|
+
for(let i=0;i<5;i++){
|
|
37
|
+
const id='ping-'+String(i).padStart(12,'0');
|
|
38
|
+
tracker.observe({event_type:'tool.request',tool:'machine_ping',request_id:id,args:{nonce:'mcpbench-'+i}},{sequence:30+i*2});
|
|
39
|
+
now+=10;
|
|
40
|
+
const line=tracker.observe({event_type:'tool.result',tool:'machine_ping',request_id:id,
|
|
41
|
+
outcome:{is_error:false,duration_ms:1+i}},{sequence:31+i*2});
|
|
42
|
+
if(i<4) assert.equal(line,null);
|
|
43
|
+
else assert.match(line,/^π‘ .*#39 machine_ping Γ5 avg 3ms β$/);
|
|
44
|
+
now+=10;
|
|
45
|
+
}
|
|
46
|
+
assert.match(tracker.summary(),/5 calls \| 0 errors .*folded 4 heartbeat lines.*machine_pingΓ5/);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('R40 transport IN/OUT echo is hidden by default and available only in verbose diagnostics',()=>{
|
|
50
|
+
const line='[TOOL IN ] 2026-09-19T00:00:00.000Z #7 coding_tree {"root_id":"core"}';
|
|
51
|
+
assert.equal(formatRuntimeDiagnosticLine('bridge.log',line),null);
|
|
52
|
+
assert.equal(formatRuntimeDiagnosticLine('bridge.log',line,{verbose:true}),'[BRIDGE.DEBUG] IN coding_tree');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('R40 argument summaries are human-sized and do not expose payload text',()=>{
|
|
56
|
+
assert.equal(summarizeLiveToolArgs('coding_file_write',{
|
|
57
|
+
root_id:'core',path:'src/x.mjs',content:'TOP_SECRET_PAYLOAD'
|
|
58
|
+
}),'core:src/x.mjs (18B)');
|
|
59
|
+
});
|
|
36
60
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
61
|
+
test('R40 interrupted spans remain correlated and session summary is available',()=>{
|
|
62
|
+
const tracker=createLiveTimelineTracker();
|
|
63
|
+
tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'pending-12345678',
|
|
64
|
+
args:{root_id:'core',path:'x.txt',content:'x'}},{sequence:50});
|
|
65
|
+
const lines=tracker.reconcileInterrupted('recovery');
|
|
66
|
+
assert.deepEqual(lines,['β [pending-] OUTCOME_UNKNOWN coding_file_write β recovery ended before terminal result; inspect state before retry']);
|
|
67
|
+
assert.match(tracker.summary(),/^π \[SUMMARY\] 0 calls \| 0 errors/);
|
|
41
68
|
});
|
|
42
69
|
|
|
43
|
-
test('
|
|
70
|
+
test('R40 CLI exposes explicit verbose mode while keeping default live mode compact',async()=>{
|
|
44
71
|
const {readFile}=await import('node:fs/promises');
|
|
45
72
|
const src=await readFile(new URL('../src/deadbyte-cli.mjs',import.meta.url),'utf8');
|
|
46
|
-
assert.match(src,/createLiveTimelineTracker/);
|
|
47
|
-
assert.match(src,/
|
|
48
|
-
assert.
|
|
49
|
-
assert.doesNotMatch(src
|
|
73
|
+
assert.match(src,/createLiveTimelineTracker\(\{verbose,displayMode\}\)/);
|
|
74
|
+
assert.match(src,/args\.includes\('--verbose'\)/);
|
|
75
|
+
assert.match(src,/Transport IN\/OUT hidden/);
|
|
76
|
+
assert.doesNotMatch(src,/\[cursor \$\{recorded\.cursor\}\]/);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
test('R40 ASCII display fallback contains no non-ASCII bytes and preserves terminal meaning',()=>{
|
|
81
|
+
const tracker=createLiveTimelineTracker({clock:()=>1250,displayMode:'ascii'});
|
|
82
|
+
tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'ascii-1234567890',
|
|
83
|
+
ts:'1970-01-01T00:00:01.000Z',args:{root_id:'projects',path:'src/ΰΉΰΈΰΈ’.mjs'}},{sequence:60});
|
|
84
|
+
const line=tracker.observe({event_type:'tool.result',tool:'coding_file_read',request_id:'ascii-1234567890',
|
|
85
|
+
ts:'1970-01-01T00:00:01.250Z',outcome:{is_error:false,duration_ms:250}},{sequence:61});
|
|
86
|
+
assert.match(line,/^R 07:00:01\.250 #61 .* coding_file_read .* 250ms OK$/);
|
|
87
|
+
assert.doesNotMatch(line,/[^\x20-\x7E]/);
|
|
88
|
+
assert.equal(formatRemoteLifecycle('device_start',{displayMode:'ascii'}),'[DEVICE] Starting DEADBYTE MCP...');
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
test('R40 interrupted side effect is explicit OUTCOME_UNKNOWN instead of implying failure or replay safety',()=>{
|
|
92
|
+
const tracker=createLiveTimelineTracker({clock:()=>1000});
|
|
93
|
+
tracker.observe({event_type:'tool.request',tool:'coding_file_write',request_id:'unknown-12345678',
|
|
94
|
+
args:{root_id:'core',path:'x.txt',content:'x'}},{sequence:70});
|
|
95
|
+
const line=tracker.observe({event_type:'tool.result',tool:'coding_file_write',request_id:'unknown-12345678',
|
|
96
|
+
outcome:{status:'interrupted',is_error:true,duration_ms:0,side_effect_state:'unknown',recovery:{reason:'runtime_restart'}}},{sequence:71});
|
|
97
|
+
assert.match(line,/OUTCOME_UNKNOWN β runtime_restart$/);
|
|
98
|
+
assert.doesNotMatch(line,/\s[ββ]\s/);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('R40 UTF-8 truncation never splits Thai or emoji into replacement characters',()=>{
|
|
102
|
+
const input='ΰΈ ΰΈ²ΰΈ©ΰΈ²ΰΉΰΈΰΈ’π'.repeat(40);
|
|
103
|
+
const clipped=truncateUtf8(input,73);
|
|
104
|
+
assert.ok(new TextEncoder().encode(clipped).length<=73);
|
|
105
|
+
assert.equal(clipped.includes('\uFFFD'),false);
|
|
106
|
+
assert.ok(clipped.endsWith('β¦'));
|
|
50
107
|
});
|