deadbyte-mcp 0.15.16 → 0.15.18
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 +99 -96
- package/PROVENANCE.json +1 -1
- package/README.txt +6 -6
- package/RELEASE.json +1 -1
- package/SBOM.cdx.json +7 -33
- package/TEST-MATRIX.json +10 -25
- package/node_modules/@modelcontextprotocol/client/dist/{index-CHhhk6PQ.d.cts → index-BCtJi0p5.d.mts} +38 -6
- package/node_modules/@modelcontextprotocol/client/dist/index-BCtJi0p5.d.mts.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/{index-D4xIIEF6.d.mts → index-CEk3qkZM.d.cts} +41 -3
- package/node_modules/@modelcontextprotocol/client/dist/index-CEk3qkZM.d.cts.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/index.cjs +375 -60
- package/node_modules/@modelcontextprotocol/client/dist/index.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.d.cts +227 -11
- package/node_modules/@modelcontextprotocol/client/dist/index.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.d.mts +227 -11
- package/node_modules/@modelcontextprotocol/client/dist/index.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/index.mjs +369 -61
- package/node_modules/@modelcontextprotocol/client/dist/index.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.cjs +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/shimsWorkerd.mjs +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/{src-NAgB4Mp8.cjs → src-D0qEN74R.cjs} +111 -38
- package/node_modules/@modelcontextprotocol/client/dist/src-D0qEN74R.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/{src-D_zzAWoS.mjs → src-DDAAhLnO.mjs} +106 -33
- package/node_modules/@modelcontextprotocol/client/dist/src-DDAAhLnO.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/client/dist/stdio.cjs +8 -2
- package/node_modules/@modelcontextprotocol/client/dist/stdio.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/client/dist/stdio.mjs +8 -2
- package/node_modules/@modelcontextprotocol/client/dist/stdio.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/client/package.json +4 -4
- package/node_modules/@modelcontextprotocol/core/dist/{auth-BWdKR39I.d.mts → auth--n_Yzytt.d.cts} +6 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-BWdKR39I.d.mts.map → auth--n_Yzytt.d.cts.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CfDMXiII.cjs → auth-4-zilcqg.cjs} +3 -2
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CfDMXiII.cjs.map → auth-4-zilcqg.cjs.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CUe6YdwF.mjs → auth-CGP0BDVq.mjs} +3 -2
- package/node_modules/@modelcontextprotocol/core/dist/{auth-CUe6YdwF.mjs.map → auth-CGP0BDVq.mjs.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-hYtaIUZm.d.cts → auth-YUQV3RRv.d.mts} +6 -1
- package/node_modules/@modelcontextprotocol/core/dist/{auth-hYtaIUZm.d.cts.map → auth-YUQV3RRv.d.mts.map} +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.cjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/index.mjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.cjs +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.d.cts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.d.mts +1 -1
- package/node_modules/@modelcontextprotocol/core/dist/internal.mjs +1 -1
- package/node_modules/@modelcontextprotocol/core/package.json +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-dBHMsxwf.d.cts → createMcpHandler-BLVe3qmU.d.cts} +110 -7
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-BLVe3qmU.d.cts.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{createMcpHandler-CLhGwQTn.d.mts → createMcpHandler-Bt6U_Fqb.d.mts} +110 -7
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-Bt6U_Fqb.d.mts.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/index.cjs +144 -248
- package/node_modules/@modelcontextprotocol/server/dist/index.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.d.cts +38 -3
- package/node_modules/@modelcontextprotocol/server/dist/index.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.d.mts +38 -3
- package/node_modules/@modelcontextprotocol/server/dist/index.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/index.mjs +136 -243
- package/node_modules/@modelcontextprotocol/server/dist/index.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/{mcp-D7GmuPnv.cjs → mcp-DUcCQSTW.cjs} +426 -21
- package/node_modules/@modelcontextprotocol/server/dist/mcp-DUcCQSTW.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{mcp-DXXb3Vv3.mjs → mcp-Dw2OlZ1f.mjs} +367 -22
- package/node_modules/@modelcontextprotocol/server/dist/mcp-Dw2OlZ1f.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.cjs +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/shimsWorkerd.mjs +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/{src-STyD_Vvf.cjs → src-CgFsfg3E.cjs} +114 -36
- package/node_modules/@modelcontextprotocol/server/dist/src-CgFsfg3E.cjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/{src-CX2iR2pK.mjs → src-D-y6h4N7.mjs} +114 -36
- package/node_modules/@modelcontextprotocol/server/dist/src-D-y6h4N7.mjs.map +1 -0
- package/node_modules/@modelcontextprotocol/server/dist/stdio.cjs +30 -3
- package/node_modules/@modelcontextprotocol/server/dist/stdio.cjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.cts +9 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.cts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.mts +9 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.d.mts.map +1 -1
- package/node_modules/@modelcontextprotocol/server/dist/stdio.mjs +30 -3
- package/node_modules/@modelcontextprotocol/server/dist/stdio.mjs.map +1 -1
- package/node_modules/@modelcontextprotocol/server/package.json +3 -3
- package/package.json +91 -93
- package/scripts/commander-hardening-gate-r47.mjs +1 -0
- package/scripts/full-regression-r47.mjs +1 -1
- package/scripts/init-host-policy.ps1 +2 -1
- package/src/coding-plane.mjs +24 -0
- package/src/commander-core-bridge.mjs +26 -30
- package/src/commander-extended-bridge-r47.mjs +17 -0
- package/src/commander-extended-runtime.mjs +2 -1
- package/src/commander-wire-adapter-r47.mjs +341 -0
- package/src/machine-fs.mjs +6 -6
- package/src/mcp-server.mjs +13 -87
- package/src/tunnel-stdio-compat.mjs +3 -3
- package/src/version.mjs +1 -1
- package/test/commander-core-bridge-r47.test.mjs +1 -1
- package/test/commander-protocol-r47.test.mjs +17 -2
- package/test/commander-wire-contract-r47.test.mjs +143 -0
- package/test/machine-fs-runtime.test.mjs +19 -1
- package/test/r47-release-contract.test.mjs +3 -3
- package/node_modules/@modelcontextprotocol/client/dist/index-CHhhk6PQ.d.cts.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/index-D4xIIEF6.d.mts.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/src-D_zzAWoS.mjs.map +0 -1
- package/node_modules/@modelcontextprotocol/client/dist/src-NAgB4Mp8.cjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-CLhGwQTn.d.mts.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/createMcpHandler-dBHMsxwf.d.cts.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/mcp-D7GmuPnv.cjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/mcp-DXXb3Vv3.mjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/src-CX2iR2pK.mjs.map +0 -1
- package/node_modules/@modelcontextprotocol/server/dist/src-STyD_Vvf.cjs.map +0 -1
- package/node_modules/which/CHANGELOG.md +0 -166
|
@@ -1,30 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
register(server,'get_more_search_results',z.strictObject({sessionId:z.string().min(1).max(128),offset:z.number().int().default(0),length:z.number().int().min(1).max(1000).default(100)}),async({sessionId,offset,length})=>{const s=sessions.get(sessionId);if(!s)return {status:'error',error:'search session not found'};if(!s.isComplete)return {results:[],returnedCount:0,totalResults:s.results.length,totalMatches:s.totalMatches,isComplete:false,isError:false,hasMoreResults:true,runtime:Date.now()-s.startTime};const start=offset<0?Math.max(0,s.results.length+offset):offset;const end=offset<0?s.results.length:Math.min(s.results.length,start+length);const results=s.results.slice(start,end);return {results,returnedCount:results.length,totalResults:s.results.length,totalMatches:s.totalMatches,isComplete:true,isError:s.isError,error:s.error,hasMoreResults:end<s.results.length,runtime:Date.now()-s.startTime,wasIncomplete:s.wasIncomplete};});
|
|
28
|
-
register(server,'stop_search',z.strictObject({sessionId:z.string().min(1).max(128)}),async({sessionId})=>{const s=sessions.get(sessionId);if(!s)return false;s.cancelled=true;return true;});
|
|
29
|
-
register(server,'list_searches',z.strictObject({}),async()=>[...sessions.values()].map(s=>({id:s.id,searchType:s.searchType,pattern:s.pattern,isComplete:s.isComplete,isError:s.isError,runtime:Date.now()-s.startTime,totalResults:s.results.length})));
|
|
30
|
-
}
|
|
1
|
+
import { createCommanderWireAdapter } from './commander-wire-adapter-r47.mjs';
|
|
2
|
+
|
|
3
|
+
export function registerCommanderCoreBridge(
|
|
4
|
+
server,
|
|
5
|
+
{ machineFsRuntime=null, processRuntime=null, searchRuntime=null, extendedRuntime=null, includeMarkdownEditor=false }={}
|
|
6
|
+
){
|
|
7
|
+
const adapter=createCommanderWireAdapter({machineFsRuntime,processRuntime,searchRuntime,extendedRuntime});
|
|
8
|
+
const names=Object.keys(adapter.handlers);
|
|
9
|
+
for(const name of names){
|
|
10
|
+
server.registerTool(name,{
|
|
11
|
+
description:'RDC wire-compatible adapter. Requests are normalized into DEADBYTE native policy/evidence planes; no Commander runtime dependency is imported.',
|
|
12
|
+
inputSchema:adapter.schemas[name]
|
|
13
|
+
},async args=>{
|
|
14
|
+
try{return await adapter.handlers[name](args);}
|
|
15
|
+
catch(error){
|
|
16
|
+
const message=error instanceof Error?error.message:String(error);
|
|
17
|
+
return {
|
|
18
|
+
content:[{type:'text',text:`Error: ${name}: ${message}`}],
|
|
19
|
+
isError:true,
|
|
20
|
+
structuredContent:{status:'error',tool:name,error:message}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
if(includeMarkdownEditor) server.registerTool('markdown_editor',{description:'RDC markdown editor compatibility alias backed by the native edit_block transaction.',inputSchema:adapter.schemas.edit_block},async args=>adapter.handlers.edit_block(args));
|
|
26
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
|
|
3
|
+
export function registerCommanderExtendedBridge(server,{extendedRuntime,observability=null,skillPlane=null}={}){
|
|
4
|
+
if(!extendedRuntime) throw new Error('Commander extended runtime is required');
|
|
5
|
+
const reg=(name,schema,handler)=>server.registerTool(name,{description:'RDC-compatible DEADBYTE native extended surface.',inputSchema:schema},async args=>{
|
|
6
|
+
try{return await handler(args??{});}
|
|
7
|
+
catch(error){const message=error instanceof Error?error.message:String(error);return {content:[{type:'text',text:`Error: ${name}: ${message}`}],isError:true,structuredContent:{status:'error',tool:name,error:message}};}
|
|
8
|
+
});
|
|
9
|
+
reg('get_config',z.strictObject({key:z.string().optional()}),a=>extendedRuntime.getConfig(a));
|
|
10
|
+
reg('set_config_value',z.strictObject({key:z.string(),value:z.union([z.string(),z.number(),z.boolean(),z.array(z.string()),z.null()]),expected_sha256:z.string().regex(/^[0-9a-f]{64}$/)}),a=>extendedRuntime.setConfigValue(a));
|
|
11
|
+
reg('give_feedback_to_desktop_commander',z.strictObject({message:z.string(),category:z.string().optional()}),a=>extendedRuntime.feedback(a));
|
|
12
|
+
reg('get_prompts',z.strictObject({}),()=>extendedRuntime.getPrompts());
|
|
13
|
+
reg('resources',z.strictObject({}),()=>extendedRuntime.getResources());
|
|
14
|
+
reg('file_preview',z.strictObject({root_id:z.string(),path:z.string(),offset:z.number().int().min(0).optional(),max_bytes:z.number().int().min(1).max(65536).optional(),mime_type:z.string().optional()}),a=>extendedRuntime.filePreview({rootId:a.root_id,path:a.path,offset:a.offset,maxBytes:a.max_bytes,mimeType:a.mime_type}));
|
|
15
|
+
reg('get_recent_tool_calls',z.strictObject({after_sequence:z.number().int().min(0).optional(),limit:z.number().int().min(1).max(1000).optional()}),a=>observability?observability.recentToolCalls({afterSequence:a.after_sequence??0,limit:a.limit??100}):({status:'unavailable',error:'observability disabled'}));
|
|
16
|
+
reg('get_usage_stats',z.strictObject({}),()=>observability?observability.usageStats():({status:'unavailable',error:'observability disabled'}));
|
|
17
|
+
}
|
|
@@ -37,7 +37,8 @@ export function createCommanderExtendedRuntime({stateRoot,history=null,prompts=[
|
|
|
37
37
|
}
|
|
38
38
|
async function setConfigValue({key,value,expected_sha256}){
|
|
39
39
|
if(!keyOk(key))throw new Error('config key invalid');
|
|
40
|
-
|
|
40
|
+
const validValue=value===null||['string','number','boolean'].includes(typeof value)||(Array.isArray(value)&&value.every(item=>typeof item==='string'));
|
|
41
|
+
if(!validValue)throw new Error('config value must be string, number, boolean, string array, or null');
|
|
41
42
|
if(Buffer.byteLength(typeof value==='string'?value:canonicalJson(value))>MAX_VALUE)throw new Error('config value exceeds byte limit');
|
|
42
43
|
const cfg=await loadConfig(),beforeSha=sha256(cfg);
|
|
43
44
|
if(expected_sha256!==beforeSha)throw new Error('config precondition mismatch');
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
|
|
5
|
+
const sha256Bytes = bytes => createHash('sha256').update(bytes).digest('hex');
|
|
6
|
+
|
|
7
|
+
const anyRecord = z.record(z.string(), z.unknown());
|
|
8
|
+
const empty = z.strictObject({});
|
|
9
|
+
const origin = z.enum(['ui','llm']).optional();
|
|
10
|
+
|
|
11
|
+
const RDC = Object.freeze({
|
|
12
|
+
read_file: z.strictObject({
|
|
13
|
+
path:z.string(), isUrl:z.boolean().optional().default(false),
|
|
14
|
+
offset:z.number().optional().default(0), length:z.number().optional().default(1000),
|
|
15
|
+
sheet:z.string().optional(), range:z.string().optional(), options:anyRecord.optional(),
|
|
16
|
+
origin
|
|
17
|
+
}),
|
|
18
|
+
read_multiple_files:z.strictObject({paths:z.array(z.string())}),
|
|
19
|
+
write_file:z.strictObject({
|
|
20
|
+
path:z.string(), content:z.string(),
|
|
21
|
+
mode:z.enum(['rewrite','append']).default('rewrite'), origin
|
|
22
|
+
}),
|
|
23
|
+
create_directory:z.strictObject({path:z.string()}),
|
|
24
|
+
list_directory:z.strictObject({path:z.string(),depth:z.number().optional().default(2),origin}),
|
|
25
|
+
move_file:z.strictObject({source:z.string(),destination:z.string()}),
|
|
26
|
+
get_file_info:z.strictObject({path:z.string()}),
|
|
27
|
+
edit_block:z.object({
|
|
28
|
+
file_path:z.string(), old_string:z.string().optional(), new_string:z.string().optional(),
|
|
29
|
+
expected_replacements:z.number().optional().default(1), range:z.string().optional(),
|
|
30
|
+
content:z.unknown().optional(), options:anyRecord.optional(), origin
|
|
31
|
+
}),
|
|
32
|
+
start_process:z.strictObject({command:z.string(),timeout_ms:z.number(),shell:z.string().optional(),verbose_timing:z.boolean().optional(),origin}),
|
|
33
|
+
read_process_output:z.strictObject({pid:z.number(),timeout_ms:z.number().optional(),offset:z.number().optional(),length:z.number().optional(),verbose_timing:z.boolean().optional()}),
|
|
34
|
+
interact_with_process:z.strictObject({pid:z.number(),input:z.string(),timeout_ms:z.number().optional(),wait_for_prompt:z.boolean().optional(),verbose_timing:z.boolean().optional()}),
|
|
35
|
+
force_terminate:z.strictObject({pid:z.number()}),
|
|
36
|
+
list_sessions:empty,
|
|
37
|
+
list_processes:empty,
|
|
38
|
+
kill_process:z.strictObject({pid:z.number()}),
|
|
39
|
+
start_search:z.strictObject({
|
|
40
|
+
path:z.string(),pattern:z.string(),searchType:z.enum(['files','content']).default('files'),
|
|
41
|
+
filePattern:z.string().optional(),ignoreCase:z.boolean().optional().default(true),
|
|
42
|
+
maxResults:z.number().optional(),includeHidden:z.boolean().optional().default(false),
|
|
43
|
+
contextLines:z.number().optional().default(5),timeout_ms:z.number().optional(),
|
|
44
|
+
earlyTermination:z.boolean().optional(),literalSearch:z.boolean().optional().default(false),origin
|
|
45
|
+
}),
|
|
46
|
+
get_more_search_results:z.strictObject({sessionId:z.string(),offset:z.number().optional().default(0),length:z.number().optional().default(100)}),
|
|
47
|
+
stop_search:z.strictObject({sessionId:z.string()}),
|
|
48
|
+
list_searches:empty,
|
|
49
|
+
write_pdf:z.strictObject({
|
|
50
|
+
path:z.string(),
|
|
51
|
+
content:z.union([z.string(),z.array(z.union([
|
|
52
|
+
z.strictObject({type:z.literal('insert'),pageIndex:z.number(),markdown:z.string().optional(),sourcePdfPath:z.string().optional(),pdfOptions:anyRecord.optional()}),
|
|
53
|
+
z.strictObject({type:z.literal('delete'),pageIndexes:z.array(z.number())})
|
|
54
|
+
]))]),
|
|
55
|
+
outputPath:z.string().optional(),
|
|
56
|
+
options:anyRecord.optional(), origin
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
function text(text,isError=false,structuredContent){
|
|
61
|
+
const out={content:[{type:'text',text:String(text)}]};
|
|
62
|
+
if(isError) out.isError=true;
|
|
63
|
+
if(structuredContent!==undefined) out.structuredContent=structuredContent;
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
function fail(name,error){
|
|
67
|
+
const message=error instanceof Error?error.message:String(error);
|
|
68
|
+
return text(`Error: ${name}: ${message}`,true,{status:'error',tool:name,error:message});
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function rootEntries(runtime){
|
|
72
|
+
const roots=runtime?.policy?.roots??{};
|
|
73
|
+
return Object.entries(roots).map(([id,r])=>[id,path.resolve(r.real_path)]);
|
|
74
|
+
}
|
|
75
|
+
function resolveRdcPath(runtime,input){
|
|
76
|
+
if(typeof input!=='string'||!input) throw new Error('path must be a non-empty string');
|
|
77
|
+
const absolute=path.resolve(input);
|
|
78
|
+
for(const [rootId,root] of rootEntries(runtime)){
|
|
79
|
+
const relative=path.relative(root,absolute);
|
|
80
|
+
if(relative===''||(!relative.startsWith('..'+path.sep)&&relative!=='..'&&!path.isAbsolute(relative))){
|
|
81
|
+
return {rootId,relativePath:relative||'.'};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
throw new Error('path is outside all configured DEADBYTE roots');
|
|
85
|
+
}
|
|
86
|
+
function rootFor(runtime,rootId){
|
|
87
|
+
const roots=runtime?.policy?.roots??{};
|
|
88
|
+
const root=roots[rootId];
|
|
89
|
+
if(!root) throw new Error(`DEADBYTE root not found: ${rootId}`);
|
|
90
|
+
return path.resolve(root.real_path);
|
|
91
|
+
}
|
|
92
|
+
function absoluteFor(runtime,rootId,relativePath){
|
|
93
|
+
const root=rootFor(runtime,rootId);
|
|
94
|
+
return path.resolve(root,relativePath);
|
|
95
|
+
}
|
|
96
|
+
function linesFrom(bytes){
|
|
97
|
+
return Buffer.from(bytes,'base64').toString('utf8').replaceAll('\\r\\n','\\n').replaceAll('\\r','\\n').split('\\n');
|
|
98
|
+
}
|
|
99
|
+
function rdcFileResult(pathname,data){
|
|
100
|
+
return {
|
|
101
|
+
path:pathname,content:data.content,mimeType:data.mime_type,
|
|
102
|
+
isImage:data.isImage??false,isPdf:data.isPdf??false,
|
|
103
|
+
...(data.fileSha256!==undefined?{fileSha256:data.fileSha256}:{}),
|
|
104
|
+
...(data.lineOffset!==undefined?{lineOffset:data.lineOffset}:{}),
|
|
105
|
+
...(data.lineCount!==undefined?{lineCount:data.lineCount}:{})
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function richFormat(pathname){
|
|
109
|
+
const ext=path.extname(pathname).toLowerCase();
|
|
110
|
+
return {
|
|
111
|
+
'.png':'image/png','.jpg':'image/jpeg','.jpeg':'image/jpeg','.gif':'image/gif','.webp':'image/webp',
|
|
112
|
+
'.pdf':'application/pdf','.docx':'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
113
|
+
'.xlsx':'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet','.xls':'application/vnd.ms-excel','.xlsm':'application/vnd.ms-excel.sheet.macroEnabled.12'
|
|
114
|
+
}[ext]??null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function createCommanderWireAdapter({machineFsRuntime=null,processRuntime=null,searchRuntime=null,extendedRuntime=null}={}){
|
|
118
|
+
const searchSessions=new Map();
|
|
119
|
+
|
|
120
|
+
async function readFile(args){
|
|
121
|
+
if(!machineFsRuntime) throw new Error('machine filesystem runtime is disabled');
|
|
122
|
+
if(args.isUrl) throw new Error('URL reads are not available in the native DEADBYTE plane');
|
|
123
|
+
if(args.sheet!==undefined||args.range!==undefined) {
|
|
124
|
+
throw new Error('sheet/range reads require a native spreadsheet adapter; request rejected rather than silently ignored');
|
|
125
|
+
}
|
|
126
|
+
if(args.options!==undefined && Object.keys(args.options).length>0) {
|
|
127
|
+
throw new Error('read_file options require a native format adapter; unsupported options are rejected rather than silently ignored');
|
|
128
|
+
}
|
|
129
|
+
if(!Number.isInteger(args.offset??0)||args.offset<0) throw new Error('offset must be a non-negative integer');
|
|
130
|
+
if(!Number.isInteger(args.length??1000)||args.length<0) throw new Error('length must be a non-negative integer');
|
|
131
|
+
const target=resolveRdcPath(machineFsRuntime,args.path);
|
|
132
|
+
const start=args.offset??0;
|
|
133
|
+
const length=args.length??1000;
|
|
134
|
+
const raw=await machineFsRuntime.read({rootId:target.rootId,relativePath:target.relativePath,offset:0,maxBytes:Math.min(4*1024*1024,machineFsRuntime.policy.max_read_bytes??4*1024*1024),hashFile:false});
|
|
135
|
+
const fileSha256=raw.file_sha256??sha256Bytes(Buffer.from(raw.data_base64,'base64'));
|
|
136
|
+
const ext=path.extname(args.path).toLowerCase();
|
|
137
|
+
const imageMime={'.png':'image/png','.jpg':'image/jpeg','.jpeg':'image/jpeg','.gif':'image/gif','.webp':'image/webp'}[ext];
|
|
138
|
+
if(imageMime) {
|
|
139
|
+
const content=raw.data_base64;
|
|
140
|
+
return text(content,false,{path:args.path,content,mimeType:imageMime,isImage:true,isPdf:false,fileSha256});
|
|
141
|
+
}
|
|
142
|
+
if(['.xlsx','.xls','.xlsm','.pdf','.docx'].includes(ext)) {
|
|
143
|
+
throw new Error(`format ${ext} requires a native document adapter; request rejected rather than returned as plain text`);
|
|
144
|
+
}
|
|
145
|
+
const all=linesFrom(raw.data_base64);
|
|
146
|
+
const selected=all.slice(start,start+length);
|
|
147
|
+
const content=selected.join('\\n')+(start+length<all.length?'\\n':'');
|
|
148
|
+
return text(content,false,{path:args.path,content,mimeType:'text/plain',isImage:false,isPdf:false,lineOffset:start,lineCount:selected.length,fileSha256});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function readMultipleFiles(args){
|
|
152
|
+
if(!machineFsRuntime) throw new Error('machine filesystem runtime is disabled');
|
|
153
|
+
const results=[];
|
|
154
|
+
for(const pathname of args.paths){
|
|
155
|
+
try{
|
|
156
|
+
const target=resolveRdcPath(machineFsRuntime,pathname);
|
|
157
|
+
const raw=await machineFsRuntime.read({rootId:target.rootId,relativePath:target.relativePath,offset:0,maxBytes:Math.min(4*1024*1024,machineFsRuntime.policy.max_read_bytes??4*1024*1024),hashFile:false});
|
|
158
|
+
const fileSha256=raw.file_sha256??sha256Bytes(Buffer.from(raw.data_base64,'base64'));
|
|
159
|
+
const ext=path.extname(pathname).toLowerCase();
|
|
160
|
+
const mime=richFormat(pathname);
|
|
161
|
+
if(['.png','.jpg','.jpeg','.gif','.webp'].includes(ext)){
|
|
162
|
+
results.push(rdcFileResult(pathname,{content:raw.data_base64,mime_type:mime,isImage:true,isPdf:false,fileSha256}));
|
|
163
|
+
} else if(['.xlsx','.xls','.xlsm','.pdf','.docx'].includes(ext)){
|
|
164
|
+
results.push({path:pathname,error:'format '+ext+' requires a native document adapter; request rejected rather than returned as plain text'});
|
|
165
|
+
} else {
|
|
166
|
+
const content=Buffer.from(raw.data_base64,'base64').toString('utf8');
|
|
167
|
+
results.push(rdcFileResult(pathname,{content,mime_type:'text/plain',isImage:false,isPdf:false,fileSha256}));
|
|
168
|
+
}
|
|
169
|
+
}catch(error){
|
|
170
|
+
results.push({path:pathname,error:error instanceof Error?error.message:String(error)});
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return text(results.map(x=>x.error?`${x.path}: Error: ${x.error}`:`${x.path}:\\n${x.content}`).join('\\n\\n'),false,{results});
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
async function writeFile(args){
|
|
177
|
+
const target=resolveRdcPath(machineFsRuntime,args.path);
|
|
178
|
+
let expected='absent';
|
|
179
|
+
let content=args.content;
|
|
180
|
+
try{
|
|
181
|
+
const current=await machineFsRuntime.read({rootId:target.rootId,relativePath:target.relativePath,offset:0,maxBytes:Math.min(4*1024*1024,machineFsRuntime.policy.max_read_bytes??4*1024*1024),hashFile:true});
|
|
182
|
+
expected=current.file_sha256??'absent';
|
|
183
|
+
if(args.mode==='append') content=Buffer.from(current.data_base64,'base64').toString('utf8')+args.content;
|
|
184
|
+
}catch(error){
|
|
185
|
+
if(args.mode==='append' || !/not found|ENOENT/i.test(String(error))) throw error;
|
|
186
|
+
}
|
|
187
|
+
const result=await machineFsRuntime.write({rootId:target.rootId,relativePath:target.relativePath,content,encoding:'utf8',expectedSha256:expected});
|
|
188
|
+
return text(`Successfully wrote ${args.path}`,false,{path:args.path,mode:args.mode,status:'committed',...result});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
async function createDirectory(args){
|
|
192
|
+
const target=resolveRdcPath(machineFsRuntime,args.path);
|
|
193
|
+
const result=await machineFsRuntime.mkdir({rootId:target.rootId,relativePath:target.relativePath});
|
|
194
|
+
return text(`Successfully created directory ${args.path}`,false,{path:args.path,status:'committed',...result});
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async function listDirectory(args){
|
|
198
|
+
const target=resolveRdcPath(machineFsRuntime,args.path);
|
|
199
|
+
const entries=await machineFsRuntime.list({rootId:target.rootId,relativePath:target.relativePath,limit:1000,hashFiles:false});
|
|
200
|
+
const rows=entries.entries.map(e=>`${e.type==='directory'?'[DIR]':'[FILE]'} ${e.path}`);
|
|
201
|
+
return text(rows.join('\\n'),false,{path:args.path,entries:entries.entries,next_cursor:entries.next_cursor??null});
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function moveFile(args){
|
|
205
|
+
const source=resolveRdcPath(machineFsRuntime,args.source);
|
|
206
|
+
const destination=resolveRdcPath(machineFsRuntime,args.destination);
|
|
207
|
+
const info=await machineFsRuntime.stat({rootId:source.rootId,relativePath:source.relativePath,hash:true});
|
|
208
|
+
const result=await machineFsRuntime.move({rootId:source.rootId,sourcePath:source.relativePath,destinationPath:destination.relativePath,expectedSourceIdentity:info.identity_sha256});
|
|
209
|
+
return text(`Successfully moved ${args.source} to ${args.destination}`,false,{source:args.source,destination:args.destination,status:'committed',...result});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
async function getFileInfo(args){
|
|
213
|
+
const target=resolveRdcPath(machineFsRuntime,args.path);
|
|
214
|
+
const result=await machineFsRuntime.stat({rootId:target.rootId,relativePath:target.relativePath,hash:true});
|
|
215
|
+
return text(JSON.stringify(result,null,2),false,result);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
async function editBlock(args){
|
|
219
|
+
if(args.range!==undefined) throw new Error('structured range edits require a native DEADBYTE document adapter');
|
|
220
|
+
if(args.old_string===undefined||args.new_string===undefined) throw new Error('Must provide either old_string + new_string');
|
|
221
|
+
const target=resolveRdcPath(machineFsRuntime,args.file_path);
|
|
222
|
+
const raw=await machineFsRuntime.read({rootId:target.rootId,relativePath:target.relativePath,offset:0,maxBytes:Math.min(4*1024*1024,machineFsRuntime.policy.max_read_bytes??4*1024*1024),hashFile:false});
|
|
223
|
+
const fileSha256=raw.file_sha256??sha256Bytes(Buffer.from(raw.data_base64,'base64'));
|
|
224
|
+
const current=Buffer.from(raw.data_base64,'base64').toString('utf8');
|
|
225
|
+
let count=0,index=0;
|
|
226
|
+
while((index=current.indexOf(args.old_string,index))>=0){count++;index+=Math.max(1,args.old_string.length);}
|
|
227
|
+
if(count!==args.expected_replacements) throw new Error(`expected ${args.expected_replacements} replacements, found ${count}`);
|
|
228
|
+
const next=current.split(args.old_string).join(args.new_string);
|
|
229
|
+
const result=await machineFsRuntime.write({rootId:target.rootId,relativePath:target.relativePath,content:next,encoding:'utf8',expectedSha256:raw.file_sha256});
|
|
230
|
+
return text(`Successfully edited ${args.file_path}`,false,{path:args.file_path,status:'committed',replacements:count,...result});
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
function profileForCommand(){
|
|
234
|
+
const id=process.env.DEADBYTE_COMMANDER_COMPAT_PROFILE;
|
|
235
|
+
if(!id) throw new Error('RDC start_process requires DEADBYTE_COMMANDER_COMPAT_PROFILE to bind command execution to a configured profile');
|
|
236
|
+
return id;
|
|
237
|
+
}
|
|
238
|
+
function defaultProcessRoot(){
|
|
239
|
+
const id=process.env.DEADBYTE_COMMANDER_COMPAT_ROOT;
|
|
240
|
+
if(id) return id;
|
|
241
|
+
const ids=processRuntime?.policy?.roots?Object.keys(processRuntime.policy.roots):[];
|
|
242
|
+
if(ids.length===1) return ids[0];
|
|
243
|
+
throw new Error('RDC start_process requires DEADBYTE_COMMANDER_COMPAT_ROOT when multiple process roots exist');
|
|
244
|
+
}
|
|
245
|
+
const pidMap=new Map();
|
|
246
|
+
|
|
247
|
+
async function startProcess(args){
|
|
248
|
+
if(args.shell!==undefined && args.shell!==process.env.DEADBYTE_COMMANDER_COMPAT_SHELL) throw new Error('RDC shell is not silently ignored; configure DEADBYTE_COMMANDER_COMPAT_SHELL to the approved native shell');
|
|
249
|
+
const profileId=profileForCommand(),rootId=defaultProcessRoot();
|
|
250
|
+
const native=await processRuntime.start({profileId,rootId,cwd:'.',args:args.command.trim()===''?[]:args.command.trim().split(/\\s+/),timeoutMs:args.timeout_ms});
|
|
251
|
+
const compatPid=native.child_pid??0;
|
|
252
|
+
if(!Number.isInteger(compatPid)||compatPid<=0) throw new Error('native process did not expose a usable child PID');
|
|
253
|
+
pidMap.set(compatPid,native.session_id);
|
|
254
|
+
return text(`Process started with PID ${compatPid} (DEADBYTE session ${native.session_id})\\n`,false,{pid:compatPid,session_id:native.session_id});
|
|
255
|
+
}
|
|
256
|
+
function sessionForPid(pid){
|
|
257
|
+
const sessionId=pidMap.get(pid);
|
|
258
|
+
if(!sessionId) throw new Error(`unknown RDC pid ${pid}`);
|
|
259
|
+
return sessionId;
|
|
260
|
+
}
|
|
261
|
+
async function readProcessOutput(args){
|
|
262
|
+
const sessionId=sessionForPid(args.pid);
|
|
263
|
+
const native=await processRuntime.read({sessionId,offset:args.offset??0,maxBytes:262144,waitMs:args.timeout_ms??0});
|
|
264
|
+
const output=Buffer.from(native.data_base64,'base64').toString('utf8');
|
|
265
|
+
return text(output,false,{pid:args.pid,session_id:sessionId,offset:native.offset,next_offset:native.next_offset,state:native.state,exit_code:native.exit_code});
|
|
266
|
+
}
|
|
267
|
+
async function interactProcess(args){
|
|
268
|
+
const sessionId=sessionForPid(args.pid);
|
|
269
|
+
const native=await processRuntime.write({sessionId,input:args.input,appendNewline:true});
|
|
270
|
+
return text(`Input sent to process ${args.pid}`,false,{pid:args.pid,session_id:sessionId,...native});
|
|
271
|
+
}
|
|
272
|
+
async function terminateProcess(args){
|
|
273
|
+
const sessionId=sessionForPid(args.pid);
|
|
274
|
+
const native=await processRuntime.terminate({sessionId});
|
|
275
|
+
pidMap.delete(args.pid);
|
|
276
|
+
return text(`Successfully terminated process ${args.pid}`,false,{pid:args.pid,session_id:sessionId,...native});
|
|
277
|
+
}
|
|
278
|
+
async function listSessions(){
|
|
279
|
+
const native=await processRuntime.list();
|
|
280
|
+
return text(native.sessions.map(s=>`Session ${s.session_id}: state=${s.state}, profile=${s.profile_id}, root=${s.root_id}`).join('\\n'),false,{sessions:native.sessions});
|
|
281
|
+
}
|
|
282
|
+
async function listProcesses(){ return listSessions(); }
|
|
283
|
+
async function killProcess(args){ return terminateProcess(args); }
|
|
284
|
+
|
|
285
|
+
async function writePdf(args){
|
|
286
|
+
if(!extendedRuntime) throw new Error('write_pdf compatibility requires the DEADBYTE document runtime');
|
|
287
|
+
if(Array.isArray(args.content)) throw new Error('write_pdf operation arrays are wire-accepted but semantic PDF page editing is not yet implemented; request rejected rather than approximated');
|
|
288
|
+
const pdf=extendedRuntime.writePdf({text:args.content,metadata:{...args.options??{}}});
|
|
289
|
+
const targetPath=args.outputPath??args.path;
|
|
290
|
+
const target=resolveRdcPath(machineFsRuntime,targetPath);
|
|
291
|
+
let expected='absent';
|
|
292
|
+
try{
|
|
293
|
+
const current=await machineFsRuntime.read({rootId:target.rootId,relativePath:target.relativePath,offset:0,maxBytes:128*1024*1024,hashFile:true});
|
|
294
|
+
expected=current.file_sha256??'absent';
|
|
295
|
+
}catch(error){
|
|
296
|
+
if(!/not found|ENOENT/i.test(String(error))) throw error;
|
|
297
|
+
}
|
|
298
|
+
const result=await machineFsRuntime.write({rootId:target.rootId,relativePath:target.relativePath,content:pdf.bytes_base64,encoding:'base64',expectedSha256:expected});
|
|
299
|
+
return text(`Successfully wrote PDF to ${targetPath}${args.outputPath?`\\nOriginal file: ${args.path}`:''}`,false,{
|
|
300
|
+
path:args.path,outputPath:args.outputPath??null,status:'committed',mimeType:'application/pdf',bytes:pdf.bytes,bytesSha256:pdf.bytes_sha256,...result
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async function startSearch(args){
|
|
305
|
+
if(!searchRuntime) throw new Error('dedicated search runtime is disabled');
|
|
306
|
+
const id=`search-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;
|
|
307
|
+
const state={id,created:Date.now(),args,isComplete:false,isError:false,results:[],error:null};
|
|
308
|
+
searchSessions.set(id,state);
|
|
309
|
+
state.promise=(async()=>{
|
|
310
|
+
try{
|
|
311
|
+
const target=machineFsRuntime?resolveRdcPath(machineFsRuntime,args.path):{rootId:'core',relativePath:args.path};
|
|
312
|
+
const query={rootId:target.rootId,path:target.relativePath,pattern:args.pattern,target:args.searchType==='content'?'content':'path',mode:args.literalSearch?'literal':'regex',caseSensitive:!args.ignoreCase,maxResults:Math.min(Math.max(Math.trunc(args.maxResults??500),1),5000),maxFileBytes:262144,maxScanBytes:64*1024*1024,pageSize:500,cursor:null,filePattern:args.filePattern,includeHidden:args.includeHidden,contextLines:args.contextLines,earlyTermination:args.earlyTermination};
|
|
313
|
+
const r=await searchRuntime(query);
|
|
314
|
+
state.results=(r.matches??[]).map(x=>({file:x.path,line:x.line,match:x.preview,type:args.searchType==='content'?'content':'file'}));
|
|
315
|
+
state.isComplete=true;
|
|
316
|
+
}catch(error){state.isError=true;state.error=String(error?.message??error);state.isComplete=true;}
|
|
317
|
+
})();
|
|
318
|
+
return {sessionId:id,isComplete:false,isError:false,results:[],totalResults:0};
|
|
319
|
+
}
|
|
320
|
+
async function getMoreSearchResults(args){
|
|
321
|
+
const s=searchSessions.get(args.sessionId);
|
|
322
|
+
if(!s) throw new Error('search session not found');
|
|
323
|
+
if(!s.isComplete) return {results:[],returnedCount:0,totalResults:0,isComplete:false,isError:false,hasMoreResults:true};
|
|
324
|
+
const start=args.offset<0?Math.max(0,s.results.length+args.offset):args.offset;
|
|
325
|
+
const end=args.offset<0?s.results.length:Math.min(s.results.length,start+args.length);
|
|
326
|
+
const results=s.results.slice(start,end);
|
|
327
|
+
return {results,returnedCount:results.length,totalResults:s.results.length,isComplete:true,isError:s.isError,error:s.error,hasMoreResults:end<s.results.length,runtime:Date.now()-s.created};
|
|
328
|
+
}
|
|
329
|
+
async function stopSearch(args){
|
|
330
|
+
const s=searchSessions.get(args.sessionId);
|
|
331
|
+
if(!s) return false;
|
|
332
|
+
s.cancelled=true;
|
|
333
|
+
return true;
|
|
334
|
+
}
|
|
335
|
+
async function listSearches(){
|
|
336
|
+
return [...searchSessions.values()].map(s=>({id:s.id,searchType:s.args.searchType,pattern:s.args.pattern,isComplete:s.isComplete,isError:s.isError,runtime:Date.now()-s.created,totalResults:s.results.length}));
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
const handlers={read_file:readFile,read_multiple_files:readMultipleFiles,write_file:writeFile,create_directory:createDirectory,list_directory:listDirectory,move_file:moveFile,get_file_info:getFileInfo,edit_block:editBlock,write_pdf:writePdf,start_process:startProcess,read_process_output:readProcessOutput,interact_with_process:interactProcess,force_terminate:terminateProcess,list_sessions:listSessions,list_processes:listProcesses,kill_process:killProcess,start_search:startSearch,get_more_search_results:getMoreSearchResults,stop_search:stopSearch,list_searches:listSearches};
|
|
340
|
+
return Object.freeze({schemas:RDC,handlers});
|
|
341
|
+
}
|
package/src/machine-fs.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { lstat, mkdir as fsMkdir, open, readFile, readdir, realpath, rename, rm,
|
|
|
5
5
|
import path from 'node:path';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
7
|
import { canonicalJson } from './canonical-json.mjs';
|
|
8
|
-
import { assertCodingArmed, recheckCodingAuthority } from './coding-plane.mjs';
|
|
8
|
+
import { assertCodingArmed, assertCodingReadAllowed, recheckCodingAuthority, recheckCodingReadAuthority } from './coding-plane.mjs';
|
|
9
9
|
import { isInside, validatePortableRelativePath } from './path-policy.mjs';
|
|
10
10
|
import { decodeUtf8Strict } from './text-policy.mjs';
|
|
11
11
|
import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
|
|
@@ -343,7 +343,7 @@ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath,
|
|
|
343
343
|
if (!signingKeyPath || !verifyKeyPath) throw new Error('machine fs runtime requires trust key paths');
|
|
344
344
|
|
|
345
345
|
async function statPath({ rootId, relativePath = '.', hash = false }) {
|
|
346
|
-
const grant = await
|
|
346
|
+
const grant = await assertCodingReadAllowed(policy, rootId);
|
|
347
347
|
const found = await resolveExisting(policy, grant, rootId, relativePath, 'read', true);
|
|
348
348
|
const info = await lstat(found.resolved);
|
|
349
349
|
const kind = kindOf(info);
|
|
@@ -367,7 +367,7 @@ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath,
|
|
|
367
367
|
}
|
|
368
368
|
async function listPage({ rootId, relativePath = '.', cursor = null, limit = 100, hashFiles = false }) {
|
|
369
369
|
if (!Number.isInteger(limit) || limit < 1 || limit > MAX_LIST_LIMIT) throw new Error(`machine fs list limit must be in [1, ${MAX_LIST_LIMIT}]`);
|
|
370
|
-
const grant = await
|
|
370
|
+
const grant = await assertCodingReadAllowed(policy, rootId);
|
|
371
371
|
const found = await resolveExisting(policy, grant, rootId, relativePath, 'read', true);
|
|
372
372
|
const info = found.targetInfo;
|
|
373
373
|
if (!info?.isDirectory()) throw new Error('machine fs list path must be a directory');
|
|
@@ -398,18 +398,18 @@ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath,
|
|
|
398
398
|
if (!Number.isInteger(offset) || offset < -policy.max_read_bytes || offset > policy.max_read_bytes) throw new Error(`machine fs read offset must be in [-${policy.max_read_bytes}, ${policy.max_read_bytes}]`);
|
|
399
399
|
if (!Number.isInteger(maxBytes) || maxBytes < 1 || maxBytes > policy.max_read_bytes) throw new Error(`machine fs max_bytes must be in [1, ${policy.max_read_bytes}]`);
|
|
400
400
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 180000) throw new Error('machine fs read timeout_ms must be in [100, 180000]');
|
|
401
|
-
const grant = await
|
|
401
|
+
const grant = await assertCodingReadAllowed(policy, rootId);
|
|
402
402
|
const found = await resolveExisting(policy, grant, rootId, relativePath, 'read', false);
|
|
403
403
|
const info = await lstat(found.resolved);
|
|
404
404
|
if (!info.isFile()) throw new Error('machine fs read target must be a regular file');
|
|
405
405
|
const effectiveOffset = offset < 0 ? Math.max(0, info.size + offset) : offset;
|
|
406
406
|
if (effectiveOffset > info.size) throw new Error('machine fs read offset exceeds file size');
|
|
407
407
|
const length = Math.min(maxBytes, info.size - effectiveOffset);
|
|
408
|
-
await
|
|
408
|
+
await recheckCodingReadAuthority(policy, grant, rootId);
|
|
409
409
|
const worker = await boundedReadWorker({ file: found.resolved, offset: effectiveOffset, length, hashFile, timeoutMs, workerPath: readWorkerPath });
|
|
410
410
|
const buffer = Buffer.from(worker.data_base64, 'base64');
|
|
411
411
|
if (buffer.length !== worker.bytes_read || buffer.length > length) throw new Error('machine fs read worker byte count mismatch');
|
|
412
|
-
await
|
|
412
|
+
await recheckCodingReadAuthority(policy, grant, rootId);
|
|
413
413
|
return {
|
|
414
414
|
status: 'ok', root_id: rootId, path: found.relative,
|
|
415
415
|
offset: effectiveOffset, requested_offset: offset, next_offset: effectiveOffset + buffer.length, file_size: info.size,
|
package/src/mcp-server.mjs
CHANGED
|
@@ -51,6 +51,9 @@ import { registerAutonomousTools } from './autonomous-mcp-tools.mjs';
|
|
|
51
51
|
import { createToolAudit, installToolAudit } from './tool-audit.mjs';
|
|
52
52
|
import { createAuditContextProvider } from './audit-context.mjs';
|
|
53
53
|
import { registerOperatorSurface } from './operator-surface.mjs';
|
|
54
|
+
import { createOperationHistory } from './operation-history.mjs';
|
|
55
|
+
import { createCommanderObservability } from './commander-observability.mjs';
|
|
56
|
+
import { registerCommanderExtendedBridge } from './commander-extended-bridge-r47.mjs';
|
|
54
57
|
import { createCommanderExtendedRuntime } from './commander-extended-runtime.mjs';
|
|
55
58
|
import { registerCommanderCoreBridge } from './commander-core-bridge.mjs';
|
|
56
59
|
import { registerCommanderRemoteBridge } from './commander-remote-bridge-r47.mjs';
|
|
@@ -242,17 +245,13 @@ const toolAudit = auditRuntimeMode === '1' ? await createToolAudit({
|
|
|
242
245
|
const skillRoot=path.join(runtimeStateRoot,'skills');
|
|
243
246
|
await mkdir(skillRoot,{recursive:true});
|
|
244
247
|
const skillRuntime=await createSkillPlane({root:skillRoot,verifyKeyPath});
|
|
245
|
-
|
|
248
|
+
const commanderExtendedRuntime=createCommanderExtendedRuntime({stateRoot:runtimeStateRoot});
|
|
249
|
+
const commanderHistory=createOperationHistory({maxEvents:1024,maxBytes:1024*1024});
|
|
250
|
+
const commanderObservability=createCommanderObservability({history:commanderHistory});
|
|
246
251
|
const remoteRelayEndpoint=process.env.DEADBYTE_REMOTE_RELAY_ENDPOINT||process.env.DEADBYTE_REMOTE_ENDPOINT||'';
|
|
247
|
-
const
|
|
248
|
-
const remoteRelay=remoteRelayEndpoint
|
|
249
|
-
const remoteDevicePlane=remoteRelay
|
|
250
|
-
? await createRemoteDevicePlaneR44({
|
|
251
|
-
stateDir:path.join(runtimeStateRoot,'remote-device-r44'),
|
|
252
|
-
relay:remoteRelay,
|
|
253
|
-
authorizeCapability:async({capabilityId})=>remoteRelayCapabilities.has(capabilityId)
|
|
254
|
-
})
|
|
255
|
-
: null;
|
|
252
|
+
const remoteCapabilities=new Set(String(process.env.DEADBYTE_REMOTE_CAPABILITIES??'').split(',').map(x=>x.trim()).filter(Boolean));
|
|
253
|
+
const remoteRelay=remoteRelayEndpoint?await createCommanderRemoteRelayR47({endpoint:remoteRelayEndpoint}):null;
|
|
254
|
+
const remoteDevicePlane=remoteRelay?await createRemoteDevicePlaneR44({stateDir:path.join(runtimeStateRoot,'remote-device-r44'),relay:remoteRelay,authorizeCapability:async capability=>remoteCapabilities.has(capability)}):null;
|
|
256
255
|
|
|
257
256
|
installStdioConsoleGuard();
|
|
258
257
|
if (process.env.DEADBYTE_STDIO_CONSOLE_GUARD_PROBE === '1') console.log('DEADBYTE_STDIO_CONSOLE_GUARD_PROBE');
|
|
@@ -292,83 +291,9 @@ serveStdio(() => {
|
|
|
292
291
|
return server.registerTool(name,...args);
|
|
293
292
|
}};
|
|
294
293
|
registerOperatorSurface(server,{packageRoot,surfaceProfile,compactToolLimit:COMPACT_SURFACE_TOOL_LIMIT});
|
|
295
|
-
const commanderExtendedRuntime=createCommanderExtendedRuntime({
|
|
296
|
-
stateRoot:runtimeStateRoot,
|
|
297
|
-
history:null,
|
|
298
|
-
prompts:[
|
|
299
|
-
{name:'deadbyte.review',title:'Review'},
|
|
300
|
-
{name:'deadbyte.patch',title:'Patch'},
|
|
301
|
-
{name:'deadbyte.diagnose',title:'Diagnose'},
|
|
302
|
-
{name:'deadbyte.run-tests',title:'Run tests'}
|
|
303
|
-
],
|
|
304
|
-
resources:[
|
|
305
|
-
{uri:'deadbyte://context',mime_type:'text/markdown'},
|
|
306
|
-
{uri:'deadbyte://architecture',mime_type:'text/markdown'},
|
|
307
|
-
{uri:'deadbyte://surface-profile',mime_type:'application/json'}
|
|
308
|
-
]
|
|
309
|
-
});
|
|
310
294
|
if (toolAudit) installToolAudit(server,toolAudit);
|
|
311
295
|
|
|
312
296
|
if (surfaceProfile === 'full') {
|
|
313
|
-
toolServer.registerTool('get_config',{
|
|
314
|
-
description:'Read bounded DEADBYTE Commander-compatible configuration.',
|
|
315
|
-
inputSchema:z.strictObject({key:z.string().min(1).max(128).nullable().default(null)})
|
|
316
|
-
},async args=>commanderExtendedRuntime.getConfig(args));
|
|
317
|
-
|
|
318
|
-
toolServer.registerTool('set_config_value',{
|
|
319
|
-
description:'Atomically update one bounded configuration scalar with an exact hash precondition.',
|
|
320
|
-
inputSchema:z.strictObject({key:z.string().min(1).max(128),value:z.union([z.string().max(16384),z.number(),z.boolean(),z.null()]),expected_sha256:z.string().regex(/^[0-9a-f]{64}$/)})
|
|
321
|
-
},async args=>commanderExtendedRuntime.setConfigValue(args));
|
|
322
|
-
|
|
323
|
-
toolServer.registerTool('give_feedback_to_desktop_commander',{
|
|
324
|
-
description:'Persist bounded operator feedback locally; no external network transmission.',
|
|
325
|
-
inputSchema:z.strictObject({message:z.string().min(1).max(4096),category:z.string().min(1).max(64).default('general')})
|
|
326
|
-
},async args=>commanderExtendedRuntime.feedback(args));
|
|
327
|
-
|
|
328
|
-
toolServer.registerTool('get_prompts',{
|
|
329
|
-
description:'Return the bounded native prompt catalog.',
|
|
330
|
-
inputSchema:z.strictObject({})
|
|
331
|
-
},async()=>commanderExtendedRuntime.getPrompts());
|
|
332
|
-
|
|
333
|
-
toolServer.registerTool('resources',{
|
|
334
|
-
description:'Return the bounded native resource catalog.',
|
|
335
|
-
inputSchema:z.strictObject({})
|
|
336
|
-
},async()=>commanderExtendedRuntime.getResources());
|
|
337
|
-
|
|
338
|
-
toolServer.registerTool('file_preview',{
|
|
339
|
-
description:'Return a bounded preview slice from an explicitly rooted file.',
|
|
340
|
-
inputSchema:z.strictObject({root_id:z.string().min(1).max(512),path:z.string().min(1).max(512),offset:z.number().int().min(0).default(0),max_bytes:z.number().int().min(1).max(65536).default(65536),mime_type:z.string().max(128).default('text/plain')})
|
|
341
|
-
},async({root_id,path:relativePath,offset,max_bytes,mime_type})=>commanderExtendedRuntime.filePreview({rootId:root_id,path:relativePath,offset,maxBytes:max_bytes,mimeType:mime_type}));
|
|
342
|
-
|
|
343
|
-
toolServer.registerTool('write_pdf',{
|
|
344
|
-
description:'Generate a bounded self-contained PDF document from text.',
|
|
345
|
-
inputSchema:z.strictObject({text:z.string().max(65536),metadata:z.record(z.string(),z.unknown()).default({})})
|
|
346
|
-
},async args=>commanderExtendedRuntime.writePdf(args));
|
|
347
|
-
|
|
348
|
-
toolServer.registerTool('markdown_editor',{
|
|
349
|
-
description:'Hash-preconditioned bounded Markdown exact edit using the native machine filesystem transaction.',
|
|
350
|
-
inputSchema:z.strictObject({root_id:z.string().min(1).max(64),path:z.string().min(1).max(512),expected_sha256:z.string().regex(/^[0-9a-f]{64}$/),old_string:z.string().min(1).max(262144),new_string:z.string().max(524288),expected_replacements:z.number().int().min(1).max(64).default(1)})
|
|
351
|
-
},async args=>{
|
|
352
|
-
if(!machineFsRuntime) return textResult(z.any(),{status:'denied',error:'machine filesystem runtime is disabled'},true);
|
|
353
|
-
return machineFsRuntime.editExact({rootId:args.root_id,relativePath:args.path,expectedSha256:args.expected_sha256,oldString:args.old_string,newString:args.new_string,expectedReplacements:args.expected_replacements});
|
|
354
|
-
});
|
|
355
|
-
|
|
356
|
-
toolServer.registerTool('get_usage_stats',{
|
|
357
|
-
description:'Return bounded audit/runtime usage status.',
|
|
358
|
-
inputSchema:z.strictObject({})
|
|
359
|
-
},async()=>{
|
|
360
|
-
if(!toolAudit) return {status:'unavailable',reason:'audit runtime is disabled'};
|
|
361
|
-
return {status:'ok',audit:await toolAudit.status()};
|
|
362
|
-
});
|
|
363
|
-
|
|
364
|
-
toolServer.registerTool('get_recent_tool_calls',{
|
|
365
|
-
description:'Return a bounded, cursorable recent signed audit event window.',
|
|
366
|
-
inputSchema:z.strictObject({limit:z.number().int().min(1).max(256).default(50),after_seq:z.number().int().min(0).default(0)})
|
|
367
|
-
},async({limit,after_seq})=>{
|
|
368
|
-
if(!toolAudit) return {status:'unavailable',reason:'audit runtime is disabled'};
|
|
369
|
-
return {status:'ok',audit:await toolAudit.recent({limit,after_seq})};
|
|
370
|
-
});
|
|
371
|
-
|
|
372
297
|
toolServer.registerTool(
|
|
373
298
|
'workspace_open',
|
|
374
299
|
{
|
|
@@ -549,8 +474,7 @@ serveStdio(() => {
|
|
|
549
474
|
|
|
550
475
|
registerCompactGatewayTools(toolServer,{
|
|
551
476
|
profile:surfaceProfile,ledger:R36_CAPABILITY_LEDGER,codingRuntime,semanticRuntime,machineFsRuntime,
|
|
552
|
-
processRuntime,observationRuntime,machineRuntime,desktopRuntime,
|
|
553
|
-
catalogProvider:()=>[...registeredToolNames]
|
|
477
|
+
processRuntime,observationRuntime,machineRuntime,desktopRuntime,catalogProvider:()=>[...registeredToolNames]
|
|
554
478
|
});
|
|
555
479
|
|
|
556
480
|
if (hostPolicy) {
|
|
@@ -680,8 +604,10 @@ serveStdio(() => {
|
|
|
680
604
|
}
|
|
681
605
|
|
|
682
606
|
if (surfaceProfile === 'full') {
|
|
683
|
-
registerCommanderCoreBridge(toolServer,{machineFsRuntime,processRuntime,searchRuntime:codingRuntime?.search??null});
|
|
607
|
+
registerCommanderCoreBridge(toolServer,{machineFsRuntime,processRuntime,searchRuntime:codingRuntime?.search??null,extendedRuntime:commanderExtendedRuntime,includeMarkdownEditor:true});
|
|
608
|
+
registerCommanderExtendedBridge(toolServer,{extendedRuntime:commanderExtendedRuntime,observability:commanderObservability,skillPlane:skillRuntime});
|
|
684
609
|
registerCommanderRemoteBridge(toolServer,{remoteDevicePlane});
|
|
685
610
|
}
|
|
611
|
+
|
|
686
612
|
return server;
|
|
687
613
|
}, { legacy: 'reject' });
|