Commit Graph
60 Commits
Author SHA1 Message Date
Ole André Vadla Ravnås a6f769221f ui: List pattern types in the sidebar
Show each file's declared types under it, with a browse popover when
there are many, and reveal a type's declaration when it is chosen.
2026-10-01 20:49:11 +02:00
Ole André Vadla Ravnås b83995dcce ui: Add a patterns section with an editor
List the library's files in the sidebar with new, import, rename and
delete, and edit each in the code editor, which now colours by syntax.
2026-10-01 20:49:11 +02:00
Ole André Vadla Ravnås 19071308ce ui: Lay out the side panel without HSplitView
HSplitView sizes itself to its panes' preferred widths rather than the
window, so at narrow widths the panel ran past the window's edge and
was clipped. Hold the panel's width ourselves and resize it through a
handle, keeping it within what the detail pane leaves.
2026-09-29 15:38:58 +02:00
Ole André Vadla Ravnås 9edcbd969e ui: Span the event stream across the window 2026-09-28 17:35:15 +02:00
Ole André Vadla Ravnås e464fd6f02 ui: Keep the REPL input above the event stream
Inset the detail column instead of the split view, which
does not shrink the detail for a bottom safe-area inset.
2026-09-28 00:39:33 +02:00
Ole André Vadla Ravnås d55c6eb128 ui: Hoist the split view to tint the sidebar
Make NavigationSplitView the window's root so its sidebar tints its
slice of the titlebar natively, the way Xcode's does. Move the side
panel into the detail column and the event stream to a bottom
safeAreaInset with an opaque background, so the stream spans the full
width and pushes the content up whether or not the sidebar is
showing. Replace CollapsibleVSplitView with a SwiftUI resize handle
and collapse bar.
2026-09-27 17:33:13 +02:00
Ole André Vadla Ravnås 31b1bf2e70 ui: Hide the window toolbar's glass backdrop
The Liquid Glass toolbar backdrop frosted the top of the detail
column's content and drew a divider across it. Hide it so the
detail stays flush to the top.
2026-09-27 15:22:56 +02:00
Ole André Vadla Ravnås 7df308f30c core: Keep QEMU off iOS
Nothing there spawns a process, and the machine UI is AppKit's.
2026-09-10 16:29:56 +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 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
Ole André Vadla Ravnås 5d1ed175fe core: Prepare attaching sessions in the engine
Frontends built the session record, set its phase and surfaced it,
briefly showing the detached banner at the idle phase before attach
began. Move construction, phase and surfacing into prepareSpawnSession
and prepareAttachSession so the session appears already attaching.
2026-07-09 17:31:45 +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 f75755911e macos: Autosave open documents in place
Mark the document edited on every working-copy commit so
AppKit autosave-in-place writes the file. Drop
ProjectAutosaver and its onDisappear flush, which lost edits
made after reopening a saved document.
2026-06-02 15:23:12 +02:00
Ole André Vadla Ravnås 782786a1a1 host: Rebuild autosaver when fileURL changes
State(initialValue:) only runs on first init, so saving an
untitled document left autosaver nil forever.
2026-05-23 08:23:20 +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 b0ec8b60d6 ui: Autosave back to source .luma file 2026-05-17 02:24:37 +02:00
Ole André Vadla Ravnås bf544430bc ios: Tidy custom instrument editor chrome 2026-05-16 23:08:16 +02:00
Ole André Vadla Ravnås 478da8032a ui: Stop marking project document dirty on commits
Changes already persist to the working copy, so the prompt
on close/reboot was noise.
2026-05-15 14:41:42 +02:00
Ole André Vadla Ravnås 6e02787d33 ui: Center collapsed event-stream bar
Use .frame(maxWidth: .infinity, maxHeight: .infinity) instead of
asymmetric .padding(.top, 4)/.padding(.bottom, 11). Chevron and
tint both fill the 32pt pane.
2026-05-15 13:07:39 +02:00
Ole André Vadla Ravnås 87cd769d7d ui: Fix iOS and macOS Release builds
Wrap CursorOverrideRegion in canImport(AppKit) and provide a no-op
View stub for iOS, which has no AppKit. The call site in
SaveBarOverlay now compiles on both platforms.

