@duckmind/dm-darwin-x64 0.32.9 → 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 (95) hide show
  1. package/dm +0 -0
  2. package/extensions/.dm-extensions.json +14 -65
  3. package/extensions/dm-9router-ext/README.md +142 -0
  4. package/extensions/dm-9router-ext/package.json +45 -0
  5. package/extensions/dm-9router-ext/src/index.ts +541 -0
  6. package/extensions/dm-9router-ext/tsconfig.json +17 -0
  7. package/extensions/dm-subagents/package-lock.json +3 -3
  8. package/extensions/dm-tasks/node_modules/.package-lock.json +3 -3
  9. package/extensions/dm-tasks/node_modules/typebox/build/type/script/mapping.d.mts +2 -2
  10. package/extensions/dm-tasks/node_modules/typebox/build/type/script/parser.d.mts +2 -2
  11. package/extensions/dm-tasks/node_modules/typebox/build/type/script/parser.mjs +2 -2
  12. package/extensions/dm-tasks/node_modules/typebox/build/type/types/number.d.mts +1 -1
  13. package/extensions/dm-tasks/node_modules/typebox/build/type/types/number.mjs +1 -1
  14. package/extensions/dm-tasks/node_modules/typebox/build/type/types/record.d.mts +1 -1
  15. package/extensions/dm-tasks/node_modules/typebox/package.json +1 -1
  16. package/extensions/dm-tasks/package-lock.json +3 -3
  17. package/package.json +1 -1
  18. package/theme/theme-alps.json +93 -0
  19. package/extensions/dm-chime/README.md +0 -11
  20. package/extensions/dm-chime/docs/protocols.md +0 -107
  21. package/extensions/dm-chime/index.ts +0 -205
  22. package/extensions/dm-chime/package.json +0 -33
  23. package/extensions/dm-phone/README.md +0 -24
  24. package/extensions/dm-phone/index.ts +0 -12
  25. package/extensions/dm-phone/node_modules/.package-lock.json +0 -29
  26. package/extensions/dm-phone/node_modules/ws/LICENSE +0 -20
  27. package/extensions/dm-phone/node_modules/ws/README.md +0 -548
  28. package/extensions/dm-phone/node_modules/ws/browser.js +0 -8
  29. package/extensions/dm-phone/node_modules/ws/index.js +0 -22
  30. package/extensions/dm-phone/node_modules/ws/lib/buffer-util.js +0 -131
  31. package/extensions/dm-phone/node_modules/ws/lib/constants.js +0 -19
  32. package/extensions/dm-phone/node_modules/ws/lib/event-target.js +0 -292
  33. package/extensions/dm-phone/node_modules/ws/lib/extension.js +0 -203
  34. package/extensions/dm-phone/node_modules/ws/lib/limiter.js +0 -55
  35. package/extensions/dm-phone/node_modules/ws/lib/permessage-deflate.js +0 -528
  36. package/extensions/dm-phone/node_modules/ws/lib/receiver.js +0 -760
  37. package/extensions/dm-phone/node_modules/ws/lib/sender.js +0 -607
  38. package/extensions/dm-phone/node_modules/ws/lib/stream.js +0 -161
  39. package/extensions/dm-phone/node_modules/ws/lib/subprotocol.js +0 -62
  40. package/extensions/dm-phone/node_modules/ws/lib/validation.js +0 -152
  41. package/extensions/dm-phone/node_modules/ws/lib/websocket-server.js +0 -562
  42. package/extensions/dm-phone/node_modules/ws/lib/websocket.js +0 -1407
  43. package/extensions/dm-phone/node_modules/ws/package.json +0 -70
  44. package/extensions/dm-phone/node_modules/ws/wrapper.mjs +0 -21
  45. package/extensions/dm-phone/package-lock.json +0 -66
  46. package/extensions/dm-phone/package.json +0 -35
  47. package/extensions/dm-phone/phone-session-pool.ts +0 -8
  48. package/extensions/dm-phone/public/app/attachments.js +0 -233
  49. package/extensions/dm-phone/public/app/autocomplete-controller.js +0 -81
  50. package/extensions/dm-phone/public/app/autocomplete.js +0 -135
  51. package/extensions/dm-phone/public/app/bindings.js +0 -178
  52. package/extensions/dm-phone/public/app/command-catalog.js +0 -76
  53. package/extensions/dm-phone/public/app/commands.js +0 -376
  54. package/extensions/dm-phone/public/app/constants.js +0 -60
  55. package/extensions/dm-phone/public/app/formatters.js +0 -131
  56. package/extensions/dm-phone/public/app/handlers.js +0 -442
  57. package/extensions/dm-phone/public/app/main.js +0 -6
  58. package/extensions/dm-phone/public/app/markdown.js +0 -105
  59. package/extensions/dm-phone/public/app/messages.js +0 -418
  60. package/extensions/dm-phone/public/app/sheet-actions.js +0 -113
  61. package/extensions/dm-phone/public/app/sheet-navigation.js +0 -19
  62. package/extensions/dm-phone/public/app/sheets-view.js +0 -287
  63. package/extensions/dm-phone/public/app/state.js +0 -95
  64. package/extensions/dm-phone/public/app/tool-rendering.js +0 -562
  65. package/extensions/dm-phone/public/app/transport.js +0 -176
  66. package/extensions/dm-phone/public/app/ui.js +0 -417
  67. package/extensions/dm-phone/public/app.js +0 -1
  68. package/extensions/dm-phone/public/icon.svg +0 -15
  69. package/extensions/dm-phone/public/index.html +0 -146
  70. package/extensions/dm-phone/public/manifest.webmanifest +0 -17
  71. package/extensions/dm-phone/public/styles.css +0 -1139
  72. package/extensions/dm-phone/public/sw.js +0 -78
  73. package/extensions/dm-phone/src/extension/duckmind-models.js +0 -264
  74. package/extensions/dm-phone/src/extension/phone-args.ts +0 -121
  75. package/extensions/dm-phone/src/extension/phone-paths.ts +0 -250
  76. package/extensions/dm-phone/src/extension/phone-quota.ts +0 -188
  77. package/extensions/dm-phone/src/extension/phone-runtime.ts +0 -154
  78. package/extensions/dm-phone/src/extension/phone-server-runtime.ts +0 -1217
  79. package/extensions/dm-phone/src/extension/phone-sessions.ts +0 -139
  80. package/extensions/dm-phone/src/extension/phone-static.ts +0 -30
  81. package/extensions/dm-phone/src/extension/phone-tailscale.ts +0 -148
  82. package/extensions/dm-phone/src/extension/phone-theme.ts +0 -85
  83. package/extensions/dm-phone/src/extension/register-phone-child-extension.ts +0 -112
  84. package/extensions/dm-phone/src/extension/register-phone-extension.ts +0 -106
  85. package/extensions/dm-phone/src/extension/types.ts +0 -73
  86. package/extensions/dm-phone/src/session-pool/parent-session-worker.ts +0 -882
  87. package/extensions/dm-phone/src/session-pool/session-pool.ts +0 -470
  88. package/extensions/dm-phone/src/session-pool/session-worker.ts +0 -739
  89. package/extensions/dm-phone/src/session-pool/types.ts +0 -111
  90. package/extensions/dm-phone/src/session-pool/utils.ts +0 -23
  91. package/extensions/dm-phone/test/duckmind-models.test.js +0 -147
  92. package/extensions/dm-thinking-timer/LICENSE +0 -21
  93. package/extensions/dm-thinking-timer/README.md +0 -7
  94. package/extensions/dm-thinking-timer/package.json +0 -20
  95. 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
- }