Skip to content

Commit 48e766f

Browse files
committed
feat(core): ensure cwd is correct when opening the panel
1 parent 0f3b34c commit 48e766f

7 files changed

Lines changed: 80 additions & 49 deletions

File tree

lua/opencode/api_client.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
local server_job = require('opencode.server_job')
2+
local state = require('opencode.state')
23

34
--- @class OpencodeApiClient
45
--- @field base_url string The base URL of the opencode server
@@ -63,7 +64,7 @@ function OpencodeApiClient:_call(endpoint, method, body, query)
6364

6465
if query then
6566
if not query.directory then
66-
query.directory = vim.fn.getcwd()
67+
query.directory = state.current_cwd or vim.fn.getcwd()
6768
end
6869

6970
local params = {}

lua/opencode/core.lua

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ local config = require('opencode.config')
1010
local image_handler = require('opencode.image_handler')
1111
local Promise = require('opencode.promise')
1212
local permission_window = require('opencode.ui.permission_window')
13+
local log = require('opencode.log')
1314

1415
local M = {}
1516
M._abort_count = 0
@@ -57,6 +58,27 @@ M.open_if_closed = Promise.async(function(opts)
5758
end
5859
end)
5960

61+
M.is_prompting_allowed = function()
62+
local mentioned_files = context.get_context().mentioned_files or {}
63+
local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)
64+
if not allowed then
65+
vim.notify(err_msg or 'Prompt denied by prompt_guard', vim.log.levels.ERROR)
66+
end
67+
return allowed
68+
end
69+
70+
M.check_cwd = function()
71+
if state.current_cwd ~= vim.fn.getcwd() then
72+
log.debug(
73+
'CWD changed since last check, resetting session and context',
74+
{ current_cwd = state.current_cwd, new_cwd = vim.fn.getcwd() }
75+
)
76+
state.current_cwd = vim.fn.getcwd()
77+
state.active_session = nil
78+
context.unload_attachments()
79+
end
80+
end
81+
6082
---@param opts? OpenOpts
6183
M.open = Promise.async(function(opts)
6284
opts = opts or { focus = 'input', new_session = false }
@@ -69,13 +91,7 @@ M.open = Promise.async(function(opts)
6991

7092
local are_windows_closed = state.windows == nil
7193
if are_windows_closed then
72-
-- Check if whether prompting will be allowed
73-
local mentioned_files = context.get_context().mentioned_files or {}
74-
local allowed, err_msg = util.check_prompt_allowed(config.prompt_guard, mentioned_files)
75-
if not allowed then
76-
vim.notify(err_msg or 'Prompts will be denied by prompt_guard', vim.log.levels.WARN)
77-
end
78-
94+
M.is_prompting_allowed()
7995
state.windows = ui.create_windows()
8096
end
8197

@@ -85,22 +101,16 @@ M.open = Promise.async(function(opts)
85101
ui.focus_output({ restore_position = are_windows_closed })
86102
end
87103

88-
local server
89-
local server_ok, server_err = pcall(function()
90-
server = server_job.ensure_server():await()
91-
end)
104+
local server = server_job.ensure_server():await()
92105

93-
if not server_ok or not server then
106+
if not server then
94107
state.is_opening = false
95-
vim.notify('Failed to start opencode server: ' .. tostring(server_err or 'Unknown error'), vim.log.levels.ERROR)
96-
return Promise.new():reject(server_err or 'Server failed to start')
108+
return Promise.new():reject('Server failed to start')
97109
end
98110

99-
state.opencode_server = server
111+
M.check_cwd()
100112

101113
local ok, err = pcall(function()
102-
state.opencode_server = server
103-
104114
if opts.new_session then
105115
state.active_session = nil
106116
state.last_sent_context = nil
@@ -109,6 +119,7 @@ M.open = Promise.async(function(opts)
109119
M.ensure_current_mode():await()
110120

111121
state.active_session = M.create_new_session():await()
122+
log.debug('Created new session on open', { session = state.active_session.id })
112123
else
113124
M.ensure_current_mode():await()
114125
if not state.active_session then
@@ -549,32 +560,22 @@ end
549560
M.handle_directory_change = Promise.async(function()
550561
local log = require('opencode.log')
551562
if not state.active_session then
552-
is_new = true
553563
state.active_session = M.create_new_session():await()
554564
end
555565

556-
if state.opencode_server then
557-
vim.notify('Working directory changed.', vim.log.levels.INFO)
558-
log.debug('Working directory change %s', vim.inspect({ cwd = vim.fn.getcwd() }))
566+
vim.notify('Working directory changed.', vim.log.levels.INFO)
567+
log.debug('Working directory change %s', vim.inspect({ cwd = vim.fn.getcwd() }))
559568

560-
vim.defer_fn(
561-
Promise.async(function()
562-
vim.notify('Loading last session for new working dir [' .. vim.fn.getcwd() .. ']', vim.log.levels.INFO)
569+
vim.notify('Loading last session for new working dir [' .. vim.fn.getcwd() .. ']', vim.log.levels.INFO)
563570

564-
state.active_session = nil
565-
state.last_sent_context = nil
566-
context.unload_attachments()
571+
state.active_session = nil
572+
state.last_sent_context = nil
573+
context.unload_attachments()
567574

568-
local is_new = false
569-
state.active_session = session.get_last_workspace_session():await() or M.create_new_session():await()
575+
local is_new = false
576+
state.active_session = session.get_last_workspace_session():await() or M.create_new_session():await()
570577

571-
log.debug(
572-
'Loaded session for new working dir' .. vim.inspect({ session = state.active_session, is_new = is_new })
573-
)
574-
end),
575-
200
576-
)
577-
end
578+
log.debug('Loaded session for new working dir' .. vim.inspect({ session = state.active_session, is_new = is_new }))
578579
end)
579580

580581
function M.setup()

lua/opencode/server_job.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local state = require('opencode.state')
22
local curl = require('opencode.curl')
33
local Promise = require('opencode.promise')
44
local opencode_server = require('opencode.opencode_server')
5+
local log = require('opencode.log')
56

67
local M = {}
78
M.requests = {}
@@ -146,6 +147,8 @@ function M.ensure_server()
146147
promise:resolve(state.opencode_server)
147148
end,
148149
on_error = function(err)
150+
log.error('Error starting opencode server: ' .. vim.inspect(err))
151+
vim.notify('Failed to start opencode server', vim.log.levels.ERROR)
149152
promise:reject(err)
150153
end,
151154
on_exit = function(exit_opts)

lua/opencode/state.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
---@field pre_zoom_width integer|nil
4444
---@field required_version string
4545
---@field opencode_cli_version string|nil
46+
---@field current_cwd string|nil
4647
---@field append fun( key:string, value:any)
4748
---@field remove fun( key:string, idx:number)
4849
---@field subscribe fun( key:string|nil, cb:fun(key:string, new_val:any, old_val:any))
@@ -97,6 +98,7 @@ local _state = {
9798
-- versions
9899
required_version = '0.6.3',
99100
opencode_cli_version = nil,
101+
current_cwd = vim.fn.getcwd(),
100102
}
101103

102104
-- Listener registry: { [key] = {cb1, cb2, ...}, ['*'] = {cb1, ...} }

lua/opencode/ui/autocmds.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
local Promise = require('opencode.promise')
21
local input_window = require('opencode.ui.input_window')
32
local output_window = require('opencode.ui.output_window')
43
local M = {}
@@ -52,6 +51,8 @@ function M.setup_autocmds(windows)
5251
vim.api.nvim_create_autocmd('DirChanged', {
5352
group = group,
5453
callback = function(event)
54+
local state = require('opencode.state')
55+
state.current_cwd = event.file
5556
local core = require('opencode.core')
5657
core.handle_directory_change()
5758
end,

tests/unit/api_client_spec.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ describe('api_client', function()
6363
local original_call_api = server_job.call_api
6464
local captured_calls = {}
6565
local original_cwd = vim.fn.getcwd
66+
local state = require('opencode.state')
67+
state.current_cwd = '/current/directory'
68+
6669
vim.fn.getcwd = function()
6770
return '/current/directory'
6871
end

tests/unit/core_spec.lua

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,37 @@ describe('opencode.core', function()
152152
}, state.windows)
153153
end)
154154

155+
it('ensure the current cwd is correct when opening', function()
156+
local cwd = vim.fn.getcwd()
157+
state.current_cwd = nil
158+
core.open({ new_session = false, focus = 'input' }):wait()
159+
assert.equal(cwd, state.current_cwd)
160+
end)
161+
162+
it('reload the active_session if cwd has changed since last session', function()
163+
local original_getcwd = vim.fn.getcwd
164+
165+
state.windows = nil
166+
state.active_session = { id = 'old-session' }
167+
state.current_cwd = '/some/old/path'
168+
vim.fn.getcwd = function()
169+
return '/some/new/path'
170+
end
171+
session.get_last_workspace_session:revert()
172+
stub(session, 'get_last_workspace_session').invokes(function()
173+
local p = Promise.new()
174+
p:resolve({ id = 'new_cwd-test-session' })
175+
return p
176+
end)
177+
178+
core.open({ new_session = false, focus = 'input' }):wait()
179+
180+
assert.truthy(state.active_session)
181+
assert.equal('new_cwd-test-session', state.active_session.id)
182+
-- Restore original cwd function
183+
vim.fn.getcwd = original_getcwd
184+
end)
185+
155186
it('handles new session properly', function()
156187
state.windows = nil
157188
state.active_session = { id = 'old-session' }
@@ -472,25 +503,14 @@ describe('opencode.core', function()
472503
describe('handle_directory_change', function()
473504
local server_job
474505
local context
475-
local original_defer_fn
476506

477507
before_each(function()
478508
server_job = require('opencode.server_job')
479509
context = require('opencode.context')
480-
original_defer_fn = vim.defer_fn
481-
482-
-- Mock vim.defer_fn to execute immediately in tests
483-
vim.defer_fn = function(fn, delay)
484-
fn()
485-
end
486510

487511
stub(context, 'unload_attachments')
488512
end)
489513

490-
after_each(function()
491-
vim.defer_fn = original_defer_fn
492-
end)
493-
494514
it('clears active session and context', function()
495515
state.active_session = { id = 'old-session' }
496516
state.last_sent_context = { some = 'context' }

0 commit comments

Comments
 (0)