Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions .opencode/workflows/code-review.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: code-review
description: Review code changes for quality, security, and best practices

agent: build
model: opencode/mimo-v2.5-free

steps:
- id: analyze
name: Analyze changes
prompt: |
Analyze the current code changes (git diff). Identify:
- Files changed
- Lines added/removed
- Key modifications

- id: quality
name: Quality review
prompt: |
Review the code changes for quality issues:
- Code style consistency
- Error handling
- Performance concerns
- Readability and maintainability

- id: security
name: Security review
prompt: |
Review the code changes for security issues:
- Input validation
- Authentication/authorization
- Data exposure risks
- Vulnerability patterns

- id: summary
name: Summary report
prompt: |
Create a summary report of the code review with:
- Overall assessment
- Key findings
- Recommendations
- Priority items to address
2 changes: 1 addition & 1 deletion packages/app/src/custom-elements.d.ts
62 changes: 62 additions & 0 deletions packages/core/src/config/plugin/workflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
export * as ConfigWorkflowPlugin from "./workflow"

import { define } from "../../plugin/internal"
import { Effect } from "effect"
import { CommandV2 } from "../../command"
import { FSUtil } from "../../fs-util"
import { Location } from "../../location"
import matter from "gray-matter"
import * as fs from "fs"
import * as path from "path"

function parseYaml(content: string) {
const result = matter(`---\n${content}\n---`)
return { data: result.data, content: "" }
}

function loadWorkflows(directory: string): Array<{ name: string; description?: string }> {
const workflows: Array<{ name: string; description?: string }> = []
const workflowDir = path.join(directory, ".opencode", "workflows")

if (!fs.existsSync(workflowDir)) return workflows

try {
const files = fs.readdirSync(workflowDir)
for (const file of files) {
if (!file.endsWith(".yaml") && !file.endsWith(".yml")) continue
const filepath = path.join(workflowDir, file)
try {
const content = fs.readFileSync(filepath, "utf-8")
const parsed = parseYaml(content)
const name = file.replace(/\.(yaml|yml)$/, "")
const data = parsed.data as Record<string, unknown>
workflows.push({
name,
description: (data.description as string) ?? `Run ${name} workflow`,
})
} catch {
// Skip invalid YAML files
}
}
} catch {
// Skip if directory read fails
}

return workflows
}

export const Plugin = define({
id: "config-workflow",
effect: Effect.fn(function* (ctx) {
const location = yield* Location.Service
yield* ctx.command.transform((draft) => {
const workflows = loadWorkflows(location.directory)
for (const workflow of workflows) {
draft.update(`workflow/${workflow.name}`, (command) => {
command.template = `[Workflow: ${workflow.name}] ${workflow.description}`
command.description = workflow.description
})
}
})
}),
})
2 changes: 2 additions & 0 deletions packages/core/src/plugin/internal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { ConfigExternalPlugin } from "../config/plugin/external"
import { ConfigProviderPlugin } from "../config/plugin/provider"
import { ConfigReferencePlugin } from "../config/plugin/reference"
import { ConfigSkillPlugin } from "../config/plugin/skill"
import { ConfigWorkflowPlugin } from "../config/plugin/workflow"
import { EventV2 } from "../event"
import { FileSystem } from "../filesystem"
import { FSUtil } from "../fs-util"
Expand Down Expand Up @@ -115,6 +116,7 @@ const layer = Layer.effectDiscard(
yield* add(ConfigAgentPlugin.Plugin)
yield* add(ConfigCommandPlugin.Plugin)
yield* add(ConfigSkillPlugin.Plugin)
yield* add(ConfigWorkflowPlugin.Plugin)
for (const item of ProviderPlugins) yield* add(item)
yield* add(ConfigExternalPlugin.Plugin)
yield* add(ConfigProviderPlugin.Plugin)
Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/v1/config/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { ConfigReference } from "../../config/reference"
import { ConfigAgentV1 } from "./agent"
import { ConfigAttachmentV1 } from "./attachment"
import { ConfigCommandV1 } from "./command"
import { ConfigWorkflowV1 } from "./workflow"
import { ConfigFormatterV1 } from "./formatter"
import { ConfigLayoutV1 } from "./layout"
import { ConfigLSPV1 } from "./lsp"
Expand Down Expand Up @@ -41,6 +42,9 @@ export const Info = Schema.Struct({
command: Schema.optional(Schema.Record(Schema.String, ConfigCommandV1.Info)).annotate({
description: "Command configuration, see https://opencode.ai/docs/commands",
}),
workflow: Schema.optional(Schema.Record(Schema.String, ConfigWorkflowV1.Info)).annotate({
description: "Workflow definitions for multi-step pipelines",
}),
skills: Schema.optional(ConfigSkillsV1.Info).annotate({ description: "Additional skill folder paths" }),
references: Schema.optional(ConfigReference.Info).annotate({
description: "Named git or local directory references",
Expand Down
30 changes: 30 additions & 0 deletions packages/core/src/v1/config/workflow.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export * as ConfigWorkflowV1 from "./workflow"

import { Schema } from "effect"

const StepOutput = Schema.Struct({
name: Schema.String,
description: Schema.optional(Schema.String),
})

const WorkflowStep = Schema.Struct({
id: Schema.String,
prompt: Schema.String,
depends_on: Schema.optional(Schema.Union([Schema.String, Schema.mutable(Schema.Array(Schema.String))])),
when: Schema.optional(Schema.String),
agent: Schema.optional(Schema.String),
model: Schema.optional(Schema.String),
outputs: Schema.optional(Schema.mutable(Schema.Array(StepOutput))),
})

export const Info = Schema.Struct({
name: Schema.optional(Schema.String),
description: Schema.optional(Schema.String),
agent: Schema.optional(Schema.String),
model: Schema.optional(Schema.String),
steps: Schema.mutable(Schema.Array(WorkflowStep)),
})
export type Info = Schema.Schema.Type<typeof Info>

export type Step = Schema.Schema.Type<typeof WorkflowStep>
export type StepOutput = Schema.Schema.Type<typeof StepOutput>
2 changes: 1 addition & 1 deletion packages/enterprise/src/custom-elements.d.ts
Loading
Loading