deadbyte-mcp 0.15.24 → 0.15.26

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 (48) hide show
  1. package/MANIFEST.SHA256 +47 -37
  2. package/PROVENANCE.json +11 -11
  3. package/R49-PARENT.json +11 -0
  4. package/README.txt +16 -7
  5. package/RELEASE.json +15 -12
  6. package/SBOM.cdx.json +3 -3
  7. package/TEST-MATRIX.json +15 -12
  8. package/docs/R49-FULL-TOOL-CATALOG.json +13 -0
  9. package/docs/R49-REMOTE-CONTROL-DONORS.json +75 -0
  10. package/package.json +2 -2
  11. package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +17 -6
  12. package/scripts/commander-hardening-gate-r47.mjs +10 -1
  13. package/scripts/deferred-slot-operation-r46.mjs +44 -2
  14. package/scripts/gate-windows-r48.ps1 +45 -0
  15. package/scripts/gate-windows-r49.ps1 +54 -0
  16. package/scripts/init-host-policy.ps1 +9 -1
  17. package/scripts/npm-release-r48.mjs +2 -1
  18. package/scripts/windows-gate-evidence-r48.mjs +27 -0
  19. package/scripts/windows-gate-evidence-r49.mjs +27 -0
  20. package/src/autonomous-planner-contracts.mjs +1 -0
  21. package/src/autonomous-planner.mjs +11 -5
  22. package/src/autonomous-runtime.mjs +11 -1
  23. package/src/capability-ledger.mjs +1 -0
  24. package/src/commander-wire-adapter-r47.mjs +16 -0
  25. package/src/desktop-mcp-tools-r40.mjs +23 -1
  26. package/src/desktop-runtime-r40.mjs +46 -2
  27. package/src/machine-fs-smoke-client.mjs +6 -17
  28. package/src/mcp-host-smoke-client.mjs +3 -2
  29. package/src/mcp-smoke-client.mjs +4 -9
  30. package/src/observation-smoke-client.mjs +5 -10
  31. package/src/process-smoke-client.mjs +3 -3
  32. package/src/remote-mcp-smoke-client.mjs +7 -1
  33. package/src/runtime-catalog-expectation.mjs +45 -0
  34. package/src/tunnel-stdio-compat-smoke.mjs +5 -9
  35. package/src/version.mjs +1 -1
  36. package/test/autonomous-desktop-r40.test.mjs +27 -1
  37. package/test/coding-catalog-consistency.test.mjs +9 -1
  38. package/test/commander-real-parity-r47.test.mjs +8 -4
  39. package/test/contained.test.mjs +4 -6
  40. package/test/controller.test.mjs +2 -1
  41. package/test/desktop-mcp-tools-r40.test.mjs +19 -4
  42. package/test/desktop-runtime-r40.test.mjs +43 -2
  43. package/test/full-max-catalog-r48.test.mjs +5 -3
  44. package/test/r48-release-contract.test.mjs +14 -20
  45. package/test/r49-remote-control-donors.test.mjs +24 -0
  46. package/test/r49-windows-gate.test.mjs +33 -0
  47. package/test/remote-r24-catalog.test.mjs +9 -0
  48. package/test/tunnel-stdio-compat.test.mjs +4 -6
@@ -19,7 +19,7 @@ function F(at,image=H('same'),window=WIN){
19
19
  bounds:{left:0,top:0,width:1000,height:800},activeWindow:window,imageSha256:image
20
20
  });
21
21
  }
