22 Commits
Author SHA1 Message Date
reaperandClaude Sonnet 5 9e2b0d00b9 Bump version to 1.0.1
Co-Authored-By: Claude Sonnet 5 <[email protected]>
v1.0.1
2026-08-08 20:13:02 -05:00
reaperandClaude Sonnet 5 0fc1a10a18 Remove stray npm lockfile
This project uses pnpm (pnpm-lock.yaml, pnpm-workspace.yaml) — the
package-lock.json was an accidental npm-install artifact. Ignore it
going forward so it doesn't get re-added by mistake.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 20:07:36 -05:00
reaperandClaude Sonnet 5 68a5f80c31 Power off all DDEV projects on app quit
Sites were previously left running in the background after closing the
app. before-quit now defers quitting until `ddev poweroff` finishes (or
times out), stopping every running project's containers in one shot.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 19:58:00 -05:00
Kris d014581eea Add npm dependency lockfile v1.0.0 2026-08-08 16:51:40 -05:00
reaperandClaude Sonnet 5 8d52a23c75 Pre-pull DDEV's default Docker images in the background on launch
A first-ever ddev start pulls several GB across the webserver, db,
router, and ssh-agent images, which reads as the app hanging rather
than as an expected download. Warms the cache automatically once per
DDEV version (re-warms after a DDEV upgrade, since image tags are
versioned) using `ddev version --json-output` to discover the exact
default image tags — stays correct without hardcoding image names.
Runs fire-and-forget right after window creation so it never blocks
app startup or usage, and no-ops quietly if ddev/docker aren't
available yet.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:53:18 -05:00
reaperandClaude Sonnet 5 c2b95d057f Close create wizard modal as soon as ddev config succeeds
handleSubmit awaited the entire post-create chain (start, then for
WordPress: download core + install) before ever calling onClose(),
so the modal overlay sat there for the whole multi-step process with
no way to see what was actually happening — the terminal panel that
already tracks this operation's live output was hidden behind it.
Close right after the quick config step succeeds and let post-create
continue as a tracked background operation; failures still surface
via the existing toast/terminal-panel error handling regardless of
modal state.

Also extracts the project-name validation helpers out of
CreateProjectModal.tsx into their own module — mixing component and
non-component exports in one file breaks React Fast Refresh.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:53:10 -05:00
reaperandClaude Sonnet 5 5beb70f1e2 Fix streamed ddev commands hanging forever on interactive prompts
Node's spawn() leaves a child's stdin as an open-but-silent pipe by
default. A GUI-spawned ddev process has no terminal to answer a
prompt (e.g. the first-run telemetry opt-in), and a blocking read on
an open pipe with no EOF just hangs indefinitely instead of failing
or defaulting — reproduced by a "Start" operation that never
progressed past "Permission to beam up?" with no way to recover short
of force-quitting the app. Closing stdin gives ddev an immediate EOF,
which it treats as "use the default" rather than blocking.

Also strips ANSI escape codes from stdout/stderr before forwarding to
the renderer — ddev colorizes output unconditionally regardless of
TTY-ness, so the terminal panel and log viewer were rendering literal
escape sequences as visible text.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:52:52 -05:00
reaperandClaude Sonnet 5 b5085c1e8a Validate and slugify project names in the create wizard
DDEV project names must be valid hostname labels. The wizard
auto-filled the name from the picked folder's basename verbatim, so a
folder like "Aurora Admin" produced a name with a space that DDEV's
`ddev config` rejected with an opaque CLI error the UI never
surfaced. Slugify the auto-filled name and block manual entry of
invalid names before they ever reach the ddev CLI.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:30:09 -05:00
reaperandClaude Sonnet 5 86be76132d Add author and homepage metadata for Linux packaging
electron-builder's .deb target (fpm) refuses to build without an
author email and project homepage in package.json.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:30:02 -05:00
reaperandClaude Sonnet 5 f68261994e Ignore macOS AppleDouble (._*) resource-fork files
Cross-platform copy left dozens of these tracked as untracked noise;
.gitignore already covered .DS_Store but not its ._* siblings.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
2026-08-08 05:29:56 -05:00
R3ap3R ffb7933b6f Split project-type setup into pluggable registry; add WordPress admin link and delete flow 2026-08-05 04:53:52 -05:00
R3ap3R d1dd8ff87c Fix WordPress scaffolding gap; add delete project + WP admin link
Found via real usage: creating a WordPress project only produced
wp-content/ + the wp-config.php bridge — ddev config never downloads
WordPress core, and even with core present the site has no database
until `wp core install` runs (confirmed live: 403/302 until fixed).
The wizard's WordPress path now chains configure -> start ->
`wp core download` -> `wp core install` as separate tracked operations
(each needs its own terminal/status lifecycle, same reasoning as the
configure->start split from the original wizard work), with new site
title/admin username/password/email fields shown only for the
WordPress project type. wp-cli requires the containers running, so
"start after creating" is bypassed (always start) for this path rather
than leaving a checkbox that could produce the exact half-built state
this fixes.

Also added, per direct request:
- Delete project: `ddev delete <name> --yes` (keeps ddev's default
  database snapshot as a safety net), confirmed via window.confirm
  with copy clarifying it only removes DDEV's registration/containers/
  database, not the project's files on disk. Clears the app's selection
  on success.
- WP Admin quick-link: for running wordpress-type projects, a header
  button opening {primary_url}/wp-admin/ directly.

Verified end-to-end against a fresh throwaway project via CDP: full
configure->start->download->install chain produced a real working
site (200 on the homepage, proper login redirect on wp-admin, WP Admin
button href matches), and delete genuinely removes the project from
`ddev list` with the confirmation copy rendering correctly. Two
apparent bugs surfaced during this testing turned out to be the test
script reading DOM state before React's re-render or before ddev's
multi-step delete (build+start+snapshot+teardown) had actually
finished — not real defects; re-verified with proper waits.
2026-08-03 03:15:35 -05:00
R3ap3R cf8104f428 Finalize packaging config and verify a real build (step 9)
Cleaned up the scaffold's electron-builder.yml: correct appId
(com.aurora-dockside.app, matching setAppUserModelId) and productName
("Aurora Dockside"), removed the camera/microphone/Documents/Downloads
Info.plist usage descriptions (boilerplate defaults irrelevant to this
app — it's not sandboxed and doesn't touch camera/mic), removed the
placeholder auto-update publish config pointing at example.com (no
signing infra for that yet, matches the plan's decision to defer
auto-update), and dropped the Linux snap target (snapcraft tooling not
part of this pass) to keep AppImage + deb.

Verified for real rather than just reading the config: ran
`pnpm build:unpack`, which typechecks, builds main/preload/renderer
for production, and packages an actual unsigned "Aurora Dockside.app"
via electron-builder (code signing correctly skipped — no Developer ID
cert on this machine, expected for a local dev build). Launched the
packaged binary directly (not `pnpm dev`) with remote debugging and
called window.api.projects.list() over CDP — it returned real project
data, confirming the PATH fallback added back in step 2 (for Homebrew
ddev not being on PATH for GUI-launched apps) actually holds up
outside a dev-mode terminal context, which is the scenario it exists
for.

This completes all 9 steps of the build plan: scaffold, tooling, core
project management, terminal/status bar, database tools, add-on
management, log viewer, project creation wizard, settings/polish, and
now packaging.
2026-08-03 00:29:31 -05:00
R3ap3R 0820c2f3d8 Add settings: theme, zoom controls, keyboard shortcuts (step 8)
Theme (light/dark/system) persisted via Zustand's persist middleware
to localStorage, applied by toggling .dark on <html> — the CSS custom
variant was already wired up from step 1 but nothing had driven it
until now, so the app was silently stuck in light mode regardless of
OS appearance. "System" resolves via matchMedia and stays live via a
change listener. Zoom in/out/reset go through a small main-process IPC
(webContents.setZoomLevel) since the renderer can't reach Electron's
webFrame directly with contextIsolation on. Keyboard shortcuts
(Cmd/Ctrl+N, +comma, +=/-/0) are a single window-level listener
mounted once at the app root.

