skydive-cli 0.2.0-beta.457 → 0.2.0-beta.482
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/js/{api-zUf_Vrzh.mjs → api-BHq-5eW_.mjs} +1 -1
- package/dist/js/bin.mjs +15 -15
- package/dist/js/{boot-D_H3xGxt.mjs → boot-B8ownO3n.mjs} +188 -27
- package/dist/js/client-CRAGDqp0.mjs +6 -0
- package/dist/js/{client-DuPxkSoH.mjs → client-t6GmE8TI.mjs} +1 -1
- package/dist/js/{print-DUsH9Dlh.mjs → print-Chg635Ye.mjs} +2 -2
- package/dist/js/{print-YqNIRwdf.mjs → print-XvAHDKqu.mjs} +1 -1
- package/dist/js/{print-share-B8sZ0w-M.mjs → print-share-DT89ADa6.mjs} +1 -1
- package/dist/js/{rest-Cz0VLhmi.mjs → rest-Ci_yRwoi.mjs} +1 -1
- package/dist/js/{rest-BBQrPIwq.mjs → rest-DZnAT7BG.mjs} +20 -7
- package/package.json +1 -1
- package/dist/js/client-A4m7lNDg.mjs +0 -6
package/dist/js/bin.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { A as getPromptHistoryPath, B as resolveSession, C as API_KEY_PREFIX, D as deleteConfig, E as DEFAULT_WEB_URL, F as getStoredApiKeyWorkspaceName, G as setLastSeenVersion, H as saveConfig, I as getUpdateCheckDisabled, L as resolveAppUrl, N as getShareMachineDefault, O as getConfigPath, P as getStoredApiKeyId, R as resolveConfig, S as API_KEY_FAMILY_PREFIX, U as saveSession, _ as getActiveWorkspaceId, b as setActiveWorkspace, g as ensureActiveOrganization, k as getLastSeenVersion, m as themes, r as brandHelpArt, v as getSessionIdentity, w as DEFAULT_API_URL, x as API_KEYS_URL, y as listWorkspaces, z as resolveManagementAuth } from "./brand-BVALAEf1.mjs";
|
|
3
3
|
import { n as printError, r as printTable, t as output } from "./output-B4cW10Ph.mjs";
|
|
4
|
-
import { n as createRestClient } from "./rest-
|
|
5
|
-
import { i as resolveAgent } from "./print-
|
|
6
|
-
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-
|
|
4
|
+
import { n as createRestClient } from "./rest-DZnAT7BG.mjs";
|
|
5
|
+
import { i as resolveAgent } from "./print-XvAHDKqu.mjs";
|
|
6
|
+
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-BHq-5eW_.mjs";
|
|
7
7
|
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
9
9
|
import yargs from "yargs";
|
|
@@ -20,7 +20,7 @@ import semver from "semver";
|
|
|
20
20
|
|
|
21
21
|
//#region package.json
|
|
22
22
|
var name = "skydive-cli";
|
|
23
|
-
var version = "0.2.0-beta.
|
|
23
|
+
var version = "0.2.0-beta.482";
|
|
24
24
|
|
|
25
25
|
//#endregion
|
|
26
26
|
//#region src/types.ts
|
|
@@ -1200,7 +1200,7 @@ const importCommand = {
|
|
|
1200
1200
|
process.exit(1);
|
|
1201
1201
|
}
|
|
1202
1202
|
}
|
|
1203
|
-
const { runChat } = await import("./boot-
|
|
1203
|
+
const { runChat } = await import("./boot-B8ownO3n.mjs");
|
|
1204
1204
|
await runChat({
|
|
1205
1205
|
appUrl,
|
|
1206
1206
|
sessionToken: session.value.sessionToken,
|
|
@@ -1226,7 +1226,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1226
1226
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login --web\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1227
1227
|
process.exit(1);
|
|
1228
1228
|
}
|
|
1229
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1229
|
+
const { connectMachineShare } = await import("./print-share-DT89ADa6.mjs");
|
|
1230
1230
|
const machineShare = await connectMachineShare({
|
|
1231
1231
|
appUrl,
|
|
1232
1232
|
sessionToken: session.value.sessionToken,
|
|
@@ -1234,7 +1234,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1234
1234
|
});
|
|
1235
1235
|
const extra = (argv.print ?? "").trim();
|
|
1236
1236
|
const prompt = buildImportSeedPrompt(process.cwd()) + (extra ? `\n\nAdditional instructions: ${extra}` : "");
|
|
1237
|
-
const { runPrint } = await import("./print-
|
|
1237
|
+
const { runPrint } = await import("./print-Chg635Ye.mjs");
|
|
1238
1238
|
try {
|
|
1239
1239
|
const result = await runPrint({
|
|
1240
1240
|
appUrl,
|
|
@@ -1511,7 +1511,7 @@ const chatCommand = {
|
|
|
1511
1511
|
printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
|
|
1512
1512
|
process.exit(1);
|
|
1513
1513
|
}
|
|
1514
|
-
const { runChat } = await import("./boot-
|
|
1514
|
+
const { runChat } = await import("./boot-B8ownO3n.mjs");
|
|
1515
1515
|
await runChat({
|
|
1516
1516
|
appUrl,
|
|
1517
1517
|
sessionToken: session.value.sessionToken,
|
|
@@ -1539,7 +1539,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1539
1539
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1540
1540
|
process.exit(1);
|
|
1541
1541
|
}
|
|
1542
|
-
const { runPrint, readStdin } = await import("./print-
|
|
1542
|
+
const { runPrint, readStdin } = await import("./print-Chg635Ye.mjs");
|
|
1543
1543
|
let prompt = (argv.print ?? "").trim();
|
|
1544
1544
|
if (!prompt) {
|
|
1545
1545
|
if (process.stdin.isTTY) {
|
|
@@ -1554,7 +1554,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1554
1554
|
}
|
|
1555
1555
|
let machineShare = null;
|
|
1556
1556
|
if (resolveShareMachine(argv)) {
|
|
1557
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1557
|
+
const { connectMachineShare } = await import("./print-share-DT89ADa6.mjs");
|
|
1558
1558
|
machineShare = await connectMachineShare({
|
|
1559
1559
|
appUrl,
|
|
1560
1560
|
sessionToken: session.value.sessionToken,
|
|
@@ -1613,7 +1613,7 @@ const getCommand = {
|
|
|
1613
1613
|
printError(`${session.error.message} Run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1614
1614
|
process.exit(1);
|
|
1615
1615
|
}
|
|
1616
|
-
const { messageGet } = await import("./print-
|
|
1616
|
+
const { messageGet } = await import("./print-Chg635Ye.mjs");
|
|
1617
1617
|
try {
|
|
1618
1618
|
const result = await messageGet({
|
|
1619
1619
|
appUrl,
|
|
@@ -1810,7 +1810,7 @@ const switchCommand = {
|
|
|
1810
1810
|
printError("The workspace picker needs the Bun runtime and it could not be set up automatically. Pass a workspace slug instead, or install Bun and retry.");
|
|
1811
1811
|
process.exit(1);
|
|
1812
1812
|
}
|
|
1813
|
-
const { runWorkspacePicker } = await import("./boot-
|
|
1813
|
+
const { runWorkspacePicker } = await import("./boot-B8ownO3n.mjs");
|
|
1814
1814
|
await runWorkspacePicker(session);
|
|
1815
1815
|
return;
|
|
1816
1816
|
}
|
|
@@ -1888,7 +1888,7 @@ const openCommand = {
|
|
|
1888
1888
|
const agent = argv.agent ? resolveAgent((await fetchPortalDevices(session)).agents, argv.agent) : null;
|
|
1889
1889
|
const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
|
|
1890
1890
|
const { machineName } = machineIdentity();
|
|
1891
|
-
const { PortalClient } = await import("./client-
|
|
1891
|
+
const { PortalClient } = await import("./client-CRAGDqp0.mjs");
|
|
1892
1892
|
let lastLine = "";
|
|
1893
1893
|
let signalConnected;
|
|
1894
1894
|
const connected = new Promise((resolve) => {
|
|
@@ -2060,8 +2060,8 @@ const sandboxCommand = {
|
|
|
2060
2060
|
}).example("skydive sandbox --agent grace", "Live terminal (Ctrl-] detaches)").example("skydive sandbox --agent grace -- tail -n 50 /tmp/harness.log", "One-shot command (use `--` so its flags reach the sandbox)").example("skydive sandbox --agent grace -- sh -c 'ls /tmp | wc -l'", "Shell features go through an explicit `sh -c`"),
|
|
2061
2061
|
handler: async (argv) => {
|
|
2062
2062
|
const session = requireSession(argv);
|
|
2063
|
-
const { createRestClient } = await import("./rest-
|
|
2064
|
-
const { resolveAgent } = await import("./print-
|
|
2063
|
+
const { createRestClient } = await import("./rest-Ci_yRwoi.mjs");
|
|
2064
|
+
const { resolveAgent } = await import("./print-Chg635Ye.mjs");
|
|
2065
2065
|
const client = createRestClient({
|
|
2066
2066
|
appUrl: session.appUrl,
|
|
2067
2067
|
sessionToken: session.sessionToken
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { M as getSavedTheme, O as getConfigPath, T as DEFAULT_APP_URL, V as resolveWebUrl, W as saveTheme, _ as getActiveWorkspaceId, a as applyTheme, b as setActiveWorkspace, c as noColorRequested, d as themeMode, f as themeModeFromColorFgBg, h as themesForMode, i as DEFAULT_THEME_ID, j as getReviewStateDir, l as theme, n as WORDMARK, o as findTheme, p as themeVersion, s as monoTheme, t as MARK_CELLS, u as themeForMode, w as DEFAULT_API_URL, y as listWorkspaces } from "./brand-BVALAEf1.mjs";
|
|
3
|
-
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-
|
|
3
|
+
import { n as createRestClient, r as errorDetail, t as HttpError } from "./rest-DZnAT7BG.mjs";
|
|
4
4
|
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
5
|
-
import { c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, m as specKeyFor, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-
|
|
6
|
-
import "./api-
|
|
5
|
+
import { c as cardActionErrorMessage, d as reconcileMaskedInput, f as resolveConnectUrl, i as resolveAgent, l as parseExternalOauthConnectParams, m as specKeyFor, p as parseConnectCard, s as MASK_CHAR, u as parseOauthConnectParams } from "./print-XvAHDKqu.mjs";
|
|
6
|
+
import "./api-BHq-5eW_.mjs";
|
|
7
7
|
import { t as SandboxStream } from "./client-CpEvH2Pq.mjs";
|
|
8
|
-
import { t as PortalClient } from "./client-
|
|
8
|
+
import { t as PortalClient } from "./client-t6GmE8TI.mjs";
|
|
9
9
|
import { t as runRawPtyPassthrough } from "./raw-pty-GAvxm2ol.mjs";
|
|
10
10
|
import * as os$1 from "node:os";
|
|
11
11
|
import { homedir, platform, release, tmpdir } from "node:os";
|
|
@@ -183,8 +183,8 @@ async function resolveInitialScreen({ rest, agentSelector, conversationId, newCo
|
|
|
183
183
|
createdAt: conversation.createdAt,
|
|
184
184
|
updatedAt: conversation.updatedAt,
|
|
185
185
|
preview: null,
|
|
186
|
-
channel:
|
|
187
|
-
channelLabel:
|
|
186
|
+
channel: conversation.channel,
|
|
187
|
+
channelLabel: conversation.channelLabel,
|
|
188
188
|
agent: {
|
|
189
189
|
id: agent.id,
|
|
190
190
|
name: agent.name,
|
|
@@ -1605,27 +1605,45 @@ function singleLine(text) {
|
|
|
1605
1605
|
return out;
|
|
1606
1606
|
}
|
|
1607
1607
|
/**
|
|
1608
|
-
* Fit a row's title
|
|
1609
|
-
*
|
|
1610
|
-
*
|
|
1608
|
+
* Fit a row's title, an optional mid-row `tag` and a trailing detail into
|
|
1609
|
+
* `width` columns, each rendered separated by one space. The title identifies
|
|
1610
|
+
* the row so it gets the space first; the tag comes next because it carries
|
|
1611
|
+
* information the detail does not; the detail takes what is left and is
|
|
1612
|
+
* dropped when nothing is.
|
|
1611
1613
|
*/
|
|
1612
|
-
function fitRowText(title, detail, width) {
|
|
1614
|
+
function fitRowText(title, detail, width, tag = "") {
|
|
1613
1615
|
if (width <= 0) return {
|
|
1614
1616
|
title: "",
|
|
1615
|
-
detail: ""
|
|
1617
|
+
detail: "",
|
|
1618
|
+
tag: ""
|
|
1616
1619
|
};
|
|
1617
|
-
|
|
1620
|
+
const segment = (text) => text ? text.length + 1 : 0;
|
|
1621
|
+
if (title.length + segment(tag) + segment(detail) <= width) return {
|
|
1618
1622
|
title,
|
|
1619
|
-
detail
|
|
1623
|
+
detail,
|
|
1624
|
+
tag
|
|
1620
1625
|
};
|
|
1621
1626
|
const room = width - title.length - 1;
|
|
1622
1627
|
if (room < 2) return {
|
|
1623
1628
|
title: truncate(title, width),
|
|
1624
|
-
detail: ""
|
|
1629
|
+
detail: "",
|
|
1630
|
+
tag: ""
|
|
1631
|
+
};
|
|
1632
|
+
if (title.length + segment(tag) > width) return {
|
|
1633
|
+
title,
|
|
1634
|
+
detail: "",
|
|
1635
|
+
tag: truncate(tag, room)
|
|
1636
|
+
};
|
|
1637
|
+
const detailRoom = room - segment(tag);
|
|
1638
|
+
if (detailRoom < 2) return {
|
|
1639
|
+
title,
|
|
1640
|
+
detail: "",
|
|
1641
|
+
tag
|
|
1625
1642
|
};
|
|
1626
1643
|
return {
|
|
1627
1644
|
title,
|
|
1628
|
-
detail: truncate(detail,
|
|
1645
|
+
detail: truncate(detail, detailRoom),
|
|
1646
|
+
tag
|
|
1629
1647
|
};
|
|
1630
1648
|
}
|
|
1631
1649
|
/**
|
|
@@ -1926,7 +1944,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1926
1944
|
children: [marker, truncate("+ new conversation", rowWidth)]
|
|
1927
1945
|
}, "new");
|
|
1928
1946
|
const archived = isArchived(row.hit.item);
|
|
1929
|
-
const { title, detail } = fitRowText(singleLine(row.hit.item.title ?? "(untitled)"), `${archived ? "archived · " : ""}${previewLine(row.hit.item)}`, rowWidth);
|
|
1947
|
+
const { title, detail, tag } = fitRowText(singleLine(row.hit.item.title ?? "(untitled)"), `${archived ? "archived · " : ""}${previewLine(row.hit.item)}`, rowWidth, coAgentsTag(row.hit.item, agent.id));
|
|
1930
1948
|
return /* @__PURE__ */ jsxs("text", {
|
|
1931
1949
|
fg: archived && !selected ? theme.dim : fg,
|
|
1932
1950
|
children: [
|
|
@@ -1935,6 +1953,10 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1935
1953
|
text: title,
|
|
1936
1954
|
indexes: row.hit.item.title ? row.hit.highlights[0] : null
|
|
1937
1955
|
}),
|
|
1956
|
+
tag ? /* @__PURE__ */ jsxs("span", {
|
|
1957
|
+
fg: theme.muted,
|
|
1958
|
+
children: [" ", tag]
|
|
1959
|
+
}) : null,
|
|
1938
1960
|
detail ? /* @__PURE__ */ jsxs("span", {
|
|
1939
1961
|
fg: theme.dim,
|
|
1940
1962
|
children: [" ", detail]
|
|
@@ -1946,7 +1968,27 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1946
1968
|
]
|
|
1947
1969
|
});
|
|
1948
1970
|
}
|
|
1949
|
-
|
|
1971
|
+
/**
|
|
1972
|
+
* Tags a row with the thread's other agents (`+Grace, Ada`). The picker is
|
|
1973
|
+
* entered per agent, so that agent stays implicit and only its co-participants
|
|
1974
|
+
* are named — this tag is the only thing in the list distinguishing a
|
|
1975
|
+
* multi-agent thread from a solo one. Empty for a solo thread.
|
|
1976
|
+
*
|
|
1977
|
+
* A string rather than a component because the row's one-line budget has to
|
|
1978
|
+
* account for it (see list-line.ts).
|
|
1979
|
+
*/
|
|
1980
|
+
function coAgentsTag(conv, viewerAgentId) {
|
|
1981
|
+
const names = conversationAgents(conv).filter((a) => a.id !== viewerAgentId).map((a) => a.name);
|
|
1982
|
+
return names.length > 0 ? `+${names.join(", ")}` : "";
|
|
1983
|
+
}
|
|
1984
|
+
function conversationAgents(c) {
|
|
1985
|
+
return c.agents && c.agents.length > 0 ? c.agents : [c.agent];
|
|
1986
|
+
}
|
|
1987
|
+
const conversationKeys = [
|
|
1988
|
+
(c) => singleLine(c.title ?? ""),
|
|
1989
|
+
(c) => c.preview ?? "",
|
|
1990
|
+
(c) => conversationAgents(c).map((a) => a.name).join(" ")
|
|
1991
|
+
];
|
|
1950
1992
|
function previewLine(c) {
|
|
1951
1993
|
const when = relativeTime(c.updatedAt);
|
|
1952
1994
|
const prefix = c.preview ? c.preview.replace(/\s+/g, " ").trim() : "";
|
|
@@ -4053,10 +4095,13 @@ function TodoCardView({ todos, isActive }) {
|
|
|
4053
4095
|
//#endregion
|
|
4054
4096
|
//#region src/chat/tui/chat/footer-hints.ts
|
|
4055
4097
|
/** Build the chat footer copy independently of its colors and layout. */
|
|
4056
|
-
function formatChatFooterStatus({ runKind, ctrlCArmed, isShared, hasPendingSteer, hasActionableCard }) {
|
|
4098
|
+
function formatChatFooterStatus({ runKind, ctrlCArmed, isShared, hasPendingSteer, hasActionableCard, nonWebChannel }) {
|
|
4057
4099
|
const connectHint = hasActionableCard ? "ctrl+r connect · " : "";
|
|
4058
4100
|
switch (runKind) {
|
|
4059
|
-
case "idle":
|
|
4101
|
+
case "idle":
|
|
4102
|
+
if (ctrlCArmed) return "press ctrl+c again to quit";
|
|
4103
|
+
if (nonWebChannel) return `esc back · ctrl+c quit · ctrl+t ${isShared ? "revoke access" : "local access"} · ? keybinds`;
|
|
4104
|
+
return `${connectHint}↵ send · / commands · esc back · ctrl+c quit · ctrl+t ${isShared ? "revoke access" : "local access"} · ? keybinds`;
|
|
4060
4105
|
case "sending": return "sending…";
|
|
4061
4106
|
case "streaming": return hasPendingSteer ? `${connectHint}↵ steer · esc cancel steer · ctrl+c cancel run` : `${connectHint}↵ steer · esc leave (keeps running) · ctrl+c cancel`;
|
|
4062
4107
|
}
|
|
@@ -4392,6 +4437,10 @@ const keybindGroups = [
|
|
|
4392
4437
|
keys: "ctrl+l",
|
|
4393
4438
|
action: "open this conversation in the browser"
|
|
4394
4439
|
},
|
|
4440
|
+
{
|
|
4441
|
+
keys: "ctrl+f",
|
|
4442
|
+
action: "fork a channel conversation into a chat you can continue here"
|
|
4443
|
+
},
|
|
4395
4444
|
{
|
|
4396
4445
|
keys: "ctrl+r",
|
|
4397
4446
|
action: "run the newest connect card (auth cards)"
|
|
@@ -7901,6 +7950,47 @@ async function runPtySession(opts) {
|
|
|
7901
7950
|
}
|
|
7902
7951
|
}
|
|
7903
7952
|
|
|
7953
|
+
//#endregion
|
|
7954
|
+
//#region src/chat/tui/screens/conversation-channel.ts
|
|
7955
|
+
function isNewConversation(c) {
|
|
7956
|
+
return "kind" in c && c.kind === "new";
|
|
7957
|
+
}
|
|
7958
|
+
/**
|
|
7959
|
+
* The channel a conversation belongs to when it isn't the web channel, else
|
|
7960
|
+
* null. A brand-new conversation is always web, and the list route reports the
|
|
7961
|
+
* web channel as either `'web'` or (legacy) null — both mean "post from here".
|
|
7962
|
+
* Anything else (slack, email, imessage, webhook, cron) is owned by that
|
|
7963
|
+
* channel: the message has to go through it, so the TUI can't send here.
|
|
7964
|
+
* Mirrors the web app's `channel !== null && channel !== 'web'` gate.
|
|
7965
|
+
*/
|
|
7966
|
+
function nonWebChannelLabel(c) {
|
|
7967
|
+
if (isNewConversation(c)) return null;
|
|
7968
|
+
if (c.channel === null || c.channel === "web") return null;
|
|
7969
|
+
return c.channelLabel ?? c.channel;
|
|
7970
|
+
}
|
|
7971
|
+
/**
|
|
7972
|
+
* The list-row shape for a conversation the TUI just forked, so the chat
|
|
7973
|
+
* screen can reopen on the copy without waiting for a list refetch. A fork
|
|
7974
|
+
* carries none of the source's channel binding — that's what makes it
|
|
7975
|
+
* sendable from here — so it is always a web conversation.
|
|
7976
|
+
*/
|
|
7977
|
+
function forkedConversationRef({ agent, forked }) {
|
|
7978
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
7979
|
+
return {
|
|
7980
|
+
id: forked.id,
|
|
7981
|
+
title: forked.title,
|
|
7982
|
+
createdAt: now,
|
|
7983
|
+
updatedAt: now,
|
|
7984
|
+
preview: null,
|
|
7985
|
+
channel: "web",
|
|
7986
|
+
channelLabel: null,
|
|
7987
|
+
agent: {
|
|
7988
|
+
id: agent.id,
|
|
7989
|
+
name: agent.name
|
|
7990
|
+
}
|
|
7991
|
+
};
|
|
7992
|
+
}
|
|
7993
|
+
|
|
7904
7994
|
//#endregion
|
|
7905
7995
|
//#region src/chat/tui/screens/chat.tsx
|
|
7906
7996
|
/**
|
|
@@ -7937,9 +8027,6 @@ const pageScrollFraction = .75;
|
|
|
7937
8027
|
/** Cap composer growth; past this the textarea scrolls its content instead. */
|
|
7938
8028
|
const maxComposerRows = 8;
|
|
7939
8029
|
const maxAttachments = 10;
|
|
7940
|
-
function isNewConversation(c) {
|
|
7941
|
-
return "kind" in c && c.kind === "new";
|
|
7942
|
-
}
|
|
7943
8030
|
/**
|
|
7944
8031
|
* A server timestamp as local epoch ms, or null when it is missing or
|
|
7945
8032
|
* unparseable so the caller can fall back to its own clock.
|
|
@@ -7992,6 +8079,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
7992
8079
|
const isShared = portal.status !== "off";
|
|
7993
8080
|
const initialConversationId = isNewConversation(conversation) ? null : conversation.id;
|
|
7994
8081
|
const agentHost = useAgentHost();
|
|
8082
|
+
const nonWebChannel = nonWebChannelLabel(conversation);
|
|
7995
8083
|
const [conversationId, setConversationId] = useState(initialConversationId);
|
|
7996
8084
|
const [items, setItems] = useState([]);
|
|
7997
8085
|
const [todos, setTodos] = useState(null);
|
|
@@ -8024,6 +8112,8 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8024
8112
|
const [composerRows, setComposerRows] = useState(1);
|
|
8025
8113
|
const [attachments, setAttachments] = useState([]);
|
|
8026
8114
|
const uploadsRef = useRef(/* @__PURE__ */ new Map());
|
|
8115
|
+
const [forking, setForking] = useState(false);
|
|
8116
|
+
const forkingRef = useRef(false);
|
|
8027
8117
|
const [credPrompt, setCredPrompt] = useState(null);
|
|
8028
8118
|
const credPromptOpen = credPrompt !== null;
|
|
8029
8119
|
const [menuDismissed, setMenuDismissed] = useState(false);
|
|
@@ -8062,10 +8152,11 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8062
8152
|
const reviewBelowBoxRef = useRef(null);
|
|
8063
8153
|
const paneDragRef = useRef(null);
|
|
8064
8154
|
const composerBoxHeight = composerRows + 2;
|
|
8065
|
-
const pendingVisible = !grantPrompt && !credPrompt && attachments.length > 0;
|
|
8155
|
+
const pendingVisible = !grantPrompt && !credPrompt && !nonWebChannel && attachments.length > 0;
|
|
8066
8156
|
const pendingRows = pendingVisible ? attachments.length + 2 : 0;
|
|
8067
8157
|
const credPromptHeight = 4 + (credPrompt && (credPrompt.error || credPrompt.submitting) ? 1 : 0);
|
|
8068
|
-
const
|
|
8158
|
+
const nonWebNoticeHeight = 5;
|
|
8159
|
+
const bottomBoxHeight = credPrompt ? credPromptHeight : nonWebChannel ? nonWebNoticeHeight : composerBoxHeight;
|
|
8069
8160
|
const bodyWidth = Math.max(1, width - 2);
|
|
8070
8161
|
const bodyHeight = Math.max(1, height - 3);
|
|
8071
8162
|
const reviewPlacement = filePanePlacement({
|
|
@@ -8712,7 +8803,7 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8712
8803
|
stageAttachment(image);
|
|
8713
8804
|
}, [stageAttachment]);
|
|
8714
8805
|
usePaste((event) => {
|
|
8715
|
-
if (modelPickerOpen || themePickerOpen || helpOpen || credPromptOpen || grantPrompt) return;
|
|
8806
|
+
if (modelPickerOpen || themePickerOpen || helpOpen || credPromptOpen || grantPrompt || nonWebChannel) return;
|
|
8716
8807
|
const text = event.metadata?.kind === "binary" ? "" : decodePasteBytes(event.bytes);
|
|
8717
8808
|
const route = routePaste({
|
|
8718
8809
|
kind: event.metadata?.kind,
|
|
@@ -8798,6 +8889,39 @@ function ChatScreen({ agent, conversation }) {
|
|
|
8798
8889
|
text: `couldn't open a browser — visit ${url} (${errorMessage(err)})`
|
|
8799
8890
|
}]));
|
|
8800
8891
|
}, [appUrl, conversationId]);
|
|
8892
|
+
const forkAndContinue = useCallback(() => {
|
|
8893
|
+
if (!rest || !conversationId || forkingRef.current) return;
|
|
8894
|
+
forkingRef.current = true;
|
|
8895
|
+
setForking(true);
|
|
8896
|
+
const stillHere = () => {
|
|
8897
|
+
const screen = useStore.getState().screen;
|
|
8898
|
+
return screen.kind === "chat" && !isNewConversation(screen.conversation) && screen.conversation.id === conversationId;
|
|
8899
|
+
};
|
|
8900
|
+
rest.forkConversation({ conversationId }).then((forked) => {
|
|
8901
|
+
if (!stillHere()) return;
|
|
8902
|
+
goTo({
|
|
8903
|
+
kind: "chat",
|
|
8904
|
+
agent,
|
|
8905
|
+
conversation: forkedConversationRef({
|
|
8906
|
+
agent,
|
|
8907
|
+
forked
|
|
8908
|
+
})
|
|
8909
|
+
});
|
|
8910
|
+
}).catch((err) => {
|
|
8911
|
+
forkingRef.current = false;
|
|
8912
|
+
setForking(false);
|
|
8913
|
+
if (!stillHere()) return;
|
|
8914
|
+
useStore.getState().showToast({
|
|
8915
|
+
variant: "error",
|
|
8916
|
+
message: `couldn't fork this conversation: ${errorMessage(err)}`
|
|
8917
|
+
});
|
|
8918
|
+
});
|
|
8919
|
+
}, [
|
|
8920
|
+
rest,
|
|
8921
|
+
conversationId,
|
|
8922
|
+
agent,
|
|
8923
|
+
goTo
|
|
8924
|
+
]);
|
|
8801
8925
|
const toggleShare = useCallback(() => {
|
|
8802
8926
|
if (!portalClient) return;
|
|
8803
8927
|
if (portal.status === "off") {
|
|
@@ -9093,11 +9217,17 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9093
9217
|
toggleShare();
|
|
9094
9218
|
return;
|
|
9095
9219
|
}
|
|
9220
|
+
if (nonWebChannel && key.name === "f" && key.ctrl) {
|
|
9221
|
+
forkAndContinue();
|
|
9222
|
+
return;
|
|
9223
|
+
}
|
|
9096
9224
|
if (key.name === "v" && key.ctrl) {
|
|
9225
|
+
if (nonWebChannel) return;
|
|
9097
9226
|
pasteImage();
|
|
9098
9227
|
return;
|
|
9099
9228
|
}
|
|
9100
9229
|
if (key.name === "x" && key.ctrl || key.name === "backspace" && attachmentsRef.current.length > 0 && !composerRef.current?.plainText) {
|
|
9230
|
+
if (nonWebChannel) return;
|
|
9101
9231
|
const last = attachmentsRef.current.at(-1);
|
|
9102
9232
|
if (last) {
|
|
9103
9233
|
uploadsRef.current.delete(last.tempId);
|
|
@@ -9162,13 +9292,15 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9162
9292
|
ctrlCArmed,
|
|
9163
9293
|
isShared,
|
|
9164
9294
|
hasPendingSteer,
|
|
9165
|
-
hasActionableCard
|
|
9295
|
+
hasActionableCard,
|
|
9296
|
+
nonWebChannel: nonWebChannel !== null
|
|
9166
9297
|
}), [
|
|
9167
9298
|
run.kind,
|
|
9168
9299
|
ctrlCArmed,
|
|
9169
9300
|
isShared,
|
|
9170
9301
|
hasPendingSteer,
|
|
9171
|
-
hasActionableCard
|
|
9302
|
+
hasActionableCard,
|
|
9303
|
+
nonWebChannel
|
|
9172
9304
|
]);
|
|
9173
9305
|
const modelHint = formatModelHint(model);
|
|
9174
9306
|
if (modelPickerOpen) return /* @__PURE__ */ jsx(ModelPicker, {
|
|
@@ -9397,6 +9529,35 @@ function ChatScreen({ agent, conversation }) {
|
|
|
9397
9529
|
children: "n"
|
|
9398
9530
|
})
|
|
9399
9531
|
]
|
|
9532
|
+
}) : nonWebChannel ? /* @__PURE__ */ jsxs("box", {
|
|
9533
|
+
style: {
|
|
9534
|
+
border: true,
|
|
9535
|
+
borderColor: theme.faint,
|
|
9536
|
+
paddingLeft: 1,
|
|
9537
|
+
paddingRight: 1,
|
|
9538
|
+
height: nonWebNoticeHeight,
|
|
9539
|
+
flexShrink: 0,
|
|
9540
|
+
marginTop: 1,
|
|
9541
|
+
flexDirection: "column"
|
|
9542
|
+
},
|
|
9543
|
+
children: [
|
|
9544
|
+
/* @__PURE__ */ jsxs("text", {
|
|
9545
|
+
fg: theme.muted,
|
|
9546
|
+
children: [
|
|
9547
|
+
"this conversation is on ",
|
|
9548
|
+
nonWebChannel,
|
|
9549
|
+
"."
|
|
9550
|
+
]
|
|
9551
|
+
}),
|
|
9552
|
+
/* @__PURE__ */ jsx("text", {
|
|
9553
|
+
fg: theme.dim,
|
|
9554
|
+
children: "reply there to continue it."
|
|
9555
|
+
}),
|
|
9556
|
+
/* @__PURE__ */ jsx("text", {
|
|
9557
|
+
fg: theme.dim,
|
|
9558
|
+
children: forking ? "forking into a new chat…" : "ctrl+f fork it into a chat you can continue here."
|
|
9559
|
+
})
|
|
9560
|
+
]
|
|
9400
9561
|
}) : /* @__PURE__ */ jsx("box", {
|
|
9401
9562
|
style: {
|
|
9402
9563
|
border: true,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
3
|
-
import { c as machineIdentity, i as mintPortalDeviceToken, l as portalWsUrl, n as findThisDevice, r as grantPortalAccess, s as buildEnv, t as fetchPortalDevices } from "./api-
|
|
3
|
+
import { c as machineIdentity, i as mintPortalDeviceToken, l as portalWsUrl, n as findThisDevice, r as grantPortalAccess, s as buildEnv, t as fetchPortalDevices } from "./api-BHq-5eW_.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { WebSocket } from "ws";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import "./rest-
|
|
3
|
-
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-
|
|
2
|
+
import "./rest-DZnAT7BG.mjs";
|
|
3
|
+
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-XvAHDKqu.mjs";
|
|
4
4
|
|
|
5
5
|
export { messageGet, readStdin, resolveAgent, runPrint };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createRestClient, t as HttpError } from "./rest-
|
|
2
|
+
import { n as createRestClient, t as HttpError } from "./rest-DZnAT7BG.mjs";
|
|
3
3
|
import { n as isRecord, t as errorMessage } from "./util-CeisaZVY.mjs";
|
|
4
4
|
import stableStringify from "safe-stable-stringify";
|
|
5
5
|
|
|
@@ -14,7 +14,7 @@ import { n as printError } from "./output-B4cW10Ph.mjs";
|
|
|
14
14
|
* the reply (and to --json).
|
|
15
15
|
*/
|
|
16
16
|
async function connectMachineShare({ appUrl, sessionToken, timeoutHint }) {
|
|
17
|
-
const { PortalClient } = await import("./client-
|
|
17
|
+
const { PortalClient } = await import("./client-CRAGDqp0.mjs");
|
|
18
18
|
let signalConnected;
|
|
19
19
|
const connected = new Promise((resolve) => {
|
|
20
20
|
signalConnected = resolve;
|
|
@@ -223,6 +223,10 @@ function createRestClient({ appUrl, sessionToken }) {
|
|
|
223
223
|
sizeBytes: finalized.sizeBytes ?? size
|
|
224
224
|
};
|
|
225
225
|
},
|
|
226
|
+
forkConversation: async ({ conversationId }) => {
|
|
227
|
+
const { conversation } = await post(`/api/v1/conversations/${encodeURIComponent(conversationId)}/fork`, {}, forkConversationResponseSchema);
|
|
228
|
+
return conversation;
|
|
229
|
+
},
|
|
226
230
|
deleteConversation: async ({ conversationId }) => {
|
|
227
231
|
await del(`/api/v1/conversations/${encodeURIComponent(conversationId)}`);
|
|
228
232
|
},
|
|
@@ -347,6 +351,12 @@ const listAgentsResponseSchema = z.object({
|
|
|
347
351
|
totalCount: z.number().nullable().optional()
|
|
348
352
|
});
|
|
349
353
|
const createAgentResponseSchema = z.object({ agent: agentSummarySchema });
|
|
354
|
+
const conversationAgentSchema = z.object({
|
|
355
|
+
id: z.string().uuid(),
|
|
356
|
+
name: z.string(),
|
|
357
|
+
slug: z.string().nullable().optional(),
|
|
358
|
+
title: z.string().nullable().optional()
|
|
359
|
+
});
|
|
350
360
|
const conversationSummarySchema = z.object({
|
|
351
361
|
id: z.string().uuid(),
|
|
352
362
|
title: z.string().nullable(),
|
|
@@ -356,20 +366,23 @@ const conversationSummarySchema = z.object({
|
|
|
356
366
|
channel: z.string().nullable(),
|
|
357
367
|
channelLabel: z.string().nullable(),
|
|
358
368
|
viewerArchivedAt: z.string().nullable().optional(),
|
|
359
|
-
agent:
|
|
360
|
-
|
|
361
|
-
name: z.string(),
|
|
362
|
-
slug: z.string().nullable().optional(),
|
|
363
|
-
title: z.string().nullable().optional()
|
|
364
|
-
})
|
|
369
|
+
agent: conversationAgentSchema,
|
|
370
|
+
agents: z.array(conversationAgentSchema).optional()
|
|
365
371
|
});
|
|
366
372
|
const conversationDetailSchema = z.object({
|
|
367
373
|
id: z.string().uuid(),
|
|
368
374
|
title: z.string().nullable(),
|
|
369
375
|
agentId: z.string().uuid(),
|
|
370
376
|
createdAt: z.string(),
|
|
371
|
-
updatedAt: z.string()
|
|
377
|
+
updatedAt: z.string(),
|
|
378
|
+
channel: z.string().nullable(),
|
|
379
|
+
channelLabel: z.string().nullable()
|
|
380
|
+
});
|
|
381
|
+
const conversationTitleSchema = z.object({
|
|
382
|
+
id: z.string().uuid(),
|
|
383
|
+
title: z.string().nullable()
|
|
372
384
|
});
|
|
385
|
+
const forkConversationResponseSchema = z.object({ conversation: conversationTitleSchema });
|
|
373
386
|
const getConversationResponseSchema = z.object({ conversation: conversationDetailSchema });
|
|
374
387
|
const listConversationsResponseSchema = z.object({
|
|
375
388
|
conversations: z.array(conversationSummarySchema),
|
package/package.json
CHANGED