luckerr 0.41.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 (156) hide show
  1. package/README.md +267 -0
  2. package/README.zh-CN.md +237 -0
  3. package/dashboard/app.css +3022 -0
  4. package/dashboard/dist/app.js +30137 -0
  5. package/dashboard/dist/app.js.map +1 -0
  6. package/dashboard/dist/vendor-hljs.css +10 -0
  7. package/dashboard/dist/vendor-uplot.css +1 -0
  8. package/dashboard/index.html +19 -0
  9. package/data/deepseek-tokenizer.json.gz +0 -0
  10. package/dist/cli/acp-EOOAI4F5.js +712 -0
  11. package/dist/cli/acp-EOOAI4F5.js.map +1 -0
  12. package/dist/cli/chat-7J6GJXL2.js +51 -0
  13. package/dist/cli/chat-7J6GJXL2.js.map +1 -0
  14. package/dist/cli/chunk-2425HK6U.js +54 -0
  15. package/dist/cli/chunk-2425HK6U.js.map +1 -0
  16. package/dist/cli/chunk-25T6CVUP.js +172 -0
  17. package/dist/cli/chunk-25T6CVUP.js.map +1 -0
  18. package/dist/cli/chunk-2UQP6H6T.js +31 -0
  19. package/dist/cli/chunk-2UQP6H6T.js.map +1 -0
  20. package/dist/cli/chunk-56OAJILV.js +47 -0
  21. package/dist/cli/chunk-56OAJILV.js.map +1 -0
  22. package/dist/cli/chunk-5FTI4KXH.js +150 -0
  23. package/dist/cli/chunk-5FTI4KXH.js.map +1 -0
  24. package/dist/cli/chunk-5TWQD73O.js +2846 -0
  25. package/dist/cli/chunk-5TWQD73O.js.map +1 -0
  26. package/dist/cli/chunk-653BOCMK.js +40 -0
  27. package/dist/cli/chunk-653BOCMK.js.map +1 -0
  28. package/dist/cli/chunk-6ALJTWWQ.js +2663 -0
  29. package/dist/cli/chunk-6ALJTWWQ.js.map +1 -0
  30. package/dist/cli/chunk-6DRKA2IL.js +341 -0
  31. package/dist/cli/chunk-6DRKA2IL.js.map +1 -0
  32. package/dist/cli/chunk-6LV63NJV.js +634 -0
  33. package/dist/cli/chunk-6LV63NJV.js.map +1 -0
  34. package/dist/cli/chunk-74EX7SUH.js +25293 -0
  35. package/dist/cli/chunk-74EX7SUH.js.map +1 -0
  36. package/dist/cli/chunk-74U5RKTX.js +60611 -0
  37. package/dist/cli/chunk-74U5RKTX.js.map +1 -0
  38. package/dist/cli/chunk-ANJSUESV.js +143 -0
  39. package/dist/cli/chunk-ANJSUESV.js.map +1 -0
  40. package/dist/cli/chunk-DB2Z3DKZ.js +54 -0
  41. package/dist/cli/chunk-DB2Z3DKZ.js.map +1 -0
  42. package/dist/cli/chunk-DDIH3ZAA.js +400 -0
  43. package/dist/cli/chunk-DDIH3ZAA.js.map +1 -0
  44. package/dist/cli/chunk-ELN3Z3B2.js +621 -0
  45. package/dist/cli/chunk-ELN3Z3B2.js.map +1 -0
  46. package/dist/cli/chunk-F6BSQJGV.js +200 -0
  47. package/dist/cli/chunk-F6BSQJGV.js.map +1 -0
  48. package/dist/cli/chunk-FET2UAG5.js +246 -0
  49. package/dist/cli/chunk-FET2UAG5.js.map +1 -0
  50. package/dist/cli/chunk-FFJ342IJ.js +190 -0
  51. package/dist/cli/chunk-FFJ342IJ.js.map +1 -0
  52. package/dist/cli/chunk-GB3247B6.js +130 -0
  53. package/dist/cli/chunk-GB3247B6.js.map +1 -0
  54. package/dist/cli/chunk-HC2J4U3G.js +373 -0
  55. package/dist/cli/chunk-HC2J4U3G.js.map +1 -0
  56. package/dist/cli/chunk-HRUZAIHQ.js +42 -0
  57. package/dist/cli/chunk-HRUZAIHQ.js.map +1 -0
  58. package/dist/cli/chunk-J3ZJFUDL.js +308 -0
  59. package/dist/cli/chunk-J3ZJFUDL.js.map +1 -0
  60. package/dist/cli/chunk-J5XJHLWM.js +55 -0
  61. package/dist/cli/chunk-J5XJHLWM.js.map +1 -0
  62. package/dist/cli/chunk-JFGLMRZ6.js +160 -0
  63. package/dist/cli/chunk-JFGLMRZ6.js.map +1 -0
  64. package/dist/cli/chunk-JMBMLOBP.js +26 -0
  65. package/dist/cli/chunk-JMBMLOBP.js.map +1 -0
  66. package/dist/cli/chunk-JMWHXZEL.js +551 -0
  67. package/dist/cli/chunk-JMWHXZEL.js.map +1 -0
  68. package/dist/cli/chunk-KEQGPJBO.js +209 -0
  69. package/dist/cli/chunk-KEQGPJBO.js.map +1 -0
  70. package/dist/cli/chunk-M4K6U37F.js +232 -0
  71. package/dist/cli/chunk-M4K6U37F.js.map +1 -0
  72. package/dist/cli/chunk-MIJI2WMN.js +95 -0
  73. package/dist/cli/chunk-MIJI2WMN.js.map +1 -0
  74. package/dist/cli/chunk-MPAO3JNR.js +128 -0
  75. package/dist/cli/chunk-MPAO3JNR.js.map +1 -0
  76. package/dist/cli/chunk-PZOFBEDC.js +873 -0
  77. package/dist/cli/chunk-PZOFBEDC.js.map +1 -0
  78. package/dist/cli/chunk-RAILYQLN.js +46 -0
  79. package/dist/cli/chunk-RAILYQLN.js.map +1 -0
  80. package/dist/cli/chunk-RR35VQVT.js +90 -0
  81. package/dist/cli/chunk-RR35VQVT.js.map +1 -0
  82. package/dist/cli/chunk-RRA7VPW4.js +417 -0
  83. package/dist/cli/chunk-RRA7VPW4.js.map +1 -0
  84. package/dist/cli/chunk-RU36QVN3.js +452 -0
  85. package/dist/cli/chunk-RU36QVN3.js.map +1 -0
  86. package/dist/cli/chunk-RUBIINXR.js +1819 -0
  87. package/dist/cli/chunk-RUBIINXR.js.map +1 -0
  88. package/dist/cli/chunk-S4XVGLRW.js +499 -0
  89. package/dist/cli/chunk-S4XVGLRW.js.map +1 -0
  90. package/dist/cli/chunk-TUK7OWJA.js +51 -0
  91. package/dist/cli/chunk-TUK7OWJA.js.map +1 -0
  92. package/dist/cli/chunk-VALDDV76.js +580 -0
  93. package/dist/cli/chunk-VALDDV76.js.map +1 -0
  94. package/dist/cli/chunk-WQOGPYGN.js +11390 -0
  95. package/dist/cli/chunk-WQOGPYGN.js.map +1 -0
  96. package/dist/cli/chunk-WREKDFXT.js +34320 -0
  97. package/dist/cli/chunk-WREKDFXT.js.map +1 -0
  98. package/dist/cli/chunk-Y7XQU2EL.js +270 -0
  99. package/dist/cli/chunk-Y7XQU2EL.js.map +1 -0
  100. package/dist/cli/chunk-YBVCZJU4.js +54 -0
  101. package/dist/cli/chunk-YBVCZJU4.js.map +1 -0
  102. package/dist/cli/chunk-YLIHDXUQ.js +749 -0
  103. package/dist/cli/chunk-YLIHDXUQ.js.map +1 -0
  104. package/dist/cli/chunk-YV5XXFD7.js +767 -0
  105. package/dist/cli/chunk-YV5XXFD7.js.map +1 -0
  106. package/dist/cli/chunk-ZRCNIYRQ.js +101 -0
  107. package/dist/cli/chunk-ZRCNIYRQ.js.map +1 -0
  108. package/dist/cli/code-CRKVCMFZ.js +155 -0
  109. package/dist/cli/code-CRKVCMFZ.js.map +1 -0
  110. package/dist/cli/commands-QLMD3T7B.js +356 -0
  111. package/dist/cli/commands-QLMD3T7B.js.map +1 -0
  112. package/dist/cli/commit-53PP32NC.js +293 -0
  113. package/dist/cli/commit-53PP32NC.js.map +1 -0
  114. package/dist/cli/desktop-R6W5CLJ5.js +1046 -0
  115. package/dist/cli/desktop-R6W5CLJ5.js.map +1 -0
  116. package/dist/cli/devtools-YECO25QO.js +3719 -0
  117. package/dist/cli/devtools-YECO25QO.js.map +1 -0
  118. package/dist/cli/diff-LYNRCJZE.js +166 -0
  119. package/dist/cli/diff-LYNRCJZE.js.map +1 -0
  120. package/dist/cli/doctor-5IBP4R5J.js +28 -0
  121. package/dist/cli/doctor-5IBP4R5J.js.map +1 -0
  122. package/dist/cli/events-QN6KLN2V.js +340 -0
  123. package/dist/cli/events-QN6KLN2V.js.map +1 -0
  124. package/dist/cli/index.js +3500 -0
  125. package/dist/cli/index.js.map +1 -0
  126. package/dist/cli/mcp-FGKEH7RG.js +277 -0
  127. package/dist/cli/mcp-FGKEH7RG.js.map +1 -0
  128. package/dist/cli/mcp-browse-YCND4NWT.js +178 -0
  129. package/dist/cli/mcp-browse-YCND4NWT.js.map +1 -0
  130. package/dist/cli/mcp-inspect-V34J3VX5.js +143 -0
  131. package/dist/cli/mcp-inspect-V34J3VX5.js.map +1 -0
  132. package/dist/cli/package.json +3 -0
  133. package/dist/cli/prompt-I775PNKT.js +16 -0
  134. package/dist/cli/prompt-I775PNKT.js.map +1 -0
  135. package/dist/cli/prune-sessions-KGIIYD3P.js +44 -0
  136. package/dist/cli/prune-sessions-KGIIYD3P.js.map +1 -0
  137. package/dist/cli/replay-RDXLUAOE.js +292 -0
  138. package/dist/cli/replay-RDXLUAOE.js.map +1 -0
  139. package/dist/cli/run-RCAC2RYW.js +223 -0
  140. package/dist/cli/run-RCAC2RYW.js.map +1 -0
  141. package/dist/cli/server-FFU6TLYJ.js +3658 -0
  142. package/dist/cli/server-FFU6TLYJ.js.map +1 -0
  143. package/dist/cli/sessions-QT26MQAE.js +107 -0
  144. package/dist/cli/sessions-QT26MQAE.js.map +1 -0
  145. package/dist/cli/setup-VV4WKXHV.js +767 -0
  146. package/dist/cli/setup-VV4WKXHV.js.map +1 -0
  147. package/dist/cli/stats-JVZPQWAN.js +15 -0
  148. package/dist/cli/stats-JVZPQWAN.js.map +1 -0
  149. package/dist/cli/update-KYI3OVJP.js +15 -0
  150. package/dist/cli/update-KYI3OVJP.js.map +1 -0
  151. package/dist/cli/version-ANYORXTI.js +34 -0
  152. package/dist/cli/version-ANYORXTI.js.map +1 -0
  153. package/dist/index.d.ts +2557 -0
  154. package/dist/index.js +15000 -0
  155. package/dist/index.js.map +1 -0
  156. package/package.json +106 -0