Verified end-to-end via CDP: confirmed system theme correctly resolved
dark to match the real OS appearance at test time, manually switching
to Light actually removed the .dark class and persisted to
localStorage, zoom in/reset both confirmed via the IPC's returned zoom
level (cumulative across calls), and both keyboard shortcuts
(dispatched as real KeyboardEvents) correctly opened their modals.

Also added a matchMedia polyfill to the Vitest setup file — jsdom
doesn't implement it, which broke App.test.tsx once useAppliedTheme
started running on every render.
2026-08-03 00:26:15 -05:00
R3ap3R 541d719680 Add project creation wizard (step 7)
New project flow: native directory picker, project name (auto-filled
from folder name), project type selector (Auto-detect plus common
CMS/framework types), optional docroot, and a "start after creating"
checkbox. Runs ddev config with cwd = the chosen directory (streamed
through the existing commandRunner), then reuses the existing
useStartProject() mutation for the start step rather than inventing
multi-phase operation semantics — ddev config registers the project
by name, so a plain `ddev start <name>` works identically to starting
any other project afterward.

Scoped down from the original app's wizard: skipped scaffolding a
fresh CMS codebase (composer create-project / wp core download /
etc.) since each framework needs different install commands — this
covers project registration + config + start, with ddev's own
--auto/--project-type detection handling "auto-detect for existing
folders" for free (no custom detection heuristics needed).

Verified end-to-end against the real scratch environment: called the
create.configure IPC directly (the picker itself opens a native OS
dialog CDP can't drive, same constraint as import/export in step 4)
with a real target directory, confirmed the generated .ddev/config.yaml
has the correct name/type/docroot, confirmed the new project appears
in the sidebar via the existing polling within one refresh cycle, and
verified the modal's form guards (Create disabled until a directory
is chosen) and all type-selector options render correctly. Cleaned up
via `ddev delete`.
2026-08-03 00:19:39 -05:00
R3ap3R 49293ac34c Add streaming log viewer with service switching and filtering (step 6)
ddev logs -f runs indefinitely rather than completing, so it doesn't
fit runStreamed's resolve/reject-on-exit model or the terminal panel's
operation semantics — added a parallel startLogStream/logs:data path
in commandRunner.ts that shares the same process-tracking map (so
stopping a log stream reuses the existing terminal:cancel IPC) but
pushes chunks over a dedicated channel decoupled from the status
bar/toast system. Kill all tracked processes on app quit so a
forgotten open log viewer doesn't leave an orphaned `ddev logs -f`.

Two real bugs found and fixed via live testing:
- react-hooks/set-state-in-effect flagged synchronous setState calls
  used only to reset state on service change. Fixed by keying the
  streaming component by service (LogPane key={service}) so switching
  services remounts it and state resets via useState initializers
  instead — the React-recommended pattern for this.
- Filtering operated on raw stream chunks, not lines: a single data
  chunk can bundle many log lines or split one across chunk
  boundaries, so filtering by chunk let unrelated lines through
  whenever a match happened to share a chunk. Fixed by buffering
  partial lines per stream and only filtering/rendering once complete
  lines are assembled.

Verified end-to-end against the real scratch project via CDP-driven
clicks: live streaming from real containers (db and web service logs
both confirmed with distinct real content), service switching,
filtering (confirmed both the false-positive case is fixed and real
matches still work), and confirmed closing the viewer actually kills
the underlying `ddev logs -f` process rather than leaving it orphaned.
2026-08-03 00:13:49 -05:00
R3ap3R ebfec5f787 Add add-on management: registry browser, install, remove (step 5)
Browse the ~270-entry DDEV add-on registry with search, install via
`ddev addon get`, remove via `ddev addon remove` — both routed through
the streaming commandRunner. `addon get`/`remove` support `--project
<name>` directly (unlike snapshot restore), so no cwd trick needed
here. Verified working with the project stopped, per the plan's
requirement.

Found and fixed a real bug via live UI testing: `ddev addon list
--installed --json-output` omits the `raw` key entirely when nothing
is installed (unlike `ddev list`/`ddev snapshot --list`, which include
`raw: null`). The shared runDdevRead helper treated that as an error,
so after removing the last add-on the query errored on refetch and
React Query kept showing the stale cached row instead of clearing it.
Split the helper into runDdevRead (strict, for describeProject where
missing data is a real error) and runDdevReadList (treats missing raw
as empty, for every list-style command) and fixed all four list call
sites to use it.

