834cf4095e
- Implemented context-hook.ts for handling session start events. - Created new-hook.ts for user prompt submission events. - Developed save-hook.ts for post tool use events. - Added summary-hook.ts for handling stop events. - Introduced worker.ts as a standalone background process for the SDK agent. - Each hook reads input from stdin, processes it, and handles errors gracefully.
309 lines
7.6 KiB
Markdown
309 lines
7.6 KiB
Markdown
# Plugin Development Guide
|
|
|
|
This guide helps developers work with the claude-mem plugin structure during development.
|
|
|
|
## Quick Start
|
|
|
|
### 1. Build the Plugin
|
|
|
|
```bash
|
|
# Build both CLI and hooks
|
|
npm run build
|
|
|
|
# Or build separately
|
|
npm run build:cli # Just the CLI
|
|
npm run build:hooks # Just the hooks
|
|
```
|
|
|
|
### 2. Test Hooks Locally
|
|
|
|
Test individual hooks by piping JSON input:
|
|
|
|
```bash
|
|
# Test context hook (SessionStart)
|
|
printf '{"session_id":"test-123","cwd":"/Users/you/project","source":"startup"}' | \
|
|
bun scripts/hooks/context-hook.js
|
|
|
|
# Test new hook (UserPromptSubmit)
|
|
printf '{"session_id":"test-123","cwd":"/Users/you/project","prompt":"help me code"}' | \
|
|
bun scripts/hooks/new-hook.js
|
|
|
|
# Test save hook (PostToolUse)
|
|
printf '{"session_id":"test-123","cwd":"/Users/you/project","tool_name":"Read","tool_input":{},"tool_output":{}}' | \
|
|
bun scripts/hooks/save-hook.js
|
|
|
|
# Test summary hook (Stop)
|
|
printf '{"session_id":"test-123","cwd":"/Users/you/project"}' | \
|
|
bun scripts/hooks/summary-hook.js
|
|
|
|
# Test worker (requires valid session ID in database)
|
|
bun scripts/hooks/worker.js 999
|
|
```
|
|
|
|
### 3. Test Worker with Plugin Root
|
|
|
|
Verify the new-hook correctly detects plugin mode:
|
|
|
|
```bash
|
|
# Without CLAUDE_PLUGIN_ROOT (traditional mode)
|
|
printf '{"session_id":"test-new","cwd":"/path","prompt":"test"}' | \
|
|
bun scripts/hooks/new-hook.js
|
|
|
|
# With CLAUDE_PLUGIN_ROOT (plugin mode)
|
|
CLAUDE_PLUGIN_ROOT=$(pwd) printf '{"session_id":"test-plugin","cwd":"/path","prompt":"test"}' | \
|
|
bun scripts/hooks/new-hook.js
|
|
```
|
|
|
|
In plugin mode, the new-hook will attempt to spawn `bun ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/worker.js`.
|
|
In traditional mode, it will attempt to spawn `claude-mem worker`.
|
|
|
|
### 4. Test With No Input
|
|
|
|
Each hook should handle missing input gracefully:
|
|
|
|
```bash
|
|
echo '' | bun scripts/hooks/context-hook.js
|
|
# Output: No input provided - this script is designed to run as a Claude Code SessionStart hook
|
|
```
|
|
|
|
## Local Plugin Testing
|
|
|
|
### Option 1: Dev Marketplace (Recommended)
|
|
|
|
Create a development marketplace to test your plugin:
|
|
|
|
```bash
|
|
# Create marketplace structure
|
|
mkdir -p ~/dev-marketplace/.claude-plugin
|
|
|
|
# Create marketplace manifest
|
|
cat > ~/dev-marketplace/.claude-plugin/marketplace.json << 'EOF'
|
|
{
|
|
"name": "dev-marketplace",
|
|
"owner": {
|
|
"name": "Developer"
|
|
},
|
|
"plugins": [
|
|
{
|
|
"name": "claude-mem",
|
|
"source": "./claude-mem-plugin",
|
|
"description": "Persistent memory system for Claude Code"
|
|
}
|
|
]
|
|
}
|
|
EOF
|
|
|
|
# Symlink your working directory
|
|
ln -s /path/to/your/claude-mem ~/dev-marketplace/claude-mem-plugin
|
|
```
|
|
|
|
Then in Claude Code:
|
|
|
|
```
|
|
/plugin marketplace add /absolute/path/to/dev-marketplace
|
|
/plugin install claude-mem@dev-marketplace
|
|
```
|
|
|
|
### Option 2: Direct Testing
|
|
|
|
Test the CLI commands directly:
|
|
|
|
```bash
|
|
# Build first
|
|
npm run build
|
|
|
|
# Test CLI commands
|
|
./dist/claude-mem.min.js --version
|
|
./dist/claude-mem.min.js status
|
|
./dist/claude-mem.min.js --help
|
|
```
|
|
|
|
## Development Workflow
|
|
|
|
### Making Changes to Hooks
|
|
|
|
1. **Edit TypeScript source** in `src/hooks/` or `src/bin/hooks/`
|
|
2. **Rebuild hooks**: `npm run build:hooks`
|
|
3. **Test locally**: Use echo piping method above
|
|
4. **Reinstall plugin** (if testing in Claude Code):
|
|
```
|
|
/plugin uninstall claude-mem@dev-marketplace
|
|
/plugin install claude-mem@dev-marketplace
|
|
```
|
|
|
|
### Making Changes to CLI
|
|
|
|
1. **Edit TypeScript source** in `src/`
|
|
2. **Rebuild CLI**: `npm run build:cli`
|
|
3. **Test directly**: `./dist/claude-mem.min.js [command]`
|
|
|
|
### Making Changes to Commands
|
|
|
|
1. **Edit markdown files** in `commands/`
|
|
2. **No rebuild needed** (commands are read directly)
|
|
3. **Reinstall plugin** to pick up changes:
|
|
```
|
|
/plugin uninstall claude-mem@dev-marketplace
|
|
/plugin install claude-mem@dev-marketplace
|
|
```
|
|
|
|
## Debugging
|
|
|
|
### Enable Verbose Logging
|
|
|
|
Set environment variables for more detailed output:
|
|
|
|
```bash
|
|
DEBUG=claude-mem:* bun scripts/hooks/context-hook.js
|
|
```
|
|
|
|
### Check Hook Output
|
|
|
|
Hooks write to stdout/stderr. Capture output:
|
|
|
|
```bash
|
|
echo '{"session_id":"test","cwd":"/path"}' | \
|
|
bun scripts/hooks/context-hook.js 2>&1 | tee hook-output.log
|
|
```
|
|
|
|
### Verify Plugin Root Variable
|
|
|
|
Test that `${CLAUDE_PLUGIN_ROOT}` resolves correctly:
|
|
|
|
```bash
|
|
# Manually set it for testing
|
|
export CLAUDE_PLUGIN_ROOT=/path/to/your/plugin
|
|
echo '{"session_id":"test","cwd":"/path"}' | \
|
|
bun ${CLAUDE_PLUGIN_ROOT}/scripts/hooks/context-hook.js
|
|
```
|
|
|
|
## Build System Details
|
|
|
|
### Hook Build Process
|
|
|
|
The `scripts/build-hooks.js` script:
|
|
1. Reads each entry point from `src/bin/hooks/`
|
|
2. Bundles with Bun build system
|
|
3. Minifies output
|
|
4. Adds shebang for direct execution
|
|
5. Sets executable permissions
|
|
6. Outputs to `scripts/hooks/`
|
|
|
|
### CLI Build Process
|
|
|
|
The `scripts/build.js` script:
|
|
1. Bundles main CLI from `src/bin/cli.ts`
|
|
2. Externalizes large dependencies
|
|
3. Minifies output
|
|
4. Adds shebang
|
|
5. Sets executable permissions
|
|
6. Outputs to `dist/claude-mem.min.js`
|
|
|
|
### Build Configuration
|
|
|
|
Both builds use similar Bun configuration:
|
|
- **Target**: `bun` runtime
|
|
- **Minify**: `true`
|
|
- **External**: `bun:sqlite` (native module)
|
|
- **Define**: `__DEFAULT_PACKAGE_VERSION__` from package.json
|
|
|
|
## Testing
|
|
|
|
### Run Tests
|
|
|
|
```bash
|
|
bun test tests/
|
|
```
|
|
|
|
### Test Database Operations
|
|
|
|
```bash
|
|
# Test hooks database
|
|
bun test tests/hooks-database-integration.test.ts
|
|
|
|
# Test session lifecycle
|
|
bun test tests/session-lifecycle.test.ts
|
|
```
|
|
|
|
## Publishing
|
|
|
|
### Pre-publish Checklist
|
|
|
|
- [ ] All tests pass: `bun test tests/`
|
|
- [ ] Build succeeds: `npm run build`
|
|
- [ ] Version updated in `package.json`
|
|
- [ ] Changelog updated in `docs/CHANGELOG.md`
|
|
- [ ] Plugin.json version matches package.json
|
|
- [ ] Hooks tested locally
|
|
- [ ] CLI tested locally
|
|
|
|
### Publish to npm
|
|
|
|
```bash
|
|
npm run publish:npm
|
|
```
|
|
|
|
This will:
|
|
1. Run `prepublishOnly` script (builds everything)
|
|
2. Publish to npm registry
|
|
3. Include files listed in `package.json` "files" array
|
|
|
|
### Files Included in Package
|
|
|
|
The npm package includes:
|
|
- `dist/` - Compiled CLI
|
|
- `scripts/` - Compiled hooks
|
|
- `commands/` - Slash command definitions
|
|
- `hooks/` - Hook configuration
|
|
- `.claude-plugin/` - Plugin metadata
|
|
- `src/` - TypeScript source (for reference)
|
|
- `docs/` - Documentation
|
|
- `.mcp.json` - MCP server configuration
|
|
|
|
## Troubleshooting
|
|
|
|
### Build Fails
|
|
|
|
**Problem**: `bun: command not found`
|
|
**Solution**: Install Bun from https://bun.sh
|
|
|
|
**Problem**: Build errors with external dependencies
|
|
**Solution**: Check that `bun:sqlite` is not bundled (should be external)
|
|
|
|
### Hooks Don't Execute
|
|
|
|
**Problem**: `Permission denied` when executing hooks
|
|
**Solution**: Ensure scripts are executable: `chmod +x scripts/hooks/*.js`
|
|
|
|
**Problem**: Hooks exit silently
|
|
**Solution**: Check error handling - hooks catch all errors and exit gracefully
|
|
|
|
### Plugin Not Found
|
|
|
|
**Problem**: `/plugin install` can't find claude-mem
|
|
**Solution**:
|
|
1. Verify marketplace is added: `/plugin marketplace list`
|
|
2. Check marketplace manifest includes claude-mem
|
|
3. Refresh marketplace: `/plugin marketplace refresh`
|
|
|
|
## Tips
|
|
|
|
1. **Use symlinks** in dev marketplace for faster iteration
|
|
2. **Test hooks with edge cases** (empty input, malformed JSON)
|
|
3. **Check file sizes** after build to catch bloat
|
|
4. **Version everything together** (CLI, hooks, plugin.json)
|
|
5. **Document breaking changes** in CHANGELOG.md
|
|
|
|
## Resources
|
|
|
|
- [Plugin Structure Documentation](./PLUGIN_STRUCTURE.md)
|
|
- [Plugin Installation Guide](./PLUGIN_INSTALLATION.md)
|
|
- [Build Documentation](./BUILD.md)
|
|
- [Claude Code Plugins Docs](https://docs.claude.com/en/docs/claude-code/plugins)
|
|
- [Bun Documentation](https://bun.sh/docs)
|
|
|
|
## Getting Help
|
|
|
|
- **Issues**: https://github.com/thedotmack/claude-mem/issues
|
|
- **Discussions**: https://github.com/thedotmack/claude-mem/discussions
|