deadbyte-mcp 0.11.3 → 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 (93) hide show
  1. package/MANIFEST.SHA256 +92 -38
  2. package/README.txt +5 -4
  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-r40.mjs +126 -0
  26. package/scripts/final-closure-r40.mjs +114 -0
  27. package/scripts/final-closure-verify-r40.mjs +212 -0
  28. package/scripts/gate-windows-r40.ps1 +43 -0
  29. package/scripts/init-desktop-policy-r40.ps1 +79 -0
  30. package/scripts/r40-compact-ledger-probe.mjs +4 -0
  31. package/scripts/release-parity-r40.mjs +212 -0
  32. package/scripts/release-parity-tests-r40.ps1 +9 -0
  33. package/scripts/windows-gate-evidence-r40.mjs +52 -0
  34. package/src/autonomous-context-engine.mjs +2 -1
  35. package/src/autonomous-planner-contracts.mjs +19 -1
  36. package/src/autonomous-planner.mjs +22 -0
  37. package/src/autonomous-runtime.mjs +144 -24
  38. package/src/capability-ledger.mjs +6 -1
  39. package/src/compact-gateway-mcp-tools.mjs +14 -2
  40. package/src/deadbyte-cli.mjs +72 -44
  41. package/src/desktop-contract.mjs +263 -0
  42. package/src/desktop-input-r40.mjs +148 -0
  43. package/src/desktop-mcp-tools-r40.mjs +126 -0
  44. package/src/desktop-memory-r40.mjs +272 -0
  45. package/src/desktop-observer-r40.mjs +231 -0
  46. package/src/desktop-policy-r40.mjs +110 -0
  47. package/src/desktop-runtime-r40.mjs +318 -0
  48. package/src/desktop-uia-r40.mjs +123 -0
  49. package/src/mcp-server.mjs +74 -19
  50. package/src/r40-compact-disarmed-probe.mjs +71 -0
  51. package/src/r40-full-surface-probe.mjs +34 -0
  52. package/src/release-generation.mjs +38 -5
  53. package/src/remote-console.mjs +41 -0
  54. package/src/remote-live-log.mjs +208 -45
  55. package/src/remote-mcp-desktop-r40-smoke-client.mjs +70 -0
  56. package/src/remote-mcp-r40-parity-client.mjs +200 -0
  57. package/src/remote-mcp-smoke-client.mjs +20 -6
  58. package/src/remote-result-journal.mjs +10 -2
  59. package/src/runtime-update.mjs +55 -17
  60. package/src/tool-audit.mjs +29 -2
  61. package/src/version.mjs +1 -1
  62. package/test/autonomous-capability-r36.test.mjs +43 -1
  63. package/test/autonomous-desktop-r40.test.mjs +188 -0
  64. package/test/capability-ledger-r36.test.mjs +1 -0
  65. package/test/cli-entrypoint.test.mjs +1 -1
  66. package/test/compact-catalog-r36.test.mjs +2 -2
  67. package/test/compact-gateway-r36.test.mjs +56 -4
  68. package/test/compact-max-catalog-r40.test.mjs +95 -0
  69. package/test/controller-desktop-r40.test.mjs +85 -0
  70. package/test/core.test.mjs +1 -1
  71. package/test/desktop-adversarial-r40.test.mjs +62 -0
  72. package/test/desktop-contract-r40.test.mjs +200 -0
  73. package/test/desktop-input-r40.test.mjs +63 -0
  74. package/test/desktop-mcp-tools-r40.test.mjs +61 -0
  75. package/test/desktop-memory-r40.test.mjs +141 -0
  76. package/test/desktop-observer-r40.test.mjs +119 -0
  77. package/test/desktop-policy-r40.test.mjs +111 -0
  78. package/test/desktop-runtime-r40.test.mjs +278 -0
  79. package/test/desktop-uia-r40.test.mjs +42 -0
  80. package/test/full-max-catalog-r40.test.mjs +91 -0
  81. package/test/helpers/autonomous-r34-fixture.mjs +3 -3
  82. package/test/r33-closeout-regression.test.mjs +7 -7
  83. package/test/r33-finalization.test.mjs +14 -14
  84. package/test/r37-remote-tool-call-timeline.test.mjs +6 -5
  85. package/test/r40-finalization.test.mjs +118 -0
  86. package/test/release-generation.test.mjs +41 -9
  87. package/test/release-version.test.mjs +19 -61
  88. package/test/remote-console-r40.test.mjs +38 -0
  89. package/test/remote-live-log-r37.test.mjs +89 -32
  90. package/test/remote-r24-catalog.test.mjs +12 -3
  91. package/test/remote-result-journal.test.mjs +15 -0
  92. package/test/remote-session-cli.test.mjs +69 -46
  93. package/test/runtime-self-update.test.mjs +44 -0
