deadbyte-mcp 0.11.2 → 0.11.3

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.
@@ -0,0 +1,208 @@
1
+ import { createHash, createPublicKey, verify as cryptoVerify } from 'node:crypto';
2
+ import { lstat, readFile, readdir } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const HEX64=/^[0-9a-f]{64}$/;
8
+ const UPDATE_DOMAIN=Buffer.from('DEADBYTE-R27-SLOT-UPDATE-V1\0','utf8');
9
+ const CLOSURE_DOMAIN=Buffer.from('DEADBYTE-R39-FINAL-CLOSURE-V1\0','utf8');
10
+ const PING_DOMAIN=Buffer.from('DEADBYTE-MACHINE-PING-V1\0','utf8');
11
+ const R39_PREDECESSOR_RELEASE_ID='v0.11.2-058605dfccaa3035';
12
+ const R39_PREDECESSOR_MANIFEST='058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b';
13
+ const R39_FULL_TOOL_COUNT=76;
14
+ const R39_COMPACT_TOOL_LIMIT=42;
15
+ const REQUIRED_PARITY_KEYS=['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface'];
16
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
17
+ const canonical=value=>Array.isArray(value)?value.map(canonical):value&&typeof value==='object'
18
+ ?Object.fromEntries(Object.keys(value).sort().map(key=>[key,canonical(value[key])])):value;
19
+ const canonicalJson=value=>JSON.stringify(canonical(value));
20
+ const same=(a,b)=>canonicalJson(a)===canonicalJson(b);
21
+ function insist(ok,msg){if(!ok) throw new Error(msg);}
22
+ function samePath(a,b){return path.resolve(String(a)).toLowerCase()===path.resolve(String(b)).toLowerCase();}
23
+ function isCandidateIdentity(value,manifest){
24
+ return value?.version==='0.11.3'&&value?.manifest_sha256===manifest&&value?.release_id===`v0.11.3-${manifest.slice(0,16)}`;
25
+ }
26
+ function isR39PredecessorIdentity(value){
27
+ return value?.version==='0.11.2'&&value?.manifest_sha256===R39_PREDECESSOR_MANIFEST&&value?.release_id===R39_PREDECESSOR_RELEASE_ID;
28
+ }
29
+
30
+ function parseManifest(text){
31
+ const out=new Map();
32
+ for(const [i,line] of text.split(/\r?\n/).entries()){
33
+ if(!line) continue;
34
+ const m=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);insist(m,`manifest line ${i+1} malformed`);
35
+ insist(!path.posix.isAbsolute(m[2])&&!m[2].split('/').includes('..')&&!out.has(m[2]),`unsafe/duplicate manifest path ${m[2]}`);
36
+ out.set(m[2],m[1]);
37
+ }
38
+ return out;
39
+ }
40
+ async function walk(root,rel=''){
41
+ const dir=path.join(root,...(rel?rel.split('/'):[]));
42
+ const names=(await readdir(dir)).sort((a,b)=>a.localeCompare(b,'en'));
43
+ const files=[];
44
+ for(const name of names){
45
+ const childRel=rel?`${rel}/${name}`:name;
46
+ const full=path.join(root,...childRel.split('/'));
47
+ const st=await lstat(full);insist(!st.isSymbolicLink(),`symlink forbidden: ${childRel}`);
48
+ if(st.isDirectory()) files.push(...await walk(root,childRel));
49
+ else{insist(st.isFile(),`non-file forbidden: ${childRel}`);files.push(childRel);}
50
+ }
51
+ return files;
52
+ }
53
+ async function verifyTree(root,manifestName,expectedDigest){
54
+ const manifestBytes=await readFile(path.join(root,manifestName));
55
+ insist(sha256(manifestBytes)===expectedDigest,`${manifestName} digest mismatch`);
56
+ const entries=parseManifest(manifestBytes.toString('utf8'));
57
+ const actual=(await walk(root)).filter(rel=>rel!==manifestName).sort((a,b)=>a.localeCompare(b,'en'));
58
+ const expected=[...entries.keys()].sort((a,b)=>a.localeCompare(b,'en'));
59
+ insist(same(actual,expected),`${manifestName} exact tree mismatch`);
60
+ for(const [rel,digest] of entries) insist(sha256(await readFile(path.join(root,...rel.split('/'))))===digest,`${manifestName} file hash mismatch: ${rel}`);
61
+ return entries.size;
62
+ }
63
+ function publicKeyInfo(publicPem){
64
+ const key=createPublicKey(publicPem);insist(key.asymmetricKeyType==='ed25519','public key must be Ed25519');
65
+ const der=Buffer.from(key.export({type:'spki',format:'der'}));
66
+ return {key,key_id:sha256(der),spki_base64:der.toString('base64')};
67
+ }
68
+ function verifyUpdateEnvelope(env,keyInfo){
69
+ insist(env?.body&&env?.attestation,'update envelope malformed');
70
+ const bodyBytes=Buffer.from(canonicalJson(env.body),'utf8');
71
+ insist(sha256(bodyBytes)===env.body_sha256,'update body hash mismatch');
72
+ const {receipt_sha256,...unsigned}=env;
73
+ insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===receipt_sha256,'update receipt hash mismatch');
74
+ insist(env.attestation.algorithm==='ed25519'&&env.attestation.domain==='DEADBYTE-R27-SLOT-UPDATE-V1','update attestation contract mismatch');
75
+ insist(env.attestation.key_id===keyInfo.key_id,'update signer mismatch');
76
+ insist(cryptoVerify(null,Buffer.concat([UPDATE_DOMAIN,bodyBytes]),keyInfo.key,Buffer.from(env.attestation.signature_base64,'base64')),'update signature invalid');
77
+ return true;
78
+ }
79
+ function verifyPing(ping,status,pointer){
80
+ insist(ping?.status==='ok'&&ping.schema==='deadbyte.machine-ping.v1','machine ping malformed');
81
+ insist(status?.status==='ok'&&typeof status.public_key_spki_base64==='string','machine status malformed');
82
+ const der=Buffer.from(status.public_key_spki_base64,'base64');
83
+ insist(der.toString('base64')===status.public_key_spki_base64,'machine SPKI base64 non-canonical');
84
+ const machineKey=createPublicKey({key:der,format:'der',type:'spki'});insist(machineKey.asymmetricKeyType==='ed25519','machine key must be Ed25519');
85
+ const machineId=sha256(der);
86
+ insist(status.machine_id===machineId&&ping.machine_id===machineId&&ping.attestation?.key_id===machineId,'machine id/key mismatch');
87
+ insist(ping.release_id===pointer.release_id&&ping.release_manifest_sha256===pointer.manifest_sha256,'machine ping release binding mismatch');
88
+ insist(ping.generation_manifest_sha256===pointer.generation_manifest_sha256,'machine ping generation binding mismatch');
89
+ const {status:_s,attestation:_a,...body}=ping;
90
+ const bytes=Buffer.from(canonicalJson(body),'utf8');
91
+ insist(cryptoVerify(null,Buffer.concat([PING_DOMAIN,bytes]),machineKey,Buffer.from(ping.attestation.signature_base64,'base64')),'machine ping signature invalid');
92
+ }
93
+
94
+ export async function verifyFinalClosureObject(envelope,{stateRoot=path.join(os.homedir(),'.deadbyte-mcp')}={}){
95
+ insist(envelope?.body?.schema==='deadbyte.r39-final-closure.v1','closure schema mismatch');
96
+ insist(envelope.body.version==='0.11.3','closure version mismatch');
97
+ insist(envelope.body.release_label==='R39 FINAL MACHINE BASELINE','closure release label mismatch');
98
+ const keyInfo=publicKeyInfo(await readFile(path.join(stateRoot,'trust','ed25519-public.pem')));
99
+ const bodyBytes=Buffer.from(canonicalJson(envelope.body),'utf8');
100
+ insist(sha256(bodyBytes)===envelope.body_sha256,'closure body hash mismatch');
101
+ const {closure_sha256,...unsigned}=envelope;
102
+ insist(sha256(Buffer.from(canonicalJson(unsigned),'utf8'))===closure_sha256,'closure envelope hash mismatch');
103
+ insist(envelope.attestation?.algorithm==='ed25519'&&envelope.attestation?.domain==='DEADBYTE-R39-FINAL-CLOSURE-V1','closure attestation contract mismatch');
104
+ insist(envelope.attestation.key_id===keyInfo.key_id,'closure signer mismatch');
105
+ insist(cryptoVerify(null,Buffer.concat([CLOSURE_DOMAIN,bodyBytes]),keyInfo.key,Buffer.from(envelope.attestation.signature_base64,'base64')),'closure signature invalid');
106
+
107
+ const pointer=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
108
+ insist(same(pointer,envelope.body.active_pointer),'active pointer drift');
109
+ insist(pointer.version==='0.11.3','active pointer version mismatch');
110
+ insist(isCandidateIdentity(pointer,pointer.manifest_sha256),'release id/content address mismatch');
111
+ const releaseFiles=await verifyTree(pointer.release_root,'MANIFEST.SHA256',pointer.manifest_sha256);
112
+ const generationFiles=await verifyTree(pointer.generation_root,'GENERATION.SHA256',pointer.generation_manifest_sha256);
113
+ insist(sha256(await readFile(path.join(stateRoot,'bin','DEADBYTE-MCP.ps1')))===pointer.launcher_sha256,'launcher hash mismatch');
114
+
115
+ const predecessor=envelope.body.predecessor;
116
+ insist(isR39PredecessorIdentity(predecessor),'closure predecessor is not exact sealed R39 predecessor');
117
+ const immutable=envelope.body.immutable_slot;
118
+ insist(immutable?.protected===true,'closure immutable-slot protection missing');
119
+ insist(samePath(immutable.release_root,pointer.release_root),'closure immutable release_root mismatch');
120
+ insist(!samePath(immutable.development_root,immutable.release_root),'closure development_root aliases immutable release_root');
121
+
122
+ const surfaces=envelope.body.surfaces;
123
+ insist(surfaces?.local_full?.status==='passed'&&surfaces.local_full.tool_count===R39_FULL_TOOL_COUNT&&surfaces.local_full.strict_output_schemas===true,'closure local full 76-tool proof invalid');
124
+ insist(HEX64.test(surfaces.local_full.catalog_sha256??''),'closure local full catalog hash missing');
125
+ insist(surfaces?.public_compact?.status==='passed'&&surfaces.public_compact.tool_count<=R39_COMPACT_TOOL_LIMIT&&surfaces.public_compact.capability_closure===true,'closure public compact capability proof invalid');
126
+ insist(surfaces.public_compact.coding_armed===false&&surfaces.public_compact.autonomous_armed===false,'closure compact authority is not DISARMED');
127
+ insist(HEX64.test(surfaces.public_compact.catalog_sha256??'')&&HEX64.test(surfaces.public_compact.ledger_sha256??''),'closure compact catalog/ledger hash missing');
128
+
129
+ const evidence=envelope.body.evidence;
130
+ insist(evidence&&evidence.parity&&evidence.activation&&evidence.rollback&&evidence.restore&&evidence.windows_gate,'closure evidence set incomplete');
131
+ for(const [name,item] of Object.entries(evidence)){
132
+ insist(item?.path&&HEX64.test(item.sha256??''),`${name} evidence identity malformed`);
133
+ insist(sha256(await readFile(item.path))===item.sha256,`${name} evidence hash mismatch`);
134
+ }
135
+
136
+ const parity=JSON.parse(await readFile(evidence.parity.path,'utf8'));
137
+ insist(parity.schema==='deadbyte.r39-parity.v1'&&parity.status==='passed','R39 parity evidence invalid');
138
+ insist(parity.rdc_operation_count===0&&parity.execution_provider==='deadbyte_mcp','R39 parity execution provider mismatch');
139
+ insist(isCandidateIdentity(parity.candidate,pointer.manifest_sha256),'R39 parity candidate binding mismatch');
140
+ insist(isCandidateIdentity(parity.successor,pointer.manifest_sha256),'R39 parity successor binding mismatch');
141
+ insist(isR39PredecessorIdentity(parity.predecessor),'R39 parity predecessor binding mismatch');
142
+ insist(parity.local_full?.status==='passed'&&parity.local_full.tool_count===R39_FULL_TOOL_COUNT&&parity.local_full.strict_output_schemas===true,'R39 parity local full proof invalid');
143
+ insist(parity.local_full.catalog_sha256===surfaces.local_full.catalog_sha256,'R36 local full catalog drift between parity and closure');
144
+ insist(parity.public_compact?.status==='passed'&&parity.public_compact.tool_count<=R39_COMPACT_TOOL_LIMIT&&parity.public_compact.capability_closure===true&&parity.public_compact.gateway_count===5,'R39 parity public compact proof invalid');
145
+ insist(parity.successor_disarmed?.status==='passed'&&parity.successor_disarmed.tool_count<=R39_COMPACT_TOOL_LIMIT&&parity.successor_disarmed.capability_closure===true&&parity.successor_disarmed.coding_armed===false&&parity.successor_disarmed.autonomous_armed===false,'R39 parity successor disarmed proof invalid');
146
+ insist(parity.successor_disarmed.catalog_sha256===surfaces.public_compact.catalog_sha256,'R36 compact catalog drift between restore and closure');
147
+ insist(parity.successor_disarmed.ledger_sha256===surfaces.public_compact.ledger_sha256,'R36 capability ledger drift between restore and closure');
148
+ insist(parity.immutable_slot?.protected===true,'R39 parity immutable-slot proof missing');
149
+ insist(samePath(parity.immutable_slot.release_root,pointer.release_root),'R39 parity immutable release_root mismatch');
150
+ insist(samePath(parity.immutable_slot.development_root,immutable.development_root),'R39 parity/closure development_root mismatch');
151
+ insist(!samePath(parity.immutable_slot.development_root,pointer.release_root),'R36 mutable development_root aliases immutable release slot');
152
+ for(const key of REQUIRED_PARITY_KEYS) insist(parity.requirements?.[key]===true,`R39 parity requirement missing ${key}`);
153
+
154
+ const activation=JSON.parse(await readFile(evidence.activation.path,'utf8'));
155
+ const rollback=JSON.parse(await readFile(evidence.rollback.path,'utf8'));
156
+ const restore=JSON.parse(await readFile(evidence.restore.path,'utf8'));
157
+ verifyUpdateEnvelope(activation,keyInfo);verifyUpdateEnvelope(rollback,keyInfo);verifyUpdateEnvelope(restore,keyInfo);
158
+ insist(activation.body.schema==='deadbyte.r27-slot-update-receipt.v1'&&activation.body.rollback_performed===false,'R39 activation receipt invalid');
159
+ insist(activation.body.release_version==='0.11.3'&&activation.body.candidate_manifest_sha256===pointer.manifest_sha256,'R39 activation candidate identity invalid');
160
+ insist(isCandidateIdentity(activation.body.active_pointer,pointer.manifest_sha256),'R39 activation active pointer invalid');
161
+ insist(isR39PredecessorIdentity(activation.body.prior_pointer),'R39 activation predecessor is not exact 0.11.2 predecessor');
162
+ insist(samePath(activation.body.development_root,immutable.development_root),'R39 activation development_root mismatch');
163
+ insist(!samePath(activation.body.development_root,activation.body.active_pointer.release_root),'R39 activation development_root aliases release slot');
164
+
165
+ insist(rollback.body.schema==='deadbyte.r31-slot-rollback-receipt.v1'&&rollback.body.rollback_performed===true,'R39 rollback receipt invalid');
166
+ insist(isCandidateIdentity(rollback.body.from_pointer,pointer.manifest_sha256),'R39 rollback source is not exact candidate');
167
+ insist(isR39PredecessorIdentity(rollback.body.active_pointer),'R39 rollback target is not exact 0.11.2 predecessor');
168
+ insist(rollback.body.activation_receipt_sha256===activation.receipt_sha256,'R39 rollback not bound to activation receipt');
169
+
170
+ insist(restore.body.schema==='deadbyte.r27-slot-update-receipt.v1'&&restore.body.rollback_performed===false,'R39 restore receipt invalid');
171
+ insist(restore.body.release_version==='0.11.3'&&restore.body.candidate_manifest_sha256===pointer.manifest_sha256,'R39 restore candidate identity invalid');
172
+ insist(isR39PredecessorIdentity(restore.body.prior_pointer),'R39 restore predecessor is not exact 0.11.2 predecessor');
173
+ insist(isCandidateIdentity(restore.body.active_pointer,pointer.manifest_sha256)&&same(restore.body.active_pointer,pointer),'R39 restore/current pointer mismatch');
174
+ insist(samePath(restore.body.development_root,immutable.development_root),'R39 restore development_root mismatch');
175
+ insist(!samePath(restore.body.development_root,restore.body.active_pointer.release_root),'R39 restore development_root aliases release slot');
176
+
177
+ const windowsGate=JSON.parse(await readFile(evidence.windows_gate.path,'utf8'));
178
+ insist(windowsGate.schema==='deadbyte.r39-windows-gate.v1'&&windowsGate.status==='passed'&&windowsGate.exit_code===0,'R39 Windows gate evidence invalid');
179
+ insist(windowsGate.version==='0.11.3'&&windowsGate.manifest_sha256===pointer.manifest_sha256,'R39 Windows gate manifest/version binding mismatch');
180
+ insist(windowsGate.marker==='DEADBYTE V0.11.3 / R39 WINDOWS BATCH GATE: PASS','R39 Windows gate PASS marker mismatch');
181
+
182
+ const machine=envelope.body.machine;
183
+ insist(machine?.status?.release_id===pointer.release_id&&machine.status.release_manifest_sha256===pointer.manifest_sha256&&machine.status.generation_manifest_sha256===pointer.generation_manifest_sha256,'machine status binding mismatch');
184
+ verifyPing(machine.ping,machine.status,pointer);
185
+ insist(machine.ping.nonce===machine.nonce,'machine ping nonce binding mismatch');
186
+
187
+ const grantNames=['process-grant.json','coding-grant.json','autonomous-grant.json','host-grant.json'];
188
+ insist(envelope.body.authority?.all_disarmed===true,'closure authority not disarmed');
189
+ for(const name of grantNames){
190
+ let exists=true;try{await lstat(path.join(stateRoot,'runtime',name));}catch(error){if(error?.code==='ENOENT') exists=false;else throw error;}
191
+ insist(!exists,`authority grant still present: ${name}`);
192
+ insist(envelope.body.authority.grants_absent?.[name]===true,`closure grant absence not recorded: ${name}`);
193
+ }
194
+ return {ok:true,status:'passed',release_id:pointer.release_id,manifest_sha256:pointer.manifest_sha256,
195
+ generation_manifest_sha256:pointer.generation_manifest_sha256,release_files:releaseFiles,generation_files:generationFiles,
196
+ machine_id:machine.status.machine_id,parity_sha256:evidence.parity.sha256,closure_sha256:envelope.closure_sha256,
197
+ full_tool_count:R39_FULL_TOOL_COUNT,compact_tool_count:surfaces.public_compact.tool_count};
198
+ }
199
+
200
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
201
+ if(invoked){
202
+ const file=process.argv[2];
203
+ if(!file) throw new Error('usage: node scripts/final-closure-verify-r39.mjs <closure.json>');
204
+ try{
205
+ const envelope=JSON.parse(await readFile(path.resolve(file),'utf8'));
206
+ console.log(JSON.stringify(await verifyFinalClosureObject(envelope),null,2));
207
+ }catch(error){console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;}
208
+ }
@@ -0,0 +1,42 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 2.0
3
+
4
+ function Invoke-GateStep {
5
+ param(
6
+ [Parameter(Mandatory = $true)][string]$Name,
7
+ [Parameter(Mandatory = $true)][string[]]$NpmArgs
8
+ )
9
+ Write-Host "==== $Name ===="
10
+ & npm.cmd @NpmArgs
11
+ if ($LASTEXITCODE -ne 0) {
12
+ throw "DEADBYTE V0.11.3 / R39 gate failed at $Name with exit code $LASTEXITCODE"
13
+ }
14
+ }
15
+
16
+ Invoke-GateStep -Name 'containment-build' -NpmArgs @('run', 'containment:build')
17
+ Invoke-GateStep -Name 'process-policy-refresh' -NpmArgs @('run', 'process:policy:refresh')
18
+ Invoke-GateStep -Name 'release-manifest-write' -NpmArgs @('run', 'manifest:write')
19
+ Invoke-GateStep -Name 'release-manifest' -NpmArgs @('run', 'manifest:verify')
20
+ Invoke-GateStep -Name 'tests' -NpmArgs @('test')
21
+ Invoke-GateStep -Name 'mcp-smoke' -NpmArgs @('run', 'mcp:smoke')
22
+ Invoke-GateStep -Name 'mcp-agent-smoke' -NpmArgs @('run', 'mcp:agent:smoke')
23
+ Invoke-GateStep -Name 'mcp-coding-smoke' -NpmArgs @('run', 'mcp:coding:smoke')
24
+ Invoke-GateStep -Name 'mcp-machine-fs-smoke' -NpmArgs @('run', 'mcp:machine-fs:smoke')
25
+ Invoke-GateStep -Name 'mcp-observation-smoke' -NpmArgs @('run', 'mcp:observation:smoke')
26
+ Invoke-GateStep -Name 'mcp-process-smoke' -NpmArgs @('run', 'mcp:process:smoke')
27
+ Invoke-GateStep -Name 'mcp-autonomous-smoke' -NpmArgs @('run', 'mcp:autonomous:smoke')
28
+ Invoke-GateStep -Name 'tunnel-stdio-compat-smoke' -NpmArgs @('run', 'mcp:tunnel-compat:smoke')
29
+ Invoke-GateStep -Name 'mcp-host-smoke' -NpmArgs @('run', 'mcp:host:smoke')
30
+ Invoke-GateStep -Name 'authority-smoke' -NpmArgs @('run', 'authority:smoke')
31
+ Invoke-GateStep -Name 'containment-smoke' -NpmArgs @('run', 'containment:smoke')
32
+ Invoke-GateStep -Name 'contained-smoke' -NpmArgs @('run', 'contained:smoke')
33
+ Invoke-GateStep -Name 'mcp-contained-smoke' -NpmArgs @('run', 'mcp:contained:smoke')
34
+ Invoke-GateStep -Name 'release-manifest-final' -NpmArgs @('run', 'manifest:verify')
35
+
36
+ Write-Host '==== windows-gate-evidence ===='
37
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r39.mjs')
38
+ if ($LASTEXITCODE -ne 0) {
39
+ throw "DEADBYTE V0.11.3 / R39 gate failed at windows-gate-evidence with exit code $LASTEXITCODE"
40
+ }
41
+
42
+ Write-Host '==== DEADBYTE V0.11.3 / R39 WINDOWS BATCH GATE: PASS ===='
@@ -0,0 +1,200 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, readFile, realpath, writeFile } from 'node:fs/promises';
3
+ import { loadPowerShellDataFile } from '../src/runtime-update.mjs';
4
+ import os from 'node:os';
5
+ import path from 'node:path';
6
+ import { spawn } from 'node:child_process';
7
+ import { fileURLToPath } from 'node:url';
8
+ import { probeR36FullSurface } from '../src/r36-full-surface-probe.mjs';
9
+ import { runR36CompactParity } from '../src/remote-mcp-r36-parity-client.mjs';
10
+ import { probeR36CompactDisarmed } from '../src/r36-compact-disarmed-probe.mjs';
11
+
12
+ const here=path.dirname(fileURLToPath(import.meta.url));
13
+ const root=path.resolve(here,'..');
14
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
15
+ const deferred=path.join(root,'scripts','deferred-slot-operation-r39.mjs');
16
+ const ps='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe';
17
+ const launcher=path.join(stateRoot,'bin','DEADBYTE-MCP.ps1');
18
+ const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
19
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
20
+
21
+ export const R39_PREDECESSOR_RELEASE_ID='v0.11.2-058605dfccaa3035';
22
+ export const R39_PREDECESSOR_MANIFEST='058605dfccaa3035a57c6393d53f2421c14e5a92bd145c2334477ba24d7cab8b';
23
+
24
+ function assert(condition,message){if(!condition) throw new Error(message);}
25
+ function parseFrozenManifest(text){
26
+ const entries=[];const seen=new Set();
27
+ for(const [index,line] of text.split(/\r?\n/).entries()){
28
+ if(!line) continue;
29
+ const match=/^([0-9a-f]{64}) ([^\0]+)$/.exec(line);
30
+ assert(match,`frozen manifest line ${index+1} malformed`);
31
+ const rel=match[2];
32
+ assert(!path.posix.isAbsolute(rel)&&!rel.split('/').includes('..')&&!seen.has(rel),`unsafe/duplicate frozen manifest path: ${rel}`);
33
+ seen.add(rel);entries.push({sha256:match[1],path:rel});
34
+ }
35
+ return entries;
36
+ }
37
+ // Restore the mutable development stage from the immutable active release after live parity work may drift it.
38
+ export async function restoreFrozenStage({developmentRoot,releaseRoot,expectedManifestSha256}){
39
+ const dev=path.resolve(developmentRoot);const release=path.resolve(releaseRoot);
40
+ const manifestBytes=await readFile(path.join(release,'MANIFEST.SHA256'));
41
+ const manifestSha256=sha256(manifestBytes);
42
+ assert(manifestSha256===expectedManifestSha256,`immutable release manifest drift: ${manifestSha256}`);
43
+ const entries=parseFrozenManifest(manifestBytes.toString('utf8'));
44
+ for(const entry of entries){
45
+ const source=path.join(release,...entry.path.split('/'));const bytes=await readFile(source);
46
+ assert(sha256(bytes)===entry.sha256,`immutable release file drift: ${entry.path}`);
47
+ const destination=path.join(dev,...entry.path.split('/'));await mkdir(path.dirname(destination),{recursive:true});
48
+ await writeFile(destination,bytes);assert(sha256(await readFile(destination))===entry.sha256,`development restore verification failed: ${entry.path}`);
49
+ }
50
+ await writeFile(path.join(dev,'MANIFEST.SHA256'),manifestBytes);
51
+ assert(sha256(await readFile(path.join(dev,'MANIFEST.SHA256')))===expectedManifestSha256,'development manifest restore verification failed');
52
+ return {status:'restored',file_count:entries.length,manifest_sha256:manifestSha256};
53
+ }
54
+ function parseJsonOutput(text,label){
55
+ const trimmed=String(text).trim();const starts=[...trimmed.matchAll(/\{/g)].map(match=>match.index);
56
+ for(const start of starts){try{return JSON.parse(trimmed.slice(start));}catch{}}
57
+ throw new Error(`${label} did not emit JSON`);
58
+ }
59
+ function run(command,args,{timeoutMs=900000,env=process.env,cwd=root}={}){
60
+ return new Promise((resolve,reject)=>{
61
+ const child=spawn(command,args,{cwd,shell:false,windowsHide:true,env,stdio:['ignore','pipe','pipe']});
62
+ const out=[],err=[];const timer=setTimeout(()=>{child.kill();reject(new Error(`command timeout: ${path.basename(command)}`));},timeoutMs);
63
+ child.stdout.on('data',chunk=>out.push(Buffer.from(chunk)));child.stderr.on('data',chunk=>err.push(Buffer.from(chunk)));
64
+ child.on('error',error=>{clearTimeout(timer);reject(error);});child.on('exit',code=>{
65
+ clearTimeout(timer);const stdout=Buffer.concat(out).toString('utf8');const stderr=Buffer.concat(err).toString('utf8');
66
+ if(code!==0) reject(new Error(`command failed exit=${code}: ${stderr||stdout}`));else resolve({stdout,stderr,exitCode:code});
67
+ });
68
+ });
69
+ }
70
+ async function publicUrl(){
71
+ const value=(await readFile(path.join(stateRoot,'bridge','mcp-url.txt'),'utf8')).trim();const url=new URL(value);
72
+ if(url.protocol!=='https:') throw new Error('public MCP URL must be HTTPS');return value;
73
+ }
74
+ async function pointer(){return JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));}
75
+ async function disarmAll(){
76
+ for(const command of ['disarmautonomous','disarmcoding','disarmprocess','disarmhost']){
77
+ await run(ps,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,command],{timeoutMs:60000});
78
+ }
79
+ }
80
+ async function waitDeferred(statePath,timeoutMs=180000){
81
+ const deadline=Date.now()+timeoutMs;
82
+ while(Date.now()<deadline){const state=JSON.parse(await readFile(statePath,'utf8'));if(state.state==='completed') return state;if(state.state==='failed') throw new Error(`deferred ${state.mode} failed: ${state.error}`);await sleep(500);}
83
+ throw new Error(`deferred operation timeout: ${statePath}`);
84
+ }
85
+ async function scheduleDeferred(mode,value,{bridgeRoot=null,bridgeScriptSha256=null}={}){
86
+ if((bridgeRoot===null)!==(bridgeScriptSha256===null)) throw new Error('deferred bridge override requires exact root + SHA pair');
87
+ const args=[deferred,mode,value];
88
+ if(bridgeRoot!==null) args.push('--bridge-root',bridgeRoot,'--bridge-script-sha256',bridgeScriptSha256);
89
+ const scheduled=parseJsonOutput((await run(process.execPath,args,{timeoutMs:30000})).stdout,`deferred ${mode}`);
90
+ assert(scheduled.status==='scheduled',`deferred ${mode} was not scheduled`);
91
+ assert(scheduled.execution_provider==='deadbyte_mcp'&&scheduled.rdc_operation_count===0,'deferred operation provider mismatch');
92
+ return {scheduled,completed:await waitDeferred(scheduled.state_path)};
93
+ }
94
+ async function publicR39Disarmed(url){
95
+ const result=await probeR36CompactDisarmed(url);
96
+ assert(result.status==='passed'&&result.tool_count<=42&&result.capability_closure===true,'R39 predecessor public compact catalog mismatch');
97
+ assert(result.release_id===R39_PREDECESSOR_RELEASE_ID&&result.release_manifest_sha256===R39_PREDECESSOR_MANIFEST,'R39 predecessor machine binding mismatch');
98
+ assert(result.coding_armed===false&&result.autonomous_armed===false,'R39 predecessor authority remained armed');
99
+ return result;
100
+ }
101
+ async function mutableCore(pointerValue){
102
+ const policy=JSON.parse(await readFile(path.join(pointerValue.generation_root,'coding-policy.json'),'utf8'));
103
+ const raw=policy?.roots?.core?.path??policy?.roots?.core?.real_path;
104
+ assert(typeof raw==='string'&&raw,'R39 generation missing coding core root');
105
+ const core=path.resolve(raw);const release=path.resolve(pointerValue.release_root);
106
+ assert(core.toLowerCase()!==release.toLowerCase(),'R39 coding core must not point at immutable active release slot');
107
+ return core;
108
+ }
109
+
110
+ export function validateParityEvidence(value){
111
+ assert(value?.schema==='deadbyte.r39-parity.v1','R39 parity schema mismatch');
112
+ assert(value.status==='passed','R39 parity status is not passed');
113
+ assert(value.rdc_operation_count===0&&value.execution_provider==='deadbyte_mcp','R39 parity used non-DEADBYTE execution');
114
+ assert(value.candidate?.version==='0.11.3'&&/^[0-9a-f]{64}$/.test(value.candidate?.manifest_sha256??''),'R39 candidate identity missing');
115
+ assert(value.local_full?.status==='passed'&&value.local_full?.tool_count===76&&value.local_full?.strict_output_schemas===true,'R39 local full 76-tool proof missing');
116
+ assert(value.public_compact?.status==='passed'&&value.public_compact?.tool_count<=42&&value.public_compact?.capability_closure===true&&value.public_compact?.gateway_count===5,'R39 public compact closure missing');
117
+ assert(value.autonomous?.status==='passed'&&value.autonomous?.signed_release_verified===true,'R39 autonomous live proof missing');
118
+ assert(value.before_rollback_disarmed?.status==='passed'&&value.before_rollback_disarmed?.capability_closure===true&&value.before_rollback_disarmed?.coding_armed===false&&value.before_rollback_disarmed?.autonomous_armed===false,'R39 pre-rollback disarm proof missing');
119
+ assert(value.rollback?.state==='completed'&&value.restore?.state==='completed','R39 rollback/restore not completed');
120
+ assert(value.stage_restore?.status==='restored'&&value.stage_restore?.manifest_sha256===value.candidate.manifest_sha256,'R39 stage restore proof missing');
121
+ assert(value.predecessor?.release_id===R39_PREDECESSOR_RELEASE_ID&&value.predecessor?.manifest_sha256===R39_PREDECESSOR_MANIFEST&&value.predecessor?.version==='0.11.2','R39 exact predecessor identity mismatch');
122
+ assert(value.predecessor_disarmed?.status==='passed'&&value.predecessor_disarmed?.tool_count<=42&&value.predecessor_disarmed?.capability_closure===true,'R39 predecessor public proof missing');
123
+ assert(value.successor?.version==='0.11.3'&&value.successor?.manifest_sha256===value.candidate.manifest_sha256,'R39 exact successor restore identity mismatch');
124
+ assert(value.successor_disarmed?.status==='passed'&&value.successor_disarmed?.capability_closure===true&&value.successor_disarmed?.coding_armed===false&&value.successor_disarmed?.autonomous_armed===false,'R39 successor disarmed proof missing');
125
+ assert(value.immutable_slot?.protected===true&&value.immutable_slot?.development_root!==value.immutable_slot?.release_root,'R39 immutable-slot separation missing');
126
+ for(const key of ['tree_read','precondition_mutation','search','owned_process','observation','coding_loop','autonomy','interrupted_recovery','evidence_verification','compact_closure','full_surface']) assert(value.requirements?.[key]===true,`R39 parity requirement not proven: ${key}`);
127
+ return true;
128
+ }
129
+
130
+ export async function runReleaseParity(activationReceiptPath){
131
+ const active=await pointer();const candidateManifest=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
132
+ assert(active.version==='0.11.3','R39 parity requires active 0.11.3 candidate');
133
+ assert(active.manifest_sha256===candidateManifest,'active release is not canonical R39 candidate');
134
+ const activeConfig=await loadPowerShellDataFile(active.config_path);
135
+ const successorBridgeRootRaw=activeConfig?.Bridge?.WorkingDirectory;
136
+ const successorBridgeConfiguredSha=activeConfig?.Bridge?.ScriptSha256;
137
+ assert(typeof successorBridgeRootRaw==='string'&&path.isAbsolute(successorBridgeRootRaw),'R39 active bridge root missing');
138
+ assert(typeof successorBridgeConfiguredSha==='string'&&/^[0-9a-f]{64}$/.test(successorBridgeConfiguredSha),'R39 active bridge SHA missing');
139
+ const successorBridgeRoot=await realpath(path.resolve(successorBridgeRootRaw));
140
+ const successorBridgeActualSha=sha256(await readFile(path.join(successorBridgeRoot,'src','bridge.mjs')));
141
+ assert(successorBridgeActualSha===successorBridgeConfiguredSha,'R39 active bridge bytes do not match generation pin');
142
+ const successorBridge={root:successorBridgeRoot,sha256:successorBridgeActualSha};
143
+ const developmentRoot=await mutableCore(active);
144
+ const localFull=await probeR36FullSurface({packageRoot:active.release_root,generationRoot:active.generation_root,stateRoot});
145
+ const url=await publicUrl();
146
+ let publicCompact,autonomous;
147
+ try{
148
+ publicCompact=await runR36CompactParity(url);
149
+ autonomous=parseJsonOutput((await run(process.execPath,[path.join(root,'src','remote-mcp-autonomous-smoke-client.mjs'),url],{timeoutMs:900000})).stdout,'R39 autonomous compact parity');
150
+ assert(autonomous.status==='passed'&&autonomous.signed_release_verified===true,'R39 autonomous compact parity failed');
151
+ }catch(error){await disarmAll().catch(()=>{});throw error;}
152
+
153
+ await disarmAll();
154
+ const beforeRollback=await probeR36CompactDisarmed(url);
155
+ const rollbackPair=await scheduleDeferred('rollback',path.resolve(activationReceiptPath));
156
+ const predecessor=await pointer();
157
+ assert(predecessor.release_id===R39_PREDECESSOR_RELEASE_ID&&predecessor.manifest_sha256===R39_PREDECESSOR_MANIFEST&&predecessor.version==='0.11.2','rollback did not reach exact sealed R39 predecessor');
158
+ const predecessorDisarmed=await publicR39Disarmed(url);
159
+ const stageRestore=await restoreFrozenStage({developmentRoot,releaseRoot:active.release_root,expectedManifestSha256:candidateManifest});
160
+ const restorePair=await scheduleDeferred('activate',candidateManifest,{bridgeRoot:successorBridge.root,bridgeScriptSha256:successorBridge.sha256});
161
+ const successor=await pointer();
162
+ assert(successor.version==='0.11.3'&&successor.manifest_sha256===candidateManifest,'restore did not return exact R39 candidate');
163
+ const successorDisarmed=await probeR36CompactDisarmed(url);
164
+ await disarmAll();
165
+
166
+ const evidence={
167
+ schema:'deadbyte.r39-parity.v1',status:'passed',completed_at_utc:new Date().toISOString(),execution_provider:'deadbyte_mcp',rdc_operation_count:0,
168
+ candidate:{release_id:active.release_id,version:active.version,manifest_sha256:candidateManifest},
169
+ immutable_slot:{protected:true,release_root:path.resolve(active.release_root),development_root:developmentRoot},
170
+ local_full:localFull,public_compact:publicCompact,autonomous,before_rollback_disarmed:beforeRollback,
171
+ rollback:{...rollbackPair.completed,scheduled_operation_id:rollbackPair.scheduled.operation_id},
172
+ predecessor:{release_id:predecessor.release_id,version:predecessor.version,manifest_sha256:predecessor.manifest_sha256},predecessor_disarmed:predecessorDisarmed,
173
+ stage_restore:stageRestore,
174
+ restore:{...restorePair.completed,scheduled_operation_id:restorePair.scheduled.operation_id},
175
+ successor:{release_id:successor.release_id,version:successor.version,manifest_sha256:successor.manifest_sha256},successor_disarmed:successorDisarmed,
176
+ requirements:{
177
+ tree_read:publicCompact.tree_entries>=0&&publicCompact.coding_stat_verified===true,
178
+ precondition_mutation:publicCompact.machine_fs_receipts_verified>=3,
179
+ search:publicCompact.coding_search_result_count>=1&&publicCompact.observation_search_result_count>=1,
180
+ owned_process:typeof publicCompact.process_session_id==='string'&&publicCompact.process_output_bytes>0,
181
+ observation:publicCompact.observation_receipts_verified>=2,
182
+ coding_loop:publicCompact.coding_receipts_verified===2,
183
+ autonomy:autonomous.signed_release_verified===true&&autonomous.observed_failure_before_replan===true,
184
+ interrupted_recovery:rollbackPair.completed.state==='completed'&&restorePair.completed.state==='completed',
185
+ evidence_verification:publicCompact.machine_fs_receipts_verified>=3&&autonomous.signed_release_verified===true,
186
+ compact_closure:publicCompact.capability_closure===true&&successorDisarmed.capability_closure===true,
187
+ full_surface:localFull.tool_count===76&&localFull.strict_output_schemas===true
188
+ }
189
+ };
190
+ validateParityEvidence(evidence);
191
+ const evidenceDir=path.join(stateRoot,'evidence','release');await mkdir(evidenceDir,{recursive:true});
192
+ const evidencePath=path.join(evidenceDir,`r39-parity-${candidateManifest.slice(0,16)}.json`);
193
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');await writeFile(evidencePath,bytes);
194
+ return {evidence,evidence_path:evidencePath,evidence_sha256:sha256(bytes)};
195
+ }
196
+
197
+ if(process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url)){
198
+ const receipt=process.argv[2];if(!receipt) throw new Error('usage: node scripts/release-parity-r39.mjs <activation-receipt.json>');
199
+ runReleaseParity(receipt).then(result=>console.log(JSON.stringify({status:'passed',...result},null,2))).catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
200
+ }
@@ -0,0 +1,9 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 2.0
3
+ $root = Split-Path -Parent $PSScriptRoot
4
+ Push-Location $root
5
+ try {
6
+ & node.exe --test test\controller.test.mjs test\r39-finalization.test.mjs test\release-version.test.mjs test\r37-0110-history.test.mjs test\r37-agent-fabric.test.mjs test\remote-live-log-r37.test.mjs test\remote-session-cli.test.mjs test\r36-finalization.test.mjs test\r36-release-identity.test.mjs test\deferred-slot-operation.test.mjs
7
+ if ($LASTEXITCODE -ne 0) { throw "R39 release parity tests failed with exit code $LASTEXITCODE" }
8
+ Write-Output 'R39 RELEASE PARITY TEST PASS'
9
+ } finally { Pop-Location }
@@ -0,0 +1,52 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { mkdir, open, readFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { fileURLToPath } from 'node:url';
6
+
7
+ const here=path.dirname(fileURLToPath(import.meta.url));
8
+ const root=path.resolve(here,'..');
9
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
10
+ const marker='DEADBYTE V0.11.3 / R39 WINDOWS BATCH GATE: PASS';
11
+ function insist(ok,message){if(!ok) throw new Error(message);}
12
+
13
+ export async function writeWindowsGateEvidence({
14
+ candidateRoot=root,
15
+ stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp')),
16
+ clock=()=>new Date()
17
+ }={}){
18
+ const candidate=path.resolve(candidateRoot);
19
+ const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
20
+ const manifestSha256=sha256(manifestBytes);
21
+ const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
22
+ insist(pkg.version==='0.11.3',`Windows gate evidence requires V0.11.3, found ${pkg.version}`);
23
+ const completed=clock();
24
+ insist(completed instanceof Date&&!Number.isNaN(completed.getTime()),'Windows gate evidence clock invalid');
25
+ const evidence={
26
+ schema:'deadbyte.r39-windows-gate.v1',status:'passed',exit_code:0,version:'0.11.3',
27
+ marker,completed_at_utc:completed.toISOString(),manifest_sha256:manifestSha256
28
+ };
29
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`,'utf8');
30
+ const dir=path.join(path.resolve(stateRoot),'evidence','release');
31
+ await mkdir(dir,{recursive:true});
32
+ const file=path.join(dir,`r39-windows-gate-${manifestSha256.slice(0,16)}.json`);
33
+ try{
34
+ const handle=await open(file,'wx',0o600);
35
+ try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}
36
+ return {status:'written',path:file,sha256:sha256(bytes),manifest_sha256:manifestSha256};
37
+ }catch(error){
38
+ if(error?.code!=='EEXIST') throw error;
39
+ const existingBytes=await readFile(file);
40
+ const existing=JSON.parse(existingBytes.toString('utf8'));
41
+ insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing Windows gate evidence invalid');
42
+ insist(existing.version==='0.11.3'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing Windows gate evidence binding mismatch');
43
+ return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256};
44
+ }
45
+ }
46
+
47
+ const invoked=process.argv[1]&&path.resolve(process.argv[1])===fileURLToPath(import.meta.url);
48
+ if(invoked){
49
+ writeWindowsGateEvidence()
50
+ .then(result=>console.log(JSON.stringify(result)))
51
+ .catch(error=>{console.error(error instanceof Error?error.stack:String(error));process.exitCode=1;});
52
+ }
@@ -55,9 +55,11 @@ async function remoteContext(){
55
55
  const powershell=await requireRegular(path.join(systemRoot,'System32','WindowsPowerShell','v1.0','powershell.exe'),'Windows PowerShell');
56
56
  return {root,launcher,powershell};
57
57
  }
58
- function invokeController(ctx,command,{capture=false,allowFailure=false,echoCaptured=true,timeoutMs=null}={}){
58
+ function invokeController(ctx,command,{capture=false,allowFailure=false,echoCaptured=true,timeoutMs=null,discardOutput=false}={}){
59
+ if(capture&&discardOutput) throw new Error('invokeController cannot capture and discard output together');
59
60
  const options={
60
- stdio:capture?['ignore','pipe','pipe']:'inherit',encoding:capture?'utf8':undefined,windowsHide:false,shell:false
61
+ stdio:discardOutput?['ignore','ignore','ignore']:(capture?['ignore','pipe','pipe']:'inherit'),
62
+ encoding:capture?'utf8':undefined,windowsHide:false,shell:false
61
63
  };
62
64
  if(Number.isInteger(timeoutMs)&&timeoutMs>0) options.timeout=timeoutMs;
63
65
  const result=spawnSync(ctx.powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',ctx.launcher,command],options);
@@ -291,7 +293,9 @@ async function runRemoteSession({resumeCursor=null}={}){
291
293
  process.stdout.write('[BOOT] Runtime already ONLINE; reusing verified bridge/cloud/supervisor.\n');
292
294
  }else{
293
295
  process.stdout.write('[BOOT] Starting bridge/runtime...\n');
294
- const started=invokeController(ctx,'start',{capture:true,echoCaptured:false,timeoutMs:REMOTE_START_TIMEOUT_MS});
296
+ invokeController(ctx,'start',{discardOutput:true,timeoutMs:REMOTE_START_TIMEOUT_MS});
297
+ const started=invokeController(ctx,'status',{capture:true,echoCaptured:false,timeoutMs:REMOTE_STATUS_TIMEOUT_MS});
298
+ if(started.status!==0||!controllerRuntimeReady(started.stdout)) throw new Error('remote controller start returned without a verified ONLINE runtime');
295
299
  startText=started.stdout||'';
296
300
  }
297
301
  process.stdout.write(`${formatRemoteLifecycle('bridge_connected')}\n`);
@@ -34,14 +34,21 @@ function summarizeArgs(args){
34
34
  }
35
35
 
36
36
  const TOOL_COLUMN_WIDTH=32;
37
+ const DISPLAY_UTC_OFFSET_MINUTES=7*60;
38
+ const DISPLAY_UTC_OFFSET_LABEL='+07:00';
39
+
40
+ function displayTimestamp(ms){
41
+ const shifted=new Date(ms+DISPLAY_UTC_OFFSET_MINUTES*60*1000).toISOString();
42
+ return `${shifted.slice(0,-1)}${DISPLAY_UTC_OFFSET_LABEL}`;
43
+ }
37
44
 
38
45
  function eventTimestamp(event,clock){
39
46
  for(const value of [event?.created_at_utc,event?.observed_at_utc]){
40
47
  const parsed=Date.parse(value);
41
- if(typeof value==='string'&&Number.isFinite(parsed)) return new Date(parsed).toISOString();
48
+ if(typeof value==='string'&&Number.isFinite(parsed)) return displayTimestamp(parsed);
42
49
  }
43
50
  const value=Number(clock());
44
- return new Date(Number.isFinite(value)?value:Date.now()).toISOString();
51
+ return displayTimestamp(Number.isFinite(value)?value:Date.now());
45
52
  }
46
53
 
47
54
  export function formatRemoteToolCall(event,{clock=()=>Date.now()}={}){
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.11.2';
1
+ export const DEADBYTE_VERSION = '0.11.3';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';
@@ -21,7 +21,7 @@ test('npx CLI reports the canonical package version through --version, -v and ve
21
21
  for(const arg of ['--version','-v','version']){
22
22
  const result=spawnSync(process.execPath,[cliPath,arg],{cwd:root,encoding:'utf8',windowsHide:true});
23
23
  assert.equal(result.status,0,result.stderr);
24
- assert.equal(result.stdout.trim(),'0.11.2');
24
+ assert.equal(result.stdout.trim(),'0.11.3');
25
25
  }
26
26
  });
27
27
 
@@ -105,7 +105,7 @@ test('proof execution creates deterministic output and signed verifiable receipt
105
105
  assert.equal(result.receipt.request.schema, 'deadbyte.request.v1');
106
106
  assert.match(result.receipt.request.nonce, /^[0-9a-f]{64}$/);
107
107
  assert.match(result.receipt.request.sha256, /^[0-9a-f]{64}$/);
108
- assert.equal(result.receipt.runtime.package_version, '0.11.2');
108
+ assert.equal(result.receipt.runtime.package_version, '0.11.3');
109
109
  assert.match(result.receipt.runtime.mcp_ingress_adapter, /^(?:none|tunnel-stdio-probe-compat-v1)$/);
110
110
  assert.match(result.receipt.runtime.mcp_ingress_adapter_sha256, /^[0-9a-f]{64}$/);
111
111
  assert.match(result.receipt.runtime.mcp_ingress_mode_source_sha256, /^[0-9a-f]{64}$/);
@@ -9,9 +9,9 @@ const readme=()=>readFile(path.join(root,'README.txt'),'utf8');
9
9
 
10
10
  test('production README documents one-command stdio configs for major MCP clients',async()=>{
11
11
  const text=await readme();
12
- assert.match(text,/npx -y deadbyte-mcp@0\.11\.2 mcp/);
12
+ assert.match(text,/npx -y deadbyte-mcp@0\.11\.3 mcp/);
13
13
  assert.match(text,/CLAUDE DESKTOP/);
14
- assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.11\.2"[\s\S]*?"mcp"/);
14
+ assert.match(text,/"mcpServers"[\s\S]*?"command"\s*:\s*"npx"[\s\S]*?"-y"[\s\S]*?"deadbyte-mcp@0\.11\.3"[\s\S]*?"mcp"/);
15
15
  assert.match(text,/CURSOR/);
16
16
  assert.match(text,/\.cursor\/mcp\.json/);
17
17
  assert.match(text,/VS CODE/);
@@ -20,7 +20,7 @@ test('production README documents one-command stdio configs for major MCP client
20
20
  assert.match(text,/CODEX/);
21
21
  assert.match(text,/\[mcp_servers\.deadbyte\]/);
22
22
  assert.match(text,/command\s*=\s*"npx"/);
23
- assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.11\.2",\s*"mcp"\]/);
23
+ assert.match(text,/args\s*=\s*\["-y",\s*"deadbyte-mcp@0\.11\.3",\s*"mcp"\]/);
24
24
  });
25
25
 
26
26
  test('production README records tracer bullet, semantic scope, remote UX, safety and document extension',async()=>{