deadbyte-mcp 0.15.39 → 0.15.42

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 (100) hide show
  1. package/DEADBYTE-MCP.cmd +8 -4
  2. package/MANIFEST.SHA256 +99 -45
  3. package/PROVENANCE.json +90 -20
  4. package/README.txt +39 -18
  5. package/RELEASE.json +85 -20
  6. package/SBOM.cdx.json +2 -2
  7. package/TEST-MATRIX.json +134 -34
  8. package/bridge/package.json +1 -1
  9. package/controller/deadbyte-controller.ps1 +132 -12
  10. package/controller/deadbyte-process-policy.json +4 -4
  11. package/docs/R64-EVIDENCE.json +95 -0
  12. package/docs/R64-REFERENCE-GAP-MATRIX.json +98 -0
  13. package/docs/R64-SCOPE.json +41 -0
  14. package/docs/R65-AUTHORITY-CONTINUITY-DESIGN.json +27 -0
  15. package/docs/R65-REFERENCE-GAP-MATRIX.json +22 -0
  16. package/package.json +7 -4
  17. package/scripts/deploy-r48.mjs +123 -7
  18. package/scripts/gate-windows-r63-prepublish.ps1 +45 -0
  19. package/scripts/gate-windows-r64-prepublish.ps1 +68 -0
  20. package/scripts/gate-windows-r65-prepublish.ps1 +65 -0
  21. package/scripts/npm-publication-r65.mjs +139 -0
  22. package/scripts/npm-release-r48.mjs +62 -37
  23. package/scripts/r64-predecessor-reproducer.mjs +32 -0
  24. package/scripts/r64-read-benchmark.mjs +84 -0
  25. package/scripts/r65-canonical-full.mjs +45 -0
  26. package/scripts/r65-focused.mjs +37 -0
  27. package/scripts/verify-r65-parent-source.mjs +75 -0
  28. package/src/activation-continuity-engine-r65.mjs +225 -0
  29. package/src/activation-lock-r65.mjs +155 -0
  30. package/src/activation-preflight-r65.mjs +197 -0
  31. package/src/authority-continuity-r65.mjs +541 -0
  32. package/src/authority-epoch-cli-r65.mjs +10 -0
  33. package/src/autonomous-policy.mjs +7 -3
  34. package/src/coding-plane.mjs +12 -3
  35. package/src/compact-gateway-mcp-tools.mjs +1 -1
  36. package/src/deadbyte-cli.mjs +16 -2
  37. package/src/desktop-policy-r40.mjs +6 -3
  38. package/src/doctor-transactions-r58.mjs +1 -1
  39. package/src/host-plane.mjs +9 -3
  40. package/src/machine-fs-mcp-tools.mjs +1 -1
  41. package/src/machine-fs.mjs +7 -4
  42. package/src/process-policy.mjs +7 -4
  43. package/src/remote-authority.mjs +20 -1
  44. package/src/runtime-update.mjs +15 -5
  45. package/src/version.mjs +1 -1
  46. package/test/audit-context.test.mjs +15 -4
  47. package/test/autonomous-local-supervisor.test.mjs +7 -6
  48. package/test/autonomous-supervisor-integration.test.mjs +8 -7
  49. package/test/capability-resolver.test.mjs +11 -5
  50. package/test/codex-autonomous-r44.test.mjs +7 -6
  51. package/test/coding-observation.test.mjs +4 -3
  52. package/test/commander-real-parity-r47.test.mjs +5 -4
  53. package/test/commander-torture-r47.test.mjs +5 -4
  54. package/test/desktop-policy-r40.test.mjs +6 -4
  55. package/test/desktop-runtime-r40.test.mjs +8 -3
  56. package/test/host-inline-r45.test.mjs +4 -3
  57. package/test/machine-fs-runtime.test.mjs +4 -3
  58. package/test/process-longrun-r36.test.mjs +3 -2
  59. package/test/process-policy.test.mjs +10 -6
  60. package/test/process-runtime.test.mjs +9 -6
  61. package/test/r52-host-revocation.test.mjs +1 -0
  62. package/test/r59-tool-surface-compat.test.mjs +14 -4
  63. package/test/r62-release-contract.test.mjs +2 -1
  64. package/test/r63-one-shot-coherence.test.mjs +38 -0
  65. package/test/r63-release-contract.test.mjs +59 -0
  66. package/test/r64-machine-fs-large-read.test.mjs +136 -0
  67. package/test/r64-release-contract.test.mjs +52 -0
  68. package/test/r65-activation-lock-recovery.test.mjs +72 -0
  69. package/test/r65-activation-lock.test.mjs +59 -0
  70. package/test/r65-activation-orchestration.test.mjs +179 -0
  71. package/test/r65-activation-preflight.test.mjs +35 -0
  72. package/test/r65-authority-continuity-decision.test.mjs +58 -0
  73. package/test/r65-authority-durable-policy-binding.test.mjs +34 -0
  74. package/test/r65-authority-epoch-cli.test.mjs +125 -0
  75. package/test/r65-authority-epoch-races.test.mjs +87 -0
  76. package/test/r65-authority-epoch-recovery.test.mjs +82 -0
  77. package/test/r65-authority-epoch-store.test.mjs +94 -0
  78. package/test/r65-authority-fixture.mjs +41 -0
  79. package/test/r65-authority-grant-capture.test.mjs +37 -0
  80. package/test/r65-authority-observation-epoch.test.mjs +25 -0
  81. package/test/r65-authority-policy-envelope.test.mjs +46 -0
  82. package/test/r65-authority-restored-safe.test.mjs +75 -0
  83. package/test/r65-authority-runtime-epoch.test.mjs +115 -0
  84. package/test/r65-authority-runtime-policy-binding.test.mjs +29 -0
  85. package/test/r65-authority-test-trust.mjs +20 -0
  86. package/test/r65-cli-invocation.test.mjs +38 -0
  87. package/test/r65-controller-authority-epoch-live.test.mjs +100 -0
  88. package/test/r65-controller-authority-epoch.test.mjs +37 -0
  89. package/test/r65-deploy-preflight.test.mjs +55 -0
  90. package/test/r65-epoch-native-activation-integration.test.mjs +141 -0
  91. package/test/r65-epoch-native-continuity-engine.test.mjs +112 -0
  92. package/test/r65-epoch-native-cross-plane.test.mjs +95 -0
  93. package/test/r65-legacy-authority-migration.test.mjs +63 -0
  94. package/test/r65-legacy-auto-restore-rejection.test.mjs +17 -0
  95. package/test/r65-npm-publication.test.mjs +114 -0
  96. package/test/r65-parent-source-verifier.test.mjs +63 -0
  97. package/test/r65-release-contract.test.mjs +74 -0
  98. package/test/r65-transaction-precondition.test.mjs +36 -0
  99. package/test/remote-session-cli.test.mjs +13 -11
  100. package/test/standing-grants.test.mjs +20 -4
