deadbyte-mcp 0.15.21 → 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.
package/package.json CHANGED
@@ -1,93 +1,94 @@
1
- {
2
- "name": "deadbyte-mcp",
3
- "version": "0.15.21",
4
- "private": false,
5
- "type": "module",
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.",
7
- "engines": {
8
- "node": ">=22"
9
- },
10
- "scripts": {
11
- "test": "node --test test/*.test.mjs",
12
- "manifest:write": "node scripts/release-manifest.mjs write",
13
- "manifest:verify": "node scripts/release-manifest.mjs verify",
14
- "r41:parent:verify": "node scripts/verify-r41-parent.mjs",
15
- "r41:memory:verify": "node scripts/verify-memory-r41.mjs",
16
- "r42:parent:verify": "node scripts/verify-r42-parent.mjs",
17
- "r42:eval": "node scripts/agent-eval-r42.mjs",
18
- "self-update:runtime": "node scripts/runtime-self-update.mjs",
19
- "self-update:deferred": "node scripts/deferred-slot-operation-r46.mjs",
20
- "release:parity": "node scripts/release-parity-r46.mjs",
21
- "release:final:write": "node scripts/final-closure-r46.mjs",
22
- "release:final:verify": "node scripts/final-closure-verify-r46.mjs",
23
- "proof": "node src/proof-cli.mjs workspaces/demo input.txt",
24
- "verify": "node src/verifier-cli.mjs workspaces/demo evidence/latest.json",
25
- "trust:init": "node src/trust-init.mjs",
26
- "mcp": "node src/mcp-server.mjs",
27
- "mcp:smoke": "node src/mcp-smoke-client.mjs",
28
- "mcp:agent:smoke": "node --test test/agent-runtime.test.mjs test/agent-runtime-adversarial.test.mjs test/agent-runtime-crash.test.mjs test/agent-task-receipt.test.mjs",
29
- "mcp:coding:smoke": "node --test test/coding-plane.test.mjs test/coding-plane-adversarial.test.mjs test/coding-runtime.test.mjs test/coding-crash.test.mjs",
30
- "mcp:machine-fs:smoke": "node src/machine-fs-smoke-client.mjs",
31
- "mcp:observation:smoke": "node src/observation-smoke-client.mjs",
32
- "mcp:process:smoke": "node src/process-smoke-client.mjs",
33
- "process:policy:refresh": "node scripts/refresh-process-policy.mjs",
34
- "mcp:autonomous:smoke": "node --test test/autonomous-runtime.test.mjs test/autonomous-loop.test.mjs test/autonomous-adversarial.test.mjs test/autonomous-supervisor-integration.test.mjs test/native-diff.test.mjs",
35
- "containment:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-containment.ps1",
36
- "containment:smoke": "node src/containment-smoke.mjs appcontainer",
37
- "containment:bootstrap": "node src/containment-bootstrap.mjs",
38
- "containment:smoke:lpac": "node src/containment-smoke.mjs lpac",
39
- "containment:smoke:appcontainer": "node src/containment-smoke.mjs appcontainer",
40
- "containment:construction": "node src/containment-construction.mjs",
41
- "containment:child-control": "node src/containment-child-control.mjs",
42
- "contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
43
- "contained:smoke": "node src/contained-smoke.mjs",
44
- "mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
45
- "gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r46.ps1",
46
- "authority:smoke": "node src/authority-smoke.mjs",
47
- "mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
48
- "mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
49
- "host:policy:init": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-host-policy.ps1",
50
- "mcp:remote:host:smoke": "node src/remote-mcp-host-smoke-client.mjs",
51
- "mcp:remote:autonomous:smoke": "node src/remote-mcp-autonomous-smoke-client.mjs",
52
- "mcp:tunnel-compat:smoke": "node src/tunnel-stdio-compat-smoke.mjs",
53
- "audit:verify": "node src/deadbyte-cli.mjs audit verify",
54
- "audit:status": "node src/deadbyte-cli.mjs audit status",
55
- "desktop:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-desktop-r40.ps1",
56
- "desktop:policy:refresh": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-desktop-policy-r40.ps1",
57
- "r43:parent:verify": "node scripts/verify-r43-parent.mjs",
58
- "r43:full:test": "node scripts/full-regression-r43.mjs",
59
- "r44:parent:verify": "node scripts/verify-r44-parent.mjs",
60
- "r44:full:test": "node scripts/full-regression-r44.mjs",
61
- "finalize:r44": "node scripts/finalize-r44.mjs",
62
- "hardware:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-hardware-r45.ps1",
63
- "doctor": "node src/deadbyte-cli.mjs doctor",
64
- "r45:parent:verify": "node scripts/verify-r45-parent.mjs",
65
- "r45:full:test": "node scripts/full-regression-r45.mjs",
66
- "finalize:r45": "node scripts/finalize-r45.mjs",
67
- "r46:fileless:test": "node --test --test-concurrency=1 test/process-policy.test.mjs test/process-policy-refresh.test.mjs test/release-generation.test.mjs test/process-runtime.test.mjs test/process-mcp-tools.test.mjs test/compact-gateway-r36.test.mjs test/capability-ledger-r36.test.mjs test/remote-device-r44.test.mjs test/observation-runtime.test.mjs test/observation-mcp-tools.test.mjs",
68
- "r46:full:test": "node scripts/full-regression-r46.mjs",
69
- "r47:full:test": "node scripts/full-regression-r47.mjs",
70
- "r47:catalog:test": "node --test --test-concurrency=1 test/full-max-catalog-r47.test.mjs",
71
- "r47:hardening:test": "node scripts/commander-hardening-gate-r47.mjs",
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"
74
- },
75
- "bundleDependencies": [
76
- "@modelcontextprotocol/server",
77
- "@modelcontextprotocol/client",
78
- "typescript",
79
- "zod"
80
- ],
81
- "dependencies": {
82
- "@modelcontextprotocol/client": "2.1.0",
83
- "@modelcontextprotocol/server": "2.1.0",
84
- "typescript": "5.9.3",
85
- "zod": "4.4.3"
86
- },
87
- "bin": {
88
- "deadbyte-mcp": "src/deadbyte-cli.mjs"
89
- },
90
- "publishConfig": {
91
- "access": "public"
92
- }
93
- }
1
+ {
2
+ "name": "deadbyte-mcp",
3
+ "version": "0.15.22",
4
+ "private": false,
5
+ "type": "module",
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.",
7
+ "engines": {
8
+ "node": ">=22"
9
+ },
10
+ "scripts": {
11
+ "test": "node --test test/*.test.mjs",
12
+ "manifest:write": "node scripts/release-manifest.mjs write",
13
+ "manifest:verify": "node scripts/release-manifest.mjs verify",
14
+ "r41:parent:verify": "node scripts/verify-r41-parent.mjs",
15
+ "r41:memory:verify": "node scripts/verify-memory-r41.mjs",
16
+ "r42:parent:verify": "node scripts/verify-r42-parent.mjs",
17
+ "r42:eval": "node scripts/agent-eval-r42.mjs",
18
+ "self-update:runtime": "node scripts/runtime-self-update.mjs",
19
+ "self-update:deferred": "node scripts/deferred-slot-operation-r46.mjs",
20
+ "release:parity": "node scripts/release-parity-r46.mjs",
21
+ "release:final:write": "node scripts/final-closure-r46.mjs",
22
+ "release:final:verify": "node scripts/final-closure-verify-r46.mjs",
23
+ "proof": "node src/proof-cli.mjs workspaces/demo input.txt",
24
+ "verify": "node src/verifier-cli.mjs workspaces/demo evidence/latest.json",
25
+ "trust:init": "node src/trust-init.mjs",
26
+ "mcp": "node src/mcp-server.mjs",
27
+ "mcp:smoke": "node src/mcp-smoke-client.mjs",
28
+ "mcp:agent:smoke": "node --test test/agent-runtime.test.mjs test/agent-runtime-adversarial.test.mjs test/agent-runtime-crash.test.mjs test/agent-task-receipt.test.mjs",
29
+ "mcp:coding:smoke": "node --test test/coding-plane.test.mjs test/coding-plane-adversarial.test.mjs test/coding-runtime.test.mjs test/coding-crash.test.mjs",
30
+ "mcp:machine-fs:smoke": "node src/machine-fs-smoke-client.mjs",
31
+ "mcp:observation:smoke": "node src/observation-smoke-client.mjs",
32
+ "mcp:process:smoke": "node src/process-smoke-client.mjs",
33
+ "process:policy:refresh": "node scripts/refresh-process-policy.mjs",
34
+ "mcp:autonomous:smoke": "node --test test/autonomous-runtime.test.mjs test/autonomous-loop.test.mjs test/autonomous-adversarial.test.mjs test/autonomous-supervisor-integration.test.mjs test/native-diff.test.mjs",
35
+ "containment:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-containment.ps1",
36
+ "containment:smoke": "node src/containment-smoke.mjs appcontainer",
37
+ "containment:bootstrap": "node src/containment-bootstrap.mjs",
38
+ "containment:smoke:lpac": "node src/containment-smoke.mjs lpac",
39
+ "containment:smoke:appcontainer": "node src/containment-smoke.mjs appcontainer",
40
+ "containment:construction": "node src/containment-construction.mjs",
41
+ "containment:child-control": "node src/containment-child-control.mjs",
42
+ "contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
43
+ "contained:smoke": "node src/contained-smoke.mjs",
44
+ "mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
45
+ "gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r46.ps1",
46
+ "authority:smoke": "node src/authority-smoke.mjs",
47
+ "mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
48
+ "mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
49
+ "host:policy:init": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-host-policy.ps1",
50
+ "mcp:remote:host:smoke": "node src/remote-mcp-host-smoke-client.mjs",
51
+ "mcp:remote:autonomous:smoke": "node src/remote-mcp-autonomous-smoke-client.mjs",
52
+ "mcp:tunnel-compat:smoke": "node src/tunnel-stdio-compat-smoke.mjs",
53
+ "audit:verify": "node src/deadbyte-cli.mjs audit verify",
54
+ "audit:status": "node src/deadbyte-cli.mjs audit status",
55
+ "desktop:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-desktop-r40.ps1",
56
+ "desktop:policy:refresh": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-desktop-policy-r40.ps1",
57
+ "r43:parent:verify": "node scripts/verify-r43-parent.mjs",
58
+ "r43:full:test": "node scripts/full-regression-r43.mjs",
59
+ "r44:parent:verify": "node scripts/verify-r44-parent.mjs",
60
+ "r44:full:test": "node scripts/full-regression-r44.mjs",
61
+ "finalize:r44": "node scripts/finalize-r44.mjs",
62
+ "hardware:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-hardware-r45.ps1",
63
+ "doctor": "node src/deadbyte-cli.mjs doctor",
64
+ "r45:parent:verify": "node scripts/verify-r45-parent.mjs",
65
+ "r45:full:test": "node scripts/full-regression-r45.mjs",
66
+ "finalize:r45": "node scripts/finalize-r45.mjs",
67
+ "r46:fileless:test": "node --test --test-concurrency=1 test/process-policy.test.mjs test/process-policy-refresh.test.mjs test/release-generation.test.mjs test/process-runtime.test.mjs test/process-mcp-tools.test.mjs test/compact-gateway-r36.test.mjs test/capability-ledger-r36.test.mjs test/remote-device-r44.test.mjs test/observation-runtime.test.mjs test/observation-mcp-tools.test.mjs",
68
+ "r46:full:test": "node scripts/full-regression-r46.mjs",
69
+ "r47:full:test": "node scripts/full-regression-r47.mjs",
70
+ "r47:catalog:test": "node --test --test-concurrency=1 test/full-max-catalog-r47.test.mjs",
71
+ "r47:hardening:test": "node scripts/commander-hardening-gate-r47.mjs",
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",
74
+ "r48:catalog:test": "node --test --test-concurrency=1 test/full-max-catalog-r48.test.mjs"
75
+ },
76
+ "bundleDependencies": [
77
+ "@modelcontextprotocol/server",
78
+ "@modelcontextprotocol/client",
79
+ "typescript",
80
+ "zod"
81
+ ],
82
+ "dependencies": {
83
+ "@modelcontextprotocol/client": "2.1.0",
84
+ "@modelcontextprotocol/server": "2.1.0",
85
+ "typescript": "5.9.3",
86
+ "zod": "4.4.3"
87
+ },
88
+ "bin": {
89
+ "deadbyte-mcp": "src/deadbyte-cli.mjs"
90
+ },
91
+ "publishConfig": {
92
+ "access": "public"
93
+ }
94
+ }
@@ -53,6 +53,24 @@ foreach($query in @('cpu','gpu','memory','storage','network','pci')){
53
53
  $queries[$query]=Get-Sha256Hex -Path $Exe
54
54
  }
