deadbyte-mcp 0.14.0 → 0.15.1

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 (157) hide show
  1. package/AGENTS.md +11 -18
  2. package/CONTEXT.md +3 -3
  3. package/MANIFEST.SHA256 +156 -70
  4. package/PROVENANCE.json +10 -0
  5. package/R43-PARENT.json +20 -0
  6. package/R44-DONORS.json +99 -0
  7. package/R44-PARENT.json +18 -0
  8. package/R45-PARENT.json +18 -0
  9. package/README.txt +19 -14
  10. package/RELEASE.json +37 -0
  11. package/SBOM.cdx.json +46 -0
  12. package/TEST-MATRIX.json +31 -0
  13. package/bin/deadbyte-hardware-observer-r45.exe +0 -0
  14. package/bin/deadbyte-hardware-observer-r45.obj +0 -0
  15. package/controller/README.TXT +5 -6
  16. package/controller/deadbyte-controller.ps1 +2 -2
  17. package/docs/ARCHITECTURE.md +8 -1
  18. package/docs/R44-ARCHITECTURE.md +37 -0
  19. package/native/deadbyte-hardware-observer.cpp +308 -0
  20. package/package.json +18 -8
  21. package/scripts/autonomous-tests.ps1 +2 -2
  22. package/scripts/build-hardware-r45.ps1 +71 -0
  23. package/scripts/deferred-slot-operation-r43.mjs +126 -0
  24. package/scripts/deferred-slot-operation-r44.mjs +126 -0
  25. package/scripts/deferred-slot-operation-r45.mjs +126 -0
  26. package/scripts/derive-r45-parent.mjs +24 -0
  27. package/scripts/derive-r45-release.mjs +72 -0
  28. package/scripts/derive-r45-tests.mjs +20 -0
  29. package/scripts/final-closure-r43.mjs +115 -0
  30. package/scripts/final-closure-r44.mjs +121 -0
  31. package/scripts/final-closure-r45.mjs +121 -0
  32. package/scripts/final-closure-verify-r43.mjs +213 -0
  33. package/scripts/final-closure-verify-r44.mjs +220 -0
  34. package/scripts/final-closure-verify-r45.mjs +220 -0
  35. package/scripts/finalize-r43.mjs +217 -0
  36. package/scripts/finalize-r44.mjs +217 -0
  37. package/scripts/finalize-r45.mjs +219 -0
  38. package/scripts/full-regression-r43.mjs +20 -0
  39. package/scripts/full-regression-r44.mjs +20 -0
  40. package/scripts/full-regression-r45.mjs +20 -0
  41. package/scripts/full-regression-summary-r45.mjs +14 -0
  42. package/scripts/gate-windows-r43.ps1 +36 -0
  43. package/scripts/gate-windows-r44.ps1 +36 -0
  44. package/scripts/gate-windows-r45.ps1 +44 -0
  45. package/scripts/init-host-policy.ps1 +39 -1
  46. package/scripts/inspect-active-release-r45.mjs +20 -0
  47. package/scripts/release-manifest.mjs +3 -1
  48. package/scripts/release-parity-r43.mjs +218 -0
  49. package/scripts/release-parity-r44.mjs +242 -0
  50. package/scripts/release-parity-r45.mjs +253 -0
  51. package/scripts/release-parity-tests-r43.ps1 +8 -0
  52. package/scripts/release-parity-tests-r44.ps1 +8 -0
  53. package/scripts/release-parity-tests-r45.ps1 +8 -0
  54. package/scripts/verify-r43-parent.mjs +126 -0
  55. package/scripts/verify-r44-parent.mjs +142 -0
  56. package/scripts/verify-r45-parent.mjs +142 -0
  57. package/scripts/windows-gate-evidence-r43.mjs +55 -0
  58. package/scripts/windows-gate-evidence-r44.mjs +55 -0
  59. package/scripts/windows-gate-evidence-r45.mjs +60 -0
  60. package/src/agent-backend-r44.mjs +254 -0
  61. package/src/autonomous-output-contracts.mjs +1 -1
  62. package/src/autonomous-policy.mjs +41 -4
  63. package/src/autonomous-runtime.mjs +37 -19
  64. package/src/autonomous-supervisor-host.mjs +12 -2
  65. package/src/capability-ledger.mjs +3 -1
  66. package/src/codex-app-server-r44.mjs +154 -0
  67. package/src/coding-plane.mjs +66 -19
  68. package/src/compact-gateway-mcp-tools.mjs +4 -2
  69. package/src/deadbyte-cli.mjs +17 -9
  70. package/src/doctor-r45.mjs +65 -0
  71. package/src/durable-job-r44.mjs +145 -0
  72. package/src/external-job-provider-r44.mjs +126 -0
  73. package/src/host-plane.mjs +156 -87
  74. package/src/job-supervisor-host-r44.mjs +112 -0
  75. package/src/machine-fs-smoke-client.mjs +1 -1
  76. package/src/machine-fs.mjs +21 -10
  77. package/src/mcp-host-smoke-client.mjs +1 -1
  78. package/src/mcp-server.mjs +84 -26
  79. package/src/mcp-smoke-client.mjs +1 -1
  80. package/src/native-diff-v2.mjs +12 -7
  81. package/src/native-diff.mjs +32 -9
  82. package/src/observation-mcp-tools.mjs +5 -1
  83. package/src/observation-output-contracts.mjs +8 -0
  84. package/src/observation-runtime.mjs +33 -2
  85. package/src/observation-smoke-client.mjs +7 -3
  86. package/src/operator-surface.mjs +2 -2
  87. package/src/output-contracts.mjs +27 -11
  88. package/src/process-policy.mjs +19 -0
  89. package/src/process-runtime.mjs +5 -2
  90. package/src/process-smoke-client.mjs +2 -2
  91. package/src/provider-circuit.mjs +8 -2
  92. package/src/r44-compact-disarmed-probe.mjs +74 -0
  93. package/src/r44-full-surface-probe.mjs +34 -0
  94. package/src/r45-compact-disarmed-probe.mjs +74 -0
  95. package/src/r45-full-surface-probe.mjs +34 -0
  96. package/src/release-generation.mjs +1 -0
  97. package/src/remote-device-r44.mjs +205 -0
  98. package/src/remote-mcp-autonomous-smoke-client.mjs +4 -4
  99. package/src/remote-mcp-r44-parity-client.mjs +203 -0
  100. package/src/remote-mcp-r45-parity-client.mjs +206 -0
  101. package/src/remote-mcp-smoke-client.mjs +7 -4
  102. package/src/runtime-update.mjs +100 -39
  103. package/src/skill-mcp-tools-r44.mjs +37 -0
  104. package/src/skill-plane-r44.mjs +203 -0
  105. package/src/tunnel-stdio-compat-smoke.mjs +1 -1
  106. package/src/version.mjs +1 -1
  107. package/test/agent-backend-r44.test.mjs +115 -0
  108. package/test/agent-runtime.test.mjs +4 -3
  109. package/test/autonomous-loop.test.mjs +121 -11
  110. package/test/autonomous-runtime.test.mjs +3 -2
  111. package/test/capability-ledger-r36.test.mjs +3 -3
  112. package/test/cli-entrypoint.test.mjs +4 -4
  113. package/test/codex-app-server-r44.test.mjs +115 -0
  114. package/test/codex-autonomous-r44.test.mjs +87 -0
  115. package/test/coding-plane.test.mjs +3 -2
  116. package/test/coding-runtime.test.mjs +36 -1
  117. package/test/compact-catalog-r36.test.mjs +3 -3
  118. package/test/compact-max-catalog-r40.test.mjs +4 -2
  119. package/test/compact-max-catalog-r44.test.mjs +97 -0
  120. package/test/compact-max-catalog-r45.test.mjs +99 -0
  121. package/test/contained.test.mjs +23 -11
  122. package/test/controller.test.mjs +5 -1
  123. package/test/core.test.mjs +1 -1
  124. package/test/durable-job-r44.test.mjs +75 -0
  125. package/test/external-job-provider-r44.test.mjs +46 -0
  126. package/test/full-max-catalog-r40.test.mjs +5 -3
  127. package/test/full-max-catalog-r44.test.mjs +91 -0
  128. package/test/full-max-catalog-r45.test.mjs +91 -0
  129. package/test/hardware-observation-r45.test.mjs +44 -0
  130. package/test/host-inline-r45.test.mjs +67 -0
  131. package/test/host-plane.test.mjs +15 -1
  132. package/test/machine-mcp-integration.test.mjs +1 -0
  133. package/test/native-diff.test.mjs +28 -0
  134. package/test/observation-mcp-tools.test.mjs +4 -3
  135. package/test/output-schema.test.mjs +3 -2
  136. package/test/package-boundary.test.mjs +1 -1
  137. package/test/process-policy.test.mjs +22 -1
  138. package/test/production-docs.test.mjs +3 -3
  139. package/test/prompts-resources.test.mjs +1 -1
  140. package/test/r33-closeout-regression.test.mjs +20 -36
  141. package/test/r33-finalization.test.mjs +7 -7
  142. package/test/r43-finalization.test.mjs +31 -0
  143. package/test/r43-finalizer.test.mjs +34 -0
  144. package/test/r43-parent.test.mjs +29 -0
  145. package/test/r44-finalization.test.mjs +58 -0
  146. package/test/r44-finalizer.test.mjs +48 -0
  147. package/test/r44-parent.test.mjs +25 -0
  148. package/test/r45-autonomous-quick-test.test.mjs +10 -0
  149. package/test/r45-finalization.test.mjs +84 -0
  150. package/test/release-generation.test.mjs +1 -0
  151. package/test/release-version.test.mjs +65 -20
  152. package/test/remote-device-r44.test.mjs +104 -0
  153. package/test/runtime-host-bootstrap-r45.test.mjs +46 -0
  154. package/test/runtime-self-update.test.mjs +42 -0
  155. package/test/skill-mcp-r44.test.mjs +38 -0
  156. package/test/skill-plane-r44.test.mjs +93 -0
  157. package/test/standing-grants.test.mjs +5 -1
