Skip to content

Commit afc8d36

Browse files
committed
merge
2 parents f80a3fe + 795182b commit afc8d36

File tree

28 files changed

+2180
-522
lines changed

28 files changed

+2180
-522
lines changed

packages/opencode/src/agent/agent.ts

Lines changed: 130 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { generateObject, type ModelMessage } from "ai"
55
import PROMPT_GENERATE from "./generate.txt"
66
import { SystemPrompt } from "../session/system"
77
import { Instance } from "../project/instance"
8+
import { State } from "../project/state"
89
import { mergeDeep } from "remeda"
910

1011
export namespace Agent {
@@ -39,145 +40,149 @@ export namespace Agent {
3940
})
4041
export type Info = z.infer<typeof Info>
4142

42-
const state = Instance.state(async () => {
43-
const cfg = await Config.get()
44-
const defaultTools = cfg.tools ?? {}
45-
const defaultPermission: Info["permission"] = {
46-
edit: "allow",
47-
bash: {
48-
"*": "allow",
49-
},
50-
webfetch: "allow",
51-
doom_loop: "ask",
52-
external_directory: "ask",
53-
}
54-
const agentPermission = mergeAgentPermissions(defaultPermission, cfg.permission ?? {})
55-
56-
const planPermission = mergeAgentPermissions(
57-
{
58-
edit: "deny",
43+
const state = State.register(
44+
"agent",
45+
() => Instance.directory,
46+
async () => {
47+
const cfg = await Config.get()
48+
const defaultTools = cfg.tools ?? {}
49+
const defaultPermission: Info["permission"] = {
50+
edit: "allow",
5951
bash: {
60-
"cut*": "allow",
61-
"diff*": "allow",
62-
"du*": "allow",
63-
"file *": "allow",
64-
"find * -delete*": "ask",
65-
"find * -exec*": "ask",
66-
"find * -fprint*": "ask",
67-
"find * -fls*": "ask",
68-
"find * -fprintf*": "ask",
69-
"find * -ok*": "ask",
70-
"find *": "allow",
71-
"git diff*": "allow",
72-
"git log*": "allow",
73-
"git show*": "allow",
74-
"git status*": "allow",
75-
"git branch": "allow",
76-
"git branch -v": "allow",
77-
"grep*": "allow",
78-
"head*": "allow",
79-
"less*": "allow",
80-
"ls*": "allow",
81-
"more*": "allow",
82-
"pwd*": "allow",
83-
"rg*": "allow",
84-
"sort --output=*": "ask",
85-
"sort -o *": "ask",
86-
"sort*": "allow",
87-
"stat*": "allow",
88-
"tail*": "allow",
89-
"tree -o *": "ask",
90-
"tree*": "allow",
91-
"uniq*": "allow",
92-
"wc*": "allow",
93-
"whereis*": "allow",
94-
"which*": "allow",
95-
"*": "ask",
52+
"*": "allow",
9653
},
9754
webfetch: "allow",
98-
},
99-
cfg.permission ?? {},
100-
)
55+
doom_loop: "ask",
56+
external_directory: "ask",
57+
}
58+
const agentPermission = mergeAgentPermissions(defaultPermission, cfg.permission ?? {})
10159

102-
const result: Record<string, Info> = {
103-
general: {
104-
name: "general",
105-
description:
106-
"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.",
107-
tools: {
108-
todoread: false,
109-
todowrite: false,
110-
...defaultTools,
60+
const planPermission = mergeAgentPermissions(
61+
{
62+
edit: "deny",
63+
bash: {
64+
"cut*": "allow",
65+
"diff*": "allow",
66+
"du*": "allow",
67+
"file *": "allow",
68+
"find * -delete*": "ask",
69+
"find * -exec*": "ask",
70+
"find * -fprint*": "ask",
71+
"find * -fls*": "ask",
72+
"find * -fprintf*": "ask",
73+
"find * -ok*": "ask",
74+
"find *": "allow",
75+
"git diff*": "allow",
76+
"git log*": "allow",
77+
"git show*": "allow",
78+
"git status*": "allow",
79+
"git branch": "allow",
80+
"git branch -v": "allow",
81+
"grep*": "allow",
82+
"head*": "allow",
83+
"less*": "allow",
84+
"ls*": "allow",
85+
"more*": "allow",
86+
"pwd*": "allow",
87+
"rg*": "allow",
88+
"sort --output=*": "ask",
89+
"sort -o *": "ask",
90+
"sort*": "allow",
91+
"stat*": "allow",
92+
"tail*": "allow",
93+
"tree -o *": "ask",
94+
"tree*": "allow",
95+
"uniq*": "allow",
96+
"wc*": "allow",
97+
"whereis*": "allow",
98+
"which*": "allow",
99+
"*": "ask",
100+
},
101+
webfetch: "allow",
111102
},
112-
options: {},
113-
permission: agentPermission,
114-
mode: "subagent",
115-
builtIn: true,
116-
},
117-
build: {
118-
name: "build",
119-
tools: { ...defaultTools },
120-
options: {},
121-
permission: agentPermission,
122-
mode: "primary",
123-
builtIn: true,
124-
},
125-
plan: {
126-
name: "plan",
127-
options: {},
128-
permission: planPermission,
129-
tools: {
130-
...defaultTools,
103+
cfg.permission ?? {},
104+
)
105+
106+
const result: Record<string, Info> = {
107+
general: {
108+
name: "general",
109+
description:
110+
"General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you.",
111+
tools: {
112+
todoread: false,
113+
todowrite: false,
114+
...defaultTools,
115+
},
116+
options: {},
117+
permission: agentPermission,
118+
mode: "subagent",
119+
builtIn: true,
131120
},
132-
mode: "primary",
133-
builtIn: true,
134-
},
135-
}
136-
for (const [key, value] of Object.entries(cfg.agent ?? {})) {
137-
if (value.disable) {
138-
delete result[key]
139-
continue
140-
}
141-
let item = result[key]
142-
if (!item)
143-
item = result[key] = {
144-
name: key,
145-
mode: "all",
121+
build: {
122+
name: "build",
123+
tools: { ...defaultTools },
124+
options: {},
146125
permission: agentPermission,
126+
mode: "primary",
127+
builtIn: true,
128+
},
129+
plan: {
130+
name: "plan",
147131
options: {},
148-
tools: {},
149-
builtIn: false,
150-
}
151-
const { name, model, prompt, tools, description, temperature, top_p, mode, permission, color, ...extra } = value
152-
item.options = {
153-
...item.options,
154-
...extra,
132+
permission: planPermission,
133+
tools: {
134+
...defaultTools,
135+
},
136+
mode: "primary",
137+
builtIn: true,
138+
},
155139
}
156-
if (model) item.model = Provider.parseModel(model)
157-
if (prompt) item.prompt = prompt
158-
if (tools)
140+
for (const [key, value] of Object.entries(cfg.agent ?? {})) {
141+
if (value.disable) {
142+
delete result[key]
143+
continue
144+
}
145+
let item = result[key]
146+
if (!item)
147+
item = result[key] = {
148+
name: key,
149+
mode: "all",
150+
permission: agentPermission,
151+
options: {},
152+
tools: {},
153+
builtIn: false,
154+
}
155+
const { name, model, prompt, tools, description, temperature, top_p, mode, permission, ...extra } = value
156+
item.options = {
157+
...item.options,
158+
...extra,
159+
}
160+
if (model) item.model = Provider.parseModel(model)
161+
if (prompt) item.prompt = prompt
162+
if (tools)
163+
item.tools = {
164+
...item.tools,
165+
...tools,
166+
}
159167
item.tools = {
168+
...defaultTools,
160169
...item.tools,
161-
...tools,
162170
}
163-
item.tools = {
164-
...defaultTools,
165-
...item.tools,
166-
}
167-
if (description) item.description = description
168-
if (temperature != undefined) item.temperature = temperature
169-
if (top_p != undefined) item.topP = top_p
170-
if (mode) item.mode = mode
171-
if (color) item.color = color
172-
// just here for consistency & to prevent it from being added as an option
173-
if (name) item.name = name
171+
if (description) item.description = description
172+
if (temperature != undefined) item.temperature = temperature
173+
if (top_p != undefined) item.topP = top_p
174+
if (mode) item.mode = mode
175+
if (color) item.color = color
176+
// just here for consistency & to prevent it from being added as an option
177+
if (name) item.name = name
174178

175-
if (permission ?? cfg.permission) {
176-
item.permission = mergeAgentPermissions(cfg.permission ?? {}, permission ?? {})
179+
if (permission ?? cfg.permission) {
180+
item.permission = mergeAgentPermissions(cfg.permission ?? {}, permission ?? {})
181+
}
177182
}
178-
}
179-
return result
180-
})
183+
return result
184+
},
185+
)
181186

182187
export async function get(agent: string) {
183188
return state().then((x) => x[agent])

packages/opencode/src/command/index.ts

Lines changed: 25 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import z from "zod"
22
import { Config } from "../config/config"
33
import { Instance } from "../project/instance"
4+
import { State } from "../project/state"
45
import PROMPT_INITIALIZE from "./template/initialize.txt"
56
import { Bus } from "../bus"
67
import { Identifier } from "../id/id"
@@ -36,32 +37,36 @@ export namespace Command {
3637
})
3738
export type Info = z.infer<typeof Info>
3839

39-
const state = Instance.state(async () => {
40-
const cfg = await Config.get()
40+
const state = State.register(
41+
"command",
42+
() => Instance.directory,
43+
async () => {
44+
const cfg = await Config.get()
4145

42-
const result: Record<string, Info> = {}
46+
const result: Record<string, Info> = {}
4347

44-
for (const [name, command] of Object.entries(cfg.command ?? {})) {
45-
result[name] = {
46-
name,
47-
agent: command.agent,
48-
model: command.model,
49-
description: command.description,
50-
template: command.template,
51-
subtask: command.subtask,
48+
for (const [name, command] of Object.entries(cfg.command ?? {})) {
49+
result[name] = {
50+
name,
51+
agent: command.agent,
52+
model: command.model,
53+
description: command.description,
54+
template: command.template,
55+
subtask: command.subtask,
56+
}
5257
}
53-
}
5458

55-
if (result[Default.INIT] === undefined) {
56-
result[Default.INIT] = {
57-
name: Default.INIT,
58-
description: "create/update AGENTS.md",
59-
template: PROMPT_INITIALIZE.replace("${path}", Instance.worktree),
59+
if (result[Default.INIT] === undefined) {
60+
result[Default.INIT] = {
61+
name: Default.INIT,
62+
description: "create/update AGENTS.md",
63+
template: PROMPT_INITIALIZE.replace("${path}", Instance.worktree),
64+
}
6065
}
61-
}
6266

63-
return result
64-
})
67+
return result
68+
},
69+
)
6570

6671
export async function get(name: string) {
6772
return state().then((x) => x[name])
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import fs from "fs/promises"
2+
3+
export async function createBackup(filepath: string): Promise<string> {
4+
const timestamp = new Date().toISOString().replace(/[:.]/g, "-")
5+
const backupPath = `${filepath}.bak-${timestamp}`
6+
7+
if (await Bun.file(filepath).exists()) {
8+
await fs.copyFile(filepath, backupPath)
9+
}
10+
11+
return backupPath
12+
}
13+
14+
export async function restoreBackup(backupPath: string, targetPath: string): Promise<void> {
15+
await fs.copyFile(backupPath, targetPath)
16+
await fs.unlink(backupPath)
17+
}

0 commit comments

Comments
 (0)