summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-02 20:46:23 +0900
committerAdam Malczewski <[email protected]>2026-06-02 20:46:23 +0900
commit80212bfb009eaf71a4743310dee6ed08b8f7e1da (patch)
tree81b1873f4a276116cf019cbcdecdd8fcba56beef /packages
parent09914c6ba15214d5ec05c106d5d11fd14a86f532 (diff)
downloaddispatch-80212bfb009eaf71a4743310dee6ed08b8f7e1da.tar.gz
dispatch-80212bfb009eaf71a4743310dee6ed08b8f7e1da.zip
fix(search_code): fuzzy mid-word matching + Luau/fuzzy live test coverage
Address the remaining real defects from the Luau/cs test reports. The wrapper- level findings (dash-leading queries, context flag, no-match message, empty query, path-is-file) were already fixed in earlier commits and verified through the tool; the two genuinely-open items were engine-level, plus a test-coverage gap (the patch-dependent behaviors were only exercised by live tests that skip without a cs binary). - Engine fix (docker/cs/fuzzy-distance.patch): cs's fuzzy `term~N` only scanned same-length windows, so it matched substitutions but never mid-word insertions/deletions — e.g. `computSlipAngle~1` (a dropped 'e') failed to find `computeSlipAngle`, contradicting cs's own "within 1 or 2 distance" docs. Now scan windows of length termLen±maxDist (true Levenshtein) and keep the best per offset. Updates one pre-existing cs test that encoded the buggy substitution-only behaviour and adds mid-word insert/delete cases. Passes cs's pkg/search + pkg/ranker suites; builds clean against the pinned commit. - Provisioning: apply the new patch everywhere the Luau patch is applied — Dockerfile, Dockerfile.dev, packaging/PKGBUILD build() — so every install path (Docker bin/up, native code-search package via bin/service install) ships both patches. - Tests: add skip-gated live tests for Luau declaration detection (function / local function / type / export type), only=usages exclusion, the Luau language tag, and fuzzy mid-word matching. New capability probes (findLuauCapableCs / findFuzzyCapableCs) run these only on a cs that actually has each patch and skip (never fail) on an unpatched/absent binary. Default suite: 600 pass / 12 skip; with a both-patched cs: 612 pass / 0 skip. - Docs: UPSTREAM_CS_FUZZY_BUG.md documents the unreported upstream defect for a potential boyter/cs PR; CS_ARTIX_DEPLOY.md updated to reflect that sync-dispatch.sh now ships the code-search package (carrying both patches). biome + tsc (core/api/frontend) + svelte-check all green.
Diffstat (limited to 'packages')
-rw-r--r--packages/core/tests/tools/search-code.test.ts160
1 files changed, 159 insertions, 1 deletions
diff --git a/packages/core/tests/tools/search-code.test.ts b/packages/core/tests/tools/search-code.test.ts
index 00eee4c..c4e933c 100644
--- a/packages/core/tests/tools/search-code.test.ts
+++ b/packages/core/tests/tools/search-code.test.ts
@@ -1,5 +1,5 @@
import { spawnSync } from "node:child_process";
-import { chmodSync, writeFileSync } from "node:fs";
+import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
import { mkdtemp as mkdtempP, rm as rmP, writeFile as writeFileP } from "node:fs/promises";
import { tmpdir } from "node:os";
import { join } from "node:path";
@@ -331,6 +331,110 @@ describe("search_code tool", () => {
const out = await tool.execute({ query: "zzz_nonexistent_token_qqq" });
expect(out).toBe("No matches found.");
});
+
+ it("tags .luau files as Luau", async () => {
+ process.env.DISPATCH_CS_BIN = liveCsBin as string;
+ await writeFileP(join(workDir, "mod.luau"), "function Mod.doThing()\n\treturn 1\nend\n");
+ const tool = createSearchCodeTool(workDir);
+ const out = await tool.execute({ query: "doThing" });
+ expect(out).toContain("mod.luau");
+ expect(out).toContain("[Luau]");
+ });
+ });
+
+ // ── Luau declaration detection: needs a cs built with the Luau patch
+ // (docker/cs/luau-declarations.patch). Skipped on an unpatched/older cs. ──
+ const luauCsBin = findLuauCapableCs(liveCsBin);
+ describe.runIf(luauCsBin)("live cs binary (Luau declaration patch)", () => {
+ // A small Luau module exercising every declaration form the patch adds.
+ const LUAU_MODULE = [
+ "local Mod = {}",
+ "",
+ "export type StuntResult = {",
+ "\tscore: number,",
+ "}",
+ "",
+ "type LaunchConfig = StuntResult",
+ "",
+ "function Mod.getDefaults(): LaunchConfig",
+ "\treturn { score = 0 }",
+ "end",
+ "",
+ "local function helperThing(x: number): number",
+ "\treturn x + 1",
+ "end",
+ "",
+ "Mod.live = Mod.getDefaults()",
+ "local used = helperThing(1)",
+ "",
+ ].join("\n");
+
+ beforeEach(async () => {
+ process.env.DISPATCH_CS_BIN = luauCsBin as string;
+ await writeFileP(join(workDir, "Mod.luau"), LUAU_MODULE);
+ });
+
+ it("detects `function Mod.x` declarations in .luau files", async () => {
+ const tool = createSearchCodeTool(workDir);
+ const out = await tool.execute({ query: "getDefaults", only: "declarations" });
+ expect(out).toContain("Mod.luau");
+ expect(out).toContain("function Mod.getDefaults");
+ expect(out).not.toContain("No matches found");
+ });
+
+ it("detects `local function` declarations in .luau files", async () => {
+ const tool = createSearchCodeTool(workDir);
+ const out = await tool.execute({ query: "helperThing", only: "declarations" });
+ expect(out).toContain("Mod.luau");
+ expect(out).toContain("local function helperThing");
+ });
+
+ it("detects `type` / `export type` declarations in .luau files", async () => {
+ const tool = createSearchCodeTool(workDir);
+ const exportType = await tool.execute({ query: "StuntResult", only: "declarations" });
+ expect(exportType).toContain("export type StuntResult");
+ const aliasType = await tool.execute({ query: "LaunchConfig", only: "declarations" });
+ expect(aliasType).toContain("type LaunchConfig");
+ });
+
+ it("excludes declaration lines when only=usages", async () => {
+ const tool = createSearchCodeTool(workDir);
+ const out = await tool.execute({ query: "getDefaults", only: "usages" });
+ // The call site is a usage; the `function Mod.getDefaults` definition is not.
+ expect(out).toContain("Mod.live = Mod.getDefaults()");
+ expect(out).not.toContain("function Mod.getDefaults");
+ });
+ });
+
+ // ── Fuzzy mid-word matching: needs a cs built with the fuzzy patch
+ // (docker/cs/fuzzy-distance.patch). Skipped on an unpatched/older cs. ──
+ const fuzzyCsBin = findFuzzyCapableCs(liveCsBin);
+ describe.runIf(fuzzyCsBin)("live cs binary (fuzzy edit-distance patch)", () => {
+ beforeEach(() => {
+ process.env.DISPATCH_CS_BIN = fuzzyCsBin as string;
+ });
+
+ it("matches a mid-word deletion within distance 1", async () => {
+ await writeFileP(
+ join(workDir, "phys.ts"),
+ "export function computeSlipAngle() {\n\treturn 0;\n}\n",
+ );
+ const tool = createSearchCodeTool(workDir);
+ // "computSlipAngle" drops the 'e' mid-word — edit distance 1.
+ const out = await tool.execute({ query: "computSlipAngle~1" });
+ expect(out).toContain("phys.ts");
+ expect(out).toContain("computeSlipAngle");
+ expect(out).not.toBe("No matches found.");
+ });
+
+ it("matches a mid-word insertion within distance 1", async () => {
+ await writeFileP(join(workDir, "tire.ts"), "const tireFriction = 1;\n");
+ const tool = createSearchCodeTool(workDir);
+ // "tireFricction" has an extra 'c' — edit distance 1.
+ const out = await tool.execute({ query: "tireFricction~1" });
+ expect(out).toContain("tire.ts");
+ expect(out).toContain("tireFriction");
+ });
});
});
@@ -351,3 +455,57 @@ function findRealCs(): string | null {
}
return null;
}
+
+/**
+ * Probe a `cs` binary against a throwaway corpus and return its trimmed stdout
+ * (or "" on any failure). Used by the capability gates below so patch-dependent
+ * live tests run only on a cs that actually has the patch — and skip (not fail)
+ * on an unpatched/older binary.
+ */
+function probeCs(bin: string, files: Record<string, string>, args: string[]): string {
+ let dir: string | undefined;
+ try {
+ dir = mkdtempSync(join(tmpdir(), "dispatch-cs-probe-"));
+ for (const [name, body] of Object.entries(files)) {
+ writeFileSync(join(dir, name), body);
+ }
+ const res = spawnSync(bin, ["-f", "json", "--dir", dir, ...args], {
+ encoding: "utf8",
+ });
+ if (res.status !== 0 || !res.stdout) return "";
+ return res.stdout.trim();
+ } catch {
+ return "";
+ } finally {
+ if (dir) rmSync(dir, { recursive: true, force: true });
+ }
+}
+
+/**
+ * Return the cs binary only if it recognises Luau declarations (i.e. was built
+ * with docker/cs/luau-declarations.patch): a `--only-declarations` search for a
+ * top-level `function` in a .luau file yields a result. Otherwise null → skip.
+ */
+function findLuauCapableCs(bin: string | null): string | null {
+ if (!bin) return null;
+ const out = probeCs(bin, { "probe.luau": "function Probe.thing()\n\treturn 1\nend\n" }, [
+ "--only-declarations",
+ "--",
+ "thing",
+ ]);
+ return out !== "" && out !== "null" ? bin : null;
+}
+
+/**
+ * Return the cs binary only if its fuzzy matcher honours mid-word edits (i.e.
+ * was built with docker/cs/fuzzy-distance.patch): a distance-1 deletion matches.
+ * Otherwise null → skip.
+ */
+function findFuzzyCapableCs(bin: string | null): string | null {
+ if (!bin) return null;
+ const out = probeCs(bin, { "probe.txt": "const x = computeSlipAngle;\n" }, [
+ "--",
+ "computSlipAngle~1",
+ ]);
+ return out !== "" && out !== "null" ? bin : null;
+}