auditor-lambda 0.6.3 → 0.6.5
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/dist/cli/dispatch.d.ts +2 -1
- package/dist/cli/dispatch.js +12 -2
- package/dist/cli.js +17 -5
- package/dist/providers/index.js +10 -3
- package/package.json +1 -1
- package/scripts/postinstall.mjs +88 -2
package/dist/cli/dispatch.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SessionConfig, DispatchModelHint } from "@audit-tools/shared";
|
|
1
|
+
import type { ProviderRateLimits, SessionConfig, DispatchModelHint } from "@audit-tools/shared";
|
|
2
2
|
import type { ArtifactBundle } from "../io/artifacts.js";
|
|
3
3
|
import type { AuditTask } from "../types.js";
|
|
4
4
|
export declare const LARGE_FILE_PACKET_TARGET_LINES = 2500;
|
|
@@ -76,5 +76,6 @@ export declare function prepareDispatchArtifacts(params: {
|
|
|
76
76
|
root?: string;
|
|
77
77
|
sessionConfig?: SessionConfig;
|
|
78
78
|
hostModel?: string | null;
|
|
79
|
+
queryLimits?: (model: string | null) => Promise<ProviderRateLimits | null>;
|
|
79
80
|
hostActiveSubagentLimit?: number | null;
|
|
80
81
|
}): Promise<PrepareDispatchResult>;
|
package/dist/cli/dispatch.js
CHANGED
|
@@ -2,12 +2,13 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
import { existsSync } from "node:fs";
|
|
3
3
|
import { isAbsolute, join, relative, resolve } from "node:path";
|
|
4
4
|
import { isFileMissingError, readJsonFile, writeJsonFile } from "@audit-tools/shared";
|
|
5
|
+
import { buildQuotaSource } from "@audit-tools/shared/quota/compositeQuotaSource";
|
|
5
6
|
import { loadArtifactBundle } from "../io/artifacts.js";
|
|
6
7
|
import { orderTasksForPacketReview, buildReviewPackets, sizeIndexFromManifest, } from "../orchestrator/reviewPackets.js";
|
|
7
8
|
import { buildFileAnchorSummary } from "../orchestrator/fileAnchors.js";
|
|
8
9
|
import { resolveFreshSessionProviderName } from "../providers/index.js";
|
|
9
10
|
import { loadSessionConfig } from "../supervisor/sessionConfig.js";
|
|
10
|
-
import { scheduleWave, buildProviderModelKey, readQuotaState, resolveHostActiveSubagentLimit, lookupDiscoveredLimits, } from "../quota/index.js";
|
|
11
|
+
import { scheduleWave, buildProviderModelKey, readQuotaState, resolveHostActiveSubagentLimit, lookupDiscoveredLimits, mergeDiscoveredLimits, } from "../quota/index.js";
|
|
11
12
|
import { taskResultPath, packetPromptPath, artifactNameForId, toBase64Url, fromBase64Url, getFlag, } from "./args.js";
|
|
12
13
|
export const LARGE_FILE_PACKET_TARGET_LINES = 2500;
|
|
13
14
|
export const SMALL_MODEL_HINT_MAX_LINES = 500;
|
|
@@ -462,7 +463,15 @@ export async function prepareDispatchArtifacts(params) {
|
|
|
462
463
|
explicitLimit: params.hostActiveSubagentLimit,
|
|
463
464
|
sessionConfig,
|
|
464
465
|
});
|
|
466
|
+
const providerLimits = await params.queryLimits?.(hostModel)
|
|
467
|
+
.then((r) => r ? { ...r, source: "provider_query" } : null)
|
|
468
|
+
.catch(() => null)
|
|
469
|
+
?? null;
|
|
465
470
|
const dispatchCachedLimits = await lookupDiscoveredLimits(quotaProviderKey).catch(() => null);
|
|
471
|
+
const discoveredLimits = mergeDiscoveredLimits(providerLimits, dispatchCachedLimits);
|
|
472
|
+
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ?? 24;
|
|
473
|
+
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
474
|
+
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(quotaProviderKey).catch(() => null);
|
|
466
475
|
const waveSchedule = scheduleWave({
|
|
467
476
|
providerName: quotaProviderName,
|
|
468
477
|
sessionConfig,
|
|
@@ -471,7 +480,8 @@ export async function prepareDispatchArtifacts(params) {
|
|
|
471
480
|
estimatedSlotTokens: perPacketTokens,
|
|
472
481
|
quotaStateEntry,
|
|
473
482
|
hostConcurrencyLimit,
|
|
474
|
-
discoveredLimits
|
|
483
|
+
discoveredLimits,
|
|
484
|
+
quotaSourceSnapshot,
|
|
475
485
|
});
|
|
476
486
|
const dispatchQuota = {
|
|
477
487
|
contract_version: "audit-code-dispatch-quota/v1alpha2",
|
package/dist/cli.js
CHANGED
|
@@ -12,6 +12,7 @@ import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.j
|
|
|
12
12
|
import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
|
|
13
13
|
import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, AUDIT_REPORT_FILENAME, } from "./io/artifacts.js";
|
|
14
14
|
import { isFileMissingError, readJsonFile, writeJsonFile, prefixValidationIssues, RunLogger } from "@audit-tools/shared";
|
|
15
|
+
import { buildQuotaSource } from "@audit-tools/shared/quota/compositeQuotaSource";
|
|
15
16
|
import { validateArtifactBundle } from "./validation/artifacts.js";
|
|
16
17
|
import { validateAuditResults, formatAuditResultIssues, } from "./validation/auditResults.js";
|
|
17
18
|
import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
|
|
@@ -35,7 +36,7 @@ import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
|
|
|
35
36
|
import { estimateTaskGroupTokens, sizeIndexFromManifest, } from "./orchestrator/reviewPackets.js";
|
|
36
37
|
import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
|
|
37
38
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
38
|
-
import { scheduleWave, buildProviderModelKey, readQuotaState, recordWaveOutcome, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, detectRateLimitError, computeCooldownUntil, runSlidingWindow,
|
|
39
|
+
import { scheduleWave, buildProviderModelKey, readQuotaState, recordWaveOutcome, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, detectRateLimitError, computeCooldownUntil, runSlidingWindow, lookupDiscoveredLimits, updateDiscoveredLimits, mergeDiscoveredLimits, getHeaderExtractorForProvider, setQuotaStateDir, } from "./quota/index.js";
|
|
39
40
|
// Re-exports from extracted modules
|
|
40
41
|
export { resolveHostDispatchCapability, DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, getArtifactsDir, getRootDir, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, chunkArray, getUiMode, looksLikeCliFlag, countLines, warnIfNotGitRepo, } from "./cli/args.js";
|
|
41
42
|
import { DIRECT_CLI_DEFAULTS, getFlag, hasFlag, getOptionalBooleanFlag, fromBase64Url, renderCommand, summarizeLaunchExit, taskResultPath, readStdinText, getArtifactsDir, getRootDir, warnIfNotGitRepo, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, getExplicitProvider, getHostModel, getHostMaxActiveSubagents, getQuotaProbeMode, resolveRunProviderName, chunkArray, getUiMode, looksLikeCliFlag, resolveHostDispatchCapability, countLines, listBatchResultFiles, } from "./cli/args.js";
|
|
@@ -915,11 +916,16 @@ async function renderSemanticReviewStep(params) {
|
|
|
915
916
|
},
|
|
916
917
|
});
|
|
917
918
|
}
|
|
919
|
+
const sessionConfig = await loadSessionConfig(artifactsDir).catch(() => ({}));
|
|
920
|
+
const provider = createFreshSessionProvider(undefined, sessionConfig);
|
|
918
921
|
const dispatch = await prepareDispatchArtifacts({
|
|
919
922
|
packageRoot,
|
|
920
923
|
runId: activeReviewRun.run_id,
|
|
921
924
|
artifactsDir,
|
|
922
925
|
root,
|
|
926
|
+
sessionConfig,
|
|
927
|
+
hostModel: sessionConfig.block_quota?.host_model ?? null,
|
|
928
|
+
queryLimits: provider.queryLimits?.bind(provider),
|
|
923
929
|
hostActiveSubagentLimit: params.hostMaxActiveSubagents,
|
|
924
930
|
});
|
|
925
931
|
const mergeCommand = mergeAndIngestCommand(artifactsDir, activeReviewRun.run_id);
|
|
@@ -1473,7 +1479,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1473
1479
|
const cachedLimits = await lookupDiscoveredLimits(providerModelKey).catch(() => null);
|
|
1474
1480
|
const discoveredLimits = mergeDiscoveredLimits(providerLimits, cachedLimits);
|
|
1475
1481
|
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ?? 24;
|
|
1476
|
-
const quotaSource =
|
|
1482
|
+
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
1477
1483
|
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(providerModelKey).catch(() => null);
|
|
1478
1484
|
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({
|
|
1479
1485
|
sessionConfig,
|
|
@@ -2155,12 +2161,18 @@ async function cmdPrepareDispatch(argv) {
|
|
|
2155
2161
|
const runId = getFlag(argv, "--run-id");
|
|
2156
2162
|
if (!runId)
|
|
2157
2163
|
throw new Error("prepare-dispatch requires --run-id <run_id>");
|
|
2164
|
+
const artifactsDir = getArtifactsDir(argv);
|
|
2165
|
+
const sessionConfig = await loadSessionConfig(artifactsDir).catch(() => ({}));
|
|
2166
|
+
const provider = createFreshSessionProvider(getExplicitProvider(argv), sessionConfig);
|
|
2167
|
+
const hostModel = getHostModel(argv) ?? sessionConfig.block_quota?.host_model ?? null;
|
|
2158
2168
|
const result = await prepareDispatchArtifacts({
|
|
2159
2169
|
packageRoot,
|
|
2160
2170
|
runId,
|
|
2161
|
-
artifactsDir
|
|
2171
|
+
artifactsDir,
|
|
2162
2172
|
root: getFlag(argv, "--root") ? getRootDir(argv) : undefined,
|
|
2163
|
-
|
|
2173
|
+
sessionConfig,
|
|
2174
|
+
hostModel,
|
|
2175
|
+
queryLimits: provider.queryLimits?.bind(provider),
|
|
2164
2176
|
hostActiveSubagentLimit: getHostMaxActiveSubagents(argv),
|
|
2165
2177
|
});
|
|
2166
2178
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -2958,7 +2970,7 @@ async function cmdQuota(argv) {
|
|
|
2958
2970
|
explicitLimit: getHostMaxActiveSubagents(argv),
|
|
2959
2971
|
sessionConfig,
|
|
2960
2972
|
});
|
|
2961
|
-
const quotaSource =
|
|
2973
|
+
const quotaSource = buildQuotaSource({ halfLifeHours });
|
|
2962
2974
|
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(providerModelKey).catch(() => null);
|
|
2963
2975
|
const queryDiscoveredLimits = await lookupDiscoveredLimits(providerModelKey).catch(() => null);
|
|
2964
2976
|
const waveSchedule = scheduleWave({
|
package/dist/providers/index.js
CHANGED
|
@@ -22,8 +22,11 @@ function commandExists(command) {
|
|
|
22
22
|
return result.status === 0;
|
|
23
23
|
}
|
|
24
24
|
export function resolveFreshSessionProviderName(name, sessionConfig = {}, options = {}) {
|
|
25
|
-
const requestedProvider = name ?? sessionConfig.provider
|
|
26
|
-
|
|
25
|
+
const requestedProvider = name ?? sessionConfig.provider;
|
|
26
|
+
const shouldAutoDetect = requestedProvider === undefined ||
|
|
27
|
+
requestedProvider === "auto" ||
|
|
28
|
+
(name === undefined && requestedProvider === "local-subprocess");
|
|
29
|
+
if (!shouldAutoDetect) {
|
|
27
30
|
return requestedProvider;
|
|
28
31
|
}
|
|
29
32
|
const env = options.env ?? process.env;
|
|
@@ -65,8 +68,12 @@ export function resolveFreshSessionProviderName(name, sessionConfig = {}, option
|
|
|
65
68
|
export function createFreshSessionProvider(name, sessionConfig = {}) {
|
|
66
69
|
const providerName = resolveFreshSessionProviderName(name, sessionConfig);
|
|
67
70
|
const opentoken = sessionConfig.opentoken ?? {};
|
|
71
|
+
const requestedProvider = name ?? sessionConfig.provider;
|
|
72
|
+
const autoDetectionRequested = requestedProvider === undefined ||
|
|
73
|
+
requestedProvider === "auto" ||
|
|
74
|
+
(name === undefined && requestedProvider === "local-subprocess");
|
|
68
75
|
if (providerName === "local-subprocess" &&
|
|
69
|
-
|
|
76
|
+
autoDetectionRequested) {
|
|
70
77
|
process.stderr.write("audit-code: auto provider resolved to local-subprocess — no capable agent provider detected. " +
|
|
71
78
|
"Agent tasks will require manual dispatch. Configure claude-code, opencode, or subprocess-template " +
|
|
72
79
|
"in session-config.json to automate them.\n");
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -5,6 +5,7 @@ import { mkdirSync, existsSync, readFileSync, writeFileSync } from 'fs';
|
|
|
5
5
|
import { fileURLToPath } from 'url';
|
|
6
6
|
|
|
7
7
|
const pkgRoot = dirname(dirname(fileURLToPath(import.meta.url)));
|
|
8
|
+
const packageVersion = JSON.parse(readFileSync(join(pkgRoot, 'package.json'), 'utf8')).version ?? '0.0.0';
|
|
8
9
|
const promptSourceFile = join(pkgRoot, 'skills', 'audit-code', 'audit-code.prompt.md');
|
|
9
10
|
const skillSourceFile = join(pkgRoot, 'skills', 'audit-code', 'SKILL.md');
|
|
10
11
|
const codexOpenAiAgentSourceFile = join(pkgRoot, 'skills', 'audit-code', 'agents', 'openai.yaml');
|
|
@@ -99,8 +100,8 @@ function renderGlobalMcpLauncher(installedPkgRoot) {
|
|
|
99
100
|
"import { join } from 'node:path';",
|
|
100
101
|
"import { homedir } from 'node:os';",
|
|
101
102
|
'',
|
|
102
|
-
|
|
103
|
-
"const artifactsDir = join(repoRoot, '.audit-artifacts');",
|
|
103
|
+
"const repoRoot = process.env.AUDIT_CODE_REPO_ROOT || process.cwd();",
|
|
104
|
+
"const artifactsDir = process.env.AUDIT_CODE_ARTIFACTS_DIR || join(repoRoot, '.audit-artifacts');",
|
|
104
105
|
`const globalPackageRoot = ${JSON.stringify(installedPkgRoot)};`,
|
|
105
106
|
"const logPath = join(homedir(), '.audit-code', 'mcp-server.log');",
|
|
106
107
|
'',
|
|
@@ -330,6 +331,37 @@ function mergeOpenCodeGlobalConfig(existing) {
|
|
|
330
331
|
};
|
|
331
332
|
}
|
|
332
333
|
|
|
334
|
+
function claudePluginExternalDir() {
|
|
335
|
+
return join(homedir(), '.claude', 'plugins', 'marketplaces', 'claude-plugins-official', 'external_plugins', 'audit-code');
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
function claudeDesktopConfigPath() {
|
|
339
|
+
if (process.platform === 'win32') {
|
|
340
|
+
return join(process.env.APPDATA || join(homedir(), 'AppData', 'Roaming'), 'Claude', 'claude_desktop_config.json');
|
|
341
|
+
}
|
|
342
|
+
if (process.platform === 'darwin') {
|
|
343
|
+
return join(homedir(), 'Library', 'Application Support', 'Claude', 'claude_desktop_config.json');
|
|
344
|
+
}
|
|
345
|
+
return join(homedir(), '.config', 'Claude', 'claude_desktop_config.json');
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function mergeClaudeDesktopConfig(existing, globalMcpLauncherPath) {
|
|
349
|
+
const parsed = existing ? JSON.parse(existing) : {};
|
|
350
|
+
const mcpServers = parsed.mcpServers && typeof parsed.mcpServers === 'object' && !Array.isArray(parsed.mcpServers)
|
|
351
|
+
? parsed.mcpServers
|
|
352
|
+
: {};
|
|
353
|
+
return {
|
|
354
|
+
...parsed,
|
|
355
|
+
mcpServers: {
|
|
356
|
+
...mcpServers,
|
|
357
|
+
auditor: {
|
|
358
|
+
command: 'node',
|
|
359
|
+
args: [replaceBackslashes(globalMcpLauncherPath)],
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
|
|
333
365
|
function installMergedJson(path, buildMerged) {
|
|
334
366
|
const existing = existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
335
367
|
const merged = buildMerged(existing);
|
|
@@ -431,3 +463,57 @@ try {
|
|
|
431
463
|
} catch (err) {
|
|
432
464
|
console.warn(`audit-code: could not install Antigravity plugin (${err.message})`);
|
|
433
465
|
}
|
|
466
|
+
|
|
467
|
+
// Install Claude Desktop plugin so /audit-code appears in the slash-command menu
|
|
468
|
+
// Claude Desktop reads external plugins from ~/.claude/plugins/marketplaces/claude-plugins-official/external_plugins/
|
|
469
|
+
const claudePluginDir = claudePluginExternalDir();
|
|
470
|
+
const claudePluginManifestPath = join(claudePluginDir, '.claude-plugin', 'plugin.json');
|
|
471
|
+
const claudePluginCommandPath = join(claudePluginDir, 'commands', 'audit-code.md');
|
|
472
|
+
const claudePluginSkillPath = join(claudePluginDir, 'skills', 'audit-code', 'SKILL.md');
|
|
473
|
+
try {
|
|
474
|
+
const manifest = {
|
|
475
|
+
name: 'audit-code',
|
|
476
|
+
description: 'Autonomous local-loop code auditing workflow',
|
|
477
|
+
version: packageVersion,
|
|
478
|
+
author: {
|
|
479
|
+
name: 'auditor-lambda',
|
|
480
|
+
url: 'https://github.com/OhOkThisIsFine/auditor-lambda',
|
|
481
|
+
},
|
|
482
|
+
homepage: 'https://github.com/OhOkThisIsFine/auditor-lambda',
|
|
483
|
+
repository: 'https://github.com/OhOkThisIsFine/auditor-lambda',
|
|
484
|
+
license: 'MIT',
|
|
485
|
+
keywords: ['audit', 'code-audit', 'static-analysis', 'orchestration'],
|
|
486
|
+
};
|
|
487
|
+
const manifestAction = writeGeneratedFile(
|
|
488
|
+
claudePluginManifestPath,
|
|
489
|
+
Buffer.from(JSON.stringify(manifest, null, 2) + '\n'),
|
|
490
|
+
);
|
|
491
|
+
console.log(`audit-code: ${manifestAction} Claude Desktop plugin manifest at ${claudePluginManifestPath}`);
|
|
492
|
+
|
|
493
|
+
const commandAction = writeGeneratedFile(claudePluginCommandPath, promptSource);
|
|
494
|
+
console.log(`audit-code: ${commandAction} Claude Desktop plugin command at ${claudePluginCommandPath}`);
|
|
495
|
+
|
|
496
|
+
const skillAction = writeGeneratedFile(claudePluginSkillPath, skillSource);
|
|
497
|
+
console.log(`audit-code: ${skillAction} Claude Desktop plugin skill at ${claudePluginSkillPath}`);
|
|
498
|
+
|
|
499
|
+
console.log(`audit-code: restart Claude Desktop for /audit-code to appear in the slash-command menu`);
|
|
500
|
+
} catch (err) {
|
|
501
|
+
console.warn(`audit-code: could not install Claude Desktop plugin (${err.message})`);
|
|
502
|
+
console.warn(` Plugin directory: ${claudePluginDir}`);
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
// Register auditor MCP server with Claude Desktop so /audit-code appears in its slash-command menu
|
|
506
|
+
const claudeDesktopConfig = claudeDesktopConfigPath();
|
|
507
|
+
try {
|
|
508
|
+
const action = installMergedJson(claudeDesktopConfig, (existing) =>
|
|
509
|
+
mergeClaudeDesktopConfig(existing, globalMcpLauncherPath),
|
|
510
|
+
);
|
|
511
|
+
console.log(`audit-code: ${action} Claude Desktop MCP server entry in ${claudeDesktopConfig}`);
|
|
512
|
+
console.log(`audit-code: restart Claude Desktop for /audit-code to appear`);
|
|
513
|
+
console.log(`audit-code: to target a specific repo, set AUDIT_CODE_REPO_ROOT in Claude Desktop's MCP env settings`);
|
|
514
|
+
} catch (err) {
|
|
515
|
+
console.warn(`audit-code: could not update Claude Desktop config (${err.message})`);
|
|
516
|
+
console.warn(` To register manually, add "mcpServers.auditor" to:`);
|
|
517
|
+
console.warn(` ${claudeDesktopConfig}`);
|
|
518
|
+
console.warn(` with command "node" and args ["${replaceBackslashes(globalMcpLauncherPath)}"]`);
|
|
519
|
+
}
|