deadbyte-mcp 0.15.23 → 0.15.25

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 (50) hide show
  1. package/MANIFEST.SHA256 +49 -40
  2. package/PROVENANCE.json +11 -10
  3. package/README.txt +7 -7
  4. package/RELEASE.json +19 -38
  5. package/TEST-MATRIX.json +32 -96
  6. package/package.json +3 -3
  7. package/proof/commander-closure-20260928/DIFFERENTIAL-CHECKPOINT.json +122 -0
  8. package/scripts/commander-hardening-gate-r47.mjs +10 -1
  9. package/scripts/commander-real-performance-benchmark-r47.mjs +12 -3
  10. package/scripts/gate-windows-r48.ps1 +45 -0
  11. package/scripts/init-host-policy.ps1 +9 -1
  12. package/scripts/npm-release-r48.mjs +2 -1
  13. package/scripts/windows-gate-evidence-r48.mjs +27 -0
  14. package/src/atomic-mutation.mjs +12 -4
  15. package/src/coding-mcp-tools.mjs +15 -1
  16. package/src/coding-output-contracts.mjs +9 -3
  17. package/src/commander-office-reader-r48.mjs +36 -3
  18. package/src/commander-pdf-r48.mjs +36 -1
  19. package/src/commander-wire-adapter-r47.mjs +72 -2
  20. package/src/host-plane.mjs +10 -31
  21. package/src/machine-fs-mcp-tools.mjs +7 -1
  22. package/src/machine-fs-output-contracts.mjs +6 -0
  23. package/src/machine-fs-smoke-client.mjs +6 -17
  24. package/src/mcp-host-smoke-client.mjs +3 -2
  25. package/src/mcp-server.mjs +14 -2
  26. package/src/mcp-smoke-client.mjs +4 -9
  27. package/src/observation-smoke-client.mjs +5 -10
  28. package/src/output-contracts.mjs +6 -4
  29. package/src/process-smoke-client.mjs +3 -3
  30. package/src/runtime-catalog-expectation.mjs +37 -0
  31. package/src/stdio-protocol-guard.mjs +71 -0
  32. package/src/tunnel-stdio-compat-smoke.mjs +5 -9
  33. package/src/version.mjs +1 -1
  34. package/test/atomic-mutation.test.mjs +61 -0
  35. package/test/coding-catalog-consistency.test.mjs +9 -1
  36. package/test/coding-mcp-unknown-effect.test.mjs +42 -0
  37. package/test/commander-biff-reference-r48.test.mjs +38 -0
  38. package/test/commander-core-bridge-r47.test.mjs +19 -0
  39. package/test/commander-office-reader-r48.test.mjs +18 -2
  40. package/test/commander-pdf-r48.test.mjs +35 -0
  41. package/test/commander-protocol-adversarial-r48.test.mjs +166 -0
  42. package/test/commander-real-parity-r47.test.mjs +41 -3
  43. package/test/commander-schema-differential-r48.test.mjs +1 -1
  44. package/test/commander-wire-contract-r47.test.mjs +32 -0
  45. package/test/contained.test.mjs +4 -6
  46. package/test/controller.test.mjs +2 -1
  47. package/test/machine-fs-mcp-tools.test.mjs +12 -0
  48. package/test/output-schema.test.mjs +20 -1
  49. package/test/r48-release-contract.test.mjs +27 -27
  50. package/test/tunnel-stdio-compat.test.mjs +7 -7
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "deadbyte-mcp",
3
- "version": "0.15.23",
3
+ "version": "0.15.25",
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-r46.ps1",
45
+ "gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r48.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",
@@ -70,7 +70,7 @@
70
70
  "r47:catalog:test": "node --test --test-concurrency=1 test/full-max-catalog-r47.test.mjs",
71
71
  "r47:hardening:test": "node scripts/commander-hardening-gate-r47.mjs",
72
72
  "r48:full:test": "node scripts/full-regression-r48.mjs",
73
- "r48:release:test": "node --test --test-concurrency=1 test/r48-release-contract.test.mjs test/commander-reference-contract-r48.test.mjs test/commander-extended-wire-r48.test.mjs test/commander-external-process-r48.test.mjs test/commander-office-reader-r48.test.mjs test/commander-pdf-r48.test.mjs test/commander-url-reader-r48.test.mjs test/commander-wire-contract-r47.test.mjs",
73
+ "r48:release:test": "node --test --test-concurrency=1 test/r48-release-contract.test.mjs test/commander-reference-contract-r48.test.mjs test/commander-extended-wire-r48.test.mjs test/commander-external-process-r48.test.mjs test/commander-office-reader-r48.test.mjs test/commander-pdf-r48.test.mjs test/commander-url-reader-r48.test.mjs test/commander-wire-contract-r47.test.mjs test/commander-protocol-adversarial-r48.test.mjs",
74
74
  "r48:catalog:test": "node --test --test-concurrency=1 test/full-max-catalog-r48.test.mjs",
75
75
  "release:npm": "node scripts/npm-release-r48.mjs"
76
76
  },
