riffer-rig 0.7.0 → 0.8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52fc3da32f169222f7f3bac50e5ecb6d878fe46cf1955b00b218f26af043b2e9
4
- data.tar.gz: a6a2c8c3c36fb9774550f2188d7cdfb529b5abb53805bd58eb31863f00c335c8
3
+ metadata.gz: 9d560ab0c2be62a87e8468ba302f443985cd5d92d4872de2073c5c77b672d83f
4
+ data.tar.gz: b75fe6a3d1a7f0c718405f619f2f56c20fe85282ddb94aff9c2beb853344c119
5
5
  SHA512:
6
- metadata.gz: 4fb9601edf932b84ee1c91b226d22814b8d80633e891ef3a3dc2436d59fc2ea617c53772ec2b9042362e937590a525f000dc6e85bb748b8bdd1ba32e017bc551
7
- data.tar.gz: c51101a3560a43400edc5608e37f4615383cfdee22f8c2975b14e7d95a52bce08c063db1d2de108189e525ee1bf3f13377e4c3b22c9bef3b0a147298ac25f228
6
+ metadata.gz: a2ca46037680a034a31b977101a9c5b442fc21f56842cb3055f2163493d42eef2d92ccdbc53aa9bf5fd2749af6fcfd52fb6d74aecbea0da907a5bac3ecee7498
7
+ data.tar.gz: 4e531d3fee7fa1107e7d6a7c5d1fa064c4bbdf9e46763353332d4b9d9b57b6a37436d54326fe06e21248c147d99e15ddaac4a18b6ee8ffd34be4e29d733444ae
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.8.0](https://github.com/bottrall/riffer-rig/compare/v0.7.0...v0.8.0) (2026-10-02)
4
+
5
+
6
+ ### Features
7
+
8
+ * discover rig.rb files with project trust and optional gem autoload ([#208](https://github.com/bottrall/riffer-rig/issues/208)) ([6ed818f](https://github.com/bottrall/riffer-rig/commit/6ed818f5b5d382b3a9c7d48ce667892b10190985))
9
+ * truncate tool output and fit lines to the terminal width ([#209](https://github.com/bottrall/riffer-rig/issues/209)) ([3765de1](https://github.com/bottrall/riffer-rig/commit/3765de1f4392d903939c1458e843c2ca1e70112e))
10
+
3
11
  ## [0.7.0](https://github.com/bottrall/riffer-rig/compare/v0.6.0...v0.7.0) (2026-09-30)
4
12
 
5
13
 
data/README.md CHANGED
@@ -35,7 +35,7 @@ The model is the first of these that is set: `--model`, `RIFFER_MODEL`, `model`
35
35
  | Flag | Effect |
36
36
  | ----------------------- | -------------------------------------------------------------------------- |
37
37
  | `--model provider/name` | the model for this session, over `RIFFER_MODEL` and the settings |
38
- | `--no-extensions` | skips extension files; accepted now, with nothing to skip until they load |
38
+ | `--no-extensions` | skips the [`rig.rb` files](docs/EXTENSIONS.md#the-rigrb-files) and gem autoload; the bundle still loads |
39
39
  | `--no-skills` | leaves out [Agent Skills](docs/SKILLS.md) |
40
40
  | `--no-agents-md` | leaves out the [AGENTS.md](docs/INSTRUCTIONS.md#agentsmd) instructions |
41
41
  | `--tools read,bash` | only these tools, by identifier ([Tools](docs/TOOLS.md)) |
@@ -124,6 +124,7 @@ Every project chore is a script in `bin/`. The Rakefile behind them is an implem
124
124
  | `bin/rbs-watch` | Regenerate `sig/generated` whenever `lib/` changes |
125
125
  | `bin/ci` | Run everything CI runs, serially. Use before pushing |
126
126
  | `bin/build` | Build the gem into `pkg/`; the publish workflow runs this before `gem push` |
127
+ | `bin/docs` | Build the docs site and API reference into `_site/`; `bin/docs serve` serves it at http://localhost:8000 |
127
128
  | `bin/plans` | Serve the building plans in `plans/` at http://localhost:8001 |
128
129
 
129
130
  ## Releasing
@@ -11,13 +11,19 @@ class Riffer::Rig::Loader
11
11
  NO_MODEL = 'No model is set: pass --model provider/name, set RIFFER_MODEL, or set "model" in ' \
12
12
  "~/.riffer/settings.json, with a provider from: #{PROVIDER_LIST}".freeze #: String
13
13
 
14
- private_constant :PROVIDER_LIST, :ONBOARDING_QUESTION, :NO_MODEL
14
+ EXTENSION_FEATURE = 'riffer/rig/extension' #: String
15
+
16
+ private_constant :EXTENSION_FEATURE, :PROVIDER_LIST, :ONBOARDING_QUESTION, :NO_MODEL
15
17
 
16
18
  # @rbs @cwd: String
17
19
  # @rbs @host: Riffer::Rig::Hosts::_Host
18
20
  # @rbs @env: Riffer::Rig::Env
19
21
  # @rbs @home: String
20
22
  # @rbs @riffer_config: Riffer::Config
23
+ # @rbs @tracked_files: Array[String]
24
+
25
+ # @dynamic tracked_files
26
+ attr_reader :tracked_files #: Array[String]
21
27
 
22
28
  # @rbs cwd: String
23
29
  # @rbs host: Riffer::Rig::Hosts::_Host
@@ -61,6 +67,7 @@ class Riffer::Rig::Loader
61
67
  @env = env
62
68
  @home = home
63
69
  @riffer_config = riffer_config
70
+ @tracked_files = []
64
71
  end
65
72
 
66
73
  # @rbs model: String?
@@ -87,10 +94,12 @@ class Riffer::Rig::Loader
87
94
  provider = Riffer::Rig::Settings.provider_for(selected).to_s
88
95
  credentials = { provider.to_sym => credentials_for(provider) }
89
96
  stripped = { skills: skills, agents_md: agents_md }.reject { |_name, kept| kept }.keys
97
+ loaded = Riffer::Rig::Bundled::BY_NAME.except(*document.disabled.map(&:to_sym), *stripped).values
98
+ loaded += load_rig_files(document.autoload) if extensions
90
99
 
91
100
  Riffer::Rig::Runtime.new(
92
101
  selected,
93
- extensions: Riffer::Rig::Bundled::BY_NAME.except(*document.disabled.map(&:to_sym), *stripped).values,
102
+ extensions: loaded,
94
103
  tools: tools,
95
104
  settings: settings,
96
105
  host: @host,
@@ -105,6 +114,74 @@ class Riffer::Rig::Loader
105
114
 
106
115
  private
107
116
 
117
+ # @rbs autoload: bool
118
+ # @rbs return: Array[Riffer::Rig::Extension]
119
+ def load_rig_files(autoload)
120
+ recorded = gem_extension_files(autoload).flat_map { |file| load_file(File.expand_path(file), track: false) }
121
+ home = File.expand_path(File.join(@home, '.riffer', 'rig.rb'))
122
+ recorded.concat(load_file(home, track: true)) if File.file?(home)
123
+ project = File.expand_path(File.join(@cwd, '.riffer', 'rig.rb'))
124
+ recorded.concat(load_file(project, track: true)) if File.file?(project) && trusted?(project)
125
+ recorded
126
+ end
127
+
128
+ # @rbs autoload: bool
129
+ # @rbs return: Array[String]
130
+ def gem_extension_files(autoload)
131
+ return [] unless autoload
132
+
133
+ Gem.find_files(EXTENSION_FEATURE)
134
+ end
135
+
136
+ # @rbs path: String
137
+ # @rbs return: bool
138
+ def trusted?(path)
139
+ stored = Riffer::Rig::Trust.read(trust_path)[path]
140
+ return stored unless stored.nil?
141
+
142
+ asked = @host.capabilities.include?(:confirm)
143
+ decision = asked ? @host.confirm("Trust #{path}?") : false
144
+ Riffer::Rig::Trust.store(trust_path, path, decision) if asked
145
+ decision
146
+ end
147
+
148
+ # @rbs return: String
149
+ def trust_path
150
+ File.join(@home, '.riffer', 'trust.json')
151
+ end
152
+
153
+ # @rbs path: String
154
+ # @rbs track: bool
155
+ # @rbs return: Array[Riffer::Rig::Extension]
156
+ def load_file(path, track:)
157
+ before = Riffer::Rig.extensions
158
+ before_features = $LOADED_FEATURES.dup
159
+ begin
160
+ load path
161
+ rescue StandardError => e
162
+ track_loaded(before_features, path) if track
163
+ @host.notify("#{path} failed to load: #{e.message}", level: :error)
164
+ return []
165
+ end
166
+ track_loaded(before_features, path) if track
167
+ Riffer::Rig.extensions.values.reject { |extension| before[extension.name] == extension }
168
+ end
169
+
170
+ # @rbs before_features: Array[String]
171
+ # @rbs path: String
172
+ # @rbs return: void
173
+ def track_loaded(before_features, path)
174
+ recorded = ($LOADED_FEATURES - before_features) + [path] #: Array[String]
175
+ @tracked_files.concat(recorded.select { |feature| local?(feature) })
176
+ end
177
+
178
+ # @rbs feature: String
179
+ # @rbs return: bool
180
+ def local?(feature)
181
+ roots = [File.expand_path(File.join(@home, '.riffer')), File.expand_path(@cwd)] #: Array[String]
182
+ roots.any? { |root| feature.start_with?("#{root}#{File::SEPARATOR}") }
183
+ end
184
+
108
185
  # @rbs configured: String?
109
186
  # @rbs return: String
110
187
  def select_model(configured)
@@ -1,12 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Riffer::Rig::Settings::Document
4
- # @dynamic model, reasoning, models, providers, disabled
4
+ # @dynamic model, reasoning, models, providers, disabled, autoload
5
5
  attr_reader :model #: String?
6
6
  attr_reader :reasoning #: String?
7
7
  attr_reader :models #: Hash[String, Riffer::Rig::Settings::Pricing]
8
8
  attr_reader :providers #: Hash[String, Hash[String, String]]
9
9
  attr_reader :disabled #: Array[String]
10
+ attr_reader :autoload #: bool
10
11
 
11
12
  # @rbs source: Hash[Symbol, untyped]
12
13
  # @rbs return: void
@@ -26,6 +27,7 @@ class Riffer::Rig::Settings::Document
26
27
  disabled = hash_or_empty(source[:extensions])[:disabled]
27
28
  names = disabled.is_a?(Array) ? disabled.grep(String) : [] #: Array[String]
28
29
  @disabled = names.freeze
30
+ @autoload = hash_or_empty(source[:extensions])[:autoload] == true
29
31
  freeze
30
32
  end
31
33
 
@@ -1,32 +1,47 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'io/console'
3
4
  require 'json'
4
5
 
5
6
  class Riffer::Rig::Terminal::Renderer
6
7
  RESULT_PREVIEW_LIMIT = 200 #: Integer
7
8
 
9
+ ARGUMENT_PREVIEW_LIMIT = 60 #: Integer
10
+
11
+ PROSE_INDENT = 2 #: Integer
12
+
13
+ TOOL_CALL_INDENT = 4 #: Integer
14
+
15
+ TOOL_RESULT_INDENT = 6 #: Integer
16
+
8
17
  # @rbs @io: IO
9
18
  # @rbs @theme: Riffer::Rig::Terminal::Theme
10
19
  # @rbs @smoother: Riffer::Rig::Terminal::Smoother | PassThroughSmoother
11
20
  # @rbs @cursor: Riffer::Rig::Terminal::Cursor
12
21
  # @rbs @prose_gap_pending: bool
22
+ # @rbs @width: Integer?
23
+ # @rbs @wrapper: Riffer::Rig::Terminal::Wrapper
13
24
 
14
25
  # @rbs io: IO
15
26
  # @rbs theme: Riffer::Rig::Terminal::Theme
16
27
  # @rbs smoother: Riffer::Rig::Terminal::Smoother | PassThroughSmoother
17
28
  # @rbs cursor: Riffer::Rig::Terminal::Cursor
29
+ # @rbs width: Integer?
18
30
  # @rbs return: void
19
31
  def initialize(
20
32
  io: $stdout,
21
33
  theme: Riffer::Rig::Terminal::Theme.for(io),
22
34
  smoother: PassThroughSmoother.new(io),
23
- cursor: Riffer::Rig::Terminal::Cursor.new(io: io, theme: theme)
35
+ cursor: Riffer::Rig::Terminal::Cursor.new(io: io, theme: theme),
36
+ width: nil
24
37
  )
25
38
  @io = io
26
39
  @theme = theme
27
40
  @smoother = smoother
28
41
  @cursor = cursor
29
42
  @prose_gap_pending = false
43
+ @width = width
44
+ @wrapper = new_wrapper
30
45
  end
31
46
 
32
47
  # @rbs event: Riffer::StreamEvents::TextDelta | Riffer::StreamEvents::ToolCallDone | Riffer::StreamEvents::Interrupt
@@ -36,7 +51,7 @@ class Riffer::Rig::Terminal::Renderer
36
51
  when Riffer::StreamEvents::TextDelta
37
52
  render_prose(event.content)
38
53
  when Riffer::StreamEvents::ToolCallDone
39
- render_tool_activity(2) { @theme.cyan("⚙ #{event.name}(#{format_arguments(event.arguments)})") }
54
+ render_tool_activity(TOOL_CALL_INDENT) { "⚙ #{event.name}(#{format_arguments(event.arguments)})" }
40
55
  when Riffer::StreamEvents::Interrupt
41
56
  render_block(0) { @theme.dim("[interrupted: #{event.reason}]") }
42
57
  end
@@ -73,7 +88,12 @@ class Riffer::Rig::Terminal::Renderer
73
88
  def usage(usage, session)
74
89
  return unless usage && session
75
90
 
76
- render_block(0) { @theme.dim(usage_line(usage, session)) }
91
+ flush_prose
92
+ @prose_gap_pending = true
93
+ @io.puts
94
+ text = (@wrapper << usage_line(usage, session)) + @wrapper.flush
95
+ @io.print(@theme.dim(text)) unless text.empty?
96
+ @io.flush
77
97
  end
78
98
 
79
99
  # @rbs return: void
@@ -115,13 +135,14 @@ class Riffer::Rig::Terminal::Renderer
115
135
 
116
136
  # @rbs return: void
117
137
  def end_turn
138
+ flush_prose
118
139
  @smoother.finish
119
140
  @cursor.show
120
141
  end
121
142
 
122
143
  # @rbs return: void
123
144
  def drain
124
- @smoother.drain
145
+ flush_prose
125
146
  end
126
147
 
127
148
  # @rbs message: Riffer::Messages::Base
@@ -130,9 +151,9 @@ class Riffer::Rig::Terminal::Renderer
130
151
  return unless message.is_a?(Riffer::Messages::Tool)
131
152
 
132
153
  open_tool_activity
133
- line = "↳ #{preview(message.content)}"
154
+ line = fit("↳ #{preview(message.content)}", TOOL_RESULT_INDENT)
134
155
  styled = message.error? ? @theme.red(line) : @theme.dim(line)
135
- @io.print(" #{styled}\n")
156
+ @io.print("#{' ' * TOOL_RESULT_INDENT}#{styled}\n")
136
157
  @io.flush
137
158
  end
138
159
 
@@ -167,7 +188,7 @@ class Riffer::Rig::Terminal::Renderer
167
188
  # @rbs &block: () -> String
168
189
  # @rbs return: void
169
190
  def render_block(indent, &)
170
- drain
191
+ flush_prose
171
192
  @io.puts
172
193
  @prose_gap_pending = true
173
194
  @io.puts((' ' * indent) + yield)
@@ -182,8 +203,10 @@ class Riffer::Rig::Terminal::Renderer
182
203
  if @prose_gap_pending
183
204
  @prose_gap_pending = false
184
205
  @io.print("\n")
206
+ @wrapper = new_wrapper
185
207
  end
186
- @smoother << content
208
+ emit = @wrapper << content
209
+ @smoother << emit unless emit.empty?
187
210
  end
188
211
 
189
212
  # @rbs indent: Integer
@@ -191,7 +214,7 @@ class Riffer::Rig::Terminal::Renderer
191
214
  # @rbs return: void
192
215
  def render_tool_activity(indent, &)
193
216
  open_tool_activity
194
- @io.puts((' ' * indent) + yield)
217
+ @io.puts((' ' * indent) + @theme.cyan(fit(yield, indent)))
195
218
  @io.flush
196
219
  end
197
220
 
@@ -201,7 +224,7 @@ class Riffer::Rig::Terminal::Renderer
201
224
  # group; the group stays open so the prose after it pays the closing gap.
202
225
  return if @prose_gap_pending
203
226
 
204
- drain
227
+ flush_prose
205
228
  @io.puts
206
229
  @prose_gap_pending = true
207
230
  end
@@ -224,7 +247,7 @@ class Riffer::Rig::Terminal::Renderer
224
247
  # @rbs return: String
225
248
  def format_arguments(arguments)
226
249
  parsed = JSON.parse(arguments)
227
- parsed.map { |key, value| "#{key}: #{value.inspect}" }.join(', ')
250
+ parsed.map { |key, value| "#{key}: #{elide(value.inspect, ARGUMENT_PREVIEW_LIMIT)}" }.join(', ')
228
251
  rescue JSON::ParserError
229
252
  arguments
230
253
  end
@@ -233,8 +256,58 @@ class Riffer::Rig::Terminal::Renderer
233
256
  # @rbs return: String
234
257
  def preview(content)
235
258
  first_line = content.to_s.lines.first.to_s.chomp
236
- return first_line if first_line.length <= RESULT_PREVIEW_LIMIT
259
+ elide(first_line, RESULT_PREVIEW_LIMIT)
260
+ end
261
+
262
+ # @rbs text: String
263
+ # @rbs limit: Integer
264
+ # @rbs return: String
265
+ def elide(text, limit)
266
+ return text if text.length <= limit
267
+ return '…' if limit < 1
268
+
269
+ "#{text[0, limit - 1]}…"
270
+ end
271
+
272
+ # Truncation is what keeps an indented line from wrapping: a wrapped
273
+ # continuation starts at column zero and destroys the prose > tool nesting.
274
+ # @rbs text: String
275
+ # @rbs indent: Integer
276
+ # @rbs return: String
277
+ def fit(text, indent)
278
+ width = detect_width
279
+ return text unless width
280
+
281
+ elide(text, width - indent)
282
+ end
283
+
284
+ # @rbs return: void
285
+ def flush_prose
286
+ emit = @wrapper.flush
287
+ @smoother << emit unless emit.empty?
288
+ @smoother.drain
289
+ end
290
+
291
+ # @rbs return: Riffer::Rig::Terminal::Wrapper
292
+ def new_wrapper
293
+ Riffer::Rig::Terminal::Wrapper.new(width: detect_width, indent: PROSE_INDENT)
294
+ end
295
+
296
+ # @rbs return: Integer?
297
+ def detect_width
298
+ @width || detected_width
299
+ end
237
300
 
238
- "#{first_line[0, RESULT_PREVIEW_LIMIT]}…"
301
+ # winsize raises on ttys with no queryable window size and some pty
302
+ # wrappers report zero columns; either way the real width is unknowable,
303
+ # and nil leaves every consumer un-fitted rather than mis-fitted.
304
+ # @rbs return: Integer?
305
+ def detected_width
306
+ return nil unless @io.tty?
307
+
308
+ width = @io.winsize[1]
309
+ width.positive? ? width : nil
310
+ rescue SystemCallError
311
+ nil
239
312
  end
240
313
  end
@@ -0,0 +1,103 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Riffer::Rig::Terminal::Wrapper
4
+ # @rbs @width: Integer?
5
+ # @rbs @indent: Integer
6
+ # @rbs @line: String
7
+
8
+ # @rbs width: Integer?
9
+ # @rbs indent: Integer
10
+ # @rbs return: void
11
+ def initialize(width:, indent:)
12
+ @width = width
13
+ @indent = indent
14
+ @line = +''
15
+ end
16
+
17
+ # @rbs text: String
18
+ # @rbs return: String
19
+ def <<(text)
20
+ @line << text
21
+ out = +''
22
+ while (logical = take_line)
23
+ out << physical_lines(logical)
24
+ end
25
+ out
26
+ end
27
+
28
+ # @rbs return: String
29
+ def flush
30
+ out = +''
31
+ out << physical_lines(@line) unless @line.strip.empty?
32
+ @line = +''
33
+ out
34
+ end
35
+
36
+ private
37
+
38
+ # @rbs return: String?
39
+ def take_line
40
+ if (index = @line.index("\n"))
41
+ @line.slice!(0, index + 1).to_s.chomp
42
+ elsif overfull?
43
+ take_overfull_head
44
+ end
45
+ end
46
+
47
+ # @rbs return: bool
48
+ def overfull?
49
+ width = @width
50
+ return false unless width
51
+
52
+ @line.length > width - @indent
53
+ end
54
+
55
+ # @rbs return: String
56
+ def take_overfull_head
57
+ limit = (@width || 0) - @indent
58
+ head = @line[0, limit].to_s
59
+ if (space = head.rindex(' '))
60
+ @line.slice!(0, space + 1)
61
+ head[0, space].to_s
62
+ else
63
+ @line.slice!(0, limit).to_s
64
+ end
65
+ end
66
+
67
+ # @rbs logical: String
68
+ # @rbs return: String
69
+ def physical_lines(logical)
70
+ return "\n" if logical.empty?
71
+
72
+ wrap_words(logical).map { |line| "#{indent}#{line}\n" }.join
73
+ end
74
+
75
+ # @rbs return: String
76
+ def indent
77
+ ' ' * @indent
78
+ end
79
+
80
+ # @rbs text: String
81
+ # @rbs return: Array[String]
82
+ def wrap_words(text)
83
+ width = @width
84
+ limit = width ? width - @indent : nil
85
+ return [text] unless limit
86
+
87
+ out = [] #: Array[String]
88
+ current = nil #: String?
89
+ text.split.each do |word|
90
+ if current
91
+ if current.length + 1 + word.length <= limit
92
+ current = "#{current} #{word}"
93
+ next
94
+ end
95
+ out << current
96
+ end
97
+ out << word.slice!(0, limit).to_s while word.length > limit
98
+ current = word unless word.empty?
99
+ end
100
+ out << current if current
101
+ out
102
+ end
103
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'fileutils'
5
+
6
+ module Riffer::Rig::Trust
7
+ extend self
8
+
9
+ # @rbs path: String
10
+ # @rbs return: Hash[String, bool]
11
+ def read(path)
12
+ return {} unless File.file?(path)
13
+
14
+ source = JSON.parse(File.read(path))
15
+ source.is_a?(Hash) ? source.select { |_file, decision| [true, false].include?(decision) } : {}
16
+ rescue JSON::ParserError
17
+ {}
18
+ end
19
+
20
+ # @rbs path: String
21
+ # @rbs file: String
22
+ # @rbs decision: bool
23
+ # @rbs return: void
24
+ def store(path, file, decision)
25
+ write(path, read(path).merge(file => decision))
26
+ end
27
+
28
+ private
29
+
30
+ # @rbs path: String
31
+ # @rbs document: Hash[String, bool]
32
+ # @rbs return: void
33
+ def write(path, document)
34
+ FileUtils.mkdir_p(File.dirname(path), mode: 0o700)
35
+ File.write(path, JSON.pretty_generate(document))
36
+ end
37
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Riffer
4
4
  module Rig
5
- VERSION = '0.7.0'
5
+ VERSION = '0.8.0'
6
6
  end
7
7
  end
@@ -10,6 +10,10 @@ class Riffer::Rig::Loader
10
10
 
11
11
  NO_MODEL: String
12
12
 
13
+ EXTENSION_FEATURE: String
14
+
15
+ @tracked_files: Array[String]
16
+
13
17
  @riffer_config: Riffer::Config
14
18
 
15
19
  @home: String
@@ -20,6 +24,9 @@ class Riffer::Rig::Loader
20
24
 
21
25
  @cwd: String
22
26
 
27
+ # @dynamic tracked_files
28
+ attr_reader tracked_files: Array[String]
29
+
23
30
  # @rbs cwd: String
24
31
  # @rbs host: Riffer::Rig::Hosts::_Host
25
32
  # @rbs env: Riffer::Rig::Env | Riffer::Rig::Env::Invalid
@@ -53,6 +60,35 @@ class Riffer::Rig::Loader
53
60
 
54
61
  private
55
62
 
63
+ # @rbs autoload: bool
64
+ # @rbs return: Array[Riffer::Rig::Extension]
65
+ def load_rig_files: (bool autoload) -> Array[Riffer::Rig::Extension]
66
+
67
+ # @rbs autoload: bool
68
+ # @rbs return: Array[String]
69
+ def gem_extension_files: (bool autoload) -> Array[String]
70
+
71
+ # @rbs path: String
72
+ # @rbs return: bool
73
+ def trusted?: (String path) -> bool
74
+
75
+ # @rbs return: String
76
+ def trust_path: () -> String
77
+
78
+ # @rbs path: String
79
+ # @rbs track: bool
80
+ # @rbs return: Array[Riffer::Rig::Extension]
81
+ def load_file: (String path, track: bool) -> Array[Riffer::Rig::Extension]
82
+
83
+ # @rbs before_features: Array[String]
84
+ # @rbs path: String
85
+ # @rbs return: void
86
+ def track_loaded: (Array[String] before_features, String path) -> void
87
+
88
+ # @rbs feature: String
89
+ # @rbs return: bool
90
+ def local?: (String feature) -> bool
91
+
56
92
  # @rbs configured: String?
57
93
  # @rbs return: String
58
94
  def select_model: (String? configured) -> String
@@ -1,7 +1,7 @@
1
1
  # Generated from lib/riffer/rig/settings/document.rb with RBS::Inline
2
2
 
3
3
  class Riffer::Rig::Settings::Document
4
- # @dynamic model, reasoning, models, providers, disabled
4
+ # @dynamic model, reasoning, models, providers, disabled, autoload
5
5
  attr_reader model: String?
6
6
 
7
7
  attr_reader reasoning: String?
@@ -12,6 +12,8 @@ class Riffer::Rig::Settings::Document
12
12
 
13
13
  attr_reader disabled: Array[String]
14
14
 
15
+ attr_reader autoload: bool
16
+
15
17
  # @rbs source: Hash[Symbol, untyped]
16
18
  # @rbs return: void
17
19
  def initialize: (Hash[Symbol, untyped] source) -> void
@@ -3,6 +3,18 @@
3
3
  class Riffer::Rig::Terminal::Renderer
4
4
  RESULT_PREVIEW_LIMIT: Integer
5
5
 
6
+ ARGUMENT_PREVIEW_LIMIT: Integer
7
+
8
+ PROSE_INDENT: Integer
9
+
10
+ TOOL_CALL_INDENT: Integer
11
+
12
+ TOOL_RESULT_INDENT: Integer
13
+
14
+ @wrapper: Riffer::Rig::Terminal::Wrapper
15
+
16
+ @width: Integer?
17
+
6
18
  @prose_gap_pending: bool
7
19
 
8
20
  @cursor: Riffer::Rig::Terminal::Cursor
@@ -17,8 +29,9 @@ class Riffer::Rig::Terminal::Renderer
17
29
  # @rbs theme: Riffer::Rig::Terminal::Theme
18
30
  # @rbs smoother: Riffer::Rig::Terminal::Smoother | PassThroughSmoother
19
31
  # @rbs cursor: Riffer::Rig::Terminal::Cursor
32
+ # @rbs width: Integer?
20
33
  # @rbs return: void
21
- def initialize: (?io: IO, ?theme: Riffer::Rig::Terminal::Theme, ?smoother: Riffer::Rig::Terminal::Smoother | PassThroughSmoother, ?cursor: Riffer::Rig::Terminal::Cursor) -> void
34
+ def initialize: (?io: IO, ?theme: Riffer::Rig::Terminal::Theme, ?smoother: Riffer::Rig::Terminal::Smoother | PassThroughSmoother, ?cursor: Riffer::Rig::Terminal::Cursor, ?width: Integer?) -> void
22
35
 
23
36
  # @rbs event: Riffer::StreamEvents::TextDelta | Riffer::StreamEvents::ToolCallDone | Riffer::StreamEvents::Interrupt
24
37
  # @rbs return: void
@@ -123,4 +136,31 @@ class Riffer::Rig::Terminal::Renderer
123
136
  # @rbs content: String
124
137
  # @rbs return: String
125
138
  def preview: (String content) -> String
139
+
140
+ # @rbs text: String
141
+ # @rbs limit: Integer
142
+ # @rbs return: String
143
+ def elide: (String text, Integer limit) -> String
144
+
145
+ # Truncation is what keeps an indented line from wrapping: a wrapped
146
+ # continuation starts at column zero and destroys the prose > tool nesting.
147
+ # @rbs text: String
148
+ # @rbs indent: Integer
149
+ # @rbs return: String
150
+ def fit: (String text, Integer indent) -> String
151
+
152
+ # @rbs return: void
153
+ def flush_prose: () -> void
154
+
155
+ # @rbs return: Riffer::Rig::Terminal::Wrapper
156
+ def new_wrapper: () -> Riffer::Rig::Terminal::Wrapper
157
+
158
+ # @rbs return: Integer?
159
+ def detect_width: () -> Integer?
160
+
161
+ # winsize raises on ttys with no queryable window size and some pty
162
+ # wrappers report zero columns; either way the real width is unknowable,
163
+ # and nil leaves every consumer un-fitted rather than mis-fitted.
164
+ # @rbs return: Integer?
165
+ def detected_width: () -> Integer?
126
166
  end
@@ -0,0 +1,43 @@
1
+ # Generated from lib/riffer/rig/terminal/wrapper.rb with RBS::Inline
2
+
3
+ class Riffer::Rig::Terminal::Wrapper
4
+ @width: Integer?
5
+
6
+ @indent: Integer
7
+
8
+ @line: String
9
+
10
+ # @rbs width: Integer?
11
+ # @rbs indent: Integer
12
+ # @rbs return: void
13
+ def initialize: (width: Integer?, indent: Integer) -> void
14
+
15
+ # @rbs text: String
16
+ # @rbs return: String
17
+ def <<: (String text) -> String
18
+
19
+ # @rbs return: String
20
+ def flush: () -> String
21
+
22
+ private
23
+
24
+ # @rbs return: String?
25
+ def take_line: () -> String?
26
+
27
+ # @rbs return: bool
28
+ def overfull?: () -> bool
29
+
30
+ # @rbs return: String
31
+ def take_overfull_head: () -> String
32
+
33
+ # @rbs logical: String
34
+ # @rbs return: String
35
+ def physical_lines: (String logical) -> String
36
+
37
+ # @rbs return: String
38
+ def indent: () -> String
39
+
40
+ # @rbs text: String
41
+ # @rbs return: Array[String]
42
+ def wrap_words: (String text) -> Array[String]
43
+ end
@@ -0,0 +1,20 @@
1
+ # Generated from lib/riffer/rig/trust.rb with RBS::Inline
2
+
3
+ module Riffer::Rig::Trust
4
+ # @rbs path: String
5
+ # @rbs return: Hash[String, bool]
6
+ def read: (String path) -> Hash[String, bool]
7
+
8
+ # @rbs path: String
9
+ # @rbs file: String
10
+ # @rbs decision: bool
11
+ # @rbs return: void
12
+ def store: (String path, String file, bool decision) -> void
13
+
14
+ private
15
+
16
+ # @rbs path: String
17
+ # @rbs document: Hash[String, bool]
18
+ # @rbs return: void
19
+ def write: (String path, Hash[String, bool] document) -> void
20
+ end
@@ -0,0 +1,6 @@
1
+ # rbs-inline does not emit `extend self`, so without this reopen the module's
2
+ # methods aren't visible as singleton methods.
3
+
4
+ module Riffer::Rig::Trust
5
+ extend ::Riffer::Rig::Trust
6
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: riffer-rig
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jake Bottrall
@@ -200,10 +200,12 @@ files:
200
200
  - lib/riffer/rig/terminal/renderer.rb
201
201
  - lib/riffer/rig/terminal/smoother.rb
202
202
  - lib/riffer/rig/terminal/theme.rb
203
+ - lib/riffer/rig/terminal/wrapper.rb
203
204
  - lib/riffer/rig/tools/bash.rb
204
205
  - lib/riffer/rig/tools/edit.rb
205
206
  - lib/riffer/rig/tools/read.rb
206
207
  - lib/riffer/rig/tools/write.rb
208
+ - lib/riffer/rig/trust.rb
207
209
  - lib/riffer/rig/version.rb
208
210
  - sig/generated/riffer/rig.rbs
209
211
  - sig/generated/riffer/rig/bundled.rbs
@@ -272,10 +274,12 @@ files:
272
274
  - sig/generated/riffer/rig/terminal/renderer.rbs
273
275
  - sig/generated/riffer/rig/terminal/smoother.rbs
274
276
  - sig/generated/riffer/rig/terminal/theme.rbs
277
+ - sig/generated/riffer/rig/terminal/wrapper.rbs
275
278
  - sig/generated/riffer/rig/tools/bash.rbs
276
279
  - sig/generated/riffer/rig/tools/edit.rbs
277
280
  - sig/generated/riffer/rig/tools/read.rbs
278
281
  - sig/generated/riffer/rig/tools/write.rbs
282
+ - sig/generated/riffer/rig/trust.rbs
279
283
  - sig/generated/riffer/rig/version.rbs
280
284
  - sig/manual/riffer/rig.rbs
281
285
  - sig/manual/riffer/rig/cli.rbs
@@ -292,6 +296,7 @@ files:
292
296
  - sig/manual/riffer/rig/support.rbs
293
297
  - sig/manual/riffer/rig/terminal/banner.rbs
294
298
  - sig/manual/riffer/rig/tools.rbs
299
+ - sig/manual/riffer/rig/trust.rbs
295
300
  homepage: https://github.com/bottrall/riffer-rig
296
301
  licenses:
297
302
  - MIT