auditor-lambda 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -9
- package/audit-code-wrapper-lib.mjs +19 -915
- package/dispatch/merge-results.mjs +1 -1
- package/dist/cli/auditStep.d.ts +1 -33
- package/dist/cli/dispatch.d.ts +47 -0
- package/dist/cli/dispatch.js +116 -1
- package/dist/cli/mergeAndIngestCommand.js +55 -8
- package/dist/cli/nextStepCommand.js +43 -15
- package/dist/cli/prompts.d.ts +2 -0
- package/dist/cli/prompts.js +9 -0
- package/dist/cli/reviewRun.js +1 -1
- package/dist/cli/runToCompletion.js +21 -8
- package/dist/cli/semanticReviewStep.js +12 -1
- package/dist/cli/steps.d.ts +15 -0
- package/dist/cli.js +1 -8
- package/dist/io/artifacts.d.ts +9 -1
- package/dist/io/artifacts.js +7 -0
- package/dist/io/runArtifacts.d.ts +14 -0
- package/dist/io/runArtifacts.js +23 -0
- package/dist/orchestrator/designReviewPrompt.d.ts +4 -1
- package/dist/orchestrator/designReviewPrompt.js +43 -2
- package/dist/orchestrator/executorResult.d.ts +25 -0
- package/dist/orchestrator/intakeExecutors.d.ts +19 -1
- package/dist/orchestrator/intakeExecutors.js +89 -3
- package/dist/orchestrator/nextStep.d.ts +1 -0
- package/dist/orchestrator/nextStep.js +1 -1
- package/dist/orchestrator/state.js +8 -1
- package/dist/providers/constants.d.ts +1 -1
- package/dist/providers/constants.js +1 -1
- package/dist/reporting/synthesis.d.ts +8 -0
- package/dist/reporting/synthesis.js +16 -1
- package/dist/supervisor/operatorHandoff.js +8 -1
- package/dist/types/auditScope.d.ts +16 -2
- package/dist/validation/sessionConfig.js +35 -0
- package/docs/contracts.md +0 -16
- package/docs/operator-guide.md +6 -8
- package/package.json +1 -1
- package/schemas/audit_findings.schema.json +1 -0
- package/scripts/postinstall.mjs +0 -174
- package/skills/audit-code/SKILL.md +17 -1
- package/skills/audit-code/audit-code.prompt.md +25 -0
- package/dist/mcp/server.d.ts +0 -72
- package/dist/mcp/server.js +0 -765
|
@@ -22,10 +22,7 @@ const INSTALL_GUIDE_FILENAME = 'GETTING-STARTED.md';
|
|
|
22
22
|
const INSTALL_MANIFEST_FILENAME = 'manifest.json';
|
|
23
23
|
const DEFAULT_INSTALL_HOST = 'all';
|
|
24
24
|
const INSTALLED_PROMPT_FILENAME = 'audit-code.import.md';
|
|
25
|
-
const MCP_LAUNCHER_FILENAME = 'run-mcp-server.mjs';
|
|
26
25
|
const packageVersion = JSON.parse(await readFile(packageJsonPath, 'utf8')).version;
|
|
27
|
-
const MCP_PROTOCOL_VERSION = '2025-06-18';
|
|
28
|
-
const INSTALL_VERIFY_TIMEOUT_MS = 10_000;
|
|
29
26
|
|
|
30
27
|
function hasFlag(argv, name) {
|
|
31
28
|
return argv.includes(name);
|
|
@@ -318,7 +315,7 @@ function printHelp({ usageName, preferredEntrypoint }) {
|
|
|
318
315
|
'- prompt-path prints the absolute path to the canonical /audit-code prompt asset',
|
|
319
316
|
'- ensure lazily bootstraps repo-local /audit-code assets when they are missing or stale',
|
|
320
317
|
'- install bootstraps /audit-code into supported repo-local host surfaces',
|
|
321
|
-
'- verify-install smoke-tests the generated host assets
|
|
318
|
+
'- verify-install smoke-tests the generated host assets after install',
|
|
322
319
|
'- mcp starts the local stdio MCP server for repo-local IDE integrations',
|
|
323
320
|
'- install-host --host copilot keeps the narrower Copilot-focused install path available',
|
|
324
321
|
'- next-step advances deterministic audit state and writes .audit-artifacts/steps/current-step.json plus current-prompt.md',
|
|
@@ -661,29 +658,6 @@ function renderVSCodeAgentFile() {
|
|
|
661
658
|
].join('\n');
|
|
662
659
|
}
|
|
663
660
|
|
|
664
|
-
function renderCodexMcpSetupGuide(root) {
|
|
665
|
-
return [
|
|
666
|
-
'# Codex MCP setup',
|
|
667
|
-
'',
|
|
668
|
-
'Codex shares MCP configuration between the app, CLI, and IDE extension. Register a local stdio MCP server named `auditor` that launches the repo-local wrapper below.',
|
|
669
|
-
'',
|
|
670
|
-
'Recommended command:',
|
|
671
|
-
`- command: \`node\``,
|
|
672
|
-
`- args: \`${toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME))}\``,
|
|
673
|
-
'',
|
|
674
|
-
'Equivalent config shape:',
|
|
675
|
-
'',
|
|
676
|
-
'```toml',
|
|
677
|
-
'[mcp_servers.auditor]',
|
|
678
|
-
'command = "node"',
|
|
679
|
-
`args = ["${replaceBackslashes(toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME)))}"]`,
|
|
680
|
-
'```',
|
|
681
|
-
'',
|
|
682
|
-
'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.',
|
|
683
|
-
'',
|
|
684
|
-
].join('\n');
|
|
685
|
-
}
|
|
686
|
-
|
|
687
661
|
function renderCodexAutomationRecipe() {
|
|
688
662
|
return [
|
|
689
663
|
'# Codex re-audit automation recipe',
|
|
@@ -692,7 +666,7 @@ function renderCodexAutomationRecipe() {
|
|
|
692
666
|
'',
|
|
693
667
|
'- 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.',
|
|
694
668
|
'- Cadence: daily on active branches or before release cut-offs',
|
|
695
|
-
'- Inputs: repository root
|
|
669
|
+
'- Inputs: repository root',
|
|
696
670
|
'',
|
|
697
671
|
'Use this recipe as a starting point for a Codex automation once the local workflow is stable in your environment.',
|
|
698
672
|
'',
|
|
@@ -739,8 +713,6 @@ const OPENCODE_AUDIT_BASH_PERMISSION = {
|
|
|
739
713
|
'*audit-code.mjs* worker-run*': 'allow',
|
|
740
714
|
'*audit-code.mjs* validate*': 'allow',
|
|
741
715
|
'*node* *auditor-lambda*dist*index.js* worker-run*': 'allow',
|
|
742
|
-
'node* .audit-code/install/run-mcp-server.mjs*': 'allow',
|
|
743
|
-
'node* ./.audit-code/install/run-mcp-server.mjs*': 'allow',
|
|
744
716
|
'git status*': 'allow',
|
|
745
717
|
'git diff*': 'allow',
|
|
746
718
|
'grep *': 'allow',
|
|
@@ -787,18 +759,6 @@ function renderOpenCodeProjectConfig(_root) {
|
|
|
787
759
|
};
|
|
788
760
|
}
|
|
789
761
|
|
|
790
|
-
function renderVSCodeMcpConfig() {
|
|
791
|
-
return {
|
|
792
|
-
servers: {
|
|
793
|
-
auditor: {
|
|
794
|
-
type: 'stdio',
|
|
795
|
-
command: 'node',
|
|
796
|
-
args: ['${workspaceFolder}/.audit-code/install/run-mcp-server.mjs'],
|
|
797
|
-
},
|
|
798
|
-
},
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
|
|
802
762
|
function objectValue(value) {
|
|
803
763
|
return value && typeof value === 'object' && !Array.isArray(value)
|
|
804
764
|
? value
|
|
@@ -910,7 +870,6 @@ function assertOpenCodeAuditPermissionConfig(permissionConfig, label) {
|
|
|
910
870
|
'*audit-code.mjs* merge-and-ingest*',
|
|
911
871
|
'*audit-code.mjs* worker-run*',
|
|
912
872
|
'*node* *auditor-lambda*dist*index.js* worker-run*',
|
|
913
|
-
'node* .audit-code/install/run-mcp-server.mjs*',
|
|
914
873
|
]) {
|
|
915
874
|
if (bash[pattern] !== 'allow') {
|
|
916
875
|
throw new Error(`OpenCode ${label}.bash must allow ${pattern}. Run "audit-code install --host opencode".`);
|
|
@@ -969,58 +928,6 @@ function buildMergedOpenCodeProjectConfig(existing, root) {
|
|
|
969
928
|
};
|
|
970
929
|
}
|
|
971
930
|
|
|
972
|
-
function buildMergedVSCodeMcpConfig(existing) {
|
|
973
|
-
const generated = renderVSCodeMcpConfig();
|
|
974
|
-
return {
|
|
975
|
-
...existing,
|
|
976
|
-
servers: {
|
|
977
|
-
...objectValue(existing.servers),
|
|
978
|
-
auditor: generated.servers.auditor,
|
|
979
|
-
},
|
|
980
|
-
};
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
function renderClaudeDesktopProjectTemplate() {
|
|
984
|
-
return [
|
|
985
|
-
'# Claude Desktop project template',
|
|
986
|
-
'',
|
|
987
|
-
'Suggested project instructions:',
|
|
988
|
-
'',
|
|
989
|
-
'- Treat `/audit-code` as the canonical autonomous audit workflow for this repository.',
|
|
990
|
-
'- Prefer `audit-code next-step`; use the installed auditor MCP tools only as a compatibility adapter over the same step contract.',
|
|
991
|
-
'- Read the operator handoff and artifact resources before asking for more context.',
|
|
992
|
-
'- Present the final deterministic audit report as work blocks first.',
|
|
993
|
-
'',
|
|
994
|
-
'Suggested project knowledge uploads:',
|
|
995
|
-
'',
|
|
996
|
-
'- `.audit-code/install/audit-code.import.md`',
|
|
997
|
-
'- `.audit-code/install/GETTING-STARTED.md`',
|
|
998
|
-
'- `docs/operator-guide.md` when you want host-specific operator context',
|
|
999
|
-
'',
|
|
1000
|
-
'Starter prompt:',
|
|
1001
|
-
'',
|
|
1002
|
-
'> 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.',
|
|
1003
|
-
'',
|
|
1004
|
-
].join('\n');
|
|
1005
|
-
}
|
|
1006
|
-
|
|
1007
|
-
function renderClaudeDesktopRemoteConnectorTemplate() {
|
|
1008
|
-
return JSON.stringify(
|
|
1009
|
-
{
|
|
1010
|
-
name: 'auditor-lambda',
|
|
1011
|
-
transport: 'remote-mcp',
|
|
1012
|
-
url: 'https://example.com/auditor-lambda/mcp',
|
|
1013
|
-
notes: [
|
|
1014
|
-
'Replace the URL with your hosted auditor MCP endpoint.',
|
|
1015
|
-
'Expose the same tool names as the local bundle: start_audit, get_status, continue_audit, explain_task, validate_artifacts, import_results, import_runtime_updates.',
|
|
1016
|
-
'Use OAuth or host-level auth when deploying this connector for Team or Enterprise rollouts.',
|
|
1017
|
-
],
|
|
1018
|
-
},
|
|
1019
|
-
null,
|
|
1020
|
-
2,
|
|
1021
|
-
) + '\n';
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
931
|
function renderAntigravityPlanningGuide(root) {
|
|
1025
932
|
return [
|
|
1026
933
|
'# Antigravity planning-mode guide',
|
|
@@ -1029,12 +936,11 @@ function renderAntigravityPlanningGuide(root) {
|
|
|
1029
936
|
'',
|
|
1030
937
|
'1. Open Antigravity in Planning mode.',
|
|
1031
938
|
'2. Load the repo-local prompt asset or the AGENTS instructions before starting the audit conversation.',
|
|
1032
|
-
'3. Ask Antigravity to use `audit-code next-step` directly.
|
|
939
|
+
'3. Ask Antigravity to use `audit-code next-step` directly.',
|
|
1033
940
|
'4. Review Antigravity artifacts before accepting major code changes or imported evidence.',
|
|
1034
941
|
'',
|
|
1035
942
|
'Recommended repo-local paths:',
|
|
1036
943
|
`- prompt asset: \`${toRepoRelativePath(root, join(root, '.audit-code', 'install', INSTALLED_PROMPT_FILENAME))}\``,
|
|
1037
|
-
`- MCP launcher: \`${toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME))}\``,
|
|
1038
944
|
'',
|
|
1039
945
|
'Artifact round-tripping policy:',
|
|
1040
946
|
'',
|
|
@@ -1059,383 +965,17 @@ function renderGeminiCommandToml(promptBody) {
|
|
|
1059
965
|
].join('\n');
|
|
1060
966
|
}
|
|
1061
967
|
|
|
1062
|
-
function renderSharedMcpLauncher(sourcePackageRoot) {
|
|
1063
|
-
return [
|
|
1064
|
-
"import { access, readFile } from 'node:fs/promises';",
|
|
1065
|
-
"import { constants } from 'node:fs';",
|
|
1066
|
-
"import { spawn } from 'node:child_process';",
|
|
1067
|
-
"import { dirname, join, resolve } from 'node:path';",
|
|
1068
|
-
"import { fileURLToPath } from 'node:url';",
|
|
1069
|
-
'',
|
|
1070
|
-
'const scriptDir = dirname(fileURLToPath(import.meta.url));',
|
|
1071
|
-
"const repoRoot = resolve(scriptDir, '..', '..');",
|
|
1072
|
-
"const artifactsDir = join(repoRoot, '.audit-artifacts');",
|
|
1073
|
-
'// Absolute path to the auditor-lambda package that generated this launcher.',
|
|
1074
|
-
'// Intentionally machine-specific: it is a load-bearing fallback candidate',
|
|
1075
|
-
'// (tried after a repo-local dependency) that lets the launcher find the',
|
|
1076
|
-
'// backend entrypoint when the target repo has no local auditor-lambda dep.',
|
|
1077
|
-
'// This file is regenerated per-install by `audit-code ensure`/`install` and',
|
|
1078
|
-
'// is gitignored, so the path is always re-derived for the current machine;',
|
|
1079
|
-
'// if it ever goes stale the launcher degrades gracefully to PATH/npx below.',
|
|
1080
|
-
`const sourcePackageRoot = ${JSON.stringify(sourcePackageRoot)};`,
|
|
1081
|
-
'',
|
|
1082
|
-
'async function exists(path) {',
|
|
1083
|
-
' try {',
|
|
1084
|
-
' await access(path, constants.F_OK);',
|
|
1085
|
-
' return true;',
|
|
1086
|
-
' } catch {',
|
|
1087
|
-
' return false;',
|
|
1088
|
-
' }',
|
|
1089
|
-
'}',
|
|
1090
|
-
'',
|
|
1091
|
-
'function spawnForward(command, args) {',
|
|
1092
|
-
' return new Promise((resolvePromise, rejectPromise) => {',
|
|
1093
|
-
' const child = spawn(command, args, {',
|
|
1094
|
-
' cwd: repoRoot,',
|
|
1095
|
-
' env: process.env,',
|
|
1096
|
-
" stdio: ['inherit', 'inherit', 'inherit'],",
|
|
1097
|
-
' });',
|
|
1098
|
-
" child.on('error', rejectPromise);",
|
|
1099
|
-
" child.on('exit', (code) => resolvePromise(code ?? 1));",
|
|
1100
|
-
' });',
|
|
1101
|
-
'}',
|
|
1102
|
-
'',
|
|
1103
|
-
'async function tryCandidates() {',
|
|
1104
|
-
" const localPackageEntrypoint = join(repoRoot, 'node_modules', 'auditor-lambda', 'audit-code.mjs');",
|
|
1105
|
-
" const localBin = process.platform === 'win32'",
|
|
1106
|
-
" ? join(repoRoot, 'node_modules', '.bin', 'audit-code.cmd')",
|
|
1107
|
-
" : join(repoRoot, 'node_modules', '.bin', 'audit-code');",
|
|
1108
|
-
" const repoPackageJsonPath = join(repoRoot, 'package.json');",
|
|
1109
|
-
" const sourcePackageEntrypoint = sourcePackageRoot",
|
|
1110
|
-
" ? join(sourcePackageRoot, 'audit-code.mjs')",
|
|
1111
|
-
" : null;",
|
|
1112
|
-
" const sourcePackageJsonPath = sourcePackageRoot",
|
|
1113
|
-
" ? join(sourcePackageRoot, 'package.json')",
|
|
1114
|
-
" : null;",
|
|
1115
|
-
' const sharedArgs = [\'mcp\', \'--root\', repoRoot, \'--artifacts-dir\', artifactsDir];',
|
|
1116
|
-
'',
|
|
1117
|
-
' if (await exists(localPackageEntrypoint)) {',
|
|
1118
|
-
' return await spawnForward(process.execPath, [localPackageEntrypoint, ...sharedArgs]);',
|
|
1119
|
-
' }',
|
|
1120
|
-
'',
|
|
1121
|
-
' if (await exists(repoPackageJsonPath) && await exists(join(repoRoot, \'audit-code.mjs\'))) {',
|
|
1122
|
-
' try {',
|
|
1123
|
-
" const packageJson = JSON.parse(await readFile(repoPackageJsonPath, 'utf8'));",
|
|
1124
|
-
" if (packageJson?.name === 'auditor-lambda') {",
|
|
1125
|
-
" return await spawnForward(process.execPath, [join(repoRoot, 'audit-code.mjs'), ...sharedArgs]);",
|
|
1126
|
-
' }',
|
|
1127
|
-
' } catch {',
|
|
1128
|
-
' // fall through to the next candidate',
|
|
1129
|
-
' }',
|
|
1130
|
-
' }',
|
|
1131
|
-
'',
|
|
1132
|
-
' if (sourcePackageEntrypoint && sourcePackageJsonPath && await exists(sourcePackageEntrypoint) && await exists(sourcePackageJsonPath)) {',
|
|
1133
|
-
' try {',
|
|
1134
|
-
" const packageJson = JSON.parse(await readFile(sourcePackageJsonPath, 'utf8'));",
|
|
1135
|
-
" if (packageJson?.name === 'auditor-lambda') {",
|
|
1136
|
-
' return await spawnForward(process.execPath, [sourcePackageEntrypoint, ...sharedArgs]);',
|
|
1137
|
-
' }',
|
|
1138
|
-
' } catch {',
|
|
1139
|
-
' // fall through to the next candidate',
|
|
1140
|
-
' }',
|
|
1141
|
-
' }',
|
|
1142
|
-
'',
|
|
1143
|
-
' if (await exists(localBin)) {',
|
|
1144
|
-
' return await spawnForward(localBin, sharedArgs);',
|
|
1145
|
-
' }',
|
|
1146
|
-
'',
|
|
1147
|
-
" const pathCandidate = process.platform === 'win32' ? 'audit-code.cmd' : 'audit-code';",
|
|
1148
|
-
' let exitCode = await spawnForward(pathCandidate, sharedArgs).catch(() => null);',
|
|
1149
|
-
' if (typeof exitCode === \'number\') {',
|
|
1150
|
-
' return exitCode;',
|
|
1151
|
-
' }',
|
|
1152
|
-
'',
|
|
1153
|
-
" exitCode = await spawnForward('npx', ['--no-install', 'audit-code', ...sharedArgs]).catch(() => null);",
|
|
1154
|
-
" if (typeof exitCode === 'number') {",
|
|
1155
|
-
' return exitCode;',
|
|
1156
|
-
' }',
|
|
1157
|
-
'',
|
|
1158
|
-
' throw new Error(',
|
|
1159
|
-
" 'Unable to locate an audit-code executable. Install auditor-lambda as a dependency or make the audit-code binary available on PATH.',",
|
|
1160
|
-
' );',
|
|
1161
|
-
'}',
|
|
1162
|
-
'',
|
|
1163
|
-
'const code = await tryCandidates();',
|
|
1164
|
-
'process.exitCode = code;',
|
|
1165
|
-
'',
|
|
1166
|
-
].join('\n');
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
function createCrc32Table() {
|
|
1170
|
-
const table = new Uint32Array(256);
|
|
1171
|
-
for (let index = 0; index < 256; index += 1) {
|
|
1172
|
-
let value = index;
|
|
1173
|
-
for (let bit = 0; bit < 8; bit += 1) {
|
|
1174
|
-
value = (value & 1) !== 0 ? (0xedb88320 ^ (value >>> 1)) : (value >>> 1);
|
|
1175
|
-
}
|
|
1176
|
-
table[index] = value >>> 0;
|
|
1177
|
-
}
|
|
1178
|
-
return table;
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
const CRC32_TABLE = createCrc32Table();
|
|
1182
|
-
|
|
1183
|
-
function crc32(buffer) {
|
|
1184
|
-
let crc = 0xffffffff;
|
|
1185
|
-
for (const byte of buffer) {
|
|
1186
|
-
crc = CRC32_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
|
|
1187
|
-
}
|
|
1188
|
-
return (crc ^ 0xffffffff) >>> 0;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
async function listFilesRecursive(root) {
|
|
1192
|
-
const files = [];
|
|
1193
|
-
const entries = await readdir(root, { withFileTypes: true });
|
|
1194
|
-
for (const entry of entries) {
|
|
1195
|
-
const absolutePath = join(root, entry.name);
|
|
1196
|
-
if (entry.isDirectory()) {
|
|
1197
|
-
files.push(...(await listFilesRecursive(absolutePath)));
|
|
1198
|
-
continue;
|
|
1199
|
-
}
|
|
1200
|
-
if (entry.isFile()) {
|
|
1201
|
-
files.push(absolutePath);
|
|
1202
|
-
}
|
|
1203
|
-
}
|
|
1204
|
-
return files.sort((a, b) => a.localeCompare(b));
|
|
1205
|
-
}
|
|
1206
|
-
|
|
1207
|
-
async function createStoredZipBuffer(sourceDir) {
|
|
1208
|
-
const absoluteFiles = await listFilesRecursive(sourceDir);
|
|
1209
|
-
const localParts = [];
|
|
1210
|
-
const centralParts = [];
|
|
1211
|
-
let offset = 0;
|
|
1212
|
-
|
|
1213
|
-
for (const absolutePath of absoluteFiles) {
|
|
1214
|
-
const relativePath = replaceBackslashes(relative(sourceDir, absolutePath));
|
|
1215
|
-
const fileName = Buffer.from(relativePath, 'utf8');
|
|
1216
|
-
const content = await readFile(absolutePath);
|
|
1217
|
-
const checksum = crc32(content);
|
|
1218
|
-
|
|
1219
|
-
const localHeader = Buffer.alloc(30);
|
|
1220
|
-
localHeader.writeUInt32LE(0x04034b50, 0);
|
|
1221
|
-
localHeader.writeUInt16LE(20, 4);
|
|
1222
|
-
localHeader.writeUInt16LE(0, 6);
|
|
1223
|
-
localHeader.writeUInt16LE(0, 8);
|
|
1224
|
-
localHeader.writeUInt16LE(0, 10);
|
|
1225
|
-
localHeader.writeUInt16LE(0, 12);
|
|
1226
|
-
localHeader.writeUInt32LE(checksum, 14);
|
|
1227
|
-
localHeader.writeUInt32LE(content.length, 18);
|
|
1228
|
-
localHeader.writeUInt32LE(content.length, 22);
|
|
1229
|
-
localHeader.writeUInt16LE(fileName.length, 26);
|
|
1230
|
-
localHeader.writeUInt16LE(0, 28);
|
|
1231
|
-
|
|
1232
|
-
localParts.push(localHeader, fileName, content);
|
|
1233
|
-
|
|
1234
|
-
const centralHeader = Buffer.alloc(46);
|
|
1235
|
-
centralHeader.writeUInt32LE(0x02014b50, 0);
|
|
1236
|
-
centralHeader.writeUInt16LE(20, 4);
|
|
1237
|
-
centralHeader.writeUInt16LE(20, 6);
|
|
1238
|
-
centralHeader.writeUInt16LE(0, 8);
|
|
1239
|
-
centralHeader.writeUInt16LE(0, 10);
|
|
1240
|
-
centralHeader.writeUInt16LE(0, 12);
|
|
1241
|
-
centralHeader.writeUInt16LE(0, 14);
|
|
1242
|
-
centralHeader.writeUInt32LE(checksum, 16);
|
|
1243
|
-
centralHeader.writeUInt32LE(content.length, 20);
|
|
1244
|
-
centralHeader.writeUInt32LE(content.length, 24);
|
|
1245
|
-
centralHeader.writeUInt16LE(fileName.length, 28);
|
|
1246
|
-
centralHeader.writeUInt16LE(0, 30);
|
|
1247
|
-
centralHeader.writeUInt16LE(0, 32);
|
|
1248
|
-
centralHeader.writeUInt16LE(0, 34);
|
|
1249
|
-
centralHeader.writeUInt16LE(0, 36);
|
|
1250
|
-
centralHeader.writeUInt32LE(0, 38);
|
|
1251
|
-
centralHeader.writeUInt32LE(offset, 42);
|
|
1252
|
-
|
|
1253
|
-
centralParts.push(centralHeader, fileName);
|
|
1254
|
-
offset += localHeader.length + fileName.length + content.length;
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
|
-
const centralDirectory = Buffer.concat(centralParts);
|
|
1258
|
-
const endOfCentralDirectory = Buffer.alloc(22);
|
|
1259
|
-
endOfCentralDirectory.writeUInt32LE(0x06054b50, 0);
|
|
1260
|
-
endOfCentralDirectory.writeUInt16LE(0, 4);
|
|
1261
|
-
endOfCentralDirectory.writeUInt16LE(0, 6);
|
|
1262
|
-
endOfCentralDirectory.writeUInt16LE(absoluteFiles.length, 8);
|
|
1263
|
-
endOfCentralDirectory.writeUInt16LE(absoluteFiles.length, 10);
|
|
1264
|
-
endOfCentralDirectory.writeUInt32LE(centralDirectory.length, 12);
|
|
1265
|
-
endOfCentralDirectory.writeUInt32LE(offset, 16);
|
|
1266
|
-
endOfCentralDirectory.writeUInt16LE(0, 20);
|
|
1267
|
-
|
|
1268
|
-
return Buffer.concat([...localParts, centralDirectory, endOfCentralDirectory]);
|
|
1269
|
-
}
|
|
1270
|
-
|
|
1271
|
-
// Copy the auditor's dist + schemas + skills + wrapper entrypoints (and, best
|
|
1272
|
-
// effort, the resolved @audit-tools/shared dist) into the Claude Desktop bundle
|
|
1273
|
-
// tree. Returns whether the bundle directory already existed (for the
|
|
1274
|
-
// created/updated result marker).
|
|
1275
|
-
async function copyClaudeDesktopBundleFiles(bundleRoot, serverRoot) {
|
|
1276
|
-
const bundleExisted = await fileExists(bundleRoot);
|
|
1277
|
-
await mkdir(serverRoot, { recursive: true });
|
|
1278
|
-
await cp(distEntry.replace(/dist[\\/]index\.js$/, 'dist'), join(bundleRoot, 'dist'), { recursive: true, force: true });
|
|
1279
|
-
await cp(join(repoRoot, 'schemas'), join(bundleRoot, 'schemas'), { recursive: true, force: true });
|
|
1280
|
-
await cp(join(repoRoot, 'skills', 'audit-code'), join(bundleRoot, 'skills', 'audit-code'), { recursive: true, force: true });
|
|
1281
|
-
await writeFile(join(bundleRoot, 'audit-code.mjs'), await readFile(join(repoRoot, 'audit-code.mjs')));
|
|
1282
|
-
await writeFile(join(bundleRoot, 'audit-code-wrapper-lib.mjs'), await readFile(join(repoRoot, 'audit-code-wrapper-lib.mjs')));
|
|
1283
|
-
await writeFile(join(bundleRoot, 'package.json'), await readFile(join(repoRoot, 'package.json')));
|
|
1284
|
-
|
|
1285
|
-
try {
|
|
1286
|
-
const req = createRequire(join(repoRoot, 'package.json'));
|
|
1287
|
-
const sharedEntry = req.resolve('@audit-tools/shared');
|
|
1288
|
-
let sharedRoot = dirname(sharedEntry);
|
|
1289
|
-
while (sharedRoot !== dirname(sharedRoot) && !(await fileExists(join(sharedRoot, 'package.json')))) {
|
|
1290
|
-
sharedRoot = dirname(sharedRoot);
|
|
1291
|
-
}
|
|
1292
|
-
const bundleSharedRoot = join(bundleRoot, 'node_modules', '@audit-tools', 'shared');
|
|
1293
|
-
await mkdir(bundleSharedRoot, { recursive: true });
|
|
1294
|
-
await cp(join(sharedRoot, 'dist'), join(bundleSharedRoot, 'dist'), { recursive: true, force: true });
|
|
1295
|
-
await writeFile(join(bundleSharedRoot, 'package.json'), await readFile(join(sharedRoot, 'package.json')));
|
|
1296
|
-
} catch {
|
|
1297
|
-
// @audit-tools/shared not resolvable — bundle will use runtime resolution
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
|
-
return { bundleExisted };
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
// Source for the bundle's server/index.js shim: it spawns the bundled
|
|
1304
|
-
// audit-code.mjs in MCP mode against the user-configured repo root.
|
|
1305
|
-
function renderClaudeDesktopServerEntry() {
|
|
1306
|
-
return [
|
|
1307
|
-
"import { spawn } from 'node:child_process';",
|
|
1308
|
-
"import { dirname, join } from 'node:path';",
|
|
1309
|
-
"import { fileURLToPath } from 'node:url';",
|
|
1310
|
-
'',
|
|
1311
|
-
'const serverDir = dirname(fileURLToPath(import.meta.url));',
|
|
1312
|
-
"const bundleRoot = join(serverDir, '..');",
|
|
1313
|
-
"const repoRoot = process.env.AUDIT_CODE_REPO_ROOT;",
|
|
1314
|
-
"const artifactsDir = process.env.AUDIT_CODE_ARTIFACTS_DIR || (repoRoot ? join(repoRoot, '.audit-artifacts') : undefined);",
|
|
1315
|
-
'',
|
|
1316
|
-
'if (!repoRoot) {',
|
|
1317
|
-
" console.error('AUDIT_CODE_REPO_ROOT must be configured before launching the auditor MCP bundle.');",
|
|
1318
|
-
' process.exit(1);',
|
|
1319
|
-
'}',
|
|
1320
|
-
'',
|
|
1321
|
-
"const child = spawn(process.execPath, [join(bundleRoot, 'audit-code.mjs'), 'mcp', '--root', repoRoot, '--artifacts-dir', artifactsDir], {",
|
|
1322
|
-
" cwd: repoRoot,",
|
|
1323
|
-
' env: process.env,',
|
|
1324
|
-
" stdio: ['inherit', 'inherit', 'inherit'],",
|
|
1325
|
-
'});',
|
|
1326
|
-
'',
|
|
1327
|
-
"child.on('exit', (code) => {",
|
|
1328
|
-
' process.exitCode = code ?? 1;',
|
|
1329
|
-
'});',
|
|
1330
|
-
'',
|
|
1331
|
-
].join('\n');
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
// The DXT/MCPB manifest.json describing the bundled node MCP server and its
|
|
1335
|
-
// Claude Desktop user-config inputs.
|
|
1336
|
-
function buildClaudeDesktopManifest() {
|
|
1337
|
-
return {
|
|
1338
|
-
manifest_version: '0.3',
|
|
1339
|
-
name: 'auditor-lambda',
|
|
1340
|
-
display_name: 'Auditor Lambda',
|
|
1341
|
-
version: packageVersion,
|
|
1342
|
-
description: 'Compatibility MCP bundle for the /audit-code autonomous audit workflow.',
|
|
1343
|
-
long_description:
|
|
1344
|
-
'Runs a local compatibility MCP adapter whose start and continue tools return the same audit-code next-step contract as the direct CLI loop.',
|
|
1345
|
-
author: {
|
|
1346
|
-
name: 'auditor-lambda',
|
|
1347
|
-
url: 'https://github.com/OhOkThisIsFine/auditor-lambda',
|
|
1348
|
-
},
|
|
1349
|
-
repository: {
|
|
1350
|
-
type: 'git',
|
|
1351
|
-
url: 'https://github.com/OhOkThisIsFine/auditor-lambda.git',
|
|
1352
|
-
},
|
|
1353
|
-
documentation: 'https://github.com/OhOkThisIsFine/auditor-lambda/tree/main/docs',
|
|
1354
|
-
support: 'https://github.com/OhOkThisIsFine/auditor-lambda/issues',
|
|
1355
|
-
license: 'MIT',
|
|
1356
|
-
compatibility: {
|
|
1357
|
-
claude_desktop: '>=1.0.0',
|
|
1358
|
-
platforms: ['darwin', 'win32', 'linux'],
|
|
1359
|
-
runtimes: {
|
|
1360
|
-
node: '>=20.0.0',
|
|
1361
|
-
},
|
|
1362
|
-
},
|
|
1363
|
-
tools_generated: true,
|
|
1364
|
-
prompts_generated: true,
|
|
1365
|
-
server: {
|
|
1366
|
-
type: 'node',
|
|
1367
|
-
entry_point: 'server/index.js',
|
|
1368
|
-
mcp_config: {
|
|
1369
|
-
command: 'node',
|
|
1370
|
-
args: ['${__dirname}/server/index.js'],
|
|
1371
|
-
env: {
|
|
1372
|
-
AUDIT_CODE_REPO_ROOT: '${user_config.repo_root}',
|
|
1373
|
-
AUDIT_CODE_ARTIFACTS_DIR: '${user_config.artifacts_dir}',
|
|
1374
|
-
},
|
|
1375
|
-
},
|
|
1376
|
-
},
|
|
1377
|
-
user_config: {
|
|
1378
|
-
repo_root: {
|
|
1379
|
-
type: 'directory',
|
|
1380
|
-
title: 'Repository Root',
|
|
1381
|
-
description: 'Repository to audit with auditor-lambda.',
|
|
1382
|
-
required: true,
|
|
1383
|
-
},
|
|
1384
|
-
artifacts_dir: {
|
|
1385
|
-
type: 'directory',
|
|
1386
|
-
title: 'Artifacts Directory',
|
|
1387
|
-
description: 'Optional override for the audit artifacts directory.',
|
|
1388
|
-
required: false,
|
|
1389
|
-
},
|
|
1390
|
-
},
|
|
1391
|
-
};
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
// Orchestrates the Claude Desktop bundle: copy files, write the server shim and
|
|
1395
|
-
// manifest, then zip into the .dxt / .mcpb archives. Pushes each generated file
|
|
1396
|
-
// into `results`.
|
|
1397
|
-
async function buildClaudeDesktopBundle(root, results) {
|
|
1398
|
-
const bundleRoot = join(root, '.audit-code', 'install', 'claude-desktop', 'bundle');
|
|
1399
|
-
const serverRoot = join(bundleRoot, 'server');
|
|
1400
|
-
const manifestPath = join(bundleRoot, 'manifest.json');
|
|
1401
|
-
const serverEntrypointPath = join(serverRoot, 'index.js');
|
|
1402
|
-
const dxtPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.dxt');
|
|
1403
|
-
const mcpbPath = join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.mcpb');
|
|
1404
|
-
|
|
1405
|
-
const { bundleExisted } = await copyClaudeDesktopBundleFiles(bundleRoot, serverRoot);
|
|
1406
|
-
results.push({ path: bundleRoot, mode: bundleExisted ? 'updated' : 'created' });
|
|
1407
|
-
|
|
1408
|
-
results.push(
|
|
1409
|
-
await writeGeneratedMarkdown(serverEntrypointPath, renderClaudeDesktopServerEntry()),
|
|
1410
|
-
);
|
|
1411
|
-
results.push(await writeGeneratedJson(manifestPath, buildClaudeDesktopManifest()));
|
|
1412
|
-
|
|
1413
|
-
const archive = await createStoredZipBuffer(bundleRoot);
|
|
1414
|
-
results.push(await writeGeneratedBinary(dxtPath, archive));
|
|
1415
|
-
results.push(await writeGeneratedBinary(mcpbPath, archive));
|
|
1416
|
-
|
|
1417
|
-
return {
|
|
1418
|
-
bundleRoot,
|
|
1419
|
-
manifestPath,
|
|
1420
|
-
dxtPath,
|
|
1421
|
-
mcpbPath,
|
|
1422
|
-
serverEntrypointPath,
|
|
1423
|
-
};
|
|
1424
|
-
}
|
|
1425
|
-
|
|
1426
968
|
const INSTALL_PROFILE_FLAGS = [
|
|
1427
969
|
'writeVSCode',
|
|
1428
970
|
'writeCopilotInstructions',
|
|
1429
971
|
'writeOpenCode',
|
|
1430
972
|
'writeCodex',
|
|
1431
|
-
'writeClaudeDesktop',
|
|
1432
973
|
'writeAntigravity',
|
|
1433
974
|
'writeAgents',
|
|
1434
975
|
];
|
|
1435
976
|
|
|
1436
977
|
const INSTALL_HOST_ORDER = [
|
|
1437
978
|
'codex',
|
|
1438
|
-
'claude-desktop',
|
|
1439
979
|
'opencode',
|
|
1440
980
|
'vscode',
|
|
1441
981
|
'antigravity',
|
|
@@ -1452,7 +992,6 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1452
992
|
primary_path_key: 'agentsInstructionsPath',
|
|
1453
993
|
supporting_path_keys: [
|
|
1454
994
|
'installedPromptPath',
|
|
1455
|
-
'mcpLauncherPath',
|
|
1456
995
|
],
|
|
1457
996
|
steps: [
|
|
1458
997
|
'Open this repository in Codex.',
|
|
@@ -1475,119 +1014,16 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1475
1014
|
});
|
|
1476
1015
|
},
|
|
1477
1016
|
},
|
|
1478
|
-
'claude-desktop': {
|
|
1479
|
-
host: 'claude-desktop',
|
|
1480
|
-
label: 'Claude Desktop',
|
|
1481
|
-
support_level: 'supported',
|
|
1482
|
-
setup_kind: 'local-mcp-bundle',
|
|
1483
|
-
summary:
|
|
1484
|
-
'Install the generated local MCP compatibility bundle in Claude Desktop, then use the project template and prompt asset as supporting context.',
|
|
1485
|
-
primary_path_key: 'claudeDesktopDxtPath',
|
|
1486
|
-
supporting_path_keys: [
|
|
1487
|
-
'claudeDesktopMcpbPath',
|
|
1488
|
-
'claudeDesktopProjectTemplatePath',
|
|
1489
|
-
'claudeDesktopRemoteConnectorPath',
|
|
1490
|
-
'installedPromptPath',
|
|
1491
|
-
],
|
|
1492
|
-
steps: [
|
|
1493
|
-
'Open Claude Desktop Settings and install the generated `.dxt` bundle.',
|
|
1494
|
-
'Configure the repository root when prompted so the bundle can launch the local auditor MCP adapter.',
|
|
1495
|
-
'Use the project template and prompt asset to kick off `/audit-code` in conversation.',
|
|
1496
|
-
],
|
|
1497
|
-
profile: {
|
|
1498
|
-
writeClaudeDesktop: true,
|
|
1499
|
-
},
|
|
1500
|
-
async verify({ checks, root, assetPaths, collectVerifyCheck: collect }) {
|
|
1501
|
-
const bundleManifestPath = join(
|
|
1502
|
-
root,
|
|
1503
|
-
'.audit-code',
|
|
1504
|
-
'install',
|
|
1505
|
-
'claude-desktop',
|
|
1506
|
-
'bundle',
|
|
1507
|
-
'manifest.json',
|
|
1508
|
-
);
|
|
1509
|
-
const bundleServerPath = join(
|
|
1510
|
-
root,
|
|
1511
|
-
'.audit-code',
|
|
1512
|
-
'install',
|
|
1513
|
-
'claude-desktop',
|
|
1514
|
-
'bundle',
|
|
1515
|
-
'server',
|
|
1516
|
-
'index.js',
|
|
1517
|
-
);
|
|
1518
|
-
|
|
1519
|
-
await collect(checks, 'claude_bundle_manifest', async () => {
|
|
1520
|
-
const manifest = await readJson(bundleManifestPath, 'Claude Desktop bundle manifest');
|
|
1521
|
-
if (manifest?.server?.entry_point !== 'server/index.js') {
|
|
1522
|
-
throw new Error(`Claude Desktop bundle manifest has an unexpected entry_point: ${manifest?.server?.entry_point ?? 'missing'}.`);
|
|
1523
|
-
}
|
|
1524
|
-
return {
|
|
1525
|
-
summary: 'Claude Desktop bundle manifest parsed successfully.',
|
|
1526
|
-
path: bundleManifestPath,
|
|
1527
|
-
};
|
|
1528
|
-
});
|
|
1529
|
-
await collect(checks, 'claude_connector_template', async () => {
|
|
1530
|
-
const connector = await readJson(
|
|
1531
|
-
assetPaths.claudeDesktopRemoteConnectorPath,
|
|
1532
|
-
'Claude Desktop remote connector template',
|
|
1533
|
-
);
|
|
1534
|
-
if (connector?.transport !== 'remote-mcp') {
|
|
1535
|
-
throw new Error(`Claude Desktop remote connector transport must be "remote-mcp", got ${connector?.transport ?? 'missing'}.`);
|
|
1536
|
-
}
|
|
1537
|
-
return {
|
|
1538
|
-
summary: 'Claude Desktop remote connector template parsed successfully.',
|
|
1539
|
-
path: assetPaths.claudeDesktopRemoteConnectorPath,
|
|
1540
|
-
};
|
|
1541
|
-
});
|
|
1542
|
-
await collect(checks, 'claude_dxt_archive', async () => ({
|
|
1543
|
-
summary: 'Claude Desktop .dxt bundle is present.',
|
|
1544
|
-
path: assetPaths.claudeDesktopDxtPath,
|
|
1545
|
-
size_bytes: await verifyZipFile(
|
|
1546
|
-
assetPaths.claudeDesktopDxtPath,
|
|
1547
|
-
'Claude Desktop .dxt bundle',
|
|
1548
|
-
),
|
|
1549
|
-
}));
|
|
1550
|
-
await collect(checks, 'claude_mcpb_archive', async () => ({
|
|
1551
|
-
summary: 'Claude Desktop .mcpb bundle is present.',
|
|
1552
|
-
path: assetPaths.claudeDesktopMcpbPath,
|
|
1553
|
-
size_bytes: await verifyZipFile(
|
|
1554
|
-
assetPaths.claudeDesktopMcpbPath,
|
|
1555
|
-
'Claude Desktop .mcpb bundle',
|
|
1556
|
-
),
|
|
1557
|
-
}));
|
|
1558
|
-
await collect(checks, 'claude_bundle_mcp', async () => {
|
|
1559
|
-
const probe = await probeMcpServer({
|
|
1560
|
-
label: 'Claude Desktop bundle server',
|
|
1561
|
-
command: process.execPath,
|
|
1562
|
-
args: [bundleServerPath],
|
|
1563
|
-
cwd: root,
|
|
1564
|
-
env: {
|
|
1565
|
-
AUDIT_CODE_REPO_ROOT: root,
|
|
1566
|
-
AUDIT_CODE_ARTIFACTS_DIR: join(root, '.audit-artifacts'),
|
|
1567
|
-
},
|
|
1568
|
-
});
|
|
1569
|
-
const toolNames = (probe.tools?.tools ?? []).map((tool) => tool.name);
|
|
1570
|
-
if (!toolNames.includes('start_audit')) {
|
|
1571
|
-
throw new Error('Claude Desktop bundle server did not expose the start_audit tool.');
|
|
1572
|
-
}
|
|
1573
|
-
return {
|
|
1574
|
-
summary: 'Claude Desktop bundle completed an MCP handshake.',
|
|
1575
|
-
tool_count: toolNames.length,
|
|
1576
|
-
};
|
|
1577
|
-
});
|
|
1578
|
-
},
|
|
1579
|
-
},
|
|
1580
1017
|
opencode: {
|
|
1581
1018
|
host: 'opencode',
|
|
1582
1019
|
label: 'OpenCode',
|
|
1583
1020
|
support_level: 'supported',
|
|
1584
|
-
setup_kind: 'global-command+project-
|
|
1021
|
+
setup_kind: 'global-command+project-permissions',
|
|
1585
1022
|
summary:
|
|
1586
|
-
'Use the global OpenCode `/audit-code` command installed by npm plus generated project permissions
|
|
1023
|
+
'Use the global OpenCode `/audit-code` command installed by npm plus generated project permissions.',
|
|
1587
1024
|
primary_path_key: 'opencodeConfigPath',
|
|
1588
1025
|
supporting_path_keys: [
|
|
1589
1026
|
'agentsInstructionsPath',
|
|
1590
|
-
'mcpLauncherPath',
|
|
1591
1027
|
],
|
|
1592
1028
|
steps: [
|
|
1593
1029
|
'Open this repository in OpenCode.',
|
|
@@ -1620,19 +1056,17 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1620
1056
|
host: 'vscode',
|
|
1621
1057
|
label: 'VS Code',
|
|
1622
1058
|
support_level: 'supported',
|
|
1623
|
-
setup_kind: 'prompt+agent
|
|
1059
|
+
setup_kind: 'prompt+agent',
|
|
1624
1060
|
summary:
|
|
1625
|
-
'Use the generated prompt file and custom agent for next-step-first VS Code integration
|
|
1061
|
+
'Use the generated prompt file and custom agent for next-step-first VS Code integration.',
|
|
1626
1062
|
primary_path_key: 'vscodePromptPath',
|
|
1627
1063
|
supporting_path_keys: [
|
|
1628
1064
|
'vscodeAgentPath',
|
|
1629
|
-
'vscodeMcpConfigPath',
|
|
1630
1065
|
'copilotInstructionsPath',
|
|
1631
1066
|
],
|
|
1632
1067
|
steps: [
|
|
1633
1068
|
'Open this repository in VS Code with Copilot.',
|
|
1634
1069
|
'Invoke `/audit-code` from the generated prompt or chat so the workflow calls `audit-code next-step` directly.',
|
|
1635
|
-
'Use the workspace MCP adapter only when direct shell access is unavailable.',
|
|
1636
1070
|
],
|
|
1637
1071
|
profile: {
|
|
1638
1072
|
writeVSCode: true,
|
|
@@ -1656,42 +1090,27 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1656
1090
|
path: assetPaths.vscodePromptPath,
|
|
1657
1091
|
};
|
|
1658
1092
|
});
|
|
1659
|
-
await collect(checks, 'vscode_mcp_config', async () => {
|
|
1660
|
-
const config = await readJson(assetPaths.vscodeMcpConfigPath, 'VS Code MCP config');
|
|
1661
|
-
const args = config?.servers?.auditor?.args;
|
|
1662
|
-
if (config?.servers?.auditor?.command !== 'node') {
|
|
1663
|
-
throw new Error(`VS Code MCP config must use node as the command, got ${config?.servers?.auditor?.command ?? 'missing'}.`);
|
|
1664
|
-
}
|
|
1665
|
-
if (!Array.isArray(args) || args[0] !== '${workspaceFolder}/.audit-code/install/run-mcp-server.mjs') {
|
|
1666
|
-
throw new Error(`VS Code MCP config must point at \${workspaceFolder}/.audit-code/install/${MCP_LAUNCHER_FILENAME}.`);
|
|
1667
|
-
}
|
|
1668
|
-
return {
|
|
1669
|
-
summary: 'VS Code MCP config parsed successfully.',
|
|
1670
|
-
path: assetPaths.vscodeMcpConfigPath,
|
|
1671
|
-
};
|
|
1672
|
-
});
|
|
1673
1093
|
},
|
|
1674
1094
|
},
|
|
1675
1095
|
antigravity: {
|
|
1676
1096
|
host: 'antigravity',
|
|
1677
1097
|
label: 'Antigravity',
|
|
1678
1098
|
support_level: 'supported',
|
|
1679
|
-
setup_kind: 'agent-skill+gemini-command+planning-guide
|
|
1099
|
+
setup_kind: 'agent-skill+gemini-command+planning-guide',
|
|
1680
1100
|
summary:
|
|
1681
|
-
'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.
|
|
1101
|
+
'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.',
|
|
1682
1102
|
primary_path_key: 'antigravitySkillPath',
|
|
1683
1103
|
supporting_path_keys: [
|
|
1684
1104
|
'geminiCommandPath',
|
|
1685
1105
|
'antigravityPlanningGuidePath',
|
|
1686
1106
|
'agentsInstructionsPath',
|
|
1687
|
-
'mcpLauncherPath',
|
|
1688
1107
|
'installedPromptPath',
|
|
1689
1108
|
],
|
|
1690
1109
|
steps: [
|
|
1691
1110
|
'Open this repository in Antigravity.',
|
|
1692
1111
|
'The audit-code skill is automatically discovered from .agent/skills/audit-code/SKILL.md.',
|
|
1693
1112
|
'The /audit-code slash command is also available from .gemini/commands/audit-code.toml.',
|
|
1694
|
-
'Use `audit-code next-step` directly
|
|
1113
|
+
'Use `audit-code next-step` directly.',
|
|
1695
1114
|
],
|
|
1696
1115
|
profile: {
|
|
1697
1116
|
writeAntigravity: true,
|
|
@@ -1710,11 +1129,11 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1710
1129
|
});
|
|
1711
1130
|
await collect(checks, 'antigravity_guide', async () => {
|
|
1712
1131
|
const content = await readFile(assetPaths.antigravityPlanningGuidePath, 'utf8');
|
|
1713
|
-
if (!content.includes(
|
|
1714
|
-
throw new Error(`Antigravity guide must reference
|
|
1132
|
+
if (!content.includes(INSTALLED_PROMPT_FILENAME)) {
|
|
1133
|
+
throw new Error(`Antigravity guide must reference ${INSTALLED_PROMPT_FILENAME}.`);
|
|
1715
1134
|
}
|
|
1716
1135
|
return {
|
|
1717
|
-
summary: 'Antigravity planning guide references the repo-local prompt asset
|
|
1136
|
+
summary: 'Antigravity planning guide references the repo-local prompt asset.',
|
|
1718
1137
|
path: assetPaths.antigravityPlanningGuidePath,
|
|
1719
1138
|
};
|
|
1720
1139
|
});
|
|
@@ -1804,7 +1223,6 @@ function renderInstallGuide({
|
|
|
1804
1223
|
installedPromptPath,
|
|
1805
1224
|
installedSkillPath,
|
|
1806
1225
|
installManifestPath,
|
|
1807
|
-
mcpLauncherPath,
|
|
1808
1226
|
hostGuidance,
|
|
1809
1227
|
}) {
|
|
1810
1228
|
const lines = [
|
|
@@ -1816,7 +1234,6 @@ function renderInstallGuide({
|
|
|
1816
1234
|
`- prompt asset: \`${toRepoRelativePath(root, installedPromptPath)}\``,
|
|
1817
1235
|
`- skill asset: \`${toRepoRelativePath(root, installedSkillPath)}\``,
|
|
1818
1236
|
`- host manifest: \`${toRepoRelativePath(root, installManifestPath)}\``,
|
|
1819
|
-
`- shared MCP launcher: \`${toRepoRelativePath(root, mcpLauncherPath)}\``,
|
|
1820
1237
|
'',
|
|
1821
1238
|
'Host-specific quick starts:',
|
|
1822
1239
|
];
|
|
@@ -1849,7 +1266,7 @@ function renderInstallGuide({
|
|
|
1849
1266
|
lines.push('', 'Backend fallback:');
|
|
1850
1267
|
lines.push('- from the repository root, run `audit-code` only when you intentionally need the repo-local backend wrapper');
|
|
1851
1268
|
lines.push('- run `audit-code verify-install` after bootstrap when you want to smoke-test the generated launchers and host configs');
|
|
1852
|
-
lines.push('- rerun `audit-code install` to refresh every generated host surface from the shared prompt
|
|
1269
|
+
lines.push('- rerun `audit-code install` to refresh every generated host surface from the shared prompt and skill assets together');
|
|
1853
1270
|
|
|
1854
1271
|
if (host !== 'all') {
|
|
1855
1272
|
lines.push('');
|
|
@@ -1873,207 +1290,6 @@ async function assertDirectoryExists(path, description) {
|
|
|
1873
1290
|
}
|
|
1874
1291
|
}
|
|
1875
1292
|
|
|
1876
|
-
function encodeMcpMessage(payload) {
|
|
1877
|
-
const body = Buffer.from(JSON.stringify(payload), 'utf8');
|
|
1878
|
-
return Buffer.concat([
|
|
1879
|
-
Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, 'utf8'),
|
|
1880
|
-
body,
|
|
1881
|
-
]);
|
|
1882
|
-
}
|
|
1883
|
-
|
|
1884
|
-
function createInstallMcpClient(command, args, options = {}) {
|
|
1885
|
-
const child = spawn(command, args, {
|
|
1886
|
-
cwd: options.cwd,
|
|
1887
|
-
env: { ...process.env, ...(options.env ?? {}) },
|
|
1888
|
-
stdio: ['pipe', 'pipe', 'pipe'],
|
|
1889
|
-
});
|
|
1890
|
-
|
|
1891
|
-
let buffer = Buffer.alloc(0);
|
|
1892
|
-
let stderr = '';
|
|
1893
|
-
let exitError = null;
|
|
1894
|
-
const pending = new Map();
|
|
1895
|
-
|
|
1896
|
-
function failPending(error) {
|
|
1897
|
-
for (const { reject } of pending.values()) {
|
|
1898
|
-
reject(error);
|
|
1899
|
-
}
|
|
1900
|
-
pending.clear();
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
child.stdout.on('data', (chunk) => {
|
|
1904
|
-
buffer = Buffer.concat([buffer, chunk]);
|
|
1905
|
-
|
|
1906
|
-
while (true) {
|
|
1907
|
-
const separator = buffer.indexOf('\r\n\r\n');
|
|
1908
|
-
if (separator < 0) {
|
|
1909
|
-
return;
|
|
1910
|
-
}
|
|
1911
|
-
|
|
1912
|
-
const headerBlock = buffer.slice(0, separator).toString('utf8');
|
|
1913
|
-
const contentLengthHeader = headerBlock
|
|
1914
|
-
.split('\r\n')
|
|
1915
|
-
.find((header) => header.toLowerCase().startsWith('content-length:'));
|
|
1916
|
-
if (!contentLengthHeader) {
|
|
1917
|
-
return;
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
const contentLength = Number(contentLengthHeader.split(':')[1]?.trim());
|
|
1921
|
-
const frameLength = separator + 4 + contentLength;
|
|
1922
|
-
if (buffer.length < frameLength) {
|
|
1923
|
-
return;
|
|
1924
|
-
}
|
|
1925
|
-
|
|
1926
|
-
const payload = JSON.parse(
|
|
1927
|
-
buffer.slice(separator + 4, frameLength).toString('utf8'),
|
|
1928
|
-
);
|
|
1929
|
-
buffer = buffer.slice(frameLength);
|
|
1930
|
-
|
|
1931
|
-
if (pending.has(payload.id)) {
|
|
1932
|
-
const { resolve, reject } = pending.get(payload.id);
|
|
1933
|
-
pending.delete(payload.id);
|
|
1934
|
-
if (payload.error) {
|
|
1935
|
-
reject(
|
|
1936
|
-
new Error(payload.error.message ?? JSON.stringify(payload.error)),
|
|
1937
|
-
);
|
|
1938
|
-
continue;
|
|
1939
|
-
}
|
|
1940
|
-
resolve(payload.result);
|
|
1941
|
-
}
|
|
1942
|
-
}
|
|
1943
|
-
});
|
|
1944
|
-
|
|
1945
|
-
child.stderr.on('data', (chunk) => {
|
|
1946
|
-
stderr += String(chunk);
|
|
1947
|
-
});
|
|
1948
|
-
|
|
1949
|
-
child.on('error', (error) => {
|
|
1950
|
-
exitError = error;
|
|
1951
|
-
failPending(error);
|
|
1952
|
-
});
|
|
1953
|
-
|
|
1954
|
-
child.on('exit', (code, signal) => {
|
|
1955
|
-
if (exitError) {
|
|
1956
|
-
return;
|
|
1957
|
-
}
|
|
1958
|
-
exitError = new Error(
|
|
1959
|
-
`MCP process exited early with code ${code ?? 'null'}${signal ? ` and signal ${signal}` : ''}.${stderr.trim().length > 0 ? ` ${stderr.trim()}` : ''}`,
|
|
1960
|
-
);
|
|
1961
|
-
failPending(exitError);
|
|
1962
|
-
});
|
|
1963
|
-
|
|
1964
|
-
function request(id, method, params = {}) {
|
|
1965
|
-
return new Promise((resolve, reject) => {
|
|
1966
|
-
if (exitError) {
|
|
1967
|
-
reject(exitError);
|
|
1968
|
-
return;
|
|
1969
|
-
}
|
|
1970
|
-
pending.set(id, { resolve, reject });
|
|
1971
|
-
child.stdin.write(
|
|
1972
|
-
encodeMcpMessage({
|
|
1973
|
-
jsonrpc: '2.0',
|
|
1974
|
-
id,
|
|
1975
|
-
method,
|
|
1976
|
-
params,
|
|
1977
|
-
}),
|
|
1978
|
-
);
|
|
1979
|
-
});
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
function notify(method, params = {}) {
|
|
1983
|
-
if (exitError) {
|
|
1984
|
-
return;
|
|
1985
|
-
}
|
|
1986
|
-
child.stdin.write(
|
|
1987
|
-
encodeMcpMessage({
|
|
1988
|
-
jsonrpc: '2.0',
|
|
1989
|
-
method,
|
|
1990
|
-
params,
|
|
1991
|
-
}),
|
|
1992
|
-
);
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
async function close() {
|
|
1996
|
-
if (!exitError) {
|
|
1997
|
-
await request('shutdown', 'shutdown');
|
|
1998
|
-
notify('exit');
|
|
1999
|
-
child.stdin.end();
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
if (child.exitCode !== null || child.signalCode !== null) {
|
|
2003
|
-
return;
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
await new Promise((resolvePromise) => {
|
|
2007
|
-
child.on('exit', () => resolvePromise());
|
|
2008
|
-
});
|
|
2009
|
-
}
|
|
2010
|
-
|
|
2011
|
-
return {
|
|
2012
|
-
request,
|
|
2013
|
-
notify,
|
|
2014
|
-
close,
|
|
2015
|
-
readStderr() {
|
|
2016
|
-
return stderr.trim();
|
|
2017
|
-
},
|
|
2018
|
-
};
|
|
2019
|
-
}
|
|
2020
|
-
|
|
2021
|
-
async function probeMcpServer(params) {
|
|
2022
|
-
const client = createInstallMcpClient(params.command, params.args, {
|
|
2023
|
-
cwd: params.cwd,
|
|
2024
|
-
env: params.env,
|
|
2025
|
-
});
|
|
2026
|
-
|
|
2027
|
-
let timerId;
|
|
2028
|
-
const timeout = new Promise((_, reject) => {
|
|
2029
|
-
timerId = setTimeout(() => {
|
|
2030
|
-
reject(
|
|
2031
|
-
new Error(
|
|
2032
|
-
`${params.label} did not complete an MCP handshake within ${INSTALL_VERIFY_TIMEOUT_MS}ms.`,
|
|
2033
|
-
),
|
|
2034
|
-
);
|
|
2035
|
-
}, INSTALL_VERIFY_TIMEOUT_MS);
|
|
2036
|
-
});
|
|
2037
|
-
|
|
2038
|
-
try {
|
|
2039
|
-
const result = await Promise.race([
|
|
2040
|
-
(async () => {
|
|
2041
|
-
const initialize = await client.request('init', 'initialize', {
|
|
2042
|
-
protocolVersion: MCP_PROTOCOL_VERSION,
|
|
2043
|
-
capabilities: {},
|
|
2044
|
-
clientInfo: {
|
|
2045
|
-
name: 'audit-code-verify-install',
|
|
2046
|
-
version: packageVersion,
|
|
2047
|
-
},
|
|
2048
|
-
});
|
|
2049
|
-
client.notify('notifications/initialized');
|
|
2050
|
-
const tools = await client.request('tools', 'tools/list');
|
|
2051
|
-
const resources = await client.request('resources', 'resources/list');
|
|
2052
|
-
await client.close();
|
|
2053
|
-
return {
|
|
2054
|
-
initialize,
|
|
2055
|
-
tools,
|
|
2056
|
-
resources,
|
|
2057
|
-
stderr: client.readStderr(),
|
|
2058
|
-
};
|
|
2059
|
-
})(),
|
|
2060
|
-
timeout,
|
|
2061
|
-
]);
|
|
2062
|
-
clearTimeout(timerId);
|
|
2063
|
-
return result;
|
|
2064
|
-
} catch (error) {
|
|
2065
|
-
clearTimeout(timerId);
|
|
2066
|
-
const stderr = client.readStderr();
|
|
2067
|
-
try {
|
|
2068
|
-
await client.close();
|
|
2069
|
-
} catch {
|
|
2070
|
-
// already failed or exited
|
|
2071
|
-
}
|
|
2072
|
-
const suffix = stderr.length > 0 ? ` ${stderr}` : '';
|
|
2073
|
-
throw new Error(`${error instanceof Error ? error.message : String(error)}${suffix}`);
|
|
2074
|
-
}
|
|
2075
|
-
}
|
|
2076
|
-
|
|
2077
1293
|
async function collectVerifyCheck(target, id, fn) {
|
|
2078
1294
|
try {
|
|
2079
1295
|
const details = await fn();
|
|
@@ -2241,39 +1457,6 @@ async function verifyInstalledBootstrap(argv) {
|
|
|
2241
1457
|
};
|
|
2242
1458
|
});
|
|
2243
1459
|
|
|
2244
|
-
await collectVerifyCheck(generalChecks, 'shared_launcher_file', async () => {
|
|
2245
|
-
const launcher = await readFile(assetPaths.mcpLauncherPath, 'utf8');
|
|
2246
|
-
if (!launcher.includes('Unable to locate an audit-code executable')) {
|
|
2247
|
-
throw new Error(`Shared MCP launcher is missing the executable resolution fallback message: ${assetPaths.mcpLauncherPath}`);
|
|
2248
|
-
}
|
|
2249
|
-
if (!launcher.includes('sourcePackageRoot')) {
|
|
2250
|
-
throw new Error(`Shared MCP launcher is missing the package-source fallback hint: ${assetPaths.mcpLauncherPath}`);
|
|
2251
|
-
}
|
|
2252
|
-
return {
|
|
2253
|
-
summary: 'Shared MCP launcher is present and includes resolver fallbacks.',
|
|
2254
|
-
path: assetPaths.mcpLauncherPath,
|
|
2255
|
-
};
|
|
2256
|
-
});
|
|
2257
|
-
|
|
2258
|
-
await collectVerifyCheck(generalChecks, 'shared_launcher_mcp', async () => {
|
|
2259
|
-
const probe = await probeMcpServer({
|
|
2260
|
-
label: 'Shared MCP launcher',
|
|
2261
|
-
command: process.execPath,
|
|
2262
|
-
args: [assetPaths.mcpLauncherPath],
|
|
2263
|
-
cwd: root,
|
|
2264
|
-
});
|
|
2265
|
-
const toolNames = (probe.tools?.tools ?? []).map((tool) => tool.name);
|
|
2266
|
-
if (!toolNames.includes('start_audit')) {
|
|
2267
|
-
throw new Error('Shared MCP launcher did not expose the start_audit tool.');
|
|
2268
|
-
}
|
|
2269
|
-
return {
|
|
2270
|
-
summary: 'Shared MCP launcher completed an MCP handshake.',
|
|
2271
|
-
server_name: probe.initialize?.serverInfo?.name ?? null,
|
|
2272
|
-
tool_count: toolNames.length,
|
|
2273
|
-
resource_count: (probe.resources?.resources ?? []).length,
|
|
2274
|
-
};
|
|
2275
|
-
});
|
|
2276
|
-
|
|
2277
1460
|
for (const hostKey of selectedHosts) {
|
|
2278
1461
|
const checks = [];
|
|
2279
1462
|
const hostEntry = hostCatalog.get(hostKey);
|
|
@@ -2468,16 +1651,6 @@ async function detectBootstrapRefreshReason(root, host) {
|
|
|
2468
1651
|
}
|
|
2469
1652
|
}
|
|
2470
1653
|
|
|
2471
|
-
const launcherPath =
|
|
2472
|
-
assetPaths.mcpLauncherPath ?? installManifest.mcp_server_launcher_path;
|
|
2473
|
-
const launcher = launcherPath ? await readTextIfExists(launcherPath) : null;
|
|
2474
|
-
if (launcher === null) {
|
|
2475
|
-
return 'missing_mcp_launcher';
|
|
2476
|
-
}
|
|
2477
|
-
if (!launcher.includes('Unable to locate an audit-code executable')) {
|
|
2478
|
-
return 'stale_mcp_launcher';
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
1654
|
return null;
|
|
2482
1655
|
}
|
|
2483
1656
|
|
|
@@ -2501,7 +1674,6 @@ async function ensureBootstrap(argv) {
|
|
|
2501
1674
|
host: installed.host,
|
|
2502
1675
|
repo_root: installed.repo_root,
|
|
2503
1676
|
install_manifest_path: installed.install_manifest_path,
|
|
2504
|
-
mcp_server_launcher_path: installed.mcp_server_launcher_path,
|
|
2505
1677
|
host_count: installed.host_guidance.length,
|
|
2506
1678
|
file_count: installed.files.length,
|
|
2507
1679
|
};
|
|
@@ -2537,13 +1709,11 @@ function buildInstallAssetPaths(root, profile) {
|
|
|
2537
1709
|
const installedSkillPath = join(root, '.audit-code', 'install', 'SKILL.md');
|
|
2538
1710
|
const installGuidePath = join(root, '.audit-code', 'install', INSTALL_GUIDE_FILENAME);
|
|
2539
1711
|
const installManifestPath = join(root, '.audit-code', 'install', INSTALL_MANIFEST_FILENAME);
|
|
2540
|
-
const mcpLauncherPath = join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME);
|
|
2541
1712
|
return {
|
|
2542
1713
|
installedPromptPath,
|
|
2543
1714
|
installedSkillPath,
|
|
2544
1715
|
installGuidePath,
|
|
2545
1716
|
installManifestPath,
|
|
2546
|
-
mcpLauncherPath,
|
|
2547
1717
|
agentsInstructionsPath: profile.writeAgents ? join(root, 'AGENTS.md') : null,
|
|
2548
1718
|
copilotInstructionsPath: profile.writeCopilotInstructions
|
|
2549
1719
|
? join(root, '.github', 'copilot-instructions.md')
|
|
@@ -2554,24 +1724,9 @@ function buildInstallAssetPaths(root, profile) {
|
|
|
2554
1724
|
codexPromptPath: profile.writeCodex
|
|
2555
1725
|
? join(root, '.codex', 'skills', 'audit-code', 'audit-code.prompt.md')
|
|
2556
1726
|
: null,
|
|
2557
|
-
codexMcpSetupPath: profile.writeCodex
|
|
2558
|
-
? join(root, '.audit-code', 'install', 'codex', 'MCP-SETUP.md')
|
|
2559
|
-
: null,
|
|
2560
1727
|
codexAutomationRecipePath: profile.writeCodex
|
|
2561
1728
|
? join(root, '.audit-code', 'install', 'codex', 'RE-AUDIT-AUTOMATION.md')
|
|
2562
1729
|
: null,
|
|
2563
|
-
claudeDesktopProjectTemplatePath: profile.writeClaudeDesktop
|
|
2564
|
-
? join(root, '.audit-code', 'install', 'claude-desktop', 'PROJECT-TEMPLATE.md')
|
|
2565
|
-
: null,
|
|
2566
|
-
claudeDesktopRemoteConnectorPath: profile.writeClaudeDesktop
|
|
2567
|
-
? join(root, '.audit-code', 'install', 'claude-desktop', 'remote-mcp-connector.json')
|
|
2568
|
-
: null,
|
|
2569
|
-
claudeDesktopDxtPath: profile.writeClaudeDesktop
|
|
2570
|
-
? join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.dxt')
|
|
2571
|
-
: null,
|
|
2572
|
-
claudeDesktopMcpbPath: profile.writeClaudeDesktop
|
|
2573
|
-
? join(root, '.audit-code', 'install', 'claude-desktop', 'auditor-lambda.mcpb')
|
|
2574
|
-
: null,
|
|
2575
1730
|
opencodeConfigPath: profile.writeOpenCode
|
|
2576
1731
|
? join(root, 'opencode.json')
|
|
2577
1732
|
: null,
|
|
@@ -2581,9 +1736,6 @@ function buildInstallAssetPaths(root, profile) {
|
|
|
2581
1736
|
vscodeAgentPath: profile.writeVSCode
|
|
2582
1737
|
? join(root, '.github', 'agents', 'auditor.agent.md')
|
|
2583
1738
|
: null,
|
|
2584
|
-
vscodeMcpConfigPath: profile.writeVSCode
|
|
2585
|
-
? join(root, '.vscode', 'mcp.json')
|
|
2586
|
-
: null,
|
|
2587
1739
|
antigravityPlanningGuidePath: profile.writeAntigravity
|
|
2588
1740
|
? join(root, '.audit-code', 'install', 'antigravity', 'PLANNING-MODE.md')
|
|
2589
1741
|
: null,
|
|
@@ -2596,7 +1748,7 @@ function buildInstallAssetPaths(root, profile) {
|
|
|
2596
1748
|
};
|
|
2597
1749
|
}
|
|
2598
1750
|
|
|
2599
|
-
// Always-written core assets (installed prompt + skill,
|
|
1751
|
+
// Always-written core assets (installed prompt + skill,
|
|
2600
1752
|
// AGENTS/copilot compatibility directive blocks) plus legacy-surface cleanup.
|
|
2601
1753
|
async function writeCoreInstallAssets(root, assetPaths, promptSource, skillSource) {
|
|
2602
1754
|
const results = [];
|
|
@@ -2606,9 +1758,6 @@ async function writeCoreInstallAssets(root, assetPaths, promptSource, skillSourc
|
|
|
2606
1758
|
}
|
|
2607
1759
|
results.push(await writeGeneratedMarkdown(assetPaths.installedPromptPath, promptSource));
|
|
2608
1760
|
results.push(await writeGeneratedMarkdown(assetPaths.installedSkillPath, skillSource));
|
|
2609
|
-
results.push(
|
|
2610
|
-
await writeGeneratedMarkdown(assetPaths.mcpLauncherPath, renderSharedMcpLauncher(repoRoot)),
|
|
2611
|
-
);
|
|
2612
1761
|
|
|
2613
1762
|
const compatibilityBlockTargets = [
|
|
2614
1763
|
assetPaths.agentsInstructionsPath,
|
|
@@ -2629,37 +1778,14 @@ async function writeCoreInstallAssets(root, assetPaths, promptSource, skillSourc
|
|
|
2629
1778
|
return results;
|
|
2630
1779
|
}
|
|
2631
1780
|
|
|
2632
|
-
async function writeCodexAssets(assetPaths, promptSource, skillSource
|
|
1781
|
+
async function writeCodexAssets(assetPaths, promptSource, skillSource) {
|
|
2633
1782
|
return [
|
|
2634
1783
|
await writeGeneratedMarkdown(assetPaths.codexSkillPath, skillSource),
|
|
2635
1784
|
await writeGeneratedMarkdown(assetPaths.codexPromptPath, promptSource),
|
|
2636
|
-
await writeGeneratedMarkdown(assetPaths.codexMcpSetupPath, renderCodexMcpSetupGuide(root)),
|
|
2637
1785
|
await writeGeneratedMarkdown(assetPaths.codexAutomationRecipePath, renderCodexAutomationRecipe()),
|
|
2638
1786
|
];
|
|
2639
1787
|
}
|
|
2640
1788
|
|
|
2641
|
-
// Builds the Claude Desktop DXT/MCPB bundle (mutating assetPaths with the
|
|
2642
|
-
// produced bundle paths) and writes the project template + remote connector.
|
|
2643
|
-
async function writeClaudeDesktopAssets(assetPaths, root) {
|
|
2644
|
-
const results = [];
|
|
2645
|
-
const claudeDesktopBundle = await buildClaudeDesktopBundle(root, results);
|
|
2646
|
-
assetPaths.claudeDesktopDxtPath = claudeDesktopBundle.dxtPath;
|
|
2647
|
-
assetPaths.claudeDesktopMcpbPath = claudeDesktopBundle.mcpbPath;
|
|
2648
|
-
results.push(
|
|
2649
|
-
await writeGeneratedMarkdown(
|
|
2650
|
-
assetPaths.claudeDesktopProjectTemplatePath,
|
|
2651
|
-
renderClaudeDesktopProjectTemplate(),
|
|
2652
|
-
),
|
|
2653
|
-
);
|
|
2654
|
-
results.push(
|
|
2655
|
-
await writeGeneratedJson(
|
|
2656
|
-
assetPaths.claudeDesktopRemoteConnectorPath,
|
|
2657
|
-
JSON.parse(renderClaudeDesktopRemoteConnectorTemplate()),
|
|
2658
|
-
),
|
|
2659
|
-
);
|
|
2660
|
-
return results;
|
|
2661
|
-
}
|
|
2662
|
-
|
|
2663
1789
|
async function writeOpenCodeAssets(assetPaths, root) {
|
|
2664
1790
|
return [
|
|
2665
1791
|
await writeMergedGeneratedJson(
|
|
@@ -2684,11 +1810,6 @@ async function writeVSCodeAssets(assetPaths, promptBody) {
|
|
|
2684
1810
|
),
|
|
2685
1811
|
),
|
|
2686
1812
|
await writeGeneratedMarkdown(assetPaths.vscodeAgentPath, renderVSCodeAgentFile()),
|
|
2687
|
-
await writeMergedGeneratedJson(
|
|
2688
|
-
assetPaths.vscodeMcpConfigPath,
|
|
2689
|
-
'VS Code MCP config',
|
|
2690
|
-
buildMergedVSCodeMcpConfig,
|
|
2691
|
-
),
|
|
2692
1813
|
];
|
|
2693
1814
|
}
|
|
2694
1815
|
|
|
@@ -2717,17 +1838,13 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2717
1838
|
installedSkillPath,
|
|
2718
1839
|
installGuidePath,
|
|
2719
1840
|
installManifestPath,
|
|
2720
|
-
mcpLauncherPath,
|
|
2721
1841
|
} = assetPaths;
|
|
2722
1842
|
|
|
2723
1843
|
const results = [];
|
|
2724
1844
|
results.push(...await writeCoreInstallAssets(root, assetPaths, promptSource, skillSource));
|
|
2725
1845
|
|
|
2726
1846
|
if (profile.writeCodex) {
|
|
2727
|
-
results.push(...await writeCodexAssets(assetPaths, promptSource, skillSource
|
|
2728
|
-
}
|
|
2729
|
-
if (profile.writeClaudeDesktop) {
|
|
2730
|
-
results.push(...await writeClaudeDesktopAssets(assetPaths, root));
|
|
1847
|
+
results.push(...await writeCodexAssets(assetPaths, promptSource, skillSource));
|
|
2731
1848
|
}
|
|
2732
1849
|
if (profile.writeOpenCode) {
|
|
2733
1850
|
results.push(...await writeOpenCodeAssets(assetPaths, root));
|
|
@@ -2753,7 +1870,6 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2753
1870
|
installed_skill_path: installedSkillPath,
|
|
2754
1871
|
install_guide_path: installGuidePath,
|
|
2755
1872
|
install_manifest_path: installManifestPath,
|
|
2756
|
-
mcp_server_launcher_path: mcpLauncherPath,
|
|
2757
1873
|
source_prompt_path: resolve(promptAssetPath),
|
|
2758
1874
|
source_skill_path: resolve(skillAssetPath),
|
|
2759
1875
|
asset_paths: assetPaths,
|
|
@@ -2769,7 +1885,6 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2769
1885
|
installedPromptPath,
|
|
2770
1886
|
installedSkillPath,
|
|
2771
1887
|
installManifestPath,
|
|
2772
|
-
mcpLauncherPath,
|
|
2773
1888
|
hostGuidance,
|
|
2774
1889
|
}),
|
|
2775
1890
|
),
|
|
@@ -2791,7 +1906,6 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2791
1906
|
installed_skill_path: installedSkillPath,
|
|
2792
1907
|
install_guide_path: installGuidePath,
|
|
2793
1908
|
install_manifest_path: installManifestPath,
|
|
2794
|
-
mcp_server_launcher_path: mcpLauncherPath,
|
|
2795
1909
|
source_prompt_path: resolve(promptAssetPath),
|
|
2796
1910
|
source_skill_path: resolve(skillAssetPath),
|
|
2797
1911
|
files: results,
|
|
@@ -2805,22 +1919,12 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2805
1919
|
agents: assetPaths.agentsInstructionsPath,
|
|
2806
1920
|
copilot_instructions: assetPaths.copilotInstructionsPath,
|
|
2807
1921
|
},
|
|
2808
|
-
mcp_surfaces: {
|
|
2809
|
-
vscode_workspace: assetPaths.vscodeMcpConfigPath,
|
|
2810
|
-
opencode_project: assetPaths.opencodeConfigPath,
|
|
2811
|
-
codex_setup: assetPaths.codexMcpSetupPath,
|
|
2812
|
-
shared_launcher: mcpLauncherPath,
|
|
2813
|
-
claude_desktop_dxt: assetPaths.claudeDesktopDxtPath,
|
|
2814
|
-
claude_desktop_mcpb: assetPaths.claudeDesktopMcpbPath,
|
|
2815
|
-
antigravity_planning_guide: assetPaths.antigravityPlanningGuidePath,
|
|
2816
|
-
},
|
|
2817
1922
|
host_guidance: hostGuidance,
|
|
2818
1923
|
unsupported_hosts: [],
|
|
2819
1924
|
next_steps: [
|
|
2820
1925
|
'Open the repository in your preferred host and follow the matching host_guidance entry.',
|
|
2821
|
-
`Open ${installGuidePath} for repo-local quick-start steps for Codex,
|
|
2822
|
-
'Run `audit-code verify-install` from the repository root to smoke-test the generated
|
|
2823
|
-
'Use the shared MCP launcher as the source of truth for local stdio MCP registration across hosts.',
|
|
1926
|
+
`Open ${installGuidePath} for repo-local quick-start steps for Codex, OpenCode, VS Code, and Antigravity.`,
|
|
1927
|
+
'Run `audit-code verify-install` from the repository root to smoke-test the generated host configs.',
|
|
2824
1928
|
],
|
|
2825
1929
|
};
|
|
2826
1930
|
|