@danya-ai/cli 0.1.0

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 (184) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +336 -0
  3. package/cli-acp.js +82 -0
  4. package/cli.js +105 -0
  5. package/dist/REPL-EYUOXCEC.js +42 -0
  6. package/dist/REPL-EYUOXCEC.js.map +7 -0
  7. package/dist/acp-S5WNCLMD.js +1372 -0
  8. package/dist/acp-S5WNCLMD.js.map +7 -0
  9. package/dist/agentsValidate-RQ2QDGNY.js +373 -0
  10. package/dist/agentsValidate-RQ2QDGNY.js.map +7 -0
  11. package/dist/ask-TX526UBD.js +129 -0
  12. package/dist/ask-TX526UBD.js.map +7 -0
  13. package/dist/autoUpdater-63RAZ24N.js +17 -0
  14. package/dist/autoUpdater-63RAZ24N.js.map +7 -0
  15. package/dist/chunk-2VQWLLDU.js +16 -0
  16. package/dist/chunk-2VQWLLDU.js.map +7 -0
  17. package/dist/chunk-4CLHMO4I.js +656 -0
  18. package/dist/chunk-4CLHMO4I.js.map +7 -0
  19. package/dist/chunk-4ZNNWJZU.js +5696 -0
  20. package/dist/chunk-4ZNNWJZU.js.map +7 -0
  21. package/dist/chunk-66EZC7Y7.js +149 -0
  22. package/dist/chunk-66EZC7Y7.js.map +7 -0
  23. package/dist/chunk-6EPQRP3S.js +96 -0
  24. package/dist/chunk-6EPQRP3S.js.map +7 -0
  25. package/dist/chunk-77IRSDFR.js +195 -0
  26. package/dist/chunk-77IRSDFR.js.map +7 -0
  27. package/dist/chunk-7RZNLBEK.js +136 -0
  28. package/dist/chunk-7RZNLBEK.js.map +7 -0
  29. package/dist/chunk-BNBV2FXC.js +19 -0
  30. package/dist/chunk-BNBV2FXC.js.map +7 -0
  31. package/dist/chunk-CQCREBDO.js +248 -0
  32. package/dist/chunk-CQCREBDO.js.map +7 -0
  33. package/dist/chunk-D77XS6TB.js +74 -0
  34. package/dist/chunk-D77XS6TB.js.map +7 -0
  35. package/dist/chunk-DHYBJN3V.js +474 -0
  36. package/dist/chunk-DHYBJN3V.js.map +7 -0
  37. package/dist/chunk-DLSLSLTR.js +842 -0
  38. package/dist/chunk-DLSLSLTR.js.map +7 -0
  39. package/dist/chunk-ELAE6Z4H.js +514 -0
  40. package/dist/chunk-ELAE6Z4H.js.map +7 -0
  41. package/dist/chunk-ELZQD7ZR.js +531 -0
  42. package/dist/chunk-ELZQD7ZR.js.map +7 -0
  43. package/dist/chunk-F6DEGMX6.js +31269 -0
  44. package/dist/chunk-F6DEGMX6.js.map +7 -0
  45. package/dist/chunk-GDF2AON2.js +124 -0
  46. package/dist/chunk-GDF2AON2.js.map +7 -0
  47. package/dist/chunk-H7BGBV4P.js +498 -0
  48. package/dist/chunk-H7BGBV4P.js.map +7 -0
  49. package/dist/chunk-HIIHGKXP.js +24 -0
  50. package/dist/chunk-HIIHGKXP.js.map +7 -0
  51. package/dist/chunk-HJCCXED7.js +17 -0
  52. package/dist/chunk-HJCCXED7.js.map +7 -0
  53. package/dist/chunk-IQ6VZB2Y.js +139 -0
  54. package/dist/chunk-IQ6VZB2Y.js.map +7 -0
  55. package/dist/chunk-J4D7AELD.js +518 -0
  56. package/dist/chunk-J4D7AELD.js.map +7 -0
  57. package/dist/chunk-JVGG2YQR.js +23 -0
  58. package/dist/chunk-JVGG2YQR.js.map +7 -0
  59. package/dist/chunk-LGEK2NV7.js +939 -0
  60. package/dist/chunk-LGEK2NV7.js.map +7 -0
  61. package/dist/chunk-LWXT5RGE.js +95 -0
  62. package/dist/chunk-LWXT5RGE.js.map +7 -0
  63. package/dist/chunk-M3TKNAUR.js +35 -0
  64. package/dist/chunk-M3TKNAUR.js.map +7 -0
  65. package/dist/chunk-MRFO7QO5.js +170 -0
  66. package/dist/chunk-MRFO7QO5.js.map +7 -0
  67. package/dist/chunk-MVN3DHQF.js +95 -0
  68. package/dist/chunk-MVN3DHQF.js.map +7 -0
  69. package/dist/chunk-O25PXGOC.js +772 -0
  70. package/dist/chunk-O25PXGOC.js.map +7 -0
  71. package/dist/chunk-OBGVKM3N.js +1618 -0
  72. package/dist/chunk-OBGVKM3N.js.map +7 -0
  73. package/dist/chunk-OV5HJXXQ.js +198 -0
  74. package/dist/chunk-OV5HJXXQ.js.map +7 -0
  75. package/dist/chunk-P5VWDMRD.js +249 -0
  76. package/dist/chunk-P5VWDMRD.js.map +7 -0
  77. package/dist/chunk-PDSAJX7G.js +49 -0
  78. package/dist/chunk-PDSAJX7G.js.map +7 -0
  79. package/dist/chunk-RHNEZOPO.js +739 -0
  80. package/dist/chunk-RHNEZOPO.js.map +7 -0
  81. package/dist/chunk-SQGAHZPM.js +3004 -0
  82. package/dist/chunk-SQGAHZPM.js.map +7 -0
  83. package/dist/chunk-U7Z4MXY4.js +21 -0
  84. package/dist/chunk-U7Z4MXY4.js.map +7 -0
  85. package/dist/chunk-UNCTVIS7.js +146 -0
  86. package/dist/chunk-UNCTVIS7.js.map +7 -0
  87. package/dist/chunk-VMEOI6MH.js +1103 -0
  88. package/dist/chunk-VMEOI6MH.js.map +7 -0
  89. package/dist/chunk-WAY3DKFO.js +47 -0
  90. package/dist/chunk-WAY3DKFO.js.map +7 -0
  91. package/dist/chunk-XEYEKVFT.js +24 -0
  92. package/dist/chunk-XEYEKVFT.js.map +7 -0
  93. package/dist/chunk-Y4BQ36T4.js +796 -0
  94. package/dist/chunk-Y4BQ36T4.js.map +7 -0
  95. package/dist/chunk-Y5LQPJWK.js +12 -0
  96. package/dist/chunk-Y5LQPJWK.js.map +7 -0
  97. package/dist/chunk-YIJWUNWF.js +1260 -0
  98. package/dist/chunk-YIJWUNWF.js.map +7 -0
  99. package/dist/chunk-YMIWYEZ7.js +34 -0
  100. package/dist/chunk-YMIWYEZ7.js.map +7 -0
  101. package/dist/cli-PQNZWJX4.js +3952 -0
  102. package/dist/cli-PQNZWJX4.js.map +7 -0
  103. package/dist/commands-HOBCZ3VQ.js +46 -0
  104. package/dist/commands-HOBCZ3VQ.js.map +7 -0
  105. package/dist/config-MLH7ZTFA.js +81 -0
  106. package/dist/config-MLH7ZTFA.js.map +7 -0
  107. package/dist/context-FZ6G4J63.js +30 -0
  108. package/dist/context-FZ6G4J63.js.map +7 -0
  109. package/dist/costTracker-5WKZXN5S.js +19 -0
  110. package/dist/costTracker-5WKZXN5S.js.map +7 -0
  111. package/dist/customCommands-EB4MMZSS.js +25 -0
  112. package/dist/customCommands-EB4MMZSS.js.map +7 -0
  113. package/dist/env-VMEIP4EW.js +28 -0
  114. package/dist/env-VMEIP4EW.js.map +7 -0
  115. package/dist/index.js +36 -0
  116. package/dist/index.js.map +7 -0
  117. package/dist/kodeAgentSessionId-WUT74FSH.js +16 -0
  118. package/dist/kodeAgentSessionId-WUT74FSH.js.map +7 -0
  119. package/dist/kodeAgentSessionLoad-KR4JSD6D.js +21 -0
  120. package/dist/kodeAgentSessionLoad-KR4JSD6D.js.map +7 -0
  121. package/dist/kodeAgentSessionResume-BCD6UV74.js +18 -0
  122. package/dist/kodeAgentSessionResume-BCD6UV74.js.map +7 -0
  123. package/dist/kodeAgentStreamJson-EDHHWNNX.js +15 -0
  124. package/dist/kodeAgentStreamJson-EDHHWNNX.js.map +7 -0
  125. package/dist/kodeAgentStreamJsonSession-G4RBNZRN.js +133 -0
  126. package/dist/kodeAgentStreamJsonSession-G4RBNZRN.js.map +7 -0
  127. package/dist/kodeAgentStructuredStdio-UA5P5UNU.js +11 -0
  128. package/dist/kodeAgentStructuredStdio-UA5P5UNU.js.map +7 -0
  129. package/dist/kodeHooks-EHM6GSIQ.js +37 -0
  130. package/dist/kodeHooks-EHM6GSIQ.js.map +7 -0
  131. package/dist/llm-SJXCV7DA.js +3138 -0
  132. package/dist/llm-SJXCV7DA.js.map +7 -0
  133. package/dist/llmLazy-2QYJVD6K.js +15 -0
  134. package/dist/llmLazy-2QYJVD6K.js.map +7 -0
  135. package/dist/loader-LJX77EFL.js +28 -0
  136. package/dist/loader-LJX77EFL.js.map +7 -0
  137. package/dist/mcp-DOROSLPN.js +49 -0
  138. package/dist/mcp-DOROSLPN.js.map +7 -0
  139. package/dist/mentionProcessor-5UZRHCGH.js +215 -0
  140. package/dist/mentionProcessor-5UZRHCGH.js.map +7 -0
  141. package/dist/messages-N5KBI53P.js +65 -0
  142. package/dist/messages-N5KBI53P.js.map +7 -0
  143. package/dist/model-HPLBR53R.js +30 -0
  144. package/dist/model-HPLBR53R.js.map +7 -0
  145. package/dist/openai-YP4OJYKF.js +29 -0
  146. package/dist/openai-YP4OJYKF.js.map +7 -0
  147. package/dist/outputStyles-NNALI5D7.js +28 -0
  148. package/dist/outputStyles-NNALI5D7.js.map +7 -0
  149. package/dist/package.json +4 -0
  150. package/dist/pluginRuntime-JYYI5BSQ.js +220 -0
  151. package/dist/pluginRuntime-JYYI5BSQ.js.map +7 -0
  152. package/dist/pluginValidation-JWUFPZUE.js +17 -0
  153. package/dist/pluginValidation-JWUFPZUE.js.map +7 -0
  154. package/dist/prompts-B2SS7CWI.js +50 -0
  155. package/dist/prompts-B2SS7CWI.js.map +7 -0
  156. package/dist/query-HIK457UU.js +50 -0
  157. package/dist/query-HIK457UU.js.map +7 -0
  158. package/dist/responsesStreaming-L2BSN37C.js +10 -0
  159. package/dist/responsesStreaming-L2BSN37C.js.map +7 -0
  160. package/dist/ripgrep-GCKI4UTL.js +17 -0
  161. package/dist/ripgrep-GCKI4UTL.js.map +7 -0
  162. package/dist/skillMarketplace-PCTUUX46.js +37 -0
  163. package/dist/skillMarketplace-PCTUUX46.js.map +7 -0
  164. package/dist/state-XJICGOUA.js +18 -0
  165. package/dist/state-XJICGOUA.js.map +7 -0
  166. package/dist/theme-DP7O4SGH.js +14 -0
  167. package/dist/theme-DP7O4SGH.js.map +7 -0
  168. package/dist/toolPermissionContext-DHAGUPEW.js +17 -0
  169. package/dist/toolPermissionContext-DHAGUPEW.js.map +7 -0
  170. package/dist/toolPermissionSettings-PT65MQIQ.js +18 -0
  171. package/dist/toolPermissionSettings-PT65MQIQ.js.map +7 -0
  172. package/dist/tools-BHW37PCF.js +47 -0
  173. package/dist/tools-BHW37PCF.js.map +7 -0
  174. package/dist/userInput-XDRYT5TI.js +316 -0
  175. package/dist/userInput-XDRYT5TI.js.map +7 -0
  176. package/dist/uuid-QUYJMIUV.js +9 -0
  177. package/dist/uuid-QUYJMIUV.js.map +7 -0
  178. package/dist/yoga.wasm +0 -0
  179. package/package.json +115 -0
  180. package/scripts/binary-utils.cjs +62 -0
  181. package/scripts/cli-acp-wrapper.cjs +82 -0
  182. package/scripts/cli-wrapper.cjs +105 -0
  183. package/scripts/postinstall.js +144 -0
  184. package/yoga.wasm +0 -0
