Skip to content

Commit 133fe41

Browse files
thdxradamdotdevin
andauthored
slash commands (anomalyco#2157)
Co-authored-by: adamdotdevin <[email protected]>
1 parent 74c1085 commit 133fe41

File tree

32 files changed

+874
-69
lines changed

32 files changed

+874
-69
lines changed

.opencode/command/commit.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
commit and push
2+
3+
make sure it includes a prefix like
4+
docs:
5+
tui:
6+
core:
7+
ci:
8+
ignore:
9+
wip:

.opencode/command/hello.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
description: hello world
3+
---
4+
5+
hey there $ARGUMENTS
6+
7+
!`ls`
8+
check out @README.md

bun.lock

Lines changed: 11 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"keep": {
3+
"days": true,
4+
"amount": 14
5+
},
6+
"auditLog": "/Users/adam/code/opencode/dev/logs/.496fc674ed58d31f8b883da41cc2adb4564aad58-audit.json",
7+
"files": [
8+
{
9+
"date": 1755891797740,
10+
"name": "/Users/adam/code/opencode/dev/logs/mcp-puppeteer-2025-08-22.log",
11+
"hash": "dd9b1f2e98b661ba2f56b91dd9afbdb25e50adbdd52ed1b0eef1d2045235d17c"
12+
}
13+
],
14+
"hashType": "sha256"
15+
}

logs/mcp-puppeteer-2025-08-22.log

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:43:17.765"}
2+
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:43:17.766"}
3+
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:46:45.539"}
4+
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:46:45.540"}
5+
{"level":"info","message":"Starting MCP server","service":"mcp-puppeteer","timestamp":"2025-08-22 14:53:08.159"}
6+
{"level":"info","message":"MCP server started successfully","service":"mcp-puppeteer","timestamp":"2025-08-22 14:53:08.160"}

opencode.json

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
{
22
"$schema": "https://opencode.ai/config.json",
3+
34
"mcp": {
4-
"context7": {
5-
"type": "remote",
6-
"url": "https://mcp.context7.com/sse"
7-
},
85
"weather": {
96
"type": "local",
107
"command": ["opencode", "x", "@h1deya/mcp-server-weather"]

package.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,8 @@
5151
"tree-sitter-bash",
5252
"web-tree-sitter"
5353
],
54+
"overrides": {
55+
"zod": "3.25.76"
56+
},
5457
"patchedDependencies": {}
5558
}

packages/opencode/script/schema.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Config } from "../src/config/config"
55
import { zodToJsonSchema } from "zod-to-json-schema"
66

77
const file = process.argv[2]
8+
console.log(file)
89

910
const result = zodToJsonSchema(Config.Info, {
1011
/**
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import z from "zod"
2+
import { App } from "../app/app"
3+
import { Config } from "../config/config"
4+
5+
export namespace Command {
6+
export const Info = z
7+
.object({
8+
name: z.string(),
9+
description: z.string().optional(),
10+
agent: z.string().optional(),
11+
model: z.string().optional(),
12+
template: z.string(),
13+
})
14+
.openapi({
15+
ref: "Command",
16+
})
17+
export type Info = z.infer<typeof Info>
18+
19+
const state = App.state("command", async () => {
20+
const cfg = await Config.get()
21+
22+
const result: Record<string, Info> = {}
23+
24+
for (const [name, command] of Object.entries(cfg.command ?? {})) {
25+
result[name] = {
26+
name,
27+
agent: command.agent,
28+
model: command.model,
29+
description: command.description,
30+
template: command.template,
31+
}
32+
}
33+
34+
return result
35+
})
36+
37+
export async function get(name: string) {
38+
return state().then((x) => x[name])
39+
}
40+
41+
export async function list() {
42+
return state().then((x) => Object.values(x))
43+
}
44+
}

packages/opencode/src/config/config.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,32 @@ export namespace Config {
107107
}
108108
throw new InvalidError({ path: item }, { cause: parsed.error })
109109
}
110+
111+
// Load command markdown files
112+
result.command = result.command || {}
113+
const markdownCommands = [
114+
...(await Filesystem.globUp("command/*.md", Global.Path.config, Global.Path.config)),
115+
...(await Filesystem.globUp(".opencode/command/*.md", app.path.cwd, app.path.root)),
116+
]
117+
for (const item of markdownCommands) {
118+
const content = await Bun.file(item).text()
119+
const md = matter(content)
120+
if (!md.data) continue
121+
122+
const config = {
123+
name: path.basename(item, ".md"),
124+
...md.data,
125+
template: md.content.trim(),
126+
}
127+
const parsed = Command.safeParse(config)
128+
if (parsed.success) {
129+
result.command = mergeDeep(result.command, {
130+
[config.name]: parsed.data,
131+
})
132+
continue
133+
}
134+
throw new InvalidError({ path: item }, { cause: parsed.error })
135+
}
110136
// Migrate deprecated mode field to agent field
111137
for (const [name, mode] of Object.entries(result.mode)) {
112138
result.agent = mergeDeep(result.agent ?? {}, {
@@ -192,6 +218,14 @@ export namespace Config {
192218
export const Permission = z.union([z.literal("ask"), z.literal("allow"), z.literal("deny")])
193219
export type Permission = z.infer<typeof Permission>
194220

221+
export const Command = z.object({
222+
template: z.string(),
223+
description: z.string().optional(),
224+
agent: z.string().optional(),
225+
model: z.string().optional(),
226+
})
227+
export type Command = z.infer<typeof Command>
228+
195229
export const Agent = z
196230
.object({
197231
model: z.string().optional(),
@@ -305,6 +339,7 @@ export namespace Config {
305339
theme: z.string().optional().describe("Theme name to use for the interface"),
306340
keybinds: Keybinds.optional().describe("Custom keybind configurations"),
307341
tui: TUI.optional().describe("TUI specific settings"),
342+
command: z.record(z.string(), Command).optional(),
308343
plugin: z.string().array().optional(),
309344
snapshot: z.boolean().optional(),
310345
share: z

0 commit comments

Comments
 (0)