Commit Graph

56 Commits (main)

Author SHA1 Message Date
mirivlad 03175aa46d feat: Notes core service + Notes API + router auto-detect notes context
- Add internal/core/notes/ service (Service, Layout, Normalize, tests)
- Register verstak/core/notes/v1 capability
- Inject NotesService into App, expose 8 Notes API endpoints
  (CreateNote, RenameNote, ReadNote, SaveNote, EnsureOverview,
   ListNotes, SearchNotes, NormalizeNoteTitle)
- Router: auto-detect Notes context via path (IsInsideNotes)
- PluginCard: show workspaceItems contribution count
- Regenerate Wails bindings (App.d.ts, App.js, models.ts with notes.NoteInfo)
- Fix .gitignore pattern for e2e-results/
2026-06-21 23:22:36 +08:00
mirivlad 0b6b0d0926 fix: workbench 'back' blocked, workspace breadcrumb-up only when btn active
- onNavigateBack/Forward now skip entirely when currentView === 'workbench'
  (user relies on close button, not mouse back)
- onNavigateBack inside workspace checks upBtn.disabled before clicking —
  in root folder (no currentPath) button exists but disabled, so navigateBack
  falls through to navigationStack for cross-view navigation
- mouseHistoryDirection and keyHistoryDirection also block 'workbench' to
  prevent bypass via pointerdown/mousedown listeners
2026-06-21 16:25:45 +08:00
mirivlad b4e66c9779 fix: mouse navigation — redirect workspace back/forward to Files buttons, remove xinput monitor
- onNavigateBack/Forward now check for currentView === 'workspace' first
  and delegate to Files plugin's up/forward buttons (breadcrumb/Fwd nav)
- Fall back to navigationStack for cross-view navigation
- Removed mouse_monitor.go (xinput test-xi2) — causes phantom X windows,
  superseded by GTK-level vendor patch
- Removed startMouseMonitor call from App.Startup
2026-06-21 16:18:45 +08:00
mirivlad d644c5bb79 feat: mouse back/forward navigation + history stack
- C patch (vendor/.../window.c): intercept GDK button 8/9 → dispatch
  CustomEvent('verstak:navigate-back'/'verstak:navigate-forward')
- App.svelte: navigation stack (snapshot-based history), alt+arrows,
  mouse button back/forward handlers, onNavigateBack/Forward
- WorkbenchHost: close via navigate-back event
- WorkspaceHost: workspace tab bar + tool panels
- wails-mock: full navigation, sidebar, vau...
2026-06-21 16:01:21 +08:00
mirivlad 8e5690e8f7 feat: intercept GDK button 8/9 for mouse back/forward navigation
WebKitGTK does not propagate XButton1/XButton2 (buttons 8 and 9) into
DOM events — event.button and event.buttons are always 0 for these
clicks. This prevents the frontend from detecting hardware back/forward
mouse buttons for history navigation.

Solution: patch Wails' window.c on Linux to intercept button-press-event
at the GTK signal level (before WebKit processes it). For button 8/9 we
call webkit_web_view_run_javascript() to dispatch a native CustomEvent
('verstak:navigate-back' / 'verstak:navigate-forward') into the page,
allowing the frontend to navigate history without any workaround on the
JS side.

The patch is applied automatically during build via scripts/build.sh:
  go mod vendor → patch -p0 < patches/window.c.button-press.patch
Vendor directory is gitignored.
2026-06-21 13:49:13 +08:00
mirivlad 0ac473d720 core: Milestone 7b — Files explorer and Default Editor improvements
- Files plugin: richer explorer with breadcrumbs, selection, toolbar actions,
  rename/trash, filter, sorting, hidden/reserved entries filtered
- Default Editor: line numbers, Ctrl+S, markdown toolbar, Edit/Preview/Split,
  markdown preview, Reload/Revert
