pwn 0.5.682 → 0.5.684

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.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +11 -10
  3. data/documentation/Agent-Tool-Registry.md +13 -9
  4. data/documentation/CLI-Drivers.md +27 -28
  5. data/documentation/Configuration.md +7 -5
  6. data/documentation/Contributing.md +2 -2
  7. data/documentation/Cron.md +11 -7
  8. data/documentation/Diagrams.md +2 -2
  9. data/documentation/General-PWN-Usage.md +1 -1
  10. data/documentation/Home.md +7 -6
  11. data/documentation/How-PWN-Works.md +9 -9
  12. data/documentation/Installation.md +1 -1
  13. data/documentation/Persistence.md +2 -1
  14. data/documentation/Plugins.md +3 -3
  15. data/documentation/Reinforcement-Learning.md +103 -101
  16. data/documentation/SAST.md +1 -1
  17. data/documentation/Session-Workflow.md +152 -0
  18. data/documentation/Sessions.md +2 -1
  19. data/documentation/Troubleshooting.md +2 -2
  20. data/documentation/What-is-PWN.md +3 -3
  21. data/documentation/diagrams/agent-tool-registry.svg +152 -152
  22. data/documentation/diagrams/cron-scheduling.svg +141 -121
  23. data/documentation/diagrams/dot/agent-tool-registry.dot +4 -4
  24. data/documentation/diagrams/dot/cron-scheduling.dot +10 -7
  25. data/documentation/diagrams/dot/driver-framework.dot +1 -1
  26. data/documentation/diagrams/dot/overall-pwn-architecture.dot +4 -4
  27. data/documentation/diagrams/dot/persistence-filesystem.dot +1 -1
  28. data/documentation/diagrams/dot/plugin-ecosystem.dot +2 -2
  29. data/documentation/diagrams/dot/task-summarizer.dot +18 -16
  30. data/documentation/diagrams/driver-framework.svg +1 -1
  31. data/documentation/diagrams/overall-pwn-architecture.svg +93 -93
  32. data/documentation/diagrams/persistence-filesystem.svg +4 -4
  33. data/documentation/diagrams/plugin-ecosystem.svg +101 -100
  34. data/documentation/diagrams/task-summarizer.svg +166 -156
  35. data/documentation/pwn-ai-Agent.md +9 -4
  36. data/lib/pwn/ai/agent/dispatch.rb +52 -1
  37. data/lib/pwn/ai/agent/loop.rb +198 -159
  38. data/lib/pwn/ai/agent/open_goal.rb +83 -0
  39. data/lib/pwn/ai/agent/policy.rb +2 -3
  40. data/lib/pwn/ai/agent/prompt_builder.rb +16 -13
  41. data/lib/pwn/ai/agent/registry.rb +6 -9
  42. data/lib/pwn/ai/agent/tools/sessions.rb +32 -0
  43. data/lib/pwn/ai/agent/tools/skills.rb +56 -0
  44. data/lib/pwn/ai/agent.rb +1 -0
  45. data/lib/pwn/ai/anthropic.rb +0 -1
  46. data/lib/pwn/ai/gemini.rb +0 -1
  47. data/lib/pwn/ai/grok.rb +0 -1
  48. data/lib/pwn/ai/ollama.rb +0 -1
  49. data/lib/pwn/ai/open_ai.rb +0 -1
  50. data/lib/pwn/ai/open_web_ui.rb +0 -1
  51. data/lib/pwn/config.rb +2 -2
  52. data/lib/pwn/cron.rb +18 -5
  53. data/lib/pwn/plugins/repl.rb +43 -1
  54. data/lib/pwn/plugins/tty_spinner.rb +109 -13
  55. data/lib/pwn/sessions.rb +82 -0
  56. data/lib/pwn/version.rb +1 -1
  57. data/spec/integration/persistence_roundtrip_spec.rb +2 -1
  58. data/spec/integration/prompt_builder_spec.rb +3 -3
  59. data/spec/integration/reinforced_feedback_loop_spec.rb +6 -11
  60. data/spec/lib/pwn/ai/agent/dispatch_spec.rb +38 -82
  61. data/spec/lib/pwn/ai/agent/loop_spec.rb +284 -11
  62. data/spec/lib/pwn/ai/agent/open_goal_spec.rb +37 -0
  63. data/spec/lib/pwn/ai/agent/prompt_builder_spec.rb +7 -3
  64. data/spec/lib/pwn/ai/agent/registry_spec.rb +16 -9
  65. data/spec/lib/pwn/ai/agent/tools/sessions_spec.rb +5 -0
  66. data/spec/lib/pwn/ai/agent/tools/skills_spec.rb +16 -0
  67. data/spec/lib/pwn/ai/red_team/test_case_engine_spec.rb +20 -0
  68. data/spec/lib/pwn/cron_spec.rb +13 -3
  69. data/spec/lib/pwn/plugins/repl_spec.rb +26 -0
  70. data/spec/lib/pwn/plugins/tty_spinner_spec.rb +44 -0
  71. data/spec/lib/pwn/sessions_spec.rb +29 -0
  72. data/spec/spec_helper.rb +6 -0
  73. data/third_party/pwn_rdoc.jsonl +28 -1
  74. metadata +4 -1