@@ -1,17 +1,91 @@
1
- import { createHash } from 'node:crypto';
2
- import { readFile, access } from 'node:fs/promises';
1
+ import { createHash,randomBytes } from 'node:crypto';
2
+ import { readFile, access,open,mkdir,unlink,lstat } from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { spawnSync } from 'node:child_process';
6
6
  import { fileURLToPath } from 'node:url';
7
- import { runSlotUpdateCli } from '../src/runtime-update.mjs';
7
+ import { runSlotUpdateCli,windowsPowerShellEnvironment,loadPowerShellDataFile } from '../src/runtime-update.mjs';
8
8
  import { parseActivePointer } from '../src/release-slot.mjs';
9
+ import {parseAuthorityObservation} from '../src/remote-authority.mjs';
10
+ import {classifyActivationPreflight,classifyAuthorityContinuity,orchestrateActivation} from '../src/activation-preflight-r65.mjs';
11
+ import {createEpochNativeContinuityEngine} from '../src/activation-continuity-engine-r65.mjs';
12
+ import {createActivationClaimManager} from '../src/activation-lock-r65.mjs';
9
13
 
10
14
  const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
11
15
  const state=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
12
16
  const sha=async f=>createHash('sha256').update(await readFile(f)).digest('hex');
13
17
  const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
14
18
 
