commit e03e44248d8c47992260028f940784dd36016f6a Author: Zhongwei Li Date: Sat Nov 29 18:02:30 2025 +0800 Initial commit diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..0fadaf0 --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,14 @@ +{ + "name": "bds-dev", + "description": "Provide tools and skills for daily development", + "version": "1.0.1", + "author": { + "name": "Break Yang" + }, + "skills": [ + "./skills" + ], + "commands": [ + "./commands" + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..136119d --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# bds-dev + +Provide tools and skills for daily development diff --git a/commands/prime.md b/commands/prime.md new file mode 100644 index 0000000..87c7803 --- /dev/null +++ b/commands/prime.md @@ -0,0 +1,20 @@ +# Prime the context by analyzing the project structure + +Use the command `lsd --tree` to get an overview of the project's code structure. In addition, + +- Read the `README.md` if exist +- Read the `flake.nix` if exist +- Files which you think are important + - For python project, read `pyproject.toml` if exist + - For javascript and typescript project, read `package.json` if exist + - For rust project, read `Cargo.toml` if exist + - For c++ project read `CMakeLists.txt` and use it as the entrypoint to understand the project structure + +## Goal + +You should be able to tell the following + +- The structure of the project +- What problem does this project solve? +- What are the major programming languages used in this project? +- What is the entrypoint of this project? diff --git a/commands/python-ready.md b/commands/python-ready.md new file mode 100644 index 0000000..2703568 --- /dev/null +++ b/commands/python-ready.md @@ -0,0 +1,36 @@ +# Prepare CLAUDE CODE with Python-Specific Context + +## Task +Read the project’s `CLAUDE.md`. Ensure all Python rules below are present. If partially present, reorganize and edit `CLAUDE.md` so all rules are included exactly and unambiguously. + +## Python Rules + +### Environment +1. Manage the dev environment with `flake.nix` only. +2. Assume `nix develop` is active. +3. Do not use `pip`, `uv`, or `poetry`. +4. Run programs as modules: `python -m package.module`. + +### Library Preferences +1. Use builtin **unittest**. + - Discover all tests: `python -m unittest discover` + - Run verbose/specific: `python -m unittest -v path/to/test_file.py` +2. Use **pydantic v2** for schemas and domain models. +3. Use **PyTorch** and **JAX** for ML models. +4. Use **loguru** for logging. +5. Use **click** for CLI/arg parsing. +6. Prefer **pathlib** over `os.path`. +7. Use explicit `StrEnum` / `IntEnum` for enums. + +### Code Style +1. **Use absolute imports**; do not use relative imports (e.g., avoid `from .x import y`). +2. Prefer specific imports (e.g., `from pydantic import BaseModel`). +3. **Use type hints everywhere**: + - Annotate all function parameters and return types. + - Use builtin generics (`list`, `dict`, `tuple`) instead of `typing.List`, etc. + - For optionals, use `MyType | None` instead of `Optional[MyType]`. + +### Documentation +1. **Write docstrings for all public modules, functions, classes, methods**, and public-facing APIs. PEP 8 and PEP 257 recommend docstrings for all public elements. +2. In docstrings: + - **Do not include types in the `Args:` section**, type hints in signatures cover that. diff --git a/commands/web-ready.md b/commands/web-ready.md new file mode 100644 index 0000000..82b6227 --- /dev/null +++ b/commands/web-ready.md @@ -0,0 +1,39 @@ +# Prepare CLAUDE CODE with Web Development Context + +## Task + +Read the project’s `CLAUDE.md`. Ensure all web development rules below are present. If some are missing or partially present, reorganize and update `CLAUDE.md` so every rule is included clearly and unambiguously. + +## Web Development Rules + +### Language & Syntax + +1. Use **TypeScript** only (no plain JavaScript). +2. Omit unnecessary semicolons—that is, do not add semicolons at statement ends unless required. +3. Prefer **arrow functions** (`const f = () => ...`) for concise, inline code and callbacks. Use **function declarations** for named or top-level functions where `this` or hoisting matters. + +### Typing & Imports + +1. Always use **explicit types**, especially for function parameters and return values. Annotate returns and arguments when it improves readability. +2. Avoid `any`. Use `unknown` or properly constrained generics instead—`unknown` forces safe type narrowing. +3. Organize imports in this order: + + * `react` + * third-party libraries + * local modules +4. Support **absolute imports** in `.ts`/`.tsx` files, e.g.: + + ```ts + import '@/components/MarkdownPreviewPanel' + ``` + + resolves to `src/components/MarkdownPreviewPanel.tsx`. + +### React & Components + +- In React components, always **destructure `props`** directly in function parameters. +- Keep `README.md` updated with essential information about React components—especially view or UI-related ones. + +### Documentation + +- Document important functions, classes, and React components with inline docstrings or comments for clarity and maintainability. diff --git a/plugin.lock.json b/plugin.lock.json new file mode 100644 index 0000000..637e02d --- /dev/null +++ b/plugin.lock.json @@ -0,0 +1,97 @@ +{ + "$schema": "internal://schemas/plugin.lock.v1.json", + "pluginId": "gh:breakds/claude.bds:bds-dev", + "normalized": { + "repo": null, + "ref": "refs/tags/v20251128.0", + "commit": "c15718f1fde63a61069d806bad838211c65240a4", + "treeHash": "7472eb9f12a9722350b008781cd7d95c726ddb1da6506fe1147b0ee1e5f889fe", + "generatedAt": "2025-11-28T10:14:24.453360Z", + "toolVersion": "publish_plugins.py@0.2.0" + }, + "origin": { + "remote": "git@github.com:zhongweili/42plugin-data.git", + "branch": "master", + "commit": "aa1497ed0949fd50e99e70d6324a29c5b34f9390", + "repoRoot": "/Users/zhongweili/projects/openmind/42plugin-data" + }, + "manifest": { + "name": "bds-dev", + "description": "Provide tools and skills for daily development", + "version": "1.0.1" + }, + "content": { + "files": [ + { + "path": "README.md", + "sha256": "52056a529c8af6260dfb803c32c8b1ad249b4c683598cd245273b7b38c71b3b7" + }, + { + "path": ".claude-plugin/plugin.json", + "sha256": "762a463cb60c13a18077e1c0a60a2369f78200b2dc675b7d6422c82f16777e45" + }, + { + "path": "commands/prime.md", + "sha256": "cc8d65d6f35b0c8c8e57eeeeddfcb9aa867d88aead3ddc77409b4dd79827954e" + }, + { + "path": "commands/python-ready.md", + "sha256": "5ea798c5898e862877aa98217aa2898185b8e5cb32aab154eb65fac4458a770a" + }, + { + "path": "commands/web-ready.md", + "sha256": "3b9b91b836666ed12efb16e56b6ea8b357e07d9fc5ab0de2676d051e1a0c9df8" + }, + { + "path": "skills/nix-packaging/SKILL.md", + "sha256": "150c14e2ff30588b0eb8661ee813a8fece458ebc8a62d37a82857712ba7990d8" + }, + { + "path": "skills/nix-packaging/python/python.md", + "sha256": "25917f62f71bbb07889741c85c4f1f776b81bafbe6eed095352caea41ddefdfd" + }, + { + "path": "skills/nix-packaging/python/swanboard/package.nix", + "sha256": "476c8e48476bcec8c0d826e9e1e7abb50bd142ce87c6ceb185787a1758cef538" + }, + { + "path": "skills/nix-packaging/python/tantivy/package.nix", + "sha256": "decc51ddd440af8a28ed6fa39ef0ed4c890887f7302dfc84c2d8b7fe2dec93c6" + }, + { + "path": "skills/nix-packaging/python/darts/package.nix", + "sha256": "7e89e0816aa082f0142185be75dcd5a1008222a51573c8e7a02e2dbf700132d1" + }, + { + "path": "skills/nix-packaging/python/agno/package.nix", + "sha256": "8d591d811c69e6bda69e39bc495b901add11c54de979a4d1be544d3574a3fd62" + }, + { + "path": "skills/nix-packaging/python/tyro/package.nix", + "sha256": "4476f22a69d79b0b116a8efde7773d80f0f1cc9a91d52ba22df55165d60ce664" + }, + { + "path": "skills/nix-packaging/js/js.md", + "sha256": "4d46fa98bd64811322cf6478934e255713e47fb4f3a92bd7c9bf47743ec17617" + }, + { + "path": "skills/nix-packaging/js/claude-code/package.nix", + "sha256": "3e4fd254f21c17016e27a4e30f16e7d7245a11a0a617524ef995a6f464758143" + }, + { + "path": "skills/nix-packaging/rust/rust.md", + "sha256": "673e7d1fa3f6c1cd05b326997410d3f2c8636f58473723e35e38e20502544718" + }, + { + "path": "skills/nix-packaging/rust/codex/package.nix", + "sha256": "9c46c61b70554a2152946fe152c5265024a4f8bed3229ff1a234c79091b33b44" + } + ], + "dirSha256": "7472eb9f12a9722350b008781cd7d95c726ddb1da6506fe1147b0ee1e5f889fe" + }, + "security": { + "scannedAt": null, + "scannerVersion": null, + "flags": [] + } +} \ No newline at end of file diff --git a/skills/nix-packaging/SKILL.md b/skills/nix-packaging/SKILL.md new file mode 100644 index 0000000..b5b1ea3 --- /dev/null +++ b/skills/nix-packaging/SKILL.md @@ -0,0 +1,40 @@ +--- +name: Nix Packaging +description: Package new software or update existing packages using Nix +--- + +# Overview + +Create new Nix packages or update existing ones, with language-specific examples and guidance. + +## Workflow: Creating a New Package + +1. Identify the software source: internal to this repo or external (e.g., a GitHub repository). +2. Determine the programming language(s) used. +3. Analyze the software structure (build system, dependencies, configuration files). +4. Create the package following language-specific guidance below. +5. Optionally, integrate the package into the current project (e.g., add to overlay and expose via `packages` in `flake.nix`). +6. Test iteratively: run `nix build .#`, read errors, fix issues, and rebuild until successful. + +## Workflow: Updating an Existing Package + +Typically, update the `version` and source fetching attributes (e.g., `fetchFromGitHub`). The `hash` field must also be updated using one of these methods: + +**Method 1: Calculate the new hash directly** +```bash +# Get the hash +nix-prefetch-url --type sha256 --unpack https://github.com/owner/repo/archive/refs/tags/v.tar.gz +# Convert to SRI format +nix hash convert --hash-algo sha256 +``` + +**Method 2: Let Nix tell you the hash** +Set `hash = "";` and run the build. The error message will display the correct hash. + +For language-specific update steps, see the references below. + +# Language-Specific Packaging Skills + +- [Python](./python/python.md) - Packaging Python modules +- [Rust](./rust/rust.md) - Packaging Rust applications +- [JavaScript/TypeScript](./js/js.md) - Packaging npm applications diff --git a/skills/nix-packaging/js/claude-code/package.nix b/skills/nix-packaging/js/claude-code/package.nix new file mode 100644 index 0000000..dcef776 --- /dev/null +++ b/skills/nix-packaging/js/claude-code/package.nix @@ -0,0 +1,52 @@ +{ + lib, + buildNpmPackage, + fetchzip, + nodejs_20, +}: + +buildNpmPackage rec { + pname = "claude-code"; + version = "2.0.21"; + + nodejs = nodejs_20; # required for sandboxed Nix builds on Darwin + + src = fetchzip { + url = "https://registry.npmjs.org/@anthropic-ai/claude-code/-/claude-code-${version}.tgz"; + hash = "sha256-sX9btcy9uEHloAQNvCJFhwh0U/W14NWz2FjkdLXm1Q0="; + }; + + npmDepsHash = "sha256-LBc1M3FwWg6SP+p7GQ00LQfiYyhmU1OzsohDu6rukjA="; + + postPatch = '' + cp ${./package-lock.json} package-lock.json + ''; + + dontNpmBuild = true; + + AUTHORIZED = "1"; + + # `claude-code` tries to auto-update by default, this disables that functionality. + # https://docs.anthropic.com/en/docs/agents-and-tools/claude-code/overview#environment-variables + # The DEV=true env var causes claude to crash with `TypeError: window.WebSocket is not a constructor` + postInstall = '' + wrapProgram $out/bin/claude \ + --set DISABLE_AUTOUPDATER 1 \ + --unset DEV + ''; + + passthru.updateScript = ./update.sh; + + meta = { + description = "Agentic coding tool that lives in your terminal, understands your codebase, and helps you code faster"; + homepage = "https://github.com/anthropics/claude-code"; + downloadPage = "https://www.npmjs.com/package/@anthropic-ai/claude-code"; + license = lib.licenses.unfree; + maintainers = with lib.maintainers; [ + malo + markus1189 + omarjatoi + ]; + mainProgram = "claude"; + }; +} diff --git a/skills/nix-packaging/js/js.md b/skills/nix-packaging/js/js.md new file mode 100644 index 0000000..68fff57 --- /dev/null +++ b/skills/nix-packaging/js/js.md @@ -0,0 +1,102 @@ +# Package a JavaScript/TypeScript Application with Nix (npm) + +Packaging an npm application (`buildNpmPackage`) involves determining the package name, version, and dependencies. The package must be available on the npm registry. + +## Normal npm Package + +See the example: [claude-code](./claude-code/package.nix) + +Key components: + +- **Source**: Fetch from npm registry using `fetchzip` with URL pattern: + ```nix + url = "https://registry.npmjs.org/@scope/package-name/-/package-name-${version}.tgz"; + ``` + For non-scoped packages, omit the `@scope/` part. + +- **Dependencies**: Set `npmDepsHash` (see update workflow below for obtaining the hash) + +- **package-lock.json**: Use `postPatch` to copy a local `package-lock.json`: + ```nix + postPatch = '' + cp ${./package-lock.json} package-lock.json + ''; + ``` + +- **Build control**: Use `dontNpmBuild = true;` if the package doesn't require a build step (already built on npm registry) + +## Updating an Existing npm Package + +Besides the general update steps, also update npm-specific fields: + +1. **Update package-lock.json**: Generate a new lock file for the target version: + + ```bash + # Find the latest version (or specific version) + npm i --package-lock-only @anthropic-ai/claude-code@"$version" + # Remove package.json (not needed for Nix packaging) + rm -f package.json + ``` + + **Note**: If `npm` is not installed, use `nix-shell` to run it: + ```bash + nix-shell -p nodejs --run "npm i --package-lock-only @anthropic-ai/claude-code@\"$version\"" + rm -f package.json + ``` + + Copy the generated `package-lock.json` to your package directory. + +2. **Update hashes**: Both `hash` (source) and `npmDepsHash` need updating. + + **Method 1: Let Nix tell you** + - Set `hash = "";` and run `nix build`. Copy the correct hash from the error message. + - Set `npmDepsHash = "";` and run `nix build`. Copy the correct hash from the error message. + + **Method 2: Calculate directly** + ```bash + # For source hash + nix-prefetch-url --type sha256 --unpack https://registry.npmjs.org/@scope/package/-/package-${version}.tgz + nix hash convert --hash-algo sha256 + ``` + +3. **Check for breaking changes**: New versions may: + - Change build requirements (update `dontNpmBuild` or add build dependencies) + - Require different Node.js versions (update `nodejs` attribute, e.g., `nodejs_20`) + - Add new environment variables or runtime requirements + +## Common Patterns + +### Specify Node.js Version + +For compatibility, especially on Darwin with sandboxed builds: + +```nix +buildNpmPackage rec { + nodejs = nodejs_20; + # ... +} +``` + +### Disable Auto-Build + +If the package is pre-built on the npm registry: + +```nix +dontNpmBuild = true; +``` + +### Set Environment Variables + +Use `postInstall` to wrap the binary with required environment variables: + +```nix +postInstall = '' + wrapProgram $out/bin/your-binary \ + --set ENV_VAR value \ + --unset UNWANTED_VAR +''; +``` + +### Handle Optional Dependencies + +npm packages often have platform-specific optional dependencies (like Sharp's native bindings). These are automatically handled by `buildNpmPackage` based on the `package-lock.json`. diff --git a/skills/nix-packaging/python/agno/package.nix b/skills/nix-packaging/python/agno/package.nix new file mode 100644 index 0000000..2c817bd --- /dev/null +++ b/skills/nix-packaging/python/agno/package.nix @@ -0,0 +1,76 @@ +{ + lib, + buildPythonPackage, + fetchFromGitHub, + setuptools, + docstring-parser, + gitpython, + httpx, + pydantic-settings, + pydantic, + python-dotenv, + python-multipart, + pyyaml, + rich, + tomli, + typer, + typing-extensions, + # optional + tantivy, + pylance, + lancedb, + qdrant-client, + unstructured, + markdown, + aiofiles, +}: + +buildPythonPackage rec { + pname = "agno"; + version = "1.7.11"; + pyproject = true; + + src = fetchFromGitHub { + owner = "agno-agi"; + repo = "agno"; + rev = "v${version}"; + hash = "sha256-9oO4qyYCgMnC1jtFr39Y76t/5/ybUGIhECP+PLhm92s="; + }; + + sourceRoot = "${src.name}/libs/agno"; + + build-system = [ setuptools ]; + + dependencies = [ + docstring-parser + gitpython + httpx + pydantic-settings + pydantic + python-dotenv + python-multipart + pyyaml + rich + tomli + typer + typing-extensions + ]; + + optional-dependencies = { + lancedb = [ lancedb tantivy ]; + pylance = [ pylance ]; # Useful for lancedb "hybrid" search + qdrant = [ qdrant-client ]; + markdown = [ unstructured markdown aiofiles ]; + }; + + pythonImportsCheck = [ "agno" ]; + + meta = { + description = "Full-stack framework for building Multi-Agent Systems with memory, knowledge and reasoning"; + homepage = "https://github.com/agno-agi/agno"; + license = lib.licenses.mpl20; + maintainers = with lib.maintainers; [ ]; + mainProgram = "agno"; + platforms = lib.platforms.all; + }; +} diff --git a/skills/nix-packaging/python/darts/package.nix b/skills/nix-packaging/python/darts/package.nix new file mode 100644 index 0000000..b608dd4 --- /dev/null +++ b/skills/nix-packaging/python/darts/package.nix @@ -0,0 +1,61 @@ +{ lib, buildPythonPackage, fetchFromGitHub, pythonRelaxDepsHook, setuptools +, holidays, joblib, matplotlib, nfoursid, numpy, pandas, pmdarima, pyod +, requests, scikit-learn, scipy, shap +# , statsforecast +, statsmodels, tbats, tqdm, typing-extensions, xarray, xgboost +, pytorch-lightning }: + +buildPythonPackage rec { + pname = "darts"; + version = "0.31.0"; + format = "pyproject"; + + src = fetchFromGitHub { + owner = "unit8co"; + repo = pname; + rev = version; + hash = "sha256-piSYRJIFr3RQTt/idfTRrqx/dD794He4d2F9flBJv7Q="; + }; + + nativeBuildInputs = [ pythonRelaxDepsHook ]; + + buildInputs = [ setuptools ]; + + propagatedBuildInputs = [ + holidays + joblib + matplotlib + nfoursid + numpy + pandas + pmdarima + pyod + requests + scikit-learn + scipy + shap + # statsforecast + statsmodels + tbats + tqdm + typing-extensions + xarray + xgboost + pytorch-lightning + ]; + + pythonRelaxDeps = [ "pmdarima" ]; + + pythonRemoveDeps = [ "statsforecast" ]; + + pythonImportsCheck = [ "darts" ]; + + meta = with lib; { + description = '' + A python library for user-friendly forecasting and anomaly detection on time series + ''; + homepage = "https://unit8co.github.io/darts/"; + license = licenses.asl20; + maintainers = with maintainers; [ breakds ]; + }; +} diff --git a/skills/nix-packaging/python/python.md b/skills/nix-packaging/python/python.md new file mode 100644 index 0000000..55c3243 --- /dev/null +++ b/skills/nix-packaging/python/python.md @@ -0,0 +1,47 @@ +# Package a Python Module with Nix + +Packaging a Python module (`buildPythonPackage`) involves determining the source, dependencies, and build system, typically from `pyproject.toml`. Ensure all dependencies are already packaged before referencing them. + +More complex cases require special handling. Below are examples for different scenarios. + +## Normal Python Module + +See the simple example: [tyro](./tyro/package.nix) + +## Customize Build System and Disable Tests + +Some Python modules require additional build tools, or have tests that cannot run in the Nix sandbox. See [Swanboard](./swanboard/package.nix) for an example. + +## Customize Source Root and Optional Dependencies + +See [agno](./agno/package.nix) for examples of: + +- Using `sourceRoot` when the Python module's root differs from the project root (specify the relative path). +- Handling optional dependencies: include them in `optional-dependencies` when available, or safely omit them if not yet packaged. + +## Rust-Backed Python Module + +For Python packages implemented in Rust with Python bindings, use `rustPlatform` as a helper. See [tantivy](./tantivy/package.nix) for an example. + +## Relax or Remove Dependencies + +When dependency requirements cannot be satisfied, investigate further: + +1. **Version mismatch**: If the dependency is packaged but the version requirement is too strict, add it to `pythonRelaxDeps` to bypass version checking. +2. **Missing dependency**: If the dependency is not packaged, assess whether it's essential for your use case. If not, add it to `pythonRemoveDeps`. + +See [darts](./darts/package.nix) for an example. + +## Updating an Existing Python Package + +Besides the general update steps, also: + +1. **Update dependencies**: Check `pyproject.toml` or `setup.py` for changed dependencies and update: + - `dependencies` - Runtime dependencies + - `build-system` - Build-time dependencies (e.g., setuptools, poetry-core) + - `optional-dependencies` - If relevant to your use case + +2. **Handle breaking changes**: New versions may: + - Drop Python version support (update `pythonOlder` or `disabled`) + - Change build backends (update `build-system` based on `pyproject.toml`) + - Add new test dependencies (update `nativeCheckInputs` or `checkInputs`) diff --git a/skills/nix-packaging/python/swanboard/package.nix b/skills/nix-packaging/python/swanboard/package.nix new file mode 100644 index 0000000..cef5241 --- /dev/null +++ b/skills/nix-packaging/python/swanboard/package.nix @@ -0,0 +1,44 @@ +{ lib, buildPythonPackage, pythonOlder, fetchFromGitHub, pytestCheckHook +, hatchling, hatch-fancy-pypi-readme, hatch-requirements-txt, swankit, fastapi +, uvicorn, peewee, ujson, psutil, pyyaml, setuptools, nanoid, numpy }: + +# TODO(breakds): Build the UI. It seemed pretty straight forward but +# for some reason I will run into this "dead spiral" of fetchYarnDeps +# always complain about a changed yarn.lock (and hash). +buildPythonPackage rec { + pname = "swanboard"; + version = "0.1.7-beta.1"; + format = "pyproject"; + + disabled = pythonOlder "3.8"; + + src = fetchFromGitHub { + owner = "SwanHubX"; + repo = "SwanLab-Dashboard"; + rev = "v${version}"; + hash = "sha256-jBYlBJaEZPJ2tORfeSUnTpwyAjENh8QYTfVb6o2UNZg="; + }; + + build-system = + [ hatchling hatch-fancy-pypi-readme hatch-requirements-txt setuptools ]; + + dependencies = [ swankit fastapi uvicorn peewee ujson psutil pyyaml ]; + + pythonImportsCheck = [ "swanboard" ]; + + nativeCheckInputs = [ pytestCheckHook nanoid numpy ]; + + disabledTests = [ + "test_get_package_version_installed" + "test_get_package_version_not_installed" + # Temporarily disable because there is a small bug that needs to be fixed. + "TestExperiment" + ]; + + meta = with lib; { + description = "Swanlab's Dashboard"; + homepage = "https://github.com/SwanHubX/SwanLab-Dashboard"; + license = licenses.asl20; + maintainers = with maintainers; [ breakds ]; + }; +} diff --git a/skills/nix-packaging/python/tantivy/package.nix b/skills/nix-packaging/python/tantivy/package.nix new file mode 100644 index 0000000..1cb1fd4 --- /dev/null +++ b/skills/nix-packaging/python/tantivy/package.nix @@ -0,0 +1,39 @@ +{ + lib + , buildPythonPackage + , fetchFromGitHub + , rustPlatform +}: + +buildPythonPackage rec { + pname = "tantivy"; + version = "0.25.0"; + format = "pyproject"; + + src = fetchFromGitHub { + owner = "quickwit-oss"; + repo = "tantivy-py"; + tag = version; + hash = "sha256-ZVQOzKojBf7yNkgiOV4huNnuxCmiFwJb610sD4M2/MU="; + }; + + cargoDeps = rustPlatform.fetchCargoVendor { + inherit pname version src; + hash = "sha256-/OADcVm01PbHp3bcw62Zt6+9ZmT96Bic+EBbPUhdoOI="; + }; + + build-system = with rustPlatform; [ cargoSetupHook maturinBuildHook ]; + + pythonImportsCheck = [ "tantivy" ]; + + meta = { + description = '' + Python bindings for Tantivy; Tantivy is a full-text search engine library + inspired by Apache Lucene and written in Rust + ''; + homepage = "https://github.com/quickwit-oss/tantivy-py"; + changeLog = "https://github.com/quickwit-oss/tantivy-py/releases/tag/${version}"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ breakds ]; + }; +} diff --git a/skills/nix-packaging/python/tyro/package.nix b/skills/nix-packaging/python/tyro/package.nix new file mode 100644 index 0000000..9bbbbf0 --- /dev/null +++ b/skills/nix-packaging/python/tyro/package.nix @@ -0,0 +1,27 @@ +{ lib, buildPythonPackage, fetchFromGitHub, setuptools, docstring-parser +, typing-extensions, rich, shtab, typeguard, hatchling }: + +buildPythonPackage rec { + pname = "tyro"; + version = "0.9.9"; + format = "pyproject"; + + src = fetchFromGitHub { + owner = "brentyi"; + repo = pname; + rev = "v${version}"; + hash = "sha256-iFKgnKd4606S/hEMHD7ZaTnGF16gmvbaE62nifw4o7c="; + }; + + build-system = [ hatchling ]; + + dependencies = [ docstring-parser typing-extensions rich shtab typeguard ]; + + pythonImportsCheck = [ "tyro" ]; + + meta = with lib; { + description = "tool for generating CLI interfaces in Python"; + homepage = "https://brentyi.github.io/tyro"; + license = licenses.mit; + }; +} diff --git a/skills/nix-packaging/rust/codex/package.nix b/skills/nix-packaging/rust/codex/package.nix new file mode 100644 index 0000000..bfb9bfc --- /dev/null +++ b/skills/nix-packaging/rust/codex/package.nix @@ -0,0 +1,74 @@ +{ + lib, + stdenv, + rustPlatform, + fetchFromGitHub, + installShellFiles, + nix-update-script, + pkg-config, + openssl, + versionCheckHook, + installShellCompletions ? stdenv.buildPlatform.canExecute stdenv.hostPlatform, +}: +rustPlatform.buildRustPackage (finalAttrs: { + pname = "codex"; + version = "0.46.0"; + + src = fetchFromGitHub { + owner = "openai"; + repo = "codex"; + tag = "rust-v${finalAttrs.version}"; + hash = "sha256-o898VjjPKevr1VRlRhJUNWsrHEGEn7jkdzWBj+DpbCs="; + }; + + sourceRoot = "${finalAttrs.src.name}/codex-rs"; + + cargoHash = "sha256-Qp5zezXjVdOp8OylLgUZRLc0HQlgII6nOZodnOrok6U="; + + nativeBuildInputs = [ + installShellFiles + pkg-config + ]; + + buildInputs = [ openssl ]; + + # NOTE: part of the test suite requires access to networking, local shells, + # apple system configuration, etc. since this is a very fast moving target + # (for now), with releases happening every other day, constantly figuring out + # which tests need to be skipped, or finding workarounds, was too burdensome, + # and in practice not adding any real value. this decision may be reversed in + # the future once this software stabilizes. + doCheck = false; + + postInstall = lib.optionalString installShellCompletions '' + installShellCompletion --cmd codex \ + --bash <($out/bin/codex completion bash) \ + --fish <($out/bin/codex completion fish) \ + --zsh <($out/bin/codex completion zsh) + ''; + + doInstallCheck = true; + nativeInstallCheckInputs = [ versionCheckHook ]; + + passthru = { + updateScript = nix-update-script { + extraArgs = [ + "--version-regex" + "^rust-v(\\d+\\.\\d+\\.\\d+)$" + ]; + }; + }; + + meta = { + description = "Lightweight coding agent that runs in your terminal"; + homepage = "https://github.com/openai/codex"; + changelog = "https://raw.githubusercontent.com/openai/codex/refs/tags/rust-v${finalAttrs.version}/CHANGELOG.md"; + license = lib.licenses.asl20; + mainProgram = "codex"; + maintainers = with lib.maintainers; [ + malo + delafthi + ]; + platforms = lib.platforms.unix; + }; +}) diff --git a/skills/nix-packaging/rust/rust.md b/skills/nix-packaging/rust/rust.md new file mode 100644 index 0000000..e3b398b --- /dev/null +++ b/skills/nix-packaging/rust/rust.md @@ -0,0 +1,14 @@ +# Packaging Rust Applications with Nix + +See [codex](./codex/package.nix) for an example. + +## Updating an Existing Rust Package + +Besides the general update steps, also update the `cargoHash`: + +```bash +# Set cargoHash = ""; then run nix build +# Nix will fail and show: "got: sha256-XXXXX" +``` + +If `Cargo.toml` dependencies changed, the build will automatically fetch new dependencies after you update the `cargoHash`.