- E2E tests: 39 passed for files + editor
- Workspace model: correction, naming alignment, compatibility wrappers
- Updated docs: NOTES_FILES_PLUGIN_PLAN.md, PLUGIN_RUNTIME.md
2026-06-20 19:20:13 +08:00
mirivlad 4de5a74a55 fix: sanitize sync error messages, detect non-sync servers, add health check in TestAuth 2026-06-20 03:20:25 +08:00
mirivlad db67c370ab fix: add backend.call() API and fix [object Object] in workspace sidebar
- Add api.backend.call(method, ...args) to VerstakPluginAPI for direct Wails method invocation
- Add wsName() helper in WorkspaceTree.svelte with String() coercion to prevent [object Object] display
- Use correct Wails path window['go']['api']['App'] in backend.call()
2026-06-20 03:02:33 +08:00
mirivlad ed69746332 feat: add sync backend methods 2026-06-20 02:25:25 +08:00
mirivlad 5c979174f1 fix: polish workspace files and editor shell 2026-06-19 23:37:10 +08:00
mirivlad a6412fa070 feat: milestones 6b-fix through 6e — default-editor, files plugin, workspace host, workspaceItems contribution
- Fix PluginCard openProviders display
- Add default-editor plugin (text/markdown/notes-context)
- Add files plugin with workspaceItems placement
- Add workspaceItems contribution point (Go + API + mock + SDK)
- Add WorkspaceHost component for workspace area
- WorkspaceTree dispatches selection event
- Fix default-editor layout to fill container
- Fix PluginCard unsafe .length access
- Add E2E tests: 34/34 pass
- Add bundle execution check to official-plugins check.sh
- Update docs: PLUGIN_RUNTIME, DEV_PLUGINS, MILESTONE_6B/6C/6D plans
2026-06-19 16:42:01 +08:00
mirivlad 6ed6df311a Implement milestone 6b workbench routing skeleton 2026-06-19 07:51:57 +08:00
mirivlad a100f5a441 fix(plugin-manager): sync UI state with plugin lifecycle + sidebar click fix
Root cause fixes:
- Sidebar: handleSidebarItem used item.id instead of item.view for viewId.
  Platform Test sidebar item has id=verstak.platform-test.sidebar but
  view=verstak.platform-test.diagnostics. Click now dispatches correct viewId.
- PluginManager: EnablePlugin/DisablePlugin only wrote to plugins.json but
  never re-discovered plugins. UI showed stale state (no Enable button after
  Disable, no Disable after Enable). Now calls ReloadPlugins() + loadAll()
  after each toggle.
- PluginManager: loadAll() fired async loads (GetCapabilities etc) without
  awaiting — loading spinner disappeared before data was ready. Now awaits
  all via Promise.all.
- PluginCard: no loading feedback on Enable/Disable buttons. Added
  actionFeedback prop — buttons show '⟳ Enabling...' / '⟳ Disabling...'
  and are disabled during operation.
- PluginManager: no visible result after Reload/Enable/Disable. Added
  toast notifications (success/error/info) with auto-dismiss.
- Settings: openSettingsFromProps didn't handle missing panel — now shows
  visible error in modal.
2026-06-17 19:40:05 +08:00
mirivlad 6d2f7858eb fix: replace emoji icons with inline SVG (Icon.svelte + icons.js)
All emoji characters replaced with inline SVG icons:
- Plugin Manager sidebar: puzzle SVG icon
- Verstak logo: stack/tray SVG icon
- Plugin icons: flask SVG (from plugin manifest)
- Warning/error indicators: warning triangle SVG
- Settings button: gear SVG
- Vault recent: vault/shield SVG
- Fallback: dot SVG

New components:
- frontend/src/lib/ui/icons.js — SVG path map
- frontend/src/lib/ui/Icon.svelte — reusable SVG icon component

Icon policy: NO emoji or unicode pictographic symbols in the app.
Only SVG icons registered in icons.js are allowed.
Wails WebKitGTK does not render colour emoji.
2026-06-17 19:02:51 +08:00
mirivlad c2e14cae69 feat: add bundle-host-test.cjs + smoke integration
- bundle-host-test.cjs: JS smoke-test for PluginBundleHost contract
  - 4 error boundary scenarios (missing frontend, JS throw, missing component, mount throw)
  - 5 real mount scenarios (bundle exec, DiagnosticsPanel mount, Settings mount, unmount, mount-throw catch)
  - Runs real platform-test bundle in vm.Sandbox with mock window/document
