skydive-cli 0.5.0-beta.14 → 0.5.0-beta.16
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/bin.mjs +7 -7
- package/dist/js/{boot-CJKq8rvL.mjs → boot-MnSkqFnR.mjs} +195 -69
- package/dist/js/{daemon-DjsUMczp.mjs → daemon-DPWYOa1E.mjs} +1 -1
- package/dist/js/{daemon-CL25CwjW.mjs → daemon-OlciVTBj.mjs} +1 -1
- package/dist/js/{daemon-client-k8ICifN2.mjs → daemon-client-Bue4JMhq.mjs} +1 -1
- package/dist/js/daemon-client-CtLwJOvc.mjs +7 -0
- package/dist/js/{profiler-COGO4LN8.mjs → profiler-DXusZ2OB.mjs} +14 -3
- package/package.json +1 -1
- package/dist/js/daemon-client-DEyOdfdA.mjs +0 -7
package/dist/js/bin.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { A as version, D as listWorkspaces, E as getSessionIdentity, O as setActiveWorkspace, S as themes, T as getActiveWorkspaceId, a as installCrashHandler, k as name, t as maybeStartProfiling, u as brandHelpArt, w as ensureActiveOrganization } from "./profiler-DXusZ2OB.mjs";
|
|
3
3
|
import { A as getStoredApiKeyId, B as saveConfig, C as getDefaultAgent, E as getPromptHistoryPath, F as resolveChatAuth, I as resolveConfig, L as resolveManagementAuth, M as getUpdateCheckDisabled, P as resolveAppUrl, R as resolveSession, S as getConfigPath, T as getPreference, U as setLastSeenVersion, V as saveSession, _ as API_KEY_PREFIX, b as PREFERENCES, g as API_KEY_FAMILY_PREFIX, h as API_KEYS_URL, i as resolveAgent, j as getStoredApiKeyWorkspaceName, k as getShareMachineDefault, v as DEFAULT_API_URL, w as getLastSeenVersion, x as deleteConfig } from "./print-riiY5Gly.mjs";
|
|
4
4
|
import { n as printError, r as printTable, t as output } from "./output-DYzzdXYV.mjs";
|
|
5
5
|
import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
|
|
6
6
|
import { t as createRestClient } from "./rest-CLrHVkxh.mjs";
|
|
7
7
|
import "./billing-blocked-2wju4gC_.mjs";
|
|
8
8
|
import { r as resolveMachineIdentity } from "./client-DbqRBquD.mjs";
|
|
9
|
-
import { i as queryDaemonStatus, l as PORTAL_DAEMON_FLAG, n as ensureDaemonRunning, s as stopDaemon, u as daemonPaths } from "./daemon-
|
|
9
|
+
import { i as queryDaemonStatus, l as PORTAL_DAEMON_FLAG, n as ensureDaemonRunning, s as stopDaemon, u as daemonPaths } from "./daemon-OlciVTBj.mjs";
|
|
10
10
|
import { i as grantPortalAccess, n as fetchPortalDevices, o as registerPortalDevice, r as findThisDevice, s as revokePortalAccess } from "./api-DG5W6iwx.mjs";
|
|
11
11
|
import { t as SandboxStream } from "./client-c4c5MmgN.mjs";
|
|
12
12
|
import { hideBin } from "yargs/helpers";
|
|
@@ -1517,7 +1517,7 @@ const importCommand = {
|
|
|
1517
1517
|
process.exit(1);
|
|
1518
1518
|
}
|
|
1519
1519
|
}
|
|
1520
|
-
const { runChat } = await import("./boot-
|
|
1520
|
+
const { runChat } = await import("./boot-MnSkqFnR.mjs");
|
|
1521
1521
|
await runChat({
|
|
1522
1522
|
appUrl,
|
|
1523
1523
|
sessionToken: session.value.sessionToken,
|
|
@@ -1930,7 +1930,7 @@ const chatCommand = {
|
|
|
1930
1930
|
sessionToken: auth.value.token,
|
|
1931
1931
|
agentSelector: argv.agent ?? null
|
|
1932
1932
|
});
|
|
1933
|
-
const { runChat } = await import("./boot-
|
|
1933
|
+
const { runChat } = await import("./boot-MnSkqFnR.mjs");
|
|
1934
1934
|
await runChat({
|
|
1935
1935
|
appUrl: auth.value.appUrl,
|
|
1936
1936
|
sessionToken: auth.value.token,
|
|
@@ -2290,7 +2290,7 @@ const switchCommand = {
|
|
|
2290
2290
|
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.");
|
|
2291
2291
|
process.exit(1);
|
|
2292
2292
|
}
|
|
2293
|
-
const { runWorkspacePicker } = await import("./boot-
|
|
2293
|
+
const { runWorkspacePicker } = await import("./boot-MnSkqFnR.mjs");
|
|
2294
2294
|
await runWorkspacePicker(session);
|
|
2295
2295
|
return;
|
|
2296
2296
|
}
|
|
@@ -2369,7 +2369,7 @@ const openCommand = {
|
|
|
2369
2369
|
const agent = argv.agent ? resolveAgent((await fetchPortalDevices(session)).agents, argv.agent) : null;
|
|
2370
2370
|
const cwd = argv.cwd ? path.resolve(argv.cwd) : process.cwd();
|
|
2371
2371
|
const { machineName } = await resolveMachineIdentity(null);
|
|
2372
|
-
const { PortalDaemonClient } = await import("./daemon-client-
|
|
2372
|
+
const { PortalDaemonClient } = await import("./daemon-client-CtLwJOvc.mjs");
|
|
2373
2373
|
let lastLine = "";
|
|
2374
2374
|
let signalConnected;
|
|
2375
2375
|
const connected = new Promise((resolve) => {
|
|
@@ -4215,7 +4215,7 @@ if (process.argv.includes(UPDATE_WORKER_FLAG)) {
|
|
|
4215
4215
|
process.exit(0);
|
|
4216
4216
|
}
|
|
4217
4217
|
if (process.argv.includes(PORTAL_DAEMON_FLAG)) {
|
|
4218
|
-
const { runPortalDaemon } = await import("./daemon-
|
|
4218
|
+
const { runPortalDaemon } = await import("./daemon-DPWYOa1E.mjs");
|
|
4219
4219
|
runPortalDaemon(process.argv);
|
|
4220
4220
|
} else runCli();
|
|
4221
4221
|
function runCli() {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { C as themesForMode, D as listWorkspaces, O as setActiveWorkspace, T as getActiveWorkspaceId, _ as theme, a as installCrashHandler, b as themeModeFromColorFgBg, c as MARK_CELLS, d as splashFitsWidth, f as DEFAULT_THEME_ID, g as noColorRequested, h as monoTheme, i as writeArtifact, l as WORDMARK, m as findTheme, n as profilingEnabled, o as buildCrashReport, p as applyTheme, r as record, s as writeCrashReport, v as themeForMode, x as themeVersion, y as themeMode } from "./profiler-DXusZ2OB.mjs";
|
|
3
3
|
import { D as getReviewStateDir, H as saveTheme, N as recordDefaultAgent, O as getSavedTheme, S as getConfigPath, 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, v as DEFAULT_API_URL, y as DEFAULT_APP_URL, z as resolveWebUrl } from "./print-riiY5Gly.mjs";
|
|
4
4
|
import { t as HttpError } from "./http-error-DzyrsLAZ.mjs";
|
|
5
5
|
import { a as isRecord, i as errorMessage, n as errorDetail, r as sendErrorMessage, t as createRestClient } from "./rest-CLrHVkxh.mjs";
|
|
6
6
|
import { i as billingBlockedOutcomeFromSendResponse } from "./billing-blocked-2wju4gC_.mjs";
|
|
7
7
|
import { t as PortalClient } from "./client-DbqRBquD.mjs";
|
|
8
|
-
import "./daemon-
|
|
8
|
+
import "./daemon-OlciVTBj.mjs";
|
|
9
9
|
import "./api-DG5W6iwx.mjs";
|
|
10
10
|
import { t as SandboxStream } from "./client-c4c5MmgN.mjs";
|
|
11
|
-
import { t as PortalDaemonClient } from "./daemon-client-
|
|
11
|
+
import { t as PortalDaemonClient } from "./daemon-client-Bue4JMhq.mjs";
|
|
12
12
|
import { t as runRawPtyPassthrough } from "./raw-pty-DY4KelZW.mjs";
|
|
13
13
|
import * as os$1 from "node:os";
|
|
14
14
|
import { homedir, platform, release, tmpdir } from "node:os";
|
|
@@ -1080,42 +1080,133 @@ function createAgentHost({ renderer, notifications }) {
|
|
|
1080
1080
|
* take the one host we can identify unambiguously (github.com, incl. `www.`),
|
|
1081
1081
|
* which covers the common product case; GHES stays the native badge's job.
|
|
1082
1082
|
*
|
|
1083
|
-
* Only the `/pull/<n>` form (not `/issues
|
|
1084
|
-
*
|
|
1085
|
-
*
|
|
1086
|
-
*
|
|
1087
|
-
*
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
*
|
|
1092
|
-
*
|
|
1093
|
-
*
|
|
1094
|
-
*
|
|
1095
|
-
*
|
|
1096
|
-
*
|
|
1097
|
-
*/
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1083
|
+
* Only the `/pull/<n>` form (not `/issues/`). A trailing path/query/fragment
|
|
1084
|
+
* (e.g. `/files`, `#discussion`) is allowed but not captured into the canonical
|
|
1085
|
+
* URL. Also matches inside markdown links, backticks, and trailing punctuation.
|
|
1086
|
+
*
|
|
1087
|
+
* The `https://` (and `www.`) prefix is optional: agents and people routinely
|
|
1088
|
+
* write a bare `github.com/o/r/pull/7`, and that should link a PR the same way
|
|
1089
|
+
* the full URL does. To keep a bare host from matching inside a longer hostname
|
|
1090
|
+
* (`mygithub.com/...`, `notgithub.com/...`), a protocol-less match must be
|
|
1091
|
+
* preceded by a start-of-string or a non-host character (anything but a word
|
|
1092
|
+
* char or `.`) — a leading boundary the `(?:^|[^\w.])` group asserts and
|
|
1093
|
+
* consumes. The consumed boundary char is outside the captured groups, so it
|
|
1094
|
+
* never leaks into owner/repo. `matchAll` won't overlap, but the boundary is a
|
|
1095
|
+
* single delimiter (space, `(`, `[`, etc.) between PRs in practice, so distinct
|
|
1096
|
+
* back-to-back URLs still each match.
|
|
1097
|
+
*/
|
|
1098
|
+
const PR_URL_RE = /(?:^|[^\w.])(?:https?:\/\/)?(?:www\.)?github\.com\/([\w.-]+)\/([\w.-]+)\/pull\/(\d+)/gi;
|
|
1099
|
+
/**
|
|
1100
|
+
* Matches a bare, human-style PR reference `#<n>` — the way people (and LLMs)
|
|
1101
|
+
* name a PR in prose ("opened #20858", "landed #42"). Requires a non-word
|
|
1102
|
+
* boundary before the `#` so a fragment tail like `/pull/7#discussion_r5` or a
|
|
1103
|
+
* hex color `#20858` embedded in a word doesn't count, and captures the digits
|
|
1104
|
+
* up to a word boundary. We only harvest these from **assistant prose**, never
|
|
1105
|
+
* from tool output, because `#N` is exactly the relevance signal we're after:
|
|
1106
|
+
* the agent chose to talk about this PR.
|
|
1107
|
+
*/
|
|
1108
|
+
const PR_HASH_RE = /(?:^|[^\w#/])#(\d+)\b/g;
|
|
1109
|
+
/**
|
|
1110
|
+
* Every full `/pull/<n>` github.com URL in `urlText`, keyed by number to the
|
|
1111
|
+
* candidate refs for that number. A number can map to more than one repo, so we
|
|
1112
|
+
* keep all candidates; a bare `#N` label can't say which repo, but the pill's
|
|
1113
|
+
* own URL does. Deduped by repo-qualified identity (`owner/repo#number`) so the
|
|
1114
|
+
* same PR linked twice — even with a different trailing path/fragment —
|
|
1115
|
+
* collapses to one ref.
|
|
1116
|
+
*
|
|
1117
|
+
* `deferTrailingNumber` guards the streaming truncation case: when true, a URL
|
|
1118
|
+
* whose number runs to the very end of `urlText` is skipped because the next
|
|
1119
|
+
* delta may extend those digits (`.../pull/19` now, `.../pull/19739` later).
|
|
1120
|
+
* Only the still-growing PROSE buffer sets this; settled tool output is always
|
|
1121
|
+
* complete, so its URLs are harvested with the guard off.
|
|
1122
|
+
*/
|
|
1123
|
+
function urlsByNumber(urlText, deferTrailingNumber, byNumber) {
|
|
1124
|
+
for (const match of urlText.matchAll(PR_URL_RE)) {
|
|
1102
1125
|
const owner = match[1];
|
|
1103
1126
|
const repo = match[2];
|
|
1104
1127
|
const numberText = match[3];
|
|
1105
1128
|
if (!owner || !repo || !numberText) continue;
|
|
1106
|
-
if (
|
|
1107
|
-
if (match.index + match[0].length >=
|
|
1129
|
+
if (deferTrailingNumber) {
|
|
1130
|
+
if (match.index + match[0].length >= urlText.length) continue;
|
|
1108
1131
|
}
|
|
1109
1132
|
const number = Number.parseInt(numberText, 10);
|
|
1110
1133
|
if (!Number.isFinite(number) || number <= 0) continue;
|
|
1111
|
-
const
|
|
1112
|
-
if (byKey.has(key)) continue;
|
|
1113
|
-
byKey.set(key, {
|
|
1134
|
+
const ref = {
|
|
1114
1135
|
number,
|
|
1115
|
-
key
|
|
1136
|
+
key: `${owner.toLowerCase()}/${repo.toLowerCase()}#${number}`,
|
|
1116
1137
|
url: `https://github.com/${owner}/${repo}/pull/${number}`
|
|
1117
|
-
}
|
|
1138
|
+
};
|
|
1139
|
+
const existing = byNumber.get(number);
|
|
1140
|
+
if (existing) {
|
|
1141
|
+
if (!existing.some((r) => r.key === ref.key)) existing.push(ref);
|
|
1142
|
+
} else byNumber.set(number, [ref]);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
/** Every human-style `#N` named in `proseText` — the relevance signal. */
|
|
1146
|
+
function hashNumbers(proseText) {
|
|
1147
|
+
const numbers = /* @__PURE__ */ new Set();
|
|
1148
|
+
for (const match of proseText.matchAll(PR_HASH_RE)) {
|
|
1149
|
+
const numberText = match[1];
|
|
1150
|
+
if (!numberText) continue;
|
|
1151
|
+
const number = Number.parseInt(numberText, 10);
|
|
1152
|
+
if (Number.isFinite(number) && number > 0) numbers.add(number);
|
|
1153
|
+
}
|
|
1154
|
+
return numbers;
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* The relevance contract, in one place.
|
|
1158
|
+
*
|
|
1159
|
+
* A GitHub PR URL is cheap to emit and shows up in bulk any time a tool dumps
|
|
1160
|
+
* PRs the conversation isn't actually about — `gh pr list`, `gh pr status`, a
|
|
1161
|
+
* `gh search` — printing dozens of `/pull/N` URLs the agent never discusses.
|
|
1162
|
+
* Pinning a sidebar pill for every one of those is noise.
|
|
1163
|
+
*
|
|
1164
|
+
* So a PR is surfaced only when BOTH hold:
|
|
1165
|
+
* 1. a fully-qualified `github.com/<o>/<r>/pull/<n>` URL exists — this may
|
|
1166
|
+
* come from the assistant's prose OR from tool output (a `gh pr create`
|
|
1167
|
+
* that printed the URL the agent then referenced by number), and
|
|
1168
|
+
* 2. the **assistant's prose** names the number as a human-style `#<n>`.
|
|
1169
|
+
*
|
|
1170
|
+
* The `#N` in prose is the intent signal — "the agent is talking about this
|
|
1171
|
+
* PR", as opposed to "a tool happened to list it". The full URL (from wherever)
|
|
1172
|
+
* proves the PR is real and pins down its repo + canonical link. A URL with no
|
|
1173
|
+
* `#N` in prose (the whole of a `gh pr list` dump) is dropped; a `#N` with no
|
|
1174
|
+
* matching URL anywhere (a bare issue-style ref) is dropped.
|
|
1175
|
+
*
|
|
1176
|
+
* `proseText` is the assistant's prose alone (the only source of the `#N`
|
|
1177
|
+
* relevance signal); `urlOnlyText` is settled tool output that may carry full
|
|
1178
|
+
* PR URLs but no `#N` intent. URLs are harvested from both; `#N` from prose
|
|
1179
|
+
* only.
|
|
1180
|
+
*/
|
|
1181
|
+
function collectRelevant(proseText, urlOnlyText, options, byKey) {
|
|
1182
|
+
const byNumber = /* @__PURE__ */ new Map();
|
|
1183
|
+
urlsByNumber(proseText, options.requireCompleteNumber, byNumber);
|
|
1184
|
+
if (urlOnlyText) urlsByNumber(urlOnlyText, false, byNumber);
|
|
1185
|
+
if (byNumber.size === 0) return;
|
|
1186
|
+
const named = hashNumbers(proseText);
|
|
1187
|
+
if (named.size === 0) return;
|
|
1188
|
+
for (const [number, refs] of byNumber) {
|
|
1189
|
+
if (!named.has(number)) continue;
|
|
1190
|
+
for (const ref of refs) if (!byKey.has(ref.key)) byKey.set(ref.key, ref);
|
|
1118
1191
|
}
|
|
1192
|
+
}
|
|
1193
|
+
/**
|
|
1194
|
+
* Extracts every distinct GitHub PR that is both linked (a full `/pull/<n>`
|
|
1195
|
+
* URL) AND named (`#<n>`), de-duplicated by **repo-qualified identity**
|
|
1196
|
+
* (`owner/repo#number`) — NOT by number, since `#42` can exist in many repos.
|
|
1197
|
+
*
|
|
1198
|
+
* The two-argument form takes the URL pool and the prose separately, so a URL
|
|
1199
|
+
* from tool output can satisfy the link requirement while the `#N` stays a
|
|
1200
|
+
* prose-only signal. The one-argument form (prose only) is the common case: it
|
|
1201
|
+
* requires the URL to be in the same prose that names it.
|
|
1202
|
+
*
|
|
1203
|
+
* See {@link collectRelevant} for the contract.
|
|
1204
|
+
*/
|
|
1205
|
+
function extractPullRequests(proseText, options) {
|
|
1206
|
+
const requireCompleteNumber = options?.requireCompleteNumber ?? true;
|
|
1207
|
+
const urlOnly = options?.urlOnlyText ?? "";
|
|
1208
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
1209
|
+
collectRelevant(proseText, urlOnly, { requireCompleteNumber }, byKey);
|
|
1119
1210
|
return [...byKey.values()];
|
|
1120
1211
|
}
|
|
1121
1212
|
/**
|
|
@@ -1154,28 +1245,34 @@ function stringifyToolOutput(value) {
|
|
|
1154
1245
|
}
|
|
1155
1246
|
/**
|
|
1156
1247
|
* A streaming PR scanner: fed run chunks as they stream, it reports each
|
|
1157
|
-
* distinct PR the moment
|
|
1158
|
-
* the
|
|
1248
|
+
* distinct PR the moment BOTH conditions hold — a full `/pull/<n>` URL has been
|
|
1249
|
+
* seen (in prose OR tool output) AND the assistant's prose names it `#<n>` —
|
|
1250
|
+
* exactly once, without ever rescanning the transcript.
|
|
1159
1251
|
*
|
|
1160
|
-
*
|
|
1161
|
-
*
|
|
1162
|
-
*
|
|
1163
|
-
*
|
|
1164
|
-
*
|
|
1165
|
-
*
|
|
1166
|
-
*
|
|
1252
|
+
* Two sources feed it, with different roles:
|
|
1253
|
+
* - **Assistant text** (`text-delta`): the ONLY source of the `#N` relevance
|
|
1254
|
+
* signal, and also a source of URLs. Accumulated per part id (a URL or `#N`
|
|
1255
|
+
* can split across two deltas); only the current part's buffer is scanned.
|
|
1256
|
+
* - **Tool output** (`tool-output-available`): a URL-only source. A
|
|
1257
|
+
* `gh pr create` prints the URL the agent then references by number, so the
|
|
1258
|
+
* URL for a #N mention often lives here, not in the prose. Tool output can
|
|
1259
|
+
* NEVER originate a pill on its own — a `gh pr list` dump (URLs, no `#N`)
|
|
1260
|
+
* stays silent — but it satisfies the URL half for a PR the prose names.
|
|
1167
1261
|
*
|
|
1168
1262
|
* `onPullRequest` fires once per never-before-seen PR (keyed by
|
|
1169
|
-
* `owner/repo#number`)
|
|
1170
|
-
*
|
|
1171
|
-
* same chunks the transcript reducer sees.
|
|
1263
|
+
* `owner/repo#number`). Construct one per run (or per conversation) and feed it
|
|
1264
|
+
* the same chunks the transcript reducer sees. See {@link collectRelevant}.
|
|
1172
1265
|
*/
|
|
1173
1266
|
function createPullRequestScanner(onPullRequest) {
|
|
1174
1267
|
let text = "";
|
|
1175
1268
|
let lastPartId;
|
|
1269
|
+
let toolUrlText = "";
|
|
1176
1270
|
const seen = /* @__PURE__ */ new Set();
|
|
1177
|
-
const report = (
|
|
1178
|
-
for (const pr of extractPullRequests(
|
|
1271
|
+
const report = (final) => {
|
|
1272
|
+
for (const pr of extractPullRequests(text, {
|
|
1273
|
+
requireCompleteNumber: !final,
|
|
1274
|
+
urlOnlyText: toolUrlText
|
|
1275
|
+
})) {
|
|
1179
1276
|
if (seen.has(pr.key)) continue;
|
|
1180
1277
|
seen.add(pr.key);
|
|
1181
1278
|
onPullRequest(pr);
|
|
@@ -1185,7 +1282,8 @@ function createPullRequestScanner(onPullRequest) {
|
|
|
1185
1282
|
if (chunk["type"] === "tool-output-available") {
|
|
1186
1283
|
const outputText = stringifyToolOutput(chunk["output"]);
|
|
1187
1284
|
if (!outputText.includes("/pull/")) return;
|
|
1188
|
-
|
|
1285
|
+
toolUrlText += `\n${outputText}`;
|
|
1286
|
+
report(true);
|
|
1189
1287
|
return;
|
|
1190
1288
|
}
|
|
1191
1289
|
if (chunk["type"] !== "text-delta") return;
|
|
@@ -1193,13 +1291,12 @@ function createPullRequestScanner(onPullRequest) {
|
|
|
1193
1291
|
if (!delta) return;
|
|
1194
1292
|
const partId = typeof chunk["id"] === "string" ? chunk["id"] : void 0;
|
|
1195
1293
|
if (partId && lastPartId && partId !== lastPartId) {
|
|
1196
|
-
|
|
1294
|
+
report(true);
|
|
1197
1295
|
text = "";
|
|
1198
1296
|
}
|
|
1199
1297
|
text += delta;
|
|
1200
1298
|
lastPartId = partId ?? lastPartId;
|
|
1201
|
-
|
|
1202
|
-
report(text, false);
|
|
1299
|
+
report(false);
|
|
1203
1300
|
} };
|
|
1204
1301
|
}
|
|
1205
1302
|
|
|
@@ -1713,13 +1810,15 @@ function WordmarkRows({ mono }) {
|
|
|
1713
1810
|
});
|
|
1714
1811
|
}
|
|
1715
1812
|
/**
|
|
1716
|
-
* Height-aware brand header for the pickers. Always shown
|
|
1717
|
-
* list is loading / empty / erroring) so the splash is
|
|
1718
|
-
* Full mark + wordmark when the terminal is tall
|
|
1719
|
-
*
|
|
1813
|
+
* Height- and width-aware brand header for the pickers. Always shown
|
|
1814
|
+
* (including while the list is loading / empty / erroring) so the splash is
|
|
1815
|
+
* never gated on data. Full mark + wordmark only when the terminal is tall
|
|
1816
|
+
* enough AND wide enough that the art sits on six lines; otherwise a compact
|
|
1817
|
+
* one-liner. Wrapping the splash would blow the 7-row budget the list
|
|
1818
|
+
* subtracts, and the overflow collapses the top list rows onto each other.
|
|
1720
1819
|
*/
|
|
1721
|
-
function BrandHeader({ height }) {
|
|
1722
|
-
if (height
|
|
1820
|
+
function BrandHeader({ height, width }) {
|
|
1821
|
+
if (showFullSplash(height, width)) return /* @__PURE__ */ jsxs("box", {
|
|
1723
1822
|
style: { flexDirection: "column" },
|
|
1724
1823
|
children: [/* @__PURE__ */ jsx(SkydiveMark, { variant: "full" }), /* @__PURE__ */ jsx("box", { style: { height: 1 } })]
|
|
1725
1824
|
});
|
|
@@ -1728,9 +1827,12 @@ function BrandHeader({ height }) {
|
|
|
1728
1827
|
children: "✦ Skydive"
|
|
1729
1828
|
});
|
|
1730
1829
|
}
|
|
1830
|
+
function showFullSplash(height, width) {
|
|
1831
|
+
return height >= 24 && splashFitsWidth(width);
|
|
1832
|
+
}
|
|
1731
1833
|
/** Row budget the BrandHeader consumes; callers subtract this from visibleRows. */
|
|
1732
|
-
function brandHeaderRows(height) {
|
|
1733
|
-
return height
|
|
1834
|
+
function brandHeaderRows(height, width) {
|
|
1835
|
+
return showFullSplash(height, width) ? 7 : 1;
|
|
1734
1836
|
}
|
|
1735
1837
|
function SkydiveMark({ variant = "full" }) {
|
|
1736
1838
|
const mono = noColor();
|
|
@@ -1817,13 +1919,16 @@ function AgentPickerScreen() {
|
|
|
1817
1919
|
scope,
|
|
1818
1920
|
cache
|
|
1819
1921
|
]);
|
|
1820
|
-
const { height } = useTerminalDimensions();
|
|
1922
|
+
const { width, height } = useTerminalDimensions();
|
|
1821
1923
|
if (state.kind === "loading") return /* @__PURE__ */ jsxs("box", {
|
|
1822
1924
|
style: {
|
|
1823
1925
|
flexDirection: "column",
|
|
1824
1926
|
flexGrow: 1
|
|
1825
1927
|
},
|
|
1826
|
-
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1928
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1929
|
+
height,
|
|
1930
|
+
width
|
|
1931
|
+
}), /* @__PURE__ */ jsx("text", {
|
|
1827
1932
|
fg: theme.muted,
|
|
1828
1933
|
children: "loading agents…"
|
|
1829
1934
|
})]
|
|
@@ -1833,7 +1938,10 @@ function AgentPickerScreen() {
|
|
|
1833
1938
|
flexDirection: "column",
|
|
1834
1939
|
flexGrow: 1
|
|
1835
1940
|
},
|
|
1836
|
-
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1941
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1942
|
+
height,
|
|
1943
|
+
width
|
|
1944
|
+
}), /* @__PURE__ */ jsxs("text", {
|
|
1837
1945
|
fg: theme.error,
|
|
1838
1946
|
children: ["error: ", state.message]
|
|
1839
1947
|
})]
|
|
@@ -1843,7 +1951,10 @@ function AgentPickerScreen() {
|
|
|
1843
1951
|
flexDirection: "column",
|
|
1844
1952
|
flexGrow: 1
|
|
1845
1953
|
},
|
|
1846
|
-
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1954
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
1955
|
+
height,
|
|
1956
|
+
width
|
|
1957
|
+
}), /* @__PURE__ */ jsx("text", {
|
|
1847
1958
|
fg: theme.muted,
|
|
1848
1959
|
children: scope === "mine" ? "no agents of yours yet. press tab to see all agents, ctrl+w to switch workspace, or ctrl+n to create one." : "no agents in this workspace. press ctrl+w to switch workspace, or ctrl+n to create one."
|
|
1849
1960
|
})]
|
|
@@ -1864,7 +1975,7 @@ function FilterableAgentList({ agents, scope, onPick }) {
|
|
|
1864
1975
|
const hits = fuzzyFilter(query, agents, agentKeys);
|
|
1865
1976
|
const filtered = hits.map((h) => h.item);
|
|
1866
1977
|
const clamped = Math.min(highlight, Math.max(0, filtered.length - 1));
|
|
1867
|
-
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height));
|
|
1978
|
+
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height, width));
|
|
1868
1979
|
const start = windowStart(clamped, filtered.length, visibleRows);
|
|
1869
1980
|
const windowed = hits.slice(start, start + visibleRows);
|
|
1870
1981
|
useKeyboard((key) => {
|
|
@@ -1896,7 +2007,10 @@ function FilterableAgentList({ agents, scope, onPick }) {
|
|
|
1896
2007
|
flexGrow: 1
|
|
1897
2008
|
},
|
|
1898
2009
|
children: [
|
|
1899
|
-
/* @__PURE__ */ jsx(BrandHeader, {
|
|
2010
|
+
/* @__PURE__ */ jsx(BrandHeader, {
|
|
2011
|
+
height,
|
|
2012
|
+
width
|
|
2013
|
+
}),
|
|
1900
2014
|
/* @__PURE__ */ jsxs("box", {
|
|
1901
2015
|
style: {
|
|
1902
2016
|
flexDirection: "row",
|
|
@@ -2556,13 +2670,16 @@ function ConversationPickerScreen({ agent }) {
|
|
|
2556
2670
|
cacheKey,
|
|
2557
2671
|
cache
|
|
2558
2672
|
]);
|
|
2559
|
-
const { height } = useTerminalDimensions();
|
|
2673
|
+
const { width, height } = useTerminalDimensions();
|
|
2560
2674
|
if (state.kind === "loading") return /* @__PURE__ */ jsxs("box", {
|
|
2561
2675
|
style: {
|
|
2562
2676
|
flexDirection: "column",
|
|
2563
2677
|
flexGrow: 1
|
|
2564
2678
|
},
|
|
2565
|
-
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
2679
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
2680
|
+
height,
|
|
2681
|
+
width
|
|
2682
|
+
}), /* @__PURE__ */ jsx("text", {
|
|
2566
2683
|
fg: theme.muted,
|
|
2567
2684
|
children: "loading conversations…"
|
|
2568
2685
|
})]
|
|
@@ -2572,7 +2689,10 @@ function ConversationPickerScreen({ agent }) {
|
|
|
2572
2689
|
flexDirection: "column",
|
|
2573
2690
|
flexGrow: 1
|
|
2574
2691
|
},
|
|
2575
|
-
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
2692
|
+
children: [/* @__PURE__ */ jsx(BrandHeader, {
|
|
2693
|
+
height,
|
|
2694
|
+
width
|
|
2695
|
+
}), /* @__PURE__ */ jsxs("text", {
|
|
2576
2696
|
fg: theme.error,
|
|
2577
2697
|
children: ["error: ", state.message]
|
|
2578
2698
|
})]
|
|
@@ -2701,7 +2821,7 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
2701
2821
|
"↵ open"
|
|
2702
2822
|
], innerWidth)
|
|
2703
2823
|
};
|
|
2704
|
-
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height));
|
|
2824
|
+
const visibleRows = Math.max(3, height - 6 - brandHeaderRows(height, width));
|
|
2705
2825
|
const start = windowStart(clamped, rows.length, visibleRows);
|
|
2706
2826
|
const windowed = rows.slice(start, start + visibleRows);
|
|
2707
2827
|
const open = (row) => {
|
|
@@ -2802,7 +2922,10 @@ function ConversationList({ agent, conversations, complete, showAutomated, onTog
|
|
|
2802
2922
|
flexGrow: 1
|
|
2803
2923
|
},
|
|
2804
2924
|
children: [
|
|
2805
|
-
/* @__PURE__ */ jsx(BrandHeader, {
|
|
2925
|
+
/* @__PURE__ */ jsx(BrandHeader, {
|
|
2926
|
+
height,
|
|
2927
|
+
width
|
|
2928
|
+
}),
|
|
2806
2929
|
/* @__PURE__ */ jsxs("box", {
|
|
2807
2930
|
style: {
|
|
2808
2931
|
flexDirection: "row",
|
|
@@ -10886,10 +11009,13 @@ function ChatScreen({ agent, conversation }) {
|
|
|
10886
11009
|
text: recapText
|
|
10887
11010
|
});
|
|
10888
11011
|
setItems(loaded);
|
|
11012
|
+
const toolUrlText = loaded.map((item) => item.kind === "tool" && item.output?.kind === "ok" ? stringifyToolOutput(item.output.value) : "").join("\n");
|
|
10889
11013
|
for (const item of loaded) {
|
|
10890
|
-
|
|
10891
|
-
|
|
10892
|
-
|
|
11014
|
+
if (item.kind !== "assistant-text") continue;
|
|
11015
|
+
for (const pr of extractPullRequests(item.text, {
|
|
11016
|
+
requireCompleteNumber: false,
|
|
11017
|
+
urlOnlyText: toolUrlText
|
|
11018
|
+
})) {
|
|
10893
11019
|
if (reportedPrsRef.current.has(pr.key)) continue;
|
|
10894
11020
|
reportedPrsRef.current.set(pr.key, pr);
|
|
10895
11021
|
setPrLinks((prev) => [...prev, pr]);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import "./client-DbqRBquD.mjs";
|
|
3
|
-
import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-
|
|
3
|
+
import { a as runPortalDaemon, i as queryDaemonStatus, n as ensureDaemonRunning, o as startPortalDaemon, r as isDaemonListening, s as stopDaemon, t as PortalDaemon } from "./daemon-OlciVTBj.mjs";
|
|
4
4
|
import "./api-DG5W6iwx.mjs";
|
|
5
5
|
|
|
6
6
|
export { runPortalDaemon };
|
|
@@ -20,7 +20,7 @@ import { access, appendFile, mkdir, readFile, unlink, writeFile } from "node:fs/
|
|
|
20
20
|
* the commit time of the built tree is one monotonic clock they share.
|
|
21
21
|
*/
|
|
22
22
|
function portalDaemonBuild() {
|
|
23
|
-
return "
|
|
23
|
+
return "1786633773";
|
|
24
24
|
}
|
|
25
25
|
/**
|
|
26
26
|
* Whether a client carrying `mine` should replace a running daemon carrying
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { c as LOCAL_PROTOCOL_VERSION, d as encodeLine, f as makeLineParser, n as ensureDaemonRunning, p as parseDaemonMessage, u as daemonPaths } from "./daemon-
|
|
2
|
+
import { c as LOCAL_PROTOCOL_VERSION, d as encodeLine, f as makeLineParser, n as ensureDaemonRunning, p as parseDaemonMessage, u as daemonPaths } from "./daemon-OlciVTBj.mjs";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { connect } from "node:net";
|
|
5
5
|
|
|
@@ -8,7 +8,7 @@ import fs from "node:fs";
|
|
|
8
8
|
|
|
9
9
|
//#region package.json
|
|
10
10
|
var name = "skydive-cli";
|
|
11
|
-
var version$1 = "0.5.0-beta.
|
|
11
|
+
var version$1 = "0.5.0-beta.16";
|
|
12
12
|
|
|
13
13
|
//#endregion
|
|
14
14
|
//#region src/auth/organization.ts
|
|
@@ -907,6 +907,17 @@ const WORDMARK = [
|
|
|
907
907
|
"███████║██║ ██╗ ██║ ██████╔╝██║ ╚████╔╝ ███████╗",
|
|
908
908
|
"╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══╝ ╚══════╝"
|
|
909
909
|
];
|
|
910
|
+
/** Columns between the pinwheel and the wordmark. */
|
|
911
|
+
const SPLASH_GAP = 3;
|
|
912
|
+
/** Columns the full mark + wordmark occupies (no chrome). */
|
|
913
|
+
const SPLASH_WIDTH = MARK_WIDTH + SPLASH_GAP + WORDMARK.reduce((max, line) => Math.max(max, line.length), 0);
|
|
914
|
+
/** Extra columns around the splash: `skydive --help` indents by 2, the TUI
|
|
915
|
+
* app pads 1 on each side. Same number, so one threshold covers both. */
|
|
916
|
+
const SPLASH_CHROME = 2;
|
|
917
|
+
/** Whether the full splash fits on one line of `columns` without wrapping. */
|
|
918
|
+
function splashFitsWidth(columns) {
|
|
919
|
+
return columns >= SPLASH_WIDTH + SPLASH_CHROME;
|
|
920
|
+
}
|
|
910
921
|
const RESET = "\x1B[0m";
|
|
911
922
|
function hexToRgb(hex) {
|
|
912
923
|
const n = Number.parseInt(hex.slice(1), 16);
|
|
@@ -933,7 +944,7 @@ function markLinesAnsi() {
|
|
|
933
944
|
function brandHelpArt(stream = process.stdout) {
|
|
934
945
|
if (!stream.isTTY) return "";
|
|
935
946
|
const truecolor = (typeof stream.getColorDepth === "function" ? stream.getColorDepth() : 1) >= 24;
|
|
936
|
-
if ((stream.columns ?? 80)
|
|
947
|
+
if (!splashFitsWidth(stream.columns ?? 80)) return truecolor ? `\n ${sgr("✦", BRAND_ACCENT)} Skydive\n` : "\n ✦ Skydive\n";
|
|
937
948
|
if (!truecolor) return `\n${WORDMARK.map((l) => ` ${l}`).join("\n")}\n`;
|
|
938
949
|
const mark = markLinesAnsi();
|
|
939
950
|
const word = [...WORDMARK];
|
|
@@ -1264,4 +1275,4 @@ function maybeStartProfiling(argv, cliVersion) {
|
|
|
1264
1275
|
}
|
|
1265
1276
|
|
|
1266
1277
|
//#endregion
|
|
1267
|
-
export {
|
|
1278
|
+
export { version$1 as A, themesForMode as C, listWorkspaces as D, getSessionIdentity as E, setActiveWorkspace as O, themes as S, getActiveWorkspaceId as T, theme as _, installCrashHandler as a, themeModeFromColorFgBg as b, MARK_CELLS as c, splashFitsWidth as d, DEFAULT_THEME_ID as f, noColorRequested as g, monoTheme as h, writeArtifact as i, name as k, WORDMARK as l, findTheme as m, profilingEnabled as n, buildCrashReport as o, applyTheme as p, record as r, writeCrashReport as s, maybeStartProfiling as t, brandHelpArt as u, themeForMode as v, ensureActiveOrganization as w, themeVersion as x, themeMode as y };
|
package/package.json
CHANGED