Skip to content
Merged
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
1 change: 1 addition & 0 deletions lua/opencode/event_manager.lua
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ local util = require('opencode.util')
--- @field type string
--- @field pattern string|string[]
--- @field sessionID string
--- @field tool? {messageID: string, callID: string}
--- @field messageID string
--- @field callID? string
--- @field title string
Expand Down
15 changes: 13 additions & 2 deletions lua/opencode/ui/formatter.lua
Original file line number Diff line number Diff line change
Expand Up @@ -683,8 +683,19 @@ function M._format_tool(output, part)

if
state.current_permission
and state.current_permission.messageID == part.messageID
and state.current_permission.callID == part.callID
and (
(
state.current_permission.tool
and state.current_permission.tool.callID == part.callID
and state.current_permission.tool.messageID == part.messageID
)
---@TODO this is for backward compatibility, remove later
or (
not state.current_permission.tool
and state.current_permission.messageID == part.messageID
and state.current_permission.callID == part.callID
)
)
then
M._handle_permission_request(output, part)
end
Expand Down
21 changes: 17 additions & 4 deletions lua/opencode/ui/renderer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ function M.setup_subscriptions(subscribe)
{ 'message.part.updated', M.on_part_updated },
{ 'message.part.removed', M.on_part_removed },
{ 'permission.updated', M.on_permission_updated },
{ 'permission.asked', M.on_permission_updated },
{ 'permission.replied', M.on_permission_replied },
{ 'file.edited', M.on_file_edited },
{ 'custom.restore_point.created', M.on_restore_points },
Expand Down Expand Up @@ -768,7 +769,13 @@ end
---Re-renders part that requires permission
---@param permission OpencodePermission Event properties
function M.on_permission_updated(permission)
if not permission or not permission.messageID or not permission.callID then
local tool = permission.tool

---@TODO this is for backward compatibility, remove later
local callID = tool and tool.callID or permission.callID
local messageID = tool and tool.messageID or permission.messageID

if not permission or not messageID or not callID then
return
end

Expand All @@ -782,9 +789,10 @@ function M.on_permission_updated(permission)

state.current_permission = permission

local part_id = M._find_part_by_call_id(permission.callID, permission.messageID)
local part_id = M._find_part_by_call_id(callID, messageID)
if part_id then
M._rerender_part(part_id)
M.scroll_to_bottom()
end
end

Expand All @@ -799,8 +807,13 @@ function M.on_permission_replied(properties)
local old_permission = state.current_permission
state.current_permission = nil

if old_permission and old_permission.callID then
local part_id = M._find_part_by_call_id(old_permission.callID, old_permission.messageID)
---@TODO this is for backward compatibility, remove later
local tool = old_permission and old_permission.tool
local callID = tool and tool.callID or (old_permission and old_permission.callID)
local messageID = tool and tool.messageID or (old_permission and old_permission.messageID)

