Drop the Monaco webview. Edit in a GtkSourceView on GTK and in a
native text view on Apple, both speaking to Frida.Compiler's
in-process language server for completions, signature help,
hovers and diagnostics.
Color, complete and indent code natively, matching the GitHub
theme in light and dark.
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.
Sessions in a lab are now collaborative artifacts. Any owner can
host (own the local Frida attachment) and any owner can drive
(issue REPL evals and instrument commands); a driver's actions
are relayed to the current host. Members watch read-only and see
an "Only lab owners can host sessions" CTA when they try the new
session button.
Re-host (Run on My Device…) lets an owner take over a running
session by attaching to their own equivalent process; the prior
host's Frida attachment detaches and the new host auto-loads the
session's instruments. Driver auto-reverts to host when the
current driver fully disconnects from the lab.
Gate min-width frames behind isCompactWidth so the event stream,
target picker, codeshare browser, and collaboration panel collapse
cleanly on iPhone instead of forcing a scroll at their regular
widths. Give the event stream a dedicated compact header that
promotes the source / process filters to icon menus and keeps the
search, pause, and clear controls inline.
Drop the auto-select-first behavior in the target picker and
codeshare browser on compact, so tapping a sidebar row navigates
to the detail pane on NavigationSplitView's built-in stack instead
of stranding the user looking at a preselected item.
Push the instrument event-row monospaced font up into each
InstrumentUI factory and out of JSInspectValueView, so tracer,
hook-pack, and codeshare rows match without recomputing it for
every sub-value. Migrate the JS inspector disclosure label to
AttributedString to kill the deprecated Text + Text concatenation
warning. Tighten REPL result formatting and relabel the detach
banner hint.
Both frontends were configuring Monaco editors with parallel,
incompatible types: a hand-rolled MonacoEditorProfile in LumaGtk,
SwiftyMonaco's MonacoEditorProfile in the SwiftUI host. Each had
its own MonacoExtraLib, TypeScriptCompilerOptions, frida compiler
options constant, and tracer-handler ambient declarations. The
LumaCore.MonacoFSSnapshot type also collided with SwiftyMonaco's
same-named type, forcing a typealias workaround in the host.
LumaCore now owns the canonical editor model:
* EditorProfile, EditorCompilerOptions, EditorExtraLib, plus
EditorScriptTarget / EditorModuleKind / EditorModuleResolutionKind
enums whose raw values match Monaco's TypeScript enums.
* EditorProfile.fridaCompilerOptions and .fridaGumLib for the
Frida-recommended TS config and the bundled gum typings.
* EditorProfile.fridaTracerHook(packages:) and .fridaCodeShare()
factory methods that build the right profile in one call.
* TracerTypings.handlerLib for the defineHandler ambient
declarations (previously duplicated verbatim in both frontends).
MonacoFSSnapshot is renamed to EditorFSSnapshot, eliminating the
name collision with SwiftyMonaco entirely.
LumaGtk's MonacoEditor.swift drops its duplicate types and uses
LumaCore.EditorProfile directly. The JS literal generation moves
to fileprivate extensions on the canonical types.
The SwiftUI host gains one new file — Editor/SwiftyMonacoBridge.swift
— containing init(from:) extensions on SwiftyMonaco's MonacoExtraLib,
TypeScriptCompilerOptions, MonacoFSSnapshot, and MonacoEditorProfile.
This is the only place that knows about both type families. All
the per-frontend editor-profile files (TracerEditorProfile,
CodeShareEditorProfile, TypeScriptEnvironment), Workspace+Packages,
and the MonacoFSSnapshotAlias hack are deleted.
Engine and ProcessNode are @Observable. Workspace
observes engine.processNodes via withObservationTracking
to sync VMs reactively. Views call workspace.engine.*
directly for spawn, attach, resume, instrument lifecycle,
insights, and tracer hooks. Engine instrument methods
take InstrumentInstance directly instead of split params.
InstrumentDescriptor (LumaCore) holds the data: kind,
identifier, display name, icon, initial config, and
event summary. Engine maintains a descriptor registry.
InstrumentUI protocol (Luma) defines the SwiftUI view
factories. TracerUI, HookPackUI, and CodeShareUI
implement it. InstrumentUIRegistry maps descriptor
IDs to UI instances.
Workspace no longer constructs templates. Views look
up descriptors via engine and UI via the registry.
Update every view and Workspace extension to use LumaCore
types and ProjectStore instead of SwiftData:
- SidebarView: fetch instruments/insights/captures from store
- DetailView: resolve sessions via store
- REPLView: load cells from store by sessionID
- NotebookView: use LumaCore.NotebookEntry value types
- Workspace+Packages: delegate to CompilerWorkspace, use
ESMBundleParser.parse(), persist via store
- Workspace+Collaboration: fetch/save collaboration state
and notebook entries through store
- All remaining views qualified with LumaCore types
The Luma app should now compile without SwiftData.
Rename ProcessNode → ProcessNodeViewModel across all views
and update RuntimeEvent to wrap the LumaCore event type.
Views access core business logic through .core (evalInREPL,
symbolicate, resolve, anchor, readRemoteMemory, modules).
The ViewModel exposes Frida types directly (device, session,
script) and handles SwiftData persistence by subscribing to
the core's async event streams.
Split UI-coupled types into portable data (LumaCore) and
platform-specific editor profiles (Luma):
- TracerConfig: data struct + template stubs to LumaCore,
TracerEditorProfile stays with SwiftyMonaco in Luma
- CodeShareConfig + CodeShareProjectRef to LumaCore,
CodeShareEditorProfile stays in Luma
- CodeShareService: drop ObservableObject, move as
stateless enum with async methods to LumaCore
- HookPack: data struct to LumaCore, discovery stays
Add swift-crypto dependency for cross-platform SHA256.
Add FoundationNetworking import for Linux URLSession.
Move pure data types out of Luma/ into Sources/LumaCore/
so they can be shared with the GTK frontend:
- AddressAnchor, CFGGraph, ITraceDecoder (+ all related
types: TraceEntry, ITraceMetadata, RegisterState, etc.)
- JSInspectValue, SpawnConfig, ProcessModule
- HookPackConfig, HookPackManifest, InstrumentConfigCodec
- InstrumentIcon, InstrumentKind, ConsoleLevel
CFGGraph uses its own Point2D instead of CoreGraphics
types, keeping the core free of Apple frameworks.
Remove premature stubs (Engine, ProcessNode,
InstrumentRuntime, EventStream) that will be properly
built in a later phase once the real implementations
are ready to move.
- Provide a trimmed node_modules filesystem snapshot to Monaco
- Inject global alias typings for installed packages
- Run tracer scripts through Frida.Compiler
Allow instruments to provide lightweight visual decorations for
addresses, independent of any specific view or instrument.
The tracer instrument uses this mechanism to mark disassembly
addresses that already have instruction hooks, providing a subtle
visual cue.
Extend AddressAnchor to support module exports and use it to drive
contextual instruction hook actions throughout the UI.
InstrumentTemplate can now provide address-specific actions, allowing
the tracer instrument to add instruction hooks directly from the
disassembly view. When a hook already exists for an address, the
context menu instead offers navigation to the hook’s code.