@@ -30,12 +30,31 @@ function normalizeProviderCircuit(raw) {
30
30
  half_open_probe_limit:integer(value.half_open_probe_limit,'planner.circuit.half_open_probe_limit',1,8,1)
31
31
  });
32
32
  }
33
- function normalizePlanner(raw) {
33
+ function normalizePlanner(raw,codingPolicy,rootIds) {
34
34
  if (!raw || typeof raw !== 'object' || Array.isArray(raw)) throw new Error('autonomous planner missing');
35
35
  const backend = raw.backend;
36
- if (!['client_sampling', 'openai_compatible', 'openai_responses'].includes(backend)) throw new Error('autonomous planner backend invalid');
36
+ if (!['client_sampling', 'openai_compatible', 'openai_responses', 'codex_app_server'].includes(backend)) throw new Error('autonomous planner backend invalid');
37
37
  const common = { backend, max_tokens: integer(raw.max_tokens, 'planner.max_tokens', 256, 16384, 4096) };
38
38
  if (backend === 'client_sampling') return common;
39
+ if (typeof raw.model !== 'string' || raw.model.length < 1 || raw.model.length > 128) throw new Error('planner.model invalid');
40
+ if (backend === 'codex_app_server') {
41
+ if (!ID_RE.test(raw.root_id ?? '') || !rootIds.includes(raw.root_id) || !codingPolicy.roots[raw.root_id]) {
42
+ throw new Error('planner.root_id invalid');
43
+ }
44
+ if (typeof raw.executable !== 'string' || !path.isAbsolute(raw.executable)) throw new Error('planner.executable must be absolute');
45
+ if (!SHA256_RE.test(raw.executable_sha256 ?? '')) throw new Error('planner.executable_sha256 invalid');
46
+ const args=raw.args ?? ['app-server'];
47
+ if (!Array.isArray(args) || args.length < 1 || args.length > 16 ||
48
+ args.some(value=>typeof value!=='string'||value.length<1||value.length>2048||value.includes('\0'))) {
49
+ throw new Error('planner.args invalid');
50
+ }
51
+ return {
52
+ ...common, model:raw.model, root_id:raw.root_id, executable:path.resolve(raw.executable),
53
+ executable_sha256:raw.executable_sha256, args:[...args],
54
+ timeout_ms:integer(raw.timeout_ms,'planner.timeout_ms',1000,300000,60000),
55
+ circuit:normalizeProviderCircuit(raw.circuit)
56
+ };
57
+ }
39
58
  if (typeof raw.endpoint !== 'string') throw new Error('planner.endpoint required');
40
59
  const endpoint = new URL(raw.endpoint);
41
60
  const loopback = ['127.0.0.1', 'localhost', '::1'].includes(endpoint.hostname);
@@ -43,7 +62,6 @@ function normalizePlanner(raw) {
43
62
  throw new Error('planner endpoint must be HTTPS or loopback HTTP');
44
63
  }
45
64
  if (endpoint.username || endpoint.password || endpoint.hash) throw new Error('planner endpoint credentials/fragments forbidden');
46
- if (typeof raw.model !== 'string' || raw.model.length < 1 || raw.model.length > 128) throw new Error('planner.model invalid');
47
65
  const apiKeyEnv = raw.api_key_env ?? null;
48
66
  if (apiKeyEnv !== null && !ENV_RE.test(apiKeyEnv)) throw new Error('planner.api_key_env invalid');
49
67
  const provider = {
@@ -117,7 +135,7 @@ export async function loadAutonomousPolicy(policyPath, codingPolicy) {
117
135
  schema: AUTONOMOUS_POLICY_SCHEMA, enabled: true, policy_path: absolute,
118
136
  lease_file: path.resolve(raw.lease_file), evidence_dir: path.resolve(raw.evidence_dir),
119
137
  coding_policy_sha256: codingPolicy.policy_sha256, root_ids: rootIds,
120
- planner: normalizePlanner(raw.planner), profiles,
138
+ planner: normalizePlanner(raw.planner,codingPolicy,rootIds), profiles,
121
139
  limits: {
122
140
  max_iterations: integer(limits.max_iterations, 'limits.max_iterations', 1, 64, 12),
123
141
  max_mutations: integer(limits.max_mutations, 'limits.max_mutations', 1, 128, 24),
@@ -165,3 +183,22 @@ export async function assertAutonomousArmed(policy, rootId = null, now = new Dat
165
183
  if (rootId !== null && !status.root_ids.includes(rootId)) throw new Error(`autonomous root '${rootId}' is outside active lease`);
166
184
  return status;
167
185
  }
186
+
187
+ export async function recheckAutonomousAuthority(policy, initial, rootId = null, now = new Date()) {
188
+ if (!initial?.armed || typeof initial.instance_nonce !== 'string' || !Array.isArray(initial.root_ids)) {
189
+ throw new Error('autonomous authority recheck requires an armed initial snapshot');
190
+ }
191
+ let current;
192
+ try { current = await assertAutonomousArmed(policy, rootId, now); }
193
+ catch (error) { throw new Error(`autonomous authority changed during operation: ${String(error?.message ?? error)}`); }
194
+ const initialRoots = [...initial.root_ids].sort();
195
+ const currentRoots = [...current.root_ids].sort();
196
+ const changed =
197
+ current.instance_nonce !== initial.instance_nonce ||
198
+ current.standing !== initial.standing ||
199
+ current.expires_at_utc !== initial.expires_at_utc ||
200
+ initialRoots.length !== currentRoots.length ||
201
+ initialRoots.some((id, index) => id !== currentRoots[index]);
202
+ if (changed) throw new Error('autonomous authority changed during operation');
203
+ return current;
204
+ }
@@ -3,7 +3,7 @@ import { access, mkdir, open, readFile, readdir, rm, writeFile } from 'node:fs/p
3
3
  import path from 'node:path';
4
4
  import { canonicalJson } from './canonical-json.mjs';
5
5
  import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
6
- import { assertAutonomousArmed, autonomousSessionStatus } from './autonomous-policy.mjs';
6
+ import { assertAutonomousArmed, autonomousSessionStatus, recheckAutonomousAuthority } from './autonomous-policy.mjs';
7
7
  import { buildPlannerPrompt, parsePlannerDecision, parseR34PlannerDecision, requestProviderDecision } from './autonomous-planner.mjs';
8
8
  import { actionIdentity, reconcileStartedAction } from './autonomous-action-reconcile.mjs';
9
9
  import { createPlan, replanPlan, completePlanStep, planIsComplete as r34PlanIsComplete } from './autonomous-plan.mjs';
@@ -274,16 +274,24 @@ async function executeProfile({ ctx, events, goalId, actionKey, profileId, epoch
274
274
  await appendEvent(ctx,events,signingKeyPath,'profile_completed',payload);
275
275
  return { status:outcome.passed ? 'passed' : 'failed', observation:payload, existing:false };
276
276
  }
277
+ const autonomousAuthority = await assertAutonomousArmed(policy,profile.root_id);
278
+ if (Number.isFinite(autonomousAuthority.remaining_ms) && autonomousAuthority.remaining_ms < 100) {
279
+ throw new Error('autonomous lease expires too soon to execute profile');
280
+ }
277
281
  await appendEvent(ctx,events,signingKeyPath,'profile_started',{ action_key:actionKey, profile_id:profileId,
278
- mutation_epoch:epoch, receipt_id:receiptId, request_sha256:requestSha256 });
282
+ mutation_epoch:epoch, receipt_id:receiptId, request_sha256:requestSha256,
283
+ authority_instance_nonce:autonomousAuthority.instance_nonce,
284
+ authority_expires_at_utc:autonomousAuthority.expires_at_utc });
285
+ const preExecutionCheck = () => recheckAutonomousAuthority(policy,autonomousAuthority,profile.root_id);
279
286
  let result;
280
287
  try {
281
288
  result = profile.kind === 'command'
282
289
  ? await codingRuntime.commandRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
283
290
  scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:profile.timeout_ms,
284
- receiptId, requestSha256 })
291
+ executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck, receiptId, requestSha256 })
285
292
  : await codingRuntime.benchmarkRun({ rootId:profile.root_id, commandId:profile.command_id, scriptPath:profile.script_path,
286
293
  scriptSha256:profile.script_sha256, args:profile.args, cwd:profile.cwd, timeoutMs:profile.timeout_ms,
294
+ executionDeadlineUtc:autonomousAuthority.expires_at_utc, preExecutionCheck,
287
295
  warmups:profile.warmups, iterations:profile.iterations, baselineMedianMs:profile.baseline_median_ms,
288
296
  maxRegressionPct:profile.max_regression_pct, receiptId, requestSha256 });
289
297
  } catch (error) {
@@ -527,7 +535,7 @@ function withLoopResult(goal,events,result) {
527
535
  return loop ? {...result,loop} : result;
528
536
  }
529
537
  function providerCircuitSnapshot(policy,events,observedAtUtc=new Date().toISOString()) {
530
- if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
538
+ if (!['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) return null;
531
539
  return deriveCircuit(events,providerCircuitId(policy.planner),policy.planner.circuit,observedAtUtc);
532
540
  }
533
541
  async function enterProviderCircuitWait({ctx,events,goal,policy,signingKeyPath,reason,circuit}) {
@@ -545,7 +553,7 @@ async function enterProviderCircuitWait({ctx,events,goal,policy,signingKeyPath,r
545
553
  });
546
554
  return {status:'paused',reason,circuit};
547
555
  }
548
- async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath}) {
556
+ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath,plannerProviderRuntime}) {
549
557
  const providerId=providerCircuitId(policy.planner);
550
558
  let circuit=providerCircuitSnapshot(policy,events);
551
559
  let disposition=providerCallDisposition(circuit);
@@ -566,7 +574,9 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
566
574
  });
