@runtypelabs/cli 2.19.4 → 2.20.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.
Files changed (2) hide show
  1. package/dist/index.js +187 -89
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -48784,6 +48784,65 @@ import chalk17 from "chalk";
48784
48784
  import React14 from "react";
48785
48785
  import { render as render14 } from "ink";
48786
48786
  import { useState as useState15, useEffect as useEffect16 } from "react";
48787
+
48788
+ // src/lib/terminal-image.ts
48789
+ var ESC = "\x1B";
48790
+ var BEL = "\x07";
48791
+ var ST = `${ESC}\\`;
48792
+ function detectImageProtocol(env = process.env, isTTY2 = process.stdout.isTTY === true) {
48793
+ if (!isTTY2) return null;
48794
+ if (env.TERM === "xterm-kitty" || env.KITTY_WINDOW_ID || env.TERM_PROGRAM === "ghostty") {
48795
+ return "kitty";
48796
+ }
48797
+ if (env.TERM_PROGRAM === "iTerm.app" || env.TERM_PROGRAM === "WezTerm" || env.LC_TERMINAL === "iTerm2") {
48798
+ return "iterm2";
48799
+ }
48800
+ return null;
48801
+ }
48802
+ function parseImageDataUri(value) {
48803
+ if (typeof value !== "string" || !value.startsWith("data:")) return null;
48804
+ const match = value.match(/^data:([^;,]+)(?:;[^,]*)?;base64,(.+)$/s);
48805
+ if (!match || !match[1] || !match[2]) return null;
48806
+ return { mimeType: match[1], base64: match[2] };
48807
+ }
48808
+ function base64DecodedByteLength(base643) {
48809
+ const len = base643.length;
48810
+ if (len === 0) return 0;
48811
+ let padding = 0;
48812
+ if (base643.endsWith("==")) padding = 2;
48813
+ else if (base643.endsWith("=")) padding = 1;
48814
+ return Math.floor(len * 3 / 4) - padding;
48815
+ }
48816
+ function kittyImageSequence(base643) {
48817
+ const CHUNK = 4096;
48818
+ if (base643.length <= CHUNK) {
48819
+ return `${ESC}_Ga=T,f=100,m=0;${base643}${ST}`;
48820
+ }
48821
+ let out = "";
48822
+ for (let i = 0; i < base643.length; i += CHUNK) {
48823
+ const piece = base643.slice(i, i + CHUNK);
48824
+ const more = i + CHUNK < base643.length ? 1 : 0;
48825
+ out += i === 0 ? `${ESC}_Ga=T,f=100,m=${more};${piece}${ST}` : `${ESC}_Gm=${more};${piece}${ST}`;
48826
+ }
48827
+ return out;
48828
+ }
48829
+ function encodeInlineImage(opts) {
48830
+ const { base64: base643, mimeType, protocol } = opts;
48831
+ if (!base643) return null;
48832
+ if (protocol === "iterm2") {
48833
+ const sizeBytes = base64DecodedByteLength(base643);
48834
+ return `${ESC}]1337;File=inline=1;size=${sizeBytes};width=auto;height=auto;preserveAspectRatio=1:${base643}${BEL}`;
48835
+ }
48836
+ if (mimeType !== "image/png") return null;
48837
+ return kittyImageSequence(base643);
48838
+ }
48839
+ function renderInlineImage(value, protocol) {
48840
+ const parsed = parseImageDataUri(value);
48841
+ if (!parsed) return null;
48842
+ return encodeInlineImage({ base64: parsed.base64, mimeType: parsed.mimeType, protocol });
48843
+ }
48844
+
48845
+ // src/commands/conversations.ts
48787
48846
  function renderMessageContent(content) {
48788
48847
  if (typeof content === "string") return content;
48789
48848
  if (!Array.isArray(content)) return content == null ? "" : String(content);
@@ -48805,6 +48864,64 @@ function renderMessageContent(content) {
48805
48864
  }
48806
48865
  }).filter((s) => s.length > 0).join(" ");
48807
48866
  }
