@osovv/vv-opencode 0.1.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/AGENTS.md +164 -0
- package/README.md +43 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +23 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +19 -0
- package/dist/commands/doctor.js +70 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/guardian.d.ts +2 -0
- package/dist/commands/guardian.js +119 -0
- package/dist/commands/guardian.js.map +1 -0
- package/dist/commands/install.d.ts +28 -0
- package/dist/commands/install.js +59 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/status.d.ts +13 -0
- package/dist/commands/status.js +47 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/sync.d.ts +23 -0
- package/dist/commands/sync.js +49 -0
- package/dist/commands/sync.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/opencode.d.ts +86 -0
- package/dist/lib/opencode.js +415 -0
- package/dist/lib/opencode.js.map +1 -0
- package/dist/lib/opencode.test.d.ts +1 -0
- package/dist/lib/opencode.test.js +47 -0
- package/dist/lib/opencode.test.js.map +1 -0
- package/dist/plugins/guardian.d.ts +2 -0
- package/dist/plugins/guardian.js +1135 -0
- package/dist/plugins/guardian.js.map +1 -0
- package/docs/development-plan.xml +155 -0
- package/docs/knowledge-graph.xml +42 -0
- package/docs/operational-packets.xml +106 -0
- package/docs/requirements.xml +66 -0
- package/docs/technology.xml +51 -0
- package/docs/verification-plan.xml +145 -0
- package/package.json +58 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { defineCommand } from "citty";
|
|
2
|
+
import { describeWriteResult, ensurePackageInstalled, resolvePaths, syncGuardianConfig, syncLocalPlugin, } from "../lib/opencode.js";
|
|
3
|
+
export default defineCommand({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "sync",
|
|
6
|
+
description: "Sync managed vv-opencode config files.",
|
|
7
|
+
},
|
|
8
|
+
args: {
|
|
9
|
+
scope: {
|
|
10
|
+
type: "enum",
|
|
11
|
+
options: ["global", "project"],
|
|
12
|
+
default: "global",
|
|
13
|
+
description: "Sync global or project config.",
|
|
14
|
+
},
|
|
15
|
+
source: {
|
|
16
|
+
type: "enum",
|
|
17
|
+
options: ["local", "npm"],
|
|
18
|
+
default: "local",
|
|
19
|
+
description: "Sync a local plugin shim or npm package reference.",
|
|
20
|
+
},
|
|
21
|
+
"config-dir": {
|
|
22
|
+
type: "string",
|
|
23
|
+
description: "Override the global OpenCode config directory.",
|
|
24
|
+
},
|
|
25
|
+
force: {
|
|
26
|
+
type: "boolean",
|
|
27
|
+
description: "Allow rewriting unmanaged guardian config files.",
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
async run({ args }) {
|
|
31
|
+
const scope = args.scope === "project" ? "project" : "global";
|
|
32
|
+
const configDir = typeof args["config-dir"] === "string" ? args["config-dir"] : undefined;
|
|
33
|
+
const paths = await resolvePaths({
|
|
34
|
+
scope: scope,
|
|
35
|
+
cwd: process.cwd(),
|
|
36
|
+
configDir,
|
|
37
|
+
});
|
|
38
|
+
const pluginResult = args.source === "npm"
|
|
39
|
+
? (() => ensurePackageInstalled(paths).then((opencode) => ({
|
|
40
|
+
action: opencode.changed ? "updated" : "kept",
|
|
41
|
+
path: opencode.path,
|
|
42
|
+
})))()
|
|
43
|
+
: syncLocalPlugin(paths, { force: Boolean(args.force) });
|
|
44
|
+
const guardian = await syncGuardianConfig(paths, { force: Boolean(args.force) });
|
|
45
|
+
console.log(describeWriteResult(await pluginResult));
|
|
46
|
+
console.log(describeWriteResult(guardian));
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
//# sourceMappingURL=sync.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AACtC,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,YAAY,EACZ,kBAAkB,EAClB,eAAe,GAEhB,MAAM,oBAAoB,CAAC;AAE5B,eAAe,aAAa,CAAC;IAC3B,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,wCAAwC;KACtD;IACD,IAAI,EAAE;QACJ,KAAK,EAAE;YACL,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,QAAQ,EAAE,SAAS,CAAC;YAC9B,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,gCAAgC;SAC9C;QACD,MAAM,EAAE;YACN,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC;YACzB,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,oDAAoD;SAClE;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,gDAAgD;SAC9D;QACD,KAAK,EAAE;YACL,IAAI,EAAE,SAAS;YACf,WAAW,EAAE,kDAAkD;SAChE;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC9D,MAAM,SAAS,GAAG,OAAO,IAAI,CAAC,YAAY,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;QAC1F,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC;YAC/B,KAAK,EAAE,KAAc;YACrB,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE;YAClB,SAAS;SACV,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,KAAK,KAAK;YACxC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,sBAAsB,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;gBACzD,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM;gBAC7C,IAAI,EAAE,QAAQ,CAAC,IAAI;aACV,CAAA,CAAC,CAAC,EAAE;YACf,CAAC,CAAC,eAAe,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAC3D,MAAM,QAAQ,GAAG,MAAM,kBAAkB,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QAEjF,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,MAAM,YAAY,CAAC,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC7C,CAAC;CACF,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { GuardianPlugin } from "./plugins/guardian.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
export declare const CLI_NAME = "vvoc";
|
|
2
|
+
export declare const PACKAGE_NAME = "@osovv/vv-opencode";
|
|
3
|
+
export declare const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
|
|
4
|
+
export type Scope = "global" | "project";
|
|
5
|
+
export type PluginInstallSource = "local" | "npm";
|
|
6
|
+
export type ResolvedPaths = {
|
|
7
|
+
scope: Scope;
|
|
8
|
+
cwd: string;
|
|
9
|
+
opencodeBaseDir: string;
|
|
10
|
+
guardianBaseDir: string;
|
|
11
|
+
pluginBaseDir: string;
|
|
12
|
+
opencodeConfigPath: string;
|
|
13
|
+
opencodeAlternatePaths: string[];
|
|
14
|
+
guardianConfigPath: string;
|
|
15
|
+
guardianAlternatePaths: string[];
|
|
16
|
+
pluginEntryPath: string;
|
|
17
|
+
};
|
|
18
|
+
export type GuardianConfigOverrides = {
|
|
19
|
+
model?: string;
|
|
20
|
+
variant?: string;
|
|
21
|
+
timeoutMs?: number;
|
|
22
|
+
approvalRiskThreshold?: number;
|
|
23
|
+
reviewToastDurationMs?: number;
|
|
24
|
+
};
|
|
25
|
+
export type WriteResult = {
|
|
26
|
+
action: "created" | "updated" | "kept" | "skipped";
|
|
27
|
+
path: string;
|
|
28
|
+
reason?: string;
|
|
29
|
+
};
|
|
30
|
+
export type InstallationInspection = {
|
|
31
|
+
scope: Scope;
|
|
32
|
+
opencode: {
|
|
33
|
+
path: string;
|
|
34
|
+
exists: boolean;
|
|
35
|
+
alternates: string[];
|
|
36
|
+
parseError?: string;
|
|
37
|
+
packageConfigured: boolean;
|
|
38
|
+
plugins: string[];
|
|
39
|
+
};
|
|
40
|
+
guardian: {
|
|
41
|
+
path: string;
|
|
42
|
+
exists: boolean;
|
|
43
|
+
alternates: string[];
|
|
44
|
+
managed: boolean;
|
|
45
|
+
parseError?: string;
|
|
46
|
+
overrides?: GuardianConfigOverrides;
|
|
47
|
+
};
|
|
48
|
+
localPlugin: {
|
|
49
|
+
path: string;
|
|
50
|
+
exists: boolean;
|
|
51
|
+
managed: boolean;
|
|
52
|
+
target?: string;
|
|
53
|
+
};
|
|
54
|
+
warnings: string[];
|
|
55
|
+
problems: string[];
|
|
56
|
+
};
|
|
57
|
+
export declare function resolvePaths(options: {
|
|
58
|
+
scope: Scope;
|
|
59
|
+
cwd: string;
|
|
60
|
+
configDir?: string;
|
|
61
|
+
}): Promise<ResolvedPaths>;
|
|
62
|
+
export declare function ensurePackageConfigText(text?: string): string;
|
|
63
|
+
export declare function parseGuardianConfigText(text: string, label: string): GuardianConfigOverrides;
|
|
64
|
+
export declare function renderGuardianConfig(overrides?: GuardianConfigOverrides): string;
|
|
65
|
+
export declare function ensurePackageInstalled(paths: ResolvedPaths): Promise<{
|
|
66
|
+
path: string;
|
|
67
|
+
changed: boolean;
|
|
68
|
+
}>;
|
|
69
|
+
export declare function installLocalPlugin(paths: ResolvedPaths, options: {
|
|
70
|
+
force: boolean;
|
|
71
|
+
}): Promise<WriteResult>;
|
|
72
|
+
export declare function syncLocalPlugin(paths: ResolvedPaths, options: {
|
|
73
|
+
force: boolean;
|
|
74
|
+
}): Promise<WriteResult>;
|
|
75
|
+
export declare function installGuardianConfig(paths: ResolvedPaths, options: {
|
|
76
|
+
force: boolean;
|
|
77
|
+
}): Promise<WriteResult>;
|
|
78
|
+
export declare function syncGuardianConfig(paths: ResolvedPaths, options: {
|
|
79
|
+
force: boolean;
|
|
80
|
+
}): Promise<WriteResult>;
|
|
81
|
+
export declare function writeGuardianConfig(paths: ResolvedPaths, overrides: GuardianConfigOverrides, options: {
|
|
82
|
+
force: boolean;
|
|
83
|
+
}): Promise<WriteResult>;
|
|
84
|
+
export declare function inspectInstallation(paths: ResolvedPaths): Promise<InstallationInspection>;
|
|
85
|
+
export declare function renderLocalPluginShim(): Promise<string>;
|
|
86
|
+
export declare function describeWriteResult(result: WriteResult): string;
|
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
import { applyEdits, format, modify, parse } from "jsonc-parser";
|
|
2
|
+
import { access, mkdir, readFile, writeFile } from "node:fs/promises";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { dirname, join } from "node:path";
|
|
5
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
6
|
+
export const CLI_NAME = "vvoc";
|
|
7
|
+
export const PACKAGE_NAME = "@osovv/vv-opencode";
|
|
8
|
+
export const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
|
|
9
|
+
const DEFAULT_GLOBAL_CONFIG_DIR = join(homedir(), ".config", "opencode");
|
|
10
|
+
const MANAGED_MARKER = "Managed by vvoc";
|
|
11
|
+
const DEFAULT_GUARDIAN_TIMEOUT_MS = 90_000;
|
|
12
|
+
const DEFAULT_GUARDIAN_APPROVAL_RISK_THRESHOLD = 80;
|
|
13
|
+
const LOCAL_PLUGIN_FILE_NAME = "vv-opencode.ts";
|
|
14
|
+
const JSON_FORMAT = {
|
|
15
|
+
insertSpaces: true,
|
|
16
|
+
tabSize: 2,
|
|
17
|
+
eol: "\n",
|
|
18
|
+
};
|
|
19
|
+
export async function resolvePaths(options) {
|
|
20
|
+
const opencodeBaseDir = options.scope === "global"
|
|
21
|
+
? options.configDir ?? DEFAULT_GLOBAL_CONFIG_DIR
|
|
22
|
+
: options.cwd;
|
|
23
|
+
const guardianBaseDir = options.scope === "global"
|
|
24
|
+
? options.configDir ?? DEFAULT_GLOBAL_CONFIG_DIR
|
|
25
|
+
: join(options.cwd, ".opencode");
|
|
26
|
+
const pluginBaseDir = options.scope === "global"
|
|
27
|
+
? join(options.configDir ?? DEFAULT_GLOBAL_CONFIG_DIR, "plugins")
|
|
28
|
+
: join(options.cwd, ".opencode", "plugins");
|
|
29
|
+
const opencodeSelection = await selectPrimaryPath([
|
|
30
|
+
join(opencodeBaseDir, "opencode.json"),
|
|
31
|
+
join(opencodeBaseDir, "opencode.jsonc"),
|
|
32
|
+
]);
|
|
33
|
+
const guardianSelection = await selectPrimaryPath([
|
|
34
|
+
join(guardianBaseDir, "guardian.jsonc"),
|
|
35
|
+
join(guardianBaseDir, "guardian.json"),
|
|
36
|
+
]);
|
|
37
|
+
return {
|
|
38
|
+
scope: options.scope,
|
|
39
|
+
cwd: options.cwd,
|
|
40
|
+
opencodeBaseDir,
|
|
41
|
+
guardianBaseDir,
|
|
42
|
+
pluginBaseDir,
|
|
43
|
+
opencodeConfigPath: opencodeSelection.primary,
|
|
44
|
+
opencodeAlternatePaths: opencodeSelection.alternates,
|
|
45
|
+
guardianConfigPath: guardianSelection.primary,
|
|
46
|
+
guardianAlternatePaths: guardianSelection.alternates,
|
|
47
|
+
pluginEntryPath: join(pluginBaseDir, LOCAL_PLUGIN_FILE_NAME),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export function ensurePackageConfigText(text) {
|
|
51
|
+
if (!text?.trim()) {
|
|
52
|
+
return renderJson({
|
|
53
|
+
$schema: OPENCODE_SCHEMA_URL,
|
|
54
|
+
plugin: [PACKAGE_NAME],
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
const document = parseObjectDocument(text, "OpenCode config");
|
|
58
|
+
const currentPlugins = readPluginList(document, "OpenCode config");
|
|
59
|
+
let nextText = text;
|
|
60
|
+
if (!Object.hasOwn(document, "$schema")) {
|
|
61
|
+
nextText = applyEdits(nextText, modify(nextText, ["$schema"], OPENCODE_SCHEMA_URL, {
|
|
62
|
+
formattingOptions: JSON_FORMAT,
|
|
63
|
+
getInsertionIndex: () => 0,
|
|
64
|
+
}));
|
|
65
|
+
}
|
|
66
|
+
const nextPlugins = Array.from(new Set([...currentPlugins, PACKAGE_NAME]));
|
|
67
|
+
if (nextPlugins.length !== currentPlugins.length) {
|
|
68
|
+
nextText = applyEdits(nextText, modify(nextText, ["plugin"], nextPlugins, {
|
|
69
|
+
formattingOptions: JSON_FORMAT,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
73
|
+
}
|
|
74
|
+
export function parseGuardianConfigText(text, label) {
|
|
75
|
+
return normalizeGuardianOverrides(parseObjectDocument(text, label), label);
|
|
76
|
+
}
|
|
77
|
+
export function renderGuardianConfig(overrides = {}) {
|
|
78
|
+
const timeoutMs = overrides.timeoutMs ?? DEFAULT_GUARDIAN_TIMEOUT_MS;
|
|
79
|
+
const approvalRiskThreshold = overrides.approvalRiskThreshold
|
|
80
|
+
?? DEFAULT_GUARDIAN_APPROVAL_RISK_THRESHOLD;
|
|
81
|
+
const reviewToastDurationMs = overrides.reviewToastDurationMs ?? timeoutMs;
|
|
82
|
+
const lines = [
|
|
83
|
+
"// Managed by vvoc.",
|
|
84
|
+
"// `vvoc sync` rewrites files with this marker while preserving current values.",
|
|
85
|
+
"// Remove this header if you want to manage the file manually.",
|
|
86
|
+
"",
|
|
87
|
+
"{",
|
|
88
|
+
];
|
|
89
|
+
if (overrides.model) {
|
|
90
|
+
lines.push(` \"model\": ${JSON.stringify(overrides.model)},`);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
lines.push(" // \"model\": \"anthropic/claude-sonnet-4-5\",");
|
|
94
|
+
}
|
|
95
|
+
lines.push("");
|
|
96
|
+
if (overrides.variant) {
|
|
97
|
+
lines.push(` \"variant\": ${JSON.stringify(overrides.variant)},`);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
lines.push(" // \"variant\": \"high\",");
|
|
101
|
+
}
|
|
102
|
+
lines.push("");
|
|
103
|
+
lines.push(` \"timeoutMs\": ${timeoutMs},`);
|
|
104
|
+
lines.push(` \"approvalRiskThreshold\": ${approvalRiskThreshold},`);
|
|
105
|
+
lines.push(` \"reviewToastDurationMs\": ${reviewToastDurationMs}`);
|
|
106
|
+
lines.push("}");
|
|
107
|
+
return `${lines.join("\n")}\n`;
|
|
108
|
+
}
|
|
109
|
+
export async function ensurePackageInstalled(paths) {
|
|
110
|
+
const currentText = await readOptionalText(paths.opencodeConfigPath);
|
|
111
|
+
const nextText = ensurePackageConfigText(currentText);
|
|
112
|
+
if (currentText === nextText) {
|
|
113
|
+
return { path: paths.opencodeConfigPath, changed: false };
|
|
114
|
+
}
|
|
115
|
+
await writeText(paths.opencodeConfigPath, nextText);
|
|
116
|
+
return { path: paths.opencodeConfigPath, changed: true };
|
|
117
|
+
}
|
|
118
|
+
export async function installLocalPlugin(paths, options) {
|
|
119
|
+
const currentText = await readOptionalText(paths.pluginEntryPath);
|
|
120
|
+
const nextText = await renderLocalPluginShim();
|
|
121
|
+
if (!currentText) {
|
|
122
|
+
await writeText(paths.pluginEntryPath, nextText);
|
|
123
|
+
return { action: "created", path: paths.pluginEntryPath };
|
|
124
|
+
}
|
|
125
|
+
if (!options.force && !isManagedFile(currentText)) {
|
|
126
|
+
return {
|
|
127
|
+
action: "skipped",
|
|
128
|
+
path: paths.pluginEntryPath,
|
|
129
|
+
reason: "existing plugin file is not managed by vvoc",
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
if (currentText === nextText) {
|
|
133
|
+
return { action: "kept", path: paths.pluginEntryPath };
|
|
134
|
+
}
|
|
135
|
+
await writeText(paths.pluginEntryPath, nextText);
|
|
136
|
+
return { action: "updated", path: paths.pluginEntryPath };
|
|
137
|
+
}
|
|
138
|
+
export async function syncLocalPlugin(paths, options) {
|
|
139
|
+
return installLocalPlugin(paths, options);
|
|
140
|
+
}
|
|
141
|
+
export async function installGuardianConfig(paths, options) {
|
|
142
|
+
const currentText = await readOptionalText(paths.guardianConfigPath);
|
|
143
|
+
if (!currentText) {
|
|
144
|
+
await writeText(paths.guardianConfigPath, renderGuardianConfig());
|
|
145
|
+
return { action: "created", path: paths.guardianConfigPath };
|
|
146
|
+
}
|
|
147
|
+
if (!options.force) {
|
|
148
|
+
if (!isManagedFile(currentText)) {
|
|
149
|
+
return {
|
|
150
|
+
action: "skipped",
|
|
151
|
+
path: paths.guardianConfigPath,
|
|
152
|
+
reason: "existing file is not managed by vvoc",
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
return { action: "kept", path: paths.guardianConfigPath };
|
|
156
|
+
}
|
|
157
|
+
return syncGuardianConfig(paths, options);
|
|
158
|
+
}
|
|
159
|
+
export async function syncGuardianConfig(paths, options) {
|
|
160
|
+
const currentText = await readOptionalText(paths.guardianConfigPath);
|
|
161
|
+
if (!currentText) {
|
|
162
|
+
await writeText(paths.guardianConfigPath, renderGuardianConfig());
|
|
163
|
+
return { action: "created", path: paths.guardianConfigPath };
|
|
164
|
+
}
|
|
165
|
+
if (!options.force && !isManagedFile(currentText)) {
|
|
166
|
+
return {
|
|
167
|
+
action: "skipped",
|
|
168
|
+
path: paths.guardianConfigPath,
|
|
169
|
+
reason: "existing file is not managed by vvoc",
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
const nextText = renderGuardianConfig(parseGuardianConfigText(currentText, paths.guardianConfigPath));
|
|
173
|
+
if (currentText === nextText) {
|
|
174
|
+
return { action: "kept", path: paths.guardianConfigPath };
|
|
175
|
+
}
|
|
176
|
+
await writeText(paths.guardianConfigPath, nextText);
|
|
177
|
+
return { action: "updated", path: paths.guardianConfigPath };
|
|
178
|
+
}
|
|
179
|
+
export async function writeGuardianConfig(paths, overrides, options) {
|
|
180
|
+
const currentText = await readOptionalText(paths.guardianConfigPath);
|
|
181
|
+
if (currentText && !options.force && !isManagedFile(currentText)) {
|
|
182
|
+
return {
|
|
183
|
+
action: "skipped",
|
|
184
|
+
path: paths.guardianConfigPath,
|
|
185
|
+
reason: "existing file is not managed by vvoc",
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const nextText = renderGuardianConfig(overrides);
|
|
189
|
+
if (currentText === nextText) {
|
|
190
|
+
return { action: "kept", path: paths.guardianConfigPath };
|
|
191
|
+
}
|
|
192
|
+
await writeText(paths.guardianConfigPath, nextText);
|
|
193
|
+
return {
|
|
194
|
+
action: currentText ? "updated" : "created",
|
|
195
|
+
path: paths.guardianConfigPath,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
export async function inspectInstallation(paths) {
|
|
199
|
+
const warnings = [];
|
|
200
|
+
const problems = [];
|
|
201
|
+
if (paths.opencodeAlternatePaths.length > 0) {
|
|
202
|
+
warnings.push(`multiple OpenCode config files exist: ${[paths.opencodeConfigPath, ...paths.opencodeAlternatePaths].join(", ")}`);
|
|
203
|
+
}
|
|
204
|
+
if (paths.guardianAlternatePaths.length > 0) {
|
|
205
|
+
warnings.push(`multiple Guardian config files exist: ${[paths.guardianConfigPath, ...paths.guardianAlternatePaths].join(", ")}`);
|
|
206
|
+
}
|
|
207
|
+
const opencodeText = await readOptionalText(paths.opencodeConfigPath);
|
|
208
|
+
let opencodeParseError;
|
|
209
|
+
let plugins = [];
|
|
210
|
+
let packageConfigured = false;
|
|
211
|
+
if (opencodeText) {
|
|
212
|
+
try {
|
|
213
|
+
const document = parseObjectDocument(opencodeText, paths.opencodeConfigPath);
|
|
214
|
+
plugins = readPluginList(document, paths.opencodeConfigPath);
|
|
215
|
+
packageConfigured = plugins.includes(PACKAGE_NAME);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
opencodeParseError = error instanceof Error ? error.message : String(error);
|
|
219
|
+
problems.push(opencodeParseError);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
const guardianText = await readOptionalText(paths.guardianConfigPath);
|
|
223
|
+
let guardianParseError;
|
|
224
|
+
let guardianOverrides;
|
|
225
|
+
const guardianManaged = guardianText ? isManagedFile(guardianText) : false;
|
|
226
|
+
if (guardianText) {
|
|
227
|
+
try {
|
|
228
|
+
guardianOverrides = parseGuardianConfigText(guardianText, paths.guardianConfigPath);
|
|
229
|
+
}
|
|
230
|
+
catch (error) {
|
|
231
|
+
guardianParseError = error instanceof Error ? error.message : String(error);
|
|
232
|
+
problems.push(guardianParseError);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
const localPluginText = await readOptionalText(paths.pluginEntryPath);
|
|
236
|
+
const localPluginManaged = localPluginText ? isManagedFile(localPluginText) : false;
|
|
237
|
+
const localPluginTarget = localPluginText ? readLocalPluginTarget(localPluginText) : undefined;
|
|
238
|
+
return {
|
|
239
|
+
scope: paths.scope,
|
|
240
|
+
opencode: {
|
|
241
|
+
path: paths.opencodeConfigPath,
|
|
242
|
+
exists: Boolean(opencodeText),
|
|
243
|
+
alternates: paths.opencodeAlternatePaths,
|
|
244
|
+
parseError: opencodeParseError,
|
|
245
|
+
packageConfigured,
|
|
246
|
+
plugins,
|
|
247
|
+
},
|
|
248
|
+
guardian: {
|
|
249
|
+
path: paths.guardianConfigPath,
|
|
250
|
+
exists: Boolean(guardianText),
|
|
251
|
+
alternates: paths.guardianAlternatePaths,
|
|
252
|
+
managed: guardianManaged,
|
|
253
|
+
parseError: guardianParseError,
|
|
254
|
+
overrides: guardianOverrides,
|
|
255
|
+
},
|
|
256
|
+
localPlugin: {
|
|
257
|
+
path: paths.pluginEntryPath,
|
|
258
|
+
exists: Boolean(localPluginText),
|
|
259
|
+
managed: localPluginManaged,
|
|
260
|
+
target: localPluginTarget,
|
|
261
|
+
},
|
|
262
|
+
warnings,
|
|
263
|
+
problems,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
export async function renderLocalPluginShim() {
|
|
267
|
+
const targetPath = await resolveLocalPluginTargetPath();
|
|
268
|
+
const targetUrl = pathToFileURL(targetPath).href;
|
|
269
|
+
return [
|
|
270
|
+
"// Managed by vvoc.",
|
|
271
|
+
"// Local development shim for @osovv/vv-opencode.",
|
|
272
|
+
`export { GuardianPlugin } from ${JSON.stringify(targetUrl)};`,
|
|
273
|
+
"",
|
|
274
|
+
].join("\n");
|
|
275
|
+
}
|
|
276
|
+
export function describeWriteResult(result) {
|
|
277
|
+
switch (result.action) {
|
|
278
|
+
case "created":
|
|
279
|
+
return `Created ${result.path}`;
|
|
280
|
+
case "updated":
|
|
281
|
+
return `Updated ${result.path}`;
|
|
282
|
+
case "kept":
|
|
283
|
+
return `Kept ${result.path}`;
|
|
284
|
+
case "skipped":
|
|
285
|
+
return `Skipped ${result.path}${result.reason ? ` (${result.reason})` : ""}`;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
function parseObjectDocument(text, label) {
|
|
289
|
+
const errors = [];
|
|
290
|
+
const value = parse(text, errors, {
|
|
291
|
+
allowEmptyContent: false,
|
|
292
|
+
allowTrailingComma: true,
|
|
293
|
+
disallowComments: false,
|
|
294
|
+
});
|
|
295
|
+
if (errors.length > 0) {
|
|
296
|
+
throw new Error(`${label}: failed to parse JSONC (${errors.length} error(s))`);
|
|
297
|
+
}
|
|
298
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
299
|
+
throw new Error(`${label}: expected a top-level object`);
|
|
300
|
+
}
|
|
301
|
+
return value;
|
|
302
|
+
}
|
|
303
|
+
function readPluginList(document, label) {
|
|
304
|
+
const raw = document.plugin;
|
|
305
|
+
if (raw === undefined)
|
|
306
|
+
return [];
|
|
307
|
+
if (!Array.isArray(raw) || raw.some((entry) => typeof entry !== "string")) {
|
|
308
|
+
throw new Error(`${label}: expected \"plugin\" to be an array of strings`);
|
|
309
|
+
}
|
|
310
|
+
return raw.slice();
|
|
311
|
+
}
|
|
312
|
+
function normalizeGuardianOverrides(raw, label) {
|
|
313
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
314
|
+
throw new Error(`${label}: expected a top-level object`);
|
|
315
|
+
}
|
|
316
|
+
const record = raw;
|
|
317
|
+
const overrides = {};
|
|
318
|
+
if (Object.hasOwn(record, "model")) {
|
|
319
|
+
overrides.model = readNonEmptyString(record.model, `${label}: model`);
|
|
320
|
+
}
|
|
321
|
+
if (Object.hasOwn(record, "variant")) {
|
|
322
|
+
overrides.variant = readNonEmptyString(record.variant, `${label}: variant`);
|
|
323
|
+
}
|
|
324
|
+
if (Object.hasOwn(record, "timeoutMs")) {
|
|
325
|
+
overrides.timeoutMs = readPositiveInteger(record.timeoutMs, `${label}: timeoutMs`);
|
|
326
|
+
}
|
|
327
|
+
if (Object.hasOwn(record, "approvalRiskThreshold")) {
|
|
328
|
+
overrides.approvalRiskThreshold = readThreshold(record.approvalRiskThreshold, `${label}: approvalRiskThreshold`);
|
|
329
|
+
}
|
|
330
|
+
if (Object.hasOwn(record, "reviewToastDurationMs")) {
|
|
331
|
+
overrides.reviewToastDurationMs = readPositiveInteger(record.reviewToastDurationMs, `${label}: reviewToastDurationMs`);
|
|
332
|
+
}
|
|
333
|
+
return overrides;
|
|
334
|
+
}
|
|
335
|
+
function readNonEmptyString(value, label) {
|
|
336
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
337
|
+
throw new Error(`${label}: expected a non-empty string`);
|
|
338
|
+
}
|
|
339
|
+
return value.trim();
|
|
340
|
+
}
|
|
341
|
+
function readPositiveInteger(value, label) {
|
|
342
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
343
|
+
return Math.round(value);
|
|
344
|
+
}
|
|
345
|
+
throw new Error(`${label}: expected a positive integer`);
|
|
346
|
+
}
|
|
347
|
+
function readThreshold(value, label) {
|
|
348
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
349
|
+
return Math.max(0, Math.min(100, Math.round(value)));
|
|
350
|
+
}
|
|
351
|
+
throw new Error(`${label}: expected a number between 0 and 100`);
|
|
352
|
+
}
|
|
353
|
+
function isManagedFile(text) {
|
|
354
|
+
return text.includes(MANAGED_MARKER);
|
|
355
|
+
}
|
|
356
|
+
function readLocalPluginTarget(text) {
|
|
357
|
+
const match = text.match(/export\s+\{\s*GuardianPlugin\s*\}\s+from\s+["']([^"']+)["']/);
|
|
358
|
+
return match?.[1];
|
|
359
|
+
}
|
|
360
|
+
function renderJson(value) {
|
|
361
|
+
return `${JSON.stringify(value, null, 2)}\n`;
|
|
362
|
+
}
|
|
363
|
+
function ensureTrailingNewline(text) {
|
|
364
|
+
return text.endsWith("\n") ? text : `${text}\n`;
|
|
365
|
+
}
|
|
366
|
+
async function readOptionalText(path) {
|
|
367
|
+
try {
|
|
368
|
+
return await readFile(path, "utf8");
|
|
369
|
+
}
|
|
370
|
+
catch (error) {
|
|
371
|
+
if (error.code === "ENOENT") {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
throw error;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
async function writeText(path, text) {
|
|
378
|
+
await mkdir(dirname(path), { recursive: true });
|
|
379
|
+
await writeFile(path, text, "utf8");
|
|
380
|
+
}
|
|
381
|
+
async function resolveLocalPluginTargetPath() {
|
|
382
|
+
const packageRoot = fileURLToPath(new URL("../../", import.meta.url));
|
|
383
|
+
const candidates = [
|
|
384
|
+
join(packageRoot, "src", "plugins", "guardian.ts"),
|
|
385
|
+
join(packageRoot, "dist", "plugins", "guardian.js"),
|
|
386
|
+
];
|
|
387
|
+
for (const candidate of candidates) {
|
|
388
|
+
if (await pathExists(candidate)) {
|
|
389
|
+
return candidate;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
return candidates[0];
|
|
393
|
+
}
|
|
394
|
+
async function selectPrimaryPath(candidates) {
|
|
395
|
+
const existing = [];
|
|
396
|
+
for (const candidate of candidates) {
|
|
397
|
+
if (await readOptionalText(candidate) !== undefined) {
|
|
398
|
+
existing.push(candidate);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
primary: existing[0] ?? candidates[0],
|
|
403
|
+
alternates: existing.slice(1),
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
async function pathExists(path) {
|
|
407
|
+
try {
|
|
408
|
+
await access(path);
|
|
409
|
+
return true;
|
|
410
|
+
}
|
|
411
|
+
catch {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
//# sourceMappingURL=opencode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.js","sourceRoot":"","sources":["../../src/lib/opencode.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { parse } from "jsonc-parser";
|
|
3
|
+
import { OPENCODE_SCHEMA_URL, PACKAGE_NAME, ensurePackageConfigText, parseGuardianConfigText, renderLocalPluginShim, renderGuardianConfig, } from "./opencode.js";
|
|
4
|
+
describe("ensurePackageConfigText", () => {
|
|
5
|
+
test("creates a new config when none exists", () => {
|
|
6
|
+
const output = ensurePackageConfigText();
|
|
7
|
+
const parsed = parse(output);
|
|
8
|
+
expect(parsed.$schema).toBe(OPENCODE_SCHEMA_URL);
|
|
9
|
+
expect(parsed.plugin).toEqual([PACKAGE_NAME]);
|
|
10
|
+
});
|
|
11
|
+
test("preserves comments while appending the plugin", () => {
|
|
12
|
+
const input = `{
|
|
13
|
+
// existing plugin comment
|
|
14
|
+
"plugin": ["foo"]
|
|
15
|
+
}\n`;
|
|
16
|
+
const output = ensurePackageConfigText(input);
|
|
17
|
+
const parsed = parse(output);
|
|
18
|
+
expect(output).toContain("// existing plugin comment");
|
|
19
|
+
expect(parsed.plugin).toEqual(["foo", PACKAGE_NAME]);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
describe("guardian config helpers", () => {
|
|
23
|
+
test("round-trips managed guardian config values", () => {
|
|
24
|
+
const output = renderGuardianConfig({
|
|
25
|
+
model: "anthropic/claude-sonnet-4-5",
|
|
26
|
+
variant: "high",
|
|
27
|
+
timeoutMs: 12_345,
|
|
28
|
+
approvalRiskThreshold: 55,
|
|
29
|
+
reviewToastDurationMs: 6_789,
|
|
30
|
+
});
|
|
31
|
+
const parsed = parseGuardianConfigText(output, "test guardian config");
|
|
32
|
+
expect(parsed).toEqual({
|
|
33
|
+
model: "anthropic/claude-sonnet-4-5",
|
|
34
|
+
variant: "high",
|
|
35
|
+
timeoutMs: 12_345,
|
|
36
|
+
approvalRiskThreshold: 55,
|
|
37
|
+
reviewToastDurationMs: 6_789,
|
|
38
|
+
});
|
|
39
|
+
});
|
|
40
|
+
test("renders a managed local plugin shim", async () => {
|
|
41
|
+
const output = await renderLocalPluginShim();
|
|
42
|
+
expect(output).toContain("Managed by vvoc");
|
|
43
|
+
expect(output).toContain("GuardianPlugin");
|
|
44
|
+
expect(output).toContain("file://");
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=opencode.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"opencode.test.js","sourceRoot":"","sources":["../../src/lib/opencode.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EACL,mBAAmB,EACnB,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,EACvB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,eAAe,CAAC;AAEvB,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,CAAC,uCAAuC,EAAE,GAAG,EAAE;QACjD,MAAM,MAAM,GAAG,uBAAuB,EAAE,CAAC;QACzC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAA4C,CAAC;QAExE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;QACjD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACzD,MAAM,KAAK,GAAG;;;IAGd,CAAC;QACD,MAAM,MAAM,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAA0B,CAAC;QAEtD,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC;QACvD,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,yBAAyB,EAAE,GAAG,EAAE;IACvC,IAAI,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACtD,MAAM,MAAM,GAAG,oBAAoB,CAAC;YAClC,KAAK,EAAE,6BAA6B;YACpC,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,MAAM;YACjB,qBAAqB,EAAE,EAAE;YACzB,qBAAqB,EAAE,KAAK;SAC7B,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,uBAAuB,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAC;QAEvE,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC;YACrB,KAAK,EAAE,6BAA6B;YACpC,OAAO,EAAE,MAAM;YACf,SAAS,EAAE,MAAM;YACjB,qBAAqB,EAAE,EAAE;YACzB,qBAAqB,EAAE,KAAK;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACrD,MAAM,MAAM,GAAG,MAAM,qBAAqB,EAAE,CAAC;QAE7C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAC;QAC5C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|