@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,451 @@
1
+ import { spawn } from "node:child_process"
2
+ import { McpError } from "../core/errors.mjs"
3
+ import { EventBus } from "../core/events.mjs"
4
+ import { EVENT_TYPES } from "../core/constants.mjs"
5
+ import { createStdioFramingDecoder, encodeRpcMessage } from "./stdio-framing.mjs"
6
+
7
+ const VALID_FRAMING = new Set(["auto", "content-length", "newline"])
8
+ const VALID_HEALTH_METHOD = new Set(["auto", "ping", "tools_list"])
9
+
10
+ function normalizeFraming(value) {
11
+ const framing = String(value || "auto").toLowerCase()
12
+ return VALID_FRAMING.has(framing) ? framing : "auto"
13
+ }
14
+
15
+ function normalizeHealthMethod(value) {
16
+ const method = String(value || "auto").toLowerCase()
17
+ return VALID_HEALTH_METHOD.has(method) ? method : "auto"
18
+ }
19
+
20
+ function classifySpawnError(error) {
21
+ const code = String(error?.code || "").toUpperCase()
22
+ const msg = String(error?.message || error || "")
23
+ if (code === "ENOENT" || code === "EACCES") return "spawn_failed"
24
+ if (msg.includes("ENOENT") || msg.includes("EACCES") || msg.includes("spawn")) return "spawn_failed"
25
+ return "unknown"
26
+ }
27
+
28
+ function normalizeToolResult(result, serverName, toolName) {
29
+ if (result?.isError) {
30
+ const text = Array.isArray(result.content)
31
+ ? result.content.map((item) => item?.text || "").join("\n").trim()
32
+ : ""
33
+ throw new McpError(text || "mcp tool returned isError", {
34
+ reason: "bad_response",
35
+ server: serverName,
36
+ action: `tools/call:${toolName}`,
37
+ phase: "request"
38
+ })
39
+ }
40
+
41
+ const content = Array.isArray(result?.content) ? result.content : null
42
+ const contentText = content
43
+ ? content.map((item) => (typeof item?.text === "string" ? item.text : "")).join("\n").trim()
44
+ : ""
45
+ const output =
46
+ contentText ||
47
+ (typeof result?.output === "string" ? result.output : "") ||
48
+ (typeof result === "string" ? result : JSON.stringify(result))
49
+
50
+ return content
51
+ ? { output, raw: result, content }
52
+ : { output, raw: result }
53
+ }
54
+
55
+ export function createStdioMcpClient(serverName, config = {}) {
56
+ const command = config.command
57
+ const cmdArgs = Array.isArray(config.args) ? config.args : []
58
+ const envOverrides = config.env || {}
59
+ const startupTimeoutMs = Math.max(100, Number(config.startup_timeout_ms || 5000))
60
+ const requestTimeoutMs = Math.max(100, Number(config.request_timeout_ms || config.timeout_ms || 30000))
61
+ const healthCheckMethod = normalizeHealthMethod(config.health_check_method)
62
+ const configuredFraming = normalizeFraming(config.framing)
63
+ const isWindows = process.platform === "win32"
64
+ const explicitShell = config.shell === true || (config.shell !== false && isWindows)
65
+
66
+ let executable
67
+ let spawnArgs
68
+ if (Array.isArray(command)) {
69
+ executable = command[0]
70
+ spawnArgs = command.slice(1)
71
+ } else {
72
+ executable = command
73
+ spawnArgs = cmdArgs
74
+ }
75
+
76
+ if (!executable) {
77
+ throw new McpError(`mcp server "${serverName}" missing command`, {
78
+ reason: "spawn_failed",
79
+ server: serverName,
80
+ phase: "startup"
81
+ })
82
+ }
83
+
84
+ let child = null
85
+ let lifecycle = "closed"
86
+ let nextId = 1
87
+ let initialized = false
88
+ let activeFraming = configuredFraming === "auto" ? "content-length" : configuredFraming
89
+ let decoder = createStdioFramingDecoder({
90
+ framing: configuredFraming === "auto" ? "auto" : activeFraming
91
+ })
92
+ let malformedSeen = false
93
+ let malformedSnippet = ""
94
+ let stderrLines = []
95
+ let ignoreClose = false
96
+
97
+ const pending = new Map()
98
+
99
+ function resetRuntime() {
100
+ decoder = createStdioFramingDecoder({
101
+ framing: configuredFraming === "auto" ? "auto" : activeFraming
102
+ })
103
+ malformedSeen = false
104
+ malformedSnippet = ""
105
+ stderrLines = []
106
+ }
107
+
108
+ function appendStderr(chunk) {
109
+ const text = String(chunk || "").trim()
110
+ if (!text) return
111
+ stderrLines.push(text)
112
+ if (stderrLines.length > 8) stderrLines = stderrLines.slice(stderrLines.length - 8)
113
+ }
114
+
115
+ function rejectPending(reason, message, details = {}) {
116
+ for (const [, entry] of pending) {
117
+ clearTimeout(entry.timer)
118
+ entry.reject(
119
+ new McpError(message, {
120
+ reason,
121
+ server: serverName,
122
+ action: entry.method,
123
+ phase: entry.phase || details.phase || "request",
124
+ stderrSnippet: stderrLines.join(" | ") || undefined,
125
+ ...details
126
+ })
127
+ )
128
+ }
129
+ pending.clear()
130
+ }
131
+
132
+ function cleanupChild() {
133
+ child = null
134
+ initialized = false
135
+ lifecycle = "closed"
136
+ }
137
+
138
+ async function startProcess() {
139
+ if (child && lifecycle !== "closed") return
140
+
141
+ resetRuntime()
142
+ lifecycle = "starting"
143
+ ignoreClose = false
144
+
145
+ await new Promise((resolve, reject) => {
146
+ let settled = false
147
+ const proc = spawn(executable, spawnArgs, {
148
+ stdio: ["pipe", "pipe", "pipe"],
149
+ env: { ...process.env, ...envOverrides },
150
+ windowsHide: true,
151
+ shell: explicitShell
152
+ })
153
+ child = proc
154
+
155
+ const timer = setTimeout(() => {
156
+ if (settled) return
157
+ settled = true
158
+ try { proc.kill() } catch {}
159
+ reject(
160
+ new McpError(`mcp server "${serverName}" startup timeout after ${startupTimeoutMs}ms`, {
161
+ reason: "timeout",
162
+ server: serverName,
163
+ phase: "startup"
164
+ })
165
+ )
166
+ }, startupTimeoutMs)
167
+
168
+ proc.once("spawn", () => {
169
+ if (settled) return
170
+ settled = true
171
+ clearTimeout(timer)
172
+ lifecycle = "running"
173
+ resolve()
174
+ })
175
+
176
+ proc.once("error", (err) => {
177
+ const reason = classifySpawnError(err)
178
+ if (!settled) {
179
+ settled = true
180
+ clearTimeout(timer)
181
+ reject(
182
+ new McpError(`mcp server "${serverName}" process error: ${err.message}`, {
183
+ reason,
184
+ server: serverName,
185
+ phase: "startup"
186
+ })
187
+ )
188
+ } else {
189
+ rejectPending(reason, `mcp server "${serverName}" process error: ${err.message}`, { phase: "request" })
190
+ }
191
+ })
192
+
193
+ proc.stdout.on("data", (chunk) => {
194
+ let payloads = []
195
+ try {
196
+ payloads = decoder.push(chunk)
197
+ } catch (error) {
198
+ malformedSeen = true
199
+ malformedSnippet = String(error.message || "invalid framing").slice(0, 240)
200
+ return
201
+ }
202
+
203
+ for (const payload of payloads) {
204
+ let msg
205
+ try {
206
+ msg = JSON.parse(payload)
207
+ } catch {
208
+ malformedSeen = true
209
+ malformedSnippet = String(payload || "").slice(0, 240)
210
+ continue
211
+ }
212
+
213
+ if (msg?.id != null && pending.has(msg.id)) {
214
+ const entry = pending.get(msg.id)
215
+ pending.delete(msg.id)
216
+ clearTimeout(entry.timer)
217
+ if (msg.error) {
218
+ entry.reject(
219
+ new McpError(
220
+ `mcp server "${serverName}" error: ${msg.error.message || JSON.stringify(msg.error)}`,
221
+ {
222
+ reason: "bad_response",
223
+ server: serverName,
224
+ action: entry.method,
225
+ phase: entry.phase,
226
+ code: msg.error.code,
227
+ stderrSnippet: stderrLines.join(" | ") || undefined
228
+ }
229
+ )
230
+ )
231
+ } else {
232
+ const elapsed = Date.now() - entry.startedAt
233
+ EventBus.emit({
234
+ type: EVENT_TYPES.MCP_REQUEST,
235
+ payload: { server: serverName, action: entry.method, elapsed, transport: "stdio" }
236
+ }).catch(() => {})
237
+ entry.resolve(msg.result ?? {})
238
+ }
239
+ }
240
+ }
241
+ })
242
+
243
+ proc.stderr.on("data", (chunk) => appendStderr(chunk))
244
+
245
+ proc.on("close", (code, signal) => {
246
+ if (ignoreClose) {
247
+ cleanupChild()
248
+ return
249
+ }
250
+ const reason = malformedSeen ? "bad_response" : "server_crash"
251
+ const extra = malformedSeen && malformedSnippet
252
+ ? `; malformed stdout: ${malformedSnippet}`
253
+ : ""
254
+ rejectPending(
255
+ reason,
256
+ `mcp server "${serverName}" process exited unexpectedly (code=${code ?? "null"}, signal=${signal || "null"})${extra}`,
257
+ { phase: lifecycle === "starting" ? "startup" : "request" }
258
+ )
259
+ cleanupChild()
260
+ })
261
+ })
262
+ }
263
+
264
+ async function shutdownProcess() {
265
+ if (!child) return
266
+ ignoreClose = true
267
+ try {
268
+ child.kill()
269
+ } catch {}
270
+ rejectPending("unknown", `mcp server "${serverName}" shutdown`, { phase: "shutdown" })
271
+ cleanupChild()
272
+ }
273
+
274
+ async function sendRequest(method, params = {}, { phase = "request", timeoutMs = requestTimeoutMs } = {}) {
275
+ await startProcess()
276
+ const id = nextId++
277
+ const payload = { jsonrpc: "2.0", id, method, params }
278
+
279
+ return new Promise((resolve, reject) => {
280
+ const startedAt = Date.now()
281
+ const timer = setTimeout(() => {
282
+ pending.delete(id)
283
+ reject(
284
+ new McpError(`mcp server "${serverName}" timed out after ${timeoutMs}ms on "${method}"`, {
285
+ reason: "timeout",
286
+ server: serverName,
287
+ action: method,
288
+ phase
289
+ })
290
+ )
291
+ }, timeoutMs)
292
+
293
+ pending.set(id, { resolve, reject, timer, method, phase, startedAt })
294
+ try {
295
+ const wireFraming = configuredFraming === "auto" ? activeFraming : configuredFraming
296
+ child.stdin.write(encodeRpcMessage(payload, wireFraming))
297
+ } catch (error) {
298
+ clearTimeout(timer)
299
+ pending.delete(id)
300
+ reject(
301
+ new McpError(`mcp server "${serverName}" stdin write failed: ${error.message}`, {
302
+ reason: "server_crash",
303
+ server: serverName,
304
+ action: method,
305
+ phase
306
+ })
307
+ )
308
+ }
309
+ })
310
+ }
311
+
312
+ function sendNotification(method, params = {}) {
313
+ if (!child || lifecycle === "closed") return
314
+ const payload = { jsonrpc: "2.0", method, params }
315
+ try {
316
+ const wireFraming = configuredFraming === "auto" ? activeFraming : configuredFraming
317
+ child.stdin.write(encodeRpcMessage(payload, wireFraming))
318
+ } catch {
319
+ // best effort
320
+ }
321
+ }
322
+
323
+ async function initializeOnce() {
324
+ if (initialized) return
325
+ const initParams = {
326
+ protocolVersion: "2024-11-05",
327
+ capabilities: {},
328
+ clientInfo: { name: "kkcode", version: "0.1.2" }
329
+ }
330
+
331
+ if (configuredFraming === "auto") {
332
+ let lastError = null
333
+ for (const candidate of ["content-length", "newline"]) {
334
+ activeFraming = candidate
335
+ await shutdownProcess()
336
+ try {
337
+ await sendRequest("initialize", initParams, { phase: "initialize" })
338
+ sendNotification("notifications/initialized")
339
+ initialized = true
340
+ return
341
+ } catch (error) {
342
+ lastError = error
343
+ }
344
+ }
345
+ throw lastError || new McpError(`mcp server "${serverName}" failed to initialize`, {
346
+ reason: "unknown",
347
+ server: serverName,
348
+ phase: "initialize"
349
+ })
350
+ }
351
+
352
+ await sendRequest("initialize", initParams, { phase: "initialize" })
353
+ sendNotification("notifications/initialized")
354
+ initialized = true
355
+ }
356
+
357
+ async function healthPingOrTools() {
358
+ if (healthCheckMethod === "ping") {
359
+ await sendRequest("ping", {}, { phase: "request" })
360
+ return
361
+ }
362
+ if (healthCheckMethod === "tools_list") {
363
+ await sendRequest("tools/list", {}, { phase: "request" })
364
+ return
365
+ }
366
+
367
+ try {
368
+ await sendRequest("ping", {}, { phase: "request" })
369
+ } catch (error) {
370
+ if (!["bad_response", "protocol_error", "unknown"].includes(error.reason)) throw error
371
+ await sendRequest("tools/list", {}, { phase: "request" })
372
+ }
373
+ }
374
+
375
+ return {
376
+ serverName,
377
+ transport: "stdio",
378
+
379
+ async health() {
380
+ try {
381
+ await initializeOnce()
382
+ await healthPingOrTools()
383
+ return {
384
+ ok: true,
385
+ reason: "ok",
386
+ framing: configuredFraming === "auto" ? activeFraming : configuredFraming
387
+ }
388
+ } catch (error) {
389
+ return {
390
+ ok: false,
391
+ error: error.message,
392
+ reason: error.reason || "unknown",
393
+ phase: error.details?.phase || "unknown",
394
+ framing: configuredFraming === "auto" ? activeFraming : configuredFraming
395
+ }
396
+ }
397
+ },
398
+
399
+ async listTools() {
400
+ await initializeOnce()
401
+ const out = await sendRequest("tools/list")
402
+ return Array.isArray(out?.tools) ? out.tools : []
403
+ },
404
+
405
+ async listPrompts() {
406
+ await initializeOnce()
407
+ try {
408
+ const out = await sendRequest("prompts/list")
409
+ return Array.isArray(out?.prompts) ? out.prompts : []
410
+ } catch {
411
+ return []
412
+ }
413
+ },
414
+
415
+ async getPrompt(name, args = {}) {
416
+ await initializeOnce()
417
+ return sendRequest("prompts/get", { name, arguments: args })
418
+ },
419
+
420
+ async listResources() {
421
+ await initializeOnce()
422
+ try {
423
+ const out = await sendRequest("resources/list")
424
+ return Array.isArray(out?.resources) ? out.resources : []
425
+ } catch {
426
+ return []
427
+ }
428
+ },
429
+
430
+ async listTemplates() {
431
+ await initializeOnce()
432
+ try {
433
+ const out = await sendRequest("resources/templates/list")
434
+ return Array.isArray(out?.templates) ? out.templates : []
435
+ } catch {
436
+ return []
437
+ }
438
+ },
439
+
440
+ async callTool(name, args = {}, signal = null) {
441
+ await initializeOnce()
442
+ const result = await sendRequest("tools/call", { name, arguments: args })
443
+ return normalizeToolResult(result, serverName, name)
444
+ },
445
+
446
+ shutdown() {
447
+ sendNotification("notifications/cancelled", { reason: "shutdown" })
448
+ shutdownProcess().catch(() => {})
449
+ }
450
+ }
451
+ }