@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.
Files changed (166) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +474 -387
  3. package/package.json +50 -46
  4. package/src/agent/agent.mjs +228 -220
  5. package/src/agent/custom-agent-loader.mjs +6 -3
  6. package/src/agent/generator.mjs +2 -2
  7. package/src/agent/prompt/assistant.txt +12 -0
  8. package/src/agent/prompt/bug-hunter.txt +89 -89
  9. package/src/agent/prompt/frontend-designer.txt +58 -58
  10. package/src/agent/prompt/guide.txt +1 -1
  11. package/src/agent/prompt/longagent-blueprint-agent.txt +83 -83
  12. package/src/agent/prompt/longagent-coding-agent.txt +37 -37
  13. package/src/agent/prompt/longagent-debugging-agent.txt +46 -46
  14. package/src/agent/prompt/longagent-preview-agent.txt +63 -63
  15. package/src/command/custom-commands.mjs +2 -2
  16. package/src/commands/agent.mjs +1 -1
  17. package/src/commands/background.mjs +145 -4
  18. package/src/commands/chat.mjs +117 -76
  19. package/src/commands/config.mjs +148 -1
  20. package/src/commands/doctor.mjs +30 -6
  21. package/src/commands/init.mjs +32 -6
  22. package/src/commands/longagent.mjs +117 -0
  23. package/src/commands/mcp.mjs +275 -43
  24. package/src/commands/permission.mjs +1 -1
  25. package/src/commands/session.mjs +195 -140
  26. package/src/commands/skill.mjs +63 -0
  27. package/src/commands/theme.mjs +1 -1
  28. package/src/commands/update.mjs +32 -0
  29. package/src/config/defaults.mjs +289 -260
  30. package/src/config/import-config.mjs +1 -1
  31. package/src/config/load-config.mjs +61 -4
  32. package/src/config/schema.mjs +604 -574
  33. package/src/context.mjs +4 -1
  34. package/src/core/constants.mjs +97 -91
  35. package/src/core/types.mjs +1 -1
  36. package/src/github/api.mjs +78 -78
  37. package/src/github/auth.mjs +294 -286
  38. package/src/github/flow.mjs +298 -298
  39. package/src/github/workspace.mjs +225 -212
  40. package/src/index.mjs +87 -82
  41. package/src/knowledge/frontend-aesthetics.txt +38 -38
  42. package/src/mcp/client-http.mjs +139 -141
  43. package/src/mcp/client-sse.mjs +297 -288
  44. package/src/mcp/client-stdio.mjs +534 -533
  45. package/src/mcp/constants.mjs +4 -2
  46. package/src/mcp/registry.mjs +498 -479
  47. package/src/mcp/stdio-framing.mjs +135 -133
  48. package/src/mcp/tool-result.mjs +24 -24
  49. package/src/observability/edit-diagnostics.mjs +449 -0
  50. package/src/observability/index.mjs +42 -42
  51. package/src/observability/metrics.mjs +165 -137
  52. package/src/observability/tracer.mjs +137 -137
  53. package/src/onboarding.mjs +209 -0
  54. package/src/orchestration/background-manager.mjs +567 -372
  55. package/src/orchestration/background-worker.mjs +419 -305
  56. package/src/orchestration/interruption-reason.mjs +21 -0
  57. package/src/orchestration/longagent-manager.mjs +197 -171
  58. package/src/orchestration/stage-scheduler.mjs +733 -728
  59. package/src/orchestration/subagent-router.mjs +7 -1
  60. package/src/orchestration/task-scheduler.mjs +219 -7
  61. package/src/permission/engine.mjs +1 -1
  62. package/src/permission/exec-policy.mjs +370 -370
  63. package/src/permission/file-edit-policy.mjs +108 -0
  64. package/src/permission/prompt.mjs +1 -1
  65. package/src/permission/rules.mjs +116 -7
  66. package/src/plugin/builtin-hooks/post-edit-format.mjs +2 -1
  67. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +104 -40
  68. package/src/plugin/hook-bus.mjs +19 -5
  69. package/src/plugin/manifest-loader.mjs +222 -0
  70. package/src/provider/anthropic.mjs +396 -390
  71. package/src/provider/ollama.mjs +7 -1
  72. package/src/provider/openai.mjs +382 -340
  73. package/src/provider/retry-policy.mjs +74 -68
  74. package/src/provider/router.mjs +242 -241
  75. package/src/provider/sse.mjs +104 -104
  76. package/src/provider/wizard.mjs +556 -0
  77. package/src/repl/capability-facade.mjs +30 -0
  78. package/src/repl/command-surface.mjs +23 -0
  79. package/src/repl/controller-entry.mjs +40 -0
  80. package/src/repl/core-shell.mjs +208 -0
  81. package/src/repl/dialog-router.mjs +87 -0
  82. package/src/repl/input-engine.mjs +76 -0
  83. package/src/repl/keymap.mjs +7 -0
  84. package/src/repl/operator-surface.mjs +15 -0
  85. package/src/repl/permission-flow.mjs +49 -0
  86. package/src/repl/runtime-facade.mjs +36 -0
  87. package/src/repl/slash-router.mjs +62 -0
  88. package/src/repl/state-store.mjs +29 -0
  89. package/src/repl/turn-controller.mjs +58 -0
  90. package/src/repl/verification.mjs +23 -0
  91. package/src/repl.mjs +3371 -2981
  92. package/src/rules/load-rules.mjs +3 -3
  93. package/src/runtime.mjs +1 -1
  94. package/src/session/agent-transaction.mjs +86 -0
  95. package/src/session/checkpoint.mjs +302 -302
  96. package/src/session/compaction.mjs +298 -298
  97. package/src/session/engine.mjs +417 -232
  98. package/src/session/longagent-4stage.mjs +467 -460
  99. package/src/session/longagent-hybrid.mjs +1344 -1097
  100. package/src/session/longagent-plan.mjs +376 -365
  101. package/src/session/longagent-project-memory.mjs +53 -53
  102. package/src/session/longagent-scaffold.mjs +291 -291
  103. package/src/session/longagent-task-bus.mjs +138 -54
  104. package/src/session/longagent-utils.mjs +828 -472
  105. package/src/session/longagent.mjs +911 -900
  106. package/src/session/loop.mjs +1005 -930
  107. package/src/session/prompt/agent.txt +25 -25
  108. package/src/session/prompt/anthropic.txt +150 -150
  109. package/src/session/prompt/beast.txt +1 -1
  110. package/src/session/prompt/plan.txt +31 -31
  111. package/src/session/prompt/qwen.txt +46 -46
  112. package/src/session/recovery.mjs +21 -0
  113. package/src/session/rollback.mjs +196 -195
  114. package/src/session/routing-observability.mjs +72 -0
  115. package/src/session/runtime-state.mjs +47 -0
  116. package/src/session/store.mjs +523 -519
  117. package/src/session/system-prompt.mjs +308 -273
  118. package/src/session/task-validator.mjs +267 -267
  119. package/src/session/usability-gates.mjs +2 -2
  120. package/src/skill/builtin/commit.mjs +64 -64
  121. package/src/skill/builtin/design.mjs +76 -76
  122. package/src/skill/generator.mjs +18 -2
  123. package/src/skill/registry.mjs +642 -390
  124. package/src/storage/audit-store.mjs +18 -11
  125. package/src/storage/event-log.mjs +7 -1
  126. package/src/storage/ghost-commit-store.mjs +243 -245
  127. package/src/storage/paths.mjs +17 -0
  128. package/src/theme/default-theme.mjs +1 -1
  129. package/src/theme/markdown.mjs +4 -0
  130. package/src/theme/schema.mjs +1 -1
  131. package/src/theme/status-bar.mjs +162 -158
  132. package/src/tool/audit-wrapper.mjs +18 -2
  133. package/src/tool/edit-transaction.mjs +23 -0
  134. package/src/tool/executor.mjs +26 -1
  135. package/src/tool/file-read-state.mjs +65 -0
  136. package/src/tool/git-auto.mjs +526 -526
  137. package/src/tool/git-full-auto.mjs +487 -478
  138. package/src/tool/mutation-guard.mjs +54 -0
  139. package/src/tool/prompt/edit.txt +3 -3
  140. package/src/tool/prompt/multiedit.txt +1 -0
  141. package/src/tool/prompt/notebookedit.txt +2 -1
  142. package/src/tool/prompt/patch.txt +25 -24
  143. package/src/tool/prompt/read.txt +3 -3
  144. package/src/tool/prompt/sysinfo.txt +29 -0
  145. package/src/tool/prompt/task.txt +66 -4
  146. package/src/tool/prompt/write.txt +2 -2
  147. package/src/tool/question-prompt.mjs +99 -93
  148. package/src/tool/registry.mjs +1701 -1343
  149. package/src/tool/task-tool.mjs +14 -6
  150. package/src/ui/activity-renderer.mjs +667 -664
  151. package/src/ui/repl-background-panel.mjs +7 -0
  152. package/src/ui/repl-capability-panel.mjs +9 -0
  153. package/src/ui/repl-dashboard.mjs +54 -4
  154. package/src/ui/repl-help.mjs +110 -0
  155. package/src/ui/repl-operator-panel.mjs +12 -0
  156. package/src/ui/repl-route-feedback.mjs +35 -0
  157. package/src/ui/repl-status-view.mjs +76 -0
  158. package/src/ui/repl-task-panel.mjs +5 -0
  159. package/src/ui/repl-transcript-panel.mjs +56 -0
  160. package/src/ui/repl-turn-summary.mjs +135 -0
  161. package/src/update/checker.mjs +184 -0
  162. package/src/usage/pricing.mjs +122 -121
  163. package/src/usage/usage-meter.mjs +1 -0
  164. package/src/util/git.mjs +562 -519
  165. package/src/util/template.mjs +6 -1
  166. package/src/version.mjs +3 -0