@@ -0,0 +1,122 @@
1
+ {
2
+ "schema": "deadbyte.commander-differential-checkpoint.v1",
3
+ "status": "INCOMPLETE",
4
+ "observed_at_utc": "2026-09-29T13:36:00.000Z",
5
+ "source": {
6
+ "requested_path": "D:\\Projects\\deadbyte-mcp-r36-dev",
7
+ "requested_path_version": "0.12.0",
8
+ "actual_successor_workspace": "D:\\Projects\\deadbyte-mcp\\development\\deadbyte-mcp-r42-agentic-dev",
9
+ "version": "0.15.25",
10
+ "git_head": "f9037d4847a7204ce4e1f808758ee3f0e9e7a738",
11
+ "path_drift_classification": "requested source path is a historical snapshot and cannot produce a successor of active 0.15.23"
12
+ },
13
+ "reference": {
14
+ "path": "D:\\Projects\\desktop-commander-stage-20260922\\desktop-commander",
15
+ "package": "@wonderwhy-er/desktop-commander",
16
+ "version": "0.2.51",
17
+ "server_sha256": "dfc303bb7dd2e8d01debac50fc43bb8644d00089bffdf2887e149497cff8b305",
18
+ "schemas_sha256": "f342345e34e48769dabaefe1b932f09d41e2e207b422f7794a15ee50ffa8f140"
19
+ },
20
+ "live": {
21
+ "release_id": "v0.15.23-c97e3d21e792420e",
22
+ "release_manifest_sha256": "c97e3d21e792420ea90dada3c1360cd56e4c1f221daa86596d611b0d1ac351ec",
23
+ "generation_manifest_sha256": "4d2d3a4dc103576c39171c52db3436366e62d8b872bcafa4c55f2adb6d3a1126",
24
+ "bridge_pid": 2804,
25
+ "cloud_pid": 13704,
26
+ "state": "ONLINE",
27
+ "authority": "Process/Coding/Autonomous/Desktop/Host ARMED standing-grant"
28
+ },
29
+ "findings": [
30
+ {
31
+ "id": "reference-biff8",
32
+ "classification": "REFERENCE_DEFECT",
33
+ "red": "real OLE/BIFF8 fixture is rejected by the reference ExcelJS xlsx reader",
34
+ "green": "independent BIFF8 fixture test proves reference read rejection and OOXML bytes emitted under .xls",
35
+ "fixture_sha256": "096168376d0abf282546749fdf6765309f895d12fe81d45c52a2c54bb6c0d139"
36
+ },
37
+ {
38
+ "id": "incremental-pdf-revisions",
39
+ "classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
40
+ "red": "valid independent-oracle-readable incremental PDF failed with PDF duplicate object 3 0",
41
+ "green": "latest revision accepted only when both revisions are bound by a validated classic xref Prev chain; PDF suite 10/10 PASS"
42
+ },
43
+ {
44
+ "id": "powershell-command-byte-preservation",
45
+ "classification": "OBSERVED_PASS",
46
+ "green": "real policy-bound PowerShell REPL preserved variables, quotes, pipe and Unicode and returned more than 1 MiB through bounded chunk reads"
47
+ },
48
+ {
49
+ "id": "atomic-mutation-post-effect-observation",
50
+ "classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
51
+ "red": "machine filesystem, coding, and Host public boundaries collapsed a post-rename observation failure into a generic denied/failed response without uncertainty identity",
52
+ "green": "shared atomic mutation marks FAILED_AFTER_UNKNOWN_EFFECT with unknown side-effect state and expected-after SHA-256; machine filesystem, coding, and Host structured outputs preserve it"
53
+ },
54
+ {
55
+ "id": "read-file-directory-and-binary-semantics",
56
+ "classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
57
+ "red": "reference returns a bounded recursive listing for read_file(directory) and explicit binary guidance, while DEADBYTE attempted a file read or lossy UTF-8 decoding",
58
+ "green": "compatibility read_file uses policy-bound stat plus paged listing for directories and deterministic binary classification without replacement-character data loss"
59
+ },
60
+ {
61
+ "id": "docx-outline-and-content-search",
62
+ "classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
63
+ "red": "reference exposes drawing markers, header/footer text, and literal DOCX part search while DEADBYTE omitted those document parts and searched ZIP bytes",
64
+ "green": "native bounded DOCX parsing now exposes drawing/header/footer evidence and searches document/header/footer w:t parts through deterministic compatibility sessions"
65
+ },
66
+ {
67
+ "id": "interactive-output-quiescence",
68
+ "classification": "REAL_DEADBYTE_DEFECT_FIXED_IN_SOURCE",
69
+ "red": "interact_with_process returned after the first stream advance and could omit the final END marker from a 1.1 MiB response",
70
+ "green": "bounded stream-quiescence waiting plus unconditional test cleanup passed 20 consecutive real PowerShell repetitions and the expanded 139-test hardening gate"
71
+ }
72
+ ],
73
+ "focused_evidence": [
74
+ {"scope": "schema-search", "tests": 21, "pass": 21, "fail": 0, "skip": 0},
75
+ {"scope": "documents-wire-url", "tests": 49, "pass": 49, "fail": 0, "skip": 0},
76
+ {"scope": "biff-reference", "tests": 1, "pass": 1, "fail": 0, "skip": 0},
77
+ {"scope": "process-adjacent", "tests": 55, "pass": 55, "fail": 0, "skip": 0},
78
+ {"scope": "mcp-protocol", "tests": 9, "pass": 9, "fail": 0, "skip": 0},
79
+ {"scope": "mcp-protocol-adversarial", "tests": 3, "pass": 3, "fail": 0, "skip": 0},
80
+ {"scope": "atomic-mutation-public-boundaries", "tests": 15, "pass": 14, "fail": 0, "skip": 1},
81
+ {"scope": "full-regression-r48", "files": 211, "batches": 8, "fail": 0, "task_receipt_sha256": "7711039e4807f6c2af02bbda897d0032b067e0a6631f789fd3bf801258160d3f"},
82
+ {"scope": "expanded-commander-hardening", "tests": 139, "pass": 139, "fail": 0, "skip": 0},
83
+ {"scope": "powershell-large-output-repeat", "runs": 20, "pass": 20, "fail": 0},
84
+ {"scope": "npm-audit-production", "vulnerabilities": 0},
85
+ {"scope": "real-performance-sample", "iterations_per_workload": 50, "reference_byte_pins_verified": true, "status": "HISTORICAL_ONLY_FRESH_RUN_BLOCKED_REFERENCE_RUNTIME_DEPS",
86
+ "results": {"read_file": {"reference_ops_per_sec": 55, "deadbyte_ops_per_sec": 1058}, "list_directory": {"reference_ops_per_sec": 3818, "deadbyte_ops_per_sec": 1959}, "get_file_info": {"reference_ops_per_sec": 1805, "deadbyte_ops_per_sec": 2231}, "read_multiple_files": {"reference_ops_per_sec": 30, "deadbyte_ops_per_sec": 562}}}
87
+ ,{"scope": "filesystem-document-search-adjacent", "tests": 54, "pass": 54, "fail": 0, "skip": 0}
88
+ ],
89
+ "changed_file_sha256": {
90
+ "src/commander-pdf-r48.mjs": "23cda18e86daa4163003fb5a80e0069bc19541d454f32a9a38b1d901ee39f26b",
91
+ "src/coding-search.mjs": "7f15b59bc240d896beddc2057354f8c72f296fe189db30c200d2c84a67d65773",
92
+ "src/commander-wire-adapter-r47.mjs": "a32226e302669553d39565176fc7ef9a0ace24834d2c19d3558ba33f13016ba0",
93
+ "src/commander-office-reader-r48.mjs": "7379825118da8fae16d63fe7c4d89b0ddb03e7649f3754adae58a4480f8b317f",
94
+ "test/commander-pdf-r48.test.mjs": "bfc2e6d7e1aa5332c1c81687001cdb5f923a45c5ce64925097fe11fd850e9214",
95
+ "test/commander-biff-reference-r48.test.mjs": "8e8b20604062a0398214e159729b10bedff334cb44bddfa4b4046b1ae396520f",
96
+ "test/commander-schema-differential-r48.test.mjs": "fb82a21e8752ccb82cbd6b631f3366bfe5af9a4c5a433db5a128c0a1fe703c66",
97
+ "test/commander-real-parity-r47.test.mjs": "5709ea1cf4e65c4f1759206123216cac6cb66d8a383c0b0a6c00f4a551d9c727"
98
+ ,"test/commander-wire-contract-r47.test.mjs": "d8e884e241c705b12797f911fb967a4a33b1ec6f3e15b433735882b3de4a34e5"
99
+ ,"test/commander-office-reader-r48.test.mjs": "abf1eb0977a064101420a0e908a4c2adbf9d606e9873433709910efafa2b4453"
100
+ ,"test/commander-core-bridge-r47.test.mjs": "16092ed097420b9da99573c1e84f62d011fcb5db069242d70ffd1649c704fd35"
101
+ ,"src/atomic-mutation.mjs": "622ee1d3c34c50a6343788cc7312e47cb43a87bdace78fb37ca7f51d453b19ad"
102
+ ,"src/machine-fs-mcp-tools.mjs": "5413fea537f9d72f73e89137b4c750530fbca41598b16bd9ede0e1c272111488"
103
+ ,"src/machine-fs-output-contracts.mjs": "d94e4478b7e465fa559065e508f65b9ef3eff815a8f2d7b2481bf2a0b05224c9"
104
+ ,"src/coding-mcp-tools.mjs": "c4e07aa6818cd989c43ce8d027dc7d467e05c8e2fe96b5548eea291285d3bbb1"
105
+ ,"src/coding-output-contracts.mjs": "059b4bef2ae6a6c2d7a706c463bea6e49d364faeb619372a429ba36c53004ab7"
106
+ ,"src/host-plane.mjs": "0ff88bce7ee34b22f48a1494efb16586b68c74bd46c608116eb9d9daa65fdc43"
107
+ ,"src/output-contracts.mjs": "6cbe72d14af097dde78e989bc7b28b48b9cb8990c989d0d40783633f3a7be465"
108
+ ,"src/mcp-server.mjs": "16e2250e20710b358b304a0bc41bb416ecb9a586c50d5933f6a4eb2230569b21"
109
+ ,"test/atomic-mutation.test.mjs": "98de1fc43092c27e0fa85f391607494b11e6cc0d53eaf47b6db1ab457c6d6a4b"
110
+ ,"test/coding-mcp-unknown-effect.test.mjs": "f37e260c2def4c48434b3f251a4cb756a1852843784c08cf6c39dba9045dfb69"
111
+ ,"scripts/commander-real-performance-benchmark-r47.mjs": "d7806aa408dc7ca74f05feec535ad6cc545f8c61892c51f0fe388bb13d975290"
112
+ ,"scripts/commander-hardening-gate-r47.mjs": "6d6e18b2a17448dad569dfbf60ac103c6c8bcfe73c49af93506816c3c0b7fe73"
113
+ ,"src/stdio-protocol-guard.mjs": "71e0ddc5e7abaedbb4659bdfb91b6e2db43a642cbec83eee62c16fb069a3c202"
114
+ ,"test/commander-protocol-adversarial-r48.test.mjs": "bacb96828ea0431cd5f3a8ecb637894f0bdf80b5f52e9308ba0cbb982f50bd2a"
115
+ },
116
+ "release_created": true,
117
+ "candidate_version": "0.15.25",
118
+ "publish_attempt": {"status":"PENDING_AUTH","npm_whoami":"E401 Unauthorized","registry_predecessor_version":"0.15.24","registry_predecessor_tarball_sha256":"23ea53fb4f331873c742c810f815d5ad18291f74c1bda1fd1d8c08475dbbd4ad"},
119
+ "published": false,
120
+ "activated": false,
121
+ "remaining_scope": "restore npm authentication, registry round-trip, successor activation, exact 0.15.23 rollback, exact successor restore and independent final closure"
122
+ }
@@ -13,7 +13,16 @@ const suites = [
13
13
  'test/commander-exhaustive-surface-r47.test.mjs',
14
14
  'test/commander-core-bridge-r47.test.mjs',
15
15
  'test/commander-wire-contract-r47.test.mjs',
16
- 'test/commander-protocol-r47.test.mjs'
16
+ 'test/commander-reference-contract-r48.test.mjs',
17
+ 'test/commander-schema-differential-r48.test.mjs',
18
+ 'test/commander-biff-reference-r48.test.mjs',
19
+ 'test/commander-office-reader-r48.test.mjs',
20
+ 'test/commander-pdf-r48.test.mjs',
21
+ 'test/commander-url-reader-r48.test.mjs',
22
+ 'test/commander-external-process-r48.test.mjs',
23
+ 'test/commander-protocol-r47.test.mjs',
24
+ 'test/commander-protocol-adversarial-r48.test.mjs',
25
+ 'test/prompts-resources.test.mjs'
17
26
  ];
