Commit Graph
73 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås 3f70d259d3 core: Persist pattern placements
Store them with the REPL cell and the address insight, as a JSON
column each, and bind the decode view to them. Older rows and wire
cells without the field decode as none.
2026-10-01 20:49:11 +02:00
Ole André Vadla Ravnås 0e933206fb Boot virtual machines from the target picker
Add a machine abstraction to LumaCore, with QEMU as its first
backend: templates mirroring frida-core's test guests, a QMP client,
and a display that maps QEMU's surface over D-Bus rather than
copying frames.

Leave readiness to the user: drive the guest, mark it ready, and come
back to that snapshot later. Keep the machine in the project, so
booting it again resumes where it was marked. Hand the stub to
addBareboneDevice, so it joins the picker beside the other devices.

Show the display while booting, and afterwards in a Machines panel,
which the side panel now models as an enum to share its slot.
2026-08-20 14:52:52 +02:00
Ole André Vadla Ravnås f8d25015ae Drop the comments that only restate the code
A comment is a last resort, and these were not one: section banners,
doc headers naming what the declaration below already names, and
notes saying in prose what the next line says in code.

What is left is what the code cannot show -- an ordering that matters,
a platform quirk, why the obvious way fails.
2026-08-13 13:09:18 +02:00
Ole André Vadla Ravnås 1e66b7a4f9 Say what a failed snippet did, and where
A compile error reads in words with a dot at the failing spot.
Evaluate splits from evaluate-and-inspect, the snippet spins while
it runs, and print it, format and browse sit on GT's keys.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås a9917a2b4c Browse and edit classes natively
Open any class in a browser folded into the inspector: its methods,
class-side ones too, a method saved from the editor, a sent method
opened in place, and a wrench offering fixes for an undeclared name.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås a248d02832 Keep evaluation results
Results survive a restart through Fuel, so a page opens where it
was left. Luma's own records stay portable so the image can revive
what it stored.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 6080bff60c Open Pharo values in panes beside the page
Each value opens in a pane on the gutter, beside the page rather
than under it. Panes drag, close and walk, a crowded tab strip
scrolls, and the split and its divider stay where they were put.
2026-08-13 12:46:08 +02:00
Ole André Vadla Ravnås 3aab17ca5a Run Pharo from the notebook and a playground
Boot the VM against a bundled image, evaluate from a notebook cell
or a playground snippet, and keep what each evaluation produced.
The image is staged on every build; the framework release is pinned.
2026-08-13 12:46:08 +02:00
necpition205 7411c3c9a4 Optimize mission context reads 2026-06-28 02:02:14 +02:00
Ole André Vadla Ravnås b2e1849901 Collapse the modules sidebar group by default
Match threads; both groups start collapsed. A stored expansion
state is still honored.
2026-06-27 23:55:55 +02:00
Ole André Vadla Ravnås 4e3038a576 Clear persisted cells on REPL Clear History
Delete the session's REPL cells from the store, otherwise the next
command reloads the old ones.
2026-06-27 19:00:36 +02:00
Ole André Vadla Ravnås 5ed87e6018 Make sidebar hooks collapsible like module groups
Give instruments that have hooks a disclosure chevron and persist
the per-instrument collapsed state in the session UI state. Toggle
the module and thread groups on a full header-row click. Pad the
module view so its tabs clear the top-left edge.
2026-06-27 15:30:30 +02:00
Ole André Vadla Ravnås 38e5198209 Move modules and threads into the sidebar
Drop the modules/threads tabs; show both as collapsible sidebar
groups mirroring the hooks UX: a handful of top picks plus a
browse popover for the rest. Default threads to collapsed.

Revert the eager re-analysis of persisted modules on attach; keep
disassembly analysis lazy and add a per-module Analyze action and
status indicator instead.