Verified end-to-end via CDP-driven clicks against the real scratch
project: search filtering, install (streamed output, confirmed via
`ddev addon list --installed` on the CLI), and remove — including
re-confirming after the fix that the installed-add-ons table actually
clears instead of showing stale data.
2026-08-03 00:02:51 -05:00
R3ap3R 9f67b13a47 Add database tools: snapshots and import/export (step 4)
Snapshot create/list/restore/delete and DB import/export via native
file dialogs, all routed through the streaming commandRunner from
step 3. `ddev snapshot restore` has no project-name flag (unlike every
other ddev command used so far) — it resolves the project from cwd,
so commandRunner/execDdev now accept an optional cwd and every
database command runs with cwd = project approot instead of passing
the name positionally.

Fixed a real bug found via live testing: the snapshot-naming UI used
window.prompt(), which Electron's renderer does not support (it
returns null with no dialog, silently). window.confirm() does work
(verified: real native dialog, respects accept/dismiss) so the delete
confirmation was left as-is. Snapshot naming now uses an inline text
input instead.

Verified end-to-end against the real scratch DDEV project via CDP-
driven clicks: named snapshot creation, deletion, and restore
(streamed output ending in "Database snapshot restoretest was
restored in 7s") all confirmed working through the actual UI.
import-db/export-db verified via direct CLI round-trip using the
exact --file= flag syntax the app invokes (skipped UI-driving these
since they open native OS file dialogs that CDP cannot dismiss).
2026-08-02 23:51:09 -05:00
R3ap3R 199c4d254e Add streaming terminal panel, status bar, and toast notifications
Step 3 of the build plan. Long-running ddev commands (start/stop/
restart) now spawn via commandRunner.ts and stream stdout/stderr to
the renderer over IPC (terminal:data/terminal:exit), instead of the
previous fire-and-forget JSON exec. A single useTerminalEvents hook
owns turning those events into terminal panel lines, status bar
progress, and success/error toasts, decoupled from whichever mutation
triggered the command so later features (snapshots, addons) can reuse
the same pipeline. Cancel is wired end-to-end: the status bar's Cancel
button kills the underlying child process via a tracked operation id.

Verified against the real scratch DDEV project via a CDP driver
script (Electron launched with --remoteDebuggingPort, driven by
clicking real DOM buttons): confirmed live streaming output, the
status bar's spinner/cancel affordance, and that cancelling mid-
restart genuinely interrupts the process rather than just hiding the
UI (only the first output line appears, vs. full output on a normal
run).
2026-08-02 23:40:29 -05:00
R3ap3R 602659c45f Add core DDEV project management (list/describe/start/stop/restart)
Wire up the full stack for step 2 of the build plan: a ddev.ts CLI
wrapper in the main process (execFile + JSON envelope parsing, with a
PATH fallback since GUI apps on macOS don't inherit Homebrew's PATH),
IPC handlers exposed through a typed preload window.api surface,
TanStack Query hooks for polling/mutations, and a two-pane UI (project
list sidebar + detail panel with URLs, services, and DB credentials).

Verified end-to-end against a real scratch DDEV project: typecheck,
lint, and tests pass, and the running app correctly displays live
project data and reflects state changes (start/stop) via polling.
2026-08-02 23:31:45 -05:00
R3ap3R 25eb6b7b58 Wire up Tailwind CSS 4, Vitest, and core app libraries
Add Tailwind (via Vite plugin), Vitest+RTL test setup, and the
Zustand/TanStack Query/Lucide libraries the architecture plan calls
for. Strip the electron-vite demo boilerplate (logo, IPC ping demo,
Versions component) in favor of a minimal placeholder screen.

Verified: typecheck, lint, and test suite all pass; pnpm dev boots
and serves the correct renderer HTML.
2026-08-02 23:21:04 -05:00
R3ap3R 5a3315eff6 Scaffold Aurora Dockside with electron-vite + React + TypeScript
Base template for a from-scratch DDEV desktop manager (Electron instead
of Tauri), built incrementally per the approved project plan.
2026-08-02 23:16:26 -05:00