siclaw 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (270) hide show
  1. package/README.md +75 -114
  2. package/dist/agentbox/gateway-client.d.ts +2 -1
  3. package/dist/agentbox/gateway-client.js +6 -2
  4. package/dist/agentbox/gateway-client.js.map +1 -1
  5. package/dist/agentbox/http-server.js +184 -19
  6. package/dist/agentbox/http-server.js.map +1 -1
  7. package/dist/agentbox/resource-handlers.d.ts +1 -0
  8. package/dist/agentbox/resource-handlers.js +23 -23
  9. package/dist/agentbox/resource-handlers.js.map +1 -1
  10. package/dist/agentbox/session.js +85 -5
  11. package/dist/agentbox/session.js.map +1 -1
  12. package/dist/agentbox-main.d.ts +2 -1
  13. package/dist/agentbox-main.js +65 -18
  14. package/dist/agentbox-main.js.map +1 -1
  15. package/dist/cli-credentials.d.ts +1 -0
  16. package/dist/cli-credentials.js +109 -0
  17. package/dist/cli-credentials.js.map +1 -0
  18. package/dist/cli-first-run.d.ts +11 -0
  19. package/dist/cli-first-run.js +99 -0
  20. package/dist/cli-first-run.js.map +1 -0
  21. package/dist/cli-main.js +33 -11
  22. package/dist/cli-main.js.map +1 -1
  23. package/dist/cli-setup.d.ts +5 -11
  24. package/dist/cli-setup.js +12 -225
  25. package/dist/cli-setup.js.map +1 -1
  26. package/dist/core/agent-factory.d.ts +4 -0
  27. package/dist/core/agent-factory.js +102 -151
  28. package/dist/core/agent-factory.js.map +1 -1
  29. package/dist/core/config.d.ts +10 -3
  30. package/dist/core/config.js +11 -95
  31. package/dist/core/config.js.map +1 -1
  32. package/dist/core/extensions/deep-investigation.d.ts +2 -1
  33. package/dist/core/extensions/deep-investigation.js +144 -24
  34. package/dist/core/extensions/deep-investigation.js.map +1 -1
  35. package/dist/core/extensions/setup.d.ts +8 -0
  36. package/dist/core/extensions/setup.js +669 -0
  37. package/dist/core/extensions/setup.js.map +1 -0
  38. package/dist/core/llm-proxy.js +7 -3
  39. package/dist/core/llm-proxy.js.map +1 -1
  40. package/dist/core/mcp-client.d.ts +0 -10
  41. package/dist/core/mcp-client.js +0 -65
  42. package/dist/core/mcp-client.js.map +1 -1
  43. package/dist/core/prompt.d.ts +1 -1
  44. package/dist/core/prompt.js +42 -5
  45. package/dist/core/prompt.js.map +1 -1
  46. package/dist/core/provider-presets.d.ts +14 -0
  47. package/dist/core/provider-presets.js +81 -0
  48. package/dist/core/provider-presets.js.map +1 -0
  49. package/dist/cron/cron-coordinator.d.ts +2 -0
  50. package/dist/cron/cron-coordinator.js +46 -14
  51. package/dist/cron/cron-coordinator.js.map +1 -1
  52. package/dist/cron/cron-executor.js +33 -8
  53. package/dist/cron/cron-executor.js.map +1 -1
  54. package/dist/cron/cron-scheduler.d.ts +1 -1
  55. package/dist/cron/gateway-client.d.ts +5 -0
  56. package/dist/cron/gateway-client.js +43 -8
  57. package/dist/cron/gateway-client.js.map +1 -1
  58. package/dist/cron-main.js +39 -9
  59. package/dist/cron-main.js.map +1 -1
  60. package/dist/gateway/agentbox/client.d.ts +11 -0
  61. package/dist/gateway/agentbox/client.js +18 -0
  62. package/dist/gateway/agentbox/client.js.map +1 -1
  63. package/dist/gateway/agentbox/k8s-spawner.d.ts +11 -2
  64. package/dist/gateway/agentbox/k8s-spawner.js +95 -52
  65. package/dist/gateway/agentbox/k8s-spawner.js.map +1 -1
  66. package/dist/gateway/agentbox/local-spawner.d.ts +1 -1
  67. package/dist/gateway/agentbox/local-spawner.js +4 -2
  68. package/dist/gateway/agentbox/local-spawner.js.map +1 -1
  69. package/dist/gateway/agentbox/manager.d.ts +0 -10
  70. package/dist/gateway/agentbox/manager.js +11 -30
  71. package/dist/gateway/agentbox/manager.js.map +1 -1
  72. package/dist/gateway/agentbox/types.d.ts +6 -4
  73. package/dist/gateway/cron/cron-service.d.ts +49 -0
  74. package/dist/gateway/cron/cron-service.js +259 -0
  75. package/dist/gateway/cron/cron-service.js.map +1 -0
  76. package/dist/gateway/db/init-schema.js +44 -0
  77. package/dist/gateway/db/init-schema.js.map +1 -1
  78. package/dist/gateway/db/migrate-sqlite.js +73 -4
  79. package/dist/gateway/db/migrate-sqlite.js.map +1 -1
  80. package/dist/gateway/db/repositories/chat-repo.d.ts +56 -2
  81. package/dist/gateway/db/repositories/chat-repo.js +132 -2
  82. package/dist/gateway/db/repositories/chat-repo.js.map +1 -1
  83. package/dist/gateway/db/repositories/config-repo.d.ts +31 -2
  84. package/dist/gateway/db/repositories/config-repo.js +57 -7
  85. package/dist/gateway/db/repositories/config-repo.js.map +1 -1
  86. package/dist/gateway/db/repositories/env-repo.d.ts +14 -0
  87. package/dist/gateway/db/repositories/env-repo.js +15 -2
  88. package/dist/gateway/db/repositories/env-repo.js.map +1 -1
  89. package/dist/gateway/db/repositories/model-config-repo.d.ts +1 -1
  90. package/dist/gateway/db/repositories/model-config-repo.js +26 -12
  91. package/dist/gateway/db/repositories/model-config-repo.js.map +1 -1
  92. package/dist/gateway/db/repositories/skill-repo.d.ts +0 -5
  93. package/dist/gateway/db/repositories/skill-review-repo.d.ts +1 -0
  94. package/dist/gateway/db/repositories/skill-review-repo.js +4 -1
  95. package/dist/gateway/db/repositories/skill-review-repo.js.map +1 -1
  96. package/dist/gateway/db/repositories/skill-version-repo.js +0 -1
  97. package/dist/gateway/db/repositories/skill-version-repo.js.map +1 -1
  98. package/dist/gateway/db/repositories/system-config-repo.d.ts +1 -1
  99. package/dist/gateway/db/repositories/system-config-repo.js +2 -1
  100. package/dist/gateway/db/repositories/system-config-repo.js.map +1 -1
  101. package/dist/gateway/db/repositories/user-env-config-repo.d.ts +13 -0
  102. package/dist/gateway/db/repositories/user-env-config-repo.js +11 -0
  103. package/dist/gateway/db/repositories/user-env-config-repo.js.map +1 -1
  104. package/dist/gateway/db/repositories/workspace-repo.d.ts +3 -2
  105. package/dist/gateway/db/repositories/workspace-repo.js +6 -2
  106. package/dist/gateway/db/repositories/workspace-repo.js.map +1 -1
  107. package/dist/gateway/db/schema-mysql.d.ts +473 -51
  108. package/dist/gateway/db/schema-mysql.js +35 -4
  109. package/dist/gateway/db/schema-mysql.js.map +1 -1
  110. package/dist/gateway/db/schema-sqlite.d.ts +522 -57
  111. package/dist/gateway/db/schema-sqlite.js +38 -6
  112. package/dist/gateway/db/schema-sqlite.js.map +1 -1
  113. package/dist/gateway/db/schema.d.ts +471 -51
  114. package/dist/gateway/db/schema.js +1 -1
  115. package/dist/gateway/db/schema.js.map +1 -1
  116. package/dist/gateway/metrics-aggregator.d.ts +65 -0
  117. package/dist/gateway/metrics-aggregator.js +244 -0
  118. package/dist/gateway/metrics-aggregator.js.map +1 -0
  119. package/dist/gateway/plugins/channel-bridge.d.ts +4 -1
  120. package/dist/gateway/plugins/channel-bridge.js +78 -86
  121. package/dist/gateway/plugins/channel-bridge.js.map +1 -1
  122. package/dist/gateway/rpc-methods.d.ts +4 -2
  123. package/dist/gateway/rpc-methods.js +962 -163
  124. package/dist/gateway/rpc-methods.js.map +1 -1
  125. package/dist/gateway/security/cert-manager.d.ts +2 -2
  126. package/dist/gateway/security/cert-manager.js +4 -2
  127. package/dist/gateway/security/cert-manager.js.map +1 -1
  128. package/dist/gateway/server.d.ts +4 -8
  129. package/dist/gateway/server.js +297 -261
  130. package/dist/gateway/server.js.map +1 -1
  131. package/dist/gateway/skills/file-writer.js +17 -11
  132. package/dist/gateway/skills/file-writer.js.map +1 -1
  133. package/dist/gateway/skills/script-evaluator.js +12 -9
  134. package/dist/gateway/skills/script-evaluator.js.map +1 -1
  135. package/dist/gateway/web/dist/assets/index-0p17ZeTP.js +740 -0
  136. package/dist/gateway/web/dist/assets/index-9eP6nPUq.js +741 -0
  137. package/dist/gateway/web/dist/assets/index-9eP6nPUq.js.map +1 -0
  138. package/dist/gateway/web/dist/assets/index-CAmSY91d.js +675 -0
  139. package/dist/gateway/web/dist/assets/index-DMFEh8Pp.css +1 -0
  140. package/dist/gateway/web/dist/assets/index-DyowBCEj.css +1 -0
  141. package/dist/gateway/web/dist/assets/index-PDK5JJDO.css +1 -0
  142. package/dist/gateway/web/dist/index.html +2 -2
  143. package/dist/gateway-main.js +27 -10
  144. package/dist/gateway-main.js.map +1 -1
  145. package/dist/memory/embeddings.js +5 -4
  146. package/dist/memory/embeddings.js.map +1 -1
  147. package/dist/memory/indexer.d.ts +23 -3
  148. package/dist/memory/indexer.js +235 -23
  149. package/dist/memory/indexer.js.map +1 -1
  150. package/dist/memory/schema.js +15 -1
  151. package/dist/memory/schema.js.map +1 -1
  152. package/dist/memory/types.d.ts +18 -0
  153. package/dist/memory/types.js +6 -1
  154. package/dist/memory/types.js.map +1 -1
  155. package/dist/shared/detect-language.d.ts +12 -0
  156. package/dist/shared/detect-language.js +78 -0
  157. package/dist/shared/detect-language.js.map +1 -0
  158. package/dist/shared/diagnostic-events.d.ts +70 -0
  159. package/dist/shared/diagnostic-events.js +38 -0
  160. package/dist/shared/diagnostic-events.js.map +1 -0
  161. package/dist/shared/local-collector.d.ts +56 -0
  162. package/dist/shared/local-collector.js +284 -0
  163. package/dist/shared/local-collector.js.map +1 -0
  164. package/dist/shared/metrics-types.d.ts +64 -0
  165. package/dist/shared/metrics-types.js +25 -0
  166. package/dist/shared/metrics-types.js.map +1 -0
  167. package/dist/shared/metrics.d.ts +19 -0
  168. package/dist/shared/metrics.js +185 -0
  169. package/dist/shared/metrics.js.map +1 -0
  170. package/dist/shared/path-utils.d.ts +15 -0
  171. package/dist/shared/path-utils.js +23 -0
  172. package/dist/shared/path-utils.js.map +1 -0
  173. package/dist/shared/retry.d.ts +35 -0
  174. package/dist/shared/retry.js +61 -0
  175. package/dist/shared/retry.js.map +1 -0
  176. package/dist/tools/command-sets.d.ts +18 -2
  177. package/dist/tools/command-sets.js +207 -32
  178. package/dist/tools/command-sets.js.map +1 -1
  179. package/dist/tools/command-validator.d.ts +56 -0
  180. package/dist/tools/command-validator.js +357 -0
  181. package/dist/tools/command-validator.js.map +1 -0
  182. package/dist/tools/create-skill.js +26 -1
  183. package/dist/tools/create-skill.js.map +1 -1
  184. package/dist/tools/credential-list.js +1 -23
  185. package/dist/tools/credential-list.js.map +1 -1
  186. package/dist/tools/credential-manager.d.ts +98 -0
  187. package/dist/tools/credential-manager.js +313 -0
  188. package/dist/tools/credential-manager.js.map +1 -0
  189. package/dist/tools/deep-search/engine.js +184 -127
  190. package/dist/tools/deep-search/engine.js.map +1 -1
  191. package/dist/tools/deep-search/prompts.d.ts +10 -2
  192. package/dist/tools/deep-search/prompts.js +37 -36
  193. package/dist/tools/deep-search/prompts.js.map +1 -1
  194. package/dist/tools/deep-search/schemas.d.ts +87 -0
  195. package/dist/tools/deep-search/schemas.js +85 -0
  196. package/dist/tools/deep-search/schemas.js.map +1 -0
  197. package/dist/tools/deep-search/sub-agent.d.ts +21 -0
  198. package/dist/tools/deep-search/sub-agent.js +153 -4
  199. package/dist/tools/deep-search/sub-agent.js.map +1 -1
  200. package/dist/tools/deep-search/tool.js +1 -0
  201. package/dist/tools/deep-search/tool.js.map +1 -1
  202. package/dist/tools/deep-search/types.d.ts +2 -0
  203. package/dist/tools/deep-search/types.js.map +1 -1
  204. package/dist/tools/dp-tools.js +29 -5
  205. package/dist/tools/dp-tools.js.map +1 -1
  206. package/dist/tools/exec-utils.d.ts +85 -0
  207. package/dist/tools/exec-utils.js +294 -0
  208. package/dist/tools/exec-utils.js.map +1 -0
  209. package/dist/tools/fork-skill.js +14 -2
  210. package/dist/tools/fork-skill.js.map +1 -1
  211. package/dist/tools/investigation-feedback.d.ts +3 -0
  212. package/dist/tools/investigation-feedback.js +71 -0
  213. package/dist/tools/investigation-feedback.js.map +1 -0
  214. package/dist/tools/manage-schedule.js +16 -6
  215. package/dist/tools/manage-schedule.js.map +1 -1
  216. package/dist/tools/netns-script.js +27 -281
  217. package/dist/tools/netns-script.js.map +1 -1
  218. package/dist/tools/node-exec.d.ts +2 -14
  219. package/dist/tools/node-exec.js +18 -225
  220. package/dist/tools/node-exec.js.map +1 -1
  221. package/dist/tools/node-script.js +14 -168
  222. package/dist/tools/node-script.js.map +1 -1
  223. package/dist/tools/pod-exec.d.ts +1 -1
  224. package/dist/tools/pod-exec.js +10 -26
  225. package/dist/tools/pod-exec.js.map +1 -1
  226. package/dist/tools/pod-nsenter-exec.js +21 -225
  227. package/dist/tools/pod-nsenter-exec.js.map +1 -1
  228. package/dist/tools/pod-script.js +10 -19
  229. package/dist/tools/pod-script.js.map +1 -1
  230. package/dist/tools/restricted-bash.d.ts +1 -17
  231. package/dist/tools/restricted-bash.js +38 -252
  232. package/dist/tools/restricted-bash.js.map +1 -1
  233. package/dist/tools/run-skill.d.ts +3 -1
  234. package/dist/tools/run-skill.js +21 -1
  235. package/dist/tools/run-skill.js.map +1 -1
  236. package/dist/tools/script-resolver.d.ts +3 -1
  237. package/dist/tools/script-resolver.js +74 -30
  238. package/dist/tools/script-resolver.js.map +1 -1
  239. package/dist/tools/update-skill.js +17 -6
  240. package/dist/tools/update-skill.js.map +1 -1
  241. package/package.json +8 -6
  242. package/siclaw.mjs +10 -1
  243. package/skills/core/cluster-events/SKILL.md +1 -1
  244. package/skills/core/deep-investigation/SKILL.md +11 -0
  245. package/skills/core/deployment-rollout-debug/SKILL.md +1 -1
  246. package/skills/core/dns-debug/SKILL.md +1 -0
  247. package/skills/core/meta.json +12 -1
  248. package/skills/core/networkpolicy-debug/SKILL.md +332 -0
  249. package/skills/core/node-logs/scripts/get-node-logs.sh +19 -9
  250. package/skills/core/pod-pending-debug/SKILL.md +1 -0
  251. package/skills/core/quota-debug/SKILL.md +203 -0
  252. package/skills/core/service-debug/SKILL.md +1 -0
  253. package/skills/core/statefulset-debug/SKILL.md +280 -0
  254. package/skills/core/volcano-diagnose-pod/SKILL.md +196 -0
  255. package/skills/core/volcano-diagnose-pod/scripts/diagnose-pod.sh +175 -0
  256. package/skills/core/volcano-gang-scheduling/SKILL.md +299 -0
  257. package/skills/core/volcano-job-diagnose/SKILL.md +319 -0
  258. package/skills/core/volcano-job-diagnose/scripts/diagnose-job.sh +253 -0
  259. package/skills/core/volcano-node-resources/SKILL.md +334 -0
  260. package/skills/core/volcano-node-resources/scripts/get-node-resources.sh +281 -0
  261. package/skills/core/volcano-queue-diagnose/SKILL.md +294 -0
  262. package/skills/core/volcano-queue-diagnose/scripts/diagnose-queue.sh +283 -0
  263. package/skills/core/volcano-resource-insufficient/SKILL.md +315 -0
  264. package/skills/core/volcano-scheduler-config/SKILL.md +371 -0
  265. package/skills/core/volcano-scheduler-config/scripts/get-scheduler-config.sh +297 -0
  266. package/skills/core/volcano-scheduler-logs/SKILL.md +241 -0
  267. package/skills/core/volcano-scheduler-logs/scripts/get-scheduler-logs.sh +159 -0
  268. package/skills/platform/create-skill/SKILL.md +35 -3
  269. package/skills/platform/manage-skill/SKILL.md +9 -2
  270. package/skills/platform/update-skill/SKILL.md +17 -6
