@kkelly-offical/kkcode 0.1.6 → 0.2.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 +452 -387
- package/package.json +50 -46
- package/src/agent/agent.mjs +19 -2
- 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 +90 -0
- 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/config/defaults.mjs +280 -260
- package/src/config/import-config.mjs +1 -1
- package/src/config/load-config.mjs +61 -4
- package/src/config/schema.mjs +591 -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 +84 -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 +2 -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 +3368 -2929
- 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 +36 -14
- package/src/session/engine.mjs +417 -227
- package/src/session/longagent-4stage.mjs +467 -460
- package/src/session/longagent-hybrid.mjs +1344 -1081
- 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 -884
- package/src/session/loop.mjs +1005 -905
- package/src/session/prompt/agent.txt +25 -0
- package/src/session/prompt/anthropic.txt +150 -150
- package/src/session/prompt/beast.txt +1 -1
- package/src/session/prompt/plan.txt +28 -6
- package/src/session/prompt/qwen.txt +46 -46
- package/src/session/recovery.mjs +21 -0
- package/src/session/rollback.mjs +197 -0
- package/src/session/routing-observability.mjs +72 -0
- package/src/session/runtime-state.mjs +47 -0
- package/src/session/store.mjs +523 -510
- package/src/session/system-prompt.mjs +56 -8
- 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 +13 -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 +17 -4
- 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/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/commands/session.mjs
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import path from "node:path"
|
|
2
|
-
import { writeFile } from "node:fs/promises"
|
|
3
|
-
import { Command } from "commander"
|
|
1
|
+
import path from "node:path"
|
|
2
|
+
import { writeFile } from "node:fs/promises"
|
|
3
|
+
import { Command } from "commander"
|
|
4
4
|
import { exportSession, getSession, listSessions, forkSession, fsckSessionStore, gcSessionStore, flushNow } from "../session/store.mjs"
|
|
5
5
|
import { newSessionId, executeTurn } from "../session/engine.mjs"
|
|
6
|
-
import { listRecoverableSessions, getResumeContext, isRecoveryEnabled } from "../session/recovery.mjs"
|
|
6
|
+
import { listRecoverableSessions, getResumeContext, isRecoveryEnabled, summarizeResumeContext } from "../session/recovery.mjs"
|
|
7
|
+
import { summarizeSessionRuntimeState } from "../session/runtime-state.mjs"
|
|
7
8
|
import { buildContext } from "../context.mjs"
|
|
8
9
|
import { ToolRegistry } from "../tool/registry.mjs"
|
|
9
10
|
|
|
@@ -15,8 +16,8 @@ function assertRecoveryEnabled(config, commandName) {
|
|
|
15
16
|
}
|
|
16
17
|
|
|
17
18
|
export function createSessionCommand() {
|
|
18
|
-
const cmd = new Command("session").description("manage persisted kkcode sessions")
|
|
19
|
-
|
|
19
|
+
const cmd = new Command("session").description("manage persisted kkcode sessions")
|
|
20
|
+
|
|
20
21
|
cmd
|
|
21
22
|
.command("fsck")
|
|
22
23
|
.description("check session index/data consistency")
|
|
@@ -62,86 +63,131 @@ export function createSessionCommand() {
|
|
|
62
63
|
|
|
63
64
|
cmd
|
|
64
65
|
.command("list")
|
|
65
|
-
.description("list sessions")
|
|
66
|
-
.option("--cwd-only", "filter by cwd", false)
|
|
67
|
-
.option("--roots", "only root sessions", false)
|
|
68
|
-
.option("--limit <n>", "max sessions", "30")
|
|
69
|
-
.action(async (options) => {
|
|
70
|
-
const list = await listSessions({
|
|
71
|
-
cwd: options.cwdOnly ? process.cwd() : null,
|
|
72
|
-
includeChildren: !options.roots,
|
|
73
|
-
limit: Number(options.limit || 30)
|
|
74
|
-
})
|
|
75
|
-
if (!list.length) {
|
|
76
|
-
console.log("no sessions found")
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
for (const session of list) {
|
|
80
|
-
const parent = session.parentSessionId ? ` parent=${session.parentSessionId}` : ""
|
|
81
|
-
console.log(
|
|
82
|
-
`${session.id} ${session.mode} ${session.providerType} ${session.model} ${new Date(session.updatedAt).toLocaleString()}${parent}`
|
|
83
|
-
)
|
|
84
|
-
}
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
cmd
|
|
88
|
-
.command("
|
|
89
|
-
.description("show
|
|
90
|
-
.
|
|
91
|
-
.
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
.
|
|
124
|
-
.
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
66
|
+
.description("list sessions")
|
|
67
|
+
.option("--cwd-only", "filter by cwd", false)
|
|
68
|
+
.option("--roots", "only root sessions", false)
|
|
69
|
+
.option("--limit <n>", "max sessions", "30")
|
|
70
|
+
.action(async (options) => {
|
|
71
|
+
const list = await listSessions({
|
|
72
|
+
cwd: options.cwdOnly ? process.cwd() : null,
|
|
73
|
+
includeChildren: !options.roots,
|
|
74
|
+
limit: Number(options.limit || 30)
|
|
75
|
+
})
|
|
76
|
+
if (!list.length) {
|
|
77
|
+
console.log("no sessions found")
|
|
78
|
+
return
|
|
79
|
+
}
|
|
80
|
+
for (const session of list) {
|
|
81
|
+
const parent = session.parentSessionId ? ` parent=${session.parentSessionId}` : ""
|
|
82
|
+
console.log(
|
|
83
|
+
`${session.id} ${session.mode} ${session.providerType} ${session.model} ${new Date(session.updatedAt).toLocaleString()}${parent}`
|
|
84
|
+
)
|
|
85
|
+
}
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
cmd
|
|
89
|
+
.command("status")
|
|
90
|
+
.description("show a unified runtime summary for the latest or selected session")
|
|
91
|
+
.option("--id <id>", "session id")
|
|
92
|
+
.option("--json", "print as json", false)
|
|
93
|
+
.action(async (options) => {
|
|
94
|
+
const ctx = await buildContext()
|
|
95
|
+
const summary = await summarizeSessionRuntimeState({
|
|
96
|
+
sessionId: options.id || null,
|
|
97
|
+
cwd: process.cwd(),
|
|
98
|
+
recoveryEnabled: isRecoveryEnabled(ctx.configState.config)
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
if (options.json) {
|
|
102
|
+
console.log(JSON.stringify(summary, null, 2))
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
if (!summary.session) {
|
|
106
|
+
console.log("no session state available")
|
|
107
|
+
return
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log(`session=${summary.session.id} mode=${summary.session.mode} provider=${summary.session.providerType} model=${summary.session.model}`)
|
|
111
|
+
console.log(`status=${summary.session.status} messages=${summary.messageCount} parts=${summary.partCount}`)
|
|
112
|
+
if (summary.retryMeta) {
|
|
113
|
+
console.log(`retry=inProgress:${Boolean(summary.retryMeta.inProgress)} step=${summary.retryMeta.step ?? "-"}`)
|
|
114
|
+
}
|
|
115
|
+
if (summary.budgetState) {
|
|
116
|
+
console.log(`budget=exceeded:${Boolean(summary.budgetState.exceeded)} warnings=${(summary.budgetState.warnings || []).length}`)
|
|
117
|
+
}
|
|
118
|
+
console.log(`recoverable=${summary.recoverableCount}`)
|
|
119
|
+
console.log(`background total=${summary.background.total} running=${summary.background.running} pending=${summary.background.pending} interrupted=${summary.background.interrupted} error=${summary.background.error}`)
|
|
120
|
+
console.log(`audit total=${summary.audit.total} error1h=${summary.audit.error1h} error24h=${summary.audit.error24h}`)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
cmd
|
|
124
|
+
.command("show")
|
|
125
|
+
.description("show one session")
|
|
126
|
+
.requiredOption("--id <id>", "session id")
|
|
127
|
+
.option("--summary", "show a concise session/resume summary")
|
|
128
|
+
.action(async (options) => {
|
|
129
|
+
const data = await getSession(options.id)
|
|
130
|
+
if (!data) {
|
|
131
|
+
console.error(`session not found: ${options.id}`)
|
|
132
|
+
process.exitCode = 1
|
|
133
|
+
return
|
|
134
|
+
}
|
|
135
|
+
if (options.summary) {
|
|
136
|
+
const resumeCtx = await getResumeContext(options.id)
|
|
137
|
+
const summary = summarizeResumeContext(resumeCtx)
|
|
138
|
+
console.log(JSON.stringify({
|
|
139
|
+
session: data.session,
|
|
140
|
+
resume: summary
|
|
141
|
+
}, null, 2))
|
|
142
|
+
return
|
|
143
|
+
}
|
|
144
|
+
console.log(JSON.stringify(data, null, 2))
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
cmd
|
|
148
|
+
.command("export")
|
|
149
|
+
.description("export session to json")
|
|
150
|
+
.requiredOption("--id <id>", "session id")
|
|
151
|
+
.option("--out <file>", "output file")
|
|
152
|
+
.action(async (options) => {
|
|
153
|
+
const data = await exportSession(options.id)
|
|
154
|
+
if (!data) {
|
|
155
|
+
console.error(`session not found: ${options.id}`)
|
|
156
|
+
process.exitCode = 1
|
|
157
|
+
return
|
|
158
|
+
}
|
|
159
|
+
const out = options.out ? path.resolve(options.out) : path.resolve(`session-${options.id}.json`)
|
|
160
|
+
await writeFile(out, JSON.stringify(data, null, 2) + "\n", "utf8")
|
|
161
|
+
console.log(`exported: ${out}`)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
cmd
|
|
165
|
+
.command("fork")
|
|
166
|
+
.description("fork session into a new child session")
|
|
167
|
+
.requiredOption("--id <id>", "source session id")
|
|
168
|
+
.option("--new-id <id>", "new session id")
|
|
169
|
+
.option("--title <title>", "child title")
|
|
170
|
+
.action(async (options) => {
|
|
171
|
+
const newId = options.newId || newSessionId()
|
|
172
|
+
const out = await forkSession({
|
|
173
|
+
sessionId: options.id,
|
|
174
|
+
newSessionId: newId,
|
|
175
|
+
title: options.title || null
|
|
176
|
+
})
|
|
177
|
+
if (!out) {
|
|
178
|
+
console.error(`session not found: ${options.id}`)
|
|
179
|
+
process.exitCode = 1
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
console.log(`forked: ${newId} <- ${options.id}`)
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
cmd
|
|
186
|
+
.command("resume")
|
|
187
|
+
.description("resume a session from the last user message")
|
|
188
|
+
.requiredOption("--id <id>", "session id to resume")
|
|
189
|
+
.option("--mode <mode>", "override mode")
|
|
190
|
+
.option("--model <model>", "override model")
|
|
145
191
|
.action(async (options) => {
|
|
146
192
|
const ctx = await buildContext()
|
|
147
193
|
if (!assertRecoveryEnabled(ctx.configState.config, "session resume")) return
|
|
@@ -152,31 +198,31 @@ export function createSessionCommand() {
|
|
|
152
198
|
process.exitCode = 1
|
|
153
199
|
return
|
|
154
200
|
}
|
|
155
|
-
if (!resumeCtx.canResume) {
|
|
156
|
-
console.error(`no user message found in session ${options.id}`)
|
|
157
|
-
process.exitCode = 1
|
|
158
|
-
return
|
|
159
|
-
}
|
|
201
|
+
if (!resumeCtx.canResume) {
|
|
202
|
+
console.error(`no user message found in session ${options.id}`)
|
|
203
|
+
process.exitCode = 1
|
|
204
|
+
return
|
|
205
|
+
}
|
|
160
206
|
await ToolRegistry.initialize({ config: ctx.configState.config, cwd: process.cwd() })
|
|
161
207
|
const mode = options.mode || resumeCtx.session.mode
|
|
162
208
|
const model = options.model || resumeCtx.session.model
|
|
163
|
-
console.log(`resuming session ${options.id} (${resumeCtx.messageCount} messages)`)
|
|
164
|
-
console.log(`last prompt: ${resumeCtx.lastPrompt.slice(0, 100)}${resumeCtx.lastPrompt.length > 100 ? "..." : ""}`)
|
|
165
|
-
const result = await executeTurn({
|
|
166
|
-
prompt: resumeCtx.lastPrompt,
|
|
167
|
-
mode,
|
|
168
|
-
model,
|
|
169
|
-
sessionId: options.id,
|
|
170
|
-
configState: ctx.configState,
|
|
171
|
-
providerType: resumeCtx.session.providerType
|
|
172
|
-
})
|
|
173
|
-
console.log(result.reply)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
cmd
|
|
209
|
+
console.log(`resuming session ${options.id} (${resumeCtx.messageCount} messages)`)
|
|
210
|
+
console.log(`last prompt: ${resumeCtx.lastPrompt.slice(0, 100)}${resumeCtx.lastPrompt.length > 100 ? "..." : ""}`)
|
|
211
|
+
const result = await executeTurn({
|
|
212
|
+
prompt: resumeCtx.lastPrompt,
|
|
213
|
+
mode,
|
|
214
|
+
model,
|
|
215
|
+
sessionId: options.id,
|
|
216
|
+
configState: ctx.configState,
|
|
217
|
+
providerType: resumeCtx.session.providerType
|
|
218
|
+
})
|
|
219
|
+
console.log(result.reply)
|
|
220
|
+
})
|
|
221
|
+
|
|
222
|
+
cmd
|
|
177
223
|
.command("retry")
|
|
178
|
-
.description("retry the last failed turn in a session")
|
|
179
|
-
.requiredOption("--id <id>", "session id to retry")
|
|
224
|
+
.description("retry the last failed turn in a session")
|
|
225
|
+
.requiredOption("--id <id>", "session id to retry")
|
|
180
226
|
.action(async (options) => {
|
|
181
227
|
const ctx = await buildContext()
|
|
182
228
|
if (!assertRecoveryEnabled(ctx.configState.config, "session retry")) return
|
|
@@ -186,34 +232,35 @@ export function createSessionCommand() {
|
|
|
186
232
|
console.error(`session not found: ${options.id}`)
|
|
187
233
|
process.exitCode = 1
|
|
188
234
|
return
|
|
189
|
-
}
|
|
190
|
-
if (!resumeCtx.canRetry) {
|
|
191
|
-
console.error(`session ${options.id} has no failed turn to retry`)
|
|
192
|
-
process.exitCode = 1
|
|
193
|
-
return
|
|
194
|
-
}
|
|
195
|
-
if (!resumeCtx.canResume) {
|
|
196
|
-
console.error(`no user message found in session ${options.id}`)
|
|
197
|
-
process.exitCode = 1
|
|
198
|
-
return
|
|
199
|
-
}
|
|
235
|
+
}
|
|
236
|
+
if (!resumeCtx.canRetry) {
|
|
237
|
+
console.error(`session ${options.id} has no failed turn to retry`)
|
|
238
|
+
process.exitCode = 1
|
|
239
|
+
return
|
|
240
|
+
}
|
|
241
|
+
if (!resumeCtx.canResume) {
|
|
242
|
+
console.error(`no user message found in session ${options.id}`)
|
|
243
|
+
process.exitCode = 1
|
|
244
|
+
return
|
|
245
|
+
}
|
|
200
246
|
await ToolRegistry.initialize({ config: ctx.configState.config, cwd: process.cwd() })
|
|
201
247
|
console.log(`retrying failed turn in session ${options.id}`)
|
|
202
|
-
const result = await executeTurn({
|
|
203
|
-
prompt: resumeCtx.lastPrompt,
|
|
204
|
-
mode: resumeCtx.session.mode,
|
|
205
|
-
model: resumeCtx.session.model,
|
|
206
|
-
sessionId: options.id,
|
|
207
|
-
configState: ctx.configState,
|
|
208
|
-
providerType: resumeCtx.session.providerType
|
|
209
|
-
})
|
|
210
|
-
console.log(result.reply)
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
cmd
|
|
248
|
+
const result = await executeTurn({
|
|
249
|
+
prompt: resumeCtx.lastPrompt,
|
|
250
|
+
mode: resumeCtx.session.mode,
|
|
251
|
+
model: resumeCtx.session.model,
|
|
252
|
+
sessionId: options.id,
|
|
253
|
+
configState: ctx.configState,
|
|
254
|
+
providerType: resumeCtx.session.providerType
|
|
255
|
+
})
|
|
256
|
+
console.log(result.reply)
|
|
257
|
+
})
|
|
258
|
+
|
|
259
|
+
cmd
|
|
214
260
|
.command("recoverable")
|
|
215
261
|
.description("list sessions that can be resumed or retried")
|
|
216
|
-
.
|
|
262
|
+
.option("--json", "print as json", false)
|
|
263
|
+
.action(async (options) => {
|
|
217
264
|
const ctx = await buildContext()
|
|
218
265
|
if (!assertRecoveryEnabled(ctx.configState.config, "session recoverable")) return
|
|
219
266
|
|
|
@@ -224,12 +271,20 @@ export function createSessionCommand() {
|
|
|
224
271
|
if (!sessions.length) {
|
|
225
272
|
console.log("no recoverable sessions")
|
|
226
273
|
return
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
}
|
|
274
|
+
}
|
|
275
|
+
if (options.json) {
|
|
276
|
+
const payload = await Promise.all(sessions.map(async (session) => ({
|
|
277
|
+
session,
|
|
278
|
+
resume: summarizeResumeContext(await getResumeContext(session.id, { enabled: true }))
|
|
279
|
+
})))
|
|
280
|
+
console.log(JSON.stringify(payload, null, 2))
|
|
281
|
+
return
|
|
282
|
+
}
|
|
283
|
+
for (const s of sessions) {
|
|
284
|
+
const summary = summarizeResumeContext(await getResumeContext(s.id, { enabled: true }))
|
|
285
|
+
console.log(`${s.id} ${s.mode} ${summary?.status || "unknown"} ${new Date(s.updatedAt).toLocaleString()} ${summary?.lastPromptPreview || ""}`)
|
|
286
|
+
}
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
return cmd
|
|
290
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { Command } from "commander"
|
|
2
|
+
import { ensureDefaultSkillPack } from "../skill/registry.mjs"
|
|
3
|
+
import { userRootDir } from "../storage/paths.mjs"
|
|
4
|
+
|
|
5
|
+
function formatSummary(scopeResults) {
|
|
6
|
+
const lines = []
|
|
7
|
+
for (const item of scopeResults) {
|
|
8
|
+
const created = item.created.join(", ")
|
|
9
|
+
const skipped = item.skipped.join(", ")
|
|
10
|
+
if (created.length) {
|
|
11
|
+
lines.push(`[${item.scope}] created: ${created}`)
|
|
12
|
+
}
|
|
13
|
+
if (skipped.length) {
|
|
14
|
+
lines.push(`[${item.scope}] already exists: ${skipped}`)
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return lines
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function createSkillCommand() {
|
|
21
|
+
const cmd = new Command("skill").description("manage kkcode skills")
|
|
22
|
+
|
|
23
|
+
cmd
|
|
24
|
+
.command("init")
|
|
25
|
+
.description("initialize built-in skill packs")
|
|
26
|
+
.option("--project", "initialize project scope .kkcode/skills")
|
|
27
|
+
.option("--global", "initialize global scope (KKCODE_HOME)/skills")
|
|
28
|
+
.option("--all", "initialize both project and global scope")
|
|
29
|
+
.option("--force", "overwrite existing files")
|
|
30
|
+
.option("--json", "print structured output", false)
|
|
31
|
+
.action(async (options) => {
|
|
32
|
+
const cwd = process.cwd()
|
|
33
|
+
const includeProject = options.all || options.project || (!options.global && !options.project)
|
|
34
|
+
const includeGlobal = options.all || options.global || (!options.global && !options.project)
|
|
35
|
+
|
|
36
|
+
const results = await ensureDefaultSkillPack({
|
|
37
|
+
cwd,
|
|
38
|
+
force: options.force || false,
|
|
39
|
+
includeProject,
|
|
40
|
+
includeGlobal
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
if (options.json) {
|
|
44
|
+
console.log(JSON.stringify({ ok: true, cwd, includeProject, includeGlobal, results }, null, 2))
|
|
45
|
+
return
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
console.log("skill init summary:")
|
|
49
|
+
for (const line of formatSummary(results)) {
|
|
50
|
+
console.log(`- ${line}`)
|
|
51
|
+
}
|
|
52
|
+
if (!results.length) {
|
|
53
|
+
console.log("- no target directories selected")
|
|
54
|
+
}
|
|
55
|
+
console.log("tip:")
|
|
56
|
+
const globalHint = userRootDir()
|
|
57
|
+
console.log(" kkcode skill init --project # initialize .kkcode/skills")
|
|
58
|
+
console.log(` kkcode skill init --global # initialize ${globalHint}/skills`)
|
|
59
|
+
console.log(" kkcode skill init # initialize both")
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return cmd
|
|
63
|
+
}
|
package/src/commands/theme.mjs
CHANGED
|
@@ -71,7 +71,7 @@ export function createThemeCommand() {
|
|
|
71
71
|
printContextWarnings(ctx)
|
|
72
72
|
const theme = ctx.themeState.theme
|
|
73
73
|
const config = ctx.configState.config
|
|
74
|
-
const modes = ["
|
|
74
|
+
const modes = ["assistant", "plan", "agent", "longagent"]
|
|
75
75
|
for (const mode of modes) {
|
|
76
76
|
const line = renderStatusBar({
|
|
77
77
|
mode,
|