@arizeai/phoenix-cli 0.10.0 → 0.11.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 CHANGED
@@ -99,6 +99,49 @@ px trace abc123def456 --file trace.json
99
99
 
100
100
  ---
101
101
 
102
+ ### `px spans [file]`
103
+
104
+ Fetch spans for the configured project with filtering options. Output is JSON.
105
+
106
+ ```bash
107
+ px spans --limit 50 # stdout (pretty)
108
+ px spans --span-kind LLM --limit 20 # only LLM spans
109
+ px spans --status-code ERROR --format raw --no-progress # pipe-friendly error spans
110
+ px spans --name chat_completion --trace-id abc123 # filter by name and trace
111
+ px spans --parent-id null # root spans only
112
+ px spans spans.json --limit 100 --include-annotations # save to file with annotations
113
+ px spans --last-n-minutes 30 --span-kind TOOL RETRIEVER # multiple span kinds
114
+ ```
115
+
116
+ | Option | Description | Default |
117
+ | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------- | -------- |
118
+ | `[file]` | Save spans as JSON to file | stdout |
119
+ | `-n, --limit <number>` | Maximum number of spans (newest first) | `100` |
120
+ | `--last-n-minutes <number>` | Only spans from the last N minutes | — |
121
+ | `--since <timestamp>` | Spans since ISO timestamp | — |
122
+ | `--span-kind <kinds...>` | Filter by span kind (`LLM`, `CHAIN`, `TOOL`, `RETRIEVER`, `EMBEDDING`, `AGENT`, `RERANKER`, `GUARDRAIL`, `EVALUATOR`, `UNKNOWN`) | — |
123
+ | `--status-code <codes...>` | Filter by status code (`OK`, `ERROR`, `UNSET`) | — |
124
+ | `--name <names...>` | Filter by span name(s) | — |
125
+ | `--trace-id <ids...>` | Filter by trace ID(s) | — |
126
+ | `--parent-id <id>` | Filter by parent span ID (use `"null"` for root spans only) | — |
127
+ | `--include-annotations` | Include span annotations in the output | — |
128
+ | `--format <format>` | `pretty`, `json`, or `raw` | `pretty` |
129
+ | `--no-progress` | Suppress progress output | — |
130
+
131
+ ```bash
132
+ # Find all ERROR spans
133
+ px spans --status-code ERROR --format raw --no-progress | jq '.[] | {name, status_code}'
134
+
135
+ # Get LLM spans with token counts
136
+ px spans --span-kind LLM --format raw --no-progress | \
137
+ jq '.[] | {name, model: .attributes["llm.model_name"], tokens: (.attributes["llm.token_count.prompt"] + .attributes["llm.token_count.completion"])}'
138
+
139
+ # Root spans only, sorted by name
140
+ px spans --parent-id null --format raw --no-progress | jq 'sort_by(.name)'
141
+ ```
142
+
143
+ ---
144
+
102
145
  ### `px datasets`
103
146
 
104
147
  List all datasets.
@@ -176,6 +219,78 @@ px prompt my-evaluator --tag production --format json | jq '.template'
176
219
 
177
220
  ---
178
221
 
