@adecore/agents 0.38.0 → 0.40.0
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/async.d.ts +5 -0
- package/dist/async.js +13 -5
- package/dist/chat/acp-protocol.js +3 -5
- package/dist/chat/chat-core.d.ts +1 -0
- package/dist/chat/chat-core.js +9 -2
- package/dist/chat/chat-process.d.ts +1 -0
- package/dist/chat/chat-process.js +1 -1
- package/dist/chat/chat-session.d.ts +2 -0
- package/dist/chat/chat-session.js +9 -10
- package/dist/chat/claude-protocol.js +1 -6
- package/dist/chat/claude-transcript.js +1 -3
- package/dist/chat/codex-protocol.js +1 -6
- package/dist/chat/projector.js +1 -3
- package/dist/chat/request-summary.js +1 -3
- package/dist/coded-error.js +1 -5
- package/dist/context/argv.js +1 -2
- package/dist/context/verb.js +1 -3
- package/dist/error-text.d.ts +1 -0
- package/dist/error-text.js +4 -0
- package/dist/fields.d.ts +3 -0
- package/dist/fields.js +12 -0
- package/dist/fs.d.ts +1 -0
- package/dist/fs.js +8 -4
- package/dist/lineage.js +11 -5
- package/dist/messages/notice-store.js +3 -4
- package/dist/providers/accounts/acp-account.js +3 -20
- package/dist/providers/accounts/service.d.ts +1 -2
- package/dist/providers/accounts/service.js +5 -9
- package/dist/providers/accounts/status.js +1 -3
- package/dist/providers/acp-agent-state.js +1 -3
- package/dist/providers/claude.js +0 -1
- package/dist/providers/codex.js +0 -1
- package/dist/providers/detect.js +1 -1
- package/dist/providers/shell-commands.js +1 -2
- package/dist/run-process.js +1 -3
- package/dist/skills.d.ts +1 -1
- package/dist/skills.js +5 -8
- package/dist/tasks/background-limit.js +3 -2
- package/dist/tasks/task-coordinator.js +11 -17
- package/dist/testing/watch.js +0 -1
- package/dist/usage/limits/monitor.js +1 -2
- package/dist/usage/readers/claude.js +3 -10
- package/dist/usage/readers/codex.js +2 -9
- package/dist/usage/readers/grok.js +3 -10
- package/dist/usage/readers/host-log.js +3 -10
- package/dist/usage/record.d.ts +2 -0
- package/dist/usage/record.js +13 -0
- package/package.json +6 -6
- package/src/async.ts +23 -5
- package/src/chat/acp-backend.ts +121 -0
- package/src/chat/acp-protocol.ts +172 -6
- package/src/chat/attachment-store.ts +21 -0
- package/src/chat/backend.ts +0 -2
- package/src/chat/bookmark-store.ts +23 -0
- package/src/chat/chat-core.ts +218 -7
- package/src/chat/chat-log.ts +19 -0
- package/src/chat/chat-process.ts +52 -1
- package/src/chat/chat-session.ts +414 -13
- package/src/chat/chat-store.ts +50 -0
- package/src/chat/chat-title.ts +9 -0
- package/src/chat/claude-backend.ts +50 -0
- package/src/chat/claude-protocol.ts +155 -8
- package/src/chat/claude-title.ts +10 -0
- package/src/chat/claude-transcript.ts +47 -4
- package/src/chat/codex-backend.ts +131 -0
- package/src/chat/codex-protocol.ts +180 -8
- package/src/chat/codex-thread.ts +23 -0
- package/src/chat/composer-preferences.ts +6 -0
- package/src/chat/context-breakdown.ts +11 -0
- package/src/chat/delta-coalescer.ts +8 -0
- package/src/chat/external-sessions.ts +28 -0
- package/src/chat/generated-image.ts +25 -0
- package/src/chat/index.ts +5 -0
- package/src/chat/input.ts +13 -0
- package/src/chat/json-rpc-transport.ts +28 -0
- package/src/chat/limit-resume.ts +13 -0
- package/src/chat/projector.ts +160 -4
- package/src/chat/readable-text.ts +3 -0
- package/src/chat/request-summary.ts +18 -4
- package/src/chat/subagent-projection.ts +3 -0
- package/src/chat/subagent-reader.ts +76 -0
- package/src/chat/subagent-settlement.ts +24 -0
- package/src/chat/thread-search.ts +13 -0
- package/src/chat/thread.ts +31 -0
- package/src/chat/ui-queries.ts +122 -0
- package/src/chat/ui-replies.ts +34 -0
- package/src/chat/visual-store.ts +49 -0
- package/src/chat/wake-chat.ts +3 -0
- package/src/client-sinks.ts +2 -0
- package/src/coded-error.ts +1 -5
- package/src/context/argv.ts +18 -2
- package/src/context/index.ts +1 -0
- package/src/context/refusal.ts +3 -0
- package/src/context/verb.ts +32 -4
- package/src/coordination/index.ts +10 -0
- package/src/error-text.ts +7 -0
- package/src/fields.ts +14 -0
- package/src/fs.ts +20 -4
- package/src/host/agent-host.ts +20 -0
- package/src/host/environment.ts +6 -0
- package/src/host/handlers.ts +18 -0
- package/src/host/memory-port.ts +4 -0
- package/src/host/wiring.ts +10 -0
- package/src/index.ts +1 -0
- package/src/lineage.ts +24 -5
- package/src/messages/deliver-message.ts +6 -0
- package/src/messages/deliver-notice.ts +13 -0
- package/src/messages/notice-store.ts +16 -4
- package/src/modes.ts +1 -0
- package/src/outbox/outbox-worker.ts +31 -0
- package/src/outbox/outbox.ts +5 -0
- package/src/providers/accounts/accounts.ts +36 -0
- package/src/providers/accounts/acp-account.ts +22 -27
- package/src/providers/accounts/launch.ts +4 -0
- package/src/providers/accounts/service.ts +110 -12
- package/src/providers/accounts/shadow-home.ts +10 -0
- package/src/providers/accounts/status.ts +13 -4
- package/src/providers/accounts/store.ts +25 -0
- package/src/providers/accounts/variables.ts +11 -1
- package/src/providers/acp-agent-state.ts +24 -3
- package/src/providers/acp-provider.ts +5 -0
- package/src/providers/acp-usage-log.ts +2 -0
- package/src/providers/catalog.ts +17 -0
- package/src/providers/claude.ts +10 -1
- package/src/providers/codex-rules.ts +3 -0
- package/src/providers/codex.ts +2 -1
- package/src/providers/detect.ts +6 -1
- package/src/providers/provider.ts +1 -1
- package/src/providers/registry.ts +18 -2
- package/src/providers/shell-commands.ts +37 -2
- package/src/record-directory.ts +19 -0
- package/src/run-process.ts +24 -3
- package/src/serializer.ts +3 -0
- package/src/skills.ts +73 -10
- package/src/tasks/background-limit.ts +9 -2
- package/src/tasks/end-children.ts +9 -0
- package/src/tasks/give-task.ts +8 -0
- package/src/tasks/task-coordinator.ts +81 -17
- package/src/tasks/task-store.ts +28 -0
- package/src/tasks/waiting-child.ts +21 -0
- package/src/tasks/wake-parent.ts +26 -0
- package/src/tasks/wiring.ts +22 -0
- package/src/testing/accounts.ts +2 -0
- package/src/testing/fake-acp-capture.ts +16 -0
- package/src/testing/fake-acp.ts +66 -0
- package/src/testing/fake-claude.ts +177 -0
- package/src/testing/fake-cli.ts +29 -0
- package/src/testing/fake-codex.ts +122 -0
- package/src/testing/manual-clock.ts +2 -0
- package/src/testing/watch.ts +7 -1
- package/src/title-file.ts +12 -0
- package/src/usage/accounts.ts +6 -0
- package/src/usage/aggregate.ts +19 -0
- package/src/usage/exchange.ts +12 -0
- package/src/usage/index-file.ts +27 -0
- package/src/usage/limits/monitor.ts +31 -3
- package/src/usage/limits/normalize.ts +30 -0
- package/src/usage/limits/probe.ts +17 -0
- package/src/usage/pricing.ts +35 -0
- package/src/usage/projects.ts +8 -0
- package/src/usage/readers/claude.ts +12 -9
- package/src/usage/readers/codex.ts +40 -8
- package/src/usage/readers/grok.ts +17 -9
- package/src/usage/readers/host-log.ts +9 -9
- package/src/usage/record.ts +22 -0
- package/src/usage/roots.ts +6 -0
- package/src/usage/scanner.ts +61 -0
- package/src/usage/usage-service.ts +14 -0
- package/src/watch-seam.ts +8 -0
- package/src/windows-command.ts +12 -0
package/src/chat/claude-title.ts
CHANGED
|
@@ -33,26 +33,32 @@ export class ClaudeTitleReader {
|
|
|
33
33
|
/* The title of a session found by its id, for a chat, which knows no transcript path; in the projects of its account, its own folder first. */
|
|
34
34
|
async forSession(agentSessionId: string, projectsDir: string = this.projectsDir, cwd?: string): Promise<string | null> {
|
|
35
35
|
const path = await findClaudeSession(projectsDir, agentSessionId, cwd);
|
|
36
|
+
|
|
36
37
|
return path === null ? null : await this.forTranscript(path);
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
async forTranscript(path: string): Promise<string | null> {
|
|
40
41
|
let size: number;
|
|
42
|
+
|
|
41
43
|
try {
|
|
42
44
|
size = (await stat(path)).size;
|
|
43
45
|
} catch {
|
|
44
46
|
return null;
|
|
45
47
|
}
|
|
48
|
+
|
|
46
49
|
let progress = this.progress.get(path);
|
|
50
|
+
|
|
47
51
|
// Smaller than where we were is a file that was replaced, not one that grew.
|
|
48
52
|
if (!progress || size < progress.offset) {
|
|
49
53
|
progress = { offset: 0, aiTitle: null, customTitle: null };
|
|
50
54
|
this.progress.set(path, progress);
|
|
51
55
|
}
|
|
56
|
+
|
|
52
57
|
if (size > progress.offset) {
|
|
53
58
|
const current = progress;
|
|
54
59
|
current.offset = await readLines(path, current.offset, size, this.chunkBytes, (line) => this.take(line, current));
|
|
55
60
|
}
|
|
61
|
+
|
|
56
62
|
return progress.customTitle ?? progress.aiTitle;
|
|
57
63
|
}
|
|
58
64
|
|
|
@@ -60,15 +66,19 @@ export class ClaudeTitleReader {
|
|
|
60
66
|
if (!MARKERS.some((marker) => line.includes(marker))) {
|
|
61
67
|
return;
|
|
62
68
|
}
|
|
69
|
+
|
|
63
70
|
let record: unknown;
|
|
71
|
+
|
|
64
72
|
try {
|
|
65
73
|
record = JSON.parse(line);
|
|
66
74
|
} catch {
|
|
67
75
|
return;
|
|
68
76
|
}
|
|
77
|
+
|
|
69
78
|
if (!isRecord(record)) {
|
|
70
79
|
return;
|
|
71
80
|
}
|
|
81
|
+
|
|
72
82
|
if (record.type === 'ai-title') {
|
|
73
83
|
progress.aiTitle = cleanTitle(record.aiTitle) ?? progress.aiTitle;
|
|
74
84
|
} else if (record.type === 'custom-title') {
|
|
@@ -3,6 +3,7 @@ import { readdir, readFile, stat } from 'node:fs/promises';
|
|
|
3
3
|
import { dirname, join } from 'node:path';
|
|
4
4
|
import type { ChatHistoryResult, ChatItem } from '@adecore/agent-contracts';
|
|
5
5
|
import { isRecord } from '@adecore/agent-contracts';
|
|
6
|
+
import { filledStr as str } from '../fields.ts';
|
|
6
7
|
import { fileExists } from '../fs.ts';
|
|
7
8
|
import { readLines } from '../title-file.ts';
|
|
8
9
|
import { ClaudeProtocol } from './claude-protocol.ts';
|
|
@@ -12,19 +13,18 @@ import type { ChatThread } from './thread.ts';
|
|
|
12
13
|
|
|
13
14
|
const CHUNK_BYTES = 4 * 1024 * 1024;
|
|
14
15
|
|
|
15
|
-
function str(value: unknown): string | null {
|
|
16
|
-
return typeof value === 'string' && value !== '' ? value : null;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
16
|
/* The words of a user line that somebody said, or null for a line that carries tool results. */
|
|
20
17
|
export function spokenText(content: unknown): string | null {
|
|
21
18
|
if (typeof content === 'string') {
|
|
22
19
|
return content;
|
|
23
20
|
}
|
|
21
|
+
|
|
24
22
|
if (!Array.isArray(content) || content.some((block) => isRecord(block) && block.type === 'tool_result')) {
|
|
25
23
|
return null;
|
|
26
24
|
}
|
|
25
|
+
|
|
27
26
|
const texts = content.filter((block) => isRecord(block) && block.type === 'text').map((block) => String((block as { text?: unknown }).text ?? ''));
|
|
27
|
+
|
|
28
28
|
return texts.length === 0 ? null : texts.join('\n');
|
|
29
29
|
}
|
|
30
30
|
|
|
@@ -56,67 +56,89 @@ export async function findClaudeSession(projectsDir: string, sessionId: string,
|
|
|
56
56
|
if (projectsDir === '' || sessionId === '' || /[/\\]|\.\./.test(sessionId)) {
|
|
57
57
|
return null;
|
|
58
58
|
}
|
|
59
|
+
|
|
59
60
|
const file = `${sessionId}.jsonl`;
|
|
60
61
|
const key = `${projectsDir}\n${sessionId}`;
|
|
61
62
|
const own = cwd === undefined ? null : join(projectsDir, claudeProjectSlug(cwd), file);
|
|
63
|
+
|
|
62
64
|
if (own !== null && (await fileExists(own))) {
|
|
63
65
|
sessionPaths.set(key, own);
|
|
66
|
+
|
|
64
67
|
return own;
|
|
65
68
|
}
|
|
69
|
+
|
|
66
70
|
const known = sessionPaths.get(key);
|
|
71
|
+
|
|
67
72
|
if (known !== undefined && known !== own && (await fileExists(known))) {
|
|
68
73
|
return known;
|
|
69
74
|
}
|
|
75
|
+
|
|
70
76
|
sessionPaths.delete(key);
|
|
71
77
|
let dirs: string[];
|
|
78
|
+
|
|
72
79
|
try {
|
|
73
80
|
dirs = await readdir(projectsDir);
|
|
74
81
|
} catch {
|
|
75
82
|
return null;
|
|
76
83
|
}
|
|
84
|
+
|
|
77
85
|
const candidates = dirs.map((dir) => join(projectsDir, dir, file)).filter((candidate) => candidate !== own);
|
|
78
86
|
const present = await Promise.all(candidates.map(fileExists));
|
|
79
87
|
const found = candidates.find((_candidate, i) => present[i]) ?? null;
|
|
88
|
+
|
|
80
89
|
if (found !== null) {
|
|
81
90
|
sessionPaths.set(key, found);
|
|
82
91
|
}
|
|
92
|
+
|
|
83
93
|
return found;
|
|
84
94
|
}
|
|
85
95
|
|
|
86
96
|
/* Where the subagents of a session keep their transcripts: the folder beside its own transcript, once the CLI made it. */
|
|
87
97
|
export async function findSubagentsDir(projectsDir: string, cwd: string, sessionId: string): Promise<string | null> {
|
|
88
98
|
const transcript = await findClaudeSession(projectsDir, sessionId, cwd);
|
|
99
|
+
|
|
89
100
|
if (transcript === null) {
|
|
90
101
|
return null;
|
|
91
102
|
}
|
|
103
|
+
|
|
92
104
|
const dir = join(dirname(transcript), sessionId, 'subagents');
|
|
105
|
+
|
|
93
106
|
return (await fileExists(dir)) ? dir : null;
|
|
94
107
|
}
|
|
95
108
|
|
|
96
109
|
/* Every meta file in a subagents folder that says which agent it is about; one that does not parse is left out. */
|
|
97
110
|
export async function readSubagentMetas(dir: string): Promise<SubagentMeta[]> {
|
|
98
111
|
let names: string[];
|
|
112
|
+
|
|
99
113
|
try {
|
|
100
114
|
names = await readdir(dir);
|
|
101
115
|
} catch {
|
|
102
116
|
return [];
|
|
103
117
|
}
|
|
118
|
+
|
|
104
119
|
const metas: SubagentMeta[] = [];
|
|
120
|
+
|
|
105
121
|
for (const name of names) {
|
|
106
122
|
const match = /^agent-(.+)\.meta\.json$/.exec(name);
|
|
123
|
+
|
|
107
124
|
if (!match) {
|
|
108
125
|
continue;
|
|
109
126
|
}
|
|
127
|
+
|
|
110
128
|
let parsed: unknown;
|
|
129
|
+
|
|
111
130
|
try {
|
|
112
131
|
parsed = JSON.parse(await readFile(join(dir, name), 'utf8'));
|
|
113
132
|
} catch {
|
|
114
133
|
continue;
|
|
115
134
|
}
|
|
135
|
+
|
|
116
136
|
if (!isRecord(parsed)) {
|
|
117
137
|
continue;
|
|
118
138
|
}
|
|
139
|
+
|
|
119
140
|
const agentId = match[1]!;
|
|
141
|
+
|
|
120
142
|
metas.push({
|
|
121
143
|
agentId,
|
|
122
144
|
toolUseId: str(parsed.toolUseId),
|
|
@@ -125,6 +147,7 @@ export async function readSubagentMetas(dir: string): Promise<SubagentMeta[]> {
|
|
|
125
147
|
transcript: join(dir, `agent-${agentId}.jsonl`)
|
|
126
148
|
});
|
|
127
149
|
}
|
|
150
|
+
|
|
128
151
|
return metas;
|
|
129
152
|
}
|
|
130
153
|
|
|
@@ -136,20 +159,25 @@ export async function findWorkflowAgent(subagentsDir: string, agentId: string):
|
|
|
136
159
|
if (!/^[\w-]+$/.test(agentId)) {
|
|
137
160
|
return null;
|
|
138
161
|
}
|
|
162
|
+
|
|
139
163
|
const workflowsDir = join(subagentsDir, 'workflows');
|
|
140
164
|
let runs: string[];
|
|
165
|
+
|
|
141
166
|
try {
|
|
142
167
|
runs = await readdir(workflowsDir);
|
|
143
168
|
} catch {
|
|
144
169
|
return null;
|
|
145
170
|
}
|
|
171
|
+
|
|
146
172
|
for (const run of runs) {
|
|
147
173
|
const dir = join(workflowsDir, run);
|
|
148
174
|
const transcript = join(dir, `agent-${agentId}.jsonl`);
|
|
175
|
+
|
|
149
176
|
if (existsSync(transcript)) {
|
|
150
177
|
return { agentId, toolUseId: null, parentAgentId: null, description: null, transcript };
|
|
151
178
|
}
|
|
152
179
|
}
|
|
180
|
+
|
|
153
181
|
return null;
|
|
154
182
|
}
|
|
155
183
|
|
|
@@ -178,19 +206,24 @@ export class TranscriptProjection {
|
|
|
178
206
|
/* Reads what was added since the last call; false when the file is not there. */
|
|
179
207
|
async refresh(): Promise<boolean> {
|
|
180
208
|
let info: { size: number; mtimeMs: number };
|
|
209
|
+
|
|
181
210
|
try {
|
|
182
211
|
info = await stat(this.path);
|
|
183
212
|
} catch {
|
|
184
213
|
return false;
|
|
185
214
|
}
|
|
215
|
+
|
|
186
216
|
if (info.size < this.size || info.mtimeMs < this.mtimeMs) {
|
|
187
217
|
this.reset();
|
|
188
218
|
}
|
|
219
|
+
|
|
189
220
|
this.size = info.size;
|
|
190
221
|
this.mtimeMs = info.mtimeMs;
|
|
222
|
+
|
|
191
223
|
if (info.size > this.offset) {
|
|
192
224
|
this.offset = await readLines(this.path, this.offset, info.size, CHUNK_BYTES, (line) => this.take(line));
|
|
193
225
|
}
|
|
226
|
+
|
|
194
227
|
return true;
|
|
195
228
|
}
|
|
196
229
|
|
|
@@ -201,6 +234,7 @@ export class TranscriptProjection {
|
|
|
201
234
|
/* The page before `cursor`, or the newest page without one; the cursors are the thread's own. */
|
|
202
235
|
page(limit: number, cursor?: string): ChatHistoryResult {
|
|
203
236
|
const page = this.thread.history(limit, cursor);
|
|
237
|
+
|
|
204
238
|
return { items: page.items.map(settledReading), history: page.history };
|
|
205
239
|
}
|
|
206
240
|
|
|
@@ -218,21 +252,28 @@ export class TranscriptProjection {
|
|
|
218
252
|
if (line.trim() === '') {
|
|
219
253
|
return;
|
|
220
254
|
}
|
|
255
|
+
|
|
221
256
|
let entry: unknown;
|
|
257
|
+
|
|
222
258
|
try {
|
|
223
259
|
entry = JSON.parse(line);
|
|
224
260
|
} catch {
|
|
225
261
|
return;
|
|
226
262
|
}
|
|
263
|
+
|
|
227
264
|
if (!isRecord(entry) || (entry.type !== 'user' && entry.type !== 'assistant')) {
|
|
228
265
|
return;
|
|
229
266
|
}
|
|
267
|
+
|
|
230
268
|
const time = typeof entry.timestamp === 'string' ? Date.parse(entry.timestamp) : Number.NaN;
|
|
269
|
+
|
|
231
270
|
if (Number.isFinite(time)) {
|
|
232
271
|
this.lineTime = time;
|
|
233
272
|
}
|
|
273
|
+
|
|
234
274
|
const message = isRecord(entry.message) ? entry.message : {};
|
|
235
275
|
const said = entry.type === 'user' ? spokenText(message.content) : null;
|
|
276
|
+
|
|
236
277
|
if (said !== null) {
|
|
237
278
|
// The prompt it was given, or a message sent to it later; a reminder the CLI slipped in is not somebody talking.
|
|
238
279
|
if (entry.isMeta !== true && said.trim() !== '') {
|
|
@@ -244,8 +285,10 @@ export class TranscriptProjection {
|
|
|
244
285
|
text: said
|
|
245
286
|
});
|
|
246
287
|
}
|
|
288
|
+
|
|
247
289
|
return;
|
|
248
290
|
}
|
|
291
|
+
|
|
249
292
|
for (const event of this.protocol.handle({ type: entry.type, message })) {
|
|
250
293
|
this.projector.project(0, event);
|
|
251
294
|
}
|