You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Creates BrowserWindow, system tray, registers global hotkey (Cmd/Ctrl+Shift+Space), defines all IPC handlers, manages app lifecycle (close-to-tray, single instance)
database.ts
SQLite layer: initializes DB, runs migrations, stores derived command index/cache plus library/auth/settings metadata, and performs batch sync transactions
github.ts
GitHub Device Flow auth, token encryption via safeStorage, GitHub API calls, and origin-backed library working-copy clone/sync flows
Preload (electron/preload/)
File
Purpose
index.ts
contextBridge.exposeInMainWorld('electronAPI', {...}) — typed wrappers around all IPC channels. Also declares Window.electronAPI global types
Shared (shared/)
File
Purpose
types.ts
Shared contracts for indexed commands, libraries, working-copy/origin metadata, manifests, sync results, and auth state (RemoteCommand remains as a legacy alias of LibraryCommand)
Vue Components (src/components/)
Component
Purpose
Uses IPC?
CommandModal.vue
Add/Edit command: language dropdown, tag autocomplete, routes to appropriate editor
No (emits to App.vue)
CodeEditor.vue
CodeMirror 6 wrapper for code languages; hot-swaps language via Compartment
No
MarkdownEditor.vue
CodeMirror 6 markdown editor with Bold/Italic/Link toolbar
window-shown — fired when global hotkey shows window; App.vue resets search + focuses input via onWindowShown(), which now returns an unsubscribe cleanup for remount/HMR safety
keep local-library command files as the canonical write target for create/edit/delete flows
rename the backing JSON file when a title change produces a new slug, but only to a safe unique path
preserve stable command-file identity and add regression coverage for rename and collision cases
Final notes:
electron/main/local-library.ts now re-slugs file-backed local command filenames on title changes and resolves collisions without regenerating the command-file id
local-library updates preserve the existing command metadata while moving the file to its new path before reindexing
regression coverage now locks rename-on-edit behavior for both direct renames and collision-safe fallback filenames
Issue #33: use shared export utility for bulk export
Plan:
Move export bundle assembly behind one shared utility so filtered export and bulk export produce the same filename and serialized payload shape.
Update App.vue to consume the shared export-preparation path instead of duplicating export save logic inline.
Add regression coverage for the shared filename/content path used by bulk export.
Final notes:
src/utils/importExport.ts now exposes prepareExportBundle() so export callers share bundle metadata, filename generation, and JSON serialization.
App.vue uses that shared path for both filtered export and bulk export, removing the bulk-only filename divergence.
Regression coverage verifies the shared filename/content path that bulk export now relies on.
Issue #29: rich text library attachments
Plan:
Extract rich text image payloads into library attachments on write instead of leaving them inline in command JSON.
Resolve attachment paths back to local file URLs when local libraries are indexed so the renderer can still edit and copy those commands.
Remove stale per-command attachments during saves and deletes.
Final notes:
electron/main/local-library.ts now rewrites rich text image data URIs to attachments/<command-id>/... paths when writing local-library command files.
Local-library indexing resolves those relative image paths back to file:// URLs before caching command HTML in SQLite for the renderer.
Attachment cleanup is command-scoped, so saves and deletes do not leave orphaned local-library image files behind.
Issue #34: batch IPC for import and bulk delete
Plan:
Add batch command mutation APIs so import and bulk delete stop doing one renderer-to-main round trip per command.
Use transactions for DB-backed command batches and a single library sync for file-backed local-library batches.
Update the preload typings, renderer flows, and regression coverage so success/failure accounting stays explicit.
Final notes:
Import replacement and bulk delete now use library:createCommands and library:deleteCommands instead of per-command IPC loops.
DB-backed batches run inside SQLite transactions, while local-library batches collapse to one sync pass per touched library.
Regression coverage now includes batch DB inserts/deletes and local-library batch create/delete flows.
IPC Channel Map
Database
Channel
Preload Method
Called From
db:getAllCommands
database.getAllCommands()
App.vue loadCommands()
db:updateCommand
database.updateCommand()
App.vue handleSaveCommand()
db:deleteCommand
database.deleteCommand()
App.vue deleteCommand()
db:addCommand
database.addCommand()
App.vue handleSaveCommand()
Clipboard
Channel
Preload Method
Called From
clipboard:writeText
clipboard.writeText()
SettingsModal (copy device code)
clipboard:write
clipboard.write()
App.vue (copy with HTML for rich text)
clipboard:readText
clipboard.readText()
Available, not currently used
File Operations
Channel
Preload Method
Called From
file:saveDialog
file.saveDialog()
App.vue export flow
file:openDialog
file.openDialog()
App.vue import flow
file:writeFile
file.writeFile()
App.vue export flow
file:readFile
file.readFile()
App.vue import flow
Window Controls
Channel
Preload Method
Called From
window:minimize
window.minimize()
App.vue title bar (Windows)
window:maximize
window.maximize()
App.vue title bar (Windows)
window:close
window.close()
App.vue title bar (Windows)
window:isMaximized
window.isMaximized()
App.vue maximize state
window:getPlatform
window.getPlatform()
Available (platform detected sync)
GitHub Auth
Channel
Preload Method
Called From
auth:login
auth.login()
SettingsModal
auth:pollLogin
auth.pollLogin()
SettingsModal (polling loop)
auth:logout
auth.logout()
SettingsModal
auth:getStatus
auth.getStatus()
SettingsModal on open
Remote Libraries
Channel
Preload Method
Called From
library:subscribe
library.subscribe()
SettingsModal
library:unsubscribe
library.unsubscribe()
SettingsModal
library:sync
library.sync()
SettingsModal
library:syncAll
library.syncAll()
SettingsModal
library:getAll
library.getAll()
SettingsModal on open
library:createCommands
library.createCommands(commands)
App.vue import flow
library:deleteCommands
library.deleteCommands(ids)
App.vue bulk delete + import replacement
library:browse
library.browse()
SettingsModal preview
Other
Channel
Preload Method
Called From
shell:openExternal
shell.openExternal()
DescriptionModal link clicks
dialog:showInputDialog
dialog.showInputDialog()
Available (superseded by VariableInputModal)
window-shown(push)
onWindowShown(cb) => cleanup
App.vue — resets UI on hotkey
Database Schema
-- Core table
commands (
id INTEGERPRIMARY KEY,
title TEXTNOT NULL,
body TEXTNOT NULL,
description TEXT DEFAULT '',
tags TEXT DEFAULT '[]', -- JSON array of strings
language TEXT DEFAULT 'plaintext',
source TEXTNOT NULL DEFAULT 'local', -- 'local' = legacy DB-only row, 'remote' = library-backed indexed row
library_id INTEGERREFERENCES libraries(id) ON DELETE CASCADE,
remote_path TEXT, -- relative file path inside the owning library
created_at TEXTNOT NULL,
updated_at TEXTNOT NULL
)
-- Library registry + sync/origin metadata
libraries (
id INTEGERPRIMARY KEY,
github_repo TEXTNOT NULL UNIQUE, -- repo/subpath for GitHub entries, absolute folder path for local entries
name TEXTNOT NULL,
description TEXT DEFAULT '',
last_synced_at TEXT,
last_synced_sha TEXT,
origin_url TEXT,
origin_ref TEXT,
manifest_path TEXT,
type TEXTNOT NULL DEFAULT 'github',
auto_sync INTEGERNOT NULL DEFAULT 0,
permission TEXTNOT NULL DEFAULT 'consumer',
created_at TEXTNOT NULL
)
-- Encrypted token storage
auth (
key TEXTPRIMARY KEY,
value TEXTNOT NULL
)
-- Indices
idx_commands_title ON commands(title)
idx_commands_updated_at ON commands(updated_at DESC)
idx_commands_library_id ON commands(library_id)
idx_commands_source ON commands(source)