Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/altimate-code/src/cli/cmd/tui/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,7 @@ export const rpc = {
}),
])
if (server) server.stop(true)
await Telemetry.shutdown()
},
}

Expand Down
9 changes: 9 additions & 0 deletions packages/altimate-code/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,15 @@ try {
}
process.exitCode = 1
} finally {
// Flush any buffered telemetry events before exiting.
// This is critical for non-session commands (auth, upgrade, mcp, etc.)
// that track events but don't go through the session prompt shutdown path.
// shutdown() is idempotent — safe even if session prompt already called it.
try {
await Telemetry.shutdown()
} catch {
// Telemetry failure must never prevent shutdown
}
// Some subprocesses don't react properly to SIGTERM and similar signals.
// Most notably, some docker-container-based MCP servers don't handle such signals unless
// run using `docker run --init`.
Expand Down
10 changes: 10 additions & 0 deletions packages/altimate-code/src/telemetry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,16 @@ export namespace Telemetry {
}

export async function shutdown() {
// Wait for init to complete so we know whether telemetry is enabled
// and have a valid endpoint to flush to. init() is fire-and-forget
// in CLI middleware, so it may still be in-flight when shutdown runs.
if (initPromise) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Nice defensive pattern — awaiting the in-flight initPromise before checking enabled state closes the race condition cleanly. The catch swallow is correct here since a failed init means there's nothing to flush.

try {
await initPromise
} catch {
// init failed — nothing to flush
}
}
if (flushTimer) {
clearInterval(flushTimer)
flushTimer = undefined
Expand Down