| author | |
| committer | |
| log | b1b433e6c16b2ca52b33bbe8aea31734aa23212c |
| tree | 31a702ff97d856c39357a91c61fea712f7733f4b |
| parent | f60c39943834cc26bc64c715c9b94d541e98526a |
| signature | Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs |
12 files changed, 289 insertions(+), 103 deletions(-)
modules/home/default.nix+6| ... | @@ -59,6 +59,12 @@ in | ... | @@ -59,6 +59,12 @@ in |
| 59 | home.shell = { | 59 | home.shell = { |
| 60 | enableShellIntegration = true; | 60 | enableShellIntegration = true; |
| 61 | }; | 61 | }; |
| 62 | home.sessionPath = [ | ||
| 63 | "$HOME/.local/bin" | ||
| 64 | "$HOME/.opencode/bin" | ||
| 65 | "$HOME/.vite-plus/bin" | ||
| 66 | "$HOME/bin" | ||
| 67 | ]; | ||
| 62 | programs = { | 68 | programs = { |
| 63 | home-manager.enable = true; | 69 | home-manager.enable = true; |
| 64 | nix-index.enable = true; | 70 | nix-index.enable = true; |
packages/autofmt/default.nix+9-7| ... | @@ -15,11 +15,13 @@ pkgs.writeTextFile { | ... | @@ -15,11 +15,13 @@ pkgs.writeTextFile { |
| 15 | name = "autofmt"; | 15 | name = "autofmt"; |
| 16 | destination = "/bin/autofmt"; | 16 | destination = "/bin/autofmt"; |
| 17 | executable = true; | 17 | executable = true; |
| 18 | text = builtins.replaceStrings | 18 | text = |
| 19 | [ "#!/usr/bin/env node" ] | 19 | builtins.replaceStrings |
| 20 | [ | 20 | [ "#!/usr/bin/env node" ] |
| 21 | ''#!${pkgs.nodejs}/bin/node | 21 | [ |
| 22 | process.env.PATH = "${pkgs.lib.makeBinPath runtimeInputs}:" + (process.env.PATH ?? "");'' | 22 | '' |
| 23 | ] | 23 | #!${pkgs.nodejs}/bin/node |
| 24 | (builtins.readFile ./autofmt.js); | 24 | process.env.PATH = "${pkgs.lib.makeBinPath runtimeInputs}:" + (process.env.PATH ?? "");'' |
| 25 | ] | ||
| 26 | (builtins.readFile ./autofmt.js); | ||
| 25 | } | 27 | } |
packages/jj-import-merge/jj-import-merge.js+42-13| ... | @@ -86,10 +86,14 @@ function usage(code) { | ... | @@ -86,10 +86,14 @@ function usage(code) { |
| 86 | const stream = code === 0 ? process.stdout : process.stderr; | 86 | const stream = code === 0 ? process.stdout : process.stderr; |
| 87 | stream.write(`usage: ${exe} [--all-jj] [--] <file>...\n`); | 87 | stream.write(`usage: ${exe} [--all-jj] [--] <file>...\n`); |
| 88 | stream.write(`\n`); | 88 | stream.write(`\n`); |
| 89 | stream.write(`merge top-of-file JS/TS imports from 2-sided Jujutsu conflicts\n`); | 89 | stream.write( |
| 90 | `merge top-of-file JS/TS imports from 2-sided Jujutsu conflicts\n`, | ||
| 91 | ); | ||
| 90 | stream.write(`\n`); | 92 | stream.write(`\n`); |
| 91 | stream.write(`options:\n`); | 93 | stream.write(`options:\n`); |
| 92 | stream.write(` --all-jj resolve all conflicted JS/TS files from 'jj resolve --list'\n`); | 94 | stream.write( |
| 95 | ` --all-jj resolve all conflicted JS/TS files from 'jj resolve --list'\n`, | ||
| 96 | ); | ||
| 93 | stream.write(` -h show help\n`); | 97 | stream.write(` -h show help\n`); |
| 94 | process.exit(code); | 98 | process.exit(code); |
| 95 | } | 99 | } |
| ... | @@ -158,7 +162,11 @@ function processFile(file) { | ... | @@ -158,7 +162,11 @@ function processFile(file) { |
| 158 | leftImports.start, | 162 | leftImports.start, |
| 159 | rightImports.start, | 163 | rightImports.start, |
| 160 | ); | 164 | ); |
| 161 | const end = projectBoundaryToOriginal(parsed.parts, leftImports.end, rightImports.end); | 165 | const end = projectBoundaryToOriginal( |
| 166 | parsed.parts, | ||
| 167 | leftImports.end, | ||
| 168 | rightImports.end, | ||
| 169 | ); | ||
| 162 | if (start == null || end == null || end < start) { | 170 | if (start == null || end == null || end < start) { |
| 163 | return { kind: "noop" }; | 171 | return { kind: "noop" }; |
| 164 | } | 172 | } |
| ... | @@ -168,7 +176,8 @@ function processFile(file) { | ... | @@ -168,7 +176,8 @@ function processFile(file) { |
| 168 | rightImports.statements, | 176 | rightImports.statements, |
| 169 | detectNewline(original), | 177 | detectNewline(original), |
| 170 | ); | 178 | ); |
| 171 | const updated = original.slice(0, start) + mergedImports + original.slice(end); | 179 | const updated = original.slice(0, start) + mergedImports + |
| 180 | original.slice(end); | ||
| 172 | 181 | ||
| 173 | if (updated === original) { | 182 | if (updated === original) { |
| 174 | return { kind: "noop" }; | 183 | return { kind: "noop" }; |
| ... | @@ -193,7 +202,9 @@ function processFile(file) { | ... | @@ -193,7 +202,9 @@ function processFile(file) { |
| 193 | if (formatResult.error || formatResult.status !== 0) { | 202 | if (formatResult.error || formatResult.status !== 0) { |
| 194 | fs.writeFileSync(file, original, "utf8"); | 203 | fs.writeFileSync(file, original, "utf8"); |
| 195 | if (formatResult.error) { | 204 | if (formatResult.error) { |
| 196 | throw new Error(`autofmt failed for ${file}: ${formatResult.error.message}`); | 205 | throw new Error( |
| 206 | `autofmt failed for ${file}: ${formatResult.error.message}`, | ||
| 207 | ); | ||
| 197 | } | 208 | } |
| 198 | throw new Error(`autofmt failed for ${file}`); | 209 | throw new Error(`autofmt failed for ${file}`); |
| 199 | } | 210 | } |
| ... | @@ -259,7 +270,9 @@ function parseConflictBlock(lines, startIndex) { | ... | @@ -259,7 +270,9 @@ function parseConflictBlock(lines, startIndex) { |
| 259 | continue; | 270 | continue; |
| 260 | } | 271 | } |
| 261 | if (line.startsWith("%%%%%%% diff from:")) { | 272 | if (line.startsWith("%%%%%%% diff from:")) { |
| 262 | if (index + 1 >= lines.length || !/^\\\\+\s*to:/.test(lines[index + 1].text)) { | 273 | if ( |
| 274 | index + 1 >= lines.length || !/^\\\\+\s*to:/.test(lines[index + 1].text) | ||
| 275 | ) { | ||
| 263 | return { supported: false, nextIndex: startIndex + 1 }; | 276 | return { supported: false, nextIndex: startIndex + 1 }; |
| 264 | } | 277 | } |
| 265 | index += 2; | 278 | index += 2; |
| ... | @@ -512,7 +525,7 @@ function scanLine(line, state) { | ... | @@ -512,7 +525,7 @@ function scanLine(line, state) { |
| 512 | index += 1; | 525 | index += 1; |
| 513 | continue; | 526 | continue; |
| 514 | } | 527 | } |
| 515 | if (char === "'" || char === "\"" || char === "`") { | 528 | if (char === "'" || char === '"' || char === "`") { |
| 516 | state.stringQuote = char; | 529 | state.stringQuote = char; |
| 517 | continue; | 530 | continue; |
| 518 | } | 531 | } |
| ... | @@ -716,12 +729,18 @@ function canMergeImports(left, right) { | ... | @@ -716,12 +729,18 @@ function canMergeImports(left, right) { |
| 716 | } | 729 | } |
| 717 | 730 | ||
| 718 | const defaultBinding = mergeField(left.defaultBinding, right.defaultBinding); | 731 | const defaultBinding = mergeField(left.defaultBinding, right.defaultBinding); |
| 719 | const namespaceImport = mergeField(left.namespaceImport, right.namespaceImport); | 732 | const namespaceImport = mergeField( |
| 733 | left.namespaceImport, | ||
| 734 | right.namespaceImport, | ||
| 735 | ); | ||
| 720 | if (defaultBinding === undefined || namespaceImport === undefined) { | 736 | if (defaultBinding === undefined || namespaceImport === undefined) { |
| 721 | return false; | 737 | return false; |
| 722 | } | 738 | } |
| 723 | 739 | ||
| 724 | const namedSpecifiers = unique([...left.namedSpecifiers, ...right.namedSpecifiers]); | 740 | const namedSpecifiers = unique([ |
| 741 | ...left.namedSpecifiers, | ||
| 742 | ...right.namedSpecifiers, | ||
| 743 | ]); | ||
| 725 | if (namespaceImport && namedSpecifiers.length > 0) { | 744 | if (namespaceImport && namedSpecifiers.length > 0) { |
| 726 | return false; | 745 | return false; |
| 727 | } | 746 | } |
| ... | @@ -731,8 +750,14 @@ function canMergeImports(left, right) { | ... | @@ -731,8 +750,14 @@ function canMergeImports(left, right) { |
| 731 | 750 | ||
| 732 | function mergeImports(left, right) { | 751 | function mergeImports(left, right) { |
| 733 | const defaultBinding = mergeField(left.defaultBinding, right.defaultBinding); | 752 | const defaultBinding = mergeField(left.defaultBinding, right.defaultBinding); |
| 734 | const namespaceImport = mergeField(left.namespaceImport, right.namespaceImport); | 753 | const namespaceImport = mergeField( |
| 735 | const namedSpecifiers = unique([...left.namedSpecifiers, ...right.namedSpecifiers]); | 754 | left.namespaceImport, |
| 755 | right.namespaceImport, | ||
| 756 | ); | ||
| 757 | const namedSpecifiers = unique([ | ||
| 758 | ...left.namedSpecifiers, | ||
| 759 | ...right.namedSpecifiers, | ||
| 760 | ]); | ||
| 736 | 761 | ||
| 737 | return { | 762 | return { |
| 738 | kind: "binding", | 763 | kind: "binding", |
| ... | @@ -782,13 +807,17 @@ function renderImport(analysis, newline) { | ... | @@ -782,13 +807,17 @@ function renderImport(analysis, newline) { |
| 782 | pieces.push(`{ ${analysis.namedSpecifiers[0]} }`); | 807 | pieces.push(`{ ${analysis.namedSpecifiers[0]} }`); |
| 783 | } else { | 808 | } else { |
| 784 | pieces.push( | 809 | pieces.push( |
| 785 | `{${newline}${analysis.namedSpecifiers.map((spec) => ` ${spec},`).join(newline)}${newline}}`, | 810 | `{${newline}${ |
| 811 | analysis.namedSpecifiers.map((spec) => ` ${spec},`).join(newline) | ||
| 812 | }${newline}}`, | ||
| 786 | ); | 813 | ); |
| 787 | } | 814 | } |
| 788 | } | 815 | } |
| 789 | 816 | ||
| 790 | return ensureTrailingNewline( | 817 | return ensureTrailingNewline( |
| 791 | `import ${analysis.isTypeImport ? "type " : ""}${pieces.join(", ")} from ${analysis.quote}${analysis.source}${analysis.quote}${analysis.attributes};`, | 818 | `import ${analysis.isTypeImport ? "type " : ""}${ |
| 819 | pieces.join(", ") | ||
| 820 | } from ${analysis.quote}${analysis.source}${analysis.quote}${analysis.attributes};`, | ||
| 792 | newline, | 821 | newline, |
| 793 | ); | 822 | ); |
| 794 | } | 823 | } |
switch+6-3| ... | @@ -12,13 +12,16 @@ if [ -z "$hostname" ]; then | ... | @@ -12,13 +12,16 @@ if [ -z "$hostname" ]; then |
| 12 | hostname="$(hostname)" | 12 | hostname="$(hostname)" |
| 13 | fi | 13 | fi |
| 14 | printf "%s" "$hostname" >.hostname | 14 | printf "%s" "$hostname" >.hostname |
| 15 | if [ "$(uname -o)" = "Darwin" ]; then | 15 | if [ "$(uname -s)" = "Darwin" ]; then |
| 16 | nh_subcommand="darwin" | 16 | nh_subcommand="darwin" |
| 17 | fallback_command="nix run .#darwin-rebuild" | 17 | fallback_command="nix run .#darwin-rebuild" |
| 18 | hostname="darwinConfigurations.$hostname" | ||
| 19 | fi | 18 | fi |
| 20 | if command -v nh >/dev/null; then | 19 | if command -v nh >/dev/null; then |
| 21 | nh $nh_subcommand switch '.#'"$hostname" | 20 | if [ "$nh_subcommand" = "darwin" ]; then |
| 21 | nh darwin switch . --hostname "$hostname" | ||
| 22 | else | ||
| 23 | nh os switch '.#'"$hostname" | ||
| 24 | fi | ||
| 22 | else | 25 | else |
| 23 | $fallback_command -- switch --flake '.#'"$hostname" | 26 | $fallback_command -- switch --flake '.#'"$hostname" |
| 24 | fi | 27 | fi |
users/clover/AGENTS.md+4| ... | @@ -13,6 +13,10 @@ You are working with Clover, an intelligent web/systems engineer. Please avoid e | ... | @@ -13,6 +13,10 @@ You are working with Clover, an intelligent web/systems engineer. Please avoid e |
| 13 | - Never include a section on checks saying "pnpm test passed" or "checks passed" or whatever. Just make sure your validation is strong in the first place; You're expected to have that done. | 13 | - Never include a section on checks saying "pnpm test passed" or "checks passed" or whatever. Just make sure your validation is strong in the first place; You're expected to have that done. |
| 14 | - Feedback should be useful and actionable. A couple words is OK if there is genuinely nothing to add. | 14 | - Feedback should be useful and actionable. A couple words is OK if there is genuinely nothing to add. |
| 15 | 15 | ||
| 16 | ## Verification | ||
| 17 | |||
| 18 | - Use the `code-reviewer` agent for all verification after meaningful code, config, test, or doc changes. The top-level agent should pass only a concise list of what it did, including changed files and intended behavior; the reviewer independently inspects the diff, runs relevant checks, and reports findings. The `code-reviewer` agent is told it is the reviewer agent, so it must not recurse into itself. | ||
| 19 | |||
| 16 | ## Comments | 20 | ## Comments |
| 17 | 21 | ||
| 18 | Comments must always be placed and edited with intent to serialize codebase theory for future versions of ourselves and coworkers. They are professionally written, containing relevant context to the current iteration. Clover's comments are always timeless and rarely written from the first person (no `I`, `we`) -- refer directly to the code. Rewording comments this way helps solidify your own understanding, and can even reveal logic bugs in the designed systems. Prefer documentation comments over line comments. | 22 | Comments must always be placed and edited with intent to serialize codebase theory for future versions of ourselves and coworkers. They are professionally written, containing relevant context to the current iteration. Clover's comments are always timeless and rarely written from the first person (no `I`, `we`) -- refer directly to the code. Rewording comments this way helps solidify your own understanding, and can even reveal logic bugs in the designed systems. Prefer documentation comments over line comments. |
users/clover/home.nix-4| ... | @@ -10,10 +10,6 @@ in | ... | @@ -10,10 +10,6 @@ in |
| 10 | { | 10 | { |
| 11 | home = { | 11 | home = { |
| 12 | stateVersion = "23.05"; # Please read the comment before changing. | 12 | stateVersion = "23.05"; # Please read the comment before changing. |
| 13 | sessionPath = [ | ||
| 14 | "$HOME/.vite-plus/bin" | ||
| 15 | "$HOME/.local/bin" | ||
| 16 | ]; | ||
| 17 | packages = | 13 | packages = |
| 18 | with pkgs; | 14 | with pkgs; |
| 19 | let | 15 | let |
users/clover/paperback/configuration.nix+5-1| ... | @@ -1,2 +1,6 @@ | ... | @@ -1,2 +1,6 @@ |
| 1 | _: { | 1 | { lib, ... }: |
| 2 | { | ||
| 3 | nix.enable = false; | ||
| 4 | nix.optimise.automatic = lib.mkForce false; | ||
| 5 | nix.gc.automatic = lib.mkForce false; | ||
| 2 | } | 6 | } |
users/clover/pnpm-lock.yaml+62-44| ... | @@ -1,99 +1,117 @@ | ... | @@ -1,99 +1,117 @@ |
| 1 | lockfileVersion: '9.0' | 1 | lockfileVersion: "9.0" |
| 2 | 2 | ||
| 3 | settings: | 3 | settings: |
| 4 | autoInstallPeers: true | 4 | autoInstallPeers: true |
| 5 | excludeLinksFromLockfile: false | 5 | excludeLinksFromLockfile: false |
| 6 | 6 | ||
| 7 | importers: | 7 | importers: |
| 8 | |||
| 9 | .: | 8 | .: |
| 10 | dependencies: | 9 | dependencies: |
| 11 | '@clo/lib': | 10 | "@clo/lib": |
| 12 | specifier: jsr:* | 11 | specifier: jsr:* |
| 13 | version: '@jsr/clo__lib@4.0.0' | 12 | version: "@jsr/clo__lib@4.0.0" |
| 14 | '@lydell/node-pty': | 13 | "@lydell/node-pty": |
| 15 | specifier: 1.2.0-beta.12 | 14 | specifier: 1.2.0-beta.12 |
| 16 | version: 1.2.0-beta.12 | 15 | version: 1.2.0-beta.12 |
| 17 | '@types/node': | 16 | "@types/node": |
| 18 | specifier: ^24.12.2 | 17 | specifier: ^24.12.2 |
| 19 | version: 24.12.2 | 18 | version: 24.12.2 |
| 20 | 19 | ||
| 21 | packages: | 20 | packages: |
| 22 | 21 | "@jsr/clo__lib@4.0.0": | |
| 23 | '@jsr/clo__lib@4.0.0': | 22 | resolution: { |
| 24 | resolution: {integrity: sha512-uOzRjwbFn9HizCpJeqPXzuiri3hqqcePNLA7ESi1Vgwon9dOmhMSzHfmb9kz599VsKF1RLH7i3NK302K60Oe/A==, tarball: https://npm.jsr.io/~/11/@jsr/clo__lib/4.0.0.tgz} | 23 | integrity: sha512-uOzRjwbFn9HizCpJeqPXzuiri3hqqcePNLA7ESi1Vgwon9dOmhMSzHfmb9kz599VsKF1RLH7i3NK302K60Oe/A==, |
| 25 | 24 | tarball: https://npm.jsr.io/~/11/@jsr/clo__lib/4.0.0.tgz, | |
| 26 | '@lydell/node-pty-darwin-arm64@1.2.0-beta.12': | 25 | } |
| 27 | resolution: {integrity: sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ==} | 26 | |
| 27 | "@lydell/node-pty-darwin-arm64@1.2.0-beta.12": | ||
| 28 | resolution: { | ||
| 29 | integrity: sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ==, | ||
| 30 | } | ||
| 28 | cpu: [arm64] | 31 | cpu: [arm64] |
| 29 | os: [darwin] | 32 | os: [darwin] |
| 30 | 33 | ||
| 31 | '@lydell/node-pty-darwin-x64@1.2.0-beta.12': | 34 | "@lydell/node-pty-darwin-x64@1.2.0-beta.12": |
| 32 | resolution: {integrity: sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q==} | 35 | resolution: { |
| 36 | integrity: sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q==, | ||
| 37 | } | ||
| 33 | cpu: [x64] | 38 | cpu: [x64] |
| 34 | os: [darwin] | 39 | os: [darwin] |
| 35 | 40 | ||
| 36 | '@lydell/node-pty-linux-arm64@1.2.0-beta.12': | 41 | "@lydell/node-pty-linux-arm64@1.2.0-beta.12": |
| 37 | resolution: {integrity: sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw==} | 42 | resolution: { |
| 43 | integrity: sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw==, | ||
| 44 | } | ||
| 38 | cpu: [arm64] | 45 | cpu: [arm64] |
| 39 | os: [linux] | 46 | os: [linux] |
| 40 | 47 | ||
| 41 | '@lydell/node-pty-linux-x64@1.2.0-beta.12': | 48 | "@lydell/node-pty-linux-x64@1.2.0-beta.12": |
| 42 | resolution: {integrity: sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ==} | 49 | resolution: { |
| 50 | integrity: sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ==, | ||
| 51 | } | ||
| 43 | cpu: [x64] | 52 | cpu: [x64] |
| 44 | os: [linux] | 53 | os: [linux] |
| 45 | 54 | ||
| 46 | '@lydell/node-pty-win32-arm64@1.2.0-beta.12': | 55 | "@lydell/node-pty-win32-arm64@1.2.0-beta.12": |
| 47 | resolution: {integrity: sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g==} | 56 | resolution: { |
| 57 | integrity: sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g==, | ||
| 58 | } | ||
| 48 | cpu: [arm64] | 59 | cpu: [arm64] |
| 49 | os: [win32] | 60 | os: [win32] |
| 50 | 61 | ||
| 51 | '@lydell/node-pty-win32-x64@1.2.0-beta.12': | 62 | "@lydell/node-pty-win32-x64@1.2.0-beta.12": |
| 52 | resolution: {integrity: sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw==} | 63 | resolution: { |
| 64 | integrity: sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw==, | ||
| 65 | } | ||
| 53 | cpu: [x64] | 66 | cpu: [x64] |
| 54 | os: [win32] | 67 | os: [win32] |
| 55 | 68 | ||
| 56 | '@lydell/node-pty@1.2.0-beta.12': | 69 | "@lydell/node-pty@1.2.0-beta.12": |
| 57 | resolution: {integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==} | 70 | resolution: { |
| 71 | integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==, | ||
| 72 | } | ||
| 58 | 73 | ||
| 59 | '@types/node@24.12.2': | 74 | "@types/node@24.12.2": |
| 60 | resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} | 75 | resolution: { |
| 76 | integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==, | ||
| 77 | } | ||
| 61 | 78 | ||
| 62 | undici-types@7.16.0: | 79 | undici-types@7.16.0: |
| 63 | resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} | 80 | resolution: { |
| 81 | integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==, | ||
| 82 | } | ||
| 64 | 83 | ||
| 65 | snapshots: | 84 | snapshots: |
| 85 | "@jsr/clo__lib@4.0.0": {} | ||
| 66 | 86 | ||
| 67 | '@jsr/clo__lib@4.0.0': {} | 87 | "@lydell/node-pty-darwin-arm64@1.2.0-beta.12": |
| 68 | |||
| 69 | '@lydell/node-pty-darwin-arm64@1.2.0-beta.12': | ||
| 70 | optional: true | 88 | optional: true |
| 71 | 89 | ||
| 72 | '@lydell/node-pty-darwin-x64@1.2.0-beta.12': | 90 | "@lydell/node-pty-darwin-x64@1.2.0-beta.12": |
| 73 | optional: true | 91 | optional: true |
| 74 | 92 | ||
| 75 | '@lydell/node-pty-linux-arm64@1.2.0-beta.12': | 93 | "@lydell/node-pty-linux-arm64@1.2.0-beta.12": |
| 76 | optional: true | 94 | optional: true |
| 77 | 95 | ||
| 78 | '@lydell/node-pty-linux-x64@1.2.0-beta.12': | 96 | "@lydell/node-pty-linux-x64@1.2.0-beta.12": |
| 79 | optional: true | 97 | optional: true |
| 80 | 98 | ||
| 81 | '@lydell/node-pty-win32-arm64@1.2.0-beta.12': | 99 | "@lydell/node-pty-win32-arm64@1.2.0-beta.12": |
| 82 | optional: true | 100 | optional: true |
| 83 | 101 | ||
| 84 | '@lydell/node-pty-win32-x64@1.2.0-beta.12': | 102 | "@lydell/node-pty-win32-x64@1.2.0-beta.12": |
| 85 | optional: true | 103 | optional: true |
| 86 | 104 | ||
| 87 | '@lydell/node-pty@1.2.0-beta.12': | 105 | "@lydell/node-pty@1.2.0-beta.12": |
| 88 | optionalDependencies: | 106 | optionalDependencies: |
| 89 | '@lydell/node-pty-darwin-arm64': 1.2.0-beta.12 | 107 | "@lydell/node-pty-darwin-arm64": 1.2.0-beta.12 |
| 90 | '@lydell/node-pty-darwin-x64': 1.2.0-beta.12 | 108 | "@lydell/node-pty-darwin-x64": 1.2.0-beta.12 |
| 91 | '@lydell/node-pty-linux-arm64': 1.2.0-beta.12 | 109 | "@lydell/node-pty-linux-arm64": 1.2.0-beta.12 |
| 92 | '@lydell/node-pty-linux-x64': 1.2.0-beta.12 | 110 | "@lydell/node-pty-linux-x64": 1.2.0-beta.12 |
| 93 | '@lydell/node-pty-win32-arm64': 1.2.0-beta.12 | 111 | "@lydell/node-pty-win32-arm64": 1.2.0-beta.12 |
| 94 | '@lydell/node-pty-win32-x64': 1.2.0-beta.12 | 112 | "@lydell/node-pty-win32-x64": 1.2.0-beta.12 |
| 95 | 113 | ||
| 96 | '@types/node@24.12.2': | 114 | "@types/node@24.12.2": |
| 97 | dependencies: | 115 | dependencies: |
| 98 | undici-types: 7.16.0 | 116 | undici-types: 7.16.0 |
| 99 | 117 |
users/clover/sandwich/home.nix+77-2| ... | @@ -1,7 +1,82 @@ | ... | @@ -1,7 +1,82 @@ |
| 1 | { pkgs, ... }: | 1 | { config, pkgs, ... }: |
| 2 | { | 2 | let |
| 3 | # Hourly backup: rsync the local working drives up to the NAS, then (only on a | ||
| 4 | # fully clean push) trigger a ZFS snapshot + tiered prune on the NAS. The backup | ||
| 5 | # on the NAS is plain browsable files; history lives in ZFS snapshots. | ||
| 6 | sandwich-backup = pkgs.writeShellApplication { | ||
| 7 | name = "sandwich-backup"; | ||
| 8 | runtimeInputs = with pkgs; [ | ||
| 9 | rsync | ||
| 10 | openssh | ||
| 11 | coreutils | ||
| 12 | ]; | ||
| 13 | text = '' | ||
| 14 | NAS=clo@git.paperclover.net | ||
| 15 | DEST=$NAS:/mnt/storage1/backup/sandwich | ||
| 16 | LOCK=/tmp/sandwich-backup.lock | ||
| 17 | |||
| 18 | # Dedicated passphraseless key so the launchd job runs unattended; the | ||
| 19 | # interactive key keeps its passphrase. IdentitiesOnly stops ssh from | ||
| 20 | # offering the passphrased key first. | ||
| 21 | SSH=(ssh -i "$HOME/.ssh/id_sandwich_backup" -o IdentitiesOnly=yes -o BatchMode=yes) | ||
| 22 | |||
| 23 | # Single-instance guard: the initial sync takes hours, far longer than the | ||
| 24 | # hourly interval. mkdir is atomic; recover if a previous run died uncleanly. | ||
| 25 | if ! mkdir "$LOCK" 2>/dev/null; then | ||
| 26 | if [ -f "$LOCK/pid" ] && kill -0 "$(cat "$LOCK/pid")" 2>/dev/null; then | ||
| 27 | echo "already running (pid $(cat "$LOCK/pid"))" | ||
| 28 | exit 0 | ||
| 29 | fi | ||
| 30 | echo "clearing stale lock" | ||
| 31 | rm -rf "$LOCK" | ||
| 32 | mkdir "$LOCK" | ||
| 33 | fi | ||
| 34 | echo $$ >"$LOCK/pid" | ||
| 35 | trap 'rm -rf "$LOCK"' EXIT | ||
| 36 | |||
| 37 | # rsync exit 24 (source files vanished mid-transfer) is benign on a live | ||
| 38 | # machine; anything else is a real failure and aborts before the snapshot. | ||
| 39 | rsync_one() { | ||
| 40 | local rc=0 | ||
| 41 | rsync -a --delete --partial --human-readable --stats \ | ||
| 42 | -e "''${SSH[*]}" \ | ||
| 43 | --exclude '.DS_Store' \ | ||
| 44 | --exclude '.Spotlight-V100' \ | ||
| 45 | --exclude '.Trashes' \ | ||
| 46 | --exclude '.fseventsd' \ | ||
| 47 | --exclude '.TemporaryItems' \ | ||
| 48 | --exclude '.DocumentRevisions-V100' \ | ||
| 49 | "$@" || rc=$? | ||
| 50 | if [ "$rc" -ne 0 ] && [ "$rc" -ne 24 ]; then | ||
| 51 | return "$rc" | ||
| 52 | fi | ||
| 53 | } | ||
| 3 | 54 | ||
| 55 | rsync_one /Volumes/Asset/ "$DEST/Asset/" | ||
| 56 | rsync_one /Volumes/Project/ "$DEST/Project/" | ||
| 57 | rsync_one --exclude 'LMStudio/' /Volumes/Documents/ "$DEST/Documents/" | ||
| 58 | rsync_one "$HOME/Desktop/" "$DEST/Desktop/" | ||
| 59 | |||
| 60 | # Snapshot only reached if every push above succeeded. | ||
| 61 | "''${SSH[@]}" "$NAS" /mnt/storage1/apps/home-infra/backup/snapshot-prune.sh storage1/backup/sandwich | ||
| 62 | ''; | ||
| 63 | }; | ||
| 64 | in | ||
| 65 | { | ||
| 4 | home.packages = with pkgs; [ | 66 | home.packages = with pkgs; [ |
| 5 | nodejs_24 | 67 | nodejs_24 |
| 68 | rsync | ||
| 69 | sandwich-backup | ||
| 6 | ]; | 70 | ]; |
| 71 | |||
| 72 | launchd.agents.sandwich-backup = { | ||
| 73 | enable = true; | ||
| 74 | config = { | ||
| 75 | ProgramArguments = [ "${sandwich-backup}/bin/sandwich-backup" ]; | ||
| 76 | StartInterval = 3600; | ||
| 77 | RunAtLoad = true; | ||
| 78 | StandardOutPath = "${config.home.homeDirectory}/Library/Logs/sandwich-backup.log"; | ||
| 79 | StandardErrorPath = "${config.home.homeDirectory}/Library/Logs/sandwich-backup.log"; | ||
| 80 | }; | ||
| 81 | }; | ||
| 7 | } | 82 | } |
users/clover/scripts/jj-ci.ts+76-24| ... | @@ -153,8 +153,9 @@ if (!fs.existsSync(ciScript)) { | ... | @@ -153,8 +153,9 @@ if (!fs.existsSync(ciScript)) { |
| 153 | if (invalid) process.exit(1); | 153 | if (invalid) process.exit(1); |
| 154 | 154 | ||
| 155 | if (parallelize) { | 155 | if (parallelize) { |
| 156 | if (dryRun) log.info("would run", "jj parallelize " + selectedRevisions.join(" ")); | 156 | if (dryRun) { |
| 157 | else jj(["parallelize", ...selectedRevisions]); | 157 | log.info("would run", "jj parallelize " + selectedRevisions.join(" ")); |
| 158 | } else jj(["parallelize", ...selectedRevisions]); | ||
| 158 | } | 159 | } |
| 159 | 160 | ||
| 160 | const changeIds = [...new Set(selectedRevisions.flatMap(resolveChangeIds))]; | 161 | const changeIds = [...new Set(selectedRevisions.flatMap(resolveChangeIds))]; |
| ... | @@ -185,14 +186,14 @@ const plans: Plan[] = changeIds.map((changeId) => ({ | ... | @@ -185,14 +186,14 @@ const plans: Plan[] = changeIds.map((changeId) => ({ |
| 185 | .filter((candidate) => candidate !== "" && candidate !== changeId), | 186 | .filter((candidate) => candidate !== "" && candidate !== changeId), |
| 186 | ), | 187 | ), |
| 187 | ], | 188 | ], |
| 188 | label: changeId.slice(0, 6) + ': ' + jj( | 189 | label: changeId.slice(0, 6) + ": " + jj( |
| 189 | [ | 190 | [ |
| 190 | "log", | 191 | "log", |
| 191 | "--no-graph", | 192 | "--no-graph", |
| 192 | "-r", | 193 | "-r", |
| 193 | `${changeId}`, | 194 | `${changeId}`, |
| 194 | "-T", | 195 | "-T", |
| 195 | 'self.description().first_line()', | 196 | "self.description().first_line()", |
| 196 | ], | 197 | ], |
| 197 | { ignoreWorkingCopy: true }, | 198 | { ignoreWorkingCopy: true }, |
| 198 | ), | 199 | ), |
| ... | @@ -272,7 +273,9 @@ try { | ... | @@ -272,7 +273,9 @@ try { |
| 272 | if (state === "ok") passed += 1; | 273 | if (state === "ok") passed += 1; |
| 273 | else if (state === "failed" || state === "skipped") failed += 1; | 274 | else if (state === "failed" || state === "skipped") failed += 1; |
| 274 | } | 275 | } |
| 275 | return `${ansi.fgGreen}${passed} pass${ansi.reset}, ${failed > 0 ? ansi.fgRed : ""}${failed} fail${ansi.reset}`; | 276 | return `${ansi.fgGreen}${passed} pass${ansi.reset}, ${ |
| 277 | failed > 0 ? ansi.fgRed : "" | ||
| 278 | }${failed} fail${ansi.reset}`; | ||
| 276 | }, | 279 | }, |
| 277 | }); | 280 | }); |
| 278 | 281 | ||
| ... | @@ -313,7 +316,14 @@ try { | ... | @@ -313,7 +316,14 @@ try { |
| 313 | 316 | ||
| 314 | try { | 317 | try { |
| 315 | plainLog.push("--- prep ---\n"); | 318 | plainLog.push("--- prep ---\n"); |
| 316 | ensureWorkspace(slot, plan.changeId, plan.label, trackedWorkspaces, node, plainLog); | 319 | ensureWorkspace( |
| 320 | slot, | ||
| 321 | plan.changeId, | ||
| 322 | plan.label, | ||
| 323 | trackedWorkspaces, | ||
| 324 | node, | ||
| 325 | plainLog, | ||
| 326 | ); | ||
| 317 | plainLog.push("\n"); | 327 | plainLog.push("\n"); |
| 318 | 328 | ||
| 319 | phase = "ci"; | 329 | phase = "ci"; |
| ... | @@ -324,7 +334,9 @@ try { | ... | @@ -324,7 +334,9 @@ try { |
| 324 | node, | 334 | node, |
| 325 | }); | 335 | }); |
| 326 | plainLog.push( | 336 | plainLog.push( |
| 327 | `--- ci ---\nexit: ${ci.exitCode ?? "signal"}\nduration_ms: ${ci.durationMs}\n\n`, | 337 | `--- ci ---\nexit: ${ |
| 338 | ci.exitCode ?? "signal" | ||
| 339 | }\nduration_ms: ${ci.durationMs}\n\n`, | ||
| 328 | ); | 340 | ); |
| 329 | plainLog.push(ci.plainText); | 341 | plainLog.push(ci.plainText); |
| 330 | if (ci.plainText !== "" && !ci.plainText.endsWith("\n")) { | 342 | if (ci.plainText !== "" && !ci.plainText.endsWith("\n")) { |
| ... | @@ -369,7 +381,9 @@ try { | ... | @@ -369,7 +381,9 @@ try { |
| 369 | ? (error.stack ?? error.message) | 381 | ? (error.stack ?? error.message) |
| 370 | : String(error); | 382 | : String(error); |
| 371 | node.log.error(error); | 383 | node.log.error(error); |
| 372 | plainLog.push(`--- ${phase} error ---\n${normalizePlain(message)}\n`); | 384 | plainLog.push( |
| 385 | `--- ${phase} error ---\n${normalizePlain(message)}\n`, | ||
| 386 | ); | ||
| 373 | writeFailureLog(plan.logPath, plainLog); | 387 | writeFailureLog(plan.logPath, plainLog); |
| 374 | return { | 388 | return { |
| 375 | changeId: plan.changeId, | 389 | changeId: plan.changeId, |
| ... | @@ -393,10 +407,13 @@ try { | ... | @@ -393,10 +407,13 @@ try { |
| 393 | for (const plan of plans) { | 407 | for (const plan of plans) { |
| 394 | if (stateByChangeId.get(plan.changeId) !== "pending") continue; | 408 | if (stateByChangeId.get(plan.changeId) !== "pending") continue; |
| 395 | 409 | ||
| 396 | const blockedBy = plan.dependencyChangeIds.filter((dependencyChangeId) => { | 410 | const blockedBy = plan.dependencyChangeIds.filter( |
| 397 | const dependencyState = stateByChangeId.get(dependencyChangeId); | 411 | (dependencyChangeId) => { |
| 398 | return dependencyState === "failed" || dependencyState === "skipped"; | 412 | const dependencyState = stateByChangeId.get(dependencyChangeId); |
| 399 | }); | 413 | return dependencyState === "failed" || |
| 414 | dependencyState === "skipped"; | ||
| 415 | }, | ||
| 416 | ); | ||
| 400 | 417 | ||
| 401 | if (blockedBy.length === 0) continue; | 418 | if (blockedBy.length === 0) continue; |
| 402 | 419 | ||
| ... | @@ -456,12 +473,17 @@ try { | ... | @@ -456,12 +473,17 @@ try { |
| 456 | 473 | ||
| 457 | if (!result.ok) continue; | 474 | if (!result.ok) continue; |
| 458 | 475 | ||
| 459 | for (const childChangeId of childrenByChangeId.get(result.changeId) ?? []) { | 476 | for ( |
| 477 | const childChangeId of childrenByChangeId.get(result.changeId) ?? [] | ||
| 478 | ) { | ||
| 460 | if (stateByChangeId.get(childChangeId) !== "pending") continue; | 479 | if (stateByChangeId.get(childChangeId) !== "pending") continue; |
| 461 | 480 | ||
| 462 | const remainingDependencies = | 481 | const remainingDependencies = |
| 463 | (remainingDependenciesByChangeId.get(childChangeId) ?? 1) - 1; | 482 | (remainingDependenciesByChangeId.get(childChangeId) ?? 1) - 1; |
| 464 | remainingDependenciesByChangeId.set(childChangeId, remainingDependencies); | 483 | remainingDependenciesByChangeId.set( |
| 484 | childChangeId, | ||
| 485 | remainingDependencies, | ||
| 486 | ); | ||
| 465 | 487 | ||
| 466 | if (remainingDependencies === 0) { | 488 | if (remainingDependencies === 0) { |
| 467 | const childPlan = planByChangeId.get(childChangeId); | 489 | const childPlan = planByChangeId.get(childChangeId); |
| ... | @@ -509,7 +531,14 @@ try { | ... | @@ -509,7 +531,14 @@ try { |
| 509 | summary.push( | 531 | summary.push( |
| 510 | `${ansi.style(failStyle, "x")} ${result.label} (${result.phase})`, | 532 | `${ansi.style(failStyle, "x")} ${result.label} (${result.phase})`, |
| 511 | result.blockedBy?.length | 533 | result.blockedBy?.length |
| 512 | ? ` ${ansi.style(dimStyle, `[waiting on ${result.blockedBy.map((id) => id.slice(0, 12)).join(", ")}]`)}` | 534 | ? ` ${ |
| 535 | ansi.style( | ||
| 536 | dimStyle, | ||
| 537 | `[waiting on ${ | ||
| 538 | result.blockedBy.map((id) => id.slice(0, 12)).join(", ") | ||
| 539 | }]`, | ||
| 540 | ) | ||
| 541 | }` | ||
| 513 | : "", | 542 | : "", |
| 514 | result.logPath | 543 | result.logPath |
| 515 | ? ` ${ansi.style(dimStyle, `[log ${result.logPath}]`)}` | 544 | ? ` ${ansi.style(dimStyle, `[log ${result.logPath}]`)}` |
| ... | @@ -525,7 +554,14 @@ try { | ... | @@ -525,7 +554,14 @@ try { |
| 525 | summary.push( | 554 | summary.push( |
| 526 | `${ansi.style(skipStyle, "-")} ${result.label}`, | 555 | `${ansi.style(skipStyle, "-")} ${result.label}`, |
| 527 | result.blockedBy?.length | 556 | result.blockedBy?.length |
| 528 | ? ` ${ansi.style(dimStyle, `[blocked by ${result.blockedBy.map((id) => id.slice(0, 12)).join(", ")}]`)}` | 557 | ? ` ${ |
| 558 | ansi.style( | ||
| 559 | dimStyle, | ||
| 560 | `[blocked by ${ | ||
| 561 | result.blockedBy.map((id) => id.slice(0, 12)).join(", ") | ||
| 562 | }]`, | ||
| 563 | ) | ||
| 564 | }` | ||
| 529 | : "", | 565 | : "", |
| 530 | "\n", | 566 | "\n", |
| 531 | ); | 567 | ); |
| ... | @@ -543,7 +579,9 @@ try { | ... | @@ -543,7 +579,9 @@ try { |
| 543 | if (successfulChangeIds.length > 0) { | 579 | if (successfulChangeIds.length > 0) { |
| 544 | summary.push( | 580 | summary.push( |
| 545 | "\n", | 581 | "\n", |
| 546 | `${ansi.style(infoStyle, "push successful commits:")} jj git push -c "${successfulChangeIds.join("|")}"`, | 582 | `${ansi.style(infoStyle, "push successful commits:")} jj git push -c "${ |
| 583 | successfulChangeIds.join("|") | ||
| 584 | }"`, | ||
| 547 | "\n", | 585 | "\n", |
| 548 | ); | 586 | ); |
| 549 | } | 587 | } |
| ... | @@ -616,7 +654,6 @@ function resolveGitDir(cwd: string): string | null { | ... | @@ -616,7 +654,6 @@ function resolveGitDir(cwd: string): string | null { |
| 616 | return value; | 654 | return value; |
| 617 | } | 655 | } |
| 618 | 656 | ||
| 619 | |||
| 620 | function jj(args: string[], options: CommandOptions = {}): string { | 657 | function jj(args: string[], options: CommandOptions = {}): string { |
| 621 | const result = child_process.spawnSync( | 658 | const result = child_process.spawnSync( |
| 622 | "jj", | 659 | "jj", |
| ... | @@ -637,7 +674,9 @@ function jj(args: string[], options: CommandOptions = {}): string { | ... | @@ -637,7 +674,9 @@ function jj(args: string[], options: CommandOptions = {}): string { |
| 637 | const text = stdout + stderr; | 674 | const text = stdout + stderr; |
| 638 | 675 | ||
| 639 | if (options.node && text !== "") options.node.log.write(text); | 676 | if (options.node && text !== "") options.node.log.write(text); |
| 640 | if (options.plainLog && text !== "") options.plainLog.push(normalizePlain(text)); | 677 | if (options.plainLog && text !== "") { |
| 678 | options.plainLog.push(normalizePlain(text)); | ||
| 679 | } | ||
| 641 | 680 | ||
| 642 | if (result.error) throw result.error; | 681 | if (result.error) throw result.error; |
| 643 | if (result.status !== 0) { | 682 | if (result.status !== 0) { |
| ... | @@ -891,7 +930,10 @@ function forgetPoolWorkspaces( | ... | @@ -891,7 +930,10 @@ function forgetPoolWorkspaces( |
| 891 | } | 930 | } |
| 892 | 931 | ||
| 893 | if (errors.length > 0) { | 932 | if (errors.length > 0) { |
| 894 | throw new AggregateError(errors, "failed to forget one or more jj-ci workspaces"); | 933 | throw new AggregateError( |
| 934 | errors, | ||
| 935 | "failed to forget one or more jj-ci workspaces", | ||
| 936 | ); | ||
| 895 | } | 937 | } |
| 896 | } | 938 | } |
| 897 | 939 | ||
| ... | @@ -964,7 +1006,12 @@ function runScript( | ... | @@ -964,7 +1006,12 @@ function runScript( |
| 964 | ? preferredShell | 1006 | ? preferredShell |
| 965 | : "bash"; | 1007 | : "bash"; |
| 966 | 1008 | ||
| 967 | const term = pty.spawn(shell, ["-c", 'set -o pipefail; set -eux; source "$1"', "jj-ci", scriptPath], { | 1009 | const term = pty.spawn(shell, [ |
| 1010 | "-c", | ||
| 1011 | 'set -o pipefail; set -eux; source "$1"', | ||
| 1012 | "jj-ci", | ||
| 1013 | scriptPath, | ||
| 1014 | ], { | ||
| 968 | cols: process.stdout.columns ?? 120, | 1015 | cols: process.stdout.columns ?? 120, |
| 969 | cwd: options.cwd, | 1016 | cwd: options.cwd, |
| 970 | encoding: "utf8", | 1017 | encoding: "utf8", |
| ... | @@ -1055,11 +1102,16 @@ function tryMatchDescendant( | ... | @@ -1055,11 +1102,16 @@ function tryMatchDescendant( |
| 1055 | matchedDependencyByDescendant: Map<string, string>, | 1102 | matchedDependencyByDescendant: Map<string, string>, |
| 1056 | seenDescendants: Set<string>, | 1103 | seenDescendants: Set<string>, |
| 1057 | ): boolean { | 1104 | ): boolean { |
| 1058 | for (const descendantChangeId of descendantsByChangeId.get(dependencyChangeId) ?? []) { | 1105 | for ( |
| 1106 | const descendantChangeId of descendantsByChangeId.get(dependencyChangeId) ?? | ||
| 1107 | [] | ||
| 1108 | ) { | ||
| 1059 | if (seenDescendants.has(descendantChangeId)) continue; | 1109 | if (seenDescendants.has(descendantChangeId)) continue; |
| 1060 | seenDescendants.add(descendantChangeId); | 1110 | seenDescendants.add(descendantChangeId); |
| 1061 | 1111 | ||
| 1062 | const matchedDependency = matchedDependencyByDescendant.get(descendantChangeId); | 1112 | const matchedDependency = matchedDependencyByDescendant.get( |
| 1113 | descendantChangeId, | ||
| 1114 | ); | ||
| 1063 | if ( | 1115 | if ( |
| 1064 | matchedDependency == null || | 1116 | matchedDependency == null || |
| 1065 | tryMatchDescendant( | 1117 | tryMatchDescendant( |
| ... | @@ -1092,7 +1144,7 @@ function progressAttachToScreen( | ... | @@ -1092,7 +1144,7 @@ function progressAttachToScreen( |
| 1092 | widget ??= startWidget({ | 1144 | widget ??= startWidget({ |
| 1093 | format: ({ now }) => progress.formatAnsi(now, root.active), | 1145 | format: ({ now }) => progress.formatAnsi(now, root.active), |
| 1094 | }) ?? null; | 1146 | }) ?? null; |
| 1095 | if (!widget)return; | 1147 | if (!widget) return; |
| 1096 | widget.fps = items.some((x) => x.showTotal !== false && x.total > 0) | 1148 | widget.fps = items.some((x) => x.showTotal !== false && x.total > 0) |
| 1097 | ? 15 | 1149 | ? 15 |
| 1098 | : null; | 1150 | : null; |
users/clover/work/home.nix-3| ... | @@ -25,7 +25,4 @@ | ... | @@ -25,7 +25,4 @@ |
| 25 | typescript | 25 | typescript |
| 26 | zig | 26 | zig |
| 27 | ]; | 27 | ]; |
| 28 | home.sessionPath = [ | ||
| 29 | "$HOME/.opencode/bin" | ||
| 30 | ]; | ||
| 31 | } | 28 | } |
users/natalie/laptop/configuration.nix+2-2| ... | @@ -7,7 +7,7 @@ | ... | @@ -7,7 +7,7 @@ |
| 7 | # Custom configuration modules in "modules" are shared between users, | 7 | # Custom configuration modules in "modules" are shared between users, |
| 8 | # and can be configured in this "shared" namespace | 8 | # and can be configured in this "shared" namespace |
| 9 | shared.darwin = { | 9 | shared.darwin = { |
| 10 | # macAppStoreApps = [ "wireguard" ]; | 10 | # macAppStoreApps = [ "wireguard" ]; |
| 11 | }; | 11 | }; |
| 12 | 12 | ||
| 13 | system.defaults.NSGlobalDomain."com.apple.trackpad.scaling" = 1.0; | 13 | system.defaults.NSGlobalDomain."com.apple.trackpad.scaling" = 1.0; |
| ... | @@ -40,7 +40,7 @@ | ... | @@ -40,7 +40,7 @@ |
| 40 | casks = [ | 40 | casks = [ |
| 41 | "battle-net" | 41 | "battle-net" |
| 42 | "stremio" | 42 | "stremio" |
| 43 | # "alt-tab" | 43 | # "alt-tab" |
| 44 | "legcord" | 44 | "legcord" |
| 45 | "zulip" | 45 | "zulip" |
| 46 | "zen" | 46 | "zen" |