ai-obs-cli 0.0.0-stage → 0.5.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 (155) hide show
  1. package/README.md +666 -2
  2. package/bin/ai-obs.js +8 -0
  3. package/dist/adapters/claude-code/analyze.js +189 -0
  4. package/dist/adapters/claude-code/analyze.js.map +1 -0
  5. package/dist/adapters/claude-code/detect.js +60 -0
  6. package/dist/adapters/claude-code/detect.js.map +1 -0
  7. package/dist/adapters/claude-code/handlers.js +183 -0
  8. package/dist/adapters/claude-code/handlers.js.map +1 -0
  9. package/dist/adapters/claude-code/index.js +55 -0
  10. package/dist/adapters/claude-code/index.js.map +1 -0
  11. package/dist/adapters/claude-code/run-links.js +53 -0
  12. package/dist/adapters/claude-code/run-links.js.map +1 -0
  13. package/dist/adapters/claude-code/session.js +427 -0
  14. package/dist/adapters/claude-code/session.js.map +1 -0
  15. package/dist/adapters/claude-code/settings.js +161 -0
  16. package/dist/adapters/claude-code/settings.js.map +1 -0
  17. package/dist/adapters/claude-code/state.js +66 -0
  18. package/dist/adapters/claude-code/state.js.map +1 -0
  19. package/dist/adapters/claude-code/subagents.js +246 -0
  20. package/dist/adapters/claude-code/subagents.js.map +1 -0
  21. package/dist/adapters/claude-code/transcript.js +309 -0
  22. package/dist/adapters/claude-code/transcript.js.map +1 -0
  23. package/dist/adapters/codex/accumulator.js +135 -0
  24. package/dist/adapters/codex/accumulator.js.map +1 -0
  25. package/dist/adapters/codex/detect.js +93 -0
  26. package/dist/adapters/codex/detect.js.map +1 -0
  27. package/dist/adapters/codex/hooks-config.js +158 -0
  28. package/dist/adapters/codex/hooks-config.js.map +1 -0
  29. package/dist/adapters/codex/index.js +270 -0
  30. package/dist/adapters/codex/index.js.map +1 -0
  31. package/dist/adapters/codex/locate.js +72 -0
  32. package/dist/adapters/codex/locate.js.map +1 -0
  33. package/dist/adapters/codex/records.js +194 -0
  34. package/dist/adapters/codex/records.js.map +1 -0
  35. package/dist/adapters/codex/rollout.js +72 -0
  36. package/dist/adapters/codex/rollout.js.map +1 -0
  37. package/dist/adapters/codex/session.js +212 -0
  38. package/dist/adapters/codex/session.js.map +1 -0
  39. package/dist/adapters/codex/subagents.js +139 -0
  40. package/dist/adapters/codex/subagents.js.map +1 -0
  41. package/dist/adapters/codex/summarize.js +84 -0
  42. package/dist/adapters/codex/summarize.js.map +1 -0
  43. package/dist/adapters/codex/tools.js +145 -0
  44. package/dist/adapters/codex/tools.js.map +1 -0
  45. package/dist/adapters/hook-command.js +94 -0
  46. package/dist/adapters/hook-command.js.map +1 -0
  47. package/dist/adapters/index.js +12 -0
  48. package/dist/adapters/index.js.map +1 -0
  49. package/dist/adapters/types.js +2 -0
  50. package/dist/adapters/types.js.map +1 -0
  51. package/dist/analysis/corrections.js +79 -0
  52. package/dist/analysis/corrections.js.map +1 -0
  53. package/dist/analysis/digest.js +16 -0
  54. package/dist/analysis/digest.js.map +1 -0
  55. package/dist/analysis/outcome.js +76 -0
  56. package/dist/analysis/outcome.js.map +1 -0
  57. package/dist/analysis/phases.js +203 -0
  58. package/dist/analysis/phases.js.map +1 -0
  59. package/dist/analysis/summaries.js +350 -0
  60. package/dist/analysis/summaries.js.map +1 -0
  61. package/dist/analysis/tokens.js +67 -0
  62. package/dist/analysis/tokens.js.map +1 -0
  63. package/dist/analysis/usage.js +229 -0
  64. package/dist/analysis/usage.js.map +1 -0
  65. package/dist/cc-cache.js +81 -0
  66. package/dist/cc-cache.js.map +1 -0
  67. package/dist/cli.js +128 -0
  68. package/dist/cli.js.map +1 -0
  69. package/dist/commands/common.js +235 -0
  70. package/dist/commands/common.js.map +1 -0
  71. package/dist/commands/doctor.js +193 -0
  72. package/dist/commands/doctor.js.map +1 -0
  73. package/dist/commands/flush.js +131 -0
  74. package/dist/commands/flush.js.map +1 -0
  75. package/dist/commands/init.js +119 -0
  76. package/dist/commands/init.js.map +1 -0
  77. package/dist/commands/link.js +171 -0
  78. package/dist/commands/link.js.map +1 -0
  79. package/dist/commands/live.js +130 -0
  80. package/dist/commands/live.js.map +1 -0
  81. package/dist/commands/login.js +397 -0
  82. package/dist/commands/login.js.map +1 -0
  83. package/dist/commands/status.js +155 -0
  84. package/dist/commands/status.js.map +1 -0
  85. package/dist/commands/token.js +92 -0
  86. package/dist/commands/token.js.map +1 -0
  87. package/dist/commands/uninstall.js +56 -0
  88. package/dist/commands/uninstall.js.map +1 -0
  89. package/dist/config.js +305 -0
  90. package/dist/config.js.map +1 -0
  91. package/dist/context.js +109 -0
  92. package/dist/context.js.map +1 -0
  93. package/dist/delivery.js +151 -0
  94. package/dist/delivery.js.map +1 -0
  95. package/dist/dotfile.js +187 -0
  96. package/dist/dotfile.js.map +1 -0
  97. package/dist/events.js +259 -0
  98. package/dist/events.js.map +1 -0
  99. package/dist/fsutil.js +50 -0
  100. package/dist/fsutil.js.map +1 -0
  101. package/dist/git.js +139 -0
  102. package/dist/git.js.map +1 -0
  103. package/dist/hook.js +147 -0
  104. package/dist/hook.js.map +1 -0
  105. package/dist/http.js +35 -0
  106. package/dist/http.js.map +1 -0
  107. package/dist/jobs.js +53 -0
  108. package/dist/jobs.js.map +1 -0
  109. package/dist/live/claude-code.js +226 -0
  110. package/dist/live/claude-code.js.map +1 -0
  111. package/dist/live/codex.js +91 -0
  112. package/dist/live/codex.js.map +1 -0
  113. package/dist/live/monitor.js +229 -0
  114. package/dist/live/monitor.js.map +1 -0
  115. package/dist/live/render.js +92 -0
  116. package/dist/live/render.js.map +1 -0
  117. package/dist/lock.js +93 -0
  118. package/dist/lock.js.map +1 -0
  119. package/dist/log.js +36 -0
  120. package/dist/log.js.map +1 -0
  121. package/dist/migrate.js +109 -0
  122. package/dist/migrate.js.map +1 -0
  123. package/dist/nudge.js +231 -0
  124. package/dist/nudge.js.map +1 -0
  125. package/dist/paths.js +73 -0
  126. package/dist/paths.js.map +1 -0
  127. package/dist/pk-cache.js +110 -0
  128. package/dist/pk-cache.js.map +1 -0
  129. package/dist/prices.js +45 -0
  130. package/dist/prices.js.map +1 -0
  131. package/dist/project-key.js +144 -0
  132. package/dist/project-key.js.map +1 -0
  133. package/dist/protocol-types.js +30 -0
  134. package/dist/protocol-types.js.map +1 -0
  135. package/dist/queue.js +649 -0
  136. package/dist/queue.js.map +1 -0
  137. package/dist/routing.js +122 -0
  138. package/dist/routing.js.map +1 -0
  139. package/dist/runtime.js +54 -0
  140. package/dist/runtime.js.map +1 -0
  141. package/dist/sender.js +559 -0
  142. package/dist/sender.js.map +1 -0
  143. package/dist/state.js +59 -0
  144. package/dist/state.js.map +1 -0
  145. package/dist/ulid.js +73 -0
  146. package/dist/ulid.js.map +1 -0
  147. package/dist/version.js +26 -0
  148. package/dist/version.js.map +1 -0
  149. package/dist/warnings.js +71 -0
  150. package/dist/warnings.js.map +1 -0
  151. package/dist/worker-main.js +14 -0
  152. package/dist/worker-main.js.map +1 -0
  153. package/dist/worker.js +295 -0
  154. package/dist/worker.js.map +1 -0
  155. package/package.json +25 -4
