Skip to content

chore: .gitignore for VCS internals, node_modules and build output - #42

Closed
Jemo69 wants to merge 35 commits into
typecraft-dev:mainfrom
Jemo69:main
Closed

Jemo69 wants to merge 35 commits into
typecraft-dev:mainfrom
Jemo69:main

Conversation

@Jemo69

@Jemo69 Jemo69 commented Oct 27, 2026

Copy link
Copy Markdown

No description provided.

Jemo69 added 30 commits October 24, 2026 11:08
…ervices

Port of the Omarchy Quickshell build to Windows as an Electron app:
- plugin/core runs unchanged (ranker, frecency, calculator, root search,
  schema, migrate, rpc); Paths gains resolveWindows, Schema the Windows
  config keys (hotkey, fontFamily, agentCommand, gapsOut, cornerRadius)
- ui/: px-for-px DOM port of plugin/ui (LauncherWindow state machine,
  ResultRow, ActionPanel, InfoPanel, Alert, KeyHint, PointerMoveGate)
- src/theme/: port of omarchy-theme-color/-set-templates and the
  Color/Style/Border singletons; Tokyo Night bundled through the real
  shell.toml.tpl, omarchy.ttf + JetBrainsMono Nerd Font for exact glyphs
- src/: JsonStore, CalculatorData (ECB rates + Intl zones), Start Menu
  app library, backend RPC surface, host adapters
- main.js: overlay window on the cursor's monitor, Alt+Space hotkey,
  named-pipe CLI, paste via keybd_event, toast HUDs
- bin/oma-cast.ps1: toggle/show/hide/run/call/doctor/install
- tests: theme golden values, store migrations, backend round-trips
The bash/Omarchy-tooling preflight tests have nothing to exercise on a
Windows runner (the port's hand-off is covered by electron's backend
tests). TEST_RUNNER lets forks without the WarpBuild app use
ubuntu-latest.
Windows keeps foreground activation locked: a freshly shown frameless
window is often painted without keyboard focus, so keystrokes stayed in
the previous app. Now show() grabs focus in three steps: moveTop+focus,
a retry after Windows answers, and — if still refused — the documented
foreground-lock break (dummy ALT keybd_event + SetForegroundWindow with
the real HWND) via PowerShell. The renderer double-checks with
document.hasFocus() and requests the steal itself if needed.

Also: everything now logs to %LOCALAPPDATA%\oma-cast\logs\main.log
(main + renderer console, hotkey registration state, focus transitions),
so a misbehaving install can be diagnosed from one file.
Icons: Chromium memory-maps fonts and mmap cannot pass through the
asar patch, so every bundled Nerd Font glyph rendered as tofu in the
packaged exe. electron-builder asarUnpack now puts assets/ on disk as
real files (app.asar.unpacked) while the file:// URLs keep resolving;
the CI layout check asserts both.

- File search (SPEC §8.6 slice): FileSearch.js (name-then-path-then-
  recency matching, shared), file-index.js (chunked home walk, 100k
  cap, excludes, hidden opt-in, disk cache, 10-min re-walk), a Files
  section after Results, Open / Reveal in Explorer / Copy Path
- unduck.link as the third web fallback + quicklink (q={query})
- Settings view (SettingsView.js): every window/hotkey/search/calc
  setting as a cycling row; hotkey writes config.json and
  re-registers immediately — the Phase-2 stub closed here [D]
- Kill Process: PowerShell snapshot sorted by working set, destructive
  confirm, synchronous taskkill /F, Reveal + Copy PID
- placeholders, copy shortcuts (Ctrl+Shift+C covers path/pid), loading
  empty state; docs updated
The Windows equivalents of Omarchy's system actions: shutdown/restart
go through the same destructive confirmation alert, then schedule
shutdown.exe /s|/r /t 15 — the success toast carries a Cancel action
(system.cancelPowerShutdown → shutdown /a) for the whole 15 seconds.
Sleep confirms nothing, closes the launcher first, and suspends via
rundll32 SetSuspendState 400 ms after the unmap (hibernates instead if
hibernation is enabled — Windows quirk, documented). Power actions skip
frecency so they never crowd Suggestions. All three glyphs verified in
the bundled Nerd Font.
The publish step wrote a fixed body, so v0.1.1 shipped with v0.1.0's
'first release' text and never mentioned Shut Down / Restart / Sleep.
Now the notes append the commit subjects since the previous tag (full
checkout for history), an existing release's notes are refreshed on a
re-run, and the stale v0.1.0 default on workflow_dispatch is gone.
A pushed "Windows Settings" view (electron/src/windows-settings.js):
71 Settings-app deep links grouped by category (System … Windows
Update), filtered by title/category/URI/keywords, ↵ opens the page
through shell.openExternal with a HUD line. It also leads the in-app
Settings view, so "settings" reaches themes, display and Windows Update
without leaving the launcher. Rows carry the standard Open action and a
Setting/Category/URI about panel.