Share one sidebar-row and one browser-popover component across
hooks, modules, and threads in both the SwiftUI and GTK frontends.
2026-06-27 14:53:01 +02:00
Ole André Vadla Ravnås 92d3846f35 Add new columns to existing project databases
Create-table-if-not-exists never alters a table that already
exists, so a shipped database lacks the REPL, seek, and styled
notebook columns and fails on save. Add each one if missing.
2026-06-26 20:09:50 +02:00
Ole André Vadla Ravnås e0da0576cd Keep colors when pinning r2 results to notebook
Carry the styled text on NotebookEntry alongside the plain
details, capture it when pinning an r2 cell, and render it with
color in both notebook frontends.
2026-06-26 19:24:51 +02:00
Ole André Vadla Ravnås 7d38ac2f7f Persist the r2 REPL seek as an address anchor
Snapshot the r2 seek after each r2 eval, storing it on
SessionUIState as an AddressAnchor so it re-bases across runs.
Resolve and restore it during the session warm-up, which now
also runs when only a seek (no analysis) was saved.
2026-06-26 18:49:13 +02:00
Ole André Vadla Ravnås d759062291 Warm up persisted module analysis on attach
Replay every module that has a persisted analysis row into the
fresh r2 core once modules are enumerated, restoring last
session's warm state without blocking attach. Replays are cheap
re-basing; modules lacking persisted analysis stay lazy.
2026-06-26 17:49:55 +02:00
Ole André Vadla Ravnås 0285de051a Enrich r2 REPL completion and persist input state
Carry a display/insert split through completion so command
suggestions show r2's help text via the native secondary title,
and complete command arguments against eval vars and flagspaces
in addition to flags. Recall the language alongside the code when
cycling history, and keep r2 output's leading whitespace intact.

Persist the REPL draft and active language per session in
SessionUIState so they survive reopening the project. Defer the
input field's first-responder change out of the view update.
2026-06-26 17:46:01 +02:00
Ole André Vadla Ravnås b84bfa0a2b Add r2 as a first-class REPL language
Make the REPL prompt a clickable mode toggle between JavaScript
and r2; ":", ":r2" and ":js" switch from the keyboard. Carry the
language on REPLCell and REPLResult, route r2 input through the
session disassembler, and render output as a JSInspectValue tree
for JSON commands or ANSI-parsed styled text otherwise.
2026-06-26 16:45:21 +02:00
Ole André Vadla Ravnås 8d6f91fe1e Plumb image attachments through to the LLM
Console widgets get an appendImage / respond.image API on the
agent. read_widget_state surfaces image entries as attachments
scaled to at most max_dimension pixels (default 1568) on the
longest edge. Anthropic nests image blocks inside tool_result;
OpenAI gets a synthetic follow-up user message. The host scales
via CoreImage on macOS and GdkPixbuf on GTK.
2026-05-22 12:15:53 +02:00
Ole André Vadla Ravnås 2f7dea2dbe Surface global Action Queue in toolbar popover 2026-05-21 01:59:33 +02:00
Ole André Vadla Ravnås dcc6c029cb core: Use db.tableExists for empty-db check
Drops the raw sqlite_master query in favour of GRDB's wrapper.
2026-05-20 20:04:49 +02:00
Ole André Vadla Ravnås 211c8d25e2 Carry symbolicate names offline
Engine.symbolDisplay returns a richer SymbolDisplay (overlay,
source, raw, primary) and persists every live symbolicate
result into module_symbol (sessionID, modulePath, function-entry
offset → name). Offline rendering falls through to that table
first, then to enclosingFunction from the persisted block
ranges, then to module+offset. ProcessNode delegates trace
block annotation back through this path via
onResolveBlockNames so the same names show up on detached
traces.
2026-05-20 19:18:13 +02:00
Ole André Vadla Ravnås dc6af656fd Persist basic blocks per analyzed function
Split ModuleAnalysis persistence into module_analysis,
module_analysis_function and module_analysis_block tables.
Harvest blocks via afbj and use them to answer enclosingFunction
offline. R2Hex accepts both 0x-prefixed strings and raw integers,
since cfg.json.num=hex doesn't cover afbj. When the cache is
present but blocks are missing, replay anyway unless we're online
and can re-analyze.
2026-05-20 19:17:57 +02:00
Ole André Vadla Ravnås dd71943d94 Allow naming address insights
Replace the auto-derived title with userTitle (nil = auto)
and a parentInsightID link. Display name is userTitle, else
<parent.title>+0x<delta>, else sub_<offset> if at a function
start, else module+offset. Sidebar context menu Rename… and
an LLM rename_insight tool both go through Engine.renameInsight,
which broadcasts via the existing updateInsight op and pushes
the new name into r2 as a flag (plus afn at function starts).

