deadbyte-mcp 0.15.20 → 0.15.22

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 (35) hide show
  1. package/MANIFEST.SHA256 +34 -25
  2. package/PROVENANCE.json +10 -10
  3. package/README.txt +7 -7
  4. package/RELEASE.json +47 -16
  5. package/SBOM.cdx.json +33 -7
  6. package/TEST-MATRIX.json +85 -15
  7. package/bin/deadbyte-hardware-observer-r45.exe +0 -0
  8. package/bin/deadbyte-hardware-observer-r45.obj +0 -0
  9. package/docs/R48-FULL-TOOL-CATALOG.json +124 -0
  10. package/native/deadbyte-hardware-observer.cpp +535 -12
  11. package/package.json +94 -93
  12. package/scripts/build-hardware-r45.ps1 +19 -0
  13. package/scripts/full-regression-r48-batch.mjs +27 -0
  14. package/scripts/promote-local-c-generation.ps1 +217 -0
  15. package/scripts/promote-local-d-generation.ps1 +217 -0
  16. package/scripts/test-r48-post-bump.ps1 +8 -0
  17. package/scripts/test-r48-windows-observation.ps1 +8 -0
  18. package/src/capability-ledger.mjs +7 -0
  19. package/src/capability-resolver.mjs +70 -14
  20. package/src/compact-gateway-mcp-tools.mjs +16 -2
  21. package/src/machine-fs.mjs +16 -3
  22. package/src/mcp-server.mjs +2 -1
  23. package/src/observation-mcp-tools.mjs +13 -1
  24. package/src/observation-output-contracts.mjs +8 -0
  25. package/src/observation-runtime.mjs +54 -2
  26. package/src/version.mjs +1 -1
  27. package/test/capability-resolver.test.mjs +68 -1
  28. package/test/compact-max-catalog-r45.test.mjs +25 -1
  29. package/test/full-max-catalog-r47.test.mjs +1 -1
  30. package/test/full-max-catalog-r48.test.mjs +78 -0
  31. package/test/machine-fs-runtime.test.mjs +28 -3
  32. package/test/observation-mcp-tools.test.mjs +4 -3
  33. package/test/r48-release-contract.test.mjs +20 -14
  34. package/test/windows-observation-r48.test.mjs +63 -0
  35. package/test/windows-observation-surface-r48.test.mjs +70 -0
