mirror of
https://github.com/nmasur/dotfiles
synced 2026-09-14 16:28:10 +00:00
Compare commits
366
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6209c039b | ||
|
|
3e246645a2 | ||
|
|
ed8be9dee6 | ||
|
|
ab98a202da | ||
|
|
e00560c42c | ||
|
|
d4e56dd190 | ||
|
|
db49e746b8 | ||
|
|
7f8400ff58 | ||
|
|
d3914768c8 | ||
|
|
fd9cae9c40 | ||
|
|
f593fdb81f | ||
|
|
01ee98155a | ||
|
|
2a3cbfb5f5 | ||
|
|
ca1343f593 | ||
|
|
a053a9ab0f | ||
|
|
90dc80f7b4 | ||
|
|
aff596aa64 | ||
|
|
6e0f4e2000 | ||
|
|
72c4f4823b | ||
|
|
a93fa75779 | ||
|
|
a50d2c01a9 | ||
|
|
a72e81fcce | ||
|
|
fe2843ead6 | ||
|
|
68320577ae | ||
|
|
38ba019c3d | ||
|
|
e339a4969f | ||
|
|
44f2ca803e | ||
|
|
239b56c1b1 | ||
|
|
4ba1ed807c | ||
|
|
32989f1758 | ||
|
|
b0b08d2475 | ||
|
|
5ecefd4589 | ||
|
|
fffb9d547c | ||
|
|
3c303ccd19 | ||
|
|
d222fef02e | ||
|
|
71ce9689ce | ||
|
|
4047cae211 | ||
|
|
e70661a623 | ||
|
|
a979036462 | ||
|
|
8ae7fd435e | ||
|
|
2d5de254e4 | ||
|
|
d90b45d194 | ||
|
|
d8a29f0267 | ||
|
|
f3a8d45722 | ||
|
|
df38163999 | ||
|
|
31cecf05cc | ||
|
|
59685bf023 | ||
|
|
a3a5c516ce | ||
|
|
033026bff8 | ||
|
|
5929b3201d | ||
|
|
373beb6daf | ||
|
|
8cef9bfb59 | ||
|
|
98d426ce89 | ||
|
|
e107431fa9 | ||
|
|
1960d84e7a | ||
|
|
671a17af76 | ||
|
|
71709776f9 | ||
|
|
829af86dd8 | ||
|
|
e7fd5eb770 | ||
|
|
f0b400d134 | ||
|
|
573c0acd33 | ||
|
|
eec777c0c1 | ||
|
|
638b112db9 | ||
|
|
27917ffede | ||
|
|
73b62e0907 | ||
|
|
b25cfe6877 | ||
|
|
d162df2515 | ||
|
|
396337f74d | ||
|
|
76b50920de | ||
|
|
e04cdab409 | ||
|
|
d238b7a81a | ||
|
|
f3e24c3730 | ||
|
|
5862c7cb29 | ||
|
|
a175acd0ad | ||
|
|
3f3cf65c77 | ||
|
|
35d40ca346 | ||
|
|
e0fb590314 | ||
|
|
2f107ad207 | ||
|
|
b6b0a29a78 | ||
|
|
fd6da7e68d | ||
|
|
28049e9c30 | ||
|
|
d95cdb1385 | ||
|
|
cf8f1fa221 | ||
|
|
8b098f0589 | ||
|
|
12961b19c0 | ||
|
|
455c047607 | ||
|
|
fa307c0f4b | ||
|
|
07a980e937 | ||
|
|
0a4a28d06a | ||
|
|
5fd6593a92 | ||
|
|
8af595b62b | ||
|
|
1e723db068 | ||
|
|
16e42c2021 | ||
|
|
38edf0a1a6 | ||
|
|
15f70dce2c | ||
|
|
1a7633fe8c | ||
|
|
40025b1211 | ||
|
|
f5d9664caf | ||
|
|
7010d6cea3 | ||
|
|
a2a429d286 | ||
|
|
7f5b5eb809 | ||
|
|
f5f3a8336e | ||
|
|
4444a479d4 | ||
|
|
395c4b4348 | ||
|
|
8dbec5f6ab | ||
|
|
f8d79cdf3a | ||
|
|
280082acfe | ||
|
|
1edf9da155 | ||
|
|
8d970103e1 | ||
|
|
d9137ad738 | ||
|
|
4eacca970e | ||
|
|
d09ee3337b | ||
|
|
22e1c9b8eb | ||
|
|
acd71623e4 | ||
|
|
9a97d94ffa | ||
|
|
84bffd13e8 | ||
|
|
774b323837 | ||
|
|
2f2d2c0145 | ||
|
|
6b17248804 | ||
|
|
a7dacb7edf | ||
|
|
dfd3b955c0 | ||
|
|
fd7ddf71f3 | ||
|
|
bba66e3e6a | ||
|
|
be6d6b0d35 | ||
|
|
0239a9925c | ||
|
|
49e35403b6 | ||
|
|
430b522c61 | ||
|
|
a64488093c | ||
|
|
54d2376437 | ||
|
|
cd0a5d5de0 | ||
|
|
10eecfa136 | ||
|
|
b5b3f6cb6a | ||
|
|
810c92a7b8 | ||
|
|
fcb28c8151 | ||
|
|
e2a2d3de14 | ||
|
|
adbc2bd261 | ||
|
|
117fd8a06e | ||
|
|
d9fbdf7bfe | ||
|
|
2d13780d2e | ||
|
|
53a712a217 | ||
|
|
31d34c6540 | ||
|
|
a978e67346 | ||
|
|
a6915a6d2d | ||
|
|
44c4034236 | ||
|
|
a99c14a8c2 | ||
|
|
f1c8e26044 | ||
|
|
29cd253d9c | ||
|
|
603b9a2eff | ||
|
|
9c35744ab9 | ||
|
|
7d6b29c30b | ||
|
|
fd589b66ef | ||
|
|
853aa644fa | ||
|
|
b6e7221cc6 | ||
|
|
235901b3b0 | ||
|
|
7cd74986df | ||
|
|
a6e15b71cd | ||
|
|
2e4467b6ea | ||
|
|
431ebd732c | ||
|
|
2d576bd25d | ||
|
|
a1615eda67 | ||
|
|
444582a5a5 | ||
|
|
fbabdadb32 | ||
|
|
f8dfa2a817 | ||
|
|
e4a8ef15ce | ||
|
|
5c922310f5 | ||
|
|
2f274cd652 | ||
|
|
407e9c3af8 | ||
|
|
c13e029805 | ||
|
|
c56bc30200 | ||
|
|
6064fdb0e0 | ||
|
|
5cf27d6d66 | ||
|
|
ceca1ffd5a | ||
|
|
ebbc9c5a5d | ||
|
|
aea3e95ef5 | ||
|
|
d79c1ba7df | ||
|
|
422131134a | ||
|
|
5d8e10b814 | ||
|
|
fdd5eb6418 | ||
|
|
72c548e707 | ||
|
|
a57207dd5d | ||
|
|
94b4217be3 | ||
|
|
7619ac6ea2 | ||
|
|
7543721020 | ||
|
|
bf52069886 | ||
|
|
839ca079c2 | ||
|
|
b98c3f04ab | ||
|
|
68d8e60b7e | ||
|
|
85f09b1126 | ||
|
|
29c7a27135 | ||
|
|
3523f20665 | ||
|
|
774773c748 | ||
|
|
c85d292d1a | ||
|
|
78cc3559f6 | ||
|
|
a35e758c2f | ||
|
|
72f30cbab1 | ||
|
|
17b30de163 | ||
|
|
8b3ab57b34 | ||
|
|
483833cdcb | ||
|
|
57e593aabc | ||
|
|
b119256ba6 | ||
|
|
54948353dd | ||
|
|
9c4219da40 | ||
|
|
ae3735586e | ||
|
|
cb00bb2e72 | ||
|
|
e64a9f14d0 | ||
|
|
e2e179c0e5 | ||
|
|
e975db7385 | ||
|
|
08ec8ce4b8 | ||
|
|
7388eed876 | ||
|
|
e53d9eb1a9 | ||
|
|
b956f9dd82 | ||
|
|
d7969cc8fc | ||
|
|
21d66d2be1 | ||
|
|
518848181a | ||
|
|
f9bf763f91 | ||
|
|
ca20fa0732 | ||
|
|
56d10c2765 | ||
|
|
3b6b4bd2e6 | ||
|
|
6f06b0a0c5 | ||
|
|
d3e69faf2f | ||
|
|
4755a27089 | ||
|
|
57303d61e9 | ||
|
|
b67c90dae0 | ||
|
|
2ff9254a0e | ||
|
|
59a8a6dc3f | ||
|
|
5943a6682e | ||
|
|
d38f767d03 | ||
|
|
ebd79aa348 | ||
|
|
f778bc58ac | ||
|
|
eb1c08f5da | ||
|
|
3e7afdc0b3 | ||
|
|
45aa5d01e5 | ||
|
|
6a9d1c14a7 | ||
|
|
3fe4843032 | ||
|
|
6a36408416 | ||
|
|
25c7aec532 | ||
|
|
b87db529ae | ||
|
|
d756b0d394 | ||
|
|
c35c2e0104 | ||
|
|
f1f85f97aa | ||
|
|
6dd67fdc58 | ||
|
|
57b40d2b31 | ||
|
|
600e7383d0 | ||
|
|
47b7cce953 | ||
|
|
fb80f6d98d | ||
|
|
98c18420ec | ||
|
|
c0091c3f21 | ||
|
|
43246234b1 | ||
|
|
019f8ae01b | ||
|
|
ee627d4161 | ||
|
|
9d7ce47ac5 | ||
|
|
b15a071782 | ||
|
|
48e714faf3 | ||
|
|
ea20d93079 | ||
|
|
b323723115 | ||
|
|
89b260d12c | ||
|
|
a0f4380c9f | ||
|
|
0a9774f9fa | ||
|
|
c569257f03 | ||
|
|
d709030211 | ||
|
|
ecf6bdda45 | ||
|
|
5e2fca427d | ||
|
|
c5ad3c66ea | ||
|
|
6b5a01262e | ||
|
|
d16ed6a4fc | ||
|
|
6d5b460cb2 | ||
|
|
a5b628dd30 | ||
|
|
5ed6870bdd | ||
|
|
26c1c09402 | ||
|
|
dd00ad6c2e | ||
|
|
192e08a9d9 | ||
|
|
227e6a68af | ||
|
|
444ede2074 | ||
|
|
c31fe46b61 | ||
|
|
28d9806720 | ||
|
|
5dea78926b | ||
|
|
e8571fe6b7 | ||
|
|
a9b3249e20 | ||
|
|
73002607ab | ||
|
|
267134044f | ||
|
|
0621c66981 | ||
|
|
18b489592e | ||
|
|
928be5132a | ||
|
|
11b7587783 | ||
|
|
2704642b3d | ||
|
|
95d86dcdff | ||
|
|
e8bc263081 | ||
|
|
03d2326724 | ||
|
|
5bc980eea9 | ||
|
|
a2866927f3 | ||
|
|
c2100cbc39 | ||
|
|
1d4b79e8f1 | ||
|
|
3974c6ce5d | ||
|
|
67f6eb3a1c | ||
|
|
e0cd3c9d79 | ||
|
|
e7e94a1dc3 | ||
|
|
20fc80c259 | ||
|
|
ae09296f36 | ||
|
|
44f769f5ed | ||
|
|
6e29c95506 | ||
|
|
ac0a8d6c38 | ||
|
|
6f32a0dfa3 | ||
|
|
9feaca58f3 | ||
|
|
3084c90c13 | ||
|
|
f20d477f67 | ||
|
|
c8441fc265 | ||
|
|
23f46e51e6 | ||
|
|
f2e09c9adc | ||
|
|
f0add607e6 | ||
|
|
b38205af93 | ||
|
|
12c9342748 | ||
|
|
5d539abe21 | ||
|
|
cea08761bb | ||
|
|
eea972492e | ||
|
|
9014ca226e | ||
|
|
515859d22d | ||
|
|
aa6c91b65c | ||
|
|
d59692c813 | ||
|
|
88266c9f8d | ||
|
|
a1dfc77790 | ||
|
|
b3a7b280b5 | ||
|
|
e803e6a02a | ||
|
|
61c4e68fef | ||
|
|
faac8f3c8b | ||
|
|
9b30f91b1d | ||
|
|
5966368620 | ||
|
|
820f5afe0b | ||
|
|
bfbacbe93e | ||
|
|
54a073b946 | ||
|
|
8eede16bcd | ||
|
|
11e0992d99 | ||
|
|
562295edb1 | ||
|
|
a719dc4309 | ||
|
|
0aecbd85cd | ||
|
|
28ac5523f8 | ||
|
|
645454cb9a | ||
|
|
b30893d968 | ||
|
|
0ec67df9a3 | ||
|
|
7182ca7cd4 | ||
|
|
fbaa6f8894 | ||
|
|
3873ab7296 | ||
|
|
7b32216684 | ||
|
|
2f042713cc | ||
|
|
011fb57347 | ||
|
|
ce308a6347 | ||
|
|
31e93606f4 | ||
|
|
b7317a721b | ||
|
|
3684ce4b39 | ||
|
|
b8337f1295 | ||
|
|
b78bc5b3bb | ||
|
|
5869e4a6b4 | ||
|
|
2c55912abf | ||
|
|
0be5c026a7 | ||
|
|
d427ccc577 | ||
|
|
3852551ebe | ||
|
|
9727fd6a56 | ||
|
|
e233a2e354 | ||
|
|
5b32f1f211 | ||
|
|
eace1ff3cf | ||
|
|
5397e4e23f | ||
|
|
956fa3184b | ||
|
|
b73867ea27 | ||
|
|
37427204de | ||
|
|
6ee5ade2bc | ||
|
|
043cd8ce5c | ||
|
|
07a0d5185b |
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"WebFetch(domain:github.com)",
|
||||||
|
"WebFetch(domain:raw.githubusercontent.com)",
|
||||||
|
"Bash(gh run *)",
|
||||||
|
"Bash(jj status *)",
|
||||||
|
"Bash(jj new *)",
|
||||||
|
"Bash(jj describe *)",
|
||||||
|
"Bash(nix flake *)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,7 +3,7 @@ name: Arrow (AWS)
|
|||||||
run-name: Arrow (AWS) - ${{ inputs.rebuild && 'Rebuild and ' || '' }}${{ inputs.action == 'create' && 'Create' || ( inputs.action == 'destroy' && 'Destroy' || 'No Action' ) }}
|
run-name: Arrow (AWS) - ${{ inputs.rebuild && 'Rebuild and ' || '' }}${{ inputs.action == 'create' && 'Create' || ( inputs.action == 'destroy' && 'Destroy' || 'No Action' ) }}
|
||||||
|
|
||||||
env:
|
env:
|
||||||
TERRAFORM_DIRECTORY: hosts/arrow/aws
|
TERRAFORM_DIRECTORY: deploy/aws
|
||||||
DEPLOY_IDENTITY_BASE64: ${{ secrets.DEPLOY_IDENTITY_BASE64 }}
|
DEPLOY_IDENTITY_BASE64: ${{ secrets.DEPLOY_IDENTITY_BASE64 }}
|
||||||
ARROW_IDENTITY_BASE64: ${{ secrets.ARROW_IDENTITY_BASE64 }}
|
ARROW_IDENTITY_BASE64: ${{ secrets.ARROW_IDENTITY_BASE64 }}
|
||||||
ZONE_NAME: masu.rs
|
ZONE_NAME: masu.rs
|
||||||
|
|||||||
@@ -0,0 +1,200 @@
|
|||||||
|
name: Flame
|
||||||
|
|
||||||
|
run-name: Flame - ${{ inputs.rebuild && 'Rebuild and ' || '' }}${{ inputs.action == 'create' && 'Create' || ( inputs.action == 'destroy' && 'Destroy' || 'No Action' ) }}
|
||||||
|
|
||||||
|
env:
|
||||||
|
TERRAFORM_DIRECTORY: deploy/oracle
|
||||||
|
DEPLOY_IDENTITY_BASE64: ${{ secrets.DEPLOY_IDENTITY_BASE64 }}
|
||||||
|
FLAME_IDENTITY_BASE64: ${{ secrets.FLAME_IDENTITY_BASE64 }}
|
||||||
|
ZONE_NAME: masu.rs
|
||||||
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||||
|
CLOUDFLARE_ZONE_ID: ${{ secrets.CLOUDFLARE_ZONE_ID }}
|
||||||
|
OCI_CLI_USER: "ocid1.user.oc1..aaaaaaaa6lro2eoxdajjypjysepvzcavq5yn4qyozjyebxdiaoqziribuqba"
|
||||||
|
OCI_CLI_TENANCY: "ocid1.tenancy.oc1..aaaaaaaaudwr2ozedhjnrn76ofjgglgug6gexknjisd7gb7tkj3mjdp763da"
|
||||||
|
OCI_CLI_FINGERPRINT: "dd:d0:da:6d:83:46:8b:b3:d9:45:2b:c7:56:ae:30:94"
|
||||||
|
OCI_CLI_KEY_CONTENT: "${{ secrets.OCI_PRIVATE_KEY }}"
|
||||||
|
TF_VAR_oci_private_key: "${{ secrets.OCI_PRIVATE_KEY }}"
|
||||||
|
OCI_CLI_REGION: "us-ashburn-1"
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
rebuild:
|
||||||
|
description: Rebuild Image
|
||||||
|
type: boolean
|
||||||
|
default: false
|
||||||
|
action:
|
||||||
|
description: Terraform Action
|
||||||
|
type: choice
|
||||||
|
required: true
|
||||||
|
default: create
|
||||||
|
options:
|
||||||
|
- create
|
||||||
|
- destroy
|
||||||
|
- nothing
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write
|
||||||
|
contents: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-deploy:
|
||||||
|
name: Build and Deploy
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
runs-on: ubuntu-24.04-arm
|
||||||
|
steps:
|
||||||
|
- name: Checkout Repo Code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# - name: Write OCI Key to File
|
||||||
|
# run: |
|
||||||
|
# echo "${{ env.OCI_PRIVATE_KEY_BASE64 }}" | base64 -d > OCI_PRIVATE_KEY
|
||||||
|
|
||||||
|
# # Enable access to KVM, required to build an image
|
||||||
|
# - name: Enable KVM group perms
|
||||||
|
# if: inputs.rebuild && inputs.action != 'destroy'
|
||||||
|
# run: |
|
||||||
|
# echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
|
||||||
|
# sudo udevadm control --reload-rules
|
||||||
|
# sudo udevadm trigger --name-match=kvm
|
||||||
|
# sudo apt-get install -y qemu-user-static
|
||||||
|
|
||||||
|
# Install Nix
|
||||||
|
- name: Install Nix
|
||||||
|
# if: inputs.rebuild && inputs.action != 'destroy'
|
||||||
|
uses: cachix/[email protected]
|
||||||
|
with:
|
||||||
|
enable_kvm: true
|
||||||
|
extra_nix_config: |
|
||||||
|
system = aarch64-linux
|
||||||
|
system-features = aarch64-linux arm-linux kvm
|
||||||
|
|
||||||
|
# Build the image
|
||||||
|
- name: Build Image
|
||||||
|
if: inputs.rebuild && inputs.action != 'destroy'
|
||||||
|
run: nix build .#flame-qcow --system aarch64-linux
|
||||||
|
|
||||||
|
- name: List Images
|
||||||
|
if: inputs.rebuild && inputs.action != 'destroy'
|
||||||
|
run: |
|
||||||
|
ls -lh result/
|
||||||
|
echo "IMAGE_NAME=$(ls result/nixos.qcow2) >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: Upload Image to S3
|
||||||
|
if: inputs.rebuild && inputs.action != 'destroy'
|
||||||
|
# env:
|
||||||
|
# AWS_ACCESS_KEY_ID: "<YOUR_OCI_ACCESS_KEY>"
|
||||||
|
# AWS_SECRET_ACCESS_KEY: "<YOUR_OCI_SECRET_KEY>"
|
||||||
|
# AWS_DEFAULT_REGION: "us-ashburn-1" # e.g., us-ashburn-1, us-phoenix-1
|
||||||
|
# AWS_ENDPOINT_URL: "https://masur.compat.objectstorage.us-ashburn-1.oraclecloud.com"
|
||||||
|
uses: oracle-actions/[email protected]
|
||||||
|
with:
|
||||||
|
command: |
|
||||||
|
os object put \
|
||||||
|
--namespace "idptr5akf9pf" \
|
||||||
|
--bucket-name "noahmasur-images" \
|
||||||
|
--name "nixos.qcow2" \
|
||||||
|
--file "${IMAGE_NAME}" \
|
||||||
|
--part-size 128 \ # Optional: Specify part size in MiB for multipart uploads, default is 128 MiB
|
||||||
|
--parallel-upload-count 5 # Optional: Number of parallel uploads, default is 3
|
||||||
|
|
||||||
|
# Login to AWS
|
||||||
|
- name: AWS Assume Role
|
||||||
|
uses: aws-actions/configure-aws-credentials@v4
|
||||||
|
with:
|
||||||
|
role-to-assume: arn:aws:iam::286370965832:role/github_actions_admin
|
||||||
|
aws-region: us-east-1
|
||||||
|
|
||||||
|
# Installs the Terraform binary and some other accessory functions.
|
||||||
|
- name: Setup Terraform
|
||||||
|
uses: hashicorp/setup-terraform@v2
|
||||||
|
|
||||||
|
# Checks whether Terraform is formatted properly. If this fails, you
|
||||||
|
# should install the pre-commit hook.
|
||||||
|
- name: Check Formatting
|
||||||
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
||||||
|
run: |
|
||||||
|
terraform fmt -no-color -check -diff -recursive
|
||||||
|
|
||||||
|
# Connects to remote state backend and download providers.
|
||||||
|
- name: Terraform Init
|
||||||
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
||||||
|
run: terraform init -input=false
|
||||||
|
|
||||||
|
# Deploys infrastructure or changes to infrastructure.
|
||||||
|
- name: Terraform Apply
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
||||||
|
run: |
|
||||||
|
terraform apply \
|
||||||
|
-auto-approve \
|
||||||
|
-input=false
|
||||||
|
|
||||||
|
# Removes infrastructure.
|
||||||
|
- name: Terraform Destroy
|
||||||
|
if: inputs.action == 'destroy'
|
||||||
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
||||||
|
run: |
|
||||||
|
terraform destroy \
|
||||||
|
-auto-approve \
|
||||||
|
-input=false
|
||||||
|
|
||||||
|
- name: Get Host IP
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
id: host
|
||||||
|
working-directory: ${{ env.TERRAFORM_DIRECTORY }}
|
||||||
|
run: terraform output -raw host_ip
|
||||||
|
|
||||||
|
- name: Wait on SSH
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
run: |
|
||||||
|
for i in $(seq 1 15); do
|
||||||
|
if $(nc -z -w 3 ${{ steps.host.outputs.stdout }} 22); then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Write Identity Keys to Files
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
run: |
|
||||||
|
echo "${{ env.DEPLOY_IDENTITY_BASE64 }}" | base64 -d > deploy_ed25519
|
||||||
|
chmod 0600 deploy_ed25519
|
||||||
|
echo "${{ env.FLAME_IDENTITY_BASE64 }}" | base64 -d > flame_ed25519
|
||||||
|
chmod 0600 flame_ed25519
|
||||||
|
mkdir -pv "${HOME}/.ssh/"
|
||||||
|
cp deploy_ed25519 "${HOME}/.ssh/id_ed25519"
|
||||||
|
|
||||||
|
- name: Run nixos-anywhere
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
run: |
|
||||||
|
nix run github:nix-community/nixos-anywhere -- --flake github:nmasur/dotfiles#flame --build-on remote --no-reboot --target-host ubuntu@${{ steps.host.outputs.stdout }}
|
||||||
|
reboot now
|
||||||
|
|
||||||
|
- name: Wait on SSH After Reboot
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
run: |
|
||||||
|
for i in $(seq 1 15); do
|
||||||
|
if $(nc -z -w 3 ${{ steps.host.outputs.stdout }} 22); then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 10
|
||||||
|
done
|
||||||
|
|
||||||
|
- name: Copy Identity File to Host
|
||||||
|
if: inputs.action == 'create'
|
||||||
|
run: |
|
||||||
|
ssh -i deploy_ed25519 -o StrictHostKeyChecking=accept-new noah@${{ steps.host.outputs.stdout }} 'mkdir -pv .ssh'
|
||||||
|
scp -i deploy_ed25519 flame_ed25519 noah@${{ steps.host.outputs.stdout }}:~/.ssh/id_ed25519
|
||||||
|
|
||||||
|
# - name: Wipe Records
|
||||||
|
# if: ${{ inputs.action == 'destroy' }}
|
||||||
|
# run: |
|
||||||
|
# RECORD_ID=$(curl --request GET \
|
||||||
|
# --url https://api.cloudflare.com/client/v4/zones/${{ env.CLOUDFLARE_ZONE_ID }}/dns_records \
|
||||||
|
# --header 'Content-Type: application/json' \
|
||||||
|
# --header "Authorization: Bearer ${{ env.CLOUDFLARE_API_TOKEN }}" | jq -r '.result[] | select(.name == "n8n2.${{ env.ZONE_NAME }}") | .id')
|
||||||
|
# curl --request DELETE \
|
||||||
|
# --url https://api.cloudflare.com/client/v4/zones/${{ env.CLOUDFLARE_ZONE_ID }}/dns_records/${RECORD_ID} \
|
||||||
|
# --header 'Content-Type: application/json' \
|
||||||
|
# --header "Authorization: Bearer ${{ env.CLOUDFLARE_API_TOKEN }}"
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
terraform {
|
||||||
|
backend "s3" {
|
||||||
|
bucket = "noahmasur-terraform"
|
||||||
|
key = "flame.tfstate"
|
||||||
|
region = "us-east-1"
|
||||||
|
use_lockfile = true
|
||||||
|
}
|
||||||
|
required_version = ">= 1.0.0"
|
||||||
|
required_providers {
|
||||||
|
oci = {
|
||||||
|
source = "oracle/oci"
|
||||||
|
version = "7.7.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "oci" {
|
||||||
|
auth = "APIKey"
|
||||||
|
tenancy_ocid = var.compartment_ocid
|
||||||
|
user_ocid = "ocid1.user.oc1..aaaaaaaa6lro2eoxdajjypjysepvzcavq5yn4qyozjyebxdiaoqziribuqba"
|
||||||
|
private_key = var.oci_private_key
|
||||||
|
fingerprint = "dd:d0:da:6d:83:46:8b:b3:d9:45:2b:c7:56:ae:30:94"
|
||||||
|
region = "us-ashburn-1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the latest Ubuntu image OCID
|
||||||
|
# We'll filter for a recent Ubuntu LTS version (e.g., 22.04 or 24.04) and pick the latest.
|
||||||
|
# Note: Image OCIDs are region-specific. This data source helps find the correct one.
|
||||||
|
data "oci_core_images" "ubuntu_image" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
operating_system = "Canonical Ubuntu"
|
||||||
|
# Adjust this version if you prefer a different Ubuntu LTS (e.g., "24.04")
|
||||||
|
operating_system_version = "24.04"
|
||||||
|
shape = var.instance_shape # Filter by the shape to ensure compatibility
|
||||||
|
sort_by = "TIMECREATED"
|
||||||
|
sort_order = "DESC"
|
||||||
|
}
|
||||||
|
|
||||||
|
# resource "oci_core_image" "my_custom_image" {
|
||||||
|
# compartment_id = var.compartment_ocid
|
||||||
|
# display_name = "noah-nixos"
|
||||||
|
|
||||||
|
# image_source_details {
|
||||||
|
# source_type = "objectStorageTuple" # Use this if specifying namespace, bucket, and object name
|
||||||
|
# # source_type = "objectStorageUri" # Use this if you have a pre-authenticated request URL (PAR)
|
||||||
|
# namespace_name = var.object_storage_namespace
|
||||||
|
# bucket_name = var.object_storage_bucket_name
|
||||||
|
# object_name = var.object_storage_object_name
|
||||||
|
|
||||||
|
# source_image_type = "QCOW2" # e.g., "QCOW2", "VMDK"
|
||||||
|
|
||||||
|
# # These properties help OCI understand how to launch instances from this image
|
||||||
|
# # Adjust based on your custom image's OS and boot mode
|
||||||
|
# operating_system = "NixOS" # e.g., "CentOS", "Debian", "Windows"
|
||||||
|
# operating_system_version = "25.05" # e.g., "7", "11", "2019"
|
||||||
|
# }
|
||||||
|
|
||||||
|
# launch_mode = "PARAVIRTUALIZED" # Or "NATIVE", "EMULATED", "CUSTOM"
|
||||||
|
# # Optional: for specific launch options if your image requires them
|
||||||
|
# # launch_options {
|
||||||
|
# # boot_volume_type = "PARAVIRTUALIZED"
|
||||||
|
# # firmware = "UEFI_64" # Or "BIOS"
|
||||||
|
# # network_type = "PARAVIRTUALIZED"
|
||||||
|
# # }
|
||||||
|
|
||||||
|
# # Time out for image import operation. Can take a while for large images.
|
||||||
|
# timeouts {
|
||||||
|
# create = "60m" # Default is 20m, often needs to be increased
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
data "oci_identity_availability_domains" "ads" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "oci_core_instance" "my_compute_instance" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
availability_domain = data.oci_identity_availability_domains.ads.availability_domains[0].name
|
||||||
|
shape = var.instance_shape
|
||||||
|
display_name = var.instance_display_name
|
||||||
|
|
||||||
|
source_details {
|
||||||
|
source_type = "image"
|
||||||
|
# Use the OCID of the latest Ubuntu image found by the data source
|
||||||
|
source_id = data.oci_core_images.ubuntu_image.images[0].id
|
||||||
|
# # Use the OCID of the newly imported custom image
|
||||||
|
# source_id = oci_core_image.my_custom_image.id
|
||||||
|
# Specify the boot volume size
|
||||||
|
boot_volume_size_in_gbs = var.boot_volume_size_in_gbs
|
||||||
|
boot_volume_vpus_per_gb = 20 # Highest free tier option
|
||||||
|
}
|
||||||
|
|
||||||
|
# launch_options {
|
||||||
|
# is_consistent_volume_naming_enabled = true # Sets boot device path to /dev/oracleoci/oraclevda
|
||||||
|
# network_type = "PARAVIRTUALIZED" # I think this is the default?
|
||||||
|
# }
|
||||||
|
|
||||||
|
create_vnic_details {
|
||||||
|
subnet_id = oci_core_subnet.my_public_subnet.id # Use the created subnet's ID
|
||||||
|
display_name = "primary_vnic"
|
||||||
|
assign_public_ip = true
|
||||||
|
hostname_label = "flame"
|
||||||
|
}
|
||||||
|
|
||||||
|
metadata = {
|
||||||
|
ssh_authorized_keys = var.ssh_public_key
|
||||||
|
user_data = base64encode(var.cloud_init_script)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Optional: For flexible shapes (e.g., VM.Standard.E4.Flex), you might need to specify OCPUs and memory
|
||||||
|
shape_config {
|
||||||
|
ocpus = 4
|
||||||
|
memory_in_gbs = 24
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
resource "oci_core_vcn" "my_vpc" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
display_name = "main"
|
||||||
|
cidr_block = "10.0.0.0/16"
|
||||||
|
is_ipv6enabled = false
|
||||||
|
dns_label = "mainvcn" # Must be unique within your tenancy
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "oci_core_internet_gateway" "my_igw" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
vcn_id = oci_core_vcn.my_vpc.id
|
||||||
|
display_name = "main-igw"
|
||||||
|
enabled = true
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "oci_core_route_table" "my_public_route_table" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
vcn_id = oci_core_vcn.my_vpc.id
|
||||||
|
display_name = "main-public-rt"
|
||||||
|
|
||||||
|
# Default route to the Internet Gateway
|
||||||
|
route_rules {
|
||||||
|
destination = "0.0.0.0/0"
|
||||||
|
destination_type = "CIDR_BLOCK"
|
||||||
|
network_entity_id = oci_core_internet_gateway.my_igw.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "oci_core_security_list" "my_public_security_list" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
vcn_id = oci_core_vcn.my_vpc.id
|
||||||
|
display_name = "main-public-sl"
|
||||||
|
|
||||||
|
# Egress Rules (Allow all outbound traffic)
|
||||||
|
egress_security_rules {
|
||||||
|
destination = "0.0.0.0/0"
|
||||||
|
destination_type = "CIDR_BLOCK"
|
||||||
|
protocol = "all"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Ingress Rules
|
||||||
|
ingress_security_rules {
|
||||||
|
# SSH (TCP 22)
|
||||||
|
protocol = "6" # TCP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
tcp_options {
|
||||||
|
min = 22
|
||||||
|
max = 22
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress_security_rules {
|
||||||
|
# HTTP (TCP 80)
|
||||||
|
protocol = "6" # TCP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
tcp_options {
|
||||||
|
min = 80
|
||||||
|
max = 80
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress_security_rules {
|
||||||
|
# HTTPS (TCP 443)
|
||||||
|
protocol = "6" # TCP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
tcp_options {
|
||||||
|
min = 443
|
||||||
|
max = 443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress_security_rules {
|
||||||
|
# Custom Minecraft
|
||||||
|
protocol = "6" # TCP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
tcp_options {
|
||||||
|
min = 49732
|
||||||
|
max = 49732
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress_security_rules {
|
||||||
|
# HTTPS (UDP 443) - For QUIC or specific UDP services
|
||||||
|
protocol = "17" # UDP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
udp_options {
|
||||||
|
min = 443
|
||||||
|
max = 443
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ingress_security_rules {
|
||||||
|
# ICMP (Ping)
|
||||||
|
protocol = "1" # ICMP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
icmp_options {
|
||||||
|
type = 3 # Destination Unreachable (common for connectivity checks)
|
||||||
|
code = 4 # Fragmentation needed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ingress_security_rules {
|
||||||
|
protocol = "1" # ICMP
|
||||||
|
source = "0.0.0.0/0"
|
||||||
|
source_type = "CIDR_BLOCK"
|
||||||
|
icmp_options {
|
||||||
|
type = 8 # Echo Request (ping)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "oci_core_subnet" "my_public_subnet" {
|
||||||
|
compartment_id = var.compartment_ocid
|
||||||
|
vcn_id = oci_core_vcn.my_vpc.id
|
||||||
|
display_name = "main-public-subnet"
|
||||||
|
cidr_block = "10.0.0.0/24"
|
||||||
|
prohibit_public_ip_on_vnic = false # Allows instances in this subnet to get public IPs
|
||||||
|
route_table_id = oci_core_route_table.my_public_route_table.id
|
||||||
|
security_list_ids = [oci_core_security_list.my_public_security_list.id]
|
||||||
|
dns_label = "mainsub" # Must be unique within the VCN
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
output "host_ip" {
|
||||||
|
description = "The public IP address of the launched instance."
|
||||||
|
value = oci_core_instance.my_compute_instance.public_ip
|
||||||
|
}
|
||||||
|
|
||||||
|
output "instance_id" {
|
||||||
|
description = "The OCID of the launched instance."
|
||||||
|
value = oci_core_instance.my_compute_instance.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "vpc_ocid" {
|
||||||
|
description = "The OCID of the created VCN."
|
||||||
|
value = oci_core_vcn.my_vpc.id
|
||||||
|
}
|
||||||
|
|
||||||
|
output "subnet_ocid" {
|
||||||
|
description = "The OCID of the created public subnet."
|
||||||
|
value = oci_core_subnet.my_public_subnet.id
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
variable "boot_volume_size_in_gbs" {
|
||||||
|
description = "The size of the boot volume in GBs."
|
||||||
|
type = number
|
||||||
|
default = 150
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "cloud_init_script" {
|
||||||
|
description = "A cloud-init script to run on instance launch."
|
||||||
|
type = string
|
||||||
|
default = <<-EOF
|
||||||
|
#!/bin/bash
|
||||||
|
echo "Hello from cloud-init!" > /home/ubuntu/cloud-init-output.txt
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "compartment_ocid" {
|
||||||
|
description = "The OCID of the compartment where the instance will be created."
|
||||||
|
type = string
|
||||||
|
default = "ocid1.tenancy.oc1..aaaaaaaaudwr2ozedhjnrn76ofjgglgug6gexknjisd7gb7tkj3mjdp763da"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "instance_display_name" {
|
||||||
|
description = "A user-friendly name for the instance."
|
||||||
|
type = string
|
||||||
|
default = "noah-nixos"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "instance_shape" {
|
||||||
|
description = "The shape of the OCI compute instance."
|
||||||
|
type = string
|
||||||
|
default = "VM.Standard.A1.Flex" # Example shape. Choose one available in your region/AD.
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "object_storage_namespace" {
|
||||||
|
description = "Your OCI Object Storage namespace (usually your tenancy name)."
|
||||||
|
type = string
|
||||||
|
default = "idptr5akf9pf"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "object_storage_bucket_name" {
|
||||||
|
description = "The name of the Object Storage bucket where your custom image is located."
|
||||||
|
type = string
|
||||||
|
default = "noahmasur-images"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "object_storage_object_name" {
|
||||||
|
description = "The object name (file name) of your custom image in Object Storage."
|
||||||
|
type = string
|
||||||
|
default = "nixos.qcow2"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "oci_private_key" {
|
||||||
|
type = string
|
||||||
|
description = "API private key for Oracle Cloud management"
|
||||||
|
sensitive = true
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "ssh_public_key" {
|
||||||
|
description = "Your public SSH key content."
|
||||||
|
type = string
|
||||||
|
# default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+AbmjGEwITk5CK9y7+Rg27Fokgj9QEjgc9wST6MA3s personal"
|
||||||
|
default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKpPU2G9rSF8Q6waH62IJexDCQ6lY+8ZyVufGE3xMDGw actions-deploy"
|
||||||
|
}
|
||||||
@@ -0,0 +1,220 @@
|
|||||||
|
# Changelog
|
||||||
|
|
||||||
|
## 2026-09-07
|
||||||
|
|
||||||
|
- **Configured OpenID Connect (OIDC) authentication for Paperless-ngx**:
|
||||||
|
- Added secret management for `paperless-oidc-secret.age` via `secrets.paperless-oidc-secret` owned by `paperless:paperless` (0440).
|
||||||
|
- Configured `systemd.services.paperless-oidc-secret-secret` to run before and be required by all Paperless units, dynamically generating `/var/private/paperless-env` with `PAPERLESS_SOCIALACCOUNT_PROVIDERS` configured for Pocket ID (`auth.masu.rs`) using `client_id = "e6ff7fce-8e67-4c66-8f32-5ec3db4740a9"`, `oauth_pkce_enabled = true`, and email authentication linking (`email_authentication = true`, `verified_email = true`) in the native `APPS` schema.
|
||||||
|
- Added `services.paperless.environmentFile = "${config.secretsDirectory}/paperless-env"` to securely pass the OIDC configuration to Paperless services without exposing secrets in the Nix store.
|
||||||
|
- Configured Paperless settings to enable `allauth.socialaccount.providers.openid_connect` in `PAPERLESS_APPS` and enabled `PAPERLESS_REDIRECT_LOGIN_TO_SSO`.
|
||||||
|
- Configured reverse proxy trust settings (`PAPERLESS_USE_X_FORWARD_HOST`, `PAPERLESS_PROXY_SSL_HEADER`, and `PAPERLESS_TRUSTED_PROXIES`) to ensure callback URIs preserve the `https://` scheme behind Caddy.
|
||||||
|
- Fixed `systemd.services.paperless-secret` to order before and be required by `paperless-scheduler.service` instead of non-existent `paperless.service`.
|
||||||
|
|
||||||
|
- **Configured real client IP forwarding for Jellyfin reverse proxy**:
|
||||||
|
- Added a `map` handler to Jellyfin's Caddy route in `platforms/nixos/modules/nmasur/presets/services/jellyfin.nix` to resolve `{client_ip}` using Cloudflare's `CF-Connecting-IP` header when available, falling back to `{http.request.remote.host}` for direct local LAN connections.
|
||||||
|
- Configured `reverse_proxy.headers.request.set` to forward `X-Real-IP`, `X-Forwarded-For`, and `X-Forwarded-Proto` with the resolved client IP and request scheme to Jellyfin.
|
||||||
|
|
||||||
|
- **Configured OpenID Connect (OIDC) authentication for Nextcloud**:
|
||||||
|
- Added `user_oidc` to `services.nextcloud.extraApps`.
|
||||||
|
- Added secret management for `nextcloud-oidc-secret.age` via `secrets.nextcloud-oidc-secret` with owner `nextcloud` and group `nextcloud` (0440).
|
||||||
|
- Configured `systemd.services.nextcloud-oidc-secret-secret` to be required by and order before `nextcloud-setup.service`.
|
||||||
|
- Set `services.nextcloud.settings.overwriteprotocol = "https"` to ensure correct scheme handling for redirect URIs behind reverse proxy.
|
||||||
|
- Configured automated idempotent upsert of the Pocket ID provider via `systemd.services.nextcloud-setup.postStart` running `nextcloud-occ user_oidc:provider pocket-id` with client ID `c8a32c58-a781-4f14-9070-f498fdfda438`, `--clientsecret-file`, discovery URI `https://${hostnames.auth}/.well-known/openid-configuration`, `--mapping-uid="preferred_username"`, and `--unique-uid=0` to connect OIDC logins directly to existing local Nextcloud accounts.
|
||||||
|
- Updated `docs/oidc-services.md` with the verified configuration and callback URI (`https://cloud.masu.rs/apps/user_oidc/code`).
|
||||||
|
|
||||||
|
## 2026-09-06
|
||||||
|
|
||||||
|
- **Configured OpenID Connect (OIDC) authentication for Immich**:
|
||||||
|
- Configured `services.immich.settings.oauth` with OIDC settings pointing to Pocket ID (`auth.masu.rs`), using client ID `1f4e0f8d-6cee-4d67-8d53-74bf6c18ae09`.
|
||||||
|
- Added secret management for `immich-oidc-secret.age` via `secrets.immich-oidc-secret` with owner `immich` and group `shared` (0440).
|
||||||
|
- Wired client secret substitution using NixOS's native `clientSecret._secret = config.secrets.immich-oidc-secret.dest`, leveraging `utils.genJqSecretsReplacement` with systemd `LoadCredential`.
|
||||||
|
- Configured `systemd.services.immich-server` to order after `immich-oidc-secret-secret.service`.
|
||||||
|
- Updated `docs/oidc-services.md` with the verified configuration and redirect URIs.
|
||||||
|
|
||||||
|
- **Fixed OpenSSH authorized principals certificate authentication for Cloudflare Tunnel**:
|
||||||
|
- Replaced manual `environment.etc."ssh/authorized_principals/${username}"` symlink and `Match User` config with NixOS native `users.users.<name>.openssh.authorizedPrincipals`.
|
||||||
|
- Root cause: `environment.etc` without an explicit `mode` creates symlinks pointing into `/nix/store`, which has group-writable mode `0775` (`nixbld` group). Under `StrictModes yes`, sshd refused authentication with `bad ownership or modes for directory /nix/store`, causing certificate principal matching to fail with `Certificate does not contain an authorized principal`.
|
||||||
|
- Setting `users.users.<name>.openssh.authorizedPrincipals` causes NixOS to generate `/etc/ssh/authorized_principals.d/<name>` with `mode = "0444"`, copying the file instead of symlinking into the store, and automatically configuring `services.openssh.settings.AuthorizedPrincipalsFile = "/etc/ssh/authorized_principals.d/%u"`.
|
||||||
|
- Also added `mode = "0444"` to `/etc/ssh/ca.pub` and moved `TrustedUserCAKeys` into `services.openssh.settings`.
|
||||||
|
|
||||||
|
- **Configured OpenID Connect (OIDC) authentication for Mealie**:
|
||||||
|
- Configured `services.mealie.settings` with OIDC settings pointing to Pocket ID (`auth.masu.rs`), using client ID `040925ed-b39e-4442-b8e8-369c948c0cd2`.
|
||||||
|
- Added secret management for `mealie-oidc-secret.age` via `secrets.mealie-oidc-secret`, using `prefix = "OIDC_CLIENT_SECRET="` to generate an environment file.
|
||||||
|
- Configured `services.mealie.credentialsFile` to load the client secret via systemd's `EnvironmentFile` without exposing it in the world-readable Nix store or systemd unit file.
|
||||||
|
- Configured `systemd.services.mealie` to order after `mealie-oidc-secret-secret.service`.
|
||||||
|
- Updated `docs/oidc-services.md` with the verified configuration and callback URI (`https://cooking.masu.rs/login`).
|
||||||
|
|
||||||
|
- **Configured OpenID Connect (OIDC) authentication for Actual Budget**:
|
||||||
|
- Configured `services.actual.settings` with `loginMethod = "openid"` and `openId` settings pointing to Pocket ID (`auth.masu.rs`), using client ID `92afe9f8-7ef6-42ab-8a06-701df3c7179d`.
|
||||||
|
- Added secret management for `actualbudget-oidc-secret.age` via `secrets.actualbudget-oidc-secret`, set with owner `actualbudget` and group `shared` (0440).
|
||||||
|
- Configured `systemd.services.actual` to order after the decrypted secret service and granted the dynamic unit access via `SupplementaryGroups = [ "shared" ]` and `PrivateUsers = false`.
|
||||||
|
- Updated `docs/oidc-services.md` with the verified callback URI (`https://money.masu.rs/openid/callback`) and NixOS configuration snippet.
|
||||||
|
|
||||||
|
## 2026-09-03: Ctrl-b did nothing because home-manager was never switched; two-phase toggle
|
||||||
|
|
||||||
|
- "Ctrl-b does nothing" root cause: the binding was built into the flake but never activated. The deployed `~/.config/fish/functions/` had no `heal-autosuggest.fish` and no `\cb` binding (0 matches), while the freshly-built config had both. On this setup a system rebuild does not switch home-manager — activation needs the home rebuild (`rebuild-home` / the Alt-Shift-H binding, i.e. `home-manager switch --flake`) followed by a fresh pane so `config.fish` re-runs `fish_user_key_bindings`. No fix works until it is actually activated; this should be the FIRST check next time a "did nothing" is reported.
|
||||||
|
- Made `heal-autosuggest` a two-phase toggle (chosen by the user over `exec fish`, to preserve the session): disable autosuggestions, `commandline -f repaint`, re-enable, `commandline -f repaint`. Grounded in `reader.rs` `update_autosuggestion`, which clears the wedged `in_flight_autosuggest_request` only on a repaint taken while autosuggestions are disabled. The old one-liner and the `fish_postexec` hook did a single back-to-back `set 0; set 1` with no disabled-state repaint, which likely never flushed the stuck request — matching the manual cure, which had prompt cycles between the off and the on. Still unverified against the real bug (not reproducible in a harness); confirm by activating, then pressing Ctrl-b in a live lagging shell.
|
||||||
|
- If the two-phase toggle still does not cure once activated: fall back to `exec fish` on the key (guaranteed per the user's day-one report that a fresh shell always fixes it), and capture a flight-recorder log for the upstream fish report.
|
||||||
|
|
||||||
|
## 2026-09-01: postexec hook fires but does not cure — moved heal to a keybinding
|
||||||
|
|
||||||
|
- Honest status: the `fish_postexec` self-heal hook IS registered and DOES fire (verified in the real config), yet the lag persists. So toggling `fish_autosuggestion_enabled` off/on from `fish_postexec` does not cure it, even though the user typing the same `set … 0; set … 1` at the prompt does.
|
||||||
|
- Why (code-level): variable dispatch is synchronous (`env_dispatch.rs` → `reader_set_autosuggestion_enabled` on every `set`), so the two sets net to no change and schedule a repaint. That repaint only has effect from inside the reader's active input loop. `fish_postexec` runs BETWEEN commands, outside that loop, so its effect is superseded before the next prompt. A key binding runs inside the loop; `fish_postexec` cannot.
|
||||||
|
- Change: bound **Ctrl-b** to a new `heal-autosuggest` function (toggle + `commandline -f repaint`) via `fish_user_key_bindings` (Ctrl-g was already taken). Verified that when `fish_user_key_bindings` runs to completion — as it does in the real config, since the existing `\cn` etc. work (`__fish_config_interactive.fish:105`) — `\cb` binds to heal-autosuggest and the toggle resets the variable. NOT verified to cure the real lag: the bug still cannot be reproduced in a harness, so only a test in a live lagging shell can confirm. The `fish_postexec`/`fish_cancel` hook is kept (harmless) but is no longer considered the fix.
|
||||||
|
- Guaranteed fallback if Ctrl-b does not cure: a fresh shell (`exec fish`), which the user has confirmed from the very start always fixes it — Ctrl-b can be rebound to that. The only path to a truly automatic fix is a flight-recorder capture (`~/.local/state/lag-triage/RECORD`) of the reader during an actual episode, then an upstream fish report.
|
||||||
|
|
||||||
|
## 2026-08-31 (evening): self-heal hook was never firing — fish cannot autoload event handlers
|
||||||
|
|
||||||
|
- The `__autosuggestion_unwedge` hook did not work because it was installed via `programs.fish.functions`, which writes to fish's **autoload** directory — and fish only registers `--on-event` handlers when a function is actually loaded, which never happens for a hook nothing calls by name. Verified in a PTY test: the autoloaded handler never fires; the identical definition `source`d eagerly fires immediately. (The zellij module's `__fish_update_cwd_osc` works as an autoloaded event function only because it overrides a function fish itself loads.)
|
||||||
|
- Meanwhile the user confirmed the instant back-to-back toggle (`set -g fish_autosuggestion_enabled 0 && set -g fish_autosuggestion_enabled 1`) cures a lagging shell — so the handler body is right; only its registration was broken.
|
||||||
|
- Fix: the handler is now defined eagerly in `config.fish` via `programs.fish.interactiveShellInit` (lag-triage module), registered on **fish_postexec** (fires after every command — the moment TUIs exit) and **fish_cancel** (fires on Ctrl-C at the prompt), so a bare Ctrl-C is an instant no-command cure. Verified in an interactive PTY against the actual nix-generated snippet: registers at startup, fires on both events, still respects a deliberate manual disable.
|
||||||
|
- Coverage note: if a wedge forms with no command running (and no Ctrl-C), it heals at the next command; worst-case lag window is "until you run anything or press Ctrl-C".
|
||||||
|
|
||||||
|
## 2026-08-31 (later): automatic self-heal hook
|
||||||
|
|
||||||
|
- Confirmed by A/B in the live shell: after curing the lag with `set -g fish_autosuggestion_enabled 0`, re-enabling with `1` does **not** bring the lag back — the toggle resets the wedged autosuggestion state rather than merely masking it.
|
||||||
|
- Added `__autosuggestion_unwedge` (lag-triage module): a `fish_postexec` event handler that toggles `fish_autosuggestion_enabled` off/on after every command — i.e. at the exact moment a TUI has just exited, when the wedge forms. Builtins only, no visible output (verified in an interactive PTY test), and it skips the reset when the user has deliberately disabled autosuggestions.
|
||||||
|
- Honest caveat: the manual cure had keystrokes between the off and the on; whether the instant off/on inside an event handler resets the same reader-internal state is unproven. The flight recorder therefore STAYS ARMED (`~/.local/state/lag-triage/RECORD`) until the hook has survived normal use for a while. If lag recurs despite the hook: cure manually (`set … 0`, type a few chars, `set … 1`), and keep the flight log for that pid — then the hook needs the stronger form (disable at postexec, re-enable one prompt-cycle later, scoped to TUI commands).
|
||||||
|
- Limitations by design: the hook fires only in shells that run commands, so a wedge formed without any command executing in that shell (if that is possible — e.g. floating-pane TUIs never touch the pane shell) would not be healed until the next command runs there.
|
||||||
|
|
||||||
|
## 2026-08-31: culprit confirmed — fish's autosuggestion pipeline
|
||||||
|
|
||||||
|
- A/B test in a live lagging shell (pid 56089): `set -g fish_autosuggestion_enabled 0` (builtin only, nothing else) **instantly cured the lag**. The post-TUI typing lag is in fish 4.8.1's autosuggestion pipeline.
|
||||||
|
- Sampling that shell afterwards showed it had **only one thread** (the main thread): the poisoned state is main-thread-side bookkeeping, not a hung worker still sitting in the process. Source review (`src/threads/threads.rs`, `src/threads/debounce.rs`): `ThreadPool::perform` silently queues work with no spawn and no wake when it believes `total_threads == max_threads` — a leaked `total_threads` count (workers that died without decrementing, e.g. across a TUI's lifetime) would strand all future autosuggestion work forever; the Debounce then abandons its token every 500ms and re-enqueues per keystroke. The exact step that delays keystroke *echo* is still unproven — the flight recorder (armed via `~/.local/state/lag-triage/RECORD`) logs the reader's per-keystroke behavior and will capture it on the next occurrence in a recorded shell.
|
||||||
|
- Precedent: fish had a closely-related bug class before (#11841 — unread terminal query responses "causing noticeable lags"). No fish release newer than 4.8.1 exists, so no upstream fix to adopt; an upstream report with the flight-recorder capture is the path to a real fix.
|
||||||
|
- Practical interim cure (harmless, instant, in the lagging shell): `set -g fish_autosuggestion_enabled 0`, and re-enable with `1` — whether lag returns on re-enable is the next discriminating datum.
|
||||||
|
|
||||||
|
## 2026-08-30 (later): sampler attach CURES the lag — wedged-thread evidence + flight recorder
|
||||||
|
|
||||||
|
- Major new datum: in a lagging shell, running `mkdir` + `/usr/bin/sample $fish_pid … &` + `disown` **cured the lag instantly**, before any planned reset/toggle test could run. Plain external commands do NOT cure it (the 2026-08-29 triage ran many and the lag survived), so the distinguishing action is the sampler **attaching and suspending/resuming fish's threads**. Conclusion: a fish-internal thread/wait is wedged (missed wakeup or stuck blocking wait), and per-keystroke work at the main commandline stalls against it; suspension/resume kicks it loose. Consistent with: `read` prompts unaffected (no autosuggestion/highlight pipeline), subshells immune (fresh threads), raw input clean. The captured sample (`~/.local/state/lag-triage/fish-sample.txt`) shows only the post-cure state — sampling is a cure, not a capture.
|
||||||
|
- Therefore the observer must be running BEFORE the lag starts: the `fish-no-query-term` wrapper is now a **flight recorder** — `touch ~/.local/state/lag-triage/RECORD`, then every newly spawned pane shell logs `FISH_DEBUG=reader,term-support,proc-termowner,iothread,fd-monitor,topic-monitor` to `~/.local/state/lag-triage/flight/fish-<ts>-<pid>.log` (3-day auto-cleanup; remove RECORD to disable, zero overhead when off). When lag next occurs, the log already contains what each keystroke did during the lag.
|
||||||
|
- `lag-sample` now takes a PID and should be run from a DIFFERENT pane (`echo $fish_pid` — a builtin — in the lagging shell to get it), since attaching from inside cures the lag.
|
||||||
|
- **Next-occurrence checklist (in order, least perturbing first):** (1) in the lagging shell, builtins only: `set -g fish_autosuggestion_enabled 0` → type at the real commandline; if cured, the autosuggestion/debounce path is implicated (a worker thread was seen in `HistorySearch::go_to_next_match`); (2) still laggy: `fish_default_key_bindings` → test (vi-mode path); (3) from another pane: `kill -WINCH <pid>` → test, then `kill -CONT <pid>` → test (discriminates reader-wakeup vs generic unwedge; if WINCH cures, a window resize would too); (4) from another pane: `lag-sample <pid>` while typing in the lagging pane; (5) immediately save the flight log for that pid.
|
||||||
|
|
||||||
|
## 2026-08-30
|
||||||
|
|
||||||
|
- **The post-TUI typing lag is NOT resolved** by the `fish-no-query-term` wrapper: lag recurred in a fresh zellij session after exiting Claude Code, in a shell verified (via `ps eww`) to have `fish_features=no-query-term` in its environment. The query-term reader-degradation bug proven on 2026-08-29 is real (and the wrapper stays as hardening against it), but it is not the mechanism behind this lag. Downgraded the entry below from "root cause" to "a root cause".
|
||||||
|
- Known constraints on the real mechanism: per-keystroke lag at the main fish commandline; fish `read` prompts unaffected; raw input reaches the pane practical as plain bytes; a subshell/`exec fish` cures it (process-local state). Note the 2026-08-29 triage's reset ladder short-circuited on a false "y" at stage A, so stages B–G (mouse/keypad/altscreen/stty/DECSTR resets) were never actually tested against real lag.
|
||||||
|
- Added `lag-sample` (fish function): stack-samples the lagging fish process plus the zellij server/client via `/usr/bin/sample` for 8s while the user types at the commandline. This directly names where the time goes (fish reader? highlighting/autosuggestion threads? zellij render loop?) instead of inferring it. Next occurrence: run `lag-sample` in the lagging shell, type junk at the prompt until done, then inspect `~/.local/state/lag-triage/sample-*.txt`. Follow with `unlag` (full reset ladder, never yet truly tested), then A/B toggles: `set -g fish_autosuggestion_enabled 0`, `fish_default_key_bindings`.
|
||||||
|
|
||||||
|
## 2026-08-29 (a root cause found and fixed — but not THE lag)
|
||||||
|
|
||||||
|
- **Root-caused and fixed the recurring post-TUI typing lag** (fish + Zellij + Ghostty) using a `lag-triage` capture from a live lagging shell plus a deterministic PTY reproduction (`presets/programs/lag-triage/upstream_repro.py`):
|
||||||
|
- **Root cause chain**: (1) fish latches feature flags from its **startup environment**, before `config.fish` runs — so the existing `set -gx fish_features no-query-term` in `shellInit` never applied to the shell that set it, only to its children. (2) Zellij spawns pane shells via `default_shell` with no `fish_features` in the environment, so every pane's fish latched `query-term` **on** (the fish 4.8.1 default; the triage log from the lagging shell confirmed `query-term on` while `$fish_features` was correctly set to `no-query-term`). (3) With query-term on, fish sends OSC 11 + CPR (`\e[6n`) + DA1 (`\e[0c`) after **every** command and waits for replies relayed by Zellij. (4) Reproduced on fish 4.8.1: if the terminal fails to reply during just **one** such cycle — answering everything before and after — that fish process's interactive reader is **permanently degraded** (keystroke echo >3s, never recovers; ~35ms before). In production Zellij drops/mangles a relay during TUI teardown or heavy output (cf. zellij-org/zellij#5158), e.g. after `nh home switch`, nvim, jjui, yazi.
|
||||||
|
- **Why every previous observation finally makes sense**: subshells and `exec fish` were never "resetting" anything — they *inherited* the exported `fish_features=no-query-term` from config.fish, latched query-term off at startup, and were therefore **immune**. The parent zellij-spawned shell never had the variable at startup and stayed vulnerable. Raw keystroke capture in the lagging pane showed instant plain bytes (input path fine) and no stuck terminal modes — the damage was inside the fish process, exactly as the repro shows.
|
||||||
|
- **Fix**: `zellij.nix` now spawns panes through a `fish-no-query-term` wrapper (`export fish_features=no-query-term; exec fish`), so the feature is latched off in every pane shell. Verified: interactive fish through the built wrapper with the real config reports `query-term off`; the PTY repro with `no-query-term` in the environment shows ~35ms echo through all failure phases.
|
||||||
|
- **Correction** to the earlier 2026-08-29 entry: `query-term` does **not** default to off in fish 4.8.1 — it defaults on; it only *appeared* off in non-interactive checks because the user config's `set -gx` takes effect for `fish -c` (no reader latch) but not for interactive shells.
|
||||||
|
- Upstream: fish-shell should bound the reader's wait for query replies instead of degrading permanently (repro script kept at `presets/programs/lag-triage/upstream_repro.py` for filing); Zellij's reply relaying is the trigger (zellij-org/zellij#5158).
|
||||||
|
- `lag-triage` now checks `status features` and calls out `query-term on` as the known root cause, and warns that its `read`-prompt typing tests may not exhibit main-commandline lag (which produced a false "fixed by stage A" in the first capture).
|
||||||
|
|
||||||
|
## 2026-08-29 (later)
|
||||||
|
|
||||||
|
- Added a diagnostic toolkit (`lag-triage` / `unlag` fish functions + `term-probe` binary, `presets/programs/lag-triage/`) for the still-recurring post-TUI typing lag in fish + Zellij + Ghostty, instead of another blind fix. Findings that motivated it:
|
||||||
|
- All three prior fixes were either no-ops or insufficient: `fish_features = no-query-term` is a **no-op** because `query-term` already defaults to *off* in fish 4.8.1 (verified with `status features`); disabling Ghostty's fish integration inside Zellij and setting `support_kitty_keyboard_protocol = false` did not stop recurrence.
|
||||||
|
- PTY captures of fish 4.8.1 (`TERM=xterm-256color`, with and without `$ZELLIJ`) show fish never writes Kitty keyboard sequences to the wire — it uses modifyOtherKeys (`\e[>4;1m`), application keypad (`\e=`), bracketed paste (`?2004`), and color-theme reporting (`?2031`), enabling them at every prompt and disabling them before every external command. Crucially, a fresh subshell's startup bytes are identical to the parent's post-command re-enable bytes, so "a subshell fixes the lag" cannot be explained by a simple terminal-state reset — leaving two competing hypotheses that only live capture can separate: (1) fish-internal reader state poisoned by stray/partial escape bytes (e.g. leaked from a closing floating pane), cleared only by a new fish process; (2) Zellij/Ghostty-level stuck state (Zellij 0.45's `StdinAnsiParser` is already a proven source of input delays — see the Alt-Shift-P fix below).
|
||||||
|
- Also note: the floating-pane TUIs (jjui via Alt-Shift-J, yazi via Alt-Shift-Y, scrollback editor) run in their own panes and never pass through the shell's fish process at all, while `nvim` runs inside the shell pane — the triage log records which path preceded the lag.
|
||||||
|
- **Next occurrence: run `lag-triage` in the lagging shell BEFORE starting a new shell.** It snapshots the environment, queries pane terminal state (kitty flags, modifyOtherKeys, DEC modes, DA1 round-trip latency), captures raw keystroke bytes+timing bypassing fish, then applies staged resets (kitty pop/clear, modifyOtherKeys off, keypad/cursor, mouse/focus/sync, altscreen, stty, DECSTR) — the stage that cures it names the stuck layer. Logs to `~/.local/state/lag-triage/` for an upstream issue. `unlag` is the one-shot convenience version (if `unlag` never helps but `exec fish` does, the bug is fish-internal).
|
||||||
|
|
||||||
|
## 2026-08-29
|
||||||
|
|
||||||
|
- Fixed 1.5-second latency when pressing `Alt-Shift-P` to trigger `zellij-session` in Zellij 0.45.0 + Ghostty:
|
||||||
|
- **Root Cause**: Zellij 0.45.0 introduced `StdinAnsiParser` (`zellij-client/src/stdin_ansi_parser.rs`) using `termwiz::InputParser` to parse ANSI control strings (OSCs, CSIs, DCSs) arriving on stdin. When pressing `Alt-Shift-P` (Option-Shift-P) with `support_kitty_keyboard_protocol = false`, Ghostty sent `\x1bP` (`ESC` + uppercase `P`). In ECMA-48 / VT100 standards, `ESC P` is the 7-bit ASCII representation of `DCS` (Device Control String). `StdinAnsiParser` buffered `\x1bP` waiting for a DCS string payload and string terminator (`ST` / `\x1b\`), hitting a ~1.5-second escape timeout before flushing `\x1bP` as residue to the keyboard handler.
|
||||||
|
- **Fix**: Added `alt+shift+p=text:\x1b[112;4u` and `super+shift+p=text:\x1b[112;4u` in `ghostty.nix` to send the explicit CSI-u sequence for `Alt+Shift+p` (`'p'` with modifier 4 = `ALT | SHIFT`). `StdinAnsiParser` immediately recognizes `\x1b[112;4u` as non-DCS input and passes it straight to the keyboard handler with 0ms latency.
|
||||||
|
|
||||||
|
## 2026-08-26
|
||||||
|
|
||||||
|
- Fixed macOS shortcuts (`Cmd+T`, `Ctrl+Tab`, `Cmd+Shift+]`, `Cmd+Shift+[`, `Cmd+K`, `Cmd+Shift+E`) in Zellij + Ghostty after disabling the Kitty keyboard protocol:
|
||||||
|
- Mapped Ghostty keybindings (`super+t`, `super+shift+]`, `super+shift+[`, `ctrl+tab`, `ctrl+shift+tab`, `super+k`, `super+shift+e`) to send standard `Alt` (`ESC`-prefix) text sequences (`\x1bt`, `\x1b}`, `\x1b{`, `\x1bK`, `\x1bE`).
|
||||||
|
- Added matching `Alt` keybindings (`Alt t`, `Alt ]`, `Alt }`, `Alt [`, `Alt {`, `Alt Shift k`, `Alt Shift e`) in `zellij.nix` for tab creation, tab navigation, scroll mode, and scrollback editing. Symbols like `]` and `}` are parsed by Zellij's termwiz input engine as distinct character codes (`'}'` vs `']'`), so binding both `Alt }` and `Alt Shift ]` ensures `\x1b}` triggers tab navigation correctly.
|
||||||
|
- Keeps Kitty keyboard protocol disabled in Zellij (`support_kitty_keyboard_protocol = false`) so no CSI-u flags leak into Fish shell, guaranteeing zero post-TUI typing lag while restoring all shortcuts.
|
||||||
|
|
||||||
|
- Fixed persistent Fish typing lag after long TUI sessions (Neovim, jjui, Yazi) inside Zellij + Ghostty, which the `no-query-term` / Ghostty-integration fixes from 2026-08-25 did not resolve:
|
||||||
|
- Verified on Fish 4.8.1 that the `query-term` feature already defaults to `off`, so exporting `fish_features = no-query-term` is a no-op on this Fish version — it isn't the cause of (or fix for) this class of lag.
|
||||||
|
- Set `support_kitty_keyboard_protocol = false` in `zellij.nix`. Zellij and Ghostty have several open upstream bugs (zellij-org/zellij#3887, #3723, #4178) where the Kitty keyboard protocol's enhancement-flag stack is left in an elevated state after a full-screen TUI exits without properly popping it. Every subsequent keystroke then arrives as a CSI-u sequence that Fish must wait out an escape-disambiguation timeout to parse, which reads as typing lag that worsens the longer the TUI session ran, and persists until the pane's protocol state resets (e.g. a fresh shell/pane). Disabling the protocol support in Zellij avoids the whole bug class; trades off precise modifier reporting (e.g. distinguishing Ctrl+Shift+key) for TUIs running inside Zellij panes, which this setup doesn't otherwise depend on (Shift+Enter is handled via a literal Ghostty `text:` keybind, not the Kitty protocol).
|
||||||
|
|
||||||
|
## 2026-08-25
|
||||||
|
|
||||||
|
- Fixed Nix evaluation warnings for `stdenv` deprecation and `gemini-cli`:
|
||||||
|
- Replaced deprecated `stdenv.isLinux` and `stdenv.isDarwin` checks across module presets and package definitions with `stdenv.hostPlatform.isLinux` and `stdenv.hostPlatform.isDarwin`.
|
||||||
|
- Replaced deprecated `pkgs.gemini-cli` with `pkgs.antigravity-cli` (and updated binary invocation to `agy`) in `experimental.nix` profile and `daily-summary.nix` launchd service.
|
||||||
|
|
||||||
|
## 2026-08-25
|
||||||
|
|
||||||
|
- Fixed multi-second hang and permanent typing latency in Fish after exiting TUIs inside Zellij and Ghostty:
|
||||||
|
- Exported `fish_features = "no-query-term"` in `home.sessionVariables` and added `set -gx fish_features no-query-term` to Fish's top-level `shellInit`. Previous attempt (`set -a fish_features no-query-term` in `interactiveShellInit`) set a local variable inside an anonymous initialization function block that went out of scope immediately after startup. Furthermore, Fish reads `fish_features` at binary launch before interactive init functions run. Without `no-query-term` exported prior to Fish startup, Fish attempted terminal feature queries (Primary Device Attributes `DA1` / `\e[?c` and termcap) whenever a TUI (e.g. Neovim, Lazygit, Yazi) exited and returned control to Fish. Zellij drops or delays DA1 response sequences, causing Fish to block on a multi-second stdin timeout, followed by severe input reader desynchronization and typing latency on every subsequent keystroke.
|
||||||
|
- Disabled `programs.ghostty.enableFishIntegration` and conditionally sourced Ghostty's shell integration script in `shellInit` only when NOT running inside a multiplexer (`not set -q ZELLIJ` and `not set -q TMUX`). Sourcing Ghostty's shell integration inside Zellij sent duplicate and conflicting OSC 133 prompt markers and DECSCUSR cursor escape sequences to Zellij's PTY parser.
|
||||||
|
|
||||||
|
## 2026-08-16
|
||||||
|
|
||||||
|
- Fixed Zellij new tab directory tracking by adding `__fish_update_cwd_osc` override in `presets/programs/zellij.nix`. Fish's default OSC 7 sequence includes `$hostname`, which on macOS or dynamic network environments evaluates to `Noah-MacBook-Pro.local` or a domain suffix. Zellij compares the OSC 7 hostname against its system hostname (`Noah-MacBook-Pro`), finds a mismatch, and silently ignores the CWD update, leaving new tabs stuck in a previous directory or session default. Overriding `__fish_update_cwd_osc` to send `file://<PWD>` (empty hostname) ensures Zellij always updates its cached CWD on every `cd` and prompt render.
|
||||||
|
- Fixed Firefox "profile cannot be loaded" error on macOS by removing `home.file."Library/Application Support/Firefox/installs.ini"`. Hardcoding an installation hash in `installs.ini` broke whenever Firefox was updated or rebuilt in the Nix store because the nix store path changed, causing Firefox to compute a new installation hash, fail to match or write to the read-only `installs.ini` symlink, and error out. Firefox on macOS uses `profiles.ini` (managed by Home Manager) and `MOZ_LEGACY_PROFILES=1` (exported by nixpkgs' launcher wrapper).
|
||||||
|
|
||||||
|
## 2026-08-03
|
||||||
|
|
||||||
|
- Added `presets/security/corporate-ca.nix` (nix-darwin) and enabled it on the
|
||||||
|
`lookingglass` host to trust a corporate TLS-intercepting proxy's root CA.
|
||||||
|
Behind the corp network, Nix fetches failed with `SSL peer certificate ...
|
||||||
|
self-signed certificate in certificate chain (19)` because Nix's stock Mozilla
|
||||||
|
CA bundle doesn't contain the interception root. The module appends the cert
|
||||||
|
to `security.pki.certificateFiles`, which rebuilds
|
||||||
|
`/etc/ssl/certs/ca-certificates.crt` (read by both the Nix daemon and, via
|
||||||
|
`NIX_SSL_CERT_FILE`, client-side flake fetches).
|
||||||
|
|
||||||
|
The cert is kept **out of this public repo** and referenced by absolute path.
|
||||||
|
It is passed as a string (not a Nix path literal) so pure flake evaluation
|
||||||
|
doesn't read it at eval time, and it lives at a root-owned, world-readable
|
||||||
|
path because the unprivileged `nixbld` build user cannot traverse `$HOME`
|
||||||
|
(mode `0750`) to read it at build time.
|
||||||
|
|
||||||
|
One-time setup on a machine behind the proxy:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# 1. Extract the self-signed corporate root from any TLS connection it MITMs
|
||||||
|
# (the last cert in the chain, subject == issuer). Any HTTPS host works:
|
||||||
|
echo | openssl s_client -connect example.com:443 -servername example.com \
|
||||||
|
-showcerts 2>/dev/null \
|
||||||
|
| awk '/BEGIN CERT/{c++} c==2' > /tmp/CorpCA.pem
|
||||||
|
openssl x509 -in /tmp/CorpCA.pem -noout -subject -issuer # sanity check
|
||||||
|
|
||||||
|
# 2. Install to the root-owned path the config points at:
|
||||||
|
sudo install -d -m 0755 -o root -g wheel /etc/ssl/corp-ca
|
||||||
|
sudo install -m 0644 -o root -g wheel /tmp/CorpCA.pem \
|
||||||
|
/etc/ssl/corp-ca/CorpCA.pem
|
||||||
|
|
||||||
|
# 3. Bootstrap the first rebuild (which must fetch inputs over the proxy)
|
||||||
|
# with a combined bundle, then it's permanent:
|
||||||
|
cat /etc/ssl/certs/ca-certificates.crt /etc/ssl/corp-ca/CorpCA.pem \
|
||||||
|
> /tmp/combined-ca.crt
|
||||||
|
NIX_SSL_CERT_FILE=/tmp/combined-ca.crt nh darwin switch . --configuration lookingglass
|
||||||
|
```
|
||||||
|
|
||||||
|
- Fixed the `zellij-session` fish function in `presets/programs/zellij.nix`
|
||||||
|
truncating the session name (derived from the target directory basename)
|
||||||
|
to 20 characters. Zellij names each session's Unix-domain IPC socket
|
||||||
|
`$TMPDIR/zellij-<uid>/<version>/<name>`, and on macOS the socket path is
|
||||||
|
capped at 103 bytes. The `/var/folders/...` `$TMPDIR` prefix consumes ~79
|
||||||
|
of those, leaving only ~24 chars for the name, so switching into directories
|
||||||
|
with long basenames overflowed the socket path. Because `switch-session`
|
||||||
|
had already detached from the current session by the time the new one failed
|
||||||
|
to bind, the failure took down the entire terminal instead of erroring
|
||||||
|
gracefully.
|
||||||
|
|
||||||
|
## 2026-09-06
|
||||||
|
|
||||||
|
- Configured Grafana OIDC authentication via Pocket ID in `platforms/nixos/modules/nmasur/presets/services/grafana/grafana.nix`.
|
||||||
|
- Enabled `auth.oauth_allow_insecure_email_lookup = true` in Grafana settings to allow linking an incoming OAuth login to an existing Grafana user account with the same email.
|
||||||
|
|
||||||
|
## 2026-07-25
|
||||||
|
|
||||||
|
- Added jjui config generation to `jujutsu.nix` in Home Manager to include custom GitHub ruleset bypass commands (`ctrl+b` and `ctrl+shift+b`).
|
||||||
|
- Added `overlays/cheetah3.nix` to disable `pythonMetadataCheckPhase` for `cheetah3`.
|
||||||
|
This fixes an issue where the NixOS rebuild fails for `sabnzbd` due to `importlib.metadata.PackageNotFoundError: No package metadata was found for cheetah3` during the Python package evaluation in `nixos-unstable`.
|
||||||
|
|
||||||
|
## 2026-07-20
|
||||||
|
|
||||||
|
- Added `overlays/paho-mqtt.nix` to disable paho-mqtt's flaky, socket-based
|
||||||
|
test suite. Its `checkPhase` hangs in the Nix sandbox and times out with a
|
||||||
|
`KeyboardInterrupt` after ~150s, which was breaking the `flame` rebuild
|
||||||
|
(paho-mqtt is pulled in transitively, e.g. via mealie). The override is
|
||||||
|
applied through `pythonPackagesExtensions` so it covers every Python
|
||||||
|
package set.
|
||||||
@@ -0,0 +1,275 @@
|
|||||||
|
# OIDC Service Analysis & Setup Requirements
|
||||||
|
|
||||||
|
This document analyzes the services defined in this repository (specifically within `platforms/nixos/modules/nmasur/presets/services/` and related server profiles like `flame` and `swan`), evaluates their OpenID Connect (OIDC) compatibility, and details the requirements for configuring OIDC logins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Identity Provider Context: Pocket ID
|
||||||
|
|
||||||
|
The configuration already includes a central self-hosted identity provider: **Pocket ID** (`platforms/nixos/modules/nmasur/presets/services/pocket-id/pocket-id.nix`), hosted on the communications server (`flame`) behind Caddy at **`https://auth.masu.rs`**.
|
||||||
|
|
||||||
|
Pocket ID is an OpenID Connect (OIDC) provider with WebAuthn/Passkey support. It exposes the following standard OIDC endpoints:
|
||||||
|
- **Issuer URL:** `https://auth.masu.rs`
|
||||||
|
- **Discovery Endpoint:** `https://auth.masu.rs/.well-known/openid-configuration`
|
||||||
|
- **Authorization Endpoint:** `https://auth.masu.rs/authorize`
|
||||||
|
- **Token Endpoint:** `https://auth.masu.rs/api/oidc/token`
|
||||||
|
- **Userinfo Endpoint:** `https://auth.masu.rs/api/oidc/userinfo`
|
||||||
|
- **JWKS Endpoint:** `https://auth.masu.rs/.well-known/jwks.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Service Compatibility Breakdown
|
||||||
|
|
||||||
|
### Tier 1: First-Class / Native OIDC Support
|
||||||
|
|
||||||
|
These services support OpenID Connect natively without requiring external authentication proxies or custom code:
|
||||||
|
|
||||||
|
| Service | Hostname | OIDC Support Level | Configuration Method |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **Immich** | `photos.masu.rs` | Native core feature | NixOS config (`services.immich.settings.oauth`) |
|
||||||
|
| **Gitea** | `git.masu.rs` | Native core feature | NixOS config / CLI or Web UI |
|
||||||
|
| **Nextcloud** | `cloud.masu.rs` | Native (official `user_oidc` app) | Nextcloud app + `nextcloud-occ user_oidc:provider` |
|
||||||
|
| **Grafana** | `metrics.masu.rs` | Native (Generic OAuth) | NixOS config (`services.grafana.settings."auth.generic_oauth"`) |
|
||||||
|
| **Paperless-ngx** | `paper.masu.rs` | Native (`django-allauth`) | NixOS env vars (`PAPERLESS_SOCIALACCOUNT_PROVIDERS`) |
|
||||||
|
| **Mealie** | `cooking.masu.rs` | Native core feature | NixOS config (`services.mealie.settings` + `credentialsFile`) |
|
||||||
|
| **Karakeep / Hoarder** | `keep.masu.rs` | Native (NextAuth OIDC) | NixOS env vars (`OAUTH_WELLKNOWN_URL`, etc.) |
|
||||||
|
| **Audiobookshelf** | `read.masu.rs` | Native core feature (v2.3+) | Web UI (Settings → Authentication) |
|
||||||
|
| **Actual Budget** | `money.masu.rs` | Native core feature (v24.3+) | NixOS config (`services.actual.settings.openId`) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Tier 2: OIDC via Plugins or Reverse Proxy Header Auth
|
||||||
|
|
||||||
|
These services do not have generic OIDC in their core web UI, but can support single sign-on through plugins or reverse proxy headers (`Remote-User` / `X-Forwarded-User`):
|
||||||
|
|
||||||
|
| Service | Hostname | Strategy | Notes |
|
||||||
|
| :--- | :--- | :--- | :--- |
|
||||||
|
| **Jellyfin** | `stream.masu.rs` | `jellyfin-plugin-sso` | Web clients work well; TV and native apps typically rely on Quick Connect. |
|
||||||
|
| **Calibre-Web** | `books.masu.rs` | Reverse proxy header auth | Set `services.calibre-web.options.reverseProxyAuth.enable = true` behind an authenticating reverse proxy. |
|
||||||
|
| **File Browser** | `files.masu.rs` | Reverse proxy header auth | Set `auth.method = "proxy"` and `auth.header = "X-Forwarded-User"` behind an authenticating reverse proxy. |
|
||||||
|
| **Navidrome** | `music.masu.rs` | Reverse proxy header auth | Supports `ReverseProxyUserHeader` for web UI; Subsonic API clients (Feishin, etc.) still require native user passwords. |
|
||||||
|
| **Stalwart** | `contacts.masu.rs` | OIDC Directory / SASL OAuth | Stalwart supports OIDC directories, but CardDAV/CalDAV clients usually require HTTP Basic Auth or application passwords. |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Tier 3: Incompatible or No Native OIDC Support
|
||||||
|
|
||||||
|
- **Vaultwarden (`vault.masu.rs`):** Incompatible for vault decryption. Vaultwarden uses client-side zero-knowledge encryption where vault keys are derived from the user's master password. Bitwarden Enterprise SSO relies on a proprietary Key Connector that Vaultwarden does not implement.
|
||||||
|
- **n8n (`n8n.masu.rs`):** SAML/OIDC SSO is an **Enterprise / commercial-only feature**; it is disabled in the free self-hosted Community edition.
|
||||||
|
- **The Arr Stack (`download.masu.rs`):** Radarr, Sonarr, Lidarr, Readarr, Prowlarr, Bazarr, and Sabnzbd only support API keys, Basic Auth, or Forms.
|
||||||
|
- **Transmission (`transmission.masu.rs`):** BitTorrent daemon; supports only HTTP Basic Auth / RPC whitelist.
|
||||||
|
- **Uptime Kuma (`status.masu.rs`), ntfy (`ntfy.masu.rs`), The Lounge (`irc.masu.rs`), Pgweb (`pg.masu.rs`), Mathesar (`mathesar.masu.rs`), Hister (`hister.masu.rs`):** No native generic OIDC login mechanism.
|
||||||
|
- **Infrastructure / Daemon Services:** PostgreSQL, InfluxDB, bind, avahi, cloudflared, wireguard, litestream (no user web UI).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. General Setup Requirements
|
||||||
|
|
||||||
|
Configuring OIDC requires setup across four layers:
|
||||||
|
|
||||||
|
### A. Pocket ID Setup
|
||||||
|
For each service, an OIDC client application must be registered in the Pocket ID admin interface:
|
||||||
|
1. **Client ID:** A unique identifier slug (e.g. `gitea`, `immich`, `paperless`).
|
||||||
|
2. **Client Secret:** A cryptographically secure random token.
|
||||||
|
3. **Redirect URIs / Callback URLs:** The exact target URLs the service exposes for authorization code callbacks.
|
||||||
|
4. **Scopes:** Usually `openid`, `profile`, and `email`.
|
||||||
|
|
||||||
|
### B. Secrets Management (agenix)
|
||||||
|
All client secrets should be encrypted with `agenix` under the respective service directory:
|
||||||
|
- Example: `platforms/nixos/modules/nmasur/presets/services/<service>/<service>-oidc.age`
|
||||||
|
- Defined in NixOS under `config.secrets.<service>-oidc` with appropriate owner/group permissions.
|
||||||
|
|
||||||
|
### C. Network & Reverse Proxy (Caddy)
|
||||||
|
1. **Back-Channel Connectivity:** When a user logs in, the service backend makes a server-to-server HTTPS call to `https://auth.masu.rs/api/oidc/token` to exchange the authorization code for tokens. Services hosted on `swan` (NAS) must be able to resolve and reach `auth.masu.rs` over HTTPS.
|
||||||
|
2. **Proxy Headers:** Caddy's `reverse_proxy` handles `X-Forwarded-Proto`, `X-Forwarded-Host`, and `X-Forwarded-For` by default. Services should have reverse proxy trust enabled (e.g., `trusted_proxies = ["127.0.0.1"]`) so generated redirect URIs preserve the `https://` scheme.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Detailed Setup Requirements for Tier 1 Services
|
||||||
|
|
||||||
|
### 1. Immich (`photos.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URIs:**
|
||||||
|
- Web: `https://photos.masu.rs/auth/login`
|
||||||
|
- Mobile: `app.immich:///oauth-callback`
|
||||||
|
- **Setup in `immich/immich.nix`:**
|
||||||
|
```nix
|
||||||
|
services.immich.settings.oauth = {
|
||||||
|
enabled = true;
|
||||||
|
issuerUrl = "https://${hostnames.auth}";
|
||||||
|
clientId = "1f4e0f8d-6cee-4d67-8d53-74bf6c18ae09";
|
||||||
|
clientSecret._secret = config.secrets.immich-oidc-secret.dest;
|
||||||
|
scope = "openid profile email";
|
||||||
|
autoRegister = true;
|
||||||
|
buttonText = "Login with Pocket ID";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Gitea (`git.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://git.masu.rs/user/oauth2/pocket-id/callback`
|
||||||
|
- **Setup in Gitea:**
|
||||||
|
Can be configured in the Web UI under **Site Administration → Authentication Sources** or via CLI:
|
||||||
|
```bash
|
||||||
|
gitea admin auth add-oauth \
|
||||||
|
--name "Pocket ID" \
|
||||||
|
--provider openidConnect \
|
||||||
|
--key "<client_id>" \
|
||||||
|
--secret "<client_secret>" \
|
||||||
|
--auto-discover-url "https://auth.masu.rs/.well-known/openid-configuration"
|
||||||
|
```
|
||||||
|
- Optional: Enable automatic account linking by matching email.
|
||||||
|
|
||||||
|
### 3. Nextcloud (`cloud.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://cloud.masu.rs/apps/user_oidc/code`
|
||||||
|
- **Setup in `nextcloud/nextcloud.nix`:**
|
||||||
|
```nix
|
||||||
|
secrets.nextcloud-oidc-secret = {
|
||||||
|
source = ./nextcloud-oidc-secret.age;
|
||||||
|
dest = "${config.secretsDirectory}/nextcloud-oidc-secret";
|
||||||
|
owner = "nextcloud";
|
||||||
|
group = "nextcloud";
|
||||||
|
permissions = "0440";
|
||||||
|
};
|
||||||
|
systemd.services.nextcloud-oidc-secret-secret = {
|
||||||
|
requiredBy = [ "nextcloud-setup.service" ];
|
||||||
|
before = [ "nextcloud-setup.service" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.nextcloud = {
|
||||||
|
settings.overwriteprotocol = "https";
|
||||||
|
extraApps = {
|
||||||
|
user_oidc = config.services.nextcloud.package.packages.apps.user_oidc;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
systemd.services.nextcloud-setup = {
|
||||||
|
after = [ "nextcloud-oidc-secret-secret.service" ];
|
||||||
|
postStart = ''
|
||||||
|
${config.services.nextcloud.occ}/bin/nextcloud-occ user_oidc:provider pocket-id \
|
||||||
|
--clientid="c8a32c58-a781-4f14-9070-f498fdfda438" \
|
||||||
|
--clientsecret-file="${config.secrets.nextcloud-oidc-secret.dest}" \
|
||||||
|
--discoveryuri="https://${hostnames.auth}/.well-known/openid-configuration" \
|
||||||
|
--scope="openid profile email" \
|
||||||
|
--mapping-uid="preferred_username" \
|
||||||
|
--unique-uid=0
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Grafana (`metrics.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://metrics.masu.rs/login/generic_oauth`
|
||||||
|
- **Setup in `grafana/grafana.nix`:**
|
||||||
|
```nix
|
||||||
|
services.grafana.settings = {
|
||||||
|
auth.oauth_allow_insecure_email_lookup = true;
|
||||||
|
"auth.generic_oauth" = {
|
||||||
|
enabled = true;
|
||||||
|
name = "Pocket ID";
|
||||||
|
allow_sign_up = true;
|
||||||
|
client_id = "85d879ed-1a86-4984-b33d-43806500ef98";
|
||||||
|
client_secret = "$__file{${config.secrets.grafana-oidc-secret.dest}}";
|
||||||
|
scopes = "openid profile email";
|
||||||
|
auth_url = "https://${hostnames.auth}/authorize";
|
||||||
|
token_url = "https://${hostnames.auth}/api/oidc/token";
|
||||||
|
api_url = "https://${hostnames.auth}/api/oidc/userinfo";
|
||||||
|
login_attribute_path = "preferred_username";
|
||||||
|
skip_org_role_sync = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. Paperless-ngx (`paper.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://paper.masu.rs/accounts/oidc/pocket-id/login/callback/`
|
||||||
|
- **Setup in `paperless/paperless.nix`:**
|
||||||
|
```nix
|
||||||
|
services.paperless.settings = {
|
||||||
|
PAPERLESS_APPS = "allauth.socialaccount.providers.openid_connect";
|
||||||
|
PAPERLESS_REDIRECT_LOGIN_TO_SSO = true;
|
||||||
|
};
|
||||||
|
# Configured via environmentFile to pass the client secret, enable PKCE, and link by email:
|
||||||
|
# PAPERLESS_SOCIALACCOUNT_PROVIDERS = builtins.toJSON {
|
||||||
|
# openid_connect = {
|
||||||
|
# APPS = [
|
||||||
|
# {
|
||||||
|
# provider_id = "pocket-id";
|
||||||
|
# name = "Pocket ID";
|
||||||
|
# client_id = "e6ff7fce-8e67-4c66-8f32-5ec3db4740a9";
|
||||||
|
# secret = "...";
|
||||||
|
# settings = {
|
||||||
|
# server_url = "https://auth.masu.rs";
|
||||||
|
# token_auth_method = "client_secret_basic";
|
||||||
|
# oauth_pkce_enabled = true;
|
||||||
|
# email_authentication = true;
|
||||||
|
# verified_email = true;
|
||||||
|
# };
|
||||||
|
# }
|
||||||
|
# ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. Mealie (`cooking.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://cooking.masu.rs/login`
|
||||||
|
- **Setup in `mealie/mealie.nix`:**
|
||||||
|
```nix
|
||||||
|
services.mealie = {
|
||||||
|
credentialsFile = config.secrets.mealie-oidc-secret.dest;
|
||||||
|
settings = {
|
||||||
|
OIDC_AUTH_ENABLED = "true";
|
||||||
|
OIDC_SIGNUP_ENABLED = "true";
|
||||||
|
OIDC_CONFIGURATION_URL = "https://${hostnames.auth}/.well-known/openid-configuration";
|
||||||
|
OIDC_CLIENT_ID = "040925ed-b39e-4442-b8e8-369c948c0cd2";
|
||||||
|
OIDC_PROVIDER_NAME = "Pocket ID";
|
||||||
|
OIDC_USER_CLAIM = "email";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 7. Karakeep / Hoarder (`keep.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://keep.masu.rs/api/auth/callback/custom`
|
||||||
|
- **Setup in `karakeep.nix`:**
|
||||||
|
```nix
|
||||||
|
services.karakeep.extraEnvironment = {
|
||||||
|
OAUTH_WELLKNOWN_URL = "https://auth.masu.rs/.well-known/openid-configuration";
|
||||||
|
OAUTH_CLIENT_ID = "hoarder";
|
||||||
|
OAUTH_CLIENT_SECRET = "...";
|
||||||
|
OAUTH_PROVIDER_NAME = "Pocket ID";
|
||||||
|
OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING = "true";
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8. Audiobookshelf (`read.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URIs:**
|
||||||
|
- Web: `https://read.masu.rs/auth/openid/callback`
|
||||||
|
- Mobile: `audiobookshelf://oauth`
|
||||||
|
- **Setup in Audiobookshelf:**
|
||||||
|
Configured in the Web UI (**Settings → Authentication → OpenID Connect**):
|
||||||
|
- Issuer URL: `https://auth.masu.rs`
|
||||||
|
- Client ID & Client Secret
|
||||||
|
- Match user by email or username
|
||||||
|
|
||||||
|
### 9. Actual Budget (`money.masu.rs`)
|
||||||
|
- **Pocket ID Redirect URI:** `https://money.masu.rs/openid/callback`
|
||||||
|
- **Setup in `actualbudget/actualbudget.nix`:**
|
||||||
|
```nix
|
||||||
|
services.actual.settings = {
|
||||||
|
loginMethod = "openid";
|
||||||
|
openId = {
|
||||||
|
discoveryURL = "https://${hostnames.auth}/.well-known/openid-configuration";
|
||||||
|
client_id = "92afe9f8-7ef6-42ab-8a06-701df3c7179d";
|
||||||
|
client_secret._secret = config.secrets.actualbudget-oidc-secret.dest;
|
||||||
|
server_hostname = "https://${hostnames.budget}";
|
||||||
|
authMethod = "openid";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
```
|
||||||
|
*Note:* The optional end-to-end budget encryption password remains separate from the server authentication.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Forward Auth Architecture for Remaining Services
|
||||||
|
|
||||||
|
For services without native OIDC support (such as Calibre-Web, File Browser, Uptime Kuma, and the Arr stack), you can implement **Forward Auth via Caddy**:
|
||||||
|
|
||||||
|
1. Deploy an authenticating proxy (such as **OAuth2-Proxy** or **Authelia**) configured with Pocket ID as its OIDC provider.
|
||||||
|
2. Configure Caddy routes using the `forward_auth` directive to verify user sessions with the proxy before forwarding requests to the target service.
|
||||||
|
3. For services supporting reverse proxy authentication (Calibre-Web and File Browser), Caddy injects identity headers (e.g. `Remote-User: noah` or `X-Forwarded-User: noah`), enabling seamless single sign-on without requiring separate logins.
|
||||||
Generated
+313
-161
@@ -1,12 +1,18 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"cl-nix-lite": {
|
"cl-nix-lite": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-parts": "flake-parts",
|
||||||
|
"nixpkgs": "nixpkgs",
|
||||||
|
"systems": "systems",
|
||||||
|
"treefmt-nix": "treefmt-nix"
|
||||||
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1728174978,
|
"lastModified": 1782994178,
|
||||||
"narHash": "sha256-Grqqg+xuicANB85j0gNEXxi9SBKY7bzGeTuyi95eGcY=",
|
"narHash": "sha256-VGc3/2fe6hnOmNSLlOygEAbeS69v7A7rjKDKRzAgE2Q=",
|
||||||
"owner": "hraban",
|
"owner": "hraban",
|
||||||
"repo": "cl-nix-lite",
|
"repo": "cl-nix-lite",
|
||||||
"rev": "31cfe6275c341eb3120a99f4b1c8516c49a29d87",
|
"rev": "eb584721e5e799bafe0c6210a8a1a398f90e8ac0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -22,11 +28,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742013980,
|
"lastModified": 1786845137,
|
||||||
"narHash": "sha256-34YbfwABU5nb0F5eaaJE3ujldaNDhmyxw7CWqhXJV08=",
|
"narHash": "sha256-oQFip+v0luP8NIxJzmiW4Wu8bILsbFWom5l0zonl8hQ=",
|
||||||
"owner": "lnl7",
|
"owner": "lnl7",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "9175b4bb5f127fb7b5784b14f7e01abff24c378f",
|
"rev": "4cff07de74b50e64bdd68cd4e722ab5b6b35ee48",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -43,11 +49,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1741786315,
|
"lastModified": 1781152676,
|
||||||
"narHash": "sha256-VT65AE2syHVj6v/DGB496bqBnu1PXrrzwlw07/Zpllc=",
|
"narHash": "sha256-RxWs5ND31KzTG7wvMM+PMfUjyNpmIEr999lqNARaM5o=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "disko",
|
"repo": "disko",
|
||||||
"rev": "0d8c6ad4a43906d14abd5c60e0ffe7b587b213de",
|
"rev": "ff8702b4de27f72b4c78573dfb89ec74e36abdf1",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -59,11 +65,11 @@
|
|||||||
"flake-compat": {
|
"flake-compat": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1730663653,
|
"lastModified": 1766808011,
|
||||||
"narHash": "sha256-kFCUWettiFHDIqxCWWQ9qY8pVh+Lj+XL0Giyy/kdomg=",
|
"narHash": "sha256-s83BS0abtIj7vzUf8JE0209KphfHA6qRw/92D9k/F+0=",
|
||||||
"owner": "hraban",
|
"owner": "hraban",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "e5b16676185cb7548581c852f51ce7f3a49bba5e",
|
"rev": "6e0aafdc4c4c2043c66f756d5045374b42184fc5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -76,11 +82,27 @@
|
|||||||
"flake-compat_2": {
|
"flake-compat_2": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1733328505,
|
"lastModified": 1767039857,
|
||||||
"narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "flake-compat",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-compat_3": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1767039857,
|
||||||
|
"narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
|
||||||
"owner": "edolstra",
|
"owner": "edolstra",
|
||||||
"repo": "flake-compat",
|
"repo": "flake-compat",
|
||||||
"rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
|
"rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -90,6 +112,24 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"flake-parts": {
|
"flake-parts": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs-lib": "nixpkgs-lib"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765835352,
|
||||||
|
"narHash": "sha256-XswHlK/Qtjasvhd1nOa1e8MgZ8GS//jBoTqWtrS1Giw=",
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"rev": "a34fae9c08a15ad73f295041fec82323541400a9",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hercules-ci",
|
||||||
|
"repo": "flake-parts",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"flake-parts_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs-lib": [
|
"nixpkgs-lib": [
|
||||||
"nur",
|
"nur",
|
||||||
@@ -132,14 +172,14 @@
|
|||||||
},
|
},
|
||||||
"flake-utils_2": {
|
"flake-utils_2": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems_2"
|
"systems": "systems_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705309234,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -155,11 +195,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1741955947,
|
"lastModified": 1789183968,
|
||||||
"narHash": "sha256-2lbURKclgKqBNm7hVRtWh0A7NrdsibD0EaWhahUVhhY=",
|
"narHash": "sha256-pEWnYdIF1pBMZwarp/rEPzl+Lknhm5hhjSfeLxH8nAA=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "4e12151c9e014e2449e0beca2c0e9534b96a26b4",
|
"rev": "cd1c9e552f41894aeb5cc5cb353d5a1d61550357",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -174,77 +214,64 @@
|
|||||||
"cl-nix-lite": "cl-nix-lite",
|
"cl-nix-lite": "cl-nix-lite",
|
||||||
"flake-compat": "flake-compat",
|
"flake-compat": "flake-compat",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
|
"nixpkgs": "nixpkgs_3",
|
||||||
|
"systems": "systems_2",
|
||||||
|
"treefmt-nix": "treefmt-nix_2"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1783182903,
|
||||||
|
"narHash": "sha256-7IteXipJZfFepi5zakxe0jQ5i3vRBQguk0+Gtte1Fu4=",
|
||||||
|
"owner": "hraban",
|
||||||
|
"repo": "mac-app-util",
|
||||||
|
"rev": "039f33deef21782d4db97087f426504951239887",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "hraban",
|
||||||
|
"repo": "mac-app-util",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-caddy-withplugins": {
|
||||||
|
"inputs": {
|
||||||
|
"flake-compat": "flake-compat_2",
|
||||||
|
"nixpkgs": "nixpkgs_5"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1784936738,
|
||||||
|
"narHash": "sha256-X4w9BrFkisfzla3m1WwDJUicUbI7JRdhzq5aS7rrB0k=",
|
||||||
|
"owner": "MichailiK",
|
||||||
|
"repo": "nix-caddy-withplugins",
|
||||||
|
"rev": "70307cfc568e5434cf42067d797b27c38ea69944",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "MichailiK",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nix-caddy-withplugins",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nix-index-database": {
|
||||||
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
]
|
||||||
"systems": "systems"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1739821351,
|
"lastModified": 1788680125,
|
||||||
"narHash": "sha256-QlVtMzAhECs9Esq3txqVW7/vM78ipB5IcI8uyCbTP7A=",
|
"narHash": "sha256-amGSoDobwmp4CFvCn841ws2iuitus+HUJdD/gKgsrJA=",
|
||||||
"owner": "hraban",
|
"owner": "nix-community",
|
||||||
"repo": "mac-app-util",
|
"repo": "nix-index-database",
|
||||||
"rev": "c00d5b21ca1fdab8acef65e696795f0f15ec1158",
|
"rev": "116ad1c2adb642405ef8916f6a94c8626f971344",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "hraban",
|
"owner": "nix-community",
|
||||||
"repo": "mac-app-util",
|
"repo": "nix-index-database",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nextcloud-cookbook": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1726214817,
|
|
||||||
"narHash": "sha256-Pfa+Xbopg20os+pnGgg+wpEX1MI5fz5JMb0K4a8rBhs=",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/cookbook-0.11.2.tar.gz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/cookbook-0.11.2.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nextcloud-external": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1729501365,
|
|
||||||
"narHash": "sha256-OV6HhFBzmnQBO5btGEnqmKlaUMY7/t2Qm3XebclpBlM=",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/nextcloud-releases/external/releases/download/v5.5.2/external-v5.5.2.tar.gz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/nextcloud-releases/external/releases/download/v5.5.2/external-v5.5.2.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nextcloud-news": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1729667622,
|
|
||||||
"narHash": "sha256-pnvyMZQ+NYMgH0Unfh5S19HdZSjnghgoUDAoi2KIXNI=",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nextcloud-snappymail": {
|
|
||||||
"flake": false,
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1728502660,
|
|
||||||
"narHash": "sha256-oCw6Brs85rINBHvz3UJXheyLVqvA3RgPXG03b30Fx7E=",
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://snappymail.eu/repository/nextcloud/snappymail-2.38.2-nextcloud.tar.gz"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"type": "tarball",
|
|
||||||
"url": "https://snappymail.eu/repository/nextcloud/snappymail-2.38.2-nextcloud.tar.gz"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nix2vim": {
|
"nix2vim": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-utils": "flake-utils_2",
|
"flake-utils": "flake-utils_2",
|
||||||
@@ -253,11 +280,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1740943170,
|
"lastModified": 1779563638,
|
||||||
"narHash": "sha256-A0F7T/euSMen004cVQN/ZkMpLkgLXDs+mq/merhd+0Y=",
|
"narHash": "sha256-9CQKxDKDqVYdDhJW+A955AZwpwZjKUgvu0LbfsL6uyI=",
|
||||||
"owner": "gytis-ivaskevicius",
|
"owner": "gytis-ivaskevicius",
|
||||||
"repo": "nix2vim",
|
"repo": "nix2vim",
|
||||||
"rev": "a562f32ff2393d0ed198103c65a3035bcdf83d4d",
|
"rev": "6927414f0de10a18fb6bc9977717088777d50d0d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -289,11 +316,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1740947705,
|
"lastModified": 1769813415,
|
||||||
"narHash": "sha256-Co2kAD2SZalOm+5zoxmzEVZNvZ17TyafuFsD46BwSdY=",
|
"narHash": "sha256-nnVmNNKBi1YiBNPhKclNYDORoHkuKipoz7EtVnXO50A=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nixos-generators",
|
"repo": "nixos-generators",
|
||||||
"rev": "507911df8c35939050ae324caccc7cf4ffb76565",
|
"rev": "8946737ff703382fda7623b9fab071d037e897d5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -304,11 +331,122 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742069588,
|
"lastModified": 1779796641,
|
||||||
"narHash": "sha256-C7jVfohcGzdZRF6DO+ybyG/sqpo1h6bZi9T56sxLy+k=",
|
"narHash": "sha256-ZsIrKmhp4vbBXoXXmR/tBXA/UCsAQiJL9vsgZEduhVY=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "c80f6a7e10b39afcc1894e02ef785b1ad0b0d7e5",
|
"rev": "25f538306313eae3927264466c70d7001dcea1df",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-25.11",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-lib": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1765674936,
|
||||||
|
"narHash": "sha256-k00uTP4JNfmejrCLJOwdObYC9jHRrr/5M/a/8L2EIdo=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"rev": "2075416fcb47225d9b68ac469a5c4801a9c4dd85",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "nixpkgs.lib",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs-stable": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1789114715,
|
||||||
|
"narHash": "sha256-ugpsyk3NM2s87vXfUiIIiibbJ4Pp0JPS5p/3mfs+q+c=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "21a67dc470149f337cecafbe965d8d252a390518",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixos-26.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1761236834,
|
||||||
|
"narHash": "sha256-+pthv6hrL5VLW2UqPdISGuLiUZ6SnAXdd2DdUE+fV2Q=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "d5faa84122bc0a1fd5d378492efce4e289f8eac1",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_3": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1782999065,
|
||||||
|
"narHash": "sha256-5Dgj5+pIQYZKrXUGaLCk7CKfN3MmpwIhO94++WVxvng=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "80d591ed473cfc46329932c2aadac9b435342c7c",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-26.05",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_4": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770107345,
|
||||||
|
"narHash": "sha256-tbS0Ebx2PiA1FRW8mt8oejR0qMXmziJmPaU1d4kYY9g=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "4533d9293756b63904b7238acb84ac8fe4c8c2c4",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nixos",
|
||||||
|
"ref": "nixpkgs-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_5": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1781074563,
|
||||||
|
"narHash": "sha256-md8WlXOlfnIeHeOScMTTHFyf2d6iaTwPl2apR5EQ3P4=",
|
||||||
|
"owner": "NixOS",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "9ae611a455b90cf061d8f332b977e387bda8e1ca",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "NixOS",
|
||||||
|
"ref": "nixos-unstable",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nixpkgs_6": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1789006805,
|
||||||
|
"narHash": "sha256-xB8mKMOx1IA9vTDNLmJZ6n4wCMq/cuWBBOzGCRnqxrU=",
|
||||||
|
"owner": "nixos",
|
||||||
|
"repo": "nixpkgs",
|
||||||
|
"rev": "8ce4ef6cb6f871616146b9fe26d2a5ae594e94fe",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -318,29 +456,13 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs-stable": {
|
"nixpkgs_7": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1735563628,
|
"lastModified": 1744536153,
|
||||||
"narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=",
|
"narHash": "sha256-awS2zRgF4uTwrOKwwiJcByDzDOdo3Q1rPZbiHQg/N38=",
|
||||||
"owner": "nixos",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nixos",
|
|
||||||
"ref": "nixos-24.05",
|
|
||||||
"repo": "nixpkgs",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"nixpkgs_2": {
|
|
||||||
"locked": {
|
|
||||||
"lastModified": 1728538411,
|
|
||||||
"narHash": "sha256-f0SBJz1eZ2yOuKUr5CA9BHULGXVSn6miBuUWdTyhUhU=",
|
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "b69de56fac8c2b6f8fd27f2eca01dcda8e0a4221",
|
"rev": "18dd725c29603f582cf1900e0d25f9f1063dbf11",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -352,18 +474,17 @@
|
|||||||
},
|
},
|
||||||
"nur": {
|
"nur": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-parts": "flake-parts",
|
"flake-parts": "flake-parts_2",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
]
|
||||||
"treefmt-nix": "treefmt-nix"
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1742145955,
|
"lastModified": 1789200175,
|
||||||
"narHash": "sha256-ju1J45e22ebpLH3eSm0ZZYg7WHkN01ryTFv+4UNwCOA=",
|
"narHash": "sha256-JriLm/izGMXB4uAHWXKj13kXa3nKZj2r/sR5xHdisgs=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "nur",
|
"repo": "nur",
|
||||||
"rev": "d6ba59dd58ebe6c184f955e1d3a4bbca9484c018",
|
"rev": "2c789298fc525713063e3b88359d02101651144f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -378,15 +499,14 @@
|
|||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"home-manager": "home-manager",
|
"home-manager": "home-manager",
|
||||||
"mac-app-util": "mac-app-util",
|
"mac-app-util": "mac-app-util",
|
||||||
"nextcloud-cookbook": "nextcloud-cookbook",
|
"nix-caddy-withplugins": "nix-caddy-withplugins",
|
||||||
"nextcloud-external": "nextcloud-external",
|
"nix-index-database": "nix-index-database",
|
||||||
"nextcloud-news": "nextcloud-news",
|
|
||||||
"nextcloud-snappymail": "nextcloud-snappymail",
|
|
||||||
"nix2vim": "nix2vim",
|
"nix2vim": "nix2vim",
|
||||||
"nixos-generators": "nixos-generators",
|
"nixos-generators": "nixos-generators",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs_6",
|
||||||
"nixpkgs-stable": "nixpkgs-stable",
|
"nixpkgs-stable": "nixpkgs-stable",
|
||||||
"nur": "nur",
|
"nur": "nur",
|
||||||
|
"rust-overlay": "rust-overlay",
|
||||||
"wsl": "wsl",
|
"wsl": "wsl",
|
||||||
"zellij-switch": "zellij-switch",
|
"zellij-switch": "zellij-switch",
|
||||||
"zenyd-mpv-scripts": "zenyd-mpv-scripts"
|
"zenyd-mpv-scripts": "zenyd-mpv-scripts"
|
||||||
@@ -394,14 +514,14 @@
|
|||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_7"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1736476219,
|
"lastModified": 1789196581,
|
||||||
"narHash": "sha256-+qyv3QqdZCdZ3cSO/cbpEY6tntyYjfe1bB12mdpNFaY=",
|
"narHash": "sha256-yJr1Bt4fKkKIpPYbsKGqJ0VFdoDnURgRwuffmBQ2WzY=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "de30cc5963da22e9742bbbbb9a3344570ed237b9",
|
"rev": "228ecefb6329d5a531b77b46b581a2f0c26ee056",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -411,21 +531,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
|
||||||
"lastModified": 1689347925,
|
|
||||||
"narHash": "sha256-ozenz5bFe1UUqOn7f60HRmgc01BgTGIKZ4Xl+HbocGQ=",
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default-darwin",
|
|
||||||
"rev": "2235d7e6cc29ae99878133c95e9fe5e157661ffb",
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"original": {
|
|
||||||
"owner": "nix-systems",
|
|
||||||
"repo": "default-darwin",
|
|
||||||
"type": "github"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"systems_2": {
|
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
@@ -440,6 +545,21 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1689347925,
|
||||||
|
"narHash": "sha256-ozenz5bFe1UUqOn7f60HRmgc01BgTGIKZ4Xl+HbocGQ=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-darwin",
|
||||||
|
"rev": "2235d7e6cc29ae99878133c95e9fe5e157661ffb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"systems_3": {
|
"systems_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
@@ -455,19 +575,49 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"systems_4": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": "nixpkgs_2"
|
||||||
"nur",
|
|
||||||
"nixpkgs"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1733222881,
|
"lastModified": 1766000401,
|
||||||
"narHash": "sha256-JIPcz1PrpXUCbaccEnrcUS8jjEb/1vJbZz5KkobyFdM=",
|
"narHash": "sha256-+cqN4PJz9y0JQXfAK5J1drd0U05D5fcAGhzhfVrDlsI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "49717b5af6f80172275d47a418c9719a31a78b53",
|
"rev": "42d96e75aa56a3f70cab7e7dc4a32868db28e8fd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"treefmt-nix_2": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": "nixpkgs_4"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1780220602,
|
||||||
|
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
|
||||||
|
"owner": "numtide",
|
||||||
|
"repo": "treefmt-nix",
|
||||||
|
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -478,17 +628,17 @@
|
|||||||
},
|
},
|
||||||
"wsl": {
|
"wsl": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"flake-compat": "flake-compat_2",
|
"flake-compat": "flake-compat_3",
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1741870048,
|
"lastModified": 1789164534,
|
||||||
"narHash": "sha256-odXRdNZGdXg1LmwlAeWL85kgy/FVHsgKlDwrvbR2BsU=",
|
"narHash": "sha256-DoYGPM6QpnYBLWj9gGw6ZwAzIX+HrAVov1BoT+8Jixo=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NixOS-WSL",
|
"repo": "NixOS-WSL",
|
||||||
"rev": "5d76001e33ee19644a598ad80e7318ab0957b122",
|
"rev": "72c92b11bb8289e6651c7fef29cc0a885fd6a255",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -502,15 +652,17 @@
|
|||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
"nixpkgs"
|
"nixpkgs"
|
||||||
],
|
],
|
||||||
"rust-overlay": "rust-overlay",
|
"rust-overlay": [
|
||||||
"systems": "systems_3"
|
"rust-overlay"
|
||||||
|
],
|
||||||
|
"systems": "systems_4"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1737011317,
|
"lastModified": 1781873766,
|
||||||
"narHash": "sha256-A8VGuw/jIw+NCo5aCYy8MFrWpKzZLf77RApGGMzHxCY=",
|
"narHash": "sha256-V8baEgRBa2SqtCLbQ4EaphIMKsnAogY2oMdttWYhkEs=",
|
||||||
"owner": "mostafaqanbaryan",
|
"owner": "mostafaqanbaryan",
|
||||||
"repo": "zellij-switch",
|
"repo": "zellij-switch",
|
||||||
"rev": "15b02834c8be735fca0d9fb41f48709f97cc9afc",
|
"rev": "ced3c681afe40785b2853e3a976908466786ee79",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -522,11 +674,11 @@
|
|||||||
"zenyd-mpv-scripts": {
|
"zenyd-mpv-scripts": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1707704915,
|
"lastModified": 1765050776,
|
||||||
"narHash": "sha256-9P/8q/OZXfaJMS08acQP4h3/zUA5mKRQee0JmkXcz1w=",
|
"narHash": "sha256-9gO+GkNoGsxAbMRrBWu0FfXEQtyTmHivlaxlYLpV2YM=",
|
||||||
"owner": "zenyd",
|
"owner": "zenyd",
|
||||||
"repo": "mpv-scripts",
|
"repo": "mpv-scripts",
|
||||||
"rev": "9bdce0050144cb24f92475f7bdd77180e0e4c26b",
|
"rev": "62f4bb313c6cb6366672e78dea940e9da8fec84a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
|
|
||||||
# Used for specific stable packages
|
# Used for specific stable packages
|
||||||
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-24.05";
|
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-26.05";
|
||||||
|
|
||||||
# Used for MacOS system config
|
# Used for MacOS system config
|
||||||
darwin = {
|
darwin = {
|
||||||
@@ -37,7 +37,13 @@
|
|||||||
# Better App install management in macOS
|
# Better App install management in macOS
|
||||||
mac-app-util = {
|
mac-app-util = {
|
||||||
url = "github:hraban/mac-app-util";
|
url = "github:hraban/mac-app-util";
|
||||||
inputs.nixpkgs.follows = "nixpkgs"; # Use system packages list for their inputs
|
# inputs.nixpkgs.follows = "nixpkgs"; # Use system packages list for their inputs
|
||||||
|
};
|
||||||
|
|
||||||
|
# Caddy with decoupled plugin hashes
|
||||||
|
nix-caddy-withplugins = {
|
||||||
|
url = "github:MichailiK/nix-caddy-withplugins/nixos-unstable";
|
||||||
|
# Important: Do not follow nixpkgs here, per the README
|
||||||
};
|
};
|
||||||
|
|
||||||
# Manage disk format and partitioning
|
# Manage disk format and partitioning
|
||||||
@@ -52,6 +58,11 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
nix-index-database = {
|
||||||
|
url = "github:nix-community/nix-index-database";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
# Convert Nix to Neovim config
|
# Convert Nix to Neovim config
|
||||||
nix2vim = {
|
nix2vim = {
|
||||||
url = "github:gytis-ivaskevicius/nix2vim";
|
url = "github:gytis-ivaskevicius/nix2vim";
|
||||||
@@ -64,35 +75,47 @@
|
|||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
rust-overlay = {
|
||||||
|
url = "github:oxalica/rust-overlay";
|
||||||
|
};
|
||||||
|
|
||||||
# Zellij Switcher
|
# Zellij Switcher
|
||||||
zellij-switch = {
|
zellij-switch = {
|
||||||
url = "github:mostafaqanbaryan/zellij-switch";
|
url = "github:mostafaqanbaryan/zellij-switch";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
inputs.rust-overlay.follows = "rust-overlay";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Nextcloud Apps
|
# # Text editor
|
||||||
nextcloud-news = {
|
# helix = {
|
||||||
# https://github.com/nextcloud/news/releases
|
# url = "github:helix-editor/helix";
|
||||||
url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz";
|
# inputs.nixpkgs.follows = "nixpkgs";
|
||||||
flake = false;
|
# inputs.rust-overlay.follows = "rust-overlay";
|
||||||
};
|
# };
|
||||||
nextcloud-external = {
|
|
||||||
# https://github.com/nextcloud-releases/external/releases
|
# # Nextcloud Apps
|
||||||
url = "https://github.com/nextcloud-releases/external/releases/download/v5.5.2/external-v5.5.2.tar.gz";
|
# nextcloud-news = {
|
||||||
flake = false;
|
# # https://github.com/nextcloud/news/releases
|
||||||
};
|
# url = "https://github.com/nextcloud/news/releases/download/25.0.0-alpha12/news.tar.gz";
|
||||||
nextcloud-cookbook = {
|
# flake = false;
|
||||||
# https://github.com/christianlupus-nextcloud/cookbook-releases/releases/
|
# };
|
||||||
url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/cookbook-0.11.2.tar.gz";
|
# nextcloud-external = {
|
||||||
flake = false;
|
# # https://github.com/nextcloud-releases/external/releases
|
||||||
};
|
# url = "https://github.com/nextcloud-releases/external/releases/download/v5.5.2/external-v5.5.2.tar.gz";
|
||||||
nextcloud-snappymail = {
|
# flake = false;
|
||||||
# https://github.com/the-djmaze/snappymail/releases
|
# };
|
||||||
# https://snappymail.eu/repository/nextcloud
|
# nextcloud-cookbook = {
|
||||||
url = "https://snappymail.eu/repository/nextcloud/snappymail-2.38.2-nextcloud.tar.gz";
|
# # https://github.com/christianlupus-nextcloud/cookbook-releases/releases/
|
||||||
# url = "https://github.com/nmasur/snappymail-nextcloud/releases/download/v2.36.3/snappymail-2.36.3-nextcloud.tar.gz";
|
# url = "https://github.com/christianlupus-nextcloud/cookbook-releases/releases/download/v0.11.2/cookbook-0.11.2.tar.gz";
|
||||||
flake = false;
|
# flake = false;
|
||||||
};
|
# };
|
||||||
|
# nextcloud-snappymail = {
|
||||||
|
# # https://github.com/the-djmaze/snappymail/releases
|
||||||
|
# # https://snappymail.eu/repository/nextcloud
|
||||||
|
# url = "https://snappymail.eu/repository/nextcloud/snappymail-2.38.2-nextcloud.tar.gz";
|
||||||
|
# # url = "https://github.com/nmasur/snappymail-nextcloud/releases/download/v2.36.3/snappymail-2.36.3-nextcloud.tar.gz";
|
||||||
|
# flake = false;
|
||||||
|
# };
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs =
|
||||||
@@ -105,23 +128,32 @@
|
|||||||
in
|
in
|
||||||
{
|
{
|
||||||
audiobooks = "read.${baseName}";
|
audiobooks = "read.${baseName}";
|
||||||
|
auth = "auth.${baseName}";
|
||||||
|
bookmarks = "keep.${baseName}";
|
||||||
books = "books.${baseName}";
|
books = "books.${baseName}";
|
||||||
budget = "money.${baseName}";
|
budget = "money.${baseName}";
|
||||||
|
contacts = "contacts.${baseName}";
|
||||||
content = "cloud.${baseName}";
|
content = "cloud.${baseName}";
|
||||||
download = "download.${baseName}";
|
download = "download.${baseName}";
|
||||||
files = "files.${baseName}";
|
files = "files.${baseName}";
|
||||||
git = "git.${baseName}";
|
git = "git.${baseName}";
|
||||||
|
hister = "hister.${baseName}";
|
||||||
imap = "imap.purelymail.com";
|
imap = "imap.purelymail.com";
|
||||||
influxdb = "influxdb.${baseName}";
|
influxdb = "influxdb.${baseName}";
|
||||||
irc = "irc.${baseName}";
|
irc = "irc.${baseName}";
|
||||||
mail = "noahmasur.com";
|
mail = "noahmasur.com";
|
||||||
|
mathesar = "mathesar.${baseName}";
|
||||||
metrics = "metrics.${baseName}";
|
metrics = "metrics.${baseName}";
|
||||||
minecraft = "minecraft.${baseName}";
|
minecraft = "minecraft.${baseName}";
|
||||||
|
mumble = "mumble.${baseName}";
|
||||||
n8n = "n8n.${baseName}";
|
n8n = "n8n.${baseName}";
|
||||||
|
navidrome = "music.${baseName}";
|
||||||
notifications = "ntfy.${baseName}";
|
notifications = "ntfy.${baseName}";
|
||||||
paperless = "paper.${baseName}";
|
paperless = "paper.${baseName}";
|
||||||
photos = "photos.${baseName}";
|
photos = "photos.${baseName}";
|
||||||
|
postgresql = "pg.${baseName}";
|
||||||
prometheus = "prom.${baseName}";
|
prometheus = "prom.${baseName}";
|
||||||
|
recipes = "cooking.${baseName}";
|
||||||
secrets = "vault.${baseName}";
|
secrets = "vault.${baseName}";
|
||||||
smtp = "smtp.purelymail.com";
|
smtp = "smtp.purelymail.com";
|
||||||
status = "status.${baseName}";
|
status = "status.${baseName}";
|
||||||
@@ -129,32 +161,8 @@
|
|||||||
transmission = "transmission.${baseName}";
|
transmission = "transmission.${baseName}";
|
||||||
};
|
};
|
||||||
|
|
||||||
in
|
|
||||||
rec {
|
|
||||||
|
|
||||||
lib = import ./lib inputs;
|
lib = import ./lib inputs;
|
||||||
|
flattenAttrset = attrs: builtins.foldl' lib.mergeAttrs { } (builtins.attrValues attrs);
|
||||||
nixosConfigurations = builtins.mapAttrs (
|
|
||||||
system: hosts:
|
|
||||||
builtins.mapAttrs (
|
|
||||||
name: module:
|
|
||||||
lib.buildNixos {
|
|
||||||
inherit system module;
|
|
||||||
specialArgs = { inherit hostnames; };
|
|
||||||
}
|
|
||||||
) hosts
|
|
||||||
) lib.linuxHosts;
|
|
||||||
|
|
||||||
darwinConfigurations = builtins.mapAttrs (
|
|
||||||
system: hosts:
|
|
||||||
builtins.mapAttrs (
|
|
||||||
name: module:
|
|
||||||
lib.buildDarwin {
|
|
||||||
inherit system module;
|
|
||||||
specialArgs = { inherit hostnames; };
|
|
||||||
}
|
|
||||||
) hosts
|
|
||||||
) lib.darwinHosts;
|
|
||||||
|
|
||||||
homeModules = builtins.mapAttrs (
|
homeModules = builtins.mapAttrs (
|
||||||
system: hosts:
|
system: hosts:
|
||||||
@@ -163,50 +171,99 @@
|
|||||||
) hosts
|
) hosts
|
||||||
) lib.hosts;
|
) lib.hosts;
|
||||||
|
|
||||||
homeConfigurations = builtins.mapAttrs (
|
|
||||||
system: hosts:
|
|
||||||
builtins.mapAttrs (
|
|
||||||
name: module:
|
|
||||||
lib.buildHome {
|
|
||||||
inherit system module;
|
|
||||||
specialArgs = { inherit hostnames; };
|
|
||||||
}
|
|
||||||
) hosts
|
|
||||||
) homeModules;
|
|
||||||
|
|
||||||
# Disk formatting, only used once
|
# Disk formatting, only used once
|
||||||
diskoConfigurations = {
|
diskoConfigurations = {
|
||||||
root = import ./hosts/x86_64-linux/swan/root.nix;
|
root = import ./hosts/x86_64-linux/swan/root.nix;
|
||||||
};
|
};
|
||||||
|
|
||||||
generators = builtins.mapAttrs (
|
generators = builtins.mapAttrs (
|
||||||
|
# x86_64-linux = { arrow = ...; swan = ...; }
|
||||||
system: hosts:
|
system: hosts:
|
||||||
builtins.mapAttrs (name: module: {
|
(lib.concatMapAttrs (name: module: {
|
||||||
aws = lib.generateImage {
|
"${name}-aws" = lib.generateImage {
|
||||||
inherit system module;
|
inherit system module;
|
||||||
format = "amazon";
|
format = "amazon";
|
||||||
specialArgs = { inherit hostnames; };
|
specialArgs = { inherit hostnames; };
|
||||||
};
|
};
|
||||||
iso = lib.generateImage {
|
"${name}-iso" = lib.generateImage {
|
||||||
inherit system module;
|
inherit system module;
|
||||||
format = "iso";
|
format = "iso";
|
||||||
specialArgs = { inherit hostnames; };
|
specialArgs = { inherit hostnames; };
|
||||||
};
|
};
|
||||||
}) hosts
|
"${name}-qcow" = lib.generateImage {
|
||||||
) lib.linuxHosts;
|
inherit system module;
|
||||||
|
format = "qcow-efi";
|
||||||
|
specialArgs = { inherit hostnames; };
|
||||||
|
# extraModules = [ "${nixpkgs}/nixos/modules/virtualisation/oci-image.nix" ];
|
||||||
|
};
|
||||||
|
}) hosts)
|
||||||
|
) lib.linuxHosts # x86_64-linux = { arrow = ...; swan = ...; }
|
||||||
|
;
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
|
||||||
|
inherit lib;
|
||||||
|
|
||||||
|
nixosConfigurations = flattenAttrset (
|
||||||
|
|
||||||
|
builtins.mapAttrs (
|
||||||
|
system: hosts:
|
||||||
|
builtins.mapAttrs (
|
||||||
|
name: module:
|
||||||
|
lib.buildNixos {
|
||||||
|
inherit system module;
|
||||||
|
specialArgs = { inherit hostnames; };
|
||||||
|
}
|
||||||
|
) hosts
|
||||||
|
) lib.linuxHosts
|
||||||
|
);
|
||||||
|
|
||||||
|
darwinConfigurations = flattenAttrset (
|
||||||
|
builtins.mapAttrs (
|
||||||
|
system: hosts:
|
||||||
|
builtins.mapAttrs (
|
||||||
|
name: module:
|
||||||
|
lib.buildDarwin {
|
||||||
|
inherit system module;
|
||||||
|
specialArgs = { inherit hostnames; };
|
||||||
|
}
|
||||||
|
) hosts
|
||||||
|
) lib.darwinHosts
|
||||||
|
);
|
||||||
|
|
||||||
|
homeConfigurations = flattenAttrset (
|
||||||
|
builtins.mapAttrs (
|
||||||
|
system: hosts:
|
||||||
|
builtins.mapAttrs (
|
||||||
|
name: module:
|
||||||
|
lib.buildHome {
|
||||||
|
inherit system module;
|
||||||
|
specialArgs = { inherit hostnames; };
|
||||||
|
}
|
||||||
|
) hosts
|
||||||
|
) homeModules
|
||||||
|
);
|
||||||
|
|
||||||
|
# packages =
|
||||||
|
# lib.forSystems lib.linuxSystems (
|
||||||
|
# system: generateImagesForHosts system // lib.pkgsBySystem.${system}.nmasur
|
||||||
|
# )
|
||||||
|
# // lib.forSystems lib.darwinSystems (system: lib.pkgsBySystem.${system}.nmasur);
|
||||||
|
|
||||||
packages = lib.forAllSystems (
|
packages = lib.forAllSystems (
|
||||||
system:
|
system:
|
||||||
# Get the configurations that we normally use
|
# Share the custom packages that I have placed under the nmasur namespace
|
||||||
{
|
lib.pkgsBySystem.${system}.nmasur
|
||||||
nixosConfigurations = nixosConfigurations.${system};
|
|
||||||
darwinConfigurations = darwinConfigurations.${system};
|
|
||||||
homeConfigurations = homeConfigurations.${system};
|
|
||||||
generators = generators.${system};
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
# Get the custom packages that I have placed under the nmasur namespace
|
# Share generated images for each relevant host
|
||||||
lib.pkgsBySystem.${system}.nmasur
|
(if (lib.hasInfix "linux" system) then generators.${system} else { })
|
||||||
|
|
||||||
|
# //
|
||||||
|
# # Oracle
|
||||||
|
# {
|
||||||
|
# flame-oci = nixosConfigurations.flame.config.system.build.OCIImage;
|
||||||
|
# }
|
||||||
);
|
);
|
||||||
|
|
||||||
# Development environments
|
# Development environments
|
||||||
@@ -214,30 +271,30 @@
|
|||||||
default = lib.pkgsBySystem.${system}.nmasur.dotfiles-devshell;
|
default = lib.pkgsBySystem.${system}.nmasur.dotfiles-devshell;
|
||||||
});
|
});
|
||||||
|
|
||||||
checks = lib.forAllSystems (
|
# checks = lib.forAllSystems (
|
||||||
system:
|
# system:
|
||||||
let
|
# let
|
||||||
pkgs = import nixpkgs {
|
# pkgs = import nixpkgs {
|
||||||
inherit system;
|
# inherit system;
|
||||||
overlays = lib.overlays;
|
# overlays = lib.overlays;
|
||||||
};
|
# };
|
||||||
in
|
# in
|
||||||
{
|
# {
|
||||||
neovim =
|
# neovim =
|
||||||
pkgs.runCommand "neovim-check-health" { buildInputs = [ inputs.self.packages.${system}.neovim ]; }
|
# pkgs.runCommand "neovim-check-health" { buildInputs = [ inputs.self.packages.${system}.neovim ]; }
|
||||||
''
|
# ''
|
||||||
mkdir -p $out
|
# mkdir -p $out
|
||||||
export HOME=$TMPDIR
|
# export HOME=$TMPDIR
|
||||||
nvim -c "checkhealth" -c "write $out/health.log" -c "quitall"
|
# nvim -c "checkhealth" -c "write $out/health.log" -c "quitall"
|
||||||
|
|
||||||
# Check for errors inside the health log
|
# # Check for errors inside the health log
|
||||||
if $(grep "ERROR" $out/health.log); then
|
# if $(grep "ERROR" $out/health.log); then
|
||||||
cat $out/health.log
|
# cat $out/health.log
|
||||||
exit 1
|
# exit 1
|
||||||
fi
|
# fi
|
||||||
'';
|
# '';
|
||||||
}
|
# }
|
||||||
);
|
# );
|
||||||
|
|
||||||
formatter = lib.forAllSystems (
|
formatter = lib.forAllSystems (
|
||||||
system:
|
system:
|
||||||
@@ -247,10 +304,10 @@
|
|||||||
inherit (lib) overlays;
|
inherit (lib) overlays;
|
||||||
};
|
};
|
||||||
in
|
in
|
||||||
pkgs.nixfmt-rfc-style
|
pkgs.nixfmt
|
||||||
);
|
);
|
||||||
|
|
||||||
# Templates for starting other projects quickly
|
# Templates for starting other projects quickly
|
||||||
templates = (import ./templates nixpkgs.lib);
|
templates = (import ./templates { inherit lib; });
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,23 +12,37 @@ rec {
|
|||||||
|
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
base.enable = true;
|
base.enable = true;
|
||||||
work.enable = true;
|
# work.enable = true;
|
||||||
extra.enable = true;
|
# extra.enable = true;
|
||||||
gaming.enable = true;
|
# gaming.enable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Corporate network runs a TLS-intercepting proxy. Trust its root CA so Nix
|
||||||
|
# fetches don't fail with "self-signed certificate in certificate chain". The
|
||||||
|
# cert lives outside this public repo at a root-owned, world-readable path so
|
||||||
|
# the unprivileged Nix build user can read it (a copy under $HOME is not
|
||||||
|
# traversable by nixbld). See docs/CHANGELOG.md to extract and install it.
|
||||||
|
nmasur.presets.security.corporateCa = {
|
||||||
|
enable = true;
|
||||||
|
certFile = "/etc/ssl/corp-ca/CorpCA.pem";
|
||||||
};
|
};
|
||||||
|
|
||||||
home-manager.users."Noah.Masur" = {
|
home-manager.users."Noah.Masur" = {
|
||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = "lookingglass";
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
darwin-base.enable = true;
|
darwin-base.enable = true;
|
||||||
|
darwin-gaming.enable = true;
|
||||||
|
llm-development.enable = true;
|
||||||
power-user.enable = true;
|
power-user.enable = true;
|
||||||
work.enable = true;
|
work.enable = true;
|
||||||
experimental.enable = true;
|
experimental.enable = true;
|
||||||
};
|
};
|
||||||
|
nmasur.presets.services.mbsync.user = "noah";
|
||||||
nmasur.presets.programs.git-work.work = {
|
nmasur.presets.programs.git-work.work = {
|
||||||
name = "Noah-Masur_1701";
|
name = "Noah-Masur_1701";
|
||||||
email = "${nmasur.settings.username}@take2games.com";
|
email = "${nmasur.settings.username}@take2games.com";
|
||||||
|
|||||||
@@ -23,30 +23,33 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
linux-base.enable = true;
|
linux-base.enable = true;
|
||||||
|
llm-development.enable = true;
|
||||||
power-user.enable = true;
|
power-user.enable = true;
|
||||||
};
|
};
|
||||||
home.stateVersion = "23.05";
|
nmasur.presets.programs.helix.enable = true;
|
||||||
|
home.stateVersion = "25.05";
|
||||||
};
|
};
|
||||||
|
|
||||||
system.stateVersion = "23.05";
|
system.stateVersion = "25.05";
|
||||||
# File systems must be declared in order to boot
|
# File systems must be declared in order to boot
|
||||||
|
|
||||||
# This is the root filesystem containing NixOS
|
# # This is the root filesystem containing NixOS
|
||||||
# I forgot to set a clean label for it
|
# # I forgot to set a clean label for it
|
||||||
fileSystems."/" = {
|
# fileSystems."/" = {
|
||||||
device = "/dev/disk/by-uuid/e1b6bd50-306d-429a-9f45-78f57bc597c3";
|
# device = "/dev/disk/by-uuid/e1b6bd50-306d-429a-9f45-78f57bc597c3";
|
||||||
fsType = "ext4";
|
# fsType = "ext4";
|
||||||
};
|
# };
|
||||||
|
|
||||||
# This is the boot filesystem for systemd-boot
|
# # This is the boot filesystem for systemd-boot
|
||||||
fileSystems."/boot" = {
|
# fileSystems."/boot" = {
|
||||||
device = "/dev/disk/by-uuid/D5CA-237A";
|
# device = "/dev/disk/by-uuid/D5CA-237A";
|
||||||
fsType = "vfat";
|
# fsType = "vfat";
|
||||||
};
|
# };
|
||||||
|
|
||||||
# Allows private remote access over the internet
|
# Allows private remote access over the internet
|
||||||
nmasur.presets.services.cloudflared = {
|
nmasur.presets.services.cloudflared = {
|
||||||
@@ -56,4 +59,111 @@ rec {
|
|||||||
ca = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK/6oyVqjFGX3Uvrc3VS8J9sphxzAnRzKC85xgkHfYgR3TK6qBGXzHrknEj21xeZrr3G2y1UsGzphWJd9ZfIcdA= open-ssh-ca@cloudflareaccess.org";
|
ca = "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBK/6oyVqjFGX3Uvrc3VS8J9sphxzAnRzKC85xgkHfYgR3TK6qBGXzHrknEj21xeZrr3G2y1UsGzphWJd9ZfIcdA= open-ssh-ca@cloudflareaccess.org";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Taken from https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/virtualisation/oci-common.nix
|
||||||
|
|
||||||
|
# fileSystems."/" = {
|
||||||
|
# device = "/dev/disk/by-label/nixos";
|
||||||
|
# fsType = "ext4";
|
||||||
|
# autoResize = true;
|
||||||
|
# };
|
||||||
|
|
||||||
|
# fileSystems."/boot" = {
|
||||||
|
# device = "/dev/disk/by-label/ESP";
|
||||||
|
# fsType = "vfat";
|
||||||
|
# };
|
||||||
|
|
||||||
|
boot.loader.efi.canTouchEfiVariables = false;
|
||||||
|
boot.loader.grub = {
|
||||||
|
device = "nodev";
|
||||||
|
splashImage = null;
|
||||||
|
extraConfig = ''
|
||||||
|
serial --unit=0 --speed=115200 --word=8 --parity=no --stop=1
|
||||||
|
terminal_input --append serial
|
||||||
|
terminal_output --append serial
|
||||||
|
'';
|
||||||
|
efiInstallAsRemovable = true;
|
||||||
|
efiSupport = true;
|
||||||
|
};
|
||||||
|
boot.loader.systemd-boot.enable = false;
|
||||||
|
|
||||||
|
# https://docs.oracle.com/en-us/iaas/Content/Compute/Tasks/configuringntpservice.htm#Configuring_the_Oracle_Cloud_Infrastructure_NTP_Service_for_an_Instance
|
||||||
|
networking.timeServers = [ "169.254.169.254" ];
|
||||||
|
|
||||||
|
boot.growPartition = true;
|
||||||
|
boot.kernelParams = [
|
||||||
|
"net.ifnames=0"
|
||||||
|
|
||||||
|
"nvme.shutdown_timeout=10"
|
||||||
|
"nvme_core.shutdown_timeout=10"
|
||||||
|
"libiscsi.debug_libiscsi_eh=1"
|
||||||
|
"crash_kexec_post_notifiers"
|
||||||
|
|
||||||
|
# aarch64-linux
|
||||||
|
"console=ttyAMA0,115200n8"
|
||||||
|
|
||||||
|
# VNC console
|
||||||
|
"console=tty1"
|
||||||
|
];
|
||||||
|
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"virtio_net"
|
||||||
|
"virtio_pci"
|
||||||
|
"virtio_mmio"
|
||||||
|
"virtio_blk"
|
||||||
|
"virtio_scsi"
|
||||||
|
"9p"
|
||||||
|
"9pnet_virtio"
|
||||||
|
];
|
||||||
|
boot.initrd.kernelModules = [
|
||||||
|
"virtio_balloon"
|
||||||
|
"virtio_console"
|
||||||
|
"virtio_rng"
|
||||||
|
"virtio_gpu"
|
||||||
|
];
|
||||||
|
|
||||||
|
networking.useDHCP = true;
|
||||||
|
# networking = {
|
||||||
|
# defaultGateway = "10.0.0.1";
|
||||||
|
# interfaces.eth0 = {
|
||||||
|
# ipAddress = throw "set your own";
|
||||||
|
# prefixLength = 24;
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
disko.devices = {
|
||||||
|
disk = {
|
||||||
|
main = {
|
||||||
|
type = "disk";
|
||||||
|
# device = "/dev/oracleoci/oraclevda"; # Consistent volume naming
|
||||||
|
device = "/dev/sda"; # Consistent volume naming
|
||||||
|
content = {
|
||||||
|
type = "gpt";
|
||||||
|
partitions = {
|
||||||
|
boot = {
|
||||||
|
size = "512M";
|
||||||
|
type = "EF00";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "vfat";
|
||||||
|
mountpoint = "/boot";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
root = {
|
||||||
|
size = "100%";
|
||||||
|
content = {
|
||||||
|
type = "filesystem";
|
||||||
|
format = "ext4";
|
||||||
|
mountpoint = "/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# # Otherwise the instance may not have a working network-online.target,
|
||||||
|
# # making the fetch-ssh-keys.service fail
|
||||||
|
# networking.useNetworkd = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
# No x86 Darwin Hosts Currently
|
||||||
@@ -19,6 +19,7 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
@@ -29,4 +30,18 @@ rec {
|
|||||||
|
|
||||||
system.stateVersion = "23.05";
|
system.stateVersion = "23.05";
|
||||||
|
|
||||||
|
# These filesystems are ignored by nixos-generators
|
||||||
|
|
||||||
|
# This is the root filesystem containing NixOS
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-label/nixos";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
# This is the boot filesystem for Grub
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-label/boot";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
@@ -30,4 +31,24 @@ rec {
|
|||||||
|
|
||||||
system.stateVersion = "23.05";
|
system.stateVersion = "23.05";
|
||||||
|
|
||||||
|
# This is the root filesystem containing NixOS
|
||||||
|
fileSystems."/" = {
|
||||||
|
device = "/dev/disk/by-label/nixos";
|
||||||
|
fsType = "ext4";
|
||||||
|
};
|
||||||
|
|
||||||
|
# This is the boot filesystem for Grub
|
||||||
|
fileSystems."/boot" = {
|
||||||
|
device = "/dev/disk/by-label/boot";
|
||||||
|
fsType = "vfat";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Not sure what's necessary but too afraid to remove anything
|
||||||
|
boot.initrd.availableKernelModules = [
|
||||||
|
"xhci_pci"
|
||||||
|
"ahci"
|
||||||
|
"nvme"
|
||||||
|
"usb_storage"
|
||||||
|
"sd_mod"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
@@ -41,6 +42,9 @@ rec {
|
|||||||
# Not sure what's necessary but too afraid to remove anything
|
# Not sure what's necessary but too afraid to remove anything
|
||||||
# File systems must be declared in order to boot
|
# File systems must be declared in order to boot
|
||||||
|
|
||||||
|
# Required to have a boot loader to work
|
||||||
|
boot.loader.systemd-boot.enable = true;
|
||||||
|
|
||||||
# This is the root filesystem containing NixOS
|
# This is the root filesystem containing NixOS
|
||||||
fileSystems."/" = {
|
fileSystems."/" = {
|
||||||
device = "/dev/disk/by-label/nixos";
|
device = "/dev/disk/by-label/nixos";
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
linux-base.enable = true;
|
linux-base.enable = true;
|
||||||
|
llm-development.enable = true;
|
||||||
power-user.enable = true;
|
power-user.enable = true;
|
||||||
};
|
};
|
||||||
home.stateVersion = "23.05";
|
home.stateVersion = "23.05";
|
||||||
@@ -32,6 +34,9 @@ rec {
|
|||||||
|
|
||||||
system.stateVersion = "23.05";
|
system.stateVersion = "23.05";
|
||||||
|
|
||||||
|
# Temp: disable while this isn't working
|
||||||
|
services.automatic-timezoned.enable = false;
|
||||||
|
|
||||||
# Not sure what's necessary but too afraid to remove anything
|
# Not sure what's necessary but too afraid to remove anything
|
||||||
boot.initrd.availableKernelModules = [
|
boot.initrd.availableKernelModules = [
|
||||||
"xhci_pci"
|
"xhci_pci"
|
||||||
|
|||||||
@@ -23,12 +23,14 @@ rec {
|
|||||||
nmasur.settings = {
|
nmasur.settings = {
|
||||||
username = nmasur.settings.username;
|
username = nmasur.settings.username;
|
||||||
fullName = nmasur.settings.fullName;
|
fullName = nmasur.settings.fullName;
|
||||||
|
host = networking.hostName;
|
||||||
};
|
};
|
||||||
nmasur.profiles = {
|
nmasur.profiles = {
|
||||||
common.enable = true;
|
common.enable = true;
|
||||||
linux-base.enable = true;
|
linux-base.enable = true;
|
||||||
linux-gui.enable = true;
|
linux-gui.enable = true;
|
||||||
linux-gaming.enable = true;
|
linux-gaming.enable = true;
|
||||||
|
llm-development.enable = true;
|
||||||
power-user.enable = true;
|
power-user.enable = true;
|
||||||
developer.enable = true;
|
developer.enable = true;
|
||||||
experimental.enable = true;
|
experimental.enable = true;
|
||||||
@@ -50,7 +52,7 @@ rec {
|
|||||||
|
|
||||||
# Graphics and VMs
|
# Graphics and VMs
|
||||||
boot.initrd.kernelModules = [ "amdgpu" ];
|
boot.initrd.kernelModules = [ "amdgpu" ];
|
||||||
boot.kernelModules = [ "kvm-amd" ];
|
boot.kernelModules = [ "kvm-amd" "it87" ];
|
||||||
services.xserver.videoDrivers = [ "amdgpu" ];
|
services.xserver.videoDrivers = [ "amdgpu" ];
|
||||||
|
|
||||||
# Required binary blobs to boot on this machine
|
# Required binary blobs to boot on this machine
|
||||||
@@ -67,16 +69,16 @@ rec {
|
|||||||
hardware.fancontrol.config = ''
|
hardware.fancontrol.config = ''
|
||||||
# Configuration file generated by pwmconfig, changes will be lost
|
# Configuration file generated by pwmconfig, changes will be lost
|
||||||
INTERVAL=10
|
INTERVAL=10
|
||||||
DEVPATH=hwmon0=devices/pci0000:00/0000:00:03.1/0000:06:00.0/0000:07:00.0/0000:08:00.0
|
DEVPATH=hwmon1=devices/pci0000:00/0000:00:03.1/0000:06:00.0/0000:07:00.0/0000:08:00.0
|
||||||
DEVNAME=hwmon0=amdgpu
|
DEVNAME=hwmon1=amdgpu
|
||||||
FCTEMPS=hwmon0/pwm1=hwmon0/temp1_input
|
FCTEMPS=hwmon1/pwm1=hwmon1/temp1_input
|
||||||
FCFANS= hwmon0/pwm1=hwmon0/fan1_input
|
FCFANS= hwmon1/pwm1=hwmon1/fan1_input
|
||||||
MINTEMP=hwmon0/pwm1=50
|
MINTEMP=hwmon1/pwm1=50
|
||||||
MAXTEMP=hwmon0/pwm1=70
|
MAXTEMP=hwmon1/pwm1=70
|
||||||
MINSTART=hwmon0/pwm1=100
|
MINSTART=hwmon1/pwm1=100
|
||||||
MINSTOP=hwmon0/pwm1=10
|
MINSTOP=hwmon1/pwm1=10
|
||||||
MINPWM=hwmon0/pwm1=10
|
MINPWM=hwmon1/pwm1=10
|
||||||
MAXPWM=hwmon0/pwm1=240
|
MAXPWM=hwmon1/pwm1=240
|
||||||
'';
|
'';
|
||||||
|
|
||||||
# File systems must be declared in order to boot
|
# File systems must be declared in order to boot
|
||||||
|
|||||||
+49
-19
@@ -66,13 +66,16 @@ lib
|
|||||||
overlays = [
|
overlays = [
|
||||||
inputs.nur.overlays.default
|
inputs.nur.overlays.default
|
||||||
inputs.nix2vim.overlay
|
inputs.nix2vim.overlay
|
||||||
inputs.zellij-switch.overlays.default
|
(final: prev: {
|
||||||
] ++ (importOverlays ../overlays);
|
zellij-switch = inputs.zellij-switch.packages.${prev.stdenv.hostPlatform.system}.default;
|
||||||
|
})
|
||||||
|
# inputs.helix.overlays.default
|
||||||
|
]
|
||||||
|
++ (importOverlays ../overlays);
|
||||||
|
|
||||||
# System types to support.
|
# System types to support.
|
||||||
supportedSystems = [
|
supportedSystems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
"x86_64-darwin"
|
|
||||||
"aarch64-linux"
|
"aarch64-linux"
|
||||||
"aarch64-darwin"
|
"aarch64-darwin"
|
||||||
];
|
];
|
||||||
@@ -96,7 +99,14 @@ lib
|
|||||||
system:
|
system:
|
||||||
import inputs.nixpkgs {
|
import inputs.nixpkgs {
|
||||||
inherit system overlays;
|
inherit system overlays;
|
||||||
config.permittedInsecurePackages = [ "litestream-0.3.13" ];
|
config.permittedInsecurePackages = [
|
||||||
|
"litestream-0.3.13"
|
||||||
|
"electron-36.9.5"
|
||||||
|
# Build-time-only dep of karakeep's frontend; CVEs don't reach
|
||||||
|
# the runtime closure. Remove once nixpkgs bumps it.
|
||||||
|
"pnpm-9.15.9"
|
||||||
|
"keybase-gui-6.5.1"
|
||||||
|
];
|
||||||
config.allowUnfree = true;
|
config.allowUnfree = true;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -129,7 +139,8 @@ lib
|
|||||||
];
|
];
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
inherit colorscheme;
|
inherit colorscheme;
|
||||||
} // specialArgs;
|
}
|
||||||
|
// specialArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
buildNixos =
|
buildNixos =
|
||||||
@@ -143,16 +154,20 @@ lib
|
|||||||
pkgs = pkgsBySystem.${system};
|
pkgs = pkgsBySystem.${system};
|
||||||
modules = [
|
modules = [
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
|
inputs.nix-index-database.nixosModules.default
|
||||||
inputs.disko.nixosModules.disko
|
inputs.disko.nixosModules.disko
|
||||||
inputs.wsl.nixosModules.wsl
|
inputs.wsl.nixosModules.wsl
|
||||||
{ imports = (nixFiles ../platforms/nixos); }
|
{ imports = (nixFiles ../platforms/nixos); }
|
||||||
module
|
module
|
||||||
|
# (builtins.removeAttrs module [ "home-manager" ])
|
||||||
{
|
{
|
||||||
home-manager = {
|
home-manager = {
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
inherit colorscheme;
|
inherit colorscheme;
|
||||||
} // specialArgs;
|
}
|
||||||
} // homeModule.home-manager;
|
// specialArgs;
|
||||||
|
}
|
||||||
|
// homeModule.home-manager;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
@@ -167,19 +182,21 @@ lib
|
|||||||
inherit system specialArgs;
|
inherit system specialArgs;
|
||||||
modules = [
|
modules = [
|
||||||
inputs.home-manager.darwinModules.home-manager
|
inputs.home-manager.darwinModules.home-manager
|
||||||
|
inputs.nix-index-database.darwinModules.nix-index
|
||||||
inputs.mac-app-util.darwinModules.default
|
inputs.mac-app-util.darwinModules.default
|
||||||
{
|
{
|
||||||
imports = (nixFiles ../platforms/nix-darwin);
|
imports = (nixFiles ../platforms/nix-darwin);
|
||||||
nixpkgs.pkgs = pkgsBySystem.${system};
|
nixpkgs.pkgs = pkgsBySystem.${system};
|
||||||
}
|
}
|
||||||
module
|
# Home Manager is intentionally NOT activated here. It is managed
|
||||||
{
|
# standalone via `nh home switch` (see homeConfigurations, extracted
|
||||||
home-manager = {
|
# from the host module's `home-manager.users`). Strip that attr so
|
||||||
extraSpecialArgs = {
|
# darwin-rebuild doesn't also activate a second, divergent HM
|
||||||
inherit colorscheme;
|
# generation with different store paths (useUserPackages puts packages
|
||||||
} // specialArgs;
|
# in /etc/profiles/per-user vs. ~/.nix-profile standalone) -- that
|
||||||
} // homeModule.home-manager;
|
# mismatch broke the prompt after every darwin-rebuild until the next
|
||||||
}
|
# `nh home switch`.
|
||||||
|
(builtins.removeAttrs module [ "home-manager" ])
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,7 +204,15 @@ lib
|
|||||||
amazon = {
|
amazon = {
|
||||||
aws.enable = true;
|
aws.enable = true;
|
||||||
};
|
};
|
||||||
iso = { };
|
iso = {
|
||||||
|
nmasur.profiles.wsl.enable = lib.mkForce false;
|
||||||
|
boot.loader.grub.enable = lib.mkForce false;
|
||||||
|
};
|
||||||
|
qcow-efi = {
|
||||||
|
nmasur.profiles.wsl.enable = lib.mkForce false;
|
||||||
|
boot.loader.grub.enable = lib.mkForce false;
|
||||||
|
fileSystems."/boot".device = lib.mkForce "/dev/disk/by-label/ESP";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
generateImage =
|
generateImage =
|
||||||
@@ -199,8 +224,10 @@ lib
|
|||||||
}:
|
}:
|
||||||
inputs.nixos-generators.nixosGenerate {
|
inputs.nixos-generators.nixosGenerate {
|
||||||
inherit system format;
|
inherit system format;
|
||||||
|
pkgs = pkgsBySystem.${system};
|
||||||
modules = [
|
modules = [
|
||||||
inputs.home-manager.nixosModules.home-manager
|
inputs.home-manager.nixosModules.home-manager
|
||||||
|
inputs.nix-index-database.nixosModules.default
|
||||||
inputs.disko.nixosModules.disko
|
inputs.disko.nixosModules.disko
|
||||||
inputs.wsl.nixosModules.wsl
|
inputs.wsl.nixosModules.wsl
|
||||||
{
|
{
|
||||||
@@ -212,12 +239,15 @@ lib
|
|||||||
home-manager = {
|
home-manager = {
|
||||||
extraSpecialArgs = {
|
extraSpecialArgs = {
|
||||||
inherit colorscheme;
|
inherit colorscheme;
|
||||||
} // specialArgs;
|
}
|
||||||
} // homeModule.home-manager;
|
// specialArgs;
|
||||||
|
}
|
||||||
|
// homeModule.home-manager;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
specialArgs = {
|
specialArgs = {
|
||||||
} // specialArgs;
|
}
|
||||||
|
// specialArgs;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
_inputs: _final: prev: {
|
||||||
|
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
|
||||||
|
(_pyfinal: pyprev: {
|
||||||
|
cheetah3 = pyprev.cheetah3.overridePythonAttrs (_old: {
|
||||||
|
dontCheckPythonMetadata = true;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
inputs: final: prev: {
|
||||||
|
|
||||||
|
# Switch firefox to stable or unstable depending on need
|
||||||
|
firefox-unwrapped = final.unstable.firefox-unwrapped;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
_inputs: _final: prev: {
|
||||||
|
|
||||||
|
kubernetes-helm = prev.kubernetes-helm.overrideAttrs (_old: {
|
||||||
|
doCheck = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
inputs: inputs.nix-caddy-withplugins.overlays.default
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# Disable paho-mqtt's flaky test suite.
|
||||||
|
#
|
||||||
|
# paho-mqtt's checkPhase runs socket-based integration tests that hang in
|
||||||
|
# the Nix sandbox (they eventually time out with a KeyboardInterrupt after
|
||||||
|
# ~150s, reporting errors and failing the build). This breaks the flame
|
||||||
|
# rebuild, where paho-mqtt is pulled in transitively (e.g. via mealie).
|
||||||
|
#
|
||||||
|
# Applied through pythonPackagesExtensions so it covers every Python
|
||||||
|
# package set (python3Packages, python314Packages, ...).
|
||||||
|
|
||||||
|
_inputs: _final: prev: {
|
||||||
|
pythonPackagesExtensions = prev.pythonPackagesExtensions ++ [
|
||||||
|
(_pyfinal: pyprev: {
|
||||||
|
paho-mqtt = pyprev.paho-mqtt.overridePythonAttrs (_old: {
|
||||||
|
doCheck = false;
|
||||||
|
doInstallCheck = false;
|
||||||
|
});
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
@@ -21,6 +21,9 @@ let
|
|||||||
# [ package1.drv package2.drv ]
|
# [ package1.drv package2.drv ]
|
||||||
(builtins.map (name: prev.callPackage name { }))
|
(builtins.map (name: prev.callPackage name { }))
|
||||||
|
|
||||||
|
# Filter out packages that return null (e.g. platform-specific packages)
|
||||||
|
(builtins.filter (v: v != null))
|
||||||
|
|
||||||
# Convert the list to an attrset
|
# Convert the list to an attrset
|
||||||
# { package1 = package1.drv, package2 = package2.drv }
|
# { package1 = package1.drv, package2 = package2.drv }
|
||||||
listToAttrsByPnameOrName
|
listToAttrsByPnameOrName
|
||||||
|
|||||||
+2
-1
@@ -4,7 +4,8 @@
|
|||||||
inputs: _final: prev: {
|
inputs: _final: prev: {
|
||||||
# Provides `pkgs.stable`.
|
# Provides `pkgs.stable`.
|
||||||
stable = import inputs.nixpkgs-stable {
|
stable = import inputs.nixpkgs-stable {
|
||||||
inherit (prev) system config;
|
system = prev.stdenv.hostPlatform.system;
|
||||||
|
config = { };
|
||||||
overlays = [
|
overlays = [
|
||||||
# inputs.self.overlays.vim-plugins
|
# inputs.self.overlays.vim-plugins
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
inputs: _final: prev: {
|
inputs: _final: prev: {
|
||||||
# Provides `pkgs.unstable`.
|
# Provides `pkgs.unstable`.
|
||||||
unstable = import inputs.nixpkgs {
|
unstable = import inputs.nixpkgs {
|
||||||
inherit (prev) system config;
|
system = prev.stdenv.hostPlatform.system;
|
||||||
|
inherit (prev) config;
|
||||||
overlays = [
|
overlays = [
|
||||||
# inputs.self.overlays.vim-plugins
|
# inputs.self.overlays.vim-plugins
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
buildNpmPackage,
|
||||||
|
fetchFromGitHub,
|
||||||
|
nodejs,
|
||||||
|
}:
|
||||||
|
|
||||||
|
buildNpmPackage rec {
|
||||||
|
pname = "actualtap";
|
||||||
|
version = "1.0.34";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "MattFaz";
|
||||||
|
repo = "actualtap";
|
||||||
|
rev = "v${version}";
|
||||||
|
hash = "sha256-I2yb3WCOXYx/6RXiKjePlpChrr9G1il44OdON/SeVCw=";
|
||||||
|
};
|
||||||
|
|
||||||
|
npmDepsHash = "sha256-LlTLwUt0Yja4NSBLbaYPV/keawSJKffno/28rtSj/oQ=";
|
||||||
|
|
||||||
|
dontNpmBuild = true;
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
substituteInPlace src/server.js \
|
||||||
|
--replace-fail 'port: 3001' 'port: process.env.PORT || 3001'
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
cat <<EOF > $out/bin/actualtap
|
||||||
|
#!/bin/sh
|
||||||
|
exec ${lib.getExe nodejs} $out/lib/node_modules/actualtap/src/server.js "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/actualtap
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "Automatically create transactions in Actual Budget when you use Tap-to-Pay on a mobile device";
|
||||||
|
homepage = "https://github.com/MattFaz/actualtap";
|
||||||
|
license = licenses.gpl3Only;
|
||||||
|
maintainers = [ ];
|
||||||
|
mainProgram = "actualtap";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,7 +9,7 @@
|
|||||||
# Sets Neovim colors based on Nix colorscheme
|
# Sets Neovim colors based on Nix colorscheme
|
||||||
|
|
||||||
options.colors = lib.mkOption {
|
options.colors = lib.mkOption {
|
||||||
type = lib.types.attrsOf lib.types.str;
|
type = lib.types.nullOr (lib.types.attrsOf lib.types.str);
|
||||||
description = "Attrset of base16 colorscheme key value pairs.";
|
description = "Attrset of base16 colorscheme key value pairs.";
|
||||||
default = {
|
default = {
|
||||||
# Nord
|
# Nord
|
||||||
@@ -32,7 +32,7 @@
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
config = {
|
config = lib.mkIf (config.colors != null) {
|
||||||
plugins = [ pkgs.vimPlugins.base16-nvim ];
|
plugins = [ pkgs.vimPlugins.base16-nvim ];
|
||||||
setup.base16-colorscheme = config.colors;
|
setup.base16-colorscheme = config.colors;
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
{
|
{
|
||||||
|
|
||||||
# Terraform optional because non-free
|
# Terraform optional because non-free
|
||||||
options.terraform = lib.mkEnableOption "Whether to enable Terraform LSP";
|
options.enableTerraform = lib.mkEnableOption "Whether to enable Terraform LSP";
|
||||||
options.github = lib.mkEnableOption "Whether to enable GitHub features";
|
options.enableGithub = lib.mkEnableOption "Whether to enable GitHub features";
|
||||||
options.kubernetes = lib.mkEnableOption "Whether to enable Kubernetes features";
|
options.enableKubernetes = lib.mkEnableOption "Whether to enable Kubernetes features";
|
||||||
|
|
||||||
config = {
|
config = {
|
||||||
plugins = [
|
plugins = [
|
||||||
@@ -54,7 +54,7 @@
|
|||||||
|
|
||||||
use.lspconfig.terraformls.setup = dsl.callWith {
|
use.lspconfig.terraformls.setup = dsl.callWith {
|
||||||
cmd =
|
cmd =
|
||||||
if config.terraform then
|
if config.enableTerraform then
|
||||||
[
|
[
|
||||||
"${pkgs.terraform-ls}/bin/terraform-ls"
|
"${pkgs.terraform-ls}/bin/terraform-ls"
|
||||||
"serve"
|
"serve"
|
||||||
@@ -93,14 +93,14 @@
|
|||||||
nix = [ "nixfmt" ];
|
nix = [ "nixfmt" ];
|
||||||
rust = [ "rustfmt" ];
|
rust = [ "rustfmt" ];
|
||||||
sh = [ "shfmt" ];
|
sh = [ "shfmt" ];
|
||||||
terraform = if config.terraform then [ "terraform_fmt" ] else [ ];
|
terraform = if config.enableTerraform then [ "terraform_fmt" ] else [ ];
|
||||||
hcl = [ "hcl" ];
|
hcl = [ "hcl" ];
|
||||||
};
|
};
|
||||||
formatters = {
|
formatters = {
|
||||||
lua.command = "${pkgs.stylua}/bin/stylua";
|
lua.command = "${pkgs.stylua}/bin/stylua";
|
||||||
black.command = "${pkgs.black}/bin/black";
|
black.command = "${pkgs.black}/bin/black";
|
||||||
fish_indent.command = "${pkgs.fish}/bin/fish_indent";
|
fish_indent.command = "${pkgs.fish}/bin/fish_indent";
|
||||||
nixfmt.command = "${pkgs.nixfmt-rfc-style}/bin/nixfmt";
|
nixfmt.command = "${pkgs.nixfmt}/bin/nixfmt";
|
||||||
rustfmt.command = "${pkgs.rustfmt}/bin/rustfmt";
|
rustfmt.command = "${pkgs.rustfmt}/bin/rustfmt";
|
||||||
shfmt = {
|
shfmt = {
|
||||||
command = "${pkgs.shfmt}/bin/shfmt";
|
command = "${pkgs.shfmt}/bin/shfmt";
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
"-ci"
|
"-ci"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
terraform_fmt.command = if config.terraform then "${pkgs.terraform}/bin/terraform" else "";
|
terraform_fmt.command = if config.enableTerraform then "${pkgs.terraform}/bin/terraform" else "";
|
||||||
hcl.command = "${pkgs.hclfmt}/bin/hclfmt";
|
hcl.command = "${pkgs.hclfmt}/bin/hclfmt";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,10 +3,10 @@
|
|||||||
|
|
||||||
plugins = [
|
plugins = [
|
||||||
(pkgs.vimPlugins.nvim-treesitter.withPlugins (_plugins: [
|
(pkgs.vimPlugins.nvim-treesitter.withPlugins (_plugins: [
|
||||||
pkgs.nmasur.ini-grammar
|
pkgs.nmasur.tree-sitter-ini
|
||||||
pkgs.nmasur.puppet-grammar
|
pkgs.nmasur.tree-sitter-puppet
|
||||||
pkgs.nmasur.rasi-grammar
|
pkgs.nmasur.tree-sitter-rasi
|
||||||
pkgs.nmasur.vimdoc-grammar
|
pkgs.nmasur.tree-sitter-vimdoc
|
||||||
pkgs.tree-sitter-grammars.tree-sitter-bash
|
pkgs.tree-sitter-grammars.tree-sitter-bash
|
||||||
pkgs.tree-sitter-grammars.tree-sitter-c
|
pkgs.tree-sitter-grammars.tree-sitter-c
|
||||||
pkgs.tree-sitter-grammars.tree-sitter-fish
|
pkgs.tree-sitter-grammars.tree-sitter-fish
|
||||||
@@ -21,7 +21,6 @@
|
|||||||
pkgs.tree-sitter-grammars.tree-sitter-yaml
|
pkgs.tree-sitter-grammars.tree-sitter-yaml
|
||||||
]))
|
]))
|
||||||
pkgs.vimPlugins.vim-matchup # Better % jumping in languages
|
pkgs.vimPlugins.vim-matchup # Better % jumping in languages
|
||||||
pkgs.vimPlugins.playground # Tree-sitter experimenting
|
|
||||||
pkgs.vimPlugins.nginx-vim
|
pkgs.vimPlugins.nginx-vim
|
||||||
pkgs.vimPlugins.vim-helm
|
pkgs.vimPlugins.vim-helm
|
||||||
# pkgs.vimPlugins.hmts-nvim # Tree-sitter injections for home-manager
|
# pkgs.vimPlugins.hmts-nvim # Tree-sitter injections for home-manager
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
lua = ''
|
lua = ''
|
||||||
${builtins.readFile ./toggleterm.lua}
|
${builtins.readFile ./toggleterm.lua}
|
||||||
${if config.github then (builtins.readFile ./github.lua) else ""}
|
${if config.enableGithub then (builtins.readFile ./github.lua) else ""}
|
||||||
${if config.kubernetes then (builtins.readFile ./kubernetes.lua) else ""}
|
${if config.enableKubernetes then (builtins.readFile ./kubernetes.lua) else ""}
|
||||||
'';
|
'';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,9 @@
|
|||||||
{
|
{
|
||||||
pkgs,
|
pkgs,
|
||||||
colors ? null,
|
colors ? null,
|
||||||
terraform ? false,
|
enableTerraform ? false,
|
||||||
github ? false,
|
enableGithub ? false,
|
||||||
kubernetes ? false,
|
enableKubernetes ? false,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
@@ -41,9 +41,9 @@ pkgs.neovimBuilder {
|
|||||||
package = pkgs.neovim-unwrapped;
|
package = pkgs.neovim-unwrapped;
|
||||||
inherit
|
inherit
|
||||||
colors
|
colors
|
||||||
terraform
|
enableTerraform
|
||||||
github
|
enableGithub
|
||||||
kubernetes
|
enableKubernetes
|
||||||
;
|
;
|
||||||
imports = [
|
imports = [
|
||||||
./config/align.nix
|
./config/align.nix
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
# Fix: Volnoti error: 'volnoti' has been removed due to lack of maintenance upstream.
|
# Fix: Volnoti error: 'volnoti' has been removed due to lack of maintenance upstream.
|
||||||
|
|
||||||
{ pkgs, lib, ... }:
|
{ pkgs, lib, ... }:
|
||||||
|
if !pkgs.stdenv.hostPlatform.isLinux then
|
||||||
|
null
|
||||||
|
else
|
||||||
pkgs.stdenv.mkDerivation {
|
pkgs.stdenv.mkDerivation {
|
||||||
pname = "volnoti";
|
pname = "volnoti";
|
||||||
version = "2013-09-23";
|
version = "2013-09-23";
|
||||||
@@ -27,7 +30,7 @@ pkgs.stdenv.mkDerivation {
|
|||||||
dbus
|
dbus
|
||||||
gdk-pixbuf
|
gdk-pixbuf
|
||||||
glib
|
glib
|
||||||
xorg.libX11
|
libx11
|
||||||
gtk2
|
gtk2
|
||||||
dbus-glib
|
dbus-glib
|
||||||
librsvg
|
librsvg
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
# Caddy with Cloudflare DNS
|
||||||
|
|
||||||
|
{
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
pkgs.caddy.withPlugins {
|
||||||
|
plugins = [ "github.com/caddy-dns/cloudflare@v0.2.1" ];
|
||||||
|
hash = "sha256-HuVBmiT3kD6RrDejQ6SnjCN8f7pFdZlGtZFbEf47bks=";
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
function exportHistory() {
|
||||||
|
const now = new Date();
|
||||||
|
const startTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0); // Beginning of today
|
||||||
|
|
||||||
|
browser.history.search({
|
||||||
|
text: '',
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: now,
|
||||||
|
maxResults: 10000
|
||||||
|
}).then(historyItems => {
|
||||||
|
const historyData = JSON.stringify(historyItems, null, 2);
|
||||||
|
const blob = new Blob([historyData], {type: 'application/json'});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const date = now.toISOString().slice(0, 10); // YYYY-MM-DD
|
||||||
|
const filename = `firefox-history/history-${date}.json`;
|
||||||
|
|
||||||
|
browser.downloads.download({
|
||||||
|
url: url,
|
||||||
|
filename: filename,
|
||||||
|
conflictAction: 'overwrite',
|
||||||
|
saveAs: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.alarms.create('daily-export', {
|
||||||
|
periodInMinutes: 60 // every 1 hour
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.alarms.onAlarm.addListener(alarm => {
|
||||||
|
if (alarm.name === 'daily-export') {
|
||||||
|
exportHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
|
if (message.command === "exportHistory") {
|
||||||
|
exportHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "History Exporter",
|
||||||
|
"version": "1.1",
|
||||||
|
"description": "Automatically exports today's browsing history.",
|
||||||
|
"permissions": [
|
||||||
|
"history",
|
||||||
|
"downloads",
|
||||||
|
"alarms"
|
||||||
|
],
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"default_popup": "popup.html"
|
||||||
|
},
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "[email protected]",
|
||||||
|
"data_collection_permissions": {
|
||||||
|
"required": ["none"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "firefox-history-exporter";
|
||||||
|
version = "1.1";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkgs.zip ];
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
dst="$out/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
|
||||||
|
mkdir -p "$dst"
|
||||||
|
zip -j "$dst/firefox-history-exporter@nmasur.com.xpi" \
|
||||||
|
"${src}/manifest.json" \
|
||||||
|
"${src}/background.js" \
|
||||||
|
"${src}/popup.html" \
|
||||||
|
"${src}/popup.js"
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Automatically exports today's browsing history.";
|
||||||
|
license = licenses.mit;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>History Exporter</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>History Exporter</h1>
|
||||||
|
<button id="export-button">Export Now</button>
|
||||||
|
<p id="status"></p>
|
||||||
|
<script src="popup.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
document.getElementById('export-button').addEventListener('click', () => {
|
||||||
|
browser.runtime.sendMessage({command: "exportHistory"});
|
||||||
|
|
||||||
|
const statusElement = document.getElementById('status');
|
||||||
|
statusElement.textContent = 'Exporting...';
|
||||||
|
setTimeout(() => {
|
||||||
|
statusElement.textContent = 'Export complete!';
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
@@ -0,0 +1,302 @@
|
|||||||
|
{
|
||||||
|
runtimeShell,
|
||||||
|
python313,
|
||||||
|
python313Packages,
|
||||||
|
fetchFromGitHub,
|
||||||
|
fetchPypi,
|
||||||
|
fetchurl,
|
||||||
|
gettext,
|
||||||
|
unzip,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
|
||||||
|
django-modern-rpc = python313Packages.buildPythonPackage rec {
|
||||||
|
pname = "django_modern_rpc";
|
||||||
|
version = "1.1.0";
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-+LBIfkBxe9lvfZIqPI2lFSshTZBL1NpmCWBAgToyJns=";
|
||||||
|
};
|
||||||
|
doCheck = false;
|
||||||
|
pyproject = true;
|
||||||
|
build-system = [
|
||||||
|
python313Packages.setuptools
|
||||||
|
python313Packages.wheel
|
||||||
|
python313Packages.poetry-core
|
||||||
|
];
|
||||||
|
};
|
||||||
|
django-property-filter = python313Packages.buildPythonPackage rec {
|
||||||
|
pname = "django_property_filter";
|
||||||
|
version = "1.3.0";
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-dpsF4hm0S4lQ6tIRJ0bXgPjWTr1fq1NSCZP0M6L4Efk=";
|
||||||
|
};
|
||||||
|
doCheck = false;
|
||||||
|
pyproject = true;
|
||||||
|
build-system = [
|
||||||
|
python313Packages.setuptools
|
||||||
|
python313Packages.wheel
|
||||||
|
python313Packages.django
|
||||||
|
python313Packages.django-filter
|
||||||
|
];
|
||||||
|
};
|
||||||
|
django-fernet-encrypted-fields = python313Packages.buildPythonPackage rec {
|
||||||
|
pname = "django-fernet-encrypted-fields";
|
||||||
|
version = "0.3.0";
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-OAMb2vFySm6IXuE3zGaivX3DcmxDjhiep+RHmewLqbM=";
|
||||||
|
};
|
||||||
|
doCheck = false;
|
||||||
|
pyproject = true;
|
||||||
|
build-system = [
|
||||||
|
python313Packages.setuptools
|
||||||
|
python313Packages.wheel
|
||||||
|
];
|
||||||
|
propagatedBuildInputs = with python313Packages; [
|
||||||
|
django
|
||||||
|
cryptography
|
||||||
|
];
|
||||||
|
};
|
||||||
|
drf-access-policy = python313Packages.buildPythonPackage rec {
|
||||||
|
pname = "drf-access-policy";
|
||||||
|
version = "1.5.0";
|
||||||
|
src = fetchPypi {
|
||||||
|
inherit pname version;
|
||||||
|
hash = "sha256-EsahQYIgjUBUSi/W8GXbc7pvYLPRJ6kpJg6A3RkrjL8=";
|
||||||
|
};
|
||||||
|
doCheck = false;
|
||||||
|
pyproject = true;
|
||||||
|
build-system = [
|
||||||
|
python313Packages.setuptools
|
||||||
|
python313Packages.wheel
|
||||||
|
];
|
||||||
|
propagatedBuildInputs = with python313Packages; [
|
||||||
|
pyparsing
|
||||||
|
djangorestframework
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
pythonPkg = python313.override {
|
||||||
|
self = python313;
|
||||||
|
packageOverrides = pyfinal: pyprev: {
|
||||||
|
inherit
|
||||||
|
django-modern-rpc
|
||||||
|
django-property-filter
|
||||||
|
django-fernet-encrypted-fields
|
||||||
|
drf-access-policy
|
||||||
|
# psycopg-binary
|
||||||
|
;
|
||||||
|
# clevercsv's test_encoding_chardet is nondeterministic (chardet
|
||||||
|
# returns None instead of ISO-8859-1/KOI8-R on some platforms),
|
||||||
|
# breaking the build. Skip its test suite.
|
||||||
|
clevercsv = pyprev.clevercsv.overridePythonAttrs (_old: {
|
||||||
|
doCheck = false;
|
||||||
|
doInstallCheck = false;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
python = pythonPkg.withPackages (
|
||||||
|
ps: with ps; [
|
||||||
|
gunicorn
|
||||||
|
django
|
||||||
|
clevercsv
|
||||||
|
django
|
||||||
|
dj-database-url
|
||||||
|
django-filter
|
||||||
|
django-modern-rpc
|
||||||
|
django-property-filter
|
||||||
|
djangorestframework
|
||||||
|
django-fernet-encrypted-fields
|
||||||
|
drf-access-policy
|
||||||
|
frozendict
|
||||||
|
gunicorn
|
||||||
|
psycopg
|
||||||
|
# psycopg-binary
|
||||||
|
psycopg2-binary
|
||||||
|
requests
|
||||||
|
sqlalchemy
|
||||||
|
whitenoise
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
staticAssets = fetchurl {
|
||||||
|
url = "https://github.com/mathesar-foundation/mathesar/releases/download/0.2.2/static_files.zip";
|
||||||
|
sha256 = "sha256-1X2zFpCSwilUxhqHlCw/tg8C5zVcVL6CxDa9yh0ylGA=";
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
python313Packages.buildPythonApplication rec {
|
||||||
|
pname = "mathesar";
|
||||||
|
version = "0.2.2";
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "mathesar-foundation";
|
||||||
|
repo = "mathesar";
|
||||||
|
rev = version;
|
||||||
|
sha256 = "sha256-LHxFJpPV0GJfokSPzfZQO44bBg/+QjXsk04Ry9uhUAs=";
|
||||||
|
};
|
||||||
|
format = "other";
|
||||||
|
nativeBuildInputs = [ unzip ];
|
||||||
|
propagatedBuildInputs = [
|
||||||
|
python.pkgs.gunicorn
|
||||||
|
python.pkgs.django
|
||||||
|
];
|
||||||
|
buildInputs = [
|
||||||
|
gettext
|
||||||
|
];
|
||||||
|
dependencies = [
|
||||||
|
pythonPkg.pkgs.clevercsv
|
||||||
|
pythonPkg.pkgs.django
|
||||||
|
pythonPkg.pkgs.dj-database-url
|
||||||
|
pythonPkg.pkgs.django-filter
|
||||||
|
pythonPkg.pkgs.django-modern-rpc
|
||||||
|
pythonPkg.pkgs.django-property-filter
|
||||||
|
pythonPkg.pkgs.djangorestframework
|
||||||
|
pythonPkg.pkgs.django-fernet-encrypted-fields
|
||||||
|
pythonPkg.pkgs.drf-access-policy
|
||||||
|
pythonPkg.pkgs.frozendict
|
||||||
|
pythonPkg.pkgs.gunicorn
|
||||||
|
pythonPkg.pkgs.psycopg
|
||||||
|
pythonPkg.pkgs.psycopg2-binary
|
||||||
|
pythonPkg.pkgs.requests
|
||||||
|
pythonPkg.pkgs.sqlalchemy
|
||||||
|
pythonPkg.pkgs.whitenoise
|
||||||
|
];
|
||||||
|
|
||||||
|
# Manually unzip the extra zip file into a temporary directory
|
||||||
|
postUnpack = ''
|
||||||
|
mkdir -p $TMPDIR/unzipped
|
||||||
|
unzip ${staticAssets} -d $TMPDIR/unzipped
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Override the default build phase to prevent it from looking for setup.py
|
||||||
|
# Add any non-Python build commands here if needed (e.g., building frontend assets)
|
||||||
|
buildPhase = ''
|
||||||
|
runHook preBuild
|
||||||
|
|
||||||
|
echo "Skipping standard Python build phase; application files copied in installPhase."
|
||||||
|
# If you had frontend assets to build, you'd run the command here, e.g.:
|
||||||
|
# npm install
|
||||||
|
# npm run build
|
||||||
|
|
||||||
|
runHook postBuild
|
||||||
|
'';
|
||||||
|
|
||||||
|
# This copies the application code into the Nix store output
|
||||||
|
installPhase = ''
|
||||||
|
runHook preInstall
|
||||||
|
|
||||||
|
# Destination: python's site-packages directory within $out
|
||||||
|
# This makes 'import mathesar', 'import db', etc. work more easily.
|
||||||
|
INSTALL_PATH="$out/lib/${python.libPrefix}/site-packages/${pname}"
|
||||||
|
mkdir -p "$INSTALL_PATH"
|
||||||
|
|
||||||
|
echo "Copying application code to $INSTALL_PATH"
|
||||||
|
|
||||||
|
# Copy all essential source directories needed at runtime
|
||||||
|
# Adjust this list based on mathesar's actual structure and runtime needs!
|
||||||
|
cp -r mathesar "$INSTALL_PATH/"
|
||||||
|
cp -r db "$INSTALL_PATH/"
|
||||||
|
cp -r config "$INSTALL_PATH/"
|
||||||
|
cp -r translations "$INSTALL_PATH/"
|
||||||
|
cp -r mathesar_ui "$INSTALL_PATH/" # If needed
|
||||||
|
|
||||||
|
# Copy the management script
|
||||||
|
cp manage.py "$INSTALL_PATH/"
|
||||||
|
|
||||||
|
# Copy assets from unzipped directory
|
||||||
|
mkdir -p "$INSTALL_PATH/mathesar/static/mathesar"
|
||||||
|
cp -r $TMPDIR/unzipped/static_files/* "$INSTALL_PATH/mathesar/static/mathesar"
|
||||||
|
|
||||||
|
# Create wrapper scripts in $out/bin for easy execution
|
||||||
|
|
||||||
|
mkdir -p $out/bin
|
||||||
|
|
||||||
|
# Wrapper for manage.py
|
||||||
|
# It ensures the app code is in PYTHONPATH and runs manage.py
|
||||||
|
echo "Creating manage.py wrapper..."
|
||||||
|
cat <<EOF > $out/bin/mathesar-manage
|
||||||
|
#!${python.interpreter}
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
# Add the installation path to the Python path
|
||||||
|
sys.path.insert(0, "$INSTALL_PATH")
|
||||||
|
|
||||||
|
# Set DJANGO_SETTINGS_MODULE environment variable if required by mathesar
|
||||||
|
# You might need to adjust 'config.settings.production' to the actual settings file used
|
||||||
|
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'config.settings.production')
|
||||||
|
|
||||||
|
# Change directory to where manage.py is, if necessary for relative paths
|
||||||
|
# os.chdir("$INSTALL_PATH")
|
||||||
|
|
||||||
|
print(f"Running manage.py from: $INSTALL_PATH/manage.py")
|
||||||
|
print(f"Python path includes: $INSTALL_PATH")
|
||||||
|
print(f"Executing with args: {sys.argv[1:]}")
|
||||||
|
|
||||||
|
# Find manage.py and execute it
|
||||||
|
manage_py_path = os.path.join("$INSTALL_PATH", "manage.py")
|
||||||
|
if not os.path.exists(manage_py_path):
|
||||||
|
print(f"Error: manage.py not found at {manage_py_path}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Prepare arguments for execute_from_command_line
|
||||||
|
# The first argument should be the script name itself
|
||||||
|
argv = [manage_py_path] + sys.argv[1:]
|
||||||
|
|
||||||
|
try:
|
||||||
|
from django.core.management import execute_from_command_line
|
||||||
|
execute_from_command_line(argv)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error executing manage.py: {e}", file=sys.stderr)
|
||||||
|
# Optionally re-raise or exit with error
|
||||||
|
import traceback
|
||||||
|
traceback.print_exc()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/mathesar-manage
|
||||||
|
|
||||||
|
# Wrapper for install
|
||||||
|
echo "Creating install wrapper..."
|
||||||
|
cat <<EOF > $out/bin/mathesar-install
|
||||||
|
#!${runtimeShell}
|
||||||
|
# Add the app to the Python Path
|
||||||
|
export PYTHONPATH="$INSTALL_PATH:\${"PYTHONPATH:-"}"
|
||||||
|
|
||||||
|
# Set Django settings module if needed
|
||||||
|
export DJANGO_SETTINGS_MODULE='config.settings.production'
|
||||||
|
|
||||||
|
# Change to the app directory
|
||||||
|
cd "$INSTALL_PATH"
|
||||||
|
${python}/bin/python -m mathesar.install
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/mathesar-install
|
||||||
|
|
||||||
|
# Wrapper for gunicorn (example)
|
||||||
|
# Assumes mathesar uses a standard wsgi entry point, e.g., config/wsgi.py
|
||||||
|
# Adjust 'config.wsgi:application' if necessary
|
||||||
|
echo "Creating gunicorn wrapper..."
|
||||||
|
cat <<EOF > $out/bin/mathesar-gunicorn
|
||||||
|
#!${runtimeShell}
|
||||||
|
# Add the app to the Python Path
|
||||||
|
export PYTHONPATH="$INSTALL_PATH:\${"PYTHONPATH:-"}"
|
||||||
|
|
||||||
|
# Set Django settings module if needed
|
||||||
|
export DJANGO_SETTINGS_MODULE='config.settings.production'
|
||||||
|
|
||||||
|
# Change to the app directory if gunicorn needs it
|
||||||
|
# cd "$INSTALL_PATH"
|
||||||
|
|
||||||
|
# Execute gunicorn, passing along any arguments
|
||||||
|
# Ensure the gunicorn package is in propagatedBuildInputs
|
||||||
|
exec ${python}/bin/gunicorn config.wsgi:application "\$@"
|
||||||
|
EOF
|
||||||
|
chmod +x $out/bin/mathesar-gunicorn
|
||||||
|
|
||||||
|
runHook postInstall
|
||||||
|
'';
|
||||||
|
}
|
||||||
@@ -5,11 +5,11 @@
|
|||||||
|
|
||||||
pkgs.stdenv.mkDerivation rec {
|
pkgs.stdenv.mkDerivation rec {
|
||||||
pname = "bypass-paywalls-clean";
|
pname = "bypass-paywalls-clean";
|
||||||
version = "4.0.6.1";
|
version = "4.1.1.4";
|
||||||
src = builtins.fetchGit {
|
src = builtins.fetchGit {
|
||||||
url = "https://gitflic.ru/project/magnolia1234/bpc_uploads.git";
|
url = "https://git.masu.rs/noah/bpc-uploads.git";
|
||||||
ref = "main";
|
ref = "main";
|
||||||
rev = "85a367220f5ae2181354f65fb1093e2f1ac9e417";
|
rev = "9166b13355721b047878f259e04c2e9b476b4210";
|
||||||
};
|
};
|
||||||
preferLocalBuild = true;
|
preferLocalBuild = true;
|
||||||
allowSubstitutes = true;
|
allowSubstitutes = true;
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
fetchFromGitHub,
|
||||||
|
nodejs_22,
|
||||||
|
buildNpmPackage,
|
||||||
|
typescript,
|
||||||
|
node-gyp,
|
||||||
|
python3,
|
||||||
|
gcc,
|
||||||
|
gnumake,
|
||||||
|
}:
|
||||||
|
let
|
||||||
|
|
||||||
|
in
|
||||||
|
|
||||||
|
buildNpmPackage (finalAttrs: rec {
|
||||||
|
pname = "prometheus-actual-exporter";
|
||||||
|
|
||||||
|
version = "1.1.5";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "sakowicz";
|
||||||
|
repo = "actual-budget-prometheus-exporter";
|
||||||
|
tag = version;
|
||||||
|
hash = "sha256-DAmWr1HngxAjhOJW9OnMfDqpxBcZT+Tpew/w/YYJIYU=";
|
||||||
|
};
|
||||||
|
|
||||||
|
patches = [ ./tsconfig.patch ];
|
||||||
|
|
||||||
|
npmDepsHash = "sha256-N8xqRYFelolNGTEhG22M7KJ7B5U/uW7o+/XfLF8rHMg=";
|
||||||
|
|
||||||
|
nativeBuildInputs = [
|
||||||
|
nodejs_22
|
||||||
|
typescript
|
||||||
|
python3
|
||||||
|
node-gyp
|
||||||
|
gcc
|
||||||
|
gnumake
|
||||||
|
];
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
echo "Removing better-sqlite3 install script before npm install"
|
||||||
|
sed -i '/"install"/d' node_modules/better-sqlite3/package.json || true
|
||||||
|
sed -i '/"install"/d' package.json || true
|
||||||
|
'';
|
||||||
|
|
||||||
|
preBuild = ''
|
||||||
|
echo "Disabling prebuilt install script from better-sqlite3"
|
||||||
|
find node_modules/better-sqlite3 -name package.json -exec sed -i '/"install"/d' {} +
|
||||||
|
rm -f node_modules/better-sqlite3/build/Release/better_sqlite3.node || true
|
||||||
|
'';
|
||||||
|
|
||||||
|
buildPhase = ''
|
||||||
|
# export npm_config_build_from_source=true
|
||||||
|
# export npm_config_unsafe_perm=true
|
||||||
|
# export BINARY_SITE=none
|
||||||
|
# export PATH=${node-gyp}/bin:$PATH
|
||||||
|
# export npm_config_node_gyp=${node-gyp}/bin/node-gyp
|
||||||
|
|
||||||
|
# npm rebuild better-sqlite3 --build-from-source --verbose
|
||||||
|
|
||||||
|
npm run build
|
||||||
|
'';
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/{bin,lib}
|
||||||
|
cp -r . $out/lib/prometheus-actual-exporter
|
||||||
|
makeWrapper ${lib.getExe nodejs_22} $out/bin/prometheus-actual-exporter \
|
||||||
|
--add-flags "$out/lib/prometheus-actual-exporter/dist/app.js"
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = ''
|
||||||
|
echo "Removing prebuilt .node and rebuilding better-sqlite3"
|
||||||
|
|
||||||
|
export npm_config_build_from_source=true
|
||||||
|
export npm_config_unsafe_perm=true
|
||||||
|
export BINARY_SITE=none
|
||||||
|
export PATH=${node-gyp}/bin:$PATH
|
||||||
|
export npm_config_node_gyp=${node-gyp}/bin/node-gyp
|
||||||
|
|
||||||
|
sed -i '/"install"/d' node_modules/better-sqlite3/package.json
|
||||||
|
rm -f node_modules/better-sqlite3/build/Release/better_sqlite3.node || true
|
||||||
|
|
||||||
|
npm rebuild better-sqlite3 --build-from-source --verbose
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = {
|
||||||
|
description = "Prometheus exporter for Actual Budget";
|
||||||
|
homepage = "https://github.com/sakowicz/actual-budget-prometheus-exporter";
|
||||||
|
mainProgram = "prometheus-actual-exporter";
|
||||||
|
};
|
||||||
|
})
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
diff --git a/tsconfig.json b/tsconfig.json
|
||||||
|
index 5106135..3a340f6 100644
|
||||||
|
--- a/tsconfig.json
|
||||||
|
+++ b/tsconfig.json
|
||||||
|
@@ -8,5 +8,6 @@
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"lib": ["es2020"],
|
||||||
|
"outDir": "./dist"
|
||||||
|
- }
|
||||||
|
+ },
|
||||||
|
+ "include": ["src/**/*", "app.ts"]
|
||||||
|
}
|
||||||
@@ -0,0 +1,248 @@
|
|||||||
|
{ fetchNuGet }:
|
||||||
|
[
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "AngleSharp";
|
||||||
|
version = "1.2.0";
|
||||||
|
hash = "sha256-l8+Var9o773VL6Ybih3boaFf9sYjS7eqtLGd8DCIPsk=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "EmbedIO";
|
||||||
|
version = "3.5.2";
|
||||||
|
hash = "sha256-e6GfVHXxYeUw3ntCrHokNoAS6mXArO7+vdMeUFnsSo8=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Goblinfactory.ProgressBar";
|
||||||
|
version = "1.0.0";
|
||||||
|
hash = "sha256-tV3Fw792zfYhB2dN97VKXBwS5eypqKExgAJy+bcDo8I=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Google.Apis";
|
||||||
|
version = "1.69.0";
|
||||||
|
hash = "sha256-/9JN0CZIFZnmGS69ki38RlNzQiwp4yO0MFDeRk1slsg=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Google.Apis.Auth";
|
||||||
|
version = "1.69.0";
|
||||||
|
hash = "sha256-T6n3hc+KpgHNqQQeJLOmgHQWkjBvnhIob5giHabREV8=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Google.Apis.Core";
|
||||||
|
version = "1.69.0";
|
||||||
|
hash = "sha256-IW1AOY8o6hHkrc/tINsS/VCOUrOSoXb6OCSEF6gamkc=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Google.Apis.YouTube.v3";
|
||||||
|
version = "1.69.0.3680";
|
||||||
|
hash = "sha256-3aNScBqmchnDkLejK5HYHiLVVDexrFUtZ6xe8cGP28M=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "HtmlAgilityPack";
|
||||||
|
version = "1.11.72";
|
||||||
|
hash = "sha256-MRt7yj6+/ORmr2WBERpQ+1gMRzIaPFKddHoB4zZmv2k=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.ApplicationInsights";
|
||||||
|
version = "2.22.0";
|
||||||
|
hash = "sha256-mUQ63atpT00r49ca50uZu2YCiLg3yd6r3HzTryqcuEA=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.AspNetCore.App.Ref";
|
||||||
|
version = "6.0.36";
|
||||||
|
hash = "sha256-9jDkWbjw/nd8yqdzVTagCuqr6owJ/DUMi4BlUZT4hWU=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Bcl.AsyncInterfaces";
|
||||||
|
version = "9.0.1";
|
||||||
|
hash = "sha256-A3W2Hvhlf1ODx1NYWHwUyziZOGMaDPvXHZ/ubgNLYJA=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.CodeCoverage";
|
||||||
|
version = "17.9.0";
|
||||||
|
hash = "sha256-OaGa4+jRPHs+T+p/oekm2Miluqfd2IX8Rt+BmUx8kr4=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.CSharp";
|
||||||
|
version = "4.7.0";
|
||||||
|
hash = "sha256-Enknv2RsFF68lEPdrf5M+BpV1kHoLTVRApKUwuk/pj0=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NET.Test.Sdk";
|
||||||
|
version = "17.9.0";
|
||||||
|
hash = "sha256-q/1AJ7eNlk02wvN76qvjl2xBx5iJ+h5ssiE/4akLmtI=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Host.linux-x64";
|
||||||
|
version = "6.0.36";
|
||||||
|
hash = "sha256-VFRDzx7LJuvI5yzKdGmw/31NYVbwHWPKQvueQt5xc10=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.NETCore.App.Ref";
|
||||||
|
version = "6.0.36";
|
||||||
|
hash = "sha256-9LZgVoIFF8qNyUu8kdJrYGLutMF/cL2K82HN2ywwlx8=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Testing.Extensions.Telemetry";
|
||||||
|
version = "1.5.3";
|
||||||
|
hash = "sha256-bIXwPSa3jkr2b6xINOqMUs6/uj/r4oVFM7xq3uVIZDU=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Testing.Extensions.TrxReport.Abstractions";
|
||||||
|
version = "1.5.3";
|
||||||
|
hash = "sha256-IfMRfcyaIKEMRtx326ICKtinDBEfGw/Sv8ZHawJ96Yc=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Testing.Extensions.VSTestBridge";
|
||||||
|
version = "1.5.3";
|
||||||
|
hash = "sha256-XpM/yFjhLSsuzyDV+xKubs4V1zVVYiV05E0+N4S1h0g=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Testing.Platform";
|
||||||
|
version = "1.5.3";
|
||||||
|
hash = "sha256-y61Iih6w5D79dmrj2V675mcaeIiHoj1HSa1FRit2BLM=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.Testing.Platform.MSBuild";
|
||||||
|
version = "1.5.3";
|
||||||
|
hash = "sha256-YspvjE5Jfi587TAfsvfDVJXNrFOkx1B3y1CKV6m7YLY=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
|
version = "17.12.0";
|
||||||
|
hash = "sha256-3XBHBSuCxggAIlHXmKNQNlPqMqwFlM952Av6RrLw1/w=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.TestPlatform.ObjectModel";
|
||||||
|
version = "17.9.0";
|
||||||
|
hash = "sha256-iiXUFzpvT8OWdzMj9FGJDqanwHx40s1TXVY9l3ii+s0=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Microsoft.TestPlatform.TestHost";
|
||||||
|
version = "17.9.0";
|
||||||
|
hash = "sha256-1BZIY1z+C9TROgdTV/tq4zsPy7Q71GQksr/LoMKAzqU=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "MSTest.Analyzers";
|
||||||
|
version = "3.7.3";
|
||||||
|
hash = "sha256-6mNfHtx9FBWA6/QrRUepwbxXWG/54GRyeZYazDiMacg=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "MSTest.TestAdapter";
|
||||||
|
version = "3.7.3";
|
||||||
|
hash = "sha256-3O/AXeS+3rHWstinivt73oa0QDp+xQpTc9p46EF+Mtc=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "MSTest.TestFramework";
|
||||||
|
version = "3.7.3";
|
||||||
|
hash = "sha256-RweCMMf14GI6HqjDIP68JM67IaJKYQTZy0jk5Q4DFxs=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Newtonsoft.Json";
|
||||||
|
version = "13.0.1";
|
||||||
|
hash = "sha256-K2tSVW4n4beRPzPu3rlVaBEMdGvWSv/3Q1fxaDh4Mjo=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Newtonsoft.Json";
|
||||||
|
version = "13.0.3";
|
||||||
|
hash = "sha256-hy/BieY4qxBWVVsDqqOPaLy1QobiIapkbrESm6v2PHc=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "SmallestCSVParser";
|
||||||
|
version = "1.1.1";
|
||||||
|
hash = "sha256-64E87w+4FcQtYsFIOMGGmYmjXVGBwsBqgLVb7p0wc04=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Soulseek";
|
||||||
|
version = "7.1.0";
|
||||||
|
hash = "sha256-n6LUNuPmmy9QYNNALR0ObYyR9LJalf0H8P+SKnoqfFc=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "SpotifyAPI.Web";
|
||||||
|
version = "7.2.1";
|
||||||
|
hash = "sha256-gbTLJaj7DSXZQlo0xpegZ8HLruMe6WmDyD8+l6YE3hg=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "SpotifyAPI.Web.Auth";
|
||||||
|
version = "7.2.1";
|
||||||
|
hash = "sha256-uzpyPlXNCuSHrcK4SKH0ydY2HlDKXU51W5ahk2Oqu98=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Buffers";
|
||||||
|
version = "4.5.1";
|
||||||
|
hash = "sha256-wws90sfi9M7kuCPWkv1CEYMJtCqx9QB/kj0ymlsNaxI=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.CodeDom";
|
||||||
|
version = "7.0.0";
|
||||||
|
hash = "sha256-7IPt39cY+0j0ZcRr/J45xPtEjnSXdUJ/5ai3ebaYQiE=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Diagnostics.DiagnosticSource";
|
||||||
|
version = "5.0.0";
|
||||||
|
hash = "sha256-6mW3N6FvcdNH/pB58pl+pFSCGWgyaP4hfVtC/SMWDV4=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.IO.Pipelines";
|
||||||
|
version = "9.0.1";
|
||||||
|
hash = "sha256-CnmDanknCGbNnoDjgZw62M/Grg8IMTJDa8x3P07UR2A=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Management";
|
||||||
|
version = "7.0.2";
|
||||||
|
hash = "sha256-bJ21ILQfbHb8mX2wnVh7WP/Ip7gdVPIw+BamQuifTVY=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Memory";
|
||||||
|
version = "4.5.5";
|
||||||
|
hash = "sha256-EPQ9o1Kin7KzGI5O3U3PUQAZTItSbk9h/i4rViN3WiI=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Memory";
|
||||||
|
version = "4.6.0";
|
||||||
|
hash = "sha256-OhAEKzUM6eEaH99DcGaMz2pFLG/q/N4KVWqqiBYUOFo=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Reflection.Metadata";
|
||||||
|
version = "1.6.0";
|
||||||
|
hash = "sha256-JJfgaPav7UfEh4yRAQdGhLZF1brr0tUWPl6qmfNWq/E=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Runtime.CompilerServices.Unsafe";
|
||||||
|
version = "6.0.0";
|
||||||
|
hash = "sha256-bEG1PnDp7uKYz/OgLOWs3RWwQSVYm+AnPwVmAmcgp2I=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Text.Encodings.Web";
|
||||||
|
version = "9.0.1";
|
||||||
|
hash = "sha256-iuAVcTiiZQLCZjDfDqdLLPHqZdZqvFabwLFHiVYdRJo=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Text.Json";
|
||||||
|
version = "9.0.1";
|
||||||
|
hash = "sha256-2dqE+Mx5eJZ8db74ofUiUXHOSxDCmXw5n9VC9w4fUr0=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.Threading.Tasks.Extensions";
|
||||||
|
version = "4.6.0";
|
||||||
|
hash = "sha256-OwIB0dpcdnyfvTUUj6gQfKW2XF2pWsQhykwM1HNCHqY=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "System.ValueTuple";
|
||||||
|
version = "4.5.0";
|
||||||
|
hash = "sha256-niH6l2fU52vAzuBlwdQMw0OEoRS/7E1w5smBFoqSaAI=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "TagLibSharp";
|
||||||
|
version = "2.3.0";
|
||||||
|
hash = "sha256-PD9bVZiPaeC8hNx2D+uDUf701cCaMi2IRi5oPTNN+/w=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "Unosquare.Swan.Lite";
|
||||||
|
version = "3.1.0";
|
||||||
|
hash = "sha256-PL8N3CqIz/wku8/mkRMC3X868Byv47C20/rBLBhkS3o=";
|
||||||
|
})
|
||||||
|
(fetchNuGet {
|
||||||
|
pname = "YoutubeExplode";
|
||||||
|
version = "6.5.4";
|
||||||
|
hash = "sha256-5sexIiBj5XP9rP5DA0NQ+vHJ9lpjwp00EvVux901WLc=";
|
||||||
|
})
|
||||||
|
]
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
{
|
||||||
|
lib,
|
||||||
|
stdenv,
|
||||||
|
buildDotnetModule,
|
||||||
|
fetchFromGitHub,
|
||||||
|
dotnetCorePackages,
|
||||||
|
}:
|
||||||
|
|
||||||
|
if !stdenv.hostPlatform.isLinux then
|
||||||
|
null
|
||||||
|
else
|
||||||
|
buildDotnetModule rec {
|
||||||
|
pname = "slsk-batchdl";
|
||||||
|
version = "2.4.7";
|
||||||
|
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "fiso64";
|
||||||
|
repo = "slsk-batchdl";
|
||||||
|
rev = "v${version}";
|
||||||
|
sha256 = "sha256-P7V7YJUA1bkfp13Glb1Q+NJ7iTya/xgO1TM88z1Nddc=";
|
||||||
|
};
|
||||||
|
|
||||||
|
projectFile = "slsk-batchdl/slsk-batchdl.csproj";
|
||||||
|
nugetDeps = ./nuget-deps.nix;
|
||||||
|
|
||||||
|
dotnet-sdk = dotnetCorePackages.sdk_8_0;
|
||||||
|
dotnet-runtime = dotnetCorePackages.runtime_8_0;
|
||||||
|
|
||||||
|
postPatch = ''
|
||||||
|
substituteInPlace slsk-batchdl/slsk-batchdl.csproj \
|
||||||
|
--replace-fail "net6.0" "net8.0"
|
||||||
|
'';
|
||||||
|
|
||||||
|
doCheck = false;
|
||||||
|
|
||||||
|
meta = with lib; {
|
||||||
|
description = "A batch downloader for Soulseek";
|
||||||
|
homepage = "https://github.com/fiso64/slsk-batchdl";
|
||||||
|
platforms = platforms.linux;
|
||||||
|
mainProgram = "slsk-batchdl";
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -6,17 +6,17 @@
|
|||||||
# Specify AWS_PROFILE and AWS_REGION before running this script
|
# Specify AWS_PROFILE and AWS_REGION before running this script
|
||||||
|
|
||||||
aws ec2 describe-instances \
|
aws ec2 describe-instances \
|
||||||
--filters "Name=instance-state-name,Values=running" |
|
--filters "Name=instance-state-name,Values=running" |
|
||||||
jq -r \
|
jq -r \
|
||||||
'.Reservations[]
|
'.Reservations[]
|
||||||
| .Instances[]
|
| .Instances[]
|
||||||
| .InstanceId + " - " +
|
| .InstanceId + " - " +
|
||||||
(.PrivateIpAddress // "n/a") + " - " +
|
(.PrivateIpAddress // "n/a") + " - " +
|
||||||
(.PublicIpAddress // "n/a") + " - " +
|
(.PublicIpAddress // "n/a") + " - " +
|
||||||
(.Tags // [] | from_entries | .Name // "n/a")' |
|
(.Tags // [] | from_entries | .Name // "n/a")' |
|
||||||
fzf \
|
fzf \
|
||||||
--height 100% \
|
--height 100% \
|
||||||
--layout reverse \
|
--layout reverse \
|
||||||
--header $'Press Enter to start SSM session\nInstance ID - Private IP - Public IP - Name' \
|
--header $'Press Enter to start SSM session\nInstance ID - Private IP - Public IP - Name' \
|
||||||
--preview "aws ec2 describe-instances --instance-ids \"\$(echo {} | cut -d' ' -f1)\" | jq -r '.Reservations[].Instances[0]'" \
|
--preview "aws ec2 describe-instances --instance-ids \"\$(echo {} | cut -d' ' -f1)\" | jq -r '.Reservations[].Instances[0]'" \
|
||||||
--bind "enter:become(aws ssm start-session --target \$(echo {} | cut -d' ' -f1))"
|
--bind "enter:become(aws ssm start-session --document-name 'AWS-StartInteractiveCommand' --parameters '{\"command\": [\"bash\"]}' --target \$(echo {} | cut -d' ' -f1))"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ pkgs.mkShell {
|
|||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
git
|
git
|
||||||
stylua
|
stylua
|
||||||
nixfmt-rfc-style
|
nixfmt
|
||||||
shfmt
|
shfmt
|
||||||
shellcheck
|
shellcheck
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,44 +1,47 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
# Inspired by https://github.com/cleverca22/nix-tests/blob/master/kexec/justdoit.nix
|
# Inspired by https://github.com/cleverca22/nix-tests/blob/master/kexec/justdoit.nix
|
||||||
# This script will partition and format drives; use at your own risk!
|
# This script will partition and format drives; use at your own risk!
|
||||||
|
|
||||||
pkgs.writeShellScriptBin "installer" ''
|
if !pkgs.stdenv.hostPlatform.isLinux then
|
||||||
set -e
|
null
|
||||||
|
else
|
||||||
|
pkgs.writeShellScriptBin "installer" ''
|
||||||
|
set -e
|
||||||
|
|
||||||
DISK=$1
|
DISK=$1
|
||||||
FLAKE=$2
|
FLAKE=$2
|
||||||
PARTITION_PREFIX=""
|
PARTITION_PREFIX=""
|
||||||
|
|
||||||
if [ -z "$DISK" ] || [ -z "$FLAKE" ]; then
|
if [ -z "$DISK" ] || [ -z "$FLAKE" ]; then
|
||||||
${pkgs.gum}/bin/gum style --width 50 --margin "1 2" --padding "2 4" \
|
${pkgs.gum}/bin/gum style --width 50 --margin "1 2" --padding "2 4" \
|
||||||
--foreground "#fb4934" \
|
--foreground "#fb4934" \
|
||||||
"Missing required parameter." \
|
"Missing required parameter." \
|
||||||
"Usage: installer -- <disk> <host>" \
|
"Usage: installer -- <disk> <host>" \
|
||||||
"Example: installer -- nvme0n1 tempest" \
|
"Example: installer -- nvme0n1 tempest" \
|
||||||
"Flake example: nix run github:nmasur/dotfiles#installer -- nvme0n1 tempest"
|
"Flake example: nix run github:nmasur/dotfiles#installer -- nvme0n1 tempest"
|
||||||
echo "(exiting)"
|
echo "(exiting)"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$DISK" in nvme*)
|
case "$DISK" in nvme*)
|
||||||
PARTITION_PREFIX="p"
|
PARTITION_PREFIX="p"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
${pkgs.gum}/bin/gum confirm \
|
${pkgs.gum}/bin/gum confirm \
|
||||||
"This will ERASE ALL DATA on the disk /dev/''${DISK}. Are you sure you want to continue?" \
|
"This will ERASE ALL DATA on the disk /dev/''${DISK}. Are you sure you want to continue?" \
|
||||||
--default=false
|
--default=false
|
||||||
|
|
||||||
${pkgs.parted}/bin/parted /dev/''${DISK} -- mklabel gpt
|
${pkgs.parted}/bin/parted /dev/''${DISK} -- mklabel gpt
|
||||||
${pkgs.parted}/bin/parted /dev/''${DISK} -- mkpart primary 512MiB 100%
|
${pkgs.parted}/bin/parted /dev/''${DISK} -- mkpart primary 512MiB 100%
|
||||||
${pkgs.parted}/bin/parted /dev/''${DISK} -- mkpart ESP fat32 1MiB 512MiB
|
${pkgs.parted}/bin/parted /dev/''${DISK} -- mkpart ESP fat32 1MiB 512MiB
|
||||||
${pkgs.parted}/bin/parted /dev/''${DISK} -- set 3 esp on
|
${pkgs.parted}/bin/parted /dev/''${DISK} -- set 3 esp on
|
||||||
mkfs.ext4 -L nixos /dev/''${DISK}''${PARTITION_PREFIX}1
|
mkfs.ext4 -L nixos /dev/''${DISK}''${PARTITION_PREFIX}1
|
||||||
mkfs.fat -F 32 -n boot /dev/''${DISK}''${PARTITION_PREFIX}2
|
mkfs.fat -F 32 -n boot /dev/''${DISK}''${PARTITION_PREFIX}2
|
||||||
|
|
||||||
mount /dev/disk/by-label/nixos /mnt
|
mount /dev/disk/by-label/nixos /mnt
|
||||||
mkdir --parents /mnt/boot
|
mkdir --parents /mnt/boot
|
||||||
mount /dev/disk/by-label/boot /mnt/boot
|
mount /dev/disk/by-label/boot /mnt/boot
|
||||||
|
|
||||||
${pkgs.nixos-install-tools}/bin/nixos-install --flake github:nmasur/dotfiles#''${FLAKE}
|
${pkgs.nixos-install-tools}/bin/nixos-install --flake github:nmasur/dotfiles#''${FLAKE}
|
||||||
''
|
''
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
|
|
||||||
pkgs.writeShellScriptBin "rebuild" ''
|
pkgs.writeShellScriptBin "rebuild" ''
|
||||||
echo ${pkgs.system}
|
echo ${pkgs.stdenv.hostPlatform.system}
|
||||||
SYSTEM=${if pkgs.stdenv.isDarwin then "darwin" else "linux"}
|
SYSTEM=${if pkgs.stdenv.hostPlatform.isDarwin then "darwin" else "linux"}
|
||||||
if [ "$SYSTEM" == "darwin" ]; then
|
if [ "$SYSTEM" == "darwin" ]; then
|
||||||
sudo darwin-rebuild switch --flake ${builtins.toString ../../../../.}
|
sudo darwin-rebuild switch --flake ${builtins.toString ../../../../.}
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -8,6 +8,5 @@ pkgs.rustPlatform.buildRustPackage {
|
|||||||
rev = "50c40172e354caffee48932266edd7c7a76a20fd";
|
rev = "50c40172e354caffee48932266edd7c7a76a20fd";
|
||||||
sha256 = "sha256-zVIt6Xp+Mvym6gySvHIZJt1QgzKVP/wbTGTubWk6kzI=";
|
sha256 = "sha256-zVIt6Xp+Mvym6gySvHIZJt1QgzKVP/wbTGTubWk6kzI=";
|
||||||
};
|
};
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-lSeO/GaJPZ8zosOIJRXVIEuPXaBg1GBvKBIuXtu1xZg=";
|
cargoHash = "sha256-lSeO/GaJPZ8zosOIJRXVIEuPXaBg1GBvKBIuXtu1xZg=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,5 @@ pkgs.rustPlatform.buildRustPackage {
|
|||||||
rev = "2a24f95170aa14b5182b2287125664a62f8688ef";
|
rev = "2a24f95170aa14b5182b2287125664a62f8688ef";
|
||||||
sha256 = "sha256-gBxrbGCy6JEHnmgJmcm8sgtEvCAqra8/gPGsfCEfLqg=";
|
sha256 = "sha256-gBxrbGCy6JEHnmgJmcm8sgtEvCAqra8/gPGsfCEfLqg=";
|
||||||
};
|
};
|
||||||
useFetchCargoVendor = true;
|
|
||||||
cargoHash = "sha256-t4tfQaFq4EV4ZWeU+IestSFiSAIeVQslTZhLbpKVoO4=";
|
cargoHash = "sha256-t4tfQaFq4EV4ZWeU+IestSFiSAIeVQslTZhLbpKVoO4=";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ in
|
|||||||
virtualisation.diskSize = lib.mkDefault (16 * 1024); # In MB
|
virtualisation.diskSize = lib.mkDefault (16 * 1024); # In MB
|
||||||
|
|
||||||
boot.kernelPackages = lib.mkDefault pkgs.linuxKernel.packages.linux_6_6;
|
boot.kernelPackages = lib.mkDefault pkgs.linuxKernel.packages.linux_6_6;
|
||||||
boot.loader.systemd-boot.enable = false;
|
boot.loader.systemd-boot.enable = lib.mkForce false;
|
||||||
boot.loader.efi.canTouchEfiVariables = false;
|
boot.loader.efi.canTouchEfiVariables = lib.mkForce false; # Default, conflicts with tempest
|
||||||
services.amazon-ssm-agent.enable = lib.mkDefault true;
|
services.amazon-ssm-agent.enable = lib.mkDefault true;
|
||||||
users.users.ssm-user.extraGroups = [ "wheel" ];
|
users.users.ssm-user.extraGroups = [ "wheel" ];
|
||||||
|
services.udisks2.enable = lib.mkForce false; # Off by default already; conflicts with gvfs for nautilus
|
||||||
|
boot.loader.grub.device = lib.mkForce "/dev/xvda"; # Default, conflicts with tempest
|
||||||
|
boot.loader.grub.efiSupport = lib.mkForce false; # Default, conflicts with tempest
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,23 +17,27 @@ in
|
|||||||
home.packages = [
|
home.packages = [
|
||||||
pkgs.nerd-fonts.victor-mono # Used for Vim and Terminal
|
pkgs.nerd-fonts.victor-mono # Used for Vim and Terminal
|
||||||
pkgs.nerd-fonts.hack # For Polybar, Rofi
|
pkgs.nerd-fonts.hack # For Polybar, Rofi
|
||||||
|
|
||||||
|
# Maple Mono NF (Ligature unhinted)
|
||||||
|
pkgs.maple-mono.NF-unhinted
|
||||||
];
|
];
|
||||||
fonts.fontconfig = {
|
fonts.fontconfig = {
|
||||||
enable = true;
|
enable = true;
|
||||||
defaultFonts.monospace = [ "Victor Mono" ];
|
defaultFonts.monospace = [ "Maple Mono NF" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
xsession.windowManager.i3.config.fonts = {
|
xsession.windowManager.i3.config.fonts = {
|
||||||
names = [ "pango:Victor Mono" ];
|
# names = [ "pango:Victor Mono" ];
|
||||||
|
names = [ "pango:Maple Mono" ];
|
||||||
# style = "Regular";
|
# style = "Regular";
|
||||||
# size = 11.0;
|
# size = 11.0;
|
||||||
};
|
};
|
||||||
services.polybar.config."bar/main".font-0 = "Hack Nerd Font:size=10;2";
|
services.polybar.config."bar/main".font-0 = "Hack Nerd Font:size=10;2";
|
||||||
programs.rofi.font = "Hack Nerd Font 14";
|
programs.rofi.font = "Hack Nerd Font 14";
|
||||||
programs.alacritty.settings.font.normal.family = "VictorMono";
|
programs.alacritty.settings.font.normal.family = "Maple Mono NF";
|
||||||
programs.kitty.font.name = "VictorMono Nerd Font Mono";
|
programs.kitty.font.name = "Maple Mono NF";
|
||||||
nmasur.presets.programs.wezterm.font = "VictorMono Nerd Font Mono";
|
nmasur.presets.programs.wezterm.font = "Maple Mono NF";
|
||||||
programs.ghostty.settings.font-family = "VictorMono Nerd Font Mono";
|
programs.ghostty.settings.font-family = "Maple Mono NF";
|
||||||
services.dunst.settings.global.font = "Hack Nerd Font 14";
|
services.dunst.settings.global.font = "Hack Nerd Font 14";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
# Cursor
|
# Cursor
|
||||||
home.pointerCursor = {
|
home.pointerCursor = {
|
||||||
|
enable = true;
|
||||||
name = "Adwaita";
|
name = "Adwaita";
|
||||||
package = pkgs.adwaita-icon-theme;
|
package = pkgs.adwaita-icon-theme;
|
||||||
size = 24;
|
size = 24;
|
||||||
@@ -48,6 +49,7 @@ in
|
|||||||
gtk4.extraConfig = {
|
gtk4.extraConfig = {
|
||||||
gtk-application-prefer-dark-theme = config.theme.mode == "dark";
|
gtk-application-prefer-dark-theme = config.theme.mode == "dark";
|
||||||
};
|
};
|
||||||
|
gtk4.theme = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,16 +18,17 @@ in
|
|||||||
"1password"
|
"1password"
|
||||||
"_1password-gui"
|
"_1password-gui"
|
||||||
"1password-cli"
|
"1password-cli"
|
||||||
"onepassword-password-manager" # Firefox extension
|
# "onepassword-password-manager" # Firefox extension
|
||||||
];
|
];
|
||||||
home.packages = [
|
home.packages = [
|
||||||
pkgs._1password-cli
|
pkgs._1password-cli
|
||||||
] ++ (if pkgs.stdenv.isLinux then [ pkgs._1password-gui ] else [ ]);
|
]
|
||||||
|
++ (if pkgs.stdenv.hostPlatform.isLinux then [ pkgs._1password-gui ] else [ ]);
|
||||||
|
|
||||||
# Firefox extension
|
# # Firefox extension
|
||||||
programs.firefox.profiles.default.extensions.packages = [
|
# programs.firefox.profiles.default.extensions.packages = [
|
||||||
pkgs.nur.repos.rycee.firefox-addons.onepassword-password-manager
|
# pkgs.nur.repos.rycee.firefox-addons.onepassword-password-manager
|
||||||
];
|
# ];
|
||||||
};
|
};
|
||||||
|
|
||||||
# # https://1password.community/discussion/135462/firefox-extension-does-not-connect-to-linux-app
|
# # https://1password.community/discussion/135462/firefox-extension-does-not-connect-to-linux-app
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ in
|
|||||||
home.packages = with pkgs; [
|
home.packages = with pkgs; [
|
||||||
w3m # Render HTML
|
w3m # Render HTML
|
||||||
dante # Socksify for rendering HTML
|
dante # Socksify for rendering HTML
|
||||||
|
aba # Address book
|
||||||
];
|
];
|
||||||
|
|
||||||
programs.aerc = {
|
programs.aerc = {
|
||||||
@@ -110,6 +111,7 @@ in
|
|||||||
"<C-j>" = ":next-part<Enter>";
|
"<C-j>" = ":next-part<Enter>";
|
||||||
J = ":next <Enter>";
|
J = ":next <Enter>";
|
||||||
K = ":prev<Enter>";
|
K = ":prev<Enter>";
|
||||||
|
aa = ":pipe -m aba parse --all<Enter>";
|
||||||
};
|
};
|
||||||
|
|
||||||
"view::passthrough" = {
|
"view::passthrough" = {
|
||||||
@@ -172,8 +174,10 @@ in
|
|||||||
filters = {
|
filters = {
|
||||||
"text/plain" = "${pkgs.aerc}/libexec/aerc/filters/colorize";
|
"text/plain" = "${pkgs.aerc}/libexec/aerc/filters/colorize";
|
||||||
"text/calendar" = "${pkgs.gawk}/bin/awk -f ${pkgs.aerc}/libexec/aerc/filters/calendar";
|
"text/calendar" = "${pkgs.gawk}/bin/awk -f ${pkgs.aerc}/libexec/aerc/filters/calendar";
|
||||||
|
# "text/html" =
|
||||||
|
# "${pkgs.aerc}/libexec/aerc/filters/html | ${pkgs.aerc}/libexec/aerc/filters/colorize"; # Requires w3m, dante
|
||||||
"text/html" =
|
"text/html" =
|
||||||
"${pkgs.aerc}/libexec/aerc/filters/html | ${pkgs.aerc}/libexec/aerc/filters/colorize"; # Requires w3m, dante
|
"!${pkgs.chawan}/bin/cha --type text/html --opt display.image-mode=kitty --opt display.columns=100 --opt display.force-columns=true";
|
||||||
# "text/*" =
|
# "text/*" =
|
||||||
# ''${pkgs.bat}/bin/bat -fP --file-name="$AERC_FILENAME "'';
|
# ''${pkgs.bat}/bin/bat -fP --file-name="$AERC_FILENAME "'';
|
||||||
"message/delivery-status" = "${pkgs.aerc}/libexec/aerc/filters/colorize";
|
"message/delivery-status" = "${pkgs.aerc}/libexec/aerc/filters/colorize";
|
||||||
@@ -183,6 +187,10 @@ in
|
|||||||
"audio/*" = "${pkgs.mpv}/bin/mpv -";
|
"audio/*" = "${pkgs.mpv}/bin/mpv -";
|
||||||
"image/*" = "${pkgs.feh}/bin/feh -";
|
"image/*" = "${pkgs.feh}/bin/feh -";
|
||||||
};
|
};
|
||||||
|
compose = {
|
||||||
|
editor = config.home.sessionVariables.EDITOR;
|
||||||
|
address-book-cmd = "aba ls \"%s\"";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
accounts.email.accounts.home.aerc = {
|
accounts.email.accounts.home.aerc = {
|
||||||
@@ -194,24 +202,36 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
xdg.desktopEntries.aerc = lib.mkIf (pkgs.stdenv.isLinux) {
|
# Used for macOS
|
||||||
|
xdg.enable = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin true;
|
||||||
|
|
||||||
|
xdg.desktopEntries.aerc = lib.mkIf (pkgs.stdenv.hostPlatform.isLinux) {
|
||||||
name = "aerc";
|
name = "aerc";
|
||||||
exec = "${lib.getExe config.nmasur.presets.services.i3.terminal} aerc %u";
|
exec = "${lib.getExe config.nmasur.presets.services.i3.terminal} -e aerc %u";
|
||||||
};
|
};
|
||||||
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.isLinux {
|
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||||
"${config.xsession.windowManager.i3.config.modifier}+Shift+e" = "exec ${
|
"${config.xsession.windowManager.i3.config.modifier}+Shift+e" =
|
||||||
# Don't name the script `aerc` or it will affect grep
|
let
|
||||||
builtins.toString (
|
terminal = config.nmasur.presets.services.i3.terminal;
|
||||||
pkgs.writeShellScript "focus-mail.sh" ''
|
startupCommand =
|
||||||
count=$(ps aux | grep -c aerc)
|
if terminal == pkgs.wezterm then
|
||||||
if [ "$count" -eq 1 ]; then
|
"start --class com.noah.aerc -- aerc"
|
||||||
i3-msg "exec --no-startup-id ${lib.getExe config.nmasur.presets.services.i3.terminal} start --class aerc -- aerc"
|
else
|
||||||
sleep 0.25
|
"--class=com.noah.aerc -e aerc";
|
||||||
fi
|
in
|
||||||
i3-msg "[class=aerc] focus"
|
"exec ${
|
||||||
''
|
# Don't name the script `aerc` or it will affect grep
|
||||||
)
|
builtins.toString (
|
||||||
}";
|
pkgs.writeShellScript "focus-mail.sh" ''
|
||||||
|
count=$(ps aux | grep -c aerc)
|
||||||
|
if [ "$count" -eq 1 ]; then
|
||||||
|
i3-msg "exec --no-startup-id ${lib.getExe terminal} ${startupCommand}"
|
||||||
|
sleep 0.25
|
||||||
|
fi
|
||||||
|
i3-msg "[class=com.noah.aerc] focus"
|
||||||
|
''
|
||||||
|
)
|
||||||
|
}";
|
||||||
};
|
};
|
||||||
|
|
||||||
programs.fish.shellAbbrs = {
|
programs.fish.shellAbbrs = {
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
programs.atuin = {
|
programs.atuin = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
daemon.enable = true;
|
||||||
flags = [
|
flags = [
|
||||||
"--disable-up-arrow"
|
"--disable-up-arrow"
|
||||||
"--disable-ctrl-r"
|
"--disable-ctrl-r"
|
||||||
@@ -33,6 +34,7 @@ in
|
|||||||
secrets_filter = true;
|
secrets_filter = true;
|
||||||
enter_accept = false;
|
enter_accept = false;
|
||||||
keymap_mode = "vim-normal";
|
keymap_mode = "vim-normal";
|
||||||
|
records = true; # Sync v2
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{ config, lib, ... }:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.aws-ssh;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.nmasur.presets.programs.aws-ssh.enable = lib.mkEnableOption "AWS SSH tools";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
# Ignore wine directories in searches
|
||||||
|
home.file.".ssh/aws-ssm-ssh-proxy-command.sh" = {
|
||||||
|
text = builtins.readFile ./aws-ssm-ssh-proxy-command.sh;
|
||||||
|
executable = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
+69
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
#
|
||||||
|
# For documentation see https://github.com/qoomon/aws-ssm-ssh-proxy-command
|
||||||
|
#
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
getInstanceId() {
|
||||||
|
local instance_name="$1"
|
||||||
|
local instance_id=$(aws ec2 describe-instances --filters "Name=tag:Name,Values=${instance_name}" --query "Reservations[].Instances[?State.Name == 'running'].InstanceId" --output text)
|
||||||
|
|
||||||
|
echo "${instance_id}"
|
||||||
|
}
|
||||||
|
|
||||||
|
instance_name="$1"
|
||||||
|
ssh_user="$2"
|
||||||
|
ssh_port="$3"
|
||||||
|
ssh_public_key_path="$4"
|
||||||
|
|
||||||
|
ec2InstanceIdPattern='^m?i-[0-9a-f]{8,17}$'
|
||||||
|
if [[ $instance_name =~ $ec2InstanceIdPattern ]]; then
|
||||||
|
instance_id=$instance_name
|
||||||
|
else
|
||||||
|
instance_id=$(getInstanceId "$instance_name")
|
||||||
|
|
||||||
|
if [[ -z $instance_id ]]; then
|
||||||
|
echo "Found no running instances with name \"${instance_name}\"."
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "Instance ID for \"${instance_name}\": \"${instance_id}\""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
REGION_SEPARATOR='--'
|
||||||
|
if echo "$instance_id" | grep -q -e "${REGION_SEPARATOR}"; then
|
||||||
|
export AWS_REGION="${instance_id##*"${REGION_SEPARATOR}"}"
|
||||||
|
instance_id="${instance_id%%"$REGION_SEPARATOR"*}"
|
||||||
|
fi
|
||||||
|
|
||||||
|
>/dev/stderr echo "Add public key ${ssh_public_key_path} for ${ssh_user} at instance ${instance_id} for 10 seconds"
|
||||||
|
ssh_public_key="$(cat "${ssh_public_key_path}")"
|
||||||
|
aws ssm send-command \
|
||||||
|
--instance-ids "${instance_id}" \
|
||||||
|
--document-name 'AWS-RunShellScript' \
|
||||||
|
--comment "Add an SSH public key to authorized_keys for 10 seconds" \
|
||||||
|
--parameters commands="
|
||||||
|
\"
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
mkdir -p ~${ssh_user}/.ssh && cd ~${ssh_user}/.ssh
|
||||||
|
|
||||||
|
authorized_key='${ssh_public_key} ssm-session'
|
||||||
|
|
||||||
|
echo \\\"\${authorized_key}\\\" >> authorized_keys
|
||||||
|
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
(grep -v -F \\\"\${authorized_key}\\\" authorized_keys || true) > authorized_keys~
|
||||||
|
mv authorized_keys~ authorized_keys
|
||||||
|
\"
|
||||||
|
"
|
||||||
|
|
||||||
|
>/dev/stderr echo "Start ssm session to instance ${instance_id}"
|
||||||
|
aws ssm start-session \
|
||||||
|
--target "${instance_id}" \
|
||||||
|
--document-name 'AWS-StartSSHSession' \
|
||||||
|
--parameters "portNumber=${ssh_port}"
|
||||||
@@ -32,7 +32,6 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
accounts.calendar.accounts.default = {
|
accounts.calendar.accounts.default = {
|
||||||
basePath = "other/calendars"; # Where to save calendars in ~ directory
|
|
||||||
name = "personal";
|
name = "personal";
|
||||||
local.type = "filesystem";
|
local.type = "filesystem";
|
||||||
primary = true;
|
primary = true;
|
||||||
|
|||||||
@@ -14,9 +14,14 @@ in
|
|||||||
options.nmasur.presets.programs.calibre.enable = lib.mkEnableOption "Calibre e-book manager";
|
options.nmasur.presets.programs.calibre.enable = lib.mkEnableOption "Calibre e-book manager";
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
home.packages = [ pkgs.calibre ];
|
home.packages = lib.mkIf pkgs.stdenv.hostPlatform.isLinux [ pkgs.calibre ];
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
CALIBRE_USE_DARK_PALETTE = 1;
|
CALIBRE_USE_DARK_PALETTE = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
home.file.".Brewfile".text = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin /* homebrew */ ''
|
||||||
|
cask "calibre" # Nix package broken on macOS
|
||||||
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,16 @@ in
|
|||||||
ca = "cargo";
|
ca = "cargo";
|
||||||
};
|
};
|
||||||
|
|
||||||
home.packages = with pkgs; [
|
home.packages = [
|
||||||
gcc
|
pkgs.gcc
|
||||||
rustc
|
pkgs.rustc
|
||||||
cargo
|
pkgs.cargo
|
||||||
cargo-watch
|
pkgs.stable.cargo-watch
|
||||||
clippy
|
pkgs.clippy
|
||||||
rustfmt
|
pkgs.rustfmt
|
||||||
pkg-config
|
pkgs.pkg-config
|
||||||
openssl
|
pkgs.openssl
|
||||||
|
pkgs.rust-analyzer
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.chawan;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.programs.chawan.enable = lib.mkEnableOption "chawan TUI web browser";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
programs.chawan = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
external.copy-cmd = if pkgs.stdenv.hostPlatform.isLinux then "xclip -selection clipboard -in" else "pbcopy";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Set Chawan as the default app for manual pages
|
||||||
|
home.sessionVariables = {
|
||||||
|
MANPAGER = "${lib.getExe pkgs.chawan} -T text/x-ansi";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.fish.shellAbbrs.man = "mancha";
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -17,6 +17,9 @@ in
|
|||||||
programs.direnv = {
|
programs.direnv = {
|
||||||
enable = true;
|
enable = true;
|
||||||
nix-direnv.enable = true;
|
nix-direnv.enable = true;
|
||||||
|
config = {
|
||||||
|
global.hide_env_diff = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
# Always make the dotfiles directory considered safe for git and direnv
|
# Always make the dotfiles directory considered safe for git and direnv
|
||||||
programs.git.extraConfig.safe.directory = cfg.path;
|
programs.git.settings.safe.directory = cfg.path;
|
||||||
programs.direnv.config.whitelist.prefix = [ cfg.path ];
|
programs.direnv.config.whitelist.prefix = [ cfg.path ];
|
||||||
|
|
||||||
home.activation = {
|
home.activation = {
|
||||||
|
|||||||
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.feishin;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.programs.feishin.enable = lib.mkEnableOption "Feishin music player";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
home.packages = [ pkgs.feishin ];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -23,7 +23,9 @@ in
|
|||||||
|
|
||||||
programs.firefox = {
|
programs.firefox = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = if pkgs.stdenv.isDarwin then pkgs.firefox-unwrapped else pkgs.firefox;
|
package = pkgs.firefox;
|
||||||
|
# Use appropriate default path depending on the OS
|
||||||
|
configPath = if pkgs.stdenv.hostPlatform.isDarwin then "Library/Application Support/Firefox" else ".mozilla/firefox";
|
||||||
profiles.default = {
|
profiles.default = {
|
||||||
id = 0;
|
id = 0;
|
||||||
name = "default";
|
name = "default";
|
||||||
@@ -46,6 +48,8 @@ in
|
|||||||
ublacklist
|
ublacklist
|
||||||
vimium
|
vimium
|
||||||
wappalyzer # TODO: only for work profile
|
wappalyzer # TODO: only for work profile
|
||||||
|
# pkgs.nmasur.firefox-history-exporter
|
||||||
|
# copy-as-markdown
|
||||||
# saml-tracer
|
# saml-tracer
|
||||||
# text-fragment
|
# text-fragment
|
||||||
];
|
];
|
||||||
@@ -53,7 +57,7 @@ in
|
|||||||
"app.update.auto" = false;
|
"app.update.auto" = false;
|
||||||
"browser.aboutConfig.showWarning" = false;
|
"browser.aboutConfig.showWarning" = false;
|
||||||
"browser.warnOnQuit" = false;
|
"browser.warnOnQuit" = false;
|
||||||
"browser.quitShortcut.disabled" = if pkgs.stdenv.isLinux then true else false;
|
"browser.quitShortcut.disabled" = if pkgs.stdenv.hostPlatform.isLinux then true else false;
|
||||||
"browser.theme.dark-private-windows" = true;
|
"browser.theme.dark-private-windows" = true;
|
||||||
"browser.toolbars.bookmarks.visibility" = false;
|
"browser.toolbars.bookmarks.visibility" = false;
|
||||||
"browser.startup.page" = 3; # Restore previous session
|
"browser.startup.page" = 3; # Restore previous session
|
||||||
@@ -61,6 +65,7 @@ in
|
|||||||
"trailhead.firstrun.didSeeAboutWelcome" = true; # Disable welcome splash
|
"trailhead.firstrun.didSeeAboutWelcome" = true; # Disable welcome splash
|
||||||
"dom.forms.autocomplete.formautofill" = false; # Disable autofill
|
"dom.forms.autocomplete.formautofill" = false; # Disable autofill
|
||||||
"extensions.formautofill.creditCards.enabled" = false; # Disable credit cards
|
"extensions.formautofill.creditCards.enabled" = false; # Disable credit cards
|
||||||
|
"extensions.autoDisableScopes" = false; # Enable extensions automatically
|
||||||
"dom.payments.defaults.saveAddress" = false; # Disable address save
|
"dom.payments.defaults.saveAddress" = false; # Disable address save
|
||||||
"general.autoScroll" = true; # Drag middle-mouse to scroll
|
"general.autoScroll" = true; # Drag middle-mouse to scroll
|
||||||
"services.sync.prefs.sync.general.autoScroll" = false; # Prevent disabling autoscroll
|
"services.sync.prefs.sync.general.autoScroll" = false; # Prevent disabling autoscroll
|
||||||
@@ -74,6 +79,8 @@ in
|
|||||||
"svg.context-properties.content.enabled" = true; # Sidebery styling
|
"svg.context-properties.content.enabled" = true; # Sidebery styling
|
||||||
"browser.tabs.hoverPreview.enabled" = false; # Disable tab previews
|
"browser.tabs.hoverPreview.enabled" = false; # Disable tab previews
|
||||||
"browser.tabs.hoverPreview.showThumbnails" = false; # Disable tab previews
|
"browser.tabs.hoverPreview.showThumbnails" = false; # Disable tab previews
|
||||||
|
"browser.gesture.swipe.left" = "cmd_scrollLeft"; # Disable swipe to go back
|
||||||
|
"browser.gesture.swipe.right" = "cmd_scrollRight"; # Disable swipe to go forward
|
||||||
};
|
};
|
||||||
userChrome = ''
|
userChrome = ''
|
||||||
:root {
|
:root {
|
||||||
@@ -182,10 +189,10 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.isLinux {
|
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.hostPlatform.isLinux {
|
||||||
"${config.xsession.windowManager.i3.config.modifier}+Shift+b" = "exec ${
|
"${config.xsession.windowManager.i3.config.modifier}+Shift+b" = "exec ${
|
||||||
# Don't name the script `firefox` or it will affect grep
|
# Don't name the script `firefox` or it will affect grep
|
||||||
builtins.toString (
|
toString (
|
||||||
pkgs.writeShellScript "focus-ff.sh" ''
|
pkgs.writeShellScript "focus-ff.sh" ''
|
||||||
count=$(ps aux | grep -c firefox)
|
count=$(ps aux | grep -c firefox)
|
||||||
if [ "$count" -eq 1 ]; then
|
if [ "$count" -eq 1 ]; then
|
||||||
|
|||||||
@@ -13,13 +13,35 @@ in
|
|||||||
|
|
||||||
options.nmasur.presets.programs.fish-darwin.enable = lib.mkEnableOption {
|
options.nmasur.presets.programs.fish-darwin.enable = lib.mkEnableOption {
|
||||||
description = "Fish macOS options";
|
description = "Fish macOS options";
|
||||||
default = config.nmasur.presets.programs.fish && pkgs.stdenv.isDarwin;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
programs.fish.shellAbbrs = {
|
# Default shell setting doesn't work
|
||||||
# Shortcut to edit hosts file
|
home.sessionVariables = {
|
||||||
hosts = "sudo nvim /etc/hosts";
|
SHELL = "${pkgs.fish}/bin/fish";
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.fish = {
|
||||||
|
shellAbbrs = {
|
||||||
|
# Shortcut to edit hosts file
|
||||||
|
hosts = "sudo hx /etc/hosts";
|
||||||
|
};
|
||||||
|
shellInit = ''
|
||||||
|
set -g __nixos_path_original $PATH
|
||||||
|
function __nixos_path_fix -d "fix PATH value"
|
||||||
|
set -l result (string split ":" $__nixos_path_original)
|
||||||
|
for elt in $PATH
|
||||||
|
if not contains -- $elt $result
|
||||||
|
set -a result $elt
|
||||||
|
end
|
||||||
|
end
|
||||||
|
set -g PATH $result
|
||||||
|
end
|
||||||
|
__nixos_path_fix
|
||||||
|
'';
|
||||||
|
|
||||||
|
# # Speeds up fish launch time on macOS
|
||||||
|
# useBabelfish = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,10 +114,17 @@ in
|
|||||||
dr = "docker run --rm -it";
|
dr = "docker run --rm -it";
|
||||||
db = "docker build . -t";
|
db = "docker build . -t";
|
||||||
};
|
};
|
||||||
shellInit = "";
|
shellInit = ''
|
||||||
|
# Fix for lagging/hanging after exiting TUIs inside terminal multiplexers like Zellij:
|
||||||
|
# Disable fish terminal querying at startup so fish does not query DA1/termcap on return.
|
||||||
|
set -gx fish_features no-query-term
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
home.sessionVariables.fish_greeting = "";
|
home.sessionVariables = {
|
||||||
|
fish_greeting = "";
|
||||||
|
fish_features = "no-query-term";
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,12 +14,16 @@ in
|
|||||||
options.nmasur.presets.programs.ghostty.enable = lib.mkEnableOption "Ghostty terminal";
|
options.nmasur.presets.programs.ghostty.enable = lib.mkEnableOption "Ghostty terminal";
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
# Set the i3 terminal
|
||||||
|
nmasur.presets.services.i3.terminal = config.programs.ghostty.package;
|
||||||
|
|
||||||
programs.ghostty = {
|
programs.ghostty = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|
||||||
package = if pkgs.stdenv.isDarwin then pkgs.nur.repos.DimitarNestorov.ghostty else pkgs.ghostty;
|
package = if pkgs.stdenv.hostPlatform.isDarwin then pkgs.ghostty-bin else pkgs.ghostty;
|
||||||
|
|
||||||
enableFishIntegration = true;
|
enableFishIntegration = false; # Handled conditionally below to avoid conflicts inside Zellij/TMUX
|
||||||
enableBashIntegration = true;
|
enableBashIntegration = true;
|
||||||
enableZshIntegration = true;
|
enableZshIntegration = true;
|
||||||
installBatSyntax = false; # The file doesn't seem to exist in the pkg
|
installBatSyntax = false; # The file doesn't seem to exist in the pkg
|
||||||
@@ -29,13 +33,21 @@ in
|
|||||||
macos-titlebar-style = "hidden";
|
macos-titlebar-style = "hidden";
|
||||||
window-decoration = false;
|
window-decoration = false;
|
||||||
macos-non-native-fullscreen = true;
|
macos-non-native-fullscreen = true;
|
||||||
fullscreen = true;
|
quit-after-last-window-closed = lib.mkIf pkgs.stdenv.hostPlatform.isDarwin true;
|
||||||
|
fullscreen = if pkgs.stdenv.hostPlatform.isDarwin then true else false;
|
||||||
keybind = [
|
keybind = [
|
||||||
"super+t=unbind" # Pass super-t to underlying tool (e.g. zellij tabs)
|
# Translate Mac Super & Ctrl combinations into Alt (ESC prefix) sequences
|
||||||
"super+shift+]=unbind"
|
# so Zellij receives them without needing Kitty keyboard protocol
|
||||||
"super+shift+[=unbind"
|
"super+t=text:\\x1bt"
|
||||||
"ctrl+tab=unbind"
|
"super+shift+]=text:\\x1b}"
|
||||||
"ctrl+shift+tab=unbind"
|
"super+shift+[=text:\\x1b{"
|
||||||
|
"ctrl+tab=text:\\x1b}"
|
||||||
|
"ctrl+shift+tab=text:\\x1b{"
|
||||||
|
"super+k=text:\\x1bK"
|
||||||
|
"super+shift+e=text:\\x1bE"
|
||||||
|
# Send CSI-u sequence for Alt+Shift+P / Super+Shift+P to bypass Zellij 0.45's DCS (ESC P) parser timeout (~1.5s delay)
|
||||||
|
"alt+shift+p=text:\\x1b[112;4u"
|
||||||
|
"super+shift+p=text:\\x1b[112;4u"
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
themes."gruvbox" = {
|
themes."gruvbox" = {
|
||||||
@@ -72,5 +84,12 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Conditionally enable Ghostty fish shell integration only when NOT running inside multiplexers like Zellij/TMUX
|
||||||
|
programs.fish.shellInit = ''
|
||||||
|
if set -q GHOSTTY_RESOURCES_DIR; and not set -q ZELLIJ; and not set -q TMUX
|
||||||
|
source "$GHOSTTY_RESOURCES_DIR/shell-integration/fish/vendor_conf.d/ghostty-shell-integration.fish"
|
||||||
|
end
|
||||||
|
'';
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
pkgs,
|
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
@@ -40,8 +39,19 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
userName = lib.mkForce cfg.work.name;
|
settings = {
|
||||||
userEmail = lib.mkForce cfg.work.email;
|
user = {
|
||||||
|
name = lib.mkForce cfg.work.name;
|
||||||
|
email = lib.mkForce cfg.work.email;
|
||||||
|
signingKey = "~/.ssh/work_github";
|
||||||
|
};
|
||||||
|
commit = {
|
||||||
|
gpgsign = true;
|
||||||
|
};
|
||||||
|
tag = {
|
||||||
|
gpgsign = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
includes = [
|
includes = [
|
||||||
{
|
{
|
||||||
path = "${config.home.homeDirectory}/${config.xdg.configFile."git/personal".target}";
|
path = "${config.home.homeDirectory}/${config.xdg.configFile."git/personal".target}";
|
||||||
@@ -51,6 +61,11 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Add work to signers file
|
||||||
|
xdg.configFile."git/allowed-signers".text = ''
|
||||||
|
${cfg.work.email} ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIP7aXbmKHmWUZgwG5HPtwx+nREVeMIRplpAAzxPOFXL
|
||||||
|
'';
|
||||||
|
|
||||||
# Personal git config
|
# Personal git config
|
||||||
xdg.configFile."git/personal".text = lib.generators.toGitINI {
|
xdg.configFile."git/personal".text = lib.generators.toGitINI {
|
||||||
user = {
|
user = {
|
||||||
@@ -58,14 +73,20 @@ in
|
|||||||
email = cfg.personal.email;
|
email = cfg.personal.email;
|
||||||
signingkey = "~/.ssh/id_ed25519";
|
signingkey = "~/.ssh/id_ed25519";
|
||||||
};
|
};
|
||||||
commit = {
|
|
||||||
gpgsign = true;
|
|
||||||
};
|
|
||||||
tag = {
|
|
||||||
gpgsign = true;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Personal jj config
|
||||||
|
programs.jujutsu.settings = {
|
||||||
|
"--scope" = [
|
||||||
|
{
|
||||||
|
"--when".repositories = [ "~/dev/personal" ];
|
||||||
|
user = {
|
||||||
|
name = cfg.personal.name;
|
||||||
|
email = cfg.personal.email;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,9 +29,11 @@ in
|
|||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
userName = cfg.name;
|
settings = {
|
||||||
userEmail = cfg.email;
|
user = {
|
||||||
extraConfig = {
|
name = cfg.name;
|
||||||
|
email = cfg.email;
|
||||||
|
};
|
||||||
core.pager = "${pkgs.git}/share/git/contrib/diff-highlight/diff-highlight | less --no-init";
|
core.pager = "${pkgs.git}/share/git/contrib/diff-highlight/diff-highlight | less --no-init";
|
||||||
interactive.difffilter = "${pkgs.git}/share/git/contrib/diff-highlight/diff-highlight";
|
interactive.difffilter = "${pkgs.git}/share/git/contrib/diff-highlight/diff-highlight";
|
||||||
pager = {
|
pager = {
|
||||||
@@ -63,7 +65,7 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
xdg.configFile."git/allowed-signers".text = ''
|
xdg.configFile."git/allowed-signers".text = ''
|
||||||
7386960+nmasur@users.noreply.github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+AbmjGEwITk5CK9y7+Rg27Fokgj9QEjgc9wST6MA3s
|
${config.nmasur.presets.programs.git.email} ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIB+AbmjGEwITk5CK9y7+Rg27Fokgj9QEjgc9wST6MA3s
|
||||||
'';
|
'';
|
||||||
|
|
||||||
programs.fish.shellAbbrs = {
|
programs.fish.shellAbbrs = {
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ in
|
|||||||
extensions = [
|
extensions = [
|
||||||
pkgs.nmasur.gh-collaborators
|
pkgs.nmasur.gh-collaborators
|
||||||
pkgs.gh-dash
|
pkgs.gh-dash
|
||||||
pkgs.gh-copilot
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,62 @@
|
|||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.nmasur.presets.programs.helix;
|
cfg = config.nmasur.presets.programs.helix;
|
||||||
|
|
||||||
|
blame_file_pretty = pkgs.writeShellScriptBin "blame_file_pretty" ''
|
||||||
|
# Source: https://gist.github.com/gloaysa/828707f067e3bb20da18d72fa5d4963a
|
||||||
|
# Utility for Helix: open the patch for the commit that last touched the current line.
|
||||||
|
# If the line isn’t committed yet, it shows the working-tree diff for THIS file only.
|
||||||
|
# The script writes the diff to /tmp and prints the absolute path to stdout
|
||||||
|
# Adjust `context` to see more/fewer unchanged lines around the change (default: 3).
|
||||||
|
#
|
||||||
|
# usage: git-file_pretty.sh <file> <line> [context_lines]
|
||||||
|
# Helix mapping example:
|
||||||
|
# B = ':open %sh{ ~/.config/helix/utils/git-blame-commit.sh "%{buffer_name}" %{cursor_line} 3 }'
|
||||||
|
file="$1"
|
||||||
|
line="$2"
|
||||||
|
ctx="''${3:-3}"
|
||||||
|
|
||||||
|
# blame the exact line
|
||||||
|
porc="$(git blame -L "$line",+1 --porcelain -- "$file")" || exit 1
|
||||||
|
sha="$(printf '%s\n' "$porc" | awk 'NR==1{print $1}')"
|
||||||
|
commit_path="$(printf '%s\n' "$porc" | awk '/^filename /{print substr($0,10); exit}')"
|
||||||
|
|
||||||
|
out="/tmp/hx-blame_$(basename "$file")_''${sha:-wt}.diff"
|
||||||
|
|
||||||
|
if [ -z "$sha" ] || [ "$sha" = 0000000000000000000000000000000000000000 ] || [ "$sha" = "^" ]; then
|
||||||
|
# uncommitted line → working tree diff for this file
|
||||||
|
git --no-pager diff --no-color -U"$ctx" -- "$file" > "$out"
|
||||||
|
else
|
||||||
|
# committed line → only this file’s patch in that commit
|
||||||
|
git --no-pager show --no-color -M -C -U"$ctx" "$sha" -- "''${commit_path:-$file}" > "$out"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# "return" the path for :open %sh{…}
|
||||||
|
printf '%s' "$out"
|
||||||
|
'';
|
||||||
|
|
||||||
|
blame_line_pretty = pkgs.writeShellScriptBin "blame_line_pretty" ''
|
||||||
|
# Source: https://gist.github.com/gloaysa/828707f067e3bb20da18d72fa5d4963a
|
||||||
|
# Utility for Helix: pretty-print blame info for the line under the cursor.
|
||||||
|
# Quite basic.
|
||||||
|
#
|
||||||
|
# usage: blame_line_pretty <file> <line>
|
||||||
|
# Helix mapping example:
|
||||||
|
# b = ":run-shell-command ~/.config/helix/utils/blame_line_pretty.sh %{buffer_name} %{cursor_line}"
|
||||||
|
file="$1"; line="$2"
|
||||||
|
out="$(git blame -L "$line",+1 --porcelain -- "$file")" || return 1
|
||||||
|
|
||||||
|
sha="$(printf '%s\n' "$out" | awk 'NR==1{print $1}')"
|
||||||
|
author="$(printf '%s\n' "$out" | awk -F'author ' '/^author /{print $2; exit}')"
|
||||||
|
epoch="$(printf '%s\n' "$out" | awk '/^author-time /{print $2; exit}')"
|
||||||
|
# dd-mm-yyyy (macOS `date -r`; fallback to gdate if present)
|
||||||
|
date="$( (date -r "$epoch" +%d-%m-%Y\ %H:%M 2>/dev/null) || (gdate -d "@$epoch" +%d-%m-%Y\ %H:%M 2>/dev/null) || printf '%s' "$epoch")"
|
||||||
|
summary="$(printf '%s\n' "$out" | awk -F'summary ' '/^summary /{print $2; exit}')"
|
||||||
|
change="$(printf '%s\n' "$out" | tail -n 1)"
|
||||||
|
|
||||||
|
printf "%s\n%s\n%s\n%s\n%s\n" "$sha" "$author" "$date" "$summary" "$change"
|
||||||
|
'';
|
||||||
|
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -16,12 +72,15 @@ in
|
|||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
# Use Neovim as the editor for git commit messages
|
# Use Neovim as the editor for git commit messages
|
||||||
programs.git.extraConfig.core.editor = lib.mkForce "${lib.getExe pkgs.helix}";
|
programs.git.settings.core.editor = lib.mkForce "${lib.getExe pkgs.helix}";
|
||||||
programs.jujutsu.settings.ui.editor = lib.mkForce "${lib.getExe pkgs.helix}";
|
programs.jujutsu.settings.ui.editor = lib.mkForce "${lib.getExe pkgs.helix}";
|
||||||
|
|
||||||
# Set Neovim as the default app for text editing and manual pages
|
# Set Neovim as the default app for text editing and manual pages
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
EDITOR = lib.mkForce "${lib.getExe pkgs.helix}";
|
EDITOR = lib.mkForce "${lib.getExe pkgs.helix}";
|
||||||
|
# MANPAGER = lib.mkForce "sh -c 'col -bx | ${lib.getExe pkgs.helix}'";
|
||||||
|
MANWIDTH = 87;
|
||||||
|
MANROFFOPT = "-c";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create quick aliases for launching Helix
|
# Create quick aliases for launching Helix
|
||||||
@@ -43,6 +102,10 @@ in
|
|||||||
command = "${pkgs.nixd}/bin/nixd";
|
command = "${pkgs.nixd}/bin/nixd";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
language-server.ty = {
|
||||||
|
command = "${pkgs.ty}/bin/ty";
|
||||||
|
};
|
||||||
|
|
||||||
language-server.fish-lsp = {
|
language-server.fish-lsp = {
|
||||||
command = "${pkgs.fish-lsp}/bin/fish-lsp";
|
command = "${pkgs.fish-lsp}/bin/fish-lsp";
|
||||||
};
|
};
|
||||||
@@ -55,8 +118,14 @@ in
|
|||||||
command = lib.getExe pkgs.marksman;
|
command = lib.getExe pkgs.marksman;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
language-server.rumdl = {
|
||||||
|
command = lib.getExe pkgs.rumdl;
|
||||||
|
args = [ "server" ];
|
||||||
|
};
|
||||||
|
|
||||||
language-server.terraform-ls = {
|
language-server.terraform-ls = {
|
||||||
command = "${lib.getExe pkgs.terraform-ls} serve";
|
command = "${lib.getExe pkgs.terraform-ls}";
|
||||||
|
args = [ "serve" ];
|
||||||
};
|
};
|
||||||
|
|
||||||
language-server.bash-language-server = {
|
language-server.bash-language-server = {
|
||||||
@@ -78,17 +147,40 @@ in
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "markdown";
|
name = "markdown";
|
||||||
auto-format = true;
|
auto-format = false;
|
||||||
language-servers = [ "marksman" ];
|
language-servers = [
|
||||||
|
"marksman"
|
||||||
|
"rumdl"
|
||||||
|
];
|
||||||
formatter = {
|
formatter = {
|
||||||
command = lib.getExe pkgs.mdformat;
|
command = lib.getExe pkgs.rumdl;
|
||||||
args = [ "-" ];
|
args = [
|
||||||
|
"fmt"
|
||||||
|
"-"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
# Allows return key to continue the token on the next line
|
||||||
|
comment-tokens = [
|
||||||
|
"-"
|
||||||
|
"+"
|
||||||
|
"*"
|
||||||
|
"- [ ]"
|
||||||
|
">"
|
||||||
|
];
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "tfvars";
|
name = "hcl";
|
||||||
|
scope = "source.hcl";
|
||||||
|
# injection-regex = "terraform";
|
||||||
auto-format = true;
|
auto-format = true;
|
||||||
language-servers = [ "terraform-ls" ];
|
language-servers = [ "terraform-ls" ];
|
||||||
|
language-id = "terraform";
|
||||||
|
file-types = [
|
||||||
|
"tf"
|
||||||
|
"tfvars"
|
||||||
|
"terraform"
|
||||||
|
{ glob = "*.auto.tfvars"; }
|
||||||
|
];
|
||||||
formatter = {
|
formatter = {
|
||||||
command = lib.getExe pkgs.terraform;
|
command = lib.getExe pkgs.terraform;
|
||||||
args = [
|
args = [
|
||||||
@@ -98,11 +190,15 @@ in
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
name = "hcl";
|
name = "hcl-packer";
|
||||||
|
scope = "source.hcl-packer";
|
||||||
auto-format = true;
|
auto-format = true;
|
||||||
language-servers = [ "terraform-ls" ];
|
file-types = [
|
||||||
|
"hcl"
|
||||||
|
"pkr.hcl"
|
||||||
|
];
|
||||||
formatter = {
|
formatter = {
|
||||||
command = lib.getExe pkgs.terraform;
|
command = "${pkgs.packer}/bin/packer";
|
||||||
args = [
|
args = [
|
||||||
"fmt"
|
"fmt"
|
||||||
"-"
|
"-"
|
||||||
@@ -117,13 +213,56 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ignores = [
|
||||||
|
"content/.obsidian/**"
|
||||||
|
".direnv/**"
|
||||||
|
];
|
||||||
|
|
||||||
settings = {
|
settings = {
|
||||||
theme = "base16";
|
theme = "base16";
|
||||||
|
|
||||||
keys.normal = {
|
keys.normal = {
|
||||||
|
|
||||||
|
# Use the enter key to save the file
|
||||||
|
ret = ":write";
|
||||||
|
|
||||||
|
# Get out of multiple cursors and selection
|
||||||
|
esc = [
|
||||||
|
"collapse_selection"
|
||||||
|
"keep_primary_selection"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Quit shortcuts
|
||||||
|
space.q = ":quit-all";
|
||||||
|
space.x = ":quit-all!";
|
||||||
|
|
||||||
# Enable and disable inlay hints
|
# Enable and disable inlay hints
|
||||||
space.H = ":toggle lsp.display-inlay-hints";
|
space.H = ":toggle lsp.display-inlay-hints";
|
||||||
|
|
||||||
|
# Toggle floating pane
|
||||||
|
space.t = ":sh zellij action toggle-floating-panes";
|
||||||
|
|
||||||
|
# Today's note
|
||||||
|
space.n = ":vsplit %sh{fish -c 'generate-today'}";
|
||||||
|
|
||||||
|
# Open lazygit
|
||||||
|
# Unfortunately, this breaks mouse input and the terminal after quitting Helix
|
||||||
|
space.l = [
|
||||||
|
":write-all"
|
||||||
|
":new"
|
||||||
|
":insert-output ${lib.getExe pkgs.lazygit} > /dev/tty"
|
||||||
|
":buffer-close!"
|
||||||
|
":redraw"
|
||||||
|
":reload-all"
|
||||||
|
":set mouse false"
|
||||||
|
":set mouse true"
|
||||||
|
];
|
||||||
|
|
||||||
|
# Commandline git blame
|
||||||
|
# space.B = ":echo %sh{git log -n1 --date=short --pretty=format:'%%h %%ad %%s' $(git blame -L %{cursor_line},+1 \"%{buffer_name}\" | cut -d' ' -f1)}";
|
||||||
|
space.B = '':open %sh{ ${blame_line_pretty}/bin/blame_line_pretty "%{buffer_name}" %{cursor_line} 3 }'';
|
||||||
|
space.i = '':open %sh{ ${blame_file_pretty}/bin/blame_file_pretty "%{buffer_name}" %{cursor_line} 3 }'';
|
||||||
|
|
||||||
# Extend selection above
|
# Extend selection above
|
||||||
X = "select_line_above";
|
X = "select_line_above";
|
||||||
|
|
||||||
@@ -140,19 +279,27 @@ in
|
|||||||
"paste_before"
|
"paste_before"
|
||||||
];
|
];
|
||||||
|
|
||||||
# Copy lines up or down
|
A-S-ret = [
|
||||||
A-J = [
|
"open_above"
|
||||||
"extend_to_line_bounds"
|
"normal_mode"
|
||||||
"yank"
|
];
|
||||||
"paste_after"
|
A-ret = [
|
||||||
|
"open_below"
|
||||||
|
"normal_mode"
|
||||||
];
|
];
|
||||||
|
|
||||||
A-K = [
|
};
|
||||||
"extend_to_line_bounds"
|
|
||||||
"yank"
|
|
||||||
"paste_before"
|
|
||||||
];
|
|
||||||
|
|
||||||
|
keys.insert = {
|
||||||
|
# Allows not continuing the comment
|
||||||
|
"A-ret" = [
|
||||||
|
"insert_newline"
|
||||||
|
"extend_to_line_bounds"
|
||||||
|
"delete_selection"
|
||||||
|
"insert_newline"
|
||||||
|
"move_line_up"
|
||||||
|
"insert_mode"
|
||||||
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
editor = {
|
editor = {
|
||||||
@@ -174,12 +321,16 @@ in
|
|||||||
|
|
||||||
# Show hidden files
|
# Show hidden files
|
||||||
file-picker = {
|
file-picker = {
|
||||||
hidden = false;
|
hidden = false; # Show hidden files
|
||||||
git-ignore = true;
|
git-ignore = true; # Skip gitignore files
|
||||||
git-global = true;
|
git-global = true; # Skip global gitignore files
|
||||||
git-exclude = true;
|
git-exclude = true; # Skip excluded files
|
||||||
};
|
};
|
||||||
|
|
||||||
|
completion-replace = true; # Replace whole word with completion
|
||||||
|
trim-trailing-whitespace = true;
|
||||||
|
# rainbow-brackets = true; # Make it easier to match parentheses
|
||||||
|
|
||||||
# Show whitespace visible to the user
|
# Show whitespace visible to the user
|
||||||
# Waiting for trailing whitespace option ideally
|
# Waiting for trailing whitespace option ideally
|
||||||
whitespace = {
|
whitespace = {
|
||||||
@@ -193,9 +344,10 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
themes."${config.programs.helix.settings.theme}" = {
|
themes.base16 = {
|
||||||
"attributes" = config.theme.colors.base09;
|
"attributes" = config.theme.colors.base09;
|
||||||
"comment" = {
|
"comment" = {
|
||||||
fg = config.theme.colors.base03;
|
fg = config.theme.colors.base03;
|
||||||
@@ -279,7 +431,7 @@ in
|
|||||||
bg = config.theme.colors.base00;
|
bg = config.theme.colors.base00;
|
||||||
};
|
};
|
||||||
"ui.cursor" = {
|
"ui.cursor" = {
|
||||||
fg = config.theme.colors.base0A;
|
fg = config.theme.colors.base04;
|
||||||
modifiers = [ "reversed" ];
|
modifiers = [ "reversed" ];
|
||||||
};
|
};
|
||||||
"ui.cursor.insert" = {
|
"ui.cursor.insert" = {
|
||||||
@@ -291,11 +443,202 @@ in
|
|||||||
bg = config.theme.colors.base01;
|
bg = config.theme.colors.base01;
|
||||||
};
|
};
|
||||||
"ui.cursor.match" = {
|
"ui.cursor.match" = {
|
||||||
fg = config.theme.colors.base0A;
|
fg = config.theme.colors.base03;
|
||||||
modifiers = [ "reversed" ];
|
modifiers = [ "reversed" ];
|
||||||
};
|
};
|
||||||
"ui.cursor.select" = {
|
"ui.cursor.select" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.gutter" = {
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.help" = {
|
||||||
|
fg = config.theme.colors.base06;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.linenr" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.linenr.selected" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.menu" = {
|
||||||
|
fg = config.theme.colors.base05;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.menu.scroll" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.menu.selected" = {
|
||||||
|
fg = config.theme.colors.base01;
|
||||||
|
bg = config.theme.colors.base04;
|
||||||
|
};
|
||||||
|
"ui.popup" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.selection" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.selection.primary" = {
|
||||||
|
bg = config.theme.colors.base02;
|
||||||
|
};
|
||||||
|
"ui.statusline" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.statusline.inactive" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.statusline.insert" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base0B;
|
||||||
|
};
|
||||||
|
"ui.statusline.normal" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.statusline.select" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base0F;
|
||||||
|
};
|
||||||
|
"ui.text" = config.theme.colors.base05;
|
||||||
|
"ui.text.focus" = config.theme.colors.base05;
|
||||||
|
"ui.virtual.indent-guide" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.virtual.inlay-hint" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.virtual.ruler" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.virtual.jump-label" = {
|
||||||
fg = config.theme.colors.base0A;
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.window" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
themes.alabaster-style = {
|
||||||
|
"attribute" = config.theme.colors.base05;
|
||||||
|
"comment" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
# modifiers = [ "italic" ];
|
||||||
|
};
|
||||||
|
"constant" = config.theme.colors.base0E;
|
||||||
|
"constant.numeric" = config.theme.colors.base0E;
|
||||||
|
"constant.builtin" = config.theme.colors.base0E;
|
||||||
|
"constant.character" = config.theme.colors.base0E;
|
||||||
|
"constant.character.escape" = config.theme.colors.base0C;
|
||||||
|
"constructor" = config.theme.colors.base0D;
|
||||||
|
"debug" = config.theme.colors.base03;
|
||||||
|
"diagnostic" = {
|
||||||
|
modifiers = [ "underlined" ];
|
||||||
|
};
|
||||||
|
"diff.delta" = config.theme.colors.base09;
|
||||||
|
"diff.minus" = config.theme.colors.base08;
|
||||||
|
"diff.plus" = config.theme.colors.base0B;
|
||||||
|
"error" = config.theme.colors.base08;
|
||||||
|
"function" = config.theme.colors.base0D;
|
||||||
|
"hint" = config.theme.colors.base03;
|
||||||
|
"info" = config.theme.colors.base0D;
|
||||||
|
"keyword" = config.theme.colors.base05;
|
||||||
|
"keyword.control" = config.theme.colors.base05;
|
||||||
|
"keyword.operator" = config.theme.colors.base05;
|
||||||
|
"label" = config.theme.colors.base0E;
|
||||||
|
"namespace" = config.theme.colors.base0E;
|
||||||
|
"operator" = config.theme.colors.base05;
|
||||||
|
"punctuation" = config.theme.colors.base04;
|
||||||
|
"punctuation.bracket" = config.theme.colors.base04;
|
||||||
|
"punctuation.delimiter" = config.theme.colors.base04;
|
||||||
|
"special" = config.theme.colors.base0D;
|
||||||
|
"string" = config.theme.colors.base0B;
|
||||||
|
"string.regexp" = config.theme.colors.base0B;
|
||||||
|
"string.special" = config.theme.colors.base0C;
|
||||||
|
"type" = config.theme.colors.base0A;
|
||||||
|
"variable" = config.theme.colors.base05;
|
||||||
|
"variable.parameter" = config.theme.colors.base05;
|
||||||
|
"variable.builtin" = config.theme.colors.base05;
|
||||||
|
"variable.other.member" = config.theme.colors.base05;
|
||||||
|
"warning" = config.theme.colors.base09;
|
||||||
|
"markup.bold" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"markup.heading" = config.theme.colors.base0D;
|
||||||
|
"markup.italic" = {
|
||||||
|
fg = config.theme.colors.base0E;
|
||||||
|
modifiers = [ "italic" ];
|
||||||
|
};
|
||||||
|
"markup.link.text" = config.theme.colors.base08;
|
||||||
|
"markup.link.url" = {
|
||||||
|
fg = config.theme.colors.base09;
|
||||||
|
modifiers = [ "underlined" ];
|
||||||
|
};
|
||||||
|
"markup.list" = config.theme.colors.base08;
|
||||||
|
"markup.quote" = config.theme.colors.base0C;
|
||||||
|
"markup.raw" = config.theme.colors.base0B;
|
||||||
|
"markup.strikethrough" = {
|
||||||
|
modifiers = [ "crossed_out" ];
|
||||||
|
};
|
||||||
|
"diagnostic.hint" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.info" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.warning" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.error" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"ui.background" = {
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.bufferline.active" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base03;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.bufferline" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.cursor" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursor.insert" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursorline.primary" = {
|
||||||
|
fg = config.theme.colors.base05;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.cursor.match" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursor.select" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
modifiers = [ "reversed" ];
|
modifiers = [ "reversed" ];
|
||||||
};
|
};
|
||||||
"ui.gutter" = {
|
"ui.gutter" = {
|
||||||
@@ -377,6 +720,27 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# Create a desktop option for launching Helix from a file manager
|
||||||
|
# (Requires launching the terminal and then executing Helix)
|
||||||
|
xdg.desktopEntries.helix =
|
||||||
|
lib.mkIf (pkgs.stdenv.hostPlatform.isLinux && config.nmasur.presets.services.i3.enable)
|
||||||
|
{
|
||||||
|
name = "Helix wrapper";
|
||||||
|
exec = ''sh -c "${lib.getExe config.nmasur.presets.services.i3.terminal} --command='hx \$1'" _ %F ''; # TODO: change to work for any terminal
|
||||||
|
mimeType = [
|
||||||
|
"text/plain"
|
||||||
|
"text/markdown"
|
||||||
|
];
|
||||||
|
};
|
||||||
|
xdg.mimeApps.defaultApplications = {
|
||||||
|
"text/plain" = lib.mkBefore [ "Helix.desktop" ];
|
||||||
|
"text/markdown" = lib.mkBefore [ "Helix.desktop" ];
|
||||||
|
};
|
||||||
|
|
||||||
|
home.packages = [
|
||||||
|
(pkgs.writers.writeDashBin "xterm" ''${lib.getExe config.nmasur.presets.services.i3.terminal} +new-window --command"$@" '')
|
||||||
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.homebrew;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.programs.homebrew.enable =
|
||||||
|
lib.mkEnableOption "Homebrew macOS package manager";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
home.file.".Brewfile".text = /* homebrew */ ''
|
||||||
|
# Taps
|
||||||
|
# tap "homebrew/bundle"
|
||||||
|
|
||||||
|
# Brews (CLI Apps)
|
||||||
|
brew "trash" # Delete files and folders to trash instead of rm
|
||||||
|
|
||||||
|
# Casks (GUI Apps)
|
||||||
|
cask "scroll-reverser" # Different scroll style for mouse vs. trackpad
|
||||||
|
cask "notunes" # Don't launch Apple Music with the play button
|
||||||
|
cask "topnotch" # Darkens the menu bar to complete black
|
||||||
|
cask "ghostty" # Terminal application (not buildable on Nix on macOS)
|
||||||
|
cask "discord" # nixpkgs bundle breaks its notarization seal on macOS 26+
|
||||||
|
|
||||||
|
# Mac App Store apps (requires 'mas' CLI, optional)
|
||||||
|
# mas "Tailscale", id: 1475387142
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Add homebrew paths to CLI path
|
||||||
|
home.sessionPath = [
|
||||||
|
"/opt/homebrew/bin/"
|
||||||
|
"/opt/homebrew/opt/trash/bin"
|
||||||
|
];
|
||||||
|
|
||||||
|
programs.fish.shellAbbrs.t = "trash";
|
||||||
|
|
||||||
|
home.activation.backendBrewBundle = /* bash */ ''
|
||||||
|
# Requires Homebrew to be installed
|
||||||
|
if ! /usr/bin/xcode-select --version 2>/dev/null; then
|
||||||
|
$DRY_RUN_CMD /usr/bin/xcode-select --install
|
||||||
|
fi
|
||||||
|
if ! /opt/homebrew/bin/brew --version 2>/dev/null; then
|
||||||
|
$DRY_RUN_CMD /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
verboseEcho "Syncing Homebrew dependencies via Brewfile..."
|
||||||
|
|
||||||
|
# Ensure Homebrew is in the PATH for the script (Apple Silicon path)
|
||||||
|
export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"
|
||||||
|
|
||||||
|
# Keep activation deterministic and non-interactive. Without this, brew
|
||||||
|
# auto-updates (git-fetches its taps) which can hang forever when there
|
||||||
|
# is no TTY (network stall, credential prompt, or a leftover brew lock).
|
||||||
|
export HOMEBREW_NO_AUTO_UPDATE=1
|
||||||
|
export HOMEBREW_NO_ENV_HINTS=1
|
||||||
|
|
||||||
|
# Point brew at the generated Brewfile in the Nix store directly. This
|
||||||
|
# avoids depending on the ~/.Brewfile symlink being linked first, and
|
||||||
|
# sidesteps the --global vs. inherited HOMEBREW_BUNDLE_FILE conflict.
|
||||||
|
unset HOMEBREW_BUNDLE_FILE
|
||||||
|
brewfile="${config.home.file.".Brewfile".source}"
|
||||||
|
|
||||||
|
if command -v brew &> /dev/null; then
|
||||||
|
# Install/upgrade everything declared in the Brewfile...
|
||||||
|
$DRY_RUN_CMD brew bundle install --file="$brewfile"
|
||||||
|
# ...then uninstall anything NOT listed (replaces deprecated --cleanup).
|
||||||
|
$DRY_RUN_CMD brew bundle cleanup --file="$brewfile" --force
|
||||||
|
else
|
||||||
|
verboseEcho "Warning: Homebrew not found. Actions skipped."
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
'';
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
let
|
let
|
||||||
cfg = config.nmasur.presets.programs.jujutsu;
|
cfg = config.nmasur.presets.programs.jujutsu;
|
||||||
|
tomlFormat = pkgs.formats.toml { };
|
||||||
in
|
in
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -19,11 +21,49 @@ in
|
|||||||
# https://github.com/martinvonz/jj/blob/main/docs/config.md
|
# https://github.com/martinvonz/jj/blob/main/docs/config.md
|
||||||
settings = {
|
settings = {
|
||||||
user = {
|
user = {
|
||||||
name = config.programs.git.userName;
|
name = config.programs.git.settings.user.name;
|
||||||
email = config.programs.git.userEmail;
|
email = config.programs.git.settings.user.email;
|
||||||
};
|
};
|
||||||
|
ui.paginate = "never";
|
||||||
|
|
||||||
|
# Automatically snapshot when files change
|
||||||
|
fsmonitor.backend = "watchman";
|
||||||
|
fsmonitor.watchman.register-snapshot-trigger = true;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
xdg.configFile."jjui/config.toml".source = tomlFormat.generate "jjui-config" {
|
||||||
|
actions = [
|
||||||
|
{
|
||||||
|
name = "set-github-bypass";
|
||||||
|
lua = ''
|
||||||
|
exec_shell([[gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/$(gh repo view --json nameWithOwner -q .nameWithOwner)/properties/values -f 'properties[][property_name]=Allow-Ruleset-Bypass' -f 'properties[][value]=true']])
|
||||||
|
flash("Set GitHub rule bypass")
|
||||||
|
'';
|
||||||
|
key = "ctrl+b";
|
||||||
|
scope = "revisions";
|
||||||
|
desc = "Set GitHub rule bypass";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
name = "remove-github-bypass";
|
||||||
|
lua = ''
|
||||||
|
exec_shell([[gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/$(gh repo view --json nameWithOwner -q .nameWithOwner)/properties/values -f 'properties[][property_name]=Allow-Ruleset-Bypass' -f 'properties[][value]=']])
|
||||||
|
flash("Removed GitHub rule bypass")
|
||||||
|
'';
|
||||||
|
key = "ctrl+shift+b";
|
||||||
|
scope = "revisions";
|
||||||
|
desc = "Remove GitHub rule bypass";
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
home.packages = [
|
||||||
|
# Required for the fsmonitor to auto-snapshot
|
||||||
|
pkgs.watchman
|
||||||
|
|
||||||
|
# Required to be on path to work in Zellij
|
||||||
|
pkgs.jjui
|
||||||
|
];
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ in
|
|||||||
nmasur.presets.services.i3.terminal = pkgs.kitty;
|
nmasur.presets.services.i3.terminal = pkgs.kitty;
|
||||||
|
|
||||||
# Set the Rofi terminal for running programs
|
# Set the Rofi terminal for running programs
|
||||||
programs.rofi.terminal = lib.mkIf pkgs.stdenv.isLinux (lib.mkDefault "${pkgs.kitty}/bin/kitty");
|
programs.rofi.terminal = lib.mkIf pkgs.stdenv.hostPlatform.isLinux (lib.mkDefault "${pkgs.kitty}/bin/kitty");
|
||||||
|
|
||||||
# Display images in the terminal
|
# Display images in the terminal
|
||||||
programs.fish.interactiveShellInit = # fish
|
programs.fish.interactiveShellInit = # fish
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.lag-triage;
|
||||||
|
|
||||||
|
term-probe = pkgs.writeScriptBin "term-probe" ''
|
||||||
|
#!${lib.getExe pkgs.python3}
|
||||||
|
${builtins.readFile ./term_probe.py}
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.programs.lag-triage.enable =
|
||||||
|
lib.mkEnableOption "Terminal input-lag triage tools";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
home.packages = [ term-probe ];
|
||||||
|
|
||||||
|
# Ctrl-b: EXECUTE the proven manual cure as a real commandline. The cure
|
||||||
|
# is not the variable's end value (it starts and ends at 1) — it is the
|
||||||
|
# reader fully exiting readline and re-entering, which only command
|
||||||
|
# EXECUTION does. Setting the variable inline (a plain binding body, or the
|
||||||
|
# old fish_postexec/fish_cancel hook) never makes the reader exit/re-enter,
|
||||||
|
# so it never cured and, with extra repaints on a wedged reader, made it
|
||||||
|
# worse. `commandline -f execute` reproduces exactly what typing the cure
|
||||||
|
# and pressing Enter does — indistinguishable to fish from the manual cure.
|
||||||
|
# Note: this submits the current commandline, so it runs the cure in place
|
||||||
|
# of whatever is typed (fine for a rescue key hit at an empty prompt).
|
||||||
|
# Ctrl-b chosen because it is otherwise unbound (Ctrl-g is taken).
|
||||||
|
nmasur.presets.programs.fish.fish_user_key_bindings = # fish
|
||||||
|
''
|
||||||
|
for mode in insert default visual
|
||||||
|
bind -M $mode \cb heal-autosuggest
|
||||||
|
end
|
||||||
|
'';
|
||||||
|
|
||||||
|
programs.fish.functions = {
|
||||||
|
lag-triage = {
|
||||||
|
description = "Diagnose post-TUI typing lag in the current shell";
|
||||||
|
body = builtins.readFile ./lag-triage.fish;
|
||||||
|
};
|
||||||
|
unlag = {
|
||||||
|
description = "Reset terminal state left behind by a TUI";
|
||||||
|
body = builtins.readFile ./unlag.fish;
|
||||||
|
};
|
||||||
|
lag-sample = {
|
||||||
|
description = "Stack-sample fish and zellij while typing lag is happening";
|
||||||
|
body = builtins.readFile ./lag-sample.fish;
|
||||||
|
};
|
||||||
|
heal-autosuggest = {
|
||||||
|
description = "Heal post-TUI typing lag by executing the autosuggestion-toggle cure (bind to a key)";
|
||||||
|
# Replace the commandline with the exact cure the user runs by hand and
|
||||||
|
# execute it. Executing (not inline-setting) is what cures: it forces
|
||||||
|
# the reader to leave and re-enter readline. Runs in place of whatever
|
||||||
|
# is currently typed.
|
||||||
|
body = # fish
|
||||||
|
''
|
||||||
|
commandline -r 'set -g fish_autosuggestion_enabled 0; and set -g fish_autosuggestion_enabled 1'
|
||||||
|
commandline -f execute
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# Capture stack samples of this fish process, the zellij server, and the
|
||||||
|
# zellij client WHILE the typing lag is happening. This names the guilty
|
||||||
|
# component directly: if fish's main thread is busy/blocked per keystroke the
|
||||||
|
# stacks show exactly where; if fish is idle while typing feels laggy, the
|
||||||
|
# delay is in zellij's render path instead.
|
||||||
|
#
|
||||||
|
# CAUTION (learned 2026-08-30): attaching the sampler to a lagging fish CURES
|
||||||
|
# the lag (thread suspend/resume unwedges it), so run this from a DIFFERENT
|
||||||
|
# pane with the lagging shell's pid: `lag-sample <pid>` (get it in the lagging
|
||||||
|
# shell with the builtin-only `echo $fish_pid`). Have someone type in the
|
||||||
|
# lagging pane while sampling runs — the first samples may catch the wedge.
|
||||||
|
# With no argument it samples the current shell.
|
||||||
|
|
||||||
|
set -l target $fish_pid
|
||||||
|
if test (count $argv) -ge 1; and test -n "$argv[1]"
|
||||||
|
set target $argv[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
set -l outdir ~/.local/state/lag-triage
|
||||||
|
mkdir -p $outdir
|
||||||
|
set -l ts (date +%Y%m%d-%H%M%S)
|
||||||
|
set -l dur 8
|
||||||
|
|
||||||
|
set -l fishfile $outdir/sample-$ts-fish-$target.txt
|
||||||
|
/usr/bin/sample $target $dur 1 -file $fishfile &>/dev/null &
|
||||||
|
disown
|
||||||
|
|
||||||
|
# this session's zellij server (socket path ends in the session name)
|
||||||
|
set -l serverpid (pgrep -f "zellij --server.*/$ZELLIJ_SESSION_NAME\$")
|
||||||
|
test -z "$serverpid"; and set serverpid (pgrep -f "zellij --server" | head -3)
|
||||||
|
for pid in $serverpid
|
||||||
|
/usr/bin/sample $pid $dur 1 -file $outdir/sample-$ts-zellij-server-$pid.txt &>/dev/null &
|
||||||
|
disown
|
||||||
|
end
|
||||||
|
|
||||||
|
# zellij clients (attached to ghostty): named zellij but without --server args
|
||||||
|
set -l allserver (pgrep -f "zellij --server")
|
||||||
|
set -l clientpid
|
||||||
|
for pid in (pgrep -x zellij)
|
||||||
|
contains $pid $allserver; or set -a clientpid $pid
|
||||||
|
end
|
||||||
|
for pid in $clientpid[1..3]
|
||||||
|
/usr/bin/sample $pid $dur 1 -file $outdir/sample-$ts-zellij-client-$pid.txt &>/dev/null &
|
||||||
|
disown
|
||||||
|
end
|
||||||
|
|
||||||
|
# notify when done, without occupying the commandline
|
||||||
|
fish -c "sleep (math $dur + 2); echo; echo '== lag-sample done: '$outdir'/sample-$ts-*.txt =='" &
|
||||||
|
disown
|
||||||
|
|
||||||
|
echo "Sampling fish (pid $target), zellij server(s) [$serverpid], client(s) [$clientpid] for $dur s."
|
||||||
|
echo ">>> TYPE CONTINUOUSLY IN THE LAGGING PANE NOW (junk text is fine) <<<"
|
||||||
|
echo "Files: $outdir/sample-$ts-*.txt"
|
||||||
@@ -0,0 +1,182 @@
|
|||||||
|
# Guided diagnosis for the post-TUI typing-lag problem (Ghostty + Zellij + fish).
|
||||||
|
# Run this IN THE LAGGING SHELL the moment you notice the lag, BEFORE starting
|
||||||
|
# a new shell. It captures evidence, then applies targeted resets one at a time
|
||||||
|
# so the stage that cures the lag identifies the layer holding stuck state.
|
||||||
|
# Everything is logged for filing an upstream issue.
|
||||||
|
|
||||||
|
set -l logdir ~/.local/state/lag-triage
|
||||||
|
mkdir -p $logdir
|
||||||
|
set -l logfile $logdir/(date +%Y%m%d-%H%M%S).log
|
||||||
|
|
||||||
|
function _lt --inherit-variable logfile
|
||||||
|
echo $argv | tee -a $logfile
|
||||||
|
end
|
||||||
|
|
||||||
|
function _lt_ask --inherit-variable logfile
|
||||||
|
# usage: _lt_ask VARNAME prompt... -> sets global $VARNAME (default: skip)
|
||||||
|
set -l __name $argv[1]
|
||||||
|
read -g -P "$argv[2..] " $__name
|
||||||
|
or set -g $__name skip
|
||||||
|
test -z "$$__name"; and set -g $__name skip
|
||||||
|
echo "ANSWER $__name: $$__name" >>$logfile
|
||||||
|
end
|
||||||
|
|
||||||
|
_lt "== lag-triage "(date)" =="
|
||||||
|
_lt "Log: $logfile"
|
||||||
|
_lt "Answer y / n, or press Enter to skip a question."
|
||||||
|
_lt ""
|
||||||
|
|
||||||
|
# ---- 1. Context -------------------------------------------------------------
|
||||||
|
_lt_ask ans_tui "Which TUI did you just exit (nvim/jjui/yazi/other)?"
|
||||||
|
_lt_ask ans_launch "Launched via (f)loating-pane keybind or (c)ommand typed in this shell?"
|
||||||
|
|
||||||
|
# ---- 2. Snapshot ------------------------------------------------------------
|
||||||
|
begin
|
||||||
|
echo "-- snapshot --"
|
||||||
|
fish --version
|
||||||
|
echo "fish pid: $fish_pid, started: "(ps -o lstart= -p $fish_pid 2>/dev/null)
|
||||||
|
zellij --version 2>/dev/null
|
||||||
|
echo "escape delay: '$fish_escape_delay_ms' sequence delay: '$fish_sequence_key_delay_ms'"
|
||||||
|
env | grep -iE '^(TERM|ZELLIJ|GHOSTTY|COLORTERM)' | sort
|
||||||
|
echo "-- status features --"
|
||||||
|
status features
|
||||||
|
echo "-- stty -a --"
|
||||||
|
stty -a
|
||||||
|
end >>$logfile 2>&1
|
||||||
|
_lt "Captured shell + environment snapshot."
|
||||||
|
|
||||||
|
# Proven root cause of the 2026-08 lag (see docs/CHANGELOG.md 2026-08-29):
|
||||||
|
# fish latches feature flags from its startup env before config.fish runs, so
|
||||||
|
# a shell with query-term ON sends terminal queries after every command; one
|
||||||
|
# reply zellij fails to relay permanently degrades this process's reader.
|
||||||
|
if status features | string match -qr '^query-term\s+on'
|
||||||
|
_lt ""
|
||||||
|
_lt "!! query-term is ON in this shell: fish did NOT get fish_features="
|
||||||
|
_lt "!! no-query-term in its STARTUP environment (config.fish is too late)."
|
||||||
|
_lt "!! This is the proven root cause of the post-TUI lag — a query reply"
|
||||||
|
_lt "!! lost by zellij permanently degrades this fish process's reader."
|
||||||
|
_lt "!! Fix: spawn fish with the variable exported (zellij default_shell"
|
||||||
|
_lt "!! wrapper fish-no-query-term). Subshells are immune because they"
|
||||||
|
_lt "!! inherit the exported variable — that's why a new shell 'fixes' it."
|
||||||
|
else
|
||||||
|
_lt "query-term is off in this shell (good — the known root cause is ruled out)."
|
||||||
|
end
|
||||||
|
|
||||||
|
# ---- 3. Terminal state below the shell --------------------------------------
|
||||||
|
_lt ""
|
||||||
|
_lt "Querying terminal state (takes a few seconds)..."
|
||||||
|
term-probe report 2>&1 | tee -a $logfile
|
||||||
|
_lt ""
|
||||||
|
_lt " ^ Things to look for: kitty flags with a reply > 0, modifyOtherKeys > 1,"
|
||||||
|
_lt " any mouse/alternate-screen mode SET while at a shell prompt, or a slow"
|
||||||
|
_lt " DA1 round-trip (> 100 ms means the input path itself is delayed)."
|
||||||
|
|
||||||
|
# ---- 4. Raw keystroke capture (bypasses fish entirely) ----------------------
|
||||||
|
_lt ""
|
||||||
|
_lt "Raw input capture: type ~10 characters at a steady pace, including one"
|
||||||
|
_lt "ESC press and one arrow key. This shows the exact bytes this pane delivers"
|
||||||
|
_lt "and their timing, with fish's input handling out of the picture."
|
||||||
|
term-probe keylog 2>&1 | tee -a $logfile
|
||||||
|
_lt_ask ans_keylog_instant "Did each keypress appear INSTANTLY in the capture? (y/n)"
|
||||||
|
_lt_ask ans_keylog_plain "Were plain letters single plain bytes like b'a' (not escape sequences)? (y/n)"
|
||||||
|
|
||||||
|
# ---- 5. Scope ---------------------------------------------------------------
|
||||||
|
_lt ""
|
||||||
|
_lt_ask ans_scope_pane "Optional: open a NEW zellij pane/tab and type — laggy there too? (y/n)"
|
||||||
|
_lt_ask ans_scope_window "Optional: type in a separate Ghostty window (outside this zellij session) — laggy? (y/n)"
|
||||||
|
|
||||||
|
# ---- 6. Staged resets -------------------------------------------------------
|
||||||
|
# Each stage resets one category of state a TUI could have left behind.
|
||||||
|
# The first stage that cures the lag names the culprit.
|
||||||
|
set -l fixed none
|
||||||
|
|
||||||
|
_lt ""
|
||||||
|
_lt "Now applying resets one at a time. After each, type into the test prompt"
|
||||||
|
_lt "to judge whether the lag is gone."
|
||||||
|
_lt "CAVEAT: fish's read prompt may NOT exhibit lag even when the main"
|
||||||
|
_lt "commandline does. If typing at these test prompts never feels laggy at"
|
||||||
|
_lt "all, answer 'u' (unsure) instead of 'y' — a 'y' here is only meaningful"
|
||||||
|
_lt "if you could feel the lag at the test prompts before the reset."
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt ""
|
||||||
|
_lt "Stage A - kitty keyboard protocol: pop stack + clear all flags"
|
||||||
|
printf '\e[<9u\e[=0;1u'
|
||||||
|
_lt_ask ans_stage_a " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_a" = y; and set fixed "A (kitty keyboard state)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage B - modifyOtherKeys off"
|
||||||
|
printf '\e[>4;0m'
|
||||||
|
_lt_ask ans_stage_b " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_b" = y; and set fixed "B (modifyOtherKeys)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage C - normal keypad + normal cursor keys"
|
||||||
|
printf '\e>\e[?1l'
|
||||||
|
_lt_ask ans_stage_c " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_c" = y; and set fixed "C (application keypad/cursor mode)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage D - disable mouse, focus reporting, synchronized output"
|
||||||
|
printf '\e[?1000l\e[?1001l\e[?1002l\e[?1003l\e[?1005l\e[?1006l\e[?1015l\e[?1016l\e[?1004l\e[?2026l'
|
||||||
|
_lt_ask ans_stage_d " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_d" = y; and set fixed "D (mouse/focus/sync modes)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage E - leave alternate screen"
|
||||||
|
printf '\e[?1049l'
|
||||||
|
_lt_ask ans_stage_e " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_e" = y; and set fixed "E (alternate screen)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage F - stty sane (line-discipline reset)"
|
||||||
|
stty sane
|
||||||
|
_lt_ask ans_stage_f " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_f" = y; and set fixed "F (termios/line discipline)"
|
||||||
|
end
|
||||||
|
|
||||||
|
if test $fixed = none
|
||||||
|
_lt "Stage G - DECSTR soft terminal reset"
|
||||||
|
printf '\e[!p'
|
||||||
|
_lt_ask ans_stage_g " Test typing here, then Enter — lag gone? (y/n)"
|
||||||
|
test "$ans_stage_g" = y; and set fixed "G (DECSTR-resettable mode)"
|
||||||
|
end
|
||||||
|
|
||||||
|
# ---- 7. Verdict --------------------------------------------------------------
|
||||||
|
_lt ""
|
||||||
|
_lt "== Verdict =="
|
||||||
|
if test $fixed != none
|
||||||
|
_lt "Lag cleared by stage $fixed."
|
||||||
|
_lt "That state was stuck BELOW fish — in the Zellij pane or relayed to"
|
||||||
|
_lt "Ghostty — and the TUI you exited ($ans_tui) failed to restore it, or"
|
||||||
|
_lt "Zellij failed to restore it when the pane closed."
|
||||||
|
_lt "Re-probing terminal state after the fix for comparison:"
|
||||||
|
term-probe report 2>&1 | tee -a $logfile
|
||||||
|
_lt ""
|
||||||
|
_lt "-> File this log against zellij (or ghostty, if a separate window also"
|
||||||
|
_lt " lagged). The before/after probe diff pinpoints the exact stuck mode."
|
||||||
|
else if test "$ans_keylog_instant" = y; and test "$ans_keylog_plain" = y
|
||||||
|
_lt "Raw input reaches this pane instantly as plain bytes, and no terminal"
|
||||||
|
_lt "state reset helps: the lag lives INSIDE this fish process (reader state)."
|
||||||
|
_lt "Confirm now: run 'exec fish' — if that cures it, it is fish-internal."
|
||||||
|
_lt ""
|
||||||
|
_lt "-> To catch it in the act, run your next long-lived shell as:"
|
||||||
|
_lt " FISH_DEBUG='reader,term-support' FISH_DEBUG_OUTPUT=$logdir/fish-debug.log fish"
|
||||||
|
_lt " then re-run lag-triage when it recurs and file both logs to fish-shell."
|
||||||
|
else
|
||||||
|
_lt "Keystrokes were delayed or arrived as escape sequences BEFORE fish saw"
|
||||||
|
_lt "them: the problem is in Zellij (client stdin parser / server) or Ghostty."
|
||||||
|
_lt " new pane also laggy: $ans_scope_pane (y -> session-wide, not this pane)"
|
||||||
|
_lt " separate window laggy: $ans_scope_window (y -> Ghostty itself)"
|
||||||
|
_lt "-> File this log against zellij; include the keylog byte capture."
|
||||||
|
end
|
||||||
|
_lt ""
|
||||||
|
_lt "Full log: $logfile"
|
||||||
|
|
||||||
|
functions -e _lt _lt_ask
|
||||||
@@ -0,0 +1,165 @@
|
|||||||
|
"""Probe the terminal state of the current pane, below the shell.
|
||||||
|
|
||||||
|
Modes:
|
||||||
|
report - query kitty-keyboard flags, modifyOtherKeys, and DEC private
|
||||||
|
modes directly on /dev/tty, reporting each reply (or lack of
|
||||||
|
one) and its round-trip latency. Answers may come from Zellij
|
||||||
|
(pane state) or be relayed from Ghostty (window state).
|
||||||
|
keylog - raw-mode keystroke capture: prints the exact bytes and
|
||||||
|
inter-key latency for every keypress, bypassing the shell's
|
||||||
|
input machinery entirely. Press q to finish.
|
||||||
|
|
||||||
|
Used by the `lag-triage` fish function to pin down which layer
|
||||||
|
(fish / zellij / ghostty) is holding stuck state when typing lags
|
||||||
|
after a TUI exits.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import select
|
||||||
|
import sys
|
||||||
|
import termios
|
||||||
|
import time
|
||||||
|
import tty
|
||||||
|
|
||||||
|
# DECRQM reply values
|
||||||
|
DECRQM_VALUES = {
|
||||||
|
"0": "not recognized",
|
||||||
|
"1": "SET",
|
||||||
|
"2": "reset",
|
||||||
|
"3": "permanently set",
|
||||||
|
"4": "permanently reset",
|
||||||
|
}
|
||||||
|
|
||||||
|
DEC_MODES = [
|
||||||
|
(1, "application cursor keys (DECCKM)"),
|
||||||
|
(25, "cursor visible"),
|
||||||
|
(1000, "mouse click reporting"),
|
||||||
|
(1002, "mouse drag reporting"),
|
||||||
|
(1003, "mouse all-motion reporting"),
|
||||||
|
(1004, "focus reporting"),
|
||||||
|
(1006, "SGR mouse encoding"),
|
||||||
|
(1049, "alternate screen"),
|
||||||
|
(2004, "bracketed paste"),
|
||||||
|
(2026, "synchronized output"),
|
||||||
|
(2031, "color theme reporting"),
|
||||||
|
]
|
||||||
|
|
||||||
|
QUERIES = [
|
||||||
|
("kitty keyboard flags (\\e[?u)", b"\x1b[?u", rb"\x1b\[\?(\d+)u", None),
|
||||||
|
("modifyOtherKeys (XTQMODKEYS)", b"\x1b[?4m", rb"\x1b\[>4;(\d+)m", None),
|
||||||
|
("background color (OSC 11)", b"\x1b]11;?\x1b\\", rb"\x1b\]11;([^\x07\x1b]+)", None),
|
||||||
|
] + [
|
||||||
|
(
|
||||||
|
f"DEC mode {num} — {desc}",
|
||||||
|
b"\x1b[?%d$p" % num,
|
||||||
|
rb"\x1b\[\?%d;(\d+)\$y" % num,
|
||||||
|
DECRQM_VALUES,
|
||||||
|
)
|
||||||
|
for num, desc in DEC_MODES
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def read_for(fd, seconds):
|
||||||
|
buf = b""
|
||||||
|
end = time.monotonic() + seconds
|
||||||
|
while True:
|
||||||
|
remaining = end - time.monotonic()
|
||||||
|
if remaining <= 0:
|
||||||
|
break
|
||||||
|
r, _, _ = select.select([fd], [], [], remaining)
|
||||||
|
if not r:
|
||||||
|
break
|
||||||
|
buf += os.read(fd, 4096)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
|
||||||
|
def report(fd):
|
||||||
|
lines = []
|
||||||
|
raw_dump = b""
|
||||||
|
for label, query, pattern, value_names in QUERIES:
|
||||||
|
raw_dump += read_for(fd, 0.02) # drain stragglers
|
||||||
|
start = time.monotonic()
|
||||||
|
os.write(fd, query)
|
||||||
|
buf = b""
|
||||||
|
match = None
|
||||||
|
deadline = time.monotonic() + 0.35
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
buf += read_for(fd, 0.05)
|
||||||
|
match = re.search(pattern, buf)
|
||||||
|
if match:
|
||||||
|
break
|
||||||
|
raw_dump += buf
|
||||||
|
if match:
|
||||||
|
latency = (time.monotonic() - start) * 1000
|
||||||
|
value = match.group(1).decode("ascii", "replace")
|
||||||
|
if value_names:
|
||||||
|
value = f"{value} ({value_names.get(value, '?')})"
|
||||||
|
lines.append(f" {label:45s} = {value:24s} [{latency:6.1f} ms]")
|
||||||
|
else:
|
||||||
|
lines.append(f" {label:45s} = (no reply)")
|
||||||
|
|
||||||
|
# DA1 as a fence: every terminal answers it, so its round-trip time
|
||||||
|
# measures the whole input path (ghostty -> zellij -> pane -> here).
|
||||||
|
start = time.monotonic()
|
||||||
|
os.write(fd, b"\x1b[c")
|
||||||
|
buf = b""
|
||||||
|
match = None
|
||||||
|
deadline = time.monotonic() + 2.0
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
buf += read_for(fd, 0.05)
|
||||||
|
match = re.search(rb"\x1b\[\?([0-9;]*)c", buf)
|
||||||
|
if match:
|
||||||
|
break
|
||||||
|
raw_dump += buf
|
||||||
|
if match:
|
||||||
|
latency = (time.monotonic() - start) * 1000
|
||||||
|
lines.append(
|
||||||
|
f" {'device attributes (DA1) round-trip':45s} = "
|
||||||
|
f"{match.group(1).decode():24s} [{latency:6.1f} ms]"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
lines.append(f" {'device attributes (DA1) round-trip':45s} = (NO REPLY in 2s!)")
|
||||||
|
lines.append(f" raw bytes received: {raw_dump!r}")
|
||||||
|
return lines
|
||||||
|
|
||||||
|
|
||||||
|
def keylog(fd):
|
||||||
|
sys.stdout.write("keylog: capturing raw bytes from the tty. Press q to finish.\r\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
last = time.monotonic()
|
||||||
|
while True:
|
||||||
|
select.select([fd], [], [], None)
|
||||||
|
data = os.read(fd, 4096)
|
||||||
|
now = time.monotonic()
|
||||||
|
delta_ms = (now - last) * 1000
|
||||||
|
last = now
|
||||||
|
sys.stdout.write(f" +{delta_ms:8.1f} ms {data!r} hex={data.hex(' ')}\r\n")
|
||||||
|
sys.stdout.flush()
|
||||||
|
if data in (b"q", b"\x03", b"\x04"):
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
mode = sys.argv[1] if len(sys.argv) > 1 else "report"
|
||||||
|
fd = os.open("/dev/tty", os.O_RDWR)
|
||||||
|
old = termios.tcgetattr(fd)
|
||||||
|
lines = None
|
||||||
|
try:
|
||||||
|
tty.setraw(fd)
|
||||||
|
if mode == "report":
|
||||||
|
lines = report(fd)
|
||||||
|
elif mode == "keylog":
|
||||||
|
keylog(fd)
|
||||||
|
else:
|
||||||
|
raise SystemExit(f"unknown mode: {mode}")
|
||||||
|
finally:
|
||||||
|
termios.tcsetattr(fd, termios.TCSADRAIN, old)
|
||||||
|
os.close(fd)
|
||||||
|
if lines:
|
||||||
|
print("terminal state as seen from this pane:")
|
||||||
|
print("\n".join(lines))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
# One-shot reset of terminal state a TUI may have left behind (kitty keyboard
|
||||||
|
# flags, modifyOtherKeys, application keypad/cursor, mouse/focus reporting,
|
||||||
|
# alternate screen, termios). fish re-enables the modes it wants at the next
|
||||||
|
# prompt, so this is safe to run any time.
|
||||||
|
#
|
||||||
|
# Diagnostic value: if this cures the lag, the stuck state was below fish
|
||||||
|
# (run lag-triage next time to find which mode). If only `exec fish` cures
|
||||||
|
# it, the lag is inside the fish process itself.
|
||||||
|
printf '\e[<9u\e[=0;1u'
|
||||||
|
printf '\e[>4;0m'
|
||||||
|
printf '\e>\e[?1l'
|
||||||
|
printf '\e[?1000l\e[?1001l\e[?1002l\e[?1003l\e[?1005l\e[?1006l\e[?1015l\e[?1016l\e[?1004l\e[?2026l'
|
||||||
|
printf '\e[?1049l'
|
||||||
|
stty sane
|
||||||
|
echo "terminal state reset — if typing still lags, run lag-triage (before exec fish!)"
|
||||||
@@ -0,0 +1,151 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Deterministic repro of permanent fish reader degradation (fish 4.8.1).
|
||||||
|
|
||||||
|
This is evidence for an upstream fish-shell report, and the proof behind the
|
||||||
|
fish-no-query-term wrapper in presets/programs/zellij.nix. Not installed by
|
||||||
|
the nix module; run directly: python3 upstream_repro.py [queryterm|noqueryterm]
|
||||||
|
|
||||||
|
Finding: with the query-term feature enabled (latched from the startup env,
|
||||||
|
which is fish's default), fish sends OSC 11 + CPR (\e[6n) + DA1 (\e[0c)
|
||||||
|
after every external command and waits for the replies. If the terminal
|
||||||
|
fails to reply during ONE such cycle -- even though it answered every query
|
||||||
|
before and answers every query after -- that fish process's interactive
|
||||||
|
reader is PERMANENTLY degraded: keystrokes are no longer echoed (>3s each,
|
||||||
|
never recovers). In production this happens when zellij drops/mis-relays a
|
||||||
|
reply during TUI teardown or heavy output (cf. zellij-org/zellij#5158), and
|
||||||
|
it presents as permanent typing lag cured only by replacing the process.
|
||||||
|
With fish_features=no-query-term in the startup environment, the same
|
||||||
|
sequence has zero effect (~35ms echo throughout).
|
||||||
|
|
||||||
|
Phases:
|
||||||
|
A. terminal answers all queries -> echo ~35ms (both variants)
|
||||||
|
B. replies dropped for one command -> queryterm: echo dead, permanently
|
||||||
|
C. replies restored, another command -> queryterm: still dead
|
||||||
|
"""
|
||||||
|
import os, pty, re, select, subprocess, sys, time, fcntl, termios
|
||||||
|
|
||||||
|
VARIANT = sys.argv[1] if len(sys.argv) > 1 else "queryterm"
|
||||||
|
|
||||||
|
env = dict(os.environ)
|
||||||
|
env["TERM"] = "xterm-ghostty"
|
||||||
|
env["ZELLIJ"] = "0"
|
||||||
|
env["ZELLIJ_SESSION_NAME"] = "repro"
|
||||||
|
env["FISH_DEBUG"] = "term-support"
|
||||||
|
env["FISH_DEBUG_OUTPUT"] = f"/tmp/fish-lagrepro-{VARIANT}.log"
|
||||||
|
env.pop("fish_features", None)
|
||||||
|
if VARIANT == "noqueryterm":
|
||||||
|
env["fish_features"] = "no-query-term"
|
||||||
|
|
||||||
|
master, slave = pty.openpty()
|
||||||
|
# give it a size
|
||||||
|
fcntl.ioctl(master, termios.TIOCSWINSZ, b"\x00\x28\x00\x78\x00\x00\x00\x00")
|
||||||
|
proc = subprocess.Popen(
|
||||||
|
["fish", "-i", "--no-config"],
|
||||||
|
stdin=slave, stdout=slave, stderr=slave, env=env,
|
||||||
|
preexec_fn=lambda: (os.setsid(), fcntl.ioctl(0, termios.TIOCSCTTY, 0)),
|
||||||
|
close_fds=True,
|
||||||
|
)
|
||||||
|
os.close(slave)
|
||||||
|
|
||||||
|
RESPOND = True
|
||||||
|
transcript = []
|
||||||
|
|
||||||
|
def respond(data):
|
||||||
|
"""Answer terminal queries the way a well-behaved terminal would."""
|
||||||
|
out = b""
|
||||||
|
for m in re.finditer(rb"\x1b\[6n", data):
|
||||||
|
out += b"\x1b[40;1R" # CPR
|
||||||
|
for m in re.finditer(rb"\x1b\[0?c", data):
|
||||||
|
out += b"\x1b[?62;22c" # DA1
|
||||||
|
for m in re.finditer(rb"\x1b\[\?u", data):
|
||||||
|
out += b"\x1b[?0u" # kitty flags
|
||||||
|
for m in re.finditer(rb"\x1b\]11;\?", data):
|
||||||
|
out += b"\x1b]11;rgb:2828/2828/2828\x1b\\" # OSC 11
|
||||||
|
for m in re.finditer(rb"\x1b\[>0?q", data):
|
||||||
|
out += b"\x1bP>|ghostty 1.3.1\x1b\\" # XTVERSION
|
||||||
|
for m in re.finditer(rb"\x1bP\+q[0-9a-fA-F;]+\x1b\\", data):
|
||||||
|
out += b"\x1bP0+r\x1b\\" # XTGETTCAP: not found
|
||||||
|
for m in re.finditer(rb"\x1b\[\?(\d+)\$p", data):
|
||||||
|
out += b"\x1b[?%s;2$y" % m.group(1) # DECRQM: reset
|
||||||
|
return out
|
||||||
|
|
||||||
|
def pump(timeout):
|
||||||
|
"""Read fish output for `timeout` seconds, answering queries if RESPOND."""
|
||||||
|
buf = b""
|
||||||
|
end = time.monotonic() + timeout
|
||||||
|
while time.monotonic() < end:
|
||||||
|
r, _, _ = select.select([master], [], [], 0.03)
|
||||||
|
if r:
|
||||||
|
try:
|
||||||
|
data = os.read(master, 65536)
|
||||||
|
except OSError:
|
||||||
|
return buf
|
||||||
|
buf += data
|
||||||
|
transcript.append(data)
|
||||||
|
if RESPOND:
|
||||||
|
reply = respond(data)
|
||||||
|
if reply:
|
||||||
|
os.write(master, reply)
|
||||||
|
return buf
|
||||||
|
|
||||||
|
def send(s):
|
||||||
|
os.write(master, s if isinstance(s, bytes) else s.encode())
|
||||||
|
|
||||||
|
def measure_echo(chars, settle=0.1):
|
||||||
|
"""Send chars one at a time; measure time until each is echoed."""
|
||||||
|
results = []
|
||||||
|
for ch in chars:
|
||||||
|
pump(settle)
|
||||||
|
t0 = time.monotonic()
|
||||||
|
send(ch)
|
||||||
|
deadline = time.monotonic() + 3.0
|
||||||
|
latency = None
|
||||||
|
buf = b""
|
||||||
|
while time.monotonic() < deadline:
|
||||||
|
buf += pump(0.02)
|
||||||
|
if ch.encode() in buf:
|
||||||
|
latency = (time.monotonic() - t0) * 1000
|
||||||
|
break
|
||||||
|
results.append((ch, latency))
|
||||||
|
return results
|
||||||
|
|
||||||
|
print(f"=== variant: {VARIANT} ===")
|
||||||
|
pump(1.2) # startup, queries answered
|
||||||
|
|
||||||
|
send("echo warmup\r")
|
||||||
|
pump(0.8)
|
||||||
|
|
||||||
|
print("phase A: terminal responsive, echo latency per key:")
|
||||||
|
for ch, ms in measure_echo("abcde"):
|
||||||
|
print(f" {ch}: {ms:.0f} ms" if ms else f" {ch}: NO ECHO in 3s")
|
||||||
|
send("\x15") # ctrl-u clear line
|
||||||
|
pump(0.3)
|
||||||
|
|
||||||
|
# Run external command, then STOP answering queries (simulate lost relay)
|
||||||
|
send("sh -c true\r")
|
||||||
|
time.sleep(0.05)
|
||||||
|
RESPOND = False
|
||||||
|
pump(1.0)
|
||||||
|
|
||||||
|
print("phase B: after external command with query replies DROPPED:")
|
||||||
|
for ch, ms in measure_echo("fghij"):
|
||||||
|
print(f" {ch}: {ms:.0f} ms" if ms else f" {ch}: NO ECHO in 3s")
|
||||||
|
send("\x15")
|
||||||
|
pump(0.3)
|
||||||
|
|
||||||
|
# Does it persist across further commands, with responses restored?
|
||||||
|
RESPOND = True
|
||||||
|
send("sh -c true\r")
|
||||||
|
pump(1.0)
|
||||||
|
print("phase C: responses restored, after another external command:")
|
||||||
|
for ch, ms in measure_echo("klmno"):
|
||||||
|
print(f" {ch}: {ms:.0f} ms" if ms else f" {ch}: NO ECHO in 3s")
|
||||||
|
|
||||||
|
send("\x15")
|
||||||
|
pump(0.2)
|
||||||
|
send("exit\r")
|
||||||
|
pump(0.5)
|
||||||
|
try:
|
||||||
|
proc.wait(timeout=3)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
proc.kill()
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.nmasur.presets.programs.lazygit;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
options.nmasur.presets.programs.lazygit.enable = lib.mkEnableOption "Lazygit git TUI";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
programs.lazygit = {
|
||||||
|
enable = true;
|
||||||
|
settings = {
|
||||||
|
git.paging = {
|
||||||
|
# useConfig = true;
|
||||||
|
pager = "${pkgs.git}/share/git/contrib/diff-highlight/diff-highlight";
|
||||||
|
};
|
||||||
|
os = {
|
||||||
|
edit = "${config.home.sessionVariables.EDITOR} {{filename}}";
|
||||||
|
editAtLine = "${config.home.sessionVariables.EDITOR} {{filename}}:{{line}}";
|
||||||
|
editAtLineAndWait = "${config.home.sessionVariables.EDITOR} {{filename}}:{{line}}";
|
||||||
|
openDirInEditor = "${config.home.sessionVariables.EDITOR}";
|
||||||
|
open = "${config.home.sessionVariables.EDITOR} {{filename}}";
|
||||||
|
};
|
||||||
|
customCommands = [
|
||||||
|
{
|
||||||
|
key = "N";
|
||||||
|
context = "files";
|
||||||
|
command = "git add -N {{.SelectedFile.Name}}";
|
||||||
|
}
|
||||||
|
{
|
||||||
|
key = "<a-enter>";
|
||||||
|
context = "global";
|
||||||
|
command =
|
||||||
|
let
|
||||||
|
openGitUrl = pkgs.writeShellScriptBin "open-git-url" ''
|
||||||
|
# Try to get the remote URL using two common methods; suppress stderr for individual commands.
|
||||||
|
# "git remote get-url origin" is generally preferred.
|
||||||
|
# "git config --get remote.origin.url" is a fallback.
|
||||||
|
URL=$(git remote get-url origin 2>/dev/null || git config --get remote.origin.url 2>/dev/null);
|
||||||
|
|
||||||
|
# Check if a URL was actually found.
|
||||||
|
if [ -z "$URL" ]; then
|
||||||
|
# Send error message to stderr so it might appear in lazygit logs or notifications.
|
||||||
|
echo "Lazygit: Could not determine remote URL for 'origin'." >&2;
|
||||||
|
# Exit with an error code.
|
||||||
|
exit 1;
|
||||||
|
fi;
|
||||||
|
|
||||||
|
# Check if the URL is a GitHub SSH URL and convert it to HTTPS.
|
||||||
|
# This uses echo and grep to check for "@github.com" and then sed for transformation.
|
||||||
|
if echo "$URL" | grep -q "@github.com:"; then
|
||||||
|
# Transform git@github.com:user/repo.git to https://github.com/user/repo
|
||||||
|
# The first sed handles the main transformation.
|
||||||
|
# The second sed removes a trailing .git if present, for a cleaner URL.
|
||||||
|
URL=$(echo "$URL" | sed "s|git@github.com:|https://github.com/|" | sed "s|\.git$||");
|
||||||
|
# Optional: Log the transformation for debugging.
|
||||||
|
# echo "Lazygit: Transformed GitHub SSH URL to '$URL'" >&2;
|
||||||
|
fi;
|
||||||
|
|
||||||
|
# Determine the operating system.
|
||||||
|
OS="$(uname -s)";
|
||||||
|
|
||||||
|
# Optional: Echo for debugging. This might appear in lazygit logs or as a brief message.
|
||||||
|
# Remove " >&2" if you want to see it as a potential success message in lazygit UI (if it shows stdout).
|
||||||
|
# echo "Lazygit: Opening URL '$URL' on '$OS'" >&2;
|
||||||
|
|
||||||
|
# Execute the appropriate command to open the URL based on the OS.
|
||||||
|
case "$OS" in
|
||||||
|
Darwin*) # macOS
|
||||||
|
open "$URL";;
|
||||||
|
Linux*) # Linux
|
||||||
|
xdg-open "$URL";;
|
||||||
|
*) # Unsupported OS
|
||||||
|
echo "Lazygit: Unsupported OS ('$OS'). Could not open URL." >&2;
|
||||||
|
exit 1;;
|
||||||
|
esac
|
||||||
|
'';
|
||||||
|
in
|
||||||
|
lib.getExe openGitUrl;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
programs.fish.shellAbbrs = {
|
||||||
|
lg = "lazygit";
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -26,7 +26,7 @@ let
|
|||||||
-E pr=5000/prompt \
|
-E pr=5000/prompt \
|
||||||
-H "${ldap_scheme}://''${LDAP_HOST}:${builtins.toString ldap_port}" \
|
-H "${ldap_scheme}://''${LDAP_HOST}:${builtins.toString ldap_port}" \
|
||||||
-D "${pkgs.lib.toUpper magic_prefix}2\\${pkgs.lib.toLower config.home.username}" \
|
-D "${pkgs.lib.toUpper magic_prefix}2\\${pkgs.lib.toLower config.home.username}" \
|
||||||
-w "$(${pkgs._1password-cli}/bin/op item get T2 --fields label=password --reveal)" \
|
-w "$(/usr/local/bin/op item get T2 --fields label=password --reveal)" \
|
||||||
-b "dc=''${LDAP_HOST//./,dc=}" \
|
-b "dc=''${LDAP_HOST//./,dc=}" \
|
||||||
-s "sub" -x "(cn=''${SEARCH_FILTER})" \
|
-s "sub" -x "(cn=''${SEARCH_FILTER})" \
|
||||||
| ${jq_parse}/bin/ljq
|
| ${jq_parse}/bin/ljq
|
||||||
|
|||||||
@@ -31,5 +31,9 @@ in
|
|||||||
pkgs.mpvScripts.mpv-delete-file
|
pkgs.mpvScripts.mpv-delete-file
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
programs.fish.shellAbbrs = {
|
||||||
|
mpvs = "mpv --shuffle=yes";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,13 +38,13 @@ in
|
|||||||
);
|
);
|
||||||
|
|
||||||
# Use Neovim as the editor for git commit messages
|
# Use Neovim as the editor for git commit messages
|
||||||
programs.git.extraConfig.core.editor = "${lib.getExe cfg.package}";
|
programs.git.settings.core.editor = "${lib.getExe cfg.package}";
|
||||||
programs.jujutsu.settings.ui.editor = "${lib.getExe cfg.package}";
|
programs.jujutsu.settings.ui.editor = "${lib.getExe cfg.package}";
|
||||||
|
|
||||||
# Set Neovim as the default app for text editing and manual pages
|
# Set Neovim as the default app for text editing and manual pages
|
||||||
home.sessionVariables = {
|
home.sessionVariables = {
|
||||||
EDITOR = "${lib.getExe cfg.package}";
|
EDITOR = "${lib.getExe cfg.package}";
|
||||||
MANPAGER = "${lib.getExe cfg.package} +Man!";
|
# MANPAGER = "${lib.getExe cfg.package} +Man!";
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create quick aliases for launching Neovim
|
# Create quick aliases for launching Neovim
|
||||||
@@ -63,10 +63,10 @@ in
|
|||||||
# Create a desktop option for launching Neovim from a file manager
|
# Create a desktop option for launching Neovim from a file manager
|
||||||
# (Requires launching the terminal and then executing Neovim)
|
# (Requires launching the terminal and then executing Neovim)
|
||||||
xdg.desktopEntries.nvim =
|
xdg.desktopEntries.nvim =
|
||||||
lib.mkIf (pkgs.stdenv.isLinux && config.nmasur.presets.services.i3.enable)
|
lib.mkIf (pkgs.stdenv.hostPlatform.isLinux && config.nmasur.presets.services.i3.enable)
|
||||||
{
|
{
|
||||||
name = "Neovim wrapper";
|
name = "Neovim wrapper";
|
||||||
exec = "${lib.getExe config.nmasur.presets.services.i3.terminal} nvim %F"; # TODO: change to generic
|
exec = ''${lib.getExe config.nmasur.presets.services.i3.terminal} --command="nvim %F"''; # TODO: change to generic
|
||||||
mimeType = [
|
mimeType = [
|
||||||
"text/plain"
|
"text/plain"
|
||||||
"text/markdown"
|
"text/markdown"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
config,
|
config,
|
||||||
pkgs,
|
# pkgs,
|
||||||
lib,
|
lib,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
@@ -23,17 +23,18 @@ in
|
|||||||
};
|
};
|
||||||
|
|
||||||
# Create nix-index if doesn't exist
|
# Create nix-index if doesn't exist
|
||||||
home.activation.createNixIndex =
|
# Should not be necessary with the nix-index-database flake
|
||||||
let
|
# home.activation.createNixIndex =
|
||||||
cacheDir = "${config.xdg.cacheHome}/nix-index";
|
# let
|
||||||
in
|
# cacheDir = "${config.xdg.cacheHome}/nix-index";
|
||||||
lib.mkIf config.programs.nix-index.enable (
|
# in
|
||||||
config.lib.dag.entryAfter [ "writeBoundary" ] ''
|
# lib.mkIf config.programs.nix-index.enable (
|
||||||
if [ ! -d ${cacheDir} ]; then
|
# config.lib.dag.entryAfter [ "writeBoundary" ] ''
|
||||||
run ${pkgs.nix-index}/bin/nix-index -f ${pkgs.path}
|
# if [ ! -d ${cacheDir} ]; then
|
||||||
fi
|
# run ${pkgs.nix-index}/bin/nix-index -f ${pkgs.path}
|
||||||
''
|
# fi
|
||||||
);
|
# ''
|
||||||
|
# );
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -15,12 +15,18 @@ in
|
|||||||
description = "Nixpkgs tools for macOS";
|
description = "Nixpkgs tools for macOS";
|
||||||
default =
|
default =
|
||||||
config.nmasur.presets.programs.nixpkgs.enable
|
config.nmasur.presets.programs.nixpkgs.enable
|
||||||
&& pkgs.stdenv.isDarwin
|
&& pkgs.stdenv.hostPlatform.isDarwin
|
||||||
&& config.nmasur.presets.programs.dotfiles.enable;
|
&& config.nmasur.presets.programs.dotfiles.enable;
|
||||||
};
|
};
|
||||||
|
|
||||||
config = lib.mkIf (cfg.enable) {
|
config = lib.mkIf (cfg.enable) {
|
||||||
|
|
||||||
|
# These are useful for triggering from zellij (rather than running directly in the shell)
|
||||||
|
nmasur.presets.programs.nixpkgs.commands.rebuildNixos = pkgs.writeShellScriptBin "rebuild-darwin" ''
|
||||||
|
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
||||||
|
sudo darwin-rebuild switch --flake "${config.nmasur.presets.programs.dotfiles.path}#${config.nmasur.settings.host}"
|
||||||
|
'';
|
||||||
|
|
||||||
programs.fish = {
|
programs.fish = {
|
||||||
shellAbbrs = lib.mkIf config.nmasur.presets.programs.dotfiles.enable {
|
shellAbbrs = lib.mkIf config.nmasur.presets.programs.dotfiles.enable {
|
||||||
nr = {
|
nr = {
|
||||||
@@ -34,13 +40,13 @@ in
|
|||||||
rebuild-darwin = {
|
rebuild-darwin = {
|
||||||
body = ''
|
body = ''
|
||||||
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
||||||
echo "darwin-rebuild switch --flake ${config.nmasur.presets.programs.dotfiles.path}#lookingglass"
|
echo "sudo darwin-rebuild switch --flake ${config.nmasur.presets.programs.dotfiles.path}#lookingglass"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rebuild-darwin-offline = {
|
rebuild-darwin-offline = {
|
||||||
body = ''
|
body = ''
|
||||||
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
||||||
echo "darwin-rebuild switch --option substitute false --flake ${config.nmasur.presets.programs.dotfiles.path}#lookingglass"
|
echo "sudo darwin-rebuild switch --option substitute false --flake ${config.nmasur.presets.programs.dotfiles.path}#lookingglass"
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
rebuild-home = lib.mkForce {
|
rebuild-home = lib.mkForce {
|
||||||
|
|||||||
@@ -11,10 +11,47 @@ in
|
|||||||
|
|
||||||
{
|
{
|
||||||
|
|
||||||
options.nmasur.presets.programs.nixpkgs.enable = lib.mkEnableOption "Nixpkgs presets";
|
options.nmasur.presets.programs.nixpkgs = {
|
||||||
|
enable = lib.mkEnableOption "Nixpkgs presets";
|
||||||
|
commands = {
|
||||||
|
# These are useful for triggering from zellij (rather than running directly in the shell)
|
||||||
|
rebuildHome = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.writeShellScriptBin "rebuild-home" ''
|
||||||
|
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
||||||
|
${lib.getExe pkgs.home-manager} switch --flake "${config.nmasur.presets.programs.dotfiles.path}#${config.nmasur.settings.host}"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
rebuildNixos = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.writeShellScriptBin "rebuild-nixos" ''
|
||||||
|
git -C ${config.nmasur.presets.programs.dotfiles.path} add --intent-to-add --all
|
||||||
|
doas nixos-rebuild switch --flake ${config.nmasur.presets.programs.dotfiles.path}
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
rebuildNixosAndPause = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.writeShellScriptBin "rebuild-nixos-pause" ''
|
||||||
|
${lib.getExe cfg.commands.rebuildNixos} || read
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
rebuildHomeAndPause = lib.mkOption {
|
||||||
|
type = lib.types.package;
|
||||||
|
default = pkgs.writeShellScriptBin "rebuild-home-pause" ''
|
||||||
|
${lib.getExe cfg.commands.rebuildHome} || read
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
home.packages = [
|
||||||
|
pkgs.nh # Allows rebuilding with a cleaner TUI
|
||||||
|
cfg.commands.rebuildHome
|
||||||
|
cfg.commands.rebuildNixos
|
||||||
|
];
|
||||||
|
|
||||||
programs.fish = {
|
programs.fish = {
|
||||||
shellAbbrs = {
|
shellAbbrs = {
|
||||||
n = "nix";
|
n = "nix";
|
||||||
|
|||||||
@@ -44,21 +44,22 @@ in
|
|||||||
programs.fish.functions = {
|
programs.fish.functions = {
|
||||||
syncnotes = {
|
syncnotes = {
|
||||||
description = "Full git commit on notes";
|
description = "Full git commit on notes";
|
||||||
body = builtins.readFile lib.getExe (
|
body =
|
||||||
pkgs.writers.writeFishBin "syncnotes" {
|
let
|
||||||
makeWrapperArgs = [
|
git = lib.getExe pkgs.git;
|
||||||
"--prefix"
|
in
|
||||||
"PATH"
|
# fish
|
||||||
":"
|
''
|
||||||
"${lib.makeBinPath [ pkgs.git ]}"
|
${git} -C ${cfg.path} pull
|
||||||
];
|
${git} -C ${cfg.path} add -A
|
||||||
} builtins.readFile ./syncnotes.fish
|
${git} -C ${cfg.path} commit -m autosync
|
||||||
);
|
${git} -C ${cfg.path} push
|
||||||
|
'';
|
||||||
};
|
};
|
||||||
note = {
|
note = {
|
||||||
description = "Edit or create a note";
|
description = "Edit or create a note";
|
||||||
argumentNames = "filename";
|
argumentNames = "filename";
|
||||||
body = builtins.readFile lib.getExe (
|
body = lib.getExe (
|
||||||
pkgs.writers.writeFishBin "note" {
|
pkgs.writers.writeFishBin "note" {
|
||||||
makeWrapperArgs = [
|
makeWrapperArgs = [
|
||||||
"--prefix"
|
"--prefix"
|
||||||
@@ -69,7 +70,44 @@ in
|
|||||||
pkgs.fzf
|
pkgs.fzf
|
||||||
]}"
|
]}"
|
||||||
];
|
];
|
||||||
} builtins.readFile ./note.fish
|
} (builtins.readFile ./note.fish)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
generate-today = {
|
||||||
|
description = "Create today's note";
|
||||||
|
body = # fish
|
||||||
|
''
|
||||||
|
set filename $(date +%Y-%m-%d_%a)
|
||||||
|
set filepath "${cfg.path}/content/journal/$filename.md"
|
||||||
|
if ! test -e "$filepath"
|
||||||
|
echo -e "---\ntitle: $(date +"%A, %B %e %Y") - $(curl "https://wttr.in/New+York+City?u&format=1")\ntags: [ journal ]\n---\n\n" > "$filepath"
|
||||||
|
end
|
||||||
|
echo "$filepath"
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
today = {
|
||||||
|
description = "Edit or create today's note";
|
||||||
|
body = lib.getExe (
|
||||||
|
pkgs.writers.writeFishBin "today"
|
||||||
|
{
|
||||||
|
makeWrapperArgs = [
|
||||||
|
"--prefix"
|
||||||
|
"PATH"
|
||||||
|
":"
|
||||||
|
"${lib.makeBinPath [
|
||||||
|
pkgs.curl
|
||||||
|
pkgs.helix
|
||||||
|
]}"
|
||||||
|
];
|
||||||
|
} # fish
|
||||||
|
''
|
||||||
|
set filename $(date +%Y-%m-%d_%a)
|
||||||
|
set filepath "${cfg.path}/content/journal/$filename.md"
|
||||||
|
if ! test -e "$filepath"
|
||||||
|
echo -e "---\ntitle: $(date +"%A, %B %e %Y") - $(curl "https://wttr.in/New+York+City?u&format=1")\ntags: [ journal ]\n---\n\n" > "$filepath"
|
||||||
|
end
|
||||||
|
hx "$filepath"
|
||||||
|
''
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,12 +13,23 @@ in
|
|||||||
|
|
||||||
options.nmasur.presets.programs.noti.enable = lib.mkEnableOption "Noti CLI notifications";
|
options.nmasur.presets.programs.noti.enable = lib.mkEnableOption "Noti CLI notifications";
|
||||||
|
|
||||||
config = lib.mkIf (cfg.enable && (pkgs.stdenv.isDarwin || config.services.dunst.enable)) {
|
config = lib.mkIf (cfg.enable && (pkgs.stdenv.hostPlatform.isDarwin || config.services.dunst.enable)) {
|
||||||
home.packages = [ pkgs.noti ];
|
home.packages = [ pkgs.noti ];
|
||||||
programs.fish.shellAbbrs = {
|
programs.fish = {
|
||||||
# Add noti for ghpr in Darwin
|
shellAbbrs = {
|
||||||
ghpr = lib.mkForce "gh pr create && sleep 3 && noti gh run watch";
|
# Add noti for ghpr in Darwin
|
||||||
grw = lib.mkForce "noti gh run watch";
|
ghpr = lib.mkForce "gh pr create && sleep 3 && noti gh run watch";
|
||||||
|
grw = lib.mkForce "noti gh run watch";
|
||||||
|
};
|
||||||
|
functions = {
|
||||||
|
gh-run = {
|
||||||
|
body =
|
||||||
|
lib.mkForce # fish
|
||||||
|
''
|
||||||
|
${lib.getExe pkgs.zellij} action new-pane --start-suspended -- noti gh run watch
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,6 @@ in
|
|||||||
|
|
||||||
# Broken on 2023-12-11
|
# Broken on 2023-12-11
|
||||||
# https://forum.obsidian.md/t/electron-25-is-now-eol-please-upgrade-to-a-newer-version/72878/8
|
# https://forum.obsidian.md/t/electron-25-is-now-eol-please-upgrade-to-a-newer-version/72878/8
|
||||||
# insecurePackages = [ "electron-25.9.0" ];
|
# allowInsecurePackages = [ "electron-36.9.5" ];
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ in
|
|||||||
.terraform/
|
.terraform/
|
||||||
.target/
|
.target/
|
||||||
/Library/
|
/Library/
|
||||||
|
.jj/
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
* {
|
* {
|
||||||
/* General */
|
/* General */
|
||||||
font: "Hack Nerd Font 60";
|
font: "Hack Nerd Font Mono 60";
|
||||||
|
|
||||||
/* option menus: i3-layout, music, power and screenshot
|
/* option menus: i3-layout, music, power and screenshot
|
||||||
*
|
*
|
||||||
@@ -13,7 +13,6 @@
|
|||||||
* around using this character: ■
|
* around using this character: ■
|
||||||
* We then add add 100 actual padding around the icons.
|
* We then add add 100 actual padding around the icons.
|
||||||
* -12px 0px -19px -96px */
|
* -12px 0px -19px -96px */
|
||||||
option-element-padding: 1% 1% 1% 1%;
|
|
||||||
option-5-window-padding: 4% 4%;
|
option-5-window-padding: 4% 4%;
|
||||||
option-5-listview-spacing: 15px;
|
option-5-listview-spacing: 15px;
|
||||||
|
|
||||||
@@ -46,7 +45,7 @@
|
|||||||
layout: horizontal;
|
layout: horizontal;
|
||||||
}
|
}
|
||||||
element {
|
element {
|
||||||
padding: 40px 68px 43px 30px;
|
padding: 40px 62px 40px 36px;
|
||||||
}
|
}
|
||||||
#window {
|
#window {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
|||||||
@@ -15,10 +15,13 @@ in
|
|||||||
|
|
||||||
config = lib.mkIf cfg.enable {
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
home.packages = [ pkgs.jj-starship ];
|
||||||
|
|
||||||
programs.starship = {
|
programs.starship = {
|
||||||
enable = true;
|
enable = true;
|
||||||
enableFishIntegration = true;
|
enableFishIntegration = true;
|
||||||
enableBashIntegration = true;
|
enableBashIntegration = true;
|
||||||
|
enableTransience = true; # Replace previous prompts with custom string
|
||||||
settings = {
|
settings = {
|
||||||
add_newline = false; # Don't print new line at the start of the prompt
|
add_newline = false; # Don't print new line at the start of the prompt
|
||||||
format = lib.concatStrings [
|
format = lib.concatStrings [
|
||||||
@@ -26,6 +29,7 @@ in
|
|||||||
"$git_branch"
|
"$git_branch"
|
||||||
"$git_commit"
|
"$git_commit"
|
||||||
"$git_status"
|
"$git_status"
|
||||||
|
"\${custom.jj}"
|
||||||
"$hostname"
|
"$hostname"
|
||||||
"$cmd_duration"
|
"$cmd_duration"
|
||||||
"$character"
|
"$character"
|
||||||
@@ -37,23 +41,37 @@ in
|
|||||||
vicmd_symbol = "[❮](bold green)";
|
vicmd_symbol = "[❮](bold green)";
|
||||||
};
|
};
|
||||||
cmd_duration = {
|
cmd_duration = {
|
||||||
min_time = 5000;
|
min_time = 5001;
|
||||||
show_notifications = if pkgs.stdenv.isLinux then false else true;
|
show_notifications = if pkgs.stdenv.hostPlatform.isLinux then false else true;
|
||||||
min_time_to_notify = 30000;
|
min_time_to_notify = 30000;
|
||||||
format = "[$duration]($style) ";
|
format = "[$duration]($style) ";
|
||||||
};
|
};
|
||||||
|
custom = {
|
||||||
|
jj = {
|
||||||
|
when = "jj-starship detect";
|
||||||
|
shell = [
|
||||||
|
"jj-starship"
|
||||||
|
"--no-jj-prefix"
|
||||||
|
"--no-git-prefix"
|
||||||
|
];
|
||||||
|
format = "$output ";
|
||||||
|
};
|
||||||
|
};
|
||||||
directory = {
|
directory = {
|
||||||
truncate_to_repo = true;
|
truncate_to_repo = true;
|
||||||
truncation_length = 100;
|
truncation_length = 100;
|
||||||
};
|
};
|
||||||
git_branch = {
|
git_branch = {
|
||||||
|
disabled = true;
|
||||||
format = "[$symbol$branch]($style)";
|
format = "[$symbol$branch]($style)";
|
||||||
};
|
};
|
||||||
git_commit = {
|
git_commit = {
|
||||||
|
disabled = true;
|
||||||
format = "( @ [$hash]($style) )";
|
format = "( @ [$hash]($style) )";
|
||||||
only_detached = false;
|
only_detached = false;
|
||||||
};
|
};
|
||||||
git_status = {
|
git_status = {
|
||||||
|
disabled = true;
|
||||||
format = "([$all_status$ahead_behind]($style) )";
|
format = "([$all_status$ahead_behind]($style) )";
|
||||||
conflicted = "=";
|
conflicted = "=";
|
||||||
ahead = "⇡";
|
ahead = "⇡";
|
||||||
@@ -80,6 +98,17 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
programs.fish = {
|
||||||
|
functions = {
|
||||||
|
# Adjust the prompt in previous commands
|
||||||
|
starship_transient_prompt_func = {
|
||||||
|
body = "echo '$ '";
|
||||||
|
};
|
||||||
|
starship_transient_rprompt_func = {
|
||||||
|
body = "echo ' '";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
-----BEGIN AGE ENCRYPTED FILE-----
|
||||||
|
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IHNzaC1lZDI1NTE5IE1nSGFPdyBTYTRy
|
||||||
|
elYzTGpSNDQ3UEcwTXlVeGJleUJmWWhaeDdDQTFRcGpmNlNrQlNVCjA5L2JrS3Vx
|
||||||
|
Q0cyRkk5dTBLOHJXa0xJSG9MTDFnNjV1M0F5L3F5RUlVbW8KLT4gc3NoLWVkMjU1
|
||||||
|
MTkgWXlTVU1RIG5vNm1Xem9lN2pkS25WRi9xSlpZUjhuYmdUVDUvc2o4M0xqYURR
|
||||||
|
UmY0VGcKWVVQc2wyV0Jqbk9JR3N4bW5HOXFTZHpCa25EMC85eThQY05MdHdaeXZy
|
||||||
|
VQotPiBzc2gtZWQyNTUxOSBuanZYNUEgWXRVa3c4STZ3WmFaNThSdE1QdVpiMVR1
|
||||||
|
cm5hYXJsckZiRGtXLzN5RzJEawpkVHBscFd2c0R1SGxnZ3lKUnNnMEZtTUxoQlB4
|
||||||
|
dVBEbTkvUzBJSVRiV1hBCi0+IHNzaC1lZDI1NTE5IENxSU9VQSAvQjhVam1heHNU
|
||||||
|
elVrVGtvaUx1elFCeTdNTkRnN3c5NEc5MWg4dDU3NUhzCm5sUlhHclJrNldnVDhF
|
||||||
|
MTV2cGd3ZFhFdm1rM2ExWVFXbkNJYWlWY0VnUmsKLT4gc3NoLWVkMjU1MTkgejFP
|
||||||
|
Y1p3IGc1QUdkZEp0Z0xEekFjcHd4WVFVam9BZTBEQm9NR3QzQmxNS09VVXpHV2sK
|
||||||
|
c2tYSElVK2prRlF3VlFqKzlVUFRHUWU3TmFXcEdsV2FKWVhKT3pWZkxVNAotLS0g
|
||||||
|
c1cxdk5sL1c3dDZuVGp5VWJrTlBGZTByNjRxMGxTdHd0NFNHV1pyN2k5Ywr7SW9q
|
||||||
|
/FaTTUHB5QiCihA+385sNogq7Q1RvgT2Dwn9NdmMRd/ObESbokJXVSiDDEt6d39s
|
||||||
|
D/uoDY20p3PCk4julNn1
|
||||||
|
-----END AGE ENCRYPTED FILE-----
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (config.nmasur.settings) hostnames;
|
||||||
|
cfg = config.nmasur.presets.programs.thunderbird;
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.programs.thunderbird = {
|
||||||
|
enable = lib.mkEnableOption "Thunderbird email client";
|
||||||
|
calendar = {
|
||||||
|
username = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Username for the calendar service backend";
|
||||||
|
default = config.nmasur.settings.username;
|
||||||
|
};
|
||||||
|
passwordCommand = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Password for the calendar service backend";
|
||||||
|
default = config.accounts.email.accounts.home.passwordCommand;
|
||||||
|
};
|
||||||
|
hostname = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Hostname for the calendar service backend";
|
||||||
|
default = hostnames.content;
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "URL for the calendar service backend";
|
||||||
|
default = "https://${cfg.calendar.hostname}/remote.php/dav";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
tasks = {
|
||||||
|
username = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Username for the tasks service backend";
|
||||||
|
default = config.nmasur.settings.username;
|
||||||
|
};
|
||||||
|
passwordCommand = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Password for the tasks service backend";
|
||||||
|
default = "${lib.getExe pkgs.age} --decrypt --identity ~/.ssh/id_ed25519 ${pkgs.writeText "taskspass.age" (builtins.readFile ./taskspass.age)}";
|
||||||
|
};
|
||||||
|
hostname = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "Hostname for the tasks service backend";
|
||||||
|
default = hostnames.content;
|
||||||
|
};
|
||||||
|
url = lib.mkOption {
|
||||||
|
type = lib.types.str;
|
||||||
|
description = "URL for the tasks service backend";
|
||||||
|
default = "https://${cfg.tasks.hostname}/remote.php/dav";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
|
||||||
|
programs.thunderbird = {
|
||||||
|
enable = true;
|
||||||
|
profiles.default = {
|
||||||
|
isDefault = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
accounts.email.accounts.home.thunderbird = {
|
||||||
|
enable = true;
|
||||||
|
profiles = [ "default" ];
|
||||||
|
};
|
||||||
|
accounts.calendar.basePath = "other/calendars"; # Where to save calendars in ~ directory
|
||||||
|
# accounts.calendar.accounts.home = {
|
||||||
|
# local.type = "filesystem";
|
||||||
|
# primary = true;
|
||||||
|
# remote = {
|
||||||
|
# passwordCommand = [ cfg.calendar.passwordCommand ];
|
||||||
|
# type = "caldav";
|
||||||
|
# url = cfg.calendar.url;
|
||||||
|
# userName = cfg.calendar.username;
|
||||||
|
# };
|
||||||
|
# thunderbird = {
|
||||||
|
# enable = true;
|
||||||
|
# profiles = [ "default" ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
# accounts.calendar.accounts.tasks = {
|
||||||
|
# local.type = "filesystem";
|
||||||
|
# primary = false;
|
||||||
|
# remote = {
|
||||||
|
# passwordCommand = [ cfg.tasks.passwordCommand ];
|
||||||
|
# type = "caldav";
|
||||||
|
# url = cfg.tasks.url;
|
||||||
|
# userName = cfg.tasks.username;
|
||||||
|
# };
|
||||||
|
# thunderbird = {
|
||||||
|
# enable = true;
|
||||||
|
# profiles = [ "default" ];
|
||||||
|
# };
|
||||||
|
# };
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user