auditor-lambda 0.3.19 → 0.3.21
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 +15 -4
- package/audit-code-wrapper-lib.mjs +248 -56
- package/dist/cli.js +578 -12
- package/dist/io/runArtifacts.js +48 -0
- package/dist/prompts/renderWorkerPrompt.js +1 -0
- package/dist/supervisor/operatorHandoff.js +10 -7
- package/docs/contracts.md +23 -1
- package/docs/operator-guide.md +14 -5
- package/docs/product.md +4 -3
- package/package.json +1 -1
- package/scripts/postinstall.mjs +174 -1
- package/skills/audit-code/SKILL.md +5 -0
- package/skills/audit-code/agents/openai.yaml +4 -0
- package/skills/audit-code/audit-code.prompt.md +15 -135
package/README.md
CHANGED
|
@@ -30,8 +30,9 @@ 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, the global Codex skill bundle
|
|
34
|
-
slash command entry in
|
|
33
|
+
the Claude command file, the global Codex skill bundle with `audit-code` display
|
|
34
|
+
metadata, and the global OpenCode slash command entry in
|
|
35
|
+
`~/.config/opencode/opencode.json`.
|
|
35
36
|
|
|
36
37
|
After that, invoke `/audit-code` in a supported host. The prompt self-bootstraps
|
|
37
38
|
the current repository by running:
|
|
@@ -50,11 +51,11 @@ The explicit repair and compatibility setup path remains:
|
|
|
50
51
|
audit-code install
|
|
51
52
|
```
|
|
52
53
|
|
|
53
|
-
That bootstraps repo-local
|
|
54
|
+
That bootstraps repo-local supporting surfaces for the hosts we can automate today, including:
|
|
54
55
|
|
|
55
56
|
- Codex `AGENTS.md` fallback guidance for the global skill surface
|
|
56
57
|
- Claude Desktop local MCP bundle artifacts and project template guidance
|
|
57
|
-
- OpenCode `opencode.json` with the `/audit-code`
|
|
58
|
+
- OpenCode `opencode.json` with auditor MCP server and permission wiring; the `/audit-code` command stays in the global npm-installed OpenCode config
|
|
58
59
|
- VS Code prompt, custom agent, Copilot instructions, and `.vscode/mcp.json`
|
|
59
60
|
- Antigravity planning-mode guidance plus the shared repo-local MCP launcher
|
|
60
61
|
|
|
@@ -129,6 +130,16 @@ For one bounded debug step instead of run-to-completion:
|
|
|
129
130
|
audit-code --single-step
|
|
130
131
|
```
|
|
131
132
|
|
|
133
|
+
For the conversation step engine used by `/audit-code`:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
audit-code next-step
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
This writes `.audit-artifacts/steps/current-step.json` and
|
|
140
|
+
`.audit-artifacts/steps/current-prompt.md`; hosts should follow only the
|
|
141
|
+
returned step prompt.
|
|
142
|
+
|
|
132
143
|
For an operator-side artifact consistency check:
|
|
133
144
|
|
|
134
145
|
```bash
|
|
@@ -258,6 +258,7 @@ function printHelp({ usageName, preferredEntrypoint }) {
|
|
|
258
258
|
'- verify-install smoke-tests the generated host assets and repo-local MCP launchers after install',
|
|
259
259
|
'- mcp starts the local stdio MCP server for repo-local IDE integrations',
|
|
260
260
|
'- install-host --host copilot keeps the narrower Copilot-focused install path available',
|
|
261
|
+
'- next-step advances deterministic audit state and writes .audit-artifacts/steps/current-step.json plus current-prompt.md',
|
|
261
262
|
'- validate checks the current artifact bundle plus session-config/provider readiness and exits non-zero when issues exist',
|
|
262
263
|
'- validate-results --results FILE validates AuditResult payloads against the active task manifest without ingesting them',
|
|
263
264
|
'- explain-task <task_id> prints the resolved file coverage and current status for a task id',
|
|
@@ -533,18 +534,82 @@ function renderCodexAutomationRecipe() {
|
|
|
533
534
|
].join('\n');
|
|
534
535
|
}
|
|
535
536
|
|
|
536
|
-
|
|
537
|
+
const OPENCODE_AUDIT_EDIT_PERMISSION = {
|
|
538
|
+
'*': 'ask',
|
|
539
|
+
'.audit-code/**': 'allow',
|
|
540
|
+
'.audit-artifacts/**': 'allow',
|
|
541
|
+
'audit-report.md': 'allow',
|
|
542
|
+
};
|
|
543
|
+
|
|
544
|
+
const OPENCODE_AUDIT_BASH_PERMISSION = {
|
|
545
|
+
'*': 'ask',
|
|
546
|
+
'audit-code run-to-completion*': 'deny',
|
|
547
|
+
'audit-code synthesize*': 'deny',
|
|
548
|
+
'audit-code cleanup*': 'deny',
|
|
549
|
+
'audit-code requeue*': 'deny',
|
|
550
|
+
'audit-code ingest-results*': 'deny',
|
|
551
|
+
'*dist*index.js* run-to-completion*': 'deny',
|
|
552
|
+
'*dist*index.js* synthesize*': 'deny',
|
|
553
|
+
'*dist*index.js* cleanup*': 'deny',
|
|
554
|
+
'*dist*index.js* requeue*': 'deny',
|
|
555
|
+
'*dist*index.js* ingest-results*': 'deny',
|
|
556
|
+
'*audit-code.mjs* run-to-completion*': 'deny',
|
|
557
|
+
'*audit-code.mjs* synthesize*': 'deny',
|
|
558
|
+
'*audit-code.mjs* cleanup*': 'deny',
|
|
559
|
+
'*audit-code.mjs* requeue*': 'deny',
|
|
560
|
+
'*audit-code.mjs* ingest-results*': 'deny',
|
|
561
|
+
'audit-code': 'allow',
|
|
562
|
+
'audit-code ensure*': 'allow',
|
|
563
|
+
'audit-code next-step*': 'allow',
|
|
564
|
+
'audit-code prepare-dispatch*': 'allow',
|
|
565
|
+
'audit-code submit-packet*': 'allow',
|
|
566
|
+
'audit-code merge-and-ingest*': 'allow',
|
|
567
|
+
'audit-code validate*': 'allow',
|
|
568
|
+
'*audit-code.mjs': 'allow',
|
|
569
|
+
'*audit-code.mjs* ensure*': 'allow',
|
|
570
|
+
'*audit-code.mjs* next-step*': 'allow',
|
|
571
|
+
'*audit-code.mjs* prepare-dispatch*': 'allow',
|
|
572
|
+
'*audit-code.mjs* submit-packet*': 'allow',
|
|
573
|
+
'*audit-code.mjs* merge-and-ingest*': 'allow',
|
|
574
|
+
'*audit-code.mjs* worker-run*': 'allow',
|
|
575
|
+
'*audit-code.mjs* validate*': 'allow',
|
|
576
|
+
'*node* *auditor-lambda*dist*index.js* worker-run*': 'allow',
|
|
577
|
+
'node* .audit-code/install/run-mcp-server.mjs*': 'allow',
|
|
578
|
+
'node* ./.audit-code/install/run-mcp-server.mjs*': 'allow',
|
|
579
|
+
'git status*': 'allow',
|
|
580
|
+
'git diff*': 'allow',
|
|
581
|
+
'grep *': 'allow',
|
|
582
|
+
'Select-String *': 'allow',
|
|
583
|
+
'rm *': 'deny',
|
|
584
|
+
};
|
|
585
|
+
|
|
586
|
+
function externalDirectoryPattern(path) {
|
|
587
|
+
return `${replaceBackslashes(path).replace(/\/+$/u, '')}/**`;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
function renderOpenCodeExternalDirectoryPermission() {
|
|
591
|
+
return {
|
|
592
|
+
[externalDirectoryPattern(repoRoot)]: 'allow',
|
|
593
|
+
[externalDirectoryPattern(dirname(process.execPath))]: 'allow',
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
function renderOpenCodePermissionConfig() {
|
|
598
|
+
return {
|
|
599
|
+
read: 'allow',
|
|
600
|
+
glob: 'allow',
|
|
601
|
+
grep: 'allow',
|
|
602
|
+
external_directory: renderOpenCodeExternalDirectoryPermission(),
|
|
603
|
+
edit: { ...OPENCODE_AUDIT_EDIT_PERMISSION },
|
|
604
|
+
bash: { ...OPENCODE_AUDIT_BASH_PERMISSION },
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function renderOpenCodeProjectConfig(root) {
|
|
537
609
|
const launcher = replaceBackslashes(toRepoRelativePath(root, join(root, '.audit-code', 'install', MCP_LAUNCHER_FILENAME)));
|
|
610
|
+
const auditPermission = renderOpenCodePermissionConfig();
|
|
538
611
|
return {
|
|
539
612
|
$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
|
-
},
|
|
548
613
|
mcp: {
|
|
549
614
|
auditor: {
|
|
550
615
|
type: 'local',
|
|
@@ -553,19 +618,7 @@ function renderOpenCodeProjectConfig(root, promptBody) {
|
|
|
553
618
|
timeout: 10000,
|
|
554
619
|
},
|
|
555
620
|
},
|
|
556
|
-
permission:
|
|
557
|
-
read: 'allow',
|
|
558
|
-
glob: 'allow',
|
|
559
|
-
grep: 'allow',
|
|
560
|
-
edit: 'ask',
|
|
561
|
-
bash: {
|
|
562
|
-
'*': 'ask',
|
|
563
|
-
'git status*': 'allow',
|
|
564
|
-
'git diff*': 'allow',
|
|
565
|
-
'grep *': 'allow',
|
|
566
|
-
'rm *': 'deny',
|
|
567
|
-
},
|
|
568
|
-
},
|
|
621
|
+
permission: auditPermission,
|
|
569
622
|
agent: {
|
|
570
623
|
auditor: {
|
|
571
624
|
description:
|
|
@@ -574,14 +627,7 @@ function renderOpenCodeProjectConfig(root, promptBody) {
|
|
|
574
627
|
'auditor*': true,
|
|
575
628
|
},
|
|
576
629
|
permission: {
|
|
577
|
-
|
|
578
|
-
bash: {
|
|
579
|
-
'*': 'ask',
|
|
580
|
-
'git status*': 'allow',
|
|
581
|
-
'git diff*': 'allow',
|
|
582
|
-
'grep *': 'allow',
|
|
583
|
-
'rm *': 'deny',
|
|
584
|
-
},
|
|
630
|
+
...auditPermission,
|
|
585
631
|
question: 'allow',
|
|
586
632
|
},
|
|
587
633
|
},
|
|
@@ -607,26 +653,164 @@ function objectValue(value) {
|
|
|
607
653
|
: {};
|
|
608
654
|
}
|
|
609
655
|
|
|
610
|
-
function
|
|
611
|
-
|
|
656
|
+
function mergeOpenCodePermissionRule(existingRule, generatedRule, managedRules = {}) {
|
|
657
|
+
if (generatedRule && typeof generatedRule === 'object' && !Array.isArray(generatedRule)) {
|
|
658
|
+
const generatedObject = generatedRule;
|
|
659
|
+
const merged = {};
|
|
660
|
+
const existingObject =
|
|
661
|
+
existingRule && typeof existingRule === 'object' && !Array.isArray(existingRule)
|
|
662
|
+
? existingRule
|
|
663
|
+
: {};
|
|
664
|
+
|
|
665
|
+
if (typeof existingRule === 'string') {
|
|
666
|
+
merged['*'] = existingRule;
|
|
667
|
+
} else {
|
|
668
|
+
merged['*'] = existingObject['*'] ?? generatedObject['*'] ?? 'ask';
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
for (const [key, value] of Object.entries(generatedObject)) {
|
|
672
|
+
if (key !== '*') merged[key] = value;
|
|
673
|
+
}
|
|
674
|
+
for (const [key, value] of Object.entries(existingObject)) {
|
|
675
|
+
if (key !== '*') merged[key] = value;
|
|
676
|
+
}
|
|
677
|
+
for (const [key, value] of Object.entries(managedRules)) {
|
|
678
|
+
merged[key] = value;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
return merged;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return existingRule ?? generatedRule;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function mergeOpenCodePermissionConfig(existingPermission, generatedPermission) {
|
|
688
|
+
if (!existingPermission || typeof existingPermission !== 'object' || Array.isArray(existingPermission)) {
|
|
689
|
+
return generatedPermission;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
return {
|
|
693
|
+
...generatedPermission,
|
|
694
|
+
...existingPermission,
|
|
695
|
+
read: generatedPermission.read,
|
|
696
|
+
glob: generatedPermission.glob,
|
|
697
|
+
grep: generatedPermission.grep,
|
|
698
|
+
external_directory: mergeOpenCodePermissionRule(
|
|
699
|
+
existingPermission.external_directory,
|
|
700
|
+
generatedPermission.external_directory,
|
|
701
|
+
generatedPermission.external_directory,
|
|
702
|
+
),
|
|
703
|
+
edit: mergeOpenCodePermissionRule(
|
|
704
|
+
existingPermission.edit,
|
|
705
|
+
generatedPermission.edit,
|
|
706
|
+
OPENCODE_AUDIT_EDIT_PERMISSION,
|
|
707
|
+
),
|
|
708
|
+
bash: mergeOpenCodePermissionRule(
|
|
709
|
+
existingPermission.bash,
|
|
710
|
+
generatedPermission.bash,
|
|
711
|
+
OPENCODE_AUDIT_BASH_PERMISSION,
|
|
712
|
+
),
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function removeManagedOpenCodeCommand(commandConfig) {
|
|
717
|
+
const command = objectValue(commandConfig);
|
|
718
|
+
const { 'audit-code': _managedAuditCodeCommand, ...remaining } = command;
|
|
719
|
+
return remaining;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function assertOpenCodeAuditPermissionConfig(permissionConfig, label) {
|
|
723
|
+
for (const tool of ['read', 'glob', 'grep']) {
|
|
724
|
+
if (permissionConfig?.[tool] !== 'allow') {
|
|
725
|
+
throw new Error(`OpenCode ${label}.${tool} must be allow. Run "audit-code install --host opencode".`);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
const externalDirectory = permissionConfig?.external_directory;
|
|
729
|
+
if (!externalDirectory || typeof externalDirectory !== 'object' || Array.isArray(externalDirectory)) {
|
|
730
|
+
throw new Error(`OpenCode ${label}.external_directory must allow audit package paths. Run "audit-code install --host opencode".`);
|
|
731
|
+
}
|
|
732
|
+
for (const pattern of Object.keys(renderOpenCodeExternalDirectoryPermission())) {
|
|
733
|
+
if (externalDirectory[pattern] !== 'allow') {
|
|
734
|
+
throw new Error(`OpenCode ${label}.external_directory must allow ${pattern}. Run "audit-code install --host opencode".`);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
const edit = permissionConfig?.edit;
|
|
738
|
+
const bash = permissionConfig?.bash;
|
|
739
|
+
if (!edit || typeof edit !== 'object' || Array.isArray(edit)) {
|
|
740
|
+
throw new Error(`OpenCode ${label}.edit must allow audit-owned file paths. Run "audit-code install --host opencode".`);
|
|
741
|
+
}
|
|
742
|
+
for (const pattern of ['.audit-code/**', '.audit-artifacts/**', 'audit-report.md']) {
|
|
743
|
+
if (edit[pattern] !== 'allow') {
|
|
744
|
+
throw new Error(`OpenCode ${label}.edit must allow ${pattern}. Run "audit-code install --host opencode".`);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
if (!bash || typeof bash !== 'object' || Array.isArray(bash)) {
|
|
748
|
+
throw new Error(`OpenCode ${label}.bash must allow audit-code commands. Run "audit-code install --host opencode".`);
|
|
749
|
+
}
|
|
750
|
+
for (const pattern of [
|
|
751
|
+
'audit-code',
|
|
752
|
+
'audit-code ensure*',
|
|
753
|
+
'audit-code next-step*',
|
|
754
|
+
'audit-code prepare-dispatch*',
|
|
755
|
+
'audit-code submit-packet*',
|
|
756
|
+
'audit-code merge-and-ingest*',
|
|
757
|
+
'*audit-code.mjs',
|
|
758
|
+
'*audit-code.mjs* next-step*',
|
|
759
|
+
'*audit-code.mjs* submit-packet*',
|
|
760
|
+
'*audit-code.mjs* merge-and-ingest*',
|
|
761
|
+
'*audit-code.mjs* worker-run*',
|
|
762
|
+
'*node* *auditor-lambda*dist*index.js* worker-run*',
|
|
763
|
+
'node* .audit-code/install/run-mcp-server.mjs*',
|
|
764
|
+
'Select-String *',
|
|
765
|
+
]) {
|
|
766
|
+
if (bash[pattern] !== 'allow') {
|
|
767
|
+
throw new Error(`OpenCode ${label}.bash must allow ${pattern}. Run "audit-code install --host opencode".`);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
for (const pattern of [
|
|
771
|
+
'audit-code run-to-completion*',
|
|
772
|
+
'audit-code synthesize*',
|
|
773
|
+
'audit-code cleanup*',
|
|
774
|
+
'audit-code requeue*',
|
|
775
|
+
'audit-code ingest-results*',
|
|
776
|
+
'*dist*index.js* run-to-completion*',
|
|
777
|
+
'*dist*index.js* synthesize*',
|
|
778
|
+
'*dist*index.js* cleanup*',
|
|
779
|
+
'*dist*index.js* requeue*',
|
|
780
|
+
'*dist*index.js* ingest-results*',
|
|
781
|
+
'*audit-code.mjs* run-to-completion*',
|
|
782
|
+
'*audit-code.mjs* synthesize*',
|
|
783
|
+
'*audit-code.mjs* cleanup*',
|
|
784
|
+
'*audit-code.mjs* requeue*',
|
|
785
|
+
'*audit-code.mjs* ingest-results*',
|
|
786
|
+
]) {
|
|
787
|
+
if (bash[pattern] !== 'deny') {
|
|
788
|
+
throw new Error(`OpenCode ${label}.bash must deny ${pattern}. Run "audit-code install --host opencode".`);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
function buildMergedOpenCodeProjectConfig(existing, root) {
|
|
794
|
+
const generated = renderOpenCodeProjectConfig(root);
|
|
612
795
|
return {
|
|
613
796
|
...existing,
|
|
614
797
|
$schema: existing.$schema ?? generated.$schema,
|
|
615
|
-
command:
|
|
616
|
-
...objectValue(existing.command),
|
|
617
|
-
'audit-code': generated.command['audit-code'],
|
|
618
|
-
},
|
|
798
|
+
command: removeManagedOpenCodeCommand(existing.command),
|
|
619
799
|
mcp: {
|
|
620
800
|
...objectValue(existing.mcp),
|
|
621
801
|
auditor: generated.mcp.auditor,
|
|
622
802
|
},
|
|
623
|
-
permission:
|
|
624
|
-
existing.permission && typeof existing.permission === 'object' && !Array.isArray(existing.permission)
|
|
625
|
-
? existing.permission
|
|
626
|
-
: generated.permission,
|
|
803
|
+
permission: mergeOpenCodePermissionConfig(existing.permission, generated.permission),
|
|
627
804
|
agent: {
|
|
628
805
|
...objectValue(existing.agent),
|
|
629
|
-
auditor:
|
|
806
|
+
auditor: {
|
|
807
|
+
...objectValue(objectValue(existing.agent).auditor),
|
|
808
|
+
...generated.agent.auditor,
|
|
809
|
+
permission: mergeOpenCodePermissionConfig(
|
|
810
|
+
objectValue(objectValue(existing.agent).auditor).permission,
|
|
811
|
+
generated.agent.auditor.permission,
|
|
812
|
+
),
|
|
813
|
+
},
|
|
630
814
|
},
|
|
631
815
|
};
|
|
632
816
|
}
|
|
@@ -1094,9 +1278,9 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1094
1278
|
host: 'opencode',
|
|
1095
1279
|
label: 'OpenCode',
|
|
1096
1280
|
support_level: 'supported',
|
|
1097
|
-
setup_kind: 'command+
|
|
1281
|
+
setup_kind: 'global-command+project-mcp',
|
|
1098
1282
|
summary:
|
|
1099
|
-
'Use the
|
|
1283
|
+
'Use the global OpenCode `/audit-code` command installed by npm plus generated project MCP and permission wiring.',
|
|
1100
1284
|
primary_path_key: 'opencodeConfigPath',
|
|
1101
1285
|
supporting_path_keys: [
|
|
1102
1286
|
'agentsInstructionsPath',
|
|
@@ -1104,8 +1288,8 @@ const INSTALL_HOST_DEFINITIONS = {
|
|
|
1104
1288
|
],
|
|
1105
1289
|
steps: [
|
|
1106
1290
|
'Open this repository in OpenCode.',
|
|
1107
|
-
'
|
|
1108
|
-
'
|
|
1291
|
+
'Use the global `/audit-code` command installed by `npm install -g auditor-lambda`.',
|
|
1292
|
+
'Let OpenCode load the generated `opencode.json` for the auditor MCP server and project permissions only.',
|
|
1109
1293
|
],
|
|
1110
1294
|
profile: {
|
|
1111
1295
|
writeOpenCode: true,
|
|
@@ -1814,16 +1998,13 @@ async function verifyInstalledBootstrap(argv) {
|
|
|
1814
1998
|
if (config?.mcp?.auditor?.type !== 'local') {
|
|
1815
1999
|
throw new Error(`OpenCode config must set mcp.auditor.type to "local", got ${config?.mcp?.auditor?.type ?? 'missing'}.`);
|
|
1816
2000
|
}
|
|
1817
|
-
|
|
1818
|
-
|
|
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".');
|
|
2001
|
+
if (config?.command?.['audit-code']) {
|
|
2002
|
+
throw new Error('OpenCode project config must not define command["audit-code"]; the slash command is global npm-installed state. Run "audit-code install --host opencode" to remove the stale local command.');
|
|
1824
2003
|
}
|
|
2004
|
+
assertOpenCodeAuditPermissionConfig(config?.permission, 'permission');
|
|
2005
|
+
assertOpenCodeAuditPermissionConfig(config?.agent?.auditor?.permission, 'agent.auditor.permission');
|
|
1825
2006
|
return {
|
|
1826
|
-
summary: 'OpenCode project config has MCP server and /audit-code
|
|
2007
|
+
summary: 'OpenCode project config has MCP server and audit permissions; /audit-code is supplied by the global npm-installed OpenCode command.',
|
|
1827
2008
|
path: assetPaths.opencodeConfigPath,
|
|
1828
2009
|
};
|
|
1829
2010
|
});
|
|
@@ -1998,8 +2179,14 @@ async function detectBootstrapRefreshReason(root, host) {
|
|
|
1998
2179
|
}
|
|
1999
2180
|
case 'opencode': {
|
|
2000
2181
|
const opencodeConfig = await readJson(assetPaths.opencodeConfigPath, 'OpenCode config').catch(() => null);
|
|
2001
|
-
if (opencodeConfig?.command?.['audit-code']
|
|
2002
|
-
return 'stale_host_asset:opencode:
|
|
2182
|
+
if (opencodeConfig?.command?.['audit-code']) {
|
|
2183
|
+
return 'stale_host_asset:opencode:local_command';
|
|
2184
|
+
}
|
|
2185
|
+
try {
|
|
2186
|
+
assertOpenCodeAuditPermissionConfig(opencodeConfig?.permission, 'permission');
|
|
2187
|
+
assertOpenCodeAuditPermissionConfig(opencodeConfig?.agent?.auditor?.permission, 'agent.auditor.permission');
|
|
2188
|
+
} catch {
|
|
2189
|
+
return 'stale_host_asset:opencode:permissions';
|
|
2003
2190
|
}
|
|
2004
2191
|
if (await fileExists(join(root, '.opencode', 'commands', 'audit-code.md'))) {
|
|
2005
2192
|
return 'stale_host_asset:opencode:legacy_command_file';
|
|
@@ -2260,7 +2447,7 @@ async function installBootstrap(argv, options = {}) {
|
|
|
2260
2447
|
await writeMergedGeneratedJson(
|
|
2261
2448
|
assetPaths.opencodeConfigPath,
|
|
2262
2449
|
'OpenCode project config',
|
|
2263
|
-
(existing) => buildMergedOpenCodeProjectConfig(existing, root
|
|
2450
|
+
(existing) => buildMergedOpenCodeProjectConfig(existing, root),
|
|
2264
2451
|
),
|
|
2265
2452
|
);
|
|
2266
2453
|
}
|
|
@@ -2483,6 +2670,11 @@ export async function runAuditCodeWrapper({
|
|
|
2483
2670
|
return;
|
|
2484
2671
|
}
|
|
2485
2672
|
|
|
2673
|
+
if (argv[0] === 'next-step') {
|
|
2674
|
+
await runDistCommand('next-step', argv.slice(1), { ensureArtifactsDir: true });
|
|
2675
|
+
return;
|
|
2676
|
+
}
|
|
2677
|
+
|
|
2486
2678
|
if (argv[0] === 'prepare-dispatch') {
|
|
2487
2679
|
await runDistCommand('prepare-dispatch', argv.slice(1));
|
|
2488
2680
|
return;
|