18
27
 
19
28
  const startedAt = new Date().toISOString();
@@ -1,5 +1,5 @@
1
1
  import { performance } from 'node:perf_hooks';
2
- import { mkdtemp, writeFile, rm } from 'node:fs/promises';
2
+ import { mkdtemp, writeFile, readFile, rm } from 'node:fs/promises';
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import { createHash } from 'node:crypto';
@@ -9,7 +9,16 @@ import { loadCodingPolicy } from '../src/coding-plane.mjs';
9
9
  import { createMachineFsRuntime } from '../src/machine-fs.mjs';
10
10
 
11
11
  const N=50;
12
- const commanderFs=await import(pathToFileURL('D:/Projects/desktop-commander-stage-20260922/desktop-commander/dist/tools/filesystem.js').href);
12
+ const referenceRoot=path.resolve(process.env.DEADBYTE_COMMANDER_REFERENCE_RUNTIME??'D:/Projects/desktop-commander-stage-20260922/desktop-commander');
13
+ const expectedReferenceHashes={
14
+ 'dist/server.js':'dfc303bb7dd2e8d01debac50fc43bb8644d00089bffdf2887e149497cff8b305',
15
+ 'dist/tools/schemas.js':'f342345e34e48769dabaefe1b932f09d41e2e207b422f7794a15ee50ffa8f140'
16
+ };
17
+ for(const [relative,expected] of Object.entries(expectedReferenceHashes)){
18
+ const actual=createHash('sha256').update(await readFile(path.join(referenceRoot,relative))).digest('hex');
19
+ if(actual!==expected)throw new Error(`reference byte pin mismatch: ${relative}`);
20
+ }
21
+ const commanderFs=await import(pathToFileURL(path.join(referenceRoot,'dist','tools','filesystem.js')).href);
13
22
  const { readFileFromDisk, readMultipleFiles, listDirectory, getFileInfo }=commanderFs;
