deadbyte-mcp 0.9.0 → 0.10.0

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 (121) hide show
  1. package/MANIFEST.SHA256 +119 -91
  2. package/README.txt +16 -11
  3. package/bench/fixtures/corpus.json +32 -13
  4. package/bench/fixtures/r36/case-map.json +8 -0
  5. package/bin/WORKER-REGISTRY.txt +3 -3
  6. package/bin/appcontainer-stage.exe +0 -0
  7. package/bin/appcontainer-stage.obj +0 -0
  8. package/bin/bootstrap-advapi32.exe +0 -0
  9. package/bin/bootstrap-advapi32.obj +0 -0
  10. package/bin/bootstrap-exitcode.exe +0 -0
  11. package/bin/bootstrap-exitcode.obj +0 -0
  12. package/bin/bootstrap-kernel32.exe +0 -0
  13. package/bin/bootstrap-kernel32.obj +0 -0
  14. package/bin/child-control-probe.exe +0 -0
  15. package/bin/child-control-probe.obj +0 -0
  16. package/bin/child-control-stage.exe +0 -0
  17. package/bin/child-control-stage.obj +0 -0
  18. package/bin/contained-reverse-worker.exe +0 -0
  19. package/bin/contained-reverse-worker.obj +0 -0
  20. package/bin/contained-transform-worker.exe +0 -0
  21. package/bin/contained-transform-worker.obj +0 -0
  22. package/bin/containment-probe.exe +0 -0
  23. package/bin/containment-probe.obj +0 -0
  24. package/bin/deadbyte-contain.exe +0 -0
  25. package/bin/deadbyte-contain.obj +0 -0
  26. package/bin/deadbyte-exec.exe +0 -0
  27. package/bin/deadbyte-exec.obj +0 -0
  28. package/bin/deadbyte-process-host.exe +0 -0
  29. package/bin/deadbyte-process-host.obj +0 -0
  30. package/bin/deadbyte-tunnel-host.exe +0 -0
  31. package/bin/deadbyte-tunnel-host.obj +0 -0
  32. package/controller/README.TXT +8 -6
  33. package/controller/deadbyte-controller.ps1 +48 -2
  34. package/controller/deadbyte-process-policy.json +5 -5
  35. package/docs/ARCHITECTURE.md +1 -1
  36. package/docs/R36-CAPABILITY-EVIDENCE.md +43 -0
  37. package/docs/superpowers/plans/2026-09-18-r36-zero-loss-autonomy.md +739 -0
  38. package/docs/superpowers/specs/2026-09-18-r36-zero-loss-autonomy-design.md +640 -0
  39. package/package.json +1 -1
  40. package/proof/CONTAINMENT-BUILD.txt +6 -6
  41. package/scripts/deferred-slot-operation.mjs +53 -15
  42. package/scripts/final-closure-verify.mjs +88 -39
  43. package/scripts/final-closure.mjs +63 -56
  44. package/scripts/gate-windows.ps1 +3 -3
  45. package/scripts/release-parity-tests.ps1 +9 -0
  46. package/scripts/release-parity.mjs +149 -139
  47. package/scripts/windows-gate-evidence.mjs +5 -5
  48. package/src/autonomous-context-engine.mjs +2 -1
  49. package/src/autonomous-mcp-tools.mjs +5 -1
  50. package/src/autonomous-output-contracts.mjs +4 -4
  51. package/src/autonomous-planner-contracts.mjs +36 -1
  52. package/src/autonomous-planner.mjs +25 -3
  53. package/src/autonomous-runtime.mjs +191 -21
  54. package/src/capability-benchmark-runner.mjs +86 -1
  55. package/src/capability-benchmark.mjs +45 -0
  56. package/src/capability-ledger.mjs +158 -0
  57. package/src/coding-mcp-tools.mjs +31 -17
  58. package/src/coding-output-contracts.mjs +48 -10
  59. package/src/coding-plane.mjs +45 -9
  60. package/src/coding-search.mjs +130 -47
  61. package/src/compact-gateway-mcp-tools.mjs +128 -0
  62. package/src/compact-gateway-output-contracts.mjs +16 -0
  63. package/src/deadbyte-cli.mjs +51 -28
  64. package/src/machine-fs-smoke-client.mjs +1 -1
  65. package/src/machine-fs.mjs +51 -8
  66. package/src/mcp-server.mjs +32 -9
  67. package/src/native-diff-v2.mjs +337 -0
  68. package/src/native-diff.mjs +50 -2
  69. package/src/observation-smoke-client.mjs +1 -1
  70. package/src/operator-surface.mjs +7 -1
  71. package/src/process-runtime.mjs +98 -11
  72. package/src/process-smoke-client.mjs +11 -3
  73. package/src/r36-compact-disarmed-probe.mjs +50 -0
  74. package/src/r36-full-surface-probe.mjs +56 -0
  75. package/src/remote-live-log.mjs +76 -0
  76. package/src/remote-mcp-autonomous-smoke-client.mjs +7 -3
  77. package/src/remote-mcp-coding-smoke-client.mjs +1 -1
  78. package/src/remote-mcp-r36-parity-client.mjs +175 -0
  79. package/src/remote-mcp-smoke-client.mjs +112 -56
  80. package/src/runtime-update.mjs +51 -1
  81. package/src/search-cursor.mjs +45 -0
  82. package/src/semantic-code.mjs +72 -5
  83. package/src/semantic-lsp-backend.mjs +39 -3
  84. package/src/version.mjs +1 -1
  85. package/test/autonomous-capability-r36.test.mjs +151 -0
  86. package/test/autonomous-runtime.test.mjs +2 -2
  87. package/test/capability-benchmark-r36.test.mjs +107 -0
  88. package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
  89. package/test/capability-claims-r36.test.mjs +23 -0
  90. package/test/capability-ledger-r36.test.mjs +102 -0
  91. package/test/coding-catalog-consistency.test.mjs +2 -2
  92. package/test/coding-plane.test.mjs +2 -2
  93. package/test/coding-runtime.test.mjs +16 -0
  94. package/test/coding-search-r36.test.mjs +90 -0
  95. package/test/compact-catalog-r36.test.mjs +37 -0
  96. package/test/compact-gateway-r36.test.mjs +66 -0
  97. package/test/contained.test.mjs +1 -1
  98. package/test/core.test.mjs +1 -1
  99. package/test/deferred-slot-operation.test.mjs +9 -0
  100. package/test/fixtures/lsp-framed-server.mjs +2 -0
  101. package/test/helpers/autonomous-r34-fixture.mjs +5 -3
  102. package/test/multi-file-read.test.mjs +3 -0
  103. package/test/native-diff-topology-r36.test.mjs +105 -0
  104. package/test/package-boundary.test.mjs +6 -0
  105. package/test/process-longrun-r36.test.mjs +82 -0
  106. package/test/process-release-gate.test.mjs +9 -0
  107. package/test/production-docs.test.mjs +3 -3
  108. package/test/prompts-resources.test.mjs +7 -1
  109. package/test/r33-closeout-regression.test.mjs +4 -3
  110. package/test/r33-finalization.test.mjs +14 -9
  111. package/test/r36-finalization.test.mjs +104 -0
  112. package/test/r36-release-identity.test.mjs +52 -0
  113. package/test/release-version.test.mjs +18 -15
  114. package/test/remote-live-log-r36.test.mjs +37 -0
  115. package/test/remote-live-log-recovery-r36.test.mjs +41 -0
  116. package/test/remote-r24-catalog.test.mjs +13 -0
  117. package/test/remote-session-cli.test.mjs +40 -30
  118. package/test/runtime-self-update.test.mjs +58 -1
  119. package/test/semantic-lsp-backend.test.mjs +9 -0
  120. package/test/semantic-r36-rename.test.mjs +82 -0
  121. package/deadbyte-mcp-0.8.9.tgz +0 -0
