auditor-lambda 0.2.5 → 0.2.8
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 +35 -7
- package/audit-code-wrapper-lib.mjs +1612 -331
- package/dist/cli.js +397 -38
- package/dist/coverage.d.ts +2 -2
- package/dist/coverage.js +5 -5
- package/dist/extractors/disposition.js +10 -1
- package/dist/extractors/flows.js +7 -1
- package/dist/extractors/pathPatterns.d.ts +3 -0
- package/dist/extractors/pathPatterns.js +15 -0
- package/dist/extractors/risk.js +7 -1
- package/dist/io/artifacts.d.ts +6 -6
- package/dist/io/artifacts.js +14 -17
- package/dist/io/json.d.ts +2 -0
- package/dist/io/json.js +15 -0
- package/dist/io/runArtifacts.d.ts +3 -1
- package/dist/io/runArtifacts.js +20 -5
- package/dist/mcp/server.d.ts +1 -0
- package/dist/mcp/server.js +579 -0
- package/dist/orchestrator/advance.js +9 -2
- package/dist/orchestrator/dependencyMap.js +9 -13
- package/dist/orchestrator/executors.js +7 -2
- package/dist/orchestrator/flowRequeue.d.ts +2 -2
- package/dist/orchestrator/flowRequeue.js +16 -3
- package/dist/orchestrator/internalExecutors.d.ts +2 -1
- package/dist/orchestrator/internalExecutors.js +129 -48
- package/dist/orchestrator/requeue.js +10 -4
- package/dist/orchestrator/requeueCommand.js +15 -2
- package/dist/orchestrator/resultIngestion.d.ts +2 -1
- package/dist/orchestrator/resultIngestion.js +26 -6
- package/dist/orchestrator/runtimeValidation.d.ts +7 -2
- package/dist/orchestrator/runtimeValidation.js +61 -49
- package/dist/orchestrator/runtimeValidationUpdate.js +2 -4
- package/dist/orchestrator/state.js +28 -14
- package/dist/orchestrator/taskBuilder.js +4 -2
- package/dist/orchestrator/trivialAudit.d.ts +4 -0
- package/dist/orchestrator/trivialAudit.js +49 -0
- package/dist/prompts/renderWorkerPrompt.js +6 -2
- package/dist/providers/spawnLoggedCommand.js +17 -0
- package/dist/reporting/mergeFindings.js +3 -11
- package/dist/reporting/rootCause.js +92 -9
- package/dist/reporting/synthesis.d.ts +25 -22
- package/dist/reporting/synthesis.js +92 -59
- package/dist/reporting/workBlocks.d.ts +12 -3
- package/dist/reporting/workBlocks.js +124 -70
- package/dist/supervisor/sessionConfig.js +4 -2
- package/dist/types/flows.d.ts +2 -0
- package/dist/types/runtimeValidation.d.ts +2 -1
- package/dist/types.d.ts +8 -6
- package/dist/validation/auditResults.d.ts +5 -2
- package/dist/validation/auditResults.js +335 -43
- package/docs/agent-integrations.md +38 -29
- package/docs/artifacts.md +18 -51
- package/docs/bootstrap-install.md +60 -30
- package/docs/contract.md +25 -117
- package/docs/field-trial-bug-report.md +237 -0
- package/docs/next-steps.md +59 -44
- package/docs/packaging.md +13 -3
- package/docs/production-launch-bar.md +2 -2
- package/docs/production-readiness.md +9 -5
- package/docs/releasing.md +81 -0
- package/docs/session-config.md +20 -1
- package/docs/usage.md +22 -0
- package/package.json +4 -1
- package/schemas/audit_result.schema.json +4 -5
- package/schemas/audit_task.schema.json +10 -0
- package/schemas/runtime_validation_report.schema.json +1 -1
- package/skills/audit-code/SKILL.md +11 -2
- package/skills/audit-code/audit-code.prompt.md +11 -10
- package/schemas/merged_findings.schema.json +0 -19
- package/schemas/root_cause_clusters.schema.json +0 -28
- package/schemas/synthesis_report.schema.json +0 -61
|
@@ -0,0 +1,579 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { spawn } from "node:child_process";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { loadArtifactBundle } from "../io/artifacts.js";
|
|
6
|
+
import { readOptionalTextFile } from "../io/json.js";
|
|
7
|
+
import { deriveAuditState } from "../orchestrator/state.js";
|
|
8
|
+
import { decideNextStep } from "../orchestrator/nextStep.js";
|
|
9
|
+
import { buildAuditCodeHandoff, } from "../supervisor/operatorHandoff.js";
|
|
10
|
+
import { readSessionConfigFile } from "../supervisor/sessionConfig.js";
|
|
11
|
+
import { resolveFreshSessionProviderName } from "../providers/index.js";
|
|
12
|
+
const moduleDir = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const packageRoot = resolve(moduleDir, "..", "..");
|
|
14
|
+
const wrapperPath = join(packageRoot, "audit-code.mjs");
|
|
15
|
+
const packageJsonPath = join(packageRoot, "package.json");
|
|
16
|
+
const PROTOCOL_VERSION = "2025-06-18";
|
|
17
|
+
function getFlag(argv, name) {
|
|
18
|
+
const index = argv.indexOf(name);
|
|
19
|
+
if (index < 0)
|
|
20
|
+
return undefined;
|
|
21
|
+
return argv[index + 1];
|
|
22
|
+
}
|
|
23
|
+
function hasValue(value) {
|
|
24
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
25
|
+
}
|
|
26
|
+
function parseServerOptions(argv) {
|
|
27
|
+
const root = resolve(getFlag(argv, "--root") ?? ".");
|
|
28
|
+
const artifactsDir = resolve(getFlag(argv, "--artifacts-dir") ?? join(root, ".audit-artifacts"));
|
|
29
|
+
return { root, artifactsDir };
|
|
30
|
+
}
|
|
31
|
+
function parseObject(value) {
|
|
32
|
+
return value && typeof value === "object"
|
|
33
|
+
? value
|
|
34
|
+
: {};
|
|
35
|
+
}
|
|
36
|
+
function getToolContext(params, defaults) {
|
|
37
|
+
const root = hasValue(params?.root)
|
|
38
|
+
? resolve(params.root)
|
|
39
|
+
: defaults.root;
|
|
40
|
+
const artifactsDir = hasValue(params?.artifacts_dir)
|
|
41
|
+
? resolve(params.artifacts_dir)
|
|
42
|
+
: hasValue(params?.artifactsDir)
|
|
43
|
+
? resolve(params.artifactsDir)
|
|
44
|
+
: defaults.artifactsDir;
|
|
45
|
+
return { root, artifactsDir };
|
|
46
|
+
}
|
|
47
|
+
async function packageVersion() {
|
|
48
|
+
const parsed = JSON.parse(await readFile(packageJsonPath, "utf8"));
|
|
49
|
+
return parsed.version ?? "0.0.0";
|
|
50
|
+
}
|
|
51
|
+
function writeMessage(payload) {
|
|
52
|
+
const body = Buffer.from(JSON.stringify(payload), "utf8");
|
|
53
|
+
const header = Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, "utf8");
|
|
54
|
+
process.stdout.write(header);
|
|
55
|
+
process.stdout.write(body);
|
|
56
|
+
}
|
|
57
|
+
function success(id, result) {
|
|
58
|
+
return { jsonrpc: "2.0", id, result };
|
|
59
|
+
}
|
|
60
|
+
function failure(id, code, message, data) {
|
|
61
|
+
return {
|
|
62
|
+
jsonrpc: "2.0",
|
|
63
|
+
id,
|
|
64
|
+
error: {
|
|
65
|
+
code,
|
|
66
|
+
message,
|
|
67
|
+
data,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function runWrapperCommand(args, options) {
|
|
72
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
73
|
+
const child = spawn(process.execPath, [
|
|
74
|
+
wrapperPath,
|
|
75
|
+
...args,
|
|
76
|
+
"--root",
|
|
77
|
+
options.root,
|
|
78
|
+
"--artifacts-dir",
|
|
79
|
+
options.artifactsDir,
|
|
80
|
+
], {
|
|
81
|
+
cwd: options.root,
|
|
82
|
+
env: process.env,
|
|
83
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
84
|
+
});
|
|
85
|
+
let stdout = "";
|
|
86
|
+
let stderr = "";
|
|
87
|
+
child.stdout.on("data", (chunk) => {
|
|
88
|
+
stdout += String(chunk);
|
|
89
|
+
});
|
|
90
|
+
child.stderr.on("data", (chunk) => {
|
|
91
|
+
stderr += String(chunk);
|
|
92
|
+
});
|
|
93
|
+
child.on("error", rejectPromise);
|
|
94
|
+
child.on("exit", (code) => {
|
|
95
|
+
resolvePromise({
|
|
96
|
+
code: code ?? 1,
|
|
97
|
+
stdout,
|
|
98
|
+
stderr,
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
async function parseCliJson(args, options, allowNonZero = false) {
|
|
104
|
+
const result = await runWrapperCommand(args, options);
|
|
105
|
+
const combined = result.stdout.trim() || result.stderr.trim();
|
|
106
|
+
if (!allowNonZero && result.code !== 0) {
|
|
107
|
+
throw new Error(combined || `Command failed with exit code ${result.code}.`);
|
|
108
|
+
}
|
|
109
|
+
if (combined.length === 0) {
|
|
110
|
+
throw new Error("Command completed without JSON output.");
|
|
111
|
+
}
|
|
112
|
+
try {
|
|
113
|
+
return JSON.parse(result.stdout);
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
try {
|
|
117
|
+
return JSON.parse(result.stderr);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
throw new Error(combined);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
async function getStatusPayload(context) {
|
|
125
|
+
const bundle = await loadArtifactBundle(context.artifactsDir);
|
|
126
|
+
const decision = decideNextStep(bundle);
|
|
127
|
+
const auditState = bundle.audit_state ?? deriveAuditState(bundle);
|
|
128
|
+
const rawSessionConfig = await readSessionConfigFile(context.artifactsDir);
|
|
129
|
+
const providerName = rawSessionConfig && typeof rawSessionConfig === "object"
|
|
130
|
+
? resolveFreshSessionProviderName(undefined, rawSessionConfig)
|
|
131
|
+
: null;
|
|
132
|
+
const handoff = buildAuditCodeHandoff({
|
|
133
|
+
root: context.root,
|
|
134
|
+
artifactsDir: context.artifactsDir,
|
|
135
|
+
state: auditState,
|
|
136
|
+
bundle,
|
|
137
|
+
providerName,
|
|
138
|
+
progressSummary: "Current artifact and handoff status.",
|
|
139
|
+
});
|
|
140
|
+
return {
|
|
141
|
+
repo_root: context.root,
|
|
142
|
+
artifacts_dir: context.artifactsDir,
|
|
143
|
+
audit_state: auditState,
|
|
144
|
+
selected_obligation: decision.selected_obligation,
|
|
145
|
+
selected_executor: decision.selected_executor,
|
|
146
|
+
next_likely_step: auditState.status === "complete" ? null : decision.selected_obligation,
|
|
147
|
+
handoff,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
function asTextContent(value) {
|
|
151
|
+
return typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
152
|
+
}
|
|
153
|
+
function toolResult(value) {
|
|
154
|
+
return {
|
|
155
|
+
content: [
|
|
156
|
+
{
|
|
157
|
+
type: "text",
|
|
158
|
+
text: asTextContent(value),
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
structuredContent: value && typeof value === "object" ? value : { value },
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
async function readResource(uri, context) {
|
|
165
|
+
switch (uri) {
|
|
166
|
+
case "audit-code://artifacts/current": {
|
|
167
|
+
const bundle = await loadArtifactBundle(context.artifactsDir);
|
|
168
|
+
return {
|
|
169
|
+
mimeType: "application/json",
|
|
170
|
+
text: JSON.stringify(bundle, null, 2),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
case "audit-code://handoff/current": {
|
|
174
|
+
const status = (await getStatusPayload(context)).handoff;
|
|
175
|
+
return {
|
|
176
|
+
mimeType: "application/json",
|
|
177
|
+
text: JSON.stringify(status, null, 2),
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
case "audit-code://install/guide": {
|
|
181
|
+
const path = join(context.root, ".audit-code", "install", "GETTING-STARTED.md");
|
|
182
|
+
const guide = (await readOptionalTextFile(path)) ??
|
|
183
|
+
"Run `audit-code install` from the repository root to generate the repo-local setup guide.";
|
|
184
|
+
return {
|
|
185
|
+
mimeType: "text/markdown",
|
|
186
|
+
text: guide,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
case "audit-code://report/current": {
|
|
190
|
+
const report = (await readOptionalTextFile(join(context.artifactsDir, "audit-report.md"))) ??
|
|
191
|
+
(await readOptionalTextFile(join(context.root, "audit-report.md"))) ??
|
|
192
|
+
"The audit report has not been rendered yet.";
|
|
193
|
+
return {
|
|
194
|
+
mimeType: "text/markdown",
|
|
195
|
+
text: report,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
default:
|
|
199
|
+
throw new Error(`Unknown resource URI: ${uri}`);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function promptDefinitions() {
|
|
203
|
+
return [
|
|
204
|
+
{
|
|
205
|
+
name: "audit-code",
|
|
206
|
+
description: "Start or continue the autonomous audit loop through the auditor MCP tools.",
|
|
207
|
+
arguments: [],
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
name: "review-task",
|
|
211
|
+
description: "Inspect one audit task with explain_task and the current artifacts before reviewing code.",
|
|
212
|
+
arguments: [
|
|
213
|
+
{
|
|
214
|
+
name: "task_id",
|
|
215
|
+
required: true,
|
|
216
|
+
description: "Audit task id to inspect.",
|
|
217
|
+
},
|
|
218
|
+
],
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
name: "synthesize-report",
|
|
222
|
+
description: "Read the current audit report resource and summarize the highest-signal findings.",
|
|
223
|
+
arguments: [],
|
|
224
|
+
},
|
|
225
|
+
];
|
|
226
|
+
}
|
|
227
|
+
function renderPrompt(name, args) {
|
|
228
|
+
switch (name) {
|
|
229
|
+
case "audit-code":
|
|
230
|
+
return [
|
|
231
|
+
"Use the auditor MCP tools as the primary interface to the backend wrapper.",
|
|
232
|
+
"1. Call `start_audit`.",
|
|
233
|
+
"2. If the audit is blocked, inspect `audit-code://handoff/current` and `audit-code://artifacts/current`.",
|
|
234
|
+
"3. When the user provides additional evidence, call `import_results` or `import_runtime_updates`.",
|
|
235
|
+
"4. Call `continue_audit` until the status is complete or explicitly blocked for operator input.",
|
|
236
|
+
].join("\n");
|
|
237
|
+
case "review-task":
|
|
238
|
+
return [
|
|
239
|
+
`Use \`explain_task\` for task \`${String(args?.task_id ?? "")}\` before you inspect code manually.`,
|
|
240
|
+
"Then read `audit-code://artifacts/current` and use the task scope to review the relevant files.",
|
|
241
|
+
].join("\n");
|
|
242
|
+
case "synthesize-report":
|
|
243
|
+
return [
|
|
244
|
+
"Read `audit-code://report/current`.",
|
|
245
|
+
"Summarize the final audit report as work blocks first, then highlight the most important risks and remediation priorities.",
|
|
246
|
+
].join("\n");
|
|
247
|
+
default:
|
|
248
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
async function handleToolCall(name, params, defaults) {
|
|
252
|
+
const context = getToolContext(params, defaults);
|
|
253
|
+
switch (name) {
|
|
254
|
+
case "start_audit":
|
|
255
|
+
return toolResult(await parseCliJson([], context));
|
|
256
|
+
case "continue_audit":
|
|
257
|
+
return toolResult(await parseCliJson([], context));
|
|
258
|
+
case "get_status":
|
|
259
|
+
return toolResult(await getStatusPayload(context));
|
|
260
|
+
case "explain_task": {
|
|
261
|
+
if (!hasValue(params?.task_id) && !hasValue(params?.taskId)) {
|
|
262
|
+
throw new Error("explain_task requires task_id.");
|
|
263
|
+
}
|
|
264
|
+
const taskId = hasValue(params?.task_id)
|
|
265
|
+
? params.task_id
|
|
266
|
+
: params?.taskId;
|
|
267
|
+
return toolResult(await parseCliJson(["explain-task", taskId], context));
|
|
268
|
+
}
|
|
269
|
+
case "validate_artifacts":
|
|
270
|
+
return toolResult(await parseCliJson(["validate"], context, true));
|
|
271
|
+
case "import_results": {
|
|
272
|
+
if (!hasValue(params?.results_path) && !hasValue(params?.resultsPath)) {
|
|
273
|
+
throw new Error("import_results requires results_path.");
|
|
274
|
+
}
|
|
275
|
+
const resultsPath = hasValue(params?.results_path)
|
|
276
|
+
? params.results_path
|
|
277
|
+
: params?.resultsPath;
|
|
278
|
+
return toolResult(await parseCliJson(["--results", resolve(resultsPath)], context));
|
|
279
|
+
}
|
|
280
|
+
case "import_runtime_updates": {
|
|
281
|
+
if (!hasValue(params?.updates_path) && !hasValue(params?.updatesPath)) {
|
|
282
|
+
throw new Error("import_runtime_updates requires updates_path.");
|
|
283
|
+
}
|
|
284
|
+
const updatesPath = hasValue(params?.updates_path)
|
|
285
|
+
? params.updates_path
|
|
286
|
+
: params?.updatesPath;
|
|
287
|
+
return toolResult(await parseCliJson(["--updates", resolve(updatesPath)], context));
|
|
288
|
+
}
|
|
289
|
+
default:
|
|
290
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
function toolDefinitions() {
|
|
294
|
+
return [
|
|
295
|
+
{
|
|
296
|
+
name: "start_audit",
|
|
297
|
+
description: "Start the audit wrapper and advance until completion or blocked operator handoff.",
|
|
298
|
+
inputSchema: {
|
|
299
|
+
type: "object",
|
|
300
|
+
properties: {
|
|
301
|
+
root: { type: "string", description: "Repository root override." },
|
|
302
|
+
artifacts_dir: {
|
|
303
|
+
type: "string",
|
|
304
|
+
description: "Artifacts directory override.",
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
},
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
name: "get_status",
|
|
311
|
+
description: "Inspect the current artifact bundle and operator handoff without mutating state.",
|
|
312
|
+
inputSchema: {
|
|
313
|
+
type: "object",
|
|
314
|
+
properties: {
|
|
315
|
+
root: { type: "string", description: "Repository root override." },
|
|
316
|
+
artifacts_dir: {
|
|
317
|
+
type: "string",
|
|
318
|
+
description: "Artifacts directory override.",
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
},
|
|
322
|
+
},
|
|
323
|
+
{
|
|
324
|
+
name: "continue_audit",
|
|
325
|
+
description: "Continue the audit wrapper from the current artifacts directory.",
|
|
326
|
+
inputSchema: {
|
|
327
|
+
type: "object",
|
|
328
|
+
properties: {
|
|
329
|
+
root: { type: "string", description: "Repository root override." },
|
|
330
|
+
artifacts_dir: {
|
|
331
|
+
type: "string",
|
|
332
|
+
description: "Artifacts directory override.",
|
|
333
|
+
},
|
|
334
|
+
},
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
{
|
|
338
|
+
name: "explain_task",
|
|
339
|
+
description: "Resolve a task id into coverage scope, matching findings, and pending work.",
|
|
340
|
+
inputSchema: {
|
|
341
|
+
type: "object",
|
|
342
|
+
properties: {
|
|
343
|
+
task_id: {
|
|
344
|
+
type: "string",
|
|
345
|
+
description: "Task id to explain.",
|
|
346
|
+
},
|
|
347
|
+
root: { type: "string", description: "Repository root override." },
|
|
348
|
+
artifacts_dir: {
|
|
349
|
+
type: "string",
|
|
350
|
+
description: "Artifacts directory override.",
|
|
351
|
+
},
|
|
352
|
+
},
|
|
353
|
+
required: ["task_id"],
|
|
354
|
+
},
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
name: "validate_artifacts",
|
|
358
|
+
description: "Validate the current artifact bundle plus provider/session-config readiness.",
|
|
359
|
+
inputSchema: {
|
|
360
|
+
type: "object",
|
|
361
|
+
properties: {
|
|
362
|
+
root: { type: "string", description: "Repository root override." },
|
|
363
|
+
artifacts_dir: {
|
|
364
|
+
type: "string",
|
|
365
|
+
description: "Artifacts directory override.",
|
|
366
|
+
},
|
|
367
|
+
},
|
|
368
|
+
},
|
|
369
|
+
},
|
|
370
|
+
{
|
|
371
|
+
name: "import_results",
|
|
372
|
+
description: "Import structured audit results into the same backend wrapper flow.",
|
|
373
|
+
inputSchema: {
|
|
374
|
+
type: "object",
|
|
375
|
+
properties: {
|
|
376
|
+
results_path: {
|
|
377
|
+
type: "string",
|
|
378
|
+
description: "Path to an AuditResult JSON payload.",
|
|
379
|
+
},
|
|
380
|
+
root: { type: "string", description: "Repository root override." },
|
|
381
|
+
artifacts_dir: {
|
|
382
|
+
type: "string",
|
|
383
|
+
description: "Artifacts directory override.",
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
required: ["results_path"],
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
{
|
|
390
|
+
name: "import_runtime_updates",
|
|
391
|
+
description: "Import runtime validation evidence updates into the backend wrapper flow.",
|
|
392
|
+
inputSchema: {
|
|
393
|
+
type: "object",
|
|
394
|
+
properties: {
|
|
395
|
+
updates_path: {
|
|
396
|
+
type: "string",
|
|
397
|
+
description: "Path to a runtime validation update JSON payload.",
|
|
398
|
+
},
|
|
399
|
+
root: { type: "string", description: "Repository root override." },
|
|
400
|
+
artifacts_dir: {
|
|
401
|
+
type: "string",
|
|
402
|
+
description: "Artifacts directory override.",
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
required: ["updates_path"],
|
|
406
|
+
},
|
|
407
|
+
},
|
|
408
|
+
];
|
|
409
|
+
}
|
|
410
|
+
export async function runAuditCodeMcpServer(argv) {
|
|
411
|
+
const defaults = parseServerOptions(argv);
|
|
412
|
+
const version = await packageVersion();
|
|
413
|
+
let shutdownRequested = false;
|
|
414
|
+
let buffer = Buffer.alloc(0);
|
|
415
|
+
process.stdin.on("data", async (chunk) => {
|
|
416
|
+
buffer = Buffer.concat([buffer, chunk]);
|
|
417
|
+
while (true) {
|
|
418
|
+
const separator = buffer.indexOf("\r\n\r\n");
|
|
419
|
+
if (separator < 0) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const headerBlock = buffer.slice(0, separator).toString("utf8");
|
|
423
|
+
const headers = headerBlock.split("\r\n");
|
|
424
|
+
const contentLengthHeader = headers.find((header) => header.toLowerCase().startsWith("content-length:"));
|
|
425
|
+
if (!contentLengthHeader) {
|
|
426
|
+
buffer = Buffer.alloc(0);
|
|
427
|
+
writeMessage(failure(null, -32700, "Invalid MCP framing: missing Content-Length."));
|
|
428
|
+
return;
|
|
429
|
+
}
|
|
430
|
+
const contentLength = Number(contentLengthHeader.split(":")[1]?.trim());
|
|
431
|
+
const frameLength = separator + 4 + contentLength;
|
|
432
|
+
if (!Number.isFinite(contentLength) || contentLength < 0) {
|
|
433
|
+
buffer = Buffer.alloc(0);
|
|
434
|
+
writeMessage(failure(null, -32700, "Invalid MCP framing: bad Content-Length."));
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (buffer.length < frameLength) {
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
const body = buffer
|
|
441
|
+
.slice(separator + 4, frameLength)
|
|
442
|
+
.toString("utf8");
|
|
443
|
+
buffer = buffer.slice(frameLength);
|
|
444
|
+
let request;
|
|
445
|
+
try {
|
|
446
|
+
request = JSON.parse(body);
|
|
447
|
+
}
|
|
448
|
+
catch (error) {
|
|
449
|
+
writeMessage(failure(null, -32700, "Invalid JSON-RPC payload.", error instanceof Error ? error.message : String(error)));
|
|
450
|
+
continue;
|
|
451
|
+
}
|
|
452
|
+
if (!request.method) {
|
|
453
|
+
writeMessage(failure(request.id ?? null, -32600, "Missing method."));
|
|
454
|
+
continue;
|
|
455
|
+
}
|
|
456
|
+
try {
|
|
457
|
+
switch (request.method) {
|
|
458
|
+
case "initialize":
|
|
459
|
+
writeMessage(success(request.id ?? null, {
|
|
460
|
+
protocolVersion: PROTOCOL_VERSION,
|
|
461
|
+
serverInfo: {
|
|
462
|
+
name: "audit-code",
|
|
463
|
+
version,
|
|
464
|
+
},
|
|
465
|
+
instructions: "Use the audit-code MCP tools as the primary interface to the backend wrapper. Prefer start_audit, get_status, continue_audit, and the audit-code resources over ad hoc shell commands.",
|
|
466
|
+
capabilities: {
|
|
467
|
+
tools: { listChanged: false },
|
|
468
|
+
resources: { subscribe: false, listChanged: false },
|
|
469
|
+
prompts: { listChanged: false },
|
|
470
|
+
},
|
|
471
|
+
}));
|
|
472
|
+
break;
|
|
473
|
+
case "notifications/initialized":
|
|
474
|
+
break;
|
|
475
|
+
case "ping":
|
|
476
|
+
if (request.id !== undefined) {
|
|
477
|
+
writeMessage(success(request.id, {}));
|
|
478
|
+
}
|
|
479
|
+
break;
|
|
480
|
+
case "tools/list":
|
|
481
|
+
writeMessage(success(request.id ?? null, { tools: toolDefinitions() }));
|
|
482
|
+
break;
|
|
483
|
+
case "tools/call": {
|
|
484
|
+
const params = parseObject(request.params);
|
|
485
|
+
const toolName = params.name;
|
|
486
|
+
if (!hasValue(toolName)) {
|
|
487
|
+
throw new Error("tools/call requires a tool name.");
|
|
488
|
+
}
|
|
489
|
+
writeMessage(success(request.id ?? null, await handleToolCall(toolName, parseObject(params.arguments), defaults)));
|
|
490
|
+
break;
|
|
491
|
+
}
|
|
492
|
+
case "resources/list":
|
|
493
|
+
writeMessage(success(request.id ?? null, {
|
|
494
|
+
resources: [
|
|
495
|
+
{
|
|
496
|
+
uri: "audit-code://artifacts/current",
|
|
497
|
+
name: "current_artifacts",
|
|
498
|
+
description: "Current artifact bundle as JSON.",
|
|
499
|
+
mimeType: "application/json",
|
|
500
|
+
},
|
|
501
|
+
{
|
|
502
|
+
uri: "audit-code://handoff/current",
|
|
503
|
+
name: "operator_handoff",
|
|
504
|
+
description: "Current operator handoff payload as JSON.",
|
|
505
|
+
mimeType: "application/json",
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
uri: "audit-code://install/guide",
|
|
509
|
+
name: "install_guide",
|
|
510
|
+
description: "Repo-local install guide for supported IDE hosts.",
|
|
511
|
+
mimeType: "text/markdown",
|
|
512
|
+
},
|
|
513
|
+
{
|
|
514
|
+
uri: "audit-code://report/current",
|
|
515
|
+
name: "audit_report",
|
|
516
|
+
description: "Current deterministic audit report if available.",
|
|
517
|
+
mimeType: "text/markdown",
|
|
518
|
+
},
|
|
519
|
+
],
|
|
520
|
+
}));
|
|
521
|
+
break;
|
|
522
|
+
case "resources/read": {
|
|
523
|
+
const params = parseObject(request.params);
|
|
524
|
+
if (!hasValue(params.uri)) {
|
|
525
|
+
throw new Error("resources/read requires uri.");
|
|
526
|
+
}
|
|
527
|
+
const resource = await readResource(params.uri, defaults);
|
|
528
|
+
writeMessage(success(request.id ?? null, {
|
|
529
|
+
contents: [
|
|
530
|
+
{
|
|
531
|
+
uri: params.uri,
|
|
532
|
+
mimeType: resource.mimeType,
|
|
533
|
+
text: resource.text,
|
|
534
|
+
},
|
|
535
|
+
],
|
|
536
|
+
}));
|
|
537
|
+
break;
|
|
538
|
+
}
|
|
539
|
+
case "prompts/list":
|
|
540
|
+
writeMessage(success(request.id ?? null, {
|
|
541
|
+
prompts: promptDefinitions(),
|
|
542
|
+
}));
|
|
543
|
+
break;
|
|
544
|
+
case "prompts/get": {
|
|
545
|
+
const params = parseObject(request.params);
|
|
546
|
+
if (!hasValue(params.name)) {
|
|
547
|
+
throw new Error("prompts/get requires name.");
|
|
548
|
+
}
|
|
549
|
+
writeMessage(success(request.id ?? null, {
|
|
550
|
+
description: promptDefinitions().find((prompt) => prompt.name === params.name)?.description,
|
|
551
|
+
messages: [
|
|
552
|
+
{
|
|
553
|
+
role: "user",
|
|
554
|
+
content: {
|
|
555
|
+
type: "text",
|
|
556
|
+
text: renderPrompt(params.name, parseObject(params.arguments)),
|
|
557
|
+
},
|
|
558
|
+
},
|
|
559
|
+
],
|
|
560
|
+
}));
|
|
561
|
+
break;
|
|
562
|
+
}
|
|
563
|
+
case "shutdown":
|
|
564
|
+
shutdownRequested = true;
|
|
565
|
+
writeMessage(success(request.id ?? null, {}));
|
|
566
|
+
break;
|
|
567
|
+
case "exit":
|
|
568
|
+
process.exit(shutdownRequested ? 0 : 1);
|
|
569
|
+
break;
|
|
570
|
+
default:
|
|
571
|
+
writeMessage(failure(request.id ?? null, -32601, `Unknown method: ${request.method}`));
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
writeMessage(failure(request.id ?? null, -32000, error instanceof Error ? error.message : String(error)));
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { decideNextStep } from "./nextStep.js";
|
|
2
2
|
import { deriveAuditState } from "./state.js";
|
|
3
3
|
import { computeArtifactMetadata } from "./artifactMetadata.js";
|
|
4
|
-
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
4
|
+
import { runIntakeExecutor, runStructureExecutor, runPlanningExecutor, runResultIngestionExecutor, runRuntimeValidationExecutor, runRuntimeValidationUpdateExecutor, runSynthesisExecutor, runExternalAnalyzerImportExecutor, } from "./internalExecutors.js";
|
|
5
5
|
import { runAutoFixExecutor } from "./autoFixExecutor.js";
|
|
6
6
|
import { runSyntaxResolutionExecutor } from "./syntaxResolutionExecutor.js";
|
|
7
7
|
export async function advanceAudit(bundle, options = {}) {
|
|
@@ -37,11 +37,18 @@ export async function advanceAudit(bundle, options = {}) {
|
|
|
37
37
|
run = runStructureExecutor(bundle);
|
|
38
38
|
break;
|
|
39
39
|
case "planning_executor":
|
|
40
|
-
|
|
40
|
+
if (!options.root)
|
|
41
|
+
throw new Error("advanceAudit planning_executor requires root");
|
|
42
|
+
run = await runPlanningExecutor(bundle, options.root, options.lineIndex ?? {});
|
|
41
43
|
break;
|
|
42
44
|
case "result_ingestion_executor":
|
|
43
45
|
run = runResultIngestionExecutor(bundle, options.auditResults ?? bundle.audit_results ?? []);
|
|
44
46
|
break;
|
|
47
|
+
case "runtime_validation_executor":
|
|
48
|
+
if (!options.root)
|
|
49
|
+
throw new Error("advanceAudit runtime_validation_executor requires root");
|
|
50
|
+
run = await runRuntimeValidationExecutor(bundle, options.root);
|
|
51
|
+
break;
|
|
45
52
|
case "synthesis_executor":
|
|
46
53
|
run = runSynthesisExecutor(bundle, options.auditResults);
|
|
47
54
|
break;
|
|
@@ -12,7 +12,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
12
12
|
"requeue_tasks.json",
|
|
13
13
|
"runtime_validation_tasks.json",
|
|
14
14
|
"runtime_validation_report.json",
|
|
15
|
-
"
|
|
15
|
+
"audit-report.md",
|
|
16
16
|
],
|
|
17
17
|
"file_disposition.json": [
|
|
18
18
|
"unit_manifest.json",
|
|
@@ -26,7 +26,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
26
26
|
"requeue_tasks.json",
|
|
27
27
|
"runtime_validation_tasks.json",
|
|
28
28
|
"runtime_validation_report.json",
|
|
29
|
-
"
|
|
29
|
+
"audit-report.md",
|
|
30
30
|
],
|
|
31
31
|
"unit_manifest.json": [
|
|
32
32
|
"risk_register.json",
|
|
@@ -34,13 +34,13 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
34
34
|
"audit_tasks.json",
|
|
35
35
|
"runtime_validation_tasks.json",
|
|
36
36
|
"requeue_tasks.json",
|
|
37
|
-
"
|
|
37
|
+
"audit-report.md",
|
|
38
38
|
],
|
|
39
39
|
"surface_manifest.json": [
|
|
40
40
|
"critical_flows.json",
|
|
41
41
|
"risk_register.json",
|
|
42
42
|
"runtime_validation_tasks.json",
|
|
43
|
-
"
|
|
43
|
+
"audit-report.md",
|
|
44
44
|
],
|
|
45
45
|
"critical_flows.json": [
|
|
46
46
|
"flow_coverage.json",
|
|
@@ -49,7 +49,7 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
49
49
|
"requeue_tasks.json",
|
|
50
50
|
"runtime_validation_tasks.json",
|
|
51
51
|
"runtime_validation_report.json",
|
|
52
|
-
"
|
|
52
|
+
"audit-report.md",
|
|
53
53
|
],
|
|
54
54
|
"audit_results.jsonl": [
|
|
55
55
|
"coverage_matrix.json",
|
|
@@ -57,26 +57,22 @@ export const ARTIFACT_DEPENDENCY_MAP = {
|
|
|
57
57
|
"requeue_tasks.json",
|
|
58
58
|
"runtime_validation_tasks.json",
|
|
59
59
|
"runtime_validation_report.json",
|
|
60
|
-
"
|
|
61
|
-
"root_cause_clusters.json",
|
|
62
|
-
"synthesis_report.json",
|
|
60
|
+
"audit-report.md",
|
|
63
61
|
],
|
|
64
62
|
"coverage_matrix.json": [
|
|
65
63
|
"flow_coverage.json",
|
|
66
64
|
"requeue_tasks.json",
|
|
67
65
|
"runtime_validation_tasks.json",
|
|
68
66
|
"runtime_validation_report.json",
|
|
69
|
-
"
|
|
67
|
+
"audit-report.md",
|
|
70
68
|
],
|
|
71
69
|
"flow_coverage.json": [
|
|
72
70
|
"requeue_tasks.json",
|
|
73
71
|
"runtime_validation_tasks.json",
|
|
74
72
|
"runtime_validation_report.json",
|
|
75
|
-
"
|
|
73
|
+
"audit-report.md",
|
|
76
74
|
],
|
|
77
75
|
"runtime_validation_report.json": [
|
|
78
|
-
"
|
|
79
|
-
"root_cause_clusters.json",
|
|
80
|
-
"synthesis_report.json",
|
|
76
|
+
"audit-report.md",
|
|
81
77
|
],
|
|
82
78
|
};
|