copilot-sdk-supercharged 2.4.0 → 2.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/copilot/client.rb +173 -2
- data/lib/copilot/json_rpc_client.rb +5 -1
- data/lib/copilot/session.rb +1 -0
- data/lib/copilot/types.rb +3 -0
- data/lib/copilot/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8a7fd46a011b45876248c40e46f1b283271631d2c52e99ebd6a782797dc534cc
|
|
4
|
+
data.tar.gz: b05f12f98a4a459b5d8dd3de5fd0606c3d6fd3f0311ec51b2061430832dbd0e1
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 60622159ecd94b6140cf217816bab128558e1f9f2e5be7f814fdba56e8aa8158a992b67e1ff24e5499ad99cf657e729db6b5ee7867257f104596b31fc872f53c
|
|
7
|
+
data.tar.gz: 58606a5efea0407d47eb7e8453ce2c1c572ffe2e513be46c3cfe339c70822dad16666f7cb11438c99d76b2c97bbb86d845bb0077c508bd9b0955d05a4563c81a
|
data/lib/copilot/client.rb
CHANGED
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
require "open3"
|
|
6
6
|
require "socket"
|
|
7
7
|
require "thread"
|
|
8
|
+
require "fileutils"
|
|
9
|
+
require "time"
|
|
8
10
|
|
|
9
11
|
module Copilot
|
|
10
12
|
# Main client for interacting with the Copilot CLI.
|
|
@@ -442,15 +444,18 @@ module Copilot
|
|
|
442
444
|
#
|
|
443
445
|
# @param initial_cwd [String, nil] Initial working directory
|
|
444
446
|
# @param session_state_path [String, nil] Path for session state persistence
|
|
445
|
-
# @param conventions [
|
|
447
|
+
# @param conventions [String, nil] Filesystem conventions ("posix" or "windows").
|
|
448
|
+
# Required by the CLI; defaults to the host platform's conventions when omitted.
|
|
446
449
|
# @return [void]
|
|
447
450
|
def set_session_fs_provider(initial_cwd: nil, session_state_path: nil, conventions: nil)
|
|
448
451
|
raise_not_connected! unless @rpc_client
|
|
449
452
|
|
|
453
|
+
conventions ||= (RUBY_PLATFORM =~ /mswin|mingw|cygwin/ ? "windows" : "posix")
|
|
454
|
+
|
|
450
455
|
params = {}
|
|
451
456
|
params[:initialCwd] = initial_cwd if initial_cwd
|
|
452
457
|
params[:sessionStatePath] = session_state_path if session_state_path
|
|
453
|
-
params[:conventions] = conventions
|
|
458
|
+
params[:conventions] = conventions
|
|
454
459
|
|
|
455
460
|
@rpc_client.request("sessionFs.setProvider", params)
|
|
456
461
|
end
|
|
@@ -647,6 +652,29 @@ module Copilot
|
|
|
647
652
|
@rpc_client.on_request("exitPlanMode.request") do |params|
|
|
648
653
|
handle_exit_plan_mode_request(params)
|
|
649
654
|
end
|
|
655
|
+
|
|
656
|
+
register_session_fs_handlers
|
|
657
|
+
end
|
|
658
|
+
|
|
659
|
+
# Registers the client-side session filesystem request handlers.
|
|
660
|
+
#
|
|
661
|
+
# When a session filesystem provider is set via {#set_session_fs_provider},
|
|
662
|
+
# the CLI drives filesystem access by sending +sessionFs.*+ requests back to
|
|
663
|
+
# the client. These handlers service those requests against the real
|
|
664
|
+
# filesystem using the absolute paths supplied by the CLI. Errors are
|
|
665
|
+
# returned in-band as +{ code:, message: }+ (SessionFsError) rather than
|
|
666
|
+
# raised, matching the reference SDK contract.
|
|
667
|
+
def register_session_fs_handlers
|
|
668
|
+
@rpc_client.on_request("sessionFs.readFile") { |params| handle_session_fs_read_file(params) }
|
|
669
|
+
@rpc_client.on_request("sessionFs.writeFile") { |params| handle_session_fs_write_file(params) }
|
|
670
|
+
@rpc_client.on_request("sessionFs.appendFile") { |params| handle_session_fs_append_file(params) }
|
|
671
|
+
@rpc_client.on_request("sessionFs.exists") { |params| handle_session_fs_exists(params) }
|
|
672
|
+
@rpc_client.on_request("sessionFs.stat") { |params| handle_session_fs_stat(params) }
|
|
673
|
+
@rpc_client.on_request("sessionFs.mkdir") { |params| handle_session_fs_mkdir(params) }
|
|
674
|
+
@rpc_client.on_request("sessionFs.readdir") { |params| handle_session_fs_readdir(params) }
|
|
675
|
+
@rpc_client.on_request("sessionFs.readdirWithTypes") { |params| handle_session_fs_readdir_with_types(params) }
|
|
676
|
+
@rpc_client.on_request("sessionFs.rm") { |params| handle_session_fs_rm(params) }
|
|
677
|
+
@rpc_client.on_request("sessionFs.rename") { |params| handle_session_fs_rename(params) }
|
|
650
678
|
end
|
|
651
679
|
|
|
652
680
|
def verify_protocol_version
|
|
@@ -798,6 +826,135 @@ module Copilot
|
|
|
798
826
|
end
|
|
799
827
|
end
|
|
800
828
|
|
|
829
|
+
# ---- SessionFs provider request handlers ----
|
|
830
|
+
#
|
|
831
|
+
# These service the CLI's +sessionFs.*+ callbacks against the real
|
|
832
|
+
# filesystem. Success returns mirror the generated result shapes and errors
|
|
833
|
+
# are returned in-band as a SessionFsError (+{ code:, message: }+) so the CLI
|
|
834
|
+
# can distinguish a missing file (ENOENT) from other failures without the
|
|
835
|
+
# request failing at the JSON-RPC layer.
|
|
836
|
+
|
|
837
|
+
def handle_session_fs_read_file(params)
|
|
838
|
+
content = File.read(params["path"], encoding: "UTF-8")
|
|
839
|
+
{ content: content }
|
|
840
|
+
rescue StandardError => e
|
|
841
|
+
{ content: "", error: session_fs_error(e) }
|
|
842
|
+
end
|
|
843
|
+
|
|
844
|
+
def handle_session_fs_write_file(params)
|
|
845
|
+
path = params["path"]
|
|
846
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
847
|
+
File.write(path, params["content"].to_s)
|
|
848
|
+
File.chmod(params["mode"], path) if params["mode"]
|
|
849
|
+
nil
|
|
850
|
+
rescue StandardError => e
|
|
851
|
+
session_fs_error(e)
|
|
852
|
+
end
|
|
853
|
+
|
|
854
|
+
def handle_session_fs_append_file(params)
|
|
855
|
+
path = params["path"]
|
|
856
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
857
|
+
File.open(path, "a") { |f| f.write(params["content"].to_s) }
|
|
858
|
+
File.chmod(params["mode"], path) if params["mode"]
|
|
859
|
+
nil
|
|
860
|
+
rescue StandardError => e
|
|
861
|
+
session_fs_error(e)
|
|
862
|
+
end
|
|
863
|
+
|
|
864
|
+
def handle_session_fs_exists(params)
|
|
865
|
+
{ exists: File.exist?(params["path"]) }
|
|
866
|
+
rescue StandardError
|
|
867
|
+
{ exists: false }
|
|
868
|
+
end
|
|
869
|
+
|
|
870
|
+
def handle_session_fs_stat(params)
|
|
871
|
+
st = File.stat(params["path"])
|
|
872
|
+
{
|
|
873
|
+
isFile: st.file?,
|
|
874
|
+
isDirectory: st.directory?,
|
|
875
|
+
size: st.size,
|
|
876
|
+
mtime: st.mtime.utc.iso8601,
|
|
877
|
+
birthtime: session_fs_birthtime(st).utc.iso8601,
|
|
878
|
+
}
|
|
879
|
+
rescue StandardError => e
|
|
880
|
+
now = Time.now.utc.iso8601
|
|
881
|
+
{
|
|
882
|
+
isFile: false,
|
|
883
|
+
isDirectory: false,
|
|
884
|
+
size: 0,
|
|
885
|
+
mtime: now,
|
|
886
|
+
birthtime: now,
|
|
887
|
+
error: session_fs_error(e),
|
|
888
|
+
}
|
|
889
|
+
end
|
|
890
|
+
|
|
891
|
+
def handle_session_fs_mkdir(params)
|
|
892
|
+
path = params["path"]
|
|
893
|
+
if params["recursive"]
|
|
894
|
+
FileUtils.mkdir_p(path)
|
|
895
|
+
else
|
|
896
|
+
Dir.mkdir(path)
|
|
897
|
+
end
|
|
898
|
+
File.chmod(params["mode"], path) if params["mode"]
|
|
899
|
+
nil
|
|
900
|
+
rescue StandardError => e
|
|
901
|
+
session_fs_error(e)
|
|
902
|
+
end
|
|
903
|
+
|
|
904
|
+
def handle_session_fs_readdir(params)
|
|
905
|
+
{ entries: Dir.children(params["path"]) }
|
|
906
|
+
rescue StandardError => e
|
|
907
|
+
{ entries: [], error: session_fs_error(e) }
|
|
908
|
+
end
|
|
909
|
+
|
|
910
|
+
def handle_session_fs_readdir_with_types(params)
|
|
911
|
+
path = params["path"]
|
|
912
|
+
entries = Dir.children(path).map do |name|
|
|
913
|
+
{ name: name, type: File.directory?(File.join(path, name)) ? "directory" : "file" }
|
|
914
|
+
end
|
|
915
|
+
{ entries: entries }
|
|
916
|
+
rescue StandardError => e
|
|
917
|
+
{ entries: [], error: session_fs_error(e) }
|
|
918
|
+
end
|
|
919
|
+
|
|
920
|
+
def handle_session_fs_rm(params)
|
|
921
|
+
path = params["path"]
|
|
922
|
+
force = params["force"]
|
|
923
|
+
if params["recursive"]
|
|
924
|
+
force ? FileUtils.rm_rf(path) : FileUtils.rm_r(path)
|
|
925
|
+
elsif force
|
|
926
|
+
FileUtils.rm_f(path)
|
|
927
|
+
else
|
|
928
|
+
File.delete(path)
|
|
929
|
+
end
|
|
930
|
+
nil
|
|
931
|
+
rescue Errno::ENOENT => e
|
|
932
|
+
params["force"] ? nil : session_fs_error(e)
|
|
933
|
+
rescue StandardError => e
|
|
934
|
+
session_fs_error(e)
|
|
935
|
+
end
|
|
936
|
+
|
|
937
|
+
def handle_session_fs_rename(params)
|
|
938
|
+
File.rename(params["src"], params["dest"])
|
|
939
|
+
nil
|
|
940
|
+
rescue StandardError => e
|
|
941
|
+
session_fs_error(e)
|
|
942
|
+
end
|
|
943
|
+
|
|
944
|
+
# Returns the creation time when the platform supports it, else falls back to mtime.
|
|
945
|
+
def session_fs_birthtime(stat)
|
|
946
|
+
stat.birthtime
|
|
947
|
+
rescue NotImplementedError
|
|
948
|
+
stat.mtime
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
# Maps a Ruby exception to a SessionFsError hash. Missing paths map to
|
|
952
|
+
# "ENOENT"; everything else maps to "UNKNOWN", matching the reference SDK.
|
|
953
|
+
def session_fs_error(err)
|
|
954
|
+
code = err.is_a?(Errno::ENOENT) ? "ENOENT" : "UNKNOWN"
|
|
955
|
+
{ code: code, message: err.message }
|
|
956
|
+
end
|
|
957
|
+
|
|
801
958
|
# ---- Payload builders ----
|
|
802
959
|
|
|
803
960
|
def build_create_session_payload(config)
|
|
@@ -859,6 +1016,20 @@ module Copilot
|
|
|
859
1016
|
payload[:otlpProtocol] = config[:otlp_protocol] if config[:otlp_protocol]
|
|
860
1017
|
payload[:enableWebSocketResponses] = config[:enable_web_socket_responses] unless config[:enable_web_socket_responses].nil?
|
|
861
1018
|
payload[:expAssignments] = config[:exp_assignments] if config[:exp_assignments]
|
|
1019
|
+
# --- Second upstream-sync batch (2026-08 parity with @github/copilot-sdk) ---
|
|
1020
|
+
payload[:rewindEnabled] = config[:rewind_enabled] unless config[:rewind_enabled].nil? # enable session rewind
|
|
1021
|
+
payload[:additionalDirectories] = config[:additional_directories] if config[:additional_directories]
|
|
1022
|
+
payload[:disabledMcpServers] = config[:disabled_mcp_servers] if config[:disabled_mcp_servers]
|
|
1023
|
+
payload[:githubMcpToolConfig] = config[:github_mcp_tool_config] if config[:github_mcp_tool_config]
|
|
1024
|
+
payload[:canvasProvider] = config[:canvas_provider] if config[:canvas_provider]
|
|
1025
|
+
payload[:customAgentsLocalOnly] = config[:custom_agents_local_only] unless config[:custom_agents_local_only].nil?
|
|
1026
|
+
payload[:builtinPluginDirectories] = config[:builtin_plugin_directories] if config[:builtin_plugin_directories]
|
|
1027
|
+
payload[:argsSchema] = config[:args_schema] if config[:args_schema] # agent-factory authoring schema
|
|
1028
|
+
payload[:decisionContext] = config[:decision_context] if config[:decision_context] # permission decision context
|
|
1029
|
+
payload[:toolSearch] = config[:tool_search] unless config[:tool_search].nil?
|
|
1030
|
+
payload[:inProcess] = config[:in_process] unless config[:in_process].nil?
|
|
1031
|
+
payload[:experimentalMode] = config[:experimental_mode] unless config[:experimental_mode].nil?
|
|
1032
|
+
payload[:contentExclusion] = config[:content_exclusion] unless config[:content_exclusion].nil?
|
|
862
1033
|
# MCP OAuth host token handler: signal to the runtime that a handler is registered.
|
|
863
1034
|
payload[:mcpAuthHandler] = true if config[:on_mcp_auth_request]
|
|
864
1035
|
|
|
@@ -296,7 +296,11 @@ module Copilot
|
|
|
296
296
|
# Execute handler (may be synchronous or may raise)
|
|
297
297
|
begin
|
|
298
298
|
result = handler.call(params)
|
|
299
|
-
|
|
299
|
+
# sessionFs.* write-ops (writeFile/appendFile/mkdir/rm/rename) signal success
|
|
300
|
+
# as JSON null (the CLI decodes the result as `SessionFsError | undefined`).
|
|
301
|
+
# Coercing nil to {} would be decoded as a malformed SessionFsError
|
|
302
|
+
# ("missing field `code`"), so preserve nil for those methods only.
|
|
303
|
+
result = {} if result.nil? && !method.to_s.start_with?("sessionFs.")
|
|
300
304
|
send_response(request_id, result)
|
|
301
305
|
rescue JsonRpcError => e
|
|
302
306
|
send_error_response(request_id, e.code, e.message, e.data)
|
data/lib/copilot/session.rb
CHANGED
|
@@ -349,6 +349,7 @@ module Copilot
|
|
|
349
349
|
"preToolUse" => hooks.on_pre_tool_use,
|
|
350
350
|
"postToolUse" => hooks.on_post_tool_use,
|
|
351
351
|
"userPromptSubmitted" => hooks.on_user_prompt_submitted,
|
|
352
|
+
"userPromptTransformed" => hooks.on_user_prompt_transformed,
|
|
352
353
|
"sessionStart" => hooks.on_session_start,
|
|
353
354
|
"sessionEnd" => hooks.on_session_end,
|
|
354
355
|
"errorOccurred" => hooks.on_error_occurred,
|
data/lib/copilot/types.rb
CHANGED
|
@@ -553,11 +553,13 @@ module Copilot
|
|
|
553
553
|
# Hook configuration for a session. Each value is a callable or nil.
|
|
554
554
|
SessionHooks = Struct.new(
|
|
555
555
|
:on_pre_tool_use, :on_post_tool_use, :on_user_prompt_submitted,
|
|
556
|
+
:on_user_prompt_transformed,
|
|
556
557
|
:on_session_start, :on_session_end, :on_error_occurred,
|
|
557
558
|
keyword_init: true
|
|
558
559
|
) do
|
|
559
560
|
def any_handler?
|
|
560
561
|
[on_pre_tool_use, on_post_tool_use, on_user_prompt_submitted,
|
|
562
|
+
on_user_prompt_transformed,
|
|
561
563
|
on_session_start, on_session_end, on_error_occurred].any?
|
|
562
564
|
end
|
|
563
565
|
end
|
|
@@ -597,6 +599,7 @@ module Copilot
|
|
|
597
599
|
:session_fs,
|
|
598
600
|
:copilot_home, :tcp_connection_token,
|
|
599
601
|
:request_handler,
|
|
602
|
+
:on_get_trace_context,
|
|
600
603
|
keyword_init: true
|
|
601
604
|
)
|
|
602
605
|
|
data/lib/copilot/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: copilot-sdk-supercharged
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 2.
|
|
4
|
+
version: 2.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jeremiah Isaacson
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-08-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
A Ruby SDK for interacting with the GitHub Copilot CLI server via JSON-RPC 2.0.
|