Add an explicit empty deinit to CollapsibleVSplitView.Coordinator
to work around an EarlyPerfInliner crash in swift-frontend on
Xcode 26.4 Release builds.
2026-05-14 22:44:41 +02:00
Ole André Vadla Ravnås 54e798553c ui: Polish sidebar and editor chrome
Sidebar: manual expansion for sessions and custom instruments;
child rows align under parent icon column. Surface tracer hooks
inline under the Tracer item with a Browse-all popover for the
overflow.

Editor: drop static header rows; SaveBar slides down from the
editor top with Save button and unsaved indicator. Shared
between tracer and custom instrument editors.

GTK: pin detached banner to system-orange across focused and
backdrop states. Trim chevron button padding so it honors the
24px column, and tighten row padding so the icon sits 4px from
the row edge.
2026-05-13 22:58:47 +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 62f1bb5705 ui: Select notebook by default on blank projects
The detail view already falls through to the notebook empty
state when nothing is selected; sync the sidebar to match.
2026-05-12 12:56:53 +02:00
Ole André Vadla Ravnås a24bcff938 core: Release engines on document close
Engine.shutdown() cancels eventLogTask, deviceChangeWatcher,
deviceEventTasks; stops MCP servers; nils observations;
detaches process nodes via node.stop(); stops collaboration.
Idempotent via a one-shot flag.

EngineRegistry.release(workingProjectURL:) awaits any pending
start task, removes the engine from the cache, and awaits
shutdown. Reopening the same URL gets a fresh engine.

MainWindowView and PhoneMainView .onDisappear call release.
2026-05-11 21:15:47 +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 704f6e05bc core: Persist event log across runs
Length-prefixed JSON log at events.log next to db.sqlite,
configurable byte cap with rolling compaction. Replays on
Engine.start.

toLogJSON/fromLogJSON carry the .raw payload and sessionID
that wire JSON drops. EventLog flushes a pendingPersist
queue so the visible-window trim can't drop events.
2026-05-10 15:45:27 +02:00
Ole André Vadla Ravnås 5a13ca1eda ui: Render session icons from one source
Sidebar and phone session list both rendered from
node.processIcons when the session was attached and
session.iconPNGData otherwise, with the iconPNGData branch
in the sidebar carrying an extra accent-color overlay. That
fork made agent-created sessions look subtly off until the
node arrived. Drop the live branch, render only from
session.iconPNGData, and replace the inline icon-stash
copies with a new ProcessSession.adoptIcon helper that
performAttach keeps current.
2026-05-10 09:22:27 +02:00
Ole André Vadla Ravnås 86d063ff2a agent: Surface attach and spawn errors
Engine.attach and Engine.spawnAndAttach now throw on
failure and return the updated ProcessSession on success,
so the mission tools can use a straight try await /
catch instead of refetching the row to read lastError.
list_sessions reports phase as a readable string and
includes last_error when set.
2026-05-10 09:07:34 +02:00
Ole André Vadla Ravnås 119cdd112e ui: Hold mission detail width above 900
Sidebar capped at 320 wide, window minimum lifted to 900,
and the Action Queue / Findings counts get layoutPriority
plus a non-zero Spacer minLength so the right-edge label
isn't first to clip when the user squeezes the window.
2026-05-09 22:09:54 +02:00
Ole André Vadla Ravnås 997e7e541a ui: Calm down mission detail layout
Earlier attempts mixed fixedSize, frame(maxWidth: .infinity),
and a horizontal ScrollView in the header, plus min/max
clamps on the navigation sidebar. The combination starved
the inner HSplitView so a freshly created mission rendered
as just the splitter handle until streaming began. Drop the
exotic modifiers, restore the standard sidebar ideal width,
and let labels truncate individually.
2026-05-09 22:03:52 +02:00
Ole André Vadla Ravnås 382fe7dea3 ui: Stop mission header from pushing layout
Bound the navigation sidebar between 180 and 360 wide so a
drag can't push detail off-screen, clamp the goal text to
two lines, and tuck the metadata labels into a horizontal
scroll view so a long provider/model identifier no longer
shoves the Cancel button out of view.
2026-05-09 21:35:08 +02:00
Ole André Vadla Ravnås a417076bc4 agent: Stash process icons on attach
performAttach now adopts process.icons.last when the
session has none yet, so sessions started by the agent
get the same icon treatment as those started from the
target picker. Icon-to-PNG conversion lives as an Icon
extension in LumaCore so host code uses it via
icon.pngData and the duplicate helper is gone.
2026-05-09 21:23:41 +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 45481e1d2a swiftui: Wire spawn gating UI
Target picker grows a Wait for Launch mode with a popover-anchored
suggestions list. Sidebar context menu adds Arm/Disarm with a regex
prompt; armed sessions get a scope badge.

