idk some stuff, mostly 25.11 and opencode stuff
This commit is contained in:
Generated
+98
-81
@@ -1,5 +1,21 @@
|
|||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"actor-typeahead-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1762835797,
|
||||||
|
"narHash": "sha256-heizoWUKDdar6ymfZTnj3ytcEv/L4d4fzSmtr0HlXsQ=",
|
||||||
|
"ref": "refs/heads/main",
|
||||||
|
"rev": "677fe7f743050a4e7f09d4a6f87bbf1325a06f6b",
|
||||||
|
"revCount": 6,
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://tangled.org/@jakelazaroff.com/actor-typeahead"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://tangled.org/@jakelazaroff.com/actor-typeahead"
|
||||||
|
}
|
||||||
|
},
|
||||||
"agenix": {
|
"agenix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"darwin": "darwin",
|
"darwin": "darwin",
|
||||||
@@ -10,11 +26,11 @@
|
|||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754433428,
|
"lastModified": 1762618334,
|
||||||
"narHash": "sha256-NA/FT2hVhKDftbHSwVnoRTFhes62+7dxZbxj5Gxvghs=",
|
"narHash": "sha256-wyT7Pl6tMFbFrs8Lk/TlEs81N6L+VSybPfiIgzU8lbQ=",
|
||||||
"owner": "ryantm",
|
"owner": "ryantm",
|
||||||
"repo": "agenix",
|
"repo": "agenix",
|
||||||
"rev": "9edb1787864c4f59ae5074ad498b6272b3ec308d",
|
"rev": "fcdea223397448d35d9b31f798479227e80183f6",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -84,11 +100,11 @@
|
|||||||
"systems": "systems_5"
|
"systems": "systems_5"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1767386128,
|
"lastModified": 1769353768,
|
||||||
"narHash": "sha256-BJDu7dIMauO2nYRSL4aI8wDNtEm2KOb7lDKP3hxdrpo=",
|
"narHash": "sha256-zI+7cbMI4wMIR57jMjDSEsVb3grapTnURDxxJPYFIW0=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "blueprint",
|
"repo": "blueprint",
|
||||||
"rev": "0ed984d51a3031065925ab08812a5434f40b93d4",
|
"rev": "c7da5c70ad1c9b60b6f5d4f674fbe205d48d8f6c",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -100,16 +116,16 @@
|
|||||||
"brew-src": {
|
"brew-src": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758543057,
|
"lastModified": 1763638478,
|
||||||
"narHash": "sha256-lw3V2jOGYphUFHYQ5oARcb6urlbNpUCLJy1qhsGdUmc=",
|
"narHash": "sha256-n/IMowE9S23ovmTkKX7KhxXC2Yq41EAVFR2FBIXPcT8=",
|
||||||
"owner": "Homebrew",
|
"owner": "Homebrew",
|
||||||
"repo": "brew",
|
"repo": "brew",
|
||||||
"rev": "5b236456eb93133c2bd0d60ef35ed63f1c0712f6",
|
"rev": "fbfdbaba008189499958a7aeb1e2c36ab10c067d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "Homebrew",
|
"owner": "Homebrew",
|
||||||
"ref": "4.6.12",
|
"ref": "5.0.3",
|
||||||
"repo": "brew",
|
"repo": "brew",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -143,16 +159,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1757432263,
|
"lastModified": 1767634391,
|
||||||
"narHash": "sha256-qHn+/0+IOz5cG68BZUwL9BV3EO/e9eNKCjH3+N7wMdI=",
|
"narHash": "sha256-owcSz2ICqTSvhBbhPP+1eWzi88e54rRZtfCNE5E/wwg=",
|
||||||
"owner": "LnL7",
|
"owner": "LnL7",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"rev": "1fef4404de4d1596aa5ab2bd68078370e1b9dcdb",
|
"rev": "08585aacc3d6d6c280a02da195fdbd4b9cf083c2",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "LnL7",
|
"owner": "LnL7",
|
||||||
"ref": "nix-darwin-25.05",
|
"ref": "nix-darwin-25.11",
|
||||||
"repo": "nix-darwin",
|
"repo": "nix-darwin",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -166,11 +182,11 @@
|
|||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1756719547,
|
"lastModified": 1766051518,
|
||||||
"narHash": "sha256-N9gBKUmjwRKPxAafXEk1EGadfk2qDZPBQp4vXWPHINQ=",
|
"narHash": "sha256-znKOwPXQnt3o7lDb3hdf19oDo0BLP4MfBOYiWkEHoik=",
|
||||||
"owner": "serokell",
|
"owner": "serokell",
|
||||||
"repo": "deploy-rs",
|
"repo": "deploy-rs",
|
||||||
"rev": "125ae9e3ecf62fb2c0fd4f2d894eb971f1ecaed2",
|
"rev": "d5eff7f948535b9c723d60cd8239f8f11ddc90fa",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -238,11 +254,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758287904,
|
"lastModified": 1768923567,
|
||||||
"narHash": "sha256-IGmaEf3Do8o5Cwp1kXBN1wQmZwQN3NLfq5t4nHtVtcU=",
|
"narHash": "sha256-GVJ0jKsyXLuBzRMXCDY6D5J8wVdwP1DuQmmvYL/Vw/Q=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "disko",
|
"repo": "disko",
|
||||||
"rev": "67ff9807dd148e704baadbd4fd783b54282ca627",
|
"rev": "00395d188e3594a1507f214a2f15d4ce5c07cb28",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -458,11 +474,11 @@
|
|||||||
"systems": "systems_6"
|
"systems": "systems_6"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1694529238,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-zsNZZGTGnMOf9YpHKJqMSsa0dXbfmxeoJ7xHlrt+xmY=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "ff7b65b44d01cf9ba6a71320833626af21126384",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -503,11 +519,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1754078208,
|
"lastModified": 1763982521,
|
||||||
"narHash": "sha256-YVoIFDCDpYuU3riaDEJ3xiGdPOtsx4sR5eTzHTytPV8=",
|
"narHash": "sha256-ur4QIAHwgFc0vXiaxn5No/FuZicxBr2p0gmT54xZkUQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "gomod2nix",
|
"repo": "gomod2nix",
|
||||||
"rev": "7f963246a71626c7fc70b431a315c4388a0c95cf",
|
"rev": "02e63a239d6eabd595db56852535992c898eba72",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -540,11 +556,11 @@
|
|||||||
},
|
},
|
||||||
"hardware": {
|
"hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758663926,
|
"lastModified": 1768736227,
|
||||||
"narHash": "sha256-6CFdj7Xs616t1W4jLDH7IohAAvl5Dyib3qEv/Uqw1rk=",
|
"narHash": "sha256-qgGq7CfrYKc3IBYQ7qp0Z/ZXndQVC5Bj0N8HW9mS2rM=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "170ff93c860b2a9868ed1e1102d4e52cb3d934e1",
|
"rev": "d447553bcbc6a178618d37e61648b19e744370df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -581,16 +597,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758463745,
|
"lastModified": 1768949235,
|
||||||
"narHash": "sha256-uhzsV0Q0I9j2y/rfweWeGif5AWe0MGrgZ/3TjpDYdGA=",
|
"narHash": "sha256-TtjKgXyg1lMfh374w5uxutd6Vx2P/hU81aEhTxrO2cg=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"rev": "3b955f5f0a942f9f60cdc9cacb7844335d0f21c3",
|
"rev": "75ed713570ca17427119e7e204ab3590cc3bf2a5",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"ref": "release-25.05",
|
"ref": "release-25.11",
|
||||||
"repo": "home-manager",
|
"repo": "home-manager",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
@@ -614,11 +630,11 @@
|
|||||||
"homebrew-cask": {
|
"homebrew-cask": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759110411,
|
"lastModified": 1769058882,
|
||||||
"narHash": "sha256-wsvLofMB/1bkjY6OQjjWU80+AbQiPzZSLZ3cjsYpOAs=",
|
"narHash": "sha256-GOSEf+DtzP/ORw+wrP1o9qZaz2XEvUOBC2j0cEEl2MY=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-cask",
|
"repo": "homebrew-cask",
|
||||||
"rev": "80f95de379d69edb696dd29106b2d8b077c98896",
|
"rev": "022be3ce1e808c0196c540471933238fc2bf0815",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -630,11 +646,11 @@
|
|||||||
"homebrew-core": {
|
"homebrew-core": {
|
||||||
"flake": false,
|
"flake": false,
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759116320,
|
"lastModified": 1769064658,
|
||||||
"narHash": "sha256-FGqC/WlIJnMkhV7l6XK6r5AqUYkwTHvHBCUjFe3DUUY=",
|
"narHash": "sha256-xT3S9geUhs4jmyuuQhsyGFfv86baCXqLID8Bvtzewpo=",
|
||||||
"owner": "homebrew",
|
"owner": "homebrew",
|
||||||
"repo": "homebrew-core",
|
"repo": "homebrew-core",
|
||||||
"rev": "0ccf924357d3eca3268d6dafb224ad9dc4f2398a",
|
"rev": "eaa460777befeb0b457587e04e05991ea90826be",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -717,11 +733,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762951919,
|
"lastModified": 1768986040,
|
||||||
"narHash": "sha256-ma/xMEGf4J6n/RdZFdxXBJUQhP53HVEPQOC6Dp2TrkQ=",
|
"narHash": "sha256-83npNk7w9yNJfSnpdZPNUjbhQwGVef3BWyBuIe6TJfk=",
|
||||||
"owner": "Jovian-Experiments",
|
"owner": "Jovian-Experiments",
|
||||||
"repo": "Jovian-NixOS",
|
"repo": "Jovian-NixOS",
|
||||||
"rev": "3d248f6e8f877218dd2573fef8925ac997889922",
|
"rev": "d75e3c96c9f935a6ccdd4a91209950289b2dc2fc",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -737,11 +753,11 @@
|
|||||||
"treefmt-nix": "treefmt-nix_2"
|
"treefmt-nix": "treefmt-nix_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768434130,
|
"lastModified": 1769482725,
|
||||||
"narHash": "sha256-4rBBs7spDuimvUcL3egp2Zh94Lk8pf00VsjkOs59h7E=",
|
"narHash": "sha256-Y4vH4PJIz4dt8SRJ5nm6yJCDzJRVEMdE5tP2TFIUfoQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "llm-agents.nix",
|
"repo": "llm-agents.nix",
|
||||||
"rev": "d0ed3ef68a04b5bd127fecd405baf803eea29c29",
|
"rev": "ae0667122f9a2336b23a4b4751997fe2f161fb37",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -846,11 +862,11 @@
|
|||||||
"brew-src": "brew-src"
|
"brew-src": "brew-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758598228,
|
"lastModified": 1764473698,
|
||||||
"narHash": "sha256-qr60maXGbZ4FX5tejPRI3nr0bnRTnZ3AbbbfO6/6jq4=",
|
"narHash": "sha256-C91gPgv6udN5WuIZWNehp8qdLqlrzX6iF/YyboOj6XI=",
|
||||||
"owner": "zhaofengli-wip",
|
"owner": "zhaofengli-wip",
|
||||||
"repo": "nix-homebrew",
|
"repo": "nix-homebrew",
|
||||||
"rev": "f36e5db56e117f7df701ab152d0d2036ea85218c",
|
"rev": "6a8ab60bfd66154feeaa1021fc3b32684814a62a",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -919,11 +935,11 @@
|
|||||||
},
|
},
|
||||||
"nixos-hardware": {
|
"nixos-hardware": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758663926,
|
"lastModified": 1768736227,
|
||||||
"narHash": "sha256-6CFdj7Xs616t1W4jLDH7IohAAvl5Dyib3qEv/Uqw1rk=",
|
"narHash": "sha256-qgGq7CfrYKc3IBYQ7qp0Z/ZXndQVC5Bj0N8HW9mS2rM=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixos-hardware",
|
"repo": "nixos-hardware",
|
||||||
"rev": "170ff93c860b2a9868ed1e1102d4e52cb3d934e1",
|
"rev": "d447553bcbc6a178618d37e61648b19e744370df",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1017,11 +1033,11 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_3": {
|
"nixpkgs_3": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768032153,
|
"lastModified": 1769421245,
|
||||||
"narHash": "sha256-6kD1MdY9fsE6FgSwdnx29hdH2UcBKs3/+JJleMShuJg=",
|
"narHash": "sha256-m5QLKjpdhbDrhyrUbEm5Haq3lqE5Z6xh2tab5vTHUTo=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "3146c6aa9995e7351a398e17470e15305e6e18ff",
|
"rev": "5b265bda51b42a2a85af0a543c3e57b778b01b7d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1049,27 +1065,27 @@
|
|||||||
},
|
},
|
||||||
"nixpkgs_5": {
|
"nixpkgs_5": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758791193,
|
"lastModified": 1768940263,
|
||||||
"narHash": "sha256-F8WmEwFoHsnix7rt290R0rFXNJiMbClMZyIC/e+HYf0=",
|
"narHash": "sha256-sJERJIYTKPFXkoz/gBaBtRKke82h4DkX3BBSsKbfbvI=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "25e53aa156d47bad5082ff7618f5feb1f5e02d01",
|
"rev": "3ceaaa8bc963ced4d830e06ea2d0863b6490ff03",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"ref": "nixos-25.05",
|
"ref": "nixos-25.11",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_6": {
|
"nixpkgs_6": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1758690382,
|
"lastModified": 1768886240,
|
||||||
"narHash": "sha256-NY3kSorgqE5LMm1LqNwGne3ZLMF2/ILgLpFr1fS4X3o=",
|
"narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "e643668fd71b949c53f8626614b21ff71a07379d",
|
"rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1085,11 +1101,11 @@
|
|||||||
"nixpkgs": "nixpkgs_6"
|
"nixpkgs": "nixpkgs_6"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759117007,
|
"lastModified": 1769056321,
|
||||||
"narHash": "sha256-DSnkPMhK2Eg0XLiyjEPVtIpdcmWmYsBMhVGCN1144SA=",
|
"narHash": "sha256-BR4ACqZEfFivkJutgeZeG8Sip/LlvmQgBbkT9eKZeIQ=",
|
||||||
"owner": "nix-community",
|
"owner": "nix-community",
|
||||||
"repo": "NUR",
|
"repo": "NUR",
|
||||||
"rev": "fccc09dffa659dc1410eceb33285831ba12bc7f6",
|
"rev": "6dd879dc2cb51262567d8b2b49b2d24f256fa343",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1105,11 +1121,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762711246,
|
"lastModified": 1759014010,
|
||||||
"narHash": "sha256-coOLG/Bp118d1T3DBIZUcW+AdiKsHz9uh6ZuiR30GBM=",
|
"narHash": "sha256-NMpUufnxiGDTs/4Nxj8t+n4wc4aSs02a4T5OORo0gBQ=",
|
||||||
"ref": "main",
|
"ref": "main",
|
||||||
"rev": "54287446e1a8a1bc40ad1b12061f053181e6d264",
|
"rev": "08c1dddf38c39d6f7c73a24f4d396f4c925185bf",
|
||||||
"revCount": 1614,
|
"revCount": 1602,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "ssh://gitea@git.sealight.xyz/aynish/kitaab"
|
"url": "ssh://gitea@git.sealight.xyz/aynish/kitaab"
|
||||||
},
|
},
|
||||||
@@ -1202,11 +1218,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759113356,
|
"lastModified": 1769050281,
|
||||||
"narHash": "sha256-xm4kEUcV2jk6u15aHazFP4YsMwhq+PczA+Ul/4FDKWI=",
|
"narHash": "sha256-1H8DN4UZgEUqPUA5ecHOufLZMscJ4IlcGaEftaPtpBY=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "be3b8843a2be2411500f6c052876119485e957a2",
|
"rev": "6deef0585c52d9e70f96b6121207e1496d4b0c49",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1336,6 +1352,7 @@
|
|||||||
},
|
},
|
||||||
"tangled": {
|
"tangled": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"actor-typeahead-src": "actor-typeahead-src",
|
||||||
"flake-compat": "flake-compat_4",
|
"flake-compat": "flake-compat_4",
|
||||||
"gomod2nix": "gomod2nix",
|
"gomod2nix": "gomod2nix",
|
||||||
"htmx-src": "htmx-src",
|
"htmx-src": "htmx-src",
|
||||||
@@ -1350,11 +1367,11 @@
|
|||||||
"sqlite-lib-src": "sqlite-lib-src"
|
"sqlite-lib-src": "sqlite-lib-src"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1759559279,
|
"lastModified": 1769064660,
|
||||||
"narHash": "sha256-gA0mh9Fx2uou2v75RMA6qUvWB3Z74Asc6pRjiojwaRo=",
|
"narHash": "sha256-2ccXZ51txbX1jAhW52Z6QuSFAgFqo3Gr1bqxD4jXNw0=",
|
||||||
"ref": "refs/heads/master",
|
"ref": "refs/heads/master",
|
||||||
"rev": "5ecd54b31547ac169a3b15d6034a67179f22aa33",
|
"rev": "2b94ee226637e13c106d7782ca852bd608530b51",
|
||||||
"revCount": 1486,
|
"revCount": 1865,
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://tangled.org/@tangled.org/core"
|
"url": "https://tangled.org/@tangled.org/core"
|
||||||
},
|
},
|
||||||
@@ -1431,11 +1448,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1768031762,
|
"lastModified": 1769353635,
|
||||||
"narHash": "sha256-b2gJDJfi+TbA7Hu2sKip+1mWqya0GJaWrrXQjpbOVTU=",
|
"narHash": "sha256-J0G1ACrUK29M0THPAsz429eZX07GmR9Bs/b0pB3N0dQ=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "0c445aa21b01fd1d4bb58927f7b268568af87b20",
|
"rev": "f46bb205f239b415309f58166f8df6919fa88377",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@@ -1446,11 +1463,11 @@
|
|||||||
},
|
},
|
||||||
"unstable": {
|
"unstable": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1762844143,
|
"lastModified": 1768886240,
|
||||||
"narHash": "sha256-SlybxLZ1/e4T2lb1czEtWVzDCVSTvk9WLwGhmxFmBxI=",
|
"narHash": "sha256-C2TjvwYZ2VDxYWeqvvJ5XPPp6U7H66zeJlRaErJKoEM=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "9da7f1cf7f8a6e2a7cb3001b048546c92a8258b4",
|
"rev": "80e4adbcf8992d3fd27ad4964fbb84907f9478b0",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
# Nixpkgs
|
# Nixpkgs
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05";
|
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11";
|
||||||
unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
unstable.url = "github:nixos/nixpkgs/nixos-unstable";
|
||||||
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
|
nixos-hardware.url = "github:NixOS/nixos-hardware/master";
|
||||||
|
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
# ngipkgs-local.url = "path:/home/anish/usr/ngipkgs";
|
# ngipkgs-local.url = "path:/home/anish/usr/ngipkgs";
|
||||||
|
|
||||||
# Home manager
|
# Home manager
|
||||||
home-manager.url = "github:nix-community/home-manager/release-25.05";
|
home-manager.url = "github:nix-community/home-manager/release-25.11";
|
||||||
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
home-manager.inputs.nixpkgs.follows = "nixpkgs";
|
||||||
hardware.url = "github:nixos/nixos-hardware";
|
hardware.url = "github:nixos/nixos-hardware";
|
||||||
|
|
||||||
@@ -44,7 +44,7 @@
|
|||||||
|
|
||||||
# Darwin
|
# Darwin
|
||||||
darwin = {
|
darwin = {
|
||||||
url = "github:LnL7/nix-darwin/nix-darwin-25.05";
|
url = "github:LnL7/nix-darwin/nix-darwin-25.11";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
nix-homebrew = {
|
nix-homebrew = {
|
||||||
@@ -160,13 +160,14 @@
|
|||||||
"SunVox"
|
"SunVox"
|
||||||
"renoise"
|
"renoise"
|
||||||
"bitwig-studio-unwrapped"
|
"bitwig-studio-unwrapped"
|
||||||
|
"via" # QMK keyboard configurator
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
overlays = [
|
overlays = [
|
||||||
rust-overlay.overlays.default
|
rust-overlay.overlays.default
|
||||||
tidalcycles.overlays.default
|
tidalcycles.overlays.default
|
||||||
agenix.overlays.default
|
agenix.overlays.default
|
||||||
nur.overlay
|
nur.overlays.default
|
||||||
# nix-matrix-appservices.overlay # nixpkgs has these packages and newer ones at that
|
# nix-matrix-appservices.overlay # nixpkgs has these packages and newer ones at that
|
||||||
unstableOverlay
|
unstableOverlay
|
||||||
vimwikiOverlay
|
vimwikiOverlay
|
||||||
@@ -217,7 +218,7 @@
|
|||||||
rust-overlay.overlays.default
|
rust-overlay.overlays.default
|
||||||
tidalcycles.overlays.default
|
tidalcycles.overlays.default
|
||||||
agenix.overlays.default
|
agenix.overlays.default
|
||||||
nur.overlay
|
nur.overlays.default
|
||||||
unstableOverlay
|
unstableOverlay
|
||||||
vimwikiOverlay
|
vimwikiOverlay
|
||||||
self.overlays.additions
|
self.overlays.additions
|
||||||
@@ -253,7 +254,7 @@
|
|||||||
rust-overlay.overlays.default
|
rust-overlay.overlays.default
|
||||||
tidalcycles.overlays.default
|
tidalcycles.overlays.default
|
||||||
agenix.overlays.default
|
agenix.overlays.default
|
||||||
nur.overlay
|
nur.overlays.default
|
||||||
unstableOverlay
|
unstableOverlay
|
||||||
vimwikiOverlay
|
vimwikiOverlay
|
||||||
self.overlays.additions
|
self.overlays.additions
|
||||||
@@ -325,7 +326,8 @@
|
|||||||
agenix.nixosModules.age
|
agenix.nixosModules.age
|
||||||
self.nixosModules.backup
|
self.nixosModules.backup
|
||||||
self.nixosModules.wireguard
|
self.nixosModules.wireguard
|
||||||
basant.nixosModule
|
# TODO: basant needs pyproject update for 25.11 - re-enable after fixing
|
||||||
|
# basant.nixosModule
|
||||||
# self.nixosModules.microbin
|
# self.nixosModules.microbin
|
||||||
disko.nixosModules.disko
|
disko.nixosModules.disko
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -2,15 +2,9 @@
|
|||||||
{
|
{
|
||||||
programs.beets = {
|
programs.beets = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.beets.override {
|
# In 25.11, beets plugins are enabled via beetsPackages or the default package
|
||||||
pluginOverrides = {
|
# The default beets package includes common plugins
|
||||||
fetchart.enable = true;
|
package = pkgs.beets;
|
||||||
embedart.enable = true;
|
|
||||||
lastgenre.enable = true;
|
|
||||||
duplicates.enable = true;
|
|
||||||
missing.enable = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
settings = {
|
settings = {
|
||||||
directory = "/tank/media/music";
|
directory = "/tank/media/music";
|
||||||
library = "/home/anish/.local/share/beets/library.db";
|
library = "/home/anish/.local/share/beets/library.db";
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
{ lib, pkgs, config, ... }:
|
|
||||||
{
|
{
|
||||||
home.packages = with pkgs; [
|
lib,
|
||||||
|
pkgs,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
home.packages =
|
||||||
|
with pkgs;
|
||||||
|
[
|
||||||
binutils
|
binutils
|
||||||
coreutils
|
coreutils
|
||||||
dnsutils
|
dnsutils
|
||||||
@@ -64,6 +71,7 @@
|
|||||||
taskwarrior-tui
|
taskwarrior-tui
|
||||||
# vimwiki-cli
|
# vimwiki-cli
|
||||||
zk
|
zk
|
||||||
|
radicle-node # rad CLI for interacting with Radicle repos
|
||||||
|
|
||||||
(pkgs.writeScriptBin "jq-repl" ''
|
(pkgs.writeScriptBin "jq-repl" ''
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
@@ -148,7 +156,8 @@
|
|||||||
|
|
||||||
disconnect_keyboard
|
disconnect_keyboard
|
||||||
'')
|
'')
|
||||||
] ++ lib.optionals pkgs.stdenv.isLinux [
|
]
|
||||||
|
++ lib.optionals pkgs.stdenv.isLinux [
|
||||||
# Linux-only packages
|
# Linux-only packages
|
||||||
iputils
|
iputils
|
||||||
strace
|
strace
|
||||||
@@ -255,7 +264,6 @@
|
|||||||
unzip = "aunpack";
|
unzip = "aunpack";
|
||||||
copy = if pkgs.stdenv.isDarwin then "pbcopy" else "xclip -selection clipboard";
|
copy = if pkgs.stdenv.isDarwin then "pbcopy" else "xclip -selection clipboard";
|
||||||
paste = if pkgs.stdenv.isDarwin then "pbpaste" else "xclip -selection clipboard -o";
|
paste = if pkgs.stdenv.isDarwin then "pbpaste" else "xclip -selection clipboard -o";
|
||||||
rm = "echo USE TRASH, FOOL: trash ";
|
|
||||||
trash = "trash-put";
|
trash = "trash-put";
|
||||||
make-secret = "< /dev/urandom \\tr -dc _A-Za-z0-9 | head -c \${1:-32};echo;";
|
make-secret = "< /dev/urandom \\tr -dc _A-Za-z0-9 | head -c \${1:-32};echo;";
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,5 @@ enable_audio_bell no
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Ctrl+V for paste
|
# Ctrl+V handled by neovim for insert mode paste (allows visual block mode in normal mode)
|
||||||
map ctrl+v paste_from_clipboard
|
|
||||||
mouse_map middle release ungrabbed paste_from_clipboard
|
mouse_map middle release ungrabbed paste_from_clipboard
|
||||||
|
|||||||
@@ -12,11 +12,14 @@
|
|||||||
unstable.git-spice
|
unstable.git-spice
|
||||||
];
|
];
|
||||||
|
|
||||||
|
# Delta (git diff pager) - moved to top-level in home-manager 25.11
|
||||||
|
programs.delta = {
|
||||||
|
enable = true;
|
||||||
|
enableGitIntegration = true;
|
||||||
|
};
|
||||||
|
|
||||||
programs.git = {
|
programs.git = {
|
||||||
enable = true;
|
enable = true;
|
||||||
userName = "Anish Lakhwara";
|
|
||||||
userEmail = "anish+git@lakhwara.com";
|
|
||||||
delta.enable = true;
|
|
||||||
signing = {
|
signing = {
|
||||||
signByDefault = if pkgs.stdenv.isLinux then false else true;
|
signByDefault = if pkgs.stdenv.isLinux then false else true;
|
||||||
key = if pkgs.stdenv.isLinux then "B8492C8FB53397B7" else "7FC5DF072EF7B716";
|
key = if pkgs.stdenv.isLinux then "B8492C8FB53397B7" else "7FC5DF072EF7B716";
|
||||||
@@ -60,14 +63,20 @@
|
|||||||
"node_modules/"
|
"node_modules/"
|
||||||
];
|
];
|
||||||
|
|
||||||
extraConfig = {
|
# 25.11: extraConfig, userName, userEmail, aliases moved under settings
|
||||||
|
settings = {
|
||||||
|
user = {
|
||||||
|
name = "Anish Lakhwara";
|
||||||
|
email = "anish+git@lakhwara.com";
|
||||||
|
};
|
||||||
pull.rebase = false;
|
pull.rebase = false;
|
||||||
push.autoSetupRemote = true;
|
push.autoSetupRemote = true;
|
||||||
init.defaultBranch = "main";
|
init.defaultBranch = "main";
|
||||||
"url \"git@github.com:\"" = { insteadOf = "https://github.com/"; };
|
"url \"git@github.com:\"" = {
|
||||||
|
insteadOf = "https://github.com/";
|
||||||
};
|
};
|
||||||
|
|
||||||
aliases = {
|
alias = {
|
||||||
a = "add -p";
|
a = "add -p";
|
||||||
co = "checkout";
|
co = "checkout";
|
||||||
cob = "checkout -b";
|
cob = "checkout -b";
|
||||||
@@ -91,12 +100,9 @@
|
|||||||
h1rd = "hard HEAD~1";
|
h1rd = "hard HEAD~1";
|
||||||
|
|
||||||
# logging
|
# logging
|
||||||
lg =
|
lg = "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
|
||||||
"log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit";
|
plog = "log --graph --pretty='format:%C(red)%d%C(reset) %C(yellow)%h%C(reset) %ar %C(green)%aN%C(reset) %s'";
|
||||||
plog =
|
tlog = "log --stat --since='1 Day Ago' --graph --pretty=oneline --abbrev-commit --date=relative";
|
||||||
"log --graph --pretty='format:%C(red)%d%C(reset) %C(yellow)%h%C(reset) %ar %C(green)%aN%C(reset) %s'";
|
|
||||||
tlog =
|
|
||||||
"log --stat --since='1 Day Ago' --graph --pretty=oneline --abbrev-commit --date=relative";
|
|
||||||
rank = "shortlog -sn --no-merges";
|
rank = "shortlog -sn --no-merges";
|
||||||
authors = "authors | sort | uniq -c | sort -n";
|
authors = "authors | sort | uniq -c | sort -n";
|
||||||
ls = "log --graph --abbrev-commit --decorate --color=always --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) - %C(dim red)%an%C(reset)%C(bold yellow)%d%C(reset)' --all";
|
ls = "log --graph --abbrev-commit --decorate --color=always --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) - %C(dim red)%an%C(reset)%C(bold yellow)%d%C(reset)' --all";
|
||||||
@@ -107,4 +113,5 @@
|
|||||||
blm = "blame -w -C -C -C";
|
blm = "blame -w -C -C -C";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ pkgs, lib, config, ... }:
|
{
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
config,
|
||||||
|
...
|
||||||
|
}:
|
||||||
let
|
let
|
||||||
customPlugins = {
|
customPlugins = {
|
||||||
vim-zettel = pkgs.vimUtils.buildVimPlugin {
|
vim-zettel = pkgs.vimUtils.buildVimPlugin {
|
||||||
@@ -116,7 +121,8 @@ let
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
my-python-packages = python-packages: with python-packages; [
|
my-python-packages =
|
||||||
|
python-packages: with python-packages; [
|
||||||
tasklib
|
tasklib
|
||||||
pynvim
|
pynvim
|
||||||
six
|
six
|
||||||
@@ -146,7 +152,8 @@ in
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
# Private mode plugin for concealing buffer content (out of store symlink for live editing)
|
# Private mode plugin for concealing buffer content (out of store symlink for live editing)
|
||||||
home.file.".config/nvim/lua/private-mode.lua".source = config.lib.file.mkOutOfStoreSymlink "${toString ./.}/private-mode.lua";
|
home.file.".config/nvim/lua/private-mode.lua".source =
|
||||||
|
config.lib.file.mkOutOfStoreSymlink "${toString ./.}/private-mode.lua";
|
||||||
|
|
||||||
#environment.systemPackages = with customPlugins; [ tidal ];
|
#environment.systemPackages = with customPlugins; [ tidal ];
|
||||||
programs.neovim = {
|
programs.neovim = {
|
||||||
@@ -1032,8 +1039,8 @@ in
|
|||||||
vim.keymap.set({'n', 't'}, '<M-k>', '<CMD>NavigatorUp<CR>')
|
vim.keymap.set({'n', 't'}, '<M-k>', '<CMD>NavigatorUp<CR>')
|
||||||
vim.keymap.set({'n', 't'}, '<M-l>', '<CMD>NavigatorRight<CR>')
|
vim.keymap.set({'n', 't'}, '<M-l>', '<CMD>NavigatorRight<CR>')
|
||||||
|
|
||||||
-- Paste from system clipboard in insert mode (handles tmux/kitty better)
|
-- Paste from system clipboard in insert mode (Ctrl+V in normal mode remains visual block)
|
||||||
-- vim.keymap.set('i', '<C-v>', '<C-r><C-p>+', {noremap = true, silent = true})
|
vim.keymap.set('i', '<C-v>', '<C-r><C-p>+', {noremap = true, silent = true})
|
||||||
|
|
||||||
-- Pane resizing with Alt+Shift+hjkl (to match tmux)
|
-- Pane resizing with Alt+Shift+hjkl (to match tmux)
|
||||||
vim.keymap.set('n', '<M-S-h>', '<Cmd>vertical resize -2<CR>', {silent = true})
|
vim.keymap.set('n', '<M-S-h>', '<Cmd>vertical resize -2<CR>', {silent = true})
|
||||||
@@ -1130,7 +1137,9 @@ in
|
|||||||
zk
|
zk
|
||||||
];
|
];
|
||||||
|
|
||||||
plugins = with pkgs.vimPlugins // customPlugins; [
|
plugins =
|
||||||
|
with pkgs.vimPlugins // customPlugins;
|
||||||
|
[
|
||||||
# ui
|
# ui
|
||||||
lualine-nvim
|
lualine-nvim
|
||||||
fzf-vim
|
fzf-vim
|
||||||
@@ -1148,7 +1157,24 @@ in
|
|||||||
telescope-nvim
|
telescope-nvim
|
||||||
plenary-nvim
|
plenary-nvim
|
||||||
nvim-navic
|
nvim-navic
|
||||||
(nvim-treesitter.withPlugins (p: [ p.nix p.clojure p.python p.fennel p.lua p.html p.css p.regex p.supercollider p.beancount p.markdown p.glsl p.yaml p.toml p.dockerfile p.json ]))
|
(nvim-treesitter.withPlugins (p: [
|
||||||
|
p.nix
|
||||||
|
p.clojure
|
||||||
|
p.python
|
||||||
|
p.fennel
|
||||||
|
p.lua
|
||||||
|
p.html
|
||||||
|
p.css
|
||||||
|
p.regex
|
||||||
|
p.supercollider
|
||||||
|
p.beancount
|
||||||
|
p.markdown
|
||||||
|
p.glsl
|
||||||
|
p.yaml
|
||||||
|
p.toml
|
||||||
|
p.dockerfile
|
||||||
|
p.json
|
||||||
|
]))
|
||||||
nvim-treesitter-context
|
nvim-treesitter-context
|
||||||
my-fterm
|
my-fterm
|
||||||
barbar-nvim
|
barbar-nvim
|
||||||
@@ -1222,14 +1248,18 @@ in
|
|||||||
# opencode integration
|
# opencode integration
|
||||||
opencode-nvim
|
opencode-nvim
|
||||||
# vim-processing
|
# vim-processing
|
||||||
] ++ lib.optionals pkgs.stdenv.isLinux [
|
]
|
||||||
|
++ lib.optionals pkgs.stdenv.isLinux [
|
||||||
# Linux-only plugins
|
# Linux-only plugins
|
||||||
vim-tidal # requires SuperCollider which is Linux-only
|
vim-tidal # requires SuperCollider which is Linux-only
|
||||||
];
|
];
|
||||||
withPython3 = true;
|
withPython3 = true;
|
||||||
extraPython3Packages = pkgs: with pkgs; [ tasklib six packaging ];
|
extraPython3Packages =
|
||||||
|
pkgs: with pkgs; [
|
||||||
|
tasklib
|
||||||
|
six
|
||||||
|
packaging
|
||||||
|
];
|
||||||
vimAlias = true;
|
vimAlias = true;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
---
|
|
||||||
description: Search through past OpenCode sessions to find relevant context, previous solutions, and historical decisions. Use this when you need to recall how something was done before or find related past work.
|
|
||||||
mode: subagent
|
|
||||||
model: anthropic/claude-haiku-4-5
|
|
||||||
temperature: 0.1
|
|
||||||
tools:
|
|
||||||
"*": false
|
|
||||||
search-history: true
|
|
||||||
skill: true
|
|
||||||
permission:
|
|
||||||
skill:
|
|
||||||
"session-search": allow
|
|
||||||
"*": deny
|
|
||||||
---
|
|
||||||
|
|
||||||
You are the Archivist, a specialized agent that searches through OpenCode session history to find relevant past conversations, code changes, and decisions.
|
|
||||||
|
|
||||||
You are running inside an AI coding system as a subagent. The main agent invokes you when it needs to find relevant context from previous sessions.
|
|
||||||
|
|
||||||
## Your Purpose
|
|
||||||
|
|
||||||
When invoked, you will:
|
|
||||||
1. Search through the local OpenCode session history
|
|
||||||
2. Find sessions and messages relevant to the query
|
|
||||||
3. Synthesize findings into a clear, actionable answer
|
|
||||||
|
|
||||||
## How to Search
|
|
||||||
|
|
||||||
First, load the `session-search` skill to understand the search strategies and storage structure.
|
|
||||||
|
|
||||||
Then use the `search-history` tool to find relevant sessions. You can:
|
|
||||||
- Search by keywords, code patterns, file names, or concepts
|
|
||||||
- Filter by project directory if the query is project-specific
|
|
||||||
- List recent sessions to get an overview
|
|
||||||
|
|
||||||
## Search Strategies
|
|
||||||
|
|
||||||
1. **Start broad**: Use general keywords related to the query
|
|
||||||
2. **Refine**: If too many results, add more specific terms or filter by directory
|
|
||||||
3. **Cross-reference**: Search for related terms (e.g., if searching for "auth", also try "login", "authentication")
|
|
||||||
4. **Check context**: Look at session titles and directories to understand the context
|
|
||||||
|
|
||||||
## Response Format
|
|
||||||
|
|
||||||
Your response should directly answer the question posed, using information from past sessions:
|
|
||||||
|
|
||||||
1. **Direct answer**: What was found that addresses the question
|
|
||||||
2. **Relevant sessions**: List session IDs where this was discussed (so user can resume if needed)
|
|
||||||
3. **Key details**: Important snippets or decisions from the history
|
|
||||||
|
|
||||||
Example response:
|
|
||||||
```
|
|
||||||
Based on past sessions, authentication was implemented using JWT tokens with a 24-hour expiry.
|
|
||||||
|
|
||||||
**Relevant sessions:**
|
|
||||||
- ses_abc123 - "Implementing user auth" (2024-01-15)
|
|
||||||
- ses_def456 - "Auth token refresh" (2024-01-20)
|
|
||||||
|
|
||||||
**Key details:**
|
|
||||||
- Tokens are stored in httpOnly cookies
|
|
||||||
- Refresh endpoint at /api/auth/refresh
|
|
||||||
- Used jose library for JWT handling
|
|
||||||
```
|
|
||||||
|
|
||||||
## Guidelines
|
|
||||||
|
|
||||||
- Be concise and direct - the main agent needs actionable information
|
|
||||||
- Include session IDs so the user can explore further if needed
|
|
||||||
- If nothing relevant is found, say so clearly
|
|
||||||
- Focus on answering the specific question, not providing exhaustive history
|
|
||||||
- Never fabricate information - only report what's actually in the history
|
|
||||||
|
|
||||||
IMPORTANT: Your final message is returned to the main agent. Make it comprehensive but focused on answering the original question.
|
|
||||||
+2
-1
@@ -1,6 +1,7 @@
|
|||||||
---
|
---
|
||||||
description: Adversarial code reviewer that critically examines code for flaws, bugs, and design issues. Invoke with @adversary to get a devil's advocate perspective on your code.
|
description: Adversarial code reviewer that critically examines code for flaws, bugs, and design issues. Invoke with @adversary to get a devil's advocate perspective on your code.
|
||||||
mode: subagent
|
mode: all
|
||||||
|
color: "#E0115F"
|
||||||
temperature: 0.2
|
temperature: 0.2
|
||||||
tools:
|
tools:
|
||||||
"*": false
|
"*": false
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
# Box Server Environment
|
||||||
|
|
||||||
|
You are running on `box`, a NAS server. The user is interacting remotely via mobile phone and cannot run local debugging tools, browser devtools, or inspect terminals directly.
|
||||||
|
|
||||||
|
## Remote Development Constraints
|
||||||
|
|
||||||
|
- User has no access to browser devtools or local terminal inspection
|
||||||
|
- Be verbose with output - include full error messages and logs
|
||||||
|
- Provide curl commands for testing endpoints
|
||||||
|
- Explain what's happening at each step since user can't easily inspect
|
||||||
|
|
||||||
|
## Running Dev Servers
|
||||||
|
|
||||||
|
When starting development servers or long-running processes:
|
||||||
|
|
||||||
|
1. **Use the `tmux` skill** - load it with `/skill tmux` for detailed instructions on spawning and managing background processes
|
||||||
|
|
||||||
|
2. **Port Selection**: Use ports in the range **7000-9000** (firewall is configured for this range)
|
||||||
|
|
||||||
|
3. **Bind Address**: Always bind to `0.0.0.0`, not `localhost`, so the server is accessible from other devices
|
||||||
|
|
||||||
|
Example commands:
|
||||||
|
- Vite: `npm run dev -- --host 0.0.0.0 --port 7500`
|
||||||
|
- Next.js: `npm run dev -- -H 0.0.0.0 -p 7500`
|
||||||
|
- Generic: `HOST=0.0.0.0 PORT=7500 npm start`
|
||||||
|
|
||||||
|
4. **Session Naming**: Name tmux sessions/windows after the project (e.g., `tmux new-window -n "helm-dev" -d`)
|
||||||
|
|
||||||
|
## Network Access
|
||||||
|
|
||||||
|
The user can access dev servers at:
|
||||||
|
- **Wireguard**: `http://10.0.69.4:<port>` (from any device on the VPN)
|
||||||
|
- **LAN**: `http://mossnet.lan:<port>` (from local network)
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
Since the user cannot inspect the browser or terminal directly:
|
||||||
|
- Always capture and report server logs using `tmux capture-pane`
|
||||||
|
- Include full stack traces in responses
|
||||||
|
- Suggest curl commands to test API endpoints
|
||||||
|
- When something fails, proactively check logs before asking the user
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
---
|
||||||
|
description: Socratic teaching mode that guides learning through questions rather than direct answers. Use when learning new codebases, concepts, or technologies.
|
||||||
|
mode: primary
|
||||||
|
color: "#22C55E"
|
||||||
|
temperature: 0.3
|
||||||
|
tools:
|
||||||
|
"*": false
|
||||||
|
read: true
|
||||||
|
glob: true
|
||||||
|
grep: true
|
||||||
|
webfetch: true
|
||||||
|
task: true
|
||||||
|
skill: true
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a Socratic programming tutor. Your purpose is to guide the user's understanding through thoughtful questions and exploration, not to provide direct answers or write code for them.
|
||||||
|
|
||||||
|
You are running inside an AI coding system as a primary agent mode. Users switch to you when they want to learn rather than just get things done.
|
||||||
|
|
||||||
|
## Core Principles
|
||||||
|
|
||||||
|
1. **Guide, don't answer**: Ask "How would you approach this?" instead of solving
|
||||||
|
2. **Socratic questioning**: Use "What do you notice?", "What happens if...?", "What evidence supports that?"
|
||||||
|
3. **Emphasize fundamentals**: Highlight underlying principles, not just syntax or implementation details
|
||||||
|
4. **Scaffold learning**: Provide progressively specific hints when the user is stuck, not solutions
|
||||||
|
|
||||||
|
## Teaching Strategies
|
||||||
|
|
||||||
|
### Starting a Topic
|
||||||
|
- Ask what the user already knows or expects
|
||||||
|
- Identify their mental model before exploring code
|
||||||
|
- Frame the exploration as a joint investigation
|
||||||
|
|
||||||
|
### During Exploration
|
||||||
|
- Point to relevant code/docs but ask the user to interpret what they see
|
||||||
|
- Use "What do you notice about...?" questions
|
||||||
|
- Ask the user to predict behavior before revealing it
|
||||||
|
- Connect new concepts to things they already understand
|
||||||
|
|
||||||
|
### When They're Stuck
|
||||||
|
- Offer a small hint, not the answer
|
||||||
|
- Break the problem into smaller questions
|
||||||
|
- Ask what specific part is confusing
|
||||||
|
- Suggest a simpler related example to reason through first
|
||||||
|
|
||||||
|
### Building Understanding
|
||||||
|
- Ask the user to explain their understanding back to you
|
||||||
|
- Have them trace through code mentally or on paper
|
||||||
|
- Encourage them to form hypotheses and test them
|
||||||
|
- Celebrate correct reasoning; gently redirect misconceptions
|
||||||
|
|
||||||
|
## Response Patterns
|
||||||
|
|
||||||
|
**Good**: "What do you think this function is responsible for, based on its name and parameters?"
|
||||||
|
|
||||||
|
**Good**: "You mentioned JWT tokens. Where would you expect to find token validation logic? Let's check your hypothesis."
|
||||||
|
|
||||||
|
**Good**: "That's a solid observation about the middleware. What implications does that have for how errors are handled?"
|
||||||
|
|
||||||
|
**Avoid**: "Here's how authentication works: [explanation]"
|
||||||
|
|
||||||
|
**Avoid**: "The answer is X because Y."
|
||||||
|
|
||||||
|
**Avoid**: Writing or suggesting code solutions directly.
|
||||||
|
|
||||||
|
## When Asked to "Just Tell Me"
|
||||||
|
|
||||||
|
Acknowledge their frustration, but gently redirect:
|
||||||
|
|
||||||
|
> I understand you want a quick answer, but working through this will help it stick. Let me give you a more specific hint: [focused question or smaller piece of the puzzle]
|
||||||
|
|
||||||
|
If they insist after multiple attempts, you may provide a partial explanation while still prompting them to fill in gaps.
|
||||||
|
|
||||||
|
## Tools Usage
|
||||||
|
|
||||||
|
You have read-only access to explore code and fetch documentation:
|
||||||
|
|
||||||
|
- **read/glob/grep**: Explore the local codebase to find relevant examples
|
||||||
|
- **webfetch**: Fetch documentation, tutorials, or reference material
|
||||||
|
- **task**: Delegate research to specialized agents (librarian, explore) when needed
|
||||||
|
- **skill**: Load skills for specialized knowledge
|
||||||
|
|
||||||
|
Use these to gather context and point the user toward relevant material - but always frame findings as prompts for their analysis, not answers.
|
||||||
|
|
||||||
|
## Providing Structure (When Asked)
|
||||||
|
|
||||||
|
You may create:
|
||||||
|
- **Learning paths**: Ordered list of concepts to study
|
||||||
|
- **Study guides**: Key questions to answer about a topic
|
||||||
|
- **Practice exercises**: Problems for the user to solve (without solutions)
|
||||||
|
- **Concept maps**: How ideas relate to each other
|
||||||
|
|
||||||
|
## Communication
|
||||||
|
|
||||||
|
Use Markdown for formatting. When including code blocks, always specify the language.
|
||||||
|
|
||||||
|
Be warm and encouraging, but not patronizing. You're a patient mentor who believes the user can figure things out with the right guidance.
|
||||||
|
|
||||||
|
Keep responses focused. A few good questions are better than a wall of text.
|
||||||
|
|
||||||
|
## Constraints
|
||||||
|
|
||||||
|
- You cannot edit files or run commands that modify state
|
||||||
|
- You must not provide direct code solutions
|
||||||
|
- If the user needs code written, suggest they switch to build mode
|
||||||
|
- Your role is to develop understanding, not to complete tasks for them
|
||||||
@@ -2,9 +2,14 @@
|
|||||||
pkgs,
|
pkgs,
|
||||||
lib,
|
lib,
|
||||||
inputs,
|
inputs,
|
||||||
|
osConfig ? { },
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
# Check if we're running on box (for box-specific config)
|
||||||
|
isBox = (osConfig.networking.hostName or "") == "box";
|
||||||
|
in
|
||||||
let
|
let
|
||||||
# Paths to agenix-decrypted secrets (same on Darwin and NixOS)
|
# Paths to agenix-decrypted secrets (same on Darwin and NixOS)
|
||||||
githubToken = "/run/agenix/github-token";
|
githubToken = "/run/agenix/github-token";
|
||||||
@@ -29,10 +34,6 @@ in
|
|||||||
autoupdate = false;
|
autoupdate = false;
|
||||||
permission = {
|
permission = {
|
||||||
external_directory = "allow";
|
external_directory = "allow";
|
||||||
# Restrict session-search skill to archivist only
|
|
||||||
skill = {
|
|
||||||
"session-search" = "deny";
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
provider = {
|
provider = {
|
||||||
anthropic = {
|
anthropic = {
|
||||||
@@ -60,12 +61,13 @@ in
|
|||||||
#plugin = ["@plannotator/opencode@latest"];
|
#plugin = ["@plannotator/opencode@latest"];
|
||||||
};
|
};
|
||||||
|
|
||||||
"opencode/themes/ayu-mirage.json".source = ./themes/ayu-mirage.json;
|
"opencode/themes".source = ./themes;
|
||||||
"opencode/agent/librarian.md".source = ./agent/librarian.md;
|
"opencode/agents".source = ./agents;
|
||||||
"opencode/agent/adversary.md".source = ./agent/adversary.md;
|
"opencode/commands".source = ./commands;
|
||||||
"opencode/agent/archivist.md".source = ./agent/archivist.md;
|
"opencode/skills".source = ./skills;
|
||||||
"opencode/command/cleanup.md".source = ./command/cleanup.md;
|
};
|
||||||
"opencode/tool/search-history.ts".source = ./tool/search-history.ts;
|
|
||||||
"opencode/skill/session-search/SKILL.md".source = ./skill/session-search/SKILL.md;
|
home.file = lib.mkIf isBox {
|
||||||
|
"usr/.opencode/agents.md".source = ./agents/box.md;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
---
|
|
||||||
name: session-search
|
|
||||||
description: Advanced strategies for searching OpenCode session history. Restricted to the archivist agent.
|
|
||||||
---
|
|
||||||
|
|
||||||
# Session Search Skill
|
|
||||||
|
|
||||||
This skill provides advanced strategies for searching through OpenCode's session history storage.
|
|
||||||
|
|
||||||
## Storage Structure
|
|
||||||
|
|
||||||
OpenCode stores data in `~/.local/share/opencode/storage/`:
|
|
||||||
|
|
||||||
```
|
|
||||||
storage/
|
|
||||||
├── session/ # Session metadata by project
|
|
||||||
│ └── {projectHash}/
|
|
||||||
│ └── ses_*.json # Session info (title, directory, timestamps)
|
|
||||||
├── message/ # Messages organized by session
|
|
||||||
│ └── ses_*/
|
|
||||||
│ └── msg_*.json # Message metadata (role, agent, model)
|
|
||||||
├── part/ # Actual message content
|
|
||||||
│ └── msg_*/
|
|
||||||
│ └── prt_*.json # Content parts (text, tool calls)
|
|
||||||
└── project/ # Project metadata
|
|
||||||
└── {hash}.json # Worktree path, timestamps
|
|
||||||
```
|
|
||||||
|
|
||||||
## Search Tool Usage
|
|
||||||
|
|
||||||
The `search-history` tool accepts:
|
|
||||||
- `query`: Text pattern to search for (searches message content)
|
|
||||||
- `directory`: Optional filter by project path (partial match)
|
|
||||||
- `limit`: Max results (default 30)
|
|
||||||
|
|
||||||
### Examples
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Find all sessions mentioning "authentication"
|
|
||||||
search-history({ query: "authentication" })
|
|
||||||
|
|
||||||
// Find sessions in a specific project
|
|
||||||
search-history({ query: "database", directory: "myproject" })
|
|
||||||
|
|
||||||
// List recent sessions (empty query)
|
|
||||||
search-history({ query: "", limit: 20 })
|
|
||||||
```
|
|
||||||
|
|
||||||
## Search Strategies
|
|
||||||
|
|
||||||
### 1. Keyword Expansion
|
|
||||||
Don't just search for the exact term. Try synonyms and related concepts:
|
|
||||||
- "auth" → also try "login", "authentication", "jwt", "token"
|
|
||||||
- "database" → also try "postgres", "sqlite", "db", "migration"
|
|
||||||
- "api" → also try "endpoint", "route", "handler"
|
|
||||||
|
|
||||||
### 2. Code Pattern Search
|
|
||||||
Search for code-specific patterns:
|
|
||||||
- Function names: `handleAuth`, `validateToken`
|
|
||||||
- File paths: `src/auth`, `lib/database`
|
|
||||||
- Import statements: `import.*prisma`
|
|
||||||
- Error messages: specific error text
|
|
||||||
|
|
||||||
### 3. Tool Usage Search
|
|
||||||
Find when specific tools were used:
|
|
||||||
- Edit operations: search for file paths that were edited
|
|
||||||
- Bash commands: search for command names
|
|
||||||
- Specific operations: "git push", "npm install"
|
|
||||||
|
|
||||||
### 4. Directory Filtering
|
|
||||||
Use the `directory` parameter to scope searches:
|
|
||||||
- Filter by project name: `directory: "myapp"`
|
|
||||||
- Filter by path segment: `directory: "usr/projects"`
|
|
||||||
|
|
||||||
### 5. Iterative Refinement
|
|
||||||
1. Start with broad search
|
|
||||||
2. If too many results, add specificity
|
|
||||||
3. If no results, broaden or try alternative terms
|
|
||||||
4. Cross-reference multiple searches
|
|
||||||
|
|
||||||
## Understanding Results
|
|
||||||
|
|
||||||
### Session Info
|
|
||||||
- `id`: Unique session identifier (can be used to reference)
|
|
||||||
- `title`: Auto-generated session title
|
|
||||||
- `directory`: Project worktree path
|
|
||||||
- `updated`: Last activity timestamp
|
|
||||||
|
|
||||||
### Content Matches
|
|
||||||
- `sessionID`: Which session contains this match
|
|
||||||
- `snippet`: Context around the match (±100 chars)
|
|
||||||
- `role`: user/assistant/tool
|
|
||||||
|
|
||||||
## Tips
|
|
||||||
|
|
||||||
1. **Recent vs Relevant**: The tool returns recent sessions first. Older but more relevant sessions may be further in results.
|
|
||||||
|
|
||||||
2. **Title Search**: Session titles are auto-generated from the conversation and can be good search targets.
|
|
||||||
|
|
||||||
3. **Multiple Searches**: Don't hesitate to run multiple searches with different terms to build a complete picture.
|
|
||||||
|
|
||||||
4. **Context Matters**: The snippet provides limited context. Session titles and directories help understand the broader context.
|
|
||||||
|
|
||||||
5. **No Results**: If no results found, the pattern may be too specific. Try shorter or more general terms.
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
---
|
||||||
|
name: tmux
|
||||||
|
description: Instructions for using tmux to spawn multiple processes, inspect them, and capture their output. Useful for running servers or long-running tasks in the background.
|
||||||
|
allowed-tools:
|
||||||
|
- Bash
|
||||||
|
---
|
||||||
|
|
||||||
|
# Tmux Skill
|
||||||
|
|
||||||
|
This skill empowers you to manage multiple concurrent processes (like servers, watchers, or long builds) using `tmux` directly from the `Bash` tool.
|
||||||
|
|
||||||
|
Since you are likely already running inside a tmux session, you can spawn new windows or panes to handle these tasks without blocking your main communication channel.
|
||||||
|
|
||||||
|
## 1. Verify Environment & Check Status
|
||||||
|
|
||||||
|
First, verify you are running inside tmux:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo $TMUX
|
||||||
|
```
|
||||||
|
|
||||||
|
If this returns empty, you are not running inside tmux and these commands will not work as expected.
|
||||||
|
|
||||||
|
Once verified, check your current windows:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux list-windows
|
||||||
|
```
|
||||||
|
|
||||||
|
## 2. Spawn a Background Process
|
||||||
|
|
||||||
|
To run a command (e.g., a dev server) in a way that persists and can be inspected:
|
||||||
|
|
||||||
|
1. **Create a new detached window** with a specific name. This keeps it isolated and easy to reference.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux new-window -n "server-log" -d
|
||||||
|
```
|
||||||
|
|
||||||
|
_(Replace "server-log" with a relevant name for your task)_
|
||||||
|
|
||||||
|
2. **Send the command** to that window.
|
||||||
|
```bash
|
||||||
|
tmux send-keys -t "server-log" "npm start" C-m
|
||||||
|
```
|
||||||
|
_(`C-m` simulates the Enter key)_
|
||||||
|
|
||||||
|
## 3. Inspect Output (Read Logs)
|
||||||
|
|
||||||
|
You can read the output of that pane at any time without switching your context.
|
||||||
|
|
||||||
|
**Get the current visible screen:**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux capture-pane -p -t "server-log"
|
||||||
|
```
|
||||||
|
|
||||||
|
**Get the entire history (scrollback):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux capture-pane -p -S - -t "server-log"
|
||||||
|
```
|
||||||
|
|
||||||
|
_Use this if the output might have scrolled off the screen._
|
||||||
|
|
||||||
|
## 4. Interact with the Process
|
||||||
|
|
||||||
|
If you need to stop or restart the process:
|
||||||
|
|
||||||
|
**Send Ctrl+C (Interrupt):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux send-keys -t "server-log" C-c
|
||||||
|
```
|
||||||
|
|
||||||
|
**Kill the window (Clean up):**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux kill-window -t "server-log"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 5. Advanced: Chaining Commands
|
||||||
|
|
||||||
|
You can chain multiple tmux commands in a single invocation using `';'` (note the quotes to avoid interpretation by the shell). This is faster and cleaner than running multiple `tmux` commands.
|
||||||
|
|
||||||
|
Example: Create window and start process in one go:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tmux new-window -n "server-log" -d ';' send-keys -t "server-log" "npm start" C-m
|
||||||
|
```
|
||||||
|
|
||||||
|
## Summary of Pattern
|
||||||
|
|
||||||
|
1. `tmux new-window -n "ID" -d`
|
||||||
|
2. `tmux send-keys -t "ID" "CMD" C-m`
|
||||||
|
3. `tmux capture-pane -p -t "ID"`
|
||||||
|
|
||||||
@@ -1,275 +0,0 @@
|
|||||||
import { tool } from "@opencode-ai/plugin"
|
|
||||||
import { $ } from "bun"
|
|
||||||
import { readdir, readFile } from "fs/promises"
|
|
||||||
import { join } from "path"
|
|
||||||
import { homedir } from "os"
|
|
||||||
|
|
||||||
const STORAGE_PATH = join(homedir(), ".local/share/opencode/storage")
|
|
||||||
|
|
||||||
interface SessionInfo {
|
|
||||||
id: string
|
|
||||||
title: string
|
|
||||||
directory: string
|
|
||||||
projectID: string
|
|
||||||
created: number
|
|
||||||
updated: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface MessageMatch {
|
|
||||||
sessionID: string
|
|
||||||
messageID: string
|
|
||||||
snippet: string
|
|
||||||
role: string
|
|
||||||
timestamp?: number
|
|
||||||
}
|
|
||||||
|
|
||||||
interface SearchResult {
|
|
||||||
sessions: SessionInfo[]
|
|
||||||
matches: MessageMatch[]
|
|
||||||
totalMatches: number
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getSessionInfo(sessionID: string): Promise<SessionInfo | null> {
|
|
||||||
try {
|
|
||||||
// Sessions are stored in directories named by project hash
|
|
||||||
const sessionDirs = await readdir(join(STORAGE_PATH, "session"))
|
|
||||||
for (const dir of sessionDirs) {
|
|
||||||
const sessionPath = join(STORAGE_PATH, "session", dir)
|
|
||||||
const files = await readdir(sessionPath).catch(() => [])
|
|
||||||
for (const file of files) {
|
|
||||||
if (file.startsWith(sessionID) || file.includes(sessionID)) {
|
|
||||||
const content = await readFile(join(sessionPath, file), "utf-8")
|
|
||||||
const data = JSON.parse(content)
|
|
||||||
return {
|
|
||||||
id: data.id,
|
|
||||||
title: data.title || "Untitled",
|
|
||||||
directory: data.directory || "",
|
|
||||||
projectID: data.projectID || "",
|
|
||||||
created: data.time?.created || 0,
|
|
||||||
updated: data.time?.updated || 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Fall back to searching message directories
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
async function searchWithRipgrep(
|
|
||||||
pattern: string,
|
|
||||||
directory?: string,
|
|
||||||
limit: number = 50
|
|
||||||
): Promise<SearchResult> {
|
|
||||||
const matches: MessageMatch[] = []
|
|
||||||
const sessionIDs = new Set<string>()
|
|
||||||
|
|
||||||
// Search through part storage (contains actual message content)
|
|
||||||
const partPath = join(STORAGE_PATH, "part")
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Use ripgrep to search JSON files, extracting context around matches
|
|
||||||
const rgResult = await $`rg -i -l ${pattern} ${partPath} --type json 2>/dev/null || true`.text()
|
|
||||||
const matchingFiles = rgResult.trim().split("\n").filter(Boolean)
|
|
||||||
|
|
||||||
for (const file of matchingFiles.slice(0, limit * 2)) {
|
|
||||||
try {
|
|
||||||
const content = await readFile(file, "utf-8")
|
|
||||||
const data = JSON.parse(content)
|
|
||||||
|
|
||||||
// Filter by directory if specified
|
|
||||||
if (directory) {
|
|
||||||
const sessionInfo = await getSessionInfo(data.sessionID)
|
|
||||||
if (sessionInfo && !sessionInfo.directory.includes(directory)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Extract snippet around the match
|
|
||||||
const text = data.text || data.content || JSON.stringify(data)
|
|
||||||
const lowerText = text.toLowerCase()
|
|
||||||
const lowerPattern = pattern.toLowerCase()
|
|
||||||
const matchIndex = lowerText.indexOf(lowerPattern)
|
|
||||||
|
|
||||||
if (matchIndex !== -1) {
|
|
||||||
const start = Math.max(0, matchIndex - 100)
|
|
||||||
const end = Math.min(text.length, matchIndex + pattern.length + 100)
|
|
||||||
const snippet = (start > 0 ? "..." : "") +
|
|
||||||
text.slice(start, end) +
|
|
||||||
(end < text.length ? "..." : "")
|
|
||||||
|
|
||||||
matches.push({
|
|
||||||
sessionID: data.sessionID,
|
|
||||||
messageID: data.messageID,
|
|
||||||
snippet: snippet.replace(/\n/g, " ").trim(),
|
|
||||||
role: data.role || "unknown",
|
|
||||||
timestamp: data.time?.created,
|
|
||||||
})
|
|
||||||
|
|
||||||
sessionIDs.add(data.sessionID)
|
|
||||||
|
|
||||||
if (matches.length >= limit) break
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Skip files that can't be parsed
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
// ripgrep not found or error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also search message metadata for titles
|
|
||||||
const messagePath = join(STORAGE_PATH, "message")
|
|
||||||
try {
|
|
||||||
const rgResult = await $`rg -i -l ${pattern} ${messagePath} --type json 2>/dev/null || true`.text()
|
|
||||||
const matchingFiles = rgResult.trim().split("\n").filter(Boolean)
|
|
||||||
|
|
||||||
for (const file of matchingFiles.slice(0, 20)) {
|
|
||||||
try {
|
|
||||||
const content = await readFile(file, "utf-8")
|
|
||||||
const data = JSON.parse(content)
|
|
||||||
if (data.sessionID) {
|
|
||||||
sessionIDs.add(data.sessionID)
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Skip
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Ignore errors
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get session info for all matched sessions
|
|
||||||
const sessions: SessionInfo[] = []
|
|
||||||
for (const sessionID of sessionIDs) {
|
|
||||||
const info = await getSessionInfo(sessionID)
|
|
||||||
if (info) {
|
|
||||||
// Apply directory filter for sessions too
|
|
||||||
if (!directory || info.directory.includes(directory)) {
|
|
||||||
sessions.push(info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sort sessions by most recent
|
|
||||||
sessions.sort((a, b) => b.updated - a.updated)
|
|
||||||
|
|
||||||
return {
|
|
||||||
sessions: sessions.slice(0, 20),
|
|
||||||
matches: matches.slice(0, limit),
|
|
||||||
totalMatches: matches.length,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function listRecentSessions(
|
|
||||||
directory?: string,
|
|
||||||
limit: number = 20
|
|
||||||
): Promise<SessionInfo[]> {
|
|
||||||
const sessions: SessionInfo[] = []
|
|
||||||
|
|
||||||
try {
|
|
||||||
const sessionDirs = await readdir(join(STORAGE_PATH, "session"))
|
|
||||||
|
|
||||||
for (const dir of sessionDirs) {
|
|
||||||
const sessionPath = join(STORAGE_PATH, "session", dir)
|
|
||||||
const files = await readdir(sessionPath).catch(() => [])
|
|
||||||
|
|
||||||
for (const file of files) {
|
|
||||||
if (!file.endsWith(".json")) continue
|
|
||||||
try {
|
|
||||||
const content = await readFile(join(sessionPath, file), "utf-8")
|
|
||||||
const data = JSON.parse(content)
|
|
||||||
|
|
||||||
if (directory && !data.directory?.includes(directory)) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
sessions.push({
|
|
||||||
id: data.id,
|
|
||||||
title: data.title || "Untitled",
|
|
||||||
directory: data.directory || "",
|
|
||||||
projectID: data.projectID || "",
|
|
||||||
created: data.time?.created || 0,
|
|
||||||
updated: data.time?.updated || 0,
|
|
||||||
})
|
|
||||||
} catch {
|
|
||||||
// Skip invalid files
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
// Storage doesn't exist
|
|
||||||
}
|
|
||||||
|
|
||||||
sessions.sort((a, b) => b.updated - a.updated)
|
|
||||||
return sessions.slice(0, limit)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default tool({
|
|
||||||
description:
|
|
||||||
"Search through OpenCode session history to find past conversations, code changes, and decisions. Use this to find relevant context from previous sessions.",
|
|
||||||
args: {
|
|
||||||
query: tool.schema
|
|
||||||
.string()
|
|
||||||
.describe(
|
|
||||||
"Search pattern to find in session history. Searches message content, titles, and tool outputs."
|
|
||||||
),
|
|
||||||
directory: tool.schema
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe(
|
|
||||||
"Optional: Filter results to sessions from a specific project directory path (partial match)"
|
|
||||||
),
|
|
||||||
limit: tool.schema
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Maximum number of matches to return (default: 30)"),
|
|
||||||
},
|
|
||||||
async execute(args) {
|
|
||||||
const limit = args.limit || 30
|
|
||||||
|
|
||||||
if (!args.query || args.query.trim() === "") {
|
|
||||||
// List recent sessions if no query
|
|
||||||
const sessions = await listRecentSessions(args.directory, limit)
|
|
||||||
return JSON.stringify(
|
|
||||||
{
|
|
||||||
type: "recent_sessions",
|
|
||||||
sessions,
|
|
||||||
message: `Found ${sessions.length} recent sessions${args.directory ? ` in ${args.directory}` : ""}`,
|
|
||||||
},
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const results = await searchWithRipgrep(args.query, args.directory, limit)
|
|
||||||
|
|
||||||
// Format output for the agent
|
|
||||||
let output = `## Search Results for "${args.query}"\n\n`
|
|
||||||
|
|
||||||
if (results.sessions.length > 0) {
|
|
||||||
output += `### Relevant Sessions (${results.sessions.length})\n\n`
|
|
||||||
for (const session of results.sessions) {
|
|
||||||
const date = new Date(session.updated).toLocaleDateString()
|
|
||||||
output += `- **${session.title}** (${session.id})\n`
|
|
||||||
output += ` - Directory: \`${session.directory}\`\n`
|
|
||||||
output += ` - Last updated: ${date}\n\n`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.matches.length > 0) {
|
|
||||||
output += `### Content Matches (${results.totalMatches})\n\n`
|
|
||||||
for (const match of results.matches.slice(0, 15)) {
|
|
||||||
output += `**Session:** ${match.sessionID}\n`
|
|
||||||
output += `> ${match.snippet}\n\n`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (results.sessions.length === 0 && results.matches.length === 0) {
|
|
||||||
output += `No matches found for "${args.query}"${args.directory ? ` in ${args.directory}` : ""}\n`
|
|
||||||
}
|
|
||||||
|
|
||||||
return output
|
|
||||||
},
|
|
||||||
})
|
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
../profiles/monitoring
|
../profiles/monitoring
|
||||||
../profiles/nfs
|
../profiles/nfs
|
||||||
../profiles/gonic
|
../profiles/gonic
|
||||||
../profiles/headphones
|
# ../profiles/headphones
|
||||||
../profiles/radicale
|
../profiles/radicale
|
||||||
# ../profiles/seafile # waiting for https://github.com/NixOS/nixpkgs/pull/249523 to be merged
|
# ../profiles/seafile # waiting for https://github.com/NixOS/nixpkgs/pull/249523 to be merged
|
||||||
../profiles/syncthing
|
../profiles/syncthing
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
../profiles/finance
|
../profiles/finance
|
||||||
../profiles/sync/website
|
../profiles/sync/website
|
||||||
../profiles/sync/music
|
../profiles/sync/music
|
||||||
|
../profiles/sync/tv
|
||||||
# ../profiles/grasp # private repo - disabled
|
# ../profiles/grasp # private repo - disabled
|
||||||
# ../profiles/archivebox # requires insecure django - fix in flake.nix permittedInsecurePackages
|
# ../profiles/archivebox # requires insecure django - fix in flake.nix permittedInsecurePackages
|
||||||
../profiles/woodpecker-agent
|
../profiles/woodpecker-agent
|
||||||
@@ -31,6 +32,7 @@
|
|||||||
../profiles/transmission
|
../profiles/transmission
|
||||||
../profiles/raven
|
../profiles/raven
|
||||||
../profiles/radicle-node
|
../profiles/radicle-node
|
||||||
|
../profiles/opencode-server
|
||||||
# ../profiles/postgres_upgrade_script # one-time use
|
# ../profiles/postgres_upgrade_script # one-time use
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
../profiles/mimetypes
|
../profiles/mimetypes
|
||||||
../profiles/syncthing
|
../profiles/syncthing
|
||||||
../profiles/mossnet-hosts
|
../profiles/mossnet-hosts
|
||||||
|
../profiles/opencode-server
|
||||||
# ../profiles/fly-wg
|
# ../profiles/fly-wg
|
||||||
# ../profiles/kuberenetes
|
# ../profiles/kuberenetes
|
||||||
# ../profiles/mount-mossnet
|
# ../profiles/mount-mossnet
|
||||||
|
|||||||
@@ -11,14 +11,15 @@
|
|||||||
../profiles/core
|
../profiles/core
|
||||||
../profiles/server
|
../profiles/server
|
||||||
# ../profiles/metrics
|
# ../profiles/metrics
|
||||||
# ../profiles/gitea # Replaced by radicle
|
../profiles/gitea
|
||||||
../profiles/radicle-seed
|
# ../profiles/radicle-seed
|
||||||
# ../profiles/woodpecker-server
|
# ../profiles/woodpecker-server
|
||||||
../profiles/rss-bridge
|
../profiles/rss-bridge
|
||||||
# ../profiles/mount-mossnet
|
# ../profiles/mount-mossnet
|
||||||
../profiles/freshrss
|
# ../profiles/freshrss
|
||||||
../profiles/microbin
|
# ../profiles/microbin
|
||||||
../profiles/site
|
# TODO: re-enable after basant pyproject fix for 25.11
|
||||||
|
# ../profiles/site
|
||||||
|
|
||||||
# ../profiles/postgres_upgrade_script
|
# ../profiles/postgres_upgrade_script
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
package = pkgs.unstable.immich;
|
package = pkgs.unstable.immich;
|
||||||
database = {
|
database = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
enableVectorChord = true; # 25.11: Use VectorChord instead of pgvecto-rs
|
||||||
};
|
};
|
||||||
host = "0.0.0.0";
|
host = "0.0.0.0";
|
||||||
port = 8567;
|
port = 8567;
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
{ config, lib, pkgs, ... }:
|
{
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
{
|
{
|
||||||
services.jackett = {
|
services.jackett = {
|
||||||
enable = true;
|
enable = true;
|
||||||
@@ -17,9 +22,9 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
services.lidarr = {
|
services.lidarr = {
|
||||||
enable = true;
|
enable = true;
|
||||||
user = "headphones";
|
|
||||||
group = "audio";
|
group = "audio";
|
||||||
};
|
};
|
||||||
services.nginx.virtualHosts."lidarr.mossnet.lan" = {
|
services.nginx.virtualHosts."lidarr.mossnet.lan" = {
|
||||||
@@ -32,4 +37,35 @@
|
|||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
services.sonarr = {
|
||||||
|
enable = true;
|
||||||
|
group = "video";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."sonarr.mossnet.lan" = {
|
||||||
|
enableACME = false;
|
||||||
|
forceSSL = false;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_pass http://127.0.0.1:8989/;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
services.jellyseerr = {
|
||||||
|
enable = true;
|
||||||
|
# group = "video";
|
||||||
|
};
|
||||||
|
services.nginx.virtualHosts."seerr.mossnet.lan" = {
|
||||||
|
enableACME = false;
|
||||||
|
forceSSL = false;
|
||||||
|
|
||||||
|
locations."/" = {
|
||||||
|
extraConfig = ''
|
||||||
|
proxy_pass http://127.0.0.1:5055/;
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,13 +6,13 @@
|
|||||||
}:
|
}:
|
||||||
{
|
{
|
||||||
# Enable Hardware Acceleration for transcoding
|
# Enable Hardware Acceleration for transcoding
|
||||||
# Note: vaapiIntel override with enableHybridCodec should be in flake.nix overlay if needed
|
# Note: intel-vaapi-driver override with enableHybridCodec should be in flake.nix overlay if needed
|
||||||
hardware.graphics = {
|
hardware.graphics = {
|
||||||
enable = true;
|
enable = true;
|
||||||
extraPackages = with pkgs; [
|
extraPackages = with pkgs; [
|
||||||
intel-media-driver
|
intel-media-driver
|
||||||
vaapiIntel
|
intel-vaapi-driver # renamed from vaapiIntel in 25.11
|
||||||
vaapiVdpau
|
libva-vdpau-driver # renamed from vaapiVdpau in 25.11
|
||||||
libvdpau-va-gl
|
libvdpau-va-gl
|
||||||
intel-compute-runtime # OpenCL filter support (hardware tonemapping and subtitle burn-in)
|
intel-compute-runtime # OpenCL filter support (hardware tonemapping and subtitle burn-in)
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
{ pkgs, ... }:
|
{ pkgs, ... }:
|
||||||
{
|
{
|
||||||
environment.systemPackages = [ pkgs.matrix-synapse-tools.rust-synapse-compress-state ];
|
environment.systemPackages = [ pkgs.rust-synapse-compress-state ];
|
||||||
systemd.services.compress-matrix-state = {
|
systemd.services.compress-matrix-state = {
|
||||||
serviceConfig.Type = "oneshot";
|
serviceConfig.Type = "oneshot";
|
||||||
path = [
|
path = [
|
||||||
pkgs.matrix-synapse-tools.rust-synapse-compress-state
|
pkgs.rust-synapse-compress-state
|
||||||
];
|
];
|
||||||
script = ''
|
script = ''
|
||||||
synapse_auto_compressor -p "host=/run/postgresql port=5432 user=matrix-synapse dbname=matrix-synapse" -n 2000000 -c 10000
|
synapse_auto_compressor -p "host=/run/postgresql port=5432 user=matrix-synapse dbname=matrix-synapse" -n 2000000 -c 10000
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
{ self, config, lib, pkgs, ... }:
|
{
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
./mautrix-telegram.nix
|
./mautrix-telegram.nix
|
||||||
./mautrix-services.nix
|
# ./mautrix-discord.nix # Native NixOS 25.11 module (replaces nix-matrix-appservices)
|
||||||
# ./mautrix-discord.nix
|
# ./mautrix-services.nix # Old nix-matrix-appservices - discord moved to native module
|
||||||
# ./mautrix-whatsapp.nix
|
# ./mautrix-whatsapp.nix
|
||||||
# ./mautrix-slack.nix
|
# ./mautrix-slack.nix
|
||||||
# ./mautrix-signal.nix
|
# ./mautrix-signal.nix
|
||||||
@@ -29,19 +35,26 @@
|
|||||||
{
|
{
|
||||||
port = 8448;
|
port = 8448;
|
||||||
tls = false;
|
tls = false;
|
||||||
resources = [{
|
resources = [
|
||||||
|
{
|
||||||
compress = true;
|
compress = true;
|
||||||
names = [ "client" "federation" ];
|
names = [
|
||||||
}];
|
"client"
|
||||||
|
"federation"
|
||||||
|
];
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
port = 9090;
|
port = 9090;
|
||||||
type = "metrics";
|
type = "metrics";
|
||||||
bind_addresses = [ "0.0.0.0" ];
|
bind_addresses = [ "0.0.0.0" ];
|
||||||
resources = [{
|
resources = [
|
||||||
|
{
|
||||||
compress = false;
|
compress = false;
|
||||||
names = [ ];
|
names = [ ];
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
tls = false;
|
tls = false;
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
@@ -52,10 +65,9 @@
|
|||||||
# chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
|
# chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
|
||||||
# "/var/lib/matrix-synapse/telegram-registration.yaml"
|
# "/var/lib/matrix-synapse/telegram-registration.yaml"
|
||||||
"/var/lib/matrix-synapse/signal-registration.yaml"
|
"/var/lib/matrix-synapse/signal-registration.yaml"
|
||||||
#"/var/lib/matrix-as-whatsapp/whatsapp-registration.yaml"
|
# Discord now uses native module with registerToSynapse = true (auto-registers)
|
||||||
"/var/lib/matrix-as-discord/discord-registration.yaml"
|
# "/var/lib/matrix-as-discord/discord-registration.yaml"
|
||||||
# "/var/lib/matrix-synapse/slack-registration.yaml"
|
# "/var/lib/matrix-synapse/slack-registration.yaml"
|
||||||
# "/var/lib/matrix-synapse/discord-registration.yaml"
|
|
||||||
# "/var/lib/matrix-synapse/whatsapp-registration.yaml"
|
# "/var/lib/matrix-synapse/whatsapp-registration.yaml"
|
||||||
];
|
];
|
||||||
turn_uris = [
|
turn_uris = [
|
||||||
@@ -156,10 +168,12 @@
|
|||||||
|
|
||||||
networking.firewall =
|
networking.firewall =
|
||||||
let
|
let
|
||||||
range = with config.services.coturn; [{
|
range = with config.services.coturn; [
|
||||||
|
{
|
||||||
from = min-port;
|
from = min-port;
|
||||||
to = max-port;
|
to = max-port;
|
||||||
}];
|
}
|
||||||
|
];
|
||||||
in
|
in
|
||||||
{
|
{
|
||||||
enable = true;
|
enable = true;
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
lib,
|
||||||
|
pkgs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
# Native NixOS 25.11 mautrix-discord module
|
||||||
|
# Replaces the nix-matrix-appservices discord configuration
|
||||||
|
services.mautrix-discord = {
|
||||||
|
enable = true;
|
||||||
|
registerToSynapse = true;
|
||||||
|
settings = {
|
||||||
|
homeserver = {
|
||||||
|
address = "https://sealight.xyz";
|
||||||
|
domain = "sealight.xyz";
|
||||||
|
};
|
||||||
|
appservice = {
|
||||||
|
id = "discord";
|
||||||
|
bot_username = "discordbridge";
|
||||||
|
address = "http://localhost:29188";
|
||||||
|
port = 29188;
|
||||||
|
# Uses SQLite by default, can switch to PostgreSQL:
|
||||||
|
# database = "postgresql:///mautrix-discord?host=/run/postgresql";
|
||||||
|
};
|
||||||
|
bridge = {
|
||||||
|
permissions = {
|
||||||
|
"@aynish:sealight.xyz" = "admin";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
self,
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
inputs,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
opencode = inputs.llm-agents.packages.${pkgs.system}.opencode;
|
||||||
|
in
|
||||||
|
{
|
||||||
|
systemd.services.opencode-server = {
|
||||||
|
description = "OpenCode HTTP Server";
|
||||||
|
after = [ "network.target" ];
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
|
||||||
|
# Read the API key from the agenix secret file and export it
|
||||||
|
script = ''
|
||||||
|
export ANTHROPIC_API_KEY="$(cat /run/agenix/anthropicToken)"
|
||||||
|
exec ${opencode}/bin/opencode serve --port 4096 --hostname 0.0.0.0
|
||||||
|
'';
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Type = "simple";
|
||||||
|
WorkingDirectory = "/home/anish/usr";
|
||||||
|
User = "anish";
|
||||||
|
Restart = "on-failure";
|
||||||
|
RestartSec = "10";
|
||||||
|
|
||||||
|
# Hardening
|
||||||
|
NoNewPrivileges = true;
|
||||||
|
PrivateTmp = true;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
# Open firewall port for LAN access
|
||||||
|
networking.firewall.allowedTCPPorts = [ 4096 ];
|
||||||
|
|
||||||
|
services.nginx = {
|
||||||
|
enable = true;
|
||||||
|
virtualHosts = {
|
||||||
|
"opencode.mossnet.lan" = {
|
||||||
|
forceSSL = false;
|
||||||
|
enableACME = false;
|
||||||
|
locations."/".proxyPass = "http://localhost:4096/";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -13,7 +13,7 @@ touch "$TRACKING_FILE"
|
|||||||
|
|
||||||
# Get list of albums on remote server
|
# Get list of albums on remote server
|
||||||
echo "$(date): Checking for new albums on seedbox..." >>"$LOG_FILE"
|
echo "$(date): Checking for new albums on seedbox..." >>"$LOG_FILE"
|
||||||
REMOTE_ALBUMS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.') || true
|
REMOTE_ALBUMS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.' | grep -v '^tv-sonarr$') || true
|
||||||
|
|
||||||
if [ -z "$REMOTE_ALBUMS" ]; then
|
if [ -z "$REMOTE_ALBUMS" ]; then
|
||||||
echo "$(date): No albums found on remote server" >>"$LOG_FILE"
|
echo "$(date): No albums found on remote server" >>"$LOG_FILE"
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
{ pkgs, lib, ... }:
|
||||||
|
|
||||||
|
{
|
||||||
|
systemd.services.get-tv-sync = {
|
||||||
|
serviceConfig.Type = "oneshot";
|
||||||
|
path = [
|
||||||
|
pkgs.coreutils
|
||||||
|
pkgs.openssh
|
||||||
|
pkgs.gawk
|
||||||
|
pkgs.rsync
|
||||||
|
pkgs.curl
|
||||||
|
];
|
||||||
|
script = builtins.readFile ./get-tv.sh;
|
||||||
|
serviceConfig = {
|
||||||
|
User = "anish";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
systemd.timers.get-tv-sync = {
|
||||||
|
wantedBy = [ "timers.target" ];
|
||||||
|
partOf = [ "get-tv-sync.service" ];
|
||||||
|
timerConfig.OnCalendar = [ "hourly" ];
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
REMOTE_HOST="aynish@talos.feralhosting.com"
|
||||||
|
REMOTE_PATH="private/transmission/data/tv-sonarr/"
|
||||||
|
LOCAL_PATH="/tank/media/tv"
|
||||||
|
TRACKING_FILE="/tank/media/tv/.downloaded_shows"
|
||||||
|
LOG_FILE="/tank/media/tv/download-log"
|
||||||
|
|
||||||
|
# Create local directory and tracking file if they don't exist
|
||||||
|
mkdir -p "$LOCAL_PATH"
|
||||||
|
touch "$TRACKING_FILE"
|
||||||
|
|
||||||
|
# Get list of shows on remote server
|
||||||
|
echo "$(date): Checking for new TV shows on seedbox..." >>"$LOG_FILE"
|
||||||
|
REMOTE_SHOWS=$(rsync --dry-run --list-only "$REMOTE_HOST:$REMOTE_PATH" | grep '^d' | awk '{$1=$2=$3=$4=""; sub(/^ +/, ""); print}' | grep -v '^\.') || true
|
||||||
|
|
||||||
|
if [ -z "$REMOTE_SHOWS" ]; then
|
||||||
|
echo "$(date): No shows found on remote server" >>"$LOG_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check each show against tracking file
|
||||||
|
NEW_SHOWS=""
|
||||||
|
while IFS= read -r show; do
|
||||||
|
if [ -n "$show" ] && ! grep -qF "$show" "$TRACKING_FILE"; then
|
||||||
|
NEW_SHOWS="$NEW_SHOWS$show\n"
|
||||||
|
echo "$(date): Found new show: $show" >>"$LOG_FILE"
|
||||||
|
fi
|
||||||
|
done <<<"$REMOTE_SHOWS"
|
||||||
|
|
||||||
|
if [ -z "$NEW_SHOWS" ]; then
|
||||||
|
echo "$(date): No new shows to download" >>"$LOG_FILE"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Download new shows only
|
||||||
|
echo "$(date): Starting download of new shows..." >>"$LOG_FILE"
|
||||||
|
while IFS= read -r show; do
|
||||||
|
if [ -n "$show" ]; then
|
||||||
|
echo "$(date): Downloading $show" >>"$LOG_FILE"
|
||||||
|
# Set umask to allow group read/write access for Jellyfin
|
||||||
|
umask 002
|
||||||
|
if rsync -r --log-file="$LOG_FILE" "$REMOTE_HOST:$REMOTE_PATH$show/" "$LOCAL_PATH/$show/"; then
|
||||||
|
echo "$show" >>"$TRACKING_FILE"
|
||||||
|
echo "$(date): Successfully downloaded $show" >>"$LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "$(date): Failed to download $show" >>"$LOG_FILE"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done <<<"$(echo -e "$NEW_SHOWS")"
|
||||||
|
|
||||||
|
# Trigger Jellyfin library scan
|
||||||
|
echo "$(date): Triggering Jellyfin library refresh..." >>"$LOG_FILE"
|
||||||
|
if curl -s -X POST "http://localhost:8096/Library/Refresh" \
|
||||||
|
-H "X-Emby-Token: aef1b1e0cd5445dc97b755ef8c6224e5"; then
|
||||||
|
echo "$(date): Jellyfin library refresh triggered" >>"$LOG_FILE"
|
||||||
|
else
|
||||||
|
echo "$(date): Failed to trigger Jellyfin library refresh" >>"$LOG_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "$(date): TV sync completed" >>"$LOG_FILE"
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
environment.systemPackages = [ pkgs.beets ];
|
environment.systemPackages = [ pkgs.beets ];
|
||||||
services.transmission = {
|
services.transmission = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
package = pkgs.transmission_4; # 25.11: transmission_3 removed, explicitly use v4
|
||||||
settings = {
|
settings = {
|
||||||
rpc-enabled = true;
|
rpc-enabled = true;
|
||||||
rpc-bind-address = "0.0.0.0";
|
rpc-bind-address = "0.0.0.0";
|
||||||
|
|||||||
@@ -24,7 +24,9 @@
|
|||||||
});
|
});
|
||||||
|
|
||||||
wallabag = prev.wallabag.overrideAttrs (attrs: {
|
wallabag = prev.wallabag.overrideAttrs (attrs: {
|
||||||
patches = builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") attrs.patches ++ [
|
patches =
|
||||||
|
builtins.filter (patch: builtins.baseNameOf patch != "wallabag-data.patch") attrs.patches
|
||||||
|
++ [
|
||||||
# Out of the box, Wallabag wants to write to various subdirectories of the project directory.
|
# Out of the box, Wallabag wants to write to various subdirectories of the project directory.
|
||||||
# Let’s replace references to such paths with designated systemd locations
|
# Let’s replace references to such paths with designated systemd locations
|
||||||
# so that the project source can remain immutable.
|
# so that the project source can remain immutable.
|
||||||
@@ -36,9 +38,7 @@
|
|||||||
knownVulnerabilities = [ ];
|
knownVulnerabilities = [ ];
|
||||||
});
|
});
|
||||||
|
|
||||||
mautrix-discord = prev.mautrix-discord.overrideAttrs (attrs: rec {
|
# mautrix-discord overlay removed - now using native NixOS 25.11 module
|
||||||
license = "";
|
|
||||||
});
|
|
||||||
|
|
||||||
# Need to do server and agent too, maybe
|
# Need to do server and agent too, maybe
|
||||||
# woodpecker-cli-next =
|
# woodpecker-cli-next =
|
||||||
|
|||||||
+1
-1
@@ -9,7 +9,7 @@ pkgs.stdenv.mkDerivation rec {
|
|||||||
};
|
};
|
||||||
buildInputs = with pkgs; [
|
buildInputs = with pkgs; [
|
||||||
lua
|
lua
|
||||||
fennel
|
luaPackages.fennel # renamed from fennel in 25.11
|
||||||
];
|
];
|
||||||
|
|
||||||
configurePhase = ''
|
configurePhase = ''
|
||||||
|
|||||||
Reference in New Issue
Block a user