diff --git a/package.json b/package.json
index a30b55be73..aa7031bec7 100644
--- a/package.json
+++ b/package.json
@@ -78,8 +78,6 @@
"url": "https://github.com/sst/opencode"
},
"license": "MIT",
- "randomField": "hello from claude",
- "anotherRandomField": "xkcd-927-compliance-level",
"prettier": {
"semi": false,
"printWidth": 120
diff --git a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
index 37f169b193..e3d519115b 100644
--- a/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
+++ b/packages/opencode/src/cli/cmd/tui/routes/session/permission.tsx
@@ -130,24 +130,24 @@ export function PermissionPrompt(props: { request: PermissionRequest }) {
This will allow the following patterns until OpenCode is restarted
-
- {(pattern) => (
-
- {"- "}
- {pattern}
-
- )}
-
+
+
+ {(pattern) => (
+
+ {"- "}
+ {pattern}
+
+ )}
+
+
}
options={{ confirm: "Confirm", cancel: "Cancel" }}
onSelect={(option) => {
- if (option === "cancel") {
- setStore("always", false)
- return
- }
+ setStore("always", false)
+ if (option === "cancel") return
sdk.client.permission.reply({
reply: "always",
requestID: props.request.id,
diff --git a/packages/opencode/src/config/config.ts b/packages/opencode/src/config/config.ts
index 80d761b71d..f5d895dc8f 100644
--- a/packages/opencode/src/config/config.ts
+++ b/packages/opencode/src/config/config.ts
@@ -123,13 +123,22 @@ export namespace Config {
result.permission = mergeDeep(result.permission ?? {}, JSON.parse(Flag.OPENCODE_PERMISSION))
}
- if (!result.username) result.username = os.userInfo().username
-
- // Handle migration from autoshare to share field
- if (result.autoshare === true && !result.share) {
- result.share = "auto"
+ // Backwards compatibility: legacy top-level `tools` config
+ if (result.tools) {
+ const perms: Record = {}
+ for (const [tool, enabled] of Object.entries(result.tools)) {
+ const action: Config.PermissionAction = enabled ? "allow" : "deny"
+ if (tool === "write" || tool === "edit" || tool === "patch" || tool === "multiedit") {
+ perms.edit = action
+ continue
+ }
+ perms[tool] = action
+ }
+ result.permission = mergeDeep(perms, result.permission ?? {})
}
+ if (!result.username) result.username = os.userInfo().username
+
// Handle migration from autoshare to share field
if (result.autoshare === true && !result.share) {
result.share = "auto"
diff --git a/packages/opencode/src/permission/arity.ts b/packages/opencode/src/permission/arity.ts
index bbc6bb03db..948841c8e7 100644
--- a/packages/opencode/src/permission/arity.ts
+++ b/packages/opencode/src/permission/arity.ts
@@ -5,7 +5,8 @@ export namespace BashArity {
const arity = ARITY[prefix]
if (arity !== undefined) return tokens.slice(0, arity)
}
- return tokens
+ if (tokens.length === 0) return []
+ return tokens.slice(0, 1)
}
/* Generated with following prompt:
diff --git a/packages/opencode/src/permission/next.ts b/packages/opencode/src/permission/next.ts
index b434b79643..5102a22fdc 100644
--- a/packages/opencode/src/permission/next.ts
+++ b/packages/opencode/src/permission/next.ts
@@ -181,7 +181,6 @@ export namespace PermissionNext {
return
}
if (input.reply === "always") {
- const projectID = Instance.project.id
for (const pattern of existing.info.always) {
s.approved.push({
permission: existing.info.permission,
@@ -189,10 +188,28 @@ export namespace PermissionNext {
action: "allow",
})
}
+
+ existing.resolve()
+
+ const sessionID = existing.info.sessionID
+ for (const [id, pending] of Object.entries(s.pending)) {
+ if (pending.info.sessionID !== sessionID) continue
+ const ok = pending.info.patterns.every(
+ (pattern) => evaluate(pending.info.permission, pattern, s.approved) === "allow",
+ )
+ if (!ok) continue
+ delete s.pending[id]
+ Bus.publish(Event.Replied, {
+ sessionID: pending.info.sessionID,
+ requestID: pending.info.id,
+ reply: "always",
+ })
+ pending.resolve()
+ }
+
// TODO: we don't save the permission ruleset to disk yet until there's
// UI to manage it
- // await Storage.write(["permission", projectID], s.approved)
- existing.resolve()
+ // await Storage.write(["permission", Instance.project.id], s.approved)
return
}
},