mirror of
https://github.com/instructkr/claw-code.git
synced 2026-10-28 00:05:50 +08:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a1c4b29c7 | ||
|
|
0663c80ba1 |
No files matched your search
@@ -25,6 +25,8 @@ on:
|
|||||||
- tests/test_roadmap_helpers.py
|
- tests/test_roadmap_helpers.py
|
||||||
- docs/**
|
- docs/**
|
||||||
- rust/**
|
- rust/**
|
||||||
|
- flake.nix
|
||||||
|
- .envrc
|
||||||
pull_request:
|
pull_request:
|
||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
@@ -47,6 +49,8 @@ on:
|
|||||||
- tests/test_roadmap_helpers.py
|
- tests/test_roadmap_helpers.py
|
||||||
- docs/**
|
- docs/**
|
||||||
- rust/**
|
- rust/**
|
||||||
|
- flake.nix
|
||||||
|
- .envrc
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
|
|||||||
@@ -15,3 +15,7 @@ status-help.txt
|
|||||||
.port_sessions/
|
.port_sessions/
|
||||||
# Local agent session state
|
# Local agent session state
|
||||||
.gjc/
|
.gjc/
|
||||||
|
# Nix build outputs and direnv
|
||||||
|
.envrc.local
|
||||||
|
result
|
||||||
|
result-*
|
||||||
@@ -0,0 +1,203 @@
|
|||||||
|
# Nix flake development environment
|
||||||
|
|
||||||
|
This repository includes a **`flake.nix`** for reproducible development environments on NixOS and systems with Nix installed.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- **Nix** (version 2.4 or later with flakes support enabled)
|
||||||
|
- **direnv** (optional, for automatic environment loading via `.envrc`)
|
||||||
|
|
||||||
|
To verify Nix is installed and flakes are enabled:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix --version
|
||||||
|
nix flake --help
|
||||||
|
```
|
||||||
|
|
||||||
|
If flakes are not enabled, add this to your `~/.config/nix/nix.conf`:
|
||||||
|
|
||||||
|
```
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
```
|
||||||
|
|
||||||
|
## Quick start
|
||||||
|
|
||||||
|
### Enter the development environment
|
||||||
|
|
||||||
|
**Option 1: Using `nix flake`** (without direnv)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix flake update # Update inputs (optional, pins nixpkgs)
|
||||||
|
nix develop # Enter default dev shell
|
||||||
|
nix develop .#full # Enter full dev shell with extra tools
|
||||||
|
exit # Leave the shell
|
||||||
|
```
|
||||||
|
|
||||||
|
**Option 2: Using direnv** (automatic on directory entry)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
direnv allow # Trust the .envrc file (one-time setup)
|
||||||
|
cd . # Direnv reloads the flake automatically
|
||||||
|
```
|
||||||
|
|
||||||
|
When you leave the repository directory, the environment is automatically unloaded.
|
||||||
|
|
||||||
|
## Development shells
|
||||||
|
|
||||||
|
The flake provides two development shells:
|
||||||
|
|
||||||
|
### `default` (minimal)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop
|
||||||
|
```
|
||||||
|
|
||||||
|
Includes:
|
||||||
|
- Rust (stable, latest)
|
||||||
|
- Rust source code (`rust-src`)
|
||||||
|
- `cargo-edit` (dependency management helpers)
|
||||||
|
- `cargo-expand` (macro expansion tool)
|
||||||
|
- `cargo-watch` (file watcher for incremental builds)
|
||||||
|
- Build tools: `pkg-config`, `openssl`, `git`, `ca-certificates`
|
||||||
|
|
||||||
|
### `full` (with extra tooling)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop .#full
|
||||||
|
```
|
||||||
|
|
||||||
|
Includes everything from `default` plus:
|
||||||
|
- `clippy` (linter)
|
||||||
|
- `rustfmt` (code formatter)
|
||||||
|
- `mold` (fast linker)
|
||||||
|
- `lldb` (debugger)
|
||||||
|
|
||||||
|
## Building the claw binary
|
||||||
|
|
||||||
|
### With the dev environment
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix develop
|
||||||
|
cd rust
|
||||||
|
cargo build -p rusty-claude-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
### Directly with `nix build`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build .#claw # Build the claw binary
|
||||||
|
nix build # Same as .#claw (default package)
|
||||||
|
```
|
||||||
|
|
||||||
|
The compiled binary is symlinked to `./result/bin/claw`.
|
||||||
|
|
||||||
|
## Running common tasks
|
||||||
|
|
||||||
|
Once in the dev shell:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Format code
|
||||||
|
cd rust
|
||||||
|
cargo fmt
|
||||||
|
|
||||||
|
# Run clippy linter
|
||||||
|
cargo clippy --workspace --all-targets -- -D warnings
|
||||||
|
|
||||||
|
# Run all tests
|
||||||
|
cargo test --workspace
|
||||||
|
|
||||||
|
# Run tests for a specific crate
|
||||||
|
cargo test -p rusty-claude-cli
|
||||||
|
|
||||||
|
# Build with optimizations
|
||||||
|
cargo build --release -p rusty-claude-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
## Environment variables
|
||||||
|
|
||||||
|
The flake automatically sets:
|
||||||
|
|
||||||
|
- `RUSTUP_TOOLCHAIN=stable` — uses stable Rust from nixpkgs
|
||||||
|
- Standard Rust build flags are inherited from the environment
|
||||||
|
|
||||||
|
For development, the minimal dev shell includes a helpful message on entry:
|
||||||
|
|
||||||
|
```
|
||||||
|
Claw Code development environment
|
||||||
|
Run 'cargo build -p rusty-claude-cli' to build the claw binary
|
||||||
|
Run 'cargo test --workspace' to run tests
|
||||||
|
Run 'scripts/fmt.sh' to format code
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### `command not found: nix`
|
||||||
|
|
||||||
|
Nix is not installed. Install it from [nixos.org/download.html](https://nixos.org/download.html).
|
||||||
|
|
||||||
|
### `error: experimental Nix feature 'flakes' is disabled`
|
||||||
|
|
||||||
|
Enable flakes in your Nix configuration (`~/.config/nix/nix.conf` or `/etc/nix/nix.conf`):
|
||||||
|
|
||||||
|
```
|
||||||
|
experimental-features = nix-command flakes
|
||||||
|
```
|
||||||
|
|
||||||
|
### `error: ... does not provide attribute 'claw'`
|
||||||
|
|
||||||
|
The flake structure may have changed. Try updating:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix flake update
|
||||||
|
nix flake check
|
||||||
|
```
|
||||||
|
|
||||||
|
### Rebuilds are slow after updating dependencies
|
||||||
|
|
||||||
|
Cargo will recompile dependencies if `Cargo.lock` changes. This is expected:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
nix build --rebuild
|
||||||
|
```
|
||||||
|
|
||||||
|
### `cache lock file needs to be updated`
|
||||||
|
|
||||||
|
The Cargo.lock in `rust/` needs to be committed. Run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd rust
|
||||||
|
cargo generate-lockfile
|
||||||
|
git add Cargo.lock
|
||||||
|
git commit -m "update: Cargo.lock"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Integration with other tools
|
||||||
|
|
||||||
|
### IDE integration (VS Code, IntelliJ, etc.)
|
||||||
|
|
||||||
|
Many IDEs can detect and use Nix environments. Direnv integration is recommended:
|
||||||
|
|
||||||
|
1. Install the direnv extension
|
||||||
|
2. Enable `direnv` shell integration in your IDE
|
||||||
|
3. Run `direnv allow` in the repository
|
||||||
|
|
||||||
|
Your IDE will automatically use the correct Rust toolchain and dependencies from the flake.
|
||||||
|
|
||||||
|
### CI/CD
|
||||||
|
|
||||||
|
For GitHub Actions, consider using [cachix/install-nix-action](https://github.com/cachix/install-nix-action) to set up Nix on the runner:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- uses: cachix/install-nix-action@v18
|
||||||
|
with:
|
||||||
|
nix_path: nixpkgs=channel:nixos-unstable
|
||||||
|
extra_nix_config: "experimental-features = nix-command flakes"
|
||||||
|
|
||||||
|
- run: nix develop -c cargo test --workspace
|
||||||
|
```
|
||||||
|
|
||||||
|
## More information
|
||||||
|
|
||||||
|
- [NixOS flakes documentation](https://nixos.wiki/wiki/Flakes)
|
||||||
|
- [Direnv documentation](https://direnv.net/)
|
||||||
|
- [Rust on Nix](https://github.com/oxalica/rust-overlay)
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
{
|
||||||
|
description = "claw-code: Claude Code CLI agent harness in Rust";
|
||||||
|
|
||||||
|
inputs = {
|
||||||
|
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
||||||
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
rust-overlay = {
|
||||||
|
url = "github:oxalica/rust-overlay";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
outputs = { self, nixpkgs, flake-utils, rust-overlay }:
|
||||||
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
|
let
|
||||||
|
overlays = [ (import rust-overlay) ];
|
||||||
|
pkgs = import nixpkgs {
|
||||||
|
inherit system overlays;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Build inputs needed for Rust and the project
|
||||||
|
buildInputs = with pkgs; [
|
||||||
|
pkg-config
|
||||||
|
openssl
|
||||||
|
ca-certificates
|
||||||
|
git
|
||||||
|
];
|
||||||
|
|
||||||
|
# Runtime inputs for the dev environment
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
(rust-bin.stable.latest.default.override {
|
||||||
|
extensions = [ "rust-src" ];
|
||||||
|
targets = [ ];
|
||||||
|
})
|
||||||
|
cargo-edit
|
||||||
|
cargo-expand
|
||||||
|
cargo-watch
|
||||||
|
];
|
||||||
|
|
||||||
|
# Derivation to build the claw binary
|
||||||
|
clawBinary = pkgs.rustPlatform.buildRustPackage {
|
||||||
|
pname = "claw";
|
||||||
|
version = (builtins.fromTOML (builtins.readFile ./rust/Cargo.toml)).workspace.package.version;
|
||||||
|
|
||||||
|
src = ./rust;
|
||||||
|
|
||||||
|
# Hash of all the dependencies in Cargo.lock
|
||||||
|
# This needs to be updated when dependencies change
|
||||||
|
# Run: nix flake update
|
||||||
|
cargoLock = {
|
||||||
|
lockFile = ./rust/Cargo.lock;
|
||||||
|
};
|
||||||
|
|
||||||
|
cargoBuildFlags = [ "-p" "rusty-claude-cli" ];
|
||||||
|
|
||||||
|
buildInputs = buildInputs ++ (with pkgs; [
|
||||||
|
openssl
|
||||||
|
]);
|
||||||
|
|
||||||
|
nativeBuildInputs = with pkgs; [
|
||||||
|
pkg-config
|
||||||
|
];
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Claude Code CLI: agent harness with Rust implementation";
|
||||||
|
homepage = "https://github.com/ultraworkers/claw-code";
|
||||||
|
license = licenses.mit;
|
||||||
|
platforms = platforms.unix;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
in
|
||||||
|
{
|
||||||
|
# Provide the claw binary as a package
|
||||||
|
packages.claw = clawBinary;
|
||||||
|
packages.default = clawBinary;
|
||||||
|
|
||||||
|
# Development shell for contributors
|
||||||
|
devShells.default = pkgs.mkShell {
|
||||||
|
name = "claw-dev";
|
||||||
|
inherit buildInputs nativeBuildInputs;
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
echo "Claw Code development environment"
|
||||||
|
echo "Run 'cargo build -p rusty-claude-cli' to build the claw binary"
|
||||||
|
echo "Run 'cargo test --workspace' to run tests"
|
||||||
|
echo "Run 'scripts/fmt.sh' to format code"
|
||||||
|
'';
|
||||||
|
|
||||||
|
# Make sure we have the right Rust toolchain
|
||||||
|
RUSTUP_TOOLCHAIN = "stable";
|
||||||
|
};
|
||||||
|
|
||||||
|
# Alternative shell with additional development tools
|
||||||
|
devShells.full = pkgs.mkShell {
|
||||||
|
name = "claw-dev-full";
|
||||||
|
inherit buildInputs nativeBuildInputs;
|
||||||
|
|
||||||
|
nativeBuildInputs = nativeBuildInputs ++ (with pkgs; [
|
||||||
|
clippy
|
||||||
|
rustfmt
|
||||||
|
mold
|
||||||
|
lldb
|
||||||
|
]);
|
||||||
|
|
||||||
|
shellHook = ''
|
||||||
|
echo "Claw Code full development environment (with extra tools)"
|
||||||
|
echo "Available tools: clippy, rustfmt, mold (linker), lldb (debugger)"
|
||||||
|
'';
|
||||||
|
|
||||||
|
RUSTUP_TOOLCHAIN = "stable";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -441,6 +441,9 @@ fn status_and_sandbox_emit_json_when_requested() {
|
|||||||
|
|
||||||
// #831: direct resume-safe slash commands should use the same local CliAction
|
// #831: direct resume-safe slash commands should use the same local CliAction
|
||||||
// JSON surfaces as their bare subcommands, not interactive_only guidance.
|
// JSON surfaces as their bare subcommands, not interactive_only guidance.
|
||||||
|
// Note: /sandbox status depends on kernel support for user namespaces.
|
||||||
|
// On systems with working user namespaces the status is "ok".
|
||||||
|
// On systems without user namespaces the status is "warn" (#731).
|
||||||
#[test]
|
#[test]
|
||||||
fn direct_resume_safe_slash_commands_route_to_local_json_actions_831() {
|
fn direct_resume_safe_slash_commands_route_to_local_json_actions_831() {
|
||||||
let root = unique_temp_dir("direct-resume-safe-slash-831");
|
let root = unique_temp_dir("direct-resume-safe-slash-831");
|
||||||
@@ -451,11 +454,11 @@ fn direct_resume_safe_slash_commands_route_to_local_json_actions_831() {
|
|||||||
.output()
|
.output()
|
||||||
.expect("git init should launch");
|
.expect("git init should launch");
|
||||||
|
|
||||||
for (command, expected_kind, expected_status) in [
|
for (command, expected_kind, expected_statuses) in [
|
||||||
("/version", "version", "ok"),
|
("/version", "version", &["ok"][..]),
|
||||||
("/sandbox", "sandbox", "warn"),
|
("/sandbox", "sandbox", &["ok", "warn"][..]),
|
||||||
("/diff", "diff", "ok"),
|
("/diff", "diff", &["ok"][..]),
|
||||||
("/status", "status", "ok"),
|
("/status", "status", &["ok"][..]),
|
||||||
] {
|
] {
|
||||||
let output = run_claw(&root, &["--output-format", "json", command], &[]);
|
let output = run_claw(&root, &["--output-format", "json", command], &[]);
|
||||||
assert!(
|
assert!(
|
||||||
@@ -470,9 +473,9 @@ fn direct_resume_safe_slash_commands_route_to_local_json_actions_831() {
|
|||||||
.unwrap_or_else(|_| panic!("{command} must emit JSON (#831), got: {stdout:?}"));
|
.unwrap_or_else(|_| panic!("{command} must emit JSON (#831), got: {stdout:?}"));
|
||||||
|
|
||||||
assert_eq!(parsed["kind"], expected_kind, "{command} kind: {parsed}");
|
assert_eq!(parsed["kind"], expected_kind, "{command} kind: {parsed}");
|
||||||
assert_eq!(
|
assert!(
|
||||||
parsed["status"], expected_status,
|
expected_statuses.contains(&parsed["status"].as_str().unwrap_or("")),
|
||||||
"{command} status: {parsed}"
|
"{command} status must be one of {expected_statuses:?}: {parsed}"
|
||||||
);
|
);
|
||||||
assert_ne!(
|
assert_ne!(
|
||||||
parsed["error_kind"], "interactive_only",
|
parsed["error_kind"], "interactive_only",
|
||||||
|
|||||||
Reference in new issue
Block a user