deadbyte-mcp 0.15.36 → 0.15.38
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.
- package/MANIFEST.SHA256 +70 -32
- package/PROVENANCE.json +127 -87
- package/README.txt +12 -12
- package/RELEASE.json +226 -187
- package/SBOM.cdx.json +10 -25
- package/TEST-MATRIX.json +305 -258
- package/bridge/package.json +1 -1
- package/bridge/src/bridge-health-r59.mjs +4 -3
- package/bridge/src/bridge.mjs +75 -18
- package/bridge/src/canonical-json-r60.mjs +13 -0
- package/bridge/src/r40-governor.mjs +109 -19
- package/bridge/src/reconnect-delay-r60.mjs +31 -0
- package/bridge/src/remote-call-claims-r60.mjs +157 -0
- package/bridge/src/remote-dispatch-r60.mjs +75 -0
- package/controller/deadbyte-controller.ps1 +6 -1
- package/controller/deadbyte-process-policy.json +4 -4
- package/docs/R59-PROVENANCE.json +87 -0
- package/docs/R59-RELEASE.json +187 -0
- package/docs/R59-SBOM.cdx.json +68 -0
- package/docs/R59-TEST-MATRIX.json +258 -0
- package/docs/R59-bridge-package.json +13 -0
- package/docs/R59-package-lock.json +184 -0
- package/docs/R59-package.json +106 -0
- package/docs/R59-version.mjs +6 -0
- package/docs/R60-TASK-CONTRACT.md +22 -0
- package/docs/R61-TASK-CONTRACT.md +11 -0
- package/docs/r61-reference-evidence.md +18 -0
- package/package.json +6 -3
- package/scripts/full-regression-r60.mjs +32 -0
- package/scripts/gate-windows-r60-prepublish.ps1 +74 -0
- package/scripts/gate-windows-r61-prepublish.ps1 +45 -0
- package/scripts/npm-artifact-identity-r61.mjs +22 -0
- package/scripts/npm-release-r48.mjs +21 -5
- package/scripts/r61-mixed-lane-benchmark.mjs +98 -0
- package/src/capability-snapshot.mjs +6 -2
- package/src/deadbyte-cli.mjs +89 -40
- package/src/remote-authority.mjs +56 -0
- package/src/remote-enforcement-probe-r60.mjs +17 -0
- package/src/remote-live-log.mjs +47 -7
- package/src/remote-log-decode-r60.mjs +32 -0
- package/src/remote-mcp-machine-smoke-client.mjs +19 -1
- package/src/remote-session-guardian.mjs +20 -3
- package/src/runtime-update.mjs +13 -1
- package/src/tool-audit.mjs +5 -0
- package/src/version.mjs +1 -1
- package/test/bridge-runtime-r59.test.mjs +5 -5
- package/test/commander-schema-differential-r48.test.mjs +1 -1
- package/test/r48-release-contract.test.mjs +1 -1
- package/test/r51-runtime-coherence.test.mjs +2 -2
- package/test/r58-cleanup-retention.test.mjs +9 -3
- package/test/r58-concurrent-recovery.test.mjs +9 -3
- package/test/r58-controller-live-local.test.mjs +22 -3
- package/test/r58-stale-owner.test.mjs +2 -2
- package/test/r59-release-contract.test.mjs +6 -6
- package/test/r60-authority-coherence.test.mjs +36 -0
- package/test/r60-authority-enforcement.test.mjs +28 -0
- package/test/r60-bridge-dispatch.test.mjs +119 -0
- package/test/r60-clock-discipline.test.mjs +15 -0
- package/test/r60-live-timeline.test.mjs +29 -0
- package/test/r60-reconnect-errors.test.mjs +21 -0
- package/test/r60-reconnect-jitter.test.mjs +18 -0
- package/test/r60-release-contract.test.mjs +82 -0
- package/test/r60-remote-call-recovery.test.mjs +170 -0
- package/test/r60-windows-log-decode.test.mjs +25 -0
- package/test/r61-control-lane.test.mjs +154 -0
- package/test/r61-live-timeline-bounds.test.mjs +31 -0
- package/test/r61-npm-artifact-identity.test.mjs +17 -0
- package/test/r61-release-bridge-binding.test.mjs +32 -0
- package/test/r61-release-contract.test.mjs +44 -0
- package/test/remote-live-log-r37.test.mjs +24 -7
- package/test/remote-session-cli.test.mjs +200 -43
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# R61 reference-mechanism decisions
|
|
2
|
+
|
|
3
|
+
This is a source-inspection record, not authority to copy donor code. R61 uses
|
|
4
|
+
patterns reimplemented inside existing DEADBYTE components. No donor source
|
|
5
|
+
bytes or dependencies are imported.
|
|
6
|
+
|
|
7
|
+
| Reference | Inspected source | Mechanism and comparison with DEADBYTE | License/decision |
|
|
8
|
+
| --- | --- | --- | --- |
|
|
9
|
+
| Better Remote Commander | `references/better-remote-commander/packages/relay/src/device-hub.ts`, `mcp/invoke.ts`, `NOTICE` | Replaces stale sockets, correlates call/result and uses a pong watchdog. DEADBYTE already has a single guarded Bridge dispatch and bounded reconnect; test half-open detection and shared recovery, but do not add a fleet or new relay. | Root package declares MIT; NOTICE identifies derived Desktop Commander code. ADAPT watchdog tests only; KEEP current dispatch. |
|
|
10
|
+
| CUA | `references/cua/rfcs/3007-cua-driver-lifecycle-sessions.md`, `3682-typed-native-window-sdk.md`, `libs/cua-driver/rust/crates/cua-driver-core/tests/session_lifecycle.rs` | Accepted lifecycle sessions separate cleanup from authority; typed window actions distinguish snapshot target and post-action verification. DEADBYTE already has native Desktop and stale-frame controls. Add adversarial lifecycle/fresh-observation tests only if missing. RFC 2447 is superseded and not an architecture guide. | Top-level Python metadata declares MIT; component licenses must be checked before any copying. KEEP native/adapter split; ADAPT tests. |
|
|
11
|
+
| Desktop Commander | `references/desktop-commander/dist/utils/toolHistory.js`, process handlers | History caps entries, stored output bytes and file size. DEADBYTE already bounds process retained output via policy, repairs PATHEXT, supports offset reads, cancellation and bounded operation history. LIVELOG completed identity set is unbounded presentation state. | Package declares MIT. ADAPT LIVELOG retention; KEEP process runtime. |
|
|
12
|
+
| Open Remote MCP | `references/open-remote-mcp/docs/ARCHITECTURE.md`, `apps/agent/src/index.ts`, `NOTICE.md` | Relay policy narrows, never widens local device capability. DEADBYTE signed ledger and separate local planes are stronger; add a focused relay/local enforcement test, not a second permission system. | Root package has no license field in inspected metadata; no source copying. KEEP local authority; ADAPT test. |
|
|
13
|
+
| ReMCP | `references/remcp/docs/TOOL_SELECTION_EVAL.md`, `scripts/check-distribution.mjs`, `docs/DISTRIBUTION.md` | Golden positive/negative tool-selection cases and cross-distribution identity checks. DEADBYTE already has exact catalog, release manifest and npm closure; add a small golden routing test without a new runtime dependency. | Package declares MIT. ADAPT evaluation; KEEP release machinery. |
|
|
14
|
+
| Secure Host MCP | `references/secure-host-mcp/src/workspace.ts`, `src/executor.ts`, `test/workspace.test.ts` | Rejects broad workspace roots, resolves symlink parents and bounds executor time. DEADBYTE already has explicit roots, policy-pinned profiles and native containment. Probe equivalent boundary cases; do not expose generic shell or change root policy without RED evidence. | Package declares MIT. KEEP architecture; ADAPT adversarial cases if missing. |
|
|
15
|
+
| WinRemote MCP | `references/winremote-mcp/src/winremote/security.py`, `tiers.py`, `tests/test_security_hardening.py` | Capability tiers and URL/OAuth hardening. DEADBYTE authority planes are narrower and independently revocable; OCR/tier expansion would add scope. Compare URL and Windows privilege boundary tests where current interfaces overlap. | Python metadata declares MIT. KEEP planes; REJECT OCR and tier expansion. |
|
|
16
|
+
|
|
17
|
+
Acceptance remains based on DEADBYTE's observed behavior, not donor popularity.
|
|
18
|
+
Any newly found donor gap requires a focused RED and a narrow local fix.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deadbyte-mcp",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.38",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Authenticated MCP agentic runtime with signed skills, persistent model backends, identity-bound remote devices, durable job supervision, immutable release slots, and separately revocable machine authority.",
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
"contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
|
|
43
43
|
"contained:smoke": "node src/contained-smoke.mjs",
|
|
44
44
|
"mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
|
|
45
|
-
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-
|
|
45
|
+
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r61-prepublish.ps1",
|
|
46
46
|
"authority:smoke": "node src/authority-smoke.mjs",
|
|
47
47
|
"mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
|
|
48
48
|
"mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
|
|
@@ -83,7 +83,10 @@
|
|
|
83
83
|
"r58:focused:test": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/r58-focused.ps1",
|
|
84
84
|
"r58:cross-plane:test": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/r58-cross-plane.ps1",
|
|
85
85
|
"r59:focused:test": "node --test --test-concurrency=1 test/capability-snapshot-r59.test.mjs test/capability-resolver.test.mjs test/runtime-plane-registry-r59.test.mjs test/optional-plane-degraded-r59.test.mjs test/bridge-runtime-r59.test.mjs test/controller-policy-preflight-r59.test.mjs test/r59-tool-surface-compat.test.mjs test/r58-controller-state-coherence.test.mjs",
|
|
86
|
-
"r59:release:test": "node --test --test-concurrency=1 test/r59-release-contract.test.mjs test/r59-tool-surface-compat.test.mjs test/bridge-runtime-r59.test.mjs test/controller-policy-preflight-r59.test.mjs"
|
|
86
|
+
"r59:release:test": "node --test --test-concurrency=1 test/r59-release-contract.test.mjs test/r59-tool-surface-compat.test.mjs test/bridge-runtime-r59.test.mjs test/controller-policy-preflight-r59.test.mjs",
|
|
87
|
+
"r60:focused:test": "node --test --test-concurrency=1 test/r60-authority-coherence.test.mjs test/r60-authority-enforcement.test.mjs test/r60-bridge-dispatch.test.mjs test/r60-clock-discipline.test.mjs test/r60-live-timeline.test.mjs test/r60-reconnect-errors.test.mjs test/r60-reconnect-jitter.test.mjs test/r60-remote-call-recovery.test.mjs test/r60-windows-log-decode.test.mjs test/r60-release-contract.test.mjs",
|
|
88
|
+
"r60:full:test": "node scripts/full-regression-r60.mjs",
|
|
89
|
+
"r61:focused:test": "node --test --test-concurrency=1 test/r61-release-contract.test.mjs test/r61-release-bridge-binding.test.mjs test/r61-control-lane.test.mjs test/r61-live-timeline-bounds.test.mjs test/r61-npm-artifact-identity.test.mjs test/remote-live-log-r37.test.mjs test/bridge-runtime-r59.test.mjs test/commander-schema-differential-r48.test.mjs test/package-boundary.test.mjs test/r60-bridge-dispatch.test.mjs test/r60-authority-enforcement.test.mjs"
|
|
87
90
|
},
|
|
88
91
|
"bundleDependencies": [
|
|
89
92
|
"@modelcontextprotocol/server",
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { readdir, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { spawnSync } from 'node:child_process';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
|
|
6
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const root=path.resolve(here,'..');
|
|
8
|
+
const testDir=path.join(root,'test');
|
|
9
|
+
const excluded=new Set(['full-max-catalog-r44.test.mjs','full-max-catalog-r45.test.mjs','full-max-catalog-r46.test.mjs']);
|
|
10
|
+
const files=(await readdir(testDir,{withFileTypes:true}))
|
|
11
|
+
.filter(entry=>entry.isFile()&&entry.name.endsWith('.test.mjs')&&!excluded.has(entry.name));
|
|
12
|
+
const weighted=[];
|
|
13
|
+
for(const entry of files) weighted.push({path:path.join('test',entry.name),size:(await stat(path.join(testDir,entry.name))).size});
|
|
14
|
+
weighted.sort((a,b)=>b.size-a.size||a.path.localeCompare(b.path,'en'));
|
|
15
|
+
const batchCount=16;
|
|
16
|
+
const batches=Array.from({length:batchCount},()=>[]);
|
|
17
|
+
weighted.forEach((entry,index)=>batches[index%batchCount].push(entry.path));
|
|
18
|
+
const match=process.argv.slice(2).map(String).find(arg=>/^--batch=\d+$/.test(arg));
|
|
19
|
+
const selected=match?Number(match.slice('--batch='.length)):null;
|
|
20
|
+
if(selected!==null&&(!Number.isInteger(selected)||selected<1||selected>batchCount))throw new Error(`R60 regression batch must be 1..${batchCount}`);
|
|
21
|
+
const indexes=selected===null?[...Array(batchCount).keys()]:[selected-1];
|
|
22
|
+
let total=0;
|
|
23
|
+
for(const index of indexes){
|
|
24
|
+
const batch=batches[index].sort((a,b)=>a.localeCompare(b,'en'));
|
|
25
|
+
console.log(`R60-BOUNDED-REGRESSION batch=${index+1}/${batchCount} files=${batch.length}`);
|
|
26
|
+
const result=spawnSync(process.execPath,['--test','--test-concurrency=1',...batch],{cwd:root,stdio:'inherit',windowsHide:true,shell:false});
|
|
27
|
+
if(result.error)throw result.error;
|
|
28
|
+
if(result.signal)throw new Error(`R60 regression batch ${index+1} terminated by ${result.signal}`);
|
|
29
|
+
if(result.status!==0)throw new Error(`R60 regression batch ${index+1} failed with exit code ${result.status}`);
|
|
30
|
+
total+=batch.length;
|
|
31
|
+
}
|
|
32
|
+
console.log(`R60-BOUNDED-REGRESSION PASS files=${total} batches=${indexes.length}`);
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
# R60 staged gate revision 3: final pre-package metadata seal identity
|
|
2
|
+
param(
|
|
3
|
+
[ValidateSet('all','preflight','focused','full-batch','manifest','doctor')]
|
|
4
|
+
[string]$Stage='all',
|
|
5
|
+
[ValidateRange(1,16)]
|
|
6
|
+
[int]$Batch=1
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
$ErrorActionPreference='Stop'
|
|
10
|
+
Set-StrictMode -Version 3.0
|
|
11
|
+
$root=Split-Path $PSScriptRoot -Parent
|
|
12
|
+
Set-Location -LiteralPath $root
|
|
13
|
+
|
|
14
|
+
function Invoke-NodeTest([string]$Name,[string[]]$Files){
|
|
15
|
+
Write-Host "==== $Name ===="
|
|
16
|
+
& node.exe --test --test-concurrency=1 @Files
|
|
17
|
+
if($LASTEXITCODE -ne 0){ throw "R60 prepublish gate failed at $Name exit=$LASTEXITCODE" }
|
|
18
|
+
}
|
|
19
|
+
function Invoke-Npm([string]$Name,[string[]]$NpmArgs){
|
|
20
|
+
Write-Host "==== $Name ===="
|
|
21
|
+
& npm.cmd @NpmArgs
|
|
22
|
+
if($LASTEXITCODE -ne 0){ throw "R60 prepublish gate failed at $Name exit=$LASTEXITCODE" }
|
|
23
|
+
}
|
|
24
|
+
function Assert-R60Predecessor {
|
|
25
|
+
$active=Get-Content -LiteralPath (Join-Path $env:USERPROFILE '.deadbyte-mcp\active-release.json') -Raw | ConvertFrom-Json
|
|
26
|
+
if($active.release_id -ne 'v0.15.36-090d9db3e0679c0d'){ throw "R60 predecessor release mismatch: $($active.release_id)" }
|
|
27
|
+
if($active.manifest_sha256 -ne '090d9db3e0679c0d4943f3229ecab7b9fcccbe4f767348a568c9f3bb60d1b431'){ throw 'R60 predecessor manifest mismatch' }
|
|
28
|
+
if($active.generation_manifest_sha256 -ne '6134f9f26b680e13ed545da4ab5f3020f411ea2569062fb9c154c8a7e036c9dc'){ throw 'R60 predecessor generation mismatch' }
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Assert-R60Predecessor
|
|
32
|
+
if($Stage -eq 'preflight'){
|
|
33
|
+
Write-Host '==== R60 PREPUBLISH WINDOWS GATE STAGE: PASS preflight ===='
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if($Stage -eq 'all' -or $Stage -eq 'focused'){
|
|
38
|
+
Invoke-Npm 'r60-focused' @('run','r60:focused:test')
|
|
39
|
+
if($Stage -eq 'focused'){
|
|
40
|
+
Write-Host '==== R60 PREPUBLISH WINDOWS GATE STAGE: PASS focused ===='
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if($Stage -eq 'full-batch'){
|
|
46
|
+
Write-Host "==== r60-full-regression-batch-$Batch ===="
|
|
47
|
+
& node.exe scripts/full-regression-r60.mjs "--batch=$Batch"
|
|
48
|
+
if($LASTEXITCODE -ne 0){ throw "R60 prepublish gate failed at full-batch-$Batch exit=$LASTEXITCODE" }
|
|
49
|
+
Write-Host "==== R60 PREPUBLISH WINDOWS GATE STAGE: PASS full-batch-$Batch ===="
|
|
50
|
+
return
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if($Stage -eq 'all'){
|
|
54
|
+
Invoke-Npm 'r60-full-regression' @('run','r60:full:test')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if($Stage -eq 'all' -or $Stage -eq 'manifest'){
|
|
58
|
+
Invoke-Npm 'manifest-write' @('run','manifest:write')
|
|
59
|
+
Invoke-Npm 'manifest-verify' @('run','manifest:verify')
|
|
60
|
+
if($Stage -eq 'manifest'){
|
|
61
|
+
Write-Host '==== R60 PREPUBLISH WINDOWS GATE STAGE: PASS manifest ===='
|
|
62
|
+
return
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if($Stage -eq 'all' -or $Stage -eq 'doctor'){
|
|
67
|
+
Invoke-Npm 'doctor' @('run','doctor')
|
|
68
|
+
if($Stage -eq 'doctor'){
|
|
69
|
+
Write-Host '==== R60 PREPUBLISH WINDOWS GATE STAGE: PASS doctor ===='
|
|
70
|
+
return
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
Write-Host '==== R60 PREPUBLISH WINDOWS GATE: PASS ===='
|
|
@@ -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 "R61 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 "R61 predecessor pointer missing: $pointer" }
|
|
22
|
+
$active=Get-Content -LiteralPath $pointer -Raw | ConvertFrom-Json
|
|
23
|
+
if($active.release_id -ne 'v0.15.37-1cfecd7889419da7'){ throw "R61 predecessor release mismatch: $($active.release_id)" }
|
|
24
|
+
if($active.manifest_sha256 -ne '1cfecd7889419da7800814e3a2a4ffa93d48dfdb0c344a5b7b91fe8d093230aa'){ throw 'R61 predecessor manifest mismatch' }
|
|
25
|
+
if($active.generation_manifest_sha256 -ne '54842021c75f01bf7ecbd5b10ab8a482ecf107765b45c46f9d39b12bab65eac4'){ throw 'R61 predecessor generation mismatch' }
|
|
26
|
+
if($Stage -eq 'preflight'){Write-Host '==== R61 WINDOWS GATE: PASS preflight ====';return}
|
|
27
|
+
|
|
28
|
+
if($Stage -eq 'all' -or $Stage -eq 'focused'){
|
|
29
|
+
Invoke-Npm 'r61-focused' @('run','r61:focused:test')
|
|
30
|
+
if($Stage -eq 'focused'){Write-Host '==== R61 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 '==== R61 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 '==== R61 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 '==== R61 WINDOWS GATE: PASS doctor ====';return}
|
|
44
|
+
}
|
|
45
|
+
Write-Host '==== R61 PREPUBLISH WINDOWS GATE: PASS ===='
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import {createHash} from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
const digest=(name,bytes,encoding='hex')=>createHash(name).update(bytes).digest(encoding);
|
|
4
|
+
|
|
5
|
+
export function verifyPublishedTarballIdentity({version,localBytes,registryBytes,published,tags}){
|
|
6
|
+
if(typeof version!=='string'||!/^\d+\.\d+\.\d+$/.test(version)||!Buffer.isBuffer(localBytes)||!Buffer.isBuffer(registryBytes)){
|
|
7
|
+
throw new Error('npm artifact identity inputs invalid');
|
|
8
|
+
}
|
|
9
|
+
const tarballSha256=digest('sha256',localBytes);
|
|
10
|
+
const integrity='sha512-'+digest('sha512',localBytes,'base64');
|
|
11
|
+
const shasum=digest('sha1',localBytes);
|
|
12
|
+
const dist=published?.dist??published;
|
|
13
|
+
if(published?.version!==version||dist?.integrity!==integrity||dist?.shasum!==shasum||
|
|
14
|
+
dist?.tarball!==`https://registry.npmjs.org/deadbyte-mcp/-/deadbyte-mcp-${version}.tgz`){
|
|
15
|
+
throw new Error('published registry metadata does not match the exact local tarball');
|
|
16
|
+
}
|
|
17
|
+
if(tags?.latest!==version)throw new Error(`npm latest tag mismatch: expected ${version}, got ${tags?.latest??'<missing>'}`);
|
|
18
|
+
if(digest('sha256',registryBytes)!==tarballSha256||'sha512-'+digest('sha512',registryBytes,'base64')!==integrity){
|
|
19
|
+
throw new Error('registry tarball bytes differ from the exact published local artifact');
|
|
20
|
+
}
|
|
21
|
+
return Object.freeze({tarball_sha256:tarballSha256,npm_integrity:integrity,shasum});
|
|
22
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { verifyPublishedTarballIdentity } from './npm-artifact-identity-r61.mjs';
|
|
2
3
|
import { mkdtemp, readFile, rm, unlink } from 'node:fs/promises';
|
|
3
4
|
import path from 'node:path';
|
|
4
5
|
import os from 'node:os';
|
|
@@ -58,6 +59,8 @@ const allowedUnmanifested = new Set([
|
|
|
58
59
|
|
|
59
60
|
async function main() {
|
|
60
61
|
const isVerifyOnly = process.argv.includes('--verify-only') || process.argv.includes('--dry-run');
|
|
62
|
+
const publishOnly = process.argv.includes('--publish-only');
|
|
63
|
+
if (isVerifyOnly && publishOnly) throw new Error('--publish-only conflicts with verify-only mode');
|
|
61
64
|
|
|
62
65
|
console.log(`[1/7] Reading package.json and checking registry publication status... ${isVerifyOnly ? '(MODE: VERIFY-ONLY / DRY-RUN)' : '(MODE: PUBLISH)'}`);
|
|
63
66
|
const pkg = JSON.parse(await readFile(path.join(root, 'package.json'), 'utf8'));
|
|
@@ -180,6 +183,8 @@ async function main() {
|
|
|
180
183
|
return;
|
|
181
184
|
}
|
|
182
185
|
|
|
186
|
+
const localBytes = await readFile(tarball);
|
|
187
|
+
|
|
183
188
|
console.log('[6/7] Publishing artifact to npm registry...');
|
|
184
189
|
publishAttempted = true;
|
|
185
190
|
let publishOut;
|
|
@@ -193,8 +198,15 @@ async function main() {
|
|
|
193
198
|
}
|
|
194
199
|
throw publishError;
|
|
195
200
|
}
|
|
196
|
-
const
|
|
201
|
+
const viewed = parseJson(runNpm(['view', `deadbyte-mcp@${version}`, 'version', 'dist.integrity', 'dist.shasum', 'dist.tarball', '--json'], { timeout: 120000 }));
|
|
202
|
+
const published = Array.isArray(viewed) ? viewed[0] : viewed;
|
|
203
|
+
const dist = published?.dist ?? published;
|
|
204
|
+
if(typeof dist?.tarball !== 'string')throw new Error('published registry tarball URL missing');
|
|
205
|
+
const registryResponse = await fetch(dist.tarball,{signal:AbortSignal.timeout(120000)});
|
|
206
|
+
if(!registryResponse.ok) throw new Error(`registry tarball fetch failed status=${registryResponse.status}`);
|
|
207
|
+
const registryBytes = Buffer.from(await registryResponse.arrayBuffer());
|
|
197
208
|
const tags = parseJson(runNpm(['view', 'deadbyte-mcp', 'dist-tags', '--json'], { timeout: 120000 }));
|
|
209
|
+
const identity=verifyPublishedTarballIdentity({version,localBytes,registryBytes,published,tags});
|
|
198
210
|
|
|
199
211
|
console.log('[7/7] Post-publish external registry smoke test (executed outside repo in temp)...');
|
|
200
212
|
const tempDir = os.tmpdir();
|
|
@@ -211,16 +223,20 @@ async function main() {
|
|
|
211
223
|
timeout: 300000,
|
|
212
224
|
});
|
|
213
225
|
|
|
214
|
-
|
|
215
|
-
|
|
226
|
+
if(!publishOnly){
|
|
227
|
+
console.log('[8/8] Activating the published release into the live immutable slot and waiting for verified handoff...');
|
|
228
|
+
run(node, [path.join(root, 'scripts', 'deploy-r48.mjs')], { cwd: root, timeout: 900000 });
|
|
229
|
+
}else console.log('[8/8] Publication verified; activation deliberately deferred to the separate production gate.');
|
|
216
230
|
|
|
217
231
|
releaseSucceeded = true;
|
|
218
232
|
console.log('\nRELEASE SUCCESSFUL:');
|
|
219
233
|
console.log(JSON.stringify({
|
|
220
|
-
status: 'published',
|
|
234
|
+
status: publishOnly?'published_verified_activation_pending':'published',
|
|
221
235
|
name: pkg.name,
|
|
222
236
|
version,
|
|
223
237
|
tarball: filename,
|
|
238
|
+
tarball_sha256: identity.tarball_sha256,
|
|
239
|
+
npm_integrity: identity.npm_integrity,
|
|
224
240
|
published,
|
|
225
241
|
published_output_tail: publishOut.slice(-2000),
|
|
226
242
|
dist_tags: tags,
|
|
@@ -231,7 +247,7 @@ async function main() {
|
|
|
231
247
|
}, null, 2));
|
|
232
248
|
|
|
233
249
|
} finally {
|
|
234
|
-
if (releaseSucceeded || !publishAttempted) {
|
|
250
|
+
if ((releaseSucceeded && !publishOnly) || !publishAttempted) {
|
|
235
251
|
await unlink(tarball).catch(() => {});
|
|
236
252
|
} else {
|
|
237
253
|
console.error('Release artifact preserved after failure: ' + tarball);
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import {mkdtemp,mkdir,readFile,readdir,stat,writeFile,open,rm} from 'node:fs/promises';
|
|
2
|
+
import {spawn} from 'node:child_process';
|
|
3
|
+
import {createHash} from 'node:crypto';
|
|
4
|
+
import {monitorEventLoopDelay,performance} from 'node:perf_hooks';
|
|
5
|
+
import {pathToFileURL} from 'node:url';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
const roots=process.argv.slice(2);
|
|
10
|
+
if(roots.length!==2||roots.some(item=>!path.isAbsolute(item)))throw new Error('two absolute governor module paths required');
|
|
11
|
+
const levels=(process.env.DEADBYTE_R61_BENCH_LEVELS??'1,2,4,8,16,32').split(',').map(Number);
|
|
12
|
+
if(!levels.length||levels.some(level=>![1,2,4,8,16,32].includes(level))||new Set(levels).size!==levels.length)throw new Error('benchmark levels invalid');
|
|
13
|
+
const ROUNDS=Number(process.env.DEADBYTE_R61_BENCH_ROUNDS??3),OPS=160;
|
|
14
|
+
if(!Number.isInteger(ROUNDS)||ROUNDS<3||ROUNDS>15)throw new Error('benchmark rounds must be 3..15');
|
|
15
|
+
const scratchRoot=process.env.DEADBYTE_R61_SCRATCH_ROOT;
|
|
16
|
+
if(!scratchRoot||!path.isAbsolute(scratchRoot))throw new Error('explicit absolute DEADBYTE_R61_SCRATCH_ROOT required');
|
|
17
|
+
const quant=(values,p)=>{const ordered=[...values].sort((a,b)=>a-b);return ordered[Math.max(0,Math.ceil(ordered.length*p)-1)]};
|
|
18
|
+
const sha=value=>createHash('sha256').update(value).digest('hex');
|
|
19
|
+
|
|
20
|
+
async function childOutput(){
|
|
21
|
+
const child=spawn(process.execPath,['-e','process.stdout.write("R61_CHILD_OK")'],{windowsHide:true,stdio:['ignore','pipe','pipe']});
|
|
22
|
+
let output='';for await(const chunk of child.stdout)output+=chunk;
|
|
23
|
+
const exit=await new Promise(resolve=>child.once('close',resolve));
|
|
24
|
+
if(exit!==0||output!=='R61_CHILD_OK')throw new Error('bounded child process oracle failed');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async function runCase(modulePath,level,round){
|
|
28
|
+
const {createBridgeGovernor}=await import(pathToFileURL(modulePath).href);
|
|
29
|
+
await mkdir(scratchRoot,{recursive:true});
|
|
30
|
+
const scratch=await mkdtemp(path.join(scratchRoot,'deadbyte-r61-bench-'));
|
|
31
|
+
const fixture=path.join(scratch,'fixture'),audit=path.join(scratch,'presentation.jsonl');
|
|
32
|
+
await mkdir(fixture);
|
|
33
|
+
const sample='deadbyte bounded corpus สวัสดี\n'.repeat(512);
|
|
34
|
+
for(let i=0;i<16;i++)await writeFile(path.join(fixture,`f${i}.txt`),sample);
|
|
35
|
+
const governor=createBridgeGovernor();
|
|
36
|
+
const calls=[],control=[],counts={error:0,unknown:0},peak={rss:process.memoryUsage().rss,queue:0,active:0};
|
|
37
|
+
const delay=monitorEventLoopDelay({resolution:20});delay.enable();
|
|
38
|
+
let next=0;
|
|
39
|
+
const started=performance.now();
|
|
40
|
+
async function worker(){
|
|
41
|
+
while(next<OPS){
|
|
42
|
+
const i=next++;
|
|
43
|
+
const kind=i%16;
|
|
44
|
+
const tool=kind<3?(kind===0?'machine_ping':'machine_status'):
|
|
45
|
+
kind<5?'capability_manifest':kind<8?'machine_fs_read':kind<10?'coding_search':
|
|
46
|
+
kind<12?'machine_fs_write':kind===12?'process_session_start':kind<15?'coding_file_read':'machine_process_list';
|
|
47
|
+
const t=performance.now();let ticket;
|
|
48
|
+
try{
|
|
49
|
+
ticket=await governor.acquire(tool);
|
|
50
|
+
if(tool==='machine_ping')sha(`nonce-${round}-${i}`);
|
|
51
|
+
else if(tool==='machine_status')await stat(fixture);
|
|
52
|
+
else if(tool==='capability_manifest')sha(await readFile(roots[0]));
|
|
53
|
+
else if(tool==='coding_search'){
|
|
54
|
+
const names=await readdir(fixture);
|
|
55
|
+
for(const name of names)if((await readFile(path.join(fixture,name),'utf8')).includes('bounded'))break;
|
|
56
|
+
}else if(tool==='machine_fs_write')await writeFile(path.join(scratch,`out-${i}.txt`),sample.slice(0,128));
|
|
57
|
+
else if(tool==='process_session_start')await childOutput();
|
|
58
|
+
else if(tool==='machine_process_list')os.cpus().length;
|
|
59
|
+
else await readFile(path.join(fixture,`f${i%16}.txt`));
|
|
60
|
+
const line=JSON.stringify({kind,at:i,hash:sha(String(i))})+'\n';
|
|
61
|
+
const handle=await open(audit,'a');try{await handle.writeFile(line);await handle.sync();}finally{await handle.close();}
|
|
62
|
+
}catch(error){counts.error++;throw error;}
|
|
63
|
+
finally{
|
|
64
|
+
ticket?.release();
|
|
65
|
+
const elapsed=performance.now()-t;
|
|
66
|
+
calls.push(elapsed);if(kind<3)control.push(elapsed);
|
|
67
|
+
const state=governor.snapshot();
|
|
68
|
+
peak.rss=Math.max(peak.rss,process.memoryUsage().rss);
|
|
69
|
+
peak.queue=Math.max(peak.queue,...Object.values(state).map(value=>value.queued));
|
|
70
|
+
peak.active=Math.max(peak.active,...Object.values(state).map(value=>value.active));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
try{
|
|
75
|
+
await Promise.all(Array.from({length:level},()=>worker()));
|
|
76
|
+
await governor.close();
|
|
77
|
+
const total=performance.now()-started;
|
|
78
|
+
return {level,round,n:calls.length,throughput_ops_s:OPS*1000/total,p50_ms:quant(calls,.5),p95_ms:quant(calls,.95),
|
|
79
|
+
p99_ms:quant(calls,.99),max_ms:Math.max(...calls),control_p95_ms:quant(control,.95),
|
|
80
|
+
event_loop_p95_ms:delay.percentile(95)/1e6,peak_rss_bytes:peak.rss,peak_queue:peak.queue,
|
|
81
|
+
peak_active:peak.active,errors:counts.error,unknown:counts.unknown};
|
|
82
|
+
}finally{delay.disable();await rm(scratch,{recursive:true,force:true});}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const results=[];
|
|
86
|
+
for(const level of levels)for(let round=0;round<ROUNDS;round++){
|
|
87
|
+
const order=round%2===0?[0,1]:[1,0];
|
|
88
|
+
for(const index of order)results.push({target:index,...await runCase(roots[index],level,round)});
|
|
89
|
+
}
|
|
90
|
+
const report={schema:'deadbyte.r61.mixed-lane-benchmark.v1',node:process.version,platform:process.platform,
|
|
91
|
+
governor_sha256:await Promise.all(roots.map(async value=>sha(await readFile(value)))),levels,rounds:ROUNDS,operations_per_run:OPS,
|
|
92
|
+
limitations:['direct governor and real scratch I/O, not full MCP transport','presentation traffic is fsynced fixture data, not signed audit'],results};
|
|
93
|
+
const outputPath=process.env.DEADBYTE_R61_BENCH_OUTPUT;
|
|
94
|
+
if(outputPath){
|
|
95
|
+
if(!path.isAbsolute(outputPath))throw new Error('benchmark output must be absolute');
|
|
96
|
+
await writeFile(outputPath,JSON.stringify(report,null,2)+'\n',{flag:'wx'});
|
|
97
|
+
console.log(JSON.stringify({schema:report.schema,output_path:outputPath,result_count:results.length,governor_sha256:report.governor_sha256}));
|
|
98
|
+
}else console.log(JSON.stringify(report,null,2));
|
|
@@ -39,7 +39,12 @@ export function createCapabilitySnapshotTracker({clock=Date.now,ttlMs=5000}={}){
|
|
|
39
39
|
const body={profile,ledger_sha256:ledger.ledger_sha256,tool_catalog:[...toolCatalog],tool_count:toolCatalog.length,
|
|
40
40
|
catalog_sha256:catalogSha256,capabilities,effective_capabilities:[...(resolution.effective_capabilities??[])],
|
|
41
41
|
unavailable_capabilities:[...(resolution.unavailable_capabilities??[])],degraded_capabilities:[...(resolution.degraded_capabilities??[])],
|
|
42
|
-
bindings:safeBindings,planes:safePlanes
|
|
42
|
+
bindings:safeBindings,planes:safePlanes,
|
|
43
|
+
// Informational transport contract, not an authority-bearing ledger entry.
|
|
44
|
+
remote_dispatch_contract:Object.freeze({scope:'bridge_ingress_only',schema:'deadbyte.remote-dispatch.v1',
|
|
45
|
+
keyed_mutation:'same stable key and canonical payload: no duplicate dispatch; unknown post-dispatch outcome is not retried',
|
|
46
|
+
read_only_recovery:'a proven read-only interrupted call may re-execute under its original deadline',
|
|
47
|
+
keyless_mutation:'cross-reconnect logical retry safety unavailable; ambiguous outcome is not auto-replayed'})};
|
|
43
48
|
const fingerprint=sha(body);
|
|
44
49
|
if(fingerprint!==lastFingerprint){stateEpoch++;lastFingerprint=fingerprint;lastSnapshotId=sha({fingerprint,state_epoch:stateEpoch});}
|
|
45
50
|
const observed=Number(clock());
|
|
@@ -49,4 +54,3 @@ export function createCapabilitySnapshotTracker({clock=Date.now,ttlMs=5000}={}){
|
|
|
49
54
|
}
|
|
50
55
|
return Object.freeze({snapshot});
|
|
51
56
|
}
|
|
52
|
-
|