Skip to content

feat(desktop): Go/Wails host + Go speech + media routes (DIVA Next W0/W3/W4/W5) - #19

Merged
mastwet merged 28 commits into
mainfrom
feat/wails-go-host
Oct 4, 2026
Merged

mastwet merged 28 commits into
mainfrom
feat/wails-go-host

Conversation

@devin-ai-integration

Copy link
Copy Markdown
Contributor

Summary

DIVA Next migration (W0/W3/W4/W5-headless): replaces the Tauri/Rust host with a single Go desktop host on pinned Wails v3.0.0-beta.27, embedding the sealed VIVY runtime via sdk pack --target go-host. Frontend seam preserved (DesktopDispatch + media routes), no behavior change for Vue callers.

Key pieces:

  • cmd/diva + internal/desktop — Wails app: AssetServer middleware + internal media mux (no TCP listener), single-instance via Wails UniqueID and VIVY workspace lease, lifecycle hooks (hide→speech invalidation, quit→bounded drain).
  • internal/speech — full Go port of diva-speech: revision-CAS config store, OS keyring credentials (dev.projectivy.diva.speech, presence-only), voice-asset store (digest ids, caps, leases), SiliconFlow + MiniMax providers (verified endpoints, timeouts, capped reads, MP3 magic), cancellable request registry with stale-context discard, speech:diagnostic events.
  • internal/desktop/media_http.go — POST /media/speech/{transcribe,synthesize}, POST|GET /media/voice-assets* with capability grant before body reads, 2KiB meta cap, typed SpeechError JSON bodies.
  • internal/desktop/speech_dispatch.go — the 8 preserved speech_*/voice_asset_* commands; credentials reported as presence booleans only.
  • W0 probe (tools/wails-probe) + wails-native-probe.json fixture: sender identity via bound window context, x-wails-window-id native overwrite, internal raw-binary media route, keyring pin (zalando/go-keyring v0.2.8).
  • W5 candidate acceptance: fixtures/wails-candidate-acceptance.json (17 rows, 8 pass on Linux headless / 9 owned-pending) + scripts/ci/check_wails_candidate.py (--require-all-passed = promotion gate).

Evidence: docs/logs/2026-10-wails-migration/{w0-1,w3-1,w4-1,w5-1}/. Verified: go test -race -tags 'gtk3 vivy_headless', sealed pack/build/inspect, xvfb smoke (fresh profile, single-instance, crash→restart), pnpm 551/551, vue-tsc.

Not in scope: src-tauri/ removal (W6, blocked on W5 promotion gate), Windows leg (Windows child Devin running: W0 Task4/5 + Windows matrix), real-provider rows (operator credentials).

Link to Devin session: https://app.devin.ai/sessions/fa737cdff8914bb382be88ac42d4ec77
Open in Devin Desktop: https://app.devin.ai/desktop/session/fa737cdff8914bb382be88ac42d4ec77?variant=devin
Requested by: @mastwet

mastwet and others added 7 commits October 4, 2026 09:23
Amend the existing DIVA Next architecture and contract authority with eight
executable migration stories, dependencies, gates and source freeze records.
Keep prior host plans as historical references and preserve domain behavior.

Planning validation covers paths, links, requirement coverage and the DAG.
No product/native/provider tests or implementation are claimed.
Paired archive branches exist; annotated tags await tag-write access.
Mainline code and product release remain unchanged.
Co-Authored-By: 大湿 <1136523089@qq.com>
- scripts/build-desktop.py --mode build|test|repin: stages exact pins
  into task-local dirs, resolves consumer modfile from the pack target
- build mode: frozen pnpm install/build once, sealed pack, inspect,
  build-report.json; --development snapshots dirty inputs labeled
  non-release
- test mode: same closure, go build + go test -race under the resolved
  consumer.mod with vivy_headless
- tracked diva.go-host-inputs/v1 lock pins vivy/laputa/inofy sources,
  recipe, pnpm lock, toolchain; host commit resolved at build time
- just recipes: desktop-build, desktop-build-dev, go-test, desktop-repin
- verified: frozen frontend build succeeds end-to-end; pack stops at
  missing cmd/diva + go.mod until W3

Co-Authored-By: 大湿 <1136523089@qq.com>
Pin wails v3.0.0-beta.27 (module+CLI+@wailsio/runtime) and
zalando/go-keyring v0.2.8; prove native sender identity, capability
gate, bounded raw media route, shutdown surface and generated bindings
on linux/amd64 (-tags gtk3). Windows x64 rows still pending per W0 gate.

Refs docs/plans/diva-next/wails/W0.md

Co-Authored-By: 大湿 <1136523089@qq.com>
Wails v3.0.0-beta.27 desktop replaces the retired Tauri host:

- internal/desktop: Compose (hostv1.Open + partial-failure unwind), RuntimeService (VivyCall CallReply envelope, Next pump -> vivy:event, MediaToken bound to main window, DesktopDispatch gated not_ready stub for W4), sender gate (origin allowlist + native window-id header), 10MiB bounded raw media mux, close-to-hide/reopen/tray, config resolution (DIVA_VIVY_CONFIG > flag > seeded user config dir)
- cmd/diva entrypoint + agent-diva-gui/assets.go embeds (dist + default vivy.yaml); deps/ symlinks keep dev replaces inside the host tree (pack contract)
- agent-diva-gui: generated TS bindings, desktop-host.ts Wails seam (vivyCall/onVivyEvent/nativeCall/nativeListen/mediaFetch), createWailsTransport, all @tauri-apps imports replaced (invoke->nativeCall, listen->nativeListen, emitTo->Events.Emit, getCurrentWindow->thisWindow, opener->Browser.OpenURL, __TAURI_INTERNALS__->_wails.environment)
- build-desktop.py: buildTags [gtk3] on Linux (sealed via vivy sdk d9dfdf49), mode test appends tags, restores dist/.gitkeep after vite
- justfile: desktop-bindings/desktop-dev/desktop-test recipes

Verified: go test -race 17/17; pnpm vitest 551/551 + vue-tsc clean; build-desktop --mode test (staged pack + race tests) and --mode build --development (sealed ELF + inspect) pass; xvfb smoke opens VIVY host + Wails window; second instance rejected (VIVY workspace lease + SingleInstance). Windows acceptance pending W0 leg.

Log: docs/logs/2026-10-wails-migration/w3-1/
Co-Authored-By: 大湿 <1136523089@qq.com>
- internal/speech: config CAS store, OS keyring credentials, voice-asset
  store with leases/caps, SiliconFlow+MiniMax providers, cancellable
  request registry, Service facade with diagnostics + graceful shutdown
