Skip to content

refactor(web): Svelte 5 event-idiom modernization (on:/createEventDispatcher → event attrs + callback props)#90

Merged
HardcoreMonk merged 10 commits into
mainfrom
feature/svelte5-event-idiom
Jul 19, 2026
Merged

refactor(web): Svelte 5 event-idiom modernization (on:/createEventDispatcher → event attrs + callback props)#90
HardcoreMonk merged 10 commits into
mainfrom
feature/svelte5-event-idiom

Conversation

@HardcoreMonk

@HardcoreMonk HardcoreMonk commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

Completes the Svelte 5 migration started in #87 (core runes) by modernizing the event idioms that #87 scoped out. Removes all deprecated Svelte-4 event syntax so the svelte-check gate can enforce the new idiom going forward. Behavior-preserving — no functional change.

Three transform classes across 24 .svelte components:

  1. DOM on:xxxonxxx event attributes (handler bodies byte-identical).
  2. Event modifiers inlined (Svelte 5 removed them):
    • Modal backdrops (16×): on:click|self={h}onclick={(e) => e.target === e.currentTarget && h()}
    • Login (1×): on:submit|preventDefault={submit}onsubmit={(e) => { e.preventDefault(); submit() }}
  3. createEventDispatcher → callback props (11 modals + their parents): child dispatch('close')let { onclose } = $props(); onclose?.(); parent <Modal on:close={h}><Modal onclose={h}>.

Notable specifics:

  • SnapshotModal { stopAfter } payload: the one detail-carrying event. oncreated?.({ stopAfter }) passes the object as the first positional arg; VMDetail.onSnapshotCreated(payload) now reads payload.stopAfter (the old CustomEvent.detail wrapper is gone).
  • SpawnModal legacy → runes: the last legacy component; adding $props() for its callbacks flips it to runes mode, so its reactive locals (profiles, selected, busy, result) became $state().

Gate

web/package.json's check script now promotes event_directive_deprecated to an error (alongside the existing non_reactive_update:error), so any regression to the old on: idiom fails the build. createEventDispatcher emits no svelte-check warning, so its removal is enforced by grep-assert (0 occurrences tree-wide).

