claude-ketchup 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +544 -0
- package/bin/cli.ts +6 -0
- package/bin/postinstall.ts +5 -0
- package/bin/preuninstall.ts +5 -0
- package/commands/ketchup.md +107 -0
- package/dist/bin/cli.d.ts +3 -0
- package/dist/bin/cli.d.ts.map +1 -0
- package/dist/bin/cli.js +7 -0
- package/dist/bin/cli.js.map +1 -0
- package/dist/bin/postinstall.d.ts +3 -0
- package/dist/bin/postinstall.d.ts.map +1 -0
- package/dist/bin/postinstall.js +6 -0
- package/dist/bin/postinstall.js.map +1 -0
- package/dist/bin/preuninstall.d.ts +3 -0
- package/dist/bin/preuninstall.d.ts.map +1 -0
- package/dist/bin/preuninstall.js +6 -0
- package/dist/bin/preuninstall.js.map +1 -0
- package/dist/scripts/pre-tool-use.d.ts +3 -0
- package/dist/scripts/pre-tool-use.d.ts.map +1 -0
- package/dist/scripts/pre-tool-use.js +43 -0
- package/dist/scripts/pre-tool-use.js.map +1 -0
- package/dist/scripts/session-start.d.ts +3 -0
- package/dist/scripts/session-start.d.ts.map +1 -0
- package/dist/scripts/session-start.js +42 -0
- package/dist/scripts/session-start.js.map +1 -0
- package/dist/scripts/user-prompt-submit.d.ts +3 -0
- package/dist/scripts/user-prompt-submit.d.ts.map +1 -0
- package/dist/scripts/user-prompt-submit.js +43 -0
- package/dist/scripts/user-prompt-submit.js.map +1 -0
- package/dist/src/clean-logs.d.ts +6 -0
- package/dist/src/clean-logs.d.ts.map +1 -0
- package/dist/src/clean-logs.js +38 -0
- package/dist/src/clean-logs.js.map +1 -0
- package/dist/src/clean-logs.test.d.ts +2 -0
- package/dist/src/clean-logs.test.d.ts.map +1 -0
- package/dist/src/clean-logs.test.js +101 -0
- package/dist/src/clean-logs.test.js.map +1 -0
- package/dist/src/cli/cli.d.ts +3 -0
- package/dist/src/cli/cli.d.ts.map +1 -0
- package/dist/src/cli/cli.js +24 -0
- package/dist/src/cli/cli.js.map +1 -0
- package/dist/src/cli/cli.test.d.ts +2 -0
- package/dist/src/cli/cli.test.d.ts.map +1 -0
- package/dist/src/cli/cli.test.js +20 -0
- package/dist/src/cli/cli.test.js.map +1 -0
- package/dist/src/cli/doctor.d.ts +7 -0
- package/dist/src/cli/doctor.d.ts.map +1 -0
- package/dist/src/cli/doctor.js +52 -0
- package/dist/src/cli/doctor.js.map +1 -0
- package/dist/src/cli/doctor.test.d.ts +2 -0
- package/dist/src/cli/doctor.test.d.ts.map +1 -0
- package/dist/src/cli/doctor.test.js +77 -0
- package/dist/src/cli/doctor.test.js.map +1 -0
- package/dist/src/cli/repair.d.ts +7 -0
- package/dist/src/cli/repair.d.ts.map +1 -0
- package/dist/src/cli/repair.js +67 -0
- package/dist/src/cli/repair.js.map +1 -0
- package/dist/src/cli/repair.test.d.ts +2 -0
- package/dist/src/cli/repair.test.d.ts.map +1 -0
- package/dist/src/cli/repair.test.js +72 -0
- package/dist/src/cli/repair.test.js.map +1 -0
- package/dist/src/cli/skills.d.ts +11 -0
- package/dist/src/cli/skills.d.ts.map +1 -0
- package/dist/src/cli/skills.js +53 -0
- package/dist/src/cli/skills.js.map +1 -0
- package/dist/src/cli/skills.test.d.ts +2 -0
- package/dist/src/cli/skills.test.d.ts.map +1 -0
- package/dist/src/cli/skills.test.js +89 -0
- package/dist/src/cli/skills.test.js.map +1 -0
- package/dist/src/cli/status.d.ts +10 -0
- package/dist/src/cli/status.d.ts.map +1 -0
- package/dist/src/cli/status.js +63 -0
- package/dist/src/cli/status.js.map +1 -0
- package/dist/src/cli/status.test.d.ts +2 -0
- package/dist/src/cli/status.test.d.ts.map +1 -0
- package/dist/src/cli/status.test.js +70 -0
- package/dist/src/cli/status.test.js.map +1 -0
- package/dist/src/clue-collector.d.ts +23 -0
- package/dist/src/clue-collector.d.ts.map +1 -0
- package/dist/src/clue-collector.js +226 -0
- package/dist/src/clue-collector.js.map +1 -0
- package/dist/src/clue-collector.test.d.ts +2 -0
- package/dist/src/clue-collector.test.d.ts.map +1 -0
- package/dist/src/clue-collector.test.js +213 -0
- package/dist/src/clue-collector.test.js.map +1 -0
- package/dist/src/debug-logger.d.ts +2 -0
- package/dist/src/debug-logger.d.ts.map +1 -0
- package/dist/src/debug-logger.js +23 -0
- package/dist/src/debug-logger.js.map +1 -0
- package/dist/src/debug-logger.test.d.ts +2 -0
- package/dist/src/debug-logger.test.d.ts.map +1 -0
- package/dist/src/debug-logger.test.js +63 -0
- package/dist/src/debug-logger.test.js.map +1 -0
- package/dist/src/deny-list.d.ts +3 -0
- package/dist/src/deny-list.d.ts.map +1 -0
- package/dist/src/deny-list.js +62 -0
- package/dist/src/deny-list.js.map +1 -0
- package/dist/src/deny-list.test.d.ts +2 -0
- package/dist/src/deny-list.test.d.ts.map +1 -0
- package/dist/src/deny-list.test.js +93 -0
- package/dist/src/deny-list.test.js.map +1 -0
- package/dist/src/e2e.test.d.ts +2 -0
- package/dist/src/e2e.test.d.ts.map +1 -0
- package/dist/src/e2e.test.js +88 -0
- package/dist/src/e2e.test.js.map +1 -0
- package/dist/src/gitignore-manager.d.ts +2 -0
- package/dist/src/gitignore-manager.d.ts.map +1 -0
- package/dist/src/gitignore-manager.js +45 -0
- package/dist/src/gitignore-manager.js.map +1 -0
- package/dist/src/gitignore-manager.test.d.ts +2 -0
- package/dist/src/gitignore-manager.test.d.ts.map +1 -0
- package/dist/src/gitignore-manager.test.js +70 -0
- package/dist/src/gitignore-manager.test.js.map +1 -0
- package/dist/src/hook-state.d.ts +43 -0
- package/dist/src/hook-state.d.ts.map +1 -0
- package/dist/src/hook-state.js +124 -0
- package/dist/src/hook-state.js.map +1 -0
- package/dist/src/hook-state.test.d.ts +2 -0
- package/dist/src/hook-state.test.d.ts.map +1 -0
- package/dist/src/hook-state.test.js +190 -0
- package/dist/src/hook-state.test.js.map +1 -0
- package/dist/src/hooks/auto-continue.d.ts +9 -0
- package/dist/src/hooks/auto-continue.d.ts.map +1 -0
- package/dist/src/hooks/auto-continue.js +56 -0
- package/dist/src/hooks/auto-continue.js.map +1 -0
- package/dist/src/hooks/auto-continue.test.d.ts +2 -0
- package/dist/src/hooks/auto-continue.test.d.ts.map +1 -0
- package/dist/src/hooks/auto-continue.test.js +141 -0
- package/dist/src/hooks/auto-continue.test.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.d.ts +8 -0
- package/dist/src/hooks/pre-tool-use.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.js +19 -0
- package/dist/src/hooks/pre-tool-use.js.map +1 -0
- package/dist/src/hooks/pre-tool-use.test.d.ts +2 -0
- package/dist/src/hooks/pre-tool-use.test.d.ts.map +1 -0
- package/dist/src/hooks/pre-tool-use.test.js +84 -0
- package/dist/src/hooks/pre-tool-use.test.js.map +1 -0
- package/dist/src/hooks/session-start.d.ts +6 -0
- package/dist/src/hooks/session-start.d.ts.map +1 -0
- package/dist/src/hooks/session-start.js +49 -0
- package/dist/src/hooks/session-start.js.map +1 -0
- package/dist/src/hooks/session-start.test.d.ts +2 -0
- package/dist/src/hooks/session-start.test.d.ts.map +1 -0
- package/dist/src/hooks/session-start.test.js +96 -0
- package/dist/src/hooks/session-start.test.js.map +1 -0
- package/dist/src/hooks/user-prompt-submit.d.ts +6 -0
- package/dist/src/hooks/user-prompt-submit.d.ts.map +1 -0
- package/dist/src/hooks/user-prompt-submit.js +54 -0
- package/dist/src/hooks/user-prompt-submit.js.map +1 -0
- package/dist/src/hooks/user-prompt-submit.test.d.ts +2 -0
- package/dist/src/hooks/user-prompt-submit.test.d.ts.map +1 -0
- package/dist/src/hooks/user-prompt-submit.test.js +92 -0
- package/dist/src/hooks/user-prompt-submit.test.js.map +1 -0
- package/dist/src/hooks/validate-commit.d.ts +12 -0
- package/dist/src/hooks/validate-commit.d.ts.map +1 -0
- package/dist/src/hooks/validate-commit.js +58 -0
- package/dist/src/hooks/validate-commit.js.map +1 -0
- package/dist/src/hooks/validate-commit.test.d.ts +2 -0
- package/dist/src/hooks/validate-commit.test.d.ts.map +1 -0
- package/dist/src/hooks/validate-commit.test.js +150 -0
- package/dist/src/hooks/validate-commit.test.js.map +1 -0
- package/dist/src/index.d.ts +13 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +38 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/linker.d.ts +6 -0
- package/dist/src/linker.d.ts.map +1 -0
- package/dist/src/linker.js +78 -0
- package/dist/src/linker.js.map +1 -0
- package/dist/src/linker.test.d.ts +2 -0
- package/dist/src/linker.test.d.ts.map +1 -0
- package/dist/src/linker.test.js +192 -0
- package/dist/src/linker.test.js.map +1 -0
- package/dist/src/logger.d.ts +21 -0
- package/dist/src/logger.d.ts.map +1 -0
- package/dist/src/logger.js +117 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/logger.test.d.ts +2 -0
- package/dist/src/logger.test.d.ts.map +1 -0
- package/dist/src/logger.test.js +159 -0
- package/dist/src/logger.test.js.map +1 -0
- package/dist/src/postinstall.d.ts +7 -0
- package/dist/src/postinstall.d.ts.map +1 -0
- package/dist/src/postinstall.js +81 -0
- package/dist/src/postinstall.js.map +1 -0
- package/dist/src/postinstall.test.d.ts +2 -0
- package/dist/src/postinstall.test.d.ts.map +1 -0
- package/dist/src/postinstall.test.js +125 -0
- package/dist/src/postinstall.test.js.map +1 -0
- package/dist/src/preuninstall.d.ts +2 -0
- package/dist/src/preuninstall.d.ts.map +1 -0
- package/dist/src/preuninstall.js +62 -0
- package/dist/src/preuninstall.js.map +1 -0
- package/dist/src/preuninstall.test.d.ts +2 -0
- package/dist/src/preuninstall.test.d.ts.map +1 -0
- package/dist/src/preuninstall.test.js +97 -0
- package/dist/src/preuninstall.test.js.map +1 -0
- package/dist/src/root-finder.d.ts +2 -0
- package/dist/src/root-finder.d.ts.map +1 -0
- package/dist/src/root-finder.js +71 -0
- package/dist/src/root-finder.js.map +1 -0
- package/dist/src/root-finder.test.d.ts +2 -0
- package/dist/src/root-finder.test.d.ts.map +1 -0
- package/dist/src/root-finder.test.js +111 -0
- package/dist/src/root-finder.test.js.map +1 -0
- package/dist/src/settings-merger.d.ts +2 -0
- package/dist/src/settings-merger.d.ts.map +1 -0
- package/dist/src/settings-merger.js +136 -0
- package/dist/src/settings-merger.js.map +1 -0
- package/dist/src/settings-merger.test.d.ts +2 -0
- package/dist/src/settings-merger.test.d.ts.map +1 -0
- package/dist/src/settings-merger.test.js +387 -0
- package/dist/src/settings-merger.test.js.map +1 -0
- package/dist/src/skills-loader.d.ts +14 -0
- package/dist/src/skills-loader.d.ts.map +1 -0
- package/dist/src/skills-loader.js +90 -0
- package/dist/src/skills-loader.js.map +1 -0
- package/dist/src/skills-loader.test.d.ts +2 -0
- package/dist/src/skills-loader.test.d.ts.map +1 -0
- package/dist/src/skills-loader.test.js +222 -0
- package/dist/src/skills-loader.test.js.map +1 -0
- package/dist/src/state-manager.d.ts +5 -0
- package/dist/src/state-manager.d.ts.map +1 -0
- package/dist/src/state-manager.js +55 -0
- package/dist/src/state-manager.js.map +1 -0
- package/dist/src/state-manager.test.d.ts +2 -0
- package/dist/src/state-manager.test.d.ts.map +1 -0
- package/dist/src/state-manager.test.js +85 -0
- package/dist/src/state-manager.test.js.map +1 -0
- package/dist/src/subagent-classifier.d.ts +4 -0
- package/dist/src/subagent-classifier.d.ts.map +1 -0
- package/dist/src/subagent-classifier.js +53 -0
- package/dist/src/subagent-classifier.js.map +1 -0
- package/dist/src/subagent-classifier.test.d.ts +2 -0
- package/dist/src/subagent-classifier.test.d.ts.map +1 -0
- package/dist/src/subagent-classifier.test.js +88 -0
- package/dist/src/subagent-classifier.test.js.map +1 -0
- package/package.json +59 -0
- package/scripts/pre-tool-use.ts +10 -0
- package/scripts/session-start.ts +9 -0
- package/scripts/tail-logs.sh +17 -0
- package/scripts/test-hooks.sh +910 -0
- package/scripts/user-prompt-submit.ts +10 -0
- package/skills/ketchup.enforced.md +23 -0
- package/templates/settings.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Sam Hatoum
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,544 @@
|
|
|
1
|
+
# claude-ketchup
|
|
2
|
+
|
|
3
|
+
Husky-style hooks and skills management for Claude Code, implementing the Ketchup Technique.\*
|
|
4
|
+
|
|
5
|
+
[](LICENSE) []()
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The Ketchup Technique
|
|
10
|
+
|
|
11
|
+
Just like with real ketchup, you don't dump the whole bottle on your plate—you dispense it in controlled bursts.
|
|
12
|
+
|
|
13
|
+
The Ketchup Technique is an AI-native development methodology that harnesses Claude's enthusiasm through:
|
|
14
|
+
|
|
15
|
+
- **Controlled Bursts**: One test, one behavior, one commit
|
|
16
|
+
- **TCR Discipline**: Test && Commit || Revert—never patch failing code
|
|
17
|
+
- **Emergent Design**: Let architecture emerge from passing tests
|
|
18
|
+
- **100% Coverage**: True TDD yields complete coverage naturally
|
|
19
|
+
- **Fresh Nomenclature**: "Bottles" and "Bursts" avoid LLM training pollution
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
BURST → COMMIT → BURST → COMMIT
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
The technique grew from frustration with AI over-execution—asking for "Hello World" and getting a nav bar, login system, and comment section. By enforcing small, reversible increments, the Ketchup Technique channels AI energy productively.
|
|
26
|
+
|
|
27
|
+
**[Read the full origin story →](KETCHUP-STORY.md)**
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Purpose
|
|
32
|
+
|
|
33
|
+
Without claude-ketchup, you would have to manually create and maintain `.claude/` directories, copy hook scripts between projects, configure `settings.json` by hand, and track which skills are active across different codebases.
|
|
34
|
+
|
|
35
|
+
claude-ketchup automates Claude Code project setup through npm lifecycle hooks. Install it once, and your project gets automatic hook management, skills injection, file protection via deny-lists, and settings merging with project/local overrides.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
npm install claude-ketchup
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Or with pnpm:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm add claude-ketchup
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
# 1. Install the package
|
|
55
|
+
pnpm add claude-ketchup
|
|
56
|
+
|
|
57
|
+
# 2. Verify installation
|
|
58
|
+
claude-ketchup status
|
|
59
|
+
|
|
60
|
+
# 3. Check symlink health
|
|
61
|
+
claude-ketchup doctor
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
After installation, claude-ketchup automatically:
|
|
65
|
+
|
|
66
|
+
- Creates a `.claude/` directory in your project root
|
|
67
|
+
- Symlinks hook scripts, skills, and commands from the package
|
|
68
|
+
- Generates a `.gitignore` for symlinked and runtime files
|
|
69
|
+
- Merges default settings into your Claude configuration
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## How-to Guides
|
|
74
|
+
|
|
75
|
+
### Create a Custom Skill
|
|
76
|
+
|
|
77
|
+
Skills are markdown files with YAML frontmatter that inject context into Claude sessions.
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
# Create a skill that runs at session start
|
|
81
|
+
cat > .claude/skills/my-project.md << 'EOF'
|
|
82
|
+
---
|
|
83
|
+
hook: SessionStart
|
|
84
|
+
priority: 50
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
# Project Guidelines
|
|
88
|
+
|
|
89
|
+
- Follow TDD principles
|
|
90
|
+
- Use TypeScript strict mode
|
|
91
|
+
- Write tests before implementation
|
|
92
|
+
EOF
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### Protect Files with Deny-List
|
|
96
|
+
|
|
97
|
+
Prevent Claude from modifying sensitive files:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# Create a project deny-list
|
|
101
|
+
cat > .claude/deny-list.project.txt << 'EOF'
|
|
102
|
+
# Secrets
|
|
103
|
+
.env
|
|
104
|
+
*.secret
|
|
105
|
+
credentials.json
|
|
106
|
+
|
|
107
|
+
# Generated files
|
|
108
|
+
dist/**
|
|
109
|
+
node_modules/**
|
|
110
|
+
EOF
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Override Package Settings
|
|
114
|
+
|
|
115
|
+
Create project-specific settings:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# .claude/settings.project.json
|
|
119
|
+
{
|
|
120
|
+
"hooks": {
|
|
121
|
+
"PreToolUse": {
|
|
122
|
+
"_disabled": ["some-command-to-disable"]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Or local-only settings (gitignored):
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# .claude/settings.local.json
|
|
132
|
+
{
|
|
133
|
+
"hooks": {
|
|
134
|
+
"SessionStart": {
|
|
135
|
+
"_mode": "replace",
|
|
136
|
+
"_value": []
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## CLI Reference
|
|
145
|
+
|
|
146
|
+
### Commands
|
|
147
|
+
|
|
148
|
+
#### `claude-ketchup status`
|
|
149
|
+
|
|
150
|
+
Show symlink status for all expected hook scripts and skills.
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
claude-ketchup status
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### `claude-ketchup doctor`
|
|
157
|
+
|
|
158
|
+
Diagnose symlink health by verifying all symlinks point to valid targets.
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
claude-ketchup doctor
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `claude-ketchup repair`
|
|
165
|
+
|
|
166
|
+
Recreate broken or missing symlinks in the `.claude/` directory.
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
claude-ketchup repair
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
#### `claude-ketchup skills`
|
|
173
|
+
|
|
174
|
+
List all skills with their metadata.
|
|
175
|
+
|
|
176
|
+
```bash
|
|
177
|
+
claude-ketchup skills
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Hooks System
|
|
183
|
+
|
|
184
|
+
claude-ketchup provides four hook types that integrate with Claude Code:
|
|
185
|
+
|
|
186
|
+
### SessionStart
|
|
187
|
+
|
|
188
|
+
Fires when a Claude Code session begins. Use it to inject project context, guidelines, or documentation.
|
|
189
|
+
|
|
190
|
+
**Input:** Claude directory path
|
|
191
|
+
**Output:** Concatenated content of matching skills
|
|
192
|
+
|
|
193
|
+
### PreToolUse
|
|
194
|
+
|
|
195
|
+
Fires before Claude uses a tool. Has two matchers:
|
|
196
|
+
|
|
197
|
+
1. **Edit/Write/NotebookEdit** - Checks deny-list to protect sensitive files
|
|
198
|
+
2. **Bash** - Validates git commits against CLAUDE.md rules
|
|
199
|
+
|
|
200
|
+
**Input:** Tool name and input parameters
|
|
201
|
+
**Output:** `{ decision: "allow" | "block", reason?: string }`
|
|
202
|
+
|
|
203
|
+
### UserPromptSubmit
|
|
204
|
+
|
|
205
|
+
Fires when user submits a prompt. Use it to inject reminders or context.
|
|
206
|
+
|
|
207
|
+
**Input:** User prompt text
|
|
208
|
+
**Output:** Original prompt with `<system-reminder>` tags appended
|
|
209
|
+
|
|
210
|
+
### Stop
|
|
211
|
+
|
|
212
|
+
Fires when Claude stops execution. Use it for auto-continue logic.
|
|
213
|
+
|
|
214
|
+
**Input:** Transcript context
|
|
215
|
+
**Output:** `{ decision: "CONTINUE" | "STOP", reason: string }`
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Skills System
|
|
220
|
+
|
|
221
|
+
Skills are markdown files in `.claude/skills/` with YAML frontmatter:
|
|
222
|
+
|
|
223
|
+
```markdown
|
|
224
|
+
---
|
|
225
|
+
hook: SessionStart
|
|
226
|
+
priority: 100
|
|
227
|
+
mode: code
|
|
228
|
+
when:
|
|
229
|
+
projectType: typescript
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
# Skill Content
|
|
233
|
+
|
|
234
|
+
Instructions for Claude...
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
### Frontmatter Schema
|
|
238
|
+
|
|
239
|
+
| Field | Type | Required | Default | Description |
|
|
240
|
+
| ---------- | ------ | -------- | ------- | ------------------------------------- |
|
|
241
|
+
| `hook` | string | Yes | - | Which hook triggers this skill |
|
|
242
|
+
| `priority` | number | No | 0 | Execution order (higher runs first) |
|
|
243
|
+
| `mode` | string | No | - | Filter by mode (plan/code) |
|
|
244
|
+
| `when` | object | No | - | Conditional activation based on state |
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Settings Merger
|
|
249
|
+
|
|
250
|
+
Settings are merged in priority order:
|
|
251
|
+
|
|
252
|
+
1. `templates/settings.json` (package defaults)
|
|
253
|
+
2. `.claude/settings.project.json` (project overrides, checked in)
|
|
254
|
+
3. `.claude/settings.local.json` (local overrides, gitignored)
|
|
255
|
+
|
|
256
|
+
### Override Modes
|
|
257
|
+
|
|
258
|
+
**Replace entire hook:**
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"hooks": {
|
|
263
|
+
"SessionStart": {
|
|
264
|
+
"_mode": "replace",
|
|
265
|
+
"_value": [{ "hooks": [{ "type": "command", "command": "my-cmd" }] }]
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Disable specific commands:**
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"hooks": {
|
|
276
|
+
"SessionStart": {
|
|
277
|
+
"_disabled": ["command-to-remove"]
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
---
|
|
284
|
+
|
|
285
|
+
## Troubleshooting
|
|
286
|
+
|
|
287
|
+
### Symlinks Not Created
|
|
288
|
+
|
|
289
|
+
**Symptom:** `.claude/` directory is empty after install
|
|
290
|
+
|
|
291
|
+
**Cause:** Project root detection failed or permission issues
|
|
292
|
+
|
|
293
|
+
**Solution:**
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
# Set explicit project root
|
|
297
|
+
KETCHUP_ROOT=/path/to/project pnpm add claude-ketchup
|
|
298
|
+
|
|
299
|
+
# Or repair manually
|
|
300
|
+
claude-ketchup repair
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Hooks Not Firing
|
|
304
|
+
|
|
305
|
+
**Symptom:** Skills don't load at session start
|
|
306
|
+
|
|
307
|
+
**Cause:** settings.json not merged correctly
|
|
308
|
+
|
|
309
|
+
**Solution:**
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
# Check symlink health
|
|
313
|
+
claude-ketchup doctor
|
|
314
|
+
|
|
315
|
+
# Repair if needed
|
|
316
|
+
claude-ketchup repair
|
|
317
|
+
|
|
318
|
+
# Verify settings
|
|
319
|
+
cat .claude/settings.json
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Enable Debug Logging
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
DEBUG=ketchup* claude-ketchup status
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
## Architecture
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
your-project/
|
|
334
|
+
├── .claude/
|
|
335
|
+
│ ├── scripts/
|
|
336
|
+
│ │ ├── pre-tool-use.ts # → symlink to package
|
|
337
|
+
│ │ ├── user-prompt-submit.ts # → symlink to package
|
|
338
|
+
│ │ ├── session-start.ts # Local (customizable)
|
|
339
|
+
│ │ ├── auto-continue.ts # Local (customizable)
|
|
340
|
+
│ │ ├── validate-commit.ts # Local (customizable)
|
|
341
|
+
│ │ ├── deny-list.ts # Local (customizable)
|
|
342
|
+
│ │ ├── prompt-reminder.ts # Local (customizable)
|
|
343
|
+
│ │ └── clean-logs.ts # Local (customizable)
|
|
344
|
+
│ ├── skills/
|
|
345
|
+
│ │ ├── ketchup.enforced.md # → symlink to package
|
|
346
|
+
│ │ └── my-project.md # Your custom skills
|
|
347
|
+
│ ├── commands/
|
|
348
|
+
│ │ ├── ketchup.md # → symlink to package
|
|
349
|
+
│ │ └── my-command.md # Your custom commands
|
|
350
|
+
│ ├── settings.json # Merged settings (generated)
|
|
351
|
+
│ ├── settings.project.json # Project overrides (optional)
|
|
352
|
+
│ ├── settings.local.json # Local overrides (optional)
|
|
353
|
+
│ ├── deny-list.project.txt # Project deny patterns
|
|
354
|
+
│ ├── deny-list.local.txt # Local deny patterns
|
|
355
|
+
│ ├── logs/ # Runtime logs
|
|
356
|
+
│ └── .gitignore # Generated
|
|
357
|
+
├── .claude.hooks.json # Hook state (runtime)
|
|
358
|
+
└── node_modules/
|
|
359
|
+
└── claude-ketchup/
|
|
360
|
+
├── scripts/ # Source scripts (symlink targets)
|
|
361
|
+
├── skills/ # Source skills (symlink targets)
|
|
362
|
+
├── commands/ # Source commands (symlink targets)
|
|
363
|
+
└── templates/ # Default settings
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### Dependencies
|
|
367
|
+
|
|
368
|
+
| Package | Usage |
|
|
369
|
+
| ---------- | ----------------------------------- |
|
|
370
|
+
| commander | CLI argument parsing |
|
|
371
|
+
| micromatch | Glob pattern matching for deny-list |
|
|
372
|
+
| yaml | YAML parsing for skill frontmatter |
|
|
373
|
+
|
|
374
|
+
---
|
|
375
|
+
|
|
376
|
+
## Hook State Management
|
|
377
|
+
|
|
378
|
+
claude-ketchup maintains a `.claude.hooks.json` file that controls hook behavior:
|
|
379
|
+
|
|
380
|
+
```json
|
|
381
|
+
{
|
|
382
|
+
"autoContinue": {
|
|
383
|
+
"mode": "smart",
|
|
384
|
+
"maxIterations": 0,
|
|
385
|
+
"iteration": 0,
|
|
386
|
+
"skipModes": ["plan"]
|
|
387
|
+
},
|
|
388
|
+
"validateCommit": {
|
|
389
|
+
"mode": "strict"
|
|
390
|
+
},
|
|
391
|
+
"denyList": {
|
|
392
|
+
"enabled": true,
|
|
393
|
+
"extraPatterns": []
|
|
394
|
+
},
|
|
395
|
+
"promptReminder": {
|
|
396
|
+
"enabled": true
|
|
397
|
+
},
|
|
398
|
+
"subagentHooks": {
|
|
399
|
+
"validateCommitOnExplore": false,
|
|
400
|
+
"validateCommitOnWork": true,
|
|
401
|
+
"validateCommitOnUnknown": true
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
### Subagent Classification
|
|
407
|
+
|
|
408
|
+
Hooks can behave differently based on the type of subagent running:
|
|
409
|
+
|
|
410
|
+
| Type | Patterns | Default Behavior |
|
|
411
|
+
| --------- | ----------------------------------------------- | ------------------------------ |
|
|
412
|
+
| `explore` | search, find, understand, investigate, analyze | Skip commit validation |
|
|
413
|
+
| `work` | implement, create, write, fix, refactor, update | Full validation |
|
|
414
|
+
| `unknown` | Ambiguous or no patterns | Full validation (safe default) |
|
|
415
|
+
|
|
416
|
+
---
|
|
417
|
+
|
|
418
|
+
## Logging
|
|
419
|
+
|
|
420
|
+
### Debug Logging
|
|
421
|
+
|
|
422
|
+
Enable debug logs during development:
|
|
423
|
+
|
|
424
|
+
```bash
|
|
425
|
+
DEBUG=ketchup* claude-ketchup status
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
Debug logs are written to `.claude/logs/ketchup/debug.log`.
|
|
429
|
+
|
|
430
|
+
### Hook Logs
|
|
431
|
+
|
|
432
|
+
Session-specific hook logs are written to `.claude/logs/hooks/{session-id}.log` with colored output for different log levels:
|
|
433
|
+
|
|
434
|
+
- `ACK` - Action acknowledged
|
|
435
|
+
- `NACK` - Action rejected
|
|
436
|
+
- `ERROR` - Error occurred
|
|
437
|
+
- `WARN` - Warning
|
|
438
|
+
- `SKIP` - Action skipped
|
|
439
|
+
- `INFO` - Informational
|
|
440
|
+
- `DENIED` - Access denied
|
|
441
|
+
- `CONTINUE` - Auto-continue triggered
|
|
442
|
+
|
|
443
|
+
---
|
|
444
|
+
|
|
445
|
+
## API Reference
|
|
446
|
+
|
|
447
|
+
For programmatic usage:
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
import {
|
|
451
|
+
// Core utilities
|
|
452
|
+
findProjectRoot,
|
|
453
|
+
createSymlink,
|
|
454
|
+
removeSymlink,
|
|
455
|
+
verifySymlink,
|
|
456
|
+
generateGitignore,
|
|
457
|
+
mergeSettings,
|
|
458
|
+
readState,
|
|
459
|
+
writeState,
|
|
460
|
+
|
|
461
|
+
// Skills
|
|
462
|
+
scanSkills,
|
|
463
|
+
parseSkill,
|
|
464
|
+
filterByHook,
|
|
465
|
+
filterByMode,
|
|
466
|
+
filterByState,
|
|
467
|
+
sortByPriority,
|
|
468
|
+
|
|
469
|
+
// Deny-list
|
|
470
|
+
loadDenyPatterns,
|
|
471
|
+
isDenied,
|
|
472
|
+
|
|
473
|
+
// CLI
|
|
474
|
+
getStatus,
|
|
475
|
+
repair,
|
|
476
|
+
getExpectedSymlinks,
|
|
477
|
+
doctor,
|
|
478
|
+
listSkills,
|
|
479
|
+
createCli,
|
|
480
|
+
} from "claude-ketchup";
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
---
|
|
484
|
+
|
|
485
|
+
## Documentation
|
|
486
|
+
|
|
487
|
+
Full documentation is available in the [`docs/`](./docs/) folder:
|
|
488
|
+
|
|
489
|
+
| Document | Description |
|
|
490
|
+
| -------------------------------------------- | ------------------------------- |
|
|
491
|
+
| [Getting Started](./docs/getting-started.md) | Installation and setup tutorial |
|
|
492
|
+
| [Hooks Guide](./docs/hooks-guide.md) | How-to guides for common tasks |
|
|
493
|
+
| [API Reference](./docs/api-reference.md) | Complete API documentation |
|
|
494
|
+
| [Architecture](./docs/architecture.md) | System design and internals |
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## Development
|
|
499
|
+
|
|
500
|
+
```bash
|
|
501
|
+
# Clone the repository
|
|
502
|
+
git clone https://github.com/samhatoum/claude-ketchup.git
|
|
503
|
+
cd claude-ketchup
|
|
504
|
+
|
|
505
|
+
# Install dependencies
|
|
506
|
+
pnpm install
|
|
507
|
+
|
|
508
|
+
# Run tests
|
|
509
|
+
pnpm test
|
|
510
|
+
|
|
511
|
+
# Run tests with coverage
|
|
512
|
+
pnpm test --coverage
|
|
513
|
+
|
|
514
|
+
# Build
|
|
515
|
+
pnpm build
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
### Testing Locally
|
|
519
|
+
|
|
520
|
+
```bash
|
|
521
|
+
# In claude-ketchup directory
|
|
522
|
+
pnpm link --global
|
|
523
|
+
|
|
524
|
+
# In your test project
|
|
525
|
+
pnpm link --global claude-ketchup
|
|
526
|
+
```
|
|
527
|
+
|
|
528
|
+
Or test postinstall directly:
|
|
529
|
+
|
|
530
|
+
```bash
|
|
531
|
+
KETCHUP_ROOT=/path/to/test-project npx tsx bin/postinstall.ts
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
---
|
|
535
|
+
|
|
536
|
+
## License
|
|
537
|
+
|
|
538
|
+
MIT © 2025 Sam Hatoum
|
|
539
|
+
|
|
540
|
+
See [LICENSE](LICENSE) for details.
|
|
541
|
+
|
|
542
|
+
---
|
|
543
|
+
|
|
544
|
+
<sub>\*The Ketchup Technique is an independent methodology for AI-native development. While it acknowledges the foundation of time-boxed intervals found in the Pomodoro® Technique (a registered trademark of Francesco Cirillo), it is a separate method. Learn more at [pomodorotechnique.com](http://pomodorotechnique.com/).</sub>
|
package/bin/cli.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# /ketchup - Ketchup Status & Control
|
|
2
|
+
|
|
3
|
+
Check the status of your claude-ketchup installation and manage symlinks.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
### `/ketchup` or `/ketchup status`
|
|
8
|
+
|
|
9
|
+
Show the current status of all managed symlinks.
|
|
10
|
+
|
|
11
|
+
### `/ketchup doctor`
|
|
12
|
+
|
|
13
|
+
Run diagnostics to check for issues with the installation.
|
|
14
|
+
|
|
15
|
+
### `/ketchup repair`
|
|
16
|
+
|
|
17
|
+
Fix any broken or missing symlinks.
|
|
18
|
+
|
|
19
|
+
### `/ketchup skills`
|
|
20
|
+
|
|
21
|
+
List all active skills with their metadata.
|
|
22
|
+
|
|
23
|
+
## Implementation
|
|
24
|
+
|
|
25
|
+
When the user runs `/ketchup <command>`, you should:
|
|
26
|
+
|
|
27
|
+
1. Determine the package directory (node_modules/claude-ketchup)
|
|
28
|
+
2. Determine the .claude directory (project root/.claude)
|
|
29
|
+
3. Run the appropriate command function
|
|
30
|
+
4. Display the results
|
|
31
|
+
|
|
32
|
+
### Response Format
|
|
33
|
+
|
|
34
|
+
**For `/ketchup status`:**
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
╭─────────────────────────────────────────╮
|
|
38
|
+
│ 🥫 Ketchup Status │
|
|
39
|
+
├─────────────────────────────────────────┤
|
|
40
|
+
│ Symlinks: │
|
|
41
|
+
│ ✓ scripts/session-start.ts │
|
|
42
|
+
│ ✓ scripts/pre-tool-use.ts │
|
|
43
|
+
│ ✓ skills/coding.md │
|
|
44
|
+
├─────────────────────────────────────────┤
|
|
45
|
+
│ All symlinks healthy │
|
|
46
|
+
╰─────────────────────────────────────────╯
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
**For `/ketchup doctor`:**
|
|
50
|
+
|
|
51
|
+
```
|
|
52
|
+
╭─────────────────────────────────────────╮
|
|
53
|
+
│ 🩺 Ketchup Doctor │
|
|
54
|
+
├─────────────────────────────────────────┤
|
|
55
|
+
│ ✓ All symlinks valid │
|
|
56
|
+
│ ✓ Settings merged │
|
|
57
|
+
│ ✓ Gitignore updated │
|
|
58
|
+
├─────────────────────────────────────────┤
|
|
59
|
+
│ Status: Healthy │
|
|
60
|
+
╰─────────────────────────────────────────╯
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**For `/ketchup repair`:**
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
╭─────────────────────────────────────────╮
|
|
67
|
+
│ 🔧 Ketchup Repair │
|
|
68
|
+
├─────────────────────────────────────────┤
|
|
69
|
+
│ Repaired: │
|
|
70
|
+
│ ↻ scripts/session-start.ts │
|
|
71
|
+
│ ↻ skills/coding.md │
|
|
72
|
+
├─────────────────────────────────────────┤
|
|
73
|
+
│ 2 symlinks repaired │
|
|
74
|
+
╰─────────────────────────────────────────╯
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**For `/ketchup skills`:**
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
╭─────────────────────────────────────────╮
|
|
81
|
+
│ 📚 Active Skills │
|
|
82
|
+
├─────────────────────────────────────────┤
|
|
83
|
+
│ coding.md │
|
|
84
|
+
│ Hook: SessionStart │
|
|
85
|
+
│ Priority: 10 │
|
|
86
|
+
│ │
|
|
87
|
+
│ reminder.md │
|
|
88
|
+
│ Hook: UserPromptSubmit │
|
|
89
|
+
│ Priority: 5 │
|
|
90
|
+
├─────────────────────────────────────────┤
|
|
91
|
+
│ 2 skills active │
|
|
92
|
+
╰─────────────────────────────────────────╯
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**For `/ketchup help`:**
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
/ketchup - Ketchup Status & Control
|
|
99
|
+
|
|
100
|
+
Commands:
|
|
101
|
+
/ketchup Show symlink status
|
|
102
|
+
/ketchup status Show symlink status
|
|
103
|
+
/ketchup doctor Run diagnostics
|
|
104
|
+
/ketchup repair Fix broken symlinks
|
|
105
|
+
/ketchup skills List active skills
|
|
106
|
+
/ketchup help Show this help
|
|
107
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":""}
|
package/dist/bin/cli.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":";;;AAEA,8CAA8C;AAE9C,MAAM,OAAO,GAAG,IAAA,kBAAS,GAAE,CAAC;AAC5B,OAAO,CAAC,KAAK,EAAE,CAAC"}
|