deadbyte-mcp 0.15.1 → 0.15.2

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 (55) hide show
  1. package/MANIFEST.SHA256 +54 -44
  2. package/PROVENANCE.json +6 -5
  3. package/README.txt +36 -20
  4. package/RELEASE.json +24 -8
  5. package/SBOM.cdx.json +3 -3
  6. package/controller/README.TXT +2 -2
  7. package/controller/deadbyte-controller.ps1 +50 -2
  8. package/controller/deadbyte-process-policy.json +63 -1
  9. package/docs/ARCHITECTURE.md +3 -4
  10. package/package.json +9 -7
  11. package/scripts/deferred-slot-operation-r46.mjs +126 -0
  12. package/scripts/final-closure-r46.mjs +98 -0
  13. package/scripts/final-closure-verify-r46.mjs +119 -0
  14. package/scripts/full-regression-r46.mjs +20 -0
  15. package/scripts/gate-windows-r46.ps1 +56 -0
  16. package/scripts/refresh-process-policy.mjs +64 -7
  17. package/scripts/release-parity-r46.mjs +187 -0
  18. package/scripts/windows-gate-evidence-r46.mjs +110 -0
  19. package/src/capability-ledger.mjs +1 -0
  20. package/src/compact-gateway-mcp-tools.mjs +7 -5
  21. package/src/deadbyte-cli.mjs +7 -3
  22. package/src/machine-fs-mcp-tools.mjs +3 -3
  23. package/src/machine-fs-output-contracts.mjs +1 -1
  24. package/src/machine-fs-read-worker.mjs +46 -0
  25. package/src/machine-fs.mjs +63 -10
  26. package/src/mcp-server.mjs +4 -0
  27. package/src/mcp-smoke-client.mjs +4 -1
  28. package/src/observation-runtime.mjs +25 -4
  29. package/src/process-mcp-tools.mjs +18 -5
  30. package/src/process-output-contracts.mjs +20 -3
  31. package/src/process-policy.mjs +3 -1
  32. package/src/process-runtime.mjs +99 -19
  33. package/src/process-smoke-client.mjs +67 -22
  34. package/src/release-generation.mjs +22 -3
  35. package/src/remote-device-r44.mjs +53 -15
  36. package/src/remote-mcp-smoke-client.mjs +1 -1
  37. package/src/stdio-console-guard.mjs +24 -0
  38. package/src/version.mjs +1 -1
  39. package/test/cli-entrypoint.test.mjs +3 -3
  40. package/test/compact-gateway-r36.test.mjs +28 -0
  41. package/test/core.test.mjs +1 -1
  42. package/test/full-max-catalog-r46.test.mjs +92 -0
  43. package/test/machine-fs-mcp-tools.test.mjs +4 -1
  44. package/test/machine-fs-runtime.test.mjs +18 -2
  45. package/test/observation-runtime.test.mjs +29 -2
  46. package/test/process-mcp-tools.test.mjs +23 -5
  47. package/test/process-policy-refresh.test.mjs +87 -10
  48. package/test/process-runtime.test.mjs +111 -1
  49. package/test/process-supervision.test.mjs +4 -2
  50. package/test/production-docs.test.mjs +3 -3
  51. package/test/r33-finalization.test.mjs +3 -3
  52. package/test/release-generation.test.mjs +25 -11
  53. package/test/release-version.test.mjs +99 -44
  54. package/test/remote-device-r44.test.mjs +75 -0
  55. package/test/remote-r24-catalog.test.mjs +2 -2
@@ -102,3 +102,78 @@ test('R44 remote state corruption fails closed',async()=>{
102
102
  await assert.rejects(createRemoteDevicePlaneR44({stateDir:root,relay:new FakeRelay(),authorizeCapability:async()=>true}),/state JSON invalid/);
103
103
  }finally{await rm(root,{recursive:true,force:true});}
104
104
  });