Verification

  • npm run check (tightened gate): 0 errors, 10 benign state_referenced_locally warnings (pre-existing from refactor(web): migrate operator UI to Svelte 5 runes (core, behavior-preserving) #87).
  • npx vite build + go build ./cmd/goose-daemon: pass. uidist rebuilt + committed (//go:embed).
  • Tree-wide greps: 0 on: directives, 0 createEventDispatcher, 0 dispatch(, 0 .detail; exactly 16 strict e.target === e.currentTarget backdrops.
  • Playwright smoke on the real compiled SpawnModal (auth-disabled mode): Login preventDefault (no reload), backdrop |self (child-click no-close / self-click close), Escape, Cancel, callback-prop end-to-end unmount, $state render — all pass; 0 Svelte runtime errors.

Domain-callback success round-trips (actual spawn/snapshot/flock actions, incl. the {stopAfter} VM-destroy branch) require a live daemon and were not exercised end-to-end this session; they're covered by the tightened static gate + the proven callback-firing mechanism + code review of the payload path. A live-daemon click-through at next test-host deploy is recommended as belt-and-suspenders.

Method

Hand-migrated (consistent with #87), executed via subagent-driven development: fresh implementer + task-scoped review per component cluster, then a whole-branch review. All per-task reviews and the final holistic review came back clean.

Summary by CodeRabbit

  • Improvements

    • Updated UI interactions across navigation, forms, buttons, tabs, filters, and modals for improved Svelte 5 compatibility.
    • Modal actions now provide more consistent close, create, restore, spawn, and update behavior.
    • Preserved keyboard handling, backdrop-click safeguards, disabled states, and existing workflows.
    • Refreshed the embedded web interface bundle.
  • Documentation

    • Added design and implementation guidance for maintaining modern event-handling patterns.

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The Svelte UI replaces deprecated event directives and dispatcher-based modal events with Svelte 5 event attributes and callback props. Validation now treats event-directive deprecations as errors, documentation records the migration, and the embedded UI bundle reference is refreshed.

Changes

Svelte 5 event idiom migration

Layer / File(s) Summary
Migration design and execution plan
docs/superpowers/plans/..., docs/superpowers/specs/...
Documents the event syntax conversions, callback-prop mappings, validation steps, task grouping, and build verification.
DOM event binding migration
web/package.json, web/src/App.svelte, web/src/components/{ActivityFeed,AuditLog,Login,ModelPicker,System,TaskPanel}.svelte
Replaces deprecated DOM event directives and promotes event_directive_deprecated to a svelte-check error.
Flock and settings modal callbacks
web/src/components/{AddAgentModal,BroadcastModal,BuiltinsModal,ChangeRoleModal,CreateFlockModal,ProfileModal,SendTaskModal,SystemPromptModal}.svelte, web/src/components/{FlockDetail,Flocks,Settings}.svelte
Replaces modal dispatchers with callback props and updates parent wiring while preserving close, keyboard, backdrop, and action behavior.
VM and snapshot modal callbacks
web/src/components/{SnapshotModal,RestoreModal,SpawnModal}.svelte, web/src/components/{VMDetail,VMList,Snapshots}.svelte
Uses callback props for snapshot, restore, and spawn flows, including direct handling of the snapshot stopAfter payload.
Embedded UI bundle update
cmd/goose-daemon/uidist/assets/index-NUOirKmO.js, cmd/goose-daemon/uidist/index.html
Updates bundled runtime messages and stream parsing, then points the HTML entry point to the new hashed asset.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant VMDetail
  participant SnapshotModal
  User->>VMDetail: open snapshot modal
  VMDetail->>SnapshotModal: pass oncreated and onclose callbacks
  SnapshotModal->>VMDetail: return stopAfter payload after creation
  VMDetail->>VMDetail: stop polling and navigate when stopAfter is set
Loading

Possibly related PRs

  • HardcoreMonk/anvil#39: Regenerates the embedded UI bundle and updates the same i18n runtime messages and hashed asset reference.

Suggested reviewers: steve-seungeui

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main migration from Svelte 4 event idioms to Svelte 5 event attributes and callback props.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/svelte5-event-idiom

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
docs/superpowers/specs/2026-07-19-svelte5-event-idiom-design.md (1)

26-28: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Add a blank line before the table.

Markdown tables should be preceded by a blank line to ensure they render correctly across all Markdown parsers.

♻️ Proposed fix
 #### 모달 ↔ 부모 매핑 (결합 단위)
+
 | 모달 | 부모 | 콜백 props |
 |---|---|---|
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/specs/2026-07-19-svelte5-event-idiom-design.md` around lines
26 - 28, Insert a blank line between the “모달 ↔ 부모 매핑 (결합 단위)” heading and the
table that follows it, leaving the table content unchanged.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/superpowers/plans/2026-07-19-svelte5-event-idiom.md`:
- Around line 1-11: Translate the entire Markdown document into Korean,
including headings, explanatory text, goals, architecture, constraints, and task
instructions. Preserve all code identifiers, API paths, environment variables,
commands, file names, Svelte syntax, and checkbox formatting exactly as written.

---

Nitpick comments:
In `@docs/superpowers/specs/2026-07-19-svelte5-event-idiom-design.md`:
- Around line 26-28: Insert a blank line between the “모달 ↔ 부모 매핑 (결합 단위)”
heading and the table that follows it, leaving the table content unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3c69710e-90c5-4feb-8990-0acec486695c

📥 Commits

Reviewing files that changed from the base of the PR and between 42d78c4 and 15664a1.

📒 Files selected for processing (30)
  • cmd/goose-daemon/uidist/assets/index-CMV4roMS.js
  • cmd/goose-daemon/uidist/assets/index-NUOirKmO.js
  • cmd/goose-daemon/uidist/index.html
  • docs/superpowers/plans/2026-07-19-svelte5-event-idiom.md
  • docs/superpowers/specs/2026-07-19-svelte5-event-idiom-design.md
  • web/package.json
  • web/src/App.svelte
  • web/src/components/ActivityFeed.svelte
  • web/src/components/AddAgentModal.svelte
  • web/src/components/AuditLog.svelte
  • web/src/components/BroadcastModal.svelte
  • web/src/components/BuiltinsModal.svelte
  • web/src/components/ChangeRoleModal.svelte
  • web/src/components/CreateFlockModal.svelte
  • web/src/components/FlockDetail.svelte
  • web/src/components/Flocks.svelte
  • web/src/components/Login.svelte
  • web/src/components/ModelPicker.svelte
  • web/src/components/ProfileModal.svelte
  • web/src/components/RestoreModal.svelte
  • web/src/components/SendTaskModal.svelte
  • web/src/components/Settings.svelte
  • web/src/components/SnapshotModal.svelte
  • web/src/components/Snapshots.svelte
  • web/src/components/SpawnModal.svelte
  • web/src/components/System.svelte
  • web/src/components/SystemPromptModal.svelte
  • web/src/components/TaskPanel.svelte
  • web/src/components/VMDetail.svelte
  • web/src/components/VMList.svelte

Comment on lines +1 to +11
# Svelte 5 event-idiom modernization Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Replace the deprecated Svelte 4 event idiom across `web/src` — `on:event`→event attributes, event modifiers inlined, `createEventDispatcher`→callback props — bringing `event_directive_deprecated` warnings to zero, behavior-preserving.

**Architecture:** Hand-migrate, each file touched once. Two independent transform classes are per-file mechanical (DOM `on:`→`on`; inline the 17 removed event modifiers). The third (custom events→callback props) couples each modal with its parent, so tasks are grouped by parent-cluster. The existing `svelte-check` gate catches signature errors; a final task promotes `event_directive_deprecated` to a failing error and greps to prove `createEventDispatcher` is gone.

**Tech Stack:** Svelte 5.56.4, Vite 8, `svelte-check` (gate already present from #87). node_modules already installed.

## Global Constraints

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟠 Major | 🏗️ Heavy lift

Write documentation in Korean.

As per coding guidelines, all Markdown files (**/*.md) must be written in Korean while preserving code identifiers, API paths, environment variables, commands, and file names in their original form. This document is currently written entirely in English. Please translate the contents of this file into Korean.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/superpowers/plans/2026-07-19-svelte5-event-idiom.md` around lines 1 -
11, Translate the entire Markdown document into Korean, including headings,
explanatory text, goals, architecture, constraints, and task instructions.
Preserve all code identifiers, API paths, environment variables, commands, file
names, Svelte syntax, and checkbox formatting exactly as written.

Source: Coding guidelines

@HardcoreMonk
HardcoreMonk merged commit d534379 into main Jul 19, 2026
4 checks passed
@HardcoreMonk
HardcoreMonk deleted the feature/svelte5-event-idiom branch July 19, 2026 10:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant