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,235 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { hostname } from 'node:os';
3
+ import { parseArgs } from 'node:util';
4
+ import { daysLeft, endpointHost, isExpired } from '../config.js';
5
+ import { readDelivery, recordDropped, serverDelivery } from '../delivery.js';
6
+ import { acquireLock, tryLock } from '../lock.js';
7
+ import { createLogger } from '../log.js';
8
+ import { migrateHome, needsMigration } from '../migrate.js';
9
+ import { identityOfRef, QueueStore } from '../queue.js';
10
+ import { loadRouting, resolveStream } from '../routing.js';
11
+ export class UsageError extends Error {
12
+ }
13
+ /** Strict option parsing; unknown flags or missing values throw UsageError. */
14
+ export function parseOptions(args, options, allowPositionals = false) {
15
+ try {
16
+ return parseArgs({ args: [...args], options, strict: true, allowPositionals });
17
+ }
18
+ catch (err) {
19
+ throw new UsageError(err instanceof Error ? err.message : String(err));
20
+ }
21
+ }
22
+ export function formatBytes(n) {
23
+ if (n < 1024)
24
+ return `${n} B`;
25
+ if (n < 1024 * 1024)
26
+ return `${(n / 1024).toFixed(1)} KB`;
27
+ return `${(n / 1024 / 1024).toFixed(1)} MB`;
28
+ }
29
+ export function ago(iso, now = Date.now()) {
30
+ if (!iso)
31
+ return 'never';
32
+ const s = Math.round((now - Date.parse(iso)) / 1000);
33
+ if (!Number.isFinite(s))
34
+ return 'unknown';
35
+ if (s < 60)
36
+ return `${s}s ago`;
37
+ if (s < 3600)
38
+ return `${Math.round(s / 60)}m ago`;
39
+ if (s < 86400)
40
+ return `${Math.round(s / 3600)}h ago`;
41
+ return `${Math.round(s / 86400)}d ago`;
42
+ }
43
+ export const nowOf = (deps) => deps.now?.() ?? Date.now();
44
+ /** Left-aligned columns separated by two spaces (trailing spaces trimmed). */
45
+ export function table(rows) {
46
+ const widths = [];
47
+ for (const r of rows)
48
+ r.forEach((c, i) => (widths[i] = Math.max(widths[i] ?? 0, c.length)));
49
+ return rows.map((r) => r.map((c, i) => c.padEnd(widths[i] ?? 0)).join(' ').trimEnd());
50
+ }
51
+ /** "a, b, c" with at most `max` items, then "… and N more". */
52
+ export function listSome(items, max = 10) {
53
+ const shown = items.slice(0, max);
54
+ const more = items.length - shown.length;
55
+ return `${shown.join(', ')}${more > 0 ? ` … and ${more} more` : ''}`;
56
+ }
57
+ /** The line every command except `hook`, `init`, `login` and `live` prints while nothing can be recorded (C6). */
58
+ export function upgradeBanner(config) {
59
+ if (!config || config.servers.length)
60
+ return null;
61
+ return '! not logged in to any ai-obs server: nothing is recorded. Run `ai-obs login --server <url>`.';
62
+ }
63
+ export const BUSY_MESSAGE = 'the background worker is busy (it may be summarizing); try again in a minute. Nothing was changed.';
64
+ /**
65
+ * C24: runs `fn` holding worker.lock (waits up to `lockWaitMs`, default 30 s). Null when the lock could
66
+ * not be taken: the busy message is printed and nothing ran.
67
+ */
68
+ export async function withWriteLock(deps, io, fn) {
69
+ const release = await acquireLock(deps.paths.workerLock, deps.lockWaitMs ?? 30_000, 15 * 60_000);
70
+ if (!release) {
71
+ io.err(`✗ ${BUSY_MESSAGE}`);
72
+ return null;
73
+ }
74
+ try {
75
+ return { value: await fn() };
76
+ }
77
+ finally {
78
+ release();
79
+ }
80
+ }
81
+ /**
82
+ * Migrates a 0.2 – 0.4 home (config.json v2, projects.json, `o-` / `t-` streams) when the worker lock is free
83
+ * right now, printing what changed; otherwise the background worker does it on its next run. An older copied
84
+ * hook runtime is refreshed first (migrateHome), or nothing is migrated.
85
+ */
86
+ export function migrateNow(deps, io) {
87
+ try {
88
+ if (!needsMigration(deps.paths))
89
+ return;
90
+ const release = tryLock(deps.paths.workerLock, 15 * 60_000);
91
+ if (!release)
92
+ return;
93
+ try {
94
+ const opts = { log: createLogger(deps.paths, 'cli'), now: new Date(nowOf(deps)), ...(deps.installRuntime ? { refreshRuntime: deps.installRuntime } : {}) };
95
+ for (const note of migrateHome(deps.paths, opts))
96
+ io.err(`ai-obs: ${note}`);
97
+ }
98
+ finally {
99
+ release();
100
+ }
101
+ }
102
+ catch {
103
+ /* the worker retries */
104
+ }
105
+ }
106
+ /** The queue as streams, with fresh routing (C17) and the drop counters. */
107
+ export function openStore(paths) {
108
+ return new QueueStore(paths.queue, { routing: () => loadRouting(paths), dropped: (d) => recordDropped(paths, d) });
109
+ }
110
+ /** The device-login page can be opened here: not over SSH; on Linux only with a display. */
111
+ export function canOpenBrowser(env) {
112
+ if (env.SSH_CONNECTION || env.SSH_TTY)
113
+ return false;
114
+ if (process.platform === 'darwin' || process.platform === 'win32')
115
+ return true;
116
+ return Boolean(env.DISPLAY || env.WAYLAND_DISPLAY);
117
+ }
118
+ export function defaultOpenBrowser(url) {
119
+ const cmd = process.platform === 'darwin' ? 'open' : process.platform === 'win32' ? 'explorer' : 'xdg-open';
120
+ try {
121
+ const child = spawn(cmd, [url], { detached: true, stdio: 'ignore' });
122
+ child.on('error', () => { });
123
+ child.unref();
124
+ }
125
+ catch {
126
+ /* no browser: the URL is printed anyway */
127
+ }
128
+ }
129
+ export const defaultHostname = () => hostname();
130
+ /** Reads all of stdin (a piped token), giving up after `timeoutMs`; '' on a terminal. */
131
+ export function readProcessStdin(timeoutMs = 2000) {
132
+ if (process.stdin.isTTY)
133
+ return Promise.resolve('');
134
+ return new Promise((resolve) => {
135
+ let data = '';
136
+ const finish = () => {
137
+ clearTimeout(timer);
138
+ process.stdin.removeAllListeners('data');
139
+ process.stdin.pause();
140
+ resolve(data);
141
+ };
142
+ const timer = setTimeout(finish, timeoutMs);
143
+ process.stdin.setEncoding('utf8');
144
+ process.stdin.on('data', (c) => {
145
+ data += c;
146
+ if (data.length > 4096)
147
+ finish();
148
+ });
149
+ process.stdin.once('end', finish);
150
+ process.stdin.once('error', finish);
151
+ });
152
+ }
153
+ /** Strips terminal control characters from server-derived text before it is printed. */
154
+ export function terminalSafe(s) {
155
+ let out = '';
156
+ for (const ch of s) {
157
+ const c = ch.codePointAt(0);
158
+ const control = (c < 0x20 && c !== 0x09) || (c >= 0x7f && c <= 0x9f) || c === 0x200e || c === 0x200f || (c >= 0x202a && c <= 0x202e) || (c >= 0x2066 && c <= 0x2069);
159
+ if (!control)
160
+ out += ch;
161
+ }
162
+ return out;
163
+ }
164
+ /** STATE column / status line of a server (no network). */
165
+ export function serverState(view, deps, s, nowMs) {
166
+ const st = serverDelivery(readDelivery(deps.paths), s);
167
+ if (isExpired(s, nowMs))
168
+ return { short: `EXPIRED: run \`ai-obs login --server ${s.endpoint}\``, problem: true };
169
+ if (st.blocked?.status === 401)
170
+ return { short: `REJECTED (401, expired or revoked): run \`ai-obs login --server ${s.endpoint}\``, problem: true };
171
+ if (st.blocked?.status === 403)
172
+ return { short: `refused (403: ${st.blocked.message || 'access denied'}); \`ai-obs flush\` retries`, problem: true };
173
+ if (st.next_attempt_at && Date.parse(st.next_attempt_at) > nowMs)
174
+ return { short: `retrying (${st.last_error ?? 'send failed'})`, problem: true };
175
+ const days = daysLeft(s, nowMs);
176
+ const expiring = days !== null && days <= 14 ? `; expires in ${days} day${days === 1 ? '' : 's'}: run \`ai-obs login --server ${s.endpoint}\`` : '';
177
+ if (!st.last_success_at)
178
+ return { short: `never sent${expiring}`, problem: false };
179
+ return { short: `ok, last send ${ago(st.last_success_at, nowMs)}${expiring}`, problem: false };
180
+ }
181
+ /** "dev@acme.com · SPECTADO · mac-dev, expires 2027-01-22" */
182
+ export function describeServer(s) {
183
+ const who = s.email ?? (s.source ? 'service user' : '(not checked yet)');
184
+ const exp = s.expires_at ? `expires ${s.expires_at.slice(0, 10)}` : s.source ? 'no expiry' : 'expiry unknown until the next send';
185
+ return [who, s.deployment?.name ?? '(deployment unknown)', `${s.label ? `${s.label}, ` : ''}${exp}`].map(terminalSafe).join(' · ');
186
+ }
187
+ export const hostOf = endpointHost;
188
+ /** Resolves every non-empty stream and counts the result. */
189
+ export function summarizeQueue(stats, view) {
190
+ const s = { stats, sendable: 0, sendableOldestAt: null, kept: 0, perServer: {}, blocked: {}, byReason: {}, noServer: {}, byKey: new Map(), unknown: [] };
191
+ for (const st of stats.streams) {
192
+ const ref = st.stream;
193
+ const events = st.events;
194
+ if (ref.pk !== undefined)
195
+ s.byKey.set(ref.pk, (s.byKey.get(ref.pk) ?? 0) + events);
196
+ if (ref.kind === 'unknown')
197
+ s.unknown.push({ dir: ref.dir, events });
198
+ const r = view ? resolveStream(view, identityOfRef(ref)) : { kind: 'held', reason: 'no-server', endpoint: ref.endpoint };
199
+ if (r.kind === 'server') {
200
+ const ep = r.server.endpoint;
201
+ s.perServer[ep] = (s.perServer[ep] ?? 0) + events;
202
+ const usable = view && !Object.prototype.hasOwnProperty.call(view.blocked, endpointHost(ep)) && !isExpired(r.server, view.nowMs);
203
+ if (!usable) {
204
+ s.blocked[ep] = (s.blocked[ep] ?? 0) + events;
205
+ s.kept += events;
206
+ }
207
+ else {
208
+ s.sendable += events;
209
+ if (st.oldestAt !== null)
210
+ s.sendableOldestAt = Math.min(s.sendableOldestAt ?? Infinity, st.oldestAt);
211
+ }
212
+ continue;
213
+ }
214
+ s.kept += events;
215
+ s.byReason[r.reason] = (s.byReason[r.reason] ?? 0) + events;
216
+ if (r.reason === 'no-server')
217
+ s.noServer[r.endpoint ?? ''] = (s.noServer[r.endpoint ?? ''] ?? 0) + events;
218
+ }
219
+ return s;
220
+ }
221
+ /** Short words for held reasons (status / flush / doctor). */
222
+ export const HELD_LABEL = {
223
+ 'no-server': 'no server to send to',
224
+ unresolved: 'repository could not be read yet (retried on the next send)',
225
+ 'pre-upgrade': 'queued by ai-obs 0.1, never sent',
226
+ legacy: 'recorded by ai-obs 0.4 or older; converted on the next worker run',
227
+ 'unknown-stream': 'queue directory without a readable stream.json (`ai-obs doctor`)',
228
+ };
229
+ /** One line per endpoint whose events wait for a server (status, doctor). */
230
+ export function noServerLines(q) {
231
+ return Object.entries(q.noServer).map(([ep, n]) => ep === ''
232
+ ? `${n} events of repositories without a server (several are registered): run \`ai-obs link --server <url> --team <slug>\` in each`
233
+ : `${n} events for ${ep}, which this machine is not logged in to: run \`ai-obs login --server ${ep}\``);
234
+ }
235
+ //# sourceMappingURL=common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/commands/common.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,193 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { ADAPTERS } from '../adapters/index.js';
3
+ import { hookRuntimeProblems } from '../adapters/hook-command.js';
4
+ import { readCache, writeCache } from '../cc-cache.js';
5
+ import { daysLeft, endpointHost, isExpired } from '../config.js';
6
+ import { clearBlocked, droppedLine, readDelivery, readDropped, serverDelivery } from '../delivery.js';
7
+ import { gitTopLevel } from '../git.js';
8
+ import { listJobs } from '../jobs.js';
9
+ import { loadRouting } from '../routing.js';
10
+ import { checkEndpoint, rejectedMessage, syncServerEntry } from '../sender.js';
11
+ import { COLLECTOR_VERSION, compareVersions } from '../version.js';
12
+ import { ago, formatBytes, nowOf, openStore, parseOptions, summarizeQueue, terminalSafe } from './common.js';
13
+ import { checkRepository, keptLines, staleRuntime } from './status.js';
14
+ const LOCAL_HTTP = /^http:\/\/(localhost|127\.0\.0\.1|\[::1\])(:|\/|$)/;
15
+ const DROPPED_SHOWN_MS = 30 * 24 * 3600_000;
16
+ const MAX_QUEUE_BYTES = 50 * 1024 * 1024;
17
+ /** `ai-obs doctor` — every check prints ✓ / ! / ✗; exit 1 when any ✗. */
18
+ export async function doctorCommand(args, io, deps) {
19
+ parseOptions(args, {});
20
+ let failed = 0;
21
+ const ok = (s) => io.out(`✓ ${s}`);
22
+ const warn = (s) => io.out(`! ${s}`);
23
+ const bad = (s) => {
24
+ failed++;
25
+ io.out(`✗ ${s}`);
26
+ };
27
+ const nowMs = nowOf(deps);
28
+ io.out(`ai-obs doctor (collector ${COLLECTOR_VERSION}, node ${process.version})`);
29
+ // 1. Config
30
+ let view = loadRouting(deps.paths, nowMs);
31
+ if (!view) {
32
+ bad(`no valid config at ${deps.paths.config} — run \`ai-obs login --server <url>\``);
33
+ return 1;
34
+ }
35
+ const config = view.config;
36
+ if (!config.servers.length) {
37
+ bad('not logged in to any server — run `ai-obs login --server <url>`');
38
+ return 1;
39
+ }
40
+ ok(`config ${deps.paths.config}: machine ${config.machine_id}, ${config.servers.length} server(s)`);
41
+ // 2. Per server: reachable, token, expiry, version, naming
42
+ for (const s of config.servers) {
43
+ const host = endpointHost(s.endpoint);
44
+ const tag = (t) => `${host}: ${t}`;
45
+ if (s.endpoint.startsWith('http://') && !LOCAL_HTTP.test(s.endpoint))
46
+ warn(tag('endpoint uses plain http: the token is sent unencrypted'));
47
+ if (isExpired(s, nowMs))
48
+ bad(tag(`token expired on ${s.expires_at.slice(0, 10)}: run \`ai-obs login --server ${s.endpoint}\``));
49
+ else {
50
+ const days = daysLeft(s, nowMs);
51
+ if (days !== null && days <= 14)
52
+ warn(tag(`token expires in ${days} day${days === 1 ? '' : 's'} (${s.expires_at.slice(0, 10)}): run \`ai-obs login --server ${s.endpoint}\``));
53
+ else if (days !== null)
54
+ ok(tag(`token expires ${s.expires_at.slice(0, 10)} (${days} days)`));
55
+ }
56
+ const check = await checkEndpoint({ endpoint: s.endpoint, token: s.token, ...(deps.transport ? { transport: deps.transport } : {}) });
57
+ if (!check.reachable)
58
+ bad(tag(`unreachable: ${check.error}`));
59
+ else if (check.status === 401)
60
+ bad(tag(rejectedMessage(s.endpoint)));
61
+ else if (check.status === 403)
62
+ bad(tag(`access denied (HTTP 403${check.serverError ? `: ${check.serverError}` : ''})`));
63
+ else if (check.status === 429)
64
+ warn(tag('rate limited: try again in a minute'));
65
+ else if (!check.value)
66
+ bad(tag(`unexpected response from collector-config (HTTP ${check.status})`));
67
+ if (check.value) {
68
+ const value = check.value;
69
+ ok(tag(`reachable, token valid (${terminalSafe(value.deployment?.name ?? '?')}, ${terminalSafe(value.user ? (value.user.email ?? `service user ${value.user.name}`) : (s.email ?? '?'))})`));
70
+ try {
71
+ writeCache(deps.paths, s, { fetched_at: new Date(nowMs).toISOString(), value, failed_at: undefined });
72
+ clearBlocked(deps.paths, s); // refused until the next manual flush / doctor succeeds
73
+ syncServerEntry(deps.paths, s, value); // e-mail, deployment and expiry of the entry, as the sender does
74
+ }
75
+ catch {
76
+ /* read-only home: the checks still stand */
77
+ }
78
+ if (value.teams)
79
+ ok(tag(`teams: ${terminalSafe(value.teams.map((t) => t.slug).join(', ') || 'none')}${value.primary_team ? ` (primary ${terminalSafe(value.primary_team)})` : ''}`));
80
+ const min = value.min_collector_version;
81
+ if (compareVersions(COLLECTOR_VERSION, min) < 0)
82
+ bad(tag(`collector ${COLLECTOR_VERSION} is older than the server minimum ${min}`));
83
+ else
84
+ ok(tag(`collector version ${COLLECTOR_VERSION} ≥ server minimum ${min}`));
85
+ ok(tag(`project naming: ${value.project_naming} (fetched now)`));
86
+ }
87
+ else {
88
+ const cached = readCache(deps.paths, s);
89
+ if (cached?.value)
90
+ ok(tag(`project naming: ${cached.value.project_naming} (cached ${ago(cached.fetched_at, nowMs)})`));
91
+ else
92
+ warn(tag('project naming: unknown until the server is reached; events stay queued meanwhile'));
93
+ }
94
+ }
95
+ view = loadRouting(deps.paths, nowMs) ?? view; // doctor may have refreshed caches, entries and blocked flags
96
+ // 3. This repository: dot file, server, team, warnings
97
+ const cwd = deps.cwd ?? process.cwd();
98
+ for (const l of await checkRepository(view, deps, cwd, nowMs)) {
99
+ const text = `repository: ${terminalSafe(l.text)}`;
100
+ if (l.level === 'ok')
101
+ ok(text);
102
+ else if (l.level === 'warn')
103
+ warn(text);
104
+ else if (l.level === 'bad')
105
+ bad(text);
106
+ else
107
+ io.out(`– ${text}`);
108
+ }
109
+ // 4. Harnesses and hooks
110
+ const projectDir = (await gitTopLevel(cwd)) ?? undefined;
111
+ let installed = 0;
112
+ for (const adapter of deps.adapters ?? ADAPTERS) {
113
+ const d = await adapter.detect(projectDir ? { projectDir } : {});
114
+ if (!d.installed) {
115
+ io.out(`– ${adapter.displayName}: not installed`);
116
+ continue;
117
+ }
118
+ installed++;
119
+ const ver = d.version ?? 'unknown version';
120
+ const hooks = d.hooksInstalled.user || d.hooksInstalled.project;
121
+ const where = [d.hooksInstalled.user && 'user', d.hooksInstalled.project && 'project'].filter(Boolean).join(' + ');
122
+ const line = `${adapter.displayName} ${ver}${d.versionSupported === false ? ' (unsupported version)' : ''}: ${hooks ? `hooks installed (${where})` : 'hooks NOT installed — run `ai-obs init`'}`;
123
+ if (!hooks || d.versionSupported === false)
124
+ bad(line);
125
+ else if (d.versionSupported === null)
126
+ warn(`${line}; version support unknown`);
127
+ else
128
+ ok(line);
129
+ for (const w of d.warnings ?? [])
130
+ warn(`${adapter.displayName}: ${w}`);
131
+ for (const n of d.notes ?? [])
132
+ io.out(` ${n}`);
133
+ if (hooks && adapter.installedHookCommands) {
134
+ // A baked-in node path or script that no longer exists makes every hook fail silently.
135
+ const problems = new Set();
136
+ for (const c of await adapter.installedHookCommands(projectDir ? { projectDir } : {}))
137
+ for (const pr of hookRuntimeProblems(c))
138
+ problems.add(pr);
139
+ for (const pr of problems)
140
+ bad(`${adapter.displayName} hooks point to a stale runtime: ${pr}; hooks do nothing until you run \`ai-obs init\` again`);
141
+ }
142
+ }
143
+ if (!installed)
144
+ bad('no supported harness installed (Claude Code, Codex)');
145
+ const entry = `${deps.paths.app}/bin/ai-obs.js`;
146
+ if (existsSync(entry)) {
147
+ ok(`hook runtime ${entry}`);
148
+ const stale = staleRuntime(deps.paths);
149
+ if (stale)
150
+ warn(stale);
151
+ }
152
+ else
153
+ warn(`hook runtime not copied to ${deps.paths.app} (hooks run from the install location)`);
154
+ // 5. Queue
155
+ const q = summarizeQueue(openStore(deps.paths).stats(), view);
156
+ const s = q.stats;
157
+ const pendingJobs = listJobs(deps.paths.jobs).length;
158
+ const qline = `queue: ${s.events} events (${formatBytes(s.bytes)}): ${q.sendable} sendable, ${q.kept} kept${pendingJobs ? `; ${pendingJobs} hook jobs pending` : ''}`;
159
+ if (q.sendableOldestAt !== null && nowMs - q.sendableOldestAt > 24 * 3600_000)
160
+ warn(`${qline}, oldest sendable ${ago(new Date(q.sendableOldestAt).toISOString(), nowMs)}`);
161
+ else
162
+ ok(qline);
163
+ for (const u of q.unknown)
164
+ bad(`queue stream ${u.dir} has no readable stream.json; its ${u.events} events are kept and never sent: inspect or delete it`);
165
+ for (const line of keptLines(q, ['unknown-stream']))
166
+ warn(line);
167
+ const dropped = readDropped(deps.paths);
168
+ const droppedText = droppedLine(dropped);
169
+ if (droppedText && dropped.last_at && nowMs - Date.parse(dropped.last_at) < DROPPED_SHOWN_MS)
170
+ warn(droppedText);
171
+ if (q.kept > 0 && s.bytes > MAX_QUEUE_BYTES * 0.8) {
172
+ warn(`queue at ${Math.round((s.bytes / MAX_QUEUE_BYTES) * 100)}% of its 50 MB cap; the oldest events, kept ones included, are dropped first`);
173
+ }
174
+ // 6. Delivery per server
175
+ const delivery = readDelivery(deps.paths);
176
+ for (const srv of view.config.servers) {
177
+ const host = endpointHost(srv.endpoint);
178
+ const st = serverDelivery(delivery, srv);
179
+ if (st.blocked)
180
+ warn(`${host}: refused by the server (HTTP ${st.blocked.status}: ${st.blocked.message})`);
181
+ else if (st.last_error)
182
+ warn(`${host}: last send failed ${ago(st.last_attempt_at, nowMs)}: ${st.last_error}`);
183
+ if (st.last_success_at) {
184
+ const r = st.last_result;
185
+ ok(`${host}: last successful send ${ago(st.last_success_at, nowMs)}${r ? ` (accepted ${r.accepted}, duplicates ${r.duplicates}, rejected ${r.rejected})` : ''}`);
186
+ }
187
+ else
188
+ io.out(`– ${host}: nothing sent yet`);
189
+ }
190
+ io.out(failed ? `${failed} problem(s) found. Log: ${deps.paths.logFile}` : 'All good.');
191
+ return failed ? 1 : 0;
192
+ }
193
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAClE,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AACjE,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACtG,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,cAAc,EAAE,YAAY,EAAyB,MAAM,aAAa,CAAC;AACpI,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAEvE,MAAM,UAAU,GAAG,oDAAoD,CAAC;AACxE,MAAM,gBAAgB,GAAG,EAAE,GAAG,EAAE,GAAG,QAAQ,CAAC;AAC5C,MAAM,eAAe,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,yEAAyE;AACzE,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAuB,EAAE,EAAM,EAAE,IAAa;IAChF,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IACvB,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,MAAM,EAAE,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3C,MAAM,IAAI,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC7C,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE;QACxB,MAAM,EAAE,CAAC;QACT,EAAE,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACnB,CAAC,CAAC;IACF,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;IAC1B,EAAE,CAAC,GAAG,CAAC,4BAA4B,iBAAiB,UAAU,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;IAElF,YAAY;IACZ,IAAI,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,GAAG,CAAC,sBAAsB,IAAI,CAAC,KAAK,CAAC,MAAM,wCAAwC,CAAC,CAAC;QACrF,OAAO,CAAC,CAAC;IACX,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;IAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;QAC3B,GAAG,CAAC,iEAAiE,CAAC,CAAC;QACvE,OAAO,CAAC,CAAC;IACX,CAAC;IACD,EAAE,CAAC,UAAU,IAAI,CAAC,KAAK,CAAC,MAAM,aAAa,MAAM,CAAC,UAAU,KAAK,MAAM,CAAC,OAAO,CAAC,MAAM,YAAY,CAAC,CAAC;IAEpG,2DAA2D;IAC3D,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC,CAAC;QAC3I,IAAI,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC;YAAE,GAAG,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC,UAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,iCAAiC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;aAC5H,CAAC;YACJ,MAAM,IAAI,GAAG,QAAQ,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;YAChC,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,EAAE;gBAAE,IAAI,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,UAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,kCAAkC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,CAAC;iBAC3K,IAAI,IAAI,KAAK,IAAI;gBAAE,EAAE,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,UAAW,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC;QAChG,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,aAAa,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACtI,IAAI,CAAC,KAAK,CAAC,SAAS;YAAE,GAAG,CAAC,GAAG,CAAC,gBAAgB,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;aACzD,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG;YAAE,GAAG,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;aAChE,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG;YAAE,GAAG,CAAC,GAAG,CAAC,0BAA0B,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;aACnH,IAAI,KAAK,CAAC,MAAM,KAAK,GAAG;YAAE,IAAI,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC,CAAC;aAC3E,IAAI,CAAC,KAAK,CAAC,KAAK;YAAE,GAAG,CAAC,GAAG,CAAC,mDAAmD,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QACpG,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;YAC1B,EAAE,CAAC,GAAG,CAAC,2BAA2B,YAAY,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,IAAI,GAAG,CAAC,KAAK,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,IAAI,gBAAgB,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC7L,IAAI,CAAC;gBACH,UAAU,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,IAAI,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC,CAAC;gBACtG,YAAY,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,wDAAwD;gBACrF,eAAe,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,iEAAiE;YAC1G,CAAC;YAAC,MAAM,CAAC;gBACP,4CAA4C;YAC9C,CAAC;YACD,IAAI,KAAK,CAAC,KAAK;gBAAE,EAAE,CAAC,GAAG,CAAC,UAAU,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,YAAY,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC;YACrL,MAAM,GAAG,GAAG,KAAK,CAAC,qBAAqB,CAAC;YACxC,IAAI,eAAe,CAAC,iBAAiB,EAAE,GAAG,CAAC,GAAG,CAAC;gBAAE,GAAG,CAAC,GAAG,CAAC,aAAa,iBAAiB,qCAAqC,GAAG,EAAE,CAAC,CAAC,CAAC;;gBAC/H,EAAE,CAAC,GAAG,CAAC,qBAAqB,iBAAiB,qBAAqB,GAAG,EAAE,CAAC,CAAC,CAAC;YAC/E,EAAE,CAAC,GAAG,CAAC,mBAAmB,KAAK,CAAC,cAAc,gBAAgB,CAAC,CAAC,CAAC;QACnE,CAAC;aAAM,CAAC;YACN,MAAM,MAAM,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YACxC,IAAI,MAAM,EAAE,KAAK;gBAAE,EAAE,CAAC,GAAG,CAAC,mBAAmB,MAAM,CAAC,KAAK,CAAC,cAAc,YAAY,GAAG,CAAC,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;;gBAClH,IAAI,CAAC,GAAG,CAAC,mFAAmF,CAAC,CAAC,CAAC;QACtG,CAAC;IACH,CAAC;IACD,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,CAAC,8DAA8D;IAE7G,uDAAuD;IACvD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,MAAM,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,EAAE,CAAC;QAC9D,MAAM,IAAI,GAAG,eAAe,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI;YAAE,EAAE,CAAC,IAAI,CAAC,CAAC;aAC1B,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;YAAE,IAAI,CAAC,IAAI,CAAC,CAAC;aACnC,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC;;YACjC,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,yBAAyB;IACzB,MAAM,UAAU,GAAG,CAAC,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC,IAAI,SAAS,CAAC;IACzD,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,IAAI,QAAQ,EAAE,CAAC;QAChD,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjE,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;YACjB,EAAE,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,WAAW,iBAAiB,CAAC,CAAC;YAClD,SAAS;QACX,CAAC;QACD,SAAS,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,IAAI,iBAAiB,CAAC;QAC3C,MAAM,KAAK,GAAG,CAAC,CAAC,cAAc,CAAC,IAAI,IAAI,CAAC,CAAC,cAAc,CAAC,OAAO,CAAC;QAChE,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,cAAc,CAAC,IAAI,IAAI,MAAM,EAAE,CAAC,CAAC,cAAc,CAAC,OAAO,IAAI,SAAS,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACnH,MAAM,IAAI,GAAG,GAAG,OAAO,CAAC,WAAW,IAAI,GAAG,GAAG,CAAC,CAAC,gBAAgB,KAAK,KAAK,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,CAAC,CAAC,oBAAoB,KAAK,GAAG,CAAC,CAAC,CAAC,yCAAyC,EAAE,CAAC;QACjM,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,gBAAgB,KAAK,KAAK;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC;aACjD,IAAI,CAAC,CAAC,gBAAgB,KAAK,IAAI;YAAE,IAAI,CAAC,GAAG,IAAI,2BAA2B,CAAC,CAAC;;YAC1E,EAAE,CAAC,IAAI,CAAC,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE;YAAE,IAAI,CAAC,GAAG,OAAO,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC,CAAC;QACvE,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE;YAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAClD,IAAI,KAAK,IAAI,OAAO,CAAC,qBAAqB,EAAE,CAAC;YAC3C,uFAAuF;YACvF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;YACnC,KAAK,MAAM,CAAC,IAAI,MAAM,OAAO,CAAC,qBAAqB,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAAE,KAAK,MAAM,EAAE,IAAI,mBAAmB,CAAC,CAAC,CAAC;oBAAE,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YACjJ,KAAK,MAAM,EAAE,IAAI,QAAQ;gBAAE,GAAG,CAAC,GAAG,OAAO,CAAC,WAAW,oCAAoC,EAAE,wDAAwD,CAAC,CAAC;QACvJ,CAAC;IACH,CAAC;IACD,IAAI,CAAC,SAAS;QAAE,GAAG,CAAC,qDAAqD,CAAC,CAAC;IAE3E,MAAM,KAAK,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,gBAAgB,CAAC;IAChD,IAAI,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,EAAE,CAAC,gBAAgB,KAAK,EAAE,CAAC,CAAC;QAC5B,MAAM,KAAK,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACvC,IAAI,KAAK;YAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;;QAAM,IAAI,CAAC,8BAA8B,IAAI,CAAC,KAAK,CAAC,GAAG,wCAAwC,CAAC,CAAC;IAElG,WAAW;IACX,MAAM,CAAC,GAAG,cAAc,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,CAAC;IAC9D,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IAClB,MAAM,WAAW,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC;IACrD,MAAM,KAAK,GAAG,UAAU,CAAC,CAAC,MAAM,YAAY,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,QAAQ,cAAc,CAAC,CAAC,IAAI,QAAQ,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,oBAAoB,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;IACtK,IAAI,CAAC,CAAC,gBAAgB,KAAK,IAAI,IAAI,KAAK,GAAG,CAAC,CAAC,gBAAgB,GAAG,EAAE,GAAG,QAAQ;QAAE,IAAI,CAAC,GAAG,KAAK,qBAAqB,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,WAAW,EAAE,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;;QACtK,EAAE,CAAC,KAAK,CAAC,CAAC;IACf,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO;QAAE,GAAG,CAAC,gBAAgB,CAAC,CAAC,GAAG,qCAAqC,CAAC,CAAC,MAAM,uDAAuD,CAAC,CAAC;IAC1J,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC;QAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,MAAM,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,WAAW,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC;IACzC,IAAI,WAAW,IAAI,OAAO,CAAC,OAAO,IAAI,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,gBAAgB;QAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IAChH,IAAI,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC,KAAK,GAAG,eAAe,GAAG,GAAG,EAAE,CAAC;QAClD,IAAI,CAAC,YAAY,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG,eAAe,CAAC,GAAG,GAAG,CAAC,8EAA8E,CAAC,CAAC;IAChJ,CAAC;IAED,yBAAyB;IACzB,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,EAAE,GAAG,cAAc,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QACzC,IAAI,EAAE,CAAC,OAAO;YAAE,IAAI,CAAC,GAAG,IAAI,iCAAiC,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,EAAE,CAAC,OAAO,CAAC,OAAO,GAAG,CAAC,CAAC;aACrG,IAAI,EAAE,CAAC,UAAU;YAAE,IAAI,CAAC,GAAG,IAAI,sBAAsB,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,CAAC,CAAC;QAC9G,IAAI,EAAE,CAAC,eAAe,EAAE,CAAC;YACvB,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC;YACzB,EAAE,CAAC,GAAG,IAAI,0BAA0B,GAAG,CAAC,EAAE,CAAC,eAAe,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,QAAQ,gBAAgB,CAAC,CAAC,UAAU,cAAc,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACnK,CAAC;;YAAM,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,oBAAoB,CAAC,CAAC;IAC/C,CAAC;IAED,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,MAAM,2BAA2B,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACxF,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC"}
@@ -0,0 +1,131 @@
1
+ import { ADAPTERS } from '../adapters/index.js';
2
+ import { countStagedDigests, pendingSummariesPath, runSummaryBatch } from '../analysis/summaries.js';
3
+ import { loadConfig } from '../config.js';
4
+ import { createContext } from '../context.js';
5
+ import { errorMessage, readJsonFile } from '../fsutil.js';
6
+ import { acquireLock, tryLock } from '../lock.js';
7
+ import { createLogger } from '../log.js';
8
+ import { RESOLVE_TIMEOUT_MS } from '../project-key.js';
9
+ import { loadRouting } from '../routing.js';
10
+ import { flushQueue } from '../sender.js';
11
+ import { HELD_LABEL, noServerLines, nowOf, openStore, parseOptions, summarizeQueue } from './common.js';
12
+ /**
13
+ * `ai-obs flush` — finish what is waiting, then send the queue now, per server, ignoring the retry
14
+ * backoff and retrying refused servers once (an expired token is never used). Before sending it runs each adapter's idle-session sweep
15
+ * (Codex ends sessions idle for 1 h, Claude Code ones silent for 24 h) and writes the staged and pending
16
+ * summaries, so data does not wait for the next hook (design §2.8). While the background worker's summary
17
+ * phase holds summaries.lock, it leaves the summaries to it (ADR-0027).
18
+ */
19
+ export async function flushCommand(args, io, deps) {
20
+ const { values } = parseOptions(args, { wait: { type: 'string', default: '30' } });
21
+ const config = loadConfig(deps.paths);
22
+ if (!config || !config.servers.length) {
23
+ io.err('not configured — run `ai-obs login --server <url>`');
24
+ return 1;
25
+ }
26
+ const release = await acquireLock(deps.paths.workerLock, Number(values.wait) * 1000, 15 * 60_000);
27
+ if (!release) {
28
+ io.out('the background worker is busy (e.g. a large backlog); it flushes when done');
29
+ return 0;
30
+ }
31
+ try {
32
+ const log = createLogger(deps.paths, 'flush');
33
+ const store = openStore(deps.paths);
34
+ const transport = deps.transport;
35
+ const resolveProject = deps.resolveProjectKey ? (cwd) => deps.resolveProjectKey(cwd, { timeoutMs: RESOLVE_TIMEOUT_MS }) : undefined;
36
+ const sum = tryLock(deps.paths.summariesLock, 15 * 60_000);
37
+ if (!sum)
38
+ io.out('summaries are being written by the background worker; they are sent when done');
39
+ try {
40
+ for (const adapter of deps.adapters ?? ADAPTERS) {
41
+ const ctx = createContext({ adapter, config, paths: deps.paths, queue: store, log, ...(resolveProject ? { resolveProject } : {}) });
42
+ try {
43
+ const before = store.stats().events;
44
+ await adapter.sweepCrashedSessions(ctx);
45
+ const swept = store.stats().events - before;
46
+ if (swept > 0)
47
+ io.out(`${adapter.displayName}: idle-session sweep queued ${swept} events`);
48
+ if (!sum)
49
+ continue;
50
+ const waiting = (readJsonFile(pendingSummariesPath(deps.paths.state, adapter.name)) ?? []).length + countStagedDigests(deps.paths.state, adapter.name);
51
+ if (waiting) {
52
+ // this process holds worker.lock: the summaries go straight into the queue it sends below
53
+ const r = await runSummaryBatch(adapter, ctx, {
54
+ retry: true,
55
+ commit: async (groups) => {
56
+ for (const g of groups)
57
+ store.enqueue(g.events, g.key);
58
+ return true;
59
+ },
60
+ });
61
+ io.out(`${adapter.displayName}: summaries ${r?.summarized ?? 0} of ${waiting} done, ${r?.pending ?? waiting} still waiting`);
62
+ }
63
+ }
64
+ catch (err) {
65
+ log.warn('flush: sweep / summaries failed', { harness: adapter.name, error: errorMessage(err).slice(0, 200) });
66
+ }
67
+ }
68
+ }
69
+ finally {
70
+ sum?.();
71
+ }
72
+ const r = await flushQueue(store, { paths: deps.paths, log, ...(transport ? { transport } : {}), ...(deps.resolveProjectKey ? { resolveProjectKey: deps.resolveProjectKey } : {}) }, { force: true, maxBatches: 1000 });
73
+ const view = loadRouting(deps.paths, nowOf(deps));
74
+ let failedServers = 0;
75
+ let printed = false;
76
+ for (const [endpoint, t] of Object.entries(r.servers)) {
77
+ const sentBefore = t.sent ? ` (${t.sent} sent before the failure)` : '';
78
+ switch (t.status) {
79
+ case 'ok':
80
+ io.out(`sent ${t.sent} events to ${endpoint} in ${t.batches} batch(es): accepted ${t.accepted}, duplicates ${t.duplicates}, rejected ${t.rejected}; ${t.left} left`);
81
+ break;
82
+ case 'auth_error':
83
+ failedServers++;
84
+ io.err(`✗ ${endpoint}: ${t.error ?? 'token refused'}; ${t.left} events stay queued${sentBefore}`);
85
+ break;
86
+ case 'expired':
87
+ failedServers++;
88
+ io.err(`✗ ${endpoint}: ${t.error ?? 'token expired'}; ${t.left} events stay queued`);
89
+ break;
90
+ case 'failed':
91
+ failedServers++;
92
+ io.err(`✗ ${endpoint}: send failed: ${t.error ?? 'unknown error'}; ${t.left} events stay queued${sentBefore}`);
93
+ break;
94
+ case 'blocked':
95
+ case 'backoff':
96
+ io.out(`! ${endpoint}: not sent now (${t.error ?? t.status}); ${t.left} events stay queued`);
97
+ break;
98
+ default:
99
+ continue;
100
+ }
101
+ printed = true;
102
+ }
103
+ const byReason = r.held.byReason;
104
+ if (byReason['no-server'] && view) {
105
+ for (const line of noServerLines(summarizeQueue(store.stats(), view)))
106
+ io.out(`! kept: ${line}`);
107
+ printed = true;
108
+ }
109
+ for (const [reason, n] of Object.entries(byReason)) {
110
+ if (!n || reason === 'no-server')
111
+ continue;
112
+ io.out(`kept: ${n} events (${HELD_LABEL[reason]})`);
113
+ printed = true;
114
+ }
115
+ if (r.dropped.events) {
116
+ io.out(`! the queue caps (30 days / 50 MB) dropped ${r.dropped.events} events (${r.dropped.heldEvents} of them could not be sent)`);
117
+ printed = true;
118
+ }
119
+ if (r.status === 'failed' && !Object.keys(r.servers).length && r.error) {
120
+ io.err(`✗ send failed: ${r.error}`);
121
+ return 1;
122
+ }
123
+ if (!printed)
124
+ io.out('queue is empty');
125
+ return failedServers ? 1 : 0;
126
+ }
127
+ finally {
128
+ release();
129
+ }
130
+ }
131
+ //# sourceMappingURL=flush.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"flush.js","sourceRoot":"","sources":["../../src/commands/flush.ts"],"names":[],"mappings":"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"}