Repository navigation
Expand file tree
/
Copy pathconfig_file.lua
More file actions
192 lines (172 loc) · 5.76 KB
/
Copy pathconfig_file.lua
File metadata and controls
192 lines (172 loc) · 5.76 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
local Promise = require('opencode.promise')
local sha1 = require('opencode.sha1')
local util = require('opencode.util')
local server_job = require('opencode.server_job')
local M = {
config_promise = nil,
project_promise = nil,
providers_promise = nil,
}
local cache_connection
local function sync_cache_connection()
local connection = require('opencode.state').opencode_server
if connection ~= cache_connection then
cache_connection = connection
M.config_promise = nil
M.project_promise = nil
M.providers_promise = nil
end
return connection
end
local resource = Promise.async(function(name, directory)
local state = require('opencode.state')
local connection = server_job.ensure_server():await()
sync_cache_connection()
local operation = connection and connection.operations and connection.operations[name]
if type(operation) ~= 'function' then
error('Connection does not support ' .. name)
end
return operation(
connection,
{ directory = directory or state.current_cwd or vim.fn.getcwd() },
util.apply_path_map,
util.apply_reverse_path_map
)
end)
---@type fun(): Promise<OpencodeConfigFile|nil>
M.get_opencode_config = Promise.async(function()
sync_cache_connection()
if not M.config_promise then
M.config_promise = Promise.retry(function()
return resource('get_config')
end, 3, 500)
end
local ok, result = pcall(function()
return M.config_promise:await()
end)
if not ok then
M.config_promise = nil
vim.notify('Error fetching Opencode config: ' .. vim.inspect(result), vim.log.levels.ERROR)
return nil
end
return result
end)
---@type fun(directory?: string): Promise<OpencodeProject|nil>
M.get_opencode_project = Promise.async(function(directory)
sync_cache_connection()
if directory then
return resource('get_current_project', directory):await()
end
if not M.project_promise then
M.project_promise = Promise.retry(function()
return resource('get_current_project')
end, 3, 500)
end
local ok, result = pcall(function()
return M.project_promise:await()
end)
if not ok then
M.project_promise = nil
vim.notify('Error fetching Opencode project: ' .. vim.inspect(result), vim.log.levels.ERROR)
return nil
end
return result --[[@as OpencodeProject|nil]]
end)
---Get the snapshot storage path for the current workspace
---Matches opencode's Global.Path.data + "snapshot" + projectId + Hash.fast(worktree)
---Can be overridden via config.snapshot_path (base path, project_id and worktree_hash are appended)
---@type fun(directory?: string): Promise<string>
M.get_workspace_snapshot_path = Promise.async(function(directory)
local cwd = directory or vim.fn.getcwd()
local project = M.get_opencode_project(cwd):await() --[[@as OpencodeProject|nil]]
if not project then
return ''
end
local data_home = require('opencode.config').snapshot_path
if not data_home or data_home == '' then
data_home = vim.uv.os_getenv('XDG_DATA_HOME')
if not data_home or data_home == '' then
data_home = vim.uv.os_homedir() .. '/.local/share'
end
data_home = vim.fs.joinpath(data_home, 'opencode')
end
local worktree_hash = sha1(cwd)
if not worktree_hash then
return ''
end
local path = vim.fs.joinpath(data_home, 'snapshot', project.id, worktree_hash)
return vim.fs.normalize(path)
end)
---@return Promise<OpencodeProvidersResponse|nil>
function M.get_opencode_providers()
sync_cache_connection()
if not M.providers_promise then
M.providers_promise = resource('get_model_catalog')
end
return M.providers_promise:catch(function(err)
vim.notify('Error fetching Opencode providers: ' .. vim.inspect(err), vim.log.levels.ERROR)
M.providers_promise = nil
return nil
end)
end
--- Get model information for a specific provider and model
--- @param provider string Provider ID
--- @param model string Model ID
--- @return OpencodeModel|nil Model information with variants
M.get_model_info = function(provider, model)
local providers_response = M.get_opencode_providers():peek()
local providers = providers_response and providers_response.providers or {}
local filtered_providers = vim.tbl_filter(function(p)
return p.id == provider
end, providers)
if #filtered_providers == 0 then
return nil
end
local model_info = filtered_providers[1] and filtered_providers[1].models and filtered_providers[1].models[model]
or nil
if not model_info or not model_info.variants or not vim.islist(model_info.variants) then
return model_info
end
local normalized = vim.deepcopy(model_info)
normalized.variants = {}
for _, variant in ipairs(model_info.variants) do
if type(variant) == 'table' and type(variant.id) == 'string' then
normalized.variants[variant.id] = variant
end
end
return normalized
end
---@type fun(): Promise<string[]>
M.get_opencode_agents = Promise.async(function()
local empty_agents = {}
return Promise.retry(function()
return resource('list_primary_agents'):and_then(function(agents)
if agents and #agents > 0 then
return agents
end
return Promise.new():reject(empty_agents)
end)
end, 3, 500)
:catch(function(err)
if err == empty_agents then
return {}
end
return Promise.new():reject(err)
end)
:await()
end)
---@type fun(): Promise<string[]>
M.get_subagents = Promise.async(function()
return resource('list_subagents'):await() or {}
end)
---@type fun(): Promise<table<string, table>|nil>
M.get_user_commands = Promise.async(function()
return resource('get_user_commands'):await()
end)
---Does this opencode user command take arguments?
---@param command OpencodeCommand
---@return boolean
function M.command_takes_arguments(command)
return command.template and command.template:find('$ARGUMENTS') ~= nil or false
end
return M