pwn 0.5.751 → 0.5.752

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: 370b89e2788788896b95041a37ef33082bf4e32f753deae04778b27262660d37
4
- data.tar.gz: 397bc93f10ee8a9b9f891c447b47b268b6d6526005762b97fd8cc94102c62053
3
+ metadata.gz: 9f090409a234eeffe46292971f044bd3f6109da51d03e8fae5909d63aa625808
4
+ data.tar.gz: '082fcd50fde34da2c0bea93a7292a4925fd017e2526e07d6fcf8c9b29bb5db8c'
5
5
  SHA512:
6
- metadata.gz: 9c92bca139bd4a6b8c6e8ce32a0ce79505ecc495586f9aa36e89a829c1007508f380e1c84603dfd19ddbba7b7c2dffececdedc3232efd93dc87affc3270119db
7
- data.tar.gz: 1ab472b60a58d992e9513d9e8a5d668ce6b543bc83109c8c04a6ac563d71baae399ea47184e5cc145bd5aa01a750d00f2ec273456cc40077f205c996726e513f
6
+ metadata.gz: 612c4b3a4d8f8311e231c2bbcceee5cd61280134157adc9f2132beb438ef65bbb698ed949aca56d19412414ed10c8540a1feab8327aaf14abcc71c33c2b23ccf
7
+ data.tar.gz: '09b64fed3ccd1e064a28b4874005e73549c8fbd7d60017dd6c552cce7bd6b45577dfb9202d7aecc54aa13456a2cdc847ef021850d387139bfa064fdc88fbc7d5'
@@ -31,7 +31,9 @@ its seeded autonomous flight is decorative, not player-controlled.
31
31
  Its framed width in terminal cells equals the complete header's height in rows;
32
32
  the interior canvas is `(header height - 2)` cells on each side. This is a
33
33
  cell-square, not a pixel-square—terminal glyph cells are usually taller than wide.
34
- Falling blocks fill the entire interior below the PWN wordmark, including the
34
+ The animation pane has no wordmark; its former label row belongs to gameplay.
35
+ The main `pwn-ai` header title and full-screen static banners are unchanged.
36
+ Falling blocks fill the entire interior, including the
35
37
  bottom two quadrants. Each logical block occupies one horizontal half-cell from
36
38
  spawn through landing and locking. This deliberately replaces independent
37
39
  quarter-cell blocks: a terminal cell has only a foreground and background, so
@@ -51,11 +53,13 @@ changing the active session selects again. Frames advance at the banner API's
51
53
  blocks/snake) using monotonic time in the existing render loop—no extra animation
52
54
  thread, input reader or provider call. This is decoration, not progress or
53
55
  telemetry. The frame keeps the existing border/title theme roles. Artwork comes
54
- from `PWN::Banner.mini_cells` with dedicated foreground/background curses pairs,
56
+ from `PWN::Banner.mini_cells(branding: false)` with dedicated foreground/background curses pairs,
55
57
  not ANSI output or theme overrides. `NO_COLOR` and terminals with too few color
56
58
  pairs retain occupied geometry in monochrome (two differently colored occupied
57
59
  halves become a full block, not a half-block with its background lost). The `mini_frame` ASCII API
58
- retains its 60-frame, 0.1-second loops for other callers. Colored replays contain
60
+ retains its 60-frame, 0.1-second loops for other callers. Both miniature APIs
61
+ default to their legacy branding; `branding: false` reclaims the label row and
62
+ leaves undersized fallback panes blank. Colored replays contain
59
63
  1800 frames (90 seconds for Pong/Asteroids, 180 for blocks/snake), use a local
60
64
  per-session seed, and share a bounded six-replay cache. Settings
61
65
  wrap in the right-hand region without losing their label colors. A bounded,
@@ -12,7 +12,7 @@ metadata:
12
12
 
13
13
  # PWN::Banner
14
14
 