- smoke-platform.sh: add bundle-host-test step
- Fix: platform-test badgeRow div call (3rd arg was ignored)
2026-06-17 18:51:14 +08:00
mirivlad 05ef1449bc feat: milestone 5b — frontend bundle host + VerstakPluginAPI stub
- Bundle contract: window.VerstakPluginRegister(id, {components: {...}})
- PluginBundleHost.svelte: loads bundle via GetPluginAssetContent, mounts components
- VerstakPluginAPI.js: restricted API (capabilities, events, settings, commands — all stub)
- ViewContainer: PluginBundleHost replaces placeholder when frontend bundle exists
- PluginManager: settings panel via PluginBundleHost (removed hardcoded form)
- Backend: GetPluginFrontendInfo, GetPluginAssetContent with path security
- Security: reject absolute paths, path traversal, escape from plugin root
- Error boundary: bundle load/execute/mount errors show fallback, not crash
- Tests: 11 backend tests (asset API), frontend bundle checks in smoke
- Docs: bundle contract, VerstakPluginAPI, security constraints
2026-06-17 17:39:50 +08:00
mirivlad 1dff97a9c0 fix: smoke test now proves manifest→discovery→registry flow with ReloadPlugins gating
- runContributionsTest rewritten: shows exact manifest fragment from plugin.json
- Capability resolution gates contribution registration (status=degraded)
- Unregister before Register throughout (matches ReloadPlugins)
- Verify contributions by name with data matching manifest
- Proper \n formatting
2026-06-17 17:21:46 +08:00
mirivlad a96ffb5801 chore: split build.sh and update-and-build-all.sh
- build.sh: deterministic local-only build, fail-fast, no git pull
- update-and-build-all.sh: dev helper, pulls all repos, builds official plugins, then builds desktop
- Docs: added Build Scripts section explaining the difference
2026-06-17 17:13:14 +08:00
mirivlad 86eeadd2a9 feat: milestone 5a — frontend plugin host, contribution lifecycle, UI shell
- Contribution Registry: ListByPoint, idempotent Register (Unregister-before-add)
- Flat ContributionSummary types for frontend (no nested .item.)
- Sidebar.svelte: items from ContributionRegistry, sort by position, error boundary
- ViewContainer.svelte: declarative placeholder host with error boundary
- PluginManager.svelte: settings panels from registry, knoppka only with settingsPanel
- PluginCard.svelte: settingsPanels prop, disabled state for Settings button
- Error boundary: ViewContainer + PluginManager catch errors, shell stays stable
- ReloadPlugins: Unregister before Register contributions (no duplicates)
- Smoke: -test-contributions flag, enable/disable/reload lifecycle verification
- Build: global_update() — pull all repos, build official plugins, install to desktop
2026-06-17 17:07:52 +08:00
mirivlad 9bb35a9fd0 fix: add workspace capability name check to smoke, clean up tracked build artifacts 2026-06-17 16:32:08 +08:00
mirivlad 67345a194a fix: vault/workspace lifecycle — CreateVault creates workspace, SetCurrentVault loads workspace, ReloadPlugins keeps workspace capability, recursive tree rendering 2026-06-17 14:26:49 +08:00
mirivlad 5fa2c0ddf9 docs: add workspace capability documentation 2026-06-17 12:24:12 +08:00
mirivlad 5c9ae7f93b feat: add workspace/cases core capability 2026-06-17 12:22:52 +08:00
mirivlad 6eecf5d005 fix: OpenVault now looks for vault.json inside VerstakVault/ subdirectory 2026-06-17 10:10:39 +08:00
mirivlad 252d075f9b fix: register OnStartup callback for Wails context initialization 2026-06-17 09:44:23 +08:00
mirivlad ffb3446cc3 feat: native directory picker for vault selection 2026-06-17 09:13:09 +08:00
mirivlad dd199f38ee fix: remove legacy config migration — new Verstak starts clean 2026-06-17 08:56:17 +08:00
mirivlad e9758ec1b5 feat: add legacy config migration + test 2026-06-17 08:23:25 +08:00
mirivlad ca089a82e9 docs: deduplicate sections, add UI layout and milestone 4b 2026-06-17 07:33:36 +08:00
mirivlad 7530e21dfd feat: ui completion — VaultSelection, Sidebar navigation, layout fixes 2026-06-17 07:28:00 +08:00
mirivlad 6202157cbf docs: update PLUGIN_RUNTIME.md with app settings, vault plugin state, first run flow 2026-06-17 04:22:16 +08:00
mirivlad a6f9e85f13 feat(m4b): add vault selection UI, enable/disable toggle, missing-installed UI
- Add VaultSelection.svelte: first-run vault create/open/recent UI
- Update App.svelte: vault check on startup, show VaultSelection when needed
- Update PluginCard.svelte: enable/disable buttons, vault state awareness
- Update PluginManager.svelte: enable/disable handlers, missing-installed section
- Add SetCurrentVault Wails API binding
- Add RecordDesiredPlugin Wails API binding
- Record desired plugins on discovery (only when vault open)
- Fix addRecent: remove duplicate sort, clean up unused import
- Update smoke-platform.sh: enable/disable lifecycle test
- Add runEnableDisableTest: vault create/open, disable/enable, plugins.json verify
2026-06-17 04:19:13 +08:00
mirivlad c8d2560bb2 docs: update plugin runtime doc with app settings + vault plugin state 2026-06-17 03:40:05 +08:00
mirivlad 04dbfa056e feat: add app settings, vault plugin state, and first-run vault selection
- internal/core/appsettings/ — app settings manager (~/.config/verstak/config.json)
- internal/core/pluginstate/ — vault plugin state (.verstak/plugins.json)
- internal/api/app.go — Wails bindings for app settings + plugin state
- main.go — init app settings, auto-open vault, init plugin state, disabled plugin filtering
- Plugin state: enable/disable, desired plugins, missing-installed tracking
- App settings: currentVaultPath, recentVaults, theme, devMode, windowState
2026-06-17 03:37:15 +08:00
mirivlad c0ea1972f6 fix: improve install-dev-plugins.sh cleanup + smoke-platform settingsPanel check 2026-06-17 03:06:50 +08:00
mirivlad ca7eb79a40 feat: add plugin UI host (sidebar, view container, settings panel) + storage API
- internal/core/storage/api.go — plugin namespace JSON storage (settings/data/cache)
- internal/core/storage/api_test.go — 8 tests (write/read, path traversal, atomic)
- internal/api/app.go — Wails bindings for storage (Read/WritePluginSettings, Read/WritePluginDataJSON)
- main.go — initialize storage service, pass to NewApp
- Sidebar.svelte — plugin sidebar items from contributions (filtered by ui.register)
- ViewContainer.svelte — plugin view host with degraded status
- PluginCard.svelte — Settings button + permission warnings
- PluginManager.svelte — settings panel modal with test form
- App.svelte — integrated sidebar + view container layout
2026-06-17 03:01:37 +08:00
mirivlad 70d4c75d7e fix: resolve plugin path relative to binary location + copy plugins in build
- main.go: use filepath.Dir(os.Args[0]) instead of ./plugins for discovery
- api/app.go: same fix for ReloadPlugins
- build.sh: copy plugins/ to build/bin/plugins/ after wails build
- Fixes: plugin not found when binary launched from different CWD
2026-06-16 21:00:44 +08:00
mirivlad fa52a0bfc3 docs: update plugin runtime for vault capability 2026-06-16 20:43:55 +08:00
mirivlad d7da8b4ee3 feat: add vault status to Plugin Manager UI 2026-06-16 20:40:00 +08:00
mirivlad d6793e8695 feat: add core vault layer with capability registration 2026-06-16 20:37:48 +08:00
mirivlad 6832b01b23 fix: show core capabilities in registry, add degraded text + contribution counts 2026-06-16 17:52:50 +08:00
mirivlad 47530559bb test: add plugin lifecycle tests (core caps, degraded, disabled, reload) 2026-06-16 17:46:24 +08:00
mirivlad b9e08f7c9d docs: add plugin runtime documentation 2026-06-16 17:43:59 +08:00
mirivlad dd3a5f8ff5 fix: register core capabilities + plugin lifecycle before discovery
Core fix: core capabilities (plugin-manager, capability-registry,
contribution-registry, permissions, events) now registered BEFORE plugin
discovery, so plugins can resolve required capabilities at load time.