14
23
  const sha=b=>createHash('sha256').update(b).digest('hex');
15
24
  const root=await mkdtemp(path.join(os.tmpdir(),'deadbyte-commander-bench-'));
@@ -37,5 +46,5 @@ rows.push(await t('Commander get_file_info',()=>getFileInfo(commanderFile)));
37
46
  rows.push(await t('DEADBYTE get_file_info',()=>db.stat({rootId:'bench',relativePath:'a.txt',hash:true})));
38
47
  rows.push(await t('Commander read_multiple_files',()=>readMultipleFiles([path.join(commanderDir,'a.txt'),path.join(commanderDir,'b.txt')])));
39
48
  rows.push(await t('DEADBYTE read_multiple_files', async()=>{ await db.read({rootId:'bench',relativePath:'a.txt',offset:0,maxBytes:4096}); await db.read({rootId:'bench',relativePath:'b.txt',offset:0,maxBytes:4096}); }));
40
- console.log(JSON.stringify({schema:'deadbyte.commander-real-performance-benchmark.v1',reference:'@wonderwhy-er/desktop-commander dist local stage',iterations:N,rows},null,2));
49
+ console.log(JSON.stringify({schema:'deadbyte.commander-real-performance-benchmark.v1',reference:'@wonderwhy-er/desktop-commander@0.2.51',reference_hashes:expectedReferenceHashes,iterations:N,rows},null,2));
41
50
  await rm(root,{recursive:true,force:true});
