riffer-rig 0.4.0 → 0.6.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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +37 -0
  3. data/README.md +43 -6
  4. data/lib/riffer/rig/cli.rb +51 -47
  5. data/lib/riffer/rig/coding_agent.rb +1 -6
  6. data/lib/riffer/rig/credentials/resolution.rb +16 -0
  7. data/lib/riffer/rig/credentials.rb +151 -60
  8. data/lib/riffer/rig/env.rb +29 -0
  9. data/lib/riffer/rig/events/command_output.rb +27 -0
  10. data/lib/riffer/rig/events/event.rb +30 -0
  11. data/lib/riffer/rig/events/notify.rb +27 -0
  12. data/lib/riffer/rig/events/session_end.rb +24 -0
  13. data/lib/riffer/rig/events/session_start.rb +27 -0
  14. data/lib/riffer/rig/events/skill_activated.rb +24 -0
  15. data/lib/riffer/rig/events/turn_end.rb +32 -0
  16. data/lib/riffer/rig/events.rb +4 -0
  17. data/lib/riffer/rig/extension.rb +27 -0
  18. data/lib/riffer/rig/hosts/base.rb +36 -0
  19. data/lib/riffer/rig/hosts/mirror.rb +60 -0
  20. data/lib/riffer/rig/hosts/null.rb +36 -0
  21. data/lib/riffer/rig/provider_setup/field.rb +24 -0
  22. data/lib/riffer/rig/provider_setup.rb +84 -0
  23. data/lib/riffer/rig/registrar.rb +35 -0
  24. data/lib/riffer/rig/repl.rb +42 -31
  25. data/lib/riffer/rig/runtime/cancel_flag.rb +27 -0
  26. data/lib/riffer/rig/runtime.rb +225 -0
  27. data/lib/riffer/rig/settings/document.rb +28 -0
  28. data/lib/riffer/rig/settings/pricing.rb +11 -1
  29. data/lib/riffer/rig/settings.rb +49 -60
  30. data/lib/riffer/rig/token_tally.rb +1 -21
  31. data/lib/riffer/rig/tools/bash.rb +33 -12
  32. data/lib/riffer/rig/tools/edit.rb +1 -1
  33. data/lib/riffer/rig/tools/read.rb +2 -2
  34. data/lib/riffer/rig/ui/animator.rb +8 -15
  35. data/lib/riffer/rig/ui/cursor.rb +4 -6
  36. data/lib/riffer/rig/ui/renderer.rb +18 -31
  37. data/lib/riffer/rig/ui/smoother.rb +15 -23
  38. data/lib/riffer/rig/ui/theme.rb +4 -6
  39. data/lib/riffer/rig/version.rb +1 -1
  40. data/lib/riffer/rig.rb +26 -0
  41. data/sig/generated/riffer/rig/cli.rbs +27 -19
  42. data/sig/generated/riffer/rig/credentials/resolution.rbs +13 -0
  43. data/sig/generated/riffer/rig/credentials.rbs +71 -41
  44. data/sig/generated/riffer/rig/env.rbs +20 -0
  45. data/sig/generated/riffer/rig/events/command_output.rbs +19 -0
  46. data/sig/generated/riffer/rig/events/event.rbs +20 -0
  47. data/sig/generated/riffer/rig/events/notify.rbs +19 -0
  48. data/sig/generated/riffer/rig/events/session_end.rbs +16 -0
  49. data/sig/generated/riffer/rig/events/session_start.rbs +19 -0
  50. data/sig/generated/riffer/rig/events/skill_activated.rbs +16 -0
  51. data/sig/generated/riffer/rig/events/turn_end.rbs +22 -0
  52. data/sig/generated/riffer/rig/events.rbs +4 -0
  53. data/sig/generated/riffer/rig/extension.rbs +24 -0
  54. data/sig/generated/riffer/rig/hosts/base.rbs +26 -0
  55. data/sig/generated/riffer/rig/hosts/mirror.rbs +41 -0
  56. data/sig/generated/riffer/rig/hosts/null.rbs +26 -0
  57. data/sig/generated/riffer/rig/provider_setup/field.rbs +22 -0
  58. data/sig/generated/riffer/rig/provider_setup.rbs +30 -0
  59. data/sig/generated/riffer/rig/registrar.rbs +25 -0
  60. data/sig/generated/riffer/rig/repl.rbs +17 -16
  61. data/sig/generated/riffer/rig/runtime/cancel_flag.rbs +19 -0
  62. data/sig/generated/riffer/rig/runtime.rbs +120 -0
  63. data/sig/generated/riffer/rig/settings/document.rbs +24 -0
  64. data/sig/generated/riffer/rig/settings/pricing.rbs +4 -1
  65. data/sig/generated/riffer/rig/settings.rbs +28 -49
  66. data/sig/generated/riffer/rig/token_tally.rbs +2 -21
  67. data/sig/generated/riffer/rig/tools/bash.rbs +15 -3
  68. data/sig/generated/riffer/rig/tools/edit.rbs +2 -2
  69. data/sig/generated/riffer/rig/tools/read.rbs +3 -3
  70. data/sig/generated/riffer/rig/ui/animator.rbs +8 -16
  71. data/sig/generated/riffer/rig/ui/cursor.rbs +4 -6
  72. data/sig/generated/riffer/rig/ui/renderer.rbs +13 -35
  73. data/sig/generated/riffer/rig/ui/smoother.rbs +9 -22
  74. data/sig/generated/riffer/rig/ui/theme.rbs +3 -5
  75. data/sig/generated/riffer/rig.rbs +12 -0
  76. data/sig/manual/riffer/rig/cli.rbs +2 -4
  77. data/sig/manual/riffer/rig/credentials.rbs +2 -4
  78. data/sig/manual/riffer/rig/hosts.rbs +5 -0
  79. data/sig/manual/riffer/rig/settings.rbs +2 -4
  80. data/sig/manual/riffer/rig/ui/banner.rbs +2 -4
  81. data/sig/manual/riffer/rig.rbs +11 -0
  82. metadata +45 -3