Changes:
- main.go: register 5 core capabilities before DiscoverPlugins();
  add plugin lifecycle (register caps, resolve required/optional,
  set status LOADED/DEGRADED/MISSING_REQUIRED, register contributions)
- api/app.go: ReloadPlugins now re-registers core + plugin capabilities
- capability/registry.go: add UnregisterAll() for reload
- cmd/smoke-platform/main.go: verify core caps, required resolution,
  degraded status, total caps >= 7
- PluginCard.svelte: remove ✗ on optional-missing, show degraded info
- PluginManager.svelte: preserved (counter shows core+plugin caps)

Rule: optional missing => DEGRADED (not FAILED).
Required missing => MISSING_REQUIRED_CAPABILITY.

Verified: smoke-platform , test.sh (10/10) , check.sh 
2026-06-16 17:12:46 +08:00
mirivlad 1c75389535 feat: dev plugin install flow + smoke-platform
- .gitignore: add plugins/ (local dev install, never committed)
- scripts/install-dev-plugins.sh: install dist package from ../verstak-official-plugins/dist/ into ./plugins/
- scripts/smoke-platform.sh: headless verification of plugin discovery, manifest, capabilities, contributions
- cmd/smoke-platform/main.go: Go smoke command for headless plugin verification
- docs/DEV_PLUGINS.md: dev plugin flow documentation
2026-06-16 16:46:00 +08:00
mirivlad d72ebeb7ec fix: PluginManager — proper await with real Wails imports; no dead code, no safety timer 2026-06-16 15:39:30 +08:00
mirivlad 1d20b833f2 hotfix: PluginManager infinite loading
Root cause: Wails v2 + webkit2gtk-4.1 production bridge deadlock.
await window.go.api.App.Xxx() deadlocks the JS event loop — Promise
never settles, finally never runs, loading=true forever.