55
55
 
56
+ $windowsQueries=[ordered]@{}
57
+ foreach($query in @('services','drivers','sockets','volumes','usb','wsl')){
58
+ $raw=& $Exe $query 2>&1
59
+ $queryExit=$LASTEXITCODE
60
+ if($queryExit -ne 0){throw "Windows query $query failed exit=$queryExit output=$($raw -join ' ')"}
61
+ $text=($raw -join [Environment]::NewLine)
62
+ $parsed=$text | ConvertFrom-Json
63
+ if($parsed.schema -ne 'deadbyte.windows-query.v1' -or $parsed.query -ne $query){throw "Windows query $query contract mismatch"}
64
+ $windowsQueries[$query]=Get-Sha256Hex -Path $Exe
65
+ }
66
+ $registryRaw=& $Exe registry HKLM 'SOFTWARE\Microsoft\Windows NT\CurrentVersion' ProductName 2>&1
67
+ $registryExit=$LASTEXITCODE
68
+ if($registryExit -ne 0){throw "Windows registry query failed exit=$registryExit output=$($registryRaw -join ' ')"}
69
+ $registryText=($registryRaw -join [Environment]::NewLine)
70
+ $registryParsed=$registryText | ConvertFrom-Json
71
+ if($registryParsed.schema -ne 'deadbyte.windows-query.v1' -or $registryParsed.query -ne 'registry'){throw 'Windows registry query contract mismatch'}
72
+ $windowsQueries['registry']=Get-Sha256Hex -Path $Exe
73
+
56
74
  $depLine='call "{0}" -no_logo -arch=x64 -host_arch=x64 && dumpbin /nologo /dependents "{1}"' -f $dev,$Exe