Built-ins now carry platform: "windows"; plugin/Backend.qml skips them
on the shell side, which also drops Kill Process from a build where
nothing implements its view. backend.VERSION now reads
electron/package.json, so doctor/system.info cannot drift from the
installer (it still said 0.1.0).

Tests: page-table invariants (no duplicates, sections cover every
page), the builtin glyph/push, the Settings-view lead row, filtering,
open dispatch and the about panel.
Caret: style.css ports LauncherWindow.qml's SequentialAnimation on the
caret's opacity — 530 ms solid, 530 ms hidden, step-end, on #caret and
the argument pills. The README promised this blink; the port never had
the animation.

Icons: powershell.exe joins everything after -Command into one command
string, so the trailing linkPath/png arguments were appended to the last
statement of the extraction script, $args never bound and every Start
Menu icon silently failed — rows showed an empty icon column. The paths
are now interpolated into the script (PowerShell-quoted), a .lnk
resolves to its target before ExtractAssociatedIcon, URLs are encoded,
and a row with nothing extracted falls back to U+F2D0 instead of a
blank box.

Themes: the place for themes is %APPDATA%\oma-cast\themes\<name>\
colors.toml (electron/src/themes.js — bundled first, then the user's,
a directory with a colors.toml is a theme, optional per-theme
shell.toml override). config.json gains "theme"; the Theme row in the
Settings view lists what is on disk and cycles it, and the change goes
out as settings.configChanged so the renderer rebuilds the theme and
repaints in place. themes.list / themes.resolve RPCs for the CLI.
ui/app.js built the backend with paths/apps/host only, so `processes`
and `fileIndex` were null in the shipped app: the Kill Process view
filtered an empty array (no listing, no search) and the Files section
never appeared. The unit tests inject both services, which is why every
suite stayed green off-Windows.

The window now creates them and hands them over: a file index rooted at
fileSearchScopes (or home) with its cache under the cache dir, and a
process snapshot that excludes this pid plus anything running from
process.execPath — main, GPU and renderer all share the exe, so the
launcher can no longer list itself and be killed from its own view.

Also: host.onVisibility never called backend.visibility(), so a show
never refreshed exchange rates, re-scanned the Start Menu or re-walked
files when stale — it does now. Both PowerShell snapshot scripts force
[Console]::OutputEncoding to UTF-8 before emitting JSON, otherwise
non-ASCII names arrive in the OEM codepage.
The left-ellipsis CSS trick (direction: rtl + text-align: left) on
#query, .pill span and .panel-search span flips the paragraph direction,
so the bidi algorithm reorders anything whose first strong character is
not LTR: typing "1 rem to px" displayed "rem to px 1".

Text.ElideLeft is now a JS helper (electron/src/text.js): the cut
happens on the logical string — the front goes, the tail stays, "…"
marks the cut — and the elements stay LTR. Applied to the query, the
argument pills and the action-panel filter, so the elide matches Qt
instead of approximating it with CSS.

Same pass: the pill caret measured pill.clientWidth on a detached
element (always 0) and parked itself left of the text; it uses the width
it just set now.

Tests: elide order/room/mark/edge cases plus a guard that no
direction:rtl survives in the UI stylesheet.
The Omarchy token model (live QML singletons, the Windows theme engine,
colors.toml / shell.toml schemas, layout scaling, contrast) lives in
docs/THEME_SPEC.md; SPEC 10.4 keeps the pointer and the deltas that
matter for the plan, and the 15-field Raycast theme model stays as a
superseded reference.
…pps, switch to an open window

(1) Open at Login: a Settings row over config.json's openAtLogin; main
turns it into the real HKCU Run entry (app.setLoginItemSettings) at
launch and on every config change — the backend's config watch notifies
main too, so an edit by hand or by the CLI also lands. oma-cast.ps1
install now writes that key instead of planting a Startup shortcut, and
both drop the legacy .lnk so two entries can never race at login and
toggle the window open on the desktop.

(2) Focus hand-back: show maps with showInactive so a resident
PowerShell helper (ping / getfg / focus, ~10 ms warm instead of a 300 ms
spawn) can sample the window that had the foreground; hide hands it back
with SetForegroundWindow — only while we still hold focus, since on blur
the clicked window already won — and the paste path waits for the
hand-back so Ctrl+V lands there. A cold helper means no wait and stock
Windows behaviour: focus never waits on the capture.

