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.
Files changed (136) hide show
  1. package/MANIFEST.SHA256 +134 -92
  2. package/README.txt +19 -15
  3. package/bench/fixtures/corpus.json +32 -13
  4. package/bench/fixtures/r36/case-map.json +8 -0
  5. package/bin/WORKER-REGISTRY.txt +3 -3
  6. package/bin/appcontainer-stage.exe +0 -0
  7. package/bin/appcontainer-stage.obj +0 -0
  8. package/bin/bootstrap-advapi32.exe +0 -0
  9. package/bin/bootstrap-advapi32.obj +0 -0
  10. package/bin/bootstrap-exitcode.exe +0 -0
  11. package/bin/bootstrap-exitcode.obj +0 -0
  12. package/bin/bootstrap-kernel32.exe +0 -0
  13. package/bin/bootstrap-kernel32.obj +0 -0
  14. package/bin/child-control-probe.exe +0 -0
  15. package/bin/child-control-probe.obj +0 -0
  16. package/bin/child-control-stage.exe +0 -0
  17. package/bin/child-control-stage.obj +0 -0
  18. package/bin/contained-reverse-worker.exe +0 -0
  19. package/bin/contained-reverse-worker.obj +0 -0
  20. package/bin/contained-transform-worker.exe +0 -0
  21. package/bin/contained-transform-worker.obj +0 -0
  22. package/bin/containment-probe.exe +0 -0
  23. package/bin/containment-probe.obj +0 -0
  24. package/bin/deadbyte-contain.exe +0 -0
  25. package/bin/deadbyte-contain.obj +0 -0
  26. package/bin/deadbyte-exec.exe +0 -0
  27. package/bin/deadbyte-exec.obj +0 -0
  28. package/bin/deadbyte-process-host.exe +0 -0
  29. package/bin/deadbyte-process-host.obj +0 -0
  30. package/bin/deadbyte-tunnel-host.exe +0 -0
  31. package/bin/deadbyte-tunnel-host.obj +0 -0
  32. package/controller/README.TXT +8 -6
  33. package/controller/deadbyte-controller.ps1 +48 -2
  34. package/controller/deadbyte-process-policy.json +5 -5
  35. package/docs/ARCHITECTURE.md +1 -1
  36. package/docs/R36-CAPABILITY-EVIDENCE.md +43 -0
  37. package/docs/superpowers/plans/2026-09-18-r36-zero-loss-autonomy.md +739 -0
  38. package/docs/superpowers/specs/2026-09-18-r36-zero-loss-autonomy-design.md +640 -0
  39. package/package.json +1 -1
  40. package/proof/CONTAINMENT-BUILD.txt +6 -6
  41. package/scripts/deferred-slot-operation.mjs +53 -15
  42. package/scripts/final-closure-r36.mjs +113 -0
  43. package/scripts/final-closure-verify-r36.mjs +208 -0
  44. package/scripts/final-closure-verify.mjs +88 -39
  45. package/scripts/final-closure.mjs +63 -56
  46. package/scripts/gate-windows-r36.ps1 +42 -0
  47. package/scripts/gate-windows.ps1 +3 -3
  48. package/scripts/release-parity-r36.mjs +200 -0
  49. package/scripts/release-parity-tests.ps1 +9 -0
  50. package/scripts/release-parity.mjs +149 -139
  51. package/scripts/windows-gate-evidence-r36.mjs +52 -0
  52. package/scripts/windows-gate-evidence.mjs +5 -5
  53. package/src/agent-memory-plane.mjs +98 -0
  54. package/src/autonomous-context-engine.mjs +2 -1
  55. package/src/autonomous-mcp-tools.mjs +5 -1
  56. package/src/autonomous-output-contracts.mjs +9 -6
  57. package/src/autonomous-planner-contracts.mjs +36 -1
  58. package/src/autonomous-planner.mjs +25 -3
  59. package/src/autonomous-runtime.mjs +337 -43
  60. package/src/autonomous-timeout-recovery.mjs +27 -0
  61. package/src/capability-benchmark-runner.mjs +86 -1
  62. package/src/capability-benchmark.mjs +45 -0
  63. package/src/capability-ledger.mjs +158 -0
  64. package/src/coding-mcp-tools.mjs +31 -17
  65. package/src/coding-output-contracts.mjs +48 -10
  66. package/src/coding-plane.mjs +45 -9
  67. package/src/coding-search.mjs +130 -47
  68. package/src/compact-gateway-mcp-tools.mjs +128 -0
  69. package/src/compact-gateway-output-contracts.mjs +16 -0
  70. package/src/deadbyte-cli.mjs +62 -78
  71. package/src/effect-ledger.mjs +47 -0
  72. package/src/machine-fs-smoke-client.mjs +1 -1
  73. package/src/machine-fs.mjs +51 -8
  74. package/src/mcp-server.mjs +32 -9
  75. package/src/native-diff-v2.mjs +337 -0
  76. package/src/native-diff.mjs +50 -2
  77. package/src/observation-lease.mjs +32 -0
  78. package/src/observation-smoke-client.mjs +1 -1
  79. package/src/operator-surface.mjs +7 -1
  80. package/src/process-runtime.mjs +98 -11
  81. package/src/process-smoke-client.mjs +11 -3
  82. package/src/r36-compact-disarmed-probe.mjs +50 -0
  83. package/src/r36-full-surface-probe.mjs +56 -0
  84. package/src/remote-live-log.mjs +135 -0
  85. package/src/remote-mcp-autonomous-smoke-client.mjs +22 -12
  86. package/src/remote-mcp-coding-smoke-client.mjs +1 -1
  87. package/src/remote-mcp-r36-parity-client.mjs +175 -0
  88. package/src/remote-mcp-smoke-client.mjs +112 -56
  89. package/src/runtime-update.mjs +51 -1
  90. package/src/search-cursor.mjs +45 -0
  91. package/src/semantic-code.mjs +72 -5
  92. package/src/semantic-lsp-backend.mjs +39 -3
  93. package/src/version.mjs +1 -1
  94. package/src/worker-scheduler.mjs +53 -0
  95. package/test/autonomous-capability-r36.test.mjs +151 -0
  96. package/test/autonomous-output-contract.test.mjs +1 -1
  97. package/test/autonomous-runtime.test.mjs +2 -2
  98. package/test/capability-benchmark-r36.test.mjs +107 -0
  99. package/test/capability-benchmark-semantic-r36.test.mjs +52 -0
  100. package/test/capability-claims-r36.test.mjs +23 -0
  101. package/test/capability-ledger-r36.test.mjs +102 -0
  102. package/test/coding-catalog-consistency.test.mjs +2 -2
  103. package/test/coding-plane.test.mjs +2 -2
  104. package/test/coding-runtime.test.mjs +16 -0
  105. package/test/coding-search-r36.test.mjs +90 -0
  106. package/test/compact-catalog-r36.test.mjs +37 -0
  107. package/test/compact-gateway-r36.test.mjs +66 -0
  108. package/test/contained.test.mjs +1 -1
  109. package/test/core.test.mjs +1 -1
  110. package/test/deferred-slot-operation.test.mjs +9 -0
  111. package/test/fixtures/lsp-framed-server.mjs +2 -0
  112. package/test/helpers/autonomous-r34-fixture.mjs +5 -3
  113. package/test/multi-file-read.test.mjs +3 -0
  114. package/test/native-diff-topology-r36.test.mjs +105 -0
  115. package/test/package-boundary.test.mjs +6 -0
  116. package/test/process-longrun-r36.test.mjs +82 -0
  117. package/test/process-release-gate.test.mjs +9 -0
  118. package/test/production-docs.test.mjs +5 -5
  119. package/test/prompts-resources.test.mjs +7 -1
  120. package/test/r33-closeout-regression.test.mjs +4 -3
  121. package/test/r33-finalization.test.mjs +14 -9
  122. package/test/r36-finalization.test.mjs +104 -0
  123. package/test/r36-release-identity.test.mjs +45 -0
  124. package/test/r37-agent-fabric.test.mjs +92 -0
  125. package/test/r37-autonomous-timeout-recovery.test.mjs +60 -0
  126. package/test/r37-finalization.test.mjs +74 -0
  127. package/test/release-version.test.mjs +42 -33
  128. package/test/remote-live-log-r36.test.mjs +37 -0
  129. package/test/remote-live-log-r37.test.mjs +47 -0
  130. package/test/remote-live-log-recovery-r36.test.mjs +41 -0
  131. package/test/remote-r24-catalog.test.mjs +13 -0
  132. package/test/remote-session-cli.test.mjs +53 -66
  133. package/test/runtime-self-update.test.mjs +58 -1
  134. package/test/semantic-lsp-backend.test.mjs +9 -0
  135. package/test/semantic-r36-rename.test.mjs +82 -0
  136. package/deadbyte-mcp-0.8.9.tgz +0 -0