Detail banner picks among armed, idle, and detached states. The
armed banner offers Resume when gating is paused or failed and
Disarm otherwise.

EventStreamView renders spawn-gating events; raw payloads unwrap to
the inner message string instead of String(describing:) on the case
wrapper. REPL inactive message reflects armed/paused/detached.
2026-05-08 16:15:25 +02:00
Ole André Vadla Ravnås 6694ae2c6c swiftui: Auto-select session on spawn or attach
Select the session row right after the record is saved, before
awaiting attach. The session detail view now opens immediately
and shows the spawning/attaching status, instead of jumping to
the REPL only after attach completes.
2026-05-07 19:11:38 +02:00
Ole André Vadla Ravnås 128b5980ff swiftui: Wire session detail and .luma directory
Sessions now have a top-level detail pane (Summary / Modules /
Threads) with master-detail panes for module symbols and thread
register snapshots. Sidebar gains a session row, and the ITrace
sidebar entries adopt the unified naming.

ITrace detail decodes the streaming trace data with first-paint
prefix, onProgress, and a Stop control restricted to thread
origins; the timeline paginates past 200 instructions.

The document is now a .luma directory wrapper containing
db.sqlite alongside a traces/ folder. Workspace owns the
ProjectUIState (selection, event-stream layout, collaboration
visibility) and a per-session SessionUIState (detail section,
last selected module/thread). MainWindowView reads/writes these
through Bindings instead of local @State.
2026-05-07 16:46:42 +02:00
Ole André Vadla Ravnås 6ab2e3d3b2 macos: Add custom instrument UI 2026-05-05 19:15:56 +02:00
Ole André Vadla Ravnås 51c693a665 swiftui: Add accessibility identifiers for UI tests 2026-05-03 22:29:31 +02:00
Ole André Vadla Ravnås 9d02419562 Sync sessions across collaborative labs
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.
2026-04-30 23:28:15 +02:00
Ole André Vadla Ravnås 88e3bb3154 Add a welcome screen on launch
Replace the auto-reopen-last-document flow with a welcome
screen that lets the user start a new project, open one
from disk, or — after signing in with GitHub — pick from
a list of labs they're a member of. The list is fetched
via a new transient portal connection that issues
.list /labs and disconnects.

Token persistence on macOS now goes through a file under
~/Library/Application Support/re.frida.Luma/tokens/ to
avoid the per-launch keychain prompt that dev-signed
builds suffer; iOS keeps using the keychain. GitHubAuth
caches the load Task so concurrent waiters share one
keychain access, and now flips state to .authenticated
when a persisted token is loaded so the welcome view
shows the labs section right away. requestToken awaits
the load before falling through to a fresh sign-in.

Engine accepts an injected GitHubAuth so the welcome
window and any subsequently-opened document share one
auth instance — no second sign-in prompt when crossing
from welcome to a document.
2026-04-27 15:03:45 +02:00
Ole André Vadla Ravnås ca518fb781 macos: Autosave on mutation, reopen synchronously
SwiftUI's DocumentGroup only autosaves when the FileDocument
value mutates, but Luma's state lives in an external SQLite file.
Wire a GRDB TransactionObserver to post a didCommit notification
and bump a revision counter on LumaProject whenever any write
commits; autosavesInPlace then writes the file on close without a
prompt. Have the saved FileWrapper go through VACUUM INTO so WAL
contents land in the snapshot too.

Move the working-copy location out of /tmp and under
LumaAppPaths.untitledDirectory/.working/ so it survives launches
on iOS (where /tmp is reset between sessions). Write the working
URL lazily and back untitled documents with LumaDocumentLoader so
they get stable "Untitled N.luma" names that the auto-reopen
path can key off.

