@osovv/vv-opencode 0.5.5 → 0.6.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 +36 -2
- package/dist/commands/agent.js +124 -79
- package/dist/commands/agent.js.map +1 -1
- package/dist/commands/completion.js +40 -4
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/init.js +13 -4
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install.js +11 -4
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/sync.js +10 -4
- package/dist/commands/sync.js.map +1 -1
- package/dist/lib/managed-agents.d.ts +13 -0
- package/dist/lib/managed-agents.js +83 -0
- package/dist/lib/managed-agents.js.map +1 -0
- package/dist/lib/opencode.d.ts +19 -0
- package/dist/lib/opencode.js +227 -6
- package/dist/lib/opencode.js.map +1 -1
- package/dist/lib/vvoc-paths.d.ts +1 -0
- package/dist/lib/vvoc-paths.js +7 -3
- package/dist/lib/vvoc-paths.js.map +1 -1
- package/dist/plugins/guardian/policy.md +50 -0
- package/dist/plugins/memory/reviewer.md +25 -0
- package/dist/plugins/memory/system-instruction.md +8 -0
- package/package.json +4 -3
- package/templates/agents/code-reviewer.md +8 -0
- package/templates/agents/implementer.md +11 -0
- package/templates/agents/investitagor.md +11 -0
- package/templates/agents/spec-reviewer.md +8 -0
package/dist/commands/install.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// FILE: src/commands/install.ts
|
|
2
|
-
// VERSION: 0.2.
|
|
2
|
+
// VERSION: 0.2.6
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Install vv-opencode into OpenCode config and bootstrap vvoc-managed config files.
|
|
5
|
-
// SCOPE: Scope parsing, path resolution, pinned plugin registration, and initial Guardian/Memory config creation.
|
|
5
|
+
// SCOPE: Scope parsing, path resolution, pinned plugin registration, managed subagent prompt scaffolding, and initial Guardian/Memory config creation.
|
|
6
6
|
// DEPENDS: [citty, src/lib/opencode.ts]
|
|
7
7
|
// LINKS: [M-CLI-COMMANDS, M-CLI-CONFIG]
|
|
8
8
|
// ROLE: RUNTIME
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
// END_MODULE_MAP
|
|
15
15
|
//
|
|
16
16
|
// START_CHANGE_SUMMARY
|
|
17
|
-
// LAST_CHANGE: [v0.2.
|
|
17
|
+
// LAST_CHANGE: [v0.2.6 - Added managed subagent registration and prompt scaffolding to install.]
|
|
18
18
|
// END_CHANGE_SUMMARY
|
|
19
19
|
import { defineCommand } from "citty";
|
|
20
|
-
import { describeWriteResult, ensurePackageInstalled, installGuardianConfig, installMemoryConfig, installSecretsRedactionConfig, resolvePaths, } from "../lib/opencode.js";
|
|
20
|
+
import { describeWriteResult, ensurePackageInstalled, installGuardianConfig, installManagedSubagentPrompts, installMemoryConfig, installSecretsRedactionConfig, resolvePaths, syncManagedSubagentRegistrations, } from "../lib/opencode.js";
|
|
21
21
|
export default defineCommand({
|
|
22
22
|
meta: {
|
|
23
23
|
name: "install",
|
|
@@ -64,7 +64,14 @@ export default defineCommand({
|
|
|
64
64
|
configDir,
|
|
65
65
|
});
|
|
66
66
|
const opencode = await ensurePackageInstalled(paths);
|
|
67
|
+
const managedSubagents = await syncManagedSubagentRegistrations(paths);
|
|
67
68
|
console.log(`${opencode.changed ? "Updated" : "Kept"} ${opencode.path}`);
|
|
69
|
+
console.log(`${managedSubagents.changed ? "Updated" : "Kept"} ${managedSubagents.path} (managed subagents)`);
|
|
70
|
+
for (const result of await installManagedSubagentPrompts(paths, {
|
|
71
|
+
force: Boolean(args.force),
|
|
72
|
+
})) {
|
|
73
|
+
console.log(describeWriteResult(result));
|
|
74
|
+
}
|
|
68
75
|
if (args["guardian-config"] === false) {
|
|
69
76
|
console.log(`Skipped ${paths.guardianConfigPath} (guardian config disabled)`);
|
|
70
77
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA,gCAAgC;AAChC,iBAAiB;AACjB,wBAAwB;AACxB,+FAA+F;AAC/F,
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// FILE: src/commands/sync.ts
|
|
2
|
-
// VERSION: 0.2.
|
|
2
|
+
// VERSION: 0.2.6
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Sync managed vvoc config files and keep the OpenCode plugin specifier current.
|
|
5
|
-
// SCOPE: Scope parsing, path resolution, pinned plugin sync, and managed Guardian/Memory config rewrites.
|
|
5
|
+
// SCOPE: Scope parsing, path resolution, pinned plugin sync, managed subagent prompt sync, and managed Guardian/Memory config rewrites.
|
|
6
6
|
// DEPENDS: [citty, src/lib/opencode.ts]
|
|
7
7
|
// LINKS: [M-CLI-COMMANDS, M-CLI-CONFIG]
|
|
8
8
|
// ROLE: RUNTIME
|
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
// END_MODULE_MAP
|
|
15
15
|
//
|
|
16
16
|
// START_CHANGE_SUMMARY
|
|
17
|
-
// LAST_CHANGE: [v0.2.
|
|
17
|
+
// LAST_CHANGE: [v0.2.6 - Added managed subagent registration and prompt syncing to vvoc sync.]
|
|
18
18
|
// END_CHANGE_SUMMARY
|
|
19
19
|
import { defineCommand } from "citty";
|
|
20
|
-
import { describeWriteResult, ensurePackageInstalled, resolvePaths, syncGuardianConfig, syncMemoryConfig, } from "../lib/opencode.js";
|
|
20
|
+
import { describeWriteResult, ensurePackageInstalled, resolvePaths, syncManagedSubagentPrompts, syncManagedSubagentRegistrations, syncGuardianConfig, syncMemoryConfig, } from "../lib/opencode.js";
|
|
21
21
|
export default defineCommand({
|
|
22
22
|
meta: {
|
|
23
23
|
name: "sync",
|
|
@@ -49,9 +49,15 @@ export default defineCommand({
|
|
|
49
49
|
configDir,
|
|
50
50
|
});
|
|
51
51
|
const opencode = await ensurePackageInstalled(paths);
|
|
52
|
+
const managedSubagents = await syncManagedSubagentRegistrations(paths);
|
|
53
|
+
const managedPrompts = await syncManagedSubagentPrompts(paths, { force: Boolean(args.force) });
|
|
52
54
|
const guardian = await syncGuardianConfig(paths, { force: Boolean(args.force) });
|
|
53
55
|
const memory = await syncMemoryConfig(paths, { force: Boolean(args.force) });
|
|
54
56
|
console.log(`${opencode.changed ? "Updated" : "Kept"} ${opencode.path}`);
|
|
57
|
+
console.log(`${managedSubagents.changed ? "Updated" : "Kept"} ${managedSubagents.path} (managed subagents)`);
|
|
58
|
+
for (const result of managedPrompts) {
|
|
59
|
+
console.log(describeWriteResult(result));
|
|
60
|
+
}
|
|
55
61
|
console.log(describeWriteResult(guardian));
|
|
56
62
|
console.log(describeWriteResult(memory));
|
|
57
63
|
// END_BLOCK_APPLY_SYNC_COMMAND
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,6BAA6B;AAC7B,iBAAiB;AACjB,wBAAwB;AACxB,4FAA4F;AAC5F,
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const MANAGED_SUBAGENT_NAMES: readonly ["implementer", "spec-reviewer", "code-reviewer", "investitagor"];
|
|
2
|
+
export type ManagedSubagentName = (typeof MANAGED_SUBAGENT_NAMES)[number];
|
|
3
|
+
export type ManagedSubagentDefinition = {
|
|
4
|
+
name: ManagedSubagentName;
|
|
5
|
+
description: string;
|
|
6
|
+
promptFileName: `${ManagedSubagentName}.md`;
|
|
7
|
+
steps?: number;
|
|
8
|
+
permission?: Record<string, unknown>;
|
|
9
|
+
};
|
|
10
|
+
export declare const MANAGED_SUBAGENTS: readonly ManagedSubagentDefinition[];
|
|
11
|
+
export declare function isManagedSubagentName(value: string): value is ManagedSubagentName;
|
|
12
|
+
export declare function getManagedSubagentDefinition(name: ManagedSubagentName): ManagedSubagentDefinition;
|
|
13
|
+
export declare function loadManagedSubagentTemplate(name: ManagedSubagentName): Promise<string>;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
// FILE: src/lib/managed-agents.ts
|
|
2
|
+
// VERSION: 0.1.0
|
|
3
|
+
// START_MODULE_CONTRACT
|
|
4
|
+
// PURPOSE: Describe vvoc-managed OpenCode subagents and load their bundled prompt templates.
|
|
5
|
+
// SCOPE: Built-in subagent metadata, name validation, definition lookup, and template file loading from package assets.
|
|
6
|
+
// DEPENDS: [node:fs/promises]
|
|
7
|
+
// LINKS: [M-CLI-CONFIG]
|
|
8
|
+
// ROLE: RUNTIME
|
|
9
|
+
// MAP_MODE: EXPORTS
|
|
10
|
+
// END_MODULE_CONTRACT
|
|
11
|
+
//
|
|
12
|
+
// START_MODULE_MAP
|
|
13
|
+
// ManagedSubagentName - Canonical vvoc-managed subagent names.
|
|
14
|
+
// ManagedSubagentDefinition - Metadata used to register a managed subagent in OpenCode config.
|
|
15
|
+
// MANAGED_SUBAGENT_NAMES - Ordered managed subagent names.
|
|
16
|
+
// MANAGED_SUBAGENTS - Built-in managed subagent definitions.
|
|
17
|
+
// isManagedSubagentName - Checks whether a string is one of the managed subagent names.
|
|
18
|
+
// getManagedSubagentDefinition - Returns metadata for a managed subagent.
|
|
19
|
+
// loadManagedSubagentTemplate - Loads the bundled prompt template for a managed subagent.
|
|
20
|
+
// END_MODULE_MAP
|
|
21
|
+
//
|
|
22
|
+
// START_CHANGE_SUMMARY
|
|
23
|
+
// LAST_CHANGE: [v0.1.0 - Added bundled metadata and asset-backed prompt loading for vvoc-managed subagents.]
|
|
24
|
+
// END_CHANGE_SUMMARY
|
|
25
|
+
import { readFile } from "node:fs/promises";
|
|
26
|
+
export const MANAGED_SUBAGENT_NAMES = [
|
|
27
|
+
"implementer",
|
|
28
|
+
"spec-reviewer",
|
|
29
|
+
"code-reviewer",
|
|
30
|
+
"investitagor",
|
|
31
|
+
];
|
|
32
|
+
export const MANAGED_SUBAGENTS = [
|
|
33
|
+
{
|
|
34
|
+
name: "implementer",
|
|
35
|
+
description: "Implements approved changes with focused verification and a minimal diff.",
|
|
36
|
+
promptFileName: "implementer.md",
|
|
37
|
+
steps: 8,
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
name: "spec-reviewer",
|
|
41
|
+
description: "Checks an implementation against the requested spec and flags missing or extra behavior.",
|
|
42
|
+
promptFileName: "spec-reviewer.md",
|
|
43
|
+
steps: 6,
|
|
44
|
+
permission: {
|
|
45
|
+
edit: "deny",
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "code-reviewer",
|
|
50
|
+
description: "Reviews changes for bugs, regressions, maintainability risks, and missing tests.",
|
|
51
|
+
promptFileName: "code-reviewer.md",
|
|
52
|
+
steps: 6,
|
|
53
|
+
permission: {
|
|
54
|
+
edit: "deny",
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
name: "investitagor",
|
|
59
|
+
description: "Investigates bugs and unclear behavior before implementation work begins.",
|
|
60
|
+
promptFileName: "investitagor.md",
|
|
61
|
+
steps: 6,
|
|
62
|
+
permission: {
|
|
63
|
+
edit: "deny",
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
];
|
|
67
|
+
const MANAGED_SUBAGENT_MAP = new Map(MANAGED_SUBAGENTS.map((definition) => [definition.name, definition]));
|
|
68
|
+
export function isManagedSubagentName(value) {
|
|
69
|
+
return MANAGED_SUBAGENT_MAP.has(value);
|
|
70
|
+
}
|
|
71
|
+
export function getManagedSubagentDefinition(name) {
|
|
72
|
+
const definition = MANAGED_SUBAGENT_MAP.get(name);
|
|
73
|
+
if (!definition) {
|
|
74
|
+
throw new Error(`unknown managed subagent: ${name}`);
|
|
75
|
+
}
|
|
76
|
+
return definition;
|
|
77
|
+
}
|
|
78
|
+
export async function loadManagedSubagentTemplate(name) {
|
|
79
|
+
const definition = getManagedSubagentDefinition(name);
|
|
80
|
+
const assetUrl = new URL(`../../templates/agents/${definition.promptFileName}`, import.meta.url);
|
|
81
|
+
return readFile(assetUrl, "utf8");
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=managed-agents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"managed-agents.js","sourceRoot":"","sources":["../../src/lib/managed-agents.ts"],"names":[],"mappings":"AAAA,kCAAkC;AAClC,iBAAiB;AACjB,wBAAwB;AACxB,+FAA+F;AAC/F,0HAA0H;AAC1H,gCAAgC;AAChC,0BAA0B;AAC1B,kBAAkB;AAClB,sBAAsB;AACtB,sBAAsB;AACtB,EAAE;AACF,mBAAmB;AACnB,iEAAiE;AACjE,iGAAiG;AACjG,6DAA6D;AAC7D,+DAA+D;AAC/D,0FAA0F;AAC1F,4EAA4E;AAC5E,4FAA4F;AAC5F,iBAAiB;AACjB,EAAE;AACF,uBAAuB;AACvB,+GAA+G;AAC/G,qBAAqB;AAErB,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,aAAa;IACb,eAAe;IACf,eAAe;IACf,cAAc;CACN,CAAC;AAYX,MAAM,CAAC,MAAM,iBAAiB,GAAyC;IACrE;QACE,IAAI,EAAE,aAAa;QACnB,WAAW,EAAE,2EAA2E;QACxF,cAAc,EAAE,gBAAgB;QAChC,KAAK,EAAE,CAAC;KACT;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EACT,0FAA0F;QAC5F,cAAc,EAAE,kBAAkB;QAClC,KAAK,EAAE,CAAC;QACR,UAAU,EAAE;YACV,IAAI,EAAE,MAAM;SACb;KACF;IACD;QACE,IAAI,EAAE,eAAe;QACrB,WAAW,EAAE,kFAAkF;QAC/F,cAAc,EAAE,kBAAkB;QAClC,KAAK,EAAE,CAAC;QACR,UAAU,EAAE;YACV,IAAI,EAAE,MAAM;SACb;KACF;IACD;QACE,IAAI,EAAE,cAAc;QACpB,WAAW,EAAE,2EAA2E;QACxF,cAAc,EAAE,iBAAiB;QACjC,KAAK,EAAE,CAAC;QACR,UAAU,EAAE;YACV,IAAI,EAAE,MAAM;SACb;KACF;CACF,CAAC;AAEF,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAClC,iBAAiB,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC,CACrE,CAAC;AAEF,MAAM,UAAU,qBAAqB,CAAC,KAAa;IACjD,OAAO,oBAAoB,CAAC,GAAG,CAAC,KAA4B,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,4BAA4B,CAAC,IAAyB;IACpE,MAAM,UAAU,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,EAAE,CAAC,CAAC;IACvD,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,IAAyB;IACzE,MAAM,UAAU,GAAG,4BAA4B,CAAC,IAAI,CAAC,CAAC;IACtD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,0BAA0B,UAAU,CAAC,cAAc,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACjG,OAAO,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AACpC,CAAC"}
|
package/dist/lib/opencode.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ManagedSubagentName } from "./managed-agents.js";
|
|
1
2
|
import { type MemoryConfigOverrides } from "../plugins/memory-store.js";
|
|
2
3
|
import { PACKAGE_NAME } from "./package.js";
|
|
3
4
|
export declare const CLI_NAME = "vvoc";
|
|
@@ -10,6 +11,7 @@ export type ResolvedPaths = {
|
|
|
10
11
|
configHome: string;
|
|
11
12
|
opencodeBaseDir: string;
|
|
12
13
|
vvocBaseDir: string;
|
|
14
|
+
managedAgentsDirPath: string;
|
|
13
15
|
opencodeConfigPath: string;
|
|
14
16
|
opencodeAlternatePaths: string[];
|
|
15
17
|
guardianConfigPath: string;
|
|
@@ -31,6 +33,7 @@ export type WriteResult = {
|
|
|
31
33
|
path: string;
|
|
32
34
|
reason?: string;
|
|
33
35
|
};
|
|
36
|
+
export type ManagedSubagentModelMap = Record<ManagedSubagentName, string | undefined>;
|
|
34
37
|
export type InstallationInspection = {
|
|
35
38
|
scope: Scope;
|
|
36
39
|
opencode: {
|
|
@@ -73,6 +76,22 @@ export declare function resolvePaths(options: {
|
|
|
73
76
|
configDir?: string;
|
|
74
77
|
}): Promise<ResolvedPaths>;
|
|
75
78
|
export declare function ensurePackageConfigText(text: string | undefined, packageSpecifier?: string): string;
|
|
79
|
+
export declare function ensureManagedSubagentsConfigText(text: string | undefined, paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "opencodeConfigPath">): string;
|
|
80
|
+
export declare function syncManagedSubagentRegistrations(paths: ResolvedPaths): Promise<{
|
|
81
|
+
path: string;
|
|
82
|
+
changed: boolean;
|
|
83
|
+
}>;
|
|
84
|
+
export declare function installManagedSubagentPrompts(paths: ResolvedPaths, options: {
|
|
85
|
+
force: boolean;
|
|
86
|
+
}): Promise<WriteResult[]>;
|
|
87
|
+
export declare function syncManagedSubagentPrompts(paths: ResolvedPaths, options: {
|
|
88
|
+
force: boolean;
|
|
89
|
+
}): Promise<WriteResult[]>;
|
|
90
|
+
export declare function readManagedSubagentModels(paths: Pick<ResolvedPaths, "opencodeConfigPath">): Promise<ManagedSubagentModelMap>;
|
|
91
|
+
export declare function writeManagedSubagentModel(paths: Pick<ResolvedPaths, "managedAgentsDirPath" | "opencodeConfigPath">, agentName: ManagedSubagentName, options: {
|
|
92
|
+
model?: string;
|
|
93
|
+
ensureEntry: boolean;
|
|
94
|
+
}): Promise<WriteResult>;
|
|
76
95
|
export declare function parseGuardianConfigText(text: string, label: string): GuardianConfigOverrides;
|
|
77
96
|
export declare function renderGuardianConfig(overrides?: GuardianConfigOverrides): string;
|
|
78
97
|
export declare function ensurePackageInstalled(paths: ResolvedPaths): Promise<{
|
package/dist/lib/opencode.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// FILE: src/lib/opencode.ts
|
|
2
|
-
// VERSION: 0.2.
|
|
2
|
+
// VERSION: 0.2.6
|
|
3
3
|
// START_MODULE_CONTRACT
|
|
4
4
|
// PURPOSE: Manage OpenCode plugin registration and vvoc-owned config files.
|
|
5
|
-
// SCOPE: Scope-aware path resolution, pinned plugin writes, Guardian/Memory config rendering and sync, and installation inspection.
|
|
6
|
-
// DEPENDS: [jsonc-parser, node:fs/promises, node:path, src/lib/package.ts, src/lib/vvoc-paths.ts, src/plugins/memory-store.ts]
|
|
5
|
+
// SCOPE: Scope-aware path resolution, pinned plugin writes, managed subagent registration/prompt sync, Guardian/Memory config rendering and sync, and installation inspection.
|
|
6
|
+
// DEPENDS: [jsonc-parser, node:fs/promises, node:path, src/lib/managed-agents.ts, src/lib/package.ts, src/lib/vvoc-paths.ts, src/plugins/memory-store.ts]
|
|
7
7
|
// LINKS: [M-CLI-CONFIG]
|
|
8
8
|
// ROLE: RUNTIME
|
|
9
9
|
// MAP_MODE: EXPORTS
|
|
@@ -20,9 +20,15 @@
|
|
|
20
20
|
// InstallationInspection - Current OpenCode and vvoc installation status snapshot.
|
|
21
21
|
// resolvePaths - Resolves OpenCode and vvoc config paths for global/project scopes.
|
|
22
22
|
// ensurePackageConfigText - Ensures OpenCode config contains the pinned vvoc plugin specifier.
|
|
23
|
+
// ensureManagedSubagentsConfigText - Ensures OpenCode config contains the vvoc-managed subagent registrations.
|
|
23
24
|
// parseGuardianConfigText - Parses Guardian config JSONC into typed overrides.
|
|
24
25
|
// renderGuardianConfig - Renders managed Guardian config JSONC.
|
|
25
26
|
// ensurePackageInstalled - Writes the pinned vvoc plugin specifier into OpenCode config.
|
|
27
|
+
// syncManagedSubagentRegistrations - Syncs the canonical vvoc-managed subagent registrations into OpenCode config.
|
|
28
|
+
// installManagedSubagentPrompts - Creates managed vvoc prompt files for the bundled subagents when missing.
|
|
29
|
+
// syncManagedSubagentPrompts - Rewrites managed vvoc prompt files for the bundled subagents.
|
|
30
|
+
// readManagedSubagentModels - Reads model overrides for the bundled vvoc subagents from OpenCode config.
|
|
31
|
+
// writeManagedSubagentModel - Writes or removes a bundled vvoc subagent model override in OpenCode config.
|
|
26
32
|
// installGuardianConfig - Creates or preserves managed Guardian config.
|
|
27
33
|
// syncGuardianConfig - Rewrites managed Guardian config while preserving current values.
|
|
28
34
|
// writeGuardianConfig - Writes explicit Guardian overrides to managed config.
|
|
@@ -33,14 +39,15 @@
|
|
|
33
39
|
// END_MODULE_MAP
|
|
34
40
|
//
|
|
35
41
|
// START_CHANGE_SUMMARY
|
|
36
|
-
// LAST_CHANGE: [v0.2.
|
|
42
|
+
// LAST_CHANGE: [v0.2.6 - Added vvoc-managed OpenCode subagent registration, prompt scaffolding, and model override helpers.]
|
|
37
43
|
// END_CHANGE_SUMMARY
|
|
38
44
|
import { applyEdits, format, modify, parse } from "jsonc-parser";
|
|
39
45
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
40
|
-
import { dirname, join } from "node:path";
|
|
46
|
+
import { dirname, join, relative } from "node:path";
|
|
47
|
+
import { MANAGED_SUBAGENTS, getManagedSubagentDefinition, loadManagedSubagentTemplate, } from "./managed-agents.js";
|
|
41
48
|
import { parseMemoryConfigText, renderMemoryConfig, } from "../plugins/memory-store.js";
|
|
42
49
|
import { getPinnedPackageSpecifier, PACKAGE_NAME } from "./package.js";
|
|
43
|
-
import { getConfigHome, getGlobalOpencodeDir, getGlobalVvocDir, getProjectVvocDir, } from "./vvoc-paths.js";
|
|
50
|
+
import { getConfigHome, getGlobalOpencodeDir, getGlobalVvocDir, getProjectVvocDir, getVvocAgentsDir, } from "./vvoc-paths.js";
|
|
44
51
|
export const CLI_NAME = "vvoc";
|
|
45
52
|
export { PACKAGE_NAME };
|
|
46
53
|
export const OPENCODE_SCHEMA_URL = "https://opencode.ai/config.json";
|
|
@@ -66,6 +73,7 @@ export async function resolvePaths(options) {
|
|
|
66
73
|
const vvocBaseDir = options.scope === "global"
|
|
67
74
|
? getGlobalVvocDir(options.configDir)
|
|
68
75
|
: getProjectVvocDir(options.cwd);
|
|
76
|
+
const managedAgentsDirPath = getVvocAgentsDir(vvocBaseDir);
|
|
69
77
|
const opencodeSelection = await selectPrimaryPath(OPENCODE_CONFIG_FILE_NAMES.map((name) => join(opencodeBaseDir, name)));
|
|
70
78
|
const guardianSelection = await selectPrimaryPath(GUARDIAN_CONFIG_FILE_NAMES.map((name) => join(vvocBaseDir, name)));
|
|
71
79
|
const memorySelection = await selectPrimaryPath(MEMORY_CONFIG_FILE_NAMES.map((name) => join(vvocBaseDir, name)));
|
|
@@ -76,6 +84,7 @@ export async function resolvePaths(options) {
|
|
|
76
84
|
configHome,
|
|
77
85
|
opencodeBaseDir,
|
|
78
86
|
vvocBaseDir,
|
|
87
|
+
managedAgentsDirPath,
|
|
79
88
|
opencodeConfigPath: opencodeSelection.primary,
|
|
80
89
|
opencodeAlternatePaths: opencodeSelection.alternates,
|
|
81
90
|
guardianConfigPath: guardianSelection.primary,
|
|
@@ -113,6 +122,138 @@ export function ensurePackageConfigText(text, packageSpecifier = PACKAGE_NAME) {
|
|
|
113
122
|
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
114
123
|
}
|
|
115
124
|
// END_BLOCK_ENSURE_OPENCODE_PLUGIN_CONFIG
|
|
125
|
+
// START_BLOCK_ENSURE_MANAGED_SUBAGENT_CONFIG
|
|
126
|
+
export function ensureManagedSubagentsConfigText(text, paths) {
|
|
127
|
+
if (!text?.trim()) {
|
|
128
|
+
return renderJson({
|
|
129
|
+
$schema: OPENCODE_SCHEMA_URL,
|
|
130
|
+
agent: Object.fromEntries(MANAGED_SUBAGENTS.map((definition) => [
|
|
131
|
+
definition.name,
|
|
132
|
+
getManagedSubagentRegistration(paths, definition.name),
|
|
133
|
+
])),
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
const document = parseObjectDocument(text, "OpenCode config");
|
|
137
|
+
const currentAgents = readAgentMap(document, "OpenCode config");
|
|
138
|
+
let nextText = text;
|
|
139
|
+
if (!Object.hasOwn(document, "$schema")) {
|
|
140
|
+
nextText = applyEdits(nextText, modify(nextText, ["$schema"], OPENCODE_SCHEMA_URL, {
|
|
141
|
+
formattingOptions: JSON_FORMAT,
|
|
142
|
+
getInsertionIndex: () => 0,
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
for (const definition of MANAGED_SUBAGENTS) {
|
|
146
|
+
const currentEntry = currentAgents[definition.name];
|
|
147
|
+
const nextEntry = {
|
|
148
|
+
...getManagedSubagentRegistration(paths, definition.name),
|
|
149
|
+
...currentEntry,
|
|
150
|
+
};
|
|
151
|
+
if (JSON.stringify(currentEntry) === JSON.stringify(nextEntry)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
nextText = applyEdits(nextText, modify(nextText, ["agent", definition.name], nextEntry, {
|
|
155
|
+
formattingOptions: JSON_FORMAT,
|
|
156
|
+
}));
|
|
157
|
+
}
|
|
158
|
+
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
159
|
+
}
|
|
160
|
+
export async function syncManagedSubagentRegistrations(paths) {
|
|
161
|
+
const currentText = await readOptionalText(paths.opencodeConfigPath);
|
|
162
|
+
const nextText = ensureManagedSubagentsConfigText(currentText, paths);
|
|
163
|
+
if (currentText === nextText) {
|
|
164
|
+
return { path: paths.opencodeConfigPath, changed: false };
|
|
165
|
+
}
|
|
166
|
+
await writeText(paths.opencodeConfigPath, nextText);
|
|
167
|
+
return { path: paths.opencodeConfigPath, changed: true };
|
|
168
|
+
}
|
|
169
|
+
export async function installManagedSubagentPrompts(paths, options) {
|
|
170
|
+
const results = [];
|
|
171
|
+
for (const definition of MANAGED_SUBAGENTS) {
|
|
172
|
+
const promptPath = getManagedSubagentPromptPath(paths, definition.name);
|
|
173
|
+
const currentText = await readOptionalText(promptPath);
|
|
174
|
+
if (!currentText) {
|
|
175
|
+
await writeText(promptPath, await renderManagedSubagentPrompt(definition.name));
|
|
176
|
+
results.push({ action: "created", path: promptPath });
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (!options.force) {
|
|
180
|
+
if (!isManagedFile(currentText)) {
|
|
181
|
+
results.push({
|
|
182
|
+
action: "skipped",
|
|
183
|
+
path: promptPath,
|
|
184
|
+
reason: "existing file is not managed by vvoc",
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
results.push({ action: "kept", path: promptPath });
|
|
189
|
+
}
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
results.push(await syncManagedSubagentPrompt(paths, definition.name, options));
|
|
193
|
+
}
|
|
194
|
+
return results;
|
|
195
|
+
}
|
|
196
|
+
export async function syncManagedSubagentPrompts(paths, options) {
|
|
197
|
+
const results = [];
|
|
198
|
+
for (const definition of MANAGED_SUBAGENTS) {
|
|
199
|
+
results.push(await syncManagedSubagentPrompt(paths, definition.name, options));
|
|
200
|
+
}
|
|
201
|
+
return results;
|
|
202
|
+
}
|
|
203
|
+
export async function readManagedSubagentModels(paths) {
|
|
204
|
+
const models = Object.fromEntries(MANAGED_SUBAGENTS.map((definition) => [definition.name, undefined]));
|
|
205
|
+
const currentText = await readOptionalText(paths.opencodeConfigPath);
|
|
206
|
+
if (!currentText) {
|
|
207
|
+
return models;
|
|
208
|
+
}
|
|
209
|
+
const document = parseObjectDocument(currentText, paths.opencodeConfigPath);
|
|
210
|
+
const agentMap = readAgentMap(document, paths.opencodeConfigPath);
|
|
211
|
+
for (const definition of MANAGED_SUBAGENTS) {
|
|
212
|
+
const currentEntry = agentMap[definition.name];
|
|
213
|
+
if (currentEntry?.model !== undefined) {
|
|
214
|
+
models[definition.name] = readNonEmptyString(currentEntry.model, `${definition.name}: model`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return models;
|
|
218
|
+
}
|
|
219
|
+
export async function writeManagedSubagentModel(paths, agentName, options) {
|
|
220
|
+
const currentText = await readOptionalText(paths.opencodeConfigPath);
|
|
221
|
+
if (!currentText && !options.ensureEntry) {
|
|
222
|
+
return { action: "kept", path: paths.opencodeConfigPath };
|
|
223
|
+
}
|
|
224
|
+
const baseText = options.ensureEntry
|
|
225
|
+
? ensureManagedSubagentsConfigText(currentText, paths)
|
|
226
|
+
: currentText;
|
|
227
|
+
if (!baseText) {
|
|
228
|
+
return { action: "kept", path: paths.opencodeConfigPath };
|
|
229
|
+
}
|
|
230
|
+
const document = parseObjectDocument(baseText, paths.opencodeConfigPath);
|
|
231
|
+
const agentMap = readAgentMap(document, paths.opencodeConfigPath);
|
|
232
|
+
const currentEntry = agentMap[agentName];
|
|
233
|
+
if (!currentEntry && !options.ensureEntry) {
|
|
234
|
+
return { action: "kept", path: paths.opencodeConfigPath };
|
|
235
|
+
}
|
|
236
|
+
const nextEntry = {
|
|
237
|
+
...getManagedSubagentRegistration(paths, agentName),
|
|
238
|
+
...currentEntry,
|
|
239
|
+
};
|
|
240
|
+
if (options.model) {
|
|
241
|
+
nextEntry.model = options.model;
|
|
242
|
+
}
|
|
243
|
+
else {
|
|
244
|
+
delete nextEntry.model;
|
|
245
|
+
}
|
|
246
|
+
const nextText = updateAgentEntryText(baseText, agentName, nextEntry);
|
|
247
|
+
if ((currentText ?? "") === nextText) {
|
|
248
|
+
return { action: "kept", path: paths.opencodeConfigPath };
|
|
249
|
+
}
|
|
250
|
+
await writeText(paths.opencodeConfigPath, nextText);
|
|
251
|
+
return {
|
|
252
|
+
action: currentText ? "updated" : "created",
|
|
253
|
+
path: paths.opencodeConfigPath,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
// END_BLOCK_ENSURE_MANAGED_SUBAGENT_CONFIG
|
|
116
257
|
export function parseGuardianConfigText(text, label) {
|
|
117
258
|
return normalizeGuardianOverrides(parseObjectDocument(text, label), label);
|
|
118
259
|
}
|
|
@@ -513,6 +654,86 @@ function normalizePluginList(currentPlugins, packageSpecifier) {
|
|
|
513
654
|
function isPackagePluginSpecifier(value) {
|
|
514
655
|
return value === PACKAGE_NAME || value.startsWith(`${PACKAGE_NAME}@`);
|
|
515
656
|
}
|
|
657
|
+
// START_BLOCK_MANAGED_SUBAGENT_HELPERS
|
|
658
|
+
function readAgentMap(document, label) {
|
|
659
|
+
const raw = document.agent;
|
|
660
|
+
if (raw === undefined) {
|
|
661
|
+
return {};
|
|
662
|
+
}
|
|
663
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
664
|
+
throw new Error(`${label}: expected "agent" to be an object`);
|
|
665
|
+
}
|
|
666
|
+
const entries = {};
|
|
667
|
+
for (const [name, value] of Object.entries(raw)) {
|
|
668
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
669
|
+
throw new Error(`${label}: expected "agent.${name}" to be an object`);
|
|
670
|
+
}
|
|
671
|
+
entries[name] = value;
|
|
672
|
+
}
|
|
673
|
+
return entries;
|
|
674
|
+
}
|
|
675
|
+
function getManagedSubagentPromptPath(paths, agentName) {
|
|
676
|
+
return join(paths.managedAgentsDirPath, getManagedSubagentDefinition(agentName).promptFileName);
|
|
677
|
+
}
|
|
678
|
+
function getManagedSubagentPromptReference(paths, agentName) {
|
|
679
|
+
const promptPath = getManagedSubagentPromptPath(paths, agentName);
|
|
680
|
+
const promptRef = relative(dirname(paths.opencodeConfigPath), promptPath).replaceAll("\\", "/");
|
|
681
|
+
return `{file:${promptRef.startsWith(".") ? promptRef : `./${promptRef}`}}`;
|
|
682
|
+
}
|
|
683
|
+
function getManagedSubagentRegistration(paths, agentName) {
|
|
684
|
+
const definition = getManagedSubagentDefinition(agentName);
|
|
685
|
+
const registration = {
|
|
686
|
+
description: definition.description,
|
|
687
|
+
mode: "subagent",
|
|
688
|
+
prompt: getManagedSubagentPromptReference(paths, agentName),
|
|
689
|
+
};
|
|
690
|
+
if (definition.steps !== undefined) {
|
|
691
|
+
registration.steps = definition.steps;
|
|
692
|
+
}
|
|
693
|
+
if (definition.permission) {
|
|
694
|
+
registration.permission = definition.permission;
|
|
695
|
+
}
|
|
696
|
+
return registration;
|
|
697
|
+
}
|
|
698
|
+
async function renderManagedSubagentPrompt(agentName) {
|
|
699
|
+
const template = (await loadManagedSubagentTemplate(agentName)).trim();
|
|
700
|
+
const header = [
|
|
701
|
+
"<!-- Managed by vvoc.",
|
|
702
|
+
"`vvoc sync` rewrites files with this marker while preserving agent registration and model settings elsewhere.",
|
|
703
|
+
"Remove this comment if you want to manage the file manually.",
|
|
704
|
+
"-->",
|
|
705
|
+
"",
|
|
706
|
+
].join("\n");
|
|
707
|
+
return `${header}${template}\n`;
|
|
708
|
+
}
|
|
709
|
+
async function syncManagedSubagentPrompt(paths, agentName, options) {
|
|
710
|
+
const promptPath = getManagedSubagentPromptPath(paths, agentName);
|
|
711
|
+
const currentText = await readOptionalText(promptPath);
|
|
712
|
+
if (!currentText) {
|
|
713
|
+
await writeText(promptPath, await renderManagedSubagentPrompt(agentName));
|
|
714
|
+
return { action: "created", path: promptPath };
|
|
715
|
+
}
|
|
716
|
+
if (!options.force && !isManagedFile(currentText)) {
|
|
717
|
+
return {
|
|
718
|
+
action: "skipped",
|
|
719
|
+
path: promptPath,
|
|
720
|
+
reason: "existing file is not managed by vvoc",
|
|
721
|
+
};
|
|
722
|
+
}
|
|
723
|
+
const nextText = await renderManagedSubagentPrompt(agentName);
|
|
724
|
+
if (currentText === nextText) {
|
|
725
|
+
return { action: "kept", path: promptPath };
|
|
726
|
+
}
|
|
727
|
+
await writeText(promptPath, nextText);
|
|
728
|
+
return { action: "updated", path: promptPath };
|
|
729
|
+
}
|
|
730
|
+
function updateAgentEntryText(text, agentName, entry) {
|
|
731
|
+
const nextText = applyEdits(text, modify(text, ["agent", agentName], entry, {
|
|
732
|
+
formattingOptions: JSON_FORMAT,
|
|
733
|
+
}));
|
|
734
|
+
return ensureTrailingNewline(applyEdits(nextText, format(nextText, undefined, JSON_FORMAT)));
|
|
735
|
+
}
|
|
736
|
+
// END_BLOCK_MANAGED_SUBAGENT_HELPERS
|
|
516
737
|
function normalizeGuardianOverrides(raw, label) {
|
|
517
738
|
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
518
739
|
throw new Error(`${label}: expected a top-level object`);
|