15
- Static banners and pure, PWN-branded retro ASCII/color loops: falling_blocks, snake, pong, and asteroids. mini_frame returns fresh rows on a borderless canvas; use equal width and height (5..16) for complete square artwork. Dimensions clamp to 0..16 (colored blocks: 0..64), with tiny panes showing a wordmark. The caller samples mini_names once per session and advances the explicit frame index every mini_frame_seconds(name:) (0.05 for Pong/Asteroids, 0.1 otherwise). mini_cells replays 1800 seeded gameplay frames (MINI_FRAME_COUNT); mini_frame retains its legacy 60-frame ASCII loop. These are decorative game simulations, not interactive games or telemetry. mini_cells uses local Random.new with seed 73 by default; callers may keep a different integer seed per session. Six immutable replays are cached. Tetrominoes stack and clear; snake pursues food and grows; Pong rallies include imperfect paddle tracking, misses and score pips between serves. Blocks use horizontal half-cells with independent foreground/background colors, filling the pane below PWN (up to 64 cells). Other games retain quadrant pixels; snake stays centered with food/head color priority. White line-clear flashes and game-over/reset wipes are intentional. Pong uses half-cell motion and one-cell-high paddles without speeding up play. Asteroids uses five-pixel cyan arrowheads on a half-cell grid, sparse small white rocks, yellow shots and red thrust; wrapped collisions split real rocks. Static Banner modules autoload only when needed. For more information, see: http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html
15
+ Static banners and pure, PWN-branded retro ASCII/color loops: falling_blocks, snake, pong, and asteroids. mini_frame returns fresh rows on a borderless canvas; use equal width and height (5..16) for complete square artwork. Dimensions clamp to 0..16 (colored blocks: 0..64). Set branding: false for an unbranded pane with the wordmark row reclaimed for play; tiny panes then stay blank. The caller samples mini_names once per session and advances the explicit frame index every mini_frame_seconds(name:) (0.05 for Pong/Asteroids, 0.1 otherwise). mini_cells replays 1800 seeded gameplay frames (MINI_FRAME_COUNT); mini_frame retains its legacy 60-frame ASCII loop. These are decorative game simulations, not interactive games or telemetry. mini_cells uses local Random.new with seed 73 by default; callers may keep a different integer seed per session. Six immutable replays are cached. Tetrominoes stack and clear; snake pursues food and grows; Pong rallies include imperfect paddle tracking, misses and score pips between serves. Blocks use horizontal half-cells with independent foreground/background colors, filling the pane below PWN (up to 64 cells). Other games retain quadrant pixels; snake stays centered with food/head color priority. White line-clear flashes and game-over/reset wipes are intentional. Pong uses half-cell motion and one-cell-high paddles without speeding up play. Asteroids uses five-pixel cyan arrowheads on a half-cell grid, sparse small white rocks, yellow shots and red thrust; wrapped collisions split real rocks. Static Banner modules autoload only when needed. For more information, see: http://www.rubyinside.com/ruby-techniques-revealed-autoload-1652.html
16
16
 
17
17
  ## When to use
18
18
 
data/lib/pwn/banner.rb CHANGED
@@ -4,7 +4,8 @@ module PWN
4
4
  # Static banners and pure, PWN-branded retro ASCII/color loops: falling_blocks,
5
5
  # snake, pong, and asteroids. mini_frame returns fresh rows on a borderless canvas;
6
6
  # use equal width and height (5..16) for complete square artwork. Dimensions
7
- # clamp to 0..16 (colored blocks: 0..64), with tiny panes showing a wordmark. The caller
7
+ # clamp to 0..16 (colored blocks: 0..64). Set branding: false for an unbranded
8
+ # pane with the wordmark row reclaimed for play; tiny panes then stay blank. The caller
8
9
  # samples mini_names once per session and advances the explicit frame index
9
10
  # every mini_frame_seconds(name:) (0.05 for Pong/Asteroids, 0.1 otherwise).
10
11
  # mini_cells replays 1800 seeded gameplay
@@ -98,7 +99,8 @@ module PWN
98
99
  # name: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',
99
100
  # frame: 'optional - integer frame index, defaults to zero and wraps at 60',
100
101
  # width: 'optional - output columns clamped to zero through 16, defaults to 16',
101
- # height: 'optional - output rows clamped to zero through 16, defaults to 16'
102
+ # height: 'optional - output rows clamped to zero through 16, defaults to 16',
103
+ # branding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'
102
104
  # )
103
105
 
104
106
  public_class_method def self.mini_frame(opts = {})