Drop the deferred DispatchQueue reopen that reliably flashed an
NSOpenPanel before the previous document slid in. Reopen inside
applicationDidFinishLaunching via synchronous makeDocument +
addDocument + showWindows so DocumentGroup sees a document
present before it decides whether to show its launch panel, and
bypass macOS's secure state restoration (which was triggering
entitlement crashes via NSOpenPanel on relaunch). Track
restorationPath via .onChange with initial so Save-As updates
LumaAppState.lastDocumentPath immediately instead of stranding
the old path.

While here, move the CodeShare sheet sibling out from underneath
the Add Instrument sheet on macOS so the "Browse CodeShare" flow
presents sequentially (dismiss add, then open browser) to match
iOS behavior.
2026-04-21 18:53:41 +02:00
Ole André Vadla Ravnås a081adc9d9 ios: Port SwiftUI app to iPhone
Restore iOS compilation by gating AppKit-only code in
StyledTextSwiftUI, ITraceTimeline, CollaborationPanel, and
MainWindowView. Stub ITraceCFGView behind #if canImport(AppKit)
since the Metal/NSView renderer is not ported yet. Add a
UIApplicationDelegateAdaptor mirroring the macOS delegate for
luma:// URL handling and APNs. Fix the rpath for iOS's flat bundle
via SDK-conditional LD_RUNPATH_SEARCH_PATHS overrides.

Build a new phone-first shell (PhoneMainView /
PhoneSessionsListView / PhoneSessionView) that replaces
MainWindowView on iOS. Right-edge drawers for events and
collaboration with glow indicators, a session-switcher popover, and
a segmented REPL / Instruments / Insights / Captures layout. The
Sessions list and Session screen each render a custom compact
header instead of the system nav bar so they sit flush under the
DocumentGroup chrome. Notebook pushes from the Sessions root.

Extract SessionContent so the detach banner lives at the parent of
any session-bound surface instead of each detail view rendering its
own. Make HexView responsive: hide the offset column and use
smaller hex and ASCII fonts in compact width, with selection hit
testing aware of the hidden column. Move the REPL cell timestamp
to share the request line so the result row gets the full cell
width, and trim the REPL horizontal padding in compact width.
Replace Color.cyan with a light/dark adaptive Color.jsTypeLabel so
Object{N} labels stay readable on a light background, and
ellipsize the JS inspector disclosure header to one line.
2026-04-21 18:53:40 +02:00
Ole André Vadla Ravnås c2f8a6be1b Round of collab-panel and notebook polish
A batch of small UI fixes across both frontends:

- GTK header bar: drop the row of text buttons ("New Session…",
  "Add Instrument…", "Install Package…", "Collaboration") and
  replace with symbolic icon buttons pinned to the right, GNOME
  HIG-style. Icons are list-add, applications-engineering,
  media-playback-start (unchanged), folder-download, and
  system-users. Labels survive as tooltips.
- Both CollaborationPanels: shorten "Share this link so others
  can open a new project and join this notebook." to "Share this
  link to invite others to this notebook."
- GTK CollaborationPanel: single-line ellipsized lab title
  (was wrapping to three lines to match picture height);
  consistent "Members"/"Chat" section labels instead of all-caps
  "PARTICIPANTS"/"CHAT".
- Mac CollaborationPanel: lab title wraps over multiple lines
  instead of ellipsizing; panel width is now draggable via
  HSplitView (min 260, ideal 300, max 520); lab picture uses
  fixed-size frame+clip so large-dimension uploads render
  crisply at 48 pt; uploads downscale to ≤512 px JPEG before
  sending.
- GTK CollaborationPanel: matching lab-picture downscale via a
  new CLuma shim (`luma_image_normalize`) that uses GdkPixbuf
  to decode→scale→JPEG-encode.
- Mac notebook editor: explicit Save/Cancel buttons on the
  entry editor (mirrors the GTK row). A freshly-inserted blank
  note cancels itself away instead of leaving a stub row.
- Mac notebook drag: capture row height via GeometryReader so
  the above/below midpoint is actually computed, which means
  drops above the first row finally work.
- GTK notebook row: drop the redundant "Edit" button from the
  header — double-click and the right-click menu both already
  enter edit mode.
