migrated custom tools to V2 plugin
This commit is contained in:
@@ -0,0 +1,22 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const gitWorktreeCreate: Info = {
|
||||||
|
name: "git-worktree-create",
|
||||||
|
description: "Create a git worktree for a branch or PR",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
branch: { type: "string", description: "Branch name or PR number" },
|
||||||
|
},
|
||||||
|
required: ["branch"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { branch } = input as { branch: string }
|
||||||
|
const result = await $`git worktree add ../worktrees/${branch}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default gitWorktreeCreate
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { Plugin } from "@opencode/plugin"
|
||||||
|
|
||||||
|
import gitWorktreeCreate from "./git-worktree-create.js"
|
||||||
|
import teaActionsRunsList from "./tea-actions-runs-list.js"
|
||||||
|
import teaActionsRunsLogs from "./tea-actions-runs-logs.js"
|
||||||
|
import teaComment from "./tea-comment.js"
|
||||||
|
import teaIssueCreate from "./tea-issue-create.js"
|
||||||
|
import teaIssueGet from "./tea-issue-get.js"
|
||||||
|
import teaIssues from "./tea-issues.js"
|
||||||
|
import teaPrCreate from "./tea-pr-create.js"
|
||||||
|
import teaPrGet from "./tea-pr-get.js"
|
||||||
|
import teaPulls from "./tea-pulls.js"
|
||||||
|
|
||||||
|
export default Plugin.define({
|
||||||
|
id: "tools",
|
||||||
|
async setup(ctx) {
|
||||||
|
await ctx.tool.transform((editor) => {
|
||||||
|
editor.add(gitWorktreeCreate)
|
||||||
|
editor.add(teaActionsRunsList)
|
||||||
|
editor.add(teaActionsRunsLogs)
|
||||||
|
editor.add(teaComment)
|
||||||
|
editor.add(teaIssueCreate)
|
||||||
|
editor.add(teaIssueGet)
|
||||||
|
editor.add(teaIssues)
|
||||||
|
editor.add(teaPrCreate)
|
||||||
|
editor.add(teaPrGet)
|
||||||
|
editor.add(teaPulls)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaActionsRunsList: Info = {
|
||||||
|
name: "tea-actions-runs-list",
|
||||||
|
description: "List workflow runs for Gitea actions with optional filters",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
status: { type: "string", description: "Filter by status (success, failure, pending, queued, in_progress, skipped, canceled)" },
|
||||||
|
branch: { type: "string", description: "Filter by branch name" },
|
||||||
|
event: { type: "string", description: "Filter by event type (push, pull_request, etc.)" },
|
||||||
|
limit: { type: "number", description: "Number of results to return (default: 30)" },
|
||||||
|
since: { type: "string", description: "Show runs started after this time (e.g., '24h', '7d')" },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { status, branch, event, limit, since } = input as {
|
||||||
|
status?: string
|
||||||
|
branch?: string
|
||||||
|
event?: string
|
||||||
|
limit?: number
|
||||||
|
since?: string
|
||||||
|
}
|
||||||
|
let cmd = [`tea`, `actions`, `runs`, `list`, `-o`, `json`]
|
||||||
|
if (status) cmd = [...cmd, `--status`, status]
|
||||||
|
if (branch) cmd = [...cmd, `--branch`, branch]
|
||||||
|
if (event) cmd = [...cmd, `--event`, event]
|
||||||
|
if (limit) cmd = [...cmd, `--limit`, String(limit)]
|
||||||
|
if (since) cmd = [...cmd, `--since`, since]
|
||||||
|
const result = await $`${cmd}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaActionsRunsList
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaActionsRunsLogs: Info = {
|
||||||
|
name: "tea-actions-runs-logs",
|
||||||
|
description: "Get logs for a specific Gitea actions workflow run to diagnose failures",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
runId: { type: "number", description: "Workflow run ID to get logs for" },
|
||||||
|
job: { type: "string", description: "Specific job ID to view (if omitted, shows all jobs)" },
|
||||||
|
},
|
||||||
|
required: ["runId"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { runId, job } = input as { runId: number; job?: string }
|
||||||
|
let cmd = [`tea`, `actions`, `runs`, `logs`]
|
||||||
|
if (job) cmd = [...cmd, `--job`, job]
|
||||||
|
cmd = [...cmd, String(runId), `-o`, `simple`]
|
||||||
|
const result = await $`${cmd}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaActionsRunsLogs
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaComment: Info = {
|
||||||
|
name: "tea-comment",
|
||||||
|
description: "Add a comment to a specific issue using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
issueNumber: { type: "number", description: "Issue number/index" },
|
||||||
|
body: { type: "string", description: "Comment body" },
|
||||||
|
},
|
||||||
|
required: ["issueNumber", "body"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { issueNumber, body } = input as { issueNumber: number; body: string }
|
||||||
|
const result = await $`tea comment ${issueNumber} ${body}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaComment
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaIssueCreate: Info = {
|
||||||
|
name: "tea-issue-create",
|
||||||
|
description: "Create a new issue in the GitHub repository using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
title: { type: "string", description: "Issue title" },
|
||||||
|
description: { type: "string", description: "Issue description (supports markdown)" },
|
||||||
|
},
|
||||||
|
required: ["title"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { title, description } = input as { title: string; description?: string }
|
||||||
|
const result = await $`tea issues create -t ${title} -d ${description}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaIssueCreate
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaIssueGet: Info = {
|
||||||
|
name: "tea-issue-get",
|
||||||
|
description: "Get a specific issue with all details and comments using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
issueNumber: { type: "number", description: "Issue number/index" },
|
||||||
|
},
|
||||||
|
required: ["issueNumber"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { issueNumber } = input as { issueNumber: number }
|
||||||
|
const result = await $`tea issues ${issueNumber} --comments --output json`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaIssueGet
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaIssues: Info = {
|
||||||
|
name: "tea-issues",
|
||||||
|
description: "List all issues in the project using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute() {
|
||||||
|
const result = await $`tea issues list`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaIssues
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaPrCreate: Info = {
|
||||||
|
name: "tea-pr-create",
|
||||||
|
description: "Create a pull request in the repository using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
title: { type: "string", description: "PR title" },
|
||||||
|
head: { type: "string", description: "Branch name of the PR source (defaults to current branch)" },
|
||||||
|
base: { type: "string", description: "Branch name of the PR target (defaults to repository default branch)" },
|
||||||
|
description: { type: "string", description: "PR description (supports markdown)" },
|
||||||
|
assignees: { type: "string", description: "Comma-separated list of usernames to assign" },
|
||||||
|
labels: { type: "string", description: "Comma-separated list of labels to assign" },
|
||||||
|
},
|
||||||
|
required: ["title"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { title, head, base, description, assignees, labels } = input as {
|
||||||
|
title: string
|
||||||
|
head?: string
|
||||||
|
base?: string
|
||||||
|
description?: string
|
||||||
|
assignees?: string
|
||||||
|
labels?: string
|
||||||
|
}
|
||||||
|
let cmd = [`tea`, `pulls`, `create`, `-t`, title]
|
||||||
|
if (head) cmd = [...cmd, `--head`, head]
|
||||||
|
if (base) cmd = [...cmd, `-b`, base]
|
||||||
|
if (description) cmd = [...cmd, `-d`, description]
|
||||||
|
if (assignees) cmd = [...cmd, `-a`, assignees]
|
||||||
|
if (labels) cmd = [...cmd, `-L`, labels]
|
||||||
|
const result = await $`${cmd}`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaPrCreate
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaPrGet: Info = {
|
||||||
|
name: "tea-pr-get",
|
||||||
|
description: "Get a specific pull request with all details and comments using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
pullNumber: { type: "number", description: "Pull request number/index" },
|
||||||
|
},
|
||||||
|
required: ["pullNumber"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { pullNumber } = input as { pullNumber: number }
|
||||||
|
const result = await $`tea pulls ${pullNumber} --comments --output json`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaPrGet
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
import { $ } from "bun"
|
||||||
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const teaPulls: Info = {
|
||||||
|
name: "tea-pulls",
|
||||||
|
description: "List pull requests in the repository using tea CLI",
|
||||||
|
input: {
|
||||||
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
state: { type: "string", description: "Filter by state (all|open|closed)" },
|
||||||
|
},
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const state = (input as { state?: string }).state || "open"
|
||||||
|
const result = await $`tea pulls --state ${state} --output json`.text()
|
||||||
|
return { content: result.trim() }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default teaPulls
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Create a git worktree for a branch or PR",
|
|
||||||
args: {
|
|
||||||
branch: tool.schema.string().describe("Branch name or PR number"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const result = await $`git worktree add ../worktrees/${args.branch}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "List workflow runs for Gitea actions with optional filters",
|
|
||||||
args: {
|
|
||||||
status: tool.schema.string().optional().describe("Filter by status (success, failure, pending, queued, in_progress, skipped, canceled)"),
|
|
||||||
branch: tool.schema.string().optional().describe("Filter by branch name"),
|
|
||||||
event: tool.schema.string().optional().describe("Filter by event type (push, pull_request, etc.)"),
|
|
||||||
limit: tool.schema.number().optional().describe("Number of results to return (default: 30)"),
|
|
||||||
since: tool.schema.string().optional().describe("Show runs started after this time (e.g., '24h', '7d')"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
let cmd = [`tea`, `actions`, `runs`, `list`, `-o`, `json`]
|
|
||||||
if (args.status) cmd = [...cmd, `--status`, args.status]
|
|
||||||
if (args.branch) cmd = [...cmd, `--branch`, args.branch]
|
|
||||||
if (args.event) cmd = [...cmd, `--event`, args.event]
|
|
||||||
if (args.limit) cmd = [...cmd, `--limit`, String(args.limit)]
|
|
||||||
if (args.since) cmd = [...cmd, `--since`, args.since]
|
|
||||||
const result = await $`${cmd}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Get logs for a specific Gitea actions workflow run to diagnose failures",
|
|
||||||
args: {
|
|
||||||
runId: tool.schema.number().describe("Workflow run ID to get logs for"),
|
|
||||||
job: tool.schema.string().optional().describe("Specific job ID to view (if omitted, shows all jobs)"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
let cmd = [`tea`, `actions`, `runs`, `logs`]
|
|
||||||
if (args.job) cmd = [...cmd, `--job`, args.job]
|
|
||||||
cmd = [...cmd, String(args.runId), `-o`, `simple`]
|
|
||||||
const result = await $`${cmd}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Add a comment to a specific issue using tea CLI",
|
|
||||||
args: {
|
|
||||||
issueNumber: tool.schema.number().describe("Issue number/index"),
|
|
||||||
body: tool.schema.string().describe("Comment body"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const result = await $`tea comment ${args.issueNumber} ${args.body}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Create a new issue in the GitHub repository using tea CLI",
|
|
||||||
args: {
|
|
||||||
title: tool.schema.string().describe("Issue title"),
|
|
||||||
description: tool.schema.string().optional().describe("Issue description (supports markdown)"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const result = await $`tea issues create -t ${args.title} -d ${args.description}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Get a specific issue with all details and comments using tea CLI",
|
|
||||||
args: {
|
|
||||||
issueNumber: tool.schema.number().describe("Issue number/index"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const result = await $`tea issues ${args.issueNumber} --comments --output json`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "List all issues in the project using tea CLI",
|
|
||||||
args: {},
|
|
||||||
async execute(args, context) {
|
|
||||||
const result = await $`tea issues list`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Create a pull request in the repository using tea CLI",
|
|
||||||
args: {
|
|
||||||
title: tool.schema.string().describe("PR title"),
|
|
||||||
head: tool.schema.string().optional().describe("Branch name of the PR source (defaults to current branch)"),
|
|
||||||
base: tool.schema.string().optional().describe("Branch name of the PR target (defaults to repository default branch)"),
|
|
||||||
description: tool.schema.string().optional().describe("PR description (supports markdown)"),
|
|
||||||
assignees: tool.schema.string().optional().describe("Comma-separated list of usernames to assign"),
|
|
||||||
labels: tool.schema.string().optional().describe("Comma-separated list of labels to assign"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
let cmd = [`tea`, `pulls`, `create`, `-t`, args.title]
|
|
||||||
if (args.head) cmd = [...cmd, `--head`, args.head]
|
|
||||||
if (args.base) cmd = [...cmd, `-b`, args.base]
|
|
||||||
if (args.description) cmd = [...cmd, `-d`, args.description]
|
|
||||||
if (args.assignees) cmd = [...cmd, `-a`, args.assignees]
|
|
||||||
if (args.labels) cmd = [...cmd, `-L`, args.labels]
|
|
||||||
const result = await $`${cmd}`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "Get a specific pull request with all details and comments using tea CLI",
|
|
||||||
args: {
|
|
||||||
pullNumber: tool.schema.number().describe("Pull request number/index"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const result = await $`tea pulls ${args.pullNumber} --comments --output json`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description: "List pull requests in the repository using tea CLI",
|
|
||||||
args: {
|
|
||||||
state: tool.schema.string().optional().describe("Filter by state (all|open|closed)"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const state = args.state || "open"
|
|
||||||
const result = await $`tea pulls --state ${state} --output json`.text()
|
|
||||||
return result.trim()
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -4,7 +4,7 @@ OPENCODE_DIR := $(HOME)/.config/opencode
|
|||||||
REPO_DIR := $(shell pwd)
|
REPO_DIR := $(shell pwd)
|
||||||
|
|
||||||
# Items to symlink
|
# Items to symlink
|
||||||
ITEMS := skills tools agents AGENTS.md
|
ITEMS := skills plugins agents AGENTS.md
|
||||||
|
|
||||||
# LLM services to manage
|
# LLM services to manage
|
||||||
LLM_SERVICES := qwen qwen-4bit
|
LLM_SERVICES := qwen qwen-4bit
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ OpenCode uses three component types:
|
|||||||
| Component | Location | Purpose | Example |
|
| Component | Location | Purpose | Example |
|
||||||
|-----------|----------|---------|---------|
|
|-----------|----------|---------|---------|
|
||||||
| **Skills** | `.opencode/skills/` | Reference knowledge | `issue-writing` knows how to structure good issues |
|
| **Skills** | `.opencode/skills/` | Reference knowledge | `issue-writing` knows how to structure good issues |
|
||||||
| **Tools** | `.opencode/tools/` | Custom functions | `spawn_issues` implements multiple issues in parallel |
|
| **Tools** | `.opencode/plugins/` | Custom functions, provided by plugins | `tools` registers the `tea-*` Gitea CLI tools |
|
||||||
| **Agents** | `.opencode/agents/` | Specialized subagents | `code-reviewer` handles PR reviews |
|
| **Agents** | `.opencode/agents/` | Specialized subagents | `code-reviewer` handles PR reviews |
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
@@ -29,7 +29,7 @@ make install
|
|||||||
|
|
||||||
This creates symlinks at:
|
This creates symlinks at:
|
||||||
- `~/.config/opencode/skills/` → `.opencode/skills/`
|
- `~/.config/opencode/skills/` → `.opencode/skills/`
|
||||||
- `~/.config/opencode/tools/` → `.opencode/tools/`
|
- `~/.config/opencode/plugins/` → `.opencode/plugins/`
|
||||||
- `~/.config/opencode/agents/` → `.opencode/agents/`
|
- `~/.config/opencode/agents/` → `.opencode/agents/`
|
||||||
|
|
||||||
### Uninstallation
|
### Uninstallation
|
||||||
@@ -67,7 +67,7 @@ architecture/
|
|||||||
│
|
│
|
||||||
├── .opencode/ # OpenCode configuration
|
├── .opencode/ # OpenCode configuration
|
||||||
│ ├── skills/ # Reference knowledge (SKILL.md files)
|
│ ├── skills/ # Reference knowledge (SKILL.md files)
|
||||||
│ ├── tools/ # Custom tools (TypeScript/JS)
|
│ ├── plugins/ # Plugins registering custom tools (TypeScript)
|
||||||
│ └── agents/ # Specialized subagents (AGENT.md files)
|
│ └── agents/ # Specialized subagents (AGENT.md files)
|
||||||
│
|
│
|
||||||
├── Makefile # Symlink management
|
├── Makefile # Symlink management
|
||||||
@@ -96,24 +96,42 @@ Skills are auto-discovered by OpenCode and available via the `skill` tool.
|
|||||||
|
|
||||||
### Tools
|
### Tools
|
||||||
|
|
||||||
Create `.opencode/tools/<name>.ts`:
|
Tools are registered by plugins under `.opencode/plugins/`. Create `.opencode/plugins/<name>/index.ts`:
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { tool } from "@opencode-ai/plugin"
|
import { Plugin } from "@opencode/plugin"
|
||||||
|
|
||||||
export default tool({
|
import type { Info } from "@opencode/plugin/promise/tool"
|
||||||
|
|
||||||
|
const example: Info = {
|
||||||
|
name: "example",
|
||||||
description: "What this tool does",
|
description: "What this tool does",
|
||||||
args: {
|
input: {
|
||||||
param: tool.schema.string().describe("Parameter description"),
|
type: "object",
|
||||||
|
properties: {
|
||||||
|
param: { type: "string", description: "Parameter description" },
|
||||||
},
|
},
|
||||||
async execute(args) {
|
required: ["param"],
|
||||||
|
additionalProperties: false,
|
||||||
|
},
|
||||||
|
async execute(input) {
|
||||||
|
const { param } = input as { param: string }
|
||||||
// Your implementation
|
// Your implementation
|
||||||
return "result"
|
return { content: `result for ${param}` }
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Plugin.define({
|
||||||
|
id: "example",
|
||||||
|
async setup(ctx) {
|
||||||
|
await ctx.tool.transform((editor) => {
|
||||||
|
editor.add(example)
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
```
|
```
|
||||||
|
|
||||||
Tools are auto-discovered and available to the LLM.
|
Tool input schemas are plain JSON Schema, and execution returns structured content. Plugins under `.opencode/plugins/` are auto-discovered and their tools are available to the LLM.
|
||||||
|
|
||||||
### Agents
|
### Agents
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user