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.
Files changed (102) hide show
  1. package/MANIFEST.SHA256 +101 -39
  2. package/README.txt +10 -9
  3. package/acceptance/r40/desktop-live-drift.mjs +106 -0
  4. package/acceptance/r40/desktop-live-ground.mjs +110 -0
  5. package/acceptance/r40/desktop-live-input.mjs +128 -0
  6. package/acceptance/r40/desktop-live-observe.mjs +100 -0
  7. package/acceptance/r40/desktop-live-uia.mjs +121 -0
  8. package/bin/deadbyte-desktop-input-r40.exe +0 -0
  9. package/bin/deadbyte-desktop-input-r40.obj +0 -0
  10. package/bin/deadbyte-desktop-observer-r40.exe +0 -0
  11. package/bin/deadbyte-desktop-observer-r40.obj +0 -0
  12. package/bin/deadbyte-desktop-uia-r40.exe +0 -0
  13. package/bin/deadbyte-desktop-uia-r40.obj +0 -0
  14. package/controller/README.TXT +7 -5
  15. package/controller/deadbyte-controller.config.psd1.example +3 -0
  16. package/controller/deadbyte-controller.ps1 +149 -4
  17. package/controller/deadbyte-desktop-policy.json +41 -0
  18. package/docs/ARCHITECTURE.md +6 -1
  19. package/docs/superpowers/specs/2026-09-19-r40-desktop-computer-use-design.md +214 -0
  20. package/native/deadbyte-desktop-input.cpp +455 -0
  21. package/native/deadbyte-desktop-observer.cpp +253 -0
  22. package/native/deadbyte-desktop-uia.cpp +307 -0
  23. package/package.json +10 -8
  24. package/scripts/build-desktop-r40.ps1 +106 -0
  25. package/scripts/deferred-slot-operation-r39.mjs +124 -0
  26. package/scripts/deferred-slot-operation-r40.mjs +126 -0
  27. package/scripts/final-closure-r39.mjs +113 -0
  28. package/scripts/final-closure-r40.mjs +114 -0
  29. package/scripts/final-closure-verify-r39.mjs +208 -0
  30. package/scripts/final-closure-verify-r40.mjs +212 -0
  31. package/scripts/gate-windows-r39.ps1 +42 -0
  32. package/scripts/gate-windows-r40.ps1 +43 -0
  33. package/scripts/init-desktop-policy-r40.ps1 +79 -0
  34. package/scripts/r40-compact-ledger-probe.mjs +4 -0
  35. package/scripts/release-parity-r39.mjs +200 -0
  36. package/scripts/release-parity-r40.mjs +212 -0
  37. package/scripts/release-parity-tests-r39.ps1 +9 -0
  38. package/scripts/release-parity-tests-r40.ps1 +9 -0
  39. package/scripts/windows-gate-evidence-r39.mjs +52 -0
  40. package/scripts/windows-gate-evidence-r40.mjs +52 -0
  41. package/src/autonomous-context-engine.mjs +2 -1
  42. package/src/autonomous-planner-contracts.mjs +19 -1
  43. package/src/autonomous-planner.mjs +22 -0
  44. package/src/autonomous-runtime.mjs +144 -24
  45. package/src/capability-ledger.mjs +6 -1
  46. package/src/compact-gateway-mcp-tools.mjs +14 -2
  47. package/src/deadbyte-cli.mjs +79 -47
  48. package/src/desktop-contract.mjs +263 -0
  49. package/src/desktop-input-r40.mjs +148 -0
  50. package/src/desktop-mcp-tools-r40.mjs +126 -0
  51. package/src/desktop-memory-r40.mjs +272 -0
  52. package/src/desktop-observer-r40.mjs +231 -0
  53. package/src/desktop-policy-r40.mjs +110 -0
  54. package/src/desktop-runtime-r40.mjs +318 -0
  55. package/src/desktop-uia-r40.mjs +123 -0
  56. package/src/mcp-server.mjs +74 -19
  57. package/src/r40-compact-disarmed-probe.mjs +71 -0
  58. package/src/r40-full-surface-probe.mjs +34 -0
  59. package/src/release-generation.mjs +38 -5
  60. package/src/remote-console.mjs +41 -0
  61. package/src/remote-live-log.mjs +215 -45
  62. package/src/remote-mcp-desktop-r40-smoke-client.mjs +70 -0
  63. package/src/remote-mcp-r40-parity-client.mjs +200 -0
  64. package/src/remote-mcp-smoke-client.mjs +20 -6
  65. package/src/remote-result-journal.mjs +10 -2
  66. package/src/runtime-update.mjs +55 -17
  67. package/src/tool-audit.mjs +29 -2
  68. package/src/version.mjs +1 -1
  69. package/test/autonomous-capability-r36.test.mjs +43 -1
  70. package/test/autonomous-desktop-r40.test.mjs +188 -0
  71. package/test/capability-ledger-r36.test.mjs +1 -0
  72. package/test/cli-entrypoint.test.mjs +1 -1
  73. package/test/compact-catalog-r36.test.mjs +2 -2
  74. package/test/compact-gateway-r36.test.mjs +56 -4
  75. package/test/compact-max-catalog-r40.test.mjs +95 -0
  76. package/test/controller-desktop-r40.test.mjs +85 -0
  77. package/test/core.test.mjs +1 -1
  78. package/test/desktop-adversarial-r40.test.mjs +62 -0
  79. package/test/desktop-contract-r40.test.mjs +200 -0
  80. package/test/desktop-input-r40.test.mjs +63 -0
  81. package/test/desktop-mcp-tools-r40.test.mjs +61 -0
  82. package/test/desktop-memory-r40.test.mjs +141 -0
  83. package/test/desktop-observer-r40.test.mjs +119 -0
  84. package/test/desktop-policy-r40.test.mjs +111 -0
  85. package/test/desktop-runtime-r40.test.mjs +278 -0
  86. package/test/desktop-uia-r40.test.mjs +42 -0
  87. package/test/full-max-catalog-r40.test.mjs +91 -0
  88. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  89. package/test/production-docs.test.mjs +3 -3
  90. package/test/r33-closeout-regression.test.mjs +8 -8
  91. package/test/r33-finalization.test.mjs +14 -14
  92. package/test/r37-remote-tool-call-timeline.test.mjs +7 -6
  93. package/test/r39-finalization.test.mjs +74 -0
  94. package/test/r40-finalization.test.mjs +118 -0
  95. package/test/release-generation.test.mjs +41 -9
  96. package/test/release-version.test.mjs +19 -58
  97. package/test/remote-console-r40.test.mjs +38 -0
  98. package/test/remote-live-log-r37.test.mjs +89 -32
  99. package/test/remote-r24-catalog.test.mjs +12 -3
  100. package/test/remote-result-journal.test.mjs +15 -0
  101. package/test/remote-session-cli.test.mjs +112 -55
  102. 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,6);
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 root=new URL('../',import.meta.url);
7
- const text=rel=>readFile(new URL(rel,root),'utf8');
8
- const R38_PREDECESSOR_RELEASE_ID='v0.11.1-220fac89dd82cdcd';
9
- const R38_PREDECESSOR_MANIFEST='220fac89dd82cdcdddb82cd7d0b71b768f84a5c87d57ebaca0f5383f33d97a76';
10
-
11
- test('R38 hotfix authority agrees on V0.11.2 and preserves exact public 0.11.1 predecessor',async()=>{
12
- const pkg=JSON.parse(await text('package.json'));
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-r38.ps1'),
15
- text('README.txt'),text('docs/ARCHITECTURE.md'),text('controller/README.TXT'),
16
- text('scripts/deferred-slot-operation-r38.mjs'),text('scripts/release-parity-r38.mjs'),text('scripts/final-closure-r38.mjs'),
17
- text('scripts/final-closure-verify-r38.mjs'),text('scripts/windows-gate-evidence-r38.mjs'),
18
- text('controller/deadbyte-semantic-lsp-config.json')
19
- ]);
20
- assert.equal(pkg.version,'0.11.2');
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('R37 live timeline renders sanitized tool-call detail and correlates terminal result with stable short span id',()=>{
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 run=tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'abcdef1234567890',
9
- args:{root_id:'projects',path:'src/a.mjs',content:'SECRET',token:'SECRET'}});
10
- assert.match(run,/^1970-01-01T00:00:01\.000Z \| coding_file_read\s+\| Arguments: \{/);
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.equal(done,'βœ“ [abcdef12] OK coding_file_read 250ms');
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(run+done,/SECRET/);
16
+ assert.doesNotMatch(String(done),/SECRET|Arguments:/);
20
17
  });