@@ -102,7 +102,7 @@ $ pwn --ai "run bin/pwn_sast against ./src and push findings to DefectDojo"
102
102
 
103
103
  ## What the agent can call
104
104
 
105
- 13 toolsets · **85 tools** - full table at
105
+ 13 toolsets · **87 tools** - full table at
106
106
  [Agent Tool Registry](Agent-Tool-Registry.md).
107
107
 
108
108
  The two that matter most:
@@ -144,7 +144,7 @@ There is no request type. Every request gets an English task compass.
144
144
  - Advancement needs a PRM +1 streak or a clear phase shift after tools on the active task (not a blind every-3-tools hop).
145
145
  - REPL contract: `on_tool.call('task', full_summary_text, '')` - result empty, no truncation.
146
146
 
147
- **Long-run pressure:** when recent turns keep hitting the iteration ceiling, the agent tightens the rest of the turn: lower `max_iters` (stricter on local engines than remote), a text-only finish, and no extra counterfactual forks. Task state and Learning still flush on the way out so the run ends with a real answer instead of thrashing.
147
+ **Long-run pressure:** budget-hot turns skip extra counterfactual forks. The last iteration strips tools only when the original request is already satisfied. Scars and overconfidence do not lower this request's `max_iters` (default 777). Task state and Learning still flush on the exhaust path.
148
148
 
149
149
  ![TaskSummarizer](diagrams/task-summarizer.svg)
150
150
 
@@ -156,7 +156,7 @@ task_summary_every: 5 # verbose progress every N tools
156
156
  task_summary_interval_s: 8.0 # or every N seconds (verbose)
157
157
  task_summary_verbose: false # mid-flight Progress: lines
158
158
  task_summary_llm: true # LLM task decompose (default on)