@@ -1,133 +1,135 @@
1
- const CRLFCRLF = Buffer.from("\r\n\r\n", "utf8")
2
- const NEWLINE = 0x0a
3
-
4
- function toBuffer(chunk) {
5
- if (Buffer.isBuffer(chunk)) return chunk
6
- if (typeof chunk === "string") return Buffer.from(chunk, "utf8")
7
- if (chunk instanceof Uint8Array) return Buffer.from(chunk)
8
- return Buffer.from(String(chunk || ""), "utf8")
9
- }
10
-
11
- function parseContentLengthHeader(headerText) {
12
- const match = /(?:^|\r?\n)content-length:\s*(\d+)\s*(?:\r?\n|$)/i.exec(headerText)
13
- if (!match) return null
14
- const len = Number(match[1])
15
- if (!Number.isFinite(len) || len < 0) return null
16
- return len
17
- }
18
-
19
- function consumeContentLengthFrame(buffer, maxFrameBytes) {
20
- const headerEnd = buffer.indexOf(CRLFCRLF)
21
- if (headerEnd === -1) return { type: "need_more" }
22
- const headerText = buffer.subarray(0, headerEnd).toString("utf8")
23
- const length = parseContentLengthHeader(headerText)
24
- if (length === null) return { type: "invalid_header" }
25
- if (length > maxFrameBytes) return { type: "invalid_size", size: length }
26
- const total = headerEnd + CRLFCRLF.length + length
27
- if (buffer.length < total) return { type: "need_more" }
28
- const payload = buffer
29
- .subarray(headerEnd + CRLFCRLF.length, total)
30
- .toString("utf8")
31
- const rest = buffer.subarray(total)
32
- return { type: "ok", payload, rest }
33
- }
34
-
35
- function consumeNewlineFrame(buffer) {
36
- const newlineIdx = buffer.indexOf(NEWLINE)
37
- if (newlineIdx === -1) return { type: "need_more" }
38
- const rawLine = buffer.subarray(0, newlineIdx).toString("utf8")
39
- const rest = buffer.subarray(newlineIdx + 1)
40
- const payload = rawLine.trim()
41
- if (!payload) return { type: "empty", rest }
42
- return { type: "ok", payload, rest }
43
- }
44
-
45
- function dropLeadingCrlf(buffer) {
46
- let cursor = 0
47
- while (cursor < buffer.length) {
48
- const c = buffer[cursor]
49
- if (c !== 0x0d && c !== 0x0a) break
50
- cursor += 1
51
- }
52
- return cursor > 0 ? buffer.subarray(cursor) : buffer
53
- }
54
-
55
- function seemsContentLength(buffer) {
56
- if (!buffer.length) return false
57
- const probe = buffer.subarray(0, Math.min(buffer.length, 32)).toString("ascii").toLowerCase()
58
- return probe.startsWith("content-length:")
59
- }
60
-
61
- export function encodeRpcMessage(message, framing = "content-length") {
62
- const payload = JSON.stringify(message)
63
- if (framing === "newline") return `${payload}\n`
64
- const size = Buffer.byteLength(payload, "utf8")
65
- return `Content-Length: ${size}\r\n\r\n${payload}`
66
- }
67
-
68
- export function createStdioFramingDecoder({ framing = "auto", maxFrameBytes = 8 * 1024 * 1024, maxBufferBytes = 16 * 1024 * 1024 } = {}) {
69
- let buffer = Buffer.alloc(0)
70
-
71
- function push(chunk) {
72
- const incoming = toBuffer(chunk)
73
- if (buffer.length + incoming.length > maxBufferBytes) {
74
- buffer = Buffer.alloc(0)
75
- throw new Error(`stdio framing buffer exceeded limit: ${maxBufferBytes} bytes`)
76
- }
77
- buffer = Buffer.concat([buffer, incoming])
78
- const messages = []
79
-
80
- while (true) {
81
- if (!buffer.length) break
82
-
83
- if (framing === "content-length") {
84
- const parsed = consumeContentLengthFrame(buffer, maxFrameBytes)
85
- if (parsed.type === "need_more") break
86
- if (parsed.type === "invalid_header") throw new Error("invalid content-length header")
87
- if (parsed.type === "invalid_size") throw new Error(`content-length exceeds limit: ${parsed.size}`)
88
- messages.push(parsed.payload)
89
- buffer = parsed.rest
90
- continue
91
- }
92
-
93
- if (framing === "newline") {
94
- const parsed = consumeNewlineFrame(buffer)
95
- if (parsed.type === "need_more") break
96
- buffer = parsed.rest
97
- if (parsed.type === "ok") messages.push(parsed.payload)
98
- continue
99
- }
100
-
101
- // auto mode: prefer standard content-length frames, then fallback to newline JSON
102
- buffer = dropLeadingCrlf(buffer)
103
- if (!buffer.length) break
104
-
105
- if (seemsContentLength(buffer)) {
106
- const parsed = consumeContentLengthFrame(buffer, maxFrameBytes)
107
- if (parsed.type === "need_more") break
108
- if (parsed.type === "invalid_header") throw new Error("invalid content-length header")
109
- if (parsed.type === "invalid_size") throw new Error(`content-length exceeds limit: ${parsed.size}`)
110
- messages.push(parsed.payload)
111
- buffer = parsed.rest
112
- continue
113
- }
114
-
115
- const parsed = consumeNewlineFrame(buffer)
116
- if (parsed.type === "need_more") break
117
- buffer = parsed.rest
118
- if (parsed.type === "ok") messages.push(parsed.payload)
119
- }
120
-
121
- return messages
122
- }
123
-
124
- function reset() {
125
- buffer = Buffer.alloc(0)
126
- }
127
-
128
- return {
129
- push,
130
- reset,
131
- bufferSize() { return buffer.length }
132
- }
133
- }
1
+ const CRLFCRLF = Buffer.from("\r\n\r\n", "utf8")
2
+ const NEWLINE = 0x0a
3
+
4
+ function toBuffer(chunk) {
5
+ if (Buffer.isBuffer(chunk)) return chunk
6
+ if (typeof chunk === "string") return Buffer.from(chunk, "utf8")
7
+ if (chunk instanceof Uint8Array) return Buffer.from(chunk)
8
+ return Buffer.from(String(chunk || ""), "utf8")
9
+ }
10
+
11
+ function parseContentLengthHeader(headerText) {
12
+ const match = /(?:^|\r?\n)content-length:\s*(\d+)\s*(?:\r?\n|$)/i.exec(headerText)
13
+ if (!match) return null
14
+ const len = Number(match[1])
15
+ if (!Number.isFinite(len) || len < 0) return null
16
+ return len
17
+ }
18
+
19
+ function consumeContentLengthFrame(buffer, maxFrameBytes) {
20
+ const headerEnd = buffer.indexOf(CRLFCRLF)
21
+ if (headerEnd === -1) return { type: "need_more" }
22
+ const headerText = buffer.subarray(0, headerEnd).toString("utf8")
23
+ const length = parseContentLengthHeader(headerText)
24
+ if (length === null) return { type: "invalid_header" }
25
+ if (length > maxFrameBytes) return { type: "invalid_size", size: length }
26
+ const total = headerEnd + CRLFCRLF.length + length
27
+ if (buffer.length < total) return { type: "need_more" }
28
+ const payload = buffer
29
+ .subarray(headerEnd + CRLFCRLF.length, total)
30
+ .toString("utf8")
31
+ const rest = buffer.subarray(total)
32
+ return { type: "ok", payload, rest }
33
+ }
34
+
35
+ function consumeNewlineFrame(buffer) {
36
+ const newlineIdx = buffer.indexOf(NEWLINE)
37
+ if (newlineIdx === -1) return { type: "need_more" }
38
+ const rawLine = buffer.subarray(0, newlineIdx).toString("utf8")
39
+ const rest = buffer.subarray(newlineIdx + 1)
40
+ const payload = rawLine.trim()
41
+ if (!payload) return { type: "empty", rest }
42
+ return { type: "ok", payload, rest }
43
+ }
44
+
45
+ function dropLeadingCrlf(buffer) {
46
+ let cursor = 0
47
+ while (cursor < buffer.length) {
48
+ const c = buffer[cursor]
49
+ if (c !== 0x0d && c !== 0x0a) break
50
+ cursor += 1
51
+ }
52
+ return cursor > 0 ? buffer.subarray(cursor) : buffer
53
+ }
54
+
55
+ function seemsContentLength(buffer) {
56
+ if (!buffer.length) return false
57
+ const probe = buffer.subarray(0, Math.min(buffer.length, 32)).toString("ascii").toLowerCase()
58
+ return probe.startsWith("content-length:")
59
+ }
60
+
61
+ export function encodeRpcMessage(message, framing = "content-length") {
62
+ const payload = JSON.stringify(message)
63
+ if (framing === "newline") return `${payload}\n`
64
+ const size = Buffer.byteLength(payload, "utf8")
65
+ return `Content-Length: ${size}\r\n\r\n${payload}`
66
+ }
67
+
68
+ export function createStdioFramingDecoder({ framing = "auto", maxFrameBytes = 8 * 1024 * 1024, maxBufferBytes = 16 * 1024 * 1024 } = {}) {
69
+ let buffer = Buffer.alloc(0)
70
+
71
+ function push(chunk) {
72
+ const incoming = toBuffer(chunk)
73
+ if (buffer.length + incoming.length > maxBufferBytes) {
74
+ // Preserve tail of buffer (last 25%) to avoid losing partial frames
75
+ const keepBytes = Math.floor(maxBufferBytes * 0.25)
76
+ buffer = buffer.subarray(buffer.length - keepBytes)
77
+ throw new Error(`stdio framing buffer exceeded limit: ${maxBufferBytes} bytes (kept last ${keepBytes} bytes)`)
78
+ }
79
+ buffer = Buffer.concat([buffer, incoming])
80
+ const messages = []
81
+
82
+ while (true) {
83
+ if (!buffer.length) break
84
+
85
+ if (framing === "content-length") {
86
+ const parsed = consumeContentLengthFrame(buffer, maxFrameBytes)
87
+ if (parsed.type === "need_more") break
88
+ if (parsed.type === "invalid_header") throw new Error("invalid content-length header")
89
+ if (parsed.type === "invalid_size") throw new Error(`content-length exceeds limit: ${parsed.size}`)
90
+ messages.push(parsed.payload)
91
+ buffer = parsed.rest
92
+ continue
93
+ }
94
+
95
+ if (framing === "newline") {
96
+ const parsed = consumeNewlineFrame(buffer)
97
+ if (parsed.type === "need_more") break
98
+ buffer = parsed.rest
99
+ if (parsed.type === "ok") messages.push(parsed.payload)
100
+ continue
101
+ }
102
+
103
+ // auto mode: prefer standard content-length frames, then fallback to newline JSON
104
+ buffer = dropLeadingCrlf(buffer)
105
+ if (!buffer.length) break
106
+
107
+ if (seemsContentLength(buffer)) {
108
+ const parsed = consumeContentLengthFrame(buffer, maxFrameBytes)
109
+ if (parsed.type === "need_more") break
110
+ if (parsed.type === "invalid_header") throw new Error("invalid content-length header")
111
+ if (parsed.type === "invalid_size") throw new Error(`content-length exceeds limit: ${parsed.size}`)
112
+ messages.push(parsed.payload)
113
+ buffer = parsed.rest
114
+ continue
115
+ }
116
+
117
+ const parsed = consumeNewlineFrame(buffer)
118
+ if (parsed.type === "need_more") break
119
+ buffer = parsed.rest
120
+ if (parsed.type === "ok") messages.push(parsed.payload)
121
+ }
122
+
123
+ return messages
124
+ }
125
+
126
+ function reset() {
127
+ buffer = Buffer.alloc(0)
128
+ }
129
+
130
+ return {
131
+ push,
132
+ reset,
133
+ bufferSize() { return buffer.length }
134
+ }
135
+ }
@@ -1,24 +1,24 @@
1
- import { McpError } from "../core/errors.mjs"
2
-
3
- export function normalizeToolResult(result, serverName, toolName) {
4
- if (result?.isError) {
5
- const text = Array.isArray(result.content)
6
- ? result.content.map((item) => item?.text || "").join("\n").trim()
7
- : ""
8
- throw new McpError(text || "mcp tool returned isError", {
9
- reason: "bad_response",
10
- server: serverName,
11
- action: `tools/call:${toolName}`,
12
- phase: "request"
13
- })
14
- }
15
- const content = Array.isArray(result?.content) ? result.content : null
16
- const contentText = content
17
- ? content.map((item) => (typeof item?.text === "string" ? item.text : "")).join("\n").trim()
18
- : ""
19
- const output =
20
- contentText ||
21
- (typeof result?.output === "string" ? result.output : "") ||
22
- (typeof result === "string" ? result : JSON.stringify(result))
23
- return content ? { output, raw: result, content } : { output, raw: result }
24
- }
1
+ import { McpError } from "../core/errors.mjs"
2
+
3
+ export function normalizeToolResult(result, serverName, toolName) {
4
+ if (result?.isError) {
5
+ const text = Array.isArray(result.content)
6
+ ? result.content.map((item) => item?.text || "").join("\n").trim()
7
+ : ""
8
+ throw new McpError(text || "mcp tool returned isError", {
9
+ reason: "bad_response",
10
+ server: serverName,
11
+ action: `tools/call:${toolName}`,
12
+ phase: "request"
13
+ })
14
+ }
15
+ const content = Array.isArray(result?.content) ? result.content : null
16
+ const contentText = content
17
+ ? content.map((item) => (typeof item?.text === "string" ? item.text : "")).join("\n").trim()
18
+ : ""
19
+ const output =
20
+ contentText ||
21
+ (typeof result?.output === "string" ? result.output : "") ||
22
+ (typeof result === "string" ? result : JSON.stringify(result))
23
+ return content ? { output, raw: result, content } : { output, raw: result }
24
+ }