222
+ ### `px projects`
223
+
224
+ List all available Phoenix projects.
225
+
226
+ ```bash
227
+ px projects # pretty output
228
+ px projects --format raw --no-progress | jq '.[].name'
229
+ px projects --limit 5
230
+ ```
231
+
232
+ | Option | Description | Default |
233
+ | ------------------- | ----------------------------------- | -------- |
234
+ | `--limit <number>` | Maximum number of projects per page | — |
235
+ | `--format <format>` | `pretty`, `json`, or `raw` | `pretty` |
236
+ | `--no-progress` | Suppress progress output | — |
237
+
238
+ ---
239
+
240
+ ### `px sessions`
241
+
242
+ List sessions for a project.
243
+
244
+ ```bash
245
+ px sessions # latest 10 sessions
246
+ px sessions --limit 20 --order asc # oldest first
247
+ px sessions --format raw --no-progress | jq '.[].session_id'
248
+ ```
249
+
250
+ | Option | Description | Default |
251
+ | ---------------------- | --------------------------- | -------- |
252
+ | `-n, --limit <number>` | Maximum number of sessions | `10` |
253
+ | `--order <order>` | Sort order: `asc` or `desc` | `desc` |
254
+ | `--format <format>` | `pretty`, `json`, or `raw` | `pretty` |
255
+ | `--no-progress` | Suppress progress output | — |
256
+
257
+ ---
258
+
259
+ ### `px session <session-id>`
260
+
261
+ View a session's conversation flow.
262
+
263
+ ```bash
264
+ px session my-session-id
265
+ px session my-session-id --file session.json
266
+ px session my-session-id --include-annotations --format raw | jq '.traces'
267
+ ```
268
+
269
+ | Option | Description | Default |
270
+ | ----------------------- | -------------------------------------- | -------- |
271
+ | `--file <path>` | Save session to file instead of stdout | — |
272
+ | `--include-annotations` | Include session annotations | — |
273
+ | `--format <format>` | `pretty`, `json`, or `raw` | `pretty` |
274
+ | `--no-progress` | Suppress progress output | — |
275
+
276
+ ---
277
+
278
+ ### `px auth status`
279
+
280
+ Show current Phoenix authentication status, including the configured endpoint, whether you are authenticated or anonymous, and an obscured API key.
281
+
282
+ ```bash
283
+ px auth status
284
+ px auth status --endpoint http://localhost:6006
285
+ ```
286
+
287
+ | Option | Description | Default |
288
+ | ------------------ | -------------------- | ------- |
289
+ | `--endpoint <url>` | Phoenix API endpoint | — |
290
+ | `--api-key <key>` | Phoenix API key | — |
291
+
292
+ ---
293
+
179
294
  ### `px api graphql <query>`
180
295
 
181
296
  Make authenticated GraphQL queries against the Phoenix API. Output is `{"data": {...}}` JSON — pipe with `jq '.data.<field>'` to extract values. Only queries are permitted; mutations and subscriptions are rejected.
@@ -184,6 +299,22 @@ Make authenticated GraphQL queries against the Phoenix API. Output is `{"data":
184
299
  px api graphql '<query>' [--endpoint <url>] [--api-key <key>]
185
300
  ```
186
301
 
302
+ Preview the exact HTTP request as `curl` without executing it:
303
+
304
+ ```bash
305
+ px api graphql '{ projects { edges { node { name } } } }' --curl
306
+ px api graphql '{ projects { edges { node { name } } } }' --curl --show-token
307
+ ```
308
+
309
+ `--curl` prints the equivalent request to stdout and exits without making a network call. Authorization headers are masked by default, including values supplied through `PHOENIX_API_KEY` or `PHOENIX_CLIENT_HEADERS`. Use `--show-token` only when you explicitly need the raw credential in the generated command.
310
+
311
+ Current scope and behavior:
312
+
313
+ - `--curl` is currently implemented for `px api graphql` only.
314
+ - `--curl` prints the request without executing it.
315
+ - `--show-token` is only valid with `--curl`.
316
+ - Authorization masking and header normalization are designed to match the live request behavior used by `fetch`.
317
+
187
318
  Use introspection to discover what fields are available:
188
319
 
