From 6427d188e664cd1f9f9b3f2b4dcb30deeb096a20 Mon Sep 17 00:00:00 2001 From: Joseph O'Brien Date: Wed, 8 Jul 2026 13:07:42 -0400 Subject: [PATCH] feat(notfiles): hexagonal architecture refactor with adapters, integration tests, and notsecrets cleanup - Extract FileStore port and InMemoryFileStore/FileStoreImpl/Reporter adapters - Add Reporter trait to notcore with TerminalReporter and JsonReporter - Refactor linker, package, status modules to use FileStore port - Add integration test suite with dotfiles fixtures - Add cross-crate integration tests - Remove ssh_rsa identity/recipient (unsupported) - Add rustqual.toml, .sccignore, notfiles.toml config files - Update CLAUDE.md, README.md, AGENTS.md with current architecture --- .DS_Store | Bin 0 -> 10244 bytes .claude/.DS_Store | Bin 0 -> 6148 bytes .claude/settings.local.json | 27 ++ .codex/hooks.json | 25 ++ .ctx/HANDOFF.md | 4 +- .ctx/HANDOFF.notfiles.notfiles.yaml | 29 +- .notfiles-state.toml | 76 +++++ .sccignore | 11 + .../brainstorm/72758-1776397235/.DS_Store | Bin 0 -> 8196 bytes .../72758-1776397235/state/server-stopped | 1 + AGENTS.md | 110 +++++++ CLAUDE.md | 69 ++++- Cargo.lock | 17 +- Cargo.toml | 8 + README.md | 64 +++- crates/.DS_Store | Bin 0 -> 8196 bytes crates/notcore/Cargo.toml | 6 + crates/notcore/src/config.rs | 161 ++++++++++ crates/notcore/src/error.rs | 6 + crates/notcore/src/lib.rs | 10 +- crates/notcore/src/reporter.rs | 46 +++ crates/notfiles/.DS_Store | Bin 0 -> 6148 bytes crates/notfiles/Cargo.toml | 6 + crates/notfiles/src/adapters/memory.rs | 293 ++++++++++++++++++ crates/notfiles/src/adapters/mod.rs | 4 + crates/notfiles/src/adapters/reporter.rs | 81 +++++ crates/notfiles/src/ignore.rs | 4 +- crates/notfiles/src/linker.rs | 274 +++++++++++----- crates/notfiles/src/package.rs | 85 ++++- crates/notfiles/src/status.rs | 137 ++++++++ .../tests/fixtures/dotfiles/README.md | 23 ++ .../.config/alacritty/alacritty.toml | 2 + .../dotfiles/docs/bootstrap-runbook.md | 3 + .../dotfiles/fish/.config/fish/config.fish | 2 + .../tests/fixtures/dotfiles/git/.gitconfig | 5 + .../dotfiles/mise/.config/mise/config.toml | 2 + .../fixtures/dotfiles/nixos/configuration.nix | 4 + .../tests/fixtures/dotfiles/notfiles.toml | 34 ++ .../.config/nushell/autoload/aliases.nu | 2 + .../nushell/.config/nushell/config.nu | 2 + .../dotfiles/nushell/.config/nushell/env.nu | 2 + .../tests/fixtures/dotfiles/scripts/doctor.sh | 3 + .../fixtures/dotfiles/scripts/lib/common.sh | 3 + .../dotfiles/secrets/.env.json.example | 3 + .../dotfiles/starship/.config/starship.toml | 2 + .../Code/User/settings.json | 4 + .../tests/fixtures/dotfiles/zsh/.zshrc | 2 + crates/notfiles/tests/integration.rs | 161 ++++++++++ crates/notgraph/.DS_Store | Bin 0 -> 6148 bytes crates/nothooks/.DS_Store | Bin 0 -> 6148 bytes crates/notsecrets/.DS_Store | Bin 0 -> 6148 bytes crates/notsecrets/Cargo.toml | 1 - crates/notsecrets/src/identities/mod.rs | 3 - crates/notsecrets/src/identities/ssh_rsa.rs | 110 ------- crates/notsecrets/src/lib.rs | 8 +- crates/notsecrets/src/recipients/mod.rs | 3 - crates/notsecrets/src/recipients/ssh_rsa.rs | 38 --- docs/superpowers/.DS_Store | Bin 0 -> 6148 bytes notfiles.toml | 7 + nushell/.DS_Store | Bin 0 -> 8196 bytes nushell/.config/.DS_Store | Bin 0 -> 8196 bytes nushell/.config/nushell/.DS_Store | Bin 0 -> 6148 bytes rustqual.toml | 99 ++++++ tests/integration/tests/cross_crate.rs | 127 ++++++++ 64 files changed, 1922 insertions(+), 287 deletions(-) create mode 100644 .DS_Store create mode 100644 .claude/.DS_Store create mode 100644 .claude/settings.local.json create mode 100644 .codex/hooks.json create mode 100644 .notfiles-state.toml create mode 100644 .sccignore create mode 100644 .superpowers/brainstorm/72758-1776397235/.DS_Store create mode 100644 .superpowers/brainstorm/72758-1776397235/state/server-stopped create mode 100644 AGENTS.md create mode 100644 crates/.DS_Store create mode 100644 crates/notcore/src/reporter.rs create mode 100644 crates/notfiles/.DS_Store create mode 100644 crates/notfiles/src/adapters/memory.rs create mode 100644 crates/notfiles/src/adapters/reporter.rs create mode 100644 crates/notfiles/tests/fixtures/dotfiles/README.md create mode 100644 crates/notfiles/tests/fixtures/dotfiles/alacritty/.config/alacritty/alacritty.toml create mode 100644 crates/notfiles/tests/fixtures/dotfiles/docs/bootstrap-runbook.md create mode 100644 crates/notfiles/tests/fixtures/dotfiles/fish/.config/fish/config.fish create mode 100644 crates/notfiles/tests/fixtures/dotfiles/git/.gitconfig create mode 100644 crates/notfiles/tests/fixtures/dotfiles/mise/.config/mise/config.toml create mode 100644 crates/notfiles/tests/fixtures/dotfiles/nixos/configuration.nix create mode 100644 crates/notfiles/tests/fixtures/dotfiles/notfiles.toml create mode 100644 crates/notfiles/tests/fixtures/dotfiles/nushell/.config/nushell/autoload/aliases.nu create mode 100644 crates/notfiles/tests/fixtures/dotfiles/nushell/.config/nushell/config.nu create mode 100644 crates/notfiles/tests/fixtures/dotfiles/nushell/.config/nushell/env.nu create mode 100644 crates/notfiles/tests/fixtures/dotfiles/scripts/doctor.sh create mode 100644 crates/notfiles/tests/fixtures/dotfiles/scripts/lib/common.sh create mode 100644 crates/notfiles/tests/fixtures/dotfiles/secrets/.env.json.example create mode 100644 crates/notfiles/tests/fixtures/dotfiles/starship/.config/starship.toml create mode 100644 crates/notfiles/tests/fixtures/dotfiles/vscode/Library/Application Support/Code/User/settings.json create mode 100644 crates/notfiles/tests/fixtures/dotfiles/zsh/.zshrc create mode 100644 crates/notgraph/.DS_Store create mode 100644 crates/nothooks/.DS_Store create mode 100644 crates/notsecrets/.DS_Store delete mode 100644 crates/notsecrets/src/identities/ssh_rsa.rs delete mode 100644 crates/notsecrets/src/recipients/ssh_rsa.rs create mode 100644 docs/superpowers/.DS_Store create mode 100644 notfiles.toml create mode 100644 nushell/.DS_Store create mode 100644 nushell/.config/.DS_Store create mode 100644 nushell/.config/nushell/.DS_Store create mode 100644 rustqual.toml diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..ddc1af161c8e34234b0b63bdebaa5e173cb45caf GIT binary patch literal 10244 zcmeHMdu$xV8J}^KnT?sgk5+1oX{ zdv}3gu&65D3E?l^0wmrdB2@zsl`7PhKoLb%8y1fmF(B0%SdINp>dJUYcG zn>z5pwg5=0u$x`@j{5+n6ZdGsqf?wRRkX=>58$bSx5WUij{GBnGr}}S1q}iWQajh{{4G)f(eToPR^9bT77+K!%8DZ zT)$xQ&{MC!v9_F)`Zc5`#_4H+=S^;-PHPw*i=HKrz5F!6;}iHK%=cq?Z`0^U?|jCv z1Z-rjX(W|o0yy|2RK;+(Aq-;mU5KH?^ZVcbZ~MpBonrod{Au6i_yNCC98ELZyNOQR zz}Op3tnu^we)m4)`28|n|Cr111AaH(NBz>6F8j)}N^vjQ z@MEYX6TrbIeVUKl#yDnVI*6oY9U=)y__2(Ab^OD`FH8C8v*SloSt^JpfzF78cx;SG zmfdN5+Cfa`yj5Pxk89ZnrQ9fE&yVf&l4bD8h|j@DO;BX`v`B%yIYE@|w;;-jvVN?m z?B^c*;!PIA)5uTf_1BRP;%1Xe9pWw^TAS=4E{m{6LYQgzNm)5R-Ur_P-MZC0|0>8% zWBq@!L7dEg4bF}>&WKKkHoDnU=62fr* zYsf9}{Qf(;b{=W_)SHhyU4N#P;|KiKFu%3L#O!j&IF8>SM!Mikc(eb}^n{^1Zd==X zAk3<&uBjDk#d`6&%V)`hL)(T& z^zCGn+G*i{h-NSj^ z(bI-DXr{8-9B7rKN+=Gxq5#|4<=BvsN^6FqN?dJa zmmC|;^EfM;yw254a%==w7FisMY)kd!F-6pVps;Npc_`hrO*cha1CsQ9k2`1kO394V1o-e$iuDh6Sy7j zfIH!ScnBVWN8vGe23~^0@Kg9XyajK=Z{ZzyA3laZ!(ZU!UkchFf8oiBNB>5H_F?^r;x(8aM3w=Zz>TERVbHAYsCuZ{^ zns@g6IIXNpE?-+pLY}q7MD?dX%lSa1u$*T(5z5!&u?6Rx+q_UduULuU3LU~?(e{e8 zHkDc~y+l4=#9~pZd2^}!0};zaso~Am=8HuvOhsT#xxKkl!tzsQ@n&oDDoIp;H&)A+ zNmz(V6>lz-6OyD5)@bf+UMFHPDc@R_pCBKTzmb2CFEPt!!(7bmrO*bKz#6y;u7-Zh z>m&@pP8fp}W;e}k6DHsWaNuT`#QdIu+u&}v2lm4OIEXp^FlIT;@n_+AcmZC7m*EvS z3a`Si;MZ^r-hkg=*8c(i2%o^G@Xt^#Zz*Omr|_?tx$OV&rVC$8c^iRH#`{0Nm8Ak7 zVVI&$Lw52>+cYe5H*#pb)#B%wE>d({{<)zA0_k2pQ^JpSedF~9@8rw9kR3nT%2ENe zWB{GvlE}pcla0%GEx3(YdFzvh!+bxMntP5s;zcfC!;hqrj2}nWO$mylnlIXB#$@9& zL9QRe$PY!%{&)Uoz-i73f|EE!8Qk9o_KDH{KidEEbC2)c{{MeOUY_Ov literal 0 HcmV?d00001 diff --git a/.claude/.DS_Store b/.claude/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..3a51aa2daa11f40aeb81b4a26b288a55ae0102cd GIT binary patch literal 6148 zcmeHKO-e&C5T4O4o^;ct%WT}Z>kZQKJVDoj)QW;FuUJdB0ng((yo?KPpx^u`eHg)o zh{#OIe3Q&flJ`NA3=#2kyBHIVh^RpmWHBlt!&TRT2M>U(bKKJ%UE#M`URNgii$k*a zBid1io!`>l{>QV+Znf4eH>W4{s8!dt^JO=Ow|RctJeg;d^2)=v$yi_MK=&C z7zhS}fnXpQ_(2A6XNxpL!_dJ%Fc1uUFd*kcLKDo6#ZZq9C@lei@{Cr2EwzN?B**Mn z4B>&Wr2;LLy~JQk$9VF%>{tvfo!E;H_Lbj@7uMA=f6{Q`Y#2Hi2nPBL99nlI_x~CG zGSwo#pAx-bAQ<>(4Dg_xwNreQ->siMPwv`;c7Y}$aYYOW?A{{)9XUsi)oK1DHsZ2l VF_c+kT+@N^5Kuxw1p~jpz#CD`G>HHJ literal 0 HcmV?d00001 diff --git a/.claude/settings.local.json b/.claude/settings.local.json new file mode 100644 index 0000000..ca90aa8 --- /dev/null +++ b/.claude/settings.local.json @@ -0,0 +1,27 @@ +{ + "permissions": { + "allow": [ + "Bash(doob:*)", + "Bash(echo:*)", + "Bash(gh:*)", + "Bash(op:*)", + "Bash(obfsck:*)", + "Bash(head:*)", + "Bash(git ls-files:*)", + "WebSearch", + "WebFetch(domain:www.apache.org)", + "Skill(todo:*)", + "Bash(PATH=\"/Users/joe/.local/share/mise/shims:$PATH\" which nu)", + "Bash(PATH=\"/Users/joe/.local/share/mise/shims:$PATH\" nu --version 2>&1 | head -1)", + "Bash(doob todo:*)", + "Bash(handoff-detect 2>&1; echo \"exit: $?\")", + "Bash(handoff-detect --name && handoff-detect --project)", + "Bash(rtk gain:*)", + "Bash(rtk rewrite:*)", + "Bash(rtk grep:*)", + "Bash(nu -c '\nlet result = \\(do { python3 -c \"import json; print\\(json.dumps\\({\\\\\"ok\\\\\": True}\\)\\)\" } | complete\\)\nprint $result.stdout\n')", + "Bash(echo '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"grep -n \\\\\"^foo\\\\\" /file.md\"}}' | nu /Users/joe/.claude/hooks/nu/pre/grep-to-grep-tool.nu)", + "Bash(echo '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"grep -c pattern file.txt\"}}' | nu /Users/joe/.claude/hooks/nu/pre/grep-to-grep-tool.nu\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"grep -i \\\\\"Hello World\\\\\" /dir/\"}}' | nu /Users/joe/.claude/hooks/nu/pre/grep-to-grep-tool.nu\necho '{\"tool_name\":\"Bash\",\"tool_input\":{\"command\":\"git status\"}}' | nu /Users/joe/.claude/hooks/nu/pre/grep-to-grep-tool.nu; echo \"exit: $?\")" + ] + } +} diff --git a/.codex/hooks.json b/.codex/hooks.json new file mode 100644 index 0000000..e6284b9 --- /dev/null +++ b/.codex/hooks.json @@ -0,0 +1,25 @@ +{ + "hooks": { + "PostToolUse": [ + { + "matcher": "Edit|Write", + "hooks": [ + { + "type": "command", + "command": "bash -c 'if [ -f Cargo.toml ]; then cargo check --quiet 2>&1 | head -20; fi'" + } + ] + } + ], + "SessionStart": [ + { + "hooks": [ + { + "type": "command", + "command": "nu /Users/joe/dev/notfiles/scripts/preflight.nu" + } + ] + } + ] + } +} diff --git a/.ctx/HANDOFF.md b/.ctx/HANDOFF.md index 4adaeb6..54c4cd9 100644 --- a/.ctx/HANDOFF.md +++ b/.ctx/HANDOFF.md @@ -1,4 +1,4 @@ -# Handoff — notfiles (2026-06-06) +# Handoff — notfiles (2026-07-07) **Branch:** main | **Build:** unknown | **Tests:** unknown @@ -6,9 +6,11 @@ | ID | P | Status | Title | |---|---|---|---| +| uncommitted-work | P1 | open | Uncommitted changes (3 files) | ## Log +- 20260606.135918: done=13 running=0 pending=0 blocked=0 - 2026-04-17: Added notnet crate with YubikeySource and threaded Tailscale into notstrap; design spec complete - 2026-04-15: Hardened bootstrap and hook-state failure handling, made notfiles FileStore usage real, and fixed copy-drift safety coverage - 2026-04-15: Pruned completed items from handoff; GitHub issues plus doob are now the source of truth for active work diff --git a/.ctx/HANDOFF.notfiles.notfiles.yaml b/.ctx/HANDOFF.notfiles.notfiles.yaml index 4948220..0b9d98b 100644 --- a/.ctx/HANDOFF.notfiles.notfiles.yaml +++ b/.ctx/HANDOFF.notfiles.notfiles.yaml @@ -1,8 +1,28 @@ project: notfiles id: notfile -updated: 2026-06-06 -items: [] +updated: 2026-07-07 +items: +- id: uncommitted-work + doob_uuid: null + name: uncommitted-work + priority: P1 + status: open + title: Uncommitted changes (3 files) + description: |- + Working tree has uncommitted changes: + .claude/worktrees/agent-a27fe5f2 + .claude/settings.local.json + .superpowers/brainstorm/72758-1776397235/state/server-stopped + files: + - .claude/worktrees/agent-a27fe5f2 + - .claude/settings.local.json + - .superpowers/brainstorm/72758-1776397235/state/server-stopped + completed: null + extra: [] log: +- date: '20260606.135918' + summary: done=13 running=0 pending=0 blocked=0 + commits: [] - date: 2026-04-17 summary: Added notnet crate with YubikeySource and threaded Tailscale into notstrap; design spec complete commits: [] @@ -12,8 +32,3 @@ log: - date: 2026-04-15 summary: Pruned completed items from handoff; GitHub issues plus doob are now the source of truth for active work commits: [] -branch: main -state: - tests: passing - build: clean - notes: Handoff is now ephemeral; track active work via GitHub issues synced through doob. diff --git a/.notfiles-state.toml b/.notfiles-state.toml new file mode 100644 index 0000000..7b71b67 --- /dev/null +++ b/.notfiles-state.toml @@ -0,0 +1,76 @@ +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/aliases.nu" +target = "/Users/joe/.config/nushell/autoload/aliases.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728685+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/audit.nu" +target = "/Users/joe/.config/nushell/autoload/audit.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728734+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/did-you-mean.nu" +target = "/Users/joe/.config/nushell/autoload/did-you-mean.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728773+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/functions.nu" +target = "/Users/joe/.config/nushell/autoload/functions.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728809+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/nu_libs.nu" +target = "/Users/joe/.config/nushell/autoload/nu_libs.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728847+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/nuenv.nu" +target = "/Users/joe/.config/nushell/autoload/nuenv.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728879+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/session-guard.nu" +target = "/Users/joe/.config/nushell/autoload/session-guard.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728915+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/settings.nu" +target = "/Users/joe/.config/nushell/autoload/settings.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728947+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/autoload/toolkit-hook.nu" +target = "/Users/joe/.config/nushell/autoload/toolkit-hook.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.728981+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/config.nu" +target = "/Users/joe/.config/nushell/config.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.729023+00:00" + +[[entries]] +package = "nushell" +source = "/Users/joe/dev/notfiles/nushell/.config/nushell/env.nu" +target = "/Users/joe/.config/nushell/env.nu" +method = "symlink" +linked_at = "2026-06-14T04:23:50.729055+00:00" diff --git a/.sccignore b/.sccignore new file mode 100644 index 0000000..43f2eb5 --- /dev/null +++ b/.sccignore @@ -0,0 +1,11 @@ +.ctx +.kgx +.github +.claude +docs +examples +fuzz +target +*.md +*.json +tests/ diff --git a/.superpowers/brainstorm/72758-1776397235/.DS_Store b/.superpowers/brainstorm/72758-1776397235/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..9ad8929eae4d39b9e9bf01228b1a944d259b6f6c GIT binary patch literal 8196 zcmeHMYitx%6u#fI&>1_xv=%7HrdyX+aIxD`k%Hi|EiY*W*_LigvF>ANN2W7%XLidY zH6;e$iN;srFMR)O)M&&Q6#Zr5E1HHx5{Xe0@sGdwg9+%lb7u){ZK8=WpmURZ&pr1% zX3p8~+}k^4j3H6TH8NJq7?Y`Us#VhPCymQ_pVlOQrJN|po-v(S%*~8A!x?j$cCZj+ zAjm+Ffgl4x27(M+3mKp@n>Treb6-e$Bo6#Kq@PrHM>HtkSpc=$w7N0 z>89O+lSt?Hajw(0%}i;Y&g?bxk$$bF)wbNUVd;6#z{u&O(${TRIeR2w7p$D)*(QZR zR%E4Lt37(Osby_6yr!jPG#WnI(iDq^o7b!z9aZG{k%kR>`VX2zmi@R01pa2g=1d9f ziRn?9PO&v(@~Fy^rKrx9qEc?CROhJOsh(c7FJ)wHD`_0j`?Yxvg|>s(-Fdx8A$4bM zvoK^i{aRHvZDtE*+SNCkCRe7lc}_NOo91rYF_3;u5P;hj`)@x9rsMk)2gb~ z8g)T;(Qu56sdtSSId`xp?PPT;XIKNhlwZp=4j6h~sX|ogw9-TRM0M?=#WyVpg{Eqk zyrc>lJ@<$Zj;HLuesmep0EsG_Ci zPKOdCTr{YSismSt2MGkiv{_v%YdNLMOlNdcEVZZ`WNoL?T@;av#TxZaSxIH>p&<&! z5o?K1o2-2*-^(A|o_5?_!@5;^r9^1EEcZHt>Ab#cgdkY5XqRR0hoyCHvL$D@cHYaz z-SweR4|laWm(z0;^y1n@)uCjlOV++28_lqa27#V_3xRzlQbJuMzDi6Zrw3m0W?qh! znv#M~`5_l#%h@^>XPxW-72PrRBs;<0VW-%K>?!8 z8V!h{5$mx58?gyH(TOhXMFt09!h#JKqj(TwIEIJu6rRR2cor|>6}*bq@dn269!}zY ze1gyLIljbKIESBc9>3rMF5xnMm#U=2(o$)ev|MVCVp5Z|M%pTElXgozQbrn(21Nu? zso?fcj!ZgC{FH5k3XVPl@`97bXDGOB+jrchwqNrF_w8I>VmH>zU$8K|Y*j<^x{aH! z08!w!1l6lcz(f6{TJcctA!90HMJ=jzT~rqOp_xijtKj7;PjKz}o7FmP78QQ=B{#gn7kPmC#U!mADnngzc@^PWWy|2jM$~UhG33bPT}2{e*TGMI6Fm9Kl04 zjz{n)9wV$jhv)GEPT*z2`)h>walDDQ@HRfcDSU*}_}D}K1ir%$_;CuBJ0@cp7p7ym zn9N(IZ4Hp5Q~{HXu1l^=ymc+V|8JT3`~P(rTkz6B27(OywG5!VE!mbJ-I?|_iDY5w z_fhAK>x~KOnb5#h__}u;Cwk={hBOcRvbayj1SJWzfBi$i-~WR` literal 0 HcmV?d00001 diff --git a/.superpowers/brainstorm/72758-1776397235/state/server-stopped b/.superpowers/brainstorm/72758-1776397235/state/server-stopped new file mode 100644 index 0000000..ac70b7f --- /dev/null +++ b/.superpowers/brainstorm/72758-1776397235/state/server-stopped @@ -0,0 +1 @@ +{"reason":"idle timeout","timestamp":1776399095365} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..d97f87a --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,110 @@ +# AGENTS.md + +This file provides guidance to Codex (Codex.ai/code) when working with code in this repository. + +## What is notfiles? + +A modern dotfiles manager written in Rust — a pure Rust alternative to GNU Stow. It symlinks (or copies) files from organized "package" directories into a target location (typically `~`). + +## Build & Test Commands + +```bash +cargo build # build all workspace crates +cargo build -p notfiles # build just the notfiles binary +cargo test # run all tests across workspace +cargo test -p notcore # test notcore only +cargo test -p notfiles # test notfiles only +cargo test -p notsecrets # test notsecrets only +cargo test -p nothooks # test nothooks only +cargo clippy --workspace # lint all crates +cargo fmt --check # check formatting +``` + +## Workspace Structure + +This is a Cargo workspace with 7 crates under `crates/`: + +| Crate | Purpose | +| ------------ | -------------------------------------------------------------------------- | +| `notcore` | Shared types: `Config`, `NotfilesError`, `Reporter`, `LinkEvent`, | +| | `expand_tilde`, `suggest_package`, `HookPhase`, `HookSpec`, `Report` | +| `notfiles` | Dotfiles linker — lib + `notfiles` binary. Subcommands: `init`, `link`, | +| | `unlink`, `status`, `check`, `diff`, `adopt`, `completions` | +| `notsecrets` | Multi-provider secret resolution (`SecretResolver`), age encryption/ | +| | decryption, identity management | +| `nothooks` | Nushell hook runner with dot/setup phases and state persistence | +| `notnet` | Network utilities — Tailscale integration, YubikeySource | +| `notstrap` | New-machine bootstrap orchestrator — ties all crates together | +| `notgraph` | Dependency/import graph for Rust files — HTML/MD/JSON/Mermaid output, | +| | heatmap, cycle detection | + +## Architecture + +### notfiles (primary user-facing tool) + +Eight subcommands: `init`, `link`, `unlink`, `status`, `check`, `diff`, +`adopt`, `completions`. Global flags: `--dry-run`, `--verbose`, `--json`. +CLI parsing in `crates/notfiles/src/cli.rs`; dispatch in `src/main.rs`. + +**Core flow for `link`:** `main` → `config.validate()` → +`resolve_packages_filtered` (include/exclude + platform filtering) → +`collect_files` (recursive walk with ignore filtering) → +`linker::link_package` (create symlinks or copies, record in state, +return `LinkResult` with counters). + +**Architecture**: Hexagonal (ports/adapters). `FileStore` trait abstracts +filesystem I/O; `Reporter` trait abstracts output. Adapters: +`FileStoreImpl` (real fs), `InMemoryFileStore` (testing), +`TerminalReporter` (ANSI), `JsonReporter` (NDJSON). + +Key modules in `crates/notfiles/src/`: + +- **linker** — Creates/removes symlinks or copies via `FileStore` port. + Manages `State` (`.notfiles-state.toml`). Returns `LinkResult` with + linked/copied/skipped/backed_up counts. Also provides `adopt_files`. +- **package** — Discovers packages with include/exclude and platform + filtering. Recursively collects files via `IgnoreMatcher`. Typo + suggestions via `suggest_package` on not-found errors. +- **ignore** — Glob-based ignore matching using `globset`. +- **status** — Compares expected vs actual state: + linked/copied/missing/conflict/orphan. Also provides `diff_package` + for copy-method divergence detection. +- **adapters/** — `FileStoreImpl`, `InMemoryFileStore`, + `TerminalReporter`, `JsonReporter`. +- **ports** — `FileStore` trait definition. + +### notsecrets + +Multi-provider secret resolution via `SecretResolver`. Providers include +`EnvSource`, `OpSource` (1Password), `BitwardenSource`, `FileSource`, +`DotenvxSource`, `SopsSource`, and others. Native age encryption/decryption +with x25519, SSH ed25519/RSA, and scrypt identity support. No external +`sops` or `age` binaries required. + +### nothooks + +`HookRunner` executes `.nu` scripts via `nu