deadbyte-mcp 0.9.0 → 0.11.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.
- package/MANIFEST.SHA256 +134 -92
- package/README.txt +19 -15
- package/bench/fixtures/corpus.json +32 -13
- package/bench/fixtures/r36/case-map.json +8 -0
- package/bin/WORKER-REGISTRY.txt +3 -3
- package/bin/appcontainer-stage.exe +0 -0
- package/bin/appcontainer-stage.obj +0 -0
- package/bin/bootstrap-advapi32.exe +0 -0
- package/bin/bootstrap-advapi32.obj +0 -0
- package/bin/bootstrap-exitcode.exe +0 -0
- package/bin/bootstrap-exitcode.obj +0 -0
- package/bin/bootstrap-kernel32.exe +0 -0
- package/bin/bootstrap-kernel32.obj +0 -0
- package/bin/child-control-probe.exe +0 -0
- package/bin/child-control-probe.obj +0 -0
- package/bin/child-control-stage.exe +0 -0
- package/bin/child-control-stage.obj +0 -0
- package/bin/contained-reverse-worker.exe +0 -0
- package/bin/contained-reverse-worker.obj +0 -0
- package/bin/contained-transform-worker.exe +0 -0
- package/bin/contained-transform-worker.obj +0 -0
- package/bin/containment-probe.exe +0 -0
- package/bin/containment-probe.obj +0 -0
- package/bin/deadbyte-contain.exe +0 -0
- package/bin/deadbyte-contain.obj +0 -0
- package/bin/deadbyte-exec.exe +0 -0
- package/bin/deadbyte-exec.obj +0 -0
- package/bin/deadbyte-process-host.exe +0 -0
- package/bin/deadbyte-process-host.obj +0 -0
- package/bin/deadbyte-tunnel-host.exe +0 -0
- package/bin/deadbyte-tunnel-host.obj +0 -0
- package/controller/README.TXT +8 -6
- package/controller/deadbyte-controller.ps1 +48 -2
- package/controller/deadbyte-process-policy.json +5 -5
- package/docs/ARCHITECTURE.md +1 -1
- package/docs/R36-CAPABILITY-EVIDENCE.md +43 -0
- package/docs/superpowers/plans/2026-09-18-r36-zero-loss-autonomy.md +739 -0
- package/docs/superpowers/specs/2026-09-18-r36-zero-loss-autonomy-design.md +640 -0
- package/package.json +1 -1
- package/proof/CONTAINMENT-BUILD.txt +6 -6
- package/scripts/deferred-slot-operation.mjs +53 -15
- package/scripts/final-closure-r36.mjs +113 -0
- package/scripts/final-closure-verify-r36.mjs +208 -0
- package/scripts/final-closure-verify.mjs +88 -39
- package/scripts/final-closure.mjs +63 -56
- package/scripts/gate-windows-r36.ps1 +42 -0
- package/scripts/gate-windows.ps1 +3 -3
- package/scripts/release-parity-r36.mjs +200 -0
- package/scripts/release-parity-tests.ps1 +9 -0
- package/scripts/release-parity.mjs +149 -139
- package/scripts/windows-gate-evidence-r36.mjs +52 -0
- package/scripts/windows-gate-evidence.mjs +5 -5
- package/src/agent-memory-plane.mjs +98 -0
- package/src/autonomous-context-engine.mjs +2 -1
- package/src/autonomous-mcp-tools.mjs +5 -1
- package/src/autonomous-output-contracts.mjs +9 -6
- package/src/autonomous-planner-contracts.mjs +36 -1
- package/src/autonomous-planner.mjs +25 -3
- package/src/autonomous-runtime.mjs +337 -43
- package/src/autonomous-timeout-recovery.mjs +27 -0
- package/src/capability-benchmark-runner.mjs +86 -1
- package/src/capability-benchmark.mjs +45 -0
- package/src/capability-ledger.mjs +158 -0
- package/src/coding-mcp-tools.mjs +31 -17
- package/src/coding-output-contracts.mjs +48 -10
- package/src/coding-plane.mjs +45 -9
- package/src/coding-search.mjs +130 -47
- package/src/compact-gateway-mcp-tools.mjs +128 -0
- package/src/compact-gateway-output-contracts.mjs +16 -0
- package/src/deadbyte-cli.mjs +62 -78
- package/src/effect-ledger.mjs +47 -0
- package/src/machine-fs-smoke-client.mjs +1 -1
- package/src/machine-fs.mjs +51 -8
- package/src/mcp-server.mjs +32 -9
- package/src/native-diff-v2.mjs +337 -0
- package/src/native-diff.mjs +50 -2
- package/src/observation-lease.mjs +32 -0
- package/src/observation-smoke-client.mjs +1 -1
- package/src/operator-surface.mjs +7 -1
- package/src/process-runtime.mjs +98 -11
- package/src/process-smoke-client.mjs +11 -3
- package/src/r36-compact-disarmed-probe.mjs +50 -0
- package/src/r36-full-surface-probe.mjs +56 -0
- package/src/remote-live-log.mjs +135 -0
- package/src/remote-mcp-autonomous-smoke-client.mjs +22 -12
- package/src/remote-mcp-coding-smoke-client.mjs +1 -1
- package/src/remote-mcp-r36-parity-client.mjs +175 -0
- package/src/remote-mcp-smoke-client.mjs +112 -56
- package/src/runtime-update.mjs +51 -1
- package/src/search-cursor.mjs +45 -0
- package/src/semantic-code.mjs +72 -5
- package/src/semantic-lsp-backend.mjs +39 -3
- package/src/version.mjs +1 -1
- package/src/worker-scheduler.mjs +53 -0
- package/test/autonomous-capability-r36.test.mjs +151 -0
- package/test/autonomous-output-contract.test.mjs +1 -1
- package/test/autonomous-runtime.test.mjs +2 -2
- package/test/capability-benchmark-r36.test.mjs +107 -0
- package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
- package/test/capability-claims-r36.test.mjs +23 -0
- package/test/capability-ledger-r36.test.mjs +102 -0
- package/test/coding-catalog-consistency.test.mjs +2 -2
- package/test/coding-plane.test.mjs +2 -2
- package/test/coding-runtime.test.mjs +16 -0
- package/test/coding-search-r36.test.mjs +90 -0
- package/test/compact-catalog-r36.test.mjs +37 -0
- package/test/compact-gateway-r36.test.mjs +66 -0
- package/test/contained.test.mjs +1 -1
- package/test/core.test.mjs +1 -1
- package/test/deferred-slot-operation.test.mjs +9 -0
- package/test/fixtures/lsp-framed-server.mjs +2 -0
- package/test/helpers/autonomous-r34-fixture.mjs +5 -3
- package/test/multi-file-read.test.mjs +3 -0
- package/test/native-diff-topology-r36.test.mjs +105 -0
- package/test/package-boundary.test.mjs +6 -0
- package/test/process-longrun-r36.test.mjs +82 -0
- package/test/process-release-gate.test.mjs +9 -0
- package/test/production-docs.test.mjs +5 -5
- package/test/prompts-resources.test.mjs +7 -1
- package/test/r33-closeout-regression.test.mjs +4 -3
- package/test/r33-finalization.test.mjs +14 -9
- package/test/r36-finalization.test.mjs +104 -0
- package/test/r36-release-identity.test.mjs +45 -0
- package/test/r37-agent-fabric.test.mjs +92 -0
- package/test/r37-autonomous-timeout-recovery.test.mjs +60 -0
- package/test/r37-finalization.test.mjs +74 -0
- package/test/release-version.test.mjs +42 -33
- package/test/remote-live-log-r36.test.mjs +37 -0
- package/test/remote-live-log-r37.test.mjs +47 -0
- package/test/remote-live-log-recovery-r36.test.mjs +41 -0
- package/test/remote-r24-catalog.test.mjs +13 -0
- package/test/remote-session-cli.test.mjs +53 -66
- package/test/runtime-self-update.test.mjs +58 -1
- package/test/semantic-lsp-backend.test.mjs +9 -0
- package/test/semantic-r36-rename.test.mjs +82 -0
- package/deadbyte-mcp-0.8.9.tgz +0 -0
package/src/semantic-code.mjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { canonicalJson } from './canonical-json.mjs';
|
|
3
|
+
|
|
4
|
+
export const WORKER_SCHEDULER_SCHEMA='deadbyte.worker-scheduler.v1';
|
|
5
|
+
const sha=value=>createHash('sha256').update(Buffer.from(canonicalJson(value),'utf8')).digest('hex');
|
|
6
|
+
|
|
7
|
+
export function createWorkerScheduler({maxConcurrent=1,totalCpuUnits=1,totalMemoryMb=1024,leaseMs=60000,clock=()=>Date.now()}={}){
|
|
8
|
+
if(!Number.isInteger(maxConcurrent)||maxConcurrent<1) throw new Error('maxConcurrent invalid');
|
|
9
|
+
if(!Number.isInteger(totalCpuUnits)||totalCpuUnits<1) throw new Error('totalCpuUnits invalid');
|
|
10
|
+
if(!Number.isInteger(totalMemoryMb)||totalMemoryMb<1) throw new Error('totalMemoryMb invalid');
|
|
11
|
+
if(!Number.isInteger(leaseMs)||leaseMs<100) throw new Error('leaseMs invalid');
|
|
12
|
+
const active=new Map(),attempts=new Map(),history=[];
|
|
13
|
+
function reclaim(){
|
|
14
|
+
const now=clock();
|
|
15
|
+
for(const [id,lease] of active) if(lease.expires_at_ms<=now){
|
|
16
|
+
active.delete(id);history.push({...lease,status:'expired',released_at_ms:now});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function usage(){
|
|
20
|
+
return [...active.values()].reduce((x,l)=>({cpu:x.cpu+l.cpu_units,memory:x.memory+l.memory_mb}),{cpu:0,memory:0});
|
|
21
|
+
}
|
|
22
|
+
function snapshot(){
|
|
23
|
+
reclaim();
|
|
24
|
+
const used=usage();
|
|
25
|
+
return Object.freeze({schema:WORKER_SCHEDULER_SCHEMA,max_concurrent:maxConcurrent,total_cpu_units:totalCpuUnits,total_memory_mb:totalMemoryMb,
|
|
26
|
+
active:[...active.values()].sort((a,b)=>a.lease_id.localeCompare(b.lease_id,'en')),
|
|
27
|
+
history:[...history],used_cpu_units:used.cpu,used_memory_mb:used.memory});
|
|
28
|
+
}
|
|
29
|
+
function acquire({taskId,workerClass,cpuUnits=1,memoryMb=128}){
|
|
30
|
+
reclaim();
|
|
31
|
+
if(typeof taskId!=='string'||!taskId) throw new Error('taskId invalid');
|
|
32
|
+
if(typeof workerClass!=='string'||!workerClass) throw new Error('workerClass invalid');
|
|
33
|
+
if(!Number.isInteger(cpuUnits)||cpuUnits<1||!Number.isInteger(memoryMb)||memoryMb<1) throw new Error('worker resources invalid');
|
|
34
|
+
const used=usage();
|
|
35
|
+
if(active.size>=maxConcurrent||used.cpu+cpuUnits>totalCpuUnits||used.memory+memoryMb>totalMemoryMb) throw new Error('worker scheduler capacity exceeded');
|
|
36
|
+
const attempt=(attempts.get(taskId)??0)+1;attempts.set(taskId,attempt);
|
|
37
|
+
const issued=clock(),expires=issued+leaseMs;
|
|
38
|
+
const body={schema:'deadbyte.worker-lease.v1',task_id:taskId,worker_class:workerClass,attempt,cpu_units:cpuUnits,memory_mb:memoryMb,issued_at_ms:issued,expires_at_ms:expires};
|
|
39
|
+
const lease=Object.freeze({...body,lease_id:sha(body)});
|
|
40
|
+
active.set(lease.lease_id,lease);
|
|
41
|
+
return lease;
|
|
42
|
+
}
|
|
43
|
+
function heartbeat(leaseId){
|
|
44
|
+
reclaim();const current=active.get(leaseId);if(!current) throw new Error('worker lease unavailable');
|
|
45
|
+
const next=Object.freeze({...current,expires_at_ms:clock()+leaseMs});active.set(leaseId,next);return next;
|
|
46
|
+
}
|
|
47
|
+
function release(leaseId,{status='completed'}={}){
|
|
48
|
+
reclaim();const lease=active.get(leaseId);if(!lease) throw new Error('worker lease unavailable');
|
|
49
|
+
active.delete(leaseId);const item={...lease,status,released_at_ms:clock()};history.push(item);
|
|
50
|
+
return Object.freeze({status:'released',lease:item});
|
|
51
|
+
}
|
|
52
|
+
return Object.freeze({acquire,heartbeat,release,snapshot});
|
|
53
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { parseR34PlannerDecision, buildPlannerPrompt } from '../src/autonomous-planner.mjs';
|
|
4
|
+
import { judgeProgress } from '../src/autonomous-progress.mjs';
|
|
5
|
+
import { createR34Fixture, sendPlannerDecision, planCreateDecision, inspectDecision } from './helpers/autonomous-r34-fixture.mjs';
|
|
6
|
+
|
|
7
|
+
const H='a'.repeat(64);
|
|
8
|
+
const policy={
|
|
9
|
+
profiles:{},
|
|
10
|
+
limits:{max_context_bytes:262144,max_files_per_diff:32,max_stalled_cycles:2,max_post_replan_stalls:2,max_replans:8}
|
|
11
|
+
};
|
|
12
|
+
const wrap=action=>JSON.stringify({schema:'deadbyte.autonomous-decision.v2',kind:'act',action});
|
|
13
|
+
|
|
14
|
+
const typedCases=[
|
|
15
|
+
['search',{kind:'search',path:'.',target:'content',mode:'regex',pattern:'foo\\d+',case_sensitive:false,max_results:50,max_file_bytes:262144,max_scan_bytes:1048576,page_size:25,cursor:null}],
|
|
16
|
+
['stat',{kind:'stat',path:'src/a.mjs',hash:true}],
|
|
17
|
+
['multi_read',{kind:'multi_read',files:[{path:'src/a.mjs',encoding:'utf8'},{path:'src/b.mjs',encoding:'utf8'}],max_total_bytes:131072}],
|
|
18
|
+
['semantic_references',{kind:'semantic_references',path:'src/a.mjs',line:1,column:2,max_results:100}],
|
|
19
|
+
['semantic_rename_preview',{kind:'semantic_rename_preview',path:'src/a.mjs',line:1,column:2,new_name:'renamed'}],
|
|
20
|
+
['native_diff_apply',{kind:'native_diff_apply',diff_id:H,expected_operation_count:1}],
|
|
21
|
+
['native_diff_verify',{kind:'native_diff_verify',diff_id:H}],
|
|
22
|
+
['process_start',{kind:'process_start',profile_id:'test',cwd:'.',args:[]}],
|
|
23
|
+
['process_read',{kind:'process_read',session_id:H,offset:0,max_bytes:65536}],
|
|
24
|
+
['process_status',{kind:'process_status',session_id:H}],
|
|
25
|
+
['process_action',{kind:'process_action',session_id:H,action_id:'ping'}],
|
|
26
|
+
['process_terminate',{kind:'process_terminate',session_id:H}],
|
|
27
|
+
['machine_fs_stat',{kind:'machine_fs_stat',path:'src',hash:true}],
|
|
28
|
+
['machine_fs_list',{kind:'machine_fs_list',path:'.',cursor:null,limit:100,hash_files:false}],
|
|
29
|
+
['machine_fs_read',{kind:'machine_fs_read',path:'src/a.mjs',offset:0,max_bytes:65536,hash_file:true}],
|
|
30
|
+
['machine_fs_mkdir',{kind:'machine_fs_mkdir',path:'generated'}],
|
|
31
|
+
['machine_fs_move',{kind:'machine_fs_move',source_path:'a.txt',destination_path:'b.txt',expected_source_identity:H}],
|
|
32
|
+
['machine_fs_delete',{kind:'machine_fs_delete',path:'empty',expected_source_identity:H}],
|
|
33
|
+
['observation_search_start',{kind:'observation_search_start',path:'.',pattern:'FAIL',case_sensitive:false,max_results:100,max_files:1000,max_bytes:1048576,max_file_bytes:262144}],
|
|
34
|
+
['observation_search_page',{kind:'observation_search_page',search_id:H,cursor:null,limit:50}],
|
|
35
|
+
['observation_system_status',{kind:'observation_system_status'}]
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
test('R36 planner parses first-class capability actions without delegate wrapper',()=>{
|
|
39
|
+
for(const [label,action] of typedCases){
|
|
40
|
+
const parsed=parseR34PlannerDecision(wrap(action),policy);
|
|
41
|
+
assert.equal(parsed.kind,'act',label);
|
|
42
|
+
assert.equal(parsed.action.kind,action.kind,label);
|
|
43
|
+
assert.notEqual(parsed.action.kind,'delegate',label);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test('R36 legacy delegate is accepted only for a known operation and normalized into typed action',()=>{
|
|
48
|
+
const parsed=parseR34PlannerDecision(wrap({kind:'delegate',operation:{kind:'process_status',session_id:H}}),policy);
|
|
49
|
+
assert.equal(parsed.action.kind,'process_status');
|
|
50
|
+
assert.equal(parsed.action.session_id,H);
|
|
51
|
+
assert.equal('operation' in parsed.action,false);
|
|
52
|
+
assert.throws(()=>parseR34PlannerDecision(wrap({kind:'delegate',operation:{kind:'arbitrary_tool',tool_name:'host_exec',args:{}}}),policy),/contract|delegated|unsupported|authority/i);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('R36 planner prompt exposes configured capability manifest and never advertises Host',()=>{
|
|
56
|
+
const prompt=buildPlannerPrompt({goal:{title:'x',goal:'fix',acceptance:'tests pass'},policy,view:{mutation_epoch:0,planner_round:0,tree:[],contexts:[],observations:[],recent_decisions:[],active_plan:null,capabilities:{schema:'deadbyte.capability-manifest.v1',ledger_sha256:H,entries:[
|
|
57
|
+
{id:'coding.search',authority:'coding',mutating:false},
|
|
58
|
+
{id:'process.start',authority:'process',mutating:true}
|
|
59
|
+
]}}});
|
|
60
|
+
assert.match(prompt,/coding\.search/);
|
|
61
|
+
assert.match(prompt,/process\.start/);
|
|
62
|
+
assert.doesNotMatch(prompt,/host\.exec|host_file|host authority/i);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test('R36 progress fingerprint ignores rationale but binds capability, evidence, session and cursor identity',()=>{
|
|
66
|
+
const base={before:{mutation_epoch:2},after:{mutation_epoch:2},decision:{kind:'process_read',rationale:'first'},evidence:{capability_id:'process.read',session_id:H,cursor:10,observation_sha256:'b'.repeat(64),receipt_sha256:'c'.repeat(64)}};
|
|
67
|
+
const a=judgeProgress(base);
|
|
68
|
+
const prose=judgeProgress({...base,decision:{...base.decision,rationale:'completely different prose'}});
|
|
69
|
+
assert.equal(a.fingerprint,prose.fingerprint);
|
|
70
|
+
const cap=judgeProgress({...base,evidence:{...base.evidence,capability_id:'process.status'}});
|
|
71
|
+
const cursor=judgeProgress({...base,evidence:{...base.evidence,cursor:11}});
|
|
72
|
+
const session=judgeProgress({...base,evidence:{...base.evidence,session_id:'d'.repeat(64)}});
|
|
73
|
+
const receipt=judgeProgress({...base,evidence:{...base.evidence,receipt_sha256:'e'.repeat(64)}});
|
|
74
|
+
assert.notEqual(a.fingerprint,cap.fingerprint);
|
|
75
|
+
assert.notEqual(a.fingerprint,cursor.fingerprint);
|
|
76
|
+
assert.notEqual(a.fingerprint,session.fingerprint);
|
|
77
|
+
assert.notEqual(a.fingerprint,receipt.fingerprint);
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test('R36 typed stat executes through the autonomous loop and records capability-bound evidence',async()=>{
|
|
81
|
+
const f=await createR34Fixture();
|
|
82
|
+
try{
|
|
83
|
+
const goal=await f.runtime.submit({submissionId:'r36-typed-stat',rootId:'project',title:'typed stat',goal:'inspect x.txt identity',acceptance:'stat evidence is journaled'});
|
|
84
|
+
let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
|
|
85
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
|
|
86
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
|
|
87
|
+
assert.equal(result.loop.phase,'ACTING');
|
|
88
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'stat',path:'x.txt',hash:true}});
|
|
89
|
+
assert.equal(result.status,'input_required');
|
|
90
|
+
assert.equal(result.loop.phase,'VERIFYING');
|
|
91
|
+
const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
|
|
92
|
+
const event=journal.events.find(item=>item.type==='delegated_action_completed'&&item.payload?.operation?.kind==='stat');
|
|
93
|
+
assert.ok(event);
|
|
94
|
+
assert.equal(event.payload.capability_id,'coding.stat');
|
|
95
|
+
assert.match(event.payload.result.observation_sha256,/^[0-9a-f]{64}$/);
|
|
96
|
+
} finally {await f.cleanup();}
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test('R36 typed native_diff_apply binds expected operation count and advances mutation epoch only after verified apply',async()=>{
|
|
100
|
+
const f=await createR34Fixture();
|
|
101
|
+
try{
|
|
102
|
+
const preview=await f.nativeDiffRuntime.preview({rootId:'project',title:'typed apply',operations:[{
|
|
103
|
+
kind:'replace',path:'x.txt',expected_sha256:f.initial_sha256,old_string:'x',new_string:'y',expected_replacements:1
|
|
104
|
+
}]});
|
|
105
|
+
assert.equal(preview.operation_count,1);
|
|
106
|
+
const goal=await f.runtime.submit({submissionId:'r36-typed-apply',rootId:'project',title:'typed apply',goal:'apply the prepared native diff',acceptance:'mutation is verified and journaled'});
|
|
107
|
+
let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
|
|
108
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
|
|
109
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
|
|
110
|
+
assert.equal(result.loop.phase,'ACTING');
|
|
111
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'native_diff_apply',diff_id:preview.diff_id,expected_operation_count:1}});
|
|
112
|
+
assert.equal(result.status,'input_required');
|
|
113
|
+
assert.equal(result.loop.phase,'VERIFYING');
|
|
114
|
+
const state=await f.runtime.status({goalId:goal.goal_id});
|
|
115
|
+
assert.equal(state.mutation_epoch,1);
|
|
116
|
+
assert.equal(state.mutation_count,1);
|
|
117
|
+
const read=await f.baseCodingRuntime.fileRead({rootId:'project',relativePath:'x.txt',encoding:'utf8'});
|
|
118
|
+
assert.equal(read.content,'y\n');
|
|
119
|
+
const verified=await f.nativeDiffRuntime.verify({diffId:preview.diff_id});
|
|
120
|
+
assert.equal(verified.ok,true);
|
|
121
|
+
assert.equal(verified.current_state_matches,true);
|
|
122
|
+
const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
|
|
123
|
+
const committed=journal.events.find(item=>item.type==='native_diff_committed'&&item.payload?.diff_id===preview.diff_id);
|
|
124
|
+
assert.ok(committed);
|
|
125
|
+
assert.equal(committed.payload.mutation_count,1);
|
|
126
|
+
assert.deepEqual(committed.payload.paths,['x.txt']);
|
|
127
|
+
} finally {await f.cleanup();}
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
test('R36 typed machine_fs_mkdir is promoted to Native Diff V2 and advances mutation epoch',async()=>{
|
|
131
|
+
const f=await createR34Fixture();
|
|
132
|
+
try{
|
|
133
|
+
const goal=await f.runtime.submit({submissionId:'r36-typed-mkdir',rootId:'project',title:'typed mkdir',goal:'create generated directory transactionally',acceptance:'directory creation is native-diff verified'});
|
|
134
|
+
let result=await f.runtime.run({goalId:goal.goal_id,maxCycles:4});
|
|
135
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,planCreateDecision());
|
|
136
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,inspectDecision());
|
|
137
|
+
result=await sendPlannerDecision(f.runtime,goal.goal_id,result,{schema:'deadbyte.autonomous-decision.v2',kind:'act',action:{kind:'machine_fs_mkdir',path:'generated'}});
|
|
138
|
+
assert.equal(result.status,'input_required');
|
|
139
|
+
assert.equal(result.loop.phase,'VERIFYING');
|
|
140
|
+
const state=await f.runtime.status({goalId:goal.goal_id});
|
|
141
|
+
assert.equal(state.mutation_epoch,1);
|
|
142
|
+
assert.equal(state.mutation_count,1);
|
|
143
|
+
const dir=await f.machineFsRuntime.state({rootId:'project',relativePath:'generated'});
|
|
144
|
+
assert.equal(dir.exists,true);
|
|
145
|
+
assert.equal(dir.kind,'directory');
|
|
146
|
+
const journal=await f.runtime.events({goalId:goal.goal_id,fromSeq:1,limit:200});
|
|
147
|
+
const committed=journal.events.find(item=>item.type==='native_diff_committed');
|
|
148
|
+
assert.ok(committed);
|
|
149
|
+
assert.deepEqual(committed.payload.paths,['generated']);
|
|
150
|
+
} finally {await f.cleanup();}
|
|
151
|
+
});
|
|
@@ -48,7 +48,7 @@ test('R34 run/status output contracts accept only the sanitized public loop proj
|
|
|
48
48
|
assert.equal(run.structuredContent.loop.phase,'ACTING');
|
|
49
49
|
const status = autonomousStructuredResult(autonomousGoalStatusOutputSchema,{
|
|
50
50
|
status:'ok',goal_id:'1'.repeat(64),goal_sha256:'2'.repeat(64),title:'x',root_id:'project',journal_verified:true,
|
|
51
|
-
|
|
51
|
+
run_busy:false,run_owner_pid:null,run_lock_created_at_utc:null,...baseDerived(),loop:publicLoop
|
|
52
52
|
});
|
|
53
53
|
assert.equal(status.structuredContent.loop.pending_action.kind,'patch');
|
|
54
54
|
const approved = autonomousStructuredResult(autonomousGoalApproveOutputSchema,{
|
|
@@ -24,7 +24,7 @@ const r23Tools = [
|
|
|
24
24
|
'agent_task_approve','agent_task_cancel','agent_task_events','agent_task_run',
|
|
25
25
|
'agent_task_status','agent_task_submit','agent_task_verify',
|
|
26
26
|
'coding_benchmark_run','coding_command_run','coding_file_read','coding_file_write','coding_files_read',
|
|
27
|
-
'coding_receipt_verify','coding_search','coding_session_status','coding_stat','coding_symbol_definition','coding_symbol_outline','coding_symbol_references','coding_symbol_replace',
|
|
27
|
+
'coding_receipt_verify','coding_search','coding_session_status','coding_stat','coding_symbol_definition','coding_symbol_diagnostics','coding_symbol_implementations','coding_symbol_outline','coding_symbol_references','coding_symbol_rename_preview','coding_symbol_replace',
|
|
28
28
|
'coding_task_approve','coding_task_cancel','coding_task_events','coding_task_run',
|
|
29
29
|
'coding_task_status','coding_task_submit','coding_task_verify','coding_text_replace','coding_tree'
|
|
30
30
|
];
|
|
@@ -75,7 +75,7 @@ async function fixture() {
|
|
|
75
75
|
return { root, client, transport };
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
test('
|
|
78
|
+
test('R36 hermetic autonomous fixture exposes the exact 49-tool no-host catalog', async () => {
|
|
79
79
|
const f = await fixture();
|
|
80
80
|
try {
|
|
81
81
|
await f.client.connect(f.transport);
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import {
|
|
7
|
+
R36_CAPABILITY_BENCHMARK_SCHEMA,
|
|
8
|
+
normalizeR36BenchmarkCase,
|
|
9
|
+
buildR36CapabilityBenchmark
|
|
10
|
+
} from '../src/capability-benchmark.mjs';
|
|
11
|
+
import {
|
|
12
|
+
R36_BENCHMARK_CASE_IDS,
|
|
13
|
+
r36BenchmarkCaseDefinitions
|
|
14
|
+
} from '../src/capability-benchmark-runner.mjs';
|
|
15
|
+
|
|
16
|
+
const REQUIRED=Object.freeze([
|
|
17
|
+
'repository_tree_exploration',
|
|
18
|
+
'literal_content_search',
|
|
19
|
+
'regex_content_search',
|
|
20
|
+
'filename_path_search',
|
|
21
|
+
'deterministic_search_paging_cancel',
|
|
22
|
+
'bounded_multi_file_read',
|
|
23
|
+
'rich_stat_reparse_handling',
|
|
24
|
+
'stale_edit_race_rejection',
|
|
25
|
+
'transactional_multi_file_native_diff',
|
|
26
|
+
'topology_mkdir_move_delete_rollback',
|
|
27
|
+
'semantic_typescript_navigation',
|
|
28
|
+
'semantic_python_navigation',
|
|
29
|
+
'semantic_rust_navigation',
|
|
30
|
+
'semantic_cpp_navigation',
|
|
31
|
+
'diagnostics_normalization',
|
|
32
|
+
'implementation_lookup',
|
|
33
|
+
'cross_file_rename_transaction',
|
|
34
|
+
'long_process_lifecycle',
|
|
35
|
+
'policy_defined_process_action',
|
|
36
|
+
'process_crash_reconciliation',
|
|
37
|
+
'autonomous_failing_test_repair',
|
|
38
|
+
'autonomous_search_semantic_patch_test',
|
|
39
|
+
'release_gate_finish_without_evidence_refusal',
|
|
40
|
+
'provider_bridge_interruption_recovery',
|
|
41
|
+
'remote_result_replay_deduplication',
|
|
42
|
+
'compact_connector_capability_closure',
|
|
43
|
+
'live_log_request_before_result',
|
|
44
|
+
'live_log_redaction',
|
|
45
|
+
'forged_stale_receipt_rejection',
|
|
46
|
+
'rollback_r35_restore_r36'
|
|
47
|
+
]);
|
|
48
|
+
const H=c=>c.repeat(64);
|
|
49
|
+
const base={
|
|
50
|
+
case_id:REQUIRED[0],fixture_sha256:H('a'),correct:true,round_trips:2,bytes_returned:128,elapsed_ms:12.5,
|
|
51
|
+
stale_rejected:false,recovery_success:true,duplicate_side_effects:0,capability_reachable:true,
|
|
52
|
+
evidence_verified:true,release_gate_result:'not_applicable',evidence_sha256:H('b')
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
test('R36 benchmark corpus exposes exactly the 30 approved production coding cases',async()=>{
|
|
56
|
+
assert.equal(R36_CAPABILITY_BENCHMARK_SCHEMA,'deadbyte.r36-capability-benchmark.v1');
|
|
57
|
+
assert.deepEqual([...R36_BENCHMARK_CASE_IDS],REQUIRED);
|
|
58
|
+
const defs=r36BenchmarkCaseDefinitions();
|
|
59
|
+
assert.equal(defs.length,30);
|
|
60
|
+
assert.deepEqual(defs.map(item=>item.case_id),REQUIRED);
|
|
61
|
+
assert.equal(new Set(defs.map(item=>item.case_id)).size,30);
|
|
62
|
+
for(const item of defs){
|
|
63
|
+
assert.ok(Array.isArray(item.test_files)&&item.test_files.length>=1,item.case_id);
|
|
64
|
+
assert.ok(Array.isArray(item.fixture_files)&&item.fixture_files.length>=1,item.case_id);
|
|
65
|
+
assert.ok(Number.isInteger(item.round_trips)&&item.round_trips>=1,item.case_id);
|
|
66
|
+
assert.equal(typeof item.capability_reachable,'boolean',item.case_id);
|
|
67
|
+
assert.equal(typeof item.evidence_verified,'boolean',item.case_id);
|
|
68
|
+
assert.ok(['passed','blocked','not_applicable'].includes(item.release_gate_result),item.case_id);
|
|
69
|
+
}
|
|
70
|
+
const root=path.resolve(fileURLToPath(new URL('../',import.meta.url)));
|
|
71
|
+
const corpus=JSON.parse(await readFile(path.join(root,'bench','fixtures','corpus.json'),'utf8'));
|
|
72
|
+
assert.equal(corpus.schema,'deadbyte.r36-capability-corpus.v1');
|
|
73
|
+
assert.equal(corpus.suite_id,'r36-production-coding-v1');
|
|
74
|
+
assert.deepEqual(corpus.cases.map(item=>item.case_id),REQUIRED);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
test('R36 benchmark case requires reachability, evidence verification and typed release-gate result',()=>{
|
|
78
|
+
const value=normalizeR36BenchmarkCase(base);
|
|
79
|
+
assert.equal(value.capability_reachable,true);
|
|
80
|
+
assert.equal(value.evidence_verified,true);
|
|
81
|
+
assert.equal(value.release_gate_result,'not_applicable');
|
|
82
|
+
assert.throws(()=>normalizeR36BenchmarkCase({...base,capability_reachable:undefined}),/reachable/i);
|
|
83
|
+
assert.throws(()=>normalizeR36BenchmarkCase({...base,evidence_verified:undefined}),/evidence/i);
|
|
84
|
+
assert.throws(()=>normalizeR36BenchmarkCase({...base,release_gate_result:'maybe'}),/release/i);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('R36 aggregate fails closed when correctness reachability or evidence proof is missing',()=>{
|
|
88
|
+
const ok=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[base]});
|
|
89
|
+
assert.equal(ok.overall_correct,true);
|
|
90
|
+
assert.equal(ok.capability_closure,true);
|
|
91
|
+
assert.equal(ok.evidence_closure,true);
|
|
92
|
+
assert.equal('score' in ok,false);
|
|
93
|
+
const unreachable=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,capability_reachable:false}]});
|
|
94
|
+
assert.equal(unreachable.overall_correct,false);
|
|
95
|
+
assert.equal(unreachable.capability_closure,false);
|
|
96
|
+
const unverified=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,evidence_verified:false}]});
|
|
97
|
+
assert.equal(unverified.overall_correct,false);
|
|
98
|
+
assert.equal(unverified.evidence_closure,false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test('R36 verdict identity is independent of timing and byte-count noise while observation identity retains it',()=>{
|
|
102
|
+
const first=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[base]});
|
|
103
|
+
const noisy=buildR36CapabilityBenchmark({suite_id:'r36-production-coding-v1',cases:[{...base,elapsed_ms:999.25,bytes_returned:999999,evidence_sha256:H('c')}]});
|
|
104
|
+
assert.match(first.verdict_identity_sha256,/^[0-9a-f]{64}$/);
|
|
105
|
+
assert.equal(first.verdict_identity_sha256,noisy.verdict_identity_sha256);
|
|
106
|
+
assert.notEqual(first.observation_sha256,noisy.observation_sha256);
|
|
107
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import { fileURLToPath } from 'node:url';
|
|
8
|
+
import { createSemanticLspBackend } from '../src/semantic-lsp-backend.mjs';
|
|
9
|
+
|
|
10
|
+
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const serverFixture=path.join(here,'fixtures','lsp-framed-server.mjs');
|
|
12
|
+
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
13
|
+
const nodeSha=sha256(await readFile(process.execPath));
|
|
14
|
+
const fixtureSha=sha256(await readFile(serverFixture));
|
|
15
|
+
|
|
16
|
+
async function proveNavigation({extension,languageId,engineId}){
|
|
17
|
+
const root=await mkdtemp(path.join(os.tmpdir(),`deadbyte-r36-${engineId}-`));
|
|
18
|
+
const main=`main${extension}`; const peer=`peer${extension}`;
|
|
19
|
+
await writeFile(path.join(root,main),'export function main() { return alpha(); }\n','utf8');
|
|
20
|
+
await writeFile(path.join(root,peer),'export function alpha() { return 1; }\n','utf8');
|
|
21
|
+
const codingRuntime={
|
|
22
|
+
policy:{roots:{project:{real_path:root,read:true,write:true,exec:false,deny_paths:[]}}},
|
|
23
|
+
async sessionStatus(){return {armed:true,reason:'standing-grant',root_ids:['project']};},
|
|
24
|
+
async tree(){return {truncated:false,entries:[{type:'file',path:main},{type:'file',path:peer}]};},
|
|
25
|
+
async fileRead({relativePath}){const content=await readFile(path.join(root,relativePath),'utf8');return {status:'ok',content,sha256:sha256(Buffer.from(content,'utf8'))};},
|
|
26
|
+
async textReplace(){throw new Error('not used by navigation benchmark');}
|
|
27
|
+
};
|
|
28
|
+
try{
|
|
29
|
+
const backend=createSemanticLspBackend({id:engineId,extensions:[extension],codingRuntime,server:{
|
|
30
|
+
language_id:languageId,executable_path:process.execPath,executable_sha256:nodeSha,args:[serverFixture],
|
|
31
|
+
dependencies:[{path:serverFixture,expectedSha256:fixtureSha}],
|
|
32
|
+
initialization_options:{expectedLanguageId:languageId,requiredOpenCount:2},request_timeout_ms:1000,max_message_bytes:131072
|
|
33
|
+
}});
|
|
34
|
+
const definition=await backend.definition({rootId:'project',relativePath:main,line:0,column:18,maxResults:10});
|
|
35
|
+
const references=await backend.references({rootId:'project',relativePath:main,line:0,column:18,maxResults:10});
|
|
36
|
+
assert.equal(definition.engine,engineId);
|
|
37
|
+
assert.ok(definition.locations.some(item=>item.path===peer),JSON.stringify(definition.locations));
|
|
38
|
+
assert.ok(references.locations.some(item=>item.path===peer),JSON.stringify(references.locations));
|
|
39
|
+
} finally {await rm(root,{recursive:true,force:true});}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
test('R36 benchmark Python symbol navigation',async()=>{
|
|
43
|
+
await proveNavigation({extension:'.py',languageId:'python',engineId:'pyright-fixture'});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('R36 benchmark Rust symbol navigation',async()=>{
|
|
47
|
+
await proveNavigation({extension:'.rs',languageId:'rust',engineId:'rust-analyzer-fixture'});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test('R36 benchmark Cpp symbol navigation',async()=>{
|
|
51
|
+
await proveNavigation({extension:'.cpp',languageId:'cpp',engineId:'clangd-fixture'});
|
|
52
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { readFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { fileURLToPath } from 'node:url';
|
|
6
|
+
const root=path.resolve(fileURLToPath(new URL('../',import.meta.url)));
|
|
7
|
+
|
|
8
|
+
test('R36 capability evidence distinguishes documented competitor claims from direct observation and avoids blanket superiority',async()=>{
|
|
9
|
+
const file=await readFile(path.join(root,'docs','R36-CAPABILITY-EVIDENCE.md'),'utf8');
|
|
10
|
+
assert.match(file,/https:\/\/github\.com\/wonderwhy-er\/DesktopCommanderMCP/i);
|
|
11
|
+
assert.match(file,/https:\/\/github\.com\/desktop-commander\/remote-desktop-commander/i);
|
|
12
|
+
assert.match(file,/https:\/\/github\.com\/oraios\/serena/i);
|
|
13
|
+
assert.match(file,/documented/i);
|
|
14
|
+
assert.match(file,/direct_observation/i);
|
|
15
|
+
assert.match(file,/3a1d668fcc0c3c38362d0c642c5247357ed7ec6063d89b544c7a1c090521c66e/);
|
|
16
|
+
assert.doesNotMatch(file,/\b(?:best|superior|beats? all|winner|dominates?)\b/i);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
test('R36 README points to reproducible capability evidence instead of a tool-count victory claim',async()=>{
|
|
20
|
+
const file=await readFile(path.join(root,'README.txt'),'utf8');
|
|
21
|
+
assert.match(file,/R36-CAPABILITY-EVIDENCE\.md/);
|
|
22
|
+
assert.doesNotMatch(file,/\b(?:most tools|tool-count victory|beats? all|best MCP)\b/i);
|
|
23
|
+
});
|