189
320
  ```bash
@@ -1,4 +1,5 @@
1
1
  import { Command } from "commander";
2
+ import type { PhoenixConfig } from "../config.js";
2
3
  /**
3
4
  * Returns true if the query string is a GraphQL mutation or subscription.
4
5
  * Strips # comments first to avoid false positives.
@@ -6,5 +7,19 @@ import { Command } from "commander";
6
7
  export declare function isNonQuery({ query }: {
7
8
  query: string;
8
9
  }): boolean;
10
+ export interface ApiGraphqlRequest {
11
+ url: string;
12
+ method: "POST";
13
+ headers: Record<string, string>;
14
+ body: string;
15
+ }
16
+ /**
17
+ * Builds the exact outbound GraphQL request used by both live execution and
18
+ * `--curl` preview mode so the two paths cannot drift apart.
19
+ */
20
+ export declare function buildGraphqlRequest({ query, config, }: {
21
+ query: string;
22
+ config: PhoenixConfig;
23
+ }): ApiGraphqlRequest;
9
24
  export declare function createApiCommand(): Command;
10
25
  //# sourceMappingURL=api.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAMpC;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGhE;AAkHD,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C"}
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAM/C;;;GAGG;AACH,wBAAgB,UAAU,CAAC,EAAE,KAAK,EAAE,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAGhE;AASD,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,EAClC,KAAK,EACL,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,aAAa,CAAC;CACvB,GAAG,iBAAiB,CAepB;AA6ID,wBAAgB,gBAAgB,IAAI,OAAO,CAK1C"}
@@ -1,5 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import { getConfigErrorMessage, resolveConfig } from "../config.js";
3
+ import { renderCurlCommand } from "../curl.js";
3
4
  import { ExitCode, getExitCodeForError } from "../exitCodes.js";
4
5
  import { writeError, writeOutput } from "../io.js";
5
6
  /**
@@ -10,8 +11,33 @@ export function isNonQuery({ query }) {
10
11
  const stripped = query.replace(/#[^\n]*/g, "");
11
12
  return /^\s*(mutation|subscription)[\s({]/m.test(stripped);
12
13
  }
14
+ /**
15
+ * Builds the exact outbound GraphQL request used by both live execution and
16
+ * `--curl` preview mode so the two paths cannot drift apart.
17
+ */
18
+ export function buildGraphqlRequest({ query, config, }) {
19
+ const headers = {
20
+ "Content-Type": "application/json",
21
+ ...(config.headers ?? {}),
22
+ };
23
+ if (config.apiKey) {
24
+ headers["Authorization"] = `Bearer ${config.apiKey}`;
25
+ }
26
+ return {
27
+ url: `${config.endpoint?.replace(/\/$/, "")}/graphql`,
28
+ method: "POST",
29
+ headers,
30
+ body: JSON.stringify({ query }),
31
+ };
32
+ }
13
33
  async function apiGraphqlHandler(query, options) {
14
34
  try {
35
+ if (options.showToken && !options.curl) {
36
+ writeError({
37
+ message: "Error: --show-token can only be used with --curl.",
38
+ });
39
+ process.exit(ExitCode.INVALID_ARGUMENT);
40
+ }
15
41
  // 1. Reject mutations and subscriptions
16
42
  if (isNonQuery({ query })) {
17
43
  writeError({
@@ -33,24 +59,31 @@ async function apiGraphqlHandler(query, options) {
33
59
  });
34
60
  process.exit(ExitCode.INVALID_ARGUMENT);
35
61
  }
36
- // 3. Build URL and auth headers
37
- const graphqlUrl = `${config.endpoint.replace(/\/$/, "")}/graphql`;
38
- const headers = {
39
- "Content-Type": "application/json",
40
- ...(config.headers ?? {}),
41
- };
42
- if (config.apiKey) {
43
- headers["Authorization"] = `Bearer ${config.apiKey}`;
62
+ const request = buildGraphqlRequest({
63
+ query,
64
+ config,
65
+ });
66
+ if (options.curl) {
67
+ writeOutput({
68
+ message: renderCurlCommand({
69
+ method: request.method,
70
+ url: request.url,
71
+ headers: request.headers,
72
+ body: request.body,
73
+ maskTokens: !options.showToken,
74
+ }),
75
+ });
76
+ return;
44
77
  }
45
78
  // 4. POST using Node 22 built-in fetch
46
- const response = await fetch(graphqlUrl, {
47
- method: "POST",
48
- headers,
49
- body: JSON.stringify({ query }),
79
+ const response = await fetch(request.url, {
80
+ method: request.method,
81
+ headers: request.headers,
82
+ body: request.body,
50
83
  });
51
84
  if (!response.ok) {
52
85
  writeError({
53
- message: `Error: HTTP ${response.status} ${response.statusText} from ${graphqlUrl}`,
86
+ message: `Error: HTTP ${response.status} ${response.statusText} from ${request.url}`,
54
87
  });
55
88
  if (response.status === 401 || response.status === 403) {
56
89
  process.exit(ExitCode.AUTH_REQUIRED);
@@ -92,10 +125,21 @@ function createApiGraphqlCommand() {
92
125
  "\n" +
93
126
  " # Pipe to jq to extract fields\n" +
94
127
  " px api graphql '{ projects { edges { node { name } } } }' | \\\n" +
95
- " jq '.data.projects.edges[].node.name'")
128
+ " jq '.data.projects.edges[].node.name'\n" +
129
+ "\n" +
130
+ " # Print the equivalent curl command without executing it\n" +
131
+ " px api graphql '{ projects { edges { node { name } } } }' --curl\n" +
132
+ "\n" +
133
+ " # Reveal the raw token in curl output\n" +
134
+ " px api graphql '{ projects { edges { node { name } } } }' --curl --show-token\n" +
135
+ "\n" +
136
+ " Curl mode prints the request without executing it.\n" +
137
+ " Auth tokens are masked by default. Use --show-token with --curl to reveal them.")
96
138
  .argument("<query>", "GraphQL query string")
97
139
  .option("--endpoint <url>", "Phoenix API endpoint (or set PHOENIX_HOST)")
98
140
  .option("--api-key <key>", "Phoenix API key (or set PHOENIX_API_KEY)")
141
+ .option("--curl", "Print the equivalent curl command instead of executing the request")
142
+ .option("--show-token", "Show the raw Authorization token in curl output (requires --curl)")
99
143
  .action(apiGraphqlHandler);
100
144
  }
101
145
  export function createApiCommand() {
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AACjE,OAAO,EAAE,QAAQ,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEhD;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,EAAE,KAAK,EAAqB;IACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC/C,OAAO,oCAAoC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC7D,CAAC;AAOD,KAAK,UAAU,iBAAiB,CAC9B,KAAa,EACb,OAA0B;IAE1B,IAAI,CAAC;QACH,wCAAwC;QACxC,IAAI,UAAU,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YAC1B,UAAU,CAAC;gBACT,OAAO,EACL,iFAAiF;aACpF,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAC1C,CAAC;QAED,0DAA0D;QAC1D,MAAM,MAAM,GAAG,aAAa,CAAC;YAC3B,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;SACnE,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACrB,UAAU,CAAC;gBACT,OAAO,EAAE,qBAAqB,CAAC;oBAC7B,MAAM,EAAE;wBACN,gGAAgG;qBACjG;iBACF,CAAC;aACH,CAAC,CAAC;YACH,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;QAC1C,CAAC;QAED,gCAAgC;QAChC,MAAM,UAAU,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,UAAU,CAAC;QACnE,MAAM,OAAO,GAA2B;YACtC,cAAc,EAAE,kBAAkB;YAClC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC;SAC1B,CAAC;QACF,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;YAClB,OAAO,CAAC,eAAe,CAAC,GAAG,UAAU,MAAM,CAAC,MAAM,EAAE,CAAC;QACvD,CAAC;QAED,uCAAuC;QACvC,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,UAAU,EAAE;YACvC,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,CAAC;SAChC,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,UAAU,CAAC;gBACT,OAAO,EAAE,eAAe,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,SAAS,UAAU,EAAE;aACpF,CAAC,CAAC;YACH,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACvD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;YACvC,CAAC;YACD,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;QAED,+BAA+B;QAC/B,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAGlC,CAAC;QAEF,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnE,UAAU,CAAC,EAAE,OAAO,EAAE,oBAAoB,IAAI,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;QAED,kEAAkE;QAClE,WAAW,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;QAExD,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC;YAC/D,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,UAAU,CAAC;YACT,OAAO,EAAE,UAAU,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE;SAC5E,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC,CAAC,CAAC;IAC3C,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB;IAC9B,OAAO,IAAI,OAAO,CAAC,SAAS,CAAC;SAC1B,WAAW,CACV,oDAAoD;QAClD,IAAI;QACJ,0DAA0D;QAC1D,IAAI;QACJ,eAAe;QACf,IAAI;QACJ,4BAA4B;QAC5B,iEAAiE;QACjE,IAAI;QACJ,uBAAuB;QACvB,2EAA2E;QAC3E,IAAI;QACJ,sCAAsC;QACtC,sEAAsE;QACtE,6CAA6C,CAChD;SACA,QAAQ,CAAC,SAAS,EAAE,sBAAsB,CAAC;SAC3C,MAAM,CAAC,kBAAkB,EAAE,4CAA4C,CAAC;SACxE,MAAM,CAAC,iBAAiB,EAAE,0CAA0C,CAAC;SACrE,MAAM,CAAC,iBAAiB,CAAC,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAC;IACnC,OAAO,CAAC,WAAW,CAAC,gDAAgD,CAAC,CAAC;IACtE,OAAO,CAAC,UAAU,CAAC,uBAAuB,EAAE,CAAC,CAAC;IAC9C,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/commands/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ export interface RenderCurlCommandOptions {
2
+ method: string;
3
+ url: string;
4
+ headers: Record<string, string>;
5
+ body?: string;
6
+ maskTokens: boolean;
7
+ }
8
+ /**
9
+ * Renders a pipe-friendly multiline curl command that matches the request
10
+ * Phoenix CLI would send over `fetch`.
11
+ */
12
+ export declare function renderCurlCommand({ method, url, headers, body, maskTokens, }: RenderCurlCommandOptions): string;
13
+ //# sourceMappingURL=curl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curl.d.ts","sourceRoot":"","sources":["../src/curl.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAqDD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,GAAG,EACH,OAAO,EACP,IAAI,EACJ,UAAU,GACX,EAAE,wBAAwB,GAAG,MAAM,CAkBnC"}
package/build/curl.js ADDED
@@ -0,0 +1,49 @@
1
+ import { obscureApiKey } from "./commands/auth.js";
2
+ function shellEscape(value) {
3
+ return "'" + value.replace(/'/g, "'\"'\"'") + "'";
4
+ }
5
+ /**
6
+ * Normalize headers through the platform `Headers` implementation so curl
7
+ * output mirrors how `fetch` combines duplicate logical headers such as
8
+ * `authorization` + `Authorization`.
9
+ */
10
+ function normalizeHeaders(headers) {
11
+ const normalizedHeaders = new Headers();
12
+ const headerNames = new Map();
13
+ for (const [key, value] of Object.entries(headers)) {
14
+ normalizedHeaders.append(key, value);
15
+ headerNames.set(key.toLowerCase(), headerNames.get(key.toLowerCase()) ?? key);
16
+ }
17
+ return Array.from(normalizedHeaders.entries()).map(([key, value]) => [
18
+ headerNames.get(key) ?? key,
19
+ value,
20
+ ]);
21
+ }
22
+ function maskHeaderValue({ key, value, maskTokens, }) {
23
+ if (!maskTokens || key.toLowerCase() !== "authorization") {
24
+ return value;
25
+ }
26
+ const match = value.match(/^(\S+)\s+(.+)$/);
27
+ if (match) {
28
+ const [, prefix, token] = match;
29
+ return `${prefix} ${obscureApiKey(token)}`;
30
+ }
31
+ return obscureApiKey(value);
32
+ }
33
+ /**
34
+ * Renders a pipe-friendly multiline curl command that matches the request
35
+ * Phoenix CLI would send over `fetch`.
36
+ */
37
+ export function renderCurlCommand({ method, url, headers, body, maskTokens, }) {
38
+ const lines = ["curl \\"];
39
+ lines.push(` -X ${method.toUpperCase()} \\`);
40
+ for (const [key, value] of normalizeHeaders(headers)) {
41
+ lines.push(` -H ${shellEscape(`${key}: ${maskHeaderValue({ key, value, maskTokens })}`)} \\`);
42
+ }
43
+ if (body !== undefined) {
44
+ lines.push(` --data-raw ${shellEscape(body)} \\`);
45
+ }
46
+ lines.push(` ${shellEscape(url)}`);
47
+ return lines.join("\n");
48
+ }
49
+ //# sourceMappingURL=curl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curl.js","sourceRoot":"","sources":["../src/curl.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAUhD,SAAS,WAAW,CAAC,KAAa;IAChC,OAAO,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,GAAG,GAAG,CAAC;AACpD,CAAC;AAED;;;;GAIG;AACH,SAAS,gBAAgB,CACvB,OAA+B;IAE/B,MAAM,iBAAiB,GAAG,IAAI,OAAO,EAAE,CAAC;IACxC,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACnD,iBAAiB,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QACrC,WAAW,CAAC,GAAG,CACb,GAAG,CAAC,WAAW,EAAE,EACjB,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,GAAG,CAC1C,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC;QACnE,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,GAAG;QAC3B,KAAK;KACN,CAAC,CAAC;AACL,CAAC;AAED,SAAS,eAAe,CAAC,EACvB,GAAG,EACH,KAAK,EACL,UAAU,GAKX;IACC,IAAI,CAAC,UAAU,IAAI,GAAG,CAAC,WAAW,EAAE,KAAK,eAAe,EAAE,CAAC;QACzD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;IAC5C,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,GAAG,KAAK,CAAC;QAChC,OAAO,GAAG,MAAM,IAAI,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;IAC7C,CAAC;IAED,OAAO,aAAa,CAAC,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,EAChC,MAAM,EACN,GAAG,EACH,OAAO,EACP,IAAI,EACJ,UAAU,GACe;IACzB,MAAM,KAAK,GAAG,CAAC,SAAS,CAAC,CAAC;IAE1B,KAAK,CAAC,IAAI,CAAC,QAAQ,MAAM,CAAC,WAAW,EAAE,KAAK,CAAC,CAAC;IAE9C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,gBAAgB,CAAC,OAAO,CAAC,EAAE,CAAC;QACrD,KAAK,CAAC,IAAI,CACR,QAAQ,WAAW,CAAC,GAAG,GAAG,KAAK,eAAe,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC,KAAK,CACnF,CAAC;IACJ,CAAC;IAED,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,KAAK,CAAC,IAAI,CAAC,gBAAgB,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEpC,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arizeai/phoenix-cli",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "A command-line interface for Phoenix",
5
5
  "keywords": [
6
6
  "arize",
@@ -32,8 +32,8 @@
32
32
  "dependencies": {
33
33
  "@arizeai/openinference-semantic-conventions": "^1.1.0",
34
34
  "commander": "^12.1.0",
35
- "@arizeai/phoenix-config": "0.1.1",
36
- "@arizeai/phoenix-client": "6.5.1"
35
+ "@arizeai/phoenix-client": "6.5.2",
36
+ "@arizeai/phoenix-config": "0.1.1"
37
37
  },
38
38
  "devDependencies": {
39
39
  "@types/node": "^18.19.0",