@@ -0,0 +1,669 @@
1
+ /**
2
+ * /setup extension — in-session environment configuration for TUI mode.
3
+ *
4
+ * Provides credential management (kubeconfig, SSH, API tokens) and
5
+ * model provider configuration via interactive dialogs.
6
+ */
7
+ import fs from "node:fs";
8
+ import path from "node:path";
9
+ import { listCredentials, registerKubeconfig, registerSshPassword, registerSshKey, registerApiToken, registerApiBasicAuth, removeCredential, probeKubeconfig, } from "../../tools/credential-manager.js";
10
+ import { getConfigPath, loadConfig, reloadConfig, } from "../config.js";
11
+ import { PRESETS } from "../provider-presets.js";
12
+ // ---------------------------------------------------------------------------
13
+ // Credential type labels
14
+ // ---------------------------------------------------------------------------
15
+ const CREDENTIAL_TYPE_LABELS = {
16
+ kubeconfig: "Kubeconfig",
17
+ ssh_password: "SSH Password",
18
+ ssh_key: "SSH Key",
19
+ api_token: "API Token",
20
+ api_basic_auth: "API Basic Auth",
21
+ };
22
+ // ---------------------------------------------------------------------------
23
+ // Extension factory
24
+ // ---------------------------------------------------------------------------
25
+ export default function setupExtension(api, credentialsDir) {
26
+ // --- Status bar: show config summary on session start ---
27
+ api.on("session_start", async (_event, ctx) => {
28
+ updateSetupStatus(ctx, credentialsDir);
29
+ });
30
+ api.registerCommand("setup", {
31
+ description: "Configure credentials and model provider",
32
+ handler: async (_args, ctx) => {
33
+ if (!ctx.hasUI) {
34
+ ctx.ui.notify("Use web UI to manage credentials", "warning");
35
+ return;
36
+ }
37
+ // Main menu loop
38
+ let running = true;
39
+ while (running) {
40
+ const action = await ctx.ui.select("Setup", [
41
+ "Credentials",
42
+ "Models",
43
+ "Exit",
44
+ ]);
45
+ if (!action || action === "Exit") {
46
+ running = false;
47
+ continue;
48
+ }
49
+ switch (action) {
50
+ case "Credentials":
51
+ await credentialsSubmenu(ctx, credentialsDir);
52
+ break;
53
+ case "Models":
54
+ await modelsSubmenu(ctx);
55
+ break;
56
+ }
57
+ }
58
+ // Refresh status bar after any config changes
59
+ updateSetupStatus(ctx, credentialsDir);
60
+ },
61
+ });
62
+ }
63
+ // ---------------------------------------------------------------------------
64
+ // Sub-menus
65
+ // ---------------------------------------------------------------------------
66
+ async function credentialsSubmenu(ctx, credentialsDir) {
67
+ let running = true;
68
+ while (running) {
69
+ const action = await ctx.ui.select("Credentials", [
70
+ "Add",
71
+ "List",
72
+ "Remove",
73
+ "Back",
74
+ ]);
75
+ if (!action || action === "Back") {
76
+ running = false;
77
+ continue;
78
+ }
79
+ switch (action) {
80
+ case "Add":
81
+ await handleAddCredential(ctx, credentialsDir);
82
+ break;
83
+ case "List":
84
+ await handleListCredentials(ctx, credentialsDir);
85
+ break;
86
+ case "Remove":
87
+ await handleRemoveCredential(ctx, credentialsDir);
88
+ break;
89
+ }
90
+ }
91
+ }
92
+ async function modelsSubmenu(ctx) {
93
+ let running = true;
94
+ while (running) {
95
+ const action = await ctx.ui.select("Models", [
96
+ "List",
97
+ "Set default",
98
+ "Add model",
99
+ "Add provider",
100
+ "Remove model",
101
+ "Remove provider",
102
+ "Back",
103
+ ]);
104
+ if (!action || action === "Back") {
105
+ running = false;
106
+ continue;
107
+ }
108
+ switch (action) {
109
+ case "List":
110
+ handleListProviders(ctx);
111
+ break;
112
+ case "Set default":
113
+ await handleSetDefault(ctx);
114
+ break;
115
+ case "Add model":
116
+ await handleAddModel(ctx);
117
+ break;
118
+ case "Add provider":
119
+ await handleModelProvider(ctx);
120
+ break;
121
+ case "Remove model":
122
+ await handleRemoveModel(ctx);
123
+ break;
124
+ case "Remove provider":
125
+ await handleRemoveProvider(ctx);
126
+ break;
127
+ }
128
+ }
129
+ }
130
+ // ---------------------------------------------------------------------------
131
+ // Add credential flow
132
+ // ---------------------------------------------------------------------------
133
+ async function handleAddCredential(ctx, credentialsDir) {
134
+ const typeLabel = await ctx.ui.select("Credential Type", Object.values(CREDENTIAL_TYPE_LABELS));
135
+ if (!typeLabel)
136
+ return;
137
+ const type = (Object.entries(CREDENTIAL_TYPE_LABELS).find(([, label]) => label === typeLabel)?.[0] ?? "kubeconfig");
138
+ switch (type) {
139
+ case "kubeconfig":
140
+ await addKubeconfig(ctx, credentialsDir);
141
+ break;
142
+ case "ssh_password":
143
+ await addSshPassword(ctx, credentialsDir);
144
+ break;
145
+ case "ssh_key":
146
+ await addSshKey(ctx, credentialsDir);
147
+ break;
148
+ case "api_token":
149
+ await addApiToken(ctx, credentialsDir);
150
+ break;
151
+ case "api_basic_auth":
152
+ await addApiBasicAuth(ctx, credentialsDir);
153
+ break;
154
+ }
155
+ }
156
+ async function addKubeconfig(ctx, credentialsDir) {
157
+ const inputMethod = await ctx.ui.select("Kubeconfig source", [
158
+ "File path",
159
+ "Paste content",
160
+ ]);
161
+ if (!inputMethod)
162
+ return;
163
+ let kubeconfigContent;
164
+ let resolvedPath;
165
+ let defaultName = "cluster";
166
+ if (inputMethod === "Paste content") {
167
+ const raw = await ctx.ui.editor("Paste kubeconfig YAML/JSON");
168
+ if (!raw)
169
+ return;
170
+ kubeconfigContent = raw;
171
+ try {
172
+ const yamlMod = await import("js-yaml");
173
+ const kc = yamlMod.load(raw);
174
+ if (kc?.["current-context"]) {
175
+ defaultName = String(kc["current-context"]);
176
+ }
177
+ }
178
+ catch { /* use default */ }
179
+ }
180
+ else {
181
+ const sourcePath = await ctx.ui.input("Kubeconfig path", "~/.kube/config");
182
+ if (!sourcePath)
183
+ return;
184
+ resolvedPath = sourcePath.startsWith("~")
185
+ ? path.join(process.env.HOME ?? "", sourcePath.slice(1))
186
+ : path.resolve(sourcePath);
187
+ defaultName = path.basename(resolvedPath, path.extname(resolvedPath));
188
+ try {
189
+ const yamlMod = await import("js-yaml");
190
+ const content = fs.readFileSync(resolvedPath, "utf-8");
191
+ const kc = yamlMod.load(content);
192
+ if (kc?.["current-context"]) {
193
+ defaultName = String(kc["current-context"]);
194
+ }
195
+ }
196
+ catch { /* use filename */ }
197
+ }
198
+ const name = await ctx.ui.input("Credential name", defaultName);
199
+ if (!name)
200
+ return;
201
+ const result = registerKubeconfig(credentialsDir, {
202
+ name,
203
+ ...(kubeconfigContent ? { content: kubeconfigContent } : { sourcePath: resolvedPath }),
204
+ });
205
+ if (result.error || !result.entry) {
206
+ ctx.ui.notify(result.error ?? "Registration failed", "error");
207
+ return;
208
+ }
209
+ // Probe connectivity
210
+ const kubeconfigFile = path.join(credentialsDir, result.entry.files[0]);
211
+ ctx.ui.notify(`Probing ${name}...`);
212
+ const probe = await probeKubeconfig(kubeconfigFile);
213
+ if (probe.reachable) {
214
+ ctx.ui.notify(`Kubeconfig "${name}" added (server ${probe.version})`);
215
+ }
216
+ else {
217
+ ctx.ui.notify(`Kubeconfig "${name}" added but unreachable: ${probe.error}`, "warning");
218
+ }
219
+ }
220
+ async function addSshPassword(ctx, credentialsDir) {
221
+ const name = await ctx.ui.input("Credential name", "my-server");
222
+ if (!name)
223
+ return;
224
+ const host = await ctx.ui.input("Host", "192.168.1.100");
225
+ if (!host)
226
+ return;
227
+ const portStr = await ctx.ui.input("Port", "22");
228
+ const port = portStr ? parseInt(portStr, 10) : 22;
229
+ const username = await ctx.ui.input("Username", "root");
230
+ if (!username)
231
+ return;
232
+ const password = await ctx.ui.input("Password");
233
+ if (!password)
234
+ return;
235
+ try {
236
+ registerSshPassword(credentialsDir, { name, host, port, username, password });
237
+ }
238
+ catch (err) {
239
+ ctx.ui.notify(err instanceof Error ? err.message : String(err), "error");
240
+ return;
241
+ }
242
+ ctx.ui.notify(`SSH password credential "${name}" added`);
243
+ }
244
+ async function addSshKey(ctx, credentialsDir) {
245
+ const name = await ctx.ui.input("Credential name", "my-server");
246
+ if (!name)
247
+ return;
248
+ const host = await ctx.ui.input("Host", "192.168.1.100");
249
+ if (!host)
250
+ return;
251
+ const portStr = await ctx.ui.input("Port", "22");
252
+ const port = portStr ? parseInt(portStr, 10) : 22;
253
+ const username = await ctx.ui.input("Username", "root");
254
+ if (!username)
255
+ return;
256
+ const keyPath = await ctx.ui.input("Private key path", "~/.ssh/id_rsa");
257
+ if (!keyPath)
258
+ return;
259
+ const resolvedKey = keyPath.startsWith("~")
260
+ ? path.join(process.env.HOME ?? "", keyPath.slice(1))
261
+ : path.resolve(keyPath);
262
+ const { error } = registerSshKey(credentialsDir, {
263
+ name, host, port, username, keyPath: resolvedKey,
264
+ });
265
+ if (error) {
266
+ ctx.ui.notify(error, "error");
267
+ return;
268
+ }
269
+ ctx.ui.notify(`SSH key credential "${name}" added`);
270
+ }
271
+ async function addApiToken(ctx, credentialsDir) {
272
+ const name = await ctx.ui.input("Credential name", "my-api");
273
+ if (!name)
274
+ return;
275
+ const url = await ctx.ui.input("API base URL (optional)");
276
+ const token = await ctx.ui.input("Token");
277
+ if (!token)
278
+ return;
279
+ try {
280
+ registerApiToken(credentialsDir, { name, url: url || undefined, token });
281
+ }
282
+ catch (err) {
283
+ ctx.ui.notify(err instanceof Error ? err.message : String(err), "error");
284
+ return;
285
+ }
286
+ ctx.ui.notify(`API token credential "${name}" added`);
287
+ }
288
+ async function addApiBasicAuth(ctx, credentialsDir) {
289
+ const name = await ctx.ui.input("Credential name", "my-api");
290
+ if (!name)
291
+ return;
292
+ const url = await ctx.ui.input("API base URL (optional)");
293
+ const username = await ctx.ui.input("Username");
294
+ if (!username)
295
+ return;
296
+ const password = await ctx.ui.input("Password");
297
+ if (!password)
298
+ return;
299
+ try {
300
+ registerApiBasicAuth(credentialsDir, {
301
+ name, url: url || undefined, username, password,
302
+ });
303
+ }
304
+ catch (err) {
305
+ ctx.ui.notify(err instanceof Error ? err.message : String(err), "error");
306
+ return;
307
+ }
308
+ ctx.ui.notify(`API basic auth credential "${name}" added`);
309
+ }
310
+ // ---------------------------------------------------------------------------
311
+ // List credentials flow
312
+ // ---------------------------------------------------------------------------
313
+ async function handleListCredentials(ctx, credentialsDir) {
314
+ const entries = await listCredentials(credentialsDir);
315
+ if (entries.length === 0) {
316
+ ctx.ui.notify("No credentials configured. Use /setup to add one.");
317
+ return;
318
+ }
319
+ const lines = ["Credentials:"];
320
+ for (const e of entries) {
321
+ let status = "";
322
+ if (e.type === "kubeconfig") {
323
+ status = e.reachable ? ` [connected, ${e.server_version}]` : ` [unreachable: ${e.probe_error}]`;
324
+ }
325
+ lines.push(` ${e.name} (${e.type})${status}`);
326
+ }
327
+ ctx.ui.notify(lines.join("\n"));
328
+ }
329
+ // ---------------------------------------------------------------------------
330
+ // Remove credential flow
331
+ // ---------------------------------------------------------------------------
332
+ async function handleRemoveCredential(ctx, credentialsDir) {
333
+ const entries = await listCredentials(credentialsDir);
334
+ if (entries.length === 0) {
335
+ ctx.ui.notify("No credentials to remove.");
336
+ return;
337
+ }
338
+ const labels = entries.map((e) => `${e.name} (${e.type})`);
339
+ const selected = await ctx.ui.select("Remove credential", labels);
340
+ if (!selected)
341
+ return;
342
+ const idx = labels.indexOf(selected);
343
+ const name = entries[idx].name;
344
+ const confirmed = await ctx.ui.confirm("Confirm removal", `Remove credential "${name}" and its files?`);
345
+ if (!confirmed)
346
+ return;
347
+ const { removed } = removeCredential(credentialsDir, name);
348
+ if (removed) {
349
+ ctx.ui.notify(`Credential "${name}" removed`);
350
+ }
351
+ else {
352
+ ctx.ui.notify(`Credential "${name}" not found`, "warning");
353
+ }
354
+ }
355
+ // ---------------------------------------------------------------------------
356
+ // Config read/write helpers
357
+ // ---------------------------------------------------------------------------
358
+ /** Read the raw settings.json (not merged with defaults like loadConfig). */
359
+ function readRawConfig() {
360
+ const configPath = getConfigPath();
361
+ try {
362
+ return JSON.parse(fs.readFileSync(configPath, "utf-8"));
363
+ }
364
+ catch {
365
+ return {};
366
+ }
367
+ }
368
+ /** Write a partial config object back to settings.json and reload cache. */
369
+ function writeRawConfig(config) {
370
+ const configPath = getConfigPath();
371
+ const configDir = path.dirname(configPath);
372
+ if (!fs.existsSync(configDir)) {
373
+ fs.mkdirSync(configDir, { recursive: true, mode: 0o700 });
374
+ }
375
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", { mode: 0o600 });
376
+ reloadConfig();
377
+ }
378
+ function saveProviderToConfig(providerName, provider) {
379
+ const existing = readRawConfig();
380
+ const providers = existing.providers ?? {};
381
+ providers[providerName] = provider;
382
+ writeRawConfig({ ...existing, providers });
383
+ }
384
+ // ---------------------------------------------------------------------------
385
+ // List providers flow
386
+ // ---------------------------------------------------------------------------
387
+ function handleListProviders(ctx) {
388
+ const config = loadConfig();
389
+ const entries = Object.entries(config.providers);
390
+ if (entries.length === 0) {
391
+ ctx.ui.notify("No providers configured. Use /setup → Models → Add provider.");
392
+ return;
393
+ }
394
+ const defaultProvider = config.default?.provider ?? entries[0][0];
395
+ const defaultModelId = config.default?.modelId;
396
+ const lines = ["Providers:"];
397
+ for (const [name, provider] of entries) {
398
+ const isDefault = name === defaultProvider;
399
+ const models = provider.models.map((m, i) => {
400
+ const active = isDefault && (defaultModelId ? defaultModelId === m.id : i === 0);
401
+ return active ? `*${m.name || m.id}` : (m.name || m.id);
402
+ });
403
+ lines.push(` ${isDefault ? ">" : " "} ${name}: ${provider.baseUrl || "(no URL)"}`);
404
+ lines.push(` Models: ${models.join(", ")}`);
405
+ }
406
+ ctx.ui.notify(lines.join("\n"));
407
+ }
408
+ // ---------------------------------------------------------------------------
409
+ // Set default provider/model
410
+ // ---------------------------------------------------------------------------
411
+ async function handleSetDefault(ctx) {
412
+ const config = loadConfig();
413
+ const entries = Object.entries(config.providers);
414
+ if (entries.length === 0) {
415
+ ctx.ui.notify("No providers configured.", "warning");
416
+ return;
417
+ }
418
+ // Build flat list: "providerName / modelName (modelId)"
419
+ const options = [];
420
+ for (const [name, provider] of entries) {
421
+ for (const m of provider.models) {
422
+ options.push({
423
+ label: `${name} / ${m.name || m.id}`,
424
+ provider: name,
425
+ modelId: m.id,
426
+ });
427
+ }
428
+ }
429
+ const selected = await ctx.ui.select("Set default model", options.map((o) => o.label));
430
+ if (!selected)
431
+ return;
432
+ const choice = options.find((o) => o.label === selected);
433
+ if (!choice)
434
+ return;
435
+ // Write to config
436
+ const existing = readRawConfig();
437
+ existing.default = {
438
+ provider: choice.provider,
439
+ modelId: choice.modelId,
440
+ };
441
+ writeRawConfig(existing);
442
+ ctx.ui.notify(`Default set to: ${choice.provider} / ${choice.modelId}\nRestart session to activate.`);
443
+ }
444
+ // ---------------------------------------------------------------------------
445
+ // Remove provider flow
446
+ // ---------------------------------------------------------------------------
447
+ async function handleRemoveProvider(ctx) {
448
+ const config = loadConfig();
449
+ const entries = Object.entries(config.providers);
450
+ if (entries.length === 0) {
451
+ ctx.ui.notify("No providers to remove.");
452
+ return;
453
+ }
454
+ const labels = entries.map(([name, p]) => {
455
+ const model = p.models[0]?.name || p.models[0]?.id || "?";
456
+ return `${name} (${model})`;
457
+ });
458
+ const selected = await ctx.ui.select("Remove provider", labels);
459
+ if (!selected)
460
+ return;
461
+ const providerName = entries[labels.indexOf(selected)][0];
462
+ const confirmed = await ctx.ui.confirm("Confirm removal", `Remove provider "${providerName}"?`);
463
+ if (!confirmed)
464
+ return;
465
+ const existing = readRawConfig();
466
+ const providers = existing.providers ?? {};
467
+ delete providers[providerName];
468
+ // Clear default if it pointed to the removed provider
469
+ if (existing.default?.provider === providerName) {
470
+ delete existing.default;
471
+ }
472
+ writeRawConfig({ ...existing, providers });
473
+ ctx.ui.notify(`Provider "${providerName}" removed. Restart session to take effect.`);
474
+ }
475
+ // ---------------------------------------------------------------------------
476
+ // Configure provider flow
477
+ // ---------------------------------------------------------------------------
478
+ async function handleModelProvider(ctx) {
479
+ const presetLabel = await ctx.ui.select("Provider", PRESETS.map((p) => p.label));
480
+ if (!presetLabel)
481
+ return;
482
+ const preset = PRESETS.find((p) => p.label === presetLabel);
483
+ if (!preset)
484
+ return;
485
+ // Provider name — auto-derive for known presets, only ask for Compatible
486
+ let providerName;
487
+ if (preset.needsBaseUrl) {
488
+ const entered = await ctx.ui.input("Provider name");
489
+ if (!entered)
490
+ return;
491
+ providerName = entered.trim();
492
+ }
493
+ else {
494
+ providerName = preset.name;
495
+ }
496
+ // API Key
497
+ const apiKey = await ctx.ui.input("API Key");
498
+ if (!apiKey) {
499
+ ctx.ui.notify("API key is required", "warning");
500
+ return;
501
+ }
502
+ // Base URL
503
+ let baseUrl = preset.baseUrl;
504
+ if (preset.needsBaseUrl) {
505
+ const entered = await ctx.ui.input("Base URL");
506
+ if (!entered) {
507
+ ctx.ui.notify("Base URL is required", "warning");
508
+ return;
509
+ }
510
+ baseUrl = entered.trim();
511
+ }
512
+ else {
513
+ const entered = await ctx.ui.input("Base URL (Enter to keep default)", preset.baseUrl);
514
+ if (entered)
515
+ baseUrl = entered.trim();
516
+ }
517
+ // Model ID (for compatible APIs)
518
+ let models = preset.models;
519
+ if (preset.needsBaseUrl) {
520
+ const modelId = await ctx.ui.input("Model ID", "default");
521
+ if (modelId && modelId !== "default") {
522
+ const trimmed = modelId.trim();
523
+ models = [{ ...models[0], id: trimmed, name: trimmed }];
524
+ }
525
+ }
526
+ // Write config
527
+ const provider = {
528
+ baseUrl,
529
+ apiKey,
530
+ api: preset.api,
531
+ authHeader: true,
532
+ models,
533
+ };
534
+ saveProviderToConfig(providerName, provider);
535
+ const modelName = models[0].name || models[0].id;
536
+ ctx.ui.notify(`Provider "${providerName}" saved | Model: ${modelName}\nRestart session to activate.`);
537
+ }
538
+ // ---------------------------------------------------------------------------
539
+ // Add model to existing provider
540
+ // ---------------------------------------------------------------------------
541
+ async function handleAddModel(ctx) {
542
+ const config = loadConfig();
543
+ const entries = Object.entries(config.providers);
544
+ if (entries.length === 0) {
545
+ ctx.ui.notify("No providers configured. Use Add provider first.", "warning");
546
+ return;
547
+ }
548
+ // Select provider
549
+ const addLabels = entries.map(([name, p]) => `${name} (${p.baseUrl || "no URL"})`);
550
+ const providerLabel = await ctx.ui.select("Add model to", addLabels);
551
+ if (!providerLabel)
552
+ return;
553
+ const providerName = entries[addLabels.indexOf(providerLabel)][0];
554
+ // Model details
555
+ const rawModelId = await ctx.ui.input("Model ID");
556
+ if (!rawModelId)
557
+ return;
558
+ const modelId = rawModelId.trim();
559
+ const rawModelName = await ctx.ui.input("Model name", modelId);
560
+ const modelName = rawModelName ? rawModelName.trim() : modelId;
561
+ const ctxWindowStr = await ctx.ui.input("Context window", "128000");
562
+ const contextWindow = parseInt(ctxWindowStr || "128000", 10);
563
+ const maxTokensStr = await ctx.ui.input("Max output tokens", "8192");
564
+ const maxTokens = parseInt(maxTokensStr || "8192", 10);
565
+ // Read existing provider to inherit api type and compat defaults
566
+ const existingProvider = entries.find(([n]) => n === providerName)?.[1];
567
+ if (!existingProvider)
568
+ return;
569
+ const isAnthropic = existingProvider.api === "anthropic";
570
+ const newModel = {
571
+ id: modelId,
572
+ name: modelName || modelId,
573
+ reasoning: false,
574
+ input: ["text"],
575
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
576
+ contextWindow,
577
+ maxTokens,
578
+ compat: {
579
+ supportsDeveloperRole: !isAnthropic,
580
+ supportsUsageInStreaming: true,
581
+ maxTokensField: "max_tokens",
582
+ },
583
+ };
584
+ // Write to config
585
+ const existing = readRawConfig();
586
+ const providers = existing.providers ?? {};
587
+ if (!providers[providerName]) {
588
+ ctx.ui.notify(`Provider "${providerName}" not found`, "error");
589
+ return;
590
+ }
591
+ providers[providerName].models.push(newModel);
592
+ writeRawConfig({ ...existing, providers });
593
+ const allModels = providers[providerName].models.map((m) => m.name || m.id).join(", ");
594
+ ctx.ui.notify(`Model "${modelName || modelId}" added to "${providerName}".\nModels: ${allModels}\nRestart session to activate.`);
595
+ }
596
+ // ---------------------------------------------------------------------------
597
+ // Remove model from existing provider
598
+ // ---------------------------------------------------------------------------
599
+ async function handleRemoveModel(ctx) {
600
+ const config = loadConfig();
601
+ const entries = Object.entries(config.providers);
602
+ if (entries.length === 0) {
603
+ ctx.ui.notify("No providers configured.", "warning");
604
+ return;
605
+ }
606
+ // Select provider
607
+ const rmProvLabels = entries.map(([name, p]) => `${name} (${p.models.length} models)`);
608
+ const providerLabel = await ctx.ui.select("Remove model from", rmProvLabels);
609
+ if (!providerLabel)
610
+ return;
611
+ const provIdx = rmProvLabels.indexOf(providerLabel);
612
+ const providerName = entries[provIdx][0];
613
+ const provider = entries[provIdx][1];
614
+ if (provider.models.length <= 1) {
615
+ ctx.ui.notify(`Provider "${providerName}" has only one model. Remove the provider instead.`, "warning");
616
+ return;
617
+ }
618
+ // Select model
619
+ const modelLabels = provider.models.map((m) => `${m.name || m.id} (${m.id})`);
620
+ const modelLabel = await ctx.ui.select("Remove model", modelLabels);
621
+ if (!modelLabel)
622
+ return;
623
+ const modelIdx = modelLabels.indexOf(modelLabel);
624
+ const modelId = provider.models[modelIdx].id;
625
+ const confirmed = await ctx.ui.confirm("Confirm removal", `Remove model "${modelId}" from provider "${providerName}"?`);
626
+ if (!confirmed)
627
+ return;
628
+ // Write to config
629
+ const existing = readRawConfig();
630
+ const providers = existing.providers ?? {};
631
+ if (!providers[providerName]) {
632
+ ctx.ui.notify(`Provider "${providerName}" not found`, "error");
633
+ return;
634
+ }
635
+ providers[providerName].models = providers[providerName].models.filter((m) => m.id !== modelId);
636
+ writeRawConfig({ ...existing, providers });
637
+ const remaining = providers[providerName].models.map((m) => m.name || m.id).join(", ");
638
+ ctx.ui.notify(`Model "${modelId}" removed from "${providerName}".\nRemaining: ${remaining}\nRestart session to activate.`);
639
+ }
640
+ // ---------------------------------------------------------------------------
641
+ // Status bar helper
642
+ // ---------------------------------------------------------------------------
643
+ function updateSetupStatus(ctx, credentialsDir) {
644
+ const config = loadConfig();
645
+ // Count credentials
646
+ let credCount = 0;
647
+ try {
648
+ const manifestPath = path.join(credentialsDir, "manifest.json");
649
+ if (fs.existsSync(manifestPath)) {
650
+ credCount = JSON.parse(fs.readFileSync(manifestPath, "utf-8")).length;
651
+ }
652
+ }
653
+ catch { /* ignore */ }
654
+ // Count providers
655
+ const providerCount = Object.keys(config.providers).length;
656
+ // Build status parts
657
+ const missing = [];
658
+ if (providerCount === 0)
659
+ missing.push("model");
660
+ if (credCount === 0)
661
+ missing.push("credentials");
662
+ if (missing.length > 0) {
663
+ ctx.ui.setStatus("setup", `/setup: ${missing.join(" + ")} not configured`);
664
+ }
665
+ else {
666
+ ctx.ui.setStatus("setup", undefined);
667
+ }
668
+ }
669
+ //# sourceMappingURL=setup.js.map