@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.
- package/LICENSE +674 -0
- package/README.md +445 -0
- package/package.json +46 -0
- package/src/agent/agent.mjs +170 -0
- package/src/agent/custom-agent-loader.mjs +158 -0
- package/src/agent/generator.mjs +115 -0
- package/src/agent/prompt/architect.txt +36 -0
- package/src/agent/prompt/build-fixer.txt +71 -0
- package/src/agent/prompt/build.txt +101 -0
- package/src/agent/prompt/compaction.txt +12 -0
- package/src/agent/prompt/explore.txt +29 -0
- package/src/agent/prompt/guide.txt +40 -0
- package/src/agent/prompt/longagent.txt +178 -0
- package/src/agent/prompt/plan.txt +50 -0
- package/src/agent/prompt/researcher.txt +23 -0
- package/src/agent/prompt/reviewer.txt +44 -0
- package/src/agent/prompt/security-reviewer.txt +62 -0
- package/src/agent/prompt/tdd-guide.txt +84 -0
- package/src/agent/prompt/title.txt +8 -0
- package/src/command/custom-commands.mjs +57 -0
- package/src/commands/agent.mjs +71 -0
- package/src/commands/audit.mjs +77 -0
- package/src/commands/background.mjs +86 -0
- package/src/commands/chat.mjs +114 -0
- package/src/commands/command.mjs +41 -0
- package/src/commands/config.mjs +44 -0
- package/src/commands/doctor.mjs +148 -0
- package/src/commands/hook.mjs +29 -0
- package/src/commands/init.mjs +141 -0
- package/src/commands/longagent.mjs +100 -0
- package/src/commands/mcp.mjs +89 -0
- package/src/commands/permission.mjs +36 -0
- package/src/commands/prompt.mjs +42 -0
- package/src/commands/review.mjs +266 -0
- package/src/commands/rule.mjs +34 -0
- package/src/commands/session.mjs +235 -0
- package/src/commands/theme.mjs +98 -0
- package/src/commands/usage.mjs +91 -0
- package/src/config/defaults.mjs +195 -0
- package/src/config/import-config.mjs +76 -0
- package/src/config/load-config.mjs +76 -0
- package/src/config/schema.mjs +509 -0
- package/src/context.mjs +40 -0
- package/src/core/constants.mjs +46 -0
- package/src/core/errors.mjs +57 -0
- package/src/core/events.mjs +29 -0
- package/src/core/types.mjs +57 -0
- package/src/github/api.mjs +78 -0
- package/src/github/auth.mjs +286 -0
- package/src/github/flow.mjs +298 -0
- package/src/github/workspace.mjs +212 -0
- package/src/index.mjs +82 -0
- package/src/knowledge/api-design.txt +9 -0
- package/src/knowledge/cpp.txt +10 -0
- package/src/knowledge/docker.txt +10 -0
- package/src/knowledge/dotnet.txt +9 -0
- package/src/knowledge/electron.txt +10 -0
- package/src/knowledge/flutter.txt +10 -0
- package/src/knowledge/go.txt +9 -0
- package/src/knowledge/graphql.txt +10 -0
- package/src/knowledge/java.txt +9 -0
- package/src/knowledge/kotlin.txt +10 -0
- package/src/knowledge/loader.mjs +125 -0
- package/src/knowledge/next.txt +8 -0
- package/src/knowledge/node.txt +8 -0
- package/src/knowledge/nuxt.txt +9 -0
- package/src/knowledge/php.txt +10 -0
- package/src/knowledge/python.txt +10 -0
- package/src/knowledge/react-native.txt +10 -0
- package/src/knowledge/react.txt +9 -0
- package/src/knowledge/ruby.txt +11 -0
- package/src/knowledge/rust.txt +9 -0
- package/src/knowledge/svelte.txt +9 -0
- package/src/knowledge/swift.txt +10 -0
- package/src/knowledge/tailwind.txt +10 -0
- package/src/knowledge/testing.txt +8 -0
- package/src/knowledge/typescript.txt +8 -0
- package/src/knowledge/vue.txt +9 -0
- package/src/mcp/client-http.mjs +157 -0
- package/src/mcp/client-sse.mjs +286 -0
- package/src/mcp/client-stdio.mjs +451 -0
- package/src/mcp/registry.mjs +394 -0
- package/src/mcp/stdio-framing.mjs +127 -0
- package/src/orchestration/background-manager.mjs +358 -0
- package/src/orchestration/background-worker.mjs +245 -0
- package/src/orchestration/longagent-manager.mjs +116 -0
- package/src/orchestration/stage-scheduler.mjs +489 -0
- package/src/orchestration/subagent-router.mjs +62 -0
- package/src/orchestration/task-scheduler.mjs +74 -0
- package/src/permission/engine.mjs +92 -0
- package/src/permission/exec-policy.mjs +372 -0
- package/src/permission/prompt.mjs +39 -0
- package/src/permission/rules.mjs +120 -0
- package/src/permission/workspace-trust.mjs +44 -0
- package/src/plugin/builtin-hooks/console-warn.mjs +41 -0
- package/src/plugin/builtin-hooks/extract-patterns.mjs +75 -0
- package/src/plugin/builtin-hooks/post-edit-format.mjs +57 -0
- package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +61 -0
- package/src/plugin/builtin-hooks/strategic-compaction.mjs +38 -0
- package/src/plugin/hook-bus.mjs +154 -0
- package/src/provider/anthropic.mjs +389 -0
- package/src/provider/ollama.mjs +236 -0
- package/src/provider/openai-compatible.mjs +1 -0
- package/src/provider/openai.mjs +339 -0
- package/src/provider/retry-policy.mjs +68 -0
- package/src/provider/router.mjs +228 -0
- package/src/provider/sse.mjs +91 -0
- package/src/repl.mjs +2929 -0
- package/src/review/diff-parser.mjs +36 -0
- package/src/review/rejection-queue.mjs +62 -0
- package/src/review/review-store.mjs +21 -0
- package/src/review/risk-score.mjs +61 -0
- package/src/rules/load-rules.mjs +64 -0
- package/src/runtime.mjs +1 -0
- package/src/session/checkpoint.mjs +239 -0
- package/src/session/compaction.mjs +276 -0
- package/src/session/engine.mjs +225 -0
- package/src/session/instinct-manager.mjs +172 -0
- package/src/session/instruction-loader.mjs +25 -0
- package/src/session/longagent-plan.mjs +329 -0
- package/src/session/longagent-scaffold.mjs +100 -0
- package/src/session/longagent.mjs +1462 -0
- package/src/session/loop.mjs +905 -0
- package/src/session/memory-loader.mjs +75 -0
- package/src/session/project-context.mjs +367 -0
- package/src/session/prompt/anthropic.txt +151 -0
- package/src/session/prompt/beast.txt +37 -0
- package/src/session/prompt/max-steps.txt +6 -0
- package/src/session/prompt/plan.txt +9 -0
- package/src/session/prompt/qwen.txt +46 -0
- package/src/session/prompt-loader.mjs +18 -0
- package/src/session/recovery.mjs +52 -0
- package/src/session/store.mjs +503 -0
- package/src/session/system-prompt.mjs +260 -0
- package/src/session/task-validator.mjs +266 -0
- package/src/session/usability-gates.mjs +379 -0
- package/src/skill/builtin/backend-patterns.mjs +123 -0
- package/src/skill/builtin/commit.mjs +64 -0
- package/src/skill/builtin/debug.mjs +45 -0
- package/src/skill/builtin/frontend-patterns.mjs +120 -0
- package/src/skill/builtin/frontend.mjs +188 -0
- package/src/skill/builtin/init.mjs +220 -0
- package/src/skill/builtin/review.mjs +49 -0
- package/src/skill/builtin/security-checklist.mjs +80 -0
- package/src/skill/builtin/tdd.mjs +54 -0
- package/src/skill/generator.mjs +113 -0
- package/src/skill/registry.mjs +336 -0
- package/src/storage/audit-store.mjs +83 -0
- package/src/storage/event-log.mjs +82 -0
- package/src/storage/ghost-commit-store.mjs +235 -0
- package/src/storage/json-store.mjs +53 -0
- package/src/storage/paths.mjs +148 -0
- package/src/theme/color.mjs +64 -0
- package/src/theme/default-theme.mjs +29 -0
- package/src/theme/load-theme.mjs +71 -0
- package/src/theme/markdown.mjs +135 -0
- package/src/theme/schema.mjs +45 -0
- package/src/theme/status-bar.mjs +158 -0
- package/src/tool/audit-wrapper.mjs +38 -0
- package/src/tool/edit-transaction.mjs +126 -0
- package/src/tool/executor.mjs +109 -0
- package/src/tool/file-lock-manager.mjs +85 -0
- package/src/tool/git-auto.mjs +545 -0
- package/src/tool/git-full-auto.mjs +478 -0
- package/src/tool/image-util.mjs +276 -0
- package/src/tool/prompt/background_cancel.txt +1 -0
- package/src/tool/prompt/background_output.txt +1 -0
- package/src/tool/prompt/bash.txt +71 -0
- package/src/tool/prompt/codesearch.txt +18 -0
- package/src/tool/prompt/edit.txt +27 -0
- package/src/tool/prompt/enter_plan.txt +74 -0
- package/src/tool/prompt/exit_plan.txt +62 -0
- package/src/tool/prompt/glob.txt +33 -0
- package/src/tool/prompt/grep.txt +43 -0
- package/src/tool/prompt/list.txt +8 -0
- package/src/tool/prompt/multiedit.txt +20 -0
- package/src/tool/prompt/notebookedit.txt +21 -0
- package/src/tool/prompt/patch.txt +24 -0
- package/src/tool/prompt/question.txt +44 -0
- package/src/tool/prompt/read.txt +40 -0
- package/src/tool/prompt/task.txt +83 -0
- package/src/tool/prompt/todowrite.txt +117 -0
- package/src/tool/prompt/webfetch.txt +38 -0
- package/src/tool/prompt/websearch.txt +43 -0
- package/src/tool/prompt/write.txt +38 -0
- package/src/tool/prompt-loader.mjs +18 -0
- package/src/tool/question-prompt.mjs +86 -0
- package/src/tool/registry.mjs +1309 -0
- package/src/tool/task-tool.mjs +28 -0
- package/src/ui/activity-renderer.mjs +410 -0
- package/src/ui/repl-dashboard.mjs +357 -0
- package/src/usage/pricing.mjs +121 -0
- package/src/usage/usage-meter.mjs +113 -0
- package/src/util/git.mjs +496 -0
- package/src/util/template.mjs +10 -0
- 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.
|