@@ -110,12 +112,16 @@ module PWN
110
112
  height = (opts[:height] || MINI_HEIGHT).to_i.clamp(0, MINI_HEIGHT)
111
113
  return [] if width.zero? || height.zero?
112
114
 
115
+ branding = opts[:branding] != false
116
+ return Array.new(height) { ' ' * width } if !branding && (width < 5 || height < 5)
117
+
118
+ height += 1 unless branding
113
119
  rows = Array.new(height) { ' ' * width }
114
120
  rows[0] = 'PWN'[0, width].center(width)
115
121
  return rows if width < 5 || height < 5
116
122
 
117
123
  send("mini_#{name}", rows: rows, phase: phase, width: width, height: height)
118
- rows
124
+ branding ? rows : rows.drop(1)
119
125
  end
120
126
 
121
127
  # Supported Method Parameters::
@@ -150,7 +156,8 @@ module PWN
150
156
  # frame: 'optional - integer index, defaults to zero and wraps at 1800',
151
157
  # width: 'optional - columns clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',
152
158
  # height: 'optional - rows clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',
153
- # seed: 'optional - integer local PRNG seed, defaults to 73; retain per session'
159
+ # seed: 'optional - integer local PRNG seed, defaults to 73; retain per session',
160
+ # branding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'
154
161
  # )
155
162
 
156
163
  public_class_method def self.mini_cells(opts = {})
@@ -163,10 +170,14 @@ module PWN
163
170
  height = (opts[:height] || MINI_HEIGHT).to_i.clamp(0, limit)
164
171
  return [] if width.zero? || height.zero?
165
172
 
173
+ branding = opts[:branding] != false
174
+ # Simulate one extra row before removing the legacy label, so every output
175
+ # row belongs to gameplay without changing the public dimension limits.
166
176
  rows = if width < 5 || height < 5
167
- ['PWN'[0, width].center(width)] + Array.new(height - 1) { ' ' * width }
177
+ [branding ? 'PWN'[0, width].center(width) : ' ' * width] + Array.new(height - 1) { ' ' * width }
168
178
  else
169
- mini_replay(name: name, width: width, height: height, seed: (opts[:seed] || MINI_SEED).to_i)[phase][:rows]
179
+ replay = mini_replay(name: name, width: width, height: height + (branding ? 0 : 1), seed: (opts[:seed] || MINI_SEED).to_i)
180
+ branding ? replay[phase][:rows] : replay[phase][:rows].drop(1)
170
181
  end
171
182
  rows.map do |row|
172
183
  row.chars.map do |pixel|
@@ -823,7 +834,8 @@ module PWN
823
834
  name: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',
824
835
  frame: 'optional - integer frame index, defaults to zero and wraps at 60',
825
836
  width: 'optional - columns clamped to zero through 16; defaults to 16',
826
- height: 'optional - rows clamped to zero through 16; defaults to 16'
837
+ height: 'optional - rows clamped to zero through 16; defaults to 16',
838
+ branding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'
827
839
  )
828
840
 
829
841
  # Return fresh Unicode block cells: { glyph:, foreground:, background: }.
@@ -838,7 +850,8 @@ module PWN
838
850
  frame: 'optional - integer frame index, defaults to zero and wraps at 1800',
839
851
  width: 'optional - columns clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',
840
852
  height: 'optional - rows clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',
841
- seed: 'optional - integer local PRNG seed, defaults to 73; retain per session'
853
+ seed: 'optional - integer local PRNG seed, defaults to 73; retain per session',
854
+ branding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'
842
855
  )
843
856
 
844
857
  # Run welcome and return its result
@@ -1042,7 +1042,7 @@ module PWN
1042
1042
  put(top + row, left + box_width - 1, '│', color)
1043
1043
  end
1044
1044
  put(top + height - 1, left, "╰#{'─' * (box_width - 2)}╯", color)
1045
- put(top, left + 2, fit(" #{title} ", box_width - 4), tone(:title))
1045
+ put(top, left + 2, fit(" #{title} ", box_width - 4), tone(:title)) unless title.empty?
1046
1046
  end
1047
1047
 
1048
1048
  def seed_request_history
@@ -1138,9 +1138,9 @@ module PWN
1138
1138
  end
1139
1139
  cadence = cells ? @banner_frame_seconds : PWN::Banner::MINI_FRAME_SECONDS