getOrCreateInsight kicks off a background pass that links a
new insight to its enclosing function-start insight, and
adopts siblings inside its region when the new insight is
itself the function start. The same adoption runs when a
fresh ModuleAnalysis newly reveals a function start under an
existing insight.
2026-05-19 16:01:25 +02:00
Ole André Vadla Ravnås 12d5491c22 Sync disasm cache across collab
Identify a process instance by a deterministic identity returned
from the agent (per-OS, with a Process.mainModule + pid fallback)
and stash it on ProcessSession.processInfo. Rekey memory_page
into memory_page_module (module UUID + offset) so cached bytes
survive ASLR, and memory_page_anon (process identity + address)
for JIT / heap regions that only survive within one process
instance. Purge stale anon pages on every fresh attach.

Add updateProcessInfo, updateModuleAnalysis and updateInsight
SessionOps plus a side-channel publish-memory-page op and a
+fetch-memory-page request. The driver write-throughs every
page it fetches; non-drivers pull on miss and persist locally.
Module-analysis rows flow the same way so non-drivers can key
their cache by module UUID. The lab-join snapshot now carries
processInfo and module_analyses too.

Refresh actions on the insight detail view: Reread Bytes drops
the pages overlapping the visible range; Reanalyze Module drops
the module's analysis and pages, re-running r2 on next access.

The macOS detail view now reads the insight live from
insightsBySession via observation; GTK forwards .insightUpdated
into the detail and reschedules a refresh when the resolved
address changes.
2026-05-19 15:16:48 +02:00
Ole André Vadla Ravnås aa87467bbb Cache memory pages across detach
Decouple Disassembler from ProcessNode via MemoryReader and
ModuleIntrospector protocols, and add a per-session page store
that r2 reads flow through. The disassembler now survives
detach; insights render from cache, with live reads
re-populating it on reattach.
2026-05-19 09:53:50 +02:00
Ole André Vadla Ravnås 143df80073 Bound disasm at function end
Persist per-session module analysis (executable ranges + known
functions, keyed by module name + LC_UUID) so on-demand
analysis runs once per binary and rebases on reattach. The
agent gains enumerateModuleRanges and getModuleIdentity; the
store gains a module_analysis table.

Disassembler queries $FB/$FE for the request address; when it
hits a function start, fetch via pDJ bounded to the function's
byte range. Otherwise fall back to pdJ N. Filter pdJ
decoration entries (xrefs, fcn headers, var summaries) that
share the addr of an instruction.

DisassemblyPage carries a scope (.function/.span) so the
SwiftUI and GTK insight views can disable loadMore when the
page is function-bounded. The disassemble AI tool surfaces the
scope too, so the model knows whether it has the whole
function or just an N-instruction span.

Go-to-Function-Start now opens (or selects) the insight rooted
at the function start, which then renders via the bounded
path.
2026-05-19 09:53:41 +02:00
Ole André Vadla Ravnås e6c3d8946f core+gtk: Delete and edit individual note messages
Engine: deleteAddressNoteMessage drops the row from the store
and enqueues an address_note_message_remove op. Collab apply
mirrors the existing edit path. AddressNoteChange grows a
messageRemoved case.