@@ -1,17 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Hides the terminal cursor while a turn is in flight: a hidden cursor can't
4
- # flicker against the animator's erase-and-redraw churn.
5
3
  class Riffer::Rig::UI::Cursor
6
4
  HIDE = "\e[?25l" #: String
7
5
 
8
6
  SHOW = "\e[?25h" #: String
9
7
 
10
- # @rbs @io: untyped
8
+ # @rbs @io: IO
11
9
  # @rbs @theme: Riffer::Rig::UI::Theme
12
10
 
13
- # @rbs io: untyped
14
- # @rbs ?theme: Riffer::Rig::UI::Theme
11
+ # @rbs io: IO
12
+ # @rbs theme: Riffer::Rig::UI::Theme
15
13
  # @rbs return: void
16
14
  def initialize(io: $stdout, theme: Riffer::Rig::UI::Theme.for(io))
17
15
  @io = io
@@ -41,6 +39,6 @@ class Riffer::Rig::UI::Cursor
41
39
 
42
40
  # @rbs return: bool
43
41
  def enabled?
44
- @theme.enabled && @io.respond_to?(:tty?) && @io.tty?
42
+ @theme.enabled && @io.tty?
45
43
  end
46
44
  end
@@ -5,17 +5,17 @@ require 'json'
5
5
  class Riffer::Rig::UI::Renderer
6
6
  RESULT_PREVIEW_LIMIT = 200 #: Integer
7
7
 
8
- # @rbs @io: untyped
8
+ # @rbs @io: IO
9
9
  # @rbs @theme: Riffer::Rig::UI::Theme
10
10
  # @rbs @tally: Riffer::Rig::TokenTally?
11
11
  # @rbs @smoother: Riffer::Rig::UI::Smoother | PassThroughSmoother?
12
12
  # @rbs @deferred_usage: Riffer::Providers::TokenUsage?
13
13
  # @rbs @prose_gap_pending: bool
14
14
 
15
- # @rbs io: untyped
16
- # @rbs ?theme: Riffer::Rig::UI::Theme
17
- # @rbs ?tally: Riffer::Rig::TokenTally?
18
- # @rbs ?smoother: Riffer::Rig::UI::Smoother | PassThroughSmoother?
15
+ # @rbs io: IO
16
+ # @rbs theme: Riffer::Rig::UI::Theme
17
+ # @rbs tally: Riffer::Rig::TokenTally?
18
+ # @rbs smoother: Riffer::Rig::UI::Smoother | PassThroughSmoother?
19
19
  # @rbs return: void
20
20
  def initialize(io: $stdout, theme: Riffer::Rig::UI::Theme.for(io), tally: nil, smoother: nil)
21
21
  @io = io
@@ -39,28 +39,24 @@ class Riffer::Rig::UI::Renderer
39
39
  when Riffer::StreamEvents::Interrupt
