auditor-lambda 0.3.23 → 0.3.24
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/audit-code-wrapper-lib.mjs +15 -0
- package/dist/cli.js +48 -15
- package/dist/mcp/server.js +110 -2
- package/package.json +1 -1
- package/scripts/postinstall.mjs +25 -15
|
@@ -605,6 +605,19 @@ function renderOpenCodePermissionConfig() {
|
|
|
605
605
|
};
|
|
606
606
|
}
|
|
607
607
|
|
|
608
|
+
const OPENCODE_MCP_COMMAND_TEMPLATE = [
|
|
609
|
+
'# audit-code',
|
|
610
|
+
'',
|
|
611
|
+
'Use the auditor MCP tools as the primary interface to the audit workflow.',
|
|
612
|
+
'',
|
|
613
|
+
'1. Call `auditor_start_audit` to initialize and receive the first step.',
|
|
614
|
+
'2. Read the `prompt_content` field in the response and follow the instructions there.',
|
|
615
|
+
'3. When a step completes (not blocked), call `auditor_continue_audit` to advance.',
|
|
616
|
+
'4. Stop when the step instructions say to stop.',
|
|
617
|
+
'',
|
|
618
|
+
'Do not run shell commands. Use only `auditor_*` MCP tools and the `task` tool for subagent dispatch.',
|
|
619
|
+
].join('\n');
|
|
620
|
+
|
|
608
621
|
function renderOpenCodeProjectConfig(root) {
|
|
609
622
|
const launcher = replaceBackslashes(toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME)));
|
|
610
623
|
const auditPermission = renderOpenCodePermissionConfig();
|
|
@@ -625,10 +638,12 @@ function renderOpenCodeProjectConfig(root) {
|
|
|
625
638
|
'Read-heavy audit orchestration agent for the /audit-code workflow.',
|
|
626
639
|
tools: {
|
|
627
640
|
'auditor*': true,
|
|
641
|
+
task: true,
|
|
628
642
|
},
|
|
629
643
|
permission: {
|
|
630
644
|
...auditPermission,
|
|
631
645
|
question: 'allow',
|
|
646
|
+
task: 'allow',
|
|
632
647
|
},
|
|
633
648
|
},
|
|
634
649
|
},
|
package/dist/cli.js
CHANGED
|
@@ -523,10 +523,21 @@ function renderCapabilityCheckPrompt(params) {
|
|
|
523
523
|
return [
|
|
524
524
|
"# audit-code capability check",
|
|
525
525
|
"",
|
|
526
|
-
"Decide one thing from the active toolset: does this host expose a callable subagent/delegation tool for source-code review, such as Agent,
|
|
526
|
+
"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?",
|
|
527
527
|
"",
|
|
528
528
|
"Do not run shell commands to answer this. Do not inspect packet prompts, schemas, or backend command catalogs.",
|
|
529
529
|
"",
|
|
530
|
+
"**If auditor MCP tools are available** (preferred — no shell required):",
|
|
531
|
+
"",
|
|
532
|
+
"Call `auditor_report_capability` with:",
|
|
533
|
+
"- `can_dispatch_subagents: true` if the `task` tool or equivalent subagent dispatch is available",
|
|
534
|
+
"- `can_dispatch_subagents: false` if not",
|
|
535
|
+
"- Optionally `can_restrict_subagent_tools: true` and/or `can_select_subagent_model: true`",
|
|
536
|
+
"",
|
|
537
|
+
"Read the `prompt_content` field in the tool response and follow it.",
|
|
538
|
+
"",
|
|
539
|
+
"**Fallback — if auditor MCP tools are not available:**",
|
|
540
|
+
"",
|
|
530
541
|
"If callable subagents are available, run:",
|
|
531
542
|
"",
|
|
532
543
|
` ${yesCommand}`,
|
|
@@ -550,30 +561,41 @@ function renderDispatchReviewPrompt(params) {
|
|
|
550
561
|
const toolsLine = params.hostCanRestrictSubagentTools
|
|
551
562
|
? "Restrict review subagents to read/search plus the packet submit command named in their prompt. Do not give them source edit/write tools."
|
|
552
563
|
: "Do not ask the user about per-subagent tool restrictions; this host did not report a callable restriction facility.";
|
|
553
|
-
const
|
|
564
|
+
const runId = params.activeReviewRun.run_id;
|
|
565
|
+
const dispatchDataLines = params.dispatchQuotaPath
|
|
554
566
|
? [
|
|
555
|
-
"
|
|
567
|
+
"**If auditor MCP tools are available** (preferred):",
|
|
568
|
+
"",
|
|
569
|
+
"The dispatch plan entries are in the `dispatch_plan_entries` field of the tool response that returned this step. The wave schedule is in the `dispatch_quota` field.",
|
|
570
|
+
"",
|
|
571
|
+
"Use the `wave_size` from `dispatch_quota`. If `cooldown_until` is non-null, wait until that timestamp before starting the first wave.",
|
|
572
|
+
"",
|
|
573
|
+
"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.",
|
|
574
|
+
"",
|
|
575
|
+
"**Fallback — if auditor MCP tools are not available:** Read both of these files:",
|
|
556
576
|
"",
|
|
557
577
|
` Dispatch plan: ${params.dispatchPlanPath}`,
|
|
558
578
|
` Dispatch quota: ${params.dispatchQuotaPath}`,
|
|
559
579
|
"",
|
|
560
|
-
"
|
|
561
|
-
"",
|
|
562
|
-
"For each wave: launch up to `wave_size` subagents in parallel (one per plan entry), wait for all of them to finish, then start the next wave. Repeat until all entries are dispatched.",
|
|
580
|
+
"Apply the same wave logic from the quota file.",
|
|
563
581
|
]
|
|
564
582
|
: [
|
|
565
|
-
"
|
|
583
|
+
"**If auditor MCP tools are available** (preferred):",
|
|
584
|
+
"",
|
|
585
|
+
"The dispatch plan entries are in the `dispatch_plan_entries` field of the tool response that returned this step.",
|
|
586
|
+
"",
|
|
587
|
+
"**Fallback — if auditor MCP tools are not available:** Read this dispatch plan JSON:",
|
|
566
588
|
"",
|
|
567
589
|
` ${params.dispatchPlanPath}`,
|
|
568
590
|
"",
|
|
569
|
-
"Launch one
|
|
591
|
+
"Launch one subagent for each entry in the plan.",
|
|
570
592
|
];
|
|
571
593
|
return [
|
|
572
594
|
"# audit-code dispatch review",
|
|
573
595
|
"",
|
|
574
|
-
...
|
|
596
|
+
...dispatchDataLines,
|
|
575
597
|
"",
|
|
576
|
-
"Pass each
|
|
598
|
+
"Pass each `entry.prompt_path` literally to its subagent; do not load packet prompt files into this orchestrator context.",
|
|
577
599
|
"",
|
|
578
600
|
"Subagent prompt shape:",
|
|
579
601
|
"",
|
|
@@ -584,7 +606,11 @@ function renderDispatchReviewPrompt(params) {
|
|
|
584
606
|
"",
|
|
585
607
|
"Each subagent must submit its packet through the submit command printed in its packet prompt and stop after successful submission.",
|
|
586
608
|
"",
|
|
587
|
-
"After all waves complete
|
|
609
|
+
"**After all waves complete:**",
|
|
610
|
+
"",
|
|
611
|
+
"If auditor MCP tools are available, call `auditor_merge_and_ingest` with `{ run_id: \"" + runId + "\" }`, then call `auditor_continue_audit` and follow the `prompt_content` in the response.",
|
|
612
|
+
"",
|
|
613
|
+
"Fallback — if auditor MCP tools are not available, run exactly:",
|
|
588
614
|
"",
|
|
589
615
|
` ${mergeCommand}`,
|
|
590
616
|
"",
|
|
@@ -624,9 +650,11 @@ function renderPresentReportPrompt(finalReportPath) {
|
|
|
624
650
|
"",
|
|
625
651
|
"The deterministic audit is complete.",
|
|
626
652
|
"",
|
|
627
|
-
"Read
|
|
628
|
-
"",
|
|
653
|
+
"Read the final audit report from the `audit-code://report/current` MCP resource (or from the file at:",
|
|
629
654
|
` ${finalReportPath}`,
|
|
655
|
+
"if a Read tool is available).",
|
|
656
|
+
"",
|
|
657
|
+
"Present the completed audit with work blocks first.",
|
|
630
658
|
"",
|
|
631
659
|
"Do not run the orchestrator again for this completed audit.",
|
|
632
660
|
"",
|
|
@@ -1231,8 +1259,13 @@ async function cmdNextStep(argv) {
|
|
|
1231
1259
|
stepKind: "dispatch_review",
|
|
1232
1260
|
status: "ready",
|
|
1233
1261
|
runId: result.activeReviewRun.run_id,
|
|
1234
|
-
allowedCommands: [
|
|
1235
|
-
|
|
1262
|
+
allowedCommands: [
|
|
1263
|
+
"auditor_merge_and_ingest",
|
|
1264
|
+
"auditor_continue_audit",
|
|
1265
|
+
mergeCommand,
|
|
1266
|
+
continueCommand,
|
|
1267
|
+
],
|
|
1268
|
+
stopCondition: "Dispatch every packet, call auditor_merge_and_ingest once, then call auditor_continue_audit.",
|
|
1236
1269
|
repoRoot: root,
|
|
1237
1270
|
artifactPaths: {
|
|
1238
1271
|
dispatch_plan: dispatch.dispatch_plan_path,
|
package/dist/mcp/server.js
CHANGED
|
@@ -85,6 +85,14 @@ function parseContentLength(headerBlock) {
|
|
|
85
85
|
}
|
|
86
86
|
return contentLength;
|
|
87
87
|
}
|
|
88
|
+
async function readOptionalJson(path) {
|
|
89
|
+
try {
|
|
90
|
+
return JSON.parse(await readFile(path, "utf8"));
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
return undefined;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
88
96
|
async function runWrapperCommand(args, options) {
|
|
89
97
|
return await new Promise((resolvePromise, rejectPromise) => {
|
|
90
98
|
const child = spawn(process.execPath, [
|
|
@@ -266,13 +274,41 @@ function renderPrompt(name, args) {
|
|
|
266
274
|
throw new Error(`Unknown prompt: ${name}`);
|
|
267
275
|
}
|
|
268
276
|
}
|
|
277
|
+
async function runContinueAudit(context, extraArgs = []) {
|
|
278
|
+
const step = await parseCliJson(extraArgs, context);
|
|
279
|
+
if (!step || typeof step !== "object" || Array.isArray(step))
|
|
280
|
+
return step;
|
|
281
|
+
const s = step;
|
|
282
|
+
if (hasValue(s.prompt_path)) {
|
|
283
|
+
try {
|
|
284
|
+
s.prompt_content = await readFile(s.prompt_path, "utf8");
|
|
285
|
+
}
|
|
286
|
+
catch {
|
|
287
|
+
// ignore — prompt_path is a fallback for hosts that can read files
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (s.step_kind === "dispatch_review") {
|
|
291
|
+
const paths = s.artifact_paths;
|
|
292
|
+
if (hasValue(paths?.dispatch_plan)) {
|
|
293
|
+
const plan = await readOptionalJson(paths.dispatch_plan);
|
|
294
|
+
if (plan !== undefined)
|
|
295
|
+
s.dispatch_plan_entries = plan;
|
|
296
|
+
}
|
|
297
|
+
if (hasValue(paths?.dispatch_quota)) {
|
|
298
|
+
const quota = await readOptionalJson(paths.dispatch_quota);
|
|
299
|
+
if (quota !== undefined)
|
|
300
|
+
s.dispatch_quota = quota;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
return s;
|
|
304
|
+
}
|
|
269
305
|
async function handleToolCall(name, params, defaults) {
|
|
270
306
|
const context = getToolContext(params, defaults);
|
|
271
307
|
switch (name) {
|
|
272
308
|
case "start_audit":
|
|
273
|
-
return toolResult(await
|
|
309
|
+
return toolResult(await runContinueAudit(context));
|
|
274
310
|
case "continue_audit":
|
|
275
|
-
return toolResult(await
|
|
311
|
+
return toolResult(await runContinueAudit(context));
|
|
276
312
|
case "get_status":
|
|
277
313
|
return toolResult(await getStatusPayload(context));
|
|
278
314
|
case "explain_task": {
|
|
@@ -304,6 +340,32 @@ async function handleToolCall(name, params, defaults) {
|
|
|
304
340
|
: params?.updatesPath;
|
|
305
341
|
return toolResult(await parseCliJson(["--updates", resolve(updatesPath)], context));
|
|
306
342
|
}
|
|
343
|
+
case "merge_and_ingest": {
|
|
344
|
+
const runId = hasValue(params?.run_id)
|
|
345
|
+
? params.run_id
|
|
346
|
+
: hasValue(params?.runId)
|
|
347
|
+
? params.runId
|
|
348
|
+
: undefined;
|
|
349
|
+
if (!runId)
|
|
350
|
+
throw new Error("merge_and_ingest requires run_id.");
|
|
351
|
+
return toolResult(await parseCliJson(["merge-and-ingest", "--run-id", runId], context, true));
|
|
352
|
+
}
|
|
353
|
+
case "report_capability": {
|
|
354
|
+
const extraArgs = [];
|
|
355
|
+
const canDispatch = params?.can_dispatch_subagents ?? params?.canDispatchSubagents;
|
|
356
|
+
if (canDispatch !== undefined) {
|
|
357
|
+
extraArgs.push("--host-can-dispatch-subagents", String(Boolean(canDispatch)));
|
|
358
|
+
}
|
|
359
|
+
const canRestrict = params?.can_restrict_subagent_tools ?? params?.canRestrictSubagentTools;
|
|
360
|
+
if (canRestrict !== undefined) {
|
|
361
|
+
extraArgs.push("--host-can-restrict-subagent-tools", String(Boolean(canRestrict)));
|
|
362
|
+
}
|
|
363
|
+
const canSelect = params?.can_select_subagent_model ?? params?.canSelectSubagentModel;
|
|
364
|
+
if (canSelect !== undefined) {
|
|
365
|
+
extraArgs.push("--host-can-select-subagent-model", String(Boolean(canSelect)));
|
|
366
|
+
}
|
|
367
|
+
return toolResult(await runContinueAudit(context, ["next-step", ...extraArgs]));
|
|
368
|
+
}
|
|
307
369
|
default:
|
|
308
370
|
throw new Error(`Unknown tool: ${name}`);
|
|
309
371
|
}
|
|
@@ -423,6 +485,52 @@ function toolDefinitions() {
|
|
|
423
485
|
required: ["updates_path"],
|
|
424
486
|
},
|
|
425
487
|
},
|
|
488
|
+
{
|
|
489
|
+
name: "merge_and_ingest",
|
|
490
|
+
description: "Merge completed packet submissions into the artifact bundle after all dispatch subagents finish.",
|
|
491
|
+
inputSchema: {
|
|
492
|
+
type: "object",
|
|
493
|
+
properties: {
|
|
494
|
+
run_id: {
|
|
495
|
+
type: "string",
|
|
496
|
+
description: "Review run ID from the dispatch_review step response.",
|
|
497
|
+
},
|
|
498
|
+
root: { type: "string", description: "Repository root override." },
|
|
499
|
+
artifacts_dir: {
|
|
500
|
+
type: "string",
|
|
501
|
+
description: "Artifacts directory override.",
|
|
502
|
+
},
|
|
503
|
+
},
|
|
504
|
+
required: ["run_id"],
|
|
505
|
+
},
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
name: "report_capability",
|
|
509
|
+
description: "Report host subagent dispatch capability and advance to the next step. Call this instead of running audit-code next-step from the shell during a capability_check step.",
|
|
510
|
+
inputSchema: {
|
|
511
|
+
type: "object",
|
|
512
|
+
properties: {
|
|
513
|
+
can_dispatch_subagents: {
|
|
514
|
+
type: "boolean",
|
|
515
|
+
description: "Whether this host can dispatch subagents (e.g. via the task tool).",
|
|
516
|
+
},
|
|
517
|
+
can_restrict_subagent_tools: {
|
|
518
|
+
type: "boolean",
|
|
519
|
+
description: "Whether this host can restrict tools per subagent.",
|
|
520
|
+
},
|
|
521
|
+
can_select_subagent_model: {
|
|
522
|
+
type: "boolean",
|
|
523
|
+
description: "Whether this host can select a model per subagent.",
|
|
524
|
+
},
|
|
525
|
+
root: { type: "string", description: "Repository root override." },
|
|
526
|
+
artifacts_dir: {
|
|
527
|
+
type: "string",
|
|
528
|
+
description: "Artifacts directory override.",
|
|
529
|
+
},
|
|
530
|
+
},
|
|
531
|
+
required: ["can_dispatch_subagents"],
|
|
532
|
+
},
|
|
533
|
+
},
|
|
426
534
|
];
|
|
427
535
|
}
|
|
428
536
|
export async function runAuditCodeMcpServer(argv) {
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -35,13 +35,6 @@ function writeGeneratedFile(path, content) {
|
|
|
35
35
|
return action;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
function splitFrontmatter(text) {
|
|
39
|
-
const normalized = text.replace(/\r\n/g, '\n');
|
|
40
|
-
const match = normalized.match(/^---\n([\s\S]*?)\n---\n?/u);
|
|
41
|
-
if (!match) return { body: normalized };
|
|
42
|
-
return { body: normalized.slice(match[0].length) };
|
|
43
|
-
}
|
|
44
|
-
|
|
45
38
|
const OPENCODE_AUDIT_EDIT_PERMISSION = {
|
|
46
39
|
'*': 'ask',
|
|
47
40
|
'.audit-code/**': 'allow',
|
|
@@ -183,7 +176,20 @@ function renderOpenCodePermissionConfig() {
|
|
|
183
176
|
};
|
|
184
177
|
}
|
|
185
178
|
|
|
186
|
-
|
|
179
|
+
const OPENCODE_MCP_COMMAND_TEMPLATE = [
|
|
180
|
+
'# audit-code',
|
|
181
|
+
'',
|
|
182
|
+
'Use the auditor MCP tools as the primary interface to the audit workflow.',
|
|
183
|
+
'',
|
|
184
|
+
'1. Call `auditor_start_audit` to initialize and receive the first step.',
|
|
185
|
+
'2. Read the `prompt_content` field in the response and follow the instructions there.',
|
|
186
|
+
'3. When a step completes (not blocked), call `auditor_continue_audit` to advance.',
|
|
187
|
+
'4. Stop when the step instructions say to stop.',
|
|
188
|
+
'',
|
|
189
|
+
'Do not run shell commands. Use only `auditor_*` MCP tools and the `task` tool for subagent dispatch.',
|
|
190
|
+
].join('\n');
|
|
191
|
+
|
|
192
|
+
function mergeOpenCodeGlobalConfig(existing) {
|
|
187
193
|
const parsed = existing ? JSON.parse(existing) : {};
|
|
188
194
|
const auditPermission = renderOpenCodePermissionConfig();
|
|
189
195
|
const existingAuditor = objectValue(objectValue(parsed.agent).auditor);
|
|
@@ -194,7 +200,7 @@ function mergeOpenCodeGlobalConfig(existing, promptBody) {
|
|
|
194
200
|
? parsed.command
|
|
195
201
|
: {}),
|
|
196
202
|
'audit-code': {
|
|
197
|
-
template:
|
|
203
|
+
template: OPENCODE_MCP_COMMAND_TEMPLATE,
|
|
198
204
|
description: 'Autonomous local loop code auditing',
|
|
199
205
|
agent: 'auditor',
|
|
200
206
|
subtask: false,
|
|
@@ -208,10 +214,15 @@ function mergeOpenCodeGlobalConfig(existing, promptBody) {
|
|
|
208
214
|
auditor: {
|
|
209
215
|
...existingAuditor,
|
|
210
216
|
description: 'Read-heavy audit orchestration agent for the /audit-code workflow.',
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
217
|
+
tools: {
|
|
218
|
+
'auditor*': true,
|
|
219
|
+
task: true,
|
|
220
|
+
},
|
|
221
|
+
permission: {
|
|
222
|
+
...mergeOpenCodePermissionConfig(existingAuditor.permission, auditPermission),
|
|
223
|
+
question: 'allow',
|
|
224
|
+
task: 'allow',
|
|
225
|
+
},
|
|
215
226
|
},
|
|
216
227
|
},
|
|
217
228
|
};
|
|
@@ -233,7 +244,6 @@ if (!promptSource || !skillSource) {
|
|
|
233
244
|
process.exit(0);
|
|
234
245
|
}
|
|
235
246
|
|
|
236
|
-
const promptBody = splitFrontmatter(promptSource.toString('utf8')).body;
|
|
237
247
|
const codexOpenAiAgentSource = readOptionalSource(codexOpenAiAgentSourceFile, 'Codex skill UI metadata');
|
|
238
248
|
|
|
239
249
|
const installs = [
|
|
@@ -284,7 +294,7 @@ for (const install of installs) {
|
|
|
284
294
|
const opencodeGlobalConfig = join(homedir(), '.config', 'opencode', 'opencode.json');
|
|
285
295
|
try {
|
|
286
296
|
const action = installMergedJson(opencodeGlobalConfig, (existing) =>
|
|
287
|
-
mergeOpenCodeGlobalConfig(existing
|
|
297
|
+
mergeOpenCodeGlobalConfig(existing),
|
|
288
298
|
);
|
|
289
299
|
console.log(`audit-code: ${action} global OpenCode command in ${opencodeGlobalConfig}`);
|
|
290
300
|
} catch (err) {
|