@kkelly-offical/kkcode 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +445 -0
  3. package/package.json +46 -0
  4. package/src/agent/agent.mjs +170 -0
  5. package/src/agent/custom-agent-loader.mjs +158 -0
  6. package/src/agent/generator.mjs +115 -0
  7. package/src/agent/prompt/architect.txt +36 -0
  8. package/src/agent/prompt/build-fixer.txt +71 -0
  9. package/src/agent/prompt/build.txt +101 -0
  10. package/src/agent/prompt/compaction.txt +12 -0
  11. package/src/agent/prompt/explore.txt +29 -0
  12. package/src/agent/prompt/guide.txt +40 -0
  13. package/src/agent/prompt/longagent.txt +178 -0
  14. package/src/agent/prompt/plan.txt +50 -0
  15. package/src/agent/prompt/researcher.txt +23 -0
  16. package/src/agent/prompt/reviewer.txt +44 -0
  17. package/src/agent/prompt/security-reviewer.txt +62 -0
  18. package/src/agent/prompt/tdd-guide.txt +84 -0
  19. package/src/agent/prompt/title.txt +8 -0
  20. package/src/command/custom-commands.mjs +57 -0
  21. package/src/commands/agent.mjs +71 -0
  22. package/src/commands/audit.mjs +77 -0
  23. package/src/commands/background.mjs +86 -0
  24. package/src/commands/chat.mjs +114 -0
  25. package/src/commands/command.mjs +41 -0
  26. package/src/commands/config.mjs +44 -0
  27. package/src/commands/doctor.mjs +148 -0
  28. package/src/commands/hook.mjs +29 -0
  29. package/src/commands/init.mjs +141 -0
  30. package/src/commands/longagent.mjs +100 -0
  31. package/src/commands/mcp.mjs +89 -0
  32. package/src/commands/permission.mjs +36 -0
  33. package/src/commands/prompt.mjs +42 -0
  34. package/src/commands/review.mjs +266 -0
  35. package/src/commands/rule.mjs +34 -0
  36. package/src/commands/session.mjs +235 -0
  37. package/src/commands/theme.mjs +98 -0
  38. package/src/commands/usage.mjs +91 -0
  39. package/src/config/defaults.mjs +195 -0
  40. package/src/config/import-config.mjs +76 -0
  41. package/src/config/load-config.mjs +76 -0
  42. package/src/config/schema.mjs +509 -0
  43. package/src/context.mjs +40 -0
  44. package/src/core/constants.mjs +46 -0
  45. package/src/core/errors.mjs +57 -0
  46. package/src/core/events.mjs +29 -0
  47. package/src/core/types.mjs +57 -0
  48. package/src/github/api.mjs +78 -0
  49. package/src/github/auth.mjs +286 -0
  50. package/src/github/flow.mjs +298 -0
  51. package/src/github/workspace.mjs +212 -0
  52. package/src/index.mjs +82 -0
  53. package/src/knowledge/api-design.txt +9 -0
  54. package/src/knowledge/cpp.txt +10 -0
  55. package/src/knowledge/docker.txt +10 -0
  56. package/src/knowledge/dotnet.txt +9 -0
  57. package/src/knowledge/electron.txt +10 -0
  58. package/src/knowledge/flutter.txt +10 -0
  59. package/src/knowledge/go.txt +9 -0
  60. package/src/knowledge/graphql.txt +10 -0
  61. package/src/knowledge/java.txt +9 -0
  62. package/src/knowledge/kotlin.txt +10 -0
  63. package/src/knowledge/loader.mjs +125 -0
  64. package/src/knowledge/next.txt +8 -0
  65. package/src/knowledge/node.txt +8 -0
  66. package/src/knowledge/nuxt.txt +9 -0
  67. package/src/knowledge/php.txt +10 -0
  68. package/src/knowledge/python.txt +10 -0
  69. package/src/knowledge/react-native.txt +10 -0
  70. package/src/knowledge/react.txt +9 -0
  71. package/src/knowledge/ruby.txt +11 -0
  72. package/src/knowledge/rust.txt +9 -0
  73. package/src/knowledge/svelte.txt +9 -0
  74. package/src/knowledge/swift.txt +10 -0
  75. package/src/knowledge/tailwind.txt +10 -0
  76. package/src/knowledge/testing.txt +8 -0
  77. package/src/knowledge/typescript.txt +8 -0
  78. package/src/knowledge/vue.txt +9 -0
  79. package/src/mcp/client-http.mjs +157 -0
  80. package/src/mcp/client-sse.mjs +286 -0
  81. package/src/mcp/client-stdio.mjs +451 -0
  82. package/src/mcp/registry.mjs +394 -0
  83. package/src/mcp/stdio-framing.mjs +127 -0
  84. package/src/orchestration/background-manager.mjs +358 -0
  85. package/src/orchestration/background-worker.mjs +245 -0
  86. package/src/orchestration/longagent-manager.mjs +116 -0
  87. package/src/orchestration/stage-scheduler.mjs +489 -0
  88. package/src/orchestration/subagent-router.mjs +62 -0
  89. package/src/orchestration/task-scheduler.mjs +74 -0
  90. package/src/permission/engine.mjs +92 -0
  91. package/src/permission/exec-policy.mjs +372 -0
  92. package/src/permission/prompt.mjs +39 -0
  93. package/src/permission/rules.mjs +120 -0
  94. package/src/permission/workspace-trust.mjs +44 -0
  95. package/src/plugin/builtin-hooks/console-warn.mjs +41 -0
  96. package/src/plugin/builtin-hooks/extract-patterns.mjs +75 -0
  97. package/src/plugin/builtin-hooks/post-edit-format.mjs +57 -0
  98. package/src/plugin/builtin-hooks/post-edit-typecheck.mjs +61 -0
  99. package/src/plugin/builtin-hooks/strategic-compaction.mjs +38 -0
  100. package/src/plugin/hook-bus.mjs +154 -0
  101. package/src/provider/anthropic.mjs +389 -0
  102. package/src/provider/ollama.mjs +236 -0
  103. package/src/provider/openai-compatible.mjs +1 -0
  104. package/src/provider/openai.mjs +339 -0
  105. package/src/provider/retry-policy.mjs +68 -0
  106. package/src/provider/router.mjs +228 -0
  107. package/src/provider/sse.mjs +91 -0
  108. package/src/repl.mjs +2929 -0
  109. package/src/review/diff-parser.mjs +36 -0
  110. package/src/review/rejection-queue.mjs +62 -0
  111. package/src/review/review-store.mjs +21 -0
  112. package/src/review/risk-score.mjs +61 -0
  113. package/src/rules/load-rules.mjs +64 -0
  114. package/src/runtime.mjs +1 -0
  115. package/src/session/checkpoint.mjs +239 -0
  116. package/src/session/compaction.mjs +276 -0
  117. package/src/session/engine.mjs +225 -0
  118. package/src/session/instinct-manager.mjs +172 -0
  119. package/src/session/instruction-loader.mjs +25 -0
  120. package/src/session/longagent-plan.mjs +329 -0
  121. package/src/session/longagent-scaffold.mjs +100 -0
  122. package/src/session/longagent.mjs +1462 -0
  123. package/src/session/loop.mjs +905 -0
  124. package/src/session/memory-loader.mjs +75 -0
  125. package/src/session/project-context.mjs +367 -0
  126. package/src/session/prompt/anthropic.txt +151 -0
  127. package/src/session/prompt/beast.txt +37 -0
  128. package/src/session/prompt/max-steps.txt +6 -0
  129. package/src/session/prompt/plan.txt +9 -0
  130. package/src/session/prompt/qwen.txt +46 -0
  131. package/src/session/prompt-loader.mjs +18 -0
  132. package/src/session/recovery.mjs +52 -0
  133. package/src/session/store.mjs +503 -0
  134. package/src/session/system-prompt.mjs +260 -0
  135. package/src/session/task-validator.mjs +266 -0
  136. package/src/session/usability-gates.mjs +379 -0
  137. package/src/skill/builtin/backend-patterns.mjs +123 -0
  138. package/src/skill/builtin/commit.mjs +64 -0
  139. package/src/skill/builtin/debug.mjs +45 -0
  140. package/src/skill/builtin/frontend-patterns.mjs +120 -0
  141. package/src/skill/builtin/frontend.mjs +188 -0
  142. package/src/skill/builtin/init.mjs +220 -0
  143. package/src/skill/builtin/review.mjs +49 -0
  144. package/src/skill/builtin/security-checklist.mjs +80 -0
  145. package/src/skill/builtin/tdd.mjs +54 -0
  146. package/src/skill/generator.mjs +113 -0
  147. package/src/skill/registry.mjs +336 -0
  148. package/src/storage/audit-store.mjs +83 -0
  149. package/src/storage/event-log.mjs +82 -0
  150. package/src/storage/ghost-commit-store.mjs +235 -0
  151. package/src/storage/json-store.mjs +53 -0
  152. package/src/storage/paths.mjs +148 -0
  153. package/src/theme/color.mjs +64 -0
  154. package/src/theme/default-theme.mjs +29 -0
  155. package/src/theme/load-theme.mjs +71 -0
  156. package/src/theme/markdown.mjs +135 -0
  157. package/src/theme/schema.mjs +45 -0
  158. package/src/theme/status-bar.mjs +158 -0
  159. package/src/tool/audit-wrapper.mjs +38 -0
  160. package/src/tool/edit-transaction.mjs +126 -0
  161. package/src/tool/executor.mjs +109 -0
  162. package/src/tool/file-lock-manager.mjs +85 -0
  163. package/src/tool/git-auto.mjs +545 -0
  164. package/src/tool/git-full-auto.mjs +478 -0
  165. package/src/tool/image-util.mjs +276 -0
  166. package/src/tool/prompt/background_cancel.txt +1 -0
  167. package/src/tool/prompt/background_output.txt +1 -0
  168. package/src/tool/prompt/bash.txt +71 -0
  169. package/src/tool/prompt/codesearch.txt +18 -0
  170. package/src/tool/prompt/edit.txt +27 -0
  171. package/src/tool/prompt/enter_plan.txt +74 -0
  172. package/src/tool/prompt/exit_plan.txt +62 -0
  173. package/src/tool/prompt/glob.txt +33 -0
  174. package/src/tool/prompt/grep.txt +43 -0
  175. package/src/tool/prompt/list.txt +8 -0
  176. package/src/tool/prompt/multiedit.txt +20 -0
  177. package/src/tool/prompt/notebookedit.txt +21 -0
  178. package/src/tool/prompt/patch.txt +24 -0
  179. package/src/tool/prompt/question.txt +44 -0
  180. package/src/tool/prompt/read.txt +40 -0
  181. package/src/tool/prompt/task.txt +83 -0
  182. package/src/tool/prompt/todowrite.txt +117 -0
  183. package/src/tool/prompt/webfetch.txt +38 -0
  184. package/src/tool/prompt/websearch.txt +43 -0
  185. package/src/tool/prompt/write.txt +38 -0
  186. package/src/tool/prompt-loader.mjs +18 -0
  187. package/src/tool/question-prompt.mjs +86 -0
  188. package/src/tool/registry.mjs +1309 -0
  189. package/src/tool/task-tool.mjs +28 -0
  190. package/src/ui/activity-renderer.mjs +410 -0
  191. package/src/ui/repl-dashboard.mjs +357 -0
  192. package/src/usage/pricing.mjs +121 -0
  193. package/src/usage/usage-meter.mjs +113 -0
  194. package/src/util/git.mjs +496 -0
  195. package/src/util/template.mjs +10 -0
  196. package/src/util/yaml.mjs +100 -0
