riffer-rig 0.14.0 → 0.15.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 +4 -4
- data/CHANGELOG.md +12 -0
- data/lib/riffer/rig/terminal/ticker.rb +1 -1
- data/lib/riffer/rig/terminal/turn_report.rb +96 -14
- data/lib/riffer/rig/version.rb +1 -1
- data/sig/generated/riffer/rig/terminal/turn_report.rbs +48 -5
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e1743d133b2e91f50f10a376bbb8cd6f2d21f4d6c2f90600d5415d4ec9047b26
|
|
4
|
+
data.tar.gz: c8131bfda29574b5c86acb1b1ebebfe0ec1dc5cc82ff7c8c8cca5410bb7b34d0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 46930dae154e4a07916c0f1391e3f44419a7e385f5d31f02509a9740276ca6bfc993efb4f0e95695ad439045f69d9c3a74e344a43af7f83a75afdb6bd94f1e58
|
|
7
|
+
data.tar.gz: 18ce4fe1003d1767a234936fae81fb921c49461cefb7f6516bf051047734b68580bfc124803d353296a71daa9919f5f77805c83bc3c2599c9e17e8b2650b4b1d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.15.0](https://github.com/bottrall/riffer-rig/compare/v0.14.0...v0.15.0) (2026-10-18)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **terminal:** style the turn report like the status bar ([#562](https://github.com/bottrall/riffer-rig/issues/562)) ([710bd34](https://github.com/bottrall/riffer-rig/commit/710bd34b993d2743a78935ebbf3116d50cc063d7))
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* label the status-bar step counter as steps, not turns ([#560](https://github.com/bottrall/riffer-rig/issues/560)) ([80e6b2b](https://github.com/bottrall/riffer-rig/commit/80e6b2b60756ba4896878ef7df736511a3ec2ed0))
|
|
14
|
+
|
|
3
15
|
## [0.14.0](https://github.com/bottrall/riffer-rig/compare/v0.13.0...v0.14.0) (2026-10-18)
|
|
4
16
|
|
|
5
17
|
|
|
@@ -83,7 +83,7 @@ class Riffer::Rig::Terminal::Ticker
|
|
|
83
83
|
estimate = @unmetered / CHARS_PER_TOKEN
|
|
84
84
|
Riffer::Rig::Terminal::StatusBar.working(
|
|
85
85
|
glyph: Riffer::Rig::Terminal::Spinner.call(@tick),
|
|
86
|
-
state: stats.steps.zero? ? '' : "
|
|
86
|
+
state: stats.steps.zero? ? '' : "step #{stats.steps}",
|
|
87
87
|
clock: clock(stats.wall_time),
|
|
88
88
|
up_tokens: usage&.input_tokens || 0,
|
|
89
89
|
down_tokens: (usage&.output_tokens || 0) + estimate,
|
|
@@ -9,14 +9,21 @@ module Riffer::Rig::Terminal::TurnReport
|
|
|
9
9
|
|
|
10
10
|
COLUMN_HEAD = /\A.*\S {2,}(?=\S)/ #: Regexp
|
|
11
11
|
|
|
12
|
+
VISIBLE = /\S/ #: Regexp
|
|
13
|
+
|
|
12
14
|
# @rbs turn: Riffer::Rig::Terminal::TurnReport::_Turn
|
|
13
15
|
# @rbs session: Riffer::Providers::TokenUsage?
|
|
14
16
|
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
15
17
|
# @rbs width: Integer?
|
|
16
18
|
# @rbs return: String
|
|
17
19
|
def call(turn, session, theme:, width:)
|
|
18
|
-
closing =
|
|
19
|
-
|
|
20
|
+
closing =
|
|
21
|
+
if turn.interrupted?
|
|
22
|
+
theme.dim(wrap(INTERRUPTED, width))
|
|
23
|
+
else
|
|
24
|
+
footer(turn.stats, session, theme: theme, width: width)
|
|
25
|
+
end
|
|
26
|
+
blocks = [*answer(turn.answer, theme: theme, width: width), closing]
|
|
20
27
|
blocks.map { |block| "\n#{block}\n" }.join
|
|
21
28
|
end
|
|
22
29
|
|
|
@@ -68,33 +75,108 @@ module Riffer::Rig::Terminal::TurnReport
|
|
|
68
75
|
|
|
69
76
|
# @rbs stats: Riffer::Rig::Terminal::TurnBuffer::Stats
|
|
70
77
|
# @rbs session: Riffer::Providers::TokenUsage?
|
|
78
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
79
|
+
# @rbs width: Integer?
|
|
71
80
|
# @rbs return: String
|
|
72
|
-
def footer(stats, session)
|
|
81
|
+
def footer(stats, session, theme:, width:)
|
|
82
|
+
parts = segments(stats, session)
|
|
83
|
+
paint(wrap(parts.map(&:first).join(' · '), width), owners(parts), theme)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# @rbs stats: Riffer::Rig::Terminal::TurnBuffer::Stats
|
|
87
|
+
# @rbs session: Riffer::Providers::TokenUsage?
|
|
88
|
+
# @rbs return: Array[[String, Symbol]]
|
|
89
|
+
def segments(stats, session)
|
|
73
90
|
usage = stats.usage
|
|
74
91
|
minutes, seconds = stats.wall_time.to_i.divmod(60)
|
|
75
92
|
[
|
|
76
|
-
"#{stats.steps} #{stats.steps == 1 ? 'step' : 'steps'}",
|
|
77
|
-
format('%<minutes>02d:%<seconds>02d', minutes: minutes, seconds: seconds),
|
|
78
|
-
*(
|
|
79
|
-
*(
|
|
80
|
-
]
|
|
93
|
+
["#{stats.steps} #{stats.steps == 1 ? 'step' : 'steps'}", :dim],
|
|
94
|
+
[format('%<minutes>02d:%<seconds>02d', minutes: minutes, seconds: seconds), :dim],
|
|
95
|
+
*usage_segments(usage),
|
|
96
|
+
*session_segments(session)
|
|
97
|
+
]
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
# @rbs usage: Riffer::Providers::TokenUsage?
|
|
101
|
+
# @rbs return: Array[[String, Symbol]]
|
|
102
|
+
def usage_segments(usage)
|
|
103
|
+
return [] unless usage
|
|
104
|
+
|
|
105
|
+
[*tokens(usage), *cost(usage)]
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# @rbs session: Riffer::Providers::TokenUsage?
|
|
109
|
+
# @rbs return: Array[[String, Symbol]]
|
|
110
|
+
def session_segments(session)
|
|
111
|
+
return [] unless session
|
|
112
|
+
|
|
113
|
+
[["session #{Riffer::Rig::Terminal::Count.call(session.total_tokens)} tok", :dim], *cost(session)]
|
|
81
114
|
end
|
|
82
115
|
|
|
83
116
|
# @rbs usage: Riffer::Providers::TokenUsage
|
|
84
|
-
# @rbs return: Array[String]
|
|
117
|
+
# @rbs return: Array[[String, Symbol]]
|
|
85
118
|
def tokens(usage)
|
|
86
119
|
cache = { cache_write: usage.cache_write_tokens, cache_read: usage.cache_read_tokens }
|
|
87
120
|
[
|
|
88
|
-
"↑#{usage.input_tokens}",
|
|
89
|
-
"↓#{usage.output_tokens}",
|
|
90
|
-
*cache.filter_map
|
|
121
|
+
["↑#{Riffer::Rig::Terminal::Count.call(usage.input_tokens)}", :dim],
|
|
122
|
+
["↓#{Riffer::Rig::Terminal::Count.call(usage.output_tokens)}", :dim],
|
|
123
|
+
*cache.filter_map do |name, count|
|
|
124
|
+
["#{name}:#{Riffer::Rig::Terminal::Count.call(count)}", :dim] if count&.positive?
|
|
125
|
+
end
|
|
91
126
|
]
|
|
92
127
|
end
|
|
93
128
|
|
|
94
129
|
# @rbs usage: Riffer::Providers::TokenUsage
|
|
95
|
-
# @rbs return: String
|
|
130
|
+
# @rbs return: Array[[String, Symbol]]
|
|
96
131
|
def cost(usage)
|
|
97
132
|
amount = usage.cost
|
|
98
|
-
format('~$%.4f', amount)
|
|
133
|
+
amount ? [[format('~$%.4f', amount), :cyan]] : []
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
# A separator's dot is dim, so a colour run carries across it into the next
|
|
137
|
+
# segment.
|
|
138
|
+
# @rbs parts: Array[[String, Symbol]]
|
|
139
|
+
# @rbs return: Array[Symbol]
|
|
140
|
+
def owners(parts)
|
|
141
|
+
parts.flat_map.with_index do |(text, role), index|
|
|
142
|
+
owned = [role] * text.scan(VISIBLE).size
|
|
143
|
+
owned << :dim unless index == parts.length - 1
|
|
144
|
+
owned
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# The Wrapper moves, drops and rewrites whitespace but never a visible
|
|
149
|
+
# character, so the nth visible character of a wrapped line is the nth one
|
|
150
|
+
# the segments supplied — which is why the colours are painted after the
|
|
151
|
+
# wrap, where a span can never be cut in two.
|
|
152
|
+
# @rbs line: String
|
|
153
|
+
# @rbs owners: Array[Symbol]
|
|
154
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
155
|
+
# @rbs return: String
|
|
156
|
+
def paint(line, owners, theme)
|
|
157
|
+
chars = line.chars
|
|
158
|
+
owner_at = chars.each_index.select { |index| chars.fetch(index).match?(VISIBLE) }.zip(owners).to_h
|
|
159
|
+
slots = chars.each_index.map { |index| owner_at[index] }
|
|
160
|
+
cells = nearest(slots).zip(nearest(slots.reverse).reverse).map { |left, right| left == right ? left : nil }
|
|
161
|
+
runs = cells.zip(chars).chunk_while { |(left, _), (right, _)| left == right }
|
|
162
|
+
runs.map { |run| color(run.map(&:last).join, run.fetch(0).first, theme) }.join
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# @rbs slots: Array[Symbol?]
|
|
166
|
+
# @rbs return: Array[Symbol?]
|
|
167
|
+
def nearest(slots)
|
|
168
|
+
slots.each_with_object([]) { |slot, filled| filled << (slot || filled.last) }
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
# @rbs text: String
|
|
172
|
+
# @rbs role: Symbol?
|
|
173
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
174
|
+
# @rbs return: String
|
|
175
|
+
def color(text, role, theme)
|
|
176
|
+
case role
|
|
177
|
+
when :dim then theme.dim(text)
|
|
178
|
+
when :cyan then theme.cyan(text)
|
|
179
|
+
else text
|
|
180
|
+
end
|
|
99
181
|
end
|
|
100
182
|
end
|
data/lib/riffer/rig/version.rb
CHANGED
|
@@ -7,6 +7,8 @@ module Riffer::Rig::Terminal::TurnReport
|
|
|
7
7
|
|
|
8
8
|
COLUMN_HEAD: Regexp
|
|
9
9
|
|
|
10
|
+
VISIBLE: Regexp
|
|
11
|
+
|
|
10
12
|
# @rbs turn: Riffer::Rig::Terminal::TurnReport::_Turn
|
|
11
13
|
# @rbs session: Riffer::Providers::TokenUsage?
|
|
12
14
|
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
@@ -39,14 +41,55 @@ module Riffer::Rig::Terminal::TurnReport
|
|
|
39
41
|
|
|
40
42
|
# @rbs stats: Riffer::Rig::Terminal::TurnBuffer::Stats
|
|
41
43
|
# @rbs session: Riffer::Providers::TokenUsage?
|
|
44
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
45
|
+
# @rbs width: Integer?
|
|
42
46
|
# @rbs return: String
|
|
43
|
-
def footer: (Riffer::Rig::Terminal::TurnBuffer::Stats stats, Riffer::Providers::TokenUsage? session) -> String
|
|
47
|
+
def footer: (Riffer::Rig::Terminal::TurnBuffer::Stats stats, Riffer::Providers::TokenUsage? session, theme: Riffer::Rig::Terminal::Theme, width: Integer?) -> String
|
|
48
|
+
|
|
49
|
+
# @rbs stats: Riffer::Rig::Terminal::TurnBuffer::Stats
|
|
50
|
+
# @rbs session: Riffer::Providers::TokenUsage?
|
|
51
|
+
# @rbs return: Array[[String, Symbol]]
|
|
52
|
+
def segments: (Riffer::Rig::Terminal::TurnBuffer::Stats stats, Riffer::Providers::TokenUsage? session) -> Array[[ String, Symbol ]]
|
|
53
|
+
|
|
54
|
+
# @rbs usage: Riffer::Providers::TokenUsage?
|
|
55
|
+
# @rbs return: Array[[String, Symbol]]
|
|
56
|
+
def usage_segments: (Riffer::Providers::TokenUsage? usage) -> Array[[ String, Symbol ]]
|
|
57
|
+
|
|
58
|
+
# @rbs session: Riffer::Providers::TokenUsage?
|
|
59
|
+
# @rbs return: Array[[String, Symbol]]
|
|
60
|
+
def session_segments: (Riffer::Providers::TokenUsage? session) -> Array[[ String, Symbol ]]
|
|
44
61
|
|
|
45
62
|
# @rbs usage: Riffer::Providers::TokenUsage
|
|
46
|
-
# @rbs return: Array[String]
|
|
47
|
-
def tokens: (Riffer::Providers::TokenUsage usage) -> Array[String]
|
|
63
|
+
# @rbs return: Array[[String, Symbol]]
|
|
64
|
+
def tokens: (Riffer::Providers::TokenUsage usage) -> Array[[ String, Symbol ]]
|
|
48
65
|
|
|
49
66
|
# @rbs usage: Riffer::Providers::TokenUsage
|
|
50
|
-
# @rbs return: String
|
|
51
|
-
def cost: (Riffer::Providers::TokenUsage usage) -> String
|
|
67
|
+
# @rbs return: Array[[String, Symbol]]
|
|
68
|
+
def cost: (Riffer::Providers::TokenUsage usage) -> Array[[ String, Symbol ]]
|
|
69
|
+
|
|
70
|
+
# A separator's dot is dim, so a colour run carries across it into the next
|
|
71
|
+
# segment.
|
|
72
|
+
# @rbs parts: Array[[String, Symbol]]
|
|
73
|
+
# @rbs return: Array[Symbol]
|
|
74
|
+
def owners: (Array[[ String, Symbol ]] parts) -> Array[Symbol]
|
|
75
|
+
|
|
76
|
+
# The Wrapper moves, drops and rewrites whitespace but never a visible
|
|
77
|
+
# character, so the nth visible character of a wrapped line is the nth one
|
|
78
|
+
# the segments supplied — which is why the colours are painted after the
|
|
79
|
+
# wrap, where a span can never be cut in two.
|
|
80
|
+
# @rbs line: String
|
|
81
|
+
# @rbs owners: Array[Symbol]
|
|
82
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
83
|
+
# @rbs return: String
|
|
84
|
+
def paint: (String line, Array[Symbol] owners, Riffer::Rig::Terminal::Theme theme) -> String
|
|
85
|
+
|
|
86
|
+
# @rbs slots: Array[Symbol?]
|
|
87
|
+
# @rbs return: Array[Symbol?]
|
|
88
|
+
def nearest: (Array[Symbol?] slots) -> Array[Symbol?]
|
|
89
|
+
|
|
90
|
+
# @rbs text: String
|
|
91
|
+
# @rbs role: Symbol?
|
|
92
|
+
# @rbs theme: Riffer::Rig::Terminal::Theme
|
|
93
|
+
# @rbs return: String
|
|
94
|
+
def color: (String text, Symbol? role, Riffer::Rig::Terminal::Theme theme) -> String
|
|
52
95
|
end
|