dexto 1.8.5 → 1.8.6
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/dist/cli/commands/span/register.d.ts +6 -0
- package/dist/cli/commands/span/register.d.ts.map +1 -0
- package/dist/cli/commands/span/register.js +25 -0
- package/dist/cli/commands/trace/client.d.ts +98 -0
- package/dist/cli/commands/trace/client.d.ts.map +1 -0
- package/dist/cli/commands/trace/client.js +150 -0
- package/dist/cli/commands/trace/format.d.ts +5 -0
- package/dist/cli/commands/trace/format.d.ts.map +1 -0
- package/dist/cli/commands/trace/format.js +58 -0
- package/dist/cli/commands/trace/index.d.ts +21 -0
- package/dist/cli/commands/trace/index.d.ts.map +1 -0
- package/dist/cli/commands/trace/index.js +49 -0
- package/dist/cli/commands/trace/register.d.ts +6 -0
- package/dist/cli/commands/trace/register.d.ts.map +1 -0
- package/dist/cli/commands/trace/register.js +71 -0
- package/dist/index-main.js +4 -0
- package/package.json +13 -13
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/span/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,WAAW,0BAA0B;IACvC,OAAO,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,OAAO,EAAE,EAAE,0BAA0B,GAAG,IAAI,CAwBjF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
|
|
2
|
+
export function registerSpanCommand({ program }) {
|
|
3
|
+
const span = program.command('span').description('Inspect hosted run spans from Dexto Cloud');
|
|
4
|
+
span.command('list <runId>')
|
|
5
|
+
.description('List spans for a hosted run')
|
|
6
|
+
.option('--json', 'Print the raw span list response as JSON')
|
|
7
|
+
.option('--limit <count>', 'Maximum number of spans to return')
|
|
8
|
+
.option('--name <spanName>', 'Filter to an exact span name')
|
|
9
|
+
.option('--platform-url <url>', 'Use a custom Dexto platform URL')
|
|
10
|
+
.option('--sort <sort>', 'Sort by started_at or duration')
|
|
11
|
+
.option('--status <status>', 'Filter to a span status')
|
|
12
|
+
.action(withAnalytics('span:list', async (runId, options) => {
|
|
13
|
+
try {
|
|
14
|
+
const { handleSpanListCommand } = await import('../trace/index.js');
|
|
15
|
+
await handleSpanListCommand(runId, options);
|
|
16
|
+
safeExit('span:list', 0);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof ExitSignal)
|
|
20
|
+
throw err;
|
|
21
|
+
console.error(`❌ dexto span list command failed: ${err}`);
|
|
22
|
+
safeExit('span:list', 1, 'error');
|
|
23
|
+
}
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const RunTraceSpanSchema: z.ZodObject<{
|
|
3
|
+
attributes: z.ZodUnknown;
|
|
4
|
+
durationMs: z.ZodNullable<z.ZodNumber>;
|
|
5
|
+
endedAt: z.ZodNullable<z.ZodString>;
|
|
6
|
+
errorCode: z.ZodNullable<z.ZodString>;
|
|
7
|
+
errorMessage: z.ZodNullable<z.ZodString>;
|
|
8
|
+
id: z.ZodString;
|
|
9
|
+
name: z.ZodString;
|
|
10
|
+
parentSpanId: z.ZodNullable<z.ZodString>;
|
|
11
|
+
runAttemptId: z.ZodNullable<z.ZodString>;
|
|
12
|
+
runId: z.ZodString;
|
|
13
|
+
sessionId: z.ZodNullable<z.ZodString>;
|
|
14
|
+
spanId: z.ZodString;
|
|
15
|
+
startedAt: z.ZodString;
|
|
16
|
+
status: z.ZodEnum<{
|
|
17
|
+
failed: "failed";
|
|
18
|
+
completed: "completed";
|
|
19
|
+
cancelled: "cancelled";
|
|
20
|
+
running: "running";
|
|
21
|
+
}>;
|
|
22
|
+
traceId: z.ZodString;
|
|
23
|
+
}, z.core.$loose>;
|
|
24
|
+
declare const RunTraceSchema: z.ZodObject<{
|
|
25
|
+
events: z.ZodArray<z.ZodObject<{
|
|
26
|
+
attributes: z.ZodUnknown;
|
|
27
|
+
eventId: z.ZodString;
|
|
28
|
+
name: z.ZodString;
|
|
29
|
+
occurredAt: z.ZodString;
|
|
30
|
+
runId: z.ZodString;
|
|
31
|
+
runSpanId: z.ZodString;
|
|
32
|
+
}, z.core.$loose>>;
|
|
33
|
+
spans: z.ZodArray<z.ZodObject<{
|
|
34
|
+
attributes: z.ZodUnknown;
|
|
35
|
+
durationMs: z.ZodNullable<z.ZodNumber>;
|
|
36
|
+
endedAt: z.ZodNullable<z.ZodString>;
|
|
37
|
+
errorCode: z.ZodNullable<z.ZodString>;
|
|
38
|
+
errorMessage: z.ZodNullable<z.ZodString>;
|
|
39
|
+
id: z.ZodString;
|
|
40
|
+
name: z.ZodString;
|
|
41
|
+
parentSpanId: z.ZodNullable<z.ZodString>;
|
|
42
|
+
runAttemptId: z.ZodNullable<z.ZodString>;
|
|
43
|
+
runId: z.ZodString;
|
|
44
|
+
sessionId: z.ZodNullable<z.ZodString>;
|
|
45
|
+
spanId: z.ZodString;
|
|
46
|
+
startedAt: z.ZodString;
|
|
47
|
+
status: z.ZodEnum<{
|
|
48
|
+
failed: "failed";
|
|
49
|
+
completed: "completed";
|
|
50
|
+
cancelled: "cancelled";
|
|
51
|
+
running: "running";
|
|
52
|
+
}>;
|
|
53
|
+
traceId: z.ZodString;
|
|
54
|
+
}, z.core.$loose>>;
|
|
55
|
+
}, z.core.$loose>;
|
|
56
|
+
declare const RunTraceSummarySchema: z.ZodObject<{
|
|
57
|
+
durationMs: z.ZodNumber;
|
|
58
|
+
errorCount: z.ZodNumber;
|
|
59
|
+
eventCount: z.ZodNumber;
|
|
60
|
+
firstSpanStartedAt: z.ZodString;
|
|
61
|
+
lastSpanStartedAt: z.ZodString;
|
|
62
|
+
runId: z.ZodString;
|
|
63
|
+
sessionId: z.ZodString;
|
|
64
|
+
spanCount: z.ZodNumber;
|
|
65
|
+
spanNames: z.ZodArray<z.ZodString>;
|
|
66
|
+
status: z.ZodString;
|
|
67
|
+
}, z.core.$loose>;
|
|
68
|
+
export type RunTrace = z.output<typeof RunTraceSchema>;
|
|
69
|
+
export type RunTraceSpan = z.output<typeof RunTraceSpanSchema>;
|
|
70
|
+
export type RunTraceSummary = z.output<typeof RunTraceSummarySchema>;
|
|
71
|
+
export interface TraceClientOptions {
|
|
72
|
+
platformUrl?: string | undefined;
|
|
73
|
+
}
|
|
74
|
+
export interface RequestOptions {
|
|
75
|
+
signal?: AbortSignal | undefined;
|
|
76
|
+
}
|
|
77
|
+
export interface FetchRunTraceOptions extends RequestOptions {
|
|
78
|
+
}
|
|
79
|
+
export interface ListRunTracesOptions extends RequestOptions {
|
|
80
|
+
limit?: number | undefined;
|
|
81
|
+
period?: string | undefined;
|
|
82
|
+
sessionId?: string | undefined;
|
|
83
|
+
status?: string | undefined;
|
|
84
|
+
}
|
|
85
|
+
export interface ListRunSpansOptions extends RequestOptions {
|
|
86
|
+
limit?: number | undefined;
|
|
87
|
+
name?: string | undefined;
|
|
88
|
+
sort?: 'started_at' | 'duration' | undefined;
|
|
89
|
+
status?: string | undefined;
|
|
90
|
+
}
|
|
91
|
+
export declare function resolveTracePlatformUrl(platformUrl?: string): string;
|
|
92
|
+
export declare function createTraceClient(options?: TraceClientOptions): {
|
|
93
|
+
fetchRunTrace(runId: string, fetchOptions?: FetchRunTraceOptions): Promise<RunTrace>;
|
|
94
|
+
listRunSpans(runId: string, listOptions?: ListRunSpansOptions): Promise<RunTraceSpan[]>;
|
|
95
|
+
listRunTraces(listOptions?: ListRunTracesOptions): Promise<RunTraceSummary[]>;
|
|
96
|
+
};
|
|
97
|
+
export {};
|
|
98
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/trace/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAQxB,QAAA,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;iBAkBN,CAAC;AAanB,QAAA,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAKF,CAAC;AAQnB,QAAA,MAAM,qBAAqB;;;;;;;;;;;iBAaT,CAAC;AAcnB,MAAM,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,cAAc,CAAC,CAAC;AACvD,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAC/D,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAErE,MAAM,WAAW,kBAAkB;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,cAAc;IAC3B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,oBAAqB,SAAQ,cAAc;CAAG;AAE/D,MAAM,WAAW,oBAAqB,SAAQ,cAAc;IACxD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,mBAAoB,SAAQ,cAAc;IACvD,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,wBAAgB,uBAAuB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAOpE;AAiDD,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB;yBAsB/C,MAAM,iBACC,oBAAoB,GACnC,OAAO,CAAC,QAAQ,CAAC;wBAUT,MAAM,gBACA,mBAAmB,GACjC,OAAO,CAAC,YAAY,EAAE,CAAC;gCAYO,oBAAoB,GAAQ,OAAO,CAAC,eAAe,EAAE,CAAC;EAY9F"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { DEXTO_PLATFORM_URL } from '../../auth/constants.js';
|
|
3
|
+
import { getDextoApiKey } from '../../auth/service.js';
|
|
4
|
+
const TRACE_REQUEST_TIMEOUT_MS = 10_000;
|
|
5
|
+
const RunTraceSpanStatusSchema = z.enum(['running', 'completed', 'failed', 'cancelled']);
|
|
6
|
+
const RunTraceSpanSchema = z
|
|
7
|
+
.object({
|
|
8
|
+
attributes: z.unknown(),
|
|
9
|
+
durationMs: z.number().nullable(),
|
|
10
|
+
endedAt: z.string().nullable(),
|
|
11
|
+
errorCode: z.string().nullable(),
|
|
12
|
+
errorMessage: z.string().nullable(),
|
|
13
|
+
id: z.string(),
|
|
14
|
+
name: z.string(),
|
|
15
|
+
parentSpanId: z.string().nullable(),
|
|
16
|
+
runAttemptId: z.string().nullable(),
|
|
17
|
+
runId: z.string(),
|
|
18
|
+
sessionId: z.string().nullable(),
|
|
19
|
+
spanId: z.string(),
|
|
20
|
+
startedAt: z.string(),
|
|
21
|
+
status: RunTraceSpanStatusSchema,
|
|
22
|
+
traceId: z.string(),
|
|
23
|
+
})
|
|
24
|
+
.passthrough();
|
|
25
|
+
const RunTraceEventSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
attributes: z.unknown(),
|
|
28
|
+
eventId: z.string(),
|
|
29
|
+
name: z.string(),
|
|
30
|
+
occurredAt: z.string(),
|
|
31
|
+
runId: z.string(),
|
|
32
|
+
runSpanId: z.string(),
|
|
33
|
+
})
|
|
34
|
+
.passthrough();
|
|
35
|
+
const RunTraceSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
events: z.array(RunTraceEventSchema),
|
|
38
|
+
spans: z.array(RunTraceSpanSchema),
|
|
39
|
+
})
|
|
40
|
+
.passthrough();
|
|
41
|
+
const RunTraceResponseSchema = z
|
|
42
|
+
.object({
|
|
43
|
+
trace: RunTraceSchema,
|
|
44
|
+
})
|
|
45
|
+
.passthrough();
|
|
46
|
+
const RunTraceSummarySchema = z
|
|
47
|
+
.object({
|
|
48
|
+
durationMs: z.number(),
|
|
49
|
+
errorCount: z.number(),
|
|
50
|
+
eventCount: z.number(),
|
|
51
|
+
firstSpanStartedAt: z.string(),
|
|
52
|
+
lastSpanStartedAt: z.string(),
|
|
53
|
+
runId: z.string(),
|
|
54
|
+
sessionId: z.string(),
|
|
55
|
+
spanCount: z.number(),
|
|
56
|
+
spanNames: z.array(z.string()),
|
|
57
|
+
status: z.string(),
|
|
58
|
+
})
|
|
59
|
+
.passthrough();
|
|
60
|
+
const RunTraceListResponseSchema = z
|
|
61
|
+
.object({
|
|
62
|
+
traces: z.array(RunTraceSummarySchema),
|
|
63
|
+
})
|
|
64
|
+
.passthrough();
|
|
65
|
+
const RunSpansResponseSchema = z
|
|
66
|
+
.object({
|
|
67
|
+
spans: z.array(RunTraceSpanSchema),
|
|
68
|
+
})
|
|
69
|
+
.passthrough();
|
|
70
|
+
export function resolveTracePlatformUrl(platformUrl) {
|
|
71
|
+
const rawUrl = platformUrl?.trim() || DEXTO_PLATFORM_URL;
|
|
72
|
+
if (rawUrl.trim().length === 0) {
|
|
73
|
+
throw new Error('Dexto platform URL is empty.');
|
|
74
|
+
}
|
|
75
|
+
return rawUrl.replace(/\/+$/, '');
|
|
76
|
+
}
|
|
77
|
+
async function resolveTraceApiKey() {
|
|
78
|
+
const apiKey = await getDextoApiKey();
|
|
79
|
+
if (!apiKey?.trim()) {
|
|
80
|
+
throw new Error('Authentication required. Run `dexto login` before using `dexto trace`.');
|
|
81
|
+
}
|
|
82
|
+
return apiKey.trim();
|
|
83
|
+
}
|
|
84
|
+
async function parseJsonResponse(response) {
|
|
85
|
+
const contentType = response.headers.get('content-type') ?? '';
|
|
86
|
+
if (!contentType.toLowerCase().includes('application/json')) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return response.json().catch(() => null);
|
|
90
|
+
}
|
|
91
|
+
function formatHttpFailure(status, payload) {
|
|
92
|
+
if (payload && typeof payload === 'object' && 'error' in payload) {
|
|
93
|
+
return `${status} ${JSON.stringify(payload)}`;
|
|
94
|
+
}
|
|
95
|
+
return `${status}`;
|
|
96
|
+
}
|
|
97
|
+
function appendOptionalSearchParam(url, key, value) {
|
|
98
|
+
if (value === undefined) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
url.searchParams.set(key, String(value));
|
|
102
|
+
}
|
|
103
|
+
function createRequestSignal(signal) {
|
|
104
|
+
const timeoutSignal = AbortSignal.timeout(TRACE_REQUEST_TIMEOUT_MS);
|
|
105
|
+
if (!signal) {
|
|
106
|
+
return timeoutSignal;
|
|
107
|
+
}
|
|
108
|
+
return AbortSignal.any([signal, timeoutSignal]);
|
|
109
|
+
}
|
|
110
|
+
export function createTraceClient(options = {}) {
|
|
111
|
+
const platformBaseUrl = resolveTracePlatformUrl(options.platformUrl);
|
|
112
|
+
async function fetchJson(path, fetchOptions = {}) {
|
|
113
|
+
const response = await fetch(`${platformBaseUrl}${path}`, {
|
|
114
|
+
method: 'GET',
|
|
115
|
+
headers: {
|
|
116
|
+
Authorization: `Bearer ${await resolveTraceApiKey()}`,
|
|
117
|
+
},
|
|
118
|
+
signal: createRequestSignal(fetchOptions.signal),
|
|
119
|
+
});
|
|
120
|
+
const payload = await parseJsonResponse(response);
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
throw new Error(`Trace request failed: ${formatHttpFailure(response.status, payload)}`);
|
|
123
|
+
}
|
|
124
|
+
return payload;
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
async fetchRunTrace(runId, fetchOptions = {}) {
|
|
128
|
+
const payload = await fetchJson(`/api/runs/${encodeURIComponent(runId)}/trace`, fetchOptions);
|
|
129
|
+
return RunTraceResponseSchema.parse(payload).trace;
|
|
130
|
+
},
|
|
131
|
+
async listRunSpans(runId, listOptions = {}) {
|
|
132
|
+
const url = new URL(`${platformBaseUrl}/api/runs/${encodeURIComponent(runId)}/spans`);
|
|
133
|
+
appendOptionalSearchParam(url, 'limit', listOptions.limit);
|
|
134
|
+
appendOptionalSearchParam(url, 'name', listOptions.name);
|
|
135
|
+
appendOptionalSearchParam(url, 'sort', listOptions.sort);
|
|
136
|
+
appendOptionalSearchParam(url, 'status', listOptions.status);
|
|
137
|
+
const payload = await fetchJson(`${url.pathname}${url.search}`, listOptions);
|
|
138
|
+
return RunSpansResponseSchema.parse(payload).spans;
|
|
139
|
+
},
|
|
140
|
+
async listRunTraces(listOptions = {}) {
|
|
141
|
+
const url = new URL(`${platformBaseUrl}/api/runs/traces`);
|
|
142
|
+
appendOptionalSearchParam(url, 'limit', listOptions.limit);
|
|
143
|
+
appendOptionalSearchParam(url, 'period', listOptions.period);
|
|
144
|
+
appendOptionalSearchParam(url, 'sessionId', listOptions.sessionId);
|
|
145
|
+
appendOptionalSearchParam(url, 'status', listOptions.status);
|
|
146
|
+
const payload = await fetchJson(`${url.pathname}${url.search}`, listOptions);
|
|
147
|
+
return RunTraceListResponseSchema.parse(payload).traces;
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { RunTrace, RunTraceSpan, RunTraceSummary } from './client.js';
|
|
2
|
+
export declare function formatTraceSummary(runId: string, trace: RunTrace): string;
|
|
3
|
+
export declare function formatTraceList(traces: RunTraceSummary[]): string;
|
|
4
|
+
export declare function formatSpanList(runId: string, spans: RunTraceSpan[]): string;
|
|
5
|
+
//# sourceMappingURL=format.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/trace/format.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAc3E,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAsBzE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,CAkBjE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,GAAG,MAAM,CAoB3E"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
function formatDuration(span) {
|
|
2
|
+
return span.durationMs === null ? 'running' : `${span.durationMs}ms`;
|
|
3
|
+
}
|
|
4
|
+
function formatDurationMs(durationMs) {
|
|
5
|
+
return durationMs === null ? 'running' : `${durationMs}ms`;
|
|
6
|
+
}
|
|
7
|
+
function sortSpans(spans) {
|
|
8
|
+
return [...spans].sort((left, right) => left.startedAt.localeCompare(right.startedAt));
|
|
9
|
+
}
|
|
10
|
+
export function formatTraceSummary(runId, trace) {
|
|
11
|
+
const lines = [
|
|
12
|
+
`Run trace ${runId}`,
|
|
13
|
+
`Spans: ${trace.spans.length} Events: ${trace.events.length}`,
|
|
14
|
+
];
|
|
15
|
+
if (trace.spans.length === 0) {
|
|
16
|
+
lines.push('No spans found.');
|
|
17
|
+
return lines.join('\n');
|
|
18
|
+
}
|
|
19
|
+
lines.push('');
|
|
20
|
+
for (const span of sortSpans(trace.spans)) {
|
|
21
|
+
lines.push(`${span.startedAt} ${span.status.padEnd(9)} ${formatDuration(span).padStart(8)} ${span.name}`);
|
|
22
|
+
if (span.errorMessage) {
|
|
23
|
+
lines.push(` error: ${span.errorMessage}`);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
export function formatTraceList(traces) {
|
|
29
|
+
if (traces.length === 0) {
|
|
30
|
+
return 'No run traces found.';
|
|
31
|
+
}
|
|
32
|
+
const lines = ['Recent run traces', ''];
|
|
33
|
+
for (const trace of traces) {
|
|
34
|
+
const names = trace.spanNames.slice(0, 5).join(', ');
|
|
35
|
+
lines.push(`${trace.lastSpanStartedAt} ${trace.status.padEnd(16)} spans=${String(trace.spanCount).padStart(2)} errors=${trace.errorCount} duration=${formatDurationMs(trace.durationMs).padStart(8)} ${trace.runId}`);
|
|
36
|
+
lines.push(` session: ${trace.sessionId}`);
|
|
37
|
+
if (names.length > 0) {
|
|
38
|
+
lines.push(` spans: ${names}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return lines.join('\n');
|
|
42
|
+
}
|
|
43
|
+
export function formatSpanList(runId, spans) {
|
|
44
|
+
const lines = [`Spans for run ${runId}`, `Count: ${spans.length}`];
|
|
45
|
+
if (spans.length === 0) {
|
|
46
|
+
lines.push('No spans found.');
|
|
47
|
+
return lines.join('\n');
|
|
48
|
+
}
|
|
49
|
+
lines.push('');
|
|
50
|
+
for (const span of spans) {
|
|
51
|
+
lines.push(`${span.startedAt} ${span.status.padEnd(9)} ${formatDuration(span).padStart(8)} ${span.name}`);
|
|
52
|
+
lines.push(` span: ${span.spanId} trace: ${span.traceId}`);
|
|
53
|
+
if (span.errorMessage) {
|
|
54
|
+
lines.push(` error: ${span.errorMessage}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return lines.join('\n');
|
|
58
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface TraceCommandOptions {
|
|
2
|
+
json?: boolean | undefined;
|
|
3
|
+
platformUrl?: string | undefined;
|
|
4
|
+
}
|
|
5
|
+
export interface TraceListCommandOptions extends TraceCommandOptions {
|
|
6
|
+
limit?: string | number | undefined;
|
|
7
|
+
period?: string | undefined;
|
|
8
|
+
session?: string | undefined;
|
|
9
|
+
status?: string | undefined;
|
|
10
|
+
}
|
|
11
|
+
export interface SpanListCommandOptions extends TraceCommandOptions {
|
|
12
|
+
limit?: string | number | undefined;
|
|
13
|
+
name?: string | undefined;
|
|
14
|
+
sort?: 'started_at' | 'duration' | undefined;
|
|
15
|
+
status?: string | undefined;
|
|
16
|
+
}
|
|
17
|
+
export declare function handleTraceCommand(runId: string, options?: TraceCommandOptions): Promise<void>;
|
|
18
|
+
export declare function handleTraceViewCommand(runId: string, options?: TraceCommandOptions): Promise<void>;
|
|
19
|
+
export declare function handleTraceListCommand(options?: TraceListCommandOptions): Promise<void>;
|
|
20
|
+
export declare function handleSpanListCommand(runId: string, options?: SpanListCommandOptions): Promise<void>;
|
|
21
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/trace/index.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,mBAAmB;IAChC,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,uBAAwB,SAAQ,mBAAmB;IAChE,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACpC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAED,MAAM,WAAW,sBAAuB,SAAQ,mBAAmB;IAC/D,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,YAAY,GAAG,UAAU,GAAG,SAAS,CAAC;IAC7C,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC/B;AAeD,wBAAsB,kBAAkB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,wBAAsB,sBAAsB,CACxC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,mBAAwB,GAClC,OAAO,CAAC,IAAI,CAAC,CAWf;AAED,wBAAsB,sBAAsB,CAAC,OAAO,GAAE,uBAA4B,GAAG,OAAO,CAAC,IAAI,CAAC,CAcjG;AAED,wBAAsB,qBAAqB,CACvC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,sBAA2B,GACrC,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { createTraceClient } from './client.js';
|
|
2
|
+
import { formatSpanList, formatTraceList, formatTraceSummary } from './format.js';
|
|
3
|
+
function parsePositiveInteger(value, fallback) {
|
|
4
|
+
if (value === undefined) {
|
|
5
|
+
return fallback;
|
|
6
|
+
}
|
|
7
|
+
const parsed = typeof value === 'number' ? value : Number(value);
|
|
8
|
+
if (!Number.isInteger(parsed) || parsed < 1) {
|
|
9
|
+
throw new Error(`Expected a positive integer, received ${String(value)}.`);
|
|
10
|
+
}
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
export async function handleTraceCommand(runId, options = {}) {
|
|
14
|
+
await handleTraceViewCommand(runId, options);
|
|
15
|
+
}
|
|
16
|
+
export async function handleTraceViewCommand(runId, options = {}) {
|
|
17
|
+
const trace = await createTraceClient({ platformUrl: options.platformUrl }).fetchRunTrace(runId);
|
|
18
|
+
if (options.json) {
|
|
19
|
+
console.log(JSON.stringify({ trace }, null, 2));
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
console.log(formatTraceSummary(runId, trace));
|
|
23
|
+
}
|
|
24
|
+
export async function handleTraceListCommand(options = {}) {
|
|
25
|
+
const traces = await createTraceClient({ platformUrl: options.platformUrl }).listRunTraces({
|
|
26
|
+
limit: parsePositiveInteger(options.limit, 20),
|
|
27
|
+
...(options.period === undefined ? {} : { period: options.period }),
|
|
28
|
+
...(options.session === undefined ? {} : { sessionId: options.session }),
|
|
29
|
+
...(options.status === undefined ? {} : { status: options.status }),
|
|
30
|
+
});
|
|
31
|
+
if (options.json) {
|
|
32
|
+
console.log(JSON.stringify({ traces }, null, 2));
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
console.log(formatTraceList(traces));
|
|
36
|
+
}
|
|
37
|
+
export async function handleSpanListCommand(runId, options = {}) {
|
|
38
|
+
const spans = await createTraceClient({ platformUrl: options.platformUrl }).listRunSpans(runId, {
|
|
39
|
+
limit: parsePositiveInteger(options.limit, 100),
|
|
40
|
+
...(options.name === undefined ? {} : { name: options.name }),
|
|
41
|
+
...(options.sort === undefined ? {} : { sort: options.sort }),
|
|
42
|
+
...(options.status === undefined ? {} : { status: options.status }),
|
|
43
|
+
});
|
|
44
|
+
if (options.json) {
|
|
45
|
+
console.log(JSON.stringify({ spans }, null, 2));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log(formatSpanList(runId, spans));
|
|
49
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/trace/register.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGzC,MAAM,WAAW,2BAA2B;IACxC,OAAO,EAAE,OAAO,CAAC;CACpB;AAOD,wBAAgB,oBAAoB,CAAC,EAAE,OAAO,EAAE,EAAE,2BAA2B,GAAG,IAAI,CAuEnF"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { withAnalytics, safeExit, ExitSignal } from '../../../analytics/wrapper.js';
|
|
2
|
+
export function registerTraceCommand({ program }) {
|
|
3
|
+
const trace = program
|
|
4
|
+
.command('trace [runId]')
|
|
5
|
+
.description('Discover and fetch hosted run traces from Dexto Cloud')
|
|
6
|
+
.option('--json', 'Print the raw trace response as JSON')
|
|
7
|
+
.option('--platform-url <url>', 'Use a custom Dexto platform URL')
|
|
8
|
+
.action(withAnalytics('trace', async (runId, options) => {
|
|
9
|
+
try {
|
|
10
|
+
if (!runId) {
|
|
11
|
+
trace.help();
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
const { handleTraceCommand } = await import('./index.js');
|
|
15
|
+
await handleTraceCommand(runId, options);
|
|
16
|
+
safeExit('trace', 0);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
if (err instanceof ExitSignal)
|
|
20
|
+
throw err;
|
|
21
|
+
console.error(`❌ dexto trace command failed: ${err}`);
|
|
22
|
+
safeExit('trace', 1, 'error');
|
|
23
|
+
}
|
|
24
|
+
}));
|
|
25
|
+
trace
|
|
26
|
+
.command('list')
|
|
27
|
+
.description('List recent hosted run traces')
|
|
28
|
+
.option('--json', 'Print the raw trace list response as JSON')
|
|
29
|
+
.option('--limit <count>', 'Maximum number of traces to return')
|
|
30
|
+
.option('--period <period>', 'Filter to a recent period such as 15m, 3h, or 7d')
|
|
31
|
+
.option('--platform-url <url>', 'Use a custom Dexto platform URL')
|
|
32
|
+
.option('--session <sessionId>', 'Filter to a session id')
|
|
33
|
+
.option('--status <status>', 'Filter to a run status')
|
|
34
|
+
.action(withAnalytics('trace:list', async (options) => {
|
|
35
|
+
try {
|
|
36
|
+
const { handleTraceListCommand } = await import('./index.js');
|
|
37
|
+
await handleTraceListCommand({
|
|
38
|
+
...trace.opts(),
|
|
39
|
+
...options,
|
|
40
|
+
});
|
|
41
|
+
safeExit('trace:list', 0);
|
|
42
|
+
}
|
|
43
|
+
catch (err) {
|
|
44
|
+
if (err instanceof ExitSignal)
|
|
45
|
+
throw err;
|
|
46
|
+
console.error(`❌ dexto trace list command failed: ${err}`);
|
|
47
|
+
safeExit('trace:list', 1, 'error');
|
|
48
|
+
}
|
|
49
|
+
}));
|
|
50
|
+
trace
|
|
51
|
+
.command('view <runId>')
|
|
52
|
+
.description('Fetch one hosted run trace')
|
|
53
|
+
.option('--json', 'Print the raw trace response as JSON')
|
|
54
|
+
.option('--platform-url <url>', 'Use a custom Dexto platform URL')
|
|
55
|
+
.action(withAnalytics('trace:view', async (runId, options) => {
|
|
56
|
+
try {
|
|
57
|
+
const { handleTraceViewCommand } = await import('./index.js');
|
|
58
|
+
await handleTraceViewCommand(runId, {
|
|
59
|
+
...trace.opts(),
|
|
60
|
+
...options,
|
|
61
|
+
});
|
|
62
|
+
safeExit('trace:view', 0);
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
if (err instanceof ExitSignal)
|
|
66
|
+
throw err;
|
|
67
|
+
console.error(`❌ dexto trace view command failed: ${err}`);
|
|
68
|
+
safeExit('trace:view', 1, 'error');
|
|
69
|
+
}
|
|
70
|
+
}));
|
|
71
|
+
}
|
package/dist/index-main.js
CHANGED
|
@@ -60,6 +60,8 @@ import { registerImageCommand } from './cli/commands/image/register.js';
|
|
|
60
60
|
import { registerPluginCommand } from './cli/commands/plugin/register.js';
|
|
61
61
|
import { registerAgentsCommand } from './cli/commands/agents/register.js';
|
|
62
62
|
import { registerDeployCommand } from './cli/commands/deploy/register.js';
|
|
63
|
+
import { registerSpanCommand } from './cli/commands/span/register.js';
|
|
64
|
+
import { registerTraceCommand } from './cli/commands/trace/register.js';
|
|
63
65
|
import { registerInitCommand } from './cli/commands/init.js';
|
|
64
66
|
import { ensureImageImporterConfigured } from './cli/utils/image-importer.js';
|
|
65
67
|
const program = new Command();
|
|
@@ -143,6 +145,8 @@ program
|
|
|
143
145
|
}));
|
|
144
146
|
registerImageCommand({ program });
|
|
145
147
|
registerDeployCommand({ program });
|
|
148
|
+
registerSpanCommand({ program });
|
|
149
|
+
registerTraceCommand({ program });
|
|
146
150
|
registerInitCommand({ program });
|
|
147
151
|
// 4) `init-app` SUB-COMMAND
|
|
148
152
|
program
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dexto",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.6",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"dexto": "./dist/index.js"
|
|
@@ -34,18 +34,18 @@
|
|
|
34
34
|
"ws": "^8.18.1",
|
|
35
35
|
"yaml": "^2.8.3",
|
|
36
36
|
"zod": "^4.3.6",
|
|
37
|
-
"@dexto/agent-config": "1.8.
|
|
38
|
-
"@dexto/agent-management": "1.8.
|
|
39
|
-
"@dexto/analytics": "1.8.
|
|
40
|
-
"@dexto/client-sdk": "1.8.
|
|
41
|
-
"@dexto/core": "1.8.
|
|
42
|
-
"@dexto/image-local": "1.8.
|
|
43
|
-
"@dexto/image-logger-agent": "1.8.
|
|
44
|
-
"@dexto/llm": "1.8.
|
|
45
|
-
"@dexto/registry": "1.8.
|
|
46
|
-
"@dexto/server": "1.8.
|
|
47
|
-
"@dexto/storage": "1.8.
|
|
48
|
-
"@dexto/tui": "1.8.
|
|
37
|
+
"@dexto/agent-config": "1.8.6",
|
|
38
|
+
"@dexto/agent-management": "1.8.6",
|
|
39
|
+
"@dexto/analytics": "1.8.6",
|
|
40
|
+
"@dexto/client-sdk": "1.8.6",
|
|
41
|
+
"@dexto/core": "1.8.6",
|
|
42
|
+
"@dexto/image-local": "1.8.6",
|
|
43
|
+
"@dexto/image-logger-agent": "1.8.6",
|
|
44
|
+
"@dexto/llm": "1.8.6",
|
|
45
|
+
"@dexto/registry": "1.8.6",
|
|
46
|
+
"@dexto/server": "1.8.6",
|
|
47
|
+
"@dexto/storage": "1.8.6",
|
|
48
|
+
"@dexto/tui": "1.8.6"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@types/ws": "^8.5.11",
|