@kkelly-offical/kkcode 0.1.6 → 0.1.7
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/package.json +1 -1
- package/src/agent/agent.mjs +220 -211
- package/src/agent/prompt/bug-hunter.txt +90 -0
- package/src/repl.mjs +58 -6
- package/src/session/compaction.mjs +298 -276
- package/src/session/engine.mjs +5 -0
- package/src/session/longagent-hybrid.mjs +21 -5
- package/src/session/longagent.mjs +21 -5
- package/src/session/loop.mjs +65 -40
- package/src/session/prompt/agent.txt +25 -0
- package/src/session/prompt/plan.txt +31 -9
- package/src/session/rollback.mjs +196 -0
- package/src/session/store.mjs +12 -3
- package/src/session/system-prompt.mjs +273 -260
- package/src/tool/question-prompt.mjs +93 -86
package/package.json
CHANGED
package/src/agent/agent.mjs
CHANGED
|
@@ -1,211 +1,220 @@
|
|
|
1
|
-
import { readFile } from "node:fs/promises"
|
|
2
|
-
import path from "node:path"
|
|
3
|
-
import { fileURLToPath } from "node:url"
|
|
4
|
-
|
|
5
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
6
|
-
|
|
7
|
-
const registry = new Map()
|
|
8
|
-
|
|
9
|
-
function promptPath(name) {
|
|
10
|
-
return path.join(__dirname, "prompt", `${name}.txt`)
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
async function loadPrompt(name) {
|
|
14
|
-
try {
|
|
15
|
-
return (await readFile(promptPath(name), "utf8")).trim()
|
|
16
|
-
} catch {
|
|
17
|
-
return ""
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function defineAgent(spec) {
|
|
22
|
-
const agent = {
|
|
23
|
-
name: spec.name,
|
|
24
|
-
description: spec.description || "",
|
|
25
|
-
mode: spec.mode || "primary",
|
|
26
|
-
permission: spec.permission || "default",
|
|
27
|
-
tools: spec.tools || null,
|
|
28
|
-
model: spec.model || null,
|
|
29
|
-
temperature: spec.temperature ?? null,
|
|
30
|
-
maxTurns: spec.maxTurns || null,
|
|
31
|
-
hidden: spec.hidden || false,
|
|
32
|
-
promptFile: spec.promptFile || spec.name,
|
|
33
|
-
_promptCache: spec._promptCache ?? null,
|
|
34
|
-
_customAgent: spec._customAgent || false,
|
|
35
|
-
_scope: spec._scope || null,
|
|
36
|
-
_source: spec._source || null
|
|
37
|
-
}
|
|
38
|
-
registry.set(agent.name, agent)
|
|
39
|
-
return agent
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export async function getAgentPrompt(name) {
|
|
43
|
-
const agent = registry.get(name)
|
|
44
|
-
if (!agent) return ""
|
|
45
|
-
if (agent._promptCache !== null) return agent._promptCache
|
|
46
|
-
agent._promptCache = await loadPrompt(agent.promptFile)
|
|
47
|
-
return agent._promptCache
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export function getAgent(name) {
|
|
51
|
-
return registry.get(name) || null
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
export function listAgents({ includeHidden = false } = {}) {
|
|
55
|
-
const agents = [...registry.values()]
|
|
56
|
-
return includeHidden ? agents : agents.filter((a) => !a.hidden)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
export function resolveAgentForMode(mode) {
|
|
60
|
-
if (registry.has(mode)) return registry.get(mode)
|
|
61
|
-
const modeMap = { ask: "build", plan: "plan", agent: "build", longagent: "longagent" }
|
|
62
|
-
const mapped = modeMap[mode]
|
|
63
|
-
return mapped ? registry.get(mapped) || null : null
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
defineAgent({
|
|
67
|
-
name: "build",
|
|
68
|
-
description: "Default agent with full tool access for code development",
|
|
69
|
-
mode: "primary",
|
|
70
|
-
permission: "full",
|
|
71
|
-
tools: null
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
defineAgent({
|
|
75
|
-
name: "plan",
|
|
76
|
-
description: "Read-only analysis agent, no file editing allowed",
|
|
77
|
-
mode: "primary",
|
|
78
|
-
permission: "readonly",
|
|
79
|
-
tools: ["read", "glob", "grep", "list", "bash"]
|
|
80
|
-
})
|
|
81
|
-
|
|
82
|
-
defineAgent({
|
|
83
|
-
name: "explore",
|
|
84
|
-
description: "Fast file search subagent for codebase exploration",
|
|
85
|
-
mode: "subagent",
|
|
86
|
-
permission: "readonly",
|
|
87
|
-
tools: ["read", "glob", "grep", "list", "bash"]
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
defineAgent({
|
|
91
|
-
name: "longagent",
|
|
92
|
-
description: "Persistent iterative execution agent for complex multi-step tasks",
|
|
93
|
-
mode: "primary",
|
|
94
|
-
permission: "full",
|
|
95
|
-
tools: null
|
|
96
|
-
})
|
|
97
|
-
|
|
98
|
-
defineAgent({
|
|
99
|
-
name: "reviewer",
|
|
100
|
-
description: "Code review specialist for analyzing code quality, bugs, and security issues",
|
|
101
|
-
mode: "subagent",
|
|
102
|
-
permission: "readonly",
|
|
103
|
-
tools: ["read", "glob", "grep", "list", "bash"]
|
|
104
|
-
})
|
|
105
|
-
|
|
106
|
-
defineAgent({
|
|
107
|
-
name: "researcher",
|
|
108
|
-
description: "Deep codebase research and web-augmented exploration agent",
|
|
109
|
-
mode: "subagent",
|
|
110
|
-
permission: "readonly",
|
|
111
|
-
tools: ["read", "glob", "grep", "list", "bash", "websearch", "codesearch", "webfetch"]
|
|
112
|
-
})
|
|
113
|
-
|
|
114
|
-
defineAgent({
|
|
115
|
-
name: "architect",
|
|
116
|
-
description: "Feature architecture designer. Analyzes codebase patterns, designs implementation blueprints with specific files, component designs, data flows.",
|
|
117
|
-
mode: "subagent",
|
|
118
|
-
permission: "readonly",
|
|
119
|
-
tools: ["read", "glob", "grep", "list", "bash"]
|
|
120
|
-
})
|
|
121
|
-
|
|
122
|
-
defineAgent({
|
|
123
|
-
name: "guide",
|
|
124
|
-
description: "kkcode self-help guide. Answers questions about kkcode features, tools, configuration, modes, skills, hooks, MCP servers, and usage patterns by searching the kkcode source code.",
|
|
125
|
-
mode: "subagent",
|
|
126
|
-
permission: "readonly",
|
|
127
|
-
tools: ["read", "glob", "grep", "list", "webfetch", "websearch"]
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
defineAgent({
|
|
131
|
-
name: "security-reviewer",
|
|
132
|
-
description: "Security audit specialist. Performs OWASP Top 10 checks, hardcoded secret scans, dependency audits, and authentication/authorization reviews.",
|
|
133
|
-
mode: "subagent",
|
|
134
|
-
permission: "readonly",
|
|
135
|
-
tools: ["read", "glob", "grep", "list", "bash"]
|
|
136
|
-
})
|
|
137
|
-
|
|
138
|
-
defineAgent({
|
|
139
|
-
name: "tdd-guide",
|
|
140
|
-
description: "TDD specialist. Guides and executes test-driven development: scaffold interfaces, write failing tests (RED), implement minimum code (GREEN), refactor (IMPROVE). Targets 80%+ coverage.",
|
|
141
|
-
mode: "subagent",
|
|
142
|
-
permission: "full",
|
|
143
|
-
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
defineAgent({
|
|
147
|
-
name: "build-fixer",
|
|
148
|
-
description: "Build error diagnosis and repair. Analyzes build failures, identifies root causes, applies fixes, and verifies the build succeeds. Supports TypeScript, Python, Go, Rust, Java.",
|
|
149
|
-
mode: "subagent",
|
|
150
|
-
permission: "full",
|
|
151
|
-
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
152
|
-
})
|
|
153
|
-
|
|
154
|
-
defineAgent({
|
|
155
|
-
name: "frontend-designer",
|
|
156
|
-
description: "Frontend design specialist. Creates polished, distinctive UIs with strong aesthetics — typography, color, motion, layout. Avoids generic AI-style designs. Reads project design system (Tailwind, CSS vars, component libraries) and produces production-grade frontend code.",
|
|
157
|
-
mode: "subagent",
|
|
158
|
-
permission: "full",
|
|
159
|
-
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
160
|
-
})
|
|
161
|
-
|
|
162
|
-
defineAgent({
|
|
163
|
-
name: "compaction",
|
|
164
|
-
description: "Conversation summarizer for context compression",
|
|
165
|
-
mode: "subagent",
|
|
166
|
-
permission: "none",
|
|
167
|
-
tools: [],
|
|
168
|
-
hidden: true
|
|
169
|
-
})
|
|
170
|
-
|
|
171
|
-
defineAgent({
|
|
172
|
-
name: "title",
|
|
173
|
-
description: "Session title generator",
|
|
174
|
-
mode: "subagent",
|
|
175
|
-
permission: "none",
|
|
176
|
-
tools: [],
|
|
177
|
-
hidden: true
|
|
178
|
-
})
|
|
179
|
-
|
|
180
|
-
// 4-Stage LongAgent agents
|
|
181
|
-
defineAgent({
|
|
182
|
-
name: "preview-agent",
|
|
183
|
-
description: "4-Stage LongAgent: Stage 1 - Previewing Agent. Explores codebase, extracts requirements, no editing allowed.",
|
|
184
|
-
mode: "subagent",
|
|
185
|
-
permission: "readonly",
|
|
186
|
-
tools: ["read", "glob", "grep", "list", "bash", "question", "todowrite"]
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
defineAgent({
|
|
190
|
-
name: "blueprint-agent",
|
|
191
|
-
description: "4-Stage LongAgent: Stage 2 - Blueprint Agent. Creates detailed implementation plan, function designs, architecture.",
|
|
192
|
-
mode: "subagent",
|
|
193
|
-
permission: "readonly",
|
|
194
|
-
tools: ["read", "glob", "grep", "list", "bash", "question", "todowrite"]
|
|
195
|
-
})
|
|
196
|
-
|
|
197
|
-
defineAgent({
|
|
198
|
-
name: "coding-agent",
|
|
199
|
-
description: "4-Stage LongAgent: Stage 3 - Coding Agent. Implements code strictly according to blueprint.",
|
|
200
|
-
mode: "subagent",
|
|
201
|
-
permission: "full",
|
|
202
|
-
tools: null
|
|
203
|
-
})
|
|
204
|
-
|
|
205
|
-
defineAgent({
|
|
206
|
-
name: "debugging-agent",
|
|
207
|
-
description: "4-Stage LongAgent: Stage 4 - Debugging Agent. Verifies implementation, runs tests, finds and fixes bugs.",
|
|
208
|
-
mode: "subagent",
|
|
209
|
-
permission: "full",
|
|
210
|
-
tools: null
|
|
211
|
-
})
|
|
1
|
+
import { readFile } from "node:fs/promises"
|
|
2
|
+
import path from "node:path"
|
|
3
|
+
import { fileURLToPath } from "node:url"
|
|
4
|
+
|
|
5
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
|
|
7
|
+
const registry = new Map()
|
|
8
|
+
|
|
9
|
+
function promptPath(name) {
|
|
10
|
+
return path.join(__dirname, "prompt", `${name}.txt`)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function loadPrompt(name) {
|
|
14
|
+
try {
|
|
15
|
+
return (await readFile(promptPath(name), "utf8")).trim()
|
|
16
|
+
} catch {
|
|
17
|
+
return ""
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function defineAgent(spec) {
|
|
22
|
+
const agent = {
|
|
23
|
+
name: spec.name,
|
|
24
|
+
description: spec.description || "",
|
|
25
|
+
mode: spec.mode || "primary",
|
|
26
|
+
permission: spec.permission || "default",
|
|
27
|
+
tools: spec.tools || null,
|
|
28
|
+
model: spec.model || null,
|
|
29
|
+
temperature: spec.temperature ?? null,
|
|
30
|
+
maxTurns: spec.maxTurns || null,
|
|
31
|
+
hidden: spec.hidden || false,
|
|
32
|
+
promptFile: spec.promptFile || spec.name,
|
|
33
|
+
_promptCache: spec._promptCache ?? null,
|
|
34
|
+
_customAgent: spec._customAgent || false,
|
|
35
|
+
_scope: spec._scope || null,
|
|
36
|
+
_source: spec._source || null
|
|
37
|
+
}
|
|
38
|
+
registry.set(agent.name, agent)
|
|
39
|
+
return agent
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export async function getAgentPrompt(name) {
|
|
43
|
+
const agent = registry.get(name)
|
|
44
|
+
if (!agent) return ""
|
|
45
|
+
if (agent._promptCache !== null) return agent._promptCache
|
|
46
|
+
agent._promptCache = await loadPrompt(agent.promptFile)
|
|
47
|
+
return agent._promptCache
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function getAgent(name) {
|
|
51
|
+
return registry.get(name) || null
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function listAgents({ includeHidden = false } = {}) {
|
|
55
|
+
const agents = [...registry.values()]
|
|
56
|
+
return includeHidden ? agents : agents.filter((a) => !a.hidden)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function resolveAgentForMode(mode) {
|
|
60
|
+
if (registry.has(mode)) return registry.get(mode)
|
|
61
|
+
const modeMap = { ask: "build", plan: "plan", agent: "build", longagent: "longagent" }
|
|
62
|
+
const mapped = modeMap[mode]
|
|
63
|
+
return mapped ? registry.get(mapped) || null : null
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
defineAgent({
|
|
67
|
+
name: "build",
|
|
68
|
+
description: "Default agent with full tool access for code development",
|
|
69
|
+
mode: "primary",
|
|
70
|
+
permission: "full",
|
|
71
|
+
tools: null
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
defineAgent({
|
|
75
|
+
name: "plan",
|
|
76
|
+
description: "Read-only analysis agent, no file editing allowed",
|
|
77
|
+
mode: "primary",
|
|
78
|
+
permission: "readonly",
|
|
79
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
defineAgent({
|
|
83
|
+
name: "explore",
|
|
84
|
+
description: "Fast file search subagent for codebase exploration",
|
|
85
|
+
mode: "subagent",
|
|
86
|
+
permission: "readonly",
|
|
87
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
defineAgent({
|
|
91
|
+
name: "longagent",
|
|
92
|
+
description: "Persistent iterative execution agent for complex multi-step tasks",
|
|
93
|
+
mode: "primary",
|
|
94
|
+
permission: "full",
|
|
95
|
+
tools: null
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
defineAgent({
|
|
99
|
+
name: "reviewer",
|
|
100
|
+
description: "Code review specialist for analyzing code quality, bugs, and security issues",
|
|
101
|
+
mode: "subagent",
|
|
102
|
+
permission: "readonly",
|
|
103
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
defineAgent({
|
|
107
|
+
name: "researcher",
|
|
108
|
+
description: "Deep codebase research and web-augmented exploration agent",
|
|
109
|
+
mode: "subagent",
|
|
110
|
+
permission: "readonly",
|
|
111
|
+
tools: ["read", "glob", "grep", "list", "bash", "websearch", "codesearch", "webfetch"]
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
defineAgent({
|
|
115
|
+
name: "architect",
|
|
116
|
+
description: "Feature architecture designer. Analyzes codebase patterns, designs implementation blueprints with specific files, component designs, data flows.",
|
|
117
|
+
mode: "subagent",
|
|
118
|
+
permission: "readonly",
|
|
119
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
defineAgent({
|
|
123
|
+
name: "guide",
|
|
124
|
+
description: "kkcode self-help guide. Answers questions about kkcode features, tools, configuration, modes, skills, hooks, MCP servers, and usage patterns by searching the kkcode source code.",
|
|
125
|
+
mode: "subagent",
|
|
126
|
+
permission: "readonly",
|
|
127
|
+
tools: ["read", "glob", "grep", "list", "webfetch", "websearch"]
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
defineAgent({
|
|
131
|
+
name: "security-reviewer",
|
|
132
|
+
description: "Security audit specialist. Performs OWASP Top 10 checks, hardcoded secret scans, dependency audits, and authentication/authorization reviews.",
|
|
133
|
+
mode: "subagent",
|
|
134
|
+
permission: "readonly",
|
|
135
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
defineAgent({
|
|
139
|
+
name: "tdd-guide",
|
|
140
|
+
description: "TDD specialist. Guides and executes test-driven development: scaffold interfaces, write failing tests (RED), implement minimum code (GREEN), refactor (IMPROVE). Targets 80%+ coverage.",
|
|
141
|
+
mode: "subagent",
|
|
142
|
+
permission: "full",
|
|
143
|
+
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
defineAgent({
|
|
147
|
+
name: "build-fixer",
|
|
148
|
+
description: "Build error diagnosis and repair. Analyzes build failures, identifies root causes, applies fixes, and verifies the build succeeds. Supports TypeScript, Python, Go, Rust, Java.",
|
|
149
|
+
mode: "subagent",
|
|
150
|
+
permission: "full",
|
|
151
|
+
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
defineAgent({
|
|
155
|
+
name: "frontend-designer",
|
|
156
|
+
description: "Frontend design specialist. Creates polished, distinctive UIs with strong aesthetics — typography, color, motion, layout. Avoids generic AI-style designs. Reads project design system (Tailwind, CSS vars, component libraries) and produces production-grade frontend code.",
|
|
157
|
+
mode: "subagent",
|
|
158
|
+
permission: "full",
|
|
159
|
+
tools: ["read", "write", "edit", "bash", "glob", "grep", "list"]
|
|
160
|
+
})
|
|
161
|
+
|
|
162
|
+
defineAgent({
|
|
163
|
+
name: "compaction",
|
|
164
|
+
description: "Conversation summarizer for context compression",
|
|
165
|
+
mode: "subagent",
|
|
166
|
+
permission: "none",
|
|
167
|
+
tools: [],
|
|
168
|
+
hidden: true
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
defineAgent({
|
|
172
|
+
name: "title",
|
|
173
|
+
description: "Session title generator",
|
|
174
|
+
mode: "subagent",
|
|
175
|
+
permission: "none",
|
|
176
|
+
tools: [],
|
|
177
|
+
hidden: true
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
// 4-Stage LongAgent agents
|
|
181
|
+
defineAgent({
|
|
182
|
+
name: "preview-agent",
|
|
183
|
+
description: "4-Stage LongAgent: Stage 1 - Previewing Agent. Explores codebase, extracts requirements, no editing allowed.",
|
|
184
|
+
mode: "subagent",
|
|
185
|
+
permission: "readonly",
|
|
186
|
+
tools: ["read", "glob", "grep", "list", "bash", "question", "todowrite"]
|
|
187
|
+
})
|
|
188
|
+
|
|
189
|
+
defineAgent({
|
|
190
|
+
name: "blueprint-agent",
|
|
191
|
+
description: "4-Stage LongAgent: Stage 2 - Blueprint Agent. Creates detailed implementation plan, function designs, architecture.",
|
|
192
|
+
mode: "subagent",
|
|
193
|
+
permission: "readonly",
|
|
194
|
+
tools: ["read", "glob", "grep", "list", "bash", "question", "todowrite"]
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
defineAgent({
|
|
198
|
+
name: "coding-agent",
|
|
199
|
+
description: "4-Stage LongAgent: Stage 3 - Coding Agent. Implements code strictly according to blueprint.",
|
|
200
|
+
mode: "subagent",
|
|
201
|
+
permission: "full",
|
|
202
|
+
tools: null
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
defineAgent({
|
|
206
|
+
name: "debugging-agent",
|
|
207
|
+
description: "4-Stage LongAgent: Stage 4 - Debugging Agent. Verifies implementation, runs tests, finds and fixes bugs.",
|
|
208
|
+
mode: "subagent",
|
|
209
|
+
permission: "full",
|
|
210
|
+
tools: null
|
|
211
|
+
})
|
|
212
|
+
|
|
213
|
+
defineAgent({
|
|
214
|
+
name: "bug-hunter",
|
|
215
|
+
description: "Deep bug detection specialist. Systematically hunts logic errors, boundary conditions, race conditions, resource leaks, error handling gaps, and state corruption. Reports only HIGH/MEDIUM confidence bugs with concrete trigger paths.",
|
|
216
|
+
mode: "subagent",
|
|
217
|
+
permission: "full",
|
|
218
|
+
maxTurns: 30,
|
|
219
|
+
tools: ["read", "glob", "grep", "list", "bash"]
|
|
220
|
+
})
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
You are a deep bug detection specialist. Your job is to systematically hunt for real, exploitable bugs in codebases — not style issues or theoretical concerns.
|
|
2
|
+
|
|
3
|
+
Available tools: Read, Glob, Grep, List, Bash
|
|
4
|
+
|
|
5
|
+
# Bug Categories (Priority Order)
|
|
6
|
+
|
|
7
|
+
## 1. Logic Errors
|
|
8
|
+
- Off-by-one errors in loops and array indexing
|
|
9
|
+
- Incorrect boolean logic (De Morgan violations, short-circuit misuse)
|
|
10
|
+
- Wrong comparison operators (== vs ===, < vs <=)
|
|
11
|
+
- Unreachable code paths, dead branches
|
|
12
|
+
- Variable shadowing that changes behavior
|
|
13
|
+
- Missing return statements in conditional branches
|
|
14
|
+
|
|
15
|
+
## 2. Boundary Conditions
|
|
16
|
+
- Empty arrays/objects/strings not handled
|
|
17
|
+
- null/undefined propagation without guards
|
|
18
|
+
- NaN comparisons (NaN !== NaN)
|
|
19
|
+
- Integer overflow / floating point precision
|
|
20
|
+
- Empty string vs null vs undefined confusion
|
|
21
|
+
- Array index out of bounds
|
|
22
|
+
|
|
23
|
+
## 3. Race Conditions & Concurrency
|
|
24
|
+
- Async state mutations without synchronization
|
|
25
|
+
- TOCTOU (time-of-check-time-of-use) patterns
|
|
26
|
+
- Promise chains with shared mutable state
|
|
27
|
+
- Event handler ordering assumptions
|
|
28
|
+
- Missing await on async calls
|
|
29
|
+
- Concurrent Map/Set modifications
|
|
30
|
+
|
|
31
|
+
## 4. Resource Leaks
|
|
32
|
+
- Unclosed file handles, streams, sockets
|
|
33
|
+
- setTimeout/setInterval without cleanup
|
|
34
|
+
- Event listeners added but never removed
|
|
35
|
+
- Database connections not released
|
|
36
|
+
- Child processes not terminated
|
|
37
|
+
- AbortController signals not wired
|
|
38
|
+
|
|
39
|
+
## 5. Error Handling Gaps
|
|
40
|
+
- Silent catch blocks that swallow errors
|
|
41
|
+
- Unhandled promise rejections
|
|
42
|
+
- try/catch that catches too broadly
|
|
43
|
+
- Error objects losing stack trace (re-throw without cause)
|
|
44
|
+
- finally blocks that override return values
|
|
45
|
+
- Missing error propagation in callbacks
|
|
46
|
+
|
|
47
|
+
## 6. State Corruption
|
|
48
|
+
- Shared mutable objects passed by reference
|
|
49
|
+
- Stale closures capturing outdated values
|
|
50
|
+
- Cache invalidation misses
|
|
51
|
+
- Partial updates leaving inconsistent state
|
|
52
|
+
- Constructor/init order dependencies
|
|
53
|
+
|
|
54
|
+
# Hunt Process
|
|
55
|
+
|
|
56
|
+
1. **Map attack surface**: Use `glob` to identify entry points, handlers, and critical paths
|
|
57
|
+
2. **Trace data flow**: Use `grep` to follow variables from input to output
|
|
58
|
+
3. **Read critical code**: Use `read` to examine complex functions, error handlers, and state management
|
|
59
|
+
4. **Verify assumptions**: Use `bash` to run tests, check types, or validate behavior
|
|
60
|
+
5. **Cross-reference**: Check if the same pattern appears elsewhere (copy-paste bugs)
|
|
61
|
+
|
|
62
|
+
# Confidence Scoring
|
|
63
|
+
|
|
64
|
+
For each bug found, assign confidence:
|
|
65
|
+
- **HIGH** (8-10): Clear bug with reproducible trigger path
|
|
66
|
+
- **MEDIUM** (5-7): Suspicious pattern, needs specific conditions to trigger
|
|
67
|
+
- **LOW** (1-4): Theoretical concern, unlikely in practice — do NOT report these
|
|
68
|
+
|
|
69
|
+
Only report HIGH and MEDIUM confidence bugs.
|
|
70
|
+
|
|
71
|
+
# Output Format
|
|
72
|
+
|
|
73
|
+
For each bug:
|
|
74
|
+
- **Confidence**: HIGH / MEDIUM (with score 1-10)
|
|
75
|
+
- **Category**: From the categories above
|
|
76
|
+
- **File**: file path and line number(s)
|
|
77
|
+
- **Bug**: Clear description of what's wrong
|
|
78
|
+
- **Trigger**: How to reproduce or what conditions cause it
|
|
79
|
+
- **Fix**: Concrete fix with code snippet
|
|
80
|
+
|
|
81
|
+
End with: total bugs by confidence, most critical fix to prioritize.
|
|
82
|
+
|
|
83
|
+
# Anti-Patterns to Avoid
|
|
84
|
+
|
|
85
|
+
- Do NOT report missing documentation or comments
|
|
86
|
+
- Do NOT report style/formatting issues
|
|
87
|
+
- Do NOT report "could be improved" suggestions
|
|
88
|
+
- Do NOT report theoretical vulnerabilities without trigger paths
|
|
89
|
+
- Do NOT flag intentional design decisions as bugs
|
|
90
|
+
- Focus on bugs that WILL cause incorrect behavior in production
|
package/src/repl.mjs
CHANGED
|
@@ -29,6 +29,7 @@ import { extractImageRefs, buildContentBlocks, readClipboardImage, readClipboard
|
|
|
29
29
|
import { generateSkill, saveSkillGlobal } from "./skill/generator.mjs"
|
|
30
30
|
import { userConfigCandidates, projectConfigCandidates, memoryFilePath } from "./storage/paths.mjs"
|
|
31
31
|
import { persistTrust, revokeTrust } from "./permission/workspace-trust.mjs"
|
|
32
|
+
import { confirmRollback, executeRollback } from "./session/rollback.mjs"
|
|
32
33
|
|
|
33
34
|
const HIST_DIR = join(homedir(), ".kkcode")
|
|
34
35
|
const HIST_FILE = join(HIST_DIR, "repl_history")
|
|
@@ -88,6 +89,7 @@ const BUILTIN_SLASH = [
|
|
|
88
89
|
{ name: "longagent", desc: "switch to longagent mode" },
|
|
89
90
|
{ name: "create-skill", desc: "generate a new skill via AI" },
|
|
90
91
|
{ name: "create-agent", desc: "generate a new sub-agent via AI" },
|
|
92
|
+
{ name: "undo", desc: "undo last code changes" },
|
|
91
93
|
{ name: "trust", desc: "trust this workspace" },
|
|
92
94
|
{ name: "untrust", desc: "revoke workspace trust" },
|
|
93
95
|
{ name: "exit", desc: "quit" }
|
|
@@ -747,7 +749,9 @@ async function processInputLine({
|
|
|
747
749
|
else {
|
|
748
750
|
for (const s of sessions) {
|
|
749
751
|
const age = ageLabel(Date.now() - s.updatedAt)
|
|
750
|
-
|
|
752
|
+
const title = s.title || `${s.mode}:${s.model || "?"}`
|
|
753
|
+
const titleClipped = title.length > 35 ? title.slice(0, 32) + "..." : title
|
|
754
|
+
print(` ${s.id.slice(0, 12)} ${padRight(titleClipped, 36)} ${padRight(s.mode, 9)} ${padRight(s.status || "-", 10)} ${age}`)
|
|
751
755
|
}
|
|
752
756
|
}
|
|
753
757
|
return { exit: false }
|
|
@@ -756,12 +760,42 @@ async function processInputLine({
|
|
|
756
760
|
if (normalized === "/resume" || normalized.startsWith("/resume ") || normalized === "/r" || normalized.startsWith("/r ")) {
|
|
757
761
|
const arg = normalized.replace(/^\/(resume|r)/, "").trim()
|
|
758
762
|
const sessions = await listSessions({ cwd: process.cwd(), limit: 20, includeChildren: false })
|
|
763
|
+
|
|
764
|
+
if (!sessions.length) {
|
|
765
|
+
print("no sessions found in current directory")
|
|
766
|
+
return { exit: false }
|
|
767
|
+
}
|
|
768
|
+
|
|
759
769
|
let target = null
|
|
760
|
-
|
|
761
|
-
|
|
770
|
+
|
|
771
|
+
if (!arg) {
|
|
772
|
+
// Show interactive numbered list
|
|
773
|
+
print(`\n Sessions in ${paint(process.cwd(), "cyan")}:\n`)
|
|
774
|
+
for (let i = 0; i < sessions.length; i++) {
|
|
775
|
+
const s = sessions[i]
|
|
776
|
+
const num = paint(` ${String(i + 1).padStart(2)}.`, "yellow")
|
|
777
|
+
const title = s.title || `${s.mode}:${s.model || "?"}`
|
|
778
|
+
const titleClipped = title.length > 45 ? title.slice(0, 42) + "..." : title
|
|
779
|
+
const age = ageLabel(Date.now() - s.updatedAt)
|
|
780
|
+
const mode = paint(padRight(s.mode, 9), "cyan")
|
|
781
|
+
const status = s.status === "active" ? paint("active", "green") : paint(s.status || "-", null, { dim: true })
|
|
782
|
+
print(`${num} ${padRight(titleClipped, 46)} ${mode} ${padRight(status, 14)} ${paint(age, null, { dim: true })}`)
|
|
783
|
+
}
|
|
784
|
+
print(`\n usage: ${paint("/resume <number>", "yellow")} or ${paint("/resume <session-id>", "yellow")}`)
|
|
785
|
+
return { exit: false }
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
// Try numeric index first (1-based)
|
|
789
|
+
const idx = parseInt(arg, 10)
|
|
790
|
+
if (!Number.isNaN(idx) && idx >= 1 && idx <= sessions.length) {
|
|
791
|
+
target = sessions[idx - 1]
|
|
792
|
+
} else {
|
|
793
|
+
// Fallback to ID prefix match
|
|
794
|
+
target = sessions.find((s) => s.id === arg || s.id.startsWith(arg)) || null
|
|
795
|
+
}
|
|
762
796
|
|
|
763
797
|
if (!target) {
|
|
764
|
-
print(
|
|
798
|
+
print(`no session matching "${arg}"`)
|
|
765
799
|
return { exit: false }
|
|
766
800
|
}
|
|
767
801
|
|
|
@@ -769,15 +803,33 @@ async function processInputLine({
|
|
|
769
803
|
state.mode = target.mode || state.mode
|
|
770
804
|
state.providerType = target.providerType || state.providerType
|
|
771
805
|
state.model = target.model || state.model
|
|
772
|
-
|
|
806
|
+
const title = target.title || `${target.mode}:${target.model || "?"}`
|
|
807
|
+
print(`resumed: ${paint(title, "cyan")} (${target.mode}, ${target.model || "?"})`)
|
|
773
808
|
const msgs = await getConversationHistory(target.id, 3)
|
|
774
809
|
for (const m of msgs) {
|
|
775
|
-
const
|
|
810
|
+
const text = typeof m.content === "string" ? m.content : JSON.stringify(m.content)
|
|
811
|
+
const preview = text.length > 84 ? `${text.slice(0, 84)}...` : text
|
|
776
812
|
print(` [${m.role}] ${preview}`)
|
|
777
813
|
}
|
|
778
814
|
return { exit: false }
|
|
779
815
|
}
|
|
780
816
|
|
|
817
|
+
if (normalized === "/undo") {
|
|
818
|
+
const language = ctx.configState.config.language || "en"
|
|
819
|
+
const cwd = process.cwd()
|
|
820
|
+
const confirmation = await confirmRollback({ cwd, language })
|
|
821
|
+
print(confirmation.message)
|
|
822
|
+
if (!confirmation.confirmed) return { exit: false }
|
|
823
|
+
const result = await executeRollback({
|
|
824
|
+
cwd,
|
|
825
|
+
commitHash: confirmation.commitHash,
|
|
826
|
+
sessionId: state.sessionId,
|
|
827
|
+
language
|
|
828
|
+
})
|
|
829
|
+
print(result.message)
|
|
830
|
+
return { exit: false }
|
|
831
|
+
}
|
|
832
|
+
|
|
781
833
|
if (["/ask", "/plan", "/agent", "/longagent"].includes(normalized)) {
|
|
782
834
|
state.mode = resolveMode(normalized.slice(1))
|
|
783
835
|
print(`mode switched: ${state.mode}`)
|