mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
* feat: add telemetry phase 1
* feat: add node telemetry event catalog
* feat: add telemetry event helpers
* feat: emit setup and connection telemetry
* feat: emit connection and stack telemetry
* feat: emit ingest and scan telemetry
* feat: emit query telemetry
* feat: emit sampled mcp telemetry
* docs: expand telemetry event catalog
* feat: add telemetry schema sync artifact
* feat: pass telemetry project id to semantic daemon
* feat: add daemon telemetry foundation
* feat: emit semantic daemon telemetry
* feat: emit daemon lifecycle telemetry
* docs: document full telemetry event catalog
* feat(telemetry): dim first-run notice
* feat(telemetry): show first-run notice before command output
* feat(telemetry): wire ktx PostHog project for live ingestion
* docs(telemetry): drop posthog project name and host from storage section
* docs(telemetry): trim to general overview and disclaimer
* docs(agents): add short telemetry guidelines
* feat(telemetry): enable posthog geoip enrichment
* docs(telemetry): drop ip-geoip note from public overview
* refactor(telemetry): drop no-op groupIdentify, rely on capture groups field
* fix(telemetry): respect CI kill switch in python daemon identity
* fix(sql): route table-count analysis to existing analyze-batch endpoint
* fix(telemetry): emit install_first_run from notice path and derive flagsPresent from commander
* fix(telemetry): read package info via getKtxCliPackageInfo to satisfy boundary check
* fix(telemetry): make python identity env={} bypass os.environ and unset CI in tests
* fix(telemetry): unset CI kill switch in cli-program-telemetry tests
59 lines
1.4 KiB
TypeScript
59 lines
1.4 KiB
TypeScript
import { scrubErrorClass } from './scrubber.js';
|
|
|
|
export type CommandOutcome = 'ok' | 'error' | 'aborted';
|
|
|
|
interface CommandSpan {
|
|
commandPath: string[];
|
|
flagsPresent: Record<string, boolean>;
|
|
projectDir?: string;
|
|
hasProject: boolean;
|
|
attachProjectGroup: boolean;
|
|
startedAt: number;
|
|
}
|
|
|
|
export interface CompletedCommandSpan {
|
|
commandPath: string[];
|
|
durationMs: number;
|
|
outcome: CommandOutcome;
|
|
errorClass?: string;
|
|
flagsPresent: Record<string, boolean>;
|
|
hasProject: boolean;
|
|
projectDir?: string;
|
|
projectGroupAttached: boolean;
|
|
}
|
|
|
|
let activeCommandSpan: CommandSpan | undefined;
|
|
|
|
export function beginCommandSpan(input: CommandSpan): void {
|
|
activeCommandSpan = input;
|
|
}
|
|
|
|
export function completeCommandSpan(input: {
|
|
completedAt: number;
|
|
outcome: CommandOutcome;
|
|
error?: unknown;
|
|
}): CompletedCommandSpan | undefined {
|
|
const span = activeCommandSpan;
|
|
activeCommandSpan = undefined;
|
|
if (!span) {
|
|
return undefined;
|
|
}
|
|
|
|
const errorClass = input.error ? scrubErrorClass(input.error) : undefined;
|
|
|
|
return {
|
|
commandPath: span.commandPath,
|
|
durationMs: Math.max(0, input.completedAt - span.startedAt),
|
|
outcome: input.outcome,
|
|
...(errorClass ? { errorClass } : {}),
|
|
flagsPresent: span.flagsPresent,
|
|
hasProject: span.hasProject,
|
|
projectDir: span.projectDir,
|
|
projectGroupAttached: span.attachProjectGroup,
|
|
};
|
|
}
|
|
|
|
/** @internal */
|
|
export function resetCommandSpan(): void {
|
|
activeCommandSpan = undefined;
|
|
}
|