From 29f54aca7a49624f108382aabedae64069391483 Mon Sep 17 00:00:00 2001 From: RealDiligent Date: Sat, 18 Jul 2026 10:24:43 +0800 Subject: [PATCH] fix(miner): scan coding-agent driver roots in env-reference generator (#6994) Co-authored-by: Cursor --- apps/loopover-ui/src/lib/ams-env-reference.ts | 26 +++++++++++++- packages/loopover-miner/docs/env-reference.md | 6 +++- .../scripts/generate-env-reference.mjs | 4 +++ scripts/gen-selfhost-env-reference.mjs | 8 ++++- test/unit/miner-env-reference-script.test.ts | 36 +++++++++++++++++++ 5 files changed, 77 insertions(+), 3 deletions(-) diff --git a/apps/loopover-ui/src/lib/ams-env-reference.ts b/apps/loopover-ui/src/lib/ams-env-reference.ts index 19bcfa5344..7c874a93ea 100644 --- a/apps/loopover-ui/src/lib/ams-env-reference.ts +++ b/apps/loopover-ui/src/lib/ams-env-reference.ts @@ -151,9 +151,29 @@ export const AMS_ENV_REFERENCE_ROWS: MinerEnvReferenceRow[] = [ firstReference: "lib/worktree-allocator.js", defaultValue: "", }, + { + name: "MINER_CODING_AGENT_CLAUDE_MODEL", + firstReference: "packages/loopover-engine/src/miner/driver-factory.ts", + defaultValue: null, + }, + { + name: "MINER_CODING_AGENT_CODEX_MODEL", + firstReference: "packages/loopover-engine/src/miner/driver-factory.ts", + defaultValue: null, + }, + { + name: "MINER_CODING_AGENT_PAUSED", + firstReference: "packages/loopover-engine/src/miner/coding-agent-mode.ts", + defaultValue: "", + }, { name: "MINER_CODING_AGENT_PROVIDER", firstReference: "lib/laptop-init.js", + defaultValue: "", + }, + { + name: "MINER_CODING_AGENT_TIMEOUT_MS", + firstReference: "packages/loopover-engine/src/miner/driver-factory.ts", defaultValue: null, }, ]; @@ -194,6 +214,10 @@ export const AMS_ENV_REFERENCE_MARKDOWN = [ '| `LOOPOVER_MINER_VERSION` | `lib/version.js` | `""` |', "| `LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB` | `lib/worktree-allocator.js` | (none) |", '| `LOOPOVER_MINER_WORKTREE_DIR` | `lib/worktree-allocator.js` | `""` |', - "| `MINER_CODING_AGENT_PROVIDER` | `lib/laptop-init.js` | (none) |", + "| `MINER_CODING_AGENT_CLAUDE_MODEL` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) |", + "| `MINER_CODING_AGENT_CODEX_MODEL` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) |", + '| `MINER_CODING_AGENT_PAUSED` | `packages/loopover-engine/src/miner/coding-agent-mode.ts` | `""` |', + '| `MINER_CODING_AGENT_PROVIDER` | `lib/laptop-init.js` | `""` |', + "| `MINER_CODING_AGENT_TIMEOUT_MS` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) |", "", ].join("\n"); diff --git a/packages/loopover-miner/docs/env-reference.md b/packages/loopover-miner/docs/env-reference.md index d4429998e1..c63d2fc64a 100644 --- a/packages/loopover-miner/docs/env-reference.md +++ b/packages/loopover-miner/docs/env-reference.md @@ -33,4 +33,8 @@ Generated by `npm run miner:env-reference`. Do not edit manually. | `LOOPOVER_MINER_VERSION` | `lib/version.js` | `""` | | `LOOPOVER_MINER_WORKTREE_ALLOCATOR_DB` | `lib/worktree-allocator.js` | (none) | | `LOOPOVER_MINER_WORKTREE_DIR` | `lib/worktree-allocator.js` | `""` | -| `MINER_CODING_AGENT_PROVIDER` | `lib/laptop-init.js` | (none) | +| `MINER_CODING_AGENT_CLAUDE_MODEL` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) | +| `MINER_CODING_AGENT_CODEX_MODEL` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) | +| `MINER_CODING_AGENT_PAUSED` | `packages/loopover-engine/src/miner/coding-agent-mode.ts` | `""` | +| `MINER_CODING_AGENT_PROVIDER` | `lib/laptop-init.js` | `""` | +| `MINER_CODING_AGENT_TIMEOUT_MS` | `packages/loopover-engine/src/miner/driver-factory.ts` | (none) | diff --git a/packages/loopover-miner/scripts/generate-env-reference.mjs b/packages/loopover-miner/scripts/generate-env-reference.mjs index 90188462a7..9ff6208fab 100644 --- a/packages/loopover-miner/scripts/generate-env-reference.mjs +++ b/packages/loopover-miner/scripts/generate-env-reference.mjs @@ -10,6 +10,10 @@ export const DEFAULT_SOURCE_ROOTS = [ "packages/loopover-miner/bin", "packages/loopover-miner/lib", "packages/loopover-miner/scripts", + // The coding-agent driver (MINER_CODING_AGENT_* vars) lives in the shared engine package, not under + // packages/loopover-miner itself -- scoped narrowly to src/miner so this doesn't pull in unrelated + // packages/loopover-engine env vars that belong to a different generator/doc. (#6994) + "packages/loopover-engine/src/miner", ]; const MINER_ENV_PREFIXES = ["LOOPOVER_MINER_", "MINER_"]; diff --git a/scripts/gen-selfhost-env-reference.mjs b/scripts/gen-selfhost-env-reference.mjs index 7afdc7b9ec..b8d9af02c8 100644 --- a/scripts/gen-selfhost-env-reference.mjs +++ b/scripts/gen-selfhost-env-reference.mjs @@ -110,7 +110,13 @@ function isStaticEnvHelperCall(node) { // isStaticEnvHelperCall above (envString) because these take the var NAME as arg[0], not arg[1] after a // container. const PROCESS_ENV_NAME_HELPERS = new Set(["parsePositiveIntEnv"]); -const ENV_NAME_LITERAL_ARG_HELPERS = new Map([["resolveLocalStoreDbPath", 1]]); +const ENV_NAME_LITERAL_ARG_HELPERS = new Map([ + ["resolveLocalStoreDbPath", 1], + // createCliProvider(command, modelEnvKey, options, env) (packages/loopover-engine/src/miner/driver-factory.ts) + // reads env[modelEnvKey] -- a computed access AST-invisible without this, since modelEnvKey is a parameter, + // not a literal at the read site. The literal var name is only visible at the CALL site (arg index 1). (#6994) + ["createCliProvider", 1], +]); function isProcessEnvNameHelperCall(node) { return ( diff --git a/test/unit/miner-env-reference-script.test.ts b/test/unit/miner-env-reference-script.test.ts index 2ebc02e972..81c5a82ab1 100644 --- a/test/unit/miner-env-reference-script.test.ts +++ b/test/unit/miner-env-reference-script.test.ts @@ -38,6 +38,32 @@ function fixtureRoot(): string { return root; } +// #6994: the coding-agent driver lives in the shared engine package (packages/loopover-engine/src/miner), +// outside the miner package's own source roots, and reads its model env vars via a computed env[modelEnvKey] +// access -- only detectable through the literal env-var-name argument at the createCliProvider call site. +function fixtureRootWithEngineMinerRoot(): string { + const root = fixtureRoot(); + mkdirSync(join(root, "packages", "loopover-engine", "src", "miner"), { recursive: true }); + // Build the env type without angle brackets in this .ts file's string literals (keeps transforms happy). + const envType = ["Record", "<", "string, string | undefined", ">"].join(""); + writeFileSync( + join(root, "packages", "loopover-engine", "src", "miner", "driver-factory.ts"), + [ + `export function isPaused(env: ${envType}) {`, + ' return env.MINER_CODING_AGENT_PAUSED ?? "";', + "}", + `function createCliProvider(command: string, modelEnvKey: string, options: unknown, env: ${envType}) {`, + " return env[modelEnvKey];", + "}", + `export function build(env: ${envType}) {`, + ' return createCliProvider("claude", "MINER_CODING_AGENT_CLAUDE_MODEL", {}, env);', + "}", + "", + ].join("\n"), + ); + return root; +} + describe("generate-env-reference (#5179)", () => { it("filters to LOOPOVER_MINER_* and MINER_* vars only", () => { expect(isMinerEnvVar("LOOPOVER_MINER_CONFIG_DIR")).toBe(true); @@ -65,6 +91,16 @@ describe("generate-env-reference (#5179)", () => { ]); }); + it("REGRESSION (#6994): scans packages/loopover-engine/src/miner and detects createCliProvider's literal model-env-key argument", () => { + const names = collectMinerEnvVars({ rootDir: fixtureRootWithEngineMinerRoot() }).map((row) => row.name); + expect(names).toContain("MINER_CODING_AGENT_PAUSED"); // a plain env.X read in the new source root + // The literal name only ever appears at the createCliProvider CALL site -- env[modelEnvKey] inside the + // function itself is a computed access with no literal name to find, so this would be silently missed + // without ENV_NAME_LITERAL_ARG_HELPERS recognizing createCliProvider the same way it already recognizes + // resolveLocalStoreDbPath. + expect(names).toContain("MINER_CODING_AGENT_CLAUDE_MODEL"); + }); + it("renders a deterministic markdown table with names, references, and defaults", () => { expect( renderMinerEnvReferenceMarkdown([