@kisev/skills-opencode 1.0.0 → 1.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/README.md +68 -9
- package/assets/agents/critic.md +14 -7
- package/assets/agents/manager.md +47 -18
- package/assets/agents/review.md +7 -4
- package/assets/commands/agent-list.md +9 -0
- package/assets/commands/agent-model-set.md +9 -0
- package/assets/commands/capabilities.md +1 -1
- package/assets/commands/critic-add.md +9 -0
- package/assets/commands/critic-remove.md +9 -0
- package/assets/commands/doctor.md +1 -1
- package/assets/commands/route.md +1 -1
- package/dist/agent-profiles.d.ts +122 -0
- package/dist/agent-profiles.js +776 -0
- package/dist/cli.js +191 -29
- package/dist/generate-assets.js +33 -4
- package/dist/index.d.ts +76 -6
- package/dist/index.js +35 -4
- package/dist/installer.d.ts +7 -6
- package/dist/installer.js +203 -282
- package/dist/lifecycle.d.ts +58 -0
- package/dist/lifecycle.js +632 -0
- package/dist/plugins/background-attempts.d.ts +3 -3
- package/dist/registry.d.ts +2 -1
- package/dist/registry.js +10 -2
- package/dist/runtime/state.js +21 -39
- package/package.json +6 -2
package/dist/cli.js
CHANGED
|
@@ -1,55 +1,217 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createInterface } from "node:readline/promises";
|
|
3
|
+
import { AgentProfileError, applyAgentProfileChange, availableModels, availableModelVariants, FIXED_AGENT_ROLES, listAgentProfiles, previewAgentProfileChange, validateAgentName, validateModel, validateVariant, } from "./agent-profiles.js";
|
|
2
4
|
import { apply, InstallerError, preview, result } from "./installer.js";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
5
|
+
import { LifecycleError } from "./lifecycle.js";
|
|
6
|
+
function parseOptions(values) {
|
|
7
|
+
const options = { dryRun: false };
|
|
8
|
+
for (let index = 0; index < values.length; index += 1) {
|
|
9
|
+
const value = values[index];
|
|
10
|
+
if (!value.startsWith("--")) {
|
|
11
|
+
if (options.name)
|
|
12
|
+
throw new InstallerError("invalid_input", `Unexpected argument: ${value}`);
|
|
13
|
+
options.name = value;
|
|
14
|
+
}
|
|
15
|
+
else if (value === "--scope") {
|
|
16
|
+
const scope = values[++index];
|
|
17
|
+
if (scope !== "global" && scope !== "project")
|
|
15
18
|
throw new InstallerError("invalid_input", "--scope must be global or project");
|
|
16
|
-
if (scope)
|
|
19
|
+
if (options.scope)
|
|
17
20
|
throw new InstallerError("invalid_input", "--scope may be supplied once");
|
|
18
|
-
scope =
|
|
21
|
+
options.scope = scope;
|
|
19
22
|
}
|
|
20
23
|
else if (value === "--dry-run") {
|
|
21
|
-
if (dryRun)
|
|
24
|
+
if (options.dryRun)
|
|
22
25
|
throw new InstallerError("invalid_input", "--dry-run may be supplied once");
|
|
23
|
-
dryRun = true;
|
|
26
|
+
options.dryRun = true;
|
|
24
27
|
}
|
|
25
28
|
else if (value === "--confirm") {
|
|
26
|
-
if (confirm)
|
|
29
|
+
if (options.confirm)
|
|
27
30
|
throw new InstallerError("invalid_input", "--confirm may be supplied once");
|
|
28
|
-
confirm =
|
|
29
|
-
if (!confirm)
|
|
31
|
+
options.confirm = values[++index];
|
|
32
|
+
if (!options.confirm)
|
|
30
33
|
throw new InstallerError("invalid_input", "--confirm requires a digest");
|
|
31
34
|
}
|
|
35
|
+
else if (value === "--provider") {
|
|
36
|
+
options.provider = values[++index];
|
|
37
|
+
if (!options.provider)
|
|
38
|
+
throw new InstallerError("invalid_input", "--provider requires a value");
|
|
39
|
+
}
|
|
40
|
+
else if (value === "--model") {
|
|
41
|
+
options.model = values[++index];
|
|
42
|
+
if (!options.model)
|
|
43
|
+
throw new InstallerError("invalid_input", "--model requires a value");
|
|
44
|
+
}
|
|
45
|
+
else if (value === "--variant") {
|
|
46
|
+
options.variant = values[++index];
|
|
47
|
+
if (!options.variant)
|
|
48
|
+
throw new InstallerError("invalid_input", "--variant requires a value");
|
|
49
|
+
}
|
|
50
|
+
else if (value === "--clear-variant") {
|
|
51
|
+
if (options.variant !== undefined)
|
|
52
|
+
throw new InstallerError("invalid_input", "Use only one variant option");
|
|
53
|
+
options.variant = null;
|
|
54
|
+
}
|
|
32
55
|
else {
|
|
33
56
|
throw new InstallerError("invalid_input", `Unknown argument: ${value}`);
|
|
34
57
|
}
|
|
35
58
|
}
|
|
36
|
-
if (!scope)
|
|
59
|
+
if (!options.scope)
|
|
37
60
|
throw new InstallerError("invalid_input", "--scope is required");
|
|
38
|
-
|
|
61
|
+
return options;
|
|
62
|
+
}
|
|
63
|
+
function requireConfirmationMode(options) {
|
|
64
|
+
if (options.dryRun === Boolean(options.confirm))
|
|
39
65
|
throw new InstallerError("invalid_input", "Use exactly one of --dry-run or --confirm <digest>");
|
|
40
|
-
return { action, scope, dryRun, confirm };
|
|
41
66
|
}
|
|
42
|
-
|
|
67
|
+
function exactModel(options) {
|
|
68
|
+
if (!options.model)
|
|
69
|
+
return undefined;
|
|
70
|
+
if (options.model.includes("/")) {
|
|
71
|
+
const model = validateModel(options.model);
|
|
72
|
+
if (options.provider && model.split("/", 1)[0] !== options.provider)
|
|
73
|
+
throw new InstallerError("invalid_input", "--provider does not match the exact --model value");
|
|
74
|
+
return model;
|
|
75
|
+
}
|
|
76
|
+
if (!options.provider)
|
|
77
|
+
throw new InstallerError("invalid_input", "--provider is required when --model is not provider/model");
|
|
78
|
+
return validateModel(`${options.provider}/${options.model}`);
|
|
79
|
+
}
|
|
80
|
+
async function choose(label, values, input) {
|
|
81
|
+
process.stderr.write(`${label}:\n${values.map((value, index) => ` ${index + 1}. ${value}`).join("\n")}\n`);
|
|
82
|
+
const answer = await input.question("> ");
|
|
83
|
+
const index = Number(answer) - 1;
|
|
84
|
+
if (!Number.isSafeInteger(index) || !values[index])
|
|
85
|
+
throw new InstallerError("invalid_input", `Invalid ${label.toLowerCase()} selection`);
|
|
86
|
+
return values[index];
|
|
87
|
+
}
|
|
88
|
+
async function interactiveSelection(options) {
|
|
89
|
+
if (!process.stdin.isTTY || !process.stderr.isTTY)
|
|
90
|
+
throw new InstallerError("terminal_required", "agent configure requires a terminal or explicit --provider and --model");
|
|
91
|
+
const input = createInterface({ input: process.stdin, output: process.stderr });
|
|
43
92
|
try {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
93
|
+
const inventory = await listAgentProfiles(options.scope);
|
|
94
|
+
const configurable = inventory.profiles.filter((item) => item.ownership !== "user-owned").map((item) => item.name);
|
|
95
|
+
const name = options.name ? validateAgentName(options.name) : await choose("Agent", configurable.length ? configurable : FIXED_AGENT_ROLES, input);
|
|
96
|
+
if (options.provider && options.model)
|
|
97
|
+
return { name, model: exactModel(options), ...(validateVariant(options.variant) ? { variant: validateVariant(options.variant) } : {}) };
|
|
98
|
+
let models;
|
|
99
|
+
try {
|
|
100
|
+
models = await availableModels();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
if (!(error instanceof AgentProfileError) || error.code !== "catalog_unavailable")
|
|
104
|
+
throw error;
|
|
105
|
+
const provider = options.provider ?? (await input.question("Provider: ")).trim();
|
|
106
|
+
const model = options.model ?? (await input.question("Model: ")).trim();
|
|
107
|
+
const variant = options.variant === undefined ? (await input.question("Variant (optional): ")).trim() : options.variant;
|
|
108
|
+
return { name, model: validateModel(model.includes("/") ? model : `${provider}/${model}`), ...(validateVariant(variant) ? { variant: validateVariant(variant) } : {}) };
|
|
109
|
+
}
|
|
110
|
+
const providers = [...new Set(models.map((model) => model.split("/", 1)[0]))].sort();
|
|
111
|
+
const provider = options.provider ?? (await choose("Provider", providers, input));
|
|
112
|
+
const selectedModel = options.model
|
|
113
|
+
? exactModel({ ...options, provider })
|
|
114
|
+
: await choose("Model", models.filter((model) => model.startsWith(`${provider}/`)), input);
|
|
115
|
+
let variants = [];
|
|
116
|
+
try {
|
|
117
|
+
variants = await availableModelVariants(selectedModel);
|
|
48
118
|
}
|
|
49
|
-
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (!(error instanceof AgentProfileError) || error.code !== "catalog_unavailable")
|
|
121
|
+
throw error;
|
|
122
|
+
}
|
|
123
|
+
const variant = options.variant === null
|
|
124
|
+
? undefined
|
|
125
|
+
: options.variant ?? (variants.length ? await choose("Variant", ["none", ...variants.filter((value) => value !== "none")], input) : (await input.question("Variant (optional): ")).trim());
|
|
126
|
+
return { name, model: selectedModel, ...(variant && variant !== "none" ? { variant: validateVariant(variant) } : {}) };
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
input.close();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async function runProfile(request, options) {
|
|
133
|
+
requireConfirmationMode(options);
|
|
134
|
+
if (options.dryRun) {
|
|
135
|
+
const plan = await previewAgentProfileChange(request, options.scope);
|
|
136
|
+
process.stdout.write(`${JSON.stringify({ status: "ok", applied: false, requires_restart: false, plan }, null, 2)}\n`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
process.stdout.write(`${JSON.stringify(await applyAgentProfileChange(request, options.scope, options.confirm), null, 2)}\n`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function run(arguments_) {
|
|
143
|
+
const [domain, operation, ...rest] = arguments_;
|
|
144
|
+
if (domain === "install" || domain === "uninstall") {
|
|
145
|
+
if (operation?.startsWith("--") || operation === undefined)
|
|
146
|
+
rest.unshift(...(operation ? [operation] : []));
|
|
147
|
+
else
|
|
148
|
+
throw new InstallerError("invalid_input", `Unexpected argument: ${operation}`);
|
|
149
|
+
const options = parseOptions(rest);
|
|
150
|
+
if (options.name || options.provider || options.model || options.variant !== undefined)
|
|
151
|
+
throw new InstallerError("invalid_input", "Installer accepts only scope and confirmation options");
|
|
152
|
+
requireConfirmationMode(options);
|
|
153
|
+
const action = domain;
|
|
154
|
+
process.stdout.write(`${result(options.dryRun ? await preview(action, options.scope) : await apply(action, options.scope, options.confirm), !options.dryRun)}\n`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
if (domain === "agent" && operation === "list") {
|
|
158
|
+
const options = parseOptions(rest);
|
|
159
|
+
if (options.dryRun || options.confirm || options.name || options.provider || options.model || options.variant !== undefined)
|
|
160
|
+
throw new InstallerError("invalid_input", "agent list accepts only --scope");
|
|
161
|
+
process.stdout.write(`${JSON.stringify({ status: "ok", inventory: await listAgentProfiles(options.scope) }, null, 2)}\n`);
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (domain === "agent" && operation === "configure") {
|
|
165
|
+
const options = parseOptions(rest);
|
|
166
|
+
requireConfirmationMode(options);
|
|
167
|
+
const selected = options.provider && options.model && options.name
|
|
168
|
+
? { name: validateAgentName(options.name), model: exactModel(options), ...(validateVariant(options.variant) ? { variant: validateVariant(options.variant) } : {}) }
|
|
169
|
+
: await interactiveSelection(options);
|
|
170
|
+
await runProfile({ action: "model-set", ...selected, variant: selected.variant ?? null }, options);
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (domain === "agent" && operation === "model-set") {
|
|
174
|
+
const options = parseOptions(rest);
|
|
175
|
+
const name = validateAgentName(options.name ?? "");
|
|
176
|
+
const model = exactModel(options);
|
|
177
|
+
if (!model)
|
|
178
|
+
throw new InstallerError("invalid_input", "agent model-set requires --provider and --model, or exact --model provider/model");
|
|
179
|
+
await runProfile({ action: "model-set", name, model, variant: options.variant ?? null }, options);
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
if (domain === "agent" && operation === "reconcile") {
|
|
183
|
+
const options = parseOptions(rest);
|
|
184
|
+
if (options.name || options.provider || options.model || options.variant !== undefined)
|
|
185
|
+
throw new InstallerError("invalid_input", "agent reconcile accepts only scope and confirmation options");
|
|
186
|
+
await runProfile({ action: "reconcile" }, options);
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
if (domain === "critic" && (operation === "add" || operation === "remove")) {
|
|
190
|
+
const options = parseOptions(rest);
|
|
191
|
+
const name = options.name === "critic" || options.name?.startsWith("critic-")
|
|
192
|
+
? options.name
|
|
193
|
+
: `critic-${options.name ?? ""}`;
|
|
194
|
+
if (operation === "add") {
|
|
195
|
+
const model = exactModel(options);
|
|
196
|
+
if (!model)
|
|
197
|
+
throw new InstallerError("invalid_input", "critic add requires --provider and --model, or exact --model provider/model");
|
|
198
|
+
await runProfile({ action: "critic-add", name, model, variant: options.variant ?? null }, options);
|
|
199
|
+
}
|
|
200
|
+
else {
|
|
201
|
+
if (options.provider || options.model || options.variant !== undefined)
|
|
202
|
+
throw new InstallerError("invalid_input", "critic remove does not accept model options");
|
|
203
|
+
await runProfile({ action: "critic-remove", name }, options);
|
|
204
|
+
}
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
throw new InstallerError("invalid_input", "Use install, uninstall, agent list|configure|model-set|reconcile, or critic add|remove");
|
|
208
|
+
}
|
|
209
|
+
async function main() {
|
|
210
|
+
try {
|
|
211
|
+
await run(process.argv.slice(2));
|
|
50
212
|
}
|
|
51
213
|
catch (error) {
|
|
52
|
-
const known = error instanceof
|
|
214
|
+
const known = error instanceof LifecycleError ? error : new InstallerError("internal_error", error instanceof Error ? error.message : String(error));
|
|
53
215
|
process.stdout.write(`${JSON.stringify({ status: "error", error: { code: known.code, message: known.message } })}\n`);
|
|
54
216
|
process.exitCode = 2;
|
|
55
217
|
}
|
package/dist/generate-assets.js
CHANGED
|
@@ -1,10 +1,39 @@
|
|
|
1
|
-
import { mkdir, writeFile } from "node:fs/promises";
|
|
1
|
+
import { mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { dirname, resolve } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { COMMAND_REGISTRY, renderCommand } from "./registry.js";
|
|
5
5
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
6
|
-
const
|
|
7
|
-
|
|
6
|
+
const arguments_ = process.argv.slice(2);
|
|
7
|
+
const rootIndex = arguments_.indexOf("--root");
|
|
8
|
+
if (rootIndex !== -1 && !arguments_[rootIndex + 1])
|
|
9
|
+
throw new Error("--root requires a path");
|
|
10
|
+
const commandsRoot = rootIndex === -1
|
|
11
|
+
? resolve(packageRoot, "assets", "commands")
|
|
12
|
+
: resolve(arguments_[rootIndex + 1] ?? "");
|
|
13
|
+
const check = arguments_.includes("--check");
|
|
14
|
+
const expectedNames = new Set(COMMAND_REGISTRY.map((command) => `${command.name}.md`));
|
|
15
|
+
if (!check)
|
|
16
|
+
await mkdir(commandsRoot, { recursive: true });
|
|
17
|
+
const entries = await readdir(commandsRoot, { withFileTypes: true }).catch(() => []);
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
if (entry.isFile() && !expectedNames.has(entry.name)) {
|
|
20
|
+
if (check)
|
|
21
|
+
throw new Error(`unexpected generated asset: ${entry.name}`);
|
|
22
|
+
await unlink(resolve(commandsRoot, entry.name));
|
|
23
|
+
}
|
|
24
|
+
else if (!entry.isFile()) {
|
|
25
|
+
throw new Error(`unexpected entry in generated assets: ${entry.name}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
8
28
|
for (const command of COMMAND_REGISTRY) {
|
|
9
|
-
|
|
29
|
+
const destination = resolve(commandsRoot, `${command.name}.md`);
|
|
30
|
+
const expected = renderCommand(command);
|
|
31
|
+
if (check) {
|
|
32
|
+
const actual = await readFile(destination, "utf8").catch(() => "");
|
|
33
|
+
if (actual !== expected)
|
|
34
|
+
throw new Error(`generated asset drift: ${command.name}.md`);
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
await writeFile(destination, expected, "utf8");
|
|
38
|
+
}
|
|
10
39
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -8,6 +8,8 @@ import zedBell, { type ZedBellOptions } from "./plugins/zed-bell.js";
|
|
|
8
8
|
import zedClickablePaths, { type ZedClickablePathsOptions } from "./plugins/zed-clickable-paths.js";
|
|
9
9
|
export { COMMAND_REGISTRY, renderCommand } from "./registry.js";
|
|
10
10
|
export { CATEGORIES, resolveRouting, RoutingGate } from "./routing.js";
|
|
11
|
+
export { AgentProfileError, FIXED_AGENT_ROLES, applyAgentProfileChange, availableModels, availableModelVariants, listAgentProfiles, previewAgentProfileChange, renderAgentProfile, validateAgentName, validateModel, validateVariant, } from "./agent-profiles.js";
|
|
12
|
+
export type { AgentInventory, AgentModelSelection, AgentOwnership, AgentProfileAction, AgentProfileConfig, AgentProfileOperation, AgentProfilePlan, AgentProfileRecord, AgentProfileRequest, AgentProfileResult, AgentProfileScope, AgentState, DeploymentManifest, DeploymentRecord, FixedAgentRole, } from "./agent-profiles.js";
|
|
11
13
|
export { backgroundAttempts, goalLoop, scheduler, autonomyPolicy, rulesInjector, rtk, zedBell, zedClickablePaths };
|
|
12
14
|
export type OpenCodeOptions = {
|
|
13
15
|
backgroundAttempts?: BackgroundAttemptsOptions;
|
|
@@ -19,7 +21,9 @@ export type OpenCodeOptions = {
|
|
|
19
21
|
zedBell?: ZedBellOptions;
|
|
20
22
|
zedClickablePaths?: ZedClickablePathsOptions;
|
|
21
23
|
};
|
|
22
|
-
declare const plugin: (
|
|
24
|
+
declare const plugin: (input: {
|
|
25
|
+
directory?: string;
|
|
26
|
+
}) => Promise<{
|
|
23
27
|
tool: {
|
|
24
28
|
route: {
|
|
25
29
|
description: string;
|
|
@@ -29,10 +33,10 @@ declare const plugin: () => Promise<{
|
|
|
29
33
|
dispatch: "dispatch";
|
|
30
34
|
}>;
|
|
31
35
|
category: import("zod").ZodEnum<{
|
|
36
|
+
review: "review";
|
|
32
37
|
exploration: "exploration";
|
|
33
38
|
architecture: "architecture";
|
|
34
39
|
implementation: "implementation";
|
|
35
|
-
review: "review";
|
|
36
40
|
documentation: "documentation";
|
|
37
41
|
quick: "quick";
|
|
38
42
|
}>;
|
|
@@ -53,7 +57,7 @@ declare const plugin: () => Promise<{
|
|
|
53
57
|
};
|
|
54
58
|
execute(args: {
|
|
55
59
|
action: "preview" | "dispatch";
|
|
56
|
-
category: "
|
|
60
|
+
category: "review" | "exploration" | "architecture" | "implementation" | "documentation" | "quick";
|
|
57
61
|
task: string;
|
|
58
62
|
requirements: string[];
|
|
59
63
|
agents: {
|
|
@@ -80,6 +84,38 @@ declare const plugin: () => Promise<{
|
|
|
80
84
|
args: {};
|
|
81
85
|
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
82
86
|
};
|
|
87
|
+
agent_profiles: {
|
|
88
|
+
description: string;
|
|
89
|
+
args: {
|
|
90
|
+
action: import("zod").ZodEnum<{
|
|
91
|
+
list: "list";
|
|
92
|
+
model_set: "model_set";
|
|
93
|
+
critic_add: "critic_add";
|
|
94
|
+
critic_remove: "critic_remove";
|
|
95
|
+
}>;
|
|
96
|
+
phase: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
97
|
+
preview: "preview";
|
|
98
|
+
apply: "apply";
|
|
99
|
+
}>>;
|
|
100
|
+
scope: import("zod").ZodEnum<{
|
|
101
|
+
global: "global";
|
|
102
|
+
project: "project";
|
|
103
|
+
}>;
|
|
104
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
105
|
+
model: import("zod").ZodOptional<import("zod").ZodString>;
|
|
106
|
+
variant: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
|
|
107
|
+
confirmation_digest: import("zod").ZodOptional<import("zod").ZodString>;
|
|
108
|
+
};
|
|
109
|
+
execute(args: {
|
|
110
|
+
action: "list" | "model_set" | "critic_add" | "critic_remove";
|
|
111
|
+
scope: "global" | "project";
|
|
112
|
+
phase?: "preview" | "apply" | undefined;
|
|
113
|
+
name?: string | undefined;
|
|
114
|
+
model?: string | undefined;
|
|
115
|
+
variant?: string | null | undefined;
|
|
116
|
+
confirmation_digest?: string | undefined;
|
|
117
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
118
|
+
};
|
|
83
119
|
};
|
|
84
120
|
"tool.execute.before": (input: {
|
|
85
121
|
tool: string;
|
|
@@ -88,7 +124,9 @@ declare const plugin: () => Promise<{
|
|
|
88
124
|
args: unknown;
|
|
89
125
|
}) => Promise<void>;
|
|
90
126
|
}>;
|
|
91
|
-
export declare const server: (
|
|
127
|
+
export declare const server: (input: {
|
|
128
|
+
directory?: string;
|
|
129
|
+
}) => Promise<{
|
|
92
130
|
tool: {
|
|
93
131
|
route: {
|
|
94
132
|
description: string;
|
|
@@ -98,10 +136,10 @@ export declare const server: () => Promise<{
|
|
|
98
136
|
dispatch: "dispatch";
|
|
99
137
|
}>;
|
|
100
138
|
category: import("zod").ZodEnum<{
|
|
139
|
+
review: "review";
|
|
101
140
|
exploration: "exploration";
|
|
102
141
|
architecture: "architecture";
|
|
103
142
|
implementation: "implementation";
|
|
104
|
-
review: "review";
|
|
105
143
|
documentation: "documentation";
|
|
106
144
|
quick: "quick";
|
|
107
145
|
}>;
|
|
@@ -122,7 +160,7 @@ export declare const server: () => Promise<{
|
|
|
122
160
|
};
|
|
123
161
|
execute(args: {
|
|
124
162
|
action: "preview" | "dispatch";
|
|
125
|
-
category: "
|
|
163
|
+
category: "review" | "exploration" | "architecture" | "implementation" | "documentation" | "quick";
|
|
126
164
|
task: string;
|
|
127
165
|
requirements: string[];
|
|
128
166
|
agents: {
|
|
@@ -149,6 +187,38 @@ export declare const server: () => Promise<{
|
|
|
149
187
|
args: {};
|
|
150
188
|
execute(args: Record<string, never>, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
151
189
|
};
|
|
190
|
+
agent_profiles: {
|
|
191
|
+
description: string;
|
|
192
|
+
args: {
|
|
193
|
+
action: import("zod").ZodEnum<{
|
|
194
|
+
list: "list";
|
|
195
|
+
model_set: "model_set";
|
|
196
|
+
critic_add: "critic_add";
|
|
197
|
+
critic_remove: "critic_remove";
|
|
198
|
+
}>;
|
|
199
|
+
phase: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
200
|
+
preview: "preview";
|
|
201
|
+
apply: "apply";
|
|
202
|
+
}>>;
|
|
203
|
+
scope: import("zod").ZodEnum<{
|
|
204
|
+
global: "global";
|
|
205
|
+
project: "project";
|
|
206
|
+
}>;
|
|
207
|
+
name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
208
|
+
model: import("zod").ZodOptional<import("zod").ZodString>;
|
|
209
|
+
variant: import("zod").ZodOptional<import("zod").ZodNullable<import("zod").ZodString>>;
|
|
210
|
+
confirmation_digest: import("zod").ZodOptional<import("zod").ZodString>;
|
|
211
|
+
};
|
|
212
|
+
execute(args: {
|
|
213
|
+
action: "list" | "model_set" | "critic_add" | "critic_remove";
|
|
214
|
+
scope: "global" | "project";
|
|
215
|
+
phase?: "preview" | "apply" | undefined;
|
|
216
|
+
name?: string | undefined;
|
|
217
|
+
model?: string | undefined;
|
|
218
|
+
variant?: string | null | undefined;
|
|
219
|
+
confirmation_digest?: string | undefined;
|
|
220
|
+
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
221
|
+
};
|
|
152
222
|
};
|
|
153
223
|
"tool.execute.before": (input: {
|
|
154
224
|
tool: string;
|
package/dist/index.js
CHANGED
|
@@ -8,16 +8,18 @@ import rulesInjector from "./plugins/rules-injector.js";
|
|
|
8
8
|
import rtk from "./plugins/rtk.js";
|
|
9
9
|
import zedBell from "./plugins/zed-bell.js";
|
|
10
10
|
import zedClickablePaths from "./plugins/zed-clickable-paths.js";
|
|
11
|
+
import { applyAgentProfileChange, listAgentProfiles, previewAgentProfileChange, } from "./agent-profiles.js";
|
|
11
12
|
export { COMMAND_REGISTRY, renderCommand } from "./registry.js";
|
|
12
13
|
export { CATEGORIES, resolveRouting, RoutingGate } from "./routing.js";
|
|
14
|
+
export { AgentProfileError, FIXED_AGENT_ROLES, applyAgentProfileChange, availableModels, availableModelVariants, listAgentProfiles, previewAgentProfileChange, renderAgentProfile, validateAgentName, validateModel, validateVariant, } from "./agent-profiles.js";
|
|
13
15
|
export { backgroundAttempts, goalLoop, scheduler, autonomyPolicy, rulesInjector, rtk, zedBell, zedClickablePaths };
|
|
14
16
|
const CATALOG = {
|
|
15
17
|
skills: ["attempt", "goal", "schedule", "multi-run", "usage", "overview", "lsp-report"],
|
|
16
18
|
plugins: ["background-attempts", "goal-loop", "schedule", "autonomy-policy", "rules-injector", "rtk", "zed-bell", "zed-clickable-paths"],
|
|
17
|
-
replacements: ["capabilities", "route", "doctor"],
|
|
18
|
-
version: "1.
|
|
19
|
+
replacements: ["capabilities", "route", "doctor", "agent_profiles"],
|
|
20
|
+
version: "1.1.0",
|
|
19
21
|
};
|
|
20
|
-
const plugin = (async () => {
|
|
22
|
+
const plugin = (async (input) => {
|
|
21
23
|
const gate = new RoutingGate();
|
|
22
24
|
const route = tool({
|
|
23
25
|
description: "Resolve a capability category and dispatch one eligible agent through a one-use Task receipt gate.",
|
|
@@ -52,8 +54,37 @@ const plugin = (async () => {
|
|
|
52
54
|
return JSON.stringify({ schema_version: 1, status: "ok", package: "@kisev/skills-opencode", opencode: ">=1.18.29", state: "not-inspected", mutations: false, defaults: { backgroundAttempts: false, goalLoop: false, scheduler: false, autonomyPolicy: false, zedBell: false, zedClickablePaths: false } });
|
|
53
55
|
},
|
|
54
56
|
});
|
|
57
|
+
const agentProfiles = tool({
|
|
58
|
+
description: "List, preview, or apply package-owned OpenCode agent profile configuration without editing opencode.json.",
|
|
59
|
+
args: {
|
|
60
|
+
action: tool.schema.enum(["list", "model_set", "critic_add", "critic_remove"]),
|
|
61
|
+
phase: tool.schema.enum(["preview", "apply"]).optional(),
|
|
62
|
+
scope: tool.schema.enum(["global", "project"]),
|
|
63
|
+
name: tool.schema.string().optional(),
|
|
64
|
+
model: tool.schema.string().optional(),
|
|
65
|
+
variant: tool.schema.string().nullable().optional(),
|
|
66
|
+
confirmation_digest: tool.schema.string().optional(),
|
|
67
|
+
},
|
|
68
|
+
async execute(args) {
|
|
69
|
+
const cwd = input.directory ?? process.cwd();
|
|
70
|
+
if (args.action === "list") {
|
|
71
|
+
if (args.phase || args.name || args.model || args.variant !== undefined || args.confirmation_digest)
|
|
72
|
+
throw new Error("agent_profiles list accepts only scope");
|
|
73
|
+
return JSON.stringify({ status: "ok", inventory: await listAgentProfiles(args.scope, cwd) });
|
|
74
|
+
}
|
|
75
|
+
if (!args.phase)
|
|
76
|
+
throw new Error("agent_profiles mutation requires preview or apply phase");
|
|
77
|
+
const action = { model_set: "model-set", critic_add: "critic-add", critic_remove: "critic-remove" }[args.action];
|
|
78
|
+
const request = { action, ...(args.name ? { name: args.name } : {}), ...(args.model ? { model: args.model } : {}), ...(args.variant !== undefined ? { variant: args.variant } : {}) };
|
|
79
|
+
if (args.phase === "preview")
|
|
80
|
+
return JSON.stringify({ status: "ok", applied: false, requires_restart: false, plan: await previewAgentProfileChange(request, args.scope, cwd) });
|
|
81
|
+
if (!args.confirmation_digest)
|
|
82
|
+
throw new Error("agent_profiles apply requires confirmation_digest");
|
|
83
|
+
return JSON.stringify(await applyAgentProfileChange(request, args.scope, args.confirmation_digest, cwd));
|
|
84
|
+
},
|
|
85
|
+
});
|
|
55
86
|
return {
|
|
56
|
-
tool: { route, capabilities, doctor },
|
|
87
|
+
tool: { route, capabilities, doctor, agent_profiles: agentProfiles },
|
|
57
88
|
"tool.execute.before": async (input, output) => {
|
|
58
89
|
if (input.tool !== "task")
|
|
59
90
|
return;
|
package/dist/installer.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import { LifecycleError, type Scope, type TransactionOptions } from "./lifecycle.js";
|
|
2
|
+
export type { Scope } from "./lifecycle.js";
|
|
2
3
|
export type Action = "install" | "uninstall";
|
|
3
4
|
export type Operation = "create" | "update" | "remove" | "unchanged" | "missing" | "conflict";
|
|
4
5
|
export type PlanItem = {
|
|
@@ -12,14 +13,14 @@ export type Plan = {
|
|
|
12
13
|
action: Action;
|
|
13
14
|
scope: Scope;
|
|
14
15
|
root: string;
|
|
16
|
+
package_version: string;
|
|
15
17
|
operations: PlanItem[];
|
|
16
|
-
manifest_sha256?: string;
|
|
17
18
|
digest: string;
|
|
19
|
+
receipt_expires_at?: string;
|
|
20
|
+
requires_restart: boolean;
|
|
18
21
|
};
|
|
19
|
-
export declare class InstallerError extends
|
|
20
|
-
readonly code: string;
|
|
21
|
-
constructor(code: string, message: string);
|
|
22
|
+
export declare class InstallerError extends LifecycleError {
|
|
22
23
|
}
|
|
23
24
|
export declare function preview(action: Action, scope: Scope, cwd?: string, home?: string): Promise<Plan>;
|
|
24
|
-
export declare function apply(action: Action, scope: Scope,
|
|
25
|
+
export declare function apply(action: Action, scope: Scope, confirmationDigest: string, cwd?: string, home?: string, options?: TransactionOptions): Promise<Plan>;
|
|
25
26
|
export declare function result(plan: Plan, applied: boolean): string;
|