19
+ async function writeExclusive(file,value){
20
+ const handle=await open(file,'wx',0o600);
21
+ try{await handle.writeFile(JSON.stringify(value)+'\n');await handle.sync();}
22
+ finally{await handle.close();}
23
+ }
24
+
25
+ const activationClaimManager=createActivationClaimManager({stateRoot:state});
26
+ let activationClaimOperationId=null;
27
+
28
+ async function claimActivation(subjectSha256){
29
+ const claim=await activationClaimManager.claim(subjectSha256);
30
+ activationClaimOperationId=claim.operation_id;
31
+ return claim.release;
32
+ }
33
+
34
+ async function activePolicyPaths(){
35
+ const active=parseActivePointer(await readFile(path.join(state,'active-release.json'),'utf8'));
36
+ const config=await loadPowerShellDataFile(active.config_path);
37
+ const fields={process:'ProcessPolicyFile',coding:'CodingPolicyFile',autonomous:'AutonomousPolicyFile',desktop:'DesktopPolicyFile',host:'HostPolicyFile'};
38
+ return Object.fromEntries(Object.entries(fields).map(([plane,key])=>{
39
+ const file=config[key];
40
+ return [plane,typeof file==='string'&&path.isAbsolute(file)?path.resolve(file):null];
41
+ }));
42
+ }
43
+
44
+ async function observeController(){
45
+ const launcher=path.join(state,'bin','DEADBYTE-MCP.ps1');
46
+ const powershell=path.join(process.env.SystemRoot||'C:\\Windows','System32','WindowsPowerShell','v1.0','powershell.exe');
47
+ const run=spawnSync(powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,'status','-Json'],{
48
+ cwd:root,env:windowsPowerShellEnvironment(),encoding:'utf8',timeout:20000,stdio:['ignore','pipe','pipe'],windowsHide:true});
49
+ if(run.error||run.status!==0)throw new Error(`activation preflight controller observation failed exit=${run.status} code=${run.error?.code??'none'}`);
50
+ const observed=parseAuthorityObservation(run.stdout);
51
+ const active=parseActivePointer(await readFile(path.join(state,'active-release.json'),'utf8'));
52
+ const policyPaths=await activePolicyPaths(),policySha256={};
53
+ for(const [plane,file] of Object.entries(policyPaths)){
54
+ if(!observed.authority[plane].configured){policySha256[plane]=null;continue;}
55
+ if(typeof file!=='string'||!path.isAbsolute(file))throw new Error(`activation ${plane} policy path missing`);
56
+ const info=await lstat(file);
57
+ if(!info.isFile()||info.isSymbolicLink())throw new Error(`activation ${plane} policy must be a regular file`);
58
+ policySha256[plane]=await sha(file);
59
+ }
60
+ return {...observed,policy_sha256:policySha256,policy_paths:policyPaths,active_release_id:active.release_id,active_manifest_sha256:active.manifest_sha256,
61
+ active_generation_manifest_sha256:active.generation_manifest_sha256};
62
+ }
63
+
64
+ function controllerCommand(command){
65
+ if(!/^(?:arm|disarm)(?:process|coding|autonomous|desktop|host)$|^supervisorstop$|^stop$/.test(command))throw new Error('activation controller command not declared');
66
+ const launcher=path.join(state,'bin','DEADBYTE-MCP.ps1');
67
+ const powershell=path.join(process.env.SystemRoot||'C:\\Windows','System32','WindowsPowerShell','v1.0','powershell.exe');
68
+ const run=spawnSync(powershell,['-NoLogo','-NoProfile','-ExecutionPolicy','Bypass','-File',launcher,command],{
69
+ cwd:root,env:windowsPowerShellEnvironment(),encoding:'utf8',timeout:30000,stdio:['ignore','pipe','pipe'],windowsHide:true});
70
+ if(run.error||run.status!==0)throw new Error(`activation controller ${command} failed exit=${run.status} code=${run.error?.code??'none'}`);
71
+ }
72
+
73
+ async function activationPreflight(manifest,pkg,pointer){
74
+ const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
75
+ const observed=await observeController();
76
+ const result=classifyActivationPreflight({pointer,expectedParent:release.parent,
77
+ candidate:{version:pkg.version,manifest_sha256:manifest},
78
+ expectedCandidate:{version:release.version,manifest_sha256:manifest},observation:observed});
79
+ const continuity=classifyAuthorityContinuity(observed);
80
+ if(continuity.state==='UNVERIFIED')return {...result,state:'AUTHORITY_CONTINUITY_UNVERIFIED',safe_to_activate:false,
81
+ reason:continuity.reason??'authority continuity observation unverified',authority_continuity:'UNVERIFIED',reauth_planes:continuity.reauth_planes??[]};
82
+ if(continuity.state==='EPOCH_NATIVE')return {...result,authority_continuity:'EPOCH_NATIVE',
83
+ epoch_planes:continuity.epoch_planes??[],reauth_planes:[]};
84
+ if(continuity.state==='LEGACY_REAUTH_REQUIRED'||continuity.state==='MIXED_REAUTH_REQUIRED')
85
+ return {...result,authority_continuity:'REAUTH_REQUIRED',reauth_planes:continuity.reauth_planes??continuity.armed_planes??[]};
86
+ return {...result,authority_continuity:'NOT_APPLICABLE',reauth_planes:[]};
87
+ }
88
+
15
89
  async function waitForActivation({handoffPath,expectedVersion,expectedManifest,timeoutMs=900000,pollMs=1000}){
16
90
  const evidenceDir=path.dirname(path.resolve(handoffPath));
17
91
  const statePath=path.join(evidenceDir,'state.json');
@@ -62,6 +136,15 @@ const bridgeRoot=path.join(root,'bridge');
62
136
  const bridgeScript=path.join(bridgeRoot,'src','bridge.mjs');
63
137
  const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
64
138
  const expectedVersion=pkg.version;
139
+ const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
140
+ const preflight=await activationPreflight(manifest,pkg,pointer);
141
+ if(process.argv.includes('--preflight')){
142
+ console.log(JSON.stringify(preflight));
143
+ process.exit(0);
144
+ }
145
+ if(process.argv.length>2)throw new Error('deploy accepts only --preflight');
146
+ if(!['ONLINE_READY','ONLINE_HOST_ARMED','PARKED_DIRTY','OFFLINE_CLEAN'].includes(preflight.state))
147
+ throw new Error(`activation preflight rejected: ${preflight.state} subject=${preflight.subject_sha256??'<incomplete>'}`);
65
148
  const args=[
66
149
  '--stage',root,'--development-root',root,'--expected-version',expectedVersion,'--expected-manifest',manifest,
67
150
  '--process-policy',path.join(root,'controller','deadbyte-process-policy.json'),'--process-policy-sha256',await sha(path.join(root,'controller','deadbyte-process-policy.json')),
@@ -70,9 +153,40 @@ const args=[
70
153
  '--bridge-root',bridgeRoot,'--bridge-script-sha256',await sha(bridgeScript),
71
154
  '--enable-machine-fs','--enable-observation','--enable-desktop','--enable-autonomous-supervisor','--recover-offline-predecessor'
72
155
  ];
73
- const result=await runSlotUpdateCli(args,{stateRoot:state});
74
- if(!result.handed_off) throw new Error('release activation unexpectedly completed inline; refusing to skip post-activation verification');
75
- const verification=await waitForActivation({handoffPath:result.handoff_path,expectedVersion,expectedManifest:manifest});
156
+ let result=null,verification=null,activationOutcomePath=null;
157
+ let continuityEngine=null,continuityUpdateId=null;
158
+
159
+ async function recordActivationOutcome(outcome){
160
+ if(typeof activationClaimOperationId!=='string')throw new Error('activation claim operation id unavailable');
161
+ const outcomeFile=path.join(state,'evidence','updates',`r65-activation-outcome-${Date.now()}-${randomBytes(8).toString('hex')}.json`);
162
+ await writeExclusive(outcomeFile,{schema:'deadbyte.r65-activation-outcome.v1',claim_operation_id:activationClaimOperationId,
163
+ candidate_version:expectedVersion,candidate_manifest_sha256:manifest,
164
+ predecessor_release_id:pointer.release_id,preflight_subject_sha256:preflight.subject_sha256,outcome,
165
+ update_id:result?.update_id??null,continuity_update_id:continuityUpdateId,
166
+ state_path:result?.state_path??null,observed_at_utc:new Date().toISOString()});
167
+ activationOutcomePath=outcomeFile;
168
+ }
169
+
170
+ if(preflight.authority_continuity==='EPOCH_NATIVE'){
171
+ const predecessorObservation=await observeController();
172
+ continuityUpdateId=`r65-${randomBytes(16).toString('hex')}`;
173
+ continuityEngine=createEpochNativeContinuityEngine({stateRoot:state,predecessorPolicyPaths:predecessorObservation.policy_paths,
174
+ successorPolicyPaths:async()=>activePolicyPaths(),updateId:continuityUpdateId});
175
+ }
176
+ const outcome=await orchestrateActivation({pointer,expectedParent:release.parent,
177
+ candidate:{version:expectedVersion,manifest_sha256:manifest},expectedCandidate:{version:release.version,manifest_sha256:manifest},
178
+ observe:async()=>observeController(),command:async command=>controllerCommand(command),claim:claimActivation,continuityEngine,
179
+ recordOutcome:recordActivationOutcome,
180
+ activate:async()=>{
181
+ result=await runSlotUpdateCli(args,{stateRoot:state});
182
+ if(!result.handed_off)throw new Error('release activation unexpectedly completed inline');
183
+ verification=await waitForActivation({handoffPath:result.handoff_path,expectedVersion,expectedManifest:manifest});
184
+ return {verified:true,release_id:verification.release_id};
185
+ }});
186
+ if(outcome.state!=='ACTIVATED'){
187
+ console.log(JSON.stringify({...outcome,update_id:result?.update_id??null,state_path:result?.state_path??null,outcome_path:activationOutcomePath}));
188
+ process.exitCode=2;
189
+ }else{
76
190
  console.log(JSON.stringify({
77
191
  status:'activated',
78
192
  manifest_sha256:manifest,
@@ -81,5 +195,7 @@ console.log(JSON.stringify({
81
195
  supervisor_pid:result.supervisor_pid,
82
196
  release_id:verification.release_id,
83
197
  receipt_path:verification.receiptPath,
84
- state_path:verification.statePath
198
+ state_path:verification.statePath,
199
+ outcome_path:activationOutcomePath
85
200
  },null,2));
201
+ }
@@ -0,0 +1,45 @@
1
+ param(
2
+ [ValidateSet('all','preflight','focused','full','manifest','doctor')]
3
+ [string]$Stage='all'
4
+ )
5
+
6
+ $ErrorActionPreference='Stop'
7
+ Set-StrictMode -Version 3.0
8
+ $root=Split-Path $PSScriptRoot -Parent
9
+ Set-Location -LiteralPath $root
10
+
11
+ function Invoke-Npm([string]$Name,[string[]]$NpmArgs){
12
+ Write-Host "==== $Name ===="
13
+ & npm.cmd @NpmArgs
14
+ if($LASTEXITCODE -ne 0){ throw "R63 prepublish gate failed at $Name exit=$LASTEXITCODE" }
15
+ }
16
+
17
+ $stateRoot=if(-not [string]::IsNullOrWhiteSpace($env:DEADBYTE_STATE_ROOT)){
18
+ [IO.Path]::GetFullPath($env:DEADBYTE_STATE_ROOT)
19
+ }else{ Join-Path $env:USERPROFILE '.deadbyte-mcp' }
20
+ $pointer=Join-Path $stateRoot 'active-release.json'
21
+ if(-not (Test-Path -LiteralPath $pointer -PathType Leaf)){ throw "R63 predecessor pointer missing: $pointer" }
22
+ $active=Get-Content -LiteralPath $pointer -Raw | ConvertFrom-Json
23
+ if($active.release_id -ne 'v0.15.39-3cda3b1c65b7b7c5'){ throw "R63 predecessor release mismatch: $($active.release_id)" }
24
+ if($active.manifest_sha256 -ne '3cda3b1c65b7b7c561c5a8617156ab87d69cf162f447f3e99a4cb4a76471b3de'){ throw 'R63 predecessor manifest mismatch' }
25
+ if($active.generation_manifest_sha256 -ne 'f47cb96083679e764725df1bde6eda53169a39f55772c173ab22f89a1dfaa7ab'){ throw 'R63 predecessor generation mismatch' }
26
+ if($Stage -eq 'preflight'){Write-Host '==== R63 WINDOWS GATE: PASS preflight ====';return}
27
+
28
+ if($Stage -eq 'all' -or $Stage -eq 'focused'){
29
+ Invoke-Npm 'r63-focused' @('run','r63:focused:test')
30
+ if($Stage -eq 'focused'){Write-Host '==== R63 WINDOWS GATE: PASS focused ====';return}
31
+ }
32
+ if($Stage -eq 'all' -or $Stage -eq 'full'){
33
+ Invoke-Npm 'full-regression' @('test')
34
+ if($Stage -eq 'full'){Write-Host '==== R63 WINDOWS GATE: PASS full ====';return}
35
+ }
36
+ if($Stage -eq 'all' -or $Stage -eq 'manifest'){
37
+ Invoke-Npm 'manifest-write' @('run','manifest:write')
38
+ Invoke-Npm 'manifest-verify' @('run','manifest:verify')
39
+ if($Stage -eq 'manifest'){Write-Host '==== R63 WINDOWS GATE: PASS manifest ====';return}
40
+ }
41
+ if($Stage -eq 'all' -or $Stage -eq 'doctor'){
42
+ Invoke-Npm 'doctor' @('run','doctor')
43
+ if($Stage -eq 'doctor'){Write-Host '==== R63 WINDOWS GATE: PASS doctor ====';return}
44
+ }
45
+ Write-Host '==== R63 PREPUBLISH WINDOWS GATE: PASS ===='
@@ -0,0 +1,68 @@
1
+ param(
2
+ [ValidateSet('all','preflight','focused','full','manifest','doctor')]
3
+ [string]$Stage='all'
4
+ )
5
+
6
+ $ErrorActionPreference='Stop'
7
+ Set-StrictMode -Version 3.0
8
+ $root=Split-Path $PSScriptRoot -Parent
9
+ Set-Location -LiteralPath $root
10
+
11
+ function Invoke-Npm([string]$Name,[string[]]$NpmArgs){
12
+ Write-Host "==== $Name ===="
13
+ & npm.cmd @NpmArgs
14
+ if($LASTEXITCODE -ne 0){ throw "R64 prepublish gate failed at $Name exit=$LASTEXITCODE" }
15
+ }
16
+
17
+ function Get-FileSha256([string]$File){
18
+ $hasher=[Security.Cryptography.SHA256]::Create()
19
+ try{
20
+ $bytes=[IO.File]::ReadAllBytes($File)
21
+ return (($hasher.ComputeHash($bytes) | ForEach-Object { $_.ToString('x2') }) -join '')
22
+ }finally{ $hasher.Dispose() }
23
+ }
24
+
25
+ $sourceRoot='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.40-r63'
26
+ $sourceManifest='d6f75feada9ad0ae2c248b3a833ac9cf0e04150d2430ddaa70b3dfb64a0b0a86'
27
+ if(-not (Test-Path -LiteralPath $sourceRoot -PathType Container)){ throw 'R64 source predecessor missing' }
28
+ $observedSourceManifest=Get-FileSha256 (Join-Path $sourceRoot 'MANIFEST.SHA256')
29
+ if($observedSourceManifest -ne $sourceManifest){ throw 'R64 source predecessor manifest identity mismatch' }
30
+ Push-Location -LiteralPath $sourceRoot
31
+ try{
32
+ & npm.cmd run manifest:verify
33
+ if($LASTEXITCODE -ne 0){ throw 'R64 source predecessor manifest verification failed' }
34
+ }finally{ Pop-Location }
35
+
36
+ $stateRoot=Join-Path $env:USERPROFILE '.deadbyte-mcp'
37
+ $pointer=Join-Path $stateRoot 'active-release.json'
38
+ if(-not (Test-Path -LiteralPath $pointer -PathType Leaf)){ throw "R64 runtime predecessor pointer missing: $pointer" }
39
+ $active=Get-Content -LiteralPath $pointer -Raw | ConvertFrom-Json
40
+ if($active.release_id -ne 'v0.15.39-3cda3b1c65b7b7c5'){ throw "R64 runtime predecessor release mismatch: $($active.release_id)" }
41
+ if($active.manifest_sha256 -ne '3cda3b1c65b7b7c561c5a8617156ab87d69cf162f447f3e99a4cb4a76471b3de'){ throw 'R64 runtime predecessor manifest mismatch' }
42
+ if($active.generation_manifest_sha256 -ne 'f47cb96083679e764725df1bde6eda53169a39f55772c173ab22f89a1dfaa7ab'){ throw 'R64 runtime predecessor generation mismatch' }
43
+ if($Stage -eq 'preflight'){Write-Host '==== R64 WINDOWS GATE: PASS preflight ====';return}
44
+
45
+ if($Stage -eq 'all' -or $Stage -eq 'focused'){
46
+ Invoke-Npm 'r64-focused' @('run','r64:focused:test')
47
+ if($Stage -eq 'focused'){Write-Host '==== R64 WINDOWS GATE: PASS focused ====';return}
48
+ }
49
+ if($Stage -eq 'all' -or $Stage -eq 'full'){
50
+ Invoke-Npm 'full-regression' @('test')
51
+ if($Stage -eq 'full'){Write-Host '==== R64 WINDOWS GATE: PASS full ====';return}
52
+ }
53
+ if($Stage -eq 'all' -or $Stage -eq 'manifest'){
54
+ Invoke-Npm 'manifest-write' @('run','manifest:write')
55
+ Invoke-Npm 'manifest-verify' @('run','manifest:verify')
56
+ if($Stage -eq 'manifest'){Write-Host '==== R64 WINDOWS GATE: PASS manifest ====';return}
57
+ }
58
+ if($Stage -eq 'all' -or $Stage -eq 'doctor'){
59
+ $doctorRoot='D:\Projects\deadbyte-mcp\testing\0.15.41-r64\doctor-isolated-empty'
60
+ if(Test-Path -LiteralPath (Join-Path $doctorRoot 'active-release.json')){ throw 'R64 isolated doctor root unexpectedly contains a release pointer' }
61
+ $priorStateRoot=$env:DEADBYTE_STATE_ROOT
62
+ try{
63
+ $env:DEADBYTE_STATE_ROOT=$doctorRoot
64
+ Invoke-Npm 'doctor-isolated-empty-state' @('run','doctor')
65
+ }finally{ $env:DEADBYTE_STATE_ROOT=$priorStateRoot }
66
+ if($Stage -eq 'doctor'){Write-Host '==== R64 WINDOWS GATE: PASS doctor ====';return}
67
+ }
68
+ Write-Host '==== R64 PREPUBLISH WINDOWS GATE: PASS ===='
@@ -0,0 +1,65 @@
1
+ param(
2
+ [ValidateSet('all','preflight','focused','full','manifest','doctor')]
3
+ [string]$Stage='all'
4
+ )
5
+
6
+ $ErrorActionPreference='Stop'
7
+ Set-StrictMode -Version 3.0
8
+ $root=Split-Path $PSScriptRoot -Parent
9
+ Set-Location -LiteralPath $root
10
+
11
+ function Invoke-Npm([string]$Name,[string[]]$NpmArgs){
12
+ Write-Host "==== $Name ===="
13
+ & npm.cmd @NpmArgs
14
+ if($LASTEXITCODE -ne 0){ throw "R65 prepublish gate failed at $Name exit=$LASTEXITCODE" }
15
+ }
16
+
17
+ function Get-FileSha256([string]$File){
18
+ $hasher=[Security.Cryptography.SHA256]::Create()
19
+ try{
20
+ $bytes=[IO.File]::ReadAllBytes($File)
21
+ return (($hasher.ComputeHash($bytes) | ForEach-Object { $_.ToString('x2') }) -join '')
22
+ }finally{ $hasher.Dispose() }
23
+ }
24
+
25
+ $sourceRoot='D:\Projects\deadbyte-mcp\development\deadbyte-mcp-0.15.41-r64'
26
+ $sourceManifest='63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e'
27
+ if(-not (Test-Path -LiteralPath $sourceRoot -PathType Container)){ throw 'R65 source predecessor missing' }
28
+ $observedSourceManifest=Get-FileSha256 (Join-Path $sourceRoot 'MANIFEST.SHA256')
29
+ if($observedSourceManifest -ne $sourceManifest){ throw 'R65 source predecessor manifest identity mismatch' }
30
+ & node (Join-Path $root 'scripts\\verify-r65-parent-source.mjs') --root $sourceRoot --expected-manifest-sha256 $sourceManifest
31
+ if($LASTEXITCODE -ne 0){ throw 'R65 source predecessor declared-manifest verification failed' }
32
+
33
+ $stateRoot=Join-Path $env:USERPROFILE '.deadbyte-mcp'
34
+ $pointer=Join-Path $stateRoot 'active-release.json'
35
+ if(-not (Test-Path -LiteralPath $pointer -PathType Leaf)){ throw "R65 runtime predecessor pointer missing: $pointer" }
36
+ $active=Get-Content -LiteralPath $pointer -Raw | ConvertFrom-Json
37
+ if($active.release_id -ne 'v0.15.41-63a78ad159ad3003'){ throw "R65 runtime predecessor release mismatch: $($active.release_id)" }
38
+ if($active.manifest_sha256 -ne '63a78ad159ad3003db3fefafcd468bef22599c829a867f4f10a46c7a20748b3e'){ throw 'R65 runtime predecessor manifest mismatch' }
39
+ if($active.generation_manifest_sha256 -ne '19ae2efcdcde9f80c474f0e55851d4ada51c22813d3e05af03b11acb28c3fca5'){ throw 'R65 runtime predecessor generation mismatch' }
40
+ if($Stage -eq 'preflight'){Write-Host '==== R65 WINDOWS GATE: PASS preflight ====';return}
41
+
42
+ if($Stage -eq 'all' -or $Stage -eq 'focused'){
43
+ Invoke-Npm 'r65-focused' @('run','r65:focused:test')
44
+ if($Stage -eq 'focused'){Write-Host '==== R65 WINDOWS GATE: PASS focused ====';return}
45
+ }
46
+ if($Stage -eq 'all' -or $Stage -eq 'full'){
47
+ Invoke-Npm 'full-regression' @('test')
48
+ if($Stage -eq 'full'){Write-Host '==== R65 WINDOWS GATE: PASS full ====';return}
49
+ }
50
+ if($Stage -eq 'all' -or $Stage -eq 'manifest'){
51
+ Invoke-Npm 'manifest-write' @('run','manifest:write')
52
+ Invoke-Npm 'manifest-verify' @('run','manifest:verify')
53
+ if($Stage -eq 'manifest'){Write-Host '==== R65 WINDOWS GATE: PASS manifest ====';return}
54
+ }
55
+ if($Stage -eq 'all' -or $Stage -eq 'doctor'){
56
+ $doctorRoot='D:\Projects\deadbyte-mcp\testing\0.15.42-r65\doctor-isolated-empty'
57
+ if(Test-Path -LiteralPath (Join-Path $doctorRoot 'active-release.json')){ throw 'R65 isolated doctor root unexpectedly contains a release pointer' }
58
+ $priorStateRoot=$env:DEADBYTE_STATE_ROOT
59
+ try{
60
+ $env:DEADBYTE_STATE_ROOT=$doctorRoot
61
+ Invoke-Npm 'doctor-isolated-empty-state' @('run','doctor')
62
+ }finally{ $env:DEADBYTE_STATE_ROOT=$priorStateRoot }
63
+ if($Stage -eq 'doctor'){Write-Host '==== R65 WINDOWS GATE: PASS doctor ====';return}
64
+ }
65
+ Write-Host '==== R65 PREPUBLISH WINDOWS GATE: PASS ===='
@@ -0,0 +1,139 @@
1
+ import {createHash, randomBytes} from 'node:crypto';
2
+ import {mkdir, open, readFile, readdir, link, unlink} from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import {performance} from 'node:perf_hooks';
5
+ import {verifyPublishedTarballIdentity} from './npm-artifact-identity-r61.mjs';
6
+
7
+ const HEX64=/^[0-9a-f]{64}$/;
8
+ const digest=bytes=>createHash('sha256').update(bytes).digest('hex');
9
+ const pause=ms=>new Promise(resolve=>setTimeout(resolve,ms));
10
+
11
+ async function writeExclusive(file,value){
12
+ const handle=await open(file,'wx',0o600);
13
+ try{await handle.writeFile(JSON.stringify(value)+'\n');await handle.sync();}
14
+ finally{await handle.close();}
15
+ }
16
+
17
+ async function publishClaim(file,value){
18
+ const temporary=`${file}.private-${process.pid}-${randomBytes(8).toString('hex')}`;
19
+ try{
20
+ await writeExclusive(temporary,value);
21
+ await link(temporary,file); // Atomic, no-clobber visibility of complete bytes.
22
+ }finally{
23
+ await unlink(temporary).catch(error=>{if(error?.code!=='ENOENT')throw error;});
24
+ }
25
+ }
26
+
27
+ async function readClaim(file){
28
+ try{return JSON.parse(await readFile(file,'utf8'));}
29
+ catch(error){
30
+ if(error?.code==='ENOENT')return null;
31
+ if(error instanceof SyntaxError)return {incomplete:true};
32
+ throw error;
33
+ }
34
+ }
35
+
36
+ async function event(recordPath,state,detail={}){
37
+ const file=path.join(recordPath,`event-${Date.now()}-${randomBytes(8).toString('hex')}.json`);
38
+ await writeExclusive(file,{schema:'deadbyte.npm-publication-event.r65.v1',state,at_utc:new Date().toISOString(),...detail});
39
+ }
40
+
41
+ async function priorState(recordPath){
42
+ const names=(await readdir(recordPath)).filter(name=>/^event-\d+-[0-9a-f]{16}\.json$/.test(name));
43
+ if(names.length>1024)throw new Error('npm publication evidence event budget exceeded');
44
+ const states=[];
45
+ for(const name of names){
46
+ const value=JSON.parse(await readFile(path.join(recordPath,name),'utf8'));
47
+ if(value.schema!=='deadbyte.npm-publication-event.r65.v1')throw new Error('npm publication event schema invalid');
48
+ states.push(value);
49
+ }
50
+ return states;
51
+ }
52
+
53
+ function result(state,extra={}){return Object.freeze({state,...extra});}
54
+
55
+ // The no-clobber claim is the dispatch fence: once it exists, no invocation may
56
+ // submit the same immutable npm version again, even if the first process dies.
57
+ export async function reconcileNpmPublication({recordPath,version,manifestSha256,localBytes,publish,lookup,tags,fetchTarball,
58
+ timeoutMs=180000,pollMs=1500,sleep=pause,now=()=>performance.now()}){
59
+ if(!path.isAbsolute(recordPath)||!/^\d+\.\d+\.\d+$/.test(version)||!HEX64.test(String(manifestSha256))||!Buffer.isBuffer(localBytes)||
60
+ !Number.isSafeInteger(timeoutMs)||timeoutMs<0||timeoutMs>900000||!Number.isSafeInteger(pollMs)||pollMs<1||pollMs>30000||
61
+ [publish,lookup,tags,fetchTarball,sleep,now].some(fn=>typeof fn!=='function'))throw new Error('npm publication reconciliation inputs invalid');
62
+ const tarballSha256=digest(localBytes);
63
+ if(!HEX64.test(tarballSha256))throw new Error('npm tarball digest invalid');
64
+ await mkdir(recordPath,{recursive:true});
65
+ const claimFile=path.join(recordPath,'claim.json');
66
+ let claim=await readClaim(claimFile);
67
+ if(claim?.incomplete)return result('OUTCOME_UNKNOWN',{reason:'publication claim incomplete; manual reconciliation required'});
68
+ if(claim&&(claim.schema!=='deadbyte.npm-publication-claim.r65.v1'||claim.version!==version||claim.manifest_sha256!==manifestSha256||claim.tarball_sha256!==tarballSha256))
69
+ return result('REGISTRY_REJECTED',{reason:'local artifact differs from existing immutable publication claim'});
70
+
71
+ const observe=async()=>{
72
+ let published;
73
+ try{published=await lookup();}
74
+ catch(error){if(error?.code==='E404'||error?.status===404)return null;throw error;}
75
+ if(!published)return null;
76
+ let registryBytes;
77
+ try{registryBytes=await fetchTarball(published);}
78
+ catch(error){if(error?.status===404||error?.code==='E404')throw Object.assign(new Error('registry tarball is still processing'),{code:'REGISTRY_PROCESSING'});throw error;}
79
+ const distTags=await tags();
80
+ const identity=verifyPublishedTarballIdentity({version,localBytes,registryBytes,published,tags:distTags});
81
+ return {identity,registry:{version:published.version,integrity:published.dist?.integrity,shasum:published.dist?.shasum,
82
+ tarball:published.dist?.tarball,latest:distTags.latest}};
83
+ };
84
+ const check=async()=>{
85
+ try{const evidence=await observe();return evidence?result('REGISTRY_IDENTITY_VERIFIED',evidence):null;}
86
+ catch(error){
87
+ if(error?.code==='REGISTRY_PROCESSING')return result('REGISTRY_PROCESSING');
88
+ if(/metadata does not match|bytes differ|latest tag mismatch/.test(String(error?.message)))return result('REGISTRY_REJECTED',{reason:String(error.message)});
89
+ return result('OUTCOME_UNKNOWN',{reason:String(error?.code??error?.message??error)});
90
+ }
91
+ };
92
+
93
+ let observed=await check();
94
+ if(observed?.state==='REGISTRY_IDENTITY_VERIFIED'||observed?.state==='REGISTRY_REJECTED'){
95
+ if(claim)await event(recordPath,observed.state,{tarball_sha256:tarballSha256,registry:observed.registry??null});
96
+ return observed;
97
+ }
98
+ if(!claim){
99
+ if(observed)return observed; // Registry outage: do not submit while identity is unknown.
100
+ let created=false;
101
+ try{
102
+ await publishClaim(claimFile,{schema:'deadbyte.npm-publication-claim.r65.v1',version,manifest_sha256:manifestSha256,tarball_sha256:tarballSha256,created_at_utc:new Date().toISOString()});
103
+ claim={version,manifest_sha256:manifestSha256,tarball_sha256:tarballSha256};created=true;
104
+ }catch(error){
105
+ if(error?.code!=='EEXIST')throw error;
106
+ claim=await readClaim(claimFile);
107
+ if(claim?.incomplete||!claim)return result('OUTCOME_UNKNOWN',{reason:'concurrent publication claim unavailable or incomplete'});
108
+ if(claim.version!==version||claim.manifest_sha256!==manifestSha256||claim.tarball_sha256!==tarballSha256)return result('REGISTRY_REJECTED',{reason:'concurrent publication claim differs'});
109
+ }
110
+ // Only the creator of the claim may dispatch publish.
111
+ if(created){
112
+ await event(recordPath,'SUBMISSION_STARTED',{tarball_sha256:tarballSha256});
113
+ try{
114
+ await publish();
115
+ await event(recordPath,'SUBMISSION_ACCEPTED',{tarball_sha256:tarballSha256});
116
+ }catch(error){
117
+ const auth=/E401|E403|EOTP|authentication|one-time password|2FA/i.test(String(error?.code??'')+' '+String(error?.message??''));
118
+ await event(recordPath,auth?'AUTH_REQUIRED':'OUTCOME_UNKNOWN',{error_code:String(error?.code??'UNKNOWN').slice(0,64)});
119
+ return result(auth?'AUTH_REQUIRED':'OUTCOME_UNKNOWN',{reason:String(error?.code??error?.message??error)});
120
+ }
121
+ }
122
+ }
123
+ const states=await priorState(recordPath);
124
+ if(states.some(item=>item.state==='AUTH_REQUIRED'))return result('AUTH_REQUIRED');
125
+ const accepted=states.some(item=>item.state==='SUBMISSION_ACCEPTED');
126
+ const started=now();
127
+ do{
128
+ observed=await check();
129
+ if(observed?.state==='REGISTRY_IDENTITY_VERIFIED'||observed?.state==='REGISTRY_REJECTED'){
130
+ await event(recordPath,observed.state,{tarball_sha256:tarballSha256,registry:observed.registry??null});return observed;
131
+ }
132
+ if(observed?.state==='OUTCOME_UNKNOWN')return observed;
133
+ const remaining=timeoutMs-(now()-started);
134
+ if(remaining<=0)break;
135
+ await sleep(Math.min(pollMs,remaining));
136
+ }while(true);
137
+ await event(recordPath,accepted?'REGISTRY_PROCESSING':'OUTCOME_UNKNOWN',{tarball_sha256:tarballSha256});
138
+ return result(accepted?'REGISTRY_PROCESSING':'OUTCOME_UNKNOWN');
139
+ }