@kkelly-offical/kkcode 0.1.7 → 0.2.3-preview.1
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 -674
- package/README.md +474 -387
- package/package.json +50 -46
- package/src/agent/agent.mjs +228 -220
- package/src/agent/custom-agent-loader.mjs +6 -3
- package/src/agent/generator.mjs +2 -2
- package/src/agent/prompt/assistant.txt +12 -0
- package/src/agent/prompt/bug-hunter.txt +89 -89
- package/src/agent/prompt/frontend-designer.txt +58 -58
- package/src/agent/prompt/guide.txt +1 -1
- package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
- package/src/agent/prompt/longagent-coding-agent.txt +37 -37
- package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
- package/src/agent/prompt/longagent-preview-agent.txt +63 -63
- package/src/command/custom-commands.mjs +2 -2
- package/src/commands/agent.mjs +1 -1
- package/src/commands/background.mjs +145 -4
- package/src/commands/chat.mjs +117 -76
- package/src/commands/config.mjs +148 -1
- package/src/commands/doctor.mjs +30 -6
- package/src/commands/init.mjs +32 -6
- package/src/commands/longagent.mjs +117 -0
- package/src/commands/mcp.mjs +275 -43
- package/src/commands/permission.mjs +1 -1
- package/src/commands/session.mjs +195 -140
- package/src/commands/skill.mjs +63 -0
- package/src/commands/theme.mjs +1 -1
- package/src/commands/update.mjs +32 -0
- package/src/config/defaults.mjs +289 -260
- package/src/config/import-config.mjs +1 -1
- package/src/config/load-config.mjs +61 -4
- package/src/config/schema.mjs +604 -574
- package/src/context.mjs +4 -1
- package/src/core/constants.mjs +97 -91
- package/src/core/types.mjs +1 -1
- package/src/github/api.mjs +78 -78
- package/src/github/auth.mjs +294 -286
- package/src/github/flow.mjs +298 -298
- package/src/github/workspace.mjs +225 -212
- package/src/index.mjs +87 -82
- package/src/knowledge/frontend-aesthetics.txt +38 -38
- package/src/mcp/client-http.mjs +139 -141
- package/src/mcp/client-sse.mjs +297 -288
- package/src/mcp/client-stdio.mjs +534 -533
- package/src/mcp/constants.mjs +4 -2
- package/src/mcp/registry.mjs +498 -479
- package/src/mcp/stdio-framing.mjs +135 -133
- package/src/mcp/tool-result.mjs +24 -24
- package/src/observability/edit-diagnostics.mjs +449 -0
- package/src/observability/index.mjs +42 -42
- package/src/observability/metrics.mjs +165 -137
- package/src/observability/tracer.mjs +137 -137
- package/src/onboarding.mjs +209 -0
- package/src/orchestration/background-manager.mjs +567 -372
- package/src/orchestration/background-worker.mjs +419 -305
- package/src/orchestration/interruption-reason.mjs +21 -0
- package/src/orchestration/longagent-manager.mjs +197 -171
- package/src/orchestration/stage-scheduler.mjs +733 -728
- package/src/orchestration/subagent-router.mjs +7 -1
- package/src/orchestration/task-scheduler.mjs +219 -7
- package/src/permission/engine.mjs +1 -1
- package/src/permission/exec-policy.mjs +370 -370
- package/src/permission/file-edit-policy.mjs +108 -0
- package/src/permission/prompt.mjs +1 -1
- package/src/permission/rules.mjs +116 -7
- package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
- package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
- package/src/plugin/hook-bus.mjs +19 -5
- package/src/plugin/manifest-loader.mjs +222 -0
- package/src/provider/anthropic.mjs +396 -390
- package/src/provider/ollama.mjs +7 -1
- package/src/provider/openai.mjs +382 -340
- package/src/provider/retry-policy.mjs +74 -68
- package/src/provider/router.mjs +242 -241
- package/src/provider/sse.mjs +104 -104
- package/src/provider/wizard.mjs +556 -0
- package/src/repl/capability-facade.mjs +30 -0
- package/src/repl/command-surface.mjs +23 -0
- package/src/repl/controller-entry.mjs +40 -0
- package/src/repl/core-shell.mjs +208 -0
- package/src/repl/dialog-router.mjs +87 -0
- package/src/repl/input-engine.mjs +76 -0
- package/src/repl/keymap.mjs +7 -0
- package/src/repl/operator-surface.mjs +15 -0
- package/src/repl/permission-flow.mjs +49 -0
- package/src/repl/runtime-facade.mjs +36 -0
- package/src/repl/slash-router.mjs +62 -0
- package/src/repl/state-store.mjs +29 -0
- package/src/repl/turn-controller.mjs +58 -0
- package/src/repl/verification.mjs +23 -0
- package/src/repl.mjs +3371 -2981
- package/src/rules/load-rules.mjs +3 -3
- package/src/runtime.mjs +1 -1
- package/src/session/agent-transaction.mjs +86 -0
- package/src/session/checkpoint.mjs +302 -302
- package/src/session/compaction.mjs +298 -298
- package/src/session/engine.mjs +417 -232
- package/src/session/longagent-4stage.mjs +467 -460
- package/src/session/longagent-hybrid.mjs +1344 -1097
- package/src/session/longagent-plan.mjs +376 -365
- package/src/session/longagent-project-memory.mjs +53 -53
- package/src/session/longagent-scaffold.mjs +291 -291
- package/src/session/longagent-task-bus.mjs +138 -54
- package/src/session/longagent-utils.mjs +828 -472
- package/src/session/longagent.mjs +911 -900
- package/src/session/loop.mjs +1005 -930
- package/src/session/prompt/agent.txt +25 -25
- package/src/session/prompt/anthropic.txt +150 -150
- package/src/session/prompt/beast.txt +1 -1
- package/src/session/prompt/plan.txt +31 -31
- package/src/session/prompt/qwen.txt +46 -46
- package/src/session/recovery.mjs +21 -0
- package/src/session/rollback.mjs +196 -195
- package/src/session/routing-observability.mjs +72 -0
- package/src/session/runtime-state.mjs +47 -0
- package/src/session/store.mjs +523 -519
- package/src/session/system-prompt.mjs +308 -273
- package/src/session/task-validator.mjs +267 -267
- package/src/session/usability-gates.mjs +2 -2
- package/src/skill/builtin/commit.mjs +64 -64
- package/src/skill/builtin/design.mjs +76 -76
- package/src/skill/generator.mjs +18 -2
- package/src/skill/registry.mjs +642 -390
- package/src/storage/audit-store.mjs +18 -11
- package/src/storage/event-log.mjs +7 -1
- package/src/storage/ghost-commit-store.mjs +243 -245
- package/src/storage/paths.mjs +17 -0
- package/src/theme/default-theme.mjs +1 -1
- package/src/theme/markdown.mjs +4 -0
- package/src/theme/schema.mjs +1 -1
- package/src/theme/status-bar.mjs +162 -158
- package/src/tool/audit-wrapper.mjs +18 -2
- package/src/tool/edit-transaction.mjs +23 -0
- package/src/tool/executor.mjs +26 -1
- package/src/tool/file-read-state.mjs +65 -0
- package/src/tool/git-auto.mjs +526 -526
- package/src/tool/git-full-auto.mjs +487 -478
- package/src/tool/mutation-guard.mjs +54 -0
- package/src/tool/prompt/edit.txt +3 -3
- package/src/tool/prompt/multiedit.txt +1 -0
- package/src/tool/prompt/notebookedit.txt +2 -1
- package/src/tool/prompt/patch.txt +25 -24
- package/src/tool/prompt/read.txt +3 -3
- package/src/tool/prompt/sysinfo.txt +29 -0
- package/src/tool/prompt/task.txt +66 -4
- package/src/tool/prompt/write.txt +2 -2
- package/src/tool/question-prompt.mjs +99 -93
- package/src/tool/registry.mjs +1701 -1343
- package/src/tool/task-tool.mjs +14 -6
- package/src/ui/activity-renderer.mjs +667 -664
- package/src/ui/repl-background-panel.mjs +7 -0
- package/src/ui/repl-capability-panel.mjs +9 -0
- package/src/ui/repl-dashboard.mjs +54 -4
- package/src/ui/repl-help.mjs +110 -0
- package/src/ui/repl-operator-panel.mjs +12 -0
- package/src/ui/repl-route-feedback.mjs +35 -0
- package/src/ui/repl-status-view.mjs +76 -0
- package/src/ui/repl-task-panel.mjs +5 -0
- package/src/ui/repl-transcript-panel.mjs +56 -0
- package/src/ui/repl-turn-summary.mjs +135 -0
- package/src/update/checker.mjs +184 -0
- package/src/usage/pricing.mjs +122 -121
- package/src/usage/usage-meter.mjs +1 -0
- package/src/util/git.mjs +562 -519
- package/src/util/template.mjs +6 -1
- package/src/version.mjs +3 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises"
|
|
2
|
+
import { stdin as input, stdout as output } from "node:process"
|
|
3
|
+
import { writeFile, readFile, mkdir } from "node:fs/promises"
|
|
4
|
+
import { dirname } from "node:path"
|
|
5
|
+
import YAML from "yaml"
|
|
6
|
+
import { paint } from "./theme/color.mjs"
|
|
7
|
+
import { profilePath } from "./storage/paths.mjs"
|
|
8
|
+
|
|
9
|
+
function ln(text = "", color, opts) {
|
|
10
|
+
console.log(color ? paint(text, color, opts) : text)
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function termWidth() {
|
|
14
|
+
return Math.max(60, Math.min(process.stdout.columns || 100, 120))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function hr(char = "─", color = "#444") {
|
|
18
|
+
ln(paint(char.repeat(termWidth()), color))
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function header() {
|
|
22
|
+
ln()
|
|
23
|
+
ln(paint(" ██╗ ██╗██╗ ██╗ ██████╗ ██████╗ ██████╗ ███████╗", "#4af5f0", { bold: true }))
|
|
24
|
+
ln(paint(" ██║ ██╔╝██║ ██╔╝██╔════╝██╔═══██╗██╔══██╗██╔════╝", "#38c8ff", { bold: true }))
|
|
25
|
+
ln(paint(" █████╔╝ █████╔╝ ██║ ██║ ██║██║ ██║█████╗ ", "#58a0ff", { bold: true }))
|
|
26
|
+
ln(paint(" ██╔═██╗ ██╔═██╗ ██║ ██║ ██║██║ ██║██╔══╝ ", "#8876ff", { bold: true }))
|
|
27
|
+
ln(paint(" ██║ ██╗██║ ██╗╚██████╗╚██████╔╝██████╔╝███████╗", "#d037ff", { bold: true }))
|
|
28
|
+
ln(paint(" ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝", "#e828f0", { bold: true }))
|
|
29
|
+
ln()
|
|
30
|
+
ln(paint(" Welcome to kkcode — AI Coding Agent", "#ffffff", { bold: true }))
|
|
31
|
+
ln(paint(" Let's set up your profile so kkcode knows how to work with you.", "#aaaaaa"))
|
|
32
|
+
ln()
|
|
33
|
+
hr()
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Single-choice menu: returns selected index (0-based)
|
|
37
|
+
async function menu(rl, prompt, choices) {
|
|
38
|
+
ln()
|
|
39
|
+
ln(paint(` ${prompt}`, "#ffffff", { bold: true }))
|
|
40
|
+
for (let i = 0; i < choices.length; i++) {
|
|
41
|
+
ln(paint(` ${i + 1}) `, "#888") + paint(choices[i], "#dddddd"))
|
|
42
|
+
}
|
|
43
|
+
ln()
|
|
44
|
+
while (true) {
|
|
45
|
+
const raw = await rl.question(paint(" Enter number: ", "#4af5f0"))
|
|
46
|
+
const n = parseInt(raw.trim(), 10)
|
|
47
|
+
if (n >= 1 && n <= choices.length) return n - 1
|
|
48
|
+
ln(paint(" Please enter a valid number.", "#ff6b6b"))
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Multi-choice menu: returns array of selected indices
|
|
53
|
+
async function multiMenu(rl, prompt, choices, hint = "comma-separated, e.g. 1,3") {
|
|
54
|
+
ln()
|
|
55
|
+
ln(paint(` ${prompt}`, "#ffffff", { bold: true }))
|
|
56
|
+
for (let i = 0; i < choices.length; i++) {
|
|
57
|
+
ln(paint(` ${i + 1}) `, "#888") + paint(choices[i], "#dddddd"))
|
|
58
|
+
}
|
|
59
|
+
ln(paint(` (${hint}, or press Enter to skip)`, "#888"))
|
|
60
|
+
ln()
|
|
61
|
+
const raw = await rl.question(paint(" Your choice: ", "#4af5f0"))
|
|
62
|
+
if (!raw.trim()) return []
|
|
63
|
+
return raw.split(",")
|
|
64
|
+
.map((s) => parseInt(s.trim(), 10) - 1)
|
|
65
|
+
.filter((n) => n >= 0 && n < choices.length)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Free-text input
|
|
69
|
+
async function ask(rl, prompt, placeholder = "") {
|
|
70
|
+
ln()
|
|
71
|
+
if (placeholder) ln(paint(` e.g. ${placeholder}`, "#666"))
|
|
72
|
+
const raw = await rl.question(paint(` ${prompt}: `, "#4af5f0"))
|
|
73
|
+
return raw.trim()
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ─── Section renderers ────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
function sectionTitle(title) {
|
|
79
|
+
ln()
|
|
80
|
+
hr("─", "#333")
|
|
81
|
+
ln(paint(` ${title}`, "#2ac26f", { bold: true }))
|
|
82
|
+
hr("─", "#333")
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// ─── Default profile ──────────────────────────────────────────────────────────
|
|
86
|
+
|
|
87
|
+
export function defaultProfile() {
|
|
88
|
+
return {
|
|
89
|
+
beginner: true,
|
|
90
|
+
tech_stack: [],
|
|
91
|
+
languages: [],
|
|
92
|
+
design_style: "clean and minimal",
|
|
93
|
+
extra_notes: "",
|
|
94
|
+
created_at: new Date().toISOString()
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ─── Save / load ──────────────────────────────────────────────────────────────
|
|
99
|
+
|
|
100
|
+
export async function saveProfile(profile) {
|
|
101
|
+
const p = profilePath()
|
|
102
|
+
await mkdir(dirname(p), { recursive: true })
|
|
103
|
+
await writeFile(p, YAML.stringify(profile), "utf8")
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export async function loadProfile() {
|
|
107
|
+
try {
|
|
108
|
+
const raw = await readFile(profilePath(), "utf8")
|
|
109
|
+
return YAML.parse(raw) || null
|
|
110
|
+
} catch {
|
|
111
|
+
return null
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function isFirstRun() {
|
|
116
|
+
// Resolved lazily — call loadProfile() to check
|
|
117
|
+
return loadProfile().then((p) => p === null)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ─── Main onboarding flow ─────────────────────────────────────────────────────
|
|
121
|
+
|
|
122
|
+
export async function runOnboarding() {
|
|
123
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
124
|
+
// Non-interactive: write default profile silently
|
|
125
|
+
await saveProfile(defaultProfile())
|
|
126
|
+
return defaultProfile()
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const rl = createInterface({ input, output, terminal: true })
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
header()
|
|
133
|
+
|
|
134
|
+
ln(paint(" Quick start options:", "#ffffff", { bold: true }))
|
|
135
|
+
ln()
|
|
136
|
+
ln(paint(" 1) ", "#888") + paint("I'm new — use kkcode defaults (recommended for beginners)", "#dddddd"))
|
|
137
|
+
ln(paint(" 2) ", "#888") + paint("Set up my profile now", "#dddddd"))
|
|
138
|
+
ln()
|
|
139
|
+
|
|
140
|
+
const modeRaw = await rl.question(paint(" Enter number [1]: ", "#4af5f0"))
|
|
141
|
+
const mode = modeRaw.trim() === "2" ? "custom" : "default"
|
|
142
|
+
|
|
143
|
+
if (mode === "default") {
|
|
144
|
+
const profile = defaultProfile()
|
|
145
|
+
await saveProfile(profile)
|
|
146
|
+
ln()
|
|
147
|
+
ln(paint(" ✓ Default profile saved. You can update it anytime with /profile.", "#2ac26f", { bold: true }))
|
|
148
|
+
ln()
|
|
149
|
+
return profile
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── Custom setup ──────────────────────────────────────────────────────────
|
|
153
|
+
const profile = { beginner: false, created_at: new Date().toISOString() }
|
|
154
|
+
|
|
155
|
+
// 1. Programming languages
|
|
156
|
+
sectionTitle("1 / 4 Programming Languages")
|
|
157
|
+
const langChoices = ["JavaScript / TypeScript", "Python", "Rust", "Go", "Java / Kotlin", "C / C++", "Ruby", "PHP", "Swift", "Other"]
|
|
158
|
+
const langIdxs = await multiMenu(rl, "Which languages do you mainly use?", langChoices)
|
|
159
|
+
profile.languages = langIdxs.map((i) => langChoices[i])
|
|
160
|
+
if (langIdxs.includes(langChoices.length - 1) || profile.languages.length === 0) {
|
|
161
|
+
const extra = await ask(rl, "Specify languages (optional)", "Elixir, Dart, ...")
|
|
162
|
+
if (extra) profile.languages = [...profile.languages.filter((l) => l !== "Other"), extra]
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 2. Tech stack / frameworks
|
|
166
|
+
sectionTitle("2 / 4 Tech Stack & Frameworks")
|
|
167
|
+
const stackChoices = ["React", "Vue", "Next.js", "Node.js / Express", "FastAPI / Django", "Spring Boot", "Docker / Kubernetes", "AWS / GCP / Azure", "PostgreSQL / MySQL", "MongoDB", "Other"]
|
|
168
|
+
const stackIdxs = await multiMenu(rl, "Which frameworks / tools do you use?", stackChoices)
|
|
169
|
+
profile.tech_stack = stackIdxs.map((i) => stackChoices[i])
|
|
170
|
+
if (stackIdxs.includes(stackChoices.length - 1) || profile.tech_stack.length === 0) {
|
|
171
|
+
const extra = await ask(rl, "Specify stack (optional)", "Svelte, Prisma, Redis, ...")
|
|
172
|
+
if (extra) profile.tech_stack = [...profile.tech_stack.filter((s) => s !== "Other"), extra]
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// 3. Design / code style
|
|
176
|
+
sectionTitle("3 / 4 Design & Code Style")
|
|
177
|
+
const styleChoices = [
|
|
178
|
+
"Clean and minimal — less is more",
|
|
179
|
+
"Functional — prefer pure functions, immutability",
|
|
180
|
+
"Object-oriented — classes and patterns",
|
|
181
|
+
"Performance-first — optimize aggressively",
|
|
182
|
+
"Pragmatic — whatever works best for the task"
|
|
183
|
+
]
|
|
184
|
+
const styleIdx = await menu(rl, "What's your preferred coding style?", styleChoices)
|
|
185
|
+
profile.design_style = styleChoices[styleIdx]
|
|
186
|
+
|
|
187
|
+
// 4. Extra notes
|
|
188
|
+
sectionTitle("4 / 4 Anything Else?")
|
|
189
|
+
ln(paint(" Tell kkcode anything else it should remember about you.", "#aaaaaa"))
|
|
190
|
+
ln(paint(" e.g. \"Always write tests\", \"I prefer concise code\", \"Use Chinese for comments\"", "#666"))
|
|
191
|
+
const notes = await ask(rl, "Extra notes (optional, press Enter to skip)")
|
|
192
|
+
profile.extra_notes = notes
|
|
193
|
+
|
|
194
|
+
// ── Save ──────────────────────────────────────────────────────────────────
|
|
195
|
+
await saveProfile(profile)
|
|
196
|
+
|
|
197
|
+
ln()
|
|
198
|
+
hr()
|
|
199
|
+
ln()
|
|
200
|
+
ln(paint(" ✓ Profile saved!", "#2ac26f", { bold: true }))
|
|
201
|
+
ln(paint(" kkcode will use this context in every conversation.", "#aaaaaa"))
|
|
202
|
+
ln(paint(" You can update it anytime with /profile.", "#aaaaaa"))
|
|
203
|
+
ln()
|
|
204
|
+
|
|
205
|
+
return profile
|
|
206
|
+
} finally {
|
|
207
|
+
rl.close()
|
|
208
|
+
}
|
|
209
|
+
}
|