deadbyte-mcp 0.15.3 → 0.15.4
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 +16 -12
- package/PROVENANCE.json +3 -3
- package/RELEASE.json +3 -3
- package/package.json +88 -88
- 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/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/MANIFEST.SHA256
CHANGED
|
@@ -1328,7 +1328,7 @@ db605a698f917c4006462596e6526fe6a9c6eff9b8409e8472fe545d4b70027c node_modules/z
|
|
|
1328
1328
|
f67a25ded944912bd4621b68df17c7c70a52aae117278c076c0aabbc32a3abba node_modules/zod/v4/mini/schemas.d.ts
|
|
1329
1329
|
51b3a7869df2d3a1bd98acb9d5b6a61bbccc7653d7a3d8fca7f0e0db7e84e284 node_modules/zod/v4/mini/schemas.js
|
|
1330
1330
|
3e3125b5a537a24c3632c1c5c09640ce7bcb3935901b127ad8ae3c37a27f133f node_modules/zod/v4/package.json
|
|
1331
|
-
|
|
1331
|
+
79175ae788fe8d549c51586c57605fd2558af0dfbcea4d916394be7620e3730b package.json
|
|
1332
1332
|
8177e3a354721a73df889f386a97e7744a2e017d150aecf4bf309f5177d18690 proof/CONTAINMENT-BUILD.txt
|
|
1333
1333
|
a8efa13e44ff50902aee64cfca542d19605a1ae23db95280ad2d44b324f3eae7 proof/MCP-SMOKE-STATUS.txt
|
|
1334
1334
|
7c115069cc4a343ca21b0ebdee74bd8f544b02d4aa906ffa13308725825d891a proof/NODE-SYNTAX.txt
|
|
@@ -1388,7 +1388,7 @@ d433aaea5cccd1e184775ac4d915f34e0b39c6c99916dddd009731ad5fd6443f proof/V073-WIN
|
|
|
1388
1388
|
bd0773a9e02e8ab11475c9cc5a7db29a8313233b7eab7f837922737e75ec5938 proof/VERIFY.txt
|
|
1389
1389
|
2c821808d4596965c577f40191daee224d3aea81989778c4af97f53a83b487db proof/WINDOWS-CONTAINED-STATUS.txt
|
|
1390
1390
|
f8bc839c7b4fcb0ea7b7e7ad9448847c3beae6f95f2eb4d407d1b284aaa4ff68 proof/WINDOWS-CONTAINMENT-STATUS.txt
|
|
1391
|
-
|
|
1391
|
+
e0788cf183f40755bf892a93d1067a79aa6a68641d60e31568fc604bb66d3e94 PROVENANCE.json
|
|
1392
1392
|
27ca0f3c9ee3a1b6374a9c8dd98008decdd0c7659c7a569c70ad7b9734c74655 R34-BASELINE.json
|
|
1393
1393
|
0b7ec5ee347ddfa6cca59740fc7a8fe3fc5d51406265bb12189e82fa106319d2 R41-PARENT.json
|
|
1394
1394
|
bd2a789b0aab5663f0d208af2ca8e4ec98179bc8c7b57e70a962d4e06a3dcfc4 R42-PARENT.json
|
|
@@ -1397,7 +1397,7 @@ f932ef78b7a72b1bb0d7aedb5fe42fbb9951c2492eb528b72442f46ddff81a6c R44-DONORS.jso
|
|
|
1397
1397
|
731b4c559fc0d25dea701e4474f02400b27e8e3f4cac9f230d5214497d4490a9 R44-PARENT.json
|
|
1398
1398
|
d33ec5d167dd44800ba4e68372b08db43deb8d01df2ef71dd435ff004ac66c8b R45-PARENT.json
|
|
1399
1399
|
9928e50a62721b5b953c8b2851bc81625a8b4b5ea10470b8080983d746f764d9 README.txt
|
|
1400
|
-
|
|
1400
|
+
6c233588e01f646535bdf2d1ab5130202dfcfb49b540be961777ef27396631d1 RELEASE.json
|
|
1401
1401
|
507a42441c8fbb0b1bef63a13fad9e1680262cd6d34cc176b7ed0c5423ddbcc7 SBOM.cdx.json
|
|
1402
1402
|
bd138fe5a64088e8e1a7a5bf6104c5b17317bdc8cf3ad8191ea00ed82ace7d9b scripts/agent-eval-r42.mjs
|
|
1403
1403
|
1d4e9dee6f0669bd825334a6a72e13ee85ee29ab430dcef21d893ffd744774b5 scripts/autonomous-benchmark.mjs
|
|
@@ -1562,12 +1562,12 @@ da5181cec30034ddf089baa5358becb5651da238a2e7cf0888007a4c60b4ea6b src/capability
|
|
|
1562
1562
|
2b62295591f142ca4b3bc5b03e6434f7fc3c51d9502f9a40ef8a03d1f72a8899 src/capability-benchmark.mjs
|
|
1563
1563
|
160199b25f45bd0490f6b21a9fa8194313e9673c4b2699afce68249d3d249a7b src/capability-ledger.mjs
|
|
1564
1564
|
94e5aeff2453cdc0239aee4d547dbbefee183c71933cb84e5e8a418fa99bc1e8 src/codex-app-server-r44.mjs
|
|
1565
|
-
|
|
1566
|
-
|
|
1565
|
+
6d0a80daaa2711e67e2597bff3db5bd2802682f559107a492f3cd89b9c6785ed src/coding-mcp-tools.mjs
|
|
1566
|
+
d6fc395575f49abbbf60bf6f6ef5ee9ad51034a7e770a381e6ec34f869788306 src/coding-output-contracts.mjs
|
|
1567
1567
|
0857a458e9c5101eee94c0596b7699adc34c50687455688fe38d03d241d27935 src/coding-plane.mjs
|
|
1568
|
-
|
|
1568
|
+
38a1b4e9f5aa14cd5fd9058345c3480ae72c4a6a6eeccdc46e71297c68b5b5a6 src/coding-search.mjs
|
|
1569
1569
|
f87284dc71c167f6a17575b93730c258ed6c433831013c776bf2d14e2b77767f src/coding-task-runtime.mjs
|
|
1570
|
-
|
|
1570
|
+
bfe4b641b61e4e7da8848c6c39d256a39191639315fb9f3c17a0b11f999ec792 src/compact-gateway-mcp-tools.mjs
|
|
1571
1571
|
4218d1d1478d9e9a044d9b61c5ae205cd2ca0651a314900fad03992d0b12d286 src/compact-gateway-output-contracts.mjs
|
|
1572
1572
|
40ac70ece531de7709d3c51686b36b48e0ae60283d1fb18d0adc037bfe6f9063 src/contained-cli.mjs
|
|
1573
1573
|
d2bacef2443705e372071d0de3c72d45d57febb1dcbb11e369fce8a78bf0bf3e src/contained-executor.mjs
|
|
@@ -1596,17 +1596,20 @@ f57fe200ad916a03480c804ca57ab12b603822cbfb8d45ba7bce4376ec3d712a src/document-a
|
|
|
1596
1596
|
ea03db2bb706033f32045ed1dad67925d0d2e89cc97bc1aff805736dcab3b153 src/evidence-publisher-r42.mjs
|
|
1597
1597
|
f5fafd46052b09f71a528594eb230edc5766ee0d006432d744590ec97c9c580d src/executor.mjs
|
|
1598
1598
|
bd5b4496676d5399cfd73a684af4aff06b44af9ab51f0d5901ead00c4c540e74 src/external-job-provider-r44.mjs
|
|
1599
|
+
99d741c72028e1cea94e971f1863a299eb6fb3445ea0d0b6af5b40ae5ee06d0c src/fuzzy-search-core.mjs
|
|
1600
|
+
f6c316f52e9096a92879dbc5debf63a486953bf87b65620601c0a5a0a96eae1f src/fuzzy-search-worker.mjs
|
|
1601
|
+
f89acac9935ec9e757ee611893d1ffbe04ae3c2a03c43feb87af0427da39e830 src/fuzzy-search.mjs
|
|
1599
1602
|
264d21a4385a0a04613fe78203e7f5e231a5c06397086cfacc88076e60b89b71 src/hash.mjs
|
|
1600
1603
|
880e942358ba4fae2139027f924b79045a7cc90c775b09761d35cd5e411b005f src/host-plane.mjs
|
|
1601
1604
|
cd00584f346160c8ad16b4dcf64b3fb6499668f3bc299c199b67f53caa995746 src/ingress-mode.mjs
|
|
1602
1605
|
e1afae872e4252a4002032f1610033d41f5224896b0b06be077f54b267ed4f4f src/invocation.mjs
|
|
1603
1606
|
9efb25c69ecb0cf5778483d24a3944d2f08f52ebcbd271a212e89189add50167 src/job-supervisor-host-r44.mjs
|
|
1604
1607
|
532fbd7d5402bb9d65b81a1efdfa9ea1d7292d96e1d9c2d1e8d40ccc52af2670 src/lsp-stdio-client.mjs
|
|
1605
|
-
|
|
1606
|
-
|
|
1608
|
+
6856b81e8aab42d144b88d0c4be5b2b4c9ad7e51b5bb36d2d4e8fd134935ae56 src/machine-fs-mcp-tools.mjs
|
|
1609
|
+
ff54c503b8503b2837d8eb3c4a2e0d06e67c609e43b964c7a1a1305c135c2bbf src/machine-fs-output-contracts.mjs
|
|
1607
1610
|
7f68488f9e48ada11b1f1ea64032efa82a68dc6b632fffcf37fbe9bd95237e26 src/machine-fs-read-worker.mjs
|
|
1608
1611
|
4b46fca90489cc314c5dd884d4d0968f7702c512f87a3166d2bc12023767caf8 src/machine-fs-smoke-client.mjs
|
|
1609
|
-
|
|
1612
|
+
74391e536f403e27de471fa6a452a79f236addaba4b4dee97f8f94060f599866 src/machine-fs.mjs
|
|
1610
1613
|
14c072f1eefac6e9a7b91e50a0eb4669b972212c1e4bab03c8141fef86933cc8 src/machine-identity.mjs
|
|
1611
1614
|
ad4ca3635cb228b57b5b98e9518f379380ee1a03ad07ab4d12f8b7f324be2517 src/machine-mcp-tools.mjs
|
|
1612
1615
|
e81b3ac2955e5dfafe308c82da24356a14da396230cb9fc47b231ab672d5be48 src/machine-output-contracts.mjs
|
|
@@ -1835,6 +1838,7 @@ f95c920ee2b24d5ec940a9bae277771562ce275556bd89f0071f183b13c154b8 test/fixtures/
|
|
|
1835
1838
|
3eddb2d1ac91187c59d9989b015886953a93e5ce84f0fd1710f4801be6b19efc test/full-max-catalog-r44.test.mjs
|
|
1836
1839
|
3d257a6d8313548e9b4327cf8b8a49cabd5af035d9bff2e1edc58a15eae80309 test/full-max-catalog-r45.test.mjs
|
|
1837
1840
|
54f5096003ea13a6232a1e4756c7496a3d6425c145d9bef4f96696cdc22df024 test/full-max-catalog-r46.test.mjs
|
|
1841
|
+
3cecf2bb61027d210f6bdf65a140ce1d5bedf2d4135e02f94edfeb2ef89ae6ae test/fuzzy-search-r46.test.mjs
|
|
1838
1842
|
506e5437ed41da3955d006294d81230c25825ff898b266fa2758ffd885ee3d07 test/hardware-observation-r45.test.mjs
|
|
1839
1843
|
2efdac248a608fe84588de8e9223f39ee32d4a483f71594ab05f20f1110be0c9 test/helpers/autonomous-r34-fixture.mjs
|
|
1840
1844
|
78f9efaafe3286a3003209e8fb4c0117822d3f8996508159e19e217b1246faba test/helpers/coding-crash-child.mjs
|
|
@@ -1842,8 +1846,8 @@ f95c920ee2b24d5ec940a9bae277771562ce275556bd89f0071f183b13c154b8 test/fixtures/
|
|
|
1842
1846
|
e80f4172b400f126d0280eba53ffcc748597442ef57c4a62b3fd6f76c27e5fdc test/host-plane.test.mjs
|
|
1843
1847
|
1205e33a1924dcc33a18372f0c973076fff39e99203a671b39d14269d51b2999 test/human-clarification-r42.test.mjs
|
|
1844
1848
|
b12322450d23f44513b02d2c54f216520f392bf76e221af22fdcb5a11261ec3d test/lsp-stdio-client.test.mjs
|
|
1845
|
-
|
|
1846
|
-
|
|
1849
|
+
af1716b6b831eabe8f43e1276b85519c3cedee9ecb98d261033ac3f5e6f84166 test/machine-fs-mcp-tools.test.mjs
|
|
1850
|
+
6eae806805d59a844e27ff410313874bc263c84a84d83dc166b442448092c3be test/machine-fs-runtime.test.mjs
|
|
1847
1851
|
ce6b64a55a3288d9c94d3ee700c508544cd2339636fc65ad4915b7f607836182 test/machine-identity.test.mjs
|
|
1848
1852
|
4429edf1a34a94e58e1bde7554af160fdf122d508ec78b01f375169a544ea422 test/machine-mcp-integration.test.mjs
|
|
1849
1853
|
fc9662d3c92d0615e9ef54ec1853862358c71659917567ae6e614912ed0b1cfc test/machine-mcp-tools.test.mjs
|
package/PROVENANCE.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "deadbyte.provenance.v1",
|
|
3
|
-
"version": "0.15.
|
|
3
|
+
"version": "0.15.4",
|
|
4
4
|
"builder": "deadbyte-r46-fileless-powershell",
|
|
5
5
|
"source_model": "development-root -> MANIFEST.SHA256 -> immutable release slot -> generation bundle -> signed final closure",
|
|
6
6
|
"signing": "ed25519",
|
|
7
|
-
"parent_release_id": "v0.15.
|
|
8
|
-
"parent_manifest_sha256": "
|
|
7
|
+
"parent_release_id": "v0.15.2-0fb46542f6a4345f",
|
|
8
|
+
"parent_manifest_sha256": "0fb46542f6a4345f1c527565d06bf6e9b8e283260e47bf684fb70a60308fcf34",
|
|
9
9
|
"reproducibility": "manifest-bound package bytes; native payloads hash-bound; Windows process executables target-repinned",
|
|
10
10
|
"parent_generation_manifest_sha256": "00cde7bf540cc2804d679a39040d5b07193c5f8a0d49cac3b882402f8f4e6ad8"
|
|
11
11
|
}
|
package/RELEASE.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schema": "deadbyte.release.v1",
|
|
3
3
|
"name": "deadbyte-mcp",
|
|
4
|
-
"version": "0.15.
|
|
4
|
+
"version": "0.15.4",
|
|
5
5
|
"train": "R46",
|
|
6
6
|
"label": "FILELESS POWERSHELL PRODUCT BASELINE",
|
|
7
7
|
"protocol_revision": "2026-07-28",
|
|
8
8
|
"parent": {
|
|
9
|
-
"release_id": "v0.15.
|
|
10
|
-
"manifest_sha256": "
|
|
9
|
+
"release_id": "v0.15.2-0fb46542f6a4345f",
|
|
10
|
+
"manifest_sha256": "0fb46542f6a4345f1c527565d06bf6e9b8e283260e47bf684fb70a60308fcf34",
|
|
11
11
|
"generation_manifest_sha256": "00cde7bf540cc2804d679a39040d5b07193c5f8a0d49cac3b882402f8f4e6ad8"
|
|
12
12
|
},
|
|
13
13
|
"platform": {
|
package/package.json
CHANGED
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
|
|
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
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "deadbyte-mcp",
|
|
3
|
+
"version": "0.15.4",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"description": "Authenticated MCP agentic runtime with signed skills, persistent model backends, identity-bound remote devices, durable job supervision, immutable release slots, and separately revocable machine authority.",
|
|
7
|
+
"engines": {
|
|
8
|
+
"node": ">=22"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node --test test/*.test.mjs",
|
|
12
|
+
"manifest:write": "node scripts/release-manifest.mjs write",
|
|
13
|
+
"manifest:verify": "node scripts/release-manifest.mjs verify",
|
|
14
|
+
"r41:parent:verify": "node scripts/verify-r41-parent.mjs",
|
|
15
|
+
"r41:memory:verify": "node scripts/verify-memory-r41.mjs",
|
|
16
|
+
"r42:parent:verify": "node scripts/verify-r42-parent.mjs",
|
|
17
|
+
"r42:eval": "node scripts/agent-eval-r42.mjs",
|
|
18
|
+
"self-update:runtime": "node scripts/runtime-self-update.mjs",
|
|
19
|
+
"self-update:deferred": "node scripts/deferred-slot-operation-r46.mjs",
|
|
20
|
+
"release:parity": "node scripts/release-parity-r46.mjs",
|
|
21
|
+
"release:final:write": "node scripts/final-closure-r46.mjs",
|
|
22
|
+
"release:final:verify": "node scripts/final-closure-verify-r46.mjs",
|
|
23
|
+
"proof": "node src/proof-cli.mjs workspaces/demo input.txt",
|
|
24
|
+
"verify": "node src/verifier-cli.mjs workspaces/demo evidence/latest.json",
|
|
25
|
+
"trust:init": "node src/trust-init.mjs",
|
|
26
|
+
"mcp": "node src/mcp-server.mjs",
|
|
27
|
+
"mcp:smoke": "node src/mcp-smoke-client.mjs",
|
|
28
|
+
"mcp:agent:smoke": "node --test test/agent-runtime.test.mjs test/agent-runtime-adversarial.test.mjs test/agent-runtime-crash.test.mjs test/agent-task-receipt.test.mjs",
|
|
29
|
+
"mcp:coding:smoke": "node --test test/coding-plane.test.mjs test/coding-plane-adversarial.test.mjs test/coding-runtime.test.mjs test/coding-crash.test.mjs",
|
|
30
|
+
"mcp:machine-fs:smoke": "node src/machine-fs-smoke-client.mjs",
|
|
31
|
+
"mcp:observation:smoke": "node src/observation-smoke-client.mjs",
|
|
32
|
+
"mcp:process:smoke": "node src/process-smoke-client.mjs",
|
|
33
|
+
"process:policy:refresh": "node scripts/refresh-process-policy.mjs",
|
|
34
|
+
"mcp:autonomous:smoke": "node --test test/autonomous-runtime.test.mjs test/autonomous-loop.test.mjs test/autonomous-adversarial.test.mjs test/autonomous-supervisor-integration.test.mjs test/native-diff.test.mjs",
|
|
35
|
+
"containment:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-containment.ps1",
|
|
36
|
+
"containment:smoke": "node src/containment-smoke.mjs appcontainer",
|
|
37
|
+
"containment:bootstrap": "node src/containment-bootstrap.mjs",
|
|
38
|
+
"containment:smoke:lpac": "node src/containment-smoke.mjs lpac",
|
|
39
|
+
"containment:smoke:appcontainer": "node src/containment-smoke.mjs appcontainer",
|
|
40
|
+
"containment:construction": "node src/containment-construction.mjs",
|
|
41
|
+
"containment:child-control": "node src/containment-child-control.mjs",
|
|
42
|
+
"contained:run": "node src/contained-cli.mjs workspaces/demo input.txt",
|
|
43
|
+
"contained:smoke": "node src/contained-smoke.mjs",
|
|
44
|
+
"mcp:contained:smoke": "node src/mcp-contained-smoke-client.mjs",
|
|
45
|
+
"gate:windows": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/gate-windows-r46.ps1",
|
|
46
|
+
"authority:smoke": "node src/authority-smoke.mjs",
|
|
47
|
+
"mcp:remote:smoke": "node src/remote-mcp-smoke-client.mjs",
|
|
48
|
+
"mcp:host:smoke": "node src/mcp-host-smoke-client.mjs",
|
|
49
|
+
"host:policy:init": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-host-policy.ps1",
|
|
50
|
+
"mcp:remote:host:smoke": "node src/remote-mcp-host-smoke-client.mjs",
|
|
51
|
+
"mcp:remote:autonomous:smoke": "node src/remote-mcp-autonomous-smoke-client.mjs",
|
|
52
|
+
"mcp:tunnel-compat:smoke": "node src/tunnel-stdio-compat-smoke.mjs",
|
|
53
|
+
"audit:verify": "node src/deadbyte-cli.mjs audit verify",
|
|
54
|
+
"audit:status": "node src/deadbyte-cli.mjs audit status",
|
|
55
|
+
"desktop:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-desktop-r40.ps1",
|
|
56
|
+
"desktop:policy:refresh": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/init-desktop-policy-r40.ps1",
|
|
57
|
+
"r43:parent:verify": "node scripts/verify-r43-parent.mjs",
|
|
58
|
+
"r43:full:test": "node scripts/full-regression-r43.mjs",
|
|
59
|
+
"r44:parent:verify": "node scripts/verify-r44-parent.mjs",
|
|
60
|
+
"r44:full:test": "node scripts/full-regression-r44.mjs",
|
|
61
|
+
"finalize:r44": "node scripts/finalize-r44.mjs",
|
|
62
|
+
"hardware:build": "powershell -NoProfile -ExecutionPolicy Bypass -File scripts/build-hardware-r45.ps1",
|
|
63
|
+
"doctor": "node src/deadbyte-cli.mjs doctor",
|
|
64
|
+
"r45:parent:verify": "node scripts/verify-r45-parent.mjs",
|
|
65
|
+
"r45:full:test": "node scripts/full-regression-r45.mjs",
|
|
66
|
+
"finalize:r45": "node scripts/finalize-r45.mjs",
|
|
67
|
+
"r46:fileless:test": "node --test --test-concurrency=1 test/process-policy.test.mjs test/process-policy-refresh.test.mjs test/release-generation.test.mjs test/process-runtime.test.mjs test/process-mcp-tools.test.mjs test/compact-gateway-r36.test.mjs test/capability-ledger-r36.test.mjs test/remote-device-r44.test.mjs test/observation-runtime.test.mjs test/observation-mcp-tools.test.mjs",
|
|
68
|
+
"r46:full:test": "node scripts/full-regression-r46.mjs"
|
|
69
|
+
},
|
|
70
|
+
"bundleDependencies": [
|
|
71
|
+
"@modelcontextprotocol/server",
|
|
72
|
+
"@modelcontextprotocol/client",
|
|
73
|
+
"typescript",
|
|
74
|
+
"zod"
|
|
75
|
+
],
|
|
76
|
+
"dependencies": {
|
|
77
|
+
"@modelcontextprotocol/client": "2.0.0",
|
|
78
|
+
"@modelcontextprotocol/server": "2.0.0",
|
|
79
|
+
"typescript": "5.9.3",
|
|
80
|
+
"zod": "4.4.3"
|
|
81
|
+
},
|
|
82
|
+
"bin": {
|
|
83
|
+
"deadbyte-mcp": "src/deadbyte-cli.mjs"
|
|
84
|
+
},
|
|
85
|
+
"publishConfig": {
|
|
86
|
+
"access": "public"
|
|
87
|
+
}
|
|
88
|
+
}
|
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
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { fuzzyIndexOf } from '../src/fuzzy-search-core.mjs';
|
|
5
|
+
import { runFuzzySearchInWorker } from '../src/fuzzy-search.mjs';
|
|
6
|
+
import { createCodingSearch } from '../src/coding-search.mjs';
|
|
7
|
+
|
|
8
|
+
const sha = text => createHash('sha256').update(text,'utf8').digest('hex');
|
|
9
|
+
const files = new Map([
|
|
10
|
+
['src/a.mjs','const deadbyte_machine_identity = true;'],
|
|
11
|
+
['src/b.mjs','const unrelated = false;']
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
function cursorCodec(){
|
|
15
|
+
return {
|
|
16
|
+
async encode(value){ return Buffer.from(JSON.stringify(value)).toString('base64url'); },
|
|
17
|
+
async decode(value){ return JSON.parse(Buffer.from(value,'base64url').toString('utf8')); }
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
test('R46 fuzzy core and worker agree under a hard timeout boundary', async () => {
|
|
22
|
+
const text='AAAA deadbyte_machine_identity SHA256 CATALOG';
|
|
23
|
+
const direct=fuzzyIndexOf(text,'deadbyte_machine_identiti');
|
|
24
|
+
const worker=await runFuzzySearchInWorker(text,'deadbyte_machine_identiti',3000);
|
|
25
|
+
assert.equal(worker.start,direct.start);
|
|
26
|
+
assert.equal(worker.end,direct.end);
|
|
27
|
+
assert.equal(worker.distance,direct.distance);
|
|
28
|
+
assert.ok(worker.similarity >= 0.90);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('R46 coding search fuzzy mode preserves bounded paging and file identity', async () => {
|
|
32
|
+
const search=createCodingSearch({
|
|
33
|
+
tree: async ({rootId,path,maxEntries}) => ({
|
|
34
|
+
status:'ok',root_id:rootId,path,
|
|
35
|
+
entries:[...files].map(([item])=>({path:item,type:'file',bytes:files.get(item).length})).slice(0,maxEntries),
|
|
36
|
+
truncated:false
|
|
37
|
+
}),
|
|
38
|
+
fileRead: async ({relativePath}) => {
|
|
39
|
+
const text=files.get(relativePath);
|
|
40
|
+
return {content:Buffer.from(text,'utf8').toString('base64'),bytes:Buffer.byteLength(text),sha256:sha(text)};
|
|
41
|
+
},
|
|
42
|
+
cursorCodec:cursorCodec()
|
|
43
|
+
});
|
|
44
|
+
const value=await search({
|
|
45
|
+
rootId:'core',path:'.',pattern:'deadbyte_machine_identiti',
|
|
46
|
+
target:'content',mode:'fuzzy',maxResults:10,maxFileBytes:4096,maxScanBytes:4096,pageSize:10
|
|
47
|
+
});
|
|
48
|
+
assert.equal(value.status,'ok');
|
|
49
|
+
assert.equal(value.matches.length,1);
|
|
50
|
+
assert.equal(value.matches[0].path,'src/a.mjs');
|
|
51
|
+
assert.equal(value.matches[0].distance,1);
|
|
52
|
+
assert.ok(value.matches[0].similarity >= 0.90);
|
|
53
|
+
assert.match(value.matches[0].file_sha256,/^[0-9a-f]{64}$/);
|
|
54
|
+
});
|
|
@@ -37,6 +37,8 @@ test('R31 machine filesystem schemas expose root-relative IDs/preconditions only
|
|
|
37
37
|
registerMachineFsTools(server, { runtime: runtime() });
|
|
38
38
|
const read = server.tools.get('machine_fs_read').spec.inputSchema;
|
|
39
39
|
assert.equal(read.safeParse({ root_id:'core', path:'a.txt', offset:0, max_bytes:65536, hash_file:false, timeout_ms:30000 }).success, true);
|
|
40
|
+
assert.equal(read.safeParse({ root_id:'core', path:'a.txt', offset:-4096, max_bytes:4096, hash_file:false, timeout_ms:30000 }).success, true);
|
|
41
|
+
assert.equal(read.safeParse({ root_id:'core', path:'a.txt', offset:-4194305, max_bytes:4096, hash_file:false, timeout_ms:30000 }).success, false);
|
|
40
42
|
assert.equal(read.safeParse({ root_id:'core', path:'a.txt', timeout_ms:99 }).success, false);
|
|
41
43
|
const write = server.tools.get('machine_fs_write').spec.inputSchema;
|
|
42
44
|
const move = server.tools.get('machine_fs_move').spec.inputSchema;
|
|
@@ -53,6 +53,12 @@ test('R31 machine fs supports exact mkdir/write/stat/list/range-read/edit/move/d
|
|
|
53
53
|
assert.equal(Buffer.from(read.data_base64, 'base64').toString('utf8'), 'beta');
|
|
54
54
|
assert.equal(read.next_offset, 10);
|
|
55
55
|
assert.equal(read.timeout_ms, 30000);
|
|
56
|
+
const tail = await f.runtime.read({ rootId: 'project', relativePath: 'dir/a.txt', offset: -5, maxBytes: 8 });
|
|
57
|
+
assert.equal(Buffer.from(tail.data_base64, 'base64').toString('utf8'), 'gamma');
|
|
58
|
+
assert.equal(tail.offset, 11);
|
|
59
|
+
assert.equal(tail.requested_offset, -5);
|
|
60
|
+
assert.equal(tail.next_offset, 16);
|
|
61
|
+
assert.equal(tail.eof, true);
|
|
56
62
|
const edited = await f.runtime.editExact({
|
|
57
63
|
rootId: 'project', relativePath: 'dir/a.txt', expectedSha256: written.sha256,
|
|
58
64
|
oldString: 'beta', newString: 'BETA', expectedReplacements: 1
|