@kisev/agentomatic 11.0.2-dev.92.gc67bdc97fcd1 → 11.0.2

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.
@@ -1,17 +1,19 @@
1
+ import { readFileSync } from "node:fs";
1
2
  import { randomUUID } from "node:crypto";
2
3
  import { lstat } from "node:fs/promises";
3
4
  import { homedir } from "node:os";
4
- import { join, resolve } from "node:path";
5
+ import { dirname, join, resolve } from "node:path";
6
+ import { fileURLToPath } from "node:url";
5
7
  import { archiveMutations } from "./installer.js";
6
8
  import { requirePackageVersion } from "./package-metadata.js";
7
9
  import { ensureDependency, planDependency } from "./self-install.js";
8
10
  import { applyTransaction, archiveRoot, deploymentRoot, LifecycleError, lifecycleRoot, inspectTransaction, readRegular, recoverTransaction, sha256, withLifecycleLock, } from "./lifecycle.js";
9
11
  import { applyJsoncEdits, parseJsonc } from "./jsonc.js";
10
- import { corePluginEdits, permissionEdits } from "./opencode-config.js";
11
12
  const PACKAGE_NAME = "@kisev/agentomatic";
13
+ const LEGACY_PACKAGE_NAME = "@kisev/skills-opencode";
14
+ const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
12
15
  const XDG_STATE_GLOB = "~/.local/state/agent-skills/**";
13
16
  const OPENCODE_SKILLS_GLOB = "~/.config/opencode/skills/**";