40
40
  render_block(0) { @theme.dim("[interrupted: #{event.reason}]") }
41
41
  when Riffer::StreamEvents::TokenUsageDone
42
+ # Usage arrives per model call but tool results arrive via the session
43
+ # callback after each call's stream ends, so rendering inline would print
44
+ # the stats above the results they belong with.
42
45
  current = @deferred_usage
43
46
  @deferred_usage = current ? current + event.token_usage : event.token_usage
44
47
  end
45
48
  end
46
49
 
47
- # The prompt holds the line open for typed input, so unlike render_block it
48
- # ends without a newline. It sits at the renderer so a tool group left open by
49
- # the previous turn closes here, and the next turn's blocks open cleanly.
50
- #
51
50
  # @rbs return: void
52
51
  def prompt
52
+ # Closes any tool group the previous turn left open, so the next turn's
53
+ # blocks open cleanly.
53
54
  @prose_gap_pending = true
54
55
  @io.puts
55
56
  @io.print("#{@theme.pink('›')} ")
56
57
  @io.flush
57
58
  end
58
59
 
59
- # Usage arrives per model call but tool results arrive via the session
60
- # callback after each call's stream ends, so rendering inline would print the
61
- # stats above the results they belong with. Held until the turn's output is
62
- # done, then printed as one line below it.
63
- #
64
60
  # @rbs return: void
65
61
  def flush_usage
66
62
  usage = @deferred_usage
@@ -86,12 +82,8 @@ class Riffer::Rig::UI::Renderer
86
82
 
87
83
  private
88
84
 
89
- # Rule 2 for one-off blocks (skill line, interrupt, stats): one blank line
90
- # above, no indent. The smoother drains first so any pending partial prose
91
- # block ends cleanly before the gap is written, and any open tool group closes
92
- # so the next group opens with its own gap.
93
- #
94
85
  # @rbs indent: Integer
86
+ # @rbs &block: () -> String
95
87
  # @rbs return: void
96
88
  def render_block(indent, &)
97
89
  drain_smoother
@@ -101,13 +93,11 @@ class Riffer::Rig::UI::Renderer
101
93
  @io.flush
102
94
  end
103
95
 
104
- # The blank line above a prose block is written at the first delta after a
105
- # non-prose block. Streaming makes "which block is first?" a stateful
106
- # question, so the answer is tracked rather than embedded at each render site.
107
- #
108
96
  # @rbs content: String
109
97
  # @rbs return: void
110
98
  def render_prose(content)
99
+ # Streaming makes "which delta opens a prose block?" a stateful question,
100
+ # so the gap is tracked in a flag rather than written at each render site.
111
101
  if @prose_gap_pending
112
102
  @prose_gap_pending = false
113
103
  @io.print("\n")
@@ -116,6 +106,7 @@ class Riffer::Rig::UI::Renderer
116
106
  end
117
107
 
118
108
  # @rbs indent: Integer
109
+ # @rbs &block: () -> String
119
110
  # @rbs return: void
120
111
  def render_tool_activity(indent, &)
121
112
  open_tool_activity
@@ -123,12 +114,10 @@ class Riffer::Rig::UI::Renderer
123
114
  @io.flush
124
115
  end
125
116
 
126
- # Tool-activity lines (⚙ calls, ↳ results) share one blank line above the
127
- # group instead of one between each line — the gap goes between groups, not
128
- # inside a pair. The group stays open so prose after it pays the closing gap.
129
- #
130
117
  # @rbs return: void
131
118
  def open_tool_activity
119
+ # Tool-activity lines (⚙ calls, ↳ results) share one blank line above the
120
+ # group; the group stays open so the prose after it pays the closing gap.
132
121
  return if @prose_gap_pending
133
122
 
134
123
  drain_smoother
@@ -155,12 +144,10 @@ class Riffer::Rig::UI::Renderer
155
144
  @smoother || PassThroughSmoother.new(@io)
156
145
  end
157
146
 
158
- # Stand-in when no smoother is injected, so a bare Riffer::Rig::UI::Renderer still prints
159
- # synchronously.
160
147
  class PassThroughSmoother
161
- # @rbs @io: untyped
148
+ # @rbs @io: IO
162
149
 
163
- # @rbs io: untyped
150
+ # @rbs io: IO
164
151
  # @rbs return: void
165
152
  def initialize(io) = @io = io
166
153
 
