Compare commits

...
220 Commits
Author SHA1 Message Date
pancake 9077de9162 Snapshot async request configuration for HTTP sessions 2026-11-06 03:19:30 +01:00
pancake 287fad0ecd Release 1.5.4 2026-11-06 02:36:06 +01:00
pancake 08afde5117 Expand ~ in decai config paths before mkdir/touch 2026-11-02 19:23:04 +01:00
Agustin Torres a086a12f1d Replace the models api.anthropic.com retired
Replaced retired Anthropic model ids with the recommended replacements: the default model in src/anthropic.c and decai (claude-sonnet-5-5), plus docs, examples and model lists.

Notice anthropic-retired-models-2026-10 about api.anthropic.com's API describes the change. It was read from a file and is not signed by the provider.
2026-10-26 18:26:18 +01:00
pancake 4a86d0fc46 Fix build for r2-6.2.5 2026-10-20 23:21:46 +02:00
pancake 0509bf6755 Add decai -e http=curl|r2|auto 2026-10-19 08:54:40 +02:00
pancake 1d55b7f72a Define the new r2.http in the R2Pipe type for decai 2026-10-19 08:45:58 +02:00
pancake 222f0b7410 Exclude POSIX HTTP timers from WASI builds 2026-10-18 18:52:46 +02:00
pancake 065288e29f Use radare2 HTTP APIs for r2ai and decai in WASI 2026-10-18 18:52:46 +02:00
Abhi 5824aa4482 Release 1.5.3 2026-10-13 11:39:08 +05:30
Abhi 3c7ed851d8 Switch release assets to r2pm bindist zips (triplet naming)
- src/Makefile: bindist target producing r2ai-$(r2 -qv)-os-arch-bits.zip
  with plugins/, bin/, man/ and prompts/ (prompts dir overridable via
  R2AI_PROMPTSDIR; uname fallback for old r2pm)
- ci: split bindist job (linux x64/arm64 + macos) and windows bindist
  build (radare2 -qv for the zip name), attach zips + decai.r2.js to tag
  releases; no version pin so the action resolves the current release
2026-10-13 11:39:08 +05:30
pancake 1586d27e93 Release 1.5.2 2026-10-06 06:57:50 +02:00
pancake 898855d7ce Fix macOS build with inline r_mem_mem 2026-10-06 01:32:58 +02:00
pancake 20a3751624 Release 1.5.0 2026-10-06 00:45:47 +02:00
pancake d81957d856 Load API keys from environment as fallback 2026-10-03 08:56:09 +02:00
pancake b6d7c9424c Fix #130 - deterministic mode for r2ai 2026-10-02 18:21:35 +02:00
pancake c3efc53c27 Deduplicate system prompt fallback and message queue logic 2026-10-02 18:11:26 +02:00
pancake b6d234c154 Fix #172 - Add r2ai.history and store all queries in its context 2026-10-02 17:59:22 +02:00
pancake ef7f49a68e Keep the gemini auth header selection in one expression 2026-10-02 17:55:07 +02:00
pancake d1fcea6859 Share request building, parsing and posting across the providers
Gemini and Vertex Gemini share the request builder and response parser,
Anthropic and Vertex Anthropic share the request builder, and every
provider posts through r2ai_post, which centralizes the payload dumps,
the curl debug output and the error reporting.

