opencode-akane 0.1.1 → 0.1.3

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 CHANGED
@@ -19,6 +19,13 @@ This repository now contains the first MVP skeleton for the plugin:
19
19
  - `src/artifacts.ts`: `.opencode/akane/` artifact and `state.json` helpers
20
20
  - `src/tools/akane-init.ts`: initializes the per-project workspace
21
21
  - `src/tools/akane-stage-artifact.ts`: writes stage artifacts deterministically
22
+ - `src/workflow.ts`: child-session orchestration, stage prompts, and artifact handoff
23
+ - `src/tools/akane-plan.ts`: planner stage
24
+ - `src/tools/akane-plan-review.ts`: plan review stage
25
+ - `src/tools/akane-implement.ts`: implementation stage
26
+ - `src/tools/akane-review.ts`: review stage
27
+ - `src/tools/akane-synthesize.ts`: final synthesis stage
28
+ - `src/tools/akane-run.ts`: end-to-end MVP workflow runner
22
29
  - `examples/akane.example.json`: example global Akane config
23
30
 
24
31
  ## Local development
@@ -31,6 +38,24 @@ bun run build
31
38
 
32
39
  The build emits `dist/index.js` as the package entrypoint and also keeps `dist/akane.js` for local file-based linking.
33
40
 
41
+ ## Available tools
42
+
43
+ Once the plugin is loaded in OpenCode, the current MVP exposes these tools:
44
+
45
+ - `akane_init`
46
+ - `akane_stage_artifact`
47
+ - `akane_plan`
48
+ - `akane_plan_review`
49
+ - `akane_implement`
50
+ - `akane_review`
51
+ - `akane_synthesize`
52
+ - `akane_run`
53
+
54
+ Notes:
55
+
56
+ - `akane_init` is optional because the stage tools lazily create `.opencode/akane/` on first use
57
+ - `akane_run` is the main MVP entrypoint when you want to test the full workflow
58
+
34
59
  ## Package install
35
60
 
36
61
  For package-based installation, publish this repository to npm and add it to the OpenCode plugin array in `~/.config/opencode/opencode.json`:
@@ -40,12 +65,14 @@ For package-based installation, publish this repository to npm and add it to the
40
65
  "$schema": "https://opencode.ai/config.json",
41
66
  "plugin": [
42
67
  "oh-my-opencode@latest",
43
- "opencode-akane@0.1.0"
68
+ "opencode-akane@latest"
44
69
  ]
45
70
  }
