diff --git a/.agents/skills/.gitkeep b/.agents/skills/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/.claude/skills b/.claude/skills new file mode 120000 index 0000000..2b7a412 --- /dev/null +++ b/.claude/skills @@ -0,0 +1 @@ +../.agents/skills \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..863a5a0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,40 @@ +# AGENTS.md + +Instructions for AI coding agents working in this repository. This file is the source of truth; tool-specific files (e.g. CLAUDE.md) should only import it. + +## Project Overview + +`@mongodb-js/zstd` is a Node.js native addon exposing [Zstandard](https://github.com/facebook/zstd) `compress`/`decompress` as async functions. It is used by the MongoDB Node.js driver to compress wire-protocol messages. The C++ addon is built with node-gyp against a vendored zstd static library. On install, `prebuild-install` looks for a *local* cached addon binary (no remote is configured in package.json `binary`), falling back to a source build. + +## Commands + +- `npm run clean-install` — download zstd into `deps/` and compile the addon (required before testing after a fresh clone). +- `npm run compile` — recompile the addon only. +- `npm test` — run mocha tests (`test/*.js`); requires a compiled addon. +- `npm run check:eslint` — lint JS/TS. +- `npm run check:clang-format` — check C++ formatting; `npm run clang-format` to fix. + +## Structure + +- `addon/` — C++ addon files. `zstd.cpp` implements the N-API `compress`/`decompress` bindings, `compression.{h,cpp}` defines/implements the wrappers leveraging zstd. `compression_worker.h` holds the 'async' component of the wrapper fns. +- `lib/index.js` — The entrypoint. Loads the compiled `.node` binary and exports promise-based wrappers. +- `index.d.ts` — The public types. +- `deps/` — vendored zstd sources (version pinned by `mongodb:zstd_version` in package.json). Populated by `etc/install-zstd.sh`, untracked. +- `build/` — node-gyp output, holds .node files to be imported in index.js. +- `test/` — mocha tests, plus `test/bundling/webpack` for bundler compatibility. +- `etc/docker.sh` — runs tests in glibc and musl Docker containers. +- `binding.gyp` — node-gyp build config linking the addon against `deps/`. + +## Code Conventions + +- **Null checks** — loose equality (`== null`), not `=== null`/`=== undefined`. +- **Type imports** — inline: `import { type Foo }`. +- **Formatting** — Prettier: single quotes, 2-space indent, 100-char width, no trailing commas. + +## Commit Messages + +- [Conventional Commits](https://www.conventionalcommits.org/) with a Jira ticket: `(NODE-XXXX): ` — types: `feat`, `fix`, `docs`, `style`, `refactor`, `perf`, `test`, `chore`; breaking changes use `!` (e.g. `feat(NODE-XXXX)!: …`). + +## Related Repositories + +- [mongodb/node-mongodb-native](https://github.com/mongodb/node-mongodb-native) — the MongoDB Node.js driver, the primary consumer of this package. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/README.md b/README.md index 6673bcd..c2cdc28 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,18 @@ export function compress(buffer: Buffer | ArrayBuffer | Uint8Array, level: numbe export function decompress(buffer: Buffer): Promise; ``` +## AI Agent Configuration + +This repository uses [agentskills.io](https://agentskills.io) conventions for AI coding agent +instructions. `AGENTS.md` is the canonical source of truth — tool-specific files like `CLAUDE.md` +are generated references. + +### Adding a nested AGENTS.md + +1. Create an `AGENTS.md` in the target directory. +2. Run `scripts/symlink-claude-md.sh` to generate the companion `CLAUDE.md`. +3. Stage and commit both files. + ### Bugs / Feature Requests Think you’ve found a bug? Want to see a new feature in `@mongodb-js/zstd`? Please open a diff --git a/scripts/symlink-claude-md.sh b/scripts/symlink-claude-md.sh new file mode 100755 index 0000000..ef5a465 --- /dev/null +++ b/scripts/symlink-claude-md.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +# 1. Ensure every staged AGENTS.md has a companion CLAUDE.md containing +# "@AGENTS.md" (a Claude Code import reference). +# 2. Ensure .claude/skills is a symlink to .agents/skills. + +set -euo pipefail + +claude_file_for_agents() { + local agents_file="$1" + local dir + + dir=$(dirname "$agents_file") + + if [ "$dir" = "." ]; then + printf 'CLAUDE.md\n' + else + printf '%s/CLAUDE.md\n' "$dir" + fi +} + +remove_generated_file() { + local generated_file="$1" + + if git ls-files --error-unmatch -- "$generated_file" > /dev/null 2>&1 || [ -e "$generated_file" ]; then + rm -f "$generated_file" + git add -u -- "$generated_file" + echo "auto-removed: $generated_file" + fi +} + +sync_claude_skills_dir() { + local claude_skills_dir=".claude/skills" + local expected_target="../.agents/skills" + local current_target + + if [ -L "$claude_skills_dir" ]; then + current_target=$(readlink "$claude_skills_dir") + if [ "$current_target" = "$expected_target" ]; then + return + fi + + rm -f "$claude_skills_dir" + elif [ -e "$claude_skills_dir" ]; then + rm -rf "$claude_skills_dir" + fi + + mkdir -p .claude + ln -s "$expected_target" "$claude_skills_dir" + git add "$claude_skills_dir" + echo "auto-synced: $claude_skills_dir -> $expected_target" +} + +sync_claude_skills_dir + +staged_agents=() +deleted_agents=() + +while IFS=$'\t ' read -r status first_path second_path; do + [ -n "$status" ] || continue + + case "$status" in + R*) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + deleted_agents+=("$first_path") + fi + if [[ "$second_path" =~ (^|/)AGENTS\.md$ ]]; then + staged_agents+=("$second_path") + fi + ;; + D) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + deleted_agents+=("$first_path") + fi + ;; + *) + if [[ "$first_path" =~ (^|/)AGENTS\.md$ ]]; then + staged_agents+=("$first_path") + fi + ;; + esac +done < <(git diff --cached --name-status --find-renames --diff-filter=ADMR) + +# --- CLAUDE.md sync --- +if [ "${#staged_agents[@]}" -gt 0 ]; then + for agents_file in "${staged_agents[@]}"; do + claude_file=$(claude_file_for_agents "$agents_file") + + # Skip if already a regular file with the correct content + if [ -f "$claude_file" ] && ! [ -L "$claude_file" ] && [ "$(cat "$claude_file")" = "@AGENTS.md" ]; then + continue + fi + + # Remove symlink if present, then write the reference file + rm -f "$claude_file" + printf '@AGENTS.md\n' > "$claude_file" + git add "$claude_file" + echo "auto-created: $claude_file with @AGENTS.md reference" + done +fi + +if [ "${#deleted_agents[@]}" -gt 0 ]; then + for agents_file in "${deleted_agents[@]}"; do + remove_generated_file "$(claude_file_for_agents "$agents_file")" + done +fi +