@zonease/happy 0.6.41 → 0.6.43

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 (87) hide show
  1. package/dist/{api-XeHlmApX.cjs → api-B-PlVQY6.cjs} +50 -4
  2. package/dist/{api-K2-jr9ar.mjs → api-BUCtd3cB.mjs} +51 -5
  3. package/dist/{auth-BQvEuSs5.cjs → auth-BqGkUXvq.cjs} +2 -2
  4. package/dist/{auth-CjLkoM3m.mjs → auth-DQH6q_q-.mjs} +4 -4
  5. package/dist/{auth-BbvPcnkY.cjs → auth-OL3nNcDX.cjs} +4 -4
  6. package/dist/{auth-DS8fzlin.mjs → auth-qM2eojWx.mjs} +2 -2
  7. package/dist/{browser-C05SP_Tt.cjs → browser-CY7VNU0C.cjs} +1 -1
  8. package/dist/{browser-C05Ak6RL.mjs → browser-D5RN_Axa.mjs} +1 -1
  9. package/dist/{claudeLocal-DJNRlHIC.mjs → claudeLocal-BXK_vQXS.mjs} +1 -1
  10. package/dist/{claudeLocal-CpDhLCcZ.cjs → claudeLocal-HAXk0deK.cjs} +1 -1
  11. package/dist/{config-DWWtjKQx.mjs → config-2wMjzcHl.mjs} +1 -1
  12. package/dist/{config-B0mns9fF.cjs → config-CaKxWGVe.cjs} +1 -1
  13. package/dist/{connect-DXQC1CJe.mjs → connect-BAunPyp_.mjs} +5 -5
  14. package/dist/{connect-BxCScVNX.cjs → connect-Dt1vY1BC.cjs} +5 -5
  15. package/dist/{controlClient-DgjVRN8D.mjs → controlClient-BzzTNSfl.mjs} +1 -1
  16. package/dist/{controlClient-DgELDZgM.cjs → controlClient-yTkpwcOq.cjs} +1 -1
  17. package/dist/cursorApprovalHook-B2chnVni.cjs +115 -0
  18. package/dist/cursorApprovalHook-BDLPzI5l.mjs +113 -0
  19. package/dist/cursorApprovalServer-Ba1yOUCA.mjs +263 -0
  20. package/dist/cursorApprovalServer-xwxVGL3u.cjs +268 -0
  21. package/dist/{deviceKeys-CejCdWpw.mjs → deviceKeys-CQyFFPtt.mjs} +2 -2
  22. package/dist/{deviceKeys-BpIAWz13.cjs → deviceKeys-CdW-HPnz.cjs} +2 -2
  23. package/dist/{doctor-DznasgP3.cjs → doctor-D4xWXiE7.cjs} +2 -2
  24. package/dist/{doctor-B-LCMVN9.mjs → doctor-DDT2TXHH.mjs} +2 -2
  25. package/dist/downloadImage-3A6zY5AX.cjs +492 -0
  26. package/dist/downloadImage-BqNp0l7y.mjs +485 -0
  27. package/dist/{enroll-HjUqyGnD.mjs → enroll-BlZ0giJI.mjs} +3 -3
  28. package/dist/{enroll-BvfpRUGJ.cjs → enroll-DeYs89Ic.cjs} +3 -3
  29. package/dist/{evidence-CVgTjBrq.cjs → evidence-Bn1JXtdz.cjs} +1 -1
  30. package/dist/{evidence-BEQd1dCh.mjs → evidence-PUnN9yPK.mjs} +1 -1
  31. package/dist/{formatImageMessage-DVs57t3x.mjs → formatImageMessage-BRHeLf0-.mjs} +1 -1
  32. package/dist/{formatImageMessage-CmJTP_hU.cjs → formatImageMessage-bVFGFDJl.cjs} +1 -1
  33. package/dist/{index-CDTNgfUf.cjs → index-BeKrqPYR.cjs} +25 -1
  34. package/dist/{index-CPKdvi7J.mjs → index-DTV7drqs.mjs} +25 -1
  35. package/dist/index.cjs +95 -41
  36. package/dist/index.mjs +95 -41
  37. package/dist/{install-UTz_vYvB.mjs → install-BLPNuSeM.mjs} +2 -2
  38. package/dist/{install-B3mMGISS.mjs → install-BOIcR_Wr.mjs} +1 -1
  39. package/dist/{install-Ck22tYHP.cjs → install-Jrs6YUu8.cjs} +1 -1
  40. package/dist/{install-2Yl_L582.cjs → install-Q-YMwwwg.cjs} +2 -2
  41. package/dist/lib.cjs +4 -4
  42. package/dist/lib.d.cts +4 -2
  43. package/dist/lib.d.mts +4 -2
  44. package/dist/lib.mjs +4 -4
  45. package/dist/{loadableToolOutput-BZYlaqHn.cjs → loadableToolOutput-B3qpMqXT.cjs} +2 -458
  46. package/dist/{loadableToolOutput-4EvraaNY.mjs → loadableToolOutput-DzReWITb.mjs} +3 -456
  47. package/dist/{persistence-DrfN7TzY.cjs → persistence-D7zNFI-d.cjs} +7 -4
  48. package/dist/{persistence-CIUFyOwz.mjs → persistence-DbLMvLvk.mjs} +7 -4
  49. package/dist/{push-CCOXCcM_.cjs → push-RT6Y0Hr3.cjs} +6 -6
  50. package/dist/{push-USXj_pv0.mjs → push-z5wQ4Ki_.mjs} +6 -6
  51. package/dist/{downloadImage-ia5SzlCV.mjs → registerKillSessionHandler-DmfnJ0zq.mjs} +7 -487
  52. package/dist/{downloadImage-B_ygLAXY.cjs → registerKillSessionHandler-MoLdSQxM.cjs} +6 -492
  53. package/dist/{run-Dy6KX6m-.mjs → run-BFnSUK1o.mjs} +14 -9
  54. package/dist/{run-D3CopmEb.cjs → run-C5StYRIB.cjs} +14 -9
  55. package/dist/{runClaude-aHzvx6Ha.cjs → runClaude-ChRp6f5G.cjs} +27 -26
  56. package/dist/{runClaude-CWux2RDq.mjs → runClaude-CjENBdrX.mjs} +22 -21
  57. package/dist/{runCodex-D0ZxSj3O.mjs → runCodex-BzQWlRoj.mjs} +27 -25
  58. package/dist/{runCodex-G-Aq531U.cjs → runCodex-DcQGyotH.cjs} +32 -30
  59. package/dist/runCursor-B73z6MCN.mjs +752 -0
  60. package/dist/runCursor-BlPAxaTy.cjs +754 -0
  61. package/dist/{runGemini-DZC2i6vA.mjs → runGemini-BPv4UzuF.mjs} +18 -16
  62. package/dist/{runGemini-DxGgDAIM.cjs → runGemini-JFqaIC3u.cjs} +23 -21
  63. package/dist/{runOneShot-BgT-JNMA.cjs → runOneShot-2iV11e9L.cjs} +3 -3
  64. package/dist/{runOneShot-cxlk7VKA.mjs → runOneShot-DTukim2A.mjs} +3 -3
  65. package/dist/{serve-Dr3wPrtK.cjs → serve-BDwuAIK4.cjs} +7 -7
  66. package/dist/{serve-CKyvJNs0.mjs → serve-BnlYj5ek.mjs} +7 -7
  67. package/dist/{session-dYzbOo_W.cjs → session-Cp9LEESM.cjs} +5 -5
  68. package/dist/{session-vf2ZjFto.mjs → session-gfeFU8CA.mjs} +5 -5
  69. package/dist/{sessionKeyCache-dDquDzn0.cjs → sessionKeyCache-3Pme04yL.cjs} +1 -1
  70. package/dist/{sessionKeyCache-D2u3JUys.mjs → sessionKeyCache-DtBS_Sb3.mjs} +1 -1
  71. package/dist/{sessionList-C1k2PNg_.mjs → sessionList-B1w4BUdv.mjs} +2 -2
  72. package/dist/{sessionList-DmmtC7uR.cjs → sessionList-BR_5UDZJ.cjs} +2 -2
  73. package/dist/{sessionSummary-DGLoVOxd.cjs → sessionSummary-DLweYgHO.cjs} +3 -3
  74. package/dist/{sessionSummary-5a1QtFVS.mjs → sessionSummary-E-a2bg8W.mjs} +3 -3
  75. package/dist/setupOfflineReconnection-DHwthFtd.mjs +459 -0
  76. package/dist/setupOfflineReconnection-Dkp00dC9.cjs +463 -0
  77. package/dist/{spawnHappyCLI-CarRI4GM.cjs → spawnHappyCLI-C2uY9WV-.cjs} +1 -1
  78. package/dist/{spawnHappyCLI-D3EkTFIn.mjs → spawnHappyCLI-Dt7fbmbk.mjs} +1 -1
  79. package/dist/{ssh-B0hvEYIl.mjs → ssh-C-nEZiGP.mjs} +5 -5
  80. package/dist/{ssh-CBgVwKsB.cjs → ssh-CsnS89Lr.cjs} +5 -5
  81. package/dist/{task-CRo6W-3_.mjs → task-B-8_QGGX.mjs} +6 -6
  82. package/dist/{task-CMunPKCV.cjs → task-lrLb4FCL.cjs} +6 -6
  83. package/dist/{uninstall-BALE2up0.mjs → uninstall-CirMt_WC.mjs} +2 -2
  84. package/dist/{uninstall-BJ3eEGM4.cjs → uninstall-DMjUlEXT.cjs} +2 -2
  85. package/dist/{update-BfjtLrhO.mjs → update-CfXbYshs.mjs} +3 -3
  86. package/dist/{update-Bb3iijy8.cjs → update-mx2p28IP.cjs} +3 -3
  87. package/package.json +1 -1
