@adecore/agents 0.23.0 → 0.24.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.
Files changed (153) hide show
  1. package/README.md +3 -3
  2. package/dist/chat/attachment-store.js +4 -5
  3. package/dist/chat/backend.d.ts +6 -1
  4. package/dist/chat/background-work.d.ts +1 -1
  5. package/dist/chat/background-work.js +2 -1
  6. package/dist/chat/chat-core.d.ts +53 -161
  7. package/dist/chat/chat-core.js +146 -112
  8. package/dist/chat/chat-log.js +3 -3
  9. package/dist/chat/chat-process.d.ts +21 -0
  10. package/dist/chat/chat-process.js +109 -9
  11. package/dist/chat/chat-session.d.ts +10 -17
  12. package/dist/chat/chat-session.js +141 -182
  13. package/dist/chat/chat-store.d.ts +1 -0
  14. package/dist/chat/chat-store.js +105 -1
  15. package/dist/chat/claude-backend.d.ts +4 -0
  16. package/dist/chat/claude-backend.js +51 -27
  17. package/dist/chat/claude-protocol.d.ts +12 -0
  18. package/dist/chat/claude-protocol.js +137 -7
  19. package/dist/chat/claude-title.d.ts +1 -3
  20. package/dist/chat/claude-title.js +11 -39
  21. package/dist/chat/claude-transcript.d.ts +1 -0
  22. package/dist/chat/claude-transcript.js +36 -17
  23. package/dist/chat/codex-backend.d.ts +21 -1
  24. package/dist/chat/codex-backend.js +168 -10
  25. package/dist/chat/codex-protocol.d.ts +2 -0
  26. package/dist/chat/codex-protocol.js +37 -3
  27. package/dist/chat/codex-thread.js +1 -3
  28. package/dist/chat/codex-transport.d.ts +3 -0
  29. package/dist/chat/codex-transport.js +38 -35
  30. package/dist/chat/context-breakdown.js +2 -2
  31. package/dist/chat/errors.d.ts +1 -1
  32. package/dist/chat/external-sessions.js +2 -2
  33. package/dist/chat/fixtures/claude-2.1.296-goal.json +136 -0
  34. package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10.jsonl +2 -0
  35. package/dist/chat/index.d.ts +29 -0
  36. package/dist/chat/index.js +23 -0
  37. package/dist/chat/projector.d.ts +2 -1
  38. package/dist/chat/projector.js +12 -3
  39. package/dist/chat/request-summary.js +1 -4
  40. package/dist/chat/subagent-settlement.js +1 -3
  41. package/dist/chat/thread.d.ts +3 -0
  42. package/dist/chat/thread.js +20 -3
  43. package/dist/chat/ui-queries.d.ts +2 -0
  44. package/dist/chat/ui-queries.js +40 -5
  45. package/dist/chat/ui-replies.d.ts +33 -0
  46. package/dist/chat/ui-replies.js +152 -0
  47. package/dist/context/index.d.ts +2 -0
  48. package/dist/context/index.js +3 -0
  49. package/dist/coordination/index.d.ts +15 -0
  50. package/dist/coordination/index.js +16 -0
  51. package/dist/host/handlers.js +8 -0
  52. package/dist/host/index.d.ts +7 -0
  53. package/dist/host/index.js +7 -0
  54. package/dist/index.d.ts +9 -0
  55. package/dist/index.js +10 -0
  56. package/dist/providers/accounts/status.js +1 -3
  57. package/dist/providers/claude.js +3 -1
  58. package/dist/providers/codex.js +3 -1
  59. package/dist/providers/index.d.ts +14 -0
  60. package/dist/providers/index.js +12 -0
  61. package/dist/run-process.js +54 -14
  62. package/dist/skills.d.ts +1 -0
  63. package/dist/skills.js +4 -0
  64. package/dist/tasks/task-coordinator.d.ts +4 -0
  65. package/dist/tasks/task-coordinator.js +16 -2
  66. package/dist/tasks/wiring.js +7 -1
  67. package/dist/{providers/accounts/test-accounts.d.ts → testing/accounts.d.ts} +2 -2
  68. package/dist/{providers/accounts/test-accounts.js → testing/accounts.js} +3 -3
  69. package/dist/testing/bin/fake-claude.d.ts +1 -0
  70. package/dist/testing/bin/fake-claude.js +6 -0
  71. package/dist/testing/bin/fake-codex.d.ts +1 -0
  72. package/dist/testing/bin/fake-codex.js +6 -0
  73. package/dist/{chat → testing}/fake-claude.d.ts +1 -1
  74. package/dist/{chat → testing}/fake-claude.js +0 -4
  75. package/dist/{chat → testing}/fake-cli.d.ts +1 -1
  76. package/dist/{chat → testing}/fake-codex.d.ts +1 -1
  77. package/dist/{chat → testing}/fake-codex.js +70 -8
  78. package/dist/testing/index.d.ts +6 -0
  79. package/dist/testing/index.js +7 -0
  80. package/dist/{outbox → testing}/manual-clock.d.ts +1 -1
  81. package/dist/{watch-test-helpers.d.ts → testing/watch.d.ts} +1 -1
  82. package/dist/usage/exchange.d.ts +5 -3
  83. package/dist/usage/exchange.js +25 -16
  84. package/dist/usage/index-file.d.ts +1 -0
  85. package/dist/usage/index-file.js +20 -2
  86. package/dist/usage/index.d.ts +9 -0
  87. package/dist/usage/index.js +6 -0
  88. package/dist/usage/limits/normalize.js +1 -3
  89. package/dist/usage/pricing.d.ts +5 -3
  90. package/dist/usage/pricing.js +28 -19
  91. package/dist/usage/scanner.js +39 -11
  92. package/dist/usage/usage-service.js +8 -3
  93. package/package.json +72 -11
  94. package/src/chat/attachment-store.ts +4 -6
  95. package/src/chat/backend.ts +8 -0
  96. package/src/chat/background-work.ts +2 -2
  97. package/src/chat/chat-core.ts +221 -143
  98. package/src/chat/chat-log.ts +3 -3
  99. package/src/chat/chat-process.ts +128 -8
  100. package/src/chat/chat-session.ts +153 -204
  101. package/src/chat/chat-store.ts +104 -1
  102. package/src/chat/claude-backend.ts +58 -26
  103. package/src/chat/claude-protocol.ts +147 -8
  104. package/src/chat/claude-title.ts +11 -39
  105. package/src/chat/claude-transcript.ts +38 -18
  106. package/src/chat/codex-backend.ts +182 -20
  107. package/src/chat/codex-protocol.ts +40 -5
  108. package/src/chat/codex-thread.ts +1 -4
  109. package/src/chat/codex-transport.ts +45 -35
  110. package/src/chat/context-breakdown.ts +2 -2
  111. package/src/chat/errors.ts +1 -0
  112. package/src/chat/external-sessions.ts +2 -2
  113. package/src/chat/fixtures/claude-2.1.296-goal.json +136 -0
  114. package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10.jsonl +2 -0
  115. package/src/chat/index.ts +49 -0
  116. package/src/chat/projector.ts +13 -4
  117. package/src/chat/request-summary.ts +8 -5
  118. package/src/chat/subagent-settlement.ts +1 -4
  119. package/src/chat/thread.ts +22 -3
  120. package/src/chat/ui-queries.ts +46 -5
  121. package/src/chat/ui-replies.ts +187 -0
  122. package/src/context/index.ts +26 -0
  123. package/src/coordination/index.ts +67 -0
  124. package/src/host/handlers.ts +8 -0
  125. package/src/host/index.ts +8 -0
  126. package/src/index.ts +20 -0
  127. package/src/providers/accounts/status.ts +1 -4
  128. package/src/providers/claude.ts +3 -1
  129. package/src/providers/codex.ts +3 -1
  130. package/src/providers/index.ts +15 -0
  131. package/src/run-process.ts +56 -16
  132. package/src/skills.ts +5 -0
  133. package/src/tasks/task-coordinator.ts +22 -2
  134. package/src/tasks/wiring.ts +7 -1
  135. package/src/{providers/accounts/test-accounts.ts → testing/accounts.ts} +4 -4
  136. package/src/testing/bin/fake-claude.ts +7 -0
  137. package/src/testing/bin/fake-codex.ts +7 -0
  138. package/src/{chat → testing}/fake-claude.ts +1 -5
  139. package/src/{chat → testing}/fake-cli.ts +1 -1
  140. package/src/{chat → testing}/fake-codex.ts +75 -6
  141. package/src/testing/index.ts +7 -0
  142. package/src/{outbox → testing}/manual-clock.ts +1 -1
  143. package/src/{watch-test-helpers.ts → testing/watch.ts} +1 -1
  144. package/src/usage/exchange.ts +31 -20
  145. package/src/usage/index-file.ts +23 -2
  146. package/src/usage/index.ts +10 -0
  147. package/src/usage/limits/normalize.ts +1 -4
  148. package/src/usage/pricing.ts +34 -23
  149. package/src/usage/scanner.ts +48 -11
  150. package/src/usage/usage-service.ts +8 -3
  151. /package/dist/{chat → testing}/fake-cli.js +0 -0
  152. /package/dist/{outbox → testing}/manual-clock.js +0 -0
  153. /package/dist/{watch-test-helpers.js → testing/watch.js} +0 -0