48867
+ function writeMessageWithImages(msg, rolePrefix, protocol) {
48868
+ const out = process.stdout;
48869
+ const content = msg.content;
48870
+ if (!Array.isArray(content)) {
48871
+ out.write(`${rolePrefix}${renderMessageContent(content)}
48872
+ `);
48873
+ return;
48874
+ }
48875
+ const inline = [];
48876
+ const images = [];
48877
+ for (const part of content) {
48878
+ if (part && typeof part === "object" && part.type === "image") {
48879
+ const image = part.image;
48880
+ const seq = typeof image === "string" ? renderInlineImage(image, protocol) : null;
48881
+ if (seq) {
48882
+ images.push(seq);
48883
+ continue;
48884
+ }
48885
+ }
48886
+ inline.push(renderMessageContent([part]));
48887
+ }
48888
+ out.write(`${rolePrefix}${inline.filter((s) => s.length > 0).join(" ")}
48889
+ `);
48890
+ for (const seq of images) {
48891
+ out.write(`${seq}
48892
+ `);
48893
+ }
48894
+ }
48895
+ function printConversationDetail(data, imageProtocol) {
48896
+ printDetail("Conversation", [
48897
+ { label: "ID", value: data.id },
48898
+ { label: "Title", value: data.title },
48899
+ { label: "Model", value: data.modelId },
48900
+ { label: "System prompt", value: data.systemPrompt },
48901
+ { label: "Owner", value: data.ownerId },
48902
+ { label: "Source", value: data.source },
48903
+ { label: "Created", value: data.createdAt },
48904
+ { label: "Updated", value: data.updatedAt }
48905
+ ]);
48906
+ const messages = data.messages ?? [];
48907
+ console.log(chalk17.cyan(`
48908
+ Messages (${messages.length}):`));
48909
+ if (messages.length === 0) {
48910
+ console.log(chalk17.gray(" No messages"));
48911
+ return;
48912
+ }
48913
+ for (const msg of messages) {
48914
+ const roleColor = msg.role === "user" ? chalk17.blue : msg.role === "assistant" ? chalk17.green : chalk17.gray;
48915
+ if (imageProtocol) {
48916
+ writeMessageWithImages(msg, ` ${roleColor(msg.role)}: `, imageProtocol);
48917
+ } else {
48918
+ console.log(` ${roleColor(msg.role)}: ${renderMessageContent(msg.content)}`);
48919
+ }
48920
+ if (msg.createdAt) {
48921
+ console.log(chalk17.dim(` ${msg.createdAt}`));
48922
+ }
48923
+ }
48924
+ }
48808
48925
  var conversationsCommand = new Command15("conversations").description("Manage conversations");
48809
48926
  conversationsCommand.command("list").description("List your conversations").option("--limit <n>", "Limit results (defaults to the API page size)").option("--cursor <cursor>", "Pagination cursor for the next page").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (options) => {
48810
48927
  const apiKey = await ensureAuth();
@@ -48882,99 +48999,80 @@ conversationsCommand.command("list").description("List your conversations").opti
48882
48999
  const { waitUntilExit } = render14(React14.createElement(App));
48883
49000
  await waitUntilExit();
48884
49001
  });
