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
@@ -1,5 +1,6 @@
1
1
  import { canonicalJson } from './canonical-json.mjs';
2
2
  import { sanitizeAuditArgs } from './tool-audit.mjs';
3
+ import { remoteDisplayText, REMOTE_DISPLAY_MODES } from './remote-console.mjs';
3
4
 
4
5
  const SAFE_ARG_KEYS=Object.freeze(['root_id','path','pattern','command_id','profile_id','session_id','goal_id','task_id','step_id','mode']);
5
6
  const LIFECYCLE=Object.freeze({
@@ -11,6 +12,15 @@ const LIFECYCLE=Object.freeze({
11
12
  ready:'✅ [READY] DEADBYTE MCP online',
12
13
  cleanup:'🔐 [AUTH] Revoking session authority...'
13
14
  });
15
+ const LIFECYCLE_ASCII=Object.freeze({
16
+ device_start:'[DEVICE] Starting DEADBYTE MCP...',
17
+ bridge_connected:'[BRIDGE] Local bridge connected',
18
+ cloud_connected:'[CLOUD] Remote MCP connected',
19
+ session_new:'[SESSION] New foreground session',
20
+ session_restored:'[SESSION] Previous result stream replayed',
21
+ ready:'[READY] DEADBYTE MCP online',
22
+ cleanup:'[AUTH] Revoking session authority...'
23
+ });
14
24
 
15
25
  function safeAtom(value){
16
26
  if(typeof value==='string'){
@@ -34,22 +44,99 @@ function summarizeArgs(args){
34
44
  }
35
45
 
36
46
  const TOOL_COLUMN_WIDTH=32;
47
+ const DISPLAY_UTC_OFFSET_MINUTES=7*60;
48
+ const DISPLAY_UTC_OFFSET_LABEL='+07:00';
49
+ const HEARTBEAT_TOOLS=new Set(['machine_ping','machine_status','machine_system_status','machine_list']);
50
+ const TOOL_ICONS=Object.freeze({read:'📖',write:'📝',edit:'✏️',run:'🏃',verify:'🧾',search:'🔍',heartbeat:'📡',desktop:'🖥️',autonomous:'🤖',process:'⚙️',generic:'•'});
51
+ const TOOL_ICONS_ASCII=Object.freeze({read:'R',write:'W',edit:'E',run:'>',verify:'V',search:'S',heartbeat:'H',desktop:'D',autonomous:'A',process:'P',generic:'*'});
52
+ const START_VISIBLE_PATTERNS=[/(?:^|_)file_write$/,/text_replace$/,/symbol_replace$/,/native_diff_(?:apply|preview)$/,
53
+ /(?:command|benchmark)_run$/,/task_run$/,/goal_run$/,/goal_submit$/,/goal_approve$/,/process_session_(?:start|action|terminate)$/,/^desktop_action$/];
37
54
 
38
- function eventTimestamp(event,clock){
39
- for(const value of [event?.created_at_utc,event?.observed_at_utc]){
55
+ export function truncateUtf8(value,maxBytes,{ellipsis='…'}={}){
56
+ if(typeof value!=='string'||!Number.isInteger(maxBytes)||maxBytes<1) return '';
57
+ const bytes=new TextEncoder().encode(value);
58
+ if(bytes.length<=maxBytes) return value;
59
+ const suffix=new TextEncoder().encode(ellipsis);
60
+ const budget=Math.max(0,maxBytes-suffix.length);
61
+ let end=Math.min(budget,bytes.length);
62
+ while(end>0&&(bytes[end]&0xc0)===0x80) end--;
63
+ return new TextDecoder('utf-8',{fatal:false}).decode(bytes.subarray(0,end))+(suffix.length<=maxBytes?ellipsis:'');
64
+ }
65
+ function clipped(value,max=72){
66
+ if(typeof value!=='string') return '';
67
+ const one=value.replace(/[\r\n\t]+/g,' ').replace(/\s{2,}/g,' ').trim();
68
+ return truncateUtf8(one,max);
69
+ }
70
+ function shortValue(value,max=12){
71
+ if(typeof value!=='string'||!value) return '';
72
+ return value.length<=max?value:value.slice(0,max)+'…';
73
+ }
74
+ function payloadByteCount(value){
75
+ return value&&typeof value==='object'&&value.redacted===true&&Number.isFinite(Number(value.byte_count))?Number(value.byte_count):null;
76
+ }
77
+ function rootPath(args){
78
+ const root=safeAtom(args?.root_id);const p=safeAtom(args?.path);
79
+ if(root&&p) return root+':'+p;
80
+ return root||p||'';
81
+ }
82
+ export function summarizeLiveToolArgs(tool,rawArgs){
83
+ const args=sanitizeAuditArgs(rawArgs??{});const where=rootPath(args);
84
+ if(/(?:file_read|files_read)$/.test(tool)) return where;
85
+ if(/file_write$/.test(tool)){const bytes=payloadByteCount(args.content);return [where,bytes!==null?'('+bytes+'B)':''].filter(Boolean).join(' ');}
86
+ if(/text_replace$|symbol_replace$/.test(tool)){const bytes=payloadByteCount(args.new_string);return [where,bytes!==null?'('+bytes+'B new)':''].filter(Boolean).join(' ');}
87
+ if(/coding_tree$/.test(tool)) return where;
88
+ if(/coding_(?:search|inspect)$/.test(tool)) return [where,args.pattern?'\"'+clipped(String(args.pattern),36)+'\"':'',args.op?String(args.op):''].filter(Boolean).join(' ');
89
+ if(/(?:command|benchmark)_run$/.test(tool)) return [safeAtom(args.root_id),safeAtom(args.command_id),safeAtom(args.script_path)].filter(Boolean).join(' ');
90
+ if(/^machine_(?:ping|status|system_status|list)$/.test(tool)) return safeAtom(args.nonce)?'nonce='+shortValue(String(args.nonce),24):'';
91
+ if(/^process_session/.test(tool)) return [safeAtom(args.profile_id),shortValue(safeAtom(args.session_id)||'',12),safeAtom(args.op)].filter(Boolean).join(' ');
92
+ if(/^desktop_/.test(tool)) return [shortValue(safeAtom(args.frame_id)||'',10),shortValue(safeAtom(args.target_id)||'',10),safeAtom(args.op)].filter(Boolean).join(' ');
93
+ if(/^autonomous_/.test(tool)) return [shortValue(safeAtom(args.goal_id)||'',12),safeAtom(args.step_id)].filter(Boolean).join(' ');
94
+ return summarizeArgs(args).trim();
95
+ }
96
+ function categoryForTool(tool){
97
+ if(/^desktop_/.test(tool)) return 'desktop';
98
+ if(/^autonomous_/.test(tool)) return 'autonomous';
99
+ if(HEARTBEAT_TOOLS.has(tool)) return 'heartbeat';
100
+ if(/(?:receipt_verify|evidence_verify|goal_verify|task_verify|audit|release_gate|native_diff_verify)/.test(tool)) return 'verify';
101
+ if(/(?:search|inspect|symbol_(?:definition|references|implementations|outline|diagnostics)|_stat$|_tree$)/.test(tool)) return 'search';
102
+ if(/(?:file_read|files_read|machine_fs_read|process_session_read)/.test(tool)) return 'read';
103
+ if(/(?:file_write|machine_fs_write|mkdir|move|delete)/.test(tool)) return 'write';
104
+ if(/(?:replace|edit_exact|native_diff_apply)/.test(tool)) return 'edit';
105
+ if(/(?:command_run|benchmark_run|task_run|goal_run|process_session_(?:start|action|terminate))/.test(tool)) return 'run';
106
+ if(/^process_/.test(tool)) return 'process';
107
+ return 'generic';
108
+ }
109
+ function iconForTool(tool,displayMode='unicode'){
110
+ const icons=displayMode==='ascii'?TOOL_ICONS_ASCII:TOOL_ICONS;
111
+ return icons[categoryForTool(tool)]??icons.generic;
112
+ }
113
+ function visibleStart(tool){return START_VISIBLE_PATTERNS.some(pattern=>pattern.test(tool));}
114
+
115
+ function displayTimestamp(ms){
116
+ const shifted=new Date(ms+DISPLAY_UTC_OFFSET_MINUTES*60*1000).toISOString();
117
+ return `${shifted.slice(0,-1)}${DISPLAY_UTC_OFFSET_LABEL}`;
118
+ }
119
+
120
+ function eventMs(event,clock){
121
+ for(const value of [event?.ts,event?.created_at_utc,event?.observed_at_utc]){
40
122
  const parsed=Date.parse(value);
41
- if(typeof value==='string'&&Number.isFinite(parsed)) return new Date(parsed).toISOString();
123
+ if(typeof value==='string'&&Number.isFinite(parsed)) return parsed;
42
124
  }
43
125
  const value=Number(clock());
44
- return new Date(Number.isFinite(value)?value:Date.now()).toISOString();
126
+ return Number.isFinite(value)?value:Date.now();
127
+ }
128
+ function eventTimestamp(event,clock){return displayTimestamp(eventMs(event,clock));}
129
+ function displayClock(ms){
130
+ const shifted=new Date(ms+DISPLAY_UTC_OFFSET_MINUTES*60*1000).toISOString();
131
+ return shifted.slice(11,23);
45
132
  }
46
133
 
47
- export function formatRemoteToolCall(event,{clock=()=>Date.now()}={}){
134
+ export function formatRemoteToolCall(event,{clock=()=>Date.now(),displayMode='unicode'}={}){
48
135
  if(!event||typeof event!=='object'||Array.isArray(event)||event.event_type!=='tool.request'||
49
136
  typeof event.tool!=='string'||!event.tool) return null;
50
137
  if(typeof clock!=='function') throw new Error('remote tool-call clock must be a function');
51
138
  const args=sanitizeAuditArgs(event.args??{});
52
- return `${eventTimestamp(event,clock)} | ${event.tool.padEnd(TOOL_COLUMN_WIDTH)} | Arguments: ${canonicalJson(args)}`;
139
+ return remoteDisplayText(`${eventTimestamp(event,clock)} | ${event.tool.padEnd(TOOL_COLUMN_WIDTH)} | Arguments: ${canonicalJson(args)}`,displayMode);
53
140
  }
54
141
 
55
142
  function formatDuration(ms){
@@ -70,9 +157,10 @@ export function formatCompactAuditEvent(event){
70
157
  return null;
71
158
  }
72
159
 
73
- export function formatRemoteLifecycle(kind){
160
+ export function formatRemoteLifecycle(kind,{displayMode='unicode'}={}){
74
161
  if(typeof kind!=='string'||!Object.hasOwn(LIFECYCLE,kind)) throw new Error(`unknown remote lifecycle '${String(kind)}'`);
75
- return LIFECYCLE[kind];
162
+ if(!REMOTE_DISPLAY_MODES.includes(displayMode)) throw new Error('remote display mode invalid');
163
+ return displayMode==='ascii'?LIFECYCLE_ASCII[kind]:LIFECYCLE[kind];
76
164
  }
77
165
 
78
166
  export function createLiveActivityTracker(){
@@ -102,56 +190,138 @@ function shortSpanId(requestId){
102
190
  return typeof requestId==='string'&&requestId.length?requestId.slice(0,8):'????????';
103
191
  }
104
192
 
105
- export function createLiveTimelineTracker({clock=()=>Date.now()}={}){
193
+ export function createLiveTimelineTracker({clock=()=>Date.now(),verbose=false,heartbeatBurstLimit=10,heartbeatWindowMs=3000,displayMode='unicode'}={}){
106
194
  if(typeof clock!=='function') throw new Error('live timeline clock must be a function');
195
+ if(!REMOTE_DISPLAY_MODES.includes(displayMode)) throw new Error('remote display mode invalid');
196
+ if(!Number.isInteger(heartbeatBurstLimit)||heartbeatBurstLimit<2||heartbeatBurstLimit>100) throw new Error('heartbeatBurstLimit invalid');
197
+ if(!Number.isInteger(heartbeatWindowMs)||heartbeatWindowMs<250||heartbeatWindowMs>60000) throw new Error('heartbeatWindowMs invalid');
107
198
  const pending=new Map();
108
199
  const completed=new Set();
109
- return Object.freeze({
110
- observe(event){
111
- if(!event||typeof event!=='object'||Array.isArray(event)) return null;
112
- const requestId=typeof event.request_id==='string'&&event.request_id?event.request_id:null;
113
- const tool=typeof event.tool==='string'&&event.tool?event.tool:null;
114
- if(event.event_type==='tool.request'&&requestId&&tool){
115
- if(pending.has(requestId)||completed.has(requestId)) return null;
116
- pending.set(requestId,{request_id:requestId,tool,started_at_ms:clock()});
117
- return formatRemoteToolCall(event,{clock});
118
- }
119
- if(event.event_type==='tool.result'&&requestId&&tool){
120
- if(completed.has(requestId)) return null;
121
- const span=pending.get(requestId)??null;
122
- pending.delete(requestId);completed.add(requestId);
123
- const error=event.outcome?.is_error===true;
124
- const duration=Number.isFinite(Number(event.outcome?.duration_ms))
125
- ? formatDuration(event.outcome.duration_ms)
126
- : span?formatDuration(Math.max(0,clock()-span.started_at_ms)):'';
127
- const marker=span?(error?'':''):'';
128
- const status=error?'ERR':'OK ';
129
- const suffix=span?'':' (request before live window)';
130
- return `${marker} [${shortSpanId(requestId)}] ${status} ${tool}${duration?` ${duration}`:''}${suffix}`;
131
- }
200
+ const toolCounts=new Map();
201
+ let resultCount=0,errorCount=0,totalDurationMs=0,burst=null,foldedHeartbeatLines=0;
202
+
203
+ function eventPrefix(event,sequence){
204
+ const seq=Number.isSafeInteger(sequence)&&sequence>0?'#'+sequence+' ':'';
205
+ return iconForTool(event.tool,displayMode)+' '+displayClock(eventMs(event,clock))+' '+seq+'['+shortSpanId(event.request_id)+'] '+event.tool;
206
+ }
207
+ function resultLine(event,span,sequence){
208
+ const error=event.outcome?.is_error===true;
209
+ const unknown=event.outcome?.side_effect_state==='unknown';
210
+ const duration=Number.isFinite(Number(event.outcome?.duration_ms))
211
+ ?formatDuration(event.outcome.duration_ms)
212
+ :span?formatDuration(Math.max(0,clock()-span.started_at_ms)):'';
213
+ const summary=span?.summary||'';
214
+ const rawReason=typeof event.outcome?.reason==='string'&&event.outcome.reason?event.outcome.reason:
215
+ (unknown&&typeof event.outcome?.recovery?.reason==='string'?event.outcome.recovery.reason:'');
216
+ const reason=rawReason?clipped(rawReason,180):(unknown?'terminal result unavailable; inspect state before retry':'');
217
+ const marker=unknown?'OUTCOME_UNKNOWN':error?(displayMode==='ascii'?'ERR':'✗'):(displayMode==='ascii'?'OK':'✓');
218
+ return remoteDisplayText(eventPrefix(event,sequence)+(summary?' '+summary:'')+(duration?' '+duration:'')+' '+marker+(reason?' — '+reason:''),displayMode);
219
+ }
220
+ function burstLine(value){
221
+ if(!value) return null;
222
+ const avg=value.count?value.total_ms/value.count:0;
223
+ const seq=Number.isSafeInteger(value.last_sequence)&&value.last_sequence>0?'#'+value.last_sequence+' ':'';
224
+ const startClock=displayClock(value.first_ms);
225
+ const endClock=displayClock(value.last_ms);
226
+ const range=value.first_ms===value.last_ms?endClock:startClock.slice(0,8)+'–'+endClock.slice(0,8);
227
+ if(value.count>1) foldedHeartbeatLines+=value.count-1;
228
+ const marker=displayMode==='ascii'?'OK':'✓';
229
+ return remoteDisplayText(iconForTool(value.tool,displayMode)+' '+range+' '+seq+value.tool+' ×'+value.count+' avg '+formatDuration(avg)+' '+marker,displayMode);
230
+ }
231
+ function flushBurst(){
232
+ const line=burstLine(burst);
233
+ burst=null;
234
+ return line;
235
+ }
236
+ function addStats(event){
237
+ resultCount++;
238
+ toolCounts.set(event.tool,(toolCounts.get(event.tool)??0)+1);
239
+ const duration=Number(event.outcome?.duration_ms);
240
+ if(Number.isFinite(duration)&&duration>=0) totalDurationMs+=duration;
241
+ if(event.outcome?.is_error===true) errorCount++;
242
+ }
243
+ function observe(event,{sequence=null}={}){
244
+ if(!event||typeof event!=='object'||Array.isArray(event)) return null;
245
+ const requestId=typeof event.request_id==='string'&&event.request_id?event.request_id:null;
246
+ const tool=typeof event.tool==='string'&&event.tool?event.tool:null;
247
+ if(event.event_type==='tool.request'&&requestId&&tool){
248
+ if(pending.has(requestId)||completed.has(requestId)) return null;
249
+ const summary=summarizeLiveToolArgs(tool,event.args??{});
250
+ pending.set(requestId,{request_id:requestId,tool,summary,started_at_ms:clock()});
251
+ if(verbose) return formatRemoteToolCall(event,{clock,displayMode});
252
+ if(visibleStart(tool)) return eventPrefix(event,sequence)+(summary?' '+summary:'')+' …';
132
253
  return null;
133
- },
134
- pending(){return [...pending.values()].map(({request_id,tool})=>({request_id,tool}));},
135
- reconcileInterrupted(reason='session_end'){
136
- const suffix=reason==='recovery'?'recovery ended before terminal result':
137
- reason==='session_end'?'session ended before terminal result':'stream ended before terminal result';
138
- const lines=[...pending.values()].map(item=>`⚠ [${shortSpanId(item.request_id)}] INTERRUPTED ${item.tool} — ${suffix}`);
139
- pending.clear();
140
- return lines;
141
254
  }
255
+ if(event.event_type==='tool.result'&&requestId&&tool){
256
+ if(completed.has(requestId)) return null;
257
+ const span=pending.get(requestId)??null;
258
+ pending.delete(requestId);
259
+ completed.add(requestId);
260
+ addStats(event);
261
+ const error=event.outcome?.is_error===true;
262
+ const nowMs=eventMs(event,clock);
263
+ if(HEARTBEAT_TOOLS.has(tool)&&!error){
264
+ const duration=Number(event.outcome?.duration_ms);
265
+ if(burst&&burst.tool===tool&&nowMs-burst.last_ms<=heartbeatWindowMs){
266
+ burst.count++;
267
+ burst.last_ms=nowMs;
268
+ burst.last_sequence=sequence;
269
+ if(Number.isFinite(duration)&&duration>=0) burst.total_ms+=duration;
270
+ }else{
271
+ const prior=flushBurst();
272
+ burst={tool,count:1,total_ms:Number.isFinite(duration)&&duration>=0?duration:0,
273
+ first_ms:nowMs,last_ms:nowMs,first_sequence:sequence,last_sequence:sequence};
274
+ return prior;
275
+ }
276
+ if(burst.count>=heartbeatBurstLimit) return flushBurst();
277
+ return null;
278
+ }
279
+ const lines=[];
280
+ const prior=flushBurst();
281
+ if(prior) lines.push(prior);
282
+ lines.push(resultLine(event,span,sequence));
283
+ return lines.length===1?lines[0]:lines;
284
+ }
285
+ return null;
286
+ }
287
+ function reconcileInterrupted(reason='session_end'){
288
+ const suffix=reason==='recovery'?'recovery ended before terminal result':
289
+ reason==='session_end'?'session ended before terminal result':'stream ended before terminal result';
290
+ const lines=[];
291
+ const folded=flushBurst();
292
+ if(folded) lines.push(folded);
293
+ for(const item of pending.values()) lines.push(remoteDisplayText((displayMode==='ascii'?'[WARN]':'⚠')+' ['+shortSpanId(item.request_id)+'] OUTCOME_UNKNOWN '+item.tool+' — '+suffix+'; inspect state before retry',displayMode));
294
+ pending.clear();
295
+ return lines;
296
+ }
297
+ function summary(){
298
+ const top=[...toolCounts.entries()].sort((a,b)=>b[1]-a[1]||a[0].localeCompare(b[0])).slice(0,3)
299
+ .map(([tool,count])=>tool+'×'+count).join(', ');
300
+ return remoteDisplayText((displayMode==='ascii'?'[SUMMARY]':'📊 [SUMMARY]')+' '+resultCount+' calls | '+errorCount+' error'+(errorCount===1?'':'s')+
301
+ ' | tool time '+(formatDuration(totalDurationMs)||'0ms')+
302
+ (foldedHeartbeatLines?' | folded '+foldedHeartbeatLines+' heartbeat lines':'')+
303
+ (top?' | top: '+top:''),displayMode);
304
+ }
305
+ return Object.freeze({
306
+ observe,
307
+ pending(){return [...pending.values()].map(({request_id,tool})=>({request_id,tool}));},
308
+ reconcileInterrupted,
309
+ summary
142
310
  });
143
311
  }
144
312
 
145
-
146
- export function formatRuntimeDiagnosticLine(file,line){
313
+ export function formatRuntimeDiagnosticLine(file,line,{verbose=false,displayMode='unicode'}={}){
147
314
  if(typeof file!=='string'||typeof line!=='string'||!line) return null;
148
315
  const label=file.split(/[\\/]/).at(-1).replace(/\.log$/i,'').toUpperCase();
149
316
  const input=line.match(/\[TOOL IN \]\s+\S+\s+#\d+\s+([A-Za-z0-9_.-]+)/);
150
- if(input) return `[${label}] IN ${input[1]}`;
317
+ if(input) return verbose?remoteDisplayText('['+label+'.DEBUG] IN '+input[1],displayMode):null;
151
318
  const output=line.match(/\[TOOL OUT\]\s+\S+\s+#\d+\s+([A-Za-z0-9_.-]+)/);
152
319
  if(output){
153
- if(/"is_error"\s*:\s*true/.test(line)) return `[${label}] ERR ${output[1]}`;
154
- return `[${label}] OUT ${output[1]}`;
320
+ if(!verbose) return null;
321
+ if(/"is_error"\s*:\s*true/.test(line)) return remoteDisplayText('['+label+'.DEBUG] ERR '+output[1],displayMode);
322
+ return remoteDisplayText('['+label+'.DEBUG] OUT '+output[1],displayMode);
155
323
  }
324
+ const compact=line.match(/^\[TOOL\]\s+(\S+)\s+#(\d+)\s+(✓|✗|OK|ERR)\s+([A-Za-z0-9_.-]+)\s+([^\s]+)(?:\s+—\s+(.+))?$/u);
325
+ if(compact) return verbose?remoteDisplayText('['+label+'.DEBUG] #'+compact[2]+' '+compact[3]+' '+compact[4]+' '+compact[5]+(compact[6]?' — '+compact[6]:''),displayMode):null;
156
326
  return null;
157
327
  }
@@ -0,0 +1,70 @@
1
+ import { randomBytes } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Client,StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
7
+ import { loadDesktopPolicy } from './desktop-policy-r40.mjs';
8
+ import { verifyDesktopReceiptObject } from './desktop-runtime-r40.mjs';
9
+ import { loadPublicVerifyKey } from './trust.mjs';
10
+
11
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
12
+ function gateway(result,label){
13
+ if(result.isError)throw new Error(label+' returned error: '+JSON.stringify(result.structuredContent??result.content));
14
+ const value=result.structuredContent;
15
+ if(!value||value.status!=='ok'||!value.result)throw new Error(label+' malformed');
16
+ return value.result;
17
+ }
18
+ function predispatchForegroundChanged(result){
19
+ if(result?.isError!==true)return false;
20
+ const value=result.structuredContent;
21
+ return value?.status==='denied'&&value?.op==='action'&&value?.error==='desktop foreground window changed before action';
22
+ }
23
+ async function verify(policy,key,id,sha,kind){
24
+ const receipt=JSON.parse(await readFile(path.join(policy.evidence_dir,id+'.json'),'utf8'));
25
+ const proof=verifyDesktopReceiptObject(receipt,{policySha256:policy.policy_sha256,publicKey:key.publicKey,keyId:key.keyId});
26
+ if(!proof.ok||proof.receipt_sha256!==sha||proof.kind!==kind)throw new Error('desktop smoke receipt mismatch '+kind);
27
+ }
28
+ export async function runR40DesktopGuardedSmoke(endpointText){
29
+ const endpoint=new URL(endpointText);if(endpoint.protocol!=='https:')throw new Error('R40 Desktop smoke requires HTTPS');
30
+ const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
31
+ const policy=await loadDesktopPolicy(path.join(pointer.generation_root,'desktop-policy.json'));
32
+ const key=await loadPublicVerifyKey(path.join(stateRoot,'trust','ed25519-public.pem'));
33
+ const client=new Client({name:'deadbyte-r40-desktop-guarded-smoke',version:'0.12.0'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
34
+ const transport=new StreamableHTTPClientTransport(endpoint);
35
+ try{
36
+ await client.connect(transport);
37
+ const status=gateway(await client.callTool({name:'desktop_control',arguments:{op:'status'}}),'desktop status');
38
+ if(status.armed!==true||!status.action_kinds?.includes('key_chord'))throw new Error('Desktop smoke requires separately armed key_chord authority');
39
+ const maxPredispatchAttempts=3;
40
+ let action=null;
41
+ let observationReceiptsVerified=0;
42
+ let predispatchRetryCount=0;
43
+ for(let attempt=1;attempt<=maxPredispatchAttempts;attempt+=1){
44
+ const observed=gateway(await client.callTool({name:'desktop_control',arguments:{op:'observe',preview:false}}),'desktop observe');
45
+ await verify(policy,key,observed.receipt_id,observed.receipt_sha256,'desktop_observation');
46
+ observationReceiptsVerified+=1;
47
+ const actionResult=await client.callTool({name:'desktop_control',arguments:{
48
+ op:'action',intent_id:randomBytes(32).toString('hex'),kind:'key_chord',expected_frame_id:observed.frame.frame_id,
49
+ target_id:null,point:null,scroll_delta:null,key_chord:['SHIFT'],text:null
50
+ }});
51
+ if(predispatchForegroundChanged(actionResult)){
52
+ if(attempt===maxPredispatchAttempts)throw new Error('Desktop guarded smoke foreground remained unstable before dispatch');
53
+ predispatchRetryCount+=1;
54
+ continue;
55
+ }
56
+ action=gateway(actionResult,'desktop key_chord');
57
+ break;
58
+ }
59
+ if(!action||action.injected!==true||action.side_effect_state!=='confirmed_injected'||action.action_summary?.kind!=='key_chord')throw new Error('Desktop guarded smoke input not confirmed');
60
+ await verify(policy,key,action.started_receipt_id,action.started_receipt_sha256,'desktop_action_started');
61
+ await verify(policy,key,action.post_receipt_id,action.post_receipt_sha256,'desktop_post_observation');
62
+ await verify(policy,key,action.receipt_id,action.receipt_sha256,'desktop_action_completed');
63
+ return {status:'passed',kind:'key_chord',keys:['SHIFT'],native_injected:true,replay_performed:false,
64
+ predispatch_retry_count:predispatchRetryCount,observation_receipts_verified:observationReceiptsVerified,
65
+ observation_receipt_verified:true,action_receipts_verified:3,action_chain_sha256:action.action_chain?.chain_sha256??null,
66
+ effect_id:action.effect_id,receipt_id:action.receipt_id,receipt_sha256:action.receipt_sha256};
67
+ }finally{await client.close().catch(()=>{});}
68
+ }
69
+ if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){const endpoint=process.argv[2];if(!endpoint)throw new Error('usage: node src/remote-mcp-desktop-r40-smoke-client.mjs https://host/mcp/path');
70
+ runR40DesktopGuardedSmoke(endpoint).then(v=>console.log(JSON.stringify(v,null,2))).catch(e=>{console.error(e instanceof Error?e.stack:String(e));process.exitCode=1;});}
@@ -0,0 +1,200 @@
1
+ import { createHash, randomBytes } from 'node:crypto';
2
+ import { readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+ import { Client, StreamableHTTPClientTransport } from '@modelcontextprotocol/client';
7
+ import { R34_EXPECTED_TOOLS } from './remote-mcp-r34-parity-client.mjs';
8
+ import { loadCodingPolicy } from './coding-plane.mjs';
9
+ import { verifyMachineFsReceiptFile } from './machine-fs.mjs';
10
+ import { verifyObservationReceiptFile } from './observation-runtime.mjs';
11
+ import { loadDesktopPolicy } from './desktop-policy-r40.mjs';
12
+ import { verifyDesktopReceiptObject } from './desktop-runtime-r40.mjs';
13
+ import { loadPublicVerifyKey } from './trust.mjs';
14
+
15
+ export const R40_EXPECTED_TOOLS=Object.freeze([...new Set([
16
+ ...R34_EXPECTED_TOOLS,
17
+ 'coding_symbol_diagnostics','coding_symbol_implementations','coding_symbol_rename_preview',
18
+ 'desktop_status','desktop_observe','desktop_target','desktop_action'
19
+ ])].sort());
20
+ if(R40_EXPECTED_TOOLS.length !== 80) throw new Error(`R40 full catalog identity mismatch: ${R40_EXPECTED_TOOLS.length}`);
21
+ export const R40_COMPACT_GATEWAYS=Object.freeze(['capability_manifest','coding_inspect','machine_fs','machine_observe','process_session','desktop_control'].sort());
22
+ export const R40_COMPACT_TOOL_LIMIT=42;
23
+
24
+ const here=path.dirname(fileURLToPath(import.meta.url));
25
+ const repoRoot=path.resolve(here,'..');
26
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
27
+ const verifyKeyPath=path.join(stateRoot,'trust','ed25519-public.pem');
28
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
29
+ const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
30
+
31
+ function structured(result,label){
32
+ if(result.isError) throw new Error(`${label} returned error: ${JSON.stringify(result.structuredContent??result.content)}`);
33
+ if(!result.structuredContent||typeof result.structuredContent!=='object') throw new Error(`${label} missing structured output`);
34
+ return result.structuredContent;
35
+ }
36
+ function gateway(result,label){
37
+ const value=structured(result,label);
38
+ if(value.status!=='ok'||!value.result||typeof value.result!=='object') throw new Error(`${label} gateway status=${String(value.status)} error=${String(value.error??'')}`);
39
+ return value.result;
40
+ }
41
+ async function fileSha(relative){return sha256(await readFile(path.join(repoRoot,...relative.split('/'))));}
42
+ async function verifyMachineReceipt(policy,receiptId,operation){
43
+ const checked=await verifyMachineFsReceiptFile({policy,verifyKeyPath,receiptId});
44
+ if(!checked.ok||checked.signature_valid!==true||checked.operation!==operation) throw new Error(`machine-fs receipt verification failed for ${operation}`);
45
+ return checked;
46
+ }
47
+ async function verifyObservationReceipt(policy,receiptId){
48
+ const checked=await verifyObservationReceiptFile({policy,verifyKeyPath,receiptId});
49
+ if(!checked.ok||checked.signature_valid!==true) throw new Error('observation receipt verification failed');
50
+ return checked;
51
+ }
52
+ async function verifyDesktopReceipt(policy,verifyKey,receiptId,receiptSha256,kind){
53
+ const file=path.join(policy.evidence_dir,`${receiptId}.json`);
54
+ const receipt=JSON.parse(await readFile(file,'utf8'));
55
+ const checked=verifyDesktopReceiptObject(receipt,{policySha256:policy.policy_sha256,publicKey:verifyKey.publicKey,keyId:verifyKey.keyId});
56
+ if(!checked.ok||checked.receipt_sha256!==receiptSha256||checked.kind!==kind) throw new Error(`desktop receipt verification failed for ${kind}`);
57
+ return checked;
58
+ }
59
+ async function waitSearch(client,searchId){
60
+ for(let attempt=0;attempt<200;attempt+=1){
61
+ const status=gateway(await client.callTool({name:'machine_observe',arguments:{op:'search_status',search_id:searchId}}),'search_status');
62
+ if(['completed','cancelled','failed'].includes(status.state)) return status;
63
+ await sleep(25);
64
+ }
65
+ throw new Error('R40 compact search timeout');
66
+ }
67
+ async function waitProcessOutput(client,sessionId){
68
+ for(let attempt=0;attempt<100;attempt+=1){
69
+ const page=gateway(await client.callTool({name:'process_session',arguments:{op:'read',session_id:sessionId,offset:0,max_bytes:65536}}),'process read');
70
+ if(Buffer.from(page.data_base64??'','base64').toString('utf8').includes('DEADBYTE_ACTION_PING')) return page;
71
+ await sleep(50);
72
+ }
73
+ throw new Error('R40 compact process output timeout');
74
+ }
75
+
76
+ export async function runR40CompactParity(endpointText){
77
+ const endpoint=new URL(endpointText);
78
+ if(endpoint.protocol!=='https:') throw new Error('R40 compact parity requires HTTPS');
79
+ const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
80
+ const policy=await loadCodingPolicy(path.join(pointer.generation_root,'coding-policy.json'));
81
+ const desktopPolicy=await loadDesktopPolicy(path.join(pointer.generation_root,'desktop-policy.json'));
82
+ const desktopVerifyKey=await loadPublicVerifyKey(verifyKeyPath);
83
+ const client=new Client({name:'deadbyte-r40-compact-parity',version:'0.12.0'},{versionNegotiation:{mode:{pin:'2026-07-28'}}});
84
+ const transport=new StreamableHTTPClientTransport(endpoint);
85
+ const tag=randomBytes(8).toString('hex');
86
+ const scratchRoot='parity_scratch';
87
+ const target=`.deadbyte-r40-parity-${tag}.txt`;
88
+ let processSession=null,targetPresent=false;
89
+ const machineReceipts=[],observationReceipts=[];
90
+ try{
91
+ await client.connect(transport);
92
+ const listed=await client.listTools();
93
+ const names=listed.tools.map(tool=>tool.name).sort();
94
+ if(names.length>R40_COMPACT_TOOL_LIMIT) throw new Error(`R40 compact catalog exceeds ${R40_COMPACT_TOOL_LIMIT}: ${names.length}`);
95
+ if(names.length!==R40_COMPACT_TOOL_LIMIT) throw new Error(`R40 compact catalog must be exactly ${R40_COMPACT_TOOL_LIMIT}, got ${names.length}`);
96
+ for(const name of R40_COMPACT_GATEWAYS) if(!names.includes(name)) throw new Error(`R40 compact gateway missing ${name}`);
97
+ for(const tool of listed.tools){
98
+ if(tool.outputSchema?.type!=='object'||tool.outputSchema?.additionalProperties!==false||!tool.outputSchema?.properties) throw new Error(`tool ${tool.name} missing strict output schema`);
99
+ }
100
+ const manifest=gateway(await client.callTool({name:'capability_manifest',arguments:{}}),'capability_manifest');
101
+ if(manifest.schema!=='deadbyte.capability-manifest.v2'||manifest.profile!=='compact'||!Array.isArray(manifest.capabilities)||!/^[0-9a-f]{64}$/.test(String(manifest.ledger_sha256??''))) throw new Error('R40 compact capability manifest malformed');
102
+ if(manifest.tool_count!==names.length||JSON.stringify(manifest.tool_catalog)!==JSON.stringify(names)||
103
+ manifest.catalog_sha256!==sha256(Buffer.from(JSON.stringify(names),'utf8'))) throw new Error('R40 compact manifest catalog binding mismatch');
104
+ const required=manifest.capabilities.filter(item=>item?.production===true&&item?.host_only!==true);
105
+ for(const item of required){
106
+ if(typeof item.compact_tool!=='string'||!names.includes(item.compact_tool)) throw new Error(`compact capability route missing: ${String(item.id)}`);
107
+ }
108
+ const coding=structured(await client.callTool({name:'coding_session_status',arguments:{}}),'coding_session_status');
109
+ const autonomous=structured(await client.callTool({name:'autonomous_session_status',arguments:{}}),'autonomous_session_status');
110
+ if(coding.armed!==true||autonomous.coding_armed!==true||autonomous.autonomous_armed!==true) throw new Error('R40 compact parity requires coding and autonomous standing grants');
111
+ const desktopStatus=gateway(await client.callTool({name:'desktop_control',arguments:{op:'status'}}),'desktop status');
112
+ if(desktopStatus.configured!==true||desktopStatus.armed!==false) throw new Error('R40 compact parity requires Desktop configured and DISARMED');
113
+ const desktopObserved=gateway(await client.callTool({name:'desktop_control',arguments:{op:'observe',preview:false}}),'desktop observe');
114
+ await verifyDesktopReceipt(desktopPolicy,desktopVerifyKey,desktopObserved.receipt_id,desktopObserved.receipt_sha256,'desktop_observation');
115
+ const desktopTarget=gateway(await client.callTool({name:'desktop_control',arguments:{op:'target',frame_id:desktopObserved.frame.frame_id,uia_query:{kind:'root',value:'',max_results:1,ordinal:0}}}),'desktop target');
116
+ await verifyDesktopReceipt(desktopPolicy,desktopVerifyKey,desktopTarget.grounding.receipt_id,desktopTarget.grounding.receipt_sha256,'desktop_grounding');
117
+ if(desktopTarget.target?.source!=='uia') throw new Error('R40 compact UIA root grounding missing');
118
+ const tree=structured(await client.callTool({name:'coding_tree',arguments:{root_id:'core',path:'workspaces/demo',max_depth:2,max_entries:128}}),'coding_tree');
119
+ if(tree.status!=='ok'||!Array.isArray(tree.entries)) throw new Error('coding_tree malformed');
120
+ const stat=gateway(await client.callTool({name:'coding_inspect',arguments:{op:'stat',root_id:'core',path:'package.json',hash:true}}),'coding stat');
121
+ if(stat.type!=='file'||!/^[0-9a-f]{64}$/.test(String(stat.sha256??''))||!/^[0-9a-f]{64}$/.test(String(stat.observation_sha256??''))) throw new Error('coding stat identity missing');
122
+ const search=gateway(await client.callTool({name:'coding_inspect',arguments:{op:'search',root_id:'core',path:'src',pattern:'R36_CAPABILITY_LEDGER',target:'content',mode:'literal',case_sensitive:true,max_results:20,max_file_bytes:262144,max_scan_bytes:4194304,page_size:20,cursor:null}}),'coding search');
123
+ if(!Array.isArray(search.matches)||search.matches.length<1) throw new Error('coding search returned no canonical ledger match');
124
+
125
+ const buildScript='scripts/autonomous-build.ps1';
126
+ const testScript='scripts/release-parity-tests-r40.ps1';
127
+ const build=structured(await client.callTool({name:'coding_command_run',arguments:{root_id:'core',command_id:'powershell_script',script_path:buildScript,script_sha256:await fileSha(buildScript),args:[],cwd:'.',timeout_ms:120000}},{timeout:180000,maxTotalTimeout:180000}),'coding build');
128
+ if(build.status!=='passed'||build.exit_code!==0) throw new Error('R40 coding build failed');
129
+ const buildVerify=structured(await client.callTool({name:'coding_receipt_verify',arguments:{receipt_id:build.receipt_id}}),'coding build receipt');
130
+ if(buildVerify.ok!==true||buildVerify.signature_valid!==true) throw new Error('R40 coding build receipt invalid');
131
+ const tests=structured(await client.callTool({name:'coding_command_run',arguments:{root_id:'core',command_id:'powershell_script',script_path:testScript,script_sha256:await fileSha(testScript),args:[],cwd:'.',timeout_ms:300000}},{timeout:360000,maxTotalTimeout:360000}),'coding tests');
132
+ if(tests.status!=='passed'||tests.exit_code!==0) throw new Error('R40 coding tests failed');
133
+ const testVerify=structured(await client.callTool({name:'coding_receipt_verify',arguments:{receipt_id:tests.receipt_id}}),'coding test receipt');
134
+ if(testVerify.ok!==true||testVerify.signature_valid!==true) throw new Error('R40 coding test receipt invalid');
135
+
136
+ const initial=`needle-${tag}\n`;
137
+ const write=gateway(await client.callTool({name:'machine_fs',arguments:{op:'write',root_id:scratchRoot,path:target,content:initial,encoding:'utf8',expected_sha256:'absent'}}),'machine_fs write');
138
+ targetPresent=true;machineReceipts.push(write.receipt_id);await verifyMachineReceipt(policy,write.receipt_id,'machine_fs_write');
139
+ const bounded=gateway(await client.callTool({name:'machine_fs',arguments:{op:'read',root_id:scratchRoot,path:target,offset:0,max_bytes:128,hash_file:true}}),'machine_fs read');
140
+ if(Buffer.from(bounded.data_base64,'base64').toString('utf8')!==initial||bounded.file_sha256!==write.sha256) throw new Error('R40 bounded machine read mismatch');
141
+ const edit=gateway(await client.callTool({name:'machine_fs',arguments:{op:'edit_exact',root_id:scratchRoot,path:target,expected_sha256:write.sha256,old_string:'needle',new_string:'beta',expected_replacements:1}}),'machine_fs edit');
142
+ machineReceipts.push(edit.receipt_id);await verifyMachineReceipt(policy,edit.receipt_id,'machine_fs_edit_exact');
143
+ const stale=await client.callTool({name:'machine_fs',arguments:{op:'edit_exact',root_id:scratchRoot,path:target,expected_sha256:write.sha256,old_string:'beta',new_string:'bad',expected_replacements:1}});
144
+ const staleValue=stale.structuredContent;
145
+ if(!staleValue||typeof staleValue!=='object') throw new Error('R40 stale machine-fs denial missing structured output');
146
+ if(stale.isError!==true||staleValue.status!=='denied'||!/precondition mismatch/i.test(String(staleValue.error??''))) {
147
+ throw new Error(`R40 stale machine-fs precondition was not denied: ${JSON.stringify(staleValue)}`);
148
+ }
149
+
150
+ const searchStart=gateway(await client.callTool({name:'machine_observe',arguments:{op:'search_start',root_id:scratchRoot,path:'.',pattern:tag,case_sensitive:true,max_results:20,max_files:200,max_bytes:262144,max_file_bytes:16384}}),'observe search start');
151
+ const searchStatus=await waitSearch(client,searchStart.search_id);
152
+ if(searchStatus.state!=='completed'||!searchStatus.receipt_id) throw new Error('R40 compact observation search failed');
153
+ observationReceipts.push(searchStatus.receipt_id);await verifyObservationReceipt(policy,searchStatus.receipt_id);
154
+ const page=gateway(await client.callTool({name:'machine_observe',arguments:{op:'search_page',search_id:searchStart.search_id,limit:20,cursor:null}}),'observe search page');
155
+ if(!page.results.some(item=>item.path===target)) throw new Error('R40 compact search did not return parity file');
156
+ const system=gateway(await client.callTool({name:'machine_observe',arguments:{op:'system_status'}}),'system status');
157
+ observationReceipts.push(system.receipt_id);await verifyObservationReceipt(policy,system.receipt_id);
158
+ const machineStatus=gateway(await client.callTool({name:'machine_observe',arguments:{op:'machine_status'}}),'machine status');
159
+ if(machineStatus.release_id!==pointer.release_id||machineStatus.release_manifest_sha256!==pointer.manifest_sha256) throw new Error('R40 compact machine status release mismatch');
160
+
161
+ const started=gateway(await client.callTool({name:'process_session',arguments:{op:'start',profile_id:'ping_hold',root_id:'core',cwd:'.',args:[]}}),'process start');
162
+ processSession=started.session_id??started.session?.session_id;
163
+ if(!/^[0-9a-f]{64}$/.test(String(processSession??''))) throw new Error('R40 compact process session id missing');
164
+ const action=gateway(await client.callTool({name:'process_session',arguments:{op:'action',session_id:processSession,action_id:'ping'}}),'process action');
165
+ const processRead=await waitProcessOutput(client,processSession);
166
+ const terminated=gateway(await client.callTool({name:'process_session',arguments:{op:'terminate',session_id:processSession}}),'process terminate');
167
+ const terminalState=terminated.state??terminated.session?.state;
168
+ if(action.action_id!=='ping'||terminalState!=='terminated') throw new Error('R40 compact process lifecycle failed');
169
+
170
+ const fsStat=gateway(await client.callTool({name:'machine_fs',arguments:{op:'stat',root_id:scratchRoot,path:target,hash:true}}),'machine_fs stat');
171
+ const deleted=gateway(await client.callTool({name:'machine_fs',arguments:{op:'delete',root_id:scratchRoot,path:target,expected_source_identity:fsStat.identity_sha256}}),'machine_fs delete');
172
+ machineReceipts.push(deleted.receipt_id);await verifyMachineReceipt(policy,deleted.receipt_id,'machine_fs_delete');targetPresent=false;
173
+
174
+ return {status:'passed',protocol_revision:client.getNegotiatedProtocolVersion(),profile:'compact',tool_count:names.length,tools:names,
175
+ catalog_sha256:sha256(Buffer.from(JSON.stringify(names),'utf8')),strict_output_schemas:true,ledger_sha256:manifest.ledger_sha256,
176
+ capability_count:manifest.capabilities.length,production_non_host_capabilities:required.length,capability_closure:true,
177
+ gateway_count:R40_COMPACT_GATEWAYS.length,tree_entries:tree.entries.length,coding_stat_verified:true,coding_search_result_count:search.matches.length,
178
+ desktop_armed:false,desktop_observation_receipt_verified:true,desktop_grounding_receipt_verified:true,
179
+ desktop_frame_id:desktopObserved.frame.frame_id,desktop_target_id:desktopTarget.target.target_id,
180
+ machine_fs_receipts_verified:machineReceipts.length,observation_receipts_verified:observationReceipts.length,
181
+ observation_search_result_count:page.results.length,process_session_id:processSession,process_output_bytes:processRead.stream_head,
182
+ process_journal_head_sha256:terminated.journal_head_sha256??terminated.session?.journal_head_sha256,
183
+ build_receipt_id:build.receipt_id,test_receipt_id:tests.receipt_id,coding_receipts_verified:2,
184
+ execution_provider:'deadbyte_mcp',rdc_operation_count:0};
185
+ } finally {
186
+ if(processSession) await client.callTool({name:'process_session',arguments:{op:'terminate',session_id:processSession}}).catch(()=>{});
187
+ if(targetPresent){
188
+ try{const fsStat=gateway(await client.callTool({name:'machine_fs',arguments:{op:'stat',root_id:scratchRoot,path:target,hash:false}}),'cleanup stat');
189
+ if(fsStat.identity_sha256) await client.callTool({name:'machine_fs',arguments:{op:'delete',root_id:scratchRoot,path:target,expected_source_identity:fsStat.identity_sha256}}).catch(()=>{});
190
+ }catch{}
191
+ }
192
+ await client.close().catch(()=>{});
193
+ }
194
+ }
195
+
196
+ if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
197
+ const endpoint=process.argv[2];
198
+ if(!endpoint) throw new Error('usage: node src/remote-mcp-r40-parity-client.mjs https://host/mcp/path');
199
+ runR40CompactParity(endpoint).then(result=>console.log(JSON.stringify(result,null,2))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
200
+ }