@@ -0,0 +1,45 @@
1
+ $ErrorActionPreference = 'Stop'
2
+ Set-StrictMode -Version 3.0
3
+
4
+ function Invoke-GateStep {
5
+ param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$NpmArgs)
6
+ Write-Host "==== $Name ===="
7
+ & npm.cmd @NpmArgs
8
+ if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.25 / R48 gate failed at $Name with exit code $LASTEXITCODE" }
9
+ }
10
+
11
+ Invoke-GateStep 'containment-build' @('run','containment:build')
12
+ Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
13
+ Invoke-GateStep 'desktop-policy-refresh' @('run','desktop:policy:refresh')
14
+ Invoke-GateStep 'hardware-build' @('run','hardware:build')
15
+
16
+ $hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
17
+ Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
18
+ if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
19
+
20
+ Invoke-GateStep 'r48-release-focused' @('run','r48:release:test')
21
+ Invoke-GateStep 'r48-catalog' @('run','r48:catalog:test')
22
+ Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
23
+ Invoke-GateStep 'full-regression' @('run','r48:full:test')
24
+ Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
25
+ Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
26
+ Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
27
+ Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
28
+ Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
29
+ Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
30
+ Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
31
+ Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
32
+ Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
33
+ Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
34
+ Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
35
+ Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
36
+ Invoke-GateStep 'manifest-write' @('run','manifest:write')
37
+ Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
38
+ Invoke-GateStep 'doctor' @('run','doctor')
39
+ Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
40
+ Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
41
+ Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
42
+
43
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r48.mjs')
44
+ if ($LASTEXITCODE -ne 0) { throw "R48 evidence writer failed with exit code $LASTEXITCODE" }
45
+ Write-Host '==== DEADBYTE 0.15.25 / R48 WINDOWS GATE: PASS ===='
@@ -10,7 +10,15 @@ Set-StrictMode -Version 3.0
10
10
  $ErrorActionPreference = 'Stop'
11
11
 
