auditor-lambda 0.3.32 → 0.3.34
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 +2 -1
- package/audit-code-wrapper-lib.mjs +30 -28
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +55 -123
- package/dist/mcp/server.js +11 -11
- package/dist/orchestrator/reviewPackets.d.ts +3 -0
- package/dist/orchestrator/reviewPackets.js +13 -2
- package/dist/quota/compositeQuotaSource.d.ts +7 -0
- package/dist/quota/compositeQuotaSource.js +20 -0
- package/dist/quota/errorParsers/claudeCodeErrorParser.d.ts +6 -0
- package/dist/quota/errorParsers/claudeCodeErrorParser.js +39 -0
- package/dist/quota/errorParsers/genericErrorParser.d.ts +9 -0
- package/dist/quota/errorParsers/genericErrorParser.js +7 -0
- package/dist/quota/errorParsers/index.d.ts +5 -0
- package/dist/quota/errorParsers/index.js +12 -0
- package/dist/quota/errorParsing.d.ts +7 -0
- package/dist/quota/errorParsing.js +69 -0
- package/dist/quota/fileLock.d.ts +6 -0
- package/dist/quota/fileLock.js +64 -0
- package/dist/quota/index.d.ts +11 -1
- package/dist/quota/index.js +7 -1
- package/dist/quota/learnedQuotaSource.d.ts +7 -0
- package/dist/quota/learnedQuotaSource.js +25 -0
- package/dist/quota/probe.d.ts +1 -4
- package/dist/quota/probe.js +1 -4
- package/dist/quota/quotaSource.d.ts +12 -0
- package/dist/quota/quotaSource.js +1 -0
- package/dist/quota/scheduler.d.ts +5 -1
- package/dist/quota/scheduler.js +51 -9
- package/dist/quota/slidingWindow.d.ts +4 -0
- package/dist/quota/slidingWindow.js +28 -0
- package/dist/quota/state.d.ts +3 -0
- package/dist/quota/state.js +57 -14
- package/dist/quota/types.d.ts +11 -2
- package/dist/supervisor/operatorHandoff.js +1 -1
- package/dist/types/sessionConfig.d.ts +3 -0
- package/dist/validation/sessionConfig.js +4 -0
- package/package.json +1 -1
- package/schemas/dispatch_quota.schema.json +23 -2
- package/skills/audit-code/audit-code.prompt.md +5 -0
package/README.md
CHANGED
|
@@ -138,7 +138,8 @@ audit-code next-step
|
|
|
138
138
|
|
|
139
139
|
This writes `.audit-artifacts/steps/current-step.json` and
|
|
140
140
|
`.audit-artifacts/steps/current-prompt.md`; hosts should follow only the
|
|
141
|
-
returned step prompt.
|
|
141
|
+
returned step prompt. MCP tools are compatibility adapters over this same
|
|
142
|
+
`next-step` contract rather than a separate orchestration path.
|
|
142
143
|
|
|
143
144
|
For an operator-side artifact consistency check:
|
|
144
145
|
|
|
@@ -580,16 +580,17 @@ function replaceBackslashes(value) {
|
|
|
580
580
|
function renderVSCodeAgentFile() {
|
|
581
581
|
return [
|
|
582
582
|
'---',
|
|
583
|
-
'description: Plan and orchestrate /audit-code
|
|
583
|
+
'description: Plan and orchestrate /audit-code through the next-step machine before making code changes.',
|
|
584
584
|
'---',
|
|
585
585
|
'',
|
|
586
586
|
'# Auditor Agent',
|
|
587
587
|
'',
|
|
588
|
-
'Use
|
|
588
|
+
'Use `audit-code next-step` as the primary integration surface for the audit workflow. The installed auditor MCP server is a compatibility adapter over the same step contract.',
|
|
589
589
|
'',
|
|
590
590
|
'When the user asks to run or continue `/audit-code`:',
|
|
591
591
|
'',
|
|
592
|
-
'-
|
|
592
|
+
'- run `audit-code next-step` directly when shell access is available',
|
|
593
|
+
'- if MCP is the only available integration, call `start_audit`, `get_status`, and `continue_audit`; those tools return the same one-step contract',
|
|
593
594
|
'- read `audit-code://handoff/current` and `audit-code://artifacts/current` when the audit blocks or you need current context',
|
|
594
595
|
'- prefer imported audit results and runtime updates over ad hoc manual state edits',
|
|
595
596
|
'- treat the deterministic audit report as the final source of truth once the audit completes',
|
|
@@ -615,7 +616,7 @@ function renderCodexMcpSetupGuide(root) {
|
|
|
615
616
|
`args = ["${replaceBackslashes(toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME)))}"]`,
|
|
616
617
|
'```',
|
|
617
618
|
'',
|
|
618
|
-
'
|
|
619
|
+
'Prefer `audit-code next-step` directly. Use the registered `auditor` MCP tools only when shell access is unavailable; they return the same one-step contract.',
|
|
619
620
|
'',
|
|
620
621
|
].join('\n');
|
|
621
622
|
}
|
|
@@ -626,9 +627,9 @@ function renderCodexAutomationRecipe() {
|
|
|
626
627
|
'',
|
|
627
628
|
'Suggested recurring task:',
|
|
628
629
|
'',
|
|
629
|
-
'- Prompt: Re-run the autonomous audit workflow for this repository
|
|
630
|
+
'- Prompt: Re-run the autonomous audit workflow for this repository with `audit-code next-step`, summarize only new or regressed findings, and stop once the deterministic report is current.',
|
|
630
631
|
'- Cadence: daily on active branches or before release cut-offs',
|
|
631
|
-
'- Inputs: repository root
|
|
632
|
+
'- Inputs: repository root; the installed `auditor` MCP server is optional compatibility plumbing',
|
|
632
633
|
'',
|
|
633
634
|
'Use this recipe as a starting point for a Codex automation once the local workflow is stable in your environment.',
|
|
634
635
|
'',
|
|
@@ -706,16 +707,17 @@ function renderOpenCodePermissionConfig() {
|
|
|
706
707
|
const OPENCODE_MCP_COMMAND_TEMPLATE = [
|
|
707
708
|
'# audit-code',
|
|
708
709
|
'',
|
|
709
|
-
'Use
|
|
710
|
+
'Use `audit-code next-step` as the primary interface to the audit workflow.',
|
|
710
711
|
'',
|
|
711
|
-
'1.
|
|
712
|
-
'2.
|
|
713
|
-
'3.
|
|
714
|
-
'4.
|
|
712
|
+
'1. Run `audit-code next-step` directly when shell access is available.',
|
|
713
|
+
'2. If MCP is your only available interface, call `auditor_start_audit` or `auditor_continue_audit`; both return the same one-step contract.',
|
|
714
|
+
'3. Read `prompt_content` in the response and follow it.',
|
|
715
|
+
'4. When a step completes (not blocked), run `audit-code next-step` again or call `auditor_continue_audit` as the compatibility adapter.',
|
|
716
|
+
'5. Stop when the step instructions say to stop.',
|
|
715
717
|
'',
|
|
716
|
-
'
|
|
718
|
+
'Use the `task` tool or equivalent for subagent dispatch when the step tells you to fan out review work.',
|
|
717
719
|
'',
|
|
718
|
-
'If `auditor_start_audit` is
|
|
720
|
+
'If neither shell access nor `auditor_start_audit` is available, stop and report that no next-step interface is connected.',
|
|
719
721
|
].join('\n');
|
|
720
722
|
|
|
721
723
|
function renderOpenCodeProjectConfig(_root) {
|
|
@@ -939,7 +941,7 @@ function renderClaudeDesktopProjectTemplate() {
|
|
|
939
941
|
'Suggested project instructions:',
|
|
940
942
|
'',
|
|
941
943
|
'- Treat `/audit-code` as the canonical autonomous audit workflow for this repository.',
|
|
942
|
-
'- Prefer the installed auditor MCP tools over
|
|
944
|
+
'- Prefer `audit-code next-step`; use the installed auditor MCP tools only as a compatibility adapter over the same step contract.',
|
|
943
945
|
'- Read the operator handoff and artifact resources before asking for more context.',
|
|
944
946
|
'- Present the final deterministic audit report as work blocks first.',
|
|
945
947
|
'',
|
|
@@ -951,7 +953,7 @@ function renderClaudeDesktopProjectTemplate() {
|
|
|
951
953
|
'',
|
|
952
954
|
'Starter prompt:',
|
|
953
955
|
'',
|
|
954
|
-
'> Start `/audit-code` for this repository using
|
|
956
|
+
'> Start `/audit-code` for this repository using `audit-code next-step`. Continue until the audit is complete or blocked for operator input, and summarize the current handoff status before you stop.',
|
|
955
957
|
'',
|
|
956
958
|
].join('\n');
|
|
957
959
|
}
|
|
@@ -981,7 +983,7 @@ function renderAntigravityPlanningGuide(root) {
|
|
|
981
983
|
'',
|
|
982
984
|
'1. Open Antigravity in Planning mode.',
|
|
983
985
|
'2. Load the repo-local prompt asset or the AGENTS instructions before starting the audit conversation.',
|
|
984
|
-
'3. Ask Antigravity to use
|
|
986
|
+
'3. Ask Antigravity to use `audit-code next-step` directly. The installed auditor MCP server is available only as compatibility plumbing when direct shell access is unavailable.',
|
|
985
987
|
'4. Review Antigravity artifacts before accepting major code changes or imported evidence.',
|
|
986
988
|
'',
|
|
987
989
|
'Recommended repo-local paths:',
|
|
@@ -1266,9 +1268,9 @@ async function buildClaudeDesktopBundle(root, results) {
|
|
|
1266
1268
|
name: 'auditor-lambda',
|
|
1267
1269
|
display_name: 'Auditor Lambda',
|
|
1268
1270
|
version: packageVersion,
|
|
1269
|
-
description: '
|
|
1271
|
+
description: 'Compatibility MCP bundle for the /audit-code autonomous audit workflow.',
|
|
1270
1272
|
long_description:
|
|
1271
|
-
'Runs
|
|
1273
|
+
'Runs a local compatibility MCP adapter whose start and continue tools return the same audit-code next-step contract as the direct CLI loop.',
|
|
1272
1274
|
author: {
|
|
1273
1275
|
name: 'auditor-lambda',
|
|
1274
1276
|
url: 'https://github.com/OhOkThisIsFine/auditor-lambda',
|
|
@@ -1390,7 +1392,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1390
1392
|
support_level: 'supported',
|
|
1391
1393
|
setup_kind: 'local-mcp-bundle',
|
|
1392
1394
|
summary:
|
|
1393
|
-
'Install the generated local MCP bundle in Claude Desktop, then use the project template and prompt asset as supporting context.',
|
|
1395
|
+
'Install the generated local MCP compatibility bundle in Claude Desktop, then use the project template and prompt asset as supporting context.',
|
|
1394
1396
|
primary_path_key: 'claudeDesktopDxtPath',
|
|
1395
1397
|
supporting_path_keys: [
|
|
1396
1398
|
'claudeDesktopMcpbPath',
|
|
@@ -1400,7 +1402,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1400
1402
|
],
|
|
1401
1403
|
steps: [
|
|
1402
1404
|
'Open Claude Desktop Settings and install the generated `.dxt` bundle.',
|
|
1403
|
-
'Configure the repository root when prompted so the bundle can launch the local auditor MCP
|
|
1405
|
+
'Configure the repository root when prompted so the bundle can launch the local auditor MCP adapter.',
|
|
1404
1406
|
'Use the project template and prompt asset to kick off `/audit-code` in conversation.',
|
|
1405
1407
|
],
|
|
1406
1408
|
profile: {
|
|
@@ -1492,7 +1494,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1492
1494
|
support_level: 'supported',
|
|
1493
1495
|
setup_kind: 'global-command+project-mcp',
|
|
1494
1496
|
summary:
|
|
1495
|
-
'Use the global OpenCode `/audit-code` command installed by npm plus generated project MCP
|
|
1497
|
+
'Use the global OpenCode `/audit-code` command installed by npm plus generated project permissions; MCP is compatibility-only.',
|
|
1496
1498
|
primary_path_key: 'opencodeConfigPath',
|
|
1497
1499
|
supporting_path_keys: [
|
|
1498
1500
|
'agentsInstructionsPath',
|
|
@@ -1501,7 +1503,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1501
1503
|
steps: [
|
|
1502
1504
|
'Open this repository in OpenCode.',
|
|
1503
1505
|
'Use the global `/audit-code` command installed by `npm install -g auditor-lambda`.',
|
|
1504
|
-
'Let OpenCode load the generated `opencode.json` for the
|
|
1506
|
+
'Let OpenCode load the generated `opencode.json` for project permissions; the global command drives `audit-code next-step` directly.',
|
|
1505
1507
|
],
|
|
1506
1508
|
profile: {
|
|
1507
1509
|
writeOpenCode: true,
|
|
@@ -1519,7 +1521,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1519
1521
|
assertOpenCodeAuditPermissionConfig(config?.permission, 'permission');
|
|
1520
1522
|
assertOpenCodeAuditPermissionConfig(config?.agent?.auditor?.permission, 'agent.auditor.permission');
|
|
1521
1523
|
return {
|
|
1522
|
-
summary: 'OpenCode project config has audit permissions;
|
|
1524
|
+
summary: 'OpenCode project config has audit permissions; /audit-code is supplied by the global npm-installed config.',
|
|
1523
1525
|
path: assetPaths.opencodeConfigPath,
|
|
1524
1526
|
};
|
|
1525
1527
|
});
|
|
@@ -1531,7 +1533,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1531
1533
|
support_level: 'supported',
|
|
1532
1534
|
setup_kind: 'prompt+agent+mcp',
|
|
1533
1535
|
summary:
|
|
1534
|
-
'Use the generated prompt file
|
|
1536
|
+
'Use the generated prompt file and custom agent for next-step-first VS Code integration; workspace MCP is compatibility-only.',
|
|
1535
1537
|
primary_path_key: 'vscodePromptPath',
|
|
1536
1538
|
supporting_path_keys: [
|
|
1537
1539
|
'vscodeAgentPath',
|
|
@@ -1540,8 +1542,8 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1540
1542
|
],
|
|
1541
1543
|
steps: [
|
|
1542
1544
|
'Open this repository in VS Code with Copilot.',
|
|
1543
|
-
'
|
|
1544
|
-
'
|
|
1545
|
+
'Invoke `/audit-code` from the generated prompt or chat so the workflow calls `audit-code next-step` directly.',
|
|
1546
|
+
'Use the workspace MCP adapter only when direct shell access is unavailable.',
|
|
1545
1547
|
],
|
|
1546
1548
|
profile: {
|
|
1547
1549
|
writeVSCode: true,
|
|
@@ -1587,7 +1589,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1587
1589
|
support_level: 'supported',
|
|
1588
1590
|
setup_kind: 'agent-skill+gemini-command+planning-guide+mcp-ready',
|
|
1589
1591
|
summary:
|
|
1590
|
-
'Uses the project-scoped .agent/skills/audit-code/SKILL.md skill, the .gemini/commands/audit-code.toml slash command, the planning guide, and AGENTS instructions. The shared MCP launcher is
|
|
1592
|
+
'Uses the project-scoped .agent/skills/audit-code/SKILL.md skill, the .gemini/commands/audit-code.toml slash command, the planning guide, and AGENTS instructions. The shared MCP launcher is compatibility-only.',
|
|
1591
1593
|
primary_path_key: 'antigravitySkillPath',
|
|
1592
1594
|
supporting_path_keys: [
|
|
1593
1595
|
'geminiCommandPath',
|
|
@@ -1600,7 +1602,7 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1600
1602
|
'Open this repository in Antigravity.',
|
|
1601
1603
|
'The audit-code skill is automatically discovered from .agent/skills/audit-code/SKILL.md.',
|
|
1602
1604
|
'The /audit-code slash command is also available from .gemini/commands/audit-code.toml.',
|
|
1603
|
-
'Use the shared auditor MCP
|
|
1605
|
+
'Use `audit-code next-step` directly; use the shared auditor MCP launcher only when direct shell access is unavailable.',
|
|
1604
1606
|
],
|
|
1605
1607
|
profile: {
|
|
1606
1608
|
writeAntigravity: true,
|
package/dist/cli.d.ts
CHANGED
|
@@ -2,6 +2,11 @@ import type { SessionConfig } from "./types/sessionConfig.js";
|
|
|
2
2
|
type UiMode = "visible" | "headless";
|
|
3
3
|
declare function getFlag(argv: string[], name: string, fallback?: string): string | undefined;
|
|
4
4
|
declare function hasFlag(argv: string[], name: string): boolean;
|
|
5
|
+
export declare function resolveHostDispatchCapability(options: {
|
|
6
|
+
explicit?: boolean;
|
|
7
|
+
sessionConfig: SessionConfig;
|
|
8
|
+
env?: NodeJS.ProcessEnv;
|
|
9
|
+
}): boolean;
|
|
5
10
|
declare function getArtifactsDir(argv: string[]): string;
|
|
6
11
|
declare function getRootDir(argv: string[]): string;
|
|
7
12
|
declare function warnIfNotGitRepo(root: string): void;
|
package/dist/cli.js
CHANGED
|
@@ -28,11 +28,11 @@ import { buildAuditCodeHandoff, writeAuditCodeHandoffArtifacts, } from "./superv
|
|
|
28
28
|
import { getSessionConfigPath, loadSessionConfig, readSessionConfigFile, } from "./supervisor/sessionConfig.js";
|
|
29
29
|
import { clearDispatchFiles, buildRunId, ensureSupervisorDirs, getRunPaths, writeDispatchBatchFiles, writeWorkerTaskFiles, } from "./io/runArtifacts.js";
|
|
30
30
|
import { renderWorkerPrompt } from "./prompts/renderWorkerPrompt.js";
|
|
31
|
-
import { buildReviewPackets, orderTasksForPacketReview, } from "./orchestrator/reviewPackets.js";
|
|
31
|
+
import { buildReviewPackets, orderTasksForPacketReview, estimateTaskGroupTokens, } from "./orchestrator/reviewPackets.js";
|
|
32
32
|
import { buildFileAnchorSummary, } from "./orchestrator/fileAnchors.js";
|
|
33
33
|
import { LOCAL_SUBPROCESS_PROVIDER_NAME } from "./providers/constants.js";
|
|
34
34
|
import { runAuditCodeMcpServer } from "./mcp/server.js";
|
|
35
|
-
import { scheduleWave, buildProviderModelKey, readQuotaState, recordWaveOutcome, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, } from "./quota/index.js";
|
|
35
|
+
import { scheduleWave, buildProviderModelKey, readQuotaState, recordWaveOutcome, resolveLimits, resolveHostActiveSubagentLimit, probeProvider, computeMaxSafeConcurrency, getQuotaStatePath, detectRateLimitError, computeCooldownUntil, runSlidingWindow, LearnedQuotaSource, CompositeQuotaSource, } from "./quota/index.js";
|
|
36
36
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
37
37
|
const ADVANCE_AUDIT_CONTRACT_VERSION = "audit-code/v1alpha1";
|
|
38
38
|
const WORKER_RESULT_CONTRACT_VERSION = "audit-code-worker-result/v1alpha1";
|
|
@@ -87,6 +87,22 @@ function getOptionalBooleanFlag(argv, name) {
|
|
|
87
87
|
}
|
|
88
88
|
throw new Error(`${name} must be either true or false.`);
|
|
89
89
|
}
|
|
90
|
+
function optionalBooleanEnv(value) {
|
|
91
|
+
if (value === "true")
|
|
92
|
+
return true;
|
|
93
|
+
if (value === "false")
|
|
94
|
+
return false;
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
export function resolveHostDispatchCapability(options) {
|
|
98
|
+
if (options.explicit !== undefined) {
|
|
99
|
+
return options.explicit;
|
|
100
|
+
}
|
|
101
|
+
if (options.sessionConfig.host_can_dispatch_subagents !== undefined) {
|
|
102
|
+
return options.sessionConfig.host_can_dispatch_subagents;
|
|
103
|
+
}
|
|
104
|
+
return optionalBooleanEnv((options.env ?? process.env).AUDIT_CODE_HOST_CAN_DISPATCH) ?? true;
|
|
105
|
+
}
|
|
90
106
|
function toBase64Url(value) {
|
|
91
107
|
return Buffer.from(value, "utf8").toString("base64url");
|
|
92
108
|
}
|
|
@@ -212,18 +228,6 @@ function getQuotaProbeMode(argv, sessionConfig) {
|
|
|
212
228
|
return raw;
|
|
213
229
|
return "auto";
|
|
214
230
|
}
|
|
215
|
-
function detectRateLimitError(errorText) {
|
|
216
|
-
const lower = errorText.toLowerCase();
|
|
217
|
-
return lower.includes("429") || lower.includes("rate limit") || lower.includes("rate_limit");
|
|
218
|
-
}
|
|
219
|
-
function defaultCooldownUntil(resetAtHeader) {
|
|
220
|
-
if (resetAtHeader) {
|
|
221
|
-
const t = new Date(resetAtHeader).getTime();
|
|
222
|
-
if (!Number.isNaN(t))
|
|
223
|
-
return new Date(t).toISOString();
|
|
224
|
-
}
|
|
225
|
-
return new Date(Date.now() + 60_000).toISOString();
|
|
226
|
-
}
|
|
227
231
|
function resolveRunProviderName(argv, sessionConfig) {
|
|
228
232
|
return resolveFreshSessionProviderName(getExplicitProvider(argv), sessionConfig);
|
|
229
233
|
}
|
|
@@ -535,50 +539,6 @@ function mergeAndIngestCommand(artifactsDir, runId) {
|
|
|
535
539
|
artifactsDir,
|
|
536
540
|
]);
|
|
537
541
|
}
|
|
538
|
-
function renderCapabilityCheckPrompt(params) {
|
|
539
|
-
const yesCommand = nextStepCommand(params.root, params.artifactsDir, [
|
|
540
|
-
"--host-can-dispatch-subagents",
|
|
541
|
-
"true",
|
|
542
|
-
]);
|
|
543
|
-
const noCommand = nextStepCommand(params.root, params.artifactsDir, [
|
|
544
|
-
"--host-can-dispatch-subagents",
|
|
545
|
-
"false",
|
|
546
|
-
]);
|
|
547
|
-
return [
|
|
548
|
-
"# audit-code capability check",
|
|
549
|
-
"",
|
|
550
|
-
"Decide one thing from the active toolset: does this host expose a callable subagent/delegation tool for source-code review, such as `task`, Agent, or an equivalent built-in subagent call?",
|
|
551
|
-
"",
|
|
552
|
-
"Do not run shell commands to answer this. Do not inspect packet prompts, schemas, or backend command catalogs.",
|
|
553
|
-
"",
|
|
554
|
-
"**If auditor MCP tools are available** (preferred — no shell required):",
|
|
555
|
-
"",
|
|
556
|
-
"Call `auditor_report_capability` with:",
|
|
557
|
-
"- `can_dispatch_subagents: true` if the `task` tool or equivalent subagent dispatch is available",
|
|
558
|
-
"- `can_dispatch_subagents: false` if not",
|
|
559
|
-
"- Optionally `can_restrict_subagent_tools: true` and/or `can_select_subagent_model: true`",
|
|
560
|
-
"- If the host documents or exposes a hard cap on simultaneously active subagents, include `max_active_subagents`.",
|
|
561
|
-
"",
|
|
562
|
-
"Read the `prompt_content` field in the tool response and follow it.",
|
|
563
|
-
"",
|
|
564
|
-
"**Fallback — if auditor MCP tools are not available:**",
|
|
565
|
-
"",
|
|
566
|
-
"If callable subagents are available, run:",
|
|
567
|
-
"",
|
|
568
|
-
` ${yesCommand}`,
|
|
569
|
-
"",
|
|
570
|
-
"If callable subagents are not available, run:",
|
|
571
|
-
"",
|
|
572
|
-
` ${noCommand}`,
|
|
573
|
-
"",
|
|
574
|
-
"If the host can also restrict tools per subagent or select models per subagent, add the matching `--host-can-restrict-subagent-tools true` or `--host-can-select-subagent-model true` flags to the same command. Omit those flags when unsure.",
|
|
575
|
-
"",
|
|
576
|
-
"If the host has a known active-subagent ceiling, add `--host-max-active-subagents <n>` to the same command. For Codex Desktop, use 6.",
|
|
577
|
-
"",
|
|
578
|
-
"After the command writes the next step, read and follow only its `prompt_path`.",
|
|
579
|
-
"",
|
|
580
|
-
].join("\n");
|
|
581
|
-
}
|
|
582
542
|
function renderDispatchReviewPrompt(params) {
|
|
583
543
|
const mergeCommand = mergeAndIngestCommand(params.artifactsDir, params.activeReviewRun.run_id);
|
|
584
544
|
const continueCommand = nextStepCommand(params.root, params.artifactsDir);
|
|
@@ -588,32 +548,21 @@ function renderDispatchReviewPrompt(params) {
|
|
|
588
548
|
const toolsLine = params.hostCanRestrictSubagentTools
|
|
589
549
|
? "Restrict review subagents to read/search plus the packet submit command named in their prompt. Do not give them source edit/write tools."
|
|
590
550
|
: "Do not ask the user about per-subagent tool restrictions; this host did not report a callable restriction facility.";
|
|
591
|
-
const runId = params.activeReviewRun.run_id;
|
|
592
551
|
const dispatchDataLines = params.dispatchQuotaPath
|
|
593
552
|
? [
|
|
594
|
-
"
|
|
553
|
+
"Read these generated files unless the current tool response already included equivalent `dispatch_plan_entries` and `dispatch_quota` fields:",
|
|
595
554
|
"",
|
|
596
|
-
|
|
555
|
+
` Dispatch plan: ${params.dispatchPlanPath}`,
|
|
556
|
+
` Dispatch quota: ${params.dispatchQuotaPath}`,
|
|
597
557
|
"",
|
|
598
|
-
"Use the `wave_size` from
|
|
558
|
+
"Use the `wave_size` from the quota data. If `cooldown_until` is non-null, wait until that timestamp before starting the first wave.",
|
|
599
559
|
"",
|
|
600
|
-
"`
|
|
560
|
+
"`host_concurrency_limit` records any detected hard host cap that contributed to `wave_size`.",
|
|
601
561
|
"",
|
|
602
562
|
"For each wave: use the `task` tool (or equivalent subagent dispatch) to launch up to `wave_size` subagents in parallel (one per entry), wait for all to finish, then start the next wave.",
|
|
603
|
-
"",
|
|
604
|
-
"**Fallback — if auditor MCP tools are not available:** Read both of these files:",
|
|
605
|
-
"",
|
|
606
|
-
` Dispatch plan: ${params.dispatchPlanPath}`,
|
|
607
|
-
` Dispatch quota: ${params.dispatchQuotaPath}`,
|
|
608
|
-
"",
|
|
609
|
-
"Apply the same wave logic from the quota file.",
|
|
610
563
|
]
|
|
611
564
|
: [
|
|
612
|
-
"
|
|
613
|
-
"",
|
|
614
|
-
"The dispatch plan entries are in the `dispatch_plan_entries` field of the tool response that returned this step.",
|
|
615
|
-
"",
|
|
616
|
-
"**Fallback — if auditor MCP tools are not available:** Read this dispatch plan JSON:",
|
|
565
|
+
"Read this generated dispatch plan unless the current tool response already included equivalent `dispatch_plan_entries`:",
|
|
617
566
|
"",
|
|
618
567
|
` ${params.dispatchPlanPath}`,
|
|
619
568
|
"",
|
|
@@ -637,9 +586,7 @@ function renderDispatchReviewPrompt(params) {
|
|
|
637
586
|
"",
|
|
638
587
|
"**After all waves complete:**",
|
|
639
588
|
"",
|
|
640
|
-
"
|
|
641
|
-
"",
|
|
642
|
-
"Fallback — if auditor MCP tools are not available, run exactly:",
|
|
589
|
+
"Run exactly:",
|
|
643
590
|
"",
|
|
644
591
|
` ${mergeCommand}`,
|
|
645
592
|
"",
|
|
@@ -1185,6 +1132,10 @@ async function cmdNextStep(argv) {
|
|
|
1185
1132
|
console.log(JSON.stringify(step, null, 2));
|
|
1186
1133
|
return;
|
|
1187
1134
|
}
|
|
1135
|
+
const hostCanDispatch = resolveHostDispatchCapability({
|
|
1136
|
+
explicit: hostCanDispatchSubagents,
|
|
1137
|
+
sessionConfig,
|
|
1138
|
+
});
|
|
1188
1139
|
const result = await runDeterministicForNextStep({
|
|
1189
1140
|
root,
|
|
1190
1141
|
artifactsDir,
|
|
@@ -1226,35 +1177,7 @@ async function cmdNextStep(argv) {
|
|
|
1226
1177
|
console.log(JSON.stringify(step, null, 2));
|
|
1227
1178
|
return;
|
|
1228
1179
|
}
|
|
1229
|
-
if (
|
|
1230
|
-
const yesCommand = nextStepCommand(root, artifactsDir, [
|
|
1231
|
-
"--host-can-dispatch-subagents",
|
|
1232
|
-
"true",
|
|
1233
|
-
]);
|
|
1234
|
-
const noCommand = nextStepCommand(root, artifactsDir, [
|
|
1235
|
-
"--host-can-dispatch-subagents",
|
|
1236
|
-
"false",
|
|
1237
|
-
]);
|
|
1238
|
-
const step = await writeCurrentStep({
|
|
1239
|
-
artifactsDir,
|
|
1240
|
-
stepKind: "capability_check",
|
|
1241
|
-
status: "ready",
|
|
1242
|
-
runId: result.activeReviewRun.run_id,
|
|
1243
|
-
allowedCommands: [yesCommand, noCommand],
|
|
1244
|
-
stopCondition: "Run exactly one next-step command with an explicit host dispatch capability.",
|
|
1245
|
-
repoRoot: root,
|
|
1246
|
-
artifactPaths: {
|
|
1247
|
-
active_review_task: result.activeReviewRun.task_path,
|
|
1248
|
-
active_review_prompt: result.activeReviewRun.prompt_path,
|
|
1249
|
-
pending_audit_tasks: result.activeReviewRun.pending_audit_tasks_path ?? null,
|
|
1250
|
-
single_task_prompt: join(artifactsDir, "dispatch", "current-single-task-prompt.md"),
|
|
1251
|
-
},
|
|
1252
|
-
prompt: renderCapabilityCheckPrompt({ root, artifactsDir }),
|
|
1253
|
-
});
|
|
1254
|
-
console.log(JSON.stringify(step, null, 2));
|
|
1255
|
-
return;
|
|
1256
|
-
}
|
|
1257
|
-
if (!hostCanDispatchSubagents) {
|
|
1180
|
+
if (!hostCanDispatch) {
|
|
1258
1181
|
const singleTaskPromptPath = join(artifactsDir, "dispatch", "current-single-task-prompt.md");
|
|
1259
1182
|
const workerCommand = renderCommand(result.activeReviewRun.worker_command);
|
|
1260
1183
|
const step = await writeCurrentStep({
|
|
@@ -1299,7 +1222,7 @@ async function cmdNextStep(argv) {
|
|
|
1299
1222
|
mergeCommand,
|
|
1300
1223
|
continueCommand,
|
|
1301
1224
|
],
|
|
1302
|
-
stopCondition: "Dispatch every packet,
|
|
1225
|
+
stopCondition: "Dispatch every packet, run merge-and-ingest once, then run next-step.",
|
|
1303
1226
|
repoRoot: root,
|
|
1304
1227
|
artifactPaths: {
|
|
1305
1228
|
dispatch_plan: dispatch.dispatch_plan_path,
|
|
@@ -1487,11 +1410,15 @@ async function cmdRunToCompletion(argv) {
|
|
|
1487
1410
|
const quotaState = await readQuotaState();
|
|
1488
1411
|
const providerModelKey = buildProviderModelKey(provider.name, hostModel);
|
|
1489
1412
|
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
1413
|
+
const allCandidateTasks = buildPendingAuditTasks(bundle);
|
|
1414
|
+
const candidateGroups = chunkArray(allCandidateTasks.slice(0, parallelWorkers * agentBatchSize), agentBatchSize);
|
|
1415
|
+
const slotTokenEstimates = candidateGroups.map((g) => estimateTaskGroupTokens(g));
|
|
1490
1416
|
const waveSchedule = scheduleWave({
|
|
1491
1417
|
providerName: resolveFreshSessionProviderName(getExplicitProvider(argv), sessionConfig),
|
|
1492
1418
|
sessionConfig,
|
|
1493
1419
|
hostModel,
|
|
1494
1420
|
requestedConcurrency: parallelWorkers,
|
|
1421
|
+
estimatedSlotTokens: slotTokenEstimates,
|
|
1495
1422
|
quotaStateEntry,
|
|
1496
1423
|
});
|
|
1497
1424
|
const waveSize = waveSchedule.wave_size;
|
|
@@ -1503,8 +1430,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1503
1430
|
await new Promise((r) => setTimeout(r, cappedWait));
|
|
1504
1431
|
}
|
|
1505
1432
|
}
|
|
1506
|
-
const
|
|
1507
|
-
const taskGroups = chunkArray(allPendingTasks.slice(0, waveSize * agentBatchSize), agentBatchSize);
|
|
1433
|
+
const taskGroups = candidateGroups.slice(0, waveSize);
|
|
1508
1434
|
const workerSlots = [];
|
|
1509
1435
|
for (const rawGroup of taskGroups) {
|
|
1510
1436
|
const group = await addFileLineCountHints(root, rawGroup);
|
|
@@ -1543,7 +1469,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1543
1469
|
pending_audit_tasks_path: slot.pendingTasksPath,
|
|
1544
1470
|
})), workerSlots.flatMap((slot) => slot.group));
|
|
1545
1471
|
const parallelStartedAt = new Date().toISOString();
|
|
1546
|
-
const launchResults = await
|
|
1472
|
+
const { results: launchResults } = await runSlidingWindow(workerSlots.map((slot) => () => provider.launch({
|
|
1547
1473
|
repoRoot: root,
|
|
1548
1474
|
runId: slot.runId,
|
|
1549
1475
|
obligationId,
|
|
@@ -1554,7 +1480,7 @@ async function cmdRunToCompletion(argv) {
|
|
|
1554
1480
|
stderrPath: slot.paths.stderrPath,
|
|
1555
1481
|
uiMode,
|
|
1556
1482
|
timeoutMs,
|
|
1557
|
-
})));
|
|
1483
|
+
})), waveSize);
|
|
1558
1484
|
const launchErrorsByRunId = new Map();
|
|
1559
1485
|
for (let index = 0; index < launchResults.length; index++) {
|
|
1560
1486
|
const outcome = launchResults[index];
|
|
@@ -1666,12 +1592,14 @@ async function cmdRunToCompletion(argv) {
|
|
|
1666
1592
|
}
|
|
1667
1593
|
// Record outcome for adaptive learning (best-effort — never blocks dispatch)
|
|
1668
1594
|
{
|
|
1669
|
-
const
|
|
1595
|
+
const rateLimitResults = batchErrors.map((e) => detectRateLimitError(e));
|
|
1596
|
+
const rateLimitHit = rateLimitResults.find((r) => r.isRateLimited);
|
|
1597
|
+
const retryAfterMs = rateLimitHit?.retryAfterMs ?? null;
|
|
1670
1598
|
await recordWaveOutcome(providerModelKey, {
|
|
1671
1599
|
concurrency: workerSlots.length,
|
|
1672
|
-
estimated_tokens:
|
|
1673
|
-
outcome:
|
|
1674
|
-
cooldown_until:
|
|
1600
|
+
estimated_tokens: slotTokenEstimates.slice(0, workerSlots.length).reduce((a, b) => a + b, 0),
|
|
1601
|
+
outcome: rateLimitHit ? "rate_limited" : batchErrors.length > 0 ? "timeout" : "success",
|
|
1602
|
+
cooldown_until: rateLimitHit ? computeCooldownUntil(retryAfterMs) : null,
|
|
1675
1603
|
}, sessionConfig.quota?.empirical_half_life_hours ?? 24).catch(() => undefined);
|
|
1676
1604
|
}
|
|
1677
1605
|
if (batchErrors.length > 0) {
|
|
@@ -2520,12 +2448,10 @@ async function prepareDispatchArtifacts(params) {
|
|
|
2520
2448
|
});
|
|
2521
2449
|
// Compute and write dispatch-quota.json
|
|
2522
2450
|
const hostModel = params.hostModel ?? null;
|
|
2523
|
-
const
|
|
2524
|
-
? Math.floor(plan.reduce((s, p) => s + p.complexity.estimated_tokens, 0) / plan.length)
|
|
2525
|
-
: 0;
|
|
2451
|
+
const perPacketTokens = plan.map((p) => p.complexity.estimated_tokens);
|
|
2526
2452
|
const quotaProviderName = resolveFreshSessionProviderName(undefined, sessionConfig);
|
|
2527
2453
|
const quotaProviderKey = buildProviderModelKey(quotaProviderName, hostModel);
|
|
2528
|
-
const quotaState = await readQuotaState().catch(() => ({ version:
|
|
2454
|
+
const quotaState = await readQuotaState().catch(() => ({ version: 2, entries: {} }));
|
|
2529
2455
|
const quotaStateEntry = quotaState.entries[quotaProviderKey] ?? null;
|
|
2530
2456
|
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({
|
|
2531
2457
|
explicitLimit: params.hostActiveSubagentLimit,
|
|
@@ -2536,12 +2462,12 @@ async function prepareDispatchArtifacts(params) {
|
|
|
2536
2462
|
sessionConfig,
|
|
2537
2463
|
hostModel,
|
|
2538
2464
|
requestedConcurrency: sessionConfig.parallel_workers ?? plan.length,
|
|
2539
|
-
|
|
2465
|
+
estimatedSlotTokens: perPacketTokens,
|
|
2540
2466
|
quotaStateEntry,
|
|
2541
2467
|
hostConcurrencyLimit,
|
|
2542
2468
|
});
|
|
2543
2469
|
const dispatchQuota = {
|
|
2544
|
-
contract_version: "audit-code-dispatch-quota/
|
|
2470
|
+
contract_version: "audit-code-dispatch-quota/v1alpha2",
|
|
2545
2471
|
run_id: runId,
|
|
2546
2472
|
model: hostModel,
|
|
2547
2473
|
resolved_limits: waveSchedule.resolved_limits,
|
|
@@ -2551,6 +2477,8 @@ async function prepareDispatchArtifacts(params) {
|
|
|
2551
2477
|
wave_size: waveSchedule.wave_size,
|
|
2552
2478
|
estimated_wave_tokens: waveSchedule.estimated_wave_tokens,
|
|
2553
2479
|
cooldown_until: waveSchedule.cooldown_until,
|
|
2480
|
+
quota_source_snapshot: waveSchedule.quota_source_snapshot ?? null,
|
|
2481
|
+
backoff_state: null,
|
|
2554
2482
|
};
|
|
2555
2483
|
const dispatchQuotaPath = join(runDir, "dispatch-quota.json");
|
|
2556
2484
|
await writeJsonFile(dispatchQuotaPath, dispatchQuota);
|
|
@@ -3277,13 +3205,15 @@ async function cmdQuota(argv) {
|
|
|
3277
3205
|
const providerModelKey = buildProviderModelKey(providerName, hostModel);
|
|
3278
3206
|
const { limits, source, confidence } = resolveLimits({ providerName, sessionConfig, hostModel });
|
|
3279
3207
|
const probeResult = await probeProvider(providerName, probeMode);
|
|
3280
|
-
const quotaState = await readQuotaState().catch(() => ({ version:
|
|
3208
|
+
const quotaState = await readQuotaState().catch(() => ({ version: 2, entries: {} }));
|
|
3281
3209
|
const quotaStateEntry = quotaState.entries[providerModelKey] ?? null;
|
|
3282
3210
|
const halfLifeHours = sessionConfig.quota?.empirical_half_life_hours ?? 24;
|
|
3283
3211
|
const hostConcurrencyLimit = resolveHostActiveSubagentLimit({
|
|
3284
3212
|
explicitLimit: getHostMaxActiveSubagents(argv),
|
|
3285
3213
|
sessionConfig,
|
|
3286
3214
|
});
|
|
3215
|
+
const quotaSource = new CompositeQuotaSource([new LearnedQuotaSource(halfLifeHours)]);
|
|
3216
|
+
const quotaSourceSnapshot = await quotaSource.queryCurrentUsage(providerModelKey).catch(() => null);
|
|
3287
3217
|
const waveSchedule = scheduleWave({
|
|
3288
3218
|
providerName,
|
|
3289
3219
|
sessionConfig,
|
|
@@ -3291,6 +3221,7 @@ async function cmdQuota(argv) {
|
|
|
3291
3221
|
requestedConcurrency: sessionConfig.parallel_workers ?? 1,
|
|
3292
3222
|
quotaStateEntry,
|
|
3293
3223
|
hostConcurrencyLimit,
|
|
3224
|
+
quotaSourceSnapshot,
|
|
3294
3225
|
});
|
|
3295
3226
|
console.log(JSON.stringify({
|
|
3296
3227
|
provider: providerName,
|
|
@@ -3308,6 +3239,7 @@ async function cmdQuota(argv) {
|
|
|
3308
3239
|
last_429_at: quotaStateEntry.last_429_at,
|
|
3309
3240
|
}
|
|
3310
3241
|
: null,
|
|
3242
|
+
quota_source_snapshot: quotaSourceSnapshot,
|
|
3311
3243
|
wave_schedule: waveSchedule,
|
|
3312
3244
|
quota_state_path: getQuotaStatePath(),
|
|
3313
3245
|
}, null, 2));
|
package/dist/mcp/server.js
CHANGED
|
@@ -250,16 +250,16 @@ function resourceListPayload() {
|
|
|
250
250
|
export const promptRegistry = [
|
|
251
251
|
{
|
|
252
252
|
name: "audit-code",
|
|
253
|
-
description: "Start or continue the autonomous audit loop through the
|
|
253
|
+
description: "Start or continue the autonomous audit loop through the next-step machine.",
|
|
254
254
|
arguments: [],
|
|
255
255
|
render() {
|
|
256
256
|
return [
|
|
257
|
-
"Use
|
|
258
|
-
"1.
|
|
259
|
-
"2. If
|
|
257
|
+
"Use `audit-code next-step` as the canonical interface to the backend wrapper.",
|
|
258
|
+
"1. Prefer running `audit-code next-step` directly from the repository root.",
|
|
259
|
+
"2. If this MCP adapter is your only available integration, call `start_audit` or `continue_audit`; both return the same one-step contract.",
|
|
260
|
+
"3. If the audit is blocked, inspect `audit-code://handoff/current`.",
|
|
260
261
|
" Do not read `audit-code://artifacts/current` unless explicitly needed for a specific task; it is massive and consumes your context window.",
|
|
261
|
-
"
|
|
262
|
-
"4. Call `continue_audit` until the status is complete or explicitly blocked for operator input.",
|
|
262
|
+
"4. When the user provides additional evidence, call `import_results` or `import_runtime_updates`.",
|
|
263
263
|
].join("\n");
|
|
264
264
|
},
|
|
265
265
|
},
|
|
@@ -306,7 +306,7 @@ function renderPrompt(name, args) {
|
|
|
306
306
|
}
|
|
307
307
|
return entry.render(args);
|
|
308
308
|
}
|
|
309
|
-
async function runContinueAudit(context, extraArgs = []) {
|
|
309
|
+
async function runContinueAudit(context, extraArgs = ["next-step"]) {
|
|
310
310
|
const step = await parseCliJson(extraArgs, context);
|
|
311
311
|
if (!step || typeof step !== "object" || Array.isArray(step))
|
|
312
312
|
return step;
|
|
@@ -410,7 +410,7 @@ function toolDefinitions() {
|
|
|
410
410
|
return [
|
|
411
411
|
{
|
|
412
412
|
name: "start_audit",
|
|
413
|
-
description: "
|
|
413
|
+
description: "Compatibility adapter over audit-code next-step; returns one step contract.",
|
|
414
414
|
inputSchema: {
|
|
415
415
|
type: "object",
|
|
416
416
|
properties: {
|
|
@@ -438,7 +438,7 @@ function toolDefinitions() {
|
|
|
438
438
|
},
|
|
439
439
|
{
|
|
440
440
|
name: "continue_audit",
|
|
441
|
-
description: "
|
|
441
|
+
description: "Compatibility adapter over audit-code next-step from the current artifacts directory.",
|
|
442
442
|
inputSchema: {
|
|
443
443
|
type: "object",
|
|
444
444
|
properties: {
|
|
@@ -542,7 +542,7 @@ function toolDefinitions() {
|
|
|
542
542
|
},
|
|
543
543
|
{
|
|
544
544
|
name: "report_capability",
|
|
545
|
-
description: "
|
|
545
|
+
description: "Compatibility adapter that calls audit-code next-step with host subagent capability flags.",
|
|
546
546
|
inputSchema: {
|
|
547
547
|
type: "object",
|
|
548
548
|
properties: {
|
|
@@ -632,7 +632,7 @@ export async function dispatchRequest(request, ctx) {
|
|
|
632
632
|
name: "audit-code",
|
|
633
633
|
version: ctx.version,
|
|
634
634
|
},
|
|
635
|
-
instructions: "Use
|
|
635
|
+
instructions: "Use audit-code next-step as the primary backend loop. These MCP tools are compatibility adapters that return the same one-step contract.",
|
|
636
636
|
capabilities: {
|
|
637
637
|
tools: { listChanged: false },
|
|
638
638
|
resources: { subscribe: false, listChanged: false },
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { AuditTask } from "../types.js";
|
|
2
2
|
import type { AuditPlanMetrics, ReviewPacket } from "../types/reviewPlanning.js";
|
|
3
3
|
import type { GraphBundle } from "../types/graph.js";
|
|
4
|
+
export declare const ESTIMATED_TOKENS_PER_LINE = 4;
|
|
5
|
+
export declare const ESTIMATED_PACKET_PROMPT_TOKENS = 900;
|
|
6
|
+
export declare function estimateTaskGroupTokens(tasks: AuditTask[]): number;
|
|
4
7
|
export interface BuildReviewPacketOptions {
|
|
5
8
|
graphBundle?: GraphBundle;
|
|
6
9
|
lineIndex?: Record<string, number>;
|