@@ -4,6 +4,7 @@ local url_encode = require('opencode.util').url_encode
44local apply_path_map = require (' opencode.util' ).apply_path_map
55local reverse_transform_paths_recursive = require (' opencode.util' ).reverse_transform_paths_recursive
66local transform_paths_recursive = require (' opencode.util' ).transform_paths_recursive
7+ local is_version_greater_or_equal = require (' opencode.util' ).is_version_greater_or_equal
78
89--- @class OpencodeApiClient
910--- @field base_url string The base URL of the opencode server
@@ -19,6 +20,51 @@ function OpencodeApiClient.new(base_url)
1920 }, OpencodeApiClient )
2021end
2122
23+ --- Convert /global/event envelopes into the legacy event shape consumed by the
24+ --- rest of the plugin.
25+ --- @param event table | nil
26+ --- @return table | nil
27+ local function normalize_global_event (event )
28+ if type (event ) ~= ' table' then
29+ return nil
30+ end
31+
32+ local payload = event .payload
33+ if type (payload ) ~= ' table' then
34+ return nil
35+ end
36+
37+ if payload .type == ' sync' then
38+ local sync_event = payload .syncEvent
39+ if type (sync_event ) ~= ' table' then
40+ return nil
41+ end
42+
43+ local event_type = sync_event .type
44+ if type (event_type ) ~= ' string' then
45+ return nil
46+ end
47+
48+ event_type = event_type :gsub (' %.%d+$' , ' ' )
49+
50+ return {
51+ id = sync_event .id or payload .id ,
52+ type = event_type ,
53+ properties = sync_event .data ,
54+ }
55+ end
56+
57+ if type (payload .type ) ~= ' string' then
58+ return nil
59+ end
60+
61+ return {
62+ id = payload .id ,
63+ type = payload .type ,
64+ properties = payload .properties ,
65+ }
66+ end
67+
2268--- Ensure that base_url is set. Even thought we're subscribed to
2369--- state.opencode_server, we still need this check because
2470--- it's possible someone will try to make an api call in their event
447493--- @param on_event fun ( event : table ) Event callback
448494--- @return table The streaming job handle
449495function OpencodeApiClient :subscribe_to_events (directory , on_event )
450- self :_ensure_base_url ()
496+ -- Make sure we have a base URL before attempting to subscribe. If we
497+ -- cannot determine a base URL (server not running), return nil so
498+ -- callers can handle the absence of a subscription without an error.
499+ if not self :_ensure_base_url () then
500+ return nil
501+ end
502+
503+ if is_version_greater_or_equal (state .opencode_cli_version , ' 1.14.42' ) then
504+ return self :_subscribe_to_global_events (directory , on_event )
505+ end
506+
451507 local url = self .base_url .. ' /event'
452508 if directory then
453509 local mapped_directory = apply_path_map (directory )
@@ -464,6 +520,39 @@ function OpencodeApiClient:subscribe_to_events(directory, on_event)
464520 end )
465521end
466522
523+ --- Subscribe to events (streaming)
524+ --- @param directory string | nil Directory path
525+ --- @param on_event fun ( event : table ) Event callback
526+ --- @return table The streaming job handle
527+ function OpencodeApiClient :_subscribe_to_global_events (directory , on_event )
528+ -- Ensure base_url is available. If not, return nil instead of erroring.
529+ if not self :_ensure_base_url () then
530+ return nil
531+ end
532+
533+ if not is_version_greater_or_equal (state .opencode_cli_version , ' 1.14.42' ) then
534+ error (' subscribe_to_global_events should not be called directly' )
535+ end
536+
537+ local url = self .base_url .. ' /global/event'
538+ if directory then
539+ local mapped_directory = apply_path_map (directory )
540+ url = url .. ' ?directory=' .. url_encode (mapped_directory )
541+ end
542+
543+ return server_job .stream_api (url , ' GET' , nil , function (chunk )
544+ chunk = chunk :gsub (' ^data:%s*' , ' ' )
545+ local ok , event = pcall (vim .json .decode , vim .trim (chunk ))
546+ if ok and event then
547+ local normalized_event = normalize_global_event (event )
548+ if normalized_event then
549+ local transformed_event = reverse_transform_paths_recursive (normalized_event )
550+ on_event (transformed_event --[[ @as table]] )
551+ end
552+ end
553+ end )
554+ end
555+
467556-- Tool endpoints
468557
469558--- List all tool IDs (including built-in and dynamically registered)
0 commit comments