diff --git a/lib/resolve.nix b/lib/resolve.nix index f954668..e26ff6b 100644 --- a/lib/resolve.nix +++ b/lib/resolve.nix @@ -48,7 +48,8 @@ let # --- Plugin resolution --- - resolvePlugin = + # Import plugin source by path or name string + importPlugin = ref: if builtins.isPath ref then import ref @@ -57,6 +58,24 @@ let else import (pluginsDir + "/${ref}"); + # Call a plugin function with args, or return plain attrset as-is + callPlugin = imported: args: if builtins.isFunction imported then imported args else imported; + + # Resolve a plugin reference: + # "claude-code" → import + call with {} + # { plugin = "claude-code"; configDir = "~/.x"; } → import + call with { configDir = "~/.x"; } + # /path/to/plugin.nix → import + call with {} + resolvePlugin = + ref: + if builtins.isAttrs ref then + let + imported = importPlugin (ref.plugin or (throw "plugin attr requires a 'plugin' key")); + args = builtins.removeAttrs ref [ "plugin" ]; + in + callPlugin imported args + else + callPlugin (importPlugin ref) { }; + pluginConfigs = map resolvePlugin (config.plugins or [ ]); # Strip meta fields before merging diff --git a/plugins/claude-code/README.md b/plugins/claude-code/README.md index 0c1d0ac..b7d964d 100644 --- a/plugins/claude-code/README.md +++ b/plugins/claude-code/README.md @@ -5,15 +5,25 @@ Runs [Claude Code](https://docs.anthropic.com/en/docs/claude-code) inside the VM ## Usage ```nix +# Default — uses ~/.claude on the host { plugins = [ "claude-code" ]; } + +# Custom config directory — use a separate Claude installation +{ plugins = [ { plugin = "claude-code"; configDir = "~/.claude-work"; } ]; } ``` +## Parameters + +| Name | Default | Description | +|---|---|---| +| `configDir` | `~/.claude` | Host-side directory to mount as `~/.claude` inside the VM | + ## What it provides | Category | Details | |---|---| | **Packages** | `claude-code` | -| **Mounts** | `~/.claude` — preserves config, credentials, and session history across VM restarts | +| **Mounts** | `` → `~/.claude` — preserves config, credentials, and session history across VM restarts | | **Domains** | `anthropic.com`, `claude.com`, `sentry.io` | | **Setup** | Overlays tmpfs on `~/.claude/{debug,statsig,telemetry,todos}` to work around virtiofs lacking `O_TMPFILE` support | diff --git a/plugins/claude-code/default.nix b/plugins/claude-code/default.nix index f27a1ff..6958af9 100644 --- a/plugins/claude-code/default.nix +++ b/plugins/claude-code/default.nix @@ -1,9 +1,10 @@ +{ configDir ? "~/.claude" }: { nix.packages = [ "claude-code" ]; mounts = [ { - source = "~/.claude"; + source = configDir; target = "~/.claude"; } ]; diff --git a/tests/run-nix-tests.sh b/tests/run-nix-tests.sh index d4813cf..d0ab4ed 100755 --- a/tests/run-nix-tests.sh +++ b/tests/run-nix-tests.sh @@ -82,6 +82,16 @@ assert_eq "user domain" "$(jq_get "$json" '.network.domains | index("user.exampl # Hook from plugin assert_eq "plugin hook" "$(jq_get "$json" '.hooks."post-up"[0]')" "echo plugin-loaded" +# --------------------------------------------------------------------------- +echo "==> Test: parameterized plugin (function with args)" +json=$(resolve "$FIXTURES/with_plugin_args.nix") + +assert_eq "projectName" "$(jq_get "$json" '.projectName')" "test-plugin-args" +assert_eq "plugin env passed through" "$(jq_get "$json" '.env.GREETING')" "world" +assert_eq "plugin packages" "$(jq_get "$json" '.nix.packages | index("curl") != null')" "true" +assert_eq "plugin domain" "$(jq_get "$json" '.network.domains | index("fn.example.com") != null')" "true" +assert_eq "user domain" "$(jq_get "$json" '.network.domains | index("user.example.com") != null')" "true" + # --------------------------------------------------------------------------- echo "==> Test: empty mounts get default" json=$(resolve "$FIXTURES/empty_mounts.nix")