claude-code: Add support for installing plugins (#8934)
Allow for configuring marketplaces or individual plugins. Both are provided as a list of either paths or packages. The lone plugins are enabled by adding a --plugin-dir argument to the wrapper script. Marketplaces are saved to the nix store and enabled by adding to the claude settings and known_marketplaces files. With the marketplace "installed", the plugin can just be enabled via the enabledPlugins setting.
This commit is contained in:
parent
0143d6ca9b
commit
7126ec6a55
11 changed files with 196 additions and 6 deletions
|
|
@ -47,7 +47,7 @@
|
|||
};
|
||||
|
||||
test.asserts.assertions.expected = [
|
||||
"`programs.claude-code.package` cannot be null when `mcpServers`, `lspServers`, or `enableMcpIntegration` is configured"
|
||||
"`programs.claude-code.package` cannot be null when `mcpServers`, `lspServers`, `enableMcpIntegration`, or `plugins` is configured"
|
||||
"Cannot specify both `programs.claude-code.memory.text` and `programs.claude-code.memory.source`"
|
||||
"Cannot specify both `programs.claude-code.agents` and `programs.claude-code.agentsDir`"
|
||||
"Cannot specify both `programs.claude-code.commands` and `programs.claude-code.commandsDir`"
|
||||
|
|
|
|||
|
|
@ -21,4 +21,6 @@
|
|||
claude-code-mixed-content = ./mixed-content.nix;
|
||||
claude-code-output-styles = ./output-styles.nix;
|
||||
claude-code-output-styles-not-set = ./output-styles-not-set.nix;
|
||||
claude-code-plugins = ./plugins.nix;
|
||||
claude-code-marketplacess = ./marketplaces.nix;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"test-duplicate": {
|
||||
"installLocation": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"lastUpdated": "1970-01-01T00:00:00Z",
|
||||
"source": {
|
||||
"path": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"source": "directory"
|
||||
}
|
||||
},
|
||||
"test-market": {
|
||||
"installLocation": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"lastUpdated": "1970-01-01T00:00:00Z",
|
||||
"source": {
|
||||
"path": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"source": "directory"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
#! @bash-interactive@/bin/bash -e
|
||||
exec -a "$0" "/nix/store/00000000000000000000000000000000-claude-code/bin/.claude-wrapped" --plugin-dir /nix/store/00000000000000000000000000000000-test-plugin "$@"
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"$schema": "https://json.schemastore.org/claude-code-settings.json",
|
||||
"extraKnownMarketplaces": {
|
||||
"test-duplicate": {
|
||||
"source": {
|
||||
"path": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"source": "directory"
|
||||
}
|
||||
},
|
||||
"test-market": {
|
||||
"source": {
|
||||
"path": "/nix/store/00000000000000000000000000000000-test-marketplace",
|
||||
"source": "directory"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
29
tests/modules/programs/claude-code/marketplaces.nix
Normal file
29
tests/modules/programs/claude-code/marketplaces.nix
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
{ config, ... }:
|
||||
|
||||
{
|
||||
programs.claude-code = {
|
||||
package = config.lib.test.mkStubPackage {
|
||||
name = "claude-code";
|
||||
buildScript = ''
|
||||
mkdir -p $out/bin
|
||||
touch $out/bin/claude
|
||||
chmod 755 $out/bin/claude
|
||||
'';
|
||||
};
|
||||
enable = true;
|
||||
|
||||
marketplaces = {
|
||||
test-market = ./test-marketplace;
|
||||
test-duplicate = ./test-marketplace;
|
||||
};
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
assertFileExists home-files/.claude/plugins/known_marketplaces.json
|
||||
assertLinkExists home-files/.claude/plugins/known_marketplaces.json
|
||||
normalizedFile=$(normalizeStorePaths home-files/.claude/plugins/known_marketplaces.json)
|
||||
assertFileContent "$normalizedFile" ${./expected-known-marketplaces.json}
|
||||
normalizedFile=$(normalizeStorePaths home-files/.claude/settings.json)
|
||||
assertFileContent "$normalizedFile" ${./expected-settings-marketplaces.json}
|
||||
'';
|
||||
}
|
||||
28
tests/modules/programs/claude-code/plugins.nix
Normal file
28
tests/modules/programs/claude-code/plugins.nix
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{ config, ... }:
|
||||
|
||||
{
|
||||
programs.claude-code = {
|
||||
package = config.lib.test.mkStubPackage {
|
||||
name = "claude-code";
|
||||
buildScript = ''
|
||||
mkdir -p $out/bin
|
||||
touch $out/bin/claude
|
||||
chmod 755 $out/bin/claude
|
||||
'';
|
||||
};
|
||||
enable = true;
|
||||
|
||||
plugins = [ ./test-plugin ];
|
||||
};
|
||||
|
||||
nmt.script = ''
|
||||
wrapperPath="$TESTED/home-path/bin/claude"
|
||||
normalizedWrapper=$(normalizeStorePaths "$wrapperPath")
|
||||
assertFileContent $normalizedWrapper ${./expected-plugin-wrapper}
|
||||
|
||||
test "$(grep -o -- '--plugin-dir ' "$wrapperPath" | wc -l)" -eq 1
|
||||
pluginDir=$(grep -o -- '--plugin-dir /nix/store/[^ ]*' "$wrapperPath")
|
||||
pluginDir="''${pluginDir#--plugin-dir }"
|
||||
assertFileContent "$pluginDir/.claude-plugin/plugin.json" ${./test-plugin/.claude-plugin/plugin.json}
|
||||
'';
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"plugins": [
|
||||
{
|
||||
"name": "test-tool",
|
||||
"source": "./plugins/test-tool"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "test-tool",
|
||||
"description": "A test tool plugin"
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"name": "test-plugin",
|
||||
"description": "A test plugin for home-manager tests"
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue