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.
Files changed (246) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +544 -0
  3. package/bin/cli.ts +6 -0
  4. package/bin/postinstall.ts +5 -0
  5. package/bin/preuninstall.ts +5 -0
  6. package/commands/ketchup.md +107 -0
  7. package/dist/bin/cli.d.ts +3 -0
  8. package/dist/bin/cli.d.ts.map +1 -0
  9. package/dist/bin/cli.js +7 -0
  10. package/dist/bin/cli.js.map +1 -0
  11. package/dist/bin/postinstall.d.ts +3 -0
  12. package/dist/bin/postinstall.d.ts.map +1 -0
  13. package/dist/bin/postinstall.js +6 -0
  14. package/dist/bin/postinstall.js.map +1 -0
  15. package/dist/bin/preuninstall.d.ts +3 -0
  16. package/dist/bin/preuninstall.d.ts.map +1 -0
  17. package/dist/bin/preuninstall.js +6 -0
  18. package/dist/bin/preuninstall.js.map +1 -0
  19. package/dist/scripts/pre-tool-use.d.ts +3 -0
  20. package/dist/scripts/pre-tool-use.d.ts.map +1 -0
  21. package/dist/scripts/pre-tool-use.js +43 -0
  22. package/dist/scripts/pre-tool-use.js.map +1 -0
  23. package/dist/scripts/session-start.d.ts +3 -0
  24. package/dist/scripts/session-start.d.ts.map +1 -0
  25. package/dist/scripts/session-start.js +42 -0
  26. package/dist/scripts/session-start.js.map +1 -0
  27. package/dist/scripts/user-prompt-submit.d.ts +3 -0
  28. package/dist/scripts/user-prompt-submit.d.ts.map +1 -0
  29. package/dist/scripts/user-prompt-submit.js +43 -0
  30. package/dist/scripts/user-prompt-submit.js.map +1 -0
  31. package/dist/src/clean-logs.d.ts +6 -0
  32. package/dist/src/clean-logs.d.ts.map +1 -0
  33. package/dist/src/clean-logs.js +38 -0
  34. package/dist/src/clean-logs.js.map +1 -0
  35. package/dist/src/clean-logs.test.d.ts +2 -0
  36. package/dist/src/clean-logs.test.d.ts.map +1 -0
  37. package/dist/src/clean-logs.test.js +101 -0
  38. package/dist/src/clean-logs.test.js.map +1 -0
  39. package/dist/src/cli/cli.d.ts +3 -0
  40. package/dist/src/cli/cli.d.ts.map +1 -0
  41. package/dist/src/cli/cli.js +24 -0
  42. package/dist/src/cli/cli.js.map +1 -0
  43. package/dist/src/cli/cli.test.d.ts +2 -0
  44. package/dist/src/cli/cli.test.d.ts.map +1 -0
  45. package/dist/src/cli/cli.test.js +20 -0
  46. package/dist/src/cli/cli.test.js.map +1 -0
  47. package/dist/src/cli/doctor.d.ts +7 -0
  48. package/dist/src/cli/doctor.d.ts.map +1 -0
  49. package/dist/src/cli/doctor.js +52 -0
  50. package/dist/src/cli/doctor.js.map +1 -0
  51. package/dist/src/cli/doctor.test.d.ts +2 -0
  52. package/dist/src/cli/doctor.test.d.ts.map +1 -0
  53. package/dist/src/cli/doctor.test.js +77 -0
  54. package/dist/src/cli/doctor.test.js.map +1 -0
  55. package/dist/src/cli/repair.d.ts +7 -0
  56. package/dist/src/cli/repair.d.ts.map +1 -0
  57. package/dist/src/cli/repair.js +67 -0
  58. package/dist/src/cli/repair.js.map +1 -0
  59. package/dist/src/cli/repair.test.d.ts +2 -0
  60. package/dist/src/cli/repair.test.d.ts.map +1 -0
  61. package/dist/src/cli/repair.test.js +72 -0
  62. package/dist/src/cli/repair.test.js.map +1 -0
  63. package/dist/src/cli/skills.d.ts +11 -0
  64. package/dist/src/cli/skills.d.ts.map +1 -0
  65. package/dist/src/cli/skills.js +53 -0
  66. package/dist/src/cli/skills.js.map +1 -0
  67. package/dist/src/cli/skills.test.d.ts +2 -0
  68. package/dist/src/cli/skills.test.d.ts.map +1 -0
  69. package/dist/src/cli/skills.test.js +89 -0
  70. package/dist/src/cli/skills.test.js.map +1 -0
  71. package/dist/src/cli/status.d.ts +10 -0
  72. package/dist/src/cli/status.d.ts.map +1 -0
  73. package/dist/src/cli/status.js +63 -0
  74. package/dist/src/cli/status.js.map +1 -0
  75. package/dist/src/cli/status.test.d.ts +2 -0
  76. package/dist/src/cli/status.test.d.ts.map +1 -0
  77. package/dist/src/cli/status.test.js +70 -0
  78. package/dist/src/cli/status.test.js.map +1 -0
  79. package/dist/src/clue-collector.d.ts +23 -0
  80. package/dist/src/clue-collector.d.ts.map +1 -0
  81. package/dist/src/clue-collector.js +226 -0
  82. package/dist/src/clue-collector.js.map +1 -0
  83. package/dist/src/clue-collector.test.d.ts +2 -0
  84. package/dist/src/clue-collector.test.d.ts.map +1 -0
  85. package/dist/src/clue-collector.test.js +213 -0
  86. package/dist/src/clue-collector.test.js.map +1 -0
  87. package/dist/src/debug-logger.d.ts +2 -0
  88. package/dist/src/debug-logger.d.ts.map +1 -0
  89. package/dist/src/debug-logger.js +23 -0
  90. package/dist/src/debug-logger.js.map +1 -0
  91. package/dist/src/debug-logger.test.d.ts +2 -0
  92. package/dist/src/debug-logger.test.d.ts.map +1 -0
  93. package/dist/src/debug-logger.test.js +63 -0
  94. package/dist/src/debug-logger.test.js.map +1 -0
  95. package/dist/src/deny-list.d.ts +3 -0
  96. package/dist/src/deny-list.d.ts.map +1 -0
  97. package/dist/src/deny-list.js +62 -0
  98. package/dist/src/deny-list.js.map +1 -0
  99. package/dist/src/deny-list.test.d.ts +2 -0
  100. package/dist/src/deny-list.test.d.ts.map +1 -0
  101. package/dist/src/deny-list.test.js +93 -0
  102. package/dist/src/deny-list.test.js.map +1 -0
  103. package/dist/src/e2e.test.d.ts +2 -0
  104. package/dist/src/e2e.test.d.ts.map +1 -0
  105. package/dist/src/e2e.test.js +88 -0
  106. package/dist/src/e2e.test.js.map +1 -0
  107. package/dist/src/gitignore-manager.d.ts +2 -0
  108. package/dist/src/gitignore-manager.d.ts.map +1 -0
  109. package/dist/src/gitignore-manager.js +45 -0
  110. package/dist/src/gitignore-manager.js.map +1 -0
  111. package/dist/src/gitignore-manager.test.d.ts +2 -0
  112. package/dist/src/gitignore-manager.test.d.ts.map +1 -0
  113. package/dist/src/gitignore-manager.test.js +70 -0
  114. package/dist/src/gitignore-manager.test.js.map +1 -0
  115. package/dist/src/hook-state.d.ts +43 -0
  116. package/dist/src/hook-state.d.ts.map +1 -0
  117. package/dist/src/hook-state.js +124 -0
  118. package/dist/src/hook-state.js.map +1 -0
  119. package/dist/src/hook-state.test.d.ts +2 -0
  120. package/dist/src/hook-state.test.d.ts.map +1 -0
  121. package/dist/src/hook-state.test.js +190 -0
  122. package/dist/src/hook-state.test.js.map +1 -0
  123. package/dist/src/hooks/auto-continue.d.ts +9 -0
  124. package/dist/src/hooks/auto-continue.d.ts.map +1 -0
  125. package/dist/src/hooks/auto-continue.js +56 -0
  126. package/dist/src/hooks/auto-continue.js.map +1 -0
  127. package/dist/src/hooks/auto-continue.test.d.ts +2 -0
  128. package/dist/src/hooks/auto-continue.test.d.ts.map +1 -0
  129. package/dist/src/hooks/auto-continue.test.js +141 -0
  130. package/dist/src/hooks/auto-continue.test.js.map +1 -0
  131. package/dist/src/hooks/pre-tool-use.d.ts +8 -0
  132. package/dist/src/hooks/pre-tool-use.d.ts.map +1 -0
  133. package/dist/src/hooks/pre-tool-use.js +19 -0
  134. package/dist/src/hooks/pre-tool-use.js.map +1 -0
  135. package/dist/src/hooks/pre-tool-use.test.d.ts +2 -0
  136. package/dist/src/hooks/pre-tool-use.test.d.ts.map +1 -0
  137. package/dist/src/hooks/pre-tool-use.test.js +84 -0
  138. package/dist/src/hooks/pre-tool-use.test.js.map +1 -0
  139. package/dist/src/hooks/session-start.d.ts +6 -0
  140. package/dist/src/hooks/session-start.d.ts.map +1 -0
  141. package/dist/src/hooks/session-start.js +49 -0
  142. package/dist/src/hooks/session-start.js.map +1 -0
  143. package/dist/src/hooks/session-start.test.d.ts +2 -0
  144. package/dist/src/hooks/session-start.test.d.ts.map +1 -0
  145. package/dist/src/hooks/session-start.test.js +96 -0
  146. package/dist/src/hooks/session-start.test.js.map +1 -0
  147. package/dist/src/hooks/user-prompt-submit.d.ts +6 -0
  148. package/dist/src/hooks/user-prompt-submit.d.ts.map +1 -0
  149. package/dist/src/hooks/user-prompt-submit.js +54 -0
  150. package/dist/src/hooks/user-prompt-submit.js.map +1 -0
  151. package/dist/src/hooks/user-prompt-submit.test.d.ts +2 -0
  152. package/dist/src/hooks/user-prompt-submit.test.d.ts.map +1 -0
  153. package/dist/src/hooks/user-prompt-submit.test.js +92 -0
  154. package/dist/src/hooks/user-prompt-submit.test.js.map +1 -0
  155. package/dist/src/hooks/validate-commit.d.ts +12 -0
  156. package/dist/src/hooks/validate-commit.d.ts.map +1 -0
  157. package/dist/src/hooks/validate-commit.js +58 -0
  158. package/dist/src/hooks/validate-commit.js.map +1 -0
  159. package/dist/src/hooks/validate-commit.test.d.ts +2 -0
  160. package/dist/src/hooks/validate-commit.test.d.ts.map +1 -0
  161. package/dist/src/hooks/validate-commit.test.js +150 -0
  162. package/dist/src/hooks/validate-commit.test.js.map +1 -0
  163. package/dist/src/index.d.ts +13 -0
  164. package/dist/src/index.d.ts.map +1 -0
  165. package/dist/src/index.js +38 -0
  166. package/dist/src/index.js.map +1 -0
  167. package/dist/src/linker.d.ts +6 -0
  168. package/dist/src/linker.d.ts.map +1 -0
  169. package/dist/src/linker.js +78 -0
  170. package/dist/src/linker.js.map +1 -0
  171. package/dist/src/linker.test.d.ts +2 -0
  172. package/dist/src/linker.test.d.ts.map +1 -0
  173. package/dist/src/linker.test.js +192 -0
  174. package/dist/src/linker.test.js.map +1 -0
  175. package/dist/src/logger.d.ts +21 -0
  176. package/dist/src/logger.d.ts.map +1 -0
  177. package/dist/src/logger.js +117 -0
  178. package/dist/src/logger.js.map +1 -0
  179. package/dist/src/logger.test.d.ts +2 -0
  180. package/dist/src/logger.test.d.ts.map +1 -0
  181. package/dist/src/logger.test.js +159 -0
  182. package/dist/src/logger.test.js.map +1 -0
  183. package/dist/src/postinstall.d.ts +7 -0
  184. package/dist/src/postinstall.d.ts.map +1 -0
  185. package/dist/src/postinstall.js +81 -0
  186. package/dist/src/postinstall.js.map +1 -0
  187. package/dist/src/postinstall.test.d.ts +2 -0
  188. package/dist/src/postinstall.test.d.ts.map +1 -0
  189. package/dist/src/postinstall.test.js +125 -0
  190. package/dist/src/postinstall.test.js.map +1 -0
  191. package/dist/src/preuninstall.d.ts +2 -0
  192. package/dist/src/preuninstall.d.ts.map +1 -0
  193. package/dist/src/preuninstall.js +62 -0
  194. package/dist/src/preuninstall.js.map +1 -0
  195. package/dist/src/preuninstall.test.d.ts +2 -0
  196. package/dist/src/preuninstall.test.d.ts.map +1 -0
  197. package/dist/src/preuninstall.test.js +97 -0
  198. package/dist/src/preuninstall.test.js.map +1 -0
  199. package/dist/src/root-finder.d.ts +2 -0
  200. package/dist/src/root-finder.d.ts.map +1 -0
  201. package/dist/src/root-finder.js +71 -0
  202. package/dist/src/root-finder.js.map +1 -0
  203. package/dist/src/root-finder.test.d.ts +2 -0
  204. package/dist/src/root-finder.test.d.ts.map +1 -0
  205. package/dist/src/root-finder.test.js +111 -0
  206. package/dist/src/root-finder.test.js.map +1 -0
  207. package/dist/src/settings-merger.d.ts +2 -0
  208. package/dist/src/settings-merger.d.ts.map +1 -0
  209. package/dist/src/settings-merger.js +136 -0
  210. package/dist/src/settings-merger.js.map +1 -0
  211. package/dist/src/settings-merger.test.d.ts +2 -0
  212. package/dist/src/settings-merger.test.d.ts.map +1 -0
  213. package/dist/src/settings-merger.test.js +387 -0
  214. package/dist/src/settings-merger.test.js.map +1 -0
  215. package/dist/src/skills-loader.d.ts +14 -0
  216. package/dist/src/skills-loader.d.ts.map +1 -0
  217. package/dist/src/skills-loader.js +90 -0
  218. package/dist/src/skills-loader.js.map +1 -0
  219. package/dist/src/skills-loader.test.d.ts +2 -0
  220. package/dist/src/skills-loader.test.d.ts.map +1 -0
  221. package/dist/src/skills-loader.test.js +222 -0
  222. package/dist/src/skills-loader.test.js.map +1 -0
  223. package/dist/src/state-manager.d.ts +5 -0
  224. package/dist/src/state-manager.d.ts.map +1 -0
  225. package/dist/src/state-manager.js +55 -0
  226. package/dist/src/state-manager.js.map +1 -0
  227. package/dist/src/state-manager.test.d.ts +2 -0
  228. package/dist/src/state-manager.test.d.ts.map +1 -0
  229. package/dist/src/state-manager.test.js +85 -0
  230. package/dist/src/state-manager.test.js.map +1 -0
  231. package/dist/src/subagent-classifier.d.ts +4 -0
  232. package/dist/src/subagent-classifier.d.ts.map +1 -0
  233. package/dist/src/subagent-classifier.js +53 -0
  234. package/dist/src/subagent-classifier.js.map +1 -0
  235. package/dist/src/subagent-classifier.test.d.ts +2 -0
  236. package/dist/src/subagent-classifier.test.d.ts.map +1 -0
  237. package/dist/src/subagent-classifier.test.js +88 -0
  238. package/dist/src/subagent-classifier.test.js.map +1 -0
  239. package/package.json +59 -0
  240. package/scripts/pre-tool-use.ts +10 -0
  241. package/scripts/session-start.ts +9 -0
  242. package/scripts/tail-logs.sh +17 -0
  243. package/scripts/test-hooks.sh +910 -0
  244. package/scripts/user-prompt-submit.ts +10 -0
  245. package/skills/ketchup.enforced.md +23 -0
  246. 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](https://img.shields.io/badge/license-MIT-blue?style=flat-square)](LICENSE) [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue?style=flat-square)]()
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,6 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { createCli } from '../src/cli/cli.js';
4
+
5
+ const program = createCli();
6
+ program.parse();
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ import { runPostinstall } from '../src/postinstall.js';
4
+
5
+ runPostinstall();
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env npx tsx
2
+
3
+ import { runPreuninstall } from '../src/preuninstall.js';
4
+
5
+ runPreuninstall();
@@ -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,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../bin/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const cli_js_1 = require("../src/cli/cli.js");
5
+ const program = (0, cli_js_1.createCli)();
6
+ program.parse();
7
+ //# sourceMappingURL=cli.js.map
@@ -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"}