@kkelly-offical/kkcode 0.1.2

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 (196) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +445 -0
  3. package/package.json +46 -0
  4. package/src/agent/agent.mjs +170 -0
  5. package/src/agent/custom-agent-loader.mjs +158 -0
  6. package/src/agent/generator.mjs +115 -0
  7. package/src/agent/prompt/architect.txt +36 -0
  8. package/src/agent/prompt/build-fixer.txt +71 -0
  9. package/src/agent/prompt/build.txt +101 -0
  10. package/src/agent/prompt/compaction.txt +12 -0
  11. package/src/agent/prompt/explore.txt +29 -0
  12. package/src/agent/prompt/guide.txt +40 -0
  13. package/src/agent/prompt/longagent.txt +178 -0
  14. package/src/agent/prompt/plan.txt +50 -0
  15. package/src/agent/prompt/researcher.txt +23 -0
  16. package/src/agent/prompt/reviewer.txt +44 -0
  17. package/src/agent/prompt/security-reviewer.txt +62 -0
  18. package/src/agent/prompt/tdd-guide.txt +84 -0
  19. package/src/agent/prompt/title.txt +8 -0
  20. package/src/command/custom-commands.mjs +57 -0
  21. package/src/commands/agent.mjs +71 -0
  22. package/src/commands/audit.mjs +77 -0
  23. package/src/commands/background.mjs +86 -0
  24. package/src/commands/chat.mjs +114 -0
  25. package/src/commands/command.mjs +41 -0
  26. package/src/commands/config.mjs +44 -0
  27. package/src/commands/doctor.mjs +148 -0
  28. package/src/commands/hook.mjs +29 -0
  29. package/src/commands/init.mjs +141 -0
  30. package/src/commands/longagent.mjs +100 -0
  31. package/src/commands/mcp.mjs +89 -0
  32. package/src/commands/permission.mjs +36 -0
  33. package/src/commands/prompt.mjs +42 -0
  34. package/src/commands/review.mjs +266 -0
  35. package/src/commands/rule.mjs +34 -0
  36. package/src/commands/session.mjs +235 -0
  37. package/src/commands/theme.mjs +98 -0
  38. package/src/commands/usage.mjs +91 -0
  39. package/src/config/defaults.mjs +195 -0
  40. package/src/config/import-config.mjs +76 -0
  41. package/src/config/load-config.mjs +76 -0
  42. package/src/config/schema.mjs +509 -0
  43. package/src/context.mjs +40 -0
  44. package/src/core/constants.mjs +46 -0
  45. package/src/core/errors.mjs +57 -0
  46. package/src/core/events.mjs +29 -0
  47. package/src/core/types.mjs +57 -0
  48. package/src/github/api.mjs +78 -0
  49. package/src/github/auth.mjs +286 -0
  50. package/src/github/flow.mjs +298 -0
  51. package/src/github/workspace.mjs +212 -0
  52. package/src/index.mjs +82 -0
  53. package/src/knowledge/api-design.txt +9 -0
  54. package/src/knowledge/cpp.txt +10 -0
  55. package/src/knowledge/docker.txt +10 -0
  56. package/src/knowledge/dotnet.txt +9 -0
  57. package/src/knowledge/electron.txt +10 -0
  58. package/src/knowledge/flutter.txt +10 -0
  59. package/src/knowledge/go.txt +9 -0
  60. package/src/knowledge/graphql.txt +10 -0
  61. package/src/knowledge/java.txt +9 -0
  62. package/src/knowledge/kotlin.txt +10 -0
  63. package/src/knowledge/loader.mjs +125 -0
  64. package/src/knowledge/next.txt +8 -0
  65. package/src/knowledge/node.txt +8 -0
  66. package/src/knowledge/nuxt.txt +9 -0
  67. package/src/knowledge/php.txt +10 -0
  68. package/src/knowledge/python.txt +10 -0
  69. package/src/knowledge/react-native.txt +10 -0
  70. package/src/knowledge/react.txt +9 -0
  71. package/src/knowledge/ruby.txt +11 -0
  72. package/src/knowledge/rust.txt +9 -0
  73. package/src/knowledge/svelte.txt +9 -0
  74. package/src/knowledge/swift.txt +10 -0
  75. package/src/knowledge/tailwind.txt +10 -0
  76. package/src/knowledge/testing.txt +8 -0
  77. package/src/knowledge/typescript.txt +8 -0
  78. package/src/knowledge/vue.txt +9 -0
  79. package/src/mcp/client-http.mjs +157 -0
  80. package/src/mcp/client-sse.mjs +286 -0
  81. package/src/mcp/client-stdio.mjs +451 -0
  82. package/src/mcp/registry.mjs +394 -0
  83. package/src/mcp/stdio-framing.mjs +127 -0
  84. package/src/orchestration/background-manager.mjs +358 -0
  85. package/src/orchestration/background-worker.mjs +245 -0
  86. package/src/orchestration/longagent-manager.mjs +116 -0
  87. package/src/orchestration/stage-scheduler.mjs +489 -0
  88. package/src/orchestration/subagent-router.mjs +62 -0
  89. package/src/orchestration/task-scheduler.mjs +74 -0
  90. package/src/permission/engine.mjs +92 -0
  91. package/src/permission/exec-policy.mjs +372 -0
  92. package/src/permission/prompt.mjs +39 -0
  93. package/src/permission/rules.mjs +120 -0
  94. package/src/permission/workspace-trust.mjs +44 -0
  95. package/src/plugin/builtin-hooks/console-warn.mjs +41 -0
  96. package/src/plugin/builtin-hooks/extract-patterns.mjs +75 -0
  97. package/src/plugin/builtin-hooks/post-edit-format.mjs +57 -0
  98. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +61 -0
  99. package/src/plugin/builtin-hooks/strategic-compaction.mjs +38 -0
  100. package/src/plugin/hook-bus.mjs +154 -0
  101. package/src/provider/anthropic.mjs +389 -0
  102. package/src/provider/ollama.mjs +236 -0
  103. package/src/provider/openai-compatible.mjs +1 -0
  104. package/src/provider/openai.mjs +339 -0
  105. package/src/provider/retry-policy.mjs +68 -0
  106. package/src/provider/router.mjs +228 -0
  107. package/src/provider/sse.mjs +91 -0
  108. package/src/repl.mjs +2929 -0
  109. package/src/review/diff-parser.mjs +36 -0
  110. package/src/review/rejection-queue.mjs +62 -0
  111. package/src/review/review-store.mjs +21 -0
  112. package/src/review/risk-score.mjs +61 -0
  113. package/src/rules/load-rules.mjs +64 -0
  114. package/src/runtime.mjs +1 -0
  115. package/src/session/checkpoint.mjs +239 -0
  116. package/src/session/compaction.mjs +276 -0
  117. package/src/session/engine.mjs +225 -0
  118. package/src/session/instinct-manager.mjs +172 -0
  119. package/src/session/instruction-loader.mjs +25 -0
  120. package/src/session/longagent-plan.mjs +329 -0
  121. package/src/session/longagent-scaffold.mjs +100 -0
  122. package/src/session/longagent.mjs +1462 -0
  123. package/src/session/loop.mjs +905 -0
  124. package/src/session/memory-loader.mjs +75 -0
  125. package/src/session/project-context.mjs +367 -0
  126. package/src/session/prompt/anthropic.txt +151 -0
  127. package/src/session/prompt/beast.txt +37 -0
  128. package/src/session/prompt/max-steps.txt +6 -0
  129. package/src/session/prompt/plan.txt +9 -0
  130. package/src/session/prompt/qwen.txt +46 -0
  131. package/src/session/prompt-loader.mjs +18 -0
  132. package/src/session/recovery.mjs +52 -0
  133. package/src/session/store.mjs +503 -0
  134. package/src/session/system-prompt.mjs +260 -0
  135. package/src/session/task-validator.mjs +266 -0
  136. package/src/session/usability-gates.mjs +379 -0
  137. package/src/skill/builtin/backend-patterns.mjs +123 -0
  138. package/src/skill/builtin/commit.mjs +64 -0
  139. package/src/skill/builtin/debug.mjs +45 -0
  140. package/src/skill/builtin/frontend-patterns.mjs +120 -0
  141. package/src/skill/builtin/frontend.mjs +188 -0
  142. package/src/skill/builtin/init.mjs +220 -0
  143. package/src/skill/builtin/review.mjs +49 -0
  144. package/src/skill/builtin/security-checklist.mjs +80 -0
  145. package/src/skill/builtin/tdd.mjs +54 -0
  146. package/src/skill/generator.mjs +113 -0
  147. package/src/skill/registry.mjs +336 -0
  148. package/src/storage/audit-store.mjs +83 -0
  149. package/src/storage/event-log.mjs +82 -0
  150. package/src/storage/ghost-commit-store.mjs +235 -0
  151. package/src/storage/json-store.mjs +53 -0
  152. package/src/storage/paths.mjs +148 -0
  153. package/src/theme/color.mjs +64 -0
  154. package/src/theme/default-theme.mjs +29 -0
  155. package/src/theme/load-theme.mjs +71 -0
  156. package/src/theme/markdown.mjs +135 -0
  157. package/src/theme/schema.mjs +45 -0
  158. package/src/theme/status-bar.mjs +158 -0
  159. package/src/tool/audit-wrapper.mjs +38 -0
  160. package/src/tool/edit-transaction.mjs +126 -0
  161. package/src/tool/executor.mjs +109 -0
  162. package/src/tool/file-lock-manager.mjs +85 -0
  163. package/src/tool/git-auto.mjs +545 -0
  164. package/src/tool/git-full-auto.mjs +478 -0
  165. package/src/tool/image-util.mjs +276 -0
  166. package/src/tool/prompt/background_cancel.txt +1 -0
  167. package/src/tool/prompt/background_output.txt +1 -0
  168. package/src/tool/prompt/bash.txt +71 -0
  169. package/src/tool/prompt/codesearch.txt +18 -0
  170. package/src/tool/prompt/edit.txt +27 -0
  171. package/src/tool/prompt/enter_plan.txt +74 -0
  172. package/src/tool/prompt/exit_plan.txt +62 -0
  173. package/src/tool/prompt/glob.txt +33 -0
  174. package/src/tool/prompt/grep.txt +43 -0
  175. package/src/tool/prompt/list.txt +8 -0
  176. package/src/tool/prompt/multiedit.txt +20 -0
  177. package/src/tool/prompt/notebookedit.txt +21 -0
  178. package/src/tool/prompt/patch.txt +24 -0
  179. package/src/tool/prompt/question.txt +44 -0
  180. package/src/tool/prompt/read.txt +40 -0
  181. package/src/tool/prompt/task.txt +83 -0
  182. package/src/tool/prompt/todowrite.txt +117 -0
  183. package/src/tool/prompt/webfetch.txt +38 -0
  184. package/src/tool/prompt/websearch.txt +43 -0
  185. package/src/tool/prompt/write.txt +38 -0
  186. package/src/tool/prompt-loader.mjs +18 -0
  187. package/src/tool/question-prompt.mjs +86 -0
  188. package/src/tool/registry.mjs +1309 -0
  189. package/src/tool/task-tool.mjs +28 -0
  190. package/src/ui/activity-renderer.mjs +410 -0
  191. package/src/ui/repl-dashboard.mjs +357 -0
  192. package/src/usage/pricing.mjs +121 -0
  193. package/src/usage/usage-meter.mjs +113 -0
  194. package/src/util/git.mjs +496 -0
  195. package/src/util/template.mjs +10 -0
  196. package/src/util/yaml.mjs +100 -0