2026-04-20 11:41:36 +02:00
Ole André Vadla Ravnås 60fc7bb706 Add lab pictures and refresh timestamps
Lab pictures are now uploadable by the owner — pick an image in
the CollaborationPanel (NSOpenPanel on Mac, GtkFileDialog shim
on GTK) and it becomes the lab's avatar on every client and on
the browser /l/<id> page. PNG, JPEG, WebP, and GIF are accepted;
the server enforces a 512 KiB cap. When no picture is set we
fall through to the owner's GitHub avatar, so a lab that nobody
bothers customizing still shows a real face. Clients get
pictures inline in the .join snapshot (bytes appended after the
notebook blob) and live updates via +update on
/labs/<id>/picture; CollaborationSession gains setLabPicture /
removeLabPicture RPCs.

Two other fixes in the same pass:

- Relative timestamps now refresh. Mac wraps each label in a
  TimelineView(.periodic(..., by: 60)); GTK runs a single 60 s
  Task that rewrites the string on every registered Label. So
  "1 min ago" actually advances to "2 min ago" without a
  rebuild.
- Closing a document window now stops collaboration. Previously
  the session stayed joined until the whole app quit — Mac via
  .onDisappear on MainWindowView, GTK via the existing
  closeHandler calling engine.collaboration.stop() before
  persisting state.
2026-04-20 10:17:50 +02:00
Ole André Vadla Ravnås c41e4e1ec8 swiftui: Make LumaProject a FileDocument
LumaProject was a ReferenceFileDocument, which forced it to also
be an ObservableObject — even though it had no @Published
properties, never published anything via objectWillChange, and
handed its store off to Workspace (the actual ObservableObject
the views observe). The mismatch with Swift 6 strict concurrency
required nonisolated final class, nonisolated(unsafe) on a
publisher we never use, and a nonisolated UTType extension just
to satisfy ReferenceFileDocument's nonisolated protocol surface.

FileDocument is a value type, has no ObservableObject baggage,
and matches what LumaProject actually does: own a temporary
on-disk SQLite file and serialize it in/out. The struct is now
33 lines and contains zero concurrency annotations. The store
is constructed inside MainWindowView from the document's
temporaryDBURL, where it can live in @StateObject Workspace
exactly like before.
2026-04-11 09:43:54 +02:00
Ole André Vadla Ravnås 0e669be3dc Move the rest of business logic into LumaCore
Workspace is now a thin host adapter. Engine owns sessions and
notebook entries (via store observation), GitHub auth + OAuth
device flow, hook-pack discovery, address annotations and address
actions, the disassembler cache, and all instrument lifecycle.
EventLog is @Observable so SwiftUI tracks it directly; the host
no longer mirrors event arrays or version counters.

R2 (live disassembly + trace inspection) lives entirely in
LumaCore as concrete Disassembler / TraceDisassembler classes
returning portable StyledText spans. ProcessNodeViewModel and
InstrumentRuntime are gone; views read engine.processNodes /
node.instruments / engine.descriptor(for:) directly.

Reorganize Luma/Models/ — instrument UI dispatch lives under
Luma/Instruments/, Monaco editor glue under Luma/Editor/, and the
remaining UI types sit at the top of Luma/.
2026-04-07 10:11:31 +02:00
Ole André Vadla Ravnås 8230ad9e4b Delete pointless Workspace delegates
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.
2026-04-07 08:13:37 +02:00
Ole André Vadla Ravnås 0d400d4150 Restore documents via SQLite-backed projects
Each .luma document is a package (directory bundle)
containing project.sqlite. LumaProject implements
ReferenceFileDocument to integrate with SwiftUI's
DocumentGroup:

- New documents create a fresh SQLite database
- Existing documents read the database from the package
- Snapshots serialize the database for save operations

Workspace takes a ProjectStore from the document rather
than creating its own. Each document window gets an
independent store/workspace pair.
2026-04-06 21:49:41 +02:00
Ole André Vadla Ravnås bddb2830fe Wire views and Workspace exts to ProjectStore
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.
2026-04-06 21:03:17 +02:00
Ole André Vadla Ravnås ce6a60899f Wire Workspace and views to ProjectStore
Workspace creates a ProjectStore at Application Support
path and uses it for remote device loading, notebook
entries, and session persistence.

performAttachToProcess, spawnAndAttach, and attachToProcess
all work with value-type ProcessSession structs, saving
through the store after each mutation.

MainWindowView creates sessions as LumaCore structs and
saves them through workspace.store before attaching.
2026-04-06 20:37:51 +02:00