Sync config from arch

- hypr/apps.lua
- hypr/autostart.lua
- hypr/envs.lua
- hypr/hyprland.lua
- hypr/hyprsunset.conf
- hypr/input.lua
- hypr/looknfeel.lua
- hypr/omasettings.lua
- hypr/xdph.conf
- omarchy/branding/about.txt
- omarchy/branding/screensaver.txt
- omarchy/extensions/omarchy-menu.jsonc
- omarchy/hooks/battery-low.d/play-warning-sound.sample
- omarchy/hooks/font-set.d/show-font-notification.sample
- omarchy/hooks/post-boot.d/weather.sample
- omarchy/hooks/post-update.d/install-voxtype.hook
- omarchy/hooks/post-update.d/setup-agent.hook
- omarchy/hooks/post-update.d/setup-fingerprint.hook
- omarchy/hooks/post-update.d/show-update-notification.sample
- omarchy/hooks/pre-refresh-pacman.d/add-custom-repo.sample
- omarchy/hooks/theme-set.d/show-theme-notification.sample
- omarchy/shell.json
- omarchy/shell.toml
- omarchy/theme.name
- omarchy/themes/azure-glow/README.md
- omarchy/themes/azure-glow/alacritty.toml
- omarchy/themes/azure-glow/btop.theme
- omarchy/themes/azure-glow/hyprland.conf
- omarchy/themes/azure-glow/hyprlock.conf
- omarchy/themes/azure-glow/icons.theme
- … 269 more
This commit is contained in:
asepharyana
2026-09-23 15:19:12 +07:00
commit 1cdb82a76f
300 changed files with 78143 additions and 0 deletions
@@ -0,0 +1,329 @@
#!/usr/bin/env node
// Regression tests for the context-aware suggestion matcher in BitwardenModel.js.
//
// The matcher is heuristic and works from window titles alone, so it is easy to
// regress in both directions: too strict and the right login stops appearing,
// too loose and every .com item is suggested on every site. Run with:
//
// node tests/context-match.test.js
const fs = require("fs")
const path = require("path")
const src = fs.readFileSync(path.join(__dirname, "..", "BitwardenModel.js"), "utf8")
const Model = {}
new Function("exports", src.replace(/^\.pragma library\s*$/m, "") + `
exports.findContextualMatches = findContextualMatches
exports.cleanWindowContext = cleanWindowContext
exports.parseHost = parseHost
exports.parseAssociations = parseAssociations
exports.serializeAssociations = serializeAssociations
exports.recordAssociation = recordAssociation
exports.forgetAssociation = forgetAssociation
exports.isAssociated = isAssociated
exports.emptyAssociations = emptyAssociations
exports.MAX_TITLE_CHARS = MAX_TITLE_CHARS
exports.MAX_ASSOC_BYTES = MAX_ASSOC_BYTES
`)(Model)
const items = [
{ id: "1", name: "GitHub", uris: ["https://github.com"] },
{ id: "2", name: "Amazon", uris: ["https://www.amazon.com"] },
{ id: "3", name: "Home Assistant",uris: ["https://homeassistant.local:8123"] },
{ id: "4", name: "Google", uris: ["https://accounts.google.com"] },
{ id: "5", name: "Reddit", uris: ["https://reddit.com"] },
{ id: "6", name: "Proton Mail", uris: ["https://account.proton.me"] },
{ id: "7", name: "Cloudflare", uris: ["https://dash.cloudflare.com"] },
{ id: "8", name: "My Bank", uris: ["https://www.chase.com"] },
{ id: "9", name: "Netflix", uris: ["https://www.netflix.com"] },
{ id: "10", name: "Jellyfin", uris: ["http://192.168.1.50:8096"] },
{ id: "11", name: "GitHub (work)", uris: ["https://github.com"] },
{ id: "12", name: "BBC iPlayer", uris: ["https://www.bbc.co.uk"] },
{ id: "13", name: "Discord", uris: ["https://discord.com"] },
{ id: "14", name: "Slack", uris: ["https://acme.slack.com"] },
{ id: "15", name: "Spotify", uris: ["https://open.spotify.com"] },
{ id: "16", name: "Nextcloud", uris: ["https://cloud.example.org"] },
{ id: "17", name: "Router Admin", uris: ["http://192.168.1.1"] },
{ id: "18", name: "AWS Console", uris: ["https://console.aws.amazon.com"] },
]
// [window class, window title, expected suggestion names]
const cases = [
// Site name lives in the title but the domain does not -- the common case.
["chromium", "Settings – Home Assistant - Chromium", ["Home Assistant"]],
["chromium", "Reddit - Dive into anything - Chromium", ["Reddit"]],
["chromium", "Netflix - Chromium", ["Netflix"]],
["chromium", "Proton Mail - Chromium", ["Proton Mail"]],
["chromium", "Cloudflare Dashboard - Chromium", ["Cloudflare"]],
["chromium", "Chase Online - Credit Cards, Mortgages, Auto - Chromium", ["My Bank"]],
["chromium", "Jellyfin - Chromium", ["Jellyfin"]],
["chromium", "Files - Nextcloud - Chromium", ["Nextcloud"]],
["chromium", "Acme Corp Slack - Chromium", ["Slack"]],
["chromium", "Spotify – Web Player - Chromium", ["Spotify"]],
["chromium", "AWS Management Console - Chromium", ["AWS Console"]],
["firefox", "BBC iPlayer - Home — Mozilla Firefox", ["BBC iPlayer"]],
["chromium", "Discord | #general | My Server - Chromium", ["Discord"]],
// Sign-in prefixes, unread counters and browser branding are noise.
["firefox", "Sign in to GitHub · GitHub — Mozilla Firefox", ["GitHub", "GitHub (work)"]],
["chromium", "(3) Inbox (1,204) - me@gmail.com - Gmail - Chromium", ["Google"]],
// Brand alias: the title never says "google".
["chromium", "Gmail - Chromium", ["Google"]],
["chromium", "Untitled document - Google Docs - Chromium", ["Google"]],
// A domain in the title must not drag in every item sharing its TLD.
["chromium", "Amazon.com. Spend less. Smile more. - Chromium", ["Amazon", "AWS Console"]],
// Nothing identifiable: suggest nothing rather than guess.
["chromium", "New Tab - Chromium", []],
["chromium", "Sign in - Chromium", []],
["chromium", "How to fix config.json v1.2 errors - Stack Overflow - Chromium", []],
// Terminals: local shells describe a machine, not a credential.
["foot", "workstation: notes", []],
// ...and a remote host must not match a different domain sharing a label.
["foot", "ssh user@git.example.com", []],
// Native desktop apps match on window class.
["discord", "Discord | #general", ["Discord"]],
["spotify", "Spotify Premium", ["Spotify"]],
]
// A large vault of .com sites: a single site must not suggest all of them.
const floodItems = ["github","amazon","google","reddit","proton","cloudflare","chase",
"netflix","discord","slack","spotify","dropbox","twitch","ebay","paypal","stripe",
"linode","digitalocean","namecheap","fastmail","zoom","notion","figma","linear",
"vercel","heroku","atlassian","gitlab","bitbucket","sentry","datadog","okta",
"auth0","twilio","sendgrid","mailgun","shopify","squarespace","wordpress","medium"]
.map((b, i) => ({ id: String(i), name: b, uris: ["https://www." + b + ".com"] }))
let pass = 0
const failures = []
function check(label, ok, detail) {
if (ok) { pass++ } else { failures.push(label + "\n " + detail) }
}
const sshLike = { id: "ssh-public", name: "GitHub deploy key", typeCode: 5,
uris: ["https://github.com"], publicKey: "ssh-ed25519 AAAA" }
check("context suggestions exclude SSH public records",
Model.findContextualMatches(items.concat([sshLike]),
{ class: "chromium", title: "GitHub - Chromium", mapped: true }).matches.every(m => m.id !== "ssh-public"),
"SSH key leaked into contextual suggestions")
for (const [cls, title, expected] of cases) {
const got = Model.findContextualMatches(items, { class: cls, title, mapped: true })
.matches.map(m => m.name).sort()
check(`[${cls}] ${title}`,
JSON.stringify(got) === JSON.stringify(expected.slice().sort()),
`expected [${expected}] but got [${got}]`)
}
for (const [title, max] of [["Amazon.com. Spend less. Smile more. - Chromium", 1],
["Some Random Blog Post About Nothing - Chromium", 0]]) {
const got = Model.findContextualMatches(floodItems, { class: "chromium", title, mapped: true }).matches
check(`flood: ${title}`, got.length <= max,
`expected at most ${max} suggestion(s) from a 40-item vault, got ${got.length}: [${got.map(g => g.name)}]`)
}
// Hostname parsing feeds every domain comparison.
for (const [host, root, base] of [
["github.com", "github", "github.com"],
["dash.cloudflare.com", "cloudflare", "cloudflare.com"],
["www.bbc.co.uk", "bbc", "bbc.co.uk"],
["homeassistant.local", "homeassistant", "homeassistant.local"],
["console.aws.amazon.com", "amazon", "amazon.com"],
]) {
const p = Model.parseHost(host)
check(`parseHost(${host})`, p && p.rootName === root && p.baseDomain === base,
`expected root=${root} base=${base}, got root=${p && p.rootName} base=${p && p.baseDomain}`)
}
// The most recently focused non-shell client wins in a `hyprctl clients` list.
const clients = [
{ class: "quickshell", title: "shell", focusHistoryID: 0, mapped: true },
{ class: "chromium", title: "Netflix - Chromium", focusHistoryID: 1, mapped: true },
{ class: "foot", title: "workstation: notes", focusHistoryID: 2, mapped: true },
]
check("clients list picks most recent non-shell window",
Model.findContextualMatches(items, clients).matches.map(m => m.name).join() === "Netflix",
`got [${Model.findContextualMatches(items, clients).matches.map(m => m.name)}]`)
// ---------------------------------------------------------------------------
// Learned associations
// ---------------------------------------------------------------------------
// The case that no title heuristic can solve: an authentik portal on
// auth.example.xyz titled "Home - authentik". The title and the stored URL
// share no word at all.
// Named so that neither the name nor the URL shares a word with the page title.
const authentikItem = { id: "auth-1", name: "Personal SSO", uris: ["https://auth.example.xyz"] }
const withAuthentik = items.concat([authentikItem])
const authentikWindow = { class: "chromium", title: "Home - authentik - Chromium", mapped: true }
let assoc = Model.emptyAssociations()
check("authentik: unmatched before learning",
Model.findContextualMatches(withAuthentik, authentikWindow, assoc).matches.length === 0,
`got [${Model.findContextualMatches(withAuthentik, authentikWindow, assoc).matches.map(m => m.name)}]`)
// Pick the credential once while that window is active.
const ctx = Model.cleanWindowContext(authentikWindow)
assoc = Model.recordAssociation(assoc, ctx, authentikItem.id, "2026-08-20T00:00:00Z")
check("authentik: suggested after one pick",
Model.findContextualMatches(withAuthentik, authentikWindow, assoc).matches.map(m => m.id).join() === "auth-1",
`got [${Model.findContextualMatches(withAuthentik, authentikWindow, assoc).matches.map(m => m.name)}]`)
// Learning generalises across pages of the same site, which share the word.
check("authentik: generalises to another page of the same site",
Model.findContextualMatches(withAuthentik,
{ class: "chromium", title: "Applications - authentik - Chromium", mapped: true }, assoc)
.matches.map(m => m.id).join() === "auth-1",
"expected the learned item on a sibling page")
check("authentik: does not leak to unrelated sites",
Model.findContextualMatches(withAuthentik,
{ class: "chromium", title: "Netflix - Chromium", mapped: true }, assoc)
.matches.map(m => m.name).join() === "Netflix",
"a learned key must not fire on an unrelated title")
check("isAssociated reports the learned pair", Model.isAssociated(assoc, ctx, "auth-1"), "expected true")
// Last pick wins, so a key learned from the wrong page corrects itself.
const retargeted = Model.recordAssociation(assoc, ctx, "9", "2026-08-21T00:00:00Z")
check("re-picking retargets the key",
Model.findContextualMatches(withAuthentik, authentikWindow, retargeted).matches.map(m => m.id).join() === "9",
"expected the newly picked item to win")
// Explicit unlearn.
const forgotten = Model.forgetAssociation(assoc, ctx, "auth-1")
check("forgetting removes the suggestion",
Model.findContextualMatches(withAuthentik, authentikWindow, forgotten).matches.length === 0,
"expected no suggestions after forgetting")
// A learned item outranks a heuristic match on the same window.
let netflixAssoc = Model.recordAssociation(Model.emptyAssociations(),
Model.cleanWindowContext({ class: "chromium", title: "Netflix - Chromium", mapped: true }), "11")
check("learned item is ranked ahead of a heuristic match",
Model.findContextualMatches(items, { class: "chromium", title: "Netflix - Chromium", mapped: true }, netflixAssoc)
.matches[0].id === "11",
"expected the learned item first")
// Round-tripping through the on-disk format must preserve behaviour.
const roundTripped = Model.parseAssociations(Model.serializeAssociations(assoc))
check("associations survive a save/load round trip",
Model.findContextualMatches(withAuthentik, authentikWindow, roundTripped).matches.map(m => m.id).join() === "auth-1",
"expected the learned item after reload")
check("corrupt association file degrades to empty",
Model.parseAssociations("{{not json").keys && Object.keys(Model.parseAssociations("{{not json").keys).length === 0,
"expected an empty store")
const hostileAssociations = Model.parseAssociations(
'{"version":1,"keys":{"__proto__":{"polluted":true},"arbitrary":{"itemId":"x"},'
+ '"word:valid":{"itemId":"auth-1","weight":1,"count":2,"updated":"2026-08-24T00:00:00Z"}}}')
const copiedHostile = Model.recordAssociation(hostileAssociations, ctx, "auth-1", "2026-12-31T00:00:00Z")
check("association parsing drops keys outside the domain/app/word schema",
!Object.prototype.hasOwnProperty.call(hostileAssociations.keys, "__proto__")
&& !Object.prototype.hasOwnProperty.call(hostileAssociations.keys, "arbitrary")
&& Object.prototype.hasOwnProperty.call(hostileAssociations.keys, "word:valid"),
Object.keys(hostileAssociations.keys).join(","))
check("hostile association keys cannot become the prototype of a copied store",
copiedHostile.keys.polluted === undefined, JSON.stringify(copiedHostile.keys))
check("association entries without a bounded string item id are dropped",
Object.keys(Model.parseAssociations(
'{"version":1,"keys":{"word:bad":{"itemId":{}},"word:good":{"itemId":"x"}}}').keys).join()
=== "word:good",
"invalid item id survived")
check("unknown association schema versions fail closed",
Object.keys(Model.parseAssociations(
'{"version":999,"keys":{"word:old":{"itemId":"x"}}}').keys).length === 0,
"unknown schema was accepted")
// Suggestions must still work with no association store at all.
check("undefined associations are safe",
Model.findContextualMatches(items, { class: "chromium", title: "Netflix - Chromium", mapped: true })
.matches.map(m => m.name).join() === "Netflix",
"expected heuristics to work without a store")
// ---------------------------------------------------------------------------
// A window title is written by the page, not by the user
// ---------------------------------------------------------------------------
//
// Everything below is about one input: document.title, chosen by whatever the
// browser is pointed at, arriving here through hyprctl. It is read on every
// panel open, on the GUI thread, with the whole vault to compare it against.
// The title reaches the matcher clipped, so the per-item work the matcher does
// over it cannot be scaled up by the page.
const longTitle = "verylongword".repeat(6000)
const clippedCtx = Model.cleanWindowContext({ class: "chromium", title: longTitle, mapped: true })
check("a page-chosen title is clipped before matching",
clippedCtx.matchText.length <= Model.MAX_TITLE_CHARS
&& clippedCtx.rawTitle.length <= Model.MAX_TITLE_CHARS,
`matchText=${clippedCtx.matchText.length} rawTitle=${clippedCtx.rawTitle.length}`)
// The host scanner used to be a single unanchored regex, and a long run of
// letters with no dot in it drove it into quadratic backtracking: ~2.5s of
// frozen shell for a 63 kB title, growing with the square of the length.
// hyprctl hands over as much as a megabyte, so this is the honest size.
const hostileTitle = "a".repeat(100000) + " - Chromium"
const hostileWindow = { class: "chromium", title: hostileTitle, mapped: true }
const bigVault = []
for (let i = 0; i < 2000; i++) {
bigVault.push({ id: `big-${i}`, name: `Account ${i}`, uris: [`https://site${i}example.com`] })
}
const started = Date.now()
Model.findContextualMatches(bigVault, hostileWindow, Model.emptyAssociations())
const elapsed = Date.now() - started
check("a hostile window title does not stall the matcher", elapsed < 2000,
`matching a 100 kB title against 2000 items took ${elapsed}ms`)
// Splitting replaced the regex, so prove it still reads the same hosts out.
for (const [text, expected] of [
["Files - Nextcloud - cloud.example.org", "example.org"],
["https://sub.example.co.uk/path", "example.co.uk"],
["see .example.com now", "example.com"],
["a..b.example.com", "example.com"],
["config.json is not a host", null],
["version 1.2.3.4 released", null],
["nothing here at all", null],
]) {
const got = Model.cleanWindowContext({ class: "chromium", title: text, mapped: true })
const base = got && got.detectedDomain ? got.detectedDomain.baseDomain : null
check(`host detection in ${JSON.stringify(text)}`, base === expected,
`expected ${expected}, got ${base}`)
}
// Every word of a title becomes a stored key, and the store is read back
// through a byte cap that turns an oversized file into no file at all. The
// write side has to stay under that cap on its own.
let grown = Model.emptyAssociations()
for (let p = 0; p < 300; p++) {
const words = []
for (let w = 0; w < 80; w++) words.push(`tok${p}x${w}zz`)
grown = Model.recordAssociation(grown,
Model.cleanWindowContext({ class: "chromium", title: words.join(" "), mapped: true }),
"auth-1", `2026-08-${String((p % 28) + 1).padStart(2, "0")}T00:00:00Z`)
}
const grownBytes = Model.serializeAssociations(grown).length
check("the association store stays inside the cap it is read back through",
grownBytes < Model.MAX_ASSOC_BYTES,
`store grew to ${grownBytes} bytes against a ${Model.MAX_ASSOC_BYTES} byte read cap`)
// Trimming must not cost the most recent lesson.
const recentCtx = Model.cleanWindowContext(authentikWindow)
const stillLearned = Model.recordAssociation(grown, recentCtx, "auth-1", "2026-12-31T00:00:00Z")
check("the newest lesson survives trimming",
Model.findContextualMatches(withAuthentik, authentikWindow, stillLearned).matches.map(m => m.id).join() === "auth-1",
"expected the just-learned item to still be suggested")
console.log(`${pass} passed, ${failures.length} failed`)
if (failures.length) {
console.error("\nFAILURES:\n " + failures.join("\n "))
process.exit(1)
}