riffer-rig 0.8.0 → 0.9.0

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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +22 -0
  3. data/README.md +11 -2
  4. data/lib/riffer/rig/cli/flags.rb +16 -2
  5. data/lib/riffer/rig/cli.rb +2 -1
  6. data/lib/riffer/rig/commands/auth.rb +79 -0
  7. data/lib/riffer/rig/commands/model.rb +70 -21
  8. data/lib/riffer/rig/commands/reload.rb +23 -0
  9. data/lib/riffer/rig/credentials.rb +13 -1
  10. data/lib/riffer/rig/extension.rb +12 -0
  11. data/lib/riffer/rig/loader.rb +258 -31
  12. data/lib/riffer/rig/provider_setup.rb +36 -5
  13. data/lib/riffer/rig/providers.rb +48 -0
  14. data/lib/riffer/rig/registrar.rb +8 -0
  15. data/lib/riffer/rig/runtime.rb +110 -21
  16. data/lib/riffer/rig/sdk.rb +62 -0
  17. data/lib/riffer/rig/settings/document.rb +7 -1
  18. data/lib/riffer/rig/settings.rb +5 -4
  19. data/lib/riffer/rig/stores/jsonl.rb +115 -0
  20. data/lib/riffer/rig/stores/recorder.rb +119 -0
  21. data/lib/riffer/rig/version.rb +1 -1
  22. data/lib/riffer/rig.rb +7 -1
  23. data/sig/generated/riffer/rig/cli/flags.rbs +5 -2
  24. data/sig/generated/riffer/rig/commands/auth.rbs +35 -0
  25. data/sig/generated/riffer/rig/commands/model.rbs +21 -9
  26. data/sig/generated/riffer/rig/commands/reload.rbs +12 -0
  27. data/sig/generated/riffer/rig/credentials.rbs +8 -0
  28. data/sig/generated/riffer/rig/extension.rbs +4 -0
  29. data/sig/generated/riffer/rig/loader.rbs +108 -7
  30. data/sig/generated/riffer/rig/provider_setup.rbs +15 -4
  31. data/sig/generated/riffer/rig/providers.rbs +28 -0
  32. data/sig/generated/riffer/rig/registrar.rbs +6 -0
  33. data/sig/generated/riffer/rig/runtime.rbs +63 -9
  34. data/sig/generated/riffer/rig/sdk.rbs +33 -0
  35. data/sig/generated/riffer/rig/settings/document.rbs +5 -1
  36. data/sig/generated/riffer/rig/settings.rbs +2 -3
  37. data/sig/generated/riffer/rig/stores/jsonl.rbs +64 -0
  38. data/sig/generated/riffer/rig/stores/recorder.rbs +67 -0
  39. data/sig/generated/riffer/rig.rbs +4 -0
  40. data/sig/manual/riffer/rig/commands/auth.rbs +6 -0
  41. data/sig/manual/riffer/rig/commands/reload.rbs +6 -0
  42. data/sig/manual/riffer/rig/providers.rbs +6 -0
  43. data/sig/manual/riffer/rig/sdk.rbs +6 -0
  44. data/sig/manual/riffer/rig/stores.rbs +11 -0
  45. metadata +18 -29
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9d560ab0c2be62a87e8468ba302f443985cd5d92d4872de2073c5c77b672d83f
4
- data.tar.gz: b75fe6a3d1a7f0c718405f619f2f56c20fe85282ddb94aff9c2beb853344c119
3
+ metadata.gz: d49bc7e8176b7eec0bc8cc2249bc39668f9637557db92bdd34c1f4baf9ee7ce0
4
+ data.tar.gz: c9d563f1ff2de6cbece63dc6735107537bc33fd1b8cefde8541e7e2fc3262f3a
5
5
  SHA512:
6
- metadata.gz: a2ca46037680a034a31b977101a9c5b442fc21f56842cb3055f2163493d42eef2d92ccdbc53aa9bf5fd2749af6fcfd52fb6d74aecbea0da907a5bac3ecee7498
7
- data.tar.gz: 4e531d3fee7fa1107e7d6a7c5d1fa064c4bbdf9e46763353332d4b9d9b57b6a37436d54326fe06e21248c147d99e15ddaac4a18b6ee8ffd34be4e29d733444ae
6
+ metadata.gz: 7b89243587acc30185f2a0f16ebc5adfb43c860f537ec5f1cab6b7fae116322109f74f49b6e990c7d4d0b48dab1a8db3ec61f804c84b69bb06f3fa14cba2f0d7
7
+ data.tar.gz: cdb0fdd4d2354fd7ed1625c022e6f0fff02f2a34b3f37babfdf1a443a57427e45bb88fab58edf07cd3cfc9e1ef14ad492589ca847df7ff9339c0695728d21290
data/CHANGELOG.md CHANGED
@@ -1,5 +1,27 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.9.0](https://github.com/bottrall/riffer-rig/compare/v0.8.0...v0.9.0) (2026-10-04)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * optional provider SDKs and the missing-SDK flow ([#211](https://github.com/bottrall/riffer-rig/issues/211))
9
+
10
+ ### Features
11
+
12
+ * /auth lists, re-runs and removes provider credentials ([#213](https://github.com/bottrall/riffer-rig/issues/213)) ([ce17f15](https://github.com/bottrall/riffer-rig/commit/ce17f15286f5bc776775e1cbff4fb6db673379f7))
13
+ * /model --save and provider switching through the Loader ([#214](https://github.com/bottrall/riffer-rig/issues/214)) ([f033caa](https://github.com/bottrall/riffer-rig/commit/f033caa6fc4b02b8a4429174f7d5256e4e7ece5b))
14
+ * extension providers with a setup on the provider seam ([#216](https://github.com/bottrall/riffer-rig/issues/216)) ([f24f632](https://github.com/bottrall/riffer-rig/commit/f24f632f7f6a1a9903e1bdd0985076a1d03f12d3))
15
+ * JSONL session store appends every Loader-built Runtime ([#219](https://github.com/bottrall/riffer-rig/issues/219)) ([67c5e80](https://github.com/bottrall/riffer-rig/commit/67c5e80efcea07b421b2c8512e576593d7a826d3))
16
+ * optional provider SDKs and the missing-SDK flow ([#211](https://github.com/bottrall/riffer-rig/issues/211)) ([334c94b](https://github.com/bottrall/riffer-rig/commit/334c94bc4954f87846ead17a936690a40d847c75)), closes [#127](https://github.com/bottrall/riffer-rig/issues/127)
17
+ * provider-native tools switched on in settings ([#217](https://github.com/bottrall/riffer-rig/issues/217)) ([6ba2a6a](https://github.com/bottrall/riffer-rig/commit/6ba2a6ad7ca0885af3e5c853786a0f3e22e0373a))
18
+ * reload tracked files with /reload ([#218](https://github.com/bottrall/riffer-rig/issues/218)) ([403de96](https://github.com/bottrall/riffer-rig/commit/403de9645afd91082551a966d04cc18beeb8f194)), closes [#132](https://github.com/bottrall/riffer-rig/issues/132)
19
+
20
+
21
+ ### Bug Fixes
22
+
23
+ * bundle provider SDKs for the checkout's bundler/setup ([#215](https://github.com/bottrall/riffer-rig/issues/215)) ([f0cc9e6](https://github.com/bottrall/riffer-rig/commit/f0cc9e6afcf82d1f006ab09679a4be38be846af2))
24
+
3
25
  ## [0.8.0](https://github.com/bottrall/riffer-rig/compare/v0.7.0...v0.8.0) (2026-10-02)
4
26
 
5
27
 
data/README.md CHANGED
@@ -16,7 +16,13 @@ Install the gem:
16
16
  gem install riffer-rig
17
17
  ```
18
18
 
19
- This provides a `riffer` executable.
19
+ This provides a `riffer` executable. No provider SDK is installed with it: `gemini/…` models work out of the box, and every other provider's SDK gem is either installed on its first use — `riffer-rig` asks, then installs it in-process — or added to a Gemfile ahead of time:
20
+
21
+ ```ruby
22
+ gem 'anthropic', '~> 1.69'
23
+ ```
24
+
25
+ [Providers](docs/PROVIDERS.md#sdk-gems) lists each provider's gem and how the install offer works.
20
26
 
21
27
  ## Usage
22
28
 
@@ -40,6 +46,7 @@ The model is the first of these that is set: `--model`, `RIFFER_MODEL`, `model`
40
46
  | `--no-agents-md` | leaves out the [AGENTS.md](docs/INSTRUCTIONS.md#agentsmd) instructions |
41
47
  | `--tools read,bash` | only these tools, by identifier ([Tools](docs/TOOLS.md)) |
42
48
  | `--max-steps N` | stops a turn after `N` model calls |
49
+ | `--no-save` | does not save this session to the [store](docs/SESSIONS.md) |
43
50
  | `-h`, `--help` | prints the usage |
44
51
 
45
52
  `riffer -p` (one prompt, no terminal) and `riffer acp` (an editor's agent over stdio) are reserved: for now each prints the usage and exits with status 2.
@@ -82,9 +89,11 @@ Each value resolves on its own: environment variable first, then the stored valu
82
89
 
83
90
  The flat `{"anthropic": "sk-…"}` shape earlier versions wrote is no longer read; paste the key again when prompted. [Providers](docs/PROVIDERS.md) has the full format.
84
91
 
92
+ Inside a session, `/auth` lists every provider with where its secret comes from — `env`, `stored`, `chain` (the SDK's own credential chain, for Bedrock) or `missing`. `/auth <provider>` re-runs that provider's setup, which is how you rotate a key, and applies the new values to the current session, so the next request uses them. `/auth remove <provider>` deletes the provider's `auth.json` entry and its `providers` block in settings.
93
+
85
94
  ### Switching the model
86
95
 
87
- `/model provider/name` switches the model for the current session only, keeping the conversation so far — `/model openai/gpt-5`, say. The provider prefix is required: a bare name such as `/model sonnet` is rejected with the list of providers. `/model` alone shows the model in use. The switch is refused when the session has no credentials for the new provider, and it never changes `settings.json`; set `model` there to change the model new sessions start with ([Configuration](docs/CONFIGURATION.md#model)).
96
+ `/model provider/name` switches the model for the current session only, keeping the conversation so far — `/model openai/gpt-5`, say. The provider prefix is required: a bare name such as `/model sonnet` is rejected with the list of providers. `/model` alone shows the model in use. Switching runs the same setup for the new provider as startup does: its SDK gem is offered for install (or refused with the exact Gemfile line), and missing credentials are resolved — you are prompted for them when the host can ask, and the values apply to the running session immediately. The switch is refused with one error when the host cannot supply what is missing, and the model is left unchanged. `/model --save` writes the model in effect to the home `settings.json`, so new sessions start with it; `/model provider/name --save` switches and saves in one step, and a refused switch saves nothing ([Configuration](docs/CONFIGURATION.md#model)).
88
97
 
89
98
  ### Configuration
90
99
 
@@ -9,11 +9,12 @@ class Riffer::Rig::CLI::Flags
9
9
  riffer acp (not available yet)
10
10
  TEXT
11
11
 
12
- # @dynamic model, extensions, skills, agents_md, tools, max_steps, help
12
+ # @dynamic model, extensions, skills, agents_md, tools, max_steps, help, save
13
13
  attr_reader :model #: String?
14
14
  attr_reader :extensions, :skills, :agents_md, :help #: bool
15
15
  attr_reader :tools #: Array[String]?
16
16
  attr_reader :max_steps #: Integer?
17
+ attr_reader :save #: bool
17
18
 
18
19
  # @rbs argv: Array[String]
19
20
  # @rbs return: Riffer::Rig::CLI::Flags | String
@@ -29,6 +30,7 @@ class Riffer::Rig::CLI::Flags
29
30
  agents_md: !values.key?(:'no-agents-md'),
30
31
  tools: values[:tools],
31
32
  max_steps: values[:'max-steps'],
33
+ save: !values.key?(:'no-save'),
32
34
  help: values.key?(:help)
33
35
  )
34
36
  rescue OptionParser::ParseError => e
@@ -51,6 +53,7 @@ class Riffer::Rig::CLI::Flags
51
53
  parser.on('--no-agents-md', 'Leave out AGENTS.md instructions')
52
54
  parser.on('--tools NAME,NAME', Array, 'Only these tools, by identifier')
53
55
  parser.on('--max-steps N', Integer, 'Stop a turn after N model calls')
56
+ parser.on('--no-save', 'Do not save this session')
54
57
  parser.on('-h', '--help', 'Show this help')
55
58
  end
56
59
  end
@@ -62,15 +65,26 @@ class Riffer::Rig::CLI::Flags
62
65
  # @rbs agents_md: bool
63
66
  # @rbs tools: Array[String]?
64
67
  # @rbs max_steps: Integer?
68
+ # @rbs save: bool
65
69
  # @rbs help: bool
66
70
  # @rbs return: void
67
- def initialize(model: nil, extensions: true, skills: true, agents_md: true, tools: nil, max_steps: nil, help: false)
71
+ def initialize(
72
+ model: nil,
73
+ extensions: true,
74
+ skills: true,
75
+ agents_md: true,
76
+ tools: nil,
77
+ max_steps: nil,
78
+ save: true,
79
+ help: false
80
+ )
68
81
  @model = model
69
82
  @extensions = extensions
70
83
  @skills = skills
71
84
  @agents_md = agents_md
72
85
  @tools = tools&.freeze
73
86
  @max_steps = max_steps
87
+ @save = save
74
88
  @help = help
75
89
  freeze
76
90
  end
@@ -62,7 +62,8 @@ module Riffer::Rig::CLI
62
62
  skills: flags.skills,
63
63
  agents_md: flags.agents_md,
64
64
  tools: flags.tools,
65
- max_steps: flags.max_steps
65
+ max_steps: flags.max_steps,
66
+ store: flags.save ? Riffer::Rig::Stores::JSONL.new : nil
66
67
  )
67
68
  end
68
69
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riffer::Rig::Commands::Auth
4
+ extend self
5
+
6
+ USAGE = 'Use /auth, /auth <provider> or /auth remove <provider>' #: String
7
+
8
+ # @rbs return: Riffer::Rig::Command
9
+ def command
10
+ Riffer::Rig::Command.new(
11
+ 'auth',
12
+ description: 'Show, re-run or remove provider credentials',
13
+ extension: 'core'
14
+ ) { |ctx| run(ctx) }
15
+ end
16
+
17
+ # @rbs ctx: Riffer::Rig::Command::Context
18
+ # @rbs return: void
19
+ def run(ctx)
20
+ words = ctx.args.split
21
+ return ctx.say(list) if words.empty?
22
+ return remove(ctx, words[1]) if words[0] == 'remove' && words.length == 2
23
+ return rerun(ctx, words[0]) if words.length == 1
24
+
25
+ ctx.say(USAGE)
26
+ end
27
+
28
+ private
29
+
30
+ # @rbs return: String
31
+ def hint
32
+ 'Use /auth <provider> or /auth remove <provider>, with a provider from: ' \
33
+ "#{Riffer::Rig::Settings.providers.join(', ')}"
34
+ end
35
+
36
+ # @rbs return: String
37
+ def list
38
+ statuses = Riffer::Rig::Settings.providers.to_h do |identifier|
39
+ [identifier, Riffer::Rig::Credentials.status(identifier)]
40
+ end
41
+ width = statuses.keys.map { |identifier| identifier.to_s.length }.max || 0
42
+ statuses.map { |identifier, status| "#{identifier.to_s.ljust(width)} #{status}" }.join("\n")
43
+ end
44
+
45
+ # @rbs ctx: Riffer::Rig::Command::Context
46
+ # @rbs identifier: String
47
+ # @rbs return: void
48
+ def rerun(ctx, identifier)
49
+ return ctx.say(hint) unless Riffer::Providers::Repository.find(identifier)
50
+
51
+ provider = identifier.to_sym
52
+ resolution = Riffer::Rig::Credentials.resolve(provider, host: ctx.host)
53
+ Riffer::Rig::Credentials.apply(provider, resolution.values)
54
+ ctx.runtime.merge_credentials(provider, resolution.values)
55
+ return ctx.host.notify(refusal(provider, resolution.missing), level: :error) unless resolution.missing.empty?
56
+
57
+ ctx.say("Updated #{provider} credentials")
58
+ end
59
+
60
+ # @rbs ctx: Riffer::Rig::Command::Context
61
+ # @rbs identifier: String
62
+ # @rbs return: void
63
+ def remove(ctx, identifier)
64
+ return ctx.say(hint) unless Riffer::Providers::Repository.find(identifier)
65
+
66
+ Riffer::Rig::Credentials.remove(identifier)
67
+ ctx.say("Removed stored #{identifier} credentials")
68
+ end
69
+
70
+ # @rbs provider: Symbol
71
+ # @rbs missing: Array[Symbol]
72
+ # @rbs return: String
73
+ def refusal(provider, missing)
74
+ setup = Riffer::Rig::ProviderSetup.for(provider)
75
+ fields = setup.fields.select { |field| missing.include?(field.name) }
76
+ wanted = fields.map { |field| "#{field.name} (#{field.env.join(' or ')})" }.join(', ')
77
+ "#{provider} still has no #{wanted}"
78
+ end
79
+ end
@@ -3,16 +3,13 @@
3
3
  module Riffer::Rig::Commands::Model
4
4
  extend self
5
5
 
6
- HINT = 'Use /model provider/name, with a provider from: ' \
7
- "#{Riffer::Rig::Settings::PROVIDERS.join(', ')}".freeze #: String
8
-
9
- SAVE_UNAVAILABLE = '/model --save is not available in this host'
6
+ SAVE = '--save' #: String
10
7
 
11
8
  # @rbs return: Riffer::Rig::Command
12
9
  def command
13
10
  Riffer::Rig::Command.new(
14
11
  'model',
15
- description: 'Switch the model for this session: /model provider/name',
12
+ description: 'Switch the model for this session: /model provider/name, /model --save',
16
13
  extension: 'core'
17
14
  ) { |ctx| run(ctx) }
18
15
  end
@@ -20,35 +17,87 @@ module Riffer::Rig::Commands::Model
20
17
  # @rbs ctx: Riffer::Rig::Command::Context
21
18
  # @rbs return: void
22
19
  def run(ctx)
23
- model = ctx.args.strip
24
- return ctx.host.notify(SAVE_UNAVAILABLE, level: :error) if model.split.include?('--save')
25
- return ctx.say("Model: #{ctx.runtime.model}") if model.empty?
20
+ words = ctx.args.split
21
+ save = words.delete(SAVE)
22
+ model = words.join(' ')
26
23
 
27
- provider = Riffer::Rig::Settings.provider_for(model)
28
- return ctx.say(HINT) unless provider && Riffer::Providers::Repository.find(provider)
24
+ if model.empty?
25
+ return ctx.say("Model: #{ctx.runtime.model}") unless save
26
+
27
+ Riffer::Rig::Settings.store_model(ctx.runtime.model)
28
+ return ctx.say("Saved #{ctx.runtime.model} to settings")
29
+ end
29
30
 
30
- missing = missing_credentials(provider, ctx.runtime.credentials)
31
- return ctx.host.notify(refusal(model, provider, missing), level: :error) unless missing.empty?
31
+ provider = Riffer::Rig::Settings.provider_for(model)
32
+ return ctx.say(hint) unless provider && Riffer::Providers::Repository.find(provider)
33
+ return unless ready?(ctx, model, provider)
32
34
 
33
35
  ctx.runtime.model = model
36
+ Riffer::Rig::Settings.store_model(model) if save
34
37
  ctx.say("Model: #{model}")
35
38
  end
36
39
 
37
40
  private
38
41
 
42
+ # @rbs return: String
43
+ def hint
44
+ "Use /model provider/name, with a provider from: #{Riffer::Rig::Settings.providers.join(', ')}"
45
+ end
46
+
47
+ # The same setup flows the Loader runs when it builds a Runtime: the
48
+ # provider's SDK gem, then its credentials, asked for when the host can ask.
49
+ # @rbs ctx: Riffer::Rig::Command::Context
39
50
  # @rbs model: String
40
51
  # @rbs provider: String
41
- # @rbs missing: Array[Symbol]
42
- # @rbs return: String
43
- def refusal(model, provider, missing)
44
- "Not switching to #{model}: #{provider} has no #{missing.join(', ')} in credentials"
52
+ # @rbs return: bool
53
+ def ready?(ctx, model, provider)
54
+ setup = Riffer::Rig::ProviderSetup[provider]
55
+ return true unless setup
56
+
57
+ sdk = setup.sdk
58
+ if sdk
59
+ message = Riffer::Rig::SDK.ensure(sdk[0], sdk[1], host: ctx.host)
60
+ if message
61
+ ctx.host.notify(message, level: :error)
62
+ return false
63
+ end
64
+ end
65
+
66
+ credentials_ready?(ctx, model, provider, setup)
45
67
  end
46
68
 
69
+ # @rbs ctx: Riffer::Rig::Command::Context
70
+ # @rbs model: String
47
71
  # @rbs provider: String
48
- # @rbs credentials: Hash[Symbol, Hash[Symbol, String]]
49
- # @rbs return: Array[Symbol]
50
- def missing_credentials(provider, credentials)
51
- required = Riffer::Rig::ProviderSetup[provider]&.fields&.select(&:required) || []
52
- required.map(&:name).reject { |name| credentials.dig(provider.to_sym, name) }
72
+ # @rbs setup: Riffer::Rig::ProviderSetup
73
+ # @rbs return: bool
74
+ def credentials_ready?(ctx, model, provider, setup)
75
+ missing = setup.fields.select(&:required)
76
+ .map(&:name)
77
+ .reject { |name| ctx.runtime.credentials.dig(provider.to_sym, name) }
78
+ return true if missing.empty?
79
+
80
+ resolution = Riffer::Rig::Credentials.resolve(provider, host: ctx.host)
81
+ unfilled = missing & resolution.missing
82
+ if unfilled.empty?
83
+ Riffer::Rig::Credentials.apply(provider, resolution.values)
84
+ empty = {} #: Hash[Symbol, String]
85
+ values = ctx.runtime.credentials.fetch(provider.to_sym, empty).merge(resolution.values)
86
+ ctx.runtime.merge_credentials(provider.to_sym, values)
87
+ true
88
+ else
89
+ refuse(ctx, model, provider, unfilled)
90
+ false
91
+ end
92
+ end
93
+
94
+ # @rbs ctx: Riffer::Rig::Command::Context
95
+ # @rbs model: String
96
+ # @rbs provider: String
97
+ # @rbs missing: Array[Symbol]
98
+ # @rbs return: void
99
+ def refuse(ctx, model, provider, missing)
100
+ wanted = Riffer::Rig::ProviderSetup.for(provider).missing_fields(missing)
101
+ ctx.host.notify("Not switching to #{model}: #{provider} has no #{wanted}", level: :error)
53
102
  end
54
103
  end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Riffer::Rig::Commands::Reload
4
+ extend self
5
+
6
+ # @rbs loader: Riffer::Rig::Loader
7
+ # @rbs return: Riffer::Rig::Command
8
+ def command(loader)
9
+ Riffer::Rig::Command.new(
10
+ 'reload',
11
+ description: 'Reload the rig.rb files, settings, credentials and trust',
12
+ extension: 'core'
13
+ ) { |ctx| run(loader, ctx) }
14
+ end
15
+
16
+ # @rbs loader: Riffer::Rig::Loader
17
+ # @rbs ctx: Riffer::Rig::Command::Context
18
+ # @rbs return: void
19
+ def run(loader, ctx)
20
+ reloaded = loader.reload(ctx.runtime, force: true)
21
+ ctx.say('Reloaded') if reloaded.is_a?(Riffer::Rig::Runtime)
22
+ end
23
+ end
@@ -11,6 +11,9 @@ module Riffer::Rig::Credentials
11
11
 
12
12
  ENTRY_TYPE = 'api_key'
13
13
 
14
+ # @rbs @applied: Hash[Symbol, Hash[Symbol, String]]
15
+ @applied = {} #: Hash[Symbol, Hash[Symbol, String]]
16
+
14
17
  # @rbs identifier: String | Symbol
15
18
  # @rbs host: Riffer::Rig::Hosts::_Host
16
19
  # @rbs setup: Riffer::Rig::ProviderSetup
@@ -39,17 +42,26 @@ module Riffer::Rig::Credentials
39
42
  Resolution.new(values:, missing: required.map(&:name) - values.keys)
40
43
  end
41
44
 
45
+ # A registered extension provider has no Riffer::Config member, so the
46
+ # assignment stays built-ins-only.
42
47
  # @rbs identifier: String | Symbol
43
48
  # @rbs values: Hash[Symbol, String]
44
49
  # @rbs config: Riffer::Config
45
50
  # @rbs return: void
46
51
  def apply(identifier, values, config: Riffer.config)
47
- return unless Riffer::Rig::ProviderSetup[identifier]
52
+ @applied[identifier.to_sym] = values.dup.freeze
53
+ return unless Riffer::Rig::ProviderSetup::TABLE.key?(identifier.to_sym)
48
54
 
49
55
  provider_config = config.public_send(identifier)
50
56
  values.each { |name, value| provider_config.public_send(:"#{name}=", value) }
51
57
  end
52
58
 
59
+ # @rbs identifier: String | Symbol
60
+ # @rbs return: Hash[Symbol, String]?
61
+ def read(identifier)
62
+ @applied[identifier.to_sym]
63
+ end
64
+
53
65
  # @rbs identifier: String | Symbol
54
66
  # @rbs values: Hash[Symbol, String]
55
67
  # @rbs setup: Riffer::Rig::ProviderSetup
@@ -30,6 +30,18 @@ class Riffer::Rig::Extension
30
30
  @block.call(registrar)
31
31
  end
32
32
 
33
+ # @rbs registrar: Riffer::Rig::Registrar
34
+ # @rbs return: StandardError?
35
+ def load_into(registrar)
36
+ rejection = mismatch || registrar.collision
37
+ return rejection if rejection
38
+
39
+ run(registrar)
40
+ nil
41
+ rescue StandardError => e
42
+ e
43
+ end
44
+
33
45
  private
34
46
 
35
47
  # @rbs requirement: Gem::Requirement?