@@ -1,23 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Paces streamed text onto a 60fps cadence so API bursts read as continuous
4
- # typing. On a non-TTY output it is transparent: writes pass through
5
- # synchronously and no thread ever runs.
6
3
  class Riffer::Rig::UI::Smoother
7
4
  TICK_SECONDS = 1.0 / 60.0 #: Float
8
5
 
9
- # A frame removes only a sixtieth of the remaining backlog — an exponential
10
- # decay whose tail keeps text flowing for a second or more, so the reveal
11
- # never visibly stops between chunks. The carry accrues sub-character
12
- # releases so the effective rate can settle at the provider's throughput;
13
- # the floor is fractional (10 chars/s) so it can't over-drain a backlog
14
- # that's trickling in slower than 60 chars/s.
15
- #
6
+ # Releasing a fraction of the backlog, not a fixed rate, makes the reveal an
7
+ # exponential decay: its tail keeps text flowing for a second or more, so
8
+ # output never visibly stops between chunks.
16
9
  BACKLOG_FRACTION_PER_TICK = Rational(1, 60) #: Rational
17
10
 
11
+ # Fractional (10 chars/s) so the floor can't over-drain a backlog that's
12
+ # trickling in slower than 60 chars/s.
18
13
  MIN_CHARS_PER_TICK = Rational(1, 6) #: Rational
19
14
 
20
- # @rbs @io: untyped
15
+ # @rbs @io: IO
21
16
  # @rbs @theme: Riffer::Rig::UI::Theme
22
17
  # @rbs @clock: singleton(Kernel)
23
18
  # @rbs @backlog: String
@@ -27,8 +22,8 @@ class Riffer::Rig::UI::Smoother
27
22
  # @rbs @stop: bool
28
23
  # @rbs @newline_pending: bool
29
24
 
30
- # @rbs io: untyped
31
- # @rbs ?theme: Riffer::Rig::UI::Theme
25
+ # @rbs io: IO
26
+ # @rbs theme: Riffer::Rig::UI::Theme
32
27
  # @rbs clock: singleton(Kernel)
33
28
  # @rbs return: void
34
29
  def initialize(io: $stdout, theme: Riffer::Rig::UI::Theme.for(io), clock: Kernel)
@@ -72,13 +67,13 @@ class Riffer::Rig::UI::Smoother
72
67
  self
73
68
  end
74
69
 
75
- # The write sits inside the mutex so a concurrent tick can't reorder a drain.
76
- #
77
70
  # @rbs return: void
78
71
  def tick
79
72
  @mutex.synchronize do
80
73
  return if @backlog.empty?
81
74
 
75
+ # The carry accrues sub-character releases so the effective rate can
76
+ # settle at the provider's throughput.
82
77
  @carry += [@backlog.length * BACKLOG_FRACTION_PER_TICK, MIN_CHARS_PER_TICK].max
83
78
  count = @carry.floor
84
79
  return if count.zero?
@@ -86,16 +81,12 @@ class Riffer::Rig::UI::Smoother
86
81
  @carry -= count
87
82
  chunk = @backlog.slice!(0, count) || ''
88
83
  @newline_pending = !chunk.end_with?("\n")
84
+ # Written inside the mutex so a concurrent drain can't reorder output.
89
85
  @io.print(chunk)
90
86
  @io.flush
91
87
  end
92
88
  end
93
89
 
94
- # Called before non-prose output so printed order matches stream order. The
95
- # backlog is flushed, then any partial prose block the model left without a
96
- # trailing newline gets one, so block spacing never depends on the model's
97
- # last character.
98
- #
99
90
  # @rbs return: void
100
91
  def drain
101
92
  @mutex.synchronize do
@@ -106,16 +97,17 @@ class Riffer::Rig::UI::Smoother
106
97
  end
107
98
  return unless @newline_pending
108
99
 
100
+ # Block spacing must not depend on whether the model ended its prose
101
+ # with a newline.
109
102
  @newline_pending = false
110
103
  @io.print("\n")
111
104
  @io.flush
112
105
  end
113
106
  end
114
107
 
115
- # Idempotent: the REPL's ensure path runs it even after a happy-path finish.
116
- #
117
108
  # @rbs return: void
118
109
  def finish
110
+ # Idempotent: the REPL's ensure path runs it even after a happy-path finish.
119
111
  thread = @thread
120
112
  if thread
121
113
  @stop = true
@@ -129,6 +121,6 @@ class Riffer::Rig::UI::Smoother
129
121
 
