happy-imou-cloud 2.1.49 → 2.1.51
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.
- package/dist/AcpBackend-CqO3D07V.mjs +2619 -0
- package/dist/AcpBackend-XPiTd6ph.cjs +2621 -0
- package/dist/{BaseReasoningProcessor-Dn9NcoHz.cjs → BaseReasoningProcessor-BD9tiwep.cjs} +1 -144
- package/dist/{BaseReasoningProcessor-CAVeOdyo.mjs → BaseReasoningProcessor-CjlayL2f.mjs} +2 -144
- package/dist/ConversationHistory-Bl2doTA-.cjs +780 -0
- package/dist/ConversationHistory-CI5bBfuA.mjs +771 -0
- package/dist/{ProviderSelectionHandler-BJJc7qOR.cjs → ProviderSelectionHandler-C7GE5QjX.cjs} +6 -6
- package/dist/{ProviderSelectionHandler-DIYidT13.mjs → ProviderSelectionHandler-uQ8jzdzr.mjs} +2 -2
- package/dist/RuntimeShell-BDt42io_.mjs +252 -0
- package/dist/RuntimeShell-D_Te12wq.cjs +258 -0
- package/dist/bootstrapManagedProviderSession-Bln-TwyB.cjs +147 -0
- package/dist/bootstrapManagedProviderSession-D2Z6YU3n.mjs +145 -0
- package/dist/claude-BKNT-2fG.cjs +1080 -0
- package/dist/claude-CnN5WCWj.mjs +1073 -0
- package/dist/codex-DLGP8WF6.mjs +577 -0
- package/dist/codex-Fv2eali8.cjs +582 -0
- package/dist/{command-VcH4hbhi.cjs → command-BWPlJyCN.cjs} +16 -8
- package/dist/{command-CzfRRhVe.mjs → command-CELwsYoG.mjs} +15 -7
- package/dist/config-CFL0Gkqt.cjs +184 -0
- package/dist/config-ChSPe7p9.mjs +174 -0
- package/dist/createDefaultRuntimeShell-BXu3vCvT.cjs +33 -0
- package/dist/createDefaultRuntimeShell-DOg6g3-G.mjs +31 -0
- package/dist/cursor-Blq1cHdr.cjs +91 -0
- package/dist/cursor-CwPNSy_A.mjs +88 -0
- package/dist/future-Dq4Ha1Dn.cjs +24 -0
- package/dist/future-xRdLl3vf.mjs +22 -0
- package/dist/{index-xa1kwZoj.cjs → index-B_JYgMUS.cjs} +189 -5352
- package/dist/{index-7Z93BoVn.mjs → index-CX-F_fuk.mjs} +177 -5331
- package/dist/index.cjs +2 -2
- package/dist/index.mjs +2 -2
- package/dist/installFatalProcessHandlers-0vaw9MAz.mjs +55 -0
- package/dist/installFatalProcessHandlers-CyURn5Bp.cjs +57 -0
- package/dist/launch-BoCCEd5p.mjs +63 -0
- package/dist/launch-wZA5BcvS.cjs +66 -0
- package/dist/lib.cjs +2 -3
- package/dist/lib.d.cts +20 -17
- package/dist/lib.d.mts +20 -17
- package/dist/lib.mjs +1 -2
- package/dist/resolveCommand-B3BGyBE2.mjs +189 -0
- package/dist/resolveCommand-DYMd9PNC.cjs +193 -0
- package/dist/{runClaude-zCwRhpOw.mjs → runClaude-Be0myF9k.mjs} +8 -5
- package/dist/{runClaude-BBGNmGj6.cjs → runClaude-DZJt5er7.cjs} +46 -43
- package/dist/{runCodex-BbgLVjb9.mjs → runCodex-BSnyN4m7.mjs} +226 -117
- package/dist/{runCodex-jUU6U2tZ.cjs → runCodex-DTCcGRue.cjs} +269 -160
- package/dist/runCursor-Bn1PuwJy.cjs +506 -0
- package/dist/runCursor-M6dQ6bGF.mjs +504 -0
- package/dist/{runGemini-DcwNsudA.mjs → runGemini-BNm4vYKA.mjs} +279 -5
- package/dist/{runGemini-C0NT8MHK.cjs → runGemini-Bn3lFhz6.cjs} +309 -35
- package/dist/{registerKillSessionHandler-DLDg2EES.mjs → sessionControl-1bT_7OI6.mjs} +1643 -2405
- package/dist/{registerKillSessionHandler-CfCya6si.cjs → sessionControl-flKnQrx0.cjs} +1647 -2417
- package/dist/{api-DnqaNvyV.mjs → types-B5vtxa38.mjs} +55 -5
- package/dist/{api-D7nAeZi7.cjs → types-CttABk32.cjs} +55 -4
- package/package.json +2 -2
- package/dist/types-CiliQpqS.mjs +0 -52
- package/dist/types-DVk3crez.cjs +0 -54
|
@@ -0,0 +1,771 @@
|
|
|
1
|
+
import { R as RuntimeShell, f as formatDisplayMessage, t as truncateDisplayMessage } from './RuntimeShell-BDt42io_.mjs';
|
|
2
|
+
import { i as renderTerminalOutputPreview } from './sessionControl-1bT_7OI6.mjs';
|
|
3
|
+
import { l as logger } from './types-B5vtxa38.mjs';
|
|
4
|
+
|
|
5
|
+
async function launchRuntimeHandleWithFactoryResult(opts) {
|
|
6
|
+
const shell = opts.shell ?? new RuntimeShell();
|
|
7
|
+
let factoryResult;
|
|
8
|
+
const session = await shell.launch({
|
|
9
|
+
provider: opts.provider,
|
|
10
|
+
cwd: opts.cwd,
|
|
11
|
+
env: opts.env,
|
|
12
|
+
createBackend: (factoryOpts) => {
|
|
13
|
+
factoryResult = opts.createBackendResult(factoryOpts);
|
|
14
|
+
return factoryResult.backend;
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
if (factoryResult === void 0) {
|
|
18
|
+
throw new Error(`Runtime provider "${opts.provider}" did not create a backend result`);
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
session,
|
|
22
|
+
factoryResult
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SESSION_LABEL_MAX_LENGTH = 60;
|
|
27
|
+
const TITLE_MAX_LENGTH = 80;
|
|
28
|
+
const BODY_MAX_LENGTH = 140;
|
|
29
|
+
function isRecord$1(value) {
|
|
30
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
function normalizeText(value) {
|
|
33
|
+
if (typeof value !== "string") {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
const normalized = value.replace(/\s+/g, " ").trim();
|
|
37
|
+
return normalized.length > 0 ? normalized : null;
|
|
38
|
+
}
|
|
39
|
+
function truncateText(value, maxLength) {
|
|
40
|
+
if (value.length <= maxLength) {
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
return `${value.slice(0, maxLength - 1).trimEnd()}\u2026`;
|
|
44
|
+
}
|
|
45
|
+
function toProviderKey(providerLabel) {
|
|
46
|
+
const normalized = normalizeText(providerLabel)?.toLowerCase();
|
|
47
|
+
if (!normalized) {
|
|
48
|
+
return "unknown";
|
|
49
|
+
}
|
|
50
|
+
if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
|
|
51
|
+
return "claude";
|
|
52
|
+
}
|
|
53
|
+
if (normalized === "codex") {
|
|
54
|
+
return "codex";
|
|
55
|
+
}
|
|
56
|
+
if (normalized === "gemini") {
|
|
57
|
+
return "gemini";
|
|
58
|
+
}
|
|
59
|
+
return normalized.replace(/\s+/g, "-");
|
|
60
|
+
}
|
|
61
|
+
function deriveNotificationProviderLabel(providerLabel) {
|
|
62
|
+
const normalized = normalizeText(providerLabel)?.toLowerCase();
|
|
63
|
+
if (!normalized) {
|
|
64
|
+
return "Agent";
|
|
65
|
+
}
|
|
66
|
+
if (normalized === "claude" || normalized === "claude code" || normalized === "cloud code") {
|
|
67
|
+
return "Claude";
|
|
68
|
+
}
|
|
69
|
+
if (normalized === "codex") {
|
|
70
|
+
return "Codex";
|
|
71
|
+
}
|
|
72
|
+
if (normalized === "gemini") {
|
|
73
|
+
return "Gemini";
|
|
74
|
+
}
|
|
75
|
+
return normalizeText(providerLabel) ?? "Agent";
|
|
76
|
+
}
|
|
77
|
+
function buildNotificationTitle(sessionLabel, providerLabel, actionLabel) {
|
|
78
|
+
const providerDisplayLabel = deriveNotificationProviderLabel(providerLabel);
|
|
79
|
+
const suffix = ` \xB7 ${providerDisplayLabel} \xB7 ${actionLabel}`;
|
|
80
|
+
const maxSessionLength = Math.max(12, TITLE_MAX_LENGTH - suffix.length);
|
|
81
|
+
return `${truncateText(sessionLabel, maxSessionLength)}${suffix}`;
|
|
82
|
+
}
|
|
83
|
+
function derivePathLabel(path) {
|
|
84
|
+
const normalized = normalizeText(path);
|
|
85
|
+
if (!normalized) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const segments = normalized.split(/[\\/]+/).filter(Boolean);
|
|
89
|
+
return segments[segments.length - 1] ?? normalized;
|
|
90
|
+
}
|
|
91
|
+
function deriveHomeLabel(homeSlug) {
|
|
92
|
+
const normalized = normalizeText(homeSlug);
|
|
93
|
+
if (!normalized) {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
return normalized.replace(/[_-]+/g, " ");
|
|
97
|
+
}
|
|
98
|
+
function deriveNotificationSessionLabel(metadata, providerLabel) {
|
|
99
|
+
const label = normalizeText(metadata?.name) ?? normalizeText(metadata?.summary?.text) ?? deriveHomeLabel(metadata?.happyOrg?.specialistHome?.homeSlug) ?? derivePathLabel(metadata?.path) ?? normalizeText(providerLabel) ?? "Session";
|
|
100
|
+
return truncateText(label, SESSION_LABEL_MAX_LENGTH);
|
|
101
|
+
}
|
|
102
|
+
function deriveNotificationSummary(candidates, fallback, sessionLabel) {
|
|
103
|
+
for (const candidate of candidates) {
|
|
104
|
+
const normalized = normalizeText(candidate);
|
|
105
|
+
if (!normalized) {
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
const truncated = truncateText(normalized, BODY_MAX_LENGTH);
|
|
109
|
+
if (truncated.toLowerCase() !== sessionLabel.toLowerCase()) {
|
|
110
|
+
return truncated;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return truncateText(fallback, BODY_MAX_LENGTH);
|
|
114
|
+
}
|
|
115
|
+
function cleanExtraData(extraData) {
|
|
116
|
+
return Object.fromEntries(
|
|
117
|
+
Object.entries(extraData).filter(([, value]) => {
|
|
118
|
+
if (value === null || value === void 0) {
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (typeof value === "string") {
|
|
122
|
+
return value.trim().length > 0;
|
|
123
|
+
}
|
|
124
|
+
return true;
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
}
|
|
128
|
+
function buildRouteData(opts) {
|
|
129
|
+
const taskContext = opts.metadata?.happyOrg?.taskContext ?? null;
|
|
130
|
+
const routeTaskId = opts.report?.taskId ?? taskContext?.taskId ?? null;
|
|
131
|
+
const routePositionId = opts.report?.positionId ?? taskContext?.positionId ?? null;
|
|
132
|
+
const routeSessionId = normalizeText(opts.sessionId);
|
|
133
|
+
const data = {
|
|
134
|
+
notificationKind: opts.notificationKind,
|
|
135
|
+
provider: toProviderKey(opts.providerLabel)
|
|
136
|
+
};
|
|
137
|
+
if (opts.routePreference === "session" && routeSessionId) {
|
|
138
|
+
data.sessionId = routeSessionId;
|
|
139
|
+
} else if (routeTaskId) {
|
|
140
|
+
data.taskId = routeTaskId;
|
|
141
|
+
} else if (routeSessionId) {
|
|
142
|
+
data.sessionId = routeSessionId;
|
|
143
|
+
} else if (routePositionId) {
|
|
144
|
+
data.positionId = routePositionId;
|
|
145
|
+
}
|
|
146
|
+
Object.assign(data, cleanExtraData({
|
|
147
|
+
contextTaskId: data.taskId ? null : routeTaskId,
|
|
148
|
+
contextPositionId: data.positionId ? null : routePositionId,
|
|
149
|
+
memberAgentId: opts.report?.memberAgentId ?? taskContext?.memberAgentId ?? null,
|
|
150
|
+
supervisorAgentId: opts.report?.supervisorAgentId ?? taskContext?.supervisorAgentId ?? null
|
|
151
|
+
}));
|
|
152
|
+
if (opts.extraData) {
|
|
153
|
+
Object.assign(data, cleanExtraData(opts.extraData));
|
|
154
|
+
}
|
|
155
|
+
return data;
|
|
156
|
+
}
|
|
157
|
+
function humanizeToolName(toolName) {
|
|
158
|
+
const normalized = normalizeText(toolName);
|
|
159
|
+
if (!normalized) {
|
|
160
|
+
return "continue";
|
|
161
|
+
}
|
|
162
|
+
const replacements = {
|
|
163
|
+
bash: "run a command",
|
|
164
|
+
execute: "run a command",
|
|
165
|
+
read: "read a file",
|
|
166
|
+
write: "write a file",
|
|
167
|
+
edit: "edit a file",
|
|
168
|
+
multiedit: "edit files",
|
|
169
|
+
patch: "apply a patch",
|
|
170
|
+
fetch: "fetch a page",
|
|
171
|
+
search: "search the web"
|
|
172
|
+
};
|
|
173
|
+
const replacement = replacements[normalized.toLowerCase()];
|
|
174
|
+
if (replacement) {
|
|
175
|
+
return replacement;
|
|
176
|
+
}
|
|
177
|
+
return normalized.replace(/[_-]+/g, " ");
|
|
178
|
+
}
|
|
179
|
+
function extractPermissionRequestPushContext(message) {
|
|
180
|
+
const payload = isRecord$1(message.payload) ? message.payload : null;
|
|
181
|
+
const toolName = normalizeText(payload?.toolName) ?? normalizeText(message.reason);
|
|
182
|
+
const payloadDescription = normalizeText(payload?.description);
|
|
183
|
+
const reasonDescription = normalizeText(message.reason);
|
|
184
|
+
let description = payloadDescription;
|
|
185
|
+
if (!description && reasonDescription && reasonDescription.toLowerCase() !== (toolName ?? "").toLowerCase()) {
|
|
186
|
+
description = reasonDescription;
|
|
187
|
+
}
|
|
188
|
+
if (description && toolName && description.toLowerCase() === toolName.toLowerCase()) {
|
|
189
|
+
description = null;
|
|
190
|
+
}
|
|
191
|
+
return {
|
|
192
|
+
requestId: message.id,
|
|
193
|
+
toolName,
|
|
194
|
+
description
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
function buildReadyPushNotification(opts) {
|
|
198
|
+
const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
|
|
199
|
+
const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
|
|
200
|
+
return {
|
|
201
|
+
title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Ready"),
|
|
202
|
+
body: truncateText(`${providerDisplayLabel} is waiting for your next message`, BODY_MAX_LENGTH),
|
|
203
|
+
data: buildRouteData({
|
|
204
|
+
...opts,
|
|
205
|
+
notificationKind: "ready",
|
|
206
|
+
routePreference: "session"
|
|
207
|
+
})
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
function buildPermissionPushNotification(opts) {
|
|
211
|
+
const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
|
|
212
|
+
const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
|
|
213
|
+
const fallback = `${providerDisplayLabel} needs your approval to ${humanizeToolName(opts.toolName)}`;
|
|
214
|
+
const body = deriveNotificationSummary([opts.description], fallback, sessionLabel);
|
|
215
|
+
return {
|
|
216
|
+
title: buildNotificationTitle(sessionLabel, opts.providerLabel, "Permission needed"),
|
|
217
|
+
body,
|
|
218
|
+
data: buildRouteData({
|
|
219
|
+
...opts,
|
|
220
|
+
notificationKind: "permission_request",
|
|
221
|
+
routePreference: "session",
|
|
222
|
+
extraData: {
|
|
223
|
+
requestId: opts.requestId,
|
|
224
|
+
tool: opts.toolName ?? null,
|
|
225
|
+
...opts.extraData
|
|
226
|
+
}
|
|
227
|
+
})
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
function buildTurnResultPushNotification(opts) {
|
|
231
|
+
const sessionLabel = deriveNotificationSessionLabel(opts.metadata, opts.providerLabel);
|
|
232
|
+
const providerDisplayLabel = deriveNotificationProviderLabel(opts.providerLabel);
|
|
233
|
+
const report = opts.report ?? null;
|
|
234
|
+
const explicitSummary = normalizeText(report?.summary) ?? normalizeText(opts.responseText);
|
|
235
|
+
if (!explicitSummary) {
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
const fallback = `${providerDisplayLabel} has a new result ready`;
|
|
239
|
+
const body = deriveNotificationSummary(
|
|
240
|
+
[
|
|
241
|
+
explicitSummary
|
|
242
|
+
],
|
|
243
|
+
fallback,
|
|
244
|
+
sessionLabel
|
|
245
|
+
);
|
|
246
|
+
const action = report?.turnStatus === "task_complete" ? "Task complete" : "New result";
|
|
247
|
+
return {
|
|
248
|
+
title: buildNotificationTitle(sessionLabel, opts.providerLabel, action),
|
|
249
|
+
body,
|
|
250
|
+
data: buildRouteData({
|
|
251
|
+
...opts,
|
|
252
|
+
report,
|
|
253
|
+
notificationKind: "turn_result",
|
|
254
|
+
routePreference: "session",
|
|
255
|
+
extraData: {
|
|
256
|
+
turnStatus: report?.turnStatus ?? "turn_update"
|
|
257
|
+
}
|
|
258
|
+
})
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const DEFAULT_MAX_MESSAGES = 200;
|
|
263
|
+
const DEFAULT_MAX_CHARACTERS = 1e5;
|
|
264
|
+
const DEFAULT_MAX_MESSAGE_CHARACTERS = 8e3;
|
|
265
|
+
const TRUNCATION_PREFIX = "...\n";
|
|
266
|
+
class MessageBuffer {
|
|
267
|
+
messages = [];
|
|
268
|
+
listeners = [];
|
|
269
|
+
nextId = 1;
|
|
270
|
+
enabled;
|
|
271
|
+
maxMessages;
|
|
272
|
+
maxCharacters;
|
|
273
|
+
maxMessageCharacters;
|
|
274
|
+
constructor(options = {}) {
|
|
275
|
+
this.enabled = options.enabled ?? true;
|
|
276
|
+
this.maxMessages = Math.max(1, options.maxMessages ?? DEFAULT_MAX_MESSAGES);
|
|
277
|
+
this.maxCharacters = Math.max(1, options.maxCharacters ?? DEFAULT_MAX_CHARACTERS);
|
|
278
|
+
this.maxMessageCharacters = Math.max(1, options.maxMessageCharacters ?? DEFAULT_MAX_MESSAGE_CHARACTERS);
|
|
279
|
+
}
|
|
280
|
+
addMessage(content, type = "assistant") {
|
|
281
|
+
const id = `msg-${this.nextId++}`;
|
|
282
|
+
if (!this.enabled) {
|
|
283
|
+
return id;
|
|
284
|
+
}
|
|
285
|
+
const message = {
|
|
286
|
+
id,
|
|
287
|
+
timestamp: /* @__PURE__ */ new Date(),
|
|
288
|
+
content: this.normalizeContent(content),
|
|
289
|
+
type
|
|
290
|
+
};
|
|
291
|
+
this.messages.push(message);
|
|
292
|
+
this.trimMessages();
|
|
293
|
+
this.notifyListeners();
|
|
294
|
+
return message.id;
|
|
295
|
+
}
|
|
296
|
+
updateMessage(id, content, options = {}) {
|
|
297
|
+
if (!this.enabled) {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
const index = this.messages.findIndex((message) => message.id === id);
|
|
301
|
+
if (index === -1) {
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
const normalizedContent = this.normalizeContent(content);
|
|
305
|
+
const previous = this.messages[index];
|
|
306
|
+
this.messages[index] = {
|
|
307
|
+
...previous,
|
|
308
|
+
content: this.truncateContent(options.mode === "replace" ? normalizedContent : previous.content + normalizedContent)
|
|
309
|
+
};
|
|
310
|
+
this.trimMessages();
|
|
311
|
+
this.notifyListeners();
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
removeMessage(id) {
|
|
315
|
+
if (!this.enabled) {
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
const index = this.messages.findIndex((message) => message.id === id);
|
|
319
|
+
if (index === -1) {
|
|
320
|
+
return false;
|
|
321
|
+
}
|
|
322
|
+
this.messages.splice(index, 1);
|
|
323
|
+
this.notifyListeners();
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Update the last message of a specific type by appending content to it
|
|
328
|
+
* Useful for streaming responses where deltas should accumulate in one message
|
|
329
|
+
*/
|
|
330
|
+
updateLastMessage(contentDelta, type = "assistant") {
|
|
331
|
+
if (!this.enabled) {
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
const normalizedDelta = this.normalizeContent(contentDelta);
|
|
335
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
336
|
+
if (this.messages[i].type === type) {
|
|
337
|
+
const oldMessage = this.messages[i];
|
|
338
|
+
const updatedMessage = {
|
|
339
|
+
...oldMessage,
|
|
340
|
+
content: this.truncateContent(oldMessage.content + normalizedDelta)
|
|
341
|
+
};
|
|
342
|
+
this.messages[i] = updatedMessage;
|
|
343
|
+
this.trimMessages();
|
|
344
|
+
this.notifyListeners();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
this.addMessage(normalizedDelta, type);
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Remove the last message of a specific type
|
|
352
|
+
* Useful for removing placeholder messages like "Thinking..." when actual response starts
|
|
353
|
+
*/
|
|
354
|
+
removeLastMessage(type) {
|
|
355
|
+
if (!this.enabled) {
|
|
356
|
+
return false;
|
|
357
|
+
}
|
|
358
|
+
for (let i = this.messages.length - 1; i >= 0; i--) {
|
|
359
|
+
if (this.messages[i].type === type) {
|
|
360
|
+
this.messages.splice(i, 1);
|
|
361
|
+
this.notifyListeners();
|
|
362
|
+
return true;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return false;
|
|
366
|
+
}
|
|
367
|
+
getMessages() {
|
|
368
|
+
return [...this.messages];
|
|
369
|
+
}
|
|
370
|
+
clear() {
|
|
371
|
+
this.messages = [];
|
|
372
|
+
this.nextId = 1;
|
|
373
|
+
if (!this.enabled) {
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
this.notifyListeners();
|
|
377
|
+
}
|
|
378
|
+
onUpdate(listener) {
|
|
379
|
+
if (!this.enabled) {
|
|
380
|
+
return () => {
|
|
381
|
+
};
|
|
382
|
+
}
|
|
383
|
+
this.listeners.push(listener);
|
|
384
|
+
return () => {
|
|
385
|
+
const index = this.listeners.indexOf(listener);
|
|
386
|
+
if (index > -1) {
|
|
387
|
+
this.listeners.splice(index, 1);
|
|
388
|
+
}
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
normalizeContent(content) {
|
|
392
|
+
return this.truncateContent(formatDisplayMessage(content));
|
|
393
|
+
}
|
|
394
|
+
truncateContent(content) {
|
|
395
|
+
if (content.length <= this.maxMessageCharacters) {
|
|
396
|
+
return content;
|
|
397
|
+
}
|
|
398
|
+
const tailLength = Math.max(0, this.maxMessageCharacters - TRUNCATION_PREFIX.length);
|
|
399
|
+
return `${TRUNCATION_PREFIX}${content.slice(content.length - tailLength)}`;
|
|
400
|
+
}
|
|
401
|
+
trimMessages() {
|
|
402
|
+
while (this.messages.length > this.maxMessages) {
|
|
403
|
+
this.messages.shift();
|
|
404
|
+
}
|
|
405
|
+
let totalCharacters = this.messages.reduce((sum, message) => sum + message.content.length, 0);
|
|
406
|
+
while (totalCharacters > this.maxCharacters && this.messages.length > 1) {
|
|
407
|
+
const removed = this.messages.shift();
|
|
408
|
+
if (removed) {
|
|
409
|
+
totalCharacters -= removed.content.length;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
notifyListeners() {
|
|
414
|
+
const messages = this.getMessages();
|
|
415
|
+
this.listeners.forEach((listener) => listener(messages));
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
function isRecord(value) {
|
|
420
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
421
|
+
}
|
|
422
|
+
function hasClaudeCompatibilityShadow(value) {
|
|
423
|
+
if (!isRecord(value)) {
|
|
424
|
+
return false;
|
|
425
|
+
}
|
|
426
|
+
if (typeof value.happyCompatibilityShadow === "string" && value.happyCompatibilityShadow.trim()) {
|
|
427
|
+
return true;
|
|
428
|
+
}
|
|
429
|
+
const message = value.message;
|
|
430
|
+
if (!isRecord(message) || !Array.isArray(message.content)) {
|
|
431
|
+
return false;
|
|
432
|
+
}
|
|
433
|
+
return message.content.some((block) => isRecord(block) && typeof block.happyCompatibilityShadow === "string" && block.happyCompatibilityShadow.trim().length > 0);
|
|
434
|
+
}
|
|
435
|
+
function createSessionTranscriptInkRenderer(opts) {
|
|
436
|
+
const streamedAssistantMessages = /* @__PURE__ */ new Map();
|
|
437
|
+
const renderBufferedText = (text, type, streamMetadata) => {
|
|
438
|
+
const normalizedText = text.trim();
|
|
439
|
+
if (!normalizedText) {
|
|
440
|
+
return;
|
|
441
|
+
}
|
|
442
|
+
const streamKey = typeof streamMetadata?.messageId === "string" ? streamMetadata.messageId : typeof streamMetadata?.id === "string" ? streamMetadata.id : null;
|
|
443
|
+
const phase = typeof streamMetadata?.phase === "string" ? streamMetadata.phase : null;
|
|
444
|
+
const updateMode = streamMetadata?.mode === "replace" || phase === "commit" ? "replace" : "append";
|
|
445
|
+
if (phase === "abort") {
|
|
446
|
+
if (streamKey) {
|
|
447
|
+
const bufferedId = streamedAssistantMessages.get(streamKey);
|
|
448
|
+
if (bufferedId) {
|
|
449
|
+
opts.messageBuffer.removeMessage(bufferedId);
|
|
450
|
+
streamedAssistantMessages.delete(streamKey);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
if (!streamKey) {
|
|
456
|
+
opts.messageBuffer.addMessage(normalizedText, type);
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
const existingBufferedId = streamedAssistantMessages.get(streamKey);
|
|
460
|
+
if (!existingBufferedId) {
|
|
461
|
+
const nextBufferedId = opts.messageBuffer.addMessage(normalizedText, type);
|
|
462
|
+
if (phase !== "commit") {
|
|
463
|
+
streamedAssistantMessages.set(streamKey, nextBufferedId);
|
|
464
|
+
}
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const updated = opts.messageBuffer.updateMessage(existingBufferedId, normalizedText, {
|
|
468
|
+
mode: updateMode
|
|
469
|
+
});
|
|
470
|
+
if (!updated) {
|
|
471
|
+
const nextBufferedId = opts.messageBuffer.addMessage(normalizedText, type);
|
|
472
|
+
if (phase !== "commit") {
|
|
473
|
+
streamedAssistantMessages.set(streamKey, nextBufferedId);
|
|
474
|
+
}
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (phase === "commit") {
|
|
478
|
+
streamedAssistantMessages.delete(streamKey);
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
const renderStructuredAgentPayload = (payload) => {
|
|
482
|
+
if (!isRecord(payload) || typeof payload.type !== "string") {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
switch (payload.type) {
|
|
486
|
+
case "message":
|
|
487
|
+
case "reasoning": {
|
|
488
|
+
if (typeof payload.message !== "string") {
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
renderBufferedText(
|
|
492
|
+
payload.message,
|
|
493
|
+
payload.type === "reasoning" ? "status" : "assistant",
|
|
494
|
+
payload
|
|
495
|
+
);
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
case "thinking": {
|
|
499
|
+
if (typeof payload.text === "string" && payload.text.trim()) {
|
|
500
|
+
opts.messageBuffer.addMessage(`[Thinking] ${payload.text.trim()}`, "status");
|
|
501
|
+
}
|
|
502
|
+
return;
|
|
503
|
+
}
|
|
504
|
+
case "tool-call": {
|
|
505
|
+
const name = typeof payload.name === "string" ? payload.name : typeof payload.toolName === "string" ? payload.toolName : "tool";
|
|
506
|
+
const inputPreview = truncateDisplayMessage(
|
|
507
|
+
isRecord(payload.input) || Array.isArray(payload.input) ? JSON.stringify(payload.input) : payload.input,
|
|
508
|
+
120
|
|
509
|
+
);
|
|
510
|
+
opts.messageBuffer.addMessage(
|
|
511
|
+
`Executing: ${name}${inputPreview ? ` ${inputPreview}` : ""}`,
|
|
512
|
+
"tool"
|
|
513
|
+
);
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
case "tool-result":
|
|
517
|
+
case "tool-call-result": {
|
|
518
|
+
const resultValue = Object.prototype.hasOwnProperty.call(payload, "output") ? payload.output : payload.result;
|
|
519
|
+
const resultPreview = truncateDisplayMessage(resultValue, 200);
|
|
520
|
+
const prefix = payload.isError ? "Error:" : "Result:";
|
|
521
|
+
opts.messageBuffer.addMessage(
|
|
522
|
+
resultPreview ? `${prefix} ${resultPreview}` : "Tool completed",
|
|
523
|
+
payload.isError ? "status" : "result"
|
|
524
|
+
);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
case "file-edit":
|
|
528
|
+
case "fs-edit": {
|
|
529
|
+
const description = typeof payload.description === "string" ? payload.description : "File edit";
|
|
530
|
+
opts.messageBuffer.addMessage(`File edit: ${description}`, "tool");
|
|
531
|
+
return;
|
|
532
|
+
}
|
|
533
|
+
case "terminal-output": {
|
|
534
|
+
if (typeof payload.data !== "string") {
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const preview = renderTerminalOutputPreview(payload.data);
|
|
538
|
+
if (preview) {
|
|
539
|
+
opts.messageBuffer.addMessage(preview, "result");
|
|
540
|
+
}
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
case "permission-request": {
|
|
544
|
+
const toolName = typeof payload.toolName === "string" ? payload.toolName : "tool";
|
|
545
|
+
opts.messageBuffer.addMessage(`Permission requested: ${toolName}`, "status");
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
case "exec-approval-request": {
|
|
549
|
+
opts.messageBuffer.addMessage("Exec approval requested", "status");
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
552
|
+
case "patch-apply-begin": {
|
|
553
|
+
opts.messageBuffer.addMessage("Applying patch...", "tool");
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
case "patch-apply-end": {
|
|
557
|
+
const completionMessage = payload.success === false ? truncateDisplayMessage(payload.stderr, 200) || "Patch failed" : truncateDisplayMessage(payload.stdout, 200) || "Patch applied";
|
|
558
|
+
opts.messageBuffer.addMessage(completionMessage, payload.success === false ? "status" : "result");
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
561
|
+
case "event": {
|
|
562
|
+
if (payload.name === "thinking" && isRecord(payload.payload) && typeof payload.payload.text === "string" && payload.payload.text.trim()) {
|
|
563
|
+
opts.messageBuffer.addMessage(`[Thinking] ${payload.payload.text.trim()}`, "status");
|
|
564
|
+
}
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
case "task_started":
|
|
568
|
+
case "task_complete":
|
|
569
|
+
case "turn_aborted":
|
|
570
|
+
case "turn-report":
|
|
571
|
+
case "token_count":
|
|
572
|
+
case "token-count":
|
|
573
|
+
return;
|
|
574
|
+
default:
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
const renderLegacyClaudeOutput = (payload) => {
|
|
579
|
+
if (!isRecord(payload) || hasClaudeCompatibilityShadow(payload)) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (payload.type === "summary" && typeof payload.summary === "string" && payload.summary.trim()) {
|
|
583
|
+
opts.messageBuffer.addMessage(payload.summary.trim(), "result");
|
|
584
|
+
return;
|
|
585
|
+
}
|
|
586
|
+
if (payload.type !== "assistant") {
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
const message = isRecord(payload.message) ? payload.message : null;
|
|
590
|
+
const content = message?.content;
|
|
591
|
+
if (typeof content === "string" && content.trim()) {
|
|
592
|
+
opts.messageBuffer.addMessage(content.trim(), "assistant");
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (!Array.isArray(content)) {
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
for (const block of content) {
|
|
599
|
+
if (!isRecord(block) || typeof block.type !== "string") {
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (block.type === "thinking" && typeof block.thinking === "string" && block.thinking.trim()) {
|
|
603
|
+
opts.messageBuffer.addMessage(`[Thinking] ${block.thinking.trim()}`, "status");
|
|
604
|
+
continue;
|
|
605
|
+
}
|
|
606
|
+
if (block.type === "text" && typeof block.text === "string" && block.text.trim()) {
|
|
607
|
+
opts.messageBuffer.addMessage(block.text.trim(), "assistant");
|
|
608
|
+
continue;
|
|
609
|
+
}
|
|
610
|
+
if (block.type === "tool_use") {
|
|
611
|
+
const toolName = typeof block.name === "string" ? block.name : "tool";
|
|
612
|
+
const inputPreview = truncateDisplayMessage(
|
|
613
|
+
isRecord(block.input) || Array.isArray(block.input) ? JSON.stringify(block.input) : block.input,
|
|
614
|
+
120
|
|
615
|
+
);
|
|
616
|
+
opts.messageBuffer.addMessage(
|
|
617
|
+
`Executing: ${toolName}${inputPreview ? ` ${inputPreview}` : ""}`,
|
|
618
|
+
"tool"
|
|
619
|
+
);
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
};
|
|
623
|
+
const renderSessionEvent = (payload) => {
|
|
624
|
+
if (!isRecord(payload) || typeof payload.type !== "string") {
|
|
625
|
+
return;
|
|
626
|
+
}
|
|
627
|
+
switch (payload.type) {
|
|
628
|
+
case "message":
|
|
629
|
+
if (typeof payload.message === "string" && payload.message.trim()) {
|
|
630
|
+
opts.messageBuffer.addMessage(payload.message.trim(), "status");
|
|
631
|
+
}
|
|
632
|
+
return;
|
|
633
|
+
case "switch":
|
|
634
|
+
if (payload.mode === "local" || payload.mode === "remote") {
|
|
635
|
+
opts.messageBuffer.addMessage(`Mode switched to ${payload.mode}`, "status");
|
|
636
|
+
}
|
|
637
|
+
return;
|
|
638
|
+
case "permission-mode-changed":
|
|
639
|
+
if (typeof payload.mode === "string" && payload.mode.trim()) {
|
|
640
|
+
opts.messageBuffer.addMessage(`Permission mode: ${payload.mode}`, "status");
|
|
641
|
+
}
|
|
642
|
+
return;
|
|
643
|
+
case "ready":
|
|
644
|
+
return;
|
|
645
|
+
default:
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
};
|
|
649
|
+
return (transcriptMessage) => {
|
|
650
|
+
if (transcriptMessage.message.role === "user") {
|
|
651
|
+
const text = transcriptMessage.message.content.text.trim();
|
|
652
|
+
if (text) {
|
|
653
|
+
opts.messageBuffer.addMessage(text, "user");
|
|
654
|
+
}
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
switch (transcriptMessage.message.content.type) {
|
|
658
|
+
case "output":
|
|
659
|
+
renderLegacyClaudeOutput(transcriptMessage.message.content.data);
|
|
660
|
+
return;
|
|
661
|
+
case "codex":
|
|
662
|
+
renderStructuredAgentPayload(transcriptMessage.message.content.data);
|
|
663
|
+
return;
|
|
664
|
+
case "acp":
|
|
665
|
+
renderStructuredAgentPayload(transcriptMessage.message.content.data);
|
|
666
|
+
return;
|
|
667
|
+
case "event":
|
|
668
|
+
renderSessionEvent(transcriptMessage.message.content.data);
|
|
669
|
+
return;
|
|
670
|
+
default:
|
|
671
|
+
opts.messageBuffer.addMessage(formatDisplayMessage(transcriptMessage.message), "status");
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
let ConversationHistory$1 = class ConversationHistory {
|
|
677
|
+
messages = [];
|
|
678
|
+
maxMessages;
|
|
679
|
+
maxCharacters;
|
|
680
|
+
constructor(options = {}) {
|
|
681
|
+
this.maxMessages = options.maxMessages ?? 20;
|
|
682
|
+
this.maxCharacters = options.maxCharacters ?? 5e4;
|
|
683
|
+
}
|
|
684
|
+
isDuplicate(role, content) {
|
|
685
|
+
if (this.messages.length === 0) {
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
688
|
+
for (let index = this.messages.length - 1; index >= 0; index -= 1) {
|
|
689
|
+
const message = this.messages[index];
|
|
690
|
+
if (message.role !== role) {
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const normalizedIncoming = content.trim().replace(/\s+/g, " ");
|
|
694
|
+
const normalizedExisting = message.content.replace(/\s+/g, " ");
|
|
695
|
+
return normalizedIncoming === normalizedExisting;
|
|
696
|
+
}
|
|
697
|
+
return false;
|
|
698
|
+
}
|
|
699
|
+
addUserMessage(content) {
|
|
700
|
+
this.addMessage("user", content);
|
|
701
|
+
}
|
|
702
|
+
addAssistantMessage(content) {
|
|
703
|
+
this.addMessage("assistant", content);
|
|
704
|
+
}
|
|
705
|
+
hasHistory() {
|
|
706
|
+
return this.messages.length > 0;
|
|
707
|
+
}
|
|
708
|
+
size() {
|
|
709
|
+
return this.messages.length;
|
|
710
|
+
}
|
|
711
|
+
clear() {
|
|
712
|
+
this.messages = [];
|
|
713
|
+
logger.debug("[ConversationHistory] History cleared");
|
|
714
|
+
}
|
|
715
|
+
getContextForNewSession(prefixMessage = "Continue from the prior session using the conversation below as context.") {
|
|
716
|
+
if (this.messages.length === 0) {
|
|
717
|
+
return "";
|
|
718
|
+
}
|
|
719
|
+
const formattedMessages = this.messages.map((message) => {
|
|
720
|
+
const role = message.role === "user" ? "User" : "Assistant";
|
|
721
|
+
const content = message.content.length > 2e3 ? `${message.content.slice(0, 2e3)}... [truncated]` : message.content;
|
|
722
|
+
return `${role}: ${content}`;
|
|
723
|
+
}).join("\n\n");
|
|
724
|
+
return [
|
|
725
|
+
"[PREVIOUS CONVERSATION CONTEXT]",
|
|
726
|
+
prefixMessage,
|
|
727
|
+
"",
|
|
728
|
+
formattedMessages,
|
|
729
|
+
"",
|
|
730
|
+
"[END OF PREVIOUS CONTEXT]",
|
|
731
|
+
""
|
|
732
|
+
].join("\n");
|
|
733
|
+
}
|
|
734
|
+
getSummary() {
|
|
735
|
+
const totalChars = this.messages.reduce((sum, message) => sum + message.content.length, 0);
|
|
736
|
+
const userCount = this.messages.filter((message) => message.role === "user").length;
|
|
737
|
+
const assistantCount = this.messages.filter((message) => message.role === "assistant").length;
|
|
738
|
+
return `${this.messages.length} messages (${userCount} user, ${assistantCount} assistant), ${totalChars} chars`;
|
|
739
|
+
}
|
|
740
|
+
addMessage(role, content) {
|
|
741
|
+
const trimmedContent = content.trim();
|
|
742
|
+
if (!trimmedContent) {
|
|
743
|
+
return;
|
|
744
|
+
}
|
|
745
|
+
if (this.isDuplicate(role, trimmedContent)) {
|
|
746
|
+
logger.debug(`[ConversationHistory] Skipping duplicate ${role} message (${trimmedContent.length} chars)`);
|
|
747
|
+
return;
|
|
748
|
+
}
|
|
749
|
+
this.messages.push({
|
|
750
|
+
role,
|
|
751
|
+
content: trimmedContent,
|
|
752
|
+
timestamp: Date.now()
|
|
753
|
+
});
|
|
754
|
+
this.trimHistory();
|
|
755
|
+
logger.debug(`[ConversationHistory] Added ${role} message (${trimmedContent.length} chars), total: ${this.messages.length}`);
|
|
756
|
+
}
|
|
757
|
+
trimHistory() {
|
|
758
|
+
while (this.messages.length > this.maxMessages) {
|
|
759
|
+
this.messages.shift();
|
|
760
|
+
}
|
|
761
|
+
let totalChars = this.messages.reduce((sum, message) => sum + message.content.length, 0);
|
|
762
|
+
while (totalChars > this.maxCharacters && this.messages.length > 1) {
|
|
763
|
+
const removed = this.messages.shift();
|
|
764
|
+
if (removed) {
|
|
765
|
+
totalChars -= removed.content.length;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
};
|
|
770
|
+
|
|
771
|
+
export { ConversationHistory$1 as C, MessageBuffer as M, buildReadyPushNotification as a, buildTurnResultPushNotification as b, buildPermissionPushNotification as c, createSessionTranscriptInkRenderer as d, extractPermissionRequestPushContext as e, launchRuntimeHandleWithFactoryResult as l };
|