skydive-cli 0.2.0-beta.604 → 0.2.0-beta.606
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-Bx5VyWaC.mjs → api-BGWcPuik.mjs} +1 -1
- package/dist/js/bin.mjs +16 -20
- package/dist/js/{boot-Cmte0eob.mjs → boot-0dKnbAAn.mjs} +233 -8
- package/dist/js/client-BRfmlbgI.mjs +6 -0
- package/dist/js/{client-BsLCAWf1.mjs → client-l3OrGKaC.mjs} +2 -2
- package/dist/js/{brand-BVALAEf1.mjs → install-CUhhdQ1L.mjs} +114 -1
- package/dist/js/{print-DLGCpIM9.mjs → print-6Bm51XhR.mjs} +1 -1
- package/dist/js/{print-QPPaRx38.mjs → print-qXJymvuF.mjs} +2 -2
- package/dist/js/{print-share-DPsQq2Cy.mjs → print-share-DE_dkZX7.mjs} +1 -1
- package/dist/js/{rest-nx0AmgJy.mjs → rest-C3RySrPa.mjs} +1 -1
- package/dist/js/{rest-vu2-Lrsa.mjs → rest-DMpigwmN.mjs} +3 -1
- package/package.json +1 -1
- package/dist/js/client-BYYp0E6M.mjs +0 -6
package/dist/js/bin.mjs
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { A as
|
|
2
|
+
import { A as deleteConfig, B as resolveAppUrl, C as setActiveWorkspace, D as DEFAULT_API_URL, E as API_KEY_PREFIX, G as saveConfig, H as resolveManagementAuth, I as getShareMachineDefault, J as setLastSeenVersion, K as saveSession, L as getStoredApiKeyId, M as getLastSeenVersion, N as getPromptHistoryPath, R as getStoredApiKeyWorkspaceName, S as listWorkspaces, T as API_KEY_FAMILY_PREFIX, U as resolveSession, V as resolveConfig, X as version, Y as name, _ as themes, b as getActiveWorkspaceId, j as getConfigPath, k as DEFAULT_WEB_URL, o as brandHelpArt, t as installCrashHandler, w as API_KEYS_URL, x as getSessionIdentity, y as ensureActiveOrganization, z as getUpdateCheckDisabled } from "./install-CUhhdQ1L.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-DMpigwmN.mjs";
|
|
5
|
+
import { i as resolveAgent } from "./print-6Bm51XhR.mjs";
|
|
6
|
+
import { a as registerPortalDevice, c as machineIdentity, n as findThisDevice, o as revokePortalAccess, r as grantPortalAccess, t as fetchPortalDevices } from "./api-BGWcPuik.mjs";
|
|
7
7
|
import { t as SandboxStream } from "./client-BVOAwU8M.mjs";
|
|
8
8
|
import { hideBin } from "yargs/helpers";
|
|
9
9
|
import yargs from "yargs";
|
|
@@ -18,11 +18,6 @@ import fs from "node:fs";
|
|
|
18
18
|
import zlib from "node:zlib";
|
|
19
19
|
import semver from "semver";
|
|
20
20
|
|
|
21
|
-
//#region package.json
|
|
22
|
-
var name = "skydive-cli";
|
|
23
|
-
var version = "0.2.0-beta.604";
|
|
24
|
-
|
|
25
|
-
//#endregion
|
|
26
21
|
//#region src/types.ts
|
|
27
22
|
const NON_INTERACTIVE_ENV_VARS = [
|
|
28
23
|
"CI",
|
|
@@ -1200,7 +1195,7 @@ const importCommand = {
|
|
|
1200
1195
|
process.exit(1);
|
|
1201
1196
|
}
|
|
1202
1197
|
}
|
|
1203
|
-
const { runChat } = await import("./boot-
|
|
1198
|
+
const { runChat } = await import("./boot-0dKnbAAn.mjs");
|
|
1204
1199
|
await runChat({
|
|
1205
1200
|
appUrl,
|
|
1206
1201
|
sessionToken: session.value.sessionToken,
|
|
@@ -1227,7 +1222,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1227
1222
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login --web\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1228
1223
|
process.exit(1);
|
|
1229
1224
|
}
|
|
1230
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1225
|
+
const { connectMachineShare } = await import("./print-share-DE_dkZX7.mjs");
|
|
1231
1226
|
const machineShare = await connectMachineShare({
|
|
1232
1227
|
appUrl,
|
|
1233
1228
|
sessionToken: session.value.sessionToken,
|
|
@@ -1235,7 +1230,7 @@ async function runImportPrintMode({ argv, appUrl }) {
|
|
|
1235
1230
|
});
|
|
1236
1231
|
const extra = (argv.print ?? "").trim();
|
|
1237
1232
|
const prompt = buildImportSeedPrompt(process.cwd()) + (extra ? `\n\nAdditional instructions: ${extra}` : "");
|
|
1238
|
-
const { runPrint } = await import("./print-
|
|
1233
|
+
const { runPrint } = await import("./print-qXJymvuF.mjs");
|
|
1239
1234
|
try {
|
|
1240
1235
|
const result = await runPrint({
|
|
1241
1236
|
appUrl,
|
|
@@ -1516,7 +1511,7 @@ const chatCommand = {
|
|
|
1516
1511
|
printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
|
|
1517
1512
|
process.exit(1);
|
|
1518
1513
|
}
|
|
1519
|
-
const { runChat } = await import("./boot-
|
|
1514
|
+
const { runChat } = await import("./boot-0dKnbAAn.mjs");
|
|
1520
1515
|
await runChat({
|
|
1521
1516
|
appUrl,
|
|
1522
1517
|
sessionToken: session.value.sessionToken,
|
|
@@ -1553,7 +1548,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1553
1548
|
printError(`${session.error.message} For non-interactive use, run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1554
1549
|
process.exit(1);
|
|
1555
1550
|
}
|
|
1556
|
-
const { runPrint, readStdin } = await import("./print-
|
|
1551
|
+
const { runPrint, readStdin } = await import("./print-qXJymvuF.mjs");
|
|
1557
1552
|
let prompt = (argv.print ?? "").trim();
|
|
1558
1553
|
if (!prompt) {
|
|
1559
1554
|
if (process.stdin.isTTY) {
|
|
@@ -1568,7 +1563,7 @@ async function runPrintMode({ argv, appUrl }) {
|
|
|
1568
1563
|
}
|
|
1569
1564
|
let machineShare = null;
|
|
1570
1565
|
if (resolveShareMachine(argv)) {
|
|
1571
|
-
const { connectMachineShare } = await import("./print-share-
|
|
1566
|
+
const { connectMachineShare } = await import("./print-share-DE_dkZX7.mjs");
|
|
1572
1567
|
machineShare = await connectMachineShare({
|
|
1573
1568
|
appUrl,
|
|
1574
1569
|
sessionToken: session.value.sessionToken,
|
|
@@ -1627,7 +1622,7 @@ const getCommand = {
|
|
|
1627
1622
|
printError(`${session.error.message} Run \`skydive auth login\` first, or set SKYDIVE_SESSION_TOKEN.`);
|
|
1628
1623
|
process.exit(1);
|
|
1629
1624
|
}
|
|
1630
|
-
const { messageGet } = await import("./print-
|
|
1625
|
+
const { messageGet } = await import("./print-qXJymvuF.mjs");
|
|
1631
1626
|
try {
|
|
1632
1627
|
const result = await messageGet({
|
|
1633
1628
|
appUrl,
|
|
@@ -1824,7 +1819,7 @@ const switchCommand = {
|
|
|
1824
1819
|
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.");
|
|
1825
1820
|
process.exit(1);
|
|
1826
1821
|
}
|
|
1827
|
-
const { runWorkspacePicker } = await import("./boot-
|
|
1822
|
+
const { runWorkspacePicker } = await import("./boot-0dKnbAAn.mjs");
|
|
1828
1823
|
await runWorkspacePicker(session);
|
|
1829
1824
|
return;
|
|
1830
1825
|
}
|
|
@@ -1902,7 +1897,7 @@ const openCommand = {
|
|
|
1902
1897
|
const agent = argv.agent ? resolveAgent((await fetchPortalDevices(session)).agents, argv.agent) : null;
|
|
1903
1898
|
const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
|
|
1904
1899
|
const { machineName } = machineIdentity();
|
|
1905
|
-
const { PortalClient } = await import("./client-
|
|
1900
|
+
const { PortalClient } = await import("./client-BRfmlbgI.mjs");
|
|
1906
1901
|
let lastLine = "";
|
|
1907
1902
|
let signalConnected;
|
|
1908
1903
|
const connected = new Promise((resolve) => {
|
|
@@ -2074,8 +2069,8 @@ const sandboxCommand = {
|
|
|
2074
2069
|
}).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`"),
|
|
2075
2070
|
handler: async (argv) => {
|
|
2076
2071
|
const session = requireSession(argv);
|
|
2077
|
-
const { createRestClient } = await import("./rest-
|
|
2078
|
-
const { resolveAgent } = await import("./print-
|
|
2072
|
+
const { createRestClient } = await import("./rest-C3RySrPa.mjs");
|
|
2073
|
+
const { resolveAgent } = await import("./print-qXJymvuF.mjs");
|
|
2079
2074
|
const client = createRestClient({
|
|
2080
2075
|
appUrl: session.appUrl,
|
|
2081
2076
|
sessionToken: session.sessionToken
|
|
@@ -2616,6 +2611,7 @@ function maybePrintWhatsNew({ stderrIsTTY = process.stderr.isTTY ?? false, nonIn
|
|
|
2616
2611
|
|
|
2617
2612
|
//#endregion
|
|
2618
2613
|
//#region src/bin.ts
|
|
2614
|
+
installCrashHandler();
|
|
2619
2615
|
if (process.argv.includes(UPDATE_WORKER_FLAG)) {
|
|
2620
2616
|
await runUpdateCheckWorker();
|
|
2621
2617
|
process.exit(0);
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, r as errorDetail, t as HttpError } from "./rest-
|
|
4
|
-
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-
|
|
5
|
-
import "./api-
|
|
2
|
+
import { C as setActiveWorkspace, D as DEFAULT_API_URL, F as getSavedTheme, O as DEFAULT_APP_URL, P as getReviewStateDir, S as listWorkspaces, W as resolveWebUrl, a as WORDMARK, b as getActiveWorkspaceId, c as applyTheme, d as noColorRequested, f as theme, g as themeVersion, h as themeModeFromColorFgBg, i as MARK_CELLS, j as getConfigPath, l as findTheme, m as themeMode, n as buildCrashReport, p as themeForMode, q as saveTheme, r as writeCrashReport, s as DEFAULT_THEME_ID, t as installCrashHandler, u as monoTheme, v as themesForMode } from "./install-CUhhdQ1L.mjs";
|
|
3
|
+
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, r as errorDetail, t as HttpError } from "./rest-DMpigwmN.mjs";
|
|
4
|
+
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-6Bm51XhR.mjs";
|
|
5
|
+
import "./api-BGWcPuik.mjs";
|
|
6
6
|
import { t as SandboxStream } from "./client-BVOAwU8M.mjs";
|
|
7
|
-
import { t as PortalClient } from "./client-
|
|
7
|
+
import { t as PortalClient } from "./client-l3OrGKaC.mjs";
|
|
8
8
|
import { t as runRawPtyPassthrough } from "./raw-pty-Dbi2kb9v.mjs";
|
|
9
9
|
import * as os$1 from "node:os";
|
|
10
10
|
import { homedir, platform, release, tmpdir } from "node:os";
|
|
@@ -1862,8 +1862,28 @@ function fitHintLine(segments, width) {
|
|
|
1862
1862
|
return truncate(kept.join(" · "), width);
|
|
1863
1863
|
}
|
|
1864
1864
|
|
|
1865
|
+
//#endregion
|
|
1866
|
+
//#region src/chat/tui/use-debounced-value.ts
|
|
1867
|
+
/**
|
|
1868
|
+
* Returns a copy of `value` that only updates after it has stopped changing
|
|
1869
|
+
* for `delayMs`. Use it to throttle work driven by fast-changing state — e.g.
|
|
1870
|
+
* a search input whose every keystroke would otherwise fire a new request.
|
|
1871
|
+
*
|
|
1872
|
+
* Mirrors the web app's `useDebouncedValue` so the CLI conversation search
|
|
1873
|
+
* debounces its server query the same way the web sidebar does.
|
|
1874
|
+
*/
|
|
1875
|
+
function useDebouncedValue(value, delayMs) {
|
|
1876
|
+
const [debounced, setDebounced] = useState(value);
|
|
1877
|
+
useEffect(() => {
|
|
1878
|
+
const timer = setTimeout(() => setDebounced(value), delayMs);
|
|
1879
|
+
return () => clearTimeout(timer);
|
|
1880
|
+
}, [value, delayMs]);
|
|
1881
|
+
return debounced;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1865
1884
|
//#endregion
|
|
1866
1885
|
//#region src/chat/tui/screens/conversation-picker.tsx
|
|
1886
|
+
const SEARCH_DEBOUNCE_MS = 250;
|
|
1867
1887
|
const humanChannels = [
|
|
1868
1888
|
"web",
|
|
1869
1889
|
"slack",
|
|
@@ -1971,16 +1991,83 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1971
1991
|
const rest = useStore((s) => s.rest);
|
|
1972
1992
|
const [query, setQuery] = useState("");
|
|
1973
1993
|
const [highlight, setHighlight] = useState(0);
|
|
1994
|
+
const debouncedQuery = useDebouncedValue(query.trim(), SEARCH_DEBOUNCE_MS);
|
|
1995
|
+
const isSearching = debouncedQuery.length > 0;
|
|
1996
|
+
const [search, setSearch] = useState(null);
|
|
1997
|
+
useEffect(() => {
|
|
1998
|
+
if (!rest || !isSearching) {
|
|
1999
|
+
setSearch(null);
|
|
2000
|
+
return;
|
|
2001
|
+
}
|
|
2002
|
+
let cancelled = false;
|
|
2003
|
+
setSearch({
|
|
2004
|
+
query: debouncedQuery,
|
|
2005
|
+
state: { kind: "loading" }
|
|
2006
|
+
});
|
|
2007
|
+
(async () => {
|
|
2008
|
+
try {
|
|
2009
|
+
const results = await rest.listConversations({
|
|
2010
|
+
agentId: agent.id,
|
|
2011
|
+
channels: showAutomated ? void 0 : humanChannels,
|
|
2012
|
+
archived: showArchived ? "include" : "exclude",
|
|
2013
|
+
query: debouncedQuery,
|
|
2014
|
+
onPage: (partial) => {
|
|
2015
|
+
if (!cancelled) setSearch({
|
|
2016
|
+
query: debouncedQuery,
|
|
2017
|
+
state: {
|
|
2018
|
+
kind: "ready",
|
|
2019
|
+
conversations: partial
|
|
2020
|
+
}
|
|
2021
|
+
});
|
|
2022
|
+
}
|
|
2023
|
+
});
|
|
2024
|
+
if (cancelled) return;
|
|
2025
|
+
setSearch({
|
|
2026
|
+
query: debouncedQuery,
|
|
2027
|
+
state: {
|
|
2028
|
+
kind: "ready",
|
|
2029
|
+
conversations: results
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
} catch (err) {
|
|
2033
|
+
if (cancelled) return;
|
|
2034
|
+
setSearch({
|
|
2035
|
+
query: debouncedQuery,
|
|
2036
|
+
state: {
|
|
2037
|
+
kind: "error",
|
|
2038
|
+
message: err instanceof Error ? err.message : String(err)
|
|
2039
|
+
}
|
|
2040
|
+
});
|
|
2041
|
+
}
|
|
2042
|
+
})();
|
|
2043
|
+
return () => {
|
|
2044
|
+
cancelled = true;
|
|
2045
|
+
};
|
|
2046
|
+
}, [
|
|
2047
|
+
rest,
|
|
2048
|
+
agent.id,
|
|
2049
|
+
debouncedQuery,
|
|
2050
|
+
isSearching,
|
|
2051
|
+
showAutomated,
|
|
2052
|
+
showArchived
|
|
2053
|
+
]);
|
|
1974
2054
|
const [removedIds, setRemovedIds] = useState(/* @__PURE__ */ new Set());
|
|
1975
2055
|
const [archiveOverrides, setArchiveOverrides] = useState(/* @__PURE__ */ new Map());
|
|
1976
2056
|
const [confirmId, setConfirmId] = useState(null);
|
|
1977
2057
|
const [error, setError] = useState(null);
|
|
1978
2058
|
const isArchived = (c) => archiveOverrides.get(c.id) ?? c.viewerArchivedAt != null;
|
|
1979
|
-
const list = conversations.filter((c) => !removedIds.has(c.id) && (showArchived || !isArchived(c)));
|
|
2059
|
+
const list = ((isSearching && search?.query === debouncedQuery && search.state.kind === "ready" ? search.state.conversations : null) ?? conversations).filter((c) => !removedIds.has(c.id) && (showArchived || !isArchived(c)));
|
|
1980
2060
|
useEffect(() => {
|
|
1981
2061
|
setHighlight(0);
|
|
1982
2062
|
}, [showAutomated, showArchived]);
|
|
1983
|
-
const hits =
|
|
2063
|
+
const hits = isSearching ? list.map((item) => ({
|
|
2064
|
+
item,
|
|
2065
|
+
highlights: [
|
|
2066
|
+
substringIndexes(singleLine(item.title ?? ""), debouncedQuery),
|
|
2067
|
+
null,
|
|
2068
|
+
null
|
|
2069
|
+
]
|
|
2070
|
+
})) : fuzzyFilter(query, list, conversationKeys);
|
|
1984
2071
|
const rows = [{ kind: "new" }, ...hits.map((hit) => ({
|
|
1985
2072
|
kind: "conv",
|
|
1986
2073
|
hit
|
|
@@ -1991,6 +2078,8 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
1991
2078
|
const highlightRow = rows[clamped];
|
|
1992
2079
|
const highlightArchived = highlightRow?.kind === "conv" && isArchived(highlightRow.hit.item);
|
|
1993
2080
|
const confirmConv = confirmId !== null ? list.find((c) => c.id === confirmId) : void 0;
|
|
2081
|
+
const searchState = isSearching ? search?.state : void 0;
|
|
2082
|
+
const countSegment = isSearching && (searchState?.kind === "loading" || search === null) ? "searching…" : isSearching && searchState?.kind === "error" ? `search failed: ${searchState.message}` : `${hits.length}/${list.length}${complete || isSearching ? "" : " (loading…)"}`;
|
|
1994
2083
|
const status = confirmConv ? {
|
|
1995
2084
|
fg: theme.error,
|
|
1996
2085
|
text: truncate(`delete “${confirmConv.title ?? "(untitled)"}”? y/n`, innerWidth)
|
|
@@ -2000,7 +2089,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
2000
2089
|
} : {
|
|
2001
2090
|
fg: theme.dim,
|
|
2002
2091
|
text: fitHintLine([
|
|
2003
|
-
|
|
2092
|
+
countSegment,
|
|
2004
2093
|
`ctrl+a ${highlightArchived ? "unarchive" : "archive"}`,
|
|
2005
2094
|
"ctrl+d delete",
|
|
2006
2095
|
`tab ${showAutomated ? "hide" : "show"} agent runs`,
|
|
@@ -2191,6 +2280,20 @@ const conversationKeys = [
|
|
|
2191
2280
|
(c) => c.preview ?? "",
|
|
2192
2281
|
(c) => conversationAgents(c).map((a) => a.name).join(" ")
|
|
2193
2282
|
];
|
|
2283
|
+
/**
|
|
2284
|
+
* Character indexes of the first case-insensitive occurrence of `needle` in
|
|
2285
|
+
* `haystack`, for highlighting a literal title match under server search (the
|
|
2286
|
+
* server's title branch is a substring ILIKE). Null when it doesn't occur — a
|
|
2287
|
+
* server row can match on message body or participant name without its title
|
|
2288
|
+
* containing the query, in which case nothing in the title is highlighted.
|
|
2289
|
+
*/
|
|
2290
|
+
function substringIndexes(haystack, needle) {
|
|
2291
|
+
const trimmed = needle.trim();
|
|
2292
|
+
if (!trimmed) return null;
|
|
2293
|
+
const at = haystack.toLowerCase().indexOf(trimmed.toLowerCase());
|
|
2294
|
+
if (at < 0) return null;
|
|
2295
|
+
return Array.from({ length: trimmed.length }, (_, i) => at + i);
|
|
2296
|
+
}
|
|
2194
2297
|
function previewLine(c) {
|
|
2195
2298
|
const when = relativeTime(c.updatedAt);
|
|
2196
2299
|
const prefix = c.preview ? c.preview.replace(/\s+/g, " ").trim() : "";
|
|
@@ -11113,6 +11216,126 @@ var LinkifiedMarkdownRenderable = class extends MarkdownRenderable {
|
|
|
11113
11216
|
}
|
|
11114
11217
|
};
|
|
11115
11218
|
|
|
11219
|
+
//#endregion
|
|
11220
|
+
//#region src/chat/memory-watchdog.ts
|
|
11221
|
+
const MB = 1024 * 1024;
|
|
11222
|
+
/** How often to sample RSS. */
|
|
11223
|
+
const DEFAULT_SAMPLE_INTERVAL_MS = 15e3;
|
|
11224
|
+
/**
|
|
11225
|
+
* Soft threshold: cross it and we warn the user once. A healthy chat session
|
|
11226
|
+
* sits in the low hundreds of MB, so 2 GB is "something is wrong" without
|
|
11227
|
+
* being so eager it fires on a legitimately large conversation.
|
|
11228
|
+
*/
|
|
11229
|
+
const DEFAULT_WARN_THRESHOLD_BYTES = 2 * 1024 * MB;
|
|
11230
|
+
/**
|
|
11231
|
+
* A clean exit still writes a report if the peak got this high — so we learn
|
|
11232
|
+
* about near-misses that didn't quite OOM, not just the crashes.
|
|
11233
|
+
*/
|
|
11234
|
+
const DEFAULT_REPORT_THRESHOLD_BYTES = 4 * 1024 * MB;
|
|
11235
|
+
/** Keep the last N samples so the report shows a growth curve, not a point. */
|
|
11236
|
+
const MAX_SAMPLES = 240;
|
|
11237
|
+
function envBytes(name, fallback) {
|
|
11238
|
+
const raw = process.env[name];
|
|
11239
|
+
if (!raw) return fallback;
|
|
11240
|
+
const n = Number(raw);
|
|
11241
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
11242
|
+
}
|
|
11243
|
+
function envMs(name, fallback) {
|
|
11244
|
+
const raw = process.env[name];
|
|
11245
|
+
if (!raw) return fallback;
|
|
11246
|
+
const n = Number(raw);
|
|
11247
|
+
return Number.isFinite(n) && n > 0 ? n : fallback;
|
|
11248
|
+
}
|
|
11249
|
+
/**
|
|
11250
|
+
* Start the memory watchdog. Returns a handle; call `stop()` on teardown.
|
|
11251
|
+
*
|
|
11252
|
+
* Disabled entirely when `SKYDIVE_NO_MEMORY_WATCHDOG` is set — an escape
|
|
11253
|
+
* hatch that also keeps the sampler out of the way in tests and CI.
|
|
11254
|
+
*/
|
|
11255
|
+
function startMemoryWatchdog(opts = {}) {
|
|
11256
|
+
const disabled = Boolean(process.env["SKYDIVE_NO_MEMORY_WATCHDOG"]);
|
|
11257
|
+
const now = opts.now ?? (() => Date.now());
|
|
11258
|
+
const readMemory = opts.readMemory ?? (() => {
|
|
11259
|
+
const u = process.memoryUsage();
|
|
11260
|
+
return {
|
|
11261
|
+
rss: u.rss,
|
|
11262
|
+
heapUsed: u.heapUsed
|
|
11263
|
+
};
|
|
11264
|
+
});
|
|
11265
|
+
const sampleIntervalMs = opts.sampleIntervalMs ?? envMs("SKYDIVE_MEMORY_SAMPLE_MS", DEFAULT_SAMPLE_INTERVAL_MS);
|
|
11266
|
+
const warnThreshold = opts.warnThresholdBytes ?? envBytes("SKYDIVE_MEMORY_WARN_BYTES", DEFAULT_WARN_THRESHOLD_BYTES);
|
|
11267
|
+
const reportThreshold = opts.reportThresholdBytes ?? envBytes("SKYDIVE_MEMORY_REPORT_BYTES", DEFAULT_REPORT_THRESHOLD_BYTES);
|
|
11268
|
+
const startedAt = now();
|
|
11269
|
+
const samples = [];
|
|
11270
|
+
let peakRss = 0;
|
|
11271
|
+
let peakHeapUsed = 0;
|
|
11272
|
+
let warned = false;
|
|
11273
|
+
function sample() {
|
|
11274
|
+
const { rss, heapUsed } = readMemory();
|
|
11275
|
+
if (rss > peakRss) peakRss = rss;
|
|
11276
|
+
if (heapUsed > peakHeapUsed) peakHeapUsed = heapUsed;
|
|
11277
|
+
const s = {
|
|
11278
|
+
at: now() - startedAt,
|
|
11279
|
+
rss,
|
|
11280
|
+
heapUsed
|
|
11281
|
+
};
|
|
11282
|
+
samples.push(s);
|
|
11283
|
+
if (samples.length > MAX_SAMPLES) samples.shift();
|
|
11284
|
+
if (!warned && rss >= warnThreshold) {
|
|
11285
|
+
warned = true;
|
|
11286
|
+
opts.onWarn?.({
|
|
11287
|
+
rss,
|
|
11288
|
+
threshold: warnThreshold
|
|
11289
|
+
});
|
|
11290
|
+
}
|
|
11291
|
+
return s;
|
|
11292
|
+
}
|
|
11293
|
+
function snapshot() {
|
|
11294
|
+
if (disabled) return null;
|
|
11295
|
+
sample();
|
|
11296
|
+
return {
|
|
11297
|
+
peakRss,
|
|
11298
|
+
peakHeapUsed,
|
|
11299
|
+
warnThreshold,
|
|
11300
|
+
uptimeMs: now() - startedAt,
|
|
11301
|
+
samples: samples.slice()
|
|
11302
|
+
};
|
|
11303
|
+
}
|
|
11304
|
+
if (disabled) return {
|
|
11305
|
+
peakRss: () => 0,
|
|
11306
|
+
samples: () => [],
|
|
11307
|
+
snapshot: () => null,
|
|
11308
|
+
stop: () => {}
|
|
11309
|
+
};
|
|
11310
|
+
sample();
|
|
11311
|
+
const timer = setInterval(sample, sampleIntervalMs);
|
|
11312
|
+
if (typeof timer.unref === "function") timer.unref();
|
|
11313
|
+
const onExit = () => {
|
|
11314
|
+
if (peakRss < reportThreshold) return;
|
|
11315
|
+
writeCrashReport(buildCrashReport({
|
|
11316
|
+
reason: "high-memory-exit",
|
|
11317
|
+
memory: {
|
|
11318
|
+
peakRss,
|
|
11319
|
+
peakHeapUsed,
|
|
11320
|
+
warnThreshold,
|
|
11321
|
+
uptimeMs: now() - startedAt,
|
|
11322
|
+
samples: samples.slice()
|
|
11323
|
+
}
|
|
11324
|
+
}));
|
|
11325
|
+
};
|
|
11326
|
+
const installExitHandler = opts.installExitHandler ?? true;
|
|
11327
|
+
if (installExitHandler) process.on("exit", onExit);
|
|
11328
|
+
return {
|
|
11329
|
+
peakRss: () => peakRss,
|
|
11330
|
+
samples: () => samples.slice(),
|
|
11331
|
+
snapshot,
|
|
11332
|
+
stop: () => {
|
|
11333
|
+
clearInterval(timer);
|
|
11334
|
+
if (installExitHandler) process.off("exit", onExit);
|
|
11335
|
+
}
|
|
11336
|
+
};
|
|
11337
|
+
}
|
|
11338
|
+
|
|
11116
11339
|
//#endregion
|
|
11117
11340
|
//#region src/chat/boot.tsx
|
|
11118
11341
|
/**
|
|
@@ -11122,6 +11345,8 @@ var LinkifiedMarkdownRenderable = class extends MarkdownRenderable {
|
|
|
11122
11345
|
* dynamically imported and never loaded on the Node management path.
|
|
11123
11346
|
*/
|
|
11124
11347
|
async function runChat({ appUrl, sessionToken, shareMachine, promptHistoryPath, theme: themeOverride, notifications, agentSelector, conversationId, newConversation, seedPrompt }) {
|
|
11348
|
+
const watchdog = startMemoryWatchdog();
|
|
11349
|
+
installCrashHandler({ memoryProvider: () => watchdog.snapshot() });
|
|
11125
11350
|
const renderer = await createCliRenderer({ exitOnCtrlC: false });
|
|
11126
11351
|
extend({ markdown: LinkifiedMarkdownRenderable });
|
|
11127
11352
|
useStore.setState({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as errorMessage } from "./rest-
|
|
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-
|
|
2
|
+
import { a as errorMessage } from "./rest-DMpigwmN.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-BGWcPuik.mjs";
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { spawn } from "node:child_process";
|
|
6
6
|
import { WebSocket } from "ws";
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import Conf from "conf";
|
|
4
5
|
import { err, ok } from "neverthrow";
|
|
5
6
|
import { z } from "zod";
|
|
7
|
+
import fs from "node:fs";
|
|
6
8
|
|
|
9
|
+
//#region package.json
|
|
10
|
+
var name = "skydive-cli";
|
|
11
|
+
var version$1 = "0.2.0-beta.606";
|
|
12
|
+
|
|
13
|
+
//#endregion
|
|
7
14
|
//#region src/config.ts
|
|
8
15
|
/** Default host for the public management API (`/v1`, API-key auth). */
|
|
9
16
|
const DEFAULT_API_URL = "https://api.skydive.com";
|
|
@@ -1130,4 +1137,110 @@ function brandHelpArt(stream = process.stdout) {
|
|
|
1130
1137
|
}
|
|
1131
1138
|
|
|
1132
1139
|
//#endregion
|
|
1133
|
-
|
|
1140
|
+
//#region src/crash/report.ts
|
|
1141
|
+
const MB = 1024 * 1024;
|
|
1142
|
+
function currentRuntime() {
|
|
1143
|
+
const bun = process.versions["bun"];
|
|
1144
|
+
return bun ? `bun ${bun}` : `node ${process.version}`;
|
|
1145
|
+
}
|
|
1146
|
+
function serializeError(error) {
|
|
1147
|
+
if (error == null) return null;
|
|
1148
|
+
if (error instanceof Error) return {
|
|
1149
|
+
name: error.name,
|
|
1150
|
+
message: error.message,
|
|
1151
|
+
...error.stack ? { stack: error.stack } : {}
|
|
1152
|
+
};
|
|
1153
|
+
return {
|
|
1154
|
+
name: "NonError",
|
|
1155
|
+
message: String(error)
|
|
1156
|
+
};
|
|
1157
|
+
}
|
|
1158
|
+
/** Directory where crash/diagnostic reports are written (beside config). */
|
|
1159
|
+
function getCrashDir() {
|
|
1160
|
+
return path.join(path.dirname(getConfigPath()), "crash");
|
|
1161
|
+
}
|
|
1162
|
+
/** Build a report object without touching disk. */
|
|
1163
|
+
function buildCrashReport(args) {
|
|
1164
|
+
return {
|
|
1165
|
+
reason: args.reason,
|
|
1166
|
+
cliVersion: version$1,
|
|
1167
|
+
runtime: currentRuntime(),
|
|
1168
|
+
platform: process.platform,
|
|
1169
|
+
arch: process.arch,
|
|
1170
|
+
nodeVersion: process.version,
|
|
1171
|
+
totalSystemMemory: os.totalmem(),
|
|
1172
|
+
error: serializeError(args.error),
|
|
1173
|
+
memory: args.memory ?? null,
|
|
1174
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
/**
|
|
1178
|
+
* Write a report to disk and return its path (or null if writing failed).
|
|
1179
|
+
* Safe to call from a fatal handler: every failure is swallowed so the
|
|
1180
|
+
* diagnostic can never mask the original crash.
|
|
1181
|
+
*/
|
|
1182
|
+
function writeCrashReport(report) {
|
|
1183
|
+
try {
|
|
1184
|
+
const dir = getCrashDir();
|
|
1185
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
1186
|
+
const stamp = report.timestamp.replace(/[:.]/g, "-");
|
|
1187
|
+
const file = path.join(dir, `crash-${stamp}.json`);
|
|
1188
|
+
fs.writeFileSync(file, `${JSON.stringify(report, null, 2)}\n`, { mode: 384 });
|
|
1189
|
+
return file;
|
|
1190
|
+
} catch (_error) {
|
|
1191
|
+
return null;
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
/** Human-readable MB, one decimal. */
|
|
1195
|
+
function formatMb(bytes) {
|
|
1196
|
+
return `${(bytes / MB).toFixed(1)} MB`;
|
|
1197
|
+
}
|
|
1198
|
+
|
|
1199
|
+
//#endregion
|
|
1200
|
+
//#region src/crash/install.ts
|
|
1201
|
+
let installed = false;
|
|
1202
|
+
/**
|
|
1203
|
+
* Install the process-wide fatal crash handler. Idempotent: a second call is
|
|
1204
|
+
* a no-op, and later options (e.g. a memory provider registered once chat
|
|
1205
|
+
* boots) update the live handler in place.
|
|
1206
|
+
*
|
|
1207
|
+
* Disabled entirely by `SKYDIVE_NO_CRASH_REPORT` — the escape hatch, and how
|
|
1208
|
+
* tests keep a real handler off the shared process.
|
|
1209
|
+
*/
|
|
1210
|
+
function installCrashHandler(opts = {}) {
|
|
1211
|
+
if (process.env["SKYDIVE_NO_CRASH_REPORT"]) return;
|
|
1212
|
+
memoryProvider = opts.memoryProvider ?? memoryProvider;
|
|
1213
|
+
writeNotice = opts.writeNotice ?? writeNotice;
|
|
1214
|
+
exitProcess = opts.exit ?? exitProcess;
|
|
1215
|
+
if (installed) return;
|
|
1216
|
+
installed = true;
|
|
1217
|
+
process.on("uncaughtException", (error) => {
|
|
1218
|
+
const memory = safeMemory();
|
|
1219
|
+
printFatalNotice(writeCrashReport(buildCrashReport({
|
|
1220
|
+
reason: "uncaughtException",
|
|
1221
|
+
error,
|
|
1222
|
+
memory
|
|
1223
|
+
})), memory);
|
|
1224
|
+
exitProcess(1);
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1227
|
+
const defaultWriteNotice = (text) => process.stderr.write(text);
|
|
1228
|
+
const defaultExit = (code) => process.exit(code);
|
|
1229
|
+
let memoryProvider = null;
|
|
1230
|
+
let writeNotice = defaultWriteNotice;
|
|
1231
|
+
let exitProcess = defaultExit;
|
|
1232
|
+
function safeMemory() {
|
|
1233
|
+
try {
|
|
1234
|
+
return memoryProvider?.() ?? void 0;
|
|
1235
|
+
} catch (_error) {
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
function printFatalNotice(file, memory) {
|
|
1240
|
+
const peak = memory ? ` (peak memory ${formatMb(memory.peakRss)})` : "";
|
|
1241
|
+
if (file) writeNotice(`\nskydive: the CLI hit a fatal error${peak}. A diagnostic report was written to:\n ${file}\nPlease send this file to the Skydive team so we can investigate.\n`);
|
|
1242
|
+
else writeNotice(`\nskydive: the CLI hit a fatal error${peak}.\n`);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
//#endregion
|
|
1246
|
+
export { deleteConfig as A, resolveAppUrl as B, setActiveWorkspace as C, DEFAULT_API_URL as D, API_KEY_PREFIX as E, getSavedTheme as F, saveConfig as G, resolveManagementAuth as H, getShareMachineDefault as I, setLastSeenVersion as J, saveSession as K, getStoredApiKeyId as L, getLastSeenVersion as M, getPromptHistoryPath as N, DEFAULT_APP_URL as O, getReviewStateDir as P, getStoredApiKeyWorkspaceName as R, listWorkspaces as S, API_KEY_FAMILY_PREFIX as T, resolveSession as U, resolveConfig as V, resolveWebUrl as W, version$1 as X, name as Y, themes as _, WORDMARK as a, getActiveWorkspaceId as b, applyTheme as c, noColorRequested as d, theme as f, themeVersion as g, themeModeFromColorFgBg as h, MARK_CELLS as i, getConfigPath as j, DEFAULT_WEB_URL as k, findTheme as l, themeMode as m, buildCrashReport as n, brandHelpArt as o, themeForMode as p, saveTheme as q, writeCrashReport as r, DEFAULT_THEME_ID as s, installCrashHandler as t, monoTheme as u, themesForMode as v, API_KEYS_URL as w, getSessionIdentity as x, ensureActiveOrganization as y, getUpdateCheckDisabled as z };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, t as HttpError } from "./rest-
|
|
2
|
+
import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, t as HttpError } from "./rest-DMpigwmN.mjs";
|
|
3
3
|
import stableStringify from "safe-stable-stringify";
|
|
4
4
|
|
|
5
5
|
//#region src/chat/tui/chat/card.ts
|
|
@@ -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-DMpigwmN.mjs";
|
|
3
|
+
import { a as runPrint, i as resolveAgent, n as messageGet, o as toPrintError, r as readStdin, t as collectRunText } from "./print-6Bm51XhR.mjs";
|
|
4
4
|
|
|
5
5
|
export { messageGet, readStdin, resolveAgent, runPrint };
|
|
@@ -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-BRfmlbgI.mjs");
|
|
18
18
|
let signalConnected;
|
|
19
19
|
const connected = new Promise((resolve) => {
|
|
20
20
|
signalConnected = resolve;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { i as sendErrorMessage, n as createRestClient, r as errorDetail, t as HttpError } from "./rest-
|
|
2
|
+
import { i as sendErrorMessage, n as createRestClient, r as errorDetail, t as HttpError } from "./rest-DMpigwmN.mjs";
|
|
3
3
|
|
|
4
4
|
export { createRestClient };
|
|
@@ -226,7 +226,8 @@ function createRestClient({ appUrl, sessionToken }) {
|
|
|
226
226
|
const { agent } = await post(`/api/v1/agents/${encodeURIComponent(agentId)}`, { model }, updateAgentResponseSchema, "PATCH");
|
|
227
227
|
return { model: agent.model ?? null };
|
|
228
228
|
},
|
|
229
|
-
listConversations: async ({ agentId, limit, channels, archived, onPage }) => {
|
|
229
|
+
listConversations: async ({ agentId, limit, channels, archived, query, onPage }) => {
|
|
230
|
+
const trimmedQuery = query?.trim();
|
|
230
231
|
const all = [];
|
|
231
232
|
const maxConversations = limit ?? 5e3;
|
|
232
233
|
let cursor;
|
|
@@ -239,6 +240,7 @@ function createRestClient({ appUrl, sessionToken }) {
|
|
|
239
240
|
params.set("limit", String(Math.min(remaining, 100)));
|
|
240
241
|
if (cursor) params.set("cursor", cursor);
|
|
241
242
|
if (archived) params.set("archived", archived);
|
|
243
|
+
if (trimmedQuery) params.set("query", trimmedQuery);
|
|
242
244
|
for (const channel of channels ?? []) params.append("channels", channel);
|
|
243
245
|
const page = await get(`/api/v1/conversations?${params.toString()}`, listConversationsResponseSchema);
|
|
244
246
|
all.push(...page.conversations);
|
package/package.json
CHANGED