@@ -0,0 +1,128 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { createHash, randomBytes } from 'node:crypto';
4
+ import { access, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
5
+ import os from 'node:os';
6
+ import path from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { generateTrustKeypair, loadPrivateSigningKey, loadPublicVerifyKey } from '../../src/trust.mjs';
9
+ import { loadDesktopPolicy, desktopSessionStatus } from '../../src/desktop-policy-r40.mjs';
10
+ import { createDesktopObserverRuntime } from '../../src/desktop-observer-r40.mjs';
11
+ import { createNativeDesktopInputProvider } from '../../src/desktop-input-r40.mjs';
12
+ import { createDesktopRuntime, verifyDesktopReceiptObject } from '../../src/desktop-runtime-r40.mjs';
13
+
14
+ const here=path.dirname(fileURLToPath(import.meta.url));
15
+ const root=path.resolve(here,'../..');
16
+ const sourcePolicyPath=path.join(root,'controller','deadbyte-desktop-policy.json');
17
+ const sha=value=>createHash('sha256').update(value).digest('hex');
18
+ const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
19
+
20
+ test('R40 guarded native input accepts one SHIFT press-release under scoped authority then revokes it',async()=>{
21
+ const temp=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-live-input-'));
22
+ let grantFile='';
23
+ let sourceGrant='';
24
+ try{
25
+ const raw=JSON.parse(await readFile(sourcePolicyPath,'utf8'));
26
+ sourceGrant=raw.grant_file;
27
+ assert.equal(await absent(sourceGrant),true,'source Desktop grant must remain absent');
28
+
29
+ grantFile=path.join(temp,'desktop-grant.json');
30
+ const evidenceDir=path.join(temp,'desktop-evidence');
31
+ const policyPath=path.join(temp,'desktop-policy.json');
32
+ raw.grant_file=grantFile;
33
+ raw.evidence_dir=evidenceDir;
34
+ raw.allowed_actions=['key_chord'];
35
+ await writeFile(policyPath,JSON.stringify(raw,null,2));
36
+
37
+ const policy=await loadDesktopPolicy(policyPath);
38
+ const trustDir=path.join(temp,'trust');
39
+ await mkdir(trustDir,{recursive:true});
40
+ const keys=await generateTrustKeypair({
41
+ privateKeyPath:path.join(trustDir,'private.pem'),
42
+ publicKeyPath:path.join(trustDir,'public.pem')
43
+ });
44
+ const signer=await loadPrivateSigningKey(keys.privateKeyPath);
45
+ const verifier=await loadPublicVerifyKey(keys.publicKeyPath);
46
+
47
+ await writeFile(grantFile,JSON.stringify({
48
+ schema:'deadbyte.desktop-grant.v1',
49
+ policy_sha256:policy.policy_sha256,
50
+ instance_nonce:randomBytes(32).toString('hex'),
51
+ action_kinds:['key_chord'],
52
+ granted_at_utc:new Date().toISOString()
53
+ }));
54
+ const authority=await desktopSessionStatus(policy);
55
+ assert.equal(authority.armed,true);
56
+ assert.deepEqual(authority.action_kinds,['key_chord']);
57
+
58
+ const observer=createDesktopObserverRuntime({
59
+ observerPath:policy.observer.executable,
60
+ expectedObserverSha256:policy.observer.sha256,
61
+ maxFrameBytes:policy.limits.max_frame_bytes,
62
+ timeoutMs:policy.limits.capture_timeout_ms,
63
+ allowInputDesktops:policy.allowed_input_desktops
64
+ });
65
+ const input=createNativeDesktopInputProvider({
66
+ inputPath:policy.input.executable,
67
+ expectedInputSha256:policy.input.sha256,
68
+ timeoutMs:policy.limits.input_timeout_ms
69
+ });
70
+ const runtime=createDesktopRuntime({
71
+ policy,observerRuntime:observer,inputProvider:input,
72
+ privateKey:signer.privateKey,keyId:signer.keyId
73
+ });
74
+
75
+ const expected=await runtime.observe();
76
+ const intentId=sha(Buffer.from('R40 guarded live acceptance: SHIFT press-release','utf8'));
77
+ const result=await runtime.action({
78
+ intentId,kind:'key_chord',expectedFrameId:expected.frame.frame_id,keyChord:['SHIFT']
79
+ });
80
+ assert.equal(result.status,'ok');
81
+ assert.equal(result.injected,true);
82
+ assert.equal(result.action.kind,'key_chord');
83
+ assert.deepEqual(result.action.key_chord,['SHIFT']);
84
+ assert.equal(result.side_effect_state,'confirmed_injected');
85
+ assert.match(result.started_receipt_id,/^[0-9a-f]{24}$/);
86
+ assert.match(result.post_receipt_id,/^[0-9a-f]{24}$/);
87
+ assert.match(result.post_receipt_sha256,/^[0-9a-f]{64}$/);
88
+ assert.match(result.action_chain.chain_sha256,/^[0-9a-f]{64}$/);
89
+ assert.match(result.effect_id,/^[0-9a-f]{64}$/);
90
+ assert.match(result.effect_fingerprint,/^[0-9a-f]{64}$/);
91
+ assert.equal(result.effect_completion.schema,'deadbyte.effect-completion.v1');
92
+ assert.match(result.receipt_id,/^[0-9a-f]{24}$/);
93
+
94
+ const ids=[expected.receipt_id,result.started_receipt_id,result.post_receipt_id,result.receipt_id];
95
+ const verified=[];
96
+ for(const id of ids){
97
+ const receipt=JSON.parse(await readFile(path.join(evidenceDir,id+'.json'),'utf8'));
98
+ const proof=verifyDesktopReceiptObject(receipt,{
99
+ policySha256:policy.policy_sha256,publicKey:verifier.publicKey,keyId:verifier.keyId
100
+ });
101
+ assert.equal(proof.ok,true,'receipt verification failed: '+id);
102
+ verified.push({id,kind:proof.kind,sha256:proof.receipt_sha256});
103
+ }
104
+ assert.deepEqual(verified.map(v=>v.kind),['desktop_observation','desktop_action_started','desktop_post_observation','desktop_action_completed']);
105
+ const postReceipt=JSON.parse(await readFile(path.join(evidenceDir,result.post_receipt_id+'.json'),'utf8'));
106
+ assert.equal(postReceipt.payload.post_observation_sha256,result.post_observation.post_observation_sha256);
107
+ const completed=JSON.parse(await readFile(path.join(evidenceDir,result.receipt_id+'.json'),'utf8'));
108
+ assert.equal(completed.payload.effect.injected,true);
109
+ assert.match(completed.payload.effect.provider_receipt_sha256,/^[0-9a-f]{64}$/);
110
+
111
+ console.log(JSON.stringify({
112
+ status:'PASS',action:'key_chord',keys:['SHIFT'],native_injected:true,
113
+ authority_scope:['key_chord'],expected_frame_id:expected.frame.frame_id,
114
+ action_sha256:result.action.action_sha256,guard_sha256:result.guard.guard_sha256,
115
+ provider_receipt_sha256:completed.payload.effect.provider_receipt_sha256,
116
+ action_chain_sha256:result.action_chain.chain_sha256,
117
+ effect_id:result.effect_id,effect_fingerprint:result.effect_fingerprint,
118
+ effect_completion_result_sha256:result.effect_completion.result_sha256,
119
+ observation_receipt:verified[0],started_receipt:verified[1],post_receipt:verified[2],completed_receipt:verified[3],
120
+ replay_performed:false
121
+ }));
122
+ } finally {
123
+ if(grantFile) await rm(grantFile,{force:true}).catch(()=>{});
124
+ if(sourceGrant) assert.equal(await absent(sourceGrant),true,'source Desktop grant changed during acceptance');
125
+ if(grantFile) assert.equal(await absent(grantFile),true,'temporary Desktop grant was not revoked');
126
+ await rm(temp,{recursive:true,force:true});
127
+ }
128
+ });
@@ -0,0 +1,100 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { access, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { generateTrustKeypair, loadPrivateSigningKey, loadPublicVerifyKey } from '../../src/trust.mjs';
8
+ import { loadDesktopPolicy } from '../../src/desktop-policy-r40.mjs';
9
+ import { createDesktopObserverRuntime } from '../../src/desktop-observer-r40.mjs';
10
+ import { createNativeDesktopInputProvider } from '../../src/desktop-input-r40.mjs';
11
+ import { createDesktopRuntime, verifyDesktopReceiptObject } from '../../src/desktop-runtime-r40.mjs';
12
+
13
+ const here=path.dirname(fileURLToPath(import.meta.url));
14
+ const root=path.resolve(here,'../..');
15
+ const sourcePolicyPath=path.join(root,'controller','deadbyte-desktop-policy.json');
16
+ const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
17
+
18
+ test('R40 live native Desktop status and observation succeed while mutation authority stays DISARMED',async()=>{
19
+ const temp=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-live-observe-'));
20
+ try{
21
+ const raw=JSON.parse(await readFile(sourcePolicyPath,'utf8'));
22
+ const sourceGrant=raw.grant_file;
23
+ assert.equal(await absent(sourceGrant),true,'source Desktop grant must be absent before live observation');
24
+
25
+ const grantFile=path.join(temp,'desktop-grant.json');
26
+ const evidenceDir=path.join(temp,'desktop-evidence');
27
+ const policyPath=path.join(temp,'desktop-policy.json');
28
+ await mkdir(evidenceDir,{recursive:true});
29
+ raw.grant_file=grantFile;
30
+ raw.evidence_dir=evidenceDir;
31
+ await writeFile(policyPath,JSON.stringify(raw,null,2));
32
+
33
+ const policy=await loadDesktopPolicy(policyPath);
34
+ const trustDir=path.join(temp,'trust');
35
+ await mkdir(trustDir,{recursive:true});
36
+ const keys=await generateTrustKeypair({
37
+ privateKeyPath:path.join(trustDir,'private.pem'),
38
+ publicKeyPath:path.join(trustDir,'public.pem')
39
+ });
40
+ const signer=await loadPrivateSigningKey(keys.privateKeyPath);
41
+ const verifier=await loadPublicVerifyKey(keys.publicKeyPath);
42
+
43
+ const observer=createDesktopObserverRuntime({
44
+ observerPath:policy.observer.executable,
45
+ expectedObserverSha256:policy.observer.sha256,
46
+ maxFrameBytes:policy.limits.max_frame_bytes,
47
+ timeoutMs:policy.limits.capture_timeout_ms,
48
+ allowInputDesktops:policy.allowed_input_desktops
49
+ });
50
+ const input=createNativeDesktopInputProvider({
51
+ inputPath:policy.input.executable,
52
+ expectedInputSha256:policy.input.sha256,
53
+ timeoutMs:policy.limits.input_timeout_ms
54
+ });
55
+ const runtime=createDesktopRuntime({
56
+ policy,observerRuntime:observer,inputProvider:input,
57
+ privateKey:signer.privateKey,keyId:signer.keyId
58
+ });
59
+
60
+ const status=await runtime.status();
61
+ assert.equal(status.status,'ok');
62
+ assert.equal(status.armed,false);
63
+ assert.equal(status.reason,'disarmed');
64
+ assert.deepEqual(status.action_kinds,[]);
65
+ assert.equal(await absent(grantFile),true);
66
+
67
+ const observed=await runtime.observe();
68
+ assert.equal(observed.status,'ok');
69
+ assert.match(observed.frame.frame_id,/^[0-9a-f]{64}$/);
70
+ assert.match(observed.frame.image_sha256,/^[0-9a-f]{64}$/);
71
+ assert.match(observed.frame.topology_sha256,/^[0-9a-f]{64}$/);
72
+ assert.ok(observed.byte_length>0);
73
+ assert.equal(Object.hasOwn(observed,'pixels'),false,'public observation must not expose raw frame pixels');
74
+ assert.match(observed.receipt_id,/^[0-9a-f]{24}$/);
75
+ assert.match(observed.receipt_sha256,/^[0-9a-f]{64}$/);
76
+
77
+ const receipt=JSON.parse(await readFile(path.join(evidenceDir,observed.receipt_id+'.json'),'utf8'));
78
+ const proof=verifyDesktopReceiptObject(receipt,{
79
+ policySha256:policy.policy_sha256,publicKey:verifier.publicKey,keyId:verifier.keyId
80
+ });
81
+ assert.equal(proof.ok,true);
82
+ assert.equal(proof.kind,'desktop_observation');
83
+
84
+ assert.equal(await absent(grantFile),true,'live observe must not create mutation authority');
85
+ assert.equal(await absent(sourceGrant),true,'live observe must not touch source Desktop grant');
86
+
87
+ const w=observed.frame.active_window;
88
+ console.log(JSON.stringify({
89
+ status:'PASS',desktop_authority:'DISARMED',observer_backend:observed.backend,
90
+ frame_id:observed.frame.frame_id,desktop_epoch:observed.frame.desktop_epoch,
91
+ topology_sha256:observed.frame.topology_sha256,image_sha256:observed.frame.image_sha256,
92
+ bounds:observed.frame.bounds,byte_length:observed.byte_length,
93
+ active_window:w?{hwnd:w.hwnd,pid:w.pid,process_image_sha256:w.process_image_sha256??null,title_sha256:w.title_sha256??null}:null,
94
+ receipt_id:observed.receipt_id,receipt_sha256:observed.receipt_sha256,receipt_verified:true,
95
+ raw_pixels_exposed:false
96
+ }));
97
+ } finally {
98
+ await rm(temp,{recursive:true,force:true});
99
+ }
100
+ });
@@ -0,0 +1,121 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { access, mkdtemp, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { fileURLToPath } from 'node:url';
7
+ import { generateTrustKeypair, loadPrivateSigningKey, loadPublicVerifyKey } from '../../src/trust.mjs';
8
+ import { loadDesktopPolicy } from '../../src/desktop-policy-r40.mjs';
9
+ import { createDesktopObserverRuntime } from '../../src/desktop-observer-r40.mjs';
10
+ import { createNativeDesktopGrounder } from '../../src/desktop-uia-r40.mjs';
11
+ import { createDesktopRuntime, verifyDesktopReceiptObject } from '../../src/desktop-runtime-r40.mjs';
12
+
13
+ const here=path.dirname(fileURLToPath(import.meta.url));
14
+ const root=path.resolve(here,'../..');
15
+ const sourcePolicyPath=path.join(root,'controller','deadbyte-desktop-policy.json');
16
+ const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
17
+
18
+ test('R40 T5 live UIA root grounding and bounded preview stay read-only and signed',async()=>{
19
+ const temp=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-live-uia-'));
20
+ let sourceGrant='';
21
+ try{
22
+ const raw=JSON.parse(await readFile(sourcePolicyPath,'utf8'));
23
+ sourceGrant=raw.grant_file;
24
+ assert.equal(await absent(sourceGrant),true,'source Desktop grant must be absent');
25
+
26
+ const grantFile=path.join(temp,'desktop-grant.json');
27
+ const evidenceDir=path.join(temp,'desktop-evidence');
28
+ const policyPath=path.join(temp,'desktop-policy.json');
29
+ raw.grant_file=grantFile;
30
+ raw.evidence_dir=evidenceDir;
31
+ await writeFile(policyPath,JSON.stringify(raw,null,2));
32
+ const policy=await loadDesktopPolicy(policyPath);
33
+
34
+ const trustDir=path.join(temp,'trust');
35
+ await mkdir(trustDir,{recursive:true});
36
+ const keys=await generateTrustKeypair({
37
+ privateKeyPath:path.join(trustDir,'private.pem'),
38
+ publicKeyPath:path.join(trustDir,'public.pem')
39
+ });
40
+ const signer=await loadPrivateSigningKey(keys.privateKeyPath);
41
+ const verifier=await loadPublicVerifyKey(keys.publicKeyPath);
42
+
43
+ const observer=createDesktopObserverRuntime({
44
+ observerPath:policy.observer.executable,
45
+ expectedObserverSha256:policy.observer.sha256,
46
+ maxFrameBytes:policy.limits.max_frame_bytes,
47
+ timeoutMs:policy.limits.capture_timeout_ms,
48
+ allowInputDesktops:policy.allowed_input_desktops,
49
+ maxCachedFrames:4
50
+ });
51
+ const grounder=createNativeDesktopGrounder({
52
+ grounderPath:policy.grounder.executable,
53
+ expectedGrounderSha256:policy.grounder.sha256,
54
+ timeoutMs:policy.limits.ground_timeout_ms
55
+ });
56
+ const runtime=createDesktopRuntime({
57
+ policy,observerRuntime:observer,
58
+ inputProvider:async()=>{throw new Error('input must not be called by T5 live grounding');},
59
+ grounderProvider:grounder,
60
+ privateKey:signer.privateKey,keyId:signer.keyId
61
+ });
62
+
63
+ const status=await runtime.status();
64
+ assert.equal(status.armed,false);
65
+ assert.equal(await absent(grantFile),true);
66
+
67
+ const observed=await runtime.observe({preview:true});
68
+ assert.equal(observed.status,'ok');
69
+ assert.ok(observed.frame.active_window,'T5 live UIA acceptance requires one foreground window');
70
+ assert.equal(observed.preview.schema,'deadbyte.desktop-preview.v1');
71
+ assert.equal(observed.preview.encoding,'ppm-base64');
72
+ assert.ok(observed.preview.byte_length<=policy.limits.max_preview_bytes);
73
+ assert.match(observed.preview.sha256,/^[0-9a-f]{64}$/);
74
+ assert.ok(Buffer.from(observed.preview.data_base64,'base64').length===observed.preview.byte_length);
75
+
76
+ const grounded=await runtime.ground({
77
+ frameId:observed.frame.frame_id,
78
+ query:{kind:'root',value:'',max_results:1,ordinal:0}
79
+ });
80
+ assert.equal(grounded.status,'ok');
81
+ assert.equal(grounded.target.source,'uia');
82
+ assert.equal(grounded.target.frame_id,grounded.frame.frame_id);
83
+ assert.equal(grounded.grounding.query_kind,'root');
84
+ assert.equal(grounded.grounding.match_count,1);
85
+ assert.equal(grounded.grounding.ordinal,0);
86
+ assert.match(grounded.target.target_id,/^[0-9a-f]{64}$/);
87
+ assert.match(grounded.grounding.provider_receipt_sha256,/^[0-9a-f]{64}$/);
88
+
89
+ const b=grounded.frame.bounds,r=grounded.target.rect;
90
+ assert.ok(r.left>=b.left&&r.top>=b.top&&r.left+r.width<=b.left+b.width&&r.top+r.height<=b.top+b.height);
91
+
92
+ const receipt=JSON.parse(await readFile(path.join(evidenceDir,grounded.grounding.receipt_id+'.json'),'utf8'));
93
+ const proof=verifyDesktopReceiptObject(receipt,{
94
+ policySha256:policy.policy_sha256,publicKey:verifier.publicKey,keyId:verifier.keyId
95
+ });
96
+ assert.equal(proof.ok,true);
97
+ assert.equal(proof.kind,'desktop_grounding');
98
+ assert.equal(receipt.payload.target_id,grounded.target.target_id);
99
+ assert.equal(receipt.payload.query_sha256,grounded.grounding.query_sha256);
100
+
101
+ assert.equal(await absent(grantFile),true,'T5 grounding must not create Desktop mutation grant');
102
+ assert.equal(await absent(sourceGrant),true,'source Desktop grant changed');
103
+
104
+ console.log(JSON.stringify({
105
+ status:'PASS',authority:'DISARMED',preview:{
106
+ width:observed.preview.width,height:observed.preview.height,
107
+ byte_length:observed.preview.byte_length,sha256:observed.preview.sha256
108
+ },
109
+ foreground:{hwnd:grounded.frame.active_window?.hwnd??null,pid:grounded.frame.active_window?.pid??null},
110
+ target_id:grounded.target.target_id,rect:grounded.target.rect,
111
+ query_sha256:grounded.grounding.query_sha256,
112
+ provider_receipt_sha256:grounded.grounding.provider_receipt_sha256,
113
+ grounding_receipt_id:grounded.grounding.receipt_id,
114
+ grounding_receipt_sha256:grounded.grounding.receipt_sha256,
115
+ receipt_verified:true,mutation:false
116
+ }));
117
+ }finally{
118
+ if(sourceGrant) assert.equal(await absent(sourceGrant),true,'source Desktop grant changed during cleanup');
119
+ await rm(temp,{recursive:true,force:true});
120
+ }
121
+ });
Binary file
Binary file
@@ -1,4 +1,4 @@
1
- DEADBYTE MCP V0.11.3 / R39 CONTROLLER
1
+ DEADBYTE MCP V0.12.0 / R40 CONTROLLER
2
2
  ====================================
3
3
 
4
4
  ENTRY POINT
@@ -8,12 +8,14 @@ Primary operator entry point:
8
8
  npx deadbyte-mcp@latest remote
9
9
 
10
10
  Bare `remote` is a foreground device session. It starts the verified runtime, arms process,
11
- coding, and autonomous authority, verifies those three planes are ARMED, and requires Host to stay
12
- DISARMED. The production Bridge uses the R37 compact capability profile (<=42 tools) while local
13
- stdio MCP keeps the exact full 76-tool profile. The compact console shows request-before-result
11
+ coding, and autonomous authority, verifies those three planes are ARMED, and requires Desktop and Host
12
+ to stay DISARMED. R40 Desktop observation/UIA grounding remains available read-only; GUI mutation needs
13
+ the separate explicit Desktop standing grant and Autonomous authority cannot substitute for it.
14
+ The production Bridge uses the compact capability profile (exact 42 tools / 6 gateways) while local
15
+ stdio MCP keeps the exact full 80-tool profile. The compact console shows request-before-result
14
16
  Live Activity without raw SHA text, request IDs, payload JSON, or duplicate Bridge stdout by
15
17
  default; use `remote --verbose` for the detailed audit/runtime stream. Ctrl+C/SIGTERM or foreground
16
- input closure revokes process/coding/autonomous authority, applies fail-safe Host disarm, and parks
18
+ input closure revokes Desktop/process/coding/autonomous authority, applies fail-safe Host disarm, and parks
17
19
  the Bridge. A detached nonce-bound guardian performs the same fixed revoke+park cleanup if the
18
20
  foreground owner is hard-killed. The v2 session marker records owner PID, guardian PID, and random
19
21
  256-bit nonce so a guardian cannot remove a replacement session marker; a later start recovers only
@@ -17,6 +17,9 @@
17
17
  MachineFsRuntimeEnabled = $false
18
18
  # R32 observation is read-only over registered roots/local runtime and never arms coding mutation authority.
19
19
  ObservationRuntimeEnabled = $false
20
+ # R40 Desktop observation/mutation runtime. Enabling runtime never arms mutation authority.
21
+ DesktopRuntimeEnabled = $false
22
+ DesktopPolicyFile = ''
20
23
  CodingPolicyFile = ''
21
24
  # Optional R35 multi-language semantic LSP config. Path and SHA-256 must be supplied together.
22
25
  # The release generator copies these exact bytes into the immutable generation when configured.