@@ -0,0 +1,226 @@
1
+ import { closeSync, fstatSync, openSync, readSync } from 'node:fs';
2
+ import { analyzeEntries, workflowKey } from '../adapters/claude-code/analyze.js';
3
+ import { addLine } from '../adapters/claude-code/session.js';
4
+ import { agentsOfToolUses, listAgents } from '../adapters/claude-code/subagents.js';
5
+ import { readTranscript } from '../adapters/claude-code/transcript.js';
6
+ import { mergeUsage } from '../analysis/tokens.js';
7
+ /**
8
+ * The last tool of a turn known only by its de-duplicated tool names (first-use order): exact when a single tool
9
+ * was used, else unknown.
10
+ */
11
+ export const soleTool = (names) => (names.length === 1 ? names[0] : null);
12
+ /** Sub-agent directory listing is repeated at most this often (or when the turn launches more agents). */
13
+ const SUBAGENT_LIST_MS = 5000;
14
+ /** A transcript with no state file is read from its last 8 MB only. */
15
+ export const SCAN_TAIL_BYTES = 8 * 1024 * 1024;
16
+ const CWD_SCAN_BYTES = 64 * 1024;
17
+ /**
18
+ * Analysis is re-run over ALL entries of a segment (token de-duplication works within one call only, tokens.ts),
19
+ * so it is cached by entry count: a poll that read nothing new costs nothing.
20
+ */
21
+ const aggCache = new WeakMap();
22
+ function aggOf(entries) {
23
+ const hit = aggCache.get(entries);
24
+ if (hit && hit.n === entries.length)
25
+ return hit.agg;
26
+ const agg = analyzeEntries(entries);
27
+ aggCache.set(entries, { n: entries.length, agg });
28
+ return agg;
29
+ }
30
+ /**
31
+ * Working / idle and the totals of one turn's entries (a prompt segment, see session.ts `addLine`).
32
+ * Working = the last activity (prompt, assistant, tool result, interrupt) has no end-of-turn record at or after it
33
+ * and is not a user interrupt, an interrupted tool result or an API-error placeholder.
34
+ */
35
+ export function segmentFacts(entries, subagentUsage = []) {
36
+ const agg = aggOf(entries);
37
+ let lastAct = null;
38
+ let lastStop = null;
39
+ let lastEntryAt = 0;
40
+ let lastTool = null;
41
+ for (const e of entries) {
42
+ lastEntryAt = Math.max(lastEntryAt, e.at);
43
+ if (e.k === 'stop') {
44
+ if (!lastStop || e.at >= lastStop.at)
45
+ lastStop = e;
46
+ continue;
47
+ }
48
+ if (e.k === 'expansion')
49
+ continue;
50
+ if (!lastAct || e.at >= lastAct.at)
51
+ lastAct = e;
52
+ if (e.k === 'assistant')
53
+ for (const b of e.blocks)
54
+ if (b.t === 'tool_use')
55
+ lastTool = b.name;
56
+ }
57
+ const working = lastAct !== null &&
58
+ !(lastStop && lastStop.at >= lastAct.at) &&
59
+ lastAct.k !== 'interrupt' &&
60
+ !(lastAct.k === 'tool_result' && lastAct.userInterrupt) &&
61
+ !(lastAct.k === 'assistant' && lastAct.synthetic);
62
+ const since = working ? (entries[0]?.at ?? 0) : (lastStop?.at ?? lastAct?.at ?? entries[0]?.at ?? 0);
63
+ return {
64
+ working,
65
+ since,
66
+ lastEntryAt,
67
+ usage: mergeUsage(agg.usage, subagentUsage),
68
+ tools: Object.values(agg.tools).reduce((a, b) => a + b, 0),
69
+ subagents: Object.keys(agg.agentCalls).length,
70
+ lastTool,
71
+ };
72
+ }
73
+ /**
74
+ * Usage of the sub-agents (and Workflow agents) a turn launched, read from their transcripts with one in-memory
75
+ * cursor per agent file. Only the current turn's agents are kept: earlier turns' are forgotten on the next poll.
76
+ */
77
+ export class SubagentTails {
78
+ now;
79
+ path = '';
80
+ metas = new Map();
81
+ listedAt = Number.NEGATIVE_INFINITY;
82
+ listedCalls = -1;
83
+ agents = new Map();
84
+ constructor(now = Date.now) {
85
+ this.now = now;
86
+ }
87
+ /** `agentCallKeys`: the turn's `agentCalls` keys (Agent tool_use ids and `wf:<run id>` keys). */
88
+ poll(transcriptPath, agentCallKeys) {
89
+ if (!agentCallKeys.length) {
90
+ this.agents.clear();
91
+ return [];
92
+ }
93
+ const t = this.now();
94
+ if (transcriptPath !== this.path || agentCallKeys.length !== this.listedCalls || t - this.listedAt >= SUBAGENT_LIST_MS) {
95
+ this.path = transcriptPath;
96
+ this.metas = listAgents(transcriptPath);
97
+ this.listedAt = t;
98
+ this.listedCalls = agentCallKeys.length;
99
+ }
100
+ const picked = new Map();
101
+ for (const a of agentsOfToolUses(this.metas, agentCallKeys))
102
+ picked.set(a.agentId, a);
103
+ const keys = new Set(agentCallKeys);
104
+ for (const a of this.metas.values())
105
+ if (a.workflowId && keys.has(workflowKey(a.workflowId)))
106
+ picked.set(a.agentId, a);
107
+ for (const id of this.agents.keys())
108
+ if (!picked.has(id))
109
+ this.agents.delete(id);
110
+ const lists = [];
111
+ for (const a of picked.values()) {
112
+ const tail = this.agents.get(a.agentId) ?? { cursor: 0, entries: [] };
113
+ const read = readTranscript(a.file, tail.cursor);
114
+ if (read.reset)
115
+ tail.entries = [];
116
+ for (const l of read.lines)
117
+ tail.entries.push(l.entry);
118
+ tail.cursor = read.end;
119
+ this.agents.set(a.agentId, tail);
120
+ if (tail.entries.length)
121
+ lists.push(aggOf(tail.entries).usage);
122
+ }
123
+ return mergeUsage(...lists);
124
+ }
125
+ }
126
+ /**
127
+ * Follows one transcript from its own cursor. Keeps only the latest prompt segment (the current turn when it is
128
+ * working, the last one when idle) and the entries before any prompt (the continuation of an earlier turn).
129
+ */
130
+ export class ClaudeSessionTail {
131
+ init;
132
+ cursor;
133
+ pre = [];
134
+ segments = [];
135
+ read = {};
136
+ sub;
137
+ subSig = '[]';
138
+ subUsage = [];
139
+ constructor(init) {
140
+ this.init = init;
141
+ this.cursor = init.offset;
142
+ this.sub = new SubagentTails(init.now);
143
+ }
144
+ /** Reads what was appended since the last poll; true when anything changed. */
145
+ poll() {
146
+ const res = readTranscript(this.init.transcriptPath, this.cursor, this.init.sessionId);
147
+ let changed = res.lines.length > 0 || res.reset;
148
+ if (res.reset) {
149
+ this.pre = [];
150
+ this.segments = [];
151
+ this.subSig = '[]';
152
+ this.subUsage = [];
153
+ }
154
+ for (const l of res.lines)
155
+ addLine(l, this.pre, this.segments);
156
+ this.cursor = res.end;
157
+ if (res.titles.custom || res.titles.ai) {
158
+ const next = { ...this.read, ...res.titles };
159
+ if (next.custom !== this.read.custom || next.ai !== this.read.ai)
160
+ changed = true;
161
+ this.read = next;
162
+ }
163
+ if (this.segments.length > 1)
164
+ this.segments.splice(0, this.segments.length - 1);
165
+ if (this.segments.length)
166
+ this.pre = [];
167
+ const calls = this.current() ? Object.keys(aggOf(this.current()).agentCalls) : [];
168
+ const usage = this.sub.poll(this.init.transcriptPath, calls);
169
+ const sig = JSON.stringify(usage);
170
+ if (sig !== this.subSig) {
171
+ this.subSig = sig;
172
+ this.subUsage = usage;
173
+ changed = true;
174
+ }
175
+ return changed;
176
+ }
177
+ current() {
178
+ const seg = this.segments.at(-1);
179
+ if (seg)
180
+ return seg.entries;
181
+ return this.pre.length ? this.pre : null;
182
+ }
183
+ /** Whether a prompt segment (a whole turn) is held, not just entries that continue an earlier turn. */
184
+ hasPrompt() {
185
+ return this.segments.length > 0;
186
+ }
187
+ /** Facts of the latest segment; null while nothing was read. */
188
+ facts() {
189
+ const entries = this.current();
190
+ return entries ? segmentFacts(entries, this.subUsage) : null;
191
+ }
192
+ /** The titles read from the transcript since the cursor started (ADR-0026). */
193
+ titles() {
194
+ return this.read;
195
+ }
196
+ /** The best title read: `/rename` over the generated one. */
197
+ title() {
198
+ return this.read.custom ?? this.read.ai ?? null;
199
+ }
200
+ }
201
+ /** The first `cwd` of a transcript (the first 64 KB are looked at); null when there is none. */
202
+ export function transcriptCwd(path) {
203
+ let fd;
204
+ try {
205
+ fd = openSync(path, 'r');
206
+ }
207
+ catch {
208
+ return null;
209
+ }
210
+ try {
211
+ const buf = Buffer.alloc(Math.min(CWD_SCAN_BYTES, fstatSync(fd).size));
212
+ const n = readSync(fd, buf, 0, buf.length, 0);
213
+ const m = /"cwd":("(?:[^"\\]|\\.)*")/.exec(buf.toString('utf8', 0, n));
214
+ if (!m?.[1])
215
+ return null;
216
+ const cwd = JSON.parse(m[1]);
217
+ return typeof cwd === 'string' && cwd ? cwd : null;
218
+ }
219
+ catch {
220
+ return null;
221
+ }
222
+ finally {
223
+ closeSync(fd);
224
+ }
225
+ }
226
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../src/live/claude-code.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,91 @@
1
+ import { mergeUsage } from '../analysis/tokens.js';
2
+ import { mtimeMs } from '../adapters/codex/locate.js';
3
+ import { parseRolloutLine } from '../adapters/codex/records.js';
4
+ import { readNewLines } from '../adapters/codex/rollout.js';
5
+ import { applyItems } from '../adapters/codex/session.js';
6
+ import { soleTool } from './claude-code.js';
7
+ /**
8
+ * Read-only live view of a Codex session (ADR-0027, `ai-obs live`). The hook state is cloned and the rollout is
9
+ * replayed into the clone from the state's offset with the adapter's own reducer, so open / closed turns and token
10
+ * deltas follow the same rules as the collector. Nothing is emitted and nothing is written back. Sub-agent usage
11
+ * comes from the hook state only (NULL_ENV resolves none), so the monitor rebuilds the tail whenever the hook
12
+ * writes newer state.
13
+ */
14
+ export const NULL_ENV = {
15
+ harness: 'codex',
16
+ emit() { },
17
+ project: async () => undefined,
18
+ children: () => ({ runs: [], usage: {}, missing: [] }),
19
+ };
20
+ const sum = (o) => Object.values(o ?? {}).reduce((a, b) => a + b, 0);
21
+ const ms = (t) => (t instanceof Date ? t.getTime() : typeof t === 'number' ? t : Date.parse(t));
22
+ export class CodexSessionTail {
23
+ lastTool;
24
+ state;
25
+ cursor;
26
+ /** `lastTool`: the last tool call an earlier tail of this rollout read (kept when the tail is rebuilt). */
27
+ constructor(state, lastTool = null) {
28
+ this.lastTool = lastTool;
29
+ this.state = structuredClone(state);
30
+ this.cursor = state.offset;
31
+ }
32
+ /** The last tool call read from the rollout so far. */
33
+ lastToolSeen() {
34
+ return this.lastTool;
35
+ }
36
+ /** Reads and applies the rollout lines appended since the last poll; true when anything changed. */
37
+ async poll() {
38
+ const path = this.state.rolloutPath;
39
+ if (!path)
40
+ return false;
41
+ const r = readNewLines(path, this.cursor);
42
+ this.cursor = r.offset;
43
+ if (r.reset)
44
+ return true; // rewritten under us: skip to the end, as the collector does
45
+ const items = r.lines.map(parseRolloutLine).filter((i) => i !== null);
46
+ if (!items.length)
47
+ return false;
48
+ for (const i of items)
49
+ if (i.kind === 'tool_call')
50
+ this.lastTool = { name: i.name, at: i.at };
51
+ await applyItems(this.state, NULL_ENV, items);
52
+ return true;
53
+ }
54
+ /** The open turn (working), else the last emitted turn (idle). */
55
+ facts() {
56
+ const s = this.state;
57
+ // toolNames / tools keys are in first-use order: the true last tool is known only from the rollout read here
58
+ const toolIn = (from, to, names) => this.lastTool && this.lastTool.at >= from && this.lastTool.at <= to ? this.lastTool.name : soleTool(names);
59
+ const lastEntryAt = Math.max(s.lastActivityAt, mtimeMs(s.rolloutPath));
60
+ const open = s.open;
61
+ if (open) {
62
+ return {
63
+ working: true,
64
+ since: open.startedAt,
65
+ lastEntryAt,
66
+ usage: open.usage,
67
+ tools: sum(open.tools),
68
+ subagents: open.spawned.length,
69
+ lastTool: toolIn(open.startedAt, Number.POSITIVE_INFINITY, open.toolNames),
70
+ };
71
+ }
72
+ const last = s.emitted.at(-1);
73
+ if (last) {
74
+ return {
75
+ working: false,
76
+ since: ms(last.input.endedAt),
77
+ lastEntryAt,
78
+ usage: mergeUsage(last.mainUsage, ...Object.values(last.children)),
79
+ tools: sum(last.input.tools),
80
+ subagents: last.spawned.length,
81
+ lastTool: toolIn(ms(last.input.startedAt), ms(last.input.endedAt), Object.keys(last.input.tools ?? {})),
82
+ };
83
+ }
84
+ return { working: false, since: s.meta?.startedAt ?? s.lastActivityAt, lastEntryAt, usage: s.carry, tools: 0, subagents: 0, lastTool: null };
85
+ }
86
+ /** The session's working directory (session_meta, else the first hook's). */
87
+ cwd() {
88
+ return this.state.meta?.cwd ?? this.state.pkCwd ?? null;
89
+ }
90
+ }
91
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../src/live/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,229 @@
1
+ import { existsSync, readdirSync, statSync } from 'node:fs';
2
+ import { basename, join, sep } from 'node:path';
3
+ import { mergeUsage, totalTokens } from '../analysis/tokens.js';
4
+ import { harnessStateDir } from '../paths.js';
5
+ import { estimateUsageCost } from '../prices.js';
6
+ import { SessionStateStore } from '../state.js';
7
+ import { ClaudeSessionTail, SCAN_TAIL_BYTES, soleTool, transcriptCwd } from './claude-code.js';
8
+ import { CodexSessionTail } from './codex.js';
9
+ /**
10
+ * `ai-obs live` (ADR-0027): the sessions running on this machine, read from the hook state files (to find them and
11
+ * to know where to start) and the transcripts / rollouts themselves (for the live part). Read-only: nothing under
12
+ * ~/.ai-obs or the harness directories is ever written, and the hook state offsets are never moved.
13
+ */
14
+ /** Same thresholds as the dashboard's apps/web/src/lib/live/status.ts IDLE_MAX_MS (a test pins both literals). */
15
+ export const LIVE_IDLE_STALE_MS = 1_800_000;
16
+ /** = apps/web/src/lib/live/status.ts WORKING_MAX_MS */
17
+ export const LIVE_WORKING_STALE_MS = 7_200_000;
18
+ /** New sessions are looked for this often; known ones are polled on every refresh. */
19
+ const DISCOVERY_MS = 5000;
20
+ /** working: stale when now - since > 2 h; idle: stale when now - lastSignalAt >= 30 min. */
21
+ export function liveStatus(f, now) {
22
+ if (f.working)
23
+ return now - f.since > LIVE_WORKING_STALE_MS ? 'stale' : 'working';
24
+ return now - f.lastSignalAt >= LIVE_IDLE_STALE_MS ? 'stale' : 'idle';
25
+ }
26
+ /** Whether `cwd` is the directory `root` or inside it. */
27
+ export function inScope(cwd, root) {
28
+ if (!cwd)
29
+ return false;
30
+ return cwd === root || cwd.startsWith(root.endsWith(sep) ? root : root + sep);
31
+ }
32
+ const UUID_JSONL = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.jsonl$/i;
33
+ /** A transcript without hook state is only followed while it was written this recently. */
34
+ const SCAN_MAX_AGE_MS = LIVE_IDLE_STALE_MS;
35
+ const safeStat = (path) => {
36
+ try {
37
+ return statSync(path);
38
+ }
39
+ catch {
40
+ return null;
41
+ }
42
+ };
43
+ const safeReaddir = (dir) => {
44
+ try {
45
+ return readdirSync(dir);
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ };
51
+ /** Facts of a session whose current segment is not (or no longer) in memory: its last stored turn. */
52
+ function factsOfTurn(t) {
53
+ return {
54
+ working: false,
55
+ since: t.agg.endedAt,
56
+ lastEntryAt: t.agg.endedAt,
57
+ usage: mergeUsage(t.agg.usage, t.runUsage),
58
+ tools: Object.values(t.agg.tools).reduce((a, b) => a + b, 0),
59
+ subagents: Object.keys(t.agg.agentCalls).length,
60
+ lastTool: soleTool(t.agg.toolNames), // toolNames is first-use order, not the last tool
61
+ };
62
+ }
63
+ export class LiveMonitor {
64
+ deps;
65
+ tracked = new Map();
66
+ discoveredAt = Number.NEGATIVE_INFINITY;
67
+ constructor(deps) {
68
+ this.deps = deps;
69
+ }
70
+ /** Finds new sessions (every 5 s), polls every known one and returns the rows: working, idle, then stale. */
71
+ async refresh() {
72
+ const now = this.deps.now();
73
+ if (now - this.discoveredAt >= DISCOVERY_MS) {
74
+ this.discover(now);
75
+ this.discoveredAt = now;
76
+ }
77
+ const rows = [];
78
+ for (const t of this.tracked.values()) {
79
+ try {
80
+ if (t.harness === 'claude-code')
81
+ t.tail.poll();
82
+ else
83
+ await t.tail.poll();
84
+ const row = this.rowOf(t, now);
85
+ if (row)
86
+ rows.push(row);
87
+ }
88
+ catch {
89
+ /* a file vanished or was unreadable this round: the next refresh tries again */
90
+ }
91
+ }
92
+ const rank = { working: 0, idle: 1, stale: 2 };
93
+ return rows.sort((a, b) => rank[a.status] - rank[b.status] ||
94
+ (a.status === 'working' ? a.since - b.since : b.since - a.since) ||
95
+ a.sessionId.localeCompare(b.sessionId));
96
+ }
97
+ // ---------------------------------------------------------------- discovery
98
+ discover(now) {
99
+ const found = new Map();
100
+ this.discoverClaude(now, found);
101
+ this.discoverCodex(now, found);
102
+ this.tracked.clear();
103
+ for (const [k, v] of found)
104
+ this.tracked.set(k, v);
105
+ }
106
+ discoverClaude(now, found) {
107
+ const store = new SessionStateStore(harnessStateDir(this.deps.paths, 'claude-code'));
108
+ for (const { sessionId: file, updatedAt } of store.list()) {
109
+ if (now - updatedAt >= LIVE_WORKING_STALE_MS)
110
+ continue;
111
+ const known = this.tracked.get(`claude-code:${file}`);
112
+ if (known?.harness === 'claude-code' && known.state && known.stateMtime === updatedAt) {
113
+ found.set(`claude-code:${known.sessionId}`, known);
114
+ continue;
115
+ }
116
+ const st = store.get(file);
117
+ if (!st || st.v !== 1 || st.ended || !st.transcriptPath)
118
+ continue;
119
+ const key = `claude-code:${st.sessionId}`;
120
+ const prev = this.tracked.get(key);
121
+ if (prev?.harness === 'claude-code' && prev.state && prev.state.transcriptPath === st.transcriptPath) {
122
+ found.set(key, { ...prev, state: st, stateMtime: updatedAt, cwd: st.cwd || prev.cwd });
123
+ continue;
124
+ }
125
+ found.set(key, {
126
+ harness: 'claude-code',
127
+ sessionId: st.sessionId,
128
+ tail: new ClaudeSessionTail({ sessionId: st.sessionId, transcriptPath: st.transcriptPath, offset: st.offset, now: this.deps.now }),
129
+ state: st,
130
+ stateMtime: updatedAt,
131
+ cwd: st.cwd || null,
132
+ });
133
+ }
134
+ if (this.deps.scanTranscripts === false)
135
+ return;
136
+ const projects = join(this.deps.claudeDir, 'projects');
137
+ for (const dir of safeReaddir(projects)) {
138
+ for (const name of safeReaddir(join(projects, dir))) {
139
+ if (!UUID_JSONL.test(name))
140
+ continue;
141
+ const sessionId = name.slice(0, -'.jsonl'.length);
142
+ const key = `claude-code:${sessionId}`;
143
+ if (found.has(key) || existsSync(store.path(sessionId)))
144
+ continue;
145
+ const path = join(projects, dir, name);
146
+ const stat = safeStat(path);
147
+ if (!stat || now - stat.mtimeMs >= SCAN_MAX_AGE_MS)
148
+ continue;
149
+ const prev = this.tracked.get(key);
150
+ if (prev?.harness === 'claude-code' && !prev.state) {
151
+ found.set(key, prev);
152
+ continue;
153
+ }
154
+ found.set(key, {
155
+ harness: 'claude-code',
156
+ sessionId,
157
+ tail: new ClaudeSessionTail({ sessionId, transcriptPath: path, offset: Math.max(0, stat.size - SCAN_TAIL_BYTES), now: this.deps.now }),
158
+ state: null,
159
+ stateMtime: 0,
160
+ cwd: transcriptCwd(path),
161
+ });
162
+ }
163
+ }
164
+ }
165
+ discoverCodex(now, found) {
166
+ const store = new SessionStateStore(harnessStateDir(this.deps.paths, 'codex'));
167
+ for (const { sessionId: file, updatedAt } of store.list()) {
168
+ if (now - updatedAt >= LIVE_WORKING_STALE_MS)
169
+ continue;
170
+ const known = this.tracked.get(`codex:${file}`);
171
+ if (known?.harness === 'codex' && known.stateMtime === updatedAt) {
172
+ found.set(`codex:${file}`, known);
173
+ continue;
174
+ }
175
+ const st = store.get(file);
176
+ if (!st || st.v !== 1 || st.ended || st.subagent || !st.rolloutPath)
177
+ continue;
178
+ const key = `codex:${file}`;
179
+ // The hook wrote newer state (a turn it closed, sub-agent usage it resolved): replay from it, not the old clone.
180
+ const prev = this.tracked.get(key);
181
+ const tail = new CodexSessionTail(st, prev?.harness === 'codex' && prev.state.rolloutPath === st.rolloutPath ? prev.tail.lastToolSeen() : null);
182
+ found.set(key, { harness: 'codex', sessionId: st.sessionId, tail, state: st, stateMtime: updatedAt, cwd: tail.cwd() });
183
+ }
184
+ }
185
+ // ---------------------------------------------------------------- rows
186
+ rowOf(t, now) {
187
+ let facts;
188
+ let title = null;
189
+ let seen;
190
+ let cwd = t.cwd;
191
+ if (t.harness === 'claude-code') {
192
+ const turn = t.state?.turns.at(-1);
193
+ facts = t.tail.facts();
194
+ // The turn finished before this monitor looked (or its prompt is out of reach): the stored last turn is complete.
195
+ if (turn && (!facts || (!facts.working && !t.tail.hasPrompt())))
196
+ facts = factsOfTurn(turn);
197
+ if (!facts && t.state) {
198
+ facts = { working: false, since: t.state.lastSeen, lastEntryAt: t.state.lastSeen, usage: [], tools: 0, subagents: 0, lastTool: null };
199
+ }
200
+ const titles = { ...t.state?.title, ...t.tail.titles() };
201
+ title = titles.custom ?? titles.ai ?? null;
202
+ seen = t.state?.lastSeen ?? 0;
203
+ }
204
+ else {
205
+ facts = t.tail.facts();
206
+ seen = t.state.lastActivityAt;
207
+ cwd = t.tail.cwd() ?? cwd; // known once the session_meta line was read
208
+ }
209
+ if (!facts)
210
+ return null;
211
+ const cost = estimateUsageCost(facts.usage);
212
+ return {
213
+ harness: t.harness,
214
+ sessionId: t.sessionId,
215
+ title,
216
+ project: cwd ? basename(cwd) : '',
217
+ cwd,
218
+ status: liveStatus({ working: facts.working, since: facts.since, lastSignalAt: Math.max(facts.lastEntryAt, seen) }, now),
219
+ since: facts.since,
220
+ usage: facts.usage,
221
+ tokens: facts.usage.reduce((n, u) => n + totalTokens(u), 0),
222
+ cost: { usd: cost.usd, partial: cost.partial },
223
+ tools: facts.tools,
224
+ subagents: facts.subagents,
225
+ lastTool: facts.lastTool,
226
+ };
227
+ }
228
+ }
229
+ //# sourceMappingURL=monitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"monitor.js","sourceRoot":"","sources":["../../src/live/monitor.ts"],"names":[],"mappings":"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"}