@kisev/agentomatic 11.0.2 → 12.0.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 +32 -16
- package/README.ru.md +33 -16
- package/dist/agent-profiles.d.ts +8 -2
- package/dist/agent-profiles.js +131 -82
- package/dist/assets/agents/architect.md +4 -4
- package/dist/assets/agents/critic.md +10 -11
- package/dist/assets/agents/manager.md +11 -12
- package/dist/assets/agents/mapper.md +4 -4
- package/dist/assets/agents/review.md +11 -12
- package/dist/assets/agents/worker.md +29 -32
- package/dist/assets/commands/asd-ste100.md +10 -0
- package/dist/assets/commands/code-simplify.md +12 -0
- package/dist/assets/commands/eli5.md +10 -0
- package/dist/assets/commands/handoff.md +10 -0
- package/dist/assets/commands/rtk-stats.md +2 -2
- package/dist/assets/commands/skill-doctor.md +10 -0
- package/dist/assets/migration-inventory.json +17 -6
- package/dist/assets/plugins/code-simplify.js +3 -0
- package/dist/assets/plugins/rtk.js +1 -1
- package/dist/assets/plugins/rules-injector.js +1 -1
- package/dist/assets/plugins/zed-bell.js +1 -1
- package/dist/catalog.d.ts +2 -2
- package/dist/catalog.js +9 -3
- package/dist/cli-output.js +6 -6
- package/dist/cli.d.ts +1 -1
- package/dist/cli.js +1 -1257
- package/dist/command-cli.d.ts +1 -0
- package/dist/command-cli.js +1004 -0
- package/dist/config-setup.d.ts +14 -8
- package/dist/config-setup.js +197 -64
- package/dist/contracts.js +26 -0
- package/dist/doctor.d.ts +0 -1
- package/dist/doctor.js +42 -55
- package/dist/index.d.ts +13 -118
- package/dist/index.js +118 -125
- package/dist/installer.d.ts +25 -2
- package/dist/installer.js +68 -23
- package/dist/jsonc.d.ts +18 -2
- package/dist/jsonc.js +109 -5
- package/dist/opencode-config.d.ts +11 -0
- package/dist/opencode-config.js +237 -0
- package/dist/plugins/code-simplify.d.ts +25 -0
- package/dist/plugins/code-simplify.js +49 -0
- package/dist/plugins/events.d.ts +20 -0
- package/dist/plugins/events.js +48 -0
- package/dist/plugins/rtk.d.ts +9 -12
- package/dist/plugins/rtk.js +20 -5
- package/dist/plugins/rules-injector.d.ts +21 -11
- package/dist/plugins/rules-injector.js +43 -31
- package/dist/plugins/zed-bell.d.ts +8 -5
- package/dist/plugins/zed-bell.js +10 -2
- package/dist/reconcile.d.ts +4 -1
- package/dist/reconcile.js +12 -16
- package/dist/registry.d.ts +1 -0
- package/dist/registry.js +21 -5
- package/dist/routing.d.ts +5 -3
- package/dist/routing.js +57 -22
- package/dist/self-install.d.ts +7 -0
- package/dist/self-install.js +52 -1
- package/dist/terminal-wizard.d.ts +1 -1
- package/dist/terminal-wizard.js +2 -2
- package/package.json +11 -6
- package/dist/assets/commands/skill-improve.md +0 -10
- package/dist/assets/commands/stopit.md +0 -10
package/dist/doctor.js
CHANGED
|
@@ -12,6 +12,7 @@ import { archiveRoot, assertSafePath, deploymentRoot, lifecycleRoot, } from "./l
|
|
|
12
12
|
import { inspectReconcile } from "./reconcile.js";
|
|
13
13
|
import { readPackageVersion } from "./package-metadata.js";
|
|
14
14
|
import { planDependency } from "./self-install.js";
|
|
15
|
+
import { parseJsonc } from "./jsonc.js";
|
|
15
16
|
import { readRtkStats, rtkCharsSaved, rtkStatsPath, rtkTokensSavedEstimate, } from "./plugins/rtk.js";
|
|
16
17
|
import { stateRoot } from "./runtime/state.js";
|
|
17
18
|
const run = promisify(execFile);
|
|
@@ -114,17 +115,19 @@ function agentManifestValid(raw) {
|
|
|
114
115
|
}
|
|
115
116
|
function redactedConfig(value) {
|
|
116
117
|
const object = value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
117
|
-
const
|
|
118
|
-
|
|
118
|
+
const configuredPlugins = object.plugins;
|
|
119
|
+
const rawPlugins = Array.isArray(configuredPlugins)
|
|
120
|
+
? configuredPlugins.flatMap((item) => {
|
|
119
121
|
if (typeof item === "string")
|
|
120
122
|
return [item];
|
|
121
|
-
if (
|
|
122
|
-
return [item
|
|
123
|
+
if (item && typeof item === "object" && typeof item.package === "string")
|
|
124
|
+
return [item.package];
|
|
123
125
|
return [];
|
|
124
126
|
})
|
|
125
127
|
: [];
|
|
126
128
|
const knownPlugins = new Set([packageName, ...CATALOG.plugins]);
|
|
127
|
-
const
|
|
129
|
+
const normalizePlugin = (plugin) => plugin === packageName || plugin.startsWith(`${packageName}@`) ? packageName : plugin;
|
|
130
|
+
const plugins = rawPlugins.map(normalizePlugin).filter((plugin) => knownPlugins.has(plugin));
|
|
128
131
|
const enabled = plugins.filter((plugin) => plugin === packageName ||
|
|
129
132
|
CATALOG.plugins.includes(plugin));
|
|
130
133
|
return {
|
|
@@ -135,17 +138,14 @@ function redactedConfig(value) {
|
|
|
135
138
|
keys: Object.keys(object)
|
|
136
139
|
.filter((key) => [
|
|
137
140
|
"$schema",
|
|
138
|
-
"
|
|
139
|
-
"keybinds",
|
|
140
|
-
"logLevel",
|
|
141
|
-
"command",
|
|
141
|
+
"commands",
|
|
142
142
|
"watcher",
|
|
143
|
-
"
|
|
143
|
+
"plugins",
|
|
144
144
|
"lsp",
|
|
145
145
|
"formatter",
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
146
|
+
"providers",
|
|
147
|
+
"agents",
|
|
148
|
+
"permissions",
|
|
149
149
|
"compaction",
|
|
150
150
|
"model",
|
|
151
151
|
].includes(key))
|
|
@@ -155,12 +155,26 @@ function redactedConfig(value) {
|
|
|
155
155
|
}
|
|
156
156
|
async function localConfig(scope, cwd, home) {
|
|
157
157
|
const paths = scope === "project"
|
|
158
|
-
? [
|
|
159
|
-
|
|
158
|
+
? [
|
|
159
|
+
join(cwd, "opencode.json"),
|
|
160
|
+
join(cwd, "opencode.jsonc"),
|
|
161
|
+
join(cwd, ".opencode", "opencode.json"),
|
|
162
|
+
join(cwd, ".opencode", "opencode.jsonc"),
|
|
163
|
+
]
|
|
164
|
+
: [
|
|
165
|
+
join(home, ".config", "opencode", "opencode.json"),
|
|
166
|
+
join(home, ".config", "opencode", "opencode.jsonc"),
|
|
167
|
+
];
|
|
160
168
|
for (const path of paths) {
|
|
161
169
|
const value = await regular(path);
|
|
162
170
|
if (value.status === "present") {
|
|
163
|
-
|
|
171
|
+
let parsed;
|
|
172
|
+
try {
|
|
173
|
+
parsed = parseJsonc(value.raw.toString("utf8"));
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
parsed = undefined;
|
|
177
|
+
}
|
|
164
178
|
return parsed
|
|
165
179
|
? { projection: redactedConfig(parsed), source: path }
|
|
166
180
|
: { incomplete: true, source: path };
|
|
@@ -250,7 +264,7 @@ async function executableAvailable(name) {
|
|
|
250
264
|
}
|
|
251
265
|
return false;
|
|
252
266
|
}
|
|
253
|
-
async function lspFacts(project,
|
|
267
|
+
async function lspFacts(project, partial) {
|
|
254
268
|
const suffixes = new Set();
|
|
255
269
|
let scanIncomplete = false;
|
|
256
270
|
const visit = async (root) => {
|
|
@@ -277,7 +291,6 @@ async function lspFacts(project, host, partial) {
|
|
|
277
291
|
await visit(project);
|
|
278
292
|
if (scanIncomplete)
|
|
279
293
|
partial.push("lsp.project-files");
|
|
280
|
-
const disabled = process.env.OPENCODE_DISABLE_LSP_DOWNLOAD === "true";
|
|
281
294
|
const servers = await Promise.all(lspCatalog.servers.map(async (server) => {
|
|
282
295
|
let available = false;
|
|
283
296
|
available = await executableAvailable(server.executable);
|
|
@@ -285,48 +298,20 @@ async function lspFacts(project, host, partial) {
|
|
|
285
298
|
return {
|
|
286
299
|
name: server.name,
|
|
287
300
|
applicable,
|
|
288
|
-
configured:
|
|
301
|
+
configured: false,
|
|
289
302
|
binary_available: available,
|
|
290
|
-
active:
|
|
291
|
-
runtime_status: "
|
|
303
|
+
active: false,
|
|
304
|
+
runtime_status: "unsupported",
|
|
292
305
|
requirement_class: server.requirement_class,
|
|
293
|
-
reason:
|
|
294
|
-
? "not-selected"
|
|
295
|
-
: disabled
|
|
296
|
-
? "download-disabled"
|
|
297
|
-
: !available
|
|
298
|
-
? "missing-dependency"
|
|
299
|
-
: "available",
|
|
306
|
+
reason: "unsupported-in-opencode-v2",
|
|
300
307
|
missing: available ? [] : [server.executable],
|
|
301
308
|
install: `Install ${server.executable} with your project toolchain.`,
|
|
302
309
|
};
|
|
303
310
|
}));
|
|
304
|
-
let runtimeStatus = "unavailable";
|
|
305
|
-
if (host?.lsp) {
|
|
306
|
-
try {
|
|
307
|
-
const value = await host.lsp();
|
|
308
|
-
runtimeStatus = Array.isArray(value)
|
|
309
|
-
? value.map((item) => {
|
|
310
|
-
const entry = item && typeof item === "object" ? item : {};
|
|
311
|
-
return {
|
|
312
|
-
id: typeof entry.id === "string" ? entry.id : "unknown",
|
|
313
|
-
name: typeof entry.name === "string" ? entry.name : "unknown",
|
|
314
|
-
status: entry.status === "connected" || entry.status === "error" ? entry.status : "unknown",
|
|
315
|
-
};
|
|
316
|
-
})
|
|
317
|
-
: { status: "unavailable" };
|
|
318
|
-
}
|
|
319
|
-
catch {
|
|
320
|
-
partial.push("lsp.runtime-status");
|
|
321
|
-
}
|
|
322
|
-
}
|
|
323
|
-
else
|
|
324
|
-
partial.push("lsp.runtime-status");
|
|
325
311
|
return {
|
|
326
312
|
schema_version: 1,
|
|
327
313
|
catalog_version: lspCatalog.catalog_version,
|
|
328
|
-
|
|
329
|
-
runtime_status: runtimeStatus,
|
|
314
|
+
runtime_status: "unsupported",
|
|
330
315
|
servers,
|
|
331
316
|
};
|
|
332
317
|
}
|
|
@@ -462,7 +447,9 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
|
|
|
462
447
|
collisions: inventory?.collisions.length ?? 0,
|
|
463
448
|
drift: inventory?.drift.length ?? 0,
|
|
464
449
|
user_owned: inventory?.user_owned.length ?? 0,
|
|
465
|
-
}, [
|
|
450
|
+
}, [
|
|
451
|
+
"Resolve ownership conflicts and restore modified bytes; preview maintenance repair for missing selected files.",
|
|
452
|
+
]));
|
|
466
453
|
const config = await localConfig(scope, project, homeRoot);
|
|
467
454
|
if (config.incomplete)
|
|
468
455
|
partial.push("config.local");
|
|
@@ -491,7 +478,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
|
|
|
491
478
|
source: config.source ?? "host-or-file-unavailable",
|
|
492
479
|
}, [
|
|
493
480
|
"Inspect OpenCode configuration without exposing secrets.",
|
|
494
|
-
"Local plugin wrappers in the deployment plugins directory load automatically without a
|
|
481
|
+
"Local plugin wrappers in the deployment plugins directory load automatically without a plugins array entry.",
|
|
495
482
|
]));
|
|
496
483
|
const wired = (config.projection?.enabled_plugins ?? []).includes(packageName) ||
|
|
497
484
|
(hostConfig?.enabled_plugins ?? []).includes(packageName);
|
|
@@ -623,7 +610,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
|
|
|
623
610
|
}, lifecycleFiles.incomplete
|
|
624
611
|
? ["Resolve inaccessible lifecycle state before applying a mutation."]
|
|
625
612
|
: undefined));
|
|
626
|
-
const tools = await Promise.all(["opencode"
|
|
613
|
+
const tools = await Promise.all(["opencode"].map(async (name) => {
|
|
627
614
|
try {
|
|
628
615
|
const result = await run(name, ["--version"], { timeout: 1000 });
|
|
629
616
|
return {
|
|
@@ -640,7 +627,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
|
|
|
640
627
|
}
|
|
641
628
|
}));
|
|
642
629
|
checks.push(check("host.tools", tools.some((item) => item.name === "opencode" && item.available) ? "pass" : "incomplete", "External tool availability is reported", { tools: tools.map((item) => `${item.name}:${item.available ? "available" : "missing"}`) }, ["Install OpenCode or missing external tools when needed."]));
|
|
643
|
-
const lsp = await lspFacts(project,
|
|
630
|
+
const lsp = await lspFacts(project, partial);
|
|
644
631
|
const counts = { pass: 0, warn: 0, fail: 0, incomplete: 0 };
|
|
645
632
|
for (const item of checks)
|
|
646
633
|
counts[item.status] += 1;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,123 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import rulesInjector,
|
|
3
|
-
import rtk,
|
|
4
|
-
import zedBell,
|
|
5
|
-
|
|
1
|
+
import type { Plugin } from "@opencode/plugin";
|
|
2
|
+
import { rulesInjector, type RulesInjectorOptions } from "./plugins/rules-injector.js";
|
|
3
|
+
import { rtk, type RtkOptions } from "./plugins/rtk.js";
|
|
4
|
+
import { zedBell, type ZedBellOptions } from "./plugins/zed-bell.js";
|
|
5
|
+
import { codeSimplify, CODE_SIMPLIFY_ROLES, type CodeSimplifyOptions, type CodeSimplifyRole } from "./plugins/code-simplify.js";
|
|
6
|
+
export { rulesInjector, rtk, zedBell, codeSimplify, CODE_SIMPLIFY_ROLES };
|
|
7
|
+
export type { CodeSimplifyOptions, CodeSimplifyRole };
|
|
6
8
|
export type OpenCodeOptions = {
|
|
7
9
|
rulesInjector?: RulesInjectorOptions;
|
|
8
10
|
rtk?: RtkOptions;
|
|
9
11
|
zedBell?: ZedBellOptions;
|
|
12
|
+
codeSimplify?: CodeSimplifyOptions;
|
|
10
13
|
};
|
|
11
|
-
declare const
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
action: import("zod").ZodEnum<{
|
|
17
|
-
dispatch: "dispatch";
|
|
18
|
-
preview: "preview";
|
|
19
|
-
}>;
|
|
20
|
-
category: import("zod").ZodEnum<{
|
|
21
|
-
architecture: "architecture";
|
|
22
|
-
exploration: "exploration";
|
|
23
|
-
implementation: "implementation";
|
|
24
|
-
review: "review";
|
|
25
|
-
}>;
|
|
26
|
-
task: import("zod").ZodString;
|
|
27
|
-
requirements: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodString>>;
|
|
28
|
-
execution_card: import("zod").ZodOptional<import("zod").ZodAny>;
|
|
29
|
-
override: import("zod").ZodOptional<import("zod").ZodString>;
|
|
30
|
-
trusted_override: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
31
|
-
budget: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
32
|
-
cost_class: import("zod").ZodOptional<import("zod").ZodString>;
|
|
33
|
-
latency_class: import("zod").ZodOptional<import("zod").ZodString>;
|
|
34
|
-
}, import("zod/v4/core").$strip>>;
|
|
35
|
-
decision: import("zod").ZodOptional<import("zod").ZodAny>;
|
|
36
|
-
};
|
|
37
|
-
execute(args: {
|
|
38
|
-
action: "dispatch" | "preview";
|
|
39
|
-
category: "architecture" | "exploration" | "implementation" | "review";
|
|
40
|
-
task: string;
|
|
41
|
-
requirements: string[];
|
|
42
|
-
execution_card?: any;
|
|
43
|
-
override?: string | undefined;
|
|
44
|
-
trusted_override?: boolean | undefined;
|
|
45
|
-
budget?: {
|
|
46
|
-
cost_class?: string | undefined;
|
|
47
|
-
latency_class?: string | undefined;
|
|
48
|
-
} | undefined;
|
|
49
|
-
decision?: any;
|
|
50
|
-
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
51
|
-
};
|
|
52
|
-
};
|
|
53
|
-
"tool.execute.before": (input: {
|
|
54
|
-
tool: string;
|
|
55
|
-
sessionID: string;
|
|
56
|
-
}, output: {
|
|
57
|
-
args: unknown;
|
|
58
|
-
}) => Promise<void>;
|
|
59
|
-
"tool.execute.after": (input: {
|
|
60
|
-
tool: string;
|
|
61
|
-
sessionID: string;
|
|
62
|
-
args: unknown;
|
|
63
|
-
}, output: {
|
|
64
|
-
output: string;
|
|
65
|
-
}) => Promise<void>;
|
|
66
|
-
}>;
|
|
67
|
-
export declare const server: (input: PluginInput) => Promise<{
|
|
68
|
-
tool: {
|
|
69
|
-
route: {
|
|
70
|
-
description: string;
|
|
71
|
-
args: {
|
|
72
|
-
action: import("zod").ZodEnum<{
|
|
73
|
-
dispatch: "dispatch";
|
|
74
|
-
preview: "preview";
|
|
75
|
-
}>;
|
|
76
|
-
category: import("zod").ZodEnum<{
|
|
77
|
-
architecture: "architecture";
|
|
78
|
-
exploration: "exploration";
|
|
79
|
-
implementation: "implementation";
|
|
80
|
-
review: "review";
|
|
81
|
-
}>;
|
|
82
|
-
task: import("zod").ZodString;
|
|
83
|
-
requirements: import("zod").ZodDefault<import("zod").ZodArray<import("zod").ZodString>>;
|
|
84
|
-
execution_card: import("zod").ZodOptional<import("zod").ZodAny>;
|
|
85
|
-
override: import("zod").ZodOptional<import("zod").ZodString>;
|
|
86
|
-
trusted_override: import("zod").ZodOptional<import("zod").ZodBoolean>;
|
|
87
|
-
budget: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
88
|
-
cost_class: import("zod").ZodOptional<import("zod").ZodString>;
|
|
89
|
-
latency_class: import("zod").ZodOptional<import("zod").ZodString>;
|
|
90
|
-
}, import("zod/v4/core").$strip>>;
|
|
91
|
-
decision: import("zod").ZodOptional<import("zod").ZodAny>;
|
|
92
|
-
};
|
|
93
|
-
execute(args: {
|
|
94
|
-
action: "dispatch" | "preview";
|
|
95
|
-
category: "architecture" | "exploration" | "implementation" | "review";
|
|
96
|
-
task: string;
|
|
97
|
-
requirements: string[];
|
|
98
|
-
execution_card?: any;
|
|
99
|
-
override?: string | undefined;
|
|
100
|
-
trusted_override?: boolean | undefined;
|
|
101
|
-
budget?: {
|
|
102
|
-
cost_class?: string | undefined;
|
|
103
|
-
latency_class?: string | undefined;
|
|
104
|
-
} | undefined;
|
|
105
|
-
decision?: any;
|
|
106
|
-
}, context: import("@opencode-ai/plugin").ToolContext): Promise<import("@opencode-ai/plugin").ToolResult>;
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
"tool.execute.before": (input: {
|
|
110
|
-
tool: string;
|
|
111
|
-
sessionID: string;
|
|
112
|
-
}, output: {
|
|
113
|
-
args: unknown;
|
|
114
|
-
}) => Promise<void>;
|
|
115
|
-
"tool.execute.after": (input: {
|
|
116
|
-
tool: string;
|
|
117
|
-
sessionID: string;
|
|
118
|
-
args: unknown;
|
|
119
|
-
}, output: {
|
|
120
|
-
output: string;
|
|
121
|
-
}) => Promise<void>;
|
|
122
|
-
}>;
|
|
123
|
-
export default plugin;
|
|
14
|
+
declare const _default: {
|
|
15
|
+
id: string;
|
|
16
|
+
setup(ctx: Plugin.Context): Promise<void>;
|
|
17
|
+
};
|
|
18
|
+
export default _default;
|
package/dist/index.js
CHANGED
|
@@ -1,140 +1,133 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { z } from "zod";
|
|
2
2
|
import { CATEGORIES, RoutingGate, } from "./routing.js";
|
|
3
|
-
import rulesInjector from "./plugins/rules-injector.js";
|
|
4
|
-
import rtk from "./plugins/rtk.js";
|
|
5
|
-
import zedBell from "./plugins/zed-bell.js";
|
|
3
|
+
import { rulesInjector } from "./plugins/rules-injector.js";
|
|
4
|
+
import { rtk } from "./plugins/rtk.js";
|
|
5
|
+
import { zedBell } from "./plugins/zed-bell.js";
|
|
6
|
+
import { codeSimplify, CODE_SIMPLIFY_ROLES, } from "./plugins/code-simplify.js";
|
|
7
|
+
import { resultText, toolInput } from "./plugins/events.js";
|
|
6
8
|
import { digest } from "./lifecycle.js";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const capabilities = {
|
|
18
|
-
mapper: ["read", "search"],
|
|
19
|
-
architect: ["read", "architecture"],
|
|
20
|
-
worker: ["read", "write", "verify"],
|
|
21
|
-
review: ["read", "review"],
|
|
22
|
-
critic: ["read", "review"],
|
|
23
|
-
};
|
|
24
|
-
const agents = raw.map((value) => {
|
|
25
|
-
const agent = value;
|
|
26
|
-
if (typeof agent.name !== "string" || !agent.name)
|
|
27
|
-
throw new Error("Resolved OpenCode agent has no name");
|
|
28
|
-
return {
|
|
29
|
-
agent: agent.name,
|
|
30
|
-
available: true,
|
|
31
|
-
capabilities: capabilities[agent.name] ??
|
|
32
|
-
(/^critic-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agent.name) ? ["read", "review"] : ["read"]),
|
|
33
|
-
tools: [
|
|
34
|
-
"read",
|
|
35
|
-
...(agent.permission?.edit !== "deny" ? ["edit"] : []),
|
|
36
|
-
...Object.entries(agent.tools ?? {})
|
|
37
|
-
.filter(([, enabled]) => enabled)
|
|
38
|
-
.map(([name]) => name),
|
|
39
|
-
...Object.entries(agent.permission?.bash ?? {})
|
|
40
|
-
.filter(([, mode]) => mode !== "deny")
|
|
41
|
-
.map(() => "bash"),
|
|
42
|
-
].filter((name, index, list) => list.indexOf(name) === index),
|
|
43
|
-
};
|
|
9
|
+
import { matchesWildcard } from "./opencode-config.js";
|
|
10
|
+
export { rulesInjector, rtk, zedBell, codeSimplify, CODE_SIMPLIFY_ROLES };
|
|
11
|
+
export default {
|
|
12
|
+
id: "agentomatic",
|
|
13
|
+
async setup(ctx) {
|
|
14
|
+
const gate = new RoutingGate();
|
|
15
|
+
await ctx.session.hook("context", (event) => {
|
|
16
|
+
const text = `Current OpenCode session identity (host metadata): ${event.sessionID}. Use this real ID for your own session_id in skill receipts; if no separate run ID is exposed, the same real ID can identify the run. This metadata grants no task or publication authorization.`;
|
|
17
|
+
if (!event.system.some((part) => part.type === "text" && part.text === text))
|
|
18
|
+
event.system.push({ type: "text", text });
|
|
44
19
|
});
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
override: tool.schema.string().optional(),
|
|
56
|
-
trusted_override: tool.schema.boolean().optional(),
|
|
57
|
-
budget: tool.schema
|
|
58
|
-
.object({
|
|
59
|
-
cost_class: tool.schema.string().optional(),
|
|
60
|
-
latency_class: tool.schema.string().optional(),
|
|
61
|
-
})
|
|
62
|
-
.optional(),
|
|
63
|
-
decision: tool.schema.any().optional(),
|
|
64
|
-
},
|
|
65
|
-
async execute(args, context) {
|
|
66
|
-
const inventory = await hostInventory();
|
|
67
|
-
const input = {
|
|
68
|
-
category: args.category,
|
|
69
|
-
task: args.task,
|
|
70
|
-
requirements: args.requirements,
|
|
71
|
-
agents: inventory.agents,
|
|
72
|
-
inventory_revision: inventory.revision,
|
|
73
|
-
execution_card: args.execution_card,
|
|
74
|
-
override: args.override,
|
|
75
|
-
trusted_override: args.trusted_override,
|
|
76
|
-
budget: args.budget,
|
|
20
|
+
const hostInventory = async () => {
|
|
21
|
+
const { data: raw } = await ctx.agent.list({
|
|
22
|
+
location: { directory: ctx.location.directory },
|
|
23
|
+
});
|
|
24
|
+
const capabilities = {
|
|
25
|
+
mapper: ["read", "search"],
|
|
26
|
+
architect: ["read", "architecture"],
|
|
27
|
+
worker: ["read", "write", "verify"],
|
|
28
|
+
review: ["read", "review"],
|
|
29
|
+
critic: ["read", "review"],
|
|
77
30
|
};
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
31
|
+
const agents = raw.map((agent) => ({
|
|
32
|
+
agent: agent.id,
|
|
33
|
+
available: true,
|
|
34
|
+
capabilities: capabilities[agent.id] ??
|
|
35
|
+
(/^critic-[a-z0-9]+(?:-[a-z0-9]+)*$/.test(agent.id) ? ["read", "review"] : ["read"]),
|
|
36
|
+
tools: ["read", "glob", "grep", "edit", "shell"].filter((action) => {
|
|
37
|
+
const rules = agent.permissions.filter((rule) => matchesWildcard(rule.action, action));
|
|
38
|
+
const broad = rules.reduce((last, rule, index) => (rule.resource === "*" ? index : last), -1);
|
|
39
|
+
return rules.slice(Math.max(0, broad)).some((rule) => rule.effect !== "deny");
|
|
40
|
+
}),
|
|
41
|
+
}));
|
|
42
|
+
return { agents, revision: digest(raw) };
|
|
43
|
+
};
|
|
44
|
+
await ctx.tool.transform((editor) => {
|
|
45
|
+
editor.add({
|
|
46
|
+
name: "route",
|
|
47
|
+
description: "Resolve a capability category and dispatch one eligible agent through a one-use subagent receipt gate.",
|
|
48
|
+
input: z.object({
|
|
49
|
+
action: z.enum(["preview", "dispatch"]),
|
|
50
|
+
category: z.enum(CATEGORIES),
|
|
51
|
+
task: z.string(),
|
|
52
|
+
requirements: z.array(z.string()).default([]),
|
|
53
|
+
execution_card: z.any().optional(),
|
|
54
|
+
override: z.string().optional(),
|
|
55
|
+
trusted_override: z.boolean().optional(),
|
|
56
|
+
budget: z
|
|
57
|
+
.object({ cost_class: z.string().optional(), latency_class: z.string().optional() })
|
|
58
|
+
.optional(),
|
|
59
|
+
decision: z.any().optional(),
|
|
60
|
+
}),
|
|
61
|
+
async execute(args, context) {
|
|
62
|
+
const inventory = await hostInventory();
|
|
63
|
+
const input = {
|
|
64
|
+
category: args.category,
|
|
65
|
+
task: args.task,
|
|
66
|
+
requirements: args.requirements,
|
|
67
|
+
agents: inventory.agents,
|
|
68
|
+
inventory_revision: inventory.revision,
|
|
69
|
+
execution_card: args.execution_card,
|
|
70
|
+
override: args.override,
|
|
71
|
+
trusted_override: args.trusted_override,
|
|
72
|
+
budget: args.budget,
|
|
73
|
+
};
|
|
74
|
+
if (args.action === "preview")
|
|
75
|
+
return { content: JSON.stringify(gate.preview(input)) };
|
|
76
|
+
const decision = gate.dispatch(input, args.decision);
|
|
77
|
+
if (decision.agent === "worker" && args.execution_card === undefined)
|
|
78
|
+
throw new Error("implementation dispatch requires a confirmed execution card");
|
|
79
|
+
const receipt = gate.grant(context.sessionID, decision, {
|
|
80
|
+
task: args.task,
|
|
81
|
+
requirements: args.requirements,
|
|
82
|
+
card: args.execution_card,
|
|
83
|
+
});
|
|
84
|
+
return { content: JSON.stringify({ decision, receipt, status: "routed" }) };
|
|
85
|
+
},
|
|
87
86
|
});
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (
|
|
87
|
+
});
|
|
88
|
+
await ctx.tool.hook("execute.before", async (event) => {
|
|
89
|
+
if (event.tool !== "subagent")
|
|
90
|
+
return;
|
|
91
|
+
const args = toolInput(event.input);
|
|
92
|
+
const agent = typeof args.agent === "string" ? args.agent : undefined;
|
|
93
|
+
if (!gate.requiresReceipt(event.sessionID, agent ?? event.agent))
|
|
95
94
|
return;
|
|
96
|
-
const args = output.args && typeof output.args === "object"
|
|
97
|
-
? output.args
|
|
98
|
-
: {};
|
|
99
|
-
const agent = typeof args.agent === "string"
|
|
100
|
-
? args.agent
|
|
101
|
-
: typeof args.subagent_type === "string"
|
|
102
|
-
? args.subagent_type
|
|
103
|
-
: undefined;
|
|
104
95
|
if (!agent)
|
|
105
|
-
throw new Error("Native
|
|
96
|
+
throw new Error("Native subagent requires an explicit agent and an active routing receipt");
|
|
106
97
|
const hasBinding = "task" in args || "requirements" in args || "execution_card" in args;
|
|
107
98
|
if (!hasBinding)
|
|
108
|
-
gate.consume(
|
|
109
|
-
else
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
? args.requirements
|
|
113
|
-
:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
if (input.tool !== "task")
|
|
99
|
+
gate.consume(event.sessionID, agent, undefined, event.id);
|
|
100
|
+
else
|
|
101
|
+
gate.consume(event.sessionID, agent, {
|
|
102
|
+
task: typeof args.task === "string" ? args.task : "",
|
|
103
|
+
requirements: Array.isArray(args.requirements) ? args.requirements : [],
|
|
104
|
+
card: args.execution_card,
|
|
105
|
+
}, event.id);
|
|
106
|
+
});
|
|
107
|
+
await ctx.tool.hook("execute.after", async (event) => {
|
|
108
|
+
if (event.tool !== "subagent")
|
|
119
109
|
return;
|
|
120
|
-
const args =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
throw new Error("Task result requires an explicit agent");
|
|
110
|
+
const args = toolInput(event.input);
|
|
111
|
+
if (typeof args.agent !== "string" || !gate.hasActive(event.sessionID, args.agent, event.id))
|
|
112
|
+
return;
|
|
113
|
+
if (event.status !== "completed") {
|
|
114
|
+
gate.cancel(event.sessionID, event.id);
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
128
117
|
let result;
|
|
129
118
|
try {
|
|
130
|
-
result = JSON.parse(
|
|
119
|
+
result = JSON.parse(resultText(event.result) ?? "");
|
|
131
120
|
}
|
|
132
121
|
catch {
|
|
133
|
-
|
|
122
|
+
gate.cancel(event.sessionID, event.id);
|
|
123
|
+
throw new Error("Subagent result must be JSON structured report");
|
|
134
124
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
125
|
+
try {
|
|
126
|
+
gate.complete(event.sessionID, args.agent, result, event.id);
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
gate.cancel(event.sessionID, event.id);
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
},
|
|
133
|
+
};
|
package/dist/installer.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type AgentProfileRequest } from "./agent-profiles.js";
|
|
1
2
|
import { LifecycleError, type FileMutation, type Scope, type TransactionOptions } from "./lifecycle.js";
|
|
2
3
|
import { CATALOG } from "./catalog.js";
|
|
3
4
|
import { type FixedAgentRole } from "./agent-profiles.js";
|
|
@@ -30,6 +31,24 @@ export type Plan = {
|
|
|
30
31
|
applied?: "changed" | "unchanged" | "skipped";
|
|
31
32
|
};
|
|
32
33
|
requires_restart: boolean;
|
|
34
|
+
digest: string;
|
|
35
|
+
};
|
|
36
|
+
type ManifestFile = {
|
|
37
|
+
sha256: string;
|
|
38
|
+
mode: number;
|
|
39
|
+
kind: "command" | "agent" | "plugin" | "state";
|
|
40
|
+
};
|
|
41
|
+
type Manifest = {
|
|
42
|
+
schema_version: 2;
|
|
43
|
+
package: string;
|
|
44
|
+
package_version: string;
|
|
45
|
+
version: string;
|
|
46
|
+
scope: Scope;
|
|
47
|
+
commands: string[];
|
|
48
|
+
agents: FixedAgentRole[];
|
|
49
|
+
plugins: SelectablePlugin[];
|
|
50
|
+
core_activation: boolean;
|
|
51
|
+
files: Record<string, ManifestFile>;
|
|
33
52
|
};
|
|
34
53
|
export type ArchiveCandidate = {
|
|
35
54
|
path: string;
|
|
@@ -44,12 +63,16 @@ export type ArchiveCandidate = {
|
|
|
44
63
|
export declare const SELECTABLE_PLUGINS: SelectablePlugin[];
|
|
45
64
|
export declare const SKILL_COMMANDS: string[];
|
|
46
65
|
export declare function defaultSelection(): InstallerSelection;
|
|
66
|
+
export declare function savedSelection(manifest: Pick<Manifest, "commands" | "agents" | "plugins">): Partial<InstallerSelection>;
|
|
67
|
+
export declare function installedSelection(scope: Scope, cwd?: string, home?: string, overrides?: Partial<InstallerSelection>): Promise<InstallerSelection | null>;
|
|
68
|
+
export declare function coreSelectionMutation(root: string, enabled: boolean): Promise<FileMutation | undefined>;
|
|
47
69
|
export declare function normalizeSelection(value?: Partial<InstallerSelection>): InstallerSelection;
|
|
48
70
|
export declare class InstallerError extends LifecycleError {
|
|
49
71
|
}
|
|
50
72
|
export declare function archiveMutations(candidates: readonly ArchiveCandidate[], scope: Scope, cwd: string, home: string, sourceVersion: string, timestamp?: string): Promise<FileMutation[]>;
|
|
51
|
-
export declare function preview(action: Action, scope: Scope, cwd?: string, home?: string, selection?: Partial<InstallerSelection>, provisionDependency?: boolean): Promise<Plan>;
|
|
73
|
+
export declare function preview(action: Action, scope: Scope, cwd?: string, home?: string, selection?: Partial<InstallerSelection>, provisionDependency?: boolean, profileChanges?: AgentProfileRequest[]): Promise<Plan>;
|
|
52
74
|
export declare function apply(action: Action, scope: Scope, cwd?: string, home?: string, options?: TransactionOptions & {
|
|
53
75
|
dependencyRunner?: DependencyRunner;
|
|
54
|
-
|
|
76
|
+
expectedDigest?: string;
|
|
77
|
+
}, selection?: Partial<InstallerSelection>, provisionDependency?: boolean, profileChanges?: AgentProfileRequest[]): Promise<Plan>;
|
|
55
78
|
export declare function result(plan: Plan, applied: boolean): string;
|