deadbyte-mcp 0.15.26 → 0.15.28

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,6 +1,6 @@
1
1
  {
2
2
  "name": "deadbyte-mcp",
3
- "version": "0.15.26",
3
+ "version": "0.15.28",
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-r49.ps1",
45
+ "gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r51.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",
@@ -72,7 +72,8 @@
72
72
  "r48:full:test": "node scripts/full-regression-r48.mjs",
73
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
- "release:npm": "node scripts/npm-release-r48.mjs"
75
+ "release:npm": "node scripts/npm-release-r48.mjs",
76
+ "r51:focused:test": "node --test --test-concurrency=1 test/r51-release-contract.test.mjs test/r51-runtime-coherence.test.mjs test/r51-live-log-polling.test.mjs test/coding-runtime.test.mjs test/remote-live-log-r37.test.mjs"
76
77
  },
77
78
  "bundleDependencies": [
78
79
  "@modelcontextprotocol/server",
@@ -8,7 +8,7 @@ import { loadPowerShellDataFile, runSlotUpdateCli } from '../src/runtime-update.
8
8
  import { parseActivePointer } from '../src/release-slot.mjs';
9
9
 
10
10
  const root=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
11
- const state=path.join(os.homedir(),'.deadbyte-mcp');
11
+ const state=path.resolve(process.env.DEADBYTE_STATE_ROOT||path.join(os.homedir(),'.deadbyte-mcp'));
12
12
  const sha=async f=>createHash('sha256').update(await readFile(f)).digest('hex');
13
13
  const sleep=ms=>new Promise(resolve=>setTimeout(resolve,ms));
14
14
 
@@ -0,0 +1,56 @@
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.27 / R50 gate failed at $Name with exit code $LASTEXITCODE" }
9
+ }
10
+
11
+ function Invoke-NodeTest {
12
+ param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$TestFiles)
13
+ Write-Host "==== $Name ===="
14
+ & node.exe --test --test-concurrency=1 @TestFiles
15
+ if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.27 / R50 gate failed at $Name with exit code $LASTEXITCODE" }
16
+ }
17
+
18
+ Invoke-NodeTest 'r50-package-boundary' @('test/package-boundary.test.mjs')
19
+ Invoke-NodeTest 'r50-release-smoke-isolation' @('test/release-smoke-isolation.test.mjs')
20
+ Invoke-GateStep 'containment-build' @('run','containment:build')
21
+ Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
22
+ Invoke-GateStep 'desktop-policy-refresh' @('run','desktop:policy:refresh')
23
+ Invoke-GateStep 'hardware-build' @('run','hardware:build')
24
+
25
+ $hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
26
+ Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
27
+ if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
28
+
29
+ Invoke-GateStep 'r50-release-focused' @('run','r48:release:test')
30
+ Invoke-NodeTest 'r49-donor-proof' @('test/r49-remote-control-donors.test.mjs')
31
+ Invoke-NodeTest 'r49-desktop-wait' @('test/desktop-runtime-r40.test.mjs','test/desktop-mcp-tools-r40.test.mjs','test/autonomous-desktop-r40.test.mjs')
32
+ Invoke-GateStep 'r49-catalog' @('run','r48:catalog:test')
33
+ Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
34
+ Invoke-GateStep 'full-regression' @('run','r48:full:test')
35
+ Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
36
+ Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
37
+ Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
38
+ Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
39
+ Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
40
+ Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
41
+ Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
42
+ Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
43
+ Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
44
+ Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
45
+ Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
46
+ Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
47
+ Invoke-GateStep 'manifest-write' @('run','manifest:write')
48
+ Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
49
+ Invoke-GateStep 'doctor' @('run','doctor')
50
+ Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
51
+ Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
52
+ Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
53
+
54
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r50.mjs')
55
+ if ($LASTEXITCODE -ne 0) { throw "R50 evidence writer failed with exit code $LASTEXITCODE" }
56
+ Write-Host '==== DEADBYTE 0.15.27 / R50 WINDOWS GATE: PASS ===='
@@ -0,0 +1,58 @@
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.28 / R51 gate failed at $Name with exit code $LASTEXITCODE" }
9
+ }
10
+
11
+ function Invoke-NodeTest {
12
+ param([Parameter(Mandatory)][string]$Name,[Parameter(Mandatory)][string[]]$TestFiles)
13
+ Write-Host "==== $Name ===="
14
+ & node.exe --test --test-concurrency=1 @TestFiles
15
+ if ($LASTEXITCODE -ne 0) { throw "DEADBYTE 0.15.28 / R51 gate failed at $Name with exit code $LASTEXITCODE" }
16
+ }
17
+
18
+ Invoke-NodeTest 'r51-package-boundary' @('test/package-boundary.test.mjs')
19
+ Invoke-NodeTest 'r51-release-smoke-isolation' @('test/release-smoke-isolation.test.mjs')
20
+ Invoke-GateStep 'r51-focused-contracts' @('run','r51:focused:test')
21
+ Invoke-GateStep 'containment-build' @('run','containment:build')
22
+ Invoke-GateStep 'process-policy-refresh' @('run','process:policy:refresh')
23
+ Write-Host "==== desktop-policy-refresh ===="
24
+ & (Join-Path $PSScriptRoot 'init-desktop-policy-r40.ps1')
25
+ Invoke-GateStep 'hardware-build' @('run','hardware:build')
26
+
27
+ $hostPolicy = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
28
+ Remove-Item -LiteralPath $hostPolicy -Force -ErrorAction SilentlyContinue
29
+ if (Test-Path -LiteralPath $hostPolicy) { throw 'could not establish hermetic Host policy absence' }
30
+
31
+ Invoke-GateStep 'r51-release-focused' @('run','r48:release:test')
32
+ Invoke-NodeTest 'r49-donor-proof' @('test/r49-remote-control-donors.test.mjs')
33
+ Invoke-NodeTest 'r49-desktop-wait' @('test/desktop-runtime-r40.test.mjs','test/desktop-mcp-tools-r40.test.mjs','test/autonomous-desktop-r40.test.mjs')
34
+ Invoke-GateStep 'r49-catalog' @('run','r48:catalog:test')
35
+ Invoke-GateStep 'commander-hardening' @('run','r47:hardening:test')
36
+ Invoke-GateStep 'full-regression' @('run','r48:full:test')
37
+ Invoke-GateStep 'mcp-smoke' @('run','mcp:smoke')
38
+ Invoke-GateStep 'mcp-agent-smoke' @('run','mcp:agent:smoke')
39
+ Invoke-GateStep 'mcp-coding-smoke' @('run','mcp:coding:smoke')
40
+ Invoke-GateStep 'mcp-machine-fs-smoke' @('run','mcp:machine-fs:smoke')
41
+ Invoke-GateStep 'mcp-observation-smoke' @('run','mcp:observation:smoke')
42
+ Invoke-GateStep 'mcp-process-smoke' @('run','mcp:process:smoke')
43
+ Invoke-GateStep 'mcp-autonomous-smoke' @('run','mcp:autonomous:smoke')
44
+ Invoke-GateStep 'tunnel-stdio-compat-smoke' @('run','mcp:tunnel-compat:smoke')
45
+ Invoke-GateStep 'containment-smoke' @('run','containment:smoke')
46
+ Invoke-GateStep 'contained-smoke' @('run','contained:smoke')
47
+ Invoke-GateStep 'mcp-contained-smoke' @('run','mcp:contained:smoke')
48
+ Invoke-GateStep 'host-policy-refresh' @('run','host:policy:init')
49
+ Invoke-GateStep 'manifest-write' @('run','manifest:write')
50
+ Invoke-GateStep 'manifest-verify' @('run','manifest:verify')
51
+ Invoke-GateStep 'doctor' @('run','doctor')
52
+ Invoke-GateStep 'mcp-host-smoke' @('run','mcp:host:smoke')
53
+ Invoke-GateStep 'authority-smoke' @('run','authority:smoke')
54
+ Invoke-GateStep 'manifest-final-verify' @('run','manifest:verify')
55
+
56
+ & node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r51.mjs')
57
+ if ($LASTEXITCODE -ne 0) { throw "R51 evidence writer failed with exit code $LASTEXITCODE" }
58
+ Write-Host '==== DEADBYTE 0.15.28 / R51 WINDOWS GATE: PASS ===='
@@ -0,0 +1,80 @@
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
+
17
+ insist(pkg.version === '0.15.27' && release.version === pkg.version && release.train === 'R50', 'R50 candidate identity mismatch');
18
+ insist(
19
+ active.release_id === release.parent.release_id &&
20
+ active.manifest_sha256 === release.parent.manifest_sha256 &&
21
+ active.generation_manifest_sha256 === release.parent.generation_manifest_sha256,
22
+ 'active runtime is not the exact sealed R50 parent'
23
+ );
24
+
25
+ const health = await doctor();
26
+ insist(health.status === 'ok' && health.package_version === pkg.version && health.manifest?.verified === true, 'R50 doctor evidence invalid');
27
+ insist(health.policy?.host_v2_ready === true, 'R50 Host policy v2 is not ready');
28
+
29
+ const evidence = {
30
+ schema: 'deadbyte.r50-windows-gate.v1',
31
+ status: 'passed',
32
+ exit_code: 0,
33
+ version: pkg.version,
34
+ train: 'R50',
35
+ completed_at_utc: new Date().toISOString(),
36
+ manifest_sha256: manifestSha256,
37
+ parent: release.parent,
38
+ active_predecessor: {
39
+ release_id: active.release_id,
40
+ version: active.version,
41
+ manifest_sha256: active.manifest_sha256,
42
+ generation_manifest_sha256: active.generation_manifest_sha256
43
+ },
44
+ doctor: { verified_entries: health.manifest.verified_entries, host_v2_ready: true },
45
+ gates: {
46
+ package_boundary: true,
47
+ release_smoke_isolation: true,
48
+ full_regression: true,
49
+ commander_hardening: true,
50
+ donor_proof: true,
51
+ desktop_wait: true,
52
+ exact_catalog: true,
53
+ stdio_smokes: true,
54
+ manifest_final_verify: true
55
+ }
56
+ };
57
+
58
+ const bytes = Buffer.from(`${JSON.stringify(evidence, null, 2)}\n`);
59
+ const dir = path.join(stateRoot, 'evidence', 'release');
60
+ await mkdir(dir, { recursive: true });
61
+ const target = path.join(dir, `r50-windows-gate-${manifestSha256.slice(0, 16)}.json`);
62
+
63
+ try {
64
+ const handle = await open(target, 'wx', 0o600);
65
+ try { await handle.writeFile(bytes); await handle.sync(); }
66
+ finally { await handle.close(); }
67
+ } catch (error) {
68
+ if (error?.code !== 'EEXIST') throw error;
69
+ const prior = JSON.parse(await readFile(target, 'utf8'));
70
+ insist(
71
+ prior.schema === evidence.schema &&
72
+ prior.status === 'passed' &&
73
+ prior.version === evidence.version &&
74
+ prior.manifest_sha256 === manifestSha256 &&
75
+ prior.parent?.release_id === release.parent.release_id,
76
+ 'conflicting R50 gate evidence identity'
77
+ );
78
+ }
79
+
80
+ console.log(JSON.stringify({ status: 'passed', path: target, sha256: sha256(bytes), manifest_sha256: manifestSha256 }));
@@ -0,0 +1,84 @@
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
+
17
+ insist(pkg.version === '0.15.28' && release.version === pkg.version && release.train === 'R51', 'R51 candidate identity mismatch');
18
+ insist(
19
+ active.release_id === release.parent.release_id &&
20
+ active.manifest_sha256 === release.parent.manifest_sha256 &&
21
+ active.generation_manifest_sha256 === release.parent.generation_manifest_sha256,
22
+ 'active runtime is not the exact sealed R51 parent'
23
+ );
24
+
25
+ const health = await doctor();
26
+ insist(health.status === 'ok' && health.package_version === pkg.version && health.manifest?.verified === true, 'R51 doctor evidence invalid');
27
+ insist(health.policy?.host_v2_ready === true, 'R51 Host policy v2 is not ready');
28
+
29
+ const evidence = {
30
+ schema: 'deadbyte.r51-windows-gate.v1',
31
+ status: 'passed',
32
+ exit_code: 0,
33
+ version: pkg.version,
34
+ train: 'R51',
35
+ completed_at_utc: new Date().toISOString(),
36
+ manifest_sha256: manifestSha256,
37
+ parent: release.parent,
38
+ active_predecessor: {
39
+ release_id: active.release_id,
40
+ version: active.version,
41
+ manifest_sha256: active.manifest_sha256,
42
+ generation_manifest_sha256: active.generation_manifest_sha256
43
+ },
44
+ doctor: { verified_entries: health.manifest.verified_entries, host_v2_ready: true },
45
+ gates: {
46
+ package_boundary: true,
47
+ release_smoke_isolation: true,
48
+ runtime_coherence: true,
49
+ coding_command_singleflight: true,
50
+ foreground_desktop_host_fail_closed: true,
51
+ livelog_optimizer: true,
52
+ full_regression: true,
53
+ commander_hardening: true,
54
+ donor_proof: true,
55
+ desktop_wait: true,
56
+ exact_catalog: true,
57
+ stdio_smokes: true,
58
+ manifest_final_verify: true
59
+ }
60
+ };
61
+
62
+ const bytes = Buffer.from(`${JSON.stringify(evidence, null, 2)}\n`);
63
+ const dir = path.join(stateRoot, 'evidence', 'release');
64
+ await mkdir(dir, { recursive: true });
65
+ const target = path.join(dir, `r51-windows-gate-${manifestSha256.slice(0, 16)}.json`);
66
+
67
+ try {
68
+ const handle = await open(target, 'wx', 0o600);
69
+ try { await handle.writeFile(bytes); await handle.sync(); }
70
+ finally { await handle.close(); }
71
+ } catch (error) {
72
+ if (error?.code !== 'EEXIST') throw error;
73
+ const prior = JSON.parse(await readFile(target, 'utf8'));
74
+ insist(
75
+ prior.schema === evidence.schema &&
76
+ prior.status === 'passed' &&
77
+ prior.version === evidence.version &&
78
+ prior.manifest_sha256 === manifestSha256 &&
79
+ prior.parent?.release_id === release.parent.release_id,
80
+ 'conflicting R51 gate evidence identity'
81
+ );
82
+ }
83
+
84
+ console.log(JSON.stringify({ status: 'passed', path: target, sha256: sha256(bytes), manifest_sha256: manifestSha256 }));
@@ -368,6 +368,93 @@ function requestSha(operation, args) {
368
368
  export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
369
369
  if (!policy) throw new Error('coding runtime requires policy');
370
370
  if (!signingKeyPath || !verifyKeyPath) throw new Error('coding runtime requires trust key paths');
371
+ const commandFlights = new Map();
372
+ const commandResults = new Map();
373
+ const COMMAND_RESULT_TTL_MS = 5 * 60 * 1000;
374
+ const COMMAND_RESULT_CACHE_MAX = 16;
375
+ const COMMAND_FLIGHT_SCHEMA = 'deadbyte.coding-command-flight.v1';
376
+ const COMMAND_RESULT_SCHEMA = 'deadbyte.coding-command-result.v1';
377
+ const commandFlightDir = path.join(policy.evidence_dir, 'command-flights');
378
+ function pruneCommandResults(now = Date.now()) {
379
+ for (const [key, entry] of commandResults) if (now - entry.completed_at_ms > COMMAND_RESULT_TTL_MS) commandResults.delete(key);
380
+ while (commandResults.size > COMMAND_RESULT_CACHE_MAX) commandResults.delete(commandResults.keys().next().value);
381
+ }
382
+ function commandFlightPaths(executionKey) {
383
+ const executionKeySha256 = sha256Bytes(Buffer.from(executionKey, 'utf8'));
384
+ return {
385
+ executionKeySha256,
386
+ claimPath: path.join(commandFlightDir, `${executionKeySha256}.claim.json`),
387
+ resultPath: path.join(commandFlightDir, `${executionKeySha256}.result.json`)
388
+ };
389
+ }
390
+ async function readDurableCommandResult(resultPath, executionKeySha256, request) {
391
+ let raw;
392
+ try { raw = JSON.parse(decodeUtf8Strict(await readFile(resultPath))); }
393
+ catch (error) {
394
+ if (error?.code === 'ENOENT') return null;
395
+ throw new Error(`coding command durable result invalid: ${String(error?.message ?? error)}`);
396
+ }
397
+ if (raw?.schema !== COMMAND_RESULT_SCHEMA || raw.execution_key_sha256 !== executionKeySha256 || raw.request_sha256 !== request ||
398
+ !Number.isInteger(raw.completed_at_ms) || !raw.result || typeof raw.result !== 'object' || Array.isArray(raw.result)) {
399
+ throw new Error('coding command durable result identity invalid');
400
+ }
401
+ if (Date.now() - raw.completed_at_ms > COMMAND_RESULT_TTL_MS) {
402
+ await rm(resultPath, { force: true });
403
+ return null;
404
+ }
405
+ const value = raw.result;
406
+ if (value.request_sha256 !== request || !RECEIPT_ID_RE.test(value.receipt_id ?? '') || !SHA256_RE.test(value.receipt_sha256 ?? '')) {
407
+ throw new Error('coding command durable result receipt identity invalid');
408
+ }
409
+ const verified = await verifyCodingReceiptFile(policy, verifyKeyPath, value.receipt_id);
410
+ if (!verified.ok || verified.request_sha256 !== request || verified.receipt_sha256 !== value.receipt_sha256) {
411
+ throw new Error(`coding command durable result receipt verification failed: ${verified.reason ?? 'identity mismatch'}`);
412
+ }
413
+ return { ...value };
414
+ }
415
+ async function writeDurableCommandResult(resultPath, executionKeySha256, request, value) {
416
+ const body = Buffer.from(`${JSON.stringify({ schema:COMMAND_RESULT_SCHEMA, execution_key_sha256:executionKeySha256,
417
+ request_sha256:request, completed_at_ms:Date.now(), result:value })}\n`, 'utf8');
418
+ try {
419
+ const handle = await open(resultPath, 'wx', 0o600);
420
+ try { await handle.writeFile(body); await handle.sync(); }
421
+ finally { await handle.close(); }
422
+ } catch (error) {
423
+ if (error?.code !== 'EEXIST') throw error;
424
+ const prior = await readDurableCommandResult(resultPath, executionKeySha256, request);
425
+ if (!prior || prior.receipt_id !== value.receipt_id || prior.receipt_sha256 !== value.receipt_sha256) {
426
+ throw new Error('coding command durable result conflict');
427
+ }
428
+ }
429
+ }
430
+ async function acquireDurableCommandFlight(executionKey, request, waitMs) {
431
+ await mkdir(commandFlightDir, { recursive: true });
432
+ const paths = commandFlightPaths(executionKey);
433
+ const cached = await readDurableCommandResult(paths.resultPath, paths.executionKeySha256, request);
434
+ if (cached) return { ...paths, owned:false, cached };
435
+ try {
436
+ const handle = await open(paths.claimPath, 'wx', 0o600);
437
+ try {
438
+ await handle.writeFile(Buffer.from(`${JSON.stringify({ schema:COMMAND_FLIGHT_SCHEMA, execution_key_sha256:paths.executionKeySha256,
439
+ request_sha256:request, owner_pid:process.pid, started_at_ms:Date.now() })}\n`, 'utf8'));
440
+ await handle.sync();
441
+ } finally { await handle.close(); }
442
+ return { ...paths, owned:true, cached:null };
443
+ } catch (error) {
444
+ if (error?.code !== 'EEXIST') throw error;
445
+ }
446
+ const deadline = Date.now() + waitMs;
447
+ for (;;) {
448
+ const result = await readDurableCommandResult(paths.resultPath, paths.executionKeySha256, request);
449
+ if (result) return { ...paths, owned:false, cached:result };
450
+ let claimExists = true;
451
+ try { await stat(paths.claimPath); }
452
+ catch (error) { if (error?.code === 'ENOENT') claimExists = false; else throw error; }
453
+ if (!claimExists) return acquireDurableCommandFlight(executionKey, request, Math.max(100, deadline - Date.now()));
454
+ if (Date.now() >= deadline) throw new Error('identical coding command is still running in another runtime instance');
455
+ await new Promise(resolve => setTimeout(resolve, 100));
456
+ }
457
+ }
371
458
 
372
459
  async function sessionStatus() {
373
460
  const status = await codingSessionStatus(policy);
@@ -587,23 +674,67 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
587
674
  root_id: rootId, command_id: commandId, script_path: scriptPath, script_sha256: scriptSha256,
588
675
  args, cwd, timeout_ms: timeoutMs
589
676
  });