46
71
  ```
47
72
 
48
73
  Akane still reads its runtime config from `~/.config/opencode/akane.json`.
74
+ If that file does not exist yet, the plugin now bootstraps it automatically on first load with the default config.
75
+ You only need to edit it when you want to override the default role or artifact settings.
49
76
 
50
77
  ## Publish flow
51
78
 
@@ -1,4 +1,4 @@
1
- import type { AkaneConfig, AkaneStageId, AkaneState, ArtifactWriteMode } from "./types.js";
1
+ import type { AkaneConfig, AkaneStageId, AkaneStageState, AkaneState, ArtifactWriteMode } from "./types.js";
2
2
  export declare function resolveProjectRoot(input: {
3
3
  directory: string;
4
4
  worktree?: string;
@@ -30,6 +30,7 @@ export declare function writeStageArtifact(input: {
30
30
  stage: AkaneStageId;
31
31
  content: string;
32
32
  mode: ArtifactWriteMode;
33
+ details?: Partial<Omit<AkaneStageState, "path" | "status" | "updatedAt">>;
33
34
  }): Promise<{
34
35
  artifactDir: string;
35
36
  artifactPath: string;
package/dist/artifacts.js CHANGED
@@ -133,6 +133,7 @@ export async function writeStageArtifact(input) {
133
133
  path: artifactPath,
134
134
  status: "completed",
135
135
  updatedAt: timestamp,
136
+ ...input.details,
136
137
  };
137
138
  await writeStateFile(ensured.statePath, state);
138
139
  return {
package/dist/config.d.ts CHANGED
@@ -3,7 +3,7 @@ type DeepPartial<T> = {
3
3
  [K in keyof T]?: T[K] extends Array<infer U> ? U[] : T[K] extends Record<string, unknown> ? DeepPartial<T[K]> : T[K];
4
4
  };
5
5
  export declare function expandHome(inputPath: string): string;
6
- export declare function defaultAkaneConfig(): AkaneConfig;
6
+ export declare function defaultAkaneConfig(configPath?: string): AkaneConfig;
7
7
  export declare function mergeAkaneConfig(base: AkaneConfig, overrides: DeepPartial<AkaneConfig>): AkaneConfig;
8
8
  export declare function loadAkaneConfig(configPath?: string): Promise<LoadedAkaneConfig>;
9
9
  export {};
package/dist/config.js CHANGED
@@ -1,4 +1,4 @@
1
- import { readFile } from "node:fs/promises";
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import os from "node:os";
3
3
  import path from "node:path";
4
4
  import { AKANE_SERVICE_NAME, AKANE_STAGE_IDS, DEFAULT_ARTIFACT_DIR, DEFAULT_GLOBAL_CONFIG_PATH, DEFAULT_PLUGIN_OUTPUT_PATH, DEFAULT_ROLE_MODELS, DEFAULT_STAGE_FILES, DEFAULT_STAGE_ORDER, DEFAULT_STATE_FILE, } from "./constants.js";
@@ -14,12 +14,35 @@ export function expandHome(inputPath) {
14
14
  }
15
15
  return inputPath;
16
16
  }
17
- export function defaultAkaneConfig() {
17
+ function formatAkaneConfig(config) {
18
+ return `${JSON.stringify(config, null, 2)}\n`;
19
+ }
20
+ async function readAkaneConfigFile(filePath) {
21
+ const raw = await readFile(filePath, "utf8");
22
+ return parseJsonFile(raw, filePath);
23
+ }
24
+ async function bootstrapAkaneConfigFile(filePath, config) {
25
+ await mkdir(path.dirname(filePath), { recursive: true });
26
+ try {
27
+ await writeFile(filePath, formatAkaneConfig(config), {
28
+ encoding: "utf8",
29
+ flag: "wx",
30
+ });
31
+ return true;
32
+ }
33
+ catch (error) {
34
+ if (error.code === "EEXIST") {
35
+ return false;
36
+ }
37
+ throw error;
38
+ }
39
+ }
40
+ export function defaultAkaneConfig(configPath = DEFAULT_GLOBAL_CONFIG_PATH) {
18
41
  return {
19
42
  version: 1,
20
43
  serviceName: AKANE_SERVICE_NAME,
21
44
  pluginOutputPath: DEFAULT_PLUGIN_OUTPUT_PATH,
22
- globalConfigPath: DEFAULT_GLOBAL_CONFIG_PATH,
45
+ globalConfigPath: configPath,
23
46
  artifacts: {
24
47
  dir: DEFAULT_ARTIFACT_DIR,
25
48
  stateFile: DEFAULT_STATE_FILE,
@@ -109,10 +132,9 @@ export function mergeAkaneConfig(base, overrides) {
109
132
  }
110
133
  export async function loadAkaneConfig(configPath = process.env.AKANE_CONFIG_PATH ?? DEFAULT_GLOBAL_CONFIG_PATH) {
111
134
  const resolvedPath = expandHome(configPath);
112
- const defaults = defaultAkaneConfig();
135
+ const defaults = defaultAkaneConfig(configPath);
113
136
  try {
114
- const raw = await readFile(resolvedPath, "utf8");
115
- const parsed = parseJsonFile(raw, resolvedPath);
137
+ const parsed = await readAkaneConfigFile(resolvedPath);
116
138
  return {
117
139
  path: resolvedPath,
118
140
  exists: true,
@@ -121,11 +143,33 @@ export async function loadAkaneConfig(configPath = process.env.AKANE_CONFIG_PATH
121
143
  }
122
144
  catch (error) {
123
145
  if (error.code === "ENOENT") {
124
- return {
125
- path: resolvedPath,
126
- exists: false,
127
- config: defaults,
128
- };
146
+ try {
147
+ const created = await bootstrapAkaneConfigFile(resolvedPath, defaults);
148
+ if (!created) {
149
+ const parsed = await readAkaneConfigFile(resolvedPath);
150
+ return {
151
+ path: resolvedPath,
152
+ exists: true,
153
+ config: mergeAkaneConfig(defaults, parsed),
154
+ };
155
+ }
156
+ return {
157
+ path: resolvedPath,
158
+ exists: true,
159
+ config: defaults,
160
+ };
161
+ }
162
+ catch (bootstrapError) {
163
+ const message = bootstrapError instanceof Error
164
+ ? bootstrapError.message
165
+ : "unknown bootstrap error";
166
+ console.warn(`Akane: failed to auto-create config at ${resolvedPath}: ${message}`);
167
+ return {
168
+ path: resolvedPath,
169
+ exists: false,
170
+ config: defaults,
171
+ };
172
+ }
129
173
  }
130
174
  throw error;
131
175
  }
@@ -4,6 +4,7 @@ export declare const DEFAULT_PLUGIN_OUTPUT_PATH = "~/.config/opencode/plugins/ak
4
4
  export declare const DEFAULT_ARTIFACT_DIR = ".opencode/akane";
5
5
  export declare const DEFAULT_STATE_FILE = "state.json";
6
6
  export declare const AKANE_STAGE_IDS: readonly ["plan", "plan-review", "implementation-context", "review-codex", "review-claude", "final-synthesis"];
7
+ export declare const AKANE_TOOL_IDS: readonly ["akane_init", "akane_stage_artifact", "akane_plan", "akane_plan_review", "akane_implement", "akane_review", "akane_synthesize", "akane_run"];
7
8
  export declare const AKANE_ROLE_IDS: readonly ["planner", "plan_reviewer", "implementer", "consultant_primary", "consultant_secondary", "reviewer_codex", "reviewer_claude", "synthesizer"];
8
9
  export declare const DEFAULT_ROLE_MODELS: {
9
10
  readonly planner: "anthropic/claude-opus-4-6";
package/dist/constants.js CHANGED
@@ -11,6 +11,16 @@ export const AKANE_STAGE_IDS = [
11
11
  "review-claude",
12
12
  "final-synthesis",
13
13
  ];
14
+ export const AKANE_TOOL_IDS = [
15
+ "akane_init",
16
+ "akane_stage_artifact",
17
+ "akane_plan",
18
+ "akane_plan_review",
19
+ "akane_implement",
20
+ "akane_review",
21
+ "akane_synthesize",
22
+ "akane_run",
23
+ ];
14
24
  export const AKANE_ROLE_IDS = [
15
25
  "planner",
16
26
  "plan_reviewer",
package/dist/plugin.js CHANGED
@@ -2,12 +2,24 @@ import { loadAkaneConfig } from "./config.js";
2
2
  import { resolveArtifactDir } from "./artifacts.js";
3
3
  import { createAkaneInitTool } from "./tools/akane-init.js";
4
4
  import { createAkaneStageArtifactTool } from "./tools/akane-stage-artifact.js";
5
+ import { createAkanePlanTool } from "./tools/akane-plan.js";
6
+ import { createAkanePlanReviewTool } from "./tools/akane-plan-review.js";
7
+ import { createAkaneImplementTool } from "./tools/akane-implement.js";
8
+ import { createAkaneReviewTool } from "./tools/akane-review.js";
9
+ import { createAkaneSynthesizeTool } from "./tools/akane-synthesize.js";
10
+ import { createAkaneRunTool } from "./tools/akane-run.js";
5
11
  export const AkanePlugin = async (input) => {
6
12
  const configInfo = await loadAkaneConfig();
7
13
  return {
8
14
  tool: {
9
15
  akane_init: createAkaneInitTool(configInfo),
10
16
  akane_stage_artifact: createAkaneStageArtifactTool(configInfo),
17
+ akane_plan: createAkanePlanTool(input, configInfo),
18
+ akane_plan_review: createAkanePlanReviewTool(input, configInfo),
19
+ akane_implement: createAkaneImplementTool(input, configInfo),
20
+ akane_review: createAkaneReviewTool(input, configInfo),
21
+ akane_synthesize: createAkaneSynthesizeTool(input, configInfo),
22
+ akane_run: createAkaneRunTool(input, configInfo),
11
23
  },
12
24
  "shell.env": async (_event, output) => {
13
25
  const projectRoot = input.worktree || input.directory;
@@ -0,0 +1,15 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkaneImplementTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ task: import("zod").ZodOptional<import("zod").ZodString>;
7
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
8
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
9
+ };
10
+ execute(args: {
11
+ task?: string | undefined;
12
+ notes?: string | undefined;
13
+ projectRoot?: string | undefined;
14
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
15
+ };
@@ -0,0 +1,53 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { executeImplementStage, resolveProjectRootFromArgs, } from "../workflow.js";
3
+ export function createAkaneImplementTool(pluginInput, configInfo) {
4
+ return tool({
5
+ description: "Implement the approved Akane plan in the repository and write implementation-context.md.",
6
+ args: {
7
+ task: tool.schema
8
+ .string()
9
+ .optional()
10
+ .describe("Optional task restatement for the implementer stage."),
11
+ notes: tool.schema
12
+ .string()
13
+ .optional()
14
+ .describe("Optional additional implementation constraints."),
15
+ projectRoot: tool.schema
16
+ .string()
17
+ .optional()
18
+ .describe("Optional project root override. Defaults to the current session worktree."),
19
+ },
20
+ async execute(args, context) {
21
+ try {
22
+ const projectRoot = resolveProjectRootFromArgs({
23
+ toolContext: context,
24
+ projectRoot: args.projectRoot,
25
+ });
26
+ context.metadata({
27
+ title: "Akane implement",
28
+ metadata: {
29
+ stage: "implementation-context",
30
+ projectRoot,
31
+ },
32
+ });
33
+ const result = await executeImplementStage({
34
+ pluginInput,
35
+ configInfo,
36
+ toolContext: context,
37
+ projectRoot,
38
+ task: args.task,
39
+ notes: args.notes,
40
+ });
41
+ return [
42
+ `Created Akane implementation artifact.`,
43
+ `Artifact: ${result.artifactPath}`,
44
+ `Session: ${result.sessionID}`,
45
+ `Model: ${result.model}`,
46
+ ].join("\n");
47
+ }
48
+ catch (error) {
49
+ return `Akane implement failed: ${error instanceof Error ? error.message : String(error)}`;
50
+ }
51
+ },
52
+ });
53
+ }
@@ -0,0 +1,15 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkanePlanReviewTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ task: import("zod").ZodOptional<import("zod").ZodString>;
7
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
8
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
9
+ };
10
+ execute(args: {
11
+ task?: string | undefined;
12
+ notes?: string | undefined;
13
+ projectRoot?: string | undefined;
14
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
15
+ };
@@ -0,0 +1,53 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { executePlanReviewStage, resolveProjectRootFromArgs, } from "../workflow.js";
3
+ export function createAkanePlanReviewTool(pluginInput, configInfo) {
4
+ return tool({
5
+ description: "Review the current Akane plan artifact and write plan-review.md using the configured review model.",
6
+ args: {
7
+ task: tool.schema
8
+ .string()
9
+ .optional()
10
+ .describe("Optional task restatement to include during review."),
11
+ notes: tool.schema
12
+ .string()
13
+ .optional()
14
+ .describe("Optional additional review constraints."),
15
+ projectRoot: tool.schema
16
+ .string()
17
+ .optional()
18
+ .describe("Optional project root override. Defaults to the current session worktree."),
19
+ },
20
+ async execute(args, context) {
21
+ try {
22
+ const projectRoot = resolveProjectRootFromArgs({
23
+ toolContext: context,
24
+ projectRoot: args.projectRoot,
25
+ });
26
+ context.metadata({
27
+ title: "Akane plan review",
28
+ metadata: {
29
+ stage: "plan-review",
30
+ projectRoot,
31
+ },
32
+ });
33
+ const result = await executePlanReviewStage({
34
+ pluginInput,
35
+ configInfo,
36
+ toolContext: context,
37
+ projectRoot,
38
+ task: args.task,
39
+ notes: args.notes,
40
+ });
41
+ return [
42
+ `Created Akane plan review.`,
43
+ `Artifact: ${result.artifactPath}`,
44
+ `Session: ${result.sessionID}`,
45
+ `Model: ${result.model}`,
46
+ ].join("\n");
47
+ }
48
+ catch (error) {
49
+ return `Akane plan review failed: ${error instanceof Error ? error.message : String(error)}`;
50
+ }
51
+ },
52
+ });
53
+ }
@@ -0,0 +1,15 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkanePlanTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ task: import("zod").ZodString;
7
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
8
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
9
+ };
10
+ execute(args: {
11
+ task: string;
12
+ notes?: string | undefined;
13
+ projectRoot?: string | undefined;
14
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
15
+ };
@@ -0,0 +1,50 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { executePlanStage, resolveProjectRootFromArgs, } from "../workflow.js";
3
+ export function createAkanePlanTool(pluginInput, configInfo) {
4
+ return tool({
5
+ description: "Create the Akane plan artifact for a task by running the planner role in a child OpenCode session.",
6
+ args: {
7
+ task: tool.schema.string().describe("The task or change request to plan."),
8
+ notes: tool.schema
9
+ .string()
10
+ .optional()
11
+ .describe("Optional additional constraints or context for the plan."),
12
+ projectRoot: tool.schema
13
+ .string()
14
+ .optional()
15
+ .describe("Optional project root override. Defaults to the current session worktree."),
16
+ },
17
+ async execute(args, context) {
18
+ try {
19
+ const projectRoot = resolveProjectRootFromArgs({
20
+ toolContext: context,
21
+ projectRoot: args.projectRoot,
22
+ });
23
+ context.metadata({
24
+ title: "Akane plan",
25
+ metadata: {
26
+ stage: "plan",
27
+ projectRoot,
28
+ },
29
+ });
30
+ const result = await executePlanStage({
31
+ pluginInput,
32
+ configInfo,
33
+ toolContext: context,
34
+ projectRoot,
35
+ task: args.task,
36
+ notes: args.notes,
37
+ });
38
+ return [
39
+ `Created Akane plan.`,
40
+ `Artifact: ${result.artifactPath}`,
41
+ `Session: ${result.sessionID}`,
42
+ `Model: ${result.model}`,
43
+ ].join("\n");
44
+ }
45
+ catch (error) {
46
+ return `Akane plan failed: ${error instanceof Error ? error.message : String(error)}`;
47
+ }
48
+ },
49
+ });
50
+ }
@@ -0,0 +1,21 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkaneReviewTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ reviewer: import("zod").ZodDefault<import("zod").ZodEnum<{
7
+ codex: "codex";
8
+ claude: "claude";
9
+ both: "both";
10
+ }>>;
11
+ task: import("zod").ZodOptional<import("zod").ZodString>;
12
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
13
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
14
+ };
15
+ execute(args: {
16
+ reviewer: "codex" | "claude" | "both";
17
+ task?: string | undefined;
18
+ notes?: string | undefined;
19
+ projectRoot?: string | undefined;
20
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
21
+ };
@@ -0,0 +1,57 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { executeReviewStage, resolveProjectRootFromArgs, reviewSelectionLabel, } from "../workflow.js";
3
+ export function createAkaneReviewTool(pluginInput, configInfo) {
4
+ return tool({
5
+ description: "Run the Akane review stage. By default this runs both Codex and Claude reviews in parallel.",
6
+ args: {
7
+ reviewer: tool.schema
8
+ .enum(["codex", "claude", "both"])
9
+ .default("both")
10
+ .describe("Which reviewer to run. 'both' runs both review artifacts in parallel."),
11
+ task: tool.schema
12
+ .string()
13
+ .optional()
14
+ .describe("Optional task restatement for the reviewers."),
15
+ notes: tool.schema
16
+ .string()
17
+ .optional()
18
+ .describe("Optional additional review constraints."),
19
+ projectRoot: tool.schema
20
+ .string()
21
+ .optional()
22
+ .describe("Optional project root override. Defaults to the current session worktree."),
23
+ },
24
+ async execute(args, context) {
25
+ try {
26
+ const projectRoot = resolveProjectRootFromArgs({
27
+ toolContext: context,
28
+ projectRoot: args.projectRoot,
29
+ });
30
+ context.metadata({
31
+ title: "Akane review",
32
+ metadata: {
33
+ stage: "review",
34
+ reviewer: args.reviewer,
35
+ projectRoot,
36
+ },
37
+ });
38
+ const result = await executeReviewStage({
39
+ pluginInput,
40
+ configInfo,
41
+ toolContext: context,
42
+ projectRoot,
43
+ reviewer: args.reviewer,
44
+ task: args.task,
45
+ notes: args.notes,
46
+ });
47
+ return [
48
+ `Created Akane review artifact(s): ${reviewSelectionLabel(result.requested)}.`,
49
+ ...result.results.map((item) => `- ${item.stage}: ${item.artifactPath} (${item.model})`),
50
+ ].join("\n");
51
+ }
52
+ catch (error) {
53
+ return `Akane review failed: ${error instanceof Error ? error.message : String(error)}`;
54
+ }
55
+ },
56
+ });
57
+ }
@@ -0,0 +1,24 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkaneRunTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ task: import("zod").ZodString;
7
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
8
+ throughStage: import("zod").ZodDefault<import("zod").ZodEnum<{
9
+ plan: "plan";
10
+ "plan-review": "plan-review";
11
+ "implementation-context": "implementation-context";
12
+ "review-codex": "review-codex";
13
+ "review-claude": "review-claude";
14
+ "final-synthesis": "final-synthesis";
15
+ }>>;
16
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
17
+ };
18
+ execute(args: {
19
+ task: string;
20
+ throughStage: "plan" | "plan-review" | "implementation-context" | "review-codex" | "review-claude" | "final-synthesis";
21
+ notes?: string | undefined;
22
+ projectRoot?: string | undefined;
23
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
24
+ };
@@ -0,0 +1,66 @@
1
+ import { tool } from "@opencode-ai/plugin/tool";
2
+ import { executeRunWorkflow, resolveProjectRootFromArgs, } from "../workflow.js";
3
+ import { AKANE_STAGE_IDS } from "../constants.js";
4
+ export function createAkaneRunTool(pluginInput, configInfo) {
5
+ return tool({
6
+ description: "Run the Akane MVP workflow from planning through synthesis, writing artifacts at each stage.",
7
+ args: {
8
+ task: tool.schema.string().describe("The task or change request to run through Akane."),
9
+ notes: tool.schema
10
+ .string()
11
+ .optional()
12
+ .describe("Optional additional constraints or context for the workflow."),
13
+ throughStage: tool.schema
14
+ .enum(AKANE_STAGE_IDS)
15
+ .default("final-synthesis")
16
+ .describe("Optional stop point for partial workflow runs."),
17
+ projectRoot: tool.schema
18
+ .string()
19
+ .optional()
20
+ .describe("Optional project root override. Defaults to the current session worktree."),
21
+ },
22
+ async execute(args, context) {
23
+ try {
24
+ const projectRoot = resolveProjectRootFromArgs({
25
+ toolContext: context,
26
+ projectRoot: args.projectRoot,
27
+ });
28
+ context.metadata({
29
+ title: "Akane run",
30
+ metadata: {
31
+ stage: "workflow",
32
+ throughStage: args.throughStage,
33
+ projectRoot,
34
+ },
35
+ });
36
+ const result = await executeRunWorkflow({
37
+ pluginInput,
38
+ configInfo,
39
+ toolContext: context,
40
+ projectRoot,
41
+ task: args.task,
42
+ notes: args.notes,
43
+ throughStage: args.throughStage,
44
+ });
45
+ return [
46
+ `Completed Akane workflow through ${args.throughStage}.`,
47
+ `Stages: ${result.completedStages.join(", ")}`,
48
+ `Plan: ${result.plan.artifactPath}`,
49
+ ...(result.planReview ? [`Plan review: ${result.planReview.artifactPath}`] : []),
50
+ ...(result.implementation
51
+ ? [`Implementation: ${result.implementation.artifactPath}`]
52
+ : []),
53
+ ...(result.reviews
54
+ ? result.reviews.map((review) => `${review.stage}: ${review.artifactPath}`)
55
+ : []),
56
+ ...(result.synthesis
57
+ ? [`Final synthesis: ${result.synthesis.artifactPath}`]
58
+ : []),
59
+ ].join("\n");
60
+ }
61
+ catch (error) {
62
+ return `Akane workflow failed: ${error instanceof Error ? error.message : String(error)}`;
63
+ }
64
+ },
65
+ });
66
+ }
@@ -0,0 +1,15 @@
1
+ import type { PluginInput } from "@opencode-ai/plugin";
2
+ import type { LoadedAkaneConfig } from "../types.js";
3
+ export declare function createAkaneSynthesizeTool(pluginInput: PluginInput, configInfo: LoadedAkaneConfig): {
4
+ description: string;
5
+ args: {
6
+ task: import("zod").ZodOptional<import("zod").ZodString>;
7
+ notes: import("zod").ZodOptional<import("zod").ZodString>;
8
+ projectRoot: import("zod").ZodOptional<import("zod").ZodString>;
9
+ };
10
+ execute(args: {
11
+ task?: string | undefined;
12
+ notes?: string | undefined;
13
+ projectRoot?: string | undefined;
14
+ }, context: import("@opencode-ai/plugin/tool").ToolContext): Promise<string>;
15
+ };