GTK: right-click on a user message offers Edit and Delete.
Edit swaps the body label for an inline editor; Save commits
via editUserMessage. Delete confirms first, then removes the
row from the popover and via the engine.
2026-05-18 18:57:50 +02:00
Ole André Vadla Ravnås 5227f0d0ce core: Add AI reply for address notes
requestAIReply runs against an ambient mission per session,
billing token usage and recording the call as a MissionAction
so the user can review the chain in the mission view. System
prompt seeds the model with disasm + pdc around the anchor.
2026-05-18 00:29:07 +02:00
Ole André Vadla Ravnås 1c4177a83d core: Sync address notes via collaboration
AddressNoteOp covers note upsert/remove plus message append/edit.
Outbox table mirrors mission_outbox; inbound ops apply through
Engine and refresh the address-annotation gutter.
2026-05-18 00:25:58 +02:00
Ole André Vadla Ravnås 22fce67575 core: Add AddressNote model and persistence
Threads anchored to an address, each with a chain of messages
(user/assistant/system). Notes carry editors[], messages carry
a single immutable author. rebuildAddressAnnotations folds note
counts into the gutter so the UI can render breadcrumbs.
2026-05-18 00:25:58 +02:00
Ole André Vadla Ravnås e31d254cc1 core: Track author on REPLCell
Cells are immutable per submission, so a single author rather
than an editors[] chain. Server stamps on session_repl_cell add.
2026-05-18 00:25:58 +02:00
Ole André Vadla Ravnås a8f4988df2 core: Track editors on Mission
Mirrors NotebookEntry attribution. Server stamps editors[] on
each upsert; clients render the chain in the mission list.
2026-05-18 00:25:58 +02:00
Ole André Vadla Ravnås 7202a840c8 core: Persist last-known main module on session
Add last_known_main_module column to the session record and
populate it from the live node after attach.
2026-05-15 16:13:07 +02:00
Ole André Vadla Ravnås d1606523b5 Support multi-file custom instruments
- Store source files as named CustomInstrumentFile rows per def
- Render sidebar with disclosure groups
- Drive editor via Monaco project models with activePath
- Validate Add/Rename/Delete dialogs and submit on Enter
- Fork installed hook packs into editable custom instruments
- Reload instances on def change; clear stale compat reasons live
- Focus editor on selection (native + Monaco)
2026-05-13 08:54:48 +02:00
Ole André Vadla Ravnås 6b0c5865ec core: Refuse to open mismatched schema versions
Stamp PRAGMA user_version on fresh databases; on subsequent
opens, throw if the stored version does not match the current
constant. Pre-launch this means bumping the version when
schema changes and recreating dev projects, instead of
crashing inside GRDB on a missing column.
2026-05-12 15:05:31 +02:00
Ole André Vadla Ravnås e1f3ea938a core: Gate instruments on device compatibility
Each instrument carries an InstrumentCompatibility (platforms,
osIDs, archs; nil set means any). Hook pack manifests and custom
defs declare it; tracer and codeshare default to universal.

System parameters are queried lazily via SystemParametersCache,
keyed by device id and invalidated when devices disappear.

Restoring an incompatible instrument now marks it with a reason
on its InstrumentRef instead of attaching.
2026-05-12 15:05:23 +02:00
Ole André Vadla Ravnås c5d2ff7050 core: Replace Workspace with per-document Engine
EngineRegistry caches one Engine per working-project URL.
MainWindowView.init does a pure lookup, so SwiftUI's
view-tree re-evaluations cannot open extra ProjectStores
that race the live one's BEGIN IMMEDIATE and crash via
try!.

UI-state persistence (collapse flag, sidebar selection,
session detail section, etc.) lives on Engine for GTK to
adopt. SQLite has a 5s busy timeout. Engine open failures
surface as an error view.

TargetPicker is host @State injected via environment.
Global instrument-UI defaults register at app startup;
per-engine instrument and local-notifier hookups live in
Engine extensions.
2026-05-11 21:15:47 +02:00
Ole André Vadla Ravnås b1a8cf484c Rework New Mission dialog
Mission defaults (provider, model, budgets, thinking, effort)
and provider base URLs move from the project document to
LumaAppState. Opening a project on another machine no longer
drags in someone else's model choice or localhost URL.

The dialog loads models asynchronously, shows loading and
error states inside a stable "Model" row, debounces typed
API keys with a length floor, and persists the key on the
first successful fetch.

Base URL field surfaces only for providers that opt in via
capability (local). Reasoning effort dropdown surfaces for
Claude Code; the extended-thinking toggle is hidden when
the provider doesn't support it.
2026-05-11 14:39:18 +02:00
Ole André Vadla Ravnås 494de6495e Rework provider capabilities
Fetch models at runtime where supported (OpenAI, local
OpenAI-compatible). Static lists for Anthropic and Claude
Code; the OpenAI list was already drifting.

Add reasoningEffortOptions capability. Claude Code exposes
[auto, low, medium, high, xhigh, max] and routes the choice
to its --effort flag. LLMTurnRequest, Mission, the executor
and the mission schema all carry reasoningEffort end to end.