22
- async function fixture({grantActions=['click_primary','text_input'],captureFrames=null,times=null,inputProvider=null,grounderProvider=null}={}){
22
+ async function fixture({grantActions=['click_primary','text_input'],captureFrames=null,times=null,inputProvider=null,grounderProvider=null,clockMs=null,sleeper=null}={}){
23
23
  const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r40-desktop-runtime-'));
24
24
  const grant=path.join(root,'grant.json'),evidence=path.join(root,'evidence');
25
25
  const policy={
@@ -59,7 +59,7 @@ async function fixture({grantActions=['click_primary','text_input'],captureFrame
59
59
  '2026-09-19T02:00:01.000Z'
60
60
  ])];
61
61
  const now=()=>clock.length?clock.shift():'2026-09-19T02:00:01.000Z';
62
- const runtime=createDesktopRuntime({policy,observerRuntime,inputProvider:provider,grounderProvider,privateKey,keyId:'test-key',evidenceDir:evidence,now});
62
+ const runtime=createDesktopRuntime({policy,observerRuntime,inputProvider:provider,grounderProvider,privateKey,keyId:'test-key',evidenceDir:evidence,now,clockMs:clockMs??undefined,sleeper:sleeper??undefined});
63
63
  return {root,grant,evidence,policy,expected,runtime,calls,publicKey};
64
64
  }
65
65
 
@@ -242,6 +242,47 @@ test('read-only observe works independently of desktop mutation grant',async()=>
242
242
  assert.match(observed.receipt_sha256,/^[0-9a-f]{64}$/);
243
243
  });
244
244
 
245
+ test('successor desktop wait observes until a frame changes and publishes signed final evidence',async()=>{
246
+ let tick=0;
247
+ const same={frame:F('2026-09-19T02:00:00.600Z'),backend:'fake',byte_length:4};
248
+ const changed={frame:F('2026-09-19T02:00:00.900Z',H('changed')),backend:'fake',byte_length:4};
249
+ const fx=await fixture({
250
+ captureFrames:[same,changed],clockMs:()=>tick,sleeper:async ms=>{tick+=ms;},
251
+ times:['2026-09-19T02:00:01.000Z']
252
+ });
253
+ await writeFile(fx.grant,'{}');
254
+ const result=await fx.runtime.wait({baselineFrameId:fx.expected.frame_id,until:'frame_changed',timeoutMs:1000,pollMs:100});
255
+ assert.equal(result.satisfied,true);
256
+ assert.equal(result.timed_out,false);
257
+ assert.equal(result.attempts,2);
258
+ assert.equal(result.frame.frame_id,changed.frame.frame_id);
259
+ assert.match(result.receipt_sha256,/^[0-9a-f]{64}$/);
260
+ const receipt=JSON.parse(await readFile(path.join(fx.evidence,`${result.receipt_id}.json`),'utf8'));
261
+ assert.equal(receipt.kind,'desktop_wait_observation');
262
+ assert.equal(receipt.payload.condition,'frame_changed');
263
+ assert.equal(receipt.payload.satisfied,true);
264
+ assert.equal(fx.calls.length,0);
265
+ });
266
+
267
+ test('successor desktop wait uses local UIA matching without leaking query text or dispatching input',async()=>{
268
+ let tick=0,queries=0;
269
+ const first={frame:F('2026-09-19T02:00:00.600Z'),backend:'fake',byte_length:4};
270
+ const second={frame:F('2026-09-19T02:00:00.900Z'),backend:'fake',byte_length:4};
271
+ const grounderProvider=async({query})=>{
272
+ queries++;
273
+ return {status:'ok',query_sha256:H('wait-query'),query_kind:query.kind,ordinal:0,visited:4,truncated:false,
274
+ matches:queries===1?[]:[{rect:{left:1,top:2,width:3,height:4},control_type:50000,enabled:true,offscreen:false}],
275
+ provider_receipt_sha256:H('wait-provider')};
276
+ };
277
+ const fx=await fixture({captureFrames:[first,second],grounderProvider,clockMs:()=>tick,sleeper:async ms=>{tick+=ms;},times:['2026-09-19T02:00:01.000Z']});
278
+ const result=await fx.runtime.wait({baselineFrameId:fx.expected.frame_id,until:'uia_present',query:{kind:'name_exact',value:'SECRET READY',max_results:8,ordinal:0},timeoutMs:1000,pollMs:100});
279
+ assert.equal(result.satisfied,true);
280
+ assert.equal(result.match.actionable,true);
281
+ assert.equal(result.match.query_sha256,H('wait-query'));
282
+ assert.equal(JSON.stringify(result).includes('SECRET READY'),false);
283
+ assert.equal(fx.calls.length,0);
284
+ });
285
+
245
286
 
