authorgravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-05-15 01:48:42-07:00
committergravatar for git@paperclover.netclover caruso <git@paperclover.net> 2026-06-09 22:27:46-07:00
logb1b433e6c16b2ca52b33bbe8aea31734aa23212c
tree31a702ff97d856c39357a91c61fea712f7733f4b
parentf60c39943834cc26bc64c715c9b94d541e98526a
signature Signed by SSH key SHA256:xbd+BjjhyBfwk7GVoURf9Yx0gzDerHbvYv7SddNWmAs

feat: random terrifying stuff + a backup systsem


12 files changed, 289 insertions(+), 103 deletions(-)

modules/home/default.nix+6
......@@ -59,6 +59,12 @@ in
5959 home.shell = {
6060 enableShellIntegration = true;
6161 };
62 home.sessionPath = [
63 "$HOME/.local/bin"
64 "$HOME/.opencode/bin"
65 "$HOME/.vite-plus/bin"
66 "$HOME/bin"
67 ];
6268 programs = {
6369 home-manager.enable = true;
6470 nix-index.enable = true;
packages/autofmt/default.nix+9-7
......@@ -15,11 +15,13 @@ pkgs.writeTextFile {
1515 name = "autofmt";
1616 destination = "/bin/autofmt";
1717 executable = true;
18 text = builtins.replaceStrings
19 [ "#!/usr/bin/env node" ]
20 [
21 ''#!${pkgs.nodejs}/bin/node
22 process.env.PATH = "${pkgs.lib.makeBinPath runtimeInputs}:" + (process.env.PATH ?? "");''
23 ]
24 (builtins.readFile ./autofmt.js);
18 text =
19 builtins.replaceStrings
20 [ "#!/usr/bin/env node" ]
21 [
22 ''
23 #!${pkgs.nodejs}/bin/node
24 process.env.PATH = "${pkgs.lib.makeBinPath runtimeInputs}:" + (process.env.PATH ?? "");''
25 ]
26 (builtins.readFile ./autofmt.js);
2527}
packages/jj-import-merge/jj-import-merge.js+42-13
......@@ -86,10 +86,14 @@ function usage(code) {
8686 const stream = code === 0 ? process.stdout : process.stderr;
8787 stream.write(`usage: ${exe} [--all-jj] [--] <file>...\n`);
8888 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 );
9092 stream.write(`\n`);
9193 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 );
9397 stream.write(` -h show help\n`);
9498 process.exit(code);
9599}
......@@ -158,7 +162,11 @@ function processFile(file) {
158162 leftImports.start,
159163 rightImports.start,
160164 );
161 const end = projectBoundaryToOriginal(parsed.parts, leftImports.end, rightImports.end);
165 const end = projectBoundaryToOriginal(
166 parsed.parts,
167 leftImports.end,
168 rightImports.end,
169 );
162170 if (start == null || end == null || end < start) {
163171 return { kind: "noop" };
164172 }
......@@ -168,7 +176,8 @@ function processFile(file) {
168176 rightImports.statements,
169177 detectNewline(original),
170178 );
171 const updated = original.slice(0, start) + mergedImports + original.slice(end);
179 const updated = original.slice(0, start) + mergedImports +
180 original.slice(end);
172181
173182 if (updated === original) {
174183 return { kind: "noop" };
......@@ -193,7 +202,9 @@ function processFile(file) {
193202 if (formatResult.error || formatResult.status !== 0) {
194203 fs.writeFileSync(file, original, "utf8");
195204 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 );
197208 }
198209 throw new Error(`autofmt failed for ${file}`);
199210 }
......@@ -259,7 +270,9 @@ function parseConflictBlock(lines, startIndex) {
259270 continue;
260271 }
261272 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 ) {
263276 return { supported: false, nextIndex: startIndex + 1 };
264277 }
265278 index += 2;
......@@ -512,7 +525,7 @@ function scanLine(line, state) {
512525 index += 1;
513526 continue;
514527 }
515 if (char === "'" || char === "\"" || char === "`") {
528 if (char === "'" || char === '"' || char === "`") {
516529 state.stringQuote = char;
517530 continue;
518531 }
......@@ -716,12 +729,18 @@ function canMergeImports(left, right) {
716729 }
717730
718731 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 );
720736 if (defaultBinding === undefined || namespaceImport === undefined) {
721737 return false;
722738 }
723739
724 const namedSpecifiers = unique([...left.namedSpecifiers, ...right.namedSpecifiers]);
740 const namedSpecifiers = unique([
741 ...left.namedSpecifiers,
742 ...right.namedSpecifiers,
743 ]);
725744 if (namespaceImport && namedSpecifiers.length > 0) {
726745 return false;
727746 }
......@@ -731,8 +750,14 @@ function canMergeImports(left, right) {
731750
732751function mergeImports(left, right) {
733752 const defaultBinding = mergeField(left.defaultBinding, right.defaultBinding);
734 const namespaceImport = mergeField(left.namespaceImport, right.namespaceImport);
735 const namedSpecifiers = unique([...left.namedSpecifiers, ...right.namedSpecifiers]);
753 const namespaceImport = mergeField(
754 left.namespaceImport,
755 right.namespaceImport,
756 );
757 const namedSpecifiers = unique([
758 ...left.namedSpecifiers,
759 ...right.namedSpecifiers,
760 ]);
736761
737762 return {
738763 kind: "binding",
......@@ -782,13 +807,17 @@ function renderImport(analysis, newline) {
782807 pieces.push(`{ ${analysis.namedSpecifiers[0]} }`);
783808 } else {
784809 pieces.push(
785 `{${newline}${analysis.namedSpecifiers.map((spec) => ` ${spec},`).join(newline)}${newline}}`,
810 `{${newline}${
811 analysis.namedSpecifiers.map((spec) => ` ${spec},`).join(newline)
812 }${newline}}`,
786813 );
787814 }
788815 }
789816
790817 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};`,
792821 newline,
793822 );
794823}
switch+6-3
......@@ -12,13 +12,16 @@ if [ -z "$hostname" ]; then
1212 hostname="$(hostname)"
1313fi
1414printf "%s" "$hostname" >.hostname
15if [ "$(uname -o)" = "Darwin" ]; then
15if [ "$(uname -s)" = "Darwin" ]; then
1616 nh_subcommand="darwin"
1717 fallback_command="nix run .#darwin-rebuild"
18 hostname="darwinConfigurations.$hostname"
1918fi
2019if 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
2225else
2326 $fallback_command -- switch --flake '.#'"$hostname"
2427fi
users/clover/AGENTS.md+4
......@@ -13,6 +13,10 @@ You are working with Clover, an intelligent web/systems engineer. Please avoid e
1313- 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.
1414- Feedback should be useful and actionable. A couple words is OK if there is genuinely nothing to add.
1515
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
1620## Comments
1721
1822Comments 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
1010{
1111 home = {
1212 stateVersion = "23.05"; # Please read the comment before changing.
13 sessionPath = [
14 "$HOME/.vite-plus/bin"
15 "$HOME/.local/bin"
16 ];
1713 packages =
1814 with pkgs;
1915 let
users/clover/paperback/configuration.nix+5-1
......@@ -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;
26}
users/clover/pnpm-lock.yaml+62-44
......@@ -1,99 +1,117 @@
1lockfileVersion: '9.0'
1lockfileVersion: "9.0"
22
33settings:
44 autoInstallPeers: true
55 excludeLinksFromLockfile: false
66
77importers:
8
98 .:
109 dependencies:
11 '@clo/lib':
10 "@clo/lib":
1211 specifier: jsr:*
13 version: '@jsr/clo__lib@4.0.0'
14 '@lydell/node-pty':
12 version: "@jsr/clo__lib@4.0.0"
13 "@lydell/node-pty":
1514 specifier: 1.2.0-beta.12
1615 version: 1.2.0-beta.12
17 '@types/node':
16 "@types/node":
1817 specifier: ^24.12.2
1918 version: 24.12.2
2019
2120packages:
22
23 '@jsr/clo__lib@4.0.0':
24 resolution: {integrity: sha512-uOzRjwbFn9HizCpJeqPXzuiri3hqqcePNLA7ESi1Vgwon9dOmhMSzHfmb9kz599VsKF1RLH7i3NK302K60Oe/A==, tarball: https://npm.jsr.io/~/11/@jsr/clo__lib/4.0.0.tgz}
25
26 '@lydell/node-pty-darwin-arm64@1.2.0-beta.12':
27 resolution: {integrity: sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ==}
21 "@jsr/clo__lib@4.0.0":
22 resolution: {
23 integrity: sha512-uOzRjwbFn9HizCpJeqPXzuiri3hqqcePNLA7ESi1Vgwon9dOmhMSzHfmb9kz599VsKF1RLH7i3NK302K60Oe/A==,
24 tarball: https://npm.jsr.io/~/11/@jsr/clo__lib/4.0.0.tgz,
25 }
26
27 "@lydell/node-pty-darwin-arm64@1.2.0-beta.12":
28 resolution: {
29 integrity: sha512-tqaifcY9Cr41SblO1+FLzh8oxxtkNhuW9Dhl22lKme9BreYvKvxEZcdPIXTuqkJc5tagOEC4QHShKmJjLyLXLQ==,
30 }
2831 cpu: [arm64]
2932 os: [darwin]
3033
31 '@lydell/node-pty-darwin-x64@1.2.0-beta.12':
32 resolution: {integrity: sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q==}
34 "@lydell/node-pty-darwin-x64@1.2.0-beta.12":
35 resolution: {
36 integrity: sha512-4LrS5pCJwqHKDVf1zS2gyNV0m4hKAXch+XZNhbZ6LY8uwVL8BhchzQBO40Os5anuRxRCWzHpw4Sp64Ie8q7E4Q==,
37 }
3338 cpu: [x64]
3439 os: [darwin]
3540
36 '@lydell/node-pty-linux-arm64@1.2.0-beta.12':
37 resolution: {integrity: sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw==}
41 "@lydell/node-pty-linux-arm64@1.2.0-beta.12":
42 resolution: {
43 integrity: sha512-Sx+A71x5BDGHt9ansfrtGxwq2VFVDWvJUAdlUL0Hv0qeiJUfts+hgopx+CgT4PSwahKjdEgtu0+FAfY9rICKRw==,
44 }
3845 cpu: [arm64]
3946 os: [linux]
4047
41 '@lydell/node-pty-linux-x64@1.2.0-beta.12':
42 resolution: {integrity: sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ==}
48 "@lydell/node-pty-linux-x64@1.2.0-beta.12":
49 resolution: {
50 integrity: sha512-bJzs94njofYhGg/UDqW1nj0dtvvu+2OvxMY+RlLS1T17VgcktKoIR6PuenTwE5HJ/D6StCPADmXcT0nNsCKmIQ==,
51 }
4352 cpu: [x64]
4453 os: [linux]
4554
46 '@lydell/node-pty-win32-arm64@1.2.0-beta.12':
47 resolution: {integrity: sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g==}
55 "@lydell/node-pty-win32-arm64@1.2.0-beta.12":
56 resolution: {
57 integrity: sha512-p7POgjVEiFaBC3/y+AKuV1FzePCsJ6HmZDv2XK+jBZSfwP8+uBAw181ZiKYN1YuRa/XpmBGaWezcI8hZkbW++g==,
58 }
4859 cpu: [arm64]
4960 os: [win32]
5061
51 '@lydell/node-pty-win32-x64@1.2.0-beta.12':
52 resolution: {integrity: sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw==}
62 "@lydell/node-pty-win32-x64@1.2.0-beta.12":
63 resolution: {
64 integrity: sha512-IDFa00g7qUDGUYgByrUBJtC+mOjYVt/8KYyWivCg5JjGOHbBUACUQZLl0jTWmnr+tld/UyTpX90a2PY6oTVtRw==,
65 }
5366 cpu: [x64]
5467 os: [win32]
5568
56 '@lydell/node-pty@1.2.0-beta.12':
57 resolution: {integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==}
69 "@lydell/node-pty@1.2.0-beta.12":
70 resolution: {
71 integrity: sha512-qIK890UwPupoj07osVvgOIa++1mxeHbcGry4PKRHhNVNs81V2SCG34eJr46GybiOmBtc8Sj5PB1/GGM5PL549g==,
72 }
5873
59 '@types/node@24.12.2':
60 resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==}
74 "@types/node@24.12.2":
75 resolution: {
76 integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==,
77 }
6178
6279 undici-types@7.16.0:
63 resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
80 resolution: {
81 integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==,
82 }
6483
6584snapshots:
85 "@jsr/clo__lib@4.0.0": {}
6686
67 '@jsr/clo__lib@4.0.0': {}
68
69 '@lydell/node-pty-darwin-arm64@1.2.0-beta.12':
87 "@lydell/node-pty-darwin-arm64@1.2.0-beta.12":
7088 optional: true
7189
72 '@lydell/node-pty-darwin-x64@1.2.0-beta.12':
90 "@lydell/node-pty-darwin-x64@1.2.0-beta.12":
7391 optional: true
7492
75 '@lydell/node-pty-linux-arm64@1.2.0-beta.12':
93 "@lydell/node-pty-linux-arm64@1.2.0-beta.12":
7694 optional: true
7795
78 '@lydell/node-pty-linux-x64@1.2.0-beta.12':
96 "@lydell/node-pty-linux-x64@1.2.0-beta.12":
7997 optional: true
8098
81 '@lydell/node-pty-win32-arm64@1.2.0-beta.12':
99 "@lydell/node-pty-win32-arm64@1.2.0-beta.12":
82100 optional: true
83101
84 '@lydell/node-pty-win32-x64@1.2.0-beta.12':
102 "@lydell/node-pty-win32-x64@1.2.0-beta.12":
85103 optional: true
86104
87 '@lydell/node-pty@1.2.0-beta.12':
105 "@lydell/node-pty@1.2.0-beta.12":
88106 optionalDependencies:
89 '@lydell/node-pty-darwin-arm64': 1.2.0-beta.12
90 '@lydell/node-pty-darwin-x64': 1.2.0-beta.12
91 '@lydell/node-pty-linux-arm64': 1.2.0-beta.12
92 '@lydell/node-pty-linux-x64': 1.2.0-beta.12
93 '@lydell/node-pty-win32-arm64': 1.2.0-beta.12
94 '@lydell/node-pty-win32-x64': 1.2.0-beta.12
95
96 '@types/node@24.12.2':
107 "@lydell/node-pty-darwin-arm64": 1.2.0-beta.12
108 "@lydell/node-pty-darwin-x64": 1.2.0-beta.12
109 "@lydell/node-pty-linux-arm64": 1.2.0-beta.12
110 "@lydell/node-pty-linux-x64": 1.2.0-beta.12
111 "@lydell/node-pty-win32-arm64": 1.2.0-beta.12
112 "@lydell/node-pty-win32-x64": 1.2.0-beta.12
113
114 "@types/node@24.12.2":
97115 dependencies:
98116 undici-types: 7.16.0
99117
users/clover/sandwich/home.nix+77-2
......@@ -1,7 +1,82 @@
1{ pkgs, ... }:
2{
1{ config, pkgs, ... }:
2let
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 }
354
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 };
64in
65{
466 home.packages = with pkgs; [
567 nodejs_24
68 rsync
69 sandwich-backup
670 ];
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 };
782}
users/clover/scripts/jj-ci.ts+76-24
......@@ -153,8 +153,9 @@ if (!fs.existsSync(ciScript)) {
153153if (invalid) process.exit(1);
154154
155155if (parallelize) {
156 if (dryRun) log.info("would run", "jj parallelize " + selectedRevisions.join(" "));
157 else jj(["parallelize", ...selectedRevisions]);
156 if (dryRun) {
157 log.info("would run", "jj parallelize " + selectedRevisions.join(" "));
158 } else jj(["parallelize", ...selectedRevisions]);
158159}
159160
160161const changeIds = [...new Set(selectedRevisions.flatMap(resolveChangeIds))];
......@@ -185,14 +186,14 @@ const plans: Plan[] = changeIds.map((changeId) => ({
185186 .filter((candidate) => candidate !== "" && candidate !== changeId),
186187 ),
187188 ],
188 label: changeId.slice(0, 6) + ': ' + jj(
189 label: changeId.slice(0, 6) + ": " + jj(
189190 [
190191 "log",
191192 "--no-graph",
192193 "-r",
193194 `${changeId}`,
194195 "-T",
195 'self.description().first_line()',
196 "self.description().first_line()",
196197 ],
197198 { ignoreWorkingCopy: true },
198199 ),
......@@ -272,7 +273,9 @@ try {
272273 if (state === "ok") passed += 1;
273274 else if (state === "failed" || state === "skipped") failed += 1;
274275 }
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}`;
276279 },
277280 });
278281
......@@ -313,7 +316,14 @@ try {
313316
314317 try {
315318 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 );
317327 plainLog.push("\n");
318328
319329 phase = "ci";
......@@ -324,7 +334,9 @@ try {
324334 node,
325335 });
326336 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`,
328340 );
329341 plainLog.push(ci.plainText);
330342 if (ci.plainText !== "" && !ci.plainText.endsWith("\n")) {
......@@ -369,7 +381,9 @@ try {
369381 ? (error.stack ?? error.message)
370382 : String(error);
371383 node.log.error(error);
372 plainLog.push(`--- ${phase} error ---\n${normalizePlain(message)}\n`);
384 plainLog.push(
385 `--- ${phase} error ---\n${normalizePlain(message)}\n`,
386 );
373387 writeFailureLog(plan.logPath, plainLog);
374388 return {
375389 changeId: plan.changeId,
......@@ -393,10 +407,13 @@ try {
393407 for (const plan of plans) {
394408 if (stateByChangeId.get(plan.changeId) !== "pending") continue;
395409
396 const blockedBy = plan.dependencyChangeIds.filter((dependencyChangeId) => {
397 const dependencyState = stateByChangeId.get(dependencyChangeId);
398 return dependencyState === "failed" || dependencyState === "skipped";
399 });
410 const blockedBy = plan.dependencyChangeIds.filter(
411 (dependencyChangeId) => {
412 const dependencyState = stateByChangeId.get(dependencyChangeId);
413 return dependencyState === "failed" ||
414 dependencyState === "skipped";
415 },
416 );
400417
401418 if (blockedBy.length === 0) continue;
402419
......@@ -456,12 +473,17 @@ try {
456473
457474 if (!result.ok) continue;
458475
459 for (const childChangeId of childrenByChangeId.get(result.changeId) ?? []) {
476 for (
477 const childChangeId of childrenByChangeId.get(result.changeId) ?? []
478 ) {
460479 if (stateByChangeId.get(childChangeId) !== "pending") continue;
461480
462481 const remainingDependencies =
463482 (remainingDependenciesByChangeId.get(childChangeId) ?? 1) - 1;
464 remainingDependenciesByChangeId.set(childChangeId, remainingDependencies);
483 remainingDependenciesByChangeId.set(
484 childChangeId,
485 remainingDependencies,
486 );
465487
466488 if (remainingDependencies === 0) {
467489 const childPlan = planByChangeId.get(childChangeId);
......@@ -509,7 +531,14 @@ try {
509531 summary.push(
510532 `${ansi.style(failStyle, "x")} ${result.label} (${result.phase})`,
511533 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 }`
513542 : "",
514543 result.logPath
515544 ? ` ${ansi.style(dimStyle, `[log ${result.logPath}]`)}`
......@@ -525,7 +554,14 @@ try {
525554 summary.push(
526555 `${ansi.style(skipStyle, "-")} ${result.label}`,
527556 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 }`
529565 : "",
530566 "\n",
531567 );
......@@ -543,7 +579,9 @@ try {
543579 if (successfulChangeIds.length > 0) {
544580 summary.push(
545581 "\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 }"`,
547585 "\n",
548586 );
549587 }
......@@ -616,7 +654,6 @@ function resolveGitDir(cwd: string): string | null {
616654 return value;
617655}
618656
619
620657function jj(args: string[], options: CommandOptions = {}): string {
621658 const result = child_process.spawnSync(
622659 "jj",
......@@ -637,7 +674,9 @@ function jj(args: string[], options: CommandOptions = {}): string {
637674 const text = stdout + stderr;
638675
639676 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 }
641680
642681 if (result.error) throw result.error;
643682 if (result.status !== 0) {
......@@ -891,7 +930,10 @@ function forgetPoolWorkspaces(
891930 }
892931
893932 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 );
895937 }
896938}
897939
......@@ -964,7 +1006,12 @@ function runScript(
9641006 ? preferredShell
9651007 : "bash";
9661008
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 ], {
9681015 cols: process.stdout.columns ?? 120,
9691016 cwd: options.cwd,
9701017 encoding: "utf8",
......@@ -1055,11 +1102,16 @@ function tryMatchDescendant(
10551102 matchedDependencyByDescendant: Map<string, string>,
10561103 seenDescendants: Set<string>,
10571104): boolean {
1058 for (const descendantChangeId of descendantsByChangeId.get(dependencyChangeId) ?? []) {
1105 for (
1106 const descendantChangeId of descendantsByChangeId.get(dependencyChangeId) ??
1107 []
1108 ) {
10591109 if (seenDescendants.has(descendantChangeId)) continue;
10601110 seenDescendants.add(descendantChangeId);
10611111
1062 const matchedDependency = matchedDependencyByDescendant.get(descendantChangeId);
1112 const matchedDependency = matchedDependencyByDescendant.get(
1113 descendantChangeId,
1114 );
10631115 if (
10641116 matchedDependency == null ||
10651117 tryMatchDescendant(
......@@ -1092,7 +1144,7 @@ function progressAttachToScreen(
10921144 widget ??= startWidget({
10931145 format: ({ now }) => progress.formatAnsi(now, root.active),
10941146 }) ?? null;
1095 if (!widget)return;
1147 if (!widget) return;
10961148 widget.fps = items.some((x) => x.showTotal !== false && x.total > 0)
10971149 ? 15
10981150 : null;
users/clover/work/home.nix-3
......@@ -25,7 +25,4 @@
2525 typescript
2626 zig
2727 ];
28 home.sessionPath = [
29 "$HOME/.opencode/bin"
30 ];
3128}
users/natalie/laptop/configuration.nix+2-2
......@@ -7,7 +7,7 @@
77 # Custom configuration modules in "modules" are shared between users,
88 # and can be configured in this "shared" namespace
99 shared.darwin = {
10# macAppStoreApps = [ "wireguard" ];
10 # macAppStoreApps = [ "wireguard" ];
1111 };
1212
1313 system.defaults.NSGlobalDomain."com.apple.trackpad.scaling" = 1.0;
......@@ -40,7 +40,7 @@
4040 casks = [
4141 "battle-net"
4242 "stremio"
43# "alt-tab"
43 # "alt-tab"
4444 "legcord"
4545 "zulip"
4646 "zen"