590
- const started = new Date().toISOString();
591
- const result = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck });
592
- const signed = await signCodingReceipt(policy, signingKeyPath, result.lease, {
593
- operation: 'coding_command_run', request_sha256: request, root_id: rootId, command_id: commandId,
594
- script_path: scriptPath, executable_sha256: result.executable_sha256, script_sha256: result.script_sha256,
595
- started_at_utc: started, completed_at_utc: new Date().toISOString(), exit_code: result.exit_code,
596
- signal: result.signal, timed_out: result.timed_out, elapsed_ms: result.elapsed_ms,
597
- stdout_sha256: result.stdout_sha256, stderr_sha256: result.stderr_sha256
598
- }, receiptId);
599
- return {
600
- status: result.timed_out || result.exit_code !== 0 ? 'observed_failure' : 'passed',
601
- root_id: rootId, command_id: commandId, executable_sha256: result.executable_sha256,
602
- script_sha256: result.script_sha256, exit_code: result.exit_code, signal: result.signal,
603
- timed_out: result.timed_out, timeout_ms: result.timeout_ms, elapsed_ms: result.elapsed_ms,
604
- stdout: result.stdout, stderr: result.stderr,
605
- receipt_id: signed.receipt.receipt_id, receipt_sha256: signed.receipt.receipt_sha256, request_sha256: request
606
- };
677
+ const executionKey = receiptId === null ? request : `${request}:${receiptId}`;
678
+ pruneCommandResults();
679
+ const cached = commandResults.get(executionKey);
680
+ if (cached) {
681
+ await assertCodingArmed(policy, rootId);
682
+ return { ...cached.result };
683
+ }
684
+ const inFlight = commandFlights.get(executionKey);
685
+ if (inFlight) {
686
+ await assertCodingArmed(policy, rootId);
687
+ return { ...(await inFlight) };
688
+ }
689
+ if (!ID_RE.test(commandId ?? '')) throw new Error('invalid coding command id');
690
+ const command = policy.commands[commandId];
691
+ if (!command) throw new Error(`coding command '${commandId}' is not allowed`);
692
+ if (!command.root_ids.includes(rootId)) throw new Error(`coding command '${commandId}' is not allowed for root '${rootId}'`);
693
+ if (!Array.isArray(args) || args.length > 64 || args.some(item => typeof item !== 'string' || item.length > 2048 || item.includes('\0'))) {
694
+ throw new Error('coding command args must be <=64 strings of <=2048 characters');
695
+ }
696
+ if (!SHA256_RE.test(scriptSha256 ?? '')) throw new Error('script_sha256 must be lowercase SHA-256');
697
+ const requestedTimeout = timeoutMs === null ? command.timeout_ms : finiteInteger(timeoutMs, 'timeout_ms', 100, command.timeout_ms, command.timeout_ms);
698
+ const durable = await acquireDurableCommandFlight(executionKey, request, Math.min(900_000, requestedTimeout + 10_000));
699
+ if (durable.cached) {
700
+ await assertCodingArmed(policy, rootId);
701
+ commandResults.set(executionKey, { completed_at_ms: Date.now(), result: durable.cached });
702
+ pruneCommandResults();
703
+ return { ...durable.cached };
704
+ }
705
+ const execution = (async () => {
706
+ const started = new Date().toISOString();
707
+ const result = await runCommandOnce({ rootId, commandId, scriptPath, scriptSha256, args, cwd, timeoutMs, executionDeadlineUtc, preExecutionCheck });
708
+ const signed = await signCodingReceipt(policy, signingKeyPath, result.lease, {
709
+ operation: 'coding_command_run', request_sha256: request, root_id: rootId, command_id: commandId,
710
+ script_path: scriptPath, executable_sha256: result.executable_sha256, script_sha256: result.script_sha256,
711
+ started_at_utc: started, completed_at_utc: new Date().toISOString(), exit_code: result.exit_code,
712
+ signal: result.signal, timed_out: result.timed_out, elapsed_ms: result.elapsed_ms,
713
+ stdout_sha256: result.stdout_sha256, stderr_sha256: result.stderr_sha256
714
+ }, receiptId);
715
+ const value = {
716
+ status: result.timed_out || result.exit_code !== 0 ? 'observed_failure' : 'passed',
717
+ root_id: rootId, command_id: commandId, executable_sha256: result.executable_sha256,
718
+ script_sha256: result.script_sha256, exit_code: result.exit_code, signal: result.signal,
719
+ timed_out: result.timed_out, timeout_ms: result.timeout_ms, elapsed_ms: result.elapsed_ms,
720
+ stdout: result.stdout, stderr: result.stderr,
721
+ receipt_id: signed.receipt.receipt_id, receipt_sha256: signed.receipt.receipt_sha256, request_sha256: request
722
+ };
723
+ await writeDurableCommandResult(durable.resultPath, durable.executionKeySha256, request, value);
724
+ return value;
725
+ })();
726
+ commandFlights.set(executionKey, execution);
727
+ let completedDurably = false;
728
+ try {
729
+ const value = await execution;
730
+ completedDurably = true;
731
+ commandResults.set(executionKey, { completed_at_ms: Date.now(), result: value });
732
+ pruneCommandResults();
733
+ return { ...value };
734
+ } finally {
735
+ if (completedDurably && durable.owned) await rm(durable.claimPath, { force: true });
736
+ if (commandFlights.get(executionKey) === execution) commandFlights.delete(executionKey);
737
+ }
607
738
  }
608
739
 
609
740
  function percentile(samples, fraction) {