Files
collinarnett ffda880708
buildbot/nix-eval Build done.
buildbot/nix-build Build done.
clan_lib: add local pytest fixtures for clan_flake tests
Add local test fixtures that were previously imported from
clan-core.  This is necessary because clan-core's fixtures use
Path(__file__).parent to locate template files, which doesn't work
when clan-core is installed as a package from the nix store.

The local fixtures include:
- clan_flake: Creates test flakes with inventory configuration
- offline_template: Session-scoped template with pre-generated
flake.lock
- Supporting fixtures for git credential and GPG signing configuration

Also adds CLAN_CORE_PATH environment variable to the devShell, which
points to the clan-core flake input for tests that need to
substitute flake inputs.
2026-01-25 15:08:43 -05:00

168 lines
5.7 KiB
Nix

{
description = "LLM-powered natural language interface for Clan configuration";
inputs = {
clan-core.url = "git+https://git.clan.lol/collinarnett/clan-core.git?ref=collinarnett-export_container_driver";
nixpkgs.follows = "clan-core/nixpkgs";
flake-parts.follows = "clan-core/flake-parts";
treefmt-nix.follows = "clan-core/treefmt-nix";
mcp-servers-nix.url = "github:natsukium/mcp-servers-nix";
mcp-servers-nix.inputs.nixpkgs.follows = "nixpkgs";
};
outputs =
inputs@{
self,
clan-core,
flake-parts,
mcp-servers-nix,
...
}:
flake-parts.lib.mkFlake { inherit inputs; } (
{ ... }:
{
imports = [
# Import clan flakeModule to provide clanInternals structure for testing
# This only creates Nix data structures, doesn't execute clan-cli
clan-core.flakeModules.clan
clan-core.flakeModules.containerTest
mcp-servers-nix.flakeModule
./formatter.nix
./machines/flake-module.nix
];
systems = [
"x86_64-linux"
"aarch64-darwin"
];
# Minimal clan configuration for AI testing
# This creates the clanInternals structure that clan ai queries
flake.clan = {
meta.name = "clan-llm-dev";
meta.description = "Development environment for Clan AI/LLM features";
# Define a minimal test machine for AI to discover
inventory.machines = {
test-machine = {
name = "test-machine";
description = "Test machine for AI development";
tags = [ "all" ];
};
};
};
perSystem =
{
config,
pkgs,
system,
...
}:
let
python = pkgs.python313;
# Override clan-cli to replace the llm and ai directories with our local versions
clanCLIPlusLLM = clan-core.packages.${system}.clan-cli.overrideAttrs (oldAttrs: {
postUnpack = (oldAttrs.postUnpack or "") + ''
rm -rf $sourceRoot/clan_lib/llm
rm -rf $sourceRoot/clan_cli/ai
cp -r ${./pkgs/clan-llm/clan_lib/llm} $sourceRoot/clan_lib/llm
cp -r ${./pkgs/clan-llm/clan_cli/ai} $sourceRoot/clan_cli/ai
'';
# Override sourceWithTests to include local LLM code for tests
passthru = oldAttrs.passthru // {
sourceWithTests = pkgs.runCommand "${oldAttrs.passthru.sourceWithTests.name}-with-llm" { } ''
cp -r ${oldAttrs.passthru.sourceWithTests} $out
chmod -R +w $out
rm -rf $out/clan_lib/llm
rm -rf $out/clan_cli/ai
cp -r ${./pkgs/clan-llm/clan_lib/llm} $out/clan_lib/llm
cp -r ${./pkgs/clan-llm/clan_cli/ai} $out/clan_cli/ai
'';
};
});
clanCLIMinusLLM = clan-core.packages.${system}.clan-cli.overrideAttrs (oldAttrs: {
postUnpack = (oldAttrs.postUnpack or "") + ''
rm -rf $sourceRoot/clan_lib/llm
rm -rf $sourceRoot/clan_cli/ai
'';
# Disable checks since clan --help would fail without AI module
doCheck = false;
doInstallCheck = false;
});
# Python dependencies needed for development
pyTestDeps =
ps: with ps; [
pytest
pytest-subprocess
pytest-xdist
pytest-timeout
pytest-cov
];
# Development wrapper for clan that preserves PYTHONPATH
# This ensures sitecustomize.py is loaded to shim local ai/llm modules
clanDevWrapper = pkgs.writeShellScriptBin "clan" ''
export PYTHONPATH="$PWD:''${PYTHONPATH}"
exec ${
python.withPackages (ps: [ (ps.toPythonModule clanCLIMinusLLM) ])
}/bin/python -m clan_cli "$@"
'';
in
{
# Configure MCP servers
mcp-servers = {
programs.context7.enable = true;
flavors.claude-code.enable = true;
};
packages = {
default = clanCLIPlusLLM;
clan-cli = clanCLIPlusLLM;
};
devShells.default = pkgs.mkShell {
inputsFrom = [ config.mcp-servers.devShell ];
packages = [
# Put wrapper first so it takes priority over python env's clan binary
clanDevWrapper
(python.withPackages (
ps: [ (ps.toPythonModule clanCLIMinusLLM) ] ++ (pyTestDeps ps) ++ [ ps.ipython ]
))
pkgs.ruff
pkgs.mypy
];
# Set CLAN_CORE_PATH for tests that need to create flakes
CLAN_CORE_PATH = clan-core;
shellHook = ''
# Add project root to PYTHONPATH so Python finds sitecustomize.py
export PYTHONPATH="$PWD:$PYTHONPATH"
# Warn if ANTHROPIC_API_KEY is not set
if [ -z "''${ANTHROPIC_API_KEY:-}" ]; then
echo "WARNING: ANTHROPIC_API_KEY is not set."
echo "Please append --model=ollama to clan ai commands, or set ANTHROPIC_API_KEY."
fi
'';
};
# Container tests using the new flake-parts module
containerTests = {
llm = import ./checks/llm {
inherit self pkgs;
clan-core = inputs.clan-core;
};
};
};
}
);
}