1140
1140
  frame = ((now - @banner_started) / cadence).floor % PWN::Banner::MINI_FRAME_COUNT
1141
- return PWN::Banner.mini_cells(name: @banner_name, frame: frame, width: size, height: size, seed: @banner_seed) if cells
1141
+ return PWN::Banner.mini_cells(name: @banner_name, frame: frame, width: size, height: size, seed: @banner_seed, branding: false) if cells
1142
1142
 
1143
- art = PWN::Banner.mini_frame(name: @banner_name, frame: frame, width: size, height: size)
1143
+ art = PWN::Banner.mini_frame(name: @banner_name, frame: frame, width: size, height: size, branding: false)
1144
1144
  canvas = Array.new(size) { ' ' * size }
1145
1145
  top = (size - art.length) / 2
1146
1146
  art.each_with_index { |row, index| canvas[top + index] = row.center(size) }
@@ -1208,7 +1208,7 @@ module PWN
1208
1208
  put(1, @header_text_column, fit("#{state} · #{elapsed} · #{scroll_status}", @header_text_width), tone(:status))
1209
1209
  visible.each_with_index { |spans, index| put_spans(2 + index, @header_text_column, spans) }
1210
1210
  if @header_pane_height
1211
- box(0, 0, height, height, 'PWN')
1211
+ box(0, 0, height, height, '')
1212
1212
  draw_banner(height - 2)
1213
1213
  end
1214
1214
  height
data/lib/pwn/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PWN
4
- VERSION = '0.5.751'
4
+ VERSION = '0.5.752'
5
5
  end
@@ -3,6 +3,29 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe PWN::Banner do
6
+ it 'reclaims the wordmark row for unbranded games and leaves tiny panes blank' do
7
+ described_class.mini_names.product([1, 3, 5, 8, 16]).each do |name, size|
8
+ [0, 6, 100, 1799].each do |frame|
9
+ args = { name: name, width: size, height: size, frame: frame, branding: false }
10
+ cells = described_class.mini_cells(**args)
11
+ ascii = described_class.mini_frame(**args)
12
+ expect(cells.length).to eq(size)
13
+ expect(cells.map(&:length)).to all(eq(size))
14
+ expect(cells.flatten.map { |cell| cell[:glyph] }.join).not_to match(/[PWN]/)
15
+ expect(ascii.length).to eq(size)
16
+ expect(ascii.map(&:length)).to all(eq(size))
17
+ expect(ascii.join).not_to match(/[PWN]/)
18
+ next if size < 5
19
+
20
+ replay = described_class.send(:mini_replay, name: name, width: size, height: size + 1, seed: 73)
21
+ expected = replay[frame][:rows].drop(1).map do |row|
22
+ row.chars.map { |pixel| described_class::MINI_PIXELS.fetch(pixel).first }.join
23
+ end
24
+ expect(cells.map { |row| row.map { |cell| cell[:glyph] }.join }).to eq(expected)
25
+ end
26
+ end
27
+ end
28
+
6
29
  def block_colors(rows)
7
30
  rows.flat_map do |row|
8
31
  [0, 2].map do |bit|
@@ -31,9 +54,9 @@ describe PWN::Banner do
31
54
 
32
55
  it 'keeps every active tetromino color beside the stack throughout its fall and lock' do
33
56
  rotations = Hash.new { |hash, key| hash[key] = [] }
34
- [5, 8, 16, 20].product([1, 73, 74]).each do |size, seed|
35
- args = { name: :falling_blocks, width: size, height: size, seed: seed }
36
- frames = described_class.send(:mini_replay, **args)
57
+ [5, 8, 16, 20].product([1, 73, 74], [true, false]).each do |size, seed, branding|
58
+ args = { name: :falling_blocks, width: size, height: size, seed: seed, branding: branding }
59
+ frames = described_class.send(:mini_replay, **args, height: size + (branding ? 0 : 1))
37
60
  frames.each_with_index do |frame, index|
38
61
  next unless frame[:state][:active]
39
62
 
@@ -45,13 +68,17 @@ describe PWN::Banner do
45
68
  points.each { |x, y| expected[y][x] = color }
46
69
  expect(block_colors(frame[:rows].drop(1))).to eq(expected)