if old_permission and messageID and callID then
local part_id = M._find_part_by_call_id(callID, messageID)
if part_id then
M._rerender_part(part_id)
end
Expand Down
1 change: 1 addition & 0 deletions tests/data/permission-ask-new-approve.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"extmarks":[[1,1,0,{"ns_id":3,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60a2001Kisjwk2mVB4dye]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[2,2,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[3,3,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[4,4,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[5,5,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[6,6,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[7,7,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[8,8,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[9,10,0,{"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:07:54)","OpencodeHint"],[" [msg_b8e7c60f1001aEWYlAaDRXQ4aJ]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[10,12,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[11,13,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[12,14,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[13,15,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[14,16,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[15,17,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[16,18,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[17,19,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[18,20,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[19,21,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[20,22,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[21,23,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[22,24,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[23,25,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[24,26,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[25,27,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[26,28,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[27,29,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[28,30,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[29,31,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[30,32,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[31,33,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[32,34,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[33,39,0,{"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:08:26)","OpencodeHint"],[" [msg_b8e7cde9e0013hRkUyt0X2yMil]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}]],"timestamp":1767622324,"lines":["----","","","@no-trust run a git status and tell me what files are changed","","[lua/opencode/ui/formatter.lua](lua/opencode/ui/formatter.lua)","","**Diagnostics:**  (11)","","----","","","** run** `Shows working tree status`","","`````bash","> git status","","On branch main","Your branch is up to date with 'origin/main'.","","Changes not staged for commit:"," (use \"git add <file>...\" to update what will be committed)"," (use \"git restore <file>...\" to discard changes in working directory)","\tmodified: lua/opencode/event_manager.lua","\tmodified: lua/opencode/ui/formatter.lua","\tmodified: lua/opencode/ui/renderer.lua","","Untracked files:"," (use \"git add <file>...\" to include in what will be committed)","\ttest.lua","\ttests/data/permission_ask_new.json","","no changes added to commit (use \"git add\" and/or \"git commit -a\")","","`````","","**󰻛 Created Snapshot** `5ba6e957`","","----","","","Here are the files that have been changed according to git status:","","- Modified (but not staged):"," - `lua/opencode/event_manager.lua`"," - `lua/opencode/ui/formatter.lua`"," - `lua/opencode/ui/renderer.lua`","","- Untracked files:"," - `test.lua`"," - `tests/data/permission_ask_new.json`","","No files are currently staged for commit. Let me know if you want more details (like the diff), want to stage/commit, or need help with anything else!","",""],"actions":[{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"text":"[R]evert file","range":{"to":36,"from":36},"key":"R","display_line":36,"type":"diff_revert_selected_file"},{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"text":"Revert [A]ll","range":{"to":36,"from":36},"key":"A","display_line":36,"type":"diff_revert_all"},{"args":["5ba6e95774829e7f501299039b72b72dc32c6620"],"text":"[D]iff","range":{"to":36,"from":36},"key":"D","display_line":36,"type":"diff_open"}]}
1 change: 1 addition & 0 deletions tests/data/permission-ask-new-approve.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions tests/data/permission-ask-new-deny.expected.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"extmarks":[[1,1,0,{"ns_id":3,"virt_text":[["▌󰭻 ","OpencodeMessageRoleUser"],[" "],["USER","OpencodeMessageRoleUser"],["","OpencodeHint"],[" (2026-01-05 14:09:08)","OpencodeHint"],[" [msg_b8e7d8222001ZAc4G1t5RfHzou]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[2,2,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[3,3,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[4,4,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[5,5,0,{"ns_id":3,"virt_text":[["▌","OpencodeMessageRoleUser"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[6,8,0,{"ns_id":3,"virt_text":[[" ","OpencodeMessageRoleAssistant"],[" "],["BUILD","OpencodeMessageRoleAssistant"],[" gpt-4.1","OpencodeHint"],[" (2026-01-05 14:09:08)","OpencodeHint"],[" [msg_b8e7d823f001HX1Rr9DYE7TYBf]","OpencodeHint"]],"right_gravity":true,"priority":10,"virt_text_repeat_linebreak":false,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-3}],[7,10,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[8,11,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[9,12,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[10,13,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[11,14,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[12,15,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[13,16,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}],[14,17,0,{"ns_id":3,"virt_text":[["▌","OpencodeToolBorder"]],"right_gravity":true,"priority":4096,"virt_text_repeat_linebreak":true,"virt_text_pos":"win_col","virt_text_hide":false,"virt_text_win_col":-1}]],"timestamp":1767622360,"lines":["----","","","@no-trust run a git status and tell me what files are changed","","[lua/opencode/ui/formatter.lua](lua/opencode/ui/formatter.lua)","","----","","","** run** `Shows working tree status`","","`````bash","> git status","","`````","","> [!ERROR] Error: The user rejected permission to use this specific tool call.","",""],"actions":[]}
1 change: 1 addition & 0 deletions tests/data/permission-ask-new-deny.json

Large diffs are not rendered by default.

Loading