handsoff 0.1.2-beta.1 → 0.1.2
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/gateway/process.js +1117 -198
- package/dist/gateway/process.js.map +1 -1
- package/package.json +1 -1
package/dist/gateway/process.js
CHANGED
|
@@ -2,12 +2,30 @@
|
|
|
2
2
|
var __create = Object.create;
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
5
7
|
var __knownSymbol = (name, symbol) => (symbol = Symbol[name]) ? symbol : /* @__PURE__ */ Symbol.for("Symbol." + name);
|
|
6
8
|
var __typeError = (msg) => {
|
|
7
9
|
throw TypeError(msg);
|
|
8
10
|
};
|
|
9
11
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
10
12
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
13
|
+
var __esm = (fn, res) => function __init() {
|
|
14
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
11
29
|
var __decoratorStart = (base) => [, , , __create(base?.[__knownSymbol("metadata")] ?? null)];
|
|
12
30
|
var __decoratorStrings = ["class", "method", "getter", "setter", "accessor", "field", "value", "get", "set"];
|
|
13
31
|
var __expectFn = (fn) => fn !== void 0 && typeof fn !== "function" ? __typeError("Function expected") : fn;
|
|
@@ -47,7 +65,312 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
|
|
|
47
65
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
48
66
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
49
67
|
|
|
68
|
+
// node_modules/.pnpm/tsup@8.5.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js
|
|
69
|
+
import path from "path";
|
|
70
|
+
import { fileURLToPath } from "url";
|
|
71
|
+
var init_esm_shims = __esm({
|
|
72
|
+
"node_modules/.pnpm/tsup@8.5.1_postcss@8.5.8_tsx@4.21.0_typescript@5.9.3/node_modules/tsup/assets/esm_shims.js"() {
|
|
73
|
+
"use strict";
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// src/adapters/channels/feishu/templates/message.ts
|
|
78
|
+
var message_exports = {};
|
|
79
|
+
__export(message_exports, {
|
|
80
|
+
buildMessageCard: () => buildMessageCard
|
|
81
|
+
});
|
|
82
|
+
function buildMessageCard(input) {
|
|
83
|
+
const elements = [];
|
|
84
|
+
elements.push({
|
|
85
|
+
tag: "markdown",
|
|
86
|
+
content: input.content,
|
|
87
|
+
text_align: "left",
|
|
88
|
+
text_size: "normal",
|
|
89
|
+
margin: "0px 0px 0px 0px"
|
|
90
|
+
});
|
|
91
|
+
if (input.meta) {
|
|
92
|
+
elements.push({ tag: "hr", margin: "0px 0px 0px 0px" });
|
|
93
|
+
elements.push({
|
|
94
|
+
tag: "column_set",
|
|
95
|
+
flex_mode: "stretch",
|
|
96
|
+
horizontal_spacing: "8px",
|
|
97
|
+
horizontal_align: "left",
|
|
98
|
+
columns: [
|
|
99
|
+
{
|
|
100
|
+
tag: "column",
|
|
101
|
+
width: "weighted",
|
|
102
|
+
elements: [
|
|
103
|
+
{
|
|
104
|
+
tag: "markdown",
|
|
105
|
+
content: input.meta,
|
|
106
|
+
text_align: "left",
|
|
107
|
+
text_size: "notation",
|
|
108
|
+
margin: "0px 0px 0px 0px",
|
|
109
|
+
icon: {
|
|
110
|
+
tag: "standard_icon",
|
|
111
|
+
token: "ccm-filter_outlined",
|
|
112
|
+
color: "grey"
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
],
|
|
116
|
+
vertical_spacing: "8px",
|
|
117
|
+
horizontal_align: "left",
|
|
118
|
+
vertical_align: "center",
|
|
119
|
+
weight: 1
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
margin: "0px 0px 0px 0px"
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
const card = {
|
|
126
|
+
schema: "2.0",
|
|
127
|
+
config: { update_multi: true },
|
|
128
|
+
body: {
|
|
129
|
+
direction: "vertical",
|
|
130
|
+
elements
|
|
131
|
+
},
|
|
132
|
+
header: {
|
|
133
|
+
title: {
|
|
134
|
+
tag: "plain_text",
|
|
135
|
+
content: input.title
|
|
136
|
+
},
|
|
137
|
+
subtitle: {
|
|
138
|
+
tag: "plain_text",
|
|
139
|
+
content: ""
|
|
140
|
+
},
|
|
141
|
+
template: "blue",
|
|
142
|
+
padding: "12px 8px 12px 8px"
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
return JSON.stringify(card);
|
|
146
|
+
}
|
|
147
|
+
var init_message = __esm({
|
|
148
|
+
"src/adapters/channels/feishu/templates/message.ts"() {
|
|
149
|
+
"use strict";
|
|
150
|
+
init_esm_shims();
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// src/adapters/channels/feishu/templates/permission.ts
|
|
155
|
+
var permission_exports = {};
|
|
156
|
+
__export(permission_exports, {
|
|
157
|
+
buildPermissionCard: () => buildPermissionCard
|
|
158
|
+
});
|
|
159
|
+
function buildPermissionCard(input) {
|
|
160
|
+
const columns = input.buttons.map((btn) => {
|
|
161
|
+
const buttonEl = {
|
|
162
|
+
tag: "button",
|
|
163
|
+
text: { tag: "plain_text", content: btn.text },
|
|
164
|
+
type: btn.type,
|
|
165
|
+
width: "default",
|
|
166
|
+
size: "small",
|
|
167
|
+
behaviors: [
|
|
168
|
+
{
|
|
169
|
+
type: "callback",
|
|
170
|
+
value: { action: btn.value }
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
};
|
|
174
|
+
if (btn.confirm) {
|
|
175
|
+
buttonEl.confirm = {
|
|
176
|
+
title: { tag: "plain_text", content: btn.confirm.title },
|
|
177
|
+
text: { tag: "plain_text", content: btn.confirm.text }
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
return {
|
|
181
|
+
tag: "column",
|
|
182
|
+
width: "auto",
|
|
183
|
+
elements: [buttonEl],
|
|
184
|
+
padding: "0px 0px 0px 0px",
|
|
185
|
+
direction: "horizontal",
|
|
186
|
+
horizontal_spacing: "4px",
|
|
187
|
+
vertical_spacing: "4px",
|
|
188
|
+
horizontal_align: "center",
|
|
189
|
+
vertical_align: "center",
|
|
190
|
+
margin: "0px 0px 0px 0px"
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
const card = {
|
|
194
|
+
schema: "2.0",
|
|
195
|
+
config: { update_multi: true },
|
|
196
|
+
body: {
|
|
197
|
+
direction: "vertical",
|
|
198
|
+
elements: [
|
|
199
|
+
{
|
|
200
|
+
tag: "markdown",
|
|
201
|
+
content: input.content,
|
|
202
|
+
text_align: "left",
|
|
203
|
+
text_size: "normal",
|
|
204
|
+
margin: "0px 0px 0px 0px"
|
|
205
|
+
},
|
|
206
|
+
{ tag: "hr", margin: "0px 0px 0px 0px" },
|
|
207
|
+
{
|
|
208
|
+
tag: "column_set",
|
|
209
|
+
horizontal_spacing: "4px",
|
|
210
|
+
horizontal_align: "left",
|
|
211
|
+
columns,
|
|
212
|
+
margin: "0px 0px 0px 0px"
|
|
213
|
+
}
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
header: {
|
|
217
|
+
title: { tag: "plain_text", content: input.title },
|
|
218
|
+
subtitle: { tag: "plain_text", content: "" },
|
|
219
|
+
template: "blue",
|
|
220
|
+
padding: "12px 8px 12px 8px"
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
return JSON.stringify(card);
|
|
224
|
+
}
|
|
225
|
+
var init_permission = __esm({
|
|
226
|
+
"src/adapters/channels/feishu/templates/permission.ts"() {
|
|
227
|
+
"use strict";
|
|
228
|
+
init_esm_shims();
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// src/adapters/channels/feishu/templates/question.ts
|
|
233
|
+
var question_exports = {};
|
|
234
|
+
__export(question_exports, {
|
|
235
|
+
buildQuestionCard: () => buildQuestionCard
|
|
236
|
+
});
|
|
237
|
+
function buildQuestionCard(input) {
|
|
238
|
+
const elements = [
|
|
239
|
+
{
|
|
240
|
+
tag: "markdown",
|
|
241
|
+
content: input.content,
|
|
242
|
+
text_align: "left",
|
|
243
|
+
text_size: "normal",
|
|
244
|
+
margin: "0px 0px 0px 0px"
|
|
245
|
+
},
|
|
246
|
+
{ tag: "hr", margin: "0px 0px 0px 0px" }
|
|
247
|
+
];
|
|
248
|
+
if (input.mode === "single") {
|
|
249
|
+
const columns = input.items.map((item) => ({
|
|
250
|
+
tag: "column",
|
|
251
|
+
width: "auto",
|
|
252
|
+
elements: [
|
|
253
|
+
{
|
|
254
|
+
tag: "button",
|
|
255
|
+
text: { tag: "plain_text", content: item.label },
|
|
256
|
+
hover_tips: { tag: "plain_text", content: item.label },
|
|
257
|
+
type: "primary",
|
|
258
|
+
width: "default",
|
|
259
|
+
size: "small",
|
|
260
|
+
behaviors: [
|
|
261
|
+
{
|
|
262
|
+
type: "callback",
|
|
263
|
+
value: { action: "select", optionId: item.id, requestId: input.requestId }
|
|
264
|
+
}
|
|
265
|
+
]
|
|
266
|
+
}
|
|
267
|
+
],
|
|
268
|
+
padding: "0px 0px 0px 0px",
|
|
269
|
+
direction: "horizontal",
|
|
270
|
+
horizontal_spacing: "4px",
|
|
271
|
+
vertical_spacing: "4px",
|
|
272
|
+
horizontal_align: "center",
|
|
273
|
+
vertical_align: "center",
|
|
274
|
+
margin: "0px 0px 0px 0px"
|
|
275
|
+
}));
|
|
276
|
+
elements.push({
|
|
277
|
+
tag: "column_set",
|
|
278
|
+
horizontal_spacing: "4px",
|
|
279
|
+
horizontal_align: "left",
|
|
280
|
+
columns,
|
|
281
|
+
margin: "0px 0px 0px 0px"
|
|
282
|
+
});
|
|
283
|
+
} else {
|
|
284
|
+
const checkerElements = input.items.map((item) => ({
|
|
285
|
+
tag: "checker",
|
|
286
|
+
element_id: `checker_${item.id}`,
|
|
287
|
+
name: `checker_${item.id}`,
|
|
288
|
+
checked: false,
|
|
289
|
+
text: { tag: "plain_text", content: item.label },
|
|
290
|
+
behaviors: [
|
|
291
|
+
{
|
|
292
|
+
type: "callback",
|
|
293
|
+
value: { action: "check", optionId: item.id, requestId: input.requestId }
|
|
294
|
+
}
|
|
295
|
+
]
|
|
296
|
+
}));
|
|
297
|
+
elements.push({
|
|
298
|
+
tag: "column_set",
|
|
299
|
+
horizontal_spacing: "4px",
|
|
300
|
+
horizontal_align: "left",
|
|
301
|
+
columns: [
|
|
302
|
+
{
|
|
303
|
+
tag: "column",
|
|
304
|
+
width: "weighted",
|
|
305
|
+
elements: checkerElements,
|
|
306
|
+
padding: "0px 0px 0px 0px",
|
|
307
|
+
direction: "horizontal",
|
|
308
|
+
horizontal_spacing: "4px",
|
|
309
|
+
vertical_spacing: "4px",
|
|
310
|
+
horizontal_align: "left",
|
|
311
|
+
vertical_align: "center",
|
|
312
|
+
margin: "0px 0px 0px 0px",
|
|
313
|
+
weight: 1
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
tag: "column",
|
|
317
|
+
width: "auto",
|
|
318
|
+
elements: [
|
|
319
|
+
{
|
|
320
|
+
tag: "button",
|
|
321
|
+
text: { tag: "plain_text", content: "Submit" },
|
|
322
|
+
type: "primary_filled",
|
|
323
|
+
width: "default",
|
|
324
|
+
size: "small",
|
|
325
|
+
margin: "0px 0px 0px 0px",
|
|
326
|
+
behaviors: [
|
|
327
|
+
{
|
|
328
|
+
type: "callback",
|
|
329
|
+
value: { action: "submit", requestId: input.requestId }
|
|
330
|
+
}
|
|
331
|
+
]
|
|
332
|
+
}
|
|
333
|
+
],
|
|
334
|
+
padding: "0px 0px 0px 0px",
|
|
335
|
+
direction: "vertical",
|
|
336
|
+
horizontal_spacing: "8px",
|
|
337
|
+
vertical_spacing: "8px",
|
|
338
|
+
horizontal_align: "right",
|
|
339
|
+
vertical_align: "center",
|
|
340
|
+
margin: "0px 0px 0px 0px"
|
|
341
|
+
}
|
|
342
|
+
],
|
|
343
|
+
margin: "0px 0px 0px 0px"
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
const card = {
|
|
347
|
+
schema: "2.0",
|
|
348
|
+
config: { update_multi: true },
|
|
349
|
+
body: {
|
|
350
|
+
direction: "vertical",
|
|
351
|
+
elements
|
|
352
|
+
},
|
|
353
|
+
header: {
|
|
354
|
+
title: { tag: "plain_text", content: input.title },
|
|
355
|
+
subtitle: { tag: "plain_text", content: "" },
|
|
356
|
+
template: "blue",
|
|
357
|
+
padding: "12px 8px 12px 8px"
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
return JSON.stringify(card);
|
|
361
|
+
}
|
|
362
|
+
var init_question = __esm({
|
|
363
|
+
"src/adapters/channels/feishu/templates/question.ts"() {
|
|
364
|
+
"use strict";
|
|
365
|
+
init_esm_shims();
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// src/gateway/process.ts
|
|
370
|
+
init_esm_shims();
|
|
371
|
+
|
|
50
372
|
// src/shared/pidfile.ts
|
|
373
|
+
init_esm_shims();
|
|
51
374
|
import { writeFileSync, readFileSync, existsSync, unlinkSync } from "fs";
|
|
52
375
|
import { dirname } from "path";
|
|
53
376
|
import { mkdirSync } from "fs";
|
|
@@ -68,6 +391,7 @@ function removePidFile(pidFilePath) {
|
|
|
68
391
|
}
|
|
69
392
|
|
|
70
393
|
// src/shared/logger.ts
|
|
394
|
+
init_esm_shims();
|
|
71
395
|
import pino from "pino";
|
|
72
396
|
import { mkdirSync as mkdirSync2, existsSync as existsSync2, appendFileSync } from "fs";
|
|
73
397
|
import { dirname as dirname2 } from "path";
|
|
@@ -184,6 +508,7 @@ function getLogger(_level) {
|
|
|
184
508
|
}
|
|
185
509
|
|
|
186
510
|
// src/shared/session-logger.ts
|
|
511
|
+
init_esm_shims();
|
|
187
512
|
var SessionLogger = class {
|
|
188
513
|
bus;
|
|
189
514
|
unsubscribeFns = [];
|
|
@@ -264,7 +589,11 @@ var SessionLogger = class {
|
|
|
264
589
|
}
|
|
265
590
|
};
|
|
266
591
|
|
|
592
|
+
// src/gateway/index.ts
|
|
593
|
+
init_esm_shims();
|
|
594
|
+
|
|
267
595
|
// src/core/agent/AgentRegistry.ts
|
|
596
|
+
init_esm_shims();
|
|
268
597
|
import { randomBytes } from "crypto";
|
|
269
598
|
var AgentRegistry = class {
|
|
270
599
|
registrations = /* @__PURE__ */ new Map();
|
|
@@ -294,9 +623,11 @@ var AgentRegistry = class {
|
|
|
294
623
|
};
|
|
295
624
|
|
|
296
625
|
// src/core/session/SessionManager.ts
|
|
626
|
+
init_esm_shims();
|
|
297
627
|
import { randomUUID } from "crypto";
|
|
298
628
|
|
|
299
629
|
// src/core/adapter/AgentAdapterRegistry.ts
|
|
630
|
+
init_esm_shims();
|
|
300
631
|
var AgentAdapterRegistry = class _AgentAdapterRegistry {
|
|
301
632
|
static instance = null;
|
|
302
633
|
adapters = /* @__PURE__ */ new Map();
|
|
@@ -366,52 +697,90 @@ var AgentAdapterRegistry = class _AgentAdapterRegistry {
|
|
|
366
697
|
};
|
|
367
698
|
|
|
368
699
|
// src/core/session/Session.ts
|
|
700
|
+
init_esm_shims();
|
|
369
701
|
var Session = class {
|
|
370
|
-
|
|
371
|
-
|
|
702
|
+
_id;
|
|
703
|
+
agent;
|
|
372
704
|
token;
|
|
373
705
|
metadata;
|
|
374
|
-
adapter;
|
|
375
706
|
createdAt;
|
|
707
|
+
_status = "active";
|
|
708
|
+
_updatedAt;
|
|
709
|
+
_transportState;
|
|
376
710
|
cwd;
|
|
377
|
-
|
|
378
|
-
|
|
711
|
+
model;
|
|
712
|
+
permissionMode;
|
|
713
|
+
slashCommands;
|
|
379
714
|
constructor(options) {
|
|
380
|
-
this.
|
|
381
|
-
this.
|
|
715
|
+
this._id = options.id;
|
|
716
|
+
this.agent = options.adapter;
|
|
382
717
|
this.token = options.token;
|
|
383
718
|
this.metadata = options.metadata ?? {};
|
|
384
|
-
this.
|
|
385
|
-
this.
|
|
386
|
-
this.
|
|
719
|
+
this._transportState = options.transportState;
|
|
720
|
+
this.createdAt = options.createdAt ?? Date.now();
|
|
721
|
+
this._updatedAt = this.createdAt;
|
|
387
722
|
this.cwd = options.cwd;
|
|
388
723
|
}
|
|
724
|
+
get id() {
|
|
725
|
+
return this._id;
|
|
726
|
+
}
|
|
727
|
+
setId(newId) {
|
|
728
|
+
this._id = newId;
|
|
729
|
+
}
|
|
730
|
+
get agentType() {
|
|
731
|
+
return this.agent.agentType;
|
|
732
|
+
}
|
|
733
|
+
get status() {
|
|
734
|
+
return this._status;
|
|
735
|
+
}
|
|
736
|
+
get updatedAt() {
|
|
737
|
+
return this._updatedAt;
|
|
738
|
+
}
|
|
739
|
+
get transportState() {
|
|
740
|
+
return this._transportState;
|
|
741
|
+
}
|
|
742
|
+
updateInfo(partial) {
|
|
743
|
+
if (partial.status !== void 0) this._status = partial.status;
|
|
744
|
+
if (partial.cwd !== void 0) this.cwd = partial.cwd;
|
|
745
|
+
if (partial.model !== void 0) this.model = partial.model;
|
|
746
|
+
if (partial.permissionMode !== void 0) this.permissionMode = partial.permissionMode;
|
|
747
|
+
if (partial.slashCommands !== void 0) this.slashCommands = partial.slashCommands;
|
|
748
|
+
this._updatedAt = Date.now();
|
|
749
|
+
}
|
|
389
750
|
async sendCommand(command) {
|
|
390
|
-
if (this.
|
|
751
|
+
if (this._status !== "active") {
|
|
391
752
|
throw new Error(`Cannot send command to closed session: ${this.id}`);
|
|
392
753
|
}
|
|
393
|
-
return this.
|
|
754
|
+
return this.agent.sendCommand(this._transportState, command);
|
|
394
755
|
}
|
|
395
756
|
async close() {
|
|
396
|
-
if (this.
|
|
757
|
+
if (this._status !== "active") {
|
|
397
758
|
return;
|
|
398
759
|
}
|
|
399
|
-
await this.
|
|
400
|
-
this.
|
|
760
|
+
await this.agent.closeTransportState(this._transportState);
|
|
761
|
+
this._status = "closed";
|
|
401
762
|
}
|
|
763
|
+
/** @deprecated Use `status` getter instead */
|
|
402
764
|
getStatus() {
|
|
403
|
-
return this.
|
|
765
|
+
return this._status;
|
|
766
|
+
}
|
|
767
|
+
/** @deprecated Use `toInfo()` instead */
|
|
768
|
+
toJSON() {
|
|
769
|
+
return this.toInfo();
|
|
404
770
|
}
|
|
405
771
|
toInfo() {
|
|
406
772
|
return {
|
|
407
773
|
id: this.id,
|
|
408
774
|
agentType: this.agentType,
|
|
409
|
-
|
|
775
|
+
transportType: this.agent.transportType,
|
|
776
|
+
status: this._status,
|
|
410
777
|
createdAt: this.createdAt,
|
|
411
|
-
updatedAt:
|
|
778
|
+
updatedAt: this._updatedAt,
|
|
412
779
|
token: this.token,
|
|
413
|
-
|
|
414
|
-
|
|
780
|
+
cwd: this.cwd,
|
|
781
|
+
model: this.model,
|
|
782
|
+
permissionMode: this.permissionMode,
|
|
783
|
+
slashCommands: this.slashCommands
|
|
415
784
|
};
|
|
416
785
|
}
|
|
417
786
|
};
|
|
@@ -434,12 +803,12 @@ var SessionManager = class {
|
|
|
434
803
|
this.logger.debug({ sessionId, optionsCwd: options?.cwd, transportCwd, resolvedCwd: cwd }, "[SessionManager] Resolved cwd for session");
|
|
435
804
|
const session = new Session({
|
|
436
805
|
id: sessionId,
|
|
437
|
-
agentType,
|
|
438
806
|
adapter,
|
|
439
807
|
transportState,
|
|
440
808
|
token: options?.token,
|
|
441
809
|
metadata: options?.metadata,
|
|
442
|
-
cwd
|
|
810
|
+
cwd,
|
|
811
|
+
createdAt: options?.createdAt
|
|
443
812
|
});
|
|
444
813
|
this.sessions.set(sessionId, session);
|
|
445
814
|
this.logger.info({ sessionId, agentType, cwd, token: options?.token?.slice(0, 8) }, "[Session] Created");
|
|
@@ -469,13 +838,53 @@ var SessionManager = class {
|
|
|
469
838
|
getSessionCount() {
|
|
470
839
|
return this.sessions.size;
|
|
471
840
|
}
|
|
841
|
+
updateSessionInfo(sessionId, info) {
|
|
842
|
+
const session = this.sessions.get(sessionId);
|
|
843
|
+
if (!session) {
|
|
844
|
+
this.logger.warn({ sessionId }, "[SessionManager] updateSessionInfo: session not found");
|
|
845
|
+
return false;
|
|
846
|
+
}
|
|
847
|
+
session.updateInfo(info);
|
|
848
|
+
this.logger.debug({ sessionId, ...info }, "[SessionManager] Session info updated");
|
|
849
|
+
return true;
|
|
850
|
+
}
|
|
851
|
+
renameSessionId(oldId, newId) {
|
|
852
|
+
const session = this.sessions.get(oldId);
|
|
853
|
+
if (!session) {
|
|
854
|
+
this.logger.warn({ oldId, newId }, "[SessionManager] renameSessionId: session not found");
|
|
855
|
+
return false;
|
|
856
|
+
}
|
|
857
|
+
if (this.sessions.has(newId)) {
|
|
858
|
+
this.logger.warn({ oldId, newId }, "[SessionManager] renameSessionId: newId already exists");
|
|
859
|
+
return false;
|
|
860
|
+
}
|
|
861
|
+
session.setId(newId);
|
|
862
|
+
this.sessions.delete(oldId);
|
|
863
|
+
this.sessions.set(newId, session);
|
|
864
|
+
this.logger.info({ oldId, newId }, "[SessionManager] Session renamed");
|
|
865
|
+
return true;
|
|
866
|
+
}
|
|
472
867
|
};
|
|
473
868
|
|
|
869
|
+
// src/gateway/events.ts
|
|
870
|
+
init_esm_shims();
|
|
871
|
+
|
|
872
|
+
// src/gateway/interaction-service.ts
|
|
873
|
+
init_esm_shims();
|
|
874
|
+
|
|
474
875
|
// src/shared/permissions.ts
|
|
876
|
+
init_esm_shims();
|
|
475
877
|
import { readFileSync as readFileSync2, existsSync as existsSync3 } from "fs";
|
|
476
878
|
import { join } from "path";
|
|
477
879
|
|
|
880
|
+
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/index.js
|
|
881
|
+
init_esm_shims();
|
|
882
|
+
|
|
883
|
+
// node_modules/.pnpm/brace-expansion@5.0.5/node_modules/brace-expansion/dist/esm/index.js
|
|
884
|
+
init_esm_shims();
|
|
885
|
+
|
|
478
886
|
// node_modules/.pnpm/balanced-match@4.0.4/node_modules/balanced-match/dist/esm/index.js
|
|
887
|
+
init_esm_shims();
|
|
479
888
|
var balanced = (a, b, str) => {
|
|
480
889
|
const ma = a instanceof RegExp ? maybeMatch(a, str) : a;
|
|
481
890
|
const mb = b instanceof RegExp ? maybeMatch(b, str) : b;
|
|
@@ -689,6 +1098,7 @@ function expand_(str, max, isTop) {
|
|
|
689
1098
|
}
|
|
690
1099
|
|
|
691
1100
|
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/assert-valid-pattern.js
|
|
1101
|
+
init_esm_shims();
|
|
692
1102
|
var MAX_PATTERN_LENGTH = 1024 * 64;
|
|
693
1103
|
var assertValidPattern = (pattern) => {
|
|
694
1104
|
if (typeof pattern !== "string") {
|
|
@@ -699,7 +1109,11 @@ var assertValidPattern = (pattern) => {
|
|
|
699
1109
|
}
|
|
700
1110
|
};
|
|
701
1111
|
|
|
1112
|
+
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/ast.js
|
|
1113
|
+
init_esm_shims();
|
|
1114
|
+
|
|
702
1115
|
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/brace-expressions.js
|
|
1116
|
+
init_esm_shims();
|
|
703
1117
|
var posixClasses = {
|
|
704
1118
|
"[:alnum:]": ["\\p{L}\\p{Nl}\\p{Nd}", true],
|
|
705
1119
|
"[:alpha:]": ["\\p{L}\\p{Nl}", true],
|
|
@@ -809,6 +1223,7 @@ var parseClass = (glob, position) => {
|
|
|
809
1223
|
};
|
|
810
1224
|
|
|
811
1225
|
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/unescape.js
|
|
1226
|
+
init_esm_shims();
|
|
812
1227
|
var unescape = (s, { windowsPathsNoEscape = false, magicalBraces = true } = {}) => {
|
|
813
1228
|
if (magicalBraces) {
|
|
814
1229
|
return windowsPathsNoEscape ? s.replace(/\[([^/\\])\]/g, "$1") : s.replace(/((?!\\).|^)\[([^/\\])\]/g, "$1$2").replace(/\\([^/])/g, "$1");
|
|
@@ -1461,6 +1876,7 @@ var AST = class {
|
|
|
1461
1876
|
_a = AST;
|
|
1462
1877
|
|
|
1463
1878
|
// node_modules/.pnpm/minimatch@10.2.5/node_modules/minimatch/dist/esm/escape.js
|
|
1879
|
+
init_esm_shims();
|
|
1464
1880
|
var escape = (s, { windowsPathsNoEscape = false, magicalBraces = false } = {}) => {
|
|
1465
1881
|
if (magicalBraces) {
|
|
1466
1882
|
return windowsPathsNoEscape ? s.replace(/[?*()[\]{}]/g, "[$&]") : s.replace(/[?*()[\]\\{}]/g, "\\$&");
|
|
@@ -1527,11 +1943,11 @@ var qmarksTestNoExtDot = ([$0]) => {
|
|
|
1527
1943
|
return (f) => f.length === len && f !== "." && f !== "..";
|
|
1528
1944
|
};
|
|
1529
1945
|
var defaultPlatform = typeof process === "object" && process ? typeof process.env === "object" && process.env && process.env.__MINIMATCH_TESTING_PLATFORM__ || process.platform : "posix";
|
|
1530
|
-
var
|
|
1946
|
+
var path2 = {
|
|
1531
1947
|
win32: { sep: "\\" },
|
|
1532
1948
|
posix: { sep: "/" }
|
|
1533
1949
|
};
|
|
1534
|
-
var sep = defaultPlatform === "win32" ?
|
|
1950
|
+
var sep = defaultPlatform === "win32" ? path2.win32.sep : path2.posix.sep;
|
|
1535
1951
|
minimatch.sep = sep;
|
|
1536
1952
|
var GLOBSTAR = /* @__PURE__ */ Symbol("globstar **");
|
|
1537
1953
|
minimatch.GLOBSTAR = GLOBSTAR;
|
|
@@ -2340,7 +2756,7 @@ function matchesRule(toolName, toolInput, rule) {
|
|
|
2340
2756
|
}
|
|
2341
2757
|
if (toolName === "codex_patch_apply" && toolInput.fileChanges && typeof toolInput.fileChanges === "object") {
|
|
2342
2758
|
const paths = Object.keys(toolInput.fileChanges);
|
|
2343
|
-
return paths.some((
|
|
2759
|
+
return paths.some((path3) => matchesPattern(path3, pattern));
|
|
2344
2760
|
}
|
|
2345
2761
|
return false;
|
|
2346
2762
|
}
|
|
@@ -2556,7 +2972,7 @@ var Gateway = class {
|
|
|
2556
2972
|
agentType: session.agentType,
|
|
2557
2973
|
payload: { ...options?.metadata ?? {}, cwd: session.cwd },
|
|
2558
2974
|
metadata: {
|
|
2559
|
-
transportType: session.
|
|
2975
|
+
transportType: session.agent.transportType
|
|
2560
2976
|
}
|
|
2561
2977
|
},
|
|
2562
2978
|
session
|
|
@@ -2577,6 +2993,12 @@ var Gateway = class {
|
|
|
2577
2993
|
const session = this.sessionManager.getSession(sessionId);
|
|
2578
2994
|
return session?.agentType;
|
|
2579
2995
|
}
|
|
2996
|
+
/**
|
|
2997
|
+
* Get session info snapshot (including model/permissionMode/slashCommands)
|
|
2998
|
+
*/
|
|
2999
|
+
getSessionInfo(sessionId) {
|
|
3000
|
+
return this.sessionManager.getSessionInfo(sessionId);
|
|
3001
|
+
}
|
|
2580
3002
|
/**
|
|
2581
3003
|
* List all sessions
|
|
2582
3004
|
*/
|
|
@@ -2667,13 +3089,20 @@ var Gateway = class {
|
|
|
2667
3089
|
toolInput: request.toolInput,
|
|
2668
3090
|
requestId: request.requestId
|
|
2669
3091
|
},
|
|
2670
|
-
metadata: { transportType: session.
|
|
3092
|
+
metadata: { transportType: session.agent.transportType }
|
|
2671
3093
|
};
|
|
2672
3094
|
return await this.interactionService.evaluate(envelope);
|
|
2673
3095
|
}
|
|
3096
|
+
updateSessionInfo(sessionId, info) {
|
|
3097
|
+
this.sessionManager.updateSessionInfo(sessionId, info);
|
|
3098
|
+
}
|
|
3099
|
+
renameSessionId(oldId, newId) {
|
|
3100
|
+
return this.sessionManager.renameSessionId(oldId, newId);
|
|
3101
|
+
}
|
|
2674
3102
|
};
|
|
2675
3103
|
|
|
2676
3104
|
// src/gateway/publisher.ts
|
|
3105
|
+
init_esm_shims();
|
|
2677
3106
|
var EventPublisher = class {
|
|
2678
3107
|
constructor(bus, broadcastFn, persistence) {
|
|
2679
3108
|
this.bus = bus;
|
|
@@ -2779,7 +3208,17 @@ var EventPublisher = class {
|
|
|
2779
3208
|
}
|
|
2780
3209
|
};
|
|
2781
3210
|
|
|
3211
|
+
// src/adapters/agent/claude/index.ts
|
|
3212
|
+
init_esm_shims();
|
|
3213
|
+
|
|
3214
|
+
// src/adapters/agent/claude/ClaudeHookAgentAdapter.ts
|
|
3215
|
+
init_esm_shims();
|
|
3216
|
+
|
|
3217
|
+
// src/core/agent/BaseAgentAdapter.ts
|
|
3218
|
+
init_esm_shims();
|
|
3219
|
+
|
|
2782
3220
|
// src/core/agent/inbound-utils.ts
|
|
3221
|
+
init_esm_shims();
|
|
2783
3222
|
function escapeRegExp(str) {
|
|
2784
3223
|
return str.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2785
3224
|
}
|
|
@@ -2805,6 +3244,7 @@ var BaseAgentAdapter = class {
|
|
|
2805
3244
|
agentCommands = /* @__PURE__ */ new Map();
|
|
2806
3245
|
eventHandler = null;
|
|
2807
3246
|
unsubscribeFns = [];
|
|
3247
|
+
enricher;
|
|
2808
3248
|
constructor(config) {
|
|
2809
3249
|
this.bus = config.bus;
|
|
2810
3250
|
this.bridge = config.bridge;
|
|
@@ -2872,6 +3312,30 @@ var BaseAgentAdapter = class {
|
|
|
2872
3312
|
}
|
|
2873
3313
|
this.bridge.emitEvent(envelope);
|
|
2874
3314
|
}
|
|
3315
|
+
/**
|
|
3316
|
+
* Enrich the event envelope if a {@link TranscriptEnricher} is configured and
|
|
3317
|
+
* capable of handling this event type.
|
|
3318
|
+
*
|
|
3319
|
+
* Subclasses should call this in their async methods **before**
|
|
3320
|
+
* {@link emitEvent}. {@link emitEvent} remains synchronous by design because
|
|
3321
|
+
* downstream consumers (e.g. {@link TurnAggregator} callbacks) expect sync
|
|
3322
|
+
* execution. The async nature of enrichment means there may be an interleaving
|
|
3323
|
+
* gap between the call to this method and the subsequent emit.
|
|
3324
|
+
*/
|
|
3325
|
+
async enrichIfNeeded(envelope) {
|
|
3326
|
+
if (!this.enricher?.canEnrich(envelope.type)) {
|
|
3327
|
+
return envelope;
|
|
3328
|
+
}
|
|
3329
|
+
try {
|
|
3330
|
+
return await this.enricher.enrich(envelope);
|
|
3331
|
+
} catch (err) {
|
|
3332
|
+
this.logger.warn(
|
|
3333
|
+
{ sessionId: envelope.sessionId, eventType: envelope.type, error: err instanceof Error ? err.message : String(err) },
|
|
3334
|
+
"Transcript enrichment failed, emitting original envelope"
|
|
3335
|
+
);
|
|
3336
|
+
return envelope;
|
|
3337
|
+
}
|
|
3338
|
+
}
|
|
2875
3339
|
getHelpText() {
|
|
2876
3340
|
const lines = [
|
|
2877
3341
|
`${this.agentType} commands:`,
|
|
@@ -2898,13 +3362,21 @@ var BaseAgentAdapter = class {
|
|
|
2898
3362
|
this.bus.onInbound((msg) => this.handleInboundMessage(msg))
|
|
2899
3363
|
);
|
|
2900
3364
|
}
|
|
3365
|
+
/**
|
|
3366
|
+
* Resolve session ID from inbound message. Subclasses may override to
|
|
3367
|
+
* return a stable session ID based on transport-level identity (e.g.
|
|
3368
|
+
* Claude SDK session_id).
|
|
3369
|
+
*/
|
|
3370
|
+
resolveSessionId(_message) {
|
|
3371
|
+
return void 0;
|
|
3372
|
+
}
|
|
2901
3373
|
async handleInboundMessage(message) {
|
|
2902
3374
|
const text = message.text.trim();
|
|
2903
3375
|
this.logger.debug({ channel: message.channel, chatId: message.chatId, targetAgent: message.targetAgent }, "Inbound message received");
|
|
2904
3376
|
if (message.systemCommand) return;
|
|
2905
3377
|
if (message.targetAgent !== this.agentType) return;
|
|
2906
3378
|
const parsed = parseInboundCommand(text, this.prefix);
|
|
2907
|
-
const sessionId = `${this.agentType}-${message.
|
|
3379
|
+
const sessionId = this.resolveSessionId(message) ?? `${this.agentType}-${message.sender.id}`;
|
|
2908
3380
|
if (!parsed) {
|
|
2909
3381
|
if (!this.supportsInboundPrompt) {
|
|
2910
3382
|
this.logger.debug({ sessionId, textPreview: text.slice(0, 60) }, "Inbound prompt ignored: adapter does not support user input");
|
|
@@ -2973,6 +3445,7 @@ Session ID: ${sessionId}` : `No active ${this.agentType} session for this chat.`
|
|
|
2973
3445
|
};
|
|
2974
3446
|
|
|
2975
3447
|
// src/core/agent/EventNormalizer.ts
|
|
3448
|
+
init_esm_shims();
|
|
2976
3449
|
var EventNormalizer = class {
|
|
2977
3450
|
static sessionStart(sessionId, agentType, transportType, payload, extraMetadata) {
|
|
2978
3451
|
return this.build("session:start", sessionId, agentType, transportType, {
|
|
@@ -3003,7 +3476,8 @@ var EventNormalizer = class {
|
|
|
3003
3476
|
isTimeout: t2.isTimeout
|
|
3004
3477
|
})),
|
|
3005
3478
|
durationMs: extra?.durationMs,
|
|
3006
|
-
usage: extra?.usage
|
|
3479
|
+
usage: extra?.usage,
|
|
3480
|
+
transcriptPath: extra?.transcriptPath
|
|
3007
3481
|
});
|
|
3008
3482
|
}
|
|
3009
3483
|
static toolExecuted(sessionId, agentType, transportType, tool) {
|
|
@@ -3106,7 +3580,8 @@ var EventNormalizer = class {
|
|
|
3106
3580
|
...common,
|
|
3107
3581
|
reason: payload.reason,
|
|
3108
3582
|
lastAssistantMessage: payload.last_assistant_message,
|
|
3109
|
-
durationMs: typeof payload.duration === "number" ? payload.duration : void 0
|
|
3583
|
+
durationMs: typeof payload.duration === "number" ? payload.duration : void 0,
|
|
3584
|
+
transcriptPath: typeof payload.transcript_path === "string" ? payload.transcript_path : void 0
|
|
3110
3585
|
}, { rawEventType: eventType });
|
|
3111
3586
|
default:
|
|
3112
3587
|
return null;
|
|
@@ -3128,6 +3603,7 @@ var EventNormalizer = class {
|
|
|
3128
3603
|
};
|
|
3129
3604
|
|
|
3130
3605
|
// src/core/agent/interaction-utils.ts
|
|
3606
|
+
init_esm_shims();
|
|
3131
3607
|
async function evaluateInteraction(bridge, request) {
|
|
3132
3608
|
const originalResponse = await bridge.evaluateInteraction(request);
|
|
3133
3609
|
if (request.toolName === "AskUserQuestion" && (originalResponse.action === "select" || originalResponse.action === "input")) {
|
|
@@ -3146,6 +3622,118 @@ async function evaluateInteraction(bridge, request) {
|
|
|
3146
3622
|
return originalResponse;
|
|
3147
3623
|
}
|
|
3148
3624
|
|
|
3625
|
+
// src/adapters/agent/claude/jsonl-reader.ts
|
|
3626
|
+
init_esm_shims();
|
|
3627
|
+
import { readFile } from "fs/promises";
|
|
3628
|
+
import { resolve } from "path";
|
|
3629
|
+
async function readClaudeJSONL(transcriptPath) {
|
|
3630
|
+
let lastError;
|
|
3631
|
+
for (let attempt = 1; attempt <= 5; attempt++) {
|
|
3632
|
+
try {
|
|
3633
|
+
const content = await readFile(transcriptPath, "utf-8");
|
|
3634
|
+
const summary = parseTranscript(content);
|
|
3635
|
+
if (summary && (summary.lastAssistantMessage !== void 0 || summary.durationMs !== void 0)) {
|
|
3636
|
+
return summary;
|
|
3637
|
+
}
|
|
3638
|
+
if (summary) {
|
|
3639
|
+
getLogger().debug({ attempt, summary }, "Transcript read but incomplete, retrying...");
|
|
3640
|
+
}
|
|
3641
|
+
} catch (error2) {
|
|
3642
|
+
lastError = error2;
|
|
3643
|
+
}
|
|
3644
|
+
if (attempt < 5) {
|
|
3645
|
+
await new Promise((resolve3) => setTimeout(resolve3, 200));
|
|
3646
|
+
}
|
|
3647
|
+
}
|
|
3648
|
+
getLogger().warn({ error: lastError instanceof Error ? lastError.message : String(lastError), transcriptPath }, "Failed to read transcript or transcript incomplete");
|
|
3649
|
+
return void 0;
|
|
3650
|
+
}
|
|
3651
|
+
function resolveTranscriptPath(cwd, sessionId) {
|
|
3652
|
+
const projectDirName = cwd.replace(/[\\/]/g, "-");
|
|
3653
|
+
return resolve(process.env.HOME || "", ".claude", "projects", projectDirName, `${sessionId}.jsonl`);
|
|
3654
|
+
}
|
|
3655
|
+
function parseTranscript(content) {
|
|
3656
|
+
const lines = content.split("\n").filter((line) => line.trim().length > 0);
|
|
3657
|
+
let lastAssistantMessage;
|
|
3658
|
+
let thinking;
|
|
3659
|
+
let inputTokens;
|
|
3660
|
+
let outputTokens;
|
|
3661
|
+
let lastTextAssistant;
|
|
3662
|
+
let lastAnyAssistant;
|
|
3663
|
+
const userTimestamps = /* @__PURE__ */ new Map();
|
|
3664
|
+
const parentMap = /* @__PURE__ */ new Map();
|
|
3665
|
+
for (const line of lines) {
|
|
3666
|
+
let entry;
|
|
3667
|
+
try {
|
|
3668
|
+
entry = JSON.parse(line);
|
|
3669
|
+
} catch (parseError) {
|
|
3670
|
+
getLogger().warn(
|
|
3671
|
+
{ error: parseError instanceof Error ? parseError.message : String(parseError), line: line.slice(0, 200) },
|
|
3672
|
+
"Skipping malformed transcript line"
|
|
3673
|
+
);
|
|
3674
|
+
continue;
|
|
3675
|
+
}
|
|
3676
|
+
const ts = typeof entry.timestamp === "string" ? new Date(entry.timestamp).getTime() : typeof entry.timestamp === "number" ? entry.timestamp : void 0;
|
|
3677
|
+
if (entry.uuid && typeof entry.parentUuid === "string") {
|
|
3678
|
+
parentMap.set(entry.uuid, entry.parentUuid);
|
|
3679
|
+
}
|
|
3680
|
+
if (entry.type === "user" && ts !== void 0 && entry.uuid) {
|
|
3681
|
+
userTimestamps.set(entry.uuid, ts);
|
|
3682
|
+
}
|
|
3683
|
+
if (entry.type === "assistant" && ts !== void 0) {
|
|
3684
|
+
const arr = Array.isArray(entry.message?.content) ? entry.message.content : [];
|
|
3685
|
+
const textBlock = arr.find((c) => c.type === "text");
|
|
3686
|
+
const thinkingBlock = arr.find((c) => c.type === "thinking");
|
|
3687
|
+
const assistantRef = { ts, uuid: entry.uuid, parentUuid: entry.parentUuid };
|
|
3688
|
+
lastAnyAssistant = assistantRef;
|
|
3689
|
+
if (textBlock && typeof textBlock.text === "string") {
|
|
3690
|
+
lastAssistantMessage = textBlock.text;
|
|
3691
|
+
lastTextAssistant = assistantRef;
|
|
3692
|
+
}
|
|
3693
|
+
if (thinkingBlock && typeof thinkingBlock.thinking === "string") {
|
|
3694
|
+
thinking = thinkingBlock.thinking;
|
|
3695
|
+
}
|
|
3696
|
+
if (textBlock) {
|
|
3697
|
+
const usage = entry.message?.usage;
|
|
3698
|
+
if (usage) {
|
|
3699
|
+
if (typeof usage.input_tokens === "number") inputTokens = usage.input_tokens;
|
|
3700
|
+
if (typeof usage.output_tokens === "number") outputTokens = usage.output_tokens;
|
|
3701
|
+
}
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
}
|
|
3705
|
+
const durationMs = resolveDuration(lastTextAssistant, userTimestamps, parentMap) ?? resolveDuration(lastAnyAssistant, userTimestamps, parentMap);
|
|
3706
|
+
const summary = {};
|
|
3707
|
+
if (lastAssistantMessage !== void 0) summary.lastAssistantMessage = lastAssistantMessage;
|
|
3708
|
+
if (thinking !== void 0) summary.thinking = thinking;
|
|
3709
|
+
if (inputTokens !== void 0) summary.inputTokens = inputTokens;
|
|
3710
|
+
if (outputTokens !== void 0) summary.outputTokens = outputTokens;
|
|
3711
|
+
if (durationMs !== void 0) summary.durationMs = durationMs;
|
|
3712
|
+
return Object.keys(summary).length > 0 ? summary : void 0;
|
|
3713
|
+
}
|
|
3714
|
+
function resolveDuration(assistantRef, userTimestamps, parentMap) {
|
|
3715
|
+
if (!assistantRef) return void 0;
|
|
3716
|
+
if (assistantRef.parentUuid) {
|
|
3717
|
+
const directParentTs = userTimestamps.get(assistantRef.parentUuid);
|
|
3718
|
+
if (directParentTs !== void 0) {
|
|
3719
|
+
return assistantRef.ts - directParentTs;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
let currentUuid = assistantRef.uuid;
|
|
3723
|
+
const visited = /* @__PURE__ */ new Set();
|
|
3724
|
+
while (currentUuid && !visited.has(currentUuid)) {
|
|
3725
|
+
visited.add(currentUuid);
|
|
3726
|
+
const parentUuid = parentMap.get(currentUuid);
|
|
3727
|
+
if (!parentUuid) break;
|
|
3728
|
+
const parentTs = userTimestamps.get(parentUuid);
|
|
3729
|
+
if (parentTs !== void 0) {
|
|
3730
|
+
return assistantRef.ts - parentTs;
|
|
3731
|
+
}
|
|
3732
|
+
currentUuid = parentUuid;
|
|
3733
|
+
}
|
|
3734
|
+
return void 0;
|
|
3735
|
+
}
|
|
3736
|
+
|
|
3149
3737
|
// src/adapters/agent/claude/ClaudeHookAgentAdapter.ts
|
|
3150
3738
|
var ClaudeHookAgentAdapter = class extends BaseAgentAdapter {
|
|
3151
3739
|
agentType = "claude";
|
|
@@ -3159,6 +3747,7 @@ var ClaudeHookAgentAdapter = class extends BaseAgentAdapter {
|
|
|
3159
3747
|
constructor(config) {
|
|
3160
3748
|
super(config);
|
|
3161
3749
|
this.token = config.token ?? "";
|
|
3750
|
+
this.enricher = this;
|
|
3162
3751
|
}
|
|
3163
3752
|
// === Transport Lifecycle ===
|
|
3164
3753
|
async createTransportState(opts) {
|
|
@@ -3182,16 +3771,22 @@ var ClaudeHookAgentAdapter = class extends BaseAgentAdapter {
|
|
|
3182
3771
|
return;
|
|
3183
3772
|
}
|
|
3184
3773
|
if (eventType === "SessionStart") {
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3774
|
+
try {
|
|
3775
|
+
await this.bridge.ensureSession(sessionId, {
|
|
3776
|
+
cwd: payload.cwd,
|
|
3777
|
+
chatId: payload.chat_id,
|
|
3778
|
+
channel: payload.channel,
|
|
3779
|
+
metadata: {
|
|
3780
|
+
rawEventType: eventType
|
|
3781
|
+
}
|
|
3782
|
+
}, this.agentType);
|
|
3783
|
+
const model = typeof payload.model === "string" ? payload.model : void 0;
|
|
3784
|
+
if (model) {
|
|
3785
|
+
this.bridge.updateSessionInfo(sessionId, { model });
|
|
3786
|
+
}
|
|
3787
|
+
} catch (err) {
|
|
3193
3788
|
this.logger.warn({ sessionId, error: err instanceof Error ? err.message : String(err) }, "ensureSession failed during SessionStart");
|
|
3194
|
-
}
|
|
3789
|
+
}
|
|
3195
3790
|
return;
|
|
3196
3791
|
}
|
|
3197
3792
|
const envelope = EventNormalizer.fromHookEvent(
|
|
@@ -3201,8 +3796,51 @@ var ClaudeHookAgentAdapter = class extends BaseAgentAdapter {
|
|
|
3201
3796
|
this.transportType
|
|
3202
3797
|
);
|
|
3203
3798
|
if (!envelope) return;
|
|
3204
|
-
this.
|
|
3799
|
+
const enriched = await this.enrichIfNeeded(envelope);
|
|
3800
|
+
this.emitEvent(enriched);
|
|
3801
|
+
}
|
|
3802
|
+
// === TranscriptEnricher implementation ===
|
|
3803
|
+
canEnrich(eventType) {
|
|
3804
|
+
return eventType === "turn:finished";
|
|
3805
|
+
}
|
|
3806
|
+
async enrich(envelope) {
|
|
3807
|
+
const { sessionId, payload } = envelope;
|
|
3808
|
+
const transcriptPath = typeof payload.transcriptPath === "string" ? payload.transcriptPath : typeof payload.cwd === "string" ? resolveTranscriptPath(payload.cwd, sessionId) : void 0;
|
|
3809
|
+
if (!transcriptPath) {
|
|
3810
|
+
return envelope;
|
|
3811
|
+
}
|
|
3812
|
+
const summary = await readClaudeJSONL(transcriptPath);
|
|
3813
|
+
if (!summary) {
|
|
3814
|
+
return envelope;
|
|
3815
|
+
}
|
|
3816
|
+
const enrichedPayload = { ...payload };
|
|
3817
|
+
if (payload.durationMs === void 0 && summary.durationMs !== void 0) {
|
|
3818
|
+
enrichedPayload.durationMs = summary.durationMs;
|
|
3819
|
+
}
|
|
3820
|
+
if (payload.usage === void 0 && summary.inputTokens !== void 0 && summary.outputTokens !== void 0) {
|
|
3821
|
+
enrichedPayload.usage = {
|
|
3822
|
+
inputTokens: summary.inputTokens,
|
|
3823
|
+
outputTokens: summary.outputTokens
|
|
3824
|
+
};
|
|
3825
|
+
}
|
|
3826
|
+
return {
|
|
3827
|
+
...envelope,
|
|
3828
|
+
payload: enrichedPayload
|
|
3829
|
+
};
|
|
3205
3830
|
}
|
|
3831
|
+
/**
|
|
3832
|
+
* Handle permission/question requests from Claude hook events.
|
|
3833
|
+
*
|
|
3834
|
+
* Called for both PreToolUse (regular tools) and PermissionRequest events.
|
|
3835
|
+
* When toolName === 'AskUserQuestion', the request type is 'question' instead
|
|
3836
|
+
* of 'permission', which causes channels to render question cards (single/multi
|
|
3837
|
+
* select) instead of permission cards (Allow/Deny).
|
|
3838
|
+
*
|
|
3839
|
+
* evaluateInteraction blocks until the user responds via a channel. The response
|
|
3840
|
+
* is returned to Claude as part of the HTTP hook response body.
|
|
3841
|
+
*
|
|
3842
|
+
* See file header for full flow diagrams.
|
|
3843
|
+
*/
|
|
3206
3844
|
async processPermissionRequest(eventType, payload, requestId) {
|
|
3207
3845
|
const sessionId = typeof payload.session_id === "string" ? payload.session_id : void 0;
|
|
3208
3846
|
const toolName = typeof payload.tool_name === "string" ? payload.tool_name : "unknown";
|
|
@@ -3245,9 +3883,11 @@ var ClaudeHookAgentAdapter = class extends BaseAgentAdapter {
|
|
|
3245
3883
|
};
|
|
3246
3884
|
|
|
3247
3885
|
// src/adapters/agent/claude/ClaudeRemoteAgentAdapter.ts
|
|
3886
|
+
init_esm_shims();
|
|
3248
3887
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
3249
3888
|
|
|
3250
3889
|
// src/core/agent/TurnAggregator.ts
|
|
3890
|
+
init_esm_shims();
|
|
3251
3891
|
var TurnAggregator = class {
|
|
3252
3892
|
constructor(logger5, sessionId) {
|
|
3253
3893
|
this.logger = logger5;
|
|
@@ -3378,7 +4018,14 @@ var TurnAggregator = class {
|
|
|
3378
4018
|
}
|
|
3379
4019
|
};
|
|
3380
4020
|
|
|
4021
|
+
// src/core/session-scanner/index.ts
|
|
4022
|
+
init_esm_shims();
|
|
4023
|
+
|
|
4024
|
+
// src/core/session-scanner/types.ts
|
|
4025
|
+
init_esm_shims();
|
|
4026
|
+
|
|
3381
4027
|
// src/core/session-scanner/registry.ts
|
|
4028
|
+
init_esm_shims();
|
|
3382
4029
|
var SessionScannerRegistry = class _SessionScannerRegistry {
|
|
3383
4030
|
scanners = /* @__PURE__ */ new Map();
|
|
3384
4031
|
/**
|
|
@@ -3440,13 +4087,14 @@ var SessionScannerRegistry = class _SessionScannerRegistry {
|
|
|
3440
4087
|
};
|
|
3441
4088
|
|
|
3442
4089
|
// src/adapters/agent/claude/scanner.ts
|
|
3443
|
-
|
|
3444
|
-
import {
|
|
4090
|
+
init_esm_shims();
|
|
4091
|
+
import { readdir, readFile as readFile2 } from "fs/promises";
|
|
4092
|
+
import { join as join2, resolve as resolve2 } from "path";
|
|
3445
4093
|
var ClaudeSessionScanner = class {
|
|
3446
4094
|
agentType = "claude";
|
|
3447
4095
|
sessionDir;
|
|
3448
4096
|
constructor() {
|
|
3449
|
-
this.sessionDir =
|
|
4097
|
+
this.sessionDir = resolve2(process.env.HOME || "", ".claude/sessions");
|
|
3450
4098
|
}
|
|
3451
4099
|
getSessionDir() {
|
|
3452
4100
|
return this.sessionDir;
|
|
@@ -3459,7 +4107,7 @@ var ClaudeSessionScanner = class {
|
|
|
3459
4107
|
for (const file of jsonFiles) {
|
|
3460
4108
|
try {
|
|
3461
4109
|
const filePath = join2(this.sessionDir, file);
|
|
3462
|
-
const content = await
|
|
4110
|
+
const content = await readFile2(filePath, "utf-8");
|
|
3463
4111
|
const meta = JSON.parse(content);
|
|
3464
4112
|
if (!meta.sessionId) {
|
|
3465
4113
|
continue;
|
|
@@ -3469,8 +4117,9 @@ var ClaudeSessionScanner = class {
|
|
|
3469
4117
|
id: meta.sessionId,
|
|
3470
4118
|
agentType: this.agentType,
|
|
3471
4119
|
transportType: "hook",
|
|
3472
|
-
status: isActive ? "active" : "
|
|
3473
|
-
|
|
4120
|
+
status: isActive ? "active" : "archived",
|
|
4121
|
+
createdAt: meta.startedAt ?? Date.now(),
|
|
4122
|
+
updatedAt: meta.startedAt ?? Date.now(),
|
|
3474
4123
|
cwd: meta.cwd
|
|
3475
4124
|
});
|
|
3476
4125
|
} catch {
|
|
@@ -3481,23 +4130,25 @@ var ClaudeSessionScanner = class {
|
|
|
3481
4130
|
return sessions;
|
|
3482
4131
|
}
|
|
3483
4132
|
async checkProcessAlive(pid) {
|
|
3484
|
-
return new Promise((
|
|
4133
|
+
return new Promise((resolve3) => {
|
|
3485
4134
|
try {
|
|
3486
4135
|
process.kill(pid, 0);
|
|
3487
|
-
|
|
4136
|
+
resolve3(true);
|
|
3488
4137
|
} catch {
|
|
3489
|
-
|
|
4138
|
+
resolve3(false);
|
|
3490
4139
|
}
|
|
3491
4140
|
});
|
|
3492
4141
|
}
|
|
3493
4142
|
};
|
|
3494
4143
|
|
|
3495
4144
|
// src/adapters/agent/claude/sdk/query.ts
|
|
4145
|
+
init_esm_shims();
|
|
3496
4146
|
import { spawn } from "child_process";
|
|
3497
4147
|
import { createInterface } from "readline";
|
|
3498
4148
|
import { existsSync as existsSync4 } from "fs";
|
|
3499
4149
|
|
|
3500
4150
|
// src/adapters/agent/claude/sdk/stream.ts
|
|
4151
|
+
init_esm_shims();
|
|
3501
4152
|
var Stream = class {
|
|
3502
4153
|
constructor(returned) {
|
|
3503
4154
|
this.returned = returned;
|
|
@@ -3526,18 +4177,18 @@ var Stream = class {
|
|
|
3526
4177
|
if (this.hasError) {
|
|
3527
4178
|
return Promise.reject(this.hasError);
|
|
3528
4179
|
}
|
|
3529
|
-
return new Promise((
|
|
3530
|
-
this.readResolve =
|
|
4180
|
+
return new Promise((resolve3, reject) => {
|
|
4181
|
+
this.readResolve = resolve3;
|
|
3531
4182
|
this.readReject = reject;
|
|
3532
4183
|
});
|
|
3533
4184
|
}
|
|
3534
4185
|
enqueue(value) {
|
|
3535
4186
|
if (this.isDone || this.hasError) return;
|
|
3536
4187
|
if (this.readResolve) {
|
|
3537
|
-
const
|
|
4188
|
+
const resolve3 = this.readResolve;
|
|
3538
4189
|
this.readResolve = void 0;
|
|
3539
4190
|
this.readReject = void 0;
|
|
3540
|
-
|
|
4191
|
+
resolve3({ done: false, value });
|
|
3541
4192
|
} else {
|
|
3542
4193
|
this.queue.push(value);
|
|
3543
4194
|
}
|
|
@@ -3546,10 +4197,10 @@ var Stream = class {
|
|
|
3546
4197
|
if (this.isDone || this.hasError) return;
|
|
3547
4198
|
this.isDone = true;
|
|
3548
4199
|
if (this.readResolve) {
|
|
3549
|
-
const
|
|
4200
|
+
const resolve3 = this.readResolve;
|
|
3550
4201
|
this.readResolve = void 0;
|
|
3551
4202
|
this.readReject = void 0;
|
|
3552
|
-
|
|
4203
|
+
resolve3({ done: true, value: void 0 });
|
|
3553
4204
|
}
|
|
3554
4205
|
}
|
|
3555
4206
|
error(error2) {
|
|
@@ -3572,6 +4223,7 @@ var Stream = class {
|
|
|
3572
4223
|
};
|
|
3573
4224
|
|
|
3574
4225
|
// src/adapters/agent/claude/sdk/types.ts
|
|
4226
|
+
init_esm_shims();
|
|
3575
4227
|
var AbortError = class extends Error {
|
|
3576
4228
|
constructor(message) {
|
|
3577
4229
|
super(message);
|
|
@@ -3726,10 +4378,10 @@ var Query = class {
|
|
|
3726
4378
|
type: "control_request",
|
|
3727
4379
|
request
|
|
3728
4380
|
};
|
|
3729
|
-
return new Promise((
|
|
4381
|
+
return new Promise((resolve3, reject) => {
|
|
3730
4382
|
this.pendingControlResponses.set(requestId, (response) => {
|
|
3731
4383
|
if (response.subtype === "success") {
|
|
3732
|
-
|
|
4384
|
+
resolve3(response);
|
|
3733
4385
|
} else {
|
|
3734
4386
|
reject(new Error(response.error));
|
|
3735
4387
|
}
|
|
@@ -3880,7 +4532,7 @@ function query(config) {
|
|
|
3880
4532
|
if (abort?.aborted) break;
|
|
3881
4533
|
const data = JSON.stringify(msg) + "\n";
|
|
3882
4534
|
if (!child.stdin.write(data)) {
|
|
3883
|
-
await new Promise((
|
|
4535
|
+
await new Promise((resolve3) => child.stdin.once("drain", resolve3));
|
|
3884
4536
|
}
|
|
3885
4537
|
}
|
|
3886
4538
|
} finally {
|
|
@@ -3893,14 +4545,14 @@ function query(config) {
|
|
|
3893
4545
|
if (!child.killed) child.kill("SIGTERM");
|
|
3894
4546
|
};
|
|
3895
4547
|
abort?.addEventListener("abort", cleanup);
|
|
3896
|
-
const processExitPromise = new Promise((
|
|
4548
|
+
const processExitPromise = new Promise((resolve3) => {
|
|
3897
4549
|
child.on("close", (code) => {
|
|
3898
4550
|
if (abort?.aborted) {
|
|
3899
4551
|
q.setError(new AbortError("Claude Code process aborted by user"));
|
|
3900
4552
|
} else if (code !== 0 && code !== null) {
|
|
3901
4553
|
q.setError(new Error(`Claude Code process exited with code ${code}`));
|
|
3902
4554
|
} else {
|
|
3903
|
-
|
|
4555
|
+
resolve3();
|
|
3904
4556
|
}
|
|
3905
4557
|
});
|
|
3906
4558
|
});
|
|
@@ -3928,8 +4580,8 @@ var PushableAsyncIterable = class {
|
|
|
3928
4580
|
push(value) {
|
|
3929
4581
|
if (this.ended) return;
|
|
3930
4582
|
if (this.resolvers.length > 0) {
|
|
3931
|
-
const
|
|
3932
|
-
|
|
4583
|
+
const resolve3 = this.resolvers.shift();
|
|
4584
|
+
resolve3({ done: false, value });
|
|
3933
4585
|
} else {
|
|
3934
4586
|
this.queue.push(value);
|
|
3935
4587
|
}
|
|
@@ -3937,8 +4589,8 @@ var PushableAsyncIterable = class {
|
|
|
3937
4589
|
end() {
|
|
3938
4590
|
this.ended = true;
|
|
3939
4591
|
while (this.resolvers.length > 0) {
|
|
3940
|
-
const
|
|
3941
|
-
|
|
4592
|
+
const resolve3 = this.resolvers.shift();
|
|
4593
|
+
resolve3({ done: true, value: void 0 });
|
|
3942
4594
|
}
|
|
3943
4595
|
}
|
|
3944
4596
|
[Symbol.asyncIterator]() {
|
|
@@ -3950,8 +4602,8 @@ var PushableAsyncIterable = class {
|
|
|
3950
4602
|
if (this.ended) {
|
|
3951
4603
|
return Promise.resolve({ done: true, value: void 0 });
|
|
3952
4604
|
}
|
|
3953
|
-
return new Promise((
|
|
3954
|
-
this.resolvers.push(
|
|
4605
|
+
return new Promise((resolve3) => {
|
|
4606
|
+
this.resolvers.push(resolve3);
|
|
3955
4607
|
});
|
|
3956
4608
|
},
|
|
3957
4609
|
return: () => {
|
|
@@ -3975,6 +4627,8 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
3975
4627
|
defaultModel;
|
|
3976
4628
|
defaultPermissionMode;
|
|
3977
4629
|
static VALID_PERMISSION_MODES = ["default", "acceptEdits", "bypassPermissions", "plan"];
|
|
4630
|
+
/** Maps sender.id → real Claude session_id for stable multi-turn sessions */
|
|
4631
|
+
senderSessionMap = /* @__PURE__ */ new Map();
|
|
3978
4632
|
constructor(options) {
|
|
3979
4633
|
super({ bus: options.bus, bridge: options.bridge, logger: options.logger });
|
|
3980
4634
|
this.token = options.token;
|
|
@@ -4025,6 +4679,13 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4025
4679
|
this.logger.info("Claude session scanner registered");
|
|
4026
4680
|
}
|
|
4027
4681
|
}
|
|
4682
|
+
/**
|
|
4683
|
+
* Return the real Claude session_id if this sender already has an active session.
|
|
4684
|
+
* This makes multi-turn conversations stable across turns.
|
|
4685
|
+
*/
|
|
4686
|
+
resolveSessionId(message) {
|
|
4687
|
+
return this.senderSessionMap.get(message.sender.id);
|
|
4688
|
+
}
|
|
4028
4689
|
async createTransportState(opts) {
|
|
4029
4690
|
const sessionId = opts.sessionId ?? `claude-${randomUUID2().slice(0, 8)}`;
|
|
4030
4691
|
const chatId = opts.chatId ?? sessionId;
|
|
@@ -4058,7 +4719,9 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4058
4719
|
turnInProgress: false,
|
|
4059
4720
|
chatId,
|
|
4060
4721
|
channel,
|
|
4061
|
-
cwd
|
|
4722
|
+
cwd,
|
|
4723
|
+
permissionMode: this.defaultPermissionMode,
|
|
4724
|
+
senderId: opts.metadata?.senderId
|
|
4062
4725
|
};
|
|
4063
4726
|
this.transports.set(sessionId, state);
|
|
4064
4727
|
this.emitEvent(EventNormalizer.sessionStart(sessionId, this.agentType, this.transportType, {
|
|
@@ -4067,7 +4730,7 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4067
4730
|
cwd,
|
|
4068
4731
|
...opts.metadata
|
|
4069
4732
|
}));
|
|
4070
|
-
this.consumeQueryMessages(q,
|
|
4733
|
+
this.consumeQueryMessages(q, state).catch((err) => {
|
|
4071
4734
|
this.logger.error({ sessionId, error: err }, "Query consumer error");
|
|
4072
4735
|
});
|
|
4073
4736
|
this.logger.info({ sessionId }, "Claude remote transport state created");
|
|
@@ -4081,6 +4744,9 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4081
4744
|
remoteState.query.kill("SIGTERM");
|
|
4082
4745
|
remoteState.aggregator.reset();
|
|
4083
4746
|
this.transports.delete(sessionId);
|
|
4747
|
+
if (remoteState.senderId) {
|
|
4748
|
+
this.senderSessionMap.delete(remoteState.senderId);
|
|
4749
|
+
}
|
|
4084
4750
|
this.emitEvent(EventNormalizer.sessionEnd(sessionId, this.agentType, this.transportType, "close"));
|
|
4085
4751
|
}
|
|
4086
4752
|
async sendCommand(state, command) {
|
|
@@ -4122,13 +4788,13 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4122
4788
|
}
|
|
4123
4789
|
}
|
|
4124
4790
|
// === Internal ===
|
|
4125
|
-
async consumeQueryMessages(q,
|
|
4791
|
+
async consumeQueryMessages(q, state) {
|
|
4126
4792
|
try {
|
|
4127
4793
|
for await (const msg of q) {
|
|
4128
|
-
await this.handleSdkMessage(msg,
|
|
4794
|
+
await this.handleSdkMessage(msg, state);
|
|
4129
4795
|
}
|
|
4130
4796
|
} catch (err) {
|
|
4131
|
-
this.logger.error({ sessionId, error: err }, "Claude remote stream ended with error");
|
|
4797
|
+
this.logger.error({ sessionId: state.sessionId, error: err }, "Claude remote stream ended with error");
|
|
4132
4798
|
this.bus.publishOutbound({
|
|
4133
4799
|
channel: state.channel,
|
|
4134
4800
|
chatId: state.chatId,
|
|
@@ -4137,16 +4803,35 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4137
4803
|
} finally {
|
|
4138
4804
|
state.aggregator.reset();
|
|
4139
4805
|
state.turnInProgress = false;
|
|
4140
|
-
this.transports.delete(sessionId);
|
|
4141
|
-
this.emitEvent(EventNormalizer.sessionEnd(sessionId, this.agentType, this.transportType, "stream_ended"));
|
|
4806
|
+
this.transports.delete(state.sessionId);
|
|
4807
|
+
this.emitEvent(EventNormalizer.sessionEnd(state.sessionId, this.agentType, this.transportType, "stream_ended"));
|
|
4142
4808
|
}
|
|
4143
4809
|
}
|
|
4144
|
-
async handleSdkMessage(msg,
|
|
4810
|
+
async handleSdkMessage(msg, state) {
|
|
4811
|
+
const sessionId = state.sessionId;
|
|
4145
4812
|
switch (msg.type) {
|
|
4146
4813
|
case "system": {
|
|
4147
4814
|
const system = msg;
|
|
4148
4815
|
if (system.subtype === "init" && system.session_id) {
|
|
4149
|
-
|
|
4816
|
+
const claudeSessionId = system.session_id;
|
|
4817
|
+
this.logger.info({ sessionId, claudeSessionId }, "Claude session initialized");
|
|
4818
|
+
if (claudeSessionId !== sessionId) {
|
|
4819
|
+
const renamed = this.bridge.renameSessionId(sessionId, claudeSessionId);
|
|
4820
|
+
if (renamed) {
|
|
4821
|
+
this.transports.delete(sessionId);
|
|
4822
|
+
state.sessionId = claudeSessionId;
|
|
4823
|
+
this.transports.set(claudeSessionId, state);
|
|
4824
|
+
this.logger.info({ oldId: sessionId, newId: claudeSessionId }, "Session renamed to Claude session_id");
|
|
4825
|
+
}
|
|
4826
|
+
}
|
|
4827
|
+
this.bridge.updateSessionInfo(claudeSessionId, {
|
|
4828
|
+
model: system.model,
|
|
4829
|
+
slashCommands: system.slash_commands,
|
|
4830
|
+
permissionMode: state.permissionMode
|
|
4831
|
+
});
|
|
4832
|
+
if (state.senderId) {
|
|
4833
|
+
this.senderSessionMap.set(state.senderId, claudeSessionId);
|
|
4834
|
+
}
|
|
4150
4835
|
}
|
|
4151
4836
|
break;
|
|
4152
4837
|
}
|
|
@@ -4199,7 +4884,9 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4199
4884
|
durationMs: result.duration_ms,
|
|
4200
4885
|
usage: result.usage ? {
|
|
4201
4886
|
inputTokens: result.usage.input_tokens,
|
|
4202
|
-
outputTokens: result.usage.output_tokens
|
|
4887
|
+
outputTokens: result.usage.output_tokens,
|
|
4888
|
+
cacheReadInputTokens: result.usage.cache_read_input_tokens,
|
|
4889
|
+
cacheCreationInputTokens: result.usage.cache_creation_input_tokens
|
|
4203
4890
|
} : void 0
|
|
4204
4891
|
})
|
|
4205
4892
|
);
|
|
@@ -4218,6 +4905,18 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4218
4905
|
}
|
|
4219
4906
|
}
|
|
4220
4907
|
}
|
|
4908
|
+
/**
|
|
4909
|
+
* Handle tool permission requests from the Claude SDK.
|
|
4910
|
+
*
|
|
4911
|
+
* The SDK calls this callback when Claude wants to run a tool. We block
|
|
4912
|
+
* the Promise until the user responds via a channel (Feishu/Telegram).
|
|
4913
|
+
*
|
|
4914
|
+
* Resolution values:
|
|
4915
|
+
* - allow → { behavior: 'allow', updatedInput? }
|
|
4916
|
+
* - deny → { behavior: 'deny', message }
|
|
4917
|
+
*
|
|
4918
|
+
* See file header for full flow diagram.
|
|
4919
|
+
*/
|
|
4221
4920
|
async handleCanCallTool(sessionId, toolName, toolInput, signal) {
|
|
4222
4921
|
const state = this.transports.get(sessionId);
|
|
4223
4922
|
if (!state) {
|
|
@@ -4234,14 +4933,14 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4234
4933
|
toolInput: toolInput ?? {},
|
|
4235
4934
|
timestamp: Date.now()
|
|
4236
4935
|
};
|
|
4237
|
-
return new Promise((
|
|
4936
|
+
return new Promise((resolve3) => {
|
|
4238
4937
|
const timeout = setTimeout(() => {
|
|
4239
4938
|
this.logger.warn({ sessionId, requestId }, "Permission request timeout");
|
|
4240
|
-
|
|
4939
|
+
resolve3({ behavior: "deny", message: "Timeout" });
|
|
4241
4940
|
}, _ClaudeRemoteAgentAdapter.CONTROL_REQUEST_TIMEOUT_MS);
|
|
4242
4941
|
const onAbort = () => {
|
|
4243
4942
|
clearTimeout(timeout);
|
|
4244
|
-
|
|
4943
|
+
resolve3({ behavior: "deny", message: "Aborted" });
|
|
4245
4944
|
};
|
|
4246
4945
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
4247
4946
|
evaluateInteraction(this.bridge, interactionRequest).then((response) => {
|
|
@@ -4249,7 +4948,7 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4249
4948
|
signal.removeEventListener("abort", onAbort);
|
|
4250
4949
|
const decision = response.action === "allow" ? "allow" : "deny";
|
|
4251
4950
|
this.logger.info({ sessionId, requestId, toolName, decision }, "Claude remote permission resolved");
|
|
4252
|
-
|
|
4951
|
+
resolve3({
|
|
4253
4952
|
behavior: decision,
|
|
4254
4953
|
updatedInput: response.updatedInput,
|
|
4255
4954
|
...decision === "deny" ? { message: "User denied this tool call" } : {}
|
|
@@ -4258,10 +4957,25 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4258
4957
|
clearTimeout(timeout);
|
|
4259
4958
|
signal.removeEventListener("abort", onAbort);
|
|
4260
4959
|
this.logger.error({ error: err, sessionId, requestId }, "Claude remote permission handler error");
|
|
4261
|
-
|
|
4960
|
+
resolve3({ behavior: "deny", message: "Error" });
|
|
4262
4961
|
});
|
|
4263
4962
|
});
|
|
4264
4963
|
}
|
|
4964
|
+
/**
|
|
4965
|
+
* Handle question requests from the Claude SDK (AskUserQuestion tool).
|
|
4966
|
+
*
|
|
4967
|
+
* The SDK calls this callback when Claude runs AskUserQuestion. We block
|
|
4968
|
+
* the Promise until the user selects an answer via a channel.
|
|
4969
|
+
*
|
|
4970
|
+
* For multi-select questions, the interaction-utils wraps the response
|
|
4971
|
+
* with updatedInput containing { answers: { [questionText]: answerValue } }.
|
|
4972
|
+
*
|
|
4973
|
+
* Resolution values:
|
|
4974
|
+
* - answer → { action: 'answer', answer: string }
|
|
4975
|
+
* - deny → { action: 'deny', message }
|
|
4976
|
+
*
|
|
4977
|
+
* See file header for full flow diagram.
|
|
4978
|
+
*/
|
|
4265
4979
|
async handleCanAnswerQuestion(sessionId, question, signal) {
|
|
4266
4980
|
const state = this.transports.get(sessionId);
|
|
4267
4981
|
if (!state) {
|
|
@@ -4278,40 +4992,41 @@ var ClaudeRemoteAgentAdapter = class _ClaudeRemoteAgentAdapter extends BaseAgent
|
|
|
4278
4992
|
toolInput: { questions: [{ question }] },
|
|
4279
4993
|
timestamp: Date.now()
|
|
4280
4994
|
};
|
|
4281
|
-
return new Promise((
|
|
4995
|
+
return new Promise((resolve3) => {
|
|
4282
4996
|
const timeout = setTimeout(() => {
|
|
4283
4997
|
this.logger.warn({ sessionId, requestId }, "Question request timeout");
|
|
4284
|
-
|
|
4998
|
+
resolve3({ action: "deny", message: "Timeout" });
|
|
4285
4999
|
}, _ClaudeRemoteAgentAdapter.CONTROL_REQUEST_TIMEOUT_MS);
|
|
4286
5000
|
const onAbort = () => {
|
|
4287
5001
|
clearTimeout(timeout);
|
|
4288
|
-
|
|
5002
|
+
resolve3({ action: "deny", message: "Aborted" });
|
|
4289
5003
|
};
|
|
4290
5004
|
signal.addEventListener("abort", onAbort, { once: true });
|
|
4291
5005
|
evaluateInteraction(this.bridge, interactionRequest).then((response) => {
|
|
4292
5006
|
clearTimeout(timeout);
|
|
4293
5007
|
signal.removeEventListener("abort", onAbort);
|
|
4294
5008
|
if (!response) {
|
|
4295
|
-
|
|
5009
|
+
resolve3({ action: "deny", message: "No response" });
|
|
4296
5010
|
return;
|
|
4297
5011
|
}
|
|
4298
5012
|
if (response.action === "allow" || response.action === "select") {
|
|
4299
5013
|
const answer = response.selectedValues?.[0] ?? response.customInput ?? "";
|
|
4300
|
-
|
|
5014
|
+
resolve3({ action: "answer", answer: String(answer) });
|
|
4301
5015
|
} else {
|
|
4302
|
-
|
|
5016
|
+
resolve3({ action: "deny", message: response.message ?? "User denied" });
|
|
4303
5017
|
}
|
|
4304
5018
|
}).catch((err) => {
|
|
4305
5019
|
clearTimeout(timeout);
|
|
4306
5020
|
signal.removeEventListener("abort", onAbort);
|
|
4307
5021
|
this.logger.error({ error: err, sessionId, requestId }, "Claude remote question handler error");
|
|
4308
|
-
|
|
5022
|
+
resolve3({ action: "deny", message: "Error" });
|
|
4309
5023
|
});
|
|
4310
5024
|
});
|
|
4311
5025
|
}
|
|
4312
5026
|
};
|
|
4313
5027
|
|
|
4314
5028
|
// src/adapters/agent/claude/hook-types.ts
|
|
5029
|
+
init_esm_shims();
|
|
4315
5030
|
var VALID_CLAUDE_EVENTS = [
|
|
4316
5031
|
"SessionStart",
|
|
4317
5032
|
"SessionEnd",
|
|
@@ -4325,10 +5040,15 @@ function isClaudeHookEventType(eventType) {
|
|
|
4325
5040
|
return VALID_CLAUDE_EVENTS.includes(eventType);
|
|
4326
5041
|
}
|
|
4327
5042
|
|
|
5043
|
+
// src/adapters/agent/codex/index.ts
|
|
5044
|
+
init_esm_shims();
|
|
5045
|
+
|
|
4328
5046
|
// src/adapters/agent/codex/CodexAppAgentAdapter.ts
|
|
5047
|
+
init_esm_shims();
|
|
4329
5048
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
4330
5049
|
|
|
4331
5050
|
// src/adapters/agent/codex/codexAppServerClient.ts
|
|
5051
|
+
init_esm_shims();
|
|
4332
5052
|
import { spawn as spawn2, execFileSync } from "child_process";
|
|
4333
5053
|
import { createInterface as createInterface2 } from "readline";
|
|
4334
5054
|
function isAppServerAvailable(command = "codex") {
|
|
@@ -4348,8 +5068,8 @@ function normalizeRawFileChangeList(changes) {
|
|
|
4348
5068
|
if (!change || typeof change !== "object" || Array.isArray(change)) {
|
|
4349
5069
|
continue;
|
|
4350
5070
|
}
|
|
4351
|
-
const
|
|
4352
|
-
if (!
|
|
5071
|
+
const path3 = typeof change.path === "string" ? change.path : null;
|
|
5072
|
+
if (!path3) {
|
|
4353
5073
|
continue;
|
|
4354
5074
|
}
|
|
4355
5075
|
const entry = {};
|
|
@@ -4359,7 +5079,7 @@ function normalizeRawFileChangeList(changes) {
|
|
|
4359
5079
|
if (change.kind && typeof change.kind === "object" && !Array.isArray(change.kind)) {
|
|
4360
5080
|
entry.kind = change.kind;
|
|
4361
5081
|
}
|
|
4362
|
-
normalized[
|
|
5082
|
+
normalized[path3] = entry;
|
|
4363
5083
|
}
|
|
4364
5084
|
return Object.keys(normalized).length > 0 ? normalized : void 0;
|
|
4365
5085
|
}
|
|
@@ -4821,7 +5541,7 @@ var CodexAppServerClient = class _CodexAppServerClient {
|
|
|
4821
5541
|
if (Date.now() >= deadline) {
|
|
4822
5542
|
return false;
|
|
4823
5543
|
}
|
|
4824
|
-
await new Promise((
|
|
5544
|
+
await new Promise((resolve3) => setTimeout(resolve3, 25));
|
|
4825
5545
|
}
|
|
4826
5546
|
return true;
|
|
4827
5547
|
}
|
|
@@ -4894,13 +5614,13 @@ var CodexAppServerClient = class _CodexAppServerClient {
|
|
|
4894
5614
|
async sendTurnAndWait(prompt, opts) {
|
|
4895
5615
|
if (this.pendingInterrupt) {
|
|
4896
5616
|
await this.pendingInterrupt;
|
|
4897
|
-
await new Promise((
|
|
5617
|
+
await new Promise((resolve3) => setTimeout(resolve3, 0));
|
|
4898
5618
|
}
|
|
4899
5619
|
const timeoutMs = opts?.turnTimeoutMs ?? _CodexAppServerClient.TURN_TIMEOUT_MS;
|
|
4900
5620
|
let timer = null;
|
|
4901
|
-
const completion = new Promise((
|
|
5621
|
+
const completion = new Promise((resolve3) => {
|
|
4902
5622
|
this.pendingTurnCompletion = {
|
|
4903
|
-
resolve:
|
|
5623
|
+
resolve: resolve3,
|
|
4904
5624
|
started: false,
|
|
4905
5625
|
turnId: null
|
|
4906
5626
|
};
|
|
@@ -4951,7 +5671,7 @@ var CodexAppServerClient = class _CodexAppServerClient {
|
|
|
4951
5671
|
static REQUEST_TIMEOUT_MS = 3e4;
|
|
4952
5672
|
request(method, params, timeoutMs) {
|
|
4953
5673
|
const timeout = timeoutMs ?? _CodexAppServerClient.REQUEST_TIMEOUT_MS;
|
|
4954
|
-
return new Promise((
|
|
5674
|
+
return new Promise((resolve3, reject) => {
|
|
4955
5675
|
if (!this.process?.stdin?.writable) {
|
|
4956
5676
|
reject(new Error(`Cannot send ${method}: stdin not writable`));
|
|
4957
5677
|
return;
|
|
@@ -4964,7 +5684,7 @@ var CodexAppServerClient = class _CodexAppServerClient {
|
|
|
4964
5684
|
this.pending.set(id, {
|
|
4965
5685
|
resolve: (result) => {
|
|
4966
5686
|
clearTimeout(timer);
|
|
4967
|
-
|
|
5687
|
+
resolve3(result);
|
|
4968
5688
|
},
|
|
4969
5689
|
reject: (err) => {
|
|
4970
5690
|
clearTimeout(timer);
|
|
@@ -5417,8 +6137,12 @@ var CodexAppAgentAdapter = class extends BaseAgentAdapter {
|
|
|
5417
6137
|
}
|
|
5418
6138
|
};
|
|
5419
6139
|
|
|
6140
|
+
// src/adapters/agent/codex/codexAppServerTypes.ts
|
|
6141
|
+
init_esm_shims();
|
|
6142
|
+
|
|
5420
6143
|
// src/shared/persistence.ts
|
|
5421
|
-
|
|
6144
|
+
init_esm_shims();
|
|
6145
|
+
import { appendFile, mkdir, readdir as readdir2, readFile as readFile3 } from "fs/promises";
|
|
5422
6146
|
import { readdirSync, statSync } from "fs";
|
|
5423
6147
|
import { join as join3 } from "path";
|
|
5424
6148
|
import { existsSync as existsSync5 } from "fs";
|
|
@@ -5458,7 +6182,7 @@ var Persistence = class {
|
|
|
5458
6182
|
const fileName = files.find((f) => f.endsWith(`-${sessionId}.jsonl`));
|
|
5459
6183
|
if (fileName) {
|
|
5460
6184
|
const filePath = join3(dirPath, fileName);
|
|
5461
|
-
const content = await
|
|
6185
|
+
const content = await readFile3(filePath, "utf-8");
|
|
5462
6186
|
const lines = content.trim().split("\n").filter((line) => line.length > 0);
|
|
5463
6187
|
for (const line of lines) {
|
|
5464
6188
|
try {
|
|
@@ -5509,6 +6233,7 @@ var Persistence = class {
|
|
|
5509
6233
|
};
|
|
5510
6234
|
|
|
5511
6235
|
// src/server/http.ts
|
|
6236
|
+
init_esm_shims();
|
|
5512
6237
|
import { createServer } from "http";
|
|
5513
6238
|
import { URL } from "url";
|
|
5514
6239
|
var VERSION = "0.1.0";
|
|
@@ -5524,19 +6249,19 @@ var HttpServer = class {
|
|
|
5524
6249
|
/**
|
|
5525
6250
|
* Register a route handler
|
|
5526
6251
|
*/
|
|
5527
|
-
registerRoute(method,
|
|
5528
|
-
this.routes.push({ method: method.toUpperCase(), path:
|
|
5529
|
-
logger2.debug(`Registered route: ${method} ${
|
|
6252
|
+
registerRoute(method, path3, handler) {
|
|
6253
|
+
this.routes.push({ method: method.toUpperCase(), path: path3, handler });
|
|
6254
|
+
logger2.debug(`Registered route: ${method} ${path3}`);
|
|
5530
6255
|
}
|
|
5531
6256
|
/**
|
|
5532
6257
|
* Register a WebSocket upgrade handler for a specific path
|
|
5533
6258
|
*/
|
|
5534
|
-
onUpgrade(
|
|
5535
|
-
this.upgradeHandlers.set(
|
|
5536
|
-
logger2.debug(`Registered upgrade handler: ${
|
|
6259
|
+
onUpgrade(path3, handler) {
|
|
6260
|
+
this.upgradeHandlers.set(path3, handler);
|
|
6261
|
+
logger2.debug(`Registered upgrade handler: ${path3}`);
|
|
5537
6262
|
return () => {
|
|
5538
|
-
this.upgradeHandlers.delete(
|
|
5539
|
-
logger2.debug(`Unregistered upgrade handler: ${
|
|
6263
|
+
this.upgradeHandlers.delete(path3);
|
|
6264
|
+
logger2.debug(`Unregistered upgrade handler: ${path3}`);
|
|
5540
6265
|
};
|
|
5541
6266
|
}
|
|
5542
6267
|
/**
|
|
@@ -5553,10 +6278,10 @@ var HttpServer = class {
|
|
|
5553
6278
|
socket.destroy();
|
|
5554
6279
|
}
|
|
5555
6280
|
});
|
|
5556
|
-
return new Promise((
|
|
6281
|
+
return new Promise((resolve3, reject) => {
|
|
5557
6282
|
this.server?.listen(this.port, () => {
|
|
5558
6283
|
logger2.info(`HTTP server listening on port ${this.port}`);
|
|
5559
|
-
|
|
6284
|
+
resolve3();
|
|
5560
6285
|
});
|
|
5561
6286
|
this.server?.on("error", reject);
|
|
5562
6287
|
});
|
|
@@ -5565,10 +6290,10 @@ var HttpServer = class {
|
|
|
5565
6290
|
* Stop the HTTP server
|
|
5566
6291
|
*/
|
|
5567
6292
|
async stop() {
|
|
5568
|
-
return new Promise((
|
|
6293
|
+
return new Promise((resolve3) => {
|
|
5569
6294
|
this.server?.close(() => {
|
|
5570
6295
|
logger2.info("HTTP server stopped");
|
|
5571
|
-
|
|
6296
|
+
resolve3();
|
|
5572
6297
|
});
|
|
5573
6298
|
});
|
|
5574
6299
|
}
|
|
@@ -5612,7 +6337,7 @@ var HttpServer = class {
|
|
|
5612
6337
|
}
|
|
5613
6338
|
};
|
|
5614
6339
|
function parseJsonBody(req) {
|
|
5615
|
-
return new Promise((
|
|
6340
|
+
return new Promise((resolve3, reject) => {
|
|
5616
6341
|
let body = "";
|
|
5617
6342
|
req.on("data", (chunk) => {
|
|
5618
6343
|
body += chunk.toString();
|
|
@@ -5620,10 +6345,10 @@ function parseJsonBody(req) {
|
|
|
5620
6345
|
req.on("end", () => {
|
|
5621
6346
|
try {
|
|
5622
6347
|
if (!body) {
|
|
5623
|
-
|
|
6348
|
+
resolve3({});
|
|
5624
6349
|
return;
|
|
5625
6350
|
}
|
|
5626
|
-
|
|
6351
|
+
resolve3(JSON.parse(body));
|
|
5627
6352
|
} catch (error2) {
|
|
5628
6353
|
reject(error2);
|
|
5629
6354
|
}
|
|
@@ -5702,7 +6427,7 @@ function setupRoutes(httpServer, gateway, getClientCount) {
|
|
|
5702
6427
|
sessionId: s.id,
|
|
5703
6428
|
agentType: s.agentType,
|
|
5704
6429
|
status: s.status,
|
|
5705
|
-
startedAt: s.
|
|
6430
|
+
startedAt: new Date(s.createdAt).toISOString(),
|
|
5706
6431
|
updatedAt: new Date(s.updatedAt).toISOString()
|
|
5707
6432
|
})),
|
|
5708
6433
|
clients: getClientCount()
|
|
@@ -5807,6 +6532,7 @@ function setupRoutes(httpServer, gateway, getClientCount) {
|
|
|
5807
6532
|
}
|
|
5808
6533
|
|
|
5809
6534
|
// src/server/websocket.ts
|
|
6535
|
+
init_esm_shims();
|
|
5810
6536
|
import { WebSocketServer as WSWebSocketServer, WebSocket } from "ws";
|
|
5811
6537
|
import { URL as URL2 } from "url";
|
|
5812
6538
|
var VERSION2 = "0.1.0";
|
|
@@ -5835,13 +6561,13 @@ var WebSocketServer = class {
|
|
|
5835
6561
|
this.wss = new WSWebSocketServer({ noServer: true });
|
|
5836
6562
|
this.setupConnectionHandlers();
|
|
5837
6563
|
this.startHeartbeat();
|
|
5838
|
-
const
|
|
5839
|
-
this.httpServer.onUpgrade(
|
|
6564
|
+
const path3 = this.options.path || "/ws";
|
|
6565
|
+
this.httpServer.onUpgrade(path3, (request, socket, head) => {
|
|
5840
6566
|
this.wss?.handleUpgrade(request, socket, head, (ws) => {
|
|
5841
6567
|
this.wss?.emit("connection", ws, request);
|
|
5842
6568
|
});
|
|
5843
6569
|
});
|
|
5844
|
-
logger3.info(`WebSocket server registered on path: ${
|
|
6570
|
+
logger3.info(`WebSocket server registered on path: ${path3}`);
|
|
5845
6571
|
}
|
|
5846
6572
|
/**
|
|
5847
6573
|
* Stop the WebSocket server
|
|
@@ -5852,10 +6578,10 @@ var WebSocketServer = class {
|
|
|
5852
6578
|
this.heartbeatInterval = null;
|
|
5853
6579
|
}
|
|
5854
6580
|
this.closeAll();
|
|
5855
|
-
return new Promise((
|
|
6581
|
+
return new Promise((resolve3) => {
|
|
5856
6582
|
this.wss?.close(() => {
|
|
5857
6583
|
logger3.info("WebSocket server stopped");
|
|
5858
|
-
|
|
6584
|
+
resolve3();
|
|
5859
6585
|
});
|
|
5860
6586
|
});
|
|
5861
6587
|
}
|
|
@@ -6071,7 +6797,7 @@ function setupWebSocketHandlers(wsServer, gateway, options = {}) {
|
|
|
6071
6797
|
id: s.id,
|
|
6072
6798
|
agentType: s.agentType,
|
|
6073
6799
|
status: s.status,
|
|
6074
|
-
startedAt: s.
|
|
6800
|
+
startedAt: new Date(s.createdAt).toISOString(),
|
|
6075
6801
|
updatedAt: new Date(s.updatedAt).toISOString()
|
|
6076
6802
|
}))
|
|
6077
6803
|
}
|
|
@@ -6133,6 +6859,7 @@ function broadcastEvent(wsServer, frame) {
|
|
|
6133
6859
|
}
|
|
6134
6860
|
|
|
6135
6861
|
// src/shared/credentials.ts
|
|
6862
|
+
init_esm_shims();
|
|
6136
6863
|
import { readFileSync as readFileSync3, writeFileSync as writeFileSync2, existsSync as existsSync6, mkdirSync as mkdirSync3 } from "fs";
|
|
6137
6864
|
import { join as join4, dirname as dirname4 } from "path";
|
|
6138
6865
|
import { homedir } from "os";
|
|
@@ -6140,15 +6867,15 @@ function getCredentialsPath() {
|
|
|
6140
6867
|
return join4(homedir(), ".handsoff", "credentials.json");
|
|
6141
6868
|
}
|
|
6142
6869
|
function loadCredentials() {
|
|
6143
|
-
const
|
|
6144
|
-
if (!existsSync6(
|
|
6870
|
+
const path3 = getCredentialsPath();
|
|
6871
|
+
if (!existsSync6(path3)) {
|
|
6145
6872
|
return null;
|
|
6146
6873
|
}
|
|
6147
6874
|
try {
|
|
6148
|
-
const content = readFileSync3(
|
|
6875
|
+
const content = readFileSync3(path3, "utf-8");
|
|
6149
6876
|
return JSON.parse(content);
|
|
6150
6877
|
} catch (error2) {
|
|
6151
|
-
console.error(`Failed to load credentials from ${
|
|
6878
|
+
console.error(`Failed to load credentials from ${path3}:`, error2);
|
|
6152
6879
|
return null;
|
|
6153
6880
|
}
|
|
6154
6881
|
}
|
|
@@ -6156,7 +6883,14 @@ function getHookToken() {
|
|
|
6156
6883
|
return loadCredentials()?.hookToken ?? null;
|
|
6157
6884
|
}
|
|
6158
6885
|
|
|
6886
|
+
// src/adapters/interaction/index.ts
|
|
6887
|
+
init_esm_shims();
|
|
6888
|
+
|
|
6889
|
+
// src/adapters/interaction/types.ts
|
|
6890
|
+
init_esm_shims();
|
|
6891
|
+
|
|
6159
6892
|
// src/adapters/interaction/queue.ts
|
|
6893
|
+
init_esm_shims();
|
|
6160
6894
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
6161
6895
|
var InteractionQueue = class {
|
|
6162
6896
|
pending = /* @__PURE__ */ new Map();
|
|
@@ -6168,13 +6902,13 @@ var InteractionQueue = class {
|
|
|
6168
6902
|
}
|
|
6169
6903
|
request(request) {
|
|
6170
6904
|
const requestId = randomUUID4();
|
|
6171
|
-
const responsePromise = new Promise((
|
|
6905
|
+
const responsePromise = new Promise((resolve3, reject) => {
|
|
6172
6906
|
const timeoutId = setTimeout(() => {
|
|
6173
6907
|
this.pending.delete(requestId);
|
|
6174
6908
|
getLogger().info(
|
|
6175
6909
|
`[Interaction] Timeout: ${request.toolName} | requestId=${requestId} | default=${this.defaultOnTimeout}`
|
|
6176
6910
|
);
|
|
6177
|
-
|
|
6911
|
+
resolve3({
|
|
6178
6912
|
requestId,
|
|
6179
6913
|
action: this.defaultOnTimeout,
|
|
6180
6914
|
message: `Interaction request timed out after ${this.timeoutMs}ms`
|
|
@@ -6191,7 +6925,7 @@ var InteractionQueue = class {
|
|
|
6191
6925
|
resolve: (response) => {
|
|
6192
6926
|
clearTimeout(timeoutId);
|
|
6193
6927
|
this.pending.delete(requestId);
|
|
6194
|
-
|
|
6928
|
+
resolve3(response);
|
|
6195
6929
|
},
|
|
6196
6930
|
reject: (error2) => {
|
|
6197
6931
|
clearTimeout(timeoutId);
|
|
@@ -6260,6 +6994,7 @@ var InteractionQueue = class {
|
|
|
6260
6994
|
};
|
|
6261
6995
|
|
|
6262
6996
|
// src/config.ts
|
|
6997
|
+
init_esm_shims();
|
|
6263
6998
|
import { readFileSync as readFileSync4, existsSync as existsSync7 } from "fs";
|
|
6264
6999
|
import { join as join5 } from "path";
|
|
6265
7000
|
import { homedir as homedir2 } from "os";
|
|
@@ -6408,7 +7143,16 @@ function loadConfig() {
|
|
|
6408
7143
|
}
|
|
6409
7144
|
|
|
6410
7145
|
// src/core/bus/index.ts
|
|
7146
|
+
init_esm_shims();
|
|
6411
7147
|
import EventEmitter from "events";
|
|
7148
|
+
|
|
7149
|
+
// src/core/bus/types.ts
|
|
7150
|
+
init_esm_shims();
|
|
7151
|
+
|
|
7152
|
+
// src/core/bus/events.ts
|
|
7153
|
+
init_esm_shims();
|
|
7154
|
+
|
|
7155
|
+
// src/core/bus/index.ts
|
|
6412
7156
|
var EventBus = class {
|
|
6413
7157
|
emitter;
|
|
6414
7158
|
logger;
|
|
@@ -6686,7 +7430,11 @@ var EventBus = class {
|
|
|
6686
7430
|
}
|
|
6687
7431
|
};
|
|
6688
7432
|
|
|
7433
|
+
// src/core/channel/manager.ts
|
|
7434
|
+
init_esm_shims();
|
|
7435
|
+
|
|
6689
7436
|
// src/core/channel/registry.ts
|
|
7437
|
+
init_esm_shims();
|
|
6690
7438
|
var ChannelRegistry = class _ChannelRegistry {
|
|
6691
7439
|
static instance = null;
|
|
6692
7440
|
registry = /* @__PURE__ */ new Map();
|
|
@@ -6853,7 +7601,7 @@ var ChannelManager = class {
|
|
|
6853
7601
|
}
|
|
6854
7602
|
const delay = 1e3 * Math.pow(2, attempt - 1);
|
|
6855
7603
|
this.logger.debug({ channel: name, delay }, "[Channel] Retrying");
|
|
6856
|
-
await new Promise((
|
|
7604
|
+
await new Promise((resolve3) => setTimeout(resolve3, delay));
|
|
6857
7605
|
}
|
|
6858
7606
|
}
|
|
6859
7607
|
}
|
|
@@ -7126,7 +7874,17 @@ var ChannelManager = class {
|
|
|
7126
7874
|
}
|
|
7127
7875
|
};
|
|
7128
7876
|
|
|
7877
|
+
// src/core/routing/index.ts
|
|
7878
|
+
init_esm_shims();
|
|
7879
|
+
|
|
7880
|
+
// src/core/routing/InboundRouter.ts
|
|
7881
|
+
init_esm_shims();
|
|
7882
|
+
|
|
7883
|
+
// src/core/binding/index.ts
|
|
7884
|
+
init_esm_shims();
|
|
7885
|
+
|
|
7129
7886
|
// src/core/binding/BindingService.ts
|
|
7887
|
+
init_esm_shims();
|
|
7130
7888
|
import { writeFileSync as writeFileSync3 } from "fs";
|
|
7131
7889
|
import { join as join6 } from "path";
|
|
7132
7890
|
import { homedir as homedir3 } from "os";
|
|
@@ -7244,6 +8002,7 @@ var BindingService = class {
|
|
|
7244
8002
|
};
|
|
7245
8003
|
|
|
7246
8004
|
// src/core/command/routing.ts
|
|
8005
|
+
init_esm_shims();
|
|
7247
8006
|
var COMMAND_ROOT_SUBCOMMAND = "__root__";
|
|
7248
8007
|
var SYSTEM_COMMAND_ROOTS = /* @__PURE__ */ new Set([
|
|
7249
8008
|
"start",
|
|
@@ -7366,7 +8125,23 @@ var InboundRouter = class {
|
|
|
7366
8125
|
}
|
|
7367
8126
|
};
|
|
7368
8127
|
|
|
8128
|
+
// src/gateway/handlers/index.ts
|
|
8129
|
+
init_esm_shims();
|
|
8130
|
+
|
|
8131
|
+
// src/gateway/handlers/command.ts
|
|
8132
|
+
init_esm_shims();
|
|
8133
|
+
|
|
8134
|
+
// src/core/command/index.ts
|
|
8135
|
+
init_esm_shims();
|
|
8136
|
+
|
|
8137
|
+
// src/core/command/types.ts
|
|
8138
|
+
init_esm_shims();
|
|
8139
|
+
|
|
8140
|
+
// src/core/command/executor.ts
|
|
8141
|
+
init_esm_shims();
|
|
8142
|
+
|
|
7369
8143
|
// src/core/command/parser.ts
|
|
8144
|
+
init_esm_shims();
|
|
7370
8145
|
var CommandParser = class {
|
|
7371
8146
|
/**
|
|
7372
8147
|
* Check if content is a command (starts with /)
|
|
@@ -7512,7 +8287,11 @@ var CommandExecutor = class {
|
|
|
7512
8287
|
}
|
|
7513
8288
|
};
|
|
7514
8289
|
|
|
8290
|
+
// src/core/command/builtin/index.ts
|
|
8291
|
+
init_esm_shims();
|
|
8292
|
+
|
|
7515
8293
|
// src/core/command/builtin/bind.ts
|
|
8294
|
+
init_esm_shims();
|
|
7516
8295
|
var bindingService = new BindingService();
|
|
7517
8296
|
var bindCommand = {
|
|
7518
8297
|
description: "Bind this channel to an agent",
|
|
@@ -7567,6 +8346,7 @@ var unbindAgentCommand = {
|
|
|
7567
8346
|
};
|
|
7568
8347
|
|
|
7569
8348
|
// src/core/command/builtin/help.ts
|
|
8349
|
+
init_esm_shims();
|
|
7570
8350
|
var helpCommand = {
|
|
7571
8351
|
description: "Show system and agent command help",
|
|
7572
8352
|
usage: "/help",
|
|
@@ -7591,6 +8371,7 @@ var helpCommand = {
|
|
|
7591
8371
|
};
|
|
7592
8372
|
|
|
7593
8373
|
// src/core/command/builtin/session.ts
|
|
8374
|
+
init_esm_shims();
|
|
7594
8375
|
var bindingService2 = new BindingService();
|
|
7595
8376
|
function formatDuration(start, end) {
|
|
7596
8377
|
const endTime = end ?? /* @__PURE__ */ new Date();
|
|
@@ -7648,7 +8429,7 @@ var listHandler = {
|
|
|
7648
8429
|
for (const [agentType, agentSessions] of byAgent) {
|
|
7649
8430
|
lines.push(`**${agentType}** (${agentSessions.length})`);
|
|
7650
8431
|
for (const session of agentSessions) {
|
|
7651
|
-
lines.push(`- \`${session.id}\` (${session.status}, ${formatDuration(session.
|
|
8432
|
+
lines.push(`- \`${session.id}\` (${session.status}, ${formatDuration(new Date(session.createdAt))})`);
|
|
7652
8433
|
}
|
|
7653
8434
|
lines.push("");
|
|
7654
8435
|
}
|
|
@@ -7674,8 +8455,8 @@ var statusHandler = {
|
|
|
7674
8455
|
`Agent: ${session.agentType}`,
|
|
7675
8456
|
`Transport: ${session.transportType}`,
|
|
7676
8457
|
`Status: ${session.status}`,
|
|
7677
|
-
`Started: ${session.
|
|
7678
|
-
`Duration: ${formatDuration(session.
|
|
8458
|
+
`Started: ${new Date(session.createdAt).toISOString()}`,
|
|
8459
|
+
`Duration: ${formatDuration(new Date(session.createdAt))}`
|
|
7679
8460
|
];
|
|
7680
8461
|
if (session.cwd) {
|
|
7681
8462
|
lines.push(`Workdir: \`${session.cwd}\``);
|
|
@@ -7768,6 +8549,7 @@ function registerSessionCommands(registerFn) {
|
|
|
7768
8549
|
}
|
|
7769
8550
|
|
|
7770
8551
|
// src/core/command/builtin/start.ts
|
|
8552
|
+
init_esm_shims();
|
|
7771
8553
|
var bindingService3 = new BindingService();
|
|
7772
8554
|
var startCommand = {
|
|
7773
8555
|
description: "Show the quick-start guide for this channel",
|
|
@@ -7789,6 +8571,7 @@ var startCommand = {
|
|
|
7789
8571
|
};
|
|
7790
8572
|
|
|
7791
8573
|
// src/core/command/builtin/system.ts
|
|
8574
|
+
init_esm_shims();
|
|
7792
8575
|
import process2 from "process";
|
|
7793
8576
|
import os from "os";
|
|
7794
8577
|
var systemStartTime = Date.now();
|
|
@@ -8077,6 +8860,7 @@ function setupCommandHandler(bus, sessionManager, logger5) {
|
|
|
8077
8860
|
}
|
|
8078
8861
|
|
|
8079
8862
|
// src/gateway/handlers/permission.ts
|
|
8863
|
+
init_esm_shims();
|
|
8080
8864
|
function setupPermissionHandler(bus, interactionQueue, logger5) {
|
|
8081
8865
|
const unsubscribe = bus.onInteractionResponse((event) => {
|
|
8082
8866
|
const { requestId, response, reason } = event;
|
|
@@ -8114,11 +8898,13 @@ function setupAllHandlers(bus, gateway, interactionQueue, logger5) {
|
|
|
8114
8898
|
}
|
|
8115
8899
|
|
|
8116
8900
|
// src/gateway/notification-handler.ts
|
|
8901
|
+
init_esm_shims();
|
|
8117
8902
|
var NotificationHandler = class {
|
|
8118
|
-
constructor(bus, logger5, getSessionAgentType, bindingService4) {
|
|
8903
|
+
constructor(bus, logger5, getSessionAgentType, getSessionInfo, bindingService4) {
|
|
8119
8904
|
this.bus = bus;
|
|
8120
8905
|
this.logger = logger5;
|
|
8121
8906
|
this.getSessionAgentType = getSessionAgentType;
|
|
8907
|
+
this.getSessionInfo = getSessionInfo;
|
|
8122
8908
|
this.bindingService = bindingService4;
|
|
8123
8909
|
if (!this.bindingService) {
|
|
8124
8910
|
this.bindingService = new BindingService(logger5);
|
|
@@ -8127,6 +8913,7 @@ var NotificationHandler = class {
|
|
|
8127
8913
|
bus;
|
|
8128
8914
|
logger;
|
|
8129
8915
|
getSessionAgentType;
|
|
8916
|
+
getSessionInfo;
|
|
8130
8917
|
bindingService;
|
|
8131
8918
|
unsubscribeFns = [];
|
|
8132
8919
|
sessionAgentMap = /* @__PURE__ */ new Map();
|
|
@@ -8264,6 +9051,7 @@ var NotificationHandler = class {
|
|
|
8264
9051
|
}
|
|
8265
9052
|
async handleTurnFinished(event) {
|
|
8266
9053
|
this.logger.debug({ sessionId: event.sessionId, cwd: event.cwd }, "[NotificationHandler] handleTurnFinished");
|
|
9054
|
+
const sessionInfo = this.getSessionInfo?.(event.sessionId);
|
|
8267
9055
|
const context = {
|
|
8268
9056
|
eventType: "turn:finished",
|
|
8269
9057
|
sessionId: event.sessionId,
|
|
@@ -8276,6 +9064,7 @@ var NotificationHandler = class {
|
|
|
8276
9064
|
thinking: event.thinking,
|
|
8277
9065
|
durationMs: event.durationMs,
|
|
8278
9066
|
usage: event.usage,
|
|
9067
|
+
model: sessionInfo?.model,
|
|
8279
9068
|
summary: event.usage || event.durationMs ? {
|
|
8280
9069
|
durationMs: event.durationMs,
|
|
8281
9070
|
inputTokens: event.usage?.inputTokens,
|
|
@@ -8374,7 +9163,14 @@ var NotificationHandler = class {
|
|
|
8374
9163
|
}
|
|
8375
9164
|
};
|
|
8376
9165
|
|
|
9166
|
+
// src/adapters/channels/index.ts
|
|
9167
|
+
init_esm_shims();
|
|
9168
|
+
|
|
9169
|
+
// src/adapters/channels/telegram/index.ts
|
|
9170
|
+
init_esm_shims();
|
|
9171
|
+
|
|
8377
9172
|
// src/core/channel/base.ts
|
|
9173
|
+
init_esm_shims();
|
|
8378
9174
|
var BaseChannel = class {
|
|
8379
9175
|
/**
|
|
8380
9176
|
* 是否支持流式消息输出
|
|
@@ -8628,6 +9424,7 @@ var BaseChannel = class {
|
|
|
8628
9424
|
};
|
|
8629
9425
|
|
|
8630
9426
|
// src/adapters/channels/telegram/bot.ts
|
|
9427
|
+
init_esm_shims();
|
|
8631
9428
|
import { Bot } from "grammy";
|
|
8632
9429
|
var TelegramBot = class {
|
|
8633
9430
|
/** grammy Bot 实例 */
|
|
@@ -8758,13 +9555,13 @@ var TelegramBot = class {
|
|
|
8758
9555
|
* @param timeoutMs - 超时时间(毫秒)
|
|
8759
9556
|
*/
|
|
8760
9557
|
async startWithTimeout(timeoutMs) {
|
|
8761
|
-
return new Promise((
|
|
9558
|
+
return new Promise((resolve3, reject) => {
|
|
8762
9559
|
const timeout = setTimeout(() => {
|
|
8763
9560
|
reject(new Error(`Bot start timed out after ${timeoutMs}ms`));
|
|
8764
9561
|
}, timeoutMs);
|
|
8765
9562
|
this.bot.start().then(() => {
|
|
8766
9563
|
clearTimeout(timeout);
|
|
8767
|
-
|
|
9564
|
+
resolve3();
|
|
8768
9565
|
}).catch((error2) => {
|
|
8769
9566
|
clearTimeout(timeout);
|
|
8770
9567
|
reject(error2);
|
|
@@ -8776,14 +9573,27 @@ var TelegramBot = class {
|
|
|
8776
9573
|
* @param ms - 毫秒
|
|
8777
9574
|
*/
|
|
8778
9575
|
sleep(ms) {
|
|
8779
|
-
return new Promise((
|
|
9576
|
+
return new Promise((resolve3) => setTimeout(resolve3, ms));
|
|
8780
9577
|
}
|
|
8781
9578
|
};
|
|
8782
9579
|
|
|
9580
|
+
// src/adapters/channels/telegram/formatter.ts
|
|
9581
|
+
init_esm_shims();
|
|
9582
|
+
|
|
9583
|
+
// src/gateway/notification-context.ts
|
|
9584
|
+
init_esm_shims();
|
|
9585
|
+
|
|
9586
|
+
// src/i18n/index.ts
|
|
9587
|
+
init_esm_shims();
|
|
9588
|
+
|
|
9589
|
+
// src/i18n/types.ts
|
|
9590
|
+
init_esm_shims();
|
|
9591
|
+
|
|
8783
9592
|
// src/i18n/index.ts
|
|
8784
9593
|
import i18next from "i18next";
|
|
8785
9594
|
|
|
8786
9595
|
// src/i18n/locales/en.ts
|
|
9596
|
+
init_esm_shims();
|
|
8787
9597
|
var en_default = {
|
|
8788
9598
|
wizard: {
|
|
8789
9599
|
section: {
|
|
@@ -9092,6 +9902,33 @@ function getEventTitle(eventType) {
|
|
|
9092
9902
|
}
|
|
9093
9903
|
}
|
|
9094
9904
|
|
|
9905
|
+
// src/shared/format.ts
|
|
9906
|
+
init_esm_shims();
|
|
9907
|
+
function formatDuration3(ms) {
|
|
9908
|
+
if (ms === void 0 || ms < 0) return "-";
|
|
9909
|
+
if (ms < 1e3) return `${ms}ms`;
|
|
9910
|
+
if (ms < 6e4) return `${Math.round(ms / 1e3)}s`;
|
|
9911
|
+
if (ms < 36e5) return `${Math.round(ms / 6e4)}m`;
|
|
9912
|
+
const hours = Math.floor(ms / 36e5);
|
|
9913
|
+
const minutes = Math.round(ms % 36e5 / 6e4);
|
|
9914
|
+
if (minutes === 0) return `${hours}h`;
|
|
9915
|
+
return `${hours}h${minutes}m`;
|
|
9916
|
+
}
|
|
9917
|
+
function formatTokenCount(n) {
|
|
9918
|
+
if (n === void 0 || n < 0) return "-";
|
|
9919
|
+
if (n < 1e3) return `${n}`;
|
|
9920
|
+
if (n < 1e6) {
|
|
9921
|
+
const val2 = n / 1e3;
|
|
9922
|
+
return `${stripZeroDecimal(val2)}k`;
|
|
9923
|
+
}
|
|
9924
|
+
const val = n / 1e6;
|
|
9925
|
+
return `${stripZeroDecimal(val)}M`;
|
|
9926
|
+
}
|
|
9927
|
+
function stripZeroDecimal(val) {
|
|
9928
|
+
const fixed = val.toFixed(1);
|
|
9929
|
+
return fixed.endsWith(".0") ? fixed.slice(0, -2) : fixed;
|
|
9930
|
+
}
|
|
9931
|
+
|
|
9095
9932
|
// src/adapters/channels/telegram/formatter.ts
|
|
9096
9933
|
var TelegramFormatter = class {
|
|
9097
9934
|
/**
|
|
@@ -9207,6 +10044,7 @@ var TelegramFormatter = class {
|
|
|
9207
10044
|
case "turn:finished":
|
|
9208
10045
|
return this.formatFinished(
|
|
9209
10046
|
title,
|
|
10047
|
+
context.model || context.agentType,
|
|
9210
10048
|
context.durationMs,
|
|
9211
10049
|
context.usage?.inputTokens,
|
|
9212
10050
|
context.usage?.outputTokens,
|
|
@@ -9242,17 +10080,19 @@ var TelegramFormatter = class {
|
|
|
9242
10080
|
/**
|
|
9243
10081
|
* 格式化结果通知消息
|
|
9244
10082
|
*/
|
|
9245
|
-
formatFinished(title, durationMs, inputTokens, outputTokens, result) {
|
|
10083
|
+
formatFinished(title, model, durationMs, inputTokens, outputTokens, result) {
|
|
9246
10084
|
const lines = [
|
|
9247
10085
|
`${this.escape(title)}`,
|
|
9248
10086
|
""
|
|
9249
10087
|
];
|
|
10088
|
+
if (model) {
|
|
10089
|
+
lines.push(`<b>Model:</b> ${this.escape(model)}`);
|
|
10090
|
+
}
|
|
9250
10091
|
if (durationMs !== void 0) {
|
|
9251
|
-
|
|
9252
|
-
lines.push(`<b>Duration:</b> ${this.escape(seconds)}s`);
|
|
10092
|
+
lines.push(`<b>Duration:</b> ${this.escape(formatDuration3(durationMs))}`);
|
|
9253
10093
|
}
|
|
9254
10094
|
if (inputTokens !== void 0 && outputTokens !== void 0) {
|
|
9255
|
-
lines.push(`<b>Tokens:</b>
|
|
10095
|
+
lines.push(`<b>Tokens:</b> ${formatTokenCount(inputTokens)}\u2191 / ${formatTokenCount(outputTokens)}\u2193`);
|
|
9256
10096
|
}
|
|
9257
10097
|
if (result) {
|
|
9258
10098
|
lines.push("", "<b>Result:</b>");
|
|
@@ -9319,6 +10159,7 @@ var TelegramFormatter = class {
|
|
|
9319
10159
|
var formatter = new TelegramFormatter();
|
|
9320
10160
|
|
|
9321
10161
|
// src/shared/channelInstance.ts
|
|
10162
|
+
init_esm_shims();
|
|
9322
10163
|
import { createHash } from "crypto";
|
|
9323
10164
|
function getChannelInstanceId(channelType, credential) {
|
|
9324
10165
|
const hash = createHash("sha256").update(credential).digest("hex").slice(0, 12);
|
|
@@ -9982,6 +10823,7 @@ TelegramChannel = __decorateElement(_init, 0, "TelegramChannel", _TelegramChanne
|
|
|
9982
10823
|
__runInitializers(_init, 1, TelegramChannel);
|
|
9983
10824
|
|
|
9984
10825
|
// src/adapters/channels/logger/index.ts
|
|
10826
|
+
init_esm_shims();
|
|
9985
10827
|
var _LoggerChannel_decorators, _init2, _a3;
|
|
9986
10828
|
_LoggerChannel_decorators = [Channel("logger")];
|
|
9987
10829
|
var LoggerChannel = class extends (_a3 = BaseChannel) {
|
|
@@ -10024,7 +10866,11 @@ _init2 = __decoratorStart(_a3);
|
|
|
10024
10866
|
LoggerChannel = __decorateElement(_init2, 0, "LoggerChannel", _LoggerChannel_decorators, LoggerChannel);
|
|
10025
10867
|
__runInitializers(_init2, 1, LoggerChannel);
|
|
10026
10868
|
|
|
10869
|
+
// src/adapters/channels/feishu/index.ts
|
|
10870
|
+
init_esm_shims();
|
|
10871
|
+
|
|
10027
10872
|
// src/adapters/channels/feishu/client.ts
|
|
10873
|
+
init_esm_shims();
|
|
10028
10874
|
import {
|
|
10029
10875
|
Client,
|
|
10030
10876
|
WSClient,
|
|
@@ -10176,7 +11022,8 @@ var FeishuClient = class {
|
|
|
10176
11022
|
userId: operator?.open_id,
|
|
10177
11023
|
messageId: context?.open_message_id,
|
|
10178
11024
|
chatId: context?.open_chat_id,
|
|
10179
|
-
optionId: value?.optionId
|
|
11025
|
+
optionId: value?.optionId,
|
|
11026
|
+
checked: actionObj?.checked
|
|
10180
11027
|
};
|
|
10181
11028
|
await this.cardActionHandler(cardAction);
|
|
10182
11029
|
} catch (error2) {
|
|
@@ -10224,6 +11071,7 @@ var FeishuClient = class {
|
|
|
10224
11071
|
};
|
|
10225
11072
|
|
|
10226
11073
|
// src/adapters/channels/feishu/formatter.ts
|
|
11074
|
+
init_esm_shims();
|
|
10227
11075
|
var FeishuFormatter = class {
|
|
10228
11076
|
/**
|
|
10229
11077
|
* 将内容转换为飞书 post 格式
|
|
@@ -10472,6 +11320,27 @@ ${JSON.stringify(content.permission.args, null, 2)}
|
|
|
10472
11320
|
};
|
|
10473
11321
|
return JSON.stringify(cardJson);
|
|
10474
11322
|
}
|
|
11323
|
+
/**
|
|
11324
|
+
* Format a message notification card
|
|
11325
|
+
*/
|
|
11326
|
+
formatMessageCard(params) {
|
|
11327
|
+
const { buildMessageCard: buildMessageCard2 } = (init_message(), __toCommonJS(message_exports));
|
|
11328
|
+
return buildMessageCard2(params);
|
|
11329
|
+
}
|
|
11330
|
+
/**
|
|
11331
|
+
* Format a permission request card
|
|
11332
|
+
*/
|
|
11333
|
+
formatPermissionCard(params) {
|
|
11334
|
+
const { buildPermissionCard: buildPermissionCard2 } = (init_permission(), __toCommonJS(permission_exports));
|
|
11335
|
+
return buildPermissionCard2(params);
|
|
11336
|
+
}
|
|
11337
|
+
/**
|
|
11338
|
+
* Format a question request card
|
|
11339
|
+
*/
|
|
11340
|
+
formatQuestionCard(params) {
|
|
11341
|
+
const { buildQuestionCard: buildQuestionCard2 } = (init_question(), __toCommonJS(question_exports));
|
|
11342
|
+
return buildQuestionCard2(params);
|
|
11343
|
+
}
|
|
10475
11344
|
};
|
|
10476
11345
|
|
|
10477
11346
|
// src/adapters/channels/feishu/index.ts
|
|
@@ -10498,6 +11367,7 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10498
11367
|
pendingOptions = /* @__PURE__ */ new Map();
|
|
10499
11368
|
pendingToolNames = /* @__PURE__ */ new Map();
|
|
10500
11369
|
// requestId -> toolName for always_allow
|
|
11370
|
+
pendingSelections = /* @__PURE__ */ new Map();
|
|
10501
11371
|
unsubscribeInteractionResponse;
|
|
10502
11372
|
formatter = new FeishuFormatter();
|
|
10503
11373
|
constructor(config, bus, logger5) {
|
|
@@ -10561,6 +11431,7 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10561
11431
|
this.pendingRequests.clear();
|
|
10562
11432
|
this.pendingOptions.clear();
|
|
10563
11433
|
this.pendingToolNames.clear();
|
|
11434
|
+
this.pendingSelections.clear();
|
|
10564
11435
|
this.client?.stopWebSocket();
|
|
10565
11436
|
await super.stop();
|
|
10566
11437
|
this.logger.info({ channel: this.name }, "[Channel] Stopped");
|
|
@@ -10587,33 +11458,48 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10587
11458
|
const ctx = message.context;
|
|
10588
11459
|
const interaction = ctx?.interaction;
|
|
10589
11460
|
const requestId = ctx?.requestId;
|
|
10590
|
-
|
|
10591
|
-
|
|
10592
|
-
|
|
10593
|
-
isInteractionRequest = true;
|
|
10594
|
-
if (eventType === "permission:request") {
|
|
10595
|
-
const toolName = ctx?.toolName || "";
|
|
11461
|
+
if (eventType === "permission:request") {
|
|
11462
|
+
const toolName = ctx?.toolName || "";
|
|
11463
|
+
if (requestId) {
|
|
10596
11464
|
this.pendingToolNames.set(requestId, toolName);
|
|
10597
|
-
|
|
10598
|
-
|
|
10599
|
-
|
|
10600
|
-
|
|
10601
|
-
|
|
10602
|
-
|
|
10603
|
-
|
|
11465
|
+
}
|
|
11466
|
+
const content = this.formatContextToMarkdown(message.context);
|
|
11467
|
+
const buttons = [
|
|
11468
|
+
{ text: "\u2705 Allow", type: "primary_filled", value: "agree" },
|
|
11469
|
+
{ text: "\u274C Deny", type: "danger_filled", value: "reject", confirm: { title: "\u786E\u8BA4\u62D2\u7EDD", text: "\u786E\u8BA4\u62D2\u7EDD\u8BE5\u5DE5\u5177\u8C03\u7528\uFF1F" } },
|
|
11470
|
+
{ text: "\u{1F513} Always Allow", type: "default", value: "always_allow", confirm: { title: "\u786E\u8BA4\u603B\u662F\u5141\u8BB8", text: "\u603B\u662F\u5141\u8BB8\u5C06\u653E\u884C\u8BE5\u5DE5\u5177\u7684\u6240\u6709\u8C03\u7528\uFF0C\u8BF7\u786E\u8BA4\u3002" } }
|
|
11471
|
+
];
|
|
11472
|
+
const cardContent = this.formatter.formatPermissionCard({ title: this.getTitleForContext(message.context), content, buttons });
|
|
11473
|
+
await this.sendCardRaw(cardContent, message);
|
|
11474
|
+
} else if (eventType === "question:request") {
|
|
11475
|
+
const question = interaction?.question;
|
|
11476
|
+
const content = this.formatContextToMarkdown(message.context);
|
|
11477
|
+
const mode = question?.multiSelect ? "multiple" : "single";
|
|
11478
|
+
const items = (question?.options || []).map((opt) => ({ id: opt.id, label: opt.label }));
|
|
11479
|
+
if (requestId && question) {
|
|
10604
11480
|
this.pendingOptions.set(
|
|
10605
11481
|
requestId,
|
|
10606
11482
|
question.options.map((opt) => ({ id: opt.id, value: opt.value }))
|
|
10607
11483
|
);
|
|
10608
|
-
buttons = question.options.map((opt) => ({
|
|
10609
|
-
text: opt.label,
|
|
10610
|
-
type: "primary",
|
|
10611
|
-
callbackValue: { action: "select", requestId, optionId: opt.id }
|
|
10612
|
-
}));
|
|
10613
11484
|
}
|
|
10614
|
-
|
|
10615
|
-
|
|
10616
|
-
|
|
11485
|
+
const cardContent = this.formatter.formatQuestionCard({ title: this.getTitleForContext(message.context), content, mode, items, requestId });
|
|
11486
|
+
await this.sendCardRaw(cardContent, message);
|
|
11487
|
+
} else {
|
|
11488
|
+
const content = message.context ? this.formatContextToMarkdown(message.context) : message.text || "";
|
|
11489
|
+
let meta = "";
|
|
11490
|
+
if (message.context?.eventType === "turn:finished") {
|
|
11491
|
+
const finishedCtx = message.context;
|
|
11492
|
+
const model = finishedCtx.model || finishedCtx.agentType || "-";
|
|
11493
|
+
const duration = formatDuration3(finishedCtx.durationMs);
|
|
11494
|
+
const outTokens = finishedCtx.usage?.outputTokens;
|
|
11495
|
+
const inTokens = finishedCtx.usage?.inputTokens;
|
|
11496
|
+
const tokens = outTokens !== void 0 && inTokens !== void 0 ? `${formatTokenCount(inTokens)}\u2191 ${formatTokenCount(outTokens)}\u2193` : "-";
|
|
11497
|
+
meta = `${model} \xB7 ${duration} \xB7 ${tokens}`;
|
|
11498
|
+
}
|
|
11499
|
+
const cardContent = this.formatter.formatMessageCard({ title: this.getTitleForContext(message.context), content, meta });
|
|
11500
|
+
await this.sendCardRaw(cardContent, message);
|
|
11501
|
+
}
|
|
11502
|
+
if ((eventType === "permission:request" || eventType === "question:request") && requestId) {
|
|
10617
11503
|
if (!this.pendingRequests.has(requestId)) {
|
|
10618
11504
|
this.pendingRequests.set(requestId, /* @__PURE__ */ new Set());
|
|
10619
11505
|
}
|
|
@@ -10731,7 +11617,7 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10731
11617
|
this.pendingOptions.delete(event.requestId);
|
|
10732
11618
|
}
|
|
10733
11619
|
/**
|
|
10734
|
-
*
|
|
11620
|
+
* Handle card button / checker callbacks
|
|
10735
11621
|
*/
|
|
10736
11622
|
async handleCardAction(data) {
|
|
10737
11623
|
const { action, requestId, userId, optionId } = data;
|
|
@@ -10743,10 +11629,6 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10743
11629
|
this.logger.warn({ requestId }, "Invalid request ID format");
|
|
10744
11630
|
return;
|
|
10745
11631
|
}
|
|
10746
|
-
if (!["agree", "reject", "always_allow", "select"].includes(action)) {
|
|
10747
|
-
this.logger.warn({ action }, "Invalid card action");
|
|
10748
|
-
return;
|
|
10749
|
-
}
|
|
10750
11632
|
if (!this.isAllowed(userId)) {
|
|
10751
11633
|
this.logger.warn({ userId, requestId }, "Unauthorized user tried to respond to request");
|
|
10752
11634
|
return;
|
|
@@ -10760,6 +11642,47 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10760
11642
|
this.logger.warn({ userId, requestId }, "User tried to respond to request they did not receive");
|
|
10761
11643
|
return;
|
|
10762
11644
|
}
|
|
11645
|
+
if (action === "check") {
|
|
11646
|
+
if (!optionId) {
|
|
11647
|
+
this.logger.warn({ requestId, userId }, "[Channel] Check missing optionId");
|
|
11648
|
+
return;
|
|
11649
|
+
}
|
|
11650
|
+
if (!this.pendingSelections.has(requestId)) {
|
|
11651
|
+
this.pendingSelections.set(requestId, /* @__PURE__ */ new Set());
|
|
11652
|
+
}
|
|
11653
|
+
const selected = this.pendingSelections.get(requestId);
|
|
11654
|
+
if (data.checked) {
|
|
11655
|
+
selected.add(optionId);
|
|
11656
|
+
} else {
|
|
11657
|
+
selected.delete(optionId);
|
|
11658
|
+
}
|
|
11659
|
+
this.logger.info({ requestId, userId, optionId, checked: data.checked, selectedCount: selected.size }, "[Channel] Checker changed");
|
|
11660
|
+
return;
|
|
11661
|
+
}
|
|
11662
|
+
if (action === "submit") {
|
|
11663
|
+
const selected = this.pendingSelections.get(requestId);
|
|
11664
|
+
const optionIds = selected ? Array.from(selected) : [];
|
|
11665
|
+
if (optionIds.length === 0) {
|
|
11666
|
+
this.logger.warn({ requestId, userId }, "[Channel] Submit with no selections");
|
|
11667
|
+
return;
|
|
11668
|
+
}
|
|
11669
|
+
const options = this.pendingOptions.get(requestId);
|
|
11670
|
+
const selectedValues = optionIds.map((id) => options?.find((opt) => opt.id === id)?.value).filter((v) => v !== void 0);
|
|
11671
|
+
this.bus.publishInteractionResponse({
|
|
11672
|
+
requestId,
|
|
11673
|
+
response: {
|
|
11674
|
+
requestId,
|
|
11675
|
+
action: "select",
|
|
11676
|
+
selectedValues
|
|
11677
|
+
},
|
|
11678
|
+
reason: `User submitted multi-select via Feishu`
|
|
11679
|
+
});
|
|
11680
|
+
this.logger.info({ requestId, userId, selectedCount: optionIds.length }, "[Channel] Multi-select submitted");
|
|
11681
|
+
this.pendingSelections.delete(requestId);
|
|
11682
|
+
this.pendingRequests.delete(requestId);
|
|
11683
|
+
this.pendingOptions.delete(requestId);
|
|
11684
|
+
return;
|
|
11685
|
+
}
|
|
10763
11686
|
if (action === "agree" || action === "reject" || action === "always_allow") {
|
|
10764
11687
|
const decision = action === "reject" ? "deny" : "allow";
|
|
10765
11688
|
const isAlwaysAllow = action === "always_allow";
|
|
@@ -10768,7 +11691,6 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10768
11691
|
rules: [{ toolName: this.pendingToolNames.get(requestId) ?? "*", ruleContent: "*" }],
|
|
10769
11692
|
behavior: "allow",
|
|
10770
11693
|
destination: "localSettings"
|
|
10771
|
-
// Project's settings.local.json
|
|
10772
11694
|
}] : void 0;
|
|
10773
11695
|
this.bus.publishInteractionResponse({
|
|
10774
11696
|
requestId,
|
|
@@ -10780,6 +11702,8 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10780
11702
|
reason: `User clicked ${action} button via Feishu`
|
|
10781
11703
|
});
|
|
10782
11704
|
this.pendingToolNames.delete(requestId);
|
|
11705
|
+
this.pendingRequests.delete(requestId);
|
|
11706
|
+
this.pendingOptions.delete(requestId);
|
|
10783
11707
|
this.logger.info({ requestId, userId, action: decision }, "[Channel] User response received");
|
|
10784
11708
|
return;
|
|
10785
11709
|
}
|
|
@@ -10804,28 +11728,20 @@ var FeishuChannel = class extends (_a4 = BaseChannel) {
|
|
|
10804
11728
|
reason: `User selected option ${optionId} via Feishu`
|
|
10805
11729
|
});
|
|
10806
11730
|
this.logger.info({ requestId, userId, action: "select", optionId }, "[Channel] User response received");
|
|
11731
|
+
this.pendingRequests.delete(requestId);
|
|
11732
|
+
this.pendingOptions.delete(requestId);
|
|
10807
11733
|
return;
|
|
10808
11734
|
}
|
|
11735
|
+
this.logger.warn({ action, requestId }, "Unknown card action");
|
|
10809
11736
|
}
|
|
10810
11737
|
/**
|
|
10811
|
-
*
|
|
11738
|
+
* Send a pre-built card JSON string
|
|
10812
11739
|
*/
|
|
10813
|
-
async
|
|
11740
|
+
async sendCardRaw(cardContent, message) {
|
|
10814
11741
|
if (!this.client) {
|
|
10815
11742
|
this.logger.error("Feishu client not initialized");
|
|
10816
11743
|
throw new Error("Feishu client not initialized");
|
|
10817
11744
|
}
|
|
10818
|
-
let content;
|
|
10819
|
-
if (message.context) {
|
|
10820
|
-
content = this.formatContextToMarkdown(message.context);
|
|
10821
|
-
} else if (message.text) {
|
|
10822
|
-
content = message.text;
|
|
10823
|
-
} else {
|
|
10824
|
-
this.logger.warn("No content to send in Feishu card message");
|
|
10825
|
-
return;
|
|
10826
|
-
}
|
|
10827
|
-
const title = this.getTitleForContext(message.context);
|
|
10828
|
-
const cardContent = this.formatter.formatCard({ title, content, buttons });
|
|
10829
11745
|
const targetUsers = this.feishuConfig.allowed_users || [];
|
|
10830
11746
|
for (const userId of targetUsers) {
|
|
10831
11747
|
if (userId === "*") continue;
|
|
@@ -10887,20 +11803,10 @@ ${context.thinking}`;
|
|
|
10887
11803
|
`;
|
|
10888
11804
|
if (context.cwd) {
|
|
10889
11805
|
md += `**WorkDir:** ${context.cwd}
|
|
10890
|
-
`;
|
|
10891
|
-
}
|
|
10892
|
-
md += `**Status:** Turn finished
|
|
10893
|
-
`;
|
|
10894
|
-
if (context.durationMs) {
|
|
10895
|
-
md += `**Duration:** ${(context.durationMs / 1e3).toFixed(1)}s
|
|
10896
|
-
`;
|
|
10897
|
-
}
|
|
10898
|
-
if (context.usage?.inputTokens !== void 0 && context.usage?.outputTokens !== void 0) {
|
|
10899
|
-
md += `**Tokens:** in ${context.usage.inputTokens} / out ${context.usage.outputTokens}
|
|
10900
11806
|
`;
|
|
10901
11807
|
}
|
|
10902
11808
|
if (context.lastAssistantMessage) {
|
|
10903
|
-
md +=
|
|
11809
|
+
md += `${context.lastAssistantMessage}`;
|
|
10904
11810
|
}
|
|
10905
11811
|
break;
|
|
10906
11812
|
case "tool:post":
|
|
@@ -11001,7 +11907,11 @@ _init3 = __decoratorStart(_a4);
|
|
|
11001
11907
|
FeishuChannel = __decorateElement(_init3, 0, "FeishuChannel", _FeishuChannel_decorators, FeishuChannel);
|
|
11002
11908
|
__runInitializers(_init3, 1, FeishuChannel);
|
|
11003
11909
|
|
|
11910
|
+
// src/adapters/channels/app/index.ts
|
|
11911
|
+
init_esm_shims();
|
|
11912
|
+
|
|
11004
11913
|
// src/adapters/channels/app/mapper.ts
|
|
11914
|
+
init_esm_shims();
|
|
11005
11915
|
function mapOutboundMessageToAppEvent(message, options = {}) {
|
|
11006
11916
|
const context = message.context;
|
|
11007
11917
|
if (!context) {
|
|
@@ -11161,6 +12071,7 @@ function readChannelInstanceId(message) {
|
|
|
11161
12071
|
}
|
|
11162
12072
|
|
|
11163
12073
|
// src/adapters/channels/app/server.ts
|
|
12074
|
+
init_esm_shims();
|
|
11164
12075
|
import { WebSocketServer as NodeWebSocketServer, WebSocket as WebSocket2 } from "ws";
|
|
11165
12076
|
var logger4 = getLogger();
|
|
11166
12077
|
var DEFAULT_PATH = "/ws/channels/app";
|
|
@@ -11211,8 +12122,8 @@ var AppChannelWebSocketServer = class {
|
|
|
11211
12122
|
if (!this.wss) {
|
|
11212
12123
|
return;
|
|
11213
12124
|
}
|
|
11214
|
-
await new Promise((
|
|
11215
|
-
this.wss?.close(() =>
|
|
12125
|
+
await new Promise((resolve3) => {
|
|
12126
|
+
this.wss?.close(() => resolve3());
|
|
11216
12127
|
});
|
|
11217
12128
|
this.wss = null;
|
|
11218
12129
|
}
|
|
@@ -11405,9 +12316,11 @@ function readFrameId(frame) {
|
|
|
11405
12316
|
}
|
|
11406
12317
|
|
|
11407
12318
|
// src/adapters/channels/app/protocol.ts
|
|
12319
|
+
init_esm_shims();
|
|
11408
12320
|
import { randomUUID as randomUUID5 } from "crypto";
|
|
11409
12321
|
|
|
11410
12322
|
// src/adapters/channels/app/query-service.ts
|
|
12323
|
+
init_esm_shims();
|
|
11411
12324
|
var DEFAULT_CAPABILITIES = {
|
|
11412
12325
|
chat: true,
|
|
11413
12326
|
multiTurn: true,
|
|
@@ -11763,6 +12676,7 @@ function error(id, code, message) {
|
|
|
11763
12676
|
}
|
|
11764
12677
|
|
|
11765
12678
|
// src/core/session/SessionRecoveryService.ts
|
|
12679
|
+
init_esm_shims();
|
|
11766
12680
|
import { readdirSync as readdirSync2, readFileSync as readFileSync5 } from "fs";
|
|
11767
12681
|
import { join as join7, extname } from "path";
|
|
11768
12682
|
var SessionRecoveryService = class {
|
|
@@ -11813,7 +12727,11 @@ var SessionRecoveryService = class {
|
|
|
11813
12727
|
await gateway.createSession(
|
|
11814
12728
|
claudeAgent.token,
|
|
11815
12729
|
sessionData.sessionId,
|
|
11816
|
-
{
|
|
12730
|
+
{
|
|
12731
|
+
metadata: { kind: sessionData.kind, entrypoint: sessionData.entrypoint },
|
|
12732
|
+
cwd: sessionData.cwd,
|
|
12733
|
+
createdAt: sessionData.startedAt
|
|
12734
|
+
},
|
|
11817
12735
|
true
|
|
11818
12736
|
// skipPublishSessionStart — don't duplicate start notification
|
|
11819
12737
|
);
|
|
@@ -11845,9 +12763,9 @@ var SessionRecoveryService = class {
|
|
|
11845
12763
|
return [];
|
|
11846
12764
|
}
|
|
11847
12765
|
}
|
|
11848
|
-
parseSessionFile(
|
|
12766
|
+
parseSessionFile(path3) {
|
|
11849
12767
|
try {
|
|
11850
|
-
const raw = readFileSync5(
|
|
12768
|
+
const raw = readFileSync5(path3, "utf-8");
|
|
11851
12769
|
const data = JSON.parse(raw);
|
|
11852
12770
|
if (!data.sessionId || typeof data.pid !== "number") {
|
|
11853
12771
|
return null;
|
|
@@ -11855,7 +12773,7 @@ var SessionRecoveryService = class {
|
|
|
11855
12773
|
return data;
|
|
11856
12774
|
} catch (err) {
|
|
11857
12775
|
this.logger.warn(
|
|
11858
|
-
{ file:
|
|
12776
|
+
{ file: path3, error: err instanceof Error ? err.message : String(err) },
|
|
11859
12777
|
"Failed to parse session file"
|
|
11860
12778
|
);
|
|
11861
12779
|
return null;
|
|
@@ -11983,6 +12901,7 @@ async function main() {
|
|
|
11983
12901
|
bus,
|
|
11984
12902
|
logger5,
|
|
11985
12903
|
(id) => gateway.getSessionAgentType(id),
|
|
12904
|
+
(id) => gateway.getSessionInfo(id),
|
|
11986
12905
|
bindingService4
|
|
11987
12906
|
);
|
|
11988
12907
|
notificationHandler.start();
|