@agentstrack/collector 0.2.1 → 0.4.1

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 (55) hide show
  1. package/CHANGELOG.md +209 -1
  2. package/README.md +114 -38
  3. package/dist/adapters/claude.d.ts +18 -0
  4. package/dist/adapters/claude.js +153 -45
  5. package/dist/adapters/claude.js.map +1 -1
  6. package/dist/adapters/codex.d.ts +15 -1
  7. package/dist/adapters/codex.js +87 -34
  8. package/dist/adapters/codex.js.map +1 -1
  9. package/dist/adapters/opencode.d.ts +17 -6
  10. package/dist/adapters/opencode.js +72 -26
  11. package/dist/adapters/opencode.js.map +1 -1
  12. package/dist/adapters/types.d.ts +16 -0
  13. package/dist/adapters/types.js +61 -0
  14. package/dist/adapters/types.js.map +1 -1
  15. package/dist/cli.js +164 -33
  16. package/dist/cli.js.map +1 -1
  17. package/dist/commands/service.js +40 -10
  18. package/dist/commands/service.js.map +1 -1
  19. package/dist/config.d.ts +1 -1
  20. package/dist/config.js +18 -5
  21. package/dist/config.js.map +1 -1
  22. package/dist/daemon.d.ts +73 -21
  23. package/dist/daemon.js +350 -119
  24. package/dist/daemon.js.map +1 -1
  25. package/dist/git/commits.d.ts +7 -1
  26. package/dist/git/commits.js +36 -17
  27. package/dist/git/commits.js.map +1 -1
  28. package/dist/git/repo.d.ts +13 -4
  29. package/dist/git/repo.js +34 -20
  30. package/dist/git/repo.js.map +1 -1
  31. package/dist/machine.d.ts +27 -0
  32. package/dist/machine.js +46 -0
  33. package/dist/machine.js.map +1 -0
  34. package/dist/privacy/pipeline.d.ts +6 -0
  35. package/dist/privacy/pipeline.js +41 -7
  36. package/dist/privacy/pipeline.js.map +1 -1
  37. package/dist/privacy/redact.d.ts +15 -2
  38. package/dist/privacy/redact.js +45 -6
  39. package/dist/privacy/redact.js.map +1 -1
  40. package/dist/queue/event-id.d.ts +9 -0
  41. package/dist/queue/event-id.js +15 -0
  42. package/dist/queue/event-id.js.map +1 -0
  43. package/dist/queue/spool.d.ts +24 -5
  44. package/dist/queue/spool.js +89 -33
  45. package/dist/queue/spool.js.map +1 -1
  46. package/dist/queue/tailer.d.ts +27 -4
  47. package/dist/queue/tailer.js +89 -28
  48. package/dist/queue/tailer.js.map +1 -1
  49. package/dist/sessions/title.d.ts +14 -2
  50. package/dist/sessions/title.js +18 -6
  51. package/dist/sessions/title.js.map +1 -1
  52. package/dist/transport/client.d.ts +37 -13
  53. package/dist/transport/client.js +50 -3
  54. package/dist/transport/client.js.map +1 -1
  55. package/package.json +2 -2
@@ -1,7 +1,8 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { deterministicEventId } from '../queue/event-id.js';
2
3
  import { homedir } from 'node:os';
3
4
  import { join } from 'node:path';
4
- import { num, safeJsonParse, str } from './types.js';
5
+ import { newestJsonl, num, readHeadLines, safeJsonParse, str } from './types.js';
5
6
  import { readClaudeAccount } from './account.js';
6
7
  import { emptyUsage } from '../schema.js';
7
8
  import { deriveTitle } from '../sessions/title.js';
@@ -19,11 +20,30 @@ import { deriveTitle } from '../sessions/title.js';
19
20
  * "output_tokens_details":{"thinking_tokens":257}}},"timestamp":"…"}
20
21
  *
21
22
  * Tool calls appear as tool_use / tool_result blocks inside message.content.
