diff --git a/README.md b/README.md index 611abb1..675db35 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,29 @@ Jason's dotfiles ================ + +This repository stores personal shell/editor/tooling config and Windows setup assets. + +## Windows backups + +Use `windows/backup/export.ps1` to snapshot common Windows app and terminal config into this repo. + +```powershell +powershell -ExecutionPolicy Bypass -File .\windows\backup\export.ps1 +``` + +The script is safe to re-run. It only copies files that exist and skips missing targets. + +## Commit messages + +Use `docs/commit-message-guide.md` for commit message conventions in this repo. + +## Prompt snippets + +Reusable prompt snippets live in `docs/prompts/`. + +Use `scripts/oprompt.ps1` to print or copy one: + +```powershell +powershell -ExecutionPolicy Bypass -File .\scripts\oprompt.ps1 commit +powershell -ExecutionPolicy Bypass -File .\scripts\oprompt.ps1 pr-update -Copy +``` diff --git a/docs/commit-message-guide.md b/docs/commit-message-guide.md new file mode 100644 index 0000000..7404890 --- /dev/null +++ b/docs/commit-message-guide.md @@ -0,0 +1,74 @@ +# Commit Message Guide + +Use this guide for all commits in this repository. + +## Format + +Use Conventional Commits: + +`(optional-scope): ` + +Examples: + +- `feat(windows): add config export workflow and initial backups` +- `fix(verify): handle missing checksum argument` +- `docs(readme): clarify Windows backup steps` + +## Types + +- `feat`: new user-visible capability +- `fix`: bug fix +- `docs`: documentation-only change +- `refactor`: code restructure without behavior change +- `chore`: maintenance work (non-feature/non-fix) +- `test`: add or update tests +- `build`: build/dependency/tooling changes +- `ci`: CI pipeline/workflow changes +- `revert`: revert a previous commit + +## Subject line rules + +- Keep it concise (target <= 50 chars when practical) +- Use imperative mood (`add`, `update`, `remove`, `fix`) +- Capitalize only where natural (acronyms/proper nouns) +- Do not end with a period +- Focus on intent, not file-by-file mechanics + +## Body (when needed) + +Add a body for non-trivial changes. Explain: + +- Why the change was made +- Any important tradeoffs or constraints +- Follow-up notes for future readers + +Wrap body lines around ~72 chars for readability. + +## Scope guidance + +Use a scope when it improves clarity: + +- `windows`, `keyboard`, `backup`, `readme`, `home`, `verify` + +Skip scope if it adds noise. + +## Good vs bad + +Good: + +- `feat(backup): export winget package snapshot` +- `docs(windows): add backup workflow and usage` +- `fix(keyboard): make apply script idempotent` + +Bad: + +- `tweaked stuff` +- `updates` +- `fixed things` + +## Pre-commit checklist + +- Message matches the actual change +- No secrets included +- Diff is focused and reviewable +- Subject is clear without opening the diff diff --git a/docs/prompts/commit.md b/docs/prompts/commit.md new file mode 100644 index 0000000..e16870a --- /dev/null +++ b/docs/prompts/commit.md @@ -0,0 +1,9 @@ +Use `docs/commit-message-guide.md` as the standard for this commit. + +Tasks: +- Review staged and unstaged changes. +- Propose 2-3 commit message options in Conventional Commit format. +- Recommend one message and explain why it best captures intent. +- If there are possible secrets in changed files, call them out before committing. + +Keep output concise and actionable. diff --git a/docs/prompts/pr-update.md b/docs/prompts/pr-update.md new file mode 100644 index 0000000..ca68866 --- /dev/null +++ b/docs/prompts/pr-update.md @@ -0,0 +1,9 @@ +Review the current branch diff against base and draft a PR update. + +Tasks: +- Summarize what changed since the last PR update. +- Propose a PR title that reflects current scope. +- Write a PR body with a `## Summary` section and 3-6 bullets. +- Flag risky or machine-specific changes that reviewers should focus on. + +Keep wording clear for reviewers scanning quickly. diff --git a/home/.config/komorebi-setup-notes.txt b/home/.config/komorebi-setup-notes.txt new file mode 100644 index 0000000..4e61a07 --- /dev/null +++ b/home/.config/komorebi-setup-notes.txt @@ -0,0 +1,62 @@ +Komorebi Setup Notes + +Core startup +- C:\Users\jason\.config\start-komorebi.cmd + Starts komorebi, bars, whkd, and workspace-cycle.ahk. + Includes retry logic for komorebi startup timing. + +Scheduled tasks +- StartKomorebi + Trigger: logon (delayed) + Action: cmd.exe /c "C:\Users\jason\.config\start-komorebi.cmd" +- StartKomorebiOnUnlock + Trigger: unlock event + Action: cmd.exe /c "C:\Users\jason\.config\start-komorebi.cmd" + +Hotkeys +- C:\Users\jason\.config\whkdrc + Main window-management hotkeys (focus/move/stack/resize/layout/etc). + Workspace number bindings are intentionally handled by AutoHotkey, not whkd. + +Why AutoHotkey handles workspace number bindings +- In this setup, whkd reliably captures many window-management bindings, but + workspace-number style bindings (Alt+1..6 and related cycle combos) were + intermittently dropped after the first successful trigger. +- The komorebic commands and workspace scripts were verified to work when run + directly, so the issue was input-hook reliability for those specific hotkeys, + not command correctness. +- AutoHotkey v2 provided stable repeated capture for these workspace bindings, + so workspace focus/move/cycle keys were moved to workspace-cycle.ahk while + keeping the rest of the keymap in whkd. + +AutoHotkey workspace layer +- C:\Users\jason\.config\workspace-cycle.ahk + Reliable workspace hotkeys and ring cycling. + Key map: + - Alt+1..6 focus E1 E2 E3 I1 I2 I3 (adaptive) + - Alt+Shift+1..6 move E1 E2 E3 I1 I2 I3 (adaptive) + - Ctrl+Alt+7 cycle previous workspace in global ring + - Ctrl+Alt+8 cycle next workspace in global ring + +Workspace scripts +- C:\Users\jason\.config\workspace-ring.ps1 + Cycles workspaces previous/next. + Adaptive behavior for 1-monitor vs 2-monitor setups. + +- C:\Users\jason\.config\workspace-target.ps1 + Maps slot 1..6 to named workspaces. + - 2 monitors: E1 E2 E3 I1 I2 I3 + - 1 monitor: I1 I2 I3 I1 I2 I3 + +- C:\Users\jason\.config\workspace-reconcile.ps1 + Ensures workspace names exist/correct after startup or monitor reconnect. + Called by startup and periodically by workspace-cycle.ahk. + +Komorebi config files +- C:\Users\jason\komorebi.json +- C:\Users\jason\komorebi.bar.0.json +- C:\Users\jason\komorebi.bar.1.json + +If workspaces look wrong after monitor changes +1) Run: C:\Users\jason\.config\start-komorebi.cmd +2) If needed, run: powershell -ExecutionPolicy Bypass -File C:\Users\jason\.config\workspace-reconcile.ps1 diff --git a/home/.config/start-komorebi.cmd b/home/.config/start-komorebi.cmd new file mode 100644 index 0000000..94f4afb --- /dev/null +++ b/home/.config/start-komorebi.cmd @@ -0,0 +1,63 @@ +@echo off +setlocal + +set "LOG=%LOCALAPPDATA%\komorebi\startup.cmd.log" +echo %date% %time% Startup CMD begin>>"%LOG%" + +set "KOMOREBI_OK=0" +for /L %%A in (1,1,8) do ( + tasklist /FI "IMAGENAME eq komorebi.exe" | find /I "komorebi.exe" >nul + if not errorlevel 1 ( + set "KOMOREBI_OK=1" + echo %date% %time% komorebi.exe already running on attempt %%A>>"%LOG%" + goto :after_komorebi + ) + + echo %date% %time% Attempt %%A starting komorebi.exe>>"%LOG%" + powershell -NoProfile -Command "Start-Process -FilePath 'C:\Program Files\komorebi\bin\komorebi.exe' -WindowStyle Hidden" >nul 2>&1 + powershell -NoProfile -Command "Start-Sleep -Seconds 20" >nul 2>&1 + + tasklist /FI "IMAGENAME eq komorebi.exe" | find /I "komorebi.exe" >nul + if not errorlevel 1 ( + set "KOMOREBI_OK=1" + echo %date% %time% komorebi.exe started on attempt %%A>>"%LOG%" + goto :after_komorebi + ) +) + +:after_komorebi +if "%KOMOREBI_OK%"=="0" ( + echo %date% %time% komorebi.exe not detected after retries>>"%LOG%" +) + +powershell -NoProfile -Command "Start-Sleep -Seconds 4" >nul 2>&1 + +tasklist /FI "IMAGENAME eq komorebi-bar.exe" | find /I "komorebi-bar.exe" >nul +if errorlevel 1 ( + echo %date% %time% Starting bars>>"%LOG%" + powershell -NoProfile -Command "Start-Process -FilePath 'C:\Program Files\komorebi\bin\komorebi-bar.exe' -ArgumentList '-c \"%USERPROFILE%\komorebi.bar.0.json\"' -WindowStyle Hidden" >nul 2>&1 + powershell -NoProfile -Command "Start-Process -FilePath 'C:\Program Files\komorebi\bin\komorebi-bar.exe' -ArgumentList '-c \"%USERPROFILE%\komorebi.bar.1.json\"' -WindowStyle Hidden" >nul 2>&1 +) else ( + echo %date% %time% bar already running>>"%LOG%" +) + +powershell -NoProfile -ExecutionPolicy Bypass -File "C:\Users\jason\.config\workspace-reconcile.ps1" >nul 2>&1 +echo %date% %time% Reconciled workspace names>>"%LOG%" + +tasklist /FI "IMAGENAME eq whkd.exe" | find /I "whkd.exe" >nul +if errorlevel 1 ( + echo %date% %time% Starting whkd.exe>>"%LOG%" + powershell -NoProfile -Command "Start-Process -FilePath 'C:\Program Files\whkd\bin\whkd.exe' -WindowStyle Hidden" >nul 2>&1 +) else ( + echo %date% %time% whkd.exe already running>>"%LOG%" +) + +powershell -NoProfile -Command "$p = Get-CimInstance Win32_Process -Filter \"Name='AutoHotkey64.exe'\" | Where-Object { $_.CommandLine -like '*workspace-cycle.ahk*' }; if (-not $p) { Start-Process -FilePath 'C:\Program Files\AutoHotkey\v2\AutoHotkey64.exe' -ArgumentList '\"C:\Users\jason\.config\workspace-cycle.ahk\"' -WindowStyle Hidden; exit 10 } else { exit 0 }" >nul 2>&1 +if errorlevel 1 ( + echo %date% %time% Starting workspace-cycle.ahk>>"%LOG%" +) else ( + echo %date% %time% workspace-cycle.ahk already running>>"%LOG%" +) + +echo %date% %time% Startup CMD end>>"%LOG%" +endlocal diff --git a/home/.config/whkdrc b/home/.config/whkdrc new file mode 100644 index 0000000..a941287 --- /dev/null +++ b/home/.config/whkdrc @@ -0,0 +1,79 @@ +.shell powershell + +# Quick cheat-sheet +# alt + h/j/k/l focus window left/down/up/right +# alt + shift + h/j/k/l move window left/down/up/right +# alt + 1/2/3 focus workspace 1/2/3 on focused monitor +# alt + shift + 1/2/3 move window to workspace 1/2/3 on focused monitor +# alt + 4/5 focus monitor 1/2 +# alt + shift + 4/5 move window to monitor 1/2 +# alt + 6 focus last workspace +# alt + shift + 6 move window to last workspace +# alt + p toggle pause +# alt + i toggle shortcuts + +# Reload whkd configuration +# alt + o : taskkill /f /im whkd.exe && start /b whkd # if shell is cmd +alt + o : taskkill /f /im whkd.exe; Start-Process whkd -WindowStyle hidden # if shell is pwsh / powershell +alt + shift + o : komorebic reload-configuration + +alt + i : komorebic toggle-shortcuts + +# App shortcuts - these require shell to be pwsh / powershell +# The apps will be focused if open, or launched if not open +# alt + f : if ($wshell.AppActivate('Firefox') -eq $False) { start firefox } +# alt + b : if ($wshell.AppActivate('Chrome') -eq $False) { start chrome } + +alt + q : komorebic close +alt + m : komorebic minimize + +# Focus windows +alt + h : komorebic focus left +alt + j : komorebic focus down +alt + k : komorebic focus up +alt + l : komorebic focus right +alt + shift + oem_4 : komorebic cycle-focus previous # oem_4 is [ +alt + shift + oem_6 : komorebic cycle-focus next # oem_6 is ] + +# Move windows +alt + shift + h : komorebic move left +alt + shift + j : komorebic move down +alt + shift + k : komorebic move up +alt + shift + l : komorebic move right +alt + shift + return : komorebic promote + +# Stack windows +alt + left : komorebic stack left +alt + down : komorebic stack down +alt + up : komorebic stack up +alt + right : komorebic stack right +alt + oem_1 : komorebic unstack # oem_1 is ; +alt + oem_4 : komorebic cycle-stack previous # oem_4 is [ +alt + oem_6 : komorebic cycle-stack next # oem_6 is ] + +# Resize +alt + oem_plus : komorebic resize-axis horizontal increase +alt + oem_minus : komorebic resize-axis horizontal decrease +alt + shift + oem_plus : komorebic resize-axis vertical increase +alt + shift + oem_minus : komorebic resize-axis vertical decrease + +# Manipulate windows +alt + t : komorebic toggle-float +alt + shift + f : komorebic toggle-monocle + +# Window manager options +alt + shift + r : komorebic retile +alt + p : komorebic toggle-pause + +# Layouts +alt + x : komorebic flip-layout horizontal +alt + y : komorebic flip-layout vertical + +# Workspace focus (global order: E1 E2 E3 I1 I2 I3) +# Managed by AutoHotkey in workspace-cycle.ahk to avoid dropped hotkeys + +# Move windows to global workspace order (E1 E2 E3 I1 I2 I3) +# Managed by AutoHotkey in workspace-cycle.ahk to avoid dropped hotkeys + +# Restart Komorebi +alt + shift + c : komorebic stop --bar --whkd;sleep 3;komorebic start --bar --whkd; diff --git a/home/.config/workspace-cycle.ahk b/home/.config/workspace-cycle.ahk new file mode 100644 index 0000000..de5298e --- /dev/null +++ b/home/.config/workspace-cycle.ahk @@ -0,0 +1,60 @@ +#Requires AutoHotkey v2.0 +#SingleInstance Force +#UseHook True + +; Key map +; Alt+1..6 focus named workspaces: E1 E2 E3 I1 I2 I3 +; Alt+Shift+1..6 move window to: E1 E2 E3 I1 I2 I3 +; Ctrl+Alt+7 cycle previous workspace in global ring +; Ctrl+Alt+8 cycle next workspace in global ring + +RunKomorebic(args) { + exe := A_ProgramFiles . "\\komorebi\\bin\\komorebic.exe" + Run("`"" . exe . "`" " . args, , "Hide") +} + +RunWorkspace(action, slot) { + userProfile := EnvGet("USERPROFILE") + script := userProfile . "\\.config\\workspace-target.ps1" + q := Chr(34) + cmd := "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " . q . script . q . " -Action " . action . " -Slot " . slot + Run(A_WinDir . "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe " . cmd, , "Hide") +} + +RunReconcile() { + userProfile := EnvGet("USERPROFILE") + script := userProfile . "\\.config\\workspace-reconcile.ps1" + q := Chr(34) + cmd := "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " . q . script . q + Run(A_WinDir . "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe " . cmd, , "Hide") +} + +SetTimer(RunReconcile, 15000) +RunReconcile() + +RunCycle(direction) { + userProfile := EnvGet("USERPROFILE") + script := userProfile . "\\.config\\workspace-ring.ps1" + q := Chr(34) + cmd := "-NoProfile -ExecutionPolicy Bypass -WindowStyle Hidden -File " . q . script . q . " -Direction " . direction + Run(A_WinDir . "\\System32\\WindowsPowerShell\\v1.0\\powershell.exe " . cmd, , "Hide") +} + +#F7::RunCycle("previous") +#F8::RunCycle("next") +^!7::RunCycle("previous") +^!8::RunCycle("next") + +!1::RunWorkspace("focus", 1) +!2::RunWorkspace("focus", 2) +!3::RunWorkspace("focus", 3) +!4::RunWorkspace("focus", 4) +!5::RunWorkspace("focus", 5) +!6::RunWorkspace("focus", 6) + +!+1::RunWorkspace("move", 1) +!+2::RunWorkspace("move", 2) +!+3::RunWorkspace("move", 3) +!+4::RunWorkspace("move", 4) +!+5::RunWorkspace("move", 5) +!+6::RunWorkspace("move", 6) diff --git a/home/.config/workspace-cycle.ps1 b/home/.config/workspace-cycle.ps1 new file mode 100644 index 0000000..7fb05a0 --- /dev/null +++ b/home/.config/workspace-cycle.ps1 @@ -0,0 +1,52 @@ +param( + [ValidateSet('next','previous')] + [string]$Direction = 'next' +) + +$log = Join-Path $env:LOCALAPPDATA 'komorebi\workspace-cycle.log' + +function Write-Log { + param([string]$Message) + $ts = Get-Date -Format 'yyyy-MM-dd HH:mm:ss' + Add-Content -Path $log -Value "$ts $Message" +} + +try { + $state = komorebic state | ConvertFrom-Json + $monitor = [int]$state.monitors.focused + $workspace = [int]$state.monitors.elements[$monitor].workspaces.focused + + if ($Direction -eq 'next') { + if ($monitor -eq 0) { + if ($workspace -lt 2) { + komorebic focus-monitor-workspace 0 ($workspace + 1) + } else { + komorebic focus-monitor-workspace 1 0 + } + } else { + if ($workspace -lt 2) { + komorebic focus-monitor-workspace 1 ($workspace + 1) + } else { + komorebic focus-monitor-workspace 0 0 + } + } + } else { + if ($monitor -eq 1) { + if ($workspace -gt 0) { + komorebic focus-monitor-workspace 1 ($workspace - 1) + } else { + komorebic focus-monitor-workspace 0 2 + } + } else { + if ($workspace -gt 0) { + komorebic focus-monitor-workspace 0 ($workspace - 1) + } else { + komorebic focus-monitor-workspace 1 2 + } + } + } + + Write-Log "ok direction=$Direction monitor=$monitor workspace=$workspace" +} catch { + Write-Log "error direction=$Direction message=$($_.Exception.Message)" +} diff --git a/home/.config/workspace-reconcile.ps1 b/home/.config/workspace-reconcile.ps1 new file mode 100644 index 0000000..6d87d83 --- /dev/null +++ b/home/.config/workspace-reconcile.ps1 @@ -0,0 +1,9 @@ +$state = komorebic state | ConvertFrom-Json +$monitorCount = @($state.monitors.elements).Count + +if ($monitorCount -ge 2) { + komorebic ensure-named-workspaces 0 I1 I2 I3 + komorebic ensure-named-workspaces 1 E1 E2 E3 +} else { + komorebic ensure-named-workspaces 0 I1 I2 I3 +} diff --git a/home/.config/workspace-ring.ps1 b/home/.config/workspace-ring.ps1 new file mode 100644 index 0000000..d59d1d3 --- /dev/null +++ b/home/.config/workspace-ring.ps1 @@ -0,0 +1,63 @@ +param( + [ValidateSet('next','previous')] + [string]$Direction = 'next' +) + +$stateDir = Join-Path $env:LOCALAPPDATA 'komorebi' + +if (-not (Test-Path $stateDir)) { + New-Item -Path $stateDir -ItemType Directory | Out-Null +} + +$s = komorebic state | ConvertFrom-Json +$monitorCount = @($s.monitors.elements).Count +$monitor = [int]$s.monitors.focused +$workspace = [int]$s.monitors.elements[$monitor].workspaces.focused + +if ($monitorCount -lt 2) { + if ($Direction -eq 'next') { + if ($workspace -lt 2) { + komorebic focus-monitor-workspace 0 ($workspace + 1) + } else { + komorebic focus-monitor-workspace 0 0 + } + } else { + if ($workspace -gt 0) { + komorebic focus-monitor-workspace 0 ($workspace - 1) + } else { + komorebic focus-monitor-workspace 0 2 + } + } + + return +} + +if ($Direction -eq 'next') { + if ($monitor -eq 0) { + if ($workspace -lt 2) { + komorebic focus-monitor-workspace 0 ($workspace + 1) + } else { + komorebic focus-monitor-workspace 1 0 + } + } else { + if ($workspace -lt 2) { + komorebic focus-monitor-workspace 1 ($workspace + 1) + } else { + komorebic focus-monitor-workspace 0 0 + } + } +} else { + if ($monitor -eq 1) { + if ($workspace -gt 0) { + komorebic focus-monitor-workspace 1 ($workspace - 1) + } else { + komorebic focus-monitor-workspace 0 2 + } + } else { + if ($workspace -gt 0) { + komorebic focus-monitor-workspace 0 ($workspace - 1) + } else { + komorebic focus-monitor-workspace 1 2 + } + } +} diff --git a/home/.config/workspace-target.ps1 b/home/.config/workspace-target.ps1 new file mode 100644 index 0000000..a7a473e --- /dev/null +++ b/home/.config/workspace-target.ps1 @@ -0,0 +1,24 @@ +param( + [ValidateSet('focus','move')] + [string]$Action, + + [ValidateRange(1, 6)] + [int]$Slot +) + +$state = komorebic state | ConvertFrom-Json +$monitorCount = @($state.monitors.elements).Count + +if ($monitorCount -ge 2) { + $targets = @('E1', 'E2', 'E3', 'I1', 'I2', 'I3') +} else { + $targets = @('I1', 'I2', 'I3', 'I1', 'I2', 'I3') +} + +$target = $targets[$Slot - 1] + +if ($Action -eq 'focus') { + komorebic focus-named-workspace $target +} else { + komorebic move-to-named-workspace $target +} diff --git a/home/.wslgconfig b/home/.wslgconfig new file mode 100644 index 0000000..564c1ee --- /dev/null +++ b/home/.wslgconfig @@ -0,0 +1,4 @@ +[system-distro-env] +WESTON_RDP_HI_DPI_SCALING=true +WESTON_RDP_FRACTIONAL_HI_DPI_SCALING=true +WESTON_RDP_DEBUG_DESKTOP_SCALING_FACTOR=100 diff --git a/home/komorebi.bar.0.json b/home/komorebi.bar.0.json new file mode 100644 index 0000000..28f181d --- /dev/null +++ b/home/komorebi.bar.0.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.37/schema.bar.json", + "monitor": 0, + "font_family": "JetBrains Mono", + "theme": { + "palette": "Base16", + "name": "Ashes", + "accent": "Base0D" + }, + "left_widgets": [ + { + "Komorebi": { + "workspaces": { + "enable": true, + "hide_empty_workspaces": false + }, + "layout": { + "enable": true + }, + "focused_window": { + "enable": true, + "show_icon": true + } + } + } + ], + "right_widgets": [ + { + "Update": { + "enable": true + } + }, + { + "Media": { + "enable": true + } + }, + { + "Storage": { + "enable": true + } + }, + { + "Memory": { + "enable": true + } + }, + { + "Network": { + "enable": true, + "show_total_data_transmitted": true, + "show_network_activity": true + } + }, + { + "Date": { + "enable": true, + "format": "DayDateMonthYear" + } + }, + { + "Time": { + "enable": true, + "format": "TwentyFourHour" + } + }, + { + "Battery": { + "enable": true + } + } + ] +} diff --git a/home/komorebi.bar.1.json b/home/komorebi.bar.1.json new file mode 100644 index 0000000..a912515 --- /dev/null +++ b/home/komorebi.bar.1.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.37/schema.bar.json", + "monitor": 1, + "font_family": "JetBrains Mono", + "theme": { + "palette": "Base16", + "name": "Ashes", + "accent": "Base0D" + }, + "left_widgets": [ + { + "Komorebi": { + "workspaces": { + "enable": true, + "hide_empty_workspaces": false + }, + "layout": { + "enable": true + }, + "focused_window": { + "enable": true, + "show_icon": true + } + } + } + ], + "right_widgets": [ + { + "Update": { + "enable": true + } + }, + { + "Media": { + "enable": true + } + }, + { + "Storage": { + "enable": true + } + }, + { + "Memory": { + "enable": true + } + }, + { + "Network": { + "enable": true, + "show_total_data_transmitted": true, + "show_network_activity": true + } + }, + { + "Date": { + "enable": true, + "format": "DayDateMonthYear" + } + }, + { + "Time": { + "enable": true, + "format": "TwentyFourHour" + } + }, + { + "Battery": { + "enable": true + } + } + ] +} diff --git a/home/komorebi.json b/home/komorebi.json new file mode 100644 index 0000000..541732a --- /dev/null +++ b/home/komorebi.json @@ -0,0 +1,60 @@ +{ + "$schema": "https://raw.githubusercontent.com/LGUG2Z/komorebi/v0.1.37/schema.json", + "app_specific_configuration_path": "$Env:USERPROFILE/applications.json", + "window_hiding_behaviour": "Cloak", + "cross_monitor_move_behaviour": "Insert", + "default_workspace_padding": 10, + "default_container_padding": 10, + "display_index_preferences": { + "0": "BOE095F-4&35609429&0&UID8388688", + "1": "VSCC336-4&35609429&0&UID53320" + }, + + "border": true, + "border_width": 8, + "border_offset": -1, + "theme": { + "palette": "Base16", + "name": "Ashes", + "unfocused_border": "Base03", + "bar_accent": "Base0D" + }, + "bar_configurations": [ + "$Env:USERPROFILE/komorebi.bar.0.json", + "$Env:USERPROFILE/komorebi.bar.1.json" + ], + "monitors": [ + { + "workspaces": [ + { + "name": "I1", + "layout": "BSP" + }, + { + "name": "I2", + "layout": "VerticalStack" + }, + { + "name": "I3", + "layout": "HorizontalStack" + } + ] + }, + { + "workspaces": [ + { + "name": "E1", + "layout": "BSP" + }, + { + "name": "E2", + "layout": "VerticalStack" + }, + { + "name": "E3", + "layout": "HorizontalStack" + } + ] + } + ] +} diff --git a/scripts/oprompt.ps1 b/scripts/oprompt.ps1 new file mode 100644 index 0000000..ce1b72e --- /dev/null +++ b/scripts/oprompt.ps1 @@ -0,0 +1,26 @@ +[CmdletBinding()] +param( + [Parameter(Mandatory = $true, Position = 0)] + [string]$Name, + + [switch]$Copy +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$repoRoot = Resolve-Path (Join-Path $PSScriptRoot "..") +$promptPath = Join-Path $repoRoot "docs\prompts\$Name.md" + +if (-not (Test-Path -LiteralPath $promptPath)) { + throw "Prompt not found: $promptPath" +} + +$content = Get-Content -LiteralPath $promptPath -Raw + +if ($Copy) { + Set-Clipboard -Value $content + Write-Host "Copied prompt '$Name' to clipboard." +} else { + Write-Output $content +} diff --git a/windows/backup/README.md b/windows/backup/README.md new file mode 100644 index 0000000..58f142c --- /dev/null +++ b/windows/backup/README.md @@ -0,0 +1,25 @@ +# Windows backup workflow + +This folder contains scripts and exported artifacts for backing up machine-specific Windows config. + +## Export + +Run from repo root: + +```powershell +powershell -ExecutionPolicy Bypass -File .\windows\backup\export.ps1 +``` + +The export script currently captures these targets when present: + +- PowerShell 7 profile (`Documents\PowerShell\Microsoft.PowerShell_profile.ps1`) +- Windows PowerShell profile (`Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1`) +- Windows Terminal settings (`settings.json` for stable/preview packages) +- VS Code user settings and keybindings +- `winget` package export (`windows/backup/winget-packages.json`) + +## Notes + +- Missing files are skipped. +- Existing repo copies are overwritten with the latest local version. +- Review diffs before committing in case local app settings include machine-specific values you do not want to track. diff --git a/windows/backup/export.ps1 b/windows/backup/export.ps1 new file mode 100644 index 0000000..6a883c5 --- /dev/null +++ b/windows/backup/export.ps1 @@ -0,0 +1,85 @@ +[CmdletBinding()] +param( + [string]$RepoRoot +) + +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +function Copy-IfExists { + param( + [Parameter(Mandatory = $true)] + [string]$Source, + + [Parameter(Mandatory = $true)] + [string]$Destination + ) + + if (-not (Test-Path -LiteralPath $Source)) { + Write-Host "skip $Source" + return + } + + $parent = Split-Path -Path $Destination -Parent + if (-not (Test-Path -LiteralPath $parent)) { + New-Item -ItemType Directory -Path $parent -Force | Out-Null + } + + Copy-Item -LiteralPath $Source -Destination $Destination -Force + Write-Host "copy $Source -> $Destination" +} + +if ([string]::IsNullOrWhiteSpace($RepoRoot)) { + $RepoRoot = Join-Path $PSScriptRoot "..\.." +} + +$repoRootPath = (Resolve-Path -LiteralPath $RepoRoot).Path + +$targets = @( + @{ + Source = Join-Path $HOME "Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + Destination = Join-Path $repoRootPath "home\Documents\PowerShell\Microsoft.PowerShell_profile.ps1" + }, + @{ + Source = Join-Path $HOME "Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" + Destination = Join-Path $repoRootPath "home\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1" + }, + @{ + Source = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json" + Destination = Join-Path $repoRootPath "windows\terminal\settings.json" + }, + @{ + Source = Join-Path $env:LOCALAPPDATA "Packages\Microsoft.WindowsTerminalPreview_8wekyb3d8bbwe\LocalState\settings.json" + Destination = Join-Path $repoRootPath "windows\terminal\settings.preview.json" + }, + @{ + Source = Join-Path $env:APPDATA "Code\User\settings.json" + Destination = Join-Path $repoRootPath "windows\vscode\settings.json" + }, + @{ + Source = Join-Path $env:APPDATA "Code\User\keybindings.json" + Destination = Join-Path $repoRootPath "windows\vscode\keybindings.json" + } +) + +Write-Host "Repo root: $repoRootPath" + +foreach ($target in $targets) { + Copy-IfExists -Source $target.Source -Destination $target.Destination +} + +$wingetOutput = Join-Path $repoRootPath "windows\backup\winget-packages.json" + +if (Get-Command winget -ErrorAction SilentlyContinue) { + $wingetParent = Split-Path -Path $wingetOutput -Parent + if (-not (Test-Path -LiteralPath $wingetParent)) { + New-Item -ItemType Directory -Path $wingetParent -Force | Out-Null + } + + winget export --output $wingetOutput --accept-source-agreements | Out-Null + Write-Host "export winget -> $wingetOutput" +} else { + Write-Host "skip winget export (winget not found)" +} + +Write-Host "Done." diff --git a/windows/backup/winget-packages.json b/windows/backup/winget-packages.json new file mode 100644 index 0000000..d064087 --- /dev/null +++ b/windows/backup/winget-packages.json @@ -0,0 +1,164 @@ +{ + "$schema" : "https://aka.ms/winget-packages.schema.2.0.json", + "CreationDate" : "2026-02-28T11:42:39.202-00:00", + "Sources" : + [ + { + "Packages" : + [ + { + "PackageIdentifier" : "AutoHotkey.AutoHotkey" + }, + { + "PackageIdentifier" : "Git.Git" + }, + { + "PackageIdentifier" : "Microsoft.OneDrive" + }, + { + "PackageIdentifier" : "Symless.Synergy" + }, + { + "PackageIdentifier" : "NordSecurity.NordVPN" + }, + { + "PackageIdentifier" : "LGUG2Z.whkd" + }, + { + "PackageIdentifier" : "calibre.calibre" + }, + { + "PackageIdentifier" : "Neovim.Neovim" + }, + { + "PackageIdentifier" : "Logitech.OptionsPlus" + }, + { + "PackageIdentifier" : "Adobe.Acrobat.Reader.64-bit" + }, + { + "PackageIdentifier" : "PaprikaApp.Paprika.3" + }, + { + "PackageIdentifier" : "LGUG2Z.komorebi" + }, + { + "PackageIdentifier" : "GitHub.cli" + }, + { + "PackageIdentifier" : "AirDroid.AirDroid" + }, + { + "PackageIdentifier" : "Brave.Brave" + }, + { + "PackageIdentifier" : "Google.Chrome.EXE" + }, + { + "PackageIdentifier" : "Microsoft.Edge" + }, + { + "PackageIdentifier" : "Avanquest.SodaPDFDesktop" + }, + { + "PackageIdentifier" : "WiresharkFoundation.Wireshark" + }, + { + "PackageIdentifier" : "Microsoft.VCRedist.2015+.x86" + }, + { + "PackageIdentifier" : "Samsung.DeX" + }, + { + "PackageIdentifier" : "Microsoft.DotNet.DesktopRuntime.8" + }, + { + "PackageIdentifier" : "Perforce.P4V" + }, + { + "PackageIdentifier" : "Microsoft.VCRedist.2008.x86" + }, + { + "PackageIdentifier" : "Microsoft.VCRedist.2010.x86" + }, + { + "PackageIdentifier" : "Microsoft.VCRedist.2015+.x64" + }, + { + "PackageIdentifier" : "Amazon.Kindle" + }, + { + "PackageIdentifier" : "Anaconda.Anaconda3" + }, + { + "PackageIdentifier" : "Discord.Discord" + }, + { + "PackageIdentifier" : "GIMP.GIMP.3" + }, + { + "PackageIdentifier" : "SST.opencode" + }, + { + "PackageIdentifier" : "Zoom.Zoom.EXE" + }, + { + "PackageIdentifier" : "reMarkable.reMarkableCompanionApp" + }, + { + "PackageIdentifier" : "Microsoft.VisualStudioCode" + }, + { + "PackageIdentifier" : "Microsoft.PowerToys" + }, + { + "PackageIdentifier" : "Canonical.Ubuntu" + }, + { + "PackageIdentifier" : "Microsoft.Teams" + }, + { + "PackageIdentifier" : "Microsoft.AppInstaller" + }, + { + "PackageIdentifier" : "Microsoft.UI.Xaml.2.7" + }, + { + "PackageIdentifier" : "Microsoft.UI.Xaml.2.8" + }, + { + "PackageIdentifier" : "Microsoft.VCLibs.Desktop.14" + }, + { + "PackageIdentifier" : "Microsoft.WindowsTerminal" + }, + { + "PackageIdentifier" : "Microsoft.WSL" + } + ], + "SourceDetails" : + { + "Argument" : "https://cdn.winget.microsoft.com/cache", + "Identifier" : "Microsoft.Winget.Source_8wekyb3d8bbwe", + "Name" : "winget", + "Type" : "Microsoft.PreIndexed.Package" + } + }, + { + "Packages" : + [ + { + "PackageIdentifier" : "9NQPSL29BFFF" + } + ], + "SourceDetails" : + { + "Argument" : "https://storeedgefd.dsx.mp.microsoft.com/v9.0", + "Identifier" : "StoreEdgeFD", + "Name" : "msstore", + "Type" : "Microsoft.Rest" + } + } + ], + "WinGetVersion" : "1.12.460" +} diff --git a/windows/keyboard/README.md b/windows/keyboard/README.md new file mode 100644 index 0000000..1b2c59b --- /dev/null +++ b/windows/keyboard/README.md @@ -0,0 +1,41 @@ +# Caps Lock to Ctrl (Scancode Map) + +This folder stores a machine-level keyboard remap for Windows: + +- Source key: Caps Lock +- Destination key: Left Ctrl + +Because this uses `Scancode Map` under `HKLM`, it applies system-wide, including elevated apps. + +## Files + +- `caps-to-ctrl.reg`: apply the remap +- `caps-to-ctrl-undo.reg`: remove the remap value +- `apply.ps1`: idempotent admin script to apply the remap + +## Apply + +Option 1 (script, recommended): + +```powershell +powershell -ExecutionPolicy Bypass -File .\windows\keyboard\apply.ps1 +``` + +Option 2 (manual): + +1. Right-click `caps-to-ctrl.reg` +2. Choose **Merge** +3. Approve UAC prompt + +## Undo + +1. Right-click `caps-to-ctrl-undo.reg` +2. Choose **Merge** +3. Approve UAC prompt + +## Notes + +- Requires Administrator privileges. +- Sign out or reboot after apply/undo. +- Registry path: `HKLM\SYSTEM\CurrentControlSet\Control\Keyboard Layout` +- Value name: `Scancode Map` (REG_BINARY) diff --git a/windows/keyboard/apply.ps1 b/windows/keyboard/apply.ps1 new file mode 100644 index 0000000..260fc72 --- /dev/null +++ b/windows/keyboard/apply.ps1 @@ -0,0 +1,31 @@ +$ErrorActionPreference = 'Stop' + +$targetPath = 'HKLM:\SYSTEM\CurrentControlSet\Control\Keyboard Layout' +$valueName = 'Scancode Map' +[byte[]]$desired = 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x1D,0x00,0x3A,0x00,0x00,0x00,0x00,0x00 + +$identity = [Security.Principal.WindowsIdentity]::GetCurrent() +$principal = [Security.Principal.WindowsPrincipal]::new($identity) +$isAdmin = $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) + +if (-not $isAdmin) { + Write-Error 'This script must be run as Administrator.' +} + +$current = (Get-ItemProperty -Path $targetPath -Name $valueName -ErrorAction SilentlyContinue).$valueName + +$isMatch = $false +if ($null -ne $current -and $current.Length -eq $desired.Length) { + $isMatch = [System.Linq.Enumerable]::SequenceEqual([byte[]]$current, $desired) +} + +if ($isMatch) { + Write-Host 'Caps Lock -> Left Ctrl remap already present. No changes made.' + Write-Host 'No reboot needed.' + exit 0 +} + +New-ItemProperty -Path $targetPath -Name $valueName -PropertyType Binary -Value $desired -Force | Out-Null + +Write-Host 'Applied Caps Lock -> Left Ctrl remap via Scancode Map.' +Write-Host 'Sign out or reboot is required for the remap to take effect.' diff --git a/windows/keyboard/caps-to-ctrl-undo.reg b/windows/keyboard/caps-to-ctrl-undo.reg new file mode 100644 index 0000000..b1f840c --- /dev/null +++ b/windows/keyboard/caps-to-ctrl-undo.reg @@ -0,0 +1,4 @@ +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout] +"Scancode Map"=- diff --git a/windows/keyboard/caps-to-ctrl.reg b/windows/keyboard/caps-to-ctrl.reg new file mode 100644 index 0000000..2237233 --- /dev/null +++ b/windows/keyboard/caps-to-ctrl.reg @@ -0,0 +1,4 @@ +Windows Registry Editor Version 5.00 + +[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout] +"Scancode Map"=hex:00,00,00,00,00,00,00,00,02,00,00,00,1d,00,3a,00,00,00,00,00 diff --git a/windows/terminal/settings.json b/windows/terminal/settings.json new file mode 100644 index 0000000..58a3343 --- /dev/null +++ b/windows/terminal/settings.json @@ -0,0 +1,106 @@ +{ + "$help": "https://aka.ms/terminal-documentation", + "$schema": "https://aka.ms/terminal-profiles-schema", + "actions": + [ + { + "command": "find", + "id": "User.find" + }, + { + "command": + { + "action": "splitPane", + "split": "auto", + "splitMode": "duplicate" + }, + "id": "User.splitPane.A6751878" + }, + { + "command": "paste", + "id": "User.paste" + }, + { + "command": + { + "action": "copy", + "singleLine": false + }, + "id": "User.copy.644BA8F2" + } + ], + "copyFormatting": "none", + "copyOnSelect": false, + "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", + "keybindings": + [ + { + "id": "User.splitPane.A6751878", + "keys": "alt+shift+d" + }, + { + "id": "User.paste", + "keys": "ctrl+v" + }, + { + "id": "User.find", + "keys": "ctrl+shift+f" + }, + { + "id": "User.copy.644BA8F2", + "keys": "ctrl+c" + } + ], + "newTabMenu": + [ + { + "type": "remainingProfiles" + } + ], + "profiles": + { + "defaults": {}, + "list": + [ + { + "commandline": "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", + "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}", + "hidden": false, + "name": "Windows PowerShell" + }, + { + "commandline": "%SystemRoot%\\System32\\cmd.exe", + "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}", + "hidden": false, + "name": "Command Prompt" + }, + { + "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}", + "hidden": false, + "name": "Azure Cloud Shell", + "source": "Windows.Terminal.Azure" + }, + { + "colorScheme": "Campbell", + "guid": "{51855cb2-8cce-5362-8f54-464b92b32386}", + "hidden": false, + "name": "Ubuntu", + "source": "CanonicalGroupLimited.Ubuntu_79rhkp1fndgsc" + }, + { + "guid": "{2c4de342-38b7-51cf-b940-2309a097f518}", + "hidden": true, + "name": "Ubuntu", + "source": "Windows.Terminal.Wsl" + }, + { + "guid": "{07b52e3e-de2c-5db4-bd2d-ba144ed6c273}", + "hidden": false, + "name": "Ubuntu-20.04", + "source": "Windows.Terminal.Wsl" + } + ] + }, + "schemes": [], + "themes": [] +} diff --git a/windows/vscode/settings.json b/windows/vscode/settings.json new file mode 100644 index 0000000..d66e5c5 --- /dev/null +++ b/windows/vscode/settings.json @@ -0,0 +1,3 @@ +{ + "workbench.colorTheme": "Default Dark Modern" +}