@@ -66,7 +66,7 @@ export class ChatLog {
66
66
  constructor(path: string | null, state: ChatLogState = { seq: 0, resetSeq: 0, lines: [] }) {
67
67
  this.path = path;
68
68
  this.lines = state.lines;
69
- this.bytes = state.lines.reduce((sum, line) => sum + JSON.stringify(line).length + 1, 0);
69
+ this.bytes = state.lines.reduce((sum, line) => sum + Buffer.byteLength(JSON.stringify(line)) + 1, 0);
70
70
  this.seqValue = Math.max(state.seq, state.lines.at(-1)?.seq ?? 0);
71
71
  this.resetSeqValue = state.resetSeq;
72
72
  const first = state.lines[0];
@@ -107,7 +107,7 @@ export class ChatLog {
107
107
  }
108
108
  const text = `${JSON.stringify(line)}\n`;
109
109
  this.lines.push(line);
110
- this.bytes += text.length;
110
+ this.bytes += Buffer.byteLength(text);
111
111
  if (this.path !== null) {
112
112
  try {
113
113
  this.fd ??= this.open(this.path);
@@ -146,7 +146,7 @@ export class ChatLog {
146
146
  this.lines = this.lines.filter((line) => line.seq > seq);
147
147
  this.base = seq;
148
148
  const text = this.lines.map((line) => `${JSON.stringify(line)}\n`).join('');
149
- this.bytes = text.length;
149
+ this.bytes = Buffer.byteLength(text);
150
150
  if (this.path === null) {
151
151
  return;
152
152
  }
@@ -42,7 +42,9 @@ export function spawnChatProcess(options: ChatSpawnOptions): ChatProcess {
42
42
  env: options.env,
43
43
  stdio: ['pipe', 'pipe', 'pipe'],
44
44
  // A group of its own, so ending the chat also ends what its agent started (a dev server, a watcher).
45
- detached: true
45
+ // On Windows that would open a console window of its own instead; `taskkill` reaches the tree there.
46
+ detached: process.platform !== 'win32',
47
+ windowsHide: true
46
48
  });
47
49
  // Node reports a missing executable as an event after the call; a start that failed says so on the spot.
48
50
  child.on('error', () => undefined);
@@ -74,16 +76,39 @@ export function spawnChatProcess(options: ChatSpawnOptions): ChatProcess {
74
76
  },
75
77
  stdout: Readable.toWeb(child.stdout) as unknown as ReadableStream<Uint8Array>,
76
78
  stderr: Readable.toWeb(child.stderr) as unknown as ReadableStream<Uint8Array>,
77
- kill: (signal) => {
78
- try {
79
- process.kill(-pid, signal);
80
- } catch {
81
- // Nothing of the group is left to signal.
82
- }
83
- }
79
+ kill: (signal) => killProcessTree(pid, signal)
84
80
  };
85
81
  }
86
82
 
83
+ export interface ProcessTreeKillOptions {
84
+ platform?: NodeJS.Platform;
85
+ kill?(pid: number, signal: NodeJS.Signals): void;
86
+ run?(command: string[]): void;
87
+ }
88
+
89
+ /* Signals a process and everything it started. Windows has no process groups and no SIGTERM, so there the tree is ended at once. */
90
+ export function killProcessTree(pid: number, signal: 'SIGTERM' | 'SIGKILL', options: ProcessTreeKillOptions = {}): void {
91
+ const { platform = process.platform, kill = process.kill, run = runQuietly } = options;
92
+ if (platform === 'win32') {
93
+ run(['taskkill', '/pid', String(pid), '/t', '/f']);
94
+ return;
95
+ }
96
+ try {
97
+ kill(-pid, signal);
98
+ } catch {
99
+ // Nothing of the group is left to signal.
100
+ }
101
+ }
102
+
103
+ function runQuietly([command, ...args]: string[]): void {
104
+ if (command === undefined) {
105
+ return;
106
+ }
107
+ const child = spawn(command, args, { stdio: 'ignore', windowsHide: true });
108
+ // A tree that already ended makes taskkill fail, which is what the caller wanted anyway.
109
+ child.on('error', () => undefined);
110
+ }
111
+
87
112
  // After stdin closed, a CLI that is still around is not going to say more.
88
113
  const EXIT_GRACE_MS = 3000;
89
114
  // What a CLI and everything it started get between the SIGTERM and the SIGKILL.
@@ -133,6 +158,101 @@ export class StreamTail {
133
158
  }
134
159
  }
135
160
 
161
+ // Far above any frame either CLI writes, a base64 document in a tool result included; it only bounds a CLI that stopped breaking lines.
162
+ export const MAX_LINE_LENGTH = 64_000_000;
163
+
164
+ /*
165
+ * Cuts decoded output into lines. A chunk is searched only for itself and a partial line is joined
166
+ * once, when its line break comes, so a long line costs its length once. A line longer than `max`
167
+ * UTF-16 units is dropped whole, with `onOverflow` called once for it, and the next line reads as usual.
168
+ */
169
+ export class LineSplitter {
170
+ private readonly onLine: (line: string) => void;
171
+ private readonly onOverflow: () => void;
172
+ private readonly max: number;
173
+ private parts: string[] = [];
174
+ private length = 0;
175
+ private dropping = false;
176
+
177
+ constructor(onLine: (line: string) => void, onOverflow: () => void, max = MAX_LINE_LENGTH) {
178
+ this.onLine = onLine;
179
+ this.onOverflow = onOverflow;
180
+ this.max = max;
181
+ }
182
+
183
+ push(text: string): void {
184
+ let start = 0;
185
+ let newline = text.indexOf('\n');
186
+ while (newline >= 0) {
187
+ this.add(text.slice(start, newline));
188
+ const line = this.take();
189
+ if (line !== null) {
190
+ this.onLine(line);
191
+ }
192
+ start = newline + 1;
193
+ newline = text.indexOf('\n', start);
194
+ }
195
+ this.add(text.slice(start));
196
+ }
197
+
198
+ /* Hands on what came after the last line break, for a stream that ended without one. */
199
+ end(): void {
200
+ const line = this.take();
201
+ if (line !== null && line !== '') {
202
+ this.onLine(line);
203
+ }
204
+ }
205
+
206
+ private add(piece: string): void {
207
+ if (this.dropping || piece === '') {
208
+ return;
209
+ }
210
+ this.length += piece.length;
211
+ if (this.length > this.max) {
212
+ this.parts = [];
213
+ this.dropping = true;
214
+ this.onOverflow();
215
+ return;
216
+ }
217
+ this.parts.push(piece);
218
+ }
219
+
220
+ private take(): string | null {
221
+ const line = this.dropping ? null : this.parts.join('');
222
+ this.parts = [];
223
+ this.length = 0;
224
+ this.dropping = false;
225
+ return line;
226
+ }
227
+ }
228
+
229
+ /*
230
+ * Hands every line of a CLI's output to `onLine` until the stream ends, through a `LineSplitter`.
231
+ * A read that fails rejects, after every line that came before it was handed on.
232
+ */
233
+ export async function readStreamLines(
234
+ stream: ReadableStream<Uint8Array>,
235
+ onLine: (line: string) => void,
236
+ onOverflow: () => void,
237
+ max = MAX_LINE_LENGTH
238
+ ): Promise<void> {
239
+ const reader = stream.getReader();
240
+ const decoder = new TextDecoder();
241
+ const lines = new LineSplitter(onLine, onOverflow, max);
242
+ try {
243
+ while (true) {
244
+ const { value, done } = await reader.read();
245
+ if (done) {
246
+ break;
247
+ }
248
+ lines.push(decoder.decode(value, { stream: true }));
249
+ }
250
+ lines.end();
251
+ } finally {
252
+ reader.releaseLock();
253
+ }
254
+ }
255
+
136
256
  export interface ChatChildOptions extends Omit<ChatSpawnOptions, 'onExit'> {
137
257
  spawn?: SpawnChatProcess;
138
258
  // `stderr` is the tail of what the CLI wrote there, for an exit with an error code only.