Conversation
- Detect $CLAUDECODE (not $CLAUDE_CODE) and include version in agent string (e.g. "Claude-Code/2.1.41") - Auto-detect model from $ANTHROPIC_MODEL env var - Add shared resolveAgent/resolveModel helpers in detect-agent.ts - Bump hook to v3 with CLAUDECODE + ANTHROPIC_MODEL detection - Make init extraction opt-in via --extract flag (no longer runs by default) - Keep $CLAUDE_CODE and $GIT_MEM_* as explicit overrides for backward compat Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> AI-Agent: Claude-Code/2.1.41 AI-Model: claude-opus-4-6
…GIT-73) - Replace --extract/--commit-count CLI flags with interactive prompts - Add `npm run package` script for .tgz builds into releases/ - Improve reinstall-global.sh with proper packaging workflow - Update docs to reflect simplified init options Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> AI-Agent: Claude-Code/2.1.41 AI-Model: claude-opus-4-6
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughAdds an interactive extraction flow to init (new --extract and numeric --commit-count), centralizes AI agent/model detection in a new module, updates remember-related code to use resolvers, enhances prepare-commit-msg detection (CLAUDEDECODE / ANTHROPIC_MODEL, fingerprint v3), and adds packaging/npm scripts plus related tests and CI helpers. Changes
Sequence Diagram(s)mermaid Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR introduces auto-detection for AI agent and model from Claude Code environment variables, upgrades the prepare-commit-msg hook to v3, and reworks the init command to use interactive prompts instead of CLI flags.
Changes:
- Auto-detects AI agent from
$CLAUDECODE(with version lookup viaclaude --version) and$ANTHROPIC_MODEL, with fallbacks to legacy$CLAUDE_CODEand explicit user-defined variables - Creates shared
detect-agent.tsutility centralizing agent/model resolution logic across CLI and MCP - Reworks
git-mem initto present interactive prompts for better UX, removing--commit-countCLI flag in favor of guided selection
Reviewed changes
Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/infrastructure/detect-agent.ts | New shared utility for agent/model detection with priority chains: GIT_MEM_AGENT > CLAUDECODE > CLAUDE_CODE, and GIT_MEM_MODEL > ANTHROPIC_MODEL |
| src/hooks/prepare-commit-msg.ts | Upgraded to v3 with CLAUDECODE version detection and ANTHROPIC_MODEL support; mirrors TypeScript detection logic in shell |
| src/commands/remember.ts | Refactored to use shared resolveAgent/resolveModel utilities instead of inline detection logic |
| src/mcp/tools/remember.ts | Updated to use shared resolveAgent/resolveModel utilities for consistent behavior across CLI and MCP |
| src/commands/init.ts | Removed --commit-count flag; added interactive prompts for Claude integration, extraction opt-in, and commit count selection |
| src/cli.ts | Updated CLI option descriptions to reference new CLAUDECODE and ANTHROPIC_MODEL env vars |
| tests/unit/hooks/prepare-commit-msg.test.ts | Updated hook version checks to v3, added tests for CLAUDECODE and ANTHROPIC_MODEL detection |
| package.json | Added package script for creating .tgz releases in releases/ directory |
| scripts/reinstall-global.sh | Enhanced with proper packaging workflow, better output formatting, and installation verification |
| docs/getting-started.md | Removed --commit-count option documentation to match new interactive prompt approach |
| .gitignore | Added releases/ directory to ignore packaged .tgz files |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| /** | ||
| * Detect AI agent and model from environment variables. | ||
| * | ||
| * Agent detection chain: $GIT_MEM_AGENT > $CLAUDECODE (with version) > $CLAUDE_CODE | ||
| * Model detection chain: $GIT_MEM_MODEL > $ANTHROPIC_MODEL | ||
| */ | ||
|
|
||
| import { execFileSync } from 'child_process'; | ||
|
|
||
| /** | ||
| * Detect Claude Code agent string including version. | ||
| * Returns e.g. "Claude-Code/2.1.41" or "Claude-Code" if version unavailable. | ||
| */ | ||
| export function detectClaudeAgent(): string { | ||
| try { | ||
| // Unset CLAUDECODE so `claude --version` doesn't refuse to run inside a session | ||
| const version = execFileSync('claude', ['--version'], { | ||
| encoding: 'utf8', | ||
| env: { ...process.env, CLAUDECODE: '' }, | ||
| timeout: 3000, | ||
| stdio: ['pipe', 'pipe', 'pipe'], | ||
| }).trim().split(/\s+/)[0]; | ||
| if (version) return `Claude-Code/${version}`; | ||
| } catch { | ||
| // claude binary not found or timed out — fall back | ||
| } | ||
| return 'Claude-Code'; | ||
| } | ||
|
|
||
| /** | ||
| * Resolve the AI agent string from env vars. | ||
| * @param explicit Optional explicit value (from CLI flag or MCP param) | ||
| */ | ||
| export function resolveAgent(explicit?: string): string | undefined { | ||
| if (explicit) return explicit; | ||
| if (process.env.GIT_MEM_AGENT) return process.env.GIT_MEM_AGENT; | ||
| if (process.env.CLAUDECODE) return detectClaudeAgent(); | ||
| if (process.env.CLAUDE_CODE) return 'Claude-Code'; | ||
| return undefined; | ||
| } | ||
|
|
||
| /** | ||
| * Resolve the AI model string from env vars. | ||
| * @param explicit Optional explicit value (from CLI flag or MCP param) | ||
| */ | ||
| export function resolveModel(explicit?: string): string | undefined { | ||
| if (explicit) return explicit; | ||
| return process.env.GIT_MEM_MODEL || process.env.ANTHROPIC_MODEL || undefined; | ||
| } |
There was a problem hiding this comment.
The new detect-agent.ts module introduces critical agent and model resolution logic used across CLI and MCP tools, but has no accompanying unit tests. Given that other infrastructure utilities in this codebase have comprehensive test coverage (as seen in tests/unit/infrastructure/), tests should be added for:
resolveAgent()- test the priority chain: explicit > GIT_MEM_AGENT > CLAUDECODE > CLAUDE_CODEresolveModel()- test the priority chain: explicit > GIT_MEM_MODEL > ANTHROPIC_MODELdetectClaudeAgent()- test both successful version detection and fallback behavior when theclaudebinary is unavailable or times out
The integration tests in prepare-commit-msg.test.ts partially cover this functionality through the hook, but direct unit tests would provide better isolation and faster feedback for this shared utility.
| "test:unit": "node -e \"const {globSync}=require('glob');const {spawnSync}=require('child_process');const files=globSync('tests/unit/**/*.test.ts');if(!files.length){console.log('No test files found');process.exit(0);}const r=spawnSync('node',['--import','tsx','--test',...files],{stdio:'inherit'});process.exit(r.status===0||r.status===2?0:r.status)\"", | ||
| "test:integration": "node -e \"const {globSync}=require('glob');const {spawnSync}=require('child_process');const files=globSync('tests/integration/**/*.test.ts');if(!files.length){console.log('No test files found');process.exit(0);}const r=spawnSync('node',['--import','tsx','--test',...files],{stdio:'inherit'});process.exit(r.status===0||r.status===2?0:r.status)\"" | ||
| "test:integration": "node -e \"const {globSync}=require('glob');const {spawnSync}=require('child_process');const files=globSync('tests/integration/**/*.test.ts');if(!files.length){console.log('No test files found');process.exit(0);}const r=spawnSync('node',['--import','tsx','--test',...files],{stdio:'inherit'});process.exit(r.status===0||r.status===2?0:r.status)\"", | ||
| "package": "rm -f *.tgz releases/*.tgz && npm run build && mkdir -p releases && npm pack && mv *.tgz releases/" |
There was a problem hiding this comment.
The package script uses Unix-specific commands (rm -f, mkdir -p) that won't work on Windows without additional tooling. Consider using cross-platform alternatives:
- Replace
rm -fwithrimraf(already a dev dependency) - Replace
mkdir -pwith a cross-platform solution or just rely on npm pack to work in the current directory
For example:
"package": "rimraf *.tgz releases/*.tgz && npm run build && npm pack && node -e \"const fs=require('fs');fs.mkdirSync('releases',{recursive:true});const pkg=fs.readdirSync('.').find(f=>f.endsWith('.tgz'));if(pkg)fs.renameSync(pkg,'releases/'+pkg)\""Or more simply, use a cross-platform build tool like npm-run-all or create a Node.js script in scripts/package.js.
| "package": "rm -f *.tgz releases/*.tgz && npm run build && mkdir -p releases && npm pack && mv *.tgz releases/" | |
| "package": "rimraf *.tgz releases/*.tgz && npm run build && npm pack && node -e \"const fs=require('fs');fs.mkdirSync('releases',{recursive:true});const pkg=fs.readdirSync('.').find(f=>f.endsWith('.tgz'));if(pkg)fs.renameSync(pkg,'releases/'+pkg);\"" |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@scripts/reinstall-global.sh`:
- Around line 26-30: Replace the fragile ls-based assignment for PACKAGE_FILE
with a safe find-based pipeline: use find to list .tgz files in RELEASES_DIR
(restrict to files, maxdepth 1), feed results through a null-safe xargs/ls or
use find's mtime output sorted to pick the newest file, then assign that path to
PACKAGE_FILE; update the logic around PACKAGE_FILE and keep the existing error
check intact (references: PACKAGE_FILE, RELEASES_DIR, the current ls -t usage
and the npm pack produced .tgz files).
In `@src/commands/init.ts`:
- Around line 132-170: The init flow currently only sets runExtract and
commitCount from prompts, so in non-interactive mode (--yes) there's no way to
enable extraction; add explicit CLI options (e.g., options.extract:boolean and
options.commitCount:number) to IInitCommandOptions, wire them into the init
handler so that when options.extract is true you set runExtract =
options.extract and commitCount = options.commitCount (with sensible defaults),
and update the CLI option definitions so the flags are parsed and passed into
the init command; ensure references to runExtract, commitCount, and
IInitCommandOptions are used so the non-interactive path behaves the same as the
prompted path.
In `@tests/unit/hooks/prepare-commit-msg.test.ts`:
- Around line 231-239: In the "should add AI-Agent trailer with version when
CLAUDECODE is set" test, replace setting GIT_MEM_AGENT: '' in the execFileSync
env with the same pattern used elsewhere: clone process.env into a local env
object and remove the key via delete env.GIT_MEM_AGENT before passing it to
execFileSync; this keeps behavior identical but standardizes cleanup and matches
the delete env.GIT_MEM_AGENT usage seen later in the test.
| PACKAGE_FILE=$(ls -t "$RELEASES_DIR"/*.tgz 2>/dev/null | head -1) | ||
| if [ -z "$PACKAGE_FILE" ]; then | ||
| echo "Error: No .tgz file found in $RELEASES_DIR" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Minor: ls parsing caveat acknowledged.
The static analysis tool (SC2012) suggests using find instead of ls for safer filename handling. However, since npm pack produces predictable filenames (git-mem-X.Y.Z.tgz), the ls -t approach is acceptable here. The error handling for missing packages is good.
If you want stricter compliance, consider:
♻️ Optional alternative using find
-PACKAGE_FILE=$(ls -t "$RELEASES_DIR"/*.tgz 2>/dev/null | head -1)
+PACKAGE_FILE=$(find "$RELEASES_DIR" -maxdepth 1 -name '*.tgz' -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| PACKAGE_FILE=$(ls -t "$RELEASES_DIR"/*.tgz 2>/dev/null | head -1) | |
| if [ -z "$PACKAGE_FILE" ]; then | |
| echo "Error: No .tgz file found in $RELEASES_DIR" | |
| exit 1 | |
| fi | |
| PACKAGE_FILE=$(find "$RELEASES_DIR" -maxdepth 1 -name '*.tgz' -printf '%T@ %p\n' 2>/dev/null | sort -rn | head -1 | cut -d' ' -f2-) | |
| if [ -z "$PACKAGE_FILE" ]; then | |
| echo "Error: No .tgz file found in $RELEASES_DIR" | |
| exit 1 | |
| fi |
🧰 Tools
🪛 Shellcheck (0.11.0)
[info] 26-26: Use find instead of ls to better handle non-alphanumeric filenames.
(SC2012)
🤖 Prompt for AI Agents
In `@scripts/reinstall-global.sh` around lines 26 - 30, Replace the fragile
ls-based assignment for PACKAGE_FILE with a safe find-based pipeline: use find
to list .tgz files in RELEASES_DIR (restrict to files, maxdepth 1), feed results
through a null-safe xargs/ls or use find's mtime output sorted to pick the
newest file, then assign that path to PACKAGE_FILE; update the logic around
PACKAGE_FILE and keep the existing error check intact (references: PACKAGE_FILE,
RELEASES_DIR, the current ls -t usage and the npm pack produced .tgz files).
| let runExtract = false; | ||
| let commitCount = 10; | ||
|
|
||
| if (!options.yes) { | ||
| const response = await prompts([ | ||
| { | ||
| type: 'number', | ||
| name: 'commitCount', | ||
| message: 'How many commits to free?', | ||
| initial: commitCount, | ||
| }, | ||
| { | ||
| type: 'confirm', | ||
| name: 'claudeIntegration', | ||
| message: 'Integrate with Claude Code?', | ||
| initial: true, | ||
| }, | ||
| { | ||
| type: 'confirm', | ||
| name: 'runExtract', | ||
| message: 'Extract knowledge from commit history?', | ||
| initial: false, | ||
| }, | ||
| { | ||
| type: (prev) => prev ? 'select' : null, | ||
| name: 'commitCount', | ||
| message: 'How many commits to extract?', | ||
| choices: [ | ||
| { title: '10', value: 10 }, | ||
| { title: '30', value: 30 }, | ||
| { title: '50', value: 50 }, | ||
| ], | ||
| initial: 0, | ||
| }, | ||
| ], { | ||
| onCancel: () => { | ||
| console.log('\nSetup cancelled.'); | ||
| process.exit(0); | ||
| }, | ||
| }); | ||
|
|
||
| commitCount = response.commitCount ?? commitCount; | ||
| claudeIntegration = response.claudeIntegration ?? true; | ||
| runExtract = response.runExtract ?? false; | ||
| commitCount = response.commitCount ?? 10; | ||
| } |
There was a problem hiding this comment.
Non-interactive init can’t opt into extraction.
With --yes, prompts are skipped and runExtract stays false, but there’s no CLI option to enable extraction. This blocks automation and CI flows that previously could run extraction via flags. Consider adding an explicit option (e.g., --extract plus an optional commit count) and wiring it through IInitCommandOptions.
💡 One possible wiring (init.ts)
interface IInitCommandOptions {
yes?: boolean;
hooks?: boolean;
uninstallHooks?: boolean;
+ extract?: boolean;
+ commitCount?: number;
}
@@
- let runExtract = false;
- let commitCount = 10;
+ let runExtract = options.extract ?? false;
+ let commitCount = options.commitCount ?? 10;
@@
- if (!options.yes) {
+ if (!options.yes && options.extract === undefined) {
const response = await prompts([
@@
runExtract = response.runExtract ?? false;
commitCount = response.commitCount ?? 10;
}You’ll also need to expose the CLI options in src/cli.ts to supply extract and commitCount.
Also applies to: 224-255
🤖 Prompt for AI Agents
In `@src/commands/init.ts` around lines 132 - 170, The init flow currently only
sets runExtract and commitCount from prompts, so in non-interactive mode (--yes)
there's no way to enable extraction; add explicit CLI options (e.g.,
options.extract:boolean and options.commitCount:number) to IInitCommandOptions,
wire them into the init handler so that when options.extract is true you set
runExtract = options.extract and commitCount = options.commitCount (with
sensible defaults), and update the CLI option definitions so the flags are
parsed and passed into the init command; ensure references to runExtract,
commitCount, and IInitCommandOptions are used so the non-interactive path
behaves the same as the prompted path.
- Add unit tests for detect-agent.ts (16 tests) - Add --extract and --commit-count CLI options for non-interactive init - Fix cross-platform package script using node/glob instead of Unix commands - Use consistent `delete env.VAR` pattern in prepare-commit-msg tests Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> AI-Agent: Claude-Code/2.1.42 AI-Model: claude-opus-4-5-20251101
Addressed Review Comments✅ detect-agent.ts — Added 16 unit tests covering ✅ package.json — Fixed cross-platform compatibility by replacing Unix commands ( ✅ init.ts — Added git-mem init --yes --extract --commit-count 50✅ prepare-commit-msg.test.ts — Fixed test cleanup to use consistent All 390 tests passing. |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/unit/hooks/prepare-commit-msg.test.ts (1)
249-264: 🧹 Nitpick | 🔵 TrivialMinor inconsistency: uses
GIT_MEM_AGENT: ''instead ofdelete.For consistency with the pattern established at line 236, consider using
delete env.GIT_MEM_AGENThere as well. However, this is a minor stylistic point—the empty string approach works correctly since the production code treats empty strings as falsy.♻️ Optional consistency fix
- const env = { ...process.env, CLAUDE_CODE: '1', GIT_MEM_AGENT: '' }; + const env = { ...process.env, CLAUDE_CODE: '1' }; + delete env.GIT_MEM_AGENT; delete env.CLAUDECODE;
🤖 Fix all issues with AI agents
In `@src/commands/init.ts`:
- Around line 134-135: Validate the parsed commitCount after reading options
(where runExtract and commitCount are set from options) to guard against NaN or
non-positive values before calling extractService.extract(); specifically, check
that commitCount is a finite integer (e.g., Number.isInteger and isFinite) and
within an acceptable range (>0), and if invalid either set a sensible default
(like 10) or throw a clear error/exit with a message indicating the invalid
--commit-count value so extractService.extract() never receives NaN.
Fallback to default of 10 when --commit-count receives invalid input. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> AI-Agent: Claude-Code/2.1.42 AI-Model: claude-opus-4-5-20251101
|
✅ Added |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In `@src/commands/init.ts`:
- Around line 231-242: The code only calls readEnvApiKey(cwd) to get
ANTHROPIC_API_KEY which ignores a key already set in the user's shell; update
the logic around runExtract to first check process.env.ANTHROPIC_API_KEY and use
that if present, otherwise call readEnvApiKey(cwd) as a fallback, then set the
enrich flag based on the resulting apiKey and assign
process.env.ANTHROPIC_API_KEY = apiKey when enrichment is enabled; adjust
references in the block using enrich and apiKey (the runExtract branch,
readEnvApiKey call, enrich variable and assignment to
process.env.ANTHROPIC_API_KEY) accordingly.
| // ── Extract from history ───────────────────────────────────── | ||
| if (runExtract) { | ||
| const apiKey = readEnvApiKey(cwd); | ||
| const enrich = !!apiKey; | ||
|
|
||
| if (apiKey) { | ||
| process.env.ANTHROPIC_API_KEY = apiKey; | ||
| console.log(`Extracting knowledge from ${commitCount} commits with LLM enrichment...`); | ||
| if (enrich) { | ||
| process.env.ANTHROPIC_API_KEY = apiKey; | ||
| console.log(`\nExtracting knowledge from ${commitCount} commits with LLM enrichment...`); | ||
| } else { | ||
| console.log(`\nExtracting knowledge from ${commitCount} commits (heuristic only)...`); | ||
| } | ||
|
|
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider checking process.env.ANTHROPIC_API_KEY before reading from .env file.
The current implementation only reads from .env file (via readEnvApiKey), but users might have ANTHROPIC_API_KEY set in their shell environment. This could cause confusion if the environment variable is set but enrichment doesn't activate because .env is empty.
♻️ Proposed fix to check environment first
// ── Extract from history ─────────────────────────────────────
if (runExtract) {
- const apiKey = readEnvApiKey(cwd);
+ const apiKey = process.env.ANTHROPIC_API_KEY || readEnvApiKey(cwd);
const enrich = !!apiKey;
if (enrich) {
- process.env.ANTHROPIC_API_KEY = apiKey;
+ if (!process.env.ANTHROPIC_API_KEY) {
+ process.env.ANTHROPIC_API_KEY = apiKey;
+ }
console.log(`\nExtracting knowledge from ${commitCount} commits with LLM enrichment...`);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| // ── Extract from history ───────────────────────────────────── | |
| if (runExtract) { | |
| const apiKey = readEnvApiKey(cwd); | |
| const enrich = !!apiKey; | |
| if (apiKey) { | |
| process.env.ANTHROPIC_API_KEY = apiKey; | |
| console.log(`Extracting knowledge from ${commitCount} commits with LLM enrichment...`); | |
| if (enrich) { | |
| process.env.ANTHROPIC_API_KEY = apiKey; | |
| console.log(`\nExtracting knowledge from ${commitCount} commits with LLM enrichment...`); | |
| } else { | |
| console.log(`\nExtracting knowledge from ${commitCount} commits (heuristic only)...`); | |
| } | |
| // ── Extract from history ───────────────────────────────────── | |
| if (runExtract) { | |
| const apiKey = process.env.ANTHROPIC_API_KEY || readEnvApiKey(cwd); | |
| const enrich = !!apiKey; | |
| if (enrich) { | |
| if (!process.env.ANTHROPIC_API_KEY) { | |
| process.env.ANTHROPIC_API_KEY = apiKey; | |
| } | |
| console.log(`\nExtracting knowledge from ${commitCount} commits with LLM enrichment...`); | |
| } else { | |
| console.log(`\nExtracting knowledge from ${commitCount} commits (heuristic only)...`); | |
| } |
🤖 Prompt for AI Agents
In `@src/commands/init.ts` around lines 231 - 242, The code only calls
readEnvApiKey(cwd) to get ANTHROPIC_API_KEY which ignores a key already set in
the user's shell; update the logic around runExtract to first check
process.env.ANTHROPIC_API_KEY and use that if present, otherwise call
readEnvApiKey(cwd) as a fallback, then set the enrich flag based on the
resulting apiKey and assign process.env.ANTHROPIC_API_KEY = apiKey when
enrichment is enabled; adjust references in the block using enrich and apiKey
(the runExtract branch, readEnvApiKey call, enrich variable and assignment to
process.env.ANTHROPIC_API_KEY) accordingly.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 12 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
$CLAUDECODE,$ANTHROPIC_MODEL)CLAUDECODEdetection, Claude version lookup, andANTHROPIC_MODELsupportdetect-agent.tsutility for consistent env var resolution across CLI and MCPgit-mem initto use interactive prompts instead of--extract/--commit-countCLI flagsnpm run packagescript for .tgz builds intoreleases/reinstall-global.shwith proper packaging workflowTest plan
npm test)AI-Agent: Claude-Code/2.1.41,AI-Model: claude-opus-4-6🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Documentation
Improvements
Tests