claude-code: tighten module implementation

Remove redundant option machinery, centralize skills shape checks, and use narrower list composition while preserving generated behavior.
This commit is contained in:
Austin Horstman 2026-07-09 22:09:44 -05:00
parent 437ae5be42
commit f938277527
2 changed files with 29 additions and 45 deletions

View file

@ -5,11 +5,7 @@
...
}:
let
inherit (lib)
mkChangedOptionModule
nameValuePair
optionalAttrs
;
inherit (lib) mkChangedOptionModule;
cfg = config.programs.claude-code;
@ -134,12 +130,10 @@ in
hasManagedPlugins = legacyPluginPaths != [ ];
useLegacyPluginWrapper = hasManagedPlugins && !supportsPersonalPlugins;
legacyWrapperArgs = lib.flatten (
map (plugin: [
"--plugin-dir"
"${plugin}"
]) legacyPluginPaths
);
legacyWrapperArgs = lib.concatMap (plugin: [
"--plugin-dir"
"${plugin}"
]) legacyPluginPaths;
legacyFinalPackage = pkgs.symlinkJoin {
name = "claude-code";
@ -157,19 +151,21 @@ in
pluginNames = map (plugin: plugin.name) pluginEntries;
skillNames =
if builtins.isAttrs cfg.skills then
lib.attrNames cfg.skills
else if lib.hm.strings.isPathLike cfg.skills && lib.pathIsDirectory cfg.skills then
lib.attrNames (builtins.readDir cfg.skills)
skillsAreAttrs = builtins.isAttrs cfg.skills;
skillsArePath = lib.hm.strings.isPathLike cfg.skills;
skillsAreDirectory = skillsArePath && lib.pathIsDirectory cfg.skills;
skillNames = lib.attrNames (
if skillsAreAttrs then
cfg.skills
else
[ ];
lib.optionalAttrs skillsAreDirectory (builtins.readDir cfg.skills)
);
pluginFileEntries = lib.optionalAttrs supportsPersonalPlugins (
lib.listToAttrs (
map (
plugin:
nameValuePair "${cfg.configDir}/skills/${plugin.name}" {
lib.nameValuePair "${cfg.configDir}/skills/${plugin.name}" {
inherit (plugin) source;
recursive = true;
}
@ -209,7 +205,7 @@ in
message = "Managed Claude Code MCP, LSP, and plugins require `programs.claude-code.package` version 2.1.76 or later";
}
{
assertion = !lib.hm.strings.isPathLike cfg.skills || lib.pathIsDirectory cfg.skills;
assertion = !skillsArePath || skillsAreDirectory;
message = "`programs.claude-code.skills` must be a directory when set to a path";
}
{
@ -242,10 +238,10 @@ in
// {
"$schema" = "https://json.schemastore.org/claude-code-settings.json";
}
// optionalAttrs (cfg.marketplaces != { }) {
// lib.optionalAttrs (cfg.marketplaces != { }) {
extraKnownMarketplaces = lib.mapAttrs mkMarketplaceEntry cfg.marketplaces;
}
// optionalAttrs (disabledMcpServerNames != [ ]) {
// lib.optionalAttrs (disabledMcpServerNames != [ ]) {
disabledMcpjsonServers = lib.unique (
(cfg.settings.disabledMcpjsonServers or [ ]) ++ disabledMcpServerNames
);
@ -275,7 +271,7 @@ in
(mkRecursiveDirAttrs "commands" cfg.commandsDir)
(mkRecursiveDirAttrs "hooks" cfg.hooksDir)
(mkRecursiveDirAttrs "rules" cfg.rulesDir)
(lib.mkIf (lib.hm.strings.isPathLike cfg.skills) {
(lib.mkIf skillsArePath {
"${cfg.configDir}/skills" = {
source = cfg.skills;
recursive = true;
@ -283,7 +279,7 @@ in
})
pluginFileEntries
(mkHookEntries cfg.hooks)
(lib.optionalAttrs (builtins.isAttrs cfg.skills) (lib.mapAttrs' mkSkillEntry cfg.skills))
(lib.optionalAttrs skillsAreAttrs (lib.mapAttrs' mkSkillEntry cfg.skills))
(mkMarkdownEntries "output-styles" cfg.outputStyles)
];
};

View file

@ -5,23 +5,17 @@
...
}:
let
inherit (lib) literalExpression mkOption optionalAttrs;
inherit (lib) literalExpression mkOption;
jsonFormat = pkgs.formats.json { };
mkContentOption =
{
description,
example ? null,
}:
mkOption (
{
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
default = { };
inherit description;
}
// optionalAttrs (example != null) { inherit example; }
);
{ description, example }:
mkOption {
type = lib.types.attrsOf (lib.types.either lib.types.lines lib.types.path);
default = { };
inherit description example;
};
mkDirOption =
{ description, example }:
@ -171,7 +165,7 @@ in
example = literalExpression ''
[
./my-local-plugin
fetchFromGithub {
fetchFromGitHub {
owner = "some-github-org";
repo = "claude-plugin";
rev = "779a68ebc2a75e4a184d2c87e5a43a758e6458a1";
@ -193,7 +187,7 @@ in
example = literalExpression ''
{
local-marketplace = ./my-local-marketplace;
gh-marketplace = fetchFromGithub {
gh-marketplace = fetchFromGitHub {
owner = "some-github-org";
repo = "claude-marketplace";
rev = "8a873a220b8427b25b03ce1a821593a24e098c34";
@ -384,13 +378,7 @@ in
};
skills = mkOption {
type = lib.types.either (lib.types.attrsOf (
lib.types.oneOf [
lib.types.lines
lib.types.path
lib.types.str
]
)) lib.types.path;
type = with lib.types; either (attrsOf (either lines path)) path;
default = { };
description = ''
Custom skills for Claude Code.