@@ -30,7 +30,7 @@ const agentTools = [
30
30
  const codingTools = [
31
31
  'coding_benchmark_run', 'coding_command_run', 'coding_file_read', 'coding_file_write', 'coding_files_read',
32
32
  'coding_receipt_verify', 'coding_search', 'coding_session_status', 'coding_stat',
33
- 'coding_symbol_definition', 'coding_symbol_outline', 'coding_symbol_references', 'coding_symbol_replace',
33
+ 'coding_symbol_definition', 'coding_symbol_diagnostics', 'coding_symbol_implementations', 'coding_symbol_outline', 'coding_symbol_references', 'coding_symbol_rename_preview', 'coding_symbol_replace',
34
34
  'coding_task_approve', 'coding_task_cancel', 'coding_task_events', 'coding_task_run',
35
35
  'coding_task_status', 'coding_task_submit', 'coding_task_verify', 'coding_text_replace', 'coding_tree'
36
36
  ];
@@ -39,6 +39,18 @@ const autonomousTools = [
39
39
  'autonomous_goal_status', 'autonomous_goal_submit', 'autonomous_goal_verify', 'autonomous_release_gate',
40
40
  'autonomous_session_status', 'native_diff_apply', 'native_diff_preview', 'native_diff_verify'
41
41
  ];
42
+ const r36CompactTools = [
43
+ 'autonomous_goal_approve','autonomous_goal_cancel','autonomous_goal_events','autonomous_goal_run','autonomous_goal_status','autonomous_goal_submit','autonomous_goal_verify','autonomous_release_gate','autonomous_session_status',
44
+ 'capability_manifest',
45
+ 'coding_benchmark_run','coding_command_run','coding_file_read','coding_file_write','coding_inspect','coding_receipt_verify','coding_session_status','coding_symbol_replace',
46
+ 'coding_task_approve','coding_task_cancel','coding_task_events','coding_task_run','coding_task_status','coding_task_submit','coding_task_verify','coding_text_replace','coding_tree',
47
+ 'evidence_verify',
48
+ 'host_exec','host_file_read','host_file_write',
49
+ 'machine_fs','machine_list','machine_observe','machine_ping','machine_revoke','machine_status',
50
+ 'native_diff_apply','native_diff_preview','native_diff_verify',
51
+ 'process_session'
52
+ ].sort();
53
+ if (r36CompactTools.length !== 41) throw new Error(`R36 compact catalog constant drift: ${r36CompactTools.length}`);
42
54
  const allowedCatalogs = [];
43
55
  for (const machine of [false, true]) for (const host of [false, true]) for (const agent of [false, true]) {
44
56
  for (const processPlane of [false, true]) for (const machineFs of [false, true]) for (const observation of [false, true]) for (const codingMode of ['none', 'coding', 'autonomous']) {
@@ -68,13 +80,21 @@ function structured(result, label) {
68
80
  if (!result.structuredContent || typeof result.structuredContent !== 'object') throw new Error(`${label} returned no structured object`);
69
81
  return result.structuredContent;
70
82
  }
83
+ function gateway(result, label) {
84
+ const value = structured(result, label);
85
+ if (value.status !== 'ok' || !value.result || typeof value.result !== 'object') {
86
+ throw new Error(`${label} gateway status=${String(value.status)} error=${String(value.error ?? '')}`);
87
+ }
88
+ return value.result;
89
+ }
71
90
 
72
91
  try {
73
92
  await client.connect(transport);
74
93
  if (client.getProtocolEra() !== 'modern') throw new Error(`expected modern MCP era, got ${String(client.getProtocolEra())}`);
75
94
  const listed = await client.listTools();
76
95
  const names = listed.tools.map(t => t.name).sort();
77
- const catalogOk = allowedCatalogs.some(expected => JSON.stringify(names) === JSON.stringify(expected));
96
+ const compactProfile = JSON.stringify(names) === JSON.stringify(r36CompactTools);
97
+ const catalogOk = compactProfile || allowedCatalogs.some(expected => JSON.stringify(names) === JSON.stringify(expected));
78
98
  if (!catalogOk) throw new Error(`tool catalog mismatch: ${JSON.stringify(names)}`);
79
99
  for (const tool of listed.tools) {
80
100
  if (tool.outputSchema?.type !== 'object' || tool.outputSchema?.additionalProperties !== false || !tool.outputSchema?.properties) {
@@ -90,72 +110,108 @@ try {
90
110
  const codingRuntime = codingTools.every(name => names.includes(name));
91
111
  const autonomousRuntime = autonomousTools.every(name => names.includes(name));
92
112
 
93
- const opened = structured(await client.callTool({ name: 'workspace_open', arguments: { workspace_id: 'demo' } }), 'workspace_open');
94
- if (opened.status !== 'ok') throw new Error(`workspace_open status=${String(opened.status)}`);
95
-
96
- const proofOutput = `remote-proof.${randomBytes(8).toString('hex')}.txt`;
97
- const proof = structured(await client.callTool({
98
- name: 'proof_execute', arguments: { workspace_id: 'demo', input: 'input.txt', output: proofOutput }
99
- }), 'proof_execute');
100
- if (proof.status !== 'passed' || !/^[0-9a-f]{64}$/.test(proof.request_sha256)) throw new Error('remote proof request identity missing');
101
- const proofVerify = structured(await client.callTool({
102
- name: 'evidence_verify', arguments: { workspace_id: 'demo', receipt_path: proof.receipt_path }
103
- }), 'evidence_verify proof');
104
- if (proofVerify.ok !== true || proofVerify.signature_valid !== true || proofVerify.receipt_schema !== 'deadbyte.receipt.v2' ||
105
- proofVerify.request_sha256 !== proof.request_sha256) throw new Error(`remote proof verify failed: ${JSON.stringify(proofVerify)}`);
106
-
113
+ let compact = null;
114
+ let proofOutput = null;
115
+ let proof = null;
107
116
  let contained = null;
108
- if (mode === 'full') {
109
- const output = `remote-contained.${randomBytes(8).toString('hex')}.txt`;
110
- const exec = structured(await client.callTool({
111
- name: 'contained_transform',
112
- arguments: { workspace_id: 'demo', input: 'input.txt', output, operation: 'uppercase_ascii' }
113
- }), 'contained_transform');
114
- if (exec.status !== 'passed' || exec.output_sha256 !== '3e740f6fcf2c6659bc5f99e0706b09f3c127407bbabe74d05285d2e3276946c2' ||
115
- !/^[0-9a-f]{64}$/.test(exec.request_sha256)) throw new Error(`remote contained result mismatch: ${JSON.stringify(exec)}`);
116
- const verify = structured(await client.callTool({
117
- name: 'evidence_verify', arguments: { workspace_id: 'demo', receipt_path: exec.receipt_path }
118
- }), 'evidence_verify contained');
119
- if (verify.ok !== true || verify.signature_valid !== true || verify.containment_verified !== true ||
120
- verify.active_network_denial_verified !== true || verify.receipt_schema !== 'deadbyte.receipt.v2' ||
121
- verify.request_sha256 !== exec.request_sha256) throw new Error(`remote contained verification failed: ${JSON.stringify(verify)}`);
122
- contained = { output, receipt_sha256: exec.receipt_sha256, request_sha256: exec.request_sha256, output_sha256: exec.output_sha256 };
123
- }
124
117
  let agent = null;
125
- if (mode === 'full' && agentRuntime) {
126
- const submissionId = `remote-gate-${randomBytes(8).toString('hex')}`;
127
- const submitted = structured(await client.callTool({
128
- name: 'agent_task_submit', arguments: {
129
- workspace_id: 'demo', submission_id: submissionId, title: 'remote R22 gate',
130
- steps: [
131
- { step_id: 'proof', kind: 'proof_execute', input: { kind: 'workspace', path: 'input.txt' }, retry_limit: 0 },
132
- { step_id: 'contained', kind: 'contained_transform', operation: 'uppercase_ascii', input: { kind: 'step_output', step_id: 'proof' }, retry_limit: 0 }
133
- ]
118
+ if (compactProfile) {
119
+ const manifest = gateway(await client.callTool({ name: 'capability_manifest', arguments: {} }), 'capability_manifest');
120
+ if (manifest.schema !== 'deadbyte.capability-manifest.v1' || manifest.profile !== 'compact' ||
121
+ !Array.isArray(manifest.capabilities) || !/^[0-9a-f]{64}$/.test(String(manifest.ledger_sha256 ?? ''))) {
122
+ throw new Error('R36 compact capability manifest malformed');
123
+ }
124
+ const required = manifest.capabilities.filter(item => item?.production === true && item?.host_only !== true);
125
+ for (const item of required) {
126
+ if (typeof item.compact_tool !== 'string' || !names.includes(item.compact_tool)) {
127
+ throw new Error(`R36 compact capability route missing: ${String(item.id)}`);
128
+ }
129
+ }
130
+ const machine = gateway(await client.callTool({ name: 'machine_observe', arguments: { op: 'machine_status' } }), 'machine_status');
131
+ const nonce = `remote-smoke-${randomBytes(16).toString('hex')}`;
132
+ const ping = gateway(await client.callTool({ name: 'machine_observe', arguments: { op: 'machine_ping', nonce } }), 'machine_ping');
133
+ if (ping.nonce !== nonce || ping.machine_id !== machine.machine_id ||
134
+ ping.release_id !== machine.release_id || ping.release_manifest_sha256 !== machine.release_manifest_sha256) {
135
+ throw new Error('R36 compact machine ping binding mismatch');
136
+ }
137
+ compact = {
138
+ profile: 'compact',
139
+ ledger_sha256: manifest.ledger_sha256,
140
+ capability_count: manifest.capabilities.length,
141
+ production_non_host_capabilities: required.length,
142
+ capability_closure: true,
143
+ machine_id: machine.machine_id,
144
+ release_id: machine.release_id,
145
+ release_manifest_sha256: machine.release_manifest_sha256,
146
+ ping_signature_valid: ping.signature_valid === true
147
+ };
148
+ } else {
149
+ const opened = structured(await client.callTool({ name: 'workspace_open', arguments: { workspace_id: 'demo' } }), 'workspace_open');
150
+ if (opened.status !== 'ok') throw new Error(`workspace_open status=${String(opened.status)}`);
151
+
152
+ proofOutput = `remote-proof.${randomBytes(8).toString('hex')}.txt`;
153
+ proof = structured(await client.callTool({
154
+ name: 'proof_execute', arguments: { workspace_id: 'demo', input: 'input.txt', output: proofOutput }
155
+ }), 'proof_execute');
156
+ if (proof.status !== 'passed' || !/^[0-9a-f]{64}$/.test(proof.request_sha256)) throw new Error('remote proof request identity missing');
157
+ const proofVerify = structured(await client.callTool({
158
+ name: 'evidence_verify', arguments: { workspace_id: 'demo', receipt_path: proof.receipt_path }
159
+ }), 'evidence_verify proof');
160
+ if (proofVerify.ok !== true || proofVerify.signature_valid !== true || proofVerify.receipt_schema !== 'deadbyte.receipt.v2' ||
161
+ proofVerify.request_sha256 !== proof.request_sha256) throw new Error(`remote proof verify failed: ${JSON.stringify(proofVerify)}`);
162
+
163
+ if (mode === 'full') {
164
+ const output = `remote-contained.${randomBytes(8).toString('hex')}.txt`;
165
+ const exec = structured(await client.callTool({
166
+ name: 'contained_transform',
167
+ arguments: { workspace_id: 'demo', input: 'input.txt', output, operation: 'uppercase_ascii' }
168
+ }), 'contained_transform');
169
+ if (exec.status !== 'passed' || exec.output_sha256 !== '3e740f6fcf2c6659bc5f99e0706b09f3c127407bbabe74d05285d2e3276946c2' ||
170
+ !/^[0-9a-f]{64}$/.test(exec.request_sha256)) throw new Error(`remote contained result mismatch: ${JSON.stringify(exec)}`);
171
+ const verify = structured(await client.callTool({
172
+ name: 'evidence_verify', arguments: { workspace_id: 'demo', receipt_path: exec.receipt_path }
173
+ }), 'evidence_verify contained');
174
+ if (verify.ok !== true || verify.signature_valid !== true || verify.containment_verified !== true ||
175
+ verify.active_network_denial_verified !== true || verify.receipt_schema !== 'deadbyte.receipt.v2' ||
176
+ verify.request_sha256 !== exec.request_sha256) throw new Error(`remote contained verification failed: ${JSON.stringify(verify)}`);
177
+ contained = { output, receipt_sha256: exec.receipt_sha256, request_sha256: exec.request_sha256, output_sha256: exec.output_sha256 };
178
+ }
179
+ if (mode === 'full' && agentRuntime) {
180
+ const submissionId = `remote-gate-${randomBytes(8).toString('hex')}`;
181
+ const submitted = structured(await client.callTool({
182
+ name: 'agent_task_submit', arguments: {
183
+ workspace_id: 'demo', submission_id: submissionId, title: 'remote R22 gate',
184
+ steps: [
185
+ { step_id: 'proof', kind: 'proof_execute', input: { kind: 'workspace', path: 'input.txt' }, retry_limit: 0 },
186
+ { step_id: 'contained', kind: 'contained_transform', operation: 'uppercase_ascii', input: { kind: 'step_output', step_id: 'proof' }, retry_limit: 0 }
187
+ ]
188
+ }
189
+ }), 'agent_task_submit');
190
+ const run = structured(await client.callTool({
191
+ name: 'agent_task_run', arguments: { workspace_id: 'demo', task_id: submitted.task_id, max_steps: 8 }
192
+ }), 'agent_task_run');
193
+ if (run.state !== 'succeeded' || run.completed_steps !== 2) throw new Error(`agent task run failed: ${JSON.stringify(run)}`);
194
+ const verified = structured(await client.callTool({
195
+ name: 'agent_task_verify', arguments: { workspace_id: 'demo', task_id: submitted.task_id }
196
+ }), 'agent_task_verify');
197
+ if (verified.ok !== true || verified.signature_valid !== true || verified.step_receipts_verified !== 2) {
198
+ throw new Error(`agent task verify failed: ${JSON.stringify(verified)}`);
134
199
  }
135
- }), 'agent_task_submit');
136
- const run = structured(await client.callTool({
137
- name: 'agent_task_run', arguments: { workspace_id: 'demo', task_id: submitted.task_id, max_steps: 8 }
138
- }), 'agent_task_run');
139
- if (run.state !== 'succeeded' || run.completed_steps !== 2) throw new Error(`agent task run failed: ${JSON.stringify(run)}`);
140
- const verified = structured(await client.callTool({
141
- name: 'agent_task_verify', arguments: { workspace_id: 'demo', task_id: submitted.task_id }
142
- }), 'agent_task_verify');
143
- if (verified.ok !== true || verified.signature_valid !== true || verified.step_receipts_verified !== 2) {
144
- throw new Error(`agent task verify failed: ${JSON.stringify(verified)}`);
200
+ agent = { task_id: submitted.task_id, plan_sha256: submitted.plan_sha256,
201
+ task_receipt_sha256: verified.task_receipt_sha256, step_receipts_verified: verified.step_receipts_verified };
145
202
  }
146
- agent = { task_id: submitted.task_id, plan_sha256: submitted.plan_sha256,
147
- task_receipt_sha256: verified.task_receipt_sha256, step_receipts_verified: verified.step_receipts_verified };
148
203
  }
149
204
  console.log(JSON.stringify({
150
- status: 'passed', mode,
205
+ status: 'passed', mode, profile: compactProfile ? 'compact' : 'legacy-full',
151
206
  protocol_revision: '2026-07-28', protocol_era: 'modern', tools: names,
152
207
  output_schemas_strict: true,
153
208
  machine_runtime: machineRuntime, privileged_host_plane: privilegedHostPlane,
154
209
  agent_runtime: agentRuntime, process_runtime: processRuntime,
155
210
  machine_fs_runtime: machineFsRuntime, observation_runtime: observationRuntime,
156
211
  coding_runtime: codingRuntime, autonomous_runtime: autonomousRuntime,
157
- proof: { output: proofOutput, receipt_sha256: proof.receipt_sha256,
158
- request_sha256: proof.request_sha256, signature_valid: true },
212
+ compact,
213
+ proof: proof ? { output: proofOutput, receipt_sha256: proof.receipt_sha256,
214
+ request_sha256: proof.request_sha256, signature_valid: true } : null,
159
215
  contained, agent
160
216
  }, null, 2));
161
217
  } finally {
@@ -497,6 +497,34 @@ export function runControllerStartNoCapture(ctx,timeoutMs=45000){
497
497
  const call=controllerInvocation(ctx,'start');
498
498
  return controlResult(call.exe,call.args,{cwd:call.cwd,timeoutMs,stdio:'ignore'});
499
499
  }
500
+ export async function readControllerStartFailure(ctx){
501
+ const file=path.join(ctx.runtime_root,'controller-start-failure.json');
502
+ let bytes;
503
+ try { bytes=await readFile(file); }
504
+ catch(error){ if(error?.code==='ENOENT') return null; throw error; }
505
+ const text=bytes.toString('utf8').replace(/^\uFEFF/,'');
506
+ let value;
507
+ try { value=JSON.parse(text); } catch(error){ throw new Error(`controller start failure evidence JSON invalid: ${error.message}`); }
508
+ if(value?.schema!=='deadbyte.controller-start-failure.v1'||!['start','resume','restart'].includes(String(value?.command??''))||
509
+ typeof value?.message!=='string'||value.message.length<1||typeof value?.failed_at_utc!=='string') {
510
+ throw new Error('controller start failure evidence schema invalid');
511
+ }
512
+ return {path:file,sha256:sha256Bytes(bytes),...value};
513
+ }
514
+ export async function preserveControllerStartFailure(ctx,evidenceDir){
515
+ const evidence=await readControllerStartFailure(ctx);
516
+ if(!evidence) return null;
517
+ const source=path.join(ctx.runtime_root,'controller-start-failure.json');
518
+ const bytes=await readFile(source);
519
+ const sourceSha256=sha256Bytes(bytes);
520
+ if(sourceSha256!==evidence.sha256) throw new Error('controller start failure evidence changed before preservation');
521
+ const destination=path.join(path.resolve(evidenceDir),'controller-start-failure.json');
522
+ await atomicBytes(destination,bytes);
523
+ const persistedSha256=sha256Bytes(await readFile(destination));
524
+ if(persistedSha256!==sourceSha256) throw new Error('preserved controller start failure evidence SHA-256 mismatch');
525
+ return {path:destination,sha256:persistedSha256,schema:evidence.schema,command:evidence.command,
526
+ failed_at_utc:evidence.failed_at_utc,message:evidence.message};
527
+ }
500
528
  async function readLedger(ctx,name){
501
529
  const file=path.join(ctx.runtime_root,`${name}.instance.json`);
502
530
  const value=JSON.parse((await readFile(file,'utf8')).replace(/^\uFEFF/,''));
@@ -554,12 +582,20 @@ async function waitCoreGone(runtime,timeoutMs=10000){
554
582
  }
555
583
  async function startAndVerify(ctx,oldRuntime){
556
584
  let start=null;
585
+ await rm(path.join(ctx.runtime_root,'controller-start-failure.json'),{force:true});
557
586
  for(let attempt=1;attempt<=3;attempt+=1){
558
587
  start=runControllerStartNoCapture(ctx,45000);
559
588
  if(!start.error&&start.status===0) break;
560
589
  if(attempt<3) await sleep(1500);
561
590
  }
562
- if(start.error||start.status!==0) throw new Error(`controller start transport failed status=${start.status} error=${start.error?.message??'none'}`);
591
+ if(start.error||start.status!==0){
592
+ let detail='';
593
+ try {
594
+ const evidence=await readControllerStartFailure(ctx);
595
+ if(evidence) detail=` controller=${evidence.message} evidence_sha256=${evidence.sha256}`;
596
+ } catch(error) { detail=` controller_evidence_error=${error.message}`; }
597
+ throw new Error(`controller start transport failed status=${start.status} error=${start.error?.message??'none'}${detail}`);
598
+ }
563
599
  let statusText=''; let status=null;
564
600
  const started=Date.now();
565
601
  while(Date.now()-started<45000){
@@ -879,6 +915,18 @@ export async function performSlotUpdate({stage,developmentRoot,expectedVersion,e
879
915
  return {ok:true,update_id:updateId,state_path:statePath,receipt_path:receiptPath,receipt_sha256:receipt.receipt_sha256,
880
916
  pointer:newPointer,new_runtime:newRuntime,final_authority:finalAuthority,workspace_root:workspace.target};
881
917
  } catch(error){
918
+ let controllerStartFailure=null,controllerStartFailurePreservationError=null;
919
+ if(pointerCommitted&&newCtx){
920
+ try {
921
+ controllerStartFailure=await preserveControllerStartFailure(newCtx,evidenceDir);
922
+ const claimed=/evidence_sha256=([0-9a-f]{64})/.exec(String(error?.message??error));
923
+ if(claimed&&(!controllerStartFailure||controllerStartFailure.sha256!==claimed[1])) {
924
+ controllerStartFailurePreservationError=`controller start failure evidence claim mismatch expected=${claimed[1]} preserved=${controllerStartFailure?.sha256??'missing'}`;
925
+ }
926
+ } catch(preserveError) {
927
+ controllerStartFailurePreservationError=String(preserveError?.message??preserveError);
928
+ }
929
+ }
882
930
  const rollback={attempted:false,new_runtime_stopped:false,pointer_restored:false,launchers_restored:false,workspace_restored:false,
883
931
  mcp_url_restored:false,old_runtime_restarted:false,authority_restored:false,errors:[]};
884
932
  try {
@@ -916,6 +964,8 @@ export async function performSlotUpdate({stage,developmentRoot,expectedVersion,e
916
964
  } catch(rollbackError){ rollback.errors.push(`rollback:${rollbackError.message}`); }
917
965
  const failure={schema:FAILURE_SCHEMA,update_id:updateId,release_version:expectedVersion,candidate_manifest_sha256:expectedManifest,
918
966
  failed_at_utc:new Date().toISOString(),phase:journal.phase??'unknown',error:{name:error?.name??'Error',code:error?.code??null,message:String(error?.message??error)},
967
+ controller_start_failure:controllerStartFailure,
968
+ controller_start_failure_preservation_error:controllerStartFailurePreservationError,
919
969
  predecessor_mode:predecessor?.mode??null,prior_pointer:publicPointer(pointerInfo?.pointer??null),attempted_pointer:publicPointer(newPointer),old_runtime:generationTuple(oldRuntime),rollback};
920
970
  await writeState(statePath,journal,'failed',{failure,rollback}).catch(()=>{});
921
971
  let failureReceipt=null;
@@ -0,0 +1,45 @@
1
+ import { sign as cryptoSign, verify as cryptoVerify } from 'node:crypto';
2
+ import { canonicalJson } from './canonical-json.mjs';
3
+ import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
4
+
5
+ const DOMAIN=Buffer.from('DEADBYTE-SEARCH-CURSOR-V1\0','utf8');
6
+ const HEX64=/^[0-9a-f]{64}$/;
7
+ const SCHEMA='deadbyte.search-cursor.v1';
8
+
9
+ function validateBody(body){
10
+ if(!body||typeof body!=='object'||Array.isArray(body)||body.schema!==SCHEMA) throw new Error('search cursor body invalid');
11
+ if(!HEX64.test(body.query_sha256??'')) throw new Error('search cursor query identity invalid');
12
+ if(!HEX64.test(body.snapshot_sha256??'')) throw new Error('search cursor snapshot identity invalid');
13
+ if(!Number.isInteger(body.offset)||body.offset<0||body.offset>1_000_000) throw new Error('search cursor offset invalid');
14
+ return {schema:SCHEMA,query_sha256:body.query_sha256,snapshot_sha256:body.snapshot_sha256,offset:body.offset};
15
+ }
16
+
17
+ export function createSearchCursorCodec({signingKeyPath,verifyKeyPath}){
18
+ if(!signingKeyPath||!verifyKeyPath) throw new Error('search cursor codec requires signing and verify keys');
19
+ return Object.freeze({
20
+ async encode(input){
21
+ const body=validateBody({...input,schema:SCHEMA});
22
+ const signing=await loadPrivateSigningKey(signingKeyPath);
23
+ const bytes=Buffer.from(canonicalJson(body),'utf8');
24
+ const signature=cryptoSign(null,Buffer.concat([DOMAIN,bytes]),signing.privateKey).toString('base64');
25
+ const envelope={body,attestation:{algorithm:'ed25519',key_id:signing.keyId,signature_base64:signature}};
26
+ return Buffer.from(canonicalJson(envelope),'utf8').toString('base64url');
27
+ },
28
+ async decode(cursor){
29
+ if(typeof cursor!=='string'||cursor.length<1||cursor.length>8192) throw new Error('search cursor invalid');
30
+ let envelope;
31
+ try{envelope=JSON.parse(Buffer.from(cursor,'base64url').toString('utf8'));}catch{throw new Error('search cursor invalid');}
32
+ const body=validateBody(envelope?.body);
33
+ const verifyKey=await loadPublicVerifyKey(verifyKeyPath);
34
+ const att=envelope?.attestation;
35
+ if(att?.algorithm!=='ed25519'||att?.key_id!==verifyKey.keyId||typeof att?.signature_base64!=='string') throw new Error('search cursor attestation invalid');
36
+ const signature=Buffer.from(att.signature_base64,'base64');
37
+ if(signature.length!==64||signature.toString('base64')!==att.signature_base64) throw new Error('search cursor signature encoding invalid');
38
+ const bytes=Buffer.from(canonicalJson(body),'utf8');
39
+ if(!cryptoVerify(null,Buffer.concat([DOMAIN,bytes]),verifyKey.publicKey,signature)) throw new Error('search cursor signature invalid');
40
+ return body;
41
+ }
42
+ });
43
+ }
44
+
45
+ export const SEARCH_CURSOR_SCHEMA=SCHEMA;
@@ -149,7 +149,7 @@ export function createTypeScriptSemanticBackend({codingRuntime}){
149
149
  }
150
150
  async function diagnostics({rootId,relativePath,maxResults=200}){
151
151
  if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
152
- await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
152
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
153
153
  const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath);
154
154
  const all=[...project.service.getSyntacticDiagnostics(target.absolute),...project.service.getSemanticDiagnostics(target.absolute)];
155
155
  const diagnosticsOut=all.slice(0,maxResults).map(item=>{
@@ -157,23 +157,90 @@ export function createTypeScriptSemanticBackend({codingRuntime}){
157
157
  const loc=locationFromSpan(project,target.absolute,span,'','diagnostic');
158
158
  return {message:ts.flattenDiagnosticMessageText(item.messageText,'\n'),code:String(item.code),severity:diagnosticCategory(item.category),...(loc?{location:loc}:{})};
159
159
  });
160
- return {status:'ok',root_id:rootId,path:relativePath,engine:`typescript-${ts.version}`,diagnostics:diagnosticsOut,truncated:all.length>maxResults};
160
+ const stable={root_id:rootId,path:relativePath,file_sha256:file.sha256,engine:`typescript-${ts.version}`,diagnostics:diagnosticsOut,truncated:all.length>maxResults};
161
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-diagnostics.v1',...stable})};
162
+ }
163
+ async function implementations({rootId,relativePath,line,column,maxResults=200}){
164
+ if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
165
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
166
+ const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath); const pos=offsetAt(target.source,line,column);
167
+ const raw=project.service.getImplementationAtPosition(target.absolute,pos)??[];
168
+ const locations=raw.map(item=>locationFromSpan(project,item.fileName,item.textSpan,item.name??'',item.kind??'implementation')).filter(Boolean).slice(0,maxResults);
169
+ const stable={root_id:rootId,path:relativePath,line,column,file_sha256:file.sha256,engine:`typescript-${ts.version}`,locations,truncated:raw.length>maxResults};
170
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-implementations.v1',...stable})};
161
171
  }
162
- return Object.freeze({id:'typescript',extensions:new Set(SOURCE_EXTENSIONS),outline,definition,references,replaceSymbol,diagnostics});
172
+ async function renameEdits({rootId,relativePath,line,column,newName}){
173
+ const file=await codingRuntime.fileRead({rootId,relativePath,encoding:'utf8'});
174
+ const project=await buildProject(codingRuntime,rootId); const target=targetFile(project,relativePath); const pos=offsetAt(target.source,line,column);
175
+ const info=project.service.getRenameInfo(target.absolute,pos,{allowRenameOfImportPath:false});
176
+ if(!info?.canRename) throw new Error(`semantic rename unavailable: ${info?.localizedErrorMessage??'symbol cannot be renamed'}`);
177
+ const raw=project.service.findRenameLocations(target.absolute,pos,false,false,true)??[];
178
+ if(raw.length<1) throw new Error('semantic rename produced no locations');
179
+ const edits=[];
180
+ for(const item of raw){
181
+ const loc=locationFromSpan(project,item.fileName,item.textSpan,'','rename');
182
+ if(!loc) continue;
183
+ edits.push({path:loc.path,start:item.textSpan.start,length:item.textSpan.length,new_text:`${item.prefixText??''}${newName}${item.suffixText??''}`});
184
+ }
185
+ if(edits.length<1) throw new Error('semantic rename produced no allowed edits');
186
+ edits.sort((a,b)=>a.path.localeCompare(b.path,'en')||a.start-b.start||a.length-b.length);
187
+ return {status:'ok',root_id:rootId,path:relativePath,engine:`typescript-${ts.version}`,target_file_sha256:file.sha256,edits};
188
+ }
189
+ return Object.freeze({id:'typescript',extensions:new Set(SOURCE_EXTENSIONS),outline,definition,references,replaceSymbol,diagnostics,implementations,renameEdits});
163
190
  }
164
191
 
165
- export function createSemanticCodeRuntime({codingRuntime,backends=[]}){
192
+ export function createSemanticCodeRuntime({codingRuntime,backends=[],nativeDiffRuntime=null}){
166
193
  if(!codingRuntime) throw new Error('semantic runtime requires coding runtime');
167
194
  if(!Array.isArray(backends)) throw new Error('semantic runtime backends must be an array');
168
195
  const typescript=createTypeScriptSemanticBackend({codingRuntime});
169
196
  const registry=createSemanticBackendRegistry({backends:[typescript,...backends]});
170
- const route=(method,args)=>registry.backendForPath(args.relativePath)[method](args);
197
+ const backendFor=args=>registry.backendForPath(args.relativePath);
198
+ const route=(method,args)=>{
199
+ const backend=backendFor(args);
200
+ if(typeof backend[method]!=='function') return {status:'unsupported',capability:method,engine:backend.id};
201
+ return backend[method](args);
202
+ };
203
+ async function renamePreview({rootId,relativePath,line,column,newName}){
204
+ if(typeof newName!=='string'||!/^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/.test(newName)) throw new Error('semantic rename new name must be a valid bounded identifier');
205
+ if(!nativeDiffRuntime||typeof nativeDiffRuntime.preview!=='function') throw new Error('semantic rename preview requires Native Diff runtime');
206
+ const backend=backendFor({relativePath});
207
+ if(typeof backend.renameEdits!=='function') return {status:'unsupported',capability:'rename_preview',engine:backend.id};
208
+ const plan=await backend.renameEdits({rootId,relativePath,line,column,newName});
209
+ if(plan?.status==='unsupported') return plan;
210
+ if(!plan||plan.status!=='ok'||!Array.isArray(plan.edits)||plan.edits.length<1) throw new Error('semantic rename backend returned no normalized edits');
211
+ const groups=new Map();
212
+ for(const edit of plan.edits){
213
+ if(!edit||typeof edit.path!=='string'||!Number.isInteger(edit.start)||edit.start<0||!Number.isInteger(edit.length)||edit.length<0||typeof edit.new_text!=='string') throw new Error('semantic rename edit malformed');
214
+ const list=groups.get(edit.path)??[]; list.push(edit); groups.set(edit.path,list);
215
+ }
216
+ const operations=[]; const preimages=[]; let editCount=0;
217
+ for(const filePath of [...groups.keys()].sort((a,b)=>a.localeCompare(b,'en'))){
218
+ const file=await codingRuntime.fileRead({rootId,relativePath:filePath,encoding:'utf8'});
219
+ const edits=[...groups.get(filePath)].sort((a,b)=>a.start-b.start||a.length-b.length);
220
+ let priorEnd=-1;
221
+ for(const edit of edits){
222
+ if(edit.start<priorEnd) throw new Error(`semantic rename overlapping edits in ${filePath}`);
223
+ if(edit.start+edit.length>file.content.length) throw new Error(`semantic rename edit outside ${filePath}`);
224
+ priorEnd=edit.start+edit.length;
225
+ }
226
+ let next=file.content;
227
+ for(const edit of [...edits].sort((a,b)=>b.start-a.start)) next=next.slice(0,edit.start)+edit.new_text+next.slice(edit.start+edit.length);
228
+ operations.push({kind:'write',path:filePath,content:next,encoding:'utf8',expected_sha256:file.sha256});
229
+ preimages.push({path:filePath,sha256:file.sha256});
230
+ editCount+=edits.length;
231
+ }
232
+ const diff=await nativeDiffRuntime.preview({rootId,title:`semantic rename ${relativePath} -> ${newName}`,operations});
233
+ return {status:'ready',diff_id:diff.diff_id,affected_files:operations.length,edit_count:editCount,
234
+ backend:plan.engine??backend.id,preimages};
235
+ }
171
236
  return Object.freeze({
172
237
  outline:async args=>route('outline',args),
173
238
  definition:async args=>route('definition',args),
174
239
  references:async args=>route('references',args),
175
240
  replaceSymbol:async args=>route('replaceSymbol',args),
176
241
  diagnostics:async args=>route('diagnostics',args),
242
+ implementations:async args=>route('implementations',args),
243
+ renamePreview,
177
244
  languages:()=>registry.languages()
178
245
  });
179
246
  }
@@ -119,7 +119,7 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
119
119
  const open=async ctx=>{
120
120
  const client=createLspStdioClient({executablePath:server.executable_path,expectedSha256:server.executable_sha256,args:server.args??[],cwd:ctx.root.real_path,env:server.env??{},dependencies:server.dependencies??[],requestTimeoutMs:server.request_timeout_ms??10000,maxMessageBytes:server.max_message_bytes??4*1024*1024});
121
121
  try{
122
- await client.initialize({processId:null,rootPath:ctx.root.real_path,rootUri:ctx.rootUri,workspaceFolders:[{uri:ctx.rootUri,name:path.basename(ctx.root.real_path)}],capabilities:{workspace:{workspaceFolders:true},textDocument:{documentSymbol:{hierarchicalDocumentSymbolSupport:true},definition:{},references:{},diagnostic:{}}},initializationOptions:server.initialization_options??{}});
122
+ await client.initialize({processId:null,rootPath:ctx.root.real_path,rootUri:ctx.rootUri,workspaceFolders:[{uri:ctx.rootUri,name:path.basename(ctx.root.real_path)}],capabilities:{workspace:{workspaceFolders:true},textDocument:{documentSymbol:{hierarchicalDocumentSymbolSupport:true},definition:{},references:{},implementation:{},rename:{prepareSupport:false},diagnostic:{}}},initializationOptions:server.initialization_options??{}});
123
123
  for(const document of await workspaceDocuments(ctx)) client.notify('textDocument/didOpen',{textDocument:{uri:document.uri,languageId,version:1,text:document.text}});
124
124
  if(startupSettleMs>0) await new Promise(resolve=>setTimeout(resolve,startupSettleMs));
125
125
  return client;
@@ -163,7 +163,43 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
163
163
  const raw=await withClient(ctx,client=>requestRead(client,'textDocument/diagnostic',{textDocument:{uri:ctx.uri}}));
164
164
  const items=Array.isArray(raw?.items)?raw.items:[];
165
165
  const diagnosticsOut=items.slice(0,maxResults).filter(item=>validRange(item?.range)).map(item=>({message:String(item.message??''),code:String(item.code??''),severity:SEVERITY[Number(item.severity)]??'unknown',location:{path:ctx.relativePath,name:'',kind:'diagnostic',start_line:item.range.start.line,start_column:item.range.start.character,end_line:item.range.end.line,end_column:item.range.end.character}}));
166
- return {status:'ok',root_id:rootId,path:ctx.relativePath,engine:id,diagnostics:diagnosticsOut,truncated:items.length>maxResults};
166
+ const stable={root_id:rootId,path:ctx.relativePath,file_sha256:ctx.file.sha256,engine:id,diagnostics:diagnosticsOut,truncated:items.length>maxResults};
167
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-diagnostics.v1',...stable})};
168
+ }
169
+ async function implementations({rootId,relativePath,line,column,maxResults=200}){
170
+ if(!Number.isInteger(maxResults)||maxResults<1||maxResults>500) throw new Error('max_results must be in [1, 500]');
171
+ const ctx=await rootContext(codingRuntime,rootId,relativePath);
172
+ let raw;
173
+ try { raw=await withClient(ctx,client=>requestRead(client,'textDocument/implementation',{textDocument:{uri:ctx.uri},position:{line,character:column}})); }
174
+ catch(error){ if(/-32601|method not found/i.test(String(error))) return {status:'unsupported',capability:'implementations',engine:id}; throw error; }
175
+ const normalized=normalizeLocations(raw,ctx,maxResults);
176
+ const stable={root_id:rootId,path:ctx.relativePath,line,column,file_sha256:ctx.file.sha256,engine:id,...normalized};
177
+ return {status:'ok',...stable,result_sha256:digest({schema:'deadbyte.semantic-implementations.v1',...stable})};
178
+ }
179
+ async function renameEdits({rootId,relativePath,line,column,newName}){
180
+ const ctx=await rootContext(codingRuntime,rootId,relativePath);
181
+ let raw;
182
+ try { raw=await withClient(ctx,client=>requestRead(client,'textDocument/rename',{textDocument:{uri:ctx.uri},position:{line,character:column},newName})); }
183
+ catch(error){ if(/-32601|method not found/i.test(String(error))) return {status:'unsupported',capability:'rename_preview',engine:id}; throw error; }
184
+ const byUri=[];
185
+ if(raw?.changes&&typeof raw.changes==='object') for(const [uri,edits] of Object.entries(raw.changes)) byUri.push({uri,edits});
186
+ for(const change of raw?.documentChanges??[]){ if(change?.textDocument?.uri&&Array.isArray(change.edits)) byUri.push({uri:change.textDocument.uri,edits:change.edits}); }
187
+ const normalized=[];
188
+ for(const group of byUri){
189
+ let absolute; try{absolute=path.resolve(fileURLToPath(group.uri));}catch{continue;}
190
+ if(!inside(ctx.root.real_path,absolute)||denied(ctx.root,absolute)) continue;
191
+ const rel=relNormalized(path.relative(ctx.root.real_path,absolute));
192
+ const file=await codingRuntime.fileRead({rootId,relativePath:rel,encoding:'utf8'});
193
+ for(const edit of group.edits??[]){
194
+ if(!validRange(edit?.range)||typeof edit?.newText!=='string') throw new Error('semantic LSP rename edit malformed');
195
+ const start=positionToOffset(file.content,edit.range.start); const end=positionToOffset(file.content,edit.range.end);
196
+ if(end<start) throw new Error('semantic LSP rename range invalid');
197
+ normalized.push({path:rel,start,length:end-start,new_text:edit.newText});
198
+ }
199
+ }
200
+ if(normalized.length<1) throw new Error('semantic LSP rename produced no allowed edits');
201
+ normalized.sort((a,b)=>a.path.localeCompare(b.path,'en')||a.start-b.start||a.length-b.length);
202
+ return {status:'ok',root_id:rootId,path:ctx.relativePath,engine:id,target_file_sha256:ctx.file.sha256,edits:normalized};
167
203
  }
168
204
  async function replaceSymbol({rootId,relativePath,symbolId,newBody,expectedSha256}){
169
205
  if(typeof newBody!=='string'||newBody.length>524288) throw new Error('new_body exceeds 524288 characters');
@@ -179,5 +215,5 @@ export function createSemanticLspBackend({id,extensions,codingRuntime,server}){
179
215
  const result=await codingRuntime.textReplace({rootId,relativePath:ctx.relativePath,oldString:oldBody,newString:newBody,expectedSha256,expectedReplacements:1});
180
216
  return {...result,symbol_id:symbolId,symbol_name:symbol.name,engine:id};
181
217
  }
182
- return Object.freeze({id,extensions:extensionSet,outline,definition,references,replaceSymbol,diagnostics});
218
+ return Object.freeze({id,extensions:extensionSet,outline,definition,references,replaceSymbol,diagnostics,implementations,renameEdits});
183
219
  }
package/src/version.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const DEADBYTE_VERSION = '0.9.0';
1
+ export const DEADBYTE_VERSION = '0.10.0';
2
2
  export const MCP_PROTOCOL_VERSION = '2026-07-28';
3
3
  export const RECEIPT_SCHEMA_V1 = 'deadbyte.receipt.v1';
4
4
  export const RECEIPT_SCHEMA_V2 = 'deadbyte.receipt.v2';