130
122
  # @rbs return: bool
131
123
  def enabled?
132
- @theme.enabled && @io.respond_to?(:tty?) && @io.tty?
124
+ @theme.enabled && @io.tty?
133
125
  end
134
126
  end
@@ -1,11 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # +enabled+ gates every escape so the same code path emits plain, escape-free
4
- # text when piped or tested.
5
3
  class Riffer::Rig::UI::Theme
6
4
  # @rbs @enabled: bool
7
5
 
8
- # @rbs return: bool
9
6
  # @dynamic enabled
10
7
  attr_reader :enabled #: bool
11
8
 
@@ -15,10 +12,11 @@ class Riffer::Rig::UI::Theme
15
12
  @enabled = enabled
16
13
  end
17
14
 
18
- # @rbs io: untyped
15
+ # @rbs io: IO
16
+ # @rbs env: Riffer::Rig::Env
19
17
  # @rbs return: Riffer::Rig::UI::Theme
20
- def self.for(io)
21
- new(enabled: io.respond_to?(:tty?) && io.tty? && !ENV.key?('NO_COLOR'))
18
+ def self.for(io, env: Riffer::Rig::Env.new)
19
+ new(enabled: io.tty? && !env.no_color)
22
20
  end
23
21
 
24
22
  # @rbs text: String
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Riffer
4
4
  module Rig
5
- VERSION = '0.4.0'
5
+ VERSION = '0.6.0'
6
6
  end
7
7
  end
data/lib/riffer/rig.rb CHANGED
@@ -8,3 +8,29 @@ loader = Zeitwerk::Loader.for_gem_extension(Riffer)
8
8
  loader.ignore("#{__dir__}/rig/version.rb")
9
9
  loader.inflector.inflect('cli' => 'CLI', 'repl' => 'REPL', 'ui' => 'UI')
10
10
  loader.setup
11
+
12
+ module Riffer::Rig
13
+ # @rbs self.@extensions: Hash[String, Riffer::Rig::Extension]
14
+ @extensions = {} #: Hash[String, Riffer::Rig::Extension]
15
+
16
+ # @rbs name: String
17
+ # @rbs requires: String?
18
+ # @rbs &block: (::Riffer::Rig::Registrar) -> void
19
+ # @rbs return: Riffer::Rig::Extension
20
+ def self.extension(name, requires: nil, &)
21
+ ext = Extension.new(name, requires: requires, &)
22
+ if ext.requires && !ext.requires.satisfied_by?(Gem::Version.new(Riffer::Rig::VERSION))
23
+ raise Riffer::ArgumentError,
24
+ "extension #{name} requires riffer-rig #{ext.requires}, found #{Riffer::Rig::VERSION}"
25
+ end
26
+
27
+ # Keyed by name so reloading a file replaces its block rather than
28
+ # duplicating it.
29
+ @extensions[name] = ext
30
+ end
31
+
32
+ # @rbs return: Hash[String, Riffer::Rig::Extension]
33
+ def self.extensions
34
+ @extensions.dup
35
+ end
36
+ end
@@ -1,34 +1,42 @@
1
1
  # Generated from lib/riffer/rig/cli.rb with RBS::Inline
2
2
 
3
3
  module Riffer::Rig::CLI
4
- PROVIDER_URLS: Hash[String, String]
5
-
6
- # @rbs output: untyped
7
- # @rbs input: untyped
4
+ # @rbs output: IO
5
+ # @rbs input: IO
6
+ # @rbs model: String
7
+ # @rbs env: Riffer::Rig::Env
8
8
  # @rbs return: Integer
9
- def start: (?output: untyped, ?input: untyped) -> Integer
9
+ def start: (?output: IO, ?input: IO, ?model: String, ?env: Riffer::Rig::Env) -> Integer
10
10
 
11
11
  private
12
12
 
13
- # @rbs provider: String?
14
- # @rbs api_key: String
15
- # @rbs return: void
16
- def configure_provider: (String? provider, String api_key) -> void
17
-
18
- # @rbs provider: String?
13
+ # @rbs provider: String
19
14
  # @rbs theme: Riffer::Rig::UI::Theme
