diff --git a/.gitignore b/.gitignore index 2c25b15..136e23d 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,5 @@ flake.lock.bak .sidecar-start.sh .sidecar-base .td-root +.pi-lens +.cache diff --git a/modules/home-manager/coding/agents/claude-code.nix b/modules/home-manager/coding/agents/claude-code.nix index 2375d88..7a5d402 100644 --- a/modules/home-manager/coding/agents/claude-code.nix +++ b/modules/home-manager/coding/agents/claude-code.nix @@ -36,9 +36,50 @@ in { ''; }; + externalSkills = mkOption { + type = types.listOf (types.submodule { + options = { + src = mkOption { + type = types.anything; + description = "Flake input pointing to a skills repository root."; + }; + skillsDir = mkOption { + type = types.str; + default = "skills"; + description = '' + Subdirectory inside src that contains skill folders. + ''; + }; + selectSkills = mkOption { + type = types.nullOr (types.listOf types.str); + default = null; + description = '' + List of skill names to cherry-pick from this source. + null means include every skill found in skillsDir. + ''; + }; + }; + }); + default = []; + description = '' + External skill sources passed to mkOpencodeSkills. + Each entry maps directly to an element of the externalSkills + list accepted by the AGENTS flake's lib.mkOpencodeSkills. + ''; + example = literalExpression '' + [ + { src = inputs.skills-anthropic; selectSkills = [ "claude-api" ]; } + { src = inputs.skills-vercel; } + ] + ''; + }; + mcpServers = mkOption { type = types.attrsOf types.anything; - default = if mcpCfg != null then mcpCfg.servers else {}; + default = + if mcpCfg != null + then mcpCfg.servers + else {}; defaultText = literalExpression "config.programs.mcp.servers"; description = '' MCP server configurations for Claude Code. @@ -82,6 +123,21 @@ in { source = "${rendered}/.claude/agents"; }; + # Skills (merged from personal AGENTS repo + optional external skills) + home.file.".claude/skills" = mkIf (cfg.agentsInput != null) { + source = cfg.agentsInput.lib.mkOpencodeSkills { + inherit pkgs; + customSkills = "${cfg.agentsInput}/skills"; + externalSkills = + map ( + entry: + {inherit (entry) src skillsDir;} + // optionalAttrs (entry.selectSkills != null) {inherit (entry) selectSkills;} + ) + cfg.externalSkills; + }; + }; + # Rendered settings.json with permissions + MCP servers home.file.".claude/settings.json" = mkIf (settingsJson != null) { source = "${settingsJson}"; diff --git a/overlays/default.nix b/overlays/default.nix index b0ad210..574659c 100644 --- a/overlays/default.nix +++ b/overlays/default.nix @@ -1,7 +1,6 @@ {inputs, ...}: { # This one brings our custom packages from the 'pkgs' directory - additions = final: prev: - (import ../pkgs {pkgs = final;}); + additions = final: prev: (import ../pkgs {pkgs = final;}); # This one contains whatever you want to overlay # You can change versions, add patches, set compilation flags, anything really. diff --git a/pkgs/eigent/default.nix b/pkgs/eigent/default.nix index afa7a92..bf6a909 100644 --- a/pkgs/eigent/default.nix +++ b/pkgs/eigent/default.nix @@ -8,10 +8,10 @@ nix-update-script, }: let pname = "eigent"; - version = "0.0.89"; + version = "0.0.90"; src = fetchurl { url = "https://github.com/eigent-ai/eigent/releases/download/v${version}/Eigent-${version}.AppImage"; - hash = "sha256-9KuiFjegfXhCu1W/FCinWX4ae/DsNPudeBcXFfW18Hc="; + hash = "sha256-mwCBx+D6mgGqQa8bDuUpo3h49EwFVkwasJwaYc6aXFE="; }; appimageContents = appimageTools.extractType2 {inherit pname version src;}; in diff --git a/pkgs/opencode-desktop/default.nix b/pkgs/opencode-desktop/default.nix index 06b53c7..97d98d2 100644 --- a/pkgs/opencode-desktop/default.nix +++ b/pkgs/opencode-desktop/default.nix @@ -31,7 +31,7 @@ # Upstream is missing outputHashes for git dependencies # Also fix stale npm deps hash in upstream node_modules FOD fixedNodeModules = opencode.node_modules.overrideAttrs { - outputHash = "sha256-LRhPPrOKCGUSCEWTpAxPdWKTKVNkg82WrvD25cP3jts="; + outputHash = "sha256-285KZ7rZLRoc6XqCZRHc25NE+mmpGh/BVeMpv8aPQtQ="; }; opencode-desktop = rustPlatform.buildRustPackage (finalAttrs: { diff --git a/tests/lib/agents-test.nix b/tests/lib/agents-test.nix index 6e3b3c0..9fe2bed 100644 --- a/tests/lib/agents-test.nix +++ b/tests/lib/agents-test.nix @@ -12,17 +12,14 @@ let } ); in - assert result.success == false; - {result = "pass";}; + assert result.success == false; {result = "pass";}; # Test 2: loadCanonical extracts loadAgents from input testLoadCanonical = let fakeInput = {lib.loadAgents = {test = {description = "test";};};}; result = agentsLib.loadCanonical {agentsInput = fakeInput;}; in - assert result == {test = {description = "test";};}; - {result = "pass";}; - + assert result == {test = {description = "test";};}; {result = "pass";}; in { unknown-tool-throws = testUnknownTool; load-canonical = testLoadCanonical; diff --git a/tests/lib/coding-rules-test.nix b/tests/lib/coding-rules-test.nix index 433b270..e37c804 100644 --- a/tests/lib/coding-rules-test.nix +++ b/tests/lib/coding-rules-test.nix @@ -11,11 +11,11 @@ let rulesDir = ".coding-rules"; }; in - assert rules.instructions == [ + assert rules.instructions + == [ ".coding-rules/concerns/naming.md" ".coding-rules/languages/python.md" - ]; - {result = "pass";}; + ]; {result = "pass";}; # Test 2: default rulesDir is .opencode-rules testDefaultRulesDir = let @@ -24,13 +24,10 @@ let }; hasCorrectPrefix = builtins.all (s: builtins.substring 0 15 s == ".opencode-rules") rules.instructions; in - assert hasCorrectPrefix == true; - {result = "pass";}; + assert hasCorrectPrefix == true; {result = "pass";}; # Test 3: backward-compat alias exists - testBackwardCompat = - assert codingRulesLib.mkOpencodeRules == codingRulesLib.mkCodingRules; - {result = "pass";}; + testBackwardCompat = assert codingRulesLib.mkOpencodeRules == codingRulesLib.mkCodingRules; {result = "pass";}; # Test 4: shellHook contains both the symlink command and the config generation testShellHook = let @@ -42,9 +39,7 @@ let hasConfigGen = builtins.match ".*coding-rules.json.*" hook != null; in assert hasSymlink; - assert hasConfigGen; - {result = "pass";}; - + assert hasConfigGen; {result = "pass";}; in { instructions-correct = testInstructions; default-rules-dir = testDefaultRulesDir;