@@ -0,0 +1,452 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __cr } from 'node:module'; if (typeof globalThis.require === 'undefined') { globalThis.require = __cr(import.meta.url); }
3
+ import {
4
+ detectProxyUrl
5
+ } from "./chunk-74EX7SUH.js";
6
+ import {
7
+ resolveDataPath
8
+ } from "./chunk-F6BSQJGV.js";
9
+ import {
10
+ loadDotenv
11
+ } from "./chunk-2UQP6H6T.js";
12
+ import {
13
+ checkOllamaStatus
14
+ } from "./chunk-ZRCNIYRQ.js";
15
+ import {
16
+ indexExists
17
+ } from "./chunk-PZOFBEDC.js";
18
+ import {
19
+ loadHooks
20
+ } from "./chunk-KEQGPJBO.js";
21
+ import {
22
+ DeepSeekClient,
23
+ pickPrimaryBalance
24
+ } from "./chunk-DDIH3ZAA.js";
25
+ import {
26
+ listSessions
27
+ } from "./chunk-Y7XQU2EL.js";
28
+ import {
29
+ t
30
+ } from "./chunk-5TWQD73O.js";
31
+ import {
32
+ defaultConfigPath,
33
+ loadBaseUrl,
34
+ readConfig,
35
+ resolveSemanticEmbeddingConfig
36
+ } from "./chunk-6ALJTWWQ.js";
37
+ import {
38
+ VERSION
39
+ } from "./chunk-MPAO3JNR.js";
40
+
41
+ // src/cli/commands/doctor.ts
42
+ import { existsSync, readFileSync, statSync } from "fs";
43
+ import { homedir } from "os";
44
+ import { join, resolve } from "path";
45
+ async function runDoctorChecks(projectRoot) {
46
+ return Promise.all([
47
+ checkApiKey(),
48
+ checkConfig(),
49
+ checkProxy(),
50
+ checkApiReach(),
51
+ checkTokenizer(),
52
+ checkSessions(),
53
+ checkHooks(projectRoot),
54
+ checkOllama(projectRoot),
55
+ checkProject(projectRoot)
56
+ ]);
57
+ }
58
+ function checkProxy() {
59
+ const url = detectProxyUrl();
60
+ if (!url) {
61
+ return {
62
+ id: "proxy",
63
+ label: "http proxy ",
64
+ level: "ok",
65
+ detail: "no HTTPS_PROXY / HTTP_PROXY / ALL_PROXY set \u2014 direct connection"
66
+ };
67
+ }
68
+ let redacted = url;
69
+ try {
70
+ const u = new URL(url);
71
+ if (u.username || u.password) {
72
+ u.username = "***";
73
+ u.password = "";
74
+ redacted = u.toString();
75
+ }
76
+ } catch {
77
+ }
78
+ return {
79
+ id: "proxy",
80
+ label: "http proxy ",
81
+ level: "ok",
82
+ detail: `routing fetch through ${redacted}`
83
+ };
84
+ }
85
+ var TTY = process.stdout.isTTY && process.env.TERM !== "dumb";
86
+ function color(text, code) {
87
+ if (!TTY) return text;
88
+ return `\x1B[${code}m${text}\x1B[0m`;
89
+ }
90
+ function badge(level) {
91
+ if (level === "ok") return color("\u2713", "32");
92
+ if (level === "warn") return color("\u26A0", "33");
93
+ return color("\u2717", "31");
94
+ }
95
+ function tail4(s) {
96
+ return s.length <= 4 ? s : `\u2026${s.slice(-4)}`;
97
+ }
98
+ function fmtBytes(n) {
99
+ if (n < 1024) return `${n} B`;
100
+ if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;
101
+ return `${(n / 1024 / 1024).toFixed(1)} MB`;
102
+ }
103
+ async function checkApiKey() {
104
+ const fromEnv = process.env.DEEPSEEK_API_KEY;
105
+ if (fromEnv) {
106
+ return {
107
+ id: "api-key",
108
+ label: "api key ",
109
+ level: "ok",
110
+ detail: `set via env DEEPSEEK_API_KEY (${tail4(fromEnv)})`
111
+ };
112
+ }
113
+ try {
114
+ const cfg = readConfig();
115
+ if (cfg.apiKey) {
116
+ return {
117
+ id: "api-key",
118
+ label: "api key ",
119
+ level: "ok",
120
+ detail: `from ${defaultConfigPath()} (${tail4(cfg.apiKey)})`
121
+ };
122
+ }
123
+ } catch {
124
+ }
125
+ return {
126
+ id: "api-key",
127
+ label: "api key ",
128
+ level: "fail",
129
+ detail: "not set \u2014 `luckerr setup` to save one, or export DEEPSEEK_API_KEY. Get a key at https://platform.deepseek.com/api_keys"
130
+ };
131
+ }
132
+ async function checkConfig() {
133
+ const path = defaultConfigPath();
134
+ if (!existsSync(path)) {
135
+ return {
136
+ id: "config",
137
+ label: "config ",
138
+ level: "warn",
139
+ detail: "missing \u2014 running with library defaults. `luckerr setup` writes one."
140
+ };
141
+ }
142
+ try {
143
+ const cfg = readConfig(path);
144
+ const parts = [];
145
+ if (cfg.preset) parts.push(`preset=${cfg.preset}`);
146
+ if (cfg.editMode) parts.push(`editMode=${cfg.editMode}`);
147
+ if (cfg.mcp && cfg.mcp.length > 0) parts.push(`mcp=${cfg.mcp.length}`);
148
+ return {
149
+ id: "config",
150
+ label: "config ",
151
+ level: "ok",
152
+ detail: `${path}${parts.length ? ` (${parts.join(", ")})` : ""}`
153
+ };
154
+ } catch (err) {
155
+ return {
156
+ id: "config",
157
+ label: "config ",
158
+ level: "fail",
159
+ detail: t("doctorErrors.unreadable", { path, message: err.message })
160
+ };
161
+ }
162
+ }
163
+ async function checkApiReach() {
164
+ const key = process.env.DEEPSEEK_API_KEY ?? readConfig().apiKey;
165
+ if (!key) {
166
+ return {
167
+ id: "api-reach",
168
+ label: "api reach ",
169
+ level: "warn",
170
+ detail: "skipped \u2014 no api key to test with"
171
+ };
172
+ }
173
+ try {
174
+ const client = new DeepSeekClient({ apiKey: key, baseUrl: loadBaseUrl() });
175
+ const ctl = new AbortController();
176
+ const timer = setTimeout(() => ctl.abort(), 8e3);
177
+ let balance;
178
+ try {
179
+ balance = await client.getBalance({ signal: ctl.signal });
180
+ } finally {
181
+ clearTimeout(timer);
182
+ }
183
+ if (!balance) {
184
+ return {
185
+ id: "api-reach",
186
+ label: "api reach ",
187
+ level: "fail",
188
+ detail: "/user/balance returned null \u2014 auth failed or network blocked"
189
+ };
190
+ }
191
+ const summary = summarizeBalances(balance.balance_infos);
192
+ if (!balance.is_available) {
193
+ return {
194
+ id: "api-reach",
195
+ label: "api reach ",
196
+ level: "warn",
197
+ detail: `account flagged not-available${summary ? ` (${summary})` : ""} \u2014 top up or check your dashboard`
198
+ };
199
+ }
200
+ return {
201
+ id: "api-reach",
202
+ label: "api reach ",
203
+ level: "ok",
204
+ detail: summary ? `/user/balance ok \u2014 ${summary}` : "/user/balance ok"
205
+ };
206
+ } catch (err) {
207
+ return {
208
+ id: "api-reach",
209
+ label: "api reach ",
210
+ level: "fail",
211
+ detail: `${err.message}`
212
+ };
213
+ }
214
+ }
215
+ function summarizeBalances(infos) {
216
+ if (infos.length === 0) return "";
217
+ const primary = pickPrimaryBalance(infos);
218
+ if (infos.length === 1 || !primary)
219
+ return primary ? `${primary.total_balance} ${primary.currency}` : "";
220
+ const rest = infos.filter((i) => i !== primary).map((i) => `${i.total_balance} ${i.currency}`);
221
+ return `${primary.total_balance} ${primary.currency} + ${rest.join(" + ")}`;
222
+ }
223
+ async function checkTokenizer() {
224
+ const path = resolveDataPath();
225
+ if (existsSync(path)) {
226
+ try {
227
+ const stat = statSync(path);
228
+ return {
229
+ id: "tokenizer",
230
+ label: "tokenizer ",
231
+ level: "ok",
232
+ detail: `${path} (${fmtBytes(stat.size)})`
233
+ };
234
+ } catch {
235
+ }
236
+ }
237
+ return {
238
+ id: "tokenizer",
239
+ label: "tokenizer ",
240
+ level: "warn",
241
+ detail: "data/deepseek-tokenizer.json.gz not found \u2014 token counts will fall back to char heuristics"
242
+ };
243
+ }
244
+ async function checkSessions() {
245
+ try {
246
+ const list = listSessions();
247
+ if (list.length === 0) {
248
+ return {
249
+ id: "sessions",
250
+ label: "sessions ",
251
+ level: "ok",
252
+ detail: "0 saved"
253
+ };
254
+ }
255
+ const totalBytes = list.reduce((s, e) => s + e.size, 0);
256
+ const oldest = list[list.length - 1];
257
+ const ageDays = Math.floor((Date.now() - oldest.mtime.getTime()) / (24 * 60 * 60 * 1e3));
258
+ const stale = list.filter(
259
+ (e) => Date.now() - e.mtime.getTime() >= 90 * 24 * 60 * 60 * 1e3
260
+ ).length;
261
+ const detail = `${list.length} saved \xB7 ${fmtBytes(totalBytes)} \xB7 oldest ${ageDays}d`;
262
+ if (stale > 0) {
263
+ return {
264
+ id: "sessions",
265
+ label: "sessions ",
266
+ level: "warn",
267
+ detail: `${detail} \xB7 ${stale} idle \u226590d (run \`luckerr prune-sessions\`)`
268
+ };
269
+ }
270
+ return { id: "sessions", label: "sessions ", level: "ok", detail };
271
+ } catch (err) {
272
+ return {
273
+ id: "sessions",
274
+ label: "sessions ",
275
+ level: "warn",
276
+ detail: t("doctorErrors.cannotList", { message: err.message })
277
+ };
278
+ }
279
+ }
280
+ async function checkHooks(projectRoot) {
281
+ try {
282
+ const all = loadHooks({ projectRoot });
283
+ const global = all.filter((h) => h.scope === "global").length;
284
+ const project = all.filter((h) => h.scope === "project").length;
285
+ return {
286
+ id: "hooks",
287
+ label: "hooks ",
288
+ level: "ok",
289
+ detail: `${global} global, ${project} project`
290
+ };
291
+ } catch (err) {
292
+ return {
293
+ id: "hooks",
294
+ label: "hooks ",
295
+ level: "warn",
296
+ detail: t("doctorErrors.parseFailed", { message: err.message })
297
+ };
298
+ }
299
+ }
300
+ async function checkOllama(projectRoot) {
301
+ let exists = false;
302
+ try {
303
+ exists = await indexExists(projectRoot);
304
+ } catch {
305
+ }
306
+ if (!exists) {
307
+ return {
308
+ id: "semantic",
309
+ label: "semantic ",
310
+ level: "ok",
311
+ detail: "not in use (no semantic index built; `luckerr index` to enable)"
312
+ };
313
+ }
314
+ const meta = readSemanticMeta(projectRoot);
315
+ if (meta?.provider === "openai-compat") {
316
+ const resolved = resolveSemanticEmbeddingConfig();
317
+ if (resolved.provider !== "openai-compat") {
318
+ return {
319
+ id: "semantic",
320
+ label: "semantic ",
321
+ level: "warn",
322
+ detail: `index uses openai-compat/${meta.model} but current config resolves to ${resolved.provider}/${resolved.model} \u2014 rebuild before searching`
323
+ };
324
+ }
325
+ return {
326
+ id: "semantic",
327
+ label: "semantic ",
328
+ level: "ok",
329
+ detail: `openai-compat \xB7 ${resolved.baseUrl} \xB7 model ${resolved.model} \xB7 api key configured`
330
+ };
331
+ }
332
+ try {
333
+ const model = meta?.model || process.env.LUCKERR_EMBED_MODEL || "nomic-embed-text";
334
+ const status = await checkOllamaStatus(model);
335
+ if (!status.binaryFound) {
336
+ return {
337
+ id: "semantic",
338
+ label: "semantic ",
339
+ level: "warn",
340
+ detail: "ollama binary not on PATH \u2014 semantic_search will fail; install from https://ollama.com"
341
+ };
342
+ }
343
+ if (!status.daemonRunning) {
344
+ return {
345
+ id: "semantic",
346
+ label: "semantic ",
347
+ level: "warn",
348
+ detail: "ollama daemon not running \u2014 `ollama serve` (or call /semantic in TUI to auto-start)"
349
+ };
350
+ }
351
+ if (!status.modelPulled) {
352
+ return {
353
+ id: "semantic",
354
+ label: "semantic ",
355
+ level: "warn",
356
+ detail: `model ${status.modelName} not pulled \u2014 \`ollama pull ${status.modelName}\``
357
+ };
358
+ }
359
+ return {
360
+ id: "semantic",
361
+ label: "semantic ",
362
+ level: "ok",
363
+ detail: `ollama daemon up \xB7 model ${status.modelName} ready`
364
+ };
365
+ } catch (err) {
366
+ return {
367
+ id: "semantic",
368
+ label: "semantic ",
369
+ level: "warn",
370
+ detail: t("doctorErrors.probeFailed", { message: err.message })
371
+ };
372
+ }
373
+ }
374
+ function readSemanticMeta(projectRoot) {
375
+ try {
376
+ const raw = readFileSync(join(projectRoot, ".luckerr", "semantic", "index.meta.json"), "utf8");
377
+ const parsed = JSON.parse(raw);
378
+ return {
379
+ provider: parsed.provider === "openai-compat" ? "openai-compat" : "ollama",
380
+ model: typeof parsed.model === "string" ? parsed.model : ""
381
+ };
382
+ } catch {
383
+ return null;
384
+ }
385
+ }
386
+ async function checkProject(projectRoot) {
387
+ const markers = [".git", "LUCKERR.md", "package.json", "pyproject.toml", "Cargo.toml", "go.mod"];
388
+ const found = markers.filter((m) => existsSync(join(projectRoot, m)));
389
+ if (found.length === 0) {
390
+ return {
391
+ id: "project",
392
+ label: "project ",
393
+ level: "warn",
394
+ detail: `${projectRoot} has none of: ${markers.slice(0, 3).join(", ")} \u2026 \u2014 \`luckerr code\` will still run, but @-mentions and project memory have nothing to anchor`
395
+ };
396
+ }
397
+ return {
398
+ id: "project",
399
+ label: "project ",
400
+ level: "ok",
401
+ detail: `${projectRoot} (${found.join(", ")})`
402
+ };
403
+ }
404
+ function formatDoctorJson(checks, version) {
405
+ const ok = checks.filter((c) => c.level === "ok").length;
406
+ const warn = checks.filter((c) => c.level === "warn").length;
407
+ const fail = checks.filter((c) => c.level === "fail").length;
408
+ return JSON.stringify({
409
+ version,
410
+ summary: { ok, warn, fail },
411
+ checks: checks.map((c) => ({ id: c.id, status: c.level, message: c.detail }))
412
+ });
413
+ }
414
+ async function doctorCommand(opts = {}) {
415
+ loadDotenv();
416
+ const projectRoot = resolve(process.cwd());
417
+ const json = !!opts.json;
418
+ if (!json) {
419
+ console.log(`${color(`luckerr ${VERSION} \xB7 doctor`, "1")} (cwd: ${projectRoot})`);
420
+ console.log(` home: ${homedir()}`);
421
+ console.log("");
422
+ }
423
+ const checks = await runDoctorChecks(projectRoot);
424
+ const ok = checks.filter((c) => c.level === "ok").length;
425
+ const warn = checks.filter((c) => c.level === "warn").length;
426
+ const fail = checks.filter((c) => c.level === "fail").length;
427
+ if (json) {
428
+ console.log(formatDoctorJson(checks, VERSION));
429
+ if (fail > 0) process.exit(1);
430
+ return;
431
+ }
432
+ for (const c of checks) {
433
+ console.log(` ${badge(c.level)} ${c.label} ${c.detail}`);
434
+ }
435
+ console.log("");
436
+ const summary = `${ok} ok \xB7 ${warn} warn \xB7 ${fail} fail`;
437
+ if (fail > 0) {
438
+ console.log(color(summary, "31"));
439
+ process.exit(1);
440
+ } else if (warn > 0) {
441
+ console.log(color(summary, "33"));
442
+ } else {
443
+ console.log(color(summary, "32"));
444
+ }
445
+ }
446
+
447
+ export {
448
+ runDoctorChecks,
449
+ formatDoctorJson,
450
+ doctorCommand
451
+ };
452
+ //# sourceMappingURL=chunk-RU36QVN3.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/commands/doctor.ts"],"sourcesContent":["/** Plain-text (not Ink) — must work when everything else is broken. fail → exit 1; warn → exit 0. */\n\nimport { existsSync, readFileSync, statSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, resolve } from \"node:path\";\nimport { DeepSeekClient, pickPrimaryBalance } from \"../../client.js\";\nimport {\n defaultConfigPath,\n loadBaseUrl,\n readConfig,\n resolveSemanticEmbeddingConfig,\n} from \"../../config.js\";\nimport { loadDotenv } from \"../../env.js\";\nimport { loadHooks } from \"../../hooks.js\";\nimport { t } from \"../../i18n/index.js\";\nimport { indexExists } from \"../../index/semantic/builder.js\";\nimport { checkOllamaStatus } from \"../../index/semantic/ollama-launcher.js\";\nimport { listSessions } from \"../../memory/session.js\";\nimport { detectProxyUrl } from \"../../net/proxy.js\";\nimport { resolveDataPath } from \"../../tokenizer.js\";\nimport { VERSION } from \"../../version.js\";\n\nexport type DoctorLevel = \"ok\" | \"warn\" | \"fail\";\n\nexport interface DoctorCheck {\n id: string;\n label: string;\n level: DoctorLevel;\n detail: string;\n}\n\nexport interface DoctorOptions {\n json?: boolean;\n}\n\ntype Level = DoctorLevel;\ntype Check = DoctorCheck;\n\nexport async function runDoctorChecks(projectRoot: string): Promise<DoctorCheck[]> {\n return Promise.all([\n checkApiKey(),\n checkConfig(),\n checkProxy(),\n checkApiReach(),\n checkTokenizer(),\n checkSessions(),\n checkHooks(projectRoot),\n checkOllama(projectRoot),\n checkProject(projectRoot),\n ]);\n}\n\nfunction checkProxy(): Check {\n const url = detectProxyUrl();\n if (!url) {\n return {\n id: \"proxy\",\n label: \"http proxy \",\n level: \"ok\",\n detail: \"no HTTPS_PROXY / HTTP_PROXY / ALL_PROXY set — direct connection\",\n };\n }\n let redacted = url;\n try {\n const u = new URL(url);\n if (u.username || u.password) {\n u.username = \"***\";\n u.password = \"\";\n redacted = u.toString();\n }\n } catch {\n /* not a URL — leave raw */\n }\n return {\n id: \"proxy\",\n label: \"http proxy \",\n level: \"ok\",\n detail: `routing fetch through ${redacted}`,\n };\n}\n\nconst TTY = process.stdout.isTTY && process.env.TERM !== \"dumb\";\n\nfunction color(text: string, code: string): string {\n if (!TTY) return text;\n return `\\x1b[${code}m${text}\\x1b[0m`;\n}\n\nfunction badge(level: Level): string {\n if (level === \"ok\") return color(\"✓\", \"32\");\n if (level === \"warn\") return color(\"⚠\", \"33\");\n return color(\"✗\", \"31\");\n}\n\nfunction tail4(s: string): string {\n return s.length <= 4 ? s : `…${s.slice(-4)}`;\n}\n\nfunction fmtBytes(n: number): string {\n if (n < 1024) return `${n} B`;\n if (n < 1024 * 1024) return `${(n / 1024).toFixed(1)} KB`;\n return `${(n / 1024 / 1024).toFixed(1)} MB`;\n}\n\nasync function checkApiKey(): Promise<Check> {\n const fromEnv = process.env.DEEPSEEK_API_KEY;\n if (fromEnv) {\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"ok\",\n detail: `set via env DEEPSEEK_API_KEY (${tail4(fromEnv)})`,\n };\n }\n try {\n const cfg = readConfig();\n if (cfg.apiKey) {\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"ok\",\n detail: `from ${defaultConfigPath()} (${tail4(cfg.apiKey)})`,\n };\n }\n } catch {\n /* fall through */\n }\n return {\n id: \"api-key\",\n label: \"api key \",\n level: \"fail\",\n detail:\n \"not set — `luckerr setup` to save one, or export DEEPSEEK_API_KEY. Get a key at https://platform.deepseek.com/api_keys\",\n };\n}\n\nasync function checkConfig(): Promise<Check> {\n const path = defaultConfigPath();\n if (!existsSync(path)) {\n return {\n id: \"config\",\n label: \"config \",\n level: \"warn\",\n detail: \"missing — running with library defaults. `luckerr setup` writes one.\",\n };\n }\n try {\n const cfg = readConfig(path);\n const parts: string[] = [];\n if (cfg.preset) parts.push(`preset=${cfg.preset}`);\n if (cfg.editMode) parts.push(`editMode=${cfg.editMode}`);\n if (cfg.mcp && cfg.mcp.length > 0) parts.push(`mcp=${cfg.mcp.length}`);\n return {\n id: \"config\",\n label: \"config \",\n level: \"ok\",\n detail: `${path}${parts.length ? ` (${parts.join(\", \")})` : \"\"}`,\n };\n } catch (err) {\n return {\n id: \"config\",\n label: \"config \",\n level: \"fail\",\n detail: t(\"doctorErrors.unreadable\", { path, message: (err as Error).message }),\n };\n }\n}\n\nasync function checkApiReach(): Promise<Check> {\n const key = process.env.DEEPSEEK_API_KEY ?? readConfig().apiKey;\n if (!key) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"warn\",\n detail: \"skipped — no api key to test with\",\n };\n }\n try {\n const client = new DeepSeekClient({ apiKey: key, baseUrl: loadBaseUrl() });\n const ctl = new AbortController();\n const timer = setTimeout(() => ctl.abort(), 8_000);\n let balance: Awaited<ReturnType<DeepSeekClient[\"getBalance\"]>>;\n try {\n balance = await client.getBalance({ signal: ctl.signal });\n } finally {\n clearTimeout(timer);\n }\n if (!balance) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"fail\",\n detail: \"/user/balance returned null — auth failed or network blocked\",\n };\n }\n const summary = summarizeBalances(balance.balance_infos);\n if (!balance.is_available) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"warn\",\n detail: `account flagged not-available${summary ? ` (${summary})` : \"\"} — top up or check your dashboard`,\n };\n }\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"ok\",\n detail: summary ? `/user/balance ok — ${summary}` : \"/user/balance ok\",\n };\n } catch (err) {\n return {\n id: \"api-reach\",\n label: \"api reach \",\n level: \"fail\",\n detail: `${(err as Error).message}`,\n };\n }\n}\n\nfunction summarizeBalances(\n infos: ReadonlyArray<{ currency: string; total_balance: string }>,\n): string {\n if (infos.length === 0) return \"\";\n const primary = pickPrimaryBalance(infos);\n if (infos.length === 1 || !primary)\n return primary ? `${primary.total_balance} ${primary.currency}` : \"\";\n const rest = infos.filter((i) => i !== primary).map((i) => `${i.total_balance} ${i.currency}`);\n return `${primary.total_balance} ${primary.currency} + ${rest.join(\" + \")}`;\n}\n\nasync function checkTokenizer(): Promise<Check> {\n // Reuse the runtime's resolver so the doctor never disagrees with what\n // the tokenizer actually loads — three candidates including a global\n // npm install probe via createRequire.\n const path = resolveDataPath();\n if (existsSync(path)) {\n try {\n const stat = statSync(path);\n return {\n id: \"tokenizer\",\n label: \"tokenizer \",\n level: \"ok\",\n detail: `${path} (${fmtBytes(stat.size)})`,\n };\n } catch {\n /* fall through to warn */\n }\n }\n return {\n id: \"tokenizer\",\n label: \"tokenizer \",\n level: \"warn\",\n detail:\n \"data/deepseek-tokenizer.json.gz not found — token counts will fall back to char heuristics\",\n };\n}\n\nasync function checkSessions(): Promise<Check> {\n try {\n const list = listSessions();\n if (list.length === 0) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"ok\",\n detail: \"0 saved\",\n };\n }\n const totalBytes = list.reduce((s, e) => s + e.size, 0);\n const oldest = list[list.length - 1]!;\n const ageDays = Math.floor((Date.now() - oldest.mtime.getTime()) / (24 * 60 * 60 * 1000));\n const stale = list.filter(\n (e) => Date.now() - e.mtime.getTime() >= 90 * 24 * 60 * 60 * 1000,\n ).length;\n const detail = `${list.length} saved · ${fmtBytes(totalBytes)} · oldest ${ageDays}d`;\n if (stale > 0) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"warn\",\n detail: `${detail} · ${stale} idle ≥90d (run \\`luckerr prune-sessions\\`)`,\n };\n }\n return { id: \"sessions\", label: \"sessions \", level: \"ok\", detail };\n } catch (err) {\n return {\n id: \"sessions\",\n label: \"sessions \",\n level: \"warn\",\n detail: t(\"doctorErrors.cannotList\", { message: (err as Error).message }),\n };\n }\n}\n\nasync function checkHooks(projectRoot: string): Promise<Check> {\n try {\n const all = loadHooks({ projectRoot });\n const global = all.filter((h) => h.scope === \"global\").length;\n const project = all.filter((h) => h.scope === \"project\").length;\n return {\n id: \"hooks\",\n label: \"hooks \",\n level: \"ok\",\n detail: `${global} global, ${project} project`,\n };\n } catch (err) {\n return {\n id: \"hooks\",\n label: \"hooks \",\n level: \"warn\",\n detail: t(\"doctorErrors.parseFailed\", { message: (err as Error).message }),\n };\n }\n}\n\nasync function checkOllama(projectRoot: string): Promise<Check> {\n let exists = false;\n try {\n exists = await indexExists(projectRoot);\n } catch {\n /* treat as no index */\n }\n if (!exists) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: \"not in use (no semantic index built; `luckerr index` to enable)\",\n };\n }\n const meta = readSemanticMeta(projectRoot);\n if (meta?.provider === \"openai-compat\") {\n const resolved = resolveSemanticEmbeddingConfig();\n if (resolved.provider !== \"openai-compat\") {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: `index uses openai-compat/${meta.model} but current config resolves to ${resolved.provider}/${resolved.model} — rebuild before searching`,\n };\n }\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: `openai-compat · ${resolved.baseUrl} · model ${resolved.model} · api key configured`,\n };\n }\n try {\n const model = meta?.model || process.env.LUCKERR_EMBED_MODEL || \"nomic-embed-text\";\n const status = await checkOllamaStatus(model);\n if (!status.binaryFound) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail:\n \"ollama binary not on PATH — semantic_search will fail; install from https://ollama.com\",\n };\n }\n if (!status.daemonRunning) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail:\n \"ollama daemon not running — `ollama serve` (or call /semantic in TUI to auto-start)\",\n };\n }\n if (!status.modelPulled) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: `model ${status.modelName} not pulled — \\`ollama pull ${status.modelName}\\``,\n };\n }\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"ok\",\n detail: `ollama daemon up · model ${status.modelName} ready`,\n };\n } catch (err) {\n return {\n id: \"semantic\",\n label: \"semantic \",\n level: \"warn\",\n detail: t(\"doctorErrors.probeFailed\", { message: (err as Error).message }),\n };\n }\n}\n\nfunction readSemanticMeta(\n projectRoot: string,\n): { provider: \"ollama\" | \"openai-compat\"; model: string } | null {\n try {\n const raw = readFileSync(join(projectRoot, \".luckerr\", \"semantic\", \"index.meta.json\"), \"utf8\");\n const parsed = JSON.parse(raw) as { provider?: string; model?: string };\n return {\n provider: parsed.provider === \"openai-compat\" ? \"openai-compat\" : \"ollama\",\n model: typeof parsed.model === \"string\" ? parsed.model : \"\",\n };\n } catch {\n return null;\n }\n}\n\nasync function checkProject(projectRoot: string): Promise<Check> {\n // Heuristic: a \"real\" project has either .git, LUCKERR.md, or\n // package.json. Lacking all three, `luckerr code` still works but\n // @-mentions and the project-memory pin won't surface much.\n const markers = [\".git\", \"LUCKERR.md\", \"package.json\", \"pyproject.toml\", \"Cargo.toml\", \"go.mod\"];\n const found = markers.filter((m) => existsSync(join(projectRoot, m)));\n if (found.length === 0) {\n return {\n id: \"project\",\n label: \"project \",\n level: \"warn\",\n detail: `${projectRoot} has none of: ${markers.slice(0, 3).join(\", \")} … — \\`luckerr code\\` will still run, but @-mentions and project memory have nothing to anchor`,\n };\n }\n return {\n id: \"project\",\n label: \"project \",\n level: \"ok\",\n detail: `${projectRoot} (${found.join(\", \")})`,\n };\n}\n\nexport function formatDoctorJson(checks: DoctorCheck[], version: string): string {\n const ok = checks.filter((c) => c.level === \"ok\").length;\n const warn = checks.filter((c) => c.level === \"warn\").length;\n const fail = checks.filter((c) => c.level === \"fail\").length;\n return JSON.stringify({\n version,\n summary: { ok, warn, fail },\n checks: checks.map((c) => ({ id: c.id, status: c.level, message: c.detail })),\n });\n}\n\nexport async function doctorCommand(opts: DoctorOptions = {}): Promise<void> {\n loadDotenv();\n\n const projectRoot = resolve(process.cwd());\n const json = !!opts.json;\n\n if (!json) {\n console.log(`${color(`luckerr ${VERSION} · doctor`, \"1\")} (cwd: ${projectRoot})`);\n console.log(` home: ${homedir()}`);\n console.log(\"\");\n }\n\n // Run independent checks in parallel — saves ~5s when api-reach has\n // to time out. Each handler swallows its own throws into a `fail`\n // result so a thrown promise can't kill the whole report.\n const checks = await runDoctorChecks(projectRoot);\n\n const ok = checks.filter((c) => c.level === \"ok\").length;\n const warn = checks.filter((c) => c.level === \"warn\").length;\n const fail = checks.filter((c) => c.level === \"fail\").length;\n\n if (json) {\n console.log(formatDoctorJson(checks, VERSION));\n if (fail > 0) process.exit(1);\n return;\n }\n\n for (const c of checks) {\n console.log(` ${badge(c.level)} ${c.label} ${c.detail}`);\n }\n\n console.log(\"\");\n const summary = `${ok} ok · ${warn} warn · ${fail} fail`;\n if (fail > 0) {\n console.log(color(summary, \"31\"));\n process.exit(1);\n } else if (warn > 0) {\n console.log(color(summary, \"33\"));\n } else {\n console.log(color(summary, \"32\"));\n }\n}\n"],"mappings":"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","names":[]}