diff --git a/.tack/default.nix b/.tack/default.nix new file mode 100644 index 0000000..d8e6485 --- /dev/null +++ b/.tack/default.nix @@ -0,0 +1,302 @@ +# SPDX-License-Identifier: EUPL-1.2 +# tack-managed resolver. delete this line to take ownership; tack will leave it alone afterwards. + +let + inherit (builtins) + attrNames + attrValues + concatMap + elemAt + filter + foldl' + fromJSON + head + intersectAttrs + isList + isString + listToAttrs + mapAttrs + match + pathExists + readFile + substring + tail + trace + ; + + call = + { + overrides ? { }, + }: + let + pins = fromTOML (readFile ./pins.toml); + lock = fromJSON (readFile ./pins.lock.json); + all_follow_raw = pins.all_follow or { }; + + # flatten `target = [aliases]` rows alongside `alias = "target"` rows + all_follow = foldl' ( + acc: key: + let + val = all_follow_raw.${key}; + in + if isList val then + acc + // { + ${key} = key; + } + // listToAttrs ( + map (a: { + name = a; + value = key; + }) val + ) + else if isString val then + acc // { ${key} = val; } + else + acc + ) { } (attrNames all_follow_raw); + + # a path node's stored path is absolute, or relative to this resolver dir + fetchPin = + name: + let + node = lock.${name}; + in + if (node.type or "") == "path" && substring 0 1 node.path != "/" then + fetchTree (node // { path = ./. + ("/" + node.path); }) + else + fetchTree node; + + fetchFixed = + name: entry: + let + raw = derivation { + inherit name; + inherit (entry) url; + builder = "builtin:fetchurl"; + system = "builtin"; + outputHash = entry.sha256; + outputHashAlgo = "sha256"; + outputHashMode = "flat"; + }; + unpacked = derivation { + inherit name; + builder = "builtin:unpack-channel"; + system = "builtin"; + src = raw; + channelName = name; + }; + in + if (entry.unpack or "file") == "tarball" then unpacked.outPath + "/" + name else raw.outPath; + + resolveSpec = upLock: spec: if isList spec then walkPath upLock upLock.root spec else spec; + + walkPath = + upLock: nodeName: path: + if path == [ ] then + nodeName + else + walkPath upLock (resolveSpec upLock upLock.nodes.${nodeName}.inputs.${head path}) (tail path); + + followsFor = + pin: + let + rules = removeAttrs all_follow (pin.exclude_follow or [ ]); + in + { + level = (pin.follows or { }) // rules; + deep = rules; + }; + + resolveFollows = mapAttrs ( + _: target: self.${target} or (throw "tack: follows target '${target}' is not a pin") + ); + + # follows key is `flake:name`, `tack:name`, or bare `name` + # project onto one side, rekeyed to bare names + followsForSide = + side: follows: + listToAttrs ( + concatMap ( + key: + let + m = match "(flake|tack):(.*)" key; + in + if m == null then + [ + { + name = key; + value = follows.${key}; + } + ] + else if head m == side then + [ + { + name = elemAt m 1; + value = follows.${key}; + } + ] + else + [ ] + ) (attrNames follows) + ); + + mkCallerInputs = + upLock: nodeName: rawInputs: levelFollows: deepFollows: + let + resolved = resolveFollows levelFollows; + in + mapAttrs ( + n: _decl: + resolved.${n} or ( + if upLock != null then + let + ref = + (upLock.nodes.${nodeName}.inputs or { }).${n} + or (throw "tack: input '${n}' declared but not in flake.lock node '${nodeName}'"); + childName = resolveSpec upLock ref; + childNode = upLock.nodes.${childName}; + childSrc = fetchTree childNode.locked; + in + if childNode.flake or true then evalTransitive upLock childName childSrc deepFollows else childSrc + else + throw "tack: no flake.lock; cannot resolve input '${n}'" + ) + ) rawInputs; + + mkFlakeResult = + sourceInfo: flakeDir: callerInputs: outputs: + outputs + // sourceInfo + // { + outPath = flakeDir; + inputs = callerInputs; + inherit outputs sourceInfo; + _type = "flake"; + }; + + evalFlake = + sourceInfo: flakeDir: upLock: nodeName: levelFollows: deepFollows: + let + raw = import (flakeDir + "/flake.nix"); + + tackPinsPath = flakeDir + "/.tack/pins.toml"; + hasTack = pathExists tackPinsPath; + upPins = if hasTack then fromTOML (readFile tackPinsPath) else { }; + + # project follows onto each side, keep only names that side has + # bare follow reaches both; `flake:`/`tack:` reaches just one + tackOverrides = resolveFollows ( + intersectAttrs (upPins.inputs or { }) (followsForSide "tack" levelFollows) + ); + flakeLevel = intersectAttrs (raw.inputs or { }) (followsForSide "flake" levelFollows); + + # deep follows pass down raw, so each descendant re-projects per side + callerInputs = mkCallerInputs upLock nodeName (raw.inputs or { }) flakeLevel deepFollows; + + # upstream declares its outputs forward tackOverrides; a closed `{ self }:` + # would throw on the extra kwarg, so forward only when declared + supportsOverrides = (upPins.tack or { }).recomposable or false; + + extraArgs = if supportsOverrides && tackOverrides != { } then { inherit tackOverrides; } else { }; + + outputs = raw.outputs (callerInputs // extraArgs // { self = result; }); + + result = + let + base = mkFlakeResult sourceInfo flakeDir callerInputs outputs; + in + if hasTack && tackOverrides != { } && !supportsOverrides then + trace "tack: ${flakeDir}: not marked recomposable (set [tack] recomposable = true); overrides will not reach upstream" base + else + base; + in + result; + + evalTransitive = + upLock: nodeName: sourceInfo: follows: + evalFlake sourceInfo sourceInfo.outPath upLock nodeName follows follows; + + evalTopFlake = + sourceInfo: pin: + let + flakeDir = sourceInfo.outPath + (if pin ? dir then "/" + pin.dir else ""); + upLockPath = flakeDir + "/flake.lock"; + upLock = if pathExists upLockPath then fromJSON (readFile upLockPath) else null; + rootNode = if upLock != null then upLock.root else null; + f = followsFor pin; + in + evalFlake sourceInfo flakeDir upLock rootNode f.level f.deep; + + evalFetch = + sourceInfo: pin: subdir: + let + path = sourceInfo.outPath + subdir; + tackPinsPath = path + "/.tack/pins.toml"; + hasTack = pathExists tackPinsPath; + upPins = if hasTack then fromTOML (readFile tackPinsPath) else { }; + f = followsFor pin; + # a fetch drill-in is tack-only + tackOverrides = resolveFollows ( + intersectAttrs (upPins.inputs or { }) (followsForSide "tack" f.level) + ); + in + # a fetch pin is a source tree (path); hand back resolved inputs only when + # there are overrides to push into the upstream's .tack + if hasTack && tackOverrides != { } then + let + upstream = import (path + "/.tack"); + in + # old resolvers return a plain attrset, not a callable functor + if upstream ? __functor then + (upstream { overrides = tackOverrides; }) // { outPath = path; } + else + trace "tack: ${path}: upstream .tack predates override support; overrides will not reach it" path + else + path; + + loadPin = + name: pin: + let + pinType = pin.type or (if pin.flake or true then "flake" else "fetch"); + subdir = if pin ? dir then "/" + pin.dir else ""; + in + if pinType == "fixed" then + fetchFixed name lock.${name} + else + let + sourceInfo = fetchPin name; + in + if pinType == "flake" then evalTopFlake sourceInfo pin else evalFetch sourceInfo pin subdir; + + declared = pins.inputs or { }; + + # undeclared lock entries are auto-dedup synthetics only when referenced as + # [all_follow] targets; stale locks from hand-edits are ignored (tack rm to clean) + autoTargets = listToAttrs ( + map (target: { + name = target; + value = true; + }) (attrValues all_follow) + ); + autoNames = filter (n: !(declared ? ${n}) && autoTargets ? ${n}) (attrNames lock); + autoPin = + name: + let + sourceInfo = fetchPin name; + in + if pathExists (sourceInfo.outPath + "/flake.nix") then evalTopFlake sourceInfo { } else sourceInfo; + + self = + (mapAttrs loadPin declared) + // listToAttrs ( + map (name: { + inherit name; + value = autoPin name; + }) autoNames + ) + // overrides; + in + self // { __functor = _: call; }; +in +call { } diff --git a/.tack/pins.lock.json b/.tack/pins.lock.json new file mode 100644 index 0000000..4b4501c --- /dev/null +++ b/.tack/pins.lock.json @@ -0,0 +1,206 @@ +{ + "arbys": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/arbys", + "ref": "refs/heads/meats", + "rev": "cc1e2613fbbb0ed98bb4ce0d52c6e99bb8f98055", + "narHash": "sha256-Z/O9W0A0SG/cZiiviNPfmciqvI6a3giCLFt/ElwtLCs=", + "lastModified": 1756449827 + }, + "autonym": { + "type": "github", + "owner": "manic-systems", + "repo": "autonym", + "rev": "0117ec675ef469d92309a25456005e44dae3d1e8", + "narHash": "sha256-WWyMNxb2HAAr13HoO7rC1wrT83zTaYf3/Q2taFUVu84=", + "lastModified": 1780983954 + }, + "cade": { + "type": "github", + "owner": "manic-systems", + "repo": "cade", + "rev": "37603ff8a75483e713ad823b53df627c72be093a", + "narHash": "sha256-+uzmExx+QszSWUKQeFJSTGm9WrNxtf6oSd2dcRNOG8M=", + "lastModified": 1780984342 + }, + "headroom": { + "type": "github", + "owner": "manic-systems", + "repo": "headroom", + "rev": "041edb0f1758372dfb64048eb5d3b18d4b620dfc", + "narHash": "sha256-NNhwKxYLf4rxJjjAKrjCfm65PGPJ/jdZZAmiTwxtoew=", + "lastModified": 1780544339 + }, + "helium": { + "type": "github", + "owner": "amaanq", + "repo": "helium-flake", + "rev": "d765e1962dbe3fa08e0bf4f6abd3dd53806cf826", + "narHash": "sha256-eHfsA/pKQAK60jmyGzGP7BvcJOXAPZJY0lEQJC2xlGc=", + "lastModified": 1780821058 + }, + "hudcore": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/hudcore-plymouth", + "ref": "refs/heads/main", + "rev": "6555d555797bf1960bd89e76a53e0240b6a93df9", + "narHash": "sha256-AI72zuAQBSYETn/dhN8qN8Hdts8PWnSDLEgAxMSZ+CU=", + "lastModified": 1774692528 + }, + "inshellah": { + "type": "github", + "owner": "manic-systems", + "repo": "inshellah", + "rev": "d9b0785a14acb6b9f439d19b0fd696489b017591", + "narHash": "sha256-yAyiffrfDxZvjsDSJzVkxJB2rHCe7pamtuv0xq0zIuU=", + "lastModified": 1780984030 + }, + "meat": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/meat", + "ref": "HEAD", + "rev": "d76f4783000aa109b8fbe63380ae8cfa1e9fcece", + "narHash": "sha256-+Psh1I2/T0x4+Efl73iI59ZR9LKrkdwKAxsB1RN9VHM=", + "lastModified": 1780984054 + }, + "ncro": { + "type": "github", + "owner": "feel-co", + "repo": "ncro", + "rev": "b33e43200b2c28924b1f6a1304f316e9f8d75654", + "narHash": "sha256-POz3sWFFCYnwp79EMnal0I9487Q/ir+hPrswfGamExw=", + "lastModified": 1780984256 + }, + "niri": { + "type": "github", + "owner": "sodiboo", + "repo": "niri-flake", + "rev": "da6577a9bef8a4d7a9d7a2a0dc1e1089edb46bed", + "narHash": "sha256-/Tzx2TY0IVm/ptBvkKaLdOHADpM7xsUMfBKOpCibH1M=", + "lastModified": 1780944960 + }, + "niri-s76": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/niri-s76-bridge", + "ref": "refs/heads/main", + "rev": "e3afb85f23c0e59b2a818094ee7b391ca2f3504d", + "narHash": "sha256-UicMzXYy2XE5jr2J7IO6pZTXUNPndPrGHSIIN6+fB1E=", + "lastModified": 1771162707 + }, + "niri-tag": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/niri-tag", + "ref": "refs/heads/main", + "rev": "785619920b8ae1dd147da795cc7e703c3367c34a", + "narHash": "sha256-y5KsYbzC3MLKr+2M1792jxs3//uV8x9kG+G0LA7cycg=", + "lastModified": 1772457471 + }, + "nix-index-database": { + "type": "github", + "owner": "Mic92", + "repo": "nix-index-database", + "rev": "1a2ea89c917781e88508d9fd2b507f2d2a0e173c", + "narHash": "sha256-0BYqs8yKWkOz2Q7+SP18N5E5gmDKSo6LSxIVIa0wWes=", + "lastModified": 1780816331 + }, + "nix-rice": { + "type": "github", + "owner": "bertof", + "repo": "nix-rice", + "rev": "98b16b0f649bb41db9a1c3b32191bccb9a1ec271", + "narHash": "sha256-nt/xmuXaJB/vWlRJ4wpdlYQCIgCzFR6QJwlRyhfNn5o=", + "lastModified": 1768817933 + }, + "nixos-core": { + "type": "github", + "owner": "manic-systems", + "repo": "nixos-core", + "rev": "20b5f8916a3fde2f02bccd2e1f2795ab511aab5b", + "narHash": "sha256-7x7KzH5p+VDBvvzpCjkRcVhNm6fIty7WYgI7sPq1SCw=", + "lastModified": 1780223676 + }, + "nixpkgs": { + "type": "tarball", + "url": "https://releases.nixos.org/nixos/unstable/nixos-26.11pre1011622.a799d3e3886d/nixexprs.tar.xz", + "narHash": "sha256-G5B1h4sOH4DN/RZ85xYi6zPm2MHdOrNMeUmMslZ28Qs=", + "lastModified": 1780879182 + }, + "nixpkgs-stable": { + "type": "tarball", + "url": "https://releases.nixos.org/nixos/26.05/nixos-26.05.1550.bd0ff2d3eac2/nixexprs.tar.xz", + "narHash": "sha256-YMnBf9lk/LYgvqfmSSJuOGigtRs5Lsy26pJHVlR9yMY=", + "lastModified": 1780936340 + }, + "qstn": { + "type": "git", + "url": "https://git.lobotomise.me/atagen/qstn", + "ref": "refs/heads/main", + "rev": "e6570c79145f3190ff93cb2036ae963a8643445f", + "narHash": "sha256-0tMAB3gHKG32A4z/hM7aWNU2t+jh1zT4dpoamcHucog=", + "lastModified": 1767007132 + }, + "qtengine": { + "type": "github", + "owner": "kossLAN", + "repo": "qtengine", + "rev": "073987f0120ac77a92fb9f0c0877aa7f1f04d3bf", + "narHash": "sha256-D7mzavE5WfLyvEXV0pvO3/gxC+SSmfjw4Lxy7I5qvnI=", + "lastModified": 1778644540 + }, + "rom": { + "type": "github", + "owner": "manic-systems", + "repo": "rom", + "rev": "c577ca3033fe997b0c2910f7abd31076a39b2c42", + "narHash": "sha256-JWOFEK7BUVt0mICxtTITWDCZWhJz7ZStc5VmvPJO9q0=", + "lastModified": 1780479426 + }, + "run0-shim": { + "type": "github", + "owner": "lordgrimmauld", + "repo": "run0-sudo-shim", + "rev": "0cc83451d5171eba0fdcba36b7f1a09b0f023fa4", + "narHash": "sha256-+t1YYIUG1aMYiryiLsXaUoc3nMNjvO5WsD73lIn/BMk=", + "lastModified": 1780915531 + }, + "stash": { + "type": "github", + "owner": "notashelf", + "repo": "stash", + "rev": "2f5cf1dd2ec964e545ad5795d69f27941d9eedfe", + "narHash": "sha256-+1uQWB/Lo1EDMTQGap246klRWCnESkkzl+uS3FJOrsQ=", + "lastModified": 1780680185 + }, + "tack": { + "type": "github", + "owner": "manic-systems", + "repo": "tack", + "rev": "0bc8dcb07dbd85d5d8d889c89accc9b228a6e4cc", + "narHash": "sha256-/GrnjZK71UdLFtugaXkShE8dWpvGxJyOHpj073v+pXU=", + "lastModified": 1780970897 + }, + "toes": { + "type": "git", + "url": "https://git.wry.land/entailz/toes", + "ref": "refs/heads/master", + "rev": "1962186ce19f771c6c407db2e29d5eb5d762f22f", + "narHash": "sha256-M8rCWv83QSC8SzK0VwyGKciEVSO9FrrncUHnTLt8r9Y=", + "lastModified": 1779607934 + }, + "tuigreet": { + "type": "github", + "owner": "notashelf", + "repo": "tuigreet", + "rev": "dc41006d4a4366f732a1a75a20b989fc1e42c0a6", + "narHash": "sha256-ZZk1ccebBjK3pzHVsDU4+fvX/c1fePZ3Tic96/OkfpA=", + "lastModified": 1780583973 + }, + "wry": { + "type": "git", + "url": "https://git.wry.land/kosslan/wry", + "ref": "refs/heads/socket-ipc", + "rev": "f92c092acc1cf6bb7b7b131f8e996c57471a77d2", + "narHash": "sha256-hw5eWVSutlAK3f2rfoSkKvV9FJx4AshWAJwFbQ8LOJE=", + "lastModified": 1780962977 + } +} diff --git a/.tack/pins.toml b/.tack/pins.toml new file mode 100644 index 0000000..f16694b --- /dev/null +++ b/.tack/pins.toml @@ -0,0 +1,100 @@ +# tack pins. edit by hand or with tack add / rm / alias +# nix reads pins.lock.json; this file drives tack update + +[shorturls] +atagen = "git+https://git.lobotomise.me/atagen/{path}" +amaan = "github:amaanq/{path}" +wry = "git+https://git.wry.land/{path}" +ms = "github:manic-systems/{path}" +raf = "github:notashelf/{path}" + +[all_follow] +nixpkgs = "nixpkgs" + +[inputs.nixpkgs] +url = "https://channels.nixos.org/nixos-unstable/nixexprs.tar.xz" + +[inputs.nixpkgs-stable] +url = "https://channels.nixos.org/nixos-26.05/nixexprs.tar.xz" +exclude_follow = [ "nixpkgs" ] + +[inputs.nix-index-database] +url = "github:Mic92/nix-index-database" +exclude_follow = [ "nixpkgs" ] + +[inputs.nix-rice] +url = "github:bertof/nix-rice" +exclude_follow = [ "nixpkgs" ] + +[inputs.meat] +url = "atagen:meat" + +[inputs.hudcore] +url = "atagen:hudcore-plymouth" +exclude_follow = [ "nixpkgs" ] + +[inputs.niri] +url = "github:sodiboo/niri-flake" +exclude_follow = [ "nixpkgs" ] + +[inputs.niri-tag] +url = "atagen:niri-tag" + +[inputs.arbys] +url = "atagen:arbys" + +[inputs.qstn] +url = "atagen:qstn" + +[inputs.run0-shim] +url = "github:lordgrimmauld/run0-sudo-shim" + +[inputs.niri-s76] +url = "atagen:niri-s76-bridge" + +[inputs.helium] +url = "amaan:helium-flake" +exclude_follow = [ "nixpkgs" ] + +[inputs.stash] +url = "raf:stash" + +[inputs.wry] +url = "wry:kosslan/wry/socket-ipc" + +[inputs.toes] +url = "wry:entailz/toes" + +[inputs.tuigreet] +url = "raf:tuigreet" + +[inputs.rom] +url = "ms:rom/small-refactor" + +[inputs.qtengine] +url = "github:kossLAN/qtengine" + +[inputs.inshellah] +url = "ms:inshellah" + +[inputs.nixos-core] +url = "ms:nixos-core" + +[inputs.headroom] +url = "ms:headroom" + +[inputs.cade] +url = "ms:cade/next" + +[inputs.tack] +url = "ms:tack/next" + +[inputs.ncro] +url = "github:feel-co/ncro" + +[inputs.autonym] +url = "ms:autonym" + +# [inputs.zedless] +# url = "github:zedless-editor/zedless-patches" +# exclude_follow = [ "nixpkgs" ] diff --git a/TODO b/TODO new file mode 100644 index 0000000..b6e8063 --- /dev/null +++ b/TODO @@ -0,0 +1,6 @@ +switch to gh:llakala/adios-wrappers +slop a qs polkit agent and get rid of soteria + +jj +tailscale ACLs / tags +merge reflector into larger config diff --git a/common/cli.nix b/common/cli.nix index 6d76afa..657c70a 100644 --- a/common/cli.nix +++ b/common/cli.nix @@ -89,7 +89,7 @@ in SHELL = "${config.users.defaultUserShell}/bin/nu"; }; }; - btop = wrapXdg "btop" pkgs.btop btopConfigDir; + btop = wrapXdg "btop" (pkgs.btop.override { cudaSupport = true; }) btopConfigDir; }; environment.variables.BAT_THEME = "ansi"; diff --git a/common/nix/gc.nix b/common/nix/gc.nix index 135f7d9..88d7351 100644 --- a/common/nix/gc.nix +++ b/common/nix/gc.nix @@ -1,14 +1,8 @@ { - pkgs, - inputs, ... }: { - imports = [ - inputs.angrr.nixosModules.angrr - ]; nix = { - package = pkgs.nixVersions.git; optimise = { automatic = true; dates = "weekly"; @@ -23,9 +17,4 @@ }; }; - services.angrr = { - enable = true; - period = "7d"; - }; - } diff --git a/common/nix/managers.nix b/common/nix/managers.nix index ceaecd8..d068d30 100644 --- a/common/nix/managers.nix +++ b/common/nix/managers.nix @@ -12,6 +12,7 @@ enable = true; flake = "/home/${mainUser}/.nix"; monitor = getFlakePkg inputs.rom; + tack = getFlakePkg inputs.tack; }; # services.smooooth = { diff --git a/common/nix/substituters.nix b/common/nix/substituters.nix index 65b96bb..e172333 100644 --- a/common/nix/substituters.nix +++ b/common/nix/substituters.nix @@ -1,28 +1,75 @@ { - scope, + lib, + inputs, ... }: -scope "nix.settings" { - substituters = [ - "https://nix-community.cachix.org" - "https://anmonteiro.nix-cache.workers.dev" - "https://cache.lobotomise.me" - # "https://cache.atagen.co" - # "https://cache.privatevoid.net" - "https://cache.flox.dev" - "https://cache.amaanq.com" - "https://cache.nixos-cuda.org" - "https://niri.cachix.org" - ]; - trusted-public-keys = [ - "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" - "ocaml.nix-cache.com-1:/xI2h2+56rwFfKyyFVbkJSeGqSIYMC/Je+7XXqGKDIY=" - "cache.lobotomise.me:oF5s/f/RDfVuMH7hl0q/Cby4V/KbPCrZJn8SjKOf/bk=" - # "cache.atagen.co:SOUkNQxuu/eQ7FcI8nlUe7FpV27e7YjQlDQdn8HTUnw=" - # "cache.privatevoid.net:SErQ8bvNWANeAvtsOESUwVYr2VJynfuc9JRwlzTTkVg=" - "flox-cache-public-1:7F4OyH7ZCnFhcze3fJdfyXYLQw/aV7GEed86nQ7IsOs=" - "cache.amaanq.com:H0iXsEEFsvUNtWb5v9V8Kss+L4F/tnXwDHXcY+xbmKk=" - "cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M=" - "niri.cachix.org-1:Wv0OmO7PsuocRKzfDoJ3mulSl7Z6oezYhGhR+3W2964=" - ]; +{ + imports = [ inputs.ncro.nixosModules.default ]; + nix.settings = { + # trusted-public-keys = [ + # "cache.privatevoid.net:SErQ8bvNWANeAvtsOESUwVYr2VJynfuc9JRwlzTTkVg=" + # ]; + substituters = lib.mkForce [ + "http://localhost:8080" + ]; + }; + services.ncro = { + enable = true; + settings = { + upstreams = [ + { + url = "https://cache.nixos.org"; + public_key = "cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="; + priority = 10; + } + { + url = "https://nix-community.cachix.org"; + public_key = "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs="; + priority = 20; + } + { + url = "https://cache.lobotomise.me"; + public_key = "cache.lobotomise.me:oF5s/f/RDfVuMH7hl0q/Cby4V/KbPCrZJn8SjKOf/bk="; + priority = 30; + } + { + public_key = "cache.nixos-cuda.org:74DUi4Ye579gUqzH4ziL9IyiJBlDpMRn9MBN8oNan9M="; + url = "https://cache.nixos-cuda.org"; + priority = 40; + } + # { + # url = "https://cache.privatevoid.net"; + # # public_key = "cache.privatevoid.net:SErQ8bvNWANeAvtsOESUwVYr2VJynfuc9JRwlzTTkVg="; + # priority = 50; + # filters = [ + # { + # action = "allow"; + # field = "name"; + # pattern = "zedless*"; + # } + # { + # action = "deny"; + # field = "name"; + # pattern = "*"; + # } + # ]; + # } + { + url = "https://cache.flox.dev"; + public_key = "flox-cache-public-1:7F4OyH7ZCnFhcze3fJdfyXYLQw/aV7GEed86nQ7IsOs="; + priority = 50; + } + { + url = "https://cache.amaanq.com"; + public_key = "cache.amaanq.com:H0iXsEEFsvUNtWb5v9V8Kss+L4F/tnXwDHXcY+xbmKk="; + priority = 50; + } + { + url = "https://niri.cachix.org"; + public_key = "niri.cachix.org-1:Wv0OmO7PsuocRKzfDoJ3mulSl7Z6oezYhGhR+3W2964="; + priority = 50; + } + ]; + }; + }; } diff --git a/common/nix/tools.nix b/common/nix/tools.nix index 8604bff..c445a86 100644 --- a/common/nix/tools.nix +++ b/common/nix/tools.nix @@ -1,6 +1,7 @@ { pkgs, inputs, + getFlakePkg, ... }: { @@ -8,8 +9,16 @@ nixfmt nil ]; + imports = [ inputs.nix-index-database.nixosModules.nix-index + inputs.tack.nixosModules.default ]; + + programs.tack = { + enable = true; + nixConfTokens = true; + }; + programs.nix-index-database.comma.enable = true; } diff --git a/common/preserve-system.nix b/common/preserve-system.nix new file mode 100644 index 0000000..d157dea --- /dev/null +++ b/common/preserve-system.nix @@ -0,0 +1 @@ +{ scope, ... }: scope "environment.etc.current-flake.source" ../. diff --git a/common/security.nix b/common/security.nix index e8a81af..f076c30 100644 --- a/common/security.nix +++ b/common/security.nix @@ -1,6 +1,8 @@ { lib, + pkgs, inputs, + mainUser, getFlakePkg, ... }: @@ -44,4 +46,38 @@ StartLimitBurst = 5; }; }; + + # polkitd drops every registered authentication agent when it restarts, and + # soteria 0.3.1 never re-registers — it lingers as a live process with a dead + # registration, after which run0/sudo silently falls back to a tty pkttyagent + # prompt instead of the GUI dialog. `nixos-rebuild switch` was restarting + # polkitd on every config change, knocking soteria out of the agent slot many + # times a day. Two-part fix: + # (B) reload polkit instead of restarting it for config-only changes — + # a polkitd SIGHUP re-reads rules without tearing down live agent + # registrations, so editing the rule above no longer de-registers soteria. + # (A) for the cases that still force a genuine restart (manual restart, + # reboot), bounce soteria afterwards so it re-registers. + # Caveat of (B): a polkit *package* bump changes the unit but won't restart it, + # so the new polkitd binary only takes effect after a reboot or manual + # `systemctl restart polkit`. Acceptable here; rule edits are the hot path. + # Proper upstream fix: soteria should watch org.freedesktop.PolicyKit1 for + # NameOwnerChanged and re-register itself (issue to be filed). + systemd.services.polkit = { + restartIfChanged = false; + reloadIfChanged = true; + }; + systemd.services.polkit-soteria-reregister = { + description = "Re-register soteria with polkitd after polkit (re)starts"; + after = [ "polkit.service" ]; + partOf = [ "polkit.service" ]; + wantedBy = [ "polkit.service" ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + # `-` ignores failure: the user manager may not be up yet (e.g. at boot), + # and try-restart is a no-op when soteria isn't currently running. + ExecStart = "-${pkgs.systemd}/bin/systemctl --user --machine ${mainUser}@.host try-restart polkit-soteria.service"; + }; + }; } diff --git a/common/terminal.nix b/common/terminal.nix index 4272aa7..99d2242 100644 --- a/common/terminal.nix +++ b/common/terminal.nix @@ -2,7 +2,7 @@ lib, pkgs, inputs, - # getFlakePkg', + getFlakePkg, config, mainUser, ... @@ -16,6 +16,7 @@ let nativeBuildInputs = [ pkgs.makeWrapper ]; postBuild = '' wrapProgram $out/bin/nu \ + --add-flags "--env-config ${nuEnv}" \ --add-flags "--config ${nuConfig}" ''; passthru = nushell.passthru or { } // { @@ -215,20 +216,25 @@ let nuScriptsPath = "${pkgs.nu_scripts}/share/nu_scripts"; + nuEnv = pkgs.writeText "env.nu" '' + use ${nuScriptsPath}/modules/capture-foreign-env + source ${nuScriptsPath}/modules/formats/from-env.nu + + let nixos_env = ('source /etc/set-environment' | capture-foreign-env --shell bash) + if ($nixos_env | describe | str starts-with "record") { $nixos_env | load-env } + ''; + nuConfig = pkgs.writeText "config.nu" '' use std/config * ${lib.mapAttrsToList (n: v: "alias ${n} = ${v}") aliases |> lib.concatStringsSep "\n"} $env.NU_LIB_DIRS = ( $env.NU_LIB_DIRS | append "${nuScriptsPath}") - use ${nuScriptsPath}/modules/capture-foreign-env - source ${nuScriptsPath}/modules/formats/from-env.nu - - let nixos_env = ('source /etc/set-environment' | capture-foreign-env --shell bash) - if ($nixos_env | describe | str starts-with "record") { $nixos_env | load-env } - source ${(pkgs.runCommand "zoxide.nu" { } ''${pkgs.zoxide}/bin/zoxide init nushell >> "$out"'')} + source ${ + (pkgs.runCommand "cade.nu" { } ''${lib.getExe (getFlakePkg inputs.cade)} hook nushell >> "$out"'') + } $env.config.buffer_editor = "${lib.getExe config.apps.editor}" @@ -250,35 +256,6 @@ let sudo $"$(p)/bin/switch-to-configuration" switch } - # direnv - $env.config = ($env.config? | default {}) - $env.config.hooks = ($env.config.hooks? | default {}) - $env.config.hooks.pre_prompt = ( - $env.config.hooks.pre_prompt? - | default [] - | append {|| - ${pkgs.direnv}/bin/direnv export json - | from json --strict - | default {} - | items {|key, value| - let value = do ( - { - "PATH": { - from_string: {|s| $s | split row (char esep) | path expand --no-symlink } - to_string: {|v| $v | path expand --no-symlink | str join (char esep) } - } - } - | merge ($env.ENV_CONVERSIONS? | default {}) - | get ([[value, optional, insensitive]; [$key, true, true] [from_string, true, false]] | into cell-path) - | if ($in | is-empty) { {|x| $x} } else { $in } - ) $value - return [ $key $value ] - } - | into record - | load-env - } - ) - # $cmd doesn't carry its args ? # $env.config.hooks.command_not_found = { |cmd| , $cmd; echo } @@ -300,11 +277,17 @@ let in { - imports = [ inputs.inshellah.nixosModules.default ]; - programs.inshellah = { + imports = [ + inputs.inshellah.nixosModules.default + inputs.autonym.nixosModules.default + ]; + + programs.autonym = { enable = true; - helpOnlyCommands = [ "nh" ]; + historyLimit = 2000; + }; + programs.inshellah.enable = true; programs.command-not-found.enable = false; programs.zoxide.enable = true; diff --git a/graphical/audio-control.nix b/graphical/audio-control.nix index e09e6cf..93758ff 100644 --- a/graphical/audio-control.nix +++ b/graphical/audio-control.nix @@ -1,6 +1,11 @@ -{ pkgs, ... }: +{ inputs, pkgs, ... }: { apps = { inherit (pkgs) playerctl; }; + imports = [ inputs.headroom.nixosModules.default ]; + programs.headroom = { + enable = true; + gui.enable = true; + }; } diff --git a/graphical/creative.nix b/graphical/creative.nix new file mode 100644 index 0000000..58c6b44 --- /dev/null +++ b/graphical/creative.nix @@ -0,0 +1,8 @@ +{ pkgs, scope, ... }: +(scope "programs.pwas.graphite" { + name = "Graphite"; + url = "https://editor.graphite.art"; + icon = builtins.fetchurl "https://static.graphite.art/logos/graphite-logo-solid.svg"; + description = "A procedural vector editor"; +}) +// (scope "apps.vector" pkgs.inkscape) diff --git a/graphical/desktop/quickshell/rice/Colours.qml b/graphical/desktop/quickshell/rice/Colours.qml index 9e86f6a..77d0889 120000 --- a/graphical/desktop/quickshell/rice/Colours.qml +++ b/graphical/desktop/quickshell/rice/Colours.qml @@ -1 +1 @@ -/nix/store/1ajn9faiksanmy64n7sg4xjqij1cc5qc-Colours.qml \ No newline at end of file +/nix/store/q7c1ck2g1q064zrgvb8r9g5pbxv9vbsi-Colours.qml \ No newline at end of file diff --git a/graphical/dev.nix b/graphical/dev.nix index 9c47f75..bcf775a 100644 --- a/graphical/dev.nix +++ b/graphical/dev.nix @@ -1,9 +1,14 @@ { pkgs, + inputs, ... }: { - programs.direnv.enable = true; + imports = [ inputs.cade.nixosModules.default ]; + programs.cade = { + enable = true; + direnvCompat = "full"; + }; programs.git = { enable = true; diff --git a/graphical/llm/codex.nix b/graphical/llm/codex.nix index c01acce..9a0f6b8 100644 --- a/graphical/llm/codex.nix +++ b/graphical/llm/codex.nix @@ -1,7 +1,23 @@ -{ pkgs, ... }: +{ + pkgs, + lib, + ... +}: +let + mkCodex = + name: + pkgs.writeScriptBin "codex-${name}" '' + #!${lib.getExe pkgs.nushell} --no-config-file + def --wrapped main [...args] { + $env.CODEX_HOME = $env | get --optional "CODEX_HOME" | default ($env.HOME | path join ".codex-${name}") + mkdir $env.CODEX_HOME + exec ${lib.getExe pkgs.codex} --dangerously-bypass-approvals-and-sandbox --enable goals --enable code_mode ...$args + } + ''; +in { environment.systemPackages = [ - pkgs.codex - pkgs.opencode + (mkCodex "amaan") + (mkCodex "koss") ]; } diff --git a/graphical/password-manager.nix b/graphical/password-manager.nix index 666bc0d..ccc2913 100644 --- a/graphical/password-manager.nix +++ b/graphical/password-manager.nix @@ -25,7 +25,7 @@ let in { apps = with pkgs; { - passwordManager = bitwarden-desktop; + # passwordManager = bitwarden-desktop; passwordCli = rbwWrapped; }; } diff --git a/graphical/terminal.nix b/graphical/terminal.nix index e58be63..41bfbc5 100644 --- a/graphical/terminal.nix +++ b/graphical/terminal.nix @@ -4,6 +4,7 @@ mkWrappers, inputs, scope, + getFlakePkg, ... }: let @@ -66,9 +67,7 @@ let tab-overview=Control+Alt+Tab ''; - toesPkg = pkgs.foot.overrideAttrs { - src = inputs.toes; - }; + toesPkg = getFlakePkg inputs.toes; toes = wrap { name = "foot"; diff --git a/hosts/quiver/hw.nix b/hosts/quiver/hw.nix index e6b3340..9baf906 100644 --- a/hosts/quiver/hw.nix +++ b/hosts/quiver/hw.nix @@ -10,7 +10,6 @@ hardware.graphics.enable = true; services.xserver.videoDrivers = [ "nvidia" ]; - nixpkgs.config.cudaSupport = true; hardware.display.outputs."DP-2".mode = "2560x1440@120e"; diff --git a/lib/create.nix b/lib/create.nix index 411de82..1ea630e 100644 --- a/lib/create.nix +++ b/lib/create.nix @@ -1,5 +1,5 @@ let - inputs = import ./inputs.nix; + inputs = import ../.tack; inherit (inputs) nixpkgs; inherit (nixpkgs) lib; recursivelyImport = import ./recursively-import.nix { inherit lib; }; diff --git a/lib/inputs.nix b/lib/inputs.nix index 4ea982b..ae408d0 100644 --- a/lib/inputs.nix +++ b/lib/inputs.nix @@ -1,6 +1,6 @@ let - pins = builtins.fromTOML (builtins.readFile ../pins/pins.toml); - lock = builtins.fromJSON (builtins.readFile ../pins/pins.lock.json); + pins = builtins.fromTOML (builtins.readFile ../.tack/pins.toml); + lock = builtins.fromJSON (builtins.readFile ../.tack/pins.lock.json); fetchPin = name: builtins.fetchTree lock.${name}; diff --git a/pins/pins.lock.json b/pins/pins.lock.json deleted file mode 100644 index 50b360e..0000000 --- a/pins/pins.lock.json +++ /dev/null @@ -1,179 +0,0 @@ -{ - "angrr": { - "type": "github", - "owner": "linyinfeng", - "repo": "angrr", - "rev": "a26f5a1d188a40077b81349e623f44466c18f75b", - "narHash": "sha256-GixsqdtE/dZr/YHzPz7c7+LOx2UnR/MoYOQ8lpz7vNc=", - "lastModified": 1778862956 - }, - "arbys": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/arbys", - "ref": "refs/heads/meats", - "rev": "cc1e2613fbbb0ed98bb4ce0d52c6e99bb8f98055", - "narHash": "sha256-Z/O9W0A0SG/cZiiviNPfmciqvI6a3giCLFt/ElwtLCs=", - "lastModified": 1756449827 - }, - "helium": { - "type": "github", - "owner": "amaanq", - "repo": "helium-flake", - "rev": "bab62ae9dbd96ed176078251a4b208743fc5ca6a", - "narHash": "sha256-DnIdzBUFd/Y7LCOQetLiP+71hoDeD/R3wG0GiTefAkg=", - "lastModified": 1778797907 - }, - "hudcore": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/hudcore-plymouth", - "ref": "refs/heads/main", - "rev": "6555d555797bf1960bd89e76a53e0240b6a93df9", - "narHash": "sha256-AI72zuAQBSYETn/dhN8qN8Hdts8PWnSDLEgAxMSZ+CU=", - "lastModified": 1774692528 - }, - "inshellah": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/inshellah", - "ref": "refs/heads/main", - "rev": "a87b5eb3bd3384970d079cf519b55d1dd84750c8", - "narHash": "sha256-x1lrJVHWwd6FNC1nYe0SkQUbd60i7MBoD1kHHxrx3oU=", - "lastModified": 1779197734 - }, - "meat": { - "lastModified": 1779254800, - "ref": "refs/heads/master", - "rev": "e44c71c128a59e7a0fa7d8a4df2b9622b1c63b69", - "revCount": 3, - "type": "git", - "url": "https://git.lobotomise.me/atagen/meat", - "narHash": "sha256-xtx6/GpboyRsK3EVT4hT9RyvE+VHukLkkM0DSu8tqdI=" - }, - "niri": { - "type": "github", - "owner": "sodiboo", - "repo": "niri-flake", - "rev": "daefca3370581223fedc24d0101c4915a3689f9e", - "narHash": "sha256-SPCWvqeVySTNUgX/shARpRl5fi/NnkObUgDGR/Aco4c=", - "lastModified": 1778942403 - }, - "niri-s76": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/niri-s76-bridge", - "ref": "refs/heads/main", - "rev": "e3afb85f23c0e59b2a818094ee7b391ca2f3504d", - "narHash": "sha256-UicMzXYy2XE5jr2J7IO6pZTXUNPndPrGHSIIN6+fB1E=", - "lastModified": 1771162707 - }, - "niri-tag": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/niri-tag", - "ref": "refs/heads/main", - "rev": "785619920b8ae1dd147da795cc7e703c3367c34a", - "narHash": "sha256-y5KsYbzC3MLKr+2M1792jxs3//uV8x9kG+G0LA7cycg=", - "lastModified": 1772457471 - }, - "nix-index-database": { - "type": "github", - "owner": "Mic92", - "repo": "nix-index-database", - "rev": "f680e0d3c1dbefe298c423691662e238496890f2", - "narHash": "sha256-V5GquqJvAqwFTcpN6hxKSQAtwuJFRUEHmyNKbeaTQDg=", - "lastModified": 1778999127 - }, - "nix-rice": { - "type": "github", - "owner": "bertof", - "repo": "nix-rice", - "rev": "98b16b0f649bb41db9a1c3b32191bccb9a1ec271", - "narHash": "sha256-nt/xmuXaJB/vWlRJ4wpdlYQCIgCzFR6QJwlRyhfNn5o=", - "lastModified": 1768817933 - }, - "nixos-core": { - "type": "github", - "owner": "feel-co", - "repo": "nixos-core", - "rev": "5512197f02333c24a9260dd9254c8d0dd8990981", - "narHash": "sha256-fTHhZmepyzXXwisSb/ULB/gGu8wqDF0FqKD/v6nMBYM=", - "lastModified": 1778833218 - }, - "nixpkgs": { - "type": "github", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d233902339c02a9c334e7e593de68855ad26c4cb", - "narHash": "sha256-30sZNZoA1cqF5JNO9fVX+wgiQYjB7HJqqJ4ztCDeBZE=", - "lastModified": 1778869304 - }, - "nixpkgs-stable": { - "type": "github", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d7a713c0b7e47c908258e71cba7a2d77cc8d71d5", - "narHash": "sha256-6xWoytx8jFW4PF1GjRm/i/53trbpKGfz6zjzQGBr4cI=", - "lastModified": 1778737229 - }, - "qstn": { - "type": "git", - "url": "https://git.lobotomise.me/atagen/qstn", - "ref": "refs/heads/main", - "rev": "e6570c79145f3190ff93cb2036ae963a8643445f", - "narHash": "sha256-0tMAB3gHKG32A4z/hM7aWNU2t+jh1zT4dpoamcHucog=", - "lastModified": 1767007132 - }, - "qtengine": { - "type": "github", - "owner": "kossLAN", - "repo": "qtengine", - "rev": "073987f0120ac77a92fb9f0c0877aa7f1f04d3bf", - "narHash": "sha256-D7mzavE5WfLyvEXV0pvO3/gxC+SSmfjw4Lxy7I5qvnI=", - "lastModified": 1778644540 - }, - "rom": { - "type": "github", - "owner": "feel-co", - "repo": "rom", - "rev": "c558ce03f4763f861d8a1de25e69b111e63c197e", - "narHash": "sha256-Ttjh24GzioYSkW7HOx9BVPRhCR20unQ5FVwa37jpr3o=", - "lastModified": 1778049674 - }, - "run0-shim": { - "type": "github", - "owner": "lordgrimmauld", - "repo": "run0-sudo-shim", - "rev": "c9e06e2f220ab2fcf2228d4315c0a7fc2dc6e438", - "narHash": "sha256-iZ0HSQwjr9nYpVn10ZI4zQTdqvSggfxhXZ1c4oSZnuc=", - "lastModified": 1774702115 - }, - "stash": { - "type": "github", - "owner": "notashelf", - "repo": "stash", - "rev": "c1ca18e332d5e2915e4d7ea25b8779e6a4f979df", - "narHash": "sha256-Fgvd+4EC59N9UmmFvhYcILxe9nms1el25goZpyXX+Lg=", - "lastModified": 1778772168 - }, - "toes": { - "type": "git", - "url": "ssh://forgejo@git.wry.land/entailz/toes", - "ref": "refs/heads/master", - "rev": "05ee680778cfb0a05d72c73d1684834d021c9a5f", - "narHash": "sha256-7LIluI0PWtWy+AoYTU1cuHoU9OEKgCh53GtwXkjZA1o=", - "lastModified": 1779130477 - }, - "tuigreet": { - "type": "github", - "owner": "notashelf", - "repo": "tuigreet", - "rev": "ba17edead8fcefc21d7dbf6e24f2c718bbc463d6", - "narHash": "sha256-LzKasoA1Ezcs6nnTzR8L/9mP9veLjU3dONi/hYoc3aA=", - "lastModified": 1779071066 - }, - "wry": { - "type": "git", - "url": "ssh://forgejo@git.wry.land/wry/wry", - "ref": "refs/heads/master", - "rev": "a29937ebe8ba6a88c6c952a27e9f22651cfbd970", - "narHash": "sha256-cwplIeQHM8OlIYMaju9qHixP8kZiViQJdnxSy7rxMhk=", - "lastModified": 1778970905 - } -} \ No newline at end of file diff --git a/pins/pins.toml b/pins/pins.toml deleted file mode 100644 index cbec21d..0000000 --- a/pins/pins.toml +++ /dev/null @@ -1,90 +0,0 @@ -# Shorturl schemes — read by `meat fresh` only. The Nix evaluator never -# resolves a shorturl; only the resolved URL appears in pins.lock.json. -[shorturls] -atagen = "git+https://git.lobotomise.me/atagen/{path}" -amaan = "github:amaanq/{path}" -kosslan = "git+ssh://git@git.kosslan.dev/{path}" -wry = "git+ssh://forgejo@git.wry.land/{path}" - -# ---- inputs -------------------------------------------------------------- -# Each [inputs.] block declares a top-level pin. Fields: -# url (required) shorturl ok; meat expands before resolving -# flake (optional) default true; false = expose source path -# follows (optional) { childInputName = "topLevelPinName" } override map -# dir (optional) subdirectory containing flake.nix -# submodules (optional) fetch git submodules - -[inputs.nixpkgs] -url = "github:NixOS/nixpkgs/nixos-unstable" - -[inputs.nixpkgs-stable] -url = "github:NixOS/nixpkgs/nixos-25.11" - -[inputs.nix-index-database] -url = "github:Mic92/nix-index-database" - -[inputs.nix-rice] -url = "github:bertof/nix-rice" - -[inputs.meat] -url = "atagen:meat" -follows = { nixpkgs = "nixpkgs" } - -[inputs.hudcore] -url = "atagen:hudcore-plymouth" - -[inputs.niri] -url = "github:sodiboo/niri-flake" - -[inputs.niri-tag] -url = "atagen:niri-tag" -follows = { nixpkgs = "nixpkgs" } - -[inputs.angrr] -url = "github:linyinfeng/angrr" - -[inputs.arbys] -url = "atagen:arbys" - -[inputs.qstn] -url = "atagen:qstn" -follows = { nixpkgs = "nixpkgs" } - -[inputs.run0-shim] -url = "github:lordgrimmauld/run0-sudo-shim" -follows = { nixpkgs = "nixpkgs" } - -[inputs.niri-s76] -url = "atagen:niri-s76-bridge" - -[inputs.helium] -url = "amaan:helium-flake" - -[inputs.stash] -url = "github:notashelf/stash" - -[inputs.wry] -url = "wry:wry/wry" -follows = { nixpkgs = "nixpkgs" } - -[inputs.toes] -url = "wry:entailz/toes" -flake = false - -[inputs.tuigreet] -url = "github:notashelf/tuigreet" - -[inputs.rom] -url = "github:feel-co/rom" - -[inputs.inshellah] -url = "atagen:inshellah" -follows = { nixpkgs = "nixpkgs" } - -[inputs.qtengine] -url = "github:kossLAN/qtengine" -follows = { nixpkgs = "nixpkgs" } - -[inputs.nixos-core] -url = "github:feel-co/nixos-core" -follows = { nixpkgs = "nixpkgs" }