159
- max_iters: 75 # budget pressure may lower the effective cap (stricter on local engines)
159
+ max_iters: 777 # scars / overconf do not lower this request
160
160
  ```
161
161
 
162
162
 
@@ -197,7 +197,7 @@ max_iters: 75 # budget pressure may lower the effective cap (s
197
197
  | `reward_llm_timeout` | `12` | seconds for the cheap ORM chat (clamped 2..30) |
198
198
  | `verify_as_reward` | `nil` (auto) | browser-grounded claim sample policy |
199
199
  | `local_introspect` | `:failure_only` | ollama / openwebui end-of-turn introspect policy |
200
- | `tool_preference` | CORE_TOOLS list (act leads with shell) | Rank bonus + Policy suggested-action order |
200
+ | `tool_preference` | same list as CORE_TOOLS (`memory_recall`, `session_recall`, `skills_recall`, `pwn_eval`, `shell`, `mistakes_record`, `mistakes_resolve`, `learning_note_outcome`, `memory_remember`) | Rank bonus + Policy suggested-action order |
201
201
  | `defer_introspect` | `true` | Post-answer Learning on a background thread |
202
202
  | `prompt_cache` | `true` | Engine-native prefix cache (not Ollama / Open WebUI) |
203
203
 
@@ -227,3 +227,8 @@ The `shell` tool also blocks hping3 / nmap-style sweep commands when recon is
227
227
  not authorized. On how-to asks, memory SOPs about repo rubocop/rake hygiene are
228
228
  kept out of the prompt so the model does not pivot into unrelated verification.
229
229
 
230
+ Keyword routing, unfinished-goal resume (`continue` / `resume`), and
231
+ write-then-read completion: [Session Workflow](Session-Workflow.md).
232
+
233
+ [← Home](Home.md)
234
+
@@ -47,7 +47,7 @@ module PWN
47
47
  required = Array(entry.schema&.dig(:parameters, :required))
48
48
  args = ToolGuard.coerce_args(args: args, required: required) if defined?(ToolGuard)
49
49
  result = entry.handler.call(args)
50
- JSON.generate(success: true, result: result)
50
+ JSON.generate(success: true, result: result, effect: effect(name: entry.name, args: args))
51
51
  rescue StandardError => e
52
52
  JSON.generate(
53
53
  success: false,
@@ -281,6 +281,56 @@ module PWN
281
281
  []
282
282
  end
283
283
 
284
+ # Effect of a tool call from NAME + ARGV only — never stdout.
285
+ # :write mutate, :browse navigate, :recall store lookup, :read/:eval observe.
286
+ WRITE_ARGV_RX = /
287
+ \bsed\s+-i\b|\bruby\s+-i\b|\btee\b|
288
+ (?:\s|\A)>{1,2}\s+\S|
289
+ File\.(?:write|open|binwrite)|IO\.write|
290
+ \bopen\s*\([^)]*['"]w|
291
+ \b(?:cp|mv|rm|mkdir|touch|chmod|chown)\b|
292
+ \bgit\s+(?:add|commit|rm)
293
+ /ix
294
+ BROWSE_ARGV_RX = /
295
+ TransparentBrowser|browser_obj|\.goto\b|dump_links|
296
+ watir|headless_?chrome|\bdevtools\b
297
+ /ix
298
+ RECALL_TOOLS = %w[
299
+ memory_recall session_recall skills_recall sessions_view
300
+ sessions_list sessions_current
301
+ ].freeze
302
+ STORE_TOOLS = %w[
303
+ memory_remember mistakes_record mistakes_resolve
304
+ learning_note_outcome skill_create skill_add_reference
305
+ ].freeze
306
+
307
+ public_class_method def self.effect(opts = {})
308
+ name = opts[:name].to_s
309
+ return :read if name.empty?
310
+ return :recall if RECALL_TOOLS.include?(name)
311
+ return :store if STORE_TOOLS.include?(name)
312
+
313
+ blob = argv_blob(args: opts[:args])
314
+ return :browse if blob.match?(BROWSE_ARGV_RX)
315
+ return :write if blob.match?(WRITE_ARGV_RX)
316
+ return :eval if name == 'pwn_eval'
317
+
318
+ :read
319
+ rescue StandardError
320
+ :read
321
+ end
322
+
323
+ private_class_method def self.argv_blob(opts = {})
324
+ args = opts[:args]
325
+ args = JSON.parse(args, symbolize_names: true) if args.is_a?(String) && args.strip.start_with?('{')
326
+ case args
327
+ when Hash then args.values.join(' ')
328
+ else args.to_s
329
+ end
330
+ rescue StandardError
331
+ opts[:args].to_s
332
+ end
333
+
284
334
  private_class_method def self.symbolize(opts = {})
285
335
  hash = opts[:hash] ||= {}
286
336
  hash.each_with_object({}) { |(k, v), m| m[k.to_sym] = v }
@@ -306,6 +356,7 @@ module PWN
306
356
  )
307
357
 
308
358
  PWN::AI::Agent::Dispatch.repair_name(name: 'run_shell') # => 'shell'
359
+ PWN::AI::Agent::Dispatch.effect(name: 'shell', args: { command: 'ls' })
309
360
  PWN::AI::Agent::Dispatch.tool_calls_from_text(text: 'shell(command="id")')
310
361
 
311
362
  #{self}.authors