@kopai/cli 0.8.2 → 0.9.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.
- package/README.md +5 -0
- package/dist/index.mjs +18 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -137,6 +137,9 @@ Search metrics by type.
|
|
|
137
137
|
kopai metrics search --type Gauge --name cpu_usage
|
|
138
138
|
kopai metrics search --type Histogram --service my-api
|
|
139
139
|
kopai metrics search --type Sum --attr "host=server1"
|
|
140
|
+
|
|
141
|
+
# Aggregate: total bytes ingested grouped by signal
|
|
142
|
+
kopai metrics search --type Sum --name kopai.ingestion.bytes --aggregate sum --group-by signal
|
|
140
143
|
```
|
|
141
144
|
|
|
142
145
|
**Types:** Gauge, Sum, Histogram, ExponentialHistogram, Summary
|
|
@@ -151,6 +154,8 @@ kopai metrics search --type Sum --attr "host=server1"
|
|
|
151
154
|
- `--resource-attr <key=value>` - repeatable
|
|
152
155
|
- `--scope-attr <key=value>` - repeatable
|
|
153
156
|
- `--sort` - ASC or DESC
|
|
157
|
+
- `--aggregate <fn>` - aggregation function (sum, avg, min, max, count). Gauge/Sum only
|
|
158
|
+
- `--group-by <attr>` - group by attribute key (repeatable, requires --aggregate)
|
|
154
159
|
|
|
155
160
|
**Fields:** TimeUnix, StartTimeUnix, MetricType, MetricName, MetricDescription, MetricUnit, ServiceName, Value, Count, Sum, Min, Max, Attributes, ResourceAttributes, ScopeName, ScopeAttributes, Exemplars, BucketCounts, ExplicitBounds
|
|
156
161
|
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Command } from "commander";
|
|
2
|
+
import { Command, InvalidArgumentError } from "commander";
|
|
3
3
|
import { KopaiClient } from "@kopai/sdk";
|
|
4
4
|
import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { homedir } from "node:os";
|
|
@@ -250,7 +250,7 @@ function collect$1(value, previous) {
|
|
|
250
250
|
//#region src/commands/metrics.ts
|
|
251
251
|
function createMetricsCommand() {
|
|
252
252
|
const metrics = new Command("metrics").description("Query metrics");
|
|
253
|
-
withConnectionOptions(metrics.command("search").description("Search metrics").requiredOption("--type <type>", "Metric type (Gauge|Sum|Histogram|ExponentialHistogram|Summary)").option("-j, --json", "JSON output").option("-t, --table", "Table output").option("-f, --fields <fields>", "Comma-separated fields to include").option("-l, --limit <n>", "Max results").option("-n, --name <name>", "Filter by metric name").option("-s, --service <name>", "Filter by service name").option("--scope <name>", "Filter by scope name").option("--time-min <ns>", "Min time (nanoseconds)").option("--time-max <ns>", "Max time (nanoseconds)").option("-a, --attr <key=value>", "Attribute filter (repeatable)", collect, []).option("--resource-attr <key=value>", "Resource attribute filter (repeatable)", collect, []).option("--scope-attr <key=value>", "Scope attribute filter (repeatable)", collect, []).option("--sort <order>", "Sort order (ASC|DESC)")).action(async (opts) => {
|
|
253
|
+
withConnectionOptions(metrics.command("search").description("Search metrics").requiredOption("--type <type>", "Metric type (Gauge|Sum|Histogram|ExponentialHistogram|Summary)").option("-j, --json", "JSON output").option("-t, --table", "Table output").option("-f, --fields <fields>", "Comma-separated fields to include").option("-l, --limit <n>", "Max results").option("-n, --name <name>", "Filter by metric name").option("-s, --service <name>", "Filter by service name").option("--scope <name>", "Filter by scope name").option("--time-min <ns>", "Min time (nanoseconds)").option("--time-max <ns>", "Max time (nanoseconds)").option("-a, --attr <key=value>", "Attribute filter (repeatable)", collect, []).option("--resource-attr <key=value>", "Resource attribute filter (repeatable)", collect, []).option("--scope-attr <key=value>", "Scope attribute filter (repeatable)", collect, []).option("--sort <order>", "Sort order (ASC|DESC)").option("--aggregate <fn>", "Aggregation function (sum|avg|min|max|count)").option("--group-by <attr>", "Group by attribute key (repeatable)", collect, [])).action(async (opts) => {
|
|
254
254
|
const format = detectFormat(opts.json, opts.table);
|
|
255
255
|
const fields = parseFields(opts.fields);
|
|
256
256
|
try {
|
|
@@ -267,9 +267,14 @@ function createMetricsCommand() {
|
|
|
267
267
|
resourceAttributes: parseAttributes(opts.resourceAttr),
|
|
268
268
|
scopeAttributes: parseAttributes(opts.scopeAttr),
|
|
269
269
|
limit,
|
|
270
|
-
sortOrder: opts.sort
|
|
270
|
+
sortOrder: opts.sort,
|
|
271
|
+
aggregate: toAggregateFn(opts.aggregate),
|
|
272
|
+
groupBy: opts.groupBy && opts.groupBy.length > 0 ? opts.groupBy : void 0
|
|
271
273
|
};
|
|
272
|
-
output((await client.
|
|
274
|
+
output((filter.aggregate ? await client.searchAggregatedMetrics({
|
|
275
|
+
...filter,
|
|
276
|
+
aggregate: filter.aggregate
|
|
277
|
+
}) : await client.searchMetricsPage(filter)).data, {
|
|
273
278
|
format,
|
|
274
279
|
fields
|
|
275
280
|
});
|
|
@@ -296,6 +301,14 @@ function createMetricsCommand() {
|
|
|
296
301
|
function collect(value, previous) {
|
|
297
302
|
return previous.concat([value]);
|
|
298
303
|
}
|
|
304
|
+
function isAggregateFn(value) {
|
|
305
|
+
return value === "sum" || value === "avg" || value === "min" || value === "max" || value === "count";
|
|
306
|
+
}
|
|
307
|
+
function toAggregateFn(value) {
|
|
308
|
+
if (value === void 0) return void 0;
|
|
309
|
+
if (isAggregateFn(value)) return value;
|
|
310
|
+
throw new InvalidArgumentError(`Invalid aggregate function: ${value}`);
|
|
311
|
+
}
|
|
299
312
|
//#endregion
|
|
300
313
|
//#region src/commands/dashboards.ts
|
|
301
314
|
async function readStdin() {
|
|
@@ -515,7 +528,7 @@ async function checkForUpdates(currentVersion, opts) {
|
|
|
515
528
|
}
|
|
516
529
|
//#endregion
|
|
517
530
|
//#region package.json
|
|
518
|
-
var version = "0.
|
|
531
|
+
var version = "0.9.0";
|
|
519
532
|
//#endregion
|
|
520
533
|
//#region src/index.ts
|
|
521
534
|
const program = new Command();
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["DEFAULT_URL","collect","collect","pkg.version"],"sources":["../src/config.ts","../src/client.ts","../src/output.ts","../src/commands/traces.ts","../src/commands/logs.ts","../src/commands/metrics.ts","../src/commands/dashboards.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/update-check.ts","../package.json","../src/index.ts"],"sourcesContent":["import { readFileSync, existsSync, writeFileSync, chmodSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface Config {\n url?: string;\n token?: string;\n}\n\nexport const CONFIG_FILENAME = \".kopairc\";\nexport const TOKEN_PREFIX_LENGTH = 10;\nexport const DEFAULT_URL = \"http://localhost:8000\";\n\n/** Owner read+write only (rw-------). Used for files containing secrets. */\nconst OWNER_READ_WRITE = 0o600;\n\nfunction loadConfigFile(path: string): Config | null {\n if (!existsSync(path)) return null;\n try {\n const content = readFileSync(path, \"utf-8\");\n return JSON.parse(content) as Config;\n } catch {\n return null;\n }\n}\n\nexport function loadConfig(configPath?: string): Config {\n // Priority: --config flag > ./.kopairc > ~/.kopairc\n const paths = configPath\n ? [configPath]\n : [join(process.cwd(), CONFIG_FILENAME), join(homedir(), CONFIG_FILENAME)];\n\n for (const path of paths) {\n const config = loadConfigFile(path);\n if (config) return config;\n }\n\n return {};\n}\n\nexport function resolveConfigPath(global: boolean): string {\n return global\n ? join(homedir(), CONFIG_FILENAME)\n : join(process.cwd(), CONFIG_FILENAME);\n}\n\nexport function saveConfig(updates: Partial<Config>, targetPath: string): void {\n let existing: Config = {};\n if (existsSync(targetPath)) {\n try {\n const content = readFileSync(targetPath, \"utf-8\");\n existing = JSON.parse(content) as Config;\n } catch {\n // ignore parse errors, overwrite\n }\n }\n const merged = { ...existing, ...updates };\n writeFileSync(targetPath, JSON.stringify(merged, null, 2) + \"\\n\", {\n encoding: \"utf-8\",\n mode: OWNER_READ_WRITE,\n });\n chmodSync(targetPath, OWNER_READ_WRITE);\n}\n\nexport function removeConfigToken(targetPath: string): boolean {\n if (!existsSync(targetPath)) return false;\n try {\n const content = readFileSync(targetPath, \"utf-8\");\n const config = JSON.parse(content) as Config;\n if (!config.token) return false;\n delete config.token;\n writeFileSync(targetPath, JSON.stringify(config, null, 2) + \"\\n\", {\n encoding: \"utf-8\",\n mode: OWNER_READ_WRITE,\n });\n } catch {\n return false;\n }\n try {\n chmodSync(targetPath, OWNER_READ_WRITE);\n } catch {\n // chmod failure does not affect the successful token removal\n }\n return true;\n}\n","import type { Command } from \"commander\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { loadConfig } from \"./config.js\";\n\nexport function withConnectionOptions<T extends Command>(cmd: T): T {\n return cmd\n .option(\"--url <url>\", \"API base URL\")\n .option(\"--token <token>\", \"Auth token\")\n .option(\"-c, --config <path>\", \"Config file path\")\n .option(\"--timeout <ms>\", \"Request timeout\") as T;\n}\n\nexport interface ClientOptions {\n config?: string;\n url?: string;\n token?: string;\n timeout?: number;\n}\n\nconst DEFAULT_URL = \"http://localhost:8000\";\n\nexport interface ConnectionOpts {\n url: string;\n token: string | undefined;\n}\n\nexport function resolveConnectionOpts(opts: ClientOptions): ConnectionOpts {\n const fileConfig = loadConfig(opts.config);\n const raw = opts.url ?? fileConfig.url ?? DEFAULT_URL;\n const url = raw.replace(/\\/signals\\/?$/, \"\").replace(/\\/$/, \"\");\n return {\n url,\n token: opts.token ?? fileConfig.token,\n };\n}\n\nexport function createClient(opts: ClientOptions): KopaiClient {\n const { url, token } = resolveConnectionOpts(opts);\n\n const timeout =\n opts.timeout != null ? parseInt(String(opts.timeout), 10) : undefined;\n\n return new KopaiClient({\n baseUrl: url,\n token,\n timeout: Number.isNaN(timeout) ? undefined : timeout,\n });\n}\n\nexport function parseAttributes(attrs?: string[]): Record<string, string> {\n if (!attrs || attrs.length === 0) return {};\n const result: Record<string, string> = {};\n for (const attr of attrs) {\n const idx = attr.indexOf(\"=\");\n if (idx === -1) {\n console.error(`Invalid attribute format: ${attr}. Use key=value`);\n process.exit(2);\n }\n result[attr.slice(0, idx)] = attr.slice(idx + 1);\n }\n return result;\n}\n","export type OutputFormat = \"json\" | \"table\";\n\nexport interface OutputOptions {\n format: OutputFormat;\n fields?: string[];\n}\n\nexport function detectFormat(json?: boolean, table?: boolean): OutputFormat {\n if (json) return \"json\";\n if (table) return \"table\";\n // Default: table for TTY, JSON for pipes\n return process.stdout.isTTY ? \"table\" : \"json\";\n}\n\nfunction countAttributes(attr: { values: Record<string, string[]> }): number {\n return Object.keys(attr.values).length;\n}\n\nfunction filterFields<T extends object>(data: T, fields: string[]): Partial<T> {\n return Object.fromEntries(\n Object.entries(data).filter(([key]) => fields.includes(key))\n ) as Partial<T>;\n}\n\nexport function parseFields(fieldsStr?: string): string[] | undefined {\n if (!fieldsStr) return undefined;\n return fieldsStr.split(\",\").map((f) => f.trim());\n}\n\nfunction isMetricsDiscoverData(data: unknown[]): data is Array<{\n attributes: { values: Record<string, string[]> };\n resourceAttributes: { values: Record<string, string[]> };\n}> {\n return (\n data.length > 0 &&\n typeof data[0] === \"object\" &&\n data[0] !== null &&\n \"attributes\" in data[0] &&\n \"resourceAttributes\" in data[0] &&\n typeof (data[0] as Record<string, unknown>).attributes === \"object\" &&\n (data[0] as Record<string, unknown>).attributes !== null &&\n \"values\" in ((data[0] as Record<string, unknown>).attributes as object)\n );\n}\n\nexport function output<T>(data: T, opts: OutputOptions): void {\n let outputData = data;\n\n // Apply field filtering\n if (opts.fields && opts.fields.length > 0) {\n if (Array.isArray(data)) {\n outputData = data.map((item) =>\n typeof item === \"object\" && item !== null\n ? filterFields(item as object, opts.fields!)\n : item\n ) as T;\n } else if (typeof data === \"object\" && data !== null) {\n outputData = filterFields(data as object, opts.fields) as T;\n }\n }\n\n if (opts.format === \"json\") {\n console.log(JSON.stringify(outputData, null, 2));\n } else {\n if (Array.isArray(outputData)) {\n if (outputData.length === 0) {\n console.log(\"No results found.\");\n } else if (!opts.fields && isMetricsDiscoverData(outputData)) {\n const transformed = outputData.map((m) => ({\n name: m.name,\n type: m.type,\n unit: m.unit,\n description: m.description,\n attrs: countAttributes(m.attributes),\n resourceAttrs: countAttributes(m.resourceAttributes),\n }));\n console.table(transformed);\n console.log(\"\\nUse --json for full attribute details.\");\n } else {\n console.table(outputData);\n }\n } else {\n console.log(outputData);\n }\n }\n}\n\nexport function outputError(error: unknown, json: boolean): void {\n const err =\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) };\n\n if (json) {\n console.error(JSON.stringify({ error: err }));\n } else {\n console.error(`Error: ${err.message}`);\n }\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface TracesGetOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n}\n\ninterface TracesSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n traceId?: string;\n spanId?: string;\n parentSpanId?: string;\n service?: string;\n spanName?: string;\n spanKind?: string;\n statusCode?: string;\n scope?: string;\n timestampMin?: string;\n timestampMax?: string;\n durationMin?: string;\n durationMax?: string;\n spanAttr?: string[];\n resourceAttr?: string[];\n sort?: string;\n}\n\nexport function createTracesCommand(): Command {\n const traces = new Command(\"traces\").description(\"Query traces\");\n\n withConnectionOptions(\n traces\n .command(\"get\")\n .description(\"Get all spans for a trace by ID\")\n .argument(\"<traceId>\", \"Trace ID\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n ).action(async (traceId: string, opts: TracesGetOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const spans = await client.getTrace(traceId);\n output(spans, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n traces\n .command(\"search\")\n .description(\"Search traces\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"--trace-id <id>\", \"Filter by trace ID\")\n .option(\"--span-id <id>\", \"Filter by span ID\")\n .option(\"--parent-span-id <id>\", \"Filter by parent span ID\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--span-name <name>\", \"Filter by span name\")\n .option(\"--span-kind <kind>\", \"Filter by span kind\")\n .option(\"--status-code <code>\", \"Filter by status code\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--timestamp-min <ns>\", \"Min timestamp (nanoseconds)\")\n .option(\"--timestamp-max <ns>\", \"Max timestamp (nanoseconds)\")\n .option(\"--duration-min <ns>\", \"Min duration (nanoseconds)\")\n .option(\"--duration-max <ns>\", \"Max duration (nanoseconds)\")\n .option(\n \"--span-attr <key=value>\",\n \"Span attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n ).action(async (opts: TracesSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n traceId: opts.traceId,\n spanId: opts.spanId,\n parentSpanId: opts.parentSpanId,\n serviceName: opts.service,\n spanName: opts.spanName,\n spanKind: opts.spanKind,\n statusCode: opts.statusCode,\n scopeName: opts.scope,\n timestampMin: opts.timestampMin,\n timestampMax: opts.timestampMax,\n durationMin: opts.durationMin,\n durationMax: opts.durationMax,\n spanAttributes: parseAttributes(opts.spanAttr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n };\n\n const result = await client.searchTracesPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return traces;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface LogsSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n traceId?: string;\n spanId?: string;\n service?: string;\n scope?: string;\n severityText?: string;\n severityMin?: string;\n severityMax?: string;\n body?: string;\n timestampMin?: string;\n timestampMax?: string;\n logAttr?: string[];\n resourceAttr?: string[];\n scopeAttr?: string[];\n sort?: string;\n}\n\nexport function createLogsCommand(): Command {\n const logs = new Command(\"logs\").description(\"Query logs\");\n\n withConnectionOptions(\n logs\n .command(\"search\")\n .description(\"Search logs\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"--trace-id <id>\", \"Filter by trace ID\")\n .option(\"--span-id <id>\", \"Filter by span ID\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--severity-text <level>\", \"Filter by severity text\")\n .option(\"--severity-min <n>\", \"Min severity number\")\n .option(\"--severity-max <n>\", \"Max severity number\")\n .option(\"-b, --body <text>\", \"Filter by body contains\")\n .option(\"--timestamp-min <ns>\", \"Min timestamp (nanoseconds)\")\n .option(\"--timestamp-max <ns>\", \"Max timestamp (nanoseconds)\")\n .option(\n \"--log-attr <key=value>\",\n \"Log attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--scope-attr <key=value>\",\n \"Scope attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n ).action(async (opts: LogsSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n traceId: opts.traceId,\n spanId: opts.spanId,\n serviceName: opts.service,\n scopeName: opts.scope,\n severityText: opts.severityText,\n severityNumberMin: opts.severityMin\n ? parseInt(opts.severityMin, 10)\n : undefined,\n severityNumberMax: opts.severityMax\n ? parseInt(opts.severityMax, 10)\n : undefined,\n bodyContains: opts.body,\n timestampMin: opts.timestampMin,\n timestampMax: opts.timestampMax,\n logAttributes: parseAttributes(opts.logAttr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n scopeAttributes: parseAttributes(opts.scopeAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n };\n\n const result = await client.searchLogsPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return logs;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface MetricsSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n type: string;\n name?: string;\n service?: string;\n scope?: string;\n timeMin?: string;\n timeMax?: string;\n attr?: string[];\n resourceAttr?: string[];\n scopeAttr?: string[];\n sort?: string;\n}\n\ninterface MetricsDiscoverOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n}\n\nexport function createMetricsCommand(): Command {\n const metrics = new Command(\"metrics\").description(\"Query metrics\");\n\n withConnectionOptions(\n metrics\n .command(\"search\")\n .description(\"Search metrics\")\n .requiredOption(\n \"--type <type>\",\n \"Metric type (Gauge|Sum|Histogram|ExponentialHistogram|Summary)\"\n )\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"-n, --name <name>\", \"Filter by metric name\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--time-min <ns>\", \"Min time (nanoseconds)\")\n .option(\"--time-max <ns>\", \"Max time (nanoseconds)\")\n .option(\n \"-a, --attr <key=value>\",\n \"Attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--scope-attr <key=value>\",\n \"Scope attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n ).action(async (opts: MetricsSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n metricType: opts.type as\n | \"Gauge\"\n | \"Sum\"\n | \"Histogram\"\n | \"ExponentialHistogram\"\n | \"Summary\",\n metricName: opts.name,\n serviceName: opts.service,\n scopeName: opts.scope,\n timeUnixMin: opts.timeMin,\n timeUnixMax: opts.timeMax,\n attributes: parseAttributes(opts.attr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n scopeAttributes: parseAttributes(opts.scopeAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n };\n\n const result = await client.searchMetricsPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n metrics\n .command(\"discover\")\n .description(\"List available metrics\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n ).action(async (opts: MetricsDiscoverOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const result = await client.discoverMetrics();\n output(result.metrics, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return metrics;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n resolveConnectionOpts,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError } from \"../output.js\";\n\ninterface DashboardCreateOptions extends ClientOptions {\n name: string;\n treeVersion: string;\n json?: boolean;\n table?: boolean;\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport function createDashboardsCommand(): Command {\n const dashboards = new Command(\"dashboards\").description(\"Manage dashboards\");\n\n withConnectionOptions(\n dashboards\n .command(\"schema\")\n .description(\"Print UI tree schema for AI agents\")\n ).action(async (opts: ClientOptions) => {\n try {\n const { url, token } = resolveConnectionOpts(opts);\n const headers: Record<string, string> = {};\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n const response = await fetch(`${url}/dashboards/schema`, { headers });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n const schema = await response.text();\n process.stdout.write(schema);\n } catch (err) {\n outputError(err, false);\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n dashboards\n .command(\"create\")\n .description(\"Create a dashboard (reads uiTree JSON from stdin)\")\n .requiredOption(\"--name <name>\", \"Dashboard name\")\n .requiredOption(\"--tree-version <semver>\", \"UI tree version (semver)\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .addHelpText(\n \"after\",\n `\nExample:\n $ echo '{\"uiTree\":{\"root\":\"s1\",\"elements\":{\"s1\":{\"key\":\"s1\",\"type\":\"Stack\",\"props\":{\"direction\":\"vertical\",\"gap\":\"md\",\"align\":null},\"children\":[],\"parentKey\":\"\"}}}}' | kopai dashboards create --name \"My Dashboard\" --tree-version \"0.5.0\" --json`\n )\n ).action(async (opts: DashboardCreateOptions) => {\n const isJson = opts.json ?? false;\n try {\n const client = createClient(opts);\n const raw = await readStdin();\n let body: Record<string, unknown>;\n try {\n body = JSON.parse(raw) as Record<string, unknown>;\n } catch (e) {\n if (e instanceof SyntaxError) {\n process.stderr.write(`Invalid JSON input: ${e.message}\\n`);\n process.exit(2);\n }\n throw e;\n }\n\n const result = await client.createDashboard({\n name: opts.name,\n uiTreeVersion: opts.treeVersion,\n uiTree: (body.uiTree ?? body) as Record<string, unknown>,\n metadata: body.metadata as Record<string, unknown> | undefined,\n });\n\n const format = detectFormat(opts.json, opts.table);\n output(result, { format });\n } catch (err) {\n outputError(err, isJson);\n process.exit(1);\n }\n });\n\n return dashboards;\n}\n","import { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n saveConfig,\n resolveConfigPath,\n TOKEN_PREFIX_LENGTH,\n DEFAULT_URL,\n type Config,\n} from \"../config.js\";\n\nfunction readTokenFromStdin(): Promise<string> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question(\"Token: \", (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport function createLoginCommand(): Command {\n return new Command(\"login\")\n .description(\"Save an API token to .kopairc\")\n .option(\"--url <url>\", \"API base URL to save alongside token\")\n .option(\"--global\", \"Write to ~/.kopairc instead of ./.kopairc\")\n .action(async (opts: { url?: string; global?: boolean }) => {\n const token = await readTokenFromStdin();\n if (!token) {\n console.error(\"Token cannot be empty.\");\n process.exitCode = 2;\n return;\n }\n\n const updates: Partial<Config> = {\n token,\n url: opts.url ?? DEFAULT_URL,\n };\n\n const targetPath = resolveConfigPath(opts.global ?? false);\n saveConfig(updates, targetPath);\n\n // Warn if in a git repo and .kopairc is not gitignored\n if (!opts.global) {\n const gitDir = join(process.cwd(), \".git\");\n if (existsSync(gitDir)) {\n const gitignorePath = join(process.cwd(), \".gitignore\");\n let isIgnored = false;\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, \"utf-8\");\n isIgnored = content\n .split(\"\\n\")\n .some((line) => line.trim() === \".kopairc\");\n }\n if (!isIgnored) {\n console.error(\n \"Warning: .kopairc is not in .gitignore. Add it to avoid committing secrets.\"\n );\n }\n }\n }\n\n console.log(\n `Logged in. Token: ${token.slice(0, TOKEN_PREFIX_LENGTH)}...`\n );\n });\n}\n","import { Command } from \"commander\";\nimport { removeConfigToken, resolveConfigPath } from \"../config.js\";\n\nexport function createLogoutCommand(): Command {\n return new Command(\"logout\")\n .description(\"Remove saved API token from .kopairc\")\n .option(\"--global\", \"Remove from ~/.kopairc instead of ./.kopairc\")\n .action((opts: { global?: boolean }) => {\n const targetPath = resolveConfigPath(opts.global ?? false);\n const removed = removeConfigToken(targetPath);\n\n if (removed) {\n console.log(\"Logged out.\");\n } else {\n console.log(\"Not logged in.\");\n }\n });\n}\n","import { Command } from \"commander\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { loadConfig, TOKEN_PREFIX_LENGTH, DEFAULT_URL } from \"../config.js\";\n\nexport function createWhoamiCommand(): Command {\n return new Command(\"whoami\")\n .description(\"Show current authentication status\")\n .option(\"-c, --config <path>\", \"Config file path\")\n .action(async (opts: { config?: string }) => {\n const config = loadConfig(opts.config);\n\n if (!config.token) {\n console.log(\"Not logged in.\");\n return;\n }\n\n console.log(`Token: ${config.token.slice(0, TOKEN_PREFIX_LENGTH)}...`);\n console.log(`URL: ${config.url ?? `${DEFAULT_URL} (default)`}`);\n\n // Try to validate token against server\n try {\n const client = new KopaiClient({\n baseUrl: config.url ?? DEFAULT_URL,\n token: config.token,\n });\n await client.searchTracesPage({ limit: 1 });\n console.log(\"Token is valid.\");\n } catch (err: unknown) {\n const status =\n err && typeof err === \"object\" && \"status\" in err\n ? (err as { status: number }).status\n : undefined;\n if (status === 401) {\n console.log(\"Token is invalid or expired.\");\n } else {\n console.log(\"Could not reach server to validate token.\");\n }\n process.exitCode = 1;\n }\n });\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst CACHE_FILENAME = \"update-check.json\";\nconst CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ninterface CacheData {\n lastCheck: number;\n latestVersion: string | null;\n}\n\ninterface CheckOptions {\n fetchFn?: typeof fetch;\n}\n\nexport function getCacheDir(): string {\n switch (process.platform) {\n case \"darwin\":\n return join(homedir(), \"Library\", \"Caches\", \"kopai\");\n case \"win32\": {\n const localAppData = process.env.LOCALAPPDATA;\n if (localAppData) return join(localAppData, \"kopai\", \"cache\");\n return join(homedir(), \"AppData\", \"Local\", \"kopai\", \"cache\");\n }\n default: {\n const xdg = process.env.XDG_CACHE_HOME;\n if (xdg) return join(xdg, \"kopai\");\n return join(homedir(), \".cache\", \"kopai\");\n }\n }\n}\n\nexport function compareVersions(current: string, latest: string): boolean {\n const parse = (v: string): [number, number, number] | null => {\n const parts = v.split(\".\").map(Number);\n if (parts.length < 3 || parts.some(isNaN)) return null;\n return [parts[0]!, parts[1]!, parts[2]!];\n };\n const c = parse(current);\n const l = parse(latest);\n if (!c || !l) return false;\n if (l[0] !== c[0]) return l[0] > c[0];\n if (l[1] !== c[1]) return l[1] > c[1];\n return l[2] > c[2];\n}\n\nexport function shouldCheck(): boolean {\n if (process.env.KOPAI_NO_UPDATE_CHECK) return false;\n if (process.env.CI || process.env.BUILD_NUMBER || process.env.RUN_ID)\n return false;\n if (!process.stderr.isTTY) return false;\n return true;\n}\n\nasync function readCache(cacheDir: string): Promise<CacheData | null> {\n try {\n const raw = await readFile(join(cacheDir, CACHE_FILENAME), \"utf-8\");\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (typeof parsed.lastCheck !== \"number\") return null;\n const latestVersion =\n typeof parsed.latestVersion === \"string\" && parsed.latestVersion\n ? parsed.latestVersion\n : null;\n return { lastCheck: parsed.lastCheck, latestVersion };\n } catch {\n return null;\n }\n}\n\nasync function writeCache(cacheDir: string, data: CacheData): Promise<void> {\n try {\n await mkdir(cacheDir, { recursive: true });\n await writeFile(join(cacheDir, CACHE_FILENAME), JSON.stringify(data));\n } catch {\n // ignore cache write failures\n }\n}\n\nasync function fetchLatestVersion(\n fetchFn: typeof fetch\n): Promise<string | null> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n try {\n const res = await fetchFn(\"https://registry.npmjs.org/@kopai/cli/latest\", {\n signal: controller.signal,\n });\n if (!res.ok) return null;\n const data = (await res.json()) as Record<string, unknown>;\n if (typeof data?.version !== \"string\" || !data.version.trim()) return null;\n return data.version;\n } catch {\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction printNotice(current: string, latest: string): void {\n process.stderr.write(\n `\\n Update available: ${current} → ${latest}\\n Run: npx @kopai/cli@latest\\n Set KOPAI_NO_UPDATE_CHECK=1 to disable.\\n\\n`\n );\n}\n\nexport async function checkForUpdates(\n currentVersion: string,\n opts?: CheckOptions\n): Promise<void> {\n if (!shouldCheck()) return;\n\n const cacheDir = getCacheDir();\n const cache = await readCache(cacheDir);\n\n if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {\n if (\n cache.latestVersion &&\n compareVersions(currentVersion, cache.latestVersion)\n ) {\n printNotice(currentVersion, cache.latestVersion);\n }\n return;\n }\n\n const fetchFn = opts?.fetchFn ?? fetch;\n const latest = await fetchLatestVersion(fetchFn);\n\n await writeCache(cacheDir, { lastCheck: Date.now(), latestVersion: latest });\n\n if (latest && compareVersions(currentVersion, latest)) {\n printNotice(currentVersion, latest);\n }\n}\n","","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { createTracesCommand } from \"./commands/traces.js\";\nimport { createLogsCommand } from \"./commands/logs.js\";\nimport { createMetricsCommand } from \"./commands/metrics.js\";\nimport { createDashboardsCommand } from \"./commands/dashboards.js\";\nimport { createLoginCommand } from \"./commands/login.js\";\nimport { createLogoutCommand } from \"./commands/logout.js\";\nimport { createWhoamiCommand } from \"./commands/whoami.js\";\nimport { checkForUpdates } from \"./update-check.js\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nconst program = new Command();\n\nprogram\n .name(\"@kopai/cli\")\n .description(\"|--k> kopai - Query OpenTelemetry data\")\n .version(pkg.version)\n .addCommand(createTracesCommand())\n .addCommand(createLogsCommand())\n .addCommand(createMetricsCommand())\n .addCommand(createDashboardsCommand())\n .addCommand(createLoginCommand())\n .addCommand(createLogoutCommand())\n .addCommand(createWhoamiCommand())\n .addHelpText(\n \"after\",\n `\nExamples:\n $ kopai traces search # localhost:8000 (default, for @kopai/app running locally)\n $ kopai traces search --url https://example.com # remote instance\n $ kopai logs search --url https://example.com --token kpi_… # with auth`\n );\n\nprogram.parse();\nvoid checkForUpdates(pkg.version);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["DEFAULT_URL","collect","collect","pkg.version"],"sources":["../src/config.ts","../src/client.ts","../src/output.ts","../src/commands/traces.ts","../src/commands/logs.ts","../src/commands/metrics.ts","../src/commands/dashboards.ts","../src/commands/login.ts","../src/commands/logout.ts","../src/commands/whoami.ts","../src/update-check.ts","../package.json","../src/index.ts"],"sourcesContent":["import { readFileSync, existsSync, writeFileSync, chmodSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\nexport interface Config {\n url?: string;\n token?: string;\n}\n\nexport const CONFIG_FILENAME = \".kopairc\";\nexport const TOKEN_PREFIX_LENGTH = 10;\nexport const DEFAULT_URL = \"http://localhost:8000\";\n\n/** Owner read+write only (rw-------). Used for files containing secrets. */\nconst OWNER_READ_WRITE = 0o600;\n\nfunction loadConfigFile(path: string): Config | null {\n if (!existsSync(path)) return null;\n try {\n const content = readFileSync(path, \"utf-8\");\n return JSON.parse(content) as Config;\n } catch {\n return null;\n }\n}\n\nexport function loadConfig(configPath?: string): Config {\n // Priority: --config flag > ./.kopairc > ~/.kopairc\n const paths = configPath\n ? [configPath]\n : [join(process.cwd(), CONFIG_FILENAME), join(homedir(), CONFIG_FILENAME)];\n\n for (const path of paths) {\n const config = loadConfigFile(path);\n if (config) return config;\n }\n\n return {};\n}\n\nexport function resolveConfigPath(global: boolean): string {\n return global\n ? join(homedir(), CONFIG_FILENAME)\n : join(process.cwd(), CONFIG_FILENAME);\n}\n\nexport function saveConfig(updates: Partial<Config>, targetPath: string): void {\n let existing: Config = {};\n if (existsSync(targetPath)) {\n try {\n const content = readFileSync(targetPath, \"utf-8\");\n existing = JSON.parse(content) as Config;\n } catch {\n // ignore parse errors, overwrite\n }\n }\n const merged = { ...existing, ...updates };\n writeFileSync(targetPath, JSON.stringify(merged, null, 2) + \"\\n\", {\n encoding: \"utf-8\",\n mode: OWNER_READ_WRITE,\n });\n chmodSync(targetPath, OWNER_READ_WRITE);\n}\n\nexport function removeConfigToken(targetPath: string): boolean {\n if (!existsSync(targetPath)) return false;\n try {\n const content = readFileSync(targetPath, \"utf-8\");\n const config = JSON.parse(content) as Config;\n if (!config.token) return false;\n delete config.token;\n writeFileSync(targetPath, JSON.stringify(config, null, 2) + \"\\n\", {\n encoding: \"utf-8\",\n mode: OWNER_READ_WRITE,\n });\n } catch {\n return false;\n }\n try {\n chmodSync(targetPath, OWNER_READ_WRITE);\n } catch {\n // chmod failure does not affect the successful token removal\n }\n return true;\n}\n","import type { Command } from \"commander\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { loadConfig } from \"./config.js\";\n\nexport function withConnectionOptions<T extends Command>(cmd: T): T {\n return cmd\n .option(\"--url <url>\", \"API base URL\")\n .option(\"--token <token>\", \"Auth token\")\n .option(\"-c, --config <path>\", \"Config file path\")\n .option(\"--timeout <ms>\", \"Request timeout\") as T;\n}\n\nexport interface ClientOptions {\n config?: string;\n url?: string;\n token?: string;\n timeout?: number;\n}\n\nconst DEFAULT_URL = \"http://localhost:8000\";\n\nexport interface ConnectionOpts {\n url: string;\n token: string | undefined;\n}\n\nexport function resolveConnectionOpts(opts: ClientOptions): ConnectionOpts {\n const fileConfig = loadConfig(opts.config);\n const raw = opts.url ?? fileConfig.url ?? DEFAULT_URL;\n const url = raw.replace(/\\/signals\\/?$/, \"\").replace(/\\/$/, \"\");\n return {\n url,\n token: opts.token ?? fileConfig.token,\n };\n}\n\nexport function createClient(opts: ClientOptions): KopaiClient {\n const { url, token } = resolveConnectionOpts(opts);\n\n const timeout =\n opts.timeout != null ? parseInt(String(opts.timeout), 10) : undefined;\n\n return new KopaiClient({\n baseUrl: url,\n token,\n timeout: Number.isNaN(timeout) ? undefined : timeout,\n });\n}\n\nexport function parseAttributes(attrs?: string[]): Record<string, string> {\n if (!attrs || attrs.length === 0) return {};\n const result: Record<string, string> = {};\n for (const attr of attrs) {\n const idx = attr.indexOf(\"=\");\n if (idx === -1) {\n console.error(`Invalid attribute format: ${attr}. Use key=value`);\n process.exit(2);\n }\n result[attr.slice(0, idx)] = attr.slice(idx + 1);\n }\n return result;\n}\n","export type OutputFormat = \"json\" | \"table\";\n\nexport interface OutputOptions {\n format: OutputFormat;\n fields?: string[];\n}\n\nexport function detectFormat(json?: boolean, table?: boolean): OutputFormat {\n if (json) return \"json\";\n if (table) return \"table\";\n // Default: table for TTY, JSON for pipes\n return process.stdout.isTTY ? \"table\" : \"json\";\n}\n\nfunction countAttributes(attr: { values: Record<string, string[]> }): number {\n return Object.keys(attr.values).length;\n}\n\nfunction filterFields<T extends object>(data: T, fields: string[]): Partial<T> {\n return Object.fromEntries(\n Object.entries(data).filter(([key]) => fields.includes(key))\n ) as Partial<T>;\n}\n\nexport function parseFields(fieldsStr?: string): string[] | undefined {\n if (!fieldsStr) return undefined;\n return fieldsStr.split(\",\").map((f) => f.trim());\n}\n\nfunction isMetricsDiscoverData(data: unknown[]): data is Array<{\n attributes: { values: Record<string, string[]> };\n resourceAttributes: { values: Record<string, string[]> };\n}> {\n return (\n data.length > 0 &&\n typeof data[0] === \"object\" &&\n data[0] !== null &&\n \"attributes\" in data[0] &&\n \"resourceAttributes\" in data[0] &&\n typeof (data[0] as Record<string, unknown>).attributes === \"object\" &&\n (data[0] as Record<string, unknown>).attributes !== null &&\n \"values\" in ((data[0] as Record<string, unknown>).attributes as object)\n );\n}\n\nexport function output<T>(data: T, opts: OutputOptions): void {\n let outputData = data;\n\n // Apply field filtering\n if (opts.fields && opts.fields.length > 0) {\n if (Array.isArray(data)) {\n outputData = data.map((item) =>\n typeof item === \"object\" && item !== null\n ? filterFields(item as object, opts.fields!)\n : item\n ) as T;\n } else if (typeof data === \"object\" && data !== null) {\n outputData = filterFields(data as object, opts.fields) as T;\n }\n }\n\n if (opts.format === \"json\") {\n console.log(JSON.stringify(outputData, null, 2));\n } else {\n if (Array.isArray(outputData)) {\n if (outputData.length === 0) {\n console.log(\"No results found.\");\n } else if (!opts.fields && isMetricsDiscoverData(outputData)) {\n const transformed = outputData.map((m) => ({\n name: m.name,\n type: m.type,\n unit: m.unit,\n description: m.description,\n attrs: countAttributes(m.attributes),\n resourceAttrs: countAttributes(m.resourceAttributes),\n }));\n console.table(transformed);\n console.log(\"\\nUse --json for full attribute details.\");\n } else {\n console.table(outputData);\n }\n } else {\n console.log(outputData);\n }\n }\n}\n\nexport function outputError(error: unknown, json: boolean): void {\n const err =\n error instanceof Error\n ? { name: error.name, message: error.message }\n : { message: String(error) };\n\n if (json) {\n console.error(JSON.stringify({ error: err }));\n } else {\n console.error(`Error: ${err.message}`);\n }\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface TracesGetOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n}\n\ninterface TracesSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n traceId?: string;\n spanId?: string;\n parentSpanId?: string;\n service?: string;\n spanName?: string;\n spanKind?: string;\n statusCode?: string;\n scope?: string;\n timestampMin?: string;\n timestampMax?: string;\n durationMin?: string;\n durationMax?: string;\n spanAttr?: string[];\n resourceAttr?: string[];\n sort?: string;\n}\n\nexport function createTracesCommand(): Command {\n const traces = new Command(\"traces\").description(\"Query traces\");\n\n withConnectionOptions(\n traces\n .command(\"get\")\n .description(\"Get all spans for a trace by ID\")\n .argument(\"<traceId>\", \"Trace ID\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n ).action(async (traceId: string, opts: TracesGetOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const spans = await client.getTrace(traceId);\n output(spans, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n traces\n .command(\"search\")\n .description(\"Search traces\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"--trace-id <id>\", \"Filter by trace ID\")\n .option(\"--span-id <id>\", \"Filter by span ID\")\n .option(\"--parent-span-id <id>\", \"Filter by parent span ID\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--span-name <name>\", \"Filter by span name\")\n .option(\"--span-kind <kind>\", \"Filter by span kind\")\n .option(\"--status-code <code>\", \"Filter by status code\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--timestamp-min <ns>\", \"Min timestamp (nanoseconds)\")\n .option(\"--timestamp-max <ns>\", \"Max timestamp (nanoseconds)\")\n .option(\"--duration-min <ns>\", \"Min duration (nanoseconds)\")\n .option(\"--duration-max <ns>\", \"Max duration (nanoseconds)\")\n .option(\n \"--span-attr <key=value>\",\n \"Span attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n ).action(async (opts: TracesSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n traceId: opts.traceId,\n spanId: opts.spanId,\n parentSpanId: opts.parentSpanId,\n serviceName: opts.service,\n spanName: opts.spanName,\n spanKind: opts.spanKind,\n statusCode: opts.statusCode,\n scopeName: opts.scope,\n timestampMin: opts.timestampMin,\n timestampMax: opts.timestampMax,\n durationMin: opts.durationMin,\n durationMax: opts.durationMax,\n spanAttributes: parseAttributes(opts.spanAttr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n };\n\n const result = await client.searchTracesPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return traces;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface LogsSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n traceId?: string;\n spanId?: string;\n service?: string;\n scope?: string;\n severityText?: string;\n severityMin?: string;\n severityMax?: string;\n body?: string;\n timestampMin?: string;\n timestampMax?: string;\n logAttr?: string[];\n resourceAttr?: string[];\n scopeAttr?: string[];\n sort?: string;\n}\n\nexport function createLogsCommand(): Command {\n const logs = new Command(\"logs\").description(\"Query logs\");\n\n withConnectionOptions(\n logs\n .command(\"search\")\n .description(\"Search logs\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"--trace-id <id>\", \"Filter by trace ID\")\n .option(\"--span-id <id>\", \"Filter by span ID\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--severity-text <level>\", \"Filter by severity text\")\n .option(\"--severity-min <n>\", \"Min severity number\")\n .option(\"--severity-max <n>\", \"Max severity number\")\n .option(\"-b, --body <text>\", \"Filter by body contains\")\n .option(\"--timestamp-min <ns>\", \"Min timestamp (nanoseconds)\")\n .option(\"--timestamp-max <ns>\", \"Max timestamp (nanoseconds)\")\n .option(\n \"--log-attr <key=value>\",\n \"Log attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--scope-attr <key=value>\",\n \"Scope attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n ).action(async (opts: LogsSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n traceId: opts.traceId,\n spanId: opts.spanId,\n serviceName: opts.service,\n scopeName: opts.scope,\n severityText: opts.severityText,\n severityNumberMin: opts.severityMin\n ? parseInt(opts.severityMin, 10)\n : undefined,\n severityNumberMax: opts.severityMax\n ? parseInt(opts.severityMax, 10)\n : undefined,\n bodyContains: opts.body,\n timestampMin: opts.timestampMin,\n timestampMax: opts.timestampMax,\n logAttributes: parseAttributes(opts.logAttr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n scopeAttributes: parseAttributes(opts.scopeAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n };\n\n const result = await client.searchLogsPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return logs;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n","import { Command, InvalidArgumentError } from \"commander\";\nimport {\n createClient,\n parseAttributes,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError, parseFields } from \"../output.js\";\n\ninterface MetricsSearchOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n limit?: string;\n type: string;\n name?: string;\n service?: string;\n scope?: string;\n timeMin?: string;\n timeMax?: string;\n attr?: string[];\n resourceAttr?: string[];\n scopeAttr?: string[];\n sort?: string;\n aggregate?: string;\n groupBy?: string[];\n}\n\ninterface MetricsDiscoverOptions extends ClientOptions {\n json?: boolean;\n table?: boolean;\n fields?: string;\n}\n\nexport function createMetricsCommand(): Command {\n const metrics = new Command(\"metrics\").description(\"Query metrics\");\n\n withConnectionOptions(\n metrics\n .command(\"search\")\n .description(\"Search metrics\")\n .requiredOption(\n \"--type <type>\",\n \"Metric type (Gauge|Sum|Histogram|ExponentialHistogram|Summary)\"\n )\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n .option(\"-l, --limit <n>\", \"Max results\")\n .option(\"-n, --name <name>\", \"Filter by metric name\")\n .option(\"-s, --service <name>\", \"Filter by service name\")\n .option(\"--scope <name>\", \"Filter by scope name\")\n .option(\"--time-min <ns>\", \"Min time (nanoseconds)\")\n .option(\"--time-max <ns>\", \"Max time (nanoseconds)\")\n .option(\n \"-a, --attr <key=value>\",\n \"Attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--resource-attr <key=value>\",\n \"Resource attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\n \"--scope-attr <key=value>\",\n \"Scope attribute filter (repeatable)\",\n collect,\n []\n )\n .option(\"--sort <order>\", \"Sort order (ASC|DESC)\")\n .option(\n \"--aggregate <fn>\",\n \"Aggregation function (sum|avg|min|max|count)\"\n )\n .option(\n \"--group-by <attr>\",\n \"Group by attribute key (repeatable)\",\n collect,\n []\n )\n ).action(async (opts: MetricsSearchOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const limit = opts.limit ? parseInt(opts.limit, 10) : undefined;\n\n const filter = {\n metricType: opts.type as\n | \"Gauge\"\n | \"Sum\"\n | \"Histogram\"\n | \"ExponentialHistogram\"\n | \"Summary\",\n metricName: opts.name,\n serviceName: opts.service,\n scopeName: opts.scope,\n timeUnixMin: opts.timeMin,\n timeUnixMax: opts.timeMax,\n attributes: parseAttributes(opts.attr),\n resourceAttributes: parseAttributes(opts.resourceAttr),\n scopeAttributes: parseAttributes(opts.scopeAttr),\n limit,\n sortOrder: opts.sort as \"ASC\" | \"DESC\" | undefined,\n aggregate: toAggregateFn(opts.aggregate),\n groupBy:\n opts.groupBy && opts.groupBy.length > 0 ? opts.groupBy : undefined,\n };\n\n const result = filter.aggregate\n ? await client.searchAggregatedMetrics({\n ...filter,\n aggregate: filter.aggregate,\n })\n : await client.searchMetricsPage(filter);\n output(result.data, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n metrics\n .command(\"discover\")\n .description(\"List available metrics\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .option(\"-f, --fields <fields>\", \"Comma-separated fields to include\")\n ).action(async (opts: MetricsDiscoverOptions) => {\n const format = detectFormat(opts.json, opts.table);\n const fields = parseFields(opts.fields);\n try {\n const client = createClient(opts);\n const result = await client.discoverMetrics();\n output(result.metrics, { format, fields });\n } catch (err) {\n outputError(err, format === \"json\");\n process.exit(1);\n }\n });\n\n return metrics;\n}\n\nfunction collect(value: string, previous: string[]): string[] {\n return previous.concat([value]);\n}\n\ntype AggregateFn = \"sum\" | \"avg\" | \"min\" | \"max\" | \"count\";\n\nfunction isAggregateFn(value: string): value is AggregateFn {\n return (\n value === \"sum\" ||\n value === \"avg\" ||\n value === \"min\" ||\n value === \"max\" ||\n value === \"count\"\n );\n}\n\nfunction toAggregateFn(value: string | undefined): AggregateFn | undefined {\n if (value === undefined) return undefined;\n if (isAggregateFn(value)) return value;\n throw new InvalidArgumentError(`Invalid aggregate function: ${value}`);\n}\n","import { Command } from \"commander\";\nimport {\n createClient,\n resolveConnectionOpts,\n withConnectionOptions,\n type ClientOptions,\n} from \"../client.js\";\nimport { detectFormat, output, outputError } from \"../output.js\";\n\ninterface DashboardCreateOptions extends ClientOptions {\n name: string;\n treeVersion: string;\n json?: boolean;\n table?: boolean;\n}\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = [];\n for await (const chunk of process.stdin) {\n chunks.push(chunk as Buffer);\n }\n return Buffer.concat(chunks).toString(\"utf-8\");\n}\n\nexport function createDashboardsCommand(): Command {\n const dashboards = new Command(\"dashboards\").description(\"Manage dashboards\");\n\n withConnectionOptions(\n dashboards\n .command(\"schema\")\n .description(\"Print UI tree schema for AI agents\")\n ).action(async (opts: ClientOptions) => {\n try {\n const { url, token } = resolveConnectionOpts(opts);\n const headers: Record<string, string> = {};\n if (token) headers[\"Authorization\"] = `Bearer ${token}`;\n const response = await fetch(`${url}/dashboards/schema`, { headers });\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`);\n }\n const schema = await response.text();\n process.stdout.write(schema);\n } catch (err) {\n outputError(err, false);\n process.exit(1);\n }\n });\n\n withConnectionOptions(\n dashboards\n .command(\"create\")\n .description(\"Create a dashboard (reads uiTree JSON from stdin)\")\n .requiredOption(\"--name <name>\", \"Dashboard name\")\n .requiredOption(\"--tree-version <semver>\", \"UI tree version (semver)\")\n .option(\"-j, --json\", \"JSON output\")\n .option(\"-t, --table\", \"Table output\")\n .addHelpText(\n \"after\",\n `\nExample:\n $ echo '{\"uiTree\":{\"root\":\"s1\",\"elements\":{\"s1\":{\"key\":\"s1\",\"type\":\"Stack\",\"props\":{\"direction\":\"vertical\",\"gap\":\"md\",\"align\":null},\"children\":[],\"parentKey\":\"\"}}}}' | kopai dashboards create --name \"My Dashboard\" --tree-version \"0.5.0\" --json`\n )\n ).action(async (opts: DashboardCreateOptions) => {\n const isJson = opts.json ?? false;\n try {\n const client = createClient(opts);\n const raw = await readStdin();\n let body: Record<string, unknown>;\n try {\n body = JSON.parse(raw) as Record<string, unknown>;\n } catch (e) {\n if (e instanceof SyntaxError) {\n process.stderr.write(`Invalid JSON input: ${e.message}\\n`);\n process.exit(2);\n }\n throw e;\n }\n\n const result = await client.createDashboard({\n name: opts.name,\n uiTreeVersion: opts.treeVersion,\n uiTree: (body.uiTree ?? body) as Record<string, unknown>,\n metadata: body.metadata as Record<string, unknown> | undefined,\n });\n\n const format = detectFormat(opts.json, opts.table);\n output(result, { format });\n } catch (err) {\n outputError(err, isJson);\n process.exit(1);\n }\n });\n\n return dashboards;\n}\n","import { Command } from \"commander\";\nimport { createInterface } from \"node:readline\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport {\n saveConfig,\n resolveConfigPath,\n TOKEN_PREFIX_LENGTH,\n DEFAULT_URL,\n type Config,\n} from \"../config.js\";\n\nfunction readTokenFromStdin(): Promise<string> {\n return new Promise((resolve) => {\n const rl = createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n rl.question(\"Token: \", (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nexport function createLoginCommand(): Command {\n return new Command(\"login\")\n .description(\"Save an API token to .kopairc\")\n .option(\"--url <url>\", \"API base URL to save alongside token\")\n .option(\"--global\", \"Write to ~/.kopairc instead of ./.kopairc\")\n .action(async (opts: { url?: string; global?: boolean }) => {\n const token = await readTokenFromStdin();\n if (!token) {\n console.error(\"Token cannot be empty.\");\n process.exitCode = 2;\n return;\n }\n\n const updates: Partial<Config> = {\n token,\n url: opts.url ?? DEFAULT_URL,\n };\n\n const targetPath = resolveConfigPath(opts.global ?? false);\n saveConfig(updates, targetPath);\n\n // Warn if in a git repo and .kopairc is not gitignored\n if (!opts.global) {\n const gitDir = join(process.cwd(), \".git\");\n if (existsSync(gitDir)) {\n const gitignorePath = join(process.cwd(), \".gitignore\");\n let isIgnored = false;\n if (existsSync(gitignorePath)) {\n const content = readFileSync(gitignorePath, \"utf-8\");\n isIgnored = content\n .split(\"\\n\")\n .some((line) => line.trim() === \".kopairc\");\n }\n if (!isIgnored) {\n console.error(\n \"Warning: .kopairc is not in .gitignore. Add it to avoid committing secrets.\"\n );\n }\n }\n }\n\n console.log(\n `Logged in. Token: ${token.slice(0, TOKEN_PREFIX_LENGTH)}...`\n );\n });\n}\n","import { Command } from \"commander\";\nimport { removeConfigToken, resolveConfigPath } from \"../config.js\";\n\nexport function createLogoutCommand(): Command {\n return new Command(\"logout\")\n .description(\"Remove saved API token from .kopairc\")\n .option(\"--global\", \"Remove from ~/.kopairc instead of ./.kopairc\")\n .action((opts: { global?: boolean }) => {\n const targetPath = resolveConfigPath(opts.global ?? false);\n const removed = removeConfigToken(targetPath);\n\n if (removed) {\n console.log(\"Logged out.\");\n } else {\n console.log(\"Not logged in.\");\n }\n });\n}\n","import { Command } from \"commander\";\nimport { KopaiClient } from \"@kopai/sdk\";\nimport { loadConfig, TOKEN_PREFIX_LENGTH, DEFAULT_URL } from \"../config.js\";\n\nexport function createWhoamiCommand(): Command {\n return new Command(\"whoami\")\n .description(\"Show current authentication status\")\n .option(\"-c, --config <path>\", \"Config file path\")\n .action(async (opts: { config?: string }) => {\n const config = loadConfig(opts.config);\n\n if (!config.token) {\n console.log(\"Not logged in.\");\n return;\n }\n\n console.log(`Token: ${config.token.slice(0, TOKEN_PREFIX_LENGTH)}...`);\n console.log(`URL: ${config.url ?? `${DEFAULT_URL} (default)`}`);\n\n // Try to validate token against server\n try {\n const client = new KopaiClient({\n baseUrl: config.url ?? DEFAULT_URL,\n token: config.token,\n });\n await client.searchTracesPage({ limit: 1 });\n console.log(\"Token is valid.\");\n } catch (err: unknown) {\n const status =\n err && typeof err === \"object\" && \"status\" in err\n ? (err as { status: number }).status\n : undefined;\n if (status === 401) {\n console.log(\"Token is invalid or expired.\");\n } else {\n console.log(\"Could not reach server to validate token.\");\n }\n process.exitCode = 1;\n }\n });\n}\n","import { readFile, writeFile, mkdir } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { homedir } from \"node:os\";\n\nconst CACHE_FILENAME = \"update-check.json\";\nconst CHECK_INTERVAL_MS = 24 * 60 * 60 * 1000;\n\ninterface CacheData {\n lastCheck: number;\n latestVersion: string | null;\n}\n\ninterface CheckOptions {\n fetchFn?: typeof fetch;\n}\n\nexport function getCacheDir(): string {\n switch (process.platform) {\n case \"darwin\":\n return join(homedir(), \"Library\", \"Caches\", \"kopai\");\n case \"win32\": {\n const localAppData = process.env.LOCALAPPDATA;\n if (localAppData) return join(localAppData, \"kopai\", \"cache\");\n return join(homedir(), \"AppData\", \"Local\", \"kopai\", \"cache\");\n }\n default: {\n const xdg = process.env.XDG_CACHE_HOME;\n if (xdg) return join(xdg, \"kopai\");\n return join(homedir(), \".cache\", \"kopai\");\n }\n }\n}\n\nexport function compareVersions(current: string, latest: string): boolean {\n const parse = (v: string): [number, number, number] | null => {\n const parts = v.split(\".\").map(Number);\n if (parts.length < 3 || parts.some(isNaN)) return null;\n return [parts[0]!, parts[1]!, parts[2]!];\n };\n const c = parse(current);\n const l = parse(latest);\n if (!c || !l) return false;\n if (l[0] !== c[0]) return l[0] > c[0];\n if (l[1] !== c[1]) return l[1] > c[1];\n return l[2] > c[2];\n}\n\nexport function shouldCheck(): boolean {\n if (process.env.KOPAI_NO_UPDATE_CHECK) return false;\n if (process.env.CI || process.env.BUILD_NUMBER || process.env.RUN_ID)\n return false;\n if (!process.stderr.isTTY) return false;\n return true;\n}\n\nasync function readCache(cacheDir: string): Promise<CacheData | null> {\n try {\n const raw = await readFile(join(cacheDir, CACHE_FILENAME), \"utf-8\");\n const parsed = JSON.parse(raw) as Record<string, unknown>;\n if (typeof parsed.lastCheck !== \"number\") return null;\n const latestVersion =\n typeof parsed.latestVersion === \"string\" && parsed.latestVersion\n ? parsed.latestVersion\n : null;\n return { lastCheck: parsed.lastCheck, latestVersion };\n } catch {\n return null;\n }\n}\n\nasync function writeCache(cacheDir: string, data: CacheData): Promise<void> {\n try {\n await mkdir(cacheDir, { recursive: true });\n await writeFile(join(cacheDir, CACHE_FILENAME), JSON.stringify(data));\n } catch {\n // ignore cache write failures\n }\n}\n\nasync function fetchLatestVersion(\n fetchFn: typeof fetch\n): Promise<string | null> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 3000);\n try {\n const res = await fetchFn(\"https://registry.npmjs.org/@kopai/cli/latest\", {\n signal: controller.signal,\n });\n if (!res.ok) return null;\n const data = (await res.json()) as Record<string, unknown>;\n if (typeof data?.version !== \"string\" || !data.version.trim()) return null;\n return data.version;\n } catch {\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction printNotice(current: string, latest: string): void {\n process.stderr.write(\n `\\n Update available: ${current} → ${latest}\\n Run: npx @kopai/cli@latest\\n Set KOPAI_NO_UPDATE_CHECK=1 to disable.\\n\\n`\n );\n}\n\nexport async function checkForUpdates(\n currentVersion: string,\n opts?: CheckOptions\n): Promise<void> {\n if (!shouldCheck()) return;\n\n const cacheDir = getCacheDir();\n const cache = await readCache(cacheDir);\n\n if (cache && Date.now() - cache.lastCheck < CHECK_INTERVAL_MS) {\n if (\n cache.latestVersion &&\n compareVersions(currentVersion, cache.latestVersion)\n ) {\n printNotice(currentVersion, cache.latestVersion);\n }\n return;\n }\n\n const fetchFn = opts?.fetchFn ?? fetch;\n const latest = await fetchLatestVersion(fetchFn);\n\n await writeCache(cacheDir, { lastCheck: Date.now(), latestVersion: latest });\n\n if (latest && compareVersions(currentVersion, latest)) {\n printNotice(currentVersion, latest);\n }\n}\n","","#!/usr/bin/env node\n\nimport { Command } from \"commander\";\nimport { createTracesCommand } from \"./commands/traces.js\";\nimport { createLogsCommand } from \"./commands/logs.js\";\nimport { createMetricsCommand } from \"./commands/metrics.js\";\nimport { createDashboardsCommand } from \"./commands/dashboards.js\";\nimport { createLoginCommand } from \"./commands/login.js\";\nimport { createLogoutCommand } from \"./commands/logout.js\";\nimport { createWhoamiCommand } from \"./commands/whoami.js\";\nimport { checkForUpdates } from \"./update-check.js\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nconst program = new Command();\n\nprogram\n .name(\"@kopai/cli\")\n .description(\"|--k> kopai - Query OpenTelemetry data\")\n .version(pkg.version)\n .addCommand(createTracesCommand())\n .addCommand(createLogsCommand())\n .addCommand(createMetricsCommand())\n .addCommand(createDashboardsCommand())\n .addCommand(createLoginCommand())\n .addCommand(createLogoutCommand())\n .addCommand(createWhoamiCommand())\n .addHelpText(\n \"after\",\n `\nExamples:\n $ kopai traces search # localhost:8000 (default, for @kopai/app running locally)\n $ kopai traces search --url https://example.com # remote instance\n $ kopai logs search --url https://example.com --token kpi_… # with auth`\n );\n\nprogram.parse();\nvoid checkForUpdates(pkg.version);\n"],"mappings":";;;;;;;;;AASA,MAAa,kBAAkB;;AAK/B,MAAM,mBAAmB;AAEzB,SAAS,eAAe,MAA6B;AACnD,KAAI,CAAC,WAAW,KAAK,CAAE,QAAO;AAC9B,KAAI;EACF,MAAM,UAAU,aAAa,MAAM,QAAQ;AAC3C,SAAO,KAAK,MAAM,QAAQ;SACpB;AACN,SAAO;;;AAIX,SAAgB,WAAW,YAA6B;CAEtD,MAAM,QAAQ,aACV,CAAC,WAAW,GACZ,CAAC,KAAK,QAAQ,KAAK,EAAE,gBAAgB,EAAE,KAAK,SAAS,EAAE,gBAAgB,CAAC;AAE5E,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,SAAS,eAAe,KAAK;AACnC,MAAI,OAAQ,QAAO;;AAGrB,QAAO,EAAE;;AAGX,SAAgB,kBAAkB,QAAyB;AACzD,QAAO,SACH,KAAK,SAAS,EAAE,gBAAgB,GAChC,KAAK,QAAQ,KAAK,EAAE,gBAAgB;;AAG1C,SAAgB,WAAW,SAA0B,YAA0B;CAC7E,IAAI,WAAmB,EAAE;AACzB,KAAI,WAAW,WAAW,CACxB,KAAI;EACF,MAAM,UAAU,aAAa,YAAY,QAAQ;AACjD,aAAW,KAAK,MAAM,QAAQ;SACxB;CAIV,MAAM,SAAS;EAAE,GAAG;EAAU,GAAG;EAAS;AAC1C,eAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,EAAE,GAAG,MAAM;EAChE,UAAU;EACV,MAAM;EACP,CAAC;AACF,WAAU,YAAY,iBAAiB;;AAGzC,SAAgB,kBAAkB,YAA6B;AAC7D,KAAI,CAAC,WAAW,WAAW,CAAE,QAAO;AACpC,KAAI;EACF,MAAM,UAAU,aAAa,YAAY,QAAQ;EACjD,MAAM,SAAS,KAAK,MAAM,QAAQ;AAClC,MAAI,CAAC,OAAO,MAAO,QAAO;AAC1B,SAAO,OAAO;AACd,gBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,EAAE,GAAG,MAAM;GAChE,UAAU;GACV,MAAM;GACP,CAAC;SACI;AACN,SAAO;;AAET,KAAI;AACF,YAAU,YAAY,iBAAiB;SACjC;AAGR,QAAO;;;;AC/ET,SAAgB,sBAAyC,KAAW;AAClE,QAAO,IACJ,OAAO,eAAe,eAAe,CACrC,OAAO,mBAAmB,aAAa,CACvC,OAAO,uBAAuB,mBAAmB,CACjD,OAAO,kBAAkB,kBAAkB;;AAUhD,MAAM,cAAc;AAOpB,SAAgB,sBAAsB,MAAqC;CACzE,MAAM,aAAa,WAAW,KAAK,OAAO;AAG1C,QAAO;EACL,MAHU,KAAK,OAAO,WAAW,OAAO,aAC1B,QAAQ,iBAAiB,GAAG,CAAC,QAAQ,OAAO,GAAG;EAG7D,OAAO,KAAK,SAAS,WAAW;EACjC;;AAGH,SAAgB,aAAa,MAAkC;CAC7D,MAAM,EAAE,KAAK,UAAU,sBAAsB,KAAK;CAElD,MAAM,UACJ,KAAK,WAAW,OAAO,SAAS,OAAO,KAAK,QAAQ,EAAE,GAAG,GAAG,KAAA;AAE9D,QAAO,IAAI,YAAY;EACrB,SAAS;EACT;EACA,SAAS,OAAO,MAAM,QAAQ,GAAG,KAAA,IAAY;EAC9C,CAAC;;AAGJ,SAAgB,gBAAgB,OAA0C;AACxE,KAAI,CAAC,SAAS,MAAM,WAAW,EAAG,QAAO,EAAE;CAC3C,MAAM,SAAiC,EAAE;AACzC,MAAK,MAAM,QAAQ,OAAO;EACxB,MAAM,MAAM,KAAK,QAAQ,IAAI;AAC7B,MAAI,QAAQ,IAAI;AACd,WAAQ,MAAM,6BAA6B,KAAK,iBAAiB;AACjE,WAAQ,KAAK,EAAE;;AAEjB,SAAO,KAAK,MAAM,GAAG,IAAI,IAAI,KAAK,MAAM,MAAM,EAAE;;AAElD,QAAO;;;;ACrDT,SAAgB,aAAa,MAAgB,OAA+B;AAC1E,KAAI,KAAM,QAAO;AACjB,KAAI,MAAO,QAAO;AAElB,QAAO,QAAQ,OAAO,QAAQ,UAAU;;AAG1C,SAAS,gBAAgB,MAAoD;AAC3E,QAAO,OAAO,KAAK,KAAK,OAAO,CAAC;;AAGlC,SAAS,aAA+B,MAAS,QAA8B;AAC7E,QAAO,OAAO,YACZ,OAAO,QAAQ,KAAK,CAAC,QAAQ,CAAC,SAAS,OAAO,SAAS,IAAI,CAAC,CAC7D;;AAGH,SAAgB,YAAY,WAA0C;AACpE,KAAI,CAAC,UAAW,QAAO,KAAA;AACvB,QAAO,UAAU,MAAM,IAAI,CAAC,KAAK,MAAM,EAAE,MAAM,CAAC;;AAGlD,SAAS,sBAAsB,MAG5B;AACD,QACE,KAAK,SAAS,KACd,OAAO,KAAK,OAAO,YACnB,KAAK,OAAO,QACZ,gBAAgB,KAAK,MACrB,wBAAwB,KAAK,MAC7B,OAAQ,KAAK,GAA+B,eAAe,YAC1D,KAAK,GAA+B,eAAe,QACpD,YAAc,KAAK,GAA+B;;AAItD,SAAgB,OAAU,MAAS,MAA2B;CAC5D,IAAI,aAAa;AAGjB,KAAI,KAAK,UAAU,KAAK,OAAO,SAAS;MAClC,MAAM,QAAQ,KAAK,CACrB,cAAa,KAAK,KAAK,SACrB,OAAO,SAAS,YAAY,SAAS,OACjC,aAAa,MAAgB,KAAK,OAAQ,GAC1C,KACL;WACQ,OAAO,SAAS,YAAY,SAAS,KAC9C,cAAa,aAAa,MAAgB,KAAK,OAAO;;AAI1D,KAAI,KAAK,WAAW,OAClB,SAAQ,IAAI,KAAK,UAAU,YAAY,MAAM,EAAE,CAAC;UAE5C,MAAM,QAAQ,WAAW,CAC3B,KAAI,WAAW,WAAW,EACxB,SAAQ,IAAI,oBAAoB;UACvB,CAAC,KAAK,UAAU,sBAAsB,WAAW,EAAE;EAC5D,MAAM,cAAc,WAAW,KAAK,OAAO;GACzC,MAAM,EAAE;GACR,MAAM,EAAE;GACR,MAAM,EAAE;GACR,aAAa,EAAE;GACf,OAAO,gBAAgB,EAAE,WAAW;GACpC,eAAe,gBAAgB,EAAE,mBAAmB;GACrD,EAAE;AACH,UAAQ,MAAM,YAAY;AAC1B,UAAQ,IAAI,2CAA2C;OAEvD,SAAQ,MAAM,WAAW;KAG3B,SAAQ,IAAI,WAAW;;AAK7B,SAAgB,YAAY,OAAgB,MAAqB;CAC/D,MAAM,MACJ,iBAAiB,QACb;EAAE,MAAM,MAAM;EAAM,SAAS,MAAM;EAAS,GAC5C,EAAE,SAAS,OAAO,MAAM,EAAE;AAEhC,KAAI,KACF,SAAQ,MAAM,KAAK,UAAU,EAAE,OAAO,KAAK,CAAC,CAAC;KAE7C,SAAQ,MAAM,UAAU,IAAI,UAAU;;;;AC3D1C,SAAgB,sBAA+B;CAC7C,MAAM,SAAS,IAAI,QAAQ,SAAS,CAAC,YAAY,eAAe;AAEhE,uBACE,OACG,QAAQ,MAAM,CACd,YAAY,kCAAkC,CAC9C,SAAS,aAAa,WAAW,CACjC,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,OAAO,yBAAyB,oCAAoC,CACxE,CAAC,OAAO,OAAO,SAAiB,SAA2B;EAC1D,MAAM,SAAS,aAAa,KAAK,MAAM,KAAK,MAAM;EAClD,MAAM,SAAS,YAAY,KAAK,OAAO;AACvC,MAAI;AAGF,UADc,MADC,aAAa,KAAK,CACN,SAAS,QAAQ,EAC9B;IAAE;IAAQ;IAAQ,CAAC;WAC1B,KAAK;AACZ,eAAY,KAAK,WAAW,OAAO;AACnC,WAAQ,KAAK,EAAE;;GAEjB;AAEF,uBACE,OACG,QAAQ,SAAS,CACjB,YAAY,gBAAgB,CAC5B,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,OAAO,yBAAyB,oCAAoC,CACpE,OAAO,mBAAmB,cAAc,CACxC,OAAO,mBAAmB,qBAAqB,CAC/C,OAAO,kBAAkB,oBAAoB,CAC7C,OAAO,yBAAyB,2BAA2B,CAC3D,OAAO,wBAAwB,yBAAyB,CACxD,OAAO,sBAAsB,sBAAsB,CACnD,OAAO,sBAAsB,sBAAsB,CACnD,OAAO,wBAAwB,wBAAwB,CACvD,OAAO,kBAAkB,uBAAuB,CAChD,OAAO,wBAAwB,8BAA8B,CAC7D,OAAO,wBAAwB,8BAA8B,CAC7D,OAAO,uBAAuB,6BAA6B,CAC3D,OAAO,uBAAuB,6BAA6B,CAC3D,OACC,2BACA,sCACAC,WACA,EAAE,CACH,CACA,OACC,+BACA,0CACAA,WACA,EAAE,CACH,CACA,OAAO,kBAAkB,wBAAwB,CACrD,CAAC,OAAO,OAAO,SAA8B;EAC5C,MAAM,SAAS,aAAa,KAAK,MAAM,KAAK,MAAM;EAClD,MAAM,SAAS,YAAY,KAAK,OAAO;AACvC,MAAI;GACF,MAAM,SAAS,aAAa,KAAK;GACjC,MAAM,QAAQ,KAAK,QAAQ,SAAS,KAAK,OAAO,GAAG,GAAG,KAAA;GAEtD,MAAM,SAAS;IACb,SAAS,KAAK;IACd,QAAQ,KAAK;IACb,cAAc,KAAK;IACnB,aAAa,KAAK;IAClB,UAAU,KAAK;IACf,UAAU,KAAK;IACf,YAAY,KAAK;IACjB,WAAW,KAAK;IAChB,cAAc,KAAK;IACnB,cAAc,KAAK;IACnB,aAAa,KAAK;IAClB,aAAa,KAAK;IAClB,gBAAgB,gBAAgB,KAAK,SAAS;IAC9C,oBAAoB,gBAAgB,KAAK,aAAa;IACtD;IACA,WAAW,KAAK;IACjB;AAGD,WADe,MAAM,OAAO,iBAAiB,OAAO,EACtC,MAAM;IAAE;IAAQ;IAAQ,CAAC;WAChC,KAAK;AACZ,eAAY,KAAK,WAAW,OAAO;AACnC,WAAQ,KAAK,EAAE;;GAEjB;AAEF,QAAO;;AAGT,SAASA,UAAQ,OAAe,UAA8B;AAC5D,QAAO,SAAS,OAAO,CAAC,MAAM,CAAC;;;;ACtGjC,SAAgB,oBAA6B;CAC3C,MAAM,OAAO,IAAI,QAAQ,OAAO,CAAC,YAAY,aAAa;AAE1D,uBACE,KACG,QAAQ,SAAS,CACjB,YAAY,cAAc,CAC1B,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,OAAO,yBAAyB,oCAAoC,CACpE,OAAO,mBAAmB,cAAc,CACxC,OAAO,mBAAmB,qBAAqB,CAC/C,OAAO,kBAAkB,oBAAoB,CAC7C,OAAO,wBAAwB,yBAAyB,CACxD,OAAO,kBAAkB,uBAAuB,CAChD,OAAO,2BAA2B,0BAA0B,CAC5D,OAAO,sBAAsB,sBAAsB,CACnD,OAAO,sBAAsB,sBAAsB,CACnD,OAAO,qBAAqB,0BAA0B,CACtD,OAAO,wBAAwB,8BAA8B,CAC7D,OAAO,wBAAwB,8BAA8B,CAC7D,OACC,0BACA,qCACAC,WACA,EAAE,CACH,CACA,OACC,+BACA,0CACAA,WACA,EAAE,CACH,CACA,OACC,4BACA,uCACAA,WACA,EAAE,CACH,CACA,OAAO,kBAAkB,wBAAwB,CACrD,CAAC,OAAO,OAAO,SAA4B;EAC1C,MAAM,SAAS,aAAa,KAAK,MAAM,KAAK,MAAM;EAClD,MAAM,SAAS,YAAY,KAAK,OAAO;AACvC,MAAI;GACF,MAAM,SAAS,aAAa,KAAK;GACjC,MAAM,QAAQ,KAAK,QAAQ,SAAS,KAAK,OAAO,GAAG,GAAG,KAAA;GAEtD,MAAM,SAAS;IACb,SAAS,KAAK;IACd,QAAQ,KAAK;IACb,aAAa,KAAK;IAClB,WAAW,KAAK;IAChB,cAAc,KAAK;IACnB,mBAAmB,KAAK,cACpB,SAAS,KAAK,aAAa,GAAG,GAC9B,KAAA;IACJ,mBAAmB,KAAK,cACpB,SAAS,KAAK,aAAa,GAAG,GAC9B,KAAA;IACJ,cAAc,KAAK;IACnB,cAAc,KAAK;IACnB,cAAc,KAAK;IACnB,eAAe,gBAAgB,KAAK,QAAQ;IAC5C,oBAAoB,gBAAgB,KAAK,aAAa;IACtD,iBAAiB,gBAAgB,KAAK,UAAU;IAChD;IACA,WAAW,KAAK;IACjB;AAGD,WADe,MAAM,OAAO,eAAe,OAAO,EACpC,MAAM;IAAE;IAAQ;IAAQ,CAAC;WAChC,KAAK;AACZ,eAAY,KAAK,WAAW,OAAO;AACnC,WAAQ,KAAK,EAAE;;GAEjB;AAEF,QAAO;;AAGT,SAASA,UAAQ,OAAe,UAA8B;AAC5D,QAAO,SAAS,OAAO,CAAC,MAAM,CAAC;;;;AC7EjC,SAAgB,uBAAgC;CAC9C,MAAM,UAAU,IAAI,QAAQ,UAAU,CAAC,YAAY,gBAAgB;AAEnE,uBACE,QACG,QAAQ,SAAS,CACjB,YAAY,iBAAiB,CAC7B,eACC,iBACA,iEACD,CACA,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,OAAO,yBAAyB,oCAAoC,CACpE,OAAO,mBAAmB,cAAc,CACxC,OAAO,qBAAqB,wBAAwB,CACpD,OAAO,wBAAwB,yBAAyB,CACxD,OAAO,kBAAkB,uBAAuB,CAChD,OAAO,mBAAmB,yBAAyB,CACnD,OAAO,mBAAmB,yBAAyB,CACnD,OACC,0BACA,iCACA,SACA,EAAE,CACH,CACA,OACC,+BACA,0CACA,SACA,EAAE,CACH,CACA,OACC,4BACA,uCACA,SACA,EAAE,CACH,CACA,OAAO,kBAAkB,wBAAwB,CACjD,OACC,oBACA,+CACD,CACA,OACC,qBACA,uCACA,SACA,EAAE,CACH,CACJ,CAAC,OAAO,OAAO,SAA+B;EAC7C,MAAM,SAAS,aAAa,KAAK,MAAM,KAAK,MAAM;EAClD,MAAM,SAAS,YAAY,KAAK,OAAO;AACvC,MAAI;GACF,MAAM,SAAS,aAAa,KAAK;GACjC,MAAM,QAAQ,KAAK,QAAQ,SAAS,KAAK,OAAO,GAAG,GAAG,KAAA;GAEtD,MAAM,SAAS;IACb,YAAY,KAAK;IAMjB,YAAY,KAAK;IACjB,aAAa,KAAK;IAClB,WAAW,KAAK;IAChB,aAAa,KAAK;IAClB,aAAa,KAAK;IAClB,YAAY,gBAAgB,KAAK,KAAK;IACtC,oBAAoB,gBAAgB,KAAK,aAAa;IACtD,iBAAiB,gBAAgB,KAAK,UAAU;IAChD;IACA,WAAW,KAAK;IAChB,WAAW,cAAc,KAAK,UAAU;IACxC,SACE,KAAK,WAAW,KAAK,QAAQ,SAAS,IAAI,KAAK,UAAU,KAAA;IAC5D;AAQD,WANe,OAAO,YAClB,MAAM,OAAO,wBAAwB;IACnC,GAAG;IACH,WAAW,OAAO;IACnB,CAAC,GACF,MAAM,OAAO,kBAAkB,OAAO,EAC5B,MAAM;IAAE;IAAQ;IAAQ,CAAC;WAChC,KAAK;AACZ,eAAY,KAAK,WAAW,OAAO;AACnC,WAAQ,KAAK,EAAE;;GAEjB;AAEF,uBACE,QACG,QAAQ,WAAW,CACnB,YAAY,yBAAyB,CACrC,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,OAAO,yBAAyB,oCAAoC,CACxE,CAAC,OAAO,OAAO,SAAiC;EAC/C,MAAM,SAAS,aAAa,KAAK,MAAM,KAAK,MAAM;EAClD,MAAM,SAAS,YAAY,KAAK,OAAO;AACvC,MAAI;AAGF,WADe,MADA,aAAa,KAAK,CACL,iBAAiB,EAC/B,SAAS;IAAE;IAAQ;IAAQ,CAAC;WACnC,KAAK;AACZ,eAAY,KAAK,WAAW,OAAO;AACnC,WAAQ,KAAK,EAAE;;GAEjB;AAEF,QAAO;;AAGT,SAAS,QAAQ,OAAe,UAA8B;AAC5D,QAAO,SAAS,OAAO,CAAC,MAAM,CAAC;;AAKjC,SAAS,cAAc,OAAqC;AAC1D,QACE,UAAU,SACV,UAAU,SACV,UAAU,SACV,UAAU,SACV,UAAU;;AAId,SAAS,cAAc,OAAoD;AACzE,KAAI,UAAU,KAAA,EAAW,QAAO,KAAA;AAChC,KAAI,cAAc,MAAM,CAAE,QAAO;AACjC,OAAM,IAAI,qBAAqB,+BAA+B,QAAQ;;;;ACvJxE,eAAe,YAA6B;CAC1C,MAAM,SAAmB,EAAE;AAC3B,YAAW,MAAM,SAAS,QAAQ,MAChC,QAAO,KAAK,MAAgB;AAE9B,QAAO,OAAO,OAAO,OAAO,CAAC,SAAS,QAAQ;;AAGhD,SAAgB,0BAAmC;CACjD,MAAM,aAAa,IAAI,QAAQ,aAAa,CAAC,YAAY,oBAAoB;AAE7E,uBACE,WACG,QAAQ,SAAS,CACjB,YAAY,qCAAqC,CACrD,CAAC,OAAO,OAAO,SAAwB;AACtC,MAAI;GACF,MAAM,EAAE,KAAK,UAAU,sBAAsB,KAAK;GAClD,MAAM,UAAkC,EAAE;AAC1C,OAAI,MAAO,SAAQ,mBAAmB,UAAU;GAChD,MAAM,WAAW,MAAM,MAAM,GAAG,IAAI,qBAAqB,EAAE,SAAS,CAAC;AACrE,OAAI,CAAC,SAAS,GACZ,OAAM,IAAI,MAAM,QAAQ,SAAS,OAAO,IAAI,SAAS,aAAa;GAEpE,MAAM,SAAS,MAAM,SAAS,MAAM;AACpC,WAAQ,OAAO,MAAM,OAAO;WACrB,KAAK;AACZ,eAAY,KAAK,MAAM;AACvB,WAAQ,KAAK,EAAE;;GAEjB;AAEF,uBACE,WACG,QAAQ,SAAS,CACjB,YAAY,oDAAoD,CAChE,eAAe,iBAAiB,iBAAiB,CACjD,eAAe,2BAA2B,2BAA2B,CACrE,OAAO,cAAc,cAAc,CACnC,OAAO,eAAe,eAAe,CACrC,YACC,SACA;;uPAGD,CACJ,CAAC,OAAO,OAAO,SAAiC;EAC/C,MAAM,SAAS,KAAK,QAAQ;AAC5B,MAAI;GACF,MAAM,SAAS,aAAa,KAAK;GACjC,MAAM,MAAM,MAAM,WAAW;GAC7B,IAAI;AACJ,OAAI;AACF,WAAO,KAAK,MAAM,IAAI;YACf,GAAG;AACV,QAAI,aAAa,aAAa;AAC5B,aAAQ,OAAO,MAAM,uBAAuB,EAAE,QAAQ,IAAI;AAC1D,aAAQ,KAAK,EAAE;;AAEjB,UAAM;;AAWR,UARe,MAAM,OAAO,gBAAgB;IAC1C,MAAM,KAAK;IACX,eAAe,KAAK;IACpB,QAAS,KAAK,UAAU;IACxB,UAAU,KAAK;IAChB,CAAC,EAGa,EAAE,QADF,aAAa,KAAK,MAAM,KAAK,MAAM,EACzB,CAAC;WACnB,KAAK;AACZ,eAAY,KAAK,OAAO;AACxB,WAAQ,KAAK,EAAE;;GAEjB;AAEF,QAAO;;;;ACjFT,SAAS,qBAAsC;AAC7C,QAAO,IAAI,SAAS,YAAY;EAC9B,MAAM,KAAK,gBAAgB;GACzB,OAAO,QAAQ;GACf,QAAQ,QAAQ;GACjB,CAAC;AACF,KAAG,SAAS,YAAY,WAAW;AACjC,MAAG,OAAO;AACV,WAAQ,OAAO,MAAM,CAAC;IACtB;GACF;;AAGJ,SAAgB,qBAA8B;AAC5C,QAAO,IAAI,QAAQ,QAAQ,CACxB,YAAY,gCAAgC,CAC5C,OAAO,eAAe,uCAAuC,CAC7D,OAAO,YAAY,4CAA4C,CAC/D,OAAO,OAAO,SAA6C;EAC1D,MAAM,QAAQ,MAAM,oBAAoB;AACxC,MAAI,CAAC,OAAO;AACV,WAAQ,MAAM,yBAAyB;AACvC,WAAQ,WAAW;AACnB;;AASF,aANiC;GAC/B;GACA,KAAK,KAAK,OAAA;GACX,EAEkB,kBAAkB,KAAK,UAAU,MAAM,CAC3B;AAG/B,MAAI,CAAC,KAAK;OAEJ,WADW,KAAK,QAAQ,KAAK,EAAE,OAAO,CACpB,EAAE;IACtB,MAAM,gBAAgB,KAAK,QAAQ,KAAK,EAAE,aAAa;IACvD,IAAI,YAAY;AAChB,QAAI,WAAW,cAAc,CAE3B,aADgB,aAAa,eAAe,QAAQ,CAEjD,MAAM,KAAK,CACX,MAAM,SAAS,KAAK,MAAM,KAAK,WAAW;AAE/C,QAAI,CAAC,UACH,SAAQ,MACN,8EACD;;;AAKP,UAAQ,IACN,qBAAqB,MAAM,MAAM,GAAA,GAAuB,CAAC,KAC1D;GACD;;;;AClEN,SAAgB,sBAA+B;AAC7C,QAAO,IAAI,QAAQ,SAAS,CACzB,YAAY,uCAAuC,CACnD,OAAO,YAAY,+CAA+C,CAClE,QAAQ,SAA+B;AAItC,MAFgB,kBADG,kBAAkB,KAAK,UAAU,MAAM,CACb,CAG3C,SAAQ,IAAI,cAAc;MAE1B,SAAQ,IAAI,iBAAiB;GAE/B;;;;ACZN,SAAgB,sBAA+B;AAC7C,QAAO,IAAI,QAAQ,SAAS,CACzB,YAAY,qCAAqC,CACjD,OAAO,uBAAuB,mBAAmB,CACjD,OAAO,OAAO,SAA8B;EAC3C,MAAM,SAAS,WAAW,KAAK,OAAO;AAEtC,MAAI,CAAC,OAAO,OAAO;AACjB,WAAQ,IAAI,iBAAiB;AAC7B;;AAGF,UAAQ,IAAI,UAAU,OAAO,MAAM,MAAM,GAAA,GAAuB,CAAC,KAAK;AACtE,UAAQ,IAAI,QAAQ,OAAO,OAAO,oCAA6B;AAG/D,MAAI;AAKF,SAJe,IAAI,YAAY;IAC7B,SAAS,OAAO,OAAA;IAChB,OAAO,OAAO;IACf,CAAC,CACW,iBAAiB,EAAE,OAAO,GAAG,CAAC;AAC3C,WAAQ,IAAI,kBAAkB;WACvB,KAAc;AAKrB,QAHE,OAAO,OAAO,QAAQ,YAAY,YAAY,MACzC,IAA2B,SAC5B,KAAA,OACS,IACb,SAAQ,IAAI,+BAA+B;OAE3C,SAAQ,IAAI,4CAA4C;AAE1D,WAAQ,WAAW;;GAErB;;;;ACnCN,MAAM,iBAAiB;AACvB,MAAM,oBAAoB,OAAU,KAAK;AAWzC,SAAgB,cAAsB;AACpC,SAAQ,QAAQ,UAAhB;EACE,KAAK,SACH,QAAO,KAAK,SAAS,EAAE,WAAW,UAAU,QAAQ;EACtD,KAAK,SAAS;GACZ,MAAM,eAAe,QAAQ,IAAI;AACjC,OAAI,aAAc,QAAO,KAAK,cAAc,SAAS,QAAQ;AAC7D,UAAO,KAAK,SAAS,EAAE,WAAW,SAAS,SAAS,QAAQ;;EAE9D,SAAS;GACP,MAAM,MAAM,QAAQ,IAAI;AACxB,OAAI,IAAK,QAAO,KAAK,KAAK,QAAQ;AAClC,UAAO,KAAK,SAAS,EAAE,UAAU,QAAQ;;;;AAK/C,SAAgB,gBAAgB,SAAiB,QAAyB;CACxE,MAAM,SAAS,MAA+C;EAC5D,MAAM,QAAQ,EAAE,MAAM,IAAI,CAAC,IAAI,OAAO;AACtC,MAAI,MAAM,SAAS,KAAK,MAAM,KAAK,MAAM,CAAE,QAAO;AAClD,SAAO;GAAC,MAAM;GAAK,MAAM;GAAK,MAAM;GAAI;;CAE1C,MAAM,IAAI,MAAM,QAAQ;CACxB,MAAM,IAAI,MAAM,OAAO;AACvB,KAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,KAAI,EAAE,OAAO,EAAE,GAAI,QAAO,EAAE,KAAK,EAAE;AACnC,KAAI,EAAE,OAAO,EAAE,GAAI,QAAO,EAAE,KAAK,EAAE;AACnC,QAAO,EAAE,KAAK,EAAE;;AAGlB,SAAgB,cAAuB;AACrC,KAAI,QAAQ,IAAI,sBAAuB,QAAO;AAC9C,KAAI,QAAQ,IAAI,MAAM,QAAQ,IAAI,gBAAgB,QAAQ,IAAI,OAC5D,QAAO;AACT,KAAI,CAAC,QAAQ,OAAO,MAAO,QAAO;AAClC,QAAO;;AAGT,eAAe,UAAU,UAA6C;AACpE,KAAI;EACF,MAAM,MAAM,MAAM,SAAS,KAAK,UAAU,eAAe,EAAE,QAAQ;EACnE,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,OAAO,OAAO,cAAc,SAAU,QAAO;EACjD,MAAM,gBACJ,OAAO,OAAO,kBAAkB,YAAY,OAAO,gBAC/C,OAAO,gBACP;AACN,SAAO;GAAE,WAAW,OAAO;GAAW;GAAe;SAC/C;AACN,SAAO;;;AAIX,eAAe,WAAW,UAAkB,MAAgC;AAC1E,KAAI;AACF,QAAM,MAAM,UAAU,EAAE,WAAW,MAAM,CAAC;AAC1C,QAAM,UAAU,KAAK,UAAU,eAAe,EAAE,KAAK,UAAU,KAAK,CAAC;SAC/D;;AAKV,eAAe,mBACb,SACwB;CACxB,MAAM,aAAa,IAAI,iBAAiB;CACxC,MAAM,UAAU,iBAAiB,WAAW,OAAO,EAAE,IAAK;AAC1D,KAAI;EACF,MAAM,MAAM,MAAM,QAAQ,gDAAgD,EACxE,QAAQ,WAAW,QACpB,CAAC;AACF,MAAI,CAAC,IAAI,GAAI,QAAO;EACpB,MAAM,OAAQ,MAAM,IAAI,MAAM;AAC9B,MAAI,OAAO,MAAM,YAAY,YAAY,CAAC,KAAK,QAAQ,MAAM,CAAE,QAAO;AACtE,SAAO,KAAK;SACN;AACN,SAAO;WACC;AACR,eAAa,QAAQ;;;AAIzB,SAAS,YAAY,SAAiB,QAAsB;AAC1D,SAAQ,OAAO,MACb,yBAAyB,QAAQ,KAAK,OAAO,+EAC9C;;AAGH,eAAsB,gBACpB,gBACA,MACe;AACf,KAAI,CAAC,aAAa,CAAE;CAEpB,MAAM,WAAW,aAAa;CAC9B,MAAM,QAAQ,MAAM,UAAU,SAAS;AAEvC,KAAI,SAAS,KAAK,KAAK,GAAG,MAAM,YAAY,mBAAmB;AAC7D,MACE,MAAM,iBACN,gBAAgB,gBAAgB,MAAM,cAAc,CAEpD,aAAY,gBAAgB,MAAM,cAAc;AAElD;;CAIF,MAAM,SAAS,MAAM,mBADL,MAAM,WAAW,MACe;AAEhD,OAAM,WAAW,UAAU;EAAE,WAAW,KAAK,KAAK;EAAE,eAAe;EAAQ,CAAC;AAE5E,KAAI,UAAU,gBAAgB,gBAAgB,OAAO,CACnD,aAAY,gBAAgB,OAAO;;;;;;;AErHvC,MAAM,UAAU,IAAI,SAAS;AAE7B,QACG,KAAK,aAAa,CAClB,YAAY,yCAAyC,CACrD,QAAQC,QAAY,CACpB,WAAW,qBAAqB,CAAC,CACjC,WAAW,mBAAmB,CAAC,CAC/B,WAAW,sBAAsB,CAAC,CAClC,WAAW,yBAAyB,CAAC,CACrC,WAAW,oBAAoB,CAAC,CAChC,WAAW,qBAAqB,CAAC,CACjC,WAAW,qBAAqB,CAAC,CACjC,YACC,SACA;;;;8EAKD;AAEH,QAAQ,OAAO;AACV,gBAAgBA,QAAY"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kopai/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "CLI for querying OpenTelemetry data from Kopai - traces, logs, and metrics",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"opentelemetry",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"commander": "^14.0.3",
|
|
39
|
-
"@kopai/core": "0.
|
|
40
|
-
"@kopai/sdk": "0.
|
|
39
|
+
"@kopai/core": "0.9.0",
|
|
40
|
+
"@kopai/sdk": "0.7.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsdown": "^0.21.2",
|