-
Notifications
You must be signed in to change notification settings - Fork 866
fix(cli): fix first launch telemetry timing and extract telemetry init #47
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@moonshot-ai/kimi-code": patch | ||
| --- | ||
|
|
||
| Emit session resume hint as a structured meta message in stream-json output format. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,9 +2,7 @@ import { execSync } from 'node:child_process'; | |
| import { homedir } from 'node:os'; | ||
| import { join } from 'node:path'; | ||
|
|
||
| import { createKimiDeviceId, KIMI_CODE_PROVIDER_NAME } from '@moonshot-ai/kimi-code-oauth'; | ||
| import { | ||
| initializeTelemetry, | ||
| setCrashPhase, | ||
| setTelemetryContext, | ||
| shutdownTelemetry, | ||
|
|
@@ -13,7 +11,7 @@ import { | |
| } from '@moonshot-ai/kimi-telemetry'; | ||
| import { KimiHarness, log, type TelemetryClient } from '@moonshot-ai/kimi-code-sdk'; | ||
|
|
||
| import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_UI_MODE, CLI_USER_AGENT_PRODUCT } from '#/constant/app'; | ||
| import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_UI_MODE } from '#/constant/app'; | ||
| import { detectPendingMigration } from '#/migration/index'; | ||
| import type { TuiConfig } from '#/tui/config'; | ||
| import { loadTuiConfig, TuiConfigParseError } from '#/tui/config'; | ||
|
|
@@ -22,6 +20,7 @@ import { KimiTUI } from '#/tui/index'; | |
| import { detectTerminalTheme } from '#/tui/theme/detect'; | ||
|
|
||
| import type { CLIOptions } from './options'; | ||
| import { createCliTelemetryBootstrap, initializeCliTelemetry } from './telemetry'; | ||
| import { createKimiCodeHostIdentity } from './version'; | ||
|
|
||
| export async function runShell( | ||
|
|
@@ -46,12 +45,14 @@ export async function runShell( | |
| const resolvedTheme = tuiConfig.theme === 'auto' ? await detectTerminalTheme() : tuiConfig.theme; | ||
|
|
||
| const workDir = process.cwd(); | ||
| const telemetryBootstrap = createCliTelemetryBootstrap(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Useful? React with 👍 / 👎. |
||
| const telemetryClient: TelemetryClient = { | ||
| track, | ||
| withContext: withTelemetryContext, | ||
| setContext: setTelemetryContext, | ||
| }; | ||
| const harness = new KimiHarness({ | ||
| homeDir: telemetryBootstrap.homeDir, | ||
| identity: createKimiCodeHostIdentity(version), | ||
| telemetry: telemetryClient, | ||
| onOAuthRefresh: (outcome) => { | ||
|
|
@@ -96,28 +97,15 @@ export async function runShell( | |
| migrateOnly: runOptions.migrateOnly, | ||
| }); | ||
|
|
||
| let firstLaunch = false; | ||
| const deviceId = createKimiDeviceId(harness.homeDir, { | ||
| onFirstLaunch: () => { | ||
| firstLaunch = true; | ||
| }, | ||
| }); | ||
| initializeTelemetry({ | ||
| homeDir: harness.homeDir, | ||
| deviceId, | ||
| enabled: config.telemetry !== false, | ||
| appName: CLI_USER_AGENT_PRODUCT, | ||
| initializeCliTelemetry({ | ||
| harness, | ||
| bootstrap: telemetryBootstrap, | ||
| config, | ||
| version, | ||
| uiMode: CLI_UI_MODE, | ||
| model: config.defaultModel, | ||
| getAccessToken: async () => | ||
| (await harness.auth.getCachedAccessToken(KIMI_CODE_PROVIDER_NAME)) ?? null, | ||
| }); | ||
| setCrashPhase('runtime'); | ||
|
|
||
| if (firstLaunch) { | ||
| harness.track('first_launch'); | ||
| } | ||
| const resumed = opts.continue || opts.session !== undefined; | ||
| const trackLifecycleForSession = ( | ||
| sessionId: string, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,9 +7,7 @@ | |
|
|
||
| import { createInterface } from 'node:readline/promises'; | ||
|
|
||
| import { createKimiDeviceId, KIMI_CODE_PROVIDER_NAME } from '@moonshot-ai/kimi-code-oauth'; | ||
| import { | ||
| initializeTelemetry, | ||
| setTelemetryContext, | ||
| shutdownTelemetry, | ||
| track, | ||
|
|
@@ -24,7 +22,8 @@ import { | |
| } from '@moonshot-ai/kimi-code-sdk'; | ||
| import type { Command } from 'commander'; | ||
|
|
||
| import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_UI_MODE, CLI_USER_AGENT_PRODUCT } from '#/constant/app'; | ||
| import { CLI_SHUTDOWN_TIMEOUT_MS, CLI_UI_MODE } from '#/constant/app'; | ||
| import { createCliTelemetryBootstrap, initializeCliTelemetry } from '#/cli/telemetry'; | ||
| import { createKimiCodeHostIdentity } from '#/cli/version'; | ||
|
|
||
| interface WritableLike { | ||
|
|
@@ -121,6 +120,7 @@ export function registerExportCommand(parent: Command, deps?: Partial<ExportDeps | |
|
|
||
| function createDefaultExportDeps(overrides: Partial<ExportDeps> = {}): ExportDeps { | ||
| let harness: KimiHarness | undefined; | ||
| let telemetryBootstrap: ReturnType<typeof createCliTelemetryBootstrap> | undefined; | ||
| let telemetryInitialized = false; | ||
| let telemetryShutdown = false; | ||
| const identity = createKimiCodeHostIdentity(); | ||
|
|
@@ -129,29 +129,31 @@ function createDefaultExportDeps(overrides: Partial<ExportDeps> = {}): ExportDep | |
| withContext: withTelemetryContext, | ||
| setContext: setTelemetryContext, | ||
| }; | ||
| const getTelemetryBootstrap = (): ReturnType<typeof createCliTelemetryBootstrap> => { | ||
| telemetryBootstrap ??= createCliTelemetryBootstrap(); | ||
| return telemetryBootstrap; | ||
| }; | ||
| const getHarness = (): KimiHarness => { | ||
| const currentTelemetryBootstrap = getTelemetryBootstrap(); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
In Useful? React with 👍 / 👎. |
||
| harness ??= new KimiHarness({ | ||
| homeDir: currentTelemetryBootstrap.homeDir, | ||
| identity, | ||
| telemetry: telemetryClient, | ||
| }); | ||
| return harness; | ||
| }; | ||
| const initializeDefaultTelemetry = async (): Promise<void> => { | ||
| if (telemetryInitialized) return; | ||
| const currentTelemetryBootstrap = getTelemetryBootstrap(); | ||
| const currentHarness = getHarness(); | ||
| await currentHarness.ensureConfigFile(); | ||
| const config = await currentHarness.getConfig(); | ||
| const deviceId = createKimiDeviceId(currentHarness.homeDir); | ||
| initializeTelemetry({ | ||
| homeDir: currentHarness.homeDir, | ||
| deviceId, | ||
| enabled: config.telemetry !== false, | ||
| appName: CLI_USER_AGENT_PRODUCT, | ||
| initializeCliTelemetry({ | ||
| harness: currentHarness, | ||
| bootstrap: currentTelemetryBootstrap, | ||
| config, | ||
| version: identity.version, | ||
| uiMode: CLI_UI_MODE, | ||
| model: config.defaultModel, | ||
| getAccessToken: async () => | ||
| (await currentHarness.auth.getCachedAccessToken(KIMI_CODE_PROVIDER_NAME)) ?? null, | ||
| }); | ||
| telemetryInitialized = true; | ||
| }; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| import { createKimiDeviceId, KIMI_CODE_PROVIDER_NAME } from '@moonshot-ai/kimi-code-oauth'; | ||
| import { initializeTelemetry } from '@moonshot-ai/kimi-telemetry'; | ||
| import { resolveKimiHome, type KimiConfig, type KimiHarness } from '@moonshot-ai/kimi-code-sdk'; | ||
|
|
||
| import { CLI_USER_AGENT_PRODUCT } from '#/constant/app'; | ||
|
|
||
| export interface CliTelemetryBootstrap { | ||
| readonly homeDir: string; | ||
| readonly deviceId: string; | ||
| readonly firstLaunch: boolean; | ||
| } | ||
|
|
||
| export interface InitializeCliTelemetryOptions { | ||
| readonly harness: KimiHarness; | ||
| readonly bootstrap: CliTelemetryBootstrap; | ||
| readonly config: Pick<KimiConfig, 'defaultModel' | 'telemetry'>; | ||
| readonly version: string; | ||
| readonly uiMode: string; | ||
| readonly model?: string; | ||
| } | ||
|
|
||
| export function createCliTelemetryBootstrap(): CliTelemetryBootstrap { | ||
| let firstLaunch = false; | ||
| const homeDir = resolveKimiHome(); | ||
| const deviceId = createKimiDeviceId(homeDir, { | ||
| onFirstLaunch: () => { | ||
| firstLaunch = true; | ||
| }, | ||
| }); | ||
| return { homeDir, deviceId, firstLaunch }; | ||
| } | ||
|
|
||
| export function initializeCliTelemetry(options: InitializeCliTelemetryOptions): void { | ||
| initializeTelemetry({ | ||
| homeDir: options.harness.homeDir, | ||
| deviceId: options.bootstrap.deviceId, | ||
| enabled: options.config.telemetry !== false, | ||
| appName: CLI_USER_AGENT_PRODUCT, | ||
| version: options.version, | ||
| uiMode: options.uiMode, | ||
| model: options.model ?? options.config.defaultModel, | ||
| getAccessToken: async () => | ||
| (await options.harness.auth.getCachedAccessToken(KIMI_CODE_PROVIDER_NAME)) ?? null, | ||
| }); | ||
| if (options.bootstrap.firstLaunch) { | ||
| options.harness.track('first_launch'); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Creating
telemetryBootstrapat function entry mintsdevice_idbefore any of the prompt startup checks run, butfirst_launchis only emitted later insideinitializeCliTelemetry(). If prompt startup fails early (for example, no configured model inresolvePromptSession()or another pre-session error), the command exits without initializing telemetry, so the first-launch event is permanently missed on subsequent successful runs.Useful? React with 👍 / 👎.