pwn 0.5.778 → 0.5.780
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 +3 -3
- data/lib/pwn/ai/agent/loop.rb +6 -3
- data/lib/pwn/plugins/repl/mesh.rb +15 -8
- data/lib/pwn/version.rb +1 -1
- data/spec/lib/pwn/ai/agent/loop_spec.rb +39 -0
- data/spec/lib/pwn/plugins/repl_mesh_origin_gps_spec.rb +16 -1
- metadata +7 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3207a135c108d0af20cc351965b217a3235abb0eaf67a31d244e3779ed6b72e5
|
|
4
|
+
data.tar.gz: 750df1371f8eb0fbab32b66e88b7568dbac4a49de7dc4020fc018a9957053acc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b10627e1329fa50ac482a49b1013ab455f52eac1a943d92ef7f9144bb93625e742935e0ad2caa1294f3d10a3c46d758b0de50695463e138af76ed7f61871438b
|
|
7
|
+
data.tar.gz: 3f55e834e447b8d51b8a28bd0c71d97498e577d49d7dadfea2a5ceda5e5bfa3876225d27f0c238b02dce690ea82d48612d29fd8a45130cea8213fc4a5650ce0a
|
data/Gemfile
CHANGED
|
@@ -49,7 +49,7 @@ gem 'jwt', '3.3.0'
|
|
|
49
49
|
gem 'libusb', '0.8.0'
|
|
50
50
|
gem 'luhn', '3.0.0'
|
|
51
51
|
gem 'mail', '2.9.1'
|
|
52
|
-
gem 'mcp', '1.8.
|
|
52
|
+
gem 'mcp', '1.8.1'
|
|
53
53
|
gem 'meshtastic', '0.0.188'
|
|
54
54
|
gem 'metasm', '1.0.6'
|
|
55
55
|
gem 'mongo', '2.26.0'
|
|
@@ -69,7 +69,7 @@ gem 'packetfu', '2.0.0'
|
|
|
69
69
|
gem 'packetgen', '4.1.1'
|
|
70
70
|
gem 'pdf-reader', '2.16.0'
|
|
71
71
|
gem 'pg', '1.7.0'
|
|
72
|
-
gem 'pry', '0.16.
|
|
72
|
+
gem 'pry', '0.16.1'
|
|
73
73
|
gem 'pry-doc', '1.7.0'
|
|
74
74
|
gem 'rake', '13.4.2'
|
|
75
75
|
gem 'rb-readline', '0.5.5'
|
|
@@ -94,7 +94,7 @@ gem 'selenium-webdriver', '4.51.0'
|
|
|
94
94
|
gem 'slack-ruby-client', '3.3.0'
|
|
95
95
|
gem 'socksify', '1.8.1'
|
|
96
96
|
gem 'spreadsheet', '1.3.5'
|
|
97
|
-
gem 'sqlite3', '2.10.
|
|
97
|
+
gem 'sqlite3', '2.10.1'
|
|
98
98
|
gem 'thin', '2.0.1'
|
|
99
99
|
gem 'tty-prompt', '0.23.1'
|
|
100
100
|
gem 'tty-spinner', '0.9.3'
|
data/lib/pwn/ai/agent/loop.rb
CHANGED
|
@@ -2195,7 +2195,8 @@ module PWN
|
|
|
2195
2195
|
pairs.each do |pair|
|
|
2196
2196
|
tool = pair.find { |m| m[:role].to_s == 'tool' }
|
|
2197
2197
|
prev = collapsed.last&.find { |m| m[:role].to_s == 'tool' }
|
|
2198
|
-
|
|
2198
|
+
# Compare raw bytes: existing history may contain malformed tool output.
|
|
2199
|
+
next if tool && prev && tool[:content].to_s.b.strip == prev[:content].to_s.b.strip
|
|
2199
2200
|
|
|
2200
2201
|
collapsed << pair
|
|
2201
2202
|
end
|
|
@@ -2241,8 +2242,10 @@ module PWN
|
|
|
2241
2242
|
FileUtils.mkdir_p(dir)
|
|
2242
2243
|
path = File.join(dir, "#{digest[0, 12]}.txt")
|
|
2243
2244
|
File.binwrite(path, text) unless File.file?(path)
|
|
2244
|
-
|
|
2245
|
-
|
|
2245
|
+
# Keep the artifact/digest byte-exact; only the displayed excerpt is text.
|
|
2246
|
+
# Byte slicing can bisect a multibyte character at either boundary.
|
|
2247
|
+
head = text.byteslice(0, 2_048).to_s.dup.force_encoding(Encoding::UTF_8).scrub
|
|
2248
|
+
tail = text.bytesize > 3_072 ? text.byteslice(-1_024, 1_024).to_s.dup.force_encoding(Encoding::UTF_8).scrub : ''
|
|
2246
2249
|
mid = tail.empty? ? '' : "\n...\n#{tail}"
|
|
2247
2250
|
"#{head}#{mid}\n[compacted path=#{path} sha256=#{digest} bytes=#{text.bytesize} ref=#{path}]"
|
|
2248
2251
|
rescue StandardError
|
|
@@ -2624,9 +2624,9 @@ class << PWN::Plugins::REPL # rubocop:disable Metrics/ClassLength
|
|
|
2624
2624
|
value = opts[:value].to_s
|
|
2625
2625
|
value = '—' if value.empty?
|
|
2626
2626
|
prefix = "#{opts[:label]}: "
|
|
2627
|
-
return [{ text: "#{prefix}#{value}" }] if Unicode::DisplayWidth.of("#{prefix}#{value}") <= width
|
|
2627
|
+
return [{ text: "#{prefix}#{value}", label: prefix.rstrip }] if Unicode::DisplayWidth.of("#{prefix}#{value}") <= width
|
|
2628
2628
|
|
|
2629
|
-
[{ text: prefix.rstrip }].concat(mesh_wrap_text(text: value, width: width).map { |line| { text: line } })
|
|
2629
|
+
[{ text: prefix.rstrip, label: prefix.rstrip }].concat(mesh_wrap_text(text: value, width: width).map { |line| { text: line } })
|
|
2630
2630
|
end
|
|
2631
2631
|
|
|
2632
2632
|
def mesh_gps_labeled_rows(opts = {})
|
|
@@ -2637,9 +2637,9 @@ class << PWN::Plugins::REPL # rubocop:disable Metrics/ClassLength
|
|
|
2637
2637
|
coord, url = label.split(' >> ', 2)
|
|
2638
2638
|
prefix = 'GPS: '
|
|
2639
2639
|
if Unicode::DisplayWidth.of("#{prefix}#{coord}") <= width
|
|
2640
|
-
[{ text: "#{prefix}#{coord}", link: true, link_at: prefix.length, url: url }]
|
|
2640
|
+
[{ text: "#{prefix}#{coord}", label: 'GPS:', link: true, link_at: prefix.length, url: url }]
|
|
2641
2641
|
else
|
|
2642
|
-
[{ text: 'GPS:' }, { text: coord, link: true, url: url }]
|
|
2642
|
+
[{ text: 'GPS:', label: 'GPS:' }, { text: coord, link: true, url: url }]
|
|
2643
2643
|
end
|
|
2644
2644
|
end
|
|
2645
2645
|
|
|
@@ -2964,7 +2964,12 @@ class << PWN::Plugins::REPL # rubocop:disable Metrics/ClassLength
|
|
|
2964
2964
|
at = line[:link_at].to_i
|
|
2965
2965
|
prefix = text[0, at].to_s
|
|
2966
2966
|
coord = text[at..] || ''
|
|
2967
|
-
|
|
2967
|
+
unless prefix.empty?
|
|
2968
|
+
win.attron(Curses.color_pair(24) | Curses::A_BOLD)
|
|
2969
|
+
win.addstr(prefix.rstrip)
|
|
2970
|
+
win.attroff(Curses.color_pair(24) | Curses::A_BOLD)
|
|
2971
|
+
win.addstr(prefix[prefix.rstrip.length..])
|
|
2972
|
+
end
|
|
2968
2973
|
win.attron(Curses::A_UNDERLINE)
|
|
2969
2974
|
win.addstr(coord)
|
|
2970
2975
|
win.attroff(Curses::A_UNDERLINE)
|
|
@@ -2973,9 +2978,11 @@ class << PWN::Plugins::REPL # rubocop:disable Metrics/ClassLength
|
|
|
2973
2978
|
hit[:pane] = opts[:pane]
|
|
2974
2979
|
opts[:hits] << hit
|
|
2975
2980
|
elsif line[:label] && win.respond_to?(:attron)
|
|
2976
|
-
|
|
2977
|
-
win.
|
|
2978
|
-
win.
|
|
2981
|
+
label = text[0, line[:label].to_s.length]
|
|
2982
|
+
win.attron(Curses.color_pair(24) | Curses::A_BOLD)
|
|
2983
|
+
win.addstr(label)
|
|
2984
|
+
win.attroff(Curses.color_pair(24) | Curses::A_BOLD)
|
|
2985
|
+
win.addstr(text[label.length..].to_s)
|
|
2979
2986
|
else
|
|
2980
2987
|
win.addstr(text)
|
|
2981
2988
|
end
|
data/lib/pwn/version.rb
CHANGED
|
@@ -1304,6 +1304,45 @@ describe PWN::AI::Agent::Loop do # rubocop:disable Metrics/BlockLength
|
|
|
1304
1304
|
expect(src).not_to match(/compact_history!\(messages: messages\) if local/)
|
|
1305
1305
|
end
|
|
1306
1306
|
|
|
1307
|
+
it 'keeps UTF-8 previews valid across repeated history compaction' do
|
|
1308
|
+
Dir.mktmpdir('pwn-history-encoding') do |dir|
|
|
1309
|
+
allow(Dir).to receive(:home).and_return(dir)
|
|
1310
|
+
messages = [{ role: 'system', content: 'sys' }, { role: 'user', content: 'goal' }]
|
|
1311
|
+
8.times do |n|
|
|
1312
|
+
messages << { role: 'assistant', content: '', tool_calls: [{ id: "c#{n}" }] }
|
|
1313
|
+
messages << { role: 'tool', tool_call_id: "c#{n}", content: "a#{'é' * 3000}#{n}" }
|
|
1314
|
+
end
|
|
1315
|
+
2.times do
|
|
1316
|
+
expect { described_class.send(:compact_history!, messages: messages) }.not_to output(/compact_history swallowed/).to_stderr
|
|
1317
|
+
expect(messages.all? { |msg| msg[:content].valid_encoding? }).to be(true)
|
|
1318
|
+
end
|
|
1319
|
+
end
|
|
1320
|
+
end
|
|
1321
|
+
|
|
1322
|
+
it 'preserves raw spilled bytes while rendering malformed and binary-tagged text safely' do
|
|
1323
|
+
Dir.mktmpdir('pwn-history-binary') do |dir|
|
|
1324
|
+
allow(Dir).to receive(:home).and_return(dir)
|
|
1325
|
+
["a#{'é' * 3000}".b, "a\xff#{'é' * 3000}"].each do |text|
|
|
1326
|
+
preview = described_class.send(:spill_tool_body, text: text)
|
|
1327
|
+
expect(preview.encoding).to eq(Encoding::UTF_8)
|
|
1328
|
+
expect(preview.valid_encoding?).to be(true)
|
|
1329
|
+
expect(preview).to include('é', '[compacted path=')
|
|
1330
|
+
path = preview[/\[compacted path=(.*?) sha256=/, 1]
|
|
1331
|
+
expect(File.binread(path)).to eq(text.b)
|
|
1332
|
+
end
|
|
1333
|
+
end
|
|
1334
|
+
end
|
|
1335
|
+
|
|
1336
|
+
it 'compacts existing malformed tool history without swallowing encoding errors' do
|
|
1337
|
+
messages = [{ role: 'system', content: 'sys' }, { role: 'user', content: 'goal' }]
|
|
1338
|
+
8.times do |n|
|
|
1339
|
+
messages << { role: 'assistant', tool_calls: [{ id: "c#{n}" }] }
|
|
1340
|
+
messages << { role: 'tool', tool_call_id: "c#{n}", content: "invalid\xff#{n}" }
|
|
1341
|
+
end
|
|
1342
|
+
expect { described_class.send(:compact_history!, messages: messages) }.not_to output(/compact_history swallowed/).to_stderr
|
|
1343
|
+
expect(messages.count { |msg| msg[:role] == 'tool' }).to eq(6)
|
|
1344
|
+
end
|
|
1345
|
+
|
|
1307
1346
|
it 'shrinks tool bodies when history is fat' do
|
|
1308
1347
|
msgs = [
|
|
1309
1348
|
{ role: 'system', content: 'sys' },
|
|
@@ -4,6 +4,21 @@ require 'spec_helper'
|
|
|
4
4
|
require 'meshtastic'
|
|
5
5
|
|
|
6
6
|
describe PWN::Plugins::REPL, 'mesh primary display, MQTT sender, and GPS link' do
|
|
7
|
+
it 'paints field labels bold white without changing value attributes' do
|
|
8
|
+
attrs = 0
|
|
9
|
+
painted = []
|
|
10
|
+
allow(Curses).to receive(:color_pair).with(20).and_return(0)
|
|
11
|
+
allow(Curses).to receive(:color_pair).with(24).and_return(256)
|
|
12
|
+
allow(details).to receive(:attron) { |value| attrs |= value }
|
|
13
|
+
allow(details).to receive(:attroff) { |value| attrs &= ~value }
|
|
14
|
+
allow(details).to receive(:addstr) { |text| painted << [text, attrs] }
|
|
15
|
+
rows = described_class.send(:mesh_value_rows, label: 'Node ID', value: '!00001337', width: 28)
|
|
16
|
+
rows += described_class.send(:mesh_value_rows, label: 'GPS', value: 'N/A', width: 28)
|
|
17
|
+
described_class.send(:mesh_paint_side, win: details, title: 'SENDER', focus: :sndr, rows: rows, hits: [])
|
|
18
|
+
expect(painted).to include(['Node ID:', 256 | Curses::A_BOLD], ['GPS:', 256 | Curses::A_BOLD])
|
|
19
|
+
expect(painted).to include([' !00001337', 0], [' N/A', 0])
|
|
20
|
+
end
|
|
21
|
+
|
|
7
22
|
let(:env) do
|
|
8
23
|
{ transport: 'serial', mqtt: { host: 'offline.invalid', region: 'US' },
|
|
9
24
|
channel: { active: 'LongFast', LongFast: { psk: 'AQ==', region: 'US', topic: '2/e/LongFast/#', from: '!00001337' } } }
|
|
@@ -224,7 +239,7 @@ describe PWN::Plugins::REPL, 'mesh primary display, MQTT sender, and GPS link' d
|
|
|
224
239
|
colors = []
|
|
225
240
|
allow(details).to receive(:attron) { |attr| colors << attr }
|
|
226
241
|
described_class.send(:mesh_handle_rx, env: env, obj: radio, msg: { packet: packet, mesh_transport: :serial })
|
|
227
|
-
painted = details.lines.join
|
|
242
|
+
painted = details.lines.join
|
|
228
243
|
expect(painted).to include('SENDER', 'Node ID: !421f6f22', 'GPS:')
|
|
229
244
|
expect(painted).not_to include('VIA')
|
|
230
245
|
node_num = 0x421f6f22
|
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.780
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- 0day Inc.
|
|
@@ -505,14 +505,14 @@ dependencies:
|
|
|
505
505
|
requirements:
|
|
506
506
|
- - '='
|
|
507
507
|
- !ruby/object:Gem::Version
|
|
508
|
-
version: 1.8.
|
|
508
|
+
version: 1.8.1
|
|
509
509
|
type: :runtime
|
|
510
510
|
prerelease: false
|
|
511
511
|
version_requirements: !ruby/object:Gem::Requirement
|
|
512
512
|
requirements:
|
|
513
513
|
- - '='
|
|
514
514
|
- !ruby/object:Gem::Version
|
|
515
|
-
version: 1.8.
|
|
515
|
+
version: 1.8.1
|
|
516
516
|
- !ruby/object:Gem::Dependency
|
|
517
517
|
name: meshtastic
|
|
518
518
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -785,14 +785,14 @@ dependencies:
|
|
|
785
785
|
requirements:
|
|
786
786
|
- - '='
|
|
787
787
|
- !ruby/object:Gem::Version
|
|
788
|
-
version: 0.16.
|
|
788
|
+
version: 0.16.1
|
|
789
789
|
type: :runtime
|
|
790
790
|
prerelease: false
|
|
791
791
|
version_requirements: !ruby/object:Gem::Requirement
|
|
792
792
|
requirements:
|
|
793
793
|
- - '='
|
|
794
794
|
- !ruby/object:Gem::Version
|
|
795
|
-
version: 0.16.
|
|
795
|
+
version: 0.16.1
|
|
796
796
|
- !ruby/object:Gem::Dependency
|
|
797
797
|
name: pry-doc
|
|
798
798
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -1121,14 +1121,14 @@ dependencies:
|
|
|
1121
1121
|
requirements:
|
|
1122
1122
|
- - '='
|
|
1123
1123
|
- !ruby/object:Gem::Version
|
|
1124
|
-
version: 2.10.
|
|
1124
|
+
version: 2.10.1
|
|
1125
1125
|
type: :development
|
|
1126
1126
|
prerelease: false
|
|
1127
1127
|
version_requirements: !ruby/object:Gem::Requirement
|
|
1128
1128
|
requirements:
|
|
1129
1129
|
- - '='
|
|
1130
1130
|
- !ruby/object:Gem::Version
|
|
1131
|
-
version: 2.10.
|
|
1131
|
+
version: 2.10.1
|
|
1132
1132
|
- !ruby/object:Gem::Dependency
|
|
1133
1133
|
name: thin
|
|
1134
1134
|
requirement: !ruby/object:Gem::Requirement
|