@linkshell/host 0.4.17 → 0.4.19
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/README.md +39 -1
- package/dist/host/src/drivers/acp/connection.d.ts +5 -0
- package/dist/host/src/drivers/acp/connection.js +19 -1
- package/dist/host/src/drivers/acp/connection.js.map +1 -1
- package/dist/host/src/drivers/acp/driver.d.ts +13 -5
- package/dist/host/src/drivers/acp/driver.js +83 -29
- package/dist/host/src/drivers/acp/driver.js.map +1 -1
- package/dist/host/src/drivers/acp/questions.d.ts +14 -0
- package/dist/host/src/drivers/acp/questions.js +114 -0
- package/dist/host/src/drivers/acp/questions.js.map +1 -0
- package/dist/host/src/drivers/claude/driver.d.ts +4 -1
- package/dist/host/src/drivers/claude/driver.js +41 -1
- package/dist/host/src/drivers/claude/driver.js.map +1 -1
- package/dist/host/src/drivers/claude/tasks.d.ts +2 -2
- package/dist/host/src/drivers/claude/transcript.d.ts +76 -69
- package/dist/host/src/drivers/codex/archives.d.ts +2 -0
- package/dist/host/src/drivers/codex/archives.js +18 -0
- package/dist/host/src/drivers/codex/archives.js.map +1 -0
- package/dist/host/src/drivers/codex/attention.d.ts +7 -0
- package/dist/host/src/drivers/codex/attention.js +82 -0
- package/dist/host/src/drivers/codex/attention.js.map +1 -0
- package/dist/host/src/drivers/codex/driver.d.ts +3 -0
- package/dist/host/src/drivers/codex/driver.js +60 -3
- package/dist/host/src/drivers/codex/driver.js.map +1 -1
- package/dist/host/src/drivers/types.d.ts +6 -1
- package/dist/host/src/hub.d.ts +4 -1
- package/dist/host/src/hub.js +68 -8
- package/dist/host/src/hub.js.map +1 -1
- package/dist/host/src/store.d.ts +2 -0
- package/dist/host/src/store.js +9 -0
- package/dist/host/src/store.js.map +1 -1
- package/dist/host/tsconfig.tsbuildinfo +1 -1
- package/dist/wire/src/async-questions.d.ts +40 -0
- package/dist/wire/src/async-questions.js +66 -0
- package/dist/wire/src/async-questions.js.map +1 -0
- package/dist/wire/src/goal.d.ts +2 -2
- package/dist/wire/src/index.d.ts +1 -0
- package/dist/wire/src/index.js +1 -0
- package/dist/wire/src/index.js.map +1 -1
- package/dist/wire/src/model.d.ts +108 -84
- package/dist/wire/src/model.js +3 -0
- package/dist/wire/src/model.js.map +1 -1
- package/dist/wire/src/rpc.d.ts +2110 -1722
- package/dist/wire/src/updates.d.ts +633 -561
- package/dist/wire/src/updates.js +6 -1
- package/dist/wire/src/updates.js.map +1 -1
- package/dist/wire/src/workflow.d.ts +8 -8
- package/package.json +2 -2
|
@@ -46,7 +46,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
46
46
|
type: "resource_link";
|
|
47
47
|
name: string;
|
|
48
48
|
uri: string;
|
|
49
|
-
kind?: "
|
|
49
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
50
50
|
};
|
|
51
51
|
sessionUpdate: "user_message_chunk";
|
|
52
52
|
messageId?: string | undefined;
|
|
@@ -63,7 +63,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
63
63
|
type: "resource_link";
|
|
64
64
|
name: string;
|
|
65
65
|
uri: string;
|
|
66
|
-
kind?: "
|
|
66
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
67
67
|
};
|
|
68
68
|
sessionUpdate: "agent_message_chunk";
|
|
69
69
|
messageId: string;
|
|
@@ -81,7 +81,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
81
81
|
type: "resource_link";
|
|
82
82
|
name: string;
|
|
83
83
|
uri: string;
|
|
84
|
-
kind?: "
|
|
84
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
85
85
|
};
|
|
86
86
|
sessionUpdate: "agent_thought_chunk";
|
|
87
87
|
messageId: string;
|
|
@@ -90,23 +90,60 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
90
90
|
status: "completed" | "failed" | "pending" | "in_progress";
|
|
91
91
|
toolCallId: string;
|
|
92
92
|
title: string;
|
|
93
|
-
kind: "
|
|
93
|
+
kind: "delete" | "other" | "read" | "edit" | "move" | "search" | "execute" | "think" | "fetch";
|
|
94
94
|
sessionUpdate: "tool_call";
|
|
95
|
+
content?: ({
|
|
96
|
+
type: "content";
|
|
97
|
+
content: {
|
|
98
|
+
type: "text";
|
|
99
|
+
text: string;
|
|
100
|
+
} | {
|
|
101
|
+
type: "image";
|
|
102
|
+
mimeType: string;
|
|
103
|
+
data?: string | undefined;
|
|
104
|
+
uri?: string | undefined;
|
|
105
|
+
} | {
|
|
106
|
+
type: "resource_link";
|
|
107
|
+
name: string;
|
|
108
|
+
uri: string;
|
|
109
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
110
|
+
};
|
|
111
|
+
} | {
|
|
112
|
+
path: string;
|
|
113
|
+
type: "diff";
|
|
114
|
+
newText: string;
|
|
115
|
+
oldText?: string | null | undefined;
|
|
116
|
+
} | {
|
|
117
|
+
path: string;
|
|
118
|
+
type: "patch";
|
|
119
|
+
diff: string;
|
|
120
|
+
change: "add" | "delete" | "update";
|
|
121
|
+
movePath?: string | undefined;
|
|
122
|
+
} | {
|
|
123
|
+
type: "terminal";
|
|
124
|
+
terminalId: string;
|
|
125
|
+
})[] | undefined;
|
|
126
|
+
parentToolCallId?: string | undefined;
|
|
127
|
+
rawInput?: unknown;
|
|
128
|
+
locations?: {
|
|
129
|
+
path: string;
|
|
130
|
+
line?: number | undefined;
|
|
131
|
+
}[] | undefined;
|
|
95
132
|
detail?: {
|
|
96
133
|
type: "mcp";
|
|
97
|
-
tool: string;
|
|
98
134
|
server: string;
|
|
135
|
+
tool: string;
|
|
99
136
|
} | {
|
|
100
137
|
type: "subagent";
|
|
101
138
|
action: "message" | "resume" | "spawn" | "wait" | "stop" | "list";
|
|
102
|
-
state?: "
|
|
139
|
+
state?: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending" | undefined;
|
|
103
140
|
model?: string | undefined;
|
|
104
141
|
name?: string | undefined;
|
|
105
142
|
task?: string | undefined;
|
|
106
143
|
agentType?: string | undefined;
|
|
107
144
|
workflow?: {
|
|
108
145
|
completed?: number | undefined;
|
|
109
|
-
state?: "
|
|
146
|
+
state?: "paused" | "running" | "completed" | "failed" | "stopped" | undefined;
|
|
110
147
|
tokens?: number | undefined;
|
|
111
148
|
durationMs?: number | undefined;
|
|
112
149
|
startedAt?: number | undefined;
|
|
@@ -122,7 +159,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
122
159
|
agents?: {
|
|
123
160
|
id: string;
|
|
124
161
|
title: string;
|
|
125
|
-
state: "
|
|
162
|
+
state: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending";
|
|
126
163
|
toolCallId?: string | undefined;
|
|
127
164
|
phaseId?: string | undefined;
|
|
128
165
|
model?: string | undefined;
|
|
@@ -154,7 +191,11 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
154
191
|
text: string;
|
|
155
192
|
more?: number | undefined;
|
|
156
193
|
} | undefined;
|
|
157
|
-
|
|
194
|
+
} | {
|
|
195
|
+
toolCallId: string;
|
|
196
|
+
sessionUpdate: "tool_call_update";
|
|
197
|
+
status?: "completed" | "failed" | "pending" | "in_progress" | undefined;
|
|
198
|
+
title?: string | undefined;
|
|
158
199
|
content?: ({
|
|
159
200
|
type: "content";
|
|
160
201
|
content: {
|
|
@@ -169,7 +210,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
169
210
|
type: "resource_link";
|
|
170
211
|
name: string;
|
|
171
212
|
uri: string;
|
|
172
|
-
kind?: "
|
|
213
|
+
kind?: "file" | "skill" | "agent" | undefined;
|
|
173
214
|
};
|
|
174
215
|
} | {
|
|
175
216
|
path: string;
|
|
@@ -180,37 +221,28 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
180
221
|
path: string;
|
|
181
222
|
type: "patch";
|
|
182
223
|
diff: string;
|
|
183
|
-
change: "
|
|
224
|
+
change: "add" | "delete" | "update";
|
|
184
225
|
movePath?: string | undefined;
|
|
185
226
|
} | {
|
|
186
227
|
type: "terminal";
|
|
187
228
|
terminalId: string;
|
|
188
229
|
})[] | undefined;
|
|
189
|
-
|
|
190
|
-
locations?: {
|
|
191
|
-
path: string;
|
|
192
|
-
line?: number | undefined;
|
|
193
|
-
}[] | undefined;
|
|
194
|
-
} | {
|
|
195
|
-
toolCallId: string;
|
|
196
|
-
sessionUpdate: "tool_call_update";
|
|
197
|
-
status?: "completed" | "failed" | "pending" | "in_progress" | undefined;
|
|
198
|
-
title?: string | undefined;
|
|
230
|
+
parentToolCallId?: string | undefined;
|
|
199
231
|
detail?: {
|
|
200
232
|
type: "mcp";
|
|
201
|
-
tool: string;
|
|
202
233
|
server: string;
|
|
234
|
+
tool: string;
|
|
203
235
|
} | {
|
|
204
236
|
type: "subagent";
|
|
205
237
|
action: "message" | "resume" | "spawn" | "wait" | "stop" | "list";
|
|
206
|
-
state?: "
|
|
238
|
+
state?: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending" | undefined;
|
|
207
239
|
model?: string | undefined;
|
|
208
240
|
name?: string | undefined;
|
|
209
241
|
task?: string | undefined;
|
|
210
242
|
agentType?: string | undefined;
|
|
211
243
|
workflow?: {
|
|
212
244
|
completed?: number | undefined;
|
|
213
|
-
state?: "
|
|
245
|
+
state?: "paused" | "running" | "completed" | "failed" | "stopped" | undefined;
|
|
214
246
|
tokens?: number | undefined;
|
|
215
247
|
durationMs?: number | undefined;
|
|
216
248
|
startedAt?: number | undefined;
|
|
@@ -226,7 +258,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
226
258
|
agents?: {
|
|
227
259
|
id: string;
|
|
228
260
|
title: string;
|
|
229
|
-
state: "
|
|
261
|
+
state: "unknown" | "paused" | "running" | "completed" | "failed" | "stopped" | "pending";
|
|
230
262
|
toolCallId?: string | undefined;
|
|
231
263
|
phaseId?: string | undefined;
|
|
232
264
|
model?: string | undefined;
|
|
@@ -258,38 +290,6 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
258
290
|
text: string;
|
|
259
291
|
more?: number | undefined;
|
|
260
292
|
} | undefined;
|
|
261
|
-
parentToolCallId?: string | undefined;
|
|
262
|
-
content?: ({
|
|
263
|
-
type: "content";
|
|
264
|
-
content: {
|
|
265
|
-
type: "text";
|
|
266
|
-
text: string;
|
|
267
|
-
} | {
|
|
268
|
-
type: "image";
|
|
269
|
-
mimeType: string;
|
|
270
|
-
data?: string | undefined;
|
|
271
|
-
uri?: string | undefined;
|
|
272
|
-
} | {
|
|
273
|
-
type: "resource_link";
|
|
274
|
-
name: string;
|
|
275
|
-
uri: string;
|
|
276
|
-
kind?: "agent" | "file" | "skill" | undefined;
|
|
277
|
-
};
|
|
278
|
-
} | {
|
|
279
|
-
path: string;
|
|
280
|
-
type: "diff";
|
|
281
|
-
newText: string;
|
|
282
|
-
oldText?: string | null | undefined;
|
|
283
|
-
} | {
|
|
284
|
-
path: string;
|
|
285
|
-
type: "patch";
|
|
286
|
-
diff: string;
|
|
287
|
-
change: "delete" | "add" | "update";
|
|
288
|
-
movePath?: string | undefined;
|
|
289
|
-
} | {
|
|
290
|
-
type: "terminal";
|
|
291
|
-
terminalId: string;
|
|
292
|
-
})[] | undefined;
|
|
293
293
|
appendOutput?: string | undefined;
|
|
294
294
|
rawOutput?: unknown;
|
|
295
295
|
} | {
|
|
@@ -302,8 +302,8 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
302
302
|
} | {
|
|
303
303
|
sessionUpdate: "ls_goal";
|
|
304
304
|
goal: {
|
|
305
|
-
status: "paused" | "active" | "blocked" | "usageLimited" | "budgetLimited" | "complete";
|
|
306
305
|
objective: string;
|
|
306
|
+
status: "active" | "paused" | "blocked" | "usageLimited" | "budgetLimited" | "complete";
|
|
307
307
|
tokenBudget?: number | null | undefined;
|
|
308
308
|
tokensUsed?: number | undefined;
|
|
309
309
|
timeUsedSeconds?: number | undefined;
|
|
@@ -328,16 +328,23 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
328
328
|
sessionUpdate: "usage_update";
|
|
329
329
|
usedTokens?: number | undefined;
|
|
330
330
|
contextWindow?: number | undefined;
|
|
331
|
+
} | {
|
|
332
|
+
sessionUpdate: "ls_async_questions";
|
|
333
|
+
questions: {
|
|
334
|
+
options: string[];
|
|
335
|
+
id: string;
|
|
336
|
+
title: string;
|
|
337
|
+
}[];
|
|
331
338
|
} | {
|
|
332
339
|
sessionUpdate: "ls_message_done";
|
|
333
340
|
messageId: string;
|
|
334
341
|
role: "agent" | "thought" | "user";
|
|
342
|
+
parentToolCallId?: string | undefined;
|
|
335
343
|
questions?: {
|
|
336
344
|
options: string[];
|
|
337
345
|
id: string;
|
|
338
346
|
title: string;
|
|
339
347
|
}[] | undefined;
|
|
340
|
-
parentToolCallId?: string | undefined;
|
|
341
348
|
} | {
|
|
342
349
|
options: {
|
|
343
350
|
values: {
|
|
@@ -347,7 +354,7 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
347
354
|
}[];
|
|
348
355
|
id: string;
|
|
349
356
|
name: string;
|
|
350
|
-
category: "model" | "
|
|
357
|
+
category: "model" | "mode" | "effort" | "other";
|
|
351
358
|
current: string;
|
|
352
359
|
}[];
|
|
353
360
|
sessionUpdate: "ls_config";
|
|
@@ -361,22 +368,22 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
361
368
|
sessionUpdate: "ls_turn";
|
|
362
369
|
parentToolCallId?: string | undefined;
|
|
363
370
|
turnId?: string | undefined;
|
|
364
|
-
stopReason?: "
|
|
371
|
+
stopReason?: "end_turn" | "cancelled" | "error" | "max_tokens" | "refusal" | undefined;
|
|
365
372
|
} | {
|
|
366
373
|
options: {
|
|
367
374
|
name: string;
|
|
368
|
-
optionId: string;
|
|
369
375
|
kind: "allow_once" | "allow_always" | "reject_once" | "reject_always";
|
|
376
|
+
optionId: string;
|
|
370
377
|
}[];
|
|
371
378
|
title: string;
|
|
372
|
-
requestId: string;
|
|
373
379
|
sessionUpdate: "ls_permission";
|
|
380
|
+
requestId: string;
|
|
374
381
|
toolCallId?: string | undefined;
|
|
375
382
|
detail?: string | undefined;
|
|
376
383
|
questions?: {
|
|
377
384
|
id: string;
|
|
378
|
-
kind: "text" | "choice" | "choices";
|
|
379
385
|
text: string;
|
|
386
|
+
kind: "text" | "choice" | "choices";
|
|
380
387
|
options?: {
|
|
381
388
|
value: string;
|
|
382
389
|
label: string;
|
|
@@ -388,8 +395,8 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
388
395
|
required?: boolean | undefined;
|
|
389
396
|
}[] | undefined;
|
|
390
397
|
} | {
|
|
391
|
-
requestId: string;
|
|
392
398
|
sessionUpdate: "ls_permission_resolved";
|
|
399
|
+
requestId: string;
|
|
393
400
|
optionId?: string | undefined;
|
|
394
401
|
answers?: {
|
|
395
402
|
values: string[];
|
|
@@ -397,27 +404,27 @@ export declare const transcriptTimes: WeakMap<{
|
|
|
397
404
|
other?: string | undefined;
|
|
398
405
|
}[] | undefined;
|
|
399
406
|
} | {
|
|
400
|
-
driver: "remote" | "desktop" | "none";
|
|
401
407
|
sessionUpdate: "ls_driver";
|
|
408
|
+
driver: "desktop" | "remote" | "none";
|
|
402
409
|
deviceId?: string | undefined;
|
|
403
410
|
} | {
|
|
404
|
-
state: "running" | "
|
|
411
|
+
state: "running" | "error" | "idle" | "waiting" | "offline";
|
|
405
412
|
sessionUpdate: "ls_status";
|
|
406
413
|
} | {
|
|
407
414
|
task: {
|
|
408
415
|
id: string;
|
|
409
416
|
title: string;
|
|
410
|
-
state: "
|
|
417
|
+
state: "unknown" | "running" | "completed" | "failed" | "stopped";
|
|
411
418
|
startedAt: number;
|
|
412
419
|
kind: "shell" | "monitor";
|
|
413
420
|
toolCallId?: string | undefined;
|
|
414
421
|
endedAt?: number | undefined;
|
|
415
|
-
lastSeq?: number | undefined;
|
|
416
422
|
command?: string | undefined;
|
|
417
423
|
summary?: string | undefined;
|
|
418
424
|
exitCode?: number | undefined;
|
|
419
425
|
output?: boolean | undefined;
|
|
420
426
|
canStop?: boolean | undefined;
|
|
427
|
+
lastSeq?: number | undefined;
|
|
421
428
|
};
|
|
422
429
|
sessionUpdate: "ls_task";
|
|
423
430
|
} | {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { readdir } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
/** Codex moves archived rollouts out of sessions; absence from a paged thread/list is not evidence of archival. */
|
|
4
|
+
export async function archivedThreadIds(codexHome) {
|
|
5
|
+
try {
|
|
6
|
+
const entries = await readdir(join(codexHome, "archived_sessions"), { withFileTypes: true });
|
|
7
|
+
return entries.flatMap((entry) => {
|
|
8
|
+
const id = entry.isFile() ? /^rollout-.+-([0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12})\.jsonl$/i.exec(entry.name)?.[1] : undefined;
|
|
9
|
+
return id ? [id] : [];
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error.code === "ENOENT")
|
|
14
|
+
return [];
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=archives.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"archives.js","sourceRoot":"","sources":["../../../../../src/drivers/codex/archives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAC3C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,mHAAmH;AACnH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,SAAiB;IACvD,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,SAAS,EAAE,mBAAmB,CAAC,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7F,OAAO,OAAO,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAC/B,MAAM,EAAE,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,oEAAoE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;YACnI,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAK,KAA+B,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,EAAE,CAAC;QAClE,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type AsyncQuestion } from "@linkshell/wire";
|
|
2
|
+
export interface CodexAttention {
|
|
3
|
+
running: boolean;
|
|
4
|
+
questions: AsyncQuestion[];
|
|
5
|
+
}
|
|
6
|
+
/** Read only the current turn, so list badges work without taking ownership of the thread. */
|
|
7
|
+
export declare function rolloutAttention(path: string, chunk?: number, limit?: number): CodexAttention | undefined;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { closeSync, fstatSync, openSync, readSync } from "node:fs";
|
|
2
|
+
import { answeredQuestions } from "@linkshell/wire";
|
|
3
|
+
import { asyncQuestions } from "./mapper.js";
|
|
4
|
+
/** Read only the current turn, so list badges work without taking ownership of the thread. */
|
|
5
|
+
export function rolloutAttention(path, chunk = 256 * 1024, limit = 16 * 1024 * 1024) {
|
|
6
|
+
let fd;
|
|
7
|
+
try {
|
|
8
|
+
fd = openSync(path, "r");
|
|
9
|
+
}
|
|
10
|
+
catch {
|
|
11
|
+
return undefined;
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
const size = fstatSync(fd).size;
|
|
15
|
+
let end = size;
|
|
16
|
+
let prefix = Buffer.alloc(0);
|
|
17
|
+
const questions = [];
|
|
18
|
+
const answered = new Set();
|
|
19
|
+
while (end > 0 && size - end < limit) {
|
|
20
|
+
const start = Math.max(0, end - Math.min(chunk, limit - (size - end)));
|
|
21
|
+
const bytes = Buffer.alloc(end - start);
|
|
22
|
+
readSync(fd, bytes, 0, bytes.length, start);
|
|
23
|
+
let data = Buffer.concat([bytes, prefix]);
|
|
24
|
+
// A writer may still be appending the last record.
|
|
25
|
+
if (end === size)
|
|
26
|
+
data = data.subarray(0, data.lastIndexOf(10) + 1);
|
|
27
|
+
end = start;
|
|
28
|
+
const first = start === 0 ? 0 : data.indexOf(10) + 1;
|
|
29
|
+
if (first === 0 && start > 0) {
|
|
30
|
+
prefix = data;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
const lines = data.subarray(first).toString("utf8").split("\n");
|
|
34
|
+
prefix = data.subarray(0, first);
|
|
35
|
+
for (let index = lines.length - 1; index >= 0; index--) {
|
|
36
|
+
const line = lines[index];
|
|
37
|
+
if (!line.includes('"task_') && !line.includes('"turn_aborted"') && !line.includes("request_user_input_async") && !line.includes("send_user_message_question_reply"))
|
|
38
|
+
continue;
|
|
39
|
+
let entry;
|
|
40
|
+
try {
|
|
41
|
+
entry = JSON.parse(line);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const payload = entry.payload;
|
|
47
|
+
if (!payload || typeof payload !== "object")
|
|
48
|
+
continue;
|
|
49
|
+
if (entry.type === "event_msg" && (payload.type === "task_complete" || payload.type === "turn_aborted"))
|
|
50
|
+
return { running: false, questions: [] };
|
|
51
|
+
if (entry.type === "event_msg" && payload.type === "task_started") {
|
|
52
|
+
return { running: true, questions: questions.filter((question) => !answered.has(question.id)) };
|
|
53
|
+
}
|
|
54
|
+
if (entry.type !== "response_item")
|
|
55
|
+
continue;
|
|
56
|
+
if (payload.type === "function_call" && typeof payload.name === "string" && /(?:^|\.)request_user_input_async$/.test(payload.name)) {
|
|
57
|
+
try {
|
|
58
|
+
const args = JSON.parse(payload.arguments);
|
|
59
|
+
questions.unshift(...(asyncQuestions({ id: payload.call_id, delivery: "async", questions: args.questions }) ?? []));
|
|
60
|
+
}
|
|
61
|
+
catch { /* Incomplete arguments cannot make an actionable question. */ }
|
|
62
|
+
}
|
|
63
|
+
if (payload.type === "message" && payload.role === "user" && Array.isArray(payload.content)) {
|
|
64
|
+
for (const block of payload.content) {
|
|
65
|
+
if (typeof block?.text === "string")
|
|
66
|
+
for (const [id] of answeredQuestions(block.text))
|
|
67
|
+
answered.add(id);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Unknown is not idle: do not clear a known pending question on a bounded read.
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
finally {
|
|
79
|
+
closeSync(fd);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=attention.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"attention.js","sourceRoot":"","sources":["../../../../../src/drivers/codex/attention.ts"],"names":[],"mappings":"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"}
|
|
@@ -116,6 +116,8 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
116
116
|
start(host: DriverHost): Promise<DriverStatus>;
|
|
117
117
|
authStatus(): Promise<AgentAuth>;
|
|
118
118
|
stop(): Promise<void>;
|
|
119
|
+
private readonly attention;
|
|
120
|
+
archivedSessions(): Promise<string[]>;
|
|
119
121
|
listSessions(limit: number): Promise<DiscoveredSession[]>;
|
|
120
122
|
private stateElsewhere;
|
|
121
123
|
/** Codex's own fork: a new thread with this one's turns, all or through `lastTurnId`, in `cwd`. */
|
|
@@ -139,6 +141,7 @@ export declare class CodexDriver implements AgentDriver {
|
|
|
139
141
|
private observe;
|
|
140
142
|
/** Reports what the other process has finished since the last look. An item still being written isn't on disk. */
|
|
141
143
|
private refresh;
|
|
144
|
+
private announceQuestions;
|
|
142
145
|
/**
|
|
143
146
|
* The model, effort and permissions the other process runs the thread with,
|
|
144
147
|
* from its rollout file: a thread that can only be read has no
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import { rolloutAttention } from "./attention.js";
|
|
1
2
|
import { closeSync, fstatSync, openSync, readSync, statSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { archivedThreadIds } from "./archives.js";
|
|
2
6
|
import { codexPreview } from "./computer-preview.js";
|
|
3
|
-
import { ABANDON, RpcError, sessionGoalSchema } from "@linkshell/wire";
|
|
7
|
+
import { ABANDON, RpcError, questionReplies, updateAsyncQuestions, sessionGoalSchema } from "@linkshell/wire";
|
|
4
8
|
import { parseCodexLoginStatus, runStatusCommand } from "../auth.js";
|
|
5
9
|
import { CodexAppServer, CodexSharedServer, detectCodex, sharedServerSocket } from "./app-server.js";
|
|
6
10
|
import { APPROVAL_METHODS, QUESTION_METHODS, mapApprovalRequest, mapQuestionRequest, mapNotification, threadStateOf, threadToDiscovered, spawnedThreads, subagentHistory, threadToHistory, toCodexInput, toolStart, turnUnderWay, } from "./mapper.js";
|
|
@@ -215,12 +219,26 @@ export class CodexDriver {
|
|
|
215
219
|
await this.server?.stop();
|
|
216
220
|
this.server = undefined;
|
|
217
221
|
}
|
|
222
|
+
attention = new Map();
|
|
223
|
+
archivedSessions() {
|
|
224
|
+
return archivedThreadIds((this.options.env ?? process.env).CODEX_HOME || join(homedir(), ".codex"));
|
|
225
|
+
}
|
|
218
226
|
async listSessions(limit) {
|
|
219
227
|
const result = await this.rpc("thread/list", { limit, archived: false });
|
|
220
228
|
return result.data.map((thread) => {
|
|
221
|
-
const discovered = threadToDiscovered(thread);
|
|
229
|
+
const discovered = { ...threadToDiscovered(thread), archived: false };
|
|
222
230
|
// This host's app-server only knows the state of the threads loaded in it.
|
|
223
231
|
const state = this.stateElsewhere(thread.id);
|
|
232
|
+
const stamp = thread.path ? fileStamp(thread.path) : undefined;
|
|
233
|
+
let attention = this.attention.get(thread.id);
|
|
234
|
+
if (thread.path && stamp && attention?.stamp !== stamp) {
|
|
235
|
+
attention = { stamp, value: rolloutAttention(thread.path) };
|
|
236
|
+
this.attention.set(thread.id, attention);
|
|
237
|
+
}
|
|
238
|
+
// Live notifications win over the file, which can lag while the agent writes.
|
|
239
|
+
if (!this.attached.has(thread.id) && !this.observed.has(thread.id) && attention?.value) {
|
|
240
|
+
return { ...discovered, state: attention.value.running ? "running" : "idle", asyncQuestions: attention.value.questions };
|
|
241
|
+
}
|
|
224
242
|
return state ? { ...discovered, state } : discovered;
|
|
225
243
|
});
|
|
226
244
|
}
|
|
@@ -297,6 +315,14 @@ export class CodexDriver {
|
|
|
297
315
|
}
|
|
298
316
|
catch (error) {
|
|
299
317
|
this.attached.delete(nativeId);
|
|
318
|
+
if (error instanceof Error && /session .+ is archived\b/i.test(error.message)) {
|
|
319
|
+
// Archives remain readable; opening history must not unarchive or resume the agent.
|
|
320
|
+
const { thread } = await this.rpc("thread/read", { threadId: nativeId, includeTurns: true });
|
|
321
|
+
this.host?.sessionSeen(this.id, { ...threadToDiscovered(thread), archived: true, state: "idle", asyncQuestions: [] });
|
|
322
|
+
const history = await this.withSubAgents(nativeId, thread, threadToHistory(thread));
|
|
323
|
+
this.host?.update(this.id, nativeId, { sessionUpdate: "ls_status", state: "idle" });
|
|
324
|
+
return history;
|
|
325
|
+
}
|
|
300
326
|
if (error instanceof Error && /no rollout/i.test(error.message)) {
|
|
301
327
|
// Opened in another client but no turn yet, so not on disk. A turn can
|
|
302
328
|
// still be started on it; after that it can be joined.
|
|
@@ -391,6 +417,7 @@ export class CodexDriver {
|
|
|
391
417
|
if (active)
|
|
392
418
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_turn", state: "started", turnId: active.id });
|
|
393
419
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_status", state: threadStateOf(thread.status) });
|
|
420
|
+
this.announceQuestions(threadId, thread, true);
|
|
394
421
|
const read = new Set((thread.turns ?? []).flatMap((turn) => turn.items.map((item) => item.id)));
|
|
395
422
|
for (const item of underWay) {
|
|
396
423
|
// A command still running: its card. (Its output so far was missed, so the whole of it comes when it finishes.)
|
|
@@ -435,6 +462,7 @@ export class CodexDriver {
|
|
|
435
462
|
this.cwds.set(threadId, thread.cwd);
|
|
436
463
|
this.host?.update(this.id, threadId, { sessionUpdate: "ls_status", state: running ? "running" : "idle" });
|
|
437
464
|
this.reportHeld(threadId, true);
|
|
465
|
+
this.announceQuestions(threadId, thread, true);
|
|
438
466
|
this.readHeldSettings(threadId, thread.path ?? undefined);
|
|
439
467
|
void this.announceCommands(threadId);
|
|
440
468
|
void this.announceGoal(threadId);
|
|
@@ -478,6 +506,7 @@ export class CodexDriver {
|
|
|
478
506
|
watch.seen.add(item.itemId);
|
|
479
507
|
this.report(threadId, item);
|
|
480
508
|
}
|
|
509
|
+
this.announceQuestions(threadId, thread);
|
|
481
510
|
const last = thread.turns?.at(-1);
|
|
482
511
|
const running = turnUnderWay(last);
|
|
483
512
|
watch.turnId = running ? last?.id : undefined;
|
|
@@ -498,6 +527,20 @@ export class CodexDriver {
|
|
|
498
527
|
watch.reading = false;
|
|
499
528
|
}
|
|
500
529
|
}
|
|
530
|
+
announceQuestions(threadId, thread, force = false) {
|
|
531
|
+
const turn = thread.turns?.at(-1);
|
|
532
|
+
let questions = [];
|
|
533
|
+
if (turnUnderWay(turn)) {
|
|
534
|
+
for (const item of threadToHistory({ ...thread, turns: turn ? [turn] : [] })) {
|
|
535
|
+
for (const update of item.updates)
|
|
536
|
+
questions = updateAsyncQuestions(questions, update);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
// Always restore on attach, even if this host already imported the history.
|
|
540
|
+
const changed = this.isNews(`questions:${threadId}`, questions);
|
|
541
|
+
if (force || changed)
|
|
542
|
+
this.host?.update(this.id, threadId, { sessionUpdate: "ls_async_questions", questions });
|
|
543
|
+
}
|
|
501
544
|
/**
|
|
502
545
|
* The model, effort and permissions the other process runs the thread with,
|
|
503
546
|
* from its rollout file: a thread that can only be read has no
|
|
@@ -1046,7 +1089,21 @@ export class CodexDriver {
|
|
|
1046
1089
|
async send(nativeId, input, clientMessageId) {
|
|
1047
1090
|
if (input.length === 0)
|
|
1048
1091
|
throw RpcError.app("invalid_params", "nothing to send");
|
|
1049
|
-
|
|
1092
|
+
const watch = this.observed.get(nativeId);
|
|
1093
|
+
if (watch?.running && questionReplies(textOf(input))) {
|
|
1094
|
+
try {
|
|
1095
|
+
if (!this.desktopBusPath)
|
|
1096
|
+
throw new Error("desktop bus unavailable");
|
|
1097
|
+
await steerThroughDesktop(this.desktopBusPath, nativeId, this.desktopMessage(nativeId, input, clientMessageId));
|
|
1098
|
+
}
|
|
1099
|
+
catch (error) {
|
|
1100
|
+
this.host?.log(`[codex] couldn't deliver a question answer to ${nativeId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
1101
|
+
throw this.refused(nativeId, "回答未确认送达 · 请重试或在电脑上回答", "回答未确认送达,问题仍保留");
|
|
1102
|
+
}
|
|
1103
|
+
void this.refresh(nativeId);
|
|
1104
|
+
return "steered";
|
|
1105
|
+
}
|
|
1106
|
+
if (watch)
|
|
1050
1107
|
return this.enqueue(nativeId, input, clientMessageId);
|
|
1051
1108
|
const activeTurnId = this.stateOf(nativeId).activeTurnId;
|
|
1052
1109
|
if (activeTurnId) {
|