(3) Missing apps (Notion): the scan covers both Desktops and Store/MSIX
apps (Get-StartApps, falling back to shell:AppsFolder — they ship no
.lnk anywhere); uwp: rows launch through explorer shell:AppsFolder\<AppID>
and show the generic window glyph. system.info.applications + the
doctor's applications line print the count so a short list is visible.

(4) Take me there: Enter on an app that already has a window switches to
it instead of spawning a second instance — exe name from the shortcut
target → Get-Process → MainWindowHandle → SW_RESTORE →
SetForegroundWindow through the helper's new app command. Main drops the
hand-back target on receipt, so the close that follows leaves the app
with focus, and the renderer's 2.5 s settle timer guarantees the launch
fallback can never be swallowed.

8 new tests; suites green (154 port / 104 core). CLAUDE.md status
updated — and carries the theme-spec table row from the docs commit.
actions/checkout on windows-latest checks out with core.autocrlf=true,
so main.js has CRLF there and /prevFh = null\n…/ matched nothing, while
the same suite passed on Linux. The pattern accepts \r?\n now — the rule
for file-content asserts: never anchor a bare \n across a line ending.
…real exe names

Live report: Enter still opens a second instance on the machine. Between
us and the answer were three blind spots plus two lookup holes:

- nothing was logged: main now logs every request and the helper's
  answer (app switch: X -> ok 1 / none / no answer) and the backend logs
  which exe it derived, asked or launched — both land in main.log.
- the handler whitelisted [A-Za-z0-9 ._+-]; any other character silently
  answered "launch". It sanitises line breaks and length instead.
- the helper had 1500 ms — a cold PowerShell spawn could blow the budget
  and time out into a duplicate; 2000 ms still settles inside the
  renderer's 2.5 s fallback.
- Store/MSIX rows never asked: the package family prefix is now the
  guess at the process name (Notion_…!App -> Notion); a wrong guess
  answers none and launches exactly as before.
- wrapper shortcuts (explorer/cmd/… targets, the real app lives in the
  arguments we do not parse) never ask — they would "find" the desktop.

Tests: the family-prefix branch both ways, the wrapper guard, the log line.
…y app switch answered err

Root-caused live on the Windows box (0.2.1; the log at
%LOCALAPPDATA%\State\oma-cast\logs\main.log): "app switch: Obsidian ->
err", "app switch: vivaldi -> err", then a launch. The lookup was fine;
the helper's type wasn't there.

A C# attribute covers only the NEXT declaration, so [DllImport] applied
to GetForegroundWindow() alone and Add-Type — warnings as errors —
refused the whole class. [Win32.Input] never existed: getfg/focus/app
all threw into the catch and printed err, and err reads as "not
running", so every Enter launched a duplicate. The same root cause had
killed the close hand-back (getfg always failed, prevFh was never
captured — zero "foreground before show" lines in the log) and the
one-shot foreground steal, which was doubly broken: it also passed its
HWND as a trailing -Command argument, which powershell.exe joins into
the script text instead of binding to $args — the apps.js lesson again.

- every extern carries its own [DllImport] (helper: six, steal: two)
- focusScript(hwnd) interpolates a validated integer handle; an
  unusable one logs and bails
- regression test: DllImport count == static extern count over main.js
  code (comments stripped) and no $args in code
- docs: logs live at %LOCALAPPDATA%\State\oma-cast\logs\main.log, cache
  at %LOCALAPPDATA%\Temp\oma-cast (resolveWindows mirrors XDG
  state/cache) — the paths in README and the release notes never
  existed, which is why the log took a find to locate

Proven on the box through the real helper, no desktop disruption:
ping/getfg/focus <fg>/app Obsidian -> pong / fg 330594 / ok 1 / ok 1,
an unknown name -> none, focusScript executed clean.
The launcher was a fullscreen transparent overlay, which paints the whole
monitor opaque black wherever compositing fails (VMs, RDP, some drivers).
It is now a card-sized window centered on the monitor under the cursor:
the renderer reports its card size after every layout and main resizes to
fit, so the desktop stays visible around the card.
Walk the Start Menu roots (not just Programs) and append the App Paths
registry (HKLM + HKCU) as a safety net, skipping rows whose exe a shortcut
already covers. Every scan logs its entry count next to the doctor line.
@Jemo69 Jemo69 closed this Oct 27, 2026
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