@osovv/vv-opencode 0.35.18 → 0.35.20
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/CHANGELOG.md +19 -0
- package/README.md +67 -24
- package/dist/cli.js +3 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/completion.js +2 -0
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/config-validate.d.ts +8 -1
- package/dist/commands/config-validate.js +31 -8
- package/dist/commands/config-validate.js.map +1 -1
- package/dist/commands/doctor.d.ts +3 -3
- package/dist/commands/doctor.js +14 -13
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.js +9 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +5 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/launch.d.ts +35 -0
- package/dist/commands/launch.js +123 -0
- package/dist/commands/launch.js.map +1 -0
- package/dist/commands/patch-provider.d.ts +8 -0
- package/dist/commands/patch-provider.js +13 -4
- package/dist/commands/patch-provider.js.map +1 -1
- package/dist/commands/plugin-list.d.ts +6 -6
- package/dist/commands/plugin-list.js +30 -24
- package/dist/commands/plugin-list.js.map +1 -1
- package/dist/commands/plugin-toggle.js +5 -3
- package/dist/commands/plugin-toggle.js.map +1 -1
- package/dist/commands/preset.d.ts +7 -0
- package/dist/commands/preset.js +37 -9
- package/dist/commands/preset.js.map +1 -1
- package/dist/commands/role.d.ts +3 -0
- package/dist/commands/role.js +45 -11
- package/dist/commands/role.js.map +1 -1
- package/dist/commands/status.d.ts +3 -3
- package/dist/commands/status.js +14 -13
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/sync.js +5 -2
- package/dist/commands/sync.js.map +1 -1
- package/dist/lib/config-layers.d.ts +56 -0
- package/dist/lib/config-layers.js +255 -0
- package/dist/lib/config-layers.js.map +1 -0
- package/dist/lib/opencode.d.ts +13 -3
- package/dist/lib/opencode.js +106 -29
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/plugin-toggle-config.d.ts +5 -1
- package/dist/lib/plugin-toggle-config.js +20 -33
- package/dist/lib/plugin-toggle-config.js.map +1 -1
- package/dist/lib/vvoc-config.js +14 -1
- package/dist/lib/vvoc-config.js.map +1 -1
- package/dist/lib/vvoc-paths.d.ts +2 -1
- package/dist/lib/vvoc-paths.js +10 -5
- package/dist/lib/vvoc-paths.js.map +1 -1
- package/dist/plugins/guardian/index.js +30 -37
- package/dist/plugins/guardian/index.js.map +1 -1
- package/dist/plugins/model-roles/index.js +11 -27
- package/dist/plugins/model-roles/index.js.map +1 -1
- package/dist/plugins/secrets-redaction/config.d.ts +1 -1
- package/dist/plugins/secrets-redaction/config.js +28 -39
- package/dist/plugins/secrets-redaction/config.js.map +1 -1
- package/dist/plugins/system-context-injection/index.js +19 -7
- package/dist/plugins/system-context-injection/index.js.map +1 -1
- package/package.json +1 -1
- package/schemas/vvoc/v3.json +1 -1
- package/templates/agents/vv-controller.md +9 -8
- package/templates/skills/vv-execute/SKILL.md +8 -8
- package/templates/skills/vv-plan/SKILL.md +11 -6
- package/templates/skills/vv-plan/references/plan-template.xml +1 -0
- package/templates/skills/vv-reflect/SKILL.md +24 -10
- package/templates/skills/vv-spec/SKILL.md +29 -3
- package/templates/skills/vv-spec/references/design-context-template.xml +62 -0
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
// FILE: src/lib/config-layers.ts
|
|
2
|
+
// VERSION: 1.0.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Resolve vvoc and OpenCode config layers for global, project, and effective scopes.
|
|
5
|
+
// SCOPE: Env override handling, ancestor project-root discovery, project write-root selection, global fallback paths, runtime vvoc loading, and source metadata.
|
|
6
|
+
// DEPENDS: [node:fs/promises, node:path, src/lib/vvoc-config.ts, src/lib/vvoc-paths.ts]
|
|
7
|
+
// LINKS: [M-CONFIG-LAYERS, M-CLI-CONFIG]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// VVOC_CONFIG_ENV - Environment variable name for explicit vvoc config selection.
|
|
14
|
+
// OPENCODE_CONFIG_ENV - Environment variable name for explicit OpenCode config selection.
|
|
15
|
+
// ConfigWriteScope - Supported write scopes for mutating commands.
|
|
16
|
+
// ConfigReadScope - Supported read scopes for list/show/diagnostic commands.
|
|
17
|
+
// ConfigSourceKind - Source kind labels for selected config sources.
|
|
18
|
+
// ConfigSource - Metadata describing a selected config source.
|
|
19
|
+
// ProjectConfigRoot - Nearest project config layer metadata.
|
|
20
|
+
// ConfigLayerOptions - Common layered config resolution inputs.
|
|
21
|
+
// findNearestProjectConfigRoot - Finds the closest ancestor with .vvoc/vvoc.json or .opencode/opencode.json(c).
|
|
22
|
+
// resolveProjectWriteRoot - Selects the project root that project-scope mutations write to.
|
|
23
|
+
// resolveProjectOpenCodeConfigPath - Selects the canonical project .opencode/opencode.json(c) path.
|
|
24
|
+
// resolveVvocConfigSource - Resolves vvoc source metadata for global, project, or effective reads.
|
|
25
|
+
// resolveOpenCodeConfigSource - Resolves OpenCode source metadata for global, project, or effective reads.
|
|
26
|
+
// resolveConfigWriteTargets - Returns canonical global or project write paths.
|
|
27
|
+
// loadVvocConfigForRead - Loads vvoc config for CLI read/list/show commands without creating files.
|
|
28
|
+
// loadEffectiveVvocConfigForRuntime - Loads the effective vvoc config for runtime plugins.
|
|
29
|
+
// END_MODULE_MAP
|
|
30
|
+
//
|
|
31
|
+
// START_CHANGE_SUMMARY
|
|
32
|
+
// LAST_CHANGE: [v1.0.0 - Added layered config source discovery, write target resolution, and runtime vvoc loading.]
|
|
33
|
+
// END_CHANGE_SUMMARY
|
|
34
|
+
import { access, readFile } from "node:fs/promises";
|
|
35
|
+
import { dirname, join, resolve } from "node:path";
|
|
36
|
+
import { createDefaultVvocConfig, loadLenientVvocConfigText, parseVvocConfigText, } from "./vvoc-config.js";
|
|
37
|
+
import { getGlobalOpencodeDir, getGlobalVvocConfigPath, getGlobalVvocDir, getProjectOpencodeDir, getProjectVvocConfigPath, } from "./vvoc-paths.js";
|
|
38
|
+
export const VVOC_CONFIG_ENV = "VVOC_CONFIG";
|
|
39
|
+
export const OPENCODE_CONFIG_ENV = "OPENCODE_CONFIG";
|
|
40
|
+
const OPENCODE_CONFIG_FILE_NAMES = ["opencode.json", "opencode.jsonc"];
|
|
41
|
+
// START_BLOCK_PROJECT_LAYER_DISCOVERY
|
|
42
|
+
export async function findNearestProjectConfigRoot(cwd) {
|
|
43
|
+
let currentDir = resolve(cwd);
|
|
44
|
+
while (true) {
|
|
45
|
+
const vvocConfigPath = getProjectVvocConfigPath(currentDir);
|
|
46
|
+
const opencodeConfigPath = await findExistingProjectOpenCodeConfigPath(currentDir);
|
|
47
|
+
const hasVvocConfig = await pathExists(vvocConfigPath);
|
|
48
|
+
if (hasVvocConfig || opencodeConfigPath) {
|
|
49
|
+
return {
|
|
50
|
+
rootDir: currentDir,
|
|
51
|
+
vvocConfigPath: hasVvocConfig ? vvocConfigPath : undefined,
|
|
52
|
+
opencodeConfigPath,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const parentDir = dirname(currentDir);
|
|
56
|
+
if (parentDir === currentDir) {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
currentDir = parentDir;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
export async function resolveProjectWriteRoot(cwd) {
|
|
63
|
+
return (await findNearestProjectConfigRoot(cwd))?.rootDir ?? resolve(cwd);
|
|
64
|
+
}
|
|
65
|
+
export async function resolveProjectOpenCodeConfigPath(projectRoot) {
|
|
66
|
+
return ((await findExistingProjectOpenCodeConfigPath(projectRoot)) ??
|
|
67
|
+
join(getProjectOpencodeDir(projectRoot), "opencode.json"));
|
|
68
|
+
}
|
|
69
|
+
// END_BLOCK_PROJECT_LAYER_DISCOVERY
|
|
70
|
+
// START_BLOCK_SOURCE_RESOLUTION
|
|
71
|
+
export async function resolveVvocConfigSource(options) {
|
|
72
|
+
if (options.scope === "global") {
|
|
73
|
+
return resolveGlobalVvocSource(options.configDir);
|
|
74
|
+
}
|
|
75
|
+
if (options.scope === "project") {
|
|
76
|
+
return resolveProjectVvocSource(options.cwd);
|
|
77
|
+
}
|
|
78
|
+
const envSource = readEnvConfigSource(options.env, VVOC_CONFIG_ENV);
|
|
79
|
+
if (envSource) {
|
|
80
|
+
return envSource;
|
|
81
|
+
}
|
|
82
|
+
const projectSource = await resolveProjectVvocSource(options.cwd);
|
|
83
|
+
if (projectSource.kind === "project") {
|
|
84
|
+
return projectSource;
|
|
85
|
+
}
|
|
86
|
+
const globalSource = await resolveGlobalVvocSource(options.configDir);
|
|
87
|
+
if (globalSource.kind === "global") {
|
|
88
|
+
return globalSource;
|
|
89
|
+
}
|
|
90
|
+
if (options.allowDefault) {
|
|
91
|
+
return { kind: "default", reason: "no vvoc config found" };
|
|
92
|
+
}
|
|
93
|
+
return globalSource.kind === "missing" ? globalSource : projectSource;
|
|
94
|
+
}
|
|
95
|
+
export async function resolveOpenCodeConfigSource(options) {
|
|
96
|
+
if (options.scope === "global") {
|
|
97
|
+
return resolveGlobalOpenCodeSource(options.configDir);
|
|
98
|
+
}
|
|
99
|
+
if (options.scope === "project") {
|
|
100
|
+
return resolveProjectOpenCodeSource(options.cwd);
|
|
101
|
+
}
|
|
102
|
+
const envSource = readEnvConfigSource(options.env, OPENCODE_CONFIG_ENV);
|
|
103
|
+
if (envSource) {
|
|
104
|
+
return envSource;
|
|
105
|
+
}
|
|
106
|
+
const projectSource = await resolveProjectOpenCodeSource(options.cwd);
|
|
107
|
+
if (projectSource.kind === "project") {
|
|
108
|
+
return projectSource;
|
|
109
|
+
}
|
|
110
|
+
return resolveGlobalOpenCodeSource(options.configDir);
|
|
111
|
+
}
|
|
112
|
+
export async function resolveConfigWriteTargets(options) {
|
|
113
|
+
if (options.scope === "global") {
|
|
114
|
+
const opencodeBaseDir = getGlobalOpencodeDir(options.configDir);
|
|
115
|
+
const opencodeConfigPath = await selectExistingPath(OPENCODE_CONFIG_FILE_NAMES.map((name) => join(opencodeBaseDir, name)));
|
|
116
|
+
return {
|
|
117
|
+
scope: "global",
|
|
118
|
+
opencodeBaseDir,
|
|
119
|
+
vvocBaseDir: getGlobalVvocDir(options.configDir),
|
|
120
|
+
opencodeConfigPath,
|
|
121
|
+
vvocConfigPath: getGlobalVvocConfigPath(options.configDir),
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
const projectRoot = await resolveProjectWriteRoot(options.cwd);
|
|
125
|
+
const opencodeBaseDir = getProjectOpencodeDir(projectRoot);
|
|
126
|
+
return {
|
|
127
|
+
scope: "project",
|
|
128
|
+
projectRoot,
|
|
129
|
+
opencodeBaseDir,
|
|
130
|
+
vvocBaseDir: dirname(getProjectVvocConfigPath(projectRoot)),
|
|
131
|
+
opencodeConfigPath: await resolveProjectOpenCodeConfigPath(projectRoot),
|
|
132
|
+
vvocConfigPath: getProjectVvocConfigPath(projectRoot),
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// END_BLOCK_SOURCE_RESOLUTION
|
|
136
|
+
// START_BLOCK_RUNTIME_VVOC_LOADING
|
|
137
|
+
export async function loadVvocConfigForRead(options) {
|
|
138
|
+
const source = await resolveVvocConfigSource(options);
|
|
139
|
+
if (source.kind === "default" ||
|
|
140
|
+
(source.kind === "missing" && options.scope === "global" && options.allowDefault)) {
|
|
141
|
+
return {
|
|
142
|
+
config: createDefaultVvocConfig(),
|
|
143
|
+
source: { kind: "default", reason: source.reason },
|
|
144
|
+
warnings: [],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
if (source.kind === "missing") {
|
|
148
|
+
throw new Error(source.reason ?? `vvoc config missing${source.path ? ` at ${source.path}` : ""}`);
|
|
149
|
+
}
|
|
150
|
+
if (!source.path) {
|
|
151
|
+
throw new Error(`selected vvoc config source has no path (${source.kind})`);
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
config: parseVvocConfigText(await readFile(source.path, "utf8"), source.path),
|
|
155
|
+
source,
|
|
156
|
+
warnings: [],
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
export async function loadEffectiveVvocConfigForRuntime(options = {}) {
|
|
160
|
+
const source = await resolveVvocConfigSource({
|
|
161
|
+
scope: "effective",
|
|
162
|
+
allowDefault: true,
|
|
163
|
+
cwd: options.cwd ?? process.cwd(),
|
|
164
|
+
configDir: options.configDir,
|
|
165
|
+
env: options.env,
|
|
166
|
+
});
|
|
167
|
+
if (source.kind === "default") {
|
|
168
|
+
return { config: createDefaultVvocConfig(), source, warnings: [] };
|
|
169
|
+
}
|
|
170
|
+
if (!source.path) {
|
|
171
|
+
throw new Error(`selected vvoc config source has no path (${source.kind})`);
|
|
172
|
+
}
|
|
173
|
+
const text = await readFile(source.path, "utf8");
|
|
174
|
+
if (source.kind === "env" || source.kind === "project") {
|
|
175
|
+
return { config: parseVvocConfigText(text, source.path), source, warnings: [] };
|
|
176
|
+
}
|
|
177
|
+
const warnings = [];
|
|
178
|
+
const config = loadLenientVvocConfigText(text, source.path, warnings);
|
|
179
|
+
return { config, source, warnings };
|
|
180
|
+
}
|
|
181
|
+
// END_BLOCK_RUNTIME_VVOC_LOADING
|
|
182
|
+
async function resolveProjectVvocSource(cwd) {
|
|
183
|
+
const root = await findNearestProjectConfigRoot(cwd);
|
|
184
|
+
if (root?.vvocConfigPath) {
|
|
185
|
+
return { kind: "project", path: root.vvocConfigPath, rootDir: root.rootDir };
|
|
186
|
+
}
|
|
187
|
+
return {
|
|
188
|
+
kind: "missing",
|
|
189
|
+
reason: "project vvoc config missing; run vvoc install --scope project",
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async function resolveProjectOpenCodeSource(cwd) {
|
|
193
|
+
const root = await findNearestProjectConfigRoot(cwd);
|
|
194
|
+
if (root?.opencodeConfigPath) {
|
|
195
|
+
return { kind: "project", path: root.opencodeConfigPath, rootDir: root.rootDir };
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
kind: "missing",
|
|
199
|
+
reason: "project OpenCode config missing; run vvoc install --scope project",
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
async function resolveGlobalVvocSource(configDir) {
|
|
203
|
+
const path = getGlobalVvocConfigPath(configDir);
|
|
204
|
+
return (await pathExists(path))
|
|
205
|
+
? { kind: "global", path }
|
|
206
|
+
: { kind: "missing", path, reason: "global vvoc config missing" };
|
|
207
|
+
}
|
|
208
|
+
async function resolveGlobalOpenCodeSource(configDir) {
|
|
209
|
+
const baseDir = getGlobalOpencodeDir(configDir);
|
|
210
|
+
const path = await findExistingOpenCodeConfigPath(baseDir);
|
|
211
|
+
return path
|
|
212
|
+
? { kind: "global", path }
|
|
213
|
+
: {
|
|
214
|
+
kind: "missing",
|
|
215
|
+
path: join(baseDir, "opencode.json"),
|
|
216
|
+
reason: "global OpenCode config missing",
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
function readEnvConfigSource(env, name) {
|
|
220
|
+
const value = env ? env[name] : process.env[name];
|
|
221
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
222
|
+
return undefined;
|
|
223
|
+
}
|
|
224
|
+
return { kind: "env", path: resolve(value.trim()), reason: name };
|
|
225
|
+
}
|
|
226
|
+
async function findExistingProjectOpenCodeConfigPath(projectRoot) {
|
|
227
|
+
return findExistingOpenCodeConfigPath(getProjectOpencodeDir(projectRoot));
|
|
228
|
+
}
|
|
229
|
+
async function findExistingOpenCodeConfigPath(baseDir) {
|
|
230
|
+
for (const name of OPENCODE_CONFIG_FILE_NAMES) {
|
|
231
|
+
const candidate = join(baseDir, name);
|
|
232
|
+
if (await pathExists(candidate)) {
|
|
233
|
+
return candidate;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return undefined;
|
|
237
|
+
}
|
|
238
|
+
async function selectExistingPath(candidates) {
|
|
239
|
+
for (const candidate of candidates) {
|
|
240
|
+
if (await pathExists(candidate)) {
|
|
241
|
+
return candidate;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
return candidates[0];
|
|
245
|
+
}
|
|
246
|
+
async function pathExists(path) {
|
|
247
|
+
try {
|
|
248
|
+
await access(path);
|
|
249
|
+
return true;
|
|
250
|
+
}
|
|
251
|
+
catch {
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
//# sourceMappingURL=config-layers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config-layers.js","sourceRoot":"","sources":["../../src/lib/config-layers.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/opencode.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type ManagedOpenCodeAgentName } from "./managed-agents.js";
|
|
2
2
|
import { type GuardianConfig, type GuardianConfigOverrides, type SecretsRedactionConfig, type VvocConfig } from "./vvoc-config.js";
|
|
3
3
|
import { PACKAGE_NAME } from "./package.js";
|
|
4
|
+
import { type ConfigReadScope, type ConfigSource } from "./config-layers.js";
|
|
4
5
|
export declare const CLI_NAME = "vvoc";
|
|
5
6
|
export { PACKAGE_NAME };
|
|
6
7
|
export declare const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
|
|
@@ -11,6 +12,7 @@ export type ResolvedPaths = {
|
|
|
11
12
|
scope: Scope;
|
|
12
13
|
cwd: string;
|
|
13
14
|
configHome: string;
|
|
15
|
+
projectRoot?: string;
|
|
14
16
|
opencodeBaseDir: string;
|
|
15
17
|
vvocBaseDir: string;
|
|
16
18
|
vvocConfigPath: string;
|
|
@@ -31,7 +33,7 @@ export type OpenCodeAgentOverride = {
|
|
|
31
33
|
};
|
|
32
34
|
export type ManagedAgentOverrideMap = Record<ManagedOpenCodeAgentName, OpenCodeAgentOverride>;
|
|
33
35
|
export type InstallationInspection = {
|
|
34
|
-
scope:
|
|
36
|
+
scope: ConfigReadScope;
|
|
35
37
|
opencode: {
|
|
36
38
|
path: string;
|
|
37
39
|
exists: boolean;
|
|
@@ -74,7 +76,7 @@ export declare function resolvePaths(options: {
|
|
|
74
76
|
configDir?: string;
|
|
75
77
|
}): Promise<ResolvedPaths>;
|
|
76
78
|
export declare function ensurePackageConfigText(text: string | undefined, packageSpecifier?: string): string;
|
|
77
|
-
export declare function ensureManagedAgentRegistrationsConfigText(text: string | undefined, paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "opencodeConfigPath">): string;
|
|
79
|
+
export declare function ensureManagedAgentRegistrationsConfigText(text: string | undefined, paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "managedSkillsDirPath" | "opencodeConfigPath">): string;
|
|
78
80
|
export declare function syncManagedAgentRegistrations(paths: ResolvedPaths): Promise<{
|
|
79
81
|
path: string;
|
|
80
82
|
changed: boolean;
|
|
@@ -107,7 +109,7 @@ export declare function writeOpenCodeDefaultModel(paths: Pick<ResolvedPaths, "op
|
|
|
107
109
|
ensureEntry: boolean;
|
|
108
110
|
}): Promise<WriteResult>;
|
|
109
111
|
export declare function writeOpenCodeProviderObject(paths: Pick<ResolvedPaths, "opencodeConfigPath">, providerID: string, value: JsonObject): Promise<WriteResult>;
|
|
110
|
-
export declare function writeManagedAgentModel(paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "opencodeConfigPath">, agentName: ManagedOpenCodeAgentName, options: {
|
|
112
|
+
export declare function writeManagedAgentModel(paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "managedSkillsDirPath" | "opencodeConfigPath">, agentName: ManagedOpenCodeAgentName, options: {
|
|
111
113
|
model?: string;
|
|
112
114
|
ensureEntry: boolean;
|
|
113
115
|
}): Promise<WriteResult>;
|
|
@@ -125,4 +127,12 @@ export declare function writeGuardianConfig(paths: Pick<ResolvedPaths, "vvocConf
|
|
|
125
127
|
merge?: boolean;
|
|
126
128
|
}): Promise<WriteResult>;
|
|
127
129
|
export declare function inspectInstallation(paths: ResolvedPaths): Promise<InstallationInspection>;
|
|
130
|
+
export declare function inspectInstallationForScope(options: {
|
|
131
|
+
scope: ConfigReadScope;
|
|
132
|
+
cwd: string;
|
|
133
|
+
configDir?: string;
|
|
134
|
+
}): Promise<InstallationInspection & {
|
|
135
|
+
opencodeSource: ConfigSource;
|
|
136
|
+
vvocSource: ConfigSource;
|
|
137
|
+
}>;
|
|
128
138
|
export declare function describeWriteResult(result: WriteResult): string;
|
package/dist/lib/opencode.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// FILE: src/lib/opencode.ts
|
|
2
2
|
// VERSION: 1.0.0
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
|
-
// PURPOSE: Manage OpenCode config mutation, provider patching, and
|
|
5
|
-
// SCOPE:
|
|
6
|
-
// DEPENDS: [jsonc-parser, node:fs/promises, node:path, src/lib/managed-agents.ts, src/lib/managed-skills.ts, src/lib/package.ts, src/lib/vvoc-config.ts, src/lib/vvoc-paths.ts]
|
|
4
|
+
// PURPOSE: Manage OpenCode config mutation, provider patching, and scoped vvoc.json config files.
|
|
5
|
+
// SCOPE: Layer-aware path resolution, pinned plugin writes, managed OpenCode defaults, local skills path registration, provider patching, managed prompts/skills, version-aware vvoc config rendering, and installation inspection.
|
|
6
|
+
// DEPENDS: [jsonc-parser, node:fs/promises, node:path, src/lib/config-layers.ts, src/lib/managed-agents.ts, src/lib/managed-skills.ts, src/lib/package.ts, src/lib/vvoc-config.ts, src/lib/vvoc-paths.ts]
|
|
7
7
|
// LINKS: [M-CLI-CONFIG]
|
|
8
8
|
// ROLE: RUNTIME
|
|
9
9
|
// MAP_MODE: EXPORTS
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
// writeManagedAgentModel - Writes or removes a bundled vvoc-managed OpenCode agent model override in OpenCode config.
|
|
46
46
|
// writeGuardianConfig - Writes the guardian section into the canonical vvoc.json document.
|
|
47
47
|
// inspectInstallation - Reads current OpenCode/vvoc installation state for status and doctor commands.
|
|
48
|
+
// inspectInstallationForScope - Reads installation state using strict/effective layered source resolution.
|
|
48
49
|
// describeWriteResult - Formats config write outcomes for CLI output.
|
|
49
50
|
// ManagedAgentModelMap - Map of managed agent names to model selections.
|
|
50
51
|
// OpenCodeAgentOverride - Agent override config for OpenCode.
|
|
@@ -56,6 +57,8 @@
|
|
|
56
57
|
// END_MODULE_MAP
|
|
57
58
|
//
|
|
58
59
|
// START_CHANGE_SUMMARY
|
|
60
|
+
// LAST_CHANGE: [v1.1.1 - Fixed syncManagedSkillFiles to not sync references when parent skill is skipped (user-owned/custom). Added regression coverage.]
|
|
61
|
+
// LAST_CHANGE: [v1.1.0 - Switched project-scope writes to .opencode/.vvoc layers and added local managed skills path registration.]
|
|
59
62
|
// LAST_CHANGE: [v0.5.1 - Added ensureManagedSkillSymlink. Fixed renderManagedSkill to preserve YAML frontmatter.]
|
|
60
63
|
// LAST_CHANGE: [v1.0.1 - Added managed plan directory resolution and creation for analyst/architect artifacts.]
|
|
61
64
|
// LAST_CHANGE: [v0.5.0 - Replaced managed command registrations (vv-plan/vv-review) with managed skills system. Added managedSkillsDirPath to ResolvedPaths. Added installManagedSkillFiles and syncManagedSkillFiles.]
|
|
@@ -76,7 +79,8 @@ import { MANAGED_SKILL_NAMES, getManagedSkillFilePath, listManagedSkillReference
|
|
|
76
79
|
import { BUILTIN_ROLE_NAMES, getBuiltInRoleBindings, ROLE_REFERENCE_PREFIX, } from "./model-roles.js";
|
|
77
80
|
import { createDefaultVvocConfig, createGuardianConfig, parseVersionedVvocConfigText, parseVvocConfigText, renderVvocConfig, } from "./vvoc-config.js";
|
|
78
81
|
import { getPinnedPackageSpecifier, PACKAGE_NAME } from "./package.js";
|
|
79
|
-
import {
|
|
82
|
+
import { resolveConfigWriteTargets, resolveOpenCodeConfigSource, resolveVvocConfigSource, } from "./config-layers.js";
|
|
83
|
+
import { getConfigHome, getGlobalOpencodeSkillsDir, getGlobalVvocDir, getVvocAgentsDir, getVvocPlansDir, getVvocSkillsDir, } from "./vvoc-paths.js";
|
|
80
84
|
export const CLI_NAME = "vvoc";
|
|
81
85
|
export { PACKAGE_NAME };
|
|
82
86
|
export const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
|
|
@@ -111,26 +115,24 @@ const JSON_FORMAT = {
|
|
|
111
115
|
};
|
|
112
116
|
// START_BLOCK_RESOLVE_CONFIG_PATHS
|
|
113
117
|
export async function resolvePaths(options) {
|
|
118
|
+
const targets = await resolveConfigWriteTargets(options);
|
|
114
119
|
const configHome = getConfigHome(options.configDir);
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
const
|
|
118
|
-
const managedAgentsDirPath = getVvocAgentsDir(managedAgentsBaseDir);
|
|
119
|
-
const managedPlansDirPath = getVvocPlansDir(managedAgentsBaseDir);
|
|
120
|
-
const managedSkillsDirPath = getVvocSkillsDir(managedAgentsBaseDir);
|
|
121
|
-
const opencodeSelection = await selectPrimaryPath(OPENCODE_CONFIG_FILE_NAMES.map((name) => join(opencodeBaseDir, name)));
|
|
120
|
+
const managedAgentsDirPath = getVvocAgentsDir(targets.vvocBaseDir);
|
|
121
|
+
const managedPlansDirPath = getVvocPlansDir(targets.vvocBaseDir);
|
|
122
|
+
const managedSkillsDirPath = getVvocSkillsDir(targets.vvocBaseDir);
|
|
122
123
|
return {
|
|
123
124
|
scope: options.scope,
|
|
124
125
|
cwd: options.cwd,
|
|
125
126
|
configHome,
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
127
|
+
projectRoot: targets.projectRoot,
|
|
128
|
+
opencodeBaseDir: targets.opencodeBaseDir,
|
|
129
|
+
vvocBaseDir: targets.vvocBaseDir,
|
|
130
|
+
vvocConfigPath: targets.vvocConfigPath,
|
|
129
131
|
managedAgentsDirPath,
|
|
130
132
|
managedPlansDirPath,
|
|
131
133
|
managedSkillsDirPath,
|
|
132
|
-
opencodeConfigPath:
|
|
133
|
-
opencodeAlternatePaths:
|
|
134
|
+
opencodeConfigPath: targets.opencodeConfigPath,
|
|
135
|
+
opencodeAlternatePaths: await resolveOpenCodeAlternates(targets.opencodeBaseDir, targets.opencodeConfigPath),
|
|
134
136
|
};
|
|
135
137
|
}
|
|
136
138
|
// END_BLOCK_RESOLVE_CONFIG_PATHS
|
|
@@ -187,6 +189,9 @@ export function ensureManagedAgentRegistrationsConfigText(text, paths) {
|
|
|
187
189
|
...Object.fromEntries(Object.entries(builtInAgentModelRefs).map(([name, model]) => [name, { model }])),
|
|
188
190
|
...managedRegistrations,
|
|
189
191
|
},
|
|
192
|
+
skills: {
|
|
193
|
+
paths: [getManagedSkillsPathReference(paths)],
|
|
194
|
+
},
|
|
190
195
|
command: {},
|
|
191
196
|
});
|
|
192
197
|
}
|
|
@@ -252,7 +257,7 @@ export function ensureManagedAgentRegistrationsConfigText(text, paths) {
|
|
|
252
257
|
}));
|
|
253
258
|
}
|
|
254
259
|
}
|
|
255
|
-
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
260
|
+
return ensureManagedSkillsPathConfigText(ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT))), paths);
|
|
256
261
|
}
|
|
257
262
|
export async function syncManagedAgentRegistrations(paths) {
|
|
258
263
|
const currentText = await readOptionalText(paths.opencodeConfigPath);
|
|
@@ -341,9 +346,13 @@ export async function installManagedSkillFiles(paths, options) {
|
|
|
341
346
|
export async function syncManagedSkillFiles(paths, options) {
|
|
342
347
|
const results = [];
|
|
343
348
|
for (const skillName of MANAGED_SKILL_NAMES) {
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
349
|
+
const skillResult = await syncManagedSkill(paths, skillName, options);
|
|
350
|
+
results.push(skillResult);
|
|
351
|
+
// Only sync references when the parent skill was not skipped (user-owned/custom)
|
|
352
|
+
if (skillResult.action !== "skipped") {
|
|
353
|
+
const refResults = await syncManagedSkillReferences(paths.managedSkillsDirPath, skillName);
|
|
354
|
+
results.push(...refResults);
|
|
355
|
+
}
|
|
347
356
|
}
|
|
348
357
|
return results;
|
|
349
358
|
}
|
|
@@ -682,6 +691,52 @@ export async function inspectInstallation(paths) {
|
|
|
682
691
|
problems,
|
|
683
692
|
};
|
|
684
693
|
}
|
|
694
|
+
export async function inspectInstallationForScope(options) {
|
|
695
|
+
const [opencodeSource, vvocSource] = await Promise.all([
|
|
696
|
+
resolveOpenCodeConfigSource({
|
|
697
|
+
scope: options.scope,
|
|
698
|
+
cwd: options.cwd,
|
|
699
|
+
configDir: options.configDir,
|
|
700
|
+
}),
|
|
701
|
+
resolveVvocConfigSource({
|
|
702
|
+
scope: options.scope,
|
|
703
|
+
cwd: options.cwd,
|
|
704
|
+
configDir: options.configDir,
|
|
705
|
+
allowDefault: options.scope === "effective",
|
|
706
|
+
}),
|
|
707
|
+
]);
|
|
708
|
+
if (options.scope === "project") {
|
|
709
|
+
const missingSource = [opencodeSource, vvocSource].find((source) => source.kind === "missing");
|
|
710
|
+
if (missingSource) {
|
|
711
|
+
throw new Error(missingSource.reason ?? "project config missing; run vvoc install --scope project");
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
const fallbackPaths = await resolvePaths({
|
|
715
|
+
scope: options.scope === "global" ? "global" : "project",
|
|
716
|
+
cwd: options.cwd,
|
|
717
|
+
configDir: options.configDir,
|
|
718
|
+
});
|
|
719
|
+
const opencodeConfigPath = opencodeSource.path ?? fallbackPaths.opencodeConfigPath;
|
|
720
|
+
const vvocConfigPath = vvocSource.path ?? fallbackPaths.vvocConfigPath;
|
|
721
|
+
const scopedPaths = {
|
|
722
|
+
...fallbackPaths,
|
|
723
|
+
opencodeBaseDir: dirname(opencodeConfigPath),
|
|
724
|
+
vvocBaseDir: dirname(vvocConfigPath),
|
|
725
|
+
opencodeConfigPath,
|
|
726
|
+
vvocConfigPath,
|
|
727
|
+
opencodeAlternatePaths: [],
|
|
728
|
+
managedAgentsDirPath: getVvocAgentsDir(dirname(vvocConfigPath)),
|
|
729
|
+
managedPlansDirPath: getVvocPlansDir(dirname(vvocConfigPath)),
|
|
730
|
+
managedSkillsDirPath: getVvocSkillsDir(dirname(vvocConfigPath)),
|
|
731
|
+
};
|
|
732
|
+
const inspection = await inspectInstallation(scopedPaths);
|
|
733
|
+
return {
|
|
734
|
+
...inspection,
|
|
735
|
+
scope: options.scope,
|
|
736
|
+
opencodeSource,
|
|
737
|
+
vvocSource,
|
|
738
|
+
};
|
|
739
|
+
}
|
|
685
740
|
// END_BLOCK_INSPECT_INSTALLATION_STATE
|
|
686
741
|
export function describeWriteResult(result) {
|
|
687
742
|
let message = "";
|
|
@@ -726,6 +781,12 @@ function readPluginList(document, label) {
|
|
|
726
781
|
}
|
|
727
782
|
return raw.slice();
|
|
728
783
|
}
|
|
784
|
+
function readStringArray(value, label) {
|
|
785
|
+
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
786
|
+
throw new Error(`${label}: expected an array of strings`);
|
|
787
|
+
}
|
|
788
|
+
return value.slice();
|
|
789
|
+
}
|
|
729
790
|
function normalizePluginList(currentPlugins, packageSpecifier) {
|
|
730
791
|
const nextPlugins = [];
|
|
731
792
|
const seen = new Set();
|
|
@@ -873,6 +934,25 @@ function getManagedOpenCodeAgentPromptReference(paths, agentName) {
|
|
|
873
934
|
const promptRef = relative(dirname(paths.opencodeConfigPath), promptPath).replaceAll("\\", "/");
|
|
874
935
|
return `{file:${promptRef.startsWith(".") ? promptRef : `./${promptRef}`}}`;
|
|
875
936
|
}
|
|
937
|
+
function getManagedSkillsPathReference(paths) {
|
|
938
|
+
const skillsRef = relative(dirname(paths.opencodeConfigPath), paths.managedSkillsDirPath).replaceAll("\\", "/");
|
|
939
|
+
return skillsRef.startsWith(".") ? skillsRef : `./${skillsRef}`;
|
|
940
|
+
}
|
|
941
|
+
function ensureManagedSkillsPathConfigText(text, paths) {
|
|
942
|
+
const document = parseObjectDocument(text, "OpenCode config");
|
|
943
|
+
const skills = readOptionalObject(document, "skills", "OpenCode config");
|
|
944
|
+
const rawPaths = skills?.paths;
|
|
945
|
+
const currentPaths = rawPaths === undefined ? [] : readStringArray(rawPaths, "OpenCode config: skills.paths");
|
|
946
|
+
const managedSkillsPath = getManagedSkillsPathReference(paths);
|
|
947
|
+
if (currentPaths.includes(managedSkillsPath)) {
|
|
948
|
+
return text;
|
|
949
|
+
}
|
|
950
|
+
const nextPaths = [...currentPaths, managedSkillsPath];
|
|
951
|
+
const nextText = applyEdits(text, modify(text, ["skills", "paths"], nextPaths, {
|
|
952
|
+
formattingOptions: JSON_FORMAT,
|
|
953
|
+
}));
|
|
954
|
+
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
955
|
+
}
|
|
876
956
|
function getLegacyTrackedManagedPromptReferences(paths, agentName) {
|
|
877
957
|
const promptPath = join(paths.managedAgentsDirPath, LEGACY_TRACKED_PROMPT_FILE_NAMES[agentName]);
|
|
878
958
|
const promptRef = relative(dirname(paths.opencodeConfigPath), promptPath).replaceAll("\\", "/");
|
|
@@ -1188,17 +1268,14 @@ async function writeText(path, text) {
|
|
|
1188
1268
|
await mkdir(dirname(path), { recursive: true });
|
|
1189
1269
|
await writeFile(path, text, "utf8");
|
|
1190
1270
|
}
|
|
1191
|
-
async function
|
|
1192
|
-
const
|
|
1193
|
-
for (const candidate of
|
|
1194
|
-
if ((await readOptionalText(candidate)) !== undefined) {
|
|
1195
|
-
|
|
1271
|
+
async function resolveOpenCodeAlternates(opencodeBaseDir, selectedPath) {
|
|
1272
|
+
const alternates = [];
|
|
1273
|
+
for (const candidate of OPENCODE_CONFIG_FILE_NAMES.map((name) => join(opencodeBaseDir, name))) {
|
|
1274
|
+
if (candidate !== selectedPath && (await readOptionalText(candidate)) !== undefined) {
|
|
1275
|
+
alternates.push(candidate);
|
|
1196
1276
|
}
|
|
1197
1277
|
}
|
|
1198
|
-
return
|
|
1199
|
-
primary: existing[0] ?? candidates[0],
|
|
1200
|
-
alternates: existing.slice(1),
|
|
1201
|
-
};
|
|
1278
|
+
return alternates;
|
|
1202
1279
|
}
|
|
1203
1280
|
// END_BLOCK_FILESYSTEM_HELPERS
|
|
1204
1281
|
//# sourceMappingURL=opencode.js.map
|