import assert from "node:assert/strict"; import { mkdtemp, readFile, stat } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { spawnSync } from "node:child_process"; import test from "node:test"; import { getSearchConfigPath, loadSearchConfigEnv, parseSearchConfig, } from "../extensions/search-config.ts"; test("search config parses only supported safe assignments", () => { assert.deepEqual( parseSearchConfig(` export TAVILY_API_KEY=tvly-test_1 EXA_API_KEY=exa-test.2 UNKNOWN_KEY=ignored KEENABLE_API_KEY=$(not-allowed) `), { TAVILY_API_KEY: "tvly-test_1", EXA_API_KEY: "exa-test.2", }, ); }); test("search config does not override explicit environment values", async () => { const root = await mkdtemp(join(tmpdir(), "my-pi-search-config-")); const configPath = join(root, "search.env"); await import("node:fs/promises").then(({ writeFile }) => writeFile(configPath, "export TAVILY_API_KEY=file-value\nexport EXA_API_KEY=exa-file\n"), ); const env: Record = { TAVILY_API_KEY: "explicit-value" }; const effective = loadSearchConfigEnv(env, configPath); assert.equal(env.TAVILY_API_KEY, "explicit-value"); assert.equal(env.EXA_API_KEY, "exa-file"); assert.deepEqual(effective, { TAVILY_API_KEY: "explicit-value", EXA_API_KEY: "exa-file" }); }); test("search config path follows XDG_CONFIG_HOME", () => { assert.equal(getSearchConfigPath({ XDG_CONFIG_HOME: "/tmp/config" }), "/tmp/config/my-pi/search.env"); }); test("search_config.sh supports noninteractive updates and preserves omitted keys", async () => { const home = await mkdtemp(join(tmpdir(), "my-pi-search-script-")); const script = new URL("../search_config.sh", import.meta.url); let result = spawnSync("sh", [script.pathname, "--tavily", "tvly-test", "--exa", "exa-test"], { env: { ...process.env, HOME: home, XDG_CONFIG_HOME: join(home, ".config") }, encoding: "utf8", }); assert.equal(result.status, 0, result.stderr); result = spawnSync("sh", [script.pathname, "--keenable", "keen-test"], { env: { ...process.env, HOME: home, XDG_CONFIG_HOME: join(home, ".config") }, encoding: "utf8", }); assert.equal(result.status, 0, result.stderr); const configPath = join(home, ".config", "my-pi", "search.env"); const content = await readFile(configPath, "utf8"); assert.match(content, /^export TAVILY_API_KEY=tvly-test$/m); assert.match(content, /^export EXA_API_KEY=exa-test$/m); assert.match(content, /^export KEENABLE_API_KEY=keen-test$/m); assert.equal((await stat(configPath)).mode & 0o777, 0o600); });