47
70
  points.each do |x, y|
48
- cell = cells[1 + (y / 2)][x]
71
+ expect(x).to be_between(0, size - 1)
72
+ expect(y).to be_between(0, ((size - (branding ? 1 : 0)) * 2) - 1)
73
+ cell = cells[(branding ? 1 : 0) + (y / 2)][x]
49
74
  mask = ' ▘▝▀▖▌▞▛▗▚▐▜▄▙▟█'.index(cell[:glyph])
50
75
  actual = mask[(y % 2) * 2] == 1 ? cell[:foreground] : cell[:background]
51
76
  expect(actual).to eq(color)
52
77
  end
53
78
  next unless frames[index + 1][:event] == :lock
54
79
 
80
+ stack = frame[:state][:stack]
81
+ expect(points.any? { |x, y| y == stack.length - 1 || stack[y + 1][x] != ' ' }).to be(true)
55
82
  expect(frames[index + 1][:rows]).to eq(frame[:rows])
56
83
  expect(described_class.mini_cells(**args, frame: index + 1)).to eq(cells)
57
84
  rotations[type] << points.map { |x, y| [x - points.map(&:first).min, y - points.map(&:last).min] }.sort
@@ -425,6 +425,25 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
425
425
  PWN::Env[:ai] = previous
426
426
  end
427
427
 
428
+ it 'draws every game without wordmark glyphs in color, monochrome and tiny panes' do
429
+ PWN::Banner.mini_names.product([1, 3, 5, 8, 16, 20], [true, false]).each do |name, size, colors|
430
+ console = PWN::Plugins::REPL::AIConsole::Console.new(pry: Pry.new, input: StringIO.new, curses: nil, getch: nil)
431
+ allow(PWN::Banner).to receive(:mini_names).and_return([name])
432
+ now = 100.0
433
+ allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC) { now }
434
+ console.instance_variable_set(:@banner_colors, colors)
435
+ console.instance_variable_set(:@banner_two_colors, colors)
436
+ calls = []
437
+ allow(console).to receive(:put) { |*args| calls << args }
438
+ console.draw_banner(size)
439
+ now += 10.0
440
+ console.draw_banner(size)
441
+ expect(calls.map { |_, _, text| text }.join).not_to match(/[PWN]/)
442
+ expect(calls).to all(satisfy { |y, x, text| y.between?(1, size) && x >= 1 && x + text.length <= size + 1 })
443
+ expect(console.banner_frame(size).join).not_to match(/[PWN]/)
444
+ end
445
+ end
446
+
428
447
  it 'selects one mini-banner per session and advances only from monotonic elapsed time' do
429
448
  pry = Pry.new
430
449
  pry.config.pwn_ai_session_id = 'banner-one'
@@ -435,16 +454,16 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
435
454
  now = 100.0
436
455
  allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC) { now }
437
456
  first = console.banner_frame(8)
438
- expect(first).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 0, width: 8, height: 8))
457
+ expect(first).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 0, width: 8, height: 8, branding: false))
439
458
  now += PWN::Banner::MINI_FRAME_SECONDS / 2
440
459
  expect(console.banner_frame(8)).to eq(first)
441
460
  now += PWN::Banner::MINI_FRAME_SECONDS * 0.75
442
- expect(console.banner_frame(8)).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 1, width: 8, height: 8))
461
+ expect(console.banner_frame(8)).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 1, width: 8, height: 8, branding: false))
443
462
  now += PWN::Banner::MINI_FRAME_SECONDS * PWN::Banner::MINI_FRAME_COUNT
444
- expect(console.banner_frame(12)).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 1, width: 12, height: 12))
463
+ expect(console.banner_frame(12)).to eq(PWN::Banner.mini_frame(name: choices.first, frame: 1, width: 12, height: 12, branding: false))
445
464
  expect(choices).to have_received(:sample).once
446
465
  pry.config.pwn_ai_session_id = 'banner-two'
447
- expect(console.banner_frame(8)).to eq(PWN::Banner.mini_frame(name: choices.last, frame: 0, width: 8, height: 8))
466
+ expect(console.banner_frame(8)).to eq(PWN::Banner.mini_frame(name: choices.last, frame: 0, width: 8, height: 8, branding: false))
448
467
  expect(choices).to have_received(:sample).twice