@@ -0,0 +1,217 @@
1
+ #requires -Version 5.1
2
+ [CmdletBinding()]
3
+ param()
4
+ Set-StrictMode -Version 3.0
5
+ $ErrorActionPreference = 'Stop'
6
+
7
+ function Fail([string]$Message) { throw "LOCAL_D_PROMOTION: $Message" }
8
+ function Sha256-File([string]$Path) {
9
+ return (Get-FileHash -LiteralPath $Path -Algorithm SHA256).Hash.ToLowerInvariant()
10
+ }
11
+ function Sha256-Text([string]$Text) {
12
+ $sha = [System.Security.Cryptography.SHA256]::Create()
13
+ try {
14
+ $bytes = [System.Text.Encoding]::UTF8.GetBytes($Text)
15
+ return -join ($sha.ComputeHash($bytes) | ForEach-Object { $_.ToString('x2') })
16
+ } finally { $sha.Dispose() }
17
+ }
18
+ function Write-Utf8NoBom([string]$Path,[string]$Text) {
19
+ [System.IO.File]::WriteAllText($Path,$Text,(New-Object System.Text.UTF8Encoding($false)))
20
+ }
21
+ function Read-Raw([string]$Path) {
22
+ return [System.IO.File]::ReadAllText($Path,[System.Text.Encoding]::UTF8)
23
+ }
24
+
25
+ $stateRoot = Join-Path $env:USERPROFILE '.deadbyte-mcp'
26
+ $pointerPath = Join-Path $stateRoot 'active-release.json'
27
+ $launcher = Join-Path $stateRoot 'bin\DEADBYTE-MCP.ps1'
28
+ $runtimeRoot = Join-Path $stateRoot 'runtime'
29
+ if (-not (Test-Path -LiteralPath $pointerPath -PathType Leaf)) { Fail 'active pointer missing' }
30
+ if (-not (Test-Path -LiteralPath $launcher -PathType Leaf)) { Fail 'stable launcher missing' }
31
+
32
+ $pointerText = Read-Raw $pointerPath
33
+ $pointer = $pointerText | ConvertFrom-Json
34
+ if ([string]$pointer.schema -ne 'deadbyte.active-release.v1') { Fail 'active pointer schema mismatch' }
35
+ $oldGeneration = [System.IO.Path]::GetFullPath([string]$pointer.generation_root)
36
+ $oldManifest = Join-Path $oldGeneration 'GENERATION.SHA256'
37
+ if (-not (Test-Path -LiteralPath $oldManifest -PathType Leaf)) { Fail 'old generation manifest missing' }
38
+ $oldManifestHash = Sha256-File $oldManifest
39
+ if ($oldManifestHash -ne [string]$pointer.generation_manifest_sha256) { Fail 'old generation manifest hash mismatch' }
40
+
41
+ $manifestLines = @(Get-Content -LiteralPath $oldManifest -Encoding UTF8)
42
+ $entries = @()
43
+ foreach ($line in $manifestLines) {
44
+ if ([string]::IsNullOrWhiteSpace([string]$line)) { continue }
45
+ if ([string]$line -notmatch '^([0-9a-f]{64}) ([A-Za-z0-9._-]+)$') { Fail "malformed old generation manifest line: $line" }
46
+ $expected = [string]$Matches[1]
47
+ $name = [string]$Matches[2]
48
+ $path = Join-Path $oldGeneration $name
49
+ if (-not (Test-Path -LiteralPath $path -PathType Leaf)) { Fail "old generation file missing: $name" }
50
+ $actual = Sha256-File $path
51
+ if ($actual -ne $expected) { Fail "old generation hash mismatch: $name" }
52
+ $entries += [pscustomobject]@{ Name=$name; Expected=$expected }
53
+ }
54
+ $names = @($entries | ForEach-Object { $_.Name })
55
+ foreach ($required in @('coding-policy.json','autonomous-policy.json','controller-config.psd1')) {
56
+ if ($required -notin $names) { Fail "required generation file not manifested: $required" }
57
+ }
58
+
59
+ $oldCodingPath = Join-Path $oldGeneration 'coding-policy.json'
60
+ $oldAutonomousPath = Join-Path $oldGeneration 'autonomous-policy.json'
61
+ $oldCodingHash = Sha256-File $oldCodingPath
62
+ $oldAutonomousHash = Sha256-File $oldAutonomousPath
63
+
64
+ $coding = (Read-Raw $oldCodingPath) | ConvertFrom-Json
65
+ if ([string]$coding.schema -ne 'deadbyte.coding-policy.v1' -or $coding.enabled -ne $true) { Fail 'coding policy schema/enabled mismatch' }
66
+ if ($null -eq $coding.roots) { Fail 'coding roots missing' }
67
+
68
+ $localRoot = [pscustomobject][ordered]@{
69
+ path = 'D:\'
70
+ read = $true
71
+ write = $true
72
+ exec = $true
73
+ deny_paths = @()
74
+ }
75
+ if ($coding.roots.PSObject.Properties.Name -contains 'local_d') {
76
+ $coding.roots.local_d = $localRoot
77
+ } else {
78
+ $coding.roots | Add-Member -NotePropertyName 'local_d' -NotePropertyValue $localRoot
79
+ }
80
+ foreach ($commandProp in @($coding.commands.PSObject.Properties)) {
81
+ $command = $commandProp.Value
82
+ if ($command.PSObject.Properties.Name -contains 'root_ids') {
83
+ $ids = @($command.root_ids)
84
+ if ('local_d' -notin $ids) { $command.root_ids = @($ids + 'local_d') }
85
+ }
86
+ }
87
+ $codingText = ($coding | ConvertTo-Json -Depth 32) + [Environment]::NewLine
88
+ $newCodingHash = Sha256-Text $codingText
89
+
90
+ $autonomous = (Read-Raw $oldAutonomousPath) | ConvertFrom-Json
91
+ if ([string]$autonomous.schema -ne 'deadbyte.autonomous-policy.v1' -or $autonomous.enabled -ne $true) { Fail 'autonomous policy schema/enabled mismatch' }
92
+ $autonomous.coding_policy_sha256 = $newCodingHash
93
+ $autonomousText = ($autonomous | ConvertTo-Json -Depth 32) + [Environment]::NewLine
94
+ $newAutonomousHash = Sha256-Text $autonomousText
95
+
96
+ $seed = $oldManifestHash + [Environment]::NewLine + $newCodingHash + [Environment]::NewLine + $newAutonomousHash + [Environment]::NewLine + 'local_d=D:\'
97
+ $generationSuffix = (Sha256-Text $seed).Substring(0,16)
98
+ $newGenerationId = ([string]$pointer.release_id) + '-g' + $generationSuffix
99
+ $generationStore = Join-Path $stateRoot 'generations'
100
+ $newGeneration = Join-Path $generationStore $newGenerationId
101
+ if (Test-Path -LiteralPath $newGeneration) { Fail "target generation already exists: $newGeneration" }
102
+ New-Item -ItemType Directory -Path $newGeneration | Out-Null
103
+
104
+ $pointerBackup = Join-Path $runtimeRoot 'active-release.before-local-d.json'
105
+ $codingGrantPath = Join-Path $runtimeRoot 'coding-grant.json'
106
+ $autonomousGrantPath = Join-Path $runtimeRoot 'autonomous-grant.json'
107
+ $hadCodingGrant = Test-Path -LiteralPath $codingGrantPath -PathType Leaf
108
+ $hadAutonomousGrant = Test-Path -LiteralPath $autonomousGrantPath -PathType Leaf
109
+ $oldCodingGrantText = if ($hadCodingGrant) { Read-Raw $codingGrantPath } else { $null }
110
+ $oldAutonomousGrantText = if ($hadAutonomousGrant) { Read-Raw $autonomousGrantPath } else { $null }
111
+ $wasAutonomousArmed = $false
112
+ if ($hadCodingGrant -and $hadAutonomousGrant) {
113
+ try {
114
+ $cg = $oldCodingGrantText | ConvertFrom-Json
115
+ $ag = $oldAutonomousGrantText | ConvertFrom-Json
116
+ $wasAutonomousArmed =
117
+ ([string]$cg.policy_sha256 -eq $oldCodingHash) -and
118
+ ([string]$ag.policy_sha256 -eq $oldAutonomousHash) -and
119
+ ([string]$ag.coding_policy_sha256 -eq $oldCodingHash)
120
+ } catch { $wasAutonomousArmed = $false }
121
+ }
122
+
123
+ $switched = $false
124
+ try {
125
+ foreach ($entry in $entries) {
126
+ $src = Join-Path $oldGeneration $entry.Name
127
+ $dst = Join-Path $newGeneration $entry.Name
128
+ Copy-Item -LiteralPath $src -Destination $dst
129
+ }
130
+
131
+ Write-Utf8NoBom (Join-Path $newGeneration 'coding-policy.json') $codingText
132
+ Write-Utf8NoBom (Join-Path $newGeneration 'autonomous-policy.json') $autonomousText
133
+
134
+ $configPath = Join-Path $newGeneration 'controller-config.psd1'
135
+ $configText = Read-Raw $configPath
136
+ if ($configText.IndexOf($oldGeneration,[System.StringComparison]::OrdinalIgnoreCase) -lt 0) { Fail 'controller config is not bound to old generation root' }
137
+ $configText = $configText.Replace($oldGeneration,$newGeneration)
138
+ Write-Utf8NoBom $configPath $configText
139
+ $cfg = Import-PowerShellDataFile -LiteralPath $configPath
140
+ if ([System.IO.Path]::GetFullPath([string]$cfg.CodingPolicyFile) -ne [System.IO.Path]::GetFullPath((Join-Path $newGeneration 'coding-policy.json'))) { Fail 'new controller CodingPolicyFile binding mismatch' }
141
+ if ([System.IO.Path]::GetFullPath([string]$cfg.AutonomousPolicyFile) -ne [System.IO.Path]::GetFullPath((Join-Path $newGeneration 'autonomous-policy.json'))) { Fail 'new controller AutonomousPolicyFile binding mismatch' }
142
+
143
+ foreach ($entry in $entries) {
144
+ $p = Join-Path $newGeneration $entry.Name
145
+ $text = $null
146
+ try { $text = Read-Raw $p } catch { $text = $null }
147
+ if ($null -ne $text -and $entry.Name -ne 'controller-config.psd1' -and $text.IndexOf($oldGeneration,[System.StringComparison]::OrdinalIgnoreCase) -ge 0) {
148
+ Fail "unexpected old generation binding remains in $($entry.Name)"
149
+ }
150
+ }
151
+
152
+ $newManifestLines = @()
153
+ foreach ($entry in $entries) {
154
+ $p = Join-Path $newGeneration $entry.Name
155
+ $newManifestLines += ((Sha256-File $p) + ' ' + $entry.Name)
156
+ }
157
+ $newManifestText = ($newManifestLines -join [Environment]::NewLine) + [Environment]::NewLine
158
+ $newManifestPath = Join-Path $newGeneration 'GENERATION.SHA256'
159
+ Write-Utf8NoBom $newManifestPath $newManifestText
160
+ $newManifestHash = Sha256-File $newManifestPath
161
+
162
+ foreach ($line in $newManifestLines) {
163
+ if ($line -notmatch '^([0-9a-f]{64}) ([A-Za-z0-9._-]+)$') { Fail 'new manifest internal format error' }
164
+ $actual = Sha256-File (Join-Path $newGeneration ([string]$Matches[2]))
165
+ if ($actual -ne [string]$Matches[1]) { Fail "new generation verification failed: $($Matches[2])" }
166
+ }
167
+ if ((Sha256-File (Join-Path $newGeneration 'coding-policy.json')) -ne $newCodingHash) { Fail 'new coding hash self-check failed' }
168
+ if ((Sha256-File (Join-Path $newGeneration 'autonomous-policy.json')) -ne $newAutonomousHash) { Fail 'new autonomous hash self-check failed' }
169
+
170
+ Write-Utf8NoBom $pointerBackup $pointerText
171
+ $pointer.generation_root = $newGeneration
172
+ $pointer.config_path = Join-Path $newGeneration 'controller-config.psd1'
173
+ $pointer.generation_manifest_sha256 = $newManifestHash
174
+ if ($pointer.PSObject.Properties.Name -contains 'generation_id') { $pointer.generation_id = $newGenerationId }
175
+ if ($pointer.PSObject.Properties.Name -contains 'generation_manifest_path') { $pointer.generation_manifest_path = $newManifestPath }
176
+ if ($pointer.PSObject.Properties.Name -contains 'updated_at_utc') { $pointer.updated_at_utc = [DateTime]::UtcNow.ToString('o') }
177
+ $newPointerText = ($pointer | ConvertTo-Json -Depth 32) + [Environment]::NewLine
178
+ $pointerTmp = $pointerPath + '.local-d.tmp'
179
+ Write-Utf8NoBom $pointerTmp $newPointerText
180
+ Move-Item -LiteralPath $pointerTmp -Destination $pointerPath -Force
181
+ $switched = $true
182
+
183
+ $statusText = (& $launcher status 2>&1 | Out-String)
184
+ if ($LASTEXITCODE -ne 0) { Fail "launcher status failed after pointer switch: $statusText" }
185
+
186
+ $armCodingText = (& $launcher armcoding 2>&1 | Out-String)
187
+ if ($LASTEXITCODE -ne 0) { Fail "armcoding failed after pointer switch: $armCodingText" }
188
+
189
+ $armAutonomousText = ''
190
+ if ($wasAutonomousArmed) {
191
+ $armAutonomousText = (& $launcher armautonomous 2>&1 | Out-String)
192
+ if ($LASTEXITCODE -ne 0) { Fail "armautonomous failed after pointer switch: $armAutonomousText" }
193
+ }
194
+
195
+ Write-Output 'LOCAL_D_PROMOTION=PASS'
196
+ Write-Output ('OLD_GENERATION=' + $oldGeneration)
197
+ Write-Output ('NEW_GENERATION=' + $newGeneration)
198
+ Write-Output ('OLD_GENERATION_MANIFEST_SHA256=' + $oldManifestHash)
199
+ Write-Output ('NEW_GENERATION_MANIFEST_SHA256=' + $newManifestHash)
200
+ Write-Output ('OLD_CODING_POLICY_SHA256=' + $oldCodingHash)
201
+ Write-Output ('NEW_CODING_POLICY_SHA256=' + $newCodingHash)
202
+ Write-Output ('NEW_AUTONOMOUS_POLICY_SHA256=' + $newAutonomousHash)
203
+ Write-Output ('AUTONOMOUS_REARMED=' + $wasAutonomousArmed)
204
+ Write-Output ('ROLLBACK_POINTER=' + $pointerBackup)
205
+ Write-Output 'RESTART_REQUIRED=YES'
206
+ } catch {
207
+ $message = $_.Exception.Message
208
+ if ($switched) {
209
+ try { Write-Utf8NoBom $pointerPath $pointerText } catch {}
210
+ if ($hadCodingGrant) { try { Write-Utf8NoBom $codingGrantPath $oldCodingGrantText } catch {} }
211
+ else { try { Remove-Item -LiteralPath $codingGrantPath -Force -ErrorAction SilentlyContinue } catch {} }
212
+ if ($hadAutonomousGrant) { try { Write-Utf8NoBom $autonomousGrantPath $oldAutonomousGrantText } catch {} }
213
+ else { try { Remove-Item -LiteralPath $autonomousGrantPath -Force -ErrorAction SilentlyContinue } catch {} }
214
+ }
215
+ try { if (Test-Path -LiteralPath $newGeneration) { Remove-Item -LiteralPath $newGeneration -Recurse -Force } } catch {}
216
+ Fail $message
217
+ }
@@ -0,0 +1,8 @@
1
+ $ErrorActionPreference='Stop'
2
+ Set-StrictMode -Version Latest
3
+ $Root=Split-Path -Parent $PSScriptRoot
4
+ Push-Location $Root
5
+ try {
6
+ & node --test --test-concurrency=1 test/r48-release-contract.test.mjs test/release-version.test.mjs test/cli-entrypoint.test.mjs test/package-boundary.test.mjs test/release-smoke-isolation.test.mjs test/full-max-catalog-r48.test.mjs
7
+ if($LASTEXITCODE -ne 0){throw "R48 post-bump release checks failed exit=$LASTEXITCODE"}
8
+ } finally { Pop-Location }
@@ -0,0 +1,8 @@
1
+ $ErrorActionPreference='Stop'
2
+ Set-StrictMode -Version Latest
3
+ $Root=Split-Path -Parent $PSScriptRoot
4
+ Push-Location $Root
5
+ try {
6
+ & node --test test/machine-fs-runtime.test.mjs test/windows-observation-r48.test.mjs test/windows-observation-surface-r48.test.mjs test/hardware-observation-r45.test.mjs test/observation-mcp-tools.test.mjs test/compact-gateway-r36.test.mjs test/capability-resolver.test.mjs test/compact-catalog-r36.test.mjs test/compact-max-catalog-r45.test.mjs test/full-max-catalog-r45.test.mjs test/full-max-catalog-r46.test.mjs test/full-max-catalog-r47.test.mjs test/full-max-catalog-r48.test.mjs
7
+ if($LASTEXITCODE -ne 0){throw "R48 focused regression failed exit=$LASTEXITCODE"}
8
+ } finally { Pop-Location }
@@ -137,6 +137,13 @@ export const R36_CAPABILITY_ENTRIES=Object.freeze([
137
137
  gateway('observation.process_list','machine_process_list','machine_observe','process_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
138
138
  gateway('observation.system_status','machine_system_status','machine_observe','system_status','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
139
139
  gateway('observation.hardware_query','machine_hardware_query','machine_observe','hardware_query','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
140
+ gateway('observation.registry_query','machine_windows_query','machine_observe','registry_query','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
141
+ gateway('observation.service_list','machine_windows_query','machine_observe','service_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
142
+ gateway('observation.driver_list','machine_windows_query','machine_observe','driver_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
143
+ gateway('observation.socket_list','machine_windows_query','machine_observe','socket_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
144
+ gateway('observation.volume_list','machine_windows_query','machine_observe','volume_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
145
+ gateway('observation.usb_list','machine_windows_query','machine_observe','usb_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
146
+ gateway('observation.wsl_list','machine_windows_query','machine_observe','wsl_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
140
147
 
141
148
  gateway('desktop.status','desktop_status','desktop_control','status','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
142
149
  gateway('desktop.observe','desktop_observe','desktop_control','observe','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
@@ -1,3 +1,11 @@
1
+ import { processSessionStatus } from './process-policy.mjs';
2
+ import { assertHostArmed } from './host-plane.mjs';
3
+
4
+ const CODING_ARMED_READ_CAPABILITIES = new Set([
5
+ 'coding.tree','coding.stat','coding.search','coding.files_read','coding.file_read',
6
+ 'semantic.outline','semantic.definition','semantic.references','semantic.diagnostics','semantic.implementations','semantic.rename_preview'
7
+ ]);
8
+
1
9
  export const CAPABILITY_STATES = Object.freeze({
2
10
  AVAILABLE: 'AVAILABLE',
3
11
  DEGRADED: 'DEGRADED',
@@ -59,6 +67,13 @@ const CAPABILITY_OPERATIONS = Object.freeze({
59
67
  'observation.process_list': ['process_list'],
60
68
  'observation.system_status': ['system_status'],
61
69
  'observation.hardware_query': ['hardware_query'],
70
+ 'observation.registry_query': ['registry_query'],
71
+ 'observation.service_list': ['service_list'],
72
+ 'observation.driver_list': ['driver_list'],
73
+ 'observation.socket_list': ['socket_list'],
74
+ 'observation.volume_list': ['volume_list'],
75
+ 'observation.usb_list': ['usb_list'],
76
+ 'observation.wsl_list': ['wsl_list'],
62
77
  'desktop.status': ['status'],
63
78
  'desktop.observe': ['observe'],
64
79
  'desktop.target': ['target'],
@@ -88,12 +103,11 @@ export function deriveCapabilityRequirements(capability) {
88
103
  reqs.push('skill_plane.valid');
89
104
  return reqs;
90
105
  }
106
+ if (CODING_ARMED_READ_CAPABILITIES.has(capability.id) && capability.authority !== 'coding') reqs.push('coding_session.armed');
91
107
  if (capability.authority === 'coding') {
92
- if (capability.mutating) {
93
- reqs.push('coding_session.armed', 'policy.write');
94
- } else {
95
- reqs.push('coding_runtime.ready');
96
- }
108
+ if (capability.mutating || CODING_ARMED_READ_CAPABILITIES.has(capability.id)) reqs.push('coding_session.armed');
109
+ else reqs.push('coding_runtime.ready');
110
+ if (capability.mutating) reqs.push('policy.write');
97
111
  } else if (capability.authority === 'process') {
98
112
  if (capability.mutating) {
99
113
  reqs.push('process_session.armed');
@@ -113,11 +127,7 @@ export function deriveCapabilityRequirements(capability) {
113
127
  reqs.push('desktop_runtime.ready');
114
128
  }
115
129
  } else if (capability.authority === 'host' || capability.host_only) {
116
- if (capability.mutating) {
117
- reqs.push('host_policy.armed');
118
- } else {
119
- reqs.push('host_policy.configured');
120
- }
130
+ reqs.push('host_policy.armed');
121
131
  }
122
132
  return reqs;
123
133
  }
@@ -148,11 +158,33 @@ export async function resolveCapabilityStates({
148
158
  try { codingStatus = await codingRuntime.sessionStatus(); } catch {}
149
159
  }
150
160
 
161
+ let processStatus = null;
162
+ if (processRuntime?.sessionStatus) {
163
+ try { processStatus = await processRuntime.sessionStatus(); } catch {}
164
+ } else if (processRuntime?.policy) {
165
+ try { processStatus = await processSessionStatus(processRuntime.policy); } catch {}
166
+ }
167
+
151
168
  let autonomousStatus = null;
152
169
  if (autonomousRuntime?.sessionStatus) {
153
170
  try { autonomousStatus = await autonomousRuntime.sessionStatus(); } catch {}
154
171
  }
155
172
 
173
+ let desktopStatus = null;
174
+ if (desktopRuntime?.status) {
175
+ try { desktopStatus = await desktopRuntime.status(); } catch {}
176
+ }
177
+
178
+ let hostStatus = null;
179
+ if (hostPolicy) {
180
+ try {
181
+ const armed = await assertHostArmed(hostPolicy);
182
+ hostStatus = { configured:true, armed:true, reason:armed.standing ? 'standing-grant' : 'armed' };
183
+ } catch (error) {
184
+ hostStatus = { configured:true, armed:false, reason:String(error?.message ?? error) };
185
+ }
186
+ }
187
+
156
188
  let skillListResult = null;
157
189
  if (skillRuntime?.list) {
158
190
  try { skillListResult = await skillRuntime.list(); } catch (err) {
@@ -225,20 +257,44 @@ export async function resolveCapabilityStates({
225
257
  };
226
258
  }
227
259
  // 4. Session Authority Checks
228
- else if (cap.authority === 'coding' && cap.mutating && codingStatus && !codingStatus.armed) {
260
+ else if (requires.includes('coding_session.armed') && !codingStatus?.armed) {
229
261
  state = CAPABILITY_STATES.DENIED;
230
262
  ready = false;
231
263
  diagnostic = {
232
264
  code: 'CODING_SESSION_DISARMED',
233
- reason: codingStatus.reason || 'Coding session is not armed for mutation',
265
+ reason: codingStatus?.reason || 'Coding session is not armed for this capability',
234
266
  recoverable: true
235
267
  };
236
- } else if (cap.authority === 'autonomous' && cap.mutating && autonomousStatus && !autonomousStatus.armed) {
268
+ } else if (requires.includes('process_session.armed') && !processStatus?.armed) {
269
+ state = CAPABILITY_STATES.DENIED;
270
+ ready = false;
271
+ diagnostic = {
272
+ code: 'PROCESS_SESSION_DISARMED',
273
+ reason: processStatus?.reason || 'Process session is not armed for mutation',
274
+ recoverable: true
275
+ };
276
+ } else if (requires.includes('autonomous_session.armed') && !autonomousStatus?.armed) {
237
277
  state = CAPABILITY_STATES.DENIED;
238
278
  ready = false;
239
279
  diagnostic = {
240
280
  code: 'AUTONOMOUS_SESSION_DISARMED',
241
- reason: autonomousStatus.reason || 'Autonomous session is not armed for mutation',
281
+ reason: autonomousStatus?.reason || 'Autonomous session is not armed for mutation',
282
+ recoverable: true
283
+ };
284
+ } else if (requires.includes('desktop_control.armed') && !desktopStatus?.armed) {
285
+ state = CAPABILITY_STATES.DENIED;
286
+ ready = false;
287
+ diagnostic = {
288
+ code: 'DESKTOP_SESSION_DISARMED',
289
+ reason: desktopStatus?.reason || 'Desktop control is not armed for mutation',
290
+ recoverable: true
291
+ };
292
+ } else if (requires.includes('host_policy.armed') && !hostStatus?.armed) {
293
+ state = CAPABILITY_STATES.DENIED;
294
+ ready = false;
295
+ diagnostic = {
296
+ code: 'HOST_POLICY_DISARMED',
297
+ reason: hostStatus?.reason || 'Privileged host policy is disarmed',
242
298
  recoverable: true
243
299
  };
244
300
  }
@@ -55,7 +55,14 @@ export const machineObserveInputSchema=z.discriminatedUnion('op',[
55
55
  z.strictObject({op:z.literal('search_cancel'),search_id:hex64}),
56
56
  z.strictObject({op:z.literal('process_list'),limit:z.number().int().min(1).max(256).default(100),include_external:z.boolean().default(false),cursor:z.string().max(512).nullable().default(null)}),
57
57
  z.strictObject({op:z.literal('system_status')}),
58
- z.strictObject({op:z.literal('hardware_query'),query:z.enum(['cpu','gpu','memory','storage','network','pci'])})
58
+ z.strictObject({op:z.literal('hardware_query'),query:z.enum(['cpu','gpu','memory','storage','network','pci'])}),
59
+ z.strictObject({op:z.literal('registry_query'),hive:z.enum(['HKLM','HKCU']),key:z.string().min(1).max(1024),value:z.string().max(260).nullable().default(null)}),
60
+ z.strictObject({op:z.literal('service_list')}),
61
+ z.strictObject({op:z.literal('driver_list')}),
62
+ z.strictObject({op:z.literal('socket_list')}),
63
+ z.strictObject({op:z.literal('volume_list')}),
64
+ z.strictObject({op:z.literal('usb_list')}),
65
+ z.strictObject({op:z.literal('wsl_list')})
59
66
  ]);
60
67
 
61
68
  const capabilityManifestInputSchema=z.strictObject({});
@@ -119,7 +126,14 @@ async function machineObserve(args,machineRuntime,observationRuntime){
119
126
  search_cancel:r=>r.searchCancel({searchId:args.search_id}),
120
127
  process_list:r=>r.processList({limit:args.limit,includeExternal:args.include_external,cursor:args.cursor}),
121
128
  system_status:r=>r.systemStatus(),
122
- hardware_query:r=>r.hardwareQuery({query:args.query})
129
+ hardware_query:r=>r.hardwareQuery({query:args.query}),
130
+ registry_query:r=>r.windowsQuery({query:'registry',hive:args.hive,key:args.key,value:args.value}),
131
+ service_list:r=>r.windowsQuery({query:'services'}),
132
+ driver_list:r=>r.windowsQuery({query:'drivers'}),
133
+ socket_list:r=>r.windowsQuery({query:'sockets'}),
134
+ volume_list:r=>r.windowsQuery({query:'volumes'}),
135
+ usb_list:r=>r.windowsQuery({query:'usb'}),
136
+ wsl_list:r=>r.windowsQuery({query:'wsl'})
123
137
  };
124
138
  return invoke(args.op,observationRuntime,'observation',map[args.op]);
125
139
  }
@@ -338,7 +338,7 @@ async function atomicWrite(target, bytes, expectedSha256, authorityCheck = null)
338
338
  assertExpected: checkExpectedFile, authorityCheck, tempTag: 'deadbyte-machine-fs' });
339
339
  }
340
340
 
341
- export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath, readWorkerPath = machineFsReadWorkerPath }) {
341
+ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath, readWorkerPath = machineFsReadWorkerPath, listEntryLstat = lstat, listEntrySha256File = sha256File }) {
342
342
  if (!policy) throw new Error('machine fs runtime requires coding policy');
343
343
  if (!signingKeyPath || !verifyKeyPath) throw new Error('machine fs runtime requires trust key paths');
344
344
 
@@ -384,9 +384,22 @@ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath,
384
384
  const rel = found.relative === '.' ? child.name : `${found.relative}/${child.name}`;
385
385
  if (child.isSymbolicLink()) return { path: rel, kind: 'reparse', bytes: 0, mtime_utc: null, sha256: null };
386
386
  const childPath = path.join(found.resolved, child.name);
387
- const childInfo = await lstat(childPath);
387
+ let childInfo;
388
+ try { childInfo = await listEntryLstat(childPath); }
389
+ catch (error) {
390
+ const code = typeof error?.code === 'string' && /^[A-Z0-9_]+$/.test(error.code) ? error.code : 'UNKNOWN';
391
+ return { path: rel, kind: 'unreadable', bytes: 0, mtime_utc: null, sha256: null, error: { code, operation: 'lstat' } };
392
+ }
388
393
  const kind = kindOf(childInfo);
389
- const digest = hashFiles && kind === 'file' ? await sha256File(childPath) : null;
394
+ let digest = null;
395
+ if (hashFiles && kind === 'file') {
396
+ try { digest = await listEntrySha256File(childPath); }
397
+ catch (error) {
398
+ const code = typeof error?.code === 'string' && /^[A-Z0-9_]+$/.test(error.code) ? error.code : 'UNKNOWN';
399
+ return { path: rel, kind, bytes: childInfo.size, mtime_utc: childInfo.mtime.toISOString(), sha256: null,
400
+ error: { code, operation: 'sha256' } };
401
+ }
402
+ }
390
403
  return { path: rel, kind, bytes: kind === 'file' ? childInfo.size : 0, mtime_utc: childInfo.mtime.toISOString(), sha256: digest };
391
404
  }));
392
405
  const nextCursor = filtered.length > selected.length && selected.length
@@ -479,7 +479,8 @@ serveStdio(() => {
479
479
 
480
480
  registerCompactGatewayTools(toolServer,{
481
481
  profile:surfaceProfile,ledger:R36_CAPABILITY_LEDGER,codingRuntime,semanticRuntime,machineFsRuntime,
482
- processRuntime,observationRuntime,machineRuntime,desktopRuntime,catalogProvider:()=>[...registeredToolNames]
482
+ processRuntime,observationRuntime,machineRuntime,desktopRuntime,skillRuntime,autonomousRuntime,hostPolicy,
483
+ catalogProvider:()=>[...registeredToolNames]
483
484
  });
484
485
 
485
486
  if (hostPolicy) {
@@ -1,7 +1,7 @@
1
1
  import * as z from 'zod/v4';
2
2
  import {
3
3
  observationHardwareQueryOutputSchema,observationProcessListOutputSchema,observationSearchCancelOutputSchema,observationSearchPageOutputSchema,
4
- observationSearchStartOutputSchema,observationSearchStatusOutputSchema,observationStructuredResult,observationSystemStatusOutputSchema
4
+ observationSearchStartOutputSchema,observationSearchStatusOutputSchema,observationStructuredResult,observationSystemStatusOutputSchema,observationWindowsQueryOutputSchema
5
5
  } from './observation-output-contracts.mjs';
6
6
 
7
7
  const hex64=z.string().regex(/^[0-9a-f]{64}$/);
@@ -45,4 +45,16 @@ export function registerObservationTools(server,{runtime}){
45
45
  description:'Read one typed native hardware snapshot (CPU, GPU, memory, storage, network, or PCI) with signed observation evidence. No shell or Host authority is used.',
46
46
  inputSchema:z.strictObject({query:z.enum(['cpu','gpu','memory','storage','network','pci'])}),outputSchema:observationHardwareQueryOutputSchema
47
47
  },async args=>{try{return ok(observationHardwareQueryOutputSchema,await runtime.hardwareQuery({query:args.query}));}catch(error){return fail(observationHardwareQueryOutputSchema,error);}});
48
+ server.registerTool('machine_windows_query',{
49
+ description:'Read one typed native Windows snapshot for Registry, services, drivers, sockets, volumes, USB, or WSL. No shell parsing is used.',
50
+ inputSchema:z.discriminatedUnion('query',[
51
+ z.strictObject({query:z.literal('registry'),hive:z.enum(['HKLM','HKCU']),key:z.string().min(1).max(1024),value:z.string().max(260).nullable().default(null)}),
52
+ z.strictObject({query:z.literal('services')}),
53
+ z.strictObject({query:z.literal('drivers')}),
54
+ z.strictObject({query:z.literal('sockets')}),
55
+ z.strictObject({query:z.literal('volumes')}),
56
+ z.strictObject({query:z.literal('usb')}),
57
+ z.strictObject({query:z.literal('wsl')})
58
+ ]),outputSchema:observationWindowsQueryOutputSchema
59
+ },async args=>{try{return ok(observationWindowsQueryOutputSchema,await runtime.windowsQuery(args));}catch(error){return fail(observationWindowsQueryOutputSchema,error);}});
48
60
  }
@@ -55,6 +55,14 @@ export const observationHardwareQueryOutputSchema=statusContract({
55
55
  ...Object.fromEntries(Object.entries(evidenceShape).map(([k,v])=>[k,v.optional()]))
56
56
  },['observed_at_utc','query','data','request_sha256','result_head_sha256','receipt_id','receipt_sha256']);
57
57
 
58
+ export const observationWindowsQueryOutputSchema=statusContract({
59
+ observed_at_utc:z.string().min(1).optional(),
60
+ query:z.enum(['registry','services','drivers','sockets','volumes','usb','wsl']).optional(),
61
+ data:z.record(z.string(),z.json()).optional(),
62
+ observer_sha256:hex64.optional(),
63
+ ...Object.fromEntries(Object.entries(evidenceShape).map(([k,v])=>[k,v.optional()]))
64
+ },['observed_at_utc','query','data','request_sha256','result_head_sha256','receipt_id','receipt_sha256']);
65
+
58
66
  export function observationStructuredResult(schema,value,isError=false){
59
67
  return structuredToolResult(schema,value,isError);
60
68
  }
@@ -15,6 +15,8 @@ const ZERO='0'.repeat(64);
15
15
  const HEX64=/^[0-9a-f]{64}$/;
16
16
  const ID=/^[A-Za-z0-9._-]{1,64}$/;
17
17
  const HARDWARE_QUERIES=new Set(['cpu','gpu','memory','storage','network','pci']);
18
+ const WINDOWS_QUERIES=new Set(['registry','services','drivers','sockets','volumes','usb','wsl']);
19
+ const REGISTRY_HIVES=new Set(['HKLM','HKCU']);
18
20
  const sha256Bytes=bytes=>createHash('sha256').update(bytes).digest('hex');
19
21
  const sha256Object=value=>sha256Bytes(Buffer.from(canonicalJson(value),'utf8'));
20
22
  const nowUtc=()=>new Date().toISOString();
@@ -131,12 +133,49 @@ async function defaultHardwareSnapshotProvider(query){
131
133
  }
132
134
  return {...parsed,observer_sha256:executableSha256};
133
135
  }
136
+ function normalizeWindowsQueryArgs(input={}){
137
+ const query=String(input.query??'');
138
+ if(!WINDOWS_QUERIES.has(query)) throw new Error('windows query must be one of registry,services,drivers,sockets,volumes,usb,wsl');
139
+ if(query==='registry'){
140
+ const hive=String(input.hive??'');
141
+ const key=String(input.key??'');
142
+ const value=input.value===null||input.value===undefined?null:String(input.value);
143
+ if(!REGISTRY_HIVES.has(hive)) throw new Error('registry hive must be HKLM or HKCU');
144
+ if(key.length<1||key.length>1024||key.includes('\0')) throw new Error('registry key must contain 1-1024 non-NUL characters');
145
+ if(value!==null&&(value.length>260||value.includes('\0'))) throw new Error('registry value must be null or at most 260 non-NUL characters');
146
+ return {query,hive,key,value};
147
+ }
148
+ const extra=Object.keys(input).filter(k=>k!=='query'&&input[k]!==undefined&&input[k]!==null);
149
+ if(extra.length) throw new Error(`windows query '${query}' does not accept additional selectors`);
150
+ return {query};
151
+ }
152
+ async function defaultWindowsSnapshotProvider(input){
153
+ if(process.platform!=='win32') throw new Error('native Windows observation is supported on win32 only');
154
+ const args=normalizeWindowsQueryArgs(input);
155
+ const executable=fileURLToPath(new URL('../bin/deadbyte-hardware-observer-r45.exe',import.meta.url));
156
+ const executableSha256=sha256Bytes(await readFile(executable));
157
+ const argv=[args.query];
158
+ if(args.query==='registry'){
159
+ argv.push(args.hive,args.key);
160
+ if(args.value!==null) argv.push(args.value);
161
+ }
162
+ const result=spawnSync(executable,argv,{encoding:'utf8',windowsHide:true,shell:false,timeout:15000,maxBuffer:16*1024*1024});
163
+ if(result.error) throw result.error;
164
+ if(result.status!==0) throw new Error(`Windows observation failed query=${args.query}: ${String(result.stderr??result.stdout??'').trim()}`);
165
+ let parsed;
166
+ try{parsed=JSON.parse(String(result.stdout??'').trim());}
167
+ catch{throw new Error(`Windows observation returned invalid JSON query=${args.query}`);}
168
+ if(parsed?.schema!=='deadbyte.windows-query.v1'||parsed?.query!==args.query||!parsed.data||typeof parsed.data!=='object'||Array.isArray(parsed.data)){
169
+ throw new Error(`Windows observation contract mismatch query=${args.query}`);
170
+ }
171
+ return {...parsed,observer_sha256:executableSha256};
172
+ }
134
173
  function requestSha(policy,operation,args){
135
174
  return sha256Object({schema:'deadbyte.observation-request.v1',policy_sha256:policy.policy_sha256,operation,args});
136
175
  }
137
176
  export function createObservationRuntime({policy,signingKeyPath,verifyKeyPath,processRuntime=null,stateRoot=path.join(os.homedir(),'.deadbyte-mcp'),
138
177
  processSnapshotProvider=defaultProcessSnapshotProvider,systemSnapshotProvider=defaultSystemSnapshotProvider,
139
- ownedRuntimePidProvider=defaultOwnedRuntimePidProvider,hardwareSnapshotProvider=defaultHardwareSnapshotProvider,
178
+ ownedRuntimePidProvider=defaultOwnedRuntimePidProvider,hardwareSnapshotProvider=defaultHardwareSnapshotProvider,windowsSnapshotProvider=defaultWindowsSnapshotProvider,
140
179
  searchSessionTtlMs=5*60*1000,maxSearchSessions=128,clockMs=()=>Date.now()}={}){
141
180
  if(!policy||!signingKeyPath||!verifyKeyPath) throw new Error('observation runtime requires policy and trust keys');
142
181
  if(!Number.isInteger(searchSessionTtlMs)||searchSessionTtlMs<10||searchSessionTtlMs>24*60*60*1000) throw new Error('searchSessionTtlMs out of range');
@@ -337,5 +376,18 @@ export function createObservationRuntime({policy,signingKeyPath,verifyKeyPath,pr
337
376
  const receipt=await writeReceipt(runtime,'machine_hardware_query',req,head,{observed_at_utc:observedAt,query,observer_sha256:result.observer_sha256??null});
338
377
  return {...result,request_sha256:req,result_head_sha256:head,...receipt};
339
378
  }
340
- return Object.freeze({policy,searchStart,searchPage,searchStatus,searchCancel,processList,systemStatus,hardwareQuery});
379
+ async function windowsQuery(input={}){
380
+ const args=normalizeWindowsQueryArgs(input);
381
+ const observedAt=nowUtc();
382
+ const snapshot=await windowsSnapshotProvider(args);
383
+ if(!snapshot||snapshot.schema!=='deadbyte.windows-query.v1'||snapshot.query!==args.query||!snapshot.data||typeof snapshot.data!=='object'||Array.isArray(snapshot.data)){
384
+ throw new Error('windows query provider contract mismatch');
385
+ }
386
+ const result={status:'ok',observed_at_utc:observedAt,query:args.query,data:snapshot.data};
387
+ if(typeof snapshot.observer_sha256==='string'&&HEX64.test(snapshot.observer_sha256)) result.observer_sha256=snapshot.observer_sha256;
388
+ const req=requestSha(policy,'machine_windows_query',args); const head=sha256Object(result);
389
+ const receipt=await writeReceipt(runtime,'machine_windows_query',req,head,{observed_at_utc:observedAt,query:args.query,observer_sha256:result.observer_sha256??null});
390
+ return {...result,request_sha256:req,result_head_sha256:head,...receipt};
391
+ }
392
+ return Object.freeze({policy,searchStart,searchPage,searchStatus,searchCancel,processList,systemStatus,hardwareQuery,windowsQuery});
341
393
  }
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.15.20';
1
+ export const DEADBYTE_VERSION = '0.15.22';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';