auditor-lambda 0.3.14 → 0.3.16
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 +3 -2
- package/audit-code-wrapper-lib.mjs +51 -105
- package/docs/operator-guide.md +4 -3
- package/package.json +1 -1
- package/scripts/postinstall.mjs +49 -0
package/README.md
CHANGED
|
@@ -30,7 +30,8 @@ npm install -g auditor-lambda
|
|
|
30
30
|
|
|
31
31
|
That makes `audit-code` available on `PATH`. During package install, the package
|
|
32
32
|
also writes user-level command/skill assets for hosts we can seed safely, including
|
|
33
|
-
the Claude command file
|
|
33
|
+
the Claude command file, the global Codex skill bundle, and the global OpenCode
|
|
34
|
+
slash command entry in `~/.config/opencode/opencode.json`.
|
|
34
35
|
|
|
35
36
|
After that, invoke `/audit-code` in a supported host. The prompt self-bootstraps
|
|
36
37
|
the current repository by running:
|
|
@@ -53,7 +54,7 @@ That bootstraps repo-local `/audit-code` surfaces for the hosts we can automate
|
|
|
53
54
|
|
|
54
55
|
- Codex `AGENTS.md` fallback guidance for the global skill surface
|
|
55
56
|
- Claude Desktop local MCP bundle artifacts and project template guidance
|
|
56
|
-
- OpenCode
|
|
57
|
+
- OpenCode `opencode.json` with the `/audit-code` slash command and auditor MCP server
|
|
57
58
|
- VS Code prompt, custom agent, Copilot instructions, and `.vscode/mcp.json`
|
|
58
59
|
- Antigravity planning-mode guidance plus the shared repo-local MCP launcher
|
|
59
60
|
|
|
@@ -533,10 +533,18 @@ function renderCodexAutomationRecipe() {
|
|
|
533
533
|
].join('\n');
|
|
534
534
|
}
|
|
535
535
|
|
|
536
|
-
function renderOpenCodeProjectConfig(root) {
|
|
536
|
+
function renderOpenCodeProjectConfig(root, promptBody) {
|
|
537
537
|
const launcher = replaceBackslashes(toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME)));
|
|
538
538
|
return {
|
|
539
539
|
$schema: 'https://opencode.ai/config.json',
|
|
540
|
+
command: {
|
|
541
|
+
'audit-code': {
|
|
542
|
+
template: promptBody.trimStart(),
|
|
543
|
+
description: 'Autonomous local loop code auditing',
|
|
544
|
+
agent: 'auditor',
|
|
545
|
+
subtask: false,
|
|
546
|
+
},
|
|
547
|
+
},
|
|
540
548
|
mcp: {
|
|
541
549
|
auditor: {
|
|
542
550
|
type: 'local',
|
|
@@ -599,11 +607,15 @@ function objectValue(value) {
|
|
|
599
607
|
: {};
|
|
600
608
|
}
|
|
601
609
|
|
|
602
|
-
function buildMergedOpenCodeProjectConfig(existing, root) {
|
|
603
|
-
const generated = renderOpenCodeProjectConfig(root);
|
|
610
|
+
function buildMergedOpenCodeProjectConfig(existing, root, promptBody) {
|
|
611
|
+
const generated = renderOpenCodeProjectConfig(root, promptBody);
|
|
604
612
|
return {
|
|
605
613
|
...existing,
|
|
606
614
|
$schema: existing.$schema ?? generated.$schema,
|
|
615
|
+
command: {
|
|
616
|
+
...objectValue(existing.command),
|
|
617
|
+
'audit-code': generated.command['audit-code'],
|
|
618
|
+
},
|
|
607
619
|
mcp: {
|
|
608
620
|
...objectValue(existing.mcp),
|
|
609
621
|
auditor: generated.mcp.auditor,
|
|
@@ -1084,17 +1096,15 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1084
1096
|
support_level: 'supported',
|
|
1085
1097
|
setup_kind: 'command+agent+mcp',
|
|
1086
1098
|
summary:
|
|
1087
|
-
'Use the generated
|
|
1088
|
-
primary_path_key: '
|
|
1099
|
+
'Use the generated `opencode.json` so the `/audit-code` slash command and the local auditor MCP server are both available.',
|
|
1100
|
+
primary_path_key: 'opencodeConfigPath',
|
|
1089
1101
|
supporting_path_keys: [
|
|
1090
|
-
'opencodeConfigPath',
|
|
1091
|
-
'opencodeSkillPath',
|
|
1092
1102
|
'agentsInstructionsPath',
|
|
1093
1103
|
'mcpLauncherPath',
|
|
1094
1104
|
],
|
|
1095
1105
|
steps: [
|
|
1096
1106
|
'Open this repository in OpenCode.',
|
|
1097
|
-
'Let OpenCode load the generated `opencode.json`
|
|
1107
|
+
'Let OpenCode load the generated `opencode.json` — it registers the `/audit-code` slash command and the auditor MCP server.',
|
|
1098
1108
|
'Invoke `/audit-code` and keep the audit loop on the auditor MCP tools.',
|
|
1099
1109
|
],
|
|
1100
1110
|
profile: {
|
|
@@ -1792,63 +1802,28 @@ async function verifyInstalledBootstrap(argv) {
|
|
|
1792
1802
|
break;
|
|
1793
1803
|
}
|
|
1794
1804
|
case 'opencode':
|
|
1795
|
-
await collectVerifyCheck(checks, 'opencode_command', async () => {
|
|
1796
|
-
const content = await readFile(assetPaths.opencodeCommandPath, 'utf8');
|
|
1797
|
-
if (!content.includes('agent: auditor')) {
|
|
1798
|
-
throw new Error(`OpenCode command file is missing the auditor agent frontmatter: ${assetPaths.opencodeCommandPath}`);
|
|
1799
|
-
}
|
|
1800
|
-
const { body: commandBody } = splitFrontmatter(content);
|
|
1801
|
-
const { body: sourceBody } = splitFrontmatter(await readFile(promptAssetPath, 'utf8'));
|
|
1802
|
-
if (commandBody !== sourceBody.trimStart()) {
|
|
1803
|
-
throw new Error(
|
|
1804
|
-
`OpenCode command prompt body is out of sync with the source prompt. Run "audit-code install --host opencode" or "audit-code install".`,
|
|
1805
|
-
);
|
|
1806
|
-
}
|
|
1807
|
-
return {
|
|
1808
|
-
summary: 'OpenCode command file is present and uses the source prompt body.',
|
|
1809
|
-
path: assetPaths.opencodeCommandPath,
|
|
1810
|
-
};
|
|
1811
|
-
});
|
|
1812
|
-
await collectVerifyCheck(checks, 'opencode_skill', async () => {
|
|
1813
|
-
const content = (await readFile(assetPaths.opencodeSkillPath, 'utf8')).replace(/\r\n/g, '\n');
|
|
1814
|
-
const sourceSkill = (await readFile(skillAssetPath, 'utf8')).replace(/\r\n/g, '\n');
|
|
1815
|
-
if (content !== sourceSkill) {
|
|
1816
|
-
throw new Error(
|
|
1817
|
-
`OpenCode skill is out of sync with the source skill. Run "audit-code install --host opencode" or "audit-code install".`,
|
|
1818
|
-
);
|
|
1819
|
-
}
|
|
1820
|
-
return {
|
|
1821
|
-
summary: 'OpenCode skill is present and matches the source skill.',
|
|
1822
|
-
path: assetPaths.opencodeSkillPath,
|
|
1823
|
-
};
|
|
1824
|
-
});
|
|
1825
|
-
await collectVerifyCheck(checks, 'opencode_prompt', async () => {
|
|
1826
|
-
const content = await readFile(assetPaths.opencodePromptPath, 'utf8');
|
|
1827
|
-
const sourcePrompt = await readFile(promptAssetPath, 'utf8');
|
|
1828
|
-
if (content !== sourcePrompt) {
|
|
1829
|
-
throw new Error(
|
|
1830
|
-
`OpenCode prompt is out of sync with the source prompt. Run "audit-code install --host opencode" or "audit-code install".`,
|
|
1831
|
-
);
|
|
1832
|
-
}
|
|
1833
|
-
return {
|
|
1834
|
-
summary: 'OpenCode prompt is present and matches the source prompt.',
|
|
1835
|
-
path: assetPaths.opencodePromptPath,
|
|
1836
|
-
};
|
|
1837
|
-
});
|
|
1838
1805
|
await collectVerifyCheck(checks, 'opencode_config', async () => {
|
|
1839
1806
|
const config = await readJson(assetPaths.opencodeConfigPath, 'OpenCode project config');
|
|
1840
|
-
const
|
|
1841
|
-
if (!Array.isArray(
|
|
1807
|
+
const mcpCommand = config?.mcp?.auditor?.command;
|
|
1808
|
+
if (!Array.isArray(mcpCommand) || mcpCommand[0] !== 'node') {
|
|
1842
1809
|
throw new Error('OpenCode config must set mcp.auditor.command as a Node command array.');
|
|
1843
1810
|
}
|
|
1844
|
-
if (
|
|
1845
|
-
throw new Error(`OpenCode config must point at .audit-code/install/${MCP_LAUNCHER_FILENAME}, got ${
|
|
1811
|
+
if (mcpCommand[1] !== '.audit-code/install/run-mcp-server.mjs') {
|
|
1812
|
+
throw new Error(`OpenCode config must point at .audit-code/install/${MCP_LAUNCHER_FILENAME}, got ${mcpCommand[1] ?? 'missing'}.`);
|
|
1846
1813
|
}
|
|
1847
1814
|
if (config?.mcp?.auditor?.type !== 'local') {
|
|
1848
1815
|
throw new Error(`OpenCode config must set mcp.auditor.type to "local", got ${config?.mcp?.auditor?.type ?? 'missing'}.`);
|
|
1849
1816
|
}
|
|
1817
|
+
const commandConfig = config?.command?.['audit-code'];
|
|
1818
|
+
if (!commandConfig?.template) {
|
|
1819
|
+
throw new Error('OpenCode config is missing command["audit-code"].template — the /audit-code slash command will not surface. Run "audit-code install".');
|
|
1820
|
+
}
|
|
1821
|
+
const { body: sourceBody } = splitFrontmatter(await readFile(promptAssetPath, 'utf8'));
|
|
1822
|
+
if (commandConfig.template !== sourceBody.trimStart()) {
|
|
1823
|
+
throw new Error('OpenCode config command["audit-code"].template is out of sync with the source prompt. Run "audit-code install".');
|
|
1824
|
+
}
|
|
1850
1825
|
return {
|
|
1851
|
-
summary: 'OpenCode project config
|
|
1826
|
+
summary: 'OpenCode project config has MCP server and /audit-code slash command.',
|
|
1852
1827
|
path: assetPaths.opencodeConfigPath,
|
|
1853
1828
|
};
|
|
1854
1829
|
});
|
|
@@ -2022,20 +1997,12 @@ async function detectBootstrapRefreshReason(root, host) {
|
|
|
2022
1997
|
break;
|
|
2023
1998
|
}
|
|
2024
1999
|
case 'opencode': {
|
|
2025
|
-
const
|
|
2026
|
-
if (
|
|
2027
|
-
return 'stale_host_asset:opencode:
|
|
2028
|
-
}
|
|
2029
|
-
const opencodePrompt = await readTextIfExists(assetPaths.opencodePromptPath);
|
|
2030
|
-
if (opencodePrompt !== sourcePrompt) {
|
|
2031
|
-
return 'stale_host_asset:opencode:prompt';
|
|
2000
|
+
const opencodeConfig = await readJson(assetPaths.opencodeConfigPath, 'OpenCode config').catch(() => null);
|
|
2001
|
+
if (opencodeConfig?.command?.['audit-code']?.template !== sourcePromptBody.trimStart()) {
|
|
2002
|
+
return 'stale_host_asset:opencode:config_command';
|
|
2032
2003
|
}
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
return 'missing_host_asset:opencode:command';
|
|
2036
|
-
}
|
|
2037
|
-
if (splitFrontmatter(opencodeCommand).body !== sourcePromptBody.trimStart()) {
|
|
2038
|
-
return 'stale_host_asset:opencode:command';
|
|
2004
|
+
if (await fileExists(join(root, '.opencode', 'commands', 'audit-code.md'))) {
|
|
2005
|
+
return 'stale_host_asset:opencode:legacy_command_file';
|
|
2039
2006
|
}
|
|
2040
2007
|
break;
|
|
2041
2008
|
}
|
|
@@ -2164,18 +2131,9 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2164
2131
|
claudeDesktopMcpbPath: profile.writeClaudeDesktop
|
|
2165
2132
|
? join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.mcpb')
|
|
2166
2133
|
: null,
|
|
2167
|
-
opencodeCommandPath: profile.writeOpenCode
|
|
2168
|
-
? join(root, '.opencode', 'commands', 'audit-code.md')
|
|
2169
|
-
: null,
|
|
2170
2134
|
opencodeConfigPath: profile.writeOpenCode
|
|
2171
2135
|
? join(root, 'opencode.json')
|
|
2172
2136
|
: null,
|
|
2173
|
-
opencodeSkillPath: profile.writeOpenCode
|
|
2174
|
-
? join(root, '.opencode', 'skills', 'audit-code', 'SKILL.md')
|
|
2175
|
-
: null,
|
|
2176
|
-
opencodePromptPath: profile.writeOpenCode
|
|
2177
|
-
? join(root, '.opencode', 'skills', 'audit-code', 'audit-code.prompt.md')
|
|
2178
|
-
: null,
|
|
2179
2137
|
vscodePromptPath: profile.writeVSCode
|
|
2180
2138
|
? join(root, '.github', 'prompts', 'audit-code.prompt.md')
|
|
2181
2139
|
: null,
|
|
@@ -2285,36 +2243,24 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2285
2243
|
}
|
|
2286
2244
|
|
|
2287
2245
|
if (profile.writeOpenCode) {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
)
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
results.push(
|
|
2302
|
-
await writeGeneratedMarkdown(
|
|
2303
|
-
assetPaths.opencodeSkillPath,
|
|
2304
|
-
skillSource,
|
|
2305
|
-
),
|
|
2306
|
-
);
|
|
2307
|
-
results.push(
|
|
2308
|
-
await writeGeneratedMarkdown(
|
|
2309
|
-
assetPaths.opencodePromptPath,
|
|
2310
|
-
promptSource,
|
|
2311
|
-
),
|
|
2312
|
-
);
|
|
2246
|
+
// Remove legacy command/skill/prompt files unconditionally — these paths are exclusively
|
|
2247
|
+
// owned by the auditor-lambda installer and keeping any version of them causes OpenCode to
|
|
2248
|
+
// load the wrong slash command regardless of prompt content.
|
|
2249
|
+
for (const legacyPath of [
|
|
2250
|
+
join(root, '.opencode', 'commands', 'audit-code.md'),
|
|
2251
|
+
join(root, '.opencode', 'skills', 'audit-code', 'SKILL.md'),
|
|
2252
|
+
join(root, '.opencode', 'skills', 'audit-code', 'audit-code.prompt.md'),
|
|
2253
|
+
]) {
|
|
2254
|
+
if (await fileExists(legacyPath)) {
|
|
2255
|
+
await unlink(legacyPath);
|
|
2256
|
+
results.push({ path: legacyPath, mode: 'removed' });
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2313
2259
|
results.push(
|
|
2314
2260
|
await writeMergedGeneratedJson(
|
|
2315
2261
|
assetPaths.opencodeConfigPath,
|
|
2316
2262
|
'OpenCode project config',
|
|
2317
|
-
(existing) => buildMergedOpenCodeProjectConfig(existing, root),
|
|
2263
|
+
(existing) => buildMergedOpenCodeProjectConfig(existing, root, promptBody),
|
|
2318
2264
|
),
|
|
2319
2265
|
);
|
|
2320
2266
|
}
|
|
@@ -2415,7 +2361,7 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2415
2361
|
files: results,
|
|
2416
2362
|
slash_command_surfaces: {
|
|
2417
2363
|
vscode_prompt: assetPaths.vscodePromptPath,
|
|
2418
|
-
|
|
2364
|
+
opencode_config: assetPaths.opencodeConfigPath,
|
|
2419
2365
|
},
|
|
2420
2366
|
instruction_surfaces: {
|
|
2421
2367
|
agents: assetPaths.agentsInstructionsPath,
|
package/docs/operator-guide.md
CHANGED
|
@@ -43,7 +43,7 @@ Host-specific files may include:
|
|
|
43
43
|
|
|
44
44
|
- Codex: managed `AGENTS.md` fallback guidance
|
|
45
45
|
- Claude Desktop: project template, remote MCP connector, local MCP bundle
|
|
46
|
-
- OpenCode:
|
|
46
|
+
- OpenCode: `opencode.json` with `/audit-code` slash command and auditor MCP server
|
|
47
47
|
- VS Code/Copilot: prompt, custom agent, instructions, and `.vscode/mcp.json`
|
|
48
48
|
- Antigravity: planning-mode and MCP-oriented guidance
|
|
49
49
|
|
|
@@ -62,8 +62,9 @@ repo-local `AGENTS.md` fallback guidance.
|
|
|
62
62
|
Claude Desktop is treated as an MCP-first host. Use the generated project
|
|
63
63
|
template and local bundle artifacts when installing the integration.
|
|
64
64
|
|
|
65
|
-
OpenCode
|
|
66
|
-
|
|
65
|
+
OpenCode uses `opencode.json` (generated by `audit-code ensure` or `audit-code
|
|
66
|
+
install`) which registers the `/audit-code` slash command and the auditor MCP
|
|
67
|
+
server together. VS Code uses repo-local prompt and MCP configuration files.
|
|
67
68
|
|
|
68
69
|
Antigravity should be treated as a workflow-and-artifacts host until it has a
|
|
69
70
|
stable project-local config surface. Use generated planning-mode guidance,
|
package/package.json
CHANGED
package/scripts/postinstall.mjs
CHANGED
|
@@ -25,6 +25,40 @@ function writeGeneratedFile(path, content) {
|
|
|
25
25
|
return action;
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
function splitFrontmatter(text) {
|
|
29
|
+
const normalized = text.replace(/\r\n/g, '\n');
|
|
30
|
+
const match = normalized.match(/^---\n([\s\S]*?)\n---\n?/u);
|
|
31
|
+
if (!match) return { body: normalized };
|
|
32
|
+
return { body: normalized.slice(match[0].length) };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function mergeOpenCodeGlobalConfig(existing, promptBody) {
|
|
36
|
+
const parsed = existing ? JSON.parse(existing) : {};
|
|
37
|
+
return {
|
|
38
|
+
...parsed,
|
|
39
|
+
command: {
|
|
40
|
+
...(parsed.command && typeof parsed.command === 'object' && !Array.isArray(parsed.command)
|
|
41
|
+
? parsed.command
|
|
42
|
+
: {}),
|
|
43
|
+
'audit-code': {
|
|
44
|
+
template: promptBody.trimStart(),
|
|
45
|
+
description: 'Autonomous local loop code auditing',
|
|
46
|
+
agent: 'auditor',
|
|
47
|
+
subtask: false,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function installMergedJson(path, buildMerged) {
|
|
54
|
+
const existing = existsSync(path) ? readFileSync(path, 'utf8') : null;
|
|
55
|
+
const merged = buildMerged(existing);
|
|
56
|
+
const action = existing ? 'updated' : 'installed';
|
|
57
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
58
|
+
writeFileSync(path, JSON.stringify(merged, null, 2) + '\n', 'utf8');
|
|
59
|
+
return action;
|
|
60
|
+
}
|
|
61
|
+
|
|
28
62
|
const promptSource = readRequiredSource(promptSourceFile, 'prompt');
|
|
29
63
|
const skillSource = readRequiredSource(skillSourceFile, 'skill');
|
|
30
64
|
|
|
@@ -32,6 +66,8 @@ if (!promptSource || !skillSource) {
|
|
|
32
66
|
process.exit(0);
|
|
33
67
|
}
|
|
34
68
|
|
|
69
|
+
const promptBody = splitFrontmatter(promptSource.toString('utf8')).body;
|
|
70
|
+
|
|
35
71
|
const installs = [
|
|
36
72
|
{
|
|
37
73
|
label: 'Claude command',
|
|
@@ -62,3 +98,16 @@ for (const install of installs) {
|
|
|
62
98
|
console.warn(` ${install.path}`);
|
|
63
99
|
}
|
|
64
100
|
}
|
|
101
|
+
|
|
102
|
+
// Install OpenCode global command via merged config
|
|
103
|
+
const opencodeGlobalConfig = join(homedir(), '.config', 'opencode', 'opencode.json');
|
|
104
|
+
try {
|
|
105
|
+
const action = installMergedJson(opencodeGlobalConfig, (existing) =>
|
|
106
|
+
mergeOpenCodeGlobalConfig(existing, promptBody),
|
|
107
|
+
);
|
|
108
|
+
console.log(`audit-code: ${action} global OpenCode command in ${opencodeGlobalConfig}`);
|
|
109
|
+
} catch (err) {
|
|
110
|
+
console.warn(`audit-code: could not install global OpenCode command (${err.message})`);
|
|
111
|
+
console.warn(` To install manually, add "command": { "audit-code": { "template": "...", "agent": "auditor" } } to:`);
|
|
112
|
+
console.warn(` ${opencodeGlobalConfig}`);
|
|
113
|
+
}
|