@@ -9,6 +9,7 @@ import { decodeUtf8Strict } from './text-policy.mjs';
9
9
  import { isInside, validatePortableRelativePath } from './path-policy.mjs';
10
10
  import { loadPrivateSigningKey, loadPublicVerifyKey } from './trust.mjs';
11
11
  import { createCodingSearch } from './coding-search.mjs';
12
+ import { createSearchCursorCodec } from './search-cursor.mjs';
12
13
 
13
14
  export const CODING_POLICY_SCHEMA = 'deadbyte.coding-policy.v1';
14
15
  export const CODING_LEASE_SCHEMA = 'deadbyte.coding-lease.v1';
@@ -613,18 +614,52 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
613
614
  async function statPath({ rootId, relativePath = '.', hash = false }) {
614
615
  const lease = await assertCodingArmed(policy, rootId);
615
616
  const root = getRoot(policy, rootId, 'read');
616
- let resolved = root.real_path;
617
+ let lexical = root.real_path;
617
618
  let reported = '.';
618
619
  if (relativePath !== '.') {
619
- const found = await resolveCodingExisting(policy, lease, rootId, relativePath, 'read');
620
- resolved = found.resolved;
620
+ validatePortableRelativePath(relativePath);
621
+ if (!lease.root_ids.includes(rootId)) throw new Error(`coding root '${rootId}' is outside active lease`);
622
+ assertNotDenied(root, relativePath);
623
+ lexical = path.resolve(root.real_path, relativePath);
624
+ if (!isInside(root.real_path, lexical)) throw new Error('coding stat path escapes allowed root');
621
625
  reported = relativePath.replaceAll('\\', '/');
622
626
  }
623
- const info = await lstat(resolved);
627
+ const info = await lstat(lexical);
624
628
  const type = info.isFile() ? 'file' : info.isDirectory() ? 'directory' : info.isSymbolicLink() ? 'symlink' : 'other';
625
- const digest = hash && type === 'file' ? await sha256File(resolved) : null;
626
- return { status: 'ok', root_id: rootId, path: reported, type, bytes: type === 'file' ? info.size : 0,
627
- mtime_utc: info.mtime.toISOString(), sha256: digest };
629
+ const reparseState = info.isSymbolicLink() ? 'symlink' : 'none';
630
+ if (type !== 'symlink') {
631
+ const resolved = await realpath(lexical);
632
+ if (!isInside(root.real_path, resolved) && resolved !== root.real_path) throw new Error('coding stat path resolves outside allowed root');
633
+ }
634
+ const contentSha = type === 'file' ? await sha256File(lexical) : null;
635
+ const objectIdentitySha = sha256Object({
636
+ schema:'deadbyte.coding-object-identity.v1',type,bytes:type==='file'?info.size:0,
637
+ content_sha256:contentSha,device:Number(info.dev),inode:Number(info.ino),reparse_state:reparseState
638
+ });
639
+ const result = {
640
+ status:'ok',root_id:rootId,path:reported,normalized_path:reported,type,
641
+ bytes:type==='file'?info.size:0,mtime_utc:info.mtime.toISOString(),
642
+ sha256:hash&&type==='file'?contentSha:null,reparse_state:reparseState,
643
+ object_identity_sha256:objectIdentitySha,policy_root_id:rootId
644
+ };
645
+ return {...result,observation_sha256:sha256Object({schema:'deadbyte.coding-stat-observation.v1',...result})};
646
+ }
647
+
648
+ async function filesRead({ rootId, files, maxTotalBytes = 1048576 }) {
649
+ if (!Array.isArray(files) || files.length < 1 || files.length > 32) throw new Error('coding multi-read requires 1-32 files');
650
+ if (!Number.isInteger(maxTotalBytes) || maxTotalBytes < 1 || maxTotalBytes > 2097152) throw new Error('coding multi-read max_total_bytes must be in [1, 2097152]');
651
+ const values=[]; let total=0;
652
+ for(const item of files){
653
+ if(!item||typeof item.path!=='string'||!['utf8','base64'].includes(item.encoding??'utf8')) throw new Error('coding multi-read file entry invalid');
654
+ const encoding=item.encoding??'utf8';
655
+ const read=await fileRead({rootId,relativePath:item.path,encoding});
656
+ total+=read.bytes;
657
+ if(total>maxTotalBytes) throw new Error(`coding multi-read exceeds ${maxTotalBytes} byte total limit`);
658
+ values.push({path:item.path,encoding,bytes:read.bytes,sha256:read.sha256,content:read.content});
659
+ }
660
+ const identity=values.map(item=>({path:item.path,encoding:item.encoding,bytes:item.bytes,sha256:item.sha256}));
661
+ return {status:'ok',root_id:rootId,total_bytes:total,files:values,
662
+ observation_sha256:sha256Object({schema:'deadbyte.coding-files-read-observation.v1',root_id:rootId,files:identity})};
628
663
  }
629
664
 
630
665
  async function fileState({ rootId, relativePath }) {
@@ -651,7 +686,8 @@ export function createCodingRuntime({ policy, signingKeyPath, verifyKeyPath }) {
651
686
  return verifyCodingReceiptFile(policy, verifyKeyPath, receiptId);
652
687
  }
653
688
 
654
- const search = createCodingSearch({ tree, fileRead });
655
- return Object.freeze({ policy, sessionStatus, tree, stat: statPath, search, fileRead, fileWrite, fileDelete, textReplace, commandRun, benchmarkRun, receiptVerify,
689
+ const cursorCodec = createSearchCursorCodec({ signingKeyPath, verifyKeyPath });
690
+ const search = createCodingSearch({ tree, fileRead, cursorCodec });
691
+ return Object.freeze({ policy, sessionStatus, tree, stat: statPath, search, filesRead, fileRead, fileWrite, fileDelete, textReplace, commandRun, benchmarkRun, receiptVerify,
656
692
  fileState, verifyReceiptById: receiptVerify, verifyReceiptDetailed, requestSha });
657
693
  }
@@ -1,55 +1,138 @@
1
- export function createCodingSearch({ tree, fileRead }) {
2
- if (typeof tree !== 'function' || typeof fileRead !== 'function') {
3
- throw new Error('coding search requires tree and fileRead');
1
+ import { createHash } from 'node:crypto';
2
+ import { canonicalJson } from './canonical-json.mjs';
3
+ import { decodeUtf8Strict } from './text-policy.mjs';
4
+
5
+ const sha256Object=value=>createHash('sha256').update(canonicalJson(value),'utf8').digest('hex');
6
+ const sha256Bytes=bytes=>createHash('sha256').update(bytes).digest('hex');
7
+
8
+ function validateInt(value,name,min,max){
9
+ if(!Number.isInteger(value)||value<min||value>max) throw new Error(`${name} must be in [${min}, ${max}]`);
10
+ }
11
+ function compileMatcher({pattern,mode,caseSensitive}){
12
+ if(typeof pattern!=='string'||pattern.length<1||pattern.length>256) throw new Error('coding search pattern must be 1-256 characters');
13
+ if(mode==='literal'){
14
+ const needle=caseSensitive?pattern:pattern.toLowerCase();
15
+ return {
16
+ all(text){
17
+ const haystack=caseSensitive?text:text.toLowerCase();
18
+ const out=[]; let from=0;
19
+ while(from<=haystack.length){
20
+ const index=haystack.indexOf(needle,from);
21
+ if(index<0) break;
22
+ out.push({index,length:Math.max(1,pattern.length)});
23
+ from=index+Math.max(1,pattern.length);
24
+ }
25
+ return out;
26
+ },
27
+ path(value){return (caseSensitive?value:value.toLowerCase()).includes(needle);}
28
+ };
29
+ }
30
+ if(mode!=='regex') throw new Error('coding search mode must be literal or regex');
31
+ let regex;
32
+ try{regex=new RegExp(pattern,caseSensitive?'gu':'giu');}
33
+ catch(error){throw new Error(`coding search regex invalid: ${error.message}`);}
34
+ return {
35
+ all(text){
36
+ const out=[]; regex.lastIndex=0; let match;
37
+ while((match=regex.exec(text))!==null){
38
+ out.push({index:match.index,length:Math.max(1,match[0].length)});
39
+ if(match[0].length===0) regex.lastIndex+=1;
40
+ }
41
+ return out;
42
+ },
43
+ path(value){regex.lastIndex=0;return regex.test(value);}
44
+ };
45
+ }
46
+ function lineColumn(text,index){
47
+ let line=1,column=1;
48
+ for(let i=0;i<index;i+=1){if(text.charCodeAt(i)===10){line+=1;column=1;}else column+=1;}
49
+ return {line,column};
50
+ }
51
+ function preview(text,index,length){
52
+ const start=Math.max(0,index-48); const end=Math.min(text.length,index+Math.max(length,1)+112);
53
+ return text.slice(start,end);
54
+ }
55
+ function normalizeQuery({rootId,path,target,mode,pattern,caseSensitive,maxResults,maxFileBytes,maxScanBytes,pageSize}){
56
+ return {
57
+ schema:'deadbyte.coding-search-query.v2',root_id:rootId,path,target,mode,pattern,
58
+ case_sensitive:caseSensitive,max_results:maxResults,max_file_bytes:maxFileBytes,
59
+ max_scan_bytes:maxScanBytes,page_size:pageSize
60
+ };
61
+ }
62
+
63
+ export function createCodingSearch({tree,fileRead,cursorCodec}){
64
+ if(typeof tree!=='function'||typeof fileRead!=='function'||!cursorCodec||typeof cursorCodec.encode!=='function'||typeof cursorCodec.decode!=='function'){
65
+ throw new Error('coding search requires tree, fileRead, and cursorCodec');
4
66
  }
5
67
  return async function search({
6
- rootId, path = '.', pattern, mode = 'literal', caseSensitive = false,
7
- maxResults = 200, maxFileBytes = 262144
8
- }) {
9
- if (mode !== 'literal') throw new Error('coding search mode must be literal');
10
- if (typeof pattern !== 'string' || pattern.length < 1 || pattern.length > 256) {
11
- throw new Error('coding search pattern must be 1-256 characters');
12
- }
13
- if (!Number.isInteger(maxResults) || maxResults < 1 || maxResults > 1000) {
14
- throw new Error('max_results must be in [1, 1000]');
15
- }
16
- if (!Number.isInteger(maxFileBytes) || maxFileBytes < 1 || maxFileBytes > 4 * 1024 * 1024) {
17
- throw new Error('max_file_bytes out of range');
68
+ rootId,path='.',pattern,target='content',mode='literal',caseSensitive=false,
69
+ maxResults=200,maxFileBytes=262144,maxScanBytes=4*1024*1024,pageSize=100,cursor=null
70
+ }){
71
+ if(!['content','path'].includes(target)) throw new Error('coding search target must be content or path');
72
+ validateInt(maxResults,'max_results',1,1000);
73
+ validateInt(maxFileBytes,'max_file_bytes',1,4*1024*1024);
74
+ validateInt(maxScanBytes,'max_scan_bytes',1,64*1024*1024);
75
+ validateInt(pageSize,'page_size',1,500);
76
+ const matcher=compileMatcher({pattern,mode,caseSensitive});
77
+ const query=normalizeQuery({rootId,path,target,mode,pattern,caseSensitive,maxResults,maxFileBytes,maxScanBytes,pageSize});
78
+ const querySha=sha256Object(query);
79
+ let decodedCursor=null;
80
+ if(cursor!==null){
81
+ decodedCursor=await cursorCodec.decode(cursor);
82
+ if(decodedCursor.query_sha256!==querySha) throw new Error('coding search cursor query mismatch');
18
83
  }
19
- const listed = await tree({ rootId, path, maxDepth: 12, maxEntries: 2000 });
20
- const files = listed.entries
21
- .filter(entry => entry.type === 'file' && entry.bytes <= maxFileBytes)
22
- .map(entry => entry.path)
23
- .sort((a, b) => a.localeCompare(b));
24
- const needle = caseSensitive ? pattern : pattern.toLowerCase();
25
- const matches = [];
26
- let filesScanned = 0;
27
- let bytesScanned = 0;
28
- for (const relativePath of files) {
29
- const item = await fileRead({ rootId, relativePath, encoding: 'utf8' }).catch(() => null);
30
- if (!item) continue;
31
- filesScanned += 1;
32
- bytesScanned += item.bytes;
33
- const haystack = caseSensitive ? item.content : item.content.toLowerCase();
34
- const index = haystack.indexOf(needle);
35
- if (index < 0) continue;
36
- const before = item.content.slice(0, index);
37
- const line = before.split('\n').length;
38
- const lastNewline = before.lastIndexOf('\n');
39
- const column = index - lastNewline;
40
- matches.push({
41
- path: relativePath,
42
- line,
43
- column,
44
- preview: item.content.slice(index, index + Math.min(160, pattern.length + 120))
45
- });
46
- if (matches.length >= maxResults) break;
84
+
85
+ const listed=await tree({rootId,path,maxDepth:12,maxEntries:2000});
86
+ const entries=listed.entries.filter(entry=>entry.type==='file').sort((a,b)=>a.path.localeCompare(b.path,'en'));
87
+ const matches=[]; const snapshotEntries=[];
88
+ let filesScanned=0,bytesScanned=0,binaryFilesSkipped=0;
89
+ let truncated=listed.truncated===true;
90
+ let truncationReason=listed.truncated===true?'tree_limit':null;
91
+
92
+ if(target==='path'){
93
+ for(const entry of entries){
94
+ snapshotEntries.push({path:entry.path,bytes:entry.bytes,type:'file'});
95
+ if(matcher.path(entry.path)){
96
+ matches.push({path:entry.path,line:null,column:null,preview:entry.path,file_sha256:null});
97
+ if(matches.length>=maxResults){truncated=true;truncationReason='max_results';break;}
98
+ }
99
+ }
100
+ } else {
101
+ for(const entry of entries){
102
+ if(entry.bytes>maxFileBytes) continue;
103
+ if(bytesScanned+entry.bytes>maxScanBytes){truncated=true;truncationReason='scan_byte_limit';break;}
104
+ let item;
105
+ try{item=await fileRead({rootId,relativePath:entry.path,encoding:'base64'});}catch{continue;}
106
+ const raw=Buffer.from(item.content,'base64');
107
+ filesScanned+=1; bytesScanned+=item.bytes;
108
+ const fileSha=item.sha256??sha256Bytes(raw);
109
+ snapshotEntries.push({path:entry.path,bytes:item.bytes,sha256:fileSha});
110
+ let text;
111
+ try{text=decodeUtf8Strict(raw);}catch{binaryFilesSkipped+=1;continue;}
112
+ const found=matcher.all(text);
113
+ for(const hit of found){
114
+ const lc=lineColumn(text,hit.index);
115
+ matches.push({path:entry.path,line:lc.line,column:lc.column,preview:preview(text,hit.index,hit.length),file_sha256:fileSha});
116
+ if(matches.length>=maxResults){truncated=true;truncationReason='max_results';break;}
117
+ }
118
+ if(matches.length>=maxResults) break;
119
+ }
47
120
  }
121
+
122
+ const snapshotSha=sha256Object({schema:'deadbyte.coding-search-snapshot.v2',query_sha256:querySha,entries:snapshotEntries});
123
+ if(decodedCursor&&decodedCursor.snapshot_sha256!==snapshotSha) throw new Error('coding search cursor stale snapshot mismatch');
124
+ const offset=decodedCursor?.offset??0;
125
+ if(offset>matches.length) throw new Error('coding search cursor offset exceeds retained results');
126
+ const pageMatches=matches.slice(offset,offset+pageSize);
127
+ const nextOffset=offset+pageMatches.length;
128
+ const hasMore=nextOffset<matches.length;
129
+ const nextCursor=hasMore?await cursorCodec.encode({query_sha256:querySha,snapshot_sha256:snapshotSha,offset:nextOffset}):null;
130
+ const pageSha=sha256Object({schema:'deadbyte.coding-search-page.v2',query_sha256:querySha,snapshot_sha256:snapshotSha,offset,matches:pageMatches});
48
131
  return {
49
- status: 'ok', root_id: rootId, path, pattern, mode,
50
- case_sensitive: caseSensitive, matches,
51
- files_scanned: filesScanned, bytes_scanned: bytesScanned,
52
- truncated: matches.length >= maxResults || listed.truncated
132
+ status:'ok',root_id:rootId,path,pattern,target,mode,case_sensitive:caseSensitive,
133
+ matches:pageMatches,files_scanned:filesScanned,bytes_scanned:bytesScanned,binary_files_skipped:binaryFilesSkipped,
134
+ truncated:truncated||hasMore,truncation_reason:truncationReason,query_sha256:querySha,snapshot_sha256:snapshotSha,
135
+ page_sha256:pageSha,next_cursor:nextCursor
53
136
  };
54
137
  };
55
138
  }
@@ -0,0 +1,128 @@
1
+ import * as z from 'zod/v4';
2
+ import { compactGatewayOutputSchema, compactGatewayResult } from './compact-gateway-output-contracts.mjs';
3
+
4
+ const id=z.string().regex(/^[A-Za-z0-9._-]{1,64}$/);
5
+ const rel=z.string().min(1).max(2048);
6
+ const rel512=z.string().min(1).max(512);
7
+ const hex64=z.string().regex(/^[0-9a-f]{64}$/);
8
+ const cursor=z.string().max(4096).nullable().default(null);
9
+ const nonneg=z.number().int().nonnegative();
10
+ const symbolName=z.string().regex(/^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/);
11
+
12
+ export const codingInspectInputSchema=z.discriminatedUnion('op',[
13
+ z.strictObject({op:z.literal('stat'),root_id:id,path:rel512.default('.'),hash:z.boolean().default(false)}),
14
+ z.strictObject({op:z.literal('search'),root_id:id,path:rel512.default('.'),pattern:z.string().min(1).max(256),target:z.enum(['content','path']).default('content'),mode:z.enum(['literal','regex']).default('literal'),case_sensitive:z.boolean().default(false),max_results:z.number().int().min(1).max(1000).default(200),max_file_bytes:z.number().int().min(1).max(4*1024*1024).default(262144),max_scan_bytes:z.number().int().min(1).max(64*1024*1024).default(4*1024*1024),page_size:z.number().int().min(1).max(500).default(100),cursor}),
15
+ z.strictObject({op:z.literal('files_read'),root_id:id,files:z.array(z.strictObject({path:rel512,encoding:z.enum(['utf8','base64']).default('utf8')})).min(1).max(32),max_total_bytes:z.number().int().min(1).max(2097152).default(1048576)}),
16
+ z.strictObject({op:z.literal('symbol_outline'),root_id:id,path:rel512,max_symbols:z.number().int().min(1).max(500).default(200)}),
17
+ z.strictObject({op:z.literal('symbol_definition'),root_id:id,path:rel512,line:nonneg,column:nonneg,max_results:z.number().int().min(1).max(200).default(50)}),
18
+ z.strictObject({op:z.literal('symbol_references'),root_id:id,path:rel512,line:nonneg,column:nonneg,max_results:z.number().int().min(1).max(500).default(200)}),
19
+ z.strictObject({op:z.literal('symbol_diagnostics'),root_id:id,path:rel512,max_results:z.number().int().min(1).max(500).default(200)}),
20
+ z.strictObject({op:z.literal('symbol_implementations'),root_id:id,path:rel512,line:nonneg,column:nonneg,max_results:z.number().int().min(1).max(500).default(200)}),
21
+ z.strictObject({op:z.literal('symbol_rename_preview'),root_id:id,path:rel512,line:nonneg,column:nonneg,new_name:symbolName})
22
+ ]);
23
+
24
+ export const machineFsGatewayInputSchema=z.discriminatedUnion('op',[
25
+ z.strictObject({op:z.literal('stat'),root_id:id,path:rel.default('.'),hash:z.boolean().default(false)}),
26
+ z.strictObject({op:z.literal('list'),root_id:id,path:rel.default('.'),cursor,limit:z.number().int().min(1).max(1000).default(100),hash_files:z.boolean().default(false)}),
27
+ z.strictObject({op:z.literal('read'),root_id:id,path:rel,offset:nonneg.default(0),max_bytes:z.number().int().min(1).max(4*1024*1024).default(65536),hash_file:z.boolean().default(false)}),
28
+ z.strictObject({op:z.literal('write'),root_id:id,path:rel,content:z.string().max(12*1024*1024),encoding:z.enum(['utf8','base64']).default('utf8'),expected_sha256:z.string().regex(/^(?:absent|[0-9a-f]{64})$/)}),
29
+ z.strictObject({op:z.literal('edit_exact'),root_id:id,path:rel,expected_sha256:hex64,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)}),
30
+ z.strictObject({op:z.literal('mkdir'),root_id:id,path:rel}),
31
+ z.strictObject({op:z.literal('move'),root_id:id,source_path:rel,destination_path:rel,expected_source_identity:hex64}),
32
+ z.strictObject({op:z.literal('delete'),root_id:id,path:rel,expected_source_identity:hex64})
33
+ ]);
34
+
35
+ export const processSessionGatewayInputSchema=z.discriminatedUnion('op',[
36
+ z.strictObject({op:z.literal('start'),profile_id:id,root_id:id,cwd:rel.default('.'),args:z.array(z.string().max(8192)).max(64).default([])}),
37
+ z.strictObject({op:z.literal('read'),session_id:hex64,offset:nonneg.default(0),max_bytes:z.number().int().min(1).max(262144).default(65536)}),
38
+ z.strictObject({op:z.literal('status'),session_id:hex64}),
39
+ z.strictObject({op:z.literal('list')}),
40
+ z.strictObject({op:z.literal('action'),session_id:hex64,action_id:id}),
41
+ z.strictObject({op:z.literal('terminate'),session_id:hex64})
42
+ ]);
43
+
44
+ export const machineObserveInputSchema=z.discriminatedUnion('op',[
45
+ z.strictObject({op:z.literal('machine_list')}),
46
+ z.strictObject({op:z.literal('machine_status')}),
47
+ z.strictObject({op:z.literal('machine_ping'),nonce:z.string().min(1).max(256)}),
48
+ z.strictObject({op:z.literal('search_start'),root_id:id,path:rel512.default('.'),pattern:z.string().min(1).max(256),case_sensitive:z.boolean().default(false),max_results:z.number().int().min(1).max(1000).default(200),max_files:z.number().int().min(1).max(10000).default(2000),max_bytes:z.number().int().min(1).max(64*1024*1024).default(4*1024*1024),max_file_bytes:z.number().int().min(1).max(4*1024*1024).default(262144)}),
49
+ z.strictObject({op:z.literal('search_page'),search_id:hex64,limit:z.number().int().min(1).max(500).default(100),cursor:z.string().max(512).nullable().default(null)}),
50
+ z.strictObject({op:z.literal('search_status'),search_id:hex64}),
51
+ z.strictObject({op:z.literal('search_cancel'),search_id:hex64}),
52
+ z.strictObject({op:z.literal('process_list'),limit:z.number().int().min(1).max(256).default(100),include_external:z.boolean().default(false),cursor:z.string().max(512).nullable().default(null)}),
53
+ z.strictObject({op:z.literal('system_status')})
54
+ ]);
55
+
56
+ const capabilityManifestInputSchema=z.strictObject({});
57
+
58
+ function unavailable(op,name){return compactGatewayResult({status:'unavailable',op,error:`${name} runtime unavailable`},true);}
59
+ async function invoke(op,runtime,name,call){
60
+ if(!runtime) return unavailable(op,name);
61
+ try{return compactGatewayResult({status:'ok',op,result:await call(runtime)},false);}
62
+ catch(error){return compactGatewayResult({status:'denied',op,error:String(error)},true);}
63
+ }
64
+
65
+ async function codingInspect(args,codingRuntime,semanticRuntime){
66
+ switch(args.op){
67
+ case 'stat': return invoke(args.op,codingRuntime,'coding',r=>r.stat({rootId:args.root_id,relativePath:args.path,hash:args.hash}));
68
+ case 'search': return invoke(args.op,codingRuntime,'coding',r=>r.search({rootId:args.root_id,path:args.path,pattern:args.pattern,target:args.target,mode:args.mode,caseSensitive:args.case_sensitive,maxResults:args.max_results,maxFileBytes:args.max_file_bytes,maxScanBytes:args.max_scan_bytes,pageSize:args.page_size,cursor:args.cursor}));
69
+ case 'files_read': return invoke(args.op,codingRuntime,'coding',r=>r.filesRead({rootId:args.root_id,files:args.files,maxTotalBytes:args.max_total_bytes}));
70
+ case 'symbol_outline': return invoke(args.op,semanticRuntime,'semantic',r=>r.outline({rootId:args.root_id,relativePath:args.path,maxSymbols:args.max_symbols}));
71
+ case 'symbol_definition': return invoke(args.op,semanticRuntime,'semantic',r=>r.definition({rootId:args.root_id,relativePath:args.path,line:args.line,column:args.column,maxResults:args.max_results}));
72
+ case 'symbol_references': return invoke(args.op,semanticRuntime,'semantic',r=>r.references({rootId:args.root_id,relativePath:args.path,line:args.line,column:args.column,maxResults:args.max_results}));
73
+ case 'symbol_diagnostics': return invoke(args.op,semanticRuntime,'semantic',r=>r.diagnostics({rootId:args.root_id,relativePath:args.path,maxResults:args.max_results}));
74
+ case 'symbol_implementations': return invoke(args.op,semanticRuntime,'semantic',r=>{if(typeof r.implementations!=='function') throw new Error('semantic implementations unavailable');return r.implementations({rootId:args.root_id,relativePath:args.path,line:args.line,column:args.column,maxResults:args.max_results});});
75
+ case 'symbol_rename_preview': return invoke(args.op,semanticRuntime,'semantic',r=>{if(typeof r.renamePreview!=='function') throw new Error('semantic rename preview unavailable');return r.renamePreview({rootId:args.root_id,relativePath:args.path,line:args.line,column:args.column,newName:args.new_name});});
76
+ }
77
+ }
78
+
79
+ async function machineFs(args,runtime){
80
+ const map={
81
+ stat:r=>r.stat({rootId:args.root_id,relativePath:args.path,hash:args.hash}),
82
+ list:r=>r.list({rootId:args.root_id,relativePath:args.path,cursor:args.cursor,limit:args.limit,hashFiles:args.hash_files}),
83
+ read:r=>r.read({rootId:args.root_id,relativePath:args.path,offset:args.offset,maxBytes:args.max_bytes,hashFile:args.hash_file}),
84
+ write:r=>r.write({rootId:args.root_id,relativePath:args.path,content:args.content,encoding:args.encoding,expectedSha256:args.expected_sha256}),
85
+ edit_exact:r=>r.editExact({rootId:args.root_id,relativePath:args.path,expectedSha256:args.expected_sha256,oldString:args.old_string,newString:args.new_string,expectedReplacements:args.expected_replacements}),
86
+ mkdir:r=>r.mkdir({rootId:args.root_id,relativePath:args.path}),
87
+ move:r=>r.move({rootId:args.root_id,sourcePath:args.source_path,destinationPath:args.destination_path,expectedSourceIdentity:args.expected_source_identity}),
88
+ delete:r=>r.delete({rootId:args.root_id,relativePath:args.path,expectedSourceIdentity:args.expected_source_identity})
89
+ };
90
+ return invoke(args.op,runtime,'machine_fs',map[args.op]);
91
+ }
92
+
93
+ async function processSession(args,runtime){
94
+ const map={
95
+ start:r=>r.start({profileId:args.profile_id,rootId:args.root_id,cwd:args.cwd,args:args.args}),
96
+ read:r=>r.read({sessionId:args.session_id,offset:args.offset,maxBytes:args.max_bytes}),
97
+ status:r=>r.status({sessionId:args.session_id}),
98
+ list:r=>r.list(),
99
+ action:r=>r.action({sessionId:args.session_id,actionId:args.action_id}),
100
+ terminate:r=>r.terminate({sessionId:args.session_id})
101
+ };
102
+ return invoke(args.op,runtime,'process',map[args.op]);
103
+ }
104
+
105
+ async function machineObserve(args,machineRuntime,observationRuntime){
106
+ if(args.op==='machine_list') return invoke(args.op,machineRuntime,'machine',r=>r.list());
107
+ if(args.op==='machine_status') return invoke(args.op,machineRuntime,'machine',r=>r.status());
108
+ if(args.op==='machine_ping') return invoke(args.op,machineRuntime,'machine',r=>r.ping({nonce:args.nonce}));
109
+ const map={
110
+ search_start:r=>r.searchStart({rootId:args.root_id,relativePath:args.path,pattern:args.pattern,caseSensitive:args.case_sensitive,maxResults:args.max_results,maxFiles:args.max_files,maxBytes:args.max_bytes,maxFileBytes:args.max_file_bytes}),
111
+ search_page:r=>r.searchPage({searchId:args.search_id,limit:args.limit,cursor:args.cursor}),
112
+ search_status:r=>r.searchStatus({searchId:args.search_id}),
113
+ search_cancel:r=>r.searchCancel({searchId:args.search_id}),
114
+ process_list:r=>r.processList({limit:args.limit,includeExternal:args.include_external,cursor:args.cursor}),
115
+ system_status:r=>r.systemStatus()
116
+ };
117
+ return invoke(args.op,observationRuntime,'observation',map[args.op]);
118
+ }
119
+
120
+ export function registerCompactGatewayTools(server,{profile,ledger,codingRuntime,semanticRuntime,machineFsRuntime,processRuntime,observationRuntime,machineRuntime}){
121
+ if(!server) throw new Error('compact gateway registration requires server');
122
+ if(profile!=='compact') return;
123
+ server.registerTool('capability_manifest',{description:'Read the canonical R36 capability ledger and active compact profile.',inputSchema:capabilityManifestInputSchema,outputSchema:compactGatewayOutputSchema},async()=>compactGatewayResult({status:'ok',op:'manifest',result:{schema:'deadbyte.capability-manifest.v1',profile,ledger_sha256:ledger?.ledger_sha256??null,capabilities:ledger?.entries??[]}},false));
124
+ server.registerTool('coding_inspect',{description:'Typed compact coding inspection and semantic navigation gateway. No arbitrary tool dispatch.',inputSchema:codingInspectInputSchema,outputSchema:compactGatewayOutputSchema},args=>codingInspect(args,codingRuntime,semanticRuntime));
125
+ server.registerTool('machine_fs',{description:'Typed compact machine filesystem gateway preserving root policy and mutation preconditions.',inputSchema:machineFsGatewayInputSchema,outputSchema:compactGatewayOutputSchema},args=>machineFs(args,machineFsRuntime));
126
+ server.registerTool('process_session',{description:'Typed compact DEADBYTE-owned process session gateway. No raw stdin or PID authority.',inputSchema:processSessionGatewayInputSchema,outputSchema:compactGatewayOutputSchema},args=>processSession(args,processRuntime));
127
+ server.registerTool('machine_observe',{description:'Typed compact machine identity and read-only observation gateway. Revoke is intentionally excluded.',inputSchema:machineObserveInputSchema,outputSchema:compactGatewayOutputSchema},args=>machineObserve(args,machineRuntime,observationRuntime));
128
+ }
@@ -0,0 +1,16 @@
1
+ import * as z from 'zod/v4';
2
+ import { structuredToolResult } from './output-contracts.mjs';
3
+
4
+ export const compactGatewayOutputSchema=z.strictObject({
5
+ status:z.enum(['ok','denied','failed','unavailable']),
6
+ op:z.string().min(1).max(64),
7
+ result:z.json().optional(),
8
+ error:z.string().max(4096).optional()
9
+ }).superRefine((value,ctx)=>{
10
+ if(value.status==='ok'&&value.result===undefined) ctx.addIssue({code:'custom',path:['result'],message:'result is required for status=ok'});
11
+ if(value.status!=='ok'&&value.error===undefined) ctx.addIssue({code:'custom',path:['error'],message:'error is required for non-ok status'});
12
+ });
13
+
14
+ export function compactGatewayResult(value,isError=false){
15
+ return structuredToolResult(compactGatewayOutputSchema,value,isError);
16
+ }