auditor-lambda 0.7.0 → 0.9.0
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/README.md +0 -21
- package/audit-code-wrapper-lib.mjs +149 -129
- package/dist/adapters/normalizeExternal.js +6 -3
- package/dist/cli/args.d.ts +0 -1
- package/dist/cli/args.js +0 -6
- package/dist/cli/auditStep.js +7 -1
- package/dist/cli/dispatch.js +3 -2
- package/dist/cli/lineIndex.js +4 -1
- package/dist/cli/mergeAndIngestCommand.d.ts +1 -0
- package/dist/cli/mergeAndIngestCommand.js +219 -0
- package/dist/cli/nextStepCommand.js +5 -1
- package/dist/cli/runToCompletion.d.ts +9 -0
- package/dist/cli/runToCompletion.js +655 -480
- package/dist/cli/statusCommand.d.ts +1 -0
- package/dist/cli/statusCommand.js +113 -0
- package/dist/cli/submitPacketCommand.d.ts +1 -0
- package/dist/cli/submitPacketCommand.js +155 -0
- package/dist/cli/workerResult.d.ts +1 -1
- package/dist/cli/workerRunCommand.d.ts +1 -0
- package/dist/cli/workerRunCommand.js +88 -0
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +14 -565
- package/dist/extractors/analyzers/sql.js +4 -1
- package/dist/extractors/analyzers/treeSitter.js +29 -15
- package/dist/extractors/analyzers/typescript.js +10 -8
- package/dist/extractors/designAssessment.js +43 -24
- package/dist/extractors/graph.js +151 -75
- package/dist/extractors/pathPatterns.js +17 -5
- package/dist/io/artifacts.d.ts +3 -1
- package/dist/io/artifacts.js +18 -2
- package/dist/io/runArtifactTypes.d.ts +18 -0
- package/dist/io/runArtifactTypes.js +1 -0
- package/dist/io/runArtifacts.d.ts +2 -18
- package/dist/io/runArtifacts.js +14 -3
- package/dist/mcp/server.js +9 -0
- package/dist/orchestrator/advance.js +38 -22
- package/dist/orchestrator/artifactFreshness.js +14 -4
- package/dist/orchestrator/autoFixExecutor.d.ts +2 -2
- package/dist/orchestrator/autoFixExecutor.js +26 -8
- package/dist/orchestrator/dependencyMap.d.ts +1 -1
- package/dist/orchestrator/dependencyMap.js +7 -1
- package/dist/orchestrator/executorResult.d.ts +12 -0
- package/dist/orchestrator/executorResult.js +1 -0
- package/dist/orchestrator/fileAnchors.js +14 -3
- package/dist/orchestrator/fileIntegrity.d.ts +1 -0
- package/dist/orchestrator/fileIntegrity.js +12 -3
- package/dist/orchestrator/flowCoverage.js +1 -0
- package/dist/orchestrator/flowRequeue.js +4 -1
- package/dist/orchestrator/graphEnrichmentExecutor.d.ts +1 -1
- package/dist/orchestrator/graphEnrichmentExecutor.js +3 -1
- package/dist/orchestrator/ingestionExecutors.d.ts +11 -0
- package/dist/orchestrator/ingestionExecutors.js +237 -0
- package/dist/orchestrator/intakeExecutors.d.ts +3 -0
- package/dist/orchestrator/intakeExecutors.js +25 -0
- package/dist/orchestrator/planningExecutors.d.ts +4 -0
- package/dist/orchestrator/planningExecutors.js +95 -0
- package/dist/orchestrator/reviewPacketGraph.d.ts +31 -0
- package/dist/orchestrator/reviewPacketGraph.js +691 -0
- package/dist/orchestrator/reviewPackets.d.ts +2 -15
- package/dist/orchestrator/reviewPackets.js +3 -685
- package/dist/orchestrator/runtimeCommand.d.ts +11 -0
- package/dist/orchestrator/runtimeCommand.js +71 -0
- package/dist/orchestrator/scope.js +1 -1
- package/dist/orchestrator/selectiveDeepening/conflict.d.ts +8 -0
- package/dist/orchestrator/selectiveDeepening/conflict.js +71 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.d.ts +10 -0
- package/dist/orchestrator/selectiveDeepening/findingFollowup.js +52 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.d.ts +7 -0
- package/dist/orchestrator/selectiveDeepening/highRiskClean.js +44 -0
- package/dist/orchestrator/selectiveDeepening/index.d.ts +18 -0
- package/dist/orchestrator/selectiveDeepening/index.js +128 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.d.ts +12 -0
- package/dist/orchestrator/selectiveDeepening/lensVerification.js +242 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.d.ts +13 -0
- package/dist/orchestrator/selectiveDeepening/runtimeValidation.js +57 -0
- package/dist/orchestrator/selectiveDeepening/shared.d.ts +45 -0
- package/dist/orchestrator/selectiveDeepening/shared.js +128 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.d.ts +6 -0
- package/dist/orchestrator/selectiveDeepening/stewardFollowup.js +72 -0
- package/dist/orchestrator/selectiveDeepening.d.ts +2 -20
- package/dist/orchestrator/selectiveDeepening.js +6 -760
- package/dist/orchestrator/staleness.js +3 -3
- package/dist/orchestrator/structureExecutors.d.ts +5 -0
- package/dist/orchestrator/structureExecutors.js +94 -0
- package/dist/orchestrator/syntaxResolutionExecutor.d.ts +1 -1
- package/dist/orchestrator/synthesisExecutors.d.ts +12 -0
- package/dist/orchestrator/synthesisExecutors.js +90 -0
- package/dist/orchestrator/taskBuilder.d.ts +2 -2
- package/dist/orchestrator/taskBuilder.js +101 -82
- package/dist/providers/index.d.ts +7 -0
- package/dist/providers/index.js +14 -95
- package/dist/quota/discoveredLimits.d.ts +1 -0
- package/dist/quota/discoveredLimits.js +7 -1
- package/dist/quota/index.d.ts +0 -2
- package/dist/quota/index.js +1 -2
- package/dist/reporting/workBlocks.js +7 -4
- package/dist/types/reviewPlanning.d.ts +23 -16
- package/dist/validation/auditResults.js +97 -95
- package/dist/validation/sessionConfig.d.ts +2 -2
- package/dist/validation/sessionConfig.js +14 -7
- package/docs/development.md +35 -139
- package/docs/history.md +26 -0
- package/docs/product.md +41 -108
- package/package.json +3 -2
- package/schemas/audit_findings.schema.json +6 -5
- package/schemas/critical_flows.schema.json +3 -2
- package/schemas/dispatch_quota.schema.json +3 -1
- package/schemas/external_analyzer_results.schema.json +2 -2
- package/schemas/graph_bundle.schema.json +1 -1
- package/schemas/repo_manifest.schema.json +1 -1
- package/schemas/review_packets.schema.json +1 -1
- package/schemas/step_contract.schema.json +80 -0
- package/scripts/postinstall.mjs +19 -2
- package/skills/audit-code/opencode-command-template.txt +3 -3
- package/dist/orchestrator/internalExecutors.d.ts +0 -34
- package/dist/orchestrator/internalExecutors.js +0 -581
- package/dist/providers/localSubprocessProvider.d.ts +0 -9
- package/dist/providers/localSubprocessProvider.js +0 -18
- package/dist/providers/subprocessTemplateProvider.d.ts +0 -8
- package/dist/providers/subprocessTemplateProvider.js +0 -59
- package/dist/providers/vscodeTaskProvider.d.ts +0 -7
- package/dist/providers/vscodeTaskProvider.js +0 -14
- package/dist/quota/probe.d.ts +0 -10
- package/dist/quota/probe.js +0 -18
- package/docs/handoff.md +0 -204
package/dist/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mkdir, readFile,
|
|
1
|
+
import { mkdir, readFile, rm, } from "node:fs/promises";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join, resolve, } from "node:path";
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
@@ -11,31 +11,31 @@ import { buildFlowCoverage } from "./orchestrator/flowCoverage.js";
|
|
|
11
11
|
import { buildRuntimeValidationTasks, } from "./orchestrator/runtimeValidation.js";
|
|
12
12
|
import { initializeCoverageFromPlan } from "./orchestrator/planning.js";
|
|
13
13
|
import { loadArtifactBundle, writeCoreArtifacts, promoteFinalAuditReport, } from "./io/artifacts.js";
|
|
14
|
-
import { isFileMissingError, readJsonFile,
|
|
14
|
+
import { isFileMissingError, readJsonFile, prefixValidationIssues, DEFAULT_EMPIRICAL_HALF_LIFE_HOURS, } from "@audit-tools/shared";
|
|
15
15
|
import { buildQuotaSource } from "@audit-tools/shared/quota/compositeQuotaSource";
|
|
16
16
|
import { validateArtifactBundle } from "./validation/artifacts.js";
|
|
17
|
-
import { validateAuditResults,
|
|
17
|
+
import { validateAuditResults, } from "./validation/auditResults.js";
|
|
18
18
|
import { validateConfiguredProviderEnvironment, validateSessionConfig, } from "./validation/sessionConfig.js";
|
|
19
19
|
import { buildAuditReportModel, renderAuditReportMarkdown, } from "./reporting/synthesis.js";
|
|
20
20
|
import { deriveAuditState } from "./orchestrator/state.js";
|
|
21
21
|
import { createFreshSessionProvider, resolveFreshSessionProviderName, } from "./providers/index.js";
|
|
22
|
-
import { loadRunLedger, } from "./supervisor/runLedger.js";
|
|
23
22
|
import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
|
|
24
23
|
import { clearDispatchFiles, ensureSupervisorDirs, } from "./io/runArtifacts.js";
|
|
25
24
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
26
|
-
import { scheduleWave, buildProviderModelKey, readQuotaState, resolveLimits, resolveHostActiveSubagentLimit,
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
import {
|
|
30
|
-
import { WORKER_RESULT_CONTRACT_VERSION, buildWorkerResult, formatAuditResultValidationError, } from "./cli/workerResult.js";
|
|
31
|
-
import { DISPATCH_RESULT_MAP_FILENAME, ACTIVE_DISPATCH_FILENAME, resolveRunScopedArg, loadDispatchResultMap, entriesByTaskId, buildPendingAuditTasks, prepareDispatchArtifacts, } from "./cli/dispatch.js";
|
|
32
|
-
import { buildLineIndex, buildLineIndexForPaths, addFileLineCountHints, } from "./cli/lineIndex.js";
|
|
25
|
+
import { scheduleWave, buildProviderModelKey, readQuotaState, resolveLimits, resolveHostActiveSubagentLimit, computeMaxSafeConcurrency, getQuotaStatePath, lookupDiscoveredLimits, setQuotaStateDir, } from "./quota/index.js";
|
|
26
|
+
import { DIRECT_CLI_DEFAULTS, getFlag, hasFlag, fromBase64Url, taskResultPath, getArtifactsDir, getRootDir, warnIfNotGitRepo, getBatchResultsDir, getMaxRuns, getAgentBatchSize, getParallelWorkers, getTimeoutMs, getExplicitProvider, getHostModel, getHostMaxActiveSubagents, resolveRunProviderName, chunkArray, getUiMode, looksLikeCliFlag, countLines, } from "./cli/args.js";
|
|
27
|
+
import { ACTIVE_DISPATCH_FILENAME, loadDispatchResultMap, prepareDispatchArtifacts, } from "./cli/dispatch.js";
|
|
28
|
+
import { buildLineIndex, } from "./cli/lineIndex.js";
|
|
33
29
|
import { emitEnvelope, } from "./cli/envelope.js";
|
|
34
30
|
import { persistConfigErrorHandoff } from "./cli/reviewRun.js";
|
|
35
31
|
import { runAuditStep, ingestBatchAuditResults, } from "./cli/auditStep.js";
|
|
36
32
|
import { packageRoot } from "./cli/paths.js";
|
|
37
33
|
import { cmdNextStep } from "./cli/nextStepCommand.js";
|
|
38
34
|
import { cmdRunToCompletion } from "./cli/runToCompletion.js";
|
|
35
|
+
import { cmdWorkerRun } from "./cli/workerRunCommand.js";
|
|
36
|
+
import { cmdSubmitPacket } from "./cli/submitPacketCommand.js";
|
|
37
|
+
import { cmdMergeAndIngest } from "./cli/mergeAndIngestCommand.js";
|
|
38
|
+
import { cmdStatus } from "./cli/statusCommand.js";
|
|
39
39
|
import { cleanupStaleArtifactsDir } from "./cli/cleanup.js";
|
|
40
40
|
const SAMPLE_REPO_FILES = [
|
|
41
41
|
{ path: "src/api/auth.ts", size_bytes: 1240, hash: "abc123" },
|
|
@@ -220,88 +220,6 @@ async function cmdAdvanceAudit(argv) {
|
|
|
220
220
|
await promoteFinalAuditReport({ artifactsDir, repoRoot: root });
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
|
-
async function cmdWorkerRun(argv) {
|
|
224
|
-
const taskPath = getFlag(argv, "--task");
|
|
225
|
-
if (!taskPath) {
|
|
226
|
-
throw new Error("worker-run requires --task <path>");
|
|
227
|
-
}
|
|
228
|
-
const task = await readJsonFile(taskPath);
|
|
229
|
-
let workerResult;
|
|
230
|
-
try {
|
|
231
|
-
if (looksLikeCliFlag(task.audit_results_path)) {
|
|
232
|
-
throw new Error(`task.audit_results_path resolved to '${task.audit_results_path}', which looks like a CLI flag instead of a file path.`);
|
|
233
|
-
}
|
|
234
|
-
if (task.preferred_executor === "agent" && !task.audit_results_path) {
|
|
235
|
-
throw new Error("agent worker-run requires audit_results_path so provider-assisted review can be ingested.");
|
|
236
|
-
}
|
|
237
|
-
if (task.preferred_executor === "agent" && task.audit_results_path) {
|
|
238
|
-
const pendingTasks = task.pending_audit_tasks_path
|
|
239
|
-
? await readJsonFile(task.pending_audit_tasks_path)
|
|
240
|
-
: [];
|
|
241
|
-
const auditResults = await readJsonFile(task.audit_results_path);
|
|
242
|
-
const pendingTaskIds = new Set(pendingTasks.map((item) => item.task_id));
|
|
243
|
-
const matchedResultCount = auditResults.filter((result) => pendingTaskIds.has(result.task_id)).length;
|
|
244
|
-
if (pendingTasks.length > 0 && matchedResultCount === 0) {
|
|
245
|
-
throw new Error("Provider-assisted review did not emit any audit results for the pending audit tasks.");
|
|
246
|
-
}
|
|
247
|
-
const issues = validateAuditResults(auditResults, pendingTasks, {
|
|
248
|
-
lineIndex: await buildLineIndexForPaths(task.repo_root, pendingTasks.flatMap((item) => item.file_paths)),
|
|
249
|
-
});
|
|
250
|
-
const errors = issues.filter((issue) => issue.severity === "error");
|
|
251
|
-
const warnings = issues.filter((issue) => issue.severity === "warning");
|
|
252
|
-
if (warnings.length > 0) {
|
|
253
|
-
process.stderr.write(`audit-results validation: ${warnings.length} warning(s):\n` +
|
|
254
|
-
formatAuditResultIssues(warnings) +
|
|
255
|
-
"\n");
|
|
256
|
-
}
|
|
257
|
-
if (errors.length > 0) {
|
|
258
|
-
throw new Error(formatAuditResultValidationError(errors));
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
const preferredExecutor = task.preferred_executor === "agent"
|
|
262
|
-
? "result_ingestion_executor"
|
|
263
|
-
: task.preferred_executor;
|
|
264
|
-
const result = await runAuditStep({
|
|
265
|
-
root: task.repo_root,
|
|
266
|
-
artifactsDir: task.artifacts_dir,
|
|
267
|
-
preferredExecutor,
|
|
268
|
-
auditResultsPath: task.audit_results_path,
|
|
269
|
-
runtimeUpdatesPath: task.runtime_updates_path,
|
|
270
|
-
externalAnalyzerPath: task.external_analyzer_results_path,
|
|
271
|
-
});
|
|
272
|
-
workerResult = {
|
|
273
|
-
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
274
|
-
run_id: task.run_id,
|
|
275
|
-
obligation_id: task.obligation_id,
|
|
276
|
-
status: result.progress_made ? "completed" : "no_progress",
|
|
277
|
-
progress_made: result.progress_made,
|
|
278
|
-
selected_executor: result.selected_executor,
|
|
279
|
-
artifacts_written: result.artifacts_written,
|
|
280
|
-
summary: result.progress_summary,
|
|
281
|
-
next_likely_step: result.next_likely_step,
|
|
282
|
-
errors: [],
|
|
283
|
-
};
|
|
284
|
-
}
|
|
285
|
-
catch (error) {
|
|
286
|
-
workerResult = {
|
|
287
|
-
contract_version: WORKER_RESULT_CONTRACT_VERSION,
|
|
288
|
-
run_id: task.run_id,
|
|
289
|
-
obligation_id: task.obligation_id,
|
|
290
|
-
status: "failed",
|
|
291
|
-
progress_made: false,
|
|
292
|
-
selected_executor: task.preferred_executor,
|
|
293
|
-
artifacts_written: [],
|
|
294
|
-
summary: `Worker failed for executor ${task.preferred_executor}: ${error instanceof Error ? error.message : String(error)}`,
|
|
295
|
-
next_likely_step: task.obligation_id,
|
|
296
|
-
errors: [error instanceof Error ? error.message : String(error)],
|
|
297
|
-
};
|
|
298
|
-
}
|
|
299
|
-
await writeJsonFile(task.result_path, workerResult);
|
|
300
|
-
console.log(JSON.stringify(workerResult, null, 2));
|
|
301
|
-
if (workerResult.status === "failed") {
|
|
302
|
-
process.exitCode = 1;
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
223
|
async function cmdPrepareDispatch(argv) {
|
|
306
224
|
const runId = getFlag(argv, "--run-id");
|
|
307
225
|
if (!runId)
|
|
@@ -322,365 +240,6 @@ async function cmdPrepareDispatch(argv) {
|
|
|
322
240
|
});
|
|
323
241
|
console.log(JSON.stringify(result, null, 2));
|
|
324
242
|
}
|
|
325
|
-
async function cmdSubmitPacket(argv) {
|
|
326
|
-
const runId = resolveRunScopedArg(argv, "--run-id", "--run-id-b64");
|
|
327
|
-
const packetId = resolveRunScopedArg(argv, "--packet-id", "--packet-id-b64");
|
|
328
|
-
const artifactsDirB64 = getFlag(argv, "--artifacts-dir-b64");
|
|
329
|
-
const artifactsDir = artifactsDirB64
|
|
330
|
-
? resolve(fromBase64Url(artifactsDirB64))
|
|
331
|
-
: getArtifactsDir(argv);
|
|
332
|
-
if (!runId || !packetId) {
|
|
333
|
-
throw new Error("submit-packet requires --run-id and --packet-id (or --run-id-b64/--packet-id-b64)");
|
|
334
|
-
}
|
|
335
|
-
const runDir = join(artifactsDir, "runs", runId);
|
|
336
|
-
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
337
|
-
const resultMap = await loadDispatchResultMap(runDir);
|
|
338
|
-
if (!resultMap) {
|
|
339
|
-
throw new Error(`No ${DISPATCH_RESULT_MAP_FILENAME} found for run ${runId}; run prepare-dispatch first.`);
|
|
340
|
-
}
|
|
341
|
-
let packetEntries = resultMap.entries.filter((entry) => entry.packet_id === packetId);
|
|
342
|
-
let resolvedPacketId = packetId;
|
|
343
|
-
if (packetEntries.length === 0) {
|
|
344
|
-
const trimmed = packetId.trim();
|
|
345
|
-
packetEntries = resultMap.entries.filter((entry) => entry.packet_id.trim().toLowerCase() === trimmed.toLowerCase());
|
|
346
|
-
if (packetEntries.length > 0) {
|
|
347
|
-
resolvedPacketId = packetEntries[0].packet_id;
|
|
348
|
-
process.stderr.write(`[submit-packet] Resolved packet_id '${packetId}' → '${resolvedPacketId}' (case/whitespace normalization)\n`);
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
if (packetEntries.length === 0) {
|
|
352
|
-
const knownIds = [...new Set(resultMap.entries.map((e) => e.packet_id))];
|
|
353
|
-
throw new Error(`Unknown packet_id '${packetId}' for run ${runId}.\n` +
|
|
354
|
-
`Valid packet IDs: ${knownIds.join(", ")}`);
|
|
355
|
-
}
|
|
356
|
-
if (entriesByTaskId(packetEntries).size !== packetEntries.length) {
|
|
357
|
-
throw new Error(`Dispatch result map has duplicate task entries for packet '${resolvedPacketId}'.`);
|
|
358
|
-
}
|
|
359
|
-
const allTasks = await readJsonFile(tasksPath);
|
|
360
|
-
const taskById = new Map(allTasks.map((task) => [task.task_id, task]));
|
|
361
|
-
const packetTasks = packetEntries.map((entry) => taskById.get(entry.task_id));
|
|
362
|
-
const missingTask = packetEntries.find((entry, index) => !packetTasks[index]);
|
|
363
|
-
if (missingTask) {
|
|
364
|
-
throw new Error(`Dispatch result map references unknown task '${missingTask.task_id}'.`);
|
|
365
|
-
}
|
|
366
|
-
const tasks = packetTasks;
|
|
367
|
-
const expectedTaskIds = new Set(tasks.map((task) => task.task_id));
|
|
368
|
-
const lineIndex = Object.fromEntries(tasks.flatMap((task) => Object.entries(task.file_line_counts ?? {})));
|
|
369
|
-
const encodedResults = getFlag(argv, "--results-b64");
|
|
370
|
-
const raw = encodedResults ? fromBase64Url(encodedResults) : await readStdinText();
|
|
371
|
-
if (raw.trim().length === 0) {
|
|
372
|
-
throw new Error("submit-packet requires an AuditResult[] JSON payload on stdin or --results-b64.");
|
|
373
|
-
}
|
|
374
|
-
let payload;
|
|
375
|
-
try {
|
|
376
|
-
payload = JSON.parse(raw);
|
|
377
|
-
}
|
|
378
|
-
catch (error) {
|
|
379
|
-
throw new Error(`Invalid submit-packet JSON: ${error instanceof Error ? error.message : String(error)}`);
|
|
380
|
-
}
|
|
381
|
-
const resultErrors = [];
|
|
382
|
-
const issues = validateAuditResults(payload, tasks, { lineIndex });
|
|
383
|
-
const validationErrors = issues.filter((issue) => issue.severity === "error");
|
|
384
|
-
const validationWarnings = issues.filter((issue) => issue.severity === "warning");
|
|
385
|
-
if (validationWarnings.length > 0) {
|
|
386
|
-
process.stderr.write(`audit-results validation: ${validationWarnings.length} warning(s):\n` +
|
|
387
|
-
formatAuditResultIssues(validationWarnings) +
|
|
388
|
-
"\n");
|
|
389
|
-
}
|
|
390
|
-
if (validationErrors.length > 0) {
|
|
391
|
-
resultErrors.push(formatAuditResultIssues(validationErrors));
|
|
392
|
-
}
|
|
393
|
-
if (Array.isArray(payload)) {
|
|
394
|
-
const seen = new Set();
|
|
395
|
-
for (const [index, result] of payload.entries()) {
|
|
396
|
-
if (!result || typeof result !== "object" || Array.isArray(result)) {
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
const taskId = result.task_id;
|
|
400
|
-
if (typeof taskId !== "string" || taskId.trim().length === 0) {
|
|
401
|
-
continue;
|
|
402
|
-
}
|
|
403
|
-
if (seen.has(taskId)) {
|
|
404
|
-
resultErrors.push(`Duplicate audit result for assigned task '${taskId}'.`);
|
|
405
|
-
}
|
|
406
|
-
seen.add(taskId);
|
|
407
|
-
if (!expectedTaskIds.has(taskId)) {
|
|
408
|
-
resultErrors.push(`Result at index ${index} uses task_id '${taskId}', which is not assigned to packet '${resolvedPacketId}'.`);
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
for (const task of tasks) {
|
|
412
|
-
if (!seen.has(task.task_id)) {
|
|
413
|
-
resultErrors.push(`Missing audit result for assigned task '${task.task_id}'.`);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
|
-
}
|
|
417
|
-
if (resultErrors.length > 0) {
|
|
418
|
-
throw new Error(`submit-packet rejected ${resolvedPacketId}:\n${resultErrors.join("\n")}`);
|
|
419
|
-
}
|
|
420
|
-
// Check for duplicate findings against already-submitted results in this run
|
|
421
|
-
const existingFindingKeys = new Set();
|
|
422
|
-
const otherEntries = resultMap.entries.filter((e) => e.packet_id !== resolvedPacketId);
|
|
423
|
-
for (const other of otherEntries) {
|
|
424
|
-
try {
|
|
425
|
-
const existing = JSON.parse(await readFile(other.result_path, "utf8"));
|
|
426
|
-
if (existing?.findings) {
|
|
427
|
-
for (const f of existing.findings) {
|
|
428
|
-
const key = [
|
|
429
|
-
(f.lens ?? "").trim().toLowerCase(),
|
|
430
|
-
(f.category ?? "").trim().toLowerCase(),
|
|
431
|
-
(f.title ?? "").trim().toLowerCase(),
|
|
432
|
-
f.affected_files?.[0]?.path ?? "",
|
|
433
|
-
].join("|");
|
|
434
|
-
existingFindingKeys.add(key);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
catch { /* file doesn't exist yet or invalid — skip */ }
|
|
439
|
-
}
|
|
440
|
-
let dupCount = 0;
|
|
441
|
-
for (const result of payload) {
|
|
442
|
-
for (const f of result.findings ?? []) {
|
|
443
|
-
const key = [
|
|
444
|
-
(f.lens ?? "").trim().toLowerCase(),
|
|
445
|
-
(f.category ?? "").trim().toLowerCase(),
|
|
446
|
-
(f.title ?? "").trim().toLowerCase(),
|
|
447
|
-
f.affected_files?.[0]?.path ?? "",
|
|
448
|
-
].join("|");
|
|
449
|
-
if (existingFindingKeys.has(key)) {
|
|
450
|
-
dupCount++;
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
}
|
|
454
|
-
if (dupCount > 0) {
|
|
455
|
-
process.stderr.write(`[submit-packet] Warning: ${dupCount} finding(s) appear to duplicate findings from other packets in this run.\n`);
|
|
456
|
-
}
|
|
457
|
-
const entryByTaskId = entriesByTaskId(packetEntries);
|
|
458
|
-
for (const result of payload) {
|
|
459
|
-
const entry = entryByTaskId.get(result.task_id);
|
|
460
|
-
if (!entry) {
|
|
461
|
-
throw new Error(`Internal error: no result path for accepted task '${result.task_id}'.`);
|
|
462
|
-
}
|
|
463
|
-
await writeJsonFile(entry.result_path, result);
|
|
464
|
-
}
|
|
465
|
-
const findingCount = payload.reduce((sum, result) => sum + result.findings.length, 0);
|
|
466
|
-
console.log(JSON.stringify({
|
|
467
|
-
run_id: runId,
|
|
468
|
-
packet_id: resolvedPacketId,
|
|
469
|
-
accepted_count: payload.length,
|
|
470
|
-
finding_count: findingCount,
|
|
471
|
-
...(dupCount > 0 ? { duplicate_warning_count: dupCount } : {}),
|
|
472
|
-
}, null, 2));
|
|
473
|
-
}
|
|
474
|
-
async function cmdMergeAndIngest(argv) {
|
|
475
|
-
const runId = getFlag(argv, "--run-id");
|
|
476
|
-
if (!runId)
|
|
477
|
-
throw new Error("merge-and-ingest requires --run-id <run_id>");
|
|
478
|
-
const artifactsDir = getArtifactsDir(argv);
|
|
479
|
-
const runDir = join(artifactsDir, "runs", runId);
|
|
480
|
-
const taskResultsDir = join(runDir, "task-results");
|
|
481
|
-
const auditResultsPath = join(runDir, "audit-results.json");
|
|
482
|
-
const taskPath = join(runDir, "task.json");
|
|
483
|
-
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
484
|
-
const workerTask = await readJsonFile(taskPath);
|
|
485
|
-
const resultMap = await loadDispatchResultMap(runDir);
|
|
486
|
-
if (!resultMap) {
|
|
487
|
-
throw new Error(`No ${DISPATCH_RESULT_MAP_FILENAME} found for run ${runId}; run prepare-dispatch first.`);
|
|
488
|
-
}
|
|
489
|
-
let allTasks = [];
|
|
490
|
-
try {
|
|
491
|
-
allTasks = await readJsonFile(tasksPath);
|
|
492
|
-
}
|
|
493
|
-
catch { /* may not exist */ }
|
|
494
|
-
const entryByTaskId = entriesByTaskId(resultMap.entries);
|
|
495
|
-
if (entryByTaskId.size !== resultMap.entries.length) {
|
|
496
|
-
throw new Error(`Dispatch result map for run ${runId} contains duplicate task entries.`);
|
|
497
|
-
}
|
|
498
|
-
const expectedPaths = new Set(resultMap.entries.map((entry) => resolve(entry.result_path)));
|
|
499
|
-
let files;
|
|
500
|
-
try {
|
|
501
|
-
files = (await readdir(taskResultsDir)).filter(f => f.endsWith(".json")).sort();
|
|
502
|
-
}
|
|
503
|
-
catch {
|
|
504
|
-
files = [];
|
|
505
|
-
}
|
|
506
|
-
const passing = [];
|
|
507
|
-
const failing = [];
|
|
508
|
-
const seenTaskIds = new Set();
|
|
509
|
-
let spuriousFileCount = 0;
|
|
510
|
-
const fallbackByTaskId = new Map();
|
|
511
|
-
for (const filename of files) {
|
|
512
|
-
const filePath = resolve(join(taskResultsDir, filename));
|
|
513
|
-
if (expectedPaths.has(filePath))
|
|
514
|
-
continue;
|
|
515
|
-
// Not part of this round's plan. Still read it so a current task can be
|
|
516
|
-
// recovered by task_id (e.g. a subagent wrote a valid result under a
|
|
517
|
-
// non-assigned name).
|
|
518
|
-
try {
|
|
519
|
-
const raw = await readFile(filePath, "utf8");
|
|
520
|
-
const parsed = JSON.parse(raw);
|
|
521
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
522
|
-
const tid = typeof parsed.task_id === "string"
|
|
523
|
-
? String(parsed.task_id) : undefined;
|
|
524
|
-
if (tid && !fallbackByTaskId.has(tid)) {
|
|
525
|
-
fallbackByTaskId.set(tid, parsed);
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
catch { /* not parseable — skip */ }
|
|
530
|
-
// Only genuinely stray files are "spurious". Canonical per-task result files
|
|
531
|
-
// (<stem>_<digest>.json) left by prior deepening rounds in the same
|
|
532
|
-
// task-results/ dir are legitimate and must not inflate the count or bury
|
|
533
|
-
// the real stray-file signal (3 -> 191 over a run before this fix).
|
|
534
|
-
if (!isCanonicalResultFilename(filename)) {
|
|
535
|
-
spuriousFileCount++;
|
|
536
|
-
process.stderr.write(`[merge-and-ingest] Warning: unexpected file in task-results/: ${filename}\n`);
|
|
537
|
-
}
|
|
538
|
-
}
|
|
539
|
-
for (const task of allTasks) {
|
|
540
|
-
const entry = entryByTaskId.get(task.task_id);
|
|
541
|
-
if (!entry) {
|
|
542
|
-
failing.push({
|
|
543
|
-
task_id: task.task_id,
|
|
544
|
-
errors: ["Missing dispatch result-map entry for assigned task."],
|
|
545
|
-
});
|
|
546
|
-
continue;
|
|
547
|
-
}
|
|
548
|
-
const filePath = entry.result_path;
|
|
549
|
-
let obj;
|
|
550
|
-
try {
|
|
551
|
-
obj = JSON.parse(await readFile(filePath, "utf8"));
|
|
552
|
-
}
|
|
553
|
-
catch (e) {
|
|
554
|
-
if (isFileMissingError(e)) {
|
|
555
|
-
const fallback = fallbackByTaskId.get(task.task_id);
|
|
556
|
-
if (fallback) {
|
|
557
|
-
process.stderr.write(`[merge-and-ingest] Recovered result for '${task.task_id}' from unexpected file (matched by task_id)\n`);
|
|
558
|
-
obj = fallback;
|
|
559
|
-
}
|
|
560
|
-
else {
|
|
561
|
-
failing.push({
|
|
562
|
-
task_id: task.task_id,
|
|
563
|
-
errors: ["Missing audit result for assigned task."],
|
|
564
|
-
});
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
|
-
else {
|
|
569
|
-
failing.push({ task_id: task.task_id, errors: [`Invalid JSON: ${e.message}`] });
|
|
570
|
-
continue;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
const record = obj && typeof obj === "object" && !Array.isArray(obj)
|
|
574
|
-
? obj
|
|
575
|
-
: undefined;
|
|
576
|
-
const taskId = typeof record?.task_id === "string"
|
|
577
|
-
? String(record.task_id) : undefined;
|
|
578
|
-
const resultErrors = [];
|
|
579
|
-
if (taskId) {
|
|
580
|
-
if (seenTaskIds.has(taskId)) {
|
|
581
|
-
resultErrors.push(`Duplicate audit result for assigned task '${taskId}'.`);
|
|
582
|
-
}
|
|
583
|
-
else {
|
|
584
|
-
seenTaskIds.add(taskId);
|
|
585
|
-
}
|
|
586
|
-
if (taskId !== task.task_id) {
|
|
587
|
-
resultErrors.push(`Result file is assigned to '${task.task_id}' but contains task_id '${taskId}'.`);
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
const issues = validateAuditResults([obj], [task], { lineIndex: task.file_line_counts ?? {} });
|
|
591
|
-
resultErrors.push(...issues
|
|
592
|
-
.filter(i => i.severity === "error")
|
|
593
|
-
.map(i => i.message));
|
|
594
|
-
if (resultErrors.length === 0) {
|
|
595
|
-
passing.push(obj);
|
|
596
|
-
}
|
|
597
|
-
else {
|
|
598
|
-
failing.push({ task_id: taskId ?? task.task_id, errors: resultErrors });
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
await writeJsonFile(auditResultsPath, passing);
|
|
602
|
-
const failedTasksPath = join(runDir, "failed-tasks.json");
|
|
603
|
-
if (failing.length > 0) {
|
|
604
|
-
await writeJsonFile(failedTasksPath, failing);
|
|
605
|
-
}
|
|
606
|
-
if (passing.length === 0 && failing.length > 0) {
|
|
607
|
-
throw new Error(`All ${failing.length} assigned task result(s) were missing or invalid; blocked before ingestion. See ${failedTasksPath}`);
|
|
608
|
-
}
|
|
609
|
-
const findingCount = passing.reduce((sum, result) => sum + result.findings.length, 0);
|
|
610
|
-
let result = null;
|
|
611
|
-
if (passing.length > 0) {
|
|
612
|
-
result = await runAuditStep({
|
|
613
|
-
root: workerTask.repo_root,
|
|
614
|
-
artifactsDir,
|
|
615
|
-
preferredExecutor: "result_ingestion_executor",
|
|
616
|
-
auditResultsPath,
|
|
617
|
-
});
|
|
618
|
-
const updatedPendingTasks = await addFileLineCountHints(workerTask.repo_root, buildPendingAuditTasks(result.updated_bundle));
|
|
619
|
-
await writeJsonFile(tasksPath, updatedPendingTasks);
|
|
620
|
-
}
|
|
621
|
-
const activeDispatchPath = join(artifactsDir, ACTIVE_DISPATCH_FILENAME);
|
|
622
|
-
try {
|
|
623
|
-
const dispatch = await readJsonFile(activeDispatchPath);
|
|
624
|
-
if (dispatch.run_id === runId) {
|
|
625
|
-
dispatch.status = failing.length > 0 ? "active" : "merged";
|
|
626
|
-
await writeJsonFile(activeDispatchPath, dispatch);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
catch { /* no active dispatch file — skip */ }
|
|
630
|
-
let retryDispatchPath = null;
|
|
631
|
-
if (failing.length > 0) {
|
|
632
|
-
const failedTaskIds = new Set(failing.map((f) => f.task_id));
|
|
633
|
-
const failedPacketIds = [
|
|
634
|
-
...new Set(resultMap.entries
|
|
635
|
-
.filter((e) => failedTaskIds.has(e.task_id))
|
|
636
|
-
.map((e) => e.packet_id)),
|
|
637
|
-
];
|
|
638
|
-
const retryDispatch = {
|
|
639
|
-
run_id: runId,
|
|
640
|
-
retry_packet_ids: failedPacketIds,
|
|
641
|
-
failed_task_count: failing.length,
|
|
642
|
-
accepted_task_count: passing.length,
|
|
643
|
-
};
|
|
644
|
-
retryDispatchPath = join(runDir, "retry-dispatch.json");
|
|
645
|
-
await writeJsonFile(retryDispatchPath, retryDispatch);
|
|
646
|
-
process.stderr.write(`[merge-and-ingest] ${passing.length} accepted, ${failing.length} failed. ` +
|
|
647
|
-
`Retry packets: ${failedPacketIds.join(", ")}\n`);
|
|
648
|
-
}
|
|
649
|
-
const status = failing.length > 0
|
|
650
|
-
? "partial"
|
|
651
|
-
: (result?.progress_made ? "completed" : "no_progress");
|
|
652
|
-
const workerResult = buildWorkerResult({
|
|
653
|
-
runId,
|
|
654
|
-
obligationId: workerTask.obligation_id,
|
|
655
|
-
status: failing.length > 0 ? "no_progress" : (result?.progress_made ? "completed" : "no_progress"),
|
|
656
|
-
progressMade: result?.progress_made ?? false,
|
|
657
|
-
selectedExecutor: result?.selected_executor ?? null,
|
|
658
|
-
artifactsWritten: result?.artifacts_written ?? [],
|
|
659
|
-
summary: result?.progress_summary ?? `${failing.length} task(s) failed`,
|
|
660
|
-
nextLikelyStep: result?.next_likely_step ?? null,
|
|
661
|
-
errors: [],
|
|
662
|
-
});
|
|
663
|
-
await writeJsonFile(workerTask.result_path, workerResult);
|
|
664
|
-
console.log(JSON.stringify({
|
|
665
|
-
run_id: runId,
|
|
666
|
-
status,
|
|
667
|
-
accepted_count: passing.length,
|
|
668
|
-
rejected_count: failing.length,
|
|
669
|
-
spurious_file_count: spuriousFileCount,
|
|
670
|
-
finding_count: findingCount,
|
|
671
|
-
audit_results_path: auditResultsPath,
|
|
672
|
-
...(retryDispatchPath ? { retry_dispatch_path: retryDispatchPath } : {}),
|
|
673
|
-
...(result ? {
|
|
674
|
-
selected_executor: workerResult.selected_executor,
|
|
675
|
-
progress_made: workerResult.progress_made,
|
|
676
|
-
progress_summary: workerResult.summary,
|
|
677
|
-
next_likely_step: workerResult.next_likely_step,
|
|
678
|
-
} : {}),
|
|
679
|
-
}, null, 2));
|
|
680
|
-
if (failing.length > 0) {
|
|
681
|
-
process.exitCode = 2;
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
243
|
async function cmdValidateResult(argv) {
|
|
685
244
|
const rawRunId = getFlag(argv, "--run-id");
|
|
686
245
|
const runIdB64 = getFlag(argv, "--run-id-b64");
|
|
@@ -872,7 +431,7 @@ async function cmdValidate(argv) {
|
|
|
872
431
|
: prefixValidationIssues("session_config", validateSessionConfig(rawSessionConfig));
|
|
873
432
|
const providerIssues = rawSessionConfig === undefined || sessionConfigIssues.length > 0
|
|
874
433
|
? []
|
|
875
|
-
: prefixValidationIssues("session_config", validateConfiguredProviderEnvironment(rawSessionConfig));
|
|
434
|
+
: prefixValidationIssues("session_config", await validateConfiguredProviderEnvironment(rawSessionConfig));
|
|
876
435
|
const issues = [
|
|
877
436
|
...artifactIssues,
|
|
878
437
|
...sessionConfigIssues,
|
|
@@ -980,114 +539,6 @@ async function cmdCleanup(argv) {
|
|
|
980
539
|
dry_run: dryRun,
|
|
981
540
|
}, null, 2));
|
|
982
541
|
}
|
|
983
|
-
async function cmdStatus(argv) {
|
|
984
|
-
const artifactsDir = getArtifactsDir(argv);
|
|
985
|
-
const auditStatePath = join(artifactsDir, "audit_state.json");
|
|
986
|
-
// 1. Read audit_state.json
|
|
987
|
-
let auditState = null;
|
|
988
|
-
try {
|
|
989
|
-
auditState = await readJsonFile(auditStatePath);
|
|
990
|
-
}
|
|
991
|
-
catch (error) {
|
|
992
|
-
if (!isFileMissingError(error)) {
|
|
993
|
-
throw error;
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
if (!auditState) {
|
|
997
|
-
console.error("No audit_state.json found; no active audit in this artifacts directory.");
|
|
998
|
-
process.exitCode = 1;
|
|
999
|
-
return;
|
|
1000
|
-
}
|
|
1001
|
-
// Build obligations summary: count by state
|
|
1002
|
-
const obligationStates = {
|
|
1003
|
-
missing: 0,
|
|
1004
|
-
present: 0,
|
|
1005
|
-
stale: 0,
|
|
1006
|
-
blocked: 0,
|
|
1007
|
-
satisfied: 0,
|
|
1008
|
-
};
|
|
1009
|
-
for (const obligation of auditState.obligations ?? []) {
|
|
1010
|
-
const state = obligation.state;
|
|
1011
|
-
if (state in obligationStates) {
|
|
1012
|
-
obligationStates[state]++;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
// 2. Read run ledger for last N entries
|
|
1016
|
-
const ledger = await loadRunLedger(artifactsDir);
|
|
1017
|
-
const RECENT_RUN_LIMIT = 5;
|
|
1018
|
-
const recentRuns = ledger.runs
|
|
1019
|
-
.slice(-RECENT_RUN_LIMIT)
|
|
1020
|
-
.reverse()
|
|
1021
|
-
.map((entry) => ({
|
|
1022
|
-
run_id: entry.run_id,
|
|
1023
|
-
obligation_id: entry.obligation_id,
|
|
1024
|
-
status: entry.status,
|
|
1025
|
-
started_at: entry.started_at,
|
|
1026
|
-
}));
|
|
1027
|
-
// 3. Find the most recent run directory and read pending-audit-tasks.json
|
|
1028
|
-
let pendingTasksSummary = null;
|
|
1029
|
-
const runsDir = join(artifactsDir, "runs");
|
|
1030
|
-
let runDirs = [];
|
|
1031
|
-
try {
|
|
1032
|
-
const entries = await readdir(runsDir, { withFileTypes: true });
|
|
1033
|
-
runDirs = entries
|
|
1034
|
-
.filter((e) => e.isDirectory())
|
|
1035
|
-
.map((e) => e.name)
|
|
1036
|
-
.sort()
|
|
1037
|
-
.reverse();
|
|
1038
|
-
}
|
|
1039
|
-
catch {
|
|
1040
|
-
// runs directory may not exist yet
|
|
1041
|
-
}
|
|
1042
|
-
for (const runDirName of runDirs) {
|
|
1043
|
-
const runDir = join(runsDir, runDirName);
|
|
1044
|
-
const tasksPath = join(runDir, "pending-audit-tasks.json");
|
|
1045
|
-
let tasks = null;
|
|
1046
|
-
try {
|
|
1047
|
-
tasks = await readJsonFile(tasksPath);
|
|
1048
|
-
}
|
|
1049
|
-
catch {
|
|
1050
|
-
continue; // no pending-audit-tasks.json in this run dir — try previous
|
|
1051
|
-
}
|
|
1052
|
-
if (!Array.isArray(tasks))
|
|
1053
|
-
continue;
|
|
1054
|
-
// Count remaining: tasks without status "complete"
|
|
1055
|
-
const total = tasks.length;
|
|
1056
|
-
const remaining = tasks.filter((t) => t.status !== "complete").length;
|
|
1057
|
-
pendingTasksSummary = {
|
|
1058
|
-
run_id: runDirName,
|
|
1059
|
-
total,
|
|
1060
|
-
remaining,
|
|
1061
|
-
};
|
|
1062
|
-
break;
|
|
1063
|
-
}
|
|
1064
|
-
// 4. Surface failed-tasks.json from the most recent run that has one
|
|
1065
|
-
let failedTasks = null;
|
|
1066
|
-
for (const runDirName of runDirs) {
|
|
1067
|
-
const failedTasksPath = join(runsDir, runDirName, "failed-tasks.json");
|
|
1068
|
-
try {
|
|
1069
|
-
const raw = await readJsonFile(failedTasksPath);
|
|
1070
|
-
if (Array.isArray(raw) && raw.length > 0) {
|
|
1071
|
-
failedTasks = raw;
|
|
1072
|
-
break;
|
|
1073
|
-
}
|
|
1074
|
-
}
|
|
1075
|
-
catch {
|
|
1076
|
-
// Not present in this run dir — keep looking
|
|
1077
|
-
}
|
|
1078
|
-
}
|
|
1079
|
-
console.log(JSON.stringify({
|
|
1080
|
-
artifacts_dir: artifactsDir,
|
|
1081
|
-
status: auditState.status,
|
|
1082
|
-
last_obligation: auditState.last_obligation ?? null,
|
|
1083
|
-
last_executor: auditState.last_executor ?? null,
|
|
1084
|
-
blockers: auditState.blockers ?? [],
|
|
1085
|
-
obligations_summary: obligationStates,
|
|
1086
|
-
recent_runs: recentRuns,
|
|
1087
|
-
pending_tasks: pendingTasksSummary,
|
|
1088
|
-
failed_tasks: failedTasks,
|
|
1089
|
-
}, null, 2));
|
|
1090
|
-
}
|
|
1091
542
|
async function cmdMcp(argv) {
|
|
1092
543
|
await runAuditCodeMcpServer(argv.slice(3));
|
|
1093
544
|
}
|
|
@@ -1096,14 +547,13 @@ async function cmdQuota(argv) {
|
|
|
1096
547
|
const sessionConfig = await loadSessionConfig(artifactsDir).catch(() => ({}));
|
|
1097
548
|
const explicitProvider = getExplicitProvider(argv);
|
|
1098
549
|
const hostModel = getHostModel(argv);
|
|
1099
|
-
const probeMode = getQuotaProbeMode(argv, sessionConfig);
|
|
1100
550
|
const providerName = resolveFreshSessionProviderName(explicitProvider, sessionConfig);
|
|
1101
551
|
const providerModelKey = buildProviderModelKey(providerName, hostModel);
|
|
1102
552
|
const { limits, source, confidence } = resolveLimits({ providerName, sessionConfig, hostModel });
|
|
1103
|
-
const probeResult = await probeProvider(providerName, probeMode);
|
|
1104
553
|
const quotaState = await readQuotaState().catch(() => ({ version: 2, entries: {} }));
|
|
1105
554
|
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
1106
|
-
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ??
|
|
555
|
+
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ??
|
|
556
|
+
DEFAULT_EMPIRICAL_HALF_LIFE_HOURS;
|
|
1107
557
|
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({
|
|
1108
558
|
explicitLimit: getHostMaxActiveSubagents(argv),
|
|
1109
559
|
sessionConfig,
|
|
@@ -1129,7 +579,6 @@ async function cmdQuota(argv) {
|
|
|
1129
579
|
confidence,
|
|
1130
580
|
source,
|
|
1131
581
|
host_concurrency_limit: hostConcurrencyLimit,
|
|
1132
|
-
probe: probeResult,
|
|
1133
582
|
learned_caps: quotaStateEntry
|
|
1134
583
|
? {
|
|
1135
584
|
max_safe_concurrency: computeMaxSafeConcurrency(quotaStateEntry, halfLifeHours),
|
|
@@ -9,7 +9,10 @@ import { normalizeGraphPath } from "../graphPathUtils.js";
|
|
|
9
9
|
function supports(file) {
|
|
10
10
|
return normalizeGraphPath(file).toLowerCase().endsWith(".sql");
|
|
11
11
|
}
|
|
12
|
-
|
|
12
|
+
// Signature matches the `LanguageAnalyzer.analyze` interface (the params the
|
|
13
|
+
// other analyzers receive) so the registry type stays uniform; the stub
|
|
14
|
+
// ignores them and emits no edges yet.
|
|
15
|
+
function analyze(_files, _context) {
|
|
13
16
|
return { edges: [] };
|
|
14
17
|
}
|
|
15
18
|
export const sqlAnalyzer = {
|