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 @@
1
+ {"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/analysis/tokens.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,229 @@
1
+ import { createHash, createHmac } from 'node:crypto';
2
+ import { MAX_MCP_SERVERS_PER_EVENT, MAX_MCP_TOOLS_PER_SERVER, MAX_SKILLS_PER_EVENT, MAX_USAGE_NAME_LENGTH, MCP_LATENCY_BUCKETS_MS, } from '../protocol-types.js';
3
+ /*
4
+ * Skill and MCP usage (docs/briefs/skills-and-mcp-stats.md). Adapters count PLAIN names here; the
5
+ * context's queue applies the deployment's project-naming mode (`hashUsageNames`) before anything is
6
+ * written to the queue, so in hashed mode plain names never leave the worker process.
7
+ */
8
+ /** `mcp__<server>__<tool>` → its parts; null for any other tool. */
9
+ export function parseMcpTool(name) {
10
+ const m = /^mcp__(.+?)__(.+)$/i.exec(name);
11
+ return m ? { server: m[1], tool: m[2] } : null;
12
+ }
13
+ /** A name as the wire format accepts it: no whitespace / control characters, ≤ 128 chars. Null when empty. */
14
+ export function usageName(raw) {
15
+ const s = raw.trim().replace(/[\s\u0000-\u001f\u007f]+/g, '-');
16
+ return s ? s.slice(0, MAX_USAGE_NAME_LENGTH) : null;
17
+ }
18
+ export function addSkill(counts, raw, source, n = 1) {
19
+ const name = usageName(raw.replace(/^\//, ''));
20
+ if (!name || n <= 0)
21
+ return;
22
+ const c = (counts[name] ??= { model: 0, user: 0 });
23
+ c[source] += n;
24
+ }
25
+ export function addMcp(counts, server, tool, n = 1) {
26
+ const s = usageName(server);
27
+ const t = usageName(tool);
28
+ if (!s || !t || n <= 0)
29
+ return;
30
+ const tools = (counts[s] ??= {});
31
+ tools[t] = (tools[t] ?? 0) + n;
32
+ }
33
+ /** MCP counts from raw tool name → call count (tools that are not MCP tools are ignored). */
34
+ export function mcpFromTools(tools) {
35
+ const out = {};
36
+ for (const [name, n] of Object.entries(tools)) {
37
+ const p = parseMcpTool(name);
38
+ if (p)
39
+ addMcp(out, p.server, p.tool, n);
40
+ }
41
+ return out;
42
+ }
43
+ export function mergeSkills(a, b) {
44
+ const out = {};
45
+ for (const src of [a, b]) {
46
+ for (const [name, c] of Object.entries(src ?? {})) {
47
+ addSkill(out, name, 'model', c.model);
48
+ addSkill(out, name, 'user', c.user);
49
+ }
50
+ }
51
+ return out;
52
+ }
53
+ export function mergeMcp(a, b) {
54
+ const out = {};
55
+ for (const src of [a, b]) {
56
+ for (const [server, tools] of Object.entries(src ?? {}))
57
+ for (const [tool, n] of Object.entries(tools))
58
+ addMcp(out, server, tool, n);
59
+ }
60
+ return out;
61
+ }
62
+ const int = (v) => (Number.isFinite(v) && v > 0 ? Math.round(v) : 0);
63
+ /** Entries with the largest totals first, capped at `max` (ties: by name, so the cut is deterministic). */
64
+ const top = (entries, total, max) => entries.sort((x, y) => total(y[1]) - total(x[1]) || (x[0] < y[0] ? -1 : 1)).slice(0, max);
65
+ /** Wire-ready skill counts (integers, names cleaned, ≤ 100 entries); undefined when empty. */
66
+ export function normalizeSkills(skills) {
67
+ const clean = mergeSkills(undefined, skills);
68
+ const entries = Object.entries(clean)
69
+ .map(([k, c]) => [k, { model: int(c.model), user: int(c.user) }])
70
+ .filter(([, c]) => c.model + c.user > 0);
71
+ if (!entries.length)
72
+ return undefined;
73
+ return Object.fromEntries(top(entries, (c) => c.model + c.user, MAX_SKILLS_PER_EVENT));
74
+ }
75
+ /** Wire-ready MCP counts (integers, names cleaned, ≤ 50 servers × 100 tools); undefined when empty. */
76
+ export function normalizeMcp(mcp) {
77
+ const clean = mergeMcp(undefined, mcp);
78
+ const servers = [];
79
+ for (const [server, tools] of Object.entries(clean)) {
80
+ const kept = top(Object.entries(tools).map(([t, n]) => [t, int(n)]).filter(([, n]) => n > 0), (n) => n, MAX_MCP_TOOLS_PER_SERVER);
81
+ if (kept.length)
82
+ servers.push([server, Object.fromEntries(kept)]);
83
+ }
84
+ if (!servers.length)
85
+ return undefined;
86
+ const sum = (t) => Object.values(t).reduce((a, b) => a + b, 0);
87
+ return Object.fromEntries(top(servers, sum, MAX_MCP_SERVERS_PER_EVENT));
88
+ }
89
+ /**
90
+ * Hashed-mode name: `sha256:` + HMAC-SHA256(deployment salt, input), or plain SHA-256 without a salt (the
91
+ * server's fallback for a plain name arriving in hashed mode uses the same plain input). Inputs are
92
+ * namespaced so a skill and a server with the same name get different hashes:
93
+ * `skill:<name>`, `mcp:<server>`, `mcp:<server>/<tool>`.
94
+ */
95
+ export function hashUsageName(input, salt) {
96
+ const hex = salt ? createHmac('sha256', salt).update(input).digest('hex') : createHash('sha256').update(input).digest('hex');
97
+ return `sha256:${hex}`;
98
+ }
99
+ const isHashed = (s) => /^sha256:[0-9a-f]{64}$/.test(s);
100
+ export function hashSkills(skills, salt) {
101
+ const out = {};
102
+ for (const [name, c] of Object.entries(skills)) {
103
+ const key = isHashed(name) ? name : hashUsageName(`skill:${name}`, salt);
104
+ const cur = (out[key] ??= { model: 0, user: 0 });
105
+ cur.model += c.model;
106
+ cur.user += c.user;
107
+ }
108
+ return out;
109
+ }
110
+ export function hashMcp(mcp, salt) {
111
+ const out = {};
112
+ for (const [server, tools] of Object.entries(mcp)) {
113
+ const s = isHashed(server) ? server : hashUsageName(`mcp:${server}`, salt);
114
+ const dst = (out[s] ??= {});
115
+ for (const [tool, n] of Object.entries(tools)) {
116
+ const t = isHashed(tool) ? tool : hashUsageName(`mcp:${server}/${tool}`, salt);
117
+ dst[t] = (dst[t] ?? 0) + n;
118
+ }
119
+ }
120
+ return out;
121
+ }
122
+ /** Applies the deployment's naming mode to the skill / MCP names of turn and run events (plain mode: unchanged). */
123
+ export function applyUsageNaming(events, naming, salt) {
124
+ if (naming !== 'hashed')
125
+ return [...events];
126
+ return events.map((e) => {
127
+ if ((e.type !== 'turn' && e.type !== 'run') || (!e.skills && !e.mcp && !e.mcp_stats))
128
+ return e;
129
+ return {
130
+ ...e,
131
+ ...(e.skills ? { skills: hashSkills(e.skills, salt) } : {}),
132
+ ...(e.mcp ? { mcp: hashMcp(e.mcp, salt) } : {}),
133
+ ...(e.mcp_stats ? { mcp_stats: hashMcpStats(e.mcp_stats, salt) } : {}),
134
+ };
135
+ });
136
+ }
137
+ /**
138
+ * Codex skill use: the model opens a skill by reading its `SKILL.md` with a shell command (Codex has no
139
+ * skill tool). Returns the skill's directory name, or null when the command does not read a SKILL.md.
140
+ */
141
+ export function skillReadBy(command) {
142
+ if (!/\b(cat|sed|head|tail|less|more|bat|nl|awk|Get-Content|type)\b/.test(command))
143
+ return null;
144
+ const m = /([A-Za-z0-9._:-]+)[\\/]SKILL\.md\b/.exec(command);
145
+ return m ? m[1] : null;
146
+ }
147
+ // ------------------------------------------------------------------ MCP reliability (errors, denials, latency)
148
+ const emptyStats = () => ({ errors: 0, denied: 0, ms: 0, buckets: [0, 0, 0, 0, 0] });
149
+ /** Index of the latency bucket for a call that took `ms`. */
150
+ export function latencyBucket(ms) {
151
+ const i = MCP_LATENCY_BUCKETS_MS.findIndex((b) => ms < b);
152
+ return i < 0 ? MCP_LATENCY_BUCKETS_MS.length : i;
153
+ }
154
+ /**
155
+ * Records the result of one MCP call. A denied call (the user refused it) is counted as denied only, not as an
156
+ * error; its wall time is not latency. Every other result with a known duration adds it to the histogram.
157
+ */
158
+ export function addMcpResult(stats, server, tool, r) {
159
+ const s = usageName(server);
160
+ const t = usageName(tool);
161
+ if (!s || !t)
162
+ return;
163
+ const cur = ((stats[s] ??= {})[t] ??= emptyStats());
164
+ if (r.denied) {
165
+ cur.denied += 1;
166
+ return;
167
+ }
168
+ if (r.error)
169
+ cur.errors += 1;
170
+ if (r.ms === null)
171
+ return; // no timing known: an error still counts, latency does not
172
+ const ms = Math.max(0, Math.round(r.ms));
173
+ cur.ms += ms;
174
+ cur.buckets[latencyBucket(ms)] += 1;
175
+ }
176
+ function addStats(into, x) {
177
+ into.errors += int(x.errors);
178
+ into.denied += int(x.denied);
179
+ into.ms += int(x.ms);
180
+ for (let i = 0; i < into.buckets.length; i++)
181
+ into.buckets[i] += int(x.buckets?.[i] ?? 0);
182
+ }
183
+ export function mergeMcpStats(a, b) {
184
+ const out = {};
185
+ for (const src of [a, b]) {
186
+ for (const [server, tools] of Object.entries(src ?? {})) {
187
+ for (const [tool, st] of Object.entries(tools)) {
188
+ const s = usageName(server);
189
+ const t = usageName(tool);
190
+ if (s && t)
191
+ addStats(((out[s] ??= {})[t] ??= emptyStats()), st);
192
+ }
193
+ }
194
+ }
195
+ return out;
196
+ }
197
+ const statTotal = (x) => x.errors + x.denied + x.buckets.reduce((a, b) => a + b, 0);
198
+ /** Wire-ready stats (integers, ≤ 50 servers × 100 tools, most active kept); undefined when empty. */
199
+ export function normalizeMcpStats(stats) {
200
+ const clean = mergeMcpStats(undefined, stats);
201
+ const servers = [];
202
+ for (const [server, tools] of Object.entries(clean)) {
203
+ const kept = top(Object.entries(tools).filter(([, x]) => statTotal(x) > 0), statTotal, MAX_MCP_TOOLS_PER_SERVER);
204
+ if (kept.length)
205
+ servers.push([server, Object.fromEntries(kept)]);
206
+ }
207
+ if (!servers.length)
208
+ return undefined;
209
+ const sum = (t) => Object.values(t).reduce((a, x) => a + statTotal(x), 0);
210
+ return Object.fromEntries(top(servers, sum, MAX_MCP_SERVERS_PER_EVENT));
211
+ }
212
+ export function hashMcpStats(stats, salt) {
213
+ const out = {};
214
+ for (const [server, tools] of Object.entries(stats)) {
215
+ const s = isHashed(server) ? server : hashUsageName(`mcp:${server}`, salt);
216
+ for (const [tool, st] of Object.entries(tools)) {
217
+ const t = isHashed(tool) ? tool : hashUsageName(`mcp:${server}/${tool}`, salt);
218
+ addStats(((out[s] ??= {})[t] ??= emptyStats()), st);
219
+ }
220
+ }
221
+ return out;
222
+ }
223
+ /**
224
+ * Claude Code's tool-result text when the user (or the permission mode) refused a tool call. From Claude Code's
225
+ * known messages; not yet seen in a recorded fixture.
226
+ */
227
+ const DENIED_RE = /^(The user doesn't want to proceed with this tool use|Permission for this tool use was denied|\[Request interrupted by user for tool use\])/;
228
+ export const isDeniedResult = (text) => DENIED_RE.test(text.trimStart());
229
+ //# sourceMappingURL=usage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage.js","sourceRoot":"","sources":["../../src/analysis/usage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ import { rmSync } from 'node:fs';
2
+ import { endpointHost, tokenFingerprint } from './config.js';
3
+ import { readJsonFile, writeJsonAtomic } from './fsutil.js';
4
+ import { collectorConfigPath } from './paths.js';
5
+ import { TEAM_SLUG_RE } from './protocol-types.js';
6
+ const isObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
7
+ const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
8
+ /**
9
+ * Validates a collector-config body (cache or response): null without a known `project_naming`. Keeps the
10
+ * salt (≥ 16 chars) and the appendix A fields that are well formed; anything malformed is left out.
11
+ */
12
+ export function parseCollectorConfigValue(raw) {
13
+ if (!isObject(raw) || (raw.project_naming !== 'plain' && raw.project_naming !== 'hashed'))
14
+ return null;
15
+ const salt = typeof raw.project_salt === 'string' && raw.project_salt.length >= 16 ? raw.project_salt : null;
16
+ const d = raw.deployment;
17
+ const deployment = isObject(d) && nonEmpty(d.name) && nonEmpty(d.slug) ? { name: d.name, slug: d.slug } : null;
18
+ const u = raw.user;
19
+ const user = isObject(u) && (u.email === null || nonEmpty(u.email)) && (u.kind === 'person' || u.kind === 'service')
20
+ ? { email: u.email, name: typeof u.name === 'string' ? u.name : '', kind: u.kind }
21
+ : null;
22
+ const teams = Array.isArray(raw.teams)
23
+ ? raw.teams.filter((t) => isObject(t) && typeof t.slug === 'string' && TEAM_SLUG_RE.test(t.slug) && nonEmpty(t.name)).map((t) => ({ slug: t.slug, name: t.name }))
24
+ : null;
25
+ const primary = raw.primary_team === null ? null : typeof raw.primary_team === 'string' && TEAM_SLUG_RE.test(raw.primary_team) ? raw.primary_team : undefined;
26
+ const t = raw.token;
27
+ const token = isObject(t) && (t.source === 'device' || t.source === 'manual') && (t.expires_at === null || (nonEmpty(t.expires_at) && Number.isFinite(Date.parse(t.expires_at))))
28
+ ? { expires_at: t.expires_at, label: nonEmpty(t.label) ? t.label : null, source: t.source }
29
+ : null;
30
+ return {
31
+ project_naming: raw.project_naming,
32
+ min_collector_version: String(raw.min_collector_version ?? '0.0.0'),
33
+ ...(salt ? { project_salt: salt } : {}),
34
+ ...(deployment ? { deployment } : {}),
35
+ ...(user ? { user } : {}),
36
+ ...(teams ? { teams } : {}),
37
+ ...(primary !== undefined ? { primary_team: primary } : {}),
38
+ ...(token ? { token } : {}),
39
+ };
40
+ }
41
+ const cachePath = (paths, entry) => collectorConfigPath(paths, endpointHost(entry.endpoint));
42
+ /** The server's cache, or null when missing, unreadable or written for another token / endpoint. */
43
+ export function readCache(paths, entry) {
44
+ let raw;
45
+ try {
46
+ raw = readJsonFile(cachePath(paths, entry));
47
+ }
48
+ catch {
49
+ return null;
50
+ }
51
+ if (!isObject(raw) || raw.token_fp !== tokenFingerprint(entry.token) || raw.endpoint !== entry.endpoint)
52
+ return null;
53
+ const value = parseCollectorConfigValue(raw.value);
54
+ return {
55
+ token_fp: raw.token_fp,
56
+ endpoint: raw.endpoint,
57
+ ...(typeof raw.fetched_at === 'string' ? { fetched_at: raw.fetched_at } : {}),
58
+ ...(value ? { value } : {}),
59
+ ...(typeof raw.failed_at === 'string' ? { failed_at: raw.failed_at } : {}),
60
+ };
61
+ }
62
+ /** Merges `patch` into the server's cache (a cache of another token is replaced). Returns the written file. */
63
+ export function writeCache(paths, entry, patch) {
64
+ const next = { ...(readCache(paths, entry) ?? {}), ...patch, token_fp: tokenFingerprint(entry.token), endpoint: entry.endpoint };
65
+ writeJsonAtomic(cachePath(paths, entry), next, 0o600);
66
+ return next;
67
+ }
68
+ /** The fetched value, or null when the server was never reached with this token (C4). */
69
+ export function cachedValue(paths, entry) {
70
+ const c = readCache(paths, entry);
71
+ return c?.value && typeof c.fetched_at === 'string' ? c.value : null;
72
+ }
73
+ export function dropCache(paths, endpoint) {
74
+ try {
75
+ rmSync(collectorConfigPath(paths, endpointHost(endpoint)), { force: true });
76
+ }
77
+ catch {
78
+ /* already gone, or a host that never had a cache */
79
+ }
80
+ }
81
+ //# sourceMappingURL=cc-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cc-cache.js","sourceRoot":"","sources":["../src/cc-cache.ts"],"names":[],"mappings":"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"}
package/dist/cli.js ADDED
@@ -0,0 +1,128 @@
1
+ /**
2
+ * ai-obs CLI entry. ZERO runtime dependencies: only node: built-ins may be imported here and in
3
+ * anything this file imports. Command modules are imported lazily so the `hook` fast path loads as
4
+ * little code as possible (< 100 ms budget).
5
+ */
6
+ import { aiObsPaths, resolveHome } from './paths.js';
7
+ export const COMMANDS = ['init', 'login', 'link', 'token', 'doctor', 'status', 'flush', 'uninstall', 'live', 'hook'];
8
+ const defaultIo = {
9
+ out: (line) => process.stdout.write(`${line}\n`),
10
+ err: (line) => process.stderr.write(`${line}\n`),
11
+ };
12
+ export const USAGE = `Usage: ai-obs <command> [options]
13
+
14
+ Commands:
15
+ login [--server <url>] [--token <token>|-] [--no-browser] [--label <name>] [--keep-queue]
16
+ log this machine in to an ai-obs server: approve a code in the browser,
17
+ or paste a token (- reads it from stdin). One token per server; queued
18
+ events of another account are set aside (--keep-queue: sent as you)
19
+ init [--project] [--project-dir <dir>] [--harness claude-code,codex] [--token <token> --endpoint <url> [--label <name>]]
20
+ install the harness hooks (user level; --project: this repository);
21
+ with --token: log in without a browser first
22
+ link --team <slug> [--server <url>] [--local] [--project-dir <dir>]
23
+ write .ai-obs.json at the repository root (--local: .ai-obs.local.json,
24
+ git-ignored): the server and team this repository reports to
25
+ token list servers, accounts, token expiry and state
26
+ token remove <server> forget a server's token (its queued events stay on this machine)
27
+ doctor check servers, tokens, this repository, harnesses, hooks and queue
28
+ status show servers, this repository's server and team, queue and last send
29
+ live [--cwd] [--once] watch this machine's running sessions: status, elapsed, tokens, ≈ cost (local only; q quits)
30
+ flush [--wait <seconds>] send queued events now (also retries a refused token)
31
+ uninstall [--purge [--yes]] [--project-dir <dir>]
32
+ remove hooks (--purge: also delete ~/.ai-obs: tokens and queue)
33
+ hook <harness> <hook> (internal) called by harness hooks; always exits 0
34
+
35
+ Global options:
36
+ --home <dir> collector home (default ~/.ai-obs, or $AI_OBS_HOME)
37
+
38
+ Environment:
39
+ AI_OBS_HOME, AI_OBS_ENDPOINT (default --server for login / init --token), AI_OBS_SUMMARIZING (internal guard)`;
40
+ const isCommand = (s) => COMMANDS.includes(s);
41
+ /** Removes `--home <dir>` / `--home=<dir>` from argv. */
42
+ export function extractHome(argv) {
43
+ const rest = [];
44
+ let home;
45
+ for (let i = 0; i < argv.length; i++) {
46
+ const a = argv[i];
47
+ if (a === '--home')
48
+ home = argv[++i];
49
+ else if (a.startsWith('--home='))
50
+ home = a.slice(7);
51
+ else
52
+ rest.push(a);
53
+ }
54
+ return { home, rest };
55
+ }
56
+ /** Dispatches a subcommand and resolves to the process exit code. */
57
+ export async function main(argv, io = defaultIo, deps = {}) {
58
+ if (process.env.AI_OBS_SUMMARIZING)
59
+ return 0; // recursion guard, see bin/ai-obs.js
60
+ const { home, rest } = extractHome(argv);
61
+ const [command, ...args] = rest;
62
+ const paths = deps.paths ?? aiObsPaths(resolveHome(home));
63
+ if (home)
64
+ process.env.AI_OBS_HOME = paths.root; // children (worker) inherit it
65
+ if (command === 'hook') {
66
+ // Fast path: no other command modules, never fails the harness.
67
+ const { runHook } = await import('./hook.js');
68
+ return runHook(args, { paths, ...(deps.env ? { env: deps.env } : {}) });
69
+ }
70
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
71
+ io.out(USAGE);
72
+ return command ? 0 : 1;
73
+ }
74
+ if (command === '--version' || command === '-v') {
75
+ const { COLLECTOR_VERSION } = await import('./version.js');
76
+ io.out(COLLECTOR_VERSION);
77
+ return 0;
78
+ }
79
+ if (!isCommand(command)) {
80
+ io.err(`ai-obs: unknown command "${command}"\n\n${USAGE}`);
81
+ return 2;
82
+ }
83
+ const full = { ...deps, paths };
84
+ const { UsageError, upgradeBanner, migrateNow } = await import('./commands/common.js');
85
+ try {
86
+ // A 0.2 – 0.4 home is migrated by the first command that finds the worker lock free (else by the worker),
87
+ // together with the copied hook runtime (an older one would drop every hook job on the new config).
88
+ if (command !== 'live' && command !== 'uninstall')
89
+ migrateNow(full, io);
90
+ // C6: while nothing can be recorded, say so first (init and login say it themselves).
91
+ if (command !== 'init' && command !== 'login' && command !== 'live') {
92
+ const { loadConfig } = await import('./config.js');
93
+ const banner = upgradeBanner(loadConfig(paths));
94
+ if (banner)
95
+ io.err(banner);
96
+ }
97
+ switch (command) {
98
+ case 'init':
99
+ return await (await import('./commands/init.js')).initCommand(args, io, full);
100
+ case 'login':
101
+ return await (await import('./commands/login.js')).loginCommand(args, io, full);
102
+ case 'link':
103
+ return await (await import('./commands/link.js')).linkCommand(args, io, full);
104
+ case 'token':
105
+ return await (await import('./commands/token.js')).tokenCommand(args, io, full);
106
+ case 'doctor':
107
+ return await (await import('./commands/doctor.js')).doctorCommand(args, io, full);
108
+ case 'status':
109
+ return await (await import('./commands/status.js')).statusCommand(args, io, full);
110
+ case 'flush':
111
+ return await (await import('./commands/flush.js')).flushCommand(args, io, full);
112
+ case 'uninstall':
113
+ return await (await import('./commands/uninstall.js')).uninstallCommand(args, io, full);
114
+ case 'live':
115
+ return await (await import('./commands/live.js')).liveCommand(args, io, full);
116
+ }
117
+ }
118
+ catch (err) {
119
+ if (err instanceof UsageError) {
120
+ io.err(`ai-obs ${command}: ${err.message}\n\n${USAGE}`);
121
+ return 2;
122
+ }
123
+ io.err(`ai-obs ${command}: ${err instanceof Error ? err.message : String(err)}`);
124
+ return 1;
125
+ }
126
+ return 2;
127
+ }
128
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}