21
18
 
22
- test('R37 live timeline distinguishes result whose request was outside live tail',()=>{
23
- const tracker=createLiveTimelineTracker();
24
- const line=tracker.observe({event_type:'tool.result',tool:'coding_tree',request_id:'old-request-12345678',
25
- outcome:{is_error:false,duration_ms:15}});
26
- assert.equal(line,'↩ [old-requ] OK coding_tree 15ms (request before live window)');
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('R37 live timeline deduplicates terminal result and reports interrupted spans with ids',()=>{
30
- const tracker=createLiveTimelineTracker();
31
- tracker.observe({event_type:'tool.request',tool:'coding_command_run',request_id:'request-23456789',args:{command_id:'node_script'}});
32
- const first=tracker.observe({event_type:'tool.result',tool:'coding_command_run',request_id:'request-23456789',outcome:{is_error:true,duration_ms:900}});
33
- const duplicate=tracker.observe({event_type:'tool.result',tool:'coding_command_run',request_id:'request-23456789',outcome:{is_error:true,duration_ms:900}});
34
- assert.equal(first,'βœ— [request-] ERR coding_command_run 900ms');
35
- assert.equal(duplicate,null);
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
- tracker.observe({event_type:'tool.request',tool:'coding_file_read',request_id:'pending-12345678',args:{path:'src/a.mjs'}});
38
- assert.deepEqual(tracker.reconcileInterrupted('recovery'),[
39
- '⚠ [pending-] INTERRUPTED coding_file_read β€” recovery ended before terminal result'
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('R37 CLI uses timeline tracker for compact live mode while keeping legacy formatter API',async()=>{
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,/const activityTracker=createLiveTimelineTracker\(\)/);
48
- assert.doesNotMatch(src,/remote --verbose/);
49
- assert.doesNotMatch(src,/args\[0\]==='--verbose'/);
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
  });