48885
- conversationsCommand.command("get <id>").description("Get conversation details including its messages").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").action(async (id, options) => {
48886
- const apiKey = await ensureAuth();
48887
- if (!apiKey) return;
48888
- const client = createCliClient(apiKey);
48889
- if (!isTTY(options) || options.json) {
48890
- try {
48891
- const data = await client.get(`/conversations/${id}`);
48892
- if (options.json) {
48893
- printJson(data);
48894
- return;
48895
- }
48896
- printDetail("Conversation", [
48897
- { label: "ID", value: data.id },
48898
- { label: "Title", value: data.title },
48899
- { label: "Model", value: data.modelId },
48900
- { label: "System prompt", value: data.systemPrompt },
48901
- { label: "Owner", value: data.ownerId },
48902
- { label: "Source", value: data.source },
48903
- { label: "Created", value: data.createdAt },
48904
- { label: "Updated", value: data.updatedAt }
48905
- ]);
48906
- const messages = data.messages ?? [];
48907
- console.log(chalk17.cyan(`
48908
- Messages (${messages.length}):`));
48909
- if (messages.length === 0) {
48910
- console.log(chalk17.gray(" No messages"));
48911
- } else {
48912
- for (const msg of messages) {
48913
- const roleColor = msg.role === "user" ? chalk17.blue : msg.role === "assistant" ? chalk17.green : chalk17.gray;
48914
- console.log(` ${roleColor(msg.role)}: ${renderMessageContent(msg.content)}`);
48915
- if (msg.createdAt) {
48916
- console.log(chalk17.dim(` ${msg.createdAt}`));
48917
- }
49002
+ conversationsCommand.command("get <id>").description("Get conversation details including its messages").option("--json", "Output as JSON").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").option("--no-images", "Disable inline image rendering even in supported terminals").action(
49003
+ async (id, options) => {
49004
+ const apiKey = await ensureAuth();
49005
+ if (!apiKey) return;
49006
+ const client = createCliClient(apiKey);
49007
+ const interactive = isTTY(options) && !options.json;
49008
+ const imageProtocol = interactive && options.images !== false ? detectImageProtocol() : null;
49009
+ if (!interactive || imageProtocol) {
49010
+ try {
49011
+ const data = await client.get(`/conversations/${id}`);
49012
+ if (options.json) {
49013
+ printJson(data);
49014
+ return;
48918
49015
  }
49016
+ printConversationDetail(data, imageProtocol);
49017
+ } catch (error51) {
49018
+ const message = error51 instanceof Error ? error51.message : "Unknown error";
49019
+ console.error(chalk17.red(`Failed to fetch conversation: ${message}`));
49020
+ process.exit(1);
48919
49021
  }
48920
- } catch (error51) {
48921
- const message = error51 instanceof Error ? error51.message : "Unknown error";
48922
- console.error(chalk17.red(`Failed to fetch conversation: ${message}`));
48923
- process.exit(1);
49022
+ return;
48924
49023
  }
48925
- return;
49024
+ const App = () => {
49025
+ const [loading, setLoading] = useState15(true);
49026
+ const [success2, setSuccess] = useState15(null);
49027
+ const [error51, setError] = useState15(null);
49028
+ const [resultNode, setResultNode] = useState15(void 0);
49029
+ useEffect16(() => {
49030
+ const run2 = async () => {
49031
+ try {
49032
+ const data = await client.get(`/conversations/${id}`);
49033
+ const messages = data.messages ?? [];
49034
+ const messageSummary = messages.length === 0 ? "No messages" : messages.map((m2) => `${m2.role}: ${renderMessageContent(m2.content)}`).join("\n");
49035
+ setResultNode(
49036
+ React14.createElement(EntityCard, {
49037
+ fields: [
49038
+ { label: "ID", value: data.id, color: "green" },
49039
+ { label: "Title", value: data.title },
49040
+ { label: "Model", value: data.modelId },
49041
+ { label: "System prompt", value: data.systemPrompt },
49042
+ { label: "Owner", value: data.ownerId },
49043
+ { label: "Source", value: data.source, color: "gray" },
49044
+ { label: "Created", value: data.createdAt },
49045
+ { label: "Updated", value: data.updatedAt },
49046
+ {
49047
+ label: `Messages (${messages.length})`,
49048
+ value: messageSummary
49049
+ }
49050
+ ]
49051
+ })
49052
+ );
49053
+ setSuccess(true);
49054
+ setLoading(false);
49055
+ } catch (err) {
49056
+ setError(err instanceof Error ? err : new Error(String(err)));
49057
+ setSuccess(false);
49058
+ setLoading(false);
49059
+ }
49060
+ };
49061
+ run2();
49062
+ }, []);
49063
+ return React14.createElement(MutationResult, {
49064
+ loading,
49065
+ loadingLabel: "Fetching conversation...",
49066
+ success: success2,
49067
+ successMessage: "Conversation",
49068
+ error: error51,
49069
+ result: resultNode
49070
+ });
49071
+ };
49072
+ const { waitUntilExit } = render14(React14.createElement(App));
49073
+ await waitUntilExit();
48926
49074
  }
48927
- const App = () => {
48928
- const [loading, setLoading] = useState15(true);
48929
- const [success2, setSuccess] = useState15(null);
48930
- const [error51, setError] = useState15(null);
48931
- const [resultNode, setResultNode] = useState15(void 0);
48932
- useEffect16(() => {
48933
- const run2 = async () => {
48934
- try {
48935
- const data = await client.get(`/conversations/${id}`);
48936
- const messages = data.messages ?? [];
48937
- const messageSummary = messages.length === 0 ? "No messages" : messages.map((m2) => `${m2.role}: ${renderMessageContent(m2.content)}`).join("\n");
48938
- setResultNode(
48939
- React14.createElement(EntityCard, {
48940
- fields: [
48941
- { label: "ID", value: data.id, color: "green" },
48942
- { label: "Title", value: data.title },
48943
- { label: "Model", value: data.modelId },
48944
- { label: "System prompt", value: data.systemPrompt },
48945
- { label: "Owner", value: data.ownerId },
48946
- { label: "Source", value: data.source, color: "gray" },
48947
- { label: "Created", value: data.createdAt },
48948
- { label: "Updated", value: data.updatedAt },
48949
- {
48950
- label: `Messages (${messages.length})`,
48951
- value: messageSummary
48952
- }
48953
- ]
48954
- })
48955
- );
48956
- setSuccess(true);
48957
- setLoading(false);
48958
- } catch (err) {
48959
- setError(err instanceof Error ? err : new Error(String(err)));
48960
- setSuccess(false);
48961
- setLoading(false);
48962
- }
48963
- };
48964
- run2();
48965
- }, []);
48966
- return React14.createElement(MutationResult, {
48967
- loading,
48968
- loadingLabel: "Fetching conversation...",
48969
- success: success2,
48970
- successMessage: "Conversation",
48971
- error: error51,
48972
- result: resultNode
48973
- });
48974
- };
48975
- const { waitUntilExit } = render14(React14.createElement(App));
48976
- await waitUntilExit();
48977
- });
49075
+ );
48978
49076
  conversationsCommand.command("delete <id>").description("Delete a conversation").option("--tty", "Force TTY mode").option("--no-tty", "Force non-TTY mode").option("--yes", "Skip confirmation").action(async (id, options) => {
48979
49077
  const apiKey = await ensureAuth();
48980
49078
  if (!apiKey) return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@runtypelabs/cli",
3
- "version": "2.19.4",
3
+ "version": "2.20.0",
4
4
  "description": "Command-line interface for Runtype AI platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",