Gemini now sends the system prompt as systemInstruction and reports
token usage. Also drops the unused streaming stubs and the dead
r2ai.system fallbacks, r2ai_llmcall always sets the system prompt.
2026-10-02 17:55:03 +02:00
pancake 96dcc0dd4f Dedup the decompilation block builder in r2ai -d and fix the prompt leak 2026-10-02 17:54:59 +02:00
pancake 659e14a4cd Dispatch providers through r2ai_send and look them up once
Rawtools now reaches every provider instead of only anthropic/openai,
and the model listing shares the header logic, sending the Gemini key
in a header instead of the URL.
2026-10-02 17:54:56 +02:00
pancake 926ef545d0 Share the conversation log formatter between -L and the compact prompt 2026-10-02 17:54:54 +02:00
pancake 1b11c648de Fix tool_call_id leak when recording auto mode tool responses 2026-10-02 17:54:51 +02:00
pancake 394e55cf87 Dedup message cloning and drop the unused json message parsers 2026-10-02 17:54:44 +02:00
pancake 8db446cf31 Dedup the async task lifecycle and command helpers
Add task_start, finish, cancelled, wait_tool, lookup and print_block
helpers, and drop the async queue guards since r2ai_init always
creates it.
2026-10-02 17:54:00 +02:00
pancake 65d7d87539 Rewrite the RJson to string converter as a single recursive emitter 2026-10-02 17:53:29 +02:00
pancake 372b38380f Share the tool confirmation prompt between r2cmd and execute_js 2026-10-02 17:53:24 +02:00
pancake 72b9ff2f49 Add ask and enqueue helpers to dedup the llm query paths 2026-10-02 17:53:16 +02:00
pancake 742d3f2a51 Unify the vdb query commands and drop the load_embeddings copy
-S and -Rq share cmd_r2ai_R, which honours r2ai.data.nth and prints
through r_cons. Also fixes the leaked file contents when indexing.
2026-10-02 17:53:01 +02:00
pancake 1f3f93fa35 Turn leftover auto mode debug prints into debug logs 2026-10-02 13:49:33 +02:00
pancake 3f1b91fbce Do not write the OpenAI bearer token to the debug log 2026-10-02 13:49:25 +02:00
pancake acd0513ebb Prompt for final auto response, fixes out of order logs 2026-10-02 13:48:55 +02:00
pancake c44e838238 Fix bogus format argument when logging the models request 2026-10-02 13:48:22 +02:00
pancake f4fa4ba432 Preserve negative integers when converting RJson to PJ 2026-10-02 13:46:49 +02:00
pancake 561db876ac Fix malformed bold escape sequences in auto mode output 2026-10-02 13:46:46 +02:00
pancake bcdc182d03 Snapshot tools and max_runs for async tasks on the main thread 2026-10-02 13:46:39 +02:00
pancake 19cba835e4 Remove leaking unreachable error paths in the Anthropic response parser 2026-10-02 13:46:32 +02:00
pancake 87a1e89112 Do not leak the Gemini API key in the request URL 2026-10-02 13:46:25 +02:00
pancake 012118c25c Fix Gemini headers and always send the Content-Type 2026-10-02 13:44:53 +02:00
pancake e2030b31a1 Escape r2ai.auto.init_commands when building for JSON 2026-10-02 13:44:39 +02:00
pancake 53f437d55a Keep assistant replies in the conversation log when clippy is enabled 2026-10-02 13:40:05 +02:00
pancake 66f202254e Fix prompt in r2ai one-shot mode and report errors 2026-10-02 13:39:42 +02:00
pancake 8e9555d144 Fix double advance on unterminated ${ and $( in prompt variables 2026-10-02 13:39:36 +02:00
pancake a8caa51e76 Do not update vdb TF-IDF statistics when querying 2026-10-02 13:39:34 +02:00
pancake 021aa205f0 Initialize the document frequency of new vdb tokens 2026-10-02 13:39:31 +02:00
pancake 92c86f94e6 Fix message leak on success in r2ai_msgs_from_json 2026-10-02 13:39:26 +02:00
pancake 50c1d63a47 Use text from the editor when confirming multiline tool calls 2026-10-02 13:35:30 +02:00
pancake 79f01945b7 Fix memleak when parsing r2ai rc file 2026-10-02 13:35:16 +02:00
pancake 9043638e01 Fix UAF in r2ai -d 2026-10-02 13:35:05 +02:00
pancake 6bd0227382 Render responses in markdown by default 2026-10-02 13:20:23 +02:00
pancake 9f9a3b87ae Fix token usage leaks after LLM calls 2026-09-07 00:44:43 +02:00
pancake b68ddaeaed Fix thread ownership race in r2ai_async_fini 2026-09-06 21:43:15 +02:00
pancake d2663f75dc Fix null deref when adding a toolCall 2026-09-06 21:41:24 +02:00
pancake e24dbab677 Release 1.4.4 2026-09-06 21:23:13 +02:00
pancake c765269b02 Add allocation checks and use calloc for KD-tree nodes 2026-09-06 21:13:54 +02:00
pancake 55b856e70b Refactor LLM call logic and improve tool call handling 2026-09-06 21:13:50 +02:00
pancake 5e148bc882 Null checks and improve error handling for curl and powershell 2026-09-06 21:13:42 +02:00
pancake 9f93754483 Fix baseurl with ending slashes 2026-08-19 16:22:42 +02:00
pancake d262fabb2b Add r2plugin abstraction for decai 2026-08-18 17:07:35 +02:00
pancake d0a1f292f5 Release 1.4.2 2026-08-16 21:26:19 +02:00
pancake dad02ac243 Fix OpenAI-compatible endpoint selection for Ollama 2026-08-05 00:42:46 +02:00
dependabot[bot] 02c561c415 Bump radareorg/github-actions from 2 to 3
Bumps [radareorg/github-actions](https://github.com/radareorg/github-actions) from 2 to 3.
- [Release notes](https://github.com/radareorg/github-actions/releases)
- [Commits](https://github.com/radareorg/github-actions/compare/v2...v3)

---
updated-dependencies:
- dependency-name: radareorg/github-actions
  dependency-version: '3'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-08-04 18:21:02 +02:00
pancake 9414cdf72b Fix build for latest r2 (abiversion 125) 2026-07-22 18:04:38 +02:00
pancake 7cc61c4cc5 Generic core editor helper 2026-07-16 16:13:17 +02:00
pancake e4875eeb37 Fix build with r2 from git 2026-07-16 13:38:30 +02:00
pancake 888251a2ea Improve kvcache misses and improve token usage 2026-06-28 19:14:33 +02:00
pancake af6153ad64 Support r2ai.apitype (also in decai) to specify generate/chat 2026-06-28 19:14:29 +02:00
dependabot[bot] 87e4e7b232 Bump actions/checkout from 6 to 7 2026-06-22 16:18:17 +02:00
pancake cc3a003a64 Cleanup the openai implementation 2026-06-17 18:07:49 +02:00
pancake f2be5cc3c2 Release 1.4.0 2026-06-03 09:53:26 +02:00
dependabot[bot] e360148931 Bump radareorg/github-actions from 1 to 2 2026-05-18 09:43:20 +03:00
pancake d06a9ee361 Implement -d in the r2ai shell to decompile from the cli 2026-05-14 21:41:20 +02:00
pancake 2e7b97b065 Add r2ai -s to seek on start 2026-05-14 21:34:28 +02:00
orbisai0security cd5d9a1640 Fix shell injection in the abandoned python implementation 2026-05-14 08:18:20 +02:00
Ole André Vadla Ravnås e606392aaf Emit libr2ai.a for embedders
meson uses library() so -Ddefault_library picks the kind.
Makefile also runs ar rcs and installs libr2ai.a + r2ai.h.
2026-05-09 13:11:07 +02:00
pancake 8bf1169844 Implement r2ai -do to decompile with offsets 2026-05-06 13:15:32 +02:00
pancake 90e3bbafc5 Format code 2026-05-05 20:05:56 +02:00
pancake e5a0639b88 Remvoe support for legacy query prompts 2026-05-05 20:02:23 +02:00
pancake 80f27cd4d9 Add -qj to list query prompts in json format 2026-05-05 19:56:40 +02:00
pancake 455da7bdba Improve query prompts syntax and parser 2026-05-05 19:49:18 +02:00
pancake 623e98ed3d Show tool command to be executed when prompting 2026-05-05 19:16:50 +02:00
pancake 17bf56b5e3 Add explicit aprove/reject actions for async tasks 2026-05-05 18:27:58 +02:00
pancake f50a7836eb Initial support for r2plugin xps 2026-05-05 14:03:40 +02:00
pancake 2d9b69c624 Reduce tool calling parameters using the new ToolResult struct 2026-05-05 13:54:48 +02:00
pancake de9c7c904c Auto prompt is no longer a global 2026-05-05 11:32:57 +02:00
pancake 6b3ea982cd Better structure for r2ai-sj 2026-05-05 11:13:50 +02:00
pancake 209d9257ee Use RCoreHelpMessage in async commands 2026-05-05 11:11:46 +02:00
pancake b840d002ee Fix #226 - R2AI_HEADERS and r2ai.http.headers 2026-05-05 10:56:44 +02:00
pancake 9d900b2a6b Fix autopurge in -sj/-s and rename -s*/-sp 2026-05-05 06:45:23 +02:00
AsherDLL 227b15e793 Add Vertex AI provider for Gemini and Anthropic models 2026-04-24 13:49:40 +02:00
pancake 4b9dbf7686 Fully go for RCore.call 2026-04-21 19:48:49 +02:00
pancake 8ca32e258f Add async.purge option and fix some thread locks 2026-04-20 20:56:16 +02:00
pancake 449c41eae6 Format the code again 2026-04-20 20:28:40 +02:00
pancake 5210fe6892 Initial support for async tasks 2026-04-20 20:26:36 +02:00
pancake 6222791075 Add SOUL.md/IDENTITY.md personality files via -id command 2026-04-14 20:48:50 +02:00
pancake 05ce908e3a Fix ollamacloud api arguments object error 2026-04-14 19:07:50 +02:00
pancake b8457c0bfa Release 1.3.8 2026-04-13 22:46:10 +02:00
pancake 6a256b9210 Refresh auto tool list when r2ai.auto.usejs changes 2026-04-13 22:45:30 +02:00
pancake 8cc748ab4c Honor per-call model/provider overrides in LLM backends 2026-04-13 22:35:18 +02:00
pancake 17df397a3d Fix argument parsing to make -Lj actually work 2026-04-13 19:54:42 +02:00
pancake fcd464f1cc Fix OpenAI debug crash with keyless backends 2026-04-13 19:48:08 +02:00
pancake 1f41b6d2d7 Fix getopt parsing for -i, -dr and -Rq 2026-04-13 19:43:37 +02:00
pancake adf8189541 Fix UB in r2ai_message_free error paths 2026-04-13 18:01:24 +02:00
dependabot[bot] cb8f3548ff Bump softprops/action-gh-release from 2 to 3 2026-04-13 18:00:24 +02:00
pancake b99034e5d8 Fix user message not included when the message list was empty 2026-04-12 21:17:53 +02:00
pancake fa1f6c1d3c Fix few logic mistakes swapping name/desc and such 2026-04-12 21:16:01 +02:00
pancake d9fb7b18df Fix duplicated user message then r2ai.data=true 2026-04-12 21:14:01 +02:00
pancake e0b9ff235c Fix invalid free crashes on tool call block 2026-04-12 21:00:38 +02:00
pancake e1bf58d4e4 Some better variable names for decai 2026-04-12 18:40:34 +02:00
pancake 51a63ac7ef Remove unused and duplicated logic using helpers where needed 2026-04-12 18:35:07 +02:00
pancake c3a3eff046 Single helper to check if function is available in decai 2026-04-12 18:11:18 +02:00
pancake 37b5c2b6d0 Fix thinking level issue causing slow queries in r2ai 2026-04-12 11:53:35 +02:00
pancake 0e6a8cc2e2 In decai fix thinking options for glm models making a clear time improvements 2026-04-12 11:42:55 +02:00
pancake 8dcc6f0418 Release 1.3.6 2026-04-11 18:06:11 +02:00
pancake b68cdd1171 Fix empty query bug in r2ai -i 2026-04-10 16:00:58 +02:00
pancake 3f935a46be Do not silently discards caller-provided message history 2026-04-10 15:53:19 +02:00
pancake fd46390d41 Break auto mode when receiving unknown actions 2026-04-10 15:45:42 +02:00
pancake 63106508dc In decai: Restore model state when decopipe execution fails 2026-04-10 15:45:00 +02:00
pancake 46f42d3dd9 Ignore comment lines in decai.txt (decai -E) 2026-04-09 21:39:08 +02:00
pancake 836fae3d91 Use github actions to install r2 in the ci 2026-04-09 11:02:00 +02:00
pancake 66dd3dced7 Oops missing file 2026-04-09 10:44:16 +02:00
pancake c016fc72ed Release 1.3.4 2026-03-31 18:32:01 +02:00
Abhi 779b787f2d Fix URL formatting for OpenAI compatible API 2026-03-31 16:49:22 +02:00
pancake ca210f149b Add zen, ollamacloud and lmstudio providers to r2ai, sync with decai 2026-03-30 17:46:10 +02:00
pancake 99e99b1797 Reduce some LOCs in decai 2026-03-30 16:51:16 +02:00
pancake fb5427238b Add 'decai -E' for the defaults 2026-03-30 16:45:46 +02:00
pancake d7c2dacd7a Add decai timeout, zen provider, improve prompt, custom headers and more 2026-03-30 16:38:10 +02:00
pancake d6c32f4b72 decai: tighten types and simplify provider/config handling 2026-03-30 15:26:23 +02:00
dependabot[bot] 0a083e7231 Bump actions/download-artifact from 4 to 8 2026-03-30 15:20:45 +02:00
dependabot[bot] 1a067fbbfc Bump softprops/action-gh-release from 1 to 2 2026-03-30 15:18:54 +02:00
dependabot[bot] 8a724d3682 Bump actions/upload-artifact from 4 to 7 2026-03-30 15:18:30 +02:00
dependabot[bot] 8f7d152aa3 Bump actions/checkout from 5 to 6 2026-03-30 15:17:48 +02:00
pancake 7120c325da Add dependabot 2026-03-30 13:47:53 +02:00
pancake 14c991cd10 Update ci actions 2026-03-30 13:47:16 +02:00
pancake d1ef1e065e Welcome to the initial r2clippy wizard 2026-03-30 13:45:06 +02:00
pancake 6f8ec21a39 Release 1.3.2 2026-03-19 14:47:39 +01:00
pancake 3db0744c91 Fix shell injection in curl command construction 2026-03-07 12:20:28 +01:00
pancake 3306e412e2 rawtools: require explicit TOOL prefix for tool execution 2026-03-07 12:20:13 +01:00
pancake 20f5e16164 fix: detect multiline after adding command annotations 2026-03-07 12:20:03 +01:00
pancake 660249a31f Fix double free and refactor the complex logic into a separate function 2026-03-06 17:03:30 +01:00
Nitan Alexandru Marcel 312921c2a1 Add r2agent reference in the README 2026-02-08 23:32:54 +01:00
pancake 2356dbef9e Release 1.3.0 2026-01-04 19:17:05 +01:00
pancake 7612a80a9c Warn about invalid syntax/lines in apikeys.txt 2025-12-10 20:05:55 +01:00
pancake 12d8bc9e22 Strip "_API_KEY" from providers in apikeys.txt 2025-12-10 20:03:25 +01:00
pancake d4be5f8569 Add .pkgname for the r2ai plugin 2025-12-10 01:01:45 +01:00
pancake a9333c8c38 Only one function doing curl and remove aliased providers in decai 2025-12-06 12:36:04 +01:00
pancake 29bdb2fcea Remove the hardcoded model names for providers with callback 2025-12-05 17:48:42 +01:00
pancake 078376c5d2 Refactor the model listing code in decai 2025-12-05 17:30:11 +01:00
pancake aa24702335 Refactor the providers logic in decai 2025-12-05 17:05:18 +01:00
pancake 9aa40216a2 Initial rewrite of decai in TypeScript 2025-12-05 16:44:09 +01:00
pancake 96e454e0c6 Fix tool calling message construction bug 2025-11-27 11:07:16 +01:00
pancake 219b034261 Don't feed system messages to Anthropic 2025-11-21 21:23:24 +01:00
pancake 797c967fb0 Remove redudant provider fields 2025-11-11 16:21:55 +01:00
pancake e61b7db8a5 Fix #219 - Add deepseek provider for r2ai.c 2025-11-11 16:03:10 +01:00
pancake 3a39f9cd9d Add decai -b to setup the baseurl 2025-11-07 00:25:59 +01:00
pancake 2b5e50d8f0 Workaround MANDIR for old r2 2025-11-06 16:36:45 +01:00
pancake bb737f5be6 Add decai -K to edit apikeys (requires latest r2 from git) 2025-11-06 16:33:05 +01:00
pancake 3e5f91e631 Load decai apikeys from ~/.config/r2ai/apikeys.txt 2025-11-06 14:19:11 +01:00
pancake a3154bdcaf Simplify and fix the gemini support in decai 2025-11-06 14:10:19 +01:00
pancake a6be6e6555 Add decai -p to select provider 2025-11-06 14:01:53 +01:00
pancake ad0bdbb902 Fix res error in gemini for decai 2025-11-06 13:44:55 +01:00
pancake 4651d3b1b3 Update the README 2025-11-05 17:40:51 +01:00
pancake 572e02c4ec Change symbol visibility to please Windows builds 2025-11-05 17:18:50 +01:00
pancake 75c787ef41 Fix the meson build 2025-11-05 12:52:25 +01:00
pancake 731f1933a9 Refactor the apikeys code into a separate file and use sample config key by default 2025-11-05 12:43:15 +01:00
pancake 573755ccef Add -e to r2ai main 2025-11-01 21:30:12 +01:00
pancake ecca7825fe Add r2ai -i to run scripts 2025-10-31 20:15:32 +01:00
pancake 95117608fb Small improvements for the clippy repl 2025-10-31 20:13:30 +01:00
pancake b3958b5f7d Initial clippy repl for the r2ai cli tool 2025-10-31 19:45:12 +01:00
pancake d0eaf37764 Fix -m? reported crash 2025-10-31 16:34:49 +01:00
pancake 65692edd54 Bring back the support for Gemini provider to r2ai.c 2025-10-30 20:08:33 +01:00
pancake 50f55bb5d2 Add r2ai -K to edit api keys and remove the unnecessary compatdb 2025-10-29 22:21:33 +01:00
pancake fe1768fcc3 Fix apikey error message 2025-10-29 16:50:30 +01:00
pancake f241fba17d Add WIP decai logo 2025-10-29 10:45:55 +01:00
pancake e5252960e0 Implement r2ai.auto.slim to make disasm slimmier for auto 2025-10-29 10:45:21 +01:00
pancake 8a45dadbde Rename r2ai.auto.hide_tool_output to r2ai.auto.verbose 2025-10-29 10:34:31 +01:00
pancake 53d32efbbe Deprecate r2ai.chat.show_cost 2025-10-29 10:28:48 +01:00
pancake f06faba9d6 Release 1.2.6 2025-10-29 00:02:52 +01:00
pancake 8b52c2f6e2 Fix ninja build 2025-10-28 23:55:39 +01:00
pancake b37436fb8d Fix more warnings 2025-10-28 23:41:45 +01:00
pancake 2524e66825 Fix warning unused variable 2025-10-28 23:35:41 +01:00
pancake 519017a75e Fix editing r2js scripts in auto mode 2025-10-28 23:34:05 +01:00
pancake 6f30d6ca37 Handle comments in commands in all the auto calls 2025-10-28 20:49:24 +01:00
pancake 08ea4d11b2 Better last call 2025-10-28 19:51:22 +01:00
pancake 0281308434 Fix the build 2025-10-28 19:42:11 +01:00
pancake 17a59d2057 Add r2ai.debug to see the llm requests and responses 2025-10-28 19:37:01 +01:00
pancake eac0b8c6ef Prompt before leaving the interrupted auto mode 2025-10-28 19:30:11 +01:00
pancake 24aee426b4 Comments in commands are now used as annotations for the conversation 2025-10-28 19:28:05 +01:00
pancake b31bc5c116 Suggested simpler auto prompt 2025-10-28 19:24:40 +01:00
pancake 01738210f5 Increase timeout to 4 minutes 2025-10-28 19:13:05 +01:00
pancake 7b19c4ff99 Resizing the terminal is no longer interrupting the network calls 2025-10-28 19:10:50 +01:00
pancake 1986dd88bd r2ai needs an argument to work 2025-10-28 12:57:20 +01:00
pancake 1ed40401dd Implement r2ai -C to compact the message log 2025-10-28 12:55:46 +01:00
pancake 6ac0ff6352 Add compact prompt 2025-10-28 12:17:49 +01:00
pancake 4158e5f157 Add an option to disable the js_execute tool 2025-10-28 00:05:30 +01:00
pancake 225ff58228 Add r2ai.auto.think to disable reasoning 2025-10-28 00:03:34 +01:00
pancake a51be44c68 Improve native tool calling prompt 2025-10-28 00:00:04 +01:00
pancake 911e455f72 Only capture ONE tool call from the auto response 2025-10-27 23:40:03 +01:00
pancake 70eb975b7f Fix the set_prompt for auto mode 2025-10-27 23:21:58 +01:00
pancake a0d36cc909 Implement the -LR command to create a log report 2025-10-27 23:08:51 +01:00
pancake 030551816b Fix windows build 2025-10-27 23:08:51 +01:00
pancake 88c44c871b Fix tool calling, at least for OpenAI 2025-10-27 23:08:51 +01:00
pancake 9218e3ea27 Capture the thinking 2025-10-27 23:08:51 +01:00
pancake 6f7ffcae1a Oh great now we have a bug in the json serializer of r2 2025-10-27 23:08:51 +01:00
pancake fe12d2f8ee Add r2ai -b for the shell 2025-10-27 23:08:51 +01:00
pancake ae55b2f204 Proper use of RList -20LOC 2025-10-27 23:08:51 +01:00
pancake 7d4e949240 Use RList instead of hardcoded NEWS vectors 2025-10-27 23:08:51 +01:00
pancake 9b97d39c7a Add r2ai -b to change the baseurl 2025-10-27 19:04:16 +01:00
pancake 33f72a997e Refactorings to avoid hardcoded ansi colors. Using Color macros instead 2025-10-27 18:47:49 +01:00
pancake 36a8f13131 Use R2_CURL on Windows 2025-10-27 18:29:01 +01:00
pancake 5c2ded0171 Fix r2ai -E and loading script 2025-10-27 17:46:18 +01:00
pancake d5a39816a8 Use R2__WINDOWS__ instead of defined(_WIN32) 2025-10-27 13:02:36 +01:00
pancake 5aab38ab76 Proper command escapes for curl and pwsh http backends 2025-10-27 13:00:35 +01:00
pancake 9f15ec6c73 Release 1.2.4 2025-10-26 15:04:03 +01:00
pancake 68baac9911 Transform all promptfiles into the new md format 2025-10-26 15:02:48 +01:00
pancake 54a280952e Load API keys from ~/.config/r2ai/apikeys.txt too 2025-10-26 14:46:20 +01:00
pancake efc2368af1 Move the examples into the attic 2025-10-26 14:31:46 +01:00
pancake 28ddcbf638 Refactor and cleanup the http.backend implementations 2025-10-26 14:04:58 +01:00
pancake 85e9ed5c65 Do not accept invalid values in r2ai.http.backend 2025-10-25 19:56:10 +02:00
146 changed files with 9489 additions and 5584 deletions

No files matched your search

+8
View File
@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
labels:
- buildsystem
+85 -69
View File
@@ -1,7 +1,7 @@
name: CI and Release
env:
R2V: 6.0.4
R2V: 6.2.6
on:
push:
@@ -26,7 +26,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Setup Meson/Ninja
if: matrix.build_system == 'meson'
@@ -34,38 +34,11 @@ jobs:
python -m pip install --upgrade pip
pip install meson ninja
- name: Install radare2 on Linux
if: matrix.os == 'ubuntu-24.04'
run: |
wget "https://github.com/radareorg/radare2/releases/download/${R2V}/radare2_${R2V}_amd64.deb"
wget "https://github.com/radareorg/radare2/releases/download/${R2V}/radare2-dev_${R2V}_amd64.deb"
sudo dpkg -i "radare2_${R2V}_amd64.deb"
sudo dpkg -i "radare2-dev_${R2V}_amd64.deb"
- name: Install radare2 on macOS
if: matrix.os == 'macos-latest'
run: |
git clone --depth=1 --branch "${{env.R2V}}" https://github.com/radareorg/radare2
cd radare2
sys/install.sh
- name: Install radare2 on Windows
if: matrix.os == 'windows-latest'
shell: powershell
run: |
$url = "https://github.com/radareorg/radare2/releases/download/${{ env.R2V }}/radare2-${{ env.R2V }}-w64.zip"
$dest = "$env:TEMP\radare2.zip"
Invoke-WebRequest -Uri $url -OutFile $dest -UseBasicParsing
$prefix = 'C:\radare2'
if (Test-Path $prefix) { Remove-Item -Path $prefix -Recurse -Force }
Expand-Archive -Path $dest -DestinationPath $prefix -Force
# Move contents from subdirectory if present
$subdirs = Get-ChildItem -Path $prefix -Directory
if ($subdirs.Count -eq 1) {
$subdir = $subdirs[0]
Get-ChildItem -Path $subdir.FullName | Move-Item -Destination $prefix -Force
Remove-Item -Path $subdir.FullName -Recurse -Force
}
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Build with Make
if: matrix.build_system == 'make'
@@ -75,7 +48,7 @@ jobs:
if: matrix.build_system == 'meson' && matrix.os != 'windows-latest'
run: |
cd src
meson setup build -Dr2_prefix=${{ secrets.R2_PREFIX }} || meson configure build
meson setup build || meson configure build
meson compile -C build
- name: Build with Meson (Windows)
@@ -83,51 +56,92 @@ jobs:
shell: powershell
run: |
cd src
$prefix = 'C:\radare2'
$prefix = "${{ steps.r2.outputs.prefix }}"
meson setup build --backend ninja --prefix="$prefix" -Dr2_prefix="$prefix"
if ($LASTEXITCODE -ne 0) { meson configure build }
meson compile -C build
- name: Create release artifacts (tags only)
if: startsWith(github.ref, 'refs/tags/')
shell: bash
run: |
mkdir -p release
# Collect common binary artefact names produced by Make/Meson
# Include both "r2ai.*" and "libr2ai.*" variants for DLL/dylib/so on all platforms.
find src -type f \( -iname "r2ai.dll" -o -iname "libr2ai.dll" -o -iname "r2ai.dylib" -o -iname "libr2ai.dylib" -o -iname "r2ai.so" -o -iname "libr2ai.so" -o -iname "r2ai.exe" \) -exec cp -f {} release/ \; || true
# Also check top-level build output directories
find . -maxdepth 3 -type f \( -iname "r2ai.dll" -o -iname "libr2ai.dll" -o -iname "r2ai.dylib" -o -iname "libr2ai.dylib" -o -iname "r2ai.so" -o -iname "libr2ai.so" -o -iname "r2ai.exe" \) -exec cp -f {} release/ \; || true
cp -f decai/decai.r2.js release/ || true
if command -v zip >/dev/null 2>&1; then
zip -j "release/r2ai-${{ github.ref_name }}-${{ matrix.os }}-${{ matrix.build_system }}.zip" release/*
else
powershell.exe -Command "Compress-Archive -Path release/* -DestinationPath 'release/r2ai-${{ github.ref_name }}-${{ matrix.os }}-${{ matrix.build_system }}.zip'"
fi
bindist:
name: Build r2pm binary (${{ matrix.os }})
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Upload artifacts (tags only)
if: startsWith(github.ref, 'refs/tags/')
uses: actions/upload-artifact@v4
- name: Install radare2
uses: radareorg/github-actions@v3
with:
name: ${{ matrix.os }}-${{ matrix.build_system }}-binary
path: release/r2ai-${{ github.ref_name }}-${{ matrix.os }}-${{ matrix.build_system }}.zip
version: ${{ env.R2V }}
# - name: Smoke test
# run: |
# if command -v r2 >/dev/null 2>&1; then
# r2 -q -c 'r2ai -h' -- || true
# fi
- name: Package r2pm binary
run: make -C src bindist
- name: Upload r2pm binary artifact
uses: actions/upload-artifact@v7
with:
name: bindist-${{ matrix.os }}
path: r2ai-*.zip
if-no-files-found: error
windows-bindist:
name: Build r2pm binary (Windows)
runs-on: windows-latest
steps:
- name: Checkout
uses: actions/checkout@v7
- name: Setup Meson/Ninja
run: |
python -m pip install --upgrade pip
pip install meson ninja
- name: Install radare2
id: r2
uses: radareorg/github-actions@v3
with:
version: ${{ env.R2V }}
- name: Build with Meson
shell: powershell
run: |
cd src
$prefix = "${{ steps.r2.outputs.prefix }}"
meson setup build --backend ninja --prefix="$prefix" -Dr2_prefix="$prefix"
if ($LASTEXITCODE -ne 0) { meson configure build }
meson compile -C build
- name: Package r2pm binary
shell: pwsh
run: |
New-Item -ItemType Directory -Force -Path bindist\plugins,bindist\bin,bindist\prompts | Out-Null
Get-ChildItem src\build\ -Filter "*r2ai*.dll" -ErrorAction SilentlyContinue | Copy-Item -Destination bindist\plugins
Get-ChildItem src\..\build\ -Filter "*r2ai*.dll" -ErrorAction SilentlyContinue | Copy-Item -Destination bindist\plugins
Copy-Item src\build\r2ai.exe bindist\bin
Copy-Item prompts\*.r2ai.md bindist\prompts
$rv = (& radare2 -qv).Trim()
Compress-Archive -Path bindist\* -DestinationPath "r2ai-$rv-windows-x86-64.zip" -Force
- name: Upload r2pm binary artifact
uses: actions/upload-artifact@v7
with:
name: windows-bindist
path: r2ai-*.zip
if-no-files-found: error
release:
name: Create Release
needs: build
needs: [bindist, windows-bindist]
if: startsWith(github.ref, 'refs/tags/')
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v7
- name: Verify tag is on master
run: |
@@ -137,18 +151,20 @@ jobs:
exit 0
fi
- name: Download artifacts
uses: actions/download-artifact@v4
- name: Download r2pm binary artifacts
uses: actions/download-artifact@v8
with:
pattern: '*bindist*'
path: release-artifacts
merge-multiple: true
- name: Add decai.r2.js to release artifacts
run: cp decai/decai.r2.js release-artifacts/
- name: Create GitHub Release
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v3
with:
files: |
release-artifacts/**/*.zip
release-artifacts/*.zip
release-artifacts/decai.r2.js
generate_release_notes: true
generate_release_notes: true
+3
View File
@@ -12,3 +12,6 @@ venv
*.dylib
*.a
third_party
# r2pm binary packages
r2ai-*.zip
+3 -3
View File
@@ -23,12 +23,12 @@ if [ -f ~/.r2ai.openai-key ]; then
OPENAI_KEY=$(cat ~/.r2ai.openai-key)
fi
CLAUDE_KEY=""
CLAUDE_MODEL="claude-3-5-sonnet-20241022"
CLAUDE_MODEL="claude-sonnet-5-5"
if [ -f ~/.r2ai.anthropic-key ]; then
CLAUDE_KEY=$(cat ~/.r2ai.anthropic-key)
fi
DEEPSEEK_KEY=""
DEEPSEEK_MODEL="claude-3-5-sonnet-20241022"
DEEPSEEK_MODEL="claude-sonnet-5-5"
if [ -f ~/.r2ai.deepseek-key ]; then
DEEPSEEK_KEY=$(cat ~/.r2ai.anthropic-key)
fi
@@ -138,7 +138,7 @@ GEMINI_KEY=~/.r2ai-gemini.key
OPENAI_KEY=~/.r2ai-openai.key
CLAUDE_KEY=~/.r2ai-anthropic.key
DEEPSEEK_KEY=~/.r2ai-deepseek.key
CLAUDE_MODEL=claude-3-5-sonnet-20241022
CLAUDE_MODEL=claude-sonnet-5-5
EOF
exit 0
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1 -1
View File
@@ -49,7 +49,7 @@ python3 main.py
**Example selecting a remote models:**
```
[r2ai:0x00006aa0]> -m anthropic:claude-3-7-sonnet-20250219
[r2ai:0x00006aa0]> -m anthropic:claude-sonnet-5-5
[r2ai:0x00006aa0]> -m openai:gpt-4
```
+4 -7
View File
@@ -62,7 +62,7 @@ Uncensored:
Remote:
-m openapi:http://localhost:5001
-m openai:gpt-4
-m anthropic:claude-3-7-sonnet-20250219
-m anthropic:claude-sonnet-5-5
-m bedrock:anthropic.claude-3-5-sonnet-20241022-v1
-m kobaldcpp:http://localhost:5001
"""
@@ -80,12 +80,9 @@ OpenAI:
-m openai:gpt-4
-m openai:gpt-4-1106-preview
Anthropic:
-m anthropic:claude-2.1
-m anthropic:claude-3-haiku-20240307
-m anthropic:claude-3-opus-20240229
-m anthropic:claude-3-sonnet-20240229
-m anthropic:claude-3-5-sonnet-20241022
-m anthropic:claude-3-7-sonnet-20250219
-m anthropic:claude-opus-4-8
-m anthropic:claude-sonnet-5-5
-m anthropic:claude-haiku-4-5-20251001
groq:
-m groq:gemma-7b-it
-m groq:llama2-70b-4096
+1 -2
View File
@@ -170,8 +170,7 @@ def slurp_until(endword):
def list_models():
print("ollama/llama3:latest")
print("ollama/granite-code:8b")
print("anthropic/claude-3-5-sonnet-20240620")
print("anthropic/claude-3-7-sonnet-20250219")
print("anthropic/claude-sonnet-5-5")
print("openai/gpt-4o")
print("mistral/mistral-tiny")
+14 -3
View File
@@ -50,8 +50,16 @@ def stt(seconds, lang):
return
tts("(r2ai) listening for 5s... ", "digues?", lang)
print(f"DEVICE IS {device}")
os.system("rm -f .audiomsg.wav")
rc = os.system(f"ffmpeg -f avfoundation -t 5 -i '{device}' .audiomsg.wav > /dev/null 2>&1")
try:
os.remove(".audiomsg.wav")
except OSError:
pass
result = subprocess.run(
["ffmpeg", "-f", "avfoundation", "-t", "5", "-i", device, ".audiomsg.wav"],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL
)
rc = result.returncode
if rc != 0:
tts("(r2ai)", "cannot record from microphone. missing permissions in terminal?", lang)
return
@@ -60,7 +68,10 @@ def stt(seconds, lang):
result = model.transcribe(".audiomsg.wav")
else:
result = model.transcribe(".audiomsg.wav", language=lang)
os.system("rm -f .audiomsg.wav")
try:
os.remove(".audiomsg.wav")
except OSError:
pass
tts("(r2ai)", "ok", lang)
text = result["text"].strip()
if text == "you":
+4 -1
View File
@@ -3,4 +3,7 @@ TARGETS=all clean mrproper user-install install user-uninstall uninstall fmt ind
$(TARGETS):
$(MAKE) -C src $@
.PHONY: $(TARGETS)
test: all
$(MAKE) -C test
.PHONY: $(TARGETS) test
+17 -10
View File
@@ -27,6 +27,9 @@ If you are looking to use radare2 with other agents via MCP:
* **r2mcp** - the [official radare2 mcp](https://github.com/radare2/radare2-mcp)
* **r2copilot** - the mcp with focus on CTF [r2copilot](https://github.com/darallium/r2-copilot)
If you are looking for a radare2 focused autonomous agent:
* **r2agent** - automate radare2 workflows through autonomous agents. [r2agent](https://github.com/nitanmarcel/r2agent)
## Features
* Configure different roles and customize prompts
@@ -67,30 +70,34 @@ $ r2pm -Uci decai
- Adds the **r2ai** command to the radare2 shell: `r2 -qc r2ai`
- You can also run the wrapper in $PATH: `r2pm -r r2ai`
Drop your API keys in environment variables or files in your home:
Drop your API keys in environment variables or use the configuration file:
```console
$ cat ~/.r2ai.anthropic-key
sk-ant-api03-CENSORED
$ export ANTHROPIC_API_KEY=sk-ant-api03-CENSORED
$ export OPENAI_API_KEY=sk-proj-6rlSPS-zN1v...
```
| AI | API key |
| --------- | -------------------------- |
| OpenAI | `$HOME/.r2ai.openai-key` |
| Gemini | `$HOME/.r2ai.gemini-key` |
| Anthropic | `$HOME/.r2ai.anthropic-key` |
| Mistral | `$HOME/.r2ai.mistral-key` |
Or edit the api keys file `~/.config/r2ai/apikeys.txt` run:
```console
$ r2ai -K
```
## Saving settings
You may customize and save your configuration settings using your OS's default settings file (e.g `~/.radare2rc` on Linux).
For example, the following configuration sets Claude 3.7 by default, with max output tokens to 64000.
```console
$ r2ai -E
```
then you can type the commands you want to run when the r2ai plugin is loaded:
```console
r2ai -e api=anthropic
r2ai -e model=claude-3-7-sonnet-20250219
r2ai -e model=claude-sonnet-5-5
r2ai -e max_tokens=64000
```
+1 -1
View File
@@ -1 +1 @@
1.2.2
1.5.4
+2 -1
View File
@@ -1,5 +1,6 @@
#!/bin/sh
vim decai/decai.r2.js
vim decai/src/constants.ts
make -C decai/src
vim src/r2ai.h
vim src/meson.build
vim VERSION
+13
View File
@@ -0,0 +1,13 @@
# Decompiler based AI
## Actions
* Build: `make -C src`
* Install: `make user-install`
* Test: `r2 -A -qc "decai -e api=ollamacloud;decai -e model=glm-5;decai -d @ 0x100000924" /bin/ls`
## Hints
* Never read the minified, autogenerated `decai.r2.js`
* Focus and work only on the TypeScript source
* Never run `tsc` or `npx`. Always use `make` targets to compile
+5 -6
View File
@@ -1,17 +1,16 @@
PD=$(shell r2 -H R2_USER_PLUGINS)
SPD=$(shell r2 -H R2_LIBR_PLUGINS)
#BF=/bin/dd
BF=a.out
BF=/bin/dd
all:
@echo "Run: make user-install"
@echo "Run: 'make user-install' to install it in your home"
@echo "Run: 'make -C src' to recompile the r2.js"
test:
@echo 'You can now use 'decai' command'
r2 -i decai.r2.js -c 'decai -e deterministic=true' -caf $(BF)
fmt indent:
deno fmt
$(MAKE) -C src fmt
user-install:
mkdir -p "$(PD)"
@@ -27,4 +26,4 @@ uninstall:
make user-uninstall PD=$(SPD)
vs open:
open -a "Visual Studio Code" .
open -a "Visual Studio Code" src
+39
View File
@@ -37,6 +37,7 @@ Usage: decai (-h) ...
decai -dd [..] - same as above, but ignoring cache
decai -dD [query]- decompile current function with given extra query
decai -e - display and change eval config vars
decai -E - edit decai.txt
decai -h - show this help
decai -i [f] [q] - include given file and query
decai -n - suggest better function name
@@ -55,10 +56,12 @@ Configuration options:
```console
[0x00000000]> decai -e
decai -e api=ollama
decai -e apitype=chat
decai -e host=http://localhost
decai -e port=11434
decai -e prompt=Rewrite this function and respond ONLY with code, NO explanations, NO markdown, Change 'goto' into if/else/for/while, Simplify as much as possible, use better variable names, take function arguments and strings from comments like 'string:'
decai -e ctxfile=
decai -e headers=
decai -e cmds=pdc
decai -e cache=false
decai -e lang=C
@@ -96,6 +99,16 @@ decai -e ctxfile=
...
```
Persist user defaults in `~/.config/r2ai/decai.txt` with one `key=value` entry
per line, then edit it with `decai -E`. That file is loaded on the first
`decai` command in a session and reloaded after `decai -E` exits.
Use `decai -e http=curl` to force system curl, `http=r2` to require `r2.http()`,
or `http=auto` (the default) to use `r2.http()` when available and curl otherwise.
Failed `r2.http()` calls return an error without falling back to curl. The
`timeout` setting applies only to system curl. Save `http=curl` in
`~/.config/r2ai/decai.txt` to persist the override.
List possible APIs to discuss with AI: `decai -e api=?`:
```
@@ -106,6 +119,14 @@ openapi
...
```
Extra headers can be injected globally with `decai -e headers=...` or from the
environment with `DECAI_HEADERS` / `R2AI_HEADERS`. Use one header per line, for
example:
```console
[0x00406cac]> decai -e headers=Authorization: Bearer sk-123\nUser-Agent: curl/8.7.1
```
### Example using a local model and ollama
For example, if Ollama serves model codegeex4:latest (`ollama ls`), set decai
@@ -197,3 +218,21 @@ void daemonize() {
}
...
```
## WASM HTTP
With radare2's WASI HTTP build, decai defaults to `r2.http()` to reach the existing
`r_socket_http_get/post` C APIs. Headers and JSON payloads go directly to the
host HTTP adapter; no shell curl, temporary payload file or WebSocket proxy is
needed. A failed/denied HTTP call is returned as an error, without a shell
fallback. In `http=auto` mode, runtimes without `r2.http()` use system curl.
Enable HTTP in the embedding application (`enabled: true` in JavaScript or
`network=True` in Python). The radare2 sandbox must permit both `socket` and
`network`; process execution is not needed. Browser requests remain subject
to CORS. The host adapter controls the HTTP deadline in WASM; decai's `timeout`
setting still controls native curl only. Responses are buffered, not streamed.
This requires radareorg/radare2#27037 and the rebuilt decai script. For the
C r2ai plugin compiled into WASM, the `auto` HTTP backend likewise selects
radare2's C HTTP implementation; native backend selection is unchanged.
+64 -1256
View File
File diff suppressed because it is too large. Load diff
+36
View File
@@ -0,0 +1,36 @@
# decai r2plugin
Boilerplate to embed `decai.r2.js` inside the radare2 core library using the
external plugin system (XPS). Unlike `r2ai/r2plugin`, this does not link any
native code: the r2.js script is converted into a C buffer and registered as
an embedded startup script, so r2 runs it at startup exactly like a file in
the `plugins/*.r2.js` directory (honoring `cfg.plugins`).
The `decai.r2.js` bundle is built from the typescript sources with
`r2frida-compile` (see `make -C src` in the decai directory). The C buffer is
generated at build time with `rax2 -C` (make builds) or `js2c.py` (meson).
## Usage
decai lives inside the r2ai repository, so expose it as `libr/xps/p/decai`:
```console
cd radare2/libr/xps/p
git clone https://github.com/radareorg/r2ai
ln -s r2ai/decai decai
```
For acr/make builds:
```console
cd radare2
make -C libr/xps EXTERNAL_PLUGINS=decai
./configure-plugins
make
```
For meson builds, make `libr/xps/p/meson.build` contain:
```meson
subdir('decai/r2plugin')
```
+2
View File
@@ -0,0 +1,2 @@
/Users/pancake/prg/radare2/libr/xps/p/decai/r2plugin/core/decai.r2.js.o: \
/Users/pancake/prg/radare2/libr/xps/p/decai/r2plugin/core/decai.r2.js.c
+3
View File
@@ -0,0 +1,3 @@
#ifdef R2_CORE_H
extern RCorePlugin r_core_plugin_decai;
#endif
+10
View File
@@ -0,0 +1,10 @@
DECAI_CORE_WD=$(LIBR)/xps/p/decai
DECAI_CORE_OBJ= \
$(DECAI_CORE_WD)/r2plugin/core/plugin.o \
$(DECAI_CORE_WD)/r2plugin/core/decai.r2.js.o
EXTERNAL_STATIC_OBJS+=$(DECAI_CORE_OBJ)
# decai.r2.js can be rebuilt from typescript with r2frida-compile (make -C src)
$(DECAI_CORE_WD)/r2plugin/core/decai.r2.js.c: $(DECAI_CORE_WD)/decai.r2.js
rax2 -C < $(DECAI_CORE_WD)/decai.r2.js | \
sed -e 's,^unsigned,const unsigned,' -e 's,buf,decai_qjs,g' > $@
+35
View File
@@ -0,0 +1,35 @@
/* decai - LGPL - Copyright 2026 - pancake */
#include <r_core.h>
// generated from ../decai.r2.js, see ../deps.mk
extern const unsigned char decai_qjs[];
extern const unsigned int decai_qjs_len;
static bool decai_init(RCorePluginSession *cps) {
r_core_script_embed (cps->core, "decai", "qjs", (const char *)decai_qjs, (int)decai_qjs_len);
return true;
}
static bool decai_call(RCorePluginSession *cps, const char *input) {
return false;
}
RCorePlugin r_core_plugin_decai = {
.meta = {
.name = "decai",
.desc = "AI decompiler (embedded decai.r2.js)",
.author = "pancake",
.license = "MIT",
},
.init = decai_init,
.call = decai_call,
};
#ifndef R2_PLUGIN_INCORE
R_API RLibStruct radare_plugin = {
.type = R_LIB_TYPE_CORE,
.data = &r_core_plugin_decai,
.version = R2_VERSION,
};
#endif
+372
View File
@@ -0,0 +1,372 @@
/Users/pancake/prg/radare2/libr/xps/p/decai/r2plugin/core/plugin.o: \
/Users/pancake/prg/radare2/libr/xps/p/decai/r2plugin/core/plugin.c \
/Users/pancake/prg/radare2/libr/include/r_core.h \
/Users/pancake/prg/radare2/libr/include/r_main.h \
/Users/pancake/prg/radare2/libr/include/r_types.h \
/Users/pancake/prg/radare2/libr/include/r_types_base.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/ctype.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_ctype.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/cdefs.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_symbol_aliasing.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_posix_availability.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/ptrcheck.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_bounds.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/runetype.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/_types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/_types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_size_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_ct_rune_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_rune_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_wchar_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_wint_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/appleapiopts.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/types.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_int8_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_int16_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_int32_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_int64_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_int8_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_int16_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_int32_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_int64_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_intptr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_uintptr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/_endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/_endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/__endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/libkern/_OSByteOrder.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/libkern/arm/_OSByteOrder.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_char.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_short.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_u_int.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_caddr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_dev_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_blkcnt_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_blksize_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_gid_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_in_addr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_in_port_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_ino_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_ino64_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_key_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_mode_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_nlink_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_id_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_pid_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_off_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_uid_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_clock_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_ssize_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_time_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_useconds_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_suseconds_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_rsize_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_errno_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_def.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/Availability.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/AvailabilityVersions.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/AvailabilityInternal.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/AvailabilityInternalLegacy.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_setsize.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_set.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_clr.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_zero.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_isset.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fd_copy.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_attr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_cond_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_condattr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_mutex_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_mutexattr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_once_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_rwlock_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_rwlockattr_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_pthread/_pthread_key_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fsblkcnt_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_fsfilcnt_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/limits.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/limits.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/limits.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/limits.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/_limits.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/syslimits.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/stdint.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdint.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_uint8_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_uint16_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_uint32_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_uint64_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_intmax_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_uintmax_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/stdbool.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/math.h \
/Users/pancake/prg/radare2/libr/include/r_types_overflow.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_str_util.h \
/Users/pancake/prg/radare2/libr/include/r_userconf.h \
/Users/pancake/prg/radare2/libr/include/r_version.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/stddef.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stddef.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_header_macro.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_ptrdiff_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_size_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_rsize_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_wchar_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_null.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_max_align_t.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stddef_offsetof.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdlib.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_stdlib.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/wait.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/signal.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/signal.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/signal.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/_mcontext.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/_mcontext.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/machine/_structs.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/mach/arm/_structs.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_sigaltstack.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_ucontext.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_sigset_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/resource.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_timeval.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/alloca.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_null.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/malloc/_malloc.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/malloc/_malloc_type.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/malloc/_ptrcheck.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_abort.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/assert.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_assert.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_static_assert.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/inttypes.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/inttypes.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_inttypes.h \
/Users/pancake/prg/radare2/libr/include/r_types_null.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/stdio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_stdio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_va_list.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/stdio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_printf.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_seek_set.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_ctermid.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_stdio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_common.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/string.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_string.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_strings.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_strings.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/secure/_string.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/stdarg.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg_header_macro.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg___gnuc_va_list.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg_va_list.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg_va_arg.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg___va_copy.h \
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/21/include/__stdarg_va_copy.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/fcntl.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/fcntl.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_o_sync.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_o_dsync.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_s_ifmt.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_timespec.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_filesec_t.h \
/Users/pancake/prg/radare2/libr/include/r_endian.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/stat.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/dirent.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/dirent.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/unistd.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/unistd.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_posix_vdisable.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/select.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_select.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_uuid_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/gethostuuid.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/time.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_timeval64.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/time.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_time.h \
/Users/pancake/prg/radare2/libr/include/r_getopt.h \
/Users/pancake/prg/radare2/libr/include/r_util.h \
/Users/pancake/prg/radare2/libr/include/r_regex.h \
/Users/pancake/prg/radare2/libr/include/r_list.h \
/Users/pancake/prg/radare2/libr/include/sdb/sdb.h \
/Users/pancake/prg/radare2/libr/include/sdb/asserts.h \
/Users/pancake/prg/radare2/libr/include/sdb/types.h \
/Users/pancake/prg/radare2/libr/include/sdb/config.h \
/Users/pancake/prg/radare2/libr/include/sdb/ht.h \
/Users/pancake/prg/radare2/libr/include/sdb/ht_pp.h \
/Users/pancake/prg/radare2/libr/include/sdb/ht_inc.h \
/Users/pancake/prg/radare2/libr/include/sdb/ls.h \
/Users/pancake/prg/radare2/libr/include/sdb/heap.h \
/Users/pancake/prg/radare2/libr/include/sdb/dict.h \
/Users/pancake/prg/radare2/libr/include/sdb/cdb.h \
/Users/pancake/prg/radare2/libr/include/sdb/cdb_make.h \
/Users/pancake/prg/radare2/libr/include/sdb/buffer.h \
/Users/pancake/prg/radare2/libr/include/sdb/version.h \
/Users/pancake/prg/radare2/libr/include/sdb/rangstr.h \
/Users/pancake/prg/radare2/libr/include/r_skiplist.h \
/Users/pancake/prg/radare2/libr/include/r_th.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_w32.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_sys.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/errno.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/errno.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/semaphore.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/semaphore.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/pthread.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/pthread/sched.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/pthread/pthread_impl.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/pthread/qos.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/qos.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_mach_port_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/signal.h \
/Users/pancake/prg/radare2/libr/include/r_event.h \
/Users/pancake/prg/radare2/libr/include/sdb/ht_up.h \
/Users/pancake/prg/radare2/libr/include/r_vec.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_assert.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_log.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_arena.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_itv.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_signal.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_alloc.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_rbtree.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_trie.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_strs.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_xml.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_new_rbtree.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_intervaltree.h \
/Users/pancake/prg/radare2/libr/include/r_util/../r_types.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_big.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_base32.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_base36.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_base64.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_base91.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_buf.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_mem.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_ref.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_bits.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_bitmap.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_bitset.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_time.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_debruijn.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_type.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_file.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_hex.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_name.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_num.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_table.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_graph.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_panels.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_pool.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_diff.h \
/Users/pancake/prg/radare2/libr/include/r_cons.h \
/Users/pancake/prg/radare2/libr/include/r_util/pj.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_strbuf.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_json.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_sandbox.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_stack.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_str.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/wchar.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_wchar.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_mbstate_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/__wctype.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/___wctype.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/_types/_wctype_t.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_str_constpool.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/termios.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/termios.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/ttycom.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/ioccom.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/ttydefaults.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/ioctl.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/filio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/sockio.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/net/if.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/net/if_var.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_timeval32.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/net/net_kev.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/socket.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/constrained_ctypes.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/machine/_param.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arm/_param.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_sa_family_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_socklen_t.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/_types/_iovec_t.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_punycode.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_queue.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_range.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_spaces.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_strs_store.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_bloom.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_strpool.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_tree.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_uleb128.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_utf8.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_utf16.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_utf32.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_idpool.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_asn1.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_graph_drawable.h \
/Users/pancake/prg/radare2/libr/include/r_config.h \
/Users/pancake/prg/radare2/libr/include/r_util/bplist.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_x509.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_pkcs7.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_protobuf.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_token.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_axml.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_cfloat.h \
/Users/pancake/prg/radare2/libr/include/r_util/libc.h \
/Users/pancake/prg/radare2/libr/include/r_socket.h \
/Users/pancake/prg/radare2/libr/include/r_bind.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/netinet/in.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/netinet6/in6.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/un.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/poll.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/poll.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/arpa/inet.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/netdb.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/netinet/tcp.h \
/Users/pancake/prg/radare2/libr/include/r_magic.h \
/Users/pancake/prg/radare2/libr/include/r_agraph.h \
/Users/pancake/prg/radare2/libr/include/r_io.h \
/Users/pancake/prg/radare2/libr/include/r_lib.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/dlfcn.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_w32dw.h \
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/sys/ptrace.h \
/Users/pancake/prg/radare2/libr/include/r_fs.h \
/Users/pancake/prg/radare2/libr/include/r_egg.h \
/Users/pancake/prg/radare2/libr/include/r_asm.h \
/Users/pancake/prg/radare2/libr/include/r_arch.h \
/Users/pancake/prg/radare2/libr/include/r_bin.h \
/Users/pancake/prg/radare2/libr/include/r_muta.h \
/Users/pancake/prg/radare2/libr/include/r_hash.h \
/Users/pancake/prg/radare2/libr/include/r_muta/r_sm4.h \
/Users/pancake/prg/radare2/libr/include/r_bin_dwarf.h \
/Users/pancake/prg/radare2/libr/include/r_reg.h \
/Users/pancake/prg/radare2/libr/include/r_anal/op.h \
/Users/pancake/prg/radare2/libr/include/r_anal/hint.h \
/Users/pancake/prg/radare2/libr/include/r_esil.h \
/Users/pancake/prg/radare2/libr/include/sdb/ht_uu.h \
/Users/pancake/prg/radare2/libr/include/r_anal.h \
/Users/pancake/prg/radare2/libr/include/r_util/r_print.h \
/Users/pancake/prg/radare2/libr/include/r_search.h \
/Users/pancake/prg/radare2/libr/include/r_syscall.h \
/Users/pancake/prg/radare2/libr/include/r_flag.h \
/Users/pancake/prg/radare2/libr/include/r_codemeta.h \
/Users/pancake/prg/radare2/libr/include/sdb/set.h \
/Users/pancake/prg/radare2/libr/include/r_lang.h \
/Users/pancake/prg/radare2/libr/include/r_cmd.h \
/Users/pancake/prg/radare2/libr/include/r_sign.h \
/Users/pancake/prg/radare2/libr/include/r_debug.h \
/Users/pancake/prg/radare2/libr/include/r_bp.h \
/Users/pancake/prg/radare2/libr/include/rvc.h \
/Users/pancake/prg/radare2/libr/include/r_core_priv.h \
/Users/pancake/prg/radare2/libr/include/r_core_task.h
+1
View File
@@ -0,0 +1 @@
include p/decai/r2plugin/core/deps.mk
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env python3
"""Convert a script file into a C buffer named decai_qjs (same output as `rax2 -C` + sed)."""
import sys
data = open(sys.argv[1], "rb").read()
with open(sys.argv[2], "w") as f:
f.write("const unsigned char decai_qjs[] = {\n")
for i in range(0, len(data), 16):
f.write(" %s,\n" % ", ".join("0x%02x" % b for b in data[i:i + 16]))
f.write("};\nconst unsigned int decai_qjs_len = %d;\n" % len(data))
+16
View File
@@ -0,0 +1,16 @@
# decai XPS integration for radare2.
# Included from libr/xps/meson.build when decai lives under libr/xps/p/decai/.
# Unlike native plugins, decai ships no native code: decai.r2.js is embedded
# as a buffer in libr_core and the tiny core plugin registers it with
# r_core_script_embed() so r2 runs it at startup like any plugins/*.r2.js file.
core_plugins += ['decai']
decai_py3 = import('python').find_installation()
r_core_additional_sources += files('core/plugin.c')
r_core_additional_sources += custom_target('decai_r2_js_c',
input: '../decai.r2.js',
output: 'decai.r2.js.c',
command: [decai_py3, files('js2c.py'), '@INPUT@', '@OUTPUT@'],
)
+1
View File
@@ -0,0 +1 @@
core.decai
+19
View File
@@ -0,0 +1,19 @@
PLUGIN_NAME=decai
R2F_C_FLAGS=-c -S
R2FRIDA_COMPILE?=r2pm -r r2frida-compile
all: build
build:
$(R2FRIDA_COMPILE) $(R2F_C_FLAGS) -o ../$(PLUGIN_NAME).r2.js main.ts
test: build
r2 -i ../$(PLUGIN_NAME).r2.js -q -c 'af;decai -d' /bin/ls
fmt:
deno fmt
clean:
rm -rf out node_modules ../$(PLUGIN_NAME).r2.js
.PHONY: all build test clean
+53
View File
@@ -0,0 +1,53 @@
import { API_KEYS_PATH, DECAI_CONFIG_DIR } from "./constants";
import { providerRegistry } from "./providers";
import { ApiKeyResult } from "./types";
import { ensurePath, fileExists, parseEnvLikeString } from "./utils";
function getProviderEnvMap(): Record<string, string> {
return Object.fromEntries(
Object.entries(providerRegistry)
.filter(([, v]) => v.authKey)
.map(([k, v]) => [k, v.authKey!]),
);
}
export function getApiKey(provider: string, envvar: string): ApiKeyResult {
const keyEnv = r2.cmd("'%" + envvar).trim();
if (!keyEnv.includes("=") && keyEnv !== "") {
return [keyEnv.trim(), null, "env"];
}
const providerLower = provider.toLowerCase();
const keysPath = API_KEYS_PATH;
if (fileExists(keysPath)) {
const keyFile = r2.cmd("'cat " + keysPath);
const kv = parseEnvLikeString(keyFile);
if (providerLower in kv) {
return [kv[providerLower], null, "txt"];
}
}
const keyPath = "~/.r2ai." + providerLower + "-key";
if (fileExists(keyPath)) {
const keyFile = r2.cmd("'cat " + keyPath);
return keyFile === ""
? [null, "Cannot read " + keyPath, "no"]
: [keyFile.trim(), null, "file"];
}
return [null, "Not available", "nope"];
}
export function editApiKeys(): void {
ensurePath(DECAI_CONFIG_DIR, API_KEYS_PATH);
r2.cmd("'ed " + API_KEYS_PATH);
}
export function listApiKeys(): void {
Object.entries(getProviderEnvMap()).forEach(([key, env]) => {
const status = getApiKey(key, env)[2];
console.log(status, "\t", key);
});
}
+568
View File
@@ -0,0 +1,568 @@
import { AutoReply } from "./types";
import { state } from "./state";
import { COMMAND, DEFAULT_PROMPT, HELP_TEXT, VERSION } from "./constants";
import {
b64,
filterResponse,
trimAnsi,
trimDown,
trimJson,
} from "./utils";
import { editApiKeys, listApiKeys } from "./apiKeys";
import { editRcConfig, evalConfig, listAllConfig } from "./config";
import { r2ai } from "./r2ai";
function withColorDisabled<T>(fn: () => T): T {
const origColor = r2.cmd("e scr.color");
r2.cmd("e scr.color=0");
try {
return fn();
} finally {
r2.cmd("e scr.color=" + origColor);
}
}
export function showHelp(): void {
let helpmsg = "";
const msg = (m: string) => (helpmsg += " " + COMMAND + " " + m + "\n");
helpmsg += "Usage: " + COMMAND + " (-h) ...\n";
helpmsg += "Version: " + VERSION + "\n";
msg("-a [query] - solve query with auto mode");
msg("-b [url] - set base URL (alias for decai -e baseurl)");
msg("-d [f1 ..] - decompile given functions");
msg("-dd [..] - same as above, but ignoring cache");
msg("-dD [query] - decompile current function with given extra query");
msg("-dr - decompile function and its called ones (recursive)");
msg("-e - display and change eval config vars");
msg("-E - edit and run decai.txt");
msg("-h - show this help");
msg("-H - help setting up r2ai");
msg("-i [f] [q] - include given file and query");
msg("-k - list API key status");
msg("-K - edit apikeys.txt");
msg("-m [model] - use -m? or -e model=? to list the available models");
msg("-n - suggest better function name");
msg("-p [provider] - same as decai -e api (will be provider)");
msg("-q [text] - query language model with given text");
msg("-Q [text] - query on top of the last output");
msg("-r [prompt] - change role prompt (same as: decai -e prompt)");
msg("-R - reset role prompt to default prompt");
msg("-s - function signature");
msg("-v - show local variables");
msg("-V - find vulnerabilities");
msg("-x[*] - eXplain current function (-x* for r2 script)");
r2.log(helpmsg.trim());
}
export function decompile(
args: string,
extraQuery: boolean,
useCache: boolean,
recursiveCalls: boolean,
): string | undefined {
if (useCache) {
const cachedAnnotation = r2.cmd("anos").trim();
if (cachedAnnotation.length > 0) {
return cachedAnnotation;
}
}
let context = "";
if (recursiveCalls) {
const at = r2.cmd("s");
context += "## Context functions:\n";
const funcs = r2.cmdAt("axff~^C[2]~$$", at);
for (const addr of funcs.split(/\n/g)) {
context += r2.cmd("pdc@" + addr);
}
r2.cmd("s " + at);
}
const appendQuery = extraQuery ? " " + args : "";
try {
const parsedArgs = args.slice(2).trim();
let text = "";
if (
state.contextFile !== "" &&
r2.cmd2("test -f " + state.contextFile).value === 0
) {
text += "## Context:\n[START]\n" +
r2.cmd("cat " + state.contextFile) +
"\n[END]\n";
}
const { body, count } = withColorDisabled(() => {
let body = "## Before:\n";
let count = 0;
for (const c of state.commands.split(",")) {
if (c.trim() === "") continue;
const oneliner = extraQuery || parsedArgs.trim().length === 0
? c
: c + "@@= " + parsedArgs;
const output = r2.cmd(oneliner);
if (output.length > 5) {
body += "Output of " + c + ":\n[START]\n" + output + "\n[END]\n";
count++;
}
}
body += "## After:\n";
return { body, count };
});
if (count === 0) {
console.error("Nothing to do.");
return;
}
let out = "";
if (state.decopipe.use) {
const origModel = state.model;
try {
const dpipe = state.decopipe[state.decopipe.default as string] as {
pipeline: Array<{ model?: string; query: string }>;
globalQuery: string;
};
let code = text + body;
for (const dp of dpipe.pipeline) {
if (dp.model) state.model = dp.model;
const query = dp.query + ". " + dpipe.globalQuery;
out = r2ai(query, code, true);
if (state.debug) {
console.log("QUERY\n", query, "\nINPUT\n", code, "\nOUTPUT\n", out);
}
code = out;
}
out = code;
} finally {
state.model = origModel;
}
} else {
const query = appendQuery;
text += body + context;
out = r2ai(query, text, false);
state.lastOutput = out;
}
if (useCache && out.length > 1) {
r2.call("ano=base64:" + b64(out));
}
if (out.startsWith("```")) {
out = out.replace(/```.*\n/, "").replace(/```$/, "");
}
return out.trim();
} catch (e) {
const err = e as Error;
console.error(err, err.stack);
return;
}
}
export function explainFunction(): string {
const hints = withColorDisabled(() =>
"[START]" +
state.commands.split(",").map((c) => r2.cmd(c)).join("\n") + "[END]"
);
const res = r2ai(
"Analyze function calls, references, comments and strings, loops and ignore registers and memory accesses. Explain the purpose of this function in a single short sentence. /no_think Do not introduce or argue the response, translation of the explanation in " +
state.humanLanguage,
hints,
true,
);
const lines = res.trim().split(/\n/g);
return lines[lines.length - 1].trim();
}
export function suggestSignature(): string {
const tmp = state.language;
const code = r2.cmd("afv;pdc");
state.language = "C";
let out = "'afs " +
r2ai(
"analyze the uses of the arguments and return value to infer the signature, identify which is the correct type for the return. Do NOT print the function body, ONLY output the function signature, like if it was going to be used in a C header",
code,
false,
);
const brace = out.indexOf("{");
if (brace !== -1) {
out = out.substring(0, brace);
}
state.language = tmp;
return out;
}
export function autoMode(
queryText: string,
mainHandler: (args: string) => boolean,
): void {
const replies: string[] = [];
while (true) {
let q = HELP_TEXT.auto;
if (replies.length > 0) {
q += "## Command Results\n\n";
for (const rep of replies) {
const rp = JSON.parse(rep);
q += "### " + rp.command + "\n\n```\n" + rp.response + "\n```\n";
}
}
q += "\n\n## User Prompt\n\n" + queryText;
if (state.debug) {
console.log("#### input\n", q, "\n#### /input");
}
console.log("Thinking...");
const out = r2ai("", q, true);
if (state.debug) {
console.log("#### output\n", out, "\n#### /output");
}
try {
const o: AutoReply = JSON.parse(
trimJson(trimDown(filterResponse(out))),
);
if (
o.action === "r2cmd" ||
o.action === "response" ||
o.action === o.command
) {
const ocmd = o.command || "";
if (o.reason) {
console.log("[r2cmd] Reasoning: " + o.reason);
if (state.tts) {
r2.syscmd("pkill say");
r2.syscmd(
"say -v Alex -r 250 '" + o.reason.replace(/'/g, "") + "' &",
);
}
}
console.log("[r2cmd] Action: " + o.description);
console.log("[r2cmd] Command: " + ocmd);
let cmd = ocmd;
if (!state.yolo) {
cmd = autoRepl(ocmd, mainHandler);
}
console.log("[r2cmd] Running: " + cmd);
const obj = r2.cmd2(cmd);
const logs = obj.logs
? obj.logs.map((x: { type: string; message: string }) =>
x.type + ": " + x.message
).join("\n")
: "";
const res = (obj.res + logs).trim();
console.log(res);
const cleanRes = trimAnsi(res);
if (state.debug) {
console.log("<r2output>\n", cleanRes, "\n<(r2output>");
}
replies.push(
JSON.stringify({
action: "response",
command: cmd,
description: o.description,
response: cleanRes,
}),
);
} else if (o.action === "reply") {
console.log("Done\n", o.response);
break;
} else {
console.log("Unknown response\n", JSON.stringify(out));
break;
}
} catch (e) {
const response = out.indexOf('response": "');
if (response !== -1) {
const res = out
.slice(response + 12)
.replace(/\\n/g, "\n")
.replace(/\\/g, "");
console.log(res);
} else {
console.log(out);
console.error(e);
}
break;
}
}
}
function autoRepl(
ocmd: string,
mainHandler: (args: string) => boolean,
): string {
while (true) {
const cmd = r2.cmd("'?ie Tweak command? ('?' for help)").trim();
if (cmd === "q!") {
console.error("Break!");
break;
}
if (cmd === "?") {
autoHelp();
continue;
} else if (cmd.startsWith(":")) {
console.log(r2.cmd(cmd.slice(1)));
continue;
} else if (cmd.startsWith("-e")) {
mainHandler(cmd);
continue;
} else if (cmd === "!") {
return "?e do NOT execute '" + ocmd + "' again, continue without it";
} else if (cmd.startsWith("!")) {
console.log(r2.syscmd(cmd.slice(1)));
continue;
} else if (cmd === "q") {
return "?e All data collected!. Do not call more commands, reply the solutions";
} else if (!cmd) {
return ocmd;
} else {
const comment = cmd.indexOf("#");
if (comment !== -1) {
const command = cmd.slice(0, comment).trim();
return command;
}
return cmd;
}
}
return ocmd;
}
function autoHelp(): void {
console.log(" '!' do not run this command");
console.log(" '!c' run system command");
console.log(" 'q' to quit auto and try to solve");
console.log(" 'q!' quit auto without solving");
console.log(" 'c # C' use given command with comment");
console.log(" ':c' run r2 command without feeding auto");
console.log(" '-e' set decai configuration variables");
}
function getFlagValue(args: string): string {
return args.slice(2).trim();
}
function currentFunctionExists(): boolean {
return r2.cmd("afi.").trim().length > 0;
}
const noFunctionMessage = "Cannot find function at current offset";
export function handleCommand(
args: string,
mainHandler: (args: string) => boolean,
): string | undefined {
if (args === "" || !args.startsWith("-")) {
showHelp();
return;
}
let output = "";
const flag = args[1];
const argValue = getFlagValue(args);
switch (flag) {
case "H":
console.log(HELP_TEXT.decai);
break;
case "a":
autoMode(argValue, mainHandler);
break;
case "m": {
if (argValue === "=") {
evalConfig("model=");
} else if (argValue) {
evalConfig("model=" + argValue);
} else {
evalConfig("model");
}
break;
}
case "n":
case "f": {
if (!currentFunctionExists()) {
output = noFunctionMessage;
break;
}
output = r2.cmd("axff~$[3]");
const considerations = r2
.cmd("fd.")
.trim()
.split(/\n/)
.filter((x: string) => !x.startsWith("secti"))
.join(",");
output = r2ai(
"give me a better name for this function. the output must be: 'afn NEWNAME'. do not include the function code, only the afn line. consider: " +
considerations,
output,
false,
).trim();
output += " @ " + r2.cmd("?v $FB").trim();
break;
}
case "v": {
if (!currentFunctionExists()) {
output = noFunctionMessage;
break;
}
output = r2.cmd("afv;pdc");
output = r2ai(
"guess a better name and type for each local variable and function argument taking using. output an r2 script using afvn and afvt commands",
output,
false,
);
break;
}
case "i": {
const parts = argValue.split(/\s+/).filter(Boolean);
if (parts.length >= 2) {
const file = parts[0];
const query = parts.slice(1).join(" ");
const fileData = r2.cmd("cat " + file);
console.log(r2ai(query, fileData, true));
} else {
console.log("Use: decai -i [file] [query ...]");
}
break;
}
case "p": {
if (argValue) {
evalConfig("api=" + argValue);
} else {
listApiKeys();
}
break;
}
case "r": {
if (argValue) {
state.prompt = argValue;
} else {
console.log(state.prompt);
}
break;
}
case "R":
state.prompt = DEFAULT_PROMPT;
break;
case "s":
if (!currentFunctionExists()) {
output = noFunctionMessage;
break;
}
output = suggestSignature();
break;
case "V":
output = r2ai(
"find vulnerabilities, dont show the code, only show the response, provide a sample exploit",
state.lastOutput,
false,
);
break;
case "K":
editApiKeys();
break;
case "E":
editRcConfig();
break;
case "k":
listApiKeys();
break;
case "b": {
if (argValue) {
evalConfig("baseurl=" + argValue);
} else {
console.log(state.baseurl);
}
break;
}
case "e": {
if (argValue) {
evalConfig(argValue);
} else {
listAllConfig();
}
break;
}
case "q":
try {
output = r2ai(argValue, null, true);
} catch (e) {
const err = e as Error;
console.error(err, err.stack);
}
break;
case "Q":
output = r2ai(argValue, state.lastOutput, false);
break;
case "x":
if (!currentFunctionExists()) {
output = noFunctionMessage;
break;
}
output = explainFunction();
if (args[2] === "*" || args[2] === "r") {
output = "'CC " + output;
}
break;
case "d":
if (args[2] === "r") {
output = decompile(args.slice(2), true, state.cache, true) || "";
} else if (args[2] === "d") {
output = decompile(args, false, false, false) || "";
} else if (args[2] === "D") {
output = decompile(args, true, false, false) || "";
} else {
output = decompile(args, false, state.cache, false) || "";
}
break;
default:
showHelp();
break;
}
return output || undefined;
}
+199
View File
@@ -0,0 +1,199 @@
import { ConfigHandler, ConfigHandlers } from "./types";
import { DECAI_CONFIG_DIR, DECAI_CONFIG_PATH } from "./constants";
import { defaultState, state } from "./state";
import { listModelsFor } from "./models";
import { listProviders } from "./providers";
import { formatHeaders, parseHeaders } from "./headers";
import { ensurePath, fileExists } from "./utils";
let rcConfigLoaded = false;
function parseBoolean(value: string): boolean {
return value === "true" || value === "1";
}
type StateKey = keyof typeof state;
function boolHandler(key: StateKey): ConfigHandler {
// deno-lint-ignore no-explicit-any
const s = state as any;
return {
get: () => s[key] as boolean,
set: (v: string) => { s[key] = parseBoolean(v); },
};
}
function stringHandler(key: StateKey): ConfigHandler {
// deno-lint-ignore no-explicit-any
const s = state as any;
return {
get: () => s[key] as string,
set: (v: string) => { s[key] = v; },
};
}
function normalizeApiType(value: string): "chat" | "generate" | null {
const apiType = value.trim();
if (apiType === "chat") {
return "chat";
}
if (apiType === "generate") {
return "generate";
}
return null;
}
export const configHandlers: ConfigHandlers = {
pipeline: {
get: () => state.pipeline,
set: (v: string) => {
state.pipeline = v;
try {
state.decopipe = JSON.parse(r2.cmd("cat " + v));
} catch (e) {
console.error(e);
}
},
},
model: {
get: () => state.model,
set: (v: string) => {
if (v === "?") {
listModelsFor(state.api);
} else {
state.model = v.trim();
}
},
},
deterministic: boolHandler("deterministic"),
files: boolHandler("useFiles"),
think: {
get: () => state.think || "false",
set: (v: string) => { state.think = v; },
},
apitype: {
get: () => state.apitype,
set: (v: string) => {
const apiType = normalizeApiType(v);
if (apiType) {
state.apitype = apiType;
} else {
console.error("Invalid apitype. Use chat or generate.");
}
},
},
debug: boolHandler("debug"),
http: {
get: () => state.http,
set: (v: string) => {
const backend = v.trim();
if (backend === "auto" || backend === "r2" || backend === "curl") {
state.http = backend;
} else {
console.error("Invalid http backend. Use auto, r2 or curl.");
}
},
},
timeout: {
get: () => state.timeout,
set: (v: string) => { state.timeout = Math.max(0, parseInt(v, 10) || 0); },
},
api: {
get: () => state.api,
set: (v: string) => {
if (v === "?") {
console.error(listProviders().join("\n"));
} else {
state.api = v;
}
},
},
lang: stringHandler("language"),
hlang: stringHandler("humanLanguage"),
cache: boolHandler("cache"),
cmds: stringHandler("commands"),
tts: boolHandler("tts"),
yolo: boolHandler("yolo"),
prompt: stringHandler("prompt"),
ctxfile: stringHandler("contextFile"),
baseurl: stringHandler("baseurl"),
headers: {
get: () => formatHeaders(state.extraHeaders),
set: (v: string) => { state.extraHeaders = parseHeaders(v); },
},
maxtokens: {
get: () => state.maxInputTokens,
set: (v: string) => { state.maxInputTokens = parseInt(v, 10) || -1; },
},
};
function resetRcConfigState(): void {
const keep = { host: state.host, port: state.port, lastOutput: state.lastOutput };
Object.assign(state, defaultState, keep);
state.decopipe = { ...defaultState.decopipe };
state.extraHeaders = [...defaultState.extraHeaders];
}
function normalizeRcLine(line: string): string | null {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) {
return null;
}
return trimmed.startsWith("decai -e ")
? trimmed.slice("decai -e ".length).trim()
: trimmed;
}
export function evalConfig(arg: string): void {
const eqIndex = arg.indexOf("=");
const k = eqIndex === -1 ? arg : arg.slice(0, eqIndex);
const v = eqIndex === -1 ? undefined : arg.slice(eqIndex + 1);
const handler = configHandlers[k];
if (!handler) {
console.error("Unknown config key");
return;
}
if (typeof v !== "undefined") {
handler.set(v);
} else {
console.log(handler.get());
}
}
export function listAllConfig(): void {
Object.entries(configHandlers).forEach(([key, handler]) => {
const value = handler.get();
console.log("decai -e " + key + "=" + value);
});
}
export function loadRcConfig(): void {
resetRcConfigState();
if (!fileExists(DECAI_CONFIG_PATH)) {
return;
}
const rcFile = r2.call("cat " + DECAI_CONFIG_PATH);
for (const line of rcFile.split(/\r?\n/)) {
const rcLine = normalizeRcLine(line);
if (rcLine && rcLine[0] != '#') {
evalConfig(rcLine);
}
}
}
export function ensureRcConfigLoaded(): void {
if (rcConfigLoaded) {
return;
}
loadRcConfig();
rcConfigLoaded = true;
}
export function editRcConfig(): void {
ensurePath(DECAI_CONFIG_DIR, DECAI_CONFIG_PATH);
r2.cmd("'ed " + DECAI_CONFIG_PATH);
loadRcConfig();
rcConfigLoaded = true;
}
+130
View File
@@ -0,0 +1,130 @@
export const VERSION = "1.5.4";
export const COMMAND = "decai";
export const DECAI_CONFIG_DIR = "~/.config/r2ai";
export const API_KEYS_PATH = DECAI_CONFIG_DIR + "/apikeys.txt";
export const DECAI_CONFIG_PATH = DECAI_CONFIG_DIR + "/decai.txt";
export const DEFAULT_PROMPT =
"Rewrite this pseudocode into concise and clean code. Output only the provided function. Do not add wrappers, helper examples, test code, or main-like functions. Replace goto with structured control flow, simplify as much as possible, infer types and use better names for variables and parameters, some strings may be appearing as comments, preserve only what is implied by the input, and remove dead code.";
export const HELP_TEXT = {
decai: `# Using Decai
Decai is the radare2 plugin for decompiling functions with the help of language models.
By default uses a local ollama server, but can you can pick any other service by using 'decai -e api=?'.
[0x00000000]> decai -e api=?
r2ai deepseek anthropic claude gemini groq hf lmstudio mistral ollama ollamacloud openapi openai openrouter vllm xai zen
## Using Ollama
* Visit https://ollama.com to install it.
* Download the model of choice: 'ollama run llama3.3'
* Configure decai to use the given model with: 'decai -e model=?'
These are the most recommended models for decompiling in local:
* hhao/qwen2.5-coder-tools:latest (18GB of ram)
* hhao/qwen2.5-coder-tools:32b (24GB of ram required)
## Common Options
* 'decai -e baseurl=<url>' override default host and port for API endpoint (e.g., 'http://localhost:11434')
* 'decai -e apitype=chat|generate' choose the Ollama API endpoint (default: chat)
* 'decai -e headers=Authorization: Bearer ...\\nUser-Agent: curl/8.7.1' add or override HTTP headers
* "export DECAI_HEADERS='Authorization: Bearer ...\\nUser-Agent: curl/8.7.1'" set extra headers from the environment
* 'decai -e http=auto|r2|curl' select the HTTP transport (default: auto, prefers r2.http)
* 'decai -e timeout=0' disable curl timeouts, or set a positive number of seconds
* 'decai -e deterministic=true' to remove randomness from decompilation responses
* 'decai -e lang=Python' to output the decompilation in Python instead of C
* 'decai -e hlang=Catalan' to add comments or explanations in that language (instead of English)
* 'decai -e cmds=pdd,pdg' use r2dec and r2ghidra instead of r2's pdc as input for decompiling
* 'decai -e prompt=..' default prompt must be fine for most models and binaries, feel free to tweak it
## API Keys
Remove services like OpenAI, Mistral, Anthropic, Grok, Gemini, .. require API keys to work.
See 'decai -k' to list the status of available APIkeys
Use 'decai -K' to edit apikeys.txt and 'decai -E' to edit decai.txt.
Decai will pick them from the environment or the config files in your home:
* echo KEY > ~/.r2ai.openai-key
* export OPENAI_API_KEY=...
* put one 'key=value' pair per line in ~/.config/r2ai/decai.txt
## Using the R2AI Server:
Install r2ai or r2ai-server with r2pm:
[0x0000000]> decai -e api=r2ai
[0x0000000]> r2pm -ci r2ai
Choose one of the recommended models (after r2pm -r r2ai):
* -m ibm-granite/granite-20b-code-instruct-8k-GGUF
* -m QuantFactory/granite-8b-code-instruct-4k-GGUF
* -m TheBloke/Mistral-7B-Instruct-v0.2-GGUF
Start the webserver:
$ r2pm -r r2ai-server -l r2ai -m granite-8...
`,
auto: `# Radare2 Auto Mode
Use function calling to execute radare2 commands in order to resolve the user request defined in the "User Prompt" section, analyze the responses attached in the "Command Results" section.
## Function Calling
Respond ONLY using plain JSON. Process user query and decide which function calls are necessary to solve the task.
1. Analyze the user request to determine if we need to run commands to extend the knowledge and context of the problem.
2. If function call is needed, construct the JSON like this:
- Fill the "action" key with the "r2cmd" value.
- Specify the "command" as a string.
- Optionally, provide a "reason" and "description"
3. If the answer can be provided and no more function calls are required:
- Use the key "action": "reply".
- Include "response" with the direct answer to the user query.
Return the result as a JSON object.
### Sample Function Calling Communication
Command Results: already performed actions with their responses
User Prompt: "Count how many functions we have here."
Response:
{
"action": "r2cmd",
"command": "aflc",
"description": "Count functions"
"reason": "Evaluate if the program is analyzed before running aaa"
}
## Rules
Use radare2 to resolve user requests.
* Explain each step in the "reason" field of the JSON.
* Follow the initial analysis instructions.
* Output only valid JSON as specified.
* Decompile and inspect functions, starting from main.
* Run only the needed commands to gather info.
* Use "@ (address|symbol)" to seek temporarily.
* Output should be a verbose markdown report.
* Use "sym." or "fcn." prefixes if "pdc" is empty.
* If a seek fails, use "f~name" to find the symbol's address.
### Initial Analysis
1. Run "aflc" to count the number of functions
2. If the output of "aflc" is "0" run "aaa" once, then "aflc" again
3. Run only one command at a time (do not use ";")
### Special cases
* On Swift binaries run...
`,
};
+91
View File
@@ -0,0 +1,91 @@
import { state } from "./state";
const HEADER_ENV_VARS = ["DECAI_HEADERS", "R2AI_HEADERS"];
interface ParsedHeader {
name: string;
value: string;
}
function readEnvVar(name: string): string {
const value = r2.cmd("'%" + name).trim();
return value !== "" && !value.includes("=") ? value : "";
}
function normalizeHeaderName(name: string): string {
return name.trim().toLowerCase();
}
function parseHeaderLine(line: string): ParsedHeader | null {
const colon = line.indexOf(":");
const equals = line.indexOf("=");
const sep = colon !== -1 && (equals === -1 || colon < equals)
? colon
: equals;
if (sep === -1) {
return null;
}
const name = line.slice(0, sep).trim();
if (name === "") {
return null;
}
return {
name,
value: line.slice(sep + 1).trim(),
};
}
function formatHeader(header: ParsedHeader): string {
return header.value === ""
? `${header.name}:`
: `${header.name}: ${header.value}`;
}
function collectHeaders(
headerLines: string[],
into: Map<string, string>,
): void {
for (const rawLine of headerLines) {
const header = parseHeaderLine(rawLine.trim());
if (header) {
into.set(normalizeHeaderName(header.name), formatHeader(header));
}
}
}
export function parseHeaders(value: string): string[] {
const headers = new Map<string, string>();
const lines = value.replace(/\\n/g, "\n").split(/\r?\n/g)
.filter((l) => { const t = l.trim(); return t && !t.startsWith("#"); });
collectHeaders(lines, headers);
return Array.from(headers.values());
}
export function formatHeaders(headers: string[]): string {
return headers.join("\\n");
}
export function mergeHeaders(...groups: string[][]): string[] {
const merged = new Map<string, string>();
for (const group of groups) {
collectHeaders(group, merged);
}
return Array.from(merged.values());
}
function readConfiguredEnvHeaders(): string[] {
for (const name of HEADER_ENV_VARS) {
const value = readEnvVar(name);
if (value) {
return parseHeaders(value);
}
}
return [];
}
export function getConfiguredHeaders(): string[] {
return mergeHeaders(readConfiguredEnvHeaders(), state.extraHeaders);
}
+108
View File
@@ -0,0 +1,108 @@
import { HttpResponse } from "./types";
import { state } from "./state";
import { mergeHeaders } from "./headers";
import { debugLog } from "./utils";
interface HttpRequestOptions {
method: "GET" | "POST";
url: string;
headers: string[];
payload?: string;
}
function shellEscape(arg: string): string {
return `'${arg.replace(/'/g, `'"'"'`)}'`;
}
function executeRequest(options: HttpRequestOptions): string {
const { method, url, headers, payload } = options;
const requestHeaders = mergeHeaders(
["Content-Type: application/json"],
headers,
);
if (state.http !== "curl") {
if (r2.http) {
return r2.http(method, url, requestHeaders.join("\n"), payload ?? "").body;
}
if (state.http === "r2") {
throw new Error("r2.http is not available in this runtime");
}
}
const cmdParts = ["curl", "-s"];
if (state.timeout > 0) {
cmdParts.push("--max-time", String(state.timeout));
}
requestHeaders.forEach((h) => cmdParts.push("-H", shellEscape(h)));
if (method === "POST") {
if (!payload) throw new Error("Payload required for POST requests");
const tmpfile = r2.fdump(payload);
cmdParts.push("--data-binary", "@" + shellEscape(tmpfile), shellEscape(url));
const cmd = cmdParts.join(" ") + "; rm " + shellEscape(tmpfile);
debugLog(cmd);
return r2.syscmds(cmd);
} else {
cmdParts.push(shellEscape(url));
const cmd = cmdParts.join(" ");
debugLog(cmd);
return r2.syscmds(cmd);
}
}
function parseNdjson(output: string): HttpResponse | null {
const lines = output.split("\n").filter((l) => l.trim() !== "");
if (lines.length <= 1) return null;
let content = "";
let lastObj: Record<string, unknown> | null = null;
for (const line of lines) {
try {
const obj = JSON.parse(line);
if (obj.error) return obj as HttpResponse;
if (obj.message?.content !== undefined) {
content += obj.message.content;
}
lastObj = obj;
} catch {
return null;
}
}
if (lastObj) {
lastObj.message = { role: "assistant", content };
return lastObj as HttpResponse;
}
return null;
}
export function httpRequest(options: HttpRequestOptions): HttpResponse {
try {
const output = executeRequest(options).trim();
if (output === "") {
return { error: "empty response" };
}
try {
return JSON.parse(output) as HttpResponse;
} catch {
const ndjson = parseNdjson(output);
if (ndjson) return ndjson;
return { error: output, rawOutput: output };
}
} catch (e) {
const err = e as Error;
return { error: err.message };
}
}
export function httpGet(url: string, headers: string[]): HttpResponse {
return httpRequest({ method: "GET", url, headers });
}
export function httpPost(
url: string,
headers: string[],
payload: string,
): HttpResponse {
return httpRequest({ method: "POST", url, headers, payload });
}
+10
View File
@@ -0,0 +1,10 @@
### 3. HTTP Request Patterns
**Location**: `http.ts`, used throughout providers and models
**Problems**:
- Two different curl methods (`curlArgs` vs `curlFile`) with similar but
separate logic
- Error handling in HTTP layer vs. application layer
- No centralized request/response abstraction
+34
View File
@@ -0,0 +1,34 @@
import { COMMAND } from "./constants";
import { handleCommand } from "./commands";
import { ensureRcConfigLoaded } from "./config";
function main(args: string): boolean {
ensureRcConfigLoaded();
const output = handleCommand(args, main);
if (output) {
r2.log(output);
}
return true;
}
function installPlugin(): void {
r2.unload("core", COMMAND);
r2.plugin("core", function () {
function coreCall(cmd: string): boolean {
if (cmd.startsWith(COMMAND)) {
const args = cmd.slice(COMMAND.length).trim();
return main(args);
}
return false;
}
return {
name: COMMAND,
license: "MIT",
desc: "r2 decompiler based on r2ai",
call: coreCall,
};
});
}
installPlugin();
+34
View File
@@ -0,0 +1,34 @@
import { getProvider, listModels } from "./providers";
export function listModelsFor(api: string): void {
const providerConfig = getProvider(api);
if (!providerConfig) {
console.error(`Unknown provider: ${api}`);
return;
}
try {
const models = listModels(api);
if (models) {
console.log(models);
}
if (providerConfig.hardcodedModels) {
providerConfig.hardcodedModels.forEach((model) => console.log(model));
}
if (api === "mistral") {
console.log("ministral-8b-latest");
}
if (!models && !providerConfig.hardcodedModels) {
console.log(providerConfig.defaultModel);
}
} catch (e) {
const err = e as Error;
console.error(`Error listing models for ${api}:`, err.message);
console.log(providerConfig.defaultModel);
}
}
+541
View File
@@ -0,0 +1,541 @@
import {
AnthropicPayload,
ApiKeyResult,
ApiStyle,
AuthStyle,
GeminiPayload,
HttpResponse,
ModelDataEntry,
OllamaModelEntry,
OllamaPayload,
ProviderConfig,
ProviderRegistry,
} from "./types";
import { state } from "./state";
import { filterResponse, joinUrl, padRight } from "./utils";
import { getApiKey } from "./apiKeys";
import { getConfiguredHeaders, mergeHeaders } from "./headers";
import { httpGet, httpPost } from "./http";
interface ProviderRuntime {
buildPayload: (model: string, query: string) => object;
parseResponse: (response: HttpResponse) => string;
buildUrl: (baseUrl: string, model: string, apiKey?: string) => string;
requiresUrlApiKey?: boolean;
}
function getApiKeyName(authKey: string): string {
return authKey.split("_")[0].toLowerCase();
}
function readProviderKey(provider: ProviderConfig): ApiKeyResult | undefined {
if (!provider.authKey) {
return undefined;
}
const keyNames = Array.from(
new Set(
[provider.keyName, getApiKeyName(provider.authKey)].filter(Boolean),
),
) as string[];
let fallback: ApiKeyResult | undefined;
for (const keyName of keyNames) {
const result = getApiKey(keyName, provider.authKey);
if (result[0]) {
return result;
}
if (!fallback && result[2] !== "nope") {
fallback = result;
}
}
return fallback ||
getApiKey(getApiKeyName(provider.authKey), provider.authKey);
}
function getErrorMessage(error: HttpResponse["error"]): string | undefined {
if (!error) {
return undefined;
}
if (typeof error === "string") {
return error;
}
return error.message || JSON.stringify(error);
}
function getProviderBaseUrl(provider: ProviderConfig): string {
return state.baseurl || provider.defaultBaseUrl;
}
function getProviderHeaders(
providerHeaders: string[],
extraHeaders: string[] = getConfiguredHeaders(),
): string[] {
return mergeHeaders(providerHeaders, extraHeaders);
}
function buildBearerHeaders(apiKey: string | null): string[] {
return apiKey ? ["Authorization: Bearer " + apiKey] : [];
}
function buildAnthropicHeaders(apiKey: string | null): string[] {
const headers = ["anthropic-version: 2023-06-01"];
return apiKey ? mergeHeaders(headers, ["x-api-key: " + apiKey]) : headers;
}
function buildAuthHeaders(
provider: ProviderConfig,
apiKey: string | null,
): string[] {
const authStyle: AuthStyle = provider.authStyle || "none";
switch (authStyle) {
case "bearer":
return buildBearerHeaders(apiKey);
case "anthropic":
return buildAnthropicHeaders(apiKey);
case "none":
default:
return [];
}
}
function listDataModels(
url: string,
headers: string[],
mapper: (model: ModelDataEntry) => string,
): string {
const response = httpGet(url, headers);
const error = getErrorMessage(response.error);
if (error) {
console.error(error);
return "error invalid response";
}
return response.data?.map(mapper).join("\n") || "";
}
function uniqueBy<T>(items: T[], getKey: (item: T) => string): T[] {
const seen = new Set<string>();
return items.filter((item) => {
const key = getKey(item);
if (seen.has(key)) {
return false;
}
seen.add(key);
return true;
});
}
function getProviderRequest(provider: ProviderConfig): {
baseUrl: string;
headers: string[];
} {
const apiKey = readProviderKey(provider)?.[0] || null;
return {
baseUrl: getProviderBaseUrl(provider),
headers: getProviderHeaders(buildAuthHeaders(provider, apiKey)),
};
}
function listV1Models(provider: ProviderConfig): string {
const { baseUrl, headers } = getProviderRequest(provider);
const url = joinUrl(baseUrl, "v1/models");
return listDataModels(url, headers, (model) => model.id);
}
function listOllamaModels(provider: ProviderConfig): string {
const { baseUrl, headers } = getProviderRequest(provider);
const response = httpGet(joinUrl(baseUrl, "api/tags"), headers);
const error = getErrorMessage(response.error);
if (error) {
console.error(error);
return "error invalid response";
}
return response.models?.map((model: OllamaModelEntry) => model.name).join(
"\n",
) || "";
}
function listMistralModels(provider: ProviderConfig): string {
const { baseUrl, headers } = getProviderRequest(provider);
const response = httpGet(joinUrl(baseUrl, "v1/models"), headers);
if (response.data) {
return uniqueBy(response.data, (model) => model.name || model.id)
.map((model) =>
[
padRight(model.name || model.id, 30),
padRight("" + (model.max_context_length || ""), 10),
model.description || "",
].join(" ")
)
.join("\n");
}
return "";
}
const providerRuntimes: Record<ApiStyle, ProviderRuntime> = {
openai: {
buildPayload: (model, query) => ({
stream: false,
model,
messages: [{ role: "user", content: query }],
}),
parseResponse: (response) => {
if (response.error) {
throw new Error(getErrorMessage(response.error) || "Unknown error");
}
if (response.choices && response.choices[0]?.message?.content) {
return filterResponse(response.choices[0].message.content);
}
throw new Error("Invalid response format");
},
buildUrl: (baseUrl) => joinUrl(baseUrl, "v1/chat/completions"),
},
anthropic: {
buildPayload: (model, query) => {
const payload: AnthropicPayload = {
model,
max_tokens: 5128,
messages: [{ role: "user", content: query }],
};
if (isThinkEnabled()) {
payload.thinking = { type: "enabled", budget_tokens: 4096 };
payload.max_tokens = 16000;
}
if (state.deterministic && !isThinkEnabled()) {
Object.assign(payload, { temperature: 0, top_p: 0, top_k: 1 });
}
return payload;
},
parseResponse: (response) => {
if (response.content && Array.isArray(response.content)) {
const parts: string[] = [];
for (const block of response.content as Array<Record<string, unknown>>) {
if (block.text) {
parts.push(block.text as string);
}
}
if (parts.length > 0) {
return filterResponse(parts.join("\n"));
}
}
if (response.error) {
throw new Error(getErrorMessage(response.error) || "Unknown error");
}
throw new Error("Invalid response format");
},
buildUrl: (baseUrl) => joinUrl(baseUrl, "v1/messages"),
},
ollama: {
buildPayload: (model, query) => {
const payload: OllamaPayload = {
stream: false,
model,
};
if (state.apitype === "generate") {
payload.prompt = query;
} else {
payload.messages = [{ role: "user", content: query }];
}
if (isThinkEnabled()) {
if (state.think === "true" || state.think === "1") {
payload.think = true;
} else {
// Pass reasoning levels like "low", "medium", "high" as-is
payload.think = state.think;
}
} else {
// Disable thinking by default — models like glm-5 enable it
// implicitly, generating thousands of reasoning tokens
payload.think = false;
}
if (state.deterministic) {
payload.options = {
repeat_last_n: 0,
top_p: 1.0,
top_k: 1.0,
temperature: 0.0,
repeat_penalty: 1.0,
seed: 123,
};
}
return payload;
},
parseResponse: (response) => {
if (response.error) {
throw new Error(getErrorMessage(response.error));
}
if (typeof response.response === "string") {
return filterResponse(response.response);
}
if (response.message?.content) {
return filterResponse(response.message.content);
}
throw new Error(JSON.stringify(response));
},
buildUrl: (baseUrl) => joinUrl(baseUrl, "api/" + state.apitype),
},
gemini: {
buildPayload: (_model, query) => {
const payload: GeminiPayload = {
contents: [{ parts: [{ text: query }] }],
};
const genConfig: Record<string, unknown> = {};
if (state.deterministic) {
Object.assign(genConfig, { temperature: 0.0, topP: 1.0, topK: 1 });
}
if (state.think !== "") {
if (isThinkDisabled()) {
genConfig.thinkingConfig = { thinkingBudget: 0 };
} else {
genConfig.thinkingConfig = { thinkingBudget: 8192 };
}
}
if (Object.keys(genConfig).length > 0) {
payload.generationConfig = genConfig;
}
return payload;
},
parseResponse: (response) => {
if (response.candidates && response.candidates[0]?.content?.parts) {
const parts = response.candidates[0].content.parts as Array<Record<string, unknown>>;
const textParts = parts
.filter((p) => !p.thought && p.text)
.map((p) => p.text as string);
if (textParts.length > 0) {
return filterResponse(textParts.join("\n"));
}
}
if (response.error) {
throw new Error(getErrorMessage(response.error));
}
console.log(JSON.stringify(response));
throw new Error("Invalid response format");
},
buildUrl: (baseUrl, model, apiKey) =>
joinUrl(
baseUrl,
`v1beta/models/${model}:generateContent?key=${apiKey}`,
),
requiresUrlApiKey: true,
},
};
export const providerRegistry: ProviderRegistry = {
anthropic: {
defaultModel: "claude-sonnet-5-5",
defaultBaseUrl: "https://api.anthropic.com",
authKey: "ANTHROPIC_API_KEY",
keyName: "anthropic",
authStyle: "anthropic",
apiStyle: "anthropic",
},
claude: {
defaultModel: "claude-sonnet-5-5",
defaultBaseUrl: "https://api.anthropic.com",
authKey: "ANTHROPIC_API_KEY",
keyName: "claude",
authStyle: "anthropic",
apiStyle: "anthropic",
},
openai: {
defaultModel: "gpt-4o-mini",
defaultBaseUrl: "https://api.openai.com",
authKey: "OPENAI_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
},
ollama: {
defaultModel: "qwen2.5-coder:latest",
defaultBaseUrl: "http://localhost:11434",
authStyle: "none",
apiStyle: "ollama",
},
ollamacloud: {
defaultModel: "gpt-oss:120b",
defaultBaseUrl: "https://ollama.com",
authKey: "OLLAMA_API_KEY",
keyName: "ollamacloud",
authStyle: "bearer",
apiStyle: "ollama",
},
zen: {
defaultModel: "big-pickle",
defaultBaseUrl: "https://opencode.ai/zen",
authKey: "OPENCODE_API_KEY",
keyName: "zen",
authStyle: "bearer",
apiStyle: "openai",
hardcodedModels: ["big-pickle", "glm-5", "kimi-k2.5"],
},
gemini: {
defaultModel: "gemini-2.5-flash",
defaultBaseUrl: "https://generativelanguage.googleapis.com",
authKey: "GEMINI_API_KEY",
authStyle: "none",
apiStyle: "gemini",
hardcodedModels: [
"gemini-2.0-flash",
"gemini-2.0-flash-lite",
"gemini-2.5-pro",
"gemini-2.5-flash",
"gemini-2.5-flash-lite",
],
},
mistral: {
defaultModel: "codestral-latest",
defaultBaseUrl: "https://api.mistral.ai",
authKey: "MISTRAL_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
},
xai: {
defaultModel: "grok-beta",
defaultBaseUrl: "https://api.x.ai",
authKey: "XAI_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
hardcodedModels: ["grok-2", "grok-beta"],
},
lmstudio: {
defaultModel: "local-model",
defaultBaseUrl: "http://127.0.0.1:1234",
authStyle: "none",
apiStyle: "openai",
},
deepseek: {
defaultModel: "deepseek-coder",
defaultBaseUrl: "https://api.deepseek.com",
authKey: "DEEPSEEK_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
hardcodedModels: ["deepseek-coder", "deepseek-chat"],
},
openrouter: {
defaultModel: "openai/gpt-4o-mini",
defaultBaseUrl: "https://openrouter.ai/api",
authKey: "OPENROUTER_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
},
groq: {
defaultModel: "llama-3.3-70b-versatile",
defaultBaseUrl: "https://api.groq.com/openai",
authKey: "GROQ_API_KEY",
authStyle: "bearer",
apiStyle: "openai",
},
};
export function getProvider(api: string): ProviderConfig | undefined {
return providerRegistry[api];
}
export function listProviders(): string[] {
return Object.keys(providerRegistry);
}
export function listModels(providerName: string): string {
const provider = getProvider(providerName);
if (!provider) {
throw new Error(`Unknown provider: ${providerName}`);
}
if (providerName === "mistral") {
return listMistralModels(provider);
}
switch (provider.apiStyle) {
case "openai":
case "anthropic":
return listV1Models(provider);
case "ollama":
return listOllamaModels(provider);
case "gemini":
return "";
default:
return "";
}
}
function isThinkDisabled(): boolean {
return state.think === "false" || state.think === "0";
}
function isThinkEnabled(): boolean {
return state.think !== "" && !isThinkDisabled();
}
function buildQuery(msg: string, hideprompt: boolean, apiStyle: ApiStyle): string {
let query = msg;
// Only add prompt-based thinking hints for APIs without native think support
if (state.think !== "" && apiStyle === "openai") {
if (isThinkDisabled()) {
query +=
' Answers directly and concisely, without showing any thinking steps or internal reasoning. Never include phrases like "Let me think".';
query += " /no_think";
} else {
query =
"Think step by step and explain the reasoning process, When answering, first output your reasoning inside <think> and </think> tags, then give the final answer." +
query;
}
}
return hideprompt ? query : state.prompt + languagePrompt() + query;
}
function languagePrompt(): string {
return "\n.Translate the code into " + state.language +
" programming language\n";
}
function callRuntime(
provider: ProviderConfig,
runtime: ProviderRuntime,
msg: string,
hideprompt: boolean,
): string {
const model = state.model || provider.defaultModel;
const query = buildQuery(msg, hideprompt, provider.apiStyle);
const apiKey = readProviderKey(provider);
if (runtime.requiresUrlApiKey && apiKey?.[1] && provider.authKey) {
return `Cannot read ~/.r2ai.${getApiKeyName(provider.authKey)}-key`;
}
const payload = runtime.buildPayload(model, query);
const authHeaders = buildAuthHeaders(provider, apiKey?.[0] || null);
if (provider.apiStyle === "ollama") {
authHeaders.push("Accept: application/x-ndjson");
}
const headers = getProviderHeaders(authHeaders);
const url = runtime.buildUrl(
getProviderBaseUrl(provider),
model,
apiKey?.[0] || undefined,
);
try {
return runtime.parseResponse(
httpPost(url, headers, JSON.stringify(payload)),
);
} catch (error) {
return "ERROR: " + (error as Error).message;
}
}
export function callProvider(msg: string, hideprompt: boolean): string {
const provider = getProvider(state.api);
if (!provider) {
return `Unknown value for 'decai -e api'. Available: ${
listProviders().join(", ")
}`;
}
return callRuntime(
provider,
providerRuntimes[provider.apiStyle],
msg,
hideprompt,
);
}
+41
View File
@@ -0,0 +1,41 @@
import { state } from "./state";
import { fileDump, joinUrl, tmpdir } from "./utils";
import { callProvider } from "./providers";
import { httpGet } from "./http";
export function r2ai(
queryText: string,
fileData: string | null,
hideprompt: boolean = false,
): string {
const cleanFileData = (fileData || "").replace(/`/g, "");
const cleanQuery = queryText.replace(/'/g, "");
// Handle r2ai server mode
if (state.api === "r2" || state.api === "r2ai") {
const fileName = tmpdir(".pdc.txt");
fileDump(fileName, cleanFileData);
const q = cleanQuery.startsWith("-")
? cleanQuery
: ["-i", fileName, cleanQuery].join(" ");
const baseUrl = state.baseurl || state.host + ":" + state.port;
const url = joinUrl(baseUrl, "cmd/" + encodeURIComponent(q));
const response = httpGet(url, []);
if (response.error) {
return `Error: ${response.error}`;
}
return response.result || JSON.stringify(response) ||
"Cannot curl, use r2ai-server or r2ai -w";
}
if (cleanQuery.startsWith("-")) return "";
let q = cleanQuery + ":\n" + cleanFileData;
if (state.maxInputTokens > 0 && q.length > state.maxInputTokens) {
q = q.slice(0, state.maxInputTokens);
}
return callProvider(q, hideprompt);
}
+290
View File
@@ -0,0 +1,290 @@
export type R2Address = number | string | unknown;
export interface R2HttpResponse {
status: number;
body: string;
}
export type R2HttpRequest = (
method: "GET" | "POST",
url: string,
headers: string,
data?: string,
) => R2HttpResponse;
export interface R2LogEntry {
type: string;
message: string;
}
export interface R2CommandResult {
res?: string;
value?: number;
logs?: R2LogEntry[];
[key: string]: unknown;
}
export interface R2Plugin {
name: string;
license: string;
desc: string;
call: (command: string) => boolean;
}
export type R2PluginFactory = () => R2Plugin;
export class R2PipeAdapter {
r2p: R2Pipe;
http?: R2HttpRequest;
constructor(r2p: R2Pipe) {
this.r2p = r2p;
this.http = r2p.http?.bind(r2p);
}
/**
* Run a command in the associated instance of radare2 and return the output as a string
*
* @param {string} command to be executed inside radare2.
* @returns {string} The output of the command execution
*/
cmd(command: string): string {
return this.r2p.cmd(command);
}
cmd2(command: string): R2CommandResult {
const output = this.r2p.cmd(command);
return typeof output === "string" ? { res: output } : output;
}
cmdAt(
command: string,
address: R2Address,
): string {
return this.r2p.cmdAt(command, address);
}
cmdj(cmd: string): unknown {
return this.r2p.cmdj(cmd);
}
call(command: string): string {
return this.r2p.call(command);
}
callj(cmd: string): unknown {
return this.r2p.cmdj(cmd);
}
callAt(
command: string,
address: R2Address,
): string {
return this.r2p.cmdAt(command, address);
}
syscmd(command: string): string {
return this.r2p.syscmd(command);
}
syscmds(command: string): string {
return this.r2p.syscmds(command);
}
fdump(data: string): string {
return this.r2p.fdump(data);
}
log(msg: string): void {
return this.r2p.log(msg);
}
plugin(type: string, maker: R2PluginFactory): boolean {
return this.r2p.plugin(type, maker);
}
unload(type: string, name: string): boolean {
return this.r2p.unload(type, name);
}
}
export function newR2PipeSync(r2p: R2Pipe): R2PipeSync {
return new R2PipeAdapter(r2p) as R2PipeSync;
}
/**
* Generic interface to interact with radare2, abstracts the access to the associated
* instance of the tool, which could be native via rlang or remote via pipes or tcp/http.
*
* @typedef R2Pipe
*/
export interface R2Pipe {
/**
* Run a command in the associated instance of radare2 and return the output as a string
*
* @param {string} command to be executed inside radare2.
* @returns {string} The output of the command execution
*/
cmd(cmd: string): string;
/**
* Run a radare2 command in a different address. Same as `.cmd(x + '@ ' + a)`
*
* @param {string} command to be executed inside radare2.
* @param {number|string|NativePointer} command to be executed inside radare2.
* @returns {string} The output of the command execution
*/
cmd2(cmd: string): R2CommandResult;
cmdAt(cmd: string, address: R2Address): string;
/**
* Run a radare2 command expecting the output to be JSON
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the output of the command
*/
cmdj(cmd: string): unknown;
/**
* Call a radare2 command. This is similar to `R2Pipe.cmd`, but skips all the command parsing rules,
* which is safer and faster but you cannot use any special modifier like `@`, `~`, ...
*
* See R2Pipe.callAt() to call a command on a different address
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the output of the command
*/
call(cmd: string): string;
/**
* Call a radare2 command in a different address
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @param {NativePointer|string|number} where to seek to execute this command (previous offset is restored after executing it)
* @returns {string} the string containing the output of the command
*/
callAt(cmd: string, address: R2Address): string;
syscmd(cmd: string): string;
syscmds(cmd: string): string;
fdump(data: string): string;
http?: R2HttpRequest;
/**
* Same as cmdj but using .call which avoids command injection problems
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the command output
*/
callj(cmd: string): unknown;
/**
* Log a string to the associated console. This is used internally by `console.log` in some implementations.
*
* @param {string} text to be displayed
*/
log(msg: string): void;
/**
* Instantiate a new radare2 plugin with the given type and constructor method.
*
* @param {string} type of plugin ("core", "io", "arch", ...)
* @param {string} function that returns the plugin definition
* @returns {boolean} true if successful
*/
plugin(type: string, maker: R2PluginFactory): boolean;
/**
* Unload the plugin associated with a `type` and a `name`.
*
* @param {string} type of plugin ("core", "io", "arch", ...)
* @param {string} name of the plugin
* @returns {boolean} true if successful
*/
unload(type: string, name: string): boolean;
}
/**
* Generic interface to interact with radare2, abstracts the access to the associated
* instance of the tool, which could be native via rlang or remote via pipes or tcp/http.
*
* @typedef R2PipeSync
*/
export interface R2PipeSync {
/**
* Run a command in the associated instance of radare2
*
* @param {string} command to be executed inside radare2.
* @returns {string} The output of the command execution
*/
cmd(cmd: string): string;
/**
* Run a radare2 command in a different address. Same as `.cmd(x + '@ ' + a)`
*
* @param {string} command to be executed inside radare2.
* @param {number|string|NativePointer} command to be executed inside radare2.
* @returns {string} The output of the command execution
*/
cmd2(cmd: string): R2CommandResult;
cmdAt(cmd: string, address: R2Address): string;
/**
* Run a radare2 command expecting the output to be JSON
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the output of the command
*/
cmdj(cmd: string): unknown;
/**
* Call a radare2 command. This is similar to `R2Pipe.cmd`, but skips all the command parsing rules,
* which is safer and faster but you cannot use any special modifier like `@`, `~`, ...
*
* See R2Pipe.callAt() to call a command on a different address
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the output of the command
*/
call(cmd: string): string;
/**
* Call a radare2 command in a different address
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @param {NativePointer|string|number} where to seek to execute this command (previous offset is restored after executing it)
* @returns {string} the string containing the output of the command
*/
callAt(cmd: string, address: R2Address): string;
syscmd(cmd: string): string;
syscmds(cmd: string): string;
fdump(data: string): string;
http?: R2HttpRequest;
/**
* Same as cmdj but using .call which avoids command injection problems
*
* @param {string} command to be executed inside radare2. The given command should end with `j`
* @returns {object} the JSON decoded object from the command output
*/
callj(cmd: string): unknown;
/**
* Log a string to the associated console. This is used internally by `console.log` in some implementations.
*
* @param {string} text to be displayed
*/
log(msg: string): void;
/**
* Instantiate a new radare2 plugin with the given type and constructor method.
*
* @param {string} type of plugin ("core", "io", "arch", ...)
* @param {string} function that returns the plugin definition
* @returns {boolean} true if successful
*/
plugin(type: string, maker: R2PluginFactory): boolean;
/**
* Unload the plugin associated with a `type` and a `name`.
*
* @param {string} type of plugin ("core", "io", "arch", ...)
* @param {string} name of the plugin
* @returns {boolean} true if successful
*/
unload(type: string, name: string): boolean;
}
/**
* A global instance of R2Pipe associated with the current instance of radare2
*
* @type {R2PipeSync}
*/
export declare const r2: R2Pipe;
+36
View File
@@ -0,0 +1,36 @@
import { AppState } from "./types";
import { DEFAULT_PROMPT } from "./constants";
export const defaultState: AppState = {
decopipe: { use: false },
host: "http://localhost",
port: "11434",
baseurl: "",
extraHeaders: [],
api: "ollama",
pipeline: "",
commands: "pdc",
yolo: false,
tts: false,
language: "C",
humanLanguage: "English",
deterministic: true,
debug: false,
timeout: 180,
http: "auto",
think: "",
apitype: "chat",
useFiles: false,
contextFile: "",
model: "",
cache: false,
maxInputTokens: -1,
prompt: DEFAULT_PROMPT,
lastOutput: "",
};
export const state: AppState = {
...defaultState,
decopipe: { ...defaultState.decopipe },
extraHeaders: [...defaultState.extraHeaders],
};
+16
View File
@@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es2020",
"lib": ["esnext"],
"module": "commonjs",
"outDir": "out",
"sourceMap": true,
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
},
"include": [
"**/*.ts"
]
}
+169
View File
@@ -0,0 +1,169 @@
import type { R2PipeSync } from "./r2pipe";
interface ConsoleLike {
log: (...args: unknown[]) => void;
error: (...args: unknown[]) => void;
}
declare global {
const r2: R2PipeSync;
const console: ConsoleLike;
function btoa(str: string): string;
}
export type ApiStyle = "openai" | "anthropic" | "ollama" | "gemini";
export type AuthStyle = "none" | "bearer" | "anthropic";
export type OllamaApiType = "chat" | "generate";
export interface ProviderConfig {
defaultModel: string;
defaultBaseUrl: string;
authKey?: string;
authStyle?: AuthStyle;
keyName?: string;
apiStyle: ApiStyle;
hardcodedModels?: string[];
}
export interface ProviderRegistry {
[key: string]: ProviderConfig;
}
export interface DecoPipeConfig {
use: boolean;
default?: string;
[key: string]: unknown;
}
export interface AppState {
decopipe: DecoPipeConfig;
host: string;
port: string;
baseurl: string;
extraHeaders: string[];
api: string;
pipeline: string;
commands: string;
yolo: boolean;
tts: boolean;
language: string;
humanLanguage: string;
deterministic: boolean;
debug: boolean;
timeout: number;
http: "auto" | "r2" | "curl";
think: string;
apitype: OllamaApiType;
useFiles: boolean;
contextFile: string;
model: string;
cache: boolean;
maxInputTokens: number;
prompt: string;
lastOutput: string;
}
export interface ConfigHandler {
get: () => string | number | boolean;
set: (v: string) => void;
}
export interface ConfigHandlers {
[key: string]: ConfigHandler;
}
export type ApiKeyResult = [string | null, string | null, string];
export interface ApiError {
message?: string;
[key: string]: unknown;
}
export interface OpenAIChoice {
message?: {
content?: string;
};
}
export interface AnthropicContentBlock {
text?: string;
}
export interface OllamaMessage {
content?: string;
}
export interface GeminiPart {
text?: string;
}
export interface GeminiCandidate {
content?: {
parts?: GeminiPart[];
};
}
export interface ModelDataEntry {
id: string;
name?: string;
max_context_length?: number;
description?: string;
}
export interface OllamaModelEntry {
name: string;
}
export interface HttpResponse {
error?: ApiError | string;
rawOutput?: string;
choices?: OpenAIChoice[];
content?: AnthropicContentBlock[];
message?: OllamaMessage;
candidates?: GeminiCandidate[];
data?: ModelDataEntry[];
models?: OllamaModelEntry[];
result?: string;
[key: string]: unknown;
}
export type JsonObject = Record<string, unknown>;
export interface AnthropicPayload {
model: string;
max_tokens: number;
messages: Array<{ role: string; content: string }>;
thinking?: { type: string; budget_tokens?: number };
temperature?: number;
top_p?: number;
top_k?: number;
}
export interface OllamaPayload {
stream: boolean;
model: string;
messages?: Array<{ role: string; content: string }>;
prompt?: string;
think?: boolean | string;
options?: {
repeat_last_n: number;
top_p: number;
top_k: number;
temperature: number;
repeat_penalty: number;
seed: number;
};
}
export interface GeminiPayload {
contents: Array<{ parts: Array<{ text: string }> }>;
generationConfig?: Record<string, unknown>;
}
export interface AutoReply {
action: string;
command?: string;
description?: string;
reason?: string;
response?: string;
}
+97
View File
@@ -0,0 +1,97 @@
import { state } from "./state";
export function tmpdir(path: string): string {
const dir = r2.cmd("-e dir.tmp").trim() ?? ".";
return dir + "/" + path;
}
// r2's mkdir and touch commands do not expand '~'
export function expandHome(path: string): string {
if (!path.startsWith("~/")) {
return path;
}
const home = r2.cmd("'%HOME").trim() || r2.cmd("'%USERPROFILE").trim();
return home ? home + path.slice(1) : path;
}
export function ensurePath(dir: string, file: string): void {
r2.cmd("'mkdir -p " + expandHome(dir));
r2.cmd("'touch " + expandHome(file));
}
export function fileExists(path: string): boolean {
const helpMessage = r2.cmd2("test -h").logs?.[0]?.message ?? "";
if (helpMessage.includes("-fdx")) {
return true; // r2 is old
}
return r2.cmd("'test -vf " + path).startsWith("found");
}
export function padRight(str: string, length: number): string {
return str + " ".repeat(Math.max(0, length - str.length));
}
export function joinUrl(baseUrl: string, path: string): string {
return baseUrl.replace(/\/+$/, "") + "/" + path.replace(/^\/+/, "");
}
export function trimAnsi(str: string): string {
return str.replace(/\x1b\[[0-9;]*m/g, "");
}
export function trimDown(out: string): string {
const jsonMatch = out.match(/```json\s*([\s\S]*?)```/);
return jsonMatch && jsonMatch[1] ? jsonMatch[1].trim() : out;
}
export function trimJson(out: string): string {
let result = out;
const openBrace = result.indexOf("{");
if (openBrace !== -1) result = result.slice(openBrace);
const closeBrace = result.lastIndexOf("}");
if (closeBrace !== -1) result = result.slice(0, closeBrace + 1);
return result;
}
export function b64(str: string): string {
return btoa(str);
}
export function fileDump(fileName: string, fileData: string): void {
const d = b64(fileData);
r2.cmd("p6ds " + d + " > " + fileName);
}
export function filterResponse(msg: string): string {
let result = msg;
result = result.replace(/<think>[\s\S]*?<\/think>/gi, "");
return result
.split("\n")
.filter((line) => !line.trim().startsWith("```"))
.join("\n");
}
export function debugLog(msg: string): void {
if (state.debug) {
console.log(msg);
}
}
export function parseEnvLikeString(input: string): Record<string, string> {
const result: Record<string, string> = {};
for (const line of input.split(/\r?\n/)) {
const trimmed = line.trim();
if (!trimmed || trimmed.startsWith("#")) {
continue;
}
const [key, ...rest] = trimmed.split("=");
if (!key || rest.length === 0) {
continue;
}
const value = rest.join("=").trim();
// Normalize key: strip trailing _API_KEY (case-insensitive)
const normKey = key.toLowerCase().replace(/_api_key$/i, "");
result[normKey] = value;
}
return result;
}
+130
View File
@@ -0,0 +1,130 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="210mm"
height="297mm"
viewBox="0 0 210 297"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940, 2025-05-08)"
sodipodi:docname="decai.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="1.0482005"
inkscape:cx="318.64133"
inkscape:cy="426.92214"
inkscape:window-width="1512"
inkscape:window-height="960"
inkscape:window-x="222"
inkscape:window-y="44"
inkscape:window-maximized="0"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#000000;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
id="rect2"
width="186.28354"
height="176.18687"
x="1.5145004"
y="23.979588"
ry="0.047831953" />
<path
sodipodi:type="star"
style="fill:#1a1a1a;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
id="path1"
inkscape:flatsided="false"
sodipodi:sides="10"
sodipodi:cx="71.751205"
sodipodi:cy="102.09375"
sodipodi:r1="53.804771"
sodipodi:r2="49.845222"
sodipodi:arg1="0.65927727"
sodipodi:arg2="0.97343657"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 114.28039,135.05163 -14.49317,8.25532 -13.001341,10.44831 -16.577574,-1.84017 -16.659669,0.81086 -12.329911,-11.23279 -13.95457,-9.1363 -3.37264,-16.33486 -5.919299,-15.59371 6.872864,-15.197565 4.376943,-16.094859 14.493168,-8.255319 13.001341,-10.448311 16.577574,1.840177 16.659669,-0.810865 12.329915,11.232788 13.95457,9.136304 3.37264,16.334856 5.91929,15.593714 -6.87286,15.19757 z"
transform="matrix(1.2188073,0,0,1.2188073,1.600691,-15.424646)" />
<path
sodipodi:type="star"
style="fill:#37662e;fill-opacity:1;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
id="path1-5"
inkscape:flatsided="false"
sodipodi:sides="10"
sodipodi:cx="71.751205"
sodipodi:cy="102.09375"
sodipodi:r1="35.902484"
sodipodi:r2="49.845222"
sodipodi:arg1="0.32368816"
sodipodi:arg2="0.63784749"
inkscape:rounded="0"
inkscape:randomized="0"
d="m 105.78923,113.51309 6.0066,18.26187 -19.219401,-0.43572 -5.874621,18.30475 L 71.4091,137.9946 55.897164,149.35045 50.372443,130.93707 31.148226,131.00645 37.501747,112.86236 21.908246,101.61878 37.71318,90.674414 31.706582,72.412538 l 19.2194,0.435725 5.874621,-18.304757 15.292708,11.649389 15.511935,-11.355844 5.524722,18.413382 19.224212,-0.06938 -6.35352,18.144089 15.5935,11.243582 z"
transform="matrix(1.2188073,0,0,1.2188073,0.97362416,-14.941195)" />
<path
sodipodi:type="star"
style="fill:#800000;stroke:#000000;stroke-width:2;stroke-linecap:round;stroke-linejoin:round"
id="path2"
inkscape:flatsided="false"
sodipodi:sides="10"
sodipodi:cx="69.252403"
sodipodi:cy="183.84013"
sodipodi:r1="76.18972"
sodipodi:r2="39.770834"
sodipodi:arg1="0.94510027"
sodipodi:arg2="1.2659605"
inkscape:rounded="0.029345222"
inkscape:randomized="0"
d="m 113.8738,245.59614 c -0.96661,0.6886 -31.555039,-24.18254 -32.684714,-23.81876 -1.120974,0.36099 -10.958876,38.2632 -12.136488,38.25221 -1.186753,-0.0111 -11.314419,-38.11167 -12.442172,-38.48137 -1.119068,-0.36685 -31.356457,24.51411 -32.302709,23.81304 -0.953595,-0.70651 13.247923,-37.48344 12.552854,-38.44541 -0.689714,-0.95456 -39.7769375,1.40147 -40.1303916,0.27809 -0.3561976,-1.13209 32.7500076,-22.5378 32.7531166,-23.7246 0.0031,-1.17766 -33.0039804,-22.24649 -32.6296302,-23.36307 0.3772559,-1.12525 39.7427032,1.0165 40.4428022,0.0582 0.694707,-0.95093 -13.624624,-37.39704 -12.665459,-38.08034 0.966611,-0.68859 31.555037,24.18255 32.684712,23.81876 1.120974,-0.36098 10.958875,-38.26319 12.136488,-38.2522 1.186752,0.0111 11.314419,38.11167 12.442172,38.48137 1.119067,0.36685 31.356459,-24.51411 32.302709,-23.81304 0.95359,0.70651 -13.24792,37.48344 -12.55285,38.44541 0.68971,0.95456 39.77693,-1.40147 40.13039,-0.2781 0.35619,1.13209 -32.75001,22.53781 -32.75312,23.72461 -0.003,1.17766 33.00398,22.24649 32.62963,23.36307 -0.37726,1.12524 -39.7427,-1.01651 -40.4428,-0.0582 -0.69471,0.95093 13.62462,37.39704 12.66546,38.08033 z"
transform="translate(19.276442,-75.320913)" />
<path
sodipodi:type="star"
style="fill:#d45500;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
id="path2-0"
inkscape:flatsided="false"
sodipodi:sides="10"
sodipodi:cx="69.252403"
sodipodi:cy="183.84013"
sodipodi:r1="3.2911112"
sodipodi:r2="71.359137"
sodipodi:arg1="1.3521275"
sodipodi:arg2="1.5760036"
inkscape:rounded="0.029345222"
inkscape:randomized="0"
d="m 69.966345,187.05287 c -1.9053,0.60813 0.905346,68.33625 -1.085527,68.14543 -1.996473,-0.19135 0.964985,-67.70967 -0.939225,-68.33936 -1.898868,-0.62792 -39.434599,55.81734 -40.933089,54.49275 -1.502705,-1.3283 40.579437,-54.21107 39.409022,-55.83977 -1.167132,-1.62412 -64.7118681,21.9781 -65.1456023,20.0257 -0.43495449,-1.95789 64.6939243,-20.00568 64.7043623,-22.01128 0.01041,-1.99997 -65.27140303,-20.25603 -64.4747102,-22.09049 0.7989341,-1.83963 64.0975312,21.84119 65.2848352,20.22477 1.183973,-1.61189 -40.89948,-54.75304 -39.17667,-55.76887 1.727657,-1.01869 39.01806,55.34548 40.92872,54.73564 1.905301,-0.60812 -0.905346,-68.33625 1.085527,-68.14543 1.996474,0.19136 -0.964984,67.70968 0.939225,68.33937 1.898868,0.62792 39.434597,-55.81734 40.933087,-54.49276 1.50271,1.32831 -40.579435,54.21108 -39.409019,55.83977 1.167131,1.62413 64.711869,-21.97809 65.145599,-20.0257 0.43496,1.9579 -64.693921,20.00569 -64.704359,22.01129 -0.01041,1.99997 65.271399,20.25602 64.474709,22.09049 -0.79893,1.83963 -64.09753,-21.8412 -65.284834,-20.22477 -1.183973,1.61189 40.899484,54.75304 39.176674,55.76887 -1.72766,1.01869 -39.018064,-55.34548 -40.928725,-54.73565 z"
transform="translate(19.25264,-74.484719)" />
<path
sodipodi:type="star"
style="fill:#ffb380;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:1"
id="path2-0-7"
inkscape:flatsided="false"
sodipodi:sides="10"
sodipodi:cx="69.252403"
sodipodi:cy="183.84013"
sodipodi:r1="2.0329688"
sodipodi:r2="36.653175"
sodipodi:arg1="1.3051581"
sodipodi:arg2="1.5885803"
inkscape:rounded="0.029345222"
inkscape:randomized="0"
d="m 69.786109,185.8018 c -0.974051,0.29744 -0.168255,34.73512 -1.18551,34.68571 -1.01845,-0.0495 0.894533,-34.41437 -0.06946,-34.74665 -0.962858,-0.3319 -20.552916,28.00241 -21.346851,27.36451 -0.794867,-0.63865 20.951954,-27.31602 20.367382,-28.15147 -0.583886,-0.83446 -33.087061,10.57373 -33.354419,9.59099 -0.267673,-0.98389 33.006439,-9.78387 33.024571,-10.80336 0.01811,-1.01829 -32.983073,-10.89376 -32.621734,-11.84596 0.361764,-0.95332 32.453587,11.48538 33.067497,10.67125 0.61319,-0.81317 -20.280673,-28.2002 -19.428655,-28.75816 0.853019,-0.55861 19.504568,28.36761 20.479763,28.06981 0.974051,-0.29744 0.168255,-34.73512 1.18551,-34.68572 1.01845,0.0495 -0.894534,34.41438 0.06946,34.74666 0.962858,0.3319 20.552915,-28.00241 21.34685,-27.36451 0.794868,0.63865 -20.951953,27.31602 -20.367382,28.15146 0.583886,0.83446 33.087059,-10.57372 33.354419,-9.59099 0.26767,0.98389 -33.006439,9.78388 -33.024571,10.80337 -0.01811,1.01829 32.983071,10.89376 32.621731,11.84596 -0.36176,0.95332 -32.453584,-11.48538 -33.067494,-10.67125 -0.613189,0.81317 20.280674,28.2002 19.428655,28.75816 C 89.412852,214.43022 70.761304,185.504 69.786109,185.8018 Z"
transform="rotate(-17.984043,-157.18948,86.992365)" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 8.3 KiB

+28 -14
View File
@@ -4,24 +4,37 @@ This directory contains predefined prompt files for the r2ai plugin.
## Format
Each prompt is stored in a `.r2ai` file using a simple Key: Value format.
Each prompt is stored in a `.r2ai.md` file with YAML-style frontmatter and a markdown body.
Lines starting with `#` are comments and ignored.
Example:
```markdown
---
description: 'Explain the current function'
author: pancake
command: r2ai -d
if-empty: exit
---
Explain the purpose of this function in one or two short sentences.
```
Supported keys:
- `Title`: The title of the prompt (required)
- `Author`: The author of the prompt
- `Description`: A brief description
- `Command` or `Commands`: Commands to execute before sending the prompt, separated by `;` (required)
- `Prompt` or `Query`: The main prompt text sent to the LLM
- `Requires`: Requirements for the prompt (e.g., "analysis" to ensure binary analysis)
- `If-Empty`: Alternative prompt or message if the command output is empty
- `If-Command`: Additional commands to run if the main command produces output
- `title`: The title of the prompt
- `author`: The author of the prompt
- `description`: A brief description
- `command`: Commands to execute before sending the prompt, separated by `;` (required)
- `requires`: Requirements for the prompt (e.g., "analysis" to ensure binary analysis)
- `if-empty`: Alternative prompt or message if the command output is empty
- `if-command`: Additional commands to run if the main command produces output
- `model`: Model override for this prompt
- `provider`: Provider override for this prompt
Legacy `.r2ai.txt` files using `Title:`, `Command:`, `Prompt:` or `Query:` are still accepted.
## Variable Substitution
In the `Prompt` field, you can use:
In the markdown body, you can use:
- `${VAR}`: Replaced with the value of the environment variable `VAR`
- `$(cmd)`: Replaced with the output of the r2 command `cmd`
@@ -29,15 +42,16 @@ In the `Prompt` field, you can use:
## Usage
- `r2ai -q`: List all available prompts
- `r2ai -qj`: List all available prompts in JSON
- `r2ai -q name`: Run the prompt named `name`
- `r2ai -q name extra text`: Run the prompt with additional text appended
## Conditionals
- `If-Empty`: If the command output is empty, use this as the prompt instead
- `If-Command`: If the command produces output, run these additional commands and append their output
- `if-empty`: If the command output is empty, use this as the prompt instead
- `if-command`: If the command produces output, run these additional commands and append their output
## Future Features
- Support for r2js scripts
- More advanced conditionals
- More advanced conditionals
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Automatically suggest a better name for this function'
version: 0.1
author: pancake
command: afv;r2ai -d
if-empty: exit
---
Suggest a better name for this function. Output only the suggested function name (must be one alphanumeric word) prefixed with `'afn '. Check the code below:
-4
View File
@@ -1,4 +0,0 @@
Title: Automatically suggest a better name for this function
Author: pancake
Command: afv;r2ai -d
Prompt: Suggest a better name for this function. Output only the suggested function name (must be one alphanumeric word) prefixed with `'afn '. Check the code below:
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Compact conversation history into a summary'
version: 0.1
author: pancake
command: r2ai -C
if-empty: exit
---
Create a compact summary of this conversation that preserves all key information, insights, and context for future reference. Focus on essential details about the binary analysis, tools used, findings, and any important conclusions.
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Augmented decompilation based on LLM'
version: 0.1
author: pancake
command: pdc
if-empty: exit
---
$(-e r2ai.prompt). Translate the code into $(-e r2ai.lang) programming language.
-4
View File
@@ -1,4 +0,0 @@
Title: Augmented decompilation based on LLM
Author: pancake
Command: pdc
Prompt: $(-e r2ai.prompt). Translate the code into $(-e r2ai.lang) programming language.
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Find and explain devices used'
version: 0.1
author: pancake
command: izqq~^/dev
if-empty: exit
---
explain in one line the purpose of each of these devices
-4
View File
@@ -1,4 +0,0 @@
Title: Find and explain devices used
Author: pancake
Command: izqq~^/dev
Prompt: explain in one line the purpose of each of these devices
+8
View File
@@ -0,0 +1,8 @@
---
description: 'List libraries loaded with dlopen'
version: 0.1
author: pancake
command: iiq~dlopen
if-empty: This binary is not using dlopen
---
Some libraries are loaded
-6
View File
@@ -1,6 +0,0 @@
Title: List libraries loaded with dlopen
Description: Some libraries are loaded
Requires: analysis
Command: iiq~dlopen
If-Empty: This binary is not using dlopen
If-Command: e emu.str=true;pd--5@@c:axtq sym.imp.dlopen
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Explain the current function'
version: 0.1
author: pancake
command: r2ai -d
if-empty: exit
---
Analyze function calls, comments and strings, ignore registers and memory accesses. Considering the references and involved loops; explain the purpose of this function in one or two short sentences. Output must be only the translation of the explanation in $(-e r2ai.hlang)
-4
View File
@@ -1,4 +0,0 @@
Title: Explain the current function
Author: pancake
Command: r2ai -d
Prompt: Analyze function calls, comments and strings, ignore registers and memory accesses. Considering the references and involved loops; explain the purpose of this function in one or two short sentences. Output must be only the translation of the explanation in $(-e r2ai.hlang)
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Group imports by Libraries'
version: 0.1
author: pancake
command: iiq;il
if-empty: exit
---
Group the imports that belong to each library and describe its purpose and usage scope
-4
View File
@@ -1,4 +0,0 @@
Title: Group imports by Libraries
Author: pancake
Commands: iiq;il
Query: Group the imports that belong to each library and describe its purpose and usage scope
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Suggest an improved function signature'
version: 0.1
author: pancake
command: ?e variables;afv;?e function name:;afd;?e current signature:?e afs
if-empty: exit
---
Analyze the uses of the arguments and return value to infer the signature, identify which is the correct type for the resturn. Do NOT print the function body. Output must be *ONLY* the function signature prefixed with the `'afs ` text
-4
View File
@@ -1,4 +0,0 @@
Title: Suggest an improved function signature
Author: pancake
Command: ?e variables;afv;?e function name:;afd;?e current signature:?e afs
Prompt: Analyze the uses of the arguments and return value to infer the signature, identify which is the correct type for the resturn. Do NOT print the function body. Output must be *ONLY* the function signature prefixed with the `'afs ` text
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Better variable names'
version: 0.1
author: pancake
command: afv
if-empty: exit
---
Output only the radare2 command without markdown, guess a better name and type for each local variable and function argument taking using. output an r2 script using afvn and afvt commands
-4
View File
@@ -1,4 +0,0 @@
Title: Better variable names
Author: pancake
Command: afv
Prompt: Output only the radare2 command without markdown, guess a better name and type for each local variable and function argument taking using. output an r2 script using afvn and afvt commands
+8
View File
@@ -0,0 +1,8 @@
---
description: 'Find vulnerabilities or bugs in the current function'
version: 0.1
author: pancake
command: pdc
if-empty: exit
---
Find vulnerabilities, do not show the code, only a short summary of the resulting analysis report including suggested good practices to address the problem and a practical exploit example.
-4
View File
@@ -1,4 +0,0 @@
Title: Find vulnerabilities or bugs in the current function
Author: pancake
Command: pdc
Prompt: Find vulnerabilities, do not show the code, only a short summary of the resulting analysis report including suggested good practices to address the problem and a practical exploit example.
+40
View File
@@ -0,0 +1,40 @@
# r2plugin
This directory contains the make and meson files required to link r2ai
inside radare2 through the external plugin system (XPS).
```console
cd radare2
make -C libr/xps EXTERNAL_PLUGINS=r2ai
./configure-plugins
make
```
For meson builds, place this repository at `libr/xps/p/r2ai` and make
`libr/xps/p/meson.build` include:
```meson
subdir('r2ai/r2plugin')
```
## WASI HTTP build
Use a radare2 checkout with the host HTTP bridge and place this repository at
`libr/xps/p/r2ai`. From that radare2 checkout:
```sh
echo 'EXTERNAL_PLUGINS+=r2ai' >> libr/xps/config.mk
make -C libr/xps
WASI_HTTP=1 sys/wasi-api.sh
```
This links the C plugin into the reactor; it does not load a native shared
library at runtime. Enable HTTP in the host adapter. The `auto` backend selects
`r_socket_http_get/post`, preserving provider authentication headers and JSON
bodies, subject to the radare2 sandbox. `--disable-network` also denies these calls.
WASI excludes POSIX signal/alarm handling; the host controls request timeouts,
not `r2ai.http.timeout`. Normal queries and model listing use buffered HTTP.
Vertex's automatic `gcloud` authentication and background tasks requiring
threads are unavailable. Explicit shell backends (`system`/`curl`) cannot work;
use `auto` or `socket`. Browser CORS and restricted-header rules still apply.
Loaded 100 of 146 files, more files were not shown because too many files have changed in this diff. Show more