57
75
  $deps=& $cmd /d /s /c $depLine 2>&1
58
76
  $depExit=$LASTEXITCODE
@@ -67,5 +85,6 @@ if($depExit -ne 0){throw "hardware observer dumpbin failed exit=$depExit"}
67
85
  obj_sha256=Get-Sha256Hex -Path $Obj
68
86
  selftest=@($self | ForEach-Object {[string]$_})
69
87
  queries=@($queries.Keys)
88
+ windows_queries=@($windowsQueries.Keys)
70
89
  dependencies=@($deps | ForEach-Object {[string]$_})
71
90
  }|ConvertTo-Json -Depth 5
@@ -0,0 +1,27 @@
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=8;
16
+ const batches=Array.from({length:batchCount},()=>[]);
17
+ weighted.forEach((entry,index)=>batches[index%batchCount].push(entry.path));
18
+ const requested=Number(process.argv[2]);
19
+ if(!Number.isInteger(requested)||requested<1||requested>batchCount) throw new Error('usage: node full-regression-r48-batch.mjs <1..8>');
20
+ const batch=batches[requested-1].sort((a,b)=>a.localeCompare(b,'en'));
21
+ console.log(`R48-BOUNDED-REGRESSION batch=${requested}/${batchCount} files=${batch.length}`);
22
+ console.log(batch.join('\n'));
23
+ const result=spawnSync(process.execPath,['--test','--test-concurrency=1',...batch],{cwd:root,stdio:'inherit',windowsHide:true,shell:false});
24
+ if(result.error) throw result.error;
25
+ if(result.signal) throw new Error(`regression batch ${requested} terminated by ${result.signal}`);
26
+ if(result.status!==0) throw new Error(`regression batch ${requested} failed with exit code ${result.status}`);
27
+ console.log(`R48-BOUNDED-REGRESSION BATCH PASS batch=${requested} files=${batch.length}`);
@@ -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_C_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 = 'C:\'
70
+ read = $true
71
+ write = $true
72
+ exec = $true
73
+ deny_paths = @()
74
+ }
75
+ if ($coding.roots.PSObject.Properties.Name -contains 'local_c') {
76
+ $coding.roots.local_c = $localRoot
77
+ } else {
78
+ $coding.roots | Add-Member -NotePropertyName 'local_c' -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_c' -notin $ids) { $command.root_ids = @($ids + 'local_c') }
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_c=C:\'
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-c.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-c.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_C_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
+ }