- internal/desktop: /media/speech/* + /media/voice-assets* routes with
  capability gating and typed error bodies; speech dispatch table for the
  8 preserved frontend commands; hide/shutdown lifecycle invalidation
- evidence: docs/logs/2026-10-wails-migration/w4-1/

Co-Authored-By: 大湿 <1136523089@qq.com>
- sealed candidate on a477ffc: fresh-profile boot, single-instance,
  crash/restart, clean quit, log sink, scripted voice — 8/17 rows pass
- 9 pending rows owned for owner E2E (GUI drive, real providers, Windows)
- scripts/ci/check_wails_candidate.py validates fixture + cross-checks
  build report/binary hash; --require-all-passed is the promotion gate
- evidence: docs/logs/2026-10-wails-migration/w5-1/

Co-Authored-By: 大湿 <1136523089@qq.com>
@devin-ai-integration

Copy link
Copy Markdown
Contributor Author

I'll fix CI failures and address comments from users with write access. I'll skip comments containing "(aside)".

  • Disable automatic comment, CI, and merge conflict monitoring

mastwet added 19 commits October 4, 2026 06:43
- src-tauri speech commands: annotate closures with SpeechResult<T>
  (rustc now rejects ambiguous E through .map_err(InvokeError::from)),
  fix voice_asset_delete &str->String mismatch, import Manager for
  app.path() — identical breakage exists on main under newer toolchains
- legacy-calls gate: allow bare fetch() only inside mediaFetch() in
  desktop-host.ts — the W3-3 internal binary media seam (token +
  native window-id headers); all other fetch sites still denied;
  selftest fixtures still 9/9

Co-Authored-By: 大湿 <1136523089@qq.com>
- shared_name() picks .dll on Windows (test wrote .so unconditionally)
- build_fake_artifact returns false when cl/cc absent so fake_ tests
  skip with a recorded reason instead of panicking on PATH-less runners

Co-Authored-By: 大湿 <1136523089@qq.com>
Co-Authored-By: 大湿 <1136523089@qq.com>
tag v* or manual dispatch -> windows/linux matrix runs
scripts/build-desktop.py --mode build against the vivy/laputa
commits pinned in build/vivy-sources.lock.json, uploads the
single-file binary + build-report + checksums, and attaches
them to the GitHub release on tag pushes. DIVA_BUILD_TOKEN is
only needed if the dependency repos are private.

Co-Authored-By: 大湿 <1136523089@qq.com>
- host go.mod adds replace github.com/google/renameio =>
  ./deps/agent-vivy/third_party/renameio so dev builds compile on
  Windows; pack rewrites it to the staged vivy path in consumer.mod.
- vivy source pin repinned to 3862b768 (carries third_party/renameio).

Co-Authored-By: 大湿 <1136523089@qq.com>
Co-Authored-By: 大湿 <1136523089@qq.com>
Co-Authored-By: 大湿 <1136523089@qq.com>
Window close only hides; without tray affordances the runtime had no
way back (F2) and no explicit quit (F3). AttachWindow + custom click
toggles through the shared hideToTray/reopen path (same speech-context
invalidation as window close); tray menu adds Show DIVA and Quit DIVA.

Co-Authored-By: 大湿 <1136523089@qq.com>
Co-Authored-By: 大湿 <1136523089@qq.com>
…ee_hash

Python os.lstat reports .cmd/.exe files as +x on Windows while Go
os.Lstat reports 0666/0444, so the lock/pack treeSHA256 diverged and
build-desktop.py could not seal a host artifact on Windows. Regular
files now mask out the synthetic exec bits when os.name == 'nt'.

Co-Authored-By: 大湿 <1136523089@qq.com>
…mespace

Standalone probe exercising speech.NewCredentialStore(speech.OsKeyring{})
against the real dev.projectivy.diva.speech / v1.siliconflow slot:
presence -> set -> presence -> delete -> presence (-op cycle|set|delete).
Used by the w0-2 Windows leg to prove wincred persistence and the
no-plaintext-fallback contract.

Co-Authored-By: 大湿 <1136523089@qq.com>
…atrix)

Windows Server 2022 native leg on sealed diva.exe (gen a24a62a2, diva
81c381f / vivy 3862b768 / laputa 6f2eed2):

- W0 Task 5 keyring: GO — wincred set/get/delete/presence on probe and
  production dev.projectivy.diva.speech/v1.siliconflow slot (cmdkey
  verified, no plaintext fallback)
- W0 Task 4 lifetime: close-to-hide, lease single-instance,
  crash->TTL->relaunch, signal-quit ordering with clean lease release
  proven; W5-T4-HIDE-REOPEN marked failed — no reopen affordance
  (unattached tray, lease blocks OnSecondInstanceLaunch)
- New findings: sealed exe embeds only .gitkeep (frontend not shipped
  to the window), no quit affordance, no audio endpoints on VM
- Fixture: 8 passed / 8 pending / 1 failed; native-probe keyring and
  lifetime rows updated; index/TODOLIST/LOCK bookkeeping

Co-Authored-By: 大湿 <1136523089@qq.com>
…path hardening)

Co-Authored-By: 大湿 <1136523089@qq.com>
…verified, F5/F6 found

- W5-T4-HIDE-REOPEN, W5-T4-WEBVIEW-RELOAD -> passed (tray AttachWindow +
  menu reopen/quit; real Vue UI embedded and reloaded)
- W5-T2-FIRST-TURN -> failed (F5: sealed turn/start gates every fresh
  session on missing frozen core; workaround capture proven)
- W5-T3-CHAT-MATRIX -> failed (F6: GUI never binds/renders session while
  runs complete and persist)
- grants/cognitive/event-loss/voice rows pending with honest reasons
- evidence: docs/logs/2026-10-wails-migration/w0-3/

Co-Authored-By: 大湿 <1136523089@qq.com>
Wails3 injects window._wails.environment via execJS on NavigationCompleted,
which can land after the app mounts. isTauri() sampled at mount then saw
undefined, skipped vivyChat.connect(), and the UI stayed on 'connecting'
forever (F6). Wait for the runtime-config-ready event (bounded 3s) before
declaring browser mode.

Co-Authored-By: 大湿 <1136523089@qq.com>
…-race verified

F5 (vivy e3b60280) verified: fresh-session GUI turn writes frozen_core_sessions
on first Prepare and reaches the model call. F6 root-caused via WebView2 CDP:
wails3 injects _wails.environment post-mount (NavigationCompleted), so the
isTauri() gate skipped connect(); fixed in dda9d7d by awaiting
wails:runtime-config-ready. Fixture 13 passed / 4 pending / 0 failed.

Co-Authored-By: 大湿 <1136523089@qq.com>
… passed on GUI

GRANTS-CATALOG: providers catalog/model selector/preset dropdown/sandbox
surface match settings/providers, settings/get, tools/list verbatim; module
catalog from sealed generation.json; approval-gated boundaries declared per
tool. COGNITIVE: persona/memory/evolution projections + controls live;
invalid_schema and backend_unavailable envelope statuses surface explicitly;
frozen-core lazy capture already proven (w0-4). Fixture 15 passed / 2 pending
/ 0 failed.

Co-Authored-By: 大湿 <1136523089@qq.com>
…xes)

Co-Authored-By: 大湿 <1136523089@qq.com>
Co-Authored-By: 大湿 <1136523089@qq.com>
@mastwet
mastwet merged commit 23c3cdc into main Oct 4, 2026
4 checks passed
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