deadbyte-mcp 0.15.3 → 0.15.5
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 +34 -30
- package/PROVENANCE.json +3 -3
- package/README.txt +14 -14
- package/RELEASE.json +3 -3
- package/controller/README.TXT +2 -2
- package/controller/deadbyte-controller.ps1 +1 -1
- package/docs/ARCHITECTURE.md +1 -1
- package/package.json +88 -88
- package/scripts/deferred-slot-operation-r46.mjs +1 -1
- package/scripts/final-closure-r46.mjs +6 -6
- package/scripts/final-closure-verify-r46.mjs +7 -7
- package/scripts/gate-windows-r46.ps1 +4 -4
- package/scripts/release-parity-r46.mjs +4 -4
- package/scripts/windows-gate-evidence-r46.mjs +7 -7
- package/src/coding-mcp-tools.mjs +4 -4
- package/src/coding-output-contracts.mjs +2 -1
- package/src/coding-search.mjs +41 -13
- package/src/compact-gateway-mcp-tools.mjs +3 -3
- package/src/fuzzy-search-core.mjs +117 -0
- package/src/fuzzy-search-worker.mjs +8 -0
- package/src/fuzzy-search.mjs +34 -0
- package/src/machine-fs-mcp-tools.mjs +1 -1
- package/src/machine-fs-output-contracts.mjs +1 -1
- package/src/machine-fs.mjs +7 -6
- package/src/version.mjs +1 -1
- package/test/cli-entrypoint.test.mjs +3 -3
- package/test/core.test.mjs +1 -1
- package/test/full-max-catalog-r44.test.mjs +3 -1
- package/test/full-max-catalog-r45.test.mjs +3 -1
- package/test/fuzzy-search-r46.test.mjs +54 -0
- package/test/machine-fs-mcp-tools.test.mjs +2 -0
- package/test/machine-fs-runtime.test.mjs +6 -0
- package/test/production-docs.test.mjs +3 -3
- package/test/release-version.test.mjs +12 -12
- package/test/runtime-self-update.test.mjs +1 -1
|
@@ -18,7 +18,7 @@ export async function verifyFinalClosureObject(envelope,{root=packageRoot,runtim
|
|
|
18
18
|
const candidate=path.resolve(root),state=path.resolve(runtimeStateRoot);
|
|
19
19
|
insist(envelope&&typeof envelope==='object'&&!Array.isArray(envelope),'R46 closure envelope invalid');
|
|
20
20
|
insist(envelope.body?.schema==='deadbyte.r46-final-closure.v1','R46 closure schema mismatch');
|
|
21
|
-
insist(envelope.body?.version==='0.15.
|
|
21
|
+
insist(envelope.body?.version==='0.15.5'&&envelope.body?.train==='R46','R46 closure version/train mismatch');
|
|
22
22
|
insist(envelope.body?.release_label==='FILELESS POWERSHELL PRODUCT BASELINE','R46 closure label mismatch');
|
|
23
23
|
|
|
24
24
|
const bodyBytes=Buffer.from(canonicalJson(envelope.body),'utf8');
|
|
@@ -39,8 +39,8 @@ export async function verifyFinalClosureObject(envelope,{root=packageRoot,runtim
|
|
|
39
39
|
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
40
40
|
const manifestSha256=sha256(manifestBytes);
|
|
41
41
|
const pointer=JSON.parse(await readFile(path.join(state,'active-release.json'),'utf8'));
|
|
42
|
-
insist(pointer.version==='0.15.
|
|
43
|
-
insist(pointer.release_id===`v0.15.
|
|
42
|
+
insist(pointer.version==='0.15.5'&&pointer.manifest_sha256===manifestSha256,'R46 active pointer/candidate mismatch');
|
|
43
|
+
insist(pointer.release_id===`v0.15.5-${manifestSha256.slice(0,16)}`,'R46 active release id mismatch');
|
|
44
44
|
insist(envelope.body.active_pointer?.release_id===pointer.release_id&&
|
|
45
45
|
envelope.body.active_pointer?.manifest_sha256===pointer.manifest_sha256&&
|
|
46
46
|
envelope.body.active_pointer?.generation_manifest_sha256===pointer.generation_manifest_sha256,
|
|
@@ -55,12 +55,12 @@ export async function verifyFinalClosureObject(envelope,{root=packageRoot,runtim
|
|
|
55
55
|
}
|
|
56
56
|
const gate=JSON.parse(await readFile(path.resolve(gateRef.path),'utf8'));
|
|
57
57
|
const parity=JSON.parse(await readFile(path.resolve(parityRef.path),'utf8'));
|
|
58
|
-
insist(gate.schema==='deadbyte.r46-windows-gate.v1'&&gate.status==='passed'&&gate.version==='0.15.
|
|
58
|
+
insist(gate.schema==='deadbyte.r46-windows-gate.v1'&&gate.status==='passed'&&gate.version==='0.15.5','R46 gate evidence invalid');
|
|
59
59
|
insist(gate.manifest_sha256===manifestSha256,'R46 gate candidate mismatch');
|
|
60
60
|
insist(gate.parent?.release_id==='v0.15.1-d55f00b5144dc31a'&&gate.parent?.manifest_sha256==='d55f00b5144dc31a7fe39e4dc60d640a94780da6aaeca0918e87636b816d7854','R46 sealed parent identity invalid');
|
|
61
|
-
insist(gate.runtime_predecessor?.release_id==='v0.15.
|
|
61
|
+
insist(gate.runtime_predecessor?.release_id==='v0.15.5-a03a4b2cf28d31d6'&&gate.runtime_predecessor?.manifest_sha256==='a03a4b2cf28d31d633cfbb0a073d375c0f19d1b972299faacef28eec05543995','R46 reopened runtime predecessor identity invalid');
|
|
62
62
|
insist(envelope.body.runtime_predecessor?.release_id===gate.runtime_predecessor.release_id&&envelope.body.runtime_predecessor?.manifest_sha256===gate.runtime_predecessor.manifest_sha256,'R46 closure runtime predecessor mismatch');
|
|
63
|
-
insist(parity.schema==='deadbyte.r46-parity.v1'&&parity.status==='passed'&&parity.version==='0.15.
|
|
63
|
+
insist(parity.schema==='deadbyte.r46-parity.v1'&&parity.status==='passed'&&parity.version==='0.15.5','R46 parity evidence invalid');
|
|
64
64
|
insist(parity.candidate?.release_id===pointer.release_id&&
|
|
65
65
|
parity.candidate?.manifest_sha256===pointer.manifest_sha256&&
|
|
66
66
|
parity.candidate?.generation_manifest_sha256===pointer.generation_manifest_sha256,
|
|
@@ -94,7 +94,7 @@ export async function verifyFinalClosureObject(envelope,{root=packageRoot,runtim
|
|
|
94
94
|
'R46 closure retained-output ring proof invalid');
|
|
95
95
|
|
|
96
96
|
return {
|
|
97
|
-
ok:true,status:'passed',version:'0.15.
|
|
97
|
+
ok:true,status:'passed',version:'0.15.5',train:'R46',
|
|
98
98
|
release_id:pointer.release_id,
|
|
99
99
|
manifest_sha256:pointer.manifest_sha256,
|
|
100
100
|
generation_manifest_sha256:pointer.generation_manifest_sha256,
|
|
@@ -10,7 +10,7 @@ function Invoke-GateStep {
|
|
|
10
10
|
$LASTEXITCODE = 0
|
|
11
11
|
& npm.cmd @NpmArgs
|
|
12
12
|
if ($LASTEXITCODE -ne 0) {
|
|
13
|
-
throw "DEADBYTE V0.15.
|
|
13
|
+
throw "DEADBYTE V0.15.5 / R46 gate failed at $Name with exit code $LASTEXITCODE"
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
@@ -23,7 +23,7 @@ Write-Host '==== host-policy-hermetic-clean ===='
|
|
|
23
23
|
$HostPolicyPath = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot '..\controller\deadbyte-host-policy.json'))
|
|
24
24
|
Remove-Item -LiteralPath $HostPolicyPath -Force -ErrorAction SilentlyContinue
|
|
25
25
|
if (Test-Path -LiteralPath $HostPolicyPath) {
|
|
26
|
-
throw "DEADBYTE V0.15.
|
|
26
|
+
throw "DEADBYTE V0.15.5 / R46 gate could not remove machine-local Host policy before hermetic regression"
|
|
27
27
|
}
|
|
28
28
|
Write-Host 'HOST_POLICY_HERMETIC_ABSENT'
|
|
29
29
|
|
|
@@ -53,6 +53,6 @@ Write-Host '==== windows-gate-evidence ===='
|
|
|
53
53
|
$LASTEXITCODE = 0
|
|
54
54
|
& node.exe (Join-Path $PSScriptRoot 'windows-gate-evidence-r46.mjs')
|
|
55
55
|
if ($LASTEXITCODE -ne 0) {
|
|
56
|
-
throw "DEADBYTE V0.15.
|
|
56
|
+
throw "DEADBYTE V0.15.5 / R46 gate failed at windows-gate-evidence with exit code $LASTEXITCODE"
|
|
57
57
|
}
|
|
58
|
-
Write-Host '==== DEADBYTE V0.15.
|
|
58
|
+
Write-Host '==== DEADBYTE V0.15.5 / R46 FILELESS POWERSHELL WINDOWS BATCH GATE: PASS ===='
|
|
@@ -37,11 +37,11 @@ export async function runReleaseParity({
|
|
|
37
37
|
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
38
38
|
const manifestSha256=sha256(manifestBytes);
|
|
39
39
|
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
40
|
-
insist(pkg.version==='0.15.
|
|
40
|
+
insist(pkg.version==='0.15.5','R46 parity requires package version 0.15.5');
|
|
41
41
|
|
|
42
42
|
const pointer=JSON.parse(await readFile(path.join(state,'active-release.json'),'utf8'));
|
|
43
|
-
insist(pointer.version==='0.15.
|
|
44
|
-
insist(pointer.release_id===`v0.15.
|
|
43
|
+
insist(pointer.version==='0.15.5'&&pointer.manifest_sha256===manifestSha256,'R46 active pointer candidate mismatch');
|
|
44
|
+
insist(pointer.release_id===`v0.15.5-${manifestSha256.slice(0,16)}`,'R46 active release id mismatch');
|
|
45
45
|
const releaseManifest=await readFile(path.join(pointer.release_root,'MANIFEST.SHA256'));
|
|
46
46
|
insist(sha256(releaseManifest)===manifestSha256,'R46 immutable release manifest mismatch');
|
|
47
47
|
|
|
@@ -116,7 +116,7 @@ export async function runReleaseParity({
|
|
|
116
116
|
const evidence={
|
|
117
117
|
schema:'deadbyte.r46-parity.v1',
|
|
118
118
|
status:'passed',
|
|
119
|
-
version:'0.15.
|
|
119
|
+
version:'0.15.5',
|
|
120
120
|
completed_at_utc:completed.toISOString(),
|
|
121
121
|
candidate:{
|
|
122
122
|
release_id:pointer.release_id,
|
|
@@ -8,7 +8,7 @@ import { doctor } from '../src/doctor-r45.mjs';
|
|
|
8
8
|
const here=path.dirname(fileURLToPath(import.meta.url));
|
|
9
9
|
const root=path.resolve(here,'..');
|
|
10
10
|
const sha256=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
11
|
-
const marker='DEADBYTE V0.15.
|
|
11
|
+
const marker='DEADBYTE V0.15.5 / R46 FILELESS POWERSHELL WINDOWS BATCH GATE: PASS';
|
|
12
12
|
const PARENT_RELEASE_ID='v0.15.1-d55f00b5144dc31a';
|
|
13
13
|
const PARENT_MANIFEST='d55f00b5144dc31a7fe39e4dc60d640a94780da6aaeca0918e87636b816d7854';
|
|
14
14
|
const PARENT_GENERATION='00cde7bf540cc2804d679a39040d5b07193c5f8a0d49cac3b882402f8f4e6ad8';
|
|
@@ -26,18 +26,18 @@ export async function writeWindowsGateEvidence({
|
|
|
26
26
|
const manifestBytes=await readFile(path.join(candidate,'MANIFEST.SHA256'));
|
|
27
27
|
const manifestSha256=sha256(manifestBytes);
|
|
28
28
|
const pkg=JSON.parse(await readFile(path.join(candidate,'package.json'),'utf8'));
|
|
29
|
-
insist(pkg.version==='0.15.
|
|
29
|
+
insist(pkg.version==='0.15.5',`R46 Windows gate evidence requires V0.15.5, found ${pkg.version}`);
|
|
30
30
|
const release=JSON.parse(await readFile(path.join(candidate,'RELEASE.json'),'utf8'));
|
|
31
|
-
insist(release.version==='0.15.
|
|
31
|
+
insist(release.version==='0.15.5'&&release.train==='R46','R46 release metadata mismatch');
|
|
32
32
|
const active=JSON.parse(await readFile(path.join(path.resolve(stateRoot),'active-release.json'),'utf8'));
|
|
33
33
|
const originalParent=active.release_id===PARENT_RELEASE_ID&&active.manifest_sha256===PARENT_MANIFEST&&active.generation_manifest_sha256===PARENT_GENERATION;
|
|
34
34
|
const reopenedPredecessor=active.release_id===REOPENED_RUNTIME_RELEASE_ID&&active.manifest_sha256===REOPENED_RUNTIME_MANIFEST&&active.generation_manifest_sha256===REOPENED_RUNTIME_GENERATION;
|
|
35
|
-
const currentR46Predecessor=active.version==='0.15.
|
|
35
|
+
const currentR46Predecessor=active.version==='0.15.5'&&active.manifest_sha256!==manifestSha256&&/^[0-9a-f]{64}$/.test(active.generation_manifest_sha256??'');
|
|
36
36
|
insist(originalParent||reopenedPredecessor||currentR46Predecessor,'R46 runtime predecessor identity mismatch');
|
|
37
37
|
const parent={release_id:PARENT_RELEASE_ID,version:'0.15.1',manifest_sha256:PARENT_MANIFEST,generation_manifest_sha256:PARENT_GENERATION};
|
|
38
38
|
|
|
39
39
|
const doctorResult=await doctor();
|
|
40
|
-
insist(doctorResult?.status==='ok'&&doctorResult?.package_version==='0.15.
|
|
40
|
+
insist(doctorResult?.status==='ok'&&doctorResult?.package_version==='0.15.5'&&doctorResult?.manifest?.verified===true,'R46 doctor evidence invalid');
|
|
41
41
|
insist(doctorResult?.policy?.host_v2_ready===true,'R46 doctor did not verify Host policy v2');
|
|
42
42
|
|
|
43
43
|
const completed=clock();
|
|
@@ -46,7 +46,7 @@ export async function writeWindowsGateEvidence({
|
|
|
46
46
|
schema:'deadbyte.r46-windows-gate.v1',
|
|
47
47
|
status:'passed',
|
|
48
48
|
exit_code:0,
|
|
49
|
-
version:'0.15.
|
|
49
|
+
version:'0.15.5',
|
|
50
50
|
train:'R46',
|
|
51
51
|
marker,
|
|
52
52
|
completed_at_utc:completed.toISOString(),
|
|
@@ -100,7 +100,7 @@ export async function writeWindowsGateEvidence({
|
|
|
100
100
|
const existingBytes=await readFile(file);
|
|
101
101
|
const existing=JSON.parse(existingBytes.toString('utf8').replace(/^\uFEFF/,''));
|
|
102
102
|
insist(existing.schema===evidence.schema&&existing.status==='passed'&&existing.exit_code===0,'existing R46 Windows gate evidence invalid');
|
|
103
|
-
insist(existing.version==='0.15.
|
|
103
|
+
insist(existing.version==='0.15.5'&&existing.marker===marker&&existing.manifest_sha256===manifestSha256,'existing R46 Windows gate identity mismatch');
|
|
104
104
|
insist(existing.parent?.release_id===parent.release_id&&existing.parent?.manifest_sha256===parent.manifest_sha256,'existing R46 parent evidence mismatch');
|
|
105
105
|
insist(existing.runtime_predecessor?.release_id===active.release_id&&existing.runtime_predecessor?.manifest_sha256===active.manifest_sha256,'existing R46 runtime predecessor evidence mismatch');
|
|
106
106
|
return {status:'existing',path:file,sha256:sha256(existingBytes),manifest_sha256:manifestSha256,parent:existing.parent};
|
package/src/coding-mcp-tools.mjs
CHANGED
|
@@ -70,14 +70,14 @@ export function registerCodingTools(server, { codingRuntime, taskRuntime, semant
|
|
|
70
70
|
server.registerTool('coding_search', {
|
|
71
71
|
description: 'Deterministic bounded content/path search with literal or regex mode, signed cursor paging, and observed file identities.',
|
|
72
72
|
inputSchema: z.strictObject({ root_id: rootId, path: relPath.default('.'), pattern: z.string().min(1).max(256),
|
|
73
|
-
target: z.enum(['content','path']).default('content'), mode: z.enum(['literal','regex']).default('literal'), case_sensitive: z.boolean().default(false),
|
|
73
|
+
target: z.enum(['content','path']).default('content'), mode: z.enum(['literal','regex','fuzzy']).default('literal'), case_sensitive: z.boolean().default(false),
|
|
74
74
|
max_results: z.number().int().min(1).max(1000).default(200), max_file_bytes: z.number().int().min(1).max(4194304).default(262144),
|
|
75
75
|
max_scan_bytes: z.number().int().min(1).max(67108864).default(4194304), page_size: z.number().int().min(1).max(500).default(100),
|
|
76
|
-
cursor: z.string().max(8192).nullable().default(null) }),
|
|
76
|
+
cursor: z.string().max(8192).nullable().default(null), fuzzy_timeout_ms: z.number().int().min(100).max(30000).default(30000) }),
|
|
77
77
|
outputSchema: codingSearchOutputSchema
|
|
78
|
-
}, async ({ root_id, path, pattern, target, mode, case_sensitive, max_results, max_file_bytes, max_scan_bytes, page_size, cursor }) => {
|
|
78
|
+
}, async ({ root_id, path, pattern, target, mode, case_sensitive, max_results, max_file_bytes, max_scan_bytes, page_size, cursor, fuzzy_timeout_ms }) => {
|
|
79
79
|
try { return result(codingSearchOutputSchema, await codingRuntime.search({ rootId: root_id, path, pattern, target, mode, caseSensitive: case_sensitive,
|
|
80
|
-
maxResults: max_results, maxFileBytes: max_file_bytes, maxScanBytes: max_scan_bytes, pageSize: page_size, cursor })); }
|
|
80
|
+
maxResults: max_results, maxFileBytes: max_file_bytes, maxScanBytes: max_scan_bytes, pageSize: page_size, cursor, fuzzyTimeoutMs: fuzzy_timeout_ms })); }
|
|
81
81
|
catch (error) { return fail(codingSearchOutputSchema, error); }
|
|
82
82
|
});
|
|
83
83
|
|
|
@@ -92,7 +92,8 @@ export const codingSearchOutputSchema = statusContract({
|
|
|
92
92
|
pattern: z.string().min(1).max(256).optional(), target: z.enum(['content','path']).optional(),
|
|
93
93
|
mode: z.enum(['literal','regex']).optional(), case_sensitive: z.boolean().optional(),
|
|
94
94
|
matches: z.array(z.strictObject({ path: z.string().min(1).max(512), line: z.number().int().min(1).nullable(),
|
|
95
|
-
column: z.number().int().min(1).nullable(), preview: z.string().max(512), file_sha256: hex64.nullable()
|
|
95
|
+
column: z.number().int().min(1).nullable(), preview: z.string().max(512), file_sha256: hex64.nullable(),
|
|
96
|
+
distance: z.number().int().nonnegative().optional(), similarity: z.number().min(0).max(1).optional(), match_length: z.number().int().positive().optional() })).max(500).optional(),
|
|
96
97
|
files_scanned: z.number().int().min(0).optional(), bytes_scanned: z.number().int().min(0).optional(),
|
|
97
98
|
binary_files_skipped: z.number().int().min(0).optional(), truncated: z.boolean().optional(),
|
|
98
99
|
truncation_reason: z.enum(['tree_limit','scan_byte_limit','max_results']).nullable().optional(),
|
package/src/coding-search.mjs
CHANGED
|
@@ -2,6 +2,8 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import { canonicalJson } from './canonical-json.mjs';
|
|
3
3
|
import { decodeUtf8Strict } from './text-policy.mjs';
|
|
4
4
|
import { createSequenceStream } from './workload-substrate.mjs';
|
|
5
|
+
import { fuzzyIndexOf } from './fuzzy-search-core.mjs';
|
|
6
|
+
import { runFuzzySearchInWorker, FUZZY_SEARCH_TIMEOUT_MS } from './fuzzy-search.mjs';
|
|
5
7
|
|
|
6
8
|
const sha256Object=value=>createHash('sha256').update(canonicalJson(value),'utf8').digest('hex');
|
|
7
9
|
const sha256Bytes=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
@@ -53,11 +55,11 @@ function preview(text,index,length){
|
|
|
53
55
|
const start=Math.max(0,index-48); const end=Math.min(text.length,index+Math.max(length,1)+112);
|
|
54
56
|
return text.slice(start,end);
|
|
55
57
|
}
|
|
56
|
-
function normalizeQuery({rootId,path,target,mode,pattern,caseSensitive,maxResults,maxFileBytes,maxScanBytes,pageSize}){
|
|
58
|
+
function normalizeQuery({rootId,path,target,mode,pattern,caseSensitive,maxResults,maxFileBytes,maxScanBytes,pageSize,fuzzyTimeoutMs}){
|
|
57
59
|
return {
|
|
58
|
-
schema:'deadbyte.coding-search-query.
|
|
60
|
+
schema:'deadbyte.coding-search-query.v3',root_id:rootId,path,target,mode,pattern,
|
|
59
61
|
case_sensitive:caseSensitive,max_results:maxResults,max_file_bytes:maxFileBytes,
|
|
60
|
-
max_scan_bytes:maxScanBytes,page_size:pageSize
|
|
62
|
+
max_scan_bytes:maxScanBytes,page_size:pageSize,fuzzy_timeout_ms:fuzzyTimeoutMs
|
|
61
63
|
};
|
|
62
64
|
}
|
|
63
65
|
|
|
@@ -67,15 +69,18 @@ export function createCodingSearch({tree,fileRead,cursorCodec}){
|
|
|
67
69
|
}
|
|
68
70
|
return async function search({
|
|
69
71
|
rootId,path='.',pattern,target='content',mode='literal',caseSensitive=false,
|
|
70
|
-
maxResults=200,maxFileBytes=262144,maxScanBytes=4*1024*1024,pageSize=100,cursor=null
|
|
72
|
+
maxResults=200,maxFileBytes=262144,maxScanBytes=4*1024*1024,pageSize=100,cursor=null,
|
|
73
|
+
fuzzyTimeoutMs=FUZZY_SEARCH_TIMEOUT_MS
|
|
71
74
|
}){
|
|
72
75
|
if(!['content','path'].includes(target)) throw new Error('coding search target must be content or path');
|
|
76
|
+
if(!['literal','regex','fuzzy'].includes(mode)) throw new Error('coding search mode must be literal, regex, or fuzzy');
|
|
73
77
|
validateInt(maxResults,'max_results',1,1000);
|
|
74
78
|
validateInt(maxFileBytes,'max_file_bytes',1,4*1024*1024);
|
|
75
79
|
validateInt(maxScanBytes,'max_scan_bytes',1,64*1024*1024);
|
|
76
80
|
validateInt(pageSize,'page_size',1,500);
|
|
77
|
-
|
|
78
|
-
const
|
|
81
|
+
if(!Number.isInteger(fuzzyTimeoutMs)||fuzzyTimeoutMs<100||fuzzyTimeoutMs>FUZZY_SEARCH_TIMEOUT_MS) throw new Error('fuzzy_timeout_ms must be in [100, 30000]');
|
|
82
|
+
const matcher=mode==='fuzzy'?null:compileMatcher({pattern,mode,caseSensitive});
|
|
83
|
+
const query=normalizeQuery({rootId,path,target,mode,pattern,caseSensitive,maxResults,maxFileBytes,maxScanBytes,pageSize,fuzzyTimeoutMs});
|
|
79
84
|
const querySha=sha256Object(query);
|
|
80
85
|
let decodedCursor=null;
|
|
81
86
|
if(cursor!==null){
|
|
@@ -93,10 +98,18 @@ export function createCodingSearch({tree,fileRead,cursorCodec}){
|
|
|
93
98
|
if(target==='path'){
|
|
94
99
|
for(const entry of entries){
|
|
95
100
|
snapshotEntries.push({path:entry.path,bytes:entry.bytes,type:'file'});
|
|
96
|
-
|
|
97
|
-
|
|
101
|
+
const found=mode==='fuzzy'
|
|
102
|
+
? [fuzzyIndexOf(caseSensitive?entry.path:entry.path.toLowerCase(),caseSensitive?pattern:pattern.toLowerCase())]
|
|
103
|
+
: (matcher.path(entry.path)?[{start:0,end:entry.path.length,value:entry.path}]:[]);
|
|
104
|
+
for(const hit of found){
|
|
105
|
+
if(mode==='fuzzy' && hit.distance>Math.max(1,Math.floor(pattern.length*0.75))) continue;
|
|
106
|
+
matches.push({
|
|
107
|
+
path:entry.path,line:null,column:null,preview:entry.path,file_sha256:null,
|
|
108
|
+
...(mode==='fuzzy'?{distance:hit.distance,similarity:hit.similarity,match_length:Math.max(1,hit.value.length)}:{})
|
|
109
|
+
});
|
|
98
110
|
if(matches.length>=maxResults){truncated=true;truncationReason='max_results';break;}
|
|
99
111
|
}
|
|
112
|
+
if(matches.length>=maxResults) break;
|
|
100
113
|
}
|
|
101
114
|
} else {
|
|
102
115
|
for(const entry of entries){
|
|
@@ -110,11 +123,26 @@ export function createCodingSearch({tree,fileRead,cursorCodec}){
|
|
|
110
123
|
snapshotEntries.push({path:entry.path,bytes:item.bytes,sha256:fileSha});
|
|
111
124
|
let text;
|
|
112
125
|
try{text=decodeUtf8Strict(raw);}catch{binaryFilesSkipped+=1;continue;}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
126
|
+
if(mode==='fuzzy'){
|
|
127
|
+
const haystack=caseSensitive?text:text.toLowerCase();
|
|
128
|
+
const queryText=caseSensitive?pattern:pattern.toLowerCase();
|
|
129
|
+
const hit=await runFuzzySearchInWorker(haystack,queryText,fuzzyTimeoutMs);
|
|
130
|
+
const threshold=Math.max(1,Math.floor(queryText.length*0.75));
|
|
131
|
+
if(hit.distance<=threshold){
|
|
132
|
+
const lc=lineColumn(haystack,hit.start);
|
|
133
|
+
matches.push({
|
|
134
|
+
path:entry.path,line:lc.line,column:lc.column,
|
|
135
|
+
preview:preview(text,hit.start,hit.end-hit.start),file_sha256:fileSha,
|
|
136
|
+
distance:hit.distance,similarity:hit.similarity,match_length:Math.max(1,hit.value.length)
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
} else {
|
|
140
|
+
const found=matcher.all(text);
|
|
141
|
+
for(const hit of found){
|
|
142
|
+
const lc=lineColumn(text,hit.index);
|
|
143
|
+
matches.push({path:entry.path,line:lc.line,column:lc.column,preview:preview(text,hit.index,hit.length),file_sha256:fileSha});
|
|
144
|
+
if(matches.length>=maxResults){truncated=true;truncationReason='max_results';break;}
|
|
145
|
+
}
|
|
118
146
|
}
|
|
119
147
|
if(matches.length>=maxResults) break;
|
|
120
148
|
}
|
|
@@ -13,7 +13,7 @@ const symbolName=z.string().regex(/^[A-Za-z_$][A-Za-z0-9_$]{0,127}$/);
|
|
|
13
13
|
|
|
14
14
|
export const codingInspectInputSchema=z.discriminatedUnion('op',[
|
|
15
15
|
z.strictObject({op:z.literal('stat'),root_id:id,path:rel512.default('.'),hash:z.boolean().default(false)}),
|
|
16
|
-
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}),
|
|
16
|
+
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','fuzzy']).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,fuzzy_timeout_ms:z.number().int().min(100).max(30000).default(30000)}),
|
|
17
17
|
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)}),
|
|
18
18
|
z.strictObject({op:z.literal('symbol_outline'),root_id:id,path:rel512,max_symbols:z.number().int().min(1).max(500).default(200)}),
|
|
19
19
|
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)}),
|
|
@@ -26,7 +26,7 @@ export const codingInspectInputSchema=z.discriminatedUnion('op',[
|
|
|
26
26
|
export const machineFsGatewayInputSchema=z.discriminatedUnion('op',[
|
|
27
27
|
z.strictObject({op:z.literal('stat'),root_id:id,path:rel.default('.'),hash:z.boolean().default(false)}),
|
|
28
28
|
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)}),
|
|
29
|
-
z.strictObject({op:z.literal('read'),root_id:id,path:rel,offset:
|
|
29
|
+
z.strictObject({op:z.literal('read'),root_id:id,path:rel,offset:z.number().int().min(-4*1024*1024).max(4*1024*1024).default(0),max_bytes:z.number().int().min(1).max(4*1024*1024).default(65536),hash_file:z.boolean().default(false),timeout_ms:z.number().int().min(100).max(180000).default(30000)}),
|
|
30
30
|
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})$/)}),
|
|
31
31
|
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)}),
|
|
32
32
|
z.strictObject({op:z.literal('mkdir'),root_id:id,path:rel}),
|
|
@@ -69,7 +69,7 @@ async function invoke(op,runtime,name,call){
|
|
|
69
69
|
async function codingInspect(args,codingRuntime,semanticRuntime){
|
|
70
70
|
switch(args.op){
|
|
71
71
|
case 'stat': return invoke(args.op,codingRuntime,'coding',r=>r.stat({rootId:args.root_id,relativePath:args.path,hash:args.hash}));
|
|
72
|
-
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}));
|
|
72
|
+
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,fuzzyTimeoutMs:args.fuzzy_timeout_ms}));
|
|
73
73
|
case 'files_read': return invoke(args.op,codingRuntime,'coding',r=>r.filesRead({rootId:args.root_id,files:args.files,maxTotalBytes:args.max_total_bytes}));
|
|
74
74
|
case 'symbol_outline': return invoke(args.op,semanticRuntime,'semantic',r=>r.outline({rootId:args.root_id,relativePath:args.path,maxSymbols:args.max_symbols}));
|
|
75
75
|
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}));
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
const clamp=(value,min,max)=>Math.min(max,Math.max(min,value));
|
|
2
|
+
|
|
3
|
+
function boundedLevenshtein(a,b,cutoff=Number.POSITIVE_INFINITY){
|
|
4
|
+
if(a===b)return 0;
|
|
5
|
+
if(a.length===0)return b.length;
|
|
6
|
+
if(b.length===0)return a.length;
|
|
7
|
+
if(a.length>b.length){const t=a;a=b;b=t;}
|
|
8
|
+
const previous=new Uint16Array(a.length+1);
|
|
9
|
+
const current=new Uint16Array(a.length+1);
|
|
10
|
+
for(let i=0;i<=a.length;i+=1)previous[i]=i;
|
|
11
|
+
const limit=Number.isFinite(cutoff)?Math.floor(cutoff):Number.MAX_SAFE_INTEGER;
|
|
12
|
+
for(let row=1;row<=b.length;row+=1){
|
|
13
|
+
current[0]=row;
|
|
14
|
+
let rowMin=current[0];
|
|
15
|
+
const ch=b.charCodeAt(row-1);
|
|
16
|
+
for(let col=1;col<=a.length;col+=1){
|
|
17
|
+
const cost=a.charCodeAt(col-1)===ch?0:1;
|
|
18
|
+
const value=Math.min(current[col-1]+1,previous[col]+1,previous[col-1]+cost);
|
|
19
|
+
current[col]=value;
|
|
20
|
+
if(value<rowMin)rowMin=value;
|
|
21
|
+
}
|
|
22
|
+
if(rowMin>limit)return limit+1;
|
|
23
|
+
previous.set(current);
|
|
24
|
+
}
|
|
25
|
+
return previous[a.length];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function cheapPositionalScore(text,query,start,length){
|
|
29
|
+
const overlap=Math.min(length,query.length);
|
|
30
|
+
if(overlap<=0)return -1;
|
|
31
|
+
let same=0;
|
|
32
|
+
for(let i=0;i<overlap;i+=1)if(text.charCodeAt(start+i)===query.charCodeAt(i))same+=1;
|
|
33
|
+
const lengthPenalty=Math.abs(length-query.length)/Math.max(1,query.length);
|
|
34
|
+
return (same/overlap)-lengthPenalty*0.20;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function candidateLengths(queryLength,textLength){
|
|
38
|
+
if(textLength<=queryLength)return [textLength];
|
|
39
|
+
const delta=clamp(Math.floor(queryLength*0.25),2,32);
|
|
40
|
+
return [...new Set([
|
|
41
|
+
Math.max(1,queryLength-delta),
|
|
42
|
+
queryLength,
|
|
43
|
+
Math.min(textLength,queryLength+delta)
|
|
44
|
+
])];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function fuzzyIndexOf(text,query){
|
|
48
|
+
if(typeof text!=='string'||typeof query!=='string')throw new Error('fuzzy search requires text and query strings');
|
|
49
|
+
if(query.length===0)return {start:0,end:0,value:'',distance:0,similarity:1};
|
|
50
|
+
if(text.length===0)return {start:0,end:0,value:'',distance:query.length,similarity:0};
|
|
51
|
+
|
|
52
|
+
const lengths=candidateLengths(query.length,text.length);
|
|
53
|
+
const stride=query.length<=32?1:Math.max(1,Math.floor(query.length/4));
|
|
54
|
+
const ranked=[];
|
|
55
|
+
const seen=new Set();
|
|
56
|
+
for(let start=0;start<text.length;start+=stride){
|
|
57
|
+
for(const length of lengths){
|
|
58
|
+
if(start+length>text.length)continue;
|
|
59
|
+
const key=`${start}:${length}`;
|
|
60
|
+
if(seen.has(key))continue;
|
|
61
|
+
seen.add(key);
|
|
62
|
+
ranked.push({start,length,score:cheapPositionalScore(text,query,start,length)});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
const tailStart=Math.max(0,text.length-query.length);
|
|
66
|
+
for(const start of [0,tailStart]){
|
|
67
|
+
for(const length of lengths){
|
|
68
|
+
if(start<0||start+length>text.length)continue;
|
|
69
|
+
const key=`${start}:${length}`;
|
|
70
|
+
if(seen.has(key))continue;
|
|
71
|
+
seen.add(key);
|
|
72
|
+
ranked.push({start,length,score:cheapPositionalScore(text,query,start,length)});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
ranked.sort((a,b)=>b.score-a.score||a.start-b.start||a.length-b.length);
|
|
77
|
+
const shortlist=ranked.slice(0,64);
|
|
78
|
+
const refined=new Set();
|
|
79
|
+
for(const item of shortlist){
|
|
80
|
+
const radius=Math.max(1,Math.floor(stride/2));
|
|
81
|
+
for(let delta=-radius;delta<=radius;delta+=1){
|
|
82
|
+
const start=item.start+delta;
|
|
83
|
+
if(start<0||start>=text.length)continue;
|
|
84
|
+
for(const length of lengths){
|
|
85
|
+
if(start+length>text.length)continue;
|
|
86
|
+
refined.add(`${start}:${length}`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
if(refined.size===0)refined.add(`0:${Math.min(text.length,query.length)}`);
|
|
91
|
+
|
|
92
|
+
let best=null;
|
|
93
|
+
for(const key of refined){
|
|
94
|
+
const [startText,lengthText]=key.split(':');
|
|
95
|
+
const start=Number(startText);
|
|
96
|
+
const length=Number(lengthText);
|
|
97
|
+
const value=text.slice(start,start+length);
|
|
98
|
+
const cutoff=best?.distance??Number.POSITIVE_INFINITY;
|
|
99
|
+
const distance=boundedLevenshtein(value,query,cutoff);
|
|
100
|
+
if(best&&distance>best.distance)continue;
|
|
101
|
+
const similarity=1-(distance/Math.max(query.length,value.length));
|
|
102
|
+
const candidate={start,end:start+value.length,value,distance,similarity};
|
|
103
|
+
if(!best||
|
|
104
|
+
candidate.distance<best.distance||
|
|
105
|
+
(candidate.distance===best.distance&&candidate.similarity>best.similarity)||
|
|
106
|
+
(candidate.distance===best.distance&&candidate.similarity===best.similarity&&candidate.start<best.start)){
|
|
107
|
+
best=candidate;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return best??{start:0,end:Math.min(text.length,query.length),value:text.slice(0,query.length),
|
|
111
|
+
distance:boundedLevenshtein(text.slice(0,query.length),query),similarity:0};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function getSimilarityRatio(a,b){
|
|
115
|
+
if(a.length===0&&b.length===0)return 1;
|
|
116
|
+
return 1-(boundedLevenshtein(a,b)/Math.max(a.length,b.length));
|
|
117
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { parentPort, workerData } from 'node:worker_threads';
|
|
2
|
+
import { fuzzyIndexOf } from './fuzzy-search-core.mjs';
|
|
3
|
+
|
|
4
|
+
try {
|
|
5
|
+
parentPort.postMessage({ ok:true, result:fuzzyIndexOf(workerData.text,workerData.query) });
|
|
6
|
+
} catch (error) {
|
|
7
|
+
parentPort.postMessage({ ok:false, error:String(error?.stack??error) });
|
|
8
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { Worker } from 'node:worker_threads';
|
|
2
|
+
|
|
3
|
+
export const FUZZY_SEARCH_TIMEOUT_MS=30000;
|
|
4
|
+
const WORKER_URL=new URL('./fuzzy-search-worker.mjs',import.meta.url);
|
|
5
|
+
|
|
6
|
+
export function runFuzzySearchInWorker(text,query,timeoutMs=FUZZY_SEARCH_TIMEOUT_MS){
|
|
7
|
+
if(!Number.isInteger(timeoutMs)||timeoutMs<100||timeoutMs>FUZZY_SEARCH_TIMEOUT_MS)throw new Error('fuzzy timeout_ms must be in [100, 30000]');
|
|
8
|
+
return new Promise((resolve,reject)=>{
|
|
9
|
+
const worker=new Worker(WORKER_URL,{type:'module',workerData:{text,query},execArgv:[]});
|
|
10
|
+
worker.unref?.();
|
|
11
|
+
let settled=false;
|
|
12
|
+
let timer;
|
|
13
|
+
const finish=(fn,value)=>{
|
|
14
|
+
if(settled)return;
|
|
15
|
+
settled=true;
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
fn(value);
|
|
18
|
+
};
|
|
19
|
+
timer=setTimeout(()=>{
|
|
20
|
+
worker.terminate().catch(()=>{});
|
|
21
|
+
finish(reject,new Error(`fuzzy search timed out after ${timeoutMs}ms`));
|
|
22
|
+
},timeoutMs);
|
|
23
|
+
timer.unref?.();
|
|
24
|
+
worker.once('message',message=>{
|
|
25
|
+
if(message?.ok)finish(resolve,message.result);
|
|
26
|
+
else finish(reject,new Error(`fuzzy search worker failed: ${String(message?.error??'unknown error')}`));
|
|
27
|
+
worker.terminate().catch(()=>{});
|
|
28
|
+
});
|
|
29
|
+
worker.once('error',error=>finish(reject,error));
|
|
30
|
+
worker.once('exit',code=>{
|
|
31
|
+
if(code!==0)finish(reject,new Error(`fuzzy search worker exited with code ${code}`));
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -32,7 +32,7 @@ export function registerMachineFsTools(server, { runtime }) {
|
|
|
32
32
|
});
|
|
33
33
|
server.registerTool('machine_fs_read', {
|
|
34
34
|
description:'Read one bounded byte range from a root-relative regular file.',
|
|
35
|
-
inputSchema:z.strictObject({ root_id:id, path:rel, offset:z.number().int().
|
|
35
|
+
inputSchema:z.strictObject({ root_id:id, path:rel, offset:z.number().int().min(-4*1024*1024).max(4*1024*1024).default(0), max_bytes:z.number().int().min(1).max(4*1024*1024).default(65536), hash_file:z.boolean().default(false), timeout_ms:z.number().int().min(100).max(180000).default(30000) }),
|
|
36
36
|
outputSchema:machineFsReadOutputSchema
|
|
37
37
|
}, async ({root_id,path,offset,max_bytes,hash_file,timeout_ms}) => {
|
|
38
38
|
try { return ok(machineFsReadOutputSchema, await runtime.read({rootId:root_id,relativePath:path,offset,maxBytes:max_bytes,hashFile:hash_file,timeoutMs:timeout_ms})); }
|
|
@@ -30,7 +30,7 @@ export const machineFsListOutputSchema = z.strictObject({
|
|
|
30
30
|
export const machineFsReadOutputSchema = z.strictObject({
|
|
31
31
|
status: statusOk, error,
|
|
32
32
|
root_id: z.string().min(1).max(64).optional(), path: pathText.optional(),
|
|
33
|
-
offset: z.number().int().nonnegative().optional(), next_offset: z.number().int().nonnegative().optional(),
|
|
33
|
+
offset: z.number().int().nonnegative().optional(), requested_offset: z.number().int().optional(), next_offset: z.number().int().nonnegative().optional(),
|
|
34
34
|
file_size: z.number().int().nonnegative().optional(), eof: z.boolean().optional(),
|
|
35
35
|
data_base64: z.string().max(12 * 1024 * 1024).optional(), data_sha256: hex64.optional(),
|
|
36
36
|
file_sha256: hex64.nullable().optional(), timeout_ms: z.number().int().min(100).max(180000).optional()
|
package/src/machine-fs.mjs
CHANGED
|
@@ -324,24 +324,25 @@ export function createMachineFsRuntime({ policy, signingKeyPath, verifyKeyPath,
|
|
|
324
324
|
return { status: 'ok', root_id: rootId, path: found.relative, entries, next_cursor: nextCursor };
|
|
325
325
|
}
|
|
326
326
|
async function readRange({ rootId, relativePath, offset = 0, maxBytes = 65536, hashFile = false, timeoutMs = 30000 }) {
|
|
327
|
-
if (!Number.isInteger(offset) || offset <
|
|
327
|
+
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}]`);
|
|
328
328
|
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}]`);
|
|
329
329
|
if (!Number.isInteger(timeoutMs) || timeoutMs < 100 || timeoutMs > 180000) throw new Error('machine fs read timeout_ms must be in [100, 180000]');
|
|
330
330
|
const grant = await assertCodingArmed(policy, rootId);
|
|
331
331
|
const found = await resolveExisting(policy, grant, rootId, relativePath, 'read', false);
|
|
332
332
|
const info = await lstat(found.resolved);
|
|
333
333
|
if (!info.isFile()) throw new Error('machine fs read target must be a regular file');
|
|
334
|
-
|
|
335
|
-
|
|
334
|
+
const effectiveOffset = offset < 0 ? Math.max(0, info.size + offset) : offset;
|
|
335
|
+
if (effectiveOffset > info.size) throw new Error('machine fs read offset exceeds file size');
|
|
336
|
+
const length = Math.min(maxBytes, info.size - effectiveOffset);
|
|
336
337
|
await recheckCodingAuthority(policy, grant, rootId);
|
|
337
|
-
const worker = await boundedReadWorker({ file: found.resolved, offset, length, hashFile, timeoutMs, workerPath: readWorkerPath });
|
|
338
|
+
const worker = await boundedReadWorker({ file: found.resolved, offset: effectiveOffset, length, hashFile, timeoutMs, workerPath: readWorkerPath });
|
|
338
339
|
const buffer = Buffer.from(worker.data_base64, 'base64');
|
|
339
340
|
if (buffer.length !== worker.bytes_read || buffer.length > length) throw new Error('machine fs read worker byte count mismatch');
|
|
340
341
|
await recheckCodingAuthority(policy, grant, rootId);
|
|
341
342
|
return {
|
|
342
343
|
status: 'ok', root_id: rootId, path: found.relative,
|
|
343
|
-
offset,
|
|
344
|
-
eof:
|
|
344
|
+
offset: effectiveOffset, requested_offset: offset, next_offset: effectiveOffset + buffer.length, file_size: info.size,
|
|
345
|
+
eof: effectiveOffset + buffer.length >= info.size, data_base64: buffer.toString('base64'),
|
|
345
346
|
data_sha256: sha256Bytes(buffer), file_sha256: worker.file_sha256,
|
|
346
347
|
timeout_ms: timeoutMs
|
|
347
348
|
};
|
package/src/version.mjs
CHANGED
|
@@ -21,7 +21,7 @@ test('npx CLI reports the canonical package version through --version, -v and ve
|
|
|
21
21
|
for(const arg of ['--version','-v','version']){
|
|
22
22
|
const result=spawnSync(process.execPath,[cliPath,arg],{cwd:root,encoding:'utf8',windowsHide:true});
|
|
23
23
|
assert.equal(result.status,0,result.stderr);
|
|
24
|
-
assert.equal(result.stdout.trim(),'0.15.
|
|
24
|
+
assert.equal(result.stdout.trim(),'0.15.5');
|
|
25
25
|
}
|
|
26
26
|
});
|
|
27
27
|
|
|
@@ -50,6 +50,6 @@ test('npx CLI exposes local supervisor lifecycle without any supervisor arm comm
|
|
|
50
50
|
|
|
51
51
|
test('README makes npx the primary operator UX',async()=>{
|
|
52
52
|
const readme=await readFile(path.join(root,'README.txt'),'utf8');
|
|
53
|
-
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.
|
|
54
|
-
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.
|
|
53
|
+
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.5 remote/);
|
|
54
|
+
assert.match(readme,/npx -y deadbyte-mcp@0\.15\.5 audit verify/);
|
|
55
55
|
});
|
package/test/core.test.mjs
CHANGED
|
@@ -105,7 +105,7 @@ test('proof execution creates deterministic output and signed verifiable receipt
|
|
|
105
105
|
assert.equal(result.receipt.request.schema, 'deadbyte.request.v1');
|
|
106
106
|
assert.match(result.receipt.request.nonce, /^[0-9a-f]{64}$/);
|
|
107
107
|
assert.match(result.receipt.request.sha256, /^[0-9a-f]{64}$/);
|
|
108
|
-
assert.equal(result.receipt.runtime.package_version, '0.15.
|
|
108
|
+
assert.equal(result.receipt.runtime.package_version, '0.15.5');
|
|
109
109
|
assert.match(result.receipt.runtime.mcp_ingress_adapter, /^(?:none|tunnel-stdio-probe-compat-v1)$/);
|
|
110
110
|
assert.match(result.receipt.runtime.mcp_ingress_adapter_sha256, /^[0-9a-f]{64}$/);
|
|
111
111
|
assert.match(result.receipt.runtime.mcp_ingress_mode_source_sha256, /^[0-9a-f]{64}$/);
|
|
@@ -15,7 +15,9 @@ const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy
|
|
|
15
15
|
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
16
|
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
17
|
|
|
18
|
-
test('R44 real max-runtime full stdio catalog is exactly 81 with skill and four Desktop primitives while authority remains disarmed',async
|
|
18
|
+
test('R44 real max-runtime full stdio catalog is exactly 81 with skill and four Desktop primitives while authority remains disarmed',async t=>{
|
|
19
|
+
const current=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8'));
|
|
20
|
+
if(current.version!=='0.15.0'){t.skip('historical R44 catalog; current development release is '+current.version);return;}
|
|
19
21
|
const f=await createR34Fixture({authority:'disarmed'});
|
|
20
22
|
const processPolicyPath=path.join(f.root,'process-policy.json');
|
|
21
23
|
const processGrant=path.join(f.root,'process-grant.json');
|
|
@@ -15,7 +15,9 @@ const desktopPolicyPath=path.join(repoRoot,'controller','deadbyte-desktop-policy
|
|
|
15
15
|
const sha=bytes=>createHash('sha256').update(bytes).digest('hex');
|
|
16
16
|
const absent=async p=>{try{await access(p);return false;}catch(e){if(e?.code==='ENOENT')return true;throw e;}};
|
|
17
17
|
|
|
18
|
-
test('R45 real max-runtime full stdio catalog is exactly 82 with skill and four Desktop primitives while authority remains disarmed',async
|
|
18
|
+
test('R45 real max-runtime full stdio catalog is exactly 82 with skill and four Desktop primitives while authority remains disarmed',async t=>{
|
|
19
|
+
const current=JSON.parse(await readFile(path.join(repoRoot,'package.json'),'utf8'));
|
|
20
|
+
if(current.version!=='0.15.1'){t.skip('historical R45 catalog; current development release is '+current.version);return;}
|
|
19
21
|
const f=await createR34Fixture({authority:'disarmed'});
|
|
20
22
|
const processPolicyPath=path.join(f.root,'process-policy.json');
|
|
21
23
|
const processGrant=path.join(f.root,'process-grant.json');
|