@@ -0,0 +1,485 @@
1
+ import { l as logger } from './persistence-DbLMvLvk.mjs';
2
+ import { createHash } from 'crypto';
3
+ import axios from 'axios';
4
+
5
+ function parseCompact(message) {
6
+ const trimmed = message.trim();
7
+ if (trimmed === "/compact") {
8
+ return {
9
+ isCompact: true,
10
+ originalMessage: trimmed
11
+ };
12
+ }
13
+ if (trimmed.startsWith("/compact ")) {
14
+ return {
15
+ isCompact: true,
16
+ originalMessage: trimmed
17
+ };
18
+ }
19
+ return {
20
+ isCompact: false,
21
+ originalMessage: message
22
+ };
23
+ }
24
+ function parseClear(message) {
25
+ const trimmed = message.trim();
26
+ return {
27
+ isClear: trimmed === "/clear"
28
+ };
29
+ }
30
+ function parseSpecialCommand(message) {
31
+ const compactResult = parseCompact(message);
32
+ if (compactResult.isCompact) {
33
+ return {
34
+ type: "compact",
35
+ originalMessage: compactResult.originalMessage
36
+ };
37
+ }
38
+ const clearResult = parseClear(message);
39
+ if (clearResult.isClear) {
40
+ return {
41
+ type: "clear"
42
+ };
43
+ }
44
+ return {
45
+ type: null
46
+ };
47
+ }
48
+
49
+ class MessageQueue2 {
50
+ queue = [];
51
+ // Made public for testing
52
+ waiter = null;
53
+ closed = false;
54
+ onMessageHandler = null;
55
+ modeHasher;
56
+ constructor(modeHasher, onMessageHandler = null) {
57
+ this.modeHasher = modeHasher;
58
+ this.onMessageHandler = onMessageHandler;
59
+ logger.debug(`[MessageQueue2] Initialized`);
60
+ }
61
+ /**
62
+ * Set a handler that will be called when a message arrives
63
+ */
64
+ setOnMessage(handler) {
65
+ this.onMessageHandler = handler;
66
+ }
67
+ /**
68
+ * Push a message to the queue with a mode.
69
+ */
70
+ push(message, mode) {
71
+ if (this.closed) {
72
+ throw new Error("Cannot push to closed queue");
73
+ }
74
+ const modeHash = this.modeHasher(mode);
75
+ logger.debug(`[MessageQueue2] push() called with mode hash: ${modeHash}`);
76
+ this.queue.push({
77
+ message,
78
+ mode,
79
+ modeHash,
80
+ isolate: false
81
+ });
82
+ if (this.onMessageHandler) {
83
+ this.onMessageHandler(message, mode);
84
+ }
85
+ if (this.waiter) {
86
+ logger.debug(`[MessageQueue2] Notifying waiter`);
87
+ const waiter = this.waiter;
88
+ this.waiter = null;
89
+ waiter(true);
90
+ }
91
+ logger.debug(`[MessageQueue2] push() completed. Queue size: ${this.queue.length}`);
92
+ }
93
+ /**
94
+ * Push a message immediately without batching delay.
95
+ * Does not clear the queue or enforce isolation.
96
+ */
97
+ pushImmediate(message, mode) {
98
+ if (this.closed) {
99
+ throw new Error("Cannot push to closed queue");
100
+ }
101
+ const modeHash = this.modeHasher(mode);
102
+ logger.debug(`[MessageQueue2] pushImmediate() called with mode hash: ${modeHash}`);
103
+ this.queue.push({
104
+ message,
105
+ mode,
106
+ modeHash,
107
+ isolate: false
108
+ });
109
+ if (this.onMessageHandler) {
110
+ this.onMessageHandler(message, mode);
111
+ }
112
+ if (this.waiter) {
113
+ logger.debug(`[MessageQueue2] Notifying waiter for immediate message`);
114
+ const waiter = this.waiter;
115
+ this.waiter = null;
116
+ waiter(true);
117
+ }
118
+ logger.debug(`[MessageQueue2] pushImmediate() completed. Queue size: ${this.queue.length}`);
119
+ }
120
+ /**
121
+ * Push a message that must be processed in complete isolation.
122
+ * Clears any pending messages and ensures this message is never batched with others.
123
+ * Used for special commands that require dedicated processing.
124
+ */
125
+ pushIsolateAndClear(message, mode) {
126
+ if (this.closed) {
127
+ throw new Error("Cannot push to closed queue");
128
+ }
129
+ const modeHash = this.modeHasher(mode);
130
+ logger.debug(`[MessageQueue2] pushIsolateAndClear() called with mode hash: ${modeHash} - clearing ${this.queue.length} pending messages`);
131
+ this.queue = [];
132
+ this.queue.push({
133
+ message,
134
+ mode,
135
+ modeHash,
136
+ isolate: true
137
+ });
138
+ if (this.onMessageHandler) {
139
+ this.onMessageHandler(message, mode);
140
+ }
141
+ if (this.waiter) {
142
+ logger.debug(`[MessageQueue2] Notifying waiter for isolated message`);
143
+ const waiter = this.waiter;
144
+ this.waiter = null;
145
+ waiter(true);
146
+ }
147
+ logger.debug(`[MessageQueue2] pushIsolateAndClear() completed. Queue size: ${this.queue.length}`);
148
+ }
149
+ /**
150
+ * Push a message to the beginning of the queue with a mode.
151
+ */
152
+ unshift(message, mode) {
153
+ if (this.closed) {
154
+ throw new Error("Cannot unshift to closed queue");
155
+ }
156
+ const modeHash = this.modeHasher(mode);
157
+ logger.debug(`[MessageQueue2] unshift() called with mode hash: ${modeHash}`);
158
+ this.queue.unshift({
159
+ message,
160
+ mode,
161
+ modeHash,
162
+ isolate: false
163
+ });
164
+ if (this.onMessageHandler) {
165
+ this.onMessageHandler(message, mode);
166
+ }
167
+ if (this.waiter) {
168
+ logger.debug(`[MessageQueue2] Notifying waiter`);
169
+ const waiter = this.waiter;
170
+ this.waiter = null;
171
+ waiter(true);
172
+ }
173
+ logger.debug(`[MessageQueue2] unshift() completed. Queue size: ${this.queue.length}`);
174
+ }
175
+ /**
176
+ * Reset the queue - clears all messages and resets to empty state
177
+ */
178
+ reset() {
179
+ logger.debug(`[MessageQueue2] reset() called. Clearing ${this.queue.length} messages`);
180
+ this.queue = [];
181
+ this.closed = false;
182
+ this.waiter = null;
183
+ }
184
+ /**
185
+ * Close the queue - no more messages can be pushed
186
+ */
187
+ close() {
188
+ logger.debug(`[MessageQueue2] close() called`);
189
+ this.closed = true;
190
+ if (this.waiter) {
191
+ const waiter = this.waiter;
192
+ this.waiter = null;
193
+ waiter(false);
194
+ }
195
+ }
196
+ /**
197
+ * Check if the queue is closed
198
+ */
199
+ isClosed() {
200
+ return this.closed;
201
+ }
202
+ /**
203
+ * Get the current queue size
204
+ */
205
+ size() {
206
+ return this.queue.length;
207
+ }
208
+ /**
209
+ * Wait for messages and return all messages with the same mode.
210
+ * For string messages, multiple messages are joined with newlines.
211
+ * For object messages (e.g., mixed content with images), returns them one at a time.
212
+ * Returns { message: M, mode: T } or null if aborted/closed
213
+ */
214
+ async waitForMessagesAndGetAsString(abortSignal) {
215
+ if (this.queue.length > 0) {
216
+ return this.collectBatch();
217
+ }
218
+ if (this.closed || abortSignal?.aborted) {
219
+ return null;
220
+ }
221
+ const hasMessages = await this.waitForMessages(abortSignal);
222
+ if (!hasMessages) {
223
+ return null;
224
+ }
225
+ return this.collectBatch();
226
+ }
227
+ /**
228
+ * Collect a batch of messages with the same mode, respecting isolation requirements.
229
+ * For string messages, joins them with newlines.
230
+ * For object messages (like mixed content with images), returns one at a time.
231
+ */
232
+ collectBatch() {
233
+ if (this.queue.length === 0) {
234
+ return null;
235
+ }
236
+ const firstItem = this.queue[0];
237
+ let mode = firstItem.mode;
238
+ let isolate = firstItem.isolate ?? false;
239
+ const targetModeHash = firstItem.modeHash;
240
+ if (firstItem.isolate) {
241
+ const item = this.queue.shift();
242
+ logger.debug(`[MessageQueue2] Collected isolated message with mode hash: ${targetModeHash}`);
243
+ return {
244
+ message: item.message,
245
+ mode,
246
+ hash: targetModeHash,
247
+ isolate
248
+ };
249
+ }
250
+ if (typeof firstItem.message !== "string") {
251
+ const item = this.queue.shift();
252
+ logger.debug(`[MessageQueue2] Collected single object message with mode hash: ${targetModeHash}`);
253
+ return {
254
+ message: item.message,
255
+ mode,
256
+ hash: targetModeHash,
257
+ isolate
258
+ };
259
+ }
260
+ const sameModeMessages = [];
261
+ while (this.queue.length > 0 && this.queue[0].modeHash === targetModeHash && !this.queue[0].isolate && typeof this.queue[0].message === "string") {
262
+ const item = this.queue.shift();
263
+ sameModeMessages.push(item.message);
264
+ }
265
+ logger.debug(`[MessageQueue2] Collected batch of ${sameModeMessages.length} messages with mode hash: ${targetModeHash}`);
266
+ const combinedMessage = sameModeMessages.join("\n");
267
+ return {
268
+ message: combinedMessage,
269
+ mode,
270
+ hash: targetModeHash,
271
+ isolate
272
+ };
273
+ }
274
+ /**
275
+ * Wait for messages to arrive
276
+ */
277
+ waitForMessages(abortSignal) {
278
+ return new Promise((resolve) => {
279
+ let abortHandler = null;
280
+ if (abortSignal) {
281
+ abortHandler = () => {
282
+ logger.debug("[MessageQueue2] Wait aborted");
283
+ if (this.waiter === waiterFunc) {
284
+ this.waiter = null;
285
+ }
286
+ resolve(false);
287
+ };
288
+ abortSignal.addEventListener("abort", abortHandler);
289
+ }
290
+ const waiterFunc = (hasMessages) => {
291
+ if (abortHandler && abortSignal) {
292
+ abortSignal.removeEventListener("abort", abortHandler);
293
+ }
294
+ resolve(hasMessages);
295
+ };
296
+ if (this.queue.length > 0) {
297
+ if (abortHandler && abortSignal) {
298
+ abortSignal.removeEventListener("abort", abortHandler);
299
+ }
300
+ resolve(true);
301
+ return;
302
+ }
303
+ if (this.closed || abortSignal?.aborted) {
304
+ if (abortHandler && abortSignal) {
305
+ abortSignal.removeEventListener("abort", abortHandler);
306
+ }
307
+ resolve(false);
308
+ return;
309
+ }
310
+ this.waiter = waiterFunc;
311
+ logger.debug("[MessageQueue2] Waiting for messages...");
312
+ });
313
+ }
314
+ }
315
+
316
+ function deterministicStringify(obj, options = {}) {
317
+ const {
318
+ undefinedBehavior = "omit",
319
+ sortArrays = false,
320
+ replacer,
321
+ includeSymbols = false
322
+ } = options;
323
+ const seen = /* @__PURE__ */ new WeakSet();
324
+ function processValue(value, key) {
325
+ if (replacer && key !== void 0) {
326
+ value = replacer(key, value);
327
+ }
328
+ if (value === null) return null;
329
+ if (value === void 0) {
330
+ switch (undefinedBehavior) {
331
+ case "omit":
332
+ return void 0;
333
+ case "null":
334
+ return null;
335
+ case "throw":
336
+ throw new Error(`Undefined value at key: ${key}`);
337
+ }
338
+ }
339
+ if (typeof value === "boolean" || typeof value === "number" || typeof value === "string") {
340
+ return value;
341
+ }
342
+ if (value instanceof Date) {
343
+ return value.toISOString();
344
+ }
345
+ if (value instanceof RegExp) {
346
+ return value.toString();
347
+ }
348
+ if (typeof value === "function") {
349
+ return void 0;
350
+ }
351
+ if (typeof value === "symbol") {
352
+ return includeSymbols ? value.toString() : void 0;
353
+ }
354
+ if (typeof value === "bigint") {
355
+ return value.toString() + "n";
356
+ }
357
+ if (seen.has(value)) {
358
+ throw new Error("Circular reference detected");
359
+ }
360
+ seen.add(value);
361
+ if (Array.isArray(value)) {
362
+ const processed2 = value.map((item, index) => processValue(item, String(index))).filter((item) => item !== void 0);
363
+ if (sortArrays) {
364
+ processed2.sort((a, b) => {
365
+ const aStr = JSON.stringify(processValue(a));
366
+ const bStr = JSON.stringify(processValue(b));
367
+ return aStr.localeCompare(bStr);
368
+ });
369
+ }
370
+ seen.delete(value);
371
+ return processed2;
372
+ }
373
+ if (value.constructor === Object || value.constructor === void 0) {
374
+ const processed2 = {};
375
+ const keys = Object.keys(value).sort();
376
+ for (const k of keys) {
377
+ const processedValue = processValue(value[k], k);
378
+ if (processedValue !== void 0) {
379
+ processed2[k] = processedValue;
380
+ }
381
+ }
382
+ seen.delete(value);
383
+ return processed2;
384
+ }
385
+ try {
386
+ const plain = { ...value };
387
+ seen.delete(value);
388
+ return processValue(plain, key);
389
+ } catch {
390
+ seen.delete(value);
391
+ return String(value);
392
+ }
393
+ }
394
+ const processed = processValue(obj);
395
+ return JSON.stringify(processed);
396
+ }
397
+ function hashObject(obj, options, encoding = "hex") {
398
+ const jsonString = deterministicStringify(obj, options);
399
+ return createHash("sha256").update(jsonString).digest(encoding);
400
+ }
401
+
402
+ class MessageBuffer {
403
+ messages = [];
404
+ listeners = [];
405
+ nextId = 1;
406
+ addMessage(content, type = "assistant") {
407
+ const message = {
408
+ id: `msg-${this.nextId++}`,
409
+ timestamp: /* @__PURE__ */ new Date(),
410
+ content,
411
+ type
412
+ };
413
+ this.messages.push(message);
414
+ this.notifyListeners();
415
+ }
416
+ /**
417
+ * Update the last message of a specific type by appending content to it
418
+ * Useful for streaming responses where deltas should accumulate in one message
419
+ */
420
+ updateLastMessage(contentDelta, type = "assistant") {
421
+ for (let i = this.messages.length - 1; i >= 0; i--) {
422
+ if (this.messages[i].type === type) {
423
+ const oldMessage = this.messages[i];
424
+ const updatedMessage = {
425
+ ...oldMessage,
426
+ content: oldMessage.content + contentDelta
427
+ };
428
+ this.messages[i] = updatedMessage;
429
+ this.notifyListeners();
430
+ return;
431
+ }
432
+ }
433
+ this.addMessage(contentDelta, type);
434
+ }
435
+ /**
436
+ * Remove the last message of a specific type
437
+ * Useful for removing placeholder messages like "Thinking..." when actual response starts
438
+ */
439
+ removeLastMessage(type) {
440
+ for (let i = this.messages.length - 1; i >= 0; i--) {
441
+ if (this.messages[i].type === type) {
442
+ this.messages.splice(i, 1);
443
+ this.notifyListeners();
444
+ return true;
445
+ }
446
+ }
447
+ return false;
448
+ }
449
+ getMessages() {
450
+ return [...this.messages];
451
+ }
452
+ clear() {
453
+ this.messages = [];
454
+ this.nextId = 1;
455
+ this.notifyListeners();
456
+ }
457
+ onUpdate(listener) {
458
+ this.listeners.push(listener);
459
+ return () => {
460
+ const index = this.listeners.indexOf(listener);
461
+ if (index > -1) {
462
+ this.listeners.splice(index, 1);
463
+ }
464
+ };
465
+ }
466
+ notifyListeners() {
467
+ const messages = this.getMessages();
468
+ this.listeners.forEach((listener) => listener(messages));
469
+ }
470
+ }
471
+
472
+ async function downloadImage(url) {
473
+ const response = await axios.get(url, {
474
+ responseType: "arraybuffer"
475
+ });
476
+ const buffer = Buffer.from(response.data);
477
+ const base64 = buffer.toString("base64");
478
+ let mimeType = response.headers["content-type"] || "image/jpeg";
479
+ if (mimeType.includes(";")) {
480
+ mimeType = mimeType.split(";")[0].trim();
481
+ }
482
+ return { base64, mimeType };
483
+ }
484
+
485
+ export { MessageQueue2 as M, MessageBuffer as a, parseSpecialCommand as b, downloadImage as d, hashObject as h, parseClear as p };
@@ -1,8 +1,8 @@
1
1
  import axios from 'axios';
2
2
  import tweetnacl from 'tweetnacl';
3
3
  import { createHmac, randomBytes } from 'node:crypto';
4
- import { r as readCredentials, c as configuration, h as decodeBase64, u as updateSettings, w as writeCredentialsDataKey, o as libsodiumPublicKeyFromSecretKey } from './persistence-CIUFyOwz.mjs';
5
- import { decryptWithEphemeralKey } from './auth-DS8fzlin.mjs';
4
+ import { r as readCredentials, c as configuration, h as decodeBase64, u as updateSettings, w as writeCredentialsDataKey, o as libsodiumPublicKeyFromSecretKey } from './persistence-DbLMvLvk.mjs';
5
+ import { decryptWithEphemeralKey } from './auth-qM2eojWx.mjs';
6
6
  import 'node:fs/promises';
7
7
  import 'node:fs';
8
8
  import 'node:os';
@@ -12,7 +12,7 @@ import 'chalk';
12
12
  import 'fs';
13
13
  import 'qrcode-terminal';
14
14
  import './time-DgsBLJA_.mjs';
15
- import './browser-C05Ak6RL.mjs';
15
+ import './browser-D5RN_Axa.mjs';
16
16
  import 'open';
17
17
  import 'react';
18
18
  import 'ink';
@@ -3,8 +3,8 @@
3
3
  var axios = require('axios');
4
4
  var tweetnacl = require('tweetnacl');
5
5
  var node_crypto = require('node:crypto');
6
- var logger = require('./persistence-DrfN7TzY.cjs');
7
- var auth = require('./auth-BQvEuSs5.cjs');
6
+ var logger = require('./persistence-D7zNFI-d.cjs');
7
+ var auth = require('./auth-BqGkUXvq.cjs');
8
8
  require('node:fs/promises');
9
9
  require('node:fs');
10
10
  require('node:os');
@@ -14,7 +14,7 @@ require('chalk');
14
14
  require('fs');
15
15
  require('qrcode-terminal');
16
16
  require('./time-Bj2HRkKH.cjs');
17
- require('./browser-C05SP_Tt.cjs');
17
+ require('./browser-CY7VNU0C.cjs');
18
18
  require('open');
19
19
  require('react');
20
20
  require('ink');
@@ -5,7 +5,7 @@ var fs = require('node:fs');
5
5
  var promises = require('node:fs/promises');
6
6
  var node_crypto = require('node:crypto');
7
7
  var path = require('node:path');
8
- var logger = require('./persistence-DrfN7TzY.cjs');
8
+ var logger = require('./persistence-D7zNFI-d.cjs');
9
9
  var workflowReports = require('./workflowReports-BEWuQesA.cjs');