Fix:
- Replace await with .then() + fallback to window.runtime.Call()
- Separated GetPlugins/GetCapabilities/GetPermissions (no Promise.all)
- Safety timer: force loading=false after 10s regardless of bridge
- All UI states: loading → error (with retry) → empty/list + badges
- Go: tilde expansion (~/.config/verstak/plugins → /home/mirivlad/...)
- Go: diagnostic logging in DiscoverPlugins + API methods
- Tests: 11 headless Go tests for DiscoverPlugins
2026-06-16 14:51:31 +08:00
mirivlad 3c613f0e44 hotfix: plugin manager infinite loading
- frontend: RPC timeout (8s), try/catch/finally on reload, proper UI
  states (loading/error/empty/list)
- frontend: reload() now sets loading=true, catches errors
- backend: tilde expansion (~/.config/verstak/plugins → /home/mirivlad/...)
- backend: ReloadPlugins returns diagnostics (count, summary string)
- backend: diagnostic logging in DiscoverPlugins (start/dirs/entries/results)
- backend: FormatDiscoverySummary helper
- testing: 11 headless tests for DiscoverPlugins (empty, missing, valid,
  broken JSON, duplicate ID, multiple dirs, nonexistent mix)
2026-06-16 13:52:49 +08:00
mirivlad e39e249556 fix: auto-detect webkit2gtk-4.1 with -tags webkit2_41, show binary path 2026-06-16 13:38:51 +08:00
mirivlad 291f4224fa fix: build.sh auto-installs wails if missing 2026-06-16 12:34:25 +08:00