246
287
  test('desktop runtime enforces policy max_text_bytes before observation or input effect',async()=>{
247
288
  const fx=await fixture({grantActions:['text_input']});
@@ -7,6 +7,7 @@ import { fileURLToPath } from 'node:url';
7
7
  import { Client } from '@modelcontextprotocol/client';
8
8
  import { StdioClientTransport, getDefaultEnvironment } from '@modelcontextprotocol/client/stdio';
9
9
  import { createR34Fixture } from './helpers/autonomous-r34-fixture.mjs';
10
+ import { expectedFullCatalogForEnv } from '../src/runtime-catalog-expectation.mjs';
10
11
 
11
12
  const here=path.dirname(fileURLToPath(import.meta.url));
12
13
  const repoRoot=path.resolve(here,'..');
@@ -15,7 +16,7 @@ const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy
15
16
  const catalogPath=path.join(repoRoot,'docs','R48-FULL-TOOL-CATALOG.json');
16
17
  const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
17
18
 
18
- test('R48 runtime full stdio catalog exactly matches canonical registration surface',async()=>{
19
+ test('R49 runtime full stdio catalog exactly matches sealed R48 base plus reviewed overlay',async()=>{
19
20
  const canonical=JSON.parse(await readFile(catalogPath,'utf8'));
20
21
  assert.equal(canonical.schema,'deadbyte.r48-full-catalog.v1');
21
22
  assert.equal(canonical.train,'R48');
@@ -61,15 +62,16 @@ test('R48 runtime full stdio catalog exactly matches canonical registration surf
61
62
  DEADBYTE_AUTONOMOUS_RUNTIME:'1',DEADBYTE_AUTONOMOUS_POLICY:path.join(f.root,'autonomous-policy.json'),
62
63
  DEADBYTE_AUTONOMOUS_SUPERVISOR_MODE:'external'
63
64
  };
65
+ const expected=await expectedFullCatalogForEnv(env);
64
66
  const transport=new StdioClientTransport({command:process.execPath,args:[serverPath],cwd:repoRoot,env,stderr:'pipe'});
65
67
  try{
66
68
  await client.connect(transport);
67
69
  const listed=await client.listTools();
68
70
  const names=listed.tools.map(t=>t.name).sort();
69
- assert.deepEqual(names,canonical.tools);
71
+ assert.deepEqual(names,expected);
70
72
  assert.equal(new Set(names).size,names.length,'runtime duplicate tool names');
71
73
  for(const tool of listed.tools) if(tool.outputSchema!==undefined) assert.equal(tool.outputSchema?.additionalProperties,false,'non-strict output '+tool.name);
72
- for(const name of ['agent_task_submit','autonomous_goal_submit','coding_task_submit','process_session_start','machine_fs_write','machine_search_start','desktop_action','host_exec','native_diff_apply','skill_catalog']) assert.ok(names.includes(name),'missing R48 surface '+name);
74
+ for(const name of ['agent_task_submit','autonomous_goal_submit','coding_task_submit','process_session_start','machine_fs_write','machine_search_start','desktop_wait','desktop_action','host_exec','native_diff_apply','skill_catalog']) assert.ok(names.includes(name),'missing R49 surface '+name);
73
75
  } finally {
74
76
  await client.close().catch(()=>{});
75
77
  for(const q of [processGrant,hostArm,desktopGrant,codingLease,autonomousLease]) assert.equal(await absent(q),true,'authority file appeared during catalog probe: '+q);
@@ -6,7 +6,7 @@ import { DEADBYTE_VERSION } from '../src/version.mjs';
6
6
  const root=new URL('../',import.meta.url);
7
7
  const read=rel=>readFile(new URL(rel,root),'utf8');
8
8
 
9
- test('R48 0.15.24 successor binds exact active 0.15.23 parent and Commander differential evidence',async()=>{
9
+ test('R49 0.15.26 successor binds exact published immutable 0.15.25 parent',async()=>{
10
10
  const [pkg,lock,release,provenance,matrix]=await Promise.all([
11
11
  read('package.json').then(JSON.parse),
12
12
  read('package-lock.json').then(JSON.parse),
@@ -14,24 +14,19 @@ test('R48 0.15.24 successor binds exact active 0.15.23 parent and Commander diff
14
14
  read('PROVENANCE.json').then(JSON.parse),
15
15
  read('TEST-MATRIX.json').then(JSON.parse)
16
16
  ]);
17
- assert.equal(pkg.version,'0.15.24');
18
- assert.equal(lock.version,'0.15.24');
19
- assert.equal(lock.packages[''].version,'0.15.24');
20
- assert.equal(DEADBYTE_VERSION,'0.15.24');
21
- assert.equal(release.version,'0.15.24');
22
- assert.equal(provenance.version,'0.15.24');
23
- assert.equal(matrix.version,'0.15.24');
24
- assert.equal(release.train,'R48');
25
- assert.equal(release.label,'COMMANDER DIFFERENTIAL + PROTOCOL HARDENING BASELINE');
26
- assert.equal(release.parent.release_id,'v0.15.23-c97e3d21e792420e');
27
- assert.equal(release.parent.manifest_sha256,'c97e3d21e792420ea90dada3c1360cd56e4c1f221daa86596d611b0d1ac351ec');
28
- assert.equal(release.parent.generation_manifest_sha256,'4d2d3a4dc103576c39171c52db3436366e62d8b872bcafa4c55f2adb6d3a1126');
29
- assert.equal(release.source_predecessor.version,'0.15.23');
30
- assert.equal(release.source_predecessor.tarball_sha256,'8c8711805bd05b9d4f61a7c9e123d888eb65121a10c85247807a723154416af4');
31
- assert.equal(release.source_predecessor.manifest_file_sha256,'c97e3d21e792420ea90dada3c1360cd56e4c1f221daa86596d611b0d1ac351ec');
17
+ for(const value of [pkg.version,lock.version,lock.packages[''].version,DEADBYTE_VERSION,release.version,provenance.version,matrix.version])assert.equal(value,'0.15.26');
18
+ assert.equal(release.train,'R49');
19
+ assert.equal(release.label,'BOUNDED SEMANTIC DESKTOP WAIT + REMOTE CONTROL HARDENING');
20
+ assert.equal(release.parent.release_id,'v0.15.25-7ed657b1aa038ee6');
21
+ assert.equal(release.parent.manifest_sha256,'7ed657b1aa038ee679ff081f1a83c421a5eeb5fc7ea6b746e0f661079b69b319');
22
+ assert.equal(release.parent.generation_manifest_sha256,'c9763738e27ec39b1180473995f2af088d85293a94f5693abd6a843e09cecec9');
23
+ assert.equal(release.source_predecessor.version,'0.15.25');
24
+ assert.equal(release.source_predecessor.tarball_sha256,'0410b41b3c891210262a4db793ee3b339862472ef069f881c9e092c1083ba6d2');
25
+ assert.equal(release.source_predecessor.manifest_file_sha256,'7ed657b1aa038ee679ff081f1a83c421a5eeb5fc7ea6b746e0f661079b69b319');
32
26
  assert.equal(release.source_predecessor.reference_server_sha256,'dfc303bb7dd2e8d01debac50fc43bb8644d00089bffdf2887e149497cff8b305');
33
27
  assert.equal(release.source_predecessor.reference_schemas_sha256,'f342345e34e48769dabaefe1b932f09d41e2e207b422f7794a15ee50ffa8f140');
34
- assert.equal(release.capabilities.full_tool_count,116);
28
+ assert.equal(release.capabilities.full_tool_count,117);
29
+ assert.equal(release.capabilities.desktop_bounded_semantic_wait,true);
35
30
  assert.equal(release.capabilities.commander_incremental_pdf_revisions,true);
36
31
  assert.equal(release.capabilities.commander_docx_header_footer_search,true);
37
32
  assert.equal(release.capabilities.commander_directory_read_fallback,true);
@@ -42,7 +37,6 @@ test('R48 0.15.24 successor binds exact active 0.15.23 parent and Commander diff
42
37
  assert.equal(provenance.parent_manifest_sha256,release.parent.manifest_sha256);
43
38
  assert.equal(provenance.parent_generation_manifest_sha256,release.parent.generation_manifest_sha256);
44
39
  assert.equal(provenance.source_predecessor_tarball_sha256,release.source_predecessor.tarball_sha256);
45
- assert.equal(matrix.full_regression_partition_proof.files,211);
46
- assert.equal(matrix.full_regression_partition_proof.fail,0);
47
- assert.equal(matrix.full_regression_partition_proof.task_receipt_sha256,'7711039e4807f6c2af02bbda897d0032b067e0a6631f789fd3bf801258160d3f');
40
+ assert.equal(matrix.predecessor_r48_full_regression_partition_proof.files,211);
41
+ assert.equal(matrix.predecessor_r48_full_regression_partition_proof.not_valid_as_r49_proof,true);
48
42
  });
@@ -0,0 +1,24 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { readFile } from 'node:fs/promises';
4
+
5
+ const artifact=new URL('../docs/R49-REMOTE-CONTROL-DONORS.json',import.meta.url);
6
+
7
+ test('R49 remote-control donor evidence pins all requested sources and records bounded native adoption',async()=>{
8
+ const value=JSON.parse(await readFile(artifact,'utf8'));
9
+ assert.equal(value.schema,'deadbyte.r49-remote-control-donors.v1');
10
+ assert.equal(value.donors.length,6);
11
+ assert.deepEqual(value.donors.map(item=>item.repository),[
12
+ 'https://github.com/shahidx0x/better-remote-commander',
13
+ 'https://github.com/Jennifer9911/open-remote-mcp',
14
+ 'https://github.com/Razewang/secure-host-mcp',
15
+ 'https://github.com/dddabtc/winremote-mcp',
16
+ 'https://github.com/getremcp/remcp',
17
+ 'https://github.com/trycua/cua'
18
+ ]);
19
+ for(const donor of value.donors)assert.match(donor.commit,/^[0-9a-f]{40}$/);
20
+ assert.equal(value.adopted_checkpoint.capability,'desktop.wait');
21
+ assert.equal(value.adopted_checkpoint.authority,'none');
22
+ assert.ok(value.adopted_checkpoint.properties.includes('no input dispatch and no action retry'));
23
+ assert.ok(value.explicit_non_adoptions.includes('generic shell or caller-selected executable authority'));
24
+ });
@@ -0,0 +1,33 @@
1
+ import assert from 'node:assert/strict';
2
+ import {readFile} from 'node:fs/promises';
3
+ import test from 'node:test';
4
+
5
+ const read = path => readFile(new URL(`../${path}`, import.meta.url), 'utf8');
6
+
7
+ test('R49 canonical Windows gate is successor-bound and preserves the R48 historical gate', async () => {
8
+ const [pkgText, gate, evidence, historical, deferred] = await Promise.all([
9
+ read('package.json'),
10
+ read('scripts/gate-windows-r49.ps1'),
11
+ read('scripts/windows-gate-evidence-r49.mjs'),
12
+ read('scripts/gate-windows-r48.ps1'),
13
+ read('scripts/deferred-slot-operation-r46.mjs')
14
+ ]);
15
+ const pkg = JSON.parse(pkgText);
16
+ assert.match(pkg.scripts['gate:windows'], /gate-windows-r49\.ps1$/);
17
+ assert.match(gate, /DEADBYTE 0\.15\.26 \/ R49 WINDOWS GATE: PASS/);
18
+ assert.match(gate, /r49-remote-control-donors\.test\.mjs/);
19
+ assert.match(gate, /desktop-runtime-r40\.test\.mjs/);
20
+ assert.match(gate, /manifest-final-verify/);
21
+ assert.match(evidence, /deadbyte\.r49-windows-gate\.v1/);
22
+ assert.match(evidence, /pkg\.version==='0\.15\.26'/);
23
+ assert.match(evidence, /release\.train==='R49'/);
24
+ assert.match(historical, /DEADBYTE 0\.15\.25 \/ R48 WINDOWS GATE: PASS/);
25
+ assert.match(deferred, /const expectedVersion=packageIdentity\.version/);
26
+ assert.match(deferred, /'--expected-version',expectedVersion/);
27
+ assert.match(deferred, /async function awaitHandoffCompletion/);
28
+ assert.match(deferred, /verifySlotUpdateEnvelope\(envelope,publicKey\)/);
29
+ assert.match(deferred, /active pointer does not match signed activation receipt/);
30
+ assert.match(deferred, /failure-receipt\.json/);
31
+ assert.match(deferred, /await awaitHandoffCompletion\(await runSlotUpdateCli/);
32
+ assert.doesNotMatch(deferred, /'--expected-version','0\.15\.5'/);
33
+ });
@@ -32,6 +32,15 @@ test('R29 remote gate accepts machine plane as an exact optional catalog dimensi
32
32
  assert.match(source, /if \(machine\) items\.push\(\.\.\.machineTools\)/);
33
33
  assert.match(source, /machine_runtime: machineRuntime/);
34
34
  });
35
+
36
+ test('R49 compact remote gate independently verifies signed machine ping', async () => {
37
+ const source = await readFile(sourcePath, 'utf8');
38
+ assert.match(source, /verifyMachinePingPublic/);
39
+ assert.match(source, /public_key_spki_base64/);
40
+ assert.match(source, /machine ping public Ed25519 verification failed/);
41
+ assert.match(source, /ping_signature_valid: true/);
42
+ assert.doesNotMatch(source, /ping_signature_valid: ping\.signature_valid === true/);
43
+ });
35
44
  test('R46 remote gate accepts seven-tool process supervision as one exact optional catalog dimension', async () => {
36
45
  const source = await readFile(sourcePath, 'utf8');
37
46
  assert.match(source, /const processTools = \[/);
@@ -145,13 +145,11 @@ test('installed stdio prefilter answers legacy startup probe and forwards split
145
145
  assert.deepEqual(hexLines, ['HEX:' + modern.toString('hex')]);
146
146
  });
147
147
 
148
- test('tunnel compatibility smoke preserves only base or base-plus-host modern catalogs', async () => {
148
+ test('tunnel compatibility smoke derives exact modern catalog and explicitly disables Host', async () => {
149
149
  const smoke = await readFile(fileURLToPath(new URL('../src/tunnel-stdio-compat-smoke.mjs', import.meta.url)), 'utf8');
150
- for (const name of ['contained_transform', 'evidence_verify', 'file_read', 'proof_execute', 'workspace_open']) assert.match(smoke, new RegExp(name));
151
- for (const name of ['host_exec', 'host_file_read', 'host_file_write']) assert.match(smoke, new RegExp(name));
152
- assert.match(smoke, /allowedCatalogs/);
153
- assert.match(smoke, /baseTools/);
154
- assert.match(smoke, /privilegedTools/);
150
+ assert.match(smoke, /expectedFullCatalogForEnv/);
151
+ assert.match(smoke, /assertExactCatalog/);
152
+ assert.match(smoke, /DEADBYTE_PRIVILEGED_POLICY: ''/);
155
153
  assert.doesNotMatch(smoke, /agent_task_/);
156
154
  });
157
155