567
575
  }
568
576
  try {
569
- const response=await requestProviderDecision(policy,pending.prompt);
577
+ const response=policy.planner.backend==='codex_app_server'
578
+ ? await plannerProviderRuntime.runPlanner({logicalId:`goal-${goal.goal_id}`,prompt:pending.prompt,timeoutMs:policy.planner.timeout_ms})
579
+ : await requestProviderDecision(policy,pending.prompt);
570
580
  await appendEvent(ctx,events,signingKeyPath,'provider_call_succeeded',{
571
581
  provider_id:providerId,request_id:pending.request_id,probe:disposition.probe===true,
572
582
  ...(response.response_id?{response_id:response.response_id}:{}),
@@ -589,15 +599,15 @@ async function requestProviderWithCircuit({ctx,events,goal,policy,pending,signin
589
599
  throw error;
590
600
  }
591
601
  }
592
- async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath, plannerResponse }) {
602
+ async function acceptPlannerDecision({ ctx, events, goal, state, policy, codingRuntime, capabilityManifest, desktopMemoryProvider,memoryProvider, signingKeyPath, plannerResponse, plannerProviderRuntime }) {
593
603
  let currentState = state;
594
604
  let pending = currentState.pending_request ?? await requestPlanner(ctx,goal,events,currentState,policy,codingRuntime,capabilityManifest,desktopMemoryProvider,memoryProvider,signingKeyPath);
595
605
  if (!pending) return null;
596
606
  let suppliedResponse = plannerResponse;
597
607
  while (pending) {
598
608
  let response;
599
- if (['openai_compatible','openai_responses'].includes(policy.planner.backend)) {
600
- const provider=await requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath});
609
+ if (['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) {
610
+ const provider=await requestProviderWithCircuit({ctx,events,goal,policy,pending,signingKeyPath,plannerProviderRuntime});
601
611
  if (provider.waiting) return {needs_planner:false,rejected:false,paused:true,provider_waiting:true};
602
612
  response=provider.response;
603
613
  } else {
@@ -1220,10 +1230,13 @@ async function runRequiredReleaseProfiles({ ctx, events, goal, state, policy, co
1220
1230
  return results;
1221
1231
  }
1222
1232
 
1223
- async function collectNativeHead(state, nativeDiffRuntime, codingRuntime) {
1233
+ async function collectNativeHead(state, nativeDiffRuntime, codingRuntime, { requireCurrentState = true } = {}) {
1224
1234
  const diffBindings = []; const head = new Map();
1225
1235
  for (const item of state.diffs) {
1226
- const checked = await nativeDiffRuntime.verify({ diffId:item.diff_id });
1236
+ const verifier = requireCurrentState
1237
+ ? nativeDiffRuntime.verify.bind(nativeDiffRuntime)
1238
+ : (nativeDiffRuntime.verifyEvidence ?? nativeDiffRuntime.verify).bind(nativeDiffRuntime);
1239
+ const checked = await verifier({ diffId:item.diff_id });
1227
1240
  if (!checked.ok || !Array.isArray(checked.final_states)) throw new Error(`release diff '${item.diff_id}' verification failed`);
1228
1241
  diffBindings.push({ diff_id:item.diff_id, receipt_sha256:checked.receipt_sha256,
1229
1242
  coding_receipts_verified:checked.coding_receipts_verified });
@@ -1233,10 +1246,12 @@ async function collectNativeHead(state, nativeDiffRuntime, codingRuntime) {
1233
1246
  }
1234
1247
  }
1235
1248
  const finalSourceStates = [...head.values()].sort((a,b) => `${a.root_id}/${a.path}`.localeCompare(`${b.root_id}/${b.path}`));
1236
- for (const expected of finalSourceStates) {
1237
- const current = await codingRuntime.fileState({ rootId:expected.root_id, relativePath:expected.path });
1238
- if (current.exists !== expected.exists || current.sha256 !== expected.sha256) {
1239
- throw new Error(`release native HEAD mismatch '${expected.path}'`);
1249
+ if (requireCurrentState) {
1250
+ for (const expected of finalSourceStates) {
1251
+ const current = await codingRuntime.fileState({ rootId:expected.root_id, relativePath:expected.path });
1252
+ if (current.exists !== expected.exists || current.sha256 !== expected.sha256) {
1253
+ throw new Error(`release native HEAD mismatch '${expected.path}'`);
1254
+ }
1240
1255
  }
1241
1256
  }
1242
1257
  return { diffBindings, finalSourceStates };
@@ -1299,7 +1314,7 @@ async function verifyReleaseReceipt({ ctx, goal, events, policy, verifyKeyPath,
1299
1314
  return { ok:false, reason:'release profile evidence mismatch' };
1300
1315
  }
1301
1316
  let nativeHead;
1302
- try { nativeHead = await collectNativeHead(preCompletionState,nativeDiffRuntime,codingRuntime); }
1317
+ try { nativeHead = await collectNativeHead(preCompletionState,nativeDiffRuntime,codingRuntime,{requireCurrentState:false}); }
1303
1318
  catch (error) { return { ok:false, reason:truncated(error) }; }
1304
1319
  if (canonicalJson(nativeHead.diffBindings) !== canonicalJson(body.native_diffs ?? [])) {
1305
1320
  return { ok:false, reason:'release native diff binding mismatch' };
@@ -1765,9 +1780,12 @@ function isAuthorityUnavailable(error) {
1765
1780
 
1766
1781
  export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRuntime, machineFsRuntime = null,
1767
1782
  observationRuntime = null, processRuntime = null, semanticRuntime = null, desktopRuntime = null,
1768
- desktopMemoryProvider = null,memoryProvider=null, signingKeyPath, verifyKeyPath }) {
1783
+ desktopMemoryProvider = null,memoryProvider=null, plannerProviderRuntime=null, signingKeyPath, verifyKeyPath }) {
1769
1784
  if (!policy || !codingRuntime || !nativeDiffRuntime) throw new Error('autonomous runtime requires policy/coding/native-diff runtimes');
1770
1785
  if (!signingKeyPath || !verifyKeyPath) throw new Error('autonomous runtime requires trust keys');
1786
+ if (policy.planner?.backend==='codex_app_server' && (!plannerProviderRuntime || typeof plannerProviderRuntime.runPlanner!=='function')) {
1787
+ throw new Error('Codex planner provider runtime is required by autonomous policy');
1788
+ }
1771
1789
  const capabilityManifest=configuredCapabilityManifest({machineFsRuntime,observationRuntime,processRuntime,semanticRuntime,desktopRuntime});
1772
1790
  const profileTimeoutCeiling=Math.max(120000,...Object.values(policy.profiles??{}).map(profile=>
1773
1791
  Number.isInteger(profile?.timeout_ms)&&profile.timeout_ms>0?profile.timeout_ms+120000:120000));
@@ -1784,7 +1802,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
1784
1802
  coding_policy_sha256:policy.coding_policy_sha256 };
1785
1803
  }
1786
1804
  async function providerCircuitStatus({goalId}) {
1787
- if (!['openai_compatible','openai_responses'].includes(policy.planner.backend)) return null;
1805
+ if (!['openai_compatible','openai_responses','codex_app_server'].includes(policy.planner.backend)) return null;
1788
1806
  const ctx=goalContext(policy,goalId);
1789
1807
  await loadGoal(ctx,policy,verifyKeyPath);
1790
1808
  const journal=await readEvents(ctx,verifyKeyPath);
@@ -2046,7 +2064,7 @@ export function createAutonomousRuntime({ policy, codingRuntime, nativeDiffRunti
2046
2064
  continue;
2047
2065
  }
2048
2066
  const accepted = await acceptPlannerDecision({ ctx,events:journal,goal,state,policy,codingRuntime,capabilityManifest,
2049
- desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse });
2067
+ desktopMemoryProvider,memoryProvider,signingKeyPath,plannerResponse:suppliedResponse,plannerProviderRuntime });
2050
2068
  suppliedResponse = null;
2051
2069
  if (accepted?.needs_planner) {
2052
2070
  state = deriveState(goal,journal);
@@ -7,6 +7,8 @@ import { createCodingRuntime, loadCodingPolicy } from './coding-plane.mjs';
7
7
  import { loadAutonomousPolicy } from './autonomous-policy.mjs';
8
8
  import { createNativeDiffRuntime } from './native-diff.mjs';
9
9
  import { createAutonomousRuntime } from './autonomous-runtime.mjs';
10
+ import { createCodexAppServerR44 } from './codex-app-server-r44.mjs';
11
+ import { DEADBYTE_VERSION } from './version.mjs';
10
12
  import { startLocalSupervisorHost } from './autonomous-local-supervisor.mjs';
11
13
 
12
14
  const packageRoot=path.resolve(path.dirname(fileURLToPath(import.meta.url)),'..');
@@ -30,7 +32,15 @@ const codingPolicy=await loadCodingPolicy(codingPolicyPath);
30
32
  const codingRuntime=createCodingRuntime({policy:codingPolicy,signingKeyPath,verifyKeyPath});
31
33
  const autonomousPolicy=await loadAutonomousPolicy(autonomousPolicyPath,codingPolicy);
32
34
  const nativeDiffRuntime=createNativeDiffRuntime({policy:autonomousPolicy,codingRuntime,signingKeyPath,verifyKeyPath});
33
- const autonomousRuntime=createAutonomousRuntime({policy:autonomousPolicy,codingRuntime,nativeDiffRuntime,signingKeyPath,verifyKeyPath});
35
+ const plannerProviderRuntime=autonomousPolicy.planner.backend==='codex_app_server'
36
+ ? await createCodexAppServerR44({
37
+ stateDir:path.join(autonomousPolicy.evidence_dir,'provider-r44','codex-app-server'),
38
+ model:autonomousPolicy.planner.model,cwd:codingPolicy.roots[autonomousPolicy.planner.root_id].real_path,
39
+ clientVersion:DEADBYTE_VERSION,executable:autonomousPolicy.planner.executable,
40
+ executableSha256:autonomousPolicy.planner.executable_sha256,args:autonomousPolicy.planner.args
41
+ })
42
+ : null;
43
+ const autonomousRuntime=createAutonomousRuntime({policy:autonomousPolicy,codingRuntime,nativeDiffRuntime,plannerProviderRuntime,signingKeyPath,verifyKeyPath});
34
44
  const markerPath=path.resolve(process.env.DEADBYTE_SUPERVISOR_MARKER||path.join(autonomousPolicy.evidence_dir,'supervisor-owner.json'));
35
45
  const host=await startLocalSupervisorHost({runtime:autonomousRuntime,policy:autonomousPolicy,markerPath,
36
46
  idleDelayMs:750,maxCycles:32,continuous:onceMode!=='1'});
@@ -43,7 +53,7 @@ let stopping=false;
43
53
  async function stopAndExit(code=0){
44
54
  if(stopping) return;
45
55
  stopping=true;
46
- try { await host.stop(); }
56
+ try { await host.stop(); await plannerProviderRuntime?.close(); }
47
57
  catch(error){ process.stderr.write(`DEADBYTE supervisor host stop failed: ${String(error)}\n`); code=1; }
48
58
  process.exitCode=code;
49
59
  }
@@ -3,7 +3,7 @@ import { createHash } from 'node:crypto';
3
3
  export const CAPABILITY_LEDGER_SCHEMA='deadbyte.capability-ledger.v1';
4
4
  const AUTHORITIES=new Set(['none','process','coding','autonomous','desktop','host']);
5
5
  const PROFILE_ENV='DEADBYTE_CAPABILITY_PROFILE';
6
- const COMPACT_TOOL_LIMIT=42;
6
+ const COMPACT_TOOL_LIMIT=43;
7
7
 
8
8
  function sha256(text){return createHash('sha256').update(text,'utf8').digest('hex');}
9
9
  function canonicalJson(value){
@@ -81,6 +81,7 @@ const gateway=(id,full_tool,compact_tool,compact_op,runtime_flag,authority,{muta
81
81
 
82
82
  export const R36_CAPABILITY_ENTRIES=Object.freeze([
83
83
  direct('evidence.verify','evidence_verify',null,'none',{receipt_class:'verification'}),
84
+ direct('skill.catalog','skill_catalog',null,'none',{receipt_class:'skill'}),
84
85
  gateway('machine.list','machine_list','machine_observe','machine_list','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
85
86
  gateway('machine.status','machine_status','machine_observe','machine_status','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
86
87
  gateway('machine.ping','machine_ping','machine_observe','machine_ping','DEADBYTE_MACHINE_RUNTIME','none',{receipt_class:'machine'}),
@@ -134,6 +135,7 @@ export const R36_CAPABILITY_ENTRIES=Object.freeze([
134
135
  gateway('observation.search_cancel','machine_search_cancel','machine_observe','search_cancel','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
135
136
  gateway('observation.process_list','machine_process_list','machine_observe','process_list','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
136
137
  gateway('observation.system_status','machine_system_status','machine_observe','system_status','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
138
+ gateway('observation.hardware_query','machine_hardware_query','machine_observe','hardware_query','DEADBYTE_OBSERVATION_RUNTIME','none',{receipt_class:'observation'}),
137
139
 
138
140
  gateway('desktop.status','desktop_status','desktop_control','status','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
139
141
  gateway('desktop.observe','desktop_observe','desktop_control','observe','DEADBYTE_DESKTOP_RUNTIME','none',{receipt_class:'desktop'}),
@@ -0,0 +1,154 @@
1
+ import path from 'node:path';
2
+ import { createAgentBackendR44 } from './agent-backend-r44.mjs';
3
+
4
+ const ID=/^[A-Za-z0-9._-]{1,64}$/;
5
+ function insist(ok,message){if(!ok)throw new Error(message);}
6
+ function text(value,label,max=262144){insist(typeof value==='string'&&value.length>=1&&value.length<=max,`${label} invalid`);return value;}
7
+ function threadIdFromResponse(value){
8
+ const id=value?.thread?.id;insist(typeof id==='string'&&id.length>=1&&id.length<=512,'Codex thread response missing thread.id');return id;
9
+ }
10
+ function turnIdFromResponse(value){
11
+ const id=value?.turn?.id;insist(typeof id==='string'&&id.length>=1&&id.length<=512,'Codex turn response missing turn.id');return id;
12
+ }
13
+ function safeThreadParams({model,cwd}){
14
+ return {model,cwd,approvalPolicy:'never',approvalsReviewer:'user',sandbox:'read-only',ephemeral:false};
15
+ }
16
+ function approvalHandler({method}){
17
+ if(method==='item/commandExecution/requestApproval'||method==='item/fileChange/requestApproval')return {decision:'decline'};
18
+ if(method==='item/permissions/requestApproval')return {permissions:{},scope:'turn'};
19
+ if(method==='item/tool/requestUserInput')return {answers:{}};
20
+ const error=new Error(`Codex server request denied: ${method}`);error.code=-32001;throw error;
21
+ }
22
+
23
+ export async function createCodexAppServerR44({
24
+ stateDir,model,cwd,clientVersion='0.15.0',transportFactory=null,
25
+ executable=null,executableSha256=null,args=['app-server'],env=null
26
+ }={}){
27
+ insist(typeof stateDir==='string'&&path.isAbsolute(stateDir),'Codex stateDir must be absolute');
28
+ text(model,'Codex model',128);insist(typeof cwd==='string'&&path.isAbsolute(cwd),'Codex cwd must be absolute');
29
+ text(clientVersion,'Codex client version',64);
30
+ const turns=new Map();
31
+ const attachedThreads=new Set();
32
+ let initialized=false;
33
+
34
+ function turnRecord(turnId,threadId=null){
35
+ let rec=turns.get(turnId);
36
+ if(!rec){rec={turn_id:turnId,thread_id:threadId,final_answer:null,unknown_answer:null,status:null,error:null,waiters:[]};turns.set(turnId,rec);}
37
+ else if(threadId&&rec.thread_id===null)rec.thread_id=threadId;
38
+ return rec;
39
+ }
40
+ function settle(rec){
41
+ if(!rec.status||!['completed','failed','interrupted'].includes(rec.status))return;
42
+ const waiters=rec.waiters.splice(0);
43
+ if(rec.status==='completed'){
44
+ const raw=rec.final_answer??rec.unknown_answer;
45
+ for(const waiter of waiters){
46
+ clearTimeout(waiter.timer);
47
+ if(typeof raw==='string'&&raw.length>0)waiter.resolve({raw_text:raw});
48
+ else waiter.reject(new Error('Codex turn completed without agent final response'));
49
+ }
50
+ }else{
51
+ for(const waiter of waiters){clearTimeout(waiter.timer);waiter.reject(new Error(rec.error??`Codex turn ${rec.status}`));}
52
+ }
53
+ }
54
+ async function notificationHandler({method,params}){
55
+ if(method==='item/completed'){
56
+ const tid=params?.turnId,threadId=params?.threadId,item=params?.item;
57
+ if(typeof tid!=='string'||!item||typeof item!=='object')return;
58
+ const rec=turnRecord(tid,typeof threadId==='string'?threadId:null);
59
+ if(item.type==='agentMessage'||item.type==='agent_message'){
60
+ if(typeof item.text!=='string')return;
61
+ if(item.phase==='final_answer'||item.phase==='finalAnswer')rec.final_answer=item.text;
62
+ else if(item.phase===null||item.phase===undefined)rec.unknown_answer=item.text;
63
+ }
64
+ return;
65
+ }
66
+ if(method==='turn/completed'){
67
+ const turn=params?.turn;const tid=turn?.id;
68
+ if(typeof tid!=='string')return;
69
+ const rec=turnRecord(tid,typeof params?.threadId==='string'?params.threadId:null);
70
+ rec.status=String(turn.status??'completed');
71
+ if(rec.status==='failed')rec.error=turn.error?.message??'Codex turn failed';
72
+ settle(rec);
73
+ }
74
+ }
75
+
76
+ const backend=await createAgentBackendR44({
77
+ backendId:'codex-app-server',stateDir:path.join(stateDir,'backend'),transportFactory,
78
+ executable,executableSha256,args,cwd,env,wireMode:'codex-app-server',
79
+ serverRequestHandler:approvalHandler,notificationHandler
80
+ });
81
+
82
+ async function start(){
83
+ if(initialized)return {status:'ok',initialized:true};
84
+ await backend.start();
85
+ await backend.request({method:'initialize',params:{
86
+ clientInfo:{name:'deadbyte-mcp',version:clientVersion},
87
+ capabilities:{experimentalApi:false,requestAttestation:false,optOutNotificationMethods:null}
88
+ },timeoutMs:30000});
89
+ await backend.notify({method:'initialized',params:{}});
90
+ initialized=true;
91
+ return {status:'ok',initialized:true,backend:'codex_app_server'};
92
+ }
93
+ async function ensureStarted(){if(!initialized)await start();}
94
+ async function ensureThread({logicalId}={}){
95
+ await ensureStarted();insist(typeof logicalId==='string'&&ID.test(logicalId),'Codex logical thread id invalid');
96
+ const status=await backend.status();const existing=status.threads[logicalId];
97
+ if(existing){
98
+ if(!attachedThreads.has(existing)){
99
+ const response=await backend.request({method:'thread/resume',params:{threadId:existing,...safeThreadParams({model,cwd}),excludeTurns:true},timeoutMs:60000});
100
+ const resumed=threadIdFromResponse(response);insist(resumed===existing,'Codex resumed thread identity mismatch');attachedThreads.add(existing);
101
+ }
102
+ return {status:'ok',logical_id:logicalId,thread_id:existing,resumed:true};
103
+ }
104
+ const response=await backend.request({method:'thread/start',params:safeThreadParams({model,cwd}),timeoutMs:60000});
105
+ const created=threadIdFromResponse(response);
106
+ await backend.bindThread({logicalId,threadId:created});attachedThreads.add(created);
107
+ return {status:'ok',logical_id:logicalId,thread_id:created,resumed:false};
108
+ }
109
+ function waitTurn(turnId,threadId,timeoutMs){
110
+ insist(Number.isInteger(timeoutMs)&&timeoutMs>=100&&timeoutMs<=900000,'Codex turn timeout invalid');
111
+ const rec=turnRecord(turnId,threadId);
112
+ if(rec.status&&['completed','failed','interrupted'].includes(rec.status)){
113
+ return new Promise((resolve,reject)=>{
114
+ const timer=setTimeout(()=>{},1);rec.waiters.push({resolve,reject,timer});settle(rec);
115
+ });
116
+ }
117
+ return new Promise((resolve,reject)=>{
118
+ const timer=setTimeout(()=>{
119
+ const index=rec.waiters.findIndex(x=>x.timer===timer);if(index>=0)rec.waiters.splice(index,1);
120
+ reject(new Error('Codex turn completion timeout'));
121
+ },timeoutMs);
122
+ rec.waiters.push({resolve,reject,timer});
123
+ });
124
+ }
125
+ async function runPlanner({logicalId='planner',prompt,timeoutMs=120000}={}){
126
+ text(prompt,'Codex planner prompt',1024*1024);
127
+ const thread=await ensureThread({logicalId});
128
+ const started=await backend.request({method:'turn/start',params:{
129
+ threadId:thread.thread_id,input:[{type:'text',text:prompt}],approvalPolicy:'never'
130
+ },timeoutMs:Math.min(timeoutMs,60000)});
131
+ const turnId=turnIdFromResponse(started);turnRecord(turnId,thread.thread_id);
132
+ const completed=await waitTurn(turnId,thread.thread_id,timeoutMs);
133
+ return {backend:'codex_app_server',model,raw_text:completed.raw_text,response_id:turnId,thread_id:thread.thread_id};
134
+ }
135
+ async function steer({threadId,turnId,text:message,timeoutMs=30000}={}){
136
+ await ensureStarted();text(threadId,'Codex threadId',512);text(turnId,'Codex turnId',512);text(message,'Codex steer text',262144);
137
+ return backend.request({method:'turn/steer',params:{threadId,expectedTurnId:turnId,input:[{type:'text',text:message}]},timeoutMs});
138
+ }
139
+ async function interrupt({threadId,turnId,timeoutMs=30000}={}){
140
+ await ensureStarted();text(threadId,'Codex threadId',512);text(turnId,'Codex turnId',512);
141
+ return backend.request({method:'turn/interrupt',params:{threadId,turnId},timeoutMs});
142
+ }
143
+ async function modelList({includeHidden=false}={}){
144
+ await ensureStarted();return backend.request({method:'model/list',params:{includeHidden:includeHidden===true},timeoutMs:30000});
145
+ }
146
+ async function status(){const value=await backend.status();return {...value,initialized,attached_threads:[...attachedThreads].sort()};}
147
+ async function close(){
148
+ for(const rec of turns.values()){
149
+ for(const waiter of rec.waiters.splice(0)){clearTimeout(waiter.timer);waiter.reject(new Error('Codex adapter closed before turn completion'));}
150
+ }
151
+ initialized=false;attachedThreads.clear();return backend.close();
152
+ }
153
+ return Object.freeze({start,ensureThread,runPlanner,steer,interrupt,modelList,status,close,backend});
154
+ }