12
12
  function Get-Sha256Lower([string]$Path) {
13
- (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
13
+ $stream = [System.IO.File]::OpenRead($Path)
14
+ try {
15
+ $sha = [System.Security.Cryptography.SHA256]::Create()
16
+ try {
17
+ ([System.BitConverter]::ToString($sha.ComputeHash($stream))).Replace('-', '').ToLowerInvariant()
18
+ }
19
+ finally { $sha.Dispose() }
20
+ }
21
+ finally { $stream.Dispose() }
14
22
  }
15
23
 
16
24
  if ([string]::IsNullOrWhiteSpace($CoreRoot)) {
@@ -105,7 +105,8 @@ async function main() {
105
105
 
106
106
  console.log('[3/7] Packing artifact with npm pack...');
107
107
  const packed = parseJson(runNpm(['pack', '--json'], { timeout: 180000 }));
108
- const filename = packed?.[0]?.filename;
108
+ const packRecord = Array.isArray(packed) ? packed[0] : packed?.[pkg.name];
109
+ const filename = packRecord?.filename;
109
110
  if (!filename) throw new Error('npm pack did not return a tarball filename');
110
111
  const tarball = path.join(root, filename);
111
112
  let releaseSucceeded = false;
@@ -0,0 +1,27 @@
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
+ import {doctor} from '../src/doctor-r45.mjs';
7
+
8
+ const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
9
+ const stateRoot=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
10
+ const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
11
+ const insist=(ok,message)=>{if(!ok)throw new Error(message);};
12
+ const pkg=JSON.parse(await readFile(path.join(root,'package.json'),'utf8'));
13
+ const release=JSON.parse(await readFile(path.join(root,'RELEASE.json'),'utf8'));
14
+ const active=JSON.parse(await readFile(path.join(stateRoot,'active-release.json'),'utf8'));
15
+ const manifestSha256=sha256(await readFile(path.join(root,'MANIFEST.SHA256')));
16
+ insist(pkg.version==='0.15.25'&&release.version===pkg.version&&release.train==='R48','R48 candidate identity mismatch');
17
+ insist(active.release_id===release.parent.release_id&&active.manifest_sha256===release.parent.manifest_sha256&&active.generation_manifest_sha256===release.parent.generation_manifest_sha256,'active runtime is not the exact sealed R48 parent');
18
+ const health=await doctor();
19
+ insist(health.status==='ok'&&health.package_version===pkg.version&&health.manifest?.verified===true,'R48 doctor evidence invalid');
20
+ insist(health.policy?.host_v2_ready===true,'R48 Host policy v2 is not ready');
21
+ const evidence={schema:'deadbyte.r48-windows-gate.v1',status:'passed',exit_code:0,version:pkg.version,train:'R48',completed_at_utc:new Date().toISOString(),manifest_sha256:manifestSha256,parent:release.parent,active_predecessor:{release_id:active.release_id,version:active.version,manifest_sha256:active.manifest_sha256,generation_manifest_sha256:active.generation_manifest_sha256},doctor:{verified_entries:health.manifest.verified_entries,host_v2_ready:true},gates:{full_regression:true,commander_hardening:true,exact_catalog:true,stdio_smokes:true,manifest_final_verify:true}};
22
+ const bytes=Buffer.from(`${JSON.stringify(evidence,null,2)}\n`);
23
+ const dir=path.join(stateRoot,'evidence','release'); await mkdir(dir,{recursive:true});
24
+ const target=path.join(dir,`r48-windows-gate-${manifestSha256.slice(0,16)}.json`);
25
+ try{const handle=await open(target,'wx',0o600);try{await handle.writeFile(bytes);await handle.sync();}finally{await handle.close();}}
26
+ catch(error){if(error?.code!=='EEXIST')throw error;const prior=JSON.parse(await readFile(target,'utf8'));insist(prior.schema===evidence.schema&&prior.status==='passed'&&prior.version===evidence.version&&prior.manifest_sha256===manifestSha256&&prior.parent?.release_id===release.parent.release_id,'conflicting R48 gate evidence identity');}
27
+ console.log(JSON.stringify({status:'passed',path:target,sha256:sha256(bytes),manifest_sha256:manifestSha256}));
@@ -74,11 +74,19 @@ export async function atomicMutation({
74
74
  throw error;
75
75
  }
76
76
 
77
- const after = await readState(target);
78
77
  const expectedAfter = sha256Bytes(bytes);
79
- if (!after.exists || after.sha256 !== expectedAfter) throw new Error('atomic mutation post-commit hash mismatch');
80
- if (verifyPostcondition) await verifyPostcondition({ before, after, expected_after_sha256: expectedAfter });
81
- return { before, after, expected_after_sha256: expectedAfter };
78
+ try {
79
+ const after = await readState(target);
80
+ if (!after.exists || after.sha256 !== expectedAfter) throw new Error('atomic mutation post-commit hash mismatch');
81
+ if (verifyPostcondition) await verifyPostcondition({ before, after, expected_after_sha256: expectedAfter });
82
+ return { before, after, expected_after_sha256: expectedAfter };
83
+ } catch (error) {
84
+ const failure = error instanceof Error ? error : new Error(String(error));
85
+ failure.outcome = 'FAILED_AFTER_UNKNOWN_EFFECT';
86
+ failure.side_effect_state = 'unknown';
87
+ failure.expected_after_sha256 = expectedAfter;
88
+ throw failure;
89
+ }
82
90
  } finally {
83
91
  await releaseLock();
84
92
  }
@@ -46,7 +46,21 @@ const taskStep = z.union([
46
46
  ]);
47
47
 
48
48
  function result(schema, value, isError = false) { return codingStructuredResult(schema, value, isError); }
49
- function fail(schema, error) { return result(schema, { status: 'failed', error: String(error) }, true); }
49
+ function fail(schema, error) {
50
+ const base = { status: 'failed', error: String(error) };
51
+ if (error?.outcome === 'FAILED_AFTER_UNKNOWN_EFFECT'
52
+ && error?.side_effect_state === 'unknown'
53
+ && HEX64.test(error?.expected_after_sha256 ?? '')) {
54
+ const enriched = {
55
+ ...base,
56
+ outcome: error.outcome,
57
+ side_effect_state: error.side_effect_state,
58
+ expected_after_sha256: error.expected_after_sha256
59
+ };
60
+ if (schema.safeParse(enriched).success) return result(schema, enriched, true);
61
+ }
62
+ return result(schema, base, true);
63
+ }
50
64
  export function registerCodingTools(server, { codingRuntime, taskRuntime, semanticRuntime }) {
51
65
  if (!codingRuntime || !taskRuntime || !semanticRuntime) throw new Error('coding tool registration requires runtimes');
52
66
 
@@ -168,7 +168,9 @@ export const codingSymbolReplaceOutputSchema = statusContract({
168
168
  shape: { root_id: z.string().min(1).max(64).optional(), path: z.string().min(1).max(512).optional(), previous_sha256: hex64.optional(),
169
169
  sha256: hex64.optional(), bytes: z.number().int().min(0).optional(), replacements: z.literal(1).optional(),
170
170
  receipt_id: receiptId.optional(), receipt_sha256: hex64.optional(), request_sha256: hex64.optional(),
171
- symbol_id: hex64.optional(), symbol_name: z.string().min(1).max(256).optional(), engine: z.string().min(1).max(64).optional() },
171
+ symbol_id: hex64.optional(), symbol_name: z.string().min(1).max(256).optional(), engine: z.string().min(1).max(64).optional(),
172
+ outcome: z.literal('FAILED_AFTER_UNKNOWN_EFFECT').optional(), side_effect_state: z.literal('unknown').optional(),
173
+ expected_after_sha256: hex64.optional() },
172
174
  successStatuses: ['committed'], successRequired: ['root_id','path','previous_sha256','sha256','bytes','replacements','receipt_id','receipt_sha256','request_sha256','symbol_id','symbol_name','engine']
173
175
  });
174
176
 
@@ -189,14 +191,18 @@ export const codingFileWriteOutputSchema = statusContract({
189
191
  statuses: ['committed', 'failed'],
190
192
  shape: { root_id: z.string().min(1).max(64).optional(), path: z.string().min(1).max(512).optional(), previous_sha256: hex64.nullable().optional(),
191
193
  sha256: hex64.optional(), bytes: z.number().int().min(0).optional(), created: z.boolean().optional(), receipt_id: receiptId.optional(),
192
- receipt_sha256: hex64.optional(), request_sha256: hex64.optional() },
194
+ receipt_sha256: hex64.optional(), request_sha256: hex64.optional(),
195
+ outcome: z.literal('FAILED_AFTER_UNKNOWN_EFFECT').optional(), side_effect_state: z.literal('unknown').optional(),
196
+ expected_after_sha256: hex64.optional() },
193
197
  successStatuses: ['committed'], successRequired: ['root_id', 'path', 'previous_sha256', 'sha256', 'bytes', 'created', 'receipt_id', 'receipt_sha256', 'request_sha256']
194
198
  });
195
199
  export const codingTextReplaceOutputSchema = statusContract({
196
200
  statuses: ['committed', 'failed'],
197
201
  shape: { root_id: z.string().min(1).max(64).optional(), path: z.string().min(1).max(512).optional(), previous_sha256: hex64.optional(),
198
202
  sha256: hex64.optional(), bytes: z.number().int().min(0).optional(), replacements: z.number().int().min(1).max(64).optional(),
199
- receipt_id: receiptId.optional(), receipt_sha256: hex64.optional(), request_sha256: hex64.optional() },
203
+ receipt_id: receiptId.optional(), receipt_sha256: hex64.optional(), request_sha256: hex64.optional(),
204
+ outcome: z.literal('FAILED_AFTER_UNKNOWN_EFFECT').optional(), side_effect_state: z.literal('unknown').optional(),
205
+ expected_after_sha256: hex64.optional() },
200
206
  successStatuses: ['committed'], successRequired: ['root_id', 'path', 'previous_sha256', 'sha256', 'bytes', 'replacements', 'receipt_id', 'receipt_sha256', 'request_sha256']
201
207
  });
202
208
  export const codingCommandRunOutputSchema = statusContract({
@@ -140,7 +140,7 @@ function prettyXml(xml){
140
140
  }
141
141
  return lines.join('\n');
142
142
  }
143
- function docxOutline(xml){
143
+ function docxOutline(xml,files){
144
144
  const body=xml.match(/<w:body\b[^>]*>([\s\S]*?)<\/w:body>/)?.[1];
145
145
  if(body===undefined) return '[No w:body found in document.xml]';
146
146
  const elements=[...body.matchAll(/<w:(p|tbl)\b[\s\S]*?<\/w:\1>/g)].map(m=>({kind:m[1],xml:m[0]}));
@@ -152,6 +152,8 @@ function docxOutline(xml){
152
152
  let line=`[${i}] w:p`;
153
153
  if(style) line+=` style="${xmlDecode(style)}"`;
154
154
  const value=wordText(item.xml);
155
+ const hasDrawing=item.xml.includes('<w:drawing')||item.xml.includes('<mc:AlternateContent');
156
+ if(hasDrawing) line+=value?' (+ drawing/image)':` [drawing/image, ${(Buffer.byteLength(item.xml)/1024).toFixed(1)}KB]`;
155
157
  if(value) line+='\n '+value;
156
158
  lines.push(line);
157
159
  }else{
@@ -163,7 +165,15 @@ function docxOutline(xml){
163
165
  }
164
166
  }
165
167
  }
166
- return lines.join('\n');
168
+ const headersFooters=[];
169
+ for(const [name,bytes] of [...files.entries()].sort(([a],[b])=>a.localeCompare(b))){
170
+ if(!/^word\/(?:header|footer)[^/]*\.xml$/i.test(name)) continue;
171
+ try{
172
+ const value=wordText(decodeUtf8(bytes,name));
173
+ headersFooters.push(`${name.slice('word/'.length)}: ${value?`"${value.length>100?value.slice(0,100)+'...':value}"`:'(no text content)'}`);
174
+ }catch{/* malformed optional part is omitted; document.xml remains authoritative */}
175
+ }
176
+ return lines.join('\n')+(headersFooters.length?`\n\nHeaders/Footers:\n${headersFooters.join('\n')}`:'');
167
177
  }
168
178
 
169
179
  export function readDocxBytes(input,{path:displayPath='document.docx',offset=0,length=1000}={}){
@@ -180,11 +190,34 @@ export function readDocxBytes(input,{path:displayPath='document.docx',offset=0,l
180
190
  return {content:`[DOCX XML: lines ${start}-${Math.max(start,start+sliced.length-1)} of ${totalLines} (${remaining} remaining)]\n${sliced.join('\n')}`,
181
191
  mimeType:'application/xml',metadata:{isDocx:true,lineCount:totalLines},outline:false};
182
192
  }
183
- const outline=docxOutline(xml);
193
+ const outline=docxOutline(xml,files);
184
194
  const rawSizeKB=(Buffer.byteLength(xml)/1024).toFixed(1);
185
195
  return {content:`${outline}\n\nRaw XML: ${totalLines} lines, ${rawSizeKB}KB.`,mimeType:'text/plain',metadata:{isDocx:true,lineCount:totalLines},outline:true};
186
196
  }
187
197
 
198
+ export function searchDocxTextBytes(input,{pattern,ignoreCase=true,maxResults=500}={}){
199
+ if(typeof pattern!=='string'||pattern.length<1||pattern.length>4096) throw new Error('DOCX search pattern invalid');
200
+ if(!Number.isInteger(maxResults)||maxResults<1||maxResults>5000) throw new Error('DOCX search maxResults invalid');
201
+ const files=unzipOffice(input),needle=ignoreCase?pattern.toLowerCase():pattern,results=[];
202
+ const names=[...files.keys()].filter(name=>name==='word/document.xml'||/^word\/(?:header|footer)[^/]*\.xml$/i.test(name)).sort((a,b)=>{
203
+ if(a==='word/document.xml')return -1;if(b==='word/document.xml')return 1;return a.localeCompare(b);
204
+ });
205
+ for(const name of names){
206
+ let xml;
207
+ try{xml=decodeUtf8(files.get(name),name);}catch{continue;}
208
+ let line=0;
209
+ for(const match of xml.matchAll(/<w:t(?:\s[^>]*)?>([^<]*)<\/w:t>/g)){
210
+ const value=xmlDecode(match[1]??'');if(!value.trim())continue;line++;
211
+ const haystack=ignoreCase?value.toLowerCase():value,index=haystack.indexOf(needle);
212
+ if(index<0)continue;
213
+ const start=Math.max(0,index-50),end=Math.min(value.length,index+needle.length+50);
214
+ results.push({part:name,line,match:`${start>0?'...':''}${value.slice(start,end)}${end<value.length?'...':''}`});
215
+ if(results.length>=maxResults)return results;
216
+ }
217
+ }
218
+ return results;
219
+ }
220
+
188
221
 
189
222
  export function createDocxBytes(content){
190
223
  if(typeof content!=='string') throw new Error('DOCX content must be string');
@@ -110,6 +110,37 @@ export function parseDeadbytePdf(input){
110
110
  const MAX_GENERIC_OBJECTS=10000;
111
111
  const MAX_GENERIC_STREAM_BYTES=16*1024*1024;
112
112
 
113
+ function classicIncrementalObjectOffsets(text){
114
+ const starts=[...text.matchAll(/startxref\s+(\d+)\s+%%EOF/g)];
115
+ if(starts.length<2)return new Map();
116
+ const offsets=new Map(),visited=new Set();
117
+ let cursor=Number(starts.at(-1)[1]);
118
+ while(Number.isSafeInteger(cursor)&&cursor>=0&&!visited.has(cursor)){
119
+ visited.add(cursor);
120
+ if(text.slice(cursor,cursor+4)!=='xref')return new Map();
121
+ const trailerAt=text.indexOf('trailer',cursor+4);
122
+ if(trailerAt<0)return new Map();
123
+ const lines=text.slice(cursor+4,trailerAt).trim().split(/\r?\n/);
124
+ for(let i=0;i<lines.length;){
125
+ const header=lines[i++].trim().match(/^(\d+)\s+(\d+)$/);if(!header)return new Map();
126
+ const first=Number(header[1]),count=Number(header[2]);
127
+ if(!Number.isSafeInteger(first)||!Number.isSafeInteger(count)||count<0||count>MAX_GENERIC_OBJECTS)return new Map();
128
+ for(let n=0;n<count;n++){
129
+ const entry=lines[i++]?.trim().match(/^(\d{10})\s+(\d{5})\s+([nf])$/);if(!entry)return new Map();
130
+ if(entry[3]==='n'){
131
+ const key=`${first+n} ${Number(entry[2])}`;
132
+ const list=offsets.get(key)??[];list.push(Number(entry[1]));offsets.set(key,list);
133
+ }
134
+ }
135
+ }
136
+ const trailerEnd=text.indexOf('startxref',trailerAt+7);if(trailerEnd<0)return new Map();
137
+ const prev=text.slice(trailerAt+7,trailerEnd).match(/\/Prev\s+(\d+)/)?.[1];
138
+ if(prev===undefined)break;
139
+ const next=Number(prev);if(!Number.isSafeInteger(next)||next>=cursor)return new Map();cursor=next;
140
+ }
141
+ return offsets;
142
+ }
143
+
113
144
  function decodePdfTextBytes(bytes){
114
145
  if(bytes.length>=2&&bytes[0]===0xfe&&bytes[1]===0xff){
115
146
  let out='';
@@ -186,6 +217,7 @@ function parseGenericPdfObjects(bytes){
186
217
  const text=bytes.toString('latin1');
187
218
  if(!text.startsWith('%PDF-')) throw new Error('invalid PDF header');
188
219
  if(/\/Encrypt\b/.test(text)) throw new Error('encrypted PDF is unsupported');
220
+ const incrementalOffsets=classicIncrementalObjectOffsets(text);
189
221
  const objects=new Map(),header=/(\d+)\s+(\d+)\s+obj\b/g;
190
222
  let match,count=0;
191
223
  while((match=header.exec(text))){
@@ -193,7 +225,10 @@ function parseGenericPdfObjects(bytes){
193
225
  const end=text.indexOf('endobj',header.lastIndex);
194
226
  if(end<0) throw new Error(`PDF object ${match[1]} ${match[2]} missing endobj`);
195
227
  const key=`${match[1]} ${match[2]}`;
196
- if(objects.has(key)) throw new Error(`PDF duplicate object ${key}`);
228
+ if(objects.has(key)){
229
+ const revisions=incrementalOffsets.get(key)??[];
230
+ if(!revisions.includes(objects.get(key).offset)||!revisions.includes(match.index)) throw new Error(`PDF duplicate object ${key}`);
231
+ }
197
232
  objects.set(key,{id:Number(match[1]),generation:Number(match[2]),body:text.slice(header.lastIndex,end),offset:match.index});
198
233
  header.lastIndex=end+6;
199
234
  }