pwn 0.5.751 → 0.5.754
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/Gemfile +2 -2
- data/documentation/pwn-ai-Agent.md +7 -3
- data/etc/default_skills/pwn/banner/SKILL.md +1 -1
- data/lib/pwn/ai/anthropic.rb +73 -1
- data/lib/pwn/banner.rb +21 -8
- data/lib/pwn/plugins/repl/ai_console.rb +7 -7
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/ai/anthropic_spec.rb +48 -0
- data/spec/lib/pwn/banner_spec.rb +31 -4
- data/spec/lib/pwn/plugins/repl/ai_console_spec.rb +47 -23
- data/third_party/pwn_rdoc.jsonl +7 -2
- metadata +6 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e01b8e88574a241d780acc3e2c4d70a7e5c07fb1e9e17fa709363a4bfcbc7898
|
|
4
|
+
data.tar.gz: f50a1f5f35d25f300c396678edb5daa8119f4fca9e1567d71652c7f45bcc1dcb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c34deaa7b6835b37cacb76a2863cb0759b4dc727301692014702468aa3d4a04ddc1c76fda3893005f58071b9060768ade05401dbbae1cac2fc3dbfc99bcfa9f0
|
|
7
|
+
data.tar.gz: de481a34a2b3776fa8003094618af168f6a33341fd236e14daa3247694e8e703e0eddb15ea74556e9bd4814a14a3187d48f51c18be90094f1bd4c83ddcd364b8
|
data/Gemfile
CHANGED
|
@@ -20,7 +20,7 @@ gem 'base32', '0.3.4'
|
|
|
20
20
|
gem 'bitcoin-ruby', '0.0.20'
|
|
21
21
|
gem 'brakeman', '8.0.6'
|
|
22
22
|
gem 'bson', '5.2.0'
|
|
23
|
-
gem 'bundler', '>=4.0.
|
|
23
|
+
gem 'bundler', '>=4.0.22'
|
|
24
24
|
gem 'bundler-audit', '>=0.9.3'
|
|
25
25
|
gem 'bunny', '3.4.0'
|
|
26
26
|
gem 'colorize', '1.1.0'
|
|
@@ -57,7 +57,7 @@ gem 'msfrpc-client', '1.1.2'
|
|
|
57
57
|
gem 'netaddr', '2.0.6'
|
|
58
58
|
gem 'net-ldap', '0.20.0'
|
|
59
59
|
gem 'net-openvpn', '0.8.7'
|
|
60
|
-
gem 'net-smtp', '0.5.
|
|
60
|
+
gem 'net-smtp', '0.5.2'
|
|
61
61
|
gem 'nexpose', '7.3.0'
|
|
62
62
|
gem 'nokogiri', '1.19.4'
|
|
63
63
|
gem 'nokogiri-diff', '0.3.0'
|
|
@@ -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
|
-
|
|
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.
|
|
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)
|
|
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/ai/anthropic.rb
CHANGED
|
@@ -575,7 +575,7 @@ module PWN
|
|
|
575
575
|
{
|
|
576
576
|
name: fn[:name] || fn['name'],
|
|
577
577
|
description: fn[:description] || fn['description'],
|
|
578
|
-
input_schema: fn[:parameters] || fn['parameters']
|
|
578
|
+
input_schema: anthropic_input_schema(schema: fn[:parameters] || fn['parameters'])
|
|
579
579
|
}
|
|
580
580
|
end
|
|
581
581
|
http_body[:tool_choice] = anth_tool_choice(choice: opts[:tool_choice]) if opts[:tool_choice]
|
|
@@ -598,6 +598,78 @@ module PWN
|
|
|
598
598
|
raise e
|
|
599
599
|
end
|
|
600
600
|
|
|
601
|
+
# Anthropic rejects oneOf, allOf, and anyOf at the root of input_schema.
|
|
602
|
+
# Return a deep copy with those root keys removed and branch properties merged.
|
|
603
|
+
# Nested combinators and the caller's schema stay unchanged.
|
|
604
|
+
private_class_method def self.anthropic_input_schema(opts = {})
|
|
605
|
+
schema = opts[:schema]
|
|
606
|
+
return { type: 'object', properties: {} } unless schema.is_a?(Hash)
|
|
607
|
+
|
|
608
|
+
copy = json_copy(value: schema)
|
|
609
|
+
notes = []
|
|
610
|
+
%w[anyOf oneOf allOf].each do |name|
|
|
611
|
+
key = anthropic_schema_key(schema: copy, name: name)
|
|
612
|
+
next unless key
|
|
613
|
+
|
|
614
|
+
Array(copy.delete(key)).each do |branch|
|
|
615
|
+
next unless branch.is_a?(Hash)
|
|
616
|
+
|
|
617
|
+
anthropic_schema_notes(branch: branch, notes: notes)
|
|
618
|
+
props = branch[:properties] || branch['properties']
|
|
619
|
+
next unless props.is_a?(Hash)
|
|
620
|
+
|
|
621
|
+
dest = copy.key?('properties') ? 'properties' : :properties
|
|
622
|
+
copy[dest] = {} unless copy[dest].is_a?(Hash)
|
|
623
|
+
props.each { |prop, spec| copy[dest][prop] = spec unless copy[dest].key?(prop) }
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
copy[:type] = 'object' unless copy.key?(:type) || copy.key?('type')
|
|
627
|
+
copy[:properties] = {} unless copy.key?(:properties) || copy.key?('properties')
|
|
628
|
+
unless notes.empty?
|
|
629
|
+
note = "One of these field sets is required: #{notes.uniq.join('; ')}."
|
|
630
|
+
copy[:description] = [copy[:description] || copy['description'], note].compact.reject { |part| part.to_s.empty? }.join(' ')
|
|
631
|
+
copy.delete('description')
|
|
632
|
+
end
|
|
633
|
+
copy
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
private_class_method def self.anthropic_schema_notes(opts = {})
|
|
637
|
+
branch = opts[:branch]
|
|
638
|
+
notes = opts[:notes]
|
|
639
|
+
return notes unless branch.is_a?(Hash) && notes.is_a?(Array)
|
|
640
|
+
|
|
641
|
+
required = branch[:required] || branch['required']
|
|
642
|
+
notes << required.join('+') if required.is_a?(Array) && required.any?
|
|
643
|
+
%w[anyOf oneOf allOf].each do |name|
|
|
644
|
+
key = anthropic_schema_key(schema: branch, name: name)
|
|
645
|
+
next unless key
|
|
646
|
+
|
|
647
|
+
Array(branch[key]).each { |child| anthropic_schema_notes(branch: child, notes: notes) }
|
|
648
|
+
end
|
|
649
|
+
notes
|
|
650
|
+
end
|
|
651
|
+
|
|
652
|
+
private_class_method def self.anthropic_schema_key(opts = {})
|
|
653
|
+
schema = opts[:schema]
|
|
654
|
+
name = opts[:name]
|
|
655
|
+
return name if schema.is_a?(Hash) && schema.key?(name)
|
|
656
|
+
return name.to_sym if schema.is_a?(Hash) && schema.key?(name.to_sym)
|
|
657
|
+
|
|
658
|
+
nil
|
|
659
|
+
end
|
|
660
|
+
|
|
661
|
+
private_class_method def self.json_copy(opts = {})
|
|
662
|
+
value = opts[:value]
|
|
663
|
+
case value
|
|
664
|
+
when Hash
|
|
665
|
+
value.each_with_object({}) { |(key, item), out| out[key] = json_copy(value: item) }
|
|
666
|
+
when Array
|
|
667
|
+
value.map { |item| json_copy(value: item) }
|
|
668
|
+
else
|
|
669
|
+
value.is_a?(String) ? value.dup : value
|
|
670
|
+
end
|
|
671
|
+
end
|
|
672
|
+
|
|
601
673
|
# OpenAI messages[] -> [system_string, anthropic messages[]]
|
|
602
674
|
private_class_method def self.oa_messages_to_anthropic(opts = {})
|
|
603
675
|
messages = opts[:messages] ||= []
|
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)
|
|
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)
|
|
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
|
|
@@ -1070,10 +1070,10 @@ module PWN
|
|
|
1070
1070
|
role = cfg[:system_role_content].to_s.gsub(/\s+/, ' ').strip
|
|
1071
1071
|
parts = []
|
|
1072
1072
|
parts << "SYSTEM ROLE CONTENT: #{role}" unless role.empty?
|
|
1073
|
-
parts << "\
|
|
1074
|
-
parts << " MAX TOKENS: #{cfg[:max_tokens]}" unless cfg[:max_tokens].nil?
|
|
1073
|
+
parts << "\nMAX TOKENS: #{cfg[:max_tokens]}" unless cfg[:max_tokens].nil?
|
|
1075
1074
|
parts << " MAX PROMPT LENGTH: #{cfg[:max_prompt_length]}" unless cfg[:max_prompt_length].nil?
|
|
1076
|
-
parts << "
|
|
1075
|
+
parts << " REASONING EFFORT: #{cfg[:reasoning_effort]}" unless cfg[:reasoning_effort].to_s.empty?
|
|
1076
|
+
parts << " TEMP: #{cfg[:temp]}" unless cfg[:temp].nil?
|
|
1077
1077
|
parts.join(' · ')
|
|
1078
1078
|
rescue StandardError
|
|
1079
1079
|
''
|
|
@@ -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, '
|
|
1211
|
+
box(0, 0, height, height, '')
|
|
1212
1212
|
draw_banner(height - 2)
|
|
1213
1213
|
end
|
|
1214
1214
|
height
|
data/lib/pwn/version.rb
CHANGED
|
@@ -58,4 +58,52 @@ describe PWN::AI::Anthropic do
|
|
|
58
58
|
expect(src).to include('PromptCache.enabled?')
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
|
+
|
|
62
|
+
it 'drops root combinators from Anthropic input_schema without mutating registry schemas' do
|
|
63
|
+
allow(PWN::Env).to receive(:[]).with(:ai).and_return(
|
|
64
|
+
anthropic: { key: 'test-key', model: 'claude-test', temp: 1, max_tokens: 100 }
|
|
65
|
+
)
|
|
66
|
+
allow(PWN::AI::Agent::PromptCache).to receive(:enabled?).and_return(false) if defined?(PWN::AI::Agent::PromptCache)
|
|
67
|
+
tools = PWN::AI::Agent::Registry.definitions(core_only: true)
|
|
68
|
+
artifact = tools.find { |tool| tool.dig(:function, :name) == 'artifact_read' }
|
|
69
|
+
original = artifact[:function][:parameters]
|
|
70
|
+
nested = {
|
|
71
|
+
type: 'object',
|
|
72
|
+
properties: {
|
|
73
|
+
item: { anyOf: [{ type: 'string' }, { type: 'object', properties: { handle: { type: 'string' } } }] }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
union = {
|
|
77
|
+
'anyOf' => [
|
|
78
|
+
{ 'type' => 'object', 'properties' => { 'handle' => { 'type' => 'string' } }, 'required' => ['handle'] },
|
|
79
|
+
{ 'type' => 'object', 'properties' => { 'path' => { 'type' => 'string' } }, 'required' => ['path'] }
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
sent = tools + [
|
|
83
|
+
{ type: 'function', function: { name: 'nested_union', description: 'keep nested', parameters: nested } },
|
|
84
|
+
{ type: 'function', function: { name: 'root_union', description: 'flatten', parameters: union } }
|
|
85
|
+
]
|
|
86
|
+
captured = nil
|
|
87
|
+
allow(described_class).to receive(:anthropic_rest_call) do |opts|
|
|
88
|
+
captured = opts[:http_body]
|
|
89
|
+
'{"id":"msg_schema","type":"message","role":"assistant","content":[{"type":"text","text":"ok"}],"stop_reason":"end_turn"}'
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
described_class.chat_with_tools(messages: [{ role: 'user', content: 'hello' }], tools: sent, model: 'claude-test')
|
|
93
|
+
|
|
94
|
+
expect(original).to have_key(:anyOf)
|
|
95
|
+
wire = captured[:tools]
|
|
96
|
+
expect(wire.map { |tool| tool[:name] }[10]).to eq('artifact_read')
|
|
97
|
+
wire.each do |tool|
|
|
98
|
+
schema = tool[:input_schema]
|
|
99
|
+
expect(schema.keys.map(&:to_s)).not_to include('anyOf', 'oneOf', 'allOf')
|
|
100
|
+
end
|
|
101
|
+
read_schema = wire[10][:input_schema]
|
|
102
|
+
expect(read_schema[:properties].keys.map(&:to_s)).to include('handle', 'path', 'ref')
|
|
103
|
+
expect(read_schema[:description]).to include('handle', 'path', 'ref')
|
|
104
|
+
expect(wire.find { |tool| tool[:name] == 'nested_union' }[:input_schema][:properties][:item]).to have_key(:anyOf)
|
|
105
|
+
flat = wire.find { |tool| tool[:name] == 'root_union' }[:input_schema]
|
|
106
|
+
expect(flat[:properties].keys.map(&:to_s)).to include('handle', 'path')
|
|
107
|
+
expect(flat[:description]).to include('handle', 'path')
|
|
108
|
+
end
|
|
61
109
|
end
|
data/spec/lib/pwn/banner_spec.rb
CHANGED
|
@@ -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
|
-
|
|
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:
|
|
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
|
|
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, '
|
|
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,
|
|
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,14 +531,14 @@ 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('
|
|
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)
|
|
518
|
-
PWN::Env[:ai][:ollama][:system_role_content] = 'operator ' *
|
|
538
|
+
PWN::Env[:ai][:ollama][:system_role_content] = 'operator ' * 200
|
|
519
539
|
console.draw
|
|
520
540
|
expect(console.instance_variable_get(:@header_text_column)).to eq(2)
|
|
521
|
-
expect(console.header_lines('ollama', 'fixture', 115).length).to be
|
|
541
|
+
expect(console.header_lines('ollama', 'fixture', 115).length).to be > 16
|
|
522
542
|
expect(PWN::Banner).to have_received(:mini_cells).once
|
|
523
543
|
expect([console.instance_variable_get(:@editor).text, console.instance_variable_get(:@editor).cursor]).to eq(['retained draft', 4])
|
|
524
544
|
end
|
|
@@ -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, '
|
|
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
|
|
@@ -699,13 +719,15 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
|
|
|
699
719
|
expect(actual).to eq(lines)
|
|
700
720
|
expect(header.select { |entry| entry[3] == console.tone(:category) }.map { |entry| entry[2] }.join).to include('SYSTEM ROLE CONTENT:', 'MAX PROMPT LENGTH:', 'REASONING EFFORT:')
|
|
701
721
|
expect(header.select { |entry| entry[3] == console.tone(:header) }.map { |entry| entry[2] }.join).to include('operator', '1024', 'high')
|
|
702
|
-
if columns == 48
|
|
703
|
-
labels = header.select { |entry| entry[3] == console.tone(:category) }.map { |entry| entry[2] }
|
|
704
|
-
expect(labels.join).to include('MAX PROMPT LENGTH:')
|
|
705
|
-
expect(labels).not_to include(a_string_including('MAX PROMPT LENGTH:'))
|
|
706
|
-
end
|
|
707
722
|
expect(console.instance_variable_get(:@page_size)).to be >= 1
|
|
708
723
|
end
|
|
724
|
+
console.header_lines('ollama', 'fixture', 35)
|
|
725
|
+
labels = []
|
|
726
|
+
console.instance_variable_get(:@header_spans).each do |row|
|
|
727
|
+
row.each { |role, text| labels << text if role == :category }
|
|
728
|
+
end
|
|
729
|
+
expect(labels.join).to include('MAX PROMPT LENGTH:')
|
|
730
|
+
expect(labels).not_to include(a_string_including('MAX PROMPT LENGTH:'))
|
|
709
731
|
console.handle("\u000f")
|
|
710
732
|
console.draw
|
|
711
733
|
console.handle(:end)
|
|
@@ -1218,7 +1240,9 @@ describe 'pwn-ai curses launch' do # rubocop:disable Metrics/BlockLength -- publ
|
|
|
1218
1240
|
if rendered_header.include?('worker-effort')
|
|
1219
1241
|
expect(rendered_header).to include('worker settings role', '0.42', '4321', '8765')
|
|
1220
1242
|
expect(painted).to include([a_kind_of(Integer), a_kind_of(Integer), 'MODEL:', 7])
|
|
1221
|
-
|
|
1243
|
+
value = painted.find { |_y, _x, text, color| color == 6 && text.to_s.include?('worker-effort') }
|
|
1244
|
+
expect(value).not_to be_nil
|
|
1245
|
+
expect(value[2]).not_to include('REASONING EFFORT:')
|
|
1222
1246
|
"\u0004"
|
|
1223
1247
|
else
|
|
1224
1248
|
Thread.pass
|
data/third_party/pwn_rdoc.jsonl
CHANGED
|
@@ -1058,13 +1058,17 @@
|
|
|
1058
1058
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::VulnGen.authors Usage"},{"role":"assistant","content":"`PWN::AI::Agent::VulnGen.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
|
1059
1059
|
{"messages":[{"role":"user","content":"PWN::AI::Agent::VulnGen.help Usage"},{"role":"assistant","content":"`PWN::AI::Agent::VulnGen.help`: "}]}
|
|
1060
1060
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anth_tool_choice Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anth_tool_choice`: "}]}
|
|
1061
|
+
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anthropic_input_schema Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anthropic_input_schema`: "}]}
|
|
1061
1062
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anthropic_resp_to_oa Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anthropic_resp_to_oa`: "}]}
|
|
1062
1063
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anthropic_rest_call Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anthropic_rest_call`: Supported Method Parameters\n\nanthropic_rest_call(\n\ntoken: 'required - anthropic api key',\nhttp_method: 'optional HTTP method (defaults to GET)',\nbase_uri: 'optional base anthropic api URI (defaults to https://api.anthropic.com/v1)',\nrest_call: 'required rest call to make per the schema',\nparams: 'optional params passed in the URI or HTTP Headers',\nhttp_body: 'optional HTTP body sent in HTTP methods that support it e.g. POST',\ntimeout: 'optional timeout in seconds (defaults to 900)',\nspinner: 'optional - display spinner (defaults to false)'\n\n)\n"}]}
|
|
1064
|
+
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anthropic_schema_key Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anthropic_schema_key`: "}]}
|
|
1065
|
+
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.anthropic_schema_notes Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.anthropic_schema_notes`: "}]}
|
|
1063
1066
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.authors Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.authors`: Author(s)\n\n0day Inc. <support@0dayinc.com>\n"}]}
|
|
1064
1067
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.chat Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.chat`: Supported Method Parameters\n\nresponse = PWN::AI::Anthropic.chat(\n\nrequest: 'required - message to Anthropic',\nmodel: 'optional - model to use for text generation (defaults to PWN::Env[:ai][:anthropic][:model])',\ntemp: 'optional - creative response float (defaults to PWN::Env[:ai][:anthropic][:temp])',\nsystem_role_content: 'optional - context to set up the model behavior for conversation (Default: PWN::Env[:ai][:anthropic][:system_role_content])',\nresponse_history: 'optional - pass response back in to have a conversation',\nspeak_answer: 'optional speak answer using PWN::Plugins::Voice.text_to_speech (Default: nil)',\ntimeout: 'optional timeout in seconds (defaults to 900)',\nspinner: 'optional - display spinner (defaults to false)'\n\n)\n"}]}
|
|
1065
1068
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.chat_with_tools Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.chat_with_tools`: Supported Method Parameters\n\nresponse = PWN::AI::Anthropic.chat_with_tools(\n\nmessages: 'required - OpenAI-format messages array (system/user/assistant/tool)',\ntools: 'optional - OpenAI tools array [{type:\"function\", function:{...}}]',\ntool_choice: 'optional - \"auto\" | \"none\" | \"required\" | {type:\"function\", function:{name:..}}',\nmodel: 'optional - overrides PWN::Env[:ai][:anthropic][:model]',\ntemp: 'optional - temperature (defaults to PWN::Env[:ai][:anthropic][:temp] || 1)',\nmax_tokens: 'optional - defaults to PWN::Env[:ai][:anthropic][:max_tokens] || 128_000',\ntimeout: 'optional - seconds (default 900)',\nspinner: 'optional - display spinner (default false)'\n\n)\n"}]}
|
|
1066
1069
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.get_models Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.get_models`: Supported Method Parameters\n\nmodels = PWN::AI::Anthropic.get_models\n"}]}
|
|
1067
1070
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.help Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.help`: "}]}
|
|
1071
|
+
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.json_copy Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.json_copy`: "}]}
|
|
1068
1072
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.jwt_exp Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.jwt_exp`: "}]}
|
|
1069
1073
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.oa_messages_to_anthropic Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.oa_messages_to_anthropic`: "}]}
|
|
1070
1074
|
{"messages":[{"role":"user","content":"PWN::AI::Anthropic.oauth_token_expiring? Usage"},{"role":"assistant","content":"`PWN::AI::Anthropic.oauth_token_expiring?`: "}]}
|
|
@@ -1708,12 +1712,13 @@
|
|
|
1708
1712
|
{"messages":[{"role":"user","content":"PWN::Banner.help Usage"},{"role":"assistant","content":"`PWN::Banner.help`: "}]}
|
|
1709
1713
|
{"messages":[{"role":"user","content":"PWN::Banner.mini_asteroids Usage"},{"role":"assistant","content":"`PWN::Banner.mini_asteroids`: "}]}
|
|
1710
1714
|
{"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.
|
|
1715
|
+
{"messages":[{"role":"user","content":"PWN::Banner.mini_block_board Usage"},{"role":"assistant","content":"`PWN::Banner.mini_block_board`: "}]}
|
|
1716
|
+
{"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
1717
|
{"messages":[{"role":"user","content":"PWN::Banner.mini_delta Usage"},{"role":"assistant","content":"`PWN::Banner.mini_delta`: "}]}
|
|
1713
1718
|
{"messages":[{"role":"user","content":"PWN::Banner.mini_emit Usage"},{"role":"assistant","content":"`PWN::Banner.mini_emit`: "}]}
|
|
1714
1719
|
{"messages":[{"role":"user","content":"PWN::Banner.mini_falling_blocks Usage"},{"role":"assistant","content":"`PWN::Banner.mini_falling_blocks`: "}]}
|
|
1715
1720
|
{"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"}]}
|
|
1721
|
+
{"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
1722
|
{"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
1723
|
{"messages":[{"role":"user","content":"PWN::Banner.mini_freeze Usage"},{"role":"assistant","content":"`PWN::Banner.mini_freeze`: "}]}
|
|
1719
1724
|
{"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.
|
|
4
|
+
version: 0.5.754
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -141,14 +141,14 @@ dependencies:
|
|
|
141
141
|
requirements:
|
|
142
142
|
- - ">="
|
|
143
143
|
- !ruby/object:Gem::Version
|
|
144
|
-
version: 4.0.
|
|
144
|
+
version: 4.0.22
|
|
145
145
|
type: :development
|
|
146
146
|
prerelease: false
|
|
147
147
|
version_requirements: !ruby/object:Gem::Requirement
|
|
148
148
|
requirements:
|
|
149
149
|
- - ">="
|
|
150
150
|
- !ruby/object:Gem::Version
|
|
151
|
-
version: 4.0.
|
|
151
|
+
version: 4.0.22
|
|
152
152
|
- !ruby/object:Gem::Dependency
|
|
153
153
|
name: bundler-audit
|
|
154
154
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -617,14 +617,14 @@ dependencies:
|
|
|
617
617
|
requirements:
|
|
618
618
|
- - '='
|
|
619
619
|
- !ruby/object:Gem::Version
|
|
620
|
-
version: 0.5.
|
|
620
|
+
version: 0.5.2
|
|
621
621
|
type: :runtime
|
|
622
622
|
prerelease: false
|
|
623
623
|
version_requirements: !ruby/object:Gem::Requirement
|
|
624
624
|
requirements:
|
|
625
625
|
- - '='
|
|
626
626
|
- !ruby/object:Gem::Version
|
|
627
|
-
version: 0.5.
|
|
627
|
+
version: 0.5.2
|
|
628
628
|
- !ruby/object:Gem::Dependency
|
|
629
629
|
name: nexpose
|
|
630
630
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -7228,7 +7228,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
7228
7228
|
- !ruby/object:Gem::Version
|
|
7229
7229
|
version: '0'
|
|
7230
7230
|
requirements: []
|
|
7231
|
-
rubygems_version: 4.0.
|
|
7231
|
+
rubygems_version: 4.0.22
|
|
7232
7232
|
specification_version: 4
|
|
7233
7233
|
summary: Automated Security Testing for CI/CD Pipelines & Beyond
|
|
7234
7234
|
test_files: []
|