@@ -0,0 +1,286 @@
1
+ import { McpError } from "../core/errors.mjs"
2
+ import { EventBus } from "../core/events.mjs"
3
+ import { EVENT_TYPES } from "../core/constants.mjs"
4
+
5
+ /**
6
+ * MCP Streamable HTTP (SSE) client.
7
+ *
8
+ * Protocol: JSON-RPC 2.0 over HTTP POST with optional SSE response streaming.
9
+ * - POST to endpoint: send JSON-RPC request, receive JSON or SSE stream
10
+ * - GET to endpoint: open persistent SSE stream for server-initiated notifications
11
+ * - Session management via Mcp-Session-Id header
12
+ */
13
+ export function createSseMcpClient(serverName, config) {
14
+ const baseUrl = String(config.url || "").replace(/\/$/, "")
15
+ const timeoutMs = Number(config.timeout_ms || 30000)
16
+ const headers = config.headers || {}
17
+
18
+ let sessionId = null
19
+ let nextId = 1
20
+ let initialized = false
21
+ let notificationStream = null
22
+
23
+ function normalizeToolResult(result, toolName) {
24
+ if (result?.isError) {
25
+ const text = Array.isArray(result.content)
26
+ ? result.content.map((item) => item?.text || "").join("\n").trim()
27
+ : ""
28
+ throw new McpError(text || "mcp tool returned isError", {
29
+ reason: "bad_response",
30
+ server: serverName,
31
+ action: `tools/call:${toolName}`,
32
+ phase: "request"
33
+ })
34
+ }
35
+ const content = Array.isArray(result?.content) ? result.content : null
36
+ const contentText = content
37
+ ? content.map((item) => (typeof item?.text === "string" ? item.text : "")).join("\n").trim()
38
+ : ""
39
+ const output =
40
+ contentText ||
41
+ (typeof result?.output === "string" ? result.output : "") ||
42
+ (typeof result === "string" ? result : JSON.stringify(result))
43
+ return content ? { output, raw: result, content } : { output, raw: result }
44
+ }
45
+
46
+ function buildHeaders(extra = {}) {
47
+ const h = {
48
+ "content-type": "application/json",
49
+ accept: "application/json, text/event-stream",
50
+ ...headers,
51
+ ...extra
52
+ }
53
+ if (sessionId) h["mcp-session-id"] = sessionId
54
+ return h
55
+ }
56
+
57
+ async function sendRequest(method, params = {}) {
58
+ const id = nextId++
59
+ const body = { jsonrpc: "2.0", id, method, params }
60
+ const startedAt = Date.now()
61
+
62
+ const controller = new AbortController()
63
+ const timer = setTimeout(() => controller.abort(), timeoutMs)
64
+
65
+ try {
66
+ const res = await fetch(baseUrl, {
67
+ method: "POST",
68
+ headers: buildHeaders(),
69
+ body: JSON.stringify(body),
70
+ signal: controller.signal
71
+ })
72
+
73
+ clearTimeout(timer)
74
+ const elapsed = Date.now() - startedAt
75
+
76
+ // Capture session ID from response
77
+ const newSessionId = res.headers.get("mcp-session-id")
78
+ if (newSessionId) sessionId = newSessionId
79
+
80
+ EventBus.emit({
81
+ type: EVENT_TYPES.MCP_REQUEST,
82
+ payload: { server: serverName, action: method, elapsed, status: res.status }
83
+ }).catch(() => {})
84
+
85
+ if (!res.ok) {
86
+ const text = await res.text().catch(() => "")
87
+ throw new McpError(
88
+ `mcp server "${serverName}" HTTP ${res.status}: ${text.slice(0, 500)}`,
89
+ {
90
+ reason: res.status >= 500 ? "server_crash" : "bad_response",
91
+ server: serverName,
92
+ action: method,
93
+ phase: "request",
94
+ statusCode: res.status
95
+ }
96
+ )
97
+ }
98
+
99
+ const contentType = res.headers.get("content-type") || ""
100
+
101
+ // SSE response — parse events and return the final result
102
+ if (contentType.includes("text/event-stream")) {
103
+ return await parseSseResponse(res.body, id)
104
+ }
105
+
106
+ // Regular JSON response
107
+ const json = await res.json().catch(() => ({}))
108
+ if (json.error) {
109
+ throw new McpError(
110
+ `mcp server "${serverName}" error: ${json.error.message || JSON.stringify(json.error)}`,
111
+ { reason: "bad_response", server: serverName, action: method, code: json.error.code, phase: "request" }
112
+ )
113
+ }
114
+ return json.result ?? json
115
+ } catch (error) {
116
+ clearTimeout(timer)
117
+ if (error instanceof McpError) throw error
118
+ const reason = error.name === "AbortError" ? "timeout" : "connection_refused"
119
+ throw new McpError(
120
+ `mcp server "${serverName}" ${reason}: ${error.message}`,
121
+ { reason, server: serverName, action: method, phase: "request" }
122
+ )
123
+ }
124
+ }
125
+
126
+ async function parseSseResponse(body, requestId) {
127
+ const reader = body.getReader()
128
+ const decoder = new TextDecoder()
129
+ let buffer = ""
130
+ let result = null
131
+
132
+ try {
133
+ while (true) {
134
+ const { done, value } = await reader.read()
135
+ if (done) break
136
+ buffer += decoder.decode(value, { stream: true })
137
+
138
+ const parts = buffer.split("\n\n")
139
+ buffer = parts.pop()
140
+
141
+ for (const part of parts) {
142
+ const event = parseSsePart(part)
143
+ if (!event) continue
144
+
145
+ try {
146
+ const msg = JSON.parse(event.data)
147
+ // Match our request ID
148
+ if (msg.id === requestId) {
149
+ if (msg.error) {
150
+ throw new McpError(
151
+ `mcp server "${serverName}" error: ${msg.error.message || JSON.stringify(msg.error)}`,
152
+ { reason: "bad_response", server: serverName, code: msg.error.code, phase: "request" }
153
+ )
154
+ }
155
+ result = msg.result ?? msg
156
+ }
157
+ // Server notifications — emit as events
158
+ if (!msg.id && msg.method) {
159
+ EventBus.emit({
160
+ type: EVENT_TYPES.MCP_REQUEST,
161
+ payload: { server: serverName, action: `notification:${msg.method}`, notification: true }
162
+ }).catch(() => {})
163
+ }
164
+ } catch (e) {
165
+ if (e instanceof McpError) throw e
166
+ // Non-JSON SSE data — skip
167
+ }
168
+ }
169
+ }
170
+ } finally {
171
+ try { reader.releaseLock() } catch { /* reader may have pending read if stream was force-closed */ }
172
+ }
173
+
174
+ return result ?? {}
175
+ }
176
+
177
+ function parseSsePart(part) {
178
+ const trimmed = part.trim()
179
+ if (!trimmed) return null
180
+ let event = null
181
+ let data = ""
182
+ for (const line of trimmed.split("\n")) {
183
+ if (line.startsWith("event:")) event = line.slice(6).trim()
184
+ else if (line.startsWith("data:")) data += line.slice(5).trim()
185
+ }
186
+ if (!data) return null
187
+ return { event, data }
188
+ }
189
+
190
+ async function ensureInitialized() {
191
+ if (initialized) return
192
+ const result = await sendRequest("initialize", {
193
+ protocolVersion: "2024-11-05",
194
+ capabilities: {},
195
+ clientInfo: { name: "kkcode", version: "0.1.2" }
196
+ })
197
+ // Send initialized notification
198
+ try {
199
+ await fetch(baseUrl, {
200
+ method: "POST",
201
+ headers: buildHeaders(),
202
+ body: JSON.stringify({ jsonrpc: "2.0", method: "notifications/initialized" })
203
+ })
204
+ } catch { /* best-effort */ }
205
+ initialized = true
206
+ return result
207
+ }
208
+
209
+ return {
210
+ serverName,
211
+ transport: "sse",
212
+
213
+ async health() {
214
+ try {
215
+ await ensureInitialized()
216
+ await sendRequest("ping")
217
+ return { ok: true }
218
+ } catch (error) {
219
+ return { ok: false, error: error.message, reason: error.reason || "unknown" }
220
+ }
221
+ },
222
+
223
+ async listTools() {
224
+ await ensureInitialized()
225
+ const out = await sendRequest("tools/list")
226
+ return Array.isArray(out?.tools) ? out.tools : []
227
+ },
228
+
229
+ async listPrompts() {
230
+ await ensureInitialized()
231
+ try {
232
+ const out = await sendRequest("prompts/list")
233
+ return Array.isArray(out?.prompts) ? out.prompts : []
234
+ } catch {
235
+ return []
236
+ }
237
+ },
238
+
239
+ async getPrompt(name, args = {}) {
240
+ await ensureInitialized()
241
+ return sendRequest("prompts/get", { name, arguments: args })
242
+ },
243
+
244
+ async listResources() {
245
+ await ensureInitialized()
246
+ try {
247
+ const out = await sendRequest("resources/list")
248
+ return Array.isArray(out?.resources) ? out.resources : []
249
+ } catch {
250
+ return []
251
+ }
252
+ },
253
+
254
+ async listTemplates() {
255
+ await ensureInitialized()
256
+ try {
257
+ const out = await sendRequest("resources/templates/list")
258
+ return Array.isArray(out?.templates) ? out.templates : []
259
+ } catch {
260
+ return []
261
+ }
262
+ },
263
+
264
+ async callTool(name, args = {}, signal = null) {
265
+ await ensureInitialized()
266
+ const result = await sendRequest("tools/call", { name, arguments: args })
267
+ return normalizeToolResult(result, name)
268
+ },
269
+
270
+ shutdown() {
271
+ if (notificationStream) {
272
+ try { notificationStream.cancel() } catch { /* ignore */ }
273
+ notificationStream = null
274
+ }
275
+ // Send session termination if we have a session
276
+ if (sessionId) {
277
+ fetch(baseUrl, {
278
+ method: "DELETE",
279
+ headers: buildHeaders()
280
+ }).catch(() => {})
281
+ }
282
+ sessionId = null
283
+ initialized = false
284
+ }
285
+ }
286
+ }