skydive-cli 0.2.0-beta.671 → 0.2.0-beta.693

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as setActiveWorkspace, S as listWorkspaces, T as version, _ as themes, b as getActiveWorkspaceId, o as brandHelpArt, t as installCrashHandler, w as name, x as getSessionIdentity, y as ensureActiveOrganization } from "./install-D78XABkd.mjs";
2
+ import { C as setActiveWorkspace, S as listWorkspaces, T as version, _ as themes, b as getActiveWorkspaceId, o as brandHelpArt, t as installCrashHandler, w as name, x as getSessionIdentity, y as ensureActiveOrganization } from "./install-D7zXhVT1.mjs";
3
3
  import { A as resolveAppUrl, C as getPromptHistoryPath, D as getStoredApiKeyId, E as getShareMachineDefault, F as saveConfig, I as saveSession, M as resolveManagementAuth, N as resolveSession, O as getStoredApiKeyWorkspaceName, R as setLastSeenVersion, S as getLastSeenVersion, _ as API_KEY_PREFIX, b as deleteConfig, g as API_KEY_FAMILY_PREFIX, h as API_KEYS_URL, i as resolveAgent, j as resolveConfig, k as getUpdateCheckDisabled, v as DEFAULT_API_URL, x as getConfigPath } from "./print-BUbxOvnm.mjs";
4
4
  import { n as printError, r as printTable, t as output } from "./output-DYzzdXYV.mjs";
5
5
  import { n as createRestClient } from "./rest-CCyln7vx.mjs";
@@ -1500,7 +1500,7 @@ const importCommand = {
1500
1500
  process.exit(1);
1501
1501
  }
1502
1502
  }