10
10
  var workflowCommon = require('./workflowCommon-Bl568-rt.cjs');
11
11
  require('node:os');
@@ -3,7 +3,7 @@ import { constants } from 'node:fs';
3
3
  import { mkdir, appendFile, access, readFile } from 'node:fs/promises';
4
4
  import { randomUUID } from 'node:crypto';
5
5
  import { basename, dirname, resolve } from 'node:path';
6
- import { c as configuration } from './persistence-CIUFyOwz.mjs';
6
+ import { c as configuration } from './persistence-DbLMvLvk.mjs';
7
7
  import { r as renderEvidenceReport, i as inferEvidenceKind } from './workflowReports-Dd8-4-8f.mjs';
8
8
  import { p as parseWorkflowArgs, s as stringFlag, b as booleanFlag, a as printOrWriteOutput } from './workflowCommon-B0d01Y_a.mjs';
9
9
  import 'node:os';
@@ -1,4 +1,4 @@
1
- import { d as downloadImage } from './downloadImage-ia5SzlCV.mjs';
1
+ import { d as downloadImage } from './downloadImage-BqNp0l7y.mjs';
2
2
 
3
3
  async function formatMessageForClaude(text, images) {
4
4
  const content = [];
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var downloadImage = require('./downloadImage-B_ygLAXY.cjs');
3
+ var downloadImage = require('./downloadImage-3A6zY5AX.cjs');
4
4
 
5
5
  async function formatMessageForClaude(text, images) {
6
6
  const content = [];
@@ -301,7 +301,18 @@ const MODEL_MODES = [
301
301
  "gpt-5.1-codex-mini-high",
302
302
  "gemini-3-pro-preview",
303
303
  "gemini-3-flash-preview",
304
- "gemini-2.5-pro"
304
+ "gemini-2.5-pro",
305
+ // Cursor resells models from every vendor — `cursor-agent --list-models`
306
+ // returned 161 ids. Only a curated set lives here: the ids below are the
307
+ // ones the picker offers. Anything else Cursor supports is still reachable
308
+ // by passing --model to `happy cursor`, which does not go through this list.
309
+ "auto",
310
+ "composer-2.5",
311
+ "composer-2.5-fast",
312
+ "cursor-grok-4.6-high",
313
+ "gemini-3.7-flash-high",
314
+ "claude-opus-5-thinking-high",
315
+ "claude-sonnet-5-high"
305
316
  ];
306
317
  const CLAUDE_MODEL_MODES = [
307
318
  MODEL_MODE_DEFAULT,
@@ -370,6 +381,17 @@ const GEMINI_MODEL_MODES = [
370
381
  "gemini-3-flash-preview",
371
382
  "gemini-2.5-pro"
372
383
  ];
384
+ const CURSOR_MODEL_MODES = [
385
+ MODEL_MODE_DEFAULT,
386
+ "auto",
387
+ "composer-2.5",
388
+ "composer-2.5-fast",
389
+ "claude-opus-5-thinking-high",
390
+ "claude-sonnet-5-high",
391
+ "gpt-5.6-sol-high",
392
+ "cursor-grok-4.6-high",
393
+ "gemini-3.7-flash-high"
394
+ ];
373
395
  const CODEX_MODEL_MODES = [
374
396
  MODEL_MODE_DEFAULT,
375
397
  "gpt-5.6-sol-low",
@@ -416,6 +438,7 @@ const MODEL_MODE_SET = new Set(MODEL_MODES);
416
438
  const CLAUDE_MODEL_MODE_SET = new Set(CLAUDE_MODEL_MODES);
417
439
  const GEMINI_MODEL_MODE_SET = new Set(GEMINI_MODEL_MODES);
418
440
  const CODEX_MODEL_MODE_SET = new Set(CODEX_MODEL_MODES);
441
+ const CURSOR_MODEL_MODE_SET = new Set(CURSOR_MODEL_MODES);
419
442
  function isModelMode(value) {
420
443
  return MODEL_MODE_SET.has(value);
421
444
  }
@@ -423,6 +446,7 @@ function isModelModeForAgent(agent, mode) {
423
446
  if (!isModelMode(mode)) return false;
424
447
  if (agent === "claude") return CLAUDE_MODEL_MODE_SET.has(mode);
425
448
  if (agent === "gemini") return GEMINI_MODEL_MODE_SET.has(mode);
449
+ if (agent === "cursor") return CURSOR_MODEL_MODE_SET.has(mode);
426
450
  return CODEX_MODEL_MODE_SET.has(mode);
427
451
  }
428
452
  const CLAUDE_MODE_TO_SELECTION = {
@@ -281,7 +281,18 @@ const MODEL_MODES = [
281
281
  "gpt-5.1-codex-mini-high",
282
282
  "gemini-3-pro-preview",
283
283
  "gemini-3-flash-preview",
284
- "gemini-2.5-pro"
284
+ "gemini-2.5-pro",
285
+ // Cursor resells models from every vendor — `cursor-agent --list-models`
286
+ // returned 161 ids. Only a curated set lives here: the ids below are the
287
+ // ones the picker offers. Anything else Cursor supports is still reachable
288
+ // by passing --model to `happy cursor`, which does not go through this list.
289
+ "auto",
290
+ "composer-2.5",
291
+ "composer-2.5-fast",
292
+ "cursor-grok-4.6-high",
293
+ "gemini-3.7-flash-high",
294
+ "claude-opus-5-thinking-high",
295
+ "claude-sonnet-5-high"
285
296
  ];
286
297
  const CLAUDE_MODEL_MODES = [
287
298
  MODEL_MODE_DEFAULT,
@@ -350,6 +361,17 @@ const GEMINI_MODEL_MODES = [
350
361
  "gemini-3-flash-preview",
351
362
  "gemini-2.5-pro"
352
363
  ];
364
+ const CURSOR_MODEL_MODES = [
365
+ MODEL_MODE_DEFAULT,
366
+ "auto",
367
+ "composer-2.5",
368
+ "composer-2.5-fast",
369
+ "claude-opus-5-thinking-high",
370
+ "claude-sonnet-5-high",
371
+ "gpt-5.6-sol-high",
372
+ "cursor-grok-4.6-high",
373
+ "gemini-3.7-flash-high"
374
+ ];
353
375
  const CODEX_MODEL_MODES = [
354
376
  MODEL_MODE_DEFAULT,
355
377
  "gpt-5.6-sol-low",
@@ -396,6 +418,7 @@ const MODEL_MODE_SET = new Set(MODEL_MODES);
396
418
  const CLAUDE_MODEL_MODE_SET = new Set(CLAUDE_MODEL_MODES);
397
419
  const GEMINI_MODEL_MODE_SET = new Set(GEMINI_MODEL_MODES);
398
420
  const CODEX_MODEL_MODE_SET = new Set(CODEX_MODEL_MODES);
421
+ const CURSOR_MODEL_MODE_SET = new Set(CURSOR_MODEL_MODES);
399
422
  function isModelMode(value) {
400
423
  return MODEL_MODE_SET.has(value);
401
424
  }
@@ -403,6 +426,7 @@ function isModelModeForAgent(agent, mode) {
403
426
  if (!isModelMode(mode)) return false;
404
427
  if (agent === "claude") return CLAUDE_MODEL_MODE_SET.has(mode);
405
428
  if (agent === "gemini") return GEMINI_MODEL_MODE_SET.has(mode);
429
+ if (agent === "cursor") return CURSOR_MODEL_MODE_SET.has(mode);
406
430
  return CODEX_MODEL_MODE_SET.has(mode);
407
431
  }
408
432
  const CLAUDE_MODE_TO_SELECTION = {