23
+ * One API response is written as SEVERAL assistant lines — one per content
24
+ * block (thinking, text, tool_use) — each repeating the same message.id and
25
+ * the same usage. Usage is therefore billed once per message.id, not per line.
26
+ *
27
+ * Sub-agents (the Agent tool, and Workflow scripts) write their own transcript
28
+ * under <session-uuid>/subagents/[workflows/<wf>/]agent-<id>.jsonl, with the
29
+ * parent's sessionId on every line, isSidechain: true and an agentId. A sibling
30
+ * agent-<id>.meta.json carries {"agentType","description","toolUseId",…}. Every
31
+ * event from such a line is stamped sidechain/agent_id/agent_kind/agent_type
32
+ * so the server can attribute the sub-agent's own usage to it.
22
33
  */
23
34
  export const CLAUDE_DIR = process.env['CLAUDE_CONFIG_DIR'] ?? join(homedir(), '.claude');
24
35
  const PROJECTS_DIR = join(CLAUDE_DIR, 'projects');
36
+ /**
37
+ * Claude Code's own markup on a user line: slash-command echoes and background
38
+ * task completions. They are not typed by a human and must not count as
39
+ * prompts or as human-active time.
40
+ */
41
+ const MARKUP_PROMPT = /^<(task-notification|local-command-stdout|command-message|command-name)[\s>]/;
42
+ const ULTRACODE = /\bultracode\b/i;
25
43
  export class ClaudeCodeAdapter {
26
44
  id = 'claude_code';
45
+ /** Cross-line facts within one transcript: a message's lines are contiguous. */
46
+ fileState = new Map();
27
47
  async detect() {
28
48
  if (!existsSync(PROJECTS_DIR)) {
29
49
  return { installed: false, watchPaths: [], note: `No transcripts at ${PROJECTS_DIR}` };
@@ -33,12 +53,10 @@ export class ClaudeCodeAdapter {
33
53
  // The version is stamped on every transcript line; read one cheaply.
34
54
  const projects = readdirSync(PROJECTS_DIR).slice(0, 5);
35
55
  for (const project of projects) {
36
- const files = readdirSync(join(PROJECTS_DIR, project)).filter((f) => f.endsWith('.jsonl'));
37
- if (files.length === 0)
56
+ const file = newestJsonl(join(PROJECTS_DIR, project));
57
+ if (!file)
38
58
  continue;
39
- // The version is stamped on every transcript line; read the newest one
40
- // rather than reporting a placeholder string as the agent version.
41
- version = readVersionFromTranscript(join(PROJECTS_DIR, project, files[0]));
59
+ version = readVersionFromTranscript(file);
42
60
  if (version)
43
61
  break;
44
62
  }
@@ -94,49 +112,81 @@ export class ClaudeCodeAdapter {
94
112
  agent: 'claude_code',
95
113
  agent_version: agentVersion,
96
114
  };
97
- const wrap = (event_type, payload) => ({ event: { ...base, event_type, payload }, cwd, repo });
98
- void ctx;
115
+ let state = this.fileState.get(ctx.sourceFile);
116
+ if (!state) {
117
+ state = { tools: new Map() };
118
+ this.fileState.set(ctx.sourceFile, state);
119
+ }
120
+ state.agent ??= readAgentStamp(ctx.sourceFile);
121
+ // A sub-agent's line, whether in its own file or (older releases) inline.
122
+ const agent = state.agent ?? (raw['isSidechain'] === true ? { agent_kind: 'subagent' } : null);
123
+ const stamp = agent ? { sidechain: true, ...agent, agent_id: str(raw['agentId']) ?? agent.agent_id } : {};
124
+ const wrap = (event_type, payload) => ({ event: { ...base, event_type, payload: { ...payload, ...stamp } }, cwd, repo });
99
125
  if (type === 'user')
100
- return this.normalizeUser(raw, wrap);
126
+ return this.normalizeUser(raw, state, wrap);
101
127
  if (type === 'assistant')
102
- return this.normalizeAssistant(raw, wrap);
128
+ return this.normalizeAssistant(raw, state, wrap);
103
129
  return [];
104
130
  }
105
- normalizeUser(raw, wrap) {
131
+ normalizeUser(raw, state, wrap) {
106
132
  const message = (raw['message'] ?? {});
107
133
  const content = message['content'];
108
134
  // A "user" line is either a real human prompt or a tool result the agent
109
- // fed back to itself. Only the former is human interaction time.
110
- if (Array.isArray(content)) {
135
+ // fed back to itself. Only the former is human interaction time. A prompt
136
+ // arrives as a string, or as text/image blocks when something was pasted.
137
+ let text;
138
+ if (typeof content === 'string')
139
+ text = content;
140
+ else if (Array.isArray(content)) {
111
141
  const events = [];
142
+ const texts = [];
112
143
  for (const block of content) {
113
144
  if (!block || typeof block !== 'object')
114
145
  continue;
115
146
  const b = block;
147
+ if (b['type'] === 'text') {
148
+ const t = str(b['text']);
149
+ if (t)
150
+ texts.push(t);
151
+ continue;
152
+ }
116
153
  if (b['type'] !== 'tool_result')
117
154
  continue;
155
+ const id = str(b['tool_use_id']);
118
156
  const failed = b['is_error'] === true;
157
+ const started = id ? state.tools.get(id) : undefined;
119
158
  events.push(wrap(failed ? 'tool.failed' : 'tool.completed', {
120
- tool_name: str(b['name']) ?? 'unknown',
121
- tool_call_id: str(b['tool_use_id']),
159
+ tool_name: started?.name ?? 'unknown',
160
+ tool_call_id: id,
161
+ ...started?.extra,
122
162
  }));
163
+ if (id)
164
+ state.tools.delete(id);
123
165
  }
124
- return events;
166
+ if (events.length > 0)
167
+ return events;
168
+ text = texts.join('\n');
125
169
  }
126
- if (typeof content !== 'string')
170
+ if (!text)
127
171
  return [];
128
- // Meta lines (command output, system reminders) are not prompts.
172
+ // Meta lines (command output, system reminders) and Claude Code's own
173
+ // markup are not prompts.
129
174
  if (raw['isMeta'] === true || str(raw['promptSource']) === 'system')
130
175
  return [];
176
+ if (MARKUP_PROMPT.test(text.trimStart()))
177
+ return [];
131
178
  return [
132
179
  wrap('user.prompted', {
133
- prompt_chars: content.length,
134
- prompt_text: content,
135
- derived_title: deriveTitle(content),
180
+ prompt_chars: text.length,
181
+ prompt_text: text,
182
+ derived_title: deriveTitle(text),
183
+ // A boolean computed here, before the privacy pipeline strips the
184
+ // text, so it survives metadata mode without the prompt travelling.
185
+ ...(ULTRACODE.test(text) ? { ultracode: true } : {}),
136
186
  }),
137
187
  ];
138
188
  }
139
- normalizeAssistant(raw, wrap) {
189
+ normalizeAssistant(raw, state, wrap) {
140
190
  const message = (raw['message'] ?? {});
141
191
  const model = str(message['model']);
142
192
  // Claude Code stamps '<synthetic>' on locally generated messages (interrupts,
@@ -144,14 +194,23 @@ export class ClaudeCodeAdapter {
144
194
  // analytics or the cost table.
145
195
  if (!model || model.startsWith('<'))
146
196
  return [];
147
- const events = [
148
- wrap('model.response', {
149
- model,
150
- provider: 'anthropic',
151
- usage: readUsage(message['usage']),
152
- stop_reason: str(message['stop_reason']),
153
- }),
154
- ];
197
+ const events = [];
198
+ // Every line of one response repeats the same usage; bill it once.
199
+ const messageId = str(message['id']) ?? str(raw['requestId']);
200
+ if (!messageId || messageId !== state.lastMessageId) {
201
+ state.lastMessageId = messageId;
202
+ events.push({
203
+ ...wrap('model.response', {
204
+ model,
205
+ provider: 'anthropic',
206
+ usage: readUsage(message['usage']),
207
+ stop_reason: str(message['stop_reason']),
208
+ }),
209
+ // Keyed on the message, not the line: a restart between two lines of
210
+ // the same response must dedupe on the server, not bill twice.
211
+ eventId: messageId ? deterministicEventId(`claude_code\nmodel.response\n${messageId}`) : undefined,
212
+ });
213
+ }
155
214
  const content = message['content'];
156
215
  if (Array.isArray(content)) {
157
216
  for (const block of content) {
@@ -161,9 +220,13 @@ export class ClaudeCodeAdapter {
161
220
  if (b['type'] !== 'tool_use')
162
221
  continue;
163
222
  const toolName = str(b['name']) ?? 'unknown';
164
- events.push(wrap('tool.started', { tool_name: toolName, tool_call_id: str(b['id']) }));
165
- // Bash invocations are the interesting ones for command analytics.
223
+ const toolId = str(b['id']);
166
224
  const input = (b['input'] ?? {});
225
+ const extra = toolExtras(toolName, input);
226
+ if (toolId)
227
+ state.tools.set(toolId, { name: toolName, extra });
228
+ events.push(wrap('tool.started', { tool_name: toolName, tool_call_id: toolId, ...extra }));
229
+ // Bash invocations are the interesting ones for command analytics.
167
230
  const command = str(input['command']);
168
231
  if (toolName === 'Bash' && command) {
169
232
  events.push(wrap('command.executed', { command }));
@@ -185,26 +248,71 @@ export class ClaudeCodeAdapter {
185
248
  }
186
249
  }
187
250
  /**
188
- * Maps Claude Code's usage block onto the normalized shape.
189
- *
190
- * thinking_tokens sits under output_tokens_details and is a SUBSET of
191
- * output_tokens — it must not be added on top, or thinking gets billed twice.
251
+ * What a Skill, Agent or Workflow call invoked — the name only, never the
252
+ * prompt or the script body. Everything else has no extras.
192
253
  */
193
- /** Reads the `version` field off the first line that carries one. */
194
- function readVersionFromTranscript(file) {
254
+ function toolExtras(toolName, input) {
255
+ const extra = {};
256
+ if (toolName === 'Skill')
257
+ extra['skill'] = str(input['skill']);
258
+ if (toolName === 'Agent') {
259
+ extra['subagent_type'] = str(input['subagent_type']);
260
+ extra['description'] = str(input['description']);
261
+ }
262
+ if (toolName === 'Workflow')
263
+ extra['workflow_name'] = workflowName(str(input['script']));
264
+ for (const key of Object.keys(extra))
265
+ if (extra[key] === undefined)
266
+ delete extra[key];
267
+ return extra;
268
+ }
269
+ /** `name: '…'` out of the script's `export const meta = {…}` header. Absent when it is not that simple. */
270
+ function workflowName(script) {
271
+ // ponytail: a regex over the first 4 KB, not a parser — meta is by convention the first export.
272
+ const m = /\bname:\s*(['"`])([^'"`\r\n]{1,120})\1/.exec(script?.slice(0, 4096) ?? '');
273
+ return m?.[2];
274
+ }
275
+ /**
276
+ * Sub-agent identity of a transcript, from its path and sibling meta file.
277
+ * Null for a main transcript. Read once per file; the meta file is written
278
+ * when the agent is spawned, before its first line.
279
+ */
280
+ function readAgentStamp(file) {
281
+ const m = /[\\/]subagents[\\/](?:.*[\\/])?agent-([^\\/]+)\.jsonl$/.exec(file);
282
+ if (!m)
283
+ return null;
284
+ const stamp = {
285
+ agent_id: m[1],
286
+ agent_kind: /[\\/]subagents[\\/]workflows[\\/]/.test(file) ? 'workflow' : 'subagent',
287
+ };
195
288
  try {
196
- for (const line of readFileSync(file, 'utf8').split('\n', 40)) {
197
- const parsed = safeJsonParse(line);
198
- const version = parsed ? str(parsed['version']) : undefined;
199
- if (version)
200
- return version;
201
- }
289
+ const meta = safeJsonParse(readFileSync(file.replace(/\.jsonl$/, '.meta.json'), 'utf8'));
290
+ // Real key is agentType (Claude Code 2.1.x); the rest are tolerated spellings.
291
+ const type = meta && (str(meta['agentType']) ?? str(meta['subagent_type']) ?? str(meta['type']) ?? str(meta['label']));
292
+ if (type)
293
+ stamp.agent_type = type;
202
294
  }
203
295
  catch {
204
- // Unreadable transcript: absent version is better than a fabricated one.
296
+ // No meta file: kind and id still come from the path.
297
+ }
298
+ return stamp;
299
+ }
300
+ /** Reads the `version` field off the first line that carries one. */
301
+ function readVersionFromTranscript(file) {
302
+ for (const line of readHeadLines(file)) {
303
+ const parsed = safeJsonParse(line);
304
+ const version = parsed ? str(parsed['version']) : undefined;
305
+ if (version)
306
+ return version;
205
307
  }
206
308
  return undefined;
207
309
  }
310
+ /**
311
+ * Maps Claude Code's usage block onto the normalized shape.
312
+ *
313
+ * thinking_tokens sits under output_tokens_details and is a SUBSET of
314
+ * output_tokens — it must not be added on top, or thinking gets billed twice.
315
+ */
208
316
  export function readUsage(raw) {
209
317
  const usage = (raw ?? {});
210
318
  const details = (usage['output_tokens_details'] ?? {});
@@ -1 +1 @@
1
- {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"claude.js","sourceRoot":"","sources":["../../src/adapters/claude.ts"],"names":[],"mappings":"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"}
@@ -11,11 +11,18 @@ import { type TokenUsage } from '../schema.js';
11
11
  * {"type":"turn_context","payload":{"turn_id":"…","model":"gpt-5.4","effort":"high"}}
12
12
  * {"type":"event_msg","payload":{"type":"token_count","info":{
13
13
  * "total_token_usage":{…},"last_token_usage":{…}},"rate_limits":{"plan_type":"plus"}}}
14
- * {"type":"response_item","payload":{"type":"function_call","name":"shell",…}}
14
+ * {"type":"response_item","payload":{"type":"function_call","name":"exec_command",…}}
15
+ * {"type":"event_msg","payload":{"type":"exec_command_end","call_id":"…",
16
+ * "command":["/bin/zsh","-lc","…"],"exit_code":0,"duration":{"secs":1,"nanos":5e8},"status":"completed"}}
17
+ * {"type":"response_item","payload":{"type":"function_call_output","call_id":"…","output":"…"}}
15
18
  *
16
19
  * The important subtlety: token_count reports RUNNING TOTALS. These are emitted
17
20
  * as cumulative snapshots so the server treats them as a gauge, not a counter —
18
21
  * summing them would multiply a session's tokens by the number of snapshots.
22
+ * Per-turn deltas from `last_token_usage` were checked against real rollouts
23
+ * and do NOT reconcile to the final total (duplicate snapshots, resets), so the
24
+ * gauge stays; the price is that a mid-session model switch reports the whole
25
+ * total under both models (see docs/EVENT_SCHEMA.md).
19
26
  */
20
27
  export declare const CODEX_DIR: string;
21
28
  export declare class CodexAdapter implements AgentAdapter {
@@ -29,6 +36,13 @@ export declare class CodexAdapter implements AgentAdapter {
29
36
  private normalizeResponseItem;
30
37
  private wrap;
31
38
  }
39
+ /**
40
+ * Codex usage shape. reasoning_output_tokens is a SUBSET of output_tokens and
41
+ * must not be added on top. Likewise cached_input_tokens is a SUBSET of
42
+ * input_tokens (codex-rs: non_cached_input = input - cached), while the
43
+ * normalized shape keeps them exclusive the way Claude Code reports them —
44
+ * copying both verbatim billed every cached token twice.
45
+ */
32
46
  export declare function readCodexUsage(raw: unknown): TokenUsage;
33
47
  interface FileTouch {
34
48
  event_type: 'file.changed' | 'file.read';
@@ -1,9 +1,10 @@
1
- import { existsSync, readdirSync, readFileSync } from 'node:fs';
1
+ import { existsSync, readdirSync } from 'node:fs';
2
2
  import { homedir } from 'node:os';
3
3
  import { join } from 'node:path';
4
- import { num, safeJsonParse, str } from './types.js';
4
+ import { newestJsonl, num, readHeadLines, safeJsonParse, str } from './types.js';
5
5
  import { emptyUsage } from '../schema.js';
6
6
  import { deriveTitle } from '../sessions/title.js';
7
+ import { redact } from '../privacy/redact.js';
7
8
  /**
8
9
  * OpenAI Codex CLI adapter.
9
10
  *
@@ -15,11 +16,18 @@ import { deriveTitle } from '../sessions/title.js';
15
16
  * {"type":"turn_context","payload":{"turn_id":"…","model":"gpt-5.4","effort":"high"}}
16
17
  * {"type":"event_msg","payload":{"type":"token_count","info":{
17
18
  * "total_token_usage":{…},"last_token_usage":{…}},"rate_limits":{"plan_type":"plus"}}}
18
- * {"type":"response_item","payload":{"type":"function_call","name":"shell",…}}
19
+ * {"type":"response_item","payload":{"type":"function_call","name":"exec_command",…}}
20
+ * {"type":"event_msg","payload":{"type":"exec_command_end","call_id":"…",
21
+ * "command":["/bin/zsh","-lc","…"],"exit_code":0,"duration":{"secs":1,"nanos":5e8},"status":"completed"}}
22
+ * {"type":"response_item","payload":{"type":"function_call_output","call_id":"…","output":"…"}}
19
23
  *
20
24
  * The important subtlety: token_count reports RUNNING TOTALS. These are emitted
21
25
  * as cumulative snapshots so the server treats them as a gauge, not a counter —
22
26
  * summing them would multiply a session's tokens by the number of snapshots.
27
+ * Per-turn deltas from `last_token_usage` were checked against real rollouts
28
+ * and do NOT reconcile to the final total (duplicate snapshots, resets), so the
29
+ * gauge stays; the price is that a mid-session model switch reports the whole
30
+ * total under both models (see docs/EVENT_SCHEMA.md).
23
31
  */
24
32
  export const CODEX_DIR = process.env['CODEX_HOME'] ?? join(homedir(), '.codex');
25
33
  const SESSIONS_DIR = join(CODEX_DIR, 'sessions');
@@ -65,12 +73,19 @@ export class CodexAdapter {
65
73
  const occurredAt = str(raw['timestamp']);
66
74
  if (!type || !occurredAt)
67
75
  return [];
68
- const state = this.fileState.get(ctx.sourceFile) ?? {};
76
+ let state = this.fileState.get(ctx.sourceFile);
77
+ if (!state) {
78
+ // A daemon restart resumes mid-file, after session_meta was consumed.
79
+ // The rollout is named rollout-<ts>-<uuid>.jsonl and that uuid IS the
80
+ // session id (13/13 real files), so seed it from the name; model and
81
+ // cwd come back with the next turn_context.
82
+ state = { sessionId: /([0-9a-f-]{36})\.jsonl$/i.exec(ctx.sourceFile)?.[1], calls: new Map() };
83
+ this.fileState.set(ctx.sourceFile, state);
84
+ }
69
85
  if (type === 'session_meta') {
70
- state.sessionId = str(payload['id']);
86
+ state.sessionId = str(payload['id']) ?? state.sessionId;
71
87
  state.version = str(payload['cli_version']);
72
88
  state.cwd = str(payload['cwd']);
73
- this.fileState.set(ctx.sourceFile, state);
74
89
  if (!state.sessionId)
75
90
  return [];
76
91
  return [
@@ -83,7 +98,7 @@ export class CodexAdapter {
83
98
  }
84
99
  if (type === 'turn_context') {
85
100
  state.model = str(payload['model']) ?? state.model;
86
- this.fileState.set(ctx.sourceFile, state);
101
+ state.cwd ??= str(payload['cwd']);
87
102
  if (!state.sessionId || !state.model)
88
103
  return [];
89
104
  return [
@@ -129,11 +144,27 @@ export class CodexAdapter {
129
144
  ];
130
145
  }
131
146
  if (kind === 'exec_command_end') {
147
+ // The real shape: argv list, {secs,nanos} duration, numeric exit_code.
148
+ // This is also where an exec_command call terminates — its
149
+ // function_call_output is a bare string with no exit status.
150
+ const callId = str(payload['call_id']);
151
+ const exitCode = num(payload['exit_code']);
152
+ const duration = (payload['duration'] ?? {});
153
+ const durationMs = num(duration['secs']) * 1000 + Math.round(num(duration['nanos']) / 1e6);
154
+ const failed = exitCode !== 0 || str(payload['status']) === 'failed';
155
+ // The entry stays in `calls`: the function_call_output that must be
156
+ // ignored below may still be on its way.
157
+ const toolName = (callId && state.calls.get(callId)) ?? 'exec_command';
132
158
  return [
159
+ this.wrap(state, occurredAt, failed ? 'tool.failed' : 'tool.completed', {
160
+ tool_name: toolName,
161
+ tool_call_id: callId,
162
+ duration_ms: durationMs,
163
+ }),
133
164
  this.wrap(state, occurredAt, 'command.executed', {
134
- command: str(payload['command']) ?? 'shell',
135
- exit_code: num(payload['exit_code']),
136
- duration_ms: num(payload['duration_ms']),
165
+ command: joinCommand(payload['command']) ?? str(payload['command']) ?? 'shell',
166
+ exit_code: exitCode,
167
+ duration_ms: durationMs,
137
168
  }),
138
169
  ];
139
170
  }
@@ -141,10 +172,14 @@ export class CodexAdapter {
141
172
  return [this.wrap(state, occurredAt, 'agent.turn.ended', { turn_id: str(payload['turn_id']) })];
142
173
  }
143
174
  if (kind === 'error' || kind === 'stream_error') {
175
+ const message = str(payload['message']);
144
176
  return [
145
177
  this.wrap(state, occurredAt, 'error', {
146
178
  error_kind: kind,
147
- message: str(payload['message'])?.slice(0, 1000),
179
+ // Redacted before the truncation, for the same reason deriveTitle is:
180
+ // a cut through a secret leaves two halves that match no pattern, so
181
+ // the privacy pipeline's later pass over `message` ships the fragment.
182
+ message: message === undefined ? undefined : redact(message).text.slice(0, 1000),
148
183
  }),
149
184
  ];
150
185
  }
@@ -155,10 +190,14 @@ export class CodexAdapter {
155
190
  // Recent Codex builds report the same tool calls as `custom_tool_call`
156
191
  // (apply_patch and the JS `exec` tool both arrive that way).
157
192
  if (kind === 'function_call' || kind === 'custom_tool_call') {
193
+ const toolName = str(payload['name']) ?? 'unknown';
194
+ const callId = str(payload['call_id']);
195
+ if (callId)
196
+ state.calls.set(callId, toolName);
158
197
  const events = [
159
198
  this.wrap(state, occurredAt, 'tool.started', {
160
- tool_name: str(payload['name']) ?? 'unknown',
161
- tool_call_id: str(payload['call_id']),
199
+ tool_name: toolName,
200
+ tool_call_id: callId,
162
201
  }),
163
202
  ];
164
203
  for (const file of fileTouches(payload)) {
@@ -168,12 +207,22 @@ export class CodexAdapter {
168
207
  return events;
169
208
  }
170
209
  if (kind === 'function_call_output' || kind === 'custom_tool_call_output') {
171
- const output = (payload['output'] ?? {});
172
- const failed = output['success'] === false || num(output['exit_code']) !== 0;
210
+ const callId = str(payload['call_id']);
211
+ const toolName = (callId && state.calls.get(callId)) ?? str(payload['name']) ?? 'unknown';
212
+ // exec_command terminates on its exec_command_end (which carries the exit
213
+ // status); the two arrive in either order, so key on the tool, not on order.
214
+ if (toolName === 'exec_command')
215
+ return [];
216
+ if (callId)
217
+ state.calls.delete(callId);
218
+ // `output` is a string (or a content list for custom tools), never an
219
+ // object. Only the shell_command tool prefixes it with the exit status.
220
+ const exitHeader = /^Exit code: (\d+)/.exec(str(payload['output']) ?? '');
221
+ const failed = exitHeader !== null && exitHeader[1] !== '0';
173
222
  return [
174
223
  this.wrap(state, occurredAt, failed ? 'tool.failed' : 'tool.completed', {
175
- tool_name: str(payload['name']) ?? 'unknown',
176
- tool_call_id: str(payload['call_id']),
224
+ tool_name: toolName,
225
+ tool_call_id: callId,
177
226
  }),
178
227
  ];
179
228
  }
@@ -197,10 +246,6 @@ export class CodexAdapter {
197
246
  };
198
247
  }
199
248
  }
200
- /**
201
- * Codex usage shape. reasoning_output_tokens is a SUBSET of output_tokens and
202
- * must not be added on top.
203
- */
204
249
  /** Newest rollout's `session_meta.cli_version`, if one can be found cheaply. */
205
250
  function readCliVersion() {
206
251
  try {
@@ -208,17 +253,17 @@ function readCliVersion() {
208
253
  for (const year of years.slice(0, 2)) {
209
254
  for (const month of readdirSync(join(SESSIONS_DIR, year)).sort().reverse()) {
210
255
  for (const day of readdirSync(join(SESSIONS_DIR, year, month)).sort().reverse()) {
211
- const dir = join(SESSIONS_DIR, year, month, day);
212
- for (const file of readdirSync(dir).filter((f) => f.endsWith('.jsonl')).sort().reverse()) {
213
- // session_meta is the first line of a rollout, so a short read suffices.
214
- for (const line of readFileSync(join(dir, file), 'utf8').split('\n', 5)) {
215
- const parsed = safeJsonParse(line);
216
- if (!parsed || str(parsed['type']) !== 'session_meta')
217
- continue;
218
- const version = str(parsed['payload']?.['cli_version']);
219
- if (version)
220
- return version;
221
- }
256
+ const file = newestJsonl(join(SESSIONS_DIR, year, month, day));
257
+ if (!file)
258
+ continue;
259
+ // session_meta is the first line of a rollout, so the head suffices.
260
+ for (const line of readHeadLines(file)) {
261
+ const parsed = safeJsonParse(line);
262
+ if (!parsed || str(parsed['type']) !== 'session_meta')
263
+ continue;
264
+ const version = str(parsed['payload']?.['cli_version']);
265
+ if (version)
266
+ return version;
222
267
  }
223
268
  }
224
269
  }
@@ -229,12 +274,20 @@ function readCliVersion() {
229
274
  }
230
275
  return undefined;
231
276
  }
277
+ /**
278
+ * Codex usage shape. reasoning_output_tokens is a SUBSET of output_tokens and
279
+ * must not be added on top. Likewise cached_input_tokens is a SUBSET of
280
+ * input_tokens (codex-rs: non_cached_input = input - cached), while the
281
+ * normalized shape keeps them exclusive the way Claude Code reports them —
282
+ * copying both verbatim billed every cached token twice.
283
+ */
232
284
  export function readCodexUsage(raw) {
233
285
  const usage = (raw ?? {});
286
+ const cached = num(usage['cached_input_tokens']);
234
287
  return {
235
288
  ...emptyUsage(),
236
- input_tokens: num(usage['input_tokens']),
237
- cached_input_tokens: num(usage['cached_input_tokens']),
289
+ input_tokens: Math.max(0, num(usage['input_tokens']) - cached),
290
+ cached_input_tokens: cached,
238
291
  output_tokens: num(usage['output_tokens']),
239
292
  reasoning_output_tokens: num(usage['reasoning_output_tokens']),
240
293
  };