105
+
106
+
107
+ test('R46 remote readiness probe retries only the idempotent probe and remains bounded by timeout',async()=>{
108
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-probe-timeout-'));
109
+ const key=deviceKey();
110
+ let attempts=0;
111
+ const relay={
112
+ requests:[],
113
+ async probe(value){
114
+ attempts+=1;
115
+ if(attempts===1) return await new Promise(()=>{});
116
+ return {device_id:value.device_id,epoch:value.epoch,nonce:value.nonce,ready:true};
117
+ },
118
+ async request(value){this.requests.push(value);return {ack:'accepted',request_id:value.request_id,terminal:{status:'completed',result_sha256:'a'.repeat(64)}};}
119
+ };
120
+ try{
121
+ const plane=await createRemoteDevicePlaneR44({
122
+ stateDir:root,relay,authorizeCapability:async()=>true,
123
+ relayTimeoutMs:100,probeRetries:1,reachableTtlMs:5000
124
+ });
125
+ await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
126
+ await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'retry-c'});
127
+ const ready=await plane.probe({deviceId:key.deviceId,epoch:1});
128
+ assert.equal(attempts,2);
129
+ assert.equal(ready.reachable,true);
130
+ }finally{await rm(root,{recursive:true,force:true});}
131
+ });
132
+
133
+ test('R46 remote reachability expires after the bounded probe freshness window',async()=>{
134
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-stale-'));
135
+ const relay=new FakeRelay(),key=deviceKey();
136
+ try{
137
+ const plane=await createRemoteDevicePlaneR44({
138
+ stateDir:root,relay,authorizeCapability:async()=>true,
139
+ relayTimeoutMs:1000,probeRetries:0,reachableTtlMs:1000
140
+ });
141
+ await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
142
+ await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'stale-c'});
143
+ await plane.probe({deviceId:key.deviceId,epoch:1});
144
+ assert.equal((await plane.status({deviceId:key.deviceId})).reachable,true);
145
+ await new Promise(resolve=>setTimeout(resolve,1100));
146
+ assert.equal((await plane.status({deviceId:key.deviceId})).reachable,false);
147
+ await assert.rejects(
148
+ plane.dispatch({deviceId:key.deviceId,epoch:1,capabilityId:'machine.status',payload:{},requestId:'8'.repeat(64)}),
149
+ /not reachable|stale/i
150
+ );
151
+ assert.equal(relay.requests.length,0);
152
+ }finally{await rm(root,{recursive:true,force:true});}
153
+ });
154
+
155
+ test('R46 remote dispatch timeout is not retried and downgrades reachability',async()=>{
156
+ const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-r46-remote-dispatch-timeout-'));
157
+ const key=deviceKey();
158
+ let requestCount=0;
159
+ const relay={
160
+ async probe(value){return {device_id:value.device_id,epoch:value.epoch,nonce:value.nonce,ready:true};},
161
+ async request(){requestCount+=1;return await new Promise(()=>{});}
162
+ };
163
+ try{
164
+ const plane=await createRemoteDevicePlaneR44({
165
+ stateDir:root,relay,authorizeCapability:async()=>true,
166
+ relayTimeoutMs:100,probeRetries:0,reachableTtlMs:5000
167
+ });
168
+ await plane.pair({publicKeySpkiBase64:key.spki,displayName:'lab'});
169
+ await plane.reportOnline({deviceId:key.deviceId,epoch:1,connectionId:'dispatch-c'});
170
+ await plane.probe({deviceId:key.deviceId,epoch:1});
171
+ const result=await plane.dispatch({
172
+ deviceId:key.deviceId,epoch:1,capabilityId:'coding.file_read',payload:{path:'README.md'},requestId:'9'.repeat(64)
173
+ });
174
+ assert.equal(result.state,'failed');
175
+ assert.equal(result.error_code,'transport_error');
176
+ assert.equal(requestCount,1,'side-effecting dispatch must never auto-retry');
177
+ assert.equal((await plane.status({deviceId:key.deviceId})).reachable,false);
178
+ }finally{await rm(root,{recursive:true,force:true});}
179
+ });
@@ -32,10 +32,10 @@ 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
- test('R32 remote gate accepts six-tool process supervision as one exact optional catalog dimension', async () => {
35
+ test('R46 remote gate accepts seven-tool process supervision as one exact optional catalog dimension', async () => {
36
36
  const source = await readFile(sourcePath, 'utf8');
37
37
  assert.match(source, /const processTools = \[/);
38
- for (const name of ['process_session_start','process_session_read','process_session_status','process_session_list','process_session_terminate','process_session_action']) {
38
+ for (const name of ['process_session_start','process_session_read','process_session_status','process_session_list','process_session_terminate','process_session_action','process_session_write']) {
39
39
  assert.match(source, new RegExp(`'${name}'`));
40
40
  }
41
41
  assert.match(source, /for \(const processPlane of \[false, true\]\)/);