auditor-lambda 0.3.25 → 0.3.27

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.
@@ -399,21 +399,122 @@ async function writeGeneratedMarkdown(targetPath, content) {
399
399
  };
400
400
  }
401
401
 
402
- async function removeGeneratedMarkdownIfMatches(targetPath, expectedContent) {
403
- const existing = await readTextIfExists(targetPath);
404
- if (existing === null) {
405
- return null;
402
+ function looksLikeAuditCodeSkill(content) {
403
+ const normalized = normalizeNewlines(content);
404
+ return (
405
+ /^name:\s*audit-code\b/mu.test(normalized)
406
+ || normalized.includes('Conversation-first autonomous code auditing workflow for the /audit-code command.')
407
+ || normalized.includes('The canonical entrypoint is `/audit-code` in conversation.')
408
+ );
409
+ }
410
+
411
+ function looksLikeAuditCodePrompt(content) {
412
+ const normalized = normalizeNewlines(content);
413
+ return (
414
+ normalized.includes('# `/audit-code`')
415
+ && (
416
+ normalized.includes('audit-code orchestrator')
417
+ || normalized.includes('Autonomous local loop code auditing')
418
+ || normalized.includes('Conversation-first autonomous code auditing workflow')
419
+ )
420
+ );
421
+ }
422
+
423
+ function looksLikeAuditCodeInterfaceMetadata(content) {
424
+ const normalized = normalizeNewlines(content);
425
+ return (
426
+ normalized.includes('audit-code')
427
+ && (
428
+ normalized.includes('display_name:')
429
+ || normalized.includes('short_description:')
430
+ || normalized.includes('default_prompt:')
431
+ )
432
+ && (
433
+ normalized.includes('/audit-code')
434
+ || normalized.includes('Start /audit-code')
435
+ )
436
+ );
437
+ }
438
+
439
+ async function buildLegacyAuditCodeSurfaceTargets(root) {
440
+ const targets = [
441
+ {
442
+ host: 'codex',
443
+ surface: 'skill',
444
+ path: join(root, '.codex', 'skills', 'audit-code', 'SKILL.md'),
445
+ matches: looksLikeAuditCodeSkill,
446
+ },
447
+ {
448
+ host: 'codex',
449
+ surface: 'prompt',
450
+ path: join(root, '.codex', 'skills', 'audit-code', 'audit-code.prompt.md'),
451
+ matches: looksLikeAuditCodePrompt,
452
+ },
453
+ {
454
+ host: 'opencode',
455
+ surface: 'command',
456
+ path: join(root, '.opencode', 'commands', 'audit-code.md'),
457
+ matches: looksLikeAuditCodePrompt,
458
+ },
459
+ {
460
+ host: 'opencode',
461
+ surface: 'skill',
462
+ path: join(root, '.opencode', 'skills', 'audit-code', 'SKILL.md'),
463
+ matches: looksLikeAuditCodeSkill,
464
+ },
465
+ {
466
+ host: 'opencode',
467
+ surface: 'prompt',
468
+ path: join(root, '.opencode', 'skills', 'audit-code', 'audit-code.prompt.md'),
469
+ matches: looksLikeAuditCodePrompt,
470
+ },
471
+ {
472
+ host: 'claude',
473
+ surface: 'command',
474
+ path: join(root, '.claude', 'commands', 'audit-code.md'),
475
+ matches: looksLikeAuditCodePrompt,
476
+ },
477
+ ];
478
+
479
+ const codexAgentDir = join(root, '.codex', 'skills', 'audit-code', 'agents');
480
+ const codexAgentEntries = await readdir(codexAgentDir).catch(() => []);
481
+ for (const entry of codexAgentEntries) {
482
+ targets.push({
483
+ host: 'codex',
484
+ surface: 'interface-metadata',
485
+ path: join(codexAgentDir, entry),
486
+ matches: looksLikeAuditCodeInterfaceMetadata,
487
+ });
406
488
  }
407
489
 
408
- if (normalizeNewlines(existing) !== normalizeNewlines(expectedContent)) {
409
- return null;
490
+ return targets;
491
+ }
492
+
493
+ async function findLegacyAuditCodeSurfaceFiles(root) {
494
+ const matches = [];
495
+ for (const target of await buildLegacyAuditCodeSurfaceTargets(root)) {
496
+ const existing = await readTextIfExists(target.path);
497
+ if (existing !== null && target.matches(existing)) {
498
+ matches.push(target.path);
499
+ }
410
500
  }
501
+ return matches;
502
+ }
411
503
 
412
- await unlink(targetPath);
413
- return {
414
- path: targetPath,
415
- mode: 'removed',
416
- };
504
+ async function removeLegacyAuditCodeSurfaceFiles(root) {
505
+ const removed = [];
506
+ for (const target of await buildLegacyAuditCodeSurfaceTargets(root)) {
507
+ const existing = await readTextIfExists(target.path);
508
+ if (existing === null || !target.matches(existing)) {
509
+ continue;
510
+ }
511
+ await unlink(target.path);
512
+ removed.push({
513
+ path: target.path,
514
+ mode: 'removed',
515
+ });
516
+ }
517
+ return removed;
417
518
  }
418
519
 
419
520
  async function writeGeneratedJson(targetPath, value) {
@@ -608,9 +709,7 @@ const OPENCODE_MCP_COMMAND_TEMPLATE = [
608
709
  'Use the auditor MCP tools as the primary interface to the audit workflow.',
609
710
  '',
610
711
  '1. Call `auditor_start_audit` to initialize and receive the first step.',
611
- '2. Check `step_kind` in the response:',
612
- ' - If `step_kind` is `"capability_check"`: immediately call `auditor_report_capability` with `can_dispatch_subagents: true` and `can_select_subagent_model: true`. Do not run shell commands or inspect prompt_content for this step.',
613
- ' - Otherwise: read `prompt_content` and follow it.',
712
+ '2. Read `prompt_content` in the response and follow it.',
614
713
  '3. When a step completes (not blocked), call `auditor_continue_audit` to advance.',
615
714
  '4. Stop when the step instructions say to stop.',
616
715
  '',
@@ -620,18 +719,9 @@ const OPENCODE_MCP_COMMAND_TEMPLATE = [
620
719
  ].join('\n');
621
720
 
622
721
  function renderOpenCodeProjectConfig(_root) {
623
- const launcher = `.audit-code/install/${MCP_LAUNCHER_FILENAME}`;
624
722
  const auditPermission = renderOpenCodePermissionConfig();
625
723
  return {
626
724
  $schema: 'https://opencode.ai/config.json',
627
- mcp: {
628
- auditor: {
629
- type: 'local',
630
- command: ['node', launcher],
631
- enabled: true,
632
- timeout: 10000,
633
- },
634
- },
635
725
  permission: auditPermission,
636
726
  agent: {
637
727
  auditor: {
@@ -803,14 +893,13 @@ function assertOpenCodeAuditPermissionConfig(permissionConfig, label) {
803
893
 
804
894
  function buildMergedOpenCodeProjectConfig(existing, root) {
805
895
  const generated = renderOpenCodeProjectConfig(root);
896
+ const mergedMcp = objectValue(existing.mcp);
897
+ delete mergedMcp.auditor;
806
898
  return {
807
899
  ...existing,
808
900
  $schema: existing.$schema ?? generated.$schema,
809
901
  command: removeManagedOpenCodeCommand(existing.command),
810
- mcp: {
811
- ...objectValue(existing.mcp),
812
- auditor: generated.mcp.auditor,
813
- },
902
+ mcp: mergedMcp,
814
903
  permission: {
815
904
  ...mergeOpenCodePermissionConfig(existing.permission, generated.permission),
816
905
  external_directory: { '*': 'allow' },
@@ -1857,6 +1946,18 @@ async function verifyInstalledBootstrap(argv) {
1857
1946
  };
1858
1947
  });
1859
1948
 
1949
+ await collectVerifyCheck(generalChecks, 'legacy_local_surfaces', async () => {
1950
+ const legacySurfaces = await findLegacyAuditCodeSurfaceFiles(root);
1951
+ if (legacySurfaces.length > 0) {
1952
+ throw new Error(
1953
+ `Legacy local /audit-code surfaces are still present: ${legacySurfaces.join(', ')}. Run "audit-code install" from ${root}.`,
1954
+ );
1955
+ }
1956
+ return {
1957
+ summary: 'No legacy local /audit-code command or skill surfaces were found.',
1958
+ };
1959
+ });
1960
+
1860
1961
  await collectVerifyCheck(generalChecks, 'shared_launcher_file', async () => {
1861
1962
  const launcher = await readFile(assetPaths.mcpLauncherPath, 'utf8');
1862
1963
  if (!launcher.includes('Unable to locate an audit-code executable')) {
@@ -2005,23 +2106,16 @@ async function verifyInstalledBootstrap(argv) {
2005
2106
  case 'opencode':
2006
2107
  await collectVerifyCheck(checks, 'opencode_config', async () => {
2007
2108
  const config = await readJson(assetPaths.opencodeConfigPath, 'OpenCode project config');
2008
- const mcpCommand = config?.mcp?.auditor?.command;
2009
- if (!Array.isArray(mcpCommand) || mcpCommand[0] !== 'node') {
2010
- throw new Error('OpenCode config must set mcp.auditor.command as a Node command array.');
2011
- }
2012
- if (!mcpCommand[1]?.includes(MCP_LAUNCHER_FILENAME)) {
2013
- throw new Error(`OpenCode config must reference ${MCP_LAUNCHER_FILENAME}, got ${mcpCommand[1] ?? 'missing'}.`);
2014
- }
2015
- if (config?.mcp?.auditor?.type !== 'local') {
2016
- throw new Error(`OpenCode config must set mcp.auditor.type to "local", got ${config?.mcp?.auditor?.type ?? 'missing'}.`);
2017
- }
2018
2109
  if (config?.command?.['audit-code']) {
2019
2110
  throw new Error('OpenCode project config must not define command["audit-code"]; the slash command is global npm-installed state. Run "audit-code install --host opencode" to remove the stale local command.');
2020
2111
  }
2112
+ if (config?.mcp?.auditor) {
2113
+ throw new Error('OpenCode project config must not define mcp.auditor; the MCP server is supplied by the global npm-installed config. Run "audit-code install --host opencode" to remove the stale project-level MCP entry.');
2114
+ }
2021
2115
  assertOpenCodeAuditPermissionConfig(config?.permission, 'permission');
2022
2116
  assertOpenCodeAuditPermissionConfig(config?.agent?.auditor?.permission, 'agent.auditor.permission');
2023
2117
  return {
2024
- summary: 'OpenCode project config has MCP server and audit permissions; /audit-code is supplied by the global npm-installed OpenCode command.',
2118
+ summary: 'OpenCode project config has audit permissions; MCP server and /audit-code command are supplied by the global npm-installed config.',
2025
2119
  path: assetPaths.opencodeConfigPath,
2026
2120
  };
2027
2121
  });
@@ -2149,7 +2243,11 @@ async function detectBootstrapRefreshReason(root, host) {
2149
2243
  );
2150
2244
 
2151
2245
  if (hostCatalog.has('codex') && (assetPaths.codexSkillPath || assetPaths.codexPromptPath)) {
2152
- return 'legacy_repo_local_codex_skill';
2246
+ return 'legacy_local_audit_code_surface';
2247
+ }
2248
+
2249
+ if ((await findLegacyAuditCodeSurfaceFiles(root)).length > 0) {
2250
+ return 'legacy_local_audit_code_surface';
2153
2251
  }
2154
2252
 
2155
2253
  for (const hostKey of getInstallHostKeys(host)) {
@@ -2199,6 +2297,9 @@ async function detectBootstrapRefreshReason(root, host) {
2199
2297
  if (opencodeConfig?.command?.['audit-code']) {
2200
2298
  return 'stale_host_asset:opencode:local_command';
2201
2299
  }
2300
+ if (opencodeConfig?.mcp?.auditor) {
2301
+ return 'stale_host_asset:opencode:project_mcp';
2302
+ }
2202
2303
  try {
2203
2304
  assertOpenCodeAuditPermissionConfig(opencodeConfig?.permission, 'permission');
2204
2305
  assertOpenCodeAuditPermissionConfig(opencodeConfig?.agent?.auditor?.permission, 'agent.auditor.permission');
@@ -2384,22 +2485,7 @@ async function installBootstrap(argv, options = {}) {
2384
2485
  );
2385
2486
  }
2386
2487
 
2387
- if (!profile.writeCodex) {
2388
- const legacyCodexSkillRemoval = await removeGeneratedMarkdownIfMatches(
2389
- join(root, '.codex', 'skills', 'audit-code', 'SKILL.md'),
2390
- skillSource,
2391
- );
2392
- if (legacyCodexSkillRemoval) {
2393
- results.push(legacyCodexSkillRemoval);
2394
- }
2395
- const legacyCodexPromptRemoval = await removeGeneratedMarkdownIfMatches(
2396
- join(root, '.codex', 'skills', 'audit-code', 'audit-code.prompt.md'),
2397
- promptSource,
2398
- );
2399
- if (legacyCodexPromptRemoval) {
2400
- results.push(legacyCodexPromptRemoval);
2401
- }
2402
- }
2488
+ results.push(...await removeLegacyAuditCodeSurfaceFiles(root));
2403
2489
 
2404
2490
  if (profile.writeCodex) {
2405
2491
  results.push(
@@ -2447,19 +2533,6 @@ async function installBootstrap(argv, options = {}) {
2447
2533
  }
2448
2534
 
2449
2535
  if (profile.writeOpenCode) {
2450
- // Remove legacy command/skill/prompt files unconditionally — these paths are exclusively
2451
- // owned by the auditor-lambda installer and keeping any version of them causes OpenCode to
2452
- // load the wrong slash command regardless of prompt content.
2453
- for (const legacyPath of [
2454
- join(root, '.opencode', 'commands', 'audit-code.md'),
2455
- join(root, '.opencode', 'skills', 'audit-code', 'SKILL.md'),
2456
- join(root, '.opencode', 'skills', 'audit-code', 'audit-code.prompt.md'),
2457
- ]) {
2458
- if (await fileExists(legacyPath)) {
2459
- await unlink(legacyPath);
2460
- results.push({ path: legacyPath, mode: 'removed' });
2461
- }
2462
- }
2463
2536
  results.push(
2464
2537
  await writeMergedGeneratedJson(
2465
2538
  assetPaths.opencodeConfigPath,
@@ -2625,6 +2698,22 @@ async function runDistCommand(commandName, argv, { ensureArtifactsDir = false }
2625
2698
  await run(nodeExecutable(), [distEntry, commandName, ...commandArgs]);
2626
2699
  }
2627
2700
 
2701
+ async function runDistCommandInline(commandName, argv) {
2702
+ const commandArgs = [...argv];
2703
+ const rootValue = resolve(getFlag(commandArgs, '--root') ?? '.');
2704
+ const artifactsDir = resolve(getFlag(commandArgs, '--artifacts-dir') ?? join(rootValue, '.audit-artifacts'));
2705
+
2706
+ setDefaultFlag(commandArgs, '--root', rootValue);
2707
+ setDefaultFlag(commandArgs, '--artifacts-dir', artifactsDir);
2708
+
2709
+ await mkdir(artifactsDir, { recursive: true });
2710
+ await ensureBuilt();
2711
+
2712
+ const distUrl = new URL(`file:///${distEntry.replace(/\\/g, '/')}`);
2713
+ const cli = await import(distUrl.href);
2714
+ await cli.runCli([process.execPath, distEntry, commandName, ...commandArgs]);
2715
+ }
2716
+
2628
2717
  export async function runAuditCodeWrapper({
2629
2718
  usageName,
2630
2719
  argv = process.argv.slice(2),
@@ -2683,7 +2772,7 @@ export async function runAuditCodeWrapper({
2683
2772
  }
2684
2773
 
2685
2774
  if (argv[0] === 'mcp') {
2686
- await runDistCommand('mcp', argv.slice(1), { ensureArtifactsDir: true });
2775
+ await runDistCommandInline('mcp', argv.slice(1));
2687
2776
  return;
2688
2777
  }
2689
2778
 
package/dist/cli.js CHANGED
@@ -2238,8 +2238,18 @@ async function prepareDispatchArtifacts(params) {
2238
2238
  const lensDefsPath = join(packageRoot, "dispatch", "lens-definitions.json");
2239
2239
  const lensDefs = await readJsonFile(lensDefsPath);
2240
2240
  await mkdir(taskResultsDir, { recursive: true });
2241
- const lineIndex = Object.fromEntries(tasks.flatMap((task) => Object.entries(task.file_line_counts ?? {})));
2242
- const orderedTasks = orderTasksForPacketReview(tasks, {
2241
+ // On resume: skip tasks whose result files already exist from a prior dispatch.
2242
+ const priorResultTaskIds = new Set();
2243
+ for (const task of tasks) {
2244
+ if (existsSync(taskResultPath(taskResultsDir, task.task_id))) {
2245
+ priorResultTaskIds.add(task.task_id);
2246
+ }
2247
+ }
2248
+ const dispatchTasks = priorResultTaskIds.size > 0
2249
+ ? tasks.filter((task) => !priorResultTaskIds.has(task.task_id))
2250
+ : tasks;
2251
+ const lineIndex = Object.fromEntries(dispatchTasks.flatMap((task) => Object.entries(task.file_line_counts ?? {})));
2252
+ const orderedTasks = orderTasksForPacketReview(dispatchTasks, {
2243
2253
  graphBundle: bundle.graph_bundle,
2244
2254
  lineIndex,
2245
2255
  });
@@ -2258,6 +2268,15 @@ async function prepareDispatchArtifacts(params) {
2258
2268
  }
2259
2269
  const plan = [];
2260
2270
  const resultMapEntries = [];
2271
+ for (const task of tasks) {
2272
+ if (priorResultTaskIds.has(task.task_id)) {
2273
+ resultMapEntries.push({
2274
+ packet_id: "__prior_dispatch__",
2275
+ task_id: task.task_id,
2276
+ result_path: taskResultPath(taskResultsDir, task.task_id),
2277
+ });
2278
+ }
2279
+ }
2261
2280
  let largestPacketId = null;
2262
2281
  let largestLines = 0;
2263
2282
  let largestEstimatedTokens = 0;
@@ -2473,7 +2492,7 @@ async function prepareDispatchArtifacts(params) {
2473
2492
  providerName: quotaProviderName,
2474
2493
  sessionConfig,
2475
2494
  hostModel,
2476
- requestedConcurrency: sessionConfig.parallel_workers ?? 1,
2495
+ requestedConcurrency: sessionConfig.parallel_workers ?? plan.length,
2477
2496
  estimatedPacketTokens: avgPacketTokens,
2478
2497
  quotaStateEntry,
2479
2498
  });
@@ -2518,6 +2537,7 @@ async function prepareDispatchArtifacts(params) {
2518
2537
  dispatch_quota_path: dispatchQuotaPath,
2519
2538
  packet_count: plan.length,
2520
2539
  task_count: orderedTasks.length,
2540
+ skipped_task_count: priorResultTaskIds.size,
2521
2541
  largest_packet: largestPacketId
2522
2542
  ? {
2523
2543
  packet_id: largestPacketId,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auditor-lambda",
3
- "version": "0.3.25",
3
+ "version": "0.3.27",
4
4
  "private": false,
5
5
  "description": "Portable hybrid code-auditing framework for arbitrary repositories.",
6
6
  "type": "module",
@@ -94,14 +94,25 @@ function renderOpenCodeExternalDirectoryPermission() {
94
94
 
95
95
  function renderGlobalMcpLauncher(installedPkgRoot) {
96
96
  return [
97
- "import { access, readFile } from 'node:fs/promises';",
97
+ "import { access, readFile, appendFile } from 'node:fs/promises';",
98
98
  "import { constants } from 'node:fs';",
99
99
  "import { spawn } from 'node:child_process';",
100
100
  "import { join } from 'node:path';",
101
+ "import { homedir } from 'node:os';",
101
102
  '',
102
103
  'const repoRoot = process.cwd();',
103
104
  "const artifactsDir = join(repoRoot, '.audit-artifacts');",
104
105
  `const globalPackageRoot = ${JSON.stringify(installedPkgRoot)};`,
106
+ "const logPath = join(homedir(), '.audit-code', 'mcp-server.log');",
107
+ '',
108
+ 'async function log(msg) {',
109
+ ' try {',
110
+ ' const ts = new Date().toISOString();',
111
+ " await appendFile(logPath, `${ts} ${msg}\\n`, 'utf8');",
112
+ ' } catch {',
113
+ ' // ignore log failures',
114
+ ' }',
115
+ '}',
105
116
  '',
106
117
  'async function exists(path) {',
107
118
  ' try {',
@@ -134,6 +145,7 @@ function renderGlobalMcpLauncher(installedPkgRoot) {
134
145
  " const sharedArgs = ['mcp', '--root', repoRoot, '--artifacts-dir', artifactsDir];",
135
146
  '',
136
147
  ' if (await exists(localPackageEntrypoint)) {',
148
+ " await log(`launching local node_modules candidate: ${localPackageEntrypoint}`);",
137
149
  ' return await spawnForward(process.execPath, [localPackageEntrypoint, ...sharedArgs]);',
138
150
  ' }',
139
151
  '',
@@ -141,6 +153,7 @@ function renderGlobalMcpLauncher(installedPkgRoot) {
141
153
  ' try {',
142
154
  " const packageJson = JSON.parse(await readFile(repoPackageJsonPath, 'utf8'));",
143
155
  " if (packageJson?.name === 'auditor-lambda') {",
156
+ " await log(`launching repo-root candidate: ${join(repoRoot, 'audit-code.mjs')}`);",
144
157
  " return await spawnForward(process.execPath, [join(repoRoot, 'audit-code.mjs'), ...sharedArgs]);",
145
158
  ' }',
146
159
  ' } catch {',
@@ -149,14 +162,17 @@ function renderGlobalMcpLauncher(installedPkgRoot) {
149
162
  ' }',
150
163
  '',
151
164
  ' if (globalPackageEntrypoint && await exists(globalPackageEntrypoint)) {',
165
+ " await log(`launching global candidate: ${globalPackageEntrypoint}`);",
152
166
  ' return await spawnForward(process.execPath, [globalPackageEntrypoint, ...sharedArgs]);',
153
167
  ' }',
154
168
  '',
155
169
  ' if (await exists(localBin)) {',
170
+ " await log(`launching local bin candidate: ${localBin}`);",
156
171
  ' return await spawnForward(localBin, sharedArgs);',
157
172
  ' }',
158
173
  '',
159
174
  " const pathCandidate = process.platform === 'win32' ? 'audit-code.cmd' : 'audit-code';",
175
+ " await log(`trying PATH candidate: ${pathCandidate}`);",
160
176
  ' let exitCode = await spawnForward(pathCandidate, sharedArgs).catch(() => null);',
161
177
  " if (typeof exitCode === 'number') {",
162
178
  ' return exitCode;',
@@ -167,12 +183,18 @@ function renderGlobalMcpLauncher(installedPkgRoot) {
167
183
  ' return exitCode;',
168
184
  ' }',
169
185
  '',
186
+ " await log('ERROR: no candidate found');",
170
187
  ' throw new Error(',
171
188
  " 'Unable to locate an audit-code executable. Install auditor-lambda globally or as a local dependency.',",
172
189
  ' );',
173
190
  '}',
174
191
  '',
175
- 'const code = await tryCandidates();',
192
+ "log(`run-mcp-server.mjs started: node=${process.execPath} cwd=${repoRoot} globalPkg=${globalPackageRoot}`).catch(() => {});",
193
+ 'const code = await tryCandidates().catch(async (err) => {',
194
+ " await log(`FATAL: ${err.message}`);",
195
+ ' process.stderr.write(err.message + "\\n");',
196
+ ' return 1;',
197
+ '});',
176
198
  'process.exitCode = code;',
177
199
  '',
178
200
  ].join('\n');
@@ -261,9 +283,7 @@ const OPENCODE_MCP_COMMAND_TEMPLATE = [
261
283
  'Use the auditor MCP tools as the primary interface to the audit workflow.',
262
284
  '',
263
285
  '1. Call `auditor_start_audit` to initialize and receive the first step.',
264
- '2. Check `step_kind` in the response:',
265
- ' - If `step_kind` is `"capability_check"`: immediately call `auditor_report_capability` with `can_dispatch_subagents: true` and `can_select_subagent_model: true`. Do not run shell commands or inspect prompt_content for this step.',
266
- ' - Otherwise: read `prompt_content` and follow it.',
286
+ '2. Read `prompt_content` in the response and follow it.',
267
287
  '3. When a step completes (not blocked), call `auditor_continue_audit` to advance.',
268
288
  '4. Stop when the step instructions say to stop.',
269
289
  '',
@@ -276,8 +296,8 @@ function mergeOpenCodeGlobalConfig(existing) {
276
296
  const parsed = existing ? JSON.parse(existing) : {};
277
297
  const auditPermission = renderOpenCodePermissionConfig();
278
298
  const existingAuditor = objectValue(objectValue(parsed.agent).auditor);
279
- const globalLauncherPath = replaceBackslashes(join(homedir(), '.audit-code', 'run-mcp-server.mjs'));
280
299
  const nodeExecPath = replaceBackslashes(process.execPath);
300
+ const pkgEntrypoint = replaceBackslashes(join(pkgRoot, 'audit-code.mjs'));
281
301
  return {
282
302
  ...parsed,
283
303
  command: {
@@ -295,7 +315,7 @@ function mergeOpenCodeGlobalConfig(existing) {
295
315
  ...objectValue(parsed.mcp),
296
316
  auditor: {
297
317
  type: 'local',
298
- command: [nodeExecPath, globalLauncherPath],
318
+ command: [nodeExecPath, pkgEntrypoint, 'mcp'],
299
319
  enabled: true,
300
320
  timeout: 10000,
301
321
  },