suggestedModels is now async/throws and takes apiKey and
baseURL so dynamic providers can authenticate and target a
caller-supplied endpoint.
2026-05-11 14:39:07 +02:00
Ole André Vadla Ravnås f4f987c7ee Add widget data model
InstrumentWidget (graph or list, with a persistence enum) lives
on CustomInstrumentDef and HookPackManifest. Runtime widget data
serializes through a widget_state table keyed by instance id and
widget id; the def itself round-trips a widgets_json column on
custom_instrument_def.
2026-05-10 21:02:42 +02:00
Ole André Vadla Ravnås fd18bc4d79 agent: Update mission rows by closure
Whole-row saves let any writer clobber fields it didn't
own. The executor saved its in-memory Mission whenever the
status moved, wiping the title or pending user text that a
parallel task had just written. Add a closure-based
ProjectStore.updateMission(id:) that fetches, mutates, and
saves inside one db.write transaction. The executor now
writes only status and token counters; the title pass
writes title; appendMissionUserMessage writes
pendingUserText; the drain reads-and-resets atomically.
2026-05-10 09:34:39 +02:00
Ole André Vadla Ravnås f005c84a08 agent: Label missions with an LLM-generated title
A new title column carries a short label generated in
parallel with mission start. Each LLMProviderDescriptor
declares a summarizationModelID so the pass runs on the
mission's own backend (Haiku for Anthropic and Claude
Code, gpt-5-mini for OpenAI, llama3.2:3b locally). The
instruction sits in the user message to dodge Claude
Code's prompt layering and asks for two to four punchy
words. Sidebar shows title or goal; header keeps the
full goal under the title.
2026-05-10 08:39:14 +02:00
Ole André Vadla Ravnås f9c760ff10 agent: List Claude Code subprocess provider first
Reorder the provider registry so Claude Code (subprocess)
shows up at the top of the New Mission picker, and update
the ProjectUIState defaults to match — fresh projects pick
"claude-code" + "default" instead of Anthropic Sonnet.
2026-05-09 22:48:07 +02:00
Ole André Vadla Ravnås b9094d4cf4 ui: Remember last new-mission settings
Provider, model, token budgets, and thinking config persist
on the project's UI state, so opening New Mission a second
time pre-fills the previous choices instead of resetting.
The API key continues to live in the credential store.
2026-05-09 21:37:17 +02:00
Ole André Vadla Ravnås adfc5e9ad8 agent: Let user steer running missions
A pending_user_text column on mission stores any text the
user types into the new MissionInputBar. The executor drains
it at the start of each iteration, folding it into the next
synthesized user turn. Send queues; Send Now interrupts the
current turn (when running) before resuming.
2026-05-09 21:35:17 +02:00
Ole André Vadla Ravnås ef0017255b mission: Drop targets, add discovery tools
The agent finds or creates its own sessions via list_devices,
list_processes, attach_to_process, and spawn_process.
2026-05-09 13:16:45 +02:00
Ole André Vadla Ravnås 5d0748515b mission: Add goal-driven agent loop
LLM agent for user-stated RE goals: propose-and-approve over the
existing RPC, evidence-grounded findings, collab via the op-outbox
pattern. Anthropic / OpenAI / local-OAI providers. r2ai used for
explain_function when the plugin is loaded; falls back to the
mission's own provider otherwise.
2026-05-09 12:54:14 +02:00
Ole André Vadla Ravnås 05380cd568 core: Add spawn gating
Engine drives device.enableSpawnGating() per armed-session intent;
matched spawns re-attach via the existing attach path and misses
resume immediately. Engagement intent is in-memory only so launches
don't auto-engage gating for sessions armed in a previous run.

ProcessSession gains armingState and lastArmPattern, mirrored in
the SQLite schema. RuntimeEvent.Source.spawnGating carries the
captured/released outcome with wire encoding.

Lab protocol adds update-arming as a SessionOp variant; armed-only
sessions announce themselves with pid 0 and phase detached so peers
can see them before any capture.

Engine.onUserNotification surfaces gating-enable failures using the
clean Frida.Error message.
2026-05-08 16:15:25 +02:00