449
468
  end
450
469
 
@@ -454,7 +473,7 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
454
473
  allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC).and_return(100.0)
455
474
  size = 24
456
475
  canvas = console.banner_frame(size)
457
- art = PWN::Banner.mini_frame(name: :pong, frame: 0, width: size, height: size)
476
+ art = PWN::Banner.mini_frame(name: :pong, frame: 0, width: size, height: size, branding: false)
458
477
  expect(canvas.length).to eq(size)
459
478
  expect(canvas.map(&:length)).to all(eq(size))
460
479
  top = (size - art.length) / 2
@@ -470,14 +489,14 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
470
489
  allow(Process).to receive(:clock_gettime).with(Process::CLOCK_MONOTONIC) { now }
471
490
  console.banner_frame(20, cells: true)
472
491
  seed = console.instance_variable_get(:@banner_seed)
473
- frames = PWN::Banner.send(:mini_replay, name: :falling_blocks, width: 20, height: 20, seed: seed)
492
+ frames = PWN::Banner.send(:mini_replay, name: :falling_blocks, width: 20, height: 21, seed: seed)
474
493
  tick = frames.index { |frame| frame[:event] == :lock }
475
494
  now += (tick + 0.1) * PWN::Banner::MINI_FRAME_SECONDS
476
495
  calls = []
477
496
  allow(console).to receive(:put) { |*args| calls << args }
478
497
  console.draw_banner(20)
479
498
  expect(calls.select { |y, _x, text| y == 20 && text.strip != '' }).not_to be_empty
480
- expect(calls).to include([1, 9, 'P', nil], [1, 10, 'W', nil], [1, 11, 'N', nil])
499
+ expect(calls.map { |_, _, text| text }.join).not_to match(/[PWN]/)
481
500
  expect(calls).to all(satisfy { |y, x, text| y.between?(1, 20) && x >= 1 && x + text.length <= 21 })
482
501
  end
483
502
 
@@ -498,12 +517,13 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
498
517
  end
499
518
  allow(PWN::Banner).to receive(:mini_cells).and_call_original
500
519
  console.draw
501
- expect(rectangles).to include([0, 0, 10, 10, 'PWN'])
520
+ expect(rectangles).to include([0, 0, 10, 10, ''])
502
521
  expect(rectangles).to include([0, 10, 10, 109, "pwn-ai v#{PWN::VERSION}"])
503
522
  expect(console.instance_variable_get(:@header_text_column)).to eq(12)
504
523
  expect(painted).to include([2, 12, 'PROVIDER (ENGINE):', console.tone(:category)])
505
524
  expect(painted.any? { |y, x, text, color| y == 0 && x == 0 && text.include?('╭') && color == console.tone(:border) }).to be(true)
506
- expect(painted.any? { |y, x, text, color| y == 0 && x == 2 && text.include?('PWN') && color == console.tone(:title) }).to be(true)
525
+ expect(painted.any? { |y, x, _text, _color| y == 0 && x == 2 }).to be(false)
526
+ expect(painted.select { |y, x, _text, _color| y < 10 && x < 10 }.map { |_, _, text| text }.join).not_to match(/[PWN]/)
507
527
  expect(painted.select { |y, x, text, _color| y.between?(1, 8) && x == 1 && text == ' ' * 8 }.length).to eq(8)
508
528
  expect(painted.select { |y, _x, _text, _color| y < 10 }).to all(satisfy { |y, x, text, _color| y >= 0 && x >= 0 && x + console.width(text) <= 120 })
509
529
  expect(PWN::Banner).to have_received(:mini_cells).with(hash_including(width: 8, height: 8)).once
@@ -511,7 +531,7 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
511
531
  allow(curses).to receive_messages(cols: columns, lines: rows)
512
532
  rectangles.clear
513
533
  console.draw
514
- expect(rectangles.map(&:last)).not_to include('PWN')
534
+ expect(rectangles.map(&:last)).not_to include('')
515
535
  expect(console.instance_variable_get(:@header_text_column)).to eq(2)
516
536
  end
517
537
  allow(curses).to receive_messages(cols: 120, lines: 26)
