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,1046 @@
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
+ createMcpRuntime
5
+ } from "./chunk-FET2UAG5.js";
6
+ import {
7
+ buildCodeToolset
8
+ } from "./chunk-HC2J4U3G.js";
9
+ import {
10
+ Eventizer,
11
+ autoResolveVerdict
12
+ } from "./chunk-RRA7VPW4.js";
13
+ import "./chunk-RAILYQLN.js";
14
+ import "./chunk-HRUZAIHQ.js";
15
+ import {
16
+ CacheFirstLoop,
17
+ ImmutablePrefix,
18
+ listDirectory,
19
+ listFilesWithStatsAsync,
20
+ parseAtQuery,
21
+ rankPickerCandidates
22
+ } from "./chunk-WQOGPYGN.js";
23
+ import "./chunk-J3ZJFUDL.js";
24
+ import "./chunk-FFJ342IJ.js";
25
+ import {
26
+ parseMcpSpec
27
+ } from "./chunk-YV5XXFD7.js";
28
+ import {
29
+ MemoryStore,
30
+ codeSystemPrompt
31
+ } from "./chunk-6LV63NJV.js";
32
+ import {
33
+ canonicalPresetName,
34
+ resolvePreset
35
+ } from "./chunk-2425HK6U.js";
36
+ import {
37
+ countTokens
38
+ } from "./chunk-F6BSQJGV.js";
39
+ import {
40
+ loadDotenv
41
+ } from "./chunk-2UQP6H6T.js";
42
+ import "./chunk-MIJI2WMN.js";
43
+ import {
44
+ pauseGate
45
+ } from "./chunk-RUBIINXR.js";
46
+ import {
47
+ SkillStore
48
+ } from "./chunk-VALDDV76.js";
49
+ import "./chunk-56OAJILV.js";
50
+ import "./chunk-PZOFBEDC.js";
51
+ import "./chunk-KEQGPJBO.js";
52
+ import "./chunk-S4XVGLRW.js";
53
+ import {
54
+ DeepSeekClient,
55
+ pickPrimaryBalance
56
+ } from "./chunk-DDIH3ZAA.js";
57
+ import "./chunk-25T6CVUP.js";
58
+ import {
59
+ deleteSession,
60
+ listSessionsForWorkspace,
61
+ loadSessionMessages,
62
+ loadSessionMeta,
63
+ patchSessionMeta,
64
+ timestampSuffix
65
+ } from "./chunk-Y7XQU2EL.js";
66
+ import "./chunk-5TWQD73O.js";
67
+ import {
68
+ isPlausibleKey,
69
+ loadApiKey,
70
+ loadBaseUrl,
71
+ loadEditMode,
72
+ loadEditor,
73
+ loadPreset,
74
+ loadReasoningEffort,
75
+ loadRecentWorkspaces,
76
+ loadWorkspaceDir,
77
+ pushRecentWorkspace,
78
+ readConfig,
79
+ saveApiKey,
80
+ saveBaseUrl,
81
+ saveEditMode,
82
+ saveEditor,
83
+ savePreset,
84
+ saveReasoningEffort,
85
+ saveWorkspaceDir,
86
+ writeConfig
87
+ } from "./chunk-6ALJTWWQ.js";
88
+ import "./chunk-M4K6U37F.js";
89
+ import "./chunk-ANJSUESV.js";
90
+ import "./chunk-JMWHXZEL.js";
91
+ import {
92
+ VERSION
93
+ } from "./chunk-MPAO3JNR.js";
94
+ import "./chunk-TUK7OWJA.js";
95
+
96
+ // src/cli/commands/desktop.ts
97
+ import { AsyncLocalStorage } from "async_hooks";
98
+ import { existsSync, statSync, writeSync } from "fs";
99
+ import { readFile } from "fs/promises";
100
+ import { isAbsolute, join, resolve } from "path";
101
+ import { stdin } from "process";
102
+ import { createInterface } from "readline";
103
+ function emit(ev, tabId) {
104
+ const payload = tabId ? { ...ev, tabId } : ev;
105
+ writeSync(1, Buffer.from(`${JSON.stringify(payload)}
106
+ `, "utf8"));
107
+ }
108
+ function buildLoadedMessages(records) {
109
+ const out = [];
110
+ let turn = 0;
111
+ let pendingAssistantIdx = -1;
112
+ for (const rec of records) {
113
+ if (rec.role === "system") continue;
114
+ if (rec.role === "user") {
115
+ out.push({ kind: "user", text: rec.content ?? "" });
116
+ pendingAssistantIdx = -1;
117
+ continue;
118
+ }
119
+ if (rec.role === "assistant") {
120
+ turn++;
121
+ const segments = [];
122
+ if (rec.reasoning_content) segments.push({ kind: "reasoning", text: rec.reasoning_content });
123
+ if (rec.content) segments.push({ kind: "text", text: rec.content });
124
+ if (rec.tool_calls) {
125
+ for (let i = 0; i < rec.tool_calls.length; i++) {
126
+ const tc = rec.tool_calls[i];
127
+ if (!tc) continue;
128
+ segments.push({
129
+ kind: "tool",
130
+ callId: tc.id ?? `tc-r-${turn}-${i}`,
131
+ name: tc.function?.name ?? "",
132
+ args: tc.function?.arguments ?? ""
133
+ });
134
+ }
135
+ }
136
+ out.push({ kind: "assistant", turn, segments, pending: false });
137
+ pendingAssistantIdx = out.length - 1;
138
+ continue;
139
+ }
140
+ if (rec.role === "tool") {
141
+ if (pendingAssistantIdx < 0) continue;
142
+ const host = out[pendingAssistantIdx];
143
+ if (host?.kind !== "assistant") continue;
144
+ const callId = rec.tool_call_id;
145
+ if (!callId) continue;
146
+ const seg = host.segments.find((s) => s.kind === "tool" && s.callId === callId);
147
+ if (seg && seg.kind === "tool") {
148
+ seg.result = rec.content ?? "";
149
+ seg.ok = !/error|failed/i.test(seg.result.slice(0, 200));
150
+ }
151
+ }
152
+ }
153
+ return out;
154
+ }
155
+ function emitSettings(tab) {
156
+ const apiKey = loadApiKey();
157
+ const recent = loadRecentWorkspaces().filter((p) => p !== tab.rootDir);
158
+ emit(
159
+ {
160
+ type: "$settings",
161
+ reasoningEffort: loadReasoningEffort(),
162
+ editMode: loadEditMode(),
163
+ budgetUsd: tab.runtime?.loop.budgetUsd ?? null,
164
+ baseUrl: loadBaseUrl(),
165
+ apiKeyPrefix: apiKey ? `${apiKey.slice(0, 6)}\u2026${apiKey.slice(-3)}` : void 0,
166
+ workspaceDir: tab.rootDir,
167
+ recentWorkspaces: recent,
168
+ model: tab.currentModel,
169
+ preset: tab.currentPreset,
170
+ editor: loadEditor(),
171
+ version: VERSION
172
+ },
173
+ tab.id
174
+ );
175
+ }
176
+ async function emitBalance(tab) {
177
+ if (!tab.runtime) return;
178
+ const bal = await tab.runtime.loop.client.getBalance().catch(() => null);
179
+ if (!bal) return;
180
+ const primary = pickPrimaryBalance(bal.balance_infos);
181
+ if (!primary) return;
182
+ emit(
183
+ {
184
+ type: "$balance",
185
+ currency: primary.currency,
186
+ total: Number(primary.total_balance),
187
+ isAvailable: bal.is_available
188
+ },
189
+ tab.id
190
+ );
191
+ }
192
+ function emitSessions(tab) {
193
+ try {
194
+ const items = listSessionsForWorkspace(tab.rootDir).map((s) => ({
195
+ name: s.name,
196
+ messageCount: s.messageCount,
197
+ mtime: s.mtime.toISOString(),
198
+ summary: s.meta.summary
199
+ }));
200
+ emit({ type: "$sessions", items }, tab.id);
201
+ } catch (err) {
202
+ emit({ type: "$error", message: `session_list failed: ${err.message}` }, tab.id);
203
+ }
204
+ }
205
+ function summarizeMcpSpec(raw) {
206
+ try {
207
+ const parsed = parseMcpSpec(raw);
208
+ if (parsed.transport === "stdio") {
209
+ const argv = [parsed.command, ...parsed.args].join(" ");
210
+ return {
211
+ raw,
212
+ name: parsed.name,
213
+ transport: "stdio",
214
+ summary: `stdio \xB7 ${argv}`,
215
+ status: "configured"
216
+ };
217
+ }
218
+ return {
219
+ raw,
220
+ name: parsed.name,
221
+ transport: parsed.transport,
222
+ summary: `${parsed.transport} \xB7 ${parsed.url}`,
223
+ status: "configured"
224
+ };
225
+ } catch (err) {
226
+ return {
227
+ raw,
228
+ name: null,
229
+ transport: "stdio",
230
+ summary: raw,
231
+ parseError: err.message,
232
+ status: "failed",
233
+ statusReason: err.message
234
+ };
235
+ }
236
+ }
237
+ function emitMcpSpecs(tab) {
238
+ const cfg = readConfig();
239
+ const specs = (cfg.mcp ?? []).map((raw) => {
240
+ const base = summarizeMcpSpec(raw);
241
+ const live = tab.mcpStatuses.get(raw);
242
+ if (!live) return base;
243
+ return { ...base, status: live.kind, statusReason: live.reason, toolCount: live.toolCount };
244
+ });
245
+ const bridged = specs.length > 0 && specs.every((s) => s.status === "connected");
246
+ emit({ type: "$mcp_specs", specs, bridged }, tab.id);
247
+ }
248
+ function emitMemory(tab) {
249
+ try {
250
+ const store = new MemoryStore({ projectRoot: tab.rootDir });
251
+ const entries = store.list().map((e) => ({
252
+ name: e.name,
253
+ scope: e.scope,
254
+ description: e.description
255
+ }));
256
+ emit({ type: "$memory", entries }, tab.id);
257
+ } catch (err) {
258
+ emit({ type: "$error", message: `memory_get failed: ${err.message}` }, tab.id);
259
+ }
260
+ }
261
+ function emitCtxBreakdown(tab) {
262
+ if (!tab.runtime) return;
263
+ try {
264
+ const sys = countTokens(tab.runtime.loop.prefix.system);
265
+ const tools = countTokens(JSON.stringify(tab.runtime.loop.prefix.toolSpecs));
266
+ emit({ type: "$ctx_breakdown", reservedTokens: sys + tools }, tab.id);
267
+ } catch {
268
+ }
269
+ }
270
+ function emitSkills(tab) {
271
+ try {
272
+ const store = new SkillStore({ projectRoot: tab.rootDir });
273
+ const items = store.list().map((s) => ({
274
+ name: s.name,
275
+ description: s.description,
276
+ scope: s.scope,
277
+ path: s.path,
278
+ runAs: s.runAs,
279
+ model: s.model
280
+ }));
281
+ emit({ type: "$skills", items }, tab.id);
282
+ } catch (err) {
283
+ emit({ type: "$error", message: `skills_get failed: ${err.message}` }, tab.id);
284
+ }
285
+ }
286
+ var tabCounter = 0;
287
+ function nextTabId() {
288
+ tabCounter++;
289
+ return `t${tabCounter}`;
290
+ }
291
+ function mintSessionFor(rootDir) {
292
+ const name = `desktop-${timestampSuffix()}-${tabCounter}`;
293
+ try {
294
+ patchSessionMeta(name, { workspace: rootDir });
295
+ } catch {
296
+ }
297
+ return name;
298
+ }
299
+ function buildRuntimeFor(tab) {
300
+ const client = new DeepSeekClient({ baseUrl: loadBaseUrl() });
301
+ const prefix = new ImmutablePrefix({ system: tab.system, toolSpecs: tab.toolset.tools.specs() });
302
+ const reasoningEffort = loadReasoningEffort();
303
+ const loop = new CacheFirstLoop({
304
+ client,
305
+ prefix,
306
+ tools: tab.toolset.tools,
307
+ model: tab.currentModel,
308
+ budgetUsd: tab.budgetUsd,
309
+ session: tab.currentSession,
310
+ reasoningEffort
311
+ });
312
+ const eventizer = new Eventizer();
313
+ const ctx = { model: tab.currentModel, prefixHash: prefix.fingerprint, reasoningEffort };
314
+ return { loop, eventizer, ctx };
315
+ }
316
+ var TS_EXPORT_RE = /^export\s+(?:default\s+)?(?:async\s+)?(function|class|const|let|var|interface|type|enum)\s+\*?\s*(\w+)/;
317
+ async function getFileIndexFor(tab) {
318
+ if (tab.fileIndex) return tab.fileIndex;
319
+ if (tab.fileIndexBuilding) return tab.fileIndexBuilding;
320
+ tab.fileIndexBuilding = listFilesWithStatsAsync(tab.rootDir, { maxResults: 5e3 }).then((res) => {
321
+ tab.fileIndex = res;
322
+ tab.fileIndexBuilding = null;
323
+ return res;
324
+ }).catch((err) => {
325
+ tab.fileIndexBuilding = null;
326
+ throw err;
327
+ });
328
+ return tab.fileIndexBuilding;
329
+ }
330
+ async function getSymbolIndexFor(tab) {
331
+ if (tab.symbolIndex) return tab.symbolIndex;
332
+ if (tab.symbolBuilding) return tab.symbolBuilding;
333
+ tab.symbolBuilding = (async () => {
334
+ const files = await getFileIndexFor(tab);
335
+ const sourceExts = /\.(?:ts|tsx|js|jsx|mts|cts)$/;
336
+ const candidates = files.filter((f) => sourceExts.test(f.path)).slice(0, 1500);
337
+ const out = [];
338
+ const PARALLEL = 16;
339
+ for (let i = 0; i < candidates.length; i += PARALLEL) {
340
+ const batch = candidates.slice(i, i + PARALLEL);
341
+ await Promise.all(
342
+ batch.map(async (entry) => {
343
+ const abs = isAbsolute(entry.path) ? entry.path : join(tab.rootDir, entry.path);
344
+ try {
345
+ const text = await readFile(abs, "utf8");
346
+ const lines = text.split(/\r?\n/);
347
+ for (let li = 0; li < lines.length; li++) {
348
+ const line = lines[li];
349
+ if (!line.startsWith("export ")) continue;
350
+ const m = TS_EXPORT_RE.exec(line);
351
+ if (m) out.push({ kind: m[1], name: m[2], path: entry.path, line: li + 1 });
352
+ }
353
+ } catch {
354
+ }
355
+ })
356
+ );
357
+ }
358
+ tab.symbolIndex = out;
359
+ tab.symbolBuilding = null;
360
+ return out;
361
+ })().catch((err) => {
362
+ tab.symbolBuilding = null;
363
+ throw err;
364
+ });
365
+ return tab.symbolBuilding;
366
+ }
367
+ function rankSymbols(syms, q, limit) {
368
+ const needle = q.toLowerCase();
369
+ const scored = [];
370
+ for (const s of syms) {
371
+ const lower = s.name.toLowerCase();
372
+ let score;
373
+ if (lower === needle) score = 0;
374
+ else if (lower.startsWith(needle)) score = 100;
375
+ else if (lower.includes(needle)) score = 500 + lower.indexOf(needle);
376
+ else continue;
377
+ scored.push({ entry: s, score });
378
+ }
379
+ scored.sort((a, b) => a.score - b.score || a.entry.name.localeCompare(b.entry.name));
380
+ return scored.slice(0, limit).map((s) => `${s.entry.path}:${s.entry.line}`);
381
+ }
382
+ function pushMentionRecent(tab, path) {
383
+ const MAX = 20;
384
+ const idx = tab.recentMentions.indexOf(path);
385
+ if (idx >= 0) tab.recentMentions.splice(idx, 1);
386
+ tab.recentMentions.unshift(path);
387
+ if (tab.recentMentions.length > MAX) tab.recentMentions.length = MAX;
388
+ }
389
+ async function desktopCommand(opts) {
390
+ loadDotenv();
391
+ const tabs = /* @__PURE__ */ new Map();
392
+ const tabContext = new AsyncLocalStorage();
393
+ function activeRunningTab() {
394
+ const id = tabContext.getStore();
395
+ return id ? tabs.get(id) : void 0;
396
+ }
397
+ async function createTab(initialDir) {
398
+ const dir = resolve(initialDir ?? opts.dir ?? loadWorkspaceDir() ?? process.cwd());
399
+ pushRecentWorkspace(dir);
400
+ const preset = canonicalPresetName(loadPreset());
401
+ const resolved = resolvePreset(preset);
402
+ const model = opts.model || resolved.model;
403
+ const toolset = await buildCodeToolset({ rootDir: dir });
404
+ const system = codeSystemPrompt(dir, {
405
+ hasSemanticSearch: toolset.semantic.enabled,
406
+ modelId: model
407
+ });
408
+ const tab = {
409
+ id: nextTabId(),
410
+ rootDir: dir,
411
+ currentSession: "",
412
+ currentPreset: preset,
413
+ currentModel: model,
414
+ budgetUsd: opts.budgetUsd,
415
+ toolset,
416
+ system,
417
+ runtime: null,
418
+ aborter: null,
419
+ fileIndex: null,
420
+ fileIndexBuilding: null,
421
+ symbolIndex: null,
422
+ symbolBuilding: null,
423
+ recentMentions: [],
424
+ pendingGateIds: /* @__PURE__ */ new Set(),
425
+ completedStepIds: /* @__PURE__ */ new Set(),
426
+ planTotalSteps: 0,
427
+ mcpRuntime: null,
428
+ mcpStatuses: /* @__PURE__ */ new Map()
429
+ };
430
+ tab.currentSession = mintSessionFor(dir);
431
+ if (loadApiKey()) {
432
+ process.env.DEEPSEEK_API_KEY = loadApiKey();
433
+ tab.runtime = buildRuntimeFor(tab);
434
+ void bridgeTabMcp(tab);
435
+ }
436
+ tabs.set(tab.id, tab);
437
+ return tab;
438
+ }
439
+ function bridgeTabMcp(tab) {
440
+ if (!tab.runtime) return Promise.resolve();
441
+ if (tab.mcpRuntime) {
442
+ return tab.mcpRuntime.reloadFromConfig(tab.runtime.loop).then(() => emitMcpSpecs(tab)).catch((err) => {
443
+ emit({ type: "$error", message: `mcp reload failed: ${err.message}` }, tab.id);
444
+ });
445
+ }
446
+ const requested = (readConfig().mcp ?? []).length;
447
+ if (requested === 0) return Promise.resolve();
448
+ const runtime = createMcpRuntime({
449
+ getTools: () => tab.toolset.tools,
450
+ getMcpPrefix: () => void 0,
451
+ getRequestedCount: () => requested,
452
+ progressSink: { current: null }
453
+ });
454
+ tab.mcpRuntime = runtime;
455
+ runtime.setLifecycleSink((notice) => {
456
+ if (notice.kind === "slow") return;
457
+ const cfg = readConfig().mcp ?? [];
458
+ const target = cfg.find((raw) => {
459
+ try {
460
+ return parseMcpSpec(raw).name === notice.name;
461
+ } catch {
462
+ return false;
463
+ }
464
+ });
465
+ if (!target) return;
466
+ if (notice.kind === "handshake") {
467
+ tab.mcpStatuses.set(target, { kind: "handshake" });
468
+ } else if (notice.kind === "connected") {
469
+ tab.mcpStatuses.set(target, { kind: "connected", toolCount: notice.tools });
470
+ } else if (notice.kind === "failed") {
471
+ tab.mcpStatuses.set(target, { kind: "failed", reason: notice.reason });
472
+ } else if (notice.kind === "disabled") {
473
+ tab.mcpStatuses.set(target, { kind: "disabled" });
474
+ }
475
+ emitMcpSpecs(tab);
476
+ });
477
+ return runtime.reloadFromConfig(tab.runtime.loop).then(() => void 0).catch((err) => {
478
+ emit({ type: "$error", message: `mcp bridge failed: ${err.message}` }, tab.id);
479
+ });
480
+ }
481
+ async function closeTab(tab) {
482
+ tab.aborter?.abort();
483
+ try {
484
+ await tab.toolset.jobs.shutdown();
485
+ } catch {
486
+ }
487
+ if (tab.mcpRuntime) {
488
+ try {
489
+ await tab.mcpRuntime.closeAll();
490
+ } catch {
491
+ }
492
+ }
493
+ tabs.delete(tab.id);
494
+ emit({ type: "$tab_closed" }, tab.id);
495
+ }
496
+ async function runTurn(tab, text) {
497
+ if (!tab.runtime) return;
498
+ const rt = tab.runtime;
499
+ tab.aborter = new AbortController();
500
+ if (tab.currentSession) {
501
+ const existing = loadSessionMeta(tab.currentSession).summary;
502
+ if (!existing || !existing.trim()) {
503
+ const summary = text.replace(/\s+/g, " ").trim().slice(0, 60);
504
+ if (summary) {
505
+ try {
506
+ patchSessionMeta(tab.currentSession, { summary });
507
+ } catch {
508
+ }
509
+ }
510
+ }
511
+ }
512
+ await tabContext.run(tab.id, async () => {
513
+ try {
514
+ for await (const ev of rt.loop.step(text)) {
515
+ for (const kev of rt.eventizer.consume(ev, rt.ctx)) emit(kev, tab.id);
516
+ if (tab.aborter?.signal.aborted) break;
517
+ }
518
+ } catch (err) {
519
+ emit({ type: "$error", message: err.message }, tab.id);
520
+ } finally {
521
+ tab.aborter = null;
522
+ emit({ type: "$turn_complete" }, tab.id);
523
+ if (tab.planTotalSteps > 0 && tab.completedStepIds.size >= tab.planTotalSteps) {
524
+ tab.completedStepIds.clear();
525
+ tab.planTotalSteps = 0;
526
+ emit({ type: "$plan_cleared" }, tab.id);
527
+ }
528
+ emitSessions(tab);
529
+ void emitBalance(tab);
530
+ }
531
+ });
532
+ }
533
+ async function switchWorkspace(tab, nextDir) {
534
+ const target = resolve(nextDir);
535
+ if (target === tab.rootDir) {
536
+ emitSettings(tab);
537
+ return;
538
+ }
539
+ if (!existsSync(target) || !statSync(target).isDirectory()) {
540
+ emit({ type: "$error", message: `Workspace not found: ${target}` }, tab.id);
541
+ emitSettings(tab);
542
+ return;
543
+ }
544
+ tab.aborter?.abort();
545
+ try {
546
+ await tab.toolset.jobs.shutdown();
547
+ } catch {
548
+ }
549
+ tab.rootDir = target;
550
+ saveWorkspaceDir(target);
551
+ pushRecentWorkspace(target);
552
+ tab.fileIndex = null;
553
+ tab.fileIndexBuilding = null;
554
+ tab.symbolIndex = null;
555
+ tab.symbolBuilding = null;
556
+ tab.recentMentions.length = 0;
557
+ tab.currentSession = mintSessionFor(target);
558
+ tab.toolset = await buildCodeToolset({ rootDir: target });
559
+ tab.system = codeSystemPrompt(target, {
560
+ hasSemanticSearch: tab.toolset.semantic.enabled,
561
+ modelId: tab.currentModel
562
+ });
563
+ if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
564
+ emitSessions(tab);
565
+ emitSettings(tab);
566
+ emitSkills(tab);
567
+ }
568
+ function forgetGate(id) {
569
+ for (const t of tabs.values()) {
570
+ if (t.pendingGateIds.delete(id)) return t;
571
+ }
572
+ return void 0;
573
+ }
574
+ function cancelPendingGates(tab) {
575
+ const hadActivePlan = tab.planTotalSteps > 0 || tab.completedStepIds.size > 0;
576
+ const ids = [...tab.pendingGateIds];
577
+ tab.pendingGateIds.clear();
578
+ for (const id of ids) pauseGate.cancel(id);
579
+ if (hadActivePlan) {
580
+ tab.completedStepIds.clear();
581
+ tab.planTotalSteps = 0;
582
+ emit({ type: "$plan_cleared" }, tab.id);
583
+ }
584
+ }
585
+ const first = await createTab();
586
+ process.once("exit", () => {
587
+ for (const t of tabs.values()) void t.toolset.jobs.shutdown();
588
+ });
589
+ pauseGate.on((req) => {
590
+ const tab = activeRunningTab();
591
+ const tabId = tab?.id;
592
+ if (tab) tab.pendingGateIds.add(req.id);
593
+ const auto = autoResolveVerdict(req, loadEditMode());
594
+ if (auto !== null) {
595
+ if (req.kind === "plan_checkpoint") {
596
+ const payload = req.payload;
597
+ if (tab) tab.completedStepIds.add(payload.stepId);
598
+ emit(
599
+ {
600
+ type: "$step_completed",
601
+ stepId: payload.stepId,
602
+ title: payload.title,
603
+ result: payload.result,
604
+ notes: payload.notes
605
+ },
606
+ tabId
607
+ );
608
+ }
609
+ if (tab) tab.pendingGateIds.delete(req.id);
610
+ pauseGate.resolve(req.id, auto);
611
+ return;
612
+ }
613
+ if (req.kind === "run_command" || req.kind === "run_background") {
614
+ const payload = req.payload;
615
+ emit(
616
+ { type: "$confirm_required", id: req.id, kind: req.kind, command: payload.command ?? "" },
617
+ tabId
618
+ );
619
+ return;
620
+ }
621
+ if (req.kind === "path_access") {
622
+ const payload = req.payload;
623
+ emit(
624
+ {
625
+ type: "$path_access_required",
626
+ id: req.id,
627
+ path: payload.path,
628
+ intent: payload.intent,
629
+ toolName: payload.toolName,
630
+ sandboxRoot: payload.sandboxRoot,
631
+ allowPrefix: payload.allowPrefix
632
+ },
633
+ tabId
634
+ );
635
+ return;
636
+ }
637
+ if (req.kind === "choice") {
638
+ const payload = req.payload;
639
+ emit(
640
+ {
641
+ type: "$choice_required",
642
+ id: req.id,
643
+ question: payload.question,
644
+ options: payload.options,
645
+ allowCustom: payload.allowCustom
646
+ },
647
+ tabId
648
+ );
649
+ return;
650
+ }
651
+ if (req.kind === "plan_proposed") {
652
+ const payload = req.payload;
653
+ if (tab) {
654
+ tab.completedStepIds.clear();
655
+ tab.planTotalSteps = payload.steps?.length ?? 0;
656
+ }
657
+ emit(
658
+ {
659
+ type: "$plan_required",
660
+ id: req.id,
661
+ plan: payload.plan,
662
+ steps: payload.steps,
663
+ summary: payload.summary
664
+ },
665
+ tabId
666
+ );
667
+ return;
668
+ }
669
+ if (req.kind === "plan_checkpoint") {
670
+ const payload = req.payload;
671
+ if (tab) tab.completedStepIds.add(payload.stepId);
672
+ emit(
673
+ {
674
+ type: "$step_completed",
675
+ stepId: payload.stepId,
676
+ title: payload.title,
677
+ result: payload.result,
678
+ notes: payload.notes
679
+ },
680
+ tabId
681
+ );
682
+ emit(
683
+ {
684
+ type: "$checkpoint_required",
685
+ id: req.id,
686
+ stepId: payload.stepId,
687
+ title: payload.title,
688
+ result: payload.result,
689
+ notes: payload.notes,
690
+ completed: tab?.completedStepIds.size ?? 0,
691
+ total: tab?.planTotalSteps ?? 0
692
+ },
693
+ tabId
694
+ );
695
+ return;
696
+ }
697
+ if (req.kind === "plan_revision") {
698
+ const payload = req.payload;
699
+ emit(
700
+ {
701
+ type: "$revision_required",
702
+ id: req.id,
703
+ reason: payload.reason,
704
+ remainingSteps: payload.remainingSteps,
705
+ summary: payload.summary
706
+ },
707
+ tabId
708
+ );
709
+ return;
710
+ }
711
+ });
712
+ emit({ type: "$tab_opened", workspaceDir: first.rootDir }, first.id);
713
+ if (loadApiKey()) emit({ type: "$ready" }, first.id);
714
+ else emit({ type: "$needs_setup", reason: "no_api_key" }, first.id);
715
+ emitSessions(first);
716
+ emitSettings(first);
717
+ emitMcpSpecs(first);
718
+ emitSkills(first);
719
+ emitMemory(first);
720
+ emitCtxBreakdown(first);
721
+ void emitBalance(first);
722
+ const rl = createInterface({ input: stdin });
723
+ rl.on("line", (line) => {
724
+ const trimmed = line.trim();
725
+ if (!trimmed) return;
726
+ let msg;
727
+ try {
728
+ msg = JSON.parse(trimmed);
729
+ } catch {
730
+ emit({ type: "$error", message: `bad json on stdin: ${trimmed.slice(0, 80)}` });
731
+ return;
732
+ }
733
+ if (msg.cmd === "tab_open") {
734
+ void (async () => {
735
+ try {
736
+ const tab2 = await createTab(msg.workspaceDir);
737
+ emit({ type: "$tab_opened", workspaceDir: tab2.rootDir }, tab2.id);
738
+ if (loadApiKey()) emit({ type: "$ready" }, tab2.id);
739
+ else emit({ type: "$needs_setup", reason: "no_api_key" }, tab2.id);
740
+ emitSessions(tab2);
741
+ emitSettings(tab2);
742
+ emitMcpSpecs(tab2);
743
+ emitSkills(tab2);
744
+ emitMemory(tab2);
745
+ emitCtxBreakdown(tab2);
746
+ void emitBalance(tab2);
747
+ } catch (err) {
748
+ emit({ type: "$error", message: `tab_open failed: ${err.message}` });
749
+ }
750
+ })();
751
+ return;
752
+ }
753
+ if (msg.cmd === "confirm_response") {
754
+ forgetGate(msg.id);
755
+ pauseGate.resolve(msg.id, msg.response);
756
+ return;
757
+ }
758
+ if (msg.cmd === "choice_response") {
759
+ forgetGate(msg.id);
760
+ pauseGate.resolve(msg.id, msg.response);
761
+ return;
762
+ }
763
+ if (msg.cmd === "plan_response") {
764
+ const tab2 = forgetGate(msg.id);
765
+ if (tab2 && msg.response.type === "cancel") {
766
+ tab2.completedStepIds.clear();
767
+ tab2.planTotalSteps = 0;
768
+ emit({ type: "$plan_cleared" }, tab2.id);
769
+ }
770
+ pauseGate.resolve(msg.id, msg.response);
771
+ return;
772
+ }
773
+ if (msg.cmd === "checkpoint_response") {
774
+ const tab2 = forgetGate(msg.id);
775
+ if (tab2 && msg.response.type === "stop") {
776
+ tab2.completedStepIds.clear();
777
+ tab2.planTotalSteps = 0;
778
+ emit({ type: "$plan_cleared" }, tab2.id);
779
+ }
780
+ pauseGate.resolve(msg.id, msg.response);
781
+ return;
782
+ }
783
+ if (msg.cmd === "revision_response") {
784
+ forgetGate(msg.id);
785
+ pauseGate.resolve(msg.id, msg.response);
786
+ return;
787
+ }
788
+ if (msg.cmd === "setup_save_key") {
789
+ const key = msg.key.trim();
790
+ if (!isPlausibleKey(key)) {
791
+ emit({
792
+ type: "$error",
793
+ message: "Key looks too short \u2014 paste the full token (16+ chars, no spaces)."
794
+ });
795
+ return;
796
+ }
797
+ try {
798
+ saveApiKey(key);
799
+ process.env.DEEPSEEK_API_KEY = key;
800
+ for (const tab2 of tabs.values()) {
801
+ tab2.runtime = buildRuntimeFor(tab2);
802
+ emit({ type: "$ready" }, tab2.id);
803
+ emitSettings(tab2);
804
+ void emitBalance(tab2);
805
+ }
806
+ } catch (err) {
807
+ emit({ type: "$error", message: `saveApiKey failed: ${err.message}` });
808
+ }
809
+ return;
810
+ }
811
+ const tab = msg.tabId ? tabs.get(msg.tabId) : first;
812
+ if (!tab) {
813
+ emit({ type: "$error", message: `unknown tab: ${msg.tabId}` });
814
+ return;
815
+ }
816
+ if (msg.cmd === "abort") {
817
+ tab.aborter?.abort();
818
+ cancelPendingGates(tab);
819
+ return;
820
+ }
821
+ if (msg.cmd === "tab_close") {
822
+ void closeTab(tab);
823
+ return;
824
+ }
825
+ if (msg.cmd === "mcp_specs_get") {
826
+ emitMcpSpecs(tab);
827
+ return;
828
+ }
829
+ if (msg.cmd === "mcp_specs_add") {
830
+ const spec = msg.spec.trim();
831
+ if (!spec) {
832
+ emit({ type: "$error", message: "mcp_specs_add: spec is empty" }, tab.id);
833
+ return;
834
+ }
835
+ try {
836
+ parseMcpSpec(spec);
837
+ } catch (err) {
838
+ emit({ type: "$error", message: `mcp_specs_add: ${err.message}` }, tab.id);
839
+ return;
840
+ }
841
+ try {
842
+ const cfg = readConfig();
843
+ const list = cfg.mcp ?? [];
844
+ if (!list.includes(spec)) {
845
+ cfg.mcp = [...list, spec];
846
+ writeConfig(cfg);
847
+ }
848
+ emitMcpSpecs(tab);
849
+ void bridgeTabMcp(tab);
850
+ } catch (err) {
851
+ emit({ type: "$error", message: `mcp_specs_add: ${err.message}` }, tab.id);
852
+ }
853
+ return;
854
+ }
855
+ if (msg.cmd === "mcp_specs_remove") {
856
+ try {
857
+ const cfg = readConfig();
858
+ const list = cfg.mcp ?? [];
859
+ if (list.includes(msg.spec)) {
860
+ cfg.mcp = list.filter((s) => s !== msg.spec);
861
+ writeConfig(cfg);
862
+ }
863
+ tab.mcpStatuses.delete(msg.spec);
864
+ emitMcpSpecs(tab);
865
+ void bridgeTabMcp(tab);
866
+ } catch (err) {
867
+ emit({ type: "$error", message: `mcp_specs_remove: ${err.message}` }, tab.id);
868
+ }
869
+ return;
870
+ }
871
+ if (msg.cmd === "skills_get") {
872
+ emitSkills(tab);
873
+ return;
874
+ }
875
+ if (msg.cmd === "session_list") {
876
+ emitSessions(tab);
877
+ return;
878
+ }
879
+ if (msg.cmd === "session_delete") {
880
+ deleteSession(msg.name);
881
+ emitSessions(tab);
882
+ return;
883
+ }
884
+ if (msg.cmd === "session_load") {
885
+ try {
886
+ const records = loadSessionMessages(msg.name);
887
+ const meta = loadSessionMeta(msg.name);
888
+ tab.aborter?.abort();
889
+ cancelPendingGates(tab);
890
+ tab.currentSession = msg.name;
891
+ if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
892
+ emit(
893
+ {
894
+ type: "$session_loaded",
895
+ name: msg.name,
896
+ messages: buildLoadedMessages(records),
897
+ carryover: {
898
+ totalCostUsd: meta.totalCostUsd ?? 0,
899
+ cacheHitTokens: meta.cacheHitTokens ?? 0,
900
+ cacheMissTokens: meta.cacheMissTokens ?? 0
901
+ }
902
+ },
903
+ tab.id
904
+ );
905
+ } catch (err) {
906
+ emit({ type: "$error", message: `session_load failed: ${err.message}` }, tab.id);
907
+ }
908
+ return;
909
+ }
910
+ if (msg.cmd === "new_chat") {
911
+ tab.aborter?.abort();
912
+ cancelPendingGates(tab);
913
+ tab.currentSession = mintSessionFor(tab.rootDir);
914
+ if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
915
+ emitSessions(tab);
916
+ return;
917
+ }
918
+ if (msg.cmd === "settings_get") {
919
+ emitSettings(tab);
920
+ return;
921
+ }
922
+ if (msg.cmd === "settings_save") {
923
+ try {
924
+ if (msg.reasoningEffort !== void 0) {
925
+ saveReasoningEffort(msg.reasoningEffort);
926
+ tab.runtime?.loop.configure({ reasoningEffort: msg.reasoningEffort });
927
+ }
928
+ if (msg.editMode !== void 0) saveEditMode(msg.editMode);
929
+ if (msg.budgetUsd !== void 0) {
930
+ tab.budgetUsd = msg.budgetUsd ?? void 0;
931
+ tab.runtime?.loop.setBudget(msg.budgetUsd);
932
+ }
933
+ if (msg.baseUrl !== void 0) saveBaseUrl(msg.baseUrl);
934
+ if (msg.workspaceDir !== void 0) {
935
+ void switchWorkspace(tab, msg.workspaceDir);
936
+ return;
937
+ }
938
+ if (msg.editor !== void 0) saveEditor(msg.editor);
939
+ if (msg.preset !== void 0) {
940
+ tab.currentPreset = canonicalPresetName(msg.preset);
941
+ const resolved = resolvePreset(tab.currentPreset);
942
+ tab.currentModel = resolved.model;
943
+ savePreset(tab.currentPreset);
944
+ tab.system = codeSystemPrompt(tab.rootDir, {
945
+ hasSemanticSearch: tab.toolset.semantic.enabled,
946
+ modelId: tab.currentModel
947
+ });
948
+ if (tab.runtime) tab.runtime = buildRuntimeFor(tab);
949
+ }
950
+ emitSettings(tab);
951
+ } catch (err) {
952
+ emit(
953
+ { type: "$error", message: `settings_save failed: ${err.message}` },
954
+ tab.id
955
+ );
956
+ }
957
+ return;
958
+ }
959
+ if (msg.cmd === "mention_query") {
960
+ const nonce = msg.nonce;
961
+ const query = msg.query;
962
+ const parsed = parseAtQuery(query);
963
+ if (parsed.trailingSlash) {
964
+ void listDirectory(tab.rootDir, parsed.dir).then((entries) => {
965
+ const results = entries.map((e) => e.isDir ? `${e.path}/` : e.path);
966
+ emit({ type: "$mention_results", nonce, query, results }, tab.id);
967
+ }).catch((err) => {
968
+ emit(
969
+ { type: "$error", message: `mention_query (dir) failed: ${err.message}` },
970
+ tab.id
971
+ );
972
+ emit({ type: "$mention_results", nonce, query, results: [] }, tab.id);
973
+ });
974
+ return;
975
+ }
976
+ const wantSymbols = query.length >= 2 && !query.includes("/");
977
+ void (async () => {
978
+ try {
979
+ const files = await getFileIndexFor(tab);
980
+ const fileResults = rankPickerCandidates(files, query, {
981
+ limit: wantSymbols ? 19 : 25,
982
+ recentlyUsed: tab.recentMentions
983
+ });
984
+ let symResults = [];
985
+ if (wantSymbols) {
986
+ const syms = await getSymbolIndexFor(tab);
987
+ symResults = rankSymbols(syms, query, 6);
988
+ }
989
+ emit(
990
+ { type: "$mention_results", nonce, query, results: [...symResults, ...fileResults] },
991
+ tab.id
992
+ );
993
+ } catch (err) {
994
+ emit(
995
+ { type: "$error", message: `mention_query failed: ${err.message}` },
996
+ tab.id
997
+ );
998
+ emit({ type: "$mention_results", nonce, query, results: [] }, tab.id);
999
+ }
1000
+ })();
1001
+ return;
1002
+ }
1003
+ if (msg.cmd === "mention_picked") {
1004
+ pushMentionRecent(tab, msg.path);
1005
+ return;
1006
+ }
1007
+ if (msg.cmd === "mention_preview") {
1008
+ const nonce = msg.nonce;
1009
+ const rel = msg.path;
1010
+ const abs = isAbsolute(rel) ? rel : join(tab.rootDir, rel);
1011
+ const safeAbs = resolve(abs);
1012
+ const safeRoot = resolve(tab.rootDir);
1013
+ if (!safeAbs.startsWith(safeRoot)) {
1014
+ emit({ type: "$mention_preview", nonce, path: rel, head: "", totalLines: 0 }, tab.id);
1015
+ return;
1016
+ }
1017
+ void readFile(safeAbs, "utf8").then((text) => {
1018
+ const lines = text.split(/\r?\n/);
1019
+ if (lines.length > 0 && lines[lines.length - 1] === "") lines.pop();
1020
+ const head = lines.slice(0, 12).join("\n");
1021
+ emit(
1022
+ { type: "$mention_preview", nonce, path: rel, head, totalLines: lines.length },
1023
+ tab.id
1024
+ );
1025
+ }).catch(() => {
1026
+ emit({ type: "$mention_preview", nonce, path: rel, head: "", totalLines: 0 }, tab.id);
1027
+ });
1028
+ return;
1029
+ }
1030
+ if (msg.cmd === "user_input") {
1031
+ if (!tab.runtime) {
1032
+ emit(
1033
+ { type: "$error", message: "Not configured yet \u2014 paste your DeepSeek API key first." },
1034
+ tab.id
1035
+ );
1036
+ return;
1037
+ }
1038
+ void runTurn(tab, msg.text);
1039
+ }
1040
+ });
1041
+ await new Promise((resolve2) => rl.on("close", resolve2));
1042
+ }
1043
+ export {
1044
+ desktopCommand
1045
+ };
1046
+ //# sourceMappingURL=desktop-R6W5CLJ5.js.map