@@ -0,0 +1,276 @@
1
+ import { readFile, unlink, writeFile as fsWriteFile } from "node:fs/promises"
2
+ import { access } from "node:fs/promises"
3
+ import { tmpdir } from "node:os"
4
+ import { execFile } from "node:child_process"
5
+ import { promisify } from "node:util"
6
+ import path from "node:path"
7
+
8
+ const execFileAsync = promisify(execFile)
9
+
10
+ const IMAGE_EXTENSIONS = new Set([
11
+ ".png", ".jpg", ".jpeg", ".gif", ".webp", ".bmp", ".svg"
12
+ ])
13
+
14
+ const MIME_MAP = {
15
+ ".png": "image/png",
16
+ ".jpg": "image/jpeg",
17
+ ".jpeg": "image/jpeg",
18
+ ".gif": "image/gif",
19
+ ".webp": "image/webp",
20
+ ".bmp": "image/bmp",
21
+ ".svg": "image/svg+xml"
22
+ }
23
+
24
+ const MAX_IMAGE_SIZE = 20 * 1024 * 1024 // 20MB
25
+
26
+ export function isImagePath(filePath) {
27
+ const ext = path.extname(String(filePath || "")).toLowerCase()
28
+ return IMAGE_EXTENSIONS.has(ext)
29
+ }
30
+
31
+ export function mimeType(filePath) {
32
+ const ext = path.extname(String(filePath || "")).toLowerCase()
33
+ return MIME_MAP[ext] || "application/octet-stream"
34
+ }
35
+
36
+ /**
37
+ * Extract image file references from user input text.
38
+ * Supports:
39
+ * @path/to/image.png (explicit file)
40
+ * @https://example.com/image.png (explicit URL)
41
+ * Bare paths ending in image extensions
42
+ * Bare http(s) URLs ending in image extensions
43
+ * Returns { text, imagePaths, imageUrls } where text has image refs removed.
44
+ */
45
+ export function extractImageRefs(text, cwd = process.cwd()) {
46
+ const raw = String(text || "")
47
+ const imagePaths = []
48
+ const imageUrls = []
49
+
50
+ // Match @"url" or @url for http(s) URLs with image extensions
51
+ const atUrlPattern = /@"(https?:\/\/[^"]+\.(png|jpe?g|gif|webp|bmp|svg)(?:\?[^"]*)?)"|@(https?:\/\/\S+\.(png|jpe?g|gif|webp|bmp|svg)(?:\?\S*)?)/gi
52
+ let cleaned = raw.replace(atUrlPattern, (match, quoted, _e1, bare, _e2) => {
53
+ const ref = quoted || bare
54
+ if (ref) imageUrls.push(ref)
55
+ return ""
56
+ })
57
+
58
+ // Match @"path" or @path (with or without quotes) for local files
59
+ const atPattern = /@"([^"]+\.(png|jpe?g|gif|webp|bmp|svg))"|@(\S+\.(png|jpe?g|gif|webp|bmp|svg))/gi
60
+ cleaned = cleaned.replace(atPattern, (match, quoted, _e1, bare, _e2) => {
61
+ const ref = quoted || bare
62
+ if (ref) imagePaths.push(path.resolve(cwd, ref))
63
+ return ""
64
+ })
65
+
66
+ // Bare http(s) URLs ending in image extensions
67
+ const bareUrlPattern = /https?:\/\/\S+\.(png|jpe?g|gif|webp|bmp|svg)(?:\?\S*)?/gi
68
+ cleaned = cleaned.replace(bareUrlPattern, (match) => {
69
+ if (!imageUrls.includes(match)) imageUrls.push(match)
70
+ return ""
71
+ })
72
+
73
+ // Also detect bare absolute/relative paths ending in image extensions
74
+ const barePattern = /(?:(?:[A-Za-z]:[\\\/]|[.\/\\])[\w\-.\\/: ]*?\.(png|jpe?g|gif|webp|bmp|svg))/gi
75
+ cleaned = cleaned.replace(barePattern, (match) => {
76
+ const trimmed = match.trim()
77
+ if (trimmed && isImagePath(trimmed)) {
78
+ const resolved = path.resolve(cwd, trimmed)
79
+ if (!imagePaths.includes(resolved)) imagePaths.push(resolved)
80
+ return ""
81
+ }
82
+ return match
83
+ })
84
+
85
+ return {
86
+ text: cleaned.replace(/\s{2,}/g, " ").trim(),
87
+ imagePaths,
88
+ imageUrls
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Read an image file and return a content block.
94
+ * Returns { type: "image", path, mediaType, data } or null on failure.
95
+ */
96
+ export async function readImageAsBlock(filePath) {
97
+ try {
98
+ await access(filePath)
99
+ const buffer = await readFile(filePath)
100
+ if (buffer.length > MAX_IMAGE_SIZE) {
101
+ return { type: "text", text: `[image too large: ${filePath} (${Math.round(buffer.length / 1024 / 1024)}MB, max 20MB)]` }
102
+ }
103
+ const data = buffer.toString("base64")
104
+ const media = mimeType(filePath)
105
+ return {
106
+ type: "image",
107
+ path: filePath,
108
+ mediaType: media,
109
+ data
110
+ }
111
+ } catch (err) {
112
+ return { type: "text", text: `[image not found: ${filePath}]` }
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Build content blocks from user text + image paths.
118
+ * Returns an array of content blocks suitable for message.content.
119
+ * If no images, returns the plain text string (backward compatible).
120
+ */
121
+ /**
122
+ * Read an image from the system clipboard.
123
+ * Returns a content block { type: "image", mediaType, data } or null if no image.
124
+ * Supports Windows (PowerShell), macOS (pngpaste/osascript), Linux (xclip).
125
+ */
126
+ export async function readClipboardImage({ onStatus } = {}) {
127
+ const tempPath = path.join(tmpdir(), `kkcode-clip-${Date.now()}.png`)
128
+ const status = typeof onStatus === "function" ? onStatus : () => {}
129
+
130
+ try {
131
+ if (process.platform === "win32") {
132
+ status("reading clipboard...")
133
+ // Use escaped path for PowerShell; try multiple clipboard formats
134
+ const psPath = tempPath.replace(/\\/g, "\\\\").replace(/'/g, "''")
135
+ const psScript = [
136
+ "Add-Type -AssemblyName System.Windows.Forms",
137
+ "Add-Type -AssemblyName System.Drawing",
138
+ `$outPath = '${psPath}'`,
139
+ "$img = [System.Windows.Forms.Clipboard]::GetImage()",
140
+ "if ($img) {",
141
+ " $img.Save($outPath, [System.Drawing.Imaging.ImageFormat]::Png)",
142
+ " Write-Output 'saved'",
143
+ " exit",
144
+ "}",
145
+ // Fallback: try reading raw clipboard data stream (handles CF_DIB from some screenshot tools)
146
+ "$data = [System.Windows.Forms.Clipboard]::GetDataObject()",
147
+ "if ($data -and $data.GetDataPresent('PNG')) {",
148
+ " $stream = $data.GetData('PNG')",
149
+ " $fs = [System.IO.File]::Create($outPath)",
150
+ " $stream.CopyTo($fs)",
151
+ " $fs.Close()",
152
+ " $stream.Close()",
153
+ " Write-Output 'saved'",
154
+ " exit",
155
+ "}",
156
+ "if ($data -and $data.GetDataPresent([System.Windows.Forms.DataFormats]::Bitmap)) {",
157
+ " $bmp = $data.GetData([System.Windows.Forms.DataFormats]::Bitmap)",
158
+ " if ($bmp) {",
159
+ " $bmp.Save($outPath, [System.Drawing.Imaging.ImageFormat]::Png)",
160
+ " Write-Output 'saved'",
161
+ " exit",
162
+ " }",
163
+ "}",
164
+ "Write-Output 'empty'"
165
+ ].join("\n")
166
+ const { stdout } = await execFileAsync("powershell", [
167
+ "-NoProfile", "-NonInteractive", "-Command", psScript
168
+ ], { timeout: 10000 })
169
+ if (!stdout.includes("saved")) {
170
+ status("")
171
+ return null
172
+ }
173
+ } else if (process.platform === "darwin") {
174
+ status("reading clipboard...")
175
+ try {
176
+ await execFileAsync("pngpaste", [tempPath], { timeout: 5000 })
177
+ } catch {
178
+ const script = `set theFile to POSIX file "${tempPath}"\ntry\n set theImage to the clipboard as «class PNGf»\n set fp to open for access theFile with write permission\n write theImage to fp\n close access fp\non error\n return "empty"\nend try`
179
+ const { stdout } = await execFileAsync("osascript", ["-e", script], { timeout: 5000 })
180
+ if (stdout.includes("empty")) { status(""); return null }
181
+ }
182
+ } else {
183
+ status("reading clipboard...")
184
+ const result = await execFileAsync("xclip", [
185
+ "-selection", "clipboard", "-t", "image/png", "-o"
186
+ ], { timeout: 5000, maxBuffer: MAX_IMAGE_SIZE, encoding: "buffer" })
187
+ if (!result.stdout || !result.stdout.length) { status(""); return null }
188
+ await fsWriteFile(tempPath, result.stdout)
189
+ }
190
+
191
+ status("processing image...")
192
+ const block = await readImageAsBlock(tempPath)
193
+ await unlink(tempPath).catch(() => {})
194
+ status("")
195
+ return block && block.type === "image" ? block : null
196
+ } catch (err) {
197
+ await unlink(tempPath).catch(() => {})
198
+ status("")
199
+ return { type: "error", message: err.message || "clipboard read failed" }
200
+ }
201
+ }
202
+
203
+ /**
204
+ * Read text from the system clipboard.
205
+ * Returns string or null if clipboard is empty / not text.
206
+ */
207
+ export async function readClipboardText() {
208
+ try {
209
+ if (process.platform === "win32") {
210
+ const { stdout } = await execFileAsync("powershell", [
211
+ "-NoProfile", "-NonInteractive", "-Command", "Get-Clipboard"
212
+ ], { timeout: 5000 })
213
+ return stdout || null
214
+ } else if (process.platform === "darwin") {
215
+ const { stdout } = await execFileAsync("pbpaste", [], { timeout: 5000 })
216
+ return stdout || null
217
+ } else {
218
+ // Try xclip first, fall back to xsel
219
+ try {
220
+ const { stdout } = await execFileAsync("xclip", [
221
+ "-selection", "clipboard", "-o"
222
+ ], { timeout: 5000 })
223
+ return stdout || null
224
+ } catch {
225
+ const { stdout } = await execFileAsync("xsel", [
226
+ "--clipboard", "--output"
227
+ ], { timeout: 5000 })
228
+ return stdout || null
229
+ }
230
+ }
231
+ } catch {
232
+ return null
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Fetch a remote image URL and return a content block.
238
+ * Returns { type: "image_url", url } for provider-native URL support,
239
+ * or fetches + base64-encodes as fallback.
240
+ */
241
+ export async function fetchImageUrlAsBlock(url) {
242
+ try {
243
+ const response = await fetch(url, { signal: AbortSignal.timeout(15000) })
244
+ if (!response.ok) return { type: "text", text: `[image fetch failed: ${url} (${response.status})]` }
245
+ const contentType = response.headers.get("content-type") || ""
246
+ if (!contentType.startsWith("image/")) {
247
+ return { type: "text", text: `[not an image: ${url} (${contentType})]` }
248
+ }
249
+ const buffer = Buffer.from(await response.arrayBuffer())
250
+ if (buffer.length > MAX_IMAGE_SIZE) {
251
+ return { type: "text", text: `[image too large: ${url} (${Math.round(buffer.length / 1024 / 1024)}MB)]` }
252
+ }
253
+ return { type: "image", path: url, mediaType: contentType.split(";")[0], data: buffer.toString("base64") }
254
+ } catch (err) {
255
+ return { type: "text", text: `[image fetch error: ${url} — ${err.message}]` }
256
+ }
257
+ }
258
+
259
+ export async function buildContentBlocks(text, imagePaths = [], imageUrls = []) {
260
+ if (!imagePaths.length && !imageUrls.length) return text
261
+
262
+ const blocks = []
263
+ if (text) blocks.push({ type: "text", text })
264
+
265
+ for (const imgPath of imagePaths) {
266
+ const block = await readImageAsBlock(imgPath)
267
+ if (block) blocks.push(block)
268
+ }
269
+
270
+ for (const url of imageUrls) {
271
+ const block = await fetchImageUrlAsBlock(url)
272
+ if (block) blocks.push(block)
273
+ }
274
+
275
+ return blocks
276
+ }
@@ -0,0 +1 @@
1
+ Cancel a running background delegated task by `task_id`.
@@ -0,0 +1 @@
1
+ Retrieve logs/result for a background delegated task by `task_id`.
@@ -0,0 +1,71 @@
1
+ Executes a shell command in the workspace directory with optional timeout.
2
+
3
+ CRITICAL — tool selection rules. Do NOT use `bash` when a dedicated tool exists:
4
+ - Read files → use `read` (NEVER cat/head/tail/type/Get-Content)
5
+ - Search contents → use `grep` (NEVER bash grep/rg)
6
+ - Find files → use `glob` (NEVER bash find/ls/dir)
7
+ - Write files → use `write` (NEVER echo/cat heredoc)
8
+ - Edit files → use `edit` (NEVER sed/awk)
9
+ Only use `bash` for: git, npm, pip, docker, make, cargo, go, python, node, and other system commands.
10
+
11
+ Parameters:
12
+ - command (required): shell command to execute
13
+ - timeout (optional): timeout in ms (default 120000, max 600000)
14
+ - description (optional): human-readable description of what this command does. For simple commands keep it brief (5-10 words). For complex commands (piped commands, obscure flags), add enough context to clarify.
15
+ - run_in_background (optional): run as background task, returns task_id immediately
16
+
17
+ Rules:
18
+ - Always quote file paths that contain spaces with double quotes.
19
+ - NEVER run long-running/dev-server commands in foreground (npm run dev, jest --watch, webpack serve, nodemon, tsc --watch, etc.). Use run_in_background: true or tell user to run manually.
20
+ - Use description to explain non-obvious commands.
21
+ - When issuing multiple independent commands, make multiple bash calls in parallel.
22
+ - When commands depend on each other, chain with && (e.g. `git add . && git commit -m "msg"`).
23
+ - NEVER use interactive flags like -i (e.g. git rebase -i, git add -i) — they require interactive input which is not supported.
24
+
25
+ # Committing changes with git
26
+
27
+ Only create commits when requested by the user. If unclear, ask first. When creating a git commit:
28
+
29
+ 1. Run in parallel:
30
+ - `git status` (NEVER use -uall flag)
31
+ - `git diff` to see changes
32
+ - `git log --oneline -5` to follow commit message style
33
+
34
+ 2. Analyze changes and draft a concise commit message focusing on "why" not "what".
35
+ Do NOT commit files that likely contain secrets (.env, credentials.json, etc.).
36
+
37
+ 3. Stage and commit:
38
+ - Prefer `git add <specific-files>` over `git add -A` or `git add .`
39
+ - ALWAYS pass the commit message via a HEREDOC:
40
+ git commit -m "$(cat <<'EOF'
41
+ Commit message here.
42
+
43
+ Co-Authored-By: kkcode <noreply@kkcode.dev>
44
+ EOF
45
+ )"
46
+ - Run `git status` after commit to verify success
47
+
48
+ 4. Git safety rules:
49
+ - NEVER update git config
50
+ - NEVER run destructive commands (push --force, reset --hard, checkout ., clean -f, branch -D) unless user explicitly requests
51
+ - NEVER skip hooks (--no-verify) unless user explicitly requests
52
+ - NEVER force push to main/master — warn the user
53
+ - ALWAYS create NEW commits rather than amending, unless user explicitly asks for amend
54
+ - When a pre-commit hook fails, the commit did NOT happen — fix the issue, re-stage, create a NEW commit (do NOT --amend)
55
+ - NEVER commit unless the user explicitly asks
56
+
57
+ # Creating pull requests
58
+
59
+ When creating a PR:
60
+ 1. Run in parallel: git status, git diff, check remote tracking, git log + git diff <base>...HEAD
61
+ 2. Analyze ALL commits and draft PR title (under 70 chars) and summary
62
+ 3. Push and create PR:
63
+ gh pr create --title "title" --body "$(cat <<'EOF'
64
+ ## Summary
65
+ <1-3 bullet points>
66
+
67
+ ## Test plan
68
+ - [ ] testing checklist...
69
+ EOF
70
+ )"
71
+ 4. Return the PR URL
@@ -0,0 +1,18 @@
1
+ Search for code examples, API docs, and SDK usage via Exa AI.
2
+
3
+ IMPORTANT — When to use PROACTIVELY (reduce hallucination):
4
+ - Working with an unfamiliar library or framework
5
+ - Need correct function signatures, parameter types, or return values
6
+ - Looking for configuration examples or migration guides
7
+ - Unsure about best practices for a specific tool or pattern
8
+
9
+ Do NOT invent API signatures. Search first, then write code.
10
+
11
+ Parameters:
12
+ - query (required): describe what you need (e.g. "Express.js middleware error handling", "Prisma schema relations")
13
+ - tokensNum (optional): context size 1000-50000 (default: 5000). Use higher for comprehensive docs, lower for quick lookups.
14
+
15
+ Tips:
16
+ - Be specific: "Next.js 14 app router server actions" > "Next.js server"
17
+ - Include the language/framework name in the query
18
+ - For debugging, include the error message or symptom
@@ -0,0 +1,27 @@
1
+ Performs exact string replacements in files. Transactional with automatic rollback on failure.
2
+
3
+ Usage:
4
+ - You must use `read` at least once before editing. This tool will error if you attempt an edit without reading the file.
5
+ - When editing text from `read` output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + arrow (→). Everything after that arrow is the actual file content to match. Never include any part of the line number prefix in the `before` or `after` strings.
6
+ - ALWAYS prefer editing existing files. NEVER write new files unless explicitly required.
7
+ - Only use emojis if the user explicitly requests it.
8
+ - The edit will FAIL if `before` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use `replace_all` to change every instance.
9
+ - Use `replace_all` for replacing and renaming strings across the file. This parameter is useful for renaming a variable, function, or class.
10
+
11
+ Parameters:
12
+ - path (required): file path
13
+ - before (required): exact text to find in the file
14
+ - after (required): replacement text (must be different from before)
15
+ - replace_all (optional, default false): replace all occurrences instead of requiring unique match
16
+
17
+ When to use replace_all:
18
+ - Renaming a variable, function, or class across a file
19
+ - Changing an import path that appears multiple times
20
+ - Updating a repeated pattern (e.g. changing all "http://" to "https://")
21
+
22
+ Common mistakes and how to avoid them:
23
+ - Editing without reading first → always `read` before `edit`
24
+ - `before` too short, matches multiple locations → include surrounding lines for uniqueness
25
+ - Stale content after failed edit → re-read the file, it may have changed
26
+ - Including line number prefixes in `before` → only use actual file content, not the " 1→" prefix
27
+ - Using `edit` for whole-file replacement → use `write` instead for complete rewrites
@@ -0,0 +1,74 @@
1
+ Enter planning mode before implementing non-trivial tasks. Getting user sign-off on your approach before writing code prevents wasted effort and ensures alignment.
2
+
3
+ ## When to Use — call enter_plan PROACTIVELY when ANY of these apply:
4
+
5
+ 1. **New Feature Implementation**: Adding meaningful new functionality
6
+ - Example: "Add a logout button" — where should it go? What should happen on click?
7
+ - Example: "Add form validation" — what rules? What error messages?
8
+
9
+ 2. **Multiple Valid Approaches**: The task can be solved in several different ways
10
+ - Example: "Add caching to the API" — could use Redis, in-memory, file-based, etc.
11
+ - Example: "Improve performance" — many optimization strategies possible
12
+
13
+ 3. **Code Modifications**: Changes that affect existing behavior or structure
14
+ - Example: "Update the login flow" — what exactly should change?
15
+ - Example: "Refactor this component" — what's the target architecture?
16
+
17
+ 4. **Architectural Decisions**: The task requires choosing between patterns or technologies
18
+ - Example: "Add real-time updates" — WebSockets vs SSE vs polling
19
+ - Example: "Implement state management" — Redux vs Context vs custom solution
20
+
21
+ 5. **Multi-File Changes**: The task will likely touch more than 2-3 files
22
+ - Example: "Refactor the authentication system"
23
+ - Example: "Add a new API endpoint with tests"
24
+
25
+ 6. **Unclear Requirements**: You need to explore before understanding the full scope
26
+ - Example: "Make the app faster" — need to profile and identify bottlenecks
27
+ - Example: "Fix the bug in checkout" — need to investigate root cause
28
+
29
+ 7. **User Preferences Matter**: The implementation could reasonably go multiple ways.
30
+ If you would use `question` to clarify the approach, use enter_plan instead — it lets you explore first, then present options with context.
31
+
32
+ ## When NOT to Use
33
+
34
+ Only skip enter_plan for simple tasks:
35
+ - Single-line or few-line fixes (typos, obvious bugs, small tweaks)
36
+ - Adding a single function with clear requirements
37
+ - Tasks where the user has given very specific, detailed instructions
38
+ - Pure research/exploration tasks (use `task` with explore subagent instead)
39
+
40
+ <example>
41
+ GOOD — Use enter_plan:
42
+ User: "Add user authentication to the app"
43
+ → Requires architectural decisions (session vs JWT, storage, middleware)
44
+
45
+ User: "Optimize the database queries"
46
+ → Multiple approaches possible, need to profile first
47
+
48
+ User: "Add a delete button to the user profile"
49
+ → Involves placement, confirmation dialog, API call, error handling, state updates
50
+
51
+ User: "Update the error handling in the API"
52
+ → Affects multiple files, user should approve the approach
53
+ </example>
54
+
55
+ <example>
56
+ BAD — Don't use enter_plan:
57
+ User: "Fix the typo in the README"
58
+ → Straightforward, no planning needed
59
+
60
+ User: "Add a console.log to debug this function"
61
+ → Simple, obvious implementation
62
+
63
+ User: "What files handle routing?"
64
+ → Research task, not implementation planning
65
+ </example>
66
+
67
+ ## After calling enter_plan:
68
+
69
+ 1. Thoroughly explore the codebase using `glob`, `grep`, and `read`
70
+ 2. Understand existing patterns and architecture
71
+ 3. Design an implementation approach
72
+ 4. Present your plan with `exit_plan` for user approval
73
+ 5. Use `question` if you need to clarify approaches DURING planning
74
+ 6. Wait for approval before making any code changes
@@ -0,0 +1,62 @@
1
+ Present your completed plan to the user for approval. The user will see the plan and can approve, reject, or request changes.
2
+
3
+ ## How This Tool Works
4
+ - You should have already outlined your plan in your text response after calling enter_plan
5
+ - This tool submits the plan for user review
6
+ - The user will see the plan content and the list of files affected
7
+
8
+ ## When to Use
9
+ IMPORTANT: Only use this tool when planning implementation steps for a task that requires writing code.
10
+ For research tasks where you're gathering information, searching files, or understanding the codebase — do NOT use this tool.
11
+
12
+ ## Before Using This Tool
13
+ Ensure your plan is complete and unambiguous:
14
+ - If you have unresolved questions about requirements or approach, use `question` first
15
+ - Once your plan is finalized, use THIS tool to request approval
16
+ - Do NOT use `question` to ask "Is this plan okay?" — that's exactly what exit_plan does
17
+
18
+ ## Requirements
19
+ - You MUST have called enter_plan first
20
+ - Your plan must be complete and specific — include file paths, function names, and concrete changes
21
+ - Include ALL files that will be created or modified in the `files` parameter
22
+
23
+ ## Parameters
24
+ - plan (required): the complete plan text to present to the user
25
+ - files (optional): array of file paths that will be created or modified
26
+
27
+ ## User Response
28
+ The user will:
29
+ - Approve: you proceed with implementation
30
+ - Reject: you receive their feedback and should revise
31
+ - Provide custom feedback: treat as rejection with specific guidance
32
+
33
+ ## Examples
34
+
35
+ <good-example>
36
+ # Complete plan with structure
37
+ plan:
38
+ ## Context
39
+ Adding dark mode toggle to the settings page.
40
+
41
+ ## Approach
42
+ Use CSS custom properties for theme switching with React Context for state management.
43
+
44
+ ## Files to modify
45
+ - src/contexts/ThemeContext.tsx — new context provider
46
+ - src/components/Settings/ThemeToggle.tsx — new toggle component
47
+ - src/styles/variables.css — add dark theme variables
48
+ - src/App.tsx — wrap with ThemeProvider
49
+
50
+ ## Verification
51
+ - Toggle switches theme visually
52
+ - Theme persists across page refresh (localStorage)
53
+ - All existing tests still pass
54
+ </good-example>
55
+ <bad-example>
56
+ # Plan too vague — no files, no specifics
57
+ plan: "I'll add dark mode by creating some components and updating styles"
58
+ </bad-example>
59
+
60
+ IMPORTANT:
61
+ - Do NOT start implementation before receiving approval
62
+ - If rejected, address the user's feedback and submit a revised plan
@@ -0,0 +1,33 @@
1
+ Fast file pattern matching tool that works with any codebase size.
2
+ Supports glob patterns like "**/*.js" or "src/**/*.ts".
3
+ Returns matching file paths sorted by name, limited to 200 results.
4
+ ALWAYS use `glob` instead of `bash` with find/ls/dir.
5
+
6
+ Parameters:
7
+ - pattern (required): glob pattern to match files against
8
+ - path (optional): directory to search in (default: cwd). Use this to limit search to a subdirectory.
9
+
10
+ Examples:
11
+ - "**/*.mjs" — all .mjs files recursively
12
+ - "src/**/*.ts" — TypeScript files under src/
13
+ - "*.json" — JSON files in root only
14
+ - "src/components/**" — everything under components/
15
+ - pattern="**/*.test.mjs" path="src/tool/" — test files under src/tool/
16
+
17
+ ## When NOT to Use
18
+ - Do NOT use glob to search file *contents* — use `grep` for that.
19
+ - Do NOT use glob when you need a simple directory listing — use `bash` with `ls` only if truly needed.
20
+ - Do NOT use glob to find a file when you already know its exact path — use `read` directly.
21
+ - If you need to search both file names AND contents, use glob for names and grep for contents in parallel.
22
+
23
+ Tips:
24
+ - When doing an open-ended search that may require multiple rounds of globbing and grepping, use the `task` tool with explore subagent instead.
25
+ - You can call multiple glob tools in a single response. It is always better to speculatively perform multiple searches in parallel if they are potentially useful.
26
+ - Use `path` parameter to narrow search to a specific directory for faster results.
27
+ - When unsure of exact file naming convention, launch multiple speculative globs in parallel:
28
+ <good-example>
29
+ # Looking for config files — try multiple patterns at once:
30
+ glob "**/*.config.{js,ts,mjs}"
31
+ glob "**/config.{js,ts,mjs,json}"
32
+ glob "**/.{eslint,prettier,babel}*"
33
+ </good-example>
@@ -0,0 +1,43 @@
1
+ Search file contents by regex pattern across the project.
2
+ ALWAYS use `grep` instead of `bash` with grep/rg.
3
+ Supports full regex syntax (e.g. "log.*Error", "function\\s+\\w+").
4
+
5
+ Parameters:
6
+ - pattern (required): regex or literal string to search for
7
+ - path (optional): file or directory to search in (default: cwd). Use this to search within a specific file or subdirectory.
8
+ - output_mode (optional): "content" (matching lines with line numbers), "files" (file paths only, default), "count" (match counts per file)
9
+ - type (optional): file type filter — js, ts, py, go, rs, etc. More efficient than glob for standard types.
10
+ - glob (optional): glob filter — "*.mjs", "src/**/*.ts"
11
+ - context (optional): lines of context around each match (-C)
12
+ - before_context (optional): lines before each match (-B)
13
+ - after_context (optional): lines after each match (-A)
14
+ - ignoreCase (optional): case-insensitive search
15
+ - maxCount (optional): max matches per file
16
+ - multiline (optional): enable cross-line matching. By default patterns match within single lines only. Use for patterns like "struct \\{[\\s\\S]*?field" that span multiple lines.
17
+ - head_limit (optional): limit output to first N lines/entries. Works across all output modes.
18
+ - offset (optional): skip first N lines/entries before applying head_limit. Combine with head_limit for paginated browsing.
19
+
20
+ ## When NOT to Use
21
+ - Do NOT use grep to find files by *name* — use `glob` for that.
22
+ - Do NOT use grep to read a whole file — use `read` instead.
23
+ - Do NOT use grep when you already know the exact file and line — use `read` with offset/limit.
24
+ - For open-ended exploration requiring multiple search rounds, use `task` with explore subagent.
25
+
26
+ Tips:
27
+ - Use `path` to search within a specific file: grep pattern="TODO" path="src/main.mjs"
28
+ - Use `path` to search a directory: grep pattern="import" path="src/utils/"
29
+ - Use output_mode "files" for quick file discovery, "content" for understanding code
30
+ - Use multiline to match patterns spanning multiple lines
31
+ - Combine head_limit + offset for paginated browsing of large result sets:
32
+ <example>
33
+ # Page 1: first 20 matches
34
+ grep pattern="TODO" output_mode="content" head_limit=20
35
+ # Page 2: next 20 matches
36
+ grep pattern="TODO" output_mode="content" head_limit=20 offset=20
37
+ </example>
38
+ - Pattern syntax uses ripgrep — literal braces need escaping (use "interface\\{\\}" to find "interface{}" in Go)
39
+
40
+ ## Using grep with patch/edit:
41
+ - Use output_mode="content" to see line numbers alongside matches.
42
+ - Line numbers from grep correspond directly to `read` (offset/limit) and `patch` (start_line/end_line).
43
+ - Workflow: grep to find location → read surrounding context → patch or edit the section.
@@ -0,0 +1,8 @@
1
+ List files and subdirectories in a single directory level.
2
+ Returns entries with type prefix: d=directory, f=file.
3
+
4
+ Use `list` for quick directory overview (what's in this folder?).
5
+ Use `glob` for recursive pattern matching across the project (find all *.ts files).
6
+ Use `grep` to search file contents by pattern.
7
+
8
+ Do NOT use `bash` with ls or find — use `list` or `glob` instead.
@@ -0,0 +1,20 @@
1
+ Apply multiple file edits in a single atomic operation.
2
+ All changes succeed together or are rolled back entirely — no half-applied states.
3
+
4
+ When to use (instead of sequential `edit` calls):
5
+ - Renaming an export and updating all its import sites
6
+ - Refactoring a function signature and all call sites
7
+ - Moving code between files (delete from one, add to another)
8
+ - Any change where partial application would break the codebase
9
+
10
+ Parameters:
11
+ - changes (required): array of file operations:
12
+ - path: file path
13
+ - before: text to find (omit to create a new file)
14
+ - after: replacement text (for edits) or full content (for new files)
15
+ - replace_all: replace all occurrences of `before` (default: false)
16
+
17
+ Rules:
18
+ - You MUST `read` each file before editing it (same as `edit` tool).
19
+ - If any change fails validation (no match, ambiguous match), the entire batch is rejected before any writes.
20
+ - On write failure mid-batch, all previously applied changes are rolled back.
@@ -0,0 +1,21 @@
1
+ Edit a Jupyter notebook (.ipynb) cell. Supports replace, insert, and delete operations.
2
+
3
+ Parameters:
4
+ - path (required): absolute or relative path to the .ipynb file
5
+ - cell_number (optional): 0-indexed cell number to operate on (default: 0)
6
+ - new_source (required): new cell source content (ignored for delete)
7
+ - cell_type (optional): "code" or "markdown" — required for insert, defaults to existing cell type for replace
8
+ - edit_mode (optional): "replace" (default), "insert", or "delete"
9
+
10
+ Operations:
11
+ - replace: Replace the source of cell at cell_number with new_source. Preserves cell type unless cell_type is specified.
12
+ - insert: Insert a new cell AFTER cell_number. cell_type is required. If cell_number is -1, inserts at the beginning.
13
+ - delete: Remove the cell at cell_number. new_source is ignored but must be provided.
14
+
15
+ IMPORTANT:
16
+ - The notebook must be a valid .ipynb JSON file with a "cells" array.
17
+ - cell_number is 0-indexed. The first cell is 0, second is 1, etc.
18
+ - For insert mode, cell_type must be specified ("code" or "markdown").
19
+ - Cell outputs are preserved during replace; cleared only if cell_type changes to "markdown".
20
+ - When inserting code cells, outputs default to an empty array.
21
+ - This tool reads the notebook, modifies the cells array, and writes it back atomically.