1503
- const { runChat } = await import("./boot-BOr9dSBv.mjs");
1503
+ const { runChat } = await import("./boot-BCV5bnUy.mjs");
1504
1504
  await runChat({
1505
1505
  appUrl,
1506
1506
  sessionToken: session.value.sessionToken,
@@ -1816,7 +1816,7 @@ const chatCommand = {
1816
1816
  printError(`Unknown theme "${themeId}". Valid themes: ${themes.map((t) => t.id).join(", ")}`);
1817
1817
  process.exit(1);
1818
1818
  }
1819
- const { runChat } = await import("./boot-BOr9dSBv.mjs");
1819
+ const { runChat } = await import("./boot-BCV5bnUy.mjs");
1820
1820
  await runChat({
1821
1821
  appUrl,
1822
1822
  sessionToken: session.value.sessionToken,
@@ -2124,7 +2124,7 @@ const switchCommand = {
2124
2124
  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.");
2125
2125
  process.exit(1);
2126
2126
  }
2127
- const { runWorkspacePicker } = await import("./boot-BOr9dSBv.mjs");
2127
+ const { runWorkspacePicker } = await import("./boot-BCV5bnUy.mjs");
2128
2128
  await runWorkspacePicker(session);
2129
2129
  return;
2130
2130
  }
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { C as setActiveWorkspace, S as listWorkspaces, 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, l as findTheme, m as themeMode, n as buildCrashReport, p as themeForMode, r as writeCrashReport, s as DEFAULT_THEME_ID, t as installCrashHandler, u as monoTheme, v as themesForMode } from "./install-D78XABkd.mjs";
2
+ import { C as setActiveWorkspace, S as listWorkspaces, 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, l as findTheme, m as themeMode, n as buildCrashReport, p as themeForMode, r as writeCrashReport, s as DEFAULT_THEME_ID, t as installCrashHandler, u as monoTheme, v as themesForMode } from "./install-D7zXhVT1.mjs";
3
3
  import { L as saveTheme, P as resolveWebUrl, T as getSavedTheme, 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, w as getReviewStateDir, x as getConfigPath, y as DEFAULT_APP_URL } from "./print-BUbxOvnm.mjs";
4
4
  import { a as errorMessage, i as sendErrorMessage, n as createRestClient, o as isRecord, r as errorDetail, t as HttpError } from "./rest-CCyln7vx.mjs";
5
5
  import { t as PortalClient } from "./client-O5KfzIaB.mjs";
@@ -1044,13 +1044,17 @@ const PR_URL_RE = /https?:\/\/(?:www\.)?github\.com\/([\w.-]+)\/([\w.-]+)\/pull\
1044
1044
  * path/query/fragment) so the same PR linked twice with different fragments
1045
1045
  * collapses to one pill.
1046
1046
  */
1047
- function extractPullRequests(text) {
1047
+ function extractPullRequests(text, options) {
1048
+ const requireCompleteNumber = options?.requireCompleteNumber ?? true;
1048
1049
  const byKey = /* @__PURE__ */ new Map();
1049
1050
  for (const match of text.matchAll(PR_URL_RE)) {
1050
1051
  const owner = match[1];
1051
1052
  const repo = match[2];
1052
1053
  const numberText = match[3];
1053
1054
  if (!owner || !repo || !numberText) continue;
1055
+ if (requireCompleteNumber) {
1056
+ if (match.index + match[0].length >= text.length) continue;
1057
+ }
1054
1058
  const number = Number.parseInt(numberText, 10);
1055
1059
  if (!Number.isFinite(number) || number <= 0) continue;
1056
1060
  const key = `${owner.toLowerCase()}/${repo.toLowerCase()}#${number}`;
@@ -1064,34 +1068,87 @@ function extractPullRequests(text) {
1064
1068
  return [...byKey.values()];
1065
1069
  }
1066
1070
  /**
1067
- * A streaming PR scanner: fed `text-delta` chunks as a run streams, it reports
1068
- * each distinct PR the moment its URL completes, exactly once, without ever
1069
- * rescanning the transcript. It accumulates text per part id (a URL can split
1070
- * across two deltas) and only scans the current part's buffer, so cost is
1071
- * bounded by one text block, not the whole scrollback.
1071
+ * Flattens an arbitrary tool-output value into one string we can scan for PR
1072
+ * URLs. A tool's output is usually a string (bash stdout, a `gh pr create`
1073
+ * line) but can be a structured payload (an object/array of content parts), so
1074
+ * we walk it and concatenate every string we find. Depth- and size-bounded so
1075
+ * a pathological payload can't blow up the scan; the cap is generous because a
1076
+ * PR URL a tool prints is short and lands early in normal output.
1077
+ */
1078
+ function stringifyToolOutput(value) {
1079
+ const MAX_LEN = 2e5;
1080
+ const parts = [];
1081
+ let total = 0;
1082
+ const visit = (v, depth) => {
1083
+ if (total >= MAX_LEN || depth > 6) return;
1084
+ if (typeof v === "string") {
1085
+ parts.push(v);
1086
+ total += v.length;
1087
+ return;
1088
+ }
1089
+ if (Array.isArray(v)) {
1090
+ for (const item of v) {
1091
+ if (total >= MAX_LEN) return;
1092
+ visit(item, depth + 1);
1093
+ }
1094
+ return;
1095
+ }
1096
+ if (v && typeof v === "object") for (const item of Object.values(v)) {
1097
+ if (total >= MAX_LEN) return;
1098
+ visit(item, depth + 1);
1099
+ }
1100
+ };
1101
+ visit(value, 0);
1102
+ return parts.join("\n");
1103
+ }
1104
+ /**
1105
+ * A streaming PR scanner: fed run chunks as they stream, it reports each
1106
+ * distinct PR the moment its URL is seen, exactly once, without ever rescanning
1107
+ * the transcript. Two sources feed it:
1108
+ *
1109
+ * - **Assistant text** (`text-delta`): accumulated per part id (a URL can split
1110
+ * across two deltas) and only the current part's buffer is scanned, so cost
1111
+ * is bounded by one text block, not the whole scrollback.
1112
+ * - **Tool output** (`tool-output-available`): the settled output of a tool
1113
+ * call (e.g. `gh pr create` stdout) arrives whole, not delta-streamed, so we
1114
+ * flatten and scan it in one pass. This catches PRs a tool printed that the
1115
+ * agent never restated in prose — the common case for an opened PR.
1072
1116
  *
1073
- * `onPullRequest` fires once per never-before-seen PR number for the life of
1074
- * the scanner. Construct one per run (or per conversation) and feed it the
1075
- * same `text-delta` chunks the transcript reducer sees.
1117
+ * `onPullRequest` fires once per never-before-seen PR (keyed by
1118
+ * `owner/repo#number`) for the life of the scanner, regardless of which source
1119
+ * it came from. Construct one per run (or per conversation) and feed it the
1120
+ * same chunks the transcript reducer sees.
1076
1121
  */
1077
1122
  function createPullRequestScanner(onPullRequest) {
1078
1123
  let text = "";
1079
1124
  let lastPartId;
1080
1125
  const seen = /* @__PURE__ */ new Set();
1126
+ const report = (buffer, final) => {
1127
+ for (const pr of extractPullRequests(buffer, { requireCompleteNumber: !final })) {
1128
+ if (seen.has(pr.key)) continue;
1129
+ seen.add(pr.key);
1130
+ onPullRequest(pr);
1131
+ }
1132
+ };
1081
1133
  return { addChunk(chunk) {
1134
+ if (chunk["type"] === "tool-output-available") {
1135
+ const outputText = stringifyToolOutput(chunk["output"]);
1136
+ if (!outputText.includes("/pull/")) return;
1137
+ report(outputText, true);
1138
+ return;
1139
+ }
1082
1140
  if (chunk["type"] !== "text-delta") return;
1083
1141
  const delta = typeof chunk["delta"] === "string" ? chunk["delta"] : typeof chunk["text"] === "string" ? chunk["text"] : "";
1084
1142
  if (!delta) return;
1085
1143
  const partId = typeof chunk["id"] === "string" ? chunk["id"] : void 0;
1086
- if (partId && lastPartId && partId !== lastPartId) text = "";
1144
+ if (partId && lastPartId && partId !== lastPartId) {
1145
+ if (text.includes("/pull/")) report(text, true);
1146
+ text = "";
1147
+ }
1087
1148
  text += delta;
1088
1149
  lastPartId = partId ?? lastPartId;
1089
- if (!delta.includes("/pull/") && !/\/\d/.test(delta)) return;
1090
- for (const pr of extractPullRequests(text)) {
1091
- if (seen.has(pr.key)) continue;
1092
- seen.add(pr.key);
1093
- onPullRequest(pr);
1094
- }
1150
+ if (!text.includes("/pull/")) return;
1151
+ report(text, false);
1095
1152
  } };
1096
1153
  }
1097
1154
 
@@ -9524,8 +9581,9 @@ function ChatScreen({ agent, conversation }) {
9524
9581
  });
9525
9582
  setItems(loaded);
9526
9583
  for (const item of loaded) {
9527
- if (item.kind !== "assistant-text") continue;
9528
- for (const pr of extractPullRequests(item.text)) {
9584
+ const text = item.kind === "assistant-text" ? item.text : item.kind === "tool" && item.output?.kind === "ok" ? stringifyToolOutput(item.output.value) : null;
9585
+ if (text === null) continue;
9586
+ for (const pr of extractPullRequests(text, { requireCompleteNumber: false })) {
9529
9587
  if (reportedPrsRef.current.has(pr.key)) continue;
9530
9588
  reportedPrsRef.current.set(pr.key, pr);
9531
9589
  setPrLinks((prev) => [...prev, pr]);
@@ -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.2.0-beta.671";
11
+ var version$1 = "0.2.0-beta.693";
12
12
 
13
13
  //#endregion
14
14
  //#region src/auth/organization.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "skydive-cli",
3
- "version": "0.2.0-beta.671",
3
+ "version": "0.2.0-beta.693",
4
4
  "description": "Skydive CLI — cloud agents from the command line",
5
5
  "homepage": "https://skydive.com",
6
6
  "license": "MIT",