ffda880708
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.
168 lines
5.7 KiB
Nix
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;
|
|
};
|
|
};
|
|
};
|
|
}
|
|
);
|
|
}
|