@@ -533,7 +553,7 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
533
553
  allow(PWN::Banner).to receive(:mini_cells).and_call_original
534
554
  height = console.draw_header('ollama', 'fixture')
535
555
  expect(height).to be > 10
536
- expect(console).to have_received(:box).with(0, 0, height, height, 'PWN')
556
+ expect(console).to have_received(:box).with(0, 0, height, height, '')
537
557
  expect(PWN::Banner).to have_received(:mini_cells).with(hash_including(width: height - 2, height: height - 2))
538
558
  expect(console.instance_variable_get(:@header_spans).length + 3).to be <= height
539
559
  expect(console.header_lines('ollama', 'fixture', console.instance_variable_get(:@header_text_width)).join).to include('REASONING EFFORT: high')
@@ -605,10 +625,10 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
605
625
  console.banner_frame(8, cells: true)
606
626
  seed = console.instance_variable_get(:@banner_seed)
607
627
  expect(seed).to be_a(Integer)
608
- expect(console.banner_frame(8, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 0, width: 8, height: 8, seed: seed))
628
+ expect(console.banner_frame(8, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 0, width: 8, height: 8, seed: seed, branding: false))
609
629
  now += 0.21
610
- expect(console.banner_frame(8, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 2, width: 8, height: 8, seed: seed))
611
- expect(console.banner_frame(12, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 2, width: 12, height: 12, seed: seed))
630
+ expect(console.banner_frame(8, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 2, width: 8, height: 8, seed: seed, branding: false))
631
+ expect(console.banner_frame(12, cells: true)).to eq(PWN::Banner.mini_cells(name: :snake, frame: 2, width: 12, height: 12, seed: seed, branding: false))
612
632
  expect(console.instance_variable_get(:@banner_seed)).to eq(seed)
613
633
  pry.config.pwn_ai_session_id = 'another-colored-session'
614
634
  console.banner_frame(8, cells: true)
@@ -630,7 +650,7 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
630
650
  console.banner_frame(8, cells: true)
631
651
  seed = console.instance_variable_get(:@banner_seed)
632
652
  now += 1.21
633
- expect(PWN::Banner).to receive(:mini_cells).with(name: name, frame: 24, width: 8, height: 8, seed: seed).twice.and_call_original
653
+ expect(PWN::Banner).to receive(:mini_cells).with(name: name, frame: 24, width: 8, height: 8, seed: seed, branding: false).twice.and_call_original
634
654
  2.times { console.banner_frame(8, cells: true) }
635
655
  end
636
656
  end
@@ -1708,12 +1708,13 @@
1708
1708
  {"messages":[{"role":"user","content":"PWN::Banner.help Usage"},{"role":"assistant","content":"`PWN::Banner.help`: "}]}
1709
1709
  {"messages":[{"role":"user","content":"PWN::Banner.mini_asteroids Usage"},{"role":"assistant","content":"`PWN::Banner.mini_asteroids`: "}]}
1710
1710
  {"messages":[{"role":"user","content":"PWN::Banner.mini_asteroids_snapshot Usage"},{"role":"assistant","content":"`PWN::Banner.mini_asteroids_snapshot`: "}]}
1711
- {"messages":[{"role":"user","content":"PWN::Banner.mini_cells Usage"},{"role":"assistant","content":"`PWN::Banner.mini_cells`: Supported Method Parameters\n\nReturn rows of single-column Unicode block cells, with named terminal colors. Each fresh cell has glyph, foreground and background keys; no ANSI or IO. Square means terminal-cell dimensions, not physical pixels. Caller owns borders. Use mini_frame_seconds for cadence; 1800 frames span 90 or 180 seconds. Colored blocks fill the canvas with quarter-cell pieces; other games cap at 16. PWN::Banner.mini_cells(\n\nname: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',\nframe: 'optional - integer index, defaults to zero and wraps at 1800',\nwidth: 'optional - columns clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',\nheight: 'optional - rows clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',\nseed: 'optional - integer local PRNG seed, defaults to 73; retain per session'\n\n)\n"}]}
1711
+ {"messages":[{"role":"user","content":"PWN::Banner.mini_block_board Usage"},{"role":"assistant","content":"`PWN::Banner.mini_block_board`: "}]}
1712
+ {"messages":[{"role":"user","content":"PWN::Banner.mini_cells Usage"},{"role":"assistant","content":"`PWN::Banner.mini_cells`: Supported Method Parameters\n\nReturn rows of single-column Unicode block cells, with named terminal colors. Each fresh cell has glyph, foreground and background keys; no ANSI or IO. Square means terminal-cell dimensions, not physical pixels. Caller owns borders. Use mini_frame_seconds for cadence; 1800 frames span 90 or 180 seconds. Colored blocks fill the canvas with half-cell pieces; other games cap at 16. PWN::Banner.mini_cells(\n\nname: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',\nframe: 'optional - integer index, defaults to zero and wraps at 1800',\nwidth: 'optional - columns clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',\nheight: 'optional - rows clamped to 0..64 for blocks, 0..16 otherwise; defaults to 16',\nseed: 'optional - integer local PRNG seed, defaults to 73; retain per session',\nbranding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'\n\n)\n"}]}
1712
1713
  {"messages":[{"role":"user","content":"PWN::Banner.mini_delta Usage"},{"role":"assistant","content":"`PWN::Banner.mini_delta`: "}]}
1713
1714
  {"messages":[{"role":"user","content":"PWN::Banner.mini_emit Usage"},{"role":"assistant","content":"`PWN::Banner.mini_emit`: "}]}
1714
1715
  {"messages":[{"role":"user","content":"PWN::Banner.mini_falling_blocks Usage"},{"role":"assistant","content":"`PWN::Banner.mini_falling_blocks`: "}]}
1715
1716
  {"messages":[{"role":"user","content":"PWN::Banner.mini_fits? Usage"},{"role":"assistant","content":"`PWN::Banner.mini_fits?`: "}]}
1716
- {"messages":[{"role":"user","content":"PWN::Banner.mini_frame Usage"},{"role":"assistant","content":"`PWN::Banner.mini_frame`: Supported Method Parameters\n\nReturn fresh ASCII rows for decorative retro loops, not interactive games. Use equal width and height for a square; 5..16 retains the complete artwork. Smaller panes degrade to a wordmark. Caller owns randomness, clock and IO. PWN::Banner.mini_frame(\n\nname: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',\nframe: 'optional - integer frame index, defaults to zero and wraps at 60',\nwidth: 'optional - output columns clamped to zero through 16, defaults to 16',\nheight: 'optional - output rows clamped to zero through 16, defaults to 16'\n\n)\n"}]}
1717
+ {"messages":[{"role":"user","content":"PWN::Banner.mini_frame Usage"},{"role":"assistant","content":"`PWN::Banner.mini_frame`: Supported Method Parameters\n\nReturn fresh ASCII rows for decorative retro loops, not interactive games. Use equal width and height for a square; 5..16 retains the complete artwork. Smaller panes degrade to a wordmark. Caller owns randomness, clock and IO. PWN::Banner.mini_frame(\n\nname: 'optional - falling_blocks, snake, pong, or asteroids; defaults to falling_blocks',\nframe: 'optional - integer frame index, defaults to zero and wraps at 60',\nwidth: 'optional - output columns clamped to zero through 16, defaults to 16',\nheight: 'optional - output rows clamped to zero through 16, defaults to 16',\nbranding: 'optional - include the legacy wordmark, defaults to true; false reclaims its row'\n\n)\n"}]}
1717
1718
  {"messages":[{"role":"user","content":"PWN::Banner.mini_frame_seconds Usage"},{"role":"assistant","content":"`PWN::Banner.mini_frame_seconds`: Supported Method Parameters\n\nReturn the presentation interval; simulations preserve their gameplay speed. PWN::Banner.mini_frame_seconds(\n\nname: 'optional - animation name, defaults to falling_blocks'\n\n)\n"}]}
1718
1719
  {"messages":[{"role":"user","content":"PWN::Banner.mini_freeze Usage"},{"role":"assistant","content":"`PWN::Banner.mini_freeze`: "}]}
1719
1720
  {"messages":[{"role":"user","content":"PWN::Banner.mini_landing Usage"},{"role":"assistant","content":"`PWN::Banner.mini_landing`: "}]}
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pwn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.751
4
+ version: 0.5.752
5
5
  platform: ruby
6
6
  authors:
7
7
  - 0day Inc.