14
- const AGENTS_SKILLS_GLOB = "~/.agents/skills/**";
15
17
  const SECRET_PATHS = [
16
18
  "**/.env",
17
19
  "**/.env.*",
@@ -46,10 +48,16 @@ export const CONFIG_FRAGMENTS = [
46
48
  },
47
49
  {
48
50
  name: "skills-state-permissions",
49
- description: "Allow the canonical ~/.agents/skills tree and legacy skills state paths without per-run prompts",
51
+ description: "Allow the standard skills XDG state paths without per-run prompts",
50
52
  targets: ["opencode", "kilo", "mimo"],
51
53
  file: "main",
52
54
  },
55
+ {
56
+ name: "lsp-preset",
57
+ description: "Add LSP servers from the shared catalog (OpenCode only)",
58
+ targets: ["opencode"],
59
+ file: "main",
60
+ },
53
61
  {
54
62
  name: "secrets-guard",
55
63
  description: "Deny reads and edits of common secret files",
@@ -64,7 +72,7 @@ export const CONFIG_FRAGMENTS = [
64
72
  },
65
73
  {
66
74
  name: "tui-schema",
67
- description: "Configure terminal settings: OpenCode V2 cli.json or Kilo/MiMo TUI files",
75
+ description: "Unify each agent TUI file: schema, theme, stacked diffs, and leader keybinds",
68
76
  targets: ["opencode", "kilo", "mimo"],
69
77
  file: "tui",
70
78
  },
@@ -129,26 +137,23 @@ const UNIFIED_TUI_KEYBINDS = {
129
137
  messages_toggle_conceal: "<leader>h,<leader>р",
130
138
  tips_toggle: "<leader>h,<leader>р",
131
139
  };
132
- const OPENCODE_KEYBINDS = {
133
- "command.palette.show": "alt+p",
134
- "app.exit": "ctrl+d,<leader>q,<leader>й",
135
- "session.first": "ctrl+g",
136
- "session.last": "ctrl+alt+g",
137
- "prompt.editor": "<leader>e,<leader>у",
138
- "theme.switch": "<leader>t,<leader>е",
139
- "session.sidebar.toggle": "<leader>b,<leader>и",
140
- "opencode.status": "<leader>s,<leader>ы",
141
- "session.export": "<leader>x,<leader>ч",
142
- "session.new": "<leader>n,<leader>т",
143
- "session.list": "<leader>l,<leader>д",
144
- "session.timeline": "<leader>g,<leader>п",
145
- "session.compact": "<leader>c,<leader>с",
146
- "model.list": "<leader>m,<leader>ь",
147
- "agent.list": "<leader>a,<leader>ф",
148
- "messages.copy": "<leader>y,<leader>н",
149
- "session.undo": "<leader>u,<leader>г",
150
- "session.redo": "<leader>r,<leader>к",
140
+ const LSP_SERVER_COMMANDS = {
141
+ python: ["basedpyright-langserver", "--stdio"],
142
+ typescript: ["typescript-language-server", "--stdio"],
143
+ yaml: ["yaml-language-server", "--stdio"],
144
+ shell: ["bash-language-server", "start"],
151
145
  };
146
+ function lspCatalog() {
147
+ const raw = readFileSync(resolve(packageRoot, "dist", "assets", "lsp-catalog.json"), "utf8");
148
+ const catalog = JSON.parse(raw);
149
+ if (!Array.isArray(catalog.servers))
150
+ throw new ConfigSetupError("invalid_package", "LSP catalog is unavailable");
151
+ return catalog.servers
152
+ .filter((server) => typeof server.name === "string" &&
153
+ Array.isArray(server.extensions) &&
154
+ server.extensions.every((extension) => typeof extension === "string"))
155
+ .filter((server) => LSP_SERVER_COMMANDS[server.name]);
156
+ }
152
157
  function mapAllowsAll(value) {
153
158
  return Boolean(value &&
154
159
  typeof value === "object" &&
@@ -166,20 +171,20 @@ function fragmentEdits(fragment, target, current) {
166
171
  ? value.permission
167
172
  : {};
168
173
  if (fragment === "core-plugin") {
169
- return corePluginEdits(value);
174
+ return [
175
+ { kind: "set-if-absent", path: ["$schema"], value: "https://opencode.ai/config.json" },
176
+ { kind: "set-if-absent", path: ["plugin"], value: [] },
177
+ {
178
+ kind: "replace-array-value",
179
+ path: ["plugin"],
180
+ from: LEGACY_PACKAGE_NAME,
181
+ to: PACKAGE_NAME,
182
+ },
183
+ { kind: "append-unique", path: ["plugin"], value: PACKAGE_NAME },
184
+ ];
170
185
  }
171
186
  if (fragment === "skills-state-permissions") {
172
- const statePaths = target === "opencode"
173
- ? [XDG_STATE_GLOB, OPENCODE_SKILLS_GLOB, AGENTS_SKILLS_GLOB]
174
- : [XDG_STATE_GLOB];
175
- if (target === "opencode")
176
- return permissionEdits(value, [
177
- ...statePaths.flatMap((resource) => [
178
- { action: "read", resource, effect: "allow" },
179
- { action: "external_directory", resource, effect: "allow" },
180
- ]),
181
- { action: "edit", resource: XDG_STATE_GLOB, effect: "allow" },
182
- ]);
187
+ const statePaths = target === "opencode" ? [XDG_STATE_GLOB, OPENCODE_SKILLS_GLOB] : [XDG_STATE_GLOB];
183
188
  const edits = [];
184
189
  if (!mapAllowsAll(permission.read))
185
190
  edits.push(...permissionMapEdits(["permission", "read"], Object.fromEntries(statePaths.map((glob) => [glob, "allow"]))));
@@ -189,15 +194,14 @@ function fragmentEdits(fragment, target, current) {
189
194
  edits.push(...permissionMapEdits(["permission", "external_directory"], Object.fromEntries(statePaths.map((glob) => [glob, "allow"]))));
190
195
  return edits;
191
196
  }
197
+ if (fragment === "lsp-preset") {
198
+ return lspCatalog().map((server) => ({
199
+ kind: "set-if-absent",
200
+ path: ["lsp", server.name],
201
+ value: { command: LSP_SERVER_COMMANDS[server.name], extensions: server.extensions },
202
+ }));
203
+ }
192
204
  if (fragment === "secrets-guard") {
193
- if (target === "opencode")
194
- return permissionEdits(value, [
195
- ...SECRET_PATHS.flatMap((glob) => [
196
- { action: "read", resource: glob.replace(/^\*\*\//, "*"), effect: "deny" },
197
- { action: "edit", resource: glob.replace(/^\*\*\//, "*"), effect: "deny" },
198
- ]),
199
- { action: "read", resource: "*.env.example", effect: "allow" },
200
- ]);
201
205
  const deny = Object.fromEntries(SECRET_PATHS.map((glob) => [glob, "deny"]));
202
206
  return [
203
207
  ...permissionMapEdits(["permission", "read"], {
@@ -215,18 +219,8 @@ function fragmentEdits(fragment, target, current) {
215
219
  { kind: "set-if-absent", path: ["mcp_tool_display"], value: "expanded" },
216
220
  ];
217
221
  }
218
- if (target === "opencode")
219
- return [
220
- { kind: "set-if-absent", path: ["$schema"], value: "https://opencode.ai/v2/cli.json" },
221
- { kind: "set-if-absent", path: ["theme", "name"], value: "ayu" },
222
- ...Object.entries(OPENCODE_KEYBINDS).map(([key, value]) => ({
223
- kind: "set-if-absent",
224
- path: ["keybinds", key],
225
- value,
226
- })),
227
- ];
228
222
  const tuiSchemas = {
229
- opencode: undefined,
223
+ opencode: "https://opencode.ai/tui.json",
230
224
  kilo: undefined,
231
225
  mimo: "https://mimo.xiaomi.com/mimocode/tui.json",
232
226
  };
@@ -314,9 +308,9 @@ async function resolveTargetFile(target, scope, cwd, home, kind = "main") {
314
308
  return {
315
309
  target,
316
310
  root: globalRoot,
317
- path: "cli.json",
318
- absolute: join(globalRoot, "cli.json"),
319
- exists: await existing(globalRoot, "cli.json"),
311
+ path: "tui.json",
312
+ absolute: join(globalRoot, "tui.json"),
313
+ exists: await existing(globalRoot, "tui.json"),
320
314
  };
321
315
  }
322
316
  if (target === "opencode") {
@@ -410,20 +404,6 @@ async function build(selection, scope, cwd = process.cwd(), home = homedir()) {
410
404
  for (const fragment of selection.fragments) {
411
405
  if (!applicable(fragment, target) || fragmentFileKind(fragment) !== kind)
412
406
  continue;
413
- if (target === "opencode" &&
414
- kind === "tui" &&
415
- !file.exists &&
416
- ((await readRegular(join(file.root, "tui.json"))) ||
417
- (await readRegular(join(file.root, "tui.jsonc"))))) {
418
- operations.push({
419
- target,
420
- path: file.absolute,
421
- fragment,
422
- operation: "conflict",
423
- reason: "Start OpenCode V2 once to migrate existing TUI preferences into cli.json before applying terminal presets",
424
- });
425
- continue;
426
- }
427
407
  let parsed = undefined;
428
408
  try {
429
409
  parsed = parseJsonc(text);
@@ -594,8 +574,6 @@ export async function applyConfigSetup(selection, scope, cwd = process.cwd(), ho
594
574
  await provision();
595
575
  return built.plan;
596
576
  }
597
- if (!built.plan.operations.some((operation) => operation.operation === "conflict"))
598
- return built.plan;
599
577
  throw new ConfigSetupError("invalid_state", "Config setup plan has no applicable changes");
600
578
  }
601
579
  const backups = [];
package/dist/doctor.d.ts CHANGED
@@ -9,6 +9,7 @@ export type DoctorCheck = {
9
9
  };
10
10
  export type DoctorHost = {
11
11
  config?: () => Promise<unknown>;
12
+ lsp?: () => Promise<unknown>;
12
13
  };
13
14
  export type DoctorReport = {
14
15
  schema_version: 1;
package/dist/doctor.js CHANGED
@@ -12,7 +12,6 @@ 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";
16
15
  import { readRtkStats, rtkCharsSaved, rtkStatsPath, rtkTokensSavedEstimate, } from "./plugins/rtk.js";
17
16
  import { stateRoot } from "./runtime/state.js";
18
17
  const run = promisify(execFile);
@@ -115,19 +114,17 @@ function agentManifestValid(raw) {
115
114
  }
116
115
  function redactedConfig(value) {
117
116
  const object = value && typeof value === "object" && !Array.isArray(value) ? value : {};
118
- const configuredPlugins = object.plugins;
119
- const rawPlugins = Array.isArray(configuredPlugins)
120
- ? configuredPlugins.flatMap((item) => {
117
+ const rawPlugins = Array.isArray(object.plugin)
118
+ ? object.plugin.flatMap((item) => {
121
119
  if (typeof item === "string")
122
120
  return [item];
123
- if (item && typeof item === "object" && typeof item.package === "string")
124
- return [item.package];
121
+ if (Array.isArray(item) && typeof item[0] === "string")
122
+ return [item[0]];
125
123
  return [];
126
124
  })
127
125
  : [];
128
126
  const knownPlugins = new Set([packageName, ...CATALOG.plugins]);
129
- const normalizePlugin = (plugin) => plugin === packageName || plugin.startsWith(`${packageName}@`) ? packageName : plugin;
130
- const plugins = rawPlugins.map(normalizePlugin).filter((plugin) => knownPlugins.has(plugin));
127
+ const plugins = rawPlugins.filter((plugin) => knownPlugins.has(plugin));
131
128
  const enabled = plugins.filter((plugin) => plugin === packageName ||
132
129
  CATALOG.plugins.includes(plugin));
133
130
  return {
@@ -138,14 +135,17 @@ function redactedConfig(value) {
138
135
  keys: Object.keys(object)
139
136
  .filter((key) => [
140
137
  "$schema",
141
- "commands",
138
+ "theme",
139
+ "keybinds",
140
+ "logLevel",
141
+ "command",
142
142
  "watcher",
143
- "plugins",
143
+ "plugin",
144
144
  "lsp",
145
145
  "formatter",
146
- "providers",
147
- "agents",
148
- "permissions",
146
+ "provider",
147
+ "agent",
148
+ "permission",
149
149
  "compaction",
150
150
  "model",
151
151
  ].includes(key))
@@ -155,26 +155,12 @@ function redactedConfig(value) {
155
155
  }
156
156
  async function localConfig(scope, cwd, home) {
157
157
  const paths = scope === "project"
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
- ];
158
+ ? [join(cwd, "opencode.json"), join(cwd, ".opencode", "opencode.json")]
159
+ : [join(home, ".config", "opencode", "opencode.json")];
168
160
  for (const path of paths) {
169
161
  const value = await regular(path);
170
162
  if (value.status === "present") {
171
- let parsed;
172
- try {
173
- parsed = parseJsonc(value.raw.toString("utf8"));
174
- }
175
- catch {
176
- parsed = undefined;
177
- }
163
+ const parsed = json(value.raw);
178
164
  return parsed
179
165
  ? { projection: redactedConfig(parsed), source: path }
180
166
  : { incomplete: true, source: path };
@@ -264,7 +250,7 @@ async function executableAvailable(name) {
264
250
  }
265
251
  return false;
266
252
  }
267
- async function lspFacts(project, partial) {
253
+ async function lspFacts(project, host, partial) {
268
254
  const suffixes = new Set();
269
255
  let scanIncomplete = false;
270
256
  const visit = async (root) => {
@@ -291,6 +277,7 @@ async function lspFacts(project, partial) {
291
277
  await visit(project);
292
278
  if (scanIncomplete)
293
279
  partial.push("lsp.project-files");
280
+ const disabled = process.env.OPENCODE_DISABLE_LSP_DOWNLOAD === "true";
294
281
  const servers = await Promise.all(lspCatalog.servers.map(async (server) => {
295
282
  let available = false;
296
283
  available = await executableAvailable(server.executable);
@@ -298,20 +285,48 @@ async function lspFacts(project, partial) {
298
285
  return {
299
286
  name: server.name,
300
287
  applicable,
301
- configured: false,
288
+ configured: applicable,
302
289
  binary_available: available,
303
- active: false,
304
- runtime_status: "unsupported",
290
+ active: applicable && available && !disabled,
291
+ runtime_status: "unavailable",
305
292
  requirement_class: server.requirement_class,
306
- reason: "unsupported-in-opencode-v2",
293
+ reason: !applicable
294
+ ? "not-selected"
295
+ : disabled
296
+ ? "download-disabled"
297
+ : !available
298
+ ? "missing-dependency"
299
+ : "available",
307
300
  missing: available ? [] : [server.executable],
308
301
  install: `Install ${server.executable} with your project toolchain.`,
309
302
  };
310
303
  }));
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");
311
325
  return {
312
326
  schema_version: 1,
313
327
  catalog_version: lspCatalog.catalog_version,
314
- runtime_status: "unsupported",
328
+ download_disabled: disabled,
329
+ runtime_status: runtimeStatus,
315
330
  servers,
316
331
  };
317
332
  }
@@ -476,7 +491,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
476
491
  source: config.source ?? "host-or-file-unavailable",
477
492
  }, [
478
493
  "Inspect OpenCode configuration without exposing secrets.",
479
- "Local plugin wrappers in the deployment plugins directory load automatically without a plugins array entry.",
494
+ "Local plugin wrappers in the deployment plugins directory load automatically without a plugin array entry.",
480
495
  ]));
481
496
  const wired = (config.projection?.enabled_plugins ?? []).includes(packageName) ||
482
497
  (hostConfig?.enabled_plugins ?? []).includes(packageName);
@@ -608,7 +623,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
608
623
  }, lifecycleFiles.incomplete
609
624
  ? ["Resolve inaccessible lifecycle state before applying a mutation."]
610
625
  : undefined));
611
- const tools = await Promise.all(["opencode"].map(async (name) => {
626
+ const tools = await Promise.all(["opencode", ...lspCatalog.servers.map((server) => server.executable)].map(async (name) => {
612
627
  try {
613
628
  const result = await run(name, ["--version"], { timeout: 1000 });
614
629
  return {
@@ -625,7 +640,7 @@ export async function collectDoctorFacts(scope, cwd = process.cwd(), home = home
625
640
  }
626
641
  }));
627
642
  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."]));
628
- const lsp = await lspFacts(project, partial);
643
+ const lsp = await lspFacts(project, host, partial);
629
644
  const counts = { pass: 0, warn: 0, fail: 0, incomplete: 0 };
630
645
  for (const item of checks)
631
646
  counts[item.status] += 1;
package/dist/index.d.ts CHANGED
@@ -1,15 +1,123 @@
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";
1
+ import { type PluginInput } from "@opencode-ai/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
5
  export { rulesInjector, rtk, zedBell };
6
6
  export type OpenCodeOptions = {
7
7
  rulesInjector?: RulesInjectorOptions;
8
8
  rtk?: RtkOptions;
9
9
  zedBell?: ZedBellOptions;
10
10
  };
11
- declare const _default: {
12
- id: string;
13
- setup(ctx: Plugin.Context): Promise<void>;
14
- };
15
- export default _default;
11
+ declare const plugin: (input: PluginInput) => Promise<{
12
+ tool: {
13
+ route: {
14
+ description: string;
15
+ args: {
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;