@duckmind/dm-darwin-x64 0.33.0 → 0.33.1

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 (81) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +1 -76
  3. package/package.json +1 -1
  4. package/theme/theme-alps.json +93 -0
  5. package/extensions/dm-chime/README.md +0 -11
  6. package/extensions/dm-chime/docs/protocols.md +0 -107
  7. package/extensions/dm-chime/index.ts +0 -205
  8. package/extensions/dm-chime/package.json +0 -33
  9. package/extensions/dm-phone/README.md +0 -24
  10. package/extensions/dm-phone/index.ts +0 -12
  11. package/extensions/dm-phone/node_modules/.package-lock.json +0 -29
  12. package/extensions/dm-phone/node_modules/ws/LICENSE +0 -20
  13. package/extensions/dm-phone/node_modules/ws/README.md +0 -548
  14. package/extensions/dm-phone/node_modules/ws/browser.js +0 -8
  15. package/extensions/dm-phone/node_modules/ws/index.js +0 -22
  16. package/extensions/dm-phone/node_modules/ws/lib/buffer-util.js +0 -131
  17. package/extensions/dm-phone/node_modules/ws/lib/constants.js +0 -19
  18. package/extensions/dm-phone/node_modules/ws/lib/event-target.js +0 -292
  19. package/extensions/dm-phone/node_modules/ws/lib/extension.js +0 -203
  20. package/extensions/dm-phone/node_modules/ws/lib/limiter.js +0 -55
  21. package/extensions/dm-phone/node_modules/ws/lib/permessage-deflate.js +0 -528
  22. package/extensions/dm-phone/node_modules/ws/lib/receiver.js +0 -760
  23. package/extensions/dm-phone/node_modules/ws/lib/sender.js +0 -607
  24. package/extensions/dm-phone/node_modules/ws/lib/stream.js +0 -161
  25. package/extensions/dm-phone/node_modules/ws/lib/subprotocol.js +0 -62
  26. package/extensions/dm-phone/node_modules/ws/lib/validation.js +0 -152
  27. package/extensions/dm-phone/node_modules/ws/lib/websocket-server.js +0 -562
  28. package/extensions/dm-phone/node_modules/ws/lib/websocket.js +0 -1407
  29. package/extensions/dm-phone/node_modules/ws/package.json +0 -70
  30. package/extensions/dm-phone/node_modules/ws/wrapper.mjs +0 -21
  31. package/extensions/dm-phone/package-lock.json +0 -66
  32. package/extensions/dm-phone/package.json +0 -35
  33. package/extensions/dm-phone/phone-session-pool.ts +0 -8
  34. package/extensions/dm-phone/public/app/attachments.js +0 -233
  35. package/extensions/dm-phone/public/app/autocomplete-controller.js +0 -81
  36. package/extensions/dm-phone/public/app/autocomplete.js +0 -135
  37. package/extensions/dm-phone/public/app/bindings.js +0 -178
  38. package/extensions/dm-phone/public/app/command-catalog.js +0 -76
  39. package/extensions/dm-phone/public/app/commands.js +0 -376
  40. package/extensions/dm-phone/public/app/constants.js +0 -60
  41. package/extensions/dm-phone/public/app/formatters.js +0 -131
  42. package/extensions/dm-phone/public/app/handlers.js +0 -442
  43. package/extensions/dm-phone/public/app/main.js +0 -6
  44. package/extensions/dm-phone/public/app/markdown.js +0 -105
  45. package/extensions/dm-phone/public/app/messages.js +0 -418
  46. package/extensions/dm-phone/public/app/sheet-actions.js +0 -113
  47. package/extensions/dm-phone/public/app/sheet-navigation.js +0 -19
  48. package/extensions/dm-phone/public/app/sheets-view.js +0 -287
  49. package/extensions/dm-phone/public/app/state.js +0 -95
  50. package/extensions/dm-phone/public/app/tool-rendering.js +0 -562
  51. package/extensions/dm-phone/public/app/transport.js +0 -176
  52. package/extensions/dm-phone/public/app/ui.js +0 -417
  53. package/extensions/dm-phone/public/app.js +0 -1
  54. package/extensions/dm-phone/public/icon.svg +0 -15
  55. package/extensions/dm-phone/public/index.html +0 -146
  56. package/extensions/dm-phone/public/manifest.webmanifest +0 -17
  57. package/extensions/dm-phone/public/styles.css +0 -1139
  58. package/extensions/dm-phone/public/sw.js +0 -78
  59. package/extensions/dm-phone/src/extension/duckmind-models.js +0 -264
  60. package/extensions/dm-phone/src/extension/phone-args.ts +0 -121
  61. package/extensions/dm-phone/src/extension/phone-paths.ts +0 -250
  62. package/extensions/dm-phone/src/extension/phone-quota.ts +0 -188
  63. package/extensions/dm-phone/src/extension/phone-runtime.ts +0 -154
  64. package/extensions/dm-phone/src/extension/phone-server-runtime.ts +0 -1217
  65. package/extensions/dm-phone/src/extension/phone-sessions.ts +0 -139
  66. package/extensions/dm-phone/src/extension/phone-static.ts +0 -30
  67. package/extensions/dm-phone/src/extension/phone-tailscale.ts +0 -148
  68. package/extensions/dm-phone/src/extension/phone-theme.ts +0 -85
  69. package/extensions/dm-phone/src/extension/register-phone-child-extension.ts +0 -112
  70. package/extensions/dm-phone/src/extension/register-phone-extension.ts +0 -106
  71. package/extensions/dm-phone/src/extension/types.ts +0 -73
  72. package/extensions/dm-phone/src/session-pool/parent-session-worker.ts +0 -882
  73. package/extensions/dm-phone/src/session-pool/session-pool.ts +0 -470
  74. package/extensions/dm-phone/src/session-pool/session-worker.ts +0 -739
  75. package/extensions/dm-phone/src/session-pool/types.ts +0 -111
  76. package/extensions/dm-phone/src/session-pool/utils.ts +0 -23
  77. package/extensions/dm-phone/test/duckmind-models.test.js +0 -147
  78. package/extensions/dm-thinking-timer/LICENSE +0 -21
  79. package/extensions/dm-thinking-timer/README.md +0 -7
  80. package/extensions/dm-thinking-timer/package.json +0 -20
  81. package/extensions/dm-thinking-timer/thinking-timer.ts +0 -250
@@ -1,131 +0,0 @@
1
- export function escapeHtml(text = "") {
2
- return String(text)
3
- .replaceAll("&", "&")
4
- .replaceAll("<", "&lt;")
5
- .replaceAll(">", "&gt;")
6
- .replaceAll('"', "&quot;")
7
- .replaceAll("'", "&#039;");
8
- }
9
-
10
- export function escapeAttribute(text = "") {
11
- return escapeHtml(text).replaceAll("`", "&#096;");
12
- }
13
-
14
- export function formatCwdDisplay(path = "") {
15
- const value = String(path || "").trim();
16
- if (!value) return "";
17
-
18
- const homeMatch = value.match(/^\/(?:home|Users)\/[^/]+(\/.*)?$/);
19
- if (homeMatch) {
20
- const suffix = homeMatch[1] || "";
21
- const parts = suffix.split("/").filter(Boolean);
22
- if (!parts.length) return "~";
23
- if (parts.length === 1) return `~/${parts[0]}`;
24
- return `~/…/${parts[parts.length - 1]}`;
25
- }
26
-
27
- if (value === "/") return value;
28
-
29
- const parts = value.split("/").filter(Boolean);
30
- if (parts.length <= 2) return value;
31
- return `/…/${parts[parts.length - 1]}`;
32
- }
33
-
34
- export function formatTimestamp(timestamp) {
35
- if (!timestamp) return "";
36
- const date = new Date(timestamp);
37
- return date.toLocaleTimeString([], { hour: "numeric", minute: "2-digit" });
38
- }
39
-
40
- export function formatDateTime(value) {
41
- if (!value) return "";
42
- const date = new Date(value);
43
- if (Number.isNaN(date.getTime())) return "";
44
- return date.toLocaleString([], { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" });
45
- }
46
-
47
- export function formatBytes(bytes) {
48
- if (!Number.isFinite(bytes)) return "";
49
- if (bytes < 1024) return `${bytes} B`;
50
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
51
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
52
- }
53
-
54
- export function formatTokenCount(count) {
55
- if (!Number.isFinite(count) || count <= 0) return "";
56
- if (count < 1000) return String(Math.round(count));
57
- if (count < 10000) return `${(count / 1000).toFixed(1)}k`;
58
- if (count < 1000000) return `${Math.round(count / 1000)}k`;
59
- if (count < 10000000) return `${(count / 1000000).toFixed(1)}M`;
60
- return `${Math.round(count / 1000000)}M`;
61
- }
62
-
63
- export function normalizeNewlines(text = "") {
64
- return String(text ?? "").replace(/\r\n?/g, "\n");
65
- }
66
-
67
- export function stripTerminalControlSequences(text = "") {
68
- return String(text ?? "")
69
- .replace(/\u001B\][^\u0007\u001B]*(?:\u0007|\u001B\\)/g, "")
70
- .replace(/\u009D[^\u009C]*\u009C/g, "")
71
- .replace(/\u001B\[[0-?]*[ -/]*[@-~]/g, "")
72
- .replace(/\u009B[0-?]*[ -/]*[@-~]/g, "")
73
- .replace(/\u001B[@-_]/g, "")
74
- .replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "");
75
- }
76
-
77
- export function countTextLines(text = "") {
78
- const normalized = normalizeNewlines(text);
79
- if (!normalized.length) return 0;
80
- return normalized.split("\n").length;
81
- }
82
-
83
- export function asRecord(value) {
84
- if (!value || typeof value !== "object" || Array.isArray(value)) return null;
85
- return value;
86
- }
87
-
88
- export function contentToText(content) {
89
- if (typeof content === "string") return stripTerminalControlSequences(content);
90
- if (!Array.isArray(content)) return "";
91
- return stripTerminalControlSequences(content
92
- .map((part) => {
93
- if (part.type === "text") return part.text || "";
94
- if (part.type === "image") return "[image]";
95
- if (part.type === "thinking") return "";
96
- if (part.type === "toolCall") return "";
97
- return "";
98
- })
99
- .join(" ")
100
- .trim());
101
- }
102
-
103
- export function countImages(content) {
104
- if (!Array.isArray(content)) return 0;
105
- return content.filter((part) => part.type === "image").length;
106
- }
107
-
108
- export function assistantParts(content) {
109
- const parts = { text: "", thinking: "", toolCalls: [] };
110
- if (!Array.isArray(content)) return parts;
111
-
112
- for (const block of content) {
113
- if (block.type === "text") parts.text += stripTerminalControlSequences(block.text || "");
114
- if (block.type === "thinking") parts.thinking += stripTerminalControlSequences(block.thinking || "");
115
- if (block.type === "toolCall") {
116
- parts.toolCalls.push({ id: block.id || "", name: block.name || "tool", arguments: block.arguments || {} });
117
- }
118
- }
119
-
120
- return parts;
121
- }
122
-
123
- export function toDetailString(details) {
124
- if (details == null) return "";
125
- if (typeof details === "string") return details;
126
- try {
127
- return JSON.stringify(details, null, 2);
128
- } catch {
129
- return String(details);
130
- }
131
- }
@@ -1,442 +0,0 @@
1
- import { contentToText } from "./formatters.js";
2
- import {
3
- clearSnapshotView,
4
- clearTransientState,
5
- handleAssistantEvent,
6
- renderMessages,
7
- renderWidgets,
8
- transformMessage,
9
- upsertLiveTool,
10
- } from "./messages.js";
11
- import { closeSheet } from "./sheet-navigation.js";
12
- import { renderSheet } from "./sheets-view.js";
13
- import { state } from "./state.js";
14
- import { refreshAll, refreshQuota, sendRpc } from "./transport.js";
15
- import {
16
- autoResizeTextarea,
17
- clearUiModal,
18
- openTokenModal,
19
- openUiModalForRequest,
20
- renderHeader,
21
- resetToken,
22
- showBanner,
23
- showToast,
24
- } from "./ui.js";
25
- import { renderCommandSuggestions } from "./autocomplete-controller.js";
26
- import { renderAutocompleteItems } from "./autocomplete.js";
27
-
28
- export function handleAuthFailure() {
29
- resetToken({ clearInput: true });
30
- state.socket = null;
31
- renderHeader();
32
- openTokenModal();
33
- showBanner("Access token required. Enter the current /phone-start token.", "error");
34
- }
35
-
36
- function sendUiResponse(payload) {
37
- sendRpc({ type: "extension_ui_response", ...payload });
38
- clearUiModal();
39
- }
40
-
41
- function handleExtensionUiRequest(request) {
42
- if (request.method === "notify") {
43
- showToast(request.message || "Notification");
44
- return;
45
- }
46
-
47
- if (request.method === "setStatus") {
48
- state.footerStatus = request.statusText || "";
49
- renderWidgets();
50
- return;
51
- }
52
-
53
- if (request.method === "setWidget") {
54
- if (request.widgetLines?.length) state.widgets.set(request.widgetKey || "widget", request.widgetLines);
55
- else state.widgets.delete(request.widgetKey || "widget");
56
- renderWidgets();
57
- return;
58
- }
59
-
60
- if (request.method === "setTitle") {
61
- document.title = request.title || "DM Phone";
62
- return;
63
- }
64
-
65
- if (request.method === "set_editor_text") {
66
- const promptInput = document.querySelector("#prompt-input");
67
- if (promptInput) promptInput.value = request.text || "";
68
- autoResizeTextarea();
69
- renderCommandSuggestions();
70
- return;
71
- }
72
-
73
- if (!["select", "confirm", "input", "editor"].includes(request.method)) {
74
- showToast(`Unsupported UI request: ${request.method || "unknown"}`);
75
- return;
76
- }
77
-
78
- openUiModalForRequest(request, sendUiResponse);
79
- }
80
-
81
- function handleRpcPayload(payload) {
82
- if (!payload) return;
83
-
84
- if (payload.type === "response") {
85
- if (!payload.success) {
86
- if (payload.command === "path_suggestions") {
87
- renderAutocompleteItems([]);
88
- return;
89
- }
90
- showToast(payload.error || `Command failed: ${payload.command}`, "error");
91
- return;
92
- }
93
-
94
- if (payload.command === "get_state") {
95
- state.snapshotState = payload.data || state.snapshotState;
96
- renderHeader();
97
- void refreshQuota();
98
- return;
99
- }
100
-
101
- if (payload.command === "get_messages") {
102
- state.messages = (payload.data?.messages || []).flatMap(transformMessage);
103
- clearTransientState();
104
- renderMessages();
105
- return;
106
- }
107
-
108
- if (payload.command === "get_commands") {
109
- state.commands = payload.data?.commands || [];
110
- renderCommandSuggestions();
111
- renderSheet();
112
- return;
113
- }
114
-
115
- if (payload.command === "path_suggestions") {
116
- const context = state.autocompleteContext;
117
- if (!context || context.type !== "path") return;
118
- if (Number(payload.data?.requestId) !== state.autocompleteRemoteRequestId) return;
119
- if (payload.data?.mode !== context.mode) return;
120
- if ((payload.data?.query || "") !== context.query) return;
121
-
122
- const suggestions = Array.isArray(payload.data?.suggestions) ? payload.data.suggestions : [];
123
- renderAutocompleteItems(suggestions.map((suggestion) => ({
124
- kind: "path",
125
- label: context.mode === "mention" ? `@${suggestion.value}` : suggestion.value,
126
- badge: suggestion.kind === "previous" ? "recent" : suggestion.isDirectory ? "dir" : "file",
127
- description: suggestion.description || suggestion.value,
128
- value: suggestion.value,
129
- isDirectory: Boolean(suggestion.isDirectory),
130
- title: suggestion.description || suggestion.value,
131
- })));
132
- return;
133
- }
134
-
135
- if (payload.command === "cd") {
136
- showToast(`Changed directory to ${payload.data?.cwd || "the selected path"}.`);
137
- refreshAll();
138
- return;
139
- }
140
-
141
- if (payload.command === "get_available_models") {
142
- state.models = payload.data?.models || [];
143
- renderSheet();
144
- return;
145
- }
146
-
147
- if (payload.command === "get_session_stats") {
148
- state.stats = payload.data || null;
149
- renderSheet();
150
- return;
151
- }
152
-
153
- if (payload.command === "phone_list_sessions") {
154
- state.sessions = payload.data?.sessions || [];
155
- renderSheet();
156
- return;
157
- }
158
-
159
- if (payload.command === "phone_get_tree") {
160
- state.tree = payload.data || null;
161
- renderSheet();
162
- return;
163
- }
164
-
165
- if (payload.command === "new_parent_session") {
166
- clearTransientState();
167
- refreshAll();
168
- showToast("Started a new parent session.");
169
- return;
170
- }
171
-
172
- if (payload.command === "new_session") {
173
- clearTransientState();
174
- refreshAll();
175
- showToast("Started a new DM session.");
176
- return;
177
- }
178
-
179
- if (payload.command === "compact") {
180
- showToast("Compaction triggered.");
181
- refreshAll();
182
- return;
183
- }
184
-
185
- if (payload.command === "slash_command") {
186
- if (payload.data?.source === "extension") {
187
- refreshAll({ forceQuota: true });
188
- }
189
- return;
190
- }
191
-
192
- if (payload.command === "reload") {
193
- clearTransientState();
194
- showToast("Reloaded extensions, skills, prompts, and themes.");
195
- refreshAll({ forceQuota: true });
196
- return;
197
- }
198
-
199
- if (payload.command === "set_model") {
200
- showToast("Model updated.");
201
- refreshAll();
202
- return;
203
- }
204
-
205
- if (payload.command === "set_thinking_level") {
206
- showToast("Thinking level updated.");
207
- refreshAll();
208
- return;
209
- }
210
-
211
- if (payload.command === "switch_session") {
212
- showToast("Session switched.");
213
- refreshAll();
214
- closeSheet();
215
- return;
216
- }
217
-
218
- if (payload.command === "fork") {
219
- showToast("Fork created.");
220
- refreshAll();
221
- closeSheet();
222
- return;
223
- }
224
-
225
- if (payload.command === "phone_open_branch_path") {
226
- showToast("Opened selected branch path as a new session.");
227
- refreshAll();
228
- closeSheet();
229
- return;
230
- }
231
-
232
- return;
233
- }
234
-
235
- if (payload.type === "agent_start") {
236
- state.status = { ...(state.status || {}), isStreaming: true };
237
- renderHeader();
238
- return;
239
- }
240
-
241
- if (payload.type === "agent_end") {
242
- state.status = { ...(state.status || {}), isStreaming: false };
243
- renderHeader();
244
- refreshAll({ forceQuota: true });
245
- return;
246
- }
247
-
248
- if (payload.type === "message_update") {
249
- handleAssistantEvent(payload.assistantMessageEvent);
250
- return;
251
- }
252
-
253
- if (payload.type === "message_end" && payload.message?.role === "assistant") {
254
- const transformed = transformMessage(payload.message, Date.now())[0];
255
- if (transformed) {
256
- state.liveAssistant = { ...transformed, live: false };
257
- renderMessages();
258
- }
259
- return;
260
- }
261
-
262
- if (payload.type === "tool_execution_start") {
263
- upsertLiveTool(payload.toolCallId, {
264
- id: `tool-live-${payload.toolCallId}`,
265
- kind: "tool",
266
- toolCallId: payload.toolCallId,
267
- toolName: payload.toolName || "tool",
268
- args: payload.args || {},
269
- command: payload.args?.command || "",
270
- live: true,
271
- title: payload.toolName || "tool",
272
- text: JSON.stringify(payload.args || {}, null, 2),
273
- meta: "Running…",
274
- status: "running",
275
- rawContent: null,
276
- });
277
- return;
278
- }
279
-
280
- if (payload.type === "tool_execution_update") {
281
- upsertLiveTool(payload.toolCallId, {
282
- ...(state.liveTools.get(payload.toolCallId) || {}),
283
- id: `tool-live-${payload.toolCallId}`,
284
- kind: "tool",
285
- toolCallId: payload.toolCallId,
286
- toolName: payload.toolName || "tool",
287
- args: payload.args || state.liveTools.get(payload.toolCallId)?.args || {},
288
- command: payload.args?.command || state.liveTools.get(payload.toolCallId)?.command || "",
289
- live: true,
290
- title: payload.toolName || "tool",
291
- text: contentToText(payload.partialResult?.content) || JSON.stringify(payload.args || {}, null, 2),
292
- meta: "Running…",
293
- status: "running",
294
- details: payload.partialResult?.details,
295
- rawContent: payload.partialResult?.content || state.liveTools.get(payload.toolCallId)?.rawContent || null,
296
- });
297
- return;
298
- }
299
-
300
- if (payload.type === "tool_execution_end") {
301
- upsertLiveTool(payload.toolCallId, {
302
- ...(state.liveTools.get(payload.toolCallId) || {}),
303
- id: `tool-live-${payload.toolCallId}`,
304
- kind: "tool",
305
- toolCallId: payload.toolCallId,
306
- toolName: payload.toolName || "tool",
307
- args: payload.args || state.liveTools.get(payload.toolCallId)?.args || {},
308
- command: payload.args?.command || state.liveTools.get(payload.toolCallId)?.command || "",
309
- live: false,
310
- title: payload.toolName || "tool",
311
- text: contentToText(payload.result?.content),
312
- meta: payload.isError ? "Failed" : "Done",
313
- status: payload.isError ? "error" : "done",
314
- details: payload.result?.details,
315
- rawContent: payload.result?.content || state.liveTools.get(payload.toolCallId)?.rawContent || null,
316
- });
317
- return;
318
- }
319
-
320
- if (payload.type === "extension_ui_request") {
321
- handleExtensionUiRequest(payload);
322
- return;
323
- }
324
-
325
- if (payload.type === "auto_retry_start") {
326
- showBanner(`Retrying after error: ${payload.errorMessage || "temporary failure"}`);
327
- return;
328
- }
329
-
330
- if (payload.type === "auto_retry_end") {
331
- showBanner(payload.success ? "" : `Retry failed: ${payload.finalError || "Unknown error"}`, payload.success ? "info" : "error");
332
- }
333
- }
334
-
335
- export async function handleEnvelope(event) {
336
- if (event.channel === "sessions" && event.event === "catalog") {
337
- const nextActiveSessionId = event.data?.activeSessionId || state.activeSessionId;
338
- const activeSessionChanged = nextActiveSessionId !== state.activeSessionId;
339
-
340
- state.activeSessions = event.data?.sessions || [];
341
- state.activeSessionId = nextActiveSessionId;
342
-
343
- if (activeSessionChanged && state.snapshotWorkerId && state.snapshotWorkerId !== state.activeSessionId) {
344
- clearSnapshotView();
345
- renderMessages();
346
- }
347
-
348
- renderHeader();
349
- renderSheet();
350
- return;
351
- }
352
-
353
- if (event.channel === "snapshot") {
354
- if (event.sessionWorkerId && state.activeSessionId && event.sessionWorkerId !== state.activeSessionId) {
355
- return;
356
- }
357
-
358
- state.snapshotState = event.state || null;
359
- state.snapshotWorkerId = event.sessionWorkerId || state.activeSessionId || null;
360
- state.status = { ...(state.status || {}), isStreaming: Boolean(event.state?.isStreaming) };
361
- state.messages = (event.messages || []).flatMap(transformMessage);
362
- state.commands = event.commands || state.commands;
363
- clearTransientState();
364
-
365
- if (event.liveAssistantMessage?.role === "assistant") {
366
- const assistant = transformMessage(event.liveAssistantMessage, Date.now())[0];
367
- if (assistant) {
368
- state.liveAssistant = { ...assistant, id: "assistant-live", live: true };
369
- }
370
- }
371
-
372
- for (const tool of event.liveTools || []) {
373
- const text =
374
- contentToText(tool.result?.content)
375
- || contentToText(tool.partialResult?.content)
376
- || JSON.stringify(tool.args || {}, null, 2);
377
-
378
- state.liveTools.set(tool.toolCallId, {
379
- id: `tool-live-${tool.toolCallId}`,
380
- kind: "tool",
381
- toolCallId: tool.toolCallId,
382
- toolName: tool.toolName || "tool",
383
- args: tool.args || {},
384
- command: tool.args?.command || "",
385
- live: !tool.result,
386
- title: tool.toolName || "tool",
387
- text,
388
- meta: tool.result ? (tool.isError ? "Failed" : "Done") : "Running…",
389
- details: tool.result?.details || tool.partialResult?.details,
390
- status: tool.isError ? "error" : (tool.result ? "done" : "running"),
391
- rawContent: tool.result?.content || tool.partialResult?.content || null,
392
- });
393
- }
394
-
395
- renderHeader();
396
- renderMessages();
397
- renderSheet();
398
- renderCommandSuggestions();
399
- void refreshQuota();
400
- return;
401
- }
402
-
403
- if (event.channel === "server") {
404
- if (event.event === "status") {
405
- state.status = event.data;
406
- renderHeader();
407
- return;
408
- }
409
- if (event.event === "stderr") {
410
- showBanner(event.data?.text?.trim() || "", "error");
411
- return;
412
- }
413
- if (event.event === "reloading") {
414
- showBanner(event.data?.message || "");
415
- return;
416
- }
417
- if (event.event === "session-spawned") {
418
- showToast(event.data?.message || "Opened new parallel session.");
419
- return;
420
- }
421
- if (event.event === "single-client-replaced") {
422
- showBanner(event.data?.message || "This phone session was replaced by another client.", "error");
423
- return;
424
- }
425
- if (event.event === "idle-timeout") {
426
- showBanner(event.data?.message || "DM Phone stopped because it was idle.", "error");
427
- return;
428
- }
429
- if (["startup-error", "snapshot-error", "client-error"].includes(event.event)) {
430
- showToast(event.data?.message || "Server error", "error");
431
- return;
432
- }
433
- if (event.event === "agent-exit") {
434
- showBanner(event.data?.message || "DM rpc exited.", "error");
435
- return;
436
- }
437
- }
438
-
439
- if (event.channel === "rpc") {
440
- handleRpcPayload(event.payload);
441
- }
442
- }
@@ -1,6 +0,0 @@
1
- import { initializeBindings } from "./bindings.js";
2
- import { handleAuthFailure, handleEnvelope } from "./handlers.js";
3
- import { boot } from "./transport.js";
4
-
5
- initializeBindings({ handleEnvelope, handleAuthFailure });
6
- boot({ handleEnvelope, handleAuthFailure });
@@ -1,105 +0,0 @@
1
- import { escapeHtml } from "./formatters.js";
2
-
3
- function findInlineCodeMarker(text, startIndex = 0) {
4
- for (let index = Math.max(0, startIndex); index < text.length; index += 1) {
5
- if (text[index] !== "`") continue;
6
- if (text[index - 1] === "`" || text[index + 1] === "`") continue;
7
- return index;
8
- }
9
- return -1;
10
- }
11
-
12
- function renderStrongText(text = "") {
13
- let html = "";
14
- let cursor = 0;
15
-
16
- while (cursor < text.length) {
17
- const open = text.indexOf("**", cursor);
18
- if (open === -1) {
19
- html += escapeHtml(text.slice(cursor));
20
- break;
21
- }
22
-
23
- const close = text.indexOf("**", open + 2);
24
- if (close === -1) {
25
- html += escapeHtml(text.slice(cursor));
26
- break;
27
- }
28
-
29
- html += escapeHtml(text.slice(cursor, open));
30
- html += `<strong>${escapeHtml(text.slice(open + 2, close))}</strong>`;
31
- cursor = close + 2;
32
- }
33
-
34
- return html;
35
- }
36
-
37
- function renderInlineMarkdown(text = "") {
38
- let html = "";
39
- let cursor = 0;
40
-
41
- while (cursor < text.length) {
42
- const open = findInlineCodeMarker(text, cursor);
43
- if (open === -1) {
44
- html += renderStrongText(text.slice(cursor));
45
- break;
46
- }
47
-
48
- const close = findInlineCodeMarker(text, open + 1);
49
- if (close === -1) {
50
- html += renderStrongText(text.slice(cursor));
51
- break;
52
- }
53
-
54
- html += renderStrongText(text.slice(cursor, open));
55
- html += `<code>${escapeHtml(text.slice(open + 1, close))}</code>`;
56
- cursor = close + 1;
57
- }
58
-
59
- return html;
60
- }
61
-
62
- function renderTextBlocks(text = "") {
63
- const blocks = text
64
- .split(/\n{2,}/)
65
- .map((block) => (block.trim() ? `<p>${renderInlineMarkdown(block)}</p>` : ""))
66
- .filter(Boolean);
67
-
68
- if (blocks.length) return blocks.join("");
69
- return text.trim() ? `<p>${renderInlineMarkdown(text)}</p>` : "";
70
- }
71
-
72
- function renderCodeBlock(code = "") {
73
- return `
74
- <pre class="message-code-block"><code>${escapeHtml(code)}</code></pre>
75
- `;
76
- }
77
-
78
- export function renderMarkdownLite(text = "") {
79
- const normalized = String(text || "").replace(/\r\n?/g, "\n");
80
- const fencePattern = /```([^`\n]*)\n([\s\S]*?)```/g;
81
- const parts = [];
82
- let cursor = 0;
83
- let match;
84
-
85
- while ((match = fencePattern.exec(normalized))) {
86
- if (match.index > cursor) {
87
- parts.push({ type: "text", value: normalized.slice(cursor, match.index) });
88
- }
89
-
90
- parts.push({ type: "code", value: match[2].replace(/\n$/, "") });
91
- cursor = match.index + match[0].length;
92
- }
93
-
94
- if (cursor < normalized.length) {
95
- parts.push({ type: "text", value: normalized.slice(cursor) });
96
- }
97
-
98
- const html = parts.map((part) => (
99
- part.type === "code"
100
- ? renderCodeBlock(part.value)
101
- : renderTextBlocks(part.value)
102
- )).join("");
103
-
104
- return html || '<p><span class="label">(no text)</span></p>';
105
- }