ruby_coded 0.2.0 → 0.2.2
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/.rubocop_todo.yml +3 -1
- data/CHANGELOG.md +20 -4
- data/lib/ruby_coded/auth/auth_manager.rb +20 -2
- data/lib/ruby_coded/auth/credentials_store.rb +2 -2
- data/lib/ruby_coded/chat/app.rb +20 -3
- data/lib/ruby_coded/initializer.rb +14 -3
- data/lib/ruby_coded/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: a1980b8f52a5fefcd383aec24380904430c10654b4cffe7bef6288b1b55e1eed
|
|
4
|
+
data.tar.gz: 1e54670c24db8f43ce9a0e4391889adf3d2d1c75f0923d43ff3260bc210e2e96
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c4d75ef0c6c7d0b3d1da17287b08bbdec2d9ee29bcc12c8551409ae2dbf2276562a10fc96294a9685b55a41f36d4711e448a640e97bb2711a9da9e0b1231e5ad
|
|
7
|
+
data.tar.gz: 75d2f43c84b9c8d027d17ac6d61b2f250fef6ce2dca88463b3ab580f74927bb16933b5a6f96eb7fed6b26e5138c621e9df8b56435f364dcbe3173c72f3a10114
|
data/.rubocop_todo.yml
CHANGED
|
@@ -55,10 +55,12 @@ Metrics/AbcSize:
|
|
|
55
55
|
Exclude:
|
|
56
56
|
- 'lib/ruby_coded/chat/state.rb'
|
|
57
57
|
|
|
58
|
-
# Offense count:
|
|
58
|
+
# Offense count: 3
|
|
59
59
|
# Configuration parameters: CountComments, Max, CountAsOne.
|
|
60
60
|
Metrics/ClassLength:
|
|
61
61
|
Exclude:
|
|
62
|
+
- 'lib/ruby_coded/auth/auth_manager.rb'
|
|
63
|
+
- 'lib/ruby_coded/chat/app.rb'
|
|
62
64
|
- 'lib/ruby_coded/chat/state.rb'
|
|
63
65
|
|
|
64
66
|
# Offense count: 2
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.2.2] - 2026-04-17
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **OAuth credentials lost after in-TUI login**: When logging in to OpenAI via OAuth from within the chat (`/login`) while already authenticated with another provider (e.g. Anthropic) and using a non-Codex model, the freshly stored OAuth credentials were wiped from `~/.ruby_coded/config.yaml`. The root cause was two `UserConfig` instances holding independent in-memory copies of the config; when `ensure_valid_codex_model!` called `@user_config.set_config("model", "gpt-5.4")`, the stale hash (loaded before the OAuth login) was serialized back to disk, overwriting the OAuth credentials written moments earlier by `CredentialsStore`. Fixed by threading a single shared `UserConfig` through `Initializer`, `AuthManager`, `CredentialsStore` and `Chat::App`.
|
|
8
|
+
|
|
9
|
+
## [0.2.1] - 2026-04-17
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Startup crash when stored model provider is not authenticated**: The CLI no longer raises `RubyLLM::ConfigurationError` at startup when the model saved in `~/.ruby_coded/config.yaml` belongs to a provider that has no credentials on the current machine (e.g. switching computers with only Anthropic authenticated but a GPT model stored). Instead, the app falls back to the default model of the authenticated provider and shows an in-chat system message suggesting `/login` or `/model` to adjust.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- `AuthManager#provider_for_model` and `AuthManager#model_provider_authenticated?` helpers to detect the provider of a given model name and validate that its credentials are available.
|
|
18
|
+
|
|
3
19
|
## [0.2.0] - 2026-04-16
|
|
4
20
|
|
|
5
21
|
### Added
|
|
@@ -19,10 +35,10 @@
|
|
|
19
35
|
- AuthManager skips OpenAI OAuth credentials for RubyLLM configuration (handled by CodexBridge)
|
|
20
36
|
- Default OpenAI model updated to `gpt-5.4`
|
|
21
37
|
|
|
22
|
-
## [0.1.0] - 2026-04-15
|
|
23
|
-
|
|
24
|
-
- Initial release
|
|
25
|
-
|
|
26
38
|
## [0.1.1] - 2026-04-15
|
|
27
39
|
|
|
28
40
|
- Fix CI workflow
|
|
41
|
+
|
|
42
|
+
## [0.1.0] - 2026-04-15
|
|
43
|
+
|
|
44
|
+
- Initial release
|
|
@@ -21,8 +21,9 @@ module RubyCoded
|
|
|
21
21
|
anthropic: Providers::Anthropic
|
|
22
22
|
}.freeze
|
|
23
23
|
|
|
24
|
-
def initialize(config_path: UserConfig::CONFIG_PATH)
|
|
24
|
+
def initialize(config_path: UserConfig::CONFIG_PATH, user_config: nil)
|
|
25
25
|
@config_path = config_path
|
|
26
|
+
@user_config = user_config
|
|
26
27
|
end
|
|
27
28
|
|
|
28
29
|
def login(provider_name)
|
|
@@ -48,6 +49,23 @@ module RubyCoded
|
|
|
48
49
|
PROVIDERS.keys.select { |name| credential_store.retrieve(name) }
|
|
49
50
|
end
|
|
50
51
|
|
|
52
|
+
def provider_for_model(model_name)
|
|
53
|
+
return nil if model_name.nil? || model_name.to_s.strip.empty?
|
|
54
|
+
|
|
55
|
+
normalized = model_name.to_s.downcase
|
|
56
|
+
return :openai if normalized.match?(/\A(gpt|o\d)/)
|
|
57
|
+
return :anthropic if normalized.start_with?("claude")
|
|
58
|
+
|
|
59
|
+
nil
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def model_provider_authenticated?(model_name)
|
|
63
|
+
provider = provider_for_model(model_name)
|
|
64
|
+
return false unless provider
|
|
65
|
+
|
|
66
|
+
authenticated_provider_names.include?(provider)
|
|
67
|
+
end
|
|
68
|
+
|
|
51
69
|
def check_authentication
|
|
52
70
|
return if configured_providers.any? { |name| credential_store.retrieve(name) }
|
|
53
71
|
|
|
@@ -96,7 +114,7 @@ module RubyCoded
|
|
|
96
114
|
end
|
|
97
115
|
|
|
98
116
|
def credential_store
|
|
99
|
-
@credential_store ||= CredentialsStore.new(config_path: @config_path)
|
|
117
|
+
@credential_store ||= CredentialsStore.new(config_path: @config_path, user_config: @user_config)
|
|
100
118
|
end
|
|
101
119
|
|
|
102
120
|
def extract_api_key(credentials)
|
|
@@ -8,8 +8,8 @@ module RubyCoded
|
|
|
8
8
|
module Auth
|
|
9
9
|
# This class is used to manage the credentials in the config file
|
|
10
10
|
class CredentialsStore
|
|
11
|
-
def initialize(config_path: UserConfig::CONFIG_PATH)
|
|
12
|
-
@config = UserConfig.new(config_path: config_path)
|
|
11
|
+
def initialize(config_path: UserConfig::CONFIG_PATH, user_config: nil)
|
|
12
|
+
@config = user_config || UserConfig.new(config_path: config_path)
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
def store(provider_name, credentials)
|
data/lib/ruby_coded/chat/app.rb
CHANGED
|
@@ -29,13 +29,19 @@ module RubyCoded
|
|
|
29
29
|
include LoginHandler
|
|
30
30
|
include OAuthHandler
|
|
31
31
|
|
|
32
|
-
def initialize(model:, user_config: nil, auth_manager: nil)
|
|
32
|
+
def initialize(model:, user_config: nil, auth_manager: nil, fallback_from_model: nil)
|
|
33
33
|
@model = model
|
|
34
34
|
@user_config = user_config
|
|
35
35
|
@auth_manager = auth_manager
|
|
36
|
+
@fallback_from_model = fallback_from_model
|
|
36
37
|
apply_plugin_extensions!
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
build_components!
|
|
39
|
+
announce_model_fallback
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def build_components!
|
|
43
|
+
@state = State.new(model: @model)
|
|
44
|
+
@credentials_store = Auth::CredentialsStore.new(user_config: @user_config)
|
|
39
45
|
@llm_bridge = create_bridge
|
|
40
46
|
@input_handler = InputHandler.new(@state)
|
|
41
47
|
@command_handler = build_command_handler
|
|
@@ -94,6 +100,17 @@ module RubyCoded
|
|
|
94
100
|
credentials_store: @credentials_store, auth_manager: @auth_manager)
|
|
95
101
|
end
|
|
96
102
|
|
|
103
|
+
def announce_model_fallback
|
|
104
|
+
return unless @fallback_from_model && !@fallback_from_model.to_s.strip.empty?
|
|
105
|
+
return if @fallback_from_model == @model
|
|
106
|
+
|
|
107
|
+
@state.add_message(
|
|
108
|
+
:system,
|
|
109
|
+
"Model #{@fallback_from_model} is not available (provider not authenticated). " \
|
|
110
|
+
"Switched to #{@model}. Use /login to authenticate or /model to change."
|
|
111
|
+
)
|
|
112
|
+
end
|
|
113
|
+
|
|
97
114
|
def apply_selected_model
|
|
98
115
|
selected = @state.selected_model
|
|
99
116
|
return @state.exit_model_select! unless selected
|
|
@@ -19,7 +19,8 @@ module RubyCoded
|
|
|
19
19
|
def initialize
|
|
20
20
|
@user_cfg = UserConfig.new
|
|
21
21
|
@prompt = TTY::Prompt.new
|
|
22
|
-
@auth_manager = Auth::AuthManager.new
|
|
22
|
+
@auth_manager = Auth::AuthManager.new(user_config: @user_cfg)
|
|
23
|
+
@fallback_from_model = nil
|
|
23
24
|
|
|
24
25
|
ask_for_directory_permission unless @user_cfg.directory_trusted?
|
|
25
26
|
@auth_manager.check_authentication
|
|
@@ -38,12 +39,22 @@ module RubyCoded
|
|
|
38
39
|
end
|
|
39
40
|
|
|
40
41
|
def start_chat
|
|
41
|
-
|
|
42
|
+
model = resolved_chat_model
|
|
43
|
+
Chat::App.new(
|
|
44
|
+
model: model,
|
|
45
|
+
user_config: @user_cfg,
|
|
46
|
+
auth_manager: @auth_manager,
|
|
47
|
+
fallback_from_model: @fallback_from_model
|
|
48
|
+
).run
|
|
42
49
|
end
|
|
43
50
|
|
|
44
51
|
def resolved_chat_model
|
|
45
52
|
stored = @user_cfg.get_config("model")
|
|
46
|
-
|
|
53
|
+
if stored && !stored.to_s.strip.empty?
|
|
54
|
+
return stored.to_s if @auth_manager.model_provider_authenticated?(stored.to_s)
|
|
55
|
+
|
|
56
|
+
@fallback_from_model = stored.to_s
|
|
57
|
+
end
|
|
47
58
|
|
|
48
59
|
provider = @auth_manager.authenticated_provider_names.first
|
|
49
60
|
PROVIDER_DEFAULT_MODELS.fetch(provider, RubyLLM.config.default_model).to_s
|
data/lib/ruby_coded/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ruby_coded
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2.
|
|
4
|
+
version: 0.2.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Cesar Rodriguez
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-04-
|
|
11
|
+
date: 2026-04-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|