20
- # @rbs output: untyped
21
- # @rbs input: untyped
22
- # @rbs return: String?
23
- def onboard: (String? provider, Riffer::Rig::UI::Theme theme, output: untyped, input: untyped) -> String?
15
+ # @rbs output: IO
16
+ # @rbs input: IO
17
+ # @rbs env: Riffer::Rig::Env
18
+ # @rbs return: Hash[Symbol, String]?
19
+ def credentials_for: (String provider, Riffer::Rig::UI::Theme theme, output: IO, input: IO, env: Riffer::Rig::Env) -> Hash[Symbol, String]?
20
+
21
+ # @rbs provider: String
22
+ # @rbs resolution: Riffer::Rig::Credentials::Resolution
23
+ # @rbs theme: Riffer::Rig::UI::Theme
24
+ # @rbs output: IO
25
+ # @rbs input: IO
26
+ # @rbs return: Hash[Symbol, String]?
27
+ def onboard: (String provider, Riffer::Rig::Credentials::Resolution resolution, Riffer::Rig::UI::Theme theme, output: IO, input: IO) -> Hash[Symbol, String]?
24
28
 
25
- # @rbs provider: String?
29
+ # @rbs provider: String
30
+ # @rbs field: Riffer::Rig::ProviderSetup::Field
31
+ # @rbs theme: Riffer::Rig::UI::Theme
32
+ # @rbs output: IO
33
+ # @rbs input: IO
26
34
  # @rbs return: String
27
- def env_var_for: (String? provider) -> String
35
+ def prompt: (String provider, Riffer::Rig::ProviderSetup::Field field, Riffer::Rig::UI::Theme theme, output: IO, input: IO) -> String
28
36
 
29
- # @rbs input: untyped
37
+ # @rbs input: IO
30
38
  # @rbs return: String?
31
- def read_secret: (untyped input) -> String?
39
+ def read_secret: (IO input) -> String?
32
40
 
33
41
  # @rbs theme: Riffer::Rig::UI::Theme
34
42
  # @rbs animator: Riffer::Rig::UI::Animator
@@ -0,0 +1,13 @@
1
+ # Generated from lib/riffer/rig/credentials/resolution.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Credentials::Resolution
4
+ # @dynamic values, missing
5
+ attr_reader values: Hash[Symbol, String]
6
+
7
+ attr_reader missing: Array[Symbol]
8
+
9
+ # @rbs values: Hash[Symbol, String]
10
+ # @rbs missing: Array[Symbol]
11
+ # @rbs return: void
12
+ def initialize: (values: Hash[Symbol, String], missing: Array[Symbol]) -> void
13
+ end
@@ -1,55 +1,85 @@
1
1
  # Generated from lib/riffer/rig/credentials.rb with RBS::Inline
2
2
 
3
- # Reads and writes API keys for each supported provider in
4
- # <tt>~/.riffer/auth.json</tt>.
5
- #
6
- # Keys are stored under the provider name, e.g.:
7
- #
8
- # {
9
- # "anthropic": "sk-ant-...",
10
- # "openai": "sk-...",
11
- # "gemini": "...",
12
- # "openrouter": "sk-or-..."
13
- # }
14
- #
15
- # The environment variable checked per provider:
16
- #
17
- # anthropic → ANTHROPIC_API_KEY
18
- # openai → OPENAI_API_KEY
19
- # gemini → GEMINI_API_KEY
20
- # openrouter → OPENROUTER_API_KEY
21
3
  module Riffer::Rig::Credentials
22
4
  PATH: String
23
5
 
24
- PROVIDER_ENV_VARS: Hash[String, String]
6
+ ENTRY_TYPE: ::String
25
7
 
26
- # Returns the API key for +provider+, checking the environment variable first,
27
- # then the stored file. Returns +nil+ if no key is available.
28
- #
29
- # @rbs provider: String?
30
- # @rbs path: String
31
- # @rbs return: String?
32
- def api_key_for: (String? provider, ?path: String) -> String?
8
+ # @rbs identifier: String | Symbol
9
+ # @rbs host: Riffer::Rig::Hosts::Base
10
+ # @rbs setup: Riffer::Rig::ProviderSetup
11
+ # @rbs env: Riffer::Rig::Env
12
+ # @rbs auth_path: String
13
+ # @rbs settings_path: String
14
+ # @rbs return: Resolution
15
+ def resolve: (String | Symbol identifier, host: Riffer::Rig::Hosts::Base, ?setup: Riffer::Rig::ProviderSetup, ?env: Riffer::Rig::Env, ?auth_path: String, ?settings_path: String) -> Resolution
33
16
 