@@ -0,0 +1,3952 @@
1
+ #!/usr/bin/env bun
2
+ import { createRequire as __kodeCreateRequire } from "node:module";
3
+ const require = __kodeCreateRequire(import.meta.url);
4
+ import {
5
+ ensurePackagedRuntimeEnv,
6
+ ensureYogaWasmPath
7
+ } from "./chunk-PDSAJX7G.js";
8
+ import {
9
+ getAllTools
10
+ } from "./chunk-4ZNNWJZU.js";
11
+ import {
12
+ DanyaAgentStructuredStdio
13
+ } from "./chunk-P5VWDMRD.js";
14
+ import {
15
+ assertMinVersion
16
+ } from "./chunk-7RZNLBEK.js";
17
+ import {
18
+ getToolDescription
19
+ } from "./chunk-HJCCXED7.js";
20
+ import {
21
+ lastX
22
+ } from "./chunk-BNBV2FXC.js";
23
+ import {
24
+ Doctor,
25
+ Onboarding,
26
+ ResumeConversation,
27
+ Select,
28
+ addToHistory,
29
+ clearTerminal,
30
+ grantReadPermissionForOriginalDir,
31
+ hasPermissionsToUseTool,
32
+ review_default,
33
+ useExitOnCtrlCD,
34
+ useTerminalSize
35
+ } from "./chunk-F6DEGMX6.js";
36
+ import "./chunk-OV5HJXXQ.js";
37
+ import {
38
+ addMcpServer,
39
+ ensureConfigScope,
40
+ getClients,
41
+ getClientsForCliMcpConfig,
42
+ getMcpServer,
43
+ getMcprcServerStatus,
44
+ listMCPServers,
45
+ looksLikeMcpUrl,
46
+ normalizeMcpScopeForCli,
47
+ normalizeMcpTransport,
48
+ parseEnvVars,
49
+ parseMcpHeaders,
50
+ removeMcpServer
51
+ } from "./chunk-OBGVKM3N.js";
52
+ import "./chunk-DHYBJN3V.js";
53
+ import "./chunk-VMEOI6MH.js";
54
+ import "./chunk-IQ6VZB2Y.js";
55
+ import "./chunk-CQCREBDO.js";
56
+ import "./chunk-Y5LQPJWK.js";
57
+ import "./chunk-JVGG2YQR.js";
58
+ import "./chunk-YIJWUNWF.js";
59
+ import "./chunk-U7Z4MXY4.js";
60
+ import {
61
+ clearOutputStyleCache
62
+ } from "./chunk-ELAE6Z4H.js";
63
+ import "./chunk-LGEK2NV7.js";
64
+ import "./chunk-YMIWYEZ7.js";
65
+ import "./chunk-MRFO7QO5.js";
66
+ import "./chunk-O25PXGOC.js";
67
+ import "./chunk-77IRSDFR.js";
68
+ import "./chunk-66EZC7Y7.js";
69
+ import "./chunk-MVN3DHQF.js";
70
+ import "./chunk-J4D7AELD.js";
71
+ import "./chunk-XEYEKVFT.js";
72
+ import {
73
+ clearAgentCache,
74
+ setFlagAgentsFromCliJson
75
+ } from "./chunk-RHNEZOPO.js";
76
+ import {
77
+ setEnabledSettingSourcesFromCli
78
+ } from "./chunk-WAY3DKFO.js";
79
+ import "./chunk-2VQWLLDU.js";
80
+ import "./chunk-H7BGBV4P.js";
81
+ import {
82
+ getModelManager,
83
+ isDefaultSlowAndCapableModel
84
+ } from "./chunk-4CLHMO4I.js";
85
+ import {
86
+ getContext,
87
+ removeContext,
88
+ setContext
89
+ } from "./chunk-ELZQD7ZR.js";
90
+ import {
91
+ getTheme
92
+ } from "./chunk-GDF2AON2.js";
93
+ import {
94
+ checkHasTrustDialogAccepted,
95
+ deleteConfigForCLI,
96
+ enableConfigs,
97
+ getConfigForCLI,
98
+ getCurrentProjectConfig,
99
+ getGlobalConfig,
100
+ getProjectMcpServerDefinitions,
101
+ listConfigForCLI,
102
+ saveCurrentProjectConfig,
103
+ saveGlobalConfig,
104
+ setConfigForCLI,
105
+ validateAndRepairAllGPT5Profiles
106
+ } from "./chunk-DLSLSLTR.js";
107
+ import {
108
+ ConfigParseError
109
+ } from "./chunk-HIIHGKXP.js";
110
+ import {
111
+ debug,
112
+ initDebugLogger
113
+ } from "./chunk-Y4BQ36T4.js";
114
+ import {
115
+ BunShell,
116
+ CACHE_PATHS,
117
+ PRODUCT_COMMAND,
118
+ PRODUCT_NAME,
119
+ dateToFilename,
120
+ formatDate,
121
+ getCwd,
122
+ getNextAvailableLogForkNumber,
123
+ initSentry,
124
+ init_log,
125
+ init_product,
126
+ init_sentry,
127
+ init_shell,
128
+ init_state,
129
+ loadLogList,
130
+ logError,
131
+ parseLogFilename,
132
+ setCwd,
133
+ setOriginalCwd
134
+ } from "./chunk-SQGAHZPM.js";
135
+ import {
136
+ MACRO,
137
+ init_macros
138
+ } from "./chunk-UNCTVIS7.js";
139
+ import "./chunk-LWXT5RGE.js";
140
+ import "./chunk-M3TKNAUR.js";
141
+
142
+ // src/entrypoints/cli.tsx
143
+ init_sentry();
144
+
145
+ // src/entrypoints/cli/runCli.tsx
146
+ init_product();
147
+ import { existsSync, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
148
+
149
+ // src/entrypoints/cli/printMode.ts
150
+ init_log();
151
+
152
+ // src/entrypoints/cli/stdio/canUseTool.ts
153
+ function createStdioCanUseTool(args) {
154
+ if (args.normalizedPermissionPromptTool !== "stdio" || !args.structured) {
155
+ return args.hasPermissionsToUseTool;
156
+ }
157
+ return (async (tool, input, toolUseContext, assistantMessage) => {
158
+ const base = await args.hasPermissionsToUseTool(
159
+ tool,
160
+ input,
161
+ toolUseContext,
162
+ assistantMessage
163
+ );
164
+ if (base.result === true) return { result: true };
165
+ const denied = base;
166
+ if (denied.shouldPromptUser === false) {
167
+ return { result: false, message: denied.message };
168
+ }
169
+ try {
170
+ const blockedPath = typeof denied.blockedPath === "string" ? String(denied.blockedPath) : typeof input?.file_path === "string" ? String(input.file_path) : typeof input?.notebook_path === "string" ? String(input.notebook_path) : typeof input?.path === "string" ? String(input.path) : void 0;
171
+ const decisionReason = typeof denied.decisionReason === "string" ? String(denied.decisionReason) : void 0;
172
+ const response = await args.structured.sendRequest(
173
+ {
174
+ subtype: "can_use_tool",
175
+ tool_name: tool.name,
176
+ input,
177
+ ...typeof toolUseContext?.toolUseId === "string" && toolUseContext.toolUseId ? { tool_use_id: toolUseContext.toolUseId } : {},
178
+ ...typeof toolUseContext?.agentId === "string" && toolUseContext.agentId ? { agent_id: toolUseContext.agentId } : {},
179
+ ...Array.isArray(denied.suggestions) ? {
180
+ permission_suggestions: denied.suggestions
181
+ } : {},
182
+ ...blockedPath ? { blocked_path: blockedPath } : {},
183
+ ...decisionReason ? { decision_reason: decisionReason } : {}
184
+ },
185
+ {
186
+ signal: toolUseContext.abortController.signal,
187
+ timeoutMs: args.permissionTimeoutMs
188
+ }
189
+ );
190
+ if (response && response.behavior === "allow") {
191
+ const updatedInput = response.updatedInput && typeof response.updatedInput === "object" ? response.updatedInput : null;
192
+ if (updatedInput) {
193
+ Object.assign(input, updatedInput);
194
+ }
195
+ const updatedPermissionsRaw = response.updatedPermissions;
196
+ const updatedPermissions = Array.isArray(updatedPermissionsRaw) && updatedPermissionsRaw.every(
197
+ (u) => u && typeof u === "object" && typeof u.type === "string"
198
+ ) ? updatedPermissionsRaw : null;
199
+ if (updatedPermissions && args.printOptions.toolPermissionContext) {
200
+ const next = args.applyToolPermissionContextUpdates(
201
+ args.printOptions.toolPermissionContext,
202
+ updatedPermissions
203
+ );
204
+ args.printOptions.toolPermissionContext = next;
205
+ if (toolUseContext?.options) {
206
+ toolUseContext.options.toolPermissionContext = next;
207
+ }
208
+ for (const update of updatedPermissions) {
209
+ args.persistToolPermissionUpdateToDisk({
210
+ update,
211
+ projectDir: args.cwd
212
+ });
213
+ }
214
+ }
215
+ return { result: true };
216
+ }
217
+ if (response && response.behavior === "deny") {
218
+ if (response.interrupt === true) {
219
+ toolUseContext.abortController.abort();
220
+ }
221
+ }
222
+ return {
223
+ result: false,
224
+ message: typeof response?.message === "string" ? String(response.message) : denied.message
225
+ };
226
+ } catch (e) {
227
+ const msg = e instanceof Error ? e.message : String(e);
228
+ return {
229
+ result: false,
230
+ message: `Permission prompt failed: ${msg}`,
231
+ shouldPromptUser: false
232
+ };
233
+ }
234
+ });
235
+ }
236
+
237
+ // src/entrypoints/cli/stdio/controlRequestHandler.ts
238
+ function createPrintModeControlRequestHandler(args) {
239
+ return async (msg) => {
240
+ const subtype = msg.request?.subtype;
241
+ if (subtype === "initialize") {
242
+ return;
243
+ }
244
+ if (subtype === "set_permission_mode") {
245
+ const mode = msg.request?.mode;
246
+ if (mode === "default" || mode === "acceptEdits" || mode === "plan" || mode === "dontAsk" || mode === "bypassPermissions") {
247
+ if (args.printOptions.toolPermissionContext) {
248
+ args.printOptions.toolPermissionContext.mode = mode;
249
+ }
250
+ }
251
+ return;
252
+ }
253
+ if (subtype === "set_model") {
254
+ const requested = msg.request?.model;
255
+ if (requested === "default") {
256
+ args.printOptions.model = void 0;
257
+ } else if (typeof requested === "string" && requested.trim()) {
258
+ args.printOptions.model = requested.trim();
259
+ }
260
+ return;
261
+ }
262
+ if (subtype === "set_max_thinking_tokens") {
263
+ const value = msg.request?.max_thinking_tokens;
264
+ if (value === null) {
265
+ args.printOptions.maxThinkingTokens = 0;
266
+ } else if (typeof value === "number" && Number.isFinite(value) && value >= 0) {
267
+ args.printOptions.maxThinkingTokens = value;
268
+ }
269
+ return;
270
+ }
271
+ if (subtype === "mcp_status") {
272
+ return {
273
+ mcpServers: args.mcpClients.map((c) => ({
274
+ name: c.name,
275
+ status: c.type,
276
+ ...c.type === "connected" && c.capabilities ? { serverInfo: c.capabilities } : {}
277
+ }))
278
+ };
279
+ }
280
+ if (subtype === "mcp_message") {
281
+ const serverName = msg.request?.server_name;
282
+ const message = msg.request?.message;
283
+ if (typeof serverName === "string" && serverName) {
284
+ const found = args.mcpClients.find((c) => c.name === serverName);
285
+ if (found && found.type === "connected") {
286
+ const transport = found.client?.transport;
287
+ if (transport && typeof transport.onmessage === "function") {
288
+ transport.onmessage(message);
289
+ }
290
+ }
291
+ }
292
+ return;
293
+ }
294
+ if (subtype === "mcp_set_servers") {
295
+ return { ok: true, sdkServersChanged: false };
296
+ }
297
+ if (subtype === "rewind_files") {
298
+ throw new Error("rewind_files is not supported in Danya yet.");
299
+ }
300
+ throw new Error(`Unsupported control request subtype: ${String(subtype)}`);
301
+ };
302
+ }
303
+
304
+ // src/entrypoints/cli/stdio/streamJsonSession.ts
305
+ async function runPrintModeStreamJsonSession(args) {
306
+ const { runDanyaAgentStreamJsonSession } = await import("./kodeAgentStreamJsonSession-G4RBNZRN.js");
307
+ await runDanyaAgentStreamJsonSession(args);
308
+ }
309
+
310
+ // src/entrypoints/cli/stdio/structuredStdio.ts
311
+ function createPrintModeStructuredStdio(args) {
312
+ if (!args.enabled) return null;
313
+ return new DanyaAgentStructuredStdio(args.stdin, args.stdout, {
314
+ onInterrupt: args.onInterrupt,
315
+ onControlRequest: args.onControlRequest
316
+ });
317
+ }
318
+
319
+ // src/entrypoints/cli/printMode.ts
320
+ async function runPrintMode({
321
+ prompt,
322
+ stdinContent,
323
+ inputPrompt,
324
+ cwd: cwd2,
325
+ safe,
326
+ verbose,
327
+ outputFormat,
328
+ inputFormat,
329
+ jsonSchema,
330
+ permissionPromptTool,
331
+ replayUserMessages,
332
+ cliTools,
333
+ tools,
334
+ commands,
335
+ ask,
336
+ initialMessages,
337
+ sessionPersistence,
338
+ systemPromptOverride,
339
+ appendSystemPrompt,
340
+ disableSlashCommands,
341
+ allowedTools,
342
+ disallowedTools,
343
+ addDir,
344
+ permissionMode,
345
+ dangerouslySkipPermissions,
346
+ allowDangerouslySkipPermissions,
347
+ model,
348
+ mcpClients
349
+ }) {
350
+ const normalizedOutputFormat = String(outputFormat || "text").toLowerCase().trim();
351
+ const normalizedInputFormat = String(inputFormat || "text").toLowerCase().trim();
352
+ if (!["text", "stream-json"].includes(normalizedInputFormat)) {
353
+ console.error(
354
+ `Error: Invalid --input-format "${inputFormat}". Expected one of: text, stream-json`
355
+ );
356
+ process.exit(1);
357
+ }
358
+ if (!["text", "json", "stream-json"].includes(normalizedOutputFormat)) {
359
+ console.error(
360
+ `Error: Invalid --output-format "${outputFormat}". Expected one of: text, json, stream-json`
361
+ );
362
+ process.exit(1);
363
+ }
364
+ if (normalizedOutputFormat === "stream-json" && !verbose) {
365
+ console.error(
366
+ "Error: When using --print, --output-format=stream-json requires --verbose"
367
+ );
368
+ process.exit(1);
369
+ }
370
+ const normalizedPermissionPromptTool = permissionPromptTool ? String(permissionPromptTool).trim() : null;
371
+ if (normalizedPermissionPromptTool) {
372
+ if (normalizedPermissionPromptTool !== "stdio") {
373
+ console.error(
374
+ `Error: Unsupported --permission-prompt-tool "${normalizedPermissionPromptTool}". Only "stdio" is supported in Danya right now.`
375
+ );
376
+ process.exit(1);
377
+ }
378
+ if (normalizedInputFormat !== "stream-json") {
379
+ console.error(
380
+ "Error: --permission-prompt-tool=stdio requires --input-format=stream-json"
381
+ );
382
+ process.exit(1);
383
+ }
384
+ if (normalizedOutputFormat !== "stream-json") {
385
+ console.error(
386
+ "Error: --permission-prompt-tool=stdio requires --output-format=stream-json"
387
+ );
388
+ process.exit(1);
389
+ }
390
+ }
391
+ if (normalizedInputFormat === "stream-json" && normalizedOutputFormat !== "stream-json") {
392
+ console.error(
393
+ "Error: --input-format=stream-json requires --output-format=stream-json"
394
+ );
395
+ process.exit(1);
396
+ }
397
+ if (replayUserMessages) {
398
+ if (normalizedInputFormat !== "stream-json" || normalizedOutputFormat !== "stream-json") {
399
+ console.error(
400
+ "Error: --replay-user-messages requires --input-format=stream-json and --output-format=stream-json"
401
+ );
402
+ process.exit(1);
403
+ }
404
+ }
405
+ if (normalizedInputFormat === "stream-json") {
406
+ if (prompt) {
407
+ console.error(
408
+ "Error: --input-format=stream-json cannot be used with a prompt argument"
409
+ );
410
+ process.exit(1);
411
+ }
412
+ if (stdinContent) {
413
+ console.error(
414
+ "Error: --input-format=stream-json cannot be used with stdin prompt text"
415
+ );
416
+ process.exit(1);
417
+ }
418
+ } else {
419
+ if (!inputPrompt) {
420
+ console.error(
421
+ "Error: Input must be provided either through stdin or as a prompt argument when using --print"
422
+ );
423
+ process.exit(1);
424
+ }
425
+ }
426
+ const toolsForPrint = (() => {
427
+ if (!cliTools) return tools;
428
+ const raw = Array.isArray(cliTools) ? cliTools : [cliTools];
429
+ const flattened = raw.flatMap((v) => String(v ?? "").split(",")).map((v) => v.trim());
430
+ if (flattened.length === 0) return tools;
431
+ if (flattened.length === 1 && flattened[0] === "") return [];
432
+ if (flattened.length === 1 && flattened[0] === "default") return tools;
433
+ const wanted = new Set(flattened.filter((v) => v && v !== "default"));
434
+ const unknown = [...wanted].filter(
435
+ (name) => !tools.some((t) => t.name === name)
436
+ );
437
+ if (unknown.length > 0) {
438
+ console.error(`Error: Unknown tool(s) in --tools: ${unknown.join(", ")}`);
439
+ process.exit(1);
440
+ }
441
+ return tools.filter((t) => wanted.has(t.name));
442
+ })();
443
+ if (normalizedOutputFormat === "text") {
444
+ addToHistory(inputPrompt);
445
+ const { resultText: response } = await ask({
446
+ commands,
447
+ hasPermissionsToUseTool,
448
+ messageLogName: dateToFilename(/* @__PURE__ */ new Date()),
449
+ prompt: inputPrompt,
450
+ cwd: cwd2,
451
+ tools: toolsForPrint,
452
+ safeMode: safe,
453
+ initialMessages,
454
+ persistSession: sessionPersistence !== false
455
+ });
456
+ process.stdout.write(`${response}
457
+ `);
458
+ process.exit(0);
459
+ }
460
+ const { createUserMessage } = await import("./messages-N5KBI53P.js");
461
+ const { getSystemPrompt } = await import("./prompts-B2SS7CWI.js");
462
+ const { getContext: getContext2 } = await import("./context-FZ6G4J63.js");
463
+ const { getTotalCost } = await import("./costTracker-5WKZXN5S.js");
464
+ const { query } = await import("./query-HIK457UU.js");
465
+ const { getDanyaAgentSessionId } = await import("./kodeAgentSessionId-WUT74FSH.js");
466
+ const { danyaMessageToSdkMessage, makeSdkInitMessage, makeSdkResultMessage } = await import("./kodeAgentStreamJson-EDHHWNNX.js");
467
+ const { DanyaAgentStructuredStdio: DanyaAgentStructuredStdio2 } = await import("./kodeAgentStructuredStdio-UA5P5UNU.js");
468
+ const {
469
+ loadToolPermissionContextFromDisk,
470
+ persistToolPermissionUpdateToDisk
471
+ } = await import("./toolPermissionSettings-PT65MQIQ.js");
472
+ const { applyToolPermissionContextUpdates } = await import("./toolPermissionContext-DHAGUPEW.js");
473
+ const sessionIdForSdk = getDanyaAgentSessionId();
474
+ const startedAt = Date.now();
475
+ const sdkMessages = [];
476
+ const baseSystemPrompt = typeof systemPromptOverride === "string" && systemPromptOverride.trim() ? [systemPromptOverride] : await getSystemPrompt({ disableSlashCommands });
477
+ const systemPrompt = typeof appendSystemPrompt === "string" && appendSystemPrompt.trim() ? [...baseSystemPrompt, appendSystemPrompt] : baseSystemPrompt;
478
+ const normalizedJsonSchema = typeof jsonSchema === "string" ? jsonSchema.trim() : "";
479
+ const parsedJsonSchema = (() => {
480
+ if (!normalizedJsonSchema) return null;
481
+ try {
482
+ const parsed = JSON.parse(normalizedJsonSchema);
483
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
484
+ throw new Error("Schema must be a JSON object");
485
+ }
486
+ return parsed;
487
+ } catch (error) {
488
+ const msg = error instanceof Error ? error.message : String(error);
489
+ console.error(`Error: Invalid --json-schema: ${msg}`);
490
+ process.exit(1);
491
+ }
492
+ })();
493
+ if (parsedJsonSchema) {
494
+ systemPrompt.push(
495
+ [
496
+ "You MUST respond with ONLY valid JSON.",
497
+ "The JSON MUST validate against the following JSON Schema.",
498
+ "Do not wrap the JSON in markdown code fences and do not add extra commentary.",
499
+ "",
500
+ `<json_schema>${JSON.stringify(parsedJsonSchema)}</json_schema>`
501
+ ].join("\n")
502
+ );
503
+ }
504
+ const ctx = await getContext2();
505
+ const isBypassAvailable = !safe || Boolean(allowDangerouslySkipPermissions) || Boolean(dangerouslySkipPermissions);
506
+ let toolPermissionContext = loadToolPermissionContextFromDisk({
507
+ projectDir: cwd2,
508
+ includeDanyaProjectConfig: true,
509
+ isBypassPermissionsModeAvailable: isBypassAvailable
510
+ });
511
+ const cliRuleList = (value) => {
512
+ if (!value) return [];
513
+ const raw = Array.isArray(value) ? value : [value];
514
+ return raw.flatMap((v) => String(v ?? "").split(",")).map((v) => v.trim()).filter(Boolean);
515
+ };
516
+ const allowedRules = cliRuleList(allowedTools);
517
+ const deniedRules = cliRuleList(disallowedTools);
518
+ const additionalDirs = cliRuleList(addDir);
519
+ const updates = [];
520
+ if (allowedRules.length > 0) {
521
+ updates.push({
522
+ type: "addRules",
523
+ destination: "cliArg",
524
+ behavior: "allow",
525
+ rules: allowedRules
526
+ });
527
+ }
528
+ if (deniedRules.length > 0) {
529
+ updates.push({
530
+ type: "addRules",
531
+ destination: "cliArg",
532
+ behavior: "deny",
533
+ rules: deniedRules
534
+ });
535
+ }
536
+ if (additionalDirs.length > 0) {
537
+ updates.push({
538
+ type: "addDirectories",
539
+ destination: "cliArg",
540
+ directories: additionalDirs
541
+ });
542
+ }
543
+ const normalizedPermissionMode = typeof permissionMode === "string" ? permissionMode.trim() : "";
544
+ if (normalizedPermissionMode) {
545
+ const normalized = normalizedPermissionMode === "delegate" ? "default" : normalizedPermissionMode;
546
+ const allowed = /* @__PURE__ */ new Set([
547
+ "acceptEdits",
548
+ "bypassPermissions",
549
+ "default",
550
+ "dontAsk",
551
+ "plan"
552
+ ]);
553
+ if (!allowed.has(normalized)) {
554
+ console.error(
555
+ `Error: Invalid --permission-mode "${normalizedPermissionMode}". Expected one of: acceptEdits, bypassPermissions, default, delegate, dontAsk, plan`
556
+ );
557
+ process.exit(1);
558
+ }
559
+ updates.push({
560
+ type: "setMode",
561
+ destination: "cliArg",
562
+ mode: normalized
563
+ });
564
+ }
565
+ if (dangerouslySkipPermissions) {
566
+ updates.push({
567
+ type: "setMode",
568
+ destination: "cliArg",
569
+ mode: "bypassPermissions"
570
+ });
571
+ }
572
+ if (updates.length > 0) {
573
+ toolPermissionContext = applyToolPermissionContextUpdates(
574
+ toolPermissionContext,
575
+ updates
576
+ );
577
+ }
578
+ const printOptions = {
579
+ commands,
580
+ tools: toolsForPrint,
581
+ verbose: true,
582
+ safeMode: safe,
583
+ forkNumber: 0,
584
+ messageLogName: "unused",
585
+ maxThinkingTokens: 0,
586
+ persistSession: sessionPersistence !== false,
587
+ toolPermissionContext,
588
+ mcpClients,
589
+ shouldAvoidPermissionPrompts: normalizedInputFormat !== "stream-json",
590
+ model: typeof model === "string" && model.trim() ? model.trim() : void 0
591
+ };
592
+ const availableTools = toolsForPrint.map((t) => t.name);
593
+ const slashCommands = disableSlashCommands === true ? void 0 : commands.filter((c) => !c.isHidden).map((c) => `/${c.userFacingName()}`);
594
+ const initMsg = makeSdkInitMessage({
595
+ sessionId: sessionIdForSdk,
596
+ cwd: cwd2,
597
+ tools: availableTools,
598
+ slashCommands
599
+ });
600
+ const writeSdkLine = (obj) => {
601
+ process.stdout.write(JSON.stringify(obj) + "\n");
602
+ };
603
+ if (normalizedOutputFormat === "stream-json") {
604
+ writeSdkLine(initMsg);
605
+ } else {
606
+ sdkMessages.push(initMsg);
607
+ }
608
+ let activeTurnAbortController = null;
609
+ const structured = createPrintModeStructuredStdio({
610
+ enabled: normalizedInputFormat === "stream-json",
611
+ stdin: process.stdin,
612
+ stdout: process.stdout,
613
+ onInterrupt: () => {
614
+ activeTurnAbortController?.abort();
615
+ },
616
+ onControlRequest: createPrintModeControlRequestHandler({
617
+ printOptions,
618
+ mcpClients
619
+ })
620
+ });
621
+ if (structured) structured.start();
622
+ const permissionTimeoutMs = (() => {
623
+ const raw = process.env.DANYA_STDIO_PERMISSION_TIMEOUT_MS ?? process.env.KODE_STDIO_PERMISSION_TIMEOUT_MS;
624
+ const n = raw ? Number(raw) : NaN;
625
+ return Number.isFinite(n) && n > 0 ? n : 3e4;
626
+ })();
627
+ const canUseTool = createStdioCanUseTool({
628
+ normalizedPermissionPromptTool,
629
+ structured,
630
+ permissionTimeoutMs,
631
+ cwd: cwd2,
632
+ printOptions,
633
+ hasPermissionsToUseTool,
634
+ applyToolPermissionContextUpdates,
635
+ persistToolPermissionUpdateToDisk
636
+ });
637
+ if (normalizedInputFormat === "stream-json") {
638
+ if (!structured) {
639
+ console.error("Error: Structured stdin is not available");
640
+ process.exit(1);
641
+ }
642
+ await runPrintModeStreamJsonSession({
643
+ structured,
644
+ query,
645
+ writeSdkLine,
646
+ sessionId: sessionIdForSdk,
647
+ systemPrompt,
648
+ jsonSchema: parsedJsonSchema,
649
+ context: ctx,
650
+ canUseTool,
651
+ toolUseContextBase: {
652
+ options: printOptions,
653
+ messageId: void 0,
654
+ readFileTimestamps: {},
655
+ setToolJSX: () => {
656
+ }
657
+ },
658
+ replayUserMessages: Boolean(replayUserMessages),
659
+ getTotalCostUsd: () => getTotalCost(),
660
+ onActiveTurnAbortControllerChanged: (controller) => {
661
+ activeTurnAbortController = controller;
662
+ },
663
+ initialMessages
664
+ });
665
+ process.exit(0);
666
+ }
667
+ const abortController = new AbortController();
668
+ const userMsg = await (async () => {
669
+ if (normalizedInputFormat !== "stream-json") {
670
+ addToHistory(inputPrompt);
671
+ return createUserMessage(inputPrompt);
672
+ }
673
+ if (!structured) {
674
+ console.error("Error: Structured stdin is not available");
675
+ process.exit(1);
676
+ }
677
+ const sdkUser2 = await structured.nextUserMessage({
678
+ signal: abortController.signal,
679
+ timeoutMs: 3e4
680
+ });
681
+ if (!sdkUser2 || typeof sdkUser2 !== "object") {
682
+ console.error("Error: Invalid stream-json input (missing user message)");
683
+ process.exit(1);
684
+ }
685
+ const sdkMessage = sdkUser2.message;
686
+ const sdkContent = sdkMessage?.content;
687
+ if (typeof sdkContent !== "string" && !Array.isArray(sdkContent)) {
688
+ console.error("Error: Invalid stream-json user message content");
689
+ process.exit(1);
690
+ }
691
+ const m = createUserMessage(sdkContent);
692
+ if (typeof sdkUser2.uuid === "string" && sdkUser2.uuid) {
693
+ ;
694
+ m.uuid = String(sdkUser2.uuid);
695
+ }
696
+ return m;
697
+ })();
698
+ const baseMessages = [...initialMessages ?? [], userMsg];
699
+ const sdkUser = danyaMessageToSdkMessage(userMsg, sessionIdForSdk);
700
+ if (sdkUser) {
701
+ if (normalizedOutputFormat === "stream-json") {
702
+ writeSdkLine(sdkUser);
703
+ } else {
704
+ sdkMessages.push(sdkUser);
705
+ }
706
+ }
707
+ let lastAssistant = null;
708
+ let queryError = null;
709
+ try {
710
+ for await (const m of query(baseMessages, systemPrompt, ctx, canUseTool, {
711
+ options: printOptions,
712
+ abortController,
713
+ messageId: void 0,
714
+ readFileTimestamps: {},
715
+ setToolJSX: () => {
716
+ }
717
+ })) {
718
+ if (m.type === "assistant") lastAssistant = m;
719
+ const sdk = danyaMessageToSdkMessage(m, sessionIdForSdk);
720
+ if (!sdk) continue;
721
+ if (normalizedOutputFormat === "stream-json") {
722
+ writeSdkLine(sdk);
723
+ } else {
724
+ sdkMessages.push(sdk);
725
+ }
726
+ }
727
+ } catch (e) {
728
+ abortController.abort();
729
+ queryError = e;
730
+ }
731
+ const textFromAssistant = lastAssistant?.message?.content?.find(
732
+ (c) => c.type === "text"
733
+ )?.text;
734
+ let text = typeof textFromAssistant === "string" ? textFromAssistant : queryError instanceof Error ? queryError.message : queryError ? String(queryError) : "";
735
+ let structuredOutput;
736
+ if (parsedJsonSchema && !queryError) {
737
+ try {
738
+ const raw = typeof textFromAssistant === "string" ? textFromAssistant : "";
739
+ const fenced = raw.trim();
740
+ const unfenced = (() => {
741
+ const m = fenced.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```$/i);
742
+ return m ? m[1].trim() : fenced;
743
+ })();
744
+ const parsed = JSON.parse(unfenced);
745
+ const Ajv = (await import("ajv")).default;
746
+ const ajv = new Ajv({ allErrors: true, strict: false });
747
+ const validate = ajv.compile(parsedJsonSchema);
748
+ const ok = validate(parsed);
749
+ if (!ok) {
750
+ const errorText = typeof ajv.errorsText === "function" ? ajv.errorsText(validate.errors, { separator: "; " }) : JSON.stringify(validate.errors ?? []);
751
+ throw new Error(
752
+ `Structured output failed JSON schema validation: ${errorText}`
753
+ );
754
+ }
755
+ if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
756
+ throw new Error("Structured output must be a JSON object");
757
+ }
758
+ structuredOutput = parsed;
759
+ } catch (e) {
760
+ const msg = e instanceof Error ? e.message : String(e);
761
+ queryError = new Error(msg);
762
+ text = msg;
763
+ }
764
+ }
765
+ const usage = lastAssistant?.message?.usage;
766
+ const totalCostUsd = getTotalCost();
767
+ const durationMs = Date.now() - startedAt;
768
+ const resultMsg = makeSdkResultMessage({
769
+ sessionId: sessionIdForSdk,
770
+ result: String(text),
771
+ structuredOutput,
772
+ numTurns: 1,
773
+ usage,
774
+ totalCostUsd,
775
+ durationMs,
776
+ durationApiMs: 0,
777
+ isError: Boolean(queryError)
778
+ });
779
+ if (normalizedOutputFormat === "stream-json") {
780
+ writeSdkLine(resultMsg);
781
+ process.exit(0);
782
+ }
783
+ sdkMessages.push(resultMsg);
784
+ if (verbose) {
785
+ process.stdout.write(`${JSON.stringify(sdkMessages, null, 2)}
786
+ `);
787
+ } else {
788
+ process.stdout.write(`${JSON.stringify(resultMsg, null, 2)}
789
+ `);
790
+ }
791
+ process.exit(0);
792
+ }
793
+
794
+ // src/utils/session/cleanup.ts
795
+ init_log();
796
+ import { promises as fs } from "fs";
797
+ import { join } from "path";
798
+ var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
799
+ function convertFileNameToDate(filename) {
800
+ const isoStr = filename.split(".")[0].replace(/T(\d{2})-(\d{2})-(\d{2})-(\d{3})Z/, "T$1:$2:$3.$4Z");
801
+ return new Date(isoStr);
802
+ }
803
+ async function cleanupOldMessageFiles() {
804
+ const messagePath = CACHE_PATHS.messages();
805
+ const errorPath = CACHE_PATHS.errors();
806
+ const thirtyDaysAgo = new Date(Date.now() - THIRTY_DAYS_MS);
807
+ const deletedCounts = { messages: 0, errors: 0 };
808
+ for (const path of [messagePath, errorPath]) {
809
+ try {
810
+ const files = await fs.readdir(path);
811
+ for (const file of files) {
812
+ try {
813
+ const timestamp = convertFileNameToDate(file);
814
+ if (timestamp < thirtyDaysAgo) {
815
+ await fs.unlink(join(path, file));
816
+ if (path === messagePath) {
817
+ deletedCounts.messages++;
818
+ } else {
819
+ deletedCounts.errors++;
820
+ }
821
+ }
822
+ } catch (error) {
823
+ logError(
824
+ `Failed to process file ${file}: ${error instanceof Error ? error.message : String(error)}`
825
+ );
826
+ }
827
+ }
828
+ } catch (error) {
829
+ if (error instanceof Error && "code" in error && error.code !== "ENOENT") {
830
+ logError(
831
+ `Failed to cleanup directory ${path}: ${error instanceof Error ? error.message : String(error)}`
832
+ );
833
+ }
834
+ }
835
+ }
836
+ return deletedCounts;
837
+ }
838
+ function cleanupOldMessageFilesInBackground() {
839
+ const immediate = setImmediate(cleanupOldMessageFiles);
840
+ immediate.unref();
841
+ }
842
+
843
+ // src/entrypoints/cli/setup.ts
844
+ init_state();
845
+ async function setup(cwd2, safeMode) {
846
+ if (cwd2 !== process.cwd()) {
847
+ setOriginalCwd(cwd2);
848
+ }
849
+ await setCwd(cwd2);
850
+ grantReadPermissionForOriginalDir();
851
+ let agentLoader;
852
+ try {
853
+ agentLoader = await import("./loader-LJX77EFL.js");
854
+ } catch {
855
+ agentLoader = await import("./loader-LJX77EFL.js");
856
+ }
857
+ const { startAgentWatcher } = agentLoader;
858
+ await startAgentWatcher(() => {
859
+ debug.info("AGENTS_HOT_RELOADED", { ok: true });
860
+ });
861
+ if (safeMode) {
862
+ if (process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0) {
863
+ console.error(
864
+ `--safe mode cannot be used with root/sudo privileges for security reasons`
865
+ );
866
+ process.exit(1);
867
+ }
868
+ }
869
+ if (process.env.NODE_ENV === "test") {
870
+ return;
871
+ }
872
+ cleanupOldMessageFilesInBackground();
873
+ getContext();
874
+ const projectConfig = getCurrentProjectConfig();
875
+ if (projectConfig.lastCost !== void 0 && projectConfig.lastDuration !== void 0) {
876
+ }
877
+ }
878
+
879
+ // src/entrypoints/cli/setupScreens.tsx
880
+ init_macros();
881
+ import React6 from "react";
882
+
883
+ // src/ui/components/TrustDialog.tsx
884
+ import React from "react";
885
+ import { Box, Text, useInput } from "ink";
886
+ init_product();
887
+ init_state();
888
+ import { homedir } from "os";
889
+ function TrustDialog({ onDone }) {
890
+ const theme = getTheme();
891
+ React.useEffect(() => {
892
+ }, []);
893
+ function onChange(value) {
894
+ const config = getCurrentProjectConfig();
895
+ switch (value) {
896
+ case "yes": {
897
+ const isHomeDir = homedir() === getCwd();
898
+ if (!isHomeDir) {
899
+ saveCurrentProjectConfig({
900
+ ...config,
901
+ hasTrustDialogAccepted: true
902
+ });
903
+ }
904
+ onDone();
905
+ break;
906
+ }
907
+ case "no": {
908
+ process.exit(1);
909
+ break;
910
+ }
911
+ }
912
+ }
913
+ const exitState = useExitOnCtrlCD(() => process.exit(0));
914
+ useInput((_input, key) => {
915
+ if (key.escape) {
916
+ process.exit(0);
917
+ return;
918
+ }
919
+ });
920
+ return /* @__PURE__ */ React.createElement(React.Fragment, null, /* @__PURE__ */ React.createElement(
921
+ Box,
922
+ {
923
+ flexDirection: "column",
924
+ gap: 1,
925
+ padding: 1,
926
+ borderStyle: "round",
927
+ borderColor: theme.warning
928
+ },
929
+ /* @__PURE__ */ React.createElement(Text, { bold: true, color: theme.warning }, "Do you trust the files in this folder?"),
930
+ /* @__PURE__ */ React.createElement(Text, { bold: true }, process.cwd()),
931
+ /* @__PURE__ */ React.createElement(Box, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React.createElement(Text, null, PRODUCT_NAME, " may read files in this folder. Reading untrusted files may lead to ", PRODUCT_NAME, " to behave in an unexpected ways."), /* @__PURE__ */ React.createElement(Text, null, "With your permission ", PRODUCT_NAME, " may execute files in this folder. Executing untrusted code is unsafe.")),
932
+ /* @__PURE__ */ React.createElement(
933
+ Select,
934
+ {
935
+ options: [
936
+ { label: "Yes, proceed", value: "yes" },
937
+ { label: "No, exit", value: "no" }
938
+ ],
939
+ onChange: (value) => onChange(value)
940
+ }
941
+ )
942
+ ), /* @__PURE__ */ React.createElement(Box, { marginLeft: 3 }, /* @__PURE__ */ React.createElement(Text, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React.createElement(React.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React.createElement(React.Fragment, null, "Enter to confirm \xB7 Esc to exit"))));
943
+ }
944
+
945
+ // src/ui/screens/MCPServerApproval.tsx
946
+ import React5 from "react";
947
+ import { render } from "ink";
948
+
949
+ // src/ui/components/MCPServerMultiselectDialog.tsx
950
+ import React3 from "react";
951
+ import { Box as Box2, Text as Text3, useInput as useInput2 } from "ink";
952
+ import { MultiSelect } from "@inkjs/ui";
953
+ import { partition } from "lodash-es";
954
+
955
+ // src/ui/components/MCPServerDialogCopy.tsx
956
+ init_product();
957
+ import React2 from "react";
958
+ import { Text as Text2 } from "ink";
959
+ import Link from "ink-link";
960
+ function MCPServerDialogCopy() {
961
+ return /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(Text2, null, "MCP servers provide additional functionality to ", PRODUCT_NAME, ". They may execute code, make network requests, or access system resources via tool calls. All tool calls will require your explicit approval before execution. For more information, see", " ", /* @__PURE__ */ React2.createElement(Link, { url: "https://github.com/shareAI-lab/kode/blob/main/docs/mcp.md" }, "MCP documentation")), /* @__PURE__ */ React2.createElement(Text2, { dimColor: true }, "Remember: You can always change these choices later by running `", PRODUCT_COMMAND, " mcp reset-project-choices`"));
962
+ }
963
+
964
+ // src/ui/components/MCPServerMultiselectDialog.tsx
965
+ function MCPServerMultiselectDialog({
966
+ serverNames,
967
+ onDone
968
+ }) {
969
+ const theme = getTheme();
970
+ function onSubmit(selectedServers) {
971
+ const config = getCurrentProjectConfig();
972
+ if (!config.approvedMcprcServers) {
973
+ config.approvedMcprcServers = [];
974
+ }
975
+ if (!config.rejectedMcprcServers) {
976
+ config.rejectedMcprcServers = [];
977
+ }
978
+ const [approvedServers, rejectedServers] = partition(
979
+ serverNames,
980
+ (server) => selectedServers.includes(server)
981
+ );
982
+ config.approvedMcprcServers.push(...approvedServers);
983
+ config.rejectedMcprcServers.push(...rejectedServers);
984
+ saveCurrentProjectConfig(config);
985
+ onDone();
986
+ }
987
+ const exitState = useExitOnCtrlCD(() => process.exit());
988
+ useInput2((_input, key) => {
989
+ if (key.escape) {
990
+ const config = getCurrentProjectConfig();
991
+ if (!config.rejectedMcprcServers) {
992
+ config.rejectedMcprcServers = [];
993
+ }
994
+ for (const server of serverNames) {
995
+ if (!config.rejectedMcprcServers.includes(server)) {
996
+ config.rejectedMcprcServers.push(server);
997
+ }
998
+ }
999
+ saveCurrentProjectConfig(config);
1000
+ onDone();
1001
+ return;
1002
+ }
1003
+ });
1004
+ return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(
1005
+ Box2,
1006
+ {
1007
+ flexDirection: "column",
1008
+ gap: 1,
1009
+ padding: 1,
1010
+ borderStyle: "round",
1011
+ borderColor: theme.warning
1012
+ },
1013
+ /* @__PURE__ */ React3.createElement(Text3, { bold: true, color: theme.warning }, "New MCP Servers Detected"),
1014
+ /* @__PURE__ */ React3.createElement(Text3, null, "This project contains an MCP config file (.mcp.json or .mcprc) with", " ", serverNames.length, " MCP servers that require your approval."),
1015
+ /* @__PURE__ */ React3.createElement(MCPServerDialogCopy, null),
1016
+ /* @__PURE__ */ React3.createElement(Text3, null, "Please select the servers you want to enable:"),
1017
+ /* @__PURE__ */ React3.createElement(
1018
+ MultiSelect,
1019
+ {
1020
+ options: serverNames.map((server) => ({
1021
+ label: server,
1022
+ value: server
1023
+ })),
1024
+ defaultValue: serverNames,
1025
+ onSubmit
1026
+ }
1027
+ )
1028
+ ), /* @__PURE__ */ React3.createElement(Box2, { marginLeft: 3 }, /* @__PURE__ */ React3.createElement(Text3, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React3.createElement(React3.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React3.createElement(React3.Fragment, null, "Space to select \xB7 Enter to confirm \xB7 Esc to reject all"))));
1029
+ }
1030
+
1031
+ // src/ui/components/MCPServerApprovalDialog.tsx
1032
+ import React4 from "react";
1033
+ import { Box as Box3, Text as Text4, useInput as useInput3 } from "ink";
1034
+ function MCPServerApprovalDialog({
1035
+ serverName,
1036
+ onDone
1037
+ }) {
1038
+ const theme = getTheme();
1039
+ function onChange(value) {
1040
+ const config = getCurrentProjectConfig();
1041
+ switch (value) {
1042
+ case "yes": {
1043
+ if (!config.approvedMcprcServers) {
1044
+ config.approvedMcprcServers = [];
1045
+ }
1046
+ if (!config.approvedMcprcServers.includes(serverName)) {
1047
+ config.approvedMcprcServers.push(serverName);
1048
+ }
1049
+ saveCurrentProjectConfig(config);
1050
+ onDone();
1051
+ break;
1052
+ }
1053
+ case "no": {
1054
+ if (!config.rejectedMcprcServers) {
1055
+ config.rejectedMcprcServers = [];
1056
+ }
1057
+ if (!config.rejectedMcprcServers.includes(serverName)) {
1058
+ config.rejectedMcprcServers.push(serverName);
1059
+ }
1060
+ saveCurrentProjectConfig(config);
1061
+ onDone();
1062
+ break;
1063
+ }
1064
+ }
1065
+ }
1066
+ const exitState = useExitOnCtrlCD(() => process.exit(0));
1067
+ useInput3((_input, key) => {
1068
+ if (key.escape) {
1069
+ onDone();
1070
+ return;
1071
+ }
1072
+ });
1073
+ return /* @__PURE__ */ React4.createElement(React4.Fragment, null, /* @__PURE__ */ React4.createElement(
1074
+ Box3,
1075
+ {
1076
+ flexDirection: "column",
1077
+ gap: 1,
1078
+ padding: 1,
1079
+ borderStyle: "round",
1080
+ borderColor: theme.warning
1081
+ },
1082
+ /* @__PURE__ */ React4.createElement(Text4, { bold: true, color: theme.warning }, "New MCP Server Detected"),
1083
+ /* @__PURE__ */ React4.createElement(Text4, null, "This project contains an MCP config file (.mcp.json or .mcprc) with an MCP server that requires your approval:"),
1084
+ /* @__PURE__ */ React4.createElement(Text4, { bold: true }, serverName),
1085
+ /* @__PURE__ */ React4.createElement(MCPServerDialogCopy, null),
1086
+ /* @__PURE__ */ React4.createElement(Text4, null, "Do you want to approve this MCP server?"),
1087
+ /* @__PURE__ */ React4.createElement(
1088
+ Select,
1089
+ {
1090
+ options: [
1091
+ { label: "Yes, approve this server", value: "yes" },
1092
+ { label: "No, reject this server", value: "no" }
1093
+ ],
1094
+ onChange: (value) => onChange(value)
1095
+ }
1096
+ )
1097
+ ), /* @__PURE__ */ React4.createElement(Box3, { marginLeft: 3 }, /* @__PURE__ */ React4.createElement(Text4, { dimColor: true }, exitState.pending ? /* @__PURE__ */ React4.createElement(React4.Fragment, null, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React4.createElement(React4.Fragment, null, "Enter to confirm \xB7 Esc to reject"))));
1098
+ }
1099
+
1100
+ // src/ui/screens/MCPServerApproval.tsx
1101
+ async function handleMcprcServerApprovals() {
1102
+ const { servers } = getProjectMcpServerDefinitions();
1103
+ const pendingServers = Object.keys(servers).filter(
1104
+ (serverName) => getMcprcServerStatus(serverName) === "pending"
1105
+ );
1106
+ if (pendingServers.length === 0) {
1107
+ return;
1108
+ }
1109
+ await new Promise((resolve) => {
1110
+ const clearScreenAndResolve = () => {
1111
+ process.stdout.write("\x1B[2J\x1B[3J\x1B[H", () => {
1112
+ resolve();
1113
+ });
1114
+ };
1115
+ if (pendingServers.length === 1 && pendingServers[0] !== void 0) {
1116
+ const result = render(
1117
+ /* @__PURE__ */ React5.createElement(
1118
+ MCPServerApprovalDialog,
1119
+ {
1120
+ serverName: pendingServers[0],
1121
+ onDone: () => {
1122
+ result.unmount?.();
1123
+ clearScreenAndResolve();
1124
+ }
1125
+ }
1126
+ ),
1127
+ { exitOnCtrlC: false }
1128
+ );
1129
+ } else {
1130
+ const result = render(
1131
+ /* @__PURE__ */ React5.createElement(
1132
+ MCPServerMultiselectDialog,
1133
+ {
1134
+ serverNames: pendingServers,
1135
+ onDone: () => {
1136
+ result.unmount?.();
1137
+ clearScreenAndResolve();
1138
+ }
1139
+ }
1140
+ ),
1141
+ { exitOnCtrlC: false }
1142
+ );
1143
+ }
1144
+ });
1145
+ }
1146
+
1147
+ // src/entrypoints/cli/setupScreens.tsx
1148
+ function completeOnboarding() {
1149
+ const config = getGlobalConfig();
1150
+ saveGlobalConfig({
1151
+ ...config,
1152
+ hasCompletedOnboarding: true,
1153
+ lastOnboardingVersion: MACRO.VERSION
1154
+ });
1155
+ }
1156
+ async function showSetupScreens(safeMode, print) {
1157
+ if (process.env.NODE_ENV === "test") {
1158
+ return;
1159
+ }
1160
+ const config = getGlobalConfig();
1161
+ if (!config.theme || !config.hasCompletedOnboarding) {
1162
+ await clearTerminal();
1163
+ const { render: render3 } = await import("ink");
1164
+ await new Promise((resolve) => {
1165
+ render3(
1166
+ /* @__PURE__ */ React6.createElement(
1167
+ Onboarding,
1168
+ {
1169
+ onDone: async () => {
1170
+ completeOnboarding();
1171
+ await clearTerminal();
1172
+ resolve();
1173
+ }
1174
+ }
1175
+ ),
1176
+ {
1177
+ exitOnCtrlC: false
1178
+ }
1179
+ );
1180
+ });
1181
+ }
1182
+ if (!print) {
1183
+ if (safeMode) {
1184
+ if (!checkHasTrustDialogAccepted()) {
1185
+ await new Promise((resolve) => {
1186
+ const onDone = () => {
1187
+ grantReadPermissionForOriginalDir();
1188
+ resolve();
1189
+ };
1190
+ (async () => {
1191
+ const { render: render3 } = await import("ink");
1192
+ render3(/* @__PURE__ */ React6.createElement(TrustDialog, { onDone }), {
1193
+ exitOnCtrlC: false
1194
+ });
1195
+ })();
1196
+ });
1197
+ }
1198
+ }
1199
+ await handleMcprcServerApprovals();
1200
+ }
1201
+ }
1202
+
1203
+ // src/entrypoints/cli/runCli.tsx
1204
+ import React10 from "react";
1205
+ import { ReadStream } from "tty";
1206
+ import { openSync } from "fs";
1207
+ import { Command } from "@commander-js/extra-typings";
1208
+ init_log();
1209
+ import { cwd } from "process";
1210
+
1211
+ // src/utils/model/modelConfigYaml.ts
1212
+ import yaml from "js-yaml";
1213
+ import { z } from "zod";
1214
+ var ApiKeySpecSchema = z.union([
1215
+ z.object({
1216
+ fromEnv: z.string().min(1)
1217
+ }).strict(),
1218
+ z.object({
1219
+ value: z.string()
1220
+ }).strict()
1221
+ ]);
1222
+ var ModelProfileYamlSchema = z.object({
1223
+ name: z.string().min(1),
1224
+ provider: z.string().min(1),
1225
+ modelName: z.string().min(1),
1226
+ baseURL: z.string().min(1).optional(),
1227
+ maxTokens: z.number().int().positive(),
1228
+ contextLength: z.number().int().positive(),
1229
+ reasoningEffort: z.string().optional(),
1230
+ isActive: z.boolean().optional(),
1231
+ apiKey: ApiKeySpecSchema.optional(),
1232
+ apiKeyEnv: z.string().min(1).optional(),
1233
+ createdAt: z.number().int().positive().optional(),
1234
+ lastUsed: z.number().int().positive().optional()
1235
+ }).strict();
1236
+ var ModelPointersYamlSchema = z.object({
1237
+ main: z.string().min(1).optional(),
1238
+ task: z.string().min(1).optional(),
1239
+ compact: z.string().min(1).optional(),
1240
+ quick: z.string().min(1).optional()
1241
+ }).strict().optional();
1242
+ var ModelConfigYamlSchema = z.object({
1243
+ version: z.number().int().positive().default(1),
1244
+ profiles: z.array(ModelProfileYamlSchema).default([]),
1245
+ pointers: ModelPointersYamlSchema
1246
+ }).strict();
1247
+ function suggestedApiKeyEnvForProvider(provider) {
1248
+ switch (provider) {
1249
+ case "anthropic":
1250
+ return "ANTHROPIC_API_KEY";
1251
+ case "openai":
1252
+ case "custom-openai":
1253
+ return "OPENAI_API_KEY";
1254
+ case "azure":
1255
+ return "AZURE_OPENAI_API_KEY";
1256
+ case "gemini":
1257
+ return "GEMINI_API_KEY";
1258
+ default:
1259
+ return void 0;
1260
+ }
1261
+ }
1262
+ function resolveApiKeyFromYaml(input, existingApiKey) {
1263
+ const warnings = [];
1264
+ if (input.apiKeyEnv) {
1265
+ const envValue = process.env[input.apiKeyEnv];
1266
+ if (envValue) return { apiKey: envValue, warnings };
1267
+ if (existingApiKey) return { apiKey: existingApiKey, warnings };
1268
+ warnings.push(`Missing env var '${input.apiKeyEnv}' for apiKey`);
1269
+ return { apiKey: "", warnings };
1270
+ }
1271
+ if (input.apiKey && "fromEnv" in input.apiKey) {
1272
+ const envValue = process.env[input.apiKey.fromEnv];
1273
+ if (envValue) return { apiKey: envValue, warnings };
1274
+ if (existingApiKey) return { apiKey: existingApiKey, warnings };
1275
+ warnings.push(`Missing env var '${input.apiKey.fromEnv}' for apiKey`);
1276
+ return { apiKey: "", warnings };
1277
+ }
1278
+ if (input.apiKey && "value" in input.apiKey) {
1279
+ return { apiKey: input.apiKey.value, warnings };
1280
+ }
1281
+ if (existingApiKey) return { apiKey: existingApiKey, warnings };
1282
+ warnings.push(
1283
+ "Missing apiKey (set apiKey.fromEnv, apiKeyEnv, or apiKey.value)"
1284
+ );
1285
+ return { apiKey: "", warnings };
1286
+ }
1287
+ function resolvePointerTarget(pointerValue, profiles) {
1288
+ if (profiles.some((p) => p.modelName === pointerValue)) return pointerValue;
1289
+ const byName = profiles.find((p) => p.name === pointerValue);
1290
+ return byName?.modelName ?? null;
1291
+ }
1292
+ function parseModelConfigYaml(yamlText) {
1293
+ const parsed = yaml.load(yamlText);
1294
+ return ModelConfigYamlSchema.parse(parsed);
1295
+ }
1296
+ function formatModelConfigYamlForSharing(config) {
1297
+ const modelProfiles = config.modelProfiles ?? [];
1298
+ const pointers = config.modelPointers;
1299
+ const exported = {
1300
+ version: 1,
1301
+ profiles: modelProfiles.map((p) => {
1302
+ const suggestedEnv = suggestedApiKeyEnvForProvider(p.provider);
1303
+ return {
1304
+ name: p.name,
1305
+ provider: p.provider,
1306
+ modelName: p.modelName,
1307
+ ...p.baseURL ? { baseURL: p.baseURL } : {},
1308
+ maxTokens: p.maxTokens,
1309
+ contextLength: p.contextLength,
1310
+ ...p.reasoningEffort ? { reasoningEffort: p.reasoningEffort } : {},
1311
+ isActive: p.isActive,
1312
+ createdAt: p.createdAt,
1313
+ ...typeof p.lastUsed === "number" ? { lastUsed: p.lastUsed } : {},
1314
+ apiKey: { fromEnv: suggestedEnv ?? "API_KEY" }
1315
+ };
1316
+ }),
1317
+ ...pointers ? { pointers } : {}
1318
+ };
1319
+ return yaml.dump(exported, {
1320
+ noRefs: true,
1321
+ lineWidth: 120
1322
+ });
1323
+ }
1324
+ function applyModelConfigYamlImport(existingConfig, yamlText, options = {}) {
1325
+ const parsed = parseModelConfigYaml(yamlText);
1326
+ const warnings = [];
1327
+ const existingProfiles = existingConfig.modelProfiles ?? [];
1328
+ const existingByModelName = new Map(
1329
+ existingProfiles.map((p) => [p.modelName, p])
1330
+ );
1331
+ const now = Date.now();
1332
+ const importedProfiles = parsed.profiles.map((profile) => {
1333
+ const existing = existingByModelName.get(profile.modelName);
1334
+ const resolved = resolveApiKeyFromYaml(
1335
+ { apiKey: profile.apiKey, apiKeyEnv: profile.apiKeyEnv },
1336
+ existing?.apiKey
1337
+ );
1338
+ warnings.push(...resolved.warnings.map((w) => `[${profile.modelName}] ${w}`));
1339
+ return {
1340
+ name: profile.name,
1341
+ provider: profile.provider,
1342
+ modelName: profile.modelName,
1343
+ ...profile.baseURL ? { baseURL: profile.baseURL } : {},
1344
+ apiKey: resolved.apiKey,
1345
+ maxTokens: profile.maxTokens,
1346
+ contextLength: profile.contextLength,
1347
+ ...profile.reasoningEffort ? { reasoningEffort: profile.reasoningEffort } : {},
1348
+ isActive: profile.isActive ?? true,
1349
+ createdAt: profile.createdAt ?? existing?.createdAt ?? now,
1350
+ ...profile.lastUsed ? { lastUsed: profile.lastUsed } : existing?.lastUsed ? { lastUsed: existing.lastUsed } : {},
1351
+ ...existing?.isGPT5 ? { isGPT5: existing.isGPT5 } : {},
1352
+ ...existing?.validationStatus ? { validationStatus: existing.validationStatus } : {},
1353
+ ...existing?.lastValidation ? { lastValidation: existing.lastValidation } : {}
1354
+ };
1355
+ });
1356
+ const mergedProfiles = options.replace ? importedProfiles : [
1357
+ ...existingProfiles.filter(
1358
+ (p) => !importedProfiles.some((i) => i.modelName === p.modelName)
1359
+ ),
1360
+ ...importedProfiles
1361
+ ];
1362
+ const nextPointers = {
1363
+ ...existingConfig.modelPointers ?? {
1364
+ main: "",
1365
+ task: "",
1366
+ compact: "",
1367
+ quick: ""
1368
+ }
1369
+ };
1370
+ if (parsed.pointers) {
1371
+ const resolvedMain = parsed.pointers.main && resolvePointerTarget(parsed.pointers.main, mergedProfiles);
1372
+ const resolvedTask = parsed.pointers.task && resolvePointerTarget(parsed.pointers.task, mergedProfiles);
1373
+ const resolvedCompact = parsed.pointers.compact && resolvePointerTarget(parsed.pointers.compact, mergedProfiles);
1374
+ const resolvedQuick = parsed.pointers.quick && resolvePointerTarget(parsed.pointers.quick, mergedProfiles);
1375
+ if (parsed.pointers.main && !resolvedMain) {
1376
+ warnings.push(
1377
+ `[pointers.main] Unknown model '${parsed.pointers.main}' (expected modelName or profile name)`
1378
+ );
1379
+ } else if (resolvedMain) {
1380
+ nextPointers.main = resolvedMain;
1381
+ }
1382
+ if (parsed.pointers.task && !resolvedTask) {
1383
+ warnings.push(
1384
+ `[pointers.task] Unknown model '${parsed.pointers.task}' (expected modelName or profile name)`
1385
+ );
1386
+ } else if (resolvedTask) {
1387
+ nextPointers.task = resolvedTask;
1388
+ }
1389
+ if (parsed.pointers.compact && !resolvedCompact) {
1390
+ warnings.push(
1391
+ `[pointers.compact] Unknown model '${parsed.pointers.compact}' (expected modelName or profile name)`
1392
+ );
1393
+ } else if (resolvedCompact) {
1394
+ nextPointers.compact = resolvedCompact;
1395
+ }
1396
+ if (parsed.pointers.quick && !resolvedQuick) {
1397
+ warnings.push(
1398
+ `[pointers.quick] Unknown model '${parsed.pointers.quick}' (expected modelName or profile name)`
1399
+ );
1400
+ } else if (resolvedQuick) {
1401
+ nextPointers.quick = resolvedQuick;
1402
+ }
1403
+ }
1404
+ return {
1405
+ nextConfig: {
1406
+ ...existingConfig,
1407
+ modelProfiles: mergedProfiles,
1408
+ modelPointers: nextPointers
1409
+ },
1410
+ warnings
1411
+ };
1412
+ }
1413
+
1414
+ // src/ui/screens/LogList.tsx
1415
+ init_log();
1416
+ import React8, { useEffect, useState } from "react";
1417
+
1418
+ // src/ui/components/LogSelector.tsx
1419
+ import React7 from "react";
1420
+ import { Box as Box4, Text as Text5 } from "ink";
1421
+ init_log();
1422
+ function LogSelector({
1423
+ logs,
1424
+ onSelect
1425
+ }) {
1426
+ const { rows, columns } = useTerminalSize();
1427
+ if (logs.length === 0) {
1428
+ return null;
1429
+ }
1430
+ const visibleCount = rows - 3;
1431
+ const hiddenCount = Math.max(0, logs.length - visibleCount);
1432
+ const indexWidth = 7;
1433
+ const modifiedWidth = 21;
1434
+ const createdWidth = 21;
1435
+ const countWidth = 9;
1436
+ const options = logs.map((log, i) => {
1437
+ const index = `[${i}]`.padEnd(indexWidth);
1438
+ const modified = formatDate(log.modified).padEnd(modifiedWidth);
1439
+ const created = formatDate(log.created).padEnd(createdWidth);
1440
+ const msgCount = `${log.messageCount}`.padStart(countWidth);
1441
+ const prompt = log.firstPrompt;
1442
+ let branchInfo = "";
1443
+ if (log.forkNumber) branchInfo += ` (fork #${log.forkNumber})`;
1444
+ if (log.sidechainNumber)
1445
+ branchInfo += ` (sidechain #${log.sidechainNumber})`;
1446
+ const labelTxt = `${index}${modified}${created}${msgCount} ${prompt}${branchInfo}`;
1447
+ const truncated = labelTxt.length > columns - 2 ? `${labelTxt.slice(0, columns - 5)}...` : labelTxt;
1448
+ return {
1449
+ label: truncated,
1450
+ value: log.value.toString()
1451
+ };
1452
+ });
1453
+ return /* @__PURE__ */ React7.createElement(Box4, { flexDirection: "column", height: "100%", width: "100%" }, /* @__PURE__ */ React7.createElement(Box4, { paddingLeft: 9 }, /* @__PURE__ */ React7.createElement(Text5, { bold: true, color: getTheme().text }, "Modified"), /* @__PURE__ */ React7.createElement(Text5, null, " "), /* @__PURE__ */ React7.createElement(Text5, { bold: true, color: getTheme().text }, "Created"), /* @__PURE__ */ React7.createElement(Text5, null, " "), /* @__PURE__ */ React7.createElement(Text5, { bold: true, color: getTheme().text }, "# Messages"), /* @__PURE__ */ React7.createElement(Text5, null, " "), /* @__PURE__ */ React7.createElement(Text5, { bold: true, color: getTheme().text }, "First message")), /* @__PURE__ */ React7.createElement(
1454
+ Select,
1455
+ {
1456
+ options,
1457
+ onChange: (index) => onSelect(parseInt(index, 10)),
1458
+ visibleOptionCount: visibleCount
1459
+ }
1460
+ ), hiddenCount > 0 && /* @__PURE__ */ React7.createElement(Box4, { paddingLeft: 2 }, /* @__PURE__ */ React7.createElement(Text5, { color: getTheme().secondaryText }, "and ", hiddenCount, " more\u2026")));
1461
+ }
1462
+
1463
+ // src/ui/screens/LogList.tsx
1464
+ init_log();
1465
+ init_log();
1466
+ function LogList({ context, type, logNumber }) {
1467
+ const [logs, setLogs] = useState([]);
1468
+ const [didSelectLog, setDidSelectLog] = useState(false);
1469
+ useEffect(() => {
1470
+ loadLogList(
1471
+ type === "messages" ? CACHE_PATHS.messages() : CACHE_PATHS.errors()
1472
+ ).then((logs2) => {
1473
+ if (logNumber !== void 0) {
1474
+ const log = logs2[logNumber >= 0 ? logNumber : 0];
1475
+ if (log) {
1476
+ console.log(JSON.stringify(log.messages, null, 2));
1477
+ process.exit(0);
1478
+ } else {
1479
+ console.error("No log found at index", logNumber);
1480
+ process.exit(1);
1481
+ }
1482
+ }
1483
+ setLogs(logs2);
1484
+ }).catch((error) => {
1485
+ logError(error);
1486
+ if (logNumber !== void 0) {
1487
+ process.exit(1);
1488
+ } else {
1489
+ context.unmount?.();
1490
+ }
1491
+ });
1492
+ }, [context, type, logNumber]);
1493
+ function onSelect(index) {
1494
+ const log = logs[index];
1495
+ if (!log) {
1496
+ return;
1497
+ }
1498
+ setDidSelectLog(true);
1499
+ setTimeout(() => {
1500
+ console.log(JSON.stringify(log.messages, null, 2));
1501
+ process.exit(0);
1502
+ }, 100);
1503
+ }
1504
+ if (logNumber !== void 0) {
1505
+ return null;
1506
+ }
1507
+ if (didSelectLog) {
1508
+ return null;
1509
+ }
1510
+ return /* @__PURE__ */ React8.createElement(LogSelector, { logs, onSelect });
1511
+ }
1512
+
1513
+ // src/entrypoints/mcp.ts
1514
+ init_state();
1515
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
1516
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
1517
+ import {
1518
+ CallToolRequestSchema,
1519
+ ListToolsRequestSchema
1520
+ } from "@modelcontextprotocol/sdk/types.js";
1521
+ import { zodToJsonSchema } from "zod-to-json-schema";
1522
+ init_log();
1523
+ init_macros();
1524
+ var state = {
1525
+ readFileTimestamps: {}
1526
+ };
1527
+ var MCP_COMMANDS = [review_default];
1528
+ var MCP_TOOLS = [...getAllTools()];
1529
+ async function startMCPServer(cwd2) {
1530
+ await setCwd(cwd2);
1531
+ const server = new Server(
1532
+ {
1533
+ name: "claude/tengu",
1534
+ version: MACRO.VERSION
1535
+ },
1536
+ {
1537
+ capabilities: {
1538
+ tools: {}
1539
+ }
1540
+ }
1541
+ );
1542
+ server.setRequestHandler(
1543
+ ListToolsRequestSchema,
1544
+ async () => {
1545
+ const tools = await Promise.all(
1546
+ MCP_TOOLS.map(async (tool) => ({
1547
+ ...tool,
1548
+ description: getToolDescription(tool),
1549
+ inputSchema: zodToJsonSchema(
1550
+ tool.inputSchema
1551
+ )
1552
+ }))
1553
+ );
1554
+ return {
1555
+ tools
1556
+ };
1557
+ }
1558
+ );
1559
+ server.setRequestHandler(
1560
+ CallToolRequestSchema,
1561
+ async (request) => {
1562
+ const { name, arguments: args } = request.params;
1563
+ const tool = MCP_TOOLS.find((_) => _.name === name);
1564
+ if (!tool) {
1565
+ throw new Error(`Tool ${name} not found`);
1566
+ }
1567
+ try {
1568
+ if (!await tool.isEnabled()) {
1569
+ throw new Error(`Tool ${name} is not enabled`);
1570
+ }
1571
+ const model = getModelManager().getModelName("main");
1572
+ const validationResult = await tool.validateInput?.(
1573
+ args ?? {},
1574
+ {
1575
+ abortController: new AbortController(),
1576
+ options: {
1577
+ commands: MCP_COMMANDS,
1578
+ tools: MCP_TOOLS,
1579
+ forkNumber: 0,
1580
+ messageLogName: "unused",
1581
+ maxThinkingTokens: 0
1582
+ },
1583
+ messageId: void 0,
1584
+ readFileTimestamps: state.readFileTimestamps
1585
+ }
1586
+ );
1587
+ if (validationResult && !validationResult.result) {
1588
+ throw new Error(
1589
+ `Tool ${name} input is invalid: ${validationResult.message}`
1590
+ );
1591
+ }
1592
+ const result = tool.call(args ?? {}, {
1593
+ abortController: new AbortController(),
1594
+ messageId: void 0,
1595
+ options: {
1596
+ commands: MCP_COMMANDS,
1597
+ tools: MCP_TOOLS,
1598
+ forkNumber: 0,
1599
+ messageLogName: "unused",
1600
+ maxThinkingTokens: 0
1601
+ },
1602
+ readFileTimestamps: state.readFileTimestamps
1603
+ });
1604
+ const finalResult = await lastX(result);
1605
+ if (finalResult.type !== "result") {
1606
+ throw new Error(`Tool ${name} did not return a result`);
1607
+ }
1608
+ return {
1609
+ content: Array.isArray(finalResult) ? finalResult.map((item) => ({
1610
+ type: "text",
1611
+ text: "text" in item ? item.text : JSON.stringify(item)
1612
+ })) : [
1613
+ {
1614
+ type: "text",
1615
+ text: typeof finalResult === "string" ? finalResult : JSON.stringify(finalResult.data)
1616
+ }
1617
+ ]
1618
+ };
1619
+ } catch (error) {
1620
+ logError(error);
1621
+ return {
1622
+ isError: true,
1623
+ content: [
1624
+ {
1625
+ type: "text",
1626
+ text: `Error: ${error instanceof Error ? error.message : String(error)}`
1627
+ }
1628
+ ]
1629
+ };
1630
+ }
1631
+ }
1632
+ );
1633
+ async function runServer() {
1634
+ const transport = new StdioServerTransport();
1635
+ await server.connect(transport);
1636
+ }
1637
+ return await runServer();
1638
+ }
1639
+
1640
+ // src/entrypoints/cli/runCli.tsx
1641
+ init_state();
1642
+ init_log();
1643
+
1644
+ // src/utils/session/conversationRecovery.ts
1645
+ init_log();
1646
+ import fs2 from "fs/promises";
1647
+ async function loadMessagesFromLog(logPath, tools) {
1648
+ try {
1649
+ const content = await fs2.readFile(logPath, "utf-8");
1650
+ const messages = JSON.parse(content);
1651
+ return deserializeMessages(messages, tools);
1652
+ } catch (error) {
1653
+ logError(`Failed to load messages from ${logPath}: ${error}`);
1654
+ throw new Error(`Failed to load messages from log: ${error}`);
1655
+ }
1656
+ }
1657
+ function deserializeMessages(messages, tools) {
1658
+ const toolMap = new Map(tools.map((tool) => [tool.name, tool]));
1659
+ return messages.map((message) => {
1660
+ const clonedMessage = JSON.parse(JSON.stringify(message));
1661
+ if (clonedMessage.toolCalls) {
1662
+ clonedMessage.toolCalls = clonedMessage.toolCalls.map((toolCall) => {
1663
+ if (toolCall.tool && typeof toolCall.tool === "string") {
1664
+ const actualTool = toolMap.get(toolCall.tool);
1665
+ if (actualTool) {
1666
+ toolCall.tool = actualTool;
1667
+ }
1668
+ }
1669
+ return toolCall;
1670
+ });
1671
+ }
1672
+ return clonedMessage;
1673
+ });
1674
+ }
1675
+
1676
+ // src/commands/approved-tools.ts
1677
+ var defaultConfigHandler = {
1678
+ getCurrentProjectConfig,
1679
+ saveCurrentProjectConfig
1680
+ };
1681
+ function handleListApprovedTools(cwd2, projectConfigHandler = defaultConfigHandler) {
1682
+ const projectConfig = projectConfigHandler.getCurrentProjectConfig();
1683
+ return `Allowed tools for ${cwd2}:
1684
+ ${projectConfig.allowedTools.join("\n")}`;
1685
+ }
1686
+ function handleRemoveApprovedTool(tool, projectConfigHandler = defaultConfigHandler) {
1687
+ const projectConfig = projectConfigHandler.getCurrentProjectConfig();
1688
+ const originalToolCount = projectConfig.allowedTools.length;
1689
+ const updatedAllowedTools = projectConfig.allowedTools.filter((t) => t !== tool);
1690
+ if (originalToolCount !== updatedAllowedTools.length) {
1691
+ projectConfig.allowedTools = updatedAllowedTools;
1692
+ projectConfigHandler.saveCurrentProjectConfig(projectConfig);
1693
+ return {
1694
+ success: true,
1695
+ message: `Removed ${tool} from the list of approved tools`
1696
+ };
1697
+ } else {
1698
+ return {
1699
+ success: false,
1700
+ message: `${tool} was not in the list of approved tools`
1701
+ };
1702
+ }
1703
+ }
1704
+
1705
+ // src/entrypoints/cli/runCli.tsx
1706
+ import { cursorShow } from "ansi-escapes";
1707
+ init_log();
1708
+ init_shell();
1709
+
1710
+ // src/ui/components/InvalidConfigDialog.tsx
1711
+ import React9 from "react";
1712
+ import { Box as Box5, Newline, Text as Text6, useInput as useInput4 } from "ink";
1713
+ import { render as render2 } from "ink";
1714
+ import { writeFileSync } from "fs";
1715
+ function InvalidConfigDialog({
1716
+ filePath,
1717
+ errorDescription,
1718
+ onExit,
1719
+ onReset
1720
+ }) {
1721
+ const theme = getTheme();
1722
+ useInput4((_, key) => {
1723
+ if (key.escape) {
1724
+ onExit();
1725
+ }
1726
+ });
1727
+ const exitState = useExitOnCtrlCD(() => process.exit(0));
1728
+ const handleSelect = (value) => {
1729
+ if (value === "exit") {
1730
+ onExit();
1731
+ } else {
1732
+ onReset();
1733
+ }
1734
+ };
1735
+ return /* @__PURE__ */ React9.createElement(React9.Fragment, null, /* @__PURE__ */ React9.createElement(
1736
+ Box5,
1737
+ {
1738
+ flexDirection: "column",
1739
+ borderColor: theme.error,
1740
+ borderStyle: "round",
1741
+ padding: 1,
1742
+ width: 70,
1743
+ gap: 1
1744
+ },
1745
+ /* @__PURE__ */ React9.createElement(Text6, { bold: true }, "Configuration Error"),
1746
+ /* @__PURE__ */ React9.createElement(Box5, { flexDirection: "column", gap: 1 }, /* @__PURE__ */ React9.createElement(Text6, null, "The configuration file at ", /* @__PURE__ */ React9.createElement(Text6, { bold: true }, filePath), " contains invalid JSON."), /* @__PURE__ */ React9.createElement(Text6, null, errorDescription)),
1747
+ /* @__PURE__ */ React9.createElement(Box5, { flexDirection: "column" }, /* @__PURE__ */ React9.createElement(Text6, { bold: true }, "Choose an option:"), /* @__PURE__ */ React9.createElement(
1748
+ Select,
1749
+ {
1750
+ options: [
1751
+ { label: "Exit and fix manually", value: "exit" },
1752
+ { label: "Reset with default configuration", value: "reset" }
1753
+ ],
1754
+ onChange: handleSelect
1755
+ }
1756
+ ))
1757
+ ), exitState.pending ? /* @__PURE__ */ React9.createElement(Text6, { dimColor: true }, "Press ", exitState.keyName, " again to exit") : /* @__PURE__ */ React9.createElement(Newline, null));
1758
+ }
1759
+ function showInvalidConfigDialog({
1760
+ error
1761
+ }) {
1762
+ return new Promise((resolve) => {
1763
+ render2(
1764
+ /* @__PURE__ */ React9.createElement(
1765
+ InvalidConfigDialog,
1766
+ {
1767
+ filePath: error.filePath,
1768
+ errorDescription: error.message,
1769
+ onExit: () => {
1770
+ resolve();
1771
+ process.exit(1);
1772
+ },
1773
+ onReset: () => {
1774
+ writeFileSync(
1775
+ error.filePath,
1776
+ JSON.stringify(error.defaultConfig, null, 2)
1777
+ );
1778
+ resolve();
1779
+ process.exit(0);
1780
+ }
1781
+ }
1782
+ ),
1783
+ { exitOnCtrlC: false }
1784
+ );
1785
+ });
1786
+ }
1787
+
1788
+ // src/entrypoints/cli/runCli.tsx
1789
+ init_macros();
1790
+ function omitKeys(input, ...keys) {
1791
+ const result = { ...input };
1792
+ for (const key of keys) {
1793
+ delete result[key];
1794
+ }
1795
+ return result;
1796
+ }
1797
+ async function runCli() {
1798
+ initDebugLogger();
1799
+ try {
1800
+ enableConfigs();
1801
+ queueMicrotask(() => {
1802
+ try {
1803
+ validateAndRepairAllGPT5Profiles();
1804
+ } catch (repairError) {
1805
+ logError(`GPT-5 configuration validation failed: ${repairError}`);
1806
+ }
1807
+ });
1808
+ } catch (error) {
1809
+ if (error instanceof ConfigParseError) {
1810
+ await showInvalidConfigDialog({ error });
1811
+ return;
1812
+ }
1813
+ }
1814
+ let inputPrompt = "";
1815
+ let renderContext = {
1816
+ exitOnCtrlC: false,
1817
+ onFlicker() {
1818
+ }
1819
+ };
1820
+ const wantsStreamJsonStdin = process.argv.some(
1821
+ (arg, idx, all) => arg === "--input-format" && all[idx + 1] === "stream-json"
1822
+ ) || process.argv.some((arg) => arg.startsWith("--input-format=stream-json"));
1823
+ if (!process.stdin.isTTY && !process.env.CI && !process.argv.includes("mcp") && !wantsStreamJsonStdin) {
1824
+ inputPrompt = await stdin();
1825
+ if (process.platform !== "win32") {
1826
+ try {
1827
+ const ttyFd = openSync("/dev/tty", "r");
1828
+ renderContext = { ...renderContext, stdin: new ReadStream(ttyFd) };
1829
+ } catch (err) {
1830
+ logError(`Could not open /dev/tty: ${err}`);
1831
+ }
1832
+ }
1833
+ }
1834
+ await parseArgs(inputPrompt, renderContext);
1835
+ }
1836
+ async function parseArgs(stdinContent, renderContext) {
1837
+ const program = new Command();
1838
+ const renderContextWithExitOnCtrlC = {
1839
+ ...renderContext,
1840
+ exitOnCtrlC: true
1841
+ };
1842
+ program.name(PRODUCT_COMMAND).description(
1843
+ `${PRODUCT_NAME} - starts an interactive session by default, use -p/--print for non-interactive output`
1844
+ ).argument("[prompt]", "Your prompt", String).option("--cwd <cwd>", "The current working directory", String, cwd()).option(
1845
+ "-d, --debug [filter]",
1846
+ 'Enable debug mode with optional category filtering (e.g., "api,hooks" or "!statsig,!file")'
1847
+ ).option(
1848
+ "--debug-verbose",
1849
+ "Enable verbose debug terminal output",
1850
+ () => true
1851
+ ).option(
1852
+ "--verbose",
1853
+ "Override verbose mode setting from config",
1854
+ () => true
1855
+ ).option("-e, --enable-architect", "Enable the Architect tool", () => true).option(
1856
+ "-p, --print",
1857
+ "Print response and exit (useful for pipes)",
1858
+ () => true
1859
+ ).option(
1860
+ "--output-format <format>",
1861
+ 'Output format (only works with --print): "text" (default), "json", or "stream-json"',
1862
+ String,
1863
+ "text"
1864
+ ).option(
1865
+ "--json-schema <schema>",
1866
+ 'JSON Schema for structured output validation. Example: {"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}',
1867
+ String
1868
+ ).option(
1869
+ "--input-format <format>",
1870
+ 'Input format (only works with --print): "text" (default) or "stream-json"',
1871
+ String,
1872
+ "text"
1873
+ ).option(
1874
+ "--mcp-debug",
1875
+ "[DEPRECATED. Use --debug instead] Enable MCP debug mode (shows MCP server errors)",
1876
+ () => true
1877
+ ).option(
1878
+ "--dangerously-skip-permissions",
1879
+ "Bypass all permission checks. Recommended only for sandboxes with no internet access.",
1880
+ () => true
1881
+ ).option(
1882
+ "--allow-dangerously-skip-permissions",
1883
+ "Enable bypassing all permission checks as an option, without it being enabled by default. Recommended only for sandboxes with no internet access.",
1884
+ () => true
1885
+ ).option(
1886
+ "--max-budget-usd <amount>",
1887
+ "Maximum dollar amount to spend on API calls (only works with --print)",
1888
+ String
1889
+ ).option(
1890
+ "--include-partial-messages",
1891
+ "Include partial message chunks as they arrive (only works with --print and --output-format=stream-json)",
1892
+ () => true
1893
+ ).option(
1894
+ "--replay-user-messages",
1895
+ "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)",
1896
+ () => true
1897
+ ).option(
1898
+ "--allowedTools, --allowed-tools <tools...>",
1899
+ 'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")'
1900
+ ).option(
1901
+ "--tools <tools...>",
1902
+ 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read"). Only works with --print mode.'
1903
+ ).option(
1904
+ "--disallowedTools, --disallowed-tools <tools...>",
1905
+ 'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")'
1906
+ ).option(
1907
+ "--mcp-config <configs...>",
1908
+ "Load MCP servers from JSON files or strings (space-separated)"
1909
+ ).option("--system-prompt <prompt>", "System prompt to use for the session").option(
1910
+ "--append-system-prompt <prompt>",
1911
+ "Append a system prompt to the default system prompt"
1912
+ ).option(
1913
+ "--permission-mode <mode>",
1914
+ 'Permission mode to use for the session (choices: "acceptEdits", "bypassPermissions", "default", "delegate", "dontAsk", "plan")',
1915
+ String
1916
+ ).option(
1917
+ "--permission-prompt-tool <tool>",
1918
+ 'Permission prompt tool (only works with --print, --output-format=stream-json, and --input-format=stream-json): "stdio"',
1919
+ String
1920
+ ).option(
1921
+ "--safe",
1922
+ "Enable strict permission checking mode (default is permissive)",
1923
+ () => true
1924
+ ).option(
1925
+ "--disable-slash-commands",
1926
+ "Disable slash commands (treat /... as plain text)",
1927
+ () => true
1928
+ ).option(
1929
+ "--plugin-dir <paths...>",
1930
+ "Load plugins from directories for this session only (repeatable)",
1931
+ (value, previous) => {
1932
+ const prev = Array.isArray(previous) ? previous : [];
1933
+ const next = Array.isArray(value) ? value : [value];
1934
+ return [...prev, ...next].filter(Boolean);
1935
+ },
1936
+ []
1937
+ ).option(
1938
+ "--model <model>",
1939
+ "Model for the current session. Provide an alias for the latest model (e.g. 'sonnet' or 'opus') or a model's full name.",
1940
+ String
1941
+ ).option(
1942
+ "--agent <agent>",
1943
+ "Agent for the current session. Overrides the 'agent' setting.",
1944
+ String
1945
+ ).option(
1946
+ "--betas <betas...>",
1947
+ "Beta headers to include in API requests (API key users only)"
1948
+ ).option(
1949
+ "--fallback-model <model>",
1950
+ "Enable automatic fallback to specified model when default model is overloaded (only works with --print)",
1951
+ String
1952
+ ).option(
1953
+ "--settings <file-or-json>",
1954
+ "Path to a settings JSON file or a JSON string to load additional settings from",
1955
+ String
1956
+ ).option(
1957
+ "--add-dir <directories...>",
1958
+ "Additional directories to allow tool access to"
1959
+ ).option(
1960
+ "--ide",
1961
+ "Automatically connect to IDE on startup if exactly one valid IDE is available",
1962
+ () => true
1963
+ ).option(
1964
+ "--strict-mcp-config",
1965
+ "Only use MCP servers from --mcp-config, ignoring all other MCP configurations",
1966
+ () => true
1967
+ ).option(
1968
+ "--agents <json>",
1969
+ `JSON object defining custom agents (e.g. '{"reviewer": {"description": "Reviews code", "prompt": "You are a code reviewer"}}')`,
1970
+ String
1971
+ ).option(
1972
+ "--setting-sources <sources>",
1973
+ "Comma-separated list of setting sources to load (user, project, local).",
1974
+ String
1975
+ ).option(
1976
+ "-r, --resume [value]",
1977
+ "Resume a conversation by session ID or session name (omit value to open selector)"
1978
+ ).option(
1979
+ "-c, --continue",
1980
+ "Continue the most recent conversation",
1981
+ () => true
1982
+ ).option(
1983
+ "--fork-session",
1984
+ "When resuming/continuing, create a new session ID instead of reusing the original (use with --resume or --continue)",
1985
+ () => true
1986
+ ).option(
1987
+ "--no-session-persistence",
1988
+ "Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)"
1989
+ ).option(
1990
+ "--session-id <uuid>",
1991
+ "Use a specific session ID for the conversation (must be a valid UUID)",
1992
+ String
1993
+ ).action(
1994
+ async (prompt, {
1995
+ cwd: cwd2,
1996
+ debug: debug2,
1997
+ verbose,
1998
+ enableArchitect,
1999
+ print,
2000
+ outputFormat,
2001
+ jsonSchema,
2002
+ inputFormat,
2003
+ mcpDebug,
2004
+ dangerouslySkipPermissions,
2005
+ allowDangerouslySkipPermissions,
2006
+ maxBudgetUsd,
2007
+ includePartialMessages,
2008
+ replayUserMessages,
2009
+ allowedTools: allowedTools2,
2010
+ tools: cliTools,
2011
+ disallowedTools,
2012
+ mcpConfig,
2013
+ systemPrompt: systemPromptOverride,
2014
+ appendSystemPrompt,
2015
+ permissionMode,
2016
+ permissionPromptTool,
2017
+ safe,
2018
+ disableSlashCommands,
2019
+ pluginDir,
2020
+ model,
2021
+ addDir,
2022
+ strictMcpConfig,
2023
+ agents,
2024
+ settingSources,
2025
+ resume,
2026
+ continue: continueConversation,
2027
+ forkSession,
2028
+ sessionId,
2029
+ sessionPersistence
2030
+ }) => {
2031
+ try {
2032
+ setEnabledSettingSourcesFromCli(settingSources);
2033
+ } catch (err) {
2034
+ process.stderr.write(
2035
+ `Error processing --setting-sources: ${err instanceof Error ? err.message : String(err)}
2036
+ `
2037
+ );
2038
+ process.exit(1);
2039
+ }
2040
+ setFlagAgentsFromCliJson(agents);
2041
+ clearAgentCache();
2042
+ clearOutputStyleCache();
2043
+ await setup(cwd2, safe);
2044
+ await showSetupScreens(safe, print);
2045
+ assertMinVersion();
2046
+ {
2047
+ const requested = Array.isArray(pluginDir) && pluginDir.length > 0 ? pluginDir : [];
2048
+ const { listEnabledInstalledPluginPackRoots } = await import("./skillMarketplace-PCTUUX46.js");
2049
+ const installed = listEnabledInstalledPluginPackRoots();
2050
+ const all = [...installed, ...requested].filter(Boolean);
2051
+ const deduped = Array.from(new Set(all));
2052
+ if (deduped.length > 0) {
2053
+ const { configureSessionPlugins } = await import("./pluginRuntime-JYYI5BSQ.js");
2054
+ const { errors } = await configureSessionPlugins({
2055
+ pluginDirs: deduped
2056
+ });
2057
+ for (const err of errors) {
2058
+ console.warn(err);
2059
+ }
2060
+ }
2061
+ }
2062
+ const [{ ask }, { getTools }, { getCommands }] = await Promise.all([
2063
+ import("./ask-TX526UBD.js"),
2064
+ import("./tools-BHW37PCF.js"),
2065
+ import("./commands-HOBCZ3VQ.js")
2066
+ ]);
2067
+ const commands = await getCommands();
2068
+ const mcpClientsPromise = Array.isArray(mcpConfig) && mcpConfig.length > 0 || strictMcpConfig === true ? getClientsForCliMcpConfig({
2069
+ mcpConfig: Array.isArray(mcpConfig) ? mcpConfig : [],
2070
+ strictMcpConfig: strictMcpConfig === true,
2071
+ projectDir: cwd2
2072
+ }) : getClients();
2073
+ const [allTools, mcpClients] = await Promise.all([
2074
+ getTools(
2075
+ enableArchitect ?? getCurrentProjectConfig().enableArchitectTool
2076
+ ),
2077
+ mcpClientsPromise
2078
+ ]);
2079
+ const tools = disableSlashCommands === true ? allTools.filter((t) => t.name !== "SlashCommand") : allTools;
2080
+ const inputPrompt = [prompt, stdinContent].filter(Boolean).join("\n");
2081
+ const {
2082
+ loadDanyaAgentSessionMessages,
2083
+ findMostRecentDanyaAgentSessionId
2084
+ } = await import("./kodeAgentSessionLoad-KR4JSD6D.js");
2085
+ const { listDanyaAgentSessions, resolveResumeSessionIdentifier } = await import("./kodeAgentSessionResume-BCD6UV74.js");
2086
+ const { isUuid } = await import("./uuid-QUYJMIUV.js");
2087
+ const { setDanyaAgentSessionId, getDanyaAgentSessionId } = await import("./kodeAgentSessionId-WUT74FSH.js");
2088
+ const { randomUUID } = await import("crypto");
2089
+ const wantsContinue = Boolean(continueConversation);
2090
+ const wantsResume = resume !== void 0;
2091
+ const wantsFork = Boolean(forkSession);
2092
+ if (sessionId && !isUuid(String(sessionId))) {
2093
+ console.error(`Error: --session-id must be a valid UUID`);
2094
+ process.exit(1);
2095
+ }
2096
+ if (sessionId && (wantsContinue || wantsResume) && !wantsFork) {
2097
+ console.error(
2098
+ `Error: --session-id can only be used with --continue or --resume if --fork-session is also specified.`
2099
+ );
2100
+ process.exit(1);
2101
+ }
2102
+ let initialMessages;
2103
+ let resumedFromSessionId = null;
2104
+ let needsResumeSelector = false;
2105
+ if (wantsContinue) {
2106
+ const latest = findMostRecentDanyaAgentSessionId(cwd2);
2107
+ if (!latest) {
2108
+ console.error("No conversation found to continue");
2109
+ process.exit(1);
2110
+ }
2111
+ initialMessages = loadDanyaAgentSessionMessages({
2112
+ cwd: cwd2,
2113
+ sessionId: latest
2114
+ });
2115
+ resumedFromSessionId = latest;
2116
+ } else if (wantsResume) {
2117
+ if (resume === true) {
2118
+ needsResumeSelector = true;
2119
+ } else {
2120
+ const identifier = String(resume);
2121
+ const resolved = resolveResumeSessionIdentifier({ cwd: cwd2, identifier });
2122
+ if (resolved.kind === "ok") {
2123
+ initialMessages = loadDanyaAgentSessionMessages({
2124
+ cwd: cwd2,
2125
+ sessionId: resolved.sessionId
2126
+ });
2127
+ resumedFromSessionId = resolved.sessionId;
2128
+ } else if (resolved.kind === "different_directory") {
2129
+ console.error(
2130
+ resolved.otherCwd ? `Error: That session belongs to a different directory: ${resolved.otherCwd}` : `Error: That session belongs to a different directory.`
2131
+ );
2132
+ process.exit(1);
2133
+ } else if (resolved.kind === "ambiguous") {
2134
+ console.error(
2135
+ `Error: Multiple sessions match "${identifier}": ${resolved.matchingSessionIds.join(
2136
+ ", "
2137
+ )}`
2138
+ );
2139
+ process.exit(1);
2140
+ } else {
2141
+ console.error(
2142
+ `No conversation found with session ID or name: ${identifier}`
2143
+ );
2144
+ process.exit(1);
2145
+ }
2146
+ }
2147
+ }
2148
+ if (needsResumeSelector && print) {
2149
+ console.error(
2150
+ "Error: --resume without a value requires interactive mode (no --print)."
2151
+ );
2152
+ process.exit(1);
2153
+ }
2154
+ if (!needsResumeSelector) {
2155
+ const effectiveSessionId = (() => {
2156
+ if (resumedFromSessionId) {
2157
+ if (wantsFork) return sessionId ? String(sessionId) : randomUUID();
2158
+ return resumedFromSessionId;
2159
+ }
2160
+ if (sessionId) return String(sessionId);
2161
+ return getDanyaAgentSessionId();
2162
+ })();
2163
+ setDanyaAgentSessionId(effectiveSessionId);
2164
+ }
2165
+ if (print) {
2166
+ await runPrintMode({
2167
+ prompt,
2168
+ stdinContent,
2169
+ inputPrompt,
2170
+ cwd: cwd2,
2171
+ safe,
2172
+ verbose,
2173
+ outputFormat,
2174
+ inputFormat,
2175
+ jsonSchema,
2176
+ permissionPromptTool,
2177
+ replayUserMessages,
2178
+ cliTools,
2179
+ tools,
2180
+ commands,
2181
+ ask,
2182
+ initialMessages,
2183
+ sessionPersistence,
2184
+ systemPromptOverride,
2185
+ appendSystemPrompt,
2186
+ disableSlashCommands,
2187
+ allowedTools: allowedTools2,
2188
+ disallowedTools,
2189
+ addDir,
2190
+ permissionMode,
2191
+ dangerouslySkipPermissions,
2192
+ allowDangerouslySkipPermissions,
2193
+ model,
2194
+ mcpClients
2195
+ });
2196
+ return;
2197
+ } else {
2198
+ if (sessionPersistence === false) {
2199
+ console.error(
2200
+ "Error: --no-session-persistence only works with --print"
2201
+ );
2202
+ process.exit(1);
2203
+ }
2204
+ const updateInfo = await (async () => {
2205
+ try {
2206
+ const [
2207
+ { getLatestVersion, getUpdateCommandSuggestions },
2208
+ semverMod
2209
+ ] = await Promise.all([
2210
+ import("./autoUpdater-63RAZ24N.js"),
2211
+ import("semver")
2212
+ ]);
2213
+ const semver = semverMod?.default ?? semverMod;
2214
+ const gt = semver?.gt;
2215
+ if (typeof gt !== "function")
2216
+ return {
2217
+ version: null,
2218
+ commands: null
2219
+ };
2220
+ const latest = await getLatestVersion();
2221
+ if (latest && gt(latest, MACRO.VERSION)) {
2222
+ const cmds = await getUpdateCommandSuggestions();
2223
+ return { version: latest, commands: cmds };
2224
+ }
2225
+ } catch {
2226
+ }
2227
+ return {
2228
+ version: null,
2229
+ commands: null
2230
+ };
2231
+ })();
2232
+ if (needsResumeSelector) {
2233
+ const sessions = listDanyaAgentSessions({ cwd: cwd2 });
2234
+ if (sessions.length === 0) {
2235
+ console.error("No conversation found to resume");
2236
+ process.exit(1);
2237
+ }
2238
+ const context2 = {};
2239
+ (async () => {
2240
+ const { render: render3 } = await import("ink");
2241
+ const { unmount } = render3(
2242
+ /* @__PURE__ */ React10.createElement(
2243
+ ResumeConversation,
2244
+ {
2245
+ cwd: cwd2,
2246
+ context: context2,
2247
+ commands,
2248
+ sessions,
2249
+ tools,
2250
+ verbose,
2251
+ safeMode: safe,
2252
+ debug: Boolean(debug2),
2253
+ disableSlashCommands: disableSlashCommands === true,
2254
+ mcpClients,
2255
+ initialPrompt: inputPrompt,
2256
+ forkSession: wantsFork,
2257
+ forkSessionId: sessionId ? String(sessionId) : null,
2258
+ initialUpdateVersion: updateInfo.version,
2259
+ initialUpdateCommands: updateInfo.commands
2260
+ }
2261
+ ),
2262
+ renderContextWithExitOnCtrlC
2263
+ );
2264
+ context2.unmount = unmount;
2265
+ })();
2266
+ return;
2267
+ }
2268
+ const isDefaultModel = await isDefaultSlowAndCapableModel();
2269
+ {
2270
+ const { render: render3 } = await import("ink");
2271
+ const { REPL } = await import("./REPL-EYUOXCEC.js");
2272
+ render3(
2273
+ /* @__PURE__ */ React10.createElement(
2274
+ REPL,
2275
+ {
2276
+ commands,
2277
+ debug: Boolean(debug2),
2278
+ disableSlashCommands: disableSlashCommands === true,
2279
+ initialPrompt: inputPrompt,
2280
+ messageLogName: dateToFilename(/* @__PURE__ */ new Date()),
2281
+ shouldShowPromptInput: true,
2282
+ verbose,
2283
+ tools,
2284
+ safeMode: safe,
2285
+ mcpClients,
2286
+ isDefaultModel,
2287
+ initialUpdateVersion: updateInfo.version,
2288
+ initialUpdateCommands: updateInfo.commands,
2289
+ initialMessages
2290
+ }
2291
+ ),
2292
+ renderContext
2293
+ );
2294
+ }
2295
+ }
2296
+ }
2297
+ ).version(MACRO.VERSION, "-v, --version");
2298
+ const config = program.command("config").description(
2299
+ `Manage configuration (eg. ${PRODUCT_COMMAND} config set -g theme dark)`
2300
+ );
2301
+ config.command("get <key>").description("Get a config value").option("--cwd <cwd>", "The current working directory", String, cwd()).option("-g, --global", "Use global config").action(async (key, { cwd: cwd2, global }) => {
2302
+ await setup(cwd2, false);
2303
+ console.log(getConfigForCLI(key, global ?? false));
2304
+ process.exit(0);
2305
+ });
2306
+ config.command("set <key> <value>").description("Set a config value").option("--cwd <cwd>", "The current working directory", String, cwd()).option("-g, --global", "Use global config").action(async (key, value, { cwd: cwd2, global }) => {
2307
+ await setup(cwd2, false);
2308
+ setConfigForCLI(key, value, global ?? false);
2309
+ console.log(`Set ${key} to ${value}`);
2310
+ process.exit(0);
2311
+ });
2312
+ config.command("remove <key>").description("Remove a config value").option("--cwd <cwd>", "The current working directory", String, cwd()).option("-g, --global", "Use global config").action(async (key, { cwd: cwd2, global }) => {
2313
+ await setup(cwd2, false);
2314
+ deleteConfigForCLI(key, global ?? false);
2315
+ console.log(`Removed ${key}`);
2316
+ process.exit(0);
2317
+ });
2318
+ config.command("list").description("List all config values").option("--cwd <cwd>", "The current working directory", String, cwd()).option("-g, --global", "Use global config", false).action(async ({ cwd: cwd2, global }) => {
2319
+ await setup(cwd2, false);
2320
+ console.log(
2321
+ JSON.stringify(
2322
+ global ? listConfigForCLI(true) : listConfigForCLI(false),
2323
+ null,
2324
+ 2
2325
+ )
2326
+ );
2327
+ process.exit(0);
2328
+ });
2329
+ const modelsCmd = program.command("models").description("Import/export model profiles and pointers (YAML)");
2330
+ modelsCmd.command("export").description(
2331
+ "Export shareable model config as YAML (does not include plaintext API keys)"
2332
+ ).option("--cwd <cwd>", "The current working directory", String, cwd()).option("-o, --output <path>", "Write YAML to file instead of stdout").action(async ({ cwd: cwd2, output }) => {
2333
+ try {
2334
+ await setup(cwd2, false);
2335
+ const yamlText = formatModelConfigYamlForSharing(getGlobalConfig());
2336
+ if (output) {
2337
+ writeFileSync2(output, yamlText, "utf-8");
2338
+ console.log(`Wrote model config YAML to ${output}`);
2339
+ } else {
2340
+ console.log(yamlText);
2341
+ }
2342
+ process.exit(0);
2343
+ } catch (error) {
2344
+ console.error(error.message);
2345
+ process.exit(1);
2346
+ }
2347
+ });
2348
+ modelsCmd.command("import <file>").description("Import model config YAML (merges by default)").option("--cwd <cwd>", "The current working directory", String, cwd()).option("--replace", "Replace existing model profiles instead of merging").action(async (file, { cwd: cwd2, replace }) => {
2349
+ try {
2350
+ await setup(cwd2, false);
2351
+ const yamlText = readFileSync(file, "utf-8");
2352
+ const { nextConfig, warnings } = applyModelConfigYamlImport(
2353
+ getGlobalConfig(),
2354
+ yamlText,
2355
+ { replace: !!replace }
2356
+ );
2357
+ saveGlobalConfig(nextConfig);
2358
+ await import("./model-HPLBR53R.js").then(({ reloadModelManager }) => {
2359
+ reloadModelManager();
2360
+ });
2361
+ if (warnings.length > 0) {
2362
+ console.error(warnings.join("\n"));
2363
+ }
2364
+ console.log(`Imported model config YAML from ${file}`);
2365
+ process.exit(0);
2366
+ } catch (error) {
2367
+ console.error(error.message);
2368
+ process.exit(1);
2369
+ }
2370
+ });
2371
+ modelsCmd.command("list").description("List configured model profiles and pointers").option("--cwd <cwd>", "The current working directory", String, cwd()).option("--json", "Output as JSON").action(async (options) => {
2372
+ try {
2373
+ const workingDir = typeof options?.cwd === "string" ? options.cwd : cwd();
2374
+ const asJson = options?.json === true;
2375
+ await setup(workingDir, false);
2376
+ const { reloadModelManager, getModelManager: getModelManager2 } = await import("./model-HPLBR53R.js");
2377
+ reloadModelManager();
2378
+ const manager = getModelManager2();
2379
+ const config2 = getGlobalConfig();
2380
+ const pointers = ["main", "task", "compact", "quick"].map(
2381
+ (pointer) => {
2382
+ const pointerId = config2.modelPointers?.[pointer] ?? null;
2383
+ const resolved = manager.resolveModelWithInfo(pointer);
2384
+ const profile = resolved.success ? resolved.profile : null;
2385
+ return {
2386
+ pointer,
2387
+ pointerId,
2388
+ resolved: profile ? {
2389
+ name: profile.name,
2390
+ provider: profile.provider,
2391
+ modelName: profile.modelName,
2392
+ isActive: profile.isActive
2393
+ } : null,
2394
+ error: resolved.success ? null : resolved.error ?? null
2395
+ };
2396
+ }
2397
+ );
2398
+ const profiles = (config2.modelProfiles ?? []).map((p) => ({
2399
+ name: p.name,
2400
+ provider: p.provider,
2401
+ modelName: p.modelName,
2402
+ baseURL: p.baseURL ?? null,
2403
+ maxTokens: p.maxTokens,
2404
+ contextLength: p.contextLength,
2405
+ reasoningEffort: p.reasoningEffort ?? null,
2406
+ isActive: p.isActive,
2407
+ createdAt: p.createdAt,
2408
+ lastUsed: typeof p.lastUsed === "number" ? p.lastUsed : null,
2409
+ isGPT5: p.isGPT5 ?? null,
2410
+ validationStatus: p.validationStatus ?? null,
2411
+ lastValidation: typeof p.lastValidation === "number" ? p.lastValidation : null,
2412
+ hasApiKey: Boolean(p.apiKey)
2413
+ }));
2414
+ if (asJson) {
2415
+ console.log(JSON.stringify({ pointers, profiles }, null, 2));
2416
+ process.exitCode = 0;
2417
+ return;
2418
+ }
2419
+ console.log("Model pointers:\n");
2420
+ for (const ptr of pointers) {
2421
+ const resolvedLabel = ptr.resolved ? `${ptr.resolved.name} (${ptr.resolved.provider}:${ptr.resolved.modelName})` : "(unresolved)";
2422
+ const configured = ptr.pointerId ? ` -> ${ptr.pointerId}` : "";
2423
+ const err = ptr.error ? ` [${ptr.error}]` : "";
2424
+ console.log(` - ${ptr.pointer}${configured}: ${resolvedLabel}${err}`);
2425
+ }
2426
+ const active = profiles.filter((p) => p.isActive);
2427
+ console.log(`
2428
+ Model profiles (${active.length}/${profiles.length} active):
2429
+ `);
2430
+ for (const p of profiles.sort((a, b) => a.name.localeCompare(b.name))) {
2431
+ const status = p.isActive ? "active" : "inactive";
2432
+ console.log(` - ${p.name} (${status})`);
2433
+ console.log(` provider=${p.provider} modelName=${p.modelName}`);
2434
+ if (p.baseURL) console.log(` baseURL=${p.baseURL}`);
2435
+ }
2436
+ process.exitCode = 0;
2437
+ return;
2438
+ } catch (error) {
2439
+ console.error(error.message);
2440
+ process.exitCode = 1;
2441
+ return;
2442
+ }
2443
+ });
2444
+ const agentsCmd = program.command("agents").description("Agent utilities (validate templates, etc.)");
2445
+ agentsCmd.command("validate [paths...]").description("Validate agent markdown files (defaults to user+project agent dirs)").option("--cwd <cwd>", "The current working directory", String, cwd()).option("--json", "Output as JSON").option("--no-tools-check", "Skip validating tool names against the tool registry").action(
2446
+ async (paths, options) => {
2447
+ try {
2448
+ const workingDir = typeof options?.cwd === "string" ? options.cwd : cwd();
2449
+ await setup(workingDir, false);
2450
+ const { validateAgentTemplates } = await import("./agentsValidate-RQ2QDGNY.js");
2451
+ const report = await validateAgentTemplates({
2452
+ cwd: workingDir,
2453
+ paths: Array.isArray(paths) ? paths : [],
2454
+ checkTools: options.toolsCheck !== false
2455
+ });
2456
+ if (options.json) {
2457
+ console.log(JSON.stringify(report, null, 2));
2458
+ process.exitCode = report.ok ? 0 : 1;
2459
+ return;
2460
+ }
2461
+ console.log(
2462
+ `Validated ${report.results.length} agent file(s): ${report.errorCount} error(s), ${report.warningCount} warning(s)
2463
+ `
2464
+ );
2465
+ for (const r of report.results) {
2466
+ const rel = r.filePath;
2467
+ const title = r.agentType ? `${r.agentType}` : "(unknown agent)";
2468
+ console.log(`${title} \u2014 ${rel}`);
2469
+ if (r.model) {
2470
+ const normalized = r.normalizedModel ? ` (normalized: ${r.normalizedModel})` : "";
2471
+ console.log(` model: ${r.model}${normalized}`);
2472
+ }
2473
+ if (r.issues.length === 0) {
2474
+ console.log(` OK`);
2475
+ } else {
2476
+ for (const issue of r.issues) {
2477
+ console.log(` - ${issue.level}: ${issue.message}`);
2478
+ }
2479
+ }
2480
+ console.log("");
2481
+ }
2482
+ process.exitCode = report.ok ? 0 : 1;
2483
+ return;
2484
+ } catch (error) {
2485
+ console.error(error.message);
2486
+ process.exitCode = 1;
2487
+ return;
2488
+ }
2489
+ }
2490
+ );
2491
+ const registerMarketplaceCommands = (marketplaceCmd2) => {
2492
+ marketplaceCmd2.command("add <source>").description("Add a marketplace from a URL, path, or GitHub repo").action(async (source) => {
2493
+ try {
2494
+ const { addMarketplace } = await import("./skillMarketplace-PCTUUX46.js");
2495
+ console.log("Adding marketplace...");
2496
+ const { name } = await addMarketplace(source);
2497
+ console.log(`Successfully added marketplace: ${name}`);
2498
+ process.exit(0);
2499
+ } catch (error) {
2500
+ console.error(error.message);
2501
+ process.exit(1);
2502
+ }
2503
+ });
2504
+ marketplaceCmd2.command("list").description("List all configured marketplaces").option("--json", "Output as JSON").action(async (options) => {
2505
+ try {
2506
+ const { listMarketplaces } = await import("./skillMarketplace-PCTUUX46.js");
2507
+ const marketplaces = listMarketplaces();
2508
+ if (options.json) {
2509
+ console.log(JSON.stringify(marketplaces, null, 2));
2510
+ process.exit(0);
2511
+ }
2512
+ const names = Object.keys(marketplaces).sort();
2513
+ if (names.length === 0) {
2514
+ console.log("No marketplaces configured");
2515
+ process.exit(0);
2516
+ }
2517
+ console.log("Configured marketplaces:\n");
2518
+ for (const name of names) {
2519
+ const entry = marketplaces[name];
2520
+ console.log(` - ${name}`);
2521
+ const src = entry?.source;
2522
+ if (src?.source === "github") {
2523
+ console.log(` Source: GitHub (${src.repo})`);
2524
+ } else if (src?.source === "git") {
2525
+ console.log(` Source: Git (${src.url})`);
2526
+ } else if (src?.source === "url") {
2527
+ console.log(` Source: URL (${src.url})`);
2528
+ } else if (src?.source === "directory") {
2529
+ console.log(` Source: Directory (${src.path})`);
2530
+ } else if (src?.source === "file") {
2531
+ console.log(` Source: File (${src.path})`);
2532
+ } else if (src?.source === "npm") {
2533
+ console.log(` Source: NPM (${src.package})`);
2534
+ }
2535
+ console.log("");
2536
+ }
2537
+ process.exit(0);
2538
+ } catch (error) {
2539
+ console.error(error.message);
2540
+ process.exit(1);
2541
+ }
2542
+ });
2543
+ marketplaceCmd2.command("remove <name>").alias("rm").description("Remove a configured marketplace").action(async (name) => {
2544
+ try {
2545
+ const { removeMarketplace } = await import("./skillMarketplace-PCTUUX46.js");
2546
+ removeMarketplace(name);
2547
+ console.log(`Successfully removed marketplace: ${name}`);
2548
+ process.exit(0);
2549
+ } catch (error) {
2550
+ console.error(error.message);
2551
+ process.exit(1);
2552
+ }
2553
+ });
2554
+ marketplaceCmd2.command("update [name]").description(
2555
+ "Update marketplace(s) from their source - updates all if no name specified"
2556
+ ).action(async (name, _options) => {
2557
+ try {
2558
+ const {
2559
+ listMarketplaces,
2560
+ refreshAllMarketplacesAsync,
2561
+ refreshMarketplaceAsync
2562
+ } = await import("./skillMarketplace-PCTUUX46.js");
2563
+ const trimmed = typeof name === "string" ? name.trim() : "";
2564
+ if (trimmed) {
2565
+ console.log(`Updating marketplace: ${trimmed}...`);
2566
+ await refreshMarketplaceAsync(trimmed);
2567
+ console.log(`Successfully updated marketplace: ${trimmed}`);
2568
+ process.exit(0);
2569
+ }
2570
+ const marketplaces = listMarketplaces();
2571
+ const names = Object.keys(marketplaces);
2572
+ if (names.length === 0) {
2573
+ console.log("No marketplaces configured");
2574
+ process.exit(0);
2575
+ }
2576
+ console.log(`Updating ${names.length} marketplace(s)...`);
2577
+ await refreshAllMarketplacesAsync((message) => {
2578
+ console.log(message);
2579
+ });
2580
+ console.log(`Successfully updated ${names.length} marketplace(s)`);
2581
+ process.exit(0);
2582
+ } catch (error) {
2583
+ console.error(error.message);
2584
+ process.exit(1);
2585
+ }
2586
+ });
2587
+ };
2588
+ const pluginCmd = program.command("plugin").description("Manage plugins and marketplaces");
2589
+ const pluginMarketplaceCmd = pluginCmd.command("marketplace").description(
2590
+ "Manage marketplaces (.danya-plugin/marketplace.json; legacy .claude-plugin supported)"
2591
+ );
2592
+ registerMarketplaceCommands(pluginMarketplaceCmd);
2593
+ const PLUGIN_SCOPES = ["user", "project", "local"];
2594
+ const parsePluginScope = (value) => {
2595
+ const normalized = String(value || "user");
2596
+ return PLUGIN_SCOPES.includes(normalized) ? normalized : null;
2597
+ };
2598
+ pluginCmd.command("install <plugin>").alias("i").description(
2599
+ "Install a plugin from available marketplaces (use plugin@marketplace for specific marketplace)"
2600
+ ).option("--cwd <cwd>", "The current working directory", String, cwd()).option(
2601
+ "-s, --scope <scope>",
2602
+ "Installation scope: user, project, or local",
2603
+ "user"
2604
+ ).option("--force", "Overwrite existing installed files", () => true).action(async (plugin, options) => {
2605
+ try {
2606
+ const scope = parsePluginScope(options.scope);
2607
+ if (!scope) {
2608
+ console.error(
2609
+ `Invalid scope: ${String(options.scope)}. Must be one of: ${PLUGIN_SCOPES.join(", ")}`
2610
+ );
2611
+ process.exit(1);
2612
+ }
2613
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2614
+ await setCwd2(options.cwd ?? cwd());
2615
+ const { installSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2616
+ const result = installSkillPlugin(plugin, {
2617
+ scope,
2618
+ force: options.force === true
2619
+ });
2620
+ const skillList = result.installedSkills.length > 0 ? `Skills: ${result.installedSkills.join(", ")}` : "Skills: (none)";
2621
+ console.log(`Installed ${result.pluginSpec}
2622
+ ${skillList}`);
2623
+ process.exit(0);
2624
+ } catch (error) {
2625
+ console.error(error.message);
2626
+ process.exit(1);
2627
+ }
2628
+ });
2629
+ pluginCmd.command("uninstall <plugin>").alias("remove").alias("rm").description("Uninstall an installed plugin").option("--cwd <cwd>", "The current working directory", String, cwd()).option(
2630
+ "-s, --scope <scope>",
2631
+ `Uninstall from scope: ${PLUGIN_SCOPES.join(", ")} (default: user)`,
2632
+ "user"
2633
+ ).action(async (plugin, options) => {
2634
+ try {
2635
+ const scope = parsePluginScope(options.scope);
2636
+ if (!scope) {
2637
+ console.error(
2638
+ `Invalid scope: ${String(options.scope)}. Must be one of: ${PLUGIN_SCOPES.join(", ")}`
2639
+ );
2640
+ process.exit(1);
2641
+ }
2642
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2643
+ await setCwd2(options.cwd ?? cwd());
2644
+ const { uninstallSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2645
+ const result = uninstallSkillPlugin(plugin, { scope });
2646
+ const skillList = result.removedSkills.length > 0 ? `Skills: ${result.removedSkills.join(", ")}` : "Skills: (none)";
2647
+ console.log(`Uninstalled ${result.pluginSpec}
2648
+ ${skillList}`);
2649
+ process.exit(0);
2650
+ } catch (error) {
2651
+ console.error(error.message);
2652
+ process.exit(1);
2653
+ }
2654
+ });
2655
+ pluginCmd.command("list").description("List installed plugins").option("--cwd <cwd>", "The current working directory", String, cwd()).option(
2656
+ "-s, --scope <scope>",
2657
+ `Filter by scope: ${PLUGIN_SCOPES.join(", ")} (default: user)`,
2658
+ "user"
2659
+ ).option("--json", "Output as JSON").action(async (options) => {
2660
+ try {
2661
+ const scope = parsePluginScope(options.scope);
2662
+ if (!scope) {
2663
+ console.error(
2664
+ `Invalid scope: ${String(options.scope)}. Must be one of: ${PLUGIN_SCOPES.join(", ")}`
2665
+ );
2666
+ process.exit(1);
2667
+ }
2668
+ const { setCwd: setCwd2, getCwd: getCwd2 } = await import("./state-XJICGOUA.js");
2669
+ await setCwd2(options.cwd ?? cwd());
2670
+ const { listInstalledSkillPlugins } = await import("./skillMarketplace-PCTUUX46.js");
2671
+ const all = listInstalledSkillPlugins();
2672
+ const filtered = Object.fromEntries(
2673
+ Object.entries(all).filter(([, record]) => {
2674
+ if (record?.scope !== scope) return false;
2675
+ if (scope === "user") return true;
2676
+ return record?.projectPath === getCwd2();
2677
+ })
2678
+ );
2679
+ if (options.json) {
2680
+ console.log(JSON.stringify(filtered, null, 2));
2681
+ process.exit(0);
2682
+ }
2683
+ const names = Object.keys(filtered).sort();
2684
+ if (names.length === 0) {
2685
+ console.log("No plugins installed");
2686
+ process.exit(0);
2687
+ }
2688
+ console.log(`Installed plugins (scope=${scope}):
2689
+ `);
2690
+ for (const spec of names) {
2691
+ const record = filtered[spec];
2692
+ const enabled = record?.isEnabled === false ? "disabled" : "enabled";
2693
+ console.log(` - ${spec} (${enabled})`);
2694
+ }
2695
+ process.exit(0);
2696
+ } catch (error) {
2697
+ console.error(error.message);
2698
+ process.exit(1);
2699
+ }
2700
+ });
2701
+ pluginCmd.command("enable <plugin>").description("Enable a disabled plugin").option("--cwd <cwd>", "The current working directory", String, cwd()).option(
2702
+ "-s, --scope <scope>",
2703
+ `Installation scope: ${PLUGIN_SCOPES.join(", ")} (default: user)`,
2704
+ "user"
2705
+ ).action(async (plugin, options) => {
2706
+ try {
2707
+ const scope = parsePluginScope(options.scope);
2708
+ if (!scope) {
2709
+ console.error(
2710
+ `Invalid scope: ${String(options.scope)}. Must be one of: ${PLUGIN_SCOPES.join(", ")}`
2711
+ );
2712
+ process.exit(1);
2713
+ }
2714
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2715
+ await setCwd2(options.cwd ?? cwd());
2716
+ const { enableSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2717
+ const result = enableSkillPlugin(plugin, { scope });
2718
+ console.log(`Enabled ${result.pluginSpec}`);
2719
+ process.exit(0);
2720
+ } catch (error) {
2721
+ console.error(error.message);
2722
+ process.exit(1);
2723
+ }
2724
+ });
2725
+ pluginCmd.command("disable <plugin>").description("Disable an enabled plugin").option("--cwd <cwd>", "The current working directory", String, cwd()).option(
2726
+ "-s, --scope <scope>",
2727
+ `Installation scope: ${PLUGIN_SCOPES.join(", ")} (default: user)`,
2728
+ "user"
2729
+ ).action(async (plugin, options) => {
2730
+ try {
2731
+ const scope = parsePluginScope(options.scope);
2732
+ if (!scope) {
2733
+ console.error(
2734
+ `Invalid scope: ${String(options.scope)}. Must be one of: ${PLUGIN_SCOPES.join(", ")}`
2735
+ );
2736
+ process.exit(1);
2737
+ }
2738
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2739
+ await setCwd2(options.cwd ?? cwd());
2740
+ const { disableSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2741
+ const result = disableSkillPlugin(plugin, { scope });
2742
+ console.log(`Disabled ${result.pluginSpec}`);
2743
+ process.exit(0);
2744
+ } catch (error) {
2745
+ console.error(error.message);
2746
+ process.exit(1);
2747
+ }
2748
+ });
2749
+ pluginCmd.command("validate <path>").description("Validate a plugin or marketplace manifest").option("--cwd <cwd>", "The current working directory", String, cwd()).action(async (path, options) => {
2750
+ try {
2751
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2752
+ await setCwd2(options.cwd ?? cwd());
2753
+ const { formatValidationResult, validatePluginOrMarketplacePath } = await import("./pluginValidation-JWUFPZUE.js");
2754
+ const result = validatePluginOrMarketplacePath(path);
2755
+ console.log(
2756
+ `Validating ${result.fileType} manifest: ${result.filePath}
2757
+ `
2758
+ );
2759
+ console.log(formatValidationResult(result));
2760
+ process.exit(result.success ? 0 : 1);
2761
+ } catch (error) {
2762
+ console.error(
2763
+ `Unexpected error during validation: ${error instanceof Error ? error.message : String(error)}`
2764
+ );
2765
+ process.exit(2);
2766
+ }
2767
+ });
2768
+ const skillsCmd = program.command("skills").description("Manage skills and skill marketplaces");
2769
+ const marketplaceCmd = skillsCmd.command("marketplace").description(
2770
+ "Manage skill marketplaces (.danya-plugin/marketplace.json; legacy .claude-plugin supported)"
2771
+ );
2772
+ registerMarketplaceCommands(marketplaceCmd);
2773
+ skillsCmd.command("install <plugin>").description("Install a skill plugin pack (<plugin>@<marketplace>)").option("--cwd <cwd>", "The current working directory", String, cwd()).option("--project", "Install into this project (.danya/...)", () => true).option("--force", "Overwrite existing installed files", () => true).action(async (plugin, options) => {
2774
+ try {
2775
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2776
+ await setCwd2(options.cwd ?? cwd());
2777
+ const { installSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2778
+ const result = installSkillPlugin(plugin, {
2779
+ project: options.project === true,
2780
+ force: options.force === true
2781
+ });
2782
+ const skillList = result.installedSkills.length > 0 ? `Skills: ${result.installedSkills.join(", ")}` : "Skills: (none)";
2783
+ console.log(`Installed ${plugin}
2784
+ ${skillList}`);
2785
+ process.exit(0);
2786
+ } catch (error) {
2787
+ console.error(error.message);
2788
+ process.exit(1);
2789
+ }
2790
+ });
2791
+ skillsCmd.command("uninstall <plugin>").description("Uninstall a skill plugin pack (<plugin>@<marketplace>)").option("--cwd <cwd>", "The current working directory", String, cwd()).option("--project", "Uninstall from this project (.danya/...)", () => true).action(async (plugin, options) => {
2792
+ try {
2793
+ const { setCwd: setCwd2 } = await import("./state-XJICGOUA.js");
2794
+ await setCwd2(options.cwd ?? cwd());
2795
+ const { uninstallSkillPlugin } = await import("./skillMarketplace-PCTUUX46.js");
2796
+ const result = uninstallSkillPlugin(plugin, {
2797
+ project: options.project === true
2798
+ });
2799
+ const skillList = result.removedSkills.length > 0 ? `Skills: ${result.removedSkills.join(", ")}` : "Skills: (none)";
2800
+ console.log(`Uninstalled ${plugin}
2801
+ ${skillList}`);
2802
+ process.exit(0);
2803
+ } catch (error) {
2804
+ console.error(error.message);
2805
+ process.exit(1);
2806
+ }
2807
+ });
2808
+ skillsCmd.command("list-installed").description("List installed skill plugins").action(async () => {
2809
+ try {
2810
+ const { listInstalledSkillPlugins } = await import("./skillMarketplace-PCTUUX46.js");
2811
+ console.log(JSON.stringify(listInstalledSkillPlugins(), null, 2));
2812
+ process.exit(0);
2813
+ } catch (error) {
2814
+ console.error(error.message);
2815
+ process.exit(1);
2816
+ }
2817
+ });
2818
+ const allowedTools = program.command("approved-tools").description("Manage approved tools");
2819
+ allowedTools.command("list").description("List all approved tools").action(async () => {
2820
+ const result = handleListApprovedTools(getCwd());
2821
+ console.log(result);
2822
+ process.exit(0);
2823
+ });
2824
+ allowedTools.command("remove <tool>").description("Remove a tool from the list of approved tools").action(async (tool) => {
2825
+ const result = handleRemoveApprovedTool(tool);
2826
+ console.log(result.message);
2827
+ process.exit(result.success ? 0 : 1);
2828
+ });
2829
+ const mcp = program.command("mcp").description("Configure and manage MCP servers");
2830
+ mcp.command("serve").description(`Start the ${PRODUCT_NAME} MCP server`).action(async () => {
2831
+ const providedCwd = program.opts().cwd ?? cwd();
2832
+ if (!existsSync(providedCwd)) {
2833
+ console.error(`Error: Directory ${providedCwd} does not exist`);
2834
+ process.exit(1);
2835
+ }
2836
+ try {
2837
+ await setup(providedCwd, false);
2838
+ await startMCPServer(providedCwd);
2839
+ } catch (error) {
2840
+ console.error("Error: Failed to start MCP server:", error);
2841
+ process.exit(1);
2842
+ }
2843
+ });
2844
+ mcp.command("add-sse <name> <url>").description("Add an SSE server").option(
2845
+ "-s, --scope <scope>",
2846
+ "Configuration scope (local, user, or project)",
2847
+ "local"
2848
+ ).option(
2849
+ "-H, --header <header...>",
2850
+ 'Set headers (e.g. -H "X-Api-Key: abc123" -H "X-Custom: value")'
2851
+ ).action(async (name, url, options) => {
2852
+ try {
2853
+ const scopeInfo = normalizeMcpScopeForCli(options.scope);
2854
+ const headers = parseMcpHeaders(options.header);
2855
+ addMcpServer(
2856
+ name,
2857
+ { type: "sse", url, ...headers ? { headers } : {} },
2858
+ scopeInfo.scope
2859
+ );
2860
+ console.log(
2861
+ `Added SSE MCP server ${name} with URL: ${url} to ${scopeInfo.display} config`
2862
+ );
2863
+ if (headers) {
2864
+ console.log(`Headers: ${JSON.stringify(headers, null, 2)}`);
2865
+ }
2866
+ process.exit(0);
2867
+ } catch (error) {
2868
+ console.error(error.message);
2869
+ process.exit(1);
2870
+ }
2871
+ });
2872
+ mcp.command("add-http <name> <url>").description("Add a Streamable HTTP MCP server").option(
2873
+ "-s, --scope <scope>",
2874
+ "Configuration scope (local, user, or project)",
2875
+ "local"
2876
+ ).option(
2877
+ "-H, --header <header...>",
2878
+ 'Set headers (e.g. -H "X-Api-Key: abc123" -H "X-Custom: value")'
2879
+ ).action(async (name, url, options) => {
2880
+ try {
2881
+ const scopeInfo = normalizeMcpScopeForCli(options.scope);
2882
+ const headers = parseMcpHeaders(options.header);
2883
+ addMcpServer(
2884
+ name,
2885
+ { type: "http", url, ...headers ? { headers } : {} },
2886
+ scopeInfo.scope
2887
+ );
2888
+ console.log(
2889
+ `Added HTTP MCP server ${name} with URL: ${url} to ${scopeInfo.display} config`
2890
+ );
2891
+ if (headers) {
2892
+ console.log(`Headers: ${JSON.stringify(headers, null, 2)}`);
2893
+ }
2894
+ process.exit(0);
2895
+ } catch (error) {
2896
+ console.error(error.message);
2897
+ process.exit(1);
2898
+ }
2899
+ });
2900
+ mcp.command("add-ws <name> <url>").description("Add a WebSocket MCP server").option(
2901
+ "-s, --scope <scope>",
2902
+ "Configuration scope (local, user, or project)",
2903
+ "local"
2904
+ ).action(async (name, url, options) => {
2905
+ try {
2906
+ const scopeInfo = normalizeMcpScopeForCli(options.scope);
2907
+ addMcpServer(name, { type: "ws", url }, scopeInfo.scope);
2908
+ console.log(
2909
+ `Added WebSocket MCP server ${name} with URL ${url} to ${scopeInfo.display} config`
2910
+ );
2911
+ process.exit(0);
2912
+ } catch (error) {
2913
+ console.error(error.message);
2914
+ process.exit(1);
2915
+ }
2916
+ });
2917
+ mcp.command("add [name] [commandOrUrl] [args...]").description("Add a server (run without arguments for interactive wizard)").option(
2918
+ "-s, --scope <scope>",
2919
+ "Configuration scope (local, user, or project)",
2920
+ "local"
2921
+ ).option(
2922
+ "-t, --transport <transport>",
2923
+ "MCP transport (stdio, sse, or http)"
2924
+ ).option(
2925
+ "-H, --header <header...>",
2926
+ 'Set headers (e.g. -H "X-Api-Key: abc123" -H "X-Custom: value")'
2927
+ ).option(
2928
+ "-e, --env <env...>",
2929
+ "Set environment variables (e.g. -e KEY=value)"
2930
+ ).action(async (name, commandOrUrl, args, options) => {
2931
+ try {
2932
+ if (!name) {
2933
+ console.log("Interactive wizard mode: Enter the server details");
2934
+ const { createInterface } = await import("readline");
2935
+ const rl = createInterface({
2936
+ input: process.stdin,
2937
+ output: process.stdout
2938
+ });
2939
+ const question = (query) => new Promise((resolve) => rl.question(query, resolve));
2940
+ const serverName = await question("Server name: ");
2941
+ if (!serverName) {
2942
+ console.error("Error: Server name is required");
2943
+ rl.close();
2944
+ process.exit(1);
2945
+ }
2946
+ const serverType = await question(
2947
+ "Server type (stdio, http, sse, ws) [stdio]: "
2948
+ );
2949
+ const type = serverType && ["stdio", "http", "sse", "ws"].includes(serverType) ? serverType : "stdio";
2950
+ const prompt = type === "stdio" ? "Command: " : "URL: ";
2951
+ const commandOrUrlValue = await question(prompt);
2952
+ if (!commandOrUrlValue) {
2953
+ console.error(
2954
+ `Error: ${type === "stdio" ? "Command" : "URL"} is required`
2955
+ );
2956
+ rl.close();
2957
+ process.exit(1);
2958
+ }
2959
+ let serverArgs = [];
2960
+ let serverEnv = {};
2961
+ if (type === "stdio") {
2962
+ const argsStr = await question(
2963
+ "Command arguments (space-separated): "
2964
+ );
2965
+ serverArgs = argsStr ? argsStr.split(" ").filter(Boolean) : [];
2966
+ const envStr = await question(
2967
+ "Environment variables (format: KEY1=value1,KEY2=value2): "
2968
+ );
2969
+ if (envStr) {
2970
+ const envPairs = envStr.split(",").map((pair) => pair.trim());
2971
+ serverEnv = parseEnvVars(envPairs.map((pair) => pair));
2972
+ }
2973
+ }
2974
+ const scopeStr = await question(
2975
+ "Configuration scope (local, user, or project) [local]: "
2976
+ );
2977
+ const scopeInfo = normalizeMcpScopeForCli(scopeStr);
2978
+ const serverScope = scopeInfo.scope;
2979
+ rl.close();
2980
+ if (type === "http") {
2981
+ addMcpServer(
2982
+ serverName,
2983
+ { type: "http", url: commandOrUrlValue },
2984
+ serverScope
2985
+ );
2986
+ console.log(
2987
+ `Added HTTP MCP server ${serverName} with URL ${commandOrUrlValue} to ${scopeInfo.display} config`
2988
+ );
2989
+ } else if (type === "sse") {
2990
+ addMcpServer(
2991
+ serverName,
2992
+ { type: "sse", url: commandOrUrlValue },
2993
+ serverScope
2994
+ );
2995
+ console.log(
2996
+ `Added SSE MCP server ${serverName} with URL ${commandOrUrlValue} to ${scopeInfo.display} config`
2997
+ );
2998
+ } else if (type === "ws") {
2999
+ addMcpServer(
3000
+ serverName,
3001
+ { type: "ws", url: commandOrUrlValue },
3002
+ serverScope
3003
+ );
3004
+ console.log(
3005
+ `Added WebSocket MCP server ${serverName} with URL ${commandOrUrlValue} to ${scopeInfo.display} config`
3006
+ );
3007
+ } else {
3008
+ addMcpServer(
3009
+ serverName,
3010
+ {
3011
+ type: "stdio",
3012
+ command: commandOrUrlValue,
3013
+ args: serverArgs,
3014
+ env: serverEnv
3015
+ },
3016
+ serverScope
3017
+ );
3018
+ console.log(
3019
+ `Added stdio MCP server ${serverName} with command: ${commandOrUrlValue} ${serverArgs.join(" ")} to ${scopeInfo.display} config`
3020
+ );
3021
+ }
3022
+ } else if (name && commandOrUrl) {
3023
+ const scopeInfo = normalizeMcpScopeForCli(options.scope);
3024
+ const transportInfo = normalizeMcpTransport(options.transport);
3025
+ if (transportInfo.transport === "stdio") {
3026
+ if (options.header?.length) {
3027
+ throw new Error(
3028
+ "--header can only be used with --transport http or --transport sse"
3029
+ );
3030
+ }
3031
+ const env = parseEnvVars(options.env);
3032
+ if (!transportInfo.explicit && looksLikeMcpUrl(commandOrUrl)) {
3033
+ console.warn(
3034
+ `Warning: "${commandOrUrl}" looks like a URL. Default transport is stdio, so it will be treated as a command.`
3035
+ );
3036
+ console.warn(
3037
+ `If you meant to add an HTTP MCP server, run: ${PRODUCT_COMMAND} mcp add ${name} ${commandOrUrl} --transport http`
3038
+ );
3039
+ console.warn(
3040
+ `If you meant to add a legacy SSE MCP server, run: ${PRODUCT_COMMAND} mcp add ${name} ${commandOrUrl} --transport sse`
3041
+ );
3042
+ }
3043
+ addMcpServer(
3044
+ name,
3045
+ { type: "stdio", command: commandOrUrl, args: args || [], env },
3046
+ scopeInfo.scope
3047
+ );
3048
+ console.log(
3049
+ `Added stdio MCP server ${name} with command: ${commandOrUrl} ${(args || []).join(" ")} to ${scopeInfo.display} config`
3050
+ );
3051
+ } else {
3052
+ if (options.env?.length) {
3053
+ throw new Error("--env is only supported for stdio MCP servers");
3054
+ }
3055
+ if (args?.length) {
3056
+ throw new Error(
3057
+ "Unexpected arguments. URL-based MCP servers do not accept command args."
3058
+ );
3059
+ }
3060
+ const headers = parseMcpHeaders(options.header);
3061
+ addMcpServer(
3062
+ name,
3063
+ {
3064
+ type: transportInfo.transport,
3065
+ url: commandOrUrl,
3066
+ ...headers ? { headers } : {}
3067
+ },
3068
+ scopeInfo.scope
3069
+ );
3070
+ const kind = transportInfo.transport.toUpperCase();
3071
+ console.log(
3072
+ `Added ${kind} MCP server ${name} with URL: ${commandOrUrl} to ${scopeInfo.display} config`
3073
+ );
3074
+ if (headers) {
3075
+ console.log(`Headers: ${JSON.stringify(headers, null, 2)}`);
3076
+ }
3077
+ }
3078
+ } else {
3079
+ console.error(
3080
+ "Error: Missing required arguments. Either provide no arguments for interactive mode or specify name and command/URL."
3081
+ );
3082
+ process.exit(1);
3083
+ }
3084
+ process.exit(0);
3085
+ } catch (error) {
3086
+ console.error(error.message);
3087
+ process.exit(1);
3088
+ }
3089
+ });
3090
+ mcp.command("remove <name>").description("Remove an MCP server").option(
3091
+ "-s, --scope <scope>",
3092
+ "Configuration scope (local, user, or project)"
3093
+ ).action(async (name, options) => {
3094
+ try {
3095
+ if (options.scope) {
3096
+ const scopeInfo = normalizeMcpScopeForCli(options.scope);
3097
+ removeMcpServer(name, scopeInfo.scope);
3098
+ console.log(
3099
+ `Removed MCP server ${name} from ${scopeInfo.display} config`
3100
+ );
3101
+ process.exit(0);
3102
+ }
3103
+ const matches = [];
3104
+ const projectConfig = getCurrentProjectConfig();
3105
+ if (projectConfig.mcpServers?.[name]) {
3106
+ matches.push({
3107
+ scope: ensureConfigScope("project"),
3108
+ display: "local"
3109
+ });
3110
+ }
3111
+ const globalConfig = getGlobalConfig();
3112
+ if (globalConfig.mcpServers?.[name]) {
3113
+ matches.push({ scope: ensureConfigScope("global"), display: "user" });
3114
+ }
3115
+ const projectFileDefinitions = getProjectMcpServerDefinitions();
3116
+ if (projectFileDefinitions.servers[name]) {
3117
+ const source = projectFileDefinitions.sources[name];
3118
+ if (source === ".mcp.json") {
3119
+ matches.push({
3120
+ scope: ensureConfigScope("mcpjson"),
3121
+ display: "project"
3122
+ });
3123
+ } else {
3124
+ matches.push({
3125
+ scope: ensureConfigScope("mcprc"),
3126
+ display: "mcprc"
3127
+ });
3128
+ }
3129
+ }
3130
+ if (matches.length === 0) {
3131
+ throw new Error(`No MCP server found with name: ${name}`);
3132
+ }
3133
+ if (matches.length > 1) {
3134
+ console.error(
3135
+ `MCP server "${name}" exists in multiple scopes: ${matches.map((m) => m.display).join(", ")}`
3136
+ );
3137
+ console.error("Please specify which scope to remove from:");
3138
+ for (const match2 of matches) {
3139
+ console.error(
3140
+ ` ${PRODUCT_COMMAND} mcp remove ${name} --scope ${match2.display}`
3141
+ );
3142
+ }
3143
+ process.exit(1);
3144
+ }
3145
+ const match = matches[0];
3146
+ removeMcpServer(name, match.scope);
3147
+ console.log(`Removed MCP server ${name} from ${match.display} config`);
3148
+ process.exit(0);
3149
+ } catch (error) {
3150
+ console.error(error.message);
3151
+ process.exit(1);
3152
+ }
3153
+ });
3154
+ mcp.command("list").description("List configured MCP servers").action(async () => {
3155
+ try {
3156
+ const servers = listMCPServers();
3157
+ if (Object.keys(servers).length === 0) {
3158
+ console.log(
3159
+ `No MCP servers configured. Use \`${PRODUCT_COMMAND} mcp add\` to add a server.`
3160
+ );
3161
+ process.exit(0);
3162
+ }
3163
+ const projectFileServers = getProjectMcpServerDefinitions();
3164
+ const clients = await getClients();
3165
+ const clientByName = /* @__PURE__ */ new Map();
3166
+ for (const client of clients) {
3167
+ clientByName.set(client.name, client);
3168
+ }
3169
+ const names = Object.keys(servers).sort((a, b) => a.localeCompare(b));
3170
+ for (const name of names) {
3171
+ const server = servers[name];
3172
+ const client = clientByName.get(name);
3173
+ const status = client?.type === "connected" ? "connected" : client?.type === "failed" ? "failed" : projectFileServers.servers[name] ? (() => {
3174
+ const approval = getMcprcServerStatus(name);
3175
+ if (approval === "pending") return "pending";
3176
+ if (approval === "rejected") return "rejected";
3177
+ return "disconnected";
3178
+ })() : "disconnected";
3179
+ const summary = (() => {
3180
+ switch (server.type) {
3181
+ case "http":
3182
+ return `${server.url} (http)`;
3183
+ case "sse":
3184
+ return `${server.url} (sse)`;
3185
+ case "sse-ide":
3186
+ return `${server.url} (sse-ide)`;
3187
+ case "ws":
3188
+ return `${server.url} (ws)`;
3189
+ case "ws-ide":
3190
+ return `${server.url} (ws-ide)`;
3191
+ case "stdio":
3192
+ default:
3193
+ return `${server.command} ${(server.args || []).join(" ")} (stdio)`;
3194
+ }
3195
+ })();
3196
+ console.log(`${name}: ${summary} [${status}]`);
3197
+ }
3198
+ process.exit(0);
3199
+ } catch (error) {
3200
+ console.error(error.message);
3201
+ process.exit(1);
3202
+ }
3203
+ });
3204
+ mcp.command("add-json <name> <json>").description("Add an MCP server with a JSON string").option(
3205
+ "-s, --scope <scope>",
3206
+ "Configuration scope (project, global, or mcprc)",
3207
+ "project"
3208
+ ).action(async (name, jsonStr, options) => {
3209
+ try {
3210
+ const scope = ensureConfigScope(options.scope);
3211
+ let serverConfig;
3212
+ try {
3213
+ serverConfig = JSON.parse(jsonStr);
3214
+ } catch (e) {
3215
+ console.error("Error: Invalid JSON string");
3216
+ process.exit(1);
3217
+ }
3218
+ if (!serverConfig.type || !["stdio", "sse", "http", "ws", "sse-ide", "ws-ide"].includes(
3219
+ serverConfig.type
3220
+ )) {
3221
+ console.error(
3222
+ 'Error: Server type must be one of: "stdio", "http", "sse", "ws", "sse-ide", "ws-ide"'
3223
+ );
3224
+ process.exit(1);
3225
+ }
3226
+ if (["sse", "http", "ws", "sse-ide", "ws-ide"].includes(
3227
+ serverConfig.type
3228
+ ) && !serverConfig.url) {
3229
+ console.error("Error: URL-based MCP servers must have a URL");
3230
+ process.exit(1);
3231
+ }
3232
+ if (serverConfig.type === "stdio" && !serverConfig.command) {
3233
+ console.error("Error: stdio server must have a command");
3234
+ process.exit(1);
3235
+ }
3236
+ if (["sse-ide", "ws-ide"].includes(serverConfig.type) && !serverConfig.ideName) {
3237
+ console.error("Error: IDE MCP servers must include ideName");
3238
+ process.exit(1);
3239
+ }
3240
+ addMcpServer(name, serverConfig, scope);
3241
+ switch (serverConfig.type) {
3242
+ case "http":
3243
+ console.log(
3244
+ `Added HTTP MCP server ${name} with URL ${serverConfig.url} to ${scope} config`
3245
+ );
3246
+ break;
3247
+ case "sse":
3248
+ console.log(
3249
+ `Added SSE MCP server ${name} with URL ${serverConfig.url} to ${scope} config`
3250
+ );
3251
+ break;
3252
+ case "sse-ide":
3253
+ console.log(
3254
+ `Added SSE-IDE MCP server ${name} with URL ${serverConfig.url} to ${scope} config`
3255
+ );
3256
+ break;
3257
+ case "ws":
3258
+ console.log(
3259
+ `Added WS MCP server ${name} with URL ${serverConfig.url} to ${scope} config`
3260
+ );
3261
+ break;
3262
+ case "ws-ide":
3263
+ console.log(
3264
+ `Added WS-IDE MCP server ${name} with URL ${serverConfig.url} to ${scope} config`
3265
+ );
3266
+ break;
3267
+ case "stdio":
3268
+ default:
3269
+ console.log(
3270
+ `Added stdio MCP server ${name} with command: ${serverConfig.command} ${(serverConfig.args || []).join(" ")} to ${scope} config`
3271
+ );
3272
+ break;
3273
+ }
3274
+ process.exit(0);
3275
+ } catch (error) {
3276
+ console.error(error.message);
3277
+ process.exit(1);
3278
+ }
3279
+ });
3280
+ mcp.command("get <name>").description("Get details about an MCP server").action(async (name) => {
3281
+ try {
3282
+ const server = getMcpServer(name);
3283
+ if (!server) {
3284
+ console.error(`No MCP server found with name: ${name}`);
3285
+ process.exit(1);
3286
+ }
3287
+ const projectFileServers = getProjectMcpServerDefinitions();
3288
+ const clients = await getClients();
3289
+ const client = clients.find((c) => c.name === name);
3290
+ const status = client?.type === "connected" ? "connected" : client?.type === "failed" ? "failed" : projectFileServers.servers[name] ? (() => {
3291
+ const approval = getMcprcServerStatus(name);
3292
+ if (approval === "pending") return "pending";
3293
+ if (approval === "rejected") return "rejected";
3294
+ return "disconnected";
3295
+ })() : "disconnected";
3296
+ const scopeDisplay = (() => {
3297
+ switch (server.scope) {
3298
+ case "project":
3299
+ return "local";
3300
+ case "global":
3301
+ return "user";
3302
+ case "mcpjson":
3303
+ return "project";
3304
+ case "mcprc":
3305
+ return "mcprc";
3306
+ default:
3307
+ return server.scope;
3308
+ }
3309
+ })();
3310
+ console.log(`${name}:`);
3311
+ console.log(` Status: ${status}`);
3312
+ console.log(` Scope: ${scopeDisplay}`);
3313
+ const printHeaders = (headers) => {
3314
+ if (!headers || Object.keys(headers).length === 0) return;
3315
+ console.log(" Headers:");
3316
+ for (const [key, value] of Object.entries(headers)) {
3317
+ console.log(` ${key}: ${value}`);
3318
+ }
3319
+ };
3320
+ switch (server.type) {
3321
+ case "http":
3322
+ console.log(` Type: http`);
3323
+ console.log(` URL: ${server.url}`);
3324
+ printHeaders(server.headers);
3325
+ break;
3326
+ case "sse":
3327
+ console.log(` Type: sse`);
3328
+ console.log(` URL: ${server.url}`);
3329
+ printHeaders(server.headers);
3330
+ break;
3331
+ case "sse-ide":
3332
+ console.log(` Type: sse-ide`);
3333
+ console.log(` URL: ${server.url}`);
3334
+ console.log(` IDE: ${server.ideName}`);
3335
+ printHeaders(server.headers);
3336
+ break;
3337
+ case "ws":
3338
+ console.log(` Type: ws`);
3339
+ console.log(` URL: ${server.url}`);
3340
+ break;
3341
+ case "ws-ide":
3342
+ console.log(` Type: ws-ide`);
3343
+ console.log(` URL: ${server.url}`);
3344
+ console.log(` IDE: ${server.ideName}`);
3345
+ break;
3346
+ case "stdio":
3347
+ default:
3348
+ console.log(` Type: stdio`);
3349
+ console.log(` Command: ${server.command}`);
3350
+ console.log(` Args: ${(server.args || []).join(" ")}`);
3351
+ if (server.env) {
3352
+ console.log(" Environment:");
3353
+ for (const [key, value] of Object.entries(server.env)) {
3354
+ console.log(` ${key}=${value}`);
3355
+ }
3356
+ }
3357
+ break;
3358
+ }
3359
+ process.exit(0);
3360
+ } catch (error) {
3361
+ console.error(error.message);
3362
+ process.exit(1);
3363
+ }
3364
+ });
3365
+ mcp.command("add-from-claude-desktop").description(
3366
+ "Import MCP servers from a desktop MCP host config (macOS, Windows and WSL)"
3367
+ ).option(
3368
+ "-s, --scope <scope>",
3369
+ "Configuration scope (project, global, or mcprc)",
3370
+ "project"
3371
+ ).action(async (options) => {
3372
+ try {
3373
+ const scope = ensureConfigScope(options.scope);
3374
+ const platform = process.platform;
3375
+ const { existsSync: existsSync2, readFileSync: readFileSync2 } = await import("fs");
3376
+ const { join: join2 } = await import("path");
3377
+ const { exec } = await import("child_process");
3378
+ const isWSL = platform === "linux" && existsSync2("/proc/version") && readFileSync2("/proc/version", "utf-8").toLowerCase().includes("microsoft");
3379
+ if (platform !== "darwin" && platform !== "win32" && !isWSL) {
3380
+ console.error(
3381
+ "Error: This command is only supported on macOS, Windows, and WSL"
3382
+ );
3383
+ process.exit(1);
3384
+ }
3385
+ let configPath;
3386
+ if (platform === "darwin") {
3387
+ configPath = join2(
3388
+ process.env.HOME || "~",
3389
+ "Library/Application Support/Claude/claude_desktop_config.json"
3390
+ );
3391
+ } else if (platform === "win32") {
3392
+ configPath = join2(
3393
+ process.env.APPDATA || "",
3394
+ "Claude/claude_desktop_config.json"
3395
+ );
3396
+ } else if (isWSL) {
3397
+ const whoamiCommand = await new Promise((resolve, reject) => {
3398
+ exec(
3399
+ 'powershell.exe -Command "whoami"',
3400
+ (err, stdout) => {
3401
+ if (err) reject(err);
3402
+ else resolve(stdout.trim().split("\\").pop() || "");
3403
+ }
3404
+ );
3405
+ });
3406
+ configPath = `/mnt/c/Users/${whoamiCommand}/AppData/Roaming/Claude/claude_desktop_config.json`;
3407
+ }
3408
+ if (!existsSync2(configPath)) {
3409
+ console.error(`Error: Config file not found at ${configPath}`);
3410
+ process.exit(1);
3411
+ }
3412
+ let config2;
3413
+ try {
3414
+ const configContent = readFileSync2(configPath, "utf-8");
3415
+ config2 = JSON.parse(configContent);
3416
+ } catch (err) {
3417
+ console.error(`Error reading config file: ${err}`);
3418
+ process.exit(1);
3419
+ }
3420
+ const mcpServers = config2.mcpServers || {};
3421
+ const serverNames = Object.keys(mcpServers);
3422
+ const numServers = serverNames.length;
3423
+ if (numServers === 0) {
3424
+ console.log("No MCP servers found in the desktop config");
3425
+ process.exit(0);
3426
+ }
3427
+ const serversInfo = serverNames.map((name) => {
3428
+ const server = mcpServers[name];
3429
+ let description = "";
3430
+ switch (server.type) {
3431
+ case "http":
3432
+ description = `HTTP: ${server.url}`;
3433
+ break;
3434
+ case "sse":
3435
+ description = `SSE: ${server.url}`;
3436
+ break;
3437
+ case "sse-ide":
3438
+ description = `SSE-IDE (${server.ideName}): ${server.url}`;
3439
+ break;
3440
+ case "ws":
3441
+ description = `WS: ${server.url}`;
3442
+ break;
3443
+ case "ws-ide":
3444
+ description = `WS-IDE (${server.ideName}): ${server.url}`;
3445
+ break;
3446
+ case "stdio":
3447
+ default:
3448
+ description = `stdio: ${server.command} ${(server.args || []).join(" ")}`;
3449
+ break;
3450
+ }
3451
+ return { name, description, server };
3452
+ });
3453
+ const ink = await import("ink");
3454
+ const reactModule = await import("react");
3455
+ const inkjsui = await import("@inkjs/ui");
3456
+ const utilsTheme = await import("./theme-DP7O4SGH.js");
3457
+ const { render: render3 } = ink;
3458
+ const React11 = reactModule;
3459
+ const { MultiSelect: MultiSelect2 } = inkjsui;
3460
+ const { Box: Box6, Text: Text7 } = ink;
3461
+ const { getTheme: getTheme2 } = utilsTheme;
3462
+ await new Promise((resolve) => {
3463
+ function ClaudeDesktopImport() {
3464
+ const { useState: useState2 } = reactModule;
3465
+ const [isFinished, setIsFinished] = useState2(false);
3466
+ const [importResults, setImportResults] = useState2(
3467
+ []
3468
+ );
3469
+ const [isImporting, setIsImporting] = useState2(false);
3470
+ const theme = getTheme2();
3471
+ const importServers = async (selectedServers) => {
3472
+ setIsImporting(true);
3473
+ const results = [];
3474
+ for (const name of selectedServers) {
3475
+ try {
3476
+ const server = mcpServers[name];
3477
+ const existingServer = getMcpServer(name);
3478
+ if (existingServer) {
3479
+ continue;
3480
+ }
3481
+ addMcpServer(name, server, scope);
3482
+ results.push({ name, success: true });
3483
+ } catch (err) {
3484
+ results.push({ name, success: false });
3485
+ }
3486
+ }
3487
+ setImportResults(results);
3488
+ setIsImporting(false);
3489
+ setIsFinished(true);
3490
+ setTimeout(() => {
3491
+ resolve();
3492
+ }, 1e3);
3493
+ };
3494
+ const handleConfirm = async (selectedServers) => {
3495
+ const existingServers = selectedServers.filter(
3496
+ (name) => getMcpServer(name)
3497
+ );
3498
+ if (existingServers.length > 0) {
3499
+ const results = [];
3500
+ const newServers = selectedServers.filter(
3501
+ (name) => !getMcpServer(name)
3502
+ );
3503
+ for (const name of newServers) {
3504
+ try {
3505
+ const server = mcpServers[name];
3506
+ addMcpServer(name, server, scope);
3507
+ results.push({ name, success: true });
3508
+ } catch (err) {
3509
+ results.push({ name, success: false });
3510
+ }
3511
+ }
3512
+ for (const name of existingServers) {
3513
+ try {
3514
+ const server = mcpServers[name];
3515
+ addMcpServer(name, server, scope);
3516
+ results.push({ name, success: true });
3517
+ } catch (err) {
3518
+ results.push({ name, success: false });
3519
+ }
3520
+ }
3521
+ setImportResults(results);
3522
+ setIsImporting(false);
3523
+ setIsFinished(true);
3524
+ setTimeout(() => {
3525
+ resolve();
3526
+ }, 1e3);
3527
+ } else {
3528
+ await importServers(selectedServers);
3529
+ }
3530
+ };
3531
+ return /* @__PURE__ */ React11.createElement(Box6, { flexDirection: "column", padding: 1 }, /* @__PURE__ */ React11.createElement(
3532
+ Box6,
3533
+ {
3534
+ flexDirection: "column",
3535
+ borderStyle: "round",
3536
+ borderColor: theme.danya,
3537
+ padding: 1,
3538
+ width: "100%"
3539
+ },
3540
+ /* @__PURE__ */ React11.createElement(Text7, { bold: true, color: theme.danya }, "Import MCP Servers from Desktop Config"),
3541
+ /* @__PURE__ */ React11.createElement(Box6, { marginY: 1 }, /* @__PURE__ */ React11.createElement(Text7, null, "Found ", numServers, " MCP servers in the desktop config.")),
3542
+ /* @__PURE__ */ React11.createElement(Text7, null, "Please select the servers you want to import:"),
3543
+ /* @__PURE__ */ React11.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(
3544
+ MultiSelect2,
3545
+ {
3546
+ options: serverNames.map((name) => ({
3547
+ label: name,
3548
+ value: name
3549
+ })),
3550
+ defaultValue: serverNames,
3551
+ onSubmit: handleConfirm
3552
+ }
3553
+ ))
3554
+ ), /* @__PURE__ */ React11.createElement(Box6, { marginTop: 0, marginLeft: 3 }, /* @__PURE__ */ React11.createElement(Text7, { dimColor: true }, "Space to select \xB7 Enter to confirm \xB7 Esc to cancel")), isFinished && /* @__PURE__ */ React11.createElement(Box6, { marginTop: 1 }, /* @__PURE__ */ React11.createElement(Text7, { color: theme.success }, "Successfully imported", " ", importResults.filter((r) => r.success).length, " MCP server to local config.")));
3555
+ }
3556
+ const { unmount } = render3(/* @__PURE__ */ React11.createElement(ClaudeDesktopImport, null));
3557
+ setTimeout(() => {
3558
+ unmount();
3559
+ resolve();
3560
+ }, 3e4);
3561
+ });
3562
+ process.exit(0);
3563
+ } catch (error) {
3564
+ console.error(`Error: ${error.message}`);
3565
+ process.exit(1);
3566
+ }
3567
+ });
3568
+ const resetMcpChoices = () => {
3569
+ const config2 = getCurrentProjectConfig();
3570
+ saveCurrentProjectConfig({
3571
+ ...config2,
3572
+ approvedMcprcServers: [],
3573
+ rejectedMcprcServers: []
3574
+ });
3575
+ console.log(
3576
+ "All project-file MCP server approvals/rejections (.mcp.json/.mcprc) have been reset."
3577
+ );
3578
+ console.log(
3579
+ `You will be prompted for approval next time you start ${PRODUCT_NAME}.`
3580
+ );
3581
+ process.exit(0);
3582
+ };
3583
+ mcp.command("reset-project-choices").description(
3584
+ "Reset approvals for project-file MCP servers (.mcp.json/.mcprc) in this project"
3585
+ ).action(() => {
3586
+ resetMcpChoices();
3587
+ });
3588
+ mcp.command("reset-mcprc-choices").description(
3589
+ "Reset approvals for project-file MCP servers (.mcp.json/.mcprc) in this project"
3590
+ ).action(() => {
3591
+ resetMcpChoices();
3592
+ });
3593
+ program.command("doctor").description(`Check the health of your ${PRODUCT_NAME} installation`).action(async () => {
3594
+ await new Promise((resolve) => {
3595
+ ;
3596
+ (async () => {
3597
+ const { render: render3 } = await import("ink");
3598
+ render3(/* @__PURE__ */ React10.createElement(Doctor, { onDone: () => resolve(), doctorMode: true }));
3599
+ })();
3600
+ });
3601
+ process.exit(0);
3602
+ });
3603
+ program.command("update").description("Show manual upgrade commands (no auto-install)").action(async () => {
3604
+ console.log(`Current version: ${MACRO.VERSION}`);
3605
+ console.log("Checking for updates...");
3606
+ const { getLatestVersion, getUpdateCommandSuggestions } = await import("./autoUpdater-63RAZ24N.js");
3607
+ const latestVersion = await getLatestVersion();
3608
+ if (!latestVersion) {
3609
+ console.error("Failed to check for updates");
3610
+ process.exit(1);
3611
+ }
3612
+ if (latestVersion === MACRO.VERSION) {
3613
+ console.log(`${PRODUCT_NAME} is up to date`);
3614
+ process.exit(0);
3615
+ }
3616
+ console.log(`New version available: ${latestVersion}`);
3617
+ const cmds = await getUpdateCommandSuggestions();
3618
+ console.log("\nRun one of the following commands to update:");
3619
+ for (const c of cmds) console.log(` ${c}`);
3620
+ if (process.platform !== "win32") {
3621
+ console.log(
3622
+ '\nNote: you may need to prefix with "sudo" on macOS/Linux.'
3623
+ );
3624
+ }
3625
+ process.exit(0);
3626
+ });
3627
+ program.command("log").description("Manage conversation logs.").argument(
3628
+ "[number]",
3629
+ "A number (0, 1, 2, etc.) to display a specific log",
3630
+ parseInt
3631
+ ).option("--cwd <cwd>", "The current working directory", String, cwd()).action(async (number, { cwd: cwd2 }) => {
3632
+ await setup(cwd2, false);
3633
+ const context2 = {};
3634
+ (async () => {
3635
+ const { render: render3 } = await import("ink");
3636
+ const { unmount } = render3(
3637
+ /* @__PURE__ */ React10.createElement(LogList, { context: context2, type: "messages", logNumber: number }),
3638
+ renderContextWithExitOnCtrlC
3639
+ );
3640
+ context2.unmount = unmount;
3641
+ })();
3642
+ });
3643
+ program.command("resume").description(
3644
+ "Resume a previous conversation. Optionally provide a session ID or session name (legacy: log index or file path)."
3645
+ ).argument(
3646
+ "[identifier]",
3647
+ "A session ID or session name (legacy: log index or file path)"
3648
+ ).option("--cwd <cwd>", "The current working directory", String, cwd()).option("-e, --enable-architect", "Enable the Architect tool", () => true).option("-v, --verbose", "Do not truncate message output", () => true).option(
3649
+ "--safe",
3650
+ "Enable strict permission checking mode (default is permissive)",
3651
+ () => true
3652
+ ).option(
3653
+ "--disable-slash-commands",
3654
+ "Disable slash commands (treat /... as plain text)",
3655
+ () => true
3656
+ ).action(
3657
+ async (identifier, { cwd: cwd2, enableArchitect, safe, verbose, disableSlashCommands }) => {
3658
+ await setup(cwd2, safe);
3659
+ assertMinVersion();
3660
+ const [{ getTools }, { getCommands }] = await Promise.all([
3661
+ import("./tools-BHW37PCF.js"),
3662
+ import("./commands-HOBCZ3VQ.js")
3663
+ ]);
3664
+ const [allTools, commands, mcpClients] = await Promise.all([
3665
+ getTools(
3666
+ enableArchitect ?? getCurrentProjectConfig().enableArchitectTool
3667
+ ),
3668
+ getCommands(),
3669
+ getClients()
3670
+ ]);
3671
+ const tools = disableSlashCommands === true ? allTools.filter((t) => t.name !== "SlashCommand") : allTools;
3672
+ if (identifier !== void 0) {
3673
+ const { loadDanyaAgentSessionMessages } = await import("./kodeAgentSessionLoad-KR4JSD6D.js");
3674
+ const { resolveResumeSessionIdentifier } = await import("./kodeAgentSessionResume-BCD6UV74.js");
3675
+ const { setDanyaAgentSessionId } = await import("./kodeAgentSessionId-WUT74FSH.js");
3676
+ const rawIdentifier = String(identifier).trim();
3677
+ const isLegacyNumber = /^-?\\d+$/.test(rawIdentifier);
3678
+ const isLegacyPath = !isLegacyNumber && existsSync(rawIdentifier);
3679
+ let messages;
3680
+ let messageLogName = dateToFilename(/* @__PURE__ */ new Date());
3681
+ let initialForkNumber = void 0;
3682
+ try {
3683
+ if (isLegacyNumber || isLegacyPath) {
3684
+ const logs = await loadLogList(CACHE_PATHS.messages());
3685
+ if (isLegacyNumber) {
3686
+ const number = Math.abs(parseInt(rawIdentifier, 10));
3687
+ const log = logs[number];
3688
+ if (!log) {
3689
+ console.error("No conversation found at index", number);
3690
+ process.exit(1);
3691
+ }
3692
+ messages = await loadMessagesFromLog(log.fullPath, tools);
3693
+ messageLogName = log.date;
3694
+ initialForkNumber = getNextAvailableLogForkNumber(
3695
+ log.date,
3696
+ log.forkNumber ?? 1,
3697
+ 0
3698
+ );
3699
+ } else {
3700
+ messages = await loadMessagesFromLog(rawIdentifier, tools);
3701
+ const pathSegments = rawIdentifier.split("/");
3702
+ const filename = pathSegments[pathSegments.length - 1] ?? "unknown";
3703
+ const { date, forkNumber } = parseLogFilename(filename);
3704
+ messageLogName = date;
3705
+ initialForkNumber = getNextAvailableLogForkNumber(
3706
+ date,
3707
+ forkNumber ?? 1,
3708
+ 0
3709
+ );
3710
+ }
3711
+ } else {
3712
+ const resolved = resolveResumeSessionIdentifier({
3713
+ cwd: cwd2,
3714
+ identifier: rawIdentifier
3715
+ });
3716
+ if (resolved.kind === "ok") {
3717
+ setDanyaAgentSessionId(resolved.sessionId);
3718
+ messages = loadDanyaAgentSessionMessages({
3719
+ cwd: cwd2,
3720
+ sessionId: resolved.sessionId
3721
+ });
3722
+ } else if (resolved.kind === "different_directory") {
3723
+ console.error(
3724
+ resolved.otherCwd ? `Error: That session belongs to a different directory: ${resolved.otherCwd}` : `Error: That session belongs to a different directory.`
3725
+ );
3726
+ process.exit(1);
3727
+ } else if (resolved.kind === "ambiguous") {
3728
+ console.error(
3729
+ `Error: Multiple sessions match "${rawIdentifier}": ${resolved.matchingSessionIds.join(
3730
+ ", "
3731
+ )}`
3732
+ );
3733
+ process.exit(1);
3734
+ } else {
3735
+ console.error(
3736
+ `No conversation found with session ID or name: ${rawIdentifier}`
3737
+ );
3738
+ process.exit(1);
3739
+ }
3740
+ }
3741
+ const isDefaultModel = await isDefaultSlowAndCapableModel();
3742
+ {
3743
+ const { render: render3 } = await import("ink");
3744
+ const { REPL } = await import("./REPL-EYUOXCEC.js");
3745
+ render3(
3746
+ /* @__PURE__ */ React10.createElement(
3747
+ REPL,
3748
+ {
3749
+ initialPrompt: "",
3750
+ messageLogName,
3751
+ initialForkNumber,
3752
+ shouldShowPromptInput: true,
3753
+ verbose,
3754
+ commands,
3755
+ disableSlashCommands: disableSlashCommands === true,
3756
+ tools,
3757
+ safeMode: safe,
3758
+ initialMessages: messages,
3759
+ mcpClients,
3760
+ isDefaultModel
3761
+ }
3762
+ ),
3763
+ { exitOnCtrlC: false }
3764
+ );
3765
+ }
3766
+ } catch (error) {
3767
+ logError(`Failed to load conversation: ${error}`);
3768
+ process.exit(1);
3769
+ }
3770
+ } else {
3771
+ const { listDanyaAgentSessions } = await import("./kodeAgentSessionResume-BCD6UV74.js");
3772
+ const sessions = listDanyaAgentSessions({ cwd: cwd2 });
3773
+ if (sessions.length === 0) {
3774
+ console.error("No conversation found to resume");
3775
+ process.exit(1);
3776
+ }
3777
+ const context2 = {};
3778
+ (async () => {
3779
+ const { render: render3 } = await import("ink");
3780
+ const { unmount } = render3(
3781
+ /* @__PURE__ */ React10.createElement(
3782
+ ResumeConversation,
3783
+ {
3784
+ cwd: cwd2,
3785
+ context: context2,
3786
+ commands,
3787
+ sessions,
3788
+ tools,
3789
+ verbose,
3790
+ safeMode: safe,
3791
+ disableSlashCommands: disableSlashCommands === true,
3792
+ mcpClients,
3793
+ initialPrompt: ""
3794
+ }
3795
+ ),
3796
+ renderContextWithExitOnCtrlC
3797
+ );
3798
+ context2.unmount = unmount;
3799
+ })();
3800
+ }
3801
+ }
3802
+ );
3803
+ program.command("error").description(
3804
+ "View error logs. Optionally provide a number (0, -1, -2, etc.) to display a specific log."
3805
+ ).argument(
3806
+ "[number]",
3807
+ "A number (0, 1, 2, etc.) to display a specific log",
3808
+ parseInt
3809
+ ).option("--cwd <cwd>", "The current working directory", String, cwd()).action(async (number, { cwd: cwd2 }) => {
3810
+ await setup(cwd2, false);
3811
+ const context2 = {};
3812
+ (async () => {
3813
+ const { render: render3 } = await import("ink");
3814
+ const { unmount } = render3(
3815
+ /* @__PURE__ */ React10.createElement(LogList, { context: context2, type: "errors", logNumber: number }),
3816
+ renderContextWithExitOnCtrlC
3817
+ );
3818
+ context2.unmount = unmount;
3819
+ })();
3820
+ });
3821
+ const context = program.command("context").description(
3822
+ `Set static context (eg. ${PRODUCT_COMMAND} context add-file ./src/*.py)`
3823
+ );
3824
+ context.command("get <key>").option("--cwd <cwd>", "The current working directory", String, cwd()).description("Get a value from context").action(async (key, { cwd: cwd2 }) => {
3825
+ await setup(cwd2, false);
3826
+ const context2 = omitKeys(
3827
+ await getContext(),
3828
+ "codeStyle",
3829
+ "directoryStructure"
3830
+ );
3831
+ console.log(context2[key]);
3832
+ process.exit(0);
3833
+ });
3834
+ context.command("set <key> <value>").description("Set a value in context").option("--cwd <cwd>", "The current working directory", String, cwd()).action(async (key, value, { cwd: cwd2 }) => {
3835
+ await setup(cwd2, false);
3836
+ setContext(key, value);
3837
+ console.log(`Set context.${key} to "${value}"`);
3838
+ process.exit(0);
3839
+ });
3840
+ context.command("list").description("List all context values").option("--cwd <cwd>", "The current working directory", String, cwd()).action(async ({ cwd: cwd2 }) => {
3841
+ await setup(cwd2, false);
3842
+ const context2 = omitKeys(
3843
+ await getContext(),
3844
+ "codeStyle",
3845
+ "directoryStructure",
3846
+ "gitStatus"
3847
+ );
3848
+ console.log(JSON.stringify(context2, null, 2));
3849
+ process.exit(0);
3850
+ });
3851
+ context.command("remove <key>").description("Remove a value from context").option("--cwd <cwd>", "The current working directory", String, cwd()).action(async (key, { cwd: cwd2 }) => {
3852
+ await setup(cwd2, false);
3853
+ removeContext(key);
3854
+ console.log(`Removed context.${key}`);
3855
+ process.exit(0);
3856
+ });
3857
+ await program.parseAsync(process.argv);
3858
+ return program;
3859
+ }
3860
+ async function stdin() {
3861
+ if (process.stdin.isTTY) {
3862
+ return "";
3863
+ }
3864
+ let data = "";
3865
+ for await (const chunk of process.stdin) data += chunk;
3866
+ return data;
3867
+ }
3868
+ var isGracefulExitInProgress = false;
3869
+ async function gracefulExit(code = 0) {
3870
+ if (isGracefulExitInProgress) {
3871
+ process.exit(code);
3872
+ return;
3873
+ }
3874
+ isGracefulExitInProgress = true;
3875
+ try {
3876
+ const { runSessionEndHooks } = await import("./kodeHooks-EHM6GSIQ.js");
3877
+ const { getDanyaAgentSessionId } = await import("./kodeAgentSessionId-WUT74FSH.js");
3878
+ const { tmpdir } = await import("os");
3879
+ const { join: join2 } = await import("path");
3880
+ const sessionId = getDanyaAgentSessionId();
3881
+ const transcriptPath = join2(
3882
+ tmpdir(),
3883
+ "danya-hooks-transcripts",
3884
+ `${sessionId}.transcript.txt`
3885
+ );
3886
+ const { signal, cleanup } = (() => {
3887
+ if (typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function") {
3888
+ return {
3889
+ signal: AbortSignal.timeout(5e3),
3890
+ cleanup: () => {
3891
+ }
3892
+ };
3893
+ }
3894
+ const controller = new AbortController();
3895
+ const timer = setTimeout(() => controller.abort(), 5e3);
3896
+ return { signal: controller.signal, cleanup: () => clearTimeout(timer) };
3897
+ })();
3898
+ try {
3899
+ await runSessionEndHooks({
3900
+ reason: "exit",
3901
+ cwd: cwd(),
3902
+ transcriptPath,
3903
+ signal
3904
+ });
3905
+ } finally {
3906
+ cleanup();
3907
+ }
3908
+ } catch {
3909
+ }
3910
+ try {
3911
+ resetCursor();
3912
+ } catch {
3913
+ }
3914
+ try {
3915
+ BunShell.getInstance().close();
3916
+ } catch {
3917
+ }
3918
+ process.exit(code);
3919
+ }
3920
+ var didInstallProcessHandlers = false;
3921
+ function installProcessHandlers() {
3922
+ if (didInstallProcessHandlers) return;
3923
+ didInstallProcessHandlers = true;
3924
+ process.on("exit", () => {
3925
+ resetCursor();
3926
+ BunShell.getInstance().close();
3927
+ });
3928
+ process.on("SIGINT", () => void gracefulExit(0));
3929
+ process.on("SIGTERM", () => void gracefulExit(0));
3930
+ process.on("SIGBREAK", () => void gracefulExit(0));
3931
+ process.on("unhandledRejection", (err) => {
3932
+ console.error("Unhandled rejection:", err);
3933
+ void gracefulExit(1);
3934
+ });
3935
+ process.on("uncaughtException", (err) => {
3936
+ console.error("Uncaught exception:", err);
3937
+ void gracefulExit(1);
3938
+ });
3939
+ }
3940
+ function resetCursor() {
3941
+ const terminal = process.stderr.isTTY ? process.stderr : process.stdout.isTTY ? process.stdout : void 0;
3942
+ terminal?.write(`\x1B[?25h${cursorShow}`);
3943
+ }
3944
+
3945
+ // src/entrypoints/cli.tsx
3946
+ import * as dontcare from "@anthropic-ai/sdk/shims/node";
3947
+ initSentry();
3948
+ ensurePackagedRuntimeEnv();
3949
+ ensureYogaWasmPath(import.meta.url);
3950
+ Object.keys(dontcare);
3951
+ installProcessHandlers();
3952
+ void runCli();