34
- # Saves an API key for +provider+ to the auth file with 0600 permissions.
35
- #
36
- # @rbs provider: String
37
- # @rbs key: String
38
- # @rbs path: String
39
- # @rbs return: String
40
- def save_api_key: (String provider, String key, ?path: String) -> String
17
+ # @rbs identifier: String | Symbol
18
+ # @rbs values: Hash[Symbol, String]
19
+ # @rbs config: Riffer::Config
20
+ # @rbs return: void
21
+ def apply: (String | Symbol identifier, Hash[Symbol, String] values, ?config: Riffer::Config) -> void
22
+
23
+ # @rbs identifier: String | Symbol
24
+ # @rbs values: Hash[Symbol, String]
25
+ # @rbs setup: Riffer::Rig::ProviderSetup
26
+ # @rbs auth_path: String
27
+ # @rbs settings_path: String
28
+ # @rbs return: void
29
+ def store: (String | Symbol identifier, Hash[Symbol, String] values, ?setup: Riffer::Rig::ProviderSetup, ?auth_path: String, ?settings_path: String) -> void
30
+
31
+ # @rbs identifier: String | Symbol
32
+ # @rbs auth_path: String
33
+ # @rbs settings_path: String
34
+ # @rbs return: void
35
+ def remove: (String | Symbol identifier, ?auth_path: String, ?settings_path: String) -> void
36
+
37
+ # @rbs identifier: String | Symbol
38
+ # @rbs setup: Riffer::Rig::ProviderSetup
39
+ # @rbs env: Riffer::Rig::Env
40
+ # @rbs auth_path: String
41
+ # @rbs return: :env | :stored | :chain | :missing
42
+ def status: (String | Symbol identifier, ?setup: Riffer::Rig::ProviderSetup, ?env: Riffer::Rig::Env, ?auth_path: String) -> (:env | :stored | :chain | :missing)
41
43
 
42
44
  private
43
45
 
44
- # @rbs provider: String?
45
- # @rbs path: String
46
+ # @rbs fields: Array[Riffer::Rig::ProviderSetup::Field]
47
+ # @rbs identifier: String | Symbol
48
+ # @rbs host: Riffer::Rig::Hosts::Base
49
+ # @rbs return: Hash[Symbol, String]
50
+ def ask_for: (Array[Riffer::Rig::ProviderSetup::Field] fields, String | Symbol identifier, Riffer::Rig::Hosts::Base host) -> Hash[Symbol, String]
51
+
52
+ # @rbs field: Riffer::Rig::ProviderSetup::Field
53
+ # @rbs secrets: Hash[String, String]
54
+ # @rbs plain: Hash[String, String]
55
+ # @rbs env: Riffer::Rig::Env
56
+ # @rbs return: String?
57
+ def stored_value: (Riffer::Rig::ProviderSetup::Field field, Hash[String, String] secrets, Hash[String, String] plain, Riffer::Rig::Env env) -> String?
58
+
59
+ # @rbs value: String?
60
+ # @rbs env: Riffer::Rig::Env
61
+ # @rbs return: String?
62
+ def expand: (String? value, Riffer::Rig::Env env) -> String?
63
+
64
+ # @rbs command: String
65
+ # @rbs return: String?
66
+ def run: (String command) -> String?
67
+
68
+ # @rbs value: String?
46
69
  # @rbs return: String?
47
- def key_from_file: (String? provider, String path) -> String?
70
+ def presence: (String? value) -> String?
71
+
72
+ # @rbs identifier: String | Symbol
73
+ # @rbs path: String
74
+ # @rbs return: Hash[String, String]
75
+ def stored_secrets: (String | Symbol identifier, String path) -> Hash[String, String]
76
+
77
+ # @rbs path: String
78
+ # @rbs return: Hash[String, Hash[String, String]]
79
+ def read_auth: (String path) -> Hash[String, Hash[String, String]]
48
80
 
49
- # The parsed auth file, or an empty hash when the file is absent or
50
- # malformed.
51
- #
52
81
  # @rbs path: String
53
- # @rbs return: Hash[String, untyped]
54
- def read: (String path) -> Hash[String, untyped]
82
+ # @rbs entries: Hash[String, Hash[String, String]]
83
+ # @rbs return: void
84
+ def write_auth: (String path, Hash[String, Hash[String, String]] entries) -> void
55
85
  end
@@ -0,0 +1,20 @@
1
+ # Generated from lib/riffer/rig/env.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Env
4
+ @source: Hash[String, String]
5
+
6
+ # @dynamic no_color
7
+ attr_reader no_color: bool
8
+
9
+ # @rbs source: Hash[String, String]
10
+ # @rbs return: void
11
+ def initialize: (?Hash[String, String] source) -> void
12
+
13
+ # @rbs name: String
14
+ # @rbs return: String?
15
+ def []: (String name) -> String?
16
+
17
+ # @rbs field: Riffer::Rig::ProviderSetup::Field
18
+ # @rbs return: String?
19
+ def value_for: (Riffer::Rig::ProviderSetup::Field field) -> String?
20
+ end
@@ -0,0 +1,19 @@
1
+ # Generated from lib/riffer/rig/events/command_output.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::CommandOutput < Riffer::Rig::Events::Event
4
+ # @dynamic command, text
5
+ attr_reader command: String
6
+
7
+ attr_reader text: String
8
+
9
+ # @rbs command: String
10
+ # @rbs text: String
11
+ # @rbs return: void
12
+ def initialize: (String command, String text) -> void
13
+
14
+ # @rbs return: Symbol
15
+ def type: () -> Symbol
16
+
17
+ # @rbs return: Hash[Symbol, untyped]
18
+ def to_h: () -> Hash[Symbol, untyped]
19
+ end
@@ -0,0 +1,20 @@
1
+ # Generated from lib/riffer/rig/events/event.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::Event
4
+ # @rbs return: Symbol
5
+ def type: () -> Symbol
6
+
7
+ # @rbs return: Hash[Symbol, untyped]
8
+ def to_h: () -> Hash[Symbol, untyped]
9
+
10
+ # @rbs other: untyped
11
+ # @rbs return: bool
12
+ def ==: (untyped other) -> bool
13
+
14
+ # @rbs return: Integer
15
+ def hash: () -> Integer
16
+
17
+ # @rbs other: untyped
18
+ # @rbs return: bool
19
+ def eql?: (untyped other) -> bool
20
+ end
@@ -0,0 +1,19 @@
1
+ # Generated from lib/riffer/rig/events/notify.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::Notify < Riffer::Rig::Events::Event
4
+ # @dynamic message, level
5
+ attr_reader message: String?
6
+
7
+ attr_reader level: Symbol
8
+
9
+ # @rbs message: String?
10
+ # @rbs level: Symbol
11
+ # @rbs return: void
12
+ def initialize: (String? message, Symbol level) -> void
13
+
14
+ # @rbs return: Symbol
15
+ def type: () -> Symbol
16
+
17
+ # @rbs return: Hash[Symbol, untyped]
18
+ def to_h: () -> Hash[Symbol, untyped]
19
+ end
@@ -0,0 +1,16 @@
1
+ # Generated from lib/riffer/rig/events/session_end.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::SessionEnd < Riffer::Rig::Events::Event
4
+ # @dynamic reason
5
+ attr_reader reason: Symbol
6
+
7
+ # @rbs reason: Symbol
8
+ # @rbs return: void
9
+ def initialize: (Symbol reason) -> void
10
+
11
+ # @rbs return: Symbol
12
+ def type: () -> Symbol
13
+
14
+ # @rbs return: Hash[Symbol, untyped]
15
+ def to_h: () -> Hash[Symbol, untyped]
16
+ end
@@ -0,0 +1,19 @@
1
+ # Generated from lib/riffer/rig/events/session_start.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::SessionStart < Riffer::Rig::Events::Event
4
+ # @dynamic id, reason
5
+ attr_reader id: String
6
+
7
+ attr_reader reason: Symbol
8
+
9
+ # @rbs id: String
10
+ # @rbs reason: Symbol
11
+ # @rbs return: void
12
+ def initialize: (String id, Symbol reason) -> void
13
+
14
+ # @rbs return: Symbol
15
+ def type: () -> Symbol
16
+
17
+ # @rbs return: Hash[Symbol, untyped]
18
+ def to_h: () -> Hash[Symbol, untyped]
19
+ end
@@ -0,0 +1,16 @@
1
+ # Generated from lib/riffer/rig/events/skill_activated.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Events::SkillActivated < Riffer::Rig::Events::Event
4
+ # @dynamic name
5
+ attr_reader name: String
6
+
7
+ # @rbs name: String
8
+ # @rbs return: void
9
+ def initialize: (String name) -> void
10
+
11
+ # @rbs return: Symbol
12
+ def type: () -> Symbol
13
+
14
+ # @rbs return: